@parhelia/localization 0.1.12451 → 0.1.12468
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/api/discovery.d.ts
CHANGED
|
@@ -4,7 +4,6 @@ export type DiscoveredItem = {
|
|
|
4
4
|
path: string;
|
|
5
5
|
parentId?: string | null;
|
|
6
6
|
hasChildren: boolean;
|
|
7
|
-
hasLayout?: boolean;
|
|
8
7
|
};
|
|
9
8
|
export type TreeNode = {
|
|
10
9
|
key: string;
|
|
@@ -16,8 +15,6 @@ export type BackendTreeNode = {
|
|
|
16
15
|
id: string;
|
|
17
16
|
name: string;
|
|
18
17
|
path: string;
|
|
19
|
-
hasLayout: boolean;
|
|
20
|
-
isTranslatable: boolean;
|
|
21
18
|
isFolder: boolean;
|
|
22
19
|
icon?: string;
|
|
23
20
|
children: BackendTreeNode[];
|
|
@@ -33,5 +30,5 @@ export type DiscoverItemsTreeResponse = {
|
|
|
33
30
|
};
|
|
34
31
|
export declare function discoverItemsTree(req: DiscoverItemsTreeRequest, sessionId?: string): Promise<DiscoverItemsTreeResponse>;
|
|
35
32
|
export declare function convertBackendTreeToTreeNodes(trees: BackendTreeNode[]): TreeNode[];
|
|
36
|
-
export declare function
|
|
33
|
+
export declare function flattenSelectableItemsFromBackendTrees(trees: BackendTreeNode[]): DiscoveredItem[];
|
|
37
34
|
//# sourceMappingURL=discovery.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../src/api/discovery.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,cAAc,GAAG;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../src/api/discovery.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,cAAc,GAAG;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,EAAE,OAAO,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,cAAc,CAAC;IAAC,QAAQ,CAAC,EAAE,QAAQ,EAAE,CAAA;CAAE,CAAC;AAInG,MAAM,MAAM,eAAe,GAAG;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,eAAe,EAAE,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG;IACtC,KAAK,EAAE,eAAe,EAAE,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,wBAAwB,EAC7B,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,yBAAyB,CAAC,CAWpC;AAED,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,eAAe,EAAE,GAAG,QAAQ,EAAE,CAQlF;AAED,wBAAgB,sCAAsC,CAAC,KAAK,EAAE,eAAe,EAAE,GAAG,cAAc,EAAE,CAQjG"}
|
package/dist/api/discovery.js
CHANGED
|
@@ -12,16 +12,15 @@ export function convertBackendTreeToTreeNodes(trees) {
|
|
|
12
12
|
const convert = (n) => ({
|
|
13
13
|
key: n.id,
|
|
14
14
|
label: n.name,
|
|
15
|
-
data: { id: n.id, name: n.name, path: n.path,
|
|
15
|
+
data: { id: n.id, name: n.name, path: n.path, isFolder: n.isFolder, icon: n.icon, parentId: undefined, hasChildren: (n.children?.length ?? 0) > 0 },
|
|
16
16
|
children: n.children?.map(convert) || [],
|
|
17
17
|
});
|
|
18
18
|
return trees.map(convert);
|
|
19
19
|
}
|
|
20
|
-
export function
|
|
20
|
+
export function flattenSelectableItemsFromBackendTrees(trees) {
|
|
21
21
|
const out = [];
|
|
22
22
|
const walk = (n) => {
|
|
23
|
-
|
|
24
|
-
out.push({ id: n.id, name: n.name, path: n.path, hasChildren: (n.children?.length ?? 0) > 0, parentId: undefined });
|
|
23
|
+
out.push({ id: n.id, name: n.name, path: n.path, hasChildren: (n.children?.length ?? 0) > 0, parentId: undefined });
|
|
25
24
|
n.children?.forEach(walk);
|
|
26
25
|
};
|
|
27
26
|
trees.forEach(walk);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SubitemDiscoveryStep.d.ts","sourceRoot":"","sources":["../../src/steps/SubitemDiscoveryStep.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAW/C,wBAAgB,oBAAoB,CAAC,EAAE,SAAS,EAAE,QAAe,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,YAAY,EAAE,EAAE,oBAAoB,
|
|
1
|
+
{"version":3,"file":"SubitemDiscoveryStep.d.ts","sourceRoot":"","sources":["../../src/steps/SubitemDiscoveryStep.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAW/C,wBAAgB,oBAAoB,CAAC,EAAE,SAAS,EAAE,QAAe,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,YAAY,EAAE,EAAE,oBAAoB,2CAoa5L"}
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
2
2
|
import { useEffect, useState, useRef, useMemo, useCallback } from "react";
|
|
3
3
|
import { Button, PerfectTree } from "@parhelia/core";
|
|
4
4
|
import { convertFullItemToStub, convertStubToFullItem } from "@parhelia/core";
|
|
5
|
-
import { discoverItemsTree, convertBackendTreeToTreeNodes,
|
|
5
|
+
import { discoverItemsTree, convertBackendTreeToTreeNodes, flattenSelectableItemsFromBackendTrees } from "../api/discovery";
|
|
6
6
|
// We need to implement a basic Spinner component since it's not in core
|
|
7
7
|
const Spinner = ({ ...props }) => (_jsx("div", { className: "animate-spin rounded-full h-4 w-4 border-b-2 border-[#9650fb]", ...props }));
|
|
8
8
|
export function SubitemDiscoveryStep({ stepIndex, isActive = true, data, setData, editContext, onStepCompleted, setBeforeNextCallback, setFooterActions, requestClose }) {
|
|
@@ -15,7 +15,6 @@ export function SubitemDiscoveryStep({ stepIndex, isActive = true, data, setData
|
|
|
15
15
|
const [userHasInteracted, setUserHasInteracted] = useState(false);
|
|
16
16
|
const [discoveredCount, setDiscoveredCount] = useState(0);
|
|
17
17
|
const [totalItemsCount, setTotalItemsCount] = useState(0);
|
|
18
|
-
const [translatableItemsCount, setTranslatableItemsCount] = useState(0);
|
|
19
18
|
const [treeInitialized, setTreeInitialized] = useState(false);
|
|
20
19
|
const [expandedIds, setExpandedIds] = useState(new Set());
|
|
21
20
|
// Refs for async safety
|
|
@@ -47,26 +46,19 @@ export function SubitemDiscoveryStep({ stepIndex, isActive = true, data, setData
|
|
|
47
46
|
const nodes = buildTreeNodes(stubs);
|
|
48
47
|
setTreeNodes(nodes);
|
|
49
48
|
setExpandedIds(new Set(nodes.map(n => n.key)));
|
|
50
|
-
// Count total items and translatable items in the tree
|
|
51
49
|
const countItems = (nodeList) => {
|
|
52
50
|
let total = 0;
|
|
53
|
-
let translatable = 0;
|
|
54
51
|
const walk = (nodeList) => {
|
|
55
52
|
nodeList.forEach(node => {
|
|
56
53
|
total++;
|
|
57
|
-
if (node?.data?.isTranslatable === true) {
|
|
58
|
-
translatable++;
|
|
59
|
-
}
|
|
60
54
|
if (node.children)
|
|
61
55
|
walk(node.children);
|
|
62
56
|
});
|
|
63
57
|
};
|
|
64
58
|
walk(nodeList);
|
|
65
|
-
return
|
|
59
|
+
return total;
|
|
66
60
|
};
|
|
67
|
-
|
|
68
|
-
setTotalItemsCount(counts.total);
|
|
69
|
-
setTranslatableItemsCount(counts.translatable);
|
|
61
|
+
setTotalItemsCount(countItems(nodes));
|
|
70
62
|
setDiscoveryComplete(true);
|
|
71
63
|
setTreeInitialized(true);
|
|
72
64
|
return;
|
|
@@ -87,11 +79,11 @@ export function SubitemDiscoveryStep({ stepIndex, isActive = true, data, setData
|
|
|
87
79
|
}, editContext.sessionId ?? undefined);
|
|
88
80
|
if (!isMountedRef.current)
|
|
89
81
|
return;
|
|
90
|
-
const
|
|
82
|
+
const items = flattenSelectableItemsFromBackendTrees(resp.trees);
|
|
91
83
|
const language = editContext?.item?.language ??
|
|
92
84
|
editContext?.currentItemDescriptor?.language ??
|
|
93
85
|
"en";
|
|
94
|
-
const stubs =
|
|
86
|
+
const stubs = items.map(x => ({
|
|
95
87
|
id: x.id,
|
|
96
88
|
name: x.name,
|
|
97
89
|
path: x.path,
|
|
@@ -114,26 +106,19 @@ export function SubitemDiscoveryStep({ stepIndex, isActive = true, data, setData
|
|
|
114
106
|
const nodes = convertBackendTreeToTreeNodes(resp.trees);
|
|
115
107
|
setTreeNodes(nodes);
|
|
116
108
|
setExpandedIds(new Set(nodes.map(n => n.key)));
|
|
117
|
-
// Count total items and translatable items in the tree
|
|
118
109
|
const countItems = (nodeList) => {
|
|
119
110
|
let total = 0;
|
|
120
|
-
let translatable = 0;
|
|
121
111
|
const walk = (nodeList) => {
|
|
122
112
|
nodeList.forEach(node => {
|
|
123
113
|
total++;
|
|
124
|
-
if (node?.data?.isTranslatable === true) {
|
|
125
|
-
translatable++;
|
|
126
|
-
}
|
|
127
114
|
if (node.children)
|
|
128
115
|
walk(node.children);
|
|
129
116
|
});
|
|
130
117
|
};
|
|
131
118
|
walk(nodeList);
|
|
132
|
-
return
|
|
119
|
+
return total;
|
|
133
120
|
};
|
|
134
|
-
|
|
135
|
-
setTotalItemsCount(counts.total);
|
|
136
|
-
setTranslatableItemsCount(counts.translatable);
|
|
121
|
+
setTotalItemsCount(countItems(nodes));
|
|
137
122
|
setDiscoveryComplete(true);
|
|
138
123
|
setTreeInitialized(true);
|
|
139
124
|
}
|
|
@@ -158,19 +143,19 @@ export function SubitemDiscoveryStep({ stepIndex, isActive = true, data, setData
|
|
|
158
143
|
initialSelection = new Set(data.discoveredItems.map(item => item.descriptor.id));
|
|
159
144
|
}
|
|
160
145
|
else {
|
|
161
|
-
// Default: select all
|
|
162
|
-
const
|
|
146
|
+
// Default: select all selectable items in the tree
|
|
147
|
+
const allSelectableIds = new Set();
|
|
163
148
|
const walk = (nodes) => {
|
|
164
149
|
nodes.forEach(node => {
|
|
165
|
-
if (node?.data?.
|
|
166
|
-
|
|
150
|
+
if (node?.data?.isFolder !== true) {
|
|
151
|
+
allSelectableIds.add(node.key);
|
|
167
152
|
}
|
|
168
153
|
if (node.children)
|
|
169
154
|
walk(node.children);
|
|
170
155
|
});
|
|
171
156
|
};
|
|
172
157
|
walk(treeNodes);
|
|
173
|
-
initialSelection =
|
|
158
|
+
initialSelection = allSelectableIds;
|
|
174
159
|
}
|
|
175
160
|
setSelectedItemIds(initialSelection);
|
|
176
161
|
}, [isActive, discoveryComplete, treeNodes, data.discoveredItems, userHasInteracted]);
|
|
@@ -195,7 +180,7 @@ export function SubitemDiscoveryStep({ stepIndex, isActive = true, data, setData
|
|
|
195
180
|
const buildNode = (item) => ({
|
|
196
181
|
key: item.id,
|
|
197
182
|
label: item.name || item.id,
|
|
198
|
-
data: { id: item.id, name: item.name, path: item.path, hasChildren: item.hasChildren },
|
|
183
|
+
data: { id: item.id, name: item.name, path: item.path, isFolder: item.hasLayout !== true, hasChildren: item.hasChildren },
|
|
199
184
|
children: (childrenMap.get(item.id) || []).map(buildNode)
|
|
200
185
|
});
|
|
201
186
|
const originalItemIds = new Set(data.items.map(item => item.descriptor.id));
|
|
@@ -205,8 +190,6 @@ export function SubitemDiscoveryStep({ stepIndex, isActive = true, data, setData
|
|
|
205
190
|
// PerfectTree integrations
|
|
206
191
|
const expandedKeys = useMemo(() => Array.from(expandedIds), [expandedIds]);
|
|
207
192
|
const selectedKeys = useMemo(() => Array.from(selectedItemIds), [selectedItemIds]);
|
|
208
|
-
// Memoize base item IDs for checkbox rendering
|
|
209
|
-
const baseItemIdsForCheckbox = useMemo(() => new Set(data.items.map(item => item.descriptor.id)), [data.items]);
|
|
210
193
|
const getDescendantIds = (nodeKey) => {
|
|
211
194
|
const findNode = (nodes) => {
|
|
212
195
|
for (const node of nodes) {
|
|
@@ -234,35 +217,6 @@ export function SubitemDiscoveryStep({ stepIndex, isActive = true, data, setData
|
|
|
234
217
|
traverse(node.children);
|
|
235
218
|
return descendants;
|
|
236
219
|
};
|
|
237
|
-
const getDescendantTranslatableIds = (nodeKey) => {
|
|
238
|
-
const findNode = (nodes) => {
|
|
239
|
-
for (const node of nodes) {
|
|
240
|
-
if (node.key === nodeKey)
|
|
241
|
-
return node;
|
|
242
|
-
if (node.children) {
|
|
243
|
-
const found = findNode(node.children);
|
|
244
|
-
if (found)
|
|
245
|
-
return found;
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
return null;
|
|
249
|
-
};
|
|
250
|
-
const root = findNode(treeNodes);
|
|
251
|
-
if (!root?.children)
|
|
252
|
-
return [];
|
|
253
|
-
const out = [];
|
|
254
|
-
const walk = (children) => {
|
|
255
|
-
children.forEach(child => {
|
|
256
|
-
const isTranslatable = child?.data?.isTranslatable === true;
|
|
257
|
-
if (isTranslatable)
|
|
258
|
-
out.push(child.key);
|
|
259
|
-
if (child.children)
|
|
260
|
-
walk(child.children);
|
|
261
|
-
});
|
|
262
|
-
};
|
|
263
|
-
walk(root.children);
|
|
264
|
-
return out;
|
|
265
|
-
};
|
|
266
220
|
const handleCancel = () => {
|
|
267
221
|
// Simplified cancel - just stop discovery
|
|
268
222
|
inFlightRef.current = false;
|
|
@@ -271,24 +225,21 @@ export function SubitemDiscoveryStep({ stepIndex, isActive = true, data, setData
|
|
|
271
225
|
};
|
|
272
226
|
return (_jsxs("div", { className: "flex min-h-0 flex-col gap-4 p-6", "data-testid": "subitem-discovery-step", children: [_jsxs("div", { className: "mb-2 shrink-0", children: [_jsx("h3", { className: "text-lg font-semibold text-[var(--color-dark)] mb-1", children: "Discover Subitems" }), _jsx("p", { className: "text-sm text-[var(--color-gray-2)]", children: "Scanning for subitems to include in translation..." })] }), _jsxs("div", { className: "flex w-full min-w-0 shrink-0 flex-col rounded-lg border border-[var(--color-gray-3)] bg-background p-4 shadow-sm", "data-testid": "discovery-status-container", children: [_jsxs("div", { className: "flex items-center justify-between mb-4", children: [_jsxs("div", { className: "flex items-center gap-2", children: [isDiscovering && _jsx(Spinner, { "data-testid": "discovery-spinner" }), _jsx("span", { className: "font-medium text-[var(--color-dark)]", "data-testid": "discovery-status-text", children: isDiscovering ? 'Discovering subitems...' :
|
|
273
227
|
discoveryComplete ? 'Discovery Complete' :
|
|
274
|
-
'Ready to discover' })] }), isDiscovering && (_jsx(Button, { size: "sm", variant: "outline", onClick: handleCancel, "data-testid": "discovery-cancel-button", children: "Cancel" }))] }), _jsx("div", { className: "text-sm text-[var(--color-gray-2)] mb-3", "data-testid": "discovery-summary", children: discoveredCount > 0 ? (_jsxs("p", { "data-testid": "discovery-total-count", children: [_jsxs("span", { className: "font-medium text-[#9650fb]", children: [totalItemsCount, " total items found"] }),
|
|
228
|
+
'Ready to discover' })] }), isDiscovering && (_jsx(Button, { size: "sm", variant: "outline", onClick: handleCancel, "data-testid": "discovery-cancel-button", children: "Cancel" }))] }), _jsx("div", { className: "text-sm text-[var(--color-gray-2)] mb-3", "data-testid": "discovery-summary", children: discoveredCount > 0 ? (_jsxs("p", { "data-testid": "discovery-total-count", children: [_jsxs("span", { className: "font-medium text-[#9650fb]", children: [totalItemsCount, " total items found"] }), _jsx("br", {}), _jsxs("span", { className: "text-xs text-[var(--color-gray-2)]", children: ["Original items: ", data.items.length, " | Subitems discovered: ", Math.max(0, totalItemsCount - data.items.length)] }), isDiscovering && (_jsxs(_Fragment, { children: [_jsx("br", {}), _jsx("span", { className: "text-xs text-[var(--color-gray-2)] italic", children: "Item tree will appear when discovery completes" })] }))] })) : (_jsx("p", { className: "text-[var(--color-gray-2)]", children: "No items discovered yet." })) }), _jsx("div", { className: "mt-4 flex flex-col", children: !isDiscovering && discoveryComplete && treeInitialized && allDiscoveredItems.length > 0 && treeNodes.length > 0 ? (_jsxs("div", { className: "flex w-full min-w-0 flex-col", "data-testid": "item-selection-section", children: [_jsxs("div", { className: "mb-3 flex flex-col gap-2 border-t border-[var(--color-gray-3)] pt-4", children: [_jsx("h3", { className: "text-lg font-semibold text-[var(--color-dark)]", children: "Select Items to Translate" }), _jsx("span", { className: "text-sm text-[var(--color-gray-2)]", "data-testid": "selection-summary-header", children: selectedItemIds.size > 0 ? _jsxs(_Fragment, { children: [_jsx("span", { className: "font-medium text-[#9650fb]", children: selectedItemIds.size }), " selected"] }) : "No items selected" }), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx(Button, { size: "sm", variant: "outline", onClick: () => {
|
|
275
229
|
if (!isActive)
|
|
276
230
|
return;
|
|
277
|
-
|
|
278
|
-
const translatableIds = new Set();
|
|
231
|
+
const allIds = new Set();
|
|
279
232
|
const walk = (nodes) => {
|
|
280
233
|
nodes.forEach(node => {
|
|
281
|
-
|
|
282
|
-
translatableIds.add(node.key);
|
|
283
|
-
}
|
|
234
|
+
allIds.add(node.key);
|
|
284
235
|
if (node.children)
|
|
285
236
|
walk(node.children);
|
|
286
237
|
});
|
|
287
238
|
};
|
|
288
239
|
walk(treeNodes);
|
|
289
240
|
setUserHasInteracted(true);
|
|
290
|
-
setSelectedItemIds(
|
|
291
|
-
onStepCompleted(
|
|
241
|
+
setSelectedItemIds(allIds);
|
|
242
|
+
onStepCompleted(allIds.size > 0);
|
|
292
243
|
}, "data-testid": "select-all-items-button", children: "Select All" }), _jsx(Button, { size: "sm", variant: "ghost", onClick: () => {
|
|
293
244
|
if (!isActive)
|
|
294
245
|
return;
|
|
@@ -311,7 +262,6 @@ export function SubitemDiscoveryStep({ stepIndex, isActive = true, data, setData
|
|
|
311
262
|
const targetNode = key;
|
|
312
263
|
const shift = event?.shiftKey === true;
|
|
313
264
|
const next = new Set(selectedItemIds);
|
|
314
|
-
// Only select translatable items
|
|
315
265
|
const findNode = (nodes) => {
|
|
316
266
|
for (const n of nodes) {
|
|
317
267
|
if (n.key === targetNode)
|
|
@@ -325,73 +275,37 @@ export function SubitemDiscoveryStep({ stepIndex, isActive = true, data, setData
|
|
|
325
275
|
return null;
|
|
326
276
|
};
|
|
327
277
|
const n = findNode(treeNodes);
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
}
|
|
336
|
-
else {
|
|
337
|
-
// Folder row click toggles all descendant translatable items
|
|
338
|
-
const translatableIds = getDescendantTranslatableIds(key);
|
|
339
|
-
const allSelected = translatableIds.length > 0 && translatableIds.every((id) => next.has(id));
|
|
340
|
-
if (allSelected)
|
|
341
|
-
translatableIds.forEach((id) => next.delete(id));
|
|
342
|
-
else
|
|
343
|
-
translatableIds.forEach((id) => next.add(id));
|
|
344
|
-
}
|
|
278
|
+
if (!n)
|
|
279
|
+
return;
|
|
280
|
+
const ids = shift ? [key, ...getDescendantIds(key)] : [key];
|
|
281
|
+
if (!next.has(key))
|
|
282
|
+
ids.forEach((id) => next.add(id));
|
|
283
|
+
else
|
|
284
|
+
ids.forEach((id) => next.delete(id));
|
|
345
285
|
setSelectedItemIds(next);
|
|
346
286
|
// Update completion when user changes selection
|
|
347
287
|
onStepCompleted(next.size > 0);
|
|
348
288
|
}, renderNode: (node) => {
|
|
349
|
-
const
|
|
350
|
-
const translatableIds = !isTranslatable ? getDescendantTranslatableIds(node.key) : [];
|
|
351
|
-
const allSelected = !isTranslatable ? (translatableIds.length > 0 && translatableIds.every((id) => selectedItemIds.has(id))) : false;
|
|
352
|
-
const someSelected = !isTranslatable ? (translatableIds.some((id) => selectedItemIds.has(id)) && !allSelected) : false;
|
|
353
|
-
// Simple checkbox logic: if it's translatable, check direct selection; otherwise check descendant translatable items
|
|
354
|
-
// Base items are treated like any other selected item - if selected, show checked
|
|
355
|
-
const isChecked = isTranslatable ? selectedItemIds.has(node.key) : allSelected;
|
|
289
|
+
const isChecked = selectedItemIds.has(node.key);
|
|
356
290
|
const icon = node?.data?.icon;
|
|
357
|
-
return (_jsxs("div", { className:
|
|
358
|
-
el.indeterminate = someSelected; }, onMouseDown: (e) => {
|
|
359
|
-
if (!isTranslatable)
|
|
360
|
-
return; // Don't handle mouse down for untranslatable items
|
|
291
|
+
return (_jsxs("div", { className: "flex items-center gap-2", children: [icon && (_jsx("img", { src: icon, alt: "", className: "w-4 h-4" })), _jsx("input", { type: "checkbox", checked: isChecked, "data-testid": `tree-item-checkbox-${node.key}`, onMouseDown: (e) => {
|
|
361
292
|
shiftToggleRef.current = e.shiftKey;
|
|
362
293
|
}, onChange: (e) => {
|
|
363
|
-
if (!isActive
|
|
364
|
-
return;
|
|
294
|
+
if (!isActive)
|
|
295
|
+
return;
|
|
365
296
|
setUserHasInteracted(true);
|
|
366
297
|
const next = new Set(selectedItemIds);
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
ids.forEach((id) => next.delete(id));
|
|
374
|
-
}
|
|
375
|
-
else {
|
|
376
|
-
const ids = getDescendantTranslatableIds(node.key);
|
|
377
|
-
const allSel = ids.length > 0 && ids.every((id) => next.has(id));
|
|
378
|
-
if (e.currentTarget.checked && !allSel)
|
|
379
|
-
ids.forEach((id) => next.add(id));
|
|
380
|
-
else if (!e.currentTarget.checked && allSel)
|
|
381
|
-
ids.forEach((id) => next.delete(id));
|
|
382
|
-
else {
|
|
383
|
-
// Toggle based on current
|
|
384
|
-
if (allSel)
|
|
385
|
-
ids.forEach((id) => next.delete(id));
|
|
386
|
-
else
|
|
387
|
-
ids.forEach((id) => next.add(id));
|
|
388
|
-
}
|
|
389
|
-
}
|
|
298
|
+
const withDesc = shiftToggleRef.current && (node.children?.length ?? 0) > 0;
|
|
299
|
+
const ids = withDesc ? [node.key, ...getDescendantIds(node.key)] : [node.key];
|
|
300
|
+
if (e.currentTarget.checked)
|
|
301
|
+
ids.forEach((id) => next.add(id));
|
|
302
|
+
else
|
|
303
|
+
ids.forEach((id) => next.delete(id));
|
|
390
304
|
setSelectedItemIds(next);
|
|
391
305
|
shiftToggleRef.current = false;
|
|
392
306
|
// Update completion when user changes selection
|
|
393
307
|
onStepCompleted(next.size > 0);
|
|
394
|
-
} }), _jsx("span", {
|
|
308
|
+
} }), _jsx("span", { children: node.label })] }));
|
|
395
309
|
} }) }))] })) : isDiscovering ? (
|
|
396
310
|
// Loading skeleton for discovery results
|
|
397
311
|
_jsxs("div", { className: "flex w-full min-w-0 flex-col", children: [_jsx("div", { className: "p-3 bg-[#f6eeff] border border-[#9650fb]/20 rounded-lg mb-4", children: _jsx("div", { className: "h-4 bg-[#9650fb]/20 rounded w-64 animate-pulse" }) }), _jsxs("div", { className: "border-t border-[var(--color-gray-3)] pt-4", children: [_jsxs("div", { className: "mb-3 flex flex-col gap-2", children: [_jsx("div", { className: "h-6 bg-[var(--color-gray-3)] rounded w-48 animate-pulse" }), _jsx("div", { className: "h-4 bg-[var(--color-gray-3)] rounded w-40 animate-pulse" }), _jsxs("div", { className: "flex flex-wrap gap-2", children: [_jsx("div", { className: "h-8 bg-[var(--color-gray-3)] rounded w-20 animate-pulse" }), _jsx("div", { className: "h-8 bg-[var(--color-gray-3)] rounded w-20 animate-pulse" })] })] }), _jsx("div", { className: "h-4 bg-[var(--color-gray-3)] rounded w-64 mb-3 animate-pulse" }), _jsx("div", { className: "border border-[var(--color-gray-3)] rounded-lg h-80 shrink-0 overflow-auto bg-[var(--color-gray-5)]", children: _jsx("div", { className: "p-3 space-y-2", children: [...Array(8)].map((_, i) => (_jsxs("div", { className: "flex items-center gap-3 animate-pulse", children: [_jsx("div", { className: "h-4 w-4 bg-[var(--color-gray-3)] rounded" }), _jsx("div", { className: "h-4 bg-[var(--color-gray-3)] rounded w-48" })] }, i))) }) })] })] })) : (
|