diff --git a/packages/builder/src/helpers/duplicate.ts b/packages/builder/src/helpers/duplicate.ts index b4740b3e52..eb705c6525 100644 --- a/packages/builder/src/helpers/duplicate.ts +++ b/packages/builder/src/helpers/duplicate.ts @@ -76,13 +76,15 @@ export const getSequentialName = ( { getName, numberFirstItem, + separator = "", }: { getName?: (item: T) => string numberFirstItem?: boolean + separator?: string } = {} ) => { if (!prefix?.length) { - return null + return "" } const trimmedPrefix = prefix.trim() const firstName = numberFirstItem ? `${prefix}1` : trimmedPrefix @@ -107,5 +109,5 @@ export const getSequentialName = ( max = num } }) - return max === 0 ? firstName : `${prefix}${max + 1}` + return max === 0 ? firstName : `${prefix}${separator}${max + 1}` } diff --git a/packages/builder/src/helpers/tests/duplicate.test.ts b/packages/builder/src/helpers/tests/duplicate.test.ts index 131e76a6c2..5e956d7b1c 100644 --- a/packages/builder/src/helpers/tests/duplicate.test.ts +++ b/packages/builder/src/helpers/tests/duplicate.test.ts @@ -49,7 +49,7 @@ describe("getSequentialName", () => { it("handles nullish prefix", async () => { const name = getSequentialName([], null) - expect(name).toBe(null) + expect(name).toBe("") }) it("handles just the prefix", async () => { diff --git a/packages/builder/src/stores/builder/components.ts b/packages/builder/src/stores/builder/components.ts index 90e1abfecf..6693cbf4dc 100644 --- a/packages/builder/src/stores/builder/components.ts +++ b/packages/builder/src/stores/builder/components.ts @@ -20,6 +20,7 @@ import { previewStore, tables, componentTreeNodesStore, + screenComponents, } from "@/stores/builder" import { buildFormSchema, getSchemaForDatasource } from "@/dataBinding" import { @@ -37,6 +38,7 @@ import { Table, } from "@budibase/types" import { utils } from "@budibase/shared-core" +import { getSequentialName } from "@/helpers/duplicate" interface Component extends ComponentType { _id: string @@ -452,7 +454,7 @@ export class ComponentStore extends BudiStore { * @returns */ createInstance( - componentName: string, + componentType: string, presetProps: any, parent: any ): Component | null { @@ -461,11 +463,20 @@ export class ComponentStore extends BudiStore { throw "A valid screen must be selected" } - const definition = this.getDefinition(componentName) + const definition = this.getDefinition(componentType) if (!definition) { return null } + const componentName = getSequentialName( + get(screenComponents), + `New ${definition.friendlyName || definition.name}`, + { + getName: c => c._instanceName, + separator: " ", + } + ) + // Generate basic component structure let instance: Component = { _id: Helpers.uuid(), @@ -475,7 +486,7 @@ export class ComponentStore extends BudiStore { hover: {}, active: {}, }, - _instanceName: `New ${definition.friendlyName || definition.name}`, + _instanceName: componentName, ...presetProps, } @@ -500,7 +511,7 @@ export class ComponentStore extends BudiStore { } // Add step name to form steps - if (componentName.endsWith("/formstep")) { + if (componentType.endsWith("/formstep")) { const parentForm = findClosestMatchingComponent( screen.props, get(selectedComponent)?._id, @@ -529,14 +540,14 @@ export class ComponentStore extends BudiStore { * @returns */ async create( - componentName: string, + componentType: string, presetProps: any, parent: Component, index: number ) { const state = get(this.store) const componentInstance = this.createInstance( - componentName, + componentType, presetProps, parent ) diff --git a/packages/builder/src/stores/builder/index.js b/packages/builder/src/stores/builder/index.js index 54c1aa39a2..7dd7f67828 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 { screenComponentErrors } from "./screenComponent" +import { screenComponents, screenComponentErrors } from "./screenComponent" // Backend import { tables } from "./tables" @@ -68,6 +68,7 @@ export { snippets, rowActions, appPublished, + screenComponents, screenComponentErrors, } diff --git a/packages/builder/src/stores/builder/screenComponent.ts b/packages/builder/src/stores/builder/screenComponent.ts index 226d233090..56e9d311a4 100644 --- a/packages/builder/src/stores/builder/screenComponent.ts +++ b/packages/builder/src/stores/builder/screenComponent.ts @@ -3,11 +3,12 @@ import { tables } from "./tables" import { selectedScreen } from "./screens" import { viewsV2 } from "./viewsV2" import { findComponentsBySettingsType } from "@/helpers/screen" -import { UIDatasourceType, Screen } from "@budibase/types" +import { UIDatasourceType, Screen, Component } from "@budibase/types" import { queries } from "./queries" import { views } from "./views" import { bindings, featureFlag } from "@/helpers" import { getBindableProperties } from "@/dataBinding" +import { findAllComponents } from "@/helpers/components" function reduceBy( key: TKey, @@ -111,3 +112,16 @@ export const screenComponentErrors = derived( return getInvalidDatasources($selectedScreen, datasources) } ) + +export const screenComponents = derived( + [selectedScreen], + ([$selectedScreen]) => { + if (!$selectedScreen) { + return [] + } + const allComponents = findAllComponents( + $selectedScreen.props + ) as Component[] + return allComponents + } +)