feat(grid): support deleting custom column formatters
This commit is contained in:
11 files changed
+508
-77
No files matched your search
@@ -1304,23 +1304,34 @@ export const useSettingsStore = defineStore("settings", () => {
|
||||
const isEditorSettingsLoaded = ref(false);
|
||||
let initEditorSettingsPromise: Promise<void> | null = null;
|
||||
let pendingEditorSettingsPatches: Partial<EditorSettings>[] = [];
|
||||
let editorSettingsSaveQueue: Promise<void> | null = null;
|
||||
let editorSettingsAtomicUpdateQueue: Promise<void> = Promise.resolve();
|
||||
let editorSettingsOperationQueue: Promise<void> | null = null;
|
||||
let editorSettingsPatchRevision = 0;
|
||||
const editorSettingsFieldRevisions = new Map<keyof EditorSettings, number>();
|
||||
const customColumnFormatterDeleteVersions = new Map<string, number>();
|
||||
let pendingAiChatSelection: AiChatSelectionState | null = null;
|
||||
let aiChatSelectionSaveRunning = false;
|
||||
|
||||
const editorSettings = ref<EditorSettings>(normalizeEditorSettings({}));
|
||||
|
||||
function enqueueEditorSettingsSave(): Promise<void> {
|
||||
const saveCurrentSettings = () => api.saveEditorSettings(editorSettingsSnapshot(editorSettings.value));
|
||||
const save = editorSettingsSaveQueue ? editorSettingsSaveQueue.catch(() => {}).then(saveCurrentSettings) : saveCurrentSettings();
|
||||
const trackedSave = save.finally(() => {
|
||||
if (editorSettingsSaveQueue === trackedSave) editorSettingsSaveQueue = null;
|
||||
function enqueueEditorSettingsOperation<T>(operation: () => Promise<T>): Promise<T> {
|
||||
const queuedOperation = editorSettingsOperationQueue ? editorSettingsOperationQueue.then(operation) : operation();
|
||||
const trackedOperation = queuedOperation.then(
|
||||
() => undefined,
|
||||
() => undefined,
|
||||
);
|
||||
editorSettingsOperationQueue = trackedOperation;
|
||||
void trackedOperation.finally(() => {
|
||||
if (editorSettingsOperationQueue === trackedOperation) editorSettingsOperationQueue = null;
|
||||
});
|
||||
editorSettingsSaveQueue = trackedSave;
|
||||
return trackedSave;
|
||||
return queuedOperation;
|
||||
}
|
||||
|
||||
function persistCurrentEditorSettings(): Promise<void> {
|
||||
return api.saveEditorSettings(editorSettingsSnapshot(editorSettings.value));
|
||||
}
|
||||
|
||||
function enqueueEditorSettingsSave(): Promise<void> {
|
||||
return enqueueEditorSettingsOperation(persistCurrentEditorSettings);
|
||||
}
|
||||
|
||||
function saveEditorSettings() {
|
||||
@@ -1823,32 +1834,33 @@ export const useSettingsStore = defineStore("settings", () => {
|
||||
await enqueueEditorSettingsSave();
|
||||
}
|
||||
|
||||
async function enqueueEditorSettingsAtomicMutation<T>(mutation: () => Promise<T>): Promise<T> {
|
||||
await initEditorSettings();
|
||||
return enqueueEditorSettingsOperation(mutation);
|
||||
}
|
||||
|
||||
function updateEditorSettingsAndPersist(partial: Partial<EditorSettings>): Promise<void> {
|
||||
const update = editorSettingsAtomicUpdateQueue
|
||||
.catch(() => {})
|
||||
.then(async () => {
|
||||
await initEditorSettings();
|
||||
const previous = editorSettingsSnapshot(editorSettings.value);
|
||||
applyEditorSettingsPatch(partial);
|
||||
const revision = markEditorSettingsPatch(partial);
|
||||
try {
|
||||
await enqueueEditorSettingsSave();
|
||||
} catch (error) {
|
||||
const restored = editorSettingsSnapshot(editorSettings.value) as unknown as Record<string, unknown>;
|
||||
const previousSettings = previous as unknown as Record<string, unknown>;
|
||||
let changed = false;
|
||||
for (const key of Object.keys(partial) as (keyof EditorSettings)[]) {
|
||||
if (partial[key] === undefined || editorSettingsFieldRevisions.get(key) !== revision) continue;
|
||||
restored[key] = previousSettings[key];
|
||||
editorSettingsFieldRevisions.set(key, ++editorSettingsPatchRevision);
|
||||
changed = true;
|
||||
}
|
||||
if (changed) editorSettings.value = normalizeEditorSettings(restored);
|
||||
throw error;
|
||||
return enqueueEditorSettingsAtomicMutation(async () => {
|
||||
await initEditorSettings();
|
||||
const previous = editorSettingsSnapshot(editorSettings.value);
|
||||
applyEditorSettingsPatch(partial);
|
||||
const revision = markEditorSettingsPatch(partial);
|
||||
try {
|
||||
await persistCurrentEditorSettings();
|
||||
} catch (error) {
|
||||
const restored = editorSettingsSnapshot(editorSettings.value) as unknown as Record<string, unknown>;
|
||||
const previousSettings = previous as unknown as Record<string, unknown>;
|
||||
let changed = false;
|
||||
for (const key of Object.keys(partial) as (keyof EditorSettings)[]) {
|
||||
if (partial[key] === undefined || editorSettingsFieldRevisions.get(key) !== revision) continue;
|
||||
restored[key] = previousSettings[key];
|
||||
editorSettingsFieldRevisions.set(key, ++editorSettingsPatchRevision);
|
||||
changed = true;
|
||||
}
|
||||
});
|
||||
editorSettingsAtomicUpdateQueue = update.catch(() => {});
|
||||
return update;
|
||||
if (changed) editorSettings.value = normalizeEditorSettings(restored);
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function updateColumnFormatter(key: string, formatter: ColumnFormatterConfig | undefined) {
|
||||
@@ -1862,29 +1874,101 @@ export const useSettingsStore = defineStore("settings", () => {
|
||||
updateEditorSettings({ columnFormatters });
|
||||
}
|
||||
|
||||
function upsertCustomColumnFormatter(formatter: CustomColumnFormatterConfig): CustomColumnFormatterConfig | undefined {
|
||||
const normalized = normalizeCustomColumnFormatter(formatter);
|
||||
if (!normalized) return undefined;
|
||||
updateEditorSettings({
|
||||
customColumnFormatters: {
|
||||
...editorSettings.value.customColumnFormatters,
|
||||
[normalized.id]: normalized,
|
||||
},
|
||||
});
|
||||
return normalized;
|
||||
function customColumnFormatterDeleteVersion(id: string): number {
|
||||
return customColumnFormatterDeleteVersions.get(id) ?? 0;
|
||||
}
|
||||
|
||||
function deleteCustomColumnFormatter(id: string) {
|
||||
const customColumnFormatters = {
|
||||
...editorSettings.value.customColumnFormatters,
|
||||
};
|
||||
delete customColumnFormatters[id];
|
||||
const columnFormatters = Object.fromEntries(
|
||||
Object.entries(editorSettings.value.columnFormatters).filter(([, formatter]) => {
|
||||
return formatter.kind !== "custom-ref" || formatter.formatterId !== id;
|
||||
}),
|
||||
);
|
||||
updateEditorSettings({ customColumnFormatters, columnFormatters });
|
||||
async function upsertCustomColumnFormatter(formatter: CustomColumnFormatterConfig, expectedDeleteVersion?: number): Promise<CustomColumnFormatterConfig | undefined> {
|
||||
const normalized = normalizeCustomColumnFormatter(formatter);
|
||||
if (!normalized) return undefined;
|
||||
return enqueueEditorSettingsAtomicMutation(async () => {
|
||||
await initEditorSettings();
|
||||
if (expectedDeleteVersion !== undefined && customColumnFormatterDeleteVersion(normalized.id) !== expectedDeleteVersion) return undefined;
|
||||
const previous = editorSettings.value.customColumnFormatters[normalized.id];
|
||||
const partial = {
|
||||
customColumnFormatters: {
|
||||
...editorSettings.value.customColumnFormatters,
|
||||
[normalized.id]: normalized,
|
||||
},
|
||||
} satisfies Partial<EditorSettings>;
|
||||
applyEditorSettingsPatch(partial);
|
||||
markEditorSettingsPatch(partial);
|
||||
try {
|
||||
await persistCurrentEditorSettings();
|
||||
} catch (error) {
|
||||
const customColumnFormatters = {
|
||||
...editorSettings.value.customColumnFormatters,
|
||||
};
|
||||
const current = customColumnFormatters[normalized.id];
|
||||
if (current?.name === normalized.name && current.template === normalized.template) {
|
||||
if (previous) {
|
||||
customColumnFormatters[normalized.id] = previous;
|
||||
} else {
|
||||
delete customColumnFormatters[normalized.id];
|
||||
}
|
||||
const rollback = { customColumnFormatters } satisfies Partial<EditorSettings>;
|
||||
applyEditorSettingsPatch(rollback);
|
||||
markEditorSettingsPatch(rollback);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
return normalized;
|
||||
});
|
||||
}
|
||||
|
||||
async function deleteCustomColumnFormatter(id: string): Promise<void> {
|
||||
return enqueueEditorSettingsAtomicMutation(async () => {
|
||||
await initEditorSettings();
|
||||
const previousDeleteVersion = customColumnFormatterDeleteVersion(id);
|
||||
const deleteVersion = previousDeleteVersion + 1;
|
||||
customColumnFormatterDeleteVersions.set(id, deleteVersion);
|
||||
const previousFormatter = editorSettings.value.customColumnFormatters[id];
|
||||
const customColumnFormatters = {
|
||||
...editorSettings.value.customColumnFormatters,
|
||||
};
|
||||
delete customColumnFormatters[id];
|
||||
const removedColumnFormatters = Object.fromEntries(
|
||||
Object.entries(editorSettings.value.columnFormatters).filter(([, formatter]) => {
|
||||
return formatter.kind === "custom-ref" && formatter.formatterId === id;
|
||||
}),
|
||||
);
|
||||
const columnFormatters = Object.fromEntries(
|
||||
Object.entries(editorSettings.value.columnFormatters).filter(([, formatter]) => {
|
||||
return formatter.kind !== "custom-ref" || formatter.formatterId !== id;
|
||||
}),
|
||||
);
|
||||
const partial = { customColumnFormatters, columnFormatters } satisfies Partial<EditorSettings>;
|
||||
applyEditorSettingsPatch(partial);
|
||||
markEditorSettingsPatch(partial);
|
||||
try {
|
||||
await persistCurrentEditorSettings();
|
||||
} catch (error) {
|
||||
if (customColumnFormatterDeleteVersion(id) === deleteVersion) {
|
||||
if (previousDeleteVersion === 0) {
|
||||
customColumnFormatterDeleteVersions.delete(id);
|
||||
} else {
|
||||
customColumnFormatterDeleteVersions.set(id, previousDeleteVersion);
|
||||
}
|
||||
}
|
||||
const restoredCustomColumnFormatters = {
|
||||
...editorSettings.value.customColumnFormatters,
|
||||
};
|
||||
if (previousFormatter && !restoredCustomColumnFormatters[id]) restoredCustomColumnFormatters[id] = previousFormatter;
|
||||
const restoredColumnFormatters = {
|
||||
...editorSettings.value.columnFormatters,
|
||||
};
|
||||
for (const [key, formatter] of Object.entries(removedColumnFormatters)) {
|
||||
if (!restoredColumnFormatters[key]) restoredColumnFormatters[key] = formatter;
|
||||
}
|
||||
const rollback = {
|
||||
customColumnFormatters: restoredCustomColumnFormatters,
|
||||
columnFormatters: restoredColumnFormatters,
|
||||
} satisfies Partial<EditorSettings>;
|
||||
applyEditorSettingsPatch(rollback);
|
||||
markEditorSettingsPatch(rollback);
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -1921,6 +2005,7 @@ export const useSettingsStore = defineStore("settings", () => {
|
||||
initMcpGlobalPolicy,
|
||||
updateMcpGlobalPolicy,
|
||||
updateColumnFormatter,
|
||||
customColumnFormatterDeleteVersion,
|
||||
upsertCustomColumnFormatter,
|
||||
deleteCustomColumnFormatter,
|
||||
};
|
||||
|
||||
Reference in new issue
Block a user