@fgv/ts-res-ui-components 5.0.0-22 → 5.0.0-23

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 (177) hide show
  1. package/README.md +226 -175
  2. package/config/jest.setup.js +10 -0
  3. package/dist/ts-res-ui-components.d.ts +1406 -89
  4. package/lib/components/common/QualifierContextControl.js +4 -1
  5. package/lib/components/common/ResourceTreeView.js +4 -1
  6. package/lib/components/forms/GenericQualifierTypeEditForm.d.ts +26 -0
  7. package/lib/components/forms/GenericQualifierTypeEditForm.js +166 -0
  8. package/lib/components/forms/QualifierEditForm.d.ts +1 -1
  9. package/lib/components/forms/index.d.ts +2 -0
  10. package/lib/components/forms/index.js +1 -0
  11. package/lib/components/orchestrator/ResourceOrchestrator.d.ts +3 -0
  12. package/lib/components/orchestrator/ResourceOrchestrator.js +115 -50
  13. package/lib/components/pickers/ResourcePicker/ResourcePickerTree.js +6 -3
  14. package/lib/components/views/CompiledView/index.js +75 -16
  15. package/lib/components/views/ConfigurationView/index.js +94 -35
  16. package/lib/components/views/FilterView/index.js +7 -4
  17. package/lib/components/views/GridView/EditableGridCell.d.ts +76 -0
  18. package/lib/components/views/GridView/EditableGridCell.js +224 -0
  19. package/lib/components/views/GridView/GridSelector.d.ts +43 -0
  20. package/lib/components/views/GridView/GridSelector.js +89 -0
  21. package/lib/components/views/GridView/MultiGridView.d.ts +85 -0
  22. package/lib/components/views/GridView/MultiGridView.js +196 -0
  23. package/lib/components/views/GridView/ResourceGrid.d.ts +38 -0
  24. package/lib/components/views/GridView/ResourceGrid.js +232 -0
  25. package/lib/components/views/GridView/SharedContextControls.d.ts +47 -0
  26. package/lib/components/views/GridView/SharedContextControls.js +95 -0
  27. package/lib/components/views/GridView/cells/BooleanCell.d.ts +44 -0
  28. package/lib/components/views/GridView/cells/BooleanCell.js +49 -0
  29. package/lib/components/views/GridView/cells/DropdownCell.d.ts +58 -0
  30. package/lib/components/views/GridView/cells/DropdownCell.js +182 -0
  31. package/lib/components/views/GridView/cells/StringCell.d.ts +57 -0
  32. package/lib/components/views/GridView/cells/StringCell.js +106 -0
  33. package/lib/components/views/GridView/cells/TriStateCell.d.ts +54 -0
  34. package/lib/components/views/GridView/cells/TriStateCell.js +112 -0
  35. package/lib/components/views/GridView/cells/index.d.ts +15 -0
  36. package/lib/components/views/GridView/cells/index.js +11 -0
  37. package/lib/components/views/GridView/index.d.ts +53 -0
  38. package/lib/components/views/GridView/index.js +212 -0
  39. package/lib/components/views/ImportView/index.js +22 -19
  40. package/lib/components/views/MessagesWindow/index.js +4 -1
  41. package/lib/components/views/ResolutionView/index.js +7 -4
  42. package/lib/contexts/ObservabilityContext.d.ts +85 -0
  43. package/lib/contexts/ObservabilityContext.js +98 -0
  44. package/lib/contexts/index.d.ts +2 -0
  45. package/lib/contexts/index.js +24 -0
  46. package/lib/hooks/useConfigurationState.d.ts +3 -3
  47. package/lib/hooks/useResolutionState.js +15 -12
  48. package/lib/hooks/useResourceData.d.ts +7 -4
  49. package/lib/hooks/useResourceData.js +185 -184
  50. package/lib/index.d.ts +5 -1
  51. package/lib/index.js +8 -1
  52. package/lib/namespaces/GridTools.d.ts +136 -0
  53. package/lib/namespaces/GridTools.js +138 -0
  54. package/lib/namespaces/ObservabilityTools.d.ts +3 -0
  55. package/lib/namespaces/ObservabilityTools.js +23 -0
  56. package/lib/namespaces/index.d.ts +2 -0
  57. package/lib/namespaces/index.js +2 -0
  58. package/lib/test/integration/observability.integration.test.d.ts +2 -0
  59. package/lib/test/unit/hooks/useResourceData.test.d.ts +2 -0
  60. package/lib/test/unit/utils/downloadHelper.test.d.ts +2 -0
  61. package/lib/types/index.d.ts +263 -1
  62. package/lib/utils/cellValidation.d.ts +113 -0
  63. package/lib/utils/cellValidation.js +248 -0
  64. package/lib/utils/downloadHelper.d.ts +66 -0
  65. package/lib/utils/downloadHelper.js +195 -0
  66. package/lib/utils/observability/factories.d.ts +29 -0
  67. package/lib/utils/observability/factories.js +58 -0
  68. package/lib/utils/observability/implementations.d.ts +61 -0
  69. package/lib/utils/observability/implementations.js +103 -0
  70. package/lib/utils/observability/index.d.ts +4 -0
  71. package/lib/utils/observability/index.js +26 -0
  72. package/lib/utils/observability/interfaces.d.ts +30 -0
  73. package/lib/utils/observability/interfaces.js +23 -0
  74. package/lib/utils/resourceSelector.d.ts +97 -0
  75. package/lib/utils/resourceSelector.js +195 -0
  76. package/lib/utils/tsResIntegration.d.ts +6 -41
  77. package/lib/utils/tsResIntegration.js +20 -16
  78. package/lib/utils/zipLoader/zipProcessingHelpers.d.ts +3 -2
  79. package/lib/utils/zipLoader/zipProcessingHelpers.js +6 -5
  80. package/lib-commonjs/components/common/QualifierContextControl.js +4 -1
  81. package/lib-commonjs/components/common/ResourceTreeView.js +4 -1
  82. package/lib-commonjs/components/forms/GenericQualifierTypeEditForm.js +171 -0
  83. package/lib-commonjs/components/forms/index.js +3 -1
  84. package/lib-commonjs/components/orchestrator/ResourceOrchestrator.js +115 -50
  85. package/lib-commonjs/components/pickers/ResourcePicker/ResourcePickerTree.js +6 -3
  86. package/lib-commonjs/components/views/CompiledView/index.js +75 -16
  87. package/lib-commonjs/components/views/ConfigurationView/index.js +93 -34
  88. package/lib-commonjs/components/views/FilterView/index.js +7 -4
  89. package/lib-commonjs/components/views/GridView/EditableGridCell.js +232 -0
  90. package/lib-commonjs/components/views/GridView/GridSelector.js +94 -0
  91. package/lib-commonjs/components/views/GridView/MultiGridView.js +201 -0
  92. package/lib-commonjs/components/views/GridView/ResourceGrid.js +237 -0
  93. package/lib-commonjs/components/views/GridView/SharedContextControls.js +100 -0
  94. package/lib-commonjs/components/views/GridView/cells/BooleanCell.js +54 -0
  95. package/lib-commonjs/components/views/GridView/cells/DropdownCell.js +187 -0
  96. package/lib-commonjs/components/views/GridView/cells/StringCell.js +111 -0
  97. package/lib-commonjs/components/views/GridView/cells/TriStateCell.js +117 -0
  98. package/lib-commonjs/components/views/GridView/cells/index.js +18 -0
  99. package/lib-commonjs/components/views/GridView/index.js +217 -0
  100. package/lib-commonjs/components/views/ImportView/index.js +22 -19
  101. package/lib-commonjs/components/views/MessagesWindow/index.js +4 -1
  102. package/lib-commonjs/components/views/ResolutionView/index.js +7 -4
  103. package/lib-commonjs/contexts/ObservabilityContext.js +104 -0
  104. package/lib-commonjs/contexts/index.js +30 -0
  105. package/lib-commonjs/hooks/useResolutionState.js +15 -12
  106. package/lib-commonjs/hooks/useResourceData.js +184 -215
  107. package/lib-commonjs/index.js +15 -1
  108. package/lib-commonjs/namespaces/GridTools.js +161 -0
  109. package/lib-commonjs/namespaces/ObservabilityTools.js +33 -0
  110. package/lib-commonjs/namespaces/index.js +3 -1
  111. package/lib-commonjs/utils/cellValidation.js +253 -0
  112. package/lib-commonjs/utils/downloadHelper.js +198 -0
  113. package/lib-commonjs/utils/observability/factories.js +63 -0
  114. package/lib-commonjs/utils/observability/implementations.js +109 -0
  115. package/lib-commonjs/utils/observability/index.js +36 -0
  116. package/lib-commonjs/utils/observability/interfaces.js +24 -0
  117. package/lib-commonjs/utils/resourceSelector.js +200 -0
  118. package/lib-commonjs/utils/tsResIntegration.js +21 -16
  119. package/lib-commonjs/utils/zipLoader/zipProcessingHelpers.js +7 -5
  120. package/package.json +7 -7
  121. package/src/components/common/QualifierContextControl.tsx +0 -338
  122. package/src/components/common/ResolutionContextOptionsControl.tsx +0 -450
  123. package/src/components/common/ResolutionResults/index.tsx +0 -481
  124. package/src/components/common/ResourceListView.tsx +0 -167
  125. package/src/components/common/ResourcePickerOptionsControl.tsx +0 -351
  126. package/src/components/common/ResourceTreeView.tsx +0 -417
  127. package/src/components/common/SourceResourceDetail/index.tsx +0 -493
  128. package/src/components/forms/HierarchyEditor.tsx +0 -285
  129. package/src/components/forms/QualifierEditForm.tsx +0 -487
  130. package/src/components/forms/QualifierTypeEditForm.tsx +0 -458
  131. package/src/components/forms/ResourceTypeEditForm.tsx +0 -437
  132. package/src/components/forms/index.ts +0 -11
  133. package/src/components/orchestrator/ResourceOrchestrator.tsx +0 -446
  134. package/src/components/pickers/ResourcePicker/README.md +0 -570
  135. package/src/components/pickers/ResourcePicker/ResourceItem.tsx +0 -127
  136. package/src/components/pickers/ResourcePicker/ResourcePickerList.tsx +0 -114
  137. package/src/components/pickers/ResourcePicker/ResourcePickerTree.tsx +0 -481
  138. package/src/components/pickers/ResourcePicker/index.tsx +0 -239
  139. package/src/components/pickers/ResourcePicker/types.ts +0 -301
  140. package/src/components/pickers/ResourcePicker/utils/treeNavigation.ts +0 -210
  141. package/src/components/views/CompiledView/index.tsx +0 -1342
  142. package/src/components/views/ConfigurationView/index.tsx +0 -848
  143. package/src/components/views/FilterView/index.tsx +0 -681
  144. package/src/components/views/ImportView/index.tsx +0 -789
  145. package/src/components/views/MessagesWindow/index.tsx +0 -325
  146. package/src/components/views/ResolutionView/EditableJsonView.tsx +0 -386
  147. package/src/components/views/ResolutionView/NewResourceModal.tsx +0 -158
  148. package/src/components/views/ResolutionView/UnifiedChangeControls.tsx +0 -163
  149. package/src/components/views/ResolutionView/index.tsx +0 -751
  150. package/src/components/views/SourceView/index.tsx +0 -291
  151. package/src/hooks/useConfigurationState.ts +0 -436
  152. package/src/hooks/useFilterState.ts +0 -150
  153. package/src/hooks/useResolutionState.ts +0 -1690
  154. package/src/hooks/useResourceData.ts +0 -596
  155. package/src/hooks/useViewState.ts +0 -97
  156. package/src/index.ts +0 -68
  157. package/src/namespaces/ConfigurationTools.ts +0 -59
  158. package/src/namespaces/FilterTools.ts +0 -47
  159. package/src/namespaces/ImportTools.ts +0 -42
  160. package/src/namespaces/PickerTools.ts +0 -104
  161. package/src/namespaces/ResolutionTools.ts +0 -80
  162. package/src/namespaces/ResourceTools.ts +0 -106
  163. package/src/namespaces/TsResTools.ts +0 -49
  164. package/src/namespaces/ViewStateTools.ts +0 -91
  165. package/src/namespaces/ZipTools.ts +0 -49
  166. package/src/namespaces/index.ts +0 -49
  167. package/src/types/index.ts +0 -1384
  168. package/src/utils/configurationUtils.ts +0 -339
  169. package/src/utils/fileProcessing.ts +0 -164
  170. package/src/utils/filterResources.ts +0 -356
  171. package/src/utils/resolutionEditing.ts +0 -346
  172. package/src/utils/resolutionUtils.ts +0 -740
  173. package/src/utils/resourceSelectors.ts +0 -278
  174. package/src/utils/tsResIntegration.ts +0 -475
  175. package/src/utils/zipLoader/index.ts +0 -5
  176. package/src/utils/zipLoader/zipProcessingHelpers.ts +0 -46
  177. package/src/utils/zipLoader/zipUtils.ts +0 -7
