173 lines
4.2 KiB
TypeScript
173 lines
4.2 KiB
TypeScript
import type {
|
|
IServiceStatus,
|
|
IIncidentDetails,
|
|
IStatusPageConfig,
|
|
IMonitorFormData,
|
|
IIncidentFormData,
|
|
} from '../interfaces/index.js';
|
|
|
|
type TStateChangeListener<T> = (data: T) => void;
|
|
|
|
/**
|
|
* Simple observable implementation for state changes
|
|
*/
|
|
class SimpleObservable<T> {
|
|
private listeners: Set<TStateChangeListener<T>> = new Set();
|
|
|
|
subscribe(listener: TStateChangeListener<T>): () => void {
|
|
this.listeners.add(listener);
|
|
return () => this.listeners.delete(listener);
|
|
}
|
|
|
|
next(value: T): void {
|
|
for (const listener of this.listeners) {
|
|
listener(value);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Centralized state management for the admin dashboard.
|
|
* Handles cross-view data passing and state synchronization.
|
|
*/
|
|
export class AdminState {
|
|
// Observable subjects for reactive updates
|
|
public monitors$ = new SimpleObservable<IServiceStatus[]>();
|
|
public incidents$ = new SimpleObservable<IIncidentDetails[]>();
|
|
public config$ = new SimpleObservable<IStatusPageConfig>();
|
|
|
|
// Current data
|
|
private _monitors: IServiceStatus[] = [];
|
|
private _incidents: IIncidentDetails[] = [];
|
|
private _config: IStatusPageConfig | null = null;
|
|
|
|
// Selected items for navigation context
|
|
private _selectedMonitor: IServiceStatus | null = null;
|
|
private _selectedIncident: IIncidentDetails | null = null;
|
|
|
|
// Monitors
|
|
get monitors(): IServiceStatus[] {
|
|
return this._monitors;
|
|
}
|
|
|
|
set monitors(value: IServiceStatus[]) {
|
|
this._monitors = value;
|
|
this.monitors$.next(value);
|
|
}
|
|
|
|
// Incidents
|
|
get incidents(): IIncidentDetails[] {
|
|
return this._incidents;
|
|
}
|
|
|
|
set incidents(value: IIncidentDetails[]) {
|
|
this._incidents = value;
|
|
this.incidents$.next(value);
|
|
}
|
|
|
|
// Config
|
|
get config(): IStatusPageConfig | null {
|
|
return this._config;
|
|
}
|
|
|
|
set config(value: IStatusPageConfig | null) {
|
|
this._config = value;
|
|
if (value) {
|
|
this.config$.next(value);
|
|
}
|
|
}
|
|
|
|
// Selected monitor for edit navigation
|
|
setSelectedMonitor(monitor: IServiceStatus | null): void {
|
|
this._selectedMonitor = monitor;
|
|
}
|
|
|
|
getSelectedMonitor(): IServiceStatus | null {
|
|
return this._selectedMonitor;
|
|
}
|
|
|
|
clearSelectedMonitor(): void {
|
|
this._selectedMonitor = null;
|
|
}
|
|
|
|
// Selected incident for edit navigation
|
|
setSelectedIncident(incident: IIncidentDetails | null): void {
|
|
this._selectedIncident = incident;
|
|
}
|
|
|
|
getSelectedIncident(): IIncidentDetails | null {
|
|
return this._selectedIncident;
|
|
}
|
|
|
|
clearSelectedIncident(): void {
|
|
this._selectedIncident = null;
|
|
}
|
|
|
|
// Helper methods
|
|
getCategories(): string[] {
|
|
const categories = new Set<string>();
|
|
for (const monitor of this._monitors) {
|
|
if (monitor.category) {
|
|
categories.add(monitor.category);
|
|
}
|
|
}
|
|
return Array.from(categories).sort();
|
|
}
|
|
|
|
getAvailableServices(): IServiceStatus[] {
|
|
return [...this._monitors];
|
|
}
|
|
|
|
getMonitorById(id: string): IServiceStatus | undefined {
|
|
return this._monitors.find(m => m.id === id);
|
|
}
|
|
|
|
getIncidentById(id: string): IIncidentDetails | undefined {
|
|
return this._incidents.find(i => i.id === id);
|
|
}
|
|
|
|
getActiveIncidents(): IIncidentDetails[] {
|
|
return this._incidents.filter(
|
|
i => !['resolved', 'postmortem'].includes(i.status)
|
|
);
|
|
}
|
|
|
|
getPastIncidents(): IIncidentDetails[] {
|
|
return this._incidents.filter(
|
|
i => ['resolved', 'postmortem'].includes(i.status)
|
|
);
|
|
}
|
|
|
|
// CRUD operations (these would typically call an API)
|
|
addMonitor(monitor: IServiceStatus): void {
|
|
this.monitors = [...this._monitors, monitor];
|
|
}
|
|
|
|
updateMonitor(id: string, data: Partial<IMonitorFormData>): void {
|
|
this.monitors = this._monitors.map(m =>
|
|
m.id === id ? { ...m, ...data } : m
|
|
);
|
|
}
|
|
|
|
deleteMonitor(id: string): void {
|
|
this.monitors = this._monitors.filter(m => m.id !== id);
|
|
}
|
|
|
|
addIncident(incident: IIncidentDetails): void {
|
|
this.incidents = [...this._incidents, incident];
|
|
}
|
|
|
|
updateIncident(id: string, data: Partial<IIncidentFormData>): void {
|
|
this.incidents = this._incidents.map(i =>
|
|
i.id === id ? { ...i, ...data } : i
|
|
);
|
|
}
|
|
|
|
deleteIncident(id: string): void {
|
|
this.incidents = this._incidents.filter(i => i.id !== id);
|
|
}
|
|
}
|
|
|
|
// Singleton instance
|
|
export const adminState = new AdminState();
|