@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.
Files changed (28) hide show
  1. package/dist/LocalizeItemDialog.d.ts.map +1 -1
  2. package/dist/LocalizeItemDialog.js +17 -13
  3. package/dist/api/discovery.d.ts +4 -1
  4. package/dist/api/discovery.d.ts.map +1 -1
  5. package/dist/api/discovery.js +4 -3
  6. package/dist/hooks/useTranslationWizard.d.ts.map +1 -1
  7. package/dist/hooks/useTranslationWizard.js +2 -3
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +28 -13
  10. package/dist/services/translationService.d.ts +7 -48
  11. package/dist/services/translationService.d.ts.map +1 -1
  12. package/dist/services/translationService.js +0 -3
  13. package/dist/settings/TranslationServicesPanel.d.ts.map +1 -1
  14. package/dist/settings/TranslationServicesPanel.js +42 -111
  15. package/dist/setup/LocalizationSetupStep.d.ts.map +1 -1
  16. package/dist/setup/LocalizationSetupStep.js +7 -8
  17. package/dist/steps/ServiceLanguageSelectionStep.d.ts.map +1 -1
  18. package/dist/steps/ServiceLanguageSelectionStep.js +1 -18
  19. package/dist/steps/SubitemDiscoveryStep.d.ts.map +1 -1
  20. package/dist/steps/SubitemDiscoveryStep.js +181 -95
  21. package/dist/translation-center/BatchTranslationView.d.ts +1 -1
  22. package/dist/translation-center/BatchTranslationView.d.ts.map +1 -1
  23. package/dist/translation-center/BatchTranslationView.js +96 -354
  24. package/dist/translation-center/RecentTranslations.d.ts.map +1 -1
  25. package/dist/translation-center/RecentTranslations.js +13 -20
  26. package/dist/translation-center/TranslationManagement.d.ts.map +1 -1
  27. package/dist/translation-center/TranslationManagement.js +4 -2
  28. package/package.json +11 -10
@@ -1,14 +1,13 @@
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";
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
- if (result.data.success && result.data.data) {
57
- setStructureState(result.data.data);
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
- if (result.data.success && result.data.data) {
83
- setStructureState(result.data.data);
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
- 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;
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((prev) => ({
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((prev) => prev.map((s) => s.serviceName === serviceName ? { ...s, creating: true } : s));
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
- 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
- }
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((prev) => prev.map((s) => s.serviceName === serviceName ? { ...s, creating: false } : s));
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 (_jsx(CheckCircleIcon, { className: "h-4 w-4 text-green-600", strokeWidth: 1 }));
182
+ return _jsx(CheckCircleIcon, { className: "h-4 w-4 text-green-600", strokeWidth: 1 });
242
183
  if (currentState === "error")
243
- return (_jsx(AlertCircleIcon, { className: "h-4 w-4 text-red-600", strokeWidth: 1 }));
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((s) => s.isConfigured).length;
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 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}`
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 }), 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}`
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 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}`
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 }), 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
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 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));
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: editContext?.isMobile ? "vertical" : "horizontal", className: "h-full w-full" }));
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,4CA6NpC;AAED,eAAe,qBAAqB,CAAC"}
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
- 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;
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
- if (result.data.success && result.data.data) {
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: result.data?.data?.itemId }
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;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
+ {"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,2CAoa5L"}
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"}