@parhelia/localization 0.1.12602 → 0.1.12612
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/LocalizeItemDialog.d.ts.map +1 -1
- package/dist/LocalizeItemDialog.js +13 -17
- package/dist/api/discovery.d.ts +1 -4
- package/dist/api/discovery.d.ts.map +1 -1
- package/dist/api/discovery.js +3 -4
- package/dist/hooks/useTranslationWizard.d.ts.map +1 -1
- package/dist/hooks/useTranslationWizard.js +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -28
- package/dist/services/translationService.d.ts +48 -7
- package/dist/services/translationService.d.ts.map +1 -1
- package/dist/services/translationService.js +3 -0
- package/dist/settings/TranslationServicesPanel.d.ts.map +1 -1
- package/dist/settings/TranslationServicesPanel.js +111 -42
- package/dist/setup/LocalizationSetupStep.d.ts.map +1 -1
- package/dist/setup/LocalizationSetupStep.js +8 -7
- package/dist/steps/ServiceLanguageSelectionStep.d.ts.map +1 -1
- package/dist/steps/ServiceLanguageSelectionStep.js +18 -1
- package/dist/steps/SubitemDiscoveryStep.d.ts.map +1 -1
- package/dist/steps/SubitemDiscoveryStep.js +95 -181
- package/dist/translation-center/BatchTranslationView.d.ts +1 -1
- package/dist/translation-center/BatchTranslationView.d.ts.map +1 -1
- package/dist/translation-center/BatchTranslationView.js +356 -98
- package/dist/translation-center/RecentTranslations.d.ts.map +1 -1
- package/dist/translation-center/RecentTranslations.js +20 -13
- package/dist/translation-center/TranslationManagement.d.ts.map +1 -1
- package/dist/translation-center/TranslationManagement.js +2 -4
- package/package.json +10 -11
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useCallback, useState, useEffect } from "react";
|
|
3
|
-
import { Button, useEditContext, Splitter, ItemConfigPanel } from "@parhelia/core";
|
|
4
|
-
import { CheckCircle as LucideCheckCircle, AlertCircle as LucideAlertCircle, RefreshCw as LucideRefreshCw, Plus as LucidePlus, Settings as LucideSettings, } from "lucide-react";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback, useState, useEffect, } from "react";
|
|
3
|
+
import { Button, useEditContext, Splitter, ItemConfigPanel, } from "@parhelia/core";
|
|
4
|
+
import { CheckCircle as LucideCheckCircle, AlertCircle as LucideAlertCircle, RefreshCw as LucideRefreshCw, Plus as LucidePlus, Settings as LucideSettings, Trash2 as LucideTrash2, } from "lucide-react";
|
|
5
5
|
import { getAvailableTranslationServices, createProviderSettings, getTranslationStructure, ensureTranslationStructure, } from "../services/translationService";
|
|
6
6
|
const CheckCircleIcon = LucideCheckCircle;
|
|
7
7
|
const AlertCircleIcon = LucideAlertCircle;
|
|
8
8
|
const RefreshCwIcon = LucideRefreshCw;
|
|
9
9
|
const PlusIcon = LucidePlus;
|
|
10
10
|
const SettingsIcon = LucideSettings;
|
|
11
|
+
const Trash2Icon = LucideTrash2;
|
|
11
12
|
const DEFAULT_STRUCTURE_SETTINGS = {
|
|
12
13
|
translationFolderPath: "/sitecore/system/Parhelia/Settings/Translation",
|
|
13
14
|
translationFolderTemplateId: "b1e40cfe-6e36-4a0e-a49e-19c10b2127b7",
|
|
@@ -52,13 +53,13 @@ export function TranslationServicesPanel() {
|
|
|
52
53
|
setStructureLoading(true);
|
|
53
54
|
const result = await getTranslationStructure(structureSettings);
|
|
54
55
|
if (result.type === "success" && result.data) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
if (success && response) {
|
|
58
|
-
setStructureState(response);
|
|
56
|
+
if (result.data.success && result.data.data) {
|
|
57
|
+
setStructureState(result.data.data);
|
|
59
58
|
}
|
|
60
59
|
else {
|
|
61
|
-
throw new Error(result.data.error ||
|
|
60
|
+
throw new Error(result.data.error ||
|
|
61
|
+
result.details ||
|
|
62
|
+
"Failed to read translation structure");
|
|
62
63
|
}
|
|
63
64
|
}
|
|
64
65
|
else {
|
|
@@ -78,13 +79,13 @@ export function TranslationServicesPanel() {
|
|
|
78
79
|
setError(null);
|
|
79
80
|
const result = await ensureTranslationStructure(structureSettings);
|
|
80
81
|
if (result.type === "success" && result.data) {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
if (success && response) {
|
|
84
|
-
setStructureState(response);
|
|
82
|
+
if (result.data.success && result.data.data) {
|
|
83
|
+
setStructureState(result.data.data);
|
|
85
84
|
return true;
|
|
86
85
|
}
|
|
87
|
-
throw new Error(result.data.error ||
|
|
86
|
+
throw new Error(result.data.error ||
|
|
87
|
+
result.details ||
|
|
88
|
+
"Failed to create translation structure");
|
|
88
89
|
}
|
|
89
90
|
throw new Error(result.details || "Failed to create translation structure");
|
|
90
91
|
}
|
|
@@ -103,20 +104,24 @@ export function TranslationServicesPanel() {
|
|
|
103
104
|
await loadStructure();
|
|
104
105
|
const result = await getAvailableTranslationServices();
|
|
105
106
|
if (result.type === "success" && result.data) {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
107
|
+
if (!result.data.success || !result.data.data) {
|
|
108
|
+
throw new Error(result.data.error ||
|
|
109
|
+
result.details ||
|
|
110
|
+
"Failed to load translation services. The translation API may not be available.");
|
|
111
|
+
}
|
|
112
|
+
const availableServices = result.data.data;
|
|
110
113
|
const serviceStates = availableServices.map((svc) => ({
|
|
111
114
|
...svc,
|
|
112
|
-
creating: false
|
|
115
|
+
creating: false,
|
|
116
|
+
deleting: false,
|
|
113
117
|
}));
|
|
114
118
|
setServices(serviceStates);
|
|
115
119
|
setState(availableServices.length === 0 ? "error" : "success");
|
|
116
120
|
}
|
|
117
121
|
else {
|
|
118
122
|
setState("error");
|
|
119
|
-
setError(result.details ||
|
|
123
|
+
setError(result.details ||
|
|
124
|
+
"Failed to load translation services. The translation API may not be available.");
|
|
120
125
|
}
|
|
121
126
|
}
|
|
122
127
|
catch (e) {
|
|
@@ -125,32 +130,38 @@ export function TranslationServicesPanel() {
|
|
|
125
130
|
}
|
|
126
131
|
}, [loadStructure]);
|
|
127
132
|
const handleStructureInputChange = useCallback((field) => (e) => {
|
|
128
|
-
setStructureSettings(prev => ({
|
|
133
|
+
setStructureSettings((prev) => ({
|
|
129
134
|
...prev,
|
|
130
135
|
[field]: e.target.value,
|
|
131
136
|
}));
|
|
132
137
|
}, []);
|
|
133
138
|
const createSettings = useCallback(async (serviceName, templateId) => {
|
|
134
139
|
try {
|
|
135
|
-
setServices(prev => prev.map(s => s.serviceName === serviceName ? { ...s, creating: true } : s));
|
|
140
|
+
setServices((prev) => prev.map((s) => s.serviceName === serviceName ? { ...s, creating: true } : s));
|
|
136
141
|
setError(null);
|
|
137
142
|
const language = editContext?.item?.language ??
|
|
138
143
|
editContext?.currentItemDescriptor?.language ??
|
|
139
144
|
"en";
|
|
140
145
|
const result = await createProviderSettings(serviceName, templateId, language, structureSettings);
|
|
141
146
|
if (result.type === "success" && result.data) {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
147
|
+
const payload = result.data.data;
|
|
148
|
+
if (result.data.success && payload) {
|
|
149
|
+
const settingsItemId = payload.itemId;
|
|
150
|
+
setServices((prev) => prev.map((s) => s.serviceName === serviceName
|
|
151
|
+
? {
|
|
152
|
+
...s,
|
|
153
|
+
isConfigured: true,
|
|
154
|
+
creating: false,
|
|
155
|
+
settingsItemId,
|
|
156
|
+
}
|
|
148
157
|
: s));
|
|
149
158
|
// Reload data to ensure consistency
|
|
150
159
|
setTimeout(() => loadData(), 500);
|
|
151
160
|
}
|
|
152
161
|
else {
|
|
153
|
-
throw new Error(result.data.error ||
|
|
162
|
+
throw new Error(result.data.error ||
|
|
163
|
+
result.details ||
|
|
164
|
+
"Failed to create settings");
|
|
154
165
|
}
|
|
155
166
|
}
|
|
156
167
|
else {
|
|
@@ -163,7 +174,8 @@ export function TranslationServicesPanel() {
|
|
|
163
174
|
let displayMessage = errorMessage;
|
|
164
175
|
if (errorMessage.includes("Translation Providers folder not found") ||
|
|
165
176
|
errorMessage.includes("Translation folder not found")) {
|
|
166
|
-
displayMessage =
|
|
177
|
+
displayMessage =
|
|
178
|
+
"The required folder structure is missing. Configure and create the parent items in the Settings section above.";
|
|
167
179
|
}
|
|
168
180
|
else if (errorMessage.includes("already exists")) {
|
|
169
181
|
displayMessage = `Settings for ${serviceName} already exist. Please refresh the list.`;
|
|
@@ -171,41 +183,98 @@ export function TranslationServicesPanel() {
|
|
|
171
183
|
setTimeout(() => loadData(), 500);
|
|
172
184
|
}
|
|
173
185
|
setError(`Failed to create settings for ${serviceName}: ${displayMessage}`);
|
|
174
|
-
setServices(prev => prev.map(s => s.serviceName === serviceName ? { ...s, creating: false } : s));
|
|
186
|
+
setServices((prev) => prev.map((s) => s.serviceName === serviceName ? { ...s, creating: false } : s));
|
|
175
187
|
}
|
|
176
188
|
}, [editContext, loadData, structureSettings]);
|
|
189
|
+
const deleteSettings = useCallback(async (service) => {
|
|
190
|
+
if (!editContext || !service.settingsItemId)
|
|
191
|
+
return;
|
|
192
|
+
try {
|
|
193
|
+
setServices((prev) => prev.map((s) => s.serviceName === service.serviceName
|
|
194
|
+
? { ...s, deleting: true }
|
|
195
|
+
: s));
|
|
196
|
+
setError(null);
|
|
197
|
+
const language = editContext.item?.language ??
|
|
198
|
+
editContext.currentItemDescriptor?.language ??
|
|
199
|
+
"en";
|
|
200
|
+
const deleted = await editContext.operations.deleteItems([
|
|
201
|
+
{
|
|
202
|
+
id: service.settingsItemId,
|
|
203
|
+
language,
|
|
204
|
+
version: 0,
|
|
205
|
+
},
|
|
206
|
+
]);
|
|
207
|
+
if (deleted) {
|
|
208
|
+
if (selectedConfigTarget?.key === `service:${service.serviceName}` ||
|
|
209
|
+
selectedConfigTarget?.itemId === service.settingsItemId) {
|
|
210
|
+
setSelectedConfigTarget(null);
|
|
211
|
+
}
|
|
212
|
+
setServices((prev) => prev.map((s) => s.serviceName === service.serviceName
|
|
213
|
+
? {
|
|
214
|
+
...s,
|
|
215
|
+
isConfigured: false,
|
|
216
|
+
settingsItemId: undefined,
|
|
217
|
+
deleting: false,
|
|
218
|
+
}
|
|
219
|
+
: s));
|
|
220
|
+
await loadData();
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
setServices((prev) => prev.map((s) => s.serviceName === service.serviceName
|
|
224
|
+
? { ...s, deleting: false }
|
|
225
|
+
: s));
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
catch (e) {
|
|
229
|
+
setError(e?.message ||
|
|
230
|
+
`Failed to delete settings for ${service.displayName || service.serviceName}`);
|
|
231
|
+
setServices((prev) => prev.map((s) => s.serviceName === service.serviceName
|
|
232
|
+
? { ...s, deleting: false }
|
|
233
|
+
: s));
|
|
234
|
+
}
|
|
235
|
+
}, [editContext, loadData, selectedConfigTarget]);
|
|
177
236
|
useEffect(() => {
|
|
178
237
|
loadData();
|
|
179
238
|
}, [loadData]);
|
|
180
239
|
const statusIcon = (currentState) => {
|
|
181
240
|
if (currentState === "success")
|
|
182
|
-
return _jsx(CheckCircleIcon, { className: "h-4 w-4 text-green-600", strokeWidth: 1 });
|
|
241
|
+
return (_jsx(CheckCircleIcon, { className: "h-4 w-4 text-green-600", strokeWidth: 1 }));
|
|
183
242
|
if (currentState === "error")
|
|
184
|
-
return _jsx(AlertCircleIcon, { className: "h-4 w-4 text-red-600", strokeWidth: 1 });
|
|
243
|
+
return (_jsx(AlertCircleIcon, { className: "h-4 w-4 text-red-600", strokeWidth: 1 }));
|
|
185
244
|
return (_jsx(RefreshCwIcon, { className: "h-4 w-4 animate-spin text-amber-600", strokeWidth: 1 }));
|
|
186
245
|
};
|
|
187
|
-
const configuredCount = services.filter(s => s.isConfigured).length;
|
|
246
|
+
const configuredCount = services.filter((s) => s.isConfigured).length;
|
|
188
247
|
const totalCount = services.length;
|
|
189
248
|
const translationFolderExists = !!structureState?.translationFolder?.exists;
|
|
190
249
|
const providersFolderExists = !!structureState?.translationProvidersFolder?.exists;
|
|
191
250
|
// Build the services list content
|
|
192
251
|
const servicesListContent = (_jsx("div", { className: "h-full overflow-auto p-4", children: _jsx("div", { className: "mx-auto", children: _jsx("div", { className: "rounded-lg bg-white p-4 md:p-6", children: _jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { children: [_jsx("div", { className: "text-sm font-semibold text-gray-900", children: "Prerequisites" }), _jsxs("div", { className: "mt-1 flex items-center gap-2", children: [translationFolderExists && providersFolderExists ? (_jsx(CheckCircleIcon, { className: "h-4 w-4 text-green-600", strokeWidth: 1 })) : (_jsx(AlertCircleIcon, { className: "h-4 w-4 text-amber-500", strokeWidth: 1 })), _jsx("span", { className: "text-sm text-gray-700", children: translationFolderExists && providersFolderExists
|
|
193
252
|
? "All parent items found"
|
|
194
|
-
: "Parent items missing" })] })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs(Button, { size: "sm", variant: "outline", onClick: loadStructure, disabled: structureLoading || ensuringStructure, children: [_jsx(RefreshCwIcon, { strokeWidth: 1, className: `h-4 w-4 ${structureLoading ? "animate-spin" : ""}` }), "Refresh"] }), !providersFolderExists && (_jsxs(Button, { size: "sm", onClick: ensureStructure, disabled: ensuringStructure || structureLoading, children: [ensuringStructure ? (_jsx(RefreshCwIcon, { strokeWidth: 1, className: "h-4 w-4 animate-spin" })) : (_jsx(PlusIcon, { strokeWidth: 1.5, className: "h-4 w-4" })), "Ensure Items"] }))] })] }), _jsxs("div", { className: "space-y-1", children: [_jsxs("div", { className: `flex items-center justify-between rounded border p-3 text-sm transition-shadow hover:shadow-sm ${selectedConfigTarget?.key ===
|
|
253
|
+
: "Parent items missing" })] })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs(Button, { size: "sm", variant: "outline", onClick: loadStructure, disabled: structureLoading || ensuringStructure, children: [_jsx(RefreshCwIcon, { strokeWidth: 1, className: `h-4 w-4 ${structureLoading ? "animate-spin" : ""}` }), "Refresh"] }), !providersFolderExists && (_jsxs(Button, { size: "sm", onClick: ensureStructure, disabled: ensuringStructure || structureLoading, children: [ensuringStructure ? (_jsx(RefreshCwIcon, { strokeWidth: 1, className: "h-4 w-4 animate-spin" })) : (_jsx(PlusIcon, { strokeWidth: 1.5, className: "h-4 w-4" })), "Ensure Items"] }))] })] }), _jsxs("div", { className: "space-y-1", children: [_jsxs("div", { className: `flex items-center justify-between rounded border p-3 text-sm transition-shadow hover:shadow-sm ${selectedConfigTarget?.key ===
|
|
254
|
+
`structure:${structureState?.translationFolder?.itemId}`
|
|
195
255
|
? "border-blue-400 bg-blue-50"
|
|
196
|
-
: "border-gray-200 bg-white"}`, children: [_jsxs("div", { className: "flex items-center gap-3 flex-1", children: [translationFolderExists ? (_jsx(CheckCircleIcon, { className: "h-4 w-4 text-green-600
|
|
256
|
+
: "border-gray-200 bg-white"}`, children: [_jsxs("div", { className: "flex items-center gap-3 flex-1 min-w-0", children: [translationFolderExists ? (_jsx(CheckCircleIcon, { className: "h-4 w-4 text-green-600 shrink-0", strokeWidth: 1.5 })) : (_jsx(AlertCircleIcon, { className: "h-4 w-4 text-amber-500 shrink-0", strokeWidth: 1.5 })), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("div", { className: "font-medium text-gray-900", children: "Translation folder" }), _jsx("div", { className: "text-xs text-gray-500 truncate", children: structureSettings.translationFolderPath })] })] }), _jsx("div", { className: "flex items-center gap-2 ml-4 shrink-0", children: translationFolderExists &&
|
|
257
|
+
structureState?.translationFolder?.itemId && (_jsxs(Button, { size: "sm", variant: selectedConfigTarget?.key ===
|
|
258
|
+
`structure:${structureState.translationFolder.itemId}`
|
|
197
259
|
? "default"
|
|
198
|
-
: "ghost", onClick: () => handleOpenStructureConfig(structureState.translationFolder.itemId, "Configure: Translation folder"), className: "shrink-0", children: [_jsx(SettingsIcon, { className: "h-4 w-4", strokeWidth: 1.5 }), "Configure"] })) })] }), _jsxs("div", { className: `flex items-center justify-between rounded border p-3 text-sm transition-shadow hover:shadow-sm ${selectedConfigTarget?.key ===
|
|
260
|
+
: "ghost", onClick: () => handleOpenStructureConfig(structureState.translationFolder.itemId, "Configure: Translation folder"), className: "shrink-0", children: [_jsx(SettingsIcon, { className: "h-4 w-4", strokeWidth: 1.5 }), editContext?.isMobile ? "" : "Configure"] })) })] }), _jsxs("div", { className: `flex items-center justify-between rounded border p-3 text-sm transition-shadow hover:shadow-sm ${selectedConfigTarget?.key ===
|
|
261
|
+
`structure:${structureState?.translationProvidersFolder?.itemId}`
|
|
199
262
|
? "border-blue-400 bg-blue-50"
|
|
200
|
-
: "border-gray-200 bg-white"}`, children: [_jsxs("div", { className: "flex items-center gap-3 flex-1", children: [providersFolderExists ? (_jsx(CheckCircleIcon, { className: "h-4 w-4 text-green-600
|
|
263
|
+
: "border-gray-200 bg-white"}`, children: [_jsxs("div", { className: "flex items-center gap-3 flex-1 min-w-0", children: [providersFolderExists ? (_jsx(CheckCircleIcon, { className: "h-4 w-4 text-green-600 shrink-0", strokeWidth: 1.5 })) : (_jsx(AlertCircleIcon, { className: "h-4 w-4 text-amber-500 shrink-0", strokeWidth: 1.5 })), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("div", { className: "font-medium text-gray-900", children: "Translation providers folder" }), _jsx("div", { className: "text-xs text-gray-500 truncate", children: structureSettings.translationProvidersPath })] })] }), _jsx("div", { className: "flex items-center gap-2 ml-4 shrink-0", children: providersFolderExists &&
|
|
264
|
+
structureState?.translationProvidersFolder?.itemId && (_jsxs(Button, { size: "sm", variant: selectedConfigTarget?.key ===
|
|
265
|
+
`structure:${structureState.translationProvidersFolder.itemId}`
|
|
201
266
|
? "default"
|
|
202
|
-
: "ghost", onClick: () => handleOpenStructureConfig(structureState.translationProvidersFolder.itemId, "Configure: Translation Providers folder"), className: "shrink-0", children: [_jsx(SettingsIcon, { className: "h-4 w-4", strokeWidth: 1.5 }), "Configure"] })) })] })] }), _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { children: [_jsx("div", { className: "text-sm font-semibold text-gray-900", children: "Providers" }), _jsxs("div", { className: "mt-1 flex items-center gap-2", children: [statusIcon(state), _jsx("span", { className: "text-sm text-gray-700", children: totalCount > 0
|
|
267
|
+
: "ghost", onClick: () => handleOpenStructureConfig(structureState.translationProvidersFolder.itemId, "Configure: Translation Providers folder"), className: "shrink-0", children: [_jsx(SettingsIcon, { className: "h-4 w-4", strokeWidth: 1.5 }), editContext?.isMobile ? "" : "Configure"] })) })] })] }), _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { children: [_jsx("div", { className: "text-sm font-semibold text-gray-900", children: "Providers" }), _jsxs("div", { className: "mt-1 flex items-center gap-2", children: [statusIcon(state), _jsx("span", { className: "text-sm text-gray-700", children: totalCount > 0
|
|
203
268
|
? `${configuredCount} of ${totalCount} service${totalCount !== 1 ? "s" : ""} configured`
|
|
204
269
|
: "No services found" })] })] }), _jsxs(Button, { size: "sm", variant: "outline", onClick: loadData, children: [_jsx(RefreshCwIcon, { strokeWidth: 1, className: "h-4 w-4" }), "Refresh"] })] }), totalCount === 0 && state === "success" && (_jsx("div", { className: "rounded border border-yellow-200 bg-yellow-50 p-3 text-sm text-yellow-800", children: "No translation services are registered in dependency injection. Please check the server configuration." })), services.length > 0 && (_jsx("div", { className: "space-y-1", children: services.map((service) => {
|
|
205
|
-
const isSelected = selectedConfigTarget?.key ===
|
|
270
|
+
const isSelected = selectedConfigTarget?.key ===
|
|
271
|
+
`service:${service.serviceName}`;
|
|
206
272
|
return (_jsxs("div", { className: `flex items-center justify-between rounded border p-3 text-sm transition-shadow hover:shadow-sm ${isSelected
|
|
207
273
|
? "border-blue-400 bg-blue-50"
|
|
208
|
-
: "border-gray-200 bg-white"}`, children: [_jsxs("div", { className: "flex items-center gap-3 flex-1", children: [service.isConfigured ? (_jsx(CheckCircleIcon, { className: "h-4 w-4 text-green-600
|
|
274
|
+
: "border-gray-200 bg-white"}`, children: [_jsxs("div", { className: "flex items-center gap-3 flex-1 min-w-0", children: [service.isConfigured ? (_jsx(CheckCircleIcon, { className: "h-4 w-4 text-green-600 shrink-0", strokeWidth: 1.5 })) : (_jsx(AlertCircleIcon, { className: "h-4 w-4 text-amber-500 shrink-0", strokeWidth: 1.5 })), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("div", { className: "font-medium text-gray-900 truncate", children: service.displayName || service.serviceName }), service.displayName &&
|
|
275
|
+
service.displayName !== service.serviceName && (_jsxs("div", { className: "text-xs text-gray-500 truncate", children: ["Service: ", service.serviceName] })), service.isConfigured &&
|
|
276
|
+
service.supportedLanguages &&
|
|
277
|
+
service.supportedLanguages.length > 0 && (_jsxs("div", { className: "text-xs text-gray-500 mt-1 truncate", children: ["Languages:", " ", service.supportedLanguages.join(", ")] })), !service.isConfigured && (_jsx("div", { className: "text-xs text-amber-600 mt-1", children: "Not configured" }))] })] }), _jsx("div", { className: "flex items-center gap-2 ml-4 shrink-0", children: service.isConfigured && service.settingsItemId ? (_jsxs(_Fragment, { children: [_jsxs(Button, { size: "sm", variant: isSelected ? "default" : "ghost", onClick: () => handleOpenConfig(service), className: "shrink-0", disabled: service.deleting, children: [_jsx(SettingsIcon, { className: "h-4 w-4", strokeWidth: 1.5 }), editContext?.isMobile ? "" : "Configure"] }), _jsxs(Button, { size: "sm", variant: "ghost", onClick: () => deleteSettings(service), className: "shrink-0 text-red-600 hover:text-red-700", disabled: service.deleting, title: `Delete settings for ${service.displayName || service.serviceName}`, children: [service.deleting ? (_jsx(RefreshCwIcon, { strokeWidth: 1, className: "h-4 w-4 animate-spin" })) : (_jsx(Trash2Icon, { className: "h-4 w-4", strokeWidth: 1.5 })), editContext?.isMobile ? "" : "Delete"] })] })) : (_jsxs(Button, { size: "sm", variant: "outline", onClick: () => createSettings(service.serviceName, service.templateId), disabled: service.creating, title: `Create settings using template: ${service.templateName}`, className: "shrink-0", children: [service.creating ? (_jsx(RefreshCwIcon, { strokeWidth: 1, className: "h-4 w-4 animate-spin" })) : (_jsx(PlusIcon, { strokeWidth: 1.5, className: "h-4 w-4" })), "Create Settings"] })) })] }, service.serviceName));
|
|
209
278
|
}) })), error && (_jsx("div", { className: "rounded border border-red-200 bg-red-50 p-3 text-sm text-red-700 whitespace-pre-wrap", children: error }))] }) }) }) }));
|
|
210
279
|
// Build splitter panels - only show config panel when a service is selected
|
|
211
280
|
const panels = selectedConfigTarget?.itemId
|
|
@@ -232,6 +301,6 @@ export function TranslationServicesPanel() {
|
|
|
232
301
|
},
|
|
233
302
|
];
|
|
234
303
|
const SplitterComponent = Splitter;
|
|
235
|
-
return (_jsx(SplitterComponent, { panels: panels, localStorageKey: "translation-services-panel-splitter", direction: "horizontal", className: "h-full" }));
|
|
304
|
+
return (_jsx(SplitterComponent, { panels: panels, localStorageKey: "translation-services-panel-splitter", direction: editContext?.isMobile ? "vertical" : "horizontal", className: "h-full w-full" }));
|
|
236
305
|
}
|
|
237
306
|
export default TranslationServicesPanel;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LocalizationSetupStep.d.ts","sourceRoot":"","sources":["../../src/setup/LocalizationSetupStep.tsx"],"names":[],"mappings":"AAgCA,wBAAgB,qBAAqB,
|
|
1
|
+
{"version":3,"file":"LocalizationSetupStep.d.ts","sourceRoot":"","sources":["../../src/setup/LocalizationSetupStep.tsx"],"names":[],"mappings":"AAgCA,wBAAgB,qBAAqB,4CA6NpC;AAED,eAAe,qBAAqB,CAAC"}
|
|
@@ -29,8 +29,12 @@ export function LocalizationSetupStep() {
|
|
|
29
29
|
setServices([]);
|
|
30
30
|
const result = await getAvailableTranslationServices();
|
|
31
31
|
if (result.type === "success" && result.data) {
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
if (!result.data.success || !result.data.data) {
|
|
33
|
+
throw new Error(result.data.error ||
|
|
34
|
+
result.details ||
|
|
35
|
+
"Failed to check translation services. The translation API may not be available.");
|
|
36
|
+
}
|
|
37
|
+
const availableServices = result.data.data;
|
|
34
38
|
if (availableServices.length === 0) {
|
|
35
39
|
setState("error");
|
|
36
40
|
setError("No translation services registered in dependency injection.");
|
|
@@ -75,12 +79,9 @@ export function LocalizationSetupStep() {
|
|
|
75
79
|
"en";
|
|
76
80
|
const result = await createProviderSettings(serviceName, templateId, language);
|
|
77
81
|
if (result.type === "success" && result.data) {
|
|
78
|
-
|
|
79
|
-
const response = result.data.success ? result.data.data : result.data;
|
|
80
|
-
const success = result.data.success !== false;
|
|
81
|
-
if (success && response) {
|
|
82
|
+
if (result.data.success && result.data.data) {
|
|
82
83
|
setServices(prev => prev.map(s => s.serviceName === serviceName
|
|
83
|
-
? { ...s, isConfigured: true, creating: false, settingsItemId:
|
|
84
|
+
? { ...s, isConfigured: true, creating: false, settingsItemId: result.data?.data?.itemId }
|
|
84
85
|
: s));
|
|
85
86
|
setTimeout(() => checkLocalization(), 500);
|
|
86
87
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ServiceLanguageSelectionStep.d.ts","sourceRoot":"","sources":["../../src/steps/ServiceLanguageSelectionStep.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAyB,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"ServiceLanguageSelectionStep.d.ts","sourceRoot":"","sources":["../../src/steps/ServiceLanguageSelectionStep.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAyB,MAAM,SAAS,CAAC;AAkBtE,wBAAgB,4BAA4B,CAAC,EAAE,SAAS,EAAE,QAAe,EAAE,IAAI,EAAE,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,gBAAgB,EAAE,YAAY,EAAE,EAAE,oBAAoB,2CA8Z7K"}
|
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useMemo, useRef, useState } from "react";
|
|
3
3
|
// Version creation now offered via VersionOnlyTranslationProvider. No custom button here.
|
|
4
|
+
function getTranslationStatusBadgeClass(status) {
|
|
5
|
+
switch (status) {
|
|
6
|
+
case "Completed":
|
|
7
|
+
return "text-green-700 bg-green-100";
|
|
8
|
+
case "Error":
|
|
9
|
+
return "text-red-700 bg-red-100";
|
|
10
|
+
case "In Progress":
|
|
11
|
+
return "text-purple-800 bg-purple-100";
|
|
12
|
+
case "Not started":
|
|
13
|
+
return "text-[var(--color-gray-2)] bg-[var(--color-gray-4)]";
|
|
14
|
+
default:
|
|
15
|
+
return "text-[var(--color-gray-2)] bg-[var(--color-gray-4)]";
|
|
16
|
+
}
|
|
17
|
+
}
|
|
4
18
|
export function ServiceLanguageSelectionStep({ stepIndex, isActive = true, data, setData, onStepCompleted, editContext, setFooterActions, requestClose }) {
|
|
5
19
|
const [languageSelection, setLanguageSelection] = useState({});
|
|
6
20
|
const dataRef = useRef(data);
|
|
@@ -220,5 +234,8 @@ export function ServiceLanguageSelectionStep({ stepIndex, isActive = true, data,
|
|
|
220
234
|
}
|
|
221
235
|
}, onChange: handleSelectAllLanguages, className: "h-4 w-4 text-[#9650fb] focus:ring-[#9650fb] border-[var(--color-gray-3)] rounded accent-[#9650fb]", "data-testid": "select-all-languages-checkbox" }), _jsx("span", { className: "ml-2 text-xs text-[var(--color-gray-2)]", children: "Select All" })] }))] }), _jsx("p", { className: "text-xs text-[var(--color-gray-2)] mb-3", children: "Select the languages you want to translate this content into." }), _jsx("div", { className: "border border-[var(--color-gray-3)] rounded-lg min-h-[200px] max-h-64 overflow-y-auto bg-[var(--color-gray-5)]", children: data.translationProviders.length === 0 || allLanguages.length === 0 ? (
|
|
222
236
|
// Loading skeleton
|
|
223
|
-
_jsx("div", { className: "p-3 space-y-2", children: [...Array(4)].map((_, i) => (_jsxs("div", { className: "flex items-center animate-pulse", children: [_jsx("div", { className: "h-4 w-4 bg-[var(--color-gray-3)] rounded" }), _jsx("div", { className: "ml-2 h-4 bg-[var(--color-gray-3)] rounded w-32" }), _jsx("div", { className: "ml-auto h-4 bg-[var(--color-gray-3)] rounded w-16" })] }, i))) })) : (_jsx("div", { className: "p-3 grid grid-cols-1 gap-2", children: allLanguages.map((lang) =>
|
|
237
|
+
_jsx("div", { className: "p-3 space-y-2", children: [...Array(4)].map((_, i) => (_jsxs("div", { className: "flex items-center animate-pulse", children: [_jsx("div", { className: "h-4 w-4 bg-[var(--color-gray-3)] rounded" }), _jsx("div", { className: "ml-2 h-4 bg-[var(--color-gray-3)] rounded w-32" }), _jsx("div", { className: "ml-auto h-4 bg-[var(--color-gray-3)] rounded w-16" })] }, i))) })) : (_jsx("div", { className: "p-3 grid grid-cols-1 gap-2", children: allLanguages.map((lang) => {
|
|
238
|
+
const statusLabel = lang.translationStatus?.status || "Not started";
|
|
239
|
+
return (_jsxs("label", { className: "flex items-start gap-2 py-1.5 px-2 rounded-md hover:bg-[var(--color-gray-4)] transition-colors cursor-pointer", children: [_jsx("input", { type: "checkbox", checked: languageSelection[lang.code] || false, onChange: () => handleLanguageToggle(lang.code), className: "mt-0.5 h-4 w-4 shrink-0 text-[#9650fb] focus:ring-[#9650fb] border-[var(--color-gray-3)] rounded accent-[#9650fb]", "data-testid": `language-checkbox-${lang.code}` }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "text-sm text-[var(--color-dark)]", children: [lang.name, " (", lang.code, ")"] }), _jsxs("div", { className: "mt-0.5 flex flex-wrap items-center gap-x-2 gap-y-1 text-xs text-[var(--color-gray-2)]", children: [lang.sourceLanguage && _jsxs("span", { children: ["from: ", lang.sourceLanguage] }), !lang.hasVersions && (_jsx("span", { className: "text-2xs text-orange-600 bg-orange-100 px-2 py-1 rounded-full font-medium", children: "No versions" })), lang.hasVersions && (_jsx("span", { title: lang.translationStatus?.message, className: `text-2xs px-2 py-1 rounded-full font-medium ${getTranslationStatusBadgeClass(statusLabel)}`, "data-testid": `translation-status-badge-${lang.code}`, children: statusLabel }))] })] })] }, lang.code));
|
|
240
|
+
}) })) })] })] })] }));
|
|
224
241
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SubitemDiscoveryStep.d.ts","sourceRoot":"","sources":["../../src/steps/SubitemDiscoveryStep.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAW/C,wBAAgB,oBAAoB,CAAC,EAAE,SAAS,EAAE,QAAe,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,YAAY,EAAE,EAAE,oBAAoB,
|
|
1
|
+
{"version":3,"file":"SubitemDiscoveryStep.d.ts","sourceRoot":"","sources":["../../src/steps/SubitemDiscoveryStep.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAW/C,wBAAgB,oBAAoB,CAAC,EAAE,SAAS,EAAE,QAAe,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,YAAY,EAAE,EAAE,oBAAoB,2CAoa5L"}
|