@burdenoff/microfe-export 2026.525.2 → 2026.527.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.
Files changed (80) hide show
  1. package/dist/export/ExportRoutes.js +5 -4
  2. package/dist/export/ExportRoutes.js.map +1 -1
  3. package/dist/export/components/ExportStatusBadge.js +2 -2
  4. package/dist/export/components/ExportStatusBadge.js.map +1 -1
  5. package/dist/export/constants/enums.js +13 -13
  6. package/dist/export/constants/enums.js.map +1 -1
  7. package/dist/export/hooks/useExportQueries.js.map +1 -1
  8. package/dist/export/pages/CreateExportPage.js +10 -1
  9. package/dist/export/pages/CreateExportPage.js.map +1 -1
  10. package/dist/export/pages/ExportDashboardPage.js +5 -0
  11. package/dist/export/pages/ExportDashboardPage.js.map +1 -1
  12. package/dist/export/pages/ExportDetailPage.js +7 -1
  13. package/dist/export/pages/ExportDetailPage.js.map +1 -1
  14. package/dist/export/pages/ExportHistoryPage.js +136 -124
  15. package/dist/export/pages/ExportHistoryPage.js.map +1 -1
  16. package/dist/export/pages/ExportTemplatesPage.js +148 -136
  17. package/dist/export/pages/ExportTemplatesPage.js.map +1 -1
  18. package/dist/export/pages/TemplateDetailPage.js +6 -1
  19. package/dist/export/pages/TemplateDetailPage.js.map +1 -1
  20. package/package.json +1 -1
  21. package/dist/dev/main.d.ts +0 -2
  22. package/dist/dev/main.d.ts.map +0 -1
  23. package/dist/export/ExportRoot.d.ts +0 -31
  24. package/dist/export/ExportRoot.d.ts.map +0 -1
  25. package/dist/export/ExportRoutes.d.ts +0 -14
  26. package/dist/export/ExportRoutes.d.ts.map +0 -1
  27. package/dist/export/components/ExportProgressBar.d.ts +0 -12
  28. package/dist/export/components/ExportProgressBar.d.ts.map +0 -1
  29. package/dist/export/components/ExportStatusBadge.d.ts +0 -12
  30. package/dist/export/components/ExportStatusBadge.d.ts.map +0 -1
  31. package/dist/export/components/PageLayout.d.ts +0 -55
  32. package/dist/export/components/PageLayout.d.ts.map +0 -1
  33. package/dist/export/components/ui.d.ts +0 -6
  34. package/dist/export/components/ui.d.ts.map +0 -1
  35. package/dist/export/constants/enums.d.ts +0 -79
  36. package/dist/export/constants/enums.d.ts.map +0 -1
  37. package/dist/export/constants/index.d.ts +0 -7
  38. package/dist/export/constants/index.d.ts.map +0 -1
  39. package/dist/export/hooks/useExportQueries.d.ts +0 -224
  40. package/dist/export/hooks/useExportQueries.d.ts.map +0 -1
  41. package/dist/export/index.d.ts +0 -29
  42. package/dist/export/index.d.ts.map +0 -1
  43. package/dist/export/pages/CreateExportPage.d.ts +0 -2
  44. package/dist/export/pages/CreateExportPage.d.ts.map +0 -1
  45. package/dist/export/pages/ExportDashboardPage.d.ts +0 -6
  46. package/dist/export/pages/ExportDashboardPage.d.ts.map +0 -1
  47. package/dist/export/pages/ExportDetailPage.d.ts +0 -7
  48. package/dist/export/pages/ExportDetailPage.d.ts.map +0 -1
  49. package/dist/export/pages/ExportHistoryPage.d.ts +0 -6
  50. package/dist/export/pages/ExportHistoryPage.d.ts.map +0 -1
  51. package/dist/export/pages/ExportLandingPage.d.ts +0 -9
  52. package/dist/export/pages/ExportLandingPage.d.ts.map +0 -1
  53. package/dist/export/pages/ExportTemplatesPage.d.ts +0 -6
  54. package/dist/export/pages/ExportTemplatesPage.d.ts.map +0 -1
  55. package/dist/export/pages/TemplateDetailPage.d.ts +0 -7
  56. package/dist/export/pages/TemplateDetailPage.d.ts.map +0 -1
  57. package/dist/export/providers/ExportProvider.d.ts +0 -13
  58. package/dist/export/providers/ExportProvider.d.ts.map +0 -1
  59. package/dist/export/store/exportStore.d.ts +0 -17
  60. package/dist/export/store/exportStore.d.ts.map +0 -1
  61. package/dist/export/types/index.d.ts +0 -230
  62. package/dist/export/types/index.d.ts.map +0 -1
  63. package/dist/export/utils/cn.d.ts +0 -8
  64. package/dist/export/utils/cn.d.ts.map +0 -1
  65. package/dist/export/utils/events.d.ts +0 -7
  66. package/dist/export/utils/events.d.ts.map +0 -1
  67. package/dist/export/utils/i18n.d.ts +0 -6
  68. package/dist/export/utils/i18n.d.ts.map +0 -1
  69. package/dist/generated/global-operations.d.ts +0 -2
  70. package/dist/generated/global-operations.d.ts.map +0 -1
  71. package/dist/generated/global-types.d.ts +0 -23527
  72. package/dist/generated/global-types.d.ts.map +0 -1
  73. package/dist/generated/wspace-operations.d.ts +0 -773
  74. package/dist/generated/wspace-operations.d.ts.map +0 -1
  75. package/dist/generated/wspace-types.d.ts +0 -57851
  76. package/dist/generated/wspace-types.d.ts.map +0 -1
  77. package/dist/index.d.ts +0 -6
  78. package/dist/index.d.ts.map +0 -1
  79. package/dist/utils/nativeBridge.d.ts +0 -3
  80. package/dist/utils/nativeBridge.d.ts.map +0 -1
@@ -1,132 +1,138 @@
1
1
  import { useExport as e } from "../providers/ExportProvider.js";
2
2
  import { useExportJobs as t } from "../hooks/useExportQueries.js";
3
3
  import { cn as n } from "../utils/cn.js";
4
- import { getAllStatuses as r, getFormatDisplayName as i, getStatusDisplayName as a } from "../constants/enums.js";
5
- import { tWithFallback as o } from "../utils/i18n.js";
6
- import { ExportStatusBadge as s } from "../components/ExportStatusBadge.js";
7
- import { EmptyState as ee, PageLayout as c } from "../components/PageLayout.js";
4
+ import { getAllStatuses as r, getFormatDisplayName as ee, getStatusDisplayName as i } from "../constants/enums.js";
5
+ import { tWithFallback as a } from "../utils/i18n.js";
6
+ import { ExportStatusBadge as o } from "../components/ExportStatusBadge.js";
7
+ import { EmptyState as s, PageLayout as c } from "../components/PageLayout.js";
8
8
  import { useExportStore as l } from "../store/exportStore.js";
