120 lines
5.6 KiB
JavaScript
120 lines
5.6 KiB
JavaScript
const VIEW_ROUTES = Object.freeze({
|
|
dashboard: '/dashboard',
|
|
devices: '/devices',
|
|
zones: '/zones',
|
|
groups: '/groups',
|
|
schedules: '/schedules',
|
|
automations: '/automations',
|
|
flows: '/flows',
|
|
simulation: '/simulation',
|
|
night: '/night-mode',
|
|
homeassistant: '/home-assistant',
|
|
settings: '/settings',
|
|
logs: '/events',
|
|
});
|
|
const ROUTE_VIEWS = Object.freeze(Object.fromEntries(Object.entries(VIEW_ROUTES).map(([view, path]) => [path, view])));
|
|
const HISTORY_TABS = Object.freeze(['overview', 'zones', 'devices', 'energy', 'network', 'sensors', 'custom']);
|
|
let routerInitialized = false;
|
|
|
|
function currentHistoryPath() {
|
|
const tab = HISTORY_TABS.includes(app.historyTab) ? app.historyTab : 'overview';
|
|
const params = new URLSearchParams();
|
|
const hours = $('#historyHours')?.value || new URLSearchParams(location.search).get('hours') || '24';
|
|
if (hours !== '24') params.set('hours', hours);
|
|
if (tab === 'zones' && app.historyZone !== 'all') params.set('zone', app.historyZone);
|
|
if (tab === 'devices' && app.historyDevice !== 'all') params.set('device', app.historyDevice);
|
|
if (tab === 'energy' && app.historyEnergyTargets?.length) params.set('targets', app.historyEnergyTargets.join(','));
|
|
if (tab === 'energy' && app.historyEnergyInterval !== 'daily') params.set('interval', app.historyEnergyInterval);
|
|
if (tab === 'energy' && app.historyEnergyCompare !== 'none') params.set('compare', app.historyEnergyCompare);
|
|
if (tab === 'network' && app.historyNetworkTarget !== 'all') params.set('target', app.historyNetworkTarget);
|
|
if (tab === 'sensors' && app.historySensor !== 'all') params.set('sensor', app.historySensor);
|
|
if (tab === 'custom' && app.customChartSeries.length) params.set('chart', encodeChartSpec(app.customChartSeries));
|
|
const query = params.toString();
|
|
return `/history/${tab}${query ? `?${query}` : ''}`;
|
|
}
|
|
|
|
function pathForView(name) {
|
|
return name === 'history' ? currentHistoryPath() : (VIEW_ROUTES[name] || VIEW_ROUTES.dashboard);
|
|
}
|
|
|
|
function appRelativePath(pathname = location.pathname) {
|
|
if (!APP_BASE) return pathname || '/';
|
|
if (pathname === APP_BASE) return '/';
|
|
if (pathname.startsWith(`${APP_BASE}/`)) return pathname.slice(APP_BASE.length) || '/';
|
|
return pathname || '/';
|
|
}
|
|
|
|
function updateBrowserUrl(path, replace = false) {
|
|
const normalized = path.startsWith('/') ? path : `/${path}`;
|
|
const target = `${APP_BASE}${normalized}` || normalized;
|
|
const current = `${location.pathname}${location.search}`;
|
|
if (current === target) return;
|
|
history[replace ? 'replaceState' : 'pushState']({}, '', target);
|
|
}
|
|
|
|
function restoreCurrentRoute(previousView) {
|
|
updateBrowserUrl(previousView === 'history' ? currentHistoryPath() : pathForView(previousView), true);
|
|
}
|
|
|
|
function applyRouteFromLocation() {
|
|
const routePath = appRelativePath();
|
|
const parts = routePath.split('/').filter(Boolean);
|
|
const first = parts[0] || 'dashboard';
|
|
const params = new URLSearchParams(location.search);
|
|
const previousView = app.currentView;
|
|
|
|
app.standaloneSimulation = first === 'simulation' && params.get('standalone') === '1';
|
|
document.body.classList.toggle('simulation-standalone', app.standaloneSimulation);
|
|
|
|
if (first === 'simulation') {
|
|
app.simulationScope = ['units', 'groups'].includes(params.get('scope')) ? params.get('scope') : 'units';
|
|
app.simulationTarget = params.get('target') || 'all';
|
|
}
|
|
|
|
if (first === 'history') {
|
|
app.historyTab = HISTORY_TABS.includes(parts[1]) ? parts[1] : 'overview';
|
|
app.historyZone = params.get('zone') || 'all';
|
|
app.historyDevice = params.get('device') || 'all';
|
|
if (app.historyTab === 'energy') {
|
|
const targetParam = params.get('targets') || params.get('device') || '';
|
|
app.historyEnergyTargets = targetParam ? targetParam.split(',').filter(Boolean).slice(0, 8) : (app.historyEnergyTargets || []);
|
|
app.historyEnergyDevice = app.historyEnergyTargets[0] || '';
|
|
if (['hourly', 'daily', 'weekly', 'monthly'].includes(params.get('interval'))) app.historyEnergyInterval = params.get('interval');
|
|
if (['none', 'previous_day', 'previous_period', 'previous_year'].includes(params.get('compare'))) app.historyEnergyCompare = params.get('compare');
|
|
}
|
|
app.historyNetworkTarget = params.get('target') || 'all';
|
|
app.historySensor = params.get('sensor') || 'all';
|
|
const hours = params.get('hours');
|
|
const validHours = hours && ['6', '24', '168', '720', '2160', '8760'].includes(hours) ? hours : null;
|
|
if (app.historyTab === 'energy') {
|
|
app.historyEnergyHours = validHours || app.historyEnergyHours || '720';
|
|
if ($('#historyHours')) $('#historyHours').value = app.historyEnergyHours;
|
|
} else if (validHours && $('#historyHours')) {
|
|
$('#historyHours').value = validHours;
|
|
}
|
|
if (app.historyTab === 'custom' && params.get('chart')) app.customChartSeries = decodeChartSpec(params.get('chart'));
|
|
if (!showView('history', { push: false, scroll: false })) restoreCurrentRoute(previousView);
|
|
return;
|
|
}
|
|
|
|
const view = first === 'index.html' ? 'dashboard' : ROUTE_VIEWS[`/${first}`];
|
|
if (!showView(view || 'dashboard', { push: false, scroll: false })) {
|
|
restoreCurrentRoute(previousView);
|
|
return;
|
|
}
|
|
|
|
if (first === 'flows') {
|
|
if (parts[1]) requestAnimationFrame(() => openFlowEditor(parts[1] === 'new' ? '' : parts[1], { push: false }));
|
|
else if (!$('#flowEditor')?.hidden) closeFlowEditor({ push: false, force: true });
|
|
}
|
|
if (!parts.length || first === 'index.html') updateBrowserUrl(VIEW_ROUTES.dashboard, true);
|
|
}
|
|
|
|
function initRouter() {
|
|
if (!routerInitialized) {
|
|
window.addEventListener('popstate', applyRouteFromLocation);
|
|
routerInitialized = true;
|
|
}
|
|
applyRouteFromLocation();
|
|
}
|