@burdenoff/microfe-export 2026.625.2 → 2026.626.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/export/pages/CreateExportPage.js +95 -90
- package/dist/export/pages/CreateExportPage.js.map +1 -1
- package/dist/export/pages/ExportDashboardPage.js +79 -46
- package/dist/export/pages/ExportDashboardPage.js.map +1 -1
- package/dist/export/pages/ExportDetailPage.js +157 -134
- package/dist/export/pages/ExportDetailPage.js.map +1 -1
- package/dist/export/pages/ExportHistoryPage.js +139 -135
- package/dist/export/pages/ExportHistoryPage.js.map +1 -1
- package/dist/export/pages/ExportTemplatesPage.js +172 -168
- package/dist/export/pages/ExportTemplatesPage.js.map +1 -1
- package/dist/export/pages/TemplateDetailPage.js +103 -97
- package/dist/export/pages/TemplateDetailPage.js.map +1 -1
- package/dist/node_modules/@apollo/client/version.js +1 -1
- package/dist/node_modules/@apollo/client/version.js.map +1 -1
- package/package.json +2 -2
|
@@ -8,35 +8,59 @@ import { PageLayout as o, PageSection as s } from "../components/PageLayout.js";
|
|
|
8
8
|
import { Activity as c, ArrowRight as l, CheckCircle2 as u, Clock as d, Download as f, FileBox as p, Plus as m } from "lucide-react";
|
|
9
9
|
import { jsx as h, jsxs as g } from "react/jsx-runtime";
|
|
10
10
|
import { useI18n as _ } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
11
|
-
import { AuroraBackground as v, EmphasisPanel as y, GlassCard as b, GradientText as x, IllustratedEmptyState as S } from "@burdenoff/fe-libs/ui";
|
|
11
|
+
import { AuroraBackground as v, EmphasisPanel as y, GlassCard as b, GradientText as x, IllustratedEmptyState as S, NextSteps as C, PagePurpose as w } from "@burdenoff/fe-libs/ui";
|
|
12
12
|
//#region src/export/pages/ExportDashboardPage.tsx
|
|
13
|
-
var
|
|
14
|
-
function
|
|
15
|
-
let { basePath:
|
|
13
|
+
var T = (e, t) => (e.endsWith("/") ? e.slice(0, -1) : e) + (t.startsWith("/") ? t : `/${t}`);
|
|
14
|
+
function E() {
|
|
15
|
+
let { basePath: E = "/", navigate: D } = e(), { t: O } = _(), k = (e, t, n) => r(O, e, t, n), { data: A, isLoading: j } = t({}), M = A.slice(0, 5), N = A.filter((e) => e.status === "RUNNING" || e.status === "QUEUED"), P = A.filter((e) => e.status === "COMPLETED"), F = [
|
|
16
16
|
{
|
|
17
17
|
icon: /* @__PURE__ */ h(f, { size: 18 }),
|
|
18
|
-
label:
|
|
19
|
-
value:
|
|
18
|
+
label: k("export.dashboard.metrics.total", "Total Exports"),
|
|
19
|
+
value: A.length,
|
|
20
20
|
treatment: "glass",
|
|
21
21
|
glow: !0
|
|
22
22
|
},
|
|
23
23
|
{
|
|
24
24
|
icon: /* @__PURE__ */ h(c, { size: 18 }),
|
|
25
|
-
label:
|
|
26
|
-
value:
|
|
25
|
+
label: k("export.dashboard.metrics.active", "Active"),
|
|
26
|
+
value: N.length,
|
|
27
27
|
treatment: "metric",
|
|
28
28
|
glow: !1
|
|
29
29
|
},
|
|
30
30
|
{
|
|
31
31
|
icon: /* @__PURE__ */ h(u, { size: 18 }),
|
|
32
|
-
label:
|
|
33
|
-
value:
|
|
32
|
+
label: k("export.dashboard.metrics.completed", "Completed"),
|
|
33
|
+
value: P.length,
|
|
34
34
|
treatment: "metric",
|
|
35
35
|
glow: !1
|
|
36
36
|
}
|
|
37
|
-
],
|
|
38
|
-
|
|
39
|
-
}
|
|
37
|
+
], I = (e) => {
|
|
38
|
+
D && D(T(E, e));
|
|
39
|
+
}, L = [
|
|
40
|
+
{
|
|
41
|
+
id: "create",
|
|
42
|
+
label: k("export.dashboard.nextSteps.create.label", "Create your first export"),
|
|
43
|
+
description: k("export.dashboard.nextSteps.create.description", "Pick the data you want and download it as CSV or JSON."),
|
|
44
|
+
icon: /* @__PURE__ */ h(m, { size: 16 }),
|
|
45
|
+
onClick: () => I("new"),
|
|
46
|
+
done: A.length > 0
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
id: "template",
|
|
50
|
+
label: k("export.dashboard.nextSteps.template.label", "Save a reusable template"),
|
|
51
|
+
description: k("export.dashboard.nextSteps.template.description", "Store a common export config so repeat exports are one click."),
|
|
52
|
+
icon: /* @__PURE__ */ h(p, { size: 16 }),
|
|
53
|
+
onClick: () => I("templates")
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
id: "history",
|
|
57
|
+
label: k("export.dashboard.nextSteps.history.label", "Track exports in History"),
|
|
58
|
+
description: k("export.dashboard.nextSteps.history.description", "Monitor progress and grab download links for finished jobs."),
|
|
59
|
+
icon: /* @__PURE__ */ h(d, { size: 16 }),
|
|
60
|
+
onClick: () => I("history"),
|
|
61
|
+
done: P.length > 0
|
|
62
|
+
}
|
|
63
|
+
];
|
|
40
64
|
return /* @__PURE__ */ g(o, {
|
|
41
65
|
showHeader: !1,
|
|
42
66
|
children: [
|
|
@@ -51,17 +75,26 @@ function w() {
|
|
|
51
75
|
className: "space-y-1",
|
|
52
76
|
children: [/* @__PURE__ */ h("h1", {
|
|
53
77
|
className: "text-2xl sm:text-3xl font-bold tracking-tight text-text-primary",
|
|
54
|
-
children: /* @__PURE__ */ h(x, { children:
|
|
78
|
+
children: /* @__PURE__ */ h(x, { children: k("export.dashboard.title", "Export") })
|
|
55
79
|
}), /* @__PURE__ */ h("p", {
|
|
56
80
|
className: "text-sm sm:text-base text-text-secondary max-w-2xl",
|
|
57
|
-
children:
|
|
81
|
+
children: k("export.dashboard.subtitle", "Export your workspace data in multiple formats")
|
|
58
82
|
})]
|
|
59
83
|
})]
|
|
60
84
|
})]
|
|
61
85
|
}),
|
|
62
|
-
|
|
86
|
+
/* @__PURE__ */ h(w, {
|
|
87
|
+
icon: /* @__PURE__ */ h(f, { size: 16 }),
|
|
88
|
+
children: k("export.dashboard.purpose", "Export takes your workspace data — people, projects, files, tags, activity and more — and packages it into downloadable CSV or JSON files. Use it to back up your data, hand it to another tool, run an audit, or take it with you when you leave. Pick what you want, choose a format, and grab the download when it's ready.")
|
|
89
|
+
}),
|
|
90
|
+
/* @__PURE__ */ h(C, {
|
|
91
|
+
storageKey: "export-dashboard",
|
|
92
|
+
title: k("export.dashboard.nextSteps.title", "Get started"),
|
|
93
|
+
steps: L
|
|
94
|
+
}),
|
|
95
|
+
!j && A.length > 0 && /* @__PURE__ */ h("div", {
|
|
63
96
|
className: "grid grid-cols-1 sm:grid-cols-3 gap-4",
|
|
64
|
-
children:
|
|
97
|
+
children: F.map((e) => /* @__PURE__ */ g(b, {
|
|
65
98
|
treatment: e.treatment,
|
|
66
99
|
glow: e.glow,
|
|
67
100
|
className: "p-5 border-border-seam",
|
|
@@ -83,35 +116,35 @@ function w() {
|
|
|
83
116
|
children: [
|
|
84
117
|
{
|
|
85
118
|
icon: /* @__PURE__ */ h(m, { size: 20 }),
|
|
86
|
-
label:
|
|
87
|
-
description:
|
|
119
|
+
label: k("export.dashboard.actions.newExport.label", "New Export"),
|
|
120
|
+
description: k("export.dashboard.actions.newExport.description", "Create a new data export"),
|
|
88
121
|
path: "new",
|
|
89
122
|
color: "bg-action-primary-bg/10 text-primary"
|
|
90
123
|
},
|
|
91
124
|
{
|
|
92
125
|
icon: /* @__PURE__ */ h(d, { size: 20 }),
|
|
93
|
-
label:
|
|
94
|
-
description:
|
|
126
|
+
label: k("export.dashboard.actions.history.label", "History"),
|
|
127
|
+
description: k("export.dashboard.actions.history.description", "View past exports"),
|
|
95
128
|
path: "history",
|
|
96
129
|
color: "bg-status-info-bg-subtle text-status-info-text"
|
|
97
130
|
},
|
|
98
131
|
{
|
|
99
132
|
icon: /* @__PURE__ */ h(p, { size: 20 }),
|
|
100
|
-
label:
|
|
101
|
-
description:
|
|
133
|
+
label: k("export.dashboard.actions.templates.label", "Templates"),
|
|
134
|
+
description: k("export.dashboard.actions.templates.description", "Reusable export configs"),
|
|
102
135
|
path: "templates",
|
|
103
136
|
color: "bg-accent-purple-subtle text-accent-purple"
|
|
104
137
|
},
|
|
105
138
|
{
|
|
106
139
|
icon: /* @__PURE__ */ h(c, { size: 20 }),
|
|
107
|
-
label:
|
|
108
|
-
description:
|
|
140
|
+
label: k("export.dashboard.actions.activeJobs.label", "Active Jobs"),
|
|
141
|
+
description: k("export.dashboard.actions.activeJobs.description", "{count} running", { count: N.length }),
|
|
109
142
|
path: "history?status=RUNNING",
|
|
110
143
|
color: "bg-status-success-bg-subtle text-status-success-text"
|
|
111
144
|
}
|
|
112
145
|
].map((e) => /* @__PURE__ */ g("button", {
|
|
113
146
|
type: "button",
|
|
114
|
-
onClick: () =>
|
|
147
|
+
onClick: () => I(e.path),
|
|
115
148
|
className: n("group relative overflow-hidden border border-border-seam rounded-xl p-5", "bg-bg-surface shadow-[var(--shadow-pop)]", "hover:border-primary/40 transition-colors duration-200", "text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/40"),
|
|
116
149
|
children: [
|
|
117
150
|
/* @__PURE__ */ h("div", {
|
|
@@ -133,23 +166,23 @@ function w() {
|
|
|
133
166
|
]
|
|
134
167
|
}, e.path + e.label))
|
|
135
168
|
}),
|
|
136
|
-
|
|
169
|
+
N.length > 0 && /* @__PURE__ */ g(y, {
|
|
137
170
|
"data-tour": "export-dashboard-active-section",
|
|
138
171
|
className: "p-5 sm:p-6",
|
|
139
172
|
children: [/* @__PURE__ */ g("div", {
|
|
140
173
|
className: "mb-4",
|
|
141
174
|
children: [/* @__PURE__ */ h("h2", {
|
|
142
175
|
className: "text-lg font-semibold text-text-primary",
|
|
143
|
-
children:
|
|
176
|
+
children: k("export.dashboard.active.title", "Active Exports")
|
|
144
177
|
}), /* @__PURE__ */ h("p", {
|
|
145
178
|
className: "text-sm text-text-secondary",
|
|
146
|
-
children:
|
|
179
|
+
children: k("export.dashboard.active.description", "Currently running export jobs")
|
|
147
180
|
})]
|
|
148
181
|
}), /* @__PURE__ */ h("div", {
|
|
149
182
|
className: "space-y-3",
|
|
150
|
-
children:
|
|
183
|
+
children: N.map((e) => /* @__PURE__ */ g("button", {
|
|
151
184
|
type: "button",
|
|
152
|
-
onClick: () =>
|
|
185
|
+
onClick: () => I(e.id),
|
|
153
186
|
className: n("w-full text-left border border-border-seam rounded-xl p-4 bg-bg-surface/70", "hover:border-primary/40 transition-colors duration-200", "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/40"),
|
|
154
187
|
children: [/* @__PURE__ */ g("div", {
|
|
155
188
|
className: "flex items-center justify-between mb-2",
|
|
@@ -166,15 +199,15 @@ function w() {
|
|
|
166
199
|
}),
|
|
167
200
|
/* @__PURE__ */ h(s, {
|
|
168
201
|
"data-tour": "export-dashboard-recent-section",
|
|
169
|
-
title:
|
|
170
|
-
description:
|
|
171
|
-
actions:
|
|
202
|
+
title: k("export.dashboard.recent.title", "Recent Exports"),
|
|
203
|
+
description: k("export.dashboard.recent.description", "Your latest export jobs"),
|
|
204
|
+
actions: M.length > 0 ? /* @__PURE__ */ h("button", {
|
|
172
205
|
type: "button",
|
|
173
|
-
onClick: () =>
|
|
206
|
+
onClick: () => I("history"),
|
|
174
207
|
className: "text-sm text-primary hover:underline font-medium",
|
|
175
|
-
children:
|
|
208
|
+
children: k("export.dashboard.recent.actions.viewAll", "View All")
|
|
176
209
|
}) : void 0,
|
|
177
|
-
children:
|
|
210
|
+
children: j ? /* @__PURE__ */ h("div", {
|
|
178
211
|
className: "space-y-3",
|
|
179
212
|
children: [...[
|
|
180
213
|
,
|
|
@@ -187,11 +220,11 @@ function w() {
|
|
|
187
220
|
children: [/* @__PURE__ */ h("div", { className: "h-4 w-48 bg-bg-sunken rounded animate-vc-shimmer" }), /* @__PURE__ */ h("div", { className: "h-5 w-20 bg-bg-sunken rounded-full animate-vc-shimmer" })]
|
|
188
221
|
}), /* @__PURE__ */ h("div", { className: "h-3 w-32 bg-bg-sunken rounded mt-2 animate-vc-shimmer" })]
|
|
189
222
|
}, t))
|
|
190
|
-
}) :
|
|
223
|
+
}) : M.length > 0 ? /* @__PURE__ */ h("div", {
|
|
191
224
|
className: "space-y-3",
|
|
192
|
-
children:
|
|
225
|
+
children: M.map((e, t) => /* @__PURE__ */ h("button", {
|
|
193
226
|
type: "button",
|
|
194
|
-
onClick: () =>
|
|
227
|
+
onClick: () => I(e.id),
|
|
195
228
|
className: n("w-full text-left border border-border-seam rounded-xl p-4 bg-bg-surface", "hover:border-primary/40 transition-colors duration-200", "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/40", "animate-in fade-in-0"),
|
|
196
229
|
style: { animationDelay: `${t * 50}ms` },
|
|
197
230
|
children: /* @__PURE__ */ g("div", {
|
|
@@ -207,7 +240,7 @@ function w() {
|
|
|
207
240
|
e.entityTypes.join(", "),
|
|
208
241
|
" · ",
|
|
209
242
|
e.format,
|
|
210
|
-
e.totalEntities != null && ` · ${
|
|
243
|
+
e.totalEntities != null && ` · ${k("export.dashboard.recent.entitiesCount", "{count} entities", { count: e.totalEntities.toLocaleString() })}`
|
|
211
244
|
]
|
|
212
245
|
})]
|
|
213
246
|
}), /* @__PURE__ */ g("div", {
|
|
@@ -221,13 +254,13 @@ function w() {
|
|
|
221
254
|
}, e.id))
|
|
222
255
|
}) : /* @__PURE__ */ h(S, {
|
|
223
256
|
illustration: "empty-files",
|
|
224
|
-
title:
|
|
225
|
-
description:
|
|
257
|
+
title: k("export.dashboard.empty.title", "No exports yet"),
|
|
258
|
+
description: k("export.dashboard.empty.description", "Create your first export to start downloading your workspace data."),
|
|
226
259
|
action: /* @__PURE__ */ g("button", {
|
|
227
260
|
type: "button",
|
|
228
|
-
onClick: () =>
|
|
261
|
+
onClick: () => I("new"),
|
|
229
262
|
className: "inline-flex items-center gap-2 px-4 py-2 bg-action-primary-bg text-action-primary-text rounded-lg hover:bg-action-primary-bg/90 transition-colors font-medium",
|
|
230
|
-
children: [/* @__PURE__ */ h(m, { size: 16 }),
|
|
263
|
+
children: [/* @__PURE__ */ h(m, { size: 16 }), k("export.dashboard.empty.actions.createFirst", "Create First Export")]
|
|
231
264
|
})
|
|
232
265
|
})
|
|
233
266
|
})
|
|
@@ -235,6 +268,6 @@ function w() {
|
|
|
235
268
|
});
|
|
236
269
|
}
|
|
237
270
|
//#endregion
|
|
238
|
-
export {
|
|
271
|
+
export { E as ExportDashboardPage };
|
|
239
272
|
|
|
240
273
|
//# sourceMappingURL=ExportDashboardPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExportDashboardPage.js","names":[],"sources":["../../../src/export/pages/ExportDashboardPage.tsx"],"sourcesContent":["import {\n Plus,\n Download,\n Clock,\n FileBox,\n ArrowRight,\n Activity,\n CheckCircle2,\n} from \"lucide-react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport {\n GlassCard,\n EmphasisPanel,\n AuroraBackground,\n GradientText,\n IllustratedEmptyState,\n} from \"@burdenoff/fe-libs/ui\";\nimport { useExport } from \"../providers/ExportProvider\";\nimport { useExportJobs } from \"../hooks/useExportQueries\";\nimport { ExportStatusBadge } from \"../components/ExportStatusBadge\";\nimport { ExportProgressBar } from \"../components/ExportProgressBar\";\nimport { PageLayout, PageSection } from \"../components/PageLayout\";\nimport { cn } from \"../utils/cn\";\nimport { tWithFallback } from \"../utils/i18n\";\n\n/**\n * Helper to join paths correctly, avoiding double slashes\n */\nconst joinPath = (base: string, path: string): string => {\n const cleanBase = base.endsWith(\"/\") ? base.slice(0, -1) : base;\n const cleanPath = path.startsWith(\"/\") ? path : `/${path}`;\n return cleanBase + cleanPath;\n};\n\n/**\n * Export Dashboard Page\n * Overview with recent exports, quick actions, and status summary\n */\nexport function ExportDashboardPage() {\n const { basePath = \"/\", navigate } = useExport();\n const { t } = useI18n();\n const tr = (\n key: string,\n fallback: string,\n params?: Record<string, string | number>,\n ) => tWithFallback(t, key, fallback, params);\n const { data: jobs, isLoading } = useExportJobs({});\n\n const recentJobs = jobs.slice(0, 5);\n const activeJobs = jobs.filter(\n (j) => j.status === \"RUNNING\" || j.status === \"QUEUED\",\n );\n const completedJobs = jobs.filter((j) => j.status === \"COMPLETED\");\n\n const metrics = [\n {\n icon: <Download size={18} />,\n label: tr(\"export.dashboard.metrics.total\", \"Total Exports\"),\n value: jobs.length,\n treatment: \"glass\" as const,\n glow: true,\n },\n {\n icon: <Activity size={18} />,\n label: tr(\"export.dashboard.metrics.active\", \"Active\"),\n value: activeJobs.length,\n treatment: \"metric\" as const,\n glow: false,\n },\n {\n icon: <CheckCircle2 size={18} />,\n label: tr(\"export.dashboard.metrics.completed\", \"Completed\"),\n value: completedJobs.length,\n treatment: \"metric\" as const,\n glow: false,\n },\n ];\n\n const handleNavigate = (path: string) => {\n if (!navigate) return;\n navigate(joinPath(basePath, path));\n };\n\n return (\n <PageLayout showHeader={false}>\n {/* Hero header with living-glass aurora backdrop (primary page only) */}\n <header className=\"relative overflow-hidden rounded-2xl\">\n <AuroraBackground intensity=\"subtle\" />\n <div className=\"relative flex items-center gap-3 px-2 py-4 sm:py-5\">\n <div className=\"flex-shrink-0 p-2.5 rounded-xl bg-action-primary-bg/10 text-primary\">\n <Download size={24} />\n </div>\n <div className=\"space-y-1\">\n <h1 className=\"text-2xl sm:text-3xl font-bold tracking-tight text-text-primary\">\n <GradientText>{tr(\"export.dashboard.title\", \"Export\")}</GradientText>\n </h1>\n <p className=\"text-sm sm:text-base text-text-secondary max-w-2xl\">\n {tr(\n \"export.dashboard.subtitle\",\n \"Export your workspace data in multiple formats\",\n )}\n </p>\n </div>\n </div>\n </header>\n\n {/* Metric strip */}\n {!isLoading && jobs.length > 0 && (\n <div className=\"grid grid-cols-1 sm:grid-cols-3 gap-4\">\n {metrics.map((m) => (\n <GlassCard\n key={m.label}\n treatment={m.treatment}\n glow={m.glow}\n className=\"p-5 border-border-seam\"\n >\n <div className=\"flex items-center gap-2 text-text-secondary mb-2\">\n {m.icon}\n <span className=\"text-xs font-medium\">{m.label}</span>\n </div>\n <p className=\"text-3xl font-bold tabular-nums text-text-primary\">\n {m.value.toLocaleString()}\n </p>\n </GlassCard>\n ))}\n </div>\n )}\n\n {/* Quick Actions */}\n <div\n className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4\"\n data-tour=\"export-dashboard-quick-actions\"\n >\n {[\n {\n icon: <Plus size={20} />,\n label: tr(\"export.dashboard.actions.newExport.label\", \"New Export\"),\n description: tr(\n \"export.dashboard.actions.newExport.description\",\n \"Create a new data export\",\n ),\n path: \"new\",\n color: \"bg-action-primary-bg/10 text-primary\",\n },\n {\n icon: <Clock size={20} />,\n label: tr(\"export.dashboard.actions.history.label\", \"History\"),\n description: tr(\n \"export.dashboard.actions.history.description\",\n \"View past exports\",\n ),\n path: \"history\",\n color: \"bg-status-info-bg-subtle text-status-info-text\",\n },\n {\n icon: <FileBox size={20} />,\n label: tr(\"export.dashboard.actions.templates.label\", \"Templates\"),\n description: tr(\n \"export.dashboard.actions.templates.description\",\n \"Reusable export configs\",\n ),\n path: \"templates\",\n color: \"bg-accent-purple-subtle text-accent-purple\",\n },\n {\n icon: <Activity size={20} />,\n label: tr(\n \"export.dashboard.actions.activeJobs.label\",\n \"Active Jobs\",\n ),\n description: tr(\n \"export.dashboard.actions.activeJobs.description\",\n \"{count} running\",\n { count: activeJobs.length },\n ),\n path: \"history?status=RUNNING\",\n color: \"bg-status-success-bg-subtle text-status-success-text\",\n },\n ].map((action) => (\n <button\n type=\"button\"\n key={action.path + action.label}\n onClick={() => handleNavigate(action.path)}\n className={cn(\n \"group relative overflow-hidden border border-border-seam rounded-xl p-5\",\n \"bg-bg-surface shadow-[var(--shadow-pop)]\",\n \"hover:border-primary/40 transition-colors duration-200\",\n \"text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/40\",\n )}\n >\n <div className={cn(\"p-2.5 rounded-lg w-fit mb-3\", action.color)}>\n {action.icon}\n </div>\n <h3 className=\"font-semibold text-text-primary mb-1\">\n {action.label}\n </h3>\n <p className=\"text-sm text-text-secondary\">\n {action.description}\n </p>\n <ArrowRight\n size={16}\n className=\"absolute top-5 right-5 text-text-secondary opacity-0 group-hover:opacity-100 transition-opacity\"\n />\n </button>\n ))}\n </div>\n\n {/* Active Exports — the single emphasised zone on this page */}\n {activeJobs.length > 0 && (\n <EmphasisPanel\n data-tour=\"export-dashboard-active-section\"\n className=\"p-5 sm:p-6\"\n >\n <div className=\"mb-4\">\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {tr(\"export.dashboard.active.title\", \"Active Exports\")}\n </h2>\n <p className=\"text-sm text-text-secondary\">\n {tr(\n \"export.dashboard.active.description\",\n \"Currently running export jobs\",\n )}\n </p>\n </div>\n <div className=\"space-y-3\">\n {activeJobs.map((job) => (\n <button\n type=\"button\"\n key={job.id}\n onClick={() => handleNavigate(job.id)}\n className={cn(\n \"w-full text-left border border-border-seam rounded-xl p-4 bg-bg-surface/70\",\n \"hover:border-primary/40 transition-colors duration-200\",\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/40\",\n )}\n >\n <div className=\"flex items-center justify-between mb-2\">\n <h4 className=\"font-semibold text-text-primary\">{job.name}</h4>\n <ExportStatusBadge status={job.status} />\n </div>\n <ExportProgressBar progress={job.progress} size=\"sm\" />\n </button>\n ))}\n </div>\n </EmphasisPanel>\n )}\n\n {/* Recent Exports */}\n <PageSection\n data-tour=\"export-dashboard-recent-section\"\n title={tr(\"export.dashboard.recent.title\", \"Recent Exports\")}\n description={tr(\n \"export.dashboard.recent.description\",\n \"Your latest export jobs\",\n )}\n actions={\n recentJobs.length > 0 ? (\n <button\n type=\"button\"\n onClick={() => handleNavigate(\"history\")}\n className=\"text-sm text-primary hover:underline font-medium\"\n >\n {tr(\"export.dashboard.recent.actions.viewAll\", \"View All\")}\n </button>\n ) : undefined\n }\n >\n {isLoading ? (\n <div className=\"space-y-3\">\n {[...Array(3)].map((_, i) => (\n <div\n key={i}\n className=\"border border-border-seam rounded-xl p-4\"\n >\n <div className=\"flex items-center justify-between mb-2\">\n <div className=\"h-4 w-48 bg-bg-sunken rounded animate-vc-shimmer\" />\n <div className=\"h-5 w-20 bg-bg-sunken rounded-full animate-vc-shimmer\" />\n </div>\n <div className=\"h-3 w-32 bg-bg-sunken rounded mt-2 animate-vc-shimmer\" />\n </div>\n ))}\n </div>\n ) : recentJobs.length > 0 ? (\n <div className=\"space-y-3\">\n {recentJobs.map((job, index) => (\n <button\n type=\"button\"\n key={job.id}\n onClick={() => handleNavigate(job.id)}\n className={cn(\n \"w-full text-left border border-border-seam rounded-xl p-4 bg-bg-surface\",\n \"hover:border-primary/40 transition-colors duration-200\",\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/40\",\n \"animate-in fade-in-0\",\n )}\n style={{ animationDelay: `${index * 50}ms` }}\n >\n <div className=\"flex items-start sm:items-center justify-between gap-3\">\n <div className=\"flex-1 min-w-0\">\n <h4 className=\"font-semibold text-text-primary truncate\">\n {job.name}\n </h4>\n <p className=\"text-sm text-text-secondary mt-1 line-clamp-2\">\n {job.entityTypes.join(\", \")} · {job.format}\n {job.totalEntities != null &&\n ` · ${tr(\n \"export.dashboard.recent.entitiesCount\",\n \"{count} entities\",\n { count: job.totalEntities.toLocaleString() },\n )}`}\n </p>\n </div>\n <div className=\"flex items-center gap-2 flex-shrink-0\">\n <ExportStatusBadge status={job.status} />\n <ArrowRight\n size={16}\n className=\"text-text-secondary hidden sm:block\"\n />\n </div>\n </div>\n </button>\n ))}\n </div>\n ) : (\n <IllustratedEmptyState\n illustration=\"empty-files\"\n title={tr(\"export.dashboard.empty.title\", \"No exports yet\")}\n description={tr(\n \"export.dashboard.empty.description\",\n \"Create your first export to start downloading your workspace data.\",\n )}\n action={\n <button\n type=\"button\"\n onClick={() => handleNavigate(\"new\")}\n className=\"inline-flex items-center gap-2 px-4 py-2 bg-action-primary-bg text-action-primary-text rounded-lg hover:bg-action-primary-bg/90 transition-colors font-medium\"\n >\n <Plus size={16} />\n {tr(\n \"export.dashboard.empty.actions.createFirst\",\n \"Create First Export\",\n )}\n </button>\n }\n />\n )}\n </PageSection>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ExportDashboardPage.js","names":[],"sources":["../../../src/export/pages/ExportDashboardPage.tsx"],"sourcesContent":["import {\n Plus,\n Download,\n Clock,\n FileBox,\n ArrowRight,\n Activity,\n CheckCircle2,\n} from \"lucide-react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport {\n GlassCard,\n EmphasisPanel,\n AuroraBackground,\n GradientText,\n IllustratedEmptyState,\n PagePurpose,\n NextSteps,\n type NextStep,\n} from \"@burdenoff/fe-libs/ui\";\nimport { useExport } from \"../providers/ExportProvider\";\nimport { useExportJobs } from \"../hooks/useExportQueries\";\nimport { ExportStatusBadge } from \"../components/ExportStatusBadge\";\nimport { ExportProgressBar } from \"../components/ExportProgressBar\";\nimport { PageLayout, PageSection } from \"../components/PageLayout\";\nimport { cn } from \"../utils/cn\";\nimport { tWithFallback } from \"../utils/i18n\";\n\n/**\n * Helper to join paths correctly, avoiding double slashes\n */\nconst joinPath = (base: string, path: string): string => {\n const cleanBase = base.endsWith(\"/\") ? base.slice(0, -1) : base;\n const cleanPath = path.startsWith(\"/\") ? path : `/${path}`;\n return cleanBase + cleanPath;\n};\n\n/**\n * Export Dashboard Page\n * Overview with recent exports, quick actions, and status summary\n */\nexport function ExportDashboardPage() {\n const { basePath = \"/\", navigate } = useExport();\n const { t } = useI18n();\n const tr = (\n key: string,\n fallback: string,\n params?: Record<string, string | number>,\n ) => tWithFallback(t, key, fallback, params);\n const { data: jobs, isLoading } = useExportJobs({});\n\n const recentJobs = jobs.slice(0, 5);\n const activeJobs = jobs.filter(\n (j) => j.status === \"RUNNING\" || j.status === \"QUEUED\",\n );\n const completedJobs = jobs.filter((j) => j.status === \"COMPLETED\");\n\n const metrics = [\n {\n icon: <Download size={18} />,\n label: tr(\"export.dashboard.metrics.total\", \"Total Exports\"),\n value: jobs.length,\n treatment: \"glass\" as const,\n glow: true,\n },\n {\n icon: <Activity size={18} />,\n label: tr(\"export.dashboard.metrics.active\", \"Active\"),\n value: activeJobs.length,\n treatment: \"metric\" as const,\n glow: false,\n },\n {\n icon: <CheckCircle2 size={18} />,\n label: tr(\"export.dashboard.metrics.completed\", \"Completed\"),\n value: completedJobs.length,\n treatment: \"metric\" as const,\n glow: false,\n },\n ];\n\n const handleNavigate = (path: string) => {\n if (!navigate) return;\n navigate(joinPath(basePath, path));\n };\n\n // New-user orientation: 2–4 concrete next actions wired to real navigation.\n const nextSteps: NextStep[] = [\n {\n id: \"create\",\n label: tr(\n \"export.dashboard.nextSteps.create.label\",\n \"Create your first export\",\n ),\n description: tr(\n \"export.dashboard.nextSteps.create.description\",\n \"Pick the data you want and download it as CSV or JSON.\",\n ),\n icon: <Plus size={16} />,\n onClick: () => handleNavigate(\"new\"),\n done: jobs.length > 0,\n },\n {\n id: \"template\",\n label: tr(\n \"export.dashboard.nextSteps.template.label\",\n \"Save a reusable template\",\n ),\n description: tr(\n \"export.dashboard.nextSteps.template.description\",\n \"Store a common export config so repeat exports are one click.\",\n ),\n icon: <FileBox size={16} />,\n onClick: () => handleNavigate(\"templates\"),\n },\n {\n id: \"history\",\n label: tr(\n \"export.dashboard.nextSteps.history.label\",\n \"Track exports in History\",\n ),\n description: tr(\n \"export.dashboard.nextSteps.history.description\",\n \"Monitor progress and grab download links for finished jobs.\",\n ),\n icon: <Clock size={16} />,\n onClick: () => handleNavigate(\"history\"),\n done: completedJobs.length > 0,\n },\n ];\n\n return (\n <PageLayout showHeader={false}>\n {/* Hero header with living-glass aurora backdrop (primary page only) */}\n <header className=\"relative overflow-hidden rounded-2xl\">\n <AuroraBackground intensity=\"subtle\" />\n <div className=\"relative flex items-center gap-3 px-2 py-4 sm:py-5\">\n <div className=\"flex-shrink-0 p-2.5 rounded-xl bg-action-primary-bg/10 text-primary\">\n <Download size={24} />\n </div>\n <div className=\"space-y-1\">\n <h1 className=\"text-2xl sm:text-3xl font-bold tracking-tight text-text-primary\">\n <GradientText>{tr(\"export.dashboard.title\", \"Export\")}</GradientText>\n </h1>\n <p className=\"text-sm sm:text-base text-text-secondary max-w-2xl\">\n {tr(\n \"export.dashboard.subtitle\",\n \"Export your workspace data in multiple formats\",\n )}\n </p>\n </div>\n </div>\n </header>\n\n {/* Page purpose — plain-language story of what Export is for */}\n <PagePurpose icon={<Download size={16} />}>\n {tr(\n \"export.dashboard.purpose\",\n \"Export takes your workspace data — people, projects, files, tags, activity and more — and packages it into downloadable CSV or JSON files. Use it to back up your data, hand it to another tool, run an audit, or take it with you when you leave. Pick what you want, choose a format, and grab the download when it's ready.\",\n )}\n </PagePurpose>\n\n {/* New-user next steps — dismissable, recommends concrete actions */}\n <NextSteps\n storageKey=\"export-dashboard\"\n title={tr(\"export.dashboard.nextSteps.title\", \"Get started\")}\n steps={nextSteps}\n />\n\n {/* Metric strip */}\n {!isLoading && jobs.length > 0 && (\n <div className=\"grid grid-cols-1 sm:grid-cols-3 gap-4\">\n {metrics.map((m) => (\n <GlassCard\n key={m.label}\n treatment={m.treatment}\n glow={m.glow}\n className=\"p-5 border-border-seam\"\n >\n <div className=\"flex items-center gap-2 text-text-secondary mb-2\">\n {m.icon}\n <span className=\"text-xs font-medium\">{m.label}</span>\n </div>\n <p className=\"text-3xl font-bold tabular-nums text-text-primary\">\n {m.value.toLocaleString()}\n </p>\n </GlassCard>\n ))}\n </div>\n )}\n\n {/* Quick Actions */}\n <div\n className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4\"\n data-tour=\"export-dashboard-quick-actions\"\n >\n {[\n {\n icon: <Plus size={20} />,\n label: tr(\"export.dashboard.actions.newExport.label\", \"New Export\"),\n description: tr(\n \"export.dashboard.actions.newExport.description\",\n \"Create a new data export\",\n ),\n path: \"new\",\n color: \"bg-action-primary-bg/10 text-primary\",\n },\n {\n icon: <Clock size={20} />,\n label: tr(\"export.dashboard.actions.history.label\", \"History\"),\n description: tr(\n \"export.dashboard.actions.history.description\",\n \"View past exports\",\n ),\n path: \"history\",\n color: \"bg-status-info-bg-subtle text-status-info-text\",\n },\n {\n icon: <FileBox size={20} />,\n label: tr(\"export.dashboard.actions.templates.label\", \"Templates\"),\n description: tr(\n \"export.dashboard.actions.templates.description\",\n \"Reusable export configs\",\n ),\n path: \"templates\",\n color: \"bg-accent-purple-subtle text-accent-purple\",\n },\n {\n icon: <Activity size={20} />,\n label: tr(\n \"export.dashboard.actions.activeJobs.label\",\n \"Active Jobs\",\n ),\n description: tr(\n \"export.dashboard.actions.activeJobs.description\",\n \"{count} running\",\n { count: activeJobs.length },\n ),\n path: \"history?status=RUNNING\",\n color: \"bg-status-success-bg-subtle text-status-success-text\",\n },\n ].map((action) => (\n <button\n type=\"button\"\n key={action.path + action.label}\n onClick={() => handleNavigate(action.path)}\n className={cn(\n \"group relative overflow-hidden border border-border-seam rounded-xl p-5\",\n \"bg-bg-surface shadow-[var(--shadow-pop)]\",\n \"hover:border-primary/40 transition-colors duration-200\",\n \"text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/40\",\n )}\n >\n <div className={cn(\"p-2.5 rounded-lg w-fit mb-3\", action.color)}>\n {action.icon}\n </div>\n <h3 className=\"font-semibold text-text-primary mb-1\">\n {action.label}\n </h3>\n <p className=\"text-sm text-text-secondary\">\n {action.description}\n </p>\n <ArrowRight\n size={16}\n className=\"absolute top-5 right-5 text-text-secondary opacity-0 group-hover:opacity-100 transition-opacity\"\n />\n </button>\n ))}\n </div>\n\n {/* Active Exports — the single emphasised zone on this page */}\n {activeJobs.length > 0 && (\n <EmphasisPanel\n data-tour=\"export-dashboard-active-section\"\n className=\"p-5 sm:p-6\"\n >\n <div className=\"mb-4\">\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {tr(\"export.dashboard.active.title\", \"Active Exports\")}\n </h2>\n <p className=\"text-sm text-text-secondary\">\n {tr(\n \"export.dashboard.active.description\",\n \"Currently running export jobs\",\n )}\n </p>\n </div>\n <div className=\"space-y-3\">\n {activeJobs.map((job) => (\n <button\n type=\"button\"\n key={job.id}\n onClick={() => handleNavigate(job.id)}\n className={cn(\n \"w-full text-left border border-border-seam rounded-xl p-4 bg-bg-surface/70\",\n \"hover:border-primary/40 transition-colors duration-200\",\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/40\",\n )}\n >\n <div className=\"flex items-center justify-between mb-2\">\n <h4 className=\"font-semibold text-text-primary\">{job.name}</h4>\n <ExportStatusBadge status={job.status} />\n </div>\n <ExportProgressBar progress={job.progress} size=\"sm\" />\n </button>\n ))}\n </div>\n </EmphasisPanel>\n )}\n\n {/* Recent Exports */}\n <PageSection\n data-tour=\"export-dashboard-recent-section\"\n title={tr(\"export.dashboard.recent.title\", \"Recent Exports\")}\n description={tr(\n \"export.dashboard.recent.description\",\n \"Your latest export jobs\",\n )}\n actions={\n recentJobs.length > 0 ? (\n <button\n type=\"button\"\n onClick={() => handleNavigate(\"history\")}\n className=\"text-sm text-primary hover:underline font-medium\"\n >\n {tr(\"export.dashboard.recent.actions.viewAll\", \"View All\")}\n </button>\n ) : undefined\n }\n >\n {isLoading ? (\n <div className=\"space-y-3\">\n {[...Array(3)].map((_, i) => (\n <div\n key={i}\n className=\"border border-border-seam rounded-xl p-4\"\n >\n <div className=\"flex items-center justify-between mb-2\">\n <div className=\"h-4 w-48 bg-bg-sunken rounded animate-vc-shimmer\" />\n <div className=\"h-5 w-20 bg-bg-sunken rounded-full animate-vc-shimmer\" />\n </div>\n <div className=\"h-3 w-32 bg-bg-sunken rounded mt-2 animate-vc-shimmer\" />\n </div>\n ))}\n </div>\n ) : recentJobs.length > 0 ? (\n <div className=\"space-y-3\">\n {recentJobs.map((job, index) => (\n <button\n type=\"button\"\n key={job.id}\n onClick={() => handleNavigate(job.id)}\n className={cn(\n \"w-full text-left border border-border-seam rounded-xl p-4 bg-bg-surface\",\n \"hover:border-primary/40 transition-colors duration-200\",\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/40\",\n \"animate-in fade-in-0\",\n )}\n style={{ animationDelay: `${index * 50}ms` }}\n >\n <div className=\"flex items-start sm:items-center justify-between gap-3\">\n <div className=\"flex-1 min-w-0\">\n <h4 className=\"font-semibold text-text-primary truncate\">\n {job.name}\n </h4>\n <p className=\"text-sm text-text-secondary mt-1 line-clamp-2\">\n {job.entityTypes.join(\", \")} · {job.format}\n {job.totalEntities != null &&\n ` · ${tr(\n \"export.dashboard.recent.entitiesCount\",\n \"{count} entities\",\n { count: job.totalEntities.toLocaleString() },\n )}`}\n </p>\n </div>\n <div className=\"flex items-center gap-2 flex-shrink-0\">\n <ExportStatusBadge status={job.status} />\n <ArrowRight\n size={16}\n className=\"text-text-secondary hidden sm:block\"\n />\n </div>\n </div>\n </button>\n ))}\n </div>\n ) : (\n <IllustratedEmptyState\n illustration=\"empty-files\"\n title={tr(\"export.dashboard.empty.title\", \"No exports yet\")}\n description={tr(\n \"export.dashboard.empty.description\",\n \"Create your first export to start downloading your workspace data.\",\n )}\n action={\n <button\n type=\"button\"\n onClick={() => handleNavigate(\"new\")}\n className=\"inline-flex items-center gap-2 px-4 py-2 bg-action-primary-bg text-action-primary-text rounded-lg hover:bg-action-primary-bg/90 transition-colors font-medium\"\n >\n <Plus size={16} />\n {tr(\n \"export.dashboard.empty.actions.createFirst\",\n \"Create First Export\",\n )}\n </button>\n }\n />\n )}\n </PageSection>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|