Merge pull request #15465 from Budibase/BUDI-9016/avoid-duplicated-names-on-creating-components

Avoid duplicated names on creating components
This commit is contained in:
Adria Navarro 2025-01-31 09:31:33 +01:00 committed by GitHub
commit 859894a82c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 39 additions and 11 deletions

View File

@ -76,13 +76,15 @@ export const getSequentialName = <T extends any>(
{ {
getName, getName,
numberFirstItem, numberFirstItem,
separator = "",
}: { }: {
getName?: (item: T) => string getName?: (item: T) => string
numberFirstItem?: boolean numberFirstItem?: boolean
separator?: string
} = {} } = {}
) => { ) => {
if (!prefix?.length) { if (!prefix?.length) {
return null return ""
} }
const trimmedPrefix = prefix.trim() const trimmedPrefix = prefix.trim()
const firstName = numberFirstItem ? `${prefix}1` : trimmedPrefix const firstName = numberFirstItem ? `${prefix}1` : trimmedPrefix
@ -107,5 +109,5 @@ export const getSequentialName = <T extends any>(
max = num max = num
} }
}) })
return max === 0 ? firstName : `${prefix}${max + 1}` return max === 0 ? firstName : `${prefix}${separator}${max + 1}`
} }

View File

@ -49,7 +49,7 @@ describe("getSequentialName", () => {
it("handles nullish prefix", async () => { it("handles nullish prefix", async () => {
const name = getSequentialName([], null) const name = getSequentialName([], null)
expect(name).toBe(null) expect(name).toBe("")
}) })
it("handles just the prefix", async () => { it("handles just the prefix", async () => {

View File

@ -20,6 +20,7 @@ import {
previewStore, previewStore,
tables, tables,
componentTreeNodesStore, componentTreeNodesStore,
screenComponents,
} from "@/stores/builder" } from "@/stores/builder"
import { buildFormSchema, getSchemaForDatasource } from "@/dataBinding" import { buildFormSchema, getSchemaForDatasource } from "@/dataBinding"
import { import {
@ -37,6 +38,7 @@ import {
Table, Table,
} from "@budibase/types" } from "@budibase/types"
import { utils } from "@budibase/shared-core" import { utils } from "@budibase/shared-core"
import { getSequentialName } from "@/helpers/duplicate"
interface Component extends ComponentType { interface Component extends ComponentType {
_id: string _id: string
@ -452,7 +454,7 @@ export class ComponentStore extends BudiStore<ComponentState> {
* @returns * @returns
*/ */
createInstance( createInstance(
componentName: string, componentType: string,
presetProps: any, presetProps: any,
parent: any parent: any
): Component | null { ): Component | null {
@ -461,11 +463,20 @@ export class ComponentStore extends BudiStore<ComponentState> {
throw "A valid screen must be selected" throw "A valid screen must be selected"
} }
const definition = this.getDefinition(componentName) const definition = this.getDefinition(componentType)
if (!definition) { if (!definition) {
return null return null
} }
const componentName = getSequentialName(
get(screenComponents),
`New ${definition.friendlyName || definition.name}`,
{
getName: c => c._instanceName,
separator: " ",
}
)
// Generate basic component structure // Generate basic component structure
let instance: Component = { let instance: Component = {
_id: Helpers.uuid(), _id: Helpers.uuid(),
@ -475,7 +486,7 @@ export class ComponentStore extends BudiStore<ComponentState> {
hover: {}, hover: {},
active: {}, active: {},
}, },
_instanceName: `New ${definition.friendlyName || definition.name}`, _instanceName: componentName,
...presetProps, ...presetProps,
} }
@ -500,7 +511,7 @@ export class ComponentStore extends BudiStore<ComponentState> {
} }
// Add step name to form steps // Add step name to form steps
if (componentName.endsWith("/formstep")) { if (componentType.endsWith("/formstep")) {
const parentForm = findClosestMatchingComponent( const parentForm = findClosestMatchingComponent(
screen.props, screen.props,
get(selectedComponent)?._id, get(selectedComponent)?._id,
@ -529,14 +540,14 @@ export class ComponentStore extends BudiStore<ComponentState> {
* @returns * @returns
*/ */
async create( async create(
componentName: string, componentType: string,
presetProps: any, presetProps: any,
parent: Component, parent: Component,
index: number index: number
) { ) {
const state = get(this.store) const state = get(this.store)
const componentInstance = this.createInstance( const componentInstance = this.createInstance(
componentName, componentType,
presetProps, presetProps,
parent parent
) )

View File

@ -16,7 +16,7 @@ import { userStore, userSelectedResourceMap, isOnlyUser } from "./users.js"
import { deploymentStore } from "./deployments.js" import { deploymentStore } from "./deployments.js"
import { contextMenuStore } from "./contextMenu.js" import { contextMenuStore } from "./contextMenu.js"
import { snippets } from "./snippets" import { snippets } from "./snippets"
import { screenComponentErrors } from "./screenComponent" import { screenComponents, screenComponentErrors } from "./screenComponent"
// Backend // Backend
import { tables } from "./tables" import { tables } from "./tables"
@ -68,6 +68,7 @@ export {
snippets, snippets,
rowActions, rowActions,
appPublished, appPublished,
screenComponents,
screenComponentErrors, screenComponentErrors,
} }

View File

@ -3,11 +3,12 @@ import { tables } from "./tables"
import { selectedScreen } from "./screens" import { selectedScreen } from "./screens"
import { viewsV2 } from "./viewsV2" import { viewsV2 } from "./viewsV2"
import { findComponentsBySettingsType } from "@/helpers/screen" import { findComponentsBySettingsType } from "@/helpers/screen"
import { UIDatasourceType, Screen } from "@budibase/types" import { UIDatasourceType, Screen, Component } from "@budibase/types"
import { queries } from "./queries" import { queries } from "./queries"
import { views } from "./views" import { views } from "./views"
import { bindings, featureFlag } from "@/helpers" import { bindings, featureFlag } from "@/helpers"
import { getBindableProperties } from "@/dataBinding" import { getBindableProperties } from "@/dataBinding"
import { findAllComponents } from "@/helpers/components"
function reduceBy<TItem extends {}, TKey extends keyof TItem>( function reduceBy<TItem extends {}, TKey extends keyof TItem>(
key: TKey, key: TKey,
@ -111,3 +112,16 @@ export const screenComponentErrors = derived(
return getInvalidDatasources($selectedScreen, datasources) return getInvalidDatasources($selectedScreen, datasources)
} }
) )
export const screenComponents = derived(
[selectedScreen],
([$selectedScreen]) => {
if (!$selectedScreen) {
return []
}
const allComponents = findAllComponents(
$selectedScreen.props
) as Component[]
return allComponents
}
)