@parhelia/localization 0.1.12906 → 0.1.12909

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/dist/LocalizeItemCommand.d.ts +7 -1
  2. package/dist/LocalizeItemCommand.d.ts.map +1 -1
  3. package/dist/LocalizeItemCommand.js +31 -18
  4. package/dist/LocalizeItemDialog.d.ts.map +1 -1
  5. package/dist/LocalizeItemDialog.js +97 -35
  6. package/dist/LocalizeItemUtils.d.ts +1 -2
  7. package/dist/LocalizeItemUtils.d.ts.map +1 -1
  8. package/dist/LocalizeItemUtils.js +78 -36
  9. package/dist/api/discovery.d.ts +25 -0
  10. package/dist/api/discovery.d.ts.map +1 -1
  11. package/dist/api/discovery.js +106 -2
  12. package/dist/hooks/useTranslationWizard.d.ts.map +1 -1
  13. package/dist/hooks/useTranslationWizard.js +3 -3
  14. package/dist/index.d.ts +10 -11
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +36 -32
  17. package/dist/services/translationService.d.ts +41 -10
  18. package/dist/services/translationService.d.ts.map +1 -1
  19. package/dist/services/translationService.js +48 -6
  20. package/dist/settings/TranslationServicesPanel.d.ts.map +1 -1
  21. package/dist/settings/TranslationServicesPanel.js +21 -36
  22. package/dist/setup/LocalizationSetupStep.d.ts.map +1 -1
  23. package/dist/setup/LocalizationSetupStep.js +29 -18
  24. package/dist/sidebar/TranslationSidebar.d.ts.map +1 -1
  25. package/dist/sidebar/TranslationSidebar.js +20 -10
  26. package/dist/steps/ItemSelectionStep.d.ts +3 -0
  27. package/dist/steps/ItemSelectionStep.d.ts.map +1 -0
  28. package/dist/steps/ItemSelectionStep.js +24 -0
  29. package/dist/steps/ItemSelectionTree.d.ts +13 -0
  30. package/dist/steps/ItemSelectionTree.d.ts.map +1 -0
  31. package/dist/steps/ItemSelectionTree.js +327 -0
  32. package/dist/steps/PromptCustomizationStep.d.ts +1 -1
  33. package/dist/steps/PromptCustomizationStep.d.ts.map +1 -1
  34. package/dist/steps/PromptCustomizationStep.js +159 -56
  35. package/dist/steps/ServiceLanguageSelectionStep.d.ts +6 -1
  36. package/dist/steps/ServiceLanguageSelectionStep.d.ts.map +1 -1
  37. package/dist/steps/ServiceLanguageSelectionStep.js +92 -165
  38. package/dist/steps/WizardStepShell.d.ts +17 -0
  39. package/dist/steps/WizardStepShell.d.ts.map +1 -0
  40. package/dist/steps/WizardStepShell.js +11 -0
  41. package/dist/steps/types.d.ts +17 -1
  42. package/dist/steps/types.d.ts.map +1 -1
  43. package/dist/translation-center/TranslationBatches.d.ts +2 -0
  44. package/dist/translation-center/TranslationBatches.d.ts.map +1 -0
  45. package/dist/translation-center/TranslationBatches.js +1180 -0
  46. package/dist/translation-center/TranslationManagement.d.ts.map +1 -1
  47. package/dist/translation-center/TranslationManagement.js +25 -15
  48. package/dist/translation-center/TranslationsTitlebar.d.ts +6 -0
  49. package/dist/translation-center/TranslationsTitlebar.d.ts.map +1 -0
  50. package/dist/translation-center/TranslationsTitlebar.js +25 -0
  51. package/dist/translationEvents.d.ts +6 -0
  52. package/dist/translationEvents.d.ts.map +1 -0
  53. package/dist/translationEvents.js +4 -0
  54. package/dist/types.d.ts +1 -0
  55. package/dist/types.d.ts.map +1 -1
  56. package/package.json +1 -1
  57. package/dist/constants.d.ts +0 -15
  58. package/dist/constants.d.ts.map +0 -1
  59. package/dist/constants.js +0 -21
  60. package/dist/steps/MetadataInputStep.d.ts +0 -4
  61. package/dist/steps/MetadataInputStep.d.ts.map +0 -1
  62. package/dist/steps/MetadataInputStep.js +0 -41
  63. package/dist/steps/SubitemDiscoveryStep.d.ts +0 -3
  64. package/dist/steps/SubitemDiscoveryStep.d.ts.map +0 -1
  65. package/dist/steps/SubitemDiscoveryStep.js +0 -313
  66. package/dist/steps/index.d.ts +0 -5
  67. package/dist/steps/index.d.ts.map +0 -1
  68. package/dist/steps/index.js +0 -4
  69. package/dist/translation-center/BatchTranslationView.d.ts +0 -8
  70. package/dist/translation-center/BatchTranslationView.d.ts.map +0 -1
  71. package/dist/translation-center/BatchTranslationView.js +0 -870
  72. package/dist/translation-center/RecentTranslations.d.ts +0 -2
  73. package/dist/translation-center/RecentTranslations.d.ts.map +0 -1
  74. package/dist/translation-center/RecentTranslations.js +0 -309
  75. package/dist/utils/createVersions.d.ts +0 -14
  76. package/dist/utils/createVersions.d.ts.map +0 -1
  77. package/dist/utils/createVersions.js +0 -26
