Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions frontend/src/lib/api/placeholders.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import type {
CompletedPayload,
DashboardFoldersPayload,
DashboardSummaryPayload,
HostsPayload,
QueueLane
} from './types';

const emptyQueueLane: QueueLane = {
running: [],
queued: [],
pending_review: [],
running_count: 0,
queued_count: 0,
pending_review_count: 0
};

export const initialDashboard: DashboardSummaryPayload = {
folders_preview: [],
library_colors: {},
scan_job: null,
calibration_queue: {
sample: emptyQueueLane,
full: emptyQueueLane,
active_count: 0
},
encode_queue: {
running_count: 0,
queued_count: 0,
running: [],
queued: [],
state: { is_paused: false, stop_requested: false, scheduler_summary: 'loading' }
},
catalog_empty: false,
folder_cache_key: 'loading',
metric_support: { vmaf: false, xpsnr: false, ssim: false },
metric_status_copy: 'loading'
};

export const initialFoldersPayload: DashboardFoldersPayload = {
folders: [],
series_folders: [],
folder_cache_key: 'loading',
catalog_empty: false
};

export const initialHosts: HostsPayload = { compact: true, hosts: [] };

export const initialCompleted: CompletedPayload = {
folders: [],
completed_count: 0,
folders_with_backups_count: 0,
archive_cleanup: {
archive_root: '',
file_count: 0,
total_size_bytes: 0,
has_cleanup: false
},
history: []
};
16 changes: 10 additions & 6 deletions frontend/src/lib/components/workstation/HomeWorkbenchView.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -184,20 +184,22 @@
isFolderIndex ? `Matching ${folderScopeLabel.toLowerCase()}` : 'Workflow lanes'
);
const visibleScopeSummary = $derived(
foldersPending && !isFolderIndex
? 'Loading work folders'
foldersPending
? isFolderIndex
? `Loading ${folderScopeLabel.toLowerCase()}`
: 'Loading work folders'
: `${visibleFolders.length.toLocaleString('en-US')} / ${folders.length.toLocaleString(
'en-US'
)} ${isFolderIndex ? folderScopeLabel.toLowerCase() : 'folders'}`
);
const visibleFoldersCopy = $derived(
foldersPending && !isFolderIndex ? 'loading' : visibleFolders.length.toLocaleString('en-US')
foldersPending ? 'loading' : visibleFolders.length.toLocaleString('en-US')
);
const visiblePendingCopy = $derived(
foldersPending && !isFolderIndex ? 'loading' : visiblePendingItems.toLocaleString('en-US')
foldersPending ? 'loading' : visiblePendingItems.toLocaleString('en-US')
);
const visibleReclaimCopy = $derived(
foldersPending && !isFolderIndex ? 'loading' : formatBytes(visibleProjectedReclaim)
foldersPending ? 'loading' : formatBytes(visibleProjectedReclaim)
);

