Migrate frontend from JavaScript to TypeScript

- Rename all 54 .js files to .ts, update esbuild entry point
- Add tsconfig.json, TypeScript devDependency, typecheck script
- Create types.ts with 25+ interfaces matching backend Pydantic schemas
  (Device, OutputTarget, ColorStripSource, PatternTemplate, ValueSource,
  AudioSource, PictureSource, ScenePreset, SyncClock, Automation, etc.)
- Make DataCache generic (DataCache<T>) with typed state instances
- Type all state variables in state.ts with proper entity types
- Type all create*Card functions with proper entity interfaces
- Type all function parameters and return types across all 54 files
- Type core component constructors (CardSection, IconSelect, EntitySelect,
  FilterList, TagInput, TreeNav, Modal) with exported option interfaces
- Add comprehensive global.d.ts for window function declarations
- Type fetchWithAuth with FetchAuthOpts interface
- Remove all (window as any) casts in favor of global.d.ts declarations
- Zero tsc errors, esbuild bundle unchanged

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-19 13:08:23 +03:00
parent 55772b58dd
commit 997ff2fd70
61 changed files with 5382 additions and 3833 deletions

View File

@@ -0,0 +1,398 @@
/**
* Global type declarations for the WLED Screen Controller frontend.
* Extends Window with dynamic properties used across modules.
*/
declare class Chart {
constructor(canvas: any, config: any);
data: any;
options: any;
update(): void;
destroy(): void;
}
interface Window {
// ─── Auth (set by inline <script> in index.html) ───
updateAuthUI: (() => void) | undefined;
showApiKeyModal: ((msg: string | null, force?: boolean) => void) | undefined;
// ─── Core / state ───
setApiKey: (key: string | null) => void;
// ─── Visual effects (called from inline <script>) ───
_updateBgAnimAccent: (accent: string) => void;
_updateBgAnimTheme: (dark: boolean) => void;
_updateTabIndicator: () => void;
// ─── Core / UI ───
toggleHint: (...args: any[]) => any;
lockBody: () => void;
unlockBody: () => void;
closeLightbox: (...args: any[]) => void;
showToast: (...args: any[]) => any;
showConfirm: (...args: any[]) => any;
closeConfirmModal: (...args: any[]) => any;
openFullImageLightbox: (...args: any[]) => any;
showOverlaySpinner: (...args: any[]) => any;
hideOverlaySpinner: (...args: any[]) => any;
// ─── Core / API + i18n ───
t: (key: string, ...args: any[]) => string;
configureApiKey: (...args: any[]) => any;
loadServerInfo: (...args: any[]) => any;
loadDisplays: (...args: any[]) => any;
changeLocale: (...args: any[]) => any;
// ─── Displays ───
openDisplayPicker: (...args: any[]) => any;
closeDisplayPicker: (...args: any[]) => any;
selectDisplay: (...args: any[]) => any;
formatDisplayLabel: (...args: any[]) => any;
// ─── Tutorials ───
startCalibrationTutorial: (...args: any[]) => any;
startDeviceTutorial: (...args: any[]) => any;
startGettingStartedTutorial: (...args: any[]) => any;
startDashboardTutorial: (...args: any[]) => any;
startTargetsTutorial: (...args: any[]) => any;
startSourcesTutorial: (...args: any[]) => any;
startAutomationsTutorial: (...args: any[]) => any;
closeTutorial: (...args: any[]) => any;
tutorialNext: (...args: any[]) => any;
tutorialPrev: (...args: any[]) => any;
// ─── Devices ───
showSettings: (...args: any[]) => any;
closeDeviceSettingsModal: (...args: any[]) => any;
forceCloseDeviceSettingsModal: (...args: any[]) => any;
saveDeviceSettings: (...args: any[]) => any;
updateBrightnessLabel: (...args: any[]) => any;
saveCardBrightness: (...args: any[]) => any;
turnOffDevice: (...args: any[]) => any;
pingDevice: (...args: any[]) => any;
removeDevice: (...args: any[]) => any;
loadDevices: (...args: any[]) => any;
updateSettingsBaudFpsHint: (...args: any[]) => any;
copyWsUrl: (...args: any[]) => any;
cloneDevice: (...args: any[]) => any;
// ─── Dashboard ───
loadDashboard: (...args: any[]) => any;
stopUptimeTimer: (...args: any[]) => any;
dashboardToggleAutomation: (...args: any[]) => any;
dashboardStartTarget: (...args: any[]) => any;
dashboardStopTarget: (...args: any[]) => any;
dashboardStopAll: (...args: any[]) => any;
dashboardPauseClock: (...args: any[]) => any;
dashboardResumeClock: (...args: any[]) => any;
dashboardResetClock: (...args: any[]) => any;
toggleDashboardSection: (...args: any[]) => any;
changeDashboardPollInterval: (...args: any[]) => any;
startPerfPolling: (...args: any[]) => any;
stopPerfPolling: (...args: any[]) => any;
// ─── Streams / Capture templates / PP templates / Audio templates / CSPT ───
loadPictureSources: (...args: any[]) => any;
switchStreamTab: (subTab: string) => void;
showAddTemplateModal: (...args: any[]) => any;
editTemplate: (...args: any[]) => any;
closeTemplateModal: (...args: any[]) => any;
saveTemplate: (...args: any[]) => any;
deleteTemplate: (...args: any[]) => any;
showTestTemplateModal: (...args: any[]) => any;
closeTestTemplateModal: (...args: any[]) => any;
onEngineChange: (...args: any[]) => any;
runTemplateTest: (...args: any[]) => any;
updateCaptureDuration: (...args: any[]) => any;
showAddStreamModal: (...args: any[]) => any;
editStream: (...args: any[]) => any;
closeStreamModal: (...args: any[]) => any;
saveStream: (...args: any[]) => any;
deleteStream: (...args: any[]) => any;
onStreamTypeChange: (...args: any[]) => any;
onStreamDisplaySelected: (...args: any[]) => any;
onTestDisplaySelected: (...args: any[]) => any;
showTestStreamModal: (...args: any[]) => any;
closeTestStreamModal: (...args: any[]) => any;
updateStreamTestDuration: (...args: any[]) => any;
runStreamTest: (...args: any[]) => any;
showTestPPTemplateModal: (...args: any[]) => any;
closeTestPPTemplateModal: (...args: any[]) => any;
updatePPTestDuration: (...args: any[]) => any;
runPPTemplateTest: (...args: any[]) => any;
showAddPPTemplateModal: (...args: any[]) => any;
editPPTemplate: (...args: any[]) => any;
closePPTemplateModal: (...args: any[]) => any;
savePPTemplate: (...args: any[]) => any;
deletePPTemplate: (...args: any[]) => any;
addFilterFromSelect: (...args: any[]) => any;
toggleFilterExpand: (...args: any[]) => any;
removeFilter: (...args: any[]) => any;
moveFilter: (...args: any[]) => any;
updateFilterOption: (...args: any[]) => any;
renderModalFilterList: (...args: any[]) => any;
cloneStream: (...args: any[]) => any;
cloneCaptureTemplate: (...args: any[]) => any;
clonePPTemplate: (...args: any[]) => any;
showAddCSPTModal: (...args: any[]) => any;
editCSPT: (...args: any[]) => any;
closeCSPTModal: (...args: any[]) => any;
saveCSPT: (...args: any[]) => any;
deleteCSPT: (...args: any[]) => any;
cloneCSPT: (...args: any[]) => any;
csptAddFilterFromSelect: (...args: any[]) => any;
csptToggleFilterExpand: (...args: any[]) => any;
csptRemoveFilter: (...args: any[]) => any;
csptUpdateFilterOption: (...args: any[]) => any;
renderCSPTModalFilterList: (...args: any[]) => any;
showAddAudioTemplateModal: (...args: any[]) => any;
editAudioTemplate: (...args: any[]) => any;
closeAudioTemplateModal: (...args: any[]) => any;
saveAudioTemplate: (...args: any[]) => any;
deleteAudioTemplate: (...args: any[]) => any;
cloneAudioTemplate: (...args: any[]) => any;
onAudioEngineChange: (...args: any[]) => any;
showTestAudioTemplateModal: (...args: any[]) => any;
closeTestAudioTemplateModal: (...args: any[]) => any;
startAudioTemplateTest: (...args: any[]) => any;
// ─── KC Targets ───
createKCTargetCard: (...args: any[]) => any;
testKCTarget: (...args: any[]) => any;
showKCEditor: (...args: any[]) => any;
closeKCEditorModal: (...args: any[]) => any;
forceCloseKCEditorModal: (...args: any[]) => any;
saveKCEditor: (...args: any[]) => any;
deleteKCTarget: (...args: any[]) => any;
disconnectAllKCWebSockets: (...args: any[]) => any;
updateKCBrightnessLabel: (...args: any[]) => any;
saveKCBrightness: (...args: any[]) => any;
cloneKCTarget: (...args: any[]) => any;
// ─── Pattern Templates ───
createPatternTemplateCard: (...args: any[]) => any;
showPatternTemplateEditor: (...args: any[]) => any;
closePatternTemplateModal: (...args: any[]) => any;
forceClosePatternTemplateModal: (...args: any[]) => any;
savePatternTemplate: (...args: any[]) => any;
deletePatternTemplate: (...args: any[]) => any;
renderPatternRectList: (...args: any[]) => any;
selectPatternRect: (...args: any[]) => any;
updatePatternRect: (...args: any[]) => any;
addPatternRect: (...args: any[]) => any;
deleteSelectedPatternRect: (...args: any[]) => any;
removePatternRect: (...args: any[]) => any;
capturePatternBackground: (...args: any[]) => any;
clonePatternTemplate: (...args: any[]) => any;
// ─── Automations ───
loadAutomations: (...args: any[]) => any;
openAutomationEditor: (...args: any[]) => any;
closeAutomationEditorModal: (...args: any[]) => any;
saveAutomationEditor: (...args: any[]) => any;
addAutomationCondition: (...args: any[]) => any;
toggleAutomationEnabled: (...args: any[]) => any;
cloneAutomation: (...args: any[]) => any;
deleteAutomation: (...args: any[]) => any;
copyWebhookUrl: (...args: any[]) => any;
// ─── Scene Presets ───
openScenePresetCapture: (...args: any[]) => any;
editScenePreset: (...args: any[]) => any;
saveScenePreset: (...args: any[]) => any;
closeScenePresetEditor: (...args: any[]) => any;
activateScenePreset: (...args: any[]) => any;
recaptureScenePreset: (...args: any[]) => any;
cloneScenePreset: (...args: any[]) => any;
deleteScenePreset: (...args: any[]) => any;
addSceneTarget: (...args: any[]) => any;
removeSceneTarget: (...args: any[]) => any;
// ─── Device Discovery ───
onDeviceTypeChanged: (...args: any[]) => any;
updateBaudFpsHint: (...args: any[]) => any;
onSerialPortFocus: (...args: any[]) => any;
showAddDevice: (...args: any[]) => any;
closeAddDeviceModal: (...args: any[]) => any;
scanForDevices: (...args: any[]) => any;
handleAddDevice: (...args: any[]) => any;
// ─── Targets ───
loadTargetsTab: (...args: any[]) => any;
switchTargetSubTab: (subTab: string) => void;
showTargetEditor: (...args: any[]) => any;
closeTargetEditorModal: (...args: any[]) => any;
forceCloseTargetEditorModal: (...args: any[]) => any;
saveTargetEditor: (...args: any[]) => any;
startTargetProcessing: (...args: any[]) => any;
stopTargetProcessing: (...args: any[]) => any;
stopAllLedTargets: (...args: any[]) => any;
stopAllKCTargets: (...args: any[]) => any;
startTargetOverlay: (...args: any[]) => any;
stopTargetOverlay: (...args: any[]) => any;
deleteTarget: (...args: any[]) => any;
cloneTarget: (...args: any[]) => any;
toggleLedPreview: (...args: any[]) => any;
disconnectAllLedPreviewWS: (...args: any[]) => any;
// ─── Color-Strip Sources ───
showCSSEditor: (...args: any[]) => any;
closeCSSEditorModal: (...args: any[]) => any;
forceCSSEditorClose: (...args: any[]) => any;
saveCSSEditor: (...args: any[]) => any;
deleteColorStrip: (...args: any[]) => any;
onCSSTypeChange: (...args: any[]) => any;
onEffectTypeChange: (...args: any[]) => any;
onCSSClockChange: (...args: any[]) => any;
onAnimationTypeChange: (...args: any[]) => any;
onDaylightRealTimeChange: (...args: any[]) => any;
colorCycleAddColor: (...args: any[]) => any;
colorCycleRemoveColor: (...args: any[]) => any;
compositeAddLayer: (...args: any[]) => any;
compositeRemoveLayer: (...args: any[]) => any;
mappedAddZone: (...args: any[]) => any;
mappedRemoveZone: (...args: any[]) => any;
onAudioVizChange: (...args: any[]) => any;
applyGradientPreset: (...args: any[]) => any;
onGradientPresetChange: (...args: any[]) => any;
promptAndSaveGradientPreset: (...args: any[]) => any;
applyCustomGradientPreset: (...args: any[]) => any;
deleteAndRefreshGradientPreset: (...args: any[]) => any;
cloneColorStrip: (...args: any[]) => any;
toggleCSSOverlay: (...args: any[]) => any;
previewCSSFromEditor: (...args: any[]) => any;
copyEndpointUrl: (...args: any[]) => any;
onNotificationFilterModeChange: (...args: any[]) => any;
notificationAddAppColor: (...args: any[]) => any;
notificationRemoveAppColor: (...args: any[]) => any;
testNotification: (...args: any[]) => any;
showNotificationHistory: (...args: any[]) => any;
closeNotificationHistory: (...args: any[]) => any;
refreshNotificationHistory: (...args: any[]) => any;
testColorStrip: (...args: any[]) => any;
testCSPT: (...args: any[]) => any;
closeTestCssSourceModal: (...args: any[]) => any;
applyCssTestSettings: (...args: any[]) => any;
fireCssTestNotification: (...args: any[]) => any;
fireCssTestNotificationLayer: (...args: any[]) => any;
// ─── Audio Sources ───
showAudioSourceModal: (...args: any[]) => any;
closeAudioSourceModal: (...args: any[]) => any;
saveAudioSource: (...args: any[]) => any;
editAudioSource: (...args: any[]) => any;
cloneAudioSource: (...args: any[]) => any;
deleteAudioSource: (...args: any[]) => any;
testAudioSource: (...args: any[]) => any;
closeTestAudioSourceModal: (...args: any[]) => any;
refreshAudioDevices: (...args: any[]) => any;
// ─── Value Sources ───
showValueSourceModal: (...args: any[]) => any;
closeValueSourceModal: (...args: any[]) => any;
saveValueSource: (...args: any[]) => any;
editValueSource: (...args: any[]) => any;
cloneValueSource: (...args: any[]) => any;
deleteValueSource: (...args: any[]) => any;
onValueSourceTypeChange: (...args: any[]) => any;
onDaylightVSRealTimeChange: (...args: any[]) => any;
addSchedulePoint: (...args: any[]) => any;
testValueSource: (...args: any[]) => any;
closeTestValueSourceModal: (...args: any[]) => any;
// ─── Calibration ───
showCalibration: (...args: any[]) => any;
closeCalibrationModal: (...args: any[]) => any;
forceCloseCalibrationModal: (...args: any[]) => any;
saveCalibration: (...args: any[]) => any;
updateOffsetSkipLock: (...args: any[]) => any;
updateCalibrationPreview: (...args: any[]) => any;
setStartPosition: (...args: any[]) => any;
toggleEdgeInputs: (...args: any[]) => any;
toggleDirection: (...args: any[]) => any;
toggleTestEdge: (...args: any[]) => any;
showCSSCalibration: (...args: any[]) => any;
toggleCalibrationOverlay: (...args: any[]) => any;
// ─── Advanced Calibration ───
showAdvancedCalibration: (...args: any[]) => any;
closeAdvancedCalibration: (...args: any[]) => any;
saveAdvancedCalibration: (...args: any[]) => any;
addCalibrationLine: (...args: any[]) => any;
removeCalibrationLine: (...args: any[]) => any;
selectCalibrationLine: (...args: any[]) => any;
moveCalibrationLine: (...args: any[]) => any;
updateCalibrationLine: (...args: any[]) => any;
resetCalibrationView: (...args: any[]) => any;
// ─── Graph Editor ───
loadGraphEditor: (...args: any[]) => any;
toggleGraphLegend: (...args: any[]) => any;
toggleGraphMinimap: (...args: any[]) => any;
toggleGraphFilter: (...args: any[]) => any;
toggleGraphFilterTypes: (...args: any[]) => any;
toggleGraphHelp: (...args: any[]) => any;
graphUndo: (...args: any[]) => any;
graphRedo: (...args: any[]) => any;
graphFitAll: (...args: any[]) => any;
graphZoomIn: (...args: any[]) => any;
graphZoomOut: (...args: any[]) => any;
graphRelayout: (...args: any[]) => any;
graphToggleFullscreen: (...args: any[]) => any;
graphAddEntity: (...args: any[]) => any;
// ─── Tabs / Navigation / Command Palette ───
switchTab: (tab: string) => void;
startAutoRefresh: (...args: any[]) => any;
navigateToCard: (...args: any[]) => any;
openCommandPalette: (...args: any[]) => any;
closeCommandPalette: (...args: any[]) => any;
// ─── Settings ───
openSettingsModal: (...args: any[]) => any;
closeSettingsModal: (...args: any[]) => any;
switchSettingsTab: (...args: any[]) => any;
downloadBackup: (...args: any[]) => any;
handleRestoreFileSelected: (...args: any[]) => any;
saveAutoBackupSettings: (...args: any[]) => any;
restoreSavedBackup: (...args: any[]) => any;
downloadSavedBackup: (...args: any[]) => any;
deleteSavedBackup: (...args: any[]) => any;
restartServer: (...args: any[]) => any;
saveMqttSettings: (...args: any[]) => any;
loadApiKeysList: (...args: any[]) => any;
downloadPartialExport: (...args: any[]) => any;
handlePartialImportFileSelected: (...args: any[]) => any;
connectLogViewer: (...args: any[]) => any;
disconnectLogViewer: (...args: any[]) => any;
clearLogViewer: (...args: any[]) => any;
applyLogFilter: (...args: any[]) => any;
openLogOverlay: (...args: any[]) => any;
closeLogOverlay: (...args: any[]) => any;
loadLogLevel: (...args: any[]) => any;
setLogLevel: (...args: any[]) => any;
saveExternalUrl: (...args: any[]) => any;
getBaseOrigin: (...args: any[]) => any;
// ─── Overlay spinner internals ───
overlaySpinnerTimer: ReturnType<typeof setInterval> | null;
_overlayEscHandler: ((e: KeyboardEvent) => void) | null;
_overlayAbortController: AbortController | null;
// ─── Color picker ───
_cpCallbacks: Record<string, (hex: string) => void> | undefined;
_cpToggle: (id: string) => void;
_cpPick: (id: string, hex: string) => void;
_cpReset: (id: string, resetColor: string) => void;
// ─── Calibration internals (stored on window for cross-function state) ───
edgeSpans: Record<string, { start: number; end: number }>;
_calibrationResizeObserver: ResizeObserver | null;
_calibrationResizeRaf: number | null;
// ─── Targets internals ───
_targetAutoName: (...args: any[]) => any;
// ─── Dynamic loader functions (entity-events uses window[loaderName]()) ───
[key: string]: any;
}