@@ -1,14 +1,15 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useCallback, useState, useEffect, } from "react";
3
- import { Button, useEditContext, Splitter, ItemConfigPanel, } from "@parhelia/core";
4
- import { CheckCircle as LucideCheckCircle, AlertCircle as LucideAlertCircle, RefreshCw as LucideRefreshCw, Plus as LucidePlus, Settings as LucideSettings, Trash2 as LucideTrash2, } from "lucide-react";
3
+ import { Button, Card, useEditContext, Splitter, ItemConfigPanel, DeleteIcon, } from "@parhelia/core";
4
+ import { CheckCircle as LucideCheckCircle, AlertCircle as LucideAlertCircle, RefreshCw as LucideRefreshCw, Plus as LucidePlus, Settings as LucideSettings, Languages as LucideLanguages, ListChecks as LucideListChecks, } 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
+ const LanguagesIcon = LucideLanguages;
12
+ const ListChecksIcon = LucideListChecks;
12
13
  const DEFAULT_STRUCTURE_SETTINGS = {
13
14
  translationFolderPath: "/sitecore/system/Parhelia/Settings/Translation",
14
15
  translationFolderTemplateId: "b1e40cfe-6e36-4a0e-a49e-19c10b2127b7",
@@ -236,46 +237,30 @@ export function TranslationServicesPanel() {
236
237
  useEffect(() => {
237
238
  loadData();
238
239
  }, [loadData]);
239
- const statusIcon = (currentState) => {
240
- if (currentState === "success")
241
- return (_jsx(CheckCircleIcon, { className: "h-4 w-4 text-green-600", strokeWidth: 1 }));
242
- if (currentState === "error")
243
- return (_jsx(AlertCircleIcon, { className: "h-4 w-4 text-red-600", strokeWidth: 1 }));
244
- return (_jsx(RefreshCwIcon, { className: "h-4 w-4 animate-spin text-amber-600", strokeWidth: 1 }));
245
- };
246
240
  const configuredCount = services.filter((s) => s.isConfigured).length;
247
241
  const totalCount = services.length;
248
242
  const translationFolderExists = !!structureState?.translationFolder?.exists;
249
243
  const providersFolderExists = !!structureState?.translationProvidersFolder?.exists;
250
244
  // Build the services list content
251
- const servicesListContent = (_jsx("div", { className: "h-full overflow-auto p-4", "data-testid": "translation-services-panel", 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: "space-y-4", "data-testid": "translation-services-prerequisites", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { children: [_jsx("div", { className: "text-sm font-semibold text-gray-900", children: "Prerequisites" }), _jsxs("div", { className: "mt-1 flex items-center gap-2", children: [translationFolderExists && providersFolderExists ? (_jsx(CheckCircleIcon, { className: "h-4 w-4 text-green-600", strokeWidth: 1 })) : (_jsx(AlertCircleIcon, { className: "h-4 w-4 text-amber-500", strokeWidth: 1 })), _jsx("span", { className: "text-sm text-gray-700", children: translationFolderExists && providersFolderExists
252
- ? "All parent items found"
253
- : "Parent items missing" })] })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs(Button, { size: "sm", variant: "outline", onClick: loadStructure, disabled: structureLoading || ensuringStructure, children: [_jsx(RefreshCwIcon, { strokeWidth: 1, className: `h-4 w-4 ${structureLoading ? "animate-spin" : ""}` }), "Refresh"] }), !providersFolderExists && (_jsxs(Button, { size: "sm", onClick: ensureStructure, disabled: ensuringStructure || structureLoading, children: [ensuringStructure ? (_jsx(RefreshCwIcon, { strokeWidth: 1, className: "h-4 w-4 animate-spin" })) : (_jsx(PlusIcon, { strokeWidth: 1.5, className: "h-4 w-4" })), "Ensure Items"] }))] })] }), _jsxs("div", { className: "space-y-1", children: [_jsxs("div", { "data-testid": "translation-structure-folder", className: `flex items-center justify-between rounded border p-3 text-sm transition-shadow hover:shadow-sm ${selectedConfigTarget?.key ===
254
- `structure:${structureState?.translationFolder?.itemId}`
255
- ? "border-blue-400 bg-blue-50"
256
- : "border-gray-200 bg-white"}`, children: [_jsxs("div", { className: "flex items-center gap-3 flex-1 min-w-0", children: [translationFolderExists ? (_jsx(CheckCircleIcon, { className: "h-4 w-4 text-green-600 shrink-0", strokeWidth: 1.5 })) : (_jsx(AlertCircleIcon, { className: "h-4 w-4 text-amber-500 shrink-0", strokeWidth: 1.5 })), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("div", { className: "font-medium text-gray-900", children: "Translation folder" }), _jsx("div", { className: "text-xs text-gray-500 truncate", children: structureSettings.translationFolderPath })] })] }), _jsx("div", { className: "flex items-center gap-2 ml-4 shrink-0", children: translationFolderExists &&
257
- structureState?.translationFolder?.itemId && (_jsxs(Button, { size: "sm", variant: selectedConfigTarget?.key ===
258
- `structure:${structureState.translationFolder.itemId}`
259
- ? "default"
260
- : "ghost", onClick: () => handleOpenStructureConfig(structureState.translationFolder.itemId, "Configure: Translation folder"), className: "shrink-0", children: [_jsx(SettingsIcon, { className: "h-4 w-4", strokeWidth: 1.5 }), editContext?.isMobile ? "" : "Configure"] })) })] }), _jsxs("div", { "data-testid": "translation-structure-providers-folder", className: `flex items-center justify-between rounded border p-3 text-sm transition-shadow hover:shadow-sm ${selectedConfigTarget?.key ===
261
- `structure:${structureState?.translationProvidersFolder?.itemId}`
262
- ? "border-blue-400 bg-blue-50"
263
- : "border-gray-200 bg-white"}`, children: [_jsxs("div", { className: "flex items-center gap-3 flex-1 min-w-0", children: [providersFolderExists ? (_jsx(CheckCircleIcon, { className: "h-4 w-4 text-green-600 shrink-0", strokeWidth: 1.5 })) : (_jsx(AlertCircleIcon, { className: "h-4 w-4 text-amber-500 shrink-0", strokeWidth: 1.5 })), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("div", { className: "font-medium text-gray-900", children: "Translation providers folder" }), _jsx("div", { className: "text-xs text-gray-500 truncate", children: structureSettings.translationProvidersPath })] })] }), _jsx("div", { className: "flex items-center gap-2 ml-4 shrink-0", children: providersFolderExists &&
264
- structureState?.translationProvidersFolder?.itemId && (_jsxs(Button, { size: "sm", variant: selectedConfigTarget?.key ===
265
- `structure:${structureState.translationProvidersFolder.itemId}`
266
- ? "default"
267
- : "ghost", onClick: () => handleOpenStructureConfig(structureState.translationProvidersFolder.itemId, "Configure: Translation Providers folder"), className: "shrink-0", children: [_jsx(SettingsIcon, { className: "h-4 w-4", strokeWidth: 1.5 }), editContext?.isMobile ? "" : "Configure"] })) })] })] })] }), _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { children: [_jsx("div", { className: "text-sm font-semibold text-gray-900", children: "Providers" }), _jsxs("div", { className: "mt-1 flex items-center gap-2", children: [statusIcon(state), _jsx("span", { className: "text-sm text-gray-700", children: totalCount > 0
268
- ? `${configuredCount} of ${totalCount} service${totalCount !== 1 ? "s" : ""} configured`
269
- : "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", "data-testid": "translation-services-providers", children: services.map((service) => {
245
+ const servicesListContent = (_jsxs("div", { className: "flex h-full flex-col gap-4 p-4", "data-testid": "translation-services-panel", children: [_jsx(Card, { icon: _jsx(ListChecksIcon, { strokeWidth: 1, className: "h-5 w-5" }), title: "Prerequisites", description: "Required Sitecore folders for translation settings.", noPadding: true, className: "shrink-0", headerActions: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "flex items-center gap-1.5 text-xs text-neutral-grey-50", children: translationFolderExists && providersFolderExists ? (_jsxs(_Fragment, { children: [_jsx(CheckCircleIcon, { className: "h-3.5 w-3.5 text-feedback-green", strokeWidth: 1.5 }), "All parent items found"] })) : (_jsxs(_Fragment, { children: [_jsx(AlertCircleIcon, { className: "h-3.5 w-3.5 text-feedback-orange", strokeWidth: 1.5 }), "Parent items missing"] })) }), !providersFolderExists && (_jsxs(Button, { size: "sm", variant: "default", onClick: ensureStructure, disabled: ensuringStructure || structureLoading, children: [ensuringStructure ? (_jsx(RefreshCwIcon, { strokeWidth: 1, className: "mr-1 h-4 w-4 animate-spin" })) : (_jsx(PlusIcon, { strokeWidth: 1.75, className: "mr-1 h-4 w-4" })), "Ensure items"] }))] }), children: _jsxs("div", { className: "divide-y divide-border-default border-t border-border-default", children: [_jsxs("div", { "data-testid": "translation-structure-folder", className: `flex items-center gap-3 px-3 py-3 text-sm transition-colors ${selectedConfigTarget?.key ===
246
+ `structure:${structureState?.translationFolder?.itemId}`
247
+ ? "bg-feedback-blue-light"
248
+ : "bg-white"}`, children: [translationFolderExists ? (_jsx(CheckCircleIcon, { className: "h-4 w-4 shrink-0 text-feedback-green", strokeWidth: 1.5 })) : (_jsx(AlertCircleIcon, { className: "h-4 w-4 shrink-0 text-feedback-orange", strokeWidth: 1.5 })), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: "font-medium text-neutral-grey-100", children: "Translation folder" }), _jsx("div", { className: "mt-0.5 truncate font-mono text-xs text-neutral-grey-50", children: structureSettings.translationFolderPath })] }), translationFolderExists &&
249
+ structureState?.translationFolder?.itemId && (_jsx(Button, { size: "sm", variant: "ghost", onClick: () => handleOpenStructureConfig(structureState.translationFolder.itemId, "Configure: Translation folder"), title: "Configure", children: _jsx(SettingsIcon, { className: "h-3.5 w-3.5", strokeWidth: 1.5 }) }))] }), _jsxs("div", { "data-testid": "translation-structure-providers-folder", className: `flex items-center gap-3 px-3 py-3 text-sm transition-colors ${selectedConfigTarget?.key ===
250
+ `structure:${structureState?.translationProvidersFolder?.itemId}`
251
+ ? "bg-feedback-blue-light"
252
+ : "bg-white"}`, children: [providersFolderExists ? (_jsx(CheckCircleIcon, { className: "h-4 w-4 shrink-0 text-feedback-green", strokeWidth: 1.5 })) : (_jsx(AlertCircleIcon, { className: "h-4 w-4 shrink-0 text-feedback-orange", strokeWidth: 1.5 })), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: "font-medium text-neutral-grey-100", children: "Translation providers folder" }), _jsx("div", { className: "mt-0.5 truncate font-mono text-xs text-neutral-grey-50", children: structureSettings.translationProvidersPath })] }), providersFolderExists &&
253
+ structureState?.translationProvidersFolder?.itemId && (_jsx(Button, { size: "sm", variant: "ghost", onClick: () => handleOpenStructureConfig(structureState.translationProvidersFolder.itemId, "Configure: Translation Providers folder"), title: "Configure", children: _jsx(SettingsIcon, { className: "h-3.5 w-3.5", strokeWidth: 1.5 }) }))] })] }) }), _jsxs(Card, { icon: _jsx(LanguagesIcon, { strokeWidth: 1, className: "h-5 w-5" }), title: _jsxs(_Fragment, { children: ["Translation providers", " ", _jsxs("span", { className: "font-normal text-neutral-grey-50", children: ["(", configuredCount, " of ", totalCount, " configured)"] })] }), description: "Translation services registered in Parhelia and their settings.", noPadding: true, className: "flex min-h-0 flex-1 flex-col overflow-hidden", children: [((totalCount === 0 && state === "success") || error) && (_jsxs("div", { className: "border-border-default space-y-2 border-t px-4 py-3", children: [totalCount === 0 && state === "success" && (_jsx("div", { className: "rounded border border-feedback-orange bg-feedback-orange-light p-2 text-xs text-feedback-orange", children: "No translation services are registered in dependency injection. Please check the server configuration." })), error && (_jsx("div", { className: "rounded border border-feedback-red bg-feedback-red-light p-2 text-xs whitespace-pre-wrap text-feedback-red", children: error }))] })), _jsx("div", { className: "min-h-0 flex-1 overflow-y-auto border-t border-border-default", "data-testid": "translation-services-providers", children: services.length > 0 && (_jsx("div", { className: "divide-y divide-border-default", children: services.map((service) => {
270
254
  const isSelected = selectedConfigTarget?.key ===
271
255
  `service:${service.serviceName}`;
272
- return (_jsxs("div", { className: `flex items-center justify-between rounded border p-3 text-sm transition-shadow hover:shadow-sm ${isSelected
273
- ? "border-blue-400 bg-blue-50"
274
- : "border-gray-200 bg-white"}`, children: [_jsxs("div", { className: "flex items-center gap-3 flex-1 min-w-0", children: [service.isConfigured ? (_jsx(CheckCircleIcon, { className: "h-4 w-4 text-green-600 shrink-0", strokeWidth: 1.5 })) : (_jsx(AlertCircleIcon, { className: "h-4 w-4 text-amber-500 shrink-0", strokeWidth: 1.5 })), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("div", { className: "font-medium text-gray-900 truncate", children: service.displayName || service.serviceName }), service.displayName &&
275
- service.displayName !== service.serviceName && (_jsxs("div", { className: "text-xs text-gray-500 truncate", children: ["Service: ", service.serviceName] })), service.isConfigured &&
276
- service.supportedLanguages &&
277
- service.supportedLanguages.length > 0 && (_jsxs("div", { className: "text-xs text-gray-500 mt-1 truncate", children: ["Languages:", " ", service.supportedLanguages.join(", ")] })), !service.isConfigured && (_jsx("div", { className: "text-xs text-amber-600 mt-1", children: "Not configured" }))] })] }), _jsx("div", { className: "flex items-center gap-2 ml-4 shrink-0", children: service.isConfigured && service.settingsItemId ? (_jsxs(_Fragment, { children: [_jsxs(Button, { size: "sm", variant: isSelected ? "default" : "ghost", onClick: () => handleOpenConfig(service), className: "shrink-0", disabled: service.deleting, children: [_jsx(SettingsIcon, { className: "h-4 w-4", strokeWidth: 1.5 }), editContext?.isMobile ? "" : "Configure"] }), _jsxs(Button, { size: "sm", variant: "ghost", onClick: () => deleteSettings(service), className: "shrink-0 text-red-600 hover:text-red-700", disabled: service.deleting, title: `Delete settings for ${service.displayName || service.serviceName}`, children: [service.deleting ? (_jsx(RefreshCwIcon, { strokeWidth: 1, className: "h-4 w-4 animate-spin" })) : (_jsx(Trash2Icon, { className: "h-4 w-4", strokeWidth: 1.5 })), editContext?.isMobile ? "" : "Delete"] })] })) : (_jsxs(Button, { size: "sm", variant: "outline", onClick: () => createSettings(service.serviceName, service.templateId), disabled: service.creating, title: `Create settings using template: ${service.templateName}`, className: "shrink-0", children: [service.creating ? (_jsx(RefreshCwIcon, { strokeWidth: 1, className: "h-4 w-4 animate-spin" })) : (_jsx(PlusIcon, { strokeWidth: 1.5, className: "h-4 w-4" })), "Create Settings"] })) })] }, service.serviceName));
278
- }) })), error && (_jsx("div", { className: "rounded border border-red-200 bg-red-50 p-3 text-sm text-red-700 whitespace-pre-wrap", children: error }))] }) }) }) }));
256
+ const isConfigured = service.isConfigured;
257
+ return (_jsxs("div", { className: `group flex items-center gap-3 px-3 py-3 text-sm transition-colors ${isSelected
258
+ ? "bg-feedback-blue-light"
259
+ : "bg-white hover:bg-neutral-grey-5"}`, children: [isConfigured ? (_jsx(CheckCircleIcon, { className: "h-4 w-4 shrink-0 text-feedback-green", strokeWidth: 1.5 })) : (_jsx(AlertCircleIcon, { className: "h-4 w-4 shrink-0 text-feedback-orange", strokeWidth: 1.5 })), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-1.5", children: [_jsx("span", { className: "truncate font-medium text-neutral-grey-100", children: service.displayName || service.serviceName }), service.displayName &&
260
+ service.displayName !== service.serviceName && (_jsx("span", { className: "shrink-0 rounded bg-neutral-grey-5 badge-pad-sm text-[10px] font-medium text-neutral-grey-50", children: service.serviceName })), !isConfigured && (_jsx("span", { className: "shrink-0 rounded bg-feedback-orange-light badge-pad-sm text-[10px] font-medium text-feedback-orange", children: "Not configured" }))] }), isConfigured &&
261
+ service.supportedLanguages &&
262
+ service.supportedLanguages.length > 0 && (_jsxs("div", { className: "mt-0.5 truncate text-xs text-neutral-grey-50", children: ["Languages: ", service.supportedLanguages.join(", ")] }))] }), _jsx("div", { className: "flex shrink-0 items-center gap-0.5", children: isConfigured && service.settingsItemId ? (_jsxs("div", { className: "flex items-center gap-0.5 opacity-60 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100", children: [_jsx(Button, { size: "sm", variant: "ghost", onClick: () => handleOpenConfig(service), disabled: service.deleting, title: "Configure", children: _jsx(SettingsIcon, { className: "h-3.5 w-3.5", strokeWidth: 1.5 }) }), _jsx(Button, { size: "sm", variant: "ghost", onClick: () => deleteSettings(service), className: "text-neutral-grey-50 hover:bg-neutral-grey-5 hover:text-neutral-grey-50", disabled: service.deleting, title: `Delete settings for ${service.displayName || service.serviceName}`, children: service.deleting ? (_jsx(RefreshCwIcon, { strokeWidth: 1, className: "h-3.5 w-3.5 animate-spin" })) : (_jsx(DeleteIcon, { size: "md" })) })] })) : (_jsxs(Button, { size: "sm", variant: "default", onClick: () => createSettings(service.serviceName, service.templateId), disabled: service.creating, title: `Create settings using template: ${service.templateName}`, children: [service.creating ? (_jsx(RefreshCwIcon, { strokeWidth: 1, className: "mr-1 h-3.5 w-3.5 animate-spin" })) : (_jsx(PlusIcon, { strokeWidth: 1.75, className: "mr-1 h-3.5 w-3.5" })), "Create"] })) })] }, service.serviceName));
263
+ }) })) })] })] }));
279
264
  // Build splitter panels - only show config panel when a service is selected
