@fgv/ts-res-ui-components 5.0.0-10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (231) hide show
  1. package/.rush/temp/03c8b056281d9db0a97d8a6e25eea798a160d393.tar.log +271 -0
  2. package/.rush/temp/chunked-rush-logs/ts-res-ui-components.build.chunks.jsonl +9 -0
  3. package/.rush/temp/operation/build/all.log +9 -0
  4. package/.rush/temp/operation/build/log-chunks.jsonl +9 -0
  5. package/.rush/temp/operation/build/state.json +3 -0
  6. package/.rush/temp/shrinkwrap-deps.json +1111 -0
  7. package/README.md +18 -0
  8. package/REFACTORING_PLAN.md +171 -0
  9. package/config/jest.config.json +16 -0
  10. package/config/jest.setup.js +64 -0
  11. package/config/rig.json +16 -0
  12. package/lib/components/common/QualifierContextControl.d.ts +14 -0
  13. package/lib/components/common/QualifierContextControl.d.ts.map +1 -0
  14. package/lib/components/common/QualifierContextControl.js +78 -0
  15. package/lib/components/common/QualifierContextControl.js.map +1 -0
  16. package/lib/components/common/ResourceListView.d.ts +11 -0
  17. package/lib/components/common/ResourceListView.d.ts.map +1 -0
  18. package/lib/components/common/ResourceListView.js +20 -0
  19. package/lib/components/common/ResourceListView.js.map +1 -0
  20. package/lib/components/common/ResourceTreeView.d.ts +12 -0
  21. package/lib/components/common/ResourceTreeView.d.ts.map +1 -0
  22. package/lib/components/common/ResourceTreeView.js +162 -0
  23. package/lib/components/common/ResourceTreeView.js.map +1 -0
  24. package/lib/components/forms/HierarchyEditor.d.ts +10 -0
  25. package/lib/components/forms/HierarchyEditor.d.ts.map +1 -0
  26. package/lib/components/forms/HierarchyEditor.js +106 -0
  27. package/lib/components/forms/HierarchyEditor.js.map +1 -0
  28. package/lib/components/forms/QualifierEditForm.d.ts +11 -0
  29. package/lib/components/forms/QualifierEditForm.d.ts.map +1 -0
  30. package/lib/components/forms/QualifierEditForm.js +181 -0
  31. package/lib/components/forms/QualifierEditForm.js.map +1 -0
  32. package/lib/components/forms/QualifierTypeEditForm.d.ts +10 -0
  33. package/lib/components/forms/QualifierTypeEditForm.d.ts.map +1 -0
  34. package/lib/components/forms/QualifierTypeEditForm.js +172 -0
  35. package/lib/components/forms/QualifierTypeEditForm.js.map +1 -0
  36. package/lib/components/forms/ResourceTypeEditForm.d.ts +10 -0
  37. package/lib/components/forms/ResourceTypeEditForm.d.ts.map +1 -0
  38. package/lib/components/forms/ResourceTypeEditForm.js +188 -0
  39. package/lib/components/forms/ResourceTypeEditForm.js.map +1 -0
  40. package/lib/components/forms/index.d.ts +9 -0
  41. package/lib/components/forms/index.d.ts.map +1 -0
  42. package/lib/components/forms/index.js +5 -0
  43. package/lib/components/forms/index.js.map +1 -0
  44. package/lib/components/orchestrator/ResourceOrchestrator.d.ts +14 -0
  45. package/lib/components/orchestrator/ResourceOrchestrator.d.ts.map +1 -0
  46. package/lib/components/orchestrator/ResourceOrchestrator.js +278 -0
  47. package/lib/components/orchestrator/ResourceOrchestrator.js.map +1 -0
  48. package/lib/components/views/CompiledView/index.d.ts +5 -0
  49. package/lib/components/views/CompiledView/index.d.ts.map +1 -0
  50. package/lib/components/views/CompiledView/index.js +595 -0
  51. package/lib/components/views/CompiledView/index.js.map +1 -0
  52. package/lib/components/views/ConfigurationView/index.d.ts +5 -0
  53. package/lib/components/views/ConfigurationView/index.d.ts.map +1 -0
  54. package/lib/components/views/ConfigurationView/index.js +363 -0
  55. package/lib/components/views/ConfigurationView/index.js.map +1 -0
  56. package/lib/components/views/FilterView/index.d.ts +5 -0
  57. package/lib/components/views/FilterView/index.d.ts.map +1 -0
  58. package/lib/components/views/FilterView/index.js +463 -0
  59. package/lib/components/views/FilterView/index.js.map +1 -0
  60. package/lib/components/views/ImportView/index.d.ts +5 -0
  61. package/lib/components/views/ImportView/index.d.ts.map +1 -0
  62. package/lib/components/views/ImportView/index.js +514 -0
  63. package/lib/components/views/ImportView/index.js.map +1 -0
  64. package/lib/components/views/ResolutionView/EditableJsonView.d.ts +21 -0
  65. package/lib/components/views/ResolutionView/EditableJsonView.d.ts.map +1 -0
  66. package/lib/components/views/ResolutionView/EditableJsonView.js +109 -0
  67. package/lib/components/views/ResolutionView/EditableJsonView.js.map +1 -0
  68. package/lib/components/views/ResolutionView/ResolutionEditControls.d.ts +19 -0
  69. package/lib/components/views/ResolutionView/ResolutionEditControls.d.ts.map +1 -0
  70. package/lib/components/views/ResolutionView/ResolutionEditControls.js +82 -0
  71. package/lib/components/views/ResolutionView/ResolutionEditControls.js.map +1 -0
  72. package/lib/components/views/ResolutionView/index.d.ts +5 -0
  73. package/lib/components/views/ResolutionView/index.d.ts.map +1 -0
  74. package/lib/components/views/ResolutionView/index.js +255 -0
  75. package/lib/components/views/ResolutionView/index.js.map +1 -0
  76. package/lib/components/views/SourceView/index.d.ts +5 -0
  77. package/lib/components/views/SourceView/index.d.ts.map +1 -0
  78. package/lib/components/views/SourceView/index.js +316 -0
  79. package/lib/components/views/SourceView/index.js.map +1 -0
  80. package/lib/components/views/ZipLoaderView/index.d.ts +5 -0
  81. package/lib/components/views/ZipLoaderView/index.d.ts.map +1 -0
  82. package/lib/components/views/ZipLoaderView/index.js +313 -0
  83. package/lib/components/views/ZipLoaderView/index.js.map +1 -0
  84. package/lib/hooks/useConfigurationState.d.ts +46 -0
  85. package/lib/hooks/useConfigurationState.d.ts.map +1 -0
  86. package/lib/hooks/useConfigurationState.js +239 -0
  87. package/lib/hooks/useConfigurationState.js.map +1 -0
  88. package/lib/hooks/useFilterState.d.ts +7 -0
  89. package/lib/hooks/useFilterState.d.ts.map +1 -0
  90. package/lib/hooks/useFilterState.js +80 -0
  91. package/lib/hooks/useFilterState.js.map +1 -0
  92. package/lib/hooks/useResolutionState.d.ts +8 -0
  93. package/lib/hooks/useResolutionState.d.ts.map +1 -0
  94. package/lib/hooks/useResolutionState.js +253 -0
  95. package/lib/hooks/useResolutionState.js.map +1 -0
  96. package/lib/hooks/useResourceData.d.ts +19 -0
  97. package/lib/hooks/useResourceData.d.ts.map +1 -0
  98. package/lib/hooks/useResourceData.js +368 -0
  99. package/lib/hooks/useResourceData.js.map +1 -0
  100. package/lib/hooks/useViewState.d.ts +10 -0
  101. package/lib/hooks/useViewState.d.ts.map +1 -0
  102. package/lib/hooks/useViewState.js +29 -0
  103. package/lib/hooks/useViewState.js.map +1 -0
  104. package/lib/index.d.ts +27 -0
  105. package/lib/index.d.ts.map +1 -0
  106. package/lib/index.js +34 -0
  107. package/lib/index.js.map +1 -0
  108. package/lib/test/helpers/testDataLoader.d.ts +37 -0
  109. package/lib/test/helpers/testDataLoader.d.ts.map +1 -0
  110. package/lib/test/helpers/testDataLoader.js +171 -0
  111. package/lib/test/helpers/testDataLoader.js.map +1 -0
  112. package/lib/test/unit/utils/configurationUtils.test.d.ts +2 -0
  113. package/lib/test/unit/utils/configurationUtils.test.d.ts.map +1 -0
  114. package/lib/test/unit/utils/configurationUtils.test.js +497 -0
  115. package/lib/test/unit/utils/configurationUtils.test.js.map +1 -0
  116. package/lib/test/unit/utils/fileProcessing.test.d.ts +2 -0
  117. package/lib/test/unit/utils/fileProcessing.test.d.ts.map +1 -0
  118. package/lib/test/unit/utils/fileProcessing.test.js +321 -0
  119. package/lib/test/unit/utils/fileProcessing.test.js.map +1 -0
  120. package/lib/test/unit/utils/filterResources.test.d.ts +2 -0
  121. package/lib/test/unit/utils/filterResources.test.d.ts.map +1 -0
  122. package/lib/test/unit/utils/filterResources.test.js +403 -0
  123. package/lib/test/unit/utils/filterResources.test.js.map +1 -0
  124. package/lib/test/unit/utils/resolutionEditing.test.d.ts +2 -0
  125. package/lib/test/unit/utils/resolutionEditing.test.d.ts.map +1 -0
  126. package/lib/test/unit/utils/resolutionEditing.test.js +439 -0
  127. package/lib/test/unit/utils/resolutionEditing.test.js.map +1 -0
  128. package/lib/test/unit/utils/resolutionUtils.test.d.ts +2 -0
  129. package/lib/test/unit/utils/resolutionUtils.test.d.ts.map +1 -0
  130. package/lib/test/unit/utils/resolutionUtils.test.js +397 -0
  131. package/lib/test/unit/utils/resolutionUtils.test.js.map +1 -0
  132. package/lib/test/unit/utils/tsResIntegration.test.d.ts +2 -0
  133. package/lib/test/unit/utils/tsResIntegration.test.d.ts.map +1 -0
  134. package/lib/test/unit/utils/tsResIntegration.test.js +376 -0
  135. package/lib/test/unit/utils/tsResIntegration.test.js.map +1 -0
  136. package/lib/types/index.d.ts +251 -0
  137. package/lib/types/index.d.ts.map +1 -0
  138. package/lib/types/index.js +2 -0
  139. package/lib/types/index.js.map +1 -0
  140. package/lib/utils/configurationUtils.d.ts +74 -0
  141. package/lib/utils/configurationUtils.d.ts.map +1 -0
  142. package/lib/utils/configurationUtils.js +359 -0
  143. package/lib/utils/configurationUtils.js.map +1 -0
  144. package/lib/utils/fileProcessing.d.ts +18 -0
  145. package/lib/utils/fileProcessing.d.ts.map +1 -0
  146. package/lib/utils/fileProcessing.js +142 -0
  147. package/lib/utils/fileProcessing.js.map +1 -0
  148. package/lib/utils/filterResources.d.ts +38 -0
  149. package/lib/utils/filterResources.d.ts.map +1 -0
  150. package/lib/utils/filterResources.js +153 -0
  151. package/lib/utils/filterResources.js.map +1 -0
  152. package/lib/utils/resolutionEditing.d.ts +58 -0
  153. package/lib/utils/resolutionEditing.d.ts.map +1 -0
  154. package/lib/utils/resolutionEditing.js +246 -0
  155. package/lib/utils/resolutionEditing.js.map +1 -0
  156. package/lib/utils/resolutionUtils.d.ts +28 -0
  157. package/lib/utils/resolutionUtils.d.ts.map +1 -0
  158. package/lib/utils/resolutionUtils.js +216 -0
  159. package/lib/utils/resolutionUtils.js.map +1 -0
  160. package/lib/utils/tsResIntegration.d.ts +71 -0
  161. package/lib/utils/tsResIntegration.d.ts.map +1 -0
  162. package/lib/utils/tsResIntegration.js +294 -0
  163. package/lib/utils/tsResIntegration.js.map +1 -0
  164. package/lib/utils/zipLoader/browserZipLoader.d.ts +48 -0
  165. package/lib/utils/zipLoader/browserZipLoader.d.ts.map +1 -0
  166. package/lib/utils/zipLoader/browserZipLoader.js +247 -0
  167. package/lib/utils/zipLoader/browserZipLoader.js.map +1 -0
  168. package/lib/utils/zipLoader/index.d.ts +8 -0
  169. package/lib/utils/zipLoader/index.d.ts.map +1 -0
  170. package/lib/utils/zipLoader/index.js +13 -0
  171. package/lib/utils/zipLoader/index.js.map +1 -0
  172. package/lib/utils/zipLoader/nodeZipBuilder.d.ts +55 -0
  173. package/lib/utils/zipLoader/nodeZipBuilder.d.ts.map +1 -0
  174. package/lib/utils/zipLoader/nodeZipBuilder.js +98 -0
  175. package/lib/utils/zipLoader/nodeZipBuilder.js.map +1 -0
  176. package/lib/utils/zipLoader/types.d.ts +139 -0
  177. package/lib/utils/zipLoader/types.d.ts.map +1 -0
  178. package/lib/utils/zipLoader/types.js +2 -0
  179. package/lib/utils/zipLoader/types.js.map +1 -0
  180. package/lib/utils/zipLoader/zipUtils.d.ts +53 -0
  181. package/lib/utils/zipLoader/zipUtils.d.ts.map +1 -0
  182. package/lib/utils/zipLoader/zipUtils.js +229 -0
  183. package/lib/utils/zipLoader/zipUtils.js.map +1 -0
  184. package/package.json +69 -0
  185. package/rush-logs/ts-res-ui-components.build.cache.log +3 -0
  186. package/rush-logs/ts-res-ui-components.build.log +9 -0
  187. package/src/components/common/QualifierContextControl.tsx +151 -0
  188. package/src/components/common/ResourceListView.tsx +63 -0
  189. package/src/components/common/ResourceTreeView.tsx +271 -0
  190. package/src/components/forms/HierarchyEditor.tsx +204 -0
  191. package/src/components/forms/QualifierEditForm.tsx +355 -0
  192. package/src/components/forms/QualifierTypeEditForm.tsx +347 -0
  193. package/src/components/forms/ResourceTypeEditForm.tsx +331 -0
  194. package/src/components/forms/index.ts +11 -0
  195. package/src/components/orchestrator/ResourceOrchestrator.tsx +372 -0
  196. package/src/components/views/CompiledView/index.tsx +922 -0
  197. package/src/components/views/ConfigurationView/index.tsx +800 -0
  198. package/src/components/views/FilterView/index.tsx +825 -0
  199. package/src/components/views/ImportView/index.tsx +717 -0
  200. package/src/components/views/ResolutionView/EditableJsonView.tsx +214 -0
  201. package/src/components/views/ResolutionView/ResolutionEditControls.tsx +170 -0
  202. package/src/components/views/ResolutionView/index.tsx +591 -0
  203. package/src/components/views/SourceView/index.tsx +536 -0
  204. package/src/components/views/ZipLoaderView/index.tsx +485 -0
  205. package/src/hooks/useConfigurationState.ts +374 -0
  206. package/src/hooks/useFilterState.ts +97 -0
  207. package/src/hooks/useResolutionState.ts +355 -0
  208. package/src/hooks/useResourceData.ts +467 -0
  209. package/src/hooks/useViewState.ts +44 -0
  210. package/src/index.ts +45 -0
  211. package/src/test/helpers/testDataLoader.ts +195 -0
  212. package/src/test/unit/utils/configurationUtils.test.ts +630 -0
  213. package/src/test/unit/utils/fileProcessing.test.ts +391 -0
  214. package/src/test/unit/utils/filterResources.test.ts +574 -0
  215. package/src/test/unit/utils/resolutionEditing.test.ts +556 -0
  216. package/src/test/unit/utils/resolutionUtils.test.ts +521 -0
  217. package/src/test/unit/utils/tsResIntegration.test.ts +433 -0
  218. package/src/types/index.ts +322 -0
  219. package/src/utils/configurationUtils.ts +424 -0
  220. package/src/utils/fileProcessing.ts +160 -0
  221. package/src/utils/filterResources.ts +206 -0
  222. package/src/utils/resolutionEditing.ts +319 -0
  223. package/src/utils/resolutionUtils.ts +289 -0
  224. package/src/utils/tsResIntegration.ts +440 -0
  225. package/src/utils/zipLoader/browserZipLoader.ts +319 -0
  226. package/src/utils/zipLoader/index.ts +26 -0
  227. package/src/utils/zipLoader/nodeZipBuilder.ts +153 -0
  228. package/src/utils/zipLoader/types.ts +175 -0
  229. package/src/utils/zipLoader/zipUtils.ts +266 -0
  230. package/temp/build/typescript/ts_gZid87Hu.json +1 -0
  231. package/tsconfig.json +15 -0
