@parhelia/localization 0.1.10745
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/LICENSE +8 -0
- package/README.md +29 -0
- package/dist/core/src/editor/ui/DragPreview.d.ts +15 -0
- package/dist/core/src/editor/ui/DragPreview.d.ts.map +1 -0
- package/dist/core/src/editor/ui/DragPreview.js +32 -0
- package/dist/core/src/editor/ui/PerfectTree.d.ts +79 -0
- package/dist/core/src/editor/ui/PerfectTree.d.ts.map +1 -0
- package/dist/core/src/editor/ui/PerfectTree.js +857 -0
- package/dist/localization/src/LocalizeItemCommand.d.ts +8 -0
- package/dist/localization/src/LocalizeItemCommand.d.ts.map +1 -0
- package/dist/localization/src/LocalizeItemCommand.js +44 -0
- package/dist/localization/src/LocalizeItemDialog.d.ts +4 -0
- package/dist/localization/src/LocalizeItemDialog.d.ts.map +1 -0
- package/dist/localization/src/LocalizeItemDialog.js +126 -0
- package/dist/localization/src/LocalizeItemUtils.d.ts +17 -0
- package/dist/localization/src/LocalizeItemUtils.d.ts.map +1 -0
- package/dist/localization/src/LocalizeItemUtils.js +93 -0
- package/dist/localization/src/api/discovery.d.ts +36 -0
- package/dist/localization/src/api/discovery.d.ts.map +1 -0
- package/dist/localization/src/api/discovery.js +29 -0
- package/dist/localization/src/constants.d.ts +15 -0
- package/dist/localization/src/constants.d.ts.map +1 -0
- package/dist/localization/src/constants.js +21 -0
- package/dist/localization/src/hooks/useTranslationWizard.d.ts +6 -0
- package/dist/localization/src/hooks/useTranslationWizard.d.ts.map +1 -0
- package/dist/localization/src/hooks/useTranslationWizard.js +78 -0
- package/dist/localization/src/index.d.ts +69 -0
- package/dist/localization/src/index.d.ts.map +1 -0
- package/dist/localization/src/index.js +152 -0
- package/dist/localization/src/services/translationService.d.ts +102 -0
- package/dist/localization/src/services/translationService.d.ts.map +1 -0
- package/dist/localization/src/services/translationService.js +37 -0
- package/dist/localization/src/setup/LocalizationSetupStep.d.ts +3 -0
- package/dist/localization/src/setup/LocalizationSetupStep.d.ts.map +1 -0
- package/dist/localization/src/setup/LocalizationSetupStep.js +108 -0
- package/dist/localization/src/sidebar/TranslationSidebar.d.ts +2 -0
- package/dist/localization/src/sidebar/TranslationSidebar.d.ts.map +1 -0
- package/dist/localization/src/sidebar/TranslationSidebar.js +93 -0
- package/dist/localization/src/steps/MetadataInputStep.d.ts +4 -0
- package/dist/localization/src/steps/MetadataInputStep.d.ts.map +1 -0
- package/dist/localization/src/steps/MetadataInputStep.js +38 -0
- package/dist/localization/src/steps/ServiceLanguageSelectionStep.d.ts +3 -0
- package/dist/localization/src/steps/ServiceLanguageSelectionStep.d.ts.map +1 -0
- package/dist/localization/src/steps/ServiceLanguageSelectionStep.js +91 -0
- package/dist/localization/src/steps/SubitemDiscoveryStep.d.ts +3 -0
- package/dist/localization/src/steps/SubitemDiscoveryStep.d.ts.map +1 -0
- package/dist/localization/src/steps/SubitemDiscoveryStep.js +391 -0
- package/dist/localization/src/steps/index.d.ts +5 -0
- package/dist/localization/src/steps/index.d.ts.map +1 -0
- package/dist/localization/src/steps/index.js +4 -0
- package/dist/localization/src/steps/types.d.ts +68 -0
- package/dist/localization/src/steps/types.d.ts.map +1 -0
- package/dist/localization/src/steps/types.js +1 -0
- package/dist/localization/src/translation-center/BatchTranslationView.d.ts +7 -0
- package/dist/localization/src/translation-center/BatchTranslationView.d.ts.map +1 -0
- package/dist/localization/src/translation-center/BatchTranslationView.js +487 -0
- package/dist/localization/src/translation-center/RecentTranslations.d.ts +2 -0
- package/dist/localization/src/translation-center/RecentTranslations.d.ts.map +1 -0
- package/dist/localization/src/translation-center/RecentTranslations.js +199 -0
- package/dist/localization/src/translation-center/TranslationManagement.d.ts +2 -0
- package/dist/localization/src/translation-center/TranslationManagement.d.ts.map +1 -0
- package/dist/localization/src/translation-center/TranslationManagement.js +25 -0
- package/dist/localization/src/types.d.ts +18 -0
- package/dist/localization/src/types.d.ts.map +1 -0
- package/dist/localization/src/types.js +1 -0
- package/dist/localization/src/utils/createVersions.d.ts +14 -0
- package/dist/localization/src/utils/createVersions.d.ts.map +1 -0
- package/dist/localization/src/utils/createVersions.js +26 -0
- package/package.json +47 -0
- package/styles.css +1 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
3
|
+
// Version creation now offered via VersionOnlyTranslationProvider. No custom button here.
|
|
4
|
+
export function ServiceLanguageSelectionStep({ data, setData, onStepCompleted, editContext, setFooterActions, requestClose }) {
|
|
5
|
+
const [languageSelection, setLanguageSelection] = useState({});
|
|
6
|
+
const dataRef = useRef(data);
|
|
7
|
+
useEffect(() => { dataRef.current = data; }, [data]);
|
|
8
|
+
// Check if multi-item translation is enabled
|
|
9
|
+
const multiItemEnabled = editContext?.configuration?.localization?.multiItem !== false;
|
|
10
|
+
// Use a ref to avoid dependency on onStepCompleted
|
|
11
|
+
const onStepCompletedRef = useRef(onStepCompleted);
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
onStepCompletedRef.current = onStepCompleted;
|
|
14
|
+
}, [onStepCompleted]);
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
const hasProvider = !!data.translationProvider;
|
|
17
|
+
const hasLanguages = data.targetLanguages.length > 0;
|
|
18
|
+
onStepCompletedRef.current(hasProvider && hasLanguages);
|
|
19
|
+
}, [data.translationProvider, data.targetLanguages.length]);
|
|
20
|
+
// 1) Derive provider + available languages (lightweight, in-memory)
|
|
21
|
+
const provider = useMemo(() => data.translationProviders.find(p => p.name === data.translationProvider), [data.translationProviders, data.translationProvider]);
|
|
22
|
+
const siteLanguageCodes = useMemo(() => Array.from(data.languageData.keys()), [data.languageData]);
|
|
23
|
+
const availableLanguageCodes = useMemo(() => (provider?.supportedLanguages?.length ? provider.supportedLanguages : siteLanguageCodes), [provider?.supportedLanguages, siteLanguageCodes]);
|
|
24
|
+
const allLanguages = useMemo(() => {
|
|
25
|
+
const arr = availableLanguageCodes
|
|
26
|
+
.map(code => ({
|
|
27
|
+
code,
|
|
28
|
+
name: data.languageData.get(code)?.name || code,
|
|
29
|
+
hasVersions: (data.languageData.get(code)?.items.length || 0) > 0,
|
|
30
|
+
translationStatus: data.languageData.get(code)?.translationStatus,
|
|
31
|
+
}))
|
|
32
|
+
// Exclude languages where the provider/source language equals the language itself
|
|
33
|
+
// e.g., if sourceLanguage is 'en', don't allow translating to 'en'
|
|
34
|
+
.filter(lang => !lang.translationStatus || lang.translationStatus.sourceLanguage !== lang.code);
|
|
35
|
+
arr.sort((a, b) => a.name.localeCompare(b.name));
|
|
36
|
+
return arr;
|
|
37
|
+
}, [availableLanguageCodes, data.languageData]);
|
|
38
|
+
// Rehydrate UI selection from saved wizard data when returning to this step
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
if (!allLanguages || allLanguages.length === 0)
|
|
41
|
+
return;
|
|
42
|
+
const initialSelection = {};
|
|
43
|
+
// Mark as selected any language that's in our saved targetLanguages array
|
|
44
|
+
for (const langCode of data.targetLanguages) {
|
|
45
|
+
const lang = allLanguages.find(l => l.code === langCode);
|
|
46
|
+
if (lang) {
|
|
47
|
+
initialSelection[langCode] = true;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
setLanguageSelection(initialSelection);
|
|
51
|
+
}, [allLanguages, data.targetLanguages]);
|
|
52
|
+
// Update wizard data when language selection changes
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
const selectedLanguages = Object.entries(languageSelection)
|
|
55
|
+
.filter(([, isSelected]) => isSelected)
|
|
56
|
+
.map(([code]) => code);
|
|
57
|
+
// Only update if the selection has actually changed
|
|
58
|
+
if (JSON.stringify(selectedLanguages.sort()) !== JSON.stringify(data.targetLanguages.sort())) {
|
|
59
|
+
const newData = {
|
|
60
|
+
...data,
|
|
61
|
+
targetLanguages: selectedLanguages
|
|
62
|
+
};
|
|
63
|
+
setData(newData);
|
|
64
|
+
}
|
|
65
|
+
}, [languageSelection]);
|
|
66
|
+
const handleProviderChange = (e) => {
|
|
67
|
+
const newProvider = e.target.value;
|
|
68
|
+
const newData = {
|
|
69
|
+
...data,
|
|
70
|
+
translationProvider: newProvider,
|
|
71
|
+
// Clear target languages when provider changes since language availability might change
|
|
72
|
+
targetLanguages: []
|
|
73
|
+
};
|
|
74
|
+
setData(newData);
|
|
75
|
+
// Clear UI selection too
|
|
76
|
+
setLanguageSelection({});
|
|
77
|
+
};
|
|
78
|
+
const handleLanguageToggle = (langCode) => {
|
|
79
|
+
setLanguageSelection(prev => ({ ...prev, [langCode]: !prev[langCode] }));
|
|
80
|
+
};
|
|
81
|
+
const handleSubitemsToggle = () => {
|
|
82
|
+
const newData = {
|
|
83
|
+
...data,
|
|
84
|
+
includeSubitems: !data.includeSubitems
|
|
85
|
+
};
|
|
86
|
+
setData(newData);
|
|
87
|
+
};
|
|
88
|
+
return (_jsxs("div", { className: "p-6 space-y-6 h-full flex flex-col", "data-testid": "service-language-selection-step", children: [_jsxs("div", { children: [_jsx("h2", { className: "text-xl font-semibold mb-2", children: "Configure Translation" }), _jsx("p", { className: "text-sm text-gray-600 mb-6", children: "Select translation provider and target languages for your content." })] }), _jsxs("div", { className: "space-y-6 flex-1", children: [_jsxs("div", { children: [_jsx("h3", { className: "text-sm font-medium text-gray-900 mb-2", children: "Translation Provider" }), _jsx("p", { className: "text-xs text-gray-600 mb-3", children: "Choose how to translate your content. \"Create Versions\" will create new language versions without automatic translation." }), _jsxs("select", { value: data.translationProvider || "", onChange: handleProviderChange, className: "block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm", "data-testid": "translation-provider-select", children: [_jsx("option", { value: "", disabled: true, children: "Select a provider..." }), data.translationProviders.map((provider) => (_jsx("option", { value: provider.name, children: provider.displayName }, provider.name)))] })] }), multiItemEnabled && (_jsxs("div", { children: [_jsxs("label", { className: "flex items-center", children: [_jsx("input", { type: "checkbox", checked: data.includeSubitems, onChange: handleSubitemsToggle, className: "h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded", "data-testid": "include-subitems-checkbox" }), _jsx("span", { className: "ml-2 text-sm text-gray-900", children: "Include subitems" })] }), _jsx("p", { className: "text-xs text-gray-500 mt-1 ml-6", children: "Also translate any child components and nested content within this item." })] })), _jsxs("div", { children: [_jsx("h3", { className: "text-sm font-medium text-gray-900 mb-2", children: "Target Languages" }), _jsx("p", { className: "text-xs text-gray-600 mb-3", children: "Select the languages you want to translate this content into." }), _jsx("div", { className: "border border-gray-200 rounded-md min-h-[200px] max-h-64 overflow-y-auto", children: data.translationProviders.length === 0 || allLanguages.length === 0 ? (
|
|
89
|
+
// Loading skeleton
|
|
90
|
+
_jsx("div", { className: "p-3 space-y-2", children: [...Array(4)].map((_, i) => (_jsxs("div", { className: "flex items-center animate-pulse", children: [_jsx("div", { className: "h-4 w-4 bg-gray-200 rounded" }), _jsx("div", { className: "ml-2 h-4 bg-gray-200 rounded w-32" }), _jsx("div", { className: "ml-auto h-4 bg-gray-200 rounded w-16" })] }, i))) })) : (_jsx("div", { className: "p-3 grid grid-cols-1 gap-2", children: allLanguages.map((lang) => (_jsxs("label", { className: "flex items-center", children: [_jsx("input", { type: "checkbox", checked: languageSelection[lang.code] || false, onChange: () => handleLanguageToggle(lang.code), className: "h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded", "data-testid": `language-checkbox-${lang.code}` }), _jsxs("span", { className: "ml-2 text-sm text-gray-900", children: [lang.name, " (", lang.code, ")"] }), !lang.hasVersions && (_jsx("span", { className: "ml-auto text-xs text-orange-600 bg-orange-100 px-2 py-1 rounded", children: "No versions" }))] }, lang.code))) })) })] })] })] }));
|
|
91
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { TranslationStepProps } from "./types";
|
|
2
|
+
export declare function SubitemDiscoveryStep({ data, setData, editContext, onStepCompleted, setBeforeNextCallback, setFooterActions, requestClose }: TranslationStepProps): import("react/jsx-runtime").JSX.Element;
|
|
3
|
+
//# sourceMappingURL=SubitemDiscoveryStep.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SubitemDiscoveryStep.d.ts","sourceRoot":"","sources":["../../../../src/steps/SubitemDiscoveryStep.tsx"],"names":[],"mappings":"AAOA,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAY/C,wBAAgB,oBAAoB,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,YAAY,EAAE,EAAE,oBAAoB,2CAyfhK"}
|
|
@@ -0,0 +1,391 @@
|
|
|
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 } from "@parhelia/core";
|
|
4
|
+
// Custom tree implementation (no rc-tree)
|
|
5
|
+
// NOTE: import PerfectTree from core package via dist path to avoid TS path issues in local package builds
|
|
6
|
+
import { PerfectTree } from "../../../core/src/editor/ui/PerfectTree";
|
|
7
|
+
import { convertFullItemToStub, convertStubToFullItem } from "@parhelia/core";
|
|
8
|
+
import { discoverItemsTree, convertBackendTreeToTreeNodes, flattenPagesFromBackendTrees } from "../api/discovery";
|
|
9
|
+
// We need to implement a basic Spinner component since it's not in core
|
|
10
|
+
const Spinner = ({ ...props }) => (_jsx("div", { className: "animate-spin rounded-full h-4 w-4 border-b-2 border-blue-600", ...props }));
|
|
11
|
+
export function SubitemDiscoveryStep({ data, setData, editContext, onStepCompleted, setBeforeNextCallback, setFooterActions, requestClose }) {
|
|
12
|
+
const [isDiscovering, setIsDiscovering] = useState(false);
|
|
13
|
+
const [discoveredCount, setDiscoveredCount] = useState(0);
|
|
14
|
+
const [cancelled, setCancelled] = useState(false);
|
|
15
|
+
const [discoveryComplete, setDiscoveryComplete] = useState(false);
|
|
16
|
+
const [subitemsFound, setSubitemsFound] = useState(0);
|
|
17
|
+
const [selectedItemIds, setSelectedItemIds] = useState(new Set());
|
|
18
|
+
const [treeNodes, setTreeNodes] = useState([]);
|
|
19
|
+
const [allDiscoveredItems, setAllDiscoveredItems] = useState([]);
|
|
20
|
+
// Once the user interacts with selection, stop auto-selecting
|
|
21
|
+
const [userSelectionOverride, setUserSelectionOverride] = useState(false);
|
|
22
|
+
// Expanded state for custom tree
|
|
23
|
+
const [expandedIds, setExpandedIds] = useState(new Set());
|
|
24
|
+
// Track when tree structure is fully built and ready for display
|
|
25
|
+
const [treeInitialized, setTreeInitialized] = useState(false);
|
|
26
|
+
const cancelledRef = useRef(false);
|
|
27
|
+
const discoveredItemsRef = useRef([]);
|
|
28
|
+
const processedItemIds = useRef(new Set());
|
|
29
|
+
const dataRef = useRef(data);
|
|
30
|
+
// Track if initialization is complete to prevent reacting to selection changes during setup
|
|
31
|
+
const [initializationComplete, setInitializationComplete] = useState(false);
|
|
32
|
+
// Keep data ref updated
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
dataRef.current = data;
|
|
35
|
+
}, [data]);
|
|
36
|
+
const contTokenRef = useRef(null);
|
|
37
|
+
const inFlightRef = useRef(false);
|
|
38
|
+
const aggregatedRef = useRef([]);
|
|
39
|
+
const backendTreesRef = useRef([]);
|
|
40
|
+
const shiftToggleRef = useRef(false);
|
|
41
|
+
const selectedItemIdsRef = useRef(new Set());
|
|
42
|
+
const allDiscoveredItemsRef = useRef([]);
|
|
43
|
+
const hasRegisteredBeforeNextRef = useRef(false);
|
|
44
|
+
// Track the last initialized item IDs to prevent re-initialization with same data
|
|
45
|
+
const lastInitializedItemIdsRef = useRef('');
|
|
46
|
+
const startDiscovery = useCallback(async () => {
|
|
47
|
+
if (inFlightRef.current)
|
|
48
|
+
return; // guard double-trigger (StrictMode, re-renders)
|
|
49
|
+
inFlightRef.current = true;
|
|
50
|
+
setIsDiscovering(true);
|
|
51
|
+
setCancelled(false);
|
|
52
|
+
setDiscoveryComplete(false);
|
|
53
|
+
// Only reset when starting fresh (no continuation token)
|
|
54
|
+
if (!contTokenRef.current) {
|
|
55
|
+
setAllDiscoveredItems([]);
|
|
56
|
+
setTreeNodes([]);
|
|
57
|
+
setTreeInitialized(false);
|
|
58
|
+
aggregatedRef.current = [];
|
|
59
|
+
}
|
|
60
|
+
cancelledRef.current = false;
|
|
61
|
+
const rootIds = data.items.map(i => i.descriptor.id);
|
|
62
|
+
try {
|
|
63
|
+
while (!cancelledRef.current) {
|
|
64
|
+
// Use new backend tree endpoint in one shot
|
|
65
|
+
const resp = await discoverItemsTree({
|
|
66
|
+
rootItemIds: rootIds,
|
|
67
|
+
language: editContext?.contentEditorItem?.language || "en",
|
|
68
|
+
}, editContext.sessionId ?? undefined);
|
|
69
|
+
const pages = flattenPagesFromBackendTrees(resp.trees);
|
|
70
|
+
aggregatedRef.current = pages;
|
|
71
|
+
backendTreesRef.current = resp.trees;
|
|
72
|
+
setDiscoveredCount(pages.length);
|
|
73
|
+
setSubitemsFound(Math.max(0, pages.length - data.items.length));
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
if (!cancelledRef.current) {
|
|
77
|
+
setIsDiscovering(false);
|
|
78
|
+
setDiscoveryComplete(true);
|
|
79
|
+
// Keep a flat list of discovered pages for selection summary/commit
|
|
80
|
+
const stubs = aggregatedRef.current.map(x => ({
|
|
81
|
+
id: x.id,
|
|
82
|
+
name: x.name,
|
|
83
|
+
path: x.path,
|
|
84
|
+
parentId: "",
|
|
85
|
+
idPath: "",
|
|
86
|
+
database: "master",
|
|
87
|
+
descriptor: { id: x.id, language: editContext?.contentEditorItem?.language || "en", version: 0 },
|
|
88
|
+
icon: "",
|
|
89
|
+
largeIcon: "",
|
|
90
|
+
templateId: "",
|
|
91
|
+
templateName: "",
|
|
92
|
+
hasLayout: false,
|
|
93
|
+
hasChildren: x.hasChildren,
|
|
94
|
+
versions: 0,
|
|
95
|
+
language: editContext?.contentEditorItem?.language || "en",
|
|
96
|
+
version: 0,
|
|
97
|
+
}));
|
|
98
|
+
setAllDiscoveredItems(stubs);
|
|
99
|
+
const nodes = convertBackendTreeToTreeNodes(backendTreesRef.current);
|
|
100
|
+
setTreeNodes(nodes);
|
|
101
|
+
setExpandedIds(new Set(nodes.map(n => n.key)));
|
|
102
|
+
setTreeInitialized(true);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
console.error("Error during discovery:", error);
|
|
107
|
+
setIsDiscovering(false);
|
|
108
|
+
}
|
|
109
|
+
finally {
|
|
110
|
+
inFlightRef.current = false;
|
|
111
|
+
}
|
|
112
|
+
}, [data.items, editContext]);
|
|
113
|
+
// Initialize discovery state when component mounts or input items change
|
|
114
|
+
useEffect(() => {
|
|
115
|
+
const convertedItems = data.items.map(convertFullItemToStub);
|
|
116
|
+
// Create a stable key from item IDs and includeSubitems flag to detect actual changes
|
|
117
|
+
const itemKey = convertedItems.map(i => i.id).sort().join(',') + ':' + data.includeSubitems;
|
|
118
|
+
// Skip re-initialization if we've already initialized with these exact items
|
|
119
|
+
if (lastInitializedItemIdsRef.current === itemKey) {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
console.log('🔄 Initializing SubitemDiscoveryStep with items:', itemKey);
|
|
123
|
+
lastInitializedItemIdsRef.current = itemKey;
|
|
124
|
+
discoveredItemsRef.current = convertedItems;
|
|
125
|
+
// Don't set allDiscoveredItems until discovery is complete
|
|
126
|
+
setDiscoveredCount(data.items.length);
|
|
127
|
+
processedItemIds.current = new Set(); // Start empty - items should be processed to find children
|
|
128
|
+
// Auto-select original items
|
|
129
|
+
if (!userSelectionOverride) {
|
|
130
|
+
setSelectedItemIds(new Set(convertedItems.map(item => item.id)));
|
|
131
|
+
}
|
|
132
|
+
// Trigger discovery after state updates
|
|
133
|
+
if (data.includeSubitems && convertedItems.some(item => item.hasChildren)) {
|
|
134
|
+
// Clear any existing tree data before starting discovery
|
|
135
|
+
setAllDiscoveredItems([]);
|
|
136
|
+
setTreeNodes([]);
|
|
137
|
+
setTreeInitialized(false);
|
|
138
|
+
setDiscoveryComplete(false);
|
|
139
|
+
setTimeout(() => startDiscovery(), 0);
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
// No discovery needed, show items immediately
|
|
143
|
+
setAllDiscoveredItems(convertedItems);
|
|
144
|
+
setDiscoveryComplete(true);
|
|
145
|
+
// Build tree structure
|
|
146
|
+
const nodes = buildTreeNodes(convertedItems);
|
|
147
|
+
setTreeNodes(nodes);
|
|
148
|
+
// Expand all root nodes by default
|
|
149
|
+
const rootNodeIds = nodes.map(node => node.key);
|
|
150
|
+
setExpandedIds(new Set(rootNodeIds));
|
|
151
|
+
// Mark tree as fully initialized
|
|
152
|
+
setTreeInitialized(true);
|
|
153
|
+
}
|
|
154
|
+
// Mark initialization as complete after all setup is done
|
|
155
|
+
setInitializationComplete(true);
|
|
156
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
157
|
+
}, [data.items, data.includeSubitems]);
|
|
158
|
+
// Keep refs in sync without causing parent rerenders
|
|
159
|
+
useEffect(() => { selectedItemIdsRef.current = selectedItemIds; }, [selectedItemIds]);
|
|
160
|
+
useEffect(() => { allDiscoveredItemsRef.current = allDiscoveredItems; }, [allDiscoveredItems]);
|
|
161
|
+
// Register the commit callback ONCE to avoid parent rerender on first selection
|
|
162
|
+
useEffect(() => {
|
|
163
|
+
if (!setBeforeNextCallback || hasRegisteredBeforeNextRef.current)
|
|
164
|
+
return;
|
|
165
|
+
const commit = async () => {
|
|
166
|
+
const selectedIds = selectedItemIdsRef.current;
|
|
167
|
+
const allStubs = allDiscoveredItemsRef.current;
|
|
168
|
+
const selectedItems = allStubs.filter(item => selectedIds.has(item.id));
|
|
169
|
+
const convertedItems = selectedItems.map(convertStubToFullItem);
|
|
170
|
+
const currentData = dataRef.current;
|
|
171
|
+
if (JSON.stringify(currentData.discoveredItems) !== JSON.stringify(convertedItems)) {
|
|
172
|
+
setData({ ...currentData, discoveredItems: convertedItems });
|
|
173
|
+
}
|
|
174
|
+
return true;
|
|
175
|
+
};
|
|
176
|
+
setBeforeNextCallback(commit);
|
|
177
|
+
hasRegisteredBeforeNextRef.current = true;
|
|
178
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
179
|
+
}, [setBeforeNextCallback]);
|
|
180
|
+
// Use a ref to avoid dependency on onStepCompleted
|
|
181
|
+
const onStepCompletedRef = useRef(onStepCompleted);
|
|
182
|
+
useEffect(() => {
|
|
183
|
+
onStepCompletedRef.current = onStepCompleted;
|
|
184
|
+
}, [onStepCompleted]);
|
|
185
|
+
// Update step completion based on selection
|
|
186
|
+
// Mark completion based on whether there is any selection
|
|
187
|
+
useEffect(() => {
|
|
188
|
+
if (!treeInitialized)
|
|
189
|
+
return;
|
|
190
|
+
onStepCompletedRef.current(selectedItemIds.size > 0);
|
|
191
|
+
}, [selectedItemIds.size, treeInitialized]);
|
|
192
|
+
const buildTreeNodes = useCallback((items) => {
|
|
193
|
+
// Fallback: Build simple tree from items for non-subitem discovery
|
|
194
|
+
const itemMap = new Map();
|
|
195
|
+
const childrenMap = new Map();
|
|
196
|
+
items.forEach(item => {
|
|
197
|
+
itemMap.set(item.id, item);
|
|
198
|
+
if (item.parentId) {
|
|
199
|
+
if (!childrenMap.has(item.parentId))
|
|
200
|
+
childrenMap.set(item.parentId, []);
|
|
201
|
+
childrenMap.get(item.parentId).push(item);
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
const buildNode = (item) => ({
|
|
205
|
+
key: item.id,
|
|
206
|
+
label: item.name || item.id,
|
|
207
|
+
data: { id: item.id, name: item.name, path: item.path, hasChildren: item.hasChildren },
|
|
208
|
+
children: (childrenMap.get(item.id) || []).map(buildNode)
|
|
209
|
+
});
|
|
210
|
+
const originalItemIds = new Set(data.items.map(item => item.descriptor.id));
|
|
211
|
+
const rootItems = items.filter(item => !item.parentId || !itemMap.has(item.parentId) || originalItemIds.has(item.id));
|
|
212
|
+
return rootItems.map(buildNode);
|
|
213
|
+
}, [data.items]);
|
|
214
|
+
// PerfectTree integrations
|
|
215
|
+
const expandedKeys = useMemo(() => Array.from(expandedIds), [expandedIds]);
|
|
216
|
+
const selectedKeys = useMemo(() => Array.from(selectedItemIds), [selectedItemIds]);
|
|
217
|
+
const getDescendantIds = (nodeKey) => {
|
|
218
|
+
const findNode = (nodes) => {
|
|
219
|
+
for (const node of nodes) {
|
|
220
|
+
if (node.key === nodeKey)
|
|
221
|
+
return node;
|
|
222
|
+
if (node.children) {
|
|
223
|
+
const found = findNode(node.children);
|
|
224
|
+
if (found)
|
|
225
|
+
return found;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return null;
|
|
229
|
+
};
|
|
230
|
+
const node = findNode(treeNodes);
|
|
231
|
+
if (!node?.children)
|
|
232
|
+
return [];
|
|
233
|
+
const descendants = [];
|
|
234
|
+
const traverse = (children) => {
|
|
235
|
+
children.forEach(child => {
|
|
236
|
+
descendants.push(child.key);
|
|
237
|
+
if (child.children)
|
|
238
|
+
traverse(child.children);
|
|
239
|
+
});
|
|
240
|
+
};
|
|
241
|
+
traverse(node.children);
|
|
242
|
+
return descendants;
|
|
243
|
+
};
|
|
244
|
+
const getDescendantPageIds = (nodeKey) => {
|
|
245
|
+
const findNode = (nodes) => {
|
|
246
|
+
for (const node of nodes) {
|
|
247
|
+
if (node.key === nodeKey)
|
|
248
|
+
return node;
|
|
249
|
+
if (node.children) {
|
|
250
|
+
const found = findNode(node.children);
|
|
251
|
+
if (found)
|
|
252
|
+
return found;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
return null;
|
|
256
|
+
};
|
|
257
|
+
const root = findNode(treeNodes);
|
|
258
|
+
if (!root?.children)
|
|
259
|
+
return [];
|
|
260
|
+
const out = [];
|
|
261
|
+
const walk = (children) => {
|
|
262
|
+
children.forEach(child => {
|
|
263
|
+
const isPage = child?.data?.hasLayout === true;
|
|
264
|
+
if (isPage)
|
|
265
|
+
out.push(child.key);
|
|
266
|
+
if (child.children)
|
|
267
|
+
walk(child.children);
|
|
268
|
+
});
|
|
269
|
+
};
|
|
270
|
+
walk(root.children);
|
|
271
|
+
return out;
|
|
272
|
+
};
|
|
273
|
+
const handleCancel = () => {
|
|
274
|
+
setCancelled(true);
|
|
275
|
+
cancelledRef.current = true;
|
|
276
|
+
setIsDiscovering(false);
|
|
277
|
+
setDiscoveryComplete(true);
|
|
278
|
+
// Update allDiscoveredItems with current results
|
|
279
|
+
setAllDiscoveredItems([...discoveredItemsRef.current]);
|
|
280
|
+
// Build tree structure with current items
|
|
281
|
+
const nodes = buildTreeNodes(discoveredItemsRef.current);
|
|
282
|
+
setTreeNodes(nodes);
|
|
283
|
+
// Expand all root nodes by default
|
|
284
|
+
const rootNodeIds = nodes.map(node => node.key);
|
|
285
|
+
setExpandedIds(new Set(rootNodeIds));
|
|
286
|
+
// Mark tree as fully initialized
|
|
287
|
+
setTreeInitialized(true);
|
|
288
|
+
};
|
|
289
|
+
// Handle individual checkbox changes (no parent-child cascading)
|
|
290
|
+
const handleIndividualCheckboxChange = (itemId, checked) => {
|
|
291
|
+
setUserSelectionOverride(true);
|
|
292
|
+
const newSelection = new Set(selectedItemIds);
|
|
293
|
+
if (checked) {
|
|
294
|
+
newSelection.add(itemId);
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
297
|
+
newSelection.delete(itemId);
|
|
298
|
+
}
|
|
299
|
+
setSelectedItemIds(newSelection);
|
|
300
|
+
};
|
|
301
|
+
return (_jsxs("div", { className: "flex flex-col gap-4 p-6 h-full", "data-testid": "subitem-discovery-step", children: [_jsxs("div", { className: "mb-2", children: [_jsx("h3", { className: "text-lg font-medium mb-1", children: "Discover Subitems" }), _jsx("p", { className: "text-sm text-gray-600", children: "Scanning for subitems to include in translation..." })] }), _jsxs("div", { className: "border rounded p-4 bg-gray-50 min-h-[120px]", "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", "data-testid": "discovery-status-text", children: isDiscovering ? 'Discovering subitems...' :
|
|
302
|
+
discoveryComplete ? 'Discovery Complete' :
|
|
303
|
+
'Ready to discover' })] }), isDiscovering && (_jsx(Button, { size: "sm", onClick: handleCancel, "data-testid": "discovery-cancel-button", children: "Cancel" }))] }), _jsx("div", { className: "text-sm text-gray-600 mb-3", "data-testid": "discovery-summary", children: discoveredCount > 0 ? (_jsxs("p", { "data-testid": "discovery-total-count", children: [_jsxs("span", { className: "font-medium text-blue-600", children: [discoveredCount, " total items found"] }), _jsx("br", {}), _jsxs("span", { className: "text-xs", children: ["Original items: ", data.items.length, " | Subitems discovered: ", Math.max(0, discoveredCount - data.items.length)] }), isDiscovering && (_jsxs(_Fragment, { children: [_jsx("br", {}), _jsx("span", { className: "text-xs text-gray-500 italic", children: "Item tree will appear when discovery completes" })] }))] })) : (_jsx("p", { children: "No items discovered yet." })) }), !isDiscovering && !discoveryComplete && (_jsx(Button, { size: "sm", onClick: startDiscovery, "data-testid": "discovery-start-button", children: "Start Discovery" })), _jsx("div", { className: "mt-4 min-h-[400px]", children: !isDiscovering && discoveryComplete && treeInitialized && allDiscoveredItems.length > 0 && treeNodes.length > 0 ? (_jsx("div", { children: _jsxs("div", { className: "border-t pt-4", "data-testid": "item-selection-section", children: [_jsxs("div", { className: "flex items-center justify-between mb-3", children: [_jsx("h3", { className: "text-lg font-medium", children: "Select Items to Translate" }), _jsxs("div", { className: "flex items-center gap-4", children: [_jsx("span", { className: "text-sm text-gray-600", "data-testid": "selection-summary-header", children: selectedItemIds.size > 0 ? `${selectedItemIds.size} selected` : "No items selected" }), _jsx(Button, { size: "sm", variant: "outline", onClick: () => { setUserSelectionOverride(true); setSelectedItemIds(new Set(allDiscoveredItems.map(i => i.id))); }, "data-testid": "select-all-items-button", children: "Select All" }), _jsx(Button, { size: "sm", variant: "outline", onClick: () => { setUserSelectionOverride(true); setSelectedItemIds(new Set()); }, "data-testid": "select-none-items-button", children: "Select None" })] })] }), _jsx("div", { className: "text-sm text-gray-600 mb-3", "data-testid": "selection-summary", children: _jsx("span", { className: "text-gray-500", children: "Tip: Hold Shift and click a checkbox to toggle all descendants." }) }), treeNodes.length > 0 && (_jsx("div", { className: "border rounded-lg h-80 overflow-auto", "data-testid": "item-tree-view", children: _jsx(PerfectTree, { nodes: treeNodes, expandedKeys: expandedKeys, selectedKeys: selectedKeys, onToggleExpand: (key) => {
|
|
304
|
+
setExpandedIds(prev => {
|
|
305
|
+
const next = new Set(prev);
|
|
306
|
+
if (next.has(key))
|
|
307
|
+
next.delete(key);
|
|
308
|
+
else
|
|
309
|
+
next.add(key);
|
|
310
|
+
return next;
|
|
311
|
+
});
|
|
312
|
+
}, onSelect: (key, event) => {
|
|
313
|
+
setUserSelectionOverride(true);
|
|
314
|
+
const targetNode = key;
|
|
315
|
+
const shift = event?.shiftKey === true;
|
|
316
|
+
const next = new Set(selectedItemIds);
|
|
317
|
+
// Only select pages
|
|
318
|
+
const findNode = (nodes) => {
|
|
319
|
+
for (const n of nodes) {
|
|
320
|
+
if (n.key === targetNode)
|
|
321
|
+
return n;
|
|
322
|
+
if (n.children) {
|
|
323
|
+
const f = findNode(n.children);
|
|
324
|
+
if (f)
|
|
325
|
+
return f;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
return null;
|
|
329
|
+
};
|
|
330
|
+
const n = findNode(treeNodes);
|
|
331
|
+
const isPage = n?.data?.hasLayout === true;
|
|
332
|
+
if (isPage) {
|
|
333
|
+
const ids = shift ? [key, ...getDescendantIds(key)] : [key];
|
|
334
|
+
if (!next.has(key))
|
|
335
|
+
ids.forEach(id => next.add(id));
|
|
336
|
+
else
|
|
337
|
+
ids.forEach(id => next.delete(id));
|
|
338
|
+
}
|
|
339
|
+
else {
|
|
340
|
+
// Folder row click toggles all descendant pages
|
|
341
|
+
const pageIds = getDescendantPageIds(key);
|
|
342
|
+
const allSelected = pageIds.length > 0 && pageIds.every(id => next.has(id));
|
|
343
|
+
if (allSelected)
|
|
344
|
+
pageIds.forEach(id => next.delete(id));
|
|
345
|
+
else
|
|
346
|
+
pageIds.forEach(id => next.add(id));
|
|
347
|
+
}
|
|
348
|
+
setSelectedItemIds(next);
|
|
349
|
+
}, renderNode: (node) => {
|
|
350
|
+
const isPage = node?.data?.hasLayout === true;
|
|
351
|
+
const pageIds = !isPage ? getDescendantPageIds(node.key) : [];
|
|
352
|
+
const allSelected = !isPage ? (pageIds.length > 0 && pageIds.every(id => selectedItemIds.has(id))) : false;
|
|
353
|
+
const someSelected = !isPage ? (pageIds.some(id => selectedItemIds.has(id)) && !allSelected) : false;
|
|
354
|
+
const isChecked = isPage ? selectedItemIds.has(node.key) : allSelected;
|
|
355
|
+
const icon = node?.data?.icon;
|
|
356
|
+
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, ref: (el) => { if (el)
|
|
357
|
+
el.indeterminate = someSelected; }, onMouseDown: (e) => { shiftToggleRef.current = e.shiftKey; }, onChange: (e) => {
|
|
358
|
+
setUserSelectionOverride(true);
|
|
359
|
+
const next = new Set(selectedItemIds);
|
|
360
|
+
if (isPage) {
|
|
361
|
+
const withDesc = shiftToggleRef.current && (node.children?.length ?? 0) > 0;
|
|
362
|
+
const ids = withDesc ? [node.key, ...getDescendantIds(node.key)] : [node.key];
|
|
363
|
+
if (e.currentTarget.checked)
|
|
364
|
+
ids.forEach(id => next.add(id));
|
|
365
|
+
else
|
|
366
|
+
ids.forEach(id => next.delete(id));
|
|
367
|
+
}
|
|
368
|
+
else {
|
|
369
|
+
const ids = getDescendantPageIds(node.key);
|
|
370
|
+
const allSel = ids.length > 0 && ids.every(id => next.has(id));
|
|
371
|
+
if (e.currentTarget.checked && !allSel)
|
|
372
|
+
ids.forEach(id => next.add(id));
|
|
373
|
+
else if (!e.currentTarget.checked && allSel)
|
|
374
|
+
ids.forEach(id => next.delete(id));
|
|
375
|
+
else {
|
|
376
|
+
// Toggle based on current
|
|
377
|
+
if (allSel)
|
|
378
|
+
ids.forEach(id => next.delete(id));
|
|
379
|
+
else
|
|
380
|
+
ids.forEach(id => next.add(id));
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
setSelectedItemIds(next);
|
|
384
|
+
shiftToggleRef.current = false;
|
|
385
|
+
} }), _jsx("span", { children: node.label })] }));
|
|
386
|
+
} }) }))] }) })) : isDiscovering ? (
|
|
387
|
+
// Loading skeleton for discovery results
|
|
388
|
+
_jsxs("div", { children: [_jsx("div", { className: "p-3 bg-blue-50 border border-blue-200 rounded mb-4", children: _jsx("div", { className: "h-4 bg-blue-200 rounded w-64 animate-pulse" }) }), _jsxs("div", { className: "border-t pt-4", children: [_jsxs("div", { className: "flex items-center justify-between mb-3", children: [_jsx("div", { className: "h-6 bg-gray-200 rounded w-48 animate-pulse" }), _jsxs("div", { className: "flex gap-2", children: [_jsx("div", { className: "h-8 bg-gray-200 rounded w-20 animate-pulse" }), _jsx("div", { className: "h-8 bg-gray-200 rounded w-20 animate-pulse" })] })] }), _jsx("div", { className: "h-4 bg-gray-200 rounded w-64 mb-3 animate-pulse" }), _jsx("div", { className: "border rounded-lg h-80 overflow-auto", 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-gray-200 rounded" }), _jsx("div", { className: "h-4 bg-gray-200 rounded w-48" })] }, i))) }) })] })] })) : (
|
|
389
|
+
// Empty state
|
|
390
|
+
_jsx("div", { className: "flex items-center justify-center h-80 border rounded-lg bg-gray-50", children: _jsxs("div", { className: "text-center text-gray-500", children: [_jsx("p", { children: "Ready to discover subitems" }), _jsx("p", { className: "text-sm", children: "Discovery will start automatically" })] }) })) })] })] }));
|
|
391
|
+
}
|
|
@@ -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"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { FullItem, ItemDescriptor, EditContextType } from "@parhelia/core";
|
|
2
|
+
export type TranslationProviderInfo = {
|
|
3
|
+
name: string;
|
|
4
|
+
displayName: string;
|
|
5
|
+
supportedLanguages: string[];
|
|
6
|
+
};
|
|
7
|
+
export type TranslationStatus = {
|
|
8
|
+
targetLanguage: string;
|
|
9
|
+
sourceLanguage?: string;
|
|
10
|
+
status: string;
|
|
11
|
+
timestamp: string;
|
|
12
|
+
hash?: string;
|
|
13
|
+
message?: string;
|
|
14
|
+
batchId?: string;
|
|
15
|
+
};
|
|
16
|
+
export type LanguageData = {
|
|
17
|
+
name: string;
|
|
18
|
+
languageCode: string;
|
|
19
|
+
items: ItemDescriptor[];
|
|
20
|
+
translationStatus?: TranslationStatus;
|
|
21
|
+
};
|
|
22
|
+
export type TranslationDialogResult = {
|
|
23
|
+
translationProvider: string;
|
|
24
|
+
targetLanguages: string[];
|
|
25
|
+
includeSubitems: boolean;
|
|
26
|
+
discoveredItems: FullItem[];
|
|
27
|
+
metadata?: any;
|
|
28
|
+
batchId?: string;
|
|
29
|
+
};
|
|
30
|
+
export type TranslationWizardConfiguration = {
|
|
31
|
+
skipLanguageSelection?: boolean;
|
|
32
|
+
predefinedTargetLanguages?: string[];
|
|
33
|
+
predefinedProvider?: string;
|
|
34
|
+
predefinedMetadata?: any;
|
|
35
|
+
};
|
|
36
|
+
export type TranslationWizardData = {
|
|
37
|
+
items: FullItem[];
|
|
38
|
+
targetLanguages: string[];
|
|
39
|
+
translationProvider: string;
|
|
40
|
+
includeSubitems: boolean;
|
|
41
|
+
discoveredItems: FullItem[];
|
|
42
|
+
languageData: Map<string, LanguageData>;
|
|
43
|
+
translationProviders: TranslationProviderInfo[];
|
|
44
|
+
itemMetadata: Map<string, Map<string, string>>;
|
|
45
|
+
metadata?: any;
|
|
46
|
+
[key: string]: any;
|
|
47
|
+
};
|
|
48
|
+
export type TranslationStepProps = {
|
|
49
|
+
data: TranslationWizardData;
|
|
50
|
+
setData: (data: TranslationWizardData) => void;
|
|
51
|
+
editContext: EditContextType;
|
|
52
|
+
onStepCompleted: (completed: boolean) => void;
|
|
53
|
+
setBeforeNextCallback?: (callback: (() => Promise<boolean>) | null) => void;
|
|
54
|
+
setFooterActions?: (actions: {
|
|
55
|
+
key: string;
|
|
56
|
+
label: string;
|
|
57
|
+
disabled?: boolean;
|
|
58
|
+
onClick: () => void;
|
|
59
|
+
signature?: string;
|
|
60
|
+
}[]) => void;
|
|
61
|
+
requestClose?: (result: TranslationDialogResult | null) => void;
|
|
62
|
+
};
|
|
63
|
+
export type LocalizeItemDialogProps = {
|
|
64
|
+
items: FullItem[];
|
|
65
|
+
editContext: EditContextType;
|
|
66
|
+
configuration?: TranslationWizardConfiguration;
|
|
67
|
+
};
|
|
68
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/steps/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
interface BatchTranslationViewProps {
|
|
2
|
+
batchId: string;
|
|
3
|
+
onBack?: () => void;
|
|
4
|
+
}
|
|
5
|
+
export declare function BatchTranslationView({ batchId, onBack }: BatchTranslationViewProps): import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
export {};
|
|
7
|
+
//# sourceMappingURL=BatchTranslationView.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BatchTranslationView.d.ts","sourceRoot":"","sources":["../../../../src/translation-center/BatchTranslationView.tsx"],"names":[],"mappings":"AAiBA,UAAU,yBAAyB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;CACrB;AAoCD,wBAAgB,oBAAoB,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,yBAAyB,2CAuxBlF"}
|