@burdenoff/microfe-export 2026.625.1 → 2026.626.1

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.
@@ -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 { GlassCard, EmphasisPanel } 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, EmptyState } 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 },\n {\n icon: <Activity size={18} />,\n label: tr(\"export.dashboard.metrics.active\", \"Active\"),\n value: activeJobs.length,\n treatment: \"metric\" as const,\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 },\n ];\n\n const handleNavigate = (path: string) => {\n if (!navigate) return;\n navigate(joinPath(basePath, path));\n };\n\n return (\n <PageLayout\n title={tr(\"export.dashboard.title\", \"Export\")}\n subtitle={tr(\n \"export.dashboard.subtitle\",\n \"Export your workspace data in multiple formats\",\n )}\n icon={<Download size={24} />}\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 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 animate-pulse\"\n >\n <div className=\"flex items-center justify-between mb-2\">\n <div className=\"h-4 w-48 bg-bg-sunken rounded\" />\n <div className=\"h-5 w-20 bg-bg-sunken rounded-full\" />\n </div>\n <div className=\"h-3 w-32 bg-bg-sunken rounded mt-2\" />\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(\", \")} &middot; {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 <EmptyState\n icon={<Download size={48} />}\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(\", \")} &middot; {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,16 +1,16 @@
1
1
  import { useExport as e } from "../providers/ExportProvider.js";
2
- import { useCancelExportJob as t, useDeleteExportJob as n, useExportJob as r, useExportJobProgress as i, useRetryExportJob as a } from "../hooks/useExportQueries.js";
3
- import { cn as o } from "../utils/cn.js";
4
- import { getArchiveFormatDisplayName as s, getFormatDisplayName as c } from "../constants/enums.js";
5
- import { ExportStatusBadge as l } from "../components/ExportStatusBadge.js";
6
- import { ExportProgressBar as u } from "../components/ExportProgressBar.js";
7
- import { PageLayout as d, PageSection as ee } from "../components/PageLayout.js";
8
- import { nativeImpact as te, nativeNotify as f } from "../../utils/nativeBridge.js";
9
- import { useState as p } from "react";
10
- import { AlertCircle as m, ArrowLeft as h, CheckCircle2 as g, Clock as _, Download as v, FileDown as y, FileText as b, HardDrive as x, Loader2 as S, RotateCcw as C, Trash2 as w, XCircle as ne } from "lucide-react";
11
- import { useNavigate as re, useParams as ie } from "react-router-dom";
12
- import { jsx as T, jsxs as E } from "react/jsx-runtime";
13
- import { CTAOverflowMenu as D, GlassCard as O } from "@burdenoff/fe-libs/ui";
2
+ import { useCancelExportJob as t, useDeleteExportJob as n, useExportJob as r, useExportJobProgress as ee, useRetryExportJob as te } from "../hooks/useExportQueries.js";
3
+ import { cn as i } from "../utils/cn.js";
4
+ import { getArchiveFormatDisplayName as ne, getFormatDisplayName as re } from "../constants/enums.js";
5
+ import { ExportStatusBadge as a } from "../components/ExportStatusBadge.js";
6
+ import { ExportProgressBar as o } from "../components/ExportProgressBar.js";
7
+ import { PageLayout as s, PageSection as c } from "../components/PageLayout.js";
8
+ import { nativeImpact as l, nativeNotify as u } from "../../utils/nativeBridge.js";
9
+ import { useState as d } from "react";
10
+ import { AlertCircle as f, ArrowLeft as p, CheckCircle2 as m, Clock as h, Download as g, FileDown as ie, FileText as ae, HardDrive as _, Loader2 as v, RotateCcw as y, Trash2 as b, XCircle as x } from "lucide-react";
11
+ import { useNavigate as S, useParams as oe } from "react-router-dom";
12
+ import { jsx as C, jsxs as w } from "react/jsx-runtime";
13
+ import { CTAOverflowMenu as T, GlassCard as E, IllustratedEmptyState as D, NextSteps as O } from "@burdenoff/fe-libs/ui";
14
14
  //#region src/export/pages/ExportDetailPage.tsx
15
15
  function k(e) {
16
16
  if (e === 0) return "0 B";
@@ -25,150 +25,168 @@ function k(e) {
25
25
  }
26
26
  var A = (e, t) => (e.endsWith("/") ? e.slice(0, -1) : e) + (t.startsWith("/") ? t : `/${t}`);
27
27
  function j() {
28
- let { jobId: j } = ie(), { basePath: M = "/", navigate: N } = e(), P = re(), F = () => {
28
+ let { jobId: j } = oe(), { basePath: M = "/", navigate: N } = e(), P = S(), F = () => {
29
29
  window.history.length > 1 ? P(-1) : N?.(M);
30
- }, { data: I, isLoading: L } = r(j), { data: R } = i(j), [z, B] = p(null), { cancelJob: V, isPending: H } = t(), { deleteJob: U, isPending: W } = n(), { retryJob: G, isPending: K } = a(), q = R ?? I ?? null, J = q?.status === "CREATED" || q?.status === "QUEUED" || q?.status === "RUNNING", ae = q?.status === "COMPLETED", oe = q?.status === "FAILED", Y = q?.status === "FAILED" || q?.status === "CANCELLED" || q?.status === "EXPIRED", se = async () => {
30
+ }, { data: I, isLoading: L } = r(j), { data: R } = ee(j), [z, B] = d(null), { cancelJob: se, isPending: V } = t(), { deleteJob: H, isPending: U } = n(), { retryJob: W, isPending: G } = te(), K = R ?? I ?? null, q = K?.status === "CREATED" || K?.status === "QUEUED" || K?.status === "RUNNING", J = K?.status === "COMPLETED", ce = K?.status === "FAILED", Y = K?.status === "FAILED" || K?.status === "CANCELLED" || K?.status === "EXPIRED", le = async () => {
31
31
  j && B("cancel");
32
- }, ce = async () => {
33
- j && (te("medium"), B("delete"));
34
- }, le = async () => {
32
+ }, ue = async () => {
33
+ j && (l("medium"), B("delete"));
34
+ }, de = async () => {
35
35
  if (!(!j || !z)) {
36
36
  try {
37
- z === "cancel" ? await V(j) : (await U(j), N?.(M)), f("success");
37
+ z === "cancel" ? await se(j) : (await H(j), N?.(M)), u("success");
38
38
  } catch {
39
- f("error");
39
+ u("error");
40
40
  }
41
41
  B(null);
42
42
  }
43
43
  }, X = async () => {
44
44
  if (!j) return;
45
- let e = await G(j);
45
+ let e = await W(j);
46
46
  e?.id && N?.(A(M, e.id));
47
- }, Z = q?.parts.find((e) => e.downloadUrl);
48
- if (L) return /* @__PURE__ */ E("div", {
47
+ }, Z = K?.parts.find((e) => e.downloadUrl);
48
+ if (L) return /* @__PURE__ */ w("div", {
49
49
  className: "flex flex-col items-center justify-center py-20",
50
- children: [/* @__PURE__ */ T(S, {
50
+ children: [/* @__PURE__ */ C(v, {
51
51
  size: 48,
52
52
  className: "animate-spin text-primary"
53
- }), /* @__PURE__ */ T("span", {
53
+ }), /* @__PURE__ */ C("span", {
54
54
  className: "mt-6 text-sm font-medium text-text-secondary",
55
55
  children: "Loading export details…"
56
56
  })]
57
57
  });
58
- if (!q) return /* @__PURE__ */ E(d, {
58
+ if (!K) return /* @__PURE__ */ w(s, {
59
59
  showHeader: !1,
60
- children: [/* @__PURE__ */ E("div", {
60
+ children: [/* @__PURE__ */ w("div", {
61
61
  className: "flex items-center gap-3 mb-6",
62
- children: [/* @__PURE__ */ T("button", {
62
+ children: [/* @__PURE__ */ C("button", {
63
63
  type: "button",
64
64
  onClick: F,
65
+ "aria-label": "Go back",
65
66
  className: "p-2.5 hover:bg-accent rounded-lg transition-all duration-200",
66
- children: /* @__PURE__ */ T(h, { size: 20 })
67
- }), /* @__PURE__ */ T("h1", {
67
+ children: /* @__PURE__ */ C(p, { size: 20 })
68
+ }), /* @__PURE__ */ C("h1", {
68
69
  className: "text-xl font-bold",
69
70
  children: "Export Not Found"
70
71
  })]
71
- }), /* @__PURE__ */ E("div", {
72
- className: "border-2 border-border-default rounded-xl bg-status-error-bg-subtle p-12 text-center",
73
- children: [
74
- /* @__PURE__ */ T(m, {
75
- size: 48,
76
- className: "text-status-error-text mx-auto mb-4"
77
- }),
78
- /* @__PURE__ */ T("h3", {
79
- className: "text-lg font-bold text-status-error-text mb-2",
80
- children: "Export Not Found"
81
- }),
82
- /* @__PURE__ */ T("p", {
83
- className: "text-status-error-text mb-6",
84
- children: "The export job you are looking for does not exist or has been deleted."
85
- }),
86
- /* @__PURE__ */ E("button", {
87
- type: "button",
88
- onClick: F,
89
- className: "inline-flex items-center gap-2 px-6 py-3 bg-action-primary-bg text-action-primary-text rounded-lg hover:bg-action-primary-bg/90 transition-colors font-medium",
90
- children: [/* @__PURE__ */ T(h, { size: 18 }), "Back to Dashboard"]
91
- })
92
- ]
72
+ }), /* @__PURE__ */ C(D, {
73
+ illustration: "empty-data",
74
+ title: "Export not found",
75
+ description: "The export job you are looking for does not exist or has been deleted.",
76
+ action: /* @__PURE__ */ w("button", {
77
+ type: "button",
78
+ onClick: F,
79
+ className: "inline-flex items-center gap-2 px-6 py-3 bg-action-primary-bg text-action-primary-text rounded-lg hover:bg-action-primary-bg/90 transition-colors font-medium",
80
+ children: [/* @__PURE__ */ C(p, { size: 18 }), "Back to Dashboard"]
81
+ })
93
82
  })]
94
83
  });
95
84
  let Q = Z ? {
96
85
  label: "Download",
97
- icon: /* @__PURE__ */ T(v, { size: 16 }),
86
+ icon: /* @__PURE__ */ C(g, { size: 16 }),
98
87
  onSelect: () => {
99
88
  Z.downloadUrl && window.location.assign(Z.downloadUrl);
100
89
  }
101
90
  } : Y ? {
102
91
  label: "Retry Export",
103
- icon: /* @__PURE__ */ T(C, { size: 16 }),
104
- disabled: K,
92
+ icon: /* @__PURE__ */ C(y, { size: 16 }),
93
+ disabled: G,
105
94
  onSelect: () => {
106
95
  X();
107
96
  }
108
97
  } : void 0, $ = [];
109
- return Y && Z && $.push({
98
+ Y && Z && $.push({
110
99
  label: "Retry Export",
111
- icon: /* @__PURE__ */ T(C, { size: 16 }),
112
- disabled: K,
100
+ icon: /* @__PURE__ */ C(y, { size: 16 }),
101
+ disabled: G,
113
102
  onSelect: () => {
114
103
  X();
115
104
  }
116
- }), J && $.push({
105
+ }), q && $.push({
117
106
  label: "Cancel Export",
118
- icon: /* @__PURE__ */ T(ne, { size: 16 }),
119
- disabled: H,
107
+ icon: /* @__PURE__ */ C(x, { size: 16 }),
108
+ disabled: V,
120
109
  onSelect: () => {
121
- se();
110
+ le();
122
111
  }
123
- }), J || $.push({
112
+ }), q || $.push({
124
113
  label: "Delete Export",
125
- icon: /* @__PURE__ */ T(w, { size: 16 }),
114
+ icon: /* @__PURE__ */ C(b, { size: 16 }),
126
115
  intent: "destructive",
127
- disabled: W,
116
+ disabled: U,
128
117
  onSelect: () => {
129
- ce();
118
+ ue();
130
119
  }
131
- }), /* @__PURE__ */ E(d, {
120
+ });
121
+ let fe = [
122
+ {
123
+ id: "download",
124
+ label: "Download your export",
125
+ description: "Grab the generated files below before their download links expire.",
126
+ icon: /* @__PURE__ */ C(g, { size: 16 }),
127
+ onClick: () => {
128
+ Z?.downloadUrl && window.location.assign(Z.downloadUrl);
129
+ },
130
+ done: J
131
+ },
132
+ ...Y ? [{
133
+ id: "retry",
134
+ label: "Retry this export",
135
+ description: "This export didn't finish — start a fresh run with the same settings.",
136
+ icon: /* @__PURE__ */ C(y, { size: 16 }),
137
+ onClick: () => {
138
+ X();
139
+ }
140
+ }] : [],
141
+ {
142
+ id: "history",
143
+ label: "Back to History",
144
+ description: "See all your exports and track other jobs in progress.",
145
+ icon: /* @__PURE__ */ C(h, { size: 16 }),
146
+ onClick: () => N?.(M)
147
+ }
148
+ ];
149
+ return /* @__PURE__ */ w(s, {
132
150
  showHeader: !1,
133
151
  children: [
134
- /* @__PURE__ */ T("div", {
152
+ /* @__PURE__ */ C("div", {
135
153
  className: "relative overflow-hidden rounded-xl bg-accent-wash border border-border-seam p-6 shadow-[var(--shadow-pop)]",
136
- children: /* @__PURE__ */ E("div", {
154
+ children: /* @__PURE__ */ w("div", {
137
155
  className: "relative z-10 flex flex-col sm:flex-row sm:items-center gap-4",
138
156
  children: [
139
- /* @__PURE__ */ T("button", {
157
+ /* @__PURE__ */ C("button", {
140
158
  type: "button",
141
159
  onClick: F,
142
160
  "aria-label": "Go back",
143
161
  className: "p-2.5 hover:bg-accent rounded-lg transition-colors duration-200 self-start focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/40",
144
- children: /* @__PURE__ */ T(h, { size: 20 })
162
+ children: /* @__PURE__ */ C(p, { size: 20 })
145
163
  }),
146
- /* @__PURE__ */ E("div", {
164
+ /* @__PURE__ */ w("div", {
147
165
  className: "flex items-center gap-3 flex-1 min-w-0",
148
166
  children: [
149
- /* @__PURE__ */ T("div", {
167
+ /* @__PURE__ */ C("div", {
150
168
  className: "p-2.5 rounded-lg bg-action-primary-bg/10",
151
- children: /* @__PURE__ */ T(v, {
169
+ children: /* @__PURE__ */ C(g, {
152
170
  size: 24,
153
171
  className: "text-primary"
154
172
  })
155
173
  }),
156
- /* @__PURE__ */ E("div", {
174
+ /* @__PURE__ */ w("div", {
157
175
  className: "flex-1 min-w-0",
158
- children: [/* @__PURE__ */ T("h1", {
176
+ children: [/* @__PURE__ */ C("h1", {
159
177
  className: "text-xl sm:text-2xl font-bold truncate",
160
- children: q.name
161
- }), /* @__PURE__ */ T("p", {
178
+ children: K.name
179
+ }), /* @__PURE__ */ C("p", {
162
180
  className: "text-sm text-text-secondary mt-1",
163
- children: q.entityTypes.join(", ")
181
+ children: K.entityTypes.join(", ")
164
182
  })]
165
183
  }),
166
- /* @__PURE__ */ T(l, { status: q.status })
184
+ /* @__PURE__ */ C(a, { status: K.status })
167
185
  ]
168
186
  }),
169
- (Q || $.length > 0) && /* @__PURE__ */ T("div", {
187
+ (Q || $.length > 0) && /* @__PURE__ */ C("div", {
170
188
  className: "flex-shrink-0",
171
- children: /* @__PURE__ */ T(D, {
189
+ children: /* @__PURE__ */ C(T, {
172
190
  primary: Q,
173
191
  actions: $
174
192
  })
@@ -176,91 +194,96 @@ function j() {
176
194
  ]
177
195
  })
178
196
  }),
179
- (q.status === "RUNNING" || q.status === "QUEUED") && /* @__PURE__ */ E("div", {
197
+ (K.status === "RUNNING" || K.status === "QUEUED") && /* @__PURE__ */ w("div", {
180
198
  className: "border border-border-seam rounded-xl bg-status-info-bg-subtle p-6",
181
- children: [/* @__PURE__ */ T(u, {
182
- progress: q.progress,
199
+ children: [/* @__PURE__ */ C(o, {
200
+ progress: K.progress,
183
201
  size: "lg"
184
- }), q.processedEntities != null && q.totalEntities != null && /* @__PURE__ */ E("p", {
202
+ }), K.processedEntities != null && K.totalEntities != null && /* @__PURE__ */ w("p", {
185
203
  className: "text-sm text-text-secondary mt-2",
186
204
  children: [
187
- q.processedEntities.toLocaleString(),
205
+ K.processedEntities.toLocaleString(),
188
206
  " /",
189
207
  " ",
190
- q.totalEntities.toLocaleString(),
208
+ K.totalEntities.toLocaleString(),
191
209
  " entities processed"
192
210
  ]
193
211
  })]
194
212
  }),
195
- oe && q.errorMessage && /* @__PURE__ */ E("div", {
213
+ ce && K.errorMessage && /* @__PURE__ */ w("div", {
196
214
  className: "border-2 border-border-default rounded-xl bg-status-error-bg-subtle p-6 flex items-start gap-4",
197
- children: [/* @__PURE__ */ T(m, {
215
+ children: [/* @__PURE__ */ C(f, {
198
216
  size: 24,
199
217
  className: "text-status-error-text flex-shrink-0 mt-0.5"
200
- }), /* @__PURE__ */ E("div", { children: [/* @__PURE__ */ T("h3", {
218
+ }), /* @__PURE__ */ w("div", { children: [/* @__PURE__ */ C("h3", {
201
219
  className: "font-semibold text-status-error-text mb-1",
202
220
  children: "Export Failed"
203
- }), /* @__PURE__ */ T("p", {
221
+ }), /* @__PURE__ */ C("p", {
204
222
  className: "text-sm text-status-error-text",
205
- children: q.errorMessage
223
+ children: K.errorMessage
206
224
  })] })]
207
225
  }),
208
- /* @__PURE__ */ T("div", {
226
+ /* @__PURE__ */ C("div", {
209
227
  className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4",
210
228
  children: [
211
229
  {
212
- icon: /* @__PURE__ */ T(b, { size: 18 }),
230
+ icon: /* @__PURE__ */ C(ae, { size: 18 }),
213
231
  label: "Format",
214
- value: c(q.format)
232
+ value: re(K.format)
215
233
  },
216
234
  {
217
- icon: /* @__PURE__ */ T(x, { size: 18 }),
235
+ icon: /* @__PURE__ */ C(_, { size: 18 }),
218
236
  label: "Archive",
219
- value: s(q.archiveFormat)
237
+ value: ne(K.archiveFormat)
220
238
  },
221
239
  {
222
- icon: /* @__PURE__ */ T(v, { size: 18 }),
240
+ icon: /* @__PURE__ */ C(g, { size: 18 }),
223
241
  label: "Total Size",
224
- value: q.totalSizeBytes == null ? "-" : k(q.totalSizeBytes)
242
+ value: K.totalSizeBytes == null ? "-" : k(K.totalSizeBytes)
225
243
  },
226
244
  {
227
- icon: /* @__PURE__ */ T(_, { size: 18 }),
245
+ icon: /* @__PURE__ */ C(h, { size: 18 }),
228
246
  label: "Created",
229
- value: new Date(q.createdAt).toLocaleDateString()
247
+ value: new Date(K.createdAt).toLocaleDateString()
230
248
  }
231
- ].map((e) => /* @__PURE__ */ E(O, {
249
+ ].map((e) => /* @__PURE__ */ w(E, {
232
250
  treatment: "metric",
233
251
  className: "p-4 border-border-seam",
234
- children: [/* @__PURE__ */ E("div", {
252
+ children: [/* @__PURE__ */ w("div", {
235
253
  className: "flex items-center gap-2 text-text-secondary mb-1",
236
- children: [e.icon, /* @__PURE__ */ T("span", {
254
+ children: [e.icon, /* @__PURE__ */ C("span", {
237
255
  className: "text-xs font-medium",
238
256
  children: e.label
239
257
  })]
240
- }), /* @__PURE__ */ T("p", {
258
+ }), /* @__PURE__ */ C("p", {
241
259
  className: "font-bold text-lg tabular-nums",
242
260
  children: e.value
243
261
  })]
244
262
  }, e.label))
245
263
  }),
246
- q.parts.length > 0 && /* @__PURE__ */ T(ee, {
264
+ /* @__PURE__ */ C(O, {
265
+ storageKey: `export-detail-${K.id}`,
266
+ title: "What's next",
267
+ steps: fe
268
+ }),
269
+ K.parts.length > 0 && /* @__PURE__ */ C(c, {
247
270
  title: "Export Parts",
248
- description: `${q.parts.length} file(s) generated`,
249
- children: /* @__PURE__ */ T("div", {
271
+ description: `${K.parts.length} file(s) generated`,
272
+ children: /* @__PURE__ */ C("div", {
250
273
  className: "space-y-2",
251
- children: q.parts.map((e) => /* @__PURE__ */ E("div", {
252
- className: o("border border-border-seam rounded-xl p-4 flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3 bg-bg-surface", "hover:border-primary/40 transition-colors duration-200"),
253
- children: [/* @__PURE__ */ E("div", {
274
+ children: K.parts.map((e) => /* @__PURE__ */ w("div", {
275
+ className: i("border border-border-seam rounded-xl p-4 flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3 bg-bg-surface", "hover:border-primary/40 transition-colors duration-200"),
276
+ children: [/* @__PURE__ */ w("div", {
254
277
  className: "flex items-center gap-3 min-w-0",
255
- children: [/* @__PURE__ */ T(y, {
278
+ children: [/* @__PURE__ */ C(ie, {
256
279
  size: 20,
257
280
  className: "text-primary flex-shrink-0"
258
- }), /* @__PURE__ */ E("div", {
281
+ }), /* @__PURE__ */ w("div", {
259
282
  className: "min-w-0",
260
- children: [/* @__PURE__ */ T("p", {
283
+ children: [/* @__PURE__ */ C("p", {
261
284
  className: "font-medium truncate",
262
285
  children: e.fileName
263
- }), /* @__PURE__ */ E("p", {
286
+ }), /* @__PURE__ */ w("p", {
264
287
  className: "text-sm text-text-secondary",
265
288
  children: [
266
289
  e.entityTypes.join(", "),
@@ -271,67 +294,67 @@ function j() {
271
294
  ]
272
295
  })]
273
296
  })]
274
- }), /* @__PURE__ */ T("div", {
297
+ }), /* @__PURE__ */ C("div", {
275
298
  className: "flex items-center gap-2 flex-shrink-0",
276
- children: e.downloadUrl ? /* @__PURE__ */ E("a", {
299
+ children: e.downloadUrl ? /* @__PURE__ */ w("a", {
277
300
  href: e.downloadUrl,
278
301
  className: "inline-flex items-center gap-2 px-3 py-1.5 bg-action-primary-bg text-action-primary-text rounded-lg hover:bg-action-primary-bg/90 transition-colors text-sm font-medium",
279
- children: [/* @__PURE__ */ T(v, { size: 14 }), "Download"]
280
- }) : /* @__PURE__ */ E("span", {
302
+ children: [/* @__PURE__ */ C(g, { size: 14 }), "Download"]
303
+ }) : /* @__PURE__ */ w("span", {
281
304
  className: "inline-flex items-center gap-1.5 text-sm text-text-secondary",
282
- children: [/* @__PURE__ */ T(_, { size: 14 }), "Pending"]
305
+ children: [/* @__PURE__ */ C(h, { size: 14 }), "Pending"]
283
306
  })
284
307
  })]
285
308
  }, e.id))
286
309
  })
287
310
  }),
288
- ae && q.parts.length === 0 && /* @__PURE__ */ E("div", {
311
+ J && K.parts.length === 0 && /* @__PURE__ */ w("div", {
289
312
  className: "border-2 border-border-default rounded-xl bg-status-success-bg-subtle p-6 text-center",
290
313
  children: [
291
- /* @__PURE__ */ T(g, {
314
+ /* @__PURE__ */ C(m, {
292
315
  size: 48,
293
316
  className: "text-status-success-text mx-auto mb-3"
294
317
  }),
295
- /* @__PURE__ */ T("h3", {
318
+ /* @__PURE__ */ C("h3", {
296
319
  className: "text-lg font-bold text-status-success-text mb-1",
297
320
  children: "Export Complete"
298
321
  }),
299
- /* @__PURE__ */ T("p", {
322
+ /* @__PURE__ */ C("p", {
300
323
  className: "text-sm text-status-success-text",
301
324
  children: "Your export has completed but no download parts are available yet."
302
325
  })
303
326
  ]
304
327
  }),
305
- z && /* @__PURE__ */ T("div", {
328
+ z && /* @__PURE__ */ C("div", {
306
329
  role: "dialog",
307
330
  "aria-modal": "true",
308
331
  "aria-labelledby": "export-confirm-title",
309
332
  className: "fixed inset-0 z-50 flex items-center justify-center bg-bg-surface/80 backdrop-blur-sm p-4",
310
- children: /* @__PURE__ */ E("div", {
333
+ children: /* @__PURE__ */ w("div", {
311
334
  className: "w-full max-w-md rounded-xl border-2 border-border-subtle bg-bg-surface p-6 shadow-xl",
312
335
  children: [
313
- /* @__PURE__ */ T("h2", {
336
+ /* @__PURE__ */ C("h2", {
314
337
  id: "export-confirm-title",
315
338
  className: "text-lg font-bold",
316
339
  children: z === "cancel" ? "Cancel export?" : "Delete export?"
317
340
  }),
318
- /* @__PURE__ */ T("p", {
341
+ /* @__PURE__ */ C("p", {
319
342
  className: "mt-2 text-sm text-text-secondary",
320
343
  children: z === "cancel" ? "This stops the running export job. You can retry it later if needed." : "This removes the export job from history. This action cannot be undone."
321
344
  }),
322
- /* @__PURE__ */ E("div", {
345
+ /* @__PURE__ */ w("div", {
323
346
  className: "mt-6 flex flex-col-reverse sm:flex-row sm:justify-end gap-3",
324
- children: [/* @__PURE__ */ T("button", {
347
+ children: [/* @__PURE__ */ C("button", {
325
348
  type: "button",
326
349
  onClick: () => B(null),
327
350
  className: "px-4 py-2 rounded-lg border-2 border-border-subtle hover:bg-accent transition-colors font-medium",
328
351
  children: "Keep Export"
329
- }), /* @__PURE__ */ E("button", {
352
+ }), /* @__PURE__ */ w("button", {
330
353
  type: "button",
331
- onClick: le,
332
- disabled: H || W,
354
+ onClick: de,
355
+ disabled: V || U,
333
356
  className: "inline-flex items-center justify-center gap-2 px-4 py-2 rounded-lg bg-status-error-bg text-status-error-text hover:bg-status-error-bg/90 transition-colors font-medium disabled:opacity-50",
334
- children: [H || W ? /* @__PURE__ */ T(S, {
357
+ children: [V || U ? /* @__PURE__ */ C(v, {
335
358
  size: 16,
336
359
  className: "animate-spin"
337
360
  }) : null, z === "cancel" ? "Cancel Export" : "Delete Export"]