Files
dockhand/lib/stores/environment.ts
Jarek Krochmalski 62e3c6439e Initial commit
2025-12-28 21:16:03 +01:00

164 lines
4.5 KiB
TypeScript

import { writable, get } from 'svelte/store';
import { browser } from '$app/environment';
export interface CurrentEnvironment {
id: number;
name: string;
highlightChanges?: boolean;
}
export interface Environment {
id: number;
name: string;
icon?: string;
host?: string;
port?: number;
protocol?: string;
socketPath?: string;
connectionType?: 'socket' | 'direct' | 'hawser-standard' | 'hawser-edge';
publicIp?: string | null;
}
const STORAGE_KEY = 'dockhand:environment';
// Load initial state from localStorage
function getInitialEnvironment(): CurrentEnvironment | null {
if (browser) {
const stored = localStorage.getItem(STORAGE_KEY);
if (stored) {
try {
return JSON.parse(stored);
} catch {
return null;
}
}
}
return null;
}
// Create a writable store for the current environment
function createEnvironmentStore() {
const { subscribe, set, update } = writable<CurrentEnvironment | null>(getInitialEnvironment());
return {
subscribe,
set: (value: CurrentEnvironment | null) => {
if (browser) {
if (value) {
localStorage.setItem(STORAGE_KEY, JSON.stringify(value));
} else {
localStorage.removeItem(STORAGE_KEY);
}
}
set(value);
},
update
};
}
export const currentEnvironment = createEnvironmentStore();
/**
* Call this when an API returns 404 for the current environment.
* Clears the stale environment from localStorage and store.
*/
export function clearStaleEnvironment(envId: number) {
if (browser) {
const current = get(currentEnvironment);
// Use Number() for type-safe comparison
if (current && Number(current.id) === Number(envId)) {
console.warn(`Environment ${envId} no longer exists, clearing from localStorage`);
currentEnvironment.set(null);
}
}
}
// Helper to get the environment ID for API calls
export function getEnvParam(envId: number | null | undefined): string {
return envId ? `?env=${envId}` : '';
}
// Helper to append env param to existing URL
export function appendEnvParam(url: string, envId: number | null | undefined): string {
if (!envId) return url;
const separator = url.includes('?') ? '&' : '?';
return `${url}${separator}env=${envId}`;
}
// Store for environments list with auto-refresh capability
function createEnvironmentsStore() {
const { subscribe, set, update } = writable<Environment[]>([]);
let loading = false;
async function fetchEnvironments() {
if (!browser || loading) return;
loading = true;
try {
const response = await fetch('/api/environments');
if (response.ok) {
const data: Environment[] = await response.json();
set(data);
// Auto-select environment if none selected or current one no longer exists
const current = get(currentEnvironment);
// Use Number() to handle any potential type mismatches from localStorage
const currentId = current ? Number(current.id) : null;
const currentExists = currentId !== null && data.some((e) => Number(e.id) === currentId);
console.log(`[EnvStore] refresh: current=${currentId}, exists=${currentExists}, envCount=${data.length}`);
if (data.length === 0) {
// No environments left - clear selection
console.log('[EnvStore] No environments, clearing selection');
currentEnvironment.set(null);
} else if (!current) {
// No selection - select first
console.log(`[EnvStore] No current env, selecting first: ${data[0].name}`);
const firstEnv = data[0];
currentEnvironment.set({
id: firstEnv.id,
name: firstEnv.name
});
} else if (!currentExists) {
// Current env was deleted - select first
console.warn(`[EnvStore] Environment ${currentId} no longer exists in list, selecting first: ${data[0].name}`);
const firstEnv = data[0];
currentEnvironment.set({
id: firstEnv.id,
name: firstEnv.name
});
} else {
console.log(`[EnvStore] Current env ${currentId} still exists, keeping selection`);
}
} else {
// Clear environments on permission denied or other errors
set([]);
// Also clear the current environment from localStorage
localStorage.removeItem(STORAGE_KEY);
currentEnvironment.set(null);
}
} catch (error) {
console.error('Failed to fetch environments:', error);
set([]);
localStorage.removeItem(STORAGE_KEY);
currentEnvironment.set(null);
} finally {
loading = false;
}
}
// Auto-fetch on browser load
if (browser) {
fetchEnvironments();
}
return {
subscribe,
refresh: fetchEnvironments,
set,
update
};
}
export const environments = createEnvironmentsStore();