280
265
  const panels = selectedConfigTarget?.itemId
281
266
  ? [
@@ -1 +1 @@
1
- {"version":3,"file":"LocalizationSetupStep.d.ts","sourceRoot":"","sources":["../../src/setup/LocalizationSetupStep.tsx"],"names":[],"mappings":"AAgCA,wBAAgB,qBAAqB,4CA6NpC;AAED,eAAe,qBAAqB,CAAC"}
1
+ {"version":3,"file":"LocalizationSetupStep.d.ts","sourceRoot":"","sources":["../../src/setup/LocalizationSetupStep.tsx"],"names":[],"mappings":"AAgCA,wBAAgB,qBAAqB,4CA6QpC;AAED,eAAe,qBAAqB,CAAC"}
@@ -15,12 +15,12 @@ export function LocalizationSetupStep() {
15
15
  const [services, setServices] = useState([]);
16
16
  const statusIcon = useCallback((state) => {
17
17
  if (state === "success")
18
- return _jsx(CheckCircleIcon, { className: "h-4 w-4 text-[#8ae048]", strokeWidth: 1 });
18
+ return (_jsx(CheckCircleIcon, { className: "h-4 w-4 text-[var(--color-feedback-green)]", strokeWidth: 1 }));
19
19
  if (state === "error")
20
- return _jsx(AlertCircleIcon, { className: "h-4 w-4 text-destructive", strokeWidth: 1 });
20
+ return (_jsx(AlertCircleIcon, { className: "h-4 w-4 text-destructive", strokeWidth: 1 }));
21
21
  if (state === "partial")
22
- return _jsx(AlertCircleIcon, { className: "h-4 w-4 text-[#ffc310]", strokeWidth: 1 });
23
- return (_jsx(RefreshCwIcon, { className: "h-4 w-4 animate-spin text-[#9650fb]", strokeWidth: 1 }));
22
+ return (_jsx(AlertCircleIcon, { className: "h-4 w-4 text-[var(--color-feedback-orange)]", strokeWidth: 1 }));
23
+ return (_jsx(RefreshCwIcon, { className: "h-4 w-4 animate-spin text-[var(--color-highlight-100)]", strokeWidth: 1 }));
24
24
  }, []);
25
25
  const checkLocalization = useCallback(async () => {
26
26
  try {
@@ -42,14 +42,14 @@ export function LocalizationSetupStep() {
42
42
  else {
43
43
  const serviceStates = availableServices.map((svc) => ({
44
44
  ...svc,
45
- creating: false
45
+ creating: false,
46
46
  }));
47
47
  setServices(serviceStates);
48
- const configuredCount = serviceStates.filter(s => s.isConfigured).length;
48
+ const configuredCount = serviceStates.filter((s) => s.isConfigured).length;
49
49
  const totalCount = serviceStates.length;
50
50
  if (configuredCount === 0) {
51
51
  setState("error");
52
- setError(`Found ${totalCount} translation service${totalCount !== 1 ? 's' : ''} in DI, but none have Sitecore Settings items configured.`);
52
+ setError(`Found ${totalCount} translation service${totalCount !== 1 ? "s" : ""} in DI, but none have Sitecore Settings items configured.`);
53
53
  }
54
54
  else if (configuredCount < totalCount) {
55
55
  setState("partial");
@@ -62,7 +62,8 @@ export function LocalizationSetupStep() {
62
62
  }
63
63
  else {
64
64
  setState("error");
65
- setError(result.details || "Failed to check translation services. The translation API may not be available.");
65
+ setError(result.details ||
66
+ "Failed to check translation services. The translation API may not be available.");
66
67
  }
67
68
  }
68
69
  catch (e) {
@@ -72,7 +73,7 @@ export function LocalizationSetupStep() {
72
73
  }, []);
73
74
  const createSettings = useCallback(async (serviceName, templateId) => {
74
75
  try {
75
- setServices(prev => prev.map(s => s.serviceName === serviceName ? { ...s, creating: true } : s));
76
+ setServices((prev) => prev.map((s) => s.serviceName === serviceName ? { ...s, creating: true } : s));
76
77
  setError(null);
77
78
  const language = editContext?.item?.language ??
78
79
  editContext?.currentItemDescriptor?.language ??
@@ -80,13 +81,20 @@ export function LocalizationSetupStep() {
80
81
  const result = await createProviderSettings(serviceName, templateId, language);
81
82
  if (result.type === "success" && result.data) {
82
83
  if (result.data.success && result.data.data) {
83
- setServices(prev => prev.map(s => s.serviceName === serviceName
84
- ? { ...s, isConfigured: true, creating: false, settingsItemId: result.data?.data?.itemId }
84
+ setServices((prev) => prev.map((s) => s.serviceName === serviceName
85
+ ? {
86
+ ...s,
87
+ isConfigured: true,
88
+ creating: false,
89
+ settingsItemId: result.data?.data?.itemId,
90
+ }
85
91
  : s));
86
92
  setTimeout(() => checkLocalization(), 500);
87
93
  }
88
94
  else {
89
- throw new Error(result.data.error || result.details || "Failed to create settings");
95
+ throw new Error(result.data.error ||
96
+ result.details ||
97
+ "Failed to create settings");
90
98
  }
91
99
  }
92
100
  else {
@@ -95,22 +103,25 @@ export function LocalizationSetupStep() {
95
103
  }
96
104
  catch (e) {
97
105
  setError(`Failed to create settings for ${serviceName}: ${e?.message || "Unknown error"}`);
98
- setServices(prev => prev.map(s => s.serviceName === serviceName ? { ...s, creating: false } : s));
106
+ setServices((prev) => prev.map((s) => s.serviceName === serviceName ? { ...s, creating: false } : s));
99
107
  }
100
108
  }, [editContext, checkLocalization]);
101
109
  React.useEffect(() => {
102
110
  checkLocalization();
103
111
  }, [checkLocalization]);
104
- const configuredCount = services.filter(s => s.isConfigured).length;
112
+ const configuredCount = services.filter((s) => s.isConfigured).length;
105
113
  const totalCount = services.length;
106
- return (_jsx(Card, { icon: _jsx(LanguagesIcon, { strokeWidth: 1, className: "h-5 w-5" }), title: "Localization setup", description: "Verifies that translation services registered in DI have corresponding Sitecore Settings items.", children: _jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "flex items-center gap-2", children: [statusIcon(state), _jsx("span", { className: "text-sm text-[var(--color-gray-1)]", children: state === "success"
107
- ? `All ${totalCount} translation service${totalCount !== 1 ? 's' : ''} configured`
114
+ return (_jsx(Card, { icon: _jsx(LanguagesIcon, { strokeWidth: 1, className: "h-5 w-5" }), title: "Localization setup", description: "Verifies that translation services registered in DI have corresponding Sitecore Settings items.", children: _jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "flex items-center gap-2", children: [statusIcon(state), _jsx("span", { className: "text-sm text-neutral-grey-100", children: state === "success"
115
+ ? `All ${totalCount} translation service${totalCount !== 1 ? "s" : ""} configured`
108
116
  : state === "partial"
109
117
  ? `${configuredCount} of ${totalCount} services configured`
110
118
  : state === "error" && totalCount > 0
111
- ? `${totalCount} service${totalCount !== 1 ? 's' : ''} found, none configured`
119
+ ? `${totalCount} service${totalCount !== 1 ? "s" : ""} found, none configured`
112
120
  : state === "error"
113
121
  ? "No services found"
114
- : "Checking..." })] }), _jsxs(Button, { size: "sm", variant: "outline", onClick: checkLocalization, children: [_jsx(RefreshCwIcon, { strokeWidth: 1, className: "h-4 w-4" }), "Recheck"] })] }), services.length > 0 && (_jsxs("div", { className: "space-y-2 rounded-lg border border-[var(--color-gray-3)] bg-[var(--color-gray-5)] p-3", children: [_jsx("div", { className: "text-xs font-semibold text-[var(--color-gray-2)] uppercase tracking-wide", children: "Translation Services" }), services.map((service) => (_jsxs("div", { className: "flex items-center justify-between rounded-md bg-background p-3 shadow-sm border border-[var(--color-gray-3)]", children: [_jsxs("div", { className: "flex items-center gap-2", children: [service.isConfigured ? (_jsx(CheckCircleIcon, { className: "h-3.5 w-3.5 text-[#8ae048]", strokeWidth: 1.5 })) : (_jsx(AlertCircleIcon, { className: "h-3.5 w-3.5 text-[#ffc310]", strokeWidth: 1.5 })), _jsxs("div", { children: [_jsx("div", { className: "text-sm font-medium text-[var(--color-dark)]", children: service.displayName || service.serviceName }), service.displayName && service.displayName !== service.serviceName && (_jsxs("div", { className: "text-xs text-[var(--color-gray-2)]", children: ["Service: ", service.serviceName] })), service.isConfigured && service.supportedLanguages && service.supportedLanguages.length > 0 && (_jsxs("div", { className: "text-xs text-[var(--color-gray-2)]", children: ["Languages: ", service.supportedLanguages.join(", ")] }))] })] }), !service.isConfigured && (_jsxs(Button, { size: "xs", onClick: () => createSettings(service.serviceName, service.templateId), disabled: service.creating, title: `Create using template: ${service.templateName}`, children: [service.creating ? (_jsx(RefreshCwIcon, { strokeWidth: 1, className: "h-3 w-3 animate-spin" })) : (_jsx(PlusIcon, { strokeWidth: 1.5, className: "h-3 w-3" })), "Create Settings"] }))] }, service.serviceName)))] })), error && (_jsx("div", { className: "rounded-md border border-[#ffc310]/30 bg-[#ffc310]/10 p-3 text-xs whitespace-pre-wrap text-[var(--color-dark)]", children: error }))] }) }));
122
+ : "Checking..." })] }), _jsxs(Button, { size: "sm", variant: "outline", onClick: checkLocalization, children: [_jsx(RefreshCwIcon, { strokeWidth: 1, className: "h-4 w-4" }), "Recheck"] })] }), services.length > 0 && (_jsxs("div", { className: "space-y-2 rounded-lg border border-border-default bg-neutral-grey-5 p-3", children: [_jsx("div", { className: "text-xs font-medium text-neutral-grey-50 tracking-wide", children: "Translation Services" }), services.map((service) => (_jsxs("div", { className: "flex items-center justify-between rounded-md bg-background p-3 shadow-sm border border-border-default", children: [_jsxs("div", { className: "flex items-center gap-2", children: [service.isConfigured ? (_jsx(CheckCircleIcon, { className: "h-3.5 w-3.5 text-[var(--color-feedback-green)]", strokeWidth: 1.5 })) : (_jsx(AlertCircleIcon, { className: "h-3.5 w-3.5 text-[var(--color-feedback-orange)]", strokeWidth: 1.5 })), _jsxs("div", { children: [_jsx("div", { className: "text-sm font-medium text-neutral-grey-100", children: service.displayName || service.serviceName }), service.displayName &&
123
+ service.displayName !== service.serviceName && (_jsxs("div", { className: "text-xs text-neutral-grey-50", children: ["Service: ", service.serviceName] })), service.isConfigured &&
124
+ service.supportedLanguages &&
125
+ service.supportedLanguages.length > 0 && (_jsxs("div", { className: "text-xs text-neutral-grey-50", children: ["Languages: ", service.supportedLanguages.join(", ")] }))] })] }), !service.isConfigured && (_jsxs(Button, { size: "xs", onClick: () => createSettings(service.serviceName, service.templateId), disabled: service.creating, title: `Create using template: ${service.templateName}`, children: [service.creating ? (_jsx(RefreshCwIcon, { strokeWidth: 1, className: "h-3 w-3 animate-spin" })) : (_jsx(PlusIcon, { strokeWidth: 1.5, className: "h-3 w-3" })), "Create Settings"] }))] }, service.serviceName)))] })), error && (_jsx("div", { className: "rounded-md border border-feedback-orange/30 bg-feedback-orange/10 p-3 text-xs whitespace-pre-wrap text-neutral-grey-100", children: error }))] }) }));
115
126
  }
