From 8671a2fb2a729aed0091239da3dcb7bd161ec520 Mon Sep 17 00:00:00 2001 From: zipg Date: Fri, 21 Aug 2026 19:44:52 +0800 Subject: [PATCH] feat(grid): support deleting custom column formatters --- apps/desktop/src/components/grid/DataGrid.vue | 115 ++++++++--- apps/desktop/src/i18n/locales/en.ts | 2 + apps/desktop/src/i18n/locales/es.ts | 2 + apps/desktop/src/i18n/locales/it.ts | 2 + apps/desktop/src/i18n/locales/ja.ts | 2 + apps/desktop/src/i18n/locales/pt-BR.ts | 2 + apps/desktop/src/i18n/locales/zh-CN.ts | 2 + apps/desktop/src/i18n/locales/zh-TW.ts | 2 + .../stores/__tests__/settingsStore.spec.ts | 91 +++++++++ apps/desktop/src/stores/settingsStore.ts | 193 +++++++++++++----- packages/app-tests/settingsStore.test.ts | 172 ++++++++++++++++ 11 files changed, 508 insertions(+), 77 deletions(-) diff --git a/apps/desktop/src/components/grid/DataGrid.vue b/apps/desktop/src/components/grid/DataGrid.vue index 7b334f962c..394ff0b690 100644 --- a/apps/desktop/src/components/grid/DataGrid.vue +++ b/apps/desktop/src/components/grid/DataGrid.vue @@ -1076,8 +1076,13 @@ const formatterJsonPath = ref("$.user.name"); const formatterMaskPrefix = ref(4); const formatterMaskSuffix = ref(4); const formatterCustomId = ref(CUSTOM_FORMATTER_NEW); +const formatterCustomCapturedDeleteVersion = ref(); const formatterCustomName = ref(""); const formatterCustomTemplate = ref("${value}"); +const formatterCustomDeleteOpen = ref(false); +const formatterCustomDeleteLoading = ref(false); +const formatterCustomDeleteId = ref(""); +const formatterCustomDeleteName = ref(""); const formatterForeignKeyRefSchema = ref(""); const formatterForeignKeyRefTable = ref(""); const formatterForeignKeyRefColumn = ref(""); @@ -1508,10 +1513,12 @@ function loadFormatterDraft(formatter: ColumnFormatterConfig | undefined) { } else if (draft.kind === "custom-ref") { const saved = settingsStore.editorSettings.customColumnFormatters[draft.formatterId]; formatterCustomId.value = saved ? saved.id : CUSTOM_FORMATTER_NEW; + formatterCustomCapturedDeleteVersion.value = saved ? settingsStore.customColumnFormatterDeleteVersion(saved.id) : undefined; formatterCustomName.value = saved?.name ?? ""; formatterCustomTemplate.value = saved?.template ?? "${value}"; } else if (draft.kind === "custom-template") { formatterCustomId.value = CUSTOM_FORMATTER_NEW; + formatterCustomCapturedDeleteVersion.value = undefined; formatterCustomName.value = ""; formatterCustomTemplate.value = draft.template; } else if (draft.kind === "foreign-key-display") { @@ -1585,22 +1592,33 @@ function handleColumnFormatterOpenChange(value: boolean, columnIndex: number) { } } -function saveColumnFormatter(columnIndex: number) { +async function saveColumnFormatter(columnIndex: number) { const column = props.result.columns[columnIndex]; const key = column ? formatterKeyForColumn(column) : null; if (!key) return; - let formatter = currentFormatterDraft(); - if (formatterKind.value === "custom-template" && formatterCustomName.value.trim()) { - const id = formatterCustomId.value === CUSTOM_FORMATTER_NEW ? createCustomFormatterId() : formatterCustomId.value; - const saved = settingsStore.upsertCustomColumnFormatter({ - id, - name: formatterCustomName.value, - template: formatterCustomTemplate.value, - }); - if (saved) formatter = { kind: "custom-ref", formatterId: saved.id }; + try { + let formatter = currentFormatterDraft(); + if (formatterKind.value === "custom-template" && formatterCustomName.value.trim()) { + const id = formatterCustomId.value === CUSTOM_FORMATTER_NEW ? createCustomFormatterId() : formatterCustomId.value; + const saved = await settingsStore.upsertCustomColumnFormatter( + { + id, + name: formatterCustomName.value, + template: formatterCustomTemplate.value, + }, + formatterCustomCapturedDeleteVersion.value, + ); + if (!saved) { + selectCustomFormatter(CUSTOM_FORMATTER_NEW); + return; + } + formatter = { kind: "custom-ref", formatterId: saved.id }; + } + settingsStore.updateColumnFormatter(key, formatter); + closeColumnFormatter(); + } catch (error) { + toast(t("grid.tableOperationFailed", { message: translateBackendError(t, error) }), 5000); } - settingsStore.updateColumnFormatter(key, formatter); - closeColumnFormatter(); } function clearColumnFormatter(columnIndex: number) { @@ -1629,16 +1647,44 @@ function selectFormatterKind(value: FormatterDraftKind, columnIndex: number) { function selectCustomFormatter(value: string) { formatterCustomId.value = value; if (value === CUSTOM_FORMATTER_NEW) { + formatterCustomCapturedDeleteVersion.value = undefined; formatterCustomName.value = ""; formatterCustomTemplate.value = "${value}"; return; } const saved = settingsStore.editorSettings.customColumnFormatters[value]; if (!saved) return; + formatterCustomCapturedDeleteVersion.value = settingsStore.customColumnFormatterDeleteVersion(saved.id); formatterCustomName.value = saved.name; formatterCustomTemplate.value = saved.template; } +function requestDeleteCustomFormatter() { + if (formatterCustomId.value === CUSTOM_FORMATTER_NEW) return; + const saved = settingsStore.editorSettings.customColumnFormatters[formatterCustomId.value]; + if (!saved) return; + formatterCustomDeleteId.value = saved.id; + formatterCustomDeleteName.value = saved.name; + formatterCustomDeleteOpen.value = true; +} + +async function confirmDeleteCustomFormatter() { + const id = formatterCustomDeleteId.value; + if (!id || formatterCustomDeleteLoading.value) return; + formatterCustomDeleteLoading.value = true; + try { + await settingsStore.deleteCustomColumnFormatter(id); + if (formatterCustomId.value === id) selectCustomFormatter(CUSTOM_FORMATTER_NEW); + formatterCustomDeleteOpen.value = false; + formatterCustomDeleteId.value = ""; + formatterCustomDeleteName.value = ""; + } catch (error) { + toast(t("grid.tableOperationFailed", { message: translateBackendError(t, error) }), 5000); + } finally { + formatterCustomDeleteLoading.value = false; + } +} + function createCustomFormatterId(): string { return `fmt_${uuid()}`; } @@ -11991,17 +12037,31 @@ function currentGridContextMenuItems(): ContextMenuItem[] {
{{ t("grid.formatterSavedCustom") }}
- +
+ + +