@parhelia/localization 0.1.12565 → 0.1.12570
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 +17 -13
- package/dist/api/discovery.d.ts +4 -1
- package/dist/api/discovery.d.ts.map +1 -1
- package/dist/api/discovery.js +4 -3
- package/dist/hooks/useTranslationWizard.d.ts.map +1 -1
- package/dist/hooks/useTranslationWizard.js +2 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +28 -13
- package/dist/services/translationService.d.ts +7 -48
- package/dist/services/translationService.d.ts.map +1 -1
- package/dist/services/translationService.js +0 -3
- package/dist/settings/TranslationServicesPanel.d.ts.map +1 -1
- package/dist/settings/TranslationServicesPanel.js +42 -111
- package/dist/setup/LocalizationSetupStep.d.ts.map +1 -1
- package/dist/setup/LocalizationSetupStep.js +7 -8
- package/dist/steps/ServiceLanguageSelectionStep.d.ts.map +1 -1
- package/dist/steps/ServiceLanguageSelectionStep.js +1 -18
- package/dist/steps/SubitemDiscoveryStep.d.ts.map +1 -1
- package/dist/steps/SubitemDiscoveryStep.js +181 -95
- 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 +96 -354
- package/dist/translation-center/RecentTranslations.d.ts.map +1 -1
- package/dist/translation-center/RecentTranslations.js +13 -20
- package/dist/translation-center/TranslationManagement.d.ts.map +1 -1
- package/dist/translation-center/TranslationManagement.js +4 -2
- package/package.json +11 -10
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs
|
|
2
|
-
import { useCallback, useState, useEffect
|
|
3
|
-
import { Button, useEditContext, Splitter, ItemConfigPanel
|
|
4
|
-
import { CheckCircle as LucideCheckCircle, AlertCircle as LucideAlertCircle, RefreshCw as LucideRefreshCw, Plus as LucidePlus, Settings as LucideSettings,
|
|
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";
|
|
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;
|
|
12
11
|
const DEFAULT_STRUCTURE_SETTINGS = {
|
|
13
12
|
translationFolderPath: "/sitecore/system/Parhelia/Settings/Translation",
|
|
14
13
|
translationFolderTemplateId: "b1e40cfe-6e36-4a0e-a49e-19c10b2127b7",
|
|
@@ -53,13 +52,13 @@ export function TranslationServicesPanel() {
|
|
|
53
52
|
setStructureLoading(true);
|
|
54
53
|
const result = await getTranslationStructure(structureSettings);
|
|
55
54
|
if (result.type === "success" && result.data) {
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
const success = result.data.success !== false;
|
|
56
|
+
const response = result.data.success !== undefined ? result.data.data : result.data;
|
|
57
|
+
if (success && response) {
|
|
58
|
+
setStructureState(response);
|
|
58
59
|
}
|
|
59
60
|
else {
|
|
60
|
-
throw new Error(result.data.error ||
|
|
61
|
-
result.details ||
|
|
62
|
-
"Failed to read translation structure");
|
|
61
|
+
throw new Error(result.data.error || result.details || "Failed to read translation structure");
|
|
63
62
|
}
|
|
64
63
|
}
|
|
65
64
|
else {
|
|
@@ -79,13 +78,13 @@ export function TranslationServicesPanel() {
|
|
|
79
78
|
setError(null);
|
|
80
79
|
const result = await ensureTranslationStructure(structureSettings);
|
|
81
80
|
if (result.type === "success" && result.data) {
|
|
82
|
-
|
|
83
|
-
|
|
81
|
+
const success = result.data.success !== false;
|
|
82
|
+
const response = result.data.success !== undefined ? result.data.data : result.data;
|
|
83
|
+
if (success && response) {
|
|
84
|
+
setStructureState(response);
|
|
84
85
|
return true;
|
|
85
86
|
}
|
|
86
|
-
throw new Error(result.data.error ||
|
|
87
|
-
result.details ||
|
|
88
|
-
"Failed to create translation structure");
|
|
87
|
+
throw new Error(result.data.error || result.details || "Failed to create translation structure");
|
|
89
88
|
}
|
|
90
89
|
throw new Error(result.details || "Failed to create translation structure");
|
|
91
90
|
}
|
|
@@ -104,24 +103,20 @@ export function TranslationServicesPanel() {
|
|
|
104
103
|
await loadStructure();
|
|
105
104
|
const result = await getAvailableTranslationServices();
|
|
106
105
|
if (result.type === "success" && result.data) {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}
|
|
112
|
-
const availableServices = result.data.data;
|
|
106
|
+
// Backend returns ApiResponse<T>, so data is wrapped: { success: true, data: [...] }
|
|
107
|
+
const availableServices = Array.isArray(result.data)
|
|
108
|
+
? result.data
|
|
109
|
+
: result.data.data || [];
|
|
113
110
|
const serviceStates = availableServices.map((svc) => ({
|
|
114
111
|
...svc,
|
|
115
|
-
creating: false
|
|
116
|
-
deleting: false,
|
|
112
|
+
creating: false
|
|
117
113
|
}));
|
|
118
114
|
setServices(serviceStates);
|
|
119
115
|
setState(availableServices.length === 0 ? "error" : "success");
|
|
120
116
|
}
|
|
121
117
|
else {
|
|
122
118
|
setState("error");
|
|
123
|
-
setError(result.details ||
|
|
124
|
-
"Failed to load translation services. The translation API may not be available.");
|
|
119
|
+
setError(result.details || "Failed to load translation services. The translation API may not be available.");
|
|
125
120
|
}
|
|
126
121
|
}
|
|
127
122
|
catch (e) {
|
|
@@ -130,38 +125,32 @@ export function TranslationServicesPanel() {
|
|
|
130
125
|
}
|
|
131
126
|
}, [loadStructure]);
|
|
132
127
|
const handleStructureInputChange = useCallback((field) => (e) => {
|
|
133
|
-
setStructureSettings(
|
|
128
|
+
setStructureSettings(prev => ({
|
|
134
129
|
...prev,
|
|
135
130
|
[field]: e.target.value,
|
|
136
131
|
}));
|
|
137
132
|
}, []);
|
|
138
133
|
const createSettings = useCallback(async (serviceName, templateId) => {
|
|
139
134
|
try {
|
|
140
|
-
setServices(
|
|
135
|
+
setServices(prev => prev.map(s => s.serviceName === serviceName ? { ...s, creating: true } : s));
|
|
141
136
|
setError(null);
|
|
142
137
|
const language = editContext?.item?.language ??
|
|
143
138
|
editContext?.currentItemDescriptor?.language ??
|
|
144
139
|
"en";
|
|
145
140
|
const result = await createProviderSettings(serviceName, templateId, language, structureSettings);
|
|
146
141
|
if (result.type === "success" && result.data) {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
isConfigured: true,
|
|
154
|
-
creating: false,
|
|
155
|
-
settingsItemId,
|
|
156
|
-
}
|
|
142
|
+
// Backend returns ApiResponse<T>, so unwrap: { success: true, data: { itemId, itemPath } }
|
|
143
|
+
const response = result.data.success ? result.data.data : result.data;
|
|
144
|
+
const success = result.data.success !== false;
|
|
145
|
+
if (success && response) {
|
|
146
|
+
setServices(prev => prev.map(s => s.serviceName === serviceName
|
|
147
|
+
? { ...s, isConfigured: true, creating: false, settingsItemId: response.itemId }
|
|
157
148
|
: s));
|
|
158
149
|
// Reload data to ensure consistency
|
|
159
150
|
setTimeout(() => loadData(), 500);
|
|
160
151
|
}
|
|
161
152
|
else {
|
|
162
|
-
throw new Error(result.data.error ||
|
|
163
|
-
result.details ||
|
|
164
|
-
"Failed to create settings");
|
|
153
|
+
throw new Error(result.data.error || result.details || "Failed to create settings");
|
|
165
154
|
}
|
|
166
155
|
}
|
|
167
156
|
else {
|
|
@@ -174,8 +163,7 @@ export function TranslationServicesPanel() {
|
|
|
174
163
|
let displayMessage = errorMessage;
|
|
175
164
|
if (errorMessage.includes("Translation Providers folder not found") ||
|
|
176
165
|
errorMessage.includes("Translation folder not found")) {
|
|
177
|
-
displayMessage =
|
|
178
|
-
"The required folder structure is missing. Configure and create the parent items in the Settings section above.";
|
|
166
|
+
displayMessage = "The required folder structure is missing. Configure and create the parent items in the Settings section above.";
|
|
179
167
|
}
|
|
180
168
|
else if (errorMessage.includes("already exists")) {
|
|
181
169
|
displayMessage = `Settings for ${serviceName} already exist. Please refresh the list.`;
|
|
@@ -183,98 +171,41 @@ export function TranslationServicesPanel() {
|
|
|
183
171
|
setTimeout(() => loadData(), 500);
|
|
184
172
|
}
|
|
185
173
|
setError(`Failed to create settings for ${serviceName}: ${displayMessage}`);
|
|
186
|
-
setServices(
|
|
174
|
+
setServices(prev => prev.map(s => s.serviceName === serviceName ? { ...s, creating: false } : s));
|
|
187
175
|
}
|
|
188
176
|
}, [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]);
|
|
236
177
|
useEffect(() => {
|
|
237
178
|
loadData();
|
|
238
179
|
}, [loadData]);
|
|
239
180
|
const statusIcon = (currentState) => {
|
|
240
181
|
if (currentState === "success")
|
|
241
|
-
return
|
|
182
|
+
return _jsx(CheckCircleIcon, { className: "h-4 w-4 text-green-600", strokeWidth: 1 });
|
|
242
183
|
if (currentState === "error")
|
|
243
|
-
return
|
|
184
|
+
return _jsx(AlertCircleIcon, { className: "h-4 w-4 text-red-600", strokeWidth: 1 });
|
|
244
185
|
return (_jsx(RefreshCwIcon, { className: "h-4 w-4 animate-spin text-amber-600", strokeWidth: 1 }));
|
|
245
186
|
};
|
|
246
|
-
const configuredCount = services.filter(
|
|
187
|
+
const configuredCount = services.filter(s => s.isConfigured).length;
|
|
247
188
|
const totalCount = services.length;
|
|
248
189
|
const translationFolderExists = !!structureState?.translationFolder?.exists;
|
|
249
190
|
const providersFolderExists = !!structureState?.translationProvidersFolder?.exists;
|
|
250
191
|
// Build the services list content
|
|
251
192
|
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
|
|
252
193
|
? "All parent items found"
|
|
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}`
|
|
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 === `structure:${structureState?.translationFolder?.itemId}`
|
|
255
195
|
? "border-blue-400 bg-blue-50"
|
|
256
|
-
: "border-gray-200 bg-white"}`, children: [_jsxs("div", { className: "flex items-center gap-3 flex-1
|
|
257
|
-
structureState?.translationFolder?.itemId && (_jsxs(Button, { size: "sm", variant: selectedConfigTarget?.key ===
|
|
258
|
-
`structure:${structureState.translationFolder.itemId}`
|
|
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 flex-shrink-0", strokeWidth: 1.5 })) : (_jsx(AlertCircleIcon, { className: "h-4 w-4 text-amber-500 flex-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", children: translationFolderExists && structureState?.translationFolder?.itemId && (_jsxs(Button, { size: "sm", variant: selectedConfigTarget?.key === `structure:${structureState.translationFolder.itemId}`
|
|
259
197
|
? "default"
|
|
260
|
-
: "ghost", onClick: () => handleOpenStructureConfig(structureState.translationFolder.itemId, "Configure: Translation folder"), className: "shrink-0", children: [_jsx(SettingsIcon, { className: "h-4 w-4", strokeWidth: 1.5 }),
|
|
261
|
-
`structure:${structureState?.translationProvidersFolder?.itemId}`
|
|
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 === `structure:${structureState?.translationProvidersFolder?.itemId}`
|
|
262
199
|
? "border-blue-400 bg-blue-50"
|
|
263
|
-
: "border-gray-200 bg-white"}`, children: [_jsxs("div", { className: "flex items-center gap-3 flex-1
|
|
264
|
-
structureState?.translationProvidersFolder?.itemId && (_jsxs(Button, { size: "sm", variant: selectedConfigTarget?.key ===
|
|
265
|
-
`structure:${structureState.translationProvidersFolder.itemId}`
|
|
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 flex-shrink-0", strokeWidth: 1.5 })) : (_jsx(AlertCircleIcon, { className: "h-4 w-4 text-amber-500 flex-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", children: providersFolderExists && structureState?.translationProvidersFolder?.itemId && (_jsxs(Button, { size: "sm", variant: selectedConfigTarget?.key === `structure:${structureState.translationProvidersFolder.itemId}`
|
|
266
201
|
? "default"
|
|
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 }),
|
|
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
|
|
268
203
|
? `${configuredCount} of ${totalCount} service${totalCount !== 1 ? "s" : ""} configured`
|
|
269
204
|
: "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) => {
|
|
270
|
-
const isSelected = selectedConfigTarget?.key ===
|
|
271
|
-
`service:${service.serviceName}`;
|
|
205
|
+
const isSelected = selectedConfigTarget?.key === `service:${service.serviceName}`;
|
|
272
206
|
return (_jsxs("div", { className: `flex items-center justify-between rounded border p-3 text-sm transition-shadow hover:shadow-sm ${isSelected
|
|
273
207
|
? "border-blue-400 bg-blue-50"
|
|
274
|
-
: "border-gray-200 bg-white"}`, children: [_jsxs("div", { className: "flex items-center gap-3 flex-1
|
|
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));
|
|
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 flex-shrink-0", strokeWidth: 1.5 })) : (_jsx(AlertCircleIcon, { className: "h-4 w-4 text-amber-500 flex-shrink-0", strokeWidth: 1.5 })), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("div", { className: "font-medium text-gray-900", children: service.displayName || service.serviceName }), service.displayName && service.displayName !== service.serviceName && (_jsxs("div", { className: "text-xs text-gray-500", children: ["Service: ", service.serviceName] })), service.isConfigured && service.supportedLanguages && service.supportedLanguages.length > 0 && (_jsxs("div", { className: "text-xs text-gray-500 mt-1", 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", children: service.isConfigured && service.settingsItemId ? (_jsxs(Button, { size: "sm", variant: isSelected ? "default" : "ghost", onClick: () => handleOpenConfig(service), className: "shrink-0", children: [_jsx(SettingsIcon, { className: "h-4 w-4", strokeWidth: 1.5 }), "Configure"] })) : (_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));
|
|
278
209
|
}) })), error && (_jsx("div", { className: "rounded border border-red-200 bg-red-50 p-3 text-sm text-red-700 whitespace-pre-wrap", children: error }))] }) }) }) }));
|
|
279
210
|
// Build splitter panels - only show config panel when a service is selected
|
|
280
211
|
const panels = selectedConfigTarget?.itemId
|
|
@@ -301,6 +232,6 @@ export function TranslationServicesPanel() {
|
|
|
301
232
|
},
|
|
302
233
|
];
|
|
303
234
|
const SplitterComponent = Splitter;
|
|
304
|
-
return (_jsx(SplitterComponent, { panels: panels, localStorageKey: "translation-services-panel-splitter", direction:
|
|
235
|
+
return (_jsx(SplitterComponent, { panels: panels, localStorageKey: "translation-services-panel-splitter", direction: "horizontal", className: "h-full" }));
|
|
305
236
|
}
|
|
306
237
|
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,4CA2NpC;AAED,eAAe,qBAAqB,CAAC"}
|
|
@@ -29,12 +29,8 @@ export function LocalizationSetupStep() {
|
|
|
29
29
|
setServices([]);
|
|
30
30
|
const result = await getAvailableTranslationServices();
|
|
31
31
|
if (result.type === "success" && result.data) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
result.details ||
|
|
35
|
-
"Failed to check translation services. The translation API may not be available.");
|
|
36
|
-
}
|
|
37
|
-
const availableServices = result.data.data;
|
|
32
|
+
// Backend returns ApiResponse<T>, so data is wrapped: { success: true, data: [...] }
|
|
33
|
+
const availableServices = Array.isArray(result.data) ? result.data : result.data.data || [];
|
|
38
34
|
if (availableServices.length === 0) {
|
|
39
35
|
setState("error");
|
|
40
36
|
setError("No translation services registered in dependency injection.");
|
|
@@ -79,9 +75,12 @@ export function LocalizationSetupStep() {
|
|
|
79
75
|
"en";
|
|
80
76
|
const result = await createProviderSettings(serviceName, templateId, language);
|
|
81
77
|
if (result.type === "success" && result.data) {
|
|
82
|
-
|
|
78
|
+
// Backend returns ApiResponse<T>, so unwrap: { success: true, data: { itemId, itemPath } }
|
|
79
|
+
const response = result.data.success ? result.data.data : result.data;
|
|
80
|
+
const success = result.data.success !== false;
|
|
81
|
+
if (success && response) {
|
|
83
82
|
setServices(prev => prev.map(s => s.serviceName === serviceName
|
|
84
|
-
? { ...s, isConfigured: true, creating: false, settingsItemId:
|
|
83
|
+
? { ...s, isConfigured: true, creating: false, settingsItemId: response.itemId }
|
|
85
84
|
: s));
|
|
86
85
|
setTimeout(() => checkLocalization(), 500);
|
|
87
86
|
}
|
|
@@ -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;AAGtE,wBAAgB,4BAA4B,CAAC,EAAE,SAAS,EAAE,QAAe,EAAE,IAAI,EAAE,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,gBAAgB,EAAE,YAAY,EAAE,EAAE,oBAAoB,2CAiZ7K"}
|
|
@@ -1,20 +1,6 @@
|
|
|
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
|
-
}
|
|
18
4
|
export function ServiceLanguageSelectionStep({ stepIndex, isActive = true, data, setData, onStepCompleted, editContext, setFooterActions, requestClose }) {
|
|
19
5
|
const [languageSelection, setLanguageSelection] = useState({});
|
|
20
6
|
const dataRef = useRef(data);
|
|
@@ -234,8 +220,5 @@ export function ServiceLanguageSelectionStep({ stepIndex, isActive = true, data,
|
|
|
234
220
|
}
|
|
235
221
|
}, 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 ? (
|
|
236
222
|
// Loading skeleton
|
|
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
|
-
}) })) })] })] })] }));
|
|
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) => (_jsxs("label", { className: "flex items-center 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: "h-4 w-4 text-[#9650fb] focus:ring-[#9650fb] border-[var(--color-gray-3)] rounded accent-[#9650fb]", "data-testid": `language-checkbox-${lang.code}` }), _jsxs("span", { className: "ml-2 text-sm text-[var(--color-dark)] flex items-center gap-2", children: [_jsxs("span", { children: [lang.name, " (", lang.code, ")"] }), lang.sourceLanguage && (_jsxs("span", { className: "text-xs text-[var(--color-gray-2)]", children: ["from: ", lang.sourceLanguage] }))] }), !lang.hasVersions && (_jsx("span", { className: "ml-auto text-2xs text-orange-600 bg-orange-100 px-2 py-1 rounded-full font-medium", children: "No versions" }))] }, lang.code))) })) })] })] })] }));
|
|
241
224
|
}
|
|
@@ -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,2CA8f5L"}
|