diff --git a/packages/builder/src/components/backend/DataTable/modals/OptionsEditor.svelte b/packages/builder/src/components/backend/DataTable/modals/OptionsEditor.svelte
new file mode 100644
index 0000000000..8e35e38ae9
--- /dev/null
+++ b/packages/builder/src/components/backend/DataTable/modals/OptionsEditor.svelte
@@ -0,0 +1,252 @@
+
+
+
+
+
+
options.set(e.detail.items)}
+ on:finalize={e => options.set(e.detail.items)}
+ >
+ {#each $enrichedOptions as option (option.id)}
+
+
+
+
+
openColorPicker(option.id)}
+ >
+
+
+
+ {#each OptionColours as colorOption}
+
handleColorChange(option.id, colorOption)}
+ style="--color:{colorOption};"
+ class="circle"
+ class:selected={colorOption === option.color}
+ />
+ {/each}
+
+
+
+
+
handleNameChange(option.id, e.target.value)}
+ />
+
removeInput(option.id)}
+ />
+
+ {/each}
+
+
+
+
+
diff --git a/packages/builder/src/helpers/duplicate.js b/packages/builder/src/helpers/duplicate.js
index c2a924f97b..361e1faa25 100644
--- a/packages/builder/src/helpers/duplicate.js
+++ b/packages/builder/src/helpers/duplicate.js
@@ -70,13 +70,18 @@ export const duplicateName = (name, allNames) => {
* @param getName optional function to extract the name for an item, if not a
* flat array of strings
*/
-export const getSequentialName = (items, prefix, getName = x => x) => {
+export const getSequentialName = (
+ items,
+ prefix,
+ { getName = x => x, numberFirstItem = false } = {}
+) => {
if (!prefix?.length || !getName) {
return null
}
const trimmedPrefix = prefix.trim()
+ const firstName = numberFirstItem ? `${prefix}1` : trimmedPrefix
if (!items?.length) {
- return trimmedPrefix
+ return firstName
}
let max = 0
items.forEach(item => {
@@ -96,5 +101,5 @@ export const getSequentialName = (items, prefix, getName = x => x) => {
max = num
}
})
- return max === 0 ? trimmedPrefix : `${prefix}${max + 1}`
+ return max === 0 ? firstName : `${prefix}${max + 1}`
}
diff --git a/packages/builder/src/helpers/tests/duplicate.test.js b/packages/builder/src/helpers/tests/duplicate.test.js
index 7e51c5ff2a..131e76a6c2 100644
--- a/packages/builder/src/helpers/tests/duplicate.test.js
+++ b/packages/builder/src/helpers/tests/duplicate.test.js
@@ -43,61 +43,71 @@ describe("duplicate", () => {
describe("getSequentialName", () => {
it("handles nullish items", async () => {
- const name = getSequentialName(null, "foo", () => {})
+ const name = getSequentialName(null, "foo")
expect(name).toBe("foo")
})
it("handles nullish prefix", async () => {
- const name = getSequentialName([], null, () => {})
- expect(name).toBe(null)
- })
-
- it("handles nullish getName function", async () => {
- const name = getSequentialName([], "foo", null)
+ const name = getSequentialName([], null)
expect(name).toBe(null)
})
it("handles just the prefix", async () => {
- const name = getSequentialName(["foo"], "foo", x => x)
+ const name = getSequentialName(["foo"], "foo")
expect(name).toBe("foo2")
})
it("handles continuous ranges", async () => {
- const name = getSequentialName(["foo", "foo2", "foo3"], "foo", x => x)
+ const name = getSequentialName(["foo", "foo2", "foo3"], "foo")
expect(name).toBe("foo4")
})
it("handles discontinuous ranges", async () => {
- const name = getSequentialName(["foo", "foo3"], "foo", x => x)
+ const name = getSequentialName(["foo", "foo3"], "foo")
expect(name).toBe("foo4")
})
it("handles a space inside the prefix", async () => {
- const name = getSequentialName(["foo", "foo 2", "foo 3"], "foo ", x => x)
+ const name = getSequentialName(["foo", "foo 2", "foo 3"], "foo ")
expect(name).toBe("foo 4")
})
it("handles a space inside the prefix with just the prefix", async () => {
- const name = getSequentialName(["foo"], "foo ", x => x)
+ const name = getSequentialName(["foo"], "foo ")
expect(name).toBe("foo 2")
})
it("handles no matches", async () => {
- const name = getSequentialName(["aaa", "bbb"], "foo", x => x)
+ const name = getSequentialName(["aaa", "bbb"], "foo")
expect(name).toBe("foo")
})
it("handles similar names", async () => {
- const name = getSequentialName(
- ["fooo1", "2foo", "a3foo4", "5foo5"],
- "foo",
- x => x
- )
+ const name = getSequentialName(["fooo1", "2foo", "a3foo4", "5foo5"], "foo")
expect(name).toBe("foo")
})
it("handles non-string names", async () => {
- const name = getSequentialName([null, 4123, [], {}], "foo", x => x)
+ const name = getSequentialName([null, 4123, [], {}], "foo")
expect(name).toBe("foo")
})
+
+ it("handles deep getters", async () => {
+ const name = getSequentialName([{ a: "foo 1" }], "foo ", {
+ getName: x => x.a,
+ })
+ expect(name).toBe("foo 2")
+ })
+
+ it("handles a mixture of spaces and not", async () => {
+ const name = getSequentialName(["foo", "foo 1", "foo 2"], "foo")
+ expect(name).toBe("foo3")
+ })
+
+ it("handles numbering the first item", async () => {
+ const name = getSequentialName(["foo1", "foo2", "foo"], "foo ", {
+ numberFirstItem: true,
+ })
+ expect(name).toBe("foo 3")
+ })
})
diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Navigation/NavItemConfiguration.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Navigation/NavItemConfiguration.svelte
index dffa4bf3ff..db55f501f0 100644
--- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Navigation/NavItemConfiguration.svelte
+++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Navigation/NavItemConfiguration.svelte
@@ -48,7 +48,9 @@
...navItems,
{
id: generate(),
- text: getSequentialName(navItems, "Nav Item ", x => x.text),
+ text: getSequentialName(navItems, "Nav Item ", {
+ getName: x => x.text,
+ }),
url: "",
roleId: Constants.Roles.BASIC,
type: "link",
diff --git a/packages/frontend-core/src/components/grid/cells/HeaderCell.svelte b/packages/frontend-core/src/components/grid/cells/HeaderCell.svelte
index de527246ca..c999bf6006 100644
--- a/packages/frontend-core/src/components/grid/cells/HeaderCell.svelte
+++ b/packages/frontend-core/src/components/grid/cells/HeaderCell.svelte
@@ -29,6 +29,7 @@
focusedCellId,
filter,
inlineFilters,
+ keyboardBlocked,
} = getContext("grid")
const searchableTypes = [
@@ -57,6 +58,8 @@
$: searching = searchValue != null
$: debouncedUpdateFilter(searchValue)
$: orderable = !column.primaryDisplay
+ $: editable = $config.canEditColumns && !column.schema.disabled
+ $: keyboardBlocked.set(open)
const close = () => {
open = false
@@ -231,6 +234,14 @@
}
const debouncedUpdateFilter = debounce(updateFilter, 250)
+ const handleDoubleClick = () => {
+ if (!editable || searching) {
+ return
+ }
+ open = true
+ editColumn()
+ }
+
onMount(() => subscribe("close-edit-column", close))
@@ -241,14 +252,15 @@