From 36f8ae45fe468ca4a015733b58fd4e0b82e2e037 Mon Sep 17 00:00:00 2001 From: Dean Date: Tue, 10 Dec 2024 14:17:46 +0000 Subject: [PATCH] Rejig the filtering behaviour in the builder around empty config. Empty filters wont cause errors on load and will clear when they are saved --- .../FlowChart/BranchNode.svelte | 11 ++++---- .../SetupPanel/AutomationBlockSetup.svelte | 5 ++-- .../buttons/TableFilterButton.svelte | 4 +-- .../controls/FilterEditor/FilterEditor.svelte | 5 ++-- .../app/dynamic-filter/DynamicFilter.svelte | 3 ++- packages/frontend-core/src/utils/utils.js | 25 +++++++++++++++++++ packages/shared-core/src/filters.ts | 4 +-- 7 files changed, 42 insertions(+), 15 deletions(-) diff --git a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/BranchNode.svelte b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/BranchNode.svelte index 670067ea260..c9205d0254c 100644 --- a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/BranchNode.svelte +++ b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/BranchNode.svelte @@ -19,7 +19,7 @@ import FlowItemHeader from "./FlowItemHeader.svelte" import FlowItemActions from "./FlowItemActions.svelte" import { automationStore, selectedAutomation } from "stores/builder" - import { QueryUtils } from "@budibase/frontend-core" + import { QueryUtils, Utils } from "@budibase/frontend-core" import { cloneDeep } from "lodash/fp" import { createEventDispatcher, getContext } from "svelte" import DragZone from "./DragZone.svelte" @@ -36,13 +36,11 @@ const view = getContext("draggableView") let drawer - let condition let open = true let confirmDeleteModal $: branch = step.inputs?.branches?.[branchIdx] - $: editableConditionUI = cloneDeep(branch.conditionUI || {}) - $: condition = QueryUtils.buildQuery(editableConditionUI) + $: editableConditionUI = branch.conditionUI || {} // Parse all the bindings into fields for the condition builder $: schemaFields = bindings.map(binding => { @@ -80,9 +78,10 @@ slot="buttons" on:click={() => { drawer.hide() + const updatedConditionsUI = Utils.parseFilter(editableConditionUI) dispatch("change", { - conditionUI: editableConditionUI, - condition, + conditionUI: updatedConditionsUI, + condition: QueryUtils.buildQuery(updatedConditionsUI), }) }} > diff --git a/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte b/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte index 3faf9140f41..ab01b561524 100644 --- a/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte +++ b/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte @@ -594,10 +594,11 @@ } function saveFilters(key) { - const query = QueryUtils.buildQuery(tempFilters) + const update = Utils.parseFilter(tempFilters) + const query = QueryUtils.buildQuery(update) onChange({ [key]: query, - [`${key}-def`]: tempFilters, // need to store the builder definition in the automation + [`${key}-def`]: update, // need to store the builder definition in the automation }) drawer.hide() diff --git a/packages/builder/src/components/backend/DataTable/buttons/TableFilterButton.svelte b/packages/builder/src/components/backend/DataTable/buttons/TableFilterButton.svelte index c6103b16974..d4a71c9ef8c 100644 --- a/packages/builder/src/components/backend/DataTable/buttons/TableFilterButton.svelte +++ b/packages/builder/src/components/backend/DataTable/buttons/TableFilterButton.svelte @@ -4,7 +4,7 @@ import FilterBuilder from "components/design/settings/controls/FilterEditor/FilterBuilder.svelte" import { getUserBindings } from "dataBinding" import { makePropSafe } from "@budibase/string-templates" - import { search } from "@budibase/frontend-core" + import { search, Utils } from "@budibase/frontend-core" import { tables } from "stores/builder" import DetailPopover from "components/common/DetailPopover.svelte" @@ -73,7 +73,7 @@ cta slot="buttons" on:click={() => { - dispatch("change", localFilters) + dispatch("change", Utils.parseFilter(localFilters)) popover.hide() }} > diff --git a/packages/builder/src/components/design/settings/controls/FilterEditor/FilterEditor.svelte b/packages/builder/src/components/design/settings/controls/FilterEditor/FilterEditor.svelte index c48cc3b8ce8..b8a6b86b4dd 100644 --- a/packages/builder/src/components/design/settings/controls/FilterEditor/FilterEditor.svelte +++ b/packages/builder/src/components/design/settings/controls/FilterEditor/FilterEditor.svelte @@ -10,7 +10,7 @@ import { getDatasourceForProvider, getSchemaForDatasource } from "dataBinding" import FilterBuilder from "./FilterBuilder.svelte" import { tables, selectedScreen } from "stores/builder" - import { search } from "@budibase/frontend-core" + import { search, Utils } from "@budibase/frontend-core" import { utils } from "@budibase/shared-core" const dispatch = createEventDispatcher() @@ -33,7 +33,8 @@ $: text = getText(value) async function saveFilter() { - dispatch("change", localFilters) + const update = Utils.parseFilter(localFilters) + dispatch("change", update) notifications.success("Filters saved") drawer.hide() } diff --git a/packages/client/src/components/app/dynamic-filter/DynamicFilter.svelte b/packages/client/src/components/app/dynamic-filter/DynamicFilter.svelte index 4ab01de17d4..28858f3112f 100644 --- a/packages/client/src/components/app/dynamic-filter/DynamicFilter.svelte +++ b/packages/client/src/components/app/dynamic-filter/DynamicFilter.svelte @@ -6,6 +6,7 @@ QueryUtils, Constants, CoreFilterBuilder, + Utils, } from "@budibase/frontend-core" import Button from "../Button.svelte" @@ -95,7 +96,7 @@ } const updateQuery = () => { - filters = editableFilters + filters = Utils.parseFilter(editableFilters) } onDestroy(() => { diff --git a/packages/frontend-core/src/utils/utils.js b/packages/frontend-core/src/utils/utils.js index fef9a7a31bb..c424aea5b20 100644 --- a/packages/frontend-core/src/utils/utils.js +++ b/packages/frontend-core/src/utils/utils.js @@ -1,5 +1,6 @@ import { makePropSafe as safe } from "@budibase/string-templates" import { Helpers } from "@budibase/bbui" +import { cloneDeep } from "lodash" export const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)) @@ -351,3 +352,27 @@ export const buildMultiStepFormBlockDefaultProps = props => { title, } } + +/** + * Parse out empty or invalid UI filters and clear empty groups + * @param {Object} filter UI filter + * @returns {Object} parsed filter + */ +export function parseFilter(filter) { + if (!filter?.groups) { + return filter + } + + const update = cloneDeep(filter) + + update.groups = update.groups + .map(group => { + group.filters = group.filters.filter(filter => { + return filter.field && filter.operator + }) + return group.filters.length ? group : null + }) + .filter(group => group) + + return update +} diff --git a/packages/shared-core/src/filters.ts b/packages/shared-core/src/filters.ts index 61950fd5235..a023015b7e9 100644 --- a/packages/shared-core/src/filters.ts +++ b/packages/shared-core/src/filters.ts @@ -298,7 +298,8 @@ export class ColumnSplitter { function buildCondition(filter: undefined): undefined function buildCondition(filter: SearchFilter): SearchFilters function buildCondition(filter?: SearchFilter): SearchFilters | undefined { - if (!filter) { + // Ignore empty or invalid filters + if (!filter || !filter?.operator || !filter?.field) { return } @@ -475,7 +476,6 @@ export function buildQuery( if (group.logicalOperator) { operator = logicalOperatorFromUI(group.logicalOperator) } - return { [operator]: { conditions: filters.map(buildCondition).filter(f => f) }, }