mirror of
https://github.com/khoaliber/dockhand.git
synced 2026-03-07 13:22:54 +00:00
Initial commit
This commit is contained in:
163
lib/stores/environment.ts
Normal file
163
lib/stores/environment.ts
Normal file
@@ -0,0 +1,163 @@
|
||||
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();
|
||||
Reference in New Issue
Block a user