summaryrefslogtreecommitdiff
path: root/frontend/src/pages/ProjectDataTab.svelte
diff options
context:
space:
mode:
Diffstat (limited to 'frontend/src/pages/ProjectDataTab.svelte')
-rw-r--r--frontend/src/pages/ProjectDataTab.svelte85
1 files changed, 85 insertions, 0 deletions
diff --git a/frontend/src/pages/ProjectDataTab.svelte b/frontend/src/pages/ProjectDataTab.svelte
new file mode 100644
index 0000000..e3b1923
--- /dev/null
+++ b/frontend/src/pages/ProjectDataTab.svelte
@@ -0,0 +1,85 @@
+<script lang="ts">
+ import Status from '../components/Status.svelte';
+ import DatasetCard from '../components/DatasetCard.svelte';
+ import DatasetWizard from '../components/DatasetWizard.svelte';
+ import { listDatasets } from '../lib/client';
+ import { extractStatusMessage } from '../lib/state';
+ import type { Dataset } from '../lib/types';
+
+ interface Props {
+ projectId?: string;
+ showWizard?: boolean;
+ }
+ let { projectId: _projectId, showWizard = false }: Props = $props();
+
+ let items: Dataset[] = $state([]);
+ let busy = $state(true);
+ let error: string | null = $state(null);
+ // svelte-ignore state_referenced_locally
+ let wizardOpen = $state(showWizard);
+
+
+ let refreshTimer: ReturnType<typeof setInterval> | null = null;
+
+ $effect(() => {
+ void load();
+ return () => {
+ if (refreshTimer) clearInterval(refreshTimer);
+ refreshTimer = null;
+ };
+ });
+
+ async function load() {
+ error = null;
+ try {
+ const { items: got } = await listDatasets();
+ items = got;
+ const active = got.some((d) => d.status === 'pending' || d.status === 'running');
+ if (active && !refreshTimer) {
+ refreshTimer = setInterval(async () => {
+ try {
+ const { items: fresh } = await listDatasets();
+ items = fresh;
+ const still = fresh.some((d) => d.status === 'pending' || d.status === 'running');
+ if (!still && refreshTimer) {
+ clearInterval(refreshTimer);
+ refreshTimer = null;
+ }
+ } catch {
+ /* transient error, keep polling */
+ }
+ }, 2000);
+ }
+ } catch (e) {
+ error = extractStatusMessage(e);
+ } finally {
+ busy = false;
+ }
+ }
+</script>
+
+<div class="stack">
+ {#if wizardOpen}
+ <DatasetWizard onCreated={() => void load()} />
+ <button class="btn ghost" onclick={() => (wizardOpen = false)}>收起新建面板</button>
+ {:else}
+ <button class="btn primary" onclick={() => (wizardOpen = true)}>新建数据集</button>
+ {/if}
+
+ <h2>我的数据集</h2>
+ <Status busy={busy} error={error} busyText="加载数据集列表…" empty={null} />
+
+ {#if !busy && !error && items.length === 0}
+ <Status
+ busy={false}
+ empty="还没有数据集"
+ emptyHint="先创建数据集:选择标的、日期范围与复权方式,提交后异步获取并给出覆盖预览"
+ />
+ {/if}
+
+ {#if !busy && !error && items.length > 0}
+ {#each items as ds (ds.id)}
+ <DatasetCard dsId={ds.id} />
+ {/each}
+ {/if}
+</div>