feat: add dataset review workspace navigation
This commit is contained in:
118
frontend/src/routes/datasets/review/+page.svelte
Normal file
118
frontend/src/routes/datasets/review/+page.svelte
Normal file
@@ -0,0 +1,118 @@
|
||||
<!-- [DEF:DatasetReviewWorkspaceEntry:Page] -->
|
||||
<!-- @COMPLEXITY: 3 -->
|
||||
<!-- @SEMANTICS: dataset-review, workspace-entry, source-intake, session-bootstrap -->
|
||||
<!-- @PURPOSE: Entry route for Dataset Review Workspace that allows starting a new resumable review session before navigating to a specific session id route. -->
|
||||
<!-- @LAYER: UI -->
|
||||
<!-- @RELATION: [CALLS] -> [api.postApi()](frontend/src/routes/datasets/review/+page.svelte:66) -->
|
||||
<!-- @RELATION: [BINDS_TO] -> [SourceIntakePanel](frontend/src/lib/components/dataset-review/SourceIntakePanel.svelte) -->
|
||||
<!-- @RELATION: [BINDS_TO] -> [environmentContextStore](frontend/src/routes/datasets/review/+page.svelte:24) -->
|
||||
<!-- @UX_STATE: Empty -> Show source intake for Superset link or dataset reference. -->
|
||||
<!-- @UX_STATE: Submitting -> Disable controls and show startup feedback. -->
|
||||
<!-- @UX_STATE: Error -> Inline error shown while keeping intake values editable. -->
|
||||
<!-- @UX_RECOVERY: Users can correct invalid input in place and retry without losing environment selection. -->
|
||||
<script>
|
||||
import { fromStore } from "svelte/store";
|
||||
import SourceIntakePanel from "$lib/components/dataset-review/SourceIntakePanel.svelte";
|
||||
import { t } from "$lib/i18n";
|
||||
import { api } from "$lib/api.js";
|
||||
import {
|
||||
environmentContextStore,
|
||||
initializeEnvironmentContext,
|
||||
} from "$lib/stores/environmentContext.js";
|
||||
|
||||
const environmentContextState = fromStore(environmentContextStore);
|
||||
|
||||
let isBootstrapping = $state(true);
|
||||
let isSubmitting = $state(false);
|
||||
let submitError = $state("");
|
||||
let intakeAcknowledgment = $state("");
|
||||
|
||||
const environments = $derived(environmentContextState.current?.environments || []);
|
||||
const selectedEnvironmentId = $derived(
|
||||
environmentContextState.current?.selectedEnvId || "",
|
||||
);
|
||||
|
||||
function buildSessionUrl(sessionId) {
|
||||
return `/datasets/review/${encodeURIComponent(String(sessionId))}`;
|
||||
}
|
||||
|
||||
async function bootstrap() {
|
||||
isBootstrapping = true;
|
||||
try {
|
||||
await initializeEnvironmentContext();
|
||||
} finally {
|
||||
isBootstrapping = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function handleSourceSubmit(payload) {
|
||||
isSubmitting = true;
|
||||
submitError = "";
|
||||
intakeAcknowledgment =
|
||||
payload.source_kind === "superset_link"
|
||||
? $t.dataset_review?.source?.recognized_link_hint
|
||||
: $t.dataset_review?.source?.dataset_selection_acknowledged;
|
||||
|
||||
try {
|
||||
const summary = await api.postApi("/dataset-orchestration/sessions", payload);
|
||||
if (!summary?.session_id) {
|
||||
throw new Error($t.dataset_review?.source?.submit_failed || "Failed to start review");
|
||||
}
|
||||
window.location.href = buildSessionUrl(summary.session_id);
|
||||
} catch (error) {
|
||||
submitError =
|
||||
error?.message ||
|
||||
$t.dataset_review?.source?.submit_failed ||
|
||||
$t.common?.error;
|
||||
throw error;
|
||||
} finally {
|
||||
isSubmitting = false;
|
||||
}
|
||||
}
|
||||
|
||||
bootstrap();
|
||||
</script>
|
||||
|
||||
<div class="mx-auto w-full max-w-7xl space-y-5 px-4 py-6">
|
||||
<div class="flex flex-col gap-3 lg:flex-row lg:items-start lg:justify-between">
|
||||
<div>
|
||||
<p class="text-xs font-semibold uppercase tracking-[0.2em] text-blue-700">
|
||||
{$t.dataset_review?.workspace?.eyebrow}
|
||||
</p>
|
||||
<h1 class="text-2xl font-bold text-slate-900">
|
||||
{$t.dataset_review?.workspace?.title}
|
||||
</h1>
|
||||
<p class="mt-1 max-w-3xl text-sm text-slate-600">
|
||||
{$t.dataset_review?.workspace?.description}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
<span class="rounded-full bg-slate-100 px-3 py-1 text-xs font-medium text-slate-700">
|
||||
{$t.dataset_review?.workspace?.state_label}: {$t.dataset_review?.workspace?.state?.empty || "Empty"}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if isBootstrapping}
|
||||
<div class="rounded-2xl border border-slate-200 bg-white p-6 text-sm text-slate-500 shadow-sm">
|
||||
{$t.dataset_review?.workspace?.loading}
|
||||
</div>
|
||||
{:else}
|
||||
<SourceIntakePanel
|
||||
environments={environments}
|
||||
selectedEnvironmentId={selectedEnvironmentId}
|
||||
submitting={isSubmitting}
|
||||
acknowledgment={intakeAcknowledgment}
|
||||
onsubmit={handleSourceSubmit}
|
||||
/>
|
||||
|
||||
{#if submitError}
|
||||
<div class="rounded-2xl border border-red-200 bg-red-50 px-4 py-4 text-sm text-red-700">
|
||||
{submitError}
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<!-- [/DEF:DatasetReviewWorkspaceEntry:Page] -->
|
||||
Reference in New Issue
Block a user