@burdenoff/microfe-export 2026.623.1 → 2026.624.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":"CreateExportPage.js","names":[],"sources":["../../../src/export/pages/CreateExportPage.tsx"],"sourcesContent":["import { useState, useEffect, useRef } from \"react\";\nimport { useSearchParams } from \"react-router-dom\";\nimport {\n ArrowLeft,\n ArrowRight,\n Download,\n CheckCircle2,\n Loader2,\n FileSpreadsheet,\n FileJson,\n Package,\n CalendarRange,\n User,\n Users,\n Building2,\n Lock,\n} from \"lucide-react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport { usePermission } from \"@burdenoff/fe-libs/shared/providers/shell\";\nimport { useExport } from \"../providers/ExportProvider\";\nimport {\n useCreateExportJob,\n useAvailableEntities,\n useExportTemplates,\n} from \"../hooks/useExportQueries\";\nimport { getFormatDisplayName } from \"../constants/enums\";\nimport { PageLayout } from \"../components/PageLayout\";\nimport { cn } from \"../utils/cn\";\nimport { isExportEntityDisabled } from \"../utils/disabledModules\";\nimport type {\n ExportAvailableEntity,\n ExportFormat,\n ExportScope,\n} from \"../types\";\nimport { tWithFallback } from \"../utils/i18n\";\n\ntype WizardStep = \"entities\" | \"options\" | \"review\";\n\n// Backend only supports CSV and JSON\nconst SUPPORTED_FORMATS: ExportFormat[] = [\"CSV\", \"JSON\"];\n\nconst FORMAT_ICONS: Record<ExportFormat, typeof FileJson> = {\n CSV: FileSpreadsheet,\n JSON: FileJson,\n};\n\n/**\n * Create Export Page\n * Multi-step form: select entities, configure options, review & start\n */\nconst SCOPE_OPTIONS: Array<{\n value: ExportScope;\n label: string;\n description: string;\n Icon: typeof User;\n}> = [\n {\n value: \"INDIVIDUAL\",\n label: \"My Data Only\",\n description: \"Export data you personally created across selected modules.\",\n Icon: User,\n },\n {\n value: \"WORKSPACE_ADMIN\",\n label: \"All Workspace Data\",\n description:\n \"Export all data in this workspace regardless of who created it. Requires workspace admin access.\",\n Icon: Users,\n },\n {\n value: \"ORG_ADMIN\",\n label: \"All Organization Data\",\n description:\n \"Export data from every workspace in your organization. Requires org-admin access.\",\n Icon: Building2,\n },\n];\n\nexport function CreateExportPage() {\n const { basePath = \"/\", navigate, organizationId } = 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 { createJob, isPending } = useCreateExportJob();\n const { data: availableEntities } = useAvailableEntities();\n const { data: templates } = useExportTemplates();\n const [searchParams] = useSearchParams();\n\n // RBAC: Check permissions for admin scopes\n const canExportWorkspaceAdmin = usePermission(\"export:workspace:admin\");\n const canExportOrgAdmin = usePermission(\"export:org:admin\");\n\n const [step, setStep] = useState<WizardStep>(\"entities\");\n const [selectedEntities, setSelectedEntities] = useState<string[]>([]);\n const [exportName, setExportName] = useState(\"\");\n const [selectedFormat, setSelectedFormat] = useState<ExportFormat>(\"CSV\");\n const [selectedScope, setSelectedScope] = useState<ExportScope>(\"INDIVIDUAL\");\n const [selectedTemplateId, setSelectedTemplateId] = useState<\n string | undefined\n >(searchParams.get(\"templateId\") ?? undefined);\n const [dateRangeStart, setDateRangeStart] = useState(\"\");\n const [dateRangeEnd, setDateRangeEnd] = useState(\"\");\n const [error, setError] = useState<string | null>(null);\n\n // Pre-populate form when arriving from \"Use Template\" — apply only once per templateId\n const appliedTemplateRef = useRef<string | null>(null);\n useEffect(() => {\n const paramTemplateId = searchParams.get(\"templateId\");\n if (!paramTemplateId || !templates?.length) return;\n if (appliedTemplateRef.current === paramTemplateId) return;\n const tpl = templates.find((t) => t.id === paramTemplateId);\n if (!tpl) return;\n appliedTemplateRef.current = paramTemplateId;\n setSelectedTemplateId(tpl.id);\n // Skip entity types whose product export is currently disabled.\n setSelectedEntities(\n (tpl.entityTypes ?? []).filter((et) => !isExportEntityDisabled(et)),\n );\n const normalizedFormat = tpl.format?.toUpperCase() as\n | ExportFormat\n | undefined;\n if (normalizedFormat && SUPPORTED_FORMATS.includes(normalizedFormat)) {\n setSelectedFormat(normalizedFormat);\n }\n if (tpl.name) setExportName(tpl.name);\n }, [searchParams, templates]);\n\n const handleBack = () => {\n if (step === \"options\") setStep(\"entities\");\n else if (step === \"review\") setStep(\"options\");\n else navigate?.(basePath);\n };\n\n const handleNext = () => {\n if (step === \"entities\") {\n if (selectedEntities.length === 0) {\n setError(\n tr(\n \"export.create.errors.selectEntity\",\n \"Please select at least one entity type to export\",\n ),\n );\n return;\n }\n setError(null);\n setStep(\"options\");\n } else if (step === \"options\") {\n if (!exportName.trim()) {\n setError(\n tr(\n \"export.create.errors.exportNameRequired\",\n \"Please provide a name for this export\",\n ),\n );\n return;\n }\n setError(null);\n setStep(\"review\");\n }\n };\n\n const handleSubmit = async () => {\n try {\n setError(null);\n await createJob({\n name: exportName,\n entityTypes: selectedEntities,\n format: selectedFormat,\n exportScope: selectedScope,\n organizationId:\n selectedScope === \"ORG_ADMIN\" ? organizationId : undefined,\n templateId: selectedTemplateId,\n dateRangeStart: dateRangeStart\n ? new Date(dateRangeStart).toISOString()\n : null,\n dateRangeEnd: dateRangeEnd\n ? new Date(dateRangeEnd).toISOString()\n : null,\n });\n navigate?.(basePath);\n } catch (err) {\n setError(\n err instanceof Error\n ? err.message\n : tr(\"export.create.errors.createFailed\", \"Failed to create export\"),\n );\n }\n };\n\n const toggleEntity = (entityType: string) => {\n // Disabled-product entities can't be selected.\n if (isExportEntityDisabled(entityType)) return;\n setSelectedEntities((prev) =>\n prev.includes(entityType)\n ? prev.filter((e) => e !== entityType)\n : [...prev, entityType],\n );\n };\n\n const getScopeLabel = (scope: ExportScope) => {\n switch (scope) {\n case \"INDIVIDUAL\":\n return tr(\"export.create.scope.individual.label\", \"My Data Only\");\n case \"WORKSPACE_ADMIN\":\n return tr(\n \"export.create.scope.workspaceAdmin.label\",\n \"All Workspace Data\",\n );\n case \"ORG_ADMIN\":\n return tr(\n \"export.create.scope.orgAdmin.label\",\n \"All Organization Data\",\n );\n default:\n return scope;\n }\n };\n\n const getScopeDescription = (scope: ExportScope) => {\n switch (scope) {\n case \"INDIVIDUAL\":\n return tr(\n \"export.create.scope.individual.description\",\n \"Export data you personally created across selected modules.\",\n );\n case \"WORKSPACE_ADMIN\":\n return tr(\n \"export.create.scope.workspaceAdmin.description\",\n \"Export all data in this workspace regardless of who created it. Requires workspace admin access.\",\n );\n case \"ORG_ADMIN\":\n return tr(\n \"export.create.scope.orgAdmin.description\",\n \"Export data from every workspace in your organization. Requires org-admin access.\",\n );\n default:\n return \"\";\n }\n };\n\n const fallbackEntityCopy: Record<\n string,\n { label: string; description: string }\n > = {\n users: {\n label: tr(\"export.create.entities.users.label\", \"Users\"),\n description: tr(\n \"export.create.entities.users.description\",\n \"Workspace members and profiles\",\n ),\n },\n projects: {\n label: tr(\"export.create.entities.projects.label\", \"Projects\"),\n description: tr(\n \"export.create.entities.projects.description\",\n \"Projects and their metadata\",\n ),\n },\n tasks: {\n label: tr(\"export.create.entities.tasks.label\", \"Tasks\"),\n description: tr(\n \"export.create.entities.tasks.description\",\n \"Task items and assignments\",\n ),\n },\n files: {\n label: tr(\"export.create.entities.files.label\", \"Files\"),\n description: tr(\n \"export.create.entities.files.description\",\n \"File metadata and references\",\n ),\n },\n conversations: {\n label: tr(\"export.create.entities.conversations.label\", \"Conversations\"),\n description: tr(\n \"export.create.entities.conversations.description\",\n \"Chat messages and threads\",\n ),\n },\n tags: {\n label: tr(\"export.create.entities.tags.label\", \"Tags\"),\n description: tr(\n \"export.create.entities.tags.description\",\n \"Tags and vocabularies\",\n ),\n },\n activity: {\n label: tr(\"export.create.entities.activity.label\", \"Activity Logs\"),\n description: tr(\n \"export.create.entities.activity.description\",\n \"Audit trail and activity history\",\n ),\n },\n calendar: {\n label: tr(\"export.create.entities.calendar.label\", \"Calendar Events\"),\n description: tr(\n \"export.create.entities.calendar.description\",\n \"Events and bookings\",\n ),\n },\n };\n\n // Entities the backend marks available, split so the ones a user can export\n // show first and disabled-product entities are listed (still visible) below.\n const visibleEntities = availableEntities.filter((e) => e.enabled !== false);\n const availableForExport = visibleEntities.filter(\n (e) => !isExportEntityDisabled(e.entityType),\n );\n const unavailableForExport = visibleEntities.filter((e) =>\n isExportEntityDisabled(e.entityType),\n );\n\n const renderEntityCard = (\n entity: ExportAvailableEntity,\n isDisabled: boolean,\n ) => {\n const isSelected =\n !isDisabled && selectedEntities.includes(entity.entityType);\n return (\n <button\n type=\"button\"\n key={entity.entityType}\n onClick={() => toggleEntity(entity.entityType)}\n disabled={isDisabled}\n aria-disabled={isDisabled}\n title={\n isDisabled\n ? tr(\n \"export.create.select.unavailableHint\",\n \"Export for this product isn't available yet\",\n )\n : undefined\n }\n className={cn(\n \"text-left border-2 rounded-xl p-4 transition-all duration-200\",\n isDisabled\n ? \"border-border/30 opacity-50 cursor-not-allowed\"\n : isSelected\n ? \"border-primary bg-primary/5 shadow-md\"\n : \"border-border/50 hover:border-primary/30 hover:shadow-sm\",\n )}\n >\n <div className=\"flex items-center justify-between mb-2 gap-2\">\n <h3 className=\"font-semibold\">\n {fallbackEntityCopy[entity.entityType]?.label ?? entity.displayName}\n </h3>\n {isDisabled ? (\n <span className=\"shrink-0 text-xs font-medium px-2 py-0.5 rounded-full bg-muted text-muted-foreground\">\n {tr(\"export.create.select.unavailable\", \"Unavailable\")}\n </span>\n ) : (\n isSelected && <CheckCircle2 size={18} className=\"text-primary\" />\n )}\n </div>\n <p className=\"text-sm text-muted-foreground\">\n {fallbackEntityCopy[entity.entityType]?.description ??\n entity.description}\n </p>\n {entity.estimatedSize && (\n <p className=\"text-xs text-muted-foreground mt-2\">\n ~{entity.estimatedSize}\n </p>\n )}\n </button>\n );\n };\n\n return (\n <PageLayout showHeader={false}>\n {/* Header */}\n <div className=\"relative overflow-hidden rounded-xl bg-gradient-to-br from-primary/5 via-primary/3 to-background border border-border/50 p-6 shadow-sm\">\n <div className=\"relative z-10 flex items-center gap-4\">\n <button\n type=\"button\"\n onClick={() => navigate?.(basePath)}\n className=\"p-2.5 hover:bg-accent rounded-lg transition-all duration-200 hover:scale-110\"\n aria-label={tr(\n \"export.create.actions.backToDashboard\",\n \"Back to export dashboard\",\n )}\n >\n <ArrowLeft size={20} />\n </button>\n <div className=\"flex items-center gap-3\">\n <div className=\"p-2.5 rounded-lg bg-primary/10 backdrop-blur-sm\">\n <Download size={24} className=\"text-primary\" />\n </div>\n <h1 className=\"text-2xl sm:text-3xl font-bold\">\n {tr(\"export.create.title\", \"New Export\")}\n </h1>\n </div>\n </div>\n </div>\n\n {/* Step Indicator */}\n <div className=\"flex items-center gap-2 justify-center flex-wrap\">\n {([\"entities\", \"options\", \"review\"] as WizardStep[]).map((s, i) => (\n <div key={s} className=\"flex items-center gap-2\">\n {i > 0 && (\n <ArrowRight size={18} className=\"text-muted-foreground\" />\n )}\n <div\n className={cn(\n \"flex items-center gap-2 px-4 py-2.5 rounded-lg text-sm font-medium border-2 transition-all duration-200\",\n step === s\n ? \"bg-primary text-primary-foreground border-primary shadow-md scale-105\"\n : \"bg-muted/50 text-muted-foreground border-border/50\",\n )}\n >\n <div className=\"flex items-center justify-center size-6 rounded-full bg-background/20 font-bold\">\n {i + 1}\n </div>\n <span className=\"hidden sm:inline capitalize\">\n {s === \"entities\"\n ? tr(\"export.create.steps.entities\", \"Select Data\")\n : s === \"options\"\n ? tr(\"export.create.steps.options\", \"Options\")\n : tr(\"export.create.steps.review\", \"Review\")}\n </span>\n </div>\n </div>\n ))}\n </div>\n\n {/* Error */}\n {error && (\n <div className=\"border-2 border-border-default rounded-xl bg-status-error-bg-subtle p-4 text-status-error-text text-sm\">\n {error}\n </div>\n )}\n\n {/* Step 1: Select Entities */}\n {step === \"entities\" && (\n <div className=\"space-y-4\">\n <h2 className=\"text-lg font-bold\">\n {tr(\"export.create.select.title\", \"Select data to export\")}\n </h2>\n <p className=\"text-sm text-muted-foreground\">\n {tr(\n \"export.create.select.description\",\n \"Choose which entity types to include in your export.\",\n )}\n </p>\n {visibleEntities.length === 0 ? (\n <div className=\"border-2 border-border rounded-xl bg-muted/30 p-6 text-sm text-muted-foreground\">\n {tr(\n \"export.create.select.empty\",\n \"No exportable entity types are configured for this workspace yet.\",\n )}\n </div>\n ) : (\n <div className=\"space-y-6\">\n {availableForExport.length > 0 && (\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3\">\n {availableForExport.map((entity) =>\n renderEntityCard(entity, false),\n )}\n </div>\n )}\n {unavailableForExport.length > 0 && (\n <div className=\"space-y-3\">\n <div className=\"flex items-center gap-3\">\n <div className=\"h-px flex-1 bg-border/60\" />\n <span className=\"text-xs font-medium uppercase tracking-wide text-muted-foreground\">\n {tr(\n \"export.create.select.unavailableSection\",\n \"Not available yet\",\n )}\n </span>\n <div className=\"h-px flex-1 bg-border/60\" />\n </div>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3\">\n {unavailableForExport.map((entity) =>\n renderEntityCard(entity, true),\n )}\n </div>\n </div>\n )}\n </div>\n )}\n </div>\n )}\n\n {/* Step 2: Configure Options */}\n {step === \"options\" && (\n <div className=\"space-y-6\">\n <div className=\"border-2 border-border/50 rounded-xl p-6 space-y-5\">\n <h2 className=\"text-lg font-bold\">\n {tr(\"export.create.options.title\", \"Export Options\")}\n </h2>\n\n {/* Scope selection */}\n <div>\n <label className=\"block text-sm font-semibold mb-2\">\n {tr(\"export.create.options.scope\", \"Export Scope\")}\n </label>\n <div className=\"grid grid-cols-1 sm:grid-cols-3 gap-3\">\n {SCOPE_OPTIONS.map(({ value, Icon }) => {\n // RBAC: Disable admin scopes if user lacks permission\n const isDisabled =\n (value === \"WORKSPACE_ADMIN\" && !canExportWorkspaceAdmin) ||\n (value === \"ORG_ADMIN\" && !canExportOrgAdmin);\n\n return (\n <button\n key={value}\n type=\"button\"\n onClick={() => !isDisabled && setSelectedScope(value)}\n disabled={isDisabled}\n className={cn(\n \"text-left border-2 rounded-xl p-4 transition-all duration-200\",\n selectedScope === value\n ? \"border-primary bg-primary/5 shadow-md\"\n : isDisabled\n ? \"border-border/30 opacity-50 cursor-not-allowed\"\n : \"border-border/50 hover:border-primary/30 hover:shadow-sm\",\n )}\n title={\n isDisabled\n ? value === \"WORKSPACE_ADMIN\"\n ? \"Workspace admin access required\"\n : \"Organization admin access required\"\n : undefined\n }\n >\n <div className=\"flex items-center justify-between mb-2\">\n <Icon\n size={18}\n className={\n selectedScope === value\n ? \"text-primary\"\n : isDisabled\n ? \"text-muted-foreground/50\"\n : \"text-muted-foreground\"\n }\n />\n {selectedScope === value && (\n <CheckCircle2 size={16} className=\"text-primary\" />\n )}\n {isDisabled && (\n <Lock\n size={14}\n className=\"text-muted-foreground/50\"\n />\n )}\n </div>\n <p className=\"font-semibold text-sm\">\n {getScopeLabel(value)}\n </p>\n <p className=\"text-xs text-muted-foreground mt-1\">\n {getScopeDescription(value)}\n </p>\n </button>\n );\n })}\n </div>\n </div>\n\n {/* Name */}\n <div>\n <label\n htmlFor=\"exportName\"\n className=\"block text-sm font-semibold mb-2\"\n >\n {tr(\"export.create.options.name\", \"Export Name\")}{\" \"}\n <span className=\"text-status-error-text\">*</span>\n </label>\n <input\n type=\"text\"\n id=\"exportName\"\n aria-label={tr(\"export.create.options.name\", \"Export Name\")}\n value={exportName}\n onChange={(e) => setExportName(e.target.value)}\n className=\"w-full px-4 py-2.5 border-2 border-border rounded-lg bg-background focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary transition-all duration-200\"\n placeholder={tr(\n \"export.create.options.namePlaceholder\",\n \"e.g., Monthly User Export\",\n )}\n />\n </div>\n\n {/* Format — only CSV and JSON are supported */}\n <div>\n <label className=\"block text-sm font-semibold mb-2\">\n {tr(\"export.create.options.outputFormat\", \"Output Format\")}\n </label>\n <div className=\"grid grid-cols-2 gap-3\">\n {SUPPORTED_FORMATS.map((format) => {\n const Icon = FORMAT_ICONS[format];\n return (\n <button\n type=\"button\"\n key={format}\n onClick={() => setSelectedFormat(format)}\n className={cn(\n \"flex items-center gap-3 border-2 rounded-lg p-3 transition-all duration-200\",\n selectedFormat === format\n ? \"border-primary bg-primary/5\"\n : \"border-border/50 hover:border-primary/30\",\n )}\n >\n <Icon\n size={18}\n className={\n selectedFormat === format\n ? \"text-primary\"\n : \"text-muted-foreground\"\n }\n />\n <span className=\"font-medium text-sm\">\n {getFormatDisplayName(format)}\n </span>\n </button>\n );\n })}\n </div>\n </div>\n\n {/* Archive format — only ZIP is supported */}\n <div>\n <label className=\"block text-sm font-semibold mb-2\">\n {tr(\"export.create.options.archiveFormat\", \"Archive Format\")}\n </label>\n <div className=\"flex gap-3\">\n <div\n className={cn(\n \"flex items-center gap-2 border-2 rounded-lg px-4 py-2 border-primary bg-primary/5\",\n )}\n >\n <Package size={16} className=\"text-primary\" />\n <span className=\"font-medium text-sm\">ZIP</span>\n </div>\n </div>\n <p className=\"text-xs text-muted-foreground mt-1.5\">\n {tr(\n \"export.create.options.archiveDescription\",\n \"Exports are packaged as ZIP archives.\",\n )}\n </p>\n </div>\n\n {/* Date range filter — always visible */}\n <div>\n <label className=\"block text-sm font-semibold mb-2\">\n <span className=\"inline-flex items-center gap-1.5\">\n <CalendarRange size={15} />\n {tr(\"export.create.options.dateRange\", \"Date Range\")}{\" \"}\n <span className=\"font-normal text-muted-foreground\">\n {tr(\"export.create.shared.optional\", \"(optional)\")}\n </span>\n </span>\n </label>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-3\">\n <div>\n <label\n htmlFor=\"dateFrom\"\n className=\"block text-xs text-muted-foreground mb-1\"\n >\n {tr(\"export.create.options.dateFrom\", \"From\")}\n </label>\n <input\n type=\"date\"\n id=\"dateFrom\"\n aria-label={tr(\"export.create.options.dateFrom\", \"From\")}\n value={dateRangeStart}\n onChange={(e) => setDateRangeStart(e.target.value)}\n className=\"w-full px-3 py-2 border-2 border-border rounded-lg bg-background focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary text-sm\"\n />\n </div>\n <div>\n <label\n htmlFor=\"dateTo\"\n className=\"block text-xs text-muted-foreground mb-1\"\n >\n {tr(\"export.create.options.dateTo\", \"To\")}\n </label>\n <input\n type=\"date\"\n id=\"dateTo\"\n aria-label={tr(\"export.create.options.dateTo\", \"To\")}\n value={dateRangeEnd}\n min={dateRangeStart}\n onChange={(e) => setDateRangeEnd(e.target.value)}\n className=\"w-full px-3 py-2 border-2 border-border rounded-lg bg-background focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary text-sm\"\n />\n </div>\n </div>\n <p className=\"text-xs text-muted-foreground mt-1.5\">\n {tr(\n \"export.create.options.dateRangeDescription\",\n \"Leave blank to export all data regardless of date.\",\n )}\n </p>\n </div>\n\n {/* Optional: Use a template */}\n <div>\n <label className=\"block text-sm font-semibold mb-2\">\n {tr(\n \"export.create.options.basedOnTemplate\",\n \"Based on Template\",\n )}{\" \"}\n <span className=\"font-normal text-muted-foreground\">\n {tr(\"export.create.shared.optional\", \"(optional)\")}\n </span>\n </label>\n {templates.length > 0 ? (\n <select\n value={selectedTemplateId ?? \"\"}\n onChange={(e) =>\n setSelectedTemplateId(e.target.value || undefined)\n }\n className=\"w-full px-3 py-2 border-2 border-border rounded-lg bg-background focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary\"\n >\n <option value=\"\">\n {tr(\"export.create.options.noTemplate\", \"No template\")}\n </option>\n {templates.map((t) => (\n <option key={t.id} value={t.id}>\n {t.name}\n </option>\n ))}\n </select>\n ) : (\n <p className=\"text-sm text-muted-foreground\">\n {tr(\"export.create.options.noTemplates\", \"No templates yet.\")}{\" \"}\n <button\n type=\"button\"\n onClick={() => navigate?.(basePath + \"/templates\")}\n className=\"text-primary underline-offset-2 hover:underline\"\n >\n {tr(\n \"export.create.options.createTemplateLink\",\n \"Create one\",\n )}\n </button>{\" \"}\n {tr(\n \"export.create.options.reuseTemplateHint\",\n \"to reuse export configurations.\",\n )}\n </p>\n )}\n </div>\n </div>\n </div>\n )}\n\n {/* Step 3: Review */}\n {step === \"review\" && (\n <div className=\"space-y-6\">\n <div className=\"border-2 border-primary/50 rounded-xl bg-primary/5 p-6 space-y-4\">\n <h2 className=\"text-lg font-bold flex items-center gap-2\">\n <CheckCircle2 size={20} className=\"text-primary\" />\n {tr(\"export.create.review.title\", \"Review Export\")}\n </h2>\n <dl className=\"space-y-3 text-sm\">\n {[\n {\n label: tr(\"export.create.review.fields.name\", \"Name\"),\n value: exportName,\n },\n {\n label: tr(\"export.create.review.fields.scope\", \"Scope\"),\n value: getScopeLabel(selectedScope),\n },\n {\n label: tr(\n \"export.create.review.fields.entityTypes\",\n \"Entity Types\",\n ),\n value: selectedEntities.join(\", \"),\n },\n {\n label: tr(\"export.create.review.fields.format\", \"Format\"),\n value: getFormatDisplayName(selectedFormat),\n },\n {\n label: tr(\"export.create.review.fields.archive\", \"Archive\"),\n value: \"ZIP\",\n },\n ...(dateRangeStart || dateRangeEnd\n ? [\n {\n label: tr(\n \"export.create.review.fields.dateRange\",\n \"Date Range\",\n ),\n value: [\n dateRangeStart || \"—\",\n dateRangeEnd || \"—\",\n ].join(\" → \"),\n },\n ]\n : []),\n ...(selectedTemplateId\n ? [\n {\n label: tr(\n \"export.create.review.fields.template\",\n \"Template\",\n ),\n value:\n templates.find((t) => t.id === selectedTemplateId)\n ?.name ?? selectedTemplateId,\n },\n ]\n : []),\n ].map(({ label, value }) => (\n <div\n key={label}\n className=\"flex flex-col sm:flex-row sm:justify-between gap-1\"\n >\n <dt className=\"text-muted-foreground\">{label}</dt>\n <dd className=\"font-semibold sm:text-right break-words\">\n {value}\n </dd>\n </div>\n ))}\n </dl>\n </div>\n </div>\n )}\n\n {/* Actions */}\n <div className=\"flex flex-col sm:flex-row gap-3 pt-2\">\n <button\n type=\"button\"\n onClick={handleBack}\n className=\"px-6 py-3 border-2 border-border/50 rounded-lg hover:bg-accent hover:border-primary/30 transition-all duration-200 font-medium\"\n >\n {step === \"entities\"\n ? tr(\"export.create.actions.cancel\", \"Cancel\")\n : tr(\"export.create.actions.back\", \"Back\")}\n </button>\n {step === \"review\" ? (\n <button\n type=\"button\"\n onClick={handleSubmit}\n disabled={isPending}\n className=\"flex-1 inline-flex items-center justify-center gap-2 px-6 py-3 bg-primary text-primary-foreground rounded-lg hover:bg-primary/90 transition-all duration-200 hover:scale-105 font-bold shadow-lg disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n {isPending ? (\n <Loader2 size={18} className=\"animate-spin\" />\n ) : (\n <Download size={18} />\n )}\n {tr(\"export.create.actions.startExport\", \"Start Export\")}\n </button>\n ) : (\n <button\n type=\"button\"\n onClick={handleNext}\n className=\"flex-1 inline-flex items-center justify-center gap-2 px-6 py-3 bg-primary text-primary-foreground rounded-lg hover:bg-primary/90 transition-all duration-200 hover:scale-105 font-bold shadow-lg\"\n >\n {tr(\"export.create.actions.next\", \"Next\")}\n <ArrowRight size={18} />\n </button>\n )}\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"CreateExportPage.js","names":[],"sources":["../../../src/export/pages/CreateExportPage.tsx"],"sourcesContent":["import { useState, useEffect, useRef } from \"react\";\nimport { useSearchParams } from \"react-router-dom\";\nimport {\n ArrowLeft,\n ArrowRight,\n Download,\n CheckCircle2,\n Loader2,\n FileSpreadsheet,\n FileJson,\n Package,\n CalendarRange,\n User,\n Users,\n Building2,\n Lock,\n} from \"lucide-react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport { usePermission } from \"@burdenoff/fe-libs/shared/providers/shell\";\nimport { useExport } from \"../providers/ExportProvider\";\nimport {\n useCreateExportJob,\n useAvailableEntities,\n useExportTemplates,\n} from \"../hooks/useExportQueries\";\nimport { getFormatDisplayName } from \"../constants/enums\";\nimport { PageLayout } from \"../components/PageLayout\";\nimport { cn } from \"../utils/cn\";\nimport { isExportEntityDisabled } from \"../utils/disabledModules\";\nimport type {\n ExportAvailableEntity,\n ExportFormat,\n ExportScope,\n} from \"../types\";\nimport { tWithFallback } from \"../utils/i18n\";\n\ntype WizardStep = \"entities\" | \"options\" | \"review\";\n\n// Backend only supports CSV and JSON\nconst SUPPORTED_FORMATS: ExportFormat[] = [\"CSV\", \"JSON\"];\n\nconst FORMAT_ICONS: Record<ExportFormat, typeof FileJson> = {\n CSV: FileSpreadsheet,\n JSON: FileJson,\n};\n\n/**\n * Create Export Page\n * Multi-step form: select entities, configure options, review & start\n */\nconst SCOPE_OPTIONS: Array<{\n value: ExportScope;\n label: string;\n description: string;\n Icon: typeof User;\n}> = [\n {\n value: \"INDIVIDUAL\",\n label: \"My Data Only\",\n description: \"Export data you personally created across selected modules.\",\n Icon: User,\n },\n {\n value: \"WORKSPACE_ADMIN\",\n label: \"All Workspace Data\",\n description:\n \"Export all data in this workspace regardless of who created it. Requires workspace admin access.\",\n Icon: Users,\n },\n {\n value: \"ORG_ADMIN\",\n label: \"All Organization Data\",\n description:\n \"Export data from every workspace in your organization. Requires org-admin access.\",\n Icon: Building2,\n },\n];\n\nexport function CreateExportPage() {\n const { basePath = \"/\", navigate, organizationId } = 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 { createJob, isPending } = useCreateExportJob();\n const { data: availableEntities } = useAvailableEntities();\n const { data: templates } = useExportTemplates();\n const [searchParams] = useSearchParams();\n\n // RBAC: Check permissions for admin scopes\n const canExportWorkspaceAdmin = usePermission(\"export:workspace:admin\");\n const canExportOrgAdmin = usePermission(\"export:org:admin\");\n\n const [step, setStep] = useState<WizardStep>(\"entities\");\n const [selectedEntities, setSelectedEntities] = useState<string[]>([]);\n const [exportName, setExportName] = useState(\"\");\n const [selectedFormat, setSelectedFormat] = useState<ExportFormat>(\"CSV\");\n const [selectedScope, setSelectedScope] = useState<ExportScope>(\"INDIVIDUAL\");\n const [selectedTemplateId, setSelectedTemplateId] = useState<\n string | undefined\n >(searchParams.get(\"templateId\") ?? undefined);\n const [dateRangeStart, setDateRangeStart] = useState(\"\");\n const [dateRangeEnd, setDateRangeEnd] = useState(\"\");\n const [error, setError] = useState<string | null>(null);\n\n // Pre-populate form when arriving from \"Use Template\" — apply only once per templateId\n const appliedTemplateRef = useRef<string | null>(null);\n useEffect(() => {\n const paramTemplateId = searchParams.get(\"templateId\");\n if (!paramTemplateId || !templates?.length) return;\n if (appliedTemplateRef.current === paramTemplateId) return;\n const tpl = templates.find((t) => t.id === paramTemplateId);\n if (!tpl) return;\n appliedTemplateRef.current = paramTemplateId;\n setSelectedTemplateId(tpl.id);\n // Skip entity types whose product export is currently disabled.\n setSelectedEntities(\n (tpl.entityTypes ?? []).filter((et) => !isExportEntityDisabled(et)),\n );\n const normalizedFormat = tpl.format?.toUpperCase() as\n | ExportFormat\n | undefined;\n if (normalizedFormat && SUPPORTED_FORMATS.includes(normalizedFormat)) {\n setSelectedFormat(normalizedFormat);\n }\n if (tpl.name) setExportName(tpl.name);\n }, [searchParams, templates]);\n\n const handleBack = () => {\n if (step === \"options\") setStep(\"entities\");\n else if (step === \"review\") setStep(\"options\");\n else navigate?.(basePath);\n };\n\n const handleNext = () => {\n if (step === \"entities\") {\n if (selectedEntities.length === 0) {\n setError(\n tr(\n \"export.create.errors.selectEntity\",\n \"Please select at least one entity type to export\",\n ),\n );\n return;\n }\n setError(null);\n setStep(\"options\");\n } else if (step === \"options\") {\n if (!exportName.trim()) {\n setError(\n tr(\n \"export.create.errors.exportNameRequired\",\n \"Please provide a name for this export\",\n ),\n );\n return;\n }\n setError(null);\n setStep(\"review\");\n }\n };\n\n const handleSubmit = async () => {\n try {\n setError(null);\n await createJob({\n name: exportName,\n entityTypes: selectedEntities,\n format: selectedFormat,\n exportScope: selectedScope,\n organizationId:\n selectedScope === \"ORG_ADMIN\" ? organizationId : undefined,\n templateId: selectedTemplateId,\n dateRangeStart: dateRangeStart\n ? new Date(dateRangeStart).toISOString()\n : null,\n dateRangeEnd: dateRangeEnd\n ? new Date(dateRangeEnd).toISOString()\n : null,\n });\n navigate?.(basePath);\n } catch (err) {\n setError(\n err instanceof Error\n ? err.message\n : tr(\"export.create.errors.createFailed\", \"Failed to create export\"),\n );\n }\n };\n\n const toggleEntity = (entityType: string) => {\n // Disabled-product entities can't be selected.\n if (isExportEntityDisabled(entityType)) return;\n setSelectedEntities((prev) =>\n prev.includes(entityType)\n ? prev.filter((e) => e !== entityType)\n : [...prev, entityType],\n );\n };\n\n const getScopeLabel = (scope: ExportScope) => {\n switch (scope) {\n case \"INDIVIDUAL\":\n return tr(\"export.create.scope.individual.label\", \"My Data Only\");\n case \"WORKSPACE_ADMIN\":\n return tr(\n \"export.create.scope.workspaceAdmin.label\",\n \"All Workspace Data\",\n );\n case \"ORG_ADMIN\":\n return tr(\n \"export.create.scope.orgAdmin.label\",\n \"All Organization Data\",\n );\n default:\n return scope;\n }\n };\n\n const getScopeDescription = (scope: ExportScope) => {\n switch (scope) {\n case \"INDIVIDUAL\":\n return tr(\n \"export.create.scope.individual.description\",\n \"Export data you personally created across selected modules.\",\n );\n case \"WORKSPACE_ADMIN\":\n return tr(\n \"export.create.scope.workspaceAdmin.description\",\n \"Export all data in this workspace regardless of who created it. Requires workspace admin access.\",\n );\n case \"ORG_ADMIN\":\n return tr(\n \"export.create.scope.orgAdmin.description\",\n \"Export data from every workspace in your organization. Requires org-admin access.\",\n );\n default:\n return \"\";\n }\n };\n\n const fallbackEntityCopy: Record<\n string,\n { label: string; description: string }\n > = {\n users: {\n label: tr(\"export.create.entities.users.label\", \"Users\"),\n description: tr(\n \"export.create.entities.users.description\",\n \"Workspace members and profiles\",\n ),\n },\n projects: {\n label: tr(\"export.create.entities.projects.label\", \"Projects\"),\n description: tr(\n \"export.create.entities.projects.description\",\n \"Projects and their metadata\",\n ),\n },\n tasks: {\n label: tr(\"export.create.entities.tasks.label\", \"Tasks\"),\n description: tr(\n \"export.create.entities.tasks.description\",\n \"Task items and assignments\",\n ),\n },\n files: {\n label: tr(\"export.create.entities.files.label\", \"Files\"),\n description: tr(\n \"export.create.entities.files.description\",\n \"File metadata and references\",\n ),\n },\n conversations: {\n label: tr(\"export.create.entities.conversations.label\", \"Conversations\"),\n description: tr(\n \"export.create.entities.conversations.description\",\n \"Chat messages and threads\",\n ),\n },\n tags: {\n label: tr(\"export.create.entities.tags.label\", \"Tags\"),\n description: tr(\n \"export.create.entities.tags.description\",\n \"Tags and vocabularies\",\n ),\n },\n activity: {\n label: tr(\"export.create.entities.activity.label\", \"Activity Logs\"),\n description: tr(\n \"export.create.entities.activity.description\",\n \"Audit trail and activity history\",\n ),\n },\n calendar: {\n label: tr(\"export.create.entities.calendar.label\", \"Calendar Events\"),\n description: tr(\n \"export.create.entities.calendar.description\",\n \"Events and bookings\",\n ),\n },\n };\n\n // Entities the backend marks available, split so the ones a user can export\n // show first and disabled-product entities are listed (still visible) below.\n const visibleEntities = availableEntities.filter((e) => e.enabled !== false);\n const availableForExport = visibleEntities.filter(\n (e) => !isExportEntityDisabled(e.entityType),\n );\n const unavailableForExport = visibleEntities.filter((e) =>\n isExportEntityDisabled(e.entityType),\n );\n\n const renderEntityCard = (\n entity: ExportAvailableEntity,\n isDisabled: boolean,\n ) => {\n const isSelected =\n !isDisabled && selectedEntities.includes(entity.entityType);\n return (\n <button\n type=\"button\"\n key={entity.entityType}\n onClick={() => toggleEntity(entity.entityType)}\n disabled={isDisabled}\n aria-disabled={isDisabled}\n title={\n isDisabled\n ? tr(\n \"export.create.select.unavailableHint\",\n \"Export for this product isn't available yet\",\n )\n : undefined\n }\n className={cn(\n \"text-left border-2 rounded-xl p-4 transition-all duration-200\",\n isDisabled\n ? \"border-border-subtle/30 opacity-50 cursor-not-allowed\"\n : isSelected\n ? \"border-primary bg-action-primary-bg/5 shadow-md\"\n : \"border-border-subtle/50 hover:border-primary/30 hover:shadow-sm\",\n )}\n >\n <div className=\"flex items-center justify-between mb-2 gap-2\">\n <h3 className=\"font-semibold\">\n {fallbackEntityCopy[entity.entityType]?.label ?? entity.displayName}\n </h3>\n {isDisabled ? (\n <span className=\"shrink-0 text-xs font-medium px-2 py-0.5 rounded-full bg-bg-sunken text-text-secondary\">\n {tr(\"export.create.select.unavailable\", \"Unavailable\")}\n </span>\n ) : (\n isSelected && <CheckCircle2 size={18} className=\"text-primary\" />\n )}\n </div>\n <p className=\"text-sm text-text-secondary\">\n {fallbackEntityCopy[entity.entityType]?.description ??\n entity.description}\n </p>\n {entity.estimatedSize && (\n <p className=\"text-xs text-text-secondary mt-2\">\n ~{entity.estimatedSize}\n </p>\n )}\n </button>\n );\n };\n\n return (\n <PageLayout showHeader={false}>\n {/* Header */}\n <div className=\"relative overflow-hidden rounded-xl bg-gradient-to-br from-primary/5 via-primary/3 to-background border border-border-subtle/50 p-6 shadow-sm\">\n <div className=\"relative z-10 flex items-center gap-4\">\n <button\n type=\"button\"\n onClick={() => navigate?.(basePath)}\n className=\"p-2.5 hover:bg-accent rounded-lg transition-all duration-200\"\n aria-label={tr(\n \"export.create.actions.backToDashboard\",\n \"Back to export dashboard\",\n )}\n >\n <ArrowLeft size={20} />\n </button>\n <div className=\"flex items-center gap-3\">\n <div className=\"p-2.5 rounded-lg bg-action-primary-bg/10 backdrop-blur-sm\">\n <Download size={24} className=\"text-primary\" />\n </div>\n <h1 className=\"text-2xl sm:text-3xl font-bold\">\n {tr(\"export.create.title\", \"New Export\")}\n </h1>\n </div>\n </div>\n </div>\n\n {/* Step Indicator */}\n <div className=\"flex items-center gap-2 justify-center flex-wrap\">\n {([\"entities\", \"options\", \"review\"] as WizardStep[]).map((s, i) => (\n <div key={s} className=\"flex items-center gap-2\">\n {i > 0 && (\n <ArrowRight size={18} className=\"text-text-secondary\" />\n )}\n <div\n className={cn(\n \"flex items-center gap-2 px-4 py-2.5 rounded-lg text-sm font-medium border-2 transition-all duration-200\",\n step === s\n ? \"bg-action-primary-bg text-action-primary-text border-primary shadow-md scale-105\"\n : \"bg-bg-sunken/50 text-text-secondary border-border-subtle/50\",\n )}\n >\n <div className=\"flex items-center justify-center size-6 rounded-full bg-bg-surface/20 font-bold\">\n {i + 1}\n </div>\n <span className=\"hidden sm:inline capitalize\">\n {s === \"entities\"\n ? tr(\"export.create.steps.entities\", \"Select Data\")\n : s === \"options\"\n ? tr(\"export.create.steps.options\", \"Options\")\n : tr(\"export.create.steps.review\", \"Review\")}\n </span>\n </div>\n </div>\n ))}\n </div>\n\n {/* Error */}\n {error && (\n <div className=\"border-2 border-border-default rounded-xl bg-status-error-bg-subtle p-4 text-status-error-text text-sm\">\n {error}\n </div>\n )}\n\n {/* Step 1: Select Entities */}\n {step === \"entities\" && (\n <div className=\"space-y-4\">\n <h2 className=\"text-lg font-bold\">\n {tr(\"export.create.select.title\", \"Select data to export\")}\n </h2>\n <p className=\"text-sm text-text-secondary\">\n {tr(\n \"export.create.select.description\",\n \"Choose which entity types to include in your export.\",\n )}\n </p>\n {visibleEntities.length === 0 ? (\n <div className=\"border-2 border-border-subtle rounded-xl bg-bg-sunken/30 p-6 text-sm text-text-secondary\">\n {tr(\n \"export.create.select.empty\",\n \"No exportable entity types are configured for this workspace yet.\",\n )}\n </div>\n ) : (\n <div className=\"space-y-6\">\n {availableForExport.length > 0 && (\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3\">\n {availableForExport.map((entity) =>\n renderEntityCard(entity, false),\n )}\n </div>\n )}\n {unavailableForExport.length > 0 && (\n <div className=\"space-y-3\">\n <div className=\"flex items-center gap-3\">\n <div className=\"h-px flex-1 bg-border/60\" />\n <span className=\"text-xs font-medium uppercase tracking-wide text-text-secondary\">\n {tr(\n \"export.create.select.unavailableSection\",\n \"Not available yet\",\n )}\n </span>\n <div className=\"h-px flex-1 bg-border/60\" />\n </div>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3\">\n {unavailableForExport.map((entity) =>\n renderEntityCard(entity, true),\n )}\n </div>\n </div>\n )}\n </div>\n )}\n </div>\n )}\n\n {/* Step 2: Configure Options */}\n {step === \"options\" && (\n <div className=\"space-y-6\">\n <div className=\"border-2 border-border-subtle/50 rounded-xl p-6 space-y-5\">\n <h2 className=\"text-lg font-bold\">\n {tr(\"export.create.options.title\", \"Export Options\")}\n </h2>\n\n {/* Scope selection */}\n <div>\n <label className=\"block text-sm font-semibold mb-2\">\n {tr(\"export.create.options.scope\", \"Export Scope\")}\n </label>\n <div className=\"grid grid-cols-1 sm:grid-cols-3 gap-3\">\n {SCOPE_OPTIONS.map(({ value, Icon }) => {\n // RBAC: Disable admin scopes if user lacks permission\n const isDisabled =\n (value === \"WORKSPACE_ADMIN\" && !canExportWorkspaceAdmin) ||\n (value === \"ORG_ADMIN\" && !canExportOrgAdmin);\n\n return (\n <button\n key={value}\n type=\"button\"\n onClick={() => !isDisabled && setSelectedScope(value)}\n disabled={isDisabled}\n className={cn(\n \"text-left border-2 rounded-xl p-4 transition-all duration-200\",\n selectedScope === value\n ? \"border-primary bg-action-primary-bg/5 shadow-md\"\n : isDisabled\n ? \"border-border-subtle/30 opacity-50 cursor-not-allowed\"\n : \"border-border-subtle/50 hover:border-primary/30 hover:shadow-sm\",\n )}\n title={\n isDisabled\n ? value === \"WORKSPACE_ADMIN\"\n ? \"Workspace admin access required\"\n : \"Organization admin access required\"\n : undefined\n }\n >\n <div className=\"flex items-center justify-between mb-2\">\n <Icon\n size={18}\n className={\n selectedScope === value\n ? \"text-primary\"\n : isDisabled\n ? \"text-text-secondary/50\"\n : \"text-text-secondary\"\n }\n />\n {selectedScope === value && (\n <CheckCircle2 size={16} className=\"text-primary\" />\n )}\n {isDisabled && (\n <Lock\n size={14}\n className=\"text-text-secondary/50\"\n />\n )}\n </div>\n <p className=\"font-semibold text-sm\">\n {getScopeLabel(value)}\n </p>\n <p className=\"text-xs text-text-secondary mt-1\">\n {getScopeDescription(value)}\n </p>\n </button>\n );\n })}\n </div>\n </div>\n\n {/* Name */}\n <div>\n <label\n htmlFor=\"exportName\"\n className=\"block text-sm font-semibold mb-2\"\n >\n {tr(\"export.create.options.name\", \"Export Name\")}{\" \"}\n <span className=\"text-status-error-text\">*</span>\n </label>\n <input\n type=\"text\"\n id=\"exportName\"\n aria-label={tr(\"export.create.options.name\", \"Export Name\")}\n value={exportName}\n onChange={(e) => setExportName(e.target.value)}\n className=\"w-full px-4 py-2.5 border-2 border-border-subtle rounded-lg bg-bg-surface focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary transition-all duration-200\"\n placeholder={tr(\n \"export.create.options.namePlaceholder\",\n \"e.g., Monthly User Export\",\n )}\n />\n </div>\n\n {/* Format — only CSV and JSON are supported */}\n <div>\n <label className=\"block text-sm font-semibold mb-2\">\n {tr(\"export.create.options.outputFormat\", \"Output Format\")}\n </label>\n <div className=\"grid grid-cols-2 gap-3\">\n {SUPPORTED_FORMATS.map((format) => {\n const Icon = FORMAT_ICONS[format];\n return (\n <button\n type=\"button\"\n key={format}\n onClick={() => setSelectedFormat(format)}\n className={cn(\n \"flex items-center gap-3 border-2 rounded-lg p-3 transition-all duration-200\",\n selectedFormat === format\n ? \"border-primary bg-action-primary-bg/5\"\n : \"border-border-subtle/50 hover:border-primary/30\",\n )}\n >\n <Icon\n size={18}\n className={\n selectedFormat === format\n ? \"text-primary\"\n : \"text-text-secondary\"\n }\n />\n <span className=\"font-medium text-sm\">\n {getFormatDisplayName(format)}\n </span>\n </button>\n );\n })}\n </div>\n </div>\n\n {/* Archive format — only ZIP is supported */}\n <div>\n <label className=\"block text-sm font-semibold mb-2\">\n {tr(\"export.create.options.archiveFormat\", \"Archive Format\")}\n </label>\n <div className=\"flex gap-3\">\n <div\n className={cn(\n \"flex items-center gap-2 border-2 rounded-lg px-4 py-2 border-primary bg-action-primary-bg/5\",\n )}\n >\n <Package size={16} className=\"text-primary\" />\n <span className=\"font-medium text-sm\">ZIP</span>\n </div>\n </div>\n <p className=\"text-xs text-text-secondary mt-1.5\">\n {tr(\n \"export.create.options.archiveDescription\",\n \"Exports are packaged as ZIP archives.\",\n )}\n </p>\n </div>\n\n {/* Date range filter — always visible */}\n <div>\n <label className=\"block text-sm font-semibold mb-2\">\n <span className=\"inline-flex items-center gap-1.5\">\n <CalendarRange size={15} />\n {tr(\"export.create.options.dateRange\", \"Date Range\")}{\" \"}\n <span className=\"font-normal text-text-secondary\">\n {tr(\"export.create.shared.optional\", \"(optional)\")}\n </span>\n </span>\n </label>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-3\">\n <div>\n <label\n htmlFor=\"dateFrom\"\n className=\"block text-xs text-text-secondary mb-1\"\n >\n {tr(\"export.create.options.dateFrom\", \"From\")}\n </label>\n <input\n type=\"date\"\n id=\"dateFrom\"\n aria-label={tr(\"export.create.options.dateFrom\", \"From\")}\n value={dateRangeStart}\n onChange={(e) => setDateRangeStart(e.target.value)}\n className=\"w-full px-3 py-2 border-2 border-border-subtle rounded-lg bg-bg-surface focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary text-sm\"\n />\n </div>\n <div>\n <label\n htmlFor=\"dateTo\"\n className=\"block text-xs text-text-secondary mb-1\"\n >\n {tr(\"export.create.options.dateTo\", \"To\")}\n </label>\n <input\n type=\"date\"\n id=\"dateTo\"\n aria-label={tr(\"export.create.options.dateTo\", \"To\")}\n value={dateRangeEnd}\n min={dateRangeStart}\n onChange={(e) => setDateRangeEnd(e.target.value)}\n className=\"w-full px-3 py-2 border-2 border-border-subtle rounded-lg bg-bg-surface focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary text-sm\"\n />\n </div>\n </div>\n <p className=\"text-xs text-text-secondary mt-1.5\">\n {tr(\n \"export.create.options.dateRangeDescription\",\n \"Leave blank to export all data regardless of date.\",\n )}\n </p>\n </div>\n\n {/* Optional: Use a template */}\n <div>\n <label className=\"block text-sm font-semibold mb-2\">\n {tr(\n \"export.create.options.basedOnTemplate\",\n \"Based on Template\",\n )}{\" \"}\n <span className=\"font-normal text-text-secondary\">\n {tr(\"export.create.shared.optional\", \"(optional)\")}\n </span>\n </label>\n {templates.length > 0 ? (\n <select\n value={selectedTemplateId ?? \"\"}\n onChange={(e) =>\n setSelectedTemplateId(e.target.value || undefined)\n }\n className=\"w-full px-3 py-2 border-2 border-border-subtle rounded-lg bg-bg-surface focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary\"\n >\n <option value=\"\">\n {tr(\"export.create.options.noTemplate\", \"No template\")}\n </option>\n {templates.map((t) => (\n <option key={t.id} value={t.id}>\n {t.name}\n </option>\n ))}\n </select>\n ) : (\n <p className=\"text-sm text-text-secondary\">\n {tr(\"export.create.options.noTemplates\", \"No templates yet.\")}{\" \"}\n <button\n type=\"button\"\n onClick={() => navigate?.(basePath + \"/templates\")}\n className=\"text-primary underline-offset-2 hover:underline\"\n >\n {tr(\n \"export.create.options.createTemplateLink\",\n \"Create one\",\n )}\n </button>{\" \"}\n {tr(\n \"export.create.options.reuseTemplateHint\",\n \"to reuse export configurations.\",\n )}\n </p>\n )}\n </div>\n </div>\n </div>\n )}\n\n {/* Step 3: Review */}\n {step === \"review\" && (\n <div className=\"space-y-6\">\n <div className=\"border-2 border-primary/50 rounded-xl bg-action-primary-bg/5 p-6 space-y-4\">\n <h2 className=\"text-lg font-bold flex items-center gap-2\">\n <CheckCircle2 size={20} className=\"text-primary\" />\n {tr(\"export.create.review.title\", \"Review Export\")}\n </h2>\n <dl className=\"space-y-3 text-sm\">\n {[\n {\n label: tr(\"export.create.review.fields.name\", \"Name\"),\n value: exportName,\n },\n {\n label: tr(\"export.create.review.fields.scope\", \"Scope\"),\n value: getScopeLabel(selectedScope),\n },\n {\n label: tr(\n \"export.create.review.fields.entityTypes\",\n \"Entity Types\",\n ),\n value: selectedEntities.join(\", \"),\n },\n {\n label: tr(\"export.create.review.fields.format\", \"Format\"),\n value: getFormatDisplayName(selectedFormat),\n },\n {\n label: tr(\"export.create.review.fields.archive\", \"Archive\"),\n value: \"ZIP\",\n },\n ...(dateRangeStart || dateRangeEnd\n ? [\n {\n label: tr(\n \"export.create.review.fields.dateRange\",\n \"Date Range\",\n ),\n value: [\n dateRangeStart || \"—\",\n dateRangeEnd || \"—\",\n ].join(\" → \"),\n },\n ]\n : []),\n ...(selectedTemplateId\n ? [\n {\n label: tr(\n \"export.create.review.fields.template\",\n \"Template\",\n ),\n value:\n templates.find((t) => t.id === selectedTemplateId)\n ?.name ?? selectedTemplateId,\n },\n ]\n : []),\n ].map(({ label, value }) => (\n <div\n key={label}\n className=\"flex flex-col sm:flex-row sm:justify-between gap-1\"\n >\n <dt className=\"text-text-secondary\">{label}</dt>\n <dd className=\"font-semibold sm:text-right break-words\">\n {value}\n </dd>\n </div>\n ))}\n </dl>\n </div>\n </div>\n )}\n\n {/* Actions */}\n <div className=\"flex flex-col sm:flex-row gap-3 pt-2\">\n <button\n type=\"button\"\n onClick={handleBack}\n className=\"px-6 py-3 border-2 border-border-subtle/50 rounded-lg hover:bg-accent hover:border-primary/30 transition-all duration-200 font-medium\"\n >\n {step === \"entities\"\n ? tr(\"export.create.actions.cancel\", \"Cancel\")\n : tr(\"export.create.actions.back\", \"Back\")}\n </button>\n {step === \"review\" ? (\n <button\n type=\"button\"\n onClick={handleSubmit}\n disabled={isPending}\n className=\"flex-1 inline-flex items-center justify-center gap-2 px-6 py-3 bg-action-primary-bg text-action-primary-text rounded-lg hover:bg-action-primary-bg/90 transition-all duration-200 font-bold shadow-lg disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n {isPending ? (\n <Loader2 size={18} className=\"animate-spin\" />\n ) : (\n <Download size={18} />\n )}\n {tr(\"export.create.actions.startExport\", \"Start Export\")}\n </button>\n ) : (\n <button\n type=\"button\"\n onClick={handleNext}\n className=\"flex-1 inline-flex items-center justify-center gap-2 px-6 py-3 bg-action-primary-bg text-action-primary-text rounded-lg hover:bg-action-primary-bg/90 transition-all duration-200 font-bold shadow-lg\"\n >\n {tr(\"export.create.actions.next\", \"Next\")}\n <ArrowRight size={18} />\n </button>\n )}\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
@@ -28,7 +28,7 @@ function y() {
28
28
  label: S("export.dashboard.actions.newExport.label", "New Export"),
29
29
  description: S("export.dashboard.actions.newExport.description", "Create a new data export"),
30
30
  path: "new",
31
- color: "bg-primary/10 text-primary"
31
+ color: "bg-action-primary-bg/10 text-primary"
32
32
  },