package/README.md CHANGED
@@ -19,20 +19,10 @@ This packlet is largely AI written, and it shows.
19
19
  - **📊 Visualization**: Multiple views for exploring resource structures and compiled output
20
20
  - **⚙️ Configuration**: Visual configuration management for qualifier types, qualifiers, and resource types
21
21
  - **🎛️ Host Control**: Programmatic control of qualifier values and resource types
22
- - **📁 File Handling**: Support for directory imports, ZIP files via ts-res zip-archive packlet, and bundle loading
22
+ - **📁 File Handling**: Support for directory imports, ZIP files, and bundle loading
23
+ - **🐛 Built-in Debugging**: Comprehensive logging and observability throughout operations
23
24
  - **🎨 Modern UI**: Built with Tailwind CSS and Heroicons for a clean, responsive interface
24
25
 
25
- ### ZIP Archive Integration
26
-
27
- This library now uses the **ts-res zip-archive packlet** as the single source of truth for all ZIP operations, providing:
28
-
29
- - **Universal compatibility**: Works in both browser and Node.js environments using fflate
30
- - **Standardized format**: Common ZIP bundle format across all ts-res tools
31
- - **Simplified API**: Direct integration with ts-res ZIP archive functionality
32
- - **Processing helpers**: Utilities to integrate ZIP data with ts-res-ui-components workflows
33
-
34
- The `ImportView` component handles ZIP files automatically, and the `ZipTools` namespace provides processing helpers for custom ZIP workflows.
35
-
36
26
  ## Installation