116
127
  export default LocalizationSetupStep;
@@ -1 +1 @@
1
- {"version":3,"file":"TranslationSidebar.d.ts","sourceRoot":"","sources":["../../src/sidebar/TranslationSidebar.tsx"],"names":[],"mappings":"AAcA,wBAAgB,kBAAkB,mDA4MjC"}
1
+ {"version":3,"file":"TranslationSidebar.d.ts","sourceRoot":"","sources":["../../src/sidebar/TranslationSidebar.tsx"],"names":[],"mappings":"AAkBA,wBAAgB,kBAAkB,mDA8NjC"}
@@ -3,6 +3,9 @@ import { Button, useEditContext, SimpleTable, confirmCreateVersion, Progress, }
3
3
  import { getTranslationStatus } from "../services/translationService";
4
4
  import { useEffect, useState } from "react";
5
5
  import { localizeItemCommand } from "../LocalizeItemCommand";
6
+ function isActiveTranslationStatus(status) {
7
+ return status === "Pending" || status === "In Progress";
8
+ }
6
9
  export function TranslationSidebar() {
7
10
  const editContext = useEditContext();
8
11
  if (!editContext)
@@ -25,7 +28,7 @@ export function TranslationSidebar() {
25
28
  });
26
29
  };
27
30
  const languageName = (language) => {
28
- return (_jsxs("div", { className: "flex items-center gap-2 text-[var(--color-dark)]", children: [_jsx("img", { src: language.icon, className: "h-5 rounded-sm", alt: language.languageCode }), _jsx("span", { className: "font-medium", children: language.name })] }, language.languageCode));
31
+ return (_jsxs("div", { className: "flex items-center gap-2 text-neutral-grey-100", children: [_jsx("img", { src: language.icon, className: "h-5 rounded-sm", alt: language.languageCode }), _jsx("span", { className: "font-medium", children: language.name })] }, language.languageCode));
29
32
  };
