@parhelia/localization 0.1.12902 → 0.1.12904
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 +2 -4
- package/dist/LocalizeItemDialog.d.ts.map +1 -1
- package/dist/LocalizeItemDialog.js +35 -97
- package/dist/LocalizeItemUtils.d.ts +2 -1
- package/dist/LocalizeItemUtils.d.ts.map +1 -1
- package/dist/LocalizeItemUtils.js +36 -78
- package/dist/api/discovery.d.ts +0 -25
- package/dist/api/discovery.d.ts.map +1 -1
- package/dist/api/discovery.js +2 -106
- package/dist/constants.d.ts +15 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +21 -0
- package/dist/hooks/useTranslationWizard.d.ts.map +1 -1
- package/dist/hooks/useTranslationWizard.js +3 -3
- package/dist/index.d.ts +11 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +32 -36
- package/dist/services/translationService.d.ts +10 -41
- package/dist/services/translationService.d.ts.map +1 -1
- package/dist/services/translationService.js +6 -48
- package/dist/settings/TranslationServicesPanel.d.ts.map +1 -1
- package/dist/settings/TranslationServicesPanel.js +36 -21
- package/dist/setup/LocalizationSetupStep.d.ts.map +1 -1
- package/dist/setup/LocalizationSetupStep.js +18 -29
- package/dist/sidebar/TranslationSidebar.d.ts.map +1 -1
- package/dist/sidebar/TranslationSidebar.js +10 -20
- package/dist/steps/MetadataInputStep.d.ts +4 -0
- package/dist/steps/MetadataInputStep.d.ts.map +1 -0
- package/dist/steps/MetadataInputStep.js +41 -0
- package/dist/steps/PromptCustomizationStep.d.ts +1 -1
- package/dist/steps/PromptCustomizationStep.d.ts.map +1 -1
- package/dist/steps/PromptCustomizationStep.js +56 -159
- package/dist/steps/ServiceLanguageSelectionStep.d.ts +1 -6
- package/dist/steps/ServiceLanguageSelectionStep.d.ts.map +1 -1
- package/dist/steps/ServiceLanguageSelectionStep.js +163 -56
- package/dist/steps/SubitemDiscoveryStep.d.ts +3 -0
- package/dist/steps/SubitemDiscoveryStep.d.ts.map +1 -0
- package/dist/steps/SubitemDiscoveryStep.js +313 -0
- package/dist/steps/index.d.ts +5 -0
- package/dist/steps/index.d.ts.map +1 -0
- package/dist/steps/index.js +4 -0
- package/dist/steps/types.d.ts +1 -17
- package/dist/steps/types.d.ts.map +1 -1
- package/dist/translation-center/BatchTranslationView.d.ts +8 -0
- package/dist/translation-center/BatchTranslationView.d.ts.map +1 -0
- package/dist/translation-center/BatchTranslationView.js +870 -0
- package/dist/translation-center/RecentTranslations.d.ts +2 -0
- package/dist/translation-center/RecentTranslations.d.ts.map +1 -0
- package/dist/translation-center/RecentTranslations.js +309 -0
- package/dist/translation-center/TranslationManagement.d.ts.map +1 -1
- package/dist/translation-center/TranslationManagement.js +15 -25
- package/dist/types.d.ts +0 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/createVersions.d.ts +14 -0
- package/dist/utils/createVersions.d.ts.map +1 -0
- package/dist/utils/createVersions.js +26 -0
- package/package.json +1 -1
- package/dist/steps/ItemSelectionStep.d.ts +0 -3
- package/dist/steps/ItemSelectionStep.d.ts.map +0 -1
- package/dist/steps/ItemSelectionStep.js +0 -24
- package/dist/steps/ItemSelectionTree.d.ts +0 -13
- package/dist/steps/ItemSelectionTree.d.ts.map +0 -1
- package/dist/steps/ItemSelectionTree.js +0 -327
- package/dist/steps/WizardStepShell.d.ts +0 -17
- package/dist/steps/WizardStepShell.d.ts.map +0 -1
- package/dist/steps/WizardStepShell.js +0 -11
- package/dist/translation-center/TranslationBatches.d.ts +0 -2
- package/dist/translation-center/TranslationBatches.d.ts.map +0 -1
- package/dist/translation-center/TranslationBatches.js +0 -1160
- package/dist/translation-center/TranslationsTitlebar.d.ts +0 -6
- package/dist/translation-center/TranslationsTitlebar.d.ts.map +0 -1
- package/dist/translation-center/TranslationsTitlebar.js +0 -16
|
@@ -0,0 +1,313 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
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,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,cAAc,SAAS,CAAC"}
|
package/dist/steps/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FullItem, ItemDescriptor, EditContextType
|
|
1
|
+
import { FullItem, ItemDescriptor, EditContextType } from "@parhelia/core";
|
|
2
2
|
export type TranslationProviderInfo = {
|
|
3
3
|
name: string;
|
|
4
4
|
displayName: string;
|
|
@@ -13,7 +13,6 @@ export type TranslationStatus = {
|
|
|
13
13
|
hash?: string;
|
|
14
14
|
message?: string;
|
|
15
15
|
batchId?: string;
|
|
16
|
-
totalCost?: number | null;
|
|
17
16
|
};
|
|
18
17
|
export type LanguageData = {
|
|
19
18
|
name: string;
|
|
@@ -26,8 +25,6 @@ export type TranslationDialogResult = {
|
|
|
26
25
|
targetLanguages: string[];
|
|
27
26
|
includeSubitems: boolean;
|
|
28
27
|
discoveredItems: FullItem[];
|
|
29
|
-
selectionTreeItems?: ItemWithSubtree[];
|
|
30
|
-
batchName?: string;
|
|
31
28
|
metadata?: any;
|
|
32
29
|
batchId?: string;
|
|
33
30
|
};
|
|
@@ -41,21 +38,8 @@ export type TranslationWizardData = {
|
|
|
41
38
|
items: FullItem[];
|
|
42
39
|
targetLanguages: string[];
|
|
43
40
|
translationProvider: string;
|
|
44
|
-
/** Legacy flag: true when ANY item in selectionTreeItems has includeSubitems on. */
|
|
45
41
|
includeSubitems: boolean;
|
|
46
|
-
/** Flattened list of items to translate (root selections + expanded subtrees). */
|
|
47
42
|
discoveredItems: FullItem[];
|
|
48
|
-
/** User's tree selection with per-item subitem flags. Authoritative for the UI. */
|
|
49
|
-
selectionTreeItems?: ItemWithSubtree[];
|
|
50
|
-
/**
|
|
51
|
-
* Live subitem counts streamed from the backend, keyed by item id.
|
|
52
|
-
* Populated by ItemSelectionTree so later steps (e.g. the Start
|
|
53
|
-
* Translation button) can show a running total with a "+" while
|
|
54
|
-
* streams are still in flight.
|
|
55
|
-
*/
|
|
56
|
-
subitemCounts?: Record<string, SubitemCountState>;
|
|
57
|
-
/** User-editable batch name (AI-suggested initially). */
|
|
58
|
-
batchName?: string;
|
|
59
43
|
languageData: Map<string, LanguageData>;
|
|
60
44
|
translationProviders: TranslationProviderInfo[];
|
|
61
45
|
itemMetadata: Map<string, Map<string, string>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/steps/types.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/steps/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import "react-json-view-lite/dist/index.css";
|
|
2
|
+
interface BatchTranslationViewProps {
|
|
3
|
+
batchId: string;
|
|
4
|
+
onBack?: () => void;
|
|
5
|
+
}
|
|
6
|
+
export declare function BatchTranslationView({ batchId, onBack, }: BatchTranslationViewProps): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=BatchTranslationView.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BatchTranslationView.d.ts","sourceRoot":"","sources":["../../src/translation-center/BatchTranslationView.tsx"],"names":[],"mappings":"AA4CA,OAAO,qCAAqC,CAAC;AA4C7C,UAAU,yBAAyB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;CACrB;AAwED,wBAAgB,oBAAoB,CAAC,EACnC,OAAO,EACP,MAAM,GACP,EAAE,yBAAyB,2CAmoD3B"}
|