@burdenoff/microfe-export 2026.625.1 → 2026.625.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/components/ExportStatusBadge.js +1 -1
- package/dist/export/components/ExportStatusBadge.js.map +1 -1
- package/dist/export/components/PageLayout.js +7 -18
- package/dist/export/components/PageLayout.js.map +1 -1
- package/dist/export/pages/ExportDashboardPage.js +114 -93
- package/dist/export/pages/ExportDashboardPage.js.map +1 -1
- package/dist/export/pages/ExportHistoryPage.js +26 -25
- package/dist/export/pages/ExportHistoryPage.js.map +1 -1
- package/dist/export/pages/ExportTemplatesPage.js +137 -137
- package/dist/export/pages/ExportTemplatesPage.js.map +1 -1
- package/package.json +2 -2
|
@@ -7,7 +7,7 @@ import { useI18n as a } from "@burdenoff/fe-libs/shared/providers/shell/I18nProv
|
|
|
7
7
|
var o = {
|
|
8
8
|
CREATED: "bg-status-info-bg-subtle text-status-info-text",
|
|
9
9
|
QUEUED: "bg-status-warning-bg-subtle text-status-warning-text",
|
|
10
|
-
RUNNING: "bg-status-info-bg-subtle text-status-info-text animate-pulse",
|
|
10
|
+
RUNNING: "bg-status-info-bg-subtle text-status-info-text motion-safe:animate-vc-glow-pulse",
|
|
11
11
|
COMPLETED: "bg-status-success-bg-subtle text-status-success-text",
|
|
12
12
|
FAILED: "bg-status-error-bg-subtle text-status-error-text",
|
|
13
13
|
CANCELLED: "bg-bg-sunken text-text-secondary",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExportStatusBadge.js","names":[],"sources":["../../../src/export/components/ExportStatusBadge.tsx"],"sourcesContent":["import { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport { cn } from \"../utils/cn\";\nimport { getStatusDisplayName } from \"../constants/enums\";\nimport type { ExportJobStatus } from \"../types\";\nimport { tWithFallback } from \"../utils/i18n\";\n\ninterface ExportStatusBadgeProps {\n status: ExportJobStatus;\n className?: string;\n}\n\nconst statusStyles: Record<ExportJobStatus, string> = {\n CREATED: \"bg-status-info-bg-subtle text-status-info-text\",\n QUEUED: \"bg-status-warning-bg-subtle text-status-warning-text\",\n RUNNING
|
|
1
|
+
{"version":3,"file":"ExportStatusBadge.js","names":[],"sources":["../../../src/export/components/ExportStatusBadge.tsx"],"sourcesContent":["import { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport { cn } from \"../utils/cn\";\nimport { getStatusDisplayName } from \"../constants/enums\";\nimport type { ExportJobStatus } from \"../types\";\nimport { tWithFallback } from \"../utils/i18n\";\n\ninterface ExportStatusBadgeProps {\n status: ExportJobStatus;\n className?: string;\n}\n\nconst statusStyles: Record<ExportJobStatus, string> = {\n CREATED: \"bg-status-info-bg-subtle text-status-info-text\",\n QUEUED: \"bg-status-warning-bg-subtle text-status-warning-text\",\n RUNNING:\n \"bg-status-info-bg-subtle text-status-info-text motion-safe:animate-vc-glow-pulse\",\n COMPLETED: \"bg-status-success-bg-subtle text-status-success-text\",\n FAILED: \"bg-status-error-bg-subtle text-status-error-text\",\n CANCELLED: \"bg-bg-sunken text-text-secondary\",\n EXPIRED: \"bg-accent-orange-subtle text-accent-orange\",\n DELETED: \"bg-bg-sunken text-text-tertiary\",\n};\n\n/**\n * ExportStatusBadge - Renders a colored badge for export job status\n */\nexport function ExportStatusBadge({\n status,\n className,\n}: ExportStatusBadgeProps) {\n const { t } = useI18n();\n const tr = (key: string, fallback: string) => tWithFallback(t, key, fallback);\n\n const statusLabel =\n {\n CREATED: tr(\"export.shared.status.created\", \"Created\"),\n QUEUED: tr(\"export.shared.status.queued\", \"Queued\"),\n RUNNING: tr(\"export.shared.status.running\", \"Running\"),\n COMPLETED: tr(\"export.shared.status.completed\", \"Completed\"),\n FAILED: tr(\"export.shared.status.failed\", \"Failed\"),\n CANCELLED: tr(\"export.shared.status.cancelled\", \"Cancelled\"),\n EXPIRED: tr(\"export.shared.status.expired\", \"Expired\"),\n DELETED: tr(\"export.shared.status.deleted\", \"Deleted\"),\n }[status] ?? getStatusDisplayName(status);\n\n return (\n <span\n className={cn(\n \"inline-flex items-center gap-1.5 px-2.5 py-0.5 rounded-full text-xs font-medium\",\n statusStyles[status],\n className,\n )}\n >\n {status === \"RUNNING\" && (\n <span className=\"relative flex size-2\">\n <span className=\"animate-ping absolute inline-flex h-full w-full rounded-full bg-accent-blue opacity-75\" />\n <span className=\"relative inline-flex rounded-full size-2 bg-accent-blue\" />\n </span>\n )}\n {statusLabel}\n </span>\n );\n}\n"],"mappings":";;;;;;AAWA,IAAM,IAAgD;CACpD,SAAS;CACT,QAAQ;CACR,SACE;CACF,WAAW;CACX,QAAQ;CACR,WAAW;CACX,SAAS;CACT,SAAS;CACV;AAKD,SAAgB,EAAkB,EAChC,WACA,gBACyB;CACzB,IAAM,EAAE,SAAM,GAAS,EACjB,KAAM,GAAa,MAAqB,EAAc,GAAG,GAAK,EAAS,EAEvE,IACJ;EACE,SAAS,EAAG,gCAAgC,UAAU;EACtD,QAAQ,EAAG,+BAA+B,SAAS;EACnD,SAAS,EAAG,gCAAgC,UAAU;EACtD,WAAW,EAAG,kCAAkC,YAAY;EAC5D,QAAQ,EAAG,+BAA+B,SAAS;EACnD,WAAW,EAAG,kCAAkC,YAAY;EAC5D,SAAS,EAAG,gCAAgC,UAAU;EACtD,SAAS,EAAG,gCAAgC,UAAU;EACvD,CAAC,MAAW,EAAqB,EAAO;AAE3C,QACE,kBAAC,QAAD;EACE,WAAW,EACT,mFACA,EAAa,IACb,EACD;YALH,CAOG,MAAW,aACV,kBAAC,QAAD;GAAM,WAAU;aAAhB,CACE,kBAAC,QAAD,EAAM,WAAU,0FAA2F,CAAA,EAC3G,kBAAC,QAAD,EAAM,WAAU,2DAA4D,CAAA,CACvE;MAER,EACI"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { cn as e } from "../utils/cn.js";
|
|
2
2
|
import { jsx as t, jsxs as n } from "react/jsx-runtime";
|
|
3
|
-
import
|
|
3
|
+
import "@burdenoff/fe-libs/ui";
|
|
4
4
|
//#region src/export/components/PageLayout.tsx
|
|
5
|
-
var
|
|
5
|
+
var r = {
|
|
6
6
|
sm: "max-w-screen-sm",
|
|
7
7
|
md: "max-w-screen-md",
|
|
8
8
|
lg: "max-w-screen-lg",
|
|
@@ -11,11 +11,11 @@ var i = {
|
|
|
11
11
|
"3xl": "max-w-[1600px]",
|
|
12
12
|
full: "max-w-full"
|
|
13
13
|
};
|
|
14
|
-
function
|
|
14
|
+
function i({ children: i, title: a, subtitle: o, icon: s, headerActions: c, headerContent: l, maxWidth: u = "xl", showHeader: d = !0, className: f, contentClassName: p }) {
|
|
15
15
|
return /* @__PURE__ */ t("div", {
|
|
16
16
|
className: e("min-h-full w-full", "px-4 sm:px-6 lg:px-8 xl:px-12", "py-6 sm:py-8 lg:py-10", "animate-in fade-in-0 slide-in-from-bottom-4 duration-500", f),
|
|
17
17
|
children: /* @__PURE__ */ n("div", {
|
|
18
|
-
className: e("mx-auto w-full",
|
|
18
|
+
className: e("mx-auto w-full", r[u], p),
|
|
19
19
|
children: [d && (a || c) && /* @__PURE__ */ n("header", {
|
|
20
20
|
className: "mb-6 sm:mb-8",
|
|
21
21
|
children: [/* @__PURE__ */ n("div", {
|
|
@@ -45,12 +45,12 @@ function a({ children: r, title: a, subtitle: o, icon: s, headerActions: c, head
|
|
|
45
45
|
})]
|
|
46
46
|
}), /* @__PURE__ */ t("div", {
|
|
47
47
|
className: "space-y-6",
|
|
48
|
-
children:
|
|
48
|
+
children: i
|
|
49
49
|
})]
|
|
50
50
|
})
|
|
51
51
|
});
|
|
52
52
|
}
|
|
53
|
-
function
|
|
53
|
+
function a({ children: r, title: i, description: a, actions: o, className: s, ...c }) {
|
|
54
54
|
return /* @__PURE__ */ n("section", {
|
|
55
55
|
className: e("space-y-4", s),
|
|
56
56
|
...c,
|
|
@@ -69,18 +69,7 @@ function o({ children: r, title: i, description: a, actions: o, className: s, ..
|
|
|
69
69
|
}), r]
|
|
70
70
|
});
|
|
71
71
|
}
|
|
72
|
-
function s({ icon: e, title: n, description: i, action: a, className: o }) {
|
|
73
|
-
return /* @__PURE__ */ t("div", {
|
|
74
|
-
className: o,
|
|
75
|
-
children: /* @__PURE__ */ t(r, {
|
|
76
|
-
icon: e,
|
|
77
|
-
title: n,
|
|
78
|
-
description: i,
|
|
79
|
-
action: a
|
|
80
|
-
})
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
72
|
//#endregion
|
|
84
|
-
export {
|
|
73
|
+
export { i as PageLayout, a as PageSection };
|
|
85
74
|
|
|
86
75
|
//# sourceMappingURL=PageLayout.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PageLayout.js","names":[],"sources":["../../../src/export/components/PageLayout.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { EmptyState as CanonicalEmptyState } from \"@burdenoff/fe-libs/ui\";\nimport { cn } from \"../utils/cn\";\n\ninterface PageLayoutProps {\n children: ReactNode;\n /** Page title */\n title?: string;\n /** Page subtitle/description */\n subtitle?: string;\n /** Icon component to display next to title */\n icon?: ReactNode;\n /** Actions to display in header (buttons, etc.) */\n headerActions?: ReactNode;\n /** Additional header content below title */\n headerContent?: ReactNode;\n /** Maximum width of content: 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full' */\n maxWidth?: \"sm\" | \"md\" | \"lg\" | \"xl\" | \"2xl\" | \"3xl\" | \"full\";\n /** Whether to show the header section */\n showHeader?: boolean;\n /** Additional CSS classes for the container */\n className?: string;\n /** Additional CSS classes for the content area */\n contentClassName?: string;\n}\n\nconst maxWidthClasses = {\n sm: \"max-w-screen-sm\", // 640px\n md: \"max-w-screen-md\", // 768px\n lg: \"max-w-screen-lg\", // 1024px\n xl: \"max-w-screen-xl\", // 1280px\n \"2xl\": \"max-w-screen-2xl\", // 1536px\n \"3xl\": \"max-w-[1600px]\",\n full: \"max-w-full\",\n};\n\n/**\n * PageLayout - A consistent page wrapper with responsive design\n *\n * Features:\n * - Proper max-width constraints\n * - Responsive padding\n * - Animated entrance\n * - Consistent header styling\n */\nexport function PageLayout({\n children,\n title,\n subtitle,\n icon,\n headerActions,\n headerContent,\n maxWidth = \"xl\",\n showHeader = true,\n className,\n contentClassName,\n}: PageLayoutProps) {\n return (\n <div\n className={cn(\n // Base styles - full width container with padding\n \"min-h-full w-full\",\n // Responsive horizontal padding\n \"px-4 sm:px-6 lg:px-8 xl:px-12\",\n // Responsive vertical padding\n \"py-6 sm:py-8 lg:py-10\",\n // Entrance animation\n \"animate-in fade-in-0 slide-in-from-bottom-4 duration-500\",\n className,\n )}\n >\n {/* Max-width constrained content container */}\n <div\n className={cn(\n \"mx-auto w-full\",\n maxWidthClasses[maxWidth],\n contentClassName,\n )}\n >\n {/* Page Header */}\n {showHeader && (title || headerActions) && (\n <header className=\"mb-6 sm:mb-8\">\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between\">\n {/* Title Section */}\n <div className=\"space-y-1\">\n {(title || icon) && (\n <div className=\"flex items-center gap-3\">\n {icon && (\n <div className=\"flex-shrink-0 p-2.5 rounded-xl bg-action-primary-bg/10 text-primary\">\n {icon}\n </div>\n )}\n {title && (\n <h1 className=\"text-2xl sm:text-3xl font-bold tracking-tight text-text-primary\">\n {title}\n </h1>\n )}\n </div>\n )}\n {subtitle && (\n <p className=\"text-sm sm:text-base text-text-secondary max-w-2xl\">\n {subtitle}\n </p>\n )}\n </div>\n\n {/* Header Actions */}\n {headerActions && (\n <div className=\"flex items-center gap-2 flex-shrink-0\">\n {headerActions}\n </div>\n )}\n </div>\n\n {/* Additional Header Content */}\n {headerContent && <div className=\"mt-4\">{headerContent}</div>}\n </header>\n )}\n\n {/* Page content — must not use a <main> landmark here because the\n host shell (AppShellLayout) already renders one; nesting <main>\n elements is invalid HTML and an a11y violation. */}\n <div className=\"space-y-6\">{children}</div>\n </div>\n </div>\n );\n}\n\n/**\n * PageSection - A section within a page with consistent spacing\n */\nexport function PageSection({\n children,\n title,\n description,\n actions,\n className,\n ...rest\n}: {\n children: ReactNode;\n title?: string;\n description?: string;\n actions?: ReactNode;\n className?: string;\n} & React.HTMLAttributes<HTMLElement>) {\n return (\n <section className={cn(\"space-y-4\", className)} {...rest}>\n {(title || actions) && (\n <div className=\"flex items-center justify-between\">\n <div>\n {title && (\n <h2 className=\"text-lg font-semibold text-text-primary\">{title}</h2>\n )}\n {description && (\n <p className=\"text-sm text-text-secondary\">{description}</p>\n )}\n </div>\n {actions && <div className=\"flex items-center gap-2\">{actions}</div>}\n </div>\n )}\n {children}\n </section>\n );\n}\n\n/**\n * Local wrapper around the canonical `EmptyState` from `@burdenoff/fe-libs/ui`.\n * Keeps the existing microfe-export call sites stable while routing all\n * empty-state rendering through the shared primitive.\n */\nexport function EmptyState({\n icon,\n title,\n description,\n action,\n className,\n}: {\n icon?: ReactNode;\n title: string;\n description?: string;\n action?: ReactNode;\n className?: string;\n}) {\n return (\n <div className={className}>\n <CanonicalEmptyState\n icon={icon}\n title={title}\n description={description}\n action={action}\n />\n </div>\n );\n}\n"],"mappings":";;;;AA0BA,IAAM,IAAkB;CACtB,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,OAAO;CACP,OAAO;CACP,MAAM;CACP;AAWD,SAAgB,EAAW,EACzB,aACA,UACA,aACA,SACA,kBACA,kBACA,cAAW,MACX,gBAAa,IACb,cACA,uBACkB;AAClB,QACE,kBAAC,OAAD;EACE,WAAW,EAET,qBAEA,iCAEA,yBAEA,4DACA,EACD;YAGD,kBAAC,OAAD;GACE,WAAW,EACT,kBACA,EAAgB,IAChB,EACD;aALH,CAQG,MAAe,KAAS,MACvB,kBAAC,UAAD;IAAQ,WAAU;cAAlB,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CAEE,kBAAC,OAAD;MAAK,WAAU;gBAAf,EACI,KAAS,MACT,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACG,KACC,kBAAC,OAAD;QAAK,WAAU;kBACZ;QACG,CAAA,EAEP,KACC,kBAAC,MAAD;QAAI,WAAU;kBACX;QACE,CAAA,CAEH;UAEP,KACC,kBAAC,KAAD;OAAG,WAAU;iBACV;OACC,CAAA,CAEF;SAGL,KACC,kBAAC,OAAD;MAAK,WAAU;gBACZ;MACG,CAAA,CAEJ;QAGL,KAAiB,kBAAC,OAAD;KAAK,WAAU;eAAQ;KAAoB,CAAA,CACtD;OAMX,kBAAC,OAAD;IAAK,WAAU;IAAa;IAAe,CAAA,CACvC;;EACF,CAAA;;AAOV,SAAgB,EAAY,EAC1B,aACA,UACA,gBACA,YACA,cACA,GAAG,KAOkC;AACrC,QACE,kBAAC,WAAD;EAAS,WAAW,EAAG,aAAa,EAAU;EAAE,GAAI;YAApD,EACI,KAAS,MACT,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACG,KACC,kBAAC,MAAD;IAAI,WAAU;cAA2C;IAAW,CAAA,EAErE,KACC,kBAAC,KAAD;IAAG,WAAU;cAA+B;IAAgB,CAAA,CAE1D,EAAA,CAAA,EACL,KAAW,kBAAC,OAAD;IAAK,WAAU;cAA2B;IAAc,CAAA,CAChE;MAEP,EACO
|
|
1
|
+
{"version":3,"file":"PageLayout.js","names":[],"sources":["../../../src/export/components/PageLayout.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { EmptyState as CanonicalEmptyState } from \"@burdenoff/fe-libs/ui\";\nimport { cn } from \"../utils/cn\";\n\ninterface PageLayoutProps {\n children: ReactNode;\n /** Page title */\n title?: string;\n /** Page subtitle/description */\n subtitle?: string;\n /** Icon component to display next to title */\n icon?: ReactNode;\n /** Actions to display in header (buttons, etc.) */\n headerActions?: ReactNode;\n /** Additional header content below title */\n headerContent?: ReactNode;\n /** Maximum width of content: 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full' */\n maxWidth?: \"sm\" | \"md\" | \"lg\" | \"xl\" | \"2xl\" | \"3xl\" | \"full\";\n /** Whether to show the header section */\n showHeader?: boolean;\n /** Additional CSS classes for the container */\n className?: string;\n /** Additional CSS classes for the content area */\n contentClassName?: string;\n}\n\nconst maxWidthClasses = {\n sm: \"max-w-screen-sm\", // 640px\n md: \"max-w-screen-md\", // 768px\n lg: \"max-w-screen-lg\", // 1024px\n xl: \"max-w-screen-xl\", // 1280px\n \"2xl\": \"max-w-screen-2xl\", // 1536px\n \"3xl\": \"max-w-[1600px]\",\n full: \"max-w-full\",\n};\n\n/**\n * PageLayout - A consistent page wrapper with responsive design\n *\n * Features:\n * - Proper max-width constraints\n * - Responsive padding\n * - Animated entrance\n * - Consistent header styling\n */\nexport function PageLayout({\n children,\n title,\n subtitle,\n icon,\n headerActions,\n headerContent,\n maxWidth = \"xl\",\n showHeader = true,\n className,\n contentClassName,\n}: PageLayoutProps) {\n return (\n <div\n className={cn(\n // Base styles - full width container with padding\n \"min-h-full w-full\",\n // Responsive horizontal padding\n \"px-4 sm:px-6 lg:px-8 xl:px-12\",\n // Responsive vertical padding\n \"py-6 sm:py-8 lg:py-10\",\n // Entrance animation\n \"animate-in fade-in-0 slide-in-from-bottom-4 duration-500\",\n className,\n )}\n >\n {/* Max-width constrained content container */}\n <div\n className={cn(\n \"mx-auto w-full\",\n maxWidthClasses[maxWidth],\n contentClassName,\n )}\n >\n {/* Page Header */}\n {showHeader && (title || headerActions) && (\n <header className=\"mb-6 sm:mb-8\">\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between\">\n {/* Title Section */}\n <div className=\"space-y-1\">\n {(title || icon) && (\n <div className=\"flex items-center gap-3\">\n {icon && (\n <div className=\"flex-shrink-0 p-2.5 rounded-xl bg-action-primary-bg/10 text-primary\">\n {icon}\n </div>\n )}\n {title && (\n <h1 className=\"text-2xl sm:text-3xl font-bold tracking-tight text-text-primary\">\n {title}\n </h1>\n )}\n </div>\n )}\n {subtitle && (\n <p className=\"text-sm sm:text-base text-text-secondary max-w-2xl\">\n {subtitle}\n </p>\n )}\n </div>\n\n {/* Header Actions */}\n {headerActions && (\n <div className=\"flex items-center gap-2 flex-shrink-0\">\n {headerActions}\n </div>\n )}\n </div>\n\n {/* Additional Header Content */}\n {headerContent && <div className=\"mt-4\">{headerContent}</div>}\n </header>\n )}\n\n {/* Page content — must not use a <main> landmark here because the\n host shell (AppShellLayout) already renders one; nesting <main>\n elements is invalid HTML and an a11y violation. */}\n <div className=\"space-y-6\">{children}</div>\n </div>\n </div>\n );\n}\n\n/**\n * PageSection - A section within a page with consistent spacing\n */\nexport function PageSection({\n children,\n title,\n description,\n actions,\n className,\n ...rest\n}: {\n children: ReactNode;\n title?: string;\n description?: string;\n actions?: ReactNode;\n className?: string;\n} & React.HTMLAttributes<HTMLElement>) {\n return (\n <section className={cn(\"space-y-4\", className)} {...rest}>\n {(title || actions) && (\n <div className=\"flex items-center justify-between\">\n <div>\n {title && (\n <h2 className=\"text-lg font-semibold text-text-primary\">{title}</h2>\n )}\n {description && (\n <p className=\"text-sm text-text-secondary\">{description}</p>\n )}\n </div>\n {actions && <div className=\"flex items-center gap-2\">{actions}</div>}\n </div>\n )}\n {children}\n </section>\n );\n}\n\n/**\n * Local wrapper around the canonical `EmptyState` from `@burdenoff/fe-libs/ui`.\n * Keeps the existing microfe-export call sites stable while routing all\n * empty-state rendering through the shared primitive.\n */\nexport function EmptyState({\n icon,\n title,\n description,\n action,\n className,\n}: {\n icon?: ReactNode;\n title: string;\n description?: string;\n action?: ReactNode;\n className?: string;\n}) {\n return (\n <div className={className}>\n <CanonicalEmptyState\n icon={icon}\n title={title}\n description={description}\n action={action}\n />\n </div>\n );\n}\n"],"mappings":";;;;AA0BA,IAAM,IAAkB;CACtB,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,OAAO;CACP,OAAO;CACP,MAAM;CACP;AAWD,SAAgB,EAAW,EACzB,aACA,UACA,aACA,SACA,kBACA,kBACA,cAAW,MACX,gBAAa,IACb,cACA,uBACkB;AAClB,QACE,kBAAC,OAAD;EACE,WAAW,EAET,qBAEA,iCAEA,yBAEA,4DACA,EACD;YAGD,kBAAC,OAAD;GACE,WAAW,EACT,kBACA,EAAgB,IAChB,EACD;aALH,CAQG,MAAe,KAAS,MACvB,kBAAC,UAAD;IAAQ,WAAU;cAAlB,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CAEE,kBAAC,OAAD;MAAK,WAAU;gBAAf,EACI,KAAS,MACT,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACG,KACC,kBAAC,OAAD;QAAK,WAAU;kBACZ;QACG,CAAA,EAEP,KACC,kBAAC,MAAD;QAAI,WAAU;kBACX;QACE,CAAA,CAEH;UAEP,KACC,kBAAC,KAAD;OAAG,WAAU;iBACV;OACC,CAAA,CAEF;SAGL,KACC,kBAAC,OAAD;MAAK,WAAU;gBACZ;MACG,CAAA,CAEJ;QAGL,KAAiB,kBAAC,OAAD;KAAK,WAAU;eAAQ;KAAoB,CAAA,CACtD;OAMX,kBAAC,OAAD;IAAK,WAAU;IAAa;IAAe,CAAA,CACvC;;EACF,CAAA;;AAOV,SAAgB,EAAY,EAC1B,aACA,UACA,gBACA,YACA,cACA,GAAG,KAOkC;AACrC,QACE,kBAAC,WAAD;EAAS,WAAW,EAAG,aAAa,EAAU;EAAE,GAAI;YAApD,EACI,KAAS,MACT,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACG,KACC,kBAAC,MAAD;IAAI,WAAU;cAA2C;IAAW,CAAA,EAErE,KACC,kBAAC,KAAD;IAAG,WAAU;cAA+B;IAAgB,CAAA,CAE1D,EAAA,CAAA,EACL,KAAW,kBAAC,OAAD;IAAK,WAAU;cAA2B;IAAc,CAAA,CAChE;MAEP,EACO"}
|
|
@@ -4,209 +4,230 @@ import { cn as n } from "../utils/cn.js";
|
|
|
4
4
|
import { tWithFallback as r } from "../utils/i18n.js";
|
|
5
5
|
import { ExportStatusBadge as i } from "../components/ExportStatusBadge.js";
|
|
6
6
|
import { ExportProgressBar as a } from "../components/ExportProgressBar.js";
|
|
7
|
-
import {
|
|
8
|
-
import { Activity as
|
|
9
|
-
import { jsx as
|
|
10
|
-
import { useI18n as
|
|
11
|
-
import { EmphasisPanel as y, GlassCard as b } from "@burdenoff/fe-libs/ui";
|
|
7
|
+
import { PageLayout as o, PageSection as s } from "../components/PageLayout.js";
|
|
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
|
+
import { jsx as h, jsxs as g } from "react/jsx-runtime";
|
|
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";
|
|
12
12
|
//#region src/export/pages/ExportDashboardPage.tsx
|
|
13
|
-
var
|
|
14
|
-
function
|
|
15
|
-
let { basePath:
|
|
13
|
+
var C = (e, t) => (e.endsWith("/") ? e.slice(0, -1) : e) + (t.startsWith("/") ? t : `/${t}`);
|
|
14
|
+
function w() {
|
|
15
|
+
let { basePath: w = "/", navigate: T } = e(), { t: E } = _(), D = (e, t, n) => r(E, e, t, n), { data: O, isLoading: k } = t({}), A = O.slice(0, 5), j = O.filter((e) => e.status === "RUNNING" || e.status === "QUEUED"), M = O.filter((e) => e.status === "COMPLETED"), N = [
|
|
16
16
|
{
|
|
17
|
-
icon: /* @__PURE__ */
|
|
18
|
-
label:
|
|
19
|
-
value:
|
|
20
|
-
treatment: "glass"
|
|
17
|
+
icon: /* @__PURE__ */ h(f, { size: 18 }),
|
|
18
|
+
label: D("export.dashboard.metrics.total", "Total Exports"),
|
|
19
|
+
value: O.length,
|
|
20
|
+
treatment: "glass",
|
|
21
|
+
glow: !0
|
|
21
22
|
},
|
|
22
23
|
{
|
|
23
|
-
icon: /* @__PURE__ */
|
|
24
|
-
label:
|
|
25
|
-
value:
|
|
26
|
-
treatment: "metric"
|
|
24
|
+
icon: /* @__PURE__ */ h(c, { size: 18 }),
|
|
25
|
+
label: D("export.dashboard.metrics.active", "Active"),
|
|
26
|
+
value: j.length,
|
|
27
|
+
treatment: "metric",
|
|
28
|
+
glow: !1
|
|
27
29
|
},
|
|
28
30
|
{
|
|
29
|
-
icon: /* @__PURE__ */
|
|
30
|
-
label:
|
|
31
|
-
value:
|
|
32
|
-
treatment: "metric"
|
|
31
|
+
icon: /* @__PURE__ */ h(u, { size: 18 }),
|
|
32
|
+
label: D("export.dashboard.metrics.completed", "Completed"),
|
|
33
|
+
value: M.length,
|
|
34
|
+
treatment: "metric",
|
|
35
|
+
glow: !1
|
|
33
36
|
}
|
|
34
|
-
],
|
|
35
|
-
|
|
37
|
+
], P = (e) => {
|
|
38
|
+
T && T(C(w, e));
|
|
36
39
|
};
|
|
37
|
-
return /* @__PURE__ */
|
|
38
|
-
|
|
39
|
-
subtitle: T("export.dashboard.subtitle", "Export your workspace data in multiple formats"),
|
|
40
|
-
icon: /* @__PURE__ */ g(p, { size: 24 }),
|
|
40
|
+
return /* @__PURE__ */ g(o, {
|
|
41
|
+
showHeader: !1,
|
|
41
42
|
children: [
|
|
42
|
-
|
|
43
|
+
/* @__PURE__ */ g("header", {
|
|
44
|
+
className: "relative overflow-hidden rounded-2xl",
|
|
45
|
+
children: [/* @__PURE__ */ h(v, { intensity: "subtle" }), /* @__PURE__ */ g("div", {
|
|
46
|
+
className: "relative flex items-center gap-3 px-2 py-4 sm:py-5",
|
|
47
|
+
children: [/* @__PURE__ */ h("div", {
|
|
48
|
+
className: "flex-shrink-0 p-2.5 rounded-xl bg-action-primary-bg/10 text-primary",
|
|
49
|
+
children: /* @__PURE__ */ h(f, { size: 24 })
|
|
50
|
+
}), /* @__PURE__ */ g("div", {
|
|
51
|
+
className: "space-y-1",
|
|
52
|
+
children: [/* @__PURE__ */ h("h1", {
|
|
53
|
+
className: "text-2xl sm:text-3xl font-bold tracking-tight text-text-primary",
|
|
54
|
+
children: /* @__PURE__ */ h(x, { children: D("export.dashboard.title", "Export") })
|
|
55
|
+
}), /* @__PURE__ */ h("p", {
|
|
56
|
+
className: "text-sm sm:text-base text-text-secondary max-w-2xl",
|
|
57
|
+
children: D("export.dashboard.subtitle", "Export your workspace data in multiple formats")
|
|
58
|
+
})]
|
|
59
|
+
})]
|
|
60
|
+
})]
|
|
61
|
+
}),
|
|
62
|
+
!k && O.length > 0 && /* @__PURE__ */ h("div", {
|
|
43
63
|
className: "grid grid-cols-1 sm:grid-cols-3 gap-4",
|
|
44
|
-
children:
|
|
64
|
+
children: N.map((e) => /* @__PURE__ */ g(b, {
|
|
45
65
|
treatment: e.treatment,
|
|
66
|
+
glow: e.glow,
|
|
46
67
|
className: "p-5 border-border-seam",
|
|
47
|
-
children: [/* @__PURE__ */
|
|
68
|
+
children: [/* @__PURE__ */ g("div", {
|
|
48
69
|
className: "flex items-center gap-2 text-text-secondary mb-2",
|
|
49
|
-
children: [e.icon, /* @__PURE__ */
|
|
70
|
+
children: [e.icon, /* @__PURE__ */ h("span", {
|
|
50
71
|
className: "text-xs font-medium",
|
|
51
72
|
children: e.label
|
|
52
73
|
})]
|
|
53
|
-
}), /* @__PURE__ */
|
|
74
|
+
}), /* @__PURE__ */ h("p", {
|
|
54
75
|
className: "text-3xl font-bold tabular-nums text-text-primary",
|
|
55
76
|
children: e.value.toLocaleString()
|
|
56
77
|
})]
|
|
57
78
|
}, e.label))
|
|
58
79
|
}),
|
|
59
|
-
/* @__PURE__ */
|
|
80
|
+
/* @__PURE__ */ h("div", {
|
|
60
81
|
className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4",
|
|
61
82
|
"data-tour": "export-dashboard-quick-actions",
|
|
62
83
|
children: [
|
|
63
84
|
{
|
|
64
|
-
icon: /* @__PURE__ */
|
|
65
|
-
label:
|
|
66
|
-
description:
|
|
85
|
+
icon: /* @__PURE__ */ h(m, { size: 20 }),
|
|
86
|
+
label: D("export.dashboard.actions.newExport.label", "New Export"),
|
|
87
|
+
description: D("export.dashboard.actions.newExport.description", "Create a new data export"),
|
|
67
88
|
path: "new",
|
|
68
89
|
color: "bg-action-primary-bg/10 text-primary"
|
|
69
90
|
},
|
|
70
91
|
{
|
|
71
|
-
icon: /* @__PURE__ */
|
|
72
|
-
label:
|
|
73
|
-
description:
|
|
92
|
+
icon: /* @__PURE__ */ h(d, { size: 20 }),
|
|
93
|
+
label: D("export.dashboard.actions.history.label", "History"),
|
|
94
|
+
description: D("export.dashboard.actions.history.description", "View past exports"),
|
|
74
95
|
path: "history",
|
|
75
96
|
color: "bg-status-info-bg-subtle text-status-info-text"
|
|
76
97
|
},
|
|
77
98
|
{
|
|
78
|
-
icon: /* @__PURE__ */
|
|
79
|
-
label:
|
|
80
|
-
description:
|
|
99
|
+
icon: /* @__PURE__ */ h(p, { size: 20 }),
|
|
100
|
+
label: D("export.dashboard.actions.templates.label", "Templates"),
|
|
101
|
+
description: D("export.dashboard.actions.templates.description", "Reusable export configs"),
|
|
81
102
|
path: "templates",
|
|
82
103
|
color: "bg-accent-purple-subtle text-accent-purple"
|
|
83
104
|
},
|
|
84
105
|
{
|
|
85
|
-
icon: /* @__PURE__ */
|
|
86
|
-
label:
|
|
87
|
-
description:
|
|
106
|
+
icon: /* @__PURE__ */ h(c, { size: 20 }),
|
|
107
|
+
label: D("export.dashboard.actions.activeJobs.label", "Active Jobs"),
|
|
108
|
+
description: D("export.dashboard.actions.activeJobs.description", "{count} running", { count: j.length }),
|
|
88
109
|
path: "history?status=RUNNING",
|
|
89
110
|
color: "bg-status-success-bg-subtle text-status-success-text"
|
|
90
111
|
}
|
|
91
|
-
].map((e) => /* @__PURE__ */
|
|
112
|
+
].map((e) => /* @__PURE__ */ g("button", {
|
|
92
113
|
type: "button",
|
|
93
|
-
onClick: () =>
|
|
114
|
+
onClick: () => P(e.path),
|
|
94
115
|
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"),
|
|
95
116
|
children: [
|
|
96
|
-
/* @__PURE__ */
|
|
117
|
+
/* @__PURE__ */ h("div", {
|
|
97
118
|
className: n("p-2.5 rounded-lg w-fit mb-3", e.color),
|
|
98
119
|
children: e.icon
|
|
99
120
|
}),
|
|
100
|
-
/* @__PURE__ */
|
|
121
|
+
/* @__PURE__ */ h("h3", {
|
|
101
122
|
className: "font-semibold text-text-primary mb-1",
|
|
102
123
|
children: e.label
|
|
103
124
|
}),
|
|
104
|
-
/* @__PURE__ */
|
|
125
|
+
/* @__PURE__ */ h("p", {
|
|
105
126
|
className: "text-sm text-text-secondary",
|
|
106
127
|
children: e.description
|
|
107
128
|
}),
|
|
108
|
-
/* @__PURE__ */
|
|
129
|
+
/* @__PURE__ */ h(l, {
|
|
109
130
|
size: 16,
|
|
110
131
|
className: "absolute top-5 right-5 text-text-secondary opacity-0 group-hover:opacity-100 transition-opacity"
|
|
111
132
|
})
|
|
112
133
|
]
|
|
113
134
|
}, e.path + e.label))
|
|
114
135
|
}),
|
|
115
|
-
|
|
136
|
+
j.length > 0 && /* @__PURE__ */ g(y, {
|
|
116
137
|
"data-tour": "export-dashboard-active-section",
|
|
117
138
|
className: "p-5 sm:p-6",
|
|
118
|
-
children: [/* @__PURE__ */
|
|
139
|
+
children: [/* @__PURE__ */ g("div", {
|
|
119
140
|
className: "mb-4",
|
|
120
|
-
children: [/* @__PURE__ */
|
|
141
|
+
children: [/* @__PURE__ */ h("h2", {
|
|
121
142
|
className: "text-lg font-semibold text-text-primary",
|
|
122
|
-
children:
|
|
123
|
-
}), /* @__PURE__ */
|
|
143
|
+
children: D("export.dashboard.active.title", "Active Exports")
|
|
144
|
+
}), /* @__PURE__ */ h("p", {
|
|
124
145
|
className: "text-sm text-text-secondary",
|
|
125
|
-
children:
|
|
146
|
+
children: D("export.dashboard.active.description", "Currently running export jobs")
|
|
126
147
|
})]
|
|
127
|
-
}), /* @__PURE__ */
|
|
148
|
+
}), /* @__PURE__ */ h("div", {
|
|
128
149
|
className: "space-y-3",
|
|
129
|
-
children:
|
|
150
|
+
children: j.map((e) => /* @__PURE__ */ g("button", {
|
|
130
151
|
type: "button",
|
|
131
|
-
onClick: () =>
|
|
152
|
+
onClick: () => P(e.id),
|
|
132
153
|
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"),
|
|
133
|
-
children: [/* @__PURE__ */
|
|
154
|
+
children: [/* @__PURE__ */ g("div", {
|
|
134
155
|
className: "flex items-center justify-between mb-2",
|
|
135
|
-
children: [/* @__PURE__ */
|
|
156
|
+
children: [/* @__PURE__ */ h("h4", {
|
|
136
157
|
className: "font-semibold text-text-primary",
|
|
137
158
|
children: e.name
|
|
138
|
-
}), /* @__PURE__ */
|
|
139
|
-
}), /* @__PURE__ */
|
|
159
|
+
}), /* @__PURE__ */ h(i, { status: e.status })]
|
|
160
|
+
}), /* @__PURE__ */ h(a, {
|
|
140
161
|
progress: e.progress,
|
|
141
162
|
size: "sm"
|
|
142
163
|
})]
|
|
143
164
|
}, e.id))
|
|
144
165
|
})]
|
|
145
166
|
}),
|
|
146
|
-
/* @__PURE__ */
|
|
167
|
+
/* @__PURE__ */ h(s, {
|
|
147
168
|
"data-tour": "export-dashboard-recent-section",
|
|
148
|
-
title:
|
|
149
|
-
description:
|
|
150
|
-
actions:
|
|
169
|
+
title: D("export.dashboard.recent.title", "Recent Exports"),
|
|
170
|
+
description: D("export.dashboard.recent.description", "Your latest export jobs"),
|
|
171
|
+
actions: A.length > 0 ? /* @__PURE__ */ h("button", {
|
|
151
172
|
type: "button",
|
|
152
|
-
onClick: () =>
|
|
173
|
+
onClick: () => P("history"),
|
|
153
174
|
className: "text-sm text-primary hover:underline font-medium",
|
|
154
|
-
children:
|
|
175
|
+
children: D("export.dashboard.recent.actions.viewAll", "View All")
|
|
155
176
|
}) : void 0,
|
|
156
|
-
children:
|
|
177
|
+
children: k ? /* @__PURE__ */ h("div", {
|
|
157
178
|
className: "space-y-3",
|
|
158
179
|
children: [...[
|
|
159
180
|
,
|
|
160
181
|
,
|
|
161
182
|
,
|
|
162
|
-
]].map((e, t) => /* @__PURE__ */
|
|
163
|
-
className: "border border-border-seam rounded-xl p-4
|
|
164
|
-
children: [/* @__PURE__ */
|
|
183
|
+
]].map((e, t) => /* @__PURE__ */ g("div", {
|
|
184
|
+
className: "border border-border-seam rounded-xl p-4",
|
|
185
|
+
children: [/* @__PURE__ */ g("div", {
|
|
165
186
|
className: "flex items-center justify-between mb-2",
|
|
166
|
-
children: [/* @__PURE__ */
|
|
167
|
-
}), /* @__PURE__ */
|
|
187
|
+
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
|
+
}), /* @__PURE__ */ h("div", { className: "h-3 w-32 bg-bg-sunken rounded mt-2 animate-vc-shimmer" })]
|
|
168
189
|
}, t))
|
|
169
|
-
}) :
|
|
190
|
+
}) : A.length > 0 ? /* @__PURE__ */ h("div", {
|
|
170
191
|
className: "space-y-3",
|
|
171
|
-
children:
|
|
192
|
+
children: A.map((e, t) => /* @__PURE__ */ h("button", {
|
|
172
193
|
type: "button",
|
|
173
|
-
onClick: () =>
|
|
194
|
+
onClick: () => P(e.id),
|
|
174
195
|
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"),
|
|
175
196
|
style: { animationDelay: `${t * 50}ms` },
|
|
176
|
-
children: /* @__PURE__ */
|
|
197
|
+
children: /* @__PURE__ */ g("div", {
|
|
177
198
|
className: "flex items-start sm:items-center justify-between gap-3",
|
|
178
|
-
children: [/* @__PURE__ */
|
|
199
|
+
children: [/* @__PURE__ */ g("div", {
|
|
179
200
|
className: "flex-1 min-w-0",
|
|
180
|
-
children: [/* @__PURE__ */
|
|
201
|
+
children: [/* @__PURE__ */ h("h4", {
|
|
181
202
|
className: "font-semibold text-text-primary truncate",
|
|
182
203
|
children: e.name
|
|
183
|
-
}), /* @__PURE__ */
|
|
204
|
+
}), /* @__PURE__ */ g("p", {
|
|
184
205
|
className: "text-sm text-text-secondary mt-1 line-clamp-2",
|
|
185
206
|
children: [
|
|
186
207
|
e.entityTypes.join(", "),
|
|
187
208
|
" · ",
|
|
188
209
|
e.format,
|
|
189
|
-
e.totalEntities != null && ` · ${
|
|
210
|
+
e.totalEntities != null && ` · ${D("export.dashboard.recent.entitiesCount", "{count} entities", { count: e.totalEntities.toLocaleString() })}`
|
|
190
211
|
]
|
|
191
212
|
})]
|
|
192
|
-
}), /* @__PURE__ */
|
|
213
|
+
}), /* @__PURE__ */ g("div", {
|
|
193
214
|
className: "flex items-center gap-2 flex-shrink-0",
|
|
194
|
-
children: [/* @__PURE__ */
|
|
215
|
+
children: [/* @__PURE__ */ h(i, { status: e.status }), /* @__PURE__ */ h(l, {
|
|
195
216
|
size: 16,
|
|
196
217
|
className: "text-text-secondary hidden sm:block"
|
|
197
218
|
})]
|
|
198
219
|
})]
|
|
199
220
|
})
|
|
200
221
|
}, e.id))
|
|
201
|
-
}) : /* @__PURE__ */
|
|
202
|
-
|
|
203
|
-
title:
|
|
204
|
-
description:
|
|
205
|
-
action: /* @__PURE__ */
|
|
222
|
+
}) : /* @__PURE__ */ h(S, {
|
|
223
|
+
illustration: "empty-files",
|
|
224
|
+
title: D("export.dashboard.empty.title", "No exports yet"),
|
|
225
|
+
description: D("export.dashboard.empty.description", "Create your first export to start downloading your workspace data."),
|
|
226
|
+
action: /* @__PURE__ */ g("button", {
|
|
206
227
|
type: "button",
|
|
207
|
-
onClick: () =>
|
|
228
|
+
onClick: () => P("new"),
|
|
208
229
|
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",
|
|
209
|
-
children: [/* @__PURE__ */
|
|
230
|
+
children: [/* @__PURE__ */ h(m, { size: 16 }), D("export.dashboard.empty.actions.createFirst", "Create First Export")]
|
|
210
231
|
})
|
|
211
232
|
})
|
|
212
233
|
})
|
|
@@ -214,6 +235,6 @@ function S() {
|
|
|
214
235
|
});
|
|
215
236
|
}
|
|
216
237
|
//#endregion
|
|
217
|
-
export {
|
|
238
|
+
export { w as ExportDashboardPage };
|
|
218
239
|
|
|
219
240
|
//# 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 { 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(\", \")} · {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} 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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"}
|