This commit is contained in:
jarek committed 2026-03-21 14:29:30 +01:00
1 parent aefa5e7925
commit b55e1e5aad
107 files changed
+2193 -443

No files matched your search

+31 -5
View File
@@ -13,10 +13,14 @@ export interface GridItem {
export interface DashboardPreferences {
gridLayout: GridItem[];
locked: boolean;
viewMode: 'grid' | 'list';
}
const defaultPreferences: DashboardPreferences = {
gridLayout: []
gridLayout: [],
locked: false,
viewMode: 'grid'
};
// Environment info from API
@@ -147,16 +151,20 @@ function createDashboardStore() {
const data = await response.json();
// Handle migration from old format
if (data.gridLayout && Array.isArray(data.gridLayout)) {
set({ gridLayout: data.gridLayout });
set({
gridLayout: data.gridLayout,
locked: data.locked ?? false,
viewMode: data.viewMode ?? 'grid'
});
} else {
set({ gridLayout: [] });
set(defaultPreferences);
}
} else {
set({ gridLayout: [] });
set(defaultPreferences);
}
} catch (error) {
console.error('Failed to load dashboard preferences:', error);
set({ gridLayout: [] });
set(defaultPreferences);
} finally {
// Always mark as initialized so saves can proceed
initialized = true;
@@ -206,6 +214,24 @@ function createDashboardStore() {
return newPrefs;
});
},
setLocked: (locked: boolean) => {
update(prefs => {
const newPrefs = { ...prefs, locked };
if (initialized) {
scheduleSave(newPrefs);
}
return newPrefs;
});
},
setViewMode: (viewMode: 'grid' | 'list') => {
update(prefs => {
const newPrefs = { ...prefs, viewMode };
if (initialized) {
scheduleSave(newPrefs);
}
return newPrefs;
});
},
reset: () => {
initialized = false;
set(defaultPreferences);
+52 -3
View File
@@ -27,8 +27,11 @@ export interface AppSettings {
eventPollInterval: number;
metricsCollectionInterval: number;
compactPorts: boolean;
formatLogTimestamps: boolean;
externalStackPaths: string[];
primaryStackLocation: string | null;
defaultGrypeImage: string;
defaultTrivyImage: string;
}
const DEFAULT_SETTINGS: AppSettings = {
@@ -52,8 +55,11 @@ const DEFAULT_SETTINGS: AppSettings = {
eventPollInterval: 60000,
metricsCollectionInterval: 30000,
compactPorts: false,
formatLogTimestamps: false,
externalStackPaths: [],
primaryStackLocation: null
primaryStackLocation: null,
defaultGrypeImage: 'anchore/grype:v0.110.0',
defaultTrivyImage: 'aquasec/trivy:0.69.3'
};
// Create a writable store for app settings
@@ -91,8 +97,11 @@ function createSettingsStore() {
eventPollInterval: settings.eventPollInterval ?? DEFAULT_SETTINGS.eventPollInterval,
metricsCollectionInterval: settings.metricsCollectionInterval ?? DEFAULT_SETTINGS.metricsCollectionInterval,
compactPorts: settings.compactPorts ?? DEFAULT_SETTINGS.compactPorts,
formatLogTimestamps: settings.formatLogTimestamps ?? DEFAULT_SETTINGS.formatLogTimestamps,
externalStackPaths: settings.externalStackPaths ?? DEFAULT_SETTINGS.externalStackPaths,
primaryStackLocation: settings.primaryStackLocation ?? DEFAULT_SETTINGS.primaryStackLocation
primaryStackLocation: settings.primaryStackLocation ?? DEFAULT_SETTINGS.primaryStackLocation,
defaultGrypeImage: settings.defaultGrypeImage ?? DEFAULT_SETTINGS.defaultGrypeImage,
defaultTrivyImage: settings.defaultTrivyImage ?? DEFAULT_SETTINGS.defaultTrivyImage
});
}
} catch {
@@ -133,8 +142,11 @@ function createSettingsStore() {
eventPollInterval: updatedSettings.eventPollInterval ?? DEFAULT_SETTINGS.eventPollInterval,
metricsCollectionInterval: updatedSettings.metricsCollectionInterval ?? DEFAULT_SETTINGS.metricsCollectionInterval,
compactPorts: updatedSettings.compactPorts ?? DEFAULT_SETTINGS.compactPorts,
formatLogTimestamps: updatedSettings.formatLogTimestamps ?? DEFAULT_SETTINGS.formatLogTimestamps,
externalStackPaths: updatedSettings.externalStackPaths ?? DEFAULT_SETTINGS.externalStackPaths,
primaryStackLocation: updatedSettings.primaryStackLocation ?? DEFAULT_SETTINGS.primaryStackLocation
primaryStackLocation: updatedSettings.primaryStackLocation ?? DEFAULT_SETTINGS.primaryStackLocation,
defaultGrypeImage: updatedSettings.defaultGrypeImage ?? DEFAULT_SETTINGS.defaultGrypeImage,
defaultTrivyImage: updatedSettings.defaultTrivyImage ?? DEFAULT_SETTINGS.defaultTrivyImage
});
}
} catch (error) {
@@ -301,6 +313,13 @@ function createSettingsStore() {
return newSettings;
});
},
setFormatLogTimestamps: (value: boolean) => {
update((current) => {
const newSettings = { ...current, formatLogTimestamps: value };
saveSettings({ formatLogTimestamps: value });
return newSettings;
});
},
setExternalStackPaths: (value: string[]) => {
update((current) => {
const newSettings = { ...current, externalStackPaths: value };
@@ -315,6 +334,20 @@ function createSettingsStore() {
return newSettings;
});
},
setDefaultGrypeImage: (value: string) => {
update((current) => {
const newSettings = { ...current, defaultGrypeImage: value };
saveSettings({ defaultGrypeImage: value });
return newSettings;
});
},
setDefaultTrivyImage: (value: string) => {
update((current) => {
const newSettings = { ...current, defaultTrivyImage: value };
saveSettings({ defaultTrivyImage: value });
return newSettings;
});
},
// Manual refresh from database
refresh: loadSettings
};
@@ -430,3 +463,19 @@ export function getTimeFormat(): TimeFormat {
export function getDateFormat(): DateFormat {
return cachedDateFormat;
}
// Regex matching ISO 8601 timestamps at the start of log lines (after optional container prefix)
// Matches: 2026-01-12T07:47:44.449821093Z or 2026-01-12T07:47:44Z
const ISO_TIMESTAMP_RE = /(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})(?:\.\d+)?Z/g;
/**
* Replace ISO 8601 timestamps in log text with formatted local timestamps.
* Uses the user's configured date/time format settings.
*/
export function formatLogTimestamps(text: string): string {
return text.replace(ISO_TIMESTAMP_RE, (_match, dateTimePart) => {
const d = new Date(_match);
if (isNaN(d.getTime())) return _match;
return `${formatDatePart(d)} ${formatTimePart(d, true)}`;
});
}
+2 -2
View File
@@ -264,7 +264,7 @@ function applyEditorFont(fontId: string) {
document.documentElement.style.setProperty('--font-editor', fontMeta.family);
}
// Load Google Font dynamically
// Load bundled font CSS (fonts are bundled in static/fonts/)
function loadGoogleFont(font: FontMeta) {
if (!font.googleFont) return;
@@ -274,7 +274,7 @@ function loadGoogleFont(font: FontMeta) {
const link = document.createElement('link');
link.id = linkId;
link.rel = 'stylesheet';
link.href = `https://fonts.googleapis.com/css2?family=${font.googleFont}&display=swap`;
link.href = `/fonts/${font.id}/font.css`;
document.head.appendChild(link);
}