@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.
Files changed (192) hide show
  1. package/README.md +401 -155
  2. package/config/jest.setup.js +10 -0
  3. package/dist/ts-res-ui-components.d.ts +1657 -76
  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 +118 -51
  13. package/lib/components/pickers/ResourcePicker/ResourcePickerTree.js +32 -10
  14. package/lib/components/pickers/ResourcePicker/index.js +4 -2
  15. package/lib/components/views/CompiledView/index.js +75 -16
  16. package/lib/components/views/ConfigurationView/index.js +94 -35
  17. package/lib/components/views/FilterView/index.js +7 -4
  18. package/lib/components/views/GridView/EditableGridCell.d.ts +76 -0
  19. package/lib/components/views/GridView/EditableGridCell.js +224 -0
  20. package/lib/components/views/GridView/GridSelector.d.ts +43 -0
  21. package/lib/components/views/GridView/GridSelector.js +89 -0
  22. package/lib/components/views/GridView/MultiGridView.d.ts +85 -0
  23. package/lib/components/views/GridView/MultiGridView.js +196 -0
  24. package/lib/components/views/GridView/ResourceGrid.d.ts +38 -0
  25. package/lib/components/views/GridView/ResourceGrid.js +232 -0
  26. package/lib/components/views/GridView/SharedContextControls.d.ts +47 -0
  27. package/lib/components/views/GridView/SharedContextControls.js +95 -0
  28. package/lib/components/views/GridView/cells/BooleanCell.d.ts +44 -0
  29. package/lib/components/views/GridView/cells/BooleanCell.js +49 -0
  30. package/lib/components/views/GridView/cells/DropdownCell.d.ts +58 -0
  31. package/lib/components/views/GridView/cells/DropdownCell.js +182 -0
  32. package/lib/components/views/GridView/cells/StringCell.d.ts +57 -0
  33. package/lib/components/views/GridView/cells/StringCell.js +106 -0
  34. package/lib/components/views/GridView/cells/TriStateCell.d.ts +54 -0
  35. package/lib/components/views/GridView/cells/TriStateCell.js +112 -0
  36. package/lib/components/views/GridView/cells/index.d.ts +15 -0
  37. package/lib/components/views/GridView/cells/index.js +11 -0
  38. package/lib/components/views/GridView/index.d.ts +53 -0
  39. package/lib/components/views/GridView/index.js +212 -0
  40. package/lib/components/views/ImportView/index.js +22 -19
  41. package/lib/components/views/MessagesWindow/index.js +4 -1
  42. package/lib/components/views/ResolutionView/index.js +8 -5
  43. package/lib/contexts/ObservabilityContext.d.ts +85 -0
  44. package/lib/contexts/ObservabilityContext.js +98 -0
  45. package/lib/contexts/index.d.ts +2 -0
  46. package/lib/contexts/index.js +24 -0
  47. package/lib/hooks/useConfigurationState.d.ts +3 -3
  48. package/lib/hooks/useResolutionState.js +850 -246
  49. package/lib/hooks/useResourceData.d.ts +7 -4
  50. package/lib/hooks/useResourceData.js +185 -184
  51. package/lib/index.d.ts +5 -1
  52. package/lib/index.js +8 -1
  53. package/lib/namespaces/GridTools.d.ts +136 -0
  54. package/lib/namespaces/GridTools.js +138 -0
  55. package/lib/namespaces/ObservabilityTools.d.ts +3 -0
  56. package/lib/namespaces/ObservabilityTools.js +23 -0
  57. package/lib/namespaces/ResolutionTools.d.ts +2 -1
  58. package/lib/namespaces/ResolutionTools.js +2 -0
  59. package/lib/namespaces/index.d.ts +2 -0
  60. package/lib/namespaces/index.js +2 -0
  61. package/lib/test/integration/observability.integration.test.d.ts +2 -0
  62. package/lib/test/unit/hooks/useResourceData.test.d.ts +2 -0
  63. package/lib/test/unit/utils/downloadHelper.test.d.ts +2 -0
  64. package/lib/test/unit/workflows/resolutionWorkflows.test.d.ts +2 -0
  65. package/lib/test/unit/workflows/resourceCreation.test.d.ts +2 -0
  66. package/lib/test/unit/workflows/resultPatternExtensions.test.d.ts +2 -0
  67. package/lib/test/unit/workflows/validation.test.d.ts +2 -0
  68. package/lib/types/index.d.ts +387 -20
  69. package/lib/types/index.js +2 -1
  70. package/lib/utils/cellValidation.d.ts +113 -0
  71. package/lib/utils/cellValidation.js +248 -0
  72. package/lib/utils/downloadHelper.d.ts +66 -0
  73. package/lib/utils/downloadHelper.js +195 -0
  74. package/lib/utils/observability/factories.d.ts +29 -0
  75. package/lib/utils/observability/factories.js +58 -0
  76. package/lib/utils/observability/implementations.d.ts +61 -0
  77. package/lib/utils/observability/implementations.js +103 -0
  78. package/lib/utils/observability/index.d.ts +4 -0
  79. package/lib/utils/observability/index.js +26 -0
  80. package/lib/utils/observability/interfaces.d.ts +30 -0
  81. package/lib/utils/observability/interfaces.js +23 -0
  82. package/lib/utils/resolutionEditing.js +2 -1
  83. package/lib/utils/resourceSelector.d.ts +97 -0
  84. package/lib/utils/resourceSelector.js +195 -0
  85. package/lib/utils/resourceSelectors.d.ts +146 -0
  86. package/lib/utils/resourceSelectors.js +233 -0
  87. package/lib/utils/tsResIntegration.d.ts +6 -41
  88. package/lib/utils/tsResIntegration.js +20 -16
  89. package/lib/utils/zipLoader/zipProcessingHelpers.d.ts +3 -2
  90. package/lib/utils/zipLoader/zipProcessingHelpers.js +6 -5
  91. package/lib-commonjs/components/common/QualifierContextControl.js +4 -1
  92. package/lib-commonjs/components/common/ResourceTreeView.js +4 -1
  93. package/lib-commonjs/components/forms/GenericQualifierTypeEditForm.js +171 -0
  94. package/lib-commonjs/components/forms/index.js +3 -1
  95. package/lib-commonjs/components/orchestrator/ResourceOrchestrator.js +118 -51
  96. package/lib-commonjs/components/pickers/ResourcePicker/ResourcePickerTree.js +32 -10
  97. package/lib-commonjs/components/pickers/ResourcePicker/index.js +4 -2
  98. package/lib-commonjs/components/views/CompiledView/index.js +75 -16
  99. package/lib-commonjs/components/views/ConfigurationView/index.js +93 -34
  100. package/lib-commonjs/components/views/FilterView/index.js +7 -4
  101. package/lib-commonjs/components/views/GridView/EditableGridCell.js +232 -0
  102. package/lib-commonjs/components/views/GridView/GridSelector.js +94 -0
  103. package/lib-commonjs/components/views/GridView/MultiGridView.js +201 -0
  104. package/lib-commonjs/components/views/GridView/ResourceGrid.js +237 -0
  105. package/lib-commonjs/components/views/GridView/SharedContextControls.js +100 -0
  106. package/lib-commonjs/components/views/GridView/cells/BooleanCell.js +54 -0
  107. package/lib-commonjs/components/views/GridView/cells/DropdownCell.js +187 -0
  108. package/lib-commonjs/components/views/GridView/cells/StringCell.js +111 -0
  109. package/lib-commonjs/components/views/GridView/cells/TriStateCell.js +117 -0
  110. package/lib-commonjs/components/views/GridView/cells/index.js +18 -0
  111. package/lib-commonjs/components/views/GridView/index.js +217 -0
  112. package/lib-commonjs/components/views/ImportView/index.js +22 -19
  113. package/lib-commonjs/components/views/MessagesWindow/index.js +4 -1
  114. package/lib-commonjs/components/views/ResolutionView/index.js +8 -5
  115. package/lib-commonjs/contexts/ObservabilityContext.js +104 -0
  116. package/lib-commonjs/contexts/index.js +30 -0
  117. package/lib-commonjs/hooks/useResolutionState.js +849 -245
  118. package/lib-commonjs/hooks/useResourceData.js +184 -215
  119. package/lib-commonjs/index.js +15 -1
  120. package/lib-commonjs/namespaces/GridTools.js +161 -0
  121. package/lib-commonjs/namespaces/ObservabilityTools.js +33 -0
  122. package/lib-commonjs/namespaces/ResolutionTools.js +10 -1
  123. package/lib-commonjs/namespaces/index.js +3 -1
  124. package/lib-commonjs/types/index.js +10 -0
  125. package/lib-commonjs/utils/cellValidation.js +253 -0
  126. package/lib-commonjs/utils/downloadHelper.js +198 -0
  127. package/lib-commonjs/utils/observability/factories.js +63 -0
  128. package/lib-commonjs/utils/observability/implementations.js +109 -0
  129. package/lib-commonjs/utils/observability/index.js +36 -0
  130. package/lib-commonjs/utils/observability/interfaces.js +24 -0
  131. package/lib-commonjs/utils/resolutionEditing.js +2 -1
  132. package/lib-commonjs/utils/resourceSelector.js +200 -0
  133. package/lib-commonjs/utils/resourceSelectors.js +242 -0
  134. package/lib-commonjs/utils/tsResIntegration.js +21 -16
  135. package/lib-commonjs/utils/zipLoader/zipProcessingHelpers.js +7 -5
  136. package/package.json +7 -7
  137. package/src/components/common/QualifierContextControl.tsx +0 -338
  138. package/src/components/common/ResolutionContextOptionsControl.tsx +0 -450
  139. package/src/components/common/ResolutionResults/index.tsx +0 -481
  140. package/src/components/common/ResourceListView.tsx +0 -167
  141. package/src/components/common/ResourcePickerOptionsControl.tsx +0 -351
  142. package/src/components/common/ResourceTreeView.tsx +0 -417
  143. package/src/components/common/SourceResourceDetail/index.tsx +0 -493
  144. package/src/components/forms/HierarchyEditor.tsx +0 -285
  145. package/src/components/forms/QualifierEditForm.tsx +0 -487
  146. package/src/components/forms/QualifierTypeEditForm.tsx +0 -458
  147. package/src/components/forms/ResourceTypeEditForm.tsx +0 -437
  148. package/src/components/forms/index.ts +0 -11
  149. package/src/components/orchestrator/ResourceOrchestrator.tsx +0 -444
  150. package/src/components/pickers/ResourcePicker/README.md +0 -570
  151. package/src/components/pickers/ResourcePicker/ResourceItem.tsx +0 -127
  152. package/src/components/pickers/ResourcePicker/ResourcePickerList.tsx +0 -114
  153. package/src/components/pickers/ResourcePicker/ResourcePickerTree.tsx +0 -461
  154. package/src/components/pickers/ResourcePicker/index.tsx +0 -234
  155. package/src/components/pickers/ResourcePicker/types.ts +0 -301
  156. package/src/components/pickers/ResourcePicker/utils/treeNavigation.ts +0 -210
  157. package/src/components/views/CompiledView/index.tsx +0 -1342
  158. package/src/components/views/ConfigurationView/index.tsx +0 -848
  159. package/src/components/views/FilterView/index.tsx +0 -681
  160. package/src/components/views/ImportView/index.tsx +0 -789
  161. package/src/components/views/MessagesWindow/index.tsx +0 -325
  162. package/src/components/views/ResolutionView/EditableJsonView.tsx +0 -386
  163. package/src/components/views/ResolutionView/NewResourceModal.tsx +0 -158
  164. package/src/components/views/ResolutionView/UnifiedChangeControls.tsx +0 -163
  165. package/src/components/views/ResolutionView/index.tsx +0 -751
  166. package/src/components/views/SourceView/index.tsx +0 -291
  167. package/src/hooks/useConfigurationState.ts +0 -436
  168. package/src/hooks/useFilterState.ts +0 -150
  169. package/src/hooks/useResolutionState.ts +0 -893
  170. package/src/hooks/useResourceData.ts +0 -596
  171. package/src/hooks/useViewState.ts +0 -97
  172. package/src/index.ts +0 -68
  173. package/src/namespaces/ConfigurationTools.ts +0 -59
  174. package/src/namespaces/FilterTools.ts +0 -47
  175. package/src/namespaces/ImportTools.ts +0 -42
  176. package/src/namespaces/PickerTools.ts +0 -104
  177. package/src/namespaces/ResolutionTools.ts +0 -68
  178. package/src/namespaces/ResourceTools.ts +0 -106
  179. package/src/namespaces/TsResTools.ts +0 -49
  180. package/src/namespaces/ViewStateTools.ts +0 -91
  181. package/src/namespaces/ZipTools.ts +0 -49
  182. package/src/namespaces/index.ts +0 -49
  183. package/src/types/index.ts +0 -1273
  184. package/src/utils/configurationUtils.ts +0 -339
  185. package/src/utils/fileProcessing.ts +0 -164
  186. package/src/utils/filterResources.ts +0 -356
  187. package/src/utils/resolutionEditing.ts +0 -346
  188. package/src/utils/resolutionUtils.ts +0 -740
  189. package/src/utils/tsResIntegration.ts +0 -475
  190. package/src/utils/zipLoader/index.ts +0 -5
  191. package/src/utils/zipLoader/zipProcessingHelpers.ts +0 -46
  192. package/src/utils/zipLoader/zipUtils.ts +0 -7
