From 0d1f5c698e529664e1a9ed0e30dce9eb52d0e778 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Mon, 20 Jan 2025 09:54:12 +0100 Subject: [PATCH 01/38] Add basic datasource validation error --- packages/client/manifest.json | 3 ++- .../client/src/components/Component.svelte | 24 ++++++++++++++++++- .../error-states/ComponentErrorState.svelte | 4 ++++ .../client/src/utils/componentsValidator.ts | 13 ++++++++++ 4 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 packages/client/src/utils/componentsValidator.ts diff --git a/packages/client/manifest.json b/packages/client/manifest.json index c236dd1ad9..7da7c60abe 100644 --- a/packages/client/manifest.json +++ b/packages/client/manifest.json @@ -7206,7 +7206,8 @@ { "type": "table", "label": "Data", - "key": "dataSource" + "key": "dataSource", + "validator": "checkValidDatasource" }, { "type": "radio", diff --git a/packages/client/src/components/Component.svelte b/packages/client/src/components/Component.svelte index 79b4ca6f68..4926965e45 100644 --- a/packages/client/src/components/Component.svelte +++ b/packages/client/src/components/Component.svelte @@ -40,6 +40,7 @@ getActionDependentContextKeys, } from "../utils/buttonActions.js" import { gridLayout } from "utils/grid" + import { validateComponentSetting } from "utils/componentsValidator" export let instance = {} export let parent = null @@ -103,6 +104,7 @@ let settingsDefinition let settingsDefinitionMap let missingRequiredSettings = false + let invalidSettings = false // Temporary styles which can be added in the app preview for things like // DND. We clear these whenever a new instance is received. @@ -141,12 +143,16 @@ $: showEmptyState = definition?.showEmptyState !== false $: hasMissingRequiredSettings = missingRequiredSettings?.length > 0 $: editable = !!definition?.editable && !hasMissingRequiredSettings + $: hasInvalidSettings = invalidSettings?.length > 0 $: requiredAncestors = definition?.requiredAncestors || [] $: missingRequiredAncestors = requiredAncestors.filter( ancestor => !$component.ancestors.includes(`${BudibasePrefix}${ancestor}`) ) $: hasMissingRequiredAncestors = missingRequiredAncestors?.length > 0 - $: errorState = hasMissingRequiredSettings || hasMissingRequiredAncestors + $: errorState = + hasMissingRequiredSettings || + hasMissingRequiredAncestors || + hasInvalidSettings // Interactive components can be selected, dragged and highlighted inside // the builder preview @@ -338,6 +344,21 @@ return missing }) + // Check for invalid settings + invalidSettings = settingsDefinition.reduce((invalidSettings, setting) => { + if (setting.validator) { + const error = validateComponentSetting( + setting.validator, + instance[setting.key] + ) + if (error) { + invalidSettings.push(error) + } + } + + return invalidSettings + }, []) + // When considering bindings we can ignore children, so we remove that // before storing the reference stringified version const noChildren = JSON.stringify({ ...instance, _children: null }) @@ -692,6 +713,7 @@ {:else} diff --git a/packages/client/src/components/error-states/ComponentErrorState.svelte b/packages/client/src/components/error-states/ComponentErrorState.svelte index b846eaa230..ba55e3cdc1 100644 --- a/packages/client/src/components/error-states/ComponentErrorState.svelte +++ b/packages/client/src/components/error-states/ComponentErrorState.svelte @@ -9,6 +9,7 @@ | { key: string; label: string }[] | undefined export let missingRequiredAncestors: string[] | undefined + export let invalidSettings: string[] | undefined const component = getContext("component") const { styleable, builderStore } = getContext("sdk") @@ -16,6 +17,7 @@ $: styles = { ...$component.styles, normal: {}, custom: null, empty: true } $: requiredSetting = missingRequiredSettings?.[0] $: requiredAncestor = missingRequiredAncestors?.[0] + $: invalidSetting = invalidSettings?.[0] {#if $builderStore.inBuilder} @@ -24,6 +26,8 @@ {#if requiredAncestor} + {:else if invalidSetting} + {invalidSetting} {:else if requiredSetting} {/if} diff --git a/packages/client/src/utils/componentsValidator.ts b/packages/client/src/utils/componentsValidator.ts new file mode 100644 index 0000000000..6609f92ed6 --- /dev/null +++ b/packages/client/src/utils/componentsValidator.ts @@ -0,0 +1,13 @@ +const validators = { + checkValidDatasource: (a: any) => { + return `Ups... "${a.label}" not found` + }, +} + +export function validateComponentSetting( + key: keyof typeof validators, + value: any +) { + const validator = validators[key] + return validator(value) +} From ba2a61841f292276169bc3c4decc659a58c98f61 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Mon, 20 Jan 2025 15:55:00 +0100 Subject: [PATCH 02/38] Allow importing @budibase/client/manifest.json --- eslint-local-rules/index.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/eslint-local-rules/index.js b/eslint-local-rules/index.js index d9d894c33e..9348706399 100644 --- a/eslint-local-rules/index.js +++ b/eslint-local-rules/index.js @@ -41,11 +41,12 @@ module.exports = { if ( /^@budibase\/[^/]+\/.*$/.test(importPath) && importPath !== "@budibase/backend-core/tests" && - importPath !== "@budibase/string-templates/test/utils" + importPath !== "@budibase/string-templates/test/utils" && + importPath !== "@budibase/client/manifest.json" ) { context.report({ node, - message: `Importing from @budibase is not allowed, except for @budibase/backend-core/tests and @budibase/string-templates/test/utils.`, + message: `Importing from @budibase is not allowed, except for @budibase/backend-core/tests, @budibase/string-templates/test/utils and @budibase/client/manifest.json.`, }) } }, From 7e029386190964097cdf1582f91568b7a694e7ef Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Mon, 20 Jan 2025 15:55:17 +0100 Subject: [PATCH 03/38] Screen helpers, findComponentsBySettingsType --- packages/builder/src/helpers/screen.ts | 30 ++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 packages/builder/src/helpers/screen.ts diff --git a/packages/builder/src/helpers/screen.ts b/packages/builder/src/helpers/screen.ts new file mode 100644 index 0000000000..e83805a511 --- /dev/null +++ b/packages/builder/src/helpers/screen.ts @@ -0,0 +1,30 @@ +import { Component, Screen, ScreenProps } from "@budibase/types" +import clientManifest from "@budibase/client/manifest.json" + +export function findComponentsBySettingsType(screen: Screen, type: string) { + const result: Component[] = [] + function recurseFieldComponentsInChildren( + component: ScreenProps, + type: string + ) { + if (!component) { + return + } + + const componentType = component._component.split("/").slice(-1)[0] + const definition = + clientManifest[componentType as keyof typeof clientManifest] + if ( + "settings" in definition && + definition.settings.some((s: any) => s.type === type) + ) { + result.push(component) + } + component._children?.forEach(child => { + recurseFieldComponentsInChildren(child, type) + }) + } + + recurseFieldComponentsInChildren(screen?.props, type) + return result +} From 3c4ac9ad5a7610645b83c8b8f3cdeb3b8c52c70a Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Mon, 20 Jan 2025 16:04:39 +0100 Subject: [PATCH 04/38] Errors from builder store --- packages/client/manifest.json | 3 +-- .../client/src/components/Component.svelte | 20 ++++--------------- packages/client/src/stores/builder.js | 3 +++ .../src/stores/derived/componentErrors.ts | 6 ++++++ packages/client/src/stores/derived/index.js | 1 + .../client/src/utils/componentsValidator.ts | 13 ------------ 6 files changed, 15 insertions(+), 31 deletions(-) create mode 100644 packages/client/src/stores/derived/componentErrors.ts delete mode 100644 packages/client/src/utils/componentsValidator.ts diff --git a/packages/client/manifest.json b/packages/client/manifest.json index 7da7c60abe..c236dd1ad9 100644 --- a/packages/client/manifest.json +++ b/packages/client/manifest.json @@ -7206,8 +7206,7 @@ { "type": "table", "label": "Data", - "key": "dataSource", - "validator": "checkValidDatasource" + "key": "dataSource" }, { "type": "radio", diff --git a/packages/client/src/components/Component.svelte b/packages/client/src/components/Component.svelte index 4926965e45..7f825c0601 100644 --- a/packages/client/src/components/Component.svelte +++ b/packages/client/src/components/Component.svelte @@ -23,6 +23,7 @@ appStore, dndComponentPath, dndIsDragging, + componentErrors, } from "stores" import { Helpers } from "@budibase/bbui" import { getActiveConditions, reduceConditionActions } from "utils/conditions" @@ -40,7 +41,6 @@ getActionDependentContextKeys, } from "../utils/buttonActions.js" import { gridLayout } from "utils/grid" - import { validateComponentSetting } from "utils/componentsValidator" export let instance = {} export let parent = null @@ -344,21 +344,6 @@ return missing }) - // Check for invalid settings - invalidSettings = settingsDefinition.reduce((invalidSettings, setting) => { - if (setting.validator) { - const error = validateComponentSetting( - setting.validator, - instance[setting.key] - ) - if (error) { - invalidSettings.push(error) - } - } - - return invalidSettings - }, []) - // When considering bindings we can ignore children, so we remove that // before storing the reference stringified version const noChildren = JSON.stringify({ ...instance, _children: null }) @@ -389,6 +374,9 @@ } } + // Check for invalid settings + $: invalidSettings = $componentErrors[id] + // Extracts a map of all context keys which are required by action settings // to provide the functions to evaluate at runtime. This needs done manually // as the action definitions themselves do not specify bindings for action diff --git a/packages/client/src/stores/builder.js b/packages/client/src/stores/builder.js index faa37eddca..62123c07e5 100644 --- a/packages/client/src/stores/builder.js +++ b/packages/client/src/stores/builder.js @@ -19,6 +19,9 @@ const createBuilderStore = () => { eventResolvers: {}, metadata: null, snippets: null, + componentErrors: { + c5ea93132725c48b2a365fcc1facaee86: ["Ups...!"], + }, // TODO // Legacy - allow the builder to specify a layout layout: null, diff --git a/packages/client/src/stores/derived/componentErrors.ts b/packages/client/src/stores/derived/componentErrors.ts new file mode 100644 index 0000000000..48185de9c3 --- /dev/null +++ b/packages/client/src/stores/derived/componentErrors.ts @@ -0,0 +1,6 @@ +import { derived } from "svelte/store" +import { builderStore } from "../builder.js" + +export const componentErrors = derived([builderStore], ([$builderStore]) => { + return $builderStore.componentErrors as Record +}) diff --git a/packages/client/src/stores/derived/index.js b/packages/client/src/stores/derived/index.js index 337c73831f..e7e70d8952 100644 --- a/packages/client/src/stores/derived/index.js +++ b/packages/client/src/stores/derived/index.js @@ -5,3 +5,4 @@ export { currentRole } from "./currentRole.js" export { dndComponentPath } from "./dndComponentPath.js" export { devToolsEnabled } from "./devToolsEnabled.js" export { snippets } from "./snippets.js" +export { componentErrors } from "./componentErrors" diff --git a/packages/client/src/utils/componentsValidator.ts b/packages/client/src/utils/componentsValidator.ts deleted file mode 100644 index 6609f92ed6..0000000000 --- a/packages/client/src/utils/componentsValidator.ts +++ /dev/null @@ -1,13 +0,0 @@ -const validators = { - checkValidDatasource: (a: any) => { - return `Ups... "${a.label}" not found` - }, -} - -export function validateComponentSetting( - key: keyof typeof validators, - value: any -) { - const validator = validators[key] - return validator(value) -} From 75dab572e956e7669ba8282c56c74be4e235f474 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Mon, 20 Jan 2025 20:06:02 +0100 Subject: [PATCH 05/38] Move data to builder --- .../design/[screenId]/_components/AppPreview.svelte | 3 +++ packages/client/src/index.js | 1 + packages/client/src/stores/builder.js | 4 +--- .../server/src/api/controllers/static/templates/preview.hbs | 4 +++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPreview.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPreview.svelte index 55a4dc4de4..661e985194 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPreview.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPreview.svelte @@ -68,6 +68,9 @@ port: window.location.port, }, snippets: $snippets, + componentErrors: { + c5ea93132725c48b2a365fcc1facaee86: ["Ups...!"], + }, // TODO } // Refresh the preview when required diff --git a/packages/client/src/index.js b/packages/client/src/index.js index 9cef52bb1e..7cb9ed4430 100644 --- a/packages/client/src/index.js +++ b/packages/client/src/index.js @@ -43,6 +43,7 @@ const loadBudibase = async () => { usedPlugins: window["##BUDIBASE_USED_PLUGINS##"], location: window["##BUDIBASE_LOCATION##"], snippets: window["##BUDIBASE_SNIPPETS##"], + componentErrors: window["##BUDIBASE_COMPONENT_ERRORS##"], }) // Set app ID - this window flag is set by both the preview and the real diff --git a/packages/client/src/stores/builder.js b/packages/client/src/stores/builder.js index 62123c07e5..1ae7d3a670 100644 --- a/packages/client/src/stores/builder.js +++ b/packages/client/src/stores/builder.js @@ -19,9 +19,7 @@ const createBuilderStore = () => { eventResolvers: {}, metadata: null, snippets: null, - componentErrors: { - c5ea93132725c48b2a365fcc1facaee86: ["Ups...!"], - }, // TODO + componentErrors: {}, // Legacy - allow the builder to specify a layout layout: null, diff --git a/packages/server/src/api/controllers/static/templates/preview.hbs b/packages/server/src/api/controllers/static/templates/preview.hbs index 87b9ad6ea3..750a780897 100644 --- a/packages/server/src/api/controllers/static/templates/preview.hbs +++ b/packages/server/src/api/controllers/static/templates/preview.hbs @@ -73,7 +73,8 @@ hiddenComponentIds, usedPlugins, location, - snippets + snippets, + componentErrors } = parsed // Set some flags so the app knows we're in the builder @@ -91,6 +92,7 @@ window["##BUDIBASE_USED_PLUGINS##"] = usedPlugins window["##BUDIBASE_LOCATION##"] = location window["##BUDIBASE_SNIPPETS##"] = snippets + window['##BUDIBASE_COMPONENT_ERRORS##'] = componentErrors // Initialise app try { From d1294c8d44e5ef9fac098ed823ae0b17ec37b24f Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 21 Jan 2025 12:38:31 +0100 Subject: [PATCH 06/38] Errors from store --- .../[screenId]/_components/AppPreview.svelte | 5 +- packages/builder/src/stores/builder/index.js | 2 + .../src/stores/builder/screenComponent.ts | 61 +++++++++++++++++++ 3 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 packages/builder/src/stores/builder/screenComponent.ts diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPreview.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPreview.svelte index 661e985194..fc0b67f63d 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPreview.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPreview.svelte @@ -11,6 +11,7 @@ selectedScreen, hoverStore, componentTreeNodesStore, + screenComponentStore, snippets, } from "@/stores/builder" import ConfirmDialog from "@/components/common/ConfirmDialog.svelte" @@ -68,9 +69,7 @@ port: window.location.port, }, snippets: $snippets, - componentErrors: { - c5ea93132725c48b2a365fcc1facaee86: ["Ups...!"], - }, // TODO + componentErrors: $screenComponentStore.errors, } // Refresh the preview when required diff --git a/packages/builder/src/stores/builder/index.js b/packages/builder/src/stores/builder/index.js index 08d87bebf5..23491996d1 100644 --- a/packages/builder/src/stores/builder/index.js +++ b/packages/builder/src/stores/builder/index.js @@ -16,6 +16,7 @@ import { userStore, userSelectedResourceMap, isOnlyUser } from "./users.js" import { deploymentStore } from "./deployments.js" import { contextMenuStore } from "./contextMenu.js" import { snippets } from "./snippets" +import { screenComponentStore } from "./screenComponent" // Backend import { tables } from "./tables" @@ -67,6 +68,7 @@ export { snippets, rowActions, appPublished, + screenComponentStore, } export const reset = () => { diff --git a/packages/builder/src/stores/builder/screenComponent.ts b/packages/builder/src/stores/builder/screenComponent.ts new file mode 100644 index 0000000000..b97bb7ba98 --- /dev/null +++ b/packages/builder/src/stores/builder/screenComponent.ts @@ -0,0 +1,61 @@ +import { derived } from "svelte/store" +import { tables, selectedScreen } from "@/stores/builder" +import { DerivedBudiStore } from "../BudiStore" +import { findComponentsBySettingsType } from "@/helpers/screen" +import { Screen } from "@budibase/types" + +interface BuilderScreenComponentStore {} + +interface DerivedScreenComponentStore extends BuilderScreenComponentStore { + errors: Record +} + +export class ScreenComponentStore extends DerivedBudiStore< + BuilderScreenComponentStore, + DerivedScreenComponentStore +> { + constructor() { + const makeDerivedStore = () => { + return derived( + [selectedScreen, tables], + ([$selectedScreen, $tables]): DerivedScreenComponentStore => { + function getErrors() { + const datasources = $tables.list.reduce( + (list, table) => ({ + ...list, + [table._id!]: table, + }), + {} + ) + return { + ...getInvalidDatasources($selectedScreen, datasources), + } + } + + return { + errors: getErrors(), + } + } + ) + } + + super({}, makeDerivedStore) + } +} + +export const screenComponentStore = new ScreenComponentStore() + +function getInvalidDatasources( + screen: Screen, + datasources: Record +) { + const result: Record = {} + for (const component of findComponentsBySettingsType(screen, "table")) { + const { resourceId, type, label } = component.dataSource + if (!datasources[resourceId]) { + result[component._id!] = [`The ${type} named "${label}" was removed`] + } + } + + return result +} From d5f34970ad9c632c06b8b9266bd247872584e8c3 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 21 Jan 2025 12:48:28 +0100 Subject: [PATCH 07/38] Use friendly name --- .../builder/src/stores/builder/screenComponent.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/builder/src/stores/builder/screenComponent.ts b/packages/builder/src/stores/builder/screenComponent.ts index b97bb7ba98..cb7e26bf93 100644 --- a/packages/builder/src/stores/builder/screenComponent.ts +++ b/packages/builder/src/stores/builder/screenComponent.ts @@ -53,9 +53,19 @@ function getInvalidDatasources( for (const component of findComponentsBySettingsType(screen, "table")) { const { resourceId, type, label } = component.dataSource if (!datasources[resourceId]) { - result[component._id!] = [`The ${type} named "${label}" was removed`] + const friendlyTypeName = + friendlyNameByType[type as keyof typeof friendlyNameByType] + result[component._id!] = [ + `The ${friendlyTypeName} named "${label}" was removed`, + ] } } return result } + +const friendlyNameByType = { + table: "table", + view: "view", + viewV2: "view", +} From 42e86554c881c01bc3f5fdc49bb83303af7158d7 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 21 Jan 2025 15:18:31 +0100 Subject: [PATCH 08/38] Validate views --- .../src/stores/builder/screenComponent.ts | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/packages/builder/src/stores/builder/screenComponent.ts b/packages/builder/src/stores/builder/screenComponent.ts index cb7e26bf93..dd2f7a8b1c 100644 --- a/packages/builder/src/stores/builder/screenComponent.ts +++ b/packages/builder/src/stores/builder/screenComponent.ts @@ -1,5 +1,5 @@ import { derived } from "svelte/store" -import { tables, selectedScreen } from "@/stores/builder" +import { tables, selectedScreen, viewsV2 } from "@/stores/builder" import { DerivedBudiStore } from "../BudiStore" import { findComponentsBySettingsType } from "@/helpers/screen" import { Screen } from "@budibase/types" @@ -17,16 +17,25 @@ export class ScreenComponentStore extends DerivedBudiStore< constructor() { const makeDerivedStore = () => { return derived( - [selectedScreen, tables], - ([$selectedScreen, $tables]): DerivedScreenComponentStore => { + [selectedScreen, tables, viewsV2], + ([$selectedScreen, $tables, $viewsV2]): DerivedScreenComponentStore => { function getErrors() { - const datasources = $tables.list.reduce( - (list, table) => ({ - ...list, - [table._id!]: table, - }), - {} - ) + const datasources = { + ...$tables.list.reduce( + (list, table) => ({ + ...list, + [table._id!]: table, + }), + {} + ), + ...$viewsV2.list.reduce( + (list, view) => ({ + ...list, + [view.id]: view, + }), + {} + ), + } return { ...getInvalidDatasources($selectedScreen, datasources), } From ec930372412b4ffc47878ddbc8de2d16aa2691a5 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 21 Jan 2025 15:19:45 +0100 Subject: [PATCH 09/38] Change error message --- packages/builder/src/stores/builder/screenComponent.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/builder/src/stores/builder/screenComponent.ts b/packages/builder/src/stores/builder/screenComponent.ts index dd2f7a8b1c..4b591cf0cf 100644 --- a/packages/builder/src/stores/builder/screenComponent.ts +++ b/packages/builder/src/stores/builder/screenComponent.ts @@ -65,7 +65,7 @@ function getInvalidDatasources( const friendlyTypeName = friendlyNameByType[type as keyof typeof friendlyNameByType] result[component._id!] = [ - `The ${friendlyTypeName} named "${label}" was removed`, + `The ${friendlyTypeName} named "${label}" does not exist`, ] } } From f32910b033863216393ef6466e6f73d5bdfa47bb Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 21 Jan 2025 15:30:04 +0100 Subject: [PATCH 10/38] Clean code --- .../src/stores/builder/screenComponent.ts | 53 +++++++++++-------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/packages/builder/src/stores/builder/screenComponent.ts b/packages/builder/src/stores/builder/screenComponent.ts index 4b591cf0cf..baa6520832 100644 --- a/packages/builder/src/stores/builder/screenComponent.ts +++ b/packages/builder/src/stores/builder/screenComponent.ts @@ -2,7 +2,7 @@ import { derived } from "svelte/store" import { tables, selectedScreen, viewsV2 } from "@/stores/builder" import { DerivedBudiStore } from "../BudiStore" import { findComponentsBySettingsType } from "@/helpers/screen" -import { Screen } from "@budibase/types" +import { Screen, Table, ViewV2 } from "@budibase/types" interface BuilderScreenComponentStore {} @@ -20,22 +20,10 @@ export class ScreenComponentStore extends DerivedBudiStore< [selectedScreen, tables, viewsV2], ([$selectedScreen, $tables, $viewsV2]): DerivedScreenComponentStore => { function getErrors() { - const datasources = { - ...$tables.list.reduce( - (list, table) => ({ - ...list, - [table._id!]: table, - }), - {} - ), - ...$viewsV2.list.reduce( - (list, view) => ({ - ...list, - [view.id]: view, - }), - {} - ), - } + const datasources = flattenTablesAndViews( + $tables.list, + $viewsV2.list + ) return { ...getInvalidDatasources($selectedScreen, datasources), } @@ -54,10 +42,35 @@ export class ScreenComponentStore extends DerivedBudiStore< export const screenComponentStore = new ScreenComponentStore() +function flattenTablesAndViews(tables: Table[], views: ViewV2[]) { + return { + ...tables.reduce( + (list, table) => ({ + ...list, + [table._id!]: table, + }), + {} + ), + ...views.reduce( + (list, view) => ({ + ...list, + [view.id]: view, + }), + {} + ), + } +} + function getInvalidDatasources( screen: Screen, datasources: Record ) { + const friendlyNameByType = { + table: "table", + view: "view", + viewV2: "view", + } + const result: Record = {} for (const component of findComponentsBySettingsType(screen, "table")) { const { resourceId, type, label } = component.dataSource @@ -72,9 +85,3 @@ function getInvalidDatasources( return result } - -const friendlyNameByType = { - table: "table", - view: "view", - viewV2: "view", -} From e1cc8da9dde735579b7f751b4513cdd33784782f Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 21 Jan 2025 15:31:16 +0100 Subject: [PATCH 11/38] Clean types --- packages/client/src/stores/derived/componentErrors.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/client/src/stores/derived/componentErrors.ts b/packages/client/src/stores/derived/componentErrors.ts index 48185de9c3..68e87a061d 100644 --- a/packages/client/src/stores/derived/componentErrors.ts +++ b/packages/client/src/stores/derived/componentErrors.ts @@ -2,5 +2,5 @@ import { derived } from "svelte/store" import { builderStore } from "../builder.js" export const componentErrors = derived([builderStore], ([$builderStore]) => { - return $builderStore.componentErrors as Record + return $builderStore.componentErrors }) From fc599767c21c23abe1d3aa14445fe5c614b42bea Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 21 Jan 2025 16:06:21 +0100 Subject: [PATCH 12/38] Fix imports --- .../src/stores/builder/screenComponent.ts | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/packages/builder/src/stores/builder/screenComponent.ts b/packages/builder/src/stores/builder/screenComponent.ts index baa6520832..b4eb01a3b7 100644 --- a/packages/builder/src/stores/builder/screenComponent.ts +++ b/packages/builder/src/stores/builder/screenComponent.ts @@ -1,5 +1,7 @@ import { derived } from "svelte/store" -import { tables, selectedScreen, viewsV2 } from "@/stores/builder" +import { tables } from "./tables" +import { selectedScreen } from "./screens" +import { viewsV2 } from "./viewsV2" import { DerivedBudiStore } from "../BudiStore" import { findComponentsBySettingsType } from "@/helpers/screen" import { Screen, Table, ViewV2 } from "@budibase/types" @@ -19,18 +21,9 @@ export class ScreenComponentStore extends DerivedBudiStore< return derived( [selectedScreen, tables, viewsV2], ([$selectedScreen, $tables, $viewsV2]): DerivedScreenComponentStore => { - function getErrors() { - const datasources = flattenTablesAndViews( - $tables.list, - $viewsV2.list - ) - return { - ...getInvalidDatasources($selectedScreen, datasources), - } - } - + const datasources = flattenTablesAndViews($tables.list, $viewsV2.list) return { - errors: getErrors(), + errors: getInvalidDatasources($selectedScreen, datasources), } } ) From cad6a08bf87570c2485cafc9538460a2cfee8f7e Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 22 Jan 2025 11:14:50 +0100 Subject: [PATCH 13/38] Move reactiviness --- packages/client/src/components/Component.svelte | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/client/src/components/Component.svelte b/packages/client/src/components/Component.svelte index 7f825c0601..57daf8cd12 100644 --- a/packages/client/src/components/Component.svelte +++ b/packages/client/src/components/Component.svelte @@ -139,6 +139,7 @@ // Derive definition properties which can all be optional, so need to be // coerced to booleans + $: invalidSettings = $componentErrors[instance._id] $: hasChildren = !!definition?.hasChildren $: showEmptyState = definition?.showEmptyState !== false $: hasMissingRequiredSettings = missingRequiredSettings?.length > 0 @@ -374,9 +375,6 @@ } } - // Check for invalid settings - $: invalidSettings = $componentErrors[id] - // Extracts a map of all context keys which are required by action settings // to provide the functions to evaluate at runtime. This needs done manually // as the action definitions themselves do not specify bindings for action From 4d85006c35e4d9b2643192902d077147069c6de8 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 22 Jan 2025 11:53:50 +0100 Subject: [PATCH 14/38] server nodemon, watch .hbs --- packages/server/nodemon.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server/nodemon.json b/packages/server/nodemon.json index ac8c38ccb2..9871b9339e 100644 --- a/packages/server/nodemon.json +++ b/packages/server/nodemon.json @@ -7,7 +7,7 @@ "../shared-core/src", "../string-templates/src" ], - "ext": "js,ts,json,svelte", + "ext": "js,ts,json,svelte,hbs", "ignore": [ "**/*.spec.ts", "**/*.spec.js", From 2213cd56c46c8f8204c98cd961dbd39482b57271 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 22 Jan 2025 12:18:55 +0100 Subject: [PATCH 15/38] Remove unnecessary derived --- packages/client/src/components/Component.svelte | 3 +-- packages/client/src/stores/derived/componentErrors.ts | 6 ------ packages/client/src/stores/derived/index.js | 1 - 3 files changed, 1 insertion(+), 9 deletions(-) delete mode 100644 packages/client/src/stores/derived/componentErrors.ts diff --git a/packages/client/src/components/Component.svelte b/packages/client/src/components/Component.svelte index 57daf8cd12..8d79de2ac4 100644 --- a/packages/client/src/components/Component.svelte +++ b/packages/client/src/components/Component.svelte @@ -23,7 +23,6 @@ appStore, dndComponentPath, dndIsDragging, - componentErrors, } from "stores" import { Helpers } from "@budibase/bbui" import { getActiveConditions, reduceConditionActions } from "utils/conditions" @@ -139,7 +138,7 @@ // Derive definition properties which can all be optional, so need to be // coerced to booleans - $: invalidSettings = $componentErrors[instance._id] + $: invalidSettings = $builderStore.componentErrors[instance._id] $: hasChildren = !!definition?.hasChildren $: showEmptyState = definition?.showEmptyState !== false $: hasMissingRequiredSettings = missingRequiredSettings?.length > 0 diff --git a/packages/client/src/stores/derived/componentErrors.ts b/packages/client/src/stores/derived/componentErrors.ts deleted file mode 100644 index 68e87a061d..0000000000 --- a/packages/client/src/stores/derived/componentErrors.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { derived } from "svelte/store" -import { builderStore } from "../builder.js" - -export const componentErrors = derived([builderStore], ([$builderStore]) => { - return $builderStore.componentErrors -}) diff --git a/packages/client/src/stores/derived/index.js b/packages/client/src/stores/derived/index.js index e7e70d8952..337c73831f 100644 --- a/packages/client/src/stores/derived/index.js +++ b/packages/client/src/stores/derived/index.js @@ -5,4 +5,3 @@ export { currentRole } from "./currentRole.js" export { dndComponentPath } from "./dndComponentPath.js" export { devToolsEnabled } from "./devToolsEnabled.js" export { snippets } from "./snippets.js" -export { componentErrors } from "./componentErrors" From d3b22e461e3f0f328bab54e4b2b58eb6d833e28e Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 22 Jan 2025 16:18:29 +0100 Subject: [PATCH 16/38] Handle errors as a part of the instance to avoid extra refreshes --- packages/client/src/components/Component.svelte | 2 +- packages/client/src/stores/screens.js | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/client/src/components/Component.svelte b/packages/client/src/components/Component.svelte index 8d79de2ac4..a86d43c676 100644 --- a/packages/client/src/components/Component.svelte +++ b/packages/client/src/components/Component.svelte @@ -138,7 +138,7 @@ // Derive definition properties which can all be optional, so need to be // coerced to booleans - $: invalidSettings = $builderStore.componentErrors[instance._id] + $: invalidSettings = instance?._meta?.errors $: hasChildren = !!definition?.hasChildren $: showEmptyState = definition?.showEmptyState !== false $: hasMissingRequiredSettings = missingRequiredSettings?.length > 0 diff --git a/packages/client/src/stores/screens.js b/packages/client/src/stores/screens.js index bc87216660..491d8d4236 100644 --- a/packages/client/src/stores/screens.js +++ b/packages/client/src/stores/screens.js @@ -42,6 +42,14 @@ const createScreenStore = () => { if ($builderStore.layout) { activeLayout = $builderStore.layout } + + // Attach meta + const errors = $builderStore.componentErrors || {} + const attachComponentMeta = component => { + component._meta = { errors: errors[component._id] || [] } + component._children?.forEach(attachComponentMeta) + } + attachComponentMeta(activeScreen.props) } else { // Find the correct screen by matching the current route screens = $appStore.screens || [] From 84c8507bad7e3ff8df572cf389e004f546be264b Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 22 Jan 2025 16:20:33 +0100 Subject: [PATCH 17/38] Renames --- packages/client/src/components/Component.svelte | 10 +++++----- .../components/error-states/ComponentErrorState.svelte | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/client/src/components/Component.svelte b/packages/client/src/components/Component.svelte index a86d43c676..236bcb7c7e 100644 --- a/packages/client/src/components/Component.svelte +++ b/packages/client/src/components/Component.svelte @@ -103,7 +103,7 @@ let settingsDefinition let settingsDefinitionMap let missingRequiredSettings = false - let invalidSettings = false + let componentErrors = false // Temporary styles which can be added in the app preview for things like // DND. We clear these whenever a new instance is received. @@ -138,12 +138,12 @@ // Derive definition properties which can all be optional, so need to be // coerced to booleans - $: invalidSettings = instance?._meta?.errors + $: componentErrors = instance?._meta?.errors $: hasChildren = !!definition?.hasChildren $: showEmptyState = definition?.showEmptyState !== false $: hasMissingRequiredSettings = missingRequiredSettings?.length > 0 $: editable = !!definition?.editable && !hasMissingRequiredSettings - $: hasInvalidSettings = invalidSettings?.length > 0 + $: hasComponentErrors = componentErrors?.length > 0 $: requiredAncestors = definition?.requiredAncestors || [] $: missingRequiredAncestors = requiredAncestors.filter( ancestor => !$component.ancestors.includes(`${BudibasePrefix}${ancestor}`) @@ -152,7 +152,7 @@ $: errorState = hasMissingRequiredSettings || hasMissingRequiredAncestors || - hasInvalidSettings + hasComponentErrors // Interactive components can be selected, dragged and highlighted inside // the builder preview @@ -698,7 +698,7 @@ {:else} diff --git a/packages/client/src/components/error-states/ComponentErrorState.svelte b/packages/client/src/components/error-states/ComponentErrorState.svelte index 8cf1ad6dfb..9eace07018 100644 --- a/packages/client/src/components/error-states/ComponentErrorState.svelte +++ b/packages/client/src/components/error-states/ComponentErrorState.svelte @@ -8,7 +8,7 @@ | { key: string; label: string }[] | undefined export let missingRequiredAncestors: string[] | undefined - export let invalidSettings: string[] | undefined + export let componentErrors: string[] | undefined const component = getContext("component") const { styleable, builderStore } = getContext("sdk") @@ -16,7 +16,7 @@ $: styles = { ...$component.styles, normal: {}, custom: null, empty: true } $: requiredSetting = missingRequiredSettings?.[0] $: requiredAncestor = missingRequiredAncestors?.[0] - $: invalidSetting = invalidSettings?.[0] + $: errorMessage = componentErrors?.[0] {#if $builderStore.inBuilder} @@ -25,8 +25,8 @@ {#if requiredAncestor} - {:else if invalidSetting} - {invalidSetting} + {:else if errorMessage} + {errorMessage} {:else if requiredSetting} {/if} From c9feae9665a33466e9486c7ca97a2f42b067142c Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 22 Jan 2025 16:26:09 +0100 Subject: [PATCH 18/38] Simplify derived screenComponentErrors --- .../[screenId]/_components/AppPreview.svelte | 4 +- packages/builder/src/stores/builder/index.js | 4 +- .../src/stores/builder/screenComponent.ts | 112 +++++++----------- 3 files changed, 49 insertions(+), 71 deletions(-) diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPreview.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPreview.svelte index fc0b67f63d..3951c0e902 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPreview.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPreview.svelte @@ -11,7 +11,7 @@ selectedScreen, hoverStore, componentTreeNodesStore, - screenComponentStore, + screenComponentErrors, snippets, } from "@/stores/builder" import ConfirmDialog from "@/components/common/ConfirmDialog.svelte" @@ -69,7 +69,7 @@ port: window.location.port, }, snippets: $snippets, - componentErrors: $screenComponentStore.errors, + componentErrors: $screenComponentErrors, } // Refresh the preview when required diff --git a/packages/builder/src/stores/builder/index.js b/packages/builder/src/stores/builder/index.js index 23491996d1..892b72c7ab 100644 --- a/packages/builder/src/stores/builder/index.js +++ b/packages/builder/src/stores/builder/index.js @@ -16,7 +16,7 @@ import { userStore, userSelectedResourceMap, isOnlyUser } from "./users.js" import { deploymentStore } from "./deployments.js" import { contextMenuStore } from "./contextMenu.js" import { snippets } from "./snippets" -import { screenComponentStore } from "./screenComponent" +import { screenComponentErrors } from "./screenComponent" // Backend import { tables } from "./tables" @@ -68,7 +68,7 @@ export { snippets, rowActions, appPublished, - screenComponentStore, + screenComponentErrors, } export const reset = () => { diff --git a/packages/builder/src/stores/builder/screenComponent.ts b/packages/builder/src/stores/builder/screenComponent.ts index b4eb01a3b7..19bafeade3 100644 --- a/packages/builder/src/stores/builder/screenComponent.ts +++ b/packages/builder/src/stores/builder/screenComponent.ts @@ -2,79 +2,57 @@ import { derived } from "svelte/store" import { tables } from "./tables" import { selectedScreen } from "./screens" import { viewsV2 } from "./viewsV2" -import { DerivedBudiStore } from "../BudiStore" import { findComponentsBySettingsType } from "@/helpers/screen" import { Screen, Table, ViewV2 } from "@budibase/types" -interface BuilderScreenComponentStore {} +export const screenComponentErrors = derived( + [selectedScreen, tables, viewsV2], + ([$selectedScreen, $tables, $viewsV2]): Record => { + function flattenTablesAndViews(tables: Table[], views: ViewV2[]) { + return { + ...tables.reduce( + (list, table) => ({ + ...list, + [table._id!]: table, + }), + {} + ), + ...views.reduce( + (list, view) => ({ + ...list, + [view.id]: view, + }), + {} + ), + } + } -interface DerivedScreenComponentStore extends BuilderScreenComponentStore { - errors: Record -} + function getInvalidDatasources( + screen: Screen, + datasources: Record + ) { + const friendlyNameByType = { + table: "table", + view: "view", + viewV2: "view", + } -export class ScreenComponentStore extends DerivedBudiStore< - BuilderScreenComponentStore, - DerivedScreenComponentStore -> { - constructor() { - const makeDerivedStore = () => { - return derived( - [selectedScreen, tables, viewsV2], - ([$selectedScreen, $tables, $viewsV2]): DerivedScreenComponentStore => { - const datasources = flattenTablesAndViews($tables.list, $viewsV2.list) - return { - errors: getInvalidDatasources($selectedScreen, datasources), - } + const result: Record = {} + for (const component of findComponentsBySettingsType(screen, "table")) { + const { resourceId, type, label } = component.dataSource + if (!datasources[resourceId]) { + const friendlyTypeName = + friendlyNameByType[type as keyof typeof friendlyNameByType] + result[component._id!] = [ + `The ${friendlyTypeName} named "${label}" does not exist`, + ] } - ) + } + + return result } - super({}, makeDerivedStore) + const datasources = flattenTablesAndViews($tables.list, $viewsV2.list) + return getInvalidDatasources($selectedScreen, datasources) } -} - -export const screenComponentStore = new ScreenComponentStore() - -function flattenTablesAndViews(tables: Table[], views: ViewV2[]) { - return { - ...tables.reduce( - (list, table) => ({ - ...list, - [table._id!]: table, - }), - {} - ), - ...views.reduce( - (list, view) => ({ - ...list, - [view.id]: view, - }), - {} - ), - } -} - -function getInvalidDatasources( - screen: Screen, - datasources: Record -) { - const friendlyNameByType = { - table: "table", - view: "view", - viewV2: "view", - } - - const result: Record = {} - for (const component of findComponentsBySettingsType(screen, "table")) { - const { resourceId, type, label } = component.dataSource - if (!datasources[resourceId]) { - const friendlyTypeName = - friendlyNameByType[type as keyof typeof friendlyNameByType] - result[component._id!] = [ - `The ${friendlyTypeName} named "${label}" does not exist`, - ] - } - } - - return result -} +) From 5c9cc915ff9c7e1da7538e282c02b6503bd006e3 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 22 Jan 2025 17:32:34 +0100 Subject: [PATCH 19/38] Remove magic string for settings --- packages/builder/src/helpers/screen.ts | 30 ++++++++++++++----- .../src/stores/builder/screenComponent.ts | 7 +++-- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/packages/builder/src/helpers/screen.ts b/packages/builder/src/helpers/screen.ts index e83805a511..71623844de 100644 --- a/packages/builder/src/helpers/screen.ts +++ b/packages/builder/src/helpers/screen.ts @@ -2,7 +2,13 @@ import { Component, Screen, ScreenProps } from "@budibase/types" import clientManifest from "@budibase/client/manifest.json" export function findComponentsBySettingsType(screen: Screen, type: string) { - const result: Component[] = [] + const result: { + component: Component + setting: { + type: string + key: string + } + }[] = [] function recurseFieldComponentsInChildren( component: ScreenProps, type: string @@ -11,14 +17,15 @@ export function findComponentsBySettingsType(screen: Screen, type: string) { return } - const componentType = component._component.split("/").slice(-1)[0] - const definition = - clientManifest[componentType as keyof typeof clientManifest] - if ( + const definition = getManifestDefinition(component) + const setting = "settings" in definition && - definition.settings.some((s: any) => s.type === type) - ) { - result.push(component) + definition.settings.find((s: any) => s.type === type) + if (setting && "type" in setting) { + result.push({ + component, + setting: { type: setting.type!, key: setting.key! }, + }) } component._children?.forEach(child => { recurseFieldComponentsInChildren(child, type) @@ -28,3 +35,10 @@ export function findComponentsBySettingsType(screen: Screen, type: string) { recurseFieldComponentsInChildren(screen?.props, type) return result } + +function getManifestDefinition(component: Component) { + const componentType = component._component.split("/").slice(-1)[0] + const definition = + clientManifest[componentType as keyof typeof clientManifest] + return definition +} diff --git a/packages/builder/src/stores/builder/screenComponent.ts b/packages/builder/src/stores/builder/screenComponent.ts index 19bafeade3..a061158e6a 100644 --- a/packages/builder/src/stores/builder/screenComponent.ts +++ b/packages/builder/src/stores/builder/screenComponent.ts @@ -38,8 +38,11 @@ export const screenComponentErrors = derived( } const result: Record = {} - for (const component of findComponentsBySettingsType(screen, "table")) { - const { resourceId, type, label } = component.dataSource + for (const { component, setting } of findComponentsBySettingsType( + screen, + "table" + )) { + const { resourceId, type, label } = component[setting.key] if (!datasources[resourceId]) { const friendlyTypeName = friendlyNameByType[type as keyof typeof friendlyNameByType] From 5d60da471484ab190129f06490f3a1aec9744639 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 23 Jan 2025 11:40:18 +0100 Subject: [PATCH 20/38] Fix null reference on viewV1 get schema --- packages/frontend-core/src/fetch/ViewFetch.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend-core/src/fetch/ViewFetch.ts b/packages/frontend-core/src/fetch/ViewFetch.ts index 6555896ae8..720f91eaab 100644 --- a/packages/frontend-core/src/fetch/ViewFetch.ts +++ b/packages/frontend-core/src/fetch/ViewFetch.ts @@ -21,7 +21,7 @@ export default class ViewFetch extends BaseDataFetch { getSchema(definition: Table) { const { datasource } = this.options - return definition?.views?.[datasource.name]?.schema + return definition?.views?.[datasource?.name]?.schema } async getData() { From fe2e93ee3e35ac35a64faf6569603eb80e8ac261 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 23 Jan 2025 11:53:09 +0100 Subject: [PATCH 21/38] Remove todos --- .../src/components/grid/stores/datasource.ts | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/packages/frontend-core/src/components/grid/stores/datasource.ts b/packages/frontend-core/src/components/grid/stores/datasource.ts index 588f373152..ebeade1050 100644 --- a/packages/frontend-core/src/components/grid/stores/datasource.ts +++ b/packages/frontend-core/src/components/grid/stores/datasource.ts @@ -1,5 +1,3 @@ -// TODO: datasource and defitions are unions of the different implementations. At this point, the datasource does not know what type is being used, and the assignations will cause TS exceptions. Casting it "as any" for now. This should be fixed improving the type usages. - import { derived, get, Readable, Writable } from "svelte/store" import { DataFetchDefinition, @@ -10,12 +8,10 @@ import { enrichSchemaWithRelColumns, memo } from "../../../utils" import { cloneDeep } from "lodash" import { SaveRowRequest, - SaveTableRequest, UIDatasource, UIFieldMutation, UIFieldSchema, UIRow, - UpdateViewRequest, ViewV2Type, } from "@budibase/types" import { Store as StoreContext, BaseStoreProps } from "." @@ -79,7 +75,7 @@ export const deriveStores = (context: StoreContext): DerivedDatasourceStore => { const schema = derived(definition, $definition => { const schema: Record | undefined = getDatasourceSchema({ API, - datasource: get(datasource) as any, // TODO: see line 1 + datasource: get(datasource), definition: $definition ?? undefined, }) if (!schema) { @@ -137,7 +133,7 @@ export const deriveStores = (context: StoreContext): DerivedDatasourceStore => { let type = $datasource?.type // @ts-expect-error if (type === "provider") { - type = ($datasource as any).value?.datasource?.type // TODO: see line 1 + type = ($datasource as any).value?.datasource?.type } // Handle calculation views if ( @@ -196,15 +192,13 @@ export const createActions = (context: StoreContext): ActionDatasourceStore => { const refreshDefinition = async () => { const def = await getDatasourceDefinition({ API, - datasource: get(datasource) as any, // TODO: see line 1 + datasource: get(datasource), }) - definition.set(def as any) // TODO: see line 1 + definition.set(def ?? null) } // Saves the datasource definition - const saveDefinition = async ( - newDefinition: SaveTableRequest | UpdateViewRequest - ) => { + const saveDefinition = async (newDefinition: DataFetchDefinition) => { // Update local state const originalDefinition = get(definition) definition.set(newDefinition) @@ -212,7 +206,7 @@ export const createActions = (context: StoreContext): ActionDatasourceStore => { // Update server if (get(config).canSaveSchema) { try { - await getAPI()?.actions.saveDefinition(newDefinition as never) + await getAPI()?.actions.saveDefinition(newDefinition) // Broadcast change so external state can be updated, as this change // will not be received by the builder websocket because we caused it @@ -245,7 +239,7 @@ export const createActions = (context: StoreContext): ActionDatasourceStore => { delete newDefinition.schema[column].default } } - return await saveDefinition(newDefinition as any) // TODO: see line 1 + return await saveDefinition(newDefinition) } // Adds a schema mutation for a single field @@ -321,7 +315,7 @@ export const createActions = (context: StoreContext): ActionDatasourceStore => { await saveDefinition({ ...$definition, schema: newSchema, - } as any) // TODO: see line 1 + }) resetSchemaMutations() } From 5f508ad7ca35b45151fdda4f931a46c1c476a714 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 23 Jan 2025 12:07:12 +0100 Subject: [PATCH 22/38] Fix type --- packages/frontend-core/src/components/grid/stores/datasource.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend-core/src/components/grid/stores/datasource.ts b/packages/frontend-core/src/components/grid/stores/datasource.ts index ebeade1050..5934c7c636 100644 --- a/packages/frontend-core/src/components/grid/stores/datasource.ts +++ b/packages/frontend-core/src/components/grid/stores/datasource.ts @@ -206,7 +206,7 @@ export const createActions = (context: StoreContext): ActionDatasourceStore => { // Update server if (get(config).canSaveSchema) { try { - await getAPI()?.actions.saveDefinition(newDefinition) + await getAPI()?.actions.saveDefinition(newDefinition as never) // Broadcast change so external state can be updated, as this change // will not be received by the builder websocket because we caused it From 19bfd71096788096e584018088ca3514ed266282 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 23 Jan 2025 12:25:10 +0100 Subject: [PATCH 23/38] Update types --- packages/frontend-core/src/fetch/index.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/frontend-core/src/fetch/index.ts b/packages/frontend-core/src/fetch/index.ts index e12e74340c..547043145d 100644 --- a/packages/frontend-core/src/fetch/index.ts +++ b/packages/frontend-core/src/fetch/index.ts @@ -101,12 +101,12 @@ export const fetchData = < // Creates an empty fetch instance with no datasource configured, so no data // will initially be loaded -const createEmptyFetchInstance = ({ +const createEmptyFetchInstance = ({ API, datasource, }: { API: APIClient - datasource: DataFetchDatasource + datasource: T }) => { const handler = DataFetchMap[datasource?.type] if (!handler) { @@ -114,7 +114,7 @@ const createEmptyFetchInstance = ({ } return new handler({ API, - datasource: null as never, + datasource: datasource as any, query: null as any, }) } From 4c48ad6526d46308a22e7b38733447d07fbe30ec Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 23 Jan 2025 15:26:18 +0100 Subject: [PATCH 24/38] Fix selected item for views v1 --- .../DataSourceSelect/DataSourceCategory.svelte | 16 ++++++++++++++-- .../DataSourceSelect/DataSourceSelect.svelte | 1 + 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/packages/builder/src/components/design/settings/controls/DataSourceSelect/DataSourceCategory.svelte b/packages/builder/src/components/design/settings/controls/DataSourceSelect/DataSourceCategory.svelte index 72e2fbf638..4ea8c63087 100644 --- a/packages/builder/src/components/design/settings/controls/DataSourceSelect/DataSourceCategory.svelte +++ b/packages/builder/src/components/design/settings/controls/DataSourceSelect/DataSourceCategory.svelte @@ -7,8 +7,21 @@ export let dataSet export let value export let onSelect + export let identifiers = ["resourceId"] $: displayDatasourceName = $datasources.list.length > 1 + + function isSelected(entry) { + if (!identifiers.length) { + return false + } + for (const identifier of identifiers) { + if (entry[identifier] !== value?.[identifier]) { + return false + } + } + return true + } {#if dividerState} @@ -24,8 +37,7 @@ {#each dataSet as data}
  • {/if} {#if queries?.length} From 8f02dff5cdfcbbf7f93f3d85be95b2cdeff1cef8 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 23 Jan 2025 15:29:59 +0100 Subject: [PATCH 25/38] Fix link selector --- .../settings/controls/DataSourceSelect/DataSourceSelect.svelte | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/builder/src/components/design/settings/controls/DataSourceSelect/DataSourceSelect.svelte b/packages/builder/src/components/design/settings/controls/DataSourceSelect/DataSourceSelect.svelte index 7c13032e42..1b7acd4a11 100644 --- a/packages/builder/src/components/design/settings/controls/DataSourceSelect/DataSourceSelect.svelte +++ b/packages/builder/src/components/design/settings/controls/DataSourceSelect/DataSourceSelect.svelte @@ -310,6 +310,7 @@ dataSet={links} {value} onSelect={handleSelected} + identifiers={["tableId", "fieldName"]} /> {/if} {#if fields?.length} From 102fbe9372e05e0a570bdc47068e15cd99309a2e Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 23 Jan 2025 15:31:07 +0100 Subject: [PATCH 26/38] Fix provider selector --- .../settings/controls/DataSourceSelect/DataSourceSelect.svelte | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/builder/src/components/design/settings/controls/DataSourceSelect/DataSourceSelect.svelte b/packages/builder/src/components/design/settings/controls/DataSourceSelect/DataSourceSelect.svelte index 1b7acd4a11..f8ee0876e7 100644 --- a/packages/builder/src/components/design/settings/controls/DataSourceSelect/DataSourceSelect.svelte +++ b/packages/builder/src/components/design/settings/controls/DataSourceSelect/DataSourceSelect.svelte @@ -338,6 +338,7 @@ dataSet={dataProviders} {value} onSelect={handleSelected} + identifiers={["providerId"]} /> {/if} Date: Thu, 23 Jan 2025 15:38:09 +0100 Subject: [PATCH 27/38] Fix fields selector --- .../settings/controls/DataSourceSelect/DataSourceSelect.svelte | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/builder/src/components/design/settings/controls/DataSourceSelect/DataSourceSelect.svelte b/packages/builder/src/components/design/settings/controls/DataSourceSelect/DataSourceSelect.svelte index f8ee0876e7..1b9fdcdf10 100644 --- a/packages/builder/src/components/design/settings/controls/DataSourceSelect/DataSourceSelect.svelte +++ b/packages/builder/src/components/design/settings/controls/DataSourceSelect/DataSourceSelect.svelte @@ -301,6 +301,7 @@ dataSet={queries} {value} onSelect={handleSelected} + identifiers={["_id"]} /> {/if} {#if links?.length} @@ -320,6 +321,7 @@ dataSet={fields} {value} onSelect={handleSelected} + identifiers={["providerId", "tableId", "fieldName"]} /> {/if} {#if jsonArrays?.length} @@ -329,6 +331,7 @@ dataSet={jsonArrays} {value} onSelect={handleSelected} + identifiers={["providerId", "tableId", "fieldName"]} /> {/if} {#if showDataProviders && dataProviders?.length} From 10a669e1d7a68093fa36f603d951ba653246ab73 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 22 Jan 2025 17:16:11 +0100 Subject: [PATCH 28/38] Support searching for multiple types --- packages/builder/src/helpers/screen.ts | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/packages/builder/src/helpers/screen.ts b/packages/builder/src/helpers/screen.ts index 71623844de..296a597adb 100644 --- a/packages/builder/src/helpers/screen.ts +++ b/packages/builder/src/helpers/screen.ts @@ -1,7 +1,12 @@ import { Component, Screen, ScreenProps } from "@budibase/types" import clientManifest from "@budibase/client/manifest.json" -export function findComponentsBySettingsType(screen: Screen, type: string) { +export function findComponentsBySettingsType( + screen: Screen, + type: string | string[] +) { + const typesArray = Array.isArray(type) ? type : [type] + const result: { component: Component setting: { @@ -9,10 +14,7 @@ export function findComponentsBySettingsType(screen: Screen, type: string) { key: string } }[] = [] - function recurseFieldComponentsInChildren( - component: ScreenProps, - type: string - ) { + function recurseFieldComponentsInChildren(component: ScreenProps) { if (!component) { return } @@ -20,7 +22,7 @@ export function findComponentsBySettingsType(screen: Screen, type: string) { const definition = getManifestDefinition(component) const setting = "settings" in definition && - definition.settings.find((s: any) => s.type === type) + definition.settings.find((s: any) => typesArray.includes(s.type)) if (setting && "type" in setting) { result.push({ component, @@ -28,11 +30,11 @@ export function findComponentsBySettingsType(screen: Screen, type: string) { }) } component._children?.forEach(child => { - recurseFieldComponentsInChildren(child, type) + recurseFieldComponentsInChildren(child) }) } - recurseFieldComponentsInChildren(screen?.props, type) + recurseFieldComponentsInChildren(screen?.props) return result } From 1c23763813e49d9b320a12faa821f09d0f815c45 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 22 Jan 2025 17:38:08 +0100 Subject: [PATCH 29/38] Handle dataSources as well --- packages/builder/src/stores/builder/screenComponent.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/builder/src/stores/builder/screenComponent.ts b/packages/builder/src/stores/builder/screenComponent.ts index a061158e6a..426fcbc58a 100644 --- a/packages/builder/src/stores/builder/screenComponent.ts +++ b/packages/builder/src/stores/builder/screenComponent.ts @@ -40,7 +40,7 @@ export const screenComponentErrors = derived( const result: Record = {} for (const { component, setting } of findComponentsBySettingsType( screen, - "table" + ["table", "dataSource"] )) { const { resourceId, type, label } = component[setting.key] if (!datasources[resourceId]) { From 1f3c466028ca1166ea94d4714e2e27e80803d4cf Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 22 Jan 2025 18:00:03 +0100 Subject: [PATCH 30/38] DRY --- .../src/stores/builder/screenComponent.ts | 44 +++++++++---------- 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/packages/builder/src/stores/builder/screenComponent.ts b/packages/builder/src/stores/builder/screenComponent.ts index 426fcbc58a..6db9f43241 100644 --- a/packages/builder/src/stores/builder/screenComponent.ts +++ b/packages/builder/src/stores/builder/screenComponent.ts @@ -3,37 +3,29 @@ import { tables } from "./tables" import { selectedScreen } from "./screens" import { viewsV2 } from "./viewsV2" import { findComponentsBySettingsType } from "@/helpers/screen" -import { Screen, Table, ViewV2 } from "@budibase/types" +import { Screen } from "@budibase/types" + +function reduceBy( + key: TKey, + list: TItem[] +) { + return list.reduce( + (result, item) => ({ + ...result, + [item[key] as string]: item, + }), + {} + ) +} export const screenComponentErrors = derived( [selectedScreen, tables, viewsV2], ([$selectedScreen, $tables, $viewsV2]): Record => { - function flattenTablesAndViews(tables: Table[], views: ViewV2[]) { - return { - ...tables.reduce( - (list, table) => ({ - ...list, - [table._id!]: table, - }), - {} - ), - ...views.reduce( - (list, view) => ({ - ...list, - [view.id]: view, - }), - {} - ), - } - } - function getInvalidDatasources( screen: Screen, datasources: Record ) { const friendlyNameByType = { - table: "table", - view: "view", viewV2: "view", } @@ -45,7 +37,7 @@ export const screenComponentErrors = derived( const { resourceId, type, label } = component[setting.key] if (!datasources[resourceId]) { const friendlyTypeName = - friendlyNameByType[type as keyof typeof friendlyNameByType] + friendlyNameByType[type as keyof typeof friendlyNameByType] ?? type result[component._id!] = [ `The ${friendlyTypeName} named "${label}" does not exist`, ] @@ -55,7 +47,11 @@ export const screenComponentErrors = derived( return result } - const datasources = flattenTablesAndViews($tables.list, $viewsV2.list) + const datasources = { + ...reduceBy("_id", $tables.list), + ...reduceBy("id", $viewsV2.list), + } + return getInvalidDatasources($selectedScreen, datasources) } ) From 41b65a6b1df471d37fd04e9146f2ea7e9057f7dc Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 23 Jan 2025 11:03:52 +0100 Subject: [PATCH 31/38] Validate queries --- .../src/stores/builder/screenComponent.ts | 29 +++++++++++++++---- .../types/src/documents/app/datasource.ts | 2 ++ 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/packages/builder/src/stores/builder/screenComponent.ts b/packages/builder/src/stores/builder/screenComponent.ts index 6db9f43241..a9444aee8c 100644 --- a/packages/builder/src/stores/builder/screenComponent.ts +++ b/packages/builder/src/stores/builder/screenComponent.ts @@ -3,7 +3,8 @@ import { tables } from "./tables" import { selectedScreen } from "./screens" import { viewsV2 } from "./viewsV2" import { findComponentsBySettingsType } from "@/helpers/screen" -import { Screen } from "@budibase/types" +import { DatasourceType, Screen } from "@budibase/types" +import { queries } from "./queries" function reduceBy( key: TKey, @@ -19,22 +20,39 @@ function reduceBy( } export const screenComponentErrors = derived( - [selectedScreen, tables, viewsV2], - ([$selectedScreen, $tables, $viewsV2]): Record => { + [selectedScreen, tables, viewsV2, queries], + ([$selectedScreen, $tables, $viewsV2, $queries]): Record< + string, + string[] + > => { function getInvalidDatasources( screen: Screen, datasources: Record ) { - const friendlyNameByType = { + const friendlyNameByType: Partial> = { viewV2: "view", } + const primaryKeyByType: Record = { + table: "resourceId", + view: "TODO", + viewV2: "resourceId", + query: "_id", + custom: "" as never, + } + const result: Record = {} for (const { component, setting } of findComponentsBySettingsType( screen, ["table", "dataSource"] )) { - const { resourceId, type, label } = component[setting.key] + const componentSettings = component[setting.key] + const { type, label } = componentSettings + if (type === "custom") { + continue + } + const resourceId = + componentSettings[primaryKeyByType[type as DatasourceType]] if (!datasources[resourceId]) { const friendlyTypeName = friendlyNameByType[type as keyof typeof friendlyNameByType] ?? type @@ -50,6 +68,7 @@ export const screenComponentErrors = derived( const datasources = { ...reduceBy("_id", $tables.list), ...reduceBy("id", $viewsV2.list), + ...reduceBy("_id", $queries.list), } return getInvalidDatasources($selectedScreen, datasources) diff --git a/packages/types/src/documents/app/datasource.ts b/packages/types/src/documents/app/datasource.ts index a0be7bd80d..27828c5455 100644 --- a/packages/types/src/documents/app/datasource.ts +++ b/packages/types/src/documents/app/datasource.ts @@ -57,3 +57,5 @@ export interface RestConfig { } dynamicVariables?: DynamicVariable[] } + +export type DatasourceType = "table" | "view" | "viewV2" | "query" | "custom" From 6e615a9907b0dc4508ccb921e5113bf3fa93779e Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 23 Jan 2025 11:19:49 +0100 Subject: [PATCH 32/38] Validate views v1 --- .../builder/src/stores/builder/screenComponent.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/builder/src/stores/builder/screenComponent.ts b/packages/builder/src/stores/builder/screenComponent.ts index a9444aee8c..2803acc953 100644 --- a/packages/builder/src/stores/builder/screenComponent.ts +++ b/packages/builder/src/stores/builder/screenComponent.ts @@ -5,6 +5,7 @@ import { viewsV2 } from "./viewsV2" import { findComponentsBySettingsType } from "@/helpers/screen" import { DatasourceType, Screen } from "@budibase/types" import { queries } from "./queries" +import { views } from "./views" function reduceBy( key: TKey, @@ -20,8 +21,8 @@ function reduceBy( } export const screenComponentErrors = derived( - [selectedScreen, tables, viewsV2, queries], - ([$selectedScreen, $tables, $viewsV2, $queries]): Record< + [selectedScreen, tables, views, viewsV2, queries], + ([$selectedScreen, $tables, $views, $viewsV2, $queries]): Record< string, string[] > => { @@ -34,9 +35,9 @@ export const screenComponentErrors = derived( } const primaryKeyByType: Record = { - table: "resourceId", - view: "TODO", - viewV2: "resourceId", + table: "tableId", + view: "name", + viewV2: "id", query: "_id", custom: "" as never, } @@ -67,6 +68,7 @@ export const screenComponentErrors = derived( const datasources = { ...reduceBy("_id", $tables.list), + ...reduceBy("name", $views.list), ...reduceBy("id", $viewsV2.list), ...reduceBy("_id", $queries.list), } From 92e2ae46f54f7e2f88baec2a72a08613106a4c76 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 23 Jan 2025 16:17:08 +0100 Subject: [PATCH 33/38] Center error message --- .../src/components/error-states/ComponentErrorState.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/client/src/components/error-states/ComponentErrorState.svelte b/packages/client/src/components/error-states/ComponentErrorState.svelte index 9eace07018..7069b7a431 100644 --- a/packages/client/src/components/error-states/ComponentErrorState.svelte +++ b/packages/client/src/components/error-states/ComponentErrorState.svelte @@ -38,7 +38,7 @@ .component-placeholder { display: flex; flex-direction: row; - justify-content: flex-start; + justify-content: center; align-items: center; color: var(--spectrum-global-color-gray-600); font-size: var(--font-size-s); From cf9b61c8c80a889c41a3cc017e431239aa70d3fc Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Thu, 23 Jan 2025 17:35:50 +0000 Subject: [PATCH 34/38] Fix selecting 'old row' in row updated trigger. --- .../automation/SetupPanel/AutomationBlockSetup.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte b/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte index 16183ea59a..e713d9bc85 100644 --- a/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte +++ b/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte @@ -293,7 +293,7 @@ type: RowSelector, props: { row: inputData["oldRow"] || { - tableId: inputData["row"].tableId, + tableId: inputData["row"]?.tableId, }, meta: { fields: inputData["meta"]?.oldFields || {}, From 388a94aee1f7b13e2baf3527a89103efff649499 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 23 Jan 2025 19:34:03 +0100 Subject: [PATCH 35/38] Add feature flag for datasource setting checks --- packages/builder/src/helpers/index.ts | 1 + packages/builder/src/stores/builder/screenComponent.ts | 6 ++++++ packages/types/src/sdk/featureFlag.ts | 2 ++ 3 files changed, 9 insertions(+) diff --git a/packages/builder/src/helpers/index.ts b/packages/builder/src/helpers/index.ts index 687723e361..81afc696a3 100644 --- a/packages/builder/src/helpers/index.ts +++ b/packages/builder/src/helpers/index.ts @@ -9,3 +9,4 @@ export { lowercase, isBuilderInputFocused, } from "./helpers" +export * as featureFlag from "./featureFlags" diff --git a/packages/builder/src/stores/builder/screenComponent.ts b/packages/builder/src/stores/builder/screenComponent.ts index a061158e6a..079401891c 100644 --- a/packages/builder/src/stores/builder/screenComponent.ts +++ b/packages/builder/src/stores/builder/screenComponent.ts @@ -5,9 +5,15 @@ import { viewsV2 } from "./viewsV2" import { findComponentsBySettingsType } from "@/helpers/screen" import { Screen, Table, ViewV2 } from "@budibase/types" +import { featureFlag } from "@/helpers" + export const screenComponentErrors = derived( [selectedScreen, tables, viewsV2], ([$selectedScreen, $tables, $viewsV2]): Record => { + if (!featureFlag.isEnabled("CHECK_SCREEN_COMPONENT_SETTINGS_ERRORS")) { + return {} + } + function flattenTablesAndViews(tables: Table[], views: ViewV2[]) { return { ...tables.reduce( diff --git a/packages/types/src/sdk/featureFlag.ts b/packages/types/src/sdk/featureFlag.ts index 996d3bba8d..d9f092c80a 100644 --- a/packages/types/src/sdk/featureFlag.ts +++ b/packages/types/src/sdk/featureFlag.ts @@ -1,5 +1,6 @@ export enum FeatureFlag { USE_ZOD_VALIDATOR = "USE_ZOD_VALIDATOR", + CHECK_SCREEN_COMPONENT_SETTINGS_ERRORS = "CHECK_SCREEN_COMPONENT_SETTINGS_ERRORS", // Account-portal DIRECT_LOGIN_TO_ACCOUNT_PORTAL = "DIRECT_LOGIN_TO_ACCOUNT_PORTAL", @@ -7,6 +8,7 @@ export enum FeatureFlag { export const FeatureFlagDefaults = { [FeatureFlag.USE_ZOD_VALIDATOR]: false, + [FeatureFlag.CHECK_SCREEN_COMPONENT_SETTINGS_ERRORS]: false, // Account-portal [FeatureFlag.DIRECT_LOGIN_TO_ACCOUNT_PORTAL]: false, From afee1ac993a4547791f8504d975f447ac40fd70b Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 24 Jan 2025 09:42:29 +0100 Subject: [PATCH 36/38] Whitelist checks --- .../src/stores/builder/screenComponent.ts | 39 ++++++++++--------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/packages/builder/src/stores/builder/screenComponent.ts b/packages/builder/src/stores/builder/screenComponent.ts index 2803acc953..6578334310 100644 --- a/packages/builder/src/stores/builder/screenComponent.ts +++ b/packages/builder/src/stores/builder/screenComponent.ts @@ -20,6 +20,18 @@ function reduceBy( ) } +const friendlyNameByType: Partial> = { + viewV2: "view", +} + +const validationKeyByType: Record = { + table: "tableId", + view: "name", + viewV2: "id", + query: "_id", + custom: null, +} + export const screenComponentErrors = derived( [selectedScreen, tables, views, viewsV2, queries], ([$selectedScreen, $tables, $views, $viewsV2, $queries]): Record< @@ -30,35 +42,24 @@ export const screenComponentErrors = derived( screen: Screen, datasources: Record ) { - const friendlyNameByType: Partial> = { - viewV2: "view", - } - - const primaryKeyByType: Record = { - table: "tableId", - view: "name", - viewV2: "id", - query: "_id", - custom: "" as never, - } - const result: Record = {} for (const { component, setting } of findComponentsBySettingsType( screen, ["table", "dataSource"] )) { const componentSettings = component[setting.key] - const { type, label } = componentSettings - if (type === "custom") { + const { label } = componentSettings + const type = componentSettings as DatasourceType + + const validationKey = validationKeyByType[type] + if (!validationKey) { continue } - const resourceId = - componentSettings[primaryKeyByType[type as DatasourceType]] + const resourceId = componentSettings[validationKey] if (!datasources[resourceId]) { - const friendlyTypeName = - friendlyNameByType[type as keyof typeof friendlyNameByType] ?? type + const friendlyTypeName = friendlyNameByType[type] ?? type result[component._id!] = [ - `The ${friendlyTypeName} named "${label}" does not exist`, + `The ${friendlyTypeName} named "${label}" could not be found`, ] } } From 8497a060407870973d8fe0494b71056df00d932c Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 24 Jan 2025 09:53:37 +0100 Subject: [PATCH 37/38] Fix --- packages/builder/src/stores/builder/screenComponent.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/builder/src/stores/builder/screenComponent.ts b/packages/builder/src/stores/builder/screenComponent.ts index 6578334310..6fb1a7d134 100644 --- a/packages/builder/src/stores/builder/screenComponent.ts +++ b/packages/builder/src/stores/builder/screenComponent.ts @@ -49,7 +49,7 @@ export const screenComponentErrors = derived( )) { const componentSettings = component[setting.key] const { label } = componentSettings - const type = componentSettings as DatasourceType + const type = componentSettings.type as DatasourceType const validationKey = validationKeyByType[type] if (!validationKey) { From 1f28bf978b79e804d6dbf5bb44db9a4f887574e8 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 24 Jan 2025 10:23:02 +0100 Subject: [PATCH 38/38] Move type to ui --- packages/builder/src/stores/builder/screenComponent.ts | 8 ++++---- packages/types/src/documents/app/datasource.ts | 2 -- packages/types/src/ui/datasource.ts | 1 + packages/types/src/ui/index.ts | 1 + 4 files changed, 6 insertions(+), 6 deletions(-) create mode 100644 packages/types/src/ui/datasource.ts diff --git a/packages/builder/src/stores/builder/screenComponent.ts b/packages/builder/src/stores/builder/screenComponent.ts index 547a8170a8..d8169fdedb 100644 --- a/packages/builder/src/stores/builder/screenComponent.ts +++ b/packages/builder/src/stores/builder/screenComponent.ts @@ -3,7 +3,7 @@ import { tables } from "./tables" import { selectedScreen } from "./screens" import { viewsV2 } from "./viewsV2" import { findComponentsBySettingsType } from "@/helpers/screen" -import { DatasourceType, Screen } from "@budibase/types" +import { UIDatasourceType, Screen } from "@budibase/types" import { queries } from "./queries" import { views } from "./views" import { featureFlag } from "@/helpers" @@ -21,11 +21,11 @@ function reduceBy( ) } -const friendlyNameByType: Partial> = { +const friendlyNameByType: Partial> = { viewV2: "view", } -const validationKeyByType: Record = { +const validationKeyByType: Record = { table: "tableId", view: "name", viewV2: "id", @@ -53,7 +53,7 @@ export const screenComponentErrors = derived( )) { const componentSettings = component[setting.key] const { label } = componentSettings - const type = componentSettings.type as DatasourceType + const type = componentSettings.type as UIDatasourceType const validationKey = validationKeyByType[type] if (!validationKey) { diff --git a/packages/types/src/documents/app/datasource.ts b/packages/types/src/documents/app/datasource.ts index 27828c5455..a0be7bd80d 100644 --- a/packages/types/src/documents/app/datasource.ts +++ b/packages/types/src/documents/app/datasource.ts @@ -57,5 +57,3 @@ export interface RestConfig { } dynamicVariables?: DynamicVariable[] } - -export type DatasourceType = "table" | "view" | "viewV2" | "query" | "custom" diff --git a/packages/types/src/ui/datasource.ts b/packages/types/src/ui/datasource.ts new file mode 100644 index 0000000000..53740e8c4d --- /dev/null +++ b/packages/types/src/ui/datasource.ts @@ -0,0 +1 @@ +export type UIDatasourceType = "table" | "view" | "viewV2" | "query" | "custom" diff --git a/packages/types/src/ui/index.ts b/packages/types/src/ui/index.ts index 907f4ec0b5..6e5f37608c 100644 --- a/packages/types/src/ui/index.ts +++ b/packages/types/src/ui/index.ts @@ -2,3 +2,4 @@ export * from "./stores" export * from "./bindings" export * from "./components" export * from "./dataFetch" +export * from "./datasource"