9
- import { useEffect as u, useMemo as d, useState as f } from "react";
10
- import { AlertCircle as p, ChevronLeft as m, ChevronRight as h, Clock as g, Download as _, Filter as v, RefreshCw as y, Search as b, X as x } from "lucide-react";
11
- import { useSearchParams as S } from "react-router-dom";
12
- import { Fragment as C, jsx as w, jsxs as T } from "react/jsx-runtime";
13
- import { useI18n as E } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
9
+ import { useEffect as u, useMemo as d, useRef as f, useState as p } from "react";
10
+ import { AlertCircle as te, ChevronLeft as ne, ChevronRight as m, Clock as h, Download as g, Filter as _, RefreshCw as v, Search as y, X as b } from "lucide-react";
11
+ import { useSearchParams as x } from "react-router-dom";
12
+ import { Fragment as S, jsx as C, jsxs as w } from "react/jsx-runtime";
13
+ import { useI18n as T } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
14
14
  //#region src/export/pages/ExportHistoryPage.tsx
15
- var D = (e, t) => (e.endsWith("/") ? e.slice(0, -1) : e) + (t.startsWith("/") ? t : `/${t}`);
16
- function O() {
17
- let { basePath: O = "/", navigate: k } = e(), { t: A } = E(), j = (e, t, n) => o(A, e, t, n), { jobFilter: M, updateFilter: N, resetFilter: P, pagination: F, setPagination: I } = l(), [L] = S();
15
+ var E = (e, t) => (e.endsWith("/") ? e.slice(0, -1) : e) + (t.startsWith("/") ? t : `/${t}`);
16
+ function D() {
17
+ let { basePath: D = "/", navigate: O } = e(), { t: k } = T(), A = (e, t, n) => a(k, e, t, n), { jobFilter: j, updateFilter: M, resetFilter: N, pagination: P, setPagination: F } = l(), [I] = x(), L = f(!1);
18
18
  u(() => {
19
- let e = L.get("status");
20
- e && N({ status: e });
21
- }, []);
22
- let [R, z] = f(!1), [B, V] = f([null]), [H, U] = f(0), W = B[H] ?? null, { data: G, totalCount: K, pageInfo: q, isLoading: J, error: Y, refetch: X } = t(M, {
23
- first: F.pageSize,
19
+ if (L.current) return;
20
+ L.current = !0;
21
+ let e = I.get("status");
22
+ e && M({ status: e });
23
+ }, [I, M]);
24
+ let [R, z] = p(!1), [B, V] = p([null]), [H, U] = p(0), W = B[H] ?? null, { data: G, totalCount: K, pageInfo: q, isLoading: J, error: Y, refetch: X } = t(j, {
25
+ first: P.pageSize,
24
26
  after: W ?? void 0
25
27
  }), Z = d(() => {
26
- if (!M.search) return G;
27
- let e = M.search.toLowerCase();
28
+ if (!j.search) return G;
29
+ let e = j.search.toLowerCase();
28
30
  return G.filter((t) => t.name.toLowerCase().includes(e) || t.entityTypes.some((t) => t.toLowerCase().includes(e)));
29
- }, [G, M.search]), Q = M.search || M.status !== "all" || M.format !== "all", te = (e) => {
30
- k?.(D(O, e));
31
- }, ne = () => {
32
- !q?.hasNextPage || !q.endCursor || (V([...B.slice(0, H + 1), q.endCursor]), U(H + 1), I({
33
- page: F.page + 1,
31
+ }, [G, j.search]), Q = j.search || j.status !== "all" || j.format !== "all", re = (e) => {
32
+ O?.(E(D, e));
33
+ }, ie = () => {
34
+ !q?.hasNextPage || !q.endCursor || (V([...B.slice(0, H + 1), q.endCursor]), U((e) => e + 1), F({
35
+ page: P.page + 1,
34
36
  cursor: q.endCursor
35
37
  }));
36
- }, re = () => {
38
+ }, ae = () => {
37
39
  if (H === 0) return;
38
40
  let e = H - 1;
39
- U(e), I({
40
- page: F.page - 1,
41
+ U(e), F({
42
+ page: P.page - 1,
41
43
  cursor: B[e] ?? null
42
44
  });
43
45
  }, $ = () => {
44
- P(), V([null]), U(0);
45
- }, ie = H > 0, ae = q?.hasNextPage ?? !1, oe = H * F.pageSize + 1, se = Math.min((H + 1) * F.pageSize, K), ce = (e) => j(`export.shared.status.${e.toLowerCase()}`, a(e));
46
- return /* @__PURE__ */ T(c, {
47
- title: j("export.history.title", "Export History"),
48
- subtitle: j("export.history.subtitle", "View and manage all your past export jobs"),
49
- icon: /* @__PURE__ */ w(g, { size: 24 }),
50
- headerActions: /* @__PURE__ */ T("button", {
51
- onClick: () => k?.(D(O, "new")),
46
+ N(), V([null]), U(0);
47
+ }, oe = H > 0, se = q?.hasNextPage ?? !1, ce = H * P.pageSize + 1, le = Math.min((H + 1) * P.pageSize, K), ue = (e) => A(`export.shared.status.${e.toLowerCase()}`, i(e));
48
+ return /* @__PURE__ */ w(c, {
49
+ title: A("export.history.title", "Export History"),
50
+ subtitle: A("export.history.subtitle", "View and manage all your past export jobs"),
51
+ icon: /* @__PURE__ */ C(h, { size: 24 }),
52
+ headerActions: /* @__PURE__ */ w("button", {
53
+ type: "button",
54
+ onClick: () => O?.(E(D, "new")),
52
55
  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",
53
- children: [/* @__PURE__ */ w(_, { size: 16 }), j("export.history.actions.newExport", "New Export")]
56
+ children: [/* @__PURE__ */ C(g, { size: 16 }), A("export.history.actions.newExport", "New Export")]
54
57
  }),
55
58
  children: [
56
- /* @__PURE__ */ T("div", {
59
+ /* @__PURE__ */ w("div", {
57
60
  className: "space-y-4",
58
- children: [/* @__PURE__ */ T("div", {
61
+ children: [/* @__PURE__ */ w("div", {
59
62
  className: "flex flex-col sm:flex-row gap-3",
60
- children: [/* @__PURE__ */ T("div", {
63
+ children: [/* @__PURE__ */ w("div", {
61
64
  className: "flex-1 relative group",
62
- children: [/* @__PURE__ */ w(b, {
65
+ children: [/* @__PURE__ */ C(y, {
63
66
  size: 18,
64
67
  className: "absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground group-focus-within:text-primary transition-colors"
65
- }), /* @__PURE__ */ w("input", {
68
+ }), /* @__PURE__ */ C("input", {
66
69
  type: "text",
67
- placeholder: j("export.history.search.placeholder", "Search exports by name or entity type..."),
68
- value: M.search,
69
- onChange: (e) => N({ search: e.target.value }),
70
+ "aria-label": A("export.history.search.placeholder", "Search exports by name or entity type"),
71
+ placeholder: A("export.history.search.placeholder", "Search exports by name or entity type..."),
72
+ value: j.search,
73
+ onChange: (e) => M({ search: e.target.value }),
70
74
  className: "w-full pl-[3.25rem] pr-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"
71
75
  })]
72
- }), /* @__PURE__ */ T("button", {
76
+ }), /* @__PURE__ */ w("button", {
77
+ type: "button",
73
78
  onClick: () => z(!R),
74
79
  className: n("inline-flex items-center gap-2 px-4 py-2.5 border-2 rounded-lg transition-all duration-200 font-medium", R || Q ? "bg-primary text-primary-foreground border-primary" : "border-border/50 hover:border-primary/30"),
75
- children: [/* @__PURE__ */ w(v, { size: 16 }), R ? j("export.history.filters.hide", "Hide") : j("export.history.filters.show", "Filter")]
80
+ children: [/* @__PURE__ */ C(_, { size: 16 }), R ? A("export.history.filters.hide", "Hide") : A("export.history.filters.show", "Filter")]
76
81
  })]
77
- }), R && /* @__PURE__ */ T("div", {
82
+ }), R && /* @__PURE__ */ w("div", {
78
83
  className: "border-2 border-border/50 rounded-xl p-4 animate-in slide-in-from-top-2 duration-200",
79
- children: [/* @__PURE__ */ T("div", {
84
+ children: [/* @__PURE__ */ w("div", {
80
85
  className: "flex items-center justify-between mb-4",
81
- children: [/* @__PURE__ */ T("h3", {
86
+ children: [/* @__PURE__ */ w("h3", {
82
87
  className: "font-semibold flex items-center gap-2",
83
- children: [/* @__PURE__ */ w(v, {
88
+ children: [/* @__PURE__ */ C(_, {
84
89
  size: 16,
85
90
  className: "text-primary"
86
- }), j("export.history.filters.title", "Filters")]
87
- }), Q && /* @__PURE__ */ T("button", {
91
+ }), A("export.history.filters.title", "Filters")]
92
+ }), Q && /* @__PURE__ */ w("button", {
93
+ type: "button",
88
94
  onClick: $,
89
95
  className: "text-sm text-muted-foreground hover:text-destructive flex items-center gap-1",
90
- children: [/* @__PURE__ */ w(x, { size: 14 }), j("export.history.filters.clearAll", "Clear All")]
96
+ children: [/* @__PURE__ */ C(b, { size: 14 }), A("export.history.filters.clearAll", "Clear All")]
91
97
  })]
92
- }), /* @__PURE__ */ T("div", {
98
+ }), /* @__PURE__ */ w("div", {
93
99
  className: "grid grid-cols-1 sm:grid-cols-2 gap-4",
94
- children: [/* @__PURE__ */ T("div", {
100
+ children: [/* @__PURE__ */ w("div", {
95
101
  className: "space-y-2",
96
- children: [/* @__PURE__ */ w("label", {
102
+ children: [/* @__PURE__ */ C("label", {
97
103
  className: "block text-sm font-medium",
98
- children: j("export.history.filters.status.label", "Status")
99
- }), /* @__PURE__ */ T("select", {
100
- value: M.status,
101
- onChange: (e) => N({ status: e.target.value }),
104
+ children: A("export.history.filters.status.label", "Status")
105
+ }), /* @__PURE__ */ w("select", {
106
+ value: j.status,
107
+ onChange: (e) => M({ status: e.target.value }),
102
108
  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",
103
- children: [/* @__PURE__ */ w("option", {
109
+ children: [/* @__PURE__ */ C("option", {
104
110
  value: "all",
105
- children: j("export.history.filters.status.all", "All Statuses")
106
- }), r().map((e) => /* @__PURE__ */ w("option", {
111
+ children: A("export.history.filters.status.all", "All Statuses")
112
+ }), r().map((e) => /* @__PURE__ */ C("option", {
107
113
  value: e,
108
- children: ce(e)
114
+ children: ue(e)
109
115
  }, e))]
110
116
  })]
111
- }), /* @__PURE__ */ T("div", {
117
+ }), /* @__PURE__ */ w("div", {
112
118
  className: "space-y-2",
113
- children: [/* @__PURE__ */ w("label", {
119
+ children: [/* @__PURE__ */ C("label", {
114
120
  className: "block text-sm font-medium",
115
- children: j("export.history.filters.format.label", "Format")
116
- }), /* @__PURE__ */ T("select", {
117
- value: M.format,
118
- onChange: (e) => N({ format: e.target.value }),
121
+ children: A("export.history.filters.format.label", "Format")
122
+ }), /* @__PURE__ */ w("select", {
123
+ value: j.format,
124
+ onChange: (e) => M({ format: e.target.value }),
119
125
  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",
120
126
  children: [
121
- /* @__PURE__ */ w("option", {
127
+ /* @__PURE__ */ C("option", {
122
128
  value: "all",
123
- children: j("export.history.filters.format.all", "All Formats")
129
+ children: A("export.history.filters.format.all", "All Formats")
124
130
  }),
125
- /* @__PURE__ */ w("option", {
131
+ /* @__PURE__ */ C("option", {
126
132
  value: "CSV",
127
133
  children: "CSV"
128
134
  }),
129
- /* @__PURE__ */ w("option", {
135
+ /* @__PURE__ */ C("option", {
130
136
  value: "JSON",
131
137
  children: "JSON"
132
138
  })
@@ -136,28 +142,29 @@ function O() {
136
142
  })]
137
143
  })]
138
144
  }),
139
- Y && /* @__PURE__ */ T("div", {
145
+ Y && /* @__PURE__ */ w("div", {
140
146
  className: "border-2 border-border-default rounded-xl bg-status-error-bg-subtle p-6 flex items-start gap-4",
141
- children: [/* @__PURE__ */ w(p, {
147
+ children: [/* @__PURE__ */ C(te, {
142
148
  size: 24,
143
149
  className: "text-status-error-text flex-shrink-0"
144
- }), /* @__PURE__ */ T("div", { children: [
145
- /* @__PURE__ */ w("h3", {
150
+ }), /* @__PURE__ */ w("div", { children: [
151
+ /* @__PURE__ */ C("h3", {
146
152
  className: "font-semibold text-status-error-text mb-1",
147
- children: j("export.history.error.title", "Error loading exports")
153
+ children: A("export.history.error.title", "Error loading exports")
148
154
  }),
149
- /* @__PURE__ */ w("p", {
155
+ /* @__PURE__ */ C("p", {
150
156
  className: "text-sm text-status-error-text mb-3",
151
157
  children: Y.message
152
158
  }),
153
- /* @__PURE__ */ T("button", {
159
+ /* @__PURE__ */ w("button", {
160
+ type: "button",
154
161
  onClick: () => X(),
155
162
  className: "inline-flex items-center gap-2 px-3 py-1.5 text-sm bg-destructive text-destructive-foreground rounded-lg hover:bg-destructive/90 transition-colors",
156
- children: [/* @__PURE__ */ w(y, { size: 14 }), j("export.history.error.retry", "Try Again")]
163
+ children: [/* @__PURE__ */ C(v, { size: 14 }), A("export.history.error.retry", "Try Again")]
157
164
  })
158
165
  ] })]
159
166
  }),
160
- J && /* @__PURE__ */ w("div", {
167
+ J && /* @__PURE__ */ C("div", {
161
168
  className: "space-y-3",
162
169
  children: [...[
163
170
  ,
@@ -165,97 +172,102 @@ function O() {
165
172
  ,
166
173
  ,
167
174
  ,
168
- ]].map((e, t) => /* @__PURE__ */ w("div", {
175
+ ]].map((e, t) => /* @__PURE__ */ C("div", {
169
176
  className: "border-2 border-border/50 rounded-xl p-4 animate-pulse",
170
- children: /* @__PURE__ */ T("div", {
177
+ children: /* @__PURE__ */ w("div", {
171
178
  className: "flex items-center justify-between",
172
- children: [/* @__PURE__ */ T("div", {
179
+ children: [/* @__PURE__ */ w("div", {
173
180
  className: "space-y-2",
174
- children: [/* @__PURE__ */ w("div", { className: "h-4 w-48 bg-muted rounded" }), /* @__PURE__ */ w("div", { className: "h-3 w-32 bg-muted rounded" })]
175
- }), /* @__PURE__ */ w("div", { className: "h-5 w-20 bg-muted rounded-full" })]
181
+ children: [/* @__PURE__ */ C("div", { className: "h-4 w-48 bg-muted rounded" }), /* @__PURE__ */ C("div", { className: "h-3 w-32 bg-muted rounded" })]
182
+ }), /* @__PURE__ */ C("div", { className: "h-5 w-20 bg-muted rounded-full" })]
176
183
  })
177
184
  }, t))
178
185
  }),
179
- !J && !Y && (Z.length > 0 ? /* @__PURE__ */ T(C, { children: [/* @__PURE__ */ w("div", {
186
+ !J && !Y && (Z.length > 0 ? /* @__PURE__ */ w(S, { children: [/* @__PURE__ */ C("div", {
180
187
  className: "space-y-2",
181
- children: Z.map((e, t) => /* @__PURE__ */ w("button", {
182
- onClick: () => te(e.id),
188
+ children: Z.map((e, t) => /* @__PURE__ */ C("button", {
189
+ type: "button",
190
+ onClick: () => re(e.id),
183
191
  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", "group animate-in fade-in-0 slide-in-from-bottom-2"),
184
192
  style: { animationDelay: `${t * 30}ms` },
185
- children: /* @__PURE__ */ T("div", {
193
+ children: /* @__PURE__ */ w("div", {
186
194
  className: "flex items-start sm:items-center justify-between gap-3",
187
- children: [/* @__PURE__ */ T("div", {
195
+ children: [/* @__PURE__ */ w("div", {
188
196
  className: "flex-1 min-w-0",
189
- children: [/* @__PURE__ */ w("h4", {
197
+ children: [/* @__PURE__ */ C("h4", {
190
198
  className: "font-semibold text-foreground truncate",
191
199
  children: e.name
192
- }), /* @__PURE__ */ T("p", {
200
+ }), /* @__PURE__ */ w("p", {
193
201
  className: "text-sm text-muted-foreground mt-1 line-clamp-2",
194
202
  children: [
195
203
  e.entityTypes.join(", "),
196
204
  " ·",
197
205
  " ",
198
- i(e.format),
206
+ ee(e.format),
199
207
  e.createdAt && ` · ${new Date(e.createdAt).toLocaleDateString()}`
200
208
  ]
201
209
  })]
202
- }), /* @__PURE__ */ T("div", {
210
+ }), /* @__PURE__ */ w("div", {
203
211
  className: "flex items-center gap-2 flex-shrink-0",
204
- children: [/* @__PURE__ */ w(s, { status: e.status }), /* @__PURE__ */ w(h, {
212
+ children: [/* @__PURE__ */ C(o, { status: e.status }), /* @__PURE__ */ C(m, {
205
213
  size: 18,
206
214
  className: "text-muted-foreground group-hover:text-primary transition-colors hidden sm:block"
207
215
  })]
208
216
  })]
209
217
  })
210
218
  }, e.id))
211
- }), K > F.pageSize && /* @__PURE__ */ T("div", {
219
+ }), K > P.pageSize && /* @__PURE__ */ w("div", {
212
220
  className: "flex flex-col sm:flex-row items-center justify-between gap-3 pt-2",
213
- children: [/* @__PURE__ */ w("p", {
221
+ children: [/* @__PURE__ */ C("p", {
214
222
  className: "text-sm text-muted-foreground",
215
- children: j("export.history.pagination.showing", "Showing {start}-{end} of {total}", {
216
- start: oe,
217
- end: se,
223
+ children: A("export.history.pagination.showing", "Showing {start}-{end} of {total}", {
224
+ start: ce,
225
+ end: le,
218
226
  total: K
219
227
  })
220
- }), /* @__PURE__ */ T("div", {
228
+ }), /* @__PURE__ */ w("div", {
221
229
  className: "flex items-center gap-2",
222
230
  children: [
223
- /* @__PURE__ */ T("button", {
224
- onClick: re,
225
- disabled: !ie,
231
+ /* @__PURE__ */ w("button", {
232
+ type: "button",
233
+ onClick: ae,
234
+ disabled: !oe,
226
235
  className: "inline-flex items-center gap-1.5 px-3 py-1.5 text-sm border-2 border-border/50 rounded-lg hover:border-primary/30 disabled:opacity-40 disabled:cursor-not-allowed transition-colors font-medium",
227
- children: [/* @__PURE__ */ w(m, { size: 16 }), j("export.history.pagination.prev", "Prev")]
236
+ children: [/* @__PURE__ */ C(ne, { size: 16 }), A("export.history.pagination.prev", "Prev")]
228
237
  }),
229
- /* @__PURE__ */ w("span", {
238
+ /* @__PURE__ */ C("span", {
230
239
  className: "text-sm text-muted-foreground px-2",
231
- children: j("export.history.pagination.page", "Page {page}", { page: F.page })
240
+ children: A("export.history.pagination.page", "Page {page}", { page: P.page })
232
241
  }),
233
- /* @__PURE__ */ T("button", {
234
- onClick: ne,
235
- disabled: !ae,
242
+ /* @__PURE__ */ w("button", {
243
+ type: "button",
244
+ onClick: ie,
245
+ disabled: !se,
236
246
  className: "inline-flex items-center gap-1.5 px-3 py-1.5 text-sm border-2 border-border/50 rounded-lg hover:border-primary/30 disabled:opacity-40 disabled:cursor-not-allowed transition-colors font-medium",
237
- children: [j("export.history.pagination.next", "Next"), /* @__PURE__ */ w(h, { size: 16 })]
247
+ children: [A("export.history.pagination.next", "Next"), /* @__PURE__ */ C(m, { size: 16 })]
238
248
  })
239
249
  ]
240
250
  })]
241
- })] }) : /* @__PURE__ */ w(ee, {
242
- icon: w(Q ? b : g, { size: 48 }),
243
- title: Q ? j("export.history.empty.filtered.title", "No matching exports") : j("export.history.empty.title", "No exports yet"),
244
- description: Q ? j("export.history.empty.filtered.description", "Try adjusting your search or filters.") : j("export.history.empty.description", "Create your first export to see it here."),
245
- action: Q ? /* @__PURE__ */ T("button", {
251
+ })] }) : /* @__PURE__ */ C(s, {
252
+ icon: C(Q ? y : h, { size: 48 }),
253
+ title: Q ? A("export.history.empty.filtered.title", "No matching exports") : A("export.history.empty.title", "No exports yet"),
254
+ description: Q ? A("export.history.empty.filtered.description", "Try adjusting your search or filters.") : A("export.history.empty.description", "Create your first export to see it here."),
255
+ action: Q ? /* @__PURE__ */ w("button", {
256
+ type: "button",
246
257
  onClick: $,
247
258
  className: "inline-flex items-center gap-2 px-4 py-2 border-2 border-border rounded-lg hover:bg-accent transition-colors font-medium",
248
- children: [/* @__PURE__ */ w(x, { size: 16 }), j("export.history.empty.filtered.actions.clear", "Clear Filters")]
249
- }) : /* @__PURE__ */ T("button", {
250
- onClick: () => k?.(D(O, "new")),
259
+ children: [/* @__PURE__ */ C(b, { size: 16 }), A("export.history.empty.filtered.actions.clear", "Clear Filters")]
260
+ }) : /* @__PURE__ */ w("button", {
261
+ type: "button",
262
+ onClick: () => O?.(E(D, "new")),
251
263
  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",
252
- children: [/* @__PURE__ */ w(_, { size: 16 }), j("export.history.empty.actions.createFirst", "Create First Export")]
264
+ children: [/* @__PURE__ */ C(g, { size: 16 }), A("export.history.empty.actions.createFirst", "Create First Export")]
253
265
  })
254
266
  }))
255
267
  ]
256
268
  });
257
269
  }
258
270
  //#endregion
259
- export { O as ExportHistoryPage };
271
+ export { D as ExportHistoryPage };
260
272
 
261
273
  //# sourceMappingURL=ExportHistoryPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ExportHistoryPage.js","names":[],"sources":["../../../src/export/pages/ExportHistoryPage.tsx"],"sourcesContent":["import { useState, useMemo, useEffect } from \"react\";\nimport { useSearchParams } from \"react-router-dom\";\nimport {\n Search,\n X,\n Clock,\n Download,\n ChevronRight,\n ChevronLeft,\n RefreshCw,\n AlertCircle,\n Filter,\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 { useExportStore } from \"../store/exportStore\";\nimport { ExportStatusBadge } from \"../components/ExportStatusBadge\";\nimport { PageLayout, EmptyState } from \"../components/PageLayout\";\nimport { cn } from \"../utils/cn\";\nimport {\n getFormatDisplayName,\n getAllStatuses,\n getStatusDisplayName,\n} from \"../constants/enums\";\nimport type { ExportJobStatus, ExportFormat } from \"../types\";\nimport { tWithFallback } from \"../utils/i18n\";\n\n/**\n * Helper to join paths correctly\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 History Page\n * Table/list of all past exports with filters and cursor-based pagination\n */\nexport function ExportHistoryPage() {\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 { jobFilter, updateFilter, resetFilter, pagination, setPagination } =\n useExportStore();\n const [searchParams] = useSearchParams();\n\n // Initialize status filter from URL search params (e.g. ?status=RUNNING)\n useEffect(() => {\n const statusParam = searchParams.get(\"status\");\n if (statusParam) {\n updateFilter({\n status: statusParam as ExportJobStatus,\n });\n }\n // Only run on mount\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const [showFilters, setShowFilters] = useState(false);\n // Cursor stack: index 0 = first page (no cursor), subsequent entries are \"after\" cursors\n const [cursorStack, setCursorStack] = useState<(string | null)[]>([null]);\n const [currentPageIndex, setCurrentPageIndex] = useState(0);\n\n const currentCursor = cursorStack[currentPageIndex] ?? null;\n\n const {\n data: jobs,\n totalCount,\n pageInfo,\n isLoading,\n error,\n refetch,\n } = useExportJobs(jobFilter, {\n first: pagination.pageSize,\n after: currentCursor ?? undefined,\n });\n\n // Client-side search filter (server-side filtering handles status/format)\n const filteredJobs = useMemo(() => {\n if (!jobFilter.search) return jobs;\n const q = jobFilter.search.toLowerCase();\n return jobs.filter(\n (job) =>\n job.name.toLowerCase().includes(q) ||\n job.entityTypes.some((e) => e.toLowerCase().includes(q)),\n );\n }, [jobs, jobFilter.search]);\n\n const hasActiveFilters =\n jobFilter.search ||\n jobFilter.status !== \"all\" ||\n jobFilter.format !== \"all\";\n\n const handleJobClick = (jobId: string) => {\n navigate?.(joinPath(basePath, jobId));\n };\n\n const handleNextPage = () => {\n if (!pageInfo?.hasNextPage || !pageInfo.endCursor) return;\n const newStack = [\n ...cursorStack.slice(0, currentPageIndex + 1),\n pageInfo.endCursor,\n ];\n setCursorStack(newStack);\n setCurrentPageIndex(currentPageIndex + 1);\n setPagination({ page: pagination.page + 1, cursor: pageInfo.endCursor });\n };\n\n const handlePrevPage = () => {\n if (currentPageIndex === 0) return;\n const prevIndex = currentPageIndex - 1;\n setCurrentPageIndex(prevIndex);\n setPagination({\n page: pagination.page - 1,\n cursor: cursorStack[prevIndex] ?? null,\n });\n };\n\n const handleResetFilters = () => {\n resetFilter();\n setCursorStack([null]);\n setCurrentPageIndex(0);\n };\n\n const hasPrevPage = currentPageIndex > 0;\n const hasNextPage = pageInfo?.hasNextPage ?? false;\n const pageStart = currentPageIndex * pagination.pageSize + 1;\n const pageEnd = Math.min(\n (currentPageIndex + 1) * pagination.pageSize,\n totalCount,\n );\n const getStatusLabel = (status: ExportJobStatus) =>\n tr(\n `export.shared.status.${status.toLowerCase()}`,\n getStatusDisplayName(status),\n );\n\n return (\n <PageLayout\n title={tr(\"export.history.title\", \"Export History\")}\n subtitle={tr(\n \"export.history.subtitle\",\n \"View and manage all your past export jobs\",\n )}\n icon={<Clock size={24} />}\n headerActions={\n <button\n onClick={() => navigate?.(joinPath(basePath, \"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 <Download size={16} />\n {tr(\"export.history.actions.newExport\", \"New Export\")}\n </button>\n }\n >\n {/* Search & Filters */}\n <div className=\"space-y-4\">\n <div className=\"flex flex-col sm:flex-row gap-3\">\n {/* Search */}\n <div className=\"flex-1 relative group\">\n <Search\n size={18}\n className=\"absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground group-focus-within:text-primary transition-colors\"\n />\n <input\n type=\"text\"\n placeholder={tr(\n \"export.history.search.placeholder\",\n \"Search exports by name or entity type...\",\n )}\n value={jobFilter.search}\n onChange={(e) => updateFilter({ search: e.target.value })}\n className=\"w-full pl-[3.25rem] pr-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 />\n </div>\n\n {/* Filter Toggle */}\n <button\n onClick={() => setShowFilters(!showFilters)}\n className={cn(\n \"inline-flex items-center gap-2 px-4 py-2.5 border-2 rounded-lg transition-all duration-200 font-medium\",\n showFilters || hasActiveFilters\n ? \"bg-primary text-primary-foreground border-primary\"\n : \"border-border/50 hover:border-primary/30\",\n )}\n >\n <Filter size={16} />\n {showFilters\n ? tr(\"export.history.filters.hide\", \"Hide\")\n : tr(\"export.history.filters.show\", \"Filter\")}\n </button>\n </div>\n\n {/* Filter Panel */}\n {showFilters && (\n <div className=\"border-2 border-border/50 rounded-xl p-4 animate-in slide-in-from-top-2 duration-200\">\n <div className=\"flex items-center justify-between mb-4\">\n <h3 className=\"font-semibold flex items-center gap-2\">\n <Filter size={16} className=\"text-primary\" />\n {tr(\"export.history.filters.title\", \"Filters\")}\n </h3>\n {hasActiveFilters && (\n <button\n onClick={handleResetFilters}\n className=\"text-sm text-muted-foreground hover:text-destructive flex items-center gap-1\"\n >\n <X size={14} />\n {tr(\"export.history.filters.clearAll\", \"Clear All\")}\n </button>\n )}\n </div>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-4\">\n {/* Status Filter */}\n <div className=\"space-y-2\">\n <label className=\"block text-sm font-medium\">\n {tr(\"export.history.filters.status.label\", \"Status\")}\n </label>\n <select\n value={jobFilter.status}\n onChange={(e) =>\n updateFilter({\n status: e.target.value as ExportJobStatus | \"all\",\n })\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=\"all\">\n {tr(\"export.history.filters.status.all\", \"All Statuses\")}\n </option>\n {getAllStatuses().map((status) => (\n <option key={status} value={status}>\n {getStatusLabel(status)}\n </option>\n ))}\n </select>\n </div>\n\n {/* Format Filter — only CSV and JSON are supported */}\n <div className=\"space-y-2\">\n <label className=\"block text-sm font-medium\">\n {tr(\"export.history.filters.format.label\", \"Format\")}\n </label>\n <select\n value={jobFilter.format}\n onChange={(e) =>\n updateFilter({\n format: e.target.value as ExportFormat | \"all\",\n })\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=\"all\">\n {tr(\"export.history.filters.format.all\", \"All Formats\")}\n </option>\n <option value=\"CSV\">CSV</option>\n <option value=\"JSON\">JSON</option>\n </select>\n </div>\n </div>\n </div>\n )}\n </div>\n\n {/* Error State */}\n {error && (\n <div className=\"border-2 border-border-default rounded-xl bg-status-error-bg-subtle p-6 flex items-start gap-4\">\n <AlertCircle\n size={24}\n className=\"text-status-error-text flex-shrink-0\"\n />\n <div>\n <h3 className=\"font-semibold text-status-error-text mb-1\">\n {tr(\"export.history.error.title\", \"Error loading exports\")}\n </h3>\n <p className=\"text-sm text-status-error-text mb-3\">\n {error.message}\n </p>\n <button\n onClick={() => refetch()}\n className=\"inline-flex items-center gap-2 px-3 py-1.5 text-sm bg-destructive text-destructive-foreground rounded-lg hover:bg-destructive/90 transition-colors\"\n >\n <RefreshCw size={14} />\n {tr(\"export.history.error.retry\", \"Try Again\")}\n </button>\n </div>\n </div>\n )}\n\n {/* Loading */}\n {isLoading && (\n <div className=\"space-y-3\">\n {[...Array(5)].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\">\n <div className=\"space-y-2\">\n <div className=\"h-4 w-48 bg-muted rounded\" />\n <div className=\"h-3 w-32 bg-muted rounded\" />\n </div>\n <div className=\"h-5 w-20 bg-muted rounded-full\" />\n </div>\n </div>\n ))}\n </div>\n )}\n\n {/* Jobs List */}\n {!isLoading &&\n !error &&\n (filteredJobs.length > 0 ? (\n <>\n <div className=\"space-y-2\">\n {filteredJobs.map((job, index) => (\n <button\n key={job.id}\n onClick={() => handleJobClick(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 \"group animate-in fade-in-0 slide-in-from-bottom-2\",\n )}\n style={{ animationDelay: `${index * 30}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;{\" \"}\n {getFormatDisplayName(job.format)}\n {job.createdAt &&\n ` · ${new Date(job.createdAt).toLocaleDateString()}`}\n </p>\n </div>\n <div className=\"flex items-center gap-2 flex-shrink-0\">\n <ExportStatusBadge status={job.status} />\n <ChevronRight\n size={18}\n className=\"text-muted-foreground group-hover:text-primary transition-colors hidden sm:block\"\n />\n </div>\n </div>\n </button>\n ))}\n </div>\n\n {/* Pagination */}\n {totalCount > pagination.pageSize && (\n <div className=\"flex flex-col sm:flex-row items-center justify-between gap-3 pt-2\">\n <p className=\"text-sm text-muted-foreground\">\n {tr(\n \"export.history.pagination.showing\",\n \"Showing {start}-{end} of {total}\",\n {\n start: pageStart,\n end: pageEnd,\n total: totalCount,\n },\n )}\n </p>\n <div className=\"flex items-center gap-2\">\n <button\n onClick={handlePrevPage}\n disabled={!hasPrevPage}\n className=\"inline-flex items-center gap-1.5 px-3 py-1.5 text-sm border-2 border-border/50 rounded-lg hover:border-primary/30 disabled:opacity-40 disabled:cursor-not-allowed transition-colors font-medium\"\n >\n <ChevronLeft size={16} />\n {tr(\"export.history.pagination.prev\", \"Prev\")}\n </button>\n <span className=\"text-sm text-muted-foreground px-2\">\n {tr(\"export.history.pagination.page\", \"Page {page}\", {\n page: pagination.page,\n })}\n </span>\n <button\n onClick={handleNextPage}\n disabled={!hasNextPage}\n className=\"inline-flex items-center gap-1.5 px-3 py-1.5 text-sm border-2 border-border/50 rounded-lg hover:border-primary/30 disabled:opacity-40 disabled:cursor-not-allowed transition-colors font-medium\"\n >\n {tr(\"export.history.pagination.next\", \"Next\")}\n <ChevronRight size={16} />\n </button>\n </div>\n </div>\n )}\n </>\n ) : (\n <EmptyState\n icon={hasActiveFilters ? <Search size={48} /> : <Clock size={48} />}\n title={\n hasActiveFilters\n ? tr(\n \"export.history.empty.filtered.title\",\n \"No matching exports\",\n )\n : tr(\"export.history.empty.title\", \"No exports yet\")\n }\n description={\n hasActiveFilters\n ? tr(\n \"export.history.empty.filtered.description\",\n \"Try adjusting your search or filters.\",\n )\n : tr(\n \"export.history.empty.description\",\n \"Create your first export to see it here.\",\n )\n }\n action={\n hasActiveFilters ? (\n <button\n onClick={handleResetFilters}\n className=\"inline-flex items-center gap-2 px-4 py-2 border-2 border-border rounded-lg hover:bg-accent transition-colors font-medium\"\n >\n <X size={16} />\n {tr(\n \"export.history.empty.filtered.actions.clear\",\n \"Clear Filters\",\n )}\n </button>\n ) : (\n <button\n onClick={() => navigate?.(joinPath(basePath, \"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 <Download size={16} />\n {tr(\n \"export.history.empty.actions.createFirst\",\n \"Create First Export\",\n )}\n </button>\n )\n }\n />\n ))}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ExportHistoryPage.js","names":[],"sources":["../../../src/export/pages/ExportHistoryPage.tsx"],"sourcesContent":["import { useState, useMemo, useEffect, useRef } from \"react\";\nimport { useSearchParams } from \"react-router-dom\";\nimport {\n Search,\n X,\n Clock,\n Download,\n ChevronRight,\n ChevronLeft,\n RefreshCw,\n AlertCircle,\n Filter,\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 { useExportStore } from \"../store/exportStore\";\nimport { ExportStatusBadge } from \"../components/ExportStatusBadge\";\nimport { PageLayout, EmptyState } from \"../components/PageLayout\";\nimport { cn } from \"../utils/cn\";\nimport {\n getFormatDisplayName,\n getAllStatuses,\n getStatusDisplayName,\n} from \"../constants/enums\";\nimport type { ExportJobStatus, ExportFormat } from \"../types\";\nimport { tWithFallback } from \"../utils/i18n\";\n\n/**\n * Helper to join paths correctly\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 History Page\n * Table/list of all past exports with filters and cursor-based pagination\n */\nexport function ExportHistoryPage() {\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 { jobFilter, updateFilter, resetFilter, pagination, setPagination } =\n useExportStore();\n const [searchParams] = useSearchParams();\n\n // Initialize status filter from URL search params (e.g. ?status=RUNNING) — once\n const didInitFromUrlRef = useRef(false);\n useEffect(() => {\n if (didInitFromUrlRef.current) return;\n didInitFromUrlRef.current = true;\n const statusParam = searchParams.get(\"status\");\n if (statusParam) {\n updateFilter({\n status: statusParam as ExportJobStatus,\n });\n }\n }, [searchParams, updateFilter]);\n\n const [showFilters, setShowFilters] = useState(false);\n // Cursor stack: index 0 = first page (no cursor), subsequent entries are \"after\" cursors\n const [cursorStack, setCursorStack] = useState<(string | null)[]>([null]);\n const [currentPageIndex, setCurrentPageIndex] = useState(0);\n\n const currentCursor = cursorStack[currentPageIndex] ?? null;\n\n const {\n data: jobs,\n totalCount,\n pageInfo,\n isLoading,\n error,\n refetch,\n } = useExportJobs(jobFilter, {\n first: pagination.pageSize,\n after: currentCursor ?? undefined,\n });\n\n // Client-side search filter (server-side filtering handles status/format)\n const filteredJobs = useMemo(() => {\n if (!jobFilter.search) return jobs;\n const q = jobFilter.search.toLowerCase();\n return jobs.filter(\n (job) =>\n job.name.toLowerCase().includes(q) ||\n job.entityTypes.some((e) => e.toLowerCase().includes(q)),\n );\n }, [jobs, jobFilter.search]);\n\n const hasActiveFilters =\n jobFilter.search ||\n jobFilter.status !== \"all\" ||\n jobFilter.format !== \"all\";\n\n const handleJobClick = (jobId: string) => {\n navigate?.(joinPath(basePath, jobId));\n };\n\n const handleNextPage = () => {\n if (!pageInfo?.hasNextPage || !pageInfo.endCursor) return;\n const newStack = [\n ...cursorStack.slice(0, currentPageIndex + 1),\n pageInfo.endCursor,\n ];\n setCursorStack(newStack);\n setCurrentPageIndex((prev) => prev + 1);\n setPagination({ page: pagination.page + 1, cursor: pageInfo.endCursor });\n };\n\n const handlePrevPage = () => {\n if (currentPageIndex === 0) return;\n const prevIndex = currentPageIndex - 1;\n setCurrentPageIndex(prevIndex);\n setPagination({\n page: pagination.page - 1,\n cursor: cursorStack[prevIndex] ?? null,\n });\n };\n\n const handleResetFilters = () => {\n resetFilter();\n setCursorStack([null]);\n setCurrentPageIndex(0);\n };\n\n const hasPrevPage = currentPageIndex > 0;\n const hasNextPage = pageInfo?.hasNextPage ?? false;\n const pageStart = currentPageIndex * pagination.pageSize + 1;\n const pageEnd = Math.min(\n (currentPageIndex + 1) * pagination.pageSize,\n totalCount,\n );\n const getStatusLabel = (status: ExportJobStatus) =>\n tr(\n `export.shared.status.${status.toLowerCase()}`,\n getStatusDisplayName(status),\n );\n\n return (\n <PageLayout\n title={tr(\"export.history.title\", \"Export History\")}\n subtitle={tr(\n \"export.history.subtitle\",\n \"View and manage all your past export jobs\",\n )}\n icon={<Clock size={24} />}\n headerActions={\n <button\n type=\"button\"\n onClick={() => navigate?.(joinPath(basePath, \"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 <Download size={16} />\n {tr(\"export.history.actions.newExport\", \"New Export\")}\n </button>\n }\n >\n {/* Search & Filters */}\n <div className=\"space-y-4\">\n <div className=\"flex flex-col sm:flex-row gap-3\">\n {/* Search */}\n <div className=\"flex-1 relative group\">\n <Search\n size={18}\n className=\"absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground group-focus-within:text-primary transition-colors\"\n />\n <input\n type=\"text\"\n aria-label={tr(\n \"export.history.search.placeholder\",\n \"Search exports by name or entity type\",\n )}\n placeholder={tr(\n \"export.history.search.placeholder\",\n \"Search exports by name or entity type...\",\n )}\n value={jobFilter.search}\n onChange={(e) => updateFilter({ search: e.target.value })}\n className=\"w-full pl-[3.25rem] pr-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 />\n </div>\n\n {/* Filter Toggle */}\n <button\n type=\"button\"\n onClick={() => setShowFilters(!showFilters)}\n className={cn(\n \"inline-flex items-center gap-2 px-4 py-2.5 border-2 rounded-lg transition-all duration-200 font-medium\",\n showFilters || hasActiveFilters\n ? \"bg-primary text-primary-foreground border-primary\"\n : \"border-border/50 hover:border-primary/30\",\n )}\n >\n <Filter size={16} />\n {showFilters\n ? tr(\"export.history.filters.hide\", \"Hide\")\n : tr(\"export.history.filters.show\", \"Filter\")}\n </button>\n </div>\n\n {/* Filter Panel */}\n {showFilters && (\n <div className=\"border-2 border-border/50 rounded-xl p-4 animate-in slide-in-from-top-2 duration-200\">\n <div className=\"flex items-center justify-between mb-4\">\n <h3 className=\"font-semibold flex items-center gap-2\">\n <Filter size={16} className=\"text-primary\" />\n {tr(\"export.history.filters.title\", \"Filters\")}\n </h3>\n {hasActiveFilters && (\n <button\n type=\"button\"\n onClick={handleResetFilters}\n className=\"text-sm text-muted-foreground hover:text-destructive flex items-center gap-1\"\n >\n <X size={14} />\n {tr(\"export.history.filters.clearAll\", \"Clear All\")}\n </button>\n )}\n </div>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-4\">\n {/* Status Filter */}\n <div className=\"space-y-2\">\n <label className=\"block text-sm font-medium\">\n {tr(\"export.history.filters.status.label\", \"Status\")}\n </label>\n <select\n value={jobFilter.status}\n onChange={(e) =>\n updateFilter({\n status: e.target.value as ExportJobStatus | \"all\",\n })\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=\"all\">\n {tr(\"export.history.filters.status.all\", \"All Statuses\")}\n </option>\n {getAllStatuses().map((status) => (\n <option key={status} value={status}>\n {getStatusLabel(status)}\n </option>\n ))}\n </select>\n </div>\n\n {/* Format Filter — only CSV and JSON are supported */}\n <div className=\"space-y-2\">\n <label className=\"block text-sm font-medium\">\n {tr(\"export.history.filters.format.label\", \"Format\")}\n </label>\n <select\n value={jobFilter.format}\n onChange={(e) =>\n updateFilter({\n format: e.target.value as ExportFormat | \"all\",\n })\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=\"all\">\n {tr(\"export.history.filters.format.all\", \"All Formats\")}\n </option>\n <option value=\"CSV\">CSV</option>\n <option value=\"JSON\">JSON</option>\n </select>\n </div>\n </div>\n </div>\n )}\n </div>\n\n {/* Error State */}\n {error && (\n <div className=\"border-2 border-border-default rounded-xl bg-status-error-bg-subtle p-6 flex items-start gap-4\">\n <AlertCircle\n size={24}\n className=\"text-status-error-text flex-shrink-0\"\n />\n <div>\n <h3 className=\"font-semibold text-status-error-text mb-1\">\n {tr(\"export.history.error.title\", \"Error loading exports\")}\n </h3>\n <p className=\"text-sm text-status-error-text mb-3\">\n {error.message}\n </p>\n <button\n type=\"button\"\n onClick={() => refetch()}\n className=\"inline-flex items-center gap-2 px-3 py-1.5 text-sm bg-destructive text-destructive-foreground rounded-lg hover:bg-destructive/90 transition-colors\"\n >\n <RefreshCw size={14} />\n {tr(\"export.history.error.retry\", \"Try Again\")}\n </button>\n </div>\n </div>\n )}\n\n {/* Loading */}\n {isLoading && (\n <div className=\"space-y-3\">\n {[...Array(5)].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\">\n <div className=\"space-y-2\">\n <div className=\"h-4 w-48 bg-muted rounded\" />\n <div className=\"h-3 w-32 bg-muted rounded\" />\n </div>\n <div className=\"h-5 w-20 bg-muted rounded-full\" />\n </div>\n </div>\n ))}\n </div>\n )}\n\n {/* Jobs List */}\n {!isLoading &&\n !error &&\n (filteredJobs.length > 0 ? (\n <>\n <div className=\"space-y-2\">\n {filteredJobs.map((job, index) => (\n <button\n type=\"button\"\n key={job.id}\n onClick={() => handleJobClick(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 \"group animate-in fade-in-0 slide-in-from-bottom-2\",\n )}\n style={{ animationDelay: `${index * 30}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;{\" \"}\n {getFormatDisplayName(job.format)}\n {job.createdAt &&\n ` · ${new Date(job.createdAt).toLocaleDateString()}`}\n </p>\n </div>\n <div className=\"flex items-center gap-2 flex-shrink-0\">\n <ExportStatusBadge status={job.status} />\n <ChevronRight\n size={18}\n className=\"text-muted-foreground group-hover:text-primary transition-colors hidden sm:block\"\n />\n </div>\n </div>\n </button>\n ))}\n </div>\n\n {/* Pagination */}\n {totalCount > pagination.pageSize && (\n <div className=\"flex flex-col sm:flex-row items-center justify-between gap-3 pt-2\">\n <p className=\"text-sm text-muted-foreground\">\n {tr(\n \"export.history.pagination.showing\",\n \"Showing {start}-{end} of {total}\",\n {\n start: pageStart,\n end: pageEnd,\n total: totalCount,\n },\n )}\n </p>\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={handlePrevPage}\n disabled={!hasPrevPage}\n className=\"inline-flex items-center gap-1.5 px-3 py-1.5 text-sm border-2 border-border/50 rounded-lg hover:border-primary/30 disabled:opacity-40 disabled:cursor-not-allowed transition-colors font-medium\"\n >\n <ChevronLeft size={16} />\n {tr(\"export.history.pagination.prev\", \"Prev\")}\n </button>\n <span className=\"text-sm text-muted-foreground px-2\">\n {tr(\"export.history.pagination.page\", \"Page {page}\", {\n page: pagination.page,\n })}\n </span>\n <button\n type=\"button\"\n onClick={handleNextPage}\n disabled={!hasNextPage}\n className=\"inline-flex items-center gap-1.5 px-3 py-1.5 text-sm border-2 border-border/50 rounded-lg hover:border-primary/30 disabled:opacity-40 disabled:cursor-not-allowed transition-colors font-medium\"\n >\n {tr(\"export.history.pagination.next\", \"Next\")}\n <ChevronRight size={16} />\n </button>\n </div>\n </div>\n )}\n </>\n ) : (\n <EmptyState\n icon={hasActiveFilters ? <Search size={48} /> : <Clock size={48} />}\n title={\n hasActiveFilters\n ? tr(\n \"export.history.empty.filtered.title\",\n \"No matching exports\",\n )\n : tr(\"export.history.empty.title\", \"No exports yet\")\n }\n description={\n hasActiveFilters\n ? tr(\n \"export.history.empty.filtered.description\",\n \"Try adjusting your search or filters.\",\n )\n : tr(\n \"export.history.empty.description\",\n \"Create your first export to see it here.\",\n )\n }\n action={\n hasActiveFilters ? (\n <button\n type=\"button\"\n onClick={handleResetFilters}\n className=\"inline-flex items-center gap-2 px-4 py-2 border-2 border-border rounded-lg hover:bg-accent transition-colors font-medium\"\n >\n <X size={16} />\n {tr(\n \"export.history.empty.filtered.actions.clear\",\n \"Clear Filters\",\n )}\n </button>\n ) : (\n <button\n type=\"button\"\n onClick={() => navigate?.(joinPath(basePath, \"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 <Download size={16} />\n {tr(\n \"export.history.empty.actions.createFirst\",\n \"Create First Export\",\n )}\n </button>\n )\n }\n />\n ))}\n </PageLayout>\n );\n}\n"],"mappings":"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"}