feat: add dataset review workspace navigation
This commit is contained in:
@@ -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",
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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": "Бэкапы",
|
||||||
|
|||||||
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