refactor(types): migrate (window as any) statics to typed window globals
59 sites across 19 feature modules switched from `(window as any).foo` to the typed `window.foo` form against global-types.d.ts. The 7 remaining sites use dynamic string indexing (`window[fnName]`) where a typed access is impossible — those keep the narrow cast and are documented as the legitimate exception in the typedef file's header. global-types.d.ts grows entries for `loadIntegrations`, `loadUpdateSettings`, `loadUpdateStatus`, `initUpdateSettingsPanel`, `onTestDisplaySelected`, `openSettingsModal`, `renderAboutPanel`, `switchSettingsTab`. The `applyAccentColor` signature is widened to accept the (accent, persist) call shape observed at the appearance preset call site so tsc validates the real contract.
This commit is contained in:
@@ -804,7 +804,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||||||
startConnectionMonitor();
|
startConnectionMonitor();
|
||||||
|
|
||||||
// Expose auth state for inline scripts (after loadServerInfo sets it)
|
// Expose auth state for inline scripts (after loadServerInfo sets it)
|
||||||
(window as any)._authRequired = authRequired;
|
window._authRequired = authRequired;
|
||||||
if (typeof window.updateAuthUI === 'function') window.updateAuthUI();
|
if (typeof window.updateAuthUI === 'function') window.updateAuthUI();
|
||||||
|
|
||||||
// Server is unconfigured for LAN access → setup screen already shown by
|
// Server is unconfigured for LAN access → setup screen already shown by
|
||||||
|
|||||||
@@ -312,21 +312,21 @@ export async function loadServerInfo() {
|
|||||||
// Auth mode detection
|
// Auth mode detection
|
||||||
const authNeeded = data.auth_required !== false;
|
const authNeeded = data.auth_required !== false;
|
||||||
setAuthRequired(authNeeded);
|
setAuthRequired(authNeeded);
|
||||||
(window as any)._authRequired = authNeeded;
|
window._authRequired = authNeeded;
|
||||||
|
|
||||||
// Setup-required detection (LAN client + no keys configured server-side).
|
// Setup-required detection (LAN client + no keys configured server-side).
|
||||||
// When true, no API key will ever succeed — show a dedicated screen
|
// When true, no API key will ever succeed — show a dedicated screen
|
||||||
// instead of the login form.
|
// instead of the login form.
|
||||||
const setupNeeded = data.setup_required === true;
|
const setupNeeded = data.setup_required === true;
|
||||||
setSetupRequired(setupNeeded);
|
setSetupRequired(setupNeeded);
|
||||||
(window as any)._setupRequired = setupNeeded;
|
window._setupRequired = setupNeeded;
|
||||||
if (setupNeeded) {
|
if (setupNeeded) {
|
||||||
if (typeof window.showSetupRequiredModal === 'function') {
|
if (typeof window.showSetupRequiredModal === 'function') {
|
||||||
window.showSetupRequiredModal();
|
window.showSetupRequiredModal();
|
||||||
}
|
}
|
||||||
} else if (typeof window.hideSetupRequiredModal === 'function') {
|
} else if (typeof window.hideSetupRequiredModal === 'function') {
|
||||||
// Server was reconfigured — clear the setup overlay if it was up.
|
// Server was reconfigured — clear the setup overlay if it was up.
|
||||||
if ((window as any)._setupModalOpen) window.hideSetupRequiredModal();
|
if (window._setupModalOpen) window.hideSetupRequiredModal();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Project URLs (repo, donate)
|
// Project URLs (repo, donate)
|
||||||
|
|||||||
@@ -177,7 +177,7 @@ function _colorPopoverHtml(pickerId: string, currentColor: string): string {
|
|||||||
function getCardColorAriaLabel(): string {
|
function getCardColorAriaLabel(): string {
|
||||||
// i18n is not always loaded when this module evaluates (renders
|
// i18n is not always loaded when this module evaluates (renders
|
||||||
// happen during early page boot). Fall back to English.
|
// happen during early page boot). Fall back to English.
|
||||||
return (window as any).__t?.('common.card_color') || 'Card color';
|
return window.__t?.('common.card_color') || 'Card color';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -315,7 +315,7 @@ export function applyStylePreset(id: string): void {
|
|||||||
document.documentElement.style.setProperty('--font-heading', preset.fontHeading);
|
document.documentElement.style.setProperty('--font-heading', preset.fontHeading);
|
||||||
|
|
||||||
// Apply accent color via existing mechanism
|
// Apply accent color via existing mechanism
|
||||||
const applyAccent = (window as any).applyAccentColor;
|
const applyAccent = window.applyAccentColor;
|
||||||
if (typeof applyAccent === 'function') {
|
if (typeof applyAccent === 'function') {
|
||||||
applyAccent(preset.accent, true);
|
applyAccent(preset.accent, true);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -38,8 +38,8 @@ registerIconEntityType('automation', makeSimpleIconAdapter<Automation>({
|
|||||||
endpointPrefix: '/automations',
|
endpointPrefix: '/automations',
|
||||||
reload: async () => {
|
reload: async () => {
|
||||||
automationsCacheObj.invalidate();
|
automationsCacheObj.invalidate();
|
||||||
if (typeof (window as any).loadAutomations === 'function') {
|
if (typeof window.loadAutomations === 'function') {
|
||||||
await (window as any).loadAutomations();
|
await window.loadAutomations();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
typeLabelKey: 'device.icon.entity.automation',
|
typeLabelKey: 'device.icon.entity.automation',
|
||||||
@@ -653,7 +653,7 @@ export async function openAutomationEditor(automationId?: any, cloneData?: any)
|
|||||||
// Auto-name wiring
|
// Auto-name wiring
|
||||||
_autoNameManuallyEdited = !!(automationId || cloneData);
|
_autoNameManuallyEdited = !!(automationId || cloneData);
|
||||||
nameInput.oninput = () => { _autoNameManuallyEdited = true; };
|
nameInput.oninput = () => { _autoNameManuallyEdited = true; };
|
||||||
(window as any)._autoGenerateAutomationName = _autoGenerateAutomationName;
|
window._autoGenerateAutomationName = _autoGenerateAutomationName;
|
||||||
if (!automationId && !cloneData) _autoGenerateAutomationName();
|
if (!automationId && !cloneData) _autoGenerateAutomationName();
|
||||||
|
|
||||||
automationModal.open();
|
automationModal.open();
|
||||||
@@ -869,7 +869,7 @@ function addAutomationRuleRow(rule: any) {
|
|||||||
removeBtn.addEventListener('click', () => {
|
removeBtn.addEventListener('click', () => {
|
||||||
_disposeHTTPPollWidgets(container);
|
_disposeHTTPPollWidgets(container);
|
||||||
row.remove();
|
row.remove();
|
||||||
const autoGen = (window as any)._autoGenerateAutomationName;
|
const autoGen = window._autoGenerateAutomationName;
|
||||||
if (typeof autoGen === 'function') autoGen();
|
if (typeof autoGen === 'function') autoGen();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -31,8 +31,8 @@ registerIconEntityType('color_strip_source', makeSimpleIconAdapter<ColorStripSou
|
|||||||
endpointPrefix: '/color-strip-sources',
|
endpointPrefix: '/color-strip-sources',
|
||||||
reload: async () => {
|
reload: async () => {
|
||||||
colorStripSourcesCache.invalidate();
|
colorStripSourcesCache.invalidate();
|
||||||
if (typeof (window as any).loadPictureSources === 'function') {
|
if (typeof window.loadPictureSources === 'function') {
|
||||||
await (window as any).loadPictureSources();
|
await window.loadPictureSources();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
typeLabelKey: 'device.icon.entity.color_strip_source',
|
typeLabelKey: 'device.icon.entity.color_strip_source',
|
||||||
|
|||||||
@@ -263,7 +263,7 @@ function _openKCRegionEditor(): void {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
(window as any)._openKCRegionEditor = _openKCRegionEditor;
|
window._openKCRegionEditor = _openKCRegionEditor;
|
||||||
|
|
||||||
async function configureKCRegions(sourceId: string): Promise<void> {
|
async function configureKCRegions(sourceId: string): Promise<void> {
|
||||||
try {
|
try {
|
||||||
@@ -296,7 +296,7 @@ async function configureKCRegions(sourceId: string): Promise<void> {
|
|||||||
showToast(e.message, 'error');
|
showToast(e.message, 'error');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(window as any).configureKCRegions = configureKCRegions;
|
window.configureKCRegions = configureKCRegions;
|
||||||
|
|
||||||
// ══════════════════════════════════════════════════════════════════
|
// ══════════════════════════════════════════════════════════════════
|
||||||
// Type selector
|
// Type selector
|
||||||
|
|||||||
@@ -32,8 +32,8 @@ registerIconEntityType('game_integration', makeSimpleIconAdapter<GameIntegration
|
|||||||
endpointPrefix: '/game-integrations',
|
endpointPrefix: '/game-integrations',
|
||||||
reload: async () => {
|
reload: async () => {
|
||||||
gameIntegrationsCache.invalidate();
|
gameIntegrationsCache.invalidate();
|
||||||
if (typeof (window as any).loadIntegrations === 'function') {
|
if (typeof window.loadIntegrations === 'function') {
|
||||||
await (window as any).loadIntegrations();
|
await window.loadIntegrations();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
typeLabelKey: 'device.icon.entity.game_integration',
|
typeLabelKey: 'device.icon.entity.game_integration',
|
||||||
@@ -799,5 +799,5 @@ export async function loadGameIntegrations() {
|
|||||||
gameAdaptersCache.fetch(),
|
gameAdaptersCache.fetch(),
|
||||||
]);
|
]);
|
||||||
// Integrations.ts handles rendering via loadIntegrations
|
// Integrations.ts handles rendering via loadIntegrations
|
||||||
if ((window as any).loadIntegrations) (window as any).loadIntegrations();
|
if (window.loadIntegrations) window.loadIntegrations();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ registerIconEntityType('ha_source', makeSimpleIconAdapter<HomeAssistantSource>({
|
|||||||
cache: haSourcesCache,
|
cache: haSourcesCache,
|
||||||
endpointPrefix: '/home-assistant/sources',
|
endpointPrefix: '/home-assistant/sources',
|
||||||
reload: async () => {
|
reload: async () => {
|
||||||
if (typeof (window as any).loadIntegrations === 'function') {
|
if (typeof window.loadIntegrations === 'function') {
|
||||||
await (window as any).loadIntegrations();
|
await window.loadIntegrations();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
typeLabelKey: 'device.icon.entity.ha_source',
|
typeLabelKey: 'device.icon.entity.ha_source',
|
||||||
@@ -188,7 +188,7 @@ export async function saveHASource(): Promise<void> {
|
|||||||
showToast(t(id ? 'ha_source.updated' : 'ha_source.created'), 'success');
|
showToast(t(id ? 'ha_source.updated' : 'ha_source.created'), 'success');
|
||||||
haSourceModal.forceClose();
|
haSourceModal.forceClose();
|
||||||
haSourcesCache.invalidate();
|
haSourcesCache.invalidate();
|
||||||
if (typeof (window as any).loadIntegrations === 'function') await (window as any).loadIntegrations();
|
if (typeof window.loadIntegrations === 'function') await window.loadIntegrations();
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
if (e.isAuth) return;
|
if (e.isAuth) return;
|
||||||
haSourceModal.showError(e.message);
|
haSourceModal.showError(e.message);
|
||||||
@@ -234,7 +234,7 @@ export async function deleteHASource(sourceId: string): Promise<void> {
|
|||||||
}
|
}
|
||||||
showToast(t('ha_source.deleted'), 'success');
|
showToast(t('ha_source.deleted'), 'success');
|
||||||
haSourcesCache.invalidate();
|
haSourcesCache.invalidate();
|
||||||
if (typeof (window as any).loadIntegrations === 'function') await (window as any).loadIntegrations();
|
if (typeof window.loadIntegrations === 'function') await window.loadIntegrations();
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
if (e.isAuth) return;
|
if (e.isAuth) return;
|
||||||
showToast(e.message, 'error');
|
showToast(e.message, 'error');
|
||||||
|
|||||||
@@ -34,8 +34,8 @@ registerIconEntityType('http_endpoint', makeSimpleIconAdapter<HTTPEndpoint>({
|
|||||||
cache: httpEndpointsCache,
|
cache: httpEndpointsCache,
|
||||||
endpointPrefix: '/http/endpoints',
|
endpointPrefix: '/http/endpoints',
|
||||||
reload: async () => {
|
reload: async () => {
|
||||||
if (typeof (window as any).loadIntegrations === 'function') {
|
if (typeof window.loadIntegrations === 'function') {
|
||||||
await (window as any).loadIntegrations();
|
await window.loadIntegrations();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
typeLabelKey: 'device.icon.entity.http_endpoint',
|
typeLabelKey: 'device.icon.entity.http_endpoint',
|
||||||
@@ -329,7 +329,7 @@ export async function saveHTTPEndpoint(): Promise<void> {
|
|||||||
showToast(t(id ? 'http_endpoint.updated' : 'http_endpoint.created'), 'success');
|
showToast(t(id ? 'http_endpoint.updated' : 'http_endpoint.created'), 'success');
|
||||||
httpEndpointModal.forceClose();
|
httpEndpointModal.forceClose();
|
||||||
httpEndpointsCache.invalidate();
|
httpEndpointsCache.invalidate();
|
||||||
if (typeof (window as any).loadIntegrations === 'function') await (window as any).loadIntegrations();
|
if (typeof window.loadIntegrations === 'function') await window.loadIntegrations();
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
if (e.isAuth) return;
|
if (e.isAuth) return;
|
||||||
httpEndpointModal.showError(e.message);
|
httpEndpointModal.showError(e.message);
|
||||||
@@ -377,7 +377,7 @@ export async function deleteHTTPEndpoint(endpointId: string): Promise<void> {
|
|||||||
}
|
}
|
||||||
showToast(t('http_endpoint.deleted'), 'success');
|
showToast(t('http_endpoint.deleted'), 'success');
|
||||||
httpEndpointsCache.invalidate();
|
httpEndpointsCache.invalidate();
|
||||||
if (typeof (window as any).loadIntegrations === 'function') await (window as any).loadIntegrations();
|
if (typeof window.loadIntegrations === 'function') await window.loadIntegrations();
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
if (e.isAuth) return;
|
if (e.isAuth) return;
|
||||||
showToast(e.message, 'error');
|
showToast(e.message, 'error');
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ registerIconEntityType('mqtt_source', makeSimpleIconAdapter<MQTTSource>({
|
|||||||
cache: mqttSourcesCache,
|
cache: mqttSourcesCache,
|
||||||
endpointPrefix: '/mqtt/sources',
|
endpointPrefix: '/mqtt/sources',
|
||||||
reload: async () => {
|
reload: async () => {
|
||||||
if (typeof (window as any).loadIntegrations === 'function') {
|
if (typeof window.loadIntegrations === 'function') {
|
||||||
await (window as any).loadIntegrations();
|
await window.loadIntegrations();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
typeLabelKey: 'device.icon.entity.mqtt_source',
|
typeLabelKey: 'device.icon.entity.mqtt_source',
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ registerIconEntityType('scene_preset', makeSimpleIconAdapter<ScenePreset>({
|
|||||||
endpointPrefix: '/scene-presets',
|
endpointPrefix: '/scene-presets',
|
||||||
reload: async () => {
|
reload: async () => {
|
||||||
scenePresetsCache.invalidate();
|
scenePresetsCache.invalidate();
|
||||||
if (typeof (window as any).loadAutomations === 'function') {
|
if (typeof window.loadAutomations === 'function') {
|
||||||
await (window as any).loadAutomations();
|
await window.loadAutomations();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
typeLabelKey: 'device.icon.entity.scene_preset',
|
typeLabelKey: 'device.icon.entity.scene_preset',
|
||||||
|
|||||||
@@ -134,13 +134,13 @@ export function switchSettingsTab(tabId: string): void {
|
|||||||
window.renderAppearanceTab();
|
window.renderAppearanceTab();
|
||||||
}
|
}
|
||||||
// Lazy-load update settings
|
// Lazy-load update settings
|
||||||
if (tabId === 'updates' && typeof (window as any).loadUpdateSettings === 'function') {
|
if (tabId === 'updates' && typeof window.loadUpdateSettings === 'function') {
|
||||||
(window as any).initUpdateSettingsPanel();
|
window.initUpdateSettingsPanel?.();
|
||||||
(window as any).loadUpdateSettings();
|
window.loadUpdateSettings();
|
||||||
}
|
}
|
||||||
// Lazy-render the about panel content
|
// Lazy-render the about panel content
|
||||||
if (tabId === 'about' && typeof (window as any).renderAboutPanel === 'function') {
|
if (tabId === 'about' && typeof window.renderAboutPanel === 'function') {
|
||||||
(window as any).renderAboutPanel();
|
window.renderAboutPanel();
|
||||||
}
|
}
|
||||||
// Lazy-render the notifications panel (build IconSelects + load prefs)
|
// Lazy-render the notifications panel (build IconSelects + load prefs)
|
||||||
if (tabId === 'notifications') {
|
if (tabId === 'notifications') {
|
||||||
@@ -530,8 +530,8 @@ export function openSettingsModal(): void {
|
|||||||
// Refresh the update status so the rail badge ("update available" pill
|
// Refresh the update status so the rail badge ("update available" pill
|
||||||
// on the Updates tab) is current when the modal opens — it would
|
// on the Updates tab) is current when the modal opens — it would
|
||||||
// otherwise reflect whatever state the app loaded with.
|
// otherwise reflect whatever state the app loaded with.
|
||||||
if (typeof (window as any).loadUpdateStatus === 'function') {
|
if (typeof window.loadUpdateStatus === 'function') {
|
||||||
(window as any).loadUpdateStatus();
|
window.loadUpdateStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -399,7 +399,7 @@ export function openTestDisplayPicker() {
|
|||||||
const engineType = currentTestingTemplate?.engine_type || null;
|
const engineType = currentTestingTemplate?.engine_type || null;
|
||||||
const pickerEngineType = _engineHasOwnDisplays(engineType) ? engineType : null;
|
const pickerEngineType = _engineHasOwnDisplays(engineType) ? engineType : null;
|
||||||
const currentValue = (document.getElementById('test-template-display') as HTMLInputElement).value;
|
const currentValue = (document.getElementById('test-template-display') as HTMLInputElement).value;
|
||||||
openDisplayPicker((window as any).onTestDisplaySelected, currentValue, pickerEngineType);
|
openDisplayPicker(window.onTestDisplaySelected, currentValue, pickerEngineType);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadDisplaysForTest() {
|
async function loadDisplaysForTest() {
|
||||||
@@ -436,7 +436,7 @@ async function loadDisplaysForTest() {
|
|||||||
|
|
||||||
if (selectedIndex !== null && _cachedDisplays) {
|
if (selectedIndex !== null && _cachedDisplays) {
|
||||||
const display = _cachedDisplays.find(d => d.index === selectedIndex);
|
const display = _cachedDisplays.find(d => d.index === selectedIndex);
|
||||||
(window as any).onTestDisplaySelected(selectedIndex, display);
|
window.onTestDisplaySelected(selectedIndex, display);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error loading displays:', error);
|
console.error('Error loading displays:', error);
|
||||||
|
|||||||
@@ -80,8 +80,8 @@ import { registerIconEntityType, makeSimpleIconAdapter } from './icon-picker.ts'
|
|||||||
// ── Icon-picker adapter registrations for streams-tab card types ──
|
// ── Icon-picker adapter registrations for streams-tab card types ──
|
||||||
|
|
||||||
const _reloadStreams = async () => {
|
const _reloadStreams = async () => {
|
||||||
if (typeof (window as any).loadPictureSources === 'function') {
|
if (typeof window.loadPictureSources === 'function') {
|
||||||
await (window as any).loadPictureSources();
|
await window.loadPictureSources();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ registerIconEntityType('sync_clock', makeSimpleIconAdapter<SyncClock>({
|
|||||||
endpointPrefix: '/sync-clocks',
|
endpointPrefix: '/sync-clocks',
|
||||||
reload: async () => {
|
reload: async () => {
|
||||||
syncClocksCache.invalidate();
|
syncClocksCache.invalidate();
|
||||||
if (typeof (window as any).loadIntegrations === 'function') {
|
if (typeof window.loadIntegrations === 'function') {
|
||||||
await (window as any).loadIntegrations();
|
await window.loadIntegrations();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
typeLabelKey: 'device.icon.entity.sync_clock',
|
typeLabelKey: 'device.icon.entity.sync_clock',
|
||||||
|
|||||||
@@ -64,12 +64,12 @@ function _setVersionBadgeUpdate(hasUpdate: boolean): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function switchSettingsTabToUpdate(): void {
|
export function switchSettingsTabToUpdate(): void {
|
||||||
if (typeof (window as any).openSettingsModal === 'function') {
|
if (typeof window.openSettingsModal === 'function') {
|
||||||
(window as any).openSettingsModal();
|
window.openSettingsModal();
|
||||||
}
|
}
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (typeof (window as any).switchSettingsTab === 'function') {
|
if (typeof window.switchSettingsTab === 'function') {
|
||||||
(window as any).switchSettingsTab('updates');
|
window.switchSettingsTab('updates');
|
||||||
}
|
}
|
||||||
}, 50);
|
}, 50);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,8 +42,8 @@ registerIconEntityType('value_source', makeSimpleIconAdapter<any>({
|
|||||||
endpointPrefix: '/value-sources',
|
endpointPrefix: '/value-sources',
|
||||||
reload: async () => {
|
reload: async () => {
|
||||||
valueSourcesCache.invalidate();
|
valueSourcesCache.invalidate();
|
||||||
if (typeof (window as any).loadIntegrations === 'function') {
|
if (typeof window.loadIntegrations === 'function') {
|
||||||
await (window as any).loadIntegrations();
|
await window.loadIntegrations();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
typeLabelKey: 'device.icon.entity.value_source',
|
typeLabelKey: 'device.icon.entity.value_source',
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ registerIconEntityType('weather_source', makeSimpleIconAdapter<WeatherSource>({
|
|||||||
cache: weatherSourcesCache,
|
cache: weatherSourcesCache,
|
||||||
endpointPrefix: '/weather-sources',
|
endpointPrefix: '/weather-sources',
|
||||||
reload: async () => {
|
reload: async () => {
|
||||||
if (typeof (window as any).loadIntegrations === 'function') {
|
if (typeof window.loadIntegrations === 'function') {
|
||||||
await (window as any).loadIntegrations();
|
await window.loadIntegrations();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
typeLabelKey: 'device.icon.entity.weather_source',
|
typeLabelKey: 'device.icon.entity.weather_source',
|
||||||
@@ -180,7 +180,7 @@ export async function saveWeatherSource(): Promise<void> {
|
|||||||
showToast(t(id ? 'weather_source.updated' : 'weather_source.created'), 'success');
|
showToast(t(id ? 'weather_source.updated' : 'weather_source.created'), 'success');
|
||||||
weatherSourceModal.forceClose();
|
weatherSourceModal.forceClose();
|
||||||
weatherSourcesCache.invalidate();
|
weatherSourcesCache.invalidate();
|
||||||
if (typeof (window as any).loadIntegrations === 'function') await (window as any).loadIntegrations();
|
if (typeof window.loadIntegrations === 'function') await window.loadIntegrations();
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
if (e.isAuth) return;
|
if (e.isAuth) return;
|
||||||
weatherSourceModal.showError(e.message);
|
weatherSourceModal.showError(e.message);
|
||||||
@@ -226,7 +226,7 @@ export async function deleteWeatherSource(sourceId: string): Promise<void> {
|
|||||||
}
|
}
|
||||||
showToast(t('weather_source.deleted'), 'success');
|
showToast(t('weather_source.deleted'), 'success');
|
||||||
weatherSourcesCache.invalidate();
|
weatherSourcesCache.invalidate();
|
||||||
if (typeof (window as any).loadIntegrations === 'function') await (window as any).loadIntegrations();
|
if (typeof window.loadIntegrations === 'function') await window.loadIntegrations();
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
if (e.isAuth) return;
|
if (e.isAuth) return;
|
||||||
showToast(e.message, 'error');
|
showToast(e.message, 'error');
|
||||||
|
|||||||
+12
-1
@@ -27,7 +27,7 @@ declare global {
|
|||||||
__t?: (key: string) => string;
|
__t?: (key: string) => string;
|
||||||
|
|
||||||
// UI helpers exposed for inline onclick handlers in templates.
|
// UI helpers exposed for inline onclick handlers in templates.
|
||||||
applyAccentColor?: () => void;
|
applyAccentColor?: (accent?: string, persist?: boolean) => void;
|
||||||
hideSetupRequiredModal?: () => void;
|
hideSetupRequiredModal?: () => void;
|
||||||
configureKCRegions?: (sourceId: string) => void;
|
configureKCRegions?: (sourceId: string) => void;
|
||||||
removeZ2MLightMapping?: (btn: HTMLElement) => void;
|
removeZ2MLightMapping?: (btn: HTMLElement) => void;
|
||||||
@@ -36,8 +36,19 @@ declare global {
|
|||||||
// doesn't want a hard module import (to avoid cycles).
|
// doesn't want a hard module import (to avoid cycles).
|
||||||
loadAutomations?: () => Promise<void> | void;
|
loadAutomations?: () => Promise<void> | void;
|
||||||
loadPictureSources?: () => Promise<void> | void;
|
loadPictureSources?: () => Promise<void> | void;
|
||||||
|
loadIntegrations?: () => Promise<void> | void;
|
||||||
|
loadUpdateSettings?: () => Promise<void> | void;
|
||||||
|
loadUpdateStatus?: () => Promise<void> | void;
|
||||||
showPatternTemplateEditor?: (...args: unknown[]) => unknown;
|
showPatternTemplateEditor?: (...args: unknown[]) => unknown;
|
||||||
|
|
||||||
|
// Settings + about panel — bound by app boot and called from
|
||||||
|
// template handlers / nav buttons.
|
||||||
|
initUpdateSettingsPanel?: () => void;
|
||||||
|
onTestDisplaySelected?: (value: string) => void;
|
||||||
|
openSettingsModal?: (...args: unknown[]) => unknown;
|
||||||
|
renderAboutPanel?: () => void;
|
||||||
|
switchSettingsTab?: (tabId: string) => void;
|
||||||
|
|
||||||
// Internal helpers attached by features for inline-call reuse.
|
// Internal helpers attached by features for inline-call reuse.
|
||||||
_autoGenerateAutomationName?: () => void;
|
_autoGenerateAutomationName?: () => void;
|
||||||
_openKCRegionEditor?: (sourceId: string) => void;
|
_openKCRegionEditor?: (sourceId: string) => void;
|
||||||
|
|||||||
Reference in New Issue
Block a user