@fgv/ts-res-ui-components 5.0.0-21 → 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.
- package/README.md +401 -155
- package/config/jest.setup.js +10 -0
- package/dist/ts-res-ui-components.d.ts +1657 -76
- package/lib/components/common/QualifierContextControl.js +4 -1
- package/lib/components/common/ResourceTreeView.js +4 -1
- package/lib/components/forms/GenericQualifierTypeEditForm.d.ts +26 -0
- package/lib/components/forms/GenericQualifierTypeEditForm.js +166 -0
- package/lib/components/forms/QualifierEditForm.d.ts +1 -1
- package/lib/components/forms/index.d.ts +2 -0
- package/lib/components/forms/index.js +1 -0
- package/lib/components/orchestrator/ResourceOrchestrator.d.ts +3 -0
- package/lib/components/orchestrator/ResourceOrchestrator.js +118 -51
- package/lib/components/pickers/ResourcePicker/ResourcePickerTree.js +32 -10
- package/lib/components/pickers/ResourcePicker/index.js +4 -2
- package/lib/components/views/CompiledView/index.js +75 -16
- package/lib/components/views/ConfigurationView/index.js +94 -35
- package/lib/components/views/FilterView/index.js +7 -4
- package/lib/components/views/GridView/EditableGridCell.d.ts +76 -0
- package/lib/components/views/GridView/EditableGridCell.js +224 -0
- package/lib/components/views/GridView/GridSelector.d.ts +43 -0
- package/lib/components/views/GridView/GridSelector.js +89 -0
- package/lib/components/views/GridView/MultiGridView.d.ts +85 -0
- package/lib/components/views/GridView/MultiGridView.js +196 -0
- package/lib/components/views/GridView/ResourceGrid.d.ts +38 -0
- package/lib/components/views/GridView/ResourceGrid.js +232 -0
- package/lib/components/views/GridView/SharedContextControls.d.ts +47 -0
- package/lib/components/views/GridView/SharedContextControls.js +95 -0
- package/lib/components/views/GridView/cells/BooleanCell.d.ts +44 -0
- package/lib/components/views/GridView/cells/BooleanCell.js +49 -0
- package/lib/components/views/GridView/cells/DropdownCell.d.ts +58 -0
- package/lib/components/views/GridView/cells/DropdownCell.js +182 -0
- package/lib/components/views/GridView/cells/StringCell.d.ts +57 -0
- package/lib/components/views/GridView/cells/StringCell.js +106 -0
- package/lib/components/views/GridView/cells/TriStateCell.d.ts +54 -0
- package/lib/components/views/GridView/cells/TriStateCell.js +112 -0
- package/lib/components/views/GridView/cells/index.d.ts +15 -0
- package/lib/components/views/GridView/cells/index.js +11 -0
- package/lib/components/views/GridView/index.d.ts +53 -0
- package/lib/components/views/GridView/index.js +212 -0
- package/lib/components/views/ImportView/index.js +22 -19
- package/lib/components/views/MessagesWindow/index.js +4 -1
- package/lib/components/views/ResolutionView/index.js +8 -5
- package/lib/contexts/ObservabilityContext.d.ts +85 -0
- package/lib/contexts/ObservabilityContext.js +98 -0
- package/lib/contexts/index.d.ts +2 -0
- package/lib/contexts/index.js +24 -0
- package/lib/hooks/useConfigurationState.d.ts +3 -3
- package/lib/hooks/useResolutionState.js +850 -246
- package/lib/hooks/useResourceData.d.ts +7 -4
- package/lib/hooks/useResourceData.js +185 -184
- package/lib/index.d.ts +5 -1
- package/lib/index.js +8 -1
- package/lib/namespaces/GridTools.d.ts +136 -0
- package/lib/namespaces/GridTools.js +138 -0
- package/lib/namespaces/ObservabilityTools.d.ts +3 -0
- package/lib/namespaces/ObservabilityTools.js +23 -0
- package/lib/namespaces/ResolutionTools.d.ts +2 -1
- package/lib/namespaces/ResolutionTools.js +2 -0
- package/lib/namespaces/index.d.ts +2 -0
- package/lib/namespaces/index.js +2 -0
- package/lib/test/integration/observability.integration.test.d.ts +2 -0
- package/lib/test/unit/hooks/useResourceData.test.d.ts +2 -0
- package/lib/test/unit/utils/downloadHelper.test.d.ts +2 -0
- package/lib/test/unit/workflows/resolutionWorkflows.test.d.ts +2 -0
- package/lib/test/unit/workflows/resourceCreation.test.d.ts +2 -0
- package/lib/test/unit/workflows/resultPatternExtensions.test.d.ts +2 -0
- package/lib/test/unit/workflows/validation.test.d.ts +2 -0
- package/lib/types/index.d.ts +387 -20
- package/lib/types/index.js +2 -1
- package/lib/utils/cellValidation.d.ts +113 -0
- package/lib/utils/cellValidation.js +248 -0
- package/lib/utils/downloadHelper.d.ts +66 -0
- package/lib/utils/downloadHelper.js +195 -0
- package/lib/utils/observability/factories.d.ts +29 -0
- package/lib/utils/observability/factories.js +58 -0
- package/lib/utils/observability/implementations.d.ts +61 -0
- package/lib/utils/observability/implementations.js +103 -0
- package/lib/utils/observability/index.d.ts +4 -0
- package/lib/utils/observability/index.js +26 -0
- package/lib/utils/observability/interfaces.d.ts +30 -0
- package/lib/utils/observability/interfaces.js +23 -0
- package/lib/utils/resolutionEditing.js +2 -1
- package/lib/utils/resourceSelector.d.ts +97 -0
- package/lib/utils/resourceSelector.js +195 -0
- package/lib/utils/resourceSelectors.d.ts +146 -0
- package/lib/utils/resourceSelectors.js +233 -0
- package/lib/utils/tsResIntegration.d.ts +6 -41
- package/lib/utils/tsResIntegration.js +20 -16
- package/lib/utils/zipLoader/zipProcessingHelpers.d.ts +3 -2
- package/lib/utils/zipLoader/zipProcessingHelpers.js +6 -5
- package/lib-commonjs/components/common/QualifierContextControl.js +4 -1
- package/lib-commonjs/components/common/ResourceTreeView.js +4 -1
- package/lib-commonjs/components/forms/GenericQualifierTypeEditForm.js +171 -0
- package/lib-commonjs/components/forms/index.js +3 -1
- package/lib-commonjs/components/orchestrator/ResourceOrchestrator.js +118 -51
- package/lib-commonjs/components/pickers/ResourcePicker/ResourcePickerTree.js +32 -10
- package/lib-commonjs/components/pickers/ResourcePicker/index.js +4 -2
- package/lib-commonjs/components/views/CompiledView/index.js +75 -16
- package/lib-commonjs/components/views/ConfigurationView/index.js +93 -34
- package/lib-commonjs/components/views/FilterView/index.js +7 -4
- package/lib-commonjs/components/views/GridView/EditableGridCell.js +232 -0
- package/lib-commonjs/components/views/GridView/GridSelector.js +94 -0
- package/lib-commonjs/components/views/GridView/MultiGridView.js +201 -0
- package/lib-commonjs/components/views/GridView/ResourceGrid.js +237 -0
- package/lib-commonjs/components/views/GridView/SharedContextControls.js +100 -0
- package/lib-commonjs/components/views/GridView/cells/BooleanCell.js +54 -0
- package/lib-commonjs/components/views/GridView/cells/DropdownCell.js +187 -0
- package/lib-commonjs/components/views/GridView/cells/StringCell.js +111 -0
- package/lib-commonjs/components/views/GridView/cells/TriStateCell.js +117 -0
- package/lib-commonjs/components/views/GridView/cells/index.js +18 -0
- package/lib-commonjs/components/views/GridView/index.js +217 -0
- package/lib-commonjs/components/views/ImportView/index.js +22 -19
- package/lib-commonjs/components/views/MessagesWindow/index.js +4 -1
- package/lib-commonjs/components/views/ResolutionView/index.js +8 -5
- package/lib-commonjs/contexts/ObservabilityContext.js +104 -0
- package/lib-commonjs/contexts/index.js +30 -0
- package/lib-commonjs/hooks/useResolutionState.js +849 -245
- package/lib-commonjs/hooks/useResourceData.js +184 -215
- package/lib-commonjs/index.js +15 -1
- package/lib-commonjs/namespaces/GridTools.js +161 -0
- package/lib-commonjs/namespaces/ObservabilityTools.js +33 -0
- package/lib-commonjs/namespaces/ResolutionTools.js +10 -1
- package/lib-commonjs/namespaces/index.js +3 -1
- package/lib-commonjs/types/index.js +10 -0
- package/lib-commonjs/utils/cellValidation.js +253 -0
- package/lib-commonjs/utils/downloadHelper.js +198 -0
- package/lib-commonjs/utils/observability/factories.js +63 -0
- package/lib-commonjs/utils/observability/implementations.js +109 -0
- package/lib-commonjs/utils/observability/index.js +36 -0
- package/lib-commonjs/utils/observability/interfaces.js +24 -0
- package/lib-commonjs/utils/resolutionEditing.js +2 -1
- package/lib-commonjs/utils/resourceSelector.js +200 -0
- package/lib-commonjs/utils/resourceSelectors.js +242 -0
- package/lib-commonjs/utils/tsResIntegration.js +21 -16
- package/lib-commonjs/utils/zipLoader/zipProcessingHelpers.js +7 -5
- package/package.json +7 -7
- package/src/components/common/QualifierContextControl.tsx +0 -338
- package/src/components/common/ResolutionContextOptionsControl.tsx +0 -450
- package/src/components/common/ResolutionResults/index.tsx +0 -481
- package/src/components/common/ResourceListView.tsx +0 -167
- package/src/components/common/ResourcePickerOptionsControl.tsx +0 -351
- package/src/components/common/ResourceTreeView.tsx +0 -417
- package/src/components/common/SourceResourceDetail/index.tsx +0 -493
- package/src/components/forms/HierarchyEditor.tsx +0 -285
- package/src/components/forms/QualifierEditForm.tsx +0 -487
- package/src/components/forms/QualifierTypeEditForm.tsx +0 -458
- package/src/components/forms/ResourceTypeEditForm.tsx +0 -437
- package/src/components/forms/index.ts +0 -11
- package/src/components/orchestrator/ResourceOrchestrator.tsx +0 -444
- package/src/components/pickers/ResourcePicker/README.md +0 -570
- package/src/components/pickers/ResourcePicker/ResourceItem.tsx +0 -127
- package/src/components/pickers/ResourcePicker/ResourcePickerList.tsx +0 -114
- package/src/components/pickers/ResourcePicker/ResourcePickerTree.tsx +0 -461
- package/src/components/pickers/ResourcePicker/index.tsx +0 -234
- package/src/components/pickers/ResourcePicker/types.ts +0 -301
- package/src/components/pickers/ResourcePicker/utils/treeNavigation.ts +0 -210
- package/src/components/views/CompiledView/index.tsx +0 -1342
- package/src/components/views/ConfigurationView/index.tsx +0 -848
- package/src/components/views/FilterView/index.tsx +0 -681
- package/src/components/views/ImportView/index.tsx +0 -789
- package/src/components/views/MessagesWindow/index.tsx +0 -325
- package/src/components/views/ResolutionView/EditableJsonView.tsx +0 -386
- package/src/components/views/ResolutionView/NewResourceModal.tsx +0 -158
- package/src/components/views/ResolutionView/UnifiedChangeControls.tsx +0 -163
- package/src/components/views/ResolutionView/index.tsx +0 -751
- package/src/components/views/SourceView/index.tsx +0 -291
- package/src/hooks/useConfigurationState.ts +0 -436
- package/src/hooks/useFilterState.ts +0 -150
- package/src/hooks/useResolutionState.ts +0 -893
- package/src/hooks/useResourceData.ts +0 -596
- package/src/hooks/useViewState.ts +0 -97
- package/src/index.ts +0 -68
- package/src/namespaces/ConfigurationTools.ts +0 -59
- package/src/namespaces/FilterTools.ts +0 -47
- package/src/namespaces/ImportTools.ts +0 -42
- package/src/namespaces/PickerTools.ts +0 -104
- package/src/namespaces/ResolutionTools.ts +0 -68
- package/src/namespaces/ResourceTools.ts +0 -106
- package/src/namespaces/TsResTools.ts +0 -49
- package/src/namespaces/ViewStateTools.ts +0 -91
- package/src/namespaces/ZipTools.ts +0 -49
- package/src/namespaces/index.ts +0 -49
- package/src/types/index.ts +0 -1273
- package/src/utils/configurationUtils.ts +0 -339
- package/src/utils/fileProcessing.ts +0 -164
- package/src/utils/filterResources.ts +0 -356
- package/src/utils/resolutionEditing.ts +0 -346
- package/src/utils/resolutionUtils.ts +0 -740
- package/src/utils/tsResIntegration.ts +0 -475
- package/src/utils/zipLoader/index.ts +0 -5
- package/src/utils/zipLoader/zipProcessingHelpers.ts +0 -46
- package/src/utils/zipLoader/zipUtils.ts +0 -7
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @fgv/ts-res-ui-components
|
|
2
2
|
|
|
3
|
-
React components for building user interfaces that work with the [ts-res](https://github.com/fgv/ts-res) multidimensional resource management library.
|
|
3
|
+
React components for building user interfaces that work with the [ts-res](https://github.com/ErikFortune/fgv/tree/main/libraries/ts-res) multidimensional resource management library.
|
|
4
4
|
|
|
5
5
|
## Overview
|
|
6
6
|
|
|
@@ -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
|
|
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
|
|
@@ -45,133 +35,62 @@ This library requires the following peer dependencies:
|
|
|
45
35
|
|
|
46
36
|
```json
|
|
47
37
|
{
|
|
48
|
-
"@fgv/ts-res": "
|
|
49
|
-
"@fgv/ts-utils": "
|
|
50
|
-
"@fgv/ts-json-base": "
|
|
51
|
-
"
|
|
52
|
-
"react
|
|
38
|
+
"@fgv/ts-res": ">=5.0.0",
|
|
39
|
+
"@fgv/ts-utils": ">=5.0.0",
|
|
40
|
+
"@fgv/ts-json-base": ">=5.0.0",
|
|
41
|
+
"@fgv/ts-json": ">=5.0.0",
|
|
42
|
+
"react": ">=18.0.0",
|
|
43
|
+
"react-dom": ">=18.0.0"
|
|
53
44
|
}
|
|
54
45
|
```
|
|
55
46
|
|
|
56
47
|
## Quick Start
|
|
57
48
|
|
|
58
|
-
###
|
|
49
|
+
### Basic Setup
|
|
59
50
|
|
|
60
51
|
```tsx
|
|
61
52
|
import React from 'react';
|
|
62
|
-
import { ResourceOrchestrator,
|
|
53
|
+
import { ResourceOrchestrator, ObservabilityProvider } from '@fgv/ts-res-ui-components';
|
|
63
54
|
|
|
64
|
-
|
|
55
|
+
function App() {
|
|
65
56
|
return (
|
|
66
|
-
<
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
resources={state.resources}
|
|
70
|
-
resolutionState={state.resolutionState}
|
|
71
|
-
resolutionActions={{
|
|
72
|
-
updateContextValue: actions.updateResolutionContext,
|
|
73
|
-
applyContext: actions.applyResolutionContext,
|
|
74
|
-
selectResource: actions.selectResourceForResolution,
|
|
75
|
-
setViewMode: actions.setResolutionViewMode,
|
|
76
|
-
resetCache: actions.resetResolutionCache,
|
|
77
|
-
saveEdit: actions.saveResourceEdit,
|
|
78
|
-
getEditedValue: actions.getEditedValue,
|
|
79
|
-
hasEdit: actions.hasResourceEdit,
|
|
80
|
-
clearEdits: actions.clearResourceEdits,
|
|
81
|
-
discardEdits: actions.discardResourceEdits,
|
|
82
|
-
startNewResource: actions.startNewResource,
|
|
83
|
-
updateNewResourceId: actions.updateNewResourceId,
|
|
84
|
-
selectResourceType: actions.selectResourceType,
|
|
85
|
-
saveNewResourceAsPending: actions.saveNewResourceAsPending,
|
|
86
|
-
cancelNewResource: actions.cancelNewResource,
|
|
87
|
-
removePendingResource: actions.removePendingResource,
|
|
88
|
-
markResourceForDeletion: actions.markResourceForDeletion,
|
|
89
|
-
applyPendingResources: actions.applyPendingResources,
|
|
90
|
-
discardPendingResources: actions.discardPendingResources
|
|
91
|
-
}}
|
|
92
|
-
allowResourceCreation
|
|
93
|
-
defaultResourceType="json"
|
|
94
|
-
showPendingResourcesInList
|
|
95
|
-
onMessage={actions.addMessage}
|
|
96
|
-
/>
|
|
97
|
-
)}
|
|
98
|
-
</ResourceOrchestrator>
|
|
57
|
+
<ObservabilityProvider>
|
|
58
|
+
<ResourceOrchestrator />
|
|
59
|
+
</ObservabilityProvider>
|
|
99
60
|
);
|
|
100
61
|
}
|
|
101
62
|
```
|
|
102
63
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
The `ResourceOrchestrator` component provides centralized state management for all ts-res UI functionality:
|
|
106
|
-
|
|
107
|
-
```tsx
|
|
108
|
-
import React from 'react';
|
|
109
|
-
import { ResourceOrchestrator, ImportView, SourceView } from '@fgv/ts-res-ui-components';
|
|
110
|
-
|
|
111
|
-
function App() {
|
|
112
|
-
return (
|
|
113
|
-
<ResourceOrchestrator>
|
|
114
|
-
{({ state, actions }) => (
|
|
115
|
-
<div className="min-h-screen bg-gray-50">
|
|
116
|
-
<div className="container mx-auto px-4 py-8">
|
|
117
|
-
<h1 className="text-3xl font-bold mb-8">Resource Manager</h1>
|
|
118
|
-
|
|
119
|
-
{!state.processedResources ? (
|
|
120
|
-
<ImportView
|
|
121
|
-
onImport={actions.importDirectory}
|
|
122
|
-
onBundleImport={actions.importBundle}
|
|
123
|
-
onZipImport={(zipData, config) => {
|
|
124
|
-
if (config) actions.applyConfiguration(config);
|
|
125
|
-
if (zipData.directory) actions.importDirectory(zipData.directory);
|
|
126
|
-
else if (zipData.files?.length) actions.importFiles(zipData.files);
|
|
127
|
-
}}
|
|
128
|
-
/>
|
|
129
|
-
) : (
|
|
130
|
-
<SourceView
|
|
131
|
-
resources={state.processedResources}
|
|
132
|
-
onExport={actions.exportData}
|
|
133
|
-
/>
|
|
134
|
-
)}
|
|
135
|
-
</div>
|
|
136
|
-
</div>
|
|
137
|
-
)}
|
|
138
|
-
</ResourceOrchestrator>
|
|
139
|
-
);
|
|
140
|
-
}
|
|
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.
|
|
141
65
|
|
|
142
|
-
|
|
143
|
-
```
|
|
66
|
+
## Core Concepts
|
|
144
67
|
|
|
145
|
-
###
|
|
68
|
+
### Resource Orchestrator
|
|
69
|
+
The central component that coordinates all resource operations. It manages the complete workflow:
|
|
146
70
|
|
|
147
|
-
|
|
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
|
|
148
76
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
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:
|
|
152
79
|
|
|
153
|
-
|
|
154
|
-
|
|
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
|
|
155
86
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
await actions.processFiles(importedFiles);
|
|
159
|
-
};
|
|
87
|
+
### Built-in Observability
|
|
88
|
+
All operations include comprehensive logging for debugging and user feedback:
|
|
160
89
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
{state.processedResources && (
|
|
166
|
-
<SourceView
|
|
167
|
-
resources={state.processedResources}
|
|
168
|
-
onExport={(data) => console.log('Export:', data)}
|
|
169
|
-
/>
|
|
170
|
-
)}
|
|
171
|
-
</div>
|
|
172
|
-
);
|
|
173
|
-
}
|
|
174
|
-
```
|
|
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
|
|
175
94
|
|
|
176
95
|
## Architecture
|
|
177
96
|
|
|
@@ -515,47 +434,128 @@ This is particularly useful when:
|
|
|
515
434
|
|
|
516
435
|
#### Resource Creation
|
|
517
436
|
|
|
518
|
-
ResolutionView
|
|
437
|
+
ResolutionView supports both atomic and sequential resource creation workflows:
|
|
438
|
+
|
|
439
|
+
##### Atomic Resource Creation (Recommended)
|
|
440
|
+
|
|
441
|
+
Use the new `createPendingResource` API for simple, robust resource creation:
|
|
442
|
+
|
|
443
|
+
```tsx
|
|
444
|
+
// Single atomic call to create a pending resource
|
|
445
|
+
const result = await actions.createPendingResource({
|
|
446
|
+
id: 'platform.languages.az-AZ', // Full resource ID (required)
|
|
447
|
+
resourceTypeName: 'json', // Resource type (required)
|
|
448
|
+
json: { text: 'Welcome', locale: 'az-AZ' } // JSON content (optional - uses base template if omitted)
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
if (result.isSuccess()) {
|
|
452
|
+
console.log('Resource created and added to pending resources');
|
|
453
|
+
// Apply all pending changes when ready
|
|
454
|
+
await actions.applyPendingResources();
|
|
455
|
+
} else {
|
|
456
|
+
console.error('Failed to create resource:', result.message);
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// Example: Creating a resource with base template (no JSON content)
|
|
460
|
+
const baseTemplateResult = await actions.createPendingResource({
|
|
461
|
+
id: 'platform.languages.fr-FR',
|
|
462
|
+
resourceTypeName: 'json'
|
|
463
|
+
// json omitted - resource type will provide base template (typically {})
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
if (baseTemplateResult.isSuccess()) {
|
|
467
|
+
console.log('Resource created using base template from resource type');
|
|
468
|
+
// You can then edit the resource using the UI or saveEdit()
|
|
469
|
+
}
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
**Benefits of the atomic API:**
|
|
473
|
+
- **Single Operation**: No multi-step sequencing required
|
|
474
|
+
- **Better Error Handling**: Returns `Result<void>` with detailed error messages
|
|
475
|
+
- **Validation**: Comprehensive validation of ID, type, and JSON content
|
|
476
|
+
- **Safe**: Prevents temporary IDs and ensures uniqueness
|
|
477
|
+
- **Context Stamping**: Automatically applies current context as conditions
|
|
478
|
+
|
|
479
|
+
##### Sequential Resource Creation (Legacy)
|
|
480
|
+
|
|
481
|
+
The traditional step-by-step workflow is still available:
|
|
482
|
+
|
|
483
|
+
```tsx
|
|
484
|
+
// Step 1: Start a new resource
|
|
485
|
+
const startResult = actions.startNewResource({ defaultTypeName: 'json' });
|
|
486
|
+
if (startResult.isFailure()) {
|
|
487
|
+
console.error('Failed to start resource:', startResult.message);
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// Step 2: Set the final resource ID
|
|
492
|
+
const idResult = actions.updateNewResourceId('platform.languages.az-AZ');
|
|
493
|
+
if (idResult.isFailure()) {
|
|
494
|
+
console.error('Invalid resource ID:', idResult.message);
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// Step 3: Update JSON content (optional)
|
|
499
|
+
const jsonResult = actions.updateNewResourceJson({
|
|
500
|
+
text: 'Welcome',
|
|
501
|
+
locale: 'az-AZ'
|
|
502
|
+
});
|
|
503
|
+
if (jsonResult.isFailure()) {
|
|
504
|
+
console.error('Invalid JSON:', jsonResult.message);
|
|
505
|
+
return;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// Step 4: Save as pending
|
|
509
|
+
const saveResult = actions.saveNewResourceAsPending();
|
|
510
|
+
if (saveResult.isFailure()) {
|
|
511
|
+
console.error('Failed to save:', saveResult.message);
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
// Step 5: Apply all pending changes
|
|
516
|
+
await actions.applyPendingResources();
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
**Enhanced Action Return Values:**
|
|
520
|
+
|
|
521
|
+
All resource creation actions now return `Result<T>` objects following the standard Result pattern:
|
|
522
|
+
- Use `.isSuccess()` and `.isFailure()` to check status
|
|
523
|
+
- Access success values with `.value` property (contains `draft`/`pendingResources` and `diagnostics`)
|
|
524
|
+
- Access error messages with `.message` property
|
|
525
|
+
- Multiline error messages include diagnostic information
|
|
526
|
+
|
|
527
|
+
```tsx
|
|
528
|
+
// Example: Working with Result values
|
|
529
|
+
const startResult = actions.startNewResource({ defaultTypeName: 'json' });
|
|
530
|
+
if (startResult.isSuccess()) {
|
|
531
|
+
console.log('Started draft:', startResult.value.draft);
|
|
532
|
+
console.log('Diagnostics:', startResult.value.diagnostics);
|
|
533
|
+
} else {
|
|
534
|
+
console.error('Error:', startResult.message); // May include diagnostics
|
|
535
|
+
}
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
##### UI Integration Example
|
|
519
539
|
|
|
520
540
|
```tsx
|
|
521
|
-
// Basic resource creation - user selects resource type
|
|
522
541
|
<ResolutionView
|
|
523
542
|
resources={state.processedResources}
|
|
524
543
|
resolutionState={resolutionState}
|
|
525
544
|
resolutionActions={resolutionActions}
|
|
526
545
|
allowResourceCreation={true}
|
|
546
|
+
defaultResourceType="json" // Optional: Host-controlled resource type
|
|
547
|
+
showPendingResourcesInList={true} // Show pending resources with visual distinction
|
|
527
548
|
onPendingResourcesApplied={(added, deleted) => {
|
|
549
|
+
console.log(`Applied ${added.length} additions, ${deleted.length} deletions`);
|
|
528
550
|
// Rebuild resource manager with new resources
|
|
529
551
|
const updatedResources = rebuildWithResources(added, deleted);
|
|
530
552
|
setState({ processedResources: updatedResources });
|
|
531
553
|
}}
|
|
532
554
|
/>
|
|
533
|
-
|
|
534
|
-
// Host-controlled resource type
|
|
535
|
-
<ResolutionView
|
|
536
|
-
resources={state.processedResources}
|
|
537
|
-
resolutionState={resolutionState}
|
|
538
|
-
resolutionActions={resolutionActions}
|
|
539
|
-
allowResourceCreation={true}
|
|
540
|
-
defaultResourceType="json" // Type selector hidden, always creates JSON resources
|
|
541
|
-
onPendingResourcesApplied={(added, deleted) => {
|
|
542
|
-
console.log(`Applied ${added.length} additions, ${deleted.length} deletions`);
|
|
543
|
-
}}
|
|
544
|
-
/>
|
|
545
|
-
|
|
546
|
-
// With custom resource types
|
|
547
|
-
<ResolutionView
|
|
548
|
-
resources={state.processedResources}
|
|
549
|
-
resolutionState={resolutionState}
|
|
550
|
-
resolutionActions={resolutionActions}
|
|
551
|
-
allowResourceCreation={true}
|
|
552
|
-
resourceTypeFactory={[customType1, customType2]} // Provide custom resource types
|
|
553
|
-
showPendingResourcesInList={true} // Show pending resources with visual distinction
|
|
554
|
-
/>
|
|
555
555
|
```
|
|
556
556
|
|
|
557
557
|
**Unified Change Workflow (Edits, Additions, Deletions):**
|
|
558
|
-
1.
|
|
558
|
+
1. Use `createPendingResource()` or the traditional UI workflow to create resources
|
|
559
559
|
2. Edit existing resources from the results pane using the JSON or custom editors
|
|
560
560
|
3. Mark resources for deletion where supported
|
|
561
561
|
4. All changes appear in a single "Pending Changes" bar with counts (edits/additions/deletions)
|
|
@@ -563,12 +563,70 @@ ResolutionView now supports creating new resources directly in the UI with a pen
|
|
|
563
563
|
6. Or click "Discard Changes" to remove all pending changes
|
|
564
564
|
|
|
565
565
|
**Key features:**
|
|
566
|
+
- **Atomic Creation**: Single API call creates complete resources
|
|
567
|
+
- **Enhanced Error Handling**: Detailed validation and error messages
|
|
566
568
|
- **Template-based creation**: Resource types provide default templates for new resources
|
|
567
569
|
- **Pending workflow**: Resources aren't added immediately, allowing review before applying
|
|
568
570
|
- **Host control**: Can specify a default resource type to hide the type selector
|
|
569
571
|
- **Batch operations**: Create multiple resources before applying
|
|
570
572
|
- **Visual feedback**: Pending resources shown with distinct styling
|
|
571
|
-
- **Validation**:
|
|
573
|
+
- **ID Validation**: Comprehensive resource ID validation and uniqueness checking
|
|
574
|
+
|
|
575
|
+
##### Resource ID Requirements
|
|
576
|
+
|
|
577
|
+
**IMPORTANT**: All pending resources use **full resource IDs** as keys, never leaf IDs:
|
|
578
|
+
|
|
579
|
+
```tsx
|
|
580
|
+
// ✅ Correct: Full resource IDs
|
|
581
|
+
createPendingResource({
|
|
582
|
+
id: 'platform.languages.az-AZ', // Full path
|
|
583
|
+
resourceTypeName: 'json',
|
|
584
|
+
json: { text: 'Azərbaycan dili' }
|
|
585
|
+
});
|
|
586
|
+
|
|
587
|
+
// ❌ Wrong: Leaf IDs
|
|
588
|
+
createPendingResource({
|
|
589
|
+
id: 'az-AZ', // Just the leaf - will be rejected
|
|
590
|
+
resourceTypeName: 'json',
|
|
591
|
+
json: { text: 'Azərbaycan dili' }
|
|
592
|
+
});
|
|
593
|
+
```
|
|
594
|
+
|
|
595
|
+
##### Helper Functions for Pending Resources
|
|
596
|
+
|
|
597
|
+
```tsx
|
|
598
|
+
import { ResolutionTools } from '@fgv/ts-res-ui-components';
|
|
599
|
+
|
|
600
|
+
// Get pending resources by type
|
|
601
|
+
const jsonResources = ResolutionTools.getPendingAdditionsByType(
|
|
602
|
+
resolutionState.pendingResources,
|
|
603
|
+
'json'
|
|
604
|
+
);
|
|
605
|
+
|
|
606
|
+
// Check if a resource is pending
|
|
607
|
+
const isPending = ResolutionTools.isPendingAddition(
|
|
608
|
+
'platform.languages.az-AZ',
|
|
609
|
+
resolutionState.pendingResources
|
|
610
|
+
);
|
|
611
|
+
|
|
612
|
+
// Work with resource IDs
|
|
613
|
+
const leafIdResult = ResolutionTools.deriveLeafId('platform.languages.az-AZ');
|
|
614
|
+
console.log(leafIdResult.value); // 'az-AZ'
|
|
615
|
+
|
|
616
|
+
const fullIdResult = ResolutionTools.deriveFullId('platform.languages', 'az-AZ');
|
|
617
|
+
console.log(fullIdResult.value); // 'platform.languages.az-AZ'
|
|
618
|
+
|
|
619
|
+
// Get statistics
|
|
620
|
+
const stats = ResolutionTools.getPendingResourceStats(resolutionState.pendingResources);
|
|
621
|
+
console.log(`${stats.totalCount} pending resources`);
|
|
622
|
+
console.log(`Types: ${Object.keys(stats.byType).join(', ')}`);
|
|
623
|
+
|
|
624
|
+
// Validate pending resource keys (diagnostic)
|
|
625
|
+
const validation = ResolutionTools.validatePendingResourceKeys(resolutionState.pendingResources);
|
|
626
|
+
if (validation.isFailure()) {
|
|
627
|
+
console.error('Key validation failed:', validation.message);
|
|
628
|
+
}
|
|
629
|
+
```
|
|
572
630
|
|
|
573
631
|
#### Custom Resource Editors
|
|
574
632
|
|
|
@@ -1254,6 +1312,181 @@ All components accept a `className` prop for custom styling:
|
|
|
1254
1312
|
/>
|
|
1255
1313
|
```
|
|
1256
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
|
+
|
|
1257
1490
|
## Advanced Usage
|
|
1258
1491
|
|
|
1259
1492
|
### Custom Resource Processing
|
|
@@ -1349,21 +1582,25 @@ For better organization and discoverability, utility functions are organized int
|
|
|
1349
1582
|
|
|
1350
1583
|
```tsx
|
|
1351
1584
|
import {
|
|
1352
|
-
FilterTools,
|
|
1353
|
-
ResolutionTools,
|
|
1585
|
+
FilterTools, // FilterView + filtering utilities
|
|
1586
|
+
ResolutionTools, // ResolutionView + resolution utilities
|
|
1354
1587
|
ConfigurationTools, // ConfigurationView + configuration utilities
|
|
1355
|
-
TsResTools,
|
|
1356
|
-
|
|
1357
|
-
ZipTools,
|
|
1358
|
-
|
|
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
|
|
1359
1595
|
} from '@fgv/ts-res-ui-components';
|
|
1360
1596
|
|
|
1361
1597
|
// Use view components from namespaces
|
|
1362
1598
|
<FilterTools.FilterView {...filterProps} />
|
|
1363
1599
|
<ResolutionTools.ResolutionView {...resolutionProps} />
|
|
1364
|
-
<
|
|
1600
|
+
<ViewStateTools.MessagesWindow {...messageProps} />
|
|
1365
1601
|
<TsResTools.SourceView {...sourceProps} />
|
|
1366
1602
|
<ZipTools.ImportView {...importProps} />
|
|
1603
|
+
<GridTools.GridView {...gridProps} />
|
|
1367
1604
|
|
|
1368
1605
|
// Use utility functions from namespaces
|
|
1369
1606
|
const hasFilters = FilterTools.hasFilterValues(filterState.values);
|
|
@@ -1372,6 +1609,15 @@ const system = await TsResTools.createTsResSystemFromConfig(config);
|
|
|
1372
1609
|
|
|
1373
1610
|
// ZIP processing helpers for ts-res-ui-components integration
|
|
1374
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);
|
|
1375
1621
|
```
|
|
1376
1622
|
|
|
1377
1623
|
### Namespace Contents
|
|
@@ -1596,6 +1842,6 @@ The API documentation includes detailed examples, usage patterns, and type infor
|
|
|
1596
1842
|
For questions and support, please:
|
|
1597
1843
|
|
|
1598
1844
|
1. Check the [API documentation](./docs/index.md) for detailed component usage
|
|
1599
|
-
2. Review the [ts-res documentation](https://
|
|
1600
|
-
3. Search [existing issues](https://github.com/fgv/
|
|
1601
|
-
4. Create a [new issue](https://github.com/fgv/
|
|
1845
|
+
2. Review the [ts-res documentation](https://github.com/ErikFortune/fgv/tree/main/libraries/ts-res) for core concepts
|
|
1846
|
+
3. Search [existing issues](https://github.com/ErikFortune/fgv/issues)
|
|
1847
|
+
4. Create a [new issue](https://github.com/ErikFortune/fgv/issues/new)
|
package/config/jest.setup.js
CHANGED
|
@@ -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(() => ({
|