@translationstudio/translationstudio-strapi-extension 2.0.2 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +1 -1
  2. package/dist/Types.d.ts +36 -0
  3. package/dist/_chunks/App-BR-y9Q87.js +331 -0
  4. package/dist/_chunks/App-Cc3EklWX.mjs +331 -0
  5. package/dist/_chunks/HistoryPage-BG_RchOk.js +1057 -0
  6. package/dist/_chunks/HistoryPage-CSMW8AED.mjs +1057 -0
  7. package/dist/_chunks/index-B9kFLfY3.js +834 -0
  8. package/dist/_chunks/index-ChM8Lw4L.mjs +835 -0
  9. package/dist/admin/index.js +2 -344
  10. package/dist/admin/index.mjs +2 -344
  11. package/dist/admin/src/components/BulkTranslationMenu.d.ts +3 -0
  12. package/dist/admin/src/components/BulkTranslationPanel.d.ts +3 -0
  13. package/dist/admin/src/components/EntryHistory.d.ts +3 -0
  14. package/dist/admin/src/components/HistoryIcon.d.ts +2 -0
  15. package/dist/admin/src/components/HistoryMenu.d.ts +2 -0
  16. package/dist/admin/src/components/LoadingSpinner.d.ts +4 -0
  17. package/dist/admin/src/components/SettingsIcon.d.ts +2 -0
  18. package/dist/admin/src/components/TranslationstudioLogo.d.ts +2 -0
  19. package/dist/admin/src/components/utils/alertUtils.d.ts +13 -0
  20. package/dist/admin/src/components/utils/dateUtils.d.ts +1 -0
  21. package/dist/admin/src/components/utils/emailUtils.d.ts +2 -0
  22. package/dist/admin/src/components/utils/entryUtils.d.ts +2 -0
  23. package/dist/admin/src/components/utils/filterAndTransformContentTypes.d.ts +2 -0
  24. package/dist/admin/src/components/utils/formatDate.d.ts +1 -0
  25. package/dist/admin/src/components/utils/getEntryHelper.d.ts +3 -0
  26. package/dist/admin/src/components/utils/handleHistoryResponse.d.ts +5 -0
  27. package/dist/admin/src/components/utils/historyDataUtils.d.ts +13 -0
  28. package/dist/admin/src/components/utils/historyStatusUtils.d.ts +7 -0
  29. package/dist/admin/src/components/utils/searchUtils.d.ts +2 -0
  30. package/dist/admin/src/components/utils/sortUtils.d.ts +9 -0
  31. package/dist/admin/src/components/utils/statusHelper.d.ts +6 -0
  32. package/dist/admin/src/components/utils/theme.d.ts +15 -0
  33. package/dist/admin/src/components/utils/translationUtils.d.ts +5 -0
  34. package/dist/admin/src/components/utils/useDebounce.d.ts +1 -0
  35. package/dist/admin/src/pages/HistoryPage.d.ts +2 -0
  36. package/dist/server/index.js +50 -29
  37. package/dist/server/index.mjs +50 -29
  38. package/dist/server/src/controllers/controller.d.ts +1 -1
  39. package/dist/server/src/controllers/index.d.ts +1 -1
  40. package/dist/server/src/index.d.ts +2 -4
  41. package/dist/server/src/services/functions/importData/transformFieldsToData.d.ts +1 -1
  42. package/dist/server/src/services/index.d.ts +1 -3
  43. package/dist/server/src/services/service.d.ts +1 -3
  44. package/package.json +23 -21
  45. package/dist/_chunks/App-C5dxwMbx.js +0 -342
  46. package/dist/_chunks/App-DxAbaDu8.mjs +0 -342
