@burdenoff/microfe-export 2026.1013.2 → 2026.1023.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.
- package/dist/export/hooks/useExportQueries.d.ts.map +1 -1
- package/dist/export/hooks/useExportQueries.js +121 -100
- package/dist/export/hooks/useExportQueries.js.map +1 -1
- package/dist/export/pages/ExportTemplatesPage.js +2 -2
- package/dist/export/pages/ExportTemplatesPage.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useExportQueries.d.ts","sourceRoot":"","sources":["../../../src/export/hooks/useExportQueries.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"useExportQueries.d.ts","sourceRoot":"","sources":["../../../src/export/hooks/useExportQueries.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,106 +2,107 @@ import { useExport as e } from "../providers/ExportProvider.js";
|
|
|
2
2
|
import { CancelExportJobDocument as t, CreateExportJobDocument as n, CreateExportTemplateDocument as r, DeleteExportJobDocument as i, DeleteExportTemplateDocument as a, ExportJobProgressDocument as o, GetAvailableExportEntitiesDocument as s, GetExportJobDocument as c, GetExportTemplateDocument as l, ListExportJobsDocument as u, ListExportTemplatesDocument as d, RetryExportJobDocument as f } from "../../generated/wspace-operations.js";
|
|
3
3
|
import { ExportFormat as p, ExportJobStatus as m, ExportScope as h } from "../../generated/wspace-types.js";
|
|
4
4
|
import { emitExportEvent as g } from "../utils/events.js";
|
|
5
|
-
import {
|
|
5
|
+
import { useEffect as _, useRef as v } from "react";
|
|
6
|
+
import { useMutation as y, useQuery as b, useSubscription as x } from "@apollo/client/react";
|
|
6
7
|
//#region src/export/hooks/useExportQueries.ts
|
|
7
|
-
function
|
|
8
|
+
function S(e) {
|
|
8
9
|
return e ?? void 0;
|
|
9
10
|
}
|
|
10
|
-
function
|
|
11
|
+
function C(e) {
|
|
11
12
|
if (e == null) return;
|
|
12
13
|
let t = typeof e == "number" ? e : Number(e);
|
|
13
14
|
return Number.isFinite(t) ? t : void 0;
|
|
14
15
|
}
|
|
15
|
-
function
|
|
16
|
-
return
|
|
16
|
+
function w(e) {
|
|
17
|
+
return C(e) ?? 0;
|
|
17
18
|
}
|
|
18
|
-
function
|
|
19
|
+
function T(e) {
|
|
19
20
|
return e && typeof e == "object" && !Array.isArray(e) ? e : void 0;
|
|
20
21
|
}
|
|
21
|
-
function
|
|
22
|
+
function E(e) {
|
|
22
23
|
return {
|
|
23
24
|
hasNextPage: e.hasNextPage,
|
|
24
25
|
hasPreviousPage: e.hasPreviousPage,
|
|
25
|
-
startCursor:
|
|
26
|
-
endCursor:
|
|
26
|
+
startCursor: S(e.startCursor),
|
|
27
|
+
endCursor: S(e.endCursor)
|
|
27
28
|
};
|
|
28
29
|
}
|
|
29
|
-
function
|
|
30
|
+
function D(e) {
|
|
30
31
|
return {
|
|
31
32
|
id: e.id,
|
|
32
|
-
jobId:
|
|
33
|
+
jobId: S(e.jobId),
|
|
33
34
|
partNumber: e.partNumber,
|
|
34
35
|
fileName: e.fileName,
|
|
35
|
-
sizeBytes:
|
|
36
|
+
sizeBytes: w(e.sizeBytes),
|
|
36
37
|
entityTypes: e.entityTypes,
|
|
37
|
-
downloadUrl:
|
|
38
|
-
downloadExpiresAt:
|
|
39
|
-
checksum:
|
|
40
|
-
createdAt:
|
|
38
|
+
downloadUrl: S(e.downloadUrl),
|
|
39
|
+
downloadExpiresAt: S(e.downloadExpiresAt),
|
|
40
|
+
checksum: S(e.checksum),
|
|
41
|
+
createdAt: S(e.createdAt)
|
|
41
42
|
};
|
|
42
43
|
}
|
|
43
|
-
function
|
|
44
|
+
function O(e) {
|
|
44
45
|
return {
|
|
45
46
|
id: e.id,
|
|
46
47
|
name: e.name,
|
|
47
|
-
description:
|
|
48
|
+
description: S(e.description),
|
|
48
49
|
status: e.status,
|
|
49
50
|
progress: e.progress,
|
|
50
51
|
exportScope: e.exportScope ? e.exportScope : void 0,
|
|
51
|
-
organizationId:
|
|
52
|
+
organizationId: S(e.organizationId),
|
|
52
53
|
targetWorkspaceIds: e.targetWorkspaceIds ?? void 0,
|
|
53
54
|
entityTypes: e.entityTypes,
|
|
54
55
|
format: e.format,
|
|
55
56
|
archiveFormat: e.archiveFormat ?? "ZIP",
|
|
56
|
-
totalEntities:
|
|
57
|
-
processedEntities:
|
|
58
|
-
totalSizeBytes:
|
|
59
|
-
parts: e.parts?.map(
|
|
60
|
-
templateId:
|
|
61
|
-
filters:
|
|
62
|
-
errorMessage:
|
|
63
|
-
startedAt:
|
|
64
|
-
completedAt:
|
|
65
|
-
expiresAt:
|
|
57
|
+
totalEntities: C(e.totalEntities),
|
|
58
|
+
processedEntities: C(e.processedEntities),
|
|
59
|
+
totalSizeBytes: C(e.totalSizeBytes),
|
|
60
|
+
parts: e.parts?.map(D) ?? [],
|
|
61
|
+
templateId: S(e.templateId),
|
|
62
|
+
filters: T(e.entityFilters),
|
|
63
|
+
errorMessage: S(e.errorMessage),
|
|
64
|
+
startedAt: S(e.startedAt),
|
|
65
|
+
completedAt: S(e.completedAt),
|
|
66
|
+
expiresAt: S(e.expiresAt),
|
|
66
67
|
createdBy: e.createdBy,
|
|
67
|
-
temporalWorkflowId:
|
|
68
|
-
workspaceId:
|
|
68
|
+
temporalWorkflowId: S(e.temporalWorkflowId),
|
|
69
|
+
workspaceId: S(e.workspaceId),
|
|
69
70
|
createdAt: e.createdAt,
|
|
70
71
|
updatedAt: e.updatedAt
|
|
71
72
|
};
|
|
72
73
|
}
|
|
73
|
-
function
|
|
74
|
+
function k(e) {
|
|
74
75
|
return {
|
|
75
76
|
id: e.id,
|
|
76
77
|
name: e.name,
|
|
77
|
-
description:
|
|
78
|
+
description: S(e.description),
|
|
78
79
|
entityTypes: e.entityTypes,
|
|
79
80
|
format: e.format,
|
|
80
|
-
filters:
|
|
81
|
+
filters: T(e.entityFilters),
|
|
81
82
|
isDefault: e.isDefault,
|
|
82
83
|
createdBy: e.createdBy,
|
|
83
|
-
workspaceId:
|
|
84
|
+
workspaceId: S(e.workspaceId),
|
|
84
85
|
createdAt: e.createdAt,
|
|
85
86
|
updatedAt: e.updatedAt
|
|
86
87
|
};
|
|
87
88
|
}
|
|
88
|
-
function
|
|
89
|
+
function A(e) {
|
|
89
90
|
return {
|
|
90
91
|
entityType: e.entityType,
|
|
91
92
|
displayName: e.displayName,
|
|
92
|
-
description:
|
|
93
|
-
estimatedSize:
|
|
93
|
+
description: S(e.description),
|
|
94
|
+
estimatedSize: S(e.estimatedSize),
|
|
94
95
|
supportsDateRange: e.supportsDateRange,
|
|
95
96
|
supportsMediaExport: e.supportsMediaExport,
|
|
96
97
|
enabled: e.enabled
|
|
97
98
|
};
|
|
98
99
|
}
|
|
99
|
-
function
|
|
100
|
+
function j(e) {
|
|
100
101
|
if (e === "CSV") return p.Csv;
|
|
101
102
|
if (e === "JSON") return p.Json;
|
|
102
103
|
throw Error(`Unsupported export format: ${e}`);
|
|
103
104
|
}
|
|
104
|
-
function
|
|
105
|
+
function M(e) {
|
|
105
106
|
switch (e) {
|
|
106
107
|
case "CANCELLED": return m.Cancelled;
|
|
107
108
|
case "COMPLETED": return m.Completed;
|
|
@@ -114,7 +115,7 @@ function A(e) {
|
|
|
114
115
|
default: throw Error(`Unsupported export status: ${e}`);
|
|
115
116
|
}
|
|
116
117
|
}
|
|
117
|
-
function
|
|
118
|
+
function N(e) {
|
|
118
119
|
switch (e) {
|
|
119
120
|
case "INDIVIDUAL": return h.Individual;
|
|
120
121
|
case "WORKSPACE_ADMIN": return h.WorkspaceAdmin;
|
|
@@ -122,12 +123,12 @@ function j(e) {
|
|
|
122
123
|
default: throw Error(`Unsupported export scope: ${e}`);
|
|
123
124
|
}
|
|
124
125
|
}
|
|
125
|
-
function
|
|
126
|
-
let { workspaceId: r } = e(), { data: i, loading: a, error: o, refetch: s } =
|
|
126
|
+
function P(t, n) {
|
|
127
|
+
let { workspaceId: r } = e(), { data: i, loading: a, error: o, refetch: s } = b(u, {
|
|
127
128
|
variables: {
|
|
128
129
|
filter: t && r ? {
|
|
129
|
-
status: t.status && t.status !== "all" ? [
|
|
130
|
-
format: t.format && t.format !== "all" ?
|
|
130
|
+
status: t.status && t.status !== "all" ? [M(t.status)] : void 0,
|
|
131
|
+
format: t.format && t.format !== "all" ? j(t.format) : void 0,
|
|
131
132
|
search: t.search ?? void 0
|
|
132
133
|
} : void 0,
|
|
133
134
|
pagination: n,
|
|
@@ -136,16 +137,16 @@ function M(t, n) {
|
|
|
136
137
|
skip: !r
|
|
137
138
|
});
|
|
138
139
|
return {
|
|
139
|
-
data: i?.listExportJobs.edges.map((e) =>
|
|
140
|
+
data: i?.listExportJobs.edges.map((e) => O(e.node)) ?? [],
|
|
140
141
|
totalCount: i?.listExportJobs.totalCount ?? 0,
|
|
141
|
-
pageInfo: i?.listExportJobs.pageInfo ?
|
|
142
|
+
pageInfo: i?.listExportJobs.pageInfo ? E(i.listExportJobs.pageInfo) : null,
|
|
142
143
|
isLoading: a,
|
|
143
144
|
error: o ?? null,
|
|
144
145
|
refetch: s
|
|
145
146
|
};
|
|
146
147
|
}
|
|
147
|
-
function
|
|
148
|
-
let { workspaceId: n } = e(), { data: r, loading: i, error: a, refetch: o } =
|
|
148
|
+
function F(t) {
|
|
149
|
+
let { workspaceId: n } = e(), { data: r, loading: i, error: a, refetch: o } = b(c, {
|
|
149
150
|
variables: {
|
|
150
151
|
id: t ?? "",
|
|
151
152
|
context: { workspaceId: n }
|
|
@@ -153,57 +154,77 @@ function N(t) {
|
|
|
153
154
|
skip: !t || !n
|
|
154
155
|
});
|
|
155
156
|
return {
|
|
156
|
-
data: r?.getExportJob ?
|
|
157
|
+
data: r?.getExportJob ? O(r.getExportJob) : null,
|
|
157
158
|
isLoading: i,
|
|
158
159
|
error: a ?? null,
|
|
159
160
|
refetch: o
|
|
160
161
|
};
|
|
161
162
|
}
|
|
162
|
-
function
|
|
163
|
-
let { data: t, loading: n, error: r } =
|
|
163
|
+
function I(e) {
|
|
164
|
+
let { data: t, loading: n, error: r } = x(o, {
|
|
164
165
|
variables: { jobId: e ?? "" },
|
|
165
166
|
skip: !e
|
|
166
167
|
});
|
|
167
168
|
return {
|
|
168
|
-
data: t?.exportJobProgress ?
|
|
169
|
+
data: t?.exportJobProgress ? O(t.exportJobProgress) : null,
|
|
169
170
|
isLoading: n,
|
|
170
171
|
error: r ?? null
|
|
171
172
|
};
|
|
172
173
|
}
|
|
173
|
-
function
|
|
174
|
-
|
|
174
|
+
function L(e, { fetchMoreResult: t }) {
|
|
175
|
+
return t ? { getAvailableExportEntities: {
|
|
176
|
+
...t.getAvailableExportEntities,
|
|
177
|
+
edges: [...e.getAvailableExportEntities.edges, ...t.getAvailableExportEntities.edges]
|
|
178
|
+
} } : e;
|
|
179
|
+
}
|
|
180
|
+
function R(t) {
|
|
181
|
+
let { workspaceId: n } = e(), r = t ?? n, { data: i, loading: a, error: o, refetch: c, fetchMore: l } = b(s, {
|
|
175
182
|
variables: {
|
|
176
183
|
context: { workspaceId: r },
|
|
177
184
|
pagination: { first: 100 }
|
|
178
185
|
},
|
|
179
186
|
skip: !r
|
|
180
|
-
}), u = i?.getAvailableExportEntities
|
|
181
|
-
|
|
182
|
-
|
|
187
|
+
}), u = i?.getAvailableExportEntities, d = u?.edges.map((e) => A(e.node)) ?? [], f = async () => {
|
|
188
|
+
!r || !u?.pageInfo.hasNextPage || await l({
|
|
189
|
+
variables: {
|
|
190
|
+
context: { workspaceId: r },
|
|
191
|
+
pagination: {
|
|
192
|
+
first: 100,
|
|
193
|
+
after: u.pageInfo.endCursor
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
updateQuery: L
|
|
197
|
+
});
|
|
198
|
+
}, p = u?.pageInfo.hasNextPage ?? !1, m = u?.pageInfo.endCursor ?? null, h = v(null);
|
|
199
|
+
return _(() => {
|
|
200
|
+
a || !r || !p || !m || h.current !== m && (h.current = m, l({
|
|
201
|
+
variables: {
|
|
202
|
+
context: { workspaceId: r },
|
|
203
|
+
pagination: {
|
|
204
|
+
first: 100,
|
|
205
|
+
after: m
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
updateQuery: L
|
|
209
|
+
}));
|
|
210
|
+
}, [
|
|
211
|
+
a,
|
|
212
|
+
r,
|
|
213
|
+
p,
|
|
214
|
+
m,
|
|
215
|
+
l
|
|
216
|
+
]), {
|
|
217
|
+
data: d,
|
|
183
218
|
totalCount: u?.totalCount ?? 0,
|
|
184
|
-
pageInfo: u?.pageInfo ?
|
|
185
|
-
loadMore:
|
|
186
|
-
!r || !u?.pageInfo.hasNextPage || await l({
|
|
187
|
-
variables: {
|
|
188
|
-
context: { workspaceId: r },
|
|
189
|
-
pagination: {
|
|
190
|
-
first: 100,
|
|
191
|
-
after: u.pageInfo.endCursor
|
|
192
|
-
}
|
|
193
|
-
},
|
|
194
|
-
updateQuery: (e, { fetchMoreResult: t }) => t ? { getAvailableExportEntities: {
|
|
195
|
-
...t.getAvailableExportEntities,
|
|
196
|
-
edges: [...e.getAvailableExportEntities.edges, ...t.getAvailableExportEntities.edges]
|
|
197
|
-
} } : e
|
|
198
|
-
});
|
|
199
|
-
},
|
|
219
|
+
pageInfo: u?.pageInfo ? E(u.pageInfo) : null,
|
|
220
|
+
loadMore: f,
|
|
200
221
|
error: o ?? null,
|
|
201
222
|
isLoading: a,
|
|
202
223
|
refetch: c
|
|
203
224
|
};
|
|
204
225
|
}
|
|
205
|
-
function
|
|
206
|
-
let { workspaceId: n } = e(), r = t ?? n, { data: i, loading: a, error: o, refetch: s, fetchMore: c } =
|
|
226
|
+
function z(t) {
|
|
227
|
+
let { workspaceId: n } = e(), r = t ?? n, { data: i, loading: a, error: o, refetch: s, fetchMore: c } = b(d, {
|
|
207
228
|
variables: {
|
|
208
229
|
context: { workspaceId: r },
|
|
209
230
|
pagination: { first: 50 }
|
|
@@ -211,9 +232,9 @@ function I(t) {
|
|
|
211
232
|
skip: !r
|
|
212
233
|
}), l = i?.listExportTemplates;
|
|
213
234
|
return {
|
|
214
|
-
data: l?.edges.map((e) =>
|
|
235
|
+
data: l?.edges.map((e) => k(e.node)) ?? [],
|
|
215
236
|
totalCount: l?.totalCount ?? 0,
|
|
216
|
-
pageInfo: l?.pageInfo ?
|
|
237
|
+
pageInfo: l?.pageInfo ? E(l.pageInfo) : null,
|
|
217
238
|
loadMore: async () => {
|
|
218
239
|
!r || !l?.pageInfo.hasNextPage || await c({
|
|
219
240
|
variables: {
|
|
@@ -234,8 +255,8 @@ function I(t) {
|
|
|
234
255
|
refetch: s
|
|
235
256
|
};
|
|
236
257
|
}
|
|
237
|
-
function
|
|
238
|
-
let { workspaceId: n } = e(), { data: r, loading: i, error: a } =
|
|
258
|
+
function B(t) {
|
|
259
|
+
let { workspaceId: n } = e(), { data: r, loading: i, error: a } = b(l, {
|
|
239
260
|
variables: {
|
|
240
261
|
id: t ?? "",
|
|
241
262
|
context: { workspaceId: n }
|
|
@@ -243,17 +264,17 @@ function L(t) {
|
|
|
243
264
|
skip: !t || !n
|
|
244
265
|
});
|
|
245
266
|
return {
|
|
246
|
-
data: r?.getExportTemplate ?
|
|
267
|
+
data: r?.getExportTemplate ? k(r.getExportTemplate) : null,
|
|
247
268
|
isLoading: i,
|
|
248
269
|
error: a ?? null
|
|
249
270
|
};
|
|
250
271
|
}
|
|
251
|
-
function
|
|
252
|
-
let t = e(), { workspaceId: r } = t, [i, { loading: a, error: o }] =
|
|
272
|
+
function V() {
|
|
273
|
+
let t = e(), { workspaceId: r } = t, [i, { loading: a, error: o }] = y(n), s = async (e) => {
|
|
253
274
|
let { filters: n, ...a } = e, o = {
|
|
254
275
|
...a,
|
|
255
|
-
exportScope: a.exportScope ?
|
|
256
|
-
format:
|
|
276
|
+
exportScope: a.exportScope ? N(a.exportScope) : void 0,
|
|
277
|
+
format: j(a.format),
|
|
257
278
|
entityFilters: n
|
|
258
279
|
}, s = await i({
|
|
259
280
|
variables: {
|
|
@@ -266,7 +287,7 @@ function R() {
|
|
|
266
287
|
}]
|
|
267
288
|
});
|
|
268
289
|
if (!s.data) throw g(t, "export.api.failed", { operation: "createExportJob" }), Error("Failed to create export job");
|
|
269
|
-
return g(t, "export.job.created", { jobId: s.data.createExportJob.id }),
|
|
290
|
+
return g(t, "export.job.created", { jobId: s.data.createExportJob.id }), O(s.data.createExportJob);
|
|
270
291
|
};
|
|
271
292
|
return {
|
|
272
293
|
createJob: s,
|
|
@@ -277,8 +298,8 @@ function R() {
|
|
|
277
298
|
error: o ?? null
|
|
278
299
|
};
|
|
279
300
|
}
|
|
280
|
-
function
|
|
281
|
-
let n = e(), { workspaceId: r } = n, [i, { loading: a, error: o }] =
|
|
301
|
+
function H() {
|
|
302
|
+
let n = e(), { workspaceId: r } = n, [i, { loading: a, error: o }] = y(t), s = async (e) => {
|
|
282
303
|
let t = await i({
|
|
283
304
|
variables: {
|
|
284
305
|
id: e,
|
|
@@ -304,8 +325,8 @@ function z() {
|
|
|
304
325
|
error: o ?? null
|
|
305
326
|
};
|
|
306
327
|
}
|
|
307
|
-
function
|
|
308
|
-
let t = e(), { workspaceId: n } = t, [r, { loading: a, error: o }] =
|
|
328
|
+
function U() {
|
|
329
|
+
let t = e(), { workspaceId: n } = t, [r, { loading: a, error: o }] = y(i), s = async (e) => (await r({
|
|
309
330
|
variables: {
|
|
310
331
|
id: e,
|
|
311
332
|
context: { workspaceId: n }
|
|
@@ -324,8 +345,8 @@ function B() {
|
|
|
324
345
|
error: o ?? null
|
|
325
346
|
};
|
|
326
347
|
}
|
|
327
|
-
function
|
|
328
|
-
let t = e(), { workspaceId: n } = t, [r, { loading: i, error: a }] =
|
|
348
|
+
function W() {
|
|
349
|
+
let t = e(), { workspaceId: n } = t, [r, { loading: i, error: a }] = y(f);
|
|
329
350
|
return {
|
|
330
351
|
retryJob: async (e) => {
|
|
331
352
|
let i = await r({
|
|
@@ -345,20 +366,20 @@ function V() {
|
|
|
345
366
|
return g(t, "export.job.retried", {
|
|
346
367
|
originalJobId: e,
|
|
347
368
|
jobId: i.data.retryExportJob.id
|
|
348
|
-
}),
|
|
369
|
+
}), O(i.data.retryExportJob);
|
|
349
370
|
},
|
|
350
371
|
loading: i,
|
|
351
372
|
isPending: i,
|
|
352
373
|
error: a ?? null
|
|
353
374
|
};
|
|
354
375
|
}
|
|
355
|
-
function
|
|
356
|
-
let t = e(), { workspaceId: n } = t, [i, { loading: a, error: o }] =
|
|
376
|
+
function G() {
|
|
377
|
+
let t = e(), { workspaceId: n } = t, [i, { loading: a, error: o }] = y(r);
|
|
357
378
|
return {
|
|
358
379
|
createTemplate: async (e) => {
|
|
359
380
|
let r = {
|
|
360
381
|
...e,
|
|
361
|
-
format:
|
|
382
|
+
format: j(e.format)
|
|
362
383
|
}, a = await i({
|
|
363
384
|
variables: {
|
|
364
385
|
context: { workspaceId: n },
|
|
@@ -370,15 +391,15 @@ function H() {
|
|
|
370
391
|
}]
|
|
371
392
|
});
|
|
372
393
|
if (!a.data) throw g(t, "export.api.failed", { operation: "createExportTemplate" }), Error("Failed to create export template");
|
|
373
|
-
return g(t, "export.template.created", { templateId: a.data.createExportTemplate.id }),
|
|
394
|
+
return g(t, "export.template.created", { templateId: a.data.createExportTemplate.id }), k(a.data.createExportTemplate);
|
|
374
395
|
},
|
|
375
396
|
loading: a,
|
|
376
397
|
isPending: a,
|
|
377
398
|
error: o ?? null
|
|
378
399
|
};
|
|
379
400
|
}
|
|
380
|
-
function
|
|
381
|
-
let t = e(), { workspaceId: n } = t, [r, { loading: i, error: o }] =
|
|
401
|
+
function K() {
|
|
402
|
+
let t = e(), { workspaceId: n } = t, [r, { loading: i, error: o }] = y(a);
|
|
382
403
|
return {
|
|
383
404
|
deleteTemplate: async (e) => (await r({
|
|
384
405
|
variables: {
|
|
@@ -396,6 +417,6 @@ function U() {
|
|
|
396
417
|
};
|
|
397
418
|
}
|
|
398
419
|
//#endregion
|
|
399
|
-
export {
|
|
420
|
+
export { R as useAvailableEntities, H as useCancelExportJob, V as useCreateExportJob, G as useCreateExportTemplate, U as useDeleteExportJob, K as useDeleteExportTemplate, F as useExportJob, I as useExportJobProgress, P as useExportJobs, B as useExportTemplate, z as useExportTemplates, W as useRetryExportJob };
|
|
400
421
|
|
|
401
422
|
//# sourceMappingURL=useExportQueries.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useExportQueries.js","names":[],"sources":["../../../src/export/hooks/useExportQueries.ts"],"sourcesContent":["/**\n * Export Query Hooks\n *\n * Real Apollo Client hooks for all export operations.\n * Keep these documents in sync with src/operations/wspace/export/*.graphql.\n */\n\nimport { useMutation, useQuery, useSubscription } from \"@apollo/client/react\";\nimport {\n CancelExportJobDocument,\n CreateExportJobDocument,\n CreateExportTemplateDocument,\n DeleteExportJobDocument,\n DeleteExportTemplateDocument,\n ExportJobProgressDocument,\n GetAvailableExportEntitiesDocument,\n GetExportJobDocument,\n GetExportTemplateDocument,\n ListExportJobsDocument,\n ListExportTemplatesDocument,\n RetryExportJobDocument,\n type CancelExportJobMutation,\n type CancelExportJobMutationVariables,\n type CreateExportJobMutation,\n type CreateExportJobMutationVariables,\n type CreateExportTemplateMutation,\n type CreateExportTemplateMutationVariables,\n type DeleteExportJobMutation,\n type DeleteExportJobMutationVariables,\n type DeleteExportTemplateMutation,\n type DeleteExportTemplateMutationVariables,\n type ExportJobProgressSubscription,\n type ExportJobProgressSubscriptionVariables,\n type GetAvailableExportEntitiesQuery,\n type GetAvailableExportEntitiesQueryVariables,\n type GetExportJobQuery,\n type GetExportJobQueryVariables,\n type GetExportTemplateQuery,\n type GetExportTemplateQueryVariables,\n type ListExportJobsQuery,\n type ListExportJobsQueryVariables,\n type ListExportTemplatesQuery,\n type ListExportTemplatesQueryVariables,\n type RetryExportJobMutation,\n type RetryExportJobMutationVariables,\n} from \"../../generated/wspace-operations\";\nimport {\n ExportFormat as GqlExportFormat,\n ExportJobStatus as GqlExportJobStatus,\n ExportScope as GqlExportScope,\n type CreateExportJobInput as GqlCreateExportJobInput,\n type CreateExportTemplateInput as GqlCreateExportTemplateInput,\n type ExportJobFilterInput as GqlExportJobFilterInput,\n type ExportPaginationInput as GqlExportPaginationInput,\n} from \"../../generated/wspace-types\";\nimport { useExport } from \"../providers/ExportProvider\";\nimport { emitExportEvent } from \"../utils/events\";\nimport type {\n ExportArchiveFormat,\n ExportFormat,\n ExportJob,\n ExportJobStatus,\n ExportScope,\n ExportTemplate,\n ExportAvailableEntity,\n ExportPart,\n ExportFilter,\n PageInfo,\n} from \"../types\";\n\n// ---------------------------------------------------------------------------\n// Mapping helpers\n// ---------------------------------------------------------------------------\n\ntype Nullable<T> = T | null | undefined;\n\ninterface ExportPartLike {\n id: string;\n jobId?: Nullable<string>;\n partNumber: number;\n fileName: string;\n sizeBytes: number | string;\n entityTypes: string[];\n downloadUrl?: Nullable<string>;\n downloadExpiresAt?: Nullable<string>;\n checksum?: Nullable<string>;\n createdAt?: Nullable<string>;\n}\n\ninterface ExportJobLike {\n id: string;\n name: string;\n description?: Nullable<string>;\n status: string;\n progress: number;\n exportScope?: Nullable<string>;\n organizationId?: Nullable<string>;\n targetWorkspaceIds?: Nullable<string[]>;\n entityTypes: string[];\n format: string;\n archiveFormat?: Nullable<string>;\n totalEntities?: Nullable<number>;\n processedEntities?: Nullable<number>;\n totalSizeBytes?: Nullable<number | string>;\n parts?: Nullable<ExportPartLike[]>;\n templateId?: Nullable<string>;\n entityFilters?: Nullable<Record<string, unknown>>;\n errorMessage?: Nullable<string>;\n startedAt?: Nullable<string>;\n completedAt?: Nullable<string>;\n expiresAt?: Nullable<string>;\n createdBy: string;\n temporalWorkflowId?: Nullable<string>;\n workspaceId?: Nullable<string>;\n createdAt: string;\n updatedAt: string;\n}\n\ninterface ExportTemplateLike {\n id: string;\n name: string;\n description?: Nullable<string>;\n entityTypes: string[];\n format: string;\n entityFilters?: Nullable<Record<string, unknown>>;\n isDefault: boolean;\n workspaceId?: Nullable<string>;\n createdBy: string;\n createdAt: string;\n updatedAt: string;\n}\n\ninterface ExportAvailableEntityLike {\n entityType: string;\n displayName: string;\n description?: Nullable<string>;\n estimatedSize?: Nullable<string>;\n supportsDateRange: boolean;\n supportsMediaExport: boolean;\n enabled: boolean;\n}\n\nfunction optionalString(value: Nullable<string>): string | undefined {\n return value ?? undefined;\n}\n\nfunction optionalNumber(value: Nullable<number | string>): number | undefined {\n if (value == null) return undefined;\n const parsed = typeof value === \"number\" ? value : Number(value);\n return Number.isFinite(parsed) ? parsed : undefined;\n}\n\nfunction numberOrZero(value: Nullable<number | string>): number {\n return optionalNumber(value) ?? 0;\n}\n\nfunction optionalRecord(\n value: Nullable<Record<string, unknown>>,\n): Record<string, unknown> | undefined {\n return value && typeof value === \"object\" && !Array.isArray(value)\n ? value\n : undefined;\n}\n\nfunction mapPageInfo(pageInfo: {\n hasNextPage: boolean;\n hasPreviousPage: boolean;\n startCursor?: Nullable<string>;\n endCursor?: Nullable<string>;\n}): PageInfo {\n return {\n hasNextPage: pageInfo.hasNextPage,\n hasPreviousPage: pageInfo.hasPreviousPage,\n startCursor: optionalString(pageInfo.startCursor),\n endCursor: optionalString(pageInfo.endCursor),\n };\n}\n\nfunction mapPart(part: ExportPartLike): ExportPart {\n return {\n id: part.id,\n jobId: optionalString(part.jobId),\n partNumber: part.partNumber,\n fileName: part.fileName,\n sizeBytes: numberOrZero(part.sizeBytes),\n entityTypes: part.entityTypes,\n downloadUrl: optionalString(part.downloadUrl),\n downloadExpiresAt: optionalString(part.downloadExpiresAt),\n checksum: optionalString(part.checksum),\n createdAt: optionalString(part.createdAt),\n };\n}\n\nfunction mapJob(job: ExportJobLike): ExportJob {\n return {\n id: job.id,\n name: job.name,\n description: optionalString(job.description),\n status: job.status as ExportJobStatus,\n progress: job.progress,\n exportScope: job.exportScope ? (job.exportScope as ExportScope) : undefined,\n organizationId: optionalString(job.organizationId),\n targetWorkspaceIds: job.targetWorkspaceIds ?? undefined,\n entityTypes: job.entityTypes,\n format: job.format as ExportFormat,\n archiveFormat: (job.archiveFormat ?? \"ZIP\") as ExportArchiveFormat,\n totalEntities: optionalNumber(job.totalEntities),\n processedEntities: optionalNumber(job.processedEntities),\n totalSizeBytes: optionalNumber(job.totalSizeBytes),\n parts: job.parts?.map(mapPart) ?? [],\n templateId: optionalString(job.templateId),\n filters: optionalRecord(job.entityFilters),\n errorMessage: optionalString(job.errorMessage),\n startedAt: optionalString(job.startedAt),\n completedAt: optionalString(job.completedAt),\n expiresAt: optionalString(job.expiresAt),\n createdBy: job.createdBy,\n temporalWorkflowId: optionalString(job.temporalWorkflowId),\n workspaceId: optionalString(job.workspaceId),\n createdAt: job.createdAt,\n updatedAt: job.updatedAt,\n };\n}\n\nfunction mapTemplate(template: ExportTemplateLike): ExportTemplate {\n return {\n id: template.id,\n name: template.name,\n description: optionalString(template.description),\n entityTypes: template.entityTypes,\n format: template.format as ExportFormat,\n filters: optionalRecord(template.entityFilters),\n isDefault: template.isDefault,\n createdBy: template.createdBy,\n workspaceId: optionalString(template.workspaceId),\n createdAt: template.createdAt,\n updatedAt: template.updatedAt,\n };\n}\n\nfunction mapAvailableEntity(\n entity: ExportAvailableEntityLike,\n): ExportAvailableEntity {\n return {\n entityType: entity.entityType,\n displayName: entity.displayName,\n description: optionalString(entity.description),\n estimatedSize: optionalString(entity.estimatedSize),\n supportsDateRange: entity.supportsDateRange,\n supportsMediaExport: entity.supportsMediaExport,\n enabled: entity.enabled,\n };\n}\n\nfunction toGqlFormat(format: ExportFormat | string): GqlExportFormat {\n if (format === \"CSV\") return GqlExportFormat.Csv;\n if (format === \"JSON\") return GqlExportFormat.Json;\n throw new Error(`Unsupported export format: ${format}`);\n}\n\nfunction toGqlStatus(status: ExportJobStatus | string): GqlExportJobStatus {\n switch (status) {\n case \"CANCELLED\":\n return GqlExportJobStatus.Cancelled;\n case \"COMPLETED\":\n return GqlExportJobStatus.Completed;\n case \"CREATED\":\n return GqlExportJobStatus.Created;\n case \"DELETED\":\n return GqlExportJobStatus.Deleted;\n case \"EXPIRED\":\n return GqlExportJobStatus.Expired;\n case \"FAILED\":\n return GqlExportJobStatus.Failed;\n case \"QUEUED\":\n return GqlExportJobStatus.Queued;\n case \"RUNNING\":\n return GqlExportJobStatus.Running;\n default:\n throw new Error(`Unsupported export status: ${status}`);\n }\n}\n\nfunction toGqlScope(scope: ExportScope | string): GqlExportScope {\n switch (scope) {\n case \"INDIVIDUAL\":\n return GqlExportScope.Individual;\n case \"WORKSPACE_ADMIN\":\n return GqlExportScope.WorkspaceAdmin;\n case \"ORG_ADMIN\":\n return GqlExportScope.OrgAdmin;\n default:\n throw new Error(`Unsupported export scope: ${scope}`);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Query Hooks\n// ---------------------------------------------------------------------------\n\n/**\n * Input for creating an export job\n */\nexport interface CreateExportJobInput {\n name: string;\n description?: string;\n exportScope?: ExportScope;\n organizationId?: string;\n entityTypes: string[];\n format: ExportFormat;\n filters?: Record<string, unknown>;\n templateId?: string;\n dateRangeStart?: string | null;\n dateRangeEnd?: string | null;\n}\n\n/**\n * Input for creating an export template\n */\nexport interface CreateExportTemplateInput {\n name: string;\n description?: string;\n entityTypes: string[];\n format: ExportFormat;\n}\n\n/**\n * Filter input for listing export jobs\n */\nexport interface ExportJobFilterInput {\n status?: ExportJobStatus[];\n format?: ExportFormat;\n entityTypes?: string[];\n search?: string;\n dateFrom?: string;\n dateTo?: string;\n}\n\n/**\n * Pagination input for export job list\n */\nexport interface ExportPaginationInput {\n first?: number;\n after?: string;\n last?: number;\n before?: string;\n}\n\n/**\n * Hook to fetch a paginated list of export jobs\n */\nexport function useExportJobs(\n filter?: Partial<ExportFilter>,\n pagination?: ExportPaginationInput,\n) {\n const { workspaceId } = useExport();\n\n // Build the backend filter from the UI filter shape\n const backendFilter: GqlExportJobFilterInput | undefined =\n filter && workspaceId\n ? {\n status:\n filter.status && filter.status !== \"all\"\n ? [toGqlStatus(filter.status)]\n : undefined,\n format:\n filter.format && filter.format !== \"all\"\n ? toGqlFormat(filter.format)\n : undefined,\n search: filter.search ?? undefined,\n }\n : undefined;\n\n const { data, loading, error, refetch } = useQuery<\n ListExportJobsQuery,\n ListExportJobsQueryVariables\n >(ListExportJobsDocument, {\n variables: {\n filter: backendFilter,\n pagination: pagination as GqlExportPaginationInput | undefined,\n context: { workspaceId },\n },\n skip: !workspaceId,\n });\n\n const jobs = data?.listExportJobs.edges.map((e) => mapJob(e.node)) ?? [];\n const totalCount = data?.listExportJobs.totalCount ?? 0;\n const pageInfo = data?.listExportJobs.pageInfo\n ? mapPageInfo(data.listExportJobs.pageInfo)\n : null;\n\n return {\n data: jobs,\n totalCount,\n pageInfo,\n isLoading: loading,\n error: error ?? null,\n refetch,\n };\n}\n\n/**\n * Hook to fetch a single export job by ID.\n */\nexport function useExportJob(jobId: string | undefined) {\n const { workspaceId } = useExport();\n\n const { data, loading, error, refetch } = useQuery<\n GetExportJobQuery,\n GetExportJobQueryVariables\n >(GetExportJobDocument, {\n variables: { id: jobId ?? \"\", context: { workspaceId } },\n skip: !jobId || !workspaceId,\n });\n\n const job = data?.getExportJob ? mapJob(data.getExportJob) : null;\n\n return {\n data: job,\n isLoading: loading,\n error: error ?? null,\n refetch,\n };\n}\n\n/**\n * Hook to subscribe to live progress updates for an export job.\n */\nexport function useExportJobProgress(jobId: string | undefined) {\n const { data, loading, error } = useSubscription<\n ExportJobProgressSubscription,\n ExportJobProgressSubscriptionVariables\n >(ExportJobProgressDocument, {\n variables: { jobId: jobId ?? \"\" },\n skip: !jobId,\n });\n\n return {\n data: data?.exportJobProgress ? mapJob(data.exportJobProgress) : null,\n isLoading: loading,\n error: error ?? null,\n };\n}\n\n/**\n * Hook to fetch available entity types for export in a workspace\n */\nexport function useAvailableEntities(overrideWorkspaceId?: string) {\n const { workspaceId: ctxWorkspaceId } = useExport();\n const workspaceId = overrideWorkspaceId ?? ctxWorkspaceId;\n\n const { data, loading, error, refetch, fetchMore } = useQuery<\n GetAvailableExportEntitiesQuery,\n GetAvailableExportEntitiesQueryVariables\n >(GetAvailableExportEntitiesDocument, {\n variables: {\n context: { workspaceId },\n pagination: { first: 100 },\n },\n skip: !workspaceId,\n });\n\n const connection = data?.getAvailableExportEntities;\n const entities =\n connection?.edges.map((edge) => mapAvailableEntity(edge.node)) ?? [];\n\n const loadMore = async () => {\n if (!workspaceId || !connection?.pageInfo.hasNextPage) return;\n await fetchMore({\n variables: {\n context: { workspaceId },\n pagination: { first: 100, after: connection.pageInfo.endCursor },\n },\n updateQuery: (previous, { fetchMoreResult }) => {\n if (!fetchMoreResult) return previous;\n return {\n getAvailableExportEntities: {\n ...fetchMoreResult.getAvailableExportEntities,\n edges: [\n ...previous.getAvailableExportEntities.edges,\n ...fetchMoreResult.getAvailableExportEntities.edges,\n ],\n },\n };\n },\n });\n };\n\n return {\n data: entities,\n totalCount: connection?.totalCount ?? 0,\n pageInfo: connection?.pageInfo ? mapPageInfo(connection.pageInfo) : null,\n loadMore,\n error: error ?? null,\n isLoading: loading,\n refetch,\n };\n}\n\n/**\n * Hook to fetch all export templates for the current workspace\n */\nexport function useExportTemplates(overrideWorkspaceId?: string) {\n const { workspaceId: ctxWorkspaceId } = useExport();\n const workspaceId = overrideWorkspaceId ?? ctxWorkspaceId;\n\n const { data, loading, error, refetch, fetchMore } = useQuery<\n ListExportTemplatesQuery,\n ListExportTemplatesQueryVariables\n >(ListExportTemplatesDocument, {\n variables: {\n context: { workspaceId },\n pagination: { first: 50 },\n },\n skip: !workspaceId,\n });\n\n const connection = data?.listExportTemplates;\n const templates =\n connection?.edges.map((edge) => mapTemplate(edge.node)) ?? [];\n\n const loadMore = async () => {\n if (!workspaceId || !connection?.pageInfo.hasNextPage) return;\n await fetchMore({\n variables: {\n context: { workspaceId },\n pagination: { first: 50, after: connection.pageInfo.endCursor },\n },\n updateQuery: (previous, { fetchMoreResult }) => {\n if (!fetchMoreResult) return previous;\n return {\n listExportTemplates: {\n ...fetchMoreResult.listExportTemplates,\n edges: [\n ...previous.listExportTemplates.edges,\n ...fetchMoreResult.listExportTemplates.edges,\n ],\n },\n };\n },\n });\n };\n\n return {\n data: templates,\n totalCount: connection?.totalCount ?? 0,\n pageInfo: connection?.pageInfo ? mapPageInfo(connection.pageInfo) : null,\n loadMore,\n isLoading: loading,\n error: error ?? null,\n refetch,\n };\n}\n\n/**\n * Hook to fetch a single export template by ID\n */\nexport function useExportTemplate(templateId: string | undefined) {\n const { workspaceId } = useExport();\n\n const { data, loading, error } = useQuery<\n GetExportTemplateQuery,\n GetExportTemplateQueryVariables\n >(GetExportTemplateDocument, {\n variables: { id: templateId ?? \"\", context: { workspaceId } },\n skip: !templateId || !workspaceId,\n });\n\n return {\n data: data?.getExportTemplate ? mapTemplate(data.getExportTemplate) : null,\n isLoading: loading,\n error: error ?? null,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Mutation Hooks\n// ---------------------------------------------------------------------------\n\n/**\n * Hook to create a new export job\n */\nexport function useCreateExportJob() {\n const exportContext = useExport();\n const { workspaceId } = exportContext;\n const [mutate, { loading, error }] = useMutation<\n CreateExportJobMutation,\n CreateExportJobMutationVariables\n >(CreateExportJobDocument);\n\n const createJob = async (input: CreateExportJobInput): Promise<ExportJob> => {\n const { filters, ...restInput } = input;\n const gqlInput: GqlCreateExportJobInput = {\n ...restInput,\n exportScope: restInput.exportScope\n ? toGqlScope(restInput.exportScope)\n : undefined,\n format: toGqlFormat(restInput.format),\n entityFilters: filters,\n };\n\n const result = await mutate({\n variables: {\n context: { workspaceId },\n input: gqlInput,\n },\n refetchQueries: [\n {\n query: ListExportJobsDocument,\n variables: { context: { workspaceId } },\n },\n ],\n });\n if (!result.data) {\n emitExportEvent(exportContext, \"export.api.failed\", {\n operation: \"createExportJob\",\n });\n throw new Error(\"Failed to create export job\");\n }\n emitExportEvent(exportContext, \"export.job.created\", {\n jobId: result.data.createExportJob.id,\n });\n return mapJob(result.data.createExportJob);\n };\n\n return {\n createJob,\n // Keep legacy names for existing callers\n mutate: createJob,\n mutateAsync: createJob,\n loading,\n isPending: loading,\n error: error ?? null,\n };\n}\n\n/**\n * Hook to cancel an export job\n */\nexport function useCancelExportJob() {\n const exportContext = useExport();\n const { workspaceId } = exportContext;\n const [mutate, { loading, error }] = useMutation<\n CancelExportJobMutation,\n CancelExportJobMutationVariables\n >(CancelExportJobDocument);\n\n const cancelJob = async (id: string) => {\n const result = await mutate({\n variables: {\n id,\n context: { workspaceId },\n },\n refetchQueries: [\n {\n query: ListExportJobsDocument,\n variables: { context: { workspaceId } },\n },\n ],\n });\n if (!result.data) {\n emitExportEvent(exportContext, \"export.api.failed\", {\n operation: \"cancelExportJob\",\n jobId: id,\n });\n throw new Error(\"Failed to cancel export job\");\n }\n emitExportEvent(exportContext, \"export.job.cancelled\", { jobId: id });\n return result.data.cancelExportJob;\n };\n\n return {\n cancelJob,\n mutate: cancelJob,\n mutateAsync: cancelJob,\n loading,\n isPending: loading,\n error: error ?? null,\n };\n}\n\n/**\n * Hook to delete an export job\n */\nexport function useDeleteExportJob() {\n const exportContext = useExport();\n const { workspaceId } = exportContext;\n const [mutate, { loading, error }] = useMutation<\n DeleteExportJobMutation,\n DeleteExportJobMutationVariables\n >(DeleteExportJobDocument);\n\n const deleteJob = async (id: string): Promise<boolean> => {\n await mutate({\n variables: {\n id,\n context: { workspaceId },\n },\n refetchQueries: [\n {\n query: ListExportJobsDocument,\n variables: { context: { workspaceId } },\n },\n ],\n });\n emitExportEvent(exportContext, \"export.job.deleted\", { jobId: id });\n return true;\n };\n\n return {\n deleteJob,\n mutate: deleteJob,\n mutateAsync: deleteJob,\n loading,\n isPending: loading,\n error: error ?? null,\n };\n}\n\n/**\n * Hook to retry a failed export job\n */\nexport function useRetryExportJob() {\n const exportContext = useExport();\n const { workspaceId } = exportContext;\n const [mutate, { loading, error }] = useMutation<\n RetryExportJobMutation,\n RetryExportJobMutationVariables\n >(RetryExportJobDocument);\n\n const retryJob = async (id: string): Promise<ExportJob> => {\n const result = await mutate({\n variables: { id, context: { workspaceId } },\n refetchQueries: [\n {\n query: ListExportJobsDocument,\n variables: { context: { workspaceId } },\n },\n ],\n });\n if (!result.data) {\n emitExportEvent(exportContext, \"export.api.failed\", {\n operation: \"retryExportJob\",\n jobId: id,\n });\n throw new Error(\"Failed to retry export job\");\n }\n emitExportEvent(exportContext, \"export.job.retried\", {\n originalJobId: id,\n jobId: result.data.retryExportJob.id,\n });\n return mapJob(result.data.retryExportJob);\n };\n\n return {\n retryJob,\n loading,\n isPending: loading,\n error: error ?? null,\n };\n}\n\n/**\n * Hook to create a new export template\n */\nexport function useCreateExportTemplate() {\n const exportContext = useExport();\n const { workspaceId } = exportContext;\n const [mutate, { loading, error }] = useMutation<\n CreateExportTemplateMutation,\n CreateExportTemplateMutationVariables\n >(CreateExportTemplateDocument);\n\n const createTemplate = async (\n input: CreateExportTemplateInput,\n ): Promise<ExportTemplate> => {\n const gqlInput: GqlCreateExportTemplateInput = {\n ...input,\n format: toGqlFormat(input.format),\n };\n\n const result = await mutate({\n variables: {\n context: { workspaceId },\n input: gqlInput,\n },\n refetchQueries: [\n {\n query: ListExportTemplatesDocument,\n variables: { context: { workspaceId } },\n },\n ],\n });\n if (!result.data) {\n emitExportEvent(exportContext, \"export.api.failed\", {\n operation: \"createExportTemplate\",\n });\n throw new Error(\"Failed to create export template\");\n }\n emitExportEvent(exportContext, \"export.template.created\", {\n templateId: result.data.createExportTemplate.id,\n });\n return mapTemplate(result.data.createExportTemplate);\n };\n\n return {\n createTemplate,\n loading,\n isPending: loading,\n error: error ?? null,\n };\n}\n\n/**\n * Hook to delete an export template\n */\nexport function useDeleteExportTemplate() {\n const exportContext = useExport();\n const { workspaceId } = exportContext;\n const [mutate, { loading, error }] = useMutation<\n DeleteExportTemplateMutation,\n DeleteExportTemplateMutationVariables\n >(DeleteExportTemplateDocument);\n\n const deleteTemplate = async (id: string): Promise<boolean> => {\n await mutate({\n variables: {\n id,\n context: { workspaceId },\n },\n refetchQueries: [\n {\n query: ListExportTemplatesDocument,\n variables: { context: { workspaceId } },\n },\n ],\n });\n emitExportEvent(exportContext, \"export.template.deleted\", {\n templateId: id,\n });\n return true;\n };\n\n return {\n deleteTemplate,\n loading,\n isPending: loading,\n error: error ?? null,\n };\n}\n"],"mappings":";;;;;;AA8IA,SAAS,EAAe,GAA6C;AACnE,QAAO,KAAS,KAAA;;AAGlB,SAAS,EAAe,GAAsD;AAC5E,KAAI,KAAS,KAAM;CACnB,IAAM,IAAS,OAAO,KAAU,WAAW,IAAQ,OAAO,EAAM;AAChE,QAAO,OAAO,SAAS,EAAO,GAAG,IAAS,KAAA;;AAG5C,SAAS,EAAa,GAA0C;AAC9D,QAAO,EAAe,EAAM,IAAI;;AAGlC,SAAS,EACP,GACqC;AACrC,QAAO,KAAS,OAAO,KAAU,YAAY,CAAC,MAAM,QAAQ,EAAM,GAC9D,IACA,KAAA;;AAGN,SAAS,EAAY,GAKR;AACX,QAAO;EACL,aAAa,EAAS;EACtB,iBAAiB,EAAS;EAC1B,aAAa,EAAe,EAAS,YAAY;EACjD,WAAW,EAAe,EAAS,UAAU;EAC9C;;AAGH,SAAS,EAAQ,GAAkC;AACjD,QAAO;EACL,IAAI,EAAK;EACT,OAAO,EAAe,EAAK,MAAM;EACjC,YAAY,EAAK;EACjB,UAAU,EAAK;EACf,WAAW,EAAa,EAAK,UAAU;EACvC,aAAa,EAAK;EAClB,aAAa,EAAe,EAAK,YAAY;EAC7C,mBAAmB,EAAe,EAAK,kBAAkB;EACzD,UAAU,EAAe,EAAK,SAAS;EACvC,WAAW,EAAe,EAAK,UAAU;EAC1C;;AAGH,SAAS,EAAO,GAA+B;AAC7C,QAAO;EACL,IAAI,EAAI;EACR,MAAM,EAAI;EACV,aAAa,EAAe,EAAI,YAAY;EAC5C,QAAQ,EAAI;EACZ,UAAU,EAAI;EACd,aAAa,EAAI,cAAe,EAAI,cAA8B,KAAA;EAClE,gBAAgB,EAAe,EAAI,eAAe;EAClD,oBAAoB,EAAI,sBAAsB,KAAA;EAC9C,aAAa,EAAI;EACjB,QAAQ,EAAI;EACZ,eAAgB,EAAI,iBAAiB;EACrC,eAAe,EAAe,EAAI,cAAc;EAChD,mBAAmB,EAAe,EAAI,kBAAkB;EACxD,gBAAgB,EAAe,EAAI,eAAe;EAClD,OAAO,EAAI,OAAO,IAAI,EAAQ,IAAI,EAAE;EACpC,YAAY,EAAe,EAAI,WAAW;EAC1C,SAAS,EAAe,EAAI,cAAc;EAC1C,cAAc,EAAe,EAAI,aAAa;EAC9C,WAAW,EAAe,EAAI,UAAU;EACxC,aAAa,EAAe,EAAI,YAAY;EAC5C,WAAW,EAAe,EAAI,UAAU;EACxC,WAAW,EAAI;EACf,oBAAoB,EAAe,EAAI,mBAAmB;EAC1D,aAAa,EAAe,EAAI,YAAY;EAC5C,WAAW,EAAI;EACf,WAAW,EAAI;EAChB;;AAGH,SAAS,EAAY,GAA8C;AACjE,QAAO;EACL,IAAI,EAAS;EACb,MAAM,EAAS;EACf,aAAa,EAAe,EAAS,YAAY;EACjD,aAAa,EAAS;EACtB,QAAQ,EAAS;EACjB,SAAS,EAAe,EAAS,cAAc;EAC/C,WAAW,EAAS;EACpB,WAAW,EAAS;EACpB,aAAa,EAAe,EAAS,YAAY;EACjD,WAAW,EAAS;EACpB,WAAW,EAAS;EACrB;;AAGH,SAAS,EACP,GACuB;AACvB,QAAO;EACL,YAAY,EAAO;EACnB,aAAa,EAAO;EACpB,aAAa,EAAe,EAAO,YAAY;EAC/C,eAAe,EAAe,EAAO,cAAc;EACnD,mBAAmB,EAAO;EAC1B,qBAAqB,EAAO;EAC5B,SAAS,EAAO;EACjB;;AAGH,SAAS,EAAY,GAAgD;AACnE,KAAI,MAAW,MAAO,QAAO,EAAgB;AAC7C,KAAI,MAAW,OAAQ,QAAO,EAAgB;AAC9C,OAAU,MAAM,8BAA8B,IAAS;;AAGzD,SAAS,EAAY,GAAsD;AACzE,SAAQ,GAAR;EACE,KAAK,YACH,QAAO,EAAmB;EAC5B,KAAK,YACH,QAAO,EAAmB;EAC5B,KAAK,UACH,QAAO,EAAmB;EAC5B,KAAK,UACH,QAAO,EAAmB;EAC5B,KAAK,UACH,QAAO,EAAmB;EAC5B,KAAK,SACH,QAAO,EAAmB;EAC5B,KAAK,SACH,QAAO,EAAmB;EAC5B,KAAK,UACH,QAAO,EAAmB;EAC5B,QACE,OAAU,MAAM,8BAA8B,IAAS;;;AAI7D,SAAS,EAAW,GAA6C;AAC/D,SAAQ,GAAR;EACE,KAAK,aACH,QAAO,EAAe;EACxB,KAAK,kBACH,QAAO,EAAe;EACxB,KAAK,YACH,QAAO,EAAe;EACxB,QACE,OAAU,MAAM,6BAA6B,IAAQ;;;AA2D3D,SAAgB,EACd,GACA,GACA;CACA,IAAM,EAAE,mBAAgB,GAAW,EAkB7B,EAAE,SAAM,YAAS,UAAO,eAAY,EAGxC,GAAwB;EACxB,WAAW;GACT,QAnBF,KAAU,IACN;IACE,QACE,EAAO,UAAU,EAAO,WAAW,QAC/B,CAAC,EAAY,EAAO,OAAO,CAAC,GAC5B,KAAA;IACN,QACE,EAAO,UAAU,EAAO,WAAW,QAC/B,EAAY,EAAO,OAAO,GAC1B,KAAA;IACN,QAAQ,EAAO,UAAU,KAAA;IAC1B,GACD,KAAA;GAQU;GACZ,SAAS,EAAE,gBAAa;GACzB;EACD,MAAM,CAAC;EACR,CAAC;AAQF,QAAO;EACL,MAPW,GAAM,eAAe,MAAM,KAAK,MAAM,EAAO,EAAE,KAAK,CAAC,IAAI,EAAE;EAQtE,YAPiB,GAAM,eAAe,cAAc;EAQpD,UAPe,GAAM,eAAe,WAClC,EAAY,EAAK,eAAe,SAAS,GACzC;EAMF,WAAW;EACX,OAAO,KAAS;EAChB;EACD;;AAMH,SAAgB,EAAa,GAA2B;CACtD,IAAM,EAAE,mBAAgB,GAAW,EAE7B,EAAE,SAAM,YAAS,UAAO,eAAY,EAGxC,GAAsB;EACtB,WAAW;GAAE,IAAI,KAAS;GAAI,SAAS,EAAE,gBAAa;GAAE;EACxD,MAAM,CAAC,KAAS,CAAC;EAClB,CAAC;AAIF,QAAO;EACL,MAHU,GAAM,eAAe,EAAO,EAAK,aAAa,GAAG;EAI3D,WAAW;EACX,OAAO,KAAS;EAChB;EACD;;AAMH,SAAgB,EAAqB,GAA2B;CAC9D,IAAM,EAAE,SAAM,YAAS,aAAU,EAG/B,GAA2B;EAC3B,WAAW,EAAE,OAAO,KAAS,IAAI;EACjC,MAAM,CAAC;EACR,CAAC;AAEF,QAAO;EACL,MAAM,GAAM,oBAAoB,EAAO,EAAK,kBAAkB,GAAG;EACjE,WAAW;EACX,OAAO,KAAS;EACjB;;AAMH,SAAgB,EAAqB,GAA8B;CACjE,IAAM,EAAE,aAAa,MAAmB,GAAW,EAC7C,IAAc,KAAuB,GAErC,EAAE,SAAM,YAAS,UAAO,YAAS,iBAAc,EAGnD,GAAoC;EACpC,WAAW;GACT,SAAS,EAAE,gBAAa;GACxB,YAAY,EAAE,OAAO,KAAK;GAC3B;EACD,MAAM,CAAC;EACR,CAAC,EAEI,IAAa,GAAM;AA0BzB,QAAO;EACL,MAzBA,GAAY,MAAM,KAAK,MAAS,EAAmB,EAAK,KAAK,CAAC,IAAI,EAAE;EA0BpE,YAAY,GAAY,cAAc;EACtC,UAAU,GAAY,WAAW,EAAY,EAAW,SAAS,GAAG;EACpE,UA1Be,YAAY;AACvB,IAAC,KAAe,CAAC,GAAY,SAAS,eAC1C,MAAM,EAAU;IACd,WAAW;KACT,SAAS,EAAE,gBAAa;KACxB,YAAY;MAAE,OAAO;MAAK,OAAO,EAAW,SAAS;MAAW;KACjE;IACD,cAAc,GAAU,EAAE,yBACnB,IACE,EACL,4BAA4B;KAC1B,GAAG,EAAgB;KACnB,OAAO,CACL,GAAG,EAAS,2BAA2B,OACvC,GAAG,EAAgB,2BAA2B,MAC/C;KACF,EACF,GAT4B;IAWhC,CAAC;;EAQF,OAAO,KAAS;EAChB,WAAW;EACX;EACD;;AAMH,SAAgB,EAAmB,GAA8B;CAC/D,IAAM,EAAE,aAAa,MAAmB,GAAW,EAC7C,IAAc,KAAuB,GAErC,EAAE,SAAM,YAAS,UAAO,YAAS,iBAAc,EAGnD,GAA6B;EAC7B,WAAW;GACT,SAAS,EAAE,gBAAa;GACxB,YAAY,EAAE,OAAO,IAAI;GAC1B;EACD,MAAM,CAAC;EACR,CAAC,EAEI,IAAa,GAAM;AA0BzB,QAAO;EACL,MAzBA,GAAY,MAAM,KAAK,MAAS,EAAY,EAAK,KAAK,CAAC,IAAI,EAAE;EA0B7D,YAAY,GAAY,cAAc;EACtC,UAAU,GAAY,WAAW,EAAY,EAAW,SAAS,GAAG;EACpE,UA1Be,YAAY;AACvB,IAAC,KAAe,CAAC,GAAY,SAAS,eAC1C,MAAM,EAAU;IACd,WAAW;KACT,SAAS,EAAE,gBAAa;KACxB,YAAY;MAAE,OAAO;MAAI,OAAO,EAAW,SAAS;MAAW;KAChE;IACD,cAAc,GAAU,EAAE,yBACnB,IACE,EACL,qBAAqB;KACnB,GAAG,EAAgB;KACnB,OAAO,CACL,GAAG,EAAS,oBAAoB,OAChC,GAAG,EAAgB,oBAAoB,MACxC;KACF,EACF,GAT4B;IAWhC,CAAC;;EAQF,WAAW;EACX,OAAO,KAAS;EAChB;EACD;;AAMH,SAAgB,EAAkB,GAAgC;CAChE,IAAM,EAAE,mBAAgB,GAAW,EAE7B,EAAE,SAAM,YAAS,aAAU,EAG/B,GAA2B;EAC3B,WAAW;GAAE,IAAI,KAAc;GAAI,SAAS,EAAE,gBAAa;GAAE;EAC7D,MAAM,CAAC,KAAc,CAAC;EACvB,CAAC;AAEF,QAAO;EACL,MAAM,GAAM,oBAAoB,EAAY,EAAK,kBAAkB,GAAG;EACtE,WAAW;EACX,OAAO,KAAS;EACjB;;AAUH,SAAgB,IAAqB;CACnC,IAAM,IAAgB,GAAW,EAC3B,EAAE,mBAAgB,GAClB,CAAC,GAAQ,EAAE,YAAS,cAAW,EAGnC,EAAwB,EAEpB,IAAY,OAAO,MAAoD;EAC3E,IAAM,EAAE,YAAS,GAAG,MAAc,GAC5B,IAAoC;GACxC,GAAG;GACH,aAAa,EAAU,cACnB,EAAW,EAAU,YAAY,GACjC,KAAA;GACJ,QAAQ,EAAY,EAAU,OAAO;GACrC,eAAe;GAChB,EAEK,IAAS,MAAM,EAAO;GAC1B,WAAW;IACT,SAAS,EAAE,gBAAa;IACxB,OAAO;IACR;GACD,gBAAgB,CACd;IACE,OAAO;IACP,WAAW,EAAE,SAAS,EAAE,gBAAa,EAAE;IACxC,CACF;GACF,CAAC;AACF,MAAI,CAAC,EAAO,KAIV,OAHA,EAAgB,GAAe,qBAAqB,EAClD,WAAW,mBACZ,CAAC,EACQ,MAAM,8BAA8B;AAKhD,SAHA,EAAgB,GAAe,sBAAsB,EACnD,OAAO,EAAO,KAAK,gBAAgB,IACpC,CAAC,EACK,EAAO,EAAO,KAAK,gBAAgB;;AAG5C,QAAO;EACL;EAEA,QAAQ;EACR,aAAa;EACb;EACA,WAAW;EACX,OAAO,KAAS;EACjB;;AAMH,SAAgB,IAAqB;CACnC,IAAM,IAAgB,GAAW,EAC3B,EAAE,mBAAgB,GAClB,CAAC,GAAQ,EAAE,YAAS,cAAW,EAGnC,EAAwB,EAEpB,IAAY,OAAO,MAAe;EACtC,IAAM,IAAS,MAAM,EAAO;GAC1B,WAAW;IACT;IACA,SAAS,EAAE,gBAAa;IACzB;GACD,gBAAgB,CACd;IACE,OAAO;IACP,WAAW,EAAE,SAAS,EAAE,gBAAa,EAAE;IACxC,CACF;GACF,CAAC;AACF,MAAI,CAAC,EAAO,KAKV,OAJA,EAAgB,GAAe,qBAAqB;GAClD,WAAW;GACX,OAAO;GACR,CAAC,EACQ,MAAM,8BAA8B;AAGhD,SADA,EAAgB,GAAe,wBAAwB,EAAE,OAAO,GAAI,CAAC,EAC9D,EAAO,KAAK;;AAGrB,QAAO;EACL;EACA,QAAQ;EACR,aAAa;EACb;EACA,WAAW;EACX,OAAO,KAAS;EACjB;;AAMH,SAAgB,IAAqB;CACnC,IAAM,IAAgB,GAAW,EAC3B,EAAE,mBAAgB,GAClB,CAAC,GAAQ,EAAE,YAAS,cAAW,EAGnC,EAAwB,EAEpB,IAAY,OAAO,OACvB,MAAM,EAAO;EACX,WAAW;GACT;GACA,SAAS,EAAE,gBAAa;GACzB;EACD,gBAAgB,CACd;GACE,OAAO;GACP,WAAW,EAAE,SAAS,EAAE,gBAAa,EAAE;GACxC,CACF;EACF,CAAC,EACF,EAAgB,GAAe,sBAAsB,EAAE,OAAO,GAAI,CAAC,EAC5D;AAGT,QAAO;EACL;EACA,QAAQ;EACR,aAAa;EACb;EACA,WAAW;EACX,OAAO,KAAS;EACjB;;AAMH,SAAgB,IAAoB;CAClC,IAAM,IAAgB,GAAW,EAC3B,EAAE,mBAAgB,GAClB,CAAC,GAAQ,EAAE,YAAS,cAAW,EAGnC,EAAuB;AA0BzB,QAAO;EACL,UAzBe,OAAO,MAAmC;GACzD,IAAM,IAAS,MAAM,EAAO;IAC1B,WAAW;KAAE;KAAI,SAAS,EAAE,gBAAa;KAAE;IAC3C,gBAAgB,CACd;KACE,OAAO;KACP,WAAW,EAAE,SAAS,EAAE,gBAAa,EAAE;KACxC,CACF;IACF,CAAC;AACF,OAAI,CAAC,EAAO,KAKV,OAJA,EAAgB,GAAe,qBAAqB;IAClD,WAAW;IACX,OAAO;IACR,CAAC,EACQ,MAAM,6BAA6B;AAM/C,UAJA,EAAgB,GAAe,sBAAsB;IACnD,eAAe;IACf,OAAO,EAAO,KAAK,eAAe;IACnC,CAAC,EACK,EAAO,EAAO,KAAK,eAAe;;EAKzC;EACA,WAAW;EACX,OAAO,KAAS;EACjB;;AAMH,SAAgB,IAA0B;CACxC,IAAM,IAAgB,GAAW,EAC3B,EAAE,mBAAgB,GAClB,CAAC,GAAQ,EAAE,YAAS,cAAW,EAGnC,EAA6B;AAkC/B,QAAO;EACL,gBAjCqB,OACrB,MAC4B;GAC5B,IAAM,IAAyC;IAC7C,GAAG;IACH,QAAQ,EAAY,EAAM,OAAO;IAClC,EAEK,IAAS,MAAM,EAAO;IAC1B,WAAW;KACT,SAAS,EAAE,gBAAa;KACxB,OAAO;KACR;IACD,gBAAgB,CACd;KACE,OAAO;KACP,WAAW,EAAE,SAAS,EAAE,gBAAa,EAAE;KACxC,CACF;IACF,CAAC;AACF,OAAI,CAAC,EAAO,KAIV,OAHA,EAAgB,GAAe,qBAAqB,EAClD,WAAW,wBACZ,CAAC,EACQ,MAAM,mCAAmC;AAKrD,UAHA,EAAgB,GAAe,2BAA2B,EACxD,YAAY,EAAO,KAAK,qBAAqB,IAC9C,CAAC,EACK,EAAY,EAAO,KAAK,qBAAqB;;EAKpD;EACA,WAAW;EACX,OAAO,KAAS;EACjB;;AAMH,SAAgB,IAA0B;CACxC,IAAM,IAAgB,GAAW,EAC3B,EAAE,mBAAgB,GAClB,CAAC,GAAQ,EAAE,YAAS,cAAW,EAGnC,EAA6B;AAqB/B,QAAO;EACL,gBApBqB,OAAO,OAC5B,MAAM,EAAO;GACX,WAAW;IACT;IACA,SAAS,EAAE,gBAAa;IACzB;GACD,gBAAgB,CACd;IACE,OAAO;IACP,WAAW,EAAE,SAAS,EAAE,gBAAa,EAAE;IACxC,CACF;GACF,CAAC,EACF,EAAgB,GAAe,2BAA2B,EACxD,YAAY,GACb,CAAC,EACK;EAKP;EACA,WAAW;EACX,OAAO,KAAS;EACjB"}
|
|
1
|
+
{"version":3,"file":"useExportQueries.js","names":[],"sources":["../../../src/export/hooks/useExportQueries.ts"],"sourcesContent":["/**\n * Export Query Hooks\n *\n * Real Apollo Client hooks for all export operations.\n * Keep these documents in sync with src/operations/wspace/export/*.graphql.\n */\n\nimport { useEffect, useRef } from \"react\";\nimport { useMutation, useQuery, useSubscription } from \"@apollo/client/react\";\nimport {\n CancelExportJobDocument,\n CreateExportJobDocument,\n CreateExportTemplateDocument,\n DeleteExportJobDocument,\n DeleteExportTemplateDocument,\n ExportJobProgressDocument,\n GetAvailableExportEntitiesDocument,\n GetExportJobDocument,\n GetExportTemplateDocument,\n ListExportJobsDocument,\n ListExportTemplatesDocument,\n RetryExportJobDocument,\n type CancelExportJobMutation,\n type CancelExportJobMutationVariables,\n type CreateExportJobMutation,\n type CreateExportJobMutationVariables,\n type CreateExportTemplateMutation,\n type CreateExportTemplateMutationVariables,\n type DeleteExportJobMutation,\n type DeleteExportJobMutationVariables,\n type DeleteExportTemplateMutation,\n type DeleteExportTemplateMutationVariables,\n type ExportJobProgressSubscription,\n type ExportJobProgressSubscriptionVariables,\n type GetAvailableExportEntitiesQuery,\n type GetAvailableExportEntitiesQueryVariables,\n type GetExportJobQuery,\n type GetExportJobQueryVariables,\n type GetExportTemplateQuery,\n type GetExportTemplateQueryVariables,\n type ListExportJobsQuery,\n type ListExportJobsQueryVariables,\n type ListExportTemplatesQuery,\n type ListExportTemplatesQueryVariables,\n type RetryExportJobMutation,\n type RetryExportJobMutationVariables,\n} from \"../../generated/wspace-operations\";\nimport {\n ExportFormat as GqlExportFormat,\n ExportJobStatus as GqlExportJobStatus,\n ExportScope as GqlExportScope,\n type CreateExportJobInput as GqlCreateExportJobInput,\n type CreateExportTemplateInput as GqlCreateExportTemplateInput,\n type ExportJobFilterInput as GqlExportJobFilterInput,\n type ExportPaginationInput as GqlExportPaginationInput,\n} from \"../../generated/wspace-types\";\nimport { useExport } from \"../providers/ExportProvider\";\nimport { emitExportEvent } from \"../utils/events\";\nimport type {\n ExportArchiveFormat,\n ExportFormat,\n ExportJob,\n ExportJobStatus,\n ExportScope,\n ExportTemplate,\n ExportAvailableEntity,\n ExportPart,\n ExportFilter,\n PageInfo,\n} from \"../types\";\n\n// ---------------------------------------------------------------------------\n// Mapping helpers\n// ---------------------------------------------------------------------------\n\ntype Nullable<T> = T | null | undefined;\n\ninterface ExportPartLike {\n id: string;\n jobId?: Nullable<string>;\n partNumber: number;\n fileName: string;\n sizeBytes: number | string;\n entityTypes: string[];\n downloadUrl?: Nullable<string>;\n downloadExpiresAt?: Nullable<string>;\n checksum?: Nullable<string>;\n createdAt?: Nullable<string>;\n}\n\ninterface ExportJobLike {\n id: string;\n name: string;\n description?: Nullable<string>;\n status: string;\n progress: number;\n exportScope?: Nullable<string>;\n organizationId?: Nullable<string>;\n targetWorkspaceIds?: Nullable<string[]>;\n entityTypes: string[];\n format: string;\n archiveFormat?: Nullable<string>;\n totalEntities?: Nullable<number>;\n processedEntities?: Nullable<number>;\n totalSizeBytes?: Nullable<number | string>;\n parts?: Nullable<ExportPartLike[]>;\n templateId?: Nullable<string>;\n entityFilters?: Nullable<Record<string, unknown>>;\n errorMessage?: Nullable<string>;\n startedAt?: Nullable<string>;\n completedAt?: Nullable<string>;\n expiresAt?: Nullable<string>;\n createdBy: string;\n temporalWorkflowId?: Nullable<string>;\n workspaceId?: Nullable<string>;\n createdAt: string;\n updatedAt: string;\n}\n\ninterface ExportTemplateLike {\n id: string;\n name: string;\n description?: Nullable<string>;\n entityTypes: string[];\n format: string;\n entityFilters?: Nullable<Record<string, unknown>>;\n isDefault: boolean;\n workspaceId?: Nullable<string>;\n createdBy: string;\n createdAt: string;\n updatedAt: string;\n}\n\ninterface ExportAvailableEntityLike {\n entityType: string;\n displayName: string;\n description?: Nullable<string>;\n estimatedSize?: Nullable<string>;\n supportsDateRange: boolean;\n supportsMediaExport: boolean;\n enabled: boolean;\n}\n\nfunction optionalString(value: Nullable<string>): string | undefined {\n return value ?? undefined;\n}\n\nfunction optionalNumber(value: Nullable<number | string>): number | undefined {\n if (value == null) return undefined;\n const parsed = typeof value === \"number\" ? value : Number(value);\n return Number.isFinite(parsed) ? parsed : undefined;\n}\n\nfunction numberOrZero(value: Nullable<number | string>): number {\n return optionalNumber(value) ?? 0;\n}\n\nfunction optionalRecord(\n value: Nullable<Record<string, unknown>>,\n): Record<string, unknown> | undefined {\n return value && typeof value === \"object\" && !Array.isArray(value)\n ? value\n : undefined;\n}\n\nfunction mapPageInfo(pageInfo: {\n hasNextPage: boolean;\n hasPreviousPage: boolean;\n startCursor?: Nullable<string>;\n endCursor?: Nullable<string>;\n}): PageInfo {\n return {\n hasNextPage: pageInfo.hasNextPage,\n hasPreviousPage: pageInfo.hasPreviousPage,\n startCursor: optionalString(pageInfo.startCursor),\n endCursor: optionalString(pageInfo.endCursor),\n };\n}\n\nfunction mapPart(part: ExportPartLike): ExportPart {\n return {\n id: part.id,\n jobId: optionalString(part.jobId),\n partNumber: part.partNumber,\n fileName: part.fileName,\n sizeBytes: numberOrZero(part.sizeBytes),\n entityTypes: part.entityTypes,\n downloadUrl: optionalString(part.downloadUrl),\n downloadExpiresAt: optionalString(part.downloadExpiresAt),\n checksum: optionalString(part.checksum),\n createdAt: optionalString(part.createdAt),\n };\n}\n\nfunction mapJob(job: ExportJobLike): ExportJob {\n return {\n id: job.id,\n name: job.name,\n description: optionalString(job.description),\n status: job.status as ExportJobStatus,\n progress: job.progress,\n exportScope: job.exportScope ? (job.exportScope as ExportScope) : undefined,\n organizationId: optionalString(job.organizationId),\n targetWorkspaceIds: job.targetWorkspaceIds ?? undefined,\n entityTypes: job.entityTypes,\n format: job.format as ExportFormat,\n archiveFormat: (job.archiveFormat ?? \"ZIP\") as ExportArchiveFormat,\n totalEntities: optionalNumber(job.totalEntities),\n processedEntities: optionalNumber(job.processedEntities),\n totalSizeBytes: optionalNumber(job.totalSizeBytes),\n parts: job.parts?.map(mapPart) ?? [],\n templateId: optionalString(job.templateId),\n filters: optionalRecord(job.entityFilters),\n errorMessage: optionalString(job.errorMessage),\n startedAt: optionalString(job.startedAt),\n completedAt: optionalString(job.completedAt),\n expiresAt: optionalString(job.expiresAt),\n createdBy: job.createdBy,\n temporalWorkflowId: optionalString(job.temporalWorkflowId),\n workspaceId: optionalString(job.workspaceId),\n createdAt: job.createdAt,\n updatedAt: job.updatedAt,\n };\n}\n\nfunction mapTemplate(template: ExportTemplateLike): ExportTemplate {\n return {\n id: template.id,\n name: template.name,\n description: optionalString(template.description),\n entityTypes: template.entityTypes,\n format: template.format as ExportFormat,\n filters: optionalRecord(template.entityFilters),\n isDefault: template.isDefault,\n createdBy: template.createdBy,\n workspaceId: optionalString(template.workspaceId),\n createdAt: template.createdAt,\n updatedAt: template.updatedAt,\n };\n}\n\nfunction mapAvailableEntity(\n entity: ExportAvailableEntityLike,\n): ExportAvailableEntity {\n return {\n entityType: entity.entityType,\n displayName: entity.displayName,\n description: optionalString(entity.description),\n estimatedSize: optionalString(entity.estimatedSize),\n supportsDateRange: entity.supportsDateRange,\n supportsMediaExport: entity.supportsMediaExport,\n enabled: entity.enabled,\n };\n}\n\nfunction toGqlFormat(format: ExportFormat | string): GqlExportFormat {\n if (format === \"CSV\") return GqlExportFormat.Csv;\n if (format === \"JSON\") return GqlExportFormat.Json;\n throw new Error(`Unsupported export format: ${format}`);\n}\n\nfunction toGqlStatus(status: ExportJobStatus | string): GqlExportJobStatus {\n switch (status) {\n case \"CANCELLED\":\n return GqlExportJobStatus.Cancelled;\n case \"COMPLETED\":\n return GqlExportJobStatus.Completed;\n case \"CREATED\":\n return GqlExportJobStatus.Created;\n case \"DELETED\":\n return GqlExportJobStatus.Deleted;\n case \"EXPIRED\":\n return GqlExportJobStatus.Expired;\n case \"FAILED\":\n return GqlExportJobStatus.Failed;\n case \"QUEUED\":\n return GqlExportJobStatus.Queued;\n case \"RUNNING\":\n return GqlExportJobStatus.Running;\n default:\n throw new Error(`Unsupported export status: ${status}`);\n }\n}\n\nfunction toGqlScope(scope: ExportScope | string): GqlExportScope {\n switch (scope) {\n case \"INDIVIDUAL\":\n return GqlExportScope.Individual;\n case \"WORKSPACE_ADMIN\":\n return GqlExportScope.WorkspaceAdmin;\n case \"ORG_ADMIN\":\n return GqlExportScope.OrgAdmin;\n default:\n throw new Error(`Unsupported export scope: ${scope}`);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Query Hooks\n// ---------------------------------------------------------------------------\n\n/**\n * Input for creating an export job\n */\nexport interface CreateExportJobInput {\n name: string;\n description?: string;\n exportScope?: ExportScope;\n organizationId?: string;\n entityTypes: string[];\n format: ExportFormat;\n filters?: Record<string, unknown>;\n templateId?: string;\n dateRangeStart?: string | null;\n dateRangeEnd?: string | null;\n}\n\n/**\n * Input for creating an export template\n */\nexport interface CreateExportTemplateInput {\n name: string;\n description?: string;\n entityTypes: string[];\n format: ExportFormat;\n}\n\n/**\n * Filter input for listing export jobs\n */\nexport interface ExportJobFilterInput {\n status?: ExportJobStatus[];\n format?: ExportFormat;\n entityTypes?: string[];\n search?: string;\n dateFrom?: string;\n dateTo?: string;\n}\n\n/**\n * Pagination input for export job list\n */\nexport interface ExportPaginationInput {\n first?: number;\n after?: string;\n last?: number;\n before?: string;\n}\n\n/**\n * Hook to fetch a paginated list of export jobs\n */\nexport function useExportJobs(\n filter?: Partial<ExportFilter>,\n pagination?: ExportPaginationInput,\n) {\n const { workspaceId } = useExport();\n\n // Build the backend filter from the UI filter shape\n const backendFilter: GqlExportJobFilterInput | undefined =\n filter && workspaceId\n ? {\n status:\n filter.status && filter.status !== \"all\"\n ? [toGqlStatus(filter.status)]\n : undefined,\n format:\n filter.format && filter.format !== \"all\"\n ? toGqlFormat(filter.format)\n : undefined,\n search: filter.search ?? undefined,\n }\n : undefined;\n\n const { data, loading, error, refetch } = useQuery<\n ListExportJobsQuery,\n ListExportJobsQueryVariables\n >(ListExportJobsDocument, {\n variables: {\n filter: backendFilter,\n pagination: pagination as GqlExportPaginationInput | undefined,\n context: { workspaceId },\n },\n skip: !workspaceId,\n });\n\n const jobs = data?.listExportJobs.edges.map((e) => mapJob(e.node)) ?? [];\n const totalCount = data?.listExportJobs.totalCount ?? 0;\n const pageInfo = data?.listExportJobs.pageInfo\n ? mapPageInfo(data.listExportJobs.pageInfo)\n : null;\n\n return {\n data: jobs,\n totalCount,\n pageInfo,\n isLoading: loading,\n error: error ?? null,\n refetch,\n };\n}\n\n/**\n * Hook to fetch a single export job by ID.\n */\nexport function useExportJob(jobId: string | undefined) {\n const { workspaceId } = useExport();\n\n const { data, loading, error, refetch } = useQuery<\n GetExportJobQuery,\n GetExportJobQueryVariables\n >(GetExportJobDocument, {\n variables: { id: jobId ?? \"\", context: { workspaceId } },\n skip: !jobId || !workspaceId,\n });\n\n const job = data?.getExportJob ? mapJob(data.getExportJob) : null;\n\n return {\n data: job,\n isLoading: loading,\n error: error ?? null,\n refetch,\n };\n}\n\n/**\n * Hook to subscribe to live progress updates for an export job.\n */\nexport function useExportJobProgress(jobId: string | undefined) {\n const { data, loading, error } = useSubscription<\n ExportJobProgressSubscription,\n ExportJobProgressSubscriptionVariables\n >(ExportJobProgressDocument, {\n variables: { jobId: jobId ?? \"\" },\n skip: !jobId,\n });\n\n return {\n data: data?.exportJobProgress ? mapJob(data.exportJobProgress) : null,\n isLoading: loading,\n error: error ?? null,\n };\n}\n\n/** Apollo `updateQuery` for the catalog: append a fetched page's edges. */\nfunction appendEntityPage(\n previous: GetAvailableExportEntitiesQuery,\n { fetchMoreResult }: { fetchMoreResult?: GetAvailableExportEntitiesQuery },\n): GetAvailableExportEntitiesQuery {\n if (!fetchMoreResult) return previous;\n return {\n getAvailableExportEntities: {\n ...fetchMoreResult.getAvailableExportEntities,\n edges: [\n ...previous.getAvailableExportEntities.edges,\n ...fetchMoreResult.getAvailableExportEntities.edges,\n ],\n },\n };\n}\n\n/**\n * Hook to fetch available entity types for export in a workspace\n */\nexport function useAvailableEntities(overrideWorkspaceId?: string) {\n const { workspaceId: ctxWorkspaceId } = useExport();\n const workspaceId = overrideWorkspaceId ?? ctxWorkspaceId;\n\n const { data, loading, error, refetch, fetchMore } = useQuery<\n GetAvailableExportEntitiesQuery,\n GetAvailableExportEntitiesQueryVariables\n >(GetAvailableExportEntitiesDocument, {\n variables: {\n context: { workspaceId },\n pagination: { first: 100 },\n },\n skip: !workspaceId,\n });\n\n const connection = data?.getAvailableExportEntities;\n const entities =\n connection?.edges.map((edge) => mapAvailableEntity(edge.node)) ?? [];\n\n const loadMore = async () => {\n if (!workspaceId || !connection?.pageInfo.hasNextPage) return;\n await fetchMore({\n variables: {\n context: { workspaceId },\n pagination: { first: 100, after: connection.pageInfo.endCursor },\n },\n updateQuery: appendEntityPage,\n });\n };\n\n // The entity picker and the template editor need the whole catalog (well\n // over one 100-entry page: entities are sorted by display name, so products\n // late in the alphabet, e.g. VibeControls, were never shown). Fetch the\n // remaining pages, once per cursor.\n const hasNextPage = connection?.pageInfo.hasNextPage ?? false;\n const endCursor = connection?.pageInfo.endCursor ?? null;\n const requestedCursor = useRef<string | null>(null);\n useEffect(() => {\n if (loading || !workspaceId || !hasNextPage || !endCursor) return;\n if (requestedCursor.current === endCursor) return;\n requestedCursor.current = endCursor;\n void fetchMore({\n variables: {\n context: { workspaceId },\n pagination: { first: 100, after: endCursor },\n },\n updateQuery: appendEntityPage,\n });\n }, [loading, workspaceId, hasNextPage, endCursor, fetchMore]);\n\n return {\n data: entities,\n totalCount: connection?.totalCount ?? 0,\n pageInfo: connection?.pageInfo ? mapPageInfo(connection.pageInfo) : null,\n loadMore,\n error: error ?? null,\n isLoading: loading,\n refetch,\n };\n}\n\n/**\n * Hook to fetch all export templates for the current workspace\n */\nexport function useExportTemplates(overrideWorkspaceId?: string) {\n const { workspaceId: ctxWorkspaceId } = useExport();\n const workspaceId = overrideWorkspaceId ?? ctxWorkspaceId;\n\n const { data, loading, error, refetch, fetchMore } = useQuery<\n ListExportTemplatesQuery,\n ListExportTemplatesQueryVariables\n >(ListExportTemplatesDocument, {\n variables: {\n context: { workspaceId },\n pagination: { first: 50 },\n },\n skip: !workspaceId,\n });\n\n const connection = data?.listExportTemplates;\n const templates =\n connection?.edges.map((edge) => mapTemplate(edge.node)) ?? [];\n\n const loadMore = async () => {\n if (!workspaceId || !connection?.pageInfo.hasNextPage) return;\n await fetchMore({\n variables: {\n context: { workspaceId },\n pagination: { first: 50, after: connection.pageInfo.endCursor },\n },\n updateQuery: (previous, { fetchMoreResult }) => {\n if (!fetchMoreResult) return previous;\n return {\n listExportTemplates: {\n ...fetchMoreResult.listExportTemplates,\n edges: [\n ...previous.listExportTemplates.edges,\n ...fetchMoreResult.listExportTemplates.edges,\n ],\n },\n };\n },\n });\n };\n\n return {\n data: templates,\n totalCount: connection?.totalCount ?? 0,\n pageInfo: connection?.pageInfo ? mapPageInfo(connection.pageInfo) : null,\n loadMore,\n isLoading: loading,\n error: error ?? null,\n refetch,\n };\n}\n\n/**\n * Hook to fetch a single export template by ID\n */\nexport function useExportTemplate(templateId: string | undefined) {\n const { workspaceId } = useExport();\n\n const { data, loading, error } = useQuery<\n GetExportTemplateQuery,\n GetExportTemplateQueryVariables\n >(GetExportTemplateDocument, {\n variables: { id: templateId ?? \"\", context: { workspaceId } },\n skip: !templateId || !workspaceId,\n });\n\n return {\n data: data?.getExportTemplate ? mapTemplate(data.getExportTemplate) : null,\n isLoading: loading,\n error: error ?? null,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Mutation Hooks\n// ---------------------------------------------------------------------------\n\n/**\n * Hook to create a new export job\n */\nexport function useCreateExportJob() {\n const exportContext = useExport();\n const { workspaceId } = exportContext;\n const [mutate, { loading, error }] = useMutation<\n CreateExportJobMutation,\n CreateExportJobMutationVariables\n >(CreateExportJobDocument);\n\n const createJob = async (input: CreateExportJobInput): Promise<ExportJob> => {\n const { filters, ...restInput } = input;\n const gqlInput: GqlCreateExportJobInput = {\n ...restInput,\n exportScope: restInput.exportScope\n ? toGqlScope(restInput.exportScope)\n : undefined,\n format: toGqlFormat(restInput.format),\n entityFilters: filters,\n };\n\n const result = await mutate({\n variables: {\n context: { workspaceId },\n input: gqlInput,\n },\n refetchQueries: [\n {\n query: ListExportJobsDocument,\n variables: { context: { workspaceId } },\n },\n ],\n });\n if (!result.data) {\n emitExportEvent(exportContext, \"export.api.failed\", {\n operation: \"createExportJob\",\n });\n throw new Error(\"Failed to create export job\");\n }\n emitExportEvent(exportContext, \"export.job.created\", {\n jobId: result.data.createExportJob.id,\n });\n return mapJob(result.data.createExportJob);\n };\n\n return {\n createJob,\n // Keep legacy names for existing callers\n mutate: createJob,\n mutateAsync: createJob,\n loading,\n isPending: loading,\n error: error ?? null,\n };\n}\n\n/**\n * Hook to cancel an export job\n */\nexport function useCancelExportJob() {\n const exportContext = useExport();\n const { workspaceId } = exportContext;\n const [mutate, { loading, error }] = useMutation<\n CancelExportJobMutation,\n CancelExportJobMutationVariables\n >(CancelExportJobDocument);\n\n const cancelJob = async (id: string) => {\n const result = await mutate({\n variables: {\n id,\n context: { workspaceId },\n },\n refetchQueries: [\n {\n query: ListExportJobsDocument,\n variables: { context: { workspaceId } },\n },\n ],\n });\n if (!result.data) {\n emitExportEvent(exportContext, \"export.api.failed\", {\n operation: \"cancelExportJob\",\n jobId: id,\n });\n throw new Error(\"Failed to cancel export job\");\n }\n emitExportEvent(exportContext, \"export.job.cancelled\", { jobId: id });\n return result.data.cancelExportJob;\n };\n\n return {\n cancelJob,\n mutate: cancelJob,\n mutateAsync: cancelJob,\n loading,\n isPending: loading,\n error: error ?? null,\n };\n}\n\n/**\n * Hook to delete an export job\n */\nexport function useDeleteExportJob() {\n const exportContext = useExport();\n const { workspaceId } = exportContext;\n const [mutate, { loading, error }] = useMutation<\n DeleteExportJobMutation,\n DeleteExportJobMutationVariables\n >(DeleteExportJobDocument);\n\n const deleteJob = async (id: string): Promise<boolean> => {\n await mutate({\n variables: {\n id,\n context: { workspaceId },\n },\n refetchQueries: [\n {\n query: ListExportJobsDocument,\n variables: { context: { workspaceId } },\n },\n ],\n });\n emitExportEvent(exportContext, \"export.job.deleted\", { jobId: id });\n return true;\n };\n\n return {\n deleteJob,\n mutate: deleteJob,\n mutateAsync: deleteJob,\n loading,\n isPending: loading,\n error: error ?? null,\n };\n}\n\n/**\n * Hook to retry a failed export job\n */\nexport function useRetryExportJob() {\n const exportContext = useExport();\n const { workspaceId } = exportContext;\n const [mutate, { loading, error }] = useMutation<\n RetryExportJobMutation,\n RetryExportJobMutationVariables\n >(RetryExportJobDocument);\n\n const retryJob = async (id: string): Promise<ExportJob> => {\n const result = await mutate({\n variables: { id, context: { workspaceId } },\n refetchQueries: [\n {\n query: ListExportJobsDocument,\n variables: { context: { workspaceId } },\n },\n ],\n });\n if (!result.data) {\n emitExportEvent(exportContext, \"export.api.failed\", {\n operation: \"retryExportJob\",\n jobId: id,\n });\n throw new Error(\"Failed to retry export job\");\n }\n emitExportEvent(exportContext, \"export.job.retried\", {\n originalJobId: id,\n jobId: result.data.retryExportJob.id,\n });\n return mapJob(result.data.retryExportJob);\n };\n\n return {\n retryJob,\n loading,\n isPending: loading,\n error: error ?? null,\n };\n}\n\n/**\n * Hook to create a new export template\n */\nexport function useCreateExportTemplate() {\n const exportContext = useExport();\n const { workspaceId } = exportContext;\n const [mutate, { loading, error }] = useMutation<\n CreateExportTemplateMutation,\n CreateExportTemplateMutationVariables\n >(CreateExportTemplateDocument);\n\n const createTemplate = async (\n input: CreateExportTemplateInput,\n ): Promise<ExportTemplate> => {\n const gqlInput: GqlCreateExportTemplateInput = {\n ...input,\n format: toGqlFormat(input.format),\n };\n\n const result = await mutate({\n variables: {\n context: { workspaceId },\n input: gqlInput,\n },\n refetchQueries: [\n {\n query: ListExportTemplatesDocument,\n variables: { context: { workspaceId } },\n },\n ],\n });\n if (!result.data) {\n emitExportEvent(exportContext, \"export.api.failed\", {\n operation: \"createExportTemplate\",\n });\n throw new Error(\"Failed to create export template\");\n }\n emitExportEvent(exportContext, \"export.template.created\", {\n templateId: result.data.createExportTemplate.id,\n });\n return mapTemplate(result.data.createExportTemplate);\n };\n\n return {\n createTemplate,\n loading,\n isPending: loading,\n error: error ?? null,\n };\n}\n\n/**\n * Hook to delete an export template\n */\nexport function useDeleteExportTemplate() {\n const exportContext = useExport();\n const { workspaceId } = exportContext;\n const [mutate, { loading, error }] = useMutation<\n DeleteExportTemplateMutation,\n DeleteExportTemplateMutationVariables\n >(DeleteExportTemplateDocument);\n\n const deleteTemplate = async (id: string): Promise<boolean> => {\n await mutate({\n variables: {\n id,\n context: { workspaceId },\n },\n refetchQueries: [\n {\n query: ListExportTemplatesDocument,\n variables: { context: { workspaceId } },\n },\n ],\n });\n emitExportEvent(exportContext, \"export.template.deleted\", {\n templateId: id,\n });\n return true;\n };\n\n return {\n deleteTemplate,\n loading,\n isPending: loading,\n error: error ?? null,\n };\n}\n"],"mappings":"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"}
|
|
@@ -273,7 +273,7 @@ function w() {
|
|
|
273
273
|
type: "button",
|
|
274
274
|
onClick: (t) => ne(t, e.id),
|
|
275
275
|
className: "p-1.5 rounded-md text-text-secondary hover:text-status-error-text hover:bg-status-error-bg/10 transition-colors",
|
|
276
|
-
"aria-label": E("export.templates.card.deleteAriaLabel", "Delete {name}", { name: e.name }),
|
|
276
|
+
"aria-label": E("export.templates.card.deleteAriaLabel", "Delete {{name}}", { name: e.name }),
|
|
277
277
|
children: /* @__PURE__ */ v(_, { size: 14 })
|
|
278
278
|
}), /* @__PURE__ */ v(te, {
|
|
279
279
|
size: 18,
|
|
@@ -293,7 +293,7 @@ function w() {
|
|
|
293
293
|
children: e
|
|
294
294
|
}, e)), e.entityTypes.length > 6 && /* @__PURE__ */ v("span", {
|
|
295
295
|
className: "inline-flex px-2 py-0.5 rounded text-xs font-medium bg-bg-sunken text-text-secondary",
|
|
296
|
-
children: E("export.templates.card.moreEntities", "+{count} more", { count: e.entityTypes.length - 6 })
|
|
296
|
+
children: E("export.templates.card.moreEntities", "+{{count}} more", { count: e.entityTypes.length - 6 })
|
|
297
297
|
})]
|
|
298
298
|
})]
|
|
299
299
|
})]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExportTemplatesPage.js","names":[],"sources":["../../../src/export/pages/ExportTemplatesPage.tsx"],"sourcesContent":["import { useState, useMemo } from \"react\";\nimport {\n Search,\n X,\n FileBox,\n Plus,\n ChevronRight,\n Sparkles,\n Loader2,\n} from \"lucide-react\";\nimport {\n CTAOverflowMenu,\n IllustratedEmptyState,\n PagePurpose,\n} from \"@burdenoff/fe-libs/ui\";\nimport { useExport } from \"../providers/ExportProvider\";\nimport {\n useExportTemplates,\n useDeleteExportTemplate,\n useCreateExportTemplate,\n useAvailableEntities,\n} from \"../hooks/useExportQueries\";\nimport { PageLayout } from \"../components/PageLayout\";\nimport { getFormatDisplayName } from \"../constants/enums\";\nimport { useTr } from \"../hooks/useTr\";\nimport { cn } from \"../utils/cn\";\nimport type { ExportFormat } from \"../types\";\nimport { nativeImpact, nativeNotify } from \"../../utils/nativeBridge\";\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 Templates Page\n * Template management list for reusable export configurations\n */\nexport function ExportTemplatesPage() {\n const { basePath = \"/\", navigate } = useExport();\n const tr = useTr();\n const { data: templates, isLoading } = useExportTemplates();\n const { deleteTemplate } = useDeleteExportTemplate();\n const { createTemplate, isPending: creating } = useCreateExportTemplate();\n const { data: availableEntities } = useAvailableEntities();\n\n const [searchQuery, setSearchQuery] = useState(\"\");\n const [showCreateForm, setShowCreateForm] = useState(false);\n const [newTemplateName, setNewTemplateName] = useState(\"\");\n const [newTemplateDescription, setNewTemplateDescription] = useState(\"\");\n const [newTemplateEntityTypes, setNewTemplateEntityTypes] = useState<\n string[]\n >([]);\n const [newTemplateFormat, setNewTemplateFormat] =\n useState<ExportFormat>(\"CSV\");\n const [createError, setCreateError] = useState<string | null>(null);\n const [templatePendingDelete, setTemplatePendingDelete] = useState<\n string | null\n >(null);\n\n const handleOpenCreate = () => {\n setNewTemplateName(\"\");\n setNewTemplateDescription(\"\");\n setNewTemplateEntityTypes([]);\n setNewTemplateFormat(\"CSV\");\n setCreateError(null);\n setShowCreateForm(true);\n };\n\n const handleCreateTemplate = async () => {\n if (!newTemplateName.trim()) {\n setCreateError(\n tr(\n \"export.templates.form.errors.nameRequired\",\n \"Template name is required.\",\n ),\n );\n return;\n }\n if (newTemplateEntityTypes.length === 0) {\n setCreateError(\n tr(\n \"export.templates.form.errors.entityRequired\",\n \"Select at least one entity type.\",\n ),\n );\n return;\n }\n setCreateError(null);\n try {\n await createTemplate({\n name: newTemplateName.trim(),\n description: newTemplateDescription.trim() || undefined,\n entityTypes: newTemplateEntityTypes,\n format: newTemplateFormat,\n });\n setShowCreateForm(false);\n } catch (err) {\n setCreateError(\n err instanceof Error\n ? err.message\n : tr(\n \"export.templates.form.errors.createFailed\",\n \"Failed to create template.\",\n ),\n );\n }\n };\n\n const toggleEntity = (entityType: string) => {\n setNewTemplateEntityTypes((prev) =>\n prev.includes(entityType)\n ? prev.filter((e) => e !== entityType)\n : [...prev, entityType],\n );\n };\n\n // Client-side search filter\n const filteredTemplates = useMemo(() => {\n if (!searchQuery) return templates;\n const q = searchQuery.toLowerCase();\n return templates.filter(\n (t) =>\n t.name.toLowerCase().includes(q) ||\n t.entityTypes.some((e) => e.toLowerCase().includes(q)),\n );\n }, [templates, searchQuery]);\n\n const handleTemplateClick = (templateId: string) => {\n navigate?.(joinPath(basePath, `templates/${templateId}`));\n };\n\n const handleDeleteTemplate = async (\n e: React.MouseEvent,\n templateId: string,\n ) => {\n e.stopPropagation();\n nativeImpact(\"medium\");\n setTemplatePendingDelete(templateId);\n };\n\n const confirmDeleteTemplate = async () => {\n if (!templatePendingDelete) return;\n try {\n await deleteTemplate(templatePendingDelete);\n nativeNotify(\"success\");\n } catch {\n nativeNotify(\"error\");\n }\n setTemplatePendingDelete(null);\n };\n\n return (\n <PageLayout\n title={tr(\"export.templates.title\", \"Export Templates\")}\n subtitle={tr(\n \"export.templates.subtitle\",\n \"Reusable export configurations for common data exports\",\n )}\n icon={<FileBox size={24} />}\n headerActions={\n <CTAOverflowMenu\n primary={{\n label: tr(\"export.templates.actions.newTemplate\", \"New Template\"),\n icon: <Plus size={16} />,\n onSelect: handleOpenCreate,\n }}\n actions={[\n {\n label: tr(\"export.templates.actions.newExport\", \"New Export\"),\n icon: <Plus size={16} />,\n onSelect: () => navigate?.(joinPath(basePath, \"new\")),\n },\n ]}\n />\n }\n headerContent={\n <span className=\"inline-flex items-center gap-1.5 px-2.5 py-0.5 rounded-full text-xs font-medium bg-bg-sunken text-text-secondary\">\n <Sparkles size={12} />\n {tr(\n \"export.templates.summary.available\",\n \"{{count}} template{{suffix}} available\",\n {\n count: filteredTemplates.length,\n suffix: filteredTemplates.length !== 1 ? \"s\" : \"\",\n },\n )}\n </span>\n }\n >\n {/* Page purpose — why templates exist */}\n <PagePurpose icon={<FileBox size={16} />}>\n {tr(\n \"export.templates.purpose\",\n \"Templates save an export setup — the entity types and format you regularly need — so you don't rebuild it each time. Create one here, then start a new export from it in a single click. Handy for recurring backups, periodic audits, or any export you run more than once.\",\n )}\n </PagePurpose>\n\n {/* Create Template Form */}\n {showCreateForm && (\n <div className=\"border border-primary/30 rounded-xl p-6 bg-accent-wash space-y-4\">\n <div className=\"flex items-center justify-between\">\n <h3 className=\"font-semibold text-lg\">\n {tr(\"export.templates.form.title\", \"New Template\")}\n </h3>\n <button\n type=\"button\"\n onClick={() => setShowCreateForm(false)}\n className=\"p-1.5 rounded-md hover:bg-accent\"\n >\n <X size={16} />\n </button>\n </div>\n {createError && (\n <p className=\"text-sm text-status-error-text bg-status-error-bg/10 rounded-lg px-3 py-2\">\n {createError}\n </p>\n )}\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-4\">\n <div className=\"space-y-1\">\n <label className=\"text-sm font-medium\">\n {tr(\"export.templates.form.fields.name\", \"Name\")} *\n </label>\n <input\n type=\"text\"\n aria-label={tr(\"export.templates.form.fields.name\", \"Name\")}\n placeholder={tr(\n \"export.templates.form.fields.namePlaceholder\",\n \"e.g. Weekly Tags Export\",\n )}\n value={newTemplateName}\n onChange={(e) => setNewTemplateName(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 transition-all\"\n />\n </div>\n <div className=\"space-y-1\">\n <label className=\"text-sm font-medium\">\n {tr(\"export.templates.form.fields.format\", \"Format\")} *\n </label>\n <select\n value={newTemplateFormat}\n onChange={(e) =>\n setNewTemplateFormat(e.target.value as ExportFormat)\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 transition-all scheme-normal dark:scheme-dark [&_option]:bg-bg-surface [&_option]:text-text-primary\"\n >\n <option value=\"CSV\">{tr(\"export.format.csv\", \"CSV\")}</option>\n <option value=\"JSON\">{tr(\"export.format.json\", \"JSON\")}</option>\n </select>\n </div>\n </div>\n <div className=\"space-y-1\">\n <label className=\"text-sm font-medium\">\n {tr(\"export.templates.form.fields.description\", \"Description\")}\n </label>\n <input\n type=\"text\"\n aria-label={tr(\n \"export.templates.form.fields.description\",\n \"Description\",\n )}\n placeholder={tr(\n \"export.templates.form.fields.descriptionPlaceholder\",\n \"Optional description\",\n )}\n value={newTemplateDescription}\n onChange={(e) => setNewTemplateDescription(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 transition-all\"\n />\n </div>\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\">\n {tr(\"export.templates.form.fields.entityTypes\", \"Entity Types\")} *{\" \"}\n <span className=\"text-text-secondary font-normal\">\n {tr(\n \"export.templates.form.fields.entityTypesHint\",\n \"(select at least one)\",\n )}\n </span>\n </label>\n <div className=\"flex flex-wrap gap-2\">\n {availableEntities.map((entity) => (\n <button\n key={entity.entityType}\n type=\"button\"\n onClick={() => toggleEntity(entity.entityType)}\n className={cn(\n \"px-3 py-1.5 rounded-lg text-sm font-medium border-2 transition-all\",\n newTemplateEntityTypes.includes(entity.entityType)\n ? \"border-primary bg-action-primary-bg/10 text-primary\"\n : \"border-border-subtle bg-bg-surface hover:border-primary/50\",\n )}\n >\n {entity.displayName}\n </button>\n ))}\n </div>\n </div>\n <div className=\"flex gap-3 pt-2\">\n <button\n type=\"button\"\n onClick={handleCreateTemplate}\n disabled={creating}\n className=\"inline-flex items-center gap-2 px-5 py-2.5 bg-action-primary-bg text-action-primary-text rounded-lg hover:bg-action-primary-bg/90 transition-colors font-medium disabled:opacity-50\"\n >\n {creating ? (\n <Loader2 size={16} className=\"animate-spin\" />\n ) : (\n <Plus size={16} />\n )}\n {tr(\"export.templates.form.actions.create\", \"Create Template\")}\n </button>\n <button\n type=\"button\"\n onClick={() => setShowCreateForm(false)}\n className=\"px-5 py-2.5 border-2 border-border-subtle rounded-lg hover:bg-accent transition-colors font-medium\"\n >\n {tr(\"export.templates.form.actions.cancel\", \"Cancel\")}\n </button>\n </div>\n </div>\n )}\n {/* Search */}\n <div className=\"relative group\">\n <Search\n size={18}\n className=\"absolute left-3 top-1/2 -translate-y-1/2 text-text-secondary group-focus-within:text-primary transition-colors\"\n />\n <input\n type=\"text\"\n aria-label={tr(\n \"export.templates.search.placeholder\",\n \"Search templates\",\n )}\n placeholder={tr(\n \"export.templates.search.placeholder\",\n \"Search templates...\",\n )}\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"w-full pl-[3.25rem] pr-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 />\n {searchQuery && (\n <button\n type=\"button\"\n onClick={() => setSearchQuery(\"\")}\n className=\"absolute right-3 top-1/2 -translate-y-1/2 p-1 rounded-md text-text-secondary hover:text-text-primary hover:bg-accent\"\n >\n <X size={16} />\n </button>\n )}\n </div>\n\n {/* Loading */}\n {isLoading && (\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-4\">\n {[...Array(4)].map((_, i) => (\n <div key={i} className=\"border border-border-seam rounded-xl p-5\">\n <div className=\"h-5 w-40 bg-bg-sunken rounded mb-3 animate-vc-shimmer\" />\n <div className=\"h-3 w-full bg-bg-sunken rounded mb-2 animate-vc-shimmer\" />\n <div className=\"flex gap-2 mt-4\">\n <div className=\"h-5 w-16 bg-bg-sunken rounded-full animate-vc-shimmer\" />\n <div className=\"h-5 w-16 bg-bg-sunken rounded-full animate-vc-shimmer\" />\n </div>\n </div>\n ))}\n </div>\n )}\n\n {/* Templates Grid */}\n {!isLoading ? (\n filteredTemplates.length > 0 ? (\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-4\">\n {filteredTemplates.map((template, index) => (\n <div\n key={template.id}\n role=\"button\"\n tabIndex={0}\n onClick={() => handleTemplateClick(template.id)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n handleTemplateClick(template.id);\n }\n }}\n className={cn(\n \"text-left group cursor-pointer border border-border-seam rounded-xl overflow-hidden bg-bg-surface\",\n \"hover:border-primary/40 shadow-[var(--shadow-pop)] transition-colors duration-200\",\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/40\",\n \"animate-in fade-in-0\",\n )}\n style={{ animationDelay: `${index * 50}ms` }}\n >\n {/* Header */}\n <div className=\"p-4 border-b bg-bg-sunken/30\">\n <div className=\"flex items-start justify-between\">\n <div className=\"flex items-center gap-3\">\n <div className=\"p-2 rounded-lg bg-action-primary-bg/10\">\n <FileBox size={20} className=\"text-primary\" />\n </div>\n <div>\n <h3 className=\"font-semibold\">{template.name}</h3>\n <p className=\"text-xs text-text-secondary\">\n {getFormatDisplayName(template.format)}\n {template.isDefault && (\n <span className=\"ml-1.5 inline-flex items-center px-1.5 py-0.5 rounded text-xs bg-action-primary-bg/10 text-primary font-medium\">\n {tr(\"export.templates.card.default\", \"Default\")}\n </span>\n )}\n </p>\n </div>\n </div>\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={(e) => handleDeleteTemplate(e, template.id)}\n className=\"p-1.5 rounded-md text-text-secondary hover:text-status-error-text hover:bg-status-error-bg/10 transition-colors\"\n aria-label={tr(\n \"export.templates.card.deleteAriaLabel\",\n \"Delete {name}\",\n { name: template.name },\n )}\n >\n <X size={14} />\n </button>\n <ChevronRight\n size={18}\n className=\"text-text-secondary group-hover:text-primary transition-colors mt-1\"\n />\n </div>\n </div>\n </div>\n\n {/* Body */}\n <div className=\"p-4\">\n {template.description && (\n <p className=\"text-sm text-text-secondary mb-3 line-clamp-2\">\n {template.description}\n </p>\n )}\n <div className=\"flex flex-wrap gap-1.5 overflow-hidden\">\n {template.entityTypes.slice(0, 6).map((entity) => (\n <span\n key={entity}\n className=\"inline-flex px-2 py-0.5 rounded text-xs font-medium bg-bg-sunken text-text-secondary max-w-full truncate\"\n >\n {entity}\n </span>\n ))}\n {template.entityTypes.length > 6 && (\n <span className=\"inline-flex px-2 py-0.5 rounded text-xs font-medium bg-bg-sunken text-text-secondary\">\n {tr(\n \"export.templates.card.moreEntities\",\n \"+{count} more\",\n {\n count: template.entityTypes.length - 6,\n },\n )}\n </span>\n )}\n </div>\n </div>\n </div>\n ))}\n </div>\n ) : (\n <IllustratedEmptyState\n illustration={searchQuery ? \"empty-search\" : \"empty-data\"}\n title={\n searchQuery\n ? tr(\n \"export.templates.empty.filtered.title\",\n \"No matching templates\",\n )\n : tr(\"export.templates.empty.title\", \"No templates yet\")\n }\n description={\n searchQuery\n ? tr(\n \"export.templates.empty.filtered.description\",\n \"Try adjusting your search to find what you are looking for.\",\n )\n : tr(\n \"export.templates.empty.description\",\n \"Create a template to save reusable export configurations.\",\n )\n }\n action={\n searchQuery ? (\n <button\n type=\"button\"\n onClick={() => setSearchQuery(\"\")}\n className=\"inline-flex items-center gap-2 px-4 py-2 border-2 border-border-subtle rounded-lg hover:bg-accent transition-colors font-medium\"\n >\n <X size={16} />\n {tr(\n \"export.templates.empty.filtered.actions.clear\",\n \"Clear Search\",\n )}\n </button>\n ) : (\n <button\n type=\"button\"\n onClick={handleOpenCreate}\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.templates.empty.actions.newTemplate\",\n \"New Template\",\n )}\n </button>\n )\n }\n />\n )\n ) : null}\n {templatePendingDelete && (\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"template-list-delete-title\"\n className=\"fixed inset-0 z-50 flex items-center justify-center bg-bg-surface/80 backdrop-blur-sm p-4\"\n >\n <div className=\"w-full max-w-md rounded-xl border-2 border-border-subtle bg-bg-surface p-6 shadow-xl\">\n <h2 id=\"template-list-delete-title\" className=\"text-lg font-bold\">\n {tr(\"export.templates.delete.title\", \"Delete template?\")}\n </h2>\n <p className=\"mt-2 text-sm text-text-secondary\">\n {tr(\n \"export.templates.delete.description\",\n \"This removes the saved export configuration. Existing export jobs are not deleted.\",\n )}\n </p>\n <div className=\"mt-6 flex flex-col-reverse sm:flex-row sm:justify-end gap-3\">\n <button\n type=\"button\"\n onClick={() => setTemplatePendingDelete(null)}\n className=\"px-4 py-2 rounded-lg border-2 border-border-subtle hover:bg-accent transition-colors font-medium\"\n >\n {tr(\"export.templates.delete.cancel\", \"Keep Template\")}\n </button>\n <button\n type=\"button\"\n onClick={confirmDeleteTemplate}\n className=\"px-4 py-2 rounded-lg bg-status-error-bg text-status-error-text hover:bg-status-error-bg/90 transition-colors font-medium\"\n >\n {tr(\"export.templates.delete.confirmAction\", \"Delete Template\")}\n </button>\n </div>\n </div>\n </div>\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ExportTemplatesPage.js","names":[],"sources":["../../../src/export/pages/ExportTemplatesPage.tsx"],"sourcesContent":["import { useState, useMemo } from \"react\";\nimport {\n Search,\n X,\n FileBox,\n Plus,\n ChevronRight,\n Sparkles,\n Loader2,\n} from \"lucide-react\";\nimport {\n CTAOverflowMenu,\n IllustratedEmptyState,\n PagePurpose,\n} from \"@burdenoff/fe-libs/ui\";\nimport { useExport } from \"../providers/ExportProvider\";\nimport {\n useExportTemplates,\n useDeleteExportTemplate,\n useCreateExportTemplate,\n useAvailableEntities,\n} from \"../hooks/useExportQueries\";\nimport { PageLayout } from \"../components/PageLayout\";\nimport { getFormatDisplayName } from \"../constants/enums\";\nimport { useTr } from \"../hooks/useTr\";\nimport { cn } from \"../utils/cn\";\nimport type { ExportFormat } from \"../types\";\nimport { nativeImpact, nativeNotify } from \"../../utils/nativeBridge\";\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 Templates Page\n * Template management list for reusable export configurations\n */\nexport function ExportTemplatesPage() {\n const { basePath = \"/\", navigate } = useExport();\n const tr = useTr();\n const { data: templates, isLoading } = useExportTemplates();\n const { deleteTemplate } = useDeleteExportTemplate();\n const { createTemplate, isPending: creating } = useCreateExportTemplate();\n const { data: availableEntities } = useAvailableEntities();\n\n const [searchQuery, setSearchQuery] = useState(\"\");\n const [showCreateForm, setShowCreateForm] = useState(false);\n const [newTemplateName, setNewTemplateName] = useState(\"\");\n const [newTemplateDescription, setNewTemplateDescription] = useState(\"\");\n const [newTemplateEntityTypes, setNewTemplateEntityTypes] = useState<\n string[]\n >([]);\n const [newTemplateFormat, setNewTemplateFormat] =\n useState<ExportFormat>(\"CSV\");\n const [createError, setCreateError] = useState<string | null>(null);\n const [templatePendingDelete, setTemplatePendingDelete] = useState<\n string | null\n >(null);\n\n const handleOpenCreate = () => {\n setNewTemplateName(\"\");\n setNewTemplateDescription(\"\");\n setNewTemplateEntityTypes([]);\n setNewTemplateFormat(\"CSV\");\n setCreateError(null);\n setShowCreateForm(true);\n };\n\n const handleCreateTemplate = async () => {\n if (!newTemplateName.trim()) {\n setCreateError(\n tr(\n \"export.templates.form.errors.nameRequired\",\n \"Template name is required.\",\n ),\n );\n return;\n }\n if (newTemplateEntityTypes.length === 0) {\n setCreateError(\n tr(\n \"export.templates.form.errors.entityRequired\",\n \"Select at least one entity type.\",\n ),\n );\n return;\n }\n setCreateError(null);\n try {\n await createTemplate({\n name: newTemplateName.trim(),\n description: newTemplateDescription.trim() || undefined,\n entityTypes: newTemplateEntityTypes,\n format: newTemplateFormat,\n });\n setShowCreateForm(false);\n } catch (err) {\n setCreateError(\n err instanceof Error\n ? err.message\n : tr(\n \"export.templates.form.errors.createFailed\",\n \"Failed to create template.\",\n ),\n );\n }\n };\n\n const toggleEntity = (entityType: string) => {\n setNewTemplateEntityTypes((prev) =>\n prev.includes(entityType)\n ? prev.filter((e) => e !== entityType)\n : [...prev, entityType],\n );\n };\n\n // Client-side search filter\n const filteredTemplates = useMemo(() => {\n if (!searchQuery) return templates;\n const q = searchQuery.toLowerCase();\n return templates.filter(\n (t) =>\n t.name.toLowerCase().includes(q) ||\n t.entityTypes.some((e) => e.toLowerCase().includes(q)),\n );\n }, [templates, searchQuery]);\n\n const handleTemplateClick = (templateId: string) => {\n navigate?.(joinPath(basePath, `templates/${templateId}`));\n };\n\n const handleDeleteTemplate = async (\n e: React.MouseEvent,\n templateId: string,\n ) => {\n e.stopPropagation();\n nativeImpact(\"medium\");\n setTemplatePendingDelete(templateId);\n };\n\n const confirmDeleteTemplate = async () => {\n if (!templatePendingDelete) return;\n try {\n await deleteTemplate(templatePendingDelete);\n nativeNotify(\"success\");\n } catch {\n nativeNotify(\"error\");\n }\n setTemplatePendingDelete(null);\n };\n\n return (\n <PageLayout\n title={tr(\"export.templates.title\", \"Export Templates\")}\n subtitle={tr(\n \"export.templates.subtitle\",\n \"Reusable export configurations for common data exports\",\n )}\n icon={<FileBox size={24} />}\n headerActions={\n <CTAOverflowMenu\n primary={{\n label: tr(\"export.templates.actions.newTemplate\", \"New Template\"),\n icon: <Plus size={16} />,\n onSelect: handleOpenCreate,\n }}\n actions={[\n {\n label: tr(\"export.templates.actions.newExport\", \"New Export\"),\n icon: <Plus size={16} />,\n onSelect: () => navigate?.(joinPath(basePath, \"new\")),\n },\n ]}\n />\n }\n headerContent={\n <span className=\"inline-flex items-center gap-1.5 px-2.5 py-0.5 rounded-full text-xs font-medium bg-bg-sunken text-text-secondary\">\n <Sparkles size={12} />\n {tr(\n \"export.templates.summary.available\",\n \"{{count}} template{{suffix}} available\",\n {\n count: filteredTemplates.length,\n suffix: filteredTemplates.length !== 1 ? \"s\" : \"\",\n },\n )}\n </span>\n }\n >\n {/* Page purpose — why templates exist */}\n <PagePurpose icon={<FileBox size={16} />}>\n {tr(\n \"export.templates.purpose\",\n \"Templates save an export setup — the entity types and format you regularly need — so you don't rebuild it each time. Create one here, then start a new export from it in a single click. Handy for recurring backups, periodic audits, or any export you run more than once.\",\n )}\n </PagePurpose>\n\n {/* Create Template Form */}\n {showCreateForm && (\n <div className=\"border border-primary/30 rounded-xl p-6 bg-accent-wash space-y-4\">\n <div className=\"flex items-center justify-between\">\n <h3 className=\"font-semibold text-lg\">\n {tr(\"export.templates.form.title\", \"New Template\")}\n </h3>\n <button\n type=\"button\"\n onClick={() => setShowCreateForm(false)}\n className=\"p-1.5 rounded-md hover:bg-accent\"\n >\n <X size={16} />\n </button>\n </div>\n {createError && (\n <p className=\"text-sm text-status-error-text bg-status-error-bg/10 rounded-lg px-3 py-2\">\n {createError}\n </p>\n )}\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-4\">\n <div className=\"space-y-1\">\n <label className=\"text-sm font-medium\">\n {tr(\"export.templates.form.fields.name\", \"Name\")} *\n </label>\n <input\n type=\"text\"\n aria-label={tr(\"export.templates.form.fields.name\", \"Name\")}\n placeholder={tr(\n \"export.templates.form.fields.namePlaceholder\",\n \"e.g. Weekly Tags Export\",\n )}\n value={newTemplateName}\n onChange={(e) => setNewTemplateName(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 transition-all\"\n />\n </div>\n <div className=\"space-y-1\">\n <label className=\"text-sm font-medium\">\n {tr(\"export.templates.form.fields.format\", \"Format\")} *\n </label>\n <select\n value={newTemplateFormat}\n onChange={(e) =>\n setNewTemplateFormat(e.target.value as ExportFormat)\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 transition-all scheme-normal dark:scheme-dark [&_option]:bg-bg-surface [&_option]:text-text-primary\"\n >\n <option value=\"CSV\">{tr(\"export.format.csv\", \"CSV\")}</option>\n <option value=\"JSON\">{tr(\"export.format.json\", \"JSON\")}</option>\n </select>\n </div>\n </div>\n <div className=\"space-y-1\">\n <label className=\"text-sm font-medium\">\n {tr(\"export.templates.form.fields.description\", \"Description\")}\n </label>\n <input\n type=\"text\"\n aria-label={tr(\n \"export.templates.form.fields.description\",\n \"Description\",\n )}\n placeholder={tr(\n \"export.templates.form.fields.descriptionPlaceholder\",\n \"Optional description\",\n )}\n value={newTemplateDescription}\n onChange={(e) => setNewTemplateDescription(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 transition-all\"\n />\n </div>\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\">\n {tr(\"export.templates.form.fields.entityTypes\", \"Entity Types\")} *{\" \"}\n <span className=\"text-text-secondary font-normal\">\n {tr(\n \"export.templates.form.fields.entityTypesHint\",\n \"(select at least one)\",\n )}\n </span>\n </label>\n <div className=\"flex flex-wrap gap-2\">\n {availableEntities.map((entity) => (\n <button\n key={entity.entityType}\n type=\"button\"\n onClick={() => toggleEntity(entity.entityType)}\n className={cn(\n \"px-3 py-1.5 rounded-lg text-sm font-medium border-2 transition-all\",\n newTemplateEntityTypes.includes(entity.entityType)\n ? \"border-primary bg-action-primary-bg/10 text-primary\"\n : \"border-border-subtle bg-bg-surface hover:border-primary/50\",\n )}\n >\n {entity.displayName}\n </button>\n ))}\n </div>\n </div>\n <div className=\"flex gap-3 pt-2\">\n <button\n type=\"button\"\n onClick={handleCreateTemplate}\n disabled={creating}\n className=\"inline-flex items-center gap-2 px-5 py-2.5 bg-action-primary-bg text-action-primary-text rounded-lg hover:bg-action-primary-bg/90 transition-colors font-medium disabled:opacity-50\"\n >\n {creating ? (\n <Loader2 size={16} className=\"animate-spin\" />\n ) : (\n <Plus size={16} />\n )}\n {tr(\"export.templates.form.actions.create\", \"Create Template\")}\n </button>\n <button\n type=\"button\"\n onClick={() => setShowCreateForm(false)}\n className=\"px-5 py-2.5 border-2 border-border-subtle rounded-lg hover:bg-accent transition-colors font-medium\"\n >\n {tr(\"export.templates.form.actions.cancel\", \"Cancel\")}\n </button>\n </div>\n </div>\n )}\n {/* Search */}\n <div className=\"relative group\">\n <Search\n size={18}\n className=\"absolute left-3 top-1/2 -translate-y-1/2 text-text-secondary group-focus-within:text-primary transition-colors\"\n />\n <input\n type=\"text\"\n aria-label={tr(\n \"export.templates.search.placeholder\",\n \"Search templates\",\n )}\n placeholder={tr(\n \"export.templates.search.placeholder\",\n \"Search templates...\",\n )}\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"w-full pl-[3.25rem] pr-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 />\n {searchQuery && (\n <button\n type=\"button\"\n onClick={() => setSearchQuery(\"\")}\n className=\"absolute right-3 top-1/2 -translate-y-1/2 p-1 rounded-md text-text-secondary hover:text-text-primary hover:bg-accent\"\n >\n <X size={16} />\n </button>\n )}\n </div>\n\n {/* Loading */}\n {isLoading && (\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-4\">\n {[...Array(4)].map((_, i) => (\n <div key={i} className=\"border border-border-seam rounded-xl p-5\">\n <div className=\"h-5 w-40 bg-bg-sunken rounded mb-3 animate-vc-shimmer\" />\n <div className=\"h-3 w-full bg-bg-sunken rounded mb-2 animate-vc-shimmer\" />\n <div className=\"flex gap-2 mt-4\">\n <div className=\"h-5 w-16 bg-bg-sunken rounded-full animate-vc-shimmer\" />\n <div className=\"h-5 w-16 bg-bg-sunken rounded-full animate-vc-shimmer\" />\n </div>\n </div>\n ))}\n </div>\n )}\n\n {/* Templates Grid */}\n {!isLoading ? (\n filteredTemplates.length > 0 ? (\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-4\">\n {filteredTemplates.map((template, index) => (\n <div\n key={template.id}\n role=\"button\"\n tabIndex={0}\n onClick={() => handleTemplateClick(template.id)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n handleTemplateClick(template.id);\n }\n }}\n className={cn(\n \"text-left group cursor-pointer border border-border-seam rounded-xl overflow-hidden bg-bg-surface\",\n \"hover:border-primary/40 shadow-[var(--shadow-pop)] transition-colors duration-200\",\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/40\",\n \"animate-in fade-in-0\",\n )}\n style={{ animationDelay: `${index * 50}ms` }}\n >\n {/* Header */}\n <div className=\"p-4 border-b bg-bg-sunken/30\">\n <div className=\"flex items-start justify-between\">\n <div className=\"flex items-center gap-3\">\n <div className=\"p-2 rounded-lg bg-action-primary-bg/10\">\n <FileBox size={20} className=\"text-primary\" />\n </div>\n <div>\n <h3 className=\"font-semibold\">{template.name}</h3>\n <p className=\"text-xs text-text-secondary\">\n {getFormatDisplayName(template.format)}\n {template.isDefault && (\n <span className=\"ml-1.5 inline-flex items-center px-1.5 py-0.5 rounded text-xs bg-action-primary-bg/10 text-primary font-medium\">\n {tr(\"export.templates.card.default\", \"Default\")}\n </span>\n )}\n </p>\n </div>\n </div>\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={(e) => handleDeleteTemplate(e, template.id)}\n className=\"p-1.5 rounded-md text-text-secondary hover:text-status-error-text hover:bg-status-error-bg/10 transition-colors\"\n aria-label={tr(\n \"export.templates.card.deleteAriaLabel\",\n \"Delete {{name}}\",\n { name: template.name },\n )}\n >\n <X size={14} />\n </button>\n <ChevronRight\n size={18}\n className=\"text-text-secondary group-hover:text-primary transition-colors mt-1\"\n />\n </div>\n </div>\n </div>\n\n {/* Body */}\n <div className=\"p-4\">\n {template.description && (\n <p className=\"text-sm text-text-secondary mb-3 line-clamp-2\">\n {template.description}\n </p>\n )}\n <div className=\"flex flex-wrap gap-1.5 overflow-hidden\">\n {template.entityTypes.slice(0, 6).map((entity) => (\n <span\n key={entity}\n className=\"inline-flex px-2 py-0.5 rounded text-xs font-medium bg-bg-sunken text-text-secondary max-w-full truncate\"\n >\n {entity}\n </span>\n ))}\n {template.entityTypes.length > 6 && (\n <span className=\"inline-flex px-2 py-0.5 rounded text-xs font-medium bg-bg-sunken text-text-secondary\">\n {tr(\n \"export.templates.card.moreEntities\",\n \"+{{count}} more\",\n {\n count: template.entityTypes.length - 6,\n },\n )}\n </span>\n )}\n </div>\n </div>\n </div>\n ))}\n </div>\n ) : (\n <IllustratedEmptyState\n illustration={searchQuery ? \"empty-search\" : \"empty-data\"}\n title={\n searchQuery\n ? tr(\n \"export.templates.empty.filtered.title\",\n \"No matching templates\",\n )\n : tr(\"export.templates.empty.title\", \"No templates yet\")\n }\n description={\n searchQuery\n ? tr(\n \"export.templates.empty.filtered.description\",\n \"Try adjusting your search to find what you are looking for.\",\n )\n : tr(\n \"export.templates.empty.description\",\n \"Create a template to save reusable export configurations.\",\n )\n }\n action={\n searchQuery ? (\n <button\n type=\"button\"\n onClick={() => setSearchQuery(\"\")}\n className=\"inline-flex items-center gap-2 px-4 py-2 border-2 border-border-subtle rounded-lg hover:bg-accent transition-colors font-medium\"\n >\n <X size={16} />\n {tr(\n \"export.templates.empty.filtered.actions.clear\",\n \"Clear Search\",\n )}\n </button>\n ) : (\n <button\n type=\"button\"\n onClick={handleOpenCreate}\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.templates.empty.actions.newTemplate\",\n \"New Template\",\n )}\n </button>\n )\n }\n />\n )\n ) : null}\n {templatePendingDelete && (\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"template-list-delete-title\"\n className=\"fixed inset-0 z-50 flex items-center justify-center bg-bg-surface/80 backdrop-blur-sm p-4\"\n >\n <div className=\"w-full max-w-md rounded-xl border-2 border-border-subtle bg-bg-surface p-6 shadow-xl\">\n <h2 id=\"template-list-delete-title\" className=\"text-lg font-bold\">\n {tr(\"export.templates.delete.title\", \"Delete template?\")}\n </h2>\n <p className=\"mt-2 text-sm text-text-secondary\">\n {tr(\n \"export.templates.delete.description\",\n \"This removes the saved export configuration. Existing export jobs are not deleted.\",\n )}\n </p>\n <div className=\"mt-6 flex flex-col-reverse sm:flex-row sm:justify-end gap-3\">\n <button\n type=\"button\"\n onClick={() => setTemplatePendingDelete(null)}\n className=\"px-4 py-2 rounded-lg border-2 border-border-subtle hover:bg-accent transition-colors font-medium\"\n >\n {tr(\"export.templates.delete.cancel\", \"Keep Template\")}\n </button>\n <button\n type=\"button\"\n onClick={confirmDeleteTemplate}\n className=\"px-4 py-2 rounded-lg bg-status-error-bg text-status-error-text hover:bg-status-error-bg/90 transition-colors font-medium\"\n >\n {tr(\"export.templates.delete.confirmAction\", \"Delete Template\")}\n </button>\n </div>\n </div>\n </div>\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|