@parhelia/localization 0.1.12259 → 0.1.12269
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TranslationServicesPanel.d.ts","sourceRoot":"","sources":["../../src/settings/TranslationServicesPanel.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"TranslationServicesPanel.d.ts","sourceRoot":"","sources":["../../src/settings/TranslationServicesPanel.tsx"],"names":[],"mappings":"AA6DA;;;GAGG;AACH,wBAAgB,wBAAwB,4CAgnBvC;AAED,eAAe,wBAAwB,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
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";
|
|
2
|
+
import { useCallback, useState, useEffect, } from "react";
|
|
3
|
+
import { Button, useEditContext, Splitter, ItemConfigPanel, useMediaQuery, } from "@parhelia/core";
|
|
4
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;
|
|
@@ -28,6 +28,7 @@ export function TranslationServicesPanel() {
|
|
|
28
28
|
const [structureState, setStructureState] = useState(null);
|
|
29
29
|
const [structureLoading, setStructureLoading] = useState(false);
|
|
30
30
|
const [ensuringStructure, setEnsuringStructure] = useState(false);
|
|
31
|
+
const isMobile = useMediaQuery("(max-width: 768px)");
|
|
31
32
|
const handleOpenConfig = useCallback((service) => {
|
|
32
33
|
if (service.isConfigured && service.settingsItemId) {
|
|
33
34
|
setSelectedConfigTarget({
|
|
@@ -53,12 +54,16 @@ export function TranslationServicesPanel() {
|
|
|
53
54
|
const result = await getTranslationStructure(structureSettings);
|
|
54
55
|
if (result.type === "success" && result.data) {
|
|
55
56
|
const success = result.data.success !== false;
|
|
56
|
-
const response = result.data.success !== undefined
|
|
57
|
+
const response = result.data.success !== undefined
|
|
58
|
+
? result.data.data
|
|
59
|
+
: result.data;
|
|
57
60
|
if (success && response) {
|
|
58
61
|
setStructureState(response);
|
|
59
62
|
}
|
|
60
63
|
else {
|
|
61
|
-
throw new Error(result.data.error ||
|
|
64
|
+
throw new Error(result.data.error ||
|
|
65
|
+
result.details ||
|
|
66
|
+
"Failed to read translation structure");
|
|
62
67
|
}
|
|
63
68
|
}
|
|
64
69
|
else {
|
|
@@ -79,12 +84,16 @@ export function TranslationServicesPanel() {
|
|
|
79
84
|
const result = await ensureTranslationStructure(structureSettings);
|
|
80
85
|
if (result.type === "success" && result.data) {
|
|
81
86
|
const success = result.data.success !== false;
|
|
82
|
-
const response = result.data.success !== undefined
|
|
87
|
+
const response = result.data.success !== undefined
|
|
88
|
+
? result.data.data
|
|
89
|
+
: result.data;
|
|
83
90
|
if (success && response) {
|
|
84
91
|
setStructureState(response);
|
|
85
92
|
return true;
|
|
86
93
|
}
|
|
87
|
-
throw new Error(result.data.error ||
|
|
94
|
+
throw new Error(result.data.error ||
|
|
95
|
+
result.details ||
|
|
96
|
+
"Failed to create translation structure");
|
|
88
97
|
}
|
|
89
98
|
throw new Error(result.details || "Failed to create translation structure");
|
|
90
99
|
}
|
|
@@ -109,14 +118,15 @@ export function TranslationServicesPanel() {
|
|
|
109
118
|
: result.data.data || [];
|
|
110
119
|
const serviceStates = availableServices.map((svc) => ({
|
|
111
120
|
...svc,
|
|
112
|
-
creating: false
|
|
121
|
+
creating: false,
|
|
113
122
|
}));
|
|
114
123
|
setServices(serviceStates);
|
|
115
124
|
setState(availableServices.length === 0 ? "error" : "success");
|
|
116
125
|
}
|
|
117
126
|
else {
|
|
118
127
|
setState("error");
|
|
119
|
-
setError(result.details ||
|
|
128
|
+
setError(result.details ||
|
|
129
|
+
"Failed to load translation services. The translation API may not be available.");
|
|
120
130
|
}
|
|
121
131
|
}
|
|
122
132
|
catch (e) {
|
|
@@ -125,14 +135,14 @@ export function TranslationServicesPanel() {
|
|
|
125
135
|
}
|
|
126
136
|
}, [loadStructure]);
|
|
127
137
|
const handleStructureInputChange = useCallback((field) => (e) => {
|
|
128
|
-
setStructureSettings(prev => ({
|
|
138
|
+
setStructureSettings((prev) => ({
|
|
129
139
|
...prev,
|
|
130
140
|
[field]: e.target.value,
|
|
131
141
|
}));
|
|
132
142
|
}, []);
|
|
133
143
|
const createSettings = useCallback(async (serviceName, templateId) => {
|
|
134
144
|
try {
|
|
135
|
-
setServices(prev => prev.map(s => s.serviceName === serviceName ? { ...s, creating: true } : s));
|
|
145
|
+
setServices((prev) => prev.map((s) => s.serviceName === serviceName ? { ...s, creating: true } : s));
|
|
136
146
|
setError(null);
|
|
137
147
|
const language = editContext?.item?.language ??
|
|
138
148
|
editContext?.currentItemDescriptor?.language ??
|
|
@@ -140,17 +150,26 @@ export function TranslationServicesPanel() {
|
|
|
140
150
|
const result = await createProviderSettings(serviceName, templateId, language, structureSettings);
|
|
141
151
|
if (result.type === "success" && result.data) {
|
|
142
152
|
// Backend returns ApiResponse<T>, so unwrap: { success: true, data: { itemId, itemPath } }
|
|
143
|
-
const response = result.data.success
|
|
153
|
+
const response = result.data.success
|
|
154
|
+
? result.data.data
|
|
155
|
+
: result.data;
|
|
144
156
|
const success = result.data.success !== false;
|
|
145
157
|
if (success && response) {
|
|
146
|
-
setServices(prev => prev.map(s => s.serviceName === serviceName
|
|
147
|
-
? {
|
|
158
|
+
setServices((prev) => prev.map((s) => s.serviceName === serviceName
|
|
159
|
+
? {
|
|
160
|
+
...s,
|
|
161
|
+
isConfigured: true,
|
|
162
|
+
creating: false,
|
|
163
|
+
settingsItemId: response.itemId,
|
|
164
|
+
}
|
|
148
165
|
: s));
|
|
149
166
|
// Reload data to ensure consistency
|
|
150
167
|
setTimeout(() => loadData(), 500);
|
|
151
168
|
}
|
|
152
169
|
else {
|
|
153
|
-
throw new Error(result.data.error ||
|
|
170
|
+
throw new Error(result.data.error ||
|
|
171
|
+
result.details ||
|
|
172
|
+
"Failed to create settings");
|
|
154
173
|
}
|
|
155
174
|
}
|
|
156
175
|
else {
|
|
@@ -163,7 +182,8 @@ export function TranslationServicesPanel() {
|
|
|
163
182
|
let displayMessage = errorMessage;
|
|
164
183
|
if (errorMessage.includes("Translation Providers folder not found") ||
|
|
165
184
|
errorMessage.includes("Translation folder not found")) {
|
|
166
|
-
displayMessage =
|
|
185
|
+
displayMessage =
|
|
186
|
+
"The required folder structure is missing. Configure and create the parent items in the Settings section above.";
|
|
167
187
|
}
|
|
168
188
|
else if (errorMessage.includes("already exists")) {
|
|
169
189
|
displayMessage = `Settings for ${serviceName} already exist. Please refresh the list.`;
|
|
@@ -171,7 +191,7 @@ export function TranslationServicesPanel() {
|
|
|
171
191
|
setTimeout(() => loadData(), 500);
|
|
172
192
|
}
|
|
173
193
|
setError(`Failed to create settings for ${serviceName}: ${displayMessage}`);
|
|
174
|
-
setServices(prev => prev.map(s => s.serviceName === serviceName ? { ...s, creating: false } : s));
|
|
194
|
+
setServices((prev) => prev.map((s) => s.serviceName === serviceName ? { ...s, creating: false } : s));
|
|
175
195
|
}
|
|
176
196
|
}, [editContext, loadData, structureSettings]);
|
|
177
197
|
useEffect(() => {
|
|
@@ -179,33 +199,43 @@ export function TranslationServicesPanel() {
|
|
|
179
199
|
}, [loadData]);
|
|
180
200
|
const statusIcon = (currentState) => {
|
|
181
201
|
if (currentState === "success")
|
|
182
|
-
return _jsx(CheckCircleIcon, { className: "h-4 w-4 text-green-600", strokeWidth: 1 });
|
|
202
|
+
return (_jsx(CheckCircleIcon, { className: "h-4 w-4 text-green-600", strokeWidth: 1 }));
|
|
183
203
|
if (currentState === "error")
|
|
184
|
-
return _jsx(AlertCircleIcon, { className: "h-4 w-4 text-red-600", strokeWidth: 1 });
|
|
204
|
+
return (_jsx(AlertCircleIcon, { className: "h-4 w-4 text-red-600", strokeWidth: 1 }));
|
|
185
205
|
return (_jsx(RefreshCwIcon, { className: "h-4 w-4 animate-spin text-amber-600", strokeWidth: 1 }));
|
|
186
206
|
};
|
|
187
|
-
const configuredCount = services.filter(s => s.isConfigured).length;
|
|
207
|
+
const configuredCount = services.filter((s) => s.isConfigured).length;
|
|
188
208
|
const totalCount = services.length;
|
|
189
209
|
const translationFolderExists = !!structureState?.translationFolder?.exists;
|
|
190
210
|
const providersFolderExists = !!structureState?.translationProvidersFolder?.exists;
|
|
191
211
|
// Build the services list content
|
|
192
212
|
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
213
|
? "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 ===
|
|
214
|
+
: "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 ===
|
|
215
|
+
`structure:${structureState?.translationFolder?.itemId}`
|
|
195
216
|
? "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
|
|
217
|
+
: "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 &&
|
|
218
|
+
structureState?.translationFolder?.itemId && (_jsxs(Button, { size: "sm", variant: selectedConfigTarget?.key ===
|
|
219
|
+
`structure:${structureState.translationFolder.itemId}`
|
|
197
220
|
? "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 ===
|
|
221
|
+
: "ghost", onClick: () => handleOpenStructureConfig(structureState.translationFolder.itemId, "Configure: Translation folder"), className: "shrink-0", children: [_jsx(SettingsIcon, { className: "h-4 w-4", strokeWidth: 1.5 }), isMobile ? "" : "Configure"] })) })] }), _jsxs("div", { className: `flex items-center justify-between rounded border p-3 text-sm transition-shadow hover:shadow-sm ${selectedConfigTarget?.key ===
|
|
222
|
+
`structure:${structureState?.translationProvidersFolder?.itemId}`
|
|
199
223
|
? "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
|
|
224
|
+
: "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 &&
|
|
225
|
+
structureState?.translationProvidersFolder?.itemId && (_jsxs(Button, { size: "sm", variant: selectedConfigTarget?.key ===
|
|
226
|
+
`structure:${structureState.translationProvidersFolder.itemId}`
|
|
201
227
|
? "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
|
|
228
|
+
: "ghost", onClick: () => handleOpenStructureConfig(structureState.translationProvidersFolder.itemId, "Configure: Translation Providers folder"), className: "shrink-0", children: [_jsx(SettingsIcon, { className: "h-4 w-4", strokeWidth: 1.5 }), 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
229
|
? `${configuredCount} of ${totalCount} service${totalCount !== 1 ? "s" : ""} configured`
|
|
204
230
|
: "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 ===
|
|
231
|
+
const isSelected = selectedConfigTarget?.key ===
|
|
232
|
+
`service:${service.serviceName}`;
|
|
206
233
|
return (_jsxs("div", { className: `flex items-center justify-between rounded border p-3 text-sm transition-shadow hover:shadow-sm ${isSelected
|
|
207
234
|
? "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
|
|
235
|
+
: "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 &&
|
|
236
|
+
service.displayName !== service.serviceName && (_jsxs("div", { className: "text-xs text-gray-500 truncate", children: ["Service: ", service.serviceName] })), service.isConfigured &&
|
|
237
|
+
service.supportedLanguages &&
|
|
238
|
+
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(Button, { size: "sm", variant: isSelected ? "default" : "ghost", onClick: () => handleOpenConfig(service), className: "shrink-0", children: [_jsx(SettingsIcon, { className: "h-4 w-4", strokeWidth: 1.5 }), isMobile ? "" : "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));
|
|
209
239
|
}) })), 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
240
|
// Build splitter panels - only show config panel when a service is selected
|
|
211
241
|
const panels = selectedConfigTarget?.itemId
|
|
@@ -232,6 +262,6 @@ export function TranslationServicesPanel() {
|
|
|
232
262
|
},
|
|
233
263
|
];
|
|
234
264
|
const SplitterComponent = Splitter;
|
|
235
|
-
return (_jsx(SplitterComponent, { panels: panels, localStorageKey: "translation-services-panel-splitter", direction: "horizontal", className: "h-full" }));
|
|
265
|
+
return (_jsx(SplitterComponent, { panels: panels, localStorageKey: "translation-services-panel-splitter", direction: isMobile ? "vertical" : "horizontal", className: "h-full w-full" }));
|
|
236
266
|
}
|
|
237
267
|
export default TranslationServicesPanel;
|