37
27
 
38
28
  ```bash
@@ -56,178 +46,51 @@ This library requires the following peer dependencies:
56
46
 
57
47
  ## Quick Start
58
48
 
59
- ### Canonical New Resource Flow
60
-
61
- The recommended approach for programmatic resource creation:
62
-
63
- ```tsx
64
- import { ResolutionTools } from '@fgv/ts-res-ui-components';
65
-
66
- // Single atomic operation (recommended)
67
- async function createResourceAtomic(actions) {
68
- const result = await actions.createPendingResource({
69
- id: 'platform.languages.az-AZ',
70
- resourceTypeName: 'json',
71
- json: { text: 'Welcome', locale: 'az-AZ' }
72
- });
73
-
74
- if (result.isSuccess()) {
75
- console.log('Resource created successfully');
76
- await actions.applyPendingResources();
77
- } else {
78
- console.error('Creation failed:', result.message);
79
- }
80
- }
81
-
82
- // Step-by-step workflow (if needed)
83
- function createResourceStepByStep(actions) {
84
- // 1) Start new resource
85
- const startResult = actions.startNewResource({ defaultTypeName: 'json' });
86
- if (!startResult.success) return;
87
-
88
- // 2) Update resource ID
89
- const idResult = actions.updateNewResourceId('platform.languages.az-AZ');
90
- if (!idResult.success) return;
91
-
92
- // 3) Select resource type (if step 1 didn't set it)
93
- const typeResult = actions.selectResourceType('json');
94
- if (!typeResult.success) return;
95
-
96
- // 4) Update JSON content (optional, recommended)
97
- const jsonResult = actions.updateNewResourceJson({
98
- text: 'Welcome',
99
- locale: 'az-AZ'
100
- });
101
- if (!jsonResult.success) return;
102
-
103
- // 5) Save as pending
104
- const saveResult = actions.saveNewResourceAsPending();
105
- if (!saveResult.success) return;
106
-
107
- // Note: Do NOT call saveResourceEdit for brand-new resources
108
- }
109
- ```
110
-
111
- ### Minimal Editing App (Unified Apply)
49
+ ### Basic Setup
112
50
 
113
51
  ```tsx