@@ -0,0 +1,514 @@
1
+ import React, { useState, useCallback, useRef } from 'react';
2
+ import { DocumentArrowUpIcon, CheckCircleIcon, ExclamationTriangleIcon, ArchiveBoxIcon, FolderOpenIcon } from '@heroicons/react/24/outline';
3
+ import { Bundle } from '@fgv/ts-res';
4
+ import { isZipFile } from '../../../utils/zipLoader';
5
+ export const ImportView = ({ onImport, onBundleImport, onZipImport, acceptedFileTypes = ['.json', '.zip'], onMessage, className = '' }) => {
6
+ const [isLoading, setIsLoading] = useState(false);
7
+ const [importStatus, setImportStatus] = useState({
8
+ hasImported: false,
9
+ fileCount: 0,
10
+ isDirectory: false,
11
+ isBundle: false,
12
+ isZip: false
13
+ });
14
+ const [error, setError] = useState(null);
15
+ const fileInputRef = useRef(null);
16
+ const dirInputRef = useRef(null);
17
+ // Check for File System Access API support
18
+ const isFileSystemAccessSupported = 'showDirectoryPicker' in window || 'showOpenFilePicker' in window;
19
+ // Handle file selection
20
+ const handleFileSelect = useCallback(async (event) => {
21
+ const files = event.target.files;
22
+ if (!files || files.length === 0)
23
+ return;
24
+ setIsLoading(true);
25
+ setError(null);
26
+ try {
27
+ // Handle single file selection - check file type first
28
+ if (files.length === 1) {
29
+ const file = files[0];
30
+ // Check if it's a ZIP file first
31
+ if (isZipFile(file.name)) {
32
+ console.log(`[ImportView] ✅ ${file.name} detected as ZIP file`);
33
+ onMessage?.('info', `Processing ZIP file: ${file.name}`);
34
+ // Just pass the File object directly to onZipImport
35
+ // The App will handle creating the FileTree
36
+ if (onZipImport) {
37
+ setImportStatus({
38
+ hasImported: true,
39
+ fileCount: 1,
40
+ isDirectory: false,
41
+ isBundle: false,
42
+ isZip: true
43
+ });
44
+ onMessage?.('success', `ZIP file detected: ${file.name}`);
45
+ onZipImport(file, undefined);
46
+ setIsLoading(false);
47
+ return;
48
+ }
49
+ else {
50
+ throw new Error('No ZIP import handler configured');
51
+ }
52
+ }
53
+ }
54
+ // Handle regular files (non-ZIP)
55
+ const importedFiles = [];
56
+ let bundleFile;
57
+ for (let i = 0; i < files.length; i++) {
58
+ const file = files[i];
59
+ const content = await readFileContent(file);
60
+ const importedFile = {
61
+ name: file.name,
62
+ path: file.webkitRelativePath || file.name,
63
+ content,
64
+ type: file.type
65
+ };
66
+ // Check if it's a bundle file using proper detection
67
+ let isCurrentFileBundle = false;
68
+ try {
69
+ const parsedData = JSON.parse(content);
70
+ console.log(`[ImportView] Checking if ${file.name} is a bundle...`);
71
+ // Use BundleUtils for proper bundle detection
72
+ if (Bundle.BundleUtils.isBundleFile(parsedData)) {
73
+ console.log(`[ImportView] ✅ ${file.name} detected as bundle file`);
74
+ bundleFile = { ...importedFile, bundle: parsedData };
75
+ isCurrentFileBundle = true;
76
+ }
77
+ else if (Bundle.BundleUtils.isBundleFileName(file.name)) {
78
+ // File name suggests it's a bundle, but content doesn't match - log a warning
79
+ console.warn(`[ImportView] ⚠️ File ${file.name} appears to be a bundle by name but content doesn't match bundle structure`);
80
+ }
81
+ else {
82
+ console.log(`[ImportView] ❌ ${file.name} is not a bundle file`);
83
+ }
84
+ }
85
+ catch (parseError) {
86
+ console.log(`[ImportView] ❌ ${file.name} failed JSON parsing:`, parseError);
87
+ // Not valid JSON or not a bundle, treat as regular file
88
+ }
89
+ // Only add to regular files if this specific file is not a bundle
90
+ if (!isCurrentFileBundle) {
91
+ importedFiles.push(importedFile);
92
+ }
93
+ }
94
+ // Process results
95
+ if (bundleFile) {
96
+ console.log(`[ImportView] Processing bundle file: ${bundleFile.name}`, bundleFile.bundle);
97
+ setImportStatus({
98
+ hasImported: true,
99
+ fileCount: 1,
100
+ isDirectory: false,
101
+ isBundle: true,
102
+ isZip: false
103
+ });
104
+ onMessage?.('info', `Bundle file detected: ${bundleFile.name}`);
105
+ if (onBundleImport && bundleFile.bundle) {
106
+ console.log(`[ImportView] Calling onBundleImport with bundle data`);
107
+ onBundleImport(bundleFile.bundle);
108
+ }
109
+ else {
110
+ console.warn(`[ImportView] No bundle import handler or bundle data missing`);
111
+ }
112
+ }
113
+ else if (importedFiles.length > 0) {
114
+ setImportStatus({
115
+ hasImported: true,
116
+ fileCount: importedFiles.length,
117
+ isDirectory: false,
118
+ isBundle: false,
119
+ isZip: false
120
+ });
121
+ onMessage?.('success', `Imported ${importedFiles.length} file(s)`);
122
+ onImport?.(importedFiles);
123
+ }
124
+ }
125
+ catch (err) {
126
+ const errorMsg = err instanceof Error ? err.message : String(err);
127
+ setError(errorMsg);
128
+ onMessage?.('error', `Import failed: ${errorMsg}`);
129
+ }
130
+ finally {
131
+ setIsLoading(false);
132
+ // Reset input
133
+ if (event.target) {
134
+ event.target.value = '';
135
+ }
136
+ }
137
+ }, [onImport, onBundleImport, onMessage]);
138
+ // Handle directory selection (for browsers with webkitdirectory support)
139
+ const handleDirectorySelect = useCallback(async (event) => {
140
+ const files = event.target.files;
141
+ if (!files || files.length === 0)
142
+ return;
143
+ setIsLoading(true);
144
+ setError(null);
145
+ try {
146
+ const filesByPath = new Map();
147
+ const dirPaths = new Set();
148
+ for (let i = 0; i < files.length; i++) {
149
+ const file = files[i];
150
+ const content = await readFileContent(file);
151
+ const path = file.webkitRelativePath;
152
+ if (path) {
153
+ const parts = path.split('/');
154
+ const dirPath = parts.slice(0, -1).join('/');
155
+ dirPaths.add(dirPath);
156
+ if (!filesByPath.has(dirPath)) {
157
+ filesByPath.set(dirPath, []);
158
+ }
159
+ filesByPath.get(dirPath).push({
160
+ name: parts[parts.length - 1],
161
+ path: path,
162
+ content,
163
+ type: file.type
164
+ });
165
+ }
166
+ }
167
+ // Build directory structure
168
+ const rootDir = {
169
+ name: 'imported',
170
+ files: filesByPath.get('') || [],
171
+ subdirectories: []
172
+ };
173
+ // Create subdirectories
174
+ const sortedPaths = Array.from(dirPaths).sort();
175
+ for (const dirPath of sortedPaths) {
176
+ if (dirPath && dirPath !== '') {
177
+ const parts = dirPath.split('/');
178
+ let currentLevel = rootDir;
179
+ for (let i = 0; i < parts.length; i++) {
180
+ const part = parts[i];
181
+ const currentPath = parts.slice(0, i + 1).join('/');
182
+ if (!currentLevel.subdirectories) {
183
+ currentLevel.subdirectories = [];
184
+ }
185
+ let subdir = currentLevel.subdirectories.find((d) => d.name === part);
186
+ if (!subdir) {
187
+ subdir = {
188
+ name: part,
189
+ path: currentPath,
190
+ files: filesByPath.get(currentPath) || [],
191
+ subdirectories: []
192
+ };
193
+ currentLevel.subdirectories.push(subdir);
194
+ }
195
+ currentLevel = subdir;
196
+ }
197
+ }
198
+ }
199
+ setImportStatus({
200
+ hasImported: true,
201
+ fileCount: files.length,
202
+ isDirectory: true,
203
+ isBundle: false,
204
+ isZip: false
205
+ });
206
+ onMessage?.('success', `Imported directory with ${files.length} file(s)`);
207
+ onImport?.(rootDir);
208
+ }
209
+ catch (err) {
210
+ const errorMsg = err instanceof Error ? err.message : String(err);
211
+ setError(errorMsg);
212
+ onMessage?.('error', `Directory import failed: ${errorMsg}`);
213
+ }
214
+ finally {
215
+ setIsLoading(false);
216
+ // Reset input
217
+ if (event.target) {
218
+ event.target.value = '';
219
+ }
220
+ }
221
+ }, [onImport, onMessage]);
222
+ // Modern File System Access API handlers
223
+ const handleModernDirectoryPick = useCallback(async () => {
224
+ if (!('showDirectoryPicker' in window)) {
225
+ onMessage?.('error', 'Directory picker not supported in this browser');
226
+ return;
227
+ }
228
+ setIsLoading(true);
229
+ setError(null);
230
+ try {
231
+ const dirHandle = await window.showDirectoryPicker();
232
+ const rootDir = await processDirectoryHandle(dirHandle);
233
+ const fileCount = countFiles(rootDir);
234
+ setImportStatus({
235
+ hasImported: true,
236
+ fileCount,
237
+ isDirectory: true,
238
+ isBundle: false,
239
+ isZip: false
240
+ });
241
+ onMessage?.('success', `Imported directory "${rootDir.name}" with ${fileCount} file(s)`);
242
+ onImport?.(rootDir);
243
+ }
244
+ catch (err) {
245
+ if (err.name !== 'AbortError') {
246
+ const errorMsg = err instanceof Error ? err.message : String(err);
247
+ setError(errorMsg);
248
+ onMessage?.('error', `Directory import failed: ${errorMsg}`);
249
+ }
250
+ }
251
+ finally {
252
+ setIsLoading(false);
253
+ }
254
+ }, [onImport, onMessage]);
255
+ const handleModernFilePick = useCallback(async () => {
256
+ if (!('showOpenFilePicker' in window)) {
257
+ onMessage?.('error', 'File picker not supported in this browser');
258
+ return;
259
+ }
260
+ setIsLoading(true);
261
+ setError(null);
262
+ try {
263
+ const fileHandles = await window.showOpenFilePicker({
264
+ multiple: true,
265
+ types: [
266
+ {
267
+ description: 'Resource files',
268
+ accept: {
269
+ 'application/json': ['.json'],
270
+ 'application/zip': ['.zip']
271
+ }
272
+ }
273
+ ]
274
+ });
275
+ // Check if we have a single ZIP file first
276
+ if (fileHandles.length === 1) {
277
+ const file = await fileHandles[0].getFile();
278
+ if (isZipFile(file.name)) {
279
+ console.log(`[ImportView] Modern API - ✅ ${file.name} detected as ZIP file`);
280
+ onMessage?.('info', `Processing ZIP file: ${file.name}`);
281
+ if (onZipImport) {
282
+ setImportStatus({
283
+ hasImported: true,
284
+ fileCount: 1,
285
+ isDirectory: false,
286
+ isBundle: false,
287
+ isZip: true
288
+ });
289
+ onMessage?.('success', `ZIP file detected: ${file.name}`);
290
+ onZipImport(file, undefined);
291
+ setIsLoading(false);
292
+ return;
293
+ }
294
+ else {
295
+ throw new Error('No ZIP import handler configured');
296
+ }
297
+ }
298
+ }
299
+ const importedFiles = [];
300
+ let bundleFile;
301
+ for (const fileHandle of fileHandles) {
302
+ const file = await fileHandle.getFile();
303
+ // Skip ZIP files in multi-file selection
304
+ if (isZipFile(file.name)) {
305
+ onMessage?.('warning', `Skipping ZIP file ${file.name} - select it individually to import`);
306
+ continue;
307
+ }
308
+ const content = await file.text();
309
+ const importedFile = {
310
+ name: file.name,
311
+ content,
312
+ type: file.type
313
+ };
314
+ // Check for bundle using proper detection
315
+ let isCurrentFileBundle = false;
316
+ try {
317
+ const parsedData = JSON.parse(content);
318
+ console.log(`[ImportView] Modern API - Checking if ${file.name} is a bundle...`);
319
+ // Use BundleUtils for proper bundle detection
320
+ if (Bundle.BundleUtils.isBundleFile(parsedData)) {
321
+ console.log(`[ImportView] Modern API - ✅ ${file.name} detected as bundle file`);
322
+ bundleFile = { ...importedFile, bundle: parsedData };
323
+ isCurrentFileBundle = true;
324
+ }
325
+ else if (Bundle.BundleUtils.isBundleFileName(file.name)) {
326
+ console.warn(`[ImportView] Modern API - ⚠️ File ${file.name} appears to be a bundle by name but content doesn't match bundle structure`);
327
+ }
328
+ else {
329
+ console.log(`[ImportView] Modern API - ❌ ${file.name} is not a bundle file`);
330
+ }
331
+ }
332
+ catch (parseError) {
333
+ console.log(`[ImportView] Modern API - ❌ ${file.name} failed JSON parsing:`, parseError);
334
+ }
335
+ // Only add to regular files if this specific file is not a bundle
336
+ if (!isCurrentFileBundle) {
337
+ importedFiles.push(importedFile);
338
+ }
339
+ }
340
+ // Process results
341
+ if (bundleFile) {
342
+ setImportStatus({
343
+ hasImported: true,
344
+ fileCount: 1,
345
+ isDirectory: false,
346
+ isBundle: true,
347
+ isZip: false
348
+ });
349
+ onMessage?.('info', `Bundle file detected: ${bundleFile.name}`);
350
+ if (onBundleImport && bundleFile.bundle) {
351
+ onBundleImport(bundleFile.bundle);
352
+ }
353
+ }
354
+ else if (importedFiles.length > 0) {
355
+ setImportStatus({
356
+ hasImported: true,
357
+ fileCount: importedFiles.length,
358
+ isDirectory: false,
359
+ isBundle: false,
360
+ isZip: false
361
+ });
362
+ onMessage?.('success', `Imported ${importedFiles.length} file(s)`);
363
+ onImport?.(importedFiles);
364
+ }
365
+ }
366
+ catch (err) {
367
+ if (err.name !== 'AbortError') {
368
+ const errorMsg = err instanceof Error ? err.message : String(err);
369
+ setError(errorMsg);
370
+ onMessage?.('error', `File import failed: ${errorMsg}`);
371
+ }
372
+ }
373
+ finally {
374
+ setIsLoading(false);
375
+ }
376
+ }, [onImport, onBundleImport, onMessage, acceptedFileTypes]);
377
+ const handleReset = useCallback(() => {
378
+ setImportStatus({
379
+ hasImported: false,
380
+ fileCount: 0,
381
+ isDirectory: false,
382
+ isBundle: false,
383
+ isZip: false
384
+ });
385
+ setError(null);
386
+ onMessage?.('info', 'Import cleared');
387
+ }, [onMessage]);
388
+ return (React.createElement("div", { className: `p-6 ${className}` },
389
+ React.createElement("div", { className: "flex items-center space-x-3 mb-6" },
390
+ React.createElement(DocumentArrowUpIcon, { className: "h-8 w-8 text-blue-600" }),
391
+ React.createElement("h2", { className: "text-2xl font-bold text-gray-900" }, "Import Resources")),
392
+ React.createElement("div", { className: "grid grid-cols-1 lg:grid-cols-2 gap-6" },
393
+ React.createElement("div", { className: "bg-white rounded-lg shadow-sm border border-gray-200 p-6" },
394
+ React.createElement("h3", { className: "text-lg font-semibold text-gray-900 mb-4" }, "Import Files"),
395
+ React.createElement("div", { className: "space-y-4" },
396
+ React.createElement("div", { className: "flex items-center space-x-2 text-sm text-gray-600" }, isFileSystemAccessSupported ? (React.createElement(React.Fragment, null,
397
+ React.createElement("div", { className: "w-2 h-2 bg-green-500 rounded-full" }),
398
+ React.createElement("span", null, "Modern File System API available"))) : (React.createElement(React.Fragment, null,
399
+ React.createElement("div", { className: "w-2 h-2 bg-yellow-500 rounded-full" }),
400
+ React.createElement("span", null, "Using fallback file input")))),
401
+ React.createElement("div", { className: "flex flex-col space-y-3" }, isFileSystemAccessSupported ? (React.createElement(React.Fragment, null,
402
+ React.createElement("button", { onClick: handleModernDirectoryPick, disabled: isLoading, className: "flex items-center justify-center space-x-2 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors" },
403
+ React.createElement(FolderOpenIcon, { className: "w-5 h-5" }),
404
+ React.createElement("span", null, isLoading ? 'Importing...' : 'Import Resource Directory')),
405
+ React.createElement("button", { onClick: handleModernFilePick, disabled: isLoading, className: "flex items-center justify-center space-x-2 px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors" },
406
+ React.createElement(DocumentArrowUpIcon, { className: "w-5 h-5" }),
407
+ React.createElement("span", null, isLoading ? 'Importing...' : 'Import Resource Files')))) : (React.createElement(React.Fragment, null,
408
+ React.createElement("input", { ref: dirInputRef, type: "file",
409
+ // @ts-ignore - webkitdirectory is not in types
410
+ webkitdirectory: "", directory: "", multiple: true, onChange: handleDirectorySelect, className: "hidden" }),
411
+ React.createElement("button", { onClick: () => dirInputRef.current?.click(), disabled: isLoading, className: "flex items-center justify-center space-x-2 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors" },
412
+ React.createElement(FolderOpenIcon, { className: "w-5 h-5" }),
413
+ React.createElement("span", null, isLoading ? 'Importing...' : 'Import Resource Directory')),
414
+ React.createElement("input", { ref: fileInputRef, type: "file", accept: acceptedFileTypes.join(','), multiple: true, onChange: handleFileSelect, className: "hidden" }),
415
+ React.createElement("button", { onClick: () => fileInputRef.current?.click(), disabled: isLoading, className: "flex items-center justify-center space-x-2 px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors" },
416
+ React.createElement(DocumentArrowUpIcon, { className: "w-5 h-5" }),
417
+ React.createElement("span", null, isLoading ? 'Importing...' : 'Import Resource Files'))))),
418
+ React.createElement("div", { className: "text-sm text-gray-600 space-y-2" },
419
+ React.createElement("p", { className: "font-medium" }, "Import Options:"),
420
+ React.createElement("ul", { className: "list-disc list-inside space-y-1 ml-2" },
421
+ React.createElement("li", null,
422
+ React.createElement("strong", null, "Directory:"),
423
+ " Select a folder with ts-res resources"),
424
+ React.createElement("li", null,
425
+ React.createElement("strong", null, "Files:"),
426
+ " Select individual JSON resource files"),
427
+ React.createElement("li", null,
428
+ React.createElement("strong", null, "Bundles:"),
429
+ " Automatically detected and loaded"))))),
430
+ React.createElement("div", { className: "space-y-6" },
431
+ React.createElement("div", { className: "bg-white rounded-lg shadow-sm border border-gray-200 p-6" },
432
+ React.createElement("h3", { className: "text-lg font-semibold text-gray-900 mb-4" }, "Import Status"),
433
+ React.createElement("div", { className: "space-y-3" },
434
+ React.createElement("div", { className: "flex items-center space-x-3" }, importStatus.hasImported ? (React.createElement(React.Fragment, null,
435
+ React.createElement(CheckCircleIcon, { className: "w-5 h-5 text-green-500" }),
436
+ React.createElement("span", { className: "text-sm text-gray-900" }, importStatus.isBundle
437
+ ? 'Bundle imported'
438
+ : importStatus.isZip
439
+ ? 'ZIP archive imported'
440
+ : importStatus.isDirectory
441
+ ? 'Directory imported'
442
+ : `${importStatus.fileCount} file(s) imported`))) : (React.createElement(React.Fragment, null,
443
+ React.createElement("div", { className: "w-5 h-5 rounded-full border-2 border-gray-300" }),
444
+ React.createElement("span", { className: "text-sm text-gray-500" }, "No files imported yet")))),
445
+ importStatus.isBundle && (React.createElement("div", { className: "flex items-center space-x-3" },
446
+ React.createElement(ArchiveBoxIcon, { className: "w-5 h-5 text-blue-500" }),
447
+ React.createElement("span", { className: "text-sm text-blue-900" }, "Bundle file detected"))),
448
+ importStatus.isZip && (React.createElement("div", { className: "flex items-center space-x-3" },
449
+ React.createElement(ArchiveBoxIcon, { className: "w-5 h-5 text-purple-500" }),
450
+ React.createElement("span", { className: "text-sm text-purple-900" }, "ZIP archive processed")))),
451
+ importStatus.hasImported && (React.createElement("button", { onClick: handleReset, className: "mt-4 px-4 py-2 text-sm bg-gray-100 text-gray-700 rounded-lg hover:bg-gray-200 transition-colors" }, "Clear Import"))),
452
+ error && (React.createElement("div", { className: "bg-white rounded-lg shadow-sm border border-red-200 p-6" },
453
+ React.createElement("div", { className: "flex items-start space-x-2" },
454
+ React.createElement(ExclamationTriangleIcon, { className: "w-5 h-5 text-red-600 mt-0.5" }),
455
+ React.createElement("div", { className: "text-sm text-red-800" },
456
+ React.createElement("p", { className: "font-medium" }, "Error"),
457
+ React.createElement("p", null, error))))),
458
+ importStatus.hasImported && !error && (React.createElement("div", { className: "bg-white rounded-lg shadow-sm border border-green-200 p-6" },
459
+ React.createElement("div", { className: "flex items-start space-x-2" },
460
+ React.createElement(CheckCircleIcon, { className: "w-5 h-5 text-green-600 mt-0.5" }),
461
+ React.createElement("div", { className: "text-sm text-green-800" },
462
+ React.createElement("p", { className: "font-medium" }, "Import Successful!"),
463
+ React.createElement("p", null, importStatus.isBundle
464
+ ? 'Bundle resources are ready to browse.'
465
+ : importStatus.isZip
466
+ ? 'ZIP archive contents have been imported and are ready for processing.'
467
+ : 'Resources are ready for processing.')))))))));
468
+ };
469
+ // Helper functions
470
+ async function readFileContent(file) {
471
+ return new Promise((resolve, reject) => {
472
+ const reader = new FileReader();
473
+ reader.onload = (e) => resolve(e.target?.result);
474
+ reader.onerror = (e) => reject(new Error(`Failed to read file: ${file.name}`));
475
+ reader.readAsText(file);
476
+ });
477
+ }
478
+ async function processDirectoryHandle(dirHandle, parentPath = '') {
479
+ const files = [];
480
+ const subdirectories = [];
481
+ for await (const entry of dirHandle.values()) {
482
+ if (entry.kind === 'file') {
483
+ const file = await entry.getFile();
484
+ const content = await file.text();
485
+ files.push({
486
+ name: file.name,
487
+ path: parentPath ? `${parentPath}/${file.name}` : file.name,
488
+ content,
489
+ type: file.type
490
+ });
491
+ }
492
+ else if (entry.kind === 'directory') {
493
+ const subdir = await processDirectoryHandle(entry, parentPath ? `${parentPath}/${entry.name}` : entry.name);
494
+ subdirectories.push(subdir);
495
+ }
496
+ }
497
+ return {
498
+ name: dirHandle.name,
499
+ path: parentPath,
500
+ files,
501
+ subdirectories: subdirectories.length > 0 ? subdirectories : undefined
502
+ };
503
+ }
504
+ function countFiles(dir) {
505
+ let count = dir.files?.length || 0;
506
+ if (dir.subdirectories) {
507
+ for (const subdir of dir.subdirectories) {
508
+ count += countFiles(subdir);
509
+ }
510
+ }
511
+ return count;
512
+ }
513
+ export default ImportView;
514
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/components/views/ImportView/index.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { useState, useCallback, useRef, useEffect } from 'react';\nimport {\n DocumentArrowUpIcon,\n CheckCircleIcon,\n ExclamationTriangleIcon,\n ArchiveBoxIcon,\n FolderOpenIcon\n} from '@heroicons/react/24/outline';\nimport { ImportViewProps, ImportedFile, ImportedDirectory, ExtendedProcessedResources } from '../../../types';\nimport { Bundle, Config } from '@fgv/ts-res';\nimport { isZipFile } from '../../../utils/zipLoader';\n\ninterface FileInputResult {\n files: ImportedFile[];\n directory?: ImportedDirectory;\n bundleFile?: ImportedFile & { bundle?: Bundle.IBundle };\n}\n\nexport const ImportView: React.FC<ImportViewProps> = ({\n onImport,\n onBundleImport,\n onZipImport,\n acceptedFileTypes = ['.json', '.zip'],\n onMessage,\n className = ''\n}) => {\n const [isLoading, setIsLoading] = useState(false);\n const [importStatus, setImportStatus] = useState<{\n hasImported: boolean;\n fileCount: number;\n isDirectory: boolean;\n isBundle: boolean;\n isZip: boolean;\n }>({\n hasImported: false,\n fileCount: 0,\n isDirectory: false,\n isBundle: false,\n isZip: false\n });\n const [error, setError] = useState<string | null>(null);\n const fileInputRef = useRef<HTMLInputElement>(null);\n const dirInputRef = useRef<HTMLInputElement>(null);\n\n // Check for File System Access API support\n const isFileSystemAccessSupported = 'showDirectoryPicker' in window || 'showOpenFilePicker' in window;\n\n // Handle file selection\n const handleFileSelect = useCallback(\n async (event: React.ChangeEvent<HTMLInputElement>) => {\n const files = event.target.files;\n if (!files || files.length === 0) return;\n\n setIsLoading(true);\n setError(null);\n\n try {\n // Handle single file selection - check file type first\n if (files.length === 1) {\n const file = files[0];\n\n // Check if it's a ZIP file first\n if (isZipFile(file.name)) {\n console.log(`[ImportView] ✅ ${file.name} detected as ZIP file`);\n onMessage?.('info', `Processing ZIP file: ${file.name}`);\n\n // Just pass the File object directly to onZipImport\n // The App will handle creating the FileTree\n if (onZipImport) {\n setImportStatus({\n hasImported: true,\n fileCount: 1,\n isDirectory: false,\n isBundle: false,\n isZip: true\n });\n\n onMessage?.('success', `ZIP file detected: ${file.name}`);\n onZipImport(file, undefined);\n\n setIsLoading(false);\n return;\n } else {\n throw new Error('No ZIP import handler configured');\n }\n }\n }\n\n // Handle regular files (non-ZIP)\n const importedFiles: ImportedFile[] = [];\n let bundleFile: (ImportedFile & { bundle?: Bundle.IBundle }) | undefined;\n\n for (let i = 0; i < files.length; i++) {\n const file = files[i];\n const content = await readFileContent(file);\n\n const importedFile: ImportedFile = {\n name: file.name,\n path: file.webkitRelativePath || file.name,\n content,\n type: file.type\n };\n\n // Check if it's a bundle file using proper detection\n let isCurrentFileBundle = false;\n try {\n const parsedData = JSON.parse(content);\n\n console.log(`[ImportView] Checking if ${file.name} is a bundle...`);\n\n // Use BundleUtils for proper bundle detection\n if (Bundle.BundleUtils.isBundleFile(parsedData)) {\n console.log(`[ImportView] ✅ ${file.name} detected as bundle file`);\n bundleFile = { ...importedFile, bundle: parsedData };\n isCurrentFileBundle = true;\n } else if (Bundle.BundleUtils.isBundleFileName(file.name)) {\n // File name suggests it's a bundle, but content doesn't match - log a warning\n console.warn(\n `[ImportView] ⚠️ File ${file.name} appears to be a bundle by name but content doesn't match bundle structure`\n );\n } else {\n console.log(`[ImportView] ❌ ${file.name} is not a bundle file`);\n }\n } catch (parseError) {\n console.log(`[ImportView] ❌ ${file.name} failed JSON parsing:`, parseError);\n // Not valid JSON or not a bundle, treat as regular file\n }\n\n // Only add to regular files if this specific file is not a bundle\n if (!isCurrentFileBundle) {\n importedFiles.push(importedFile);\n }\n }\n\n // Process results\n if (bundleFile) {\n console.log(`[ImportView] Processing bundle file: ${bundleFile.name}`, bundleFile.bundle);\n\n setImportStatus({\n hasImported: true,\n fileCount: 1,\n isDirectory: false,\n isBundle: true,\n isZip: false\n });\n onMessage?.('info', `Bundle file detected: ${bundleFile.name}`);\n if (onBundleImport && bundleFile.bundle) {\n console.log(`[ImportView] Calling onBundleImport with bundle data`);\n onBundleImport(bundleFile.bundle);\n } else {\n console.warn(`[ImportView] No bundle import handler or bundle data missing`);\n }\n } else if (importedFiles.length > 0) {\n setImportStatus({\n hasImported: true,\n fileCount: importedFiles.length,\n isDirectory: false,\n isBundle: false,\n isZip: false\n });\n onMessage?.('success', `Imported ${importedFiles.length} file(s)`);\n onImport?.(importedFiles);\n }\n } catch (err) {\n const errorMsg = err instanceof Error ? err.message : String(err);\n setError(errorMsg);\n onMessage?.('error', `Import failed: ${errorMsg}`);\n } finally {\n setIsLoading(false);\n // Reset input\n if (event.target) {\n event.target.value = '';\n }\n }\n },\n [onImport, onBundleImport, onMessage]\n );\n\n // Handle directory selection (for browsers with webkitdirectory support)\n const handleDirectorySelect = useCallback(\n async (event: React.ChangeEvent<HTMLInputElement>) => {\n const files = event.target.files;\n if (!files || files.length === 0) return;\n\n setIsLoading(true);\n setError(null);\n\n try {\n const filesByPath = new Map<string, ImportedFile[]>();\n const dirPaths = new Set<string>();\n\n for (let i = 0; i < files.length; i++) {\n const file = files[i];\n const content = await readFileContent(file);\n const path = file.webkitRelativePath;\n\n if (path) {\n const parts = path.split('/');\n const dirPath = parts.slice(0, -1).join('/');\n dirPaths.add(dirPath);\n\n if (!filesByPath.has(dirPath)) {\n filesByPath.set(dirPath, []);\n }\n\n filesByPath.get(dirPath)!.push({\n name: parts[parts.length - 1],\n path: path,\n content,\n type: file.type\n });\n }\n }\n\n // Build directory structure\n const rootDir: ImportedDirectory = {\n name: 'imported',\n files: filesByPath.get('') || [],\n subdirectories: []\n };\n\n // Create subdirectories\n const sortedPaths = Array.from(dirPaths).sort();\n for (const dirPath of sortedPaths) {\n if (dirPath && dirPath !== '') {\n const parts = dirPath.split('/');\n let currentLevel = rootDir;\n\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i];\n const currentPath = parts.slice(0, i + 1).join('/');\n\n if (!currentLevel.subdirectories) {\n currentLevel.subdirectories = [];\n }\n\n let subdir = currentLevel.subdirectories.find((d) => d.name === part);\n if (!subdir) {\n subdir = {\n name: part,\n path: currentPath,\n files: filesByPath.get(currentPath) || [],\n subdirectories: []\n };\n currentLevel.subdirectories.push(subdir);\n }\n\n currentLevel = subdir;\n }\n }\n }\n\n setImportStatus({\n hasImported: true,\n fileCount: files.length,\n isDirectory: true,\n isBundle: false,\n isZip: false\n });\n\n onMessage?.('success', `Imported directory with ${files.length} file(s)`);\n onImport?.(rootDir);\n } catch (err) {\n const errorMsg = err instanceof Error ? err.message : String(err);\n setError(errorMsg);\n onMessage?.('error', `Directory import failed: ${errorMsg}`);\n } finally {\n setIsLoading(false);\n // Reset input\n if (event.target) {\n event.target.value = '';\n }\n }\n },\n [onImport, onMessage]\n );\n\n // Modern File System Access API handlers\n const handleModernDirectoryPick = useCallback(async () => {\n if (!('showDirectoryPicker' in window)) {\n onMessage?.('error', 'Directory picker not supported in this browser');\n return;\n }\n\n setIsLoading(true);\n setError(null);\n\n try {\n const dirHandle = await (window as any).showDirectoryPicker();\n const rootDir = await processDirectoryHandle(dirHandle);\n\n const fileCount = countFiles(rootDir);\n setImportStatus({\n hasImported: true,\n fileCount,\n isDirectory: true,\n isBundle: false,\n isZip: false\n });\n\n onMessage?.('success', `Imported directory \"${rootDir.name}\" with ${fileCount} file(s)`);\n onImport?.(rootDir);\n } catch (err: any) {\n if (err.name !== 'AbortError') {\n const errorMsg = err instanceof Error ? err.message : String(err);\n setError(errorMsg);\n onMessage?.('error', `Directory import failed: ${errorMsg}`);\n }\n } finally {\n setIsLoading(false);\n }\n }, [onImport, onMessage]);\n\n const handleModernFilePick = useCallback(async () => {\n if (!('showOpenFilePicker' in window)) {\n onMessage?.('error', 'File picker not supported in this browser');\n return;\n }\n\n setIsLoading(true);\n setError(null);\n\n try {\n const fileHandles = await (window as any).showOpenFilePicker({\n multiple: true,\n types: [\n {\n description: 'Resource files',\n accept: {\n 'application/json': ['.json'],\n 'application/zip': ['.zip']\n }\n }\n ]\n });\n\n // Check if we have a single ZIP file first\n if (fileHandles.length === 1) {\n const file = await fileHandles[0].getFile();\n\n if (isZipFile(file.name)) {\n console.log(`[ImportView] Modern API - ✅ ${file.name} detected as ZIP file`);\n onMessage?.('info', `Processing ZIP file: ${file.name}`);\n\n if (onZipImport) {\n setImportStatus({\n hasImported: true,\n fileCount: 1,\n isDirectory: false,\n isBundle: false,\n isZip: true\n });\n\n onMessage?.('success', `ZIP file detected: ${file.name}`);\n onZipImport(file, undefined);\n\n setIsLoading(false);\n return;\n } else {\n throw new Error('No ZIP import handler configured');\n }\n }\n }\n\n const importedFiles: ImportedFile[] = [];\n let bundleFile: (ImportedFile & { bundle?: Bundle.IBundle }) | undefined;\n\n for (const fileHandle of fileHandles) {\n const file = await fileHandle.getFile();\n\n // Skip ZIP files in multi-file selection\n if (isZipFile(file.name)) {\n onMessage?.('warning', `Skipping ZIP file ${file.name} - select it individually to import`);\n continue;\n }\n\n const content = await file.text();\n\n const importedFile: ImportedFile = {\n name: file.name,\n content,\n type: file.type\n };\n\n // Check for bundle using proper detection\n let isCurrentFileBundle = false;\n try {\n const parsedData = JSON.parse(content);\n\n console.log(`[ImportView] Modern API - Checking if ${file.name} is a bundle...`);\n\n // Use BundleUtils for proper bundle detection\n if (Bundle.BundleUtils.isBundleFile(parsedData)) {\n console.log(`[ImportView] Modern API - ✅ ${file.name} detected as bundle file`);\n bundleFile = { ...importedFile, bundle: parsedData };\n isCurrentFileBundle = true;\n } else if (Bundle.BundleUtils.isBundleFileName(file.name)) {\n console.warn(\n `[ImportView] Modern API - ⚠️ File ${file.name} appears to be a bundle by name but content doesn't match bundle structure`\n );\n } else {\n console.log(`[ImportView] Modern API - ❌ ${file.name} is not a bundle file`);\n }\n } catch (parseError) {\n console.log(`[ImportView] Modern API - ❌ ${file.name} failed JSON parsing:`, parseError);\n }\n\n // Only add to regular files if this specific file is not a bundle\n if (!isCurrentFileBundle) {\n importedFiles.push(importedFile);\n }\n }\n\n // Process results\n if (bundleFile) {\n setImportStatus({\n hasImported: true,\n fileCount: 1,\n isDirectory: false,\n isBundle: true,\n isZip: false\n });\n onMessage?.('info', `Bundle file detected: ${bundleFile.name}`);\n if (onBundleImport && bundleFile.bundle) {\n onBundleImport(bundleFile.bundle);\n }\n } else if (importedFiles.length > 0) {\n setImportStatus({\n hasImported: true,\n fileCount: importedFiles.length,\n isDirectory: false,\n isBundle: false,\n isZip: false\n });\n onMessage?.('success', `Imported ${importedFiles.length} file(s)`);\n onImport?.(importedFiles);\n }\n } catch (err: any) {\n if (err.name !== 'AbortError') {\n const errorMsg = err instanceof Error ? err.message : String(err);\n setError(errorMsg);\n onMessage?.('error', `File import failed: ${errorMsg}`);\n }\n } finally {\n setIsLoading(false);\n }\n }, [onImport, onBundleImport, onMessage, acceptedFileTypes]);\n\n const handleReset = useCallback(() => {\n setImportStatus({\n hasImported: false,\n fileCount: 0,\n isDirectory: false,\n isBundle: false,\n isZip: false\n });\n setError(null);\n onMessage?.('info', 'Import cleared');\n }, [onMessage]);\n\n return (\n <div className={`p-6 ${className}`}>\n <div className=\"flex items-center space-x-3 mb-6\">\n <DocumentArrowUpIcon className=\"h-8 w-8 text-blue-600\" />\n <h2 className=\"text-2xl font-bold text-gray-900\">Import Resources</h2>\n </div>\n\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\n {/* Left column: Import Controls */}\n <div className=\"bg-white rounded-lg shadow-sm border border-gray-200 p-6\">\n <h3 className=\"text-lg font-semibold text-gray-900 mb-4\">Import Files</h3>\n\n <div className=\"space-y-4\">\n {/* API Support Status */}\n <div className=\"flex items-center space-x-2 text-sm text-gray-600\">\n {isFileSystemAccessSupported ? (\n <>\n <div className=\"w-2 h-2 bg-green-500 rounded-full\"></div>\n <span>Modern File System API available</span>\n </>\n ) : (\n <>\n <div className=\"w-2 h-2 bg-yellow-500 rounded-full\"></div>\n <span>Using fallback file input</span>\n </>\n )}\n </div>\n\n {/* Import Buttons */}\n <div className=\"flex flex-col space-y-3\">\n {isFileSystemAccessSupported ? (\n <>\n <button\n onClick={handleModernDirectoryPick}\n disabled={isLoading}\n className=\"flex items-center justify-center space-x-2 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors\"\n >\n <FolderOpenIcon className=\"w-5 h-5\" />\n <span>{isLoading ? 'Importing...' : 'Import Resource Directory'}</span>\n </button>\n\n <button\n onClick={handleModernFilePick}\n disabled={isLoading}\n className=\"flex items-center justify-center space-x-2 px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors\"\n >\n <DocumentArrowUpIcon className=\"w-5 h-5\" />\n <span>{isLoading ? 'Importing...' : 'Import Resource Files'}</span>\n </button>\n </>\n ) : (\n <>\n {/* Fallback inputs */}\n <input\n ref={dirInputRef}\n type=\"file\"\n // @ts-ignore - webkitdirectory is not in types\n webkitdirectory=\"\"\n directory=\"\"\n multiple\n onChange={handleDirectorySelect}\n className=\"hidden\"\n />\n <button\n onClick={() => dirInputRef.current?.click()}\n disabled={isLoading}\n className=\"flex items-center justify-center space-x-2 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors\"\n >\n <FolderOpenIcon className=\"w-5 h-5\" />\n <span>{isLoading ? 'Importing...' : 'Import Resource Directory'}</span>\n </button>\n\n <input\n ref={fileInputRef}\n type=\"file\"\n accept={acceptedFileTypes.join(',')}\n multiple\n onChange={handleFileSelect}\n className=\"hidden\"\n />\n <button\n onClick={() => fileInputRef.current?.click()}\n disabled={isLoading}\n className=\"flex items-center justify-center space-x-2 px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors\"\n >\n <DocumentArrowUpIcon className=\"w-5 h-5\" />\n <span>{isLoading ? 'Importing...' : 'Import Resource Files'}</span>\n </button>\n </>\n )}\n </div>\n\n {/* Usage Instructions */}\n <div className=\"text-sm text-gray-600 space-y-2\">\n <p className=\"font-medium\">Import Options:</p>\n <ul className=\"list-disc list-inside space-y-1 ml-2\">\n <li>\n <strong>Directory:</strong> Select a folder with ts-res resources\n </li>\n <li>\n <strong>Files:</strong> Select individual JSON resource files\n </li>\n <li>\n <strong>Bundles:</strong> Automatically detected and loaded\n </li>\n </ul>\n </div>\n </div>\n </div>\n\n {/* Right column: Status */}\n <div className=\"space-y-6\">\n {/* Import Status */}\n <div className=\"bg-white rounded-lg shadow-sm border border-gray-200 p-6\">\n <h3 className=\"text-lg font-semibold text-gray-900 mb-4\">Import Status</h3>\n\n <div className=\"space-y-3\">\n {/* Import Status */}\n <div className=\"flex items-center space-x-3\">\n {importStatus.hasImported ? (\n <>\n <CheckCircleIcon className=\"w-5 h-5 text-green-500\" />\n <span className=\"text-sm text-gray-900\">\n {importStatus.isBundle\n ? 'Bundle imported'\n : importStatus.isZip\n ? 'ZIP archive imported'\n : importStatus.isDirectory\n ? 'Directory imported'\n : `${importStatus.fileCount} file(s) imported`}\n </span>\n </>\n ) : (\n <>\n <div className=\"w-5 h-5 rounded-full border-2 border-gray-300\"></div>\n <span className=\"text-sm text-gray-500\">No files imported yet</span>\n </>\n )}\n </div>\n\n {/* Bundle Detection */}\n {importStatus.isBundle && (\n <div className=\"flex items-center space-x-3\">\n <ArchiveBoxIcon className=\"w-5 h-5 text-blue-500\" />\n <span className=\"text-sm text-blue-900\">Bundle file detected</span>\n </div>\n )}\n\n {/* ZIP Detection */}\n {importStatus.isZip && (\n <div className=\"flex items-center space-x-3\">\n <ArchiveBoxIcon className=\"w-5 h-5 text-purple-500\" />\n <span className=\"text-sm text-purple-900\">ZIP archive processed</span>\n </div>\n )}\n </div>\n\n {/* Reset Button */}\n {importStatus.hasImported && (\n <button\n onClick={handleReset}\n className=\"mt-4 px-4 py-2 text-sm bg-gray-100 text-gray-700 rounded-lg hover:bg-gray-200 transition-colors\"\n >\n Clear Import\n </button>\n )}\n </div>\n\n {/* Error Display */}\n {error && (\n <div className=\"bg-white rounded-lg shadow-sm border border-red-200 p-6\">\n <div className=\"flex items-start space-x-2\">\n <ExclamationTriangleIcon className=\"w-5 h-5 text-red-600 mt-0.5\" />\n <div className=\"text-sm text-red-800\">\n <p className=\"font-medium\">Error</p>\n <p>{error}</p>\n </div>\n </div>\n </div>\n )}\n\n {/* Success Message */}\n {importStatus.hasImported && !error && (\n <div className=\"bg-white rounded-lg shadow-sm border border-green-200 p-6\">\n <div className=\"flex items-start space-x-2\">\n <CheckCircleIcon className=\"w-5 h-5 text-green-600 mt-0.5\" />\n <div className=\"text-sm text-green-800\">\n <p className=\"font-medium\">Import Successful!</p>\n <p>\n {importStatus.isBundle\n ? 'Bundle resources are ready to browse.'\n : importStatus.isZip\n ? 'ZIP archive contents have been imported and are ready for processing.'\n : 'Resources are ready for processing.'}\n </p>\n </div>\n </div>\n </div>\n )}\n </div>\n </div>\n </div>\n );\n};\n\n// Helper functions\nasync function readFileContent(file: File): Promise<string> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = (e) => resolve(e.target?.result as string);\n reader.onerror = (e) => reject(new Error(`Failed to read file: ${file.name}`));\n reader.readAsText(file);\n });\n}\n\nasync function processDirectoryHandle(dirHandle: any, parentPath: string = ''): Promise<ImportedDirectory> {\n const files: ImportedFile[] = [];\n const subdirectories: ImportedDirectory[] = [];\n\n for await (const entry of dirHandle.values()) {\n if (entry.kind === 'file') {\n const file = await entry.getFile();\n const content = await file.text();\n files.push({\n name: file.name,\n path: parentPath ? `${parentPath}/${file.name}` : file.name,\n content,\n type: file.type\n });\n } else if (entry.kind === 'directory') {\n const subdir = await processDirectoryHandle(\n entry,\n parentPath ? `${parentPath}/${entry.name}` : entry.name\n );\n subdirectories.push(subdir);\n }\n }\n\n return {\n name: dirHandle.name,\n path: parentPath,\n files,\n subdirectories: subdirectories.length > 0 ? subdirectories : undefined\n };\n}\n\nfunction countFiles(dir: ImportedDirectory): number {\n let count = dir.files?.length || 0;\n if (dir.subdirectories) {\n for (const subdir of dir.subdirectories) {\n count += countFiles(subdir);\n }\n }\n return count;\n}\n\nexport default ImportView;\n"]}
@@ -0,0 +1,21 @@
1
+ import React from 'react';
2
+ export interface EditableJsonViewProps {
3
+ /** The original JSON value */
4
+ value: any;
5
+ /** The resource ID for tracking edits */
6
+ resourceId: string;
7
+ /** Whether this resource has been edited */
8
+ isEdited?: boolean;
9
+ /** The current edited value if any */
10
+ editedValue?: any;
11
+ /** Callback when the user saves an edit */
12
+ onSave?: (resourceId: string, editedValue: any, originalValue: any) => void;
13
+ /** Callback when the user cancels an edit */
14
+ onCancel?: (resourceId: string) => void;
15
+ /** Whether editing is currently disabled */
16
+ disabled?: boolean;
17
+ /** Additional CSS classes */
18
+ className?: string;
19
+ }
20
+ export declare const EditableJsonView: React.FC<EditableJsonViewProps>;
21
+ //# sourceMappingURL=EditableJsonView.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EditableJsonView.d.ts","sourceRoot":"","sources":["../../../../src/components/views/ResolutionView/EditableJsonView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAyC,MAAM,OAAO,CAAC;AAK9D,MAAM,WAAW,qBAAqB;IACpC,8BAA8B;IAC9B,KAAK,EAAE,GAAG,CAAC;IACX,yCAAyC;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sCAAsC;IACtC,WAAW,CAAC,EAAE,GAAG,CAAC;IAClB,2CAA2C;IAC3C,MAAM,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,EAAE,aAAa,EAAE,GAAG,KAAK,IAAI,CAAC;IAC5E,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,6BAA6B;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CA6L5D,CAAC"}