refactor
This commit is contained in:
16
frontend/src/routes/storage/+page.svelte
Normal file
16
frontend/src/routes/storage/+page.svelte
Normal file
@@ -0,0 +1,16 @@
|
||||
<!-- [DEF:StorageIndexPage:Page] -->
|
||||
<!--
|
||||
@TIER: TRIVIAL
|
||||
@PURPOSE: Redirect to the backups page as the default storage view.
|
||||
@LAYER: Page
|
||||
@INVARIANT: Always redirects to /storage/backups.
|
||||
-->
|
||||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
import { goto } from '$app/navigation';
|
||||
|
||||
onMount(() => {
|
||||
goto('/storage/backups');
|
||||
});
|
||||
</script>
|
||||
<!-- [/DEF:StorageIndexPage:Page] -->
|
||||
35
frontend/src/routes/storage/backups/+page.svelte
Normal file
35
frontend/src/routes/storage/backups/+page.svelte
Normal file
@@ -0,0 +1,35 @@
|
||||
<!-- [DEF:StorageBackupsPage:Page] -->
|
||||
<!--
|
||||
@TIER: STANDARD
|
||||
@SEMANTICS: backup, page, tools
|
||||
@PURPOSE: Entry point for the Backup Management interface (moved from /tools/backups).
|
||||
@LAYER: Page
|
||||
@RELATION: USES -> BackupManager
|
||||
|
||||
@INVARIANT: BackupManager component is always rendered.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
/**
|
||||
* @UX_STATE: Loading -> (via BackupManager) showing spinner.
|
||||
* @UX_STATE: Idle -> Showing BackupManager interface.
|
||||
* @UX_FEEDBACK: Toast -> (via BackupManager) success/error notifications.
|
||||
*/
|
||||
// [SECTION: IMPORTS]
|
||||
import { t } from '$lib/i18n';
|
||||
import { PageHeader } from '$lib/ui';
|
||||
import BackupManager from '../../../components/backups/BackupManager.svelte';
|
||||
// [/SECTION]
|
||||
</script>
|
||||
|
||||
<!-- [SECTION: TEMPLATE] -->
|
||||
<div class="container mx-auto p-4 max-w-6xl">
|
||||
<PageHeader title={$t.nav?.backups || "Backups"} />
|
||||
|
||||
<div class="mt-6">
|
||||
<BackupManager />
|
||||
</div>
|
||||
</div>
|
||||
<!-- [/SECTION] -->
|
||||
|
||||
<!-- [/DEF:StorageBackupsPage:Page] -->
|
||||
110
frontend/src/routes/storage/repos/+page.svelte
Normal file
110
frontend/src/routes/storage/repos/+page.svelte
Normal file
@@ -0,0 +1,110 @@
|
||||
<!-- [DEF:frontend.src.routes.storage.repos.+page:Module] -->
|
||||
<!--
|
||||
@TIER: STANDARD
|
||||
@SEMANTICS: git, dashboard, management, ui
|
||||
@PURPOSE: Dashboard management page for Git integration (moved from /git).
|
||||
@LAYER: UI (Page)
|
||||
@RELATION: DEPENDS_ON -> DashboardGrid
|
||||
@RELATION: DEPENDS_ON -> api
|
||||
@INVARIANT: Dashboard grid is always shown when an environment is selected.
|
||||
-->
|
||||
|
||||
<!-- [DEF:StorageReposPage:Page] -->
|
||||
<script lang="ts">
|
||||
/**
|
||||
* @UX_STATE: Loading -> Showing spinner while fetching environments/dashboards.
|
||||
* @UX_STATE: Idle -> Showing dashboard grid with actions.
|
||||
* @UX_FEEDBACK: Toast -> Error messages on fetch failure.
|
||||
* @UX_RECOVERY: Environment Selection -> Switch environment to retry loading.
|
||||
*/
|
||||
import { onMount } from 'svelte';
|
||||
import DashboardGrid from '../../../components/DashboardGrid.svelte';
|
||||
import { addToast as toast } from '$lib/toasts.js';
|
||||
import { api } from '$lib/api.js';
|
||||
import type { DashboardMetadata } from '$lib/types/dashboard';
|
||||
import { t } from '$lib/i18n';
|
||||
import { Button, Card, PageHeader, Select } from '$lib/ui';
|
||||
|
||||
let environments: any[] = [];
|
||||
let selectedEnvId = "";
|
||||
let dashboards: DashboardMetadata[] = [];
|
||||
let loading = true;
|
||||
let fetchingDashboards = false;
|
||||
|
||||
// [DEF:fetchEnvironments:Function]
|
||||
/**
|
||||
* @PURPOSE: Fetches the list of available environments.
|
||||
* @PRE: None.
|
||||
* @POST: environments array is populated, selectedEnvId is set to first env if available.
|
||||
*/
|
||||
async function fetchEnvironments() {
|
||||
try {
|
||||
environments = await api.getEnvironmentsList();
|
||||
if (environments.length > 0) {
|
||||
selectedEnvId = environments[0].id;
|
||||
}
|
||||
} catch (e) {
|
||||
toast(e.message, 'error');
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
// [/DEF:fetchEnvironments:Function]
|
||||
|
||||
// [DEF:fetchDashboards:Function]
|
||||
/**
|
||||
* @PURPOSE: Fetches dashboards for a specific environment.
|
||||
* @PRE: envId is a valid environment ID.
|
||||
* @POST: dashboards array is populated with metadata for the selected environment.
|
||||
*/
|
||||
async function fetchDashboards(envId: string) {
|
||||
if (!envId) return;
|
||||
fetchingDashboards = true;
|
||||
try {
|
||||
dashboards = await api.requestApi(`/environments/${envId}/dashboards`);
|
||||
} catch (e) {
|
||||
toast(e.message, 'error');
|
||||
dashboards = [];
|
||||
} finally {
|
||||
fetchingDashboards = false;
|
||||
}
|
||||
}
|
||||
// [/DEF:fetchDashboards:Function]
|
||||
|
||||
onMount(fetchEnvironments);
|
||||
|
||||
$: if (selectedEnvId) {
|
||||
fetchDashboards(selectedEnvId);
|
||||
localStorage.setItem('selected_env_id', selectedEnvId);
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="max-w-6xl mx-auto p-6">
|
||||
<PageHeader title={$t.nav?.repositories || "Git Repositories"}>
|
||||
<div slot="actions" class="flex items-center space-x-4">
|
||||
<Select
|
||||
label="Environment"
|
||||
bind:value={selectedEnvId}
|
||||
options={environments.map(e => ({ value: e.id, label: e.name }))}
|
||||
/>
|
||||
</div>
|
||||
</PageHeader>
|
||||
|
||||
{#if loading}
|
||||
<div class="flex justify-center py-12">
|
||||
<div class="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600"></div>
|
||||
</div>
|
||||
{:else}
|
||||
<Card title="Select Dashboard to Manage">
|
||||
{#if fetchingDashboards}
|
||||
<p class="text-gray-500">Loading dashboards...</p>
|
||||
{:else if dashboards.length > 0}
|
||||
<DashboardGrid {dashboards} />
|
||||
{:else}
|
||||
<p class="text-gray-500 italic">No dashboards found in this environment.</p>
|
||||
{/if}
|
||||
</Card>
|
||||
{/if}
|
||||
</div>
|
||||
<!-- [/DEF:StorageReposPage:Page] -->
|
||||
<!-- [/DEF:frontend.src.routes.storage.repos.+page:Module] -->
|
||||
Reference in New Issue
Block a user