diff --git a/apps/desktop/src/components/structure/TableStructureEditor.vue b/apps/desktop/src/components/structure/TableStructureEditor.vue index 6822672595..a03dfbc140 100644 --- a/apps/desktop/src/components/structure/TableStructureEditor.vue +++ b/apps/desktop/src/components/structure/TableStructureEditor.vue @@ -55,6 +55,7 @@ import { dataTypeLengthInputValue, dataTypeLengthUnitValue, defaultNewColumnDataType, + filterStructureIndexColumnOptions, generateIndexName, generateUniqueIndexName, getColumnEditorControls, @@ -2108,11 +2109,10 @@ const availableColumnNames = computed(() => ); const colSearch = ref(""); -const filteredColumnNames = computed(() => { - const q = colSearch.value.toLowerCase().trim(); - if (!q) return availableColumnNames.value; - return availableColumnNames.value.filter((c) => c.toLowerCase().includes(q)); -}); + +function filteredIndexColumnNames(selectedColumns: readonly string[]): string[] { + return filterStructureIndexColumnOptions(availableColumnNames.value, selectedColumns, colSearch.value); +} function toggleIndexColumn(index: EditableStructureIndex, col: string) { const previousColumns = [...index.columns]; @@ -3163,7 +3163,7 @@ watch([activeTab, ddlLoading], ([tab, loading]) => {
- + {{ col }} @@ -3199,7 +3199,7 @@ watch([activeTab, ddlLoading], ([tab, loading]) => {
- + {{ col }} diff --git a/apps/desktop/src/lib/table/tableStructureEditorState.ts b/apps/desktop/src/lib/table/tableStructureEditorState.ts index 4df6cea0d0..36b348f43c 100644 --- a/apps/desktop/src/lib/table/tableStructureEditorState.ts +++ b/apps/desktop/src/lib/table/tableStructureEditorState.ts @@ -777,6 +777,15 @@ export function sameStructureIndexType(left: string | null | undefined, right: s return normalizeStructureIndexType(left) === normalizeStructureIndexType(right); } +/** Keep selected fields removable even after they are no longer available on the table. */ +export function filterStructureIndexColumnOptions(availableColumns: readonly string[], selectedColumns: readonly string[], search = ""): string[] { + const availableSet = new Set(availableColumns); + const unavailableSelected = selectedColumns.filter((column) => column.trim() && !availableSet.has(column)); + const options = [...new Set([...unavailableSelected, ...availableColumns])]; + const query = search.trim().toLowerCase(); + return query ? options.filter((column) => column.toLowerCase().includes(query)) : options; +} + export function createIndexDrafts(indexes: IndexInfo[]): EditableStructureIndex[] { return indexes.map((index) => ({ id: `existing:${index.name}`, diff --git a/packages/app-tests/tableStructureEditorState.test.ts b/packages/app-tests/tableStructureEditorState.test.ts index c6e2817e32..8e7983d653 100644 --- a/packages/app-tests/tableStructureEditorState.test.ts +++ b/packages/app-tests/tableStructureEditorState.test.ts @@ -9,6 +9,7 @@ import { createColumnDrafts, createIndexDrafts, dataTypeLengthInputValue, + filterStructureIndexColumnOptions, generateIndexName, generateUniqueIndexName, getColumnEditorControls, @@ -404,6 +405,12 @@ test("creates editable index drafts and splits pasted column lists", () => { assert.equal(toColumnNames(["id", "name"]), "id, name"); }); +test("keeps unavailable selected index fields removable", () => { + assert.deepEqual(filterStructureIndexColumnOptions(["id", "customer_id", "name"], ["platform_code"]), ["platform_code", "id", "customer_id", "name"]); + assert.deepEqual(filterStructureIndexColumnOptions(["id", "customer_id", "name"], ["customer_id", "platform_code"]), ["platform_code", "id", "customer_id", "name"]); + assert.deepEqual(filterStructureIndexColumnOptions(["id", "customer_id", "name"], ["platform_code"], "PLAT"), ["platform_code"]); +}); + test("normalizes Postgres lowercase index types when creating structure drafts", () => { const postgresIndexes: IndexInfo[] = [ {