diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/FilterEditor/FilterDrawer.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/FilterEditor/FilterDrawer.svelte index d9425c961d..8d7f50a527 100644 --- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/FilterEditor/FilterDrawer.svelte +++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/FilterEditor/FilterDrawer.svelte @@ -14,6 +14,7 @@ import ClientBindingPanel from "components/common/bindings/ClientBindingPanel.svelte" import { generate } from "shortid" import { getValidOperatorsForType, OperatorOptions } from "constants/lucene" + import { getFields } from "helpers/searchFields" export let schemaFields export let filters = [] @@ -21,11 +22,8 @@ export let panel = ClientBindingPanel export let allowBindings = true - const BannedTypes = ["link", "attachment", "formula", "json", "jsonarray"] - - $: fieldOptions = (schemaFields ?? []) - .filter(field => !BannedTypes.includes(field.type)) - .map(field => field.name) + $: enrichedSchemaFields = getFields(schemaFields || []) + $: fieldOptions = enrichedSchemaFields.map(field => field.name) || [] $: valueTypeOptions = allowBindings ? ["Value", "Binding"] : ["Value"] const addFilter = () => { @@ -53,7 +51,7 @@ const onFieldChange = (expression, field) => { // Update the field type - expression.type = schemaFields.find(x => x.name === field)?.type + expression.type = enrichedSchemaFields.find(x => x.name === field)?.type // Ensure a valid operator is set const validOperators = getValidOperatorsForType(expression.type).map( @@ -85,7 +83,7 @@ } const getFieldOptions = field => { - const schema = schemaFields.find(x => x.name === field) + const schema = enrichedSchemaFields.find(x => x.name === field) return schema?.constraints?.inclusion || [] } diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/SearchFieldSelect.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/SearchFieldSelect.svelte new file mode 100644 index 0000000000..474fbc676c --- /dev/null +++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/SearchFieldSelect.svelte @@ -0,0 +1,47 @@ + + + diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/componentSettings.js b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/componentSettings.js index e752240302..5e27cdce28 100644 --- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/componentSettings.js +++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/componentSettings.js @@ -7,6 +7,7 @@ import ColorPicker from "./ColorPicker.svelte" import { IconSelect } from "./IconSelect" import FieldSelect from "./FieldSelect.svelte" import MultiFieldSelect from "./MultiFieldSelect.svelte" +import SearchFieldSelect from "./SearchFieldSelect.svelte" import SchemaSelect from "./SchemaSelect.svelte" import SectionSelect from "./SectionSelect.svelte" import NavigationEditor from "./NavigationEditor/NavigationEditor.svelte" @@ -30,6 +31,7 @@ const componentMap = { icon: IconSelect, field: FieldSelect, multifield: MultiFieldSelect, + searchfield: SearchFieldSelect, options: OptionsEditor, schema: SchemaSelect, section: SectionSelect, diff --git a/packages/builder/src/constants/backend/index.js b/packages/builder/src/constants/backend/index.js index c5fb294f80..c1eea5b0ef 100644 --- a/packages/builder/src/constants/backend/index.js +++ b/packages/builder/src/constants/backend/index.js @@ -229,3 +229,11 @@ export const PaginationLocations = [ { label: "Query parameters", value: "query" }, { label: "Request body", value: "body" }, ] + +export const BannedSearchTypes = [ + "link", + "attachment", + "formula", + "json", + "jsonarray", +] diff --git a/packages/builder/src/helpers/searchFields.js b/packages/builder/src/helpers/searchFields.js new file mode 100644 index 0000000000..650e04a680 --- /dev/null +++ b/packages/builder/src/helpers/searchFields.js @@ -0,0 +1,31 @@ +import { tables } from "../stores/backend" +import { BannedSearchTypes } from "../constants/backend" +import { get } from "svelte/store" + +export function getTableFields(linkField) { + const table = get(tables).list.find(table => table._id === linkField.tableId) + if (!table || !table.sql) { + return [] + } + const linkFields = getFields(Object.values(table.schema), { + allowLinks: false, + }) + return linkFields.map(field => ({ + ...field, + name: `${table.name}.${field.name}`, + })) +} + +export function getFields(fields, { allowLinks } = { allowLinks: true }) { + let filteredFields = fields.filter( + field => !BannedSearchTypes.includes(field.type) + ) + if (allowLinks) { + const linkFields = fields.filter(field => field.type === "link") + for (let linkField of linkFields) { + // only allow one depth of SQL relationship filtering + filteredFields = filteredFields.concat(getTableFields(linkField)) + } + } + return filteredFields +} diff --git a/packages/client/manifest.json b/packages/client/manifest.json index dfe9ae5a91..9431129fa0 100644 --- a/packages/client/manifest.json +++ b/packages/client/manifest.json @@ -2811,7 +2811,7 @@ "key": "dataSource" }, { - "type": "multifield", + "type": "searchfield", "label": "Search Columns", "key": "searchColumns", "placeholder": "Choose search columns" @@ -2958,7 +2958,7 @@ "key": "dataSource" }, { - "type": "multifield", + "type": "searchfield", "label": "Search Columns", "key": "searchColumns", "placeholder": "Choose search columns" diff --git a/packages/client/src/components/app/DataProvider.svelte b/packages/client/src/components/app/DataProvider.svelte index 71c54db4da..2341eef3b2 100644 --- a/packages/client/src/components/app/DataProvider.svelte +++ b/packages/client/src/components/app/DataProvider.svelte @@ -67,6 +67,7 @@ $: dataContext = { rows: $fetch.rows, info: $fetch.info, + datasource: dataSource || {}, schema: $fetch.schema, rowsLength: $fetch.rows.length, diff --git a/packages/client/src/components/app/blocks/CardsBlock.svelte b/packages/client/src/components/app/blocks/CardsBlock.svelte index 301b440ab3..f0892ca447 100644 --- a/packages/client/src/components/app/blocks/CardsBlock.svelte +++ b/packages/client/src/components/app/blocks/CardsBlock.svelte @@ -71,12 +71,13 @@ const enrichFilter = (filter, columns, formId) => { let enrichedFilter = [...(filter || [])] columns?.forEach(column => { + const safePath = column.name.split(".").map(safe).join(".") enrichedFilter.push({ field: column.name, operator: column.type === "string" ? "string" : "equal", type: column.type === "string" ? "string" : "number", valueType: "Binding", - value: `{{ [${formId}].[${column.name}] }}`, + value: `{{ ${safe(formId)}.${safePath} }}`, }) }) return enrichedFilter @@ -112,7 +113,9 @@ // Load the datasource schema so we can determine column types const fetchSchema = async dataSource => { if (dataSource) { - schema = await fetchDatasourceSchema(dataSource) + schema = await fetchDatasourceSchema(dataSource, { + enrichRelationships: true, + }) } schemaLoaded = true } diff --git a/packages/client/src/components/app/blocks/TableBlock.svelte b/packages/client/src/components/app/blocks/TableBlock.svelte index 936a8d1734..3de4497731 100644 --- a/packages/client/src/components/app/blocks/TableBlock.svelte +++ b/packages/client/src/components/app/blocks/TableBlock.svelte @@ -59,12 +59,13 @@ const enrichFilter = (filter, columns, formId) => { let enrichedFilter = [...(filter || [])] columns?.forEach(column => { + const safePath = column.name.split(".").map(safe).join(".") enrichedFilter.push({ field: column.name, operator: column.type === "string" ? "string" : "equal", type: column.type === "string" ? "string" : "number", valueType: "Binding", - value: `{{ ${safe(formId)}.${safe(column.name)} }}`, + value: `{{ ${safe(formId)}.${safePath} }}`, }) }) return enrichedFilter @@ -90,7 +91,9 @@ // Load the datasource schema so we can determine column types const fetchSchema = async dataSource => { if (dataSource) { - schema = await fetchDatasourceSchema(dataSource) + schema = await fetchDatasourceSchema(dataSource, { + enrichRelationships: true, + }) } schemaLoaded = true } diff --git a/packages/client/src/components/app/dynamic-filter/DynamicFilter.svelte b/packages/client/src/components/app/dynamic-filter/DynamicFilter.svelte index 20909d011c..6a114afe3e 100644 --- a/packages/client/src/components/app/dynamic-filter/DynamicFilter.svelte +++ b/packages/client/src/components/app/dynamic-filter/DynamicFilter.svelte @@ -11,11 +11,14 @@ export let size = "M" const component = getContext("component") - const { builderStore, ActionTypes, getAction } = getContext("sdk") + const { builderStore, ActionTypes, getAction, fetchDatasourceSchema } = + getContext("sdk") let modal let tmpFilters = [] let filters = [] + let schemaLoaded = false, + schema $: dataProviderId = dataProvider?.id $: addExtension = getAction( @@ -26,7 +29,7 @@ dataProviderId, ActionTypes.RemoveDataProviderQueryExtension ) - $: schema = dataProvider?.schema + $: fetchSchema(dataProvider || {}) $: schemaFields = getSchemaFields(schema, allowedFields) // Add query extension to data provider @@ -39,7 +42,20 @@ } } - const getSchemaFields = (schema, allowedFields) => { + async function fetchSchema(dataProvider) { + const datasource = dataProvider?.datasource + if (datasource) { + schema = await fetchDatasourceSchema(datasource, { + enrichRelationships: true, + }) + } + schemaLoaded = true + } + + function getSchemaFields(schema, allowedFields) { + if (!schemaLoaded) { + return {} + } let clonedSchema = {} if (!allowedFields?.length) { clonedSchema = schema @@ -68,18 +84,20 @@ }) -