Pulse/frontend-modern/src/stores/alertsActivation.ts
rcourtman 6eb1a10d9b Refactor: Code cleanup and localStorage consolidation
This commit includes comprehensive codebase cleanup and refactoring:

## Code Cleanup
- Remove dead TypeScript code (types/monitoring.ts - 194 lines duplicate)
- Remove unused Go functions (GetClusterNodes, MigratePassword, GetClusterHealthInfo)
- Clean up commented-out code blocks across multiple files
- Remove unused TypeScript exports (helpTextClass, private tag color helpers)
- Delete obsolete test files and components

## localStorage Consolidation
- Centralize all storage keys into STORAGE_KEYS constant
- Update 5 files to use centralized keys:
  * utils/apiClient.ts (AUTH, LEGACY_TOKEN)
  * components/Dashboard/Dashboard.tsx (GUEST_METADATA)
  * components/Docker/DockerHosts.tsx (DOCKER_METADATA)
  * App.tsx (PLATFORMS_SEEN)
  * stores/updates.ts (UPDATES)
- Benefits: Single source of truth, prevents typos, better maintainability

## Previous Work Committed
- Docker monitoring improvements and disk metrics
- Security enhancements and setup fixes
- API refactoring and cleanup
- Documentation updates
- Build system improvements

## Testing
- All frontend tests pass (29 tests)
- All Go tests pass (15 packages)
- Production build successful
- Zero breaking changes

Total: 186 files changed, 5825 insertions(+), 11602 deletions(-)
2025-11-04 21:50:46 +00:00

139 lines
4 KiB
TypeScript

import { createSignal } from 'solid-js';
import { AlertsAPI } from '@/api/alerts';
import type { AlertConfig, ActivationState as ActivationStateType } from '@/types/alerts';
import type { Alert } from '@/types/api';
import { setGlobalActivationState } from '@/utils/alertsActivation';
import { logger } from '@/utils/logger';
// Create signals for activation state
const [config, setConfig] = createSignal<AlertConfig | null>(null);
const [activationState, setActivationStateSignal] = createSignal<ActivationStateType | null>(null);
const [isLoading, setIsLoading] = createSignal(false);
const [activeAlerts, setActiveAlerts] = createSignal<Alert[]>([]);
const [lastError, setLastError] = createSignal<string | null>(null);
const applyActivationState = (state: ActivationStateType | null) => {
setActivationStateSignal(state);
setGlobalActivationState(state);
};
const ensureConfigLoaded = async (): Promise<AlertConfig | null> => {
let current = config();
if (!current) {
await refreshConfig();
current = config();
}
return current;
};
// Refresh config from API
const refreshConfig = async (): Promise<void> => {
try {
setIsLoading(true);
setLastError(null);
const alertConfig = await AlertsAPI.getConfig();
setConfig(alertConfig);
applyActivationState(alertConfig.activationState || 'active');
} catch (error) {
logger.error('Failed to fetch alert config:', error);
setLastError(error instanceof Error ? error.message : 'Unknown error');
} finally {
setIsLoading(false);
}
};
// Fetch active alerts (for violation count)
const refreshActiveAlerts = async (): Promise<void> => {
try {
const alerts = await AlertsAPI.getActive();
setActiveAlerts(alerts);
} catch (error) {
logger.error('Failed to fetch active alerts:', error);
// Don't set error state for this - it's not critical
}
};
// Activate alert notifications
const activate = async (): Promise<boolean> => {
try {
setIsLoading(true);
setLastError(null);
const result = await AlertsAPI.activate();
if (result.success) {
// Refresh config to get updated state
await refreshConfig();
return true;
}
return false;
} catch (error) {
logger.error('Failed to activate alerts:', error);
setLastError(error instanceof Error ? error.message : 'Unknown error');
return false;
} finally {
setIsLoading(false);
}
};
const updateActivationState = async (state: ActivationStateType): Promise<boolean> => {
try {
setIsLoading(true);
setLastError(null);
const current = await ensureConfigLoaded();
if (!current) {
throw new Error('Alert configuration is unavailable');
}
const updated: AlertConfig = { ...current, activationState: state };
const result = await AlertsAPI.updateConfig(updated);
if (!result.success) {
return false;
}
setConfig(updated);
applyActivationState(state);
return true;
} catch (error) {
logger.error('Failed to update activation state:', error);
setLastError(error instanceof Error ? error.message : 'Unknown error');
return false;
} finally {
setIsLoading(false);
}
};
const deactivate = async (): Promise<boolean> => updateActivationState('pending_review');
const snooze = async (): Promise<boolean> => updateActivationState('snoozed');
// Check if past observation window
const isPastObservationWindow = (): boolean => {
const cfg = config();
if (!cfg || !cfg.activationTime || !cfg.observationWindowHours) {
return false;
}
const activationTime = new Date(cfg.activationTime);
const windowMs = cfg.observationWindowHours * 60 * 60 * 1000;
const expiryTime = activationTime.getTime() + windowMs;
return Date.now() > expiryTime;
};
// Export the store
export const useAlertsActivation = () => ({
// Signals
config,
activationState,
isLoading,
activeAlerts,
lastError,
// Computed
isPastObservationWindow,
// Actions
refreshConfig,
refreshActiveAlerts,
activate,
deactivate,
snooze,
});