Files
ss-tools/frontend/src/routes/settings/settings-utils.ts

154 lines
5.2 KiB
TypeScript

/**
* Shared utilities for the Settings page.
* Centralises constants, URL helpers, normalisation functions and validation
* helpers that are consumed by +page.svelte and EnvironmentsTab.svelte.
*/
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
export const SETTINGS_TABS = [
"environments",
"connections",
"logging",
"git",
"llm",
"migration",
"storage",
"features",
"reports",
"automation",
"languages",
"system",
] as const;
export type SettingsTab = typeof SETTINGS_TABS[number];
interface LlmPrompts {
documentation_prompt: string;
git_commit_prompt: string;
}
interface LlmProviderBindings {
documentation: string;
git_commit: string;
}
interface LlmSettings {
prompts?: Partial<LlmPrompts>;
provider_bindings?: Partial<LlmProviderBindings>;
[key: string]: unknown;
}
export const DEFAULT_LLM_PROMPTS: LlmPrompts = {
documentation_prompt:
'Generate professional documentation for the following dataset and its columns.\nDataset: {dataset_name}\nColumns: {columns_json}\n\nProvide the documentation in JSON format:\n{\n \"dataset_description\": \"General description of the dataset\",\n \"column_descriptions\": [\n {\n \"name\": \"column_name\",\n \"description\": \"Generated description\"\n }\n ]\n}',
git_commit_prompt:
'Generate a concise and professional git commit message based on the following diff and recent history.\nUse Conventional Commits format (e.g., feat: ..., fix: ..., docs: ...).\n\nRecent History:\n{history}\n\nDiff:\n{diff}\n\nCommit Message:',
};
export const DEFAULT_LLM_PROVIDER_BINDINGS: LlmProviderBindings = {
documentation: "",
git_commit: "",
};
// ---------------------------------------------------------------------------
// URL tab helpers
// ---------------------------------------------------------------------------
/**
* Read the current settings tab from the URL hash fragment.
* Falls back to "environments" when the hash is missing or invalid.
*/
export function readTabFromUrl(): string {
const hash = typeof window !== "undefined" ? window.location.hash : "";
const tab = hash.replace(/^#\/?settings\//, "") || "";
return normalizeTab(tab) || "environments";
}
/**
* Write the active settings tab to the URL hash fragment so it survives
* browser refreshes and can be linked to directly.
*/
export function writeTabToUrl(tab: string): void {
if (typeof window === "undefined") return;
const normalized = normalizeTab(tab);
if (normalized) {
window.location.hash = `/settings/${normalized}`;
}
}
/**
* Normalise an arbitrary tab identifier to a valid tab key, or return null
* when the identifier does not match any known tab.
*/
export function normalizeTab(tab: string): string | null {
if (!tab || typeof tab !== "string") return null;
const candidate = tab.trim().toLowerCase();
return SETTINGS_TABS.includes(candidate as SettingsTab) ? candidate : null;
}
// ---------------------------------------------------------------------------
// LLM helpers
// ---------------------------------------------------------------------------
/**
* Merge incoming LLM settings with the default prompts and bindings so that
* individual fields are never accidentally set to `undefined`.
*/
export function normalizeLlmSettings(llm: LlmSettings | null | undefined): LlmSettings {
if (!llm || typeof llm !== "object") {
return {
prompts: { ...DEFAULT_LLM_PROMPTS },
provider_bindings: { ...DEFAULT_LLM_PROVIDER_BINDINGS },
};
}
return {
...llm,
prompts: { ...DEFAULT_LLM_PROMPTS, ...llm.prompts },
provider_bindings: {
...DEFAULT_LLM_PROVIDER_BINDINGS,
...llm.provider_bindings,
},
};
}
// ---------------------------------------------------------------------------
// Environment helpers
// ---------------------------------------------------------------------------
/**
* Strip trailing slashes and the `/api/v1` suffix from a Superset base URL,
* auto-prepend https:// if no scheme is present,
* returning a clean base URL suitable for constructing dashboard links.
*/
export function normalizeSupersetBaseUrl(rawUrl: string): string | null {
let baseUrl = String(rawUrl || "").trim().replace(/\/+$/, "");
if (!baseUrl) return null;
if (baseUrl.endsWith("/api/v1")) {
baseUrl = baseUrl.slice(0, -"/api/v1".length);
}
// Auto-prepend https:// if no scheme is present
if (baseUrl && !/^https?:\/\//i.test(baseUrl)) {
baseUrl = `https://${baseUrl}`;
}
return baseUrl;
}
/**
* Classify an environment's deployment stage from its `name` or `url`.
* Returns one of: `"PROD"`, `"PREPROD"`, or `"DEV"`.
*/
export function resolveEnvStage(env: { name?: string; url?: string } | null | undefined): string {
if (!env) return "DEV";
const needle = ((env.name || "") + " " + (env.url || "")).toLowerCase();
if (/prod(uction)?/.test(needle) && !/preprod/.test(needle)) return "PROD";
if (/preprod|staging|stage/.test(needle)) return "PREPROD";
return "DEV";
}
// ---------------------------------------------------------------------------
// Connection draft helper
// ---------------------------------------------------------------------------