Reuse filter drawer component to allow full table filtering on any type in data UI
This commit is contained in:
parent
9bdc1b824b
commit
98341b7237
|
@ -7,17 +7,16 @@
|
|||
import EditRolesButton from "./buttons/EditRolesButton.svelte"
|
||||
import ManageAccessButton from "./buttons/ManageAccessButton.svelte"
|
||||
import HideAutocolumnButton from "./buttons/HideAutocolumnButton.svelte"
|
||||
import TableFilterButton from "./buttons/TableFilterButton.svelte"
|
||||
import Table from "./Table.svelte"
|
||||
import { TableNames } from "constants"
|
||||
import CreateEditRow from "./modals/CreateEditRow.svelte"
|
||||
import { fetchTableData } from "helpers/fetchTableData"
|
||||
import { Layout, Pagination, Select, Input } from "@budibase/bbui"
|
||||
import { OperatorOptions } from "constants/lucene"
|
||||
import { Pagination } from "@budibase/bbui"
|
||||
|
||||
const search = fetchTableData()
|
||||
let hideAutocolumns = true
|
||||
let searchColumn
|
||||
let searchValue
|
||||
let filters
|
||||
|
||||
$: isUsersTable = $tables.selected?._id === TableNames.USERS
|
||||
$: title = $tables.selected?.name
|
||||
|
@ -26,15 +25,14 @@
|
|||
$: isInternal = type !== "external"
|
||||
$: id = $tables.selected?._id
|
||||
$: columnOptions = Object.keys($search.schema || {})
|
||||
$: filter = buildFilter(searchColumn, searchValue)
|
||||
$: fetchTable(id, filter)
|
||||
$: fetchTable(id, filters)
|
||||
|
||||
// Fetches new data whenever the table changes
|
||||
const fetchTable = (tableId, filter) => {
|
||||
const fetchTable = (tableId, filters) => {
|
||||
search.update({
|
||||
tableId,
|
||||
schema,
|
||||
filter,
|
||||
filters,
|
||||
limit: 10,
|
||||
paginate: true,
|
||||
})
|
||||
|
@ -47,23 +45,6 @@
|
|||
sortOrder: e.detail.order,
|
||||
})
|
||||
}
|
||||
|
||||
// Builds a filter expression to search with
|
||||
const buildFilter = (column, value) => {
|
||||
if (!column || !value) {
|
||||
return null
|
||||
}
|
||||
return [
|
||||
{
|
||||
type: "string",
|
||||
field: column,
|
||||
operator: OperatorOptions.StartsWith.value,
|
||||
value,
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
$: console.log(filter)
|
||||
</script>
|
||||
|
||||
<div>
|
||||
|
@ -79,39 +60,32 @@
|
|||
allowEditing
|
||||
disableSorting
|
||||
>
|
||||
<Layout noPadding gap="S">
|
||||
<div class="buttons">
|
||||
{#if isInternal}
|
||||
<CreateColumnButton />
|
||||
{/if}
|
||||
{#if schema && Object.keys(schema).length > 0}
|
||||
{#if !isUsersTable}
|
||||
<CreateRowButton
|
||||
title={"Create row"}
|
||||
modalContentComponent={CreateEditRow}
|
||||
/>
|
||||
{/if}
|
||||
{#if isInternal}
|
||||
<CreateViewButton />
|
||||
{/if}
|
||||
<ManageAccessButton resourceId={$tables.selected?._id} />
|
||||
{#if isUsersTable}
|
||||
<EditRolesButton />
|
||||
{/if}
|
||||
<HideAutocolumnButton bind:hideAutocolumns />
|
||||
<!-- always have the export last -->
|
||||
<ExportButton view={$tables.selected?._id} />
|
||||
{/if}
|
||||
</div>
|
||||
<div class="search">
|
||||
<Select bind:value={searchColumn} options={columnOptions} />
|
||||
<Input
|
||||
updateOnChange={false}
|
||||
on:change={e => (searchValue = e.detail)}
|
||||
placeholder="Search"
|
||||
{#if isInternal}
|
||||
<CreateColumnButton />
|
||||
{/if}
|
||||
{#if schema && Object.keys(schema).length > 0}
|
||||
{#if !isUsersTable}
|
||||
<CreateRowButton
|
||||
title={"Create row"}
|
||||
modalContentComponent={CreateEditRow}
|
||||
/>
|
||||
</div>
|
||||
</Layout>
|
||||
{/if}
|
||||
{#if isInternal}
|
||||
<CreateViewButton />
|
||||
{/if}
|
||||
<ManageAccessButton resourceId={$tables.selected?._id} />
|
||||
{#if isUsersTable}
|
||||
<EditRolesButton />
|
||||
{/if}
|
||||
<HideAutocolumnButton bind:hideAutocolumns />
|
||||
<!-- always have the export last -->
|
||||
<ExportButton view={$tables.selected?._id} />
|
||||
<TableFilterButton
|
||||
{schema}
|
||||
{filters}
|
||||
on:change={e => (filters = e.detail)}
|
||||
/>
|
||||
{/if}
|
||||
</Table>
|
||||
<div class="pagination">
|
||||
<Pagination
|
||||
|
@ -125,19 +99,6 @@
|
|||
</div>
|
||||
|
||||
<style>
|
||||
.buttons {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
gap: var(--spacing-s);
|
||||
}
|
||||
.search {
|
||||
display: grid;
|
||||
align-items: center;
|
||||
grid-template-columns: 200px 200px;
|
||||
gap: var(--spacing-s);
|
||||
}
|
||||
.pagination {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
|
|
@ -164,7 +164,7 @@
|
|||
align-items: center;
|
||||
gap: var(--spacing-s);
|
||||
}
|
||||
.popovers :global(.spectrum-ActionButton) {
|
||||
.popovers :global(button) {
|
||||
font-weight: 600;
|
||||
margin-top: var(--spacing-l);
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
import Table from "./Table.svelte"
|
||||
import CalculateButton from "./buttons/CalculateButton.svelte"
|
||||
import GroupByButton from "./buttons/GroupByButton.svelte"
|
||||
import FilterButton from "./buttons/FilterButton.svelte"
|
||||
import ViewFilterButton from "./buttons/ViewFilterButton.svelte"
|
||||
import ExportButton from "./buttons/ExportButton.svelte"
|
||||
import ManageAccessButton from "./buttons/ManageAccessButton.svelte"
|
||||
import HideAutocolumnButton from "./buttons/HideAutocolumnButton.svelte"
|
||||
|
@ -61,7 +61,7 @@
|
|||
allowEditing={!view?.calculation}
|
||||
bind:hideAutocolumns
|
||||
>
|
||||
<FilterButton {view} />
|
||||
<ViewFilterButton {view} />
|
||||
<CalculateButton {view} />
|
||||
{#if view.calculation}
|
||||
<GroupByButton {view} />
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
<script>
|
||||
import { createEventDispatcher } from "svelte"
|
||||
import { ActionButton, Modal, ModalContent } from "@budibase/bbui"
|
||||
import FilterDrawer from "components/design/PropertiesPanel/PropertyControls/FilterEditor/FilterDrawer.svelte"
|
||||
|
||||
export let schema
|
||||
export let filters
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
let modal
|
||||
let tempValue = filters || []
|
||||
|
||||
$: schemaFields = Object.values(schema || {})
|
||||
</script>
|
||||
|
||||
<ActionButton
|
||||
icon="Filter"
|
||||
size="S"
|
||||
quiet
|
||||
on:click={modal.show}
|
||||
active={tempValue?.length > 0}
|
||||
>
|
||||
Filter
|
||||
</ActionButton>
|
||||
<Modal bind:this={modal}>
|
||||
<ModalContent
|
||||
title="Filter"
|
||||
confirmText="Save"
|
||||
size="XL"
|
||||
onConfirm={() => dispatch("change", tempValue)}
|
||||
>
|
||||
<div class="wrapper">
|
||||
<FilterDrawer bind:filters={tempValue} {schemaFields} />
|
||||
</div>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
|
||||
<style>
|
||||
.wrapper :global(.main) {
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
|
@ -20,7 +20,6 @@
|
|||
$: dataSource = getDatasourceForProvider($currentAsset, componentInstance)
|
||||
$: schema = getSchemaForDatasource($currentAsset, dataSource)?.schema
|
||||
$: schemaFields = Object.values(schema || {})
|
||||
$: internalTable = dataSource?.type === "table"
|
||||
|
||||
const saveFilter = async () => {
|
||||
dispatch("change", tempValue)
|
||||
|
|
|
@ -6,7 +6,7 @@ import { buildLuceneQuery } from "./lucene"
|
|||
|
||||
const defaultOptions = {
|
||||
tableId: null,
|
||||
filter: null,
|
||||
filters: null,
|
||||
limit: 10,
|
||||
sortColumn: null,
|
||||
sortOrder: "ascending",
|
||||
|
@ -65,7 +65,7 @@ export const fetchTableData = opts => {
|
|||
|
||||
// Fetches a fresh set of results from the server
|
||||
const fetchData = async () => {
|
||||
const { tableId, schema, sortColumn, filter } = options
|
||||
const { tableId, schema, sortColumn, filters } = options
|
||||
|
||||
// Ensure table ID exists
|
||||
if (!tableId) {
|
||||
|
@ -113,7 +113,7 @@ export const fetchTableData = opts => {
|
|||
sortType = type === "number" ? "number" : "string"
|
||||
|
||||
// Build the lucene query
|
||||
query = buildLuceneQuery(filter)
|
||||
query = buildLuceneQuery(filters)
|
||||
|
||||
// Actually fetch data
|
||||
const page = await fetchPage()
|
||||
|
|
Loading…
Reference in New Issue