Files
ss-tools/frontend/src/routes/+layout.svelte
busya 27168664b8 fix(translate): normalize Unix timestamps to YYYY-MM-DD for ClickHouse Date columns
- Add _normalize_timestamp_value to key column values in orchestrator.py and executor.py before SQL generation
- Fix test mocks for .options(joinedload()) chain, explicit None attrs for mock job
- Add global translation run progress indicator (TranslationRunGlobalIndicator + store)
- Fix translate page import missing translationRunStore
- All 208 translate tests pass
2026-05-15 22:06:27 +03:00

102 lines
4.5 KiB
Svelte

<!-- #region RootLayout [C:3] [TYPE Layout] [SEMANTICS sveltekit, layout, sidebar, navigation, shell] -->
<!-- @BRIEF Root layout component providing global UI structure: Sidebar, TopNavbar, Footer, TaskDrawer, Toasts. -->
<!-- @LAYER Layout -->
<!-- @RELATION DEPENDS_ON -> [Sidebar] -->
<!-- @RELATION DEPENDS_ON -> [TopNavbar] -->
<!-- @RELATION DEPENDS_ON -> [Footer] -->
<!-- @RELATION DEPENDS_ON -> [Toast] -->
<!-- @RELATION DEPENDS_ON -> [ProtectedRoute] -->
<!-- @RELATION DEPENDS_ON -> [TaskDrawer] -->
<!-- @RELATION DEPENDS_ON -> [Breadcrumbs] -->
<!-- @RELATION DEPENDS_ON -> [AssistantChatPanel] -->
<!-- @RELATION BINDS_TO -> [isProductionContextStore] -->
<!-- @RELATION BINDS_TO -> [selectedEnvironmentStore] -->
<!-- @RELATION BINDS_TO -> [sidebarStore] -->
<!-- @UX_STATE Loading -> Sidebar/TopNavbar rendered; page content loading. -->
<!-- @UX_STATE LoginRoute -> Only login page content rendered, no shell. -->
<!-- @UX_STATE Authenticated -> Full shell rendered with Sidebar, TopNavbar, Footer, global components. -->
<!-- @UX_FEEDBACK Production context warning bar visible when isProductionContext = true. -->
<!-- @UX_FEEDBACK Toast notifications rendered globally. -->
<!-- @INVARIANT All pages except /login wrapped in ProtectedRoute. -->
<!-- @INVARIANT Sidebar width adapts (ml-60 vs ml-16) based on sidebar expanded state. -->
<script>
import '../app.css';
import Navbar from '../components/Navbar.svelte';
import Footer from '../components/Footer.svelte';
import Toast from '../components/Toast.svelte';
import ProtectedRoute from '../components/auth/ProtectedRoute.svelte';
import Breadcrumbs from '$lib/components/layout/Breadcrumbs.svelte';
import Sidebar from '$lib/components/layout/Sidebar.svelte';
import TopNavbar from '$lib/components/layout/TopNavbar.svelte';
import TaskDrawer from '$lib/components/layout/TaskDrawer.svelte';
import AssistantChatPanel from '$lib/components/assistant/AssistantChatPanel.svelte';
import TranslationRunGlobalIndicator from '$lib/components/translate/TranslationRunGlobalIndicator.svelte';
import { t } from '$lib/i18n';
import {
isProductionContextStore,
selectedEnvironmentStore
} from '$lib/stores/environmentContext.js';
import { page } from '$app/state';
import { sidebarStore } from '$lib/stores/sidebar.js';
import { fromStore } from 'svelte/store';
let { children } = $props();
const sidebarState = fromStore(sidebarStore);
const productionContextState = fromStore(isProductionContextStore);
const selectedEnvironmentState = fromStore(selectedEnvironmentStore);
let isLoginPage = $derived(page.url.pathname === '/login');
let isExpanded = $derived(sidebarState.current?.isExpanded || true);
let isProductionContext = $derived(productionContextState.current);
let selectedEnvironment = $derived(selectedEnvironmentState.current);
</script>
<Toast />
<!-- Global persistent translation run progress indicator -->
<TranslationRunGlobalIndicator />
<main class="min-h-screen {isProductionContext ? 'bg-red-50/40' : 'bg-slate-50'}">
{#if isLoginPage}
<div class="p-4">
{@render children?.()}
</div>
{:else}
<ProtectedRoute>
<!-- Sidebar -->
<Sidebar />
<!-- Main content area with TopNavbar -->
<div class="flex flex-col min-h-screen {isExpanded ? 'md:ml-60' : 'md:ml-16'} transition-all duration-200">
<!-- Top Navigation Bar -->
<TopNavbar />
<!-- Breadcrumbs -->
<div class="mt-16 pt-3">
<Breadcrumbs />
</div>
{#if isProductionContext}
<div class="mx-4 mb-3 rounded-md border border-red-300 bg-red-100 px-4 py-2 text-sm font-semibold text-red-900 md:mx-6">
{$t.common?.prod_context_warning || "PROD context active"}:
{selectedEnvironment?.name || selectedEnvironment?.id || 'environment'}
</div>
{/if}
<!-- Page content -->
<div class="flex-grow px-4 pb-6 pt-2 md:px-6 {isProductionContext ? 'md:border-l-4 md:border-red-500' : ''}">
{@render children?.()}
</div>
<!-- Footer -->
<Footer />
</div>
<!-- Global Task Drawer -->
<TaskDrawer />
<AssistantChatPanel />
</ProtectedRoute>
{/if}
</main>
<!-- #endregion RootLayout -->