@parhelia/localization 0.1.12808 → 0.1.12838
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/LocalizeItemCommand.d.ts.map +1 -1
- package/dist/LocalizeItemCommand.js +4 -2
- package/dist/LocalizeItemDialog.d.ts.map +1 -1
- package/dist/LocalizeItemDialog.js +7 -4
- package/dist/LocalizeItemUtils.d.ts.map +1 -1
- package/dist/LocalizeItemUtils.js +35 -25
- package/dist/api/discovery.d.ts.map +1 -1
- package/dist/api/discovery.js +20 -3
- package/dist/hooks/useTranslationWizard.d.ts.map +1 -1
- package/dist/hooks/useTranslationWizard.js +3 -3
- package/dist/services/translationService.d.ts +2 -2
- package/dist/services/translationService.d.ts.map +1 -1
- package/dist/services/translationService.js +21 -5
- package/dist/settings/TranslationServicesPanel.d.ts.map +1 -1
- package/dist/settings/TranslationServicesPanel.js +24 -21
- package/dist/setup/LocalizationSetupStep.d.ts.map +1 -1
- package/dist/setup/LocalizationSetupStep.js +29 -18
- package/dist/sidebar/TranslationSidebar.d.ts.map +1 -1
- package/dist/sidebar/TranslationSidebar.js +17 -10
- package/dist/steps/ItemSelectionStep.d.ts.map +1 -1
- package/dist/steps/ItemSelectionStep.js +2 -1
- package/dist/steps/ItemSelectionTree.d.ts.map +1 -1
- package/dist/steps/ItemSelectionTree.js +2 -1
- package/dist/steps/PromptCustomizationStep.d.ts.map +1 -1
- package/dist/steps/PromptCustomizationStep.js +6 -8
- package/dist/steps/ServiceLanguageSelectionStep.d.ts.map +1 -1
- package/dist/steps/ServiceLanguageSelectionStep.js +6 -4
- package/dist/steps/WizardStepShell.d.ts.map +1 -1
- package/dist/steps/types.d.ts.map +1 -1
- package/dist/translation-center/TranslationBatches.d.ts.map +1 -1
- package/dist/translation-center/TranslationBatches.js +187 -115
- package/dist/translation-center/TranslationManagement.js +4 -4
- package/dist/translation-center/TranslationsTitlebar.d.ts.map +1 -1
- package/dist/translation-center/TranslationsTitlebar.js +2 -2
- package/package.json +1 -1
- package/dist/constants.d.ts +0 -15
- package/dist/constants.d.ts.map +0 -1
- package/dist/constants.js +0 -21
- package/dist/steps/MetadataInputStep.d.ts +0 -4
- package/dist/steps/MetadataInputStep.d.ts.map +0 -1
- package/dist/steps/MetadataInputStep.js +0 -48
- package/dist/steps/SubitemDiscoveryStep.d.ts +0 -3
- package/dist/steps/SubitemDiscoveryStep.d.ts.map +0 -1
- package/dist/steps/SubitemDiscoveryStep.js +0 -313
- package/dist/steps/index.d.ts +0 -6
- package/dist/steps/index.d.ts.map +0 -1
- package/dist/steps/index.js +0 -5
- package/dist/utils/createVersions.d.ts +0 -14
- package/dist/utils/createVersions.d.ts.map +0 -1
- package/dist/utils/createVersions.js +0 -26
|
@@ -10,9 +10,9 @@ export function TranslationManagement() {
|
|
|
10
10
|
?.flatMap((x) => x.panels)
|
|
11
11
|
?.find((panel) => panel.id === "translation-batches");
|
|
12
12
|
if (!config) {
|
|
13
|
-
return (_jsx("div", { className: "flex h-full flex-col items-center justify-center bg-
|
|
13
|
+
return (_jsx("div", { className: "flex h-full flex-col items-center justify-center bg-neutral-grey-5", children: _jsxs("div", { className: "flex items-center gap-2 text-neutral-grey-50", children: [_jsx("i", { className: "pi pi-spin pi-spinner text-[var(--color-highlight-100)]" }), "Loading..."] }) }));
|
|
14
14
|
}
|
|
15
|
-
const managementContent = translationBatchesPanel ? (_jsx("div", { className: "flex-1 min-h-0", children: translationBatchesPanel.content })) : (_jsxs("div", { className: "flex h-full flex-col items-center justify-center text-
|
|
15
|
+
const managementContent = translationBatchesPanel ? (_jsx("div", { className: "flex-1 min-h-0", children: translationBatchesPanel.content })) : (_jsxs("div", { className: "flex h-full flex-col items-center justify-center text-neutral-grey-50", children: [_jsx("i", { className: "pi pi-language mb-4 text-4xl text-neutral-grey-15" }), _jsx("p", { className: "font-medium text-neutral-grey-100", children: "Translation batches not available" })] }));
|
|
16
16
|
const panels = [
|
|
17
17
|
{
|
|
18
18
|
name: "translation-management",
|
|
@@ -24,8 +24,8 @@ export function TranslationManagement() {
|
|
|
24
24
|
panels.push({
|
|
25
25
|
name: "editor-preview",
|
|
26
26
|
defaultSize: isMobile ? 45 : 500,
|
|
27
|
-
content: (_jsx("div", { className: "h-full overflow-hidden border-l border-
|
|
27
|
+
content: (_jsx("div", { className: "h-full overflow-hidden border-l border-border-default bg-neutral-grey-5", children: _jsx(ItemEditorPane, { name: "translation-management-preview", emptyDescription: "Select a translation batch item or language row to preview and edit it here." }) })),
|
|
28
28
|
});
|
|
29
29
|
}
|
|
30
|
-
return (_jsx("div", { className: "absolute inset-0 flex flex-col bg-
|
|
30
|
+
return (_jsx("div", { className: "absolute inset-0 flex flex-col bg-neutral-grey-5", "data-testid": "translation-management", children: _jsx(Splitter, { panels: panels, direction: isMobile ? "vertical" : "horizontal", localStorageKey: "translation-management.panelSizes" }) }));
|
|
31
31
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TranslationsTitlebar.d.ts","sourceRoot":"","sources":["../../src/translation-center/TranslationsTitlebar.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"TranslationsTitlebar.d.ts","sourceRoot":"","sources":["../../src/translation-center/TranslationsTitlebar.tsx"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,wBAAgB,oBAAoB,mDA8CnC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { SimpleIconButton, useEditContext, cn
|
|
2
|
+
import { SimpleIconButton, useEditContext, cn } from "@parhelia/core";
|
|
3
3
|
import { SquarePen } from "lucide-react";
|
|
4
4
|
/**
|
|
5
5
|
* TranslationsTitlebar - Titlebar content for the Translation Management workspace.
|
|
@@ -12,5 +12,5 @@ export function TranslationsTitlebar() {
|
|
|
12
12
|
return null;
|
|
13
13
|
const showSubtitle = !editContext.isMobile;
|
|
14
14
|
const { showAgentsWorkspaceEditor, setShowAgentsWorkspaceEditor } = editContext;
|
|
15
|
-
return (_jsxs("div", { className: cn("flex w-full flex-row items-center gap-3 pl-2", editContext.isMobile && "border-b px-1.5 py-1"), children: [_jsxs("div", { className: "flex min-w-0 flex-1 flex-col items-start justify-center leading-tight", "data-testid": "translations-titlebar-identity", children: [_jsx("span", { className: "truncate text-sm font-medium leading-tight text-
|
|
15
|
+
return (_jsxs("div", { className: cn("flex w-full flex-row items-center gap-3 pl-2", editContext.isMobile && "border-b px-1.5 py-1"), children: [_jsxs("div", { className: "flex min-w-0 flex-1 flex-col items-start justify-center leading-tight", "data-testid": "translations-titlebar-identity", children: [_jsx("span", { className: "truncate text-sm font-medium leading-tight text-neutral-grey-100", children: "Translation Management" }), showSubtitle && (_jsx("span", { className: "truncate text-[11px] leading-tight text-neutral-grey-50", children: "Track and manage content translations" }))] }), !editContext.isMobile && (_jsx("div", { className: "flex shrink-0 items-center gap-2", children: _jsx(SimpleIconButton, { icon: _jsx(SquarePen, { className: "h-5 w-5", strokeWidth: 1 }), label: showAgentsWorkspaceEditor ? "Hide Editor" : "Show Editor", size: "large", "data-testid": "translations-editor-panel-toggle", selected: showAgentsWorkspaceEditor, onClick: () => setShowAgentsWorkspaceEditor(!showAgentsWorkspaceEditor) }) }))] }));
|
|
16
16
|
}
|
package/package.json
CHANGED
package/dist/constants.d.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
export declare const DISCOVERY_CONFIRMATION_THRESHOLD = 100;
|
|
2
|
-
export declare const EXCLUDED_TEMPLATE_IDS: string[];
|
|
3
|
-
export declare const DIALOG_DIMENSIONS: {
|
|
4
|
-
width: string;
|
|
5
|
-
height: string;
|
|
6
|
-
};
|
|
7
|
-
export declare const STEP_STATES: {
|
|
8
|
-
readonly COMPLETED: "completed";
|
|
9
|
-
readonly CURRENT: "current";
|
|
10
|
-
readonly PENDING: "pending";
|
|
11
|
-
};
|
|
12
|
-
export declare const STORAGE_KEYS: {
|
|
13
|
-
readonly TRANSLATION_PROVIDER: "editor.translationProvider";
|
|
14
|
-
};
|
|
15
|
-
//# sourceMappingURL=constants.d.ts.map
|
package/dist/constants.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,gCAAgC,MAAM,CAAC;AAGpD,eAAO,MAAM,qBAAqB,UAEjC,CAAC;AAGF,eAAO,MAAM,iBAAiB;;;CAG7B,CAAC;AAGF,eAAO,MAAM,WAAW;;;;CAId,CAAC;AAGX,eAAO,MAAM,YAAY;;CAEf,CAAC"}
|
package/dist/constants.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
// Discovery configuration
|
|
2
|
-
export const DISCOVERY_CONFIRMATION_THRESHOLD = 100; // Pause every N subitems
|
|
3
|
-
// Template IDs to exclude from translation
|
|
4
|
-
export const EXCLUDED_TEMPLATE_IDS = [
|
|
5
|
-
"de8bfdac-5f9f-40c3-a680-2fce9997ae28" // System template ID
|
|
6
|
-
];
|
|
7
|
-
// Dialog dimensions
|
|
8
|
-
export const DIALOG_DIMENSIONS = {
|
|
9
|
-
width: "75vw",
|
|
10
|
-
height: "75vh"
|
|
11
|
-
};
|
|
12
|
-
// Step progress indicators
|
|
13
|
-
export const STEP_STATES = {
|
|
14
|
-
COMPLETED: "completed",
|
|
15
|
-
CURRENT: "current",
|
|
16
|
-
PENDING: "pending"
|
|
17
|
-
};
|
|
18
|
-
// Local storage keys
|
|
19
|
-
export const STORAGE_KEYS = {
|
|
20
|
-
TRANSLATION_PROVIDER: "editor.translationProvider"
|
|
21
|
-
};
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import { TranslationStepProps } from "./types";
|
|
2
|
-
/** Example Step for metadata input testing */
|
|
3
|
-
export declare function MetadataInputStep({ stepIndex, isActive, data, setData, onStepCompleted, }: TranslationStepProps): import("react/jsx-runtime").JSX.Element;
|
|
4
|
-
//# sourceMappingURL=MetadataInputStep.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"MetadataInputStep.d.ts","sourceRoot":"","sources":["../../src/steps/MetadataInputStep.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAE/C,8CAA8C;AAC9C,wBAAgB,iBAAiB,CAAC,EAChC,SAAS,EACT,QAAe,EACf,IAAI,EACJ,OAAO,EACP,eAAe,GAChB,EAAE,oBAAoB,2CAsFtB"}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useState, useEffect } from "react";
|
|
3
|
-
/** Example Step for metadata input testing */
|
|
4
|
-
export function MetadataInputStep({ stepIndex, isActive = true, data, setData, onStepCompleted, }) {
|
|
5
|
-
// Convert Map<string, Map<string, string>> to a flat object for local state management
|
|
6
|
-
const [itemMetadata, setItemMetadata] = useState(() => {
|
|
7
|
-
const result = {};
|
|
8
|
-
data.itemMetadata.forEach((languageMap, itemId) => {
|
|
9
|
-
result[itemId] = Object.fromEntries(languageMap);
|
|
10
|
-
});
|
|
11
|
-
return result;
|
|
12
|
-
});
|
|
13
|
-
// Prefer the user's tree selection (per-item subitem flags) when present,
|
|
14
|
-
// otherwise the legacy expanded list, otherwise the initial wizard items.
|
|
15
|
-
const allItems = (data.selectionTreeItems && data.selectionTreeItems.length > 0
|
|
16
|
-
? data.selectionTreeItems.map((entry) => entry.descriptor)
|
|
17
|
-
: null) ??
|
|
18
|
-
(data.discoveredItems && data.discoveredItems.length > 0
|
|
19
|
-
? data.discoveredItems
|
|
20
|
-
: data.items);
|
|
21
|
-
const handleMetadataChange = (itemId, language, metadata) => {
|
|
22
|
-
const updated = {
|
|
23
|
-
...itemMetadata,
|
|
24
|
-
[itemId]: {
|
|
25
|
-
...(itemMetadata[itemId] || {}),
|
|
26
|
-
[language]: metadata
|
|
27
|
-
}
|
|
28
|
-
};
|
|
29
|
-
setItemMetadata(updated);
|
|
30
|
-
// Convert back to Map structure for wizard data
|
|
31
|
-
const metadataMap = new Map();
|
|
32
|
-
Object.entries(updated).forEach(([itemId, languageMap]) => {
|
|
33
|
-
metadataMap.set(itemId, new Map(Object.entries(languageMap)));
|
|
34
|
-
});
|
|
35
|
-
setData({ ...data, itemMetadata: metadataMap });
|
|
36
|
-
console.log('Updated itemMetadata:', metadataMap);
|
|
37
|
-
};
|
|
38
|
-
// Data is saved automatically on change
|
|
39
|
-
useEffect(() => {
|
|
40
|
-
// Only update completion when this step is active
|
|
41
|
-
if (!isActive)
|
|
42
|
-
return;
|
|
43
|
-
// Mark step as completed since metadata is optional
|
|
44
|
-
onStepCompleted(true);
|
|
45
|
-
}, [isActive, onStepCompleted]); // Check when active state changes
|
|
46
|
-
// No footer actions needed since data is saved automatically
|
|
47
|
-
return (_jsxs("div", { className: "flex flex-col gap-4 p-6", "data-testid": "metadata-input-step", children: [_jsxs("div", { children: [_jsx("h3", { className: "text-xl font-semibold text-[var(--color-dark)] mb-2", children: "Enter Metadata Per Item Per Language" }), _jsx("p", { className: "text-sm text-[var(--color-gray-2)]", children: "Provide custom metadata for each item and language combination (optional)." })] }), _jsx("div", { className: "max-h-64 overflow-y-auto space-y-4", "data-testid": "metadata-input-container", children: allItems.map((item) => (_jsxs("div", { className: "border border-[var(--color-gray-3)] rounded-lg p-4 bg-background shadow-sm", "data-testid": `metadata-item-${item.id}`, children: [_jsx("label", { className: "block text-sm font-medium text-[var(--color-dark)] mb-3", "data-testid": `metadata-item-label-${item.id}`, children: item.name || item.id }), data.targetLanguages?.map((language) => (_jsxs("div", { className: "mb-3", "data-testid": `metadata-field-${item.id}-${language}`, children: [_jsxs("label", { className: "block text-xs font-medium mb-1.5 text-[var(--color-gray-2)]", "data-testid": `metadata-language-label-${item.id}-${language}`, children: [language.toUpperCase(), ":"] }), _jsx("textarea", { className: "w-full border border-[var(--color-gray-3)] rounded-md p-2.5 text-sm bg-[var(--color-gray-5)] text-[var(--color-dark)] focus:outline-none focus:ring-2 focus:ring-[#9650fb] focus:border-[#9650fb] transition-colors", rows: 2, value: itemMetadata[item.id]?.[language] || "", onChange: (e) => handleMetadataChange(item.id, language, e.target.value), placeholder: `Enter metadata for ${language}...`, "data-testid": `metadata-textarea-${item.id}-${language}` })] }, `${item.id}-${language}`)))] }, item.id))) })] }));
|
|
48
|
-
}
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import { TranslationStepProps } from "./types";
|
|
2
|
-
export declare function SubitemDiscoveryStep({ stepIndex, isActive, data, setData, editContext, onStepCompleted, setBeforeNextCallback, setFooterActions, requestClose }: TranslationStepProps): import("react/jsx-runtime").JSX.Element;
|
|
3
|
-
//# sourceMappingURL=SubitemDiscoveryStep.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
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,2CAga5L"}
|
|
@@ -1,313 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect, useState, useRef, useMemo, useCallback } from "react";
|
|
3
|
-
import { Button, PerfectTree } from "@parhelia/core";
|
|
4
|
-
import { convertFullItemToStub, convertStubToFullItem } from "@parhelia/core";
|
|
5
|
-
import { discoverItemsTree, convertBackendTreeToTreeNodes, flattenSelectableItemsFromBackendTrees } from "../api/discovery";
|
|
6
|
-
// We need to implement a basic Spinner component since it's not in core
|
|
7
|
-
const Spinner = ({ ...props }) => (_jsx("div", { className: "animate-spin rounded-full h-4 w-4 border-b-2 border-[#9650fb]", ...props }));
|
|
8
|
-
export function SubitemDiscoveryStep({ stepIndex, isActive = true, data, setData, editContext, onStepCompleted, setBeforeNextCallback, setFooterActions, requestClose }) {
|
|
9
|
-
// Core state - simplified
|
|
10
|
-
const [isDiscovering, setIsDiscovering] = useState(false);
|
|
11
|
-
const [discoveryComplete, setDiscoveryComplete] = useState(false);
|
|
12
|
-
const [selectedItemIds, setSelectedItemIds] = useState(new Set());
|
|
13
|
-
const [treeNodes, setTreeNodes] = useState([]);
|
|
14
|
-
const [allDiscoveredItems, setAllDiscoveredItems] = useState([]);
|
|
15
|
-
const [userHasInteracted, setUserHasInteracted] = useState(false);
|
|
16
|
-
const [discoveredCount, setDiscoveredCount] = useState(0);
|
|
17
|
-
const [totalItemsCount, setTotalItemsCount] = useState(0);
|
|
18
|
-
const [treeInitialized, setTreeInitialized] = useState(false);
|
|
19
|
-
const [expandedIds, setExpandedIds] = useState(new Set());
|
|
20
|
-
// Refs for async safety
|
|
21
|
-
const isMountedRef = useRef(true);
|
|
22
|
-
const inFlightRef = useRef(false);
|
|
23
|
-
const shiftToggleRef = useRef(false);
|
|
24
|
-
// Cleanup
|
|
25
|
-
useEffect(() => {
|
|
26
|
-
isMountedRef.current = true;
|
|
27
|
-
return () => { isMountedRef.current = false; };
|
|
28
|
-
}, []);
|
|
29
|
-
// Commit callback - simplified
|
|
30
|
-
useEffect(() => {
|
|
31
|
-
const commit = async () => {
|
|
32
|
-
const selectedItems = allDiscoveredItems.filter(item => selectedItemIds.has(item.id));
|
|
33
|
-
const convertedItems = selectedItems.map(convertStubToFullItem);
|
|
34
|
-
setData({ ...data, discoveredItems: convertedItems });
|
|
35
|
-
return true;
|
|
36
|
-
};
|
|
37
|
-
setBeforeNextCallback?.(commit);
|
|
38
|
-
}, [setBeforeNextCallback, allDiscoveredItems, selectedItemIds, setData, data]);
|
|
39
|
-
// Initialize discovery or simple display
|
|
40
|
-
useEffect(() => {
|
|
41
|
-
if (!data.includeSubitems) {
|
|
42
|
-
// Simple mode: just show base items
|
|
43
|
-
const stubs = data.items.map(convertFullItemToStub);
|
|
44
|
-
setAllDiscoveredItems(stubs);
|
|
45
|
-
setDiscoveredCount(stubs.length);
|
|
46
|
-
const nodes = buildTreeNodes(stubs);
|
|
47
|
-
setTreeNodes(nodes);
|
|
48
|
-
setExpandedIds(new Set(nodes.map(n => n.key)));
|
|
49
|
-
const countItems = (nodeList) => {
|
|
50
|
-
let total = 0;
|
|
51
|
-
const walk = (nodeList) => {
|
|
52
|
-
nodeList.forEach(node => {
|
|
53
|
-
total++;
|
|
54
|
-
if (node.children)
|
|
55
|
-
walk(node.children);
|
|
56
|
-
});
|
|
57
|
-
};
|
|
58
|
-
walk(nodeList);
|
|
59
|
-
return total;
|
|
60
|
-
};
|
|
61
|
-
setTotalItemsCount(countItems(nodes));
|
|
62
|
-
setDiscoveryComplete(true);
|
|
63
|
-
setTreeInitialized(true);
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
// Discovery mode: fetch tree from backend
|
|
67
|
-
if (inFlightRef.current)
|
|
68
|
-
return;
|
|
69
|
-
inFlightRef.current = true;
|
|
70
|
-
const runDiscovery = async () => {
|
|
71
|
-
setIsDiscovering(true);
|
|
72
|
-
try {
|
|
73
|
-
const rootIds = data.items.map(i => i.descriptor.id);
|
|
74
|
-
const resp = await discoverItemsTree({
|
|
75
|
-
rootItemIds: rootIds,
|
|
76
|
-
language: editContext?.item?.language ??
|
|
77
|
-
editContext?.currentItemDescriptor?.language ??
|
|
78
|
-
"en",
|
|
79
|
-
}, editContext.sessionId ?? undefined);
|
|
80
|
-
if (!isMountedRef.current)
|
|
81
|
-
return;
|
|
82
|
-
const items = flattenSelectableItemsFromBackendTrees(resp.trees);
|
|
83
|
-
const language = editContext?.item?.language ??
|
|
84
|
-
editContext?.currentItemDescriptor?.language ??
|
|
85
|
-
"en";
|
|
86
|
-
const stubs = items.map(x => ({
|
|
87
|
-
id: x.id,
|
|
88
|
-
name: x.name,
|
|
89
|
-
path: x.path,
|
|
90
|
-
parentId: "",
|
|
91
|
-
idPath: "",
|
|
92
|
-
database: "master",
|
|
93
|
-
descriptor: { id: x.id, language, version: 0 },
|
|
94
|
-
icon: "",
|
|
95
|
-
largeIcon: "",
|
|
96
|
-
templateId: "",
|
|
97
|
-
templateName: "",
|
|
98
|
-
hasLayout: false,
|
|
99
|
-
hasChildren: x.hasChildren,
|
|
100
|
-
versions: 0,
|
|
101
|
-
language,
|
|
102
|
-
version: 0,
|
|
103
|
-
}));
|
|
104
|
-
setAllDiscoveredItems(stubs);
|
|
105
|
-
setDiscoveredCount(stubs.length);
|
|
106
|
-
const nodes = convertBackendTreeToTreeNodes(resp.trees);
|
|
107
|
-
setTreeNodes(nodes);
|
|
108
|
-
setExpandedIds(new Set(nodes.map(n => n.key)));
|
|
109
|
-
const countItems = (nodeList) => {
|
|
110
|
-
let total = 0;
|
|
111
|
-
const walk = (nodeList) => {
|
|
112
|
-
nodeList.forEach(node => {
|
|
113
|
-
total++;
|
|
114
|
-
if (node.children)
|
|
115
|
-
walk(node.children);
|
|
116
|
-
});
|
|
117
|
-
};
|
|
118
|
-
walk(nodeList);
|
|
119
|
-
return total;
|
|
120
|
-
};
|
|
121
|
-
setTotalItemsCount(countItems(nodes));
|
|
122
|
-
setDiscoveryComplete(true);
|
|
123
|
-
setTreeInitialized(true);
|
|
124
|
-
}
|
|
125
|
-
catch (error) {
|
|
126
|
-
console.error("Discovery error:", error);
|
|
127
|
-
}
|
|
128
|
-
finally {
|
|
129
|
-
if (isMountedRef.current)
|
|
130
|
-
setIsDiscovering(false);
|
|
131
|
-
inFlightRef.current = false;
|
|
132
|
-
}
|
|
133
|
-
};
|
|
134
|
-
runDiscovery();
|
|
135
|
-
}, [data.items, data.includeSubitems, editContext]);
|
|
136
|
-
// Set initial selection when tree is ready
|
|
137
|
-
useEffect(() => {
|
|
138
|
-
if (!isActive || !discoveryComplete || treeNodes.length === 0 || userHasInteracted)
|
|
139
|
-
return;
|
|
140
|
-
let initialSelection;
|
|
141
|
-
if (data.discoveredItems?.length > 0) {
|
|
142
|
-
// Restore previous selection
|
|
143
|
-
initialSelection = new Set(data.discoveredItems.map(item => item.descriptor.id));
|
|
144
|
-
}
|
|
145
|
-
else {
|
|
146
|
-
// Default: select all selectable items in the tree
|
|
147
|
-
const allSelectableIds = new Set();
|
|
148
|
-
const walk = (nodes) => {
|
|
149
|
-
nodes.forEach(node => {
|
|
150
|
-
if (node?.data?.isFolder !== true) {
|
|
151
|
-
allSelectableIds.add(node.key);
|
|
152
|
-
}
|
|
153
|
-
if (node.children)
|
|
154
|
-
walk(node.children);
|
|
155
|
-
});
|
|
156
|
-
};
|
|
157
|
-
walk(treeNodes);
|
|
158
|
-
initialSelection = allSelectableIds;
|
|
159
|
-
}
|
|
160
|
-
setSelectedItemIds(initialSelection);
|
|
161
|
-
}, [isActive, discoveryComplete, treeNodes, data.discoveredItems, userHasInteracted]);
|
|
162
|
-
// Update completion status
|
|
163
|
-
useEffect(() => {
|
|
164
|
-
if (isActive && discoveryComplete) {
|
|
165
|
-
onStepCompleted(selectedItemIds.size > 0);
|
|
166
|
-
}
|
|
167
|
-
}, [isActive, discoveryComplete, selectedItemIds.size, onStepCompleted]);
|
|
168
|
-
const buildTreeNodes = useCallback((items) => {
|
|
169
|
-
// Fallback: Build simple tree from items for non-subitem discovery
|
|
170
|
-
const itemMap = new Map();
|
|
171
|
-
const childrenMap = new Map();
|
|
172
|
-
items.forEach(item => {
|
|
173
|
-
itemMap.set(item.id, item);
|
|
174
|
-
if (item.parentId) {
|
|
175
|
-
if (!childrenMap.has(item.parentId))
|
|
176
|
-
childrenMap.set(item.parentId, []);
|
|
177
|
-
childrenMap.get(item.parentId).push(item);
|
|
178
|
-
}
|
|
179
|
-
});
|
|
180
|
-
const buildNode = (item) => ({
|
|
181
|
-
key: item.id,
|
|
182
|
-
label: item.name || item.id,
|
|
183
|
-
data: { id: item.id, name: item.name, path: item.path, isFolder: item.hasLayout !== true, hasChildren: item.hasChildren },
|
|
184
|
-
children: (childrenMap.get(item.id) || []).map(buildNode)
|
|
185
|
-
});
|
|
186
|
-
const originalItemIds = new Set(data.items.map(item => item.descriptor.id));
|
|
187
|
-
const rootItems = items.filter(item => !item.parentId || !itemMap.has(item.parentId) || originalItemIds.has(item.id));
|
|
188
|
-
return rootItems.map(buildNode);
|
|
189
|
-
}, [data.items]);
|
|
190
|
-
// PerfectTree integrations
|
|
191
|
-
const expandedKeys = useMemo(() => Array.from(expandedIds), [expandedIds]);
|
|
192
|
-
const selectedKeys = useMemo(() => Array.from(selectedItemIds), [selectedItemIds]);
|
|
193
|
-
const getDescendantIds = (nodeKey) => {
|
|
194
|
-
const findNode = (nodes) => {
|
|
195
|
-
for (const node of nodes) {
|
|
196
|
-
if (node.key === nodeKey)
|
|
197
|
-
return node;
|
|
198
|
-
if (node.children) {
|
|
199
|
-
const found = findNode(node.children);
|
|
200
|
-
if (found)
|
|
201
|
-
return found;
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
return null;
|
|
205
|
-
};
|
|
206
|
-
const node = findNode(treeNodes);
|
|
207
|
-
if (!node?.children)
|
|
208
|
-
return [];
|
|
209
|
-
const descendants = [];
|
|
210
|
-
const traverse = (children) => {
|
|
211
|
-
children.forEach(child => {
|
|
212
|
-
descendants.push(child.key);
|
|
213
|
-
if (child.children)
|
|
214
|
-
traverse(child.children);
|
|
215
|
-
});
|
|
216
|
-
};
|
|
217
|
-
traverse(node.children);
|
|
218
|
-
return descendants;
|
|
219
|
-
};
|
|
220
|
-
const handleCancel = () => {
|
|
221
|
-
// Simplified cancel - just stop discovery
|
|
222
|
-
inFlightRef.current = false;
|
|
223
|
-
setIsDiscovering(false);
|
|
224
|
-
setDiscoveryComplete(true);
|
|
225
|
-
};
|
|
226
|
-
const showDiscoveryStatus = isDiscovering || !discoveryComplete;
|
|
227
|
-
return (_jsx("div", { className: "flex h-full min-h-0 flex-col gap-4 p-6", "data-testid": "subitem-discovery-step", children: _jsxs("div", { className: "flex min-h-0 w-full min-w-0 flex-1 flex-col rounded-lg border border-[var(--color-gray-3)] bg-background p-4 shadow-sm", "data-testid": "discovery-status-container", children: [showDiscoveryStatus && (_jsxs(_Fragment, { children: [_jsxs("div", { className: "mb-4 flex items-center justify-between", 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...' : 'Ready to discover' })] }), isDiscovering && (_jsx(Button, { size: "sm", variant: "outline", onClick: handleCancel, "data-testid": "discovery-cancel-button", children: "Cancel" }))] }), _jsx("div", { className: "mb-3 text-sm text-[var(--color-gray-2)]", "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: showDiscoveryStatus ? "mt-4 flex min-h-0 flex-1 flex-col" : "flex min-h-0 flex-1 flex-col", children: !isDiscovering && discoveryComplete && treeInitialized && allDiscoveredItems.length > 0 && treeNodes.length > 0 ? (_jsxs("div", { className: "flex min-h-0 w-full min-w-0 flex-1 flex-col", "data-testid": "item-selection-section", children: [_jsxs("div", { className: showDiscoveryStatus ? "mb-3 flex flex-col gap-2 border-t border-[var(--color-gray-3)] pt-4" : "mb-3 flex flex-col gap-2", 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
|
-
if (!isActive)
|
|
229
|
-
return;
|
|
230
|
-
const allIds = new Set();
|
|
231
|
-
const walk = (nodes) => {
|
|
232
|
-
nodes.forEach(node => {
|
|
233
|
-
allIds.add(node.key);
|
|
234
|
-
if (node.children)
|
|
235
|
-
walk(node.children);
|
|
236
|
-
});
|
|
237
|
-
};
|
|
238
|
-
walk(treeNodes);
|
|
239
|
-
setUserHasInteracted(true);
|
|
240
|
-
setSelectedItemIds(allIds);
|
|
241
|
-
onStepCompleted(allIds.size > 0);
|
|
242
|
-
}, "data-testid": "select-all-items-button", children: "Select All" }), _jsx(Button, { size: "sm", variant: "ghost", onClick: () => {
|
|
243
|
-
if (!isActive)
|
|
244
|
-
return;
|
|
245
|
-
setUserHasInteracted(true);
|
|
246
|
-
setSelectedItemIds(new Set());
|
|
247
|
-
onStepCompleted(false);
|
|
248
|
-
}, "data-testid": "select-none-items-button", children: "Select None" })] })] }), _jsx("div", { className: "text-xs text-[var(--color-gray-2)] mb-3", "data-testid": "selection-summary", children: _jsx("span", { children: "Tip: Hold Shift and click a checkbox to toggle all descendants." }) }), treeNodes.length > 0 && (_jsx("div", { className: "min-h-0 w-full min-w-0 flex-1 overflow-auto rounded-lg border border-[var(--color-gray-3)] bg-[var(--color-gray-5)]", "data-testid": "item-tree-view", children: _jsx(PerfectTree, { nodes: treeNodes, expandedKeys: expandedKeys, selectedKeys: selectedKeys, onToggleExpand: (key) => {
|
|
249
|
-
setExpandedIds(prev => {
|
|
250
|
-
const next = new Set(prev);
|
|
251
|
-
if (next.has(key))
|
|
252
|
-
next.delete(key);
|
|
253
|
-
else
|
|
254
|
-
next.add(key);
|
|
255
|
-
return next;
|
|
256
|
-
});
|
|
257
|
-
}, onSelect: (key, event) => {
|
|
258
|
-
if (!isActive)
|
|
259
|
-
return; // Don't handle selection when inactive
|
|
260
|
-
setUserHasInteracted(true);
|
|
261
|
-
const targetNode = key;
|
|
262
|
-
const shift = event?.shiftKey === true;
|
|
263
|
-
const next = new Set(selectedItemIds);
|
|
264
|
-
const findNode = (nodes) => {
|
|
265
|
-
for (const n of nodes) {
|
|
266
|
-
if (n.key === targetNode)
|
|
267
|
-
return n;
|
|
268
|
-
if (n.children) {
|
|
269
|
-
const f = findNode(n.children);
|
|
270
|
-
if (f)
|
|
271
|
-
return f;
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
return null;
|
|
275
|
-
};
|
|
276
|
-
const n = findNode(treeNodes);
|
|
277
|
-
if (!n)
|
|
278
|
-
return;
|
|
279
|
-
const ids = shift ? [key, ...getDescendantIds(key)] : [key];
|
|
280
|
-
if (!next.has(key))
|
|
281
|
-
ids.forEach((id) => next.add(id));
|
|
282
|
-
else
|
|
283
|
-
ids.forEach((id) => next.delete(id));
|
|
284
|
-
setSelectedItemIds(next);
|
|
285
|
-
// Update completion when user changes selection
|
|
286
|
-
onStepCompleted(next.size > 0);
|
|
287
|
-
}, renderNode: (node) => {
|
|
288
|
-
const isChecked = selectedItemIds.has(node.key);
|
|
289
|
-
const icon = node?.data?.icon;
|
|
290
|
-
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) => {
|
|
291
|
-
shiftToggleRef.current = e.shiftKey;
|
|
292
|
-
}, onChange: (e) => {
|
|
293
|
-
if (!isActive)
|
|
294
|
-
return;
|
|
295
|
-
setUserHasInteracted(true);
|
|
296
|
-
const next = new Set(selectedItemIds);
|
|
297
|
-
const withDesc = shiftToggleRef.current && (node.children?.length ?? 0) > 0;
|
|
298
|
-
const ids = withDesc ? [node.key, ...getDescendantIds(node.key)] : [node.key];
|
|
299
|
-
if (e.currentTarget.checked)
|
|
300
|
-
ids.forEach((id) => next.add(id));
|
|
301
|
-
else
|
|
302
|
-
ids.forEach((id) => next.delete(id));
|
|
303
|
-
setSelectedItemIds(next);
|
|
304
|
-
shiftToggleRef.current = false;
|
|
305
|
-
// Update completion when user changes selection
|
|
306
|
-
onStepCompleted(next.size > 0);
|
|
307
|
-
} }), _jsx("span", { children: node.label })] }));
|
|
308
|
-
} }) }))] })) : isDiscovering ? (
|
|
309
|
-
// Loading skeleton for discovery results
|
|
310
|
-
_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: "flex min-h-0 flex-1 flex-col 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: "min-h-0 flex-1 overflow-auto rounded-lg border border-[var(--color-gray-3)] 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))) }) })] })] })) : (
|
|
311
|
-
// Empty state
|
|
312
|
-
_jsx("div", { className: "flex h-80 shrink-0 items-center justify-center overflow-auto rounded-lg border border-[var(--color-gray-3)] bg-[var(--color-gray-5)]", children: _jsxs("div", { className: "text-center text-[var(--color-gray-2)]", children: [_jsx("p", { className: "font-medium text-[var(--color-gray-1)]", children: "Ready to discover subitems" }), _jsx("p", { className: "text-sm mt-1", children: "Discovery will start automatically" })] }) })) })] }) }));
|
|
313
|
-
}
|
package/dist/steps/index.d.ts
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
export { ServiceLanguageSelectionStep } from "./ServiceLanguageSelectionStep";
|
|
2
|
-
export { ItemSelectionStep } from "./ItemSelectionStep";
|
|
3
|
-
export { SubitemDiscoveryStep } from "./SubitemDiscoveryStep";
|
|
4
|
-
export { MetadataInputStep } from "./MetadataInputStep";
|
|
5
|
-
export * from "./types";
|
|
6
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/steps/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,4BAA4B,EAAE,MAAM,gCAAgC,CAAC;AAC9E,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,cAAc,SAAS,CAAC"}
|
package/dist/steps/index.js
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
export { ServiceLanguageSelectionStep } from "./ServiceLanguageSelectionStep";
|
|
2
|
-
export { ItemSelectionStep } from "./ItemSelectionStep";
|
|
3
|
-
export { SubitemDiscoveryStep } from "./SubitemDiscoveryStep";
|
|
4
|
-
export { MetadataInputStep } from "./MetadataInputStep";
|
|
5
|
-
export * from "./types";
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { EditContextType } from "@parhelia/core";
|
|
2
|
-
import { TranslationWizardData, TranslationDialogResult } from "../steps/types";
|
|
3
|
-
export type ItemVersionDescriptor = {
|
|
4
|
-
id: string;
|
|
5
|
-
version?: number;
|
|
6
|
-
};
|
|
7
|
-
export declare function createVersionsOnlyAndClose(params: {
|
|
8
|
-
items: ItemVersionDescriptor[];
|
|
9
|
-
targetLanguages: string[];
|
|
10
|
-
editContext: EditContextType;
|
|
11
|
-
data: TranslationWizardData;
|
|
12
|
-
requestClose: (result: TranslationDialogResult | null) => void;
|
|
13
|
-
}): Promise<void>;
|
|
14
|
-
//# sourceMappingURL=createVersions.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"createVersions.d.ts","sourceRoot":"","sources":["../../src/utils/createVersions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,qBAAqB,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AAGhF,MAAM,MAAM,qBAAqB,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAErE,wBAAsB,0BAA0B,CAC9C,MAAM,EAAE;IACN,KAAK,EAAE,qBAAqB,EAAE,CAAC;IAC/B,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,WAAW,EAAE,eAAe,CAAC;IAC7B,IAAI,EAAE,qBAAqB,CAAC;IAC5B,YAAY,EAAE,CAAC,MAAM,EAAE,uBAAuB,GAAG,IAAI,KAAK,IAAI,CAAC;CAChE,GACA,OAAO,CAAC,IAAI,CAAC,CAyBf"}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { createVersion as createVersionEdit, createVersionsBatch as createVersionsBatchEdit } from "@parhelia/core";
|
|
2
|
-
export async function createVersionsOnlyAndClose(params) {
|
|
3
|
-
const { items, targetLanguages, editContext, data, requestClose } = params;
|
|
4
|
-
try {
|
|
5
|
-
if (items.length === 1 && targetLanguages.length === 1) {
|
|
6
|
-
const item = items[0];
|
|
7
|
-
await createVersionEdit({ id: item.id, language: targetLanguages[0], version: item.version || 0 }, editContext.sessionId);
|
|
8
|
-
}
|
|
9
|
-
else {
|
|
10
|
-
const descriptors = items.flatMap(it => targetLanguages.map(lang => ({ id: it.id, language: lang, version: it.version || 0 })));
|
|
11
|
-
await createVersionsBatchEdit(descriptors, editContext.sessionId);
|
|
12
|
-
}
|
|
13
|
-
editContext?.showToast?.("Versions created");
|
|
14
|
-
const result = {
|
|
15
|
-
translationProvider: data.translationProvider,
|
|
16
|
-
targetLanguages: data.targetLanguages,
|
|
17
|
-
includeSubitems: data.includeSubitems,
|
|
18
|
-
discoveredItems: data.discoveredItems,
|
|
19
|
-
};
|
|
20
|
-
requestClose(result);
|
|
21
|
-
}
|
|
22
|
-
catch (e) {
|
|
23
|
-
console.error("Create versions failed", e);
|
|
24
|
-
editContext?.showToast?.("Failed to create versions");
|
|
25
|
-
}
|
|
26
|
-
}
|