diff --git a/.github/workflows/readme-openapi.yml b/.github/workflows/readme-openapi.yml index 14e9887dd6..b52787934f 100644 --- a/.github/workflows/readme-openapi.yml +++ b/.github/workflows/readme-openapi.yml @@ -20,9 +20,4 @@ jobs: - run: yarn --frozen-lockfile - name: update specs - run: cd packages/server && yarn specs - - - name: Run `openapi` command - uses: readmeio/rdme@v8 - with: - rdme: openapi specs/openapi.yaml --key=${{ secrets.README_API_KEY }} --id=6728a74f5918b50036c61841 + run: cd packages/server && yarn specs && openapi specs/openapi.yaml --key=${{ secrets.README_API_KEY }} --id=6728a74f5918b50036c61841 diff --git a/lerna.json b/lerna.json index afd0db6374..d893fc97bd 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "$schema": "node_modules/lerna/schemas/lerna-schema.json", - "version": "3.2.26", + "version": "3.2.27", "npmClient": "yarn", "concurrency": 20, "command": { diff --git a/packages/bbui/src/Form/Core/CheckboxGroup.svelte b/packages/bbui/src/Form/Core/CheckboxGroup.svelte index d1a107fcc5..5aca7911e8 100644 --- a/packages/bbui/src/Form/Core/CheckboxGroup.svelte +++ b/packages/bbui/src/Form/Core/CheckboxGroup.svelte @@ -13,9 +13,8 @@ const dispatch = createEventDispatcher() - const onChange = e => { - const optionValue = e.target.value - if (e.target.checked && !value.includes(optionValue)) { + const onChange = optionValue => { + if (!value.includes(optionValue)) { dispatch("change", [...value, optionValue]) } else { dispatch( @@ -39,10 +38,9 @@ class="spectrum-Checkbox spectrum-Checkbox--sizeM spectrum-FieldGroup-item" > onChange(optionValue)} type="checkbox" class="spectrum-Checkbox-input" - value={optionValue} checked={value.includes(optionValue)} {disabled} /> diff --git a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/BranchNode.svelte b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/BranchNode.svelte index 670067ea26..c9205d0254 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 3faf9140f4..ab01b56152 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 c6103b1697..d4a71c9ef8 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 c48cc3b8ce..b8a6b86b4d 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 4ab01de17d..28858f3112 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/components/CoreFilterBuilder.svelte b/packages/frontend-core/src/components/CoreFilterBuilder.svelte index 3aff981082..2bf40bda37 100644 --- a/packages/frontend-core/src/components/CoreFilterBuilder.svelte +++ b/packages/frontend-core/src/components/CoreFilterBuilder.svelte @@ -407,6 +407,7 @@ /> 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 61950fd523..a023015b7e 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) }, }