type LibraryOption = {
Expand Down Expand Up @@ -742,7 +744,9 @@
{/each}
{:else if foldersPending}
<tr>
<td colspan="8">Loading folder worklist...</td>
<td colspan="8">
{isFolderIndex ? 'Loading folder index...' : 'Loading folder worklist...'}
</td>
</tr>
{:else}
<tr>
Expand Down
40 changes: 1 addition & 39 deletions frontend/src/routes/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,52 +1,14 @@
<script lang="ts">
import { onMount } from 'svelte';
import { fetchJson } from '$lib/api/client';
import { initialDashboard, initialFoldersPayload, initialHosts } from '$lib/api/placeholders';
import type {
DashboardFoldersPayload,
DashboardSummaryPayload,
HostsPayload
} from '$lib/api/types';
import HomeWorkbenchView from '$lib/components/workstation/HomeWorkbenchView.svelte';

const emptyQueueLane = {
running: [],
queued: [],
pending_review: [],
running_count: 0,
queued_count: 0,
pending_review_count: 0
};

const initialDashboard: DashboardSummaryPayload = {
folders_preview: [],
library_colors: {},
scan_job: null,
calibration_queue: {
sample: emptyQueueLane,
full: emptyQueueLane,
active_count: 0
},
encode_queue: {
running_count: 0,
queued_count: 0,
running: [],
queued: [],
state: { is_paused: false, stop_requested: false, scheduler_summary: 'loading' }
},
catalog_empty: false,
folder_cache_key: 'loading',
metric_support: { vmaf: false, xpsnr: false, ssim: false },
metric_status_copy: 'loading'
};

const initialFoldersPayload: DashboardFoldersPayload = {
folders: [],
folder_cache_key: 'loading',
catalog_empty: false
};

const initialHosts: HostsPayload = { compact: true, hosts: [] };

let dashboard = $state<DashboardSummaryPayload>(initialDashboard);
let foldersPayload = $state<DashboardFoldersPayload>(initialFoldersPayload);
let hosts = $state<HostsPayload>(initialHosts);
Expand Down
7 changes: 1 addition & 6 deletions frontend/src/routes/completed/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import { fetchJson } from '$lib/api/client';
import type { CompletedPayload } from '$lib/api/types';
import CompletedWorkstationView from '$lib/components/workstation/CompletedWorkstationView.svelte';
import RouteLoadingView from '$lib/components/workstation/RouteLoadingView.svelte';

let completed = $state<CompletedPayload | null>(null);
let loadError = $state('');
Expand All @@ -21,8 +20,4 @@
<title>Mediaforce Completed</title>
</svelte:head>

{#if completed}
<CompletedWorkstationView {completed} loadError={null} />
{:else}
<RouteLoadingView route="completed" subject="Completed" crumb="/completed" error={loadError} />
{/if}
<CompletedWorkstationView {completed} loadError={loadError || null} />
25 changes: 16 additions & 9 deletions frontend/src/routes/folders/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
<script lang="ts">
import { onMount } from 'svelte';
import { fetchJson } from '$lib/api/client';
import { initialDashboard, initialFoldersPayload, initialHosts } from '$lib/api/placeholders';
import type {
DashboardFoldersPayload,
DashboardSummaryPayload,
HostsPayload
} from '$lib/api/types';
import HomeWorkbenchView from '$lib/components/workstation/HomeWorkbenchView.svelte';
import RouteLoadingView from '$lib/components/workstation/RouteLoadingView.svelte';

let dashboard = $state<DashboardSummaryPayload | null>(null);
let foldersPayload = $state<DashboardFoldersPayload | null>(null);
let hosts = $state<HostsPayload | null>(null);
let dashboard = $state<DashboardSummaryPayload>(initialDashboard);
let foldersPayload = $state<DashboardFoldersPayload>(initialFoldersPayload);
let hosts = $state<HostsPayload>(initialHosts);
let loadError = $state('');
let foldersPending = $state(true);

onMount(async () => {
try {
Expand All @@ -26,6 +27,8 @@
hosts = hostsPayload;
} catch (error) {
loadError = error instanceof Error ? error.message : 'Folders route failed to load.';
} finally {
foldersPending = false;
}
});
</script>
Expand All @@ -34,8 +37,12 @@
<title>Mediaforce Folders</title>
</svelte:head>

{#if dashboard && foldersPayload && hosts}
<HomeWorkbenchView crumb="/folders" {dashboard} {foldersPayload} {hosts} mode="folders" />
{:else}
<RouteLoadingView route="folders" subject="Folders" crumb="/folders" error={loadError} />
{/if}
<HomeWorkbenchView
crumb="/folders"
{dashboard}
{foldersPayload}
{hosts}
{foldersPending}
{loadError}
mode="folders"
/>
12 changes: 4 additions & 8 deletions frontend/src/routes/ops/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
<script lang="ts">
import { onMount } from 'svelte';
import { fetchJson } from '$lib/api/client';
import { initialDashboard, initialHosts } from '$lib/api/placeholders';
import type { DashboardSummaryPayload, HostsPayload } from '$lib/api/types';
import OpsWorkstationView from '$lib/components/workstation/OpsWorkstationView.svelte';
import RouteLoadingView from '$lib/components/workstation/RouteLoadingView.svelte';

let dashboard = $state<DashboardSummaryPayload | null>(null);
let hosts = $state<HostsPayload | null>(null);
let dashboard = $state<DashboardSummaryPayload | null>(initialDashboard);
let hosts = $state<HostsPayload | null>(initialHosts);
let loadError = $state('');

onMount(async () => {
Expand All @@ -27,8 +27,4 @@
<title>Mediaforce Ops</title>
</svelte:head>

{#if dashboard && hosts}
<OpsWorkstationView {dashboard} {hosts} loadError={null} />
{:else}
<RouteLoadingView route="ops" subject="Ops" crumb="/ops" error={loadError} />
{/if}
<OpsWorkstationView {dashboard} {hosts} loadError={loadError || null} />
33 changes: 31 additions & 2 deletions frontend/src/routes/settings/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,11 +1,40 @@
<script lang="ts">
import { onMount } from 'svelte';
import { fetchJson } from '$lib/api/client';
import type { HostsPayload, SettingsPayload } from '$lib/api/types';
import SettingsEditor from '$lib/components/settings/SettingsEditor.svelte';

let { data } = $props();
type SettledPayload<T> = { data: T; error: null } | { data: null; error: string };

let settings = $state<SettingsPayload | null>(null);
let hosts = $state<HostsPayload | null>(null);
let loadError = $state<string | null>(null);

function errorMessage(error: unknown): string {
return error instanceof Error ? error.message : 'Request failed.';
}

async function settle<T>(promise: Promise<T>): Promise<SettledPayload<T>> {
try {
return { data: await promise, error: null };
} catch (error) {
return { data: null, error: errorMessage(error) };
}
}

onMount(async () => {
const [settingsPayload, hostsPayload] = await Promise.all([
settle(fetchJson<SettingsPayload>('/api/settings?include_archive_cleanup=0')),
settle(fetchJson<HostsPayload>('/api/hosts?compact=1'))
]);
settings = settingsPayload.data;
hosts = hostsPayload.data;
loadError = [settingsPayload.error, hostsPayload.error].filter(Boolean).join(' · ') || null;
});
</script>

<svelte:head>
<title>Mediaforce Settings</title>
</svelte:head>

<SettingsEditor settings={data.settings} hosts={data.hosts} loadError={data.loadError} />
<SettingsEditor {settings} {hosts} {loadError} />
30 changes: 0 additions & 30 deletions frontend/src/routes/settings/+page.ts

This file was deleted.