feat: add dataset review workspace navigation

This commit is contained in:
2026-03-17 20:18:24 +03:00
parent 78f1e6803f
commit ad6a7eb755
4 changed files with 126 additions and 0 deletions

View File

@@ -69,6 +69,12 @@ export function buildSidebarCategories(i18nState, user) {
requiredPermission: "plugin:migration", requiredPermission: "plugin:migration",
requiredAction: "READ", requiredAction: "READ",
}, },
{
label: nav.dataset_review_workspace,
path: "/datasets/review",
requiredPermission: "plugin:migration",
requiredAction: "READ",
},
], ],
}, },
{ {

View File

@@ -45,6 +45,7 @@
"datasets": "Datasets", "datasets": "Datasets",
"overview": "Overview", "overview": "Overview",
"all_datasets": "All Datasets", "all_datasets": "All Datasets",
"dataset_review_workspace": "Review Workspace",
"health_center": "Health Center", "health_center": "Health Center",
"storage": "Storage", "storage": "Storage",
"backups": "Backups", "backups": "Backups",

View File

@@ -45,6 +45,7 @@
"datasets": "Датасеты", "datasets": "Датасеты",
"overview": "Обзор", "overview": "Обзор",
"all_datasets": "Все датасеты", "all_datasets": "Все датасеты",
"dataset_review_workspace": "Review Workspace",
"health_center": "Центр здоровья", "health_center": "Центр здоровья",
"storage": "Хранилище", "storage": "Хранилище",
"backups": "Бэкапы", "backups": "Бэкапы",

View 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] -->