253 lines
7.9 KiB
TypeScript
253 lines
7.9 KiB
TypeScript
import { ref, computed, watch } from "vue";
|
|
import { uuid } from "@/lib/common/utils";
|
|
import type { SchemaDiffConfig, SchemaDiffCompareOptions } from "@/types/schemaDiff";
|
|
import { createEmptyConfig, getDefaultOptionsForDbType } from "@/types/schemaDiff";
|
|
|
|
const STORAGE_KEY = "dbx-schema-diff-configs";
|
|
const HISTORY_KEY = "dbx-schema-diff-history";
|
|
const MAX_HISTORY = 10;
|
|
|
|
const configs = ref<SchemaDiffConfig[]>(loadConfigsFromStorage());
|
|
const activeConfigId = ref<string>("");
|
|
const recentConfigs = ref<SchemaDiffConfig[]>(loadHistoryFromStorage());
|
|
|
|
function loadConfigsFromStorage(): SchemaDiffConfig[] {
|
|
try {
|
|
const raw = localStorage.getItem(STORAGE_KEY);
|
|
if (!raw) return [];
|
|
const parsed = JSON.parse(raw) as SchemaDiffConfig[];
|
|
return Array.isArray(parsed) ? parsed : [];
|
|
} catch {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
function loadHistoryFromStorage(): SchemaDiffConfig[] {
|
|
try {
|
|
const raw = localStorage.getItem(HISTORY_KEY);
|
|
if (!raw) return [];
|
|
const parsed = JSON.parse(raw) as SchemaDiffConfig[];
|
|
return Array.isArray(parsed) ? parsed : [];
|
|
} catch {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
function saveConfigsToStorage() {
|
|
localStorage.setItem(STORAGE_KEY, JSON.stringify(configs.value));
|
|
}
|
|
|
|
function saveHistoryToStorage() {
|
|
localStorage.setItem(HISTORY_KEY, JSON.stringify(recentConfigs.value));
|
|
}
|
|
|
|
function createDefaultConfig(dbType?: string): SchemaDiffConfig {
|
|
const id = uuid();
|
|
const config = createEmptyConfig(id, "Default");
|
|
if (dbType) {
|
|
config.options = getDefaultOptionsForDbType(dbType);
|
|
}
|
|
return config;
|
|
}
|
|
|
|
export function useSchemaDiffConfig() {
|
|
const activeConfig = computed(() => configs.value.find((c) => c.id === activeConfigId.value) ?? configs.value[0] ?? null);
|
|
|
|
function ensureDefaultConfig(dbType?: string) {
|
|
if (configs.value.length === 0) {
|
|
const defaultConfig = createDefaultConfig(dbType);
|
|
configs.value.push(defaultConfig);
|
|
activeConfigId.value = defaultConfig.id;
|
|
saveConfigsToStorage();
|
|
} else if (!activeConfigId.value) {
|
|
activeConfigId.value = configs.value[0].id;
|
|
}
|
|
}
|
|
|
|
function createConfig(name: string, base?: SchemaDiffConfig, dbType?: string): SchemaDiffConfig {
|
|
const id = uuid();
|
|
const config = base ? { ...base, id, name, createdAt: Date.now(), updatedAt: Date.now() } : createEmptyConfig(id, name);
|
|
if (dbType && !base) {
|
|
config.options = getDefaultOptionsForDbType(dbType);
|
|
}
|
|
configs.value.push(config);
|
|
activeConfigId.value = id;
|
|
saveConfigsToStorage();
|
|
return config;
|
|
}
|
|
|
|
function updateConfig(id: string, updates: Partial<Omit<SchemaDiffConfig, "id" | "createdAt">>) {
|
|
const index = configs.value.findIndex((c) => c.id === id);
|
|
if (index === -1) return;
|
|
configs.value[index] = {
|
|
...configs.value[index],
|
|
...updates,
|
|
updatedAt: Date.now(),
|
|
};
|
|
saveConfigsToStorage();
|
|
}
|
|
|
|
function renameConfig(id: string, name: string) {
|
|
updateConfig(id, { name });
|
|
}
|
|
|
|
function deleteConfig(id: string) {
|
|
configs.value = configs.value.filter((c) => c.id !== id);
|
|
if (activeConfigId.value === id) {
|
|
activeConfigId.value = configs.value[0]?.id ?? "";
|
|
}
|
|
saveConfigsToStorage();
|
|
}
|
|
|
|
function duplicateConfig(id: string) {
|
|
const source = configs.value.find((c) => c.id === id);
|
|
if (!source) return;
|
|
let newName = `${source.name} (1)`;
|
|
let counter = 1;
|
|
while (configs.value.some((c) => c.name === newName)) {
|
|
counter++;
|
|
newName = `${source.name} (${counter})`;
|
|
}
|
|
createConfig(newName, source);
|
|
}
|
|
|
|
function exportConfigs(): string {
|
|
return JSON.stringify(configs.value, null, 2);
|
|
}
|
|
|
|
function exportActiveConfig(): string {
|
|
if (!activeConfig.value) return "";
|
|
return JSON.stringify(activeConfig.value, null, 2);
|
|
}
|
|
|
|
function importConfigs(
|
|
jsonText: string,
|
|
mode: "merge" | "replace" = "merge",
|
|
): {
|
|
imported: number;
|
|
renamed: number;
|
|
} {
|
|
const parsed = JSON.parse(jsonText) as SchemaDiffConfig | SchemaDiffConfig[];
|
|
const items = Array.isArray(parsed) ? parsed : [parsed];
|
|
let renamed = 0;
|
|
|
|
if (mode === "replace") {
|
|
configs.value = [];
|
|
}
|
|
|
|
for (const item of items) {
|
|
let name = item.name;
|
|
if (configs.value.some((c) => c.name === name && c.id !== item.id)) {
|
|
let counter = 1;
|
|
let candidate = `${name} (${counter})`;
|
|
while (configs.value.some((c) => c.name === candidate)) {
|
|
counter++;
|
|
candidate = `${name} (${counter})`;
|
|
}
|
|
name = candidate;
|
|
renamed++;
|
|
}
|
|
const newId = uuid();
|
|
configs.value.push({
|
|
...item,
|
|
id: newId,
|
|
name,
|
|
createdAt: Date.now(),
|
|
updatedAt: Date.now(),
|
|
});
|
|
}
|
|
|
|
saveConfigsToStorage();
|
|
if (!activeConfigId.value && configs.value.length > 0) {
|
|
activeConfigId.value = configs.value[0].id;
|
|
}
|
|
|
|
return { imported: items.length, renamed };
|
|
}
|
|
|
|
function updateActiveConfigOptions(options: SchemaDiffCompareOptions) {
|
|
if (!activeConfig.value) return;
|
|
updateConfig(activeConfig.value.id, { options: { ...options } });
|
|
}
|
|
|
|
function updateActiveConfigConnection(updates: Partial<SchemaDiffConfig>) {
|
|
if (!activeConfig.value) return;
|
|
const filtered: Partial<SchemaDiffConfig> = {};
|
|
if (updates.sourceConnectionId !== undefined) filtered.sourceConnectionId = updates.sourceConnectionId;
|
|
if (updates.sourceDatabase !== undefined) filtered.sourceDatabase = updates.sourceDatabase;
|
|
if (updates.sourceSchema !== undefined) filtered.sourceSchema = updates.sourceSchema;
|
|
if (updates.targetConnectionId !== undefined) filtered.targetConnectionId = updates.targetConnectionId;
|
|
if (updates.targetDatabase !== undefined) filtered.targetDatabase = updates.targetDatabase;
|
|
if (updates.targetSchema !== undefined) filtered.targetSchema = updates.targetSchema;
|
|
updateConfig(activeConfig.value.id, filtered);
|
|
}
|
|
|
|
function saveToHistory(config: SchemaDiffConfig) {
|
|
// Check if same config already exists (same connection/db/schema)
|
|
const existingIndex = recentConfigs.value.findIndex(
|
|
(c) => c.sourceConnectionId === config.sourceConnectionId && c.sourceDatabase === config.sourceDatabase && c.sourceSchema === config.sourceSchema && c.targetConnectionId === config.targetConnectionId && c.targetDatabase === config.targetDatabase && c.targetSchema === config.targetSchema,
|
|
);
|
|
|
|
if (existingIndex !== -1) {
|
|
// Update existing entry
|
|
recentConfigs.value[existingIndex] = {
|
|
...config,
|
|
id: recentConfigs.value[existingIndex].id,
|
|
updatedAt: Date.now(),
|
|
};
|
|
// Move to front
|
|
const updated = recentConfigs.value.splice(existingIndex, 1)[0];
|
|
recentConfigs.value.unshift(updated);
|
|
} else {
|
|
// Add new entry
|
|
recentConfigs.value.unshift({
|
|
...config,
|
|
id: uuid(),
|
|
createdAt: Date.now(),
|
|
updatedAt: Date.now(),
|
|
});
|
|
}
|
|
|
|
// Keep only MAX_HISTORY items
|
|
if (recentConfigs.value.length > MAX_HISTORY) {
|
|
recentConfigs.value = recentConfigs.value.slice(0, MAX_HISTORY);
|
|
}
|
|
|
|
saveHistoryToStorage();
|
|
}
|
|
|
|
function loadFromHistory(configId: string) {
|
|
const config = recentConfigs.value.find((c) => c.id === configId);
|
|
if (!config) return null;
|
|
return config;
|
|
}
|
|
|
|
function deleteFromHistory(configId: string) {
|
|
recentConfigs.value = recentConfigs.value.filter((c) => c.id !== configId);
|
|
saveHistoryToStorage();
|
|
}
|
|
|
|
watch(configs, saveConfigsToStorage, { deep: true });
|
|
|
|
return {
|
|
configs: computed(() => configs.value),
|
|
activeConfigId,
|
|
activeConfig,
|
|
recentConfigs: computed(() => recentConfigs.value),
|
|
ensureDefaultConfig,
|
|
createConfig,
|
|
updateConfig,
|
|
renameConfig,
|
|
deleteConfig,
|
|
duplicateConfig,
|
|
exportConfigs,
|
|
exportActiveConfig,
|
|
importConfigs,
|
|
updateActiveConfigOptions,
|
|
updateActiveConfigConnection,
|
|
saveToHistory,
|
|
loadFromHistory,
|
|
deleteFromHistory,
|
|
};
|
|
}
|