@parhelia/localization 0.1.12477 → 0.1.12479

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.
@@ -4,7 +4,6 @@ export type DiscoveredItem = {
4
4
  path: string;
5
5
  parentId?: string | null;
6
6
  hasChildren: boolean;
7
- hasLayout?: boolean;
8
7
  };
9
8
  export type TreeNode = {
10
9
  key: string;
@@ -16,8 +15,6 @@ export type BackendTreeNode = {
16
15
  id: string;
17
16
  name: string;
18
17
  path: string;
19
- hasLayout: boolean;
20
- isTranslatable: boolean;
21
18
  isFolder: boolean;
22
19
  icon?: string;
23
20
  children: BackendTreeNode[];
@@ -33,5 +30,5 @@ export type DiscoverItemsTreeResponse = {
33
30
  };
34
31
  export declare function discoverItemsTree(req: DiscoverItemsTreeRequest, sessionId?: string): Promise<DiscoverItemsTreeResponse>;
35
32
  export declare function convertBackendTreeToTreeNodes(trees: BackendTreeNode[]): TreeNode[];
36
- export declare function flattenPagesFromBackendTrees(trees: BackendTreeNode[]): DiscoveredItem[];
33
+ export declare function flattenSelectableItemsFromBackendTrees(trees: BackendTreeNode[]): DiscoveredItem[];
37
34
  //# 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;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"}
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;CACtB,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,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,sCAAsC,CAAC,KAAK,EAAE,eAAe,EAAE,GAAG,cAAc,EAAE,CAQjG"}
@@ -12,16 +12,15 @@ 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, hasLayout: n.hasLayout, isTranslatable: n.isTranslatable, icon: n.icon, parentId: undefined, hasChildren: (n.children?.length ?? 0) > 0 },
15
+ data: { id: n.id, name: n.name, path: n.path, isFolder: n.isFolder, 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 flattenPagesFromBackendTrees(trees) {
20
+ export function flattenSelectableItemsFromBackendTrees(trees) {
21
21
  const out = [];
22
22
  const walk = (n) => {
23
- if (n.isTranslatable)
24
- out.push({ id: n.id, name: n.name, path: n.path, hasChildren: (n.children?.length ?? 0) > 0, parentId: undefined });
23
+ out.push({ id: n.id, name: n.name, path: n.path, hasChildren: (n.children?.length ?? 0) > 0, parentId: undefined });
25
24
  n.children?.forEach(walk);
26
25
  };
27
26
  trees.forEach(walk);
@@ -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,uBAiIpC"}
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,uBAsHpC"}
package/dist/index.js CHANGED
@@ -6,7 +6,6 @@ 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";
10
9
  import { TranslationServicesPanel } from "./settings/TranslationServicesPanel";
11
10
  import { Languages as LucideLanguages, LayoutGrid as LucideLayoutGrid, Globe as LucideGlobe, } from "lucide-react";
12
11
  const LanguagesIcon = LucideLanguages;
@@ -179,20 +178,10 @@ export function configureLocalization(configuration, options) {
179
178
  icon: _jsx(LanguagesIcon, { strokeWidth: 1 }),
180
179
  content: _jsx(TranslationServicesPanel, {}),
181
180
  };
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
- };
189
181
  const ensureLocalizationPanels = (group) => {
190
182
  if (!group.panels.some((p) => p.id === "translation-services")) {
191
183
  group.panels.push(translationServicesPanel);
192
184
  }
193
- if (!group.panels.some((p) => p.id === "localization-setup")) {
194
- group.panels.push(localizationSetupPanel);
195
- }
196
185
  };
197
186
  if (localizationGroupIndex >= 0) {
198
187
  const group = configuration.settings.groups[localizationGroupIndex];
@@ -206,7 +195,7 @@ export function configureLocalization(configuration, options) {
206
195
  const localizationGroup = {
207
196
  title: "Localization",
208
197
  icon: _jsx(LanguagesIcon, { strokeWidth: 1 }),
209
- panels: [translationServicesPanel, localizationSetupPanel],
198
+ panels: [translationServicesPanel],
210
199
  };
211
200
  if (aboutIndex >= 0) {
212
201
  groups.splice(aboutIndex, 0, localizationGroup);
@@ -1 +1 @@
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
+ {"version":3,"file":"TranslationServicesPanel.d.ts","sourceRoot":"","sources":["../../src/settings/TranslationServicesPanel.tsx"],"names":[],"mappings":"AAgEA;;;GAGG;AACH,wBAAgB,wBAAwB,4CAktBvC;AAED,eAAe,wBAAwB,CAAC"}
@@ -1,13 +1,14 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } 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, } from "lucide-react";
4
+ import { CheckCircle as LucideCheckCircle, AlertCircle as LucideAlertCircle, RefreshCw as LucideRefreshCw, Plus as LucidePlus, Settings as LucideSettings, Trash2 as LucideTrash2, } from "lucide-react";
5
5
  import { getAvailableTranslationServices, createProviderSettings, getTranslationStructure, ensureTranslationStructure, } from "../services/translationService";
6
6
  const CheckCircleIcon = LucideCheckCircle;
7
7
  const AlertCircleIcon = LucideAlertCircle;
8
8
  const RefreshCwIcon = LucideRefreshCw;
9
9
  const PlusIcon = LucidePlus;
10
10
  const SettingsIcon = LucideSettings;
11
+ const Trash2Icon = LucideTrash2;
11
12
  const DEFAULT_STRUCTURE_SETTINGS = {
12
13
  translationFolderPath: "/sitecore/system/Parhelia/Settings/Translation",
13
14
  translationFolderTemplateId: "b1e40cfe-6e36-4a0e-a49e-19c10b2127b7",
@@ -118,6 +119,7 @@ export function TranslationServicesPanel() {
118
119
  const serviceStates = availableServices.map((svc) => ({
119
120
  ...svc,
120
121
  creating: false,
122
+ deleting: false,
121
123
  }));
122
124
  setServices(serviceStates);
123
125
  setState(availableServices.length === 0 ? "error" : "success");
@@ -193,6 +195,53 @@ export function TranslationServicesPanel() {
193
195
  setServices((prev) => prev.map((s) => s.serviceName === serviceName ? { ...s, creating: false } : s));
194
196
  }
195
197
  }, [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]);
196
245
  useEffect(() => {
197
246
  loadData();
198
247
  }, [loadData]);
@@ -234,7 +283,7 @@ export function TranslationServicesPanel() {
234
283
  : "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 &&
235
284
  service.displayName !== service.serviceName && (_jsxs("div", { className: "text-xs text-gray-500 truncate", children: ["Service: ", service.serviceName] })), service.isConfigured &&
236
285
  service.supportedLanguages &&
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));
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(_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));
238
287
  }) })), error && (_jsx("div", { className: "rounded border border-red-200 bg-red-50 p-3 text-sm text-red-700 whitespace-pre-wrap", children: error }))] }) }) }) }));
