@translationstudio/translationstudio-strapi-extension 4.1.1 → 4.3.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.
- package/dist/Types.d.ts +5 -1
- package/dist/_chunks/{App-5ldte7Ku.js → App-C2A-alX9.js} +1 -1
- package/dist/_chunks/{App-DQUxEmfa.mjs → App-CUYIBOWI.mjs} +1 -1
- package/dist/_chunks/{HistoryPage-Cwm3HJc9.mjs → HistoryPage-AhmPF4m4.mjs} +187 -168
- package/dist/_chunks/{HistoryPage-C1EG7XIt.js → HistoryPage-C77OaOGZ.js} +186 -167
- package/dist/_chunks/{index-DF5d8Feh.mjs → index-Csx0xlBL.mjs} +65 -71
- package/dist/_chunks/{index-DkASHLO0.js → index-Dgpsawos.js} +53 -59
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +2 -2
- package/dist/admin/src/components/DeleteHistoryEntryRequest.d.ts +6 -0
- package/dist/admin/src/components/utils/historyDataUtils.d.ts +9 -10
- package/dist/admin/src/components/utils/historyStatusUtils.d.ts +3 -6
- package/dist/admin/src/components/utils/sortUtils.d.ts +0 -1
- package/dist/server/index.js +54 -9
- package/dist/server/index.mjs +54 -9
- package/dist/server/src/controllers/controller.d.ts +1 -0
- package/dist/server/src/controllers/index.d.ts +1 -0
- package/dist/server/src/index.d.ts +2 -0
- package/dist/server/src/services/index.d.ts +1 -0
- package/dist/server/src/services/service.d.ts +1 -0
- package/package.json +1 -1
package/dist/Types.d.ts
CHANGED
|
@@ -143,6 +143,9 @@ export interface ImportPayload {
|
|
|
143
143
|
keep?: TranslatedDocumentReplaceFields;
|
|
144
144
|
}[];
|
|
145
145
|
}
|
|
146
|
+
export type HistoryDataMap = {
|
|
147
|
+
[id: string]: HistoryItem[];
|
|
148
|
+
};
|
|
146
149
|
export interface HistoryItem {
|
|
147
150
|
'time-intranslation': number;
|
|
148
151
|
'project-name': string;
|
|
@@ -152,6 +155,7 @@ export interface HistoryItem {
|
|
|
152
155
|
'time-updated': number;
|
|
153
156
|
'element-name': string;
|
|
154
157
|
'time-requested': number;
|
|
158
|
+
'id': string;
|
|
155
159
|
}
|
|
156
160
|
export interface ContentType {
|
|
157
161
|
uid: string;
|
|
@@ -167,7 +171,7 @@ export interface Entry {
|
|
|
167
171
|
[key: string]: any;
|
|
168
172
|
}
|
|
169
173
|
export interface BulkTranslationMenuProps {
|
|
170
|
-
historyData:
|
|
174
|
+
historyData: HistoryDataMap;
|
|
171
175
|
isLoadingHistory: boolean;
|
|
172
176
|
onTranslationComplete?: () => void;
|
|
173
177
|
}
|
|
@@ -5,7 +5,7 @@ const admin = require("@strapi/strapi/admin");
|
|
|
5
5
|
const reactRouterDom = require("react-router-dom");
|
|
6
6
|
const designSystem = require("@strapi/design-system");
|
|
7
7
|
const react = require("react");
|
|
8
|
-
const index = require("./index-
|
|
8
|
+
const index = require("./index-Dgpsawos.js");
|
|
9
9
|
const apiService = {
|
|
10
10
|
async loadLicense(get) {
|
|
11
11
|
try {
|
|
@@ -3,7 +3,7 @@ import { getFetchClient, Page } from "@strapi/strapi/admin";
|
|
|
3
3
|
import { Routes, Route } from "react-router-dom";
|
|
4
4
|
import { Main, Box, Alert, Grid, Typography, TextInput, Switch, Button } from "@strapi/design-system";
|
|
5
5
|
import { useState, useCallback, useEffect } from "react";
|
|
6
|
-
import { T as TranslationstudioLogo } from "./index-
|
|
6
|
+
import { T as TranslationstudioLogo } from "./index-Csx0xlBL.mjs";
|
|
7
7
|
const apiService = {
|
|
8
8
|
async loadLicense(get) {
|
|
9
9
|
try {
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { Modal, Typography, Button, Box, Alert, TextInput, Table, Thead, Tr, Th, Tbody, Td, Badge, SimpleMenu, IconButton, MenuItem, Radio, Checkbox, DatePicker, ProgressBar, Main, Grid, Flex } from "@strapi/design-system";
|
|
3
3
|
import { useState, useEffect, useMemo } from "react";
|
|
4
4
|
import { getFetchClient } from "@strapi/strapi/admin";
|
|
5
|
-
import { g as groupHistoryData,
|
|
5
|
+
import { g as getThemeColors, a as groupHistoryData, G as GetStatusColor, b as GetStatusText, f as formatDate, h as handleHistoryResponse, u as useThemeMode, c as getStoredEmail, d as getSubmitLabel, s as setStoredEmail, v as validateDueDate, e as createEntryUid, i as determineEntryName, j as createTranslationPayload, k as createSuccessMessage, l as createErrorMessage, m as createGeneralErrorMessage, n as getElementStatus, T as TranslationstudioLogo } from "./index-Csx0xlBL.mjs";
|
|
6
|
+
import { Trash, More, Bell } from "@strapi/icons";
|
|
6
7
|
const getSearchableText = (item) => {
|
|
7
8
|
return `${item["project-name"]} ${item["element-name"]} ${item["element-uid"]} ${item.targetLanguages.join(" ")} ${item.combinedStatus.text}`.toLowerCase();
|
|
8
9
|
};
|
|
@@ -12,19 +13,33 @@ const filterBySearchTerm = (items, searchTerm, getSearchableText2) => {
|
|
|
12
13
|
return items.filter((item) => getSearchableText2(item).includes(lowerSearchTerm));
|
|
13
14
|
};
|
|
14
15
|
const getSortValue = (item, sortField) => {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
switch (sortField) {
|
|
17
|
+
case "project-name":
|
|
18
|
+
case "element-uid":
|
|
19
|
+
return item["element-uid"] ?? "";
|
|
20
|
+
case "status":
|
|
21
|
+
return item["status"] ?? "";
|
|
22
|
+
case "element-name":
|
|
23
|
+
return item["element-name"];
|
|
24
|
+
case "target-language":
|
|
25
|
+
return item["targetLanguage"] ?? "";
|
|
26
|
+
case "time-imported":
|
|
27
|
+
return item.timeUpdated ?? 0;
|
|
28
|
+
default:
|
|
29
|
+
return "";
|
|
20
30
|
}
|
|
21
|
-
|
|
31
|
+
};
|
|
32
|
+
const compareValues = function(a, b) {
|
|
33
|
+
if (typeof a === "number" && typeof b === "number")
|
|
34
|
+
return a - b;
|
|
35
|
+
else
|
|
36
|
+
return a.localeCompare(b);
|
|
22
37
|
};
|
|
23
38
|
const sortItems = (items, sortState) => {
|
|
24
39
|
return [...items].sort((a, b) => {
|
|
25
40
|
const aValue = getSortValue(a, sortState.field);
|
|
26
41
|
const bValue = getSortValue(b, sortState.field);
|
|
27
|
-
const result = aValue
|
|
42
|
+
const result = compareValues(aValue, bValue);
|
|
28
43
|
return sortState.direction === "asc" ? result : -result;
|
|
29
44
|
});
|
|
30
45
|
};
|
|
@@ -48,6 +63,30 @@ const useDebounce = (value, delay) => {
|
|
|
48
63
|
}, [value, delay]);
|
|
49
64
|
return debouncedValue;
|
|
50
65
|
};
|
|
66
|
+
function DeleteHistoryEntryRequest({ item, onDeleted, onClose }) {
|
|
67
|
+
return /* @__PURE__ */ jsx(Modal.Root, { open: true, onOpenChange: () => onClose(), children: /* @__PURE__ */ jsxs(Modal.Content, { children: [
|
|
68
|
+
/* @__PURE__ */ jsx(Modal.Header, { children: /* @__PURE__ */ jsx(Modal.Title, { children: "Delete translation history information" }) }),
|
|
69
|
+
/* @__PURE__ */ jsxs(Modal.Body, { children: [
|
|
70
|
+
/* @__PURE__ */ jsx("p", { children: /* @__PURE__ */ jsx(Typography, { variant: "beta", children: "Really delete this enty?" }) }),
|
|
71
|
+
/* @__PURE__ */ jsx("p", { children: /* @__PURE__ */ jsx(Typography, { children: "This cannot be undone. You can always translate the entry again." }) }),
|
|
72
|
+
/* @__PURE__ */ jsx("p", { children: " " }),
|
|
73
|
+
/* @__PURE__ */ jsx("p", { children: /* @__PURE__ */ jsxs(Typography, { children: [
|
|
74
|
+
"Name: ",
|
|
75
|
+
item["element-name"],
|
|
76
|
+
/* @__PURE__ */ jsx("br", {}),
|
|
77
|
+
"Status: ",
|
|
78
|
+
item.status,
|
|
79
|
+
/* @__PURE__ */ jsx("br", {}),
|
|
80
|
+
"Language: ",
|
|
81
|
+
item.targetLanguage
|
|
82
|
+
] }) })
|
|
83
|
+
] }),
|
|
84
|
+
/* @__PURE__ */ jsxs(Modal.Footer, { children: [
|
|
85
|
+
/* @__PURE__ */ jsx(Button, { onClick: onClose, variant: "tertiary", children: "Cancel" }),
|
|
86
|
+
/* @__PURE__ */ jsx(Button, { onClick: onDeleted, startIcon: /* @__PURE__ */ jsx(Trash, {}), children: "Delete" })
|
|
87
|
+
] })
|
|
88
|
+
] }) });
|
|
89
|
+
}
|
|
51
90
|
const DEBOUNCE_DELAY = 500;
|
|
52
91
|
const LoadingState = () => /* @__PURE__ */ jsx(Box, { padding: 4, children: /* @__PURE__ */ jsx(Typography, { variant: "beta", children: "Loading history..." }) });
|
|
53
92
|
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." }) });
|
|
@@ -85,7 +124,9 @@ const SortableHeader = ({
|
|
|
85
124
|
const HistoryTable = ({
|
|
86
125
|
data,
|
|
87
126
|
sortState,
|
|
88
|
-
onSort
|
|
127
|
+
onSort,
|
|
128
|
+
onDelete,
|
|
129
|
+
secondaryColor
|
|
89
130
|
}) => /* @__PURE__ */ jsx(
|
|
90
131
|
Box,
|
|
91
132
|
{
|
|
@@ -94,35 +135,63 @@ const HistoryTable = ({
|
|
|
94
135
|
},
|
|
95
136
|
children: /* @__PURE__ */ jsxs(Table, { colCount: 6, rowCount: data.length + 1, children: [
|
|
96
137
|
/* @__PURE__ */ jsx(Thead, { children: /* @__PURE__ */ jsxs(Tr, { children: [
|
|
97
|
-
/* @__PURE__ */ jsx(SortableHeader, { field: "project-name", currentSort: sortState, onSort, children: "Content Type" }),
|
|
98
138
|
/* @__PURE__ */ jsx(SortableHeader, { field: "element-name", currentSort: sortState, onSort, children: "Entry" }),
|
|
99
|
-
/* @__PURE__ */ jsx(SortableHeader, { field: "
|
|
139
|
+
/* @__PURE__ */ jsx(SortableHeader, { field: "project-name", currentSort: sortState, onSort, children: "Content Type" }),
|
|
100
140
|
/* @__PURE__ */ jsx(SortableHeader, { field: "status", currentSort: sortState, onSort, children: "Status" }),
|
|
101
141
|
/* @__PURE__ */ jsx(SortableHeader, { field: "target-language", currentSort: sortState, onSort, children: "Target Language" }),
|
|
102
|
-
/* @__PURE__ */ jsx(SortableHeader, { field: "time-imported", currentSort: sortState, onSort, children: "Date" })
|
|
142
|
+
/* @__PURE__ */ jsx(SortableHeader, { field: "time-imported", currentSort: sortState, onSort, children: "Date" }),
|
|
143
|
+
/* @__PURE__ */ jsx(Th, {})
|
|
103
144
|
] }) }),
|
|
104
|
-
/* @__PURE__ */ jsx(Tbody, { children: data.map((item, index) => /* @__PURE__ */ jsx(
|
|
145
|
+
/* @__PURE__ */ jsx(Tbody, { children: data.map((item, index) => /* @__PURE__ */ jsx(
|
|
146
|
+
HistoryRow,
|
|
147
|
+
{
|
|
148
|
+
item,
|
|
149
|
+
onDelete,
|
|
150
|
+
secondaryColor
|
|
151
|
+
},
|
|
152
|
+
`${item["element-uid"]}-${index}`
|
|
153
|
+
)) })
|
|
105
154
|
] })
|
|
106
155
|
}
|
|
107
156
|
);
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
157
|
+
const getContentType = function(input) {
|
|
158
|
+
const left = input.indexOf(".");
|
|
159
|
+
const right = input.lastIndexOf("#");
|
|
160
|
+
if (left === -1 || left > right || right === -1)
|
|
161
|
+
return "-";
|
|
162
|
+
return input.substring(left + 1, right);
|
|
163
|
+
};
|
|
164
|
+
const getElementId = function(input) {
|
|
165
|
+
const right = input.lastIndexOf("#");
|
|
166
|
+
if (right === -1)
|
|
167
|
+
return "-";
|
|
168
|
+
return input.substring(right + 1);
|
|
169
|
+
};
|
|
170
|
+
const HistoryRow = ({ item, onDelete, secondaryColor }) => /* @__PURE__ */ jsxs(Tr, { children: [
|
|
171
|
+
/* @__PURE__ */ jsxs(Td, { children: [
|
|
172
|
+
/* @__PURE__ */ jsx("p", { children: /* @__PURE__ */ jsx(Typography, { variant: "omega", children: item["element-name"] }) }),
|
|
173
|
+
/* @__PURE__ */ jsx(Typography, { variant: "omega", style: { fontFamily: "monospace", fontSize: "12px", color: secondaryColor }, children: getElementId(item["element-uid"]) })
|
|
174
|
+
] }),
|
|
175
|
+
/* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Typography, { variant: "omega", children: getContentType(item["element-uid"]) }) }),
|
|
176
|
+
/* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Badge, { variant: GetStatusColor(item.status), children: GetStatusText(item.status) }) }),
|
|
177
|
+
/* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Typography, { variant: "omega", children: item.targetLanguage.toUpperCase() }) }),
|
|
178
|
+
/* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Typography, { textColor: "neutral800", children: formatDate(item.timeUpdated) }) }),
|
|
179
|
+
/* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(SimpleMenu, { label: "Actions", tag: IconButton, icon: /* @__PURE__ */ jsx(More, {}), children: /* @__PURE__ */ jsx(MenuItem, { startIcon: /* @__PURE__ */ jsx(Bell, {}), variant: "danger", onSelect: () => onDelete(item), children: "Delete history entry" }) }) })
|
|
115
180
|
] });
|
|
116
181
|
const HistoryMenu = () => {
|
|
117
182
|
const [historyData, setHistoryData] = useState([]);
|
|
118
183
|
const [isLoading, setIsLoading] = useState(true);
|
|
119
184
|
const [error, setError] = useState(null);
|
|
185
|
+
const [errorMessage, setErrorMessage] = useState("");
|
|
186
|
+
const [succcessMessage, setSucccessMessage] = useState("");
|
|
120
187
|
const [searchTerm, setSearchTerm] = useState("");
|
|
188
|
+
const [deleteItem, setDeleteItem] = useState(null);
|
|
121
189
|
const [sortState, setSortState] = useState({
|
|
122
|
-
field: "
|
|
123
|
-
direction: "
|
|
190
|
+
field: "time-imported",
|
|
191
|
+
direction: "desc"
|
|
124
192
|
});
|
|
125
|
-
const { get } = getFetchClient();
|
|
193
|
+
const { get, post } = getFetchClient();
|
|
194
|
+
const themeColors = getThemeColors();
|
|
126
195
|
const debouncedSearchTerm = useDebounce(searchTerm, DEBOUNCE_DELAY);
|
|
127
196
|
useEffect(() => {
|
|
128
197
|
const fetchHistory = async () => {
|
|
@@ -133,8 +202,10 @@ const HistoryMenu = () => {
|
|
|
133
202
|
const result = handleHistoryResponse(response.data);
|
|
134
203
|
if (result.isError) {
|
|
135
204
|
setError(result.errorMessage || "Failed to fetch translation history.");
|
|
136
|
-
} else {
|
|
137
|
-
|
|
205
|
+
} else if (result.historyData && Array.isArray(result.historyData) && result.historyData.length > 0) {
|
|
206
|
+
const res = result.historyData;
|
|
207
|
+
res.sort((a, b) => a["time-updated"] - b["time-updated"]);
|
|
208
|
+
setHistoryData(res);
|
|
138
209
|
}
|
|
139
210
|
} catch (error2) {
|
|
140
211
|
console.error("Failed to fetch history:", error2);
|
|
@@ -163,11 +234,49 @@ const HistoryMenu = () => {
|
|
|
163
234
|
if (error) {
|
|
164
235
|
return /* @__PURE__ */ jsx(Box, { padding: 4, children: /* @__PURE__ */ jsx(Typography, { variant: "beta", textColor: "danger600", children: error }) });
|
|
165
236
|
}
|
|
237
|
+
const removeHistoryEntry = function(item) {
|
|
238
|
+
if (!item || historyData.length === 0)
|
|
239
|
+
return;
|
|
240
|
+
if (historyData.length === 1) {
|
|
241
|
+
setHistoryData([]);
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
let index = -1;
|
|
245
|
+
for (let i = 0; i < historyData.length && index === -1; i++) {
|
|
246
|
+
if (historyData[i].id === item.id)
|
|
247
|
+
index = i;
|
|
248
|
+
}
|
|
249
|
+
if (index === -1)
|
|
250
|
+
return;
|
|
251
|
+
historyData.splice(index, 1);
|
|
252
|
+
setHistoryData([...historyData]);
|
|
253
|
+
};
|
|
254
|
+
const onDeleteHistoyInfo = function(elem) {
|
|
255
|
+
if (!errorMessage)
|
|
256
|
+
setErrorMessage("");
|
|
257
|
+
if (!succcessMessage)
|
|
258
|
+
setSucccessMessage("");
|
|
259
|
+
if (!deleteItem)
|
|
260
|
+
return;
|
|
261
|
+
post("/translationstudio/history", {
|
|
262
|
+
uid: deleteItem.id
|
|
263
|
+
}).then((res) => {
|
|
264
|
+
if (res.status !== 204)
|
|
265
|
+
throw new Error("Could not delete entry");
|
|
266
|
+
removeHistoryEntry(deleteItem);
|
|
267
|
+
setSucccessMessage("Successfully removed history entry.");
|
|
268
|
+
}).catch(() => setErrorMessage("Could not delete history entry " + deleteItem["element-name"])).finally(() => setDeleteItem(null));
|
|
269
|
+
};
|
|
166
270
|
const hasData = processedData.length > 0;
|
|
167
271
|
const hasSearchTerm = Boolean(debouncedSearchTerm.trim());
|
|
168
272
|
return /* @__PURE__ */ jsx(Box, { paddingTop: 4, paddingBottom: 4, style: { width: "100%" }, children: !hasData && !hasSearchTerm ? /* @__PURE__ */ jsx(EmptyState, { hasSearchTerm: false }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
169
273
|
historyData.length > 10 && /* @__PURE__ */ jsx(SearchInput, { value: searchTerm, onChange: handleSearchChange }),
|
|
170
|
-
|
|
274
|
+
errorMessage && /* @__PURE__ */ jsx(Alert, { title: errorMessage, variant: "danger", style: { marginBottom: "2em" }, children: errorMessage }),
|
|
275
|
+
succcessMessage && /* @__PURE__ */ jsx(Alert, { title: succcessMessage, variant: "success", style: { marginBottom: "2em" }, children: succcessMessage }),
|
|
276
|
+
hasData ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
277
|
+
deleteItem && /* @__PURE__ */ jsx(DeleteHistoryEntryRequest, { item: deleteItem, onClose: () => setDeleteItem(null), onDeleted: onDeleteHistoyInfo }),
|
|
278
|
+
/* @__PURE__ */ jsx(HistoryTable, { data: processedData, sortState, onSort: handleSort, onDelete: setDeleteItem, secondaryColor: themeColors.secondaryText })
|
|
279
|
+
] }) : /* @__PURE__ */ jsx(EmptyState, { hasSearchTerm: true })
|
|
171
280
|
] }) });
|
|
172
281
|
};
|
|
173
282
|
const LoadingSpinner = () => /* @__PURE__ */ jsxs(Box, { paddingBottom: 4, style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
|
|
@@ -213,7 +322,7 @@ const LanguageSelector = ({
|
|
|
213
322
|
tag: "label",
|
|
214
323
|
paddingBottom: 2,
|
|
215
324
|
style: { color: themeColors.primaryText },
|
|
216
|
-
children: "
|
|
325
|
+
children: "Translation Options"
|
|
217
326
|
}
|
|
218
327
|
),
|
|
219
328
|
languages.map((lang) => /* @__PURE__ */ jsx(Radio.Item, { value: lang.name, children: lang.name }, lang.id))
|
|
@@ -539,6 +648,7 @@ const BulkTranslationPanel = ({
|
|
|
539
648
|
children: /* @__PURE__ */ jsx("path", { d: "M2,21L23,12L2,3V10L17,12L2,14V21Z", fill: "currentColor" })
|
|
540
649
|
}
|
|
541
650
|
),
|
|
651
|
+
style: { height: "auto" },
|
|
542
652
|
children: getSubmitLabel(selectedEntries.length, isUrgent, isMachineTranslation)
|
|
543
653
|
}
|
|
544
654
|
)
|
|
@@ -572,65 +682,6 @@ const getEntryTitle = (entry) => {
|
|
|
572
682
|
const getEntryId = (entry) => {
|
|
573
683
|
return entry.documentId || entry.id;
|
|
574
684
|
};
|
|
575
|
-
const getTranslationStatus = (entryId, historyData) => {
|
|
576
|
-
if (!Array.isArray(historyData) || historyData.length === 0) {
|
|
577
|
-
return "";
|
|
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
|
-
switch (status) {
|
|
614
|
-
case "translated":
|
|
615
|
-
return "success";
|
|
616
|
-
case "in_translation":
|
|
617
|
-
return "secondary";
|
|
618
|
-
default:
|
|
619
|
-
return "neutral";
|
|
620
|
-
}
|
|
621
|
-
};
|
|
622
|
-
const getStatusDisplayText = (status) => {
|
|
623
|
-
switch (status) {
|
|
624
|
-
case "translated":
|
|
625
|
-
return "Translated";
|
|
626
|
-
case "in_translation":
|
|
627
|
-
return "In Translation";
|
|
628
|
-
case "not_translated":
|
|
629
|
-
return "Not translated";
|
|
630
|
-
default:
|
|
631
|
-
return "n.a.";
|
|
632
|
-
}
|
|
633
|
-
};
|
|
634
685
|
const ContentTypesList = ({
|
|
635
686
|
contentTypes,
|
|
636
687
|
isLoading,
|
|
@@ -740,60 +791,13 @@ const EntriesTable = ({
|
|
|
740
791
|
maxHeight: "fit-content",
|
|
741
792
|
backgroundColor: themeColors.cardBackground
|
|
742
793
|
},
|
|
743
|
-
children: /* @__PURE__ */ jsxs(Table, { colCount:
|
|
794
|
+
children: /* @__PURE__ */ jsxs(Table, { colCount: 5, children: [
|
|
744
795
|
/* @__PURE__ */ jsx(Thead, { children: /* @__PURE__ */ jsxs(Tr, { children: [
|
|
745
|
-
/* @__PURE__ */ jsx(Th, { style: { width: "50px" }, children: /* @__PURE__ */ jsx(
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
}
|
|
751
|
-
) }),
|
|
752
|
-
/* @__PURE__ */ jsx(Th, { children: /* @__PURE__ */ jsx(
|
|
753
|
-
Typography,
|
|
754
|
-
{
|
|
755
|
-
variant: "sigma",
|
|
756
|
-
fontWeight: "bold",
|
|
757
|
-
style: { color: themeColors.primaryText },
|
|
758
|
-
children: "Title"
|
|
759
|
-
}
|
|
760
|
-
) }),
|
|
761
|
-
/* @__PURE__ */ jsx(Th, { children: /* @__PURE__ */ jsx(
|
|
762
|
-
Typography,
|
|
763
|
-
{
|
|
764
|
-
variant: "sigma",
|
|
765
|
-
fontWeight: "bold",
|
|
766
|
-
style: { color: themeColors.primaryText },
|
|
767
|
-
children: "ID"
|
|
768
|
-
}
|
|
769
|
-
) }),
|
|
770
|
-
/* @__PURE__ */ jsx(Th, { children: /* @__PURE__ */ jsx(
|
|
771
|
-
Typography,
|
|
772
|
-
{
|
|
773
|
-
variant: "sigma",
|
|
774
|
-
fontWeight: "bold",
|
|
775
|
-
style: { color: themeColors.primaryText },
|
|
776
|
-
children: "Status"
|
|
777
|
-
}
|
|
778
|
-
) }),
|
|
779
|
-
/* @__PURE__ */ jsx(Th, { children: /* @__PURE__ */ jsx(
|
|
780
|
-
Typography,
|
|
781
|
-
{
|
|
782
|
-
variant: "sigma",
|
|
783
|
-
fontWeight: "bold",
|
|
784
|
-
style: { color: themeColors.primaryText },
|
|
785
|
-
children: "Target Language"
|
|
786
|
-
}
|
|
787
|
-
) }),
|
|
788
|
-
/* @__PURE__ */ jsx(Th, { children: /* @__PURE__ */ jsx(
|
|
789
|
-
Typography,
|
|
790
|
-
{
|
|
791
|
-
variant: "sigma",
|
|
792
|
-
fontWeight: "bold",
|
|
793
|
-
style: { color: themeColors.primaryText },
|
|
794
|
-
children: "Date"
|
|
795
|
-
}
|
|
796
|
-
) })
|
|
796
|
+
/* @__PURE__ */ jsx(Th, { style: { width: "50px" }, children: /* @__PURE__ */ jsx(Checkbox, { checked: checkedType, onCheckedChange: onSelectAll }) }),
|
|
797
|
+
/* @__PURE__ */ jsx(Th, { children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", fontWeight: "bold", style: { color: themeColors.primaryText }, children: "Title" }) }),
|
|
798
|
+
/* @__PURE__ */ jsx(Th, { children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", fontWeight: "bold", style: { color: themeColors.primaryText }, children: "Translated" }) }),
|
|
799
|
+
/* @__PURE__ */ jsx(Th, { children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", fontWeight: "bold", style: { color: themeColors.primaryText }, children: "In translation" }) }),
|
|
800
|
+
/* @__PURE__ */ jsx(Th, { children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", fontWeight: "bold", style: { color: themeColors.primaryText }, children: "Queued" }) })
|
|
797
801
|
] }) }),
|
|
798
802
|
/* @__PURE__ */ jsx(Tbody, { children: entries.map((entry) => /* @__PURE__ */ jsx(
|
|
799
803
|
EntryRow,
|
|
@@ -811,6 +815,15 @@ const EntriesTable = ({
|
|
|
811
815
|
}
|
|
812
816
|
);
|
|
813
817
|
};
|
|
818
|
+
const getLangQueued = function(list) {
|
|
819
|
+
return list.filter((e) => getElementStatus(e) === "queued").map((e) => e["target-language"]).sort().join(", ");
|
|
820
|
+
};
|
|
821
|
+
const getLangInTranslation = function(list) {
|
|
822
|
+
return list.filter((e) => getElementStatus(e) === "intranslation").map((e) => e["target-language"]).sort().join(", ");
|
|
823
|
+
};
|
|
824
|
+
const getLangTranslated = function(list) {
|
|
825
|
+
return list.filter((e) => getElementStatus(e) === "translated").map((e) => e["target-language"]).sort().join(", ");
|
|
826
|
+
};
|
|
814
827
|
const EntryRow = ({
|
|
815
828
|
entry,
|
|
816
829
|
isSelected,
|
|
@@ -820,9 +833,7 @@ const EntryRow = ({
|
|
|
820
833
|
themeColors
|
|
821
834
|
}) => {
|
|
822
835
|
const entryId = getEntryId(entry);
|
|
823
|
-
const
|
|
824
|
-
const targetLanguages = getTargetLanguages(entryId, historyData);
|
|
825
|
-
const date = getTranslationDate(entryId, historyData);
|
|
836
|
+
const history = historyData[entryId] ?? [];
|
|
826
837
|
return /* @__PURE__ */ jsxs(Tr, { children: [
|
|
827
838
|
/* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(
|
|
828
839
|
Checkbox,
|
|
@@ -831,18 +842,14 @@ const EntryRow = ({
|
|
|
831
842
|
onCheckedChange: (checked) => onEntrySelection(entryId, checked)
|
|
832
843
|
}
|
|
833
844
|
) }),
|
|
834
|
-
/* @__PURE__ */
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
{
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
) }),
|
|
843
|
-
/* @__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) }) }),
|
|
844
|
-
/* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Typography, { variant: "omega", style: { color: themeColors.primaryText }, children: targetLanguages.map((lang) => lang.toUpperCase()).join(", ") || "-" }) }),
|
|
845
|
-
/* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Typography, { variant: "omega", style: { color: themeColors.primaryText }, children: date }) })
|
|
845
|
+
/* @__PURE__ */ jsxs(Td, { children: [
|
|
846
|
+
/* @__PURE__ */ jsx(Typography, { variant: "omega", style: { color: themeColors.primaryText }, children: getEntryTitle(entry) }),
|
|
847
|
+
/* @__PURE__ */ jsx("br", {}),
|
|
848
|
+
/* @__PURE__ */ jsx(Typography, { variant: "omega", style: { fontFamily: "monospace", fontSize: "12px", color: themeColors.secondaryText }, children: entryId })
|
|
849
|
+
] }),
|
|
850
|
+
/* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Typography, { variant: "omega", style: { color: themeColors.primaryText }, children: getLangTranslated(history) }) }),
|
|
851
|
+
/* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Typography, { variant: "omega", style: { color: themeColors.primaryText }, children: getLangInTranslation(history) }) }),
|
|
852
|
+
/* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Typography, { variant: "omega", style: { color: themeColors.primaryText }, children: getLangQueued(history) }) })
|
|
846
853
|
] });
|
|
847
854
|
};
|
|
848
855
|
const fetchContentEntriesData = async function(selectedContentType) {
|
|
@@ -976,7 +983,7 @@ const BulkTranslationMenu = ({
|
|
|
976
983
|
}
|
|
977
984
|
),
|
|
978
985
|
/* @__PURE__ */ jsx(Box, { style: { width: "400px", flexShrink: 0, display: "flex", flexDirection: "column" }, children: selectedEntries.size > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
979
|
-
/* @__PURE__ */ jsx(Typography, { variant: "omega", paddingBottom: 3, style: { fontWeight: "bold" }, children: "Translation
|
|
986
|
+
/* @__PURE__ */ jsx(Typography, { variant: "omega", paddingBottom: 3, style: { fontWeight: "bold" }, children: "Translation Options" }),
|
|
980
987
|
/* @__PURE__ */ jsx(Box, { style: { borderRadius: "4px", overflow: "hidden" }, children: /* @__PURE__ */ jsx(
|
|
981
988
|
BulkTranslationPanel,
|
|
982
989
|
{
|
|
@@ -988,8 +995,21 @@ const BulkTranslationMenu = ({
|
|
|
988
995
|
] }) })
|
|
989
996
|
] }) });
|
|
990
997
|
};
|
|
998
|
+
const processHistoryData = function(list) {
|
|
999
|
+
const map = {};
|
|
1000
|
+
for (const elem of list) {
|
|
1001
|
+
const id = elem["element-uid"].split("#");
|
|
1002
|
+
if (id.length !== 2)
|
|
1003
|
+
continue;
|
|
1004
|
+
if (!map[id[0]])
|
|
1005
|
+
map[id[0]] = [elem];
|
|
1006
|
+
else
|
|
1007
|
+
map[id[0]].push(elem);
|
|
1008
|
+
}
|
|
1009
|
+
return map;
|
|
1010
|
+
};
|
|
991
1011
|
const HistoryPage = () => {
|
|
992
|
-
const [historyData, setHistoryData] = useState(
|
|
1012
|
+
const [historyData, setHistoryData] = useState({});
|
|
993
1013
|
const [isLoadingHistory, setIsLoadingHistory] = useState(true);
|
|
994
1014
|
const [activeTab, setActiveTab] = useState("history");
|
|
995
1015
|
const { get } = getFetchClient();
|
|
@@ -998,13 +1018,13 @@ const HistoryPage = () => {
|
|
|
998
1018
|
try {
|
|
999
1019
|
const response = await get("/translationstudio/history");
|
|
1000
1020
|
const result = handleHistoryResponse(response.data);
|
|
1001
|
-
if (result.isError)
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1021
|
+
if (result.isError)
|
|
1022
|
+
throw new Error("Cold not fetch data");
|
|
1023
|
+
if (result.historyData && Array.isArray(result.historyData))
|
|
1024
|
+
setHistoryData(processHistoryData(result.historyData));
|
|
1005
1025
|
} catch (error) {
|
|
1006
1026
|
console.error("Failed to fetch history:", error);
|
|
1007
|
-
setHistoryData(
|
|
1027
|
+
setHistoryData({});
|
|
1008
1028
|
} finally {
|
|
1009
1029
|
setIsLoadingHistory(false);
|
|
1010
1030
|
}
|
|
@@ -1016,13 +1036,12 @@ const HistoryPage = () => {
|
|
|
1016
1036
|
try {
|
|
1017
1037
|
const response = await get("/translationstudio/history");
|
|
1018
1038
|
const result = handleHistoryResponse(response.data);
|
|
1019
|
-
if (result.isError)
|
|
1020
|
-
setHistoryData(
|
|
1021
|
-
|
|
1022
|
-
setHistoryData(result.historyData);
|
|
1023
|
-
}
|
|
1039
|
+
if (result.isError)
|
|
1040
|
+
setHistoryData({});
|
|
1041
|
+
else if (result.historyData && Array.isArray(result.historyData))
|
|
1042
|
+
setHistoryData(processHistoryData(result.historyData));
|
|
1024
1043
|
} catch (error) {
|
|
1025
|
-
setHistoryData(
|
|
1044
|
+
setHistoryData({});
|
|
1026
1045
|
} finally {
|
|
1027
1046
|
setIsLoadingHistory(false);
|
|
1028
1047
|
}
|