114
52
  import React from 'react';
115
- import { ResourceOrchestrator, ResolutionView } from '@fgv/ts-res-ui-components';
53
+ import { ResourceOrchestrator, ObservabilityProvider } from '@fgv/ts-res-ui-components';
116
54
 
117
- export default function App() {
55
+ function App() {
118
56
  return (
119
- <ResourceOrchestrator>
120
- {({ state, actions }) => (
121
- <ResolutionView
122
- resources={state.resources}
123
- resolutionState={state.resolutionState}
124
- resolutionActions={{
125
- updateContextValue: actions.updateResolutionContext,
126
- applyContext: actions.applyResolutionContext,
127
- selectResource: actions.selectResourceForResolution,
128
- setViewMode: actions.setResolutionViewMode,
129
- resetCache: actions.resetResolutionCache,
130
- saveEdit: actions.saveResourceEdit,
131
- getEditedValue: actions.getEditedValue,
132
- hasEdit: actions.hasResourceEdit,
133
- clearEdits: actions.clearResourceEdits,
134
- discardEdits: actions.discardResourceEdits,
135
- // Enhanced resource creation actions with atomic API
136
- createPendingResource: actions.createPendingResource,
137
- startNewResource: actions.startNewResource,
138
- updateNewResourceId: actions.updateNewResourceId,
139
- selectResourceType: actions.selectResourceType,
140
- updateNewResourceJson: actions.updateNewResourceJson,
141
- saveNewResourceAsPending: actions.saveNewResourceAsPending,
142
- cancelNewResource: actions.cancelNewResource,
143
- removePendingResource: actions.removePendingResource,
144
- markResourceForDeletion: actions.markResourceForDeletion,
145
- applyPendingResources: actions.applyPendingResources,
146
- discardPendingResources: actions.discardPendingResources
147
- }}
148
- allowResourceCreation
149
- defaultResourceType="json"
150
- showPendingResourcesInList
151
- onMessage={actions.addMessage}
152
- />
153
- )}
154
- </ResourceOrchestrator>
57
+ <ObservabilityProvider>
58
+ <ResourceOrchestrator />
59
+ </ObservabilityProvider>
155
60
  );
156
61
  }
157
62
  ```
158
63
 
159
- ### Basic Usage with ResourceOrchestrator
160
-
161
- The `ResourceOrchestrator` component provides centralized state management for all ts-res UI functionality:
162
-
163
- ```tsx
164
- import React from 'react';
165
- import { ResourceOrchestrator, ImportView, SourceView } from '@fgv/ts-res-ui-components';
166
-
167
- function App() {
168
- return (
169
- <ResourceOrchestrator>
170
- {({ state, actions }) => (
171
- <div className="min-h-screen bg-gray-50">
172
- <div className="container mx-auto px-4 py-8">
173
- <h1 className="text-3xl font-bold mb-8">Resource Manager</h1>
174
-
175
- {!state.processedResources ? (
176
- <ImportView
177
- onImport={actions.importDirectory}
178
- onBundleImport={actions.importBundle}
179
- onZipImport={(zipData, config) => {
180
- if (config) actions.applyConfiguration(config);
181
- if (zipData.directory) actions.importDirectory(zipData.directory);
182
- else if (zipData.files?.length) actions.importFiles(zipData.files);
183
- }}
184
- />
185
- ) : (
186
- <SourceView
187
- resources={state.processedResources}
188
- onExport={actions.exportData}
189
- />
190
- )}
191
- </div>
192
- </div>
193
- )}
194
- </ResourceOrchestrator>
195
- );
196
- }
64
+ The `ResourceOrchestrator` provides a complete resource management interface with import, filtering, resolution, and editing capabilities. The `ObservabilityProvider` enables built-in logging and debugging features throughout the component tree.
197
65
 
198
- export default App;
199
- ```
66
+ ## Core Concepts
200
67
 
201
- ### Using Individual Hooks
68
+ ### Resource Orchestrator
69
+ The central component that coordinates all resource operations. It manages the complete workflow:
202
70
 
203
- For more granular control, you can use individual hooks:
71
+ - **Configuration Management**: Set up qualifier types, qualifiers, and resource types
72
+ - **Resource Import**: Load resources from files, ZIP archives, or bundles
73
+ - **Resource Filtering**: Filter resources by context to create deployment subsets
74
+ - **Resource Resolution**: Test how resources resolve for different contexts
75
+ - **Resource Editing**: Create and modify resources with real-time validation
204
76
 
205
- ```tsx
206
- import React from 'react';
207
- import { useResourceData, SourceView } from '@fgv/ts-res-ui-components';
77
+ ### Component Architecture
78
+ The library is organized into specialized namespaces, each containing related components and utilities:
208
79
 
209
- function MyResourceViewer() {
210
- const { state, actions } = useResourceData();
80
+ - **FilterTools**: Resource filtering with context-aware capabilities
81
+ - **ResolutionTools**: Resource resolution testing and editing
82
+ - **ConfigurationTools**: System configuration management
83
+ - **GridTools**: Advanced data grid for tabular resource management
84
+ - **ImportTools**: File and archive import capabilities
85
+ - **ObservabilityTools**: Logging and debugging infrastructure
211
86
 
212
- const handleFileImport = async (files: File[]) => {
213
- const importedFiles = await processFiles(files); // Your file processing logic
214
- await actions.processFiles(importedFiles);
215
- };
87
+ ### Built-in Observability
88
+ All operations include comprehensive logging for debugging and user feedback:
216
89
 
217
- return (
218
- <div>
219
- {state.isProcessing && <div>Processing...</div>}
220
- {state.error && <div className="error">{state.error}</div>}
221
- {state.processedResources && (
222
- <SourceView
223
- resources={state.processedResources}
224
- onExport={(data) => console.log('Export:', data)}
225
- />
226
- )}
227
- </div>
228
- );
229
- }
230
- ```
90
+ - **Diagnostic Logging**: Developer-focused information for troubleshooting
91
+ - **User Messaging**: User-friendly success/error notifications
92
+ - **Configurable Loggers**: Console output for development, silent for production
93
+ - **React Integration**: Observability context available throughout the component tree
231
94
 
232
95
  ## Architecture
233
96
 
@@ -1449,6 +1312,181 @@ All components accept a `className` prop for custom styling:
1449
1312
  />
1450
1313
  ```
1451
1314
 
1315
+ ## Detailed Examples
1316
+
1317
+ ### Canonical New Resource Flow
1318
+
1319
+ The recommended approach for programmatic resource creation:
1320
+
1321
+ ```tsx
1322
+ import { ResolutionTools } from '@fgv/ts-res-ui-components';
1323
+
1324
+ // Single atomic operation (recommended)
1325
+ async function createResourceAtomic(actions) {
1326
+ const result = await actions.createPendingResource({
1327
+ id: 'platform.languages.az-AZ',
1328
+ resourceTypeName: 'json',
1329
+ json: { text: 'Welcome', locale: 'az-AZ' }
1330
+ });
1331
+
1332
+ if (result.isSuccess()) {
1333
+ console.log('Resource created successfully');
1334
+ await actions.applyPendingResources();
1335
+ } else {
1336
+ console.error('Creation failed:', result.message);
1337
+ }
1338
+ }
1339
+
1340
+ // Step-by-step workflow (if needed)
1341
+ function createResourceStepByStep(actions) {
1342
+ // 1) Start new resource
1343
+ const startResult = actions.startNewResource({ defaultTypeName: 'json' });
1344
+ if (!startResult.success) return;
1345
+
1346
+ // 2) Update resource ID
1347
+ const idResult = actions.updateNewResourceId('platform.languages.az-AZ');
1348
+ if (!idResult.success) return;
1349
+
1350
+ // 3) Select resource type (if step 1 didn't set it)
1351
+ const typeResult = actions.selectResourceType('json');
1352
+ if (!typeResult.success) return;
1353
+
1354
+ // 4) Update JSON content (optional, recommended)
1355
+ const jsonResult = actions.updateNewResourceJson({
1356
+ text: 'Welcome',
1357
+ locale: 'az-AZ'
1358
+ });
1359
+ if (!jsonResult.success) return;
1360
+
1361
+ // 5) Save as pending
1362
+ const saveResult = actions.saveNewResourceAsPending();
1363
+ if (!saveResult.success) return;
1364
+
1365
+ // Note: Do NOT call saveResourceEdit for brand-new resources
1366
+ }
1367
+ ```
1368
+
1369
+ ### Minimal Editing App (Unified Apply)
1370
+
1371
+ ```tsx
1372
+ import React from 'react';
1373
+ import { ResourceOrchestrator, ResolutionView } from '@fgv/ts-res-ui-components';
1374
+
1375
+ export default function App() {
1376
+ return (
1377
+ <ResourceOrchestrator>
1378
+ {({ state, actions }) => (
1379
+ <ResolutionView
1380
+ resources={state.resources}
1381
+ resolutionState={state.resolutionState}
1382
+ resolutionActions={{
1383
+ updateContextValue: actions.updateResolutionContext,
1384
+ applyContext: actions.applyResolutionContext,
1385
+ selectResource: actions.selectResourceForResolution,
1386
+ setViewMode: actions.setResolutionViewMode,
1387
+ resetCache: actions.resetResolutionCache,
1388
+ saveEdit: actions.saveResourceEdit,
1389
+ getEditedValue: actions.getEditedValue,
1390
+ hasEdit: actions.hasResourceEdit,
1391
+ clearEdits: actions.clearResourceEdits,
1392
+ discardEdits: actions.discardResourceEdits,
1393
+ // Enhanced resource creation actions with atomic API
1394
+ createPendingResource: actions.createPendingResource,
1395
+ startNewResource: actions.startNewResource,
1396
+ updateNewResourceId: actions.updateNewResourceId,
1397
+ selectResourceType: actions.selectResourceType,
1398
+ updateNewResourceJson: actions.updateNewResourceJson,
1399
+ saveNewResourceAsPending: actions.saveNewResourceAsPending,
1400
+ cancelNewResource: actions.cancelNewResource,
1401
+ removePendingResource: actions.removePendingResource,
1402
+ markResourceForDeletion: actions.markResourceForDeletion,
1403
+ applyPendingResources: actions.applyPendingResources,
1404
+ discardPendingResources: actions.discardPendingResources
1405
+ }}
1406
+ allowResourceCreation
1407
+ defaultResourceType="json"
1408
+ showPendingResourcesInList
1409
+ onMessage={actions.addMessage}
1410
+ />
1411
+ )}
1412
+ </ResourceOrchestrator>
1413
+ );
1414
+ }
1415
+ ```
1416
+
1417
+ ### Basic Usage with ResourceOrchestrator
1418
+
1419
+ The `ResourceOrchestrator` component provides centralized state management for all ts-res UI functionality:
1420
+
1421
+ ```tsx
1422
+ import React from 'react';
1423
+ import { ResourceOrchestrator, ImportView, SourceView } from '@fgv/ts-res-ui-components';
1424
+
1425
+ function App() {
1426
+ return (
1427
+ <ResourceOrchestrator>
1428
+ {({ state, actions }) => (
1429
+ <div className="min-h-screen bg-gray-50">
1430
+ <div className="container mx-auto px-4 py-8">
1431
+ <h1 className="text-3xl font-bold mb-8">Resource Manager</h1>
1432
+
1433
+ {!state.processedResources ? (
1434
+ <ImportView
1435
+ onImport={actions.importDirectory}
1436
+ onBundleImport={actions.importBundle}
1437
+ onZipImport={(zipData, config) => {
1438
+ if (config) actions.applyConfiguration(config);
1439
+ if (zipData.directory) actions.importDirectory(zipData.directory);
1440
+ else if (zipData.files?.length) actions.importFiles(zipData.files);
1441
+ }}
1442
+ />
1443
+ ) : (
1444
+ <SourceView
1445
+ resources={state.processedResources}
1446
+ onExport={actions.exportData}
1447
+ />
1448
+ )}
1449
+ </div>
1450
+ </div>
1451
+ )}
1452
+ </ResourceOrchestrator>
1453
+ );
1454
+ }
1455
+
1456
+ export default App;
1457
+ ```
1458
+
1459
+ ### Using Individual Hooks
1460
+
1461
+ For more granular control, you can use individual hooks:
1462
+
1463
+ ```tsx
1464
+ import React from 'react';
1465
+ import { useResourceData, SourceView } from '@fgv/ts-res-ui-components';
1466
+
1467
+ function MyResourceViewer() {
1468
+ const { state, actions } = useResourceData();
1469
+
1470
+ const handleFileImport = async (files: File[]) => {
1471
+ const importedFiles = await processFiles(files); // Your file processing logic
1472
+ await actions.processFiles(importedFiles);
1473
+ };
1474
+
1475
+ return (
1476
+ <div>
1477
+ {state.isProcessing && <div>Processing...</div>}
1478
+ {state.error && <div className="error">{state.error}</div>}
1479
+ {state.processedResources && (
1480
+ <SourceView
1481
+ resources={state.processedResources}
1482
+ onExport={(data) => console.log('Export:', data)}
1483
+ />
1484
+ )}
1485
+ </div>
1486
+ );
1487
+ }
1488
+ ```
1489
+
1452
1490
  ## Advanced Usage
1453
1491
 
1454
1492
  ### Custom Resource Processing
@@ -1544,21 +1582,25 @@ For better organization and discoverability, utility functions are organized int
1544
1582
 
1545
1583
  ```tsx
1546
1584
  import {
1547
- FilterTools, // FilterView + filtering utilities
1548
- ResolutionTools, // ResolutionView + resolution utilities
1585
+ FilterTools, // FilterView + filtering utilities
1586
+ ResolutionTools, // ResolutionView + resolution utilities
1549
1587
  ConfigurationTools, // ConfigurationView + configuration utilities
1550
- TsResTools, // SourceView, CompiledView + ts-res utilities
1551
- ViewTools, // MessagesWindow + view state utilities
1552
- ZipTools, // ImportView + ZIP processing helpers
1553
- FileTools // File processing utilities
1588
+ TsResTools, // SourceView, CompiledView + ts-res utilities
1589
+ ViewStateTools, // MessagesWindow + view state utilities
1590
+ ZipTools, // ImportView + ZIP processing helpers
1591
+ ObservabilityTools, // Observability context and loggers
1592
+ GridTools, // GridView + data grid utilities
1593
+ PickerTools, // ResourcePicker + picker utilities
1594
+ ImportTools // Import utilities and types
1554
1595
  } from '@fgv/ts-res-ui-components';
1555
1596
 
1556
1597
  // Use view components from namespaces
1557
1598
  <FilterTools.FilterView {...filterProps} />
1558
1599
  <ResolutionTools.ResolutionView {...resolutionProps} />
1559
- <ViewTools.MessagesWindow {...messageProps} />
1600
+ <ViewStateTools.MessagesWindow {...messageProps} />
1560
1601
  <TsResTools.SourceView {...sourceProps} />
1561
1602
  <ZipTools.ImportView {...importProps} />
1603
+ <GridTools.GridView {...gridProps} />
1562
1604
 
1563
1605
  // Use utility functions from namespaces
1564
1606
  const hasFilters = FilterTools.hasFilterValues(filterState.values);
@@ -1567,6 +1609,15 @@ const system = await TsResTools.createTsResSystemFromConfig(config);
1567
1609
 
1568
1610
  // ZIP processing helpers for ts-res-ui-components integration
1569
1611
  const processResult = await ZipTools.processZipLoadResult(zipData, config);
1612
+
1613
+ // Observability context and loggers
1614
+ const consoleContext = ObservabilityTools.createConsoleObservabilityContext('debug', 'info');
1615
+ const noOpContext = ObservabilityTools.createNoOpObservabilityContext();
1616
+ const customLogger = new ObservabilityTools.ConsoleUserLogger('info');
1617
+
1618
+ // Grid utilities and selectors
1619
+ const gridSelector = new GridTools.ResourceSelector();
1620
+ const validation = GridTools.validateCellValue(value, rules);
1570
1621
  ```
1571
1622
 
1572
1623
  ### Namespace Contents
@@ -53,6 +53,16 @@ global.URL = {
53
53
  // Extend jest matchers (toBeInTheDocument, etc.)
54
54
  require('@testing-library/jest-dom');
55
55
 
56
+ // Suppress console output in tests by providing a no-op logger
57
+ // This affects both direct console calls and components that use logger dependency injection
58
+ global.testLogger = () => {}; // No-op logger for tests
59
+ global.console = {
60
+ ...console,
61
+ log: global.testLogger,
62
+ warn: global.testLogger,
63
+ error: console.error // Keep error for actual test failures
64
+ };
65
+
56
66
  // Mock document methods for file export
57
67
  global.document = {
58
68
  createElement: jest.fn(() => ({