239
288
  // Build splitter panels - only show config panel when a service is selected
240
289
  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,2CA4f5L"}
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"}
@@ -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, flattenPagesFromBackendTrees } from "../api/discovery";
5
+ import { discoverItemsTree, convertBackendTreeToTreeNodes, flattenSelectableItemsFromBackendTrees } 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,7 +15,6 @@ 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);
19
18
  const [treeInitialized, setTreeInitialized] = useState(false);
20
19
  const [expandedIds, setExpandedIds] = useState(new Set());
21
20
  // Refs for async safety
@@ -47,26 +46,19 @@ export function SubitemDiscoveryStep({ stepIndex, isActive = true, data, setData
47
46
  const nodes = buildTreeNodes(stubs);
48
47
  setTreeNodes(nodes);
49
48
  setExpandedIds(new Set(nodes.map(n => n.key)));
50
- // Count total items and translatable items in the tree
51
49
  const countItems = (nodeList) => {
52
50
  let total = 0;
53
- let translatable = 0;
54
51
  const walk = (nodeList) => {
55
52
  nodeList.forEach(node => {
56
53
  total++;
57
- if (node?.data?.isTranslatable === true) {
58
- translatable++;
59
- }
60
54
  if (node.children)
61
55
  walk(node.children);
62
56
  });
63
57
  };
64
58
  walk(nodeList);
65
- return { total, translatable };
59
+ return total;
66
60
  };
67
- const counts = countItems(nodes);
68
- setTotalItemsCount(counts.total);
69
- setTranslatableItemsCount(counts.translatable);
61
+ setTotalItemsCount(countItems(nodes));
70
62
  setDiscoveryComplete(true);
71
63
  setTreeInitialized(true);
72
64
  return;
@@ -87,11 +79,11 @@ export function SubitemDiscoveryStep({ stepIndex, isActive = true, data, setData
87
79
  }, editContext.sessionId ?? undefined);
88
80
  if (!isMountedRef.current)
89
81
  return;
90
- const pages = flattenPagesFromBackendTrees(resp.trees);
82
+ const items = flattenSelectableItemsFromBackendTrees(resp.trees);
91
83
  const language = editContext?.item?.language ??
92
84
  editContext?.currentItemDescriptor?.language ??
93
85
  "en";
94
- const stubs = pages.map(x => ({
86
+ const stubs = items.map(x => ({
95
87
  id: x.id,
96
88
  name: x.name,
97
89
  path: x.path,
@@ -114,26 +106,19 @@ export function SubitemDiscoveryStep({ stepIndex, isActive = true, data, setData
114
106
  const nodes = convertBackendTreeToTreeNodes(resp.trees);
115
107
  setTreeNodes(nodes);
116
108
  setExpandedIds(new Set(nodes.map(n => n.key)));
117
- // Count total items and translatable items in the tree
118
109
  const countItems = (nodeList) => {
119
110
  let total = 0;
120
- let translatable = 0;
121
111
  const walk = (nodeList) => {
122
112
  nodeList.forEach(node => {
123
113
  total++;
124
- if (node?.data?.isTranslatable === true) {
125
- translatable++;
126
- }
127
114
  if (node.children)
128
115
  walk(node.children);
129
116
  });
130
117
  };
131
118
  walk(nodeList);
132
- return { total, translatable };
119
+ return total;
133
120
  };
134
- const counts = countItems(nodes);
135
- setTotalItemsCount(counts.total);
136
- setTranslatableItemsCount(counts.translatable);
121
+ setTotalItemsCount(countItems(nodes));
137
122
  setDiscoveryComplete(true);
138
123
  setTreeInitialized(true);
139
124
  }
@@ -158,19 +143,19 @@ export function SubitemDiscoveryStep({ stepIndex, isActive = true, data, setData
158
143
  initialSelection = new Set(data.discoveredItems.map(item => item.descriptor.id));
159
144
  }
160
145
  else {
161
- // Default: select all translatable items in the tree
162
- const allTranslatableIds = new Set();
146
+ // Default: select all selectable items in the tree
147
+ const allSelectableIds = new Set();
163
148
  const walk = (nodes) => {
164
149
  nodes.forEach(node => {
165
- if (node?.data?.isTranslatable) {
166
- allTranslatableIds.add(node.key);
150
+ if (node?.data?.isFolder !== true) {
151
+ allSelectableIds.add(node.key);
167
152
  }
168
153
  if (node.children)
169
154
  walk(node.children);
170
155
  });
171
156
  };
172
157
  walk(treeNodes);
173
- initialSelection = allTranslatableIds;
158
+ initialSelection = allSelectableIds;
174
159
  }
175
160
  setSelectedItemIds(initialSelection);
176
161
  }, [isActive, discoveryComplete, treeNodes, data.discoveredItems, userHasInteracted]);
@@ -195,7 +180,7 @@ export function SubitemDiscoveryStep({ stepIndex, isActive = true, data, setData
195
180
  const buildNode = (item) => ({
196
181
  key: item.id,
197
182
  label: item.name || item.id,
198
- data: { id: item.id, name: item.name, path: item.path, hasChildren: item.hasChildren },
183
+ data: { id: item.id, name: item.name, path: item.path, isFolder: item.hasLayout !== true, hasChildren: item.hasChildren },
199
184
  children: (childrenMap.get(item.id) || []).map(buildNode)
200
185
  });
201
186
  const originalItemIds = new Set(data.items.map(item => item.descriptor.id));
@@ -205,8 +190,6 @@ export function SubitemDiscoveryStep({ stepIndex, isActive = true, data, setData
205
190
  // PerfectTree integrations
206
191
  const expandedKeys = useMemo(() => Array.from(expandedIds), [expandedIds]);
207
192
  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]);
210
193
  const getDescendantIds = (nodeKey) => {
211
194
  const findNode = (nodes) => {
212
195
  for (const node of nodes) {
@@ -234,35 +217,6 @@ export function SubitemDiscoveryStep({ stepIndex, isActive = true, data, setData
234
217
  traverse(node.children);
235
218
  return descendants;
236
219
  };
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
- };
266
220
  const handleCancel = () => {
267
221
  // Simplified cancel - just stop discovery
268
222
  inFlightRef.current = false;
@@ -271,24 +225,21 @@ export function SubitemDiscoveryStep({ stepIndex, isActive = true, data, setData
271
225
  };
272
226
  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...' :
273
227
  discoveryComplete ? 'Discovery Complete' :
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: () => {
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: () => {
275
229
  if (!isActive)
276
230
  return;
277
- // Only select translatable items
278
- const translatableIds = new Set();
231
+ const allIds = new Set();
279
232
  const walk = (nodes) => {
280
233
  nodes.forEach(node => {
281
- if (node?.data?.isTranslatable === true) {
282
- translatableIds.add(node.key);
283
- }
234
+ allIds.add(node.key);
284
235
  if (node.children)
285
236
  walk(node.children);
286
237
  });
287
238
  };
288
239
  walk(treeNodes);
289
240
  setUserHasInteracted(true);
290
- setSelectedItemIds(translatableIds);
291
- onStepCompleted(translatableIds.size > 0);
241
+ setSelectedItemIds(allIds);
242
+ onStepCompleted(allIds.size > 0);
292
243
  }, "data-testid": "select-all-items-button", children: "Select All" }), _jsx(Button, { size: "sm", variant: "ghost", onClick: () => {
293
244
  if (!isActive)
294
245
  return;
@@ -311,7 +262,6 @@ export function SubitemDiscoveryStep({ stepIndex, isActive = true, data, setData
311
262
  const targetNode = key;
312
263
  const shift = event?.shiftKey === true;
313
264
  const next = new Set(selectedItemIds);
314
- // Only select translatable items
315
265
  const findNode = (nodes) => {
316
266
  for (const n of nodes) {
317
267
  if (n.key === targetNode)
@@ -325,73 +275,37 @@ export function SubitemDiscoveryStep({ stepIndex, isActive = true, data, setData
325
275
  return null;
326
276
  };
327
277
  const n = findNode(treeNodes);
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
- }
278
+ if (!n)
279
+ return;
280
+ const ids = shift ? [key, ...getDescendantIds(key)] : [key];
281
+ if (!next.has(key))
282
+ ids.forEach((id) => next.add(id));
283
+ else
284
+ ids.forEach((id) => next.delete(id));
345
285
  setSelectedItemIds(next);
346
286
  // Update completion when user changes selection
347
287
  onStepCompleted(next.size > 0);
348
288
  }, renderNode: (node) => {
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;
289
+ const isChecked = selectedItemIds.has(node.key);
356
290
  const icon = node?.data?.icon;
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
291
+ return (_jsxs("div", { className: "flex items-center gap-2", children: [icon && (_jsx("img", { src: icon, alt: "", className: "w-4 h-4" })), _jsx("input", { type: "checkbox", checked: isChecked, "data-testid": `tree-item-checkbox-${node.key}`, onMouseDown: (e) => {
361
292
  shiftToggleRef.current = e.shiftKey;
362
293
  }, onChange: (e) => {
363
- if (!isActive || !isTranslatable)
364
- return; // Don't handle changes when inactive or untranslatable
294
+ if (!isActive)
295
+ return;
365
296
  setUserHasInteracted(true);
366
297
  const next = new Set(selectedItemIds);
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
- }
298
+ const withDesc = shiftToggleRef.current && (node.children?.length ?? 0) > 0;
299
+ const ids = withDesc ? [node.key, ...getDescendantIds(node.key)] : [node.key];
300
+ if (e.currentTarget.checked)
301
+ ids.forEach((id) => next.add(id));
302
+ else
303
+ ids.forEach((id) => next.delete(id));
390
304
  setSelectedItemIds(next);
391
305
  shiftToggleRef.current = false;
392
306
  // Update completion when user changes selection
393
307
  onStepCompleted(next.size > 0);
394
- } }), _jsx("span", { className: `${!isTranslatable ? 'opacity-70 italic' : ''}`, children: node.label })] }));
308
+ } }), _jsx("span", { children: node.label })] }));
395
309
  } }) }))] })) : isDiscovering ? (
396
310
  // Loading skeleton for discovery results
397
311
  _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))) }) })] })] })) : (
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@parhelia/localization",
3
- "version": "0.1.12477",
3
+ "version": "0.1.12479",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"