33
33
  {
34
34
  icon: /* @__PURE__ */ h(d, { size: 20 }),
@@ -54,23 +54,23 @@ function y() {
54
54
  ].map((e) => /* @__PURE__ */ g("button", {
55
55
  type: "button",
56
56
  onClick: () => D(e.path),
57
- className: n("group relative overflow-hidden border-2 border-border/50 rounded-xl p-5", "bg-gradient-to-br from-card/50 to-background shadow-sm", "hover:shadow-md hover:border-primary/30 transition-all duration-200", "text-left"),
57
+ className: n("group relative overflow-hidden border-2 border-border-subtle/50 rounded-xl p-5", "bg-gradient-to-br from-card/50 to-background shadow-sm", "hover:shadow-md hover:border-primary/30 transition-all duration-200", "text-left"),
58
58
  children: [
59
59
  /* @__PURE__ */ h("div", {
60
60
  className: n("p-2.5 rounded-lg w-fit mb-3", e.color),
61
61
  children: e.icon
62
62
  }),
63
63
  /* @__PURE__ */ h("h3", {
64
- className: "font-semibold text-foreground mb-1",
64
+ className: "font-semibold text-text-primary mb-1",
65
65
  children: e.label
66
66
  }),
67
67
  /* @__PURE__ */ h("p", {
68
- className: "text-sm text-muted-foreground",
68
+ className: "text-sm text-text-secondary",
69
69
  children: e.description
70
70
  }),
71
71
  /* @__PURE__ */ h(u, {
72
72
  size: 16,
73
- className: "absolute top-5 right-5 text-muted-foreground opacity-0 group-hover:opacity-100 transition-opacity"
73
+ className: "absolute top-5 right-5 text-text-secondary opacity-0 group-hover:opacity-100 transition-opacity"
74
74
  })
75
75
  ]
76
76
  }, e.path + e.label))
@@ -84,11 +84,11 @@ function y() {
84
84
  children: E.map((e) => /* @__PURE__ */ g("button", {
85
85
  type: "button",
86
86
  onClick: () => D(e.id),
87
- className: n("w-full text-left border-2 border-border/50 rounded-xl p-4", "hover:shadow-md hover:border-primary/30 transition-all duration-200", "bg-gradient-to-r from-card/50 to-background"),
87
+ className: n("w-full text-left border-2 border-border-subtle/50 rounded-xl p-4", "hover:shadow-md hover:border-primary/30 transition-all duration-200", "bg-gradient-to-r from-card/50 to-background"),
88
88
  children: [/* @__PURE__ */ g("div", {
89
89
  className: "flex items-center justify-between mb-2",
90
90
  children: [/* @__PURE__ */ h("h4", {
91
- className: "font-semibold text-foreground",
91
+ className: "font-semibold text-text-primary",
92
92
  children: e.name
93
93
  }), /* @__PURE__ */ h(i, { status: e.status })]
94
94
  }), /* @__PURE__ */ h(a, {
@@ -115,28 +115,28 @@ function y() {
115
115
  ,
116
116
  ,
117
117
  ]].map((e, t) => /* @__PURE__ */ g("div", {
118
- className: "border-2 border-border/50 rounded-xl p-4 animate-pulse",
118
+ className: "border-2 border-border-subtle/50 rounded-xl p-4 animate-pulse",
119
119
  children: [/* @__PURE__ */ g("div", {
120
120
  className: "flex items-center justify-between mb-2",
121
- children: [/* @__PURE__ */ h("div", { className: "h-4 w-48 bg-muted rounded" }), /* @__PURE__ */ h("div", { className: "h-5 w-20 bg-muted rounded-full" })]
122
- }), /* @__PURE__ */ h("div", { className: "h-3 w-32 bg-muted rounded mt-2" })]
121
+ children: [/* @__PURE__ */ h("div", { className: "h-4 w-48 bg-bg-sunken rounded" }), /* @__PURE__ */ h("div", { className: "h-5 w-20 bg-bg-sunken rounded-full" })]
122
+ }), /* @__PURE__ */ h("div", { className: "h-3 w-32 bg-bg-sunken rounded mt-2" })]
123
123
  }, t))
124
124
  }) : T.length > 0 ? /* @__PURE__ */ h("div", {
125
125
  className: "space-y-3",
126
126
  children: T.map((e, t) => /* @__PURE__ */ h("button", {
127
127
  type: "button",
128
128
  onClick: () => D(e.id),
129
- className: n("w-full text-left border-2 border-border/50 rounded-xl p-4", "hover:shadow-md hover:border-primary/30 transition-all duration-200", "bg-gradient-to-r from-card/50 to-background", "animate-in fade-in-0 slide-in-from-bottom-2"),
129
+ className: n("w-full text-left border-2 border-border-subtle/50 rounded-xl p-4", "hover:shadow-md hover:border-primary/30 transition-all duration-200", "bg-gradient-to-r from-card/50 to-background", "animate-in fade-in-0 slide-in-from-bottom-2"),
130
130
  style: { animationDelay: `${t * 50}ms` },
131
131
  children: /* @__PURE__ */ g("div", {
132
132
  className: "flex items-start sm:items-center justify-between gap-3",
133
133
  children: [/* @__PURE__ */ g("div", {
134
134
  className: "flex-1 min-w-0",
135
135
  children: [/* @__PURE__ */ h("h4", {
136
- className: "font-semibold text-foreground truncate",
136
+ className: "font-semibold text-text-primary truncate",
137
137
  children: e.name
138
138
  }), /* @__PURE__ */ g("p", {
139
- className: "text-sm text-muted-foreground mt-1 line-clamp-2",
139
+ className: "text-sm text-text-secondary mt-1 line-clamp-2",
140
140
  children: [
141
141
  e.entityTypes.join(", "),
142
142
  " · ",
@@ -148,7 +148,7 @@ function y() {
148
148
  className: "flex items-center gap-2 flex-shrink-0",
149
149
  children: [/* @__PURE__ */ h(i, { status: e.status }), /* @__PURE__ */ h(u, {
150
150
  size: 16,
151
- className: "text-muted-foreground hidden sm:block"
151
+ className: "text-text-secondary hidden sm:block"
152
152
  })]
153
153
  })]
154
154
  })
@@ -160,7 +160,7 @@ function y() {
160
160
  action: /* @__PURE__ */ g("button", {
161
161
  type: "button",
162
162
  onClick: () => D("new"),
163
- className: "inline-flex items-center gap-2 px-4 py-2 bg-primary text-primary-foreground rounded-lg hover:bg-primary/90 transition-colors font-medium",
163
+ 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",
164
164
  children: [/* @__PURE__ */ h(m, { size: 16 }), S("export.dashboard.empty.actions.createFirst", "Create First Export")]
165
165
  })
166
166
  })
@@ -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} from \"lucide-react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\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\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 {/* 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-primary/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-2 border-border/50 rounded-xl p-5\",\n \"bg-gradient-to-br from-card/50 to-background shadow-sm\",\n \"hover:shadow-md hover:border-primary/30 transition-all duration-200\",\n \"text-left\",\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-foreground mb-1\">\n {action.label}\n </h3>\n <p className=\"text-sm text-muted-foreground\">\n {action.description}\n </p>\n <ArrowRight\n size={16}\n className=\"absolute top-5 right-5 text-muted-foreground opacity-0 group-hover:opacity-100 transition-opacity\"\n />\n </button>\n ))}\n </div>\n\n {/* Active Exports */}\n {activeJobs.length > 0 && (\n <PageSection\n data-tour=\"export-dashboard-active-section\"\n title={tr(\"export.dashboard.active.title\", \"Active Exports\")}\n description={tr(\n \"export.dashboard.active.description\",\n \"Currently running export jobs\",\n )}\n >\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-2 border-border/50 rounded-xl p-4\",\n \"hover:shadow-md hover:border-primary/30 transition-all duration-200\",\n \"bg-gradient-to-r from-card/50 to-background\",\n )}\n >\n <div className=\"flex items-center justify-between mb-2\">\n <h4 className=\"font-semibold text-foreground\">{job.name}</h4>\n <ExportStatusBadge status={job.status} />\n </div>\n <ExportProgressBar progress={job.progress} size=\"sm\" />\n </button>\n ))}\n </div>\n </PageSection>\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-2 border-border/50 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-muted rounded\" />\n <div className=\"h-5 w-20 bg-muted rounded-full\" />\n </div>\n <div className=\"h-3 w-32 bg-muted 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-2 border-border/50 rounded-xl p-4\",\n \"hover:shadow-md hover:border-primary/30 transition-all duration-200\",\n \"bg-gradient-to-r from-card/50 to-background\",\n \"animate-in fade-in-0 slide-in-from-bottom-2\",\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-foreground truncate\">\n {job.name}\n </h4>\n <p className=\"text-sm text-muted-foreground 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-muted-foreground 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-primary text-primary-foreground rounded-lg hover:bg-primary/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} from \"lucide-react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\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\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 {/* 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-2 border-border-subtle/50 rounded-xl p-5\",\n \"bg-gradient-to-br from-card/50 to-background shadow-sm\",\n \"hover:shadow-md hover:border-primary/30 transition-all duration-200\",\n \"text-left\",\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 */}\n {activeJobs.length > 0 && (\n <PageSection\n data-tour=\"export-dashboard-active-section\"\n title={tr(\"export.dashboard.active.title\", \"Active Exports\")}\n description={tr(\n \"export.dashboard.active.description\",\n \"Currently running export jobs\",\n )}\n >\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-2 border-border-subtle/50 rounded-xl p-4\",\n \"hover:shadow-md hover:border-primary/30 transition-all duration-200\",\n \"bg-gradient-to-r from-card/50 to-background\",\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 </PageSection>\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-2 border-border-subtle/50 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-2 border-border-subtle/50 rounded-xl p-4\",\n \"hover:shadow-md hover:border-primary/30 transition-all duration-200\",\n \"bg-gradient-to-r from-card/50 to-background\",\n \"animate-in fade-in-0 slide-in-from-bottom-2\",\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":";;;;;;;;;;;AAoBA,IAAM,KAAY,GAAc,OACZ,EAAK,SAAS,IAAI,GAAG,EAAK,MAAM,GAAG,GAAG,GAAG,MACzC,EAAK,WAAW,IAAI,GAAG,IAAO,IAAI;AAQtD,SAAgB,IAAsB;CACpC,IAAM,EAAE,cAAW,KAAK,gBAAa,GAAW,EAC1C,EAAE,SAAM,GAAS,EACjB,KACJ,GACA,GACA,MACG,EAAc,GAAG,GAAK,GAAU,EAAO,EACtC,EAAE,MAAM,GAAM,iBAAc,EAAc,EAAE,CAAC,EAE7C,IAAa,EAAK,MAAM,GAAG,EAAE,EAC7B,IAAa,EAAK,QACrB,MAAM,EAAE,WAAW,aAAa,EAAE,WAAW,SAC/C,EAEK,KAAkB,MAAiB;AAClC,OACL,EAAS,EAAS,GAAU,EAAK,CAAC;;AAGpC,QACE,kBAAC,GAAD;EACE,OAAO,EAAG,0BAA0B,SAAS;EAC7C,UAAU,EACR,6BACA,iDACD;EACD,MAAM,kBAAC,GAAD,EAAU,MAAM,IAAM,CAAA;YAN9B;GASE,kBAAC,OAAD;IACE,WAAU;IACV,aAAU;cAET;KACC;MACE,MAAM,kBAAC,GAAD,EAAM,MAAM,IAAM,CAAA;MACxB,OAAO,EAAG,4CAA4C,aAAa;MACnE,aAAa,EACX,kDACA,2BACD;MACD,MAAM;MACN,OAAO;MACR;KACD;MACE,MAAM,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA;MACzB,OAAO,EAAG,0CAA0C,UAAU;MAC9D,aAAa,EACX,gDACA,oBACD;MACD,MAAM;MACN,OAAO;MACR;KACD;MACE,MAAM,kBAAC,GAAD,EAAS,MAAM,IAAM,CAAA;MAC3B,OAAO,EAAG,4CAA4C,YAAY;MAClE,aAAa,EACX,kDACA,0BACD;MACD,MAAM;MACN,OAAO;MACR;KACD;MACE,MAAM,kBAAC,GAAD,EAAU,MAAM,IAAM,CAAA;MAC5B,OAAO,EACL,6CACA,cACD;MACD,aAAa,EACX,mDACA,mBACA,EAAE,OAAO,EAAW,QAAQ,CAC7B;MACD,MAAM;MACN,OAAO;MACR;KACF,CAAC,KAAK,MACL,kBAAC,UAAD;KACE,MAAK;KAEL,eAAe,EAAe,EAAO,KAAK;KAC1C,WAAW,EACT,kFACA,0DACA,uEACA,YACD;eATH;MAWE,kBAAC,OAAD;OAAK,WAAW,EAAG,+BAA+B,EAAO,MAAM;iBAC5D,EAAO;OACJ,CAAA;MACN,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAO;OACL,CAAA;MACL,kBAAC,KAAD;OAAG,WAAU;iBACV,EAAO;OACN,CAAA;MACJ,kBAAC,GAAD;OACE,MAAM;OACN,WAAU;OACV,CAAA;MACK;OAtBF,EAAO,OAAO,EAAO,MAsBnB,CACT;IACE,CAAA;GAGL,EAAW,SAAS,KACnB,kBAAC,GAAD;IACE,aAAU;IACV,OAAO,EAAG,iCAAiC,iBAAiB;IAC5D,aAAa,EACX,uCACA,gCACD;cAED,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAW,KAAK,MACf,kBAAC,UAAD;MACE,MAAK;MAEL,eAAe,EAAe,EAAI,GAAG;MACrC,WAAW,EACT,oEACA,uEACA,8CACD;gBARH,CAUE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,MAAD;QAAI,WAAU;kBAAmC,EAAI;QAAU,CAAA,EAC/D,kBAAC,GAAD,EAAmB,QAAQ,EAAI,QAAU,CAAA,CACrC;UACN,kBAAC,GAAD;OAAmB,UAAU,EAAI;OAAU,MAAK;OAAO,CAAA,CAChD;QAbF,EAAI,GAaF,CACT;KACE,CAAA;IACM,CAAA;GAIhB,kBAAC,GAAD;IACE,aAAU;IACV,OAAO,EAAG,iCAAiC,iBAAiB;IAC5D,aAAa,EACX,uCACA,0BACD;IACD,SACE,EAAW,SAAS,IAClB,kBAAC,UAAD;KACE,MAAK;KACL,eAAe,EAAe,UAAU;KACxC,WAAU;eAET,EAAG,2CAA2C,WAAW;KACnD,CAAA,GACP,KAAA;cAGL,IACC,kBAAC,OAAD;KAAK,WAAU;eACZ,CAAC,GAAG;;;;MAAQ,CAAC,CAAC,KAAK,GAAG,MACrB,kBAAC,OAAD;MAEE,WAAU;gBAFZ,CAIE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,OAAD,EAAK,WAAU,iCAAkC,CAAA,EACjD,kBAAC,OAAD,EAAK,WAAU,sCAAuC,CAAA,CAClD;UACN,kBAAC,OAAD,EAAK,WAAU,sCAAuC,CAAA,CAClD;QARC,EAQD,CACN;KACE,CAAA,GACJ,EAAW,SAAS,IACtB,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAW,KAAK,GAAK,MACpB,kBAAC,UAAD;MACE,MAAK;MAEL,eAAe,EAAe,EAAI,GAAG;MACrC,WAAW,EACT,oEACA,uEACA,+CACA,8CACD;MACD,OAAO,EAAE,gBAAgB,GAAG,IAAQ,GAAG,KAAK;gBAE5C,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAI;SACF,CAAA,EACL,kBAAC,KAAD;SAAG,WAAU;mBAAb;UACG,EAAI,YAAY,KAAK,KAAK;UAAC;UAAW,EAAI;UAC1C,EAAI,iBAAiB,QACpB,MAAM,EACJ,yCACA,oBACA,EAAE,OAAO,EAAI,cAAc,gBAAgB,EAAE,CAC9C;UACD;WACA;WACN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,GAAD,EAAmB,QAAQ,EAAI,QAAU,CAAA,EACzC,kBAAC,GAAD;SACE,MAAM;SACN,WAAU;SACV,CAAA,CACE;UACF;;MACC,EAjCF,EAAI,GAiCF,CACT;KACE,CAAA,GAEN,kBAAC,GAAD;KACE,MAAM,kBAAC,GAAD,EAAU,MAAM,IAAM,CAAA;KAC5B,OAAO,EAAG,gCAAgC,iBAAiB;KAC3D,aAAa,EACX,sCACA,qEACD;KACD,QACE,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,EAAe,MAAM;MACpC,WAAU;gBAHZ,CAKE,kBAAC,GAAD,EAAM,MAAM,IAAM,CAAA,EACjB,EACC,8CACA,sBACD,CACM;;KAEX,CAAA;IAEQ,CAAA;GACH"}
@@ -33,14 +33,14 @@ function P() {
33
33
  size: 48,
34
34
  className: "animate-spin text-primary"
35
35
  }), /* @__PURE__ */ A("span", {
36
- className: "mt-6 text-sm font-medium text-muted-foreground",
36
+ className: "mt-6 text-sm font-medium text-text-secondary",
37
37
  children: "Loading export details…"
38
38
  })]
39
39
  }) : X ? /* @__PURE__ */ j(d, {
40
40
  showHeader: !1,
41
41
  children: [
42
42
  /* @__PURE__ */ A("div", {
43
- className: "relative overflow-hidden rounded-xl bg-gradient-to-br from-primary/5 via-primary/3 to-background border border-border/50 p-6 shadow-sm",
43
+ className: "relative overflow-hidden rounded-xl bg-gradient-to-br from-primary/5 via-primary/3 to-background border border-border-subtle/50 p-6 shadow-sm",
44
44
  children: /* @__PURE__ */ j("div", {
45
45
  className: "relative z-10 flex items-center gap-4",
46
46
  children: [/* @__PURE__ */ A("button", {
@@ -52,7 +52,7 @@ function P() {
52
52
  className: "flex items-center gap-3 flex-1",
53
53
  children: [
54
54
  /* @__PURE__ */ A("div", {
55
- className: "p-2.5 rounded-lg bg-primary/10",
55
+ className: "p-2.5 rounded-lg bg-action-primary-bg/10",
56
56
  children: /* @__PURE__ */ A(b, {
57
57
  size: 24,
58
58
  className: "text-primary"
@@ -64,7 +64,7 @@ function P() {
64
64
  className: "text-xl sm:text-2xl font-bold truncate",
65
65
  children: X.name
66
66
  }), /* @__PURE__ */ A("p", {
67
- className: "text-sm text-muted-foreground mt-1",
67
+ className: "text-sm text-text-secondary mt-1",
68
68
  children: X.entityTypes.join(", ")
69
69
  })]
70
70
  }),
@@ -79,7 +79,7 @@ function P() {
79
79
  progress: X.progress,
80
80
  size: "lg"
81
81
  }), X.processedEntities != null && X.totalEntities != null && /* @__PURE__ */ j("p", {
82
- className: "text-sm text-muted-foreground mt-2",
82
+ className: "text-sm text-text-secondary mt-2",
83
83
  children: [
84
84
  X.processedEntities.toLocaleString(),
85
85
  " /",
@@ -126,9 +126,9 @@ function P() {
126
126
  value: new Date(X.createdAt).toLocaleDateString()
127
127
  }
128
128
  ].map((e) => /* @__PURE__ */ j("div", {
129
- className: "border-2 border-border/50 rounded-xl p-4 bg-gradient-to-br from-card/50 to-background",
129
+ className: "border-2 border-border-subtle/50 rounded-xl p-4 bg-gradient-to-br from-card/50 to-background",
130
130
  children: [/* @__PURE__ */ j("div", {
131
- className: "flex items-center gap-2 text-muted-foreground mb-1",
131
+ className: "flex items-center gap-2 text-text-secondary mb-1",
132
132
  children: [e.icon, /* @__PURE__ */ A("span", {
133
133
  className: "text-xs font-medium",
134
134
  children: e.label
@@ -145,7 +145,7 @@ function P() {
145
145
  children: /* @__PURE__ */ A("div", {
146
146
  className: "space-y-2",
147
147
  children: X.parts.map((e) => /* @__PURE__ */ j("div", {
148
- className: o("border-2 border-border/50 rounded-xl p-4 flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3", "hover:border-primary/30 transition-all duration-200"),
148
+ className: o("border-2 border-border-subtle/50 rounded-xl p-4 flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3", "hover:border-primary/30 transition-all duration-200"),
149
149
  children: [/* @__PURE__ */ j("div", {
150
150
  className: "flex items-center gap-3 min-w-0",
151
151
  children: [/* @__PURE__ */ A(x, {
@@ -157,7 +157,7 @@ function P() {
157
157
  className: "font-medium truncate",
158
158
  children: e.fileName
159
159
  }), /* @__PURE__ */ j("p", {
160
- className: "text-sm text-muted-foreground",
160
+ className: "text-sm text-text-secondary",
161
161
  children: [
162
162
  e.entityTypes.join(", "),
163
163
  " ·",
@@ -171,10 +171,10 @@ function P() {
171
171
  className: "flex items-center gap-2 flex-shrink-0",
172
172
  children: e.downloadUrl ? /* @__PURE__ */ j("a", {
173
173
  href: e.downloadUrl,
174
- className: "inline-flex items-center gap-2 px-3 py-1.5 bg-primary text-primary-foreground rounded-lg hover:bg-primary/90 transition-colors text-sm font-medium",
174
+ 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",
175
175
  children: [/* @__PURE__ */ A(b, { size: 14 }), "Download"]
176
176
  }) : /* @__PURE__ */ j("span", {
177
- className: "inline-flex items-center gap-1.5 text-sm text-muted-foreground",
177
+ className: "inline-flex items-center gap-1.5 text-sm text-text-secondary",
178
178
  children: [/* @__PURE__ */ A(y, { size: 14 }), "Pending"]
179
179
  })
180
180
  })]
@@ -221,7 +221,7 @@ function P() {
221
221
  e?.id && I?.(N(F, e.id));
222
222
  },
223
223
  disabled: Y,
224
- className: "inline-flex items-center justify-center gap-2 px-6 py-3 border-2 border-primary/50 text-primary rounded-lg hover:bg-primary/5 transition-all duration-200 font-medium disabled:opacity-50",
224
+ className: "inline-flex items-center justify-center gap-2 px-6 py-3 border-2 border-primary/50 text-primary rounded-lg hover:bg-action-primary-bg/5 transition-all duration-200 font-medium disabled:opacity-50",
225
225
  children: [Y ? /* @__PURE__ */ A(w, {
226
226
  size: 18,
227
227
  className: "animate-spin"
@@ -245,9 +245,9 @@ function P() {
245
245
  role: "dialog",
246
246
  "aria-modal": "true",
247
247
  "aria-labelledby": "export-confirm-title",
248
- className: "fixed inset-0 z-50 flex items-center justify-center bg-background/80 backdrop-blur-sm p-4",
248
+ className: "fixed inset-0 z-50 flex items-center justify-center bg-bg-surface/80 backdrop-blur-sm p-4",
249
249
  children: /* @__PURE__ */ j("div", {
250
- className: "w-full max-w-md rounded-xl border-2 border-border bg-card p-6 shadow-xl",
250
+ className: "w-full max-w-md rounded-xl border-2 border-border-subtle bg-bg-surface p-6 shadow-xl",
251
251
  children: [
252
252
  /* @__PURE__ */ A("h2", {
253
253
  id: "export-confirm-title",
@@ -255,7 +255,7 @@ function P() {
255
255
  children: H === "cancel" ? "Cancel export?" : "Delete export?"
256
256
  }),
257
257
  /* @__PURE__ */ A("p", {
258
- className: "mt-2 text-sm text-muted-foreground",
258
+ className: "mt-2 text-sm text-text-secondary",
259
259
  children: H === "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."
260
260
  }),
261
261
  /* @__PURE__ */ j("div", {
@@ -263,7 +263,7 @@ function P() {
263
263
  children: [/* @__PURE__ */ A("button", {
264
264
  type: "button",
265
265
  onClick: () => U(null),
266
- className: "px-4 py-2 rounded-lg border-2 border-border hover:bg-accent transition-colors font-medium",
266
+ className: "px-4 py-2 rounded-lg border-2 border-border-subtle hover:bg-accent transition-colors font-medium",
267
267
  children: "Keep Export"
268
268
  }), /* @__PURE__ */ j("button", {
269
269
  type: "button",
@@ -278,7 +278,7 @@ function P() {
278
278
  }
279
279
  },
280
280
  disabled: G || q,
281
- className: "inline-flex items-center justify-center gap-2 px-4 py-2 rounded-lg bg-destructive text-destructive-foreground hover:bg-destructive/90 transition-colors font-medium disabled:opacity-50",
281
+ 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",
282
282
  children: [G || q ? /* @__PURE__ */ A(w, {
283
283
  size: 16,
284
284
  className: "animate-spin"
@@ -320,7 +320,7 @@ function P() {
320
320
  /* @__PURE__ */ j("button", {
321
321
  type: "button",
322
322
  onClick: R,
323
- className: "inline-flex items-center gap-2 px-6 py-3 bg-primary text-primary-foreground rounded-lg hover:bg-primary/90 transition-colors font-medium",
323
+ 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",
324
324
  children: [/* @__PURE__ */ A(_, { size: 18 }), "Back to Dashboard"]
325
325
  })
326
326
  ]