30
33
  const loadTranslationStatus = async () => {
31
34
  if (!item)
@@ -72,7 +75,11 @@ export function TranslationSidebar() {
72
75
  const effectiveStatus = progress ? "In Progress" : status?.status;
73
76
  return {
74
77
  ...x,
75
- translationStatus: status ? { ...status, status: effectiveStatus } : (progress ? { status: "In Progress" } : undefined),
78
+ translationStatus: status
79
+ ? { ...status, status: effectiveStatus }
80
+ : progress
81
+ ? { status: "In Progress" }
82
+ : undefined,
76
83
  translationProgress: progress,
77
84
  };
78
85
  });
@@ -85,7 +92,7 @@ export function TranslationSidebar() {
85
92
  // Sort by name for languages that both have versions or both don't
86
93
  return a.name.localeCompare(b.name);
87
94
  });
88
- return (_jsxs("div", { className: "flex h-full flex-col", "data-testid": "translation-sidebar", children: [_jsx("div", { className: "flex items-center justify-end border-b border-[var(--color-gray-3)] p-1 px-2", children: item && (_jsx(Button, { size: "xs", "data-testid": "translation-sidebar-localize-button", onClick: () => {
95
+ return (_jsxs("div", { className: "flex h-full flex-col", "data-testid": "translation-sidebar", children: [_jsx("div", { className: "flex items-center justify-end border-b border-border-default p-1 px-2", children: item && (_jsx(Button, { size: "xs", "data-testid": "translation-sidebar-localize-button", onClick: () => {
89
96
  editContext.executeCommand({
90
97
  command: localizeItemCommand,
91
98
  data: {
@@ -94,20 +101,23 @@ export function TranslationSidebar() {
94
101
  });
95
102
  }, children: "Translate" })) }), _jsx("div", { className: "relative flex-1", children: _jsx("div", { className: "absolute inset-0 overflow-y-auto", children: _jsx(SimpleTable, { "data-testid": "translation-sidebar-language-table", columns: [
96
103
  { header: "Language", body: languageName },
97
- { header: "Ver.", body: (x) => _jsx("span", { className: "text-[var(--color-gray-1)]", children: x.versions.toString() }) },
104
+ {
105
+ header: "Ver.",
106
+ body: (x) => (_jsx("span", { className: "text-neutral-grey-100", children: x.versions.toString() })),
107
+ },
98
108
  {
99
109
  header: "Src",
100
- body: (x) => _jsx("span", { className: "text-[var(--color-gray-2)]", children: x.translationStatus?.sourceLanguage }),
110
+ body: (x) => (_jsx("span", { className: "text-neutral-grey-50", children: x.translationStatus?.sourceLanguage })),
101
111
  },
102
112
  {
103
113
  header: "Status",
104
- body: (x) => (_jsxs("div", { className: "flex items-center gap-2", "data-testid": `translation-status-${x.languageCode}`, children: [x.translationStatus?.status === "In Progress" && (_jsxs("div", { className: "relative w-full", children: [_jsx(Progress, { className: "h-5", value: (x.translationProgress?.progress || 0) * 100, showValue: false, indicatorClassName: "bg-[#9650fb]", "data-testid": `translation-progress-${x.languageCode}` }), _jsx("div", { className: "absolute inset-0 flex items-center justify-center text-white text-xs font-medium", children: x.translationProgress?.message })] })), x.translationStatus?.status !== "In Progress" && (_jsx("span", { title: x.translationStatus?.message, className: x.translationStatus?.status === "Completed"
105
- ? "text-green-600 font-medium"
114
+ body: (x) => (_jsxs("div", { className: "flex items-center gap-2", "data-testid": `translation-status-${x.languageCode}`, children: [isActiveTranslationStatus(x.translationStatus?.status) && (_jsxs("div", { className: "relative w-full", children: [_jsx(Progress, { className: "h-5", value: (x.translationProgress?.progress || 0) * 100, showValue: false, indicatorClassName: "bg-[var(--color-highlight-100)]", "data-testid": `translation-progress-${x.languageCode}` }), _jsx("div", { className: "absolute inset-0 flex items-center justify-center text-white text-xs font-medium", children: x.translationProgress?.message })] })), !isActiveTranslationStatus(x.translationStatus?.status) && (_jsx("span", { title: x.translationStatus?.message, className: x.translationStatus?.status === "Completed"
115
+ ? "text-feedback-green font-medium"
106
116
  : x.translationStatus?.status === "Error"
107
- ? "text-red-600 font-medium"
108
- : "text-[var(--color-gray-2)]", children: x.translationStatus?.status || "Not started" }))] })),
117
+ ? "text-feedback-red font-medium"
118
+ : "text-neutral-grey-50", children: x.translationStatus?.status || "Not started" }))] })),
109
119
  },
110
120
  ], items: languageData, onRowClick: (data) => selectLanguage(data.item), rowClassName: (item) => item.languageCode == editContext.currentItemDescriptor?.language
111
- ? "bg-[#f6eeff]"
121
+ ? "bg-[var(--color-highlight-10)]"
112
122
  : "" }) }) })] }));
113
123
  }
@@ -0,0 +1,3 @@
1
+ import { TranslationStepProps } from "./types";
2
+ export declare function ItemSelectionStep({ isActive, data, setData, onStepCompleted, editContext, }: TranslationStepProps): import("react/jsx-runtime").JSX.Element;
3
+ //# sourceMappingURL=ItemSelectionStep.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ItemSelectionStep.d.ts","sourceRoot":"","sources":["../../src/steps/ItemSelectionStep.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAI/C,wBAAgB,iBAAiB,CAAC,EAChC,QAAe,EACf,IAAI,EACJ,OAAO,EACP,eAAe,EACf,WAAW,GACZ,EAAE,oBAAoB,2CAoCtB"}
@@ -0,0 +1,24 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useEffect, useRef, useState } from "react";
3
+ import { ItemSelectionTree } from "./ItemSelectionTree";
4
+ import { WizardStepShell } from "./WizardStepShell";
5
+ export function ItemSelectionStep({ isActive = true, data, setData, onStepCompleted, editContext, }) {
6
+ const multiItemEnabled = editContext?.configuration?.localization?.multiItem !== false;
7
+ const [itemSelectionValid, setItemSelectionValid] = useState(!multiItemEnabled ||
8
+ (data.selectionTreeItems?.length ?? data.items.length) > 0);
9
+ const onStepCompletedRef = useRef(onStepCompleted);
10
+ useEffect(() => {
11
+ onStepCompletedRef.current = onStepCompleted;
12
+ }, [onStepCompleted]);
13
+ const lastCompletionRef = useRef(null);
14
+ useEffect(() => {
15
+ if (!isActive)
16
+ return;
17
+ const completed = !multiItemEnabled || itemSelectionValid;
18
+ if (lastCompletionRef.current !== completed) {
19
+ lastCompletionRef.current = completed;
20
+ onStepCompletedRef.current(completed);
21
+ }
22
+ }, [isActive, itemSelectionValid, multiItemEnabled]);
23
+ return (_jsx(WizardStepShell, { fillHeight: true, testId: "item-selection-step", children: _jsx(ItemSelectionTree, { data: data, setData: setData, editContext: editContext, isActive: isActive, onSelectionValidChange: setItemSelectionValid, height: "100%" }) }));
24
+ }
@@ -0,0 +1,13 @@
1
+ import { type EditContextType } from "@parhelia/core";
2
+ import type { TranslationWizardData } from "./types";
3
+ type ItemSelectionTreeProps = {
4
+ data: TranslationWizardData;
5
+ setData: (data: TranslationWizardData) => void;
6
+ editContext: EditContextType;
7
+ isActive?: boolean;
8
+ onSelectionValidChange?: (valid: boolean) => void;
9
+ height?: number | string;
10
+ };
11
+ export declare function ItemSelectionTree({ data, setData, editContext, isActive, onSelectionValidChange, height, }: ItemSelectionTreeProps): import("react/jsx-runtime").JSX.Element;
12
+ export {};
13
+ //# sourceMappingURL=ItemSelectionTree.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ItemSelectionTree.d.ts","sourceRoot":"","sources":["../../src/steps/ItemSelectionTree.tsx"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,eAAe,EAMrB,MAAM,gBAAgB,CAAC;AAExB,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAGrD,KAAK,sBAAsB,GAAG;IAC5B,IAAI,EAAE,qBAAqB,CAAC;IAC5B,OAAO,EAAE,CAAC,IAAI,EAAE,qBAAqB,KAAK,IAAI,CAAC;IAC/C,WAAW,EAAE,eAAe,CAAC;IAC7B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sBAAsB,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IAClD,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC1B,CAAC;AAkEF,wBAAgB,iBAAiB,CAAC,EAChC,IAAI,EACJ,OAAO,EACP,WAAW,EACX,QAAe,EACf,sBAAsB,EACtB,MAAY,GACb,EAAE,sBAAsB,2CA4VxB"}