@@ -1,234 +0,0 @@
1
- import React, { useState, useMemo, useCallback } from 'react';
2
- import { MagnifyingGlassIcon, ListBulletIcon, FolderIcon } from '@heroicons/react/24/outline';
3
- import { ResourcePickerProps, ResourceSelection, ResourcePickerOptions } from './types';
4
- import { ResourcePickerList } from './ResourcePickerList';
5
- import { ResourcePickerTree } from './ResourcePickerTree';
6
- import { searchResources, filterTreeBranch } from './utils/treeNavigation';
7
-
8
- /**
9
- * Comprehensive resource picker component with search, view modes, and annotation support.
10
- *
11
- * The ResourcePicker provides a flexible interface for browsing and selecting resources
12
- * from processed resource collections. It supports both list and tree view modes,
13
- * search functionality, visual annotations, and pending resource management.
14
- *
15
- * Key features:
16
- * - **Multiple view modes**: List view for simple browsing, tree view for hierarchical navigation
17
- * - **Search functionality**: Search across all resources or within a specific branch
18
- * - **Visual annotations**: Display badges, indicators, and suffixes for enhanced UX
19
- * - **Pending resources**: Show unsaved changes alongside persisted resources
20
- * - **Branch isolation**: Focus on a specific branch node of the resource tree
21
- * - **Type safety**: Full TypeScript support with generic resource data types
22
- *
23
- * @example
24
- * ```tsx
25
- * function MyResourceEditor() {
26
- * const [selectedId, setSelectedId] = useState<string | null>(null);
27
- * const [selectedData, setSelectedData] = useState<MyResourceType | null>(null);
28
- *
29
- * return (
30
- * <ResourcePicker<MyResourceType>
31
- * resources={processedResources}
32
- * selectedResourceId={selectedId}
33
- * onResourceSelect={(selection) => {
34
- * setSelectedId(selection.resourceId);
35
- * setSelectedData(selection.resourceData || null);
36
- *
37
- * if (selection.isPending) {
38
- * console.log(`Pending ${selection.pendingType} operation`);
39
- * }
40
- * }}
41
- * defaultView="tree"
42
- * enableSearch={true}
43
- * searchPlaceholder="Search resources..."
44
- * resourceAnnotations={{
45
- * 'user.welcome': {
46
- * badge: { text: '3', variant: 'info' },
47
- * suffix: '(3 candidates)'
48
- * }
49
- * }}
50
- * pendingResources={[{
51
- * id: 'user.new-item',
52
- * type: 'new',
53
- * displayName: 'New Welcome Message',
54
- * resourceData: { text: 'Hello World!' }
55
- * }]}
56
- * height="500px"
57
- * />
58
- * );
59
- * }
60
- * ```
61
- *
62
- * @public
63
- */
64
- export const ResourcePicker = <T = unknown,>({
65
- resources,
66
- selectedResourceId,
67
- onResourceSelect,
68
- resourceAnnotations,
69
- pendingResources,
70
- options,
71
- className = '',
72
- onMessage
73
- }: ResourcePickerProps<T>) => {
74
- // Extract options with defaults
75
- const {
76
- defaultView = 'list',
77
- showViewToggle = true,
78
- rootPath,
79
- hideRootNode = false,
80
- enableSearch = true,
81
- searchPlaceholder,
82
- searchScope = 'current-branch',
83
- emptyMessage,
84
- height = '600px'
85
- } = options || {};
86
- const [viewMode, setViewMode] = useState<'list' | 'tree'>(defaultView);
87
- const [searchTerm, setSearchTerm] = useState('');
88
-
89
- // Get resource IDs based on current filters
90
- const resourceIds = useMemo(() => {
91
- if (!resources?.summary.resourceIds) {
92
- return [];
93
- }
94
-
95
- let ids = resources.summary.resourceIds;
96
-
97
- // Apply branch filtering if specified
98
- if (rootPath) {
99
- ids = filterTreeBranch(ids, rootPath, hideRootNode);
100
- }
101
-
102
- // Apply search filtering
103
- if (searchTerm) {
104
- ids = searchResources(ids, searchTerm, searchScope, rootPath);
105
- }
106
-
107
- return ids;
108
- }, [resources?.summary.resourceIds, rootPath, hideRootNode, searchTerm, searchScope]);
109
-
110
- // Handle resource selection
111
- const handleResourceSelect = useCallback(
112
- (selection: ResourceSelection<T>) => {
113
- onResourceSelect(selection);
114
- if (selection.resourceId) {
115
- onMessage?.('info', `Selected resource: ${selection.resourceId}`);
116
- }
117
- },
118
- [onResourceSelect, onMessage]
119
- );
120
-
121
- // Calculate dynamic search placeholder
122
- const getSearchPlaceholder = () => {
123
- if (searchPlaceholder) {
124
- return searchPlaceholder;
125
- }
126
- if (rootPath && hideRootNode) {
127
- const segments = rootPath.split('/');
128
- const branchName = segments[segments.length - 1];
129
- return `Search ${branchName}...`;
130
- }
131
- return 'Search resources...';
132
- };
133
-
134
- // Handle empty state
135
- if (!resources) {
136
- return (
137
- <div className={`${className} p-4 text-center text-gray-500`}>
138
- <p>{emptyMessage || 'No resources loaded'}</p>
139
- </div>
140
- );
141
- }
142
-
143
- const containerHeight = typeof height === 'number' ? `${height}px` : height;
144
-
145
- return (
146
- <div className={`flex flex-col ${className}`} style={{ height: containerHeight }}>
147
- {/* Header with search and view toggle */}
148
- {(enableSearch || showViewToggle) && (
149
- <div className="flex flex-col gap-3 mb-4">
150
- {/* Search Box */}
151
- {enableSearch && (
152
- <div className="relative">
153
- <MagnifyingGlassIcon className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-gray-400" />
154
- <input
155
- type="text"
156
- placeholder={getSearchPlaceholder()}
157
- value={searchTerm}
158
- onChange={(e) => setSearchTerm(e.target.value)}
159
- className="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent text-sm"
160
- />
161
- </div>
162
- )}
163
-
164
- {/* View Mode Toggle */}
165
- {showViewToggle && (
166
- <div className="flex items-center justify-between">
167
- <span className="text-sm text-gray-600">
168
- {resourceIds.length} resource{resourceIds.length !== 1 ? 's' : ''}
169
- {searchTerm && ` matching "${searchTerm}"`}
170
- </span>
171
- <div className="flex items-center space-x-1 bg-gray-100 rounded-lg p-1">
172
- <button
173
- onClick={() => setViewMode('list')}
174
- className={`flex items-center px-2 py-1 text-xs font-medium rounded transition-colors ${
175
- viewMode === 'list'
176
- ? 'bg-white text-gray-900 shadow-sm'
177
- : 'text-gray-600 hover:text-gray-900'
178
- }`}
179
- title="List View"
180
- >
181
- <ListBulletIcon className="h-4 w-4" />
182
- <span className="ml-1">List</span>
183
- </button>
184
- <button
185
- onClick={() => setViewMode('tree')}
186
- className={`flex items-center px-2 py-1 text-xs font-medium rounded transition-colors ${
187
- viewMode === 'tree'
188
- ? 'bg-white text-gray-900 shadow-sm'
189
- : 'text-gray-600 hover:text-gray-900'
190
- }`}
191
- title="Tree View"
192
- >
193
- <FolderIcon className="h-4 w-4" />
194
- <span className="ml-1">Tree</span>
195
- </button>
196
- </div>
197
- </div>
198
- )}
199
- </div>
200
- )}
201
-
202
- {/* Resource List or Tree */}
203
- <div className="flex-1 overflow-y-auto border border-gray-200 rounded-lg bg-gray-50">
204
- {viewMode === 'tree' ? (
205
- <ResourcePickerTree<T>
206
- resources={resources}
207
- pendingResources={pendingResources}
208
- selectedResourceId={selectedResourceId}
209
- onResourceSelect={handleResourceSelect}
210
- resourceAnnotations={resourceAnnotations}
211
- searchTerm={searchTerm}
212
- rootPath={rootPath}
213
- hideRootNode={hideRootNode}
214
- emptyMessage={emptyMessage}
215
- />
216
- ) : (
217
- <ResourcePickerList<T>
218
- resourceIds={resources.summary.resourceIds || []}
219
- pendingResources={pendingResources}
220
- selectedResourceId={selectedResourceId}
221
- onResourceSelect={handleResourceSelect}
222
- resourceAnnotations={resourceAnnotations}
223
- searchTerm={searchTerm}
224
- rootPath={rootPath}
225
- hideRootNode={hideRootNode}
226
- emptyMessage={emptyMessage}
227
- />
228
- )}
229
- </div>
230
- </div>
231
- );
232
- };
233
-
234
- export default ResourcePicker;
@@ -1,301 +0,0 @@
1
- import React from 'react';
2
- import { ProcessedResources, ExtendedProcessedResources, ViewBaseProps } from '../../../types';
3
-
4
- /**
5
- * Resource selection data returned by the onResourceSelect callback.
6
- *
7
- * This interface provides comprehensive information about the selected resource,
8
- * eliminating the need for consumers to perform additional lookups.
9
- *
10
- * @example
11
- * ```tsx
12
- * const handleResourceSelect = (selection: ResourceSelection<MyResourceType>) => {
13
- * if (selection.resourceId) {
14
- * console.log('Selected:', selection.resourceId);
15
- * if (selection.resourceData) {
16
- * console.log('Data:', selection.resourceData);
17
- * }
18
- * if (selection.isPending) {
19
- * console.log('Pending operation:', selection.pendingType);
20
- * }
21
- * }
22
- * };
23
- * ```
24
- *
25
- * @public
26
- */
27
- export interface ResourceSelection<T = unknown> {
28
- /** The ID of the selected resource, or null if no selection */
29
- resourceId: string | null;
30
- /** The actual resource data if available and typed */
31
- resourceData?: T;
32
- /** Whether this is a pending (unsaved) resource */
33
- isPending?: boolean;
34
- /** Type of pending operation for unsaved resources */
35
- pendingType?: 'new' | 'modified' | 'deleted';
36
- }
37
-
38
- /**
39
- * UI behavior configuration options for ResourcePicker.
40
- *
41
- * This interface groups all UI-related options that control how the ResourcePicker
42
- * behaves and appears, separate from functional data like annotations and pending resources.
43
- *
44
- * @example
45
- * ```tsx
46
- * const pickerOptions: ResourcePickerOptions = {
47
- * defaultView: 'tree',
48
- * enableSearch: true,
49
- * searchPlaceholder: 'Find resources...',
50
- * rootPath: 'user.messages',
51
- * hideRootNode: true,
52
- * height: '400px'
53
- * };
54
- * ```
55
- *
56
- * @public
57
- */
58
- export interface ResourcePickerOptions {
59
- /** View and navigation options */
60
- /** Default view mode to use on initial render */
61
- defaultView?: 'list' | 'tree';
62
- /** Whether to show the list/tree view toggle buttons */
63
- showViewToggle?: boolean;
64
-
65
- /** Branch isolation options */
66
- /** Path to treat as root for tree branch isolation (e.g., "platform/territories") */
67
- rootPath?: string;
68
- /** Hide the root node itself, showing only its children */
69
- hideRootNode?: boolean;
70
-
71
- /** Search options */
72
- /** Whether to enable the search input */
73
- enableSearch?: boolean;
74
- /** Placeholder text for the search input */
75
- searchPlaceholder?: string;
76
- /** Scope of search - entire tree or just the currently visible branch */
77
- searchScope?: 'all' | 'current-branch';
78
-
79
- /** Appearance options */
80
- /** Message to display when no resources are available */
81
- emptyMessage?: string;
82
- /** Height of the picker component */
83
- height?: string | number;
84
- }
85
-
86
- /**
87
- * Props for the ResourcePicker component.
88
- *
89
- * The ResourcePicker is a comprehensive component for browsing and selecting resources
90
- * with support for multiple view modes, search, annotations, and pending resources.
91
- * UI behavior is controlled through the options object, while functional data is
92
- * passed as separate props.
93
- *
94
- * @example
95
- * ```tsx
96
- * <ResourcePicker
97
- * resources={processedResources}
98
- * selectedResourceId={currentId}
99
- * onResourceSelect={(selection) => {
100
- * setCurrentId(selection.resourceId);
101
- * if (selection.resourceData) {
102
- * // Use the resource data directly
103
- * handleResourceData(selection.resourceData);
104
- * }
105
- * }}
106
- * resourceAnnotations={{
107
- * 'res1': { badge: { text: '3', variant: 'info' } }
108
- * }}
109
- * options={{
110
- * defaultView: 'tree',
111
- * enableSearch: true,
112
- * searchPlaceholder: 'Find resources...',
113
- * height: '400px'
114
- * }}
115
- * />
116
- * ```
117
- *
118
- * @public
119
- */
120
- export interface ResourcePickerProps<T = unknown> extends ViewBaseProps {
121
- /** Core functionality */
122
- /** Processed resources to display in the picker */
123
- resources: ProcessedResources | ExtendedProcessedResources | null;
124
- /** Currently selected resource ID */
125
- selectedResourceId: string | null;
126
- /** Callback fired when a resource is selected, providing comprehensive selection data */
127
- onResourceSelect: (selection: ResourceSelection<T>) => void;
128
-
129
- /** Functional data */
130
- /** Annotations to display next to resource names (badges, indicators, etc.) */
131
- resourceAnnotations?: ResourceAnnotations;
132
- /** Pending (unsaved) resources to display alongside persisted resources */
133
- pendingResources?: PendingResource<T>[];
134
-
135
- /** UI behavior configuration */
136
- /** Options controlling picker appearance and behavior */
137
- options?: ResourcePickerOptions;
138
- }
139
-
140
- /**
141
- * Annotations that can be displayed next to resource names in the picker.
142
- *
143
- * This allows the host application to provide visual indicators for resources,
144
- * such as candidate counts, editing status, or validation states.
145
- *
146
- * @example
147
- * ```tsx
148
- * const annotations: ResourceAnnotations = {
149
- * 'user.welcome': {
150
- * badge: { text: '3', variant: 'info' },
151
- * suffix: '(3 candidates)'
152
- * },
153
- * 'user.modified': {
154
- * badge: { text: 'M', variant: 'edited' },
155
- * indicator: { type: 'dot', value: 'orange', tooltip: 'Modified' }
156
- * }
157
- * };
158
- * ```
159
- *
160
- * @public
161
- */
162
- export interface ResourceAnnotations {
163
- /** Map of resource IDs to their annotation configurations */
164
- [resourceId: string]: ResourceAnnotation;
165
- }
166
-
167
- /**
168
- * Individual resource annotation configuration.
169
- *
170
- * Supports multiple types of visual indicators that can be combined:
171
- * - Badge: Small colored badge with text
172
- * - Indicator: Dot, icon, or text indicator with optional tooltip
173
- * - Suffix: Additional content displayed after the resource name
174
- *
175
- * @example
176
- * ```tsx
177
- * const annotation: ResourceAnnotation = {
178
- * badge: { text: 'NEW', variant: 'new' },
179
- * indicator: {
180
- * type: 'icon',
181
- * value: <CheckIcon />,
182
- * tooltip: 'Validated'
183
- * },
184
- * suffix: <span className="text-gray-500">(5 candidates)</span>,
185
- * className: 'resource-highlighted'
186
- * };
187
- * ```
188
- *
189
- * @public
190
- */
191
- export interface ResourceAnnotation {
192
- /** Small colored badge displayed next to the resource name */
193
- badge?: {
194
- /** Text content of the badge */
195
- text: string;
196
- /** Visual style variant for the badge */
197
- variant: 'info' | 'warning' | 'success' | 'error' | 'edited' | 'new';
198
- };
199
- /** Visual indicator (dot, icon, or text) with optional tooltip */
200
- indicator?: {
201
- /** Type of indicator to display */
202
- type: 'dot' | 'icon' | 'text';
203
- /** Content of the indicator (color for dot, React element for icon, string for text) */
204
- value: string | React.ReactNode;
205
- /** Optional tooltip text shown on hover */
206
- tooltip?: string;
207
- };
208
- /** Additional content displayed after the resource name (e.g., candidate counts) */
209
- suffix?: React.ReactNode;
210
- /** Additional CSS class names to apply to the resource item */
211
- className?: string;
212
- }
213
-
214
- /**
215
- * Represents a resource that hasn't been persisted yet.
216
- *
217
- * Pending resources are displayed alongside persisted resources in the picker,
218
- * allowing users to interact with unsaved changes. They are visually distinguished
219
- * with appropriate styling and annotations.
220
- *
221
- * @example
222
- * ```tsx
223
- * const pendingResources: PendingResource<MyResourceType>[] = [
224
- * {
225
- * id: 'user.new-welcome',
226
- * type: 'new',
227
- * resourceType: 'string',
228
- * displayName: 'Welcome Message (New)',
229
- * resourceData: { text: 'Welcome!', locale: 'en' }
230
- * },
231
- * {
232
- * id: 'user.existing-modified',
233
- * type: 'modified',
234
- * displayName: 'User Profile (Modified)',
235
- * resourceData: { name: 'Updated Name' }
236
- * }
237
- * ];
238
- * ```
239
- *
240
- * @public
241
- */
242
- export interface PendingResource<T = unknown> {
243
- /** Unique identifier for the pending resource */
244
- id: string;
245
- /** Type of pending operation */
246
- type: 'new' | 'modified' | 'deleted';
247
- /** Optional resource type identifier */
248
- resourceType?: string;
249
- /** Display name for the resource in the picker */
250
- displayName?: string;
251
- /** The actual resource data with type safety */
252
- resourceData?: T;
253
- }
254
-
255
- /**
256
- * Props for individual resource items
257
- */
258
- export interface ResourceItemProps<T = unknown> {
259
- resourceId: string;
260
- displayName?: string;
261
- isSelected: boolean;
262
- isPending?: boolean;
263
- annotation?: ResourceAnnotation;
264
- onClick: (selection: ResourceSelection<T>) => void;
265
- searchTerm?: string;
266
- className?: string;
267
- resourceData?: T; // The actual resource data if available
268
- pendingType?: 'new' | 'modified' | 'deleted'; // Type of pending operation
269
- }
270
-
271
- /**
272
- * Props for the list view component
273
- */
274
- export interface ResourcePickerListProps<T = unknown> {
275
- resourceIds: string[];
276
- pendingResources?: PendingResource<T>[];
277
- selectedResourceId: string | null;
278
- onResourceSelect: (selection: ResourceSelection<T>) => void;
279
- resourceAnnotations?: ResourceAnnotations;
280
- searchTerm?: string;
281
- rootPath?: string;
282
- hideRootNode?: boolean;
283
- className?: string;
284
- emptyMessage?: string;
285
- }
286
-
287
- /**
288
- * Props for the tree view component
289
- */
290
- export interface ResourcePickerTreeProps<T = unknown> {
291
- resources: ProcessedResources | ExtendedProcessedResources;
292
- pendingResources?: PendingResource<T>[];
293
- selectedResourceId: string | null;
294
- onResourceSelect: (selection: ResourceSelection<T>) => void;
295
- resourceAnnotations?: ResourceAnnotations;
296
- searchTerm?: string;
297
- rootPath?: string;
298
- hideRootNode?: boolean;
299
- className?: string;
300
- emptyMessage?: string;
301
- }