@@ -0,0 +1,1057 @@
1
+ import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
+ import { Box, Typography, TextInput, Table, Thead, Tr, Tbody, Td, Badge, Th, Button, Radio, Checkbox, DatePicker, ProgressBar, Alert, Main, Grid, Flex } from "@strapi/design-system";
3
+ import { useState, useEffect, useMemo } from "react";
4
+ import { getFetchClient } from "@strapi/strapi/admin";
5
+ import { g as groupHistoryData, f as formatDate, h as handleHistoryResponse, a as getThemeColors, u as useThemeMode, b as getStoredEmail, c as getSubmitLabel, s as setStoredEmail, v as validateDueDate, d as createEntryUid, e as determineEntryName, i as createTranslationPayload, j as createSuccessMessage, k as createErrorMessage, l as createGeneralErrorMessage, T as TranslationstudioLogo } from "./index-ChM8Lw4L.mjs";
6
+ const getSearchableText = (item) => {
7
+ return `${item["project-name"]} ${item["element-name"]} ${item["element-uid"]} ${item.targetLanguages.join(" ")} ${item.combinedStatus.text}`.toLowerCase();
8
+ };
9
+ const filterBySearchTerm = (items, searchTerm, getSearchableText2) => {
10
+ if (!searchTerm.trim()) return items;
11
+ const lowerSearchTerm = searchTerm.toLowerCase();
12
+ return items.filter((item) => getSearchableText2(item).includes(lowerSearchTerm));
13
+ };
14
+ const getSortValue = (item, sortField) => {
15
+ if (sortField === "status") {
16
+ return item.combinedStatus.text.toLowerCase();
17
+ }
18
+ if (sortField === "target-language") {
19
+ return item.targetLanguages.join(", ").toLowerCase();
20
+ }
21
+ return item[sortField].toString().toLowerCase();
22
+ };
23
+ const sortItems = (items, sortState) => {
24
+ return [...items].sort((a, b) => {
25
+ const aValue = getSortValue(a, sortState.field);
26
+ const bValue = getSortValue(b, sortState.field);
27
+ const result = aValue.localeCompare(bValue);
28
+ return sortState.direction === "asc" ? result : -result;
29
+ });
30
+ };
31
+ const getNextSortState = (currentState, clickedField) => {
32
+ if (currentState.field === clickedField) {
33
+ return {
34
+ field: clickedField,
35
+ direction: currentState.direction === "asc" ? "desc" : "asc"
36
+ };
37
+ }
38
+ return {
39
+ field: clickedField,
40
+ direction: "asc"
41
+ };
42
+ };
43
+ const useDebounce = (value, delay) => {
44
+ const [debouncedValue, setDebouncedValue] = useState(value);
45
+ useEffect(() => {
46
+ const timer = setTimeout(() => setDebouncedValue(value), delay);
47
+ return () => clearTimeout(timer);
48
+ }, [value, delay]);
49
+ return debouncedValue;
50
+ };
51
+ const DEBOUNCE_DELAY = 500;
52
+ const LoadingState = () => /* @__PURE__ */ jsx(Box, { padding: 4, children: /* @__PURE__ */ jsx(Typography, { variant: "beta", children: "Loading history..." }) });
53
+ const EmptyState = ({ hasSearchTerm }) => /* @__PURE__ */ jsx(Box, { padding: 4, children: /* @__PURE__ */ jsx(Typography, { variant: "omega", style: { color: "#666" }, children: hasSearchTerm ? "No matching translation history found." : "No translation history available." }) });
54
+ const SearchInput = ({ value, onChange }) => /* @__PURE__ */ jsx(Box, { paddingBottom: 4, children: /* @__PURE__ */ jsx(
55
+ TextInput,
56
+ {
57
+ placeholder: "Search by content type, entry, ID, target language, or status...",
58
+ value,
59
+ onChange,
60
+ style: { width: "100%" }
61
+ }
62
+ ) });
63
+ const SortableHeader = ({
64
+ field,
65
+ currentSort,
66
+ onSort,
67
+ children
68
+ }) => /* @__PURE__ */ jsx(Th, { children: /* @__PURE__ */ jsxs(
69
+ Box,
70
+ {
71
+ style: {
72
+ cursor: "pointer",
73
+ userSelect: "none",
74
+ display: "flex",
75
+ alignItems: "center",
76
+ gap: "4px"
77
+ },
78
+ onClick: () => onSort(field),
79
+ children: [
80
+ /* @__PURE__ */ jsx(Typography, { variant: "sigma", fontWeight: "bold", children }),
81
+ currentSort.field === field && /* @__PURE__ */ jsx("span", { style: { fontSize: "12px" }, children: currentSort.direction === "asc" ? "↑" : "↓" })
82
+ ]
83
+ }
84
+ ) });
85
+ const HistoryTable = ({
86
+ data,
87
+ sortState,
88
+ onSort
89
+ }) => /* @__PURE__ */ jsx(
90
+ Box,
91
+ {
92
+ style: {
93
+ borderRadius: "4px"
94
+ },
95
+ children: /* @__PURE__ */ jsxs(Table, { colCount: 6, rowCount: data.length + 1, children: [
96
+ /* @__PURE__ */ jsx(Thead, { children: /* @__PURE__ */ jsxs(Tr, { children: [
97
+ /* @__PURE__ */ jsx(SortableHeader, { field: "project-name", currentSort: sortState, onSort, children: "Content Type" }),
98
+ /* @__PURE__ */ jsx(SortableHeader, { field: "element-name", currentSort: sortState, onSort, children: "Entry" }),
99
+ /* @__PURE__ */ jsx(SortableHeader, { field: "element-uid", currentSort: sortState, onSort, children: "ID" }),
100
+ /* @__PURE__ */ jsx(SortableHeader, { field: "status", currentSort: sortState, onSort, children: "Status" }),
101
+ /* @__PURE__ */ jsx(SortableHeader, { field: "target-language", currentSort: sortState, onSort, children: "Target Language" }),
102
+ /* @__PURE__ */ jsx(SortableHeader, { field: "time-imported", currentSort: sortState, onSort, children: "Date" })
103
+ ] }) }),
104
+ /* @__PURE__ */ jsx(Tbody, { children: data.map((item, index) => /* @__PURE__ */ jsx(HistoryRow, { item }, `${item["element-uid"]}-${index}`)) })
105
+ ] })
106
+ }
107
+ );
108
+ const HistoryRow = ({ item }) => /* @__PURE__ */ jsxs(Tr, { children: [
109
+ /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Typography, { variant: "omega", children: item["project-name"] }) }),
110
+ /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Typography, { variant: "omega", children: item["element-name"] }) }),
111
+ /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Typography, { variant: "omega", style: { fontFamily: "monospace", fontSize: "12px" }, children: item["element-uid"] }) }),
112
+ /* @__PURE__ */ jsx(Td, { children: item.combinedStatus.text && /* @__PURE__ */ jsx(Badge, { variant: item.combinedStatus.variant, children: item.combinedStatus.text }) }),
113
+ /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Typography, { variant: "omega", children: item.targetLanguages.map((lang) => lang.toUpperCase()).join(", ") }) }),
114
+ /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Typography, { textColor: "neutral800", children: formatDate(item["time-imported"]) }) })
115
+ ] });
116
+ const HistoryMenu = () => {
117
+ const [historyData, setHistoryData] = useState([]);
118
+ const [isLoading, setIsLoading] = useState(true);
119
+ const [error, setError] = useState(null);
120
+ const [searchTerm, setSearchTerm] = useState("");
121
+ const [sortState, setSortState] = useState({
122
+ field: "project-name",
123
+ direction: "asc"
124
+ });
125
+ const { get } = getFetchClient();
126
+ const debouncedSearchTerm = useDebounce(searchTerm, DEBOUNCE_DELAY);
127
+ useEffect(() => {
128
+ const fetchHistory = async () => {
129
+ setIsLoading(true);
130
+ setError(null);
131
+ try {
132
+ const response = await get("/translationstudio/history");
133
+ const result = handleHistoryResponse(response.data);
134
+ if (result.isError) {
135
+ setError(result.errorMessage || "Failed to fetch translation history.");
136
+ } else {
137
+ setHistoryData(result.historyData);
138
+ }
139
+ } catch (error2) {
140
+ console.error("Failed to fetch history:", error2);
141
+ setError("Failed to fetch translation history.");
142
+ setHistoryData([]);
143
+ } finally {
144
+ setIsLoading(false);
145
+ }
146
+ };
147
+ fetchHistory();
148
+ }, [setIsLoading, setError, setHistoryData]);
149
+ const processedData = useMemo(() => {
150
+ const grouped = groupHistoryData(historyData);
151
+ const filtered = filterBySearchTerm(grouped, debouncedSearchTerm, getSearchableText);
152
+ return sortItems(filtered, sortState);
153
+ }, [historyData, debouncedSearchTerm, sortState]);
154
+ const handleSort = (field) => {
155
+ setSortState((currentState) => getNextSortState(currentState, field));
156
+ };
157
+ const handleSearchChange = (e) => {
158
+ setSearchTerm(e.target.value);
159
+ };
160
+ if (isLoading) {
161
+ return /* @__PURE__ */ jsx(LoadingState, {});
162
+ }
163
+ if (error) {
164
+ return /* @__PURE__ */ jsx(Box, { padding: 4, children: /* @__PURE__ */ jsx(Typography, { variant: "beta", textColor: "danger600", children: error }) });
165
+ }
166
+ const hasData = processedData.length > 0;
167
+ const hasSearchTerm = Boolean(debouncedSearchTerm.trim());
168
+ return /* @__PURE__ */ jsx(Box, { paddingTop: 4, paddingBottom: 4, style: { width: "100%" }, children: !hasData && !hasSearchTerm ? /* @__PURE__ */ jsx(EmptyState, { hasSearchTerm: false }) : /* @__PURE__ */ jsxs(Fragment, { children: [
169
+ historyData.length > 10 && /* @__PURE__ */ jsx(SearchInput, { value: searchTerm, onChange: handleSearchChange }),
170
+ hasData ? /* @__PURE__ */ jsx(HistoryTable, { data: processedData, sortState, onSort: handleSort }) : /* @__PURE__ */ jsx(EmptyState, { hasSearchTerm: true })
171
+ ] }) });
172
+ };
173
+ const LoadingSpinner = () => /* @__PURE__ */ jsxs(Box, { paddingBottom: 4, style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
174
+ /* @__PURE__ */ jsx(
175
+ Box,
176
+ {
177
+ style: {
178
+ width: "16px",
179
+ height: "16px",
180
+ border: "2px solid #f3f3f3",
181
+ borderTop: "2px solid #3498db",
182
+ borderRadius: "50%",
183
+ animation: "spin 1s linear infinite"
184
+ }
185
+ }
186
+ ),
187
+ /* @__PURE__ */ jsx(Typography, { children: "Loading translation settings..." }),
188
+ /* @__PURE__ */ jsx("style", { children: `
189
+ @keyframes spin {
190
+ 0% { transform: rotate(0deg); }
191
+ 100% { transform: rotate(360deg); }
192
+ }
193
+ ` })
194
+ ] });
195
+ const ErrorMessage = ({ message }) => /* @__PURE__ */ jsx(Box, { paddingBottom: 4, children: /* @__PURE__ */ jsx(Typography, { children: message }) });
196
+ const LanguageSelector = ({
197
+ languages,
198
+ selectedOption,
199
+ onSelectionChange,
200
+ themeColors
201
+ }) => /* @__PURE__ */ jsx(Box, { paddingBottom: 4, style: { color: themeColors.primaryText }, children: /* @__PURE__ */ jsxs(
202
+ Radio.Group,
203
+ {
204
+ onValueChange: onSelectionChange,
205
+ value: selectedOption,
206
+ name: "languages",
207
+ "aria-label": "translationstudio settings",
208
+ children: [
209
+ /* @__PURE__ */ jsx(
210
+ Typography,
211
+ {
212
+ variant: "omega",
213
+ tag: "label",
214
+ paddingBottom: 2,
215
+ style: { color: themeColors.primaryText },
216
+ children: "Languages / Connectors"
217
+ }
218
+ ),
219
+ languages.map((lang) => /* @__PURE__ */ jsx(Radio.Item, { value: lang.name, children: lang.name }, lang.id))
220
+ ]
221
+ }
222
+ ) });
223
+ const AdditionalSettings = ({
224
+ isUrgent,
225
+ isEmail,
226
+ email,
227
+ dueDate,
228
+ onUrgentChange,
229
+ onEmailChange,
230
+ onEmailInputChange,
231
+ onDueDateChange,
232
+ themeColors
233
+ }) => /* @__PURE__ */ jsxs(Fragment, { children: [
234
+ /* @__PURE__ */ jsx(Box, { paddingBottom: 4, children: /* @__PURE__ */ jsx(
235
+ Typography,
236
+ {
237
+ variant: "omega",
238
+ tag: "label",
239
+ style: { color: themeColors.primaryText },
240
+ paddingBottom: 4,
241
+ children: "Additional Settings"
242
+ }
243
+ ) }),
244
+ /* @__PURE__ */ jsx(Box, { paddingBottom: 4, children: /* @__PURE__ */ jsx(Checkbox, { onCheckedChange: onUrgentChange, defaultChecked: isUrgent, children: /* @__PURE__ */ jsx(Typography, { variant: "omega", style: { color: themeColors.primaryText }, children: "translate immediately (and ignore quotes)" }) }) }),
245
+ /* @__PURE__ */ jsx(Box, { paddingBottom: 4, children: /* @__PURE__ */ jsx(Checkbox, { onCheckedChange: onEmailChange, defaultChecked: isEmail, children: /* @__PURE__ */ jsx(Typography, { variant: "omega", style: { color: themeColors.primaryText }, children: "Send email notifications on translation status updates" }) }) }),
246
+ isEmail && /* @__PURE__ */ jsx(Box, { paddingBottom: 4, children: /* @__PURE__ */ jsx(
247
+ TextInput,
248
+ {
249
+ label: "Email Address",
250
+ name: "email",
251
+ type: "email",
252
+ value: email,
253
+ onChange: onEmailInputChange,
254
+ placeholder: "Enter your email address"
255
+ }
256
+ ) }),
257
+ !isUrgent && /* @__PURE__ */ jsxs(Box, { paddingBottom: 4, children: [
258
+ /* @__PURE__ */ jsx(Box, { paddingBottom: 2, children: /* @__PURE__ */ jsx(Typography, { variant: "omega", style: { color: themeColors.primaryText }, children: "Due Date" }) }),
259
+ /* @__PURE__ */ jsx(DatePicker, { onChange: onDueDateChange, selecteddate: dueDate ? new Date(dueDate) : null })
260
+ ] })
261
+ ] });
262
+ const ProgressIndicator = ({ progress }) => /* @__PURE__ */ jsxs(Box, { paddingBottom: 4, children: [
263
+ /* @__PURE__ */ jsxs(Typography, { variant: "omega", paddingBottom: 2, children: [
264
+ "Processing... ",
265
+ Math.round(progress),
266
+ "%"
267
+ ] }),
268
+ /* @__PURE__ */ jsx(ProgressBar, { value: progress })
269
+ ] });
270
+ const AlertMessage = ({
271
+ show,
272
+ type,
273
+ message,
274
+ onClose
275
+ }) => {
276
+ if (!show) return null;
277
+ return /* @__PURE__ */ jsx(
278
+ Box,
279
+ {
280
+ style: {
281
+ position: "fixed",
282
+ top: "10%",
283
+ left: "50%",
284
+ transform: "translate(-50%, -50%)",
285
+ zIndex: 10,
286
+ minWidth: "400px",
287
+ maxWidth: "90%"
288
+ },
289
+ children: /* @__PURE__ */ jsx(Alert, { closeLabel: "Close", variant: type, onClose, children: message })
290
+ }
291
+ );
292
+ };
293
+ const BulkTranslationPanel = ({
294
+ contentType,
295
+ selectedEntries,
296
+ onTranslationComplete
297
+ }) => {
298
+ const [languages, setLanguages] = useState([]);
299
+ const [selectedOption, setSelectedOption] = useState("");
300
+ const [source, setSource] = useState("");
301
+ const [email, setEmail] = useState("");
302
+ const [isEmail, setIsEmail] = useState(true);
303
+ const [isUrgent, setIsUrgent] = useState(false);
304
+ const [dueDate, setDueDate] = useState(0);
305
+ const [showAlert, setShowAlert] = useState(false);
306
+ const [alertType, setAlertType] = useState("success");
307
+ const [alertMessage, setAlertMessage] = useState("");
308
+ const [licenseValid, setLicenseValid] = useState(null);
309
+ const [tsIsAvailable, setTsIsAvailable] = useState(true);
310
+ const [isProcessing, setIsProcessing] = useState(false);
311
+ const [progress, setProgress] = useState(0);
312
+ const [isLoadingMappings, setIsLoadingMappings] = useState(false);
313
+ const [mappingsError, setMappingsError] = useState(false);
314
+ const themeColors = getThemeColors();
315
+ useThemeMode();
316
+ const { get, post } = getFetchClient();
317
+ const selectedLang = languages.find((lang) => lang.name === selectedOption);
318
+ const isMachineTranslation = selectedLang?.machine ?? false;
319
+ useEffect(() => {
320
+ if (!contentType) return;
321
+ setIsLoadingMappings(true);
322
+ setMappingsError(false);
323
+ get("/translationstudio/getLicense").then((response) => {
324
+ if (typeof response.data.license !== "string") return false;
325
+ return response.data.license !== "";
326
+ }).then((hasLicense) => {
327
+ setLicenseValid(hasLicense);
328
+ if (!hasLicense) throw new Error("No license set");
329
+ setTsIsAvailable(true);
330
+ return get("/translationstudio/mappings");
331
+ }).then((langs) => {
332
+ if (langs.data && Array.isArray(langs.data) && langs.data.length > 0) {
333
+ setLanguages(langs.data);
334
+ setMappingsError(false);
335
+ } else {
336
+ setLanguages([]);
337
+ setMappingsError(true);
338
+ }
339
+ }).catch((err) => {
340
+ console.error(err);
341
+ setTsIsAvailable(false);
342
+ setMappingsError(true);
343
+ }).finally(() => {
344
+ setIsLoadingMappings(false);
345
+ });
346
+ }, [contentType]);
347
+ useEffect(() => {
348
+ if (!contentType || !isEmail) return;
349
+ const savedEmail = getStoredEmail();
350
+ if (savedEmail) {
351
+ setEmail(savedEmail);
352
+ }
353
+ }, [isEmail]);
354
+ const handleUrgentChange = () => {
355
+ if (isUrgent) {
356
+ setIsUrgent(false);
357
+ setDueDate(0);
358
+ } else {
359
+ setIsUrgent(true);
360
+ }
361
+ };
362
+ const handleEmailChange = () => {
363
+ const newEmailState = !isEmail;
364
+ setIsEmail(newEmailState);
365
+ if (newEmailState) {
366
+ const savedEmail = getStoredEmail();
367
+ if (savedEmail) {
368
+ setEmail(savedEmail);
369
+ }
370
+ } else {
371
+ setEmail("");
372
+ }
373
+ };
374
+ const handleEmailInputChange = (e) => {
375
+ const newEmail = e.target.value;
376
+ setEmail(newEmail);
377
+ setStoredEmail(newEmail);
378
+ };
379
+ const handleDueDateChange = (date) => {
380
+ const validatedDate = validateDueDate(date);
381
+ setDueDate(validatedDate);
382
+ setIsUrgent(false);
383
+ };
384
+ const handleRadioSelection = (value) => {
385
+ setSelectedOption(value);
386
+ const lang = languages.find((l) => l.name === value);
387
+ if (lang) {
388
+ setSource(lang.source);
389
+ if (lang.machine) {
390
+ setIsUrgent(false);
391
+ setDueDate(0);
392
+ }
393
+ }
394
+ };
395
+ const displayAlert = (type, message) => {
396
+ setAlertType(type);
397
+ setAlertMessage(message);
398
+ setShowAlert(true);
399
+ setTimeout(() => setShowAlert(false), 5e3);
400
+ };
401
+ const handleBulkTranslationRequest = async () => {
402
+ if (!contentType || !selectedLang) return;
403
+ setIsProcessing(true);
404
+ setProgress(0);
405
+ try {
406
+ let successCount = 0;
407
+ let errorCount = 0;
408
+ for (let i = 0; i < selectedEntries.length; i++) {
409
+ const entryId = selectedEntries[i];
410
+ setProgress((i + 1) / selectedEntries.length * 100);
411
+ try {
412
+ const entryUid = createEntryUid(contentType, entryId);
413
+ const entryResponse = await post("/translationstudio/entrydata", {
414
+ uid: entryUid,
415
+ locale: source
416
+ });
417
+ const fetchedEntryData = entryResponse.data;
418
+ const entryName = determineEntryName(fetchedEntryData, contentType.displayName);
419
+ const payload = createTranslationPayload(
420
+ selectedLang,
421
+ dueDate,
422
+ isEmail,
423
+ isMachineTranslation,
424
+ email,
425
+ isUrgent,
426
+ contentType.displayName,
427
+ entryUid,
428
+ entryName
429
+ );
430
+ const response = await post("/translationstudio/translate", payload);
431
+ if (response.data === true) {
432
+ successCount++;
433
+ } else {
434
+ errorCount++;
435
+ }
436
+ } catch (error) {
437
+ console.error(`Failed to translate entry ${entryId}:`, error);
438
+ errorCount++;
439
+ }
440
+ await new Promise((resolve) => setTimeout(resolve, 100));
441
+ }
442
+ if (errorCount === 0) {
443
+ const { type, message } = createSuccessMessage(successCount, selectedEntries.length);
444
+ displayAlert(type, message);
445
+ } else if (successCount === 0) {
446
+ const { type, message } = createErrorMessage(selectedEntries.length);
447
+ displayAlert(type, message);
448
+ } else {
449
+ const { type, message } = createSuccessMessage(successCount, selectedEntries.length);
450
+ displayAlert(type, message);
451
+ }
452
+ onTranslationComplete();
453
+ } catch (error) {
454
+ console.error("Bulk translation error:", error);
455
+ const { type, message } = createGeneralErrorMessage();
456
+ displayAlert(type, message);
457
+ } finally {
458
+ setIsProcessing(false);
459
+ setProgress(0);
460
+ }
461
+ };
462
+ const renderNotAvailable = () => {
463
+ if (isLoadingMappings) {
464
+ return /* @__PURE__ */ jsx(LoadingSpinner, {});
465
+ }
466
+ if (!tsIsAvailable || mappingsError) {
467
+ return /* @__PURE__ */ jsx(ErrorMessage, { message: "Error fetching translation settings." });
468
+ }
469
+ if (licenseValid === false) {
470
+ return /* @__PURE__ */ jsx(ErrorMessage, { message: "Your translationstudio license is invalid. Please update your strapi configuration." });
471
+ }
472
+ if (languages.length === 0) {
473
+ return /* @__PURE__ */ jsx(ErrorMessage, { message: "No translation settings available. translationstudio has not been configured yet. Please add translation settings first." });
474
+ }
475
+ return null;
476
+ };
477
+ const pluginIsAvailable = () => {
478
+ return !isLoadingMappings && licenseValid !== null && tsIsAvailable === true && !mappingsError;
479
+ };
480
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
481
+ /* @__PURE__ */ jsx(
482
+ AlertMessage,
483
+ {
484
+ show: showAlert,
485
+ type: alertType,
486
+ message: alertMessage,
487
+ onClose: () => setShowAlert(false)
488
+ }
489
+ ),
490
+ /* @__PURE__ */ jsx(
491
+ Box,
492
+ {
493
+ padding: 4,
494
+ style: {
495
+ width: "100%",
496
+ backgroundColor: themeColors.cardBackground,
497
+ borderRadius: "4px"
498
+ },
499
+ children: !pluginIsAvailable() ? renderNotAvailable() : /* @__PURE__ */ jsxs(Fragment, { children: [
500
+ /* @__PURE__ */ jsx(
501
+ LanguageSelector,
502
+ {
503
+ languages,
504
+ selectedOption,
505
+ onSelectionChange: handleRadioSelection,
506
+ themeColors
507
+ }
508
+ ),
509
+ !isMachineTranslation && selectedOption !== "" && /* @__PURE__ */ jsx(
510
+ AdditionalSettings,
511
+ {
512
+ isUrgent,
513
+ isEmail,
514
+ email,
515
+ dueDate,
516
+ onUrgentChange: handleUrgentChange,
517
+ onEmailChange: handleEmailChange,
518
+ onEmailInputChange: handleEmailInputChange,
519
+ onDueDateChange: handleDueDateChange,
520
+ themeColors
521
+ }
522
+ ),
523
+ isProcessing && /* @__PURE__ */ jsx(ProgressIndicator, { progress }),
524
+ /* @__PURE__ */ jsx(
525
+ Button,
526
+ {
527
+ fullWidth: true,
528
+ onClick: handleBulkTranslationRequest,
529
+ disabled: !selectedOption || isProcessing,
530
+ loading: isProcessing,
531
+ startIcon: /* @__PURE__ */ jsx(
532
+ "svg",
533
+ {
534
+ width: "20",
535
+ height: "20",
536
+ viewBox: "0 0 24 24",
537
+ fill: "none",
538
+ xmlns: "http://www.w3.org/2000/svg",
539
+ children: /* @__PURE__ */ jsx("path", { d: "M2,21L23,12L2,3V10L17,12L2,14V21Z", fill: "currentColor" })
540
+ }
541
+ ),
542
+ children: getSubmitLabel(selectedEntries.length, isUrgent, isMachineTranslation)
543
+ }
544
+ )
545
+ ] })
546
+ }
547
+ )
548
+ ] });
549
+ };
550
+ const filterAndTransformContentTypes = (data) => {
551
+ return data.filter((type) => type.kind === "collectionType" || type.kind === "singleType").filter((type) => !type.uid.startsWith("admin::") && !type.uid.startsWith("plugin::")).map((type) => ({
552
+ uid: type.uid,
553
+ displayName: type.info.displayName,
554
+ kind: type.kind
555
+ }));
556
+ };
557
+ const getEntryTitle = (entry) => {
558
+ const titleFields = ["title", "name", "headline"];
559
+ for (const field of titleFields) {
560
+ if (entry[field] && typeof entry[field] === "string") {
561
+ return entry[field];
562
+ }
563
+ }
564
+ const excludedFields = ["id", "documentId", "createdAt", "updatedAt", "publishedAt", "locale"];
565
+ for (const [key, value] of Object.entries(entry)) {
566
+ if (!excludedFields.includes(key) && typeof value === "string" && value.trim()) {
567
+ return value;
568
+ }
569
+ }
570
+ return `Entry #${entry.documentId || entry.id}`;
571
+ };
572
+ const getEntryId = (entry) => {
573
+ return entry.documentId || entry.id;
574
+ };
575
+ const getTranslationStatus = (entryId, historyData) => {
576
+ if (!Array.isArray(historyData) || historyData.length === 0) {
577
+ return "error_fetching_history";
578
+ }
579
+ const matchingItems = historyData.filter((h) => h["element-uid"].includes(entryId));
580
+ if (matchingItems.length === 0) {
581
+ return "not_translated";
582
+ }
583
+ const hasInTranslation = matchingItems.some((item) => {
584
+ const timeInTranslation = item["time-intranslation"] || 0;
585
+ const timeImported = item["time-imported"] || 0;
586
+ return timeInTranslation > timeImported;
587
+ });
588
+ if (hasInTranslation) {
589
+ return "in_translation";
590
+ }
591
+ const hasTranslated = matchingItems.some((item) => {
592
+ const timeImported = item["time-imported"] || 0;
593
+ return timeImported > 0;
594
+ });
595
+ return hasTranslated ? "translated" : "not_translated";
596
+ };
597
+ const getTargetLanguages = (entryId, historyData) => {
598
+ if (!Array.isArray(historyData) || historyData.length === 0) return [];
599
+ const matchingItems = historyData.filter((h) => h["element-uid"].includes(entryId));
600
+ const languages = [...new Set(matchingItems.map((item) => item["target-language"]))];
601
+ return languages.sort();
602
+ };
603
+ const getTranslationDate = (entryId, historyData) => {
604
+ if (!Array.isArray(historyData) || historyData.length === 0) return "";
605
+ const matchingItems = historyData.filter((h) => h["element-uid"].includes(entryId));
606
+ if (matchingItems.length === 0) return "";
607
+ const latestImportTime = Math.max(
608
+ ...matchingItems.map((item) => item["time-imported"] || 0)
609
+ );
610
+ return latestImportTime > 0 ? formatDate(latestImportTime) : "";
611
+ };
612
+ const getStatusBadgeVariant = (status) => {
613
+ const variants = {
614
+ translated: "success",
615
+ in_translation: "secondary",
616
+ error_fetching_history: "danger",
617
+ not_translated: "neutral"
618
+ };
619
+ return variants[status] || "neutral";
620
+ };
621
+ const getStatusDisplayText = (status) => {
622
+ const texts = {
623
+ translated: "Translated",
624
+ in_translation: "In Translation",
625
+ error_fetching_history: "Error fetching history",
626
+ not_translated: "Not Translated"
627
+ };
628
+ return texts[status] || "Not Translated";
629
+ };
630
+ const ContentTypesList = ({
631
+ contentTypes,
632
+ isLoading,
633
+ selectedContentType,
634
+ onContentTypeClick,
635
+ themeColors
636
+ }) => /* @__PURE__ */ jsxs(Box, { style: { width: "250px", flexShrink: 0, display: "flex", flexDirection: "column" }, children: [
637
+ /* @__PURE__ */ jsx(
638
+ Typography,
639
+ {
640
+ variant: "omega",
641
+ paddingBottom: 3,
642
+ style: { fontWeight: "bold", color: themeColors.primaryText },
643
+ children: "Content Types"
644
+ }
645
+ ),
646
+ /* @__PURE__ */ jsx(Box, { style: { paddingTop: "8px", paddingBottom: "8px" }, children: isLoading ? /* @__PURE__ */ jsx(Box, { padding: 2, children: /* @__PURE__ */ jsx(Typography, { variant: "omega", style: { color: themeColors.primaryText }, children: "Loading..." }) }) : /* @__PURE__ */ jsx(Box, { style: { display: "flex", flexDirection: "column", gap: "4px" }, children: contentTypes.map((type) => /* @__PURE__ */ jsx(
647
+ ContentTypeItem,
648
+ {
649
+ type,
650
+ isSelected: selectedContentType === type.uid,
651
+ onClick: () => onContentTypeClick(type.uid),
652
+ themeColors
653
+ },
654
+ type.uid
655
+ )) }) })
656
+ ] });
657
+ const ContentTypeItem = ({
658
+ type,
659
+ isSelected,
660
+ onClick,
661
+ themeColors
662
+ }) => /* @__PURE__ */ jsxs(
663
+ Box,
664
+ {
665
+ style: {
666
+ padding: "8px 12px",
667
+ borderRadius: "4px",
668
+ cursor: "pointer",
669
+ backgroundColor: themeColors.cardBackground,
670
+ border: isSelected ? "1px solid #7b79ff" : "1px solid transparent",
671
+ transition: "all 0.2s ease"
672
+ },
673
+ onClick,
674
+ children: [
675
+ /* @__PURE__ */ jsx(
676
+ Typography,
677
+ {
678
+ variant: "omega",
679
+ style: {
680
+ fontWeight: isSelected ? "bold" : "normal",
681
+ color: isSelected ? "#7b79ff" : themeColors.primaryText
682
+ },
683
+ children: type.displayName
684
+ }
685
+ ),
686
+ /* @__PURE__ */ jsx(Box, { paddingTop: 1, children: /* @__PURE__ */ jsx(Typography, { variant: "pi", style: { color: themeColors.mutedText, fontSize: "11px" }, children: type.kind }) })
687
+ ]
688
+ }
689
+ );
690
+ const EntriesTable = ({
691
+ entries,
692
+ isLoading,
693
+ selectedEntries,
694
+ historyData,
695
+ isLoadingHistory,
696
+ onEntrySelection,
697
+ onSelectAll,
698
+ themeColors
699
+ }) => {
700
+ if (isLoading) {
701
+ return /* @__PURE__ */ jsx(
702
+ Box,
703
+ {
704
+ style: {
705
+ borderRadius: "4px",
706
+ padding: "16px",
707
+ backgroundColor: themeColors.cardBackground
708
+ },
709
+ children: /* @__PURE__ */ jsx(Typography, { variant: "omega", style: { color: themeColors.secondaryText }, children: "Loading entries..." })
710
+ }
711
+ );
712
+ }
713
+ if (entries.length === 0) {
714
+ return /* @__PURE__ */ jsx(
715
+ Box,
716
+ {
717
+ style: {
718
+ borderRadius: "4px",
719
+ padding: "16px",
720
+ backgroundColor: themeColors.cardBackground
721
+ },
722
+ children: /* @__PURE__ */ jsx(Typography, { variant: "omega", style: { color: themeColors.mutedText }, children: "No entries found for this content type." })
723
+ }
724
+ );
725
+ }
726
+ return /* @__PURE__ */ jsx(
727
+ Box,
728
+ {
729
+ style: {
730
+ borderRadius: "4px",
731
+ overflow: "auto",
732
+ display: "flex",
733
+ flexDirection: "column",
734
+ maxHeight: "fit-content",
735
+ backgroundColor: themeColors.cardBackground
736
+ },
737
+ children: /* @__PURE__ */ jsxs(Table, { colCount: 6, rowCount: entries.length + 1, children: [
738
+ /* @__PURE__ */ jsx(Thead, { children: /* @__PURE__ */ jsxs(Tr, { children: [
739
+ /* @__PURE__ */ jsx(Th, { style: { width: "50px" }, children: /* @__PURE__ */ jsx(
740
+ Checkbox,
741
+ {
742
+ checked: selectedEntries.size === entries.length && entries.length > 0,
743
+ indeterminate: selectedEntries.size > 0 && selectedEntries.size < entries.length,
744
+ onCheckedChange: onSelectAll
745
+ }
746
+ ) }),
747
+ /* @__PURE__ */ jsx(Th, { children: /* @__PURE__ */ jsx(
748
+ Typography,
749
+ {
750
+ variant: "sigma",
751
+ fontWeight: "bold",
752
+ style: { color: themeColors.primaryText },
753
+ children: "Title"
754
+ }
755
+ ) }),
756
+ /* @__PURE__ */ jsx(Th, { children: /* @__PURE__ */ jsx(
757
+ Typography,
758
+ {
759
+ variant: "sigma",
760
+ fontWeight: "bold",
761
+ style: { color: themeColors.primaryText },
762
+ children: "ID"
763
+ }
764
+ ) }),
765
+ /* @__PURE__ */ jsx(Th, { children: /* @__PURE__ */ jsx(
766
+ Typography,
767
+ {
768
+ variant: "sigma",
769
+ fontWeight: "bold",
770
+ style: { color: themeColors.primaryText },
771
+ children: "Status"
772
+ }
773
+ ) }),
774
+ /* @__PURE__ */ jsx(Th, { children: /* @__PURE__ */ jsx(
775
+ Typography,
776
+ {
777
+ variant: "sigma",
778
+ fontWeight: "bold",
779
+ style: { color: themeColors.primaryText },
780
+ children: "Target Language"
781
+ }
782
+ ) }),
783
+ /* @__PURE__ */ jsx(Th, { children: /* @__PURE__ */ jsx(
784
+ Typography,
785
+ {
786
+ variant: "sigma",
787
+ fontWeight: "bold",
788
+ style: { color: themeColors.primaryText },
789
+ children: "Date"
790
+ }
791
+ ) })
792
+ ] }) }),
793
+ /* @__PURE__ */ jsx(Tbody, { children: entries.map((entry) => /* @__PURE__ */ jsx(
794
+ EntryRow,
795
+ {
796
+ entry,
797
+ isSelected: selectedEntries.has(getEntryId(entry)),
798
+ historyData,
799
+ isLoadingHistory,
800
+ onEntrySelection,
801
+ themeColors
802
+ },
803
+ getEntryId(entry)
804
+ )) })
805
+ ] })
806
+ }
807
+ );
808
+ };
809
+ const EntryRow = ({
810
+ entry,
811
+ isSelected,
812
+ historyData,
813
+ isLoadingHistory,
814
+ onEntrySelection,
815
+ themeColors
816
+ }) => {
817
+ const entryId = getEntryId(entry);
818
+ const status = getTranslationStatus(entryId, historyData);
819
+ const targetLanguages = getTargetLanguages(entryId, historyData);
820
+ const date = getTranslationDate(entryId, historyData);
821
+ return /* @__PURE__ */ jsxs(Tr, { children: [
822
+ /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(
823
+ Checkbox,
824
+ {
825
+ checked: isSelected,
826
+ onCheckedChange: (checked) => onEntrySelection(entryId, checked)
827
+ }
828
+ ) }),
829
+ /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Typography, { variant: "omega", style: { color: themeColors.primaryText }, children: getEntryTitle(entry) }) }),
830
+ /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(
831
+ Typography,
832
+ {
833
+ variant: "omega",
834
+ style: { fontFamily: "monospace", fontSize: "12px", color: themeColors.secondaryText },
835
+ children: entryId
836
+ }
837
+ ) }),
838
+ /* @__PURE__ */ jsx(Td, { children: isLoadingHistory ? /* @__PURE__ */ jsx(Typography, { variant: "omega", style: { color: themeColors.mutedText }, children: "Loading..." }) : /* @__PURE__ */ jsx(Badge, { variant: getStatusBadgeVariant(status), children: getStatusDisplayText(status) }) }),
839
+ /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Typography, { variant: "omega", style: { color: themeColors.primaryText }, children: targetLanguages.map((lang) => lang.toUpperCase()).join(", ") || "-" }) }),
840
+ /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Typography, { variant: "omega", style: { color: themeColors.primaryText }, children: date }) })
841
+ ] });
842
+ };
843
+ const BulkTranslationMenu = ({
844
+ historyData,
845
+ isLoadingHistory,
846
+ onTranslationComplete
847
+ }) => {
848
+ const [contentTypes, setContentTypes] = useState([]);
849
+ const [selectedContentType, setSelectedContentType] = useState("");
850
+ const [entries, setEntries] = useState([]);
851
+ const [selectedEntries, setSelectedEntries] = useState(/* @__PURE__ */ new Set());
852
+ const [isLoadingContentTypes, setIsLoadingContentTypes] = useState(false);
853
+ const [isLoadingEntries, setIsLoadingEntries] = useState(false);
854
+ const themeColors = getThemeColors();
855
+ const { get } = getFetchClient();
856
+ useEffect(() => {
857
+ const fetchContentTypes = async () => {
858
+ setIsLoadingContentTypes(true);
859
+ try {
860
+ const response = await get("/content-manager/content-types");
861
+ const types = filterAndTransformContentTypes(response.data.data);
862
+ setContentTypes(types);
863
+ } catch (error) {
864
+ console.error("Failed to fetch content types:", error);
865
+ } finally {
866
+ setIsLoadingContentTypes(false);
867
+ }
868
+ };
869
+ fetchContentTypes();
870
+ }, [setIsLoadingContentTypes, setContentTypes]);
871
+ const fetchContentEntries = function(selectedContentType2) {
872
+ if (!selectedContentType2) {
873
+ return;
874
+ }
875
+ setIsLoadingEntries(true);
876
+ get(`/content-manager/collection-types/${selectedContentType2}`).then((response) => {
877
+ setEntries(response.data.results || []);
878
+ setSelectedEntries(/* @__PURE__ */ new Set());
879
+ }).catch((error) => {
880
+ console.error("Failed to fetch entries:", error);
881
+ setEntries([]);
882
+ }).finally(() => setIsLoadingEntries(false));
883
+ };
884
+ const selectedContentTypeData = useMemo(
885
+ () => contentTypes.find((ct) => ct.uid === selectedContentType),
886
+ [contentTypes, selectedContentType]
887
+ );
888
+ const handleContentTypeClick = (contentTypeUid) => {
889
+ if (selectedContentType === contentTypeUid)
890
+ return;
891
+ setSelectedContentType(contentTypeUid);
892
+ fetchContentEntries(contentTypeUid);
893
+ };
894
+ const handleEntrySelection = (entryId, isSelected) => {
895
+ const newSelection = new Set(selectedEntries);
896
+ if (isSelected) {
897
+ newSelection.add(entryId);
898
+ } else {
899
+ newSelection.delete(entryId);
900
+ }
901
+ setSelectedEntries(newSelection);
902
+ };
903
+ const handleSelectAll = (isSelected) => {
904
+ if (isSelected) {
905
+ setSelectedEntries(new Set(entries.map(getEntryId)));
906
+ } else {
907
+ setSelectedEntries(/* @__PURE__ */ new Set());
908
+ }
909
+ };
910
+ const handleTranslationComplete = () => {
911
+ setSelectedEntries(/* @__PURE__ */ new Set());
912
+ onTranslationComplete?.();
913
+ };
914
+ return /* @__PURE__ */ jsx(Box, { paddingTop: 4, paddingBottom: 4, style: { overflow: "hidden", display: "flex", flexDirection: "column" }, children: /* @__PURE__ */ jsxs(Box, { style: { flex: 1, display: "flex", gap: "16px", overflow: "hidden" }, children: [
915
+ /* @__PURE__ */ jsx(
916
+ ContentTypesList,
917
+ {
918
+ contentTypes,
919
+ isLoading: isLoadingContentTypes,
920
+ selectedContentType,
921
+ onContentTypeClick: handleContentTypeClick,
922
+ themeColors
923
+ }
924
+ ),
925
+ /* @__PURE__ */ jsxs(
926
+ Box,
927
+ {
928
+ style: {
929
+ flex: 1,
930
+ display: "flex",
931
+ flexDirection: "column",
932
+ minWidth: "400px",
933
+ width: "60vw"
934
+ },
935
+ children: [
936
+ /* @__PURE__ */ jsx(Typography, { variant: "omega", paddingBottom: 3, style: { fontWeight: "bold" }, children: "Entries" }),
937
+ selectedContentType ? /* @__PURE__ */ jsx(
938
+ EntriesTable,
939
+ {
940
+ entries,
941
+ isLoading: isLoadingEntries,
942
+ selectedEntries,
943
+ historyData,
944
+ isLoadingHistory,
945
+ onEntrySelection: handleEntrySelection,
946
+ onSelectAll: handleSelectAll,
947
+ themeColors
948
+ }
949
+ ) : /* @__PURE__ */ jsx(Box, { style: { borderRadius: "4px", padding: "16px" }, children: /* @__PURE__ */ jsx(Typography, { variant: "omega", style: { color: "#666" }, children: "Select a content type to view entries." }) })
950
+ ]
951
+ }
952
+ ),
953
+ /* @__PURE__ */ jsx(Box, { style: { width: "400px", flexShrink: 0, display: "flex", flexDirection: "column" }, children: selectedEntries.size > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
954
+ /* @__PURE__ */ jsx(Typography, { variant: "omega", paddingBottom: 3, style: { fontWeight: "bold" }, children: "Translation Settings" }),
955
+ /* @__PURE__ */ jsx(Box, { style: { borderRadius: "4px", overflow: "hidden" }, children: /* @__PURE__ */ jsx(
956
+ BulkTranslationPanel,
957
+ {
958
+ contentType: selectedContentTypeData,
959
+ selectedEntries: Array.from(selectedEntries),
960
+ onTranslationComplete: handleTranslationComplete
961
+ }
962
+ ) })
963
+ ] }) })
964
+ ] }) });
965
+ };
966
+ const HistoryPage = () => {
967
+ const [historyData, setHistoryData] = useState([]);
968
+ const [isLoadingHistory, setIsLoadingHistory] = useState(true);
969
+ const [activeTab, setActiveTab] = useState("history");
970
+ const { get } = getFetchClient();
971
+ useEffect(() => {
972
+ const fetchHistory = async () => {
973
+ try {
974
+ const response = await get("/translationstudio/history");
975
+ const result = handleHistoryResponse(response.data);
976
+ if (result.isError) {
977
+ } else {
978
+ setHistoryData(result.historyData);
979
+ }
980
+ } catch (error) {
981
+ console.error("Failed to fetch history:", error);
982
+ setHistoryData([]);
983
+ } finally {
984
+ setIsLoadingHistory(false);
985
+ }
986
+ };
987
+ fetchHistory();
988
+ }, [setHistoryData, setIsLoadingHistory]);
989
+ const refreshHistoryData = async () => {
990
+ setIsLoadingHistory(true);
991
+ try {
992
+ const response = await get("/translationstudio/history");
993
+ const result = handleHistoryResponse(response.data);
994
+ if (result.isError) {
995
+ setHistoryData([]);
996
+ } else {
997
+ setHistoryData(result.historyData);
998
+ }
999
+ } catch (error) {
1000
+ setHistoryData([]);
1001
+ } finally {
1002
+ setIsLoadingHistory(false);
1003
+ }
1004
+ };
1005
+ return /* @__PURE__ */ jsx(Main, { children: /* @__PURE__ */ jsx(Box, { padding: 10, style: { minHeight: "90vh", marginTop: "5vh" }, children: /* @__PURE__ */ jsxs(Grid.Root, { children: [
1006
+ /* @__PURE__ */ jsx(Grid.Item, { xs: 12, children: /* @__PURE__ */ jsx(Box, { style: { textAlign: "right", width: "100%" }, children: /* @__PURE__ */ jsx(
1007
+ "picture",
1008
+ {
1009
+ style: {
1010
+ width: "150px",
1011
+ height: "auto",
1012
+ display: "inline-block"
1013
+ },
1014
+ children: /* @__PURE__ */ jsx(TranslationstudioLogo, {})
1015
+ }
1016
+ ) }) }),
1017
+ /* @__PURE__ */ jsx(Grid.Item, { xs: 12, children: /* @__PURE__ */ jsx(Box, { paddingBottom: 4, children: /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
1018
+ /* @__PURE__ */ jsx(
1019
+ Button,
1020
+ {
1021
+ variant: activeTab === "history" ? "default" : "tertiary",
1022
+ onClick: () => setActiveTab("history"),
1023
+ children: "Translation History"
1024
+ }
1025
+ ),
1026
+ /* @__PURE__ */ jsx(
1027
+ Button,
1028
+ {
1029
+ variant: activeTab === "bulk" ? "default" : "tertiary",
1030
+ onClick: () => setActiveTab("bulk"),
1031
+ children: "Translate multiple entries"
1032
+ }
1033
+ )
1034
+ ] }) }) }),
1035
+ /* @__PURE__ */ jsxs(Grid.Item, { xs: 12, children: [
1036
+ activeTab === "bulk" && /* @__PURE__ */ jsx(
1037
+ BulkTranslationMenu,
1038
+ {
1039
+ historyData,
1040
+ isLoadingHistory,
1041
+ onTranslationComplete: refreshHistoryData
1042
+ }
1043
+ ),
1044
+ activeTab === "history" && /* @__PURE__ */ jsx(
1045
+ HistoryMenu,
1046
+ {
1047
+ historyData,
1048
+ isLoadingHistory,
1049
+ onRefresh: refreshHistoryData
1050
+ }
1051
+ )
1052
+ ] })
1053
+ ] }) }) });
1054
+ };
1055
+ export {
1056
+ HistoryPage
1057
+ };