@parhelia/localization 0.1.12468 → 0.1.12470
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/api/discovery.d.ts +4 -1
- package/dist/api/discovery.d.ts.map +1 -1
- package/dist/api/discovery.js +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -1
- package/dist/settings/TranslationServicesPanel.d.ts.map +1 -1
- package/dist/settings/TranslationServicesPanel.js +3 -52
- package/dist/steps/SubitemDiscoveryStep.d.ts.map +1 -1
- package/dist/steps/SubitemDiscoveryStep.js +122 -36
- package/package.json +1 -1
package/dist/api/discovery.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export type DiscoveredItem = {
|
|
|
4
4
|
path: string;
|
|
5
5
|
parentId?: string | null;
|
|
6
6
|
hasChildren: boolean;
|
|
7
|
+
hasLayout?: boolean;
|
|
7
8
|
};
|
|
8
9
|
export type TreeNode = {
|
|
9
10
|
key: string;
|
|
@@ -15,6 +16,8 @@ export type BackendTreeNode = {
|
|
|
15
16
|
id: string;
|
|
16
17
|
name: string;
|
|
17
18
|
path: string;
|
|
19
|
+
hasLayout: boolean;
|
|
20
|
+
isTranslatable: boolean;
|
|
18
21
|
isFolder: boolean;
|
|
19
22
|
icon?: string;
|
|
20
23
|
children: BackendTreeNode[];
|
|
@@ -30,5 +33,5 @@ export type DiscoverItemsTreeResponse = {
|
|
|
30
33
|
};
|
|
31
34
|
export declare function discoverItemsTree(req: DiscoverItemsTreeRequest, sessionId?: string): Promise<DiscoverItemsTreeResponse>;
|
|
32
35
|
export declare function convertBackendTreeToTreeNodes(trees: BackendTreeNode[]): TreeNode[];
|
|
33
|
-
export declare function
|
|
36
|
+
export declare function flattenPagesFromBackendTrees(trees: BackendTreeNode[]): DiscoveredItem[];
|
|
34
37
|
//# sourceMappingURL=discovery.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../src/api/discovery.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,cAAc,GAAG;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../src/api/discovery.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,cAAc,GAAG;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,cAAc,CAAC;IAAC,QAAQ,CAAC,EAAE,QAAQ,EAAE,CAAA;CAAE,CAAC;AAInG,MAAM,MAAM,eAAe,GAAG;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;IACnB,cAAc,EAAE,OAAO,CAAC;IACxB,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,eAAe,EAAE,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG;IACtC,KAAK,EAAE,eAAe,EAAE,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,wBAAwB,EAC7B,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,yBAAyB,CAAC,CAWpC;AAED,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,eAAe,EAAE,GAAG,QAAQ,EAAE,CAQlF;AAED,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,eAAe,EAAE,GAAG,cAAc,EAAE,CAQvF"}
|
package/dist/api/discovery.js
CHANGED
|
@@ -12,15 +12,16 @@ export function convertBackendTreeToTreeNodes(trees) {
|
|
|
12
12
|
const convert = (n) => ({
|
|
13
13
|
key: n.id,
|
|
14
14
|
label: n.name,
|
|
15
|
-
data: { id: n.id, name: n.name, path: n.path,
|
|
15
|
+
data: { id: n.id, name: n.name, path: n.path, hasLayout: n.hasLayout, isTranslatable: n.isTranslatable, icon: n.icon, parentId: undefined, hasChildren: (n.children?.length ?? 0) > 0 },
|
|
16
16
|
children: n.children?.map(convert) || [],
|
|
17
17
|
});
|
|
18
18
|
return trees.map(convert);
|
|
19
19
|
}
|
|
20
|
-
export function
|
|
20
|
+
export function flattenPagesFromBackendTrees(trees) {
|
|
21
21
|
const out = [];
|
|
22
22
|
const walk = (n) => {
|
|
23
|
-
|
|
23
|
+
if (n.isTranslatable)
|
|
24
|
+
out.push({ id: n.id, name: n.name, path: n.path, hasChildren: (n.children?.length ?? 0) > 0, parentId: undefined });
|
|
24
25
|
n.children?.forEach(walk);
|
|
25
26
|
};
|
|
26
27
|
trees.forEach(walk);
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,4BAA4B,EAAE,MAAM,sCAAsC,CAAC;AACpF,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AAEpE,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAatD,OAAO,EACL,mBAAmB,EAGpB,MAAM,gBAAgB,CAAC;AAUxB,QAAA,MAAM,wCAAwC;;;;;;;;;;;;8BAalB,qBAAqB;;CAchD,CAAC;AAEF,QAAA,MAAM,4CAA4C;;;;;;;CAUjD,CAAC;AAkCF,OAAO,EAAE,wCAAwC,EAAE,4CAA4C,EAAE,CAAC;AAClG,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,4CAA4C,CAAC;AACnF,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAC7E,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,wBAAwB,EAAE,MAAM,qCAAqC,CAAC;AAC/E,YAAY,EACV,mBAAmB,EACnB,0BAA0B,EAC1B,uBAAuB,EACxB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,mBAAmB,EACnB,eAAe,EACf,yBAAyB,EACzB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACvB,MAAM,qBAAqB,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,YAAY,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAEhF,MAAM,MAAM,yBAAyB,GAAG;IACtC;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;;OAGG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACjC,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,qBAAqB,CACnC,aAAa,EAAE,mBAAmB,EAClC,OAAO,CAAC,EAAE,yBAAyB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,4BAA4B,EAAE,MAAM,sCAAsC,CAAC;AACpF,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AAEpE,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAatD,OAAO,EACL,mBAAmB,EAGpB,MAAM,gBAAgB,CAAC;AAUxB,QAAA,MAAM,wCAAwC;;;;;;;;;;;;8BAalB,qBAAqB;;CAchD,CAAC;AAEF,QAAA,MAAM,4CAA4C;;;;;;;CAUjD,CAAC;AAkCF,OAAO,EAAE,wCAAwC,EAAE,4CAA4C,EAAE,CAAC;AAClG,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,4CAA4C,CAAC;AACnF,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAC7E,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,wBAAwB,EAAE,MAAM,qCAAqC,CAAC;AAC/E,YAAY,EACV,mBAAmB,EACnB,0BAA0B,EAC1B,uBAAuB,EACxB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,mBAAmB,EACnB,eAAe,EACf,yBAAyB,EACzB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACvB,MAAM,qBAAqB,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,YAAY,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAEhF,MAAM,MAAM,yBAAyB,GAAG;IACtC;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;;OAGG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACjC,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,qBAAqB,CACnC,aAAa,EAAE,mBAAmB,EAClC,OAAO,CAAC,EAAE,yBAAyB,uBAiIpC"}
|
package/dist/index.js
CHANGED
|
@@ -6,6 +6,7 @@ import { localizeItemCommand } from "./LocalizeItemCommand";
|
|
|
6
6
|
import { TranslationSidebar } from "./sidebar/TranslationSidebar";
|
|
7
7
|
import { TranslationManagement } from "./translation-center/TranslationManagement";
|
|
8
8
|
import { RecentTranslations } from "./translation-center/RecentTranslations";
|
|
9
|
+
import { LocalizationSetupStep } from "./setup/LocalizationSetupStep";
|
|
9
10
|
import { TranslationServicesPanel } from "./settings/TranslationServicesPanel";
|
|
10
11
|
import { Languages as LucideLanguages, LayoutGrid as LucideLayoutGrid, Globe as LucideGlobe, } from "lucide-react";
|
|
11
12
|
const LanguagesIcon = LucideLanguages;
|
|
@@ -178,10 +179,20 @@ export function configureLocalization(configuration, options) {
|
|
|
178
179
|
icon: _jsx(LanguagesIcon, { strokeWidth: 1 }),
|
|
179
180
|
content: _jsx(TranslationServicesPanel, {}),
|
|
180
181
|
};
|
|
182
|
+
const localizationSetupPanel = {
|
|
183
|
+
id: "localization-setup",
|
|
184
|
+
title: "Localization Setup",
|
|
185
|
+
subtitle: "Verify translation services and create provider settings items",
|
|
186
|
+
icon: _jsx(LanguagesIcon, { strokeWidth: 1 }),
|
|
187
|
+
content: _jsx(LocalizationSetupStep, {}),
|
|
188
|
+
};
|
|
181
189
|
const ensureLocalizationPanels = (group) => {
|
|
182
190
|
if (!group.panels.some((p) => p.id === "translation-services")) {
|
|
183
191
|
group.panels.push(translationServicesPanel);
|
|
184
192
|
}
|
|
193
|
+
if (!group.panels.some((p) => p.id === "localization-setup")) {
|
|
194
|
+
group.panels.push(localizationSetupPanel);
|
|
195
|
+
}
|
|
185
196
|
};
|
|
186
197
|
if (localizationGroupIndex >= 0) {
|
|
187
198
|
const group = configuration.settings.groups[localizationGroupIndex];
|
|
@@ -195,7 +206,7 @@ export function configureLocalization(configuration, options) {
|
|
|
195
206
|
const localizationGroup = {
|
|
196
207
|
title: "Localization",
|
|
197
208
|
icon: _jsx(LanguagesIcon, { strokeWidth: 1 }),
|
|
198
|
-
panels: [translationServicesPanel],
|
|
209
|
+
panels: [translationServicesPanel, localizationSetupPanel],
|
|
199
210
|
};
|
|
200
211
|
if (aboutIndex >= 0) {
|
|
201
212
|
groups.splice(aboutIndex, 0, localizationGroup);
|
|
@@ -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,4CA+mBvC;AAED,eAAe,wBAAwB,CAAC"}
|
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useCallback, useState, useEffect, } from "react";
|
|
3
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,
|
|
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",
|
|
@@ -119,7 +118,6 @@ export function TranslationServicesPanel() {
|
|
|
119
118
|
const serviceStates = availableServices.map((svc) => ({
|
|
120
119
|
...svc,
|
|
121
120
|
creating: false,
|
|
122
|
-
deleting: false,
|
|
123
121
|
}));
|
|
124
122
|
setServices(serviceStates);
|
|
125
123
|
setState(availableServices.length === 0 ? "error" : "success");
|
|
@@ -195,53 +193,6 @@ export function TranslationServicesPanel() {
|
|
|
195
193
|
setServices((prev) => prev.map((s) => s.serviceName === serviceName ? { ...s, creating: false } : s));
|
|
196
194
|
}
|
|
197
195
|
}, [editContext, loadData, structureSettings]);
|
|
198
|
-
const deleteSettings = useCallback(async (service) => {
|
|
199
|
-
if (!editContext || !service.settingsItemId)
|
|
200
|
-
return;
|
|
201
|
-
try {
|
|
202
|
-
setServices((prev) => prev.map((s) => s.serviceName === service.serviceName
|
|
203
|
-
? { ...s, deleting: true }
|
|
204
|
-
: s));
|
|
205
|
-
setError(null);
|
|
206
|
-
const language = editContext.item?.language ??
|
|
207
|
-
editContext.currentItemDescriptor?.language ??
|
|
208
|
-
"en";
|
|
209
|
-
const deleted = await editContext.operations.deleteItems([
|
|
210
|
-
{
|
|
211
|
-
id: service.settingsItemId,
|
|
212
|
-
language,
|
|
213
|
-
version: 0,
|
|
214
|
-
},
|
|
215
|
-
]);
|
|
216
|
-
if (deleted) {
|
|
217
|
-
if (selectedConfigTarget?.key === `service:${service.serviceName}` ||
|
|
218
|
-
selectedConfigTarget?.itemId === service.settingsItemId) {
|
|
219
|
-
setSelectedConfigTarget(null);
|
|
220
|
-
}
|
|
221
|
-
setServices((prev) => prev.map((s) => s.serviceName === service.serviceName
|
|
222
|
-
? {
|
|
223
|
-
...s,
|
|
224
|
-
isConfigured: false,
|
|
225
|
-
settingsItemId: undefined,
|
|
226
|
-
deleting: false,
|
|
227
|
-
}
|
|
228
|
-
: s));
|
|
229
|
-
await loadData();
|
|
230
|
-
}
|
|
231
|
-
else {
|
|
232
|
-
setServices((prev) => prev.map((s) => s.serviceName === service.serviceName
|
|
233
|
-
? { ...s, deleting: false }
|
|
234
|
-
: s));
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
catch (e) {
|
|
238
|
-
setError(e?.message ||
|
|
239
|
-
`Failed to delete settings for ${service.displayName || service.serviceName}`);
|
|
240
|
-
setServices((prev) => prev.map((s) => s.serviceName === service.serviceName
|
|
241
|
-
? { ...s, deleting: false }
|
|
242
|
-
: s));
|
|
243
|
-
}
|
|
244
|
-
}, [editContext, loadData, selectedConfigTarget]);
|
|
245
196
|
useEffect(() => {
|
|
246
197
|
loadData();
|
|
247
198
|
}, [loadData]);
|
|
@@ -283,7 +234,7 @@ export function TranslationServicesPanel() {
|
|
|
283
234
|
: "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 &&
|
|
284
235
|
service.displayName !== service.serviceName && (_jsxs("div", { className: "text-xs text-gray-500 truncate", children: ["Service: ", service.serviceName] })), service.isConfigured &&
|
|
285
236
|
service.supportedLanguages &&
|
|
286
|
-
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(
|
|
237
|
+
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 }), editContext?.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));
|
|
287
238
|
}) })), error && (_jsx("div", { className: "rounded border border-red-200 bg-red-50 p-3 text-sm text-red-700 whitespace-pre-wrap", children: error }))] }) }) }) }));
|
|
288
239
|
// Build splitter panels - only show config panel when a service is selected
|
|
289
240
|
const panels = selectedConfigTarget?.itemId
|
|
@@ -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,2CA4f5L"}
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
2
2
|
import { useEffect, useState, useRef, useMemo, useCallback } from "react";
|
|
3
3
|
import { Button, PerfectTree } from "@parhelia/core";
|
|
4
4
|
import { convertFullItemToStub, convertStubToFullItem } from "@parhelia/core";
|
|
5
|
-
import { discoverItemsTree, convertBackendTreeToTreeNodes,
|
|
5
|
+
import { discoverItemsTree, convertBackendTreeToTreeNodes, flattenPagesFromBackendTrees } from "../api/discovery";
|
|
6
6
|
// We need to implement a basic Spinner component since it's not in core
|
|
7
7
|
const Spinner = ({ ...props }) => (_jsx("div", { className: "animate-spin rounded-full h-4 w-4 border-b-2 border-[#9650fb]", ...props }));
|
|
8
8
|
export function SubitemDiscoveryStep({ stepIndex, isActive = true, data, setData, editContext, onStepCompleted, setBeforeNextCallback, setFooterActions, requestClose }) {
|
|
@@ -15,6 +15,7 @@ export function SubitemDiscoveryStep({ stepIndex, isActive = true, data, setData
|
|
|
15
15
|
const [userHasInteracted, setUserHasInteracted] = useState(false);
|
|
16
16
|
const [discoveredCount, setDiscoveredCount] = useState(0);
|
|
17
17
|
const [totalItemsCount, setTotalItemsCount] = useState(0);
|
|
18
|
+
const [translatableItemsCount, setTranslatableItemsCount] = useState(0);
|
|
18
19
|
const [treeInitialized, setTreeInitialized] = useState(false);
|
|
19
20
|
const [expandedIds, setExpandedIds] = useState(new Set());
|
|
20
21
|
// Refs for async safety
|
|
@@ -46,19 +47,26 @@ export function SubitemDiscoveryStep({ stepIndex, isActive = true, data, setData
|
|
|
46
47
|
const nodes = buildTreeNodes(stubs);
|
|
47
48
|
setTreeNodes(nodes);
|
|
48
49
|
setExpandedIds(new Set(nodes.map(n => n.key)));
|
|
50
|
+
// Count total items and translatable items in the tree
|
|
49
51
|
const countItems = (nodeList) => {
|
|
50
52
|
let total = 0;
|
|
53
|
+
let translatable = 0;
|
|
51
54
|
const walk = (nodeList) => {
|
|
52
55
|
nodeList.forEach(node => {
|
|
53
56
|
total++;
|
|
57
|
+
if (node?.data?.isTranslatable === true) {
|
|
58
|
+
translatable++;
|
|
59
|
+
}
|
|
54
60
|
if (node.children)
|
|
55
61
|
walk(node.children);
|
|
56
62
|
});
|
|
57
63
|
};
|
|
58
64
|
walk(nodeList);
|
|
59
|
-
return total;
|
|
65
|
+
return { total, translatable };
|
|
60
66
|
};
|
|
61
|
-
|
|
67
|
+
const counts = countItems(nodes);
|
|
68
|
+
setTotalItemsCount(counts.total);
|
|
69
|
+
setTranslatableItemsCount(counts.translatable);
|
|
62
70
|
setDiscoveryComplete(true);
|
|
63
71
|
setTreeInitialized(true);
|
|
64
72
|
return;
|
|
@@ -79,11 +87,11 @@ export function SubitemDiscoveryStep({ stepIndex, isActive = true, data, setData
|
|
|
79
87
|
}, editContext.sessionId ?? undefined);
|
|
80
88
|
if (!isMountedRef.current)
|
|
81
89
|
return;
|
|
82
|
-
const
|
|
90
|
+
const pages = flattenPagesFromBackendTrees(resp.trees);
|
|
83
91
|
const language = editContext?.item?.language ??
|
|
84
92
|
editContext?.currentItemDescriptor?.language ??
|
|
85
93
|
"en";
|
|
86
|
-
const stubs =
|
|
94
|
+
const stubs = pages.map(x => ({
|
|
87
95
|
id: x.id,
|
|
88
96
|
name: x.name,
|
|
89
97
|
path: x.path,
|
|
@@ -106,19 +114,26 @@ export function SubitemDiscoveryStep({ stepIndex, isActive = true, data, setData
|
|
|
106
114
|
const nodes = convertBackendTreeToTreeNodes(resp.trees);
|
|
107
115
|
setTreeNodes(nodes);
|
|
108
116
|
setExpandedIds(new Set(nodes.map(n => n.key)));
|
|
117
|
+
// Count total items and translatable items in the tree
|
|
109
118
|
const countItems = (nodeList) => {
|
|
110
119
|
let total = 0;
|
|
120
|
+
let translatable = 0;
|
|
111
121
|
const walk = (nodeList) => {
|
|
112
122
|
nodeList.forEach(node => {
|
|
113
123
|
total++;
|
|
124
|
+
if (node?.data?.isTranslatable === true) {
|
|
125
|
+
translatable++;
|
|
126
|
+
}
|
|
114
127
|
if (node.children)
|
|
115
128
|
walk(node.children);
|
|
116
129
|
});
|
|
117
130
|
};
|
|
118
131
|
walk(nodeList);
|
|
119
|
-
return total;
|
|
132
|
+
return { total, translatable };
|
|
120
133
|
};
|
|
121
|
-
|
|
134
|
+
const counts = countItems(nodes);
|
|
135
|
+
setTotalItemsCount(counts.total);
|
|
136
|
+
setTranslatableItemsCount(counts.translatable);
|
|
122
137
|
setDiscoveryComplete(true);
|
|
123
138
|
setTreeInitialized(true);
|
|
124
139
|
}
|
|
@@ -143,19 +158,19 @@ export function SubitemDiscoveryStep({ stepIndex, isActive = true, data, setData
|
|
|
143
158
|
initialSelection = new Set(data.discoveredItems.map(item => item.descriptor.id));
|
|
144
159
|
}
|
|
145
160
|
else {
|
|
146
|
-
// Default: select all
|
|
147
|
-
const
|
|
161
|
+
// Default: select all translatable items in the tree
|
|
162
|
+
const allTranslatableIds = new Set();
|
|
148
163
|
const walk = (nodes) => {
|
|
149
164
|
nodes.forEach(node => {
|
|
150
|
-
if (node?.data?.
|
|
151
|
-
|
|
165
|
+
if (node?.data?.isTranslatable) {
|
|
166
|
+
allTranslatableIds.add(node.key);
|
|
152
167
|
}
|
|
153
168
|
if (node.children)
|
|
154
169
|
walk(node.children);
|
|
155
170
|
});
|
|
156
171
|
};
|
|
157
172
|
walk(treeNodes);
|
|
158
|
-
initialSelection =
|
|
173
|
+
initialSelection = allTranslatableIds;
|
|
159
174
|
}
|
|
160
175
|
setSelectedItemIds(initialSelection);
|
|
161
176
|
}, [isActive, discoveryComplete, treeNodes, data.discoveredItems, userHasInteracted]);
|
|
@@ -180,7 +195,7 @@ export function SubitemDiscoveryStep({ stepIndex, isActive = true, data, setData
|
|
|
180
195
|
const buildNode = (item) => ({
|
|
181
196
|
key: item.id,
|
|
182
197
|
label: item.name || item.id,
|
|
183
|
-
data: { id: item.id, name: item.name, path: item.path,
|
|
198
|
+
data: { id: item.id, name: item.name, path: item.path, hasChildren: item.hasChildren },
|
|
184
199
|
children: (childrenMap.get(item.id) || []).map(buildNode)
|
|
185
200
|
});
|
|
186
201
|
const originalItemIds = new Set(data.items.map(item => item.descriptor.id));
|
|
@@ -190,6 +205,8 @@ export function SubitemDiscoveryStep({ stepIndex, isActive = true, data, setData
|
|
|
190
205
|
// PerfectTree integrations
|
|
191
206
|
const expandedKeys = useMemo(() => Array.from(expandedIds), [expandedIds]);
|
|
192
207
|
const selectedKeys = useMemo(() => Array.from(selectedItemIds), [selectedItemIds]);
|
|
208
|
+
// Memoize base item IDs for checkbox rendering
|
|
209
|
+
const baseItemIdsForCheckbox = useMemo(() => new Set(data.items.map(item => item.descriptor.id)), [data.items]);
|
|
193
210
|
const getDescendantIds = (nodeKey) => {
|
|
194
211
|
const findNode = (nodes) => {
|
|
195
212
|
for (const node of nodes) {
|
|
@@ -217,6 +234,35 @@ export function SubitemDiscoveryStep({ stepIndex, isActive = true, data, setData
|
|
|
217
234
|
traverse(node.children);
|
|
218
235
|
return descendants;
|
|
219
236
|
};
|
|
237
|
+
const getDescendantTranslatableIds = (nodeKey) => {
|
|
238
|
+
const findNode = (nodes) => {
|
|
239
|
+
for (const node of nodes) {
|
|
240
|
+
if (node.key === nodeKey)
|
|
241
|
+
return node;
|
|
242
|
+
if (node.children) {
|
|
243
|
+
const found = findNode(node.children);
|
|
244
|
+
if (found)
|
|
245
|
+
return found;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
return null;
|
|
249
|
+
};
|
|
250
|
+
const root = findNode(treeNodes);
|
|
251
|
+
if (!root?.children)
|
|
252
|
+
return [];
|
|
253
|
+
const out = [];
|
|
254
|
+
const walk = (children) => {
|
|
255
|
+
children.forEach(child => {
|
|
256
|
+
const isTranslatable = child?.data?.isTranslatable === true;
|
|
257
|
+
if (isTranslatable)
|
|
258
|
+
out.push(child.key);
|
|
259
|
+
if (child.children)
|
|
260
|
+
walk(child.children);
|
|
261
|
+
});
|
|
262
|
+
};
|
|
263
|
+
walk(root.children);
|
|
264
|
+
return out;
|
|
265
|
+
};
|
|
220
266
|
const handleCancel = () => {
|
|
221
267
|
// Simplified cancel - just stop discovery
|
|
222
268
|
inFlightRef.current = false;
|
|
@@ -225,21 +271,24 @@ export function SubitemDiscoveryStep({ stepIndex, isActive = true, data, setData
|
|
|
225
271
|
};
|
|
226
272
|
return (_jsxs("div", { className: "flex min-h-0 flex-col gap-4 p-6", "data-testid": "subitem-discovery-step", children: [_jsxs("div", { className: "mb-2 shrink-0", children: [_jsx("h3", { className: "text-lg font-semibold text-[var(--color-dark)] mb-1", children: "Discover Subitems" }), _jsx("p", { className: "text-sm text-[var(--color-gray-2)]", children: "Scanning for subitems to include in translation..." })] }), _jsxs("div", { className: "flex w-full min-w-0 shrink-0 flex-col rounded-lg border border-[var(--color-gray-3)] bg-background p-4 shadow-sm", "data-testid": "discovery-status-container", children: [_jsxs("div", { className: "flex items-center justify-between mb-4", children: [_jsxs("div", { className: "flex items-center gap-2", children: [isDiscovering && _jsx(Spinner, { "data-testid": "discovery-spinner" }), _jsx("span", { className: "font-medium text-[var(--color-dark)]", "data-testid": "discovery-status-text", children: isDiscovering ? 'Discovering subitems...' :
|
|
227
273
|
discoveryComplete ? 'Discovery Complete' :
|
|
228
|
-
'Ready to discover' })] }), isDiscovering && (_jsx(Button, { size: "sm", variant: "outline", onClick: handleCancel, "data-testid": "discovery-cancel-button", children: "Cancel" }))] }), _jsx("div", { className: "text-sm text-[var(--color-gray-2)] mb-3", "data-testid": "discovery-summary", children: discoveredCount > 0 ? (_jsxs("p", { "data-testid": "discovery-total-count", children: [_jsxs("span", { className: "font-medium text-[#9650fb]", children: [totalItemsCount, " total items found"] }), _jsx("br", {}), _jsxs("span", { className: "text-xs text-[var(--color-gray-2)]", children: ["Original items: ", data.items.length, " | Subitems discovered: ", Math.max(0, totalItemsCount - data.items.length)] }), isDiscovering && (_jsxs(_Fragment, { children: [_jsx("br", {}), _jsx("span", { className: "text-xs text-[var(--color-gray-2)] italic", children: "Item tree will appear when discovery completes" })] }))] })) : (_jsx("p", { className: "text-[var(--color-gray-2)]", children: "No items discovered yet." })) }), _jsx("div", { className: "mt-4 flex flex-col", children: !isDiscovering && discoveryComplete && treeInitialized && allDiscoveredItems.length > 0 && treeNodes.length > 0 ? (_jsxs("div", { className: "flex w-full min-w-0 flex-col", "data-testid": "item-selection-section", children: [_jsxs("div", { className: "mb-3 flex flex-col gap-2 border-t border-[var(--color-gray-3)] pt-4", children: [_jsx("h3", { className: "text-lg font-semibold text-[var(--color-dark)]", children: "Select Items to Translate" }), _jsx("span", { className: "text-sm text-[var(--color-gray-2)]", "data-testid": "selection-summary-header", children: selectedItemIds.size > 0 ? _jsxs(_Fragment, { children: [_jsx("span", { className: "font-medium text-[#9650fb]", children: selectedItemIds.size }), " selected"] }) : "No items selected" }), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx(Button, { size: "sm", variant: "outline", onClick: () => {
|
|
274
|
+
'Ready to discover' })] }), isDiscovering && (_jsx(Button, { size: "sm", variant: "outline", onClick: handleCancel, "data-testid": "discovery-cancel-button", children: "Cancel" }))] }), _jsx("div", { className: "text-sm text-[var(--color-gray-2)] mb-3", "data-testid": "discovery-summary", children: discoveredCount > 0 ? (_jsxs("p", { "data-testid": "discovery-total-count", children: [_jsxs("span", { className: "font-medium text-[#9650fb]", children: [totalItemsCount, " total items found"] }), totalItemsCount !== translatableItemsCount && (_jsxs(_Fragment, { children: [_jsx("br", {}), _jsxs("span", { className: "text-xs text-[var(--color-gray-2)]", children: ["Translatable items: ", translatableItemsCount, " | Non-translatable: ", totalItemsCount - translatableItemsCount] })] })), _jsx("br", {}), _jsxs("span", { className: "text-xs text-[var(--color-gray-2)]", children: ["Original items: ", data.items.length, " | Subitems discovered: ", Math.max(0, totalItemsCount - data.items.length)] }), isDiscovering && (_jsxs(_Fragment, { children: [_jsx("br", {}), _jsx("span", { className: "text-xs text-[var(--color-gray-2)] italic", children: "Item tree will appear when discovery completes" })] }))] })) : (_jsx("p", { className: "text-[var(--color-gray-2)]", children: "No items discovered yet." })) }), _jsx("div", { className: "mt-4 flex flex-col", children: !isDiscovering && discoveryComplete && treeInitialized && allDiscoveredItems.length > 0 && treeNodes.length > 0 ? (_jsxs("div", { className: "flex w-full min-w-0 flex-col", "data-testid": "item-selection-section", children: [_jsxs("div", { className: "mb-3 flex flex-col gap-2 border-t border-[var(--color-gray-3)] pt-4", children: [_jsx("h3", { className: "text-lg font-semibold text-[var(--color-dark)]", children: "Select Items to Translate" }), _jsx("span", { className: "text-sm text-[var(--color-gray-2)]", "data-testid": "selection-summary-header", children: selectedItemIds.size > 0 ? _jsxs(_Fragment, { children: [_jsx("span", { className: "font-medium text-[#9650fb]", children: selectedItemIds.size }), " selected"] }) : "No items selected" }), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx(Button, { size: "sm", variant: "outline", onClick: () => {
|
|
229
275
|
if (!isActive)
|
|
230
276
|
return;
|
|
231
|
-
|
|
277
|
+
// Only select translatable items
|
|
278
|
+
const translatableIds = new Set();
|
|
232
279
|
const walk = (nodes) => {
|
|
233
280
|
nodes.forEach(node => {
|
|
234
|
-
|
|
281
|
+
if (node?.data?.isTranslatable === true) {
|
|
282
|
+
translatableIds.add(node.key);
|
|
283
|
+
}
|
|
235
284
|
if (node.children)
|
|
236
285
|
walk(node.children);
|
|
237
286
|
});
|
|
238
287
|
};
|
|
239
288
|
walk(treeNodes);
|
|
240
289
|
setUserHasInteracted(true);
|
|
241
|
-
setSelectedItemIds(
|
|
242
|
-
onStepCompleted(
|
|
290
|
+
setSelectedItemIds(translatableIds);
|
|
291
|
+
onStepCompleted(translatableIds.size > 0);
|
|
243
292
|
}, "data-testid": "select-all-items-button", children: "Select All" }), _jsx(Button, { size: "sm", variant: "ghost", onClick: () => {
|
|
244
293
|
if (!isActive)
|
|
245
294
|
return;
|
|
@@ -262,6 +311,7 @@ export function SubitemDiscoveryStep({ stepIndex, isActive = true, data, setData
|
|
|
262
311
|
const targetNode = key;
|
|
263
312
|
const shift = event?.shiftKey === true;
|
|
264
313
|
const next = new Set(selectedItemIds);
|
|
314
|
+
// Only select translatable items
|
|
265
315
|
const findNode = (nodes) => {
|
|
266
316
|
for (const n of nodes) {
|
|
267
317
|
if (n.key === targetNode)
|
|
@@ -275,37 +325,73 @@ export function SubitemDiscoveryStep({ stepIndex, isActive = true, data, setData
|
|
|
275
325
|
return null;
|
|
276
326
|
};
|
|
277
327
|
const n = findNode(treeNodes);
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
328
|
+
const isTranslatable = n?.data?.isTranslatable === true;
|
|
329
|
+
if (isTranslatable) {
|
|
330
|
+
const ids = shift ? [key, ...getDescendantIds(key)] : [key];
|
|
331
|
+
if (!next.has(key))
|
|
332
|
+
ids.forEach((id) => next.add(id));
|
|
333
|
+
else
|
|
334
|
+
ids.forEach((id) => next.delete(id));
|
|
335
|
+
}
|
|
336
|
+
else {
|
|
337
|
+
// Folder row click toggles all descendant translatable items
|
|
338
|
+
const translatableIds = getDescendantTranslatableIds(key);
|
|
339
|
+
const allSelected = translatableIds.length > 0 && translatableIds.every((id) => next.has(id));
|
|
340
|
+
if (allSelected)
|
|
341
|
+
translatableIds.forEach((id) => next.delete(id));
|
|
342
|
+
else
|
|
343
|
+
translatableIds.forEach((id) => next.add(id));
|
|
344
|
+
}
|
|
285
345
|
setSelectedItemIds(next);
|
|
286
346
|
// Update completion when user changes selection
|
|
287
347
|
onStepCompleted(next.size > 0);
|
|
288
348
|
}, renderNode: (node) => {
|
|
289
|
-
const
|
|
349
|
+
const isTranslatable = node?.data?.isTranslatable === true;
|
|
350
|
+
const translatableIds = !isTranslatable ? getDescendantTranslatableIds(node.key) : [];
|
|
351
|
+
const allSelected = !isTranslatable ? (translatableIds.length > 0 && translatableIds.every((id) => selectedItemIds.has(id))) : false;
|
|
352
|
+
const someSelected = !isTranslatable ? (translatableIds.some((id) => selectedItemIds.has(id)) && !allSelected) : false;
|
|
353
|
+
// Simple checkbox logic: if it's translatable, check direct selection; otherwise check descendant translatable items
|
|
354
|
+
// Base items are treated like any other selected item - if selected, show checked
|
|
355
|
+
const isChecked = isTranslatable ? selectedItemIds.has(node.key) : allSelected;
|
|
290
356
|
const icon = node?.data?.icon;
|
|
291
|
-
return (_jsxs("div", { className:
|
|
357
|
+
return (_jsxs("div", { className: `flex items-center gap-2 ${!isTranslatable ? 'opacity-70' : ''}`, children: [icon && (_jsx("img", { src: icon, alt: "", className: `w-4 h-4 ${!isTranslatable ? 'opacity-50' : ''}` })), _jsx("input", { type: "checkbox", checked: isChecked, disabled: !isTranslatable, "data-testid": `tree-item-checkbox-${node.key}`, ref: (el) => { if (el)
|
|
358
|
+
el.indeterminate = someSelected; }, onMouseDown: (e) => {
|
|
359
|
+
if (!isTranslatable)
|
|
360
|
+
return; // Don't handle mouse down for untranslatable items
|
|
292
361
|
shiftToggleRef.current = e.shiftKey;
|
|
293
362
|
}, onChange: (e) => {
|
|
294
|
-
if (!isActive)
|
|
295
|
-
return;
|
|
363
|
+
if (!isActive || !isTranslatable)
|
|
364
|
+
return; // Don't handle changes when inactive or untranslatable
|
|
296
365
|
setUserHasInteracted(true);
|
|
297
366
|
const next = new Set(selectedItemIds);
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
367
|
+
if (isTranslatable) {
|
|
368
|
+
const withDesc = shiftToggleRef.current && (node.children?.length ?? 0) > 0;
|
|
369
|
+
const ids = withDesc ? [node.key, ...getDescendantIds(node.key)] : [node.key];
|
|
370
|
+
if (e.currentTarget.checked)
|
|
371
|
+
ids.forEach((id) => next.add(id));
|
|
372
|
+
else
|
|
373
|
+
ids.forEach((id) => next.delete(id));
|
|
374
|
+
}
|
|
375
|
+
else {
|
|
376
|
+
const ids = getDescendantTranslatableIds(node.key);
|
|
377
|
+
const allSel = ids.length > 0 && ids.every((id) => next.has(id));
|
|
378
|
+
if (e.currentTarget.checked && !allSel)
|
|
379
|
+
ids.forEach((id) => next.add(id));
|
|
380
|
+
else if (!e.currentTarget.checked && allSel)
|
|
381
|
+
ids.forEach((id) => next.delete(id));
|
|
382
|
+
else {
|
|
383
|
+
// Toggle based on current
|
|
384
|
+
if (allSel)
|
|
385
|
+
ids.forEach((id) => next.delete(id));
|
|
386
|
+
else
|
|
387
|
+
ids.forEach((id) => next.add(id));
|
|
388
|
+
}
|
|
389
|
+
}
|
|
304
390
|
setSelectedItemIds(next);
|
|
305
391
|
shiftToggleRef.current = false;
|
|
306
392
|
// Update completion when user changes selection
|
|
307
393
|
onStepCompleted(next.size > 0);
|
|
308
|
-
} }), _jsx("span", { children: node.label })] }));
|
|
394
|
+
} }), _jsx("span", { className: `${!isTranslatable ? 'opacity-70 italic' : ''}`, children: node.label })] }));
|
|
309
395
|
} }) }))] })) : isDiscovering ? (
|
|
310
396
|
// Loading skeleton for discovery results
|
|
311
397
|
_jsxs("div", { className: "flex w-full min-w-0 flex-col", children: [_jsx("div", { className: "p-3 bg-[#f6eeff] border border-[#9650fb]/20 rounded-lg mb-4", children: _jsx("div", { className: "h-4 bg-[#9650fb]/20 rounded w-64 animate-pulse" }) }), _jsxs("div", { className: "border-t border-[var(--color-gray-3)] pt-4", children: [_jsxs("div", { className: "mb-3 flex flex-col gap-2", children: [_jsx("div", { className: "h-6 bg-[var(--color-gray-3)] rounded w-48 animate-pulse" }), _jsx("div", { className: "h-4 bg-[var(--color-gray-3)] rounded w-40 animate-pulse" }), _jsxs("div", { className: "flex flex-wrap gap-2", children: [_jsx("div", { className: "h-8 bg-[var(--color-gray-3)] rounded w-20 animate-pulse" }), _jsx("div", { className: "h-8 bg-[var(--color-gray-3)] rounded w-20 animate-pulse" })] })] }), _jsx("div", { className: "h-4 bg-[var(--color-gray-3)] rounded w-64 mb-3 animate-pulse" }), _jsx("div", { className: "border border-[var(--color-gray-3)] rounded-lg h-80 shrink-0 overflow-auto bg-[var(--color-gray-5)]", children: _jsx("div", { className: "p-3 space-y-2", children: [...Array(8)].map((_, i) => (_jsxs("div", { className: "flex items-center gap-3 animate-pulse", children: [_jsx("div", { className: "h-4 w-4 bg-[var(--color-gray-3)] rounded" }), _jsx("div", { className: "h-4 bg-[var(--color-gray-3)] rounded w-48" })] }, i))) }) })] })] })) : (
|