@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
@@ -0,0 +1,111 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.StringCell = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const react_1 = tslib_1.__importStar(require("react"));
6
+ const outline_1 = require("@heroicons/react/24/outline");
7
+ const cellValidation_1 = require("../../../../utils/cellValidation");
8
+ /**
9
+ * StringCell component for editing string values with validation.
10
+ *
11
+ * Provides text input with configurable validation, visual error highlighting,
12
+ * and support for required fields, length limits, and pattern matching.
13
+ *
14
+ * @example
15
+ * ```tsx
16
+ * <StringCell
17
+ * value="user@example.com"
18
+ * resourceId="user-123"
19
+ * column={{
20
+ * id: 'email',
21
+ * validation: {
22
+ * required: true,
23
+ * pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/
24
+ * }
25
+ * }}
26
+ * isEditing={false}
27
+ * onChange={handleChange}
28
+ * onSave={handleSave}
29
+ * onValidationChange={handleValidation}
30
+ * />
31
+ * ```
32
+ * @public
33
+ */
34
+ const StringCell = ({ value, resourceId, column, isEditing, disabled = false, onChange, onStartEdit, onCancel, onSave, onValidationChange }) => {
35
+ const [editValue, setEditValue] = (0, react_1.useState)('');
36
+ const [validationError, setValidationError] = (0, react_1.useState)(null);
37
+ // Convert value to string for editing
38
+ const stringValue = react_1.default.useMemo(() => {
39
+ if (value === null || value === undefined)
40
+ return '';
41
+ if (typeof value === 'string')
42
+ return value;
43
+ return String(value);
44
+ }, [value]);
45
+ // Initialize edit value when editing starts
46
+ (0, react_1.useEffect)(() => {
47
+ if (isEditing) {
48
+ setEditValue(stringValue);
49
+ }
50
+ }, [isEditing, stringValue]);
51
+ // Validate the current edit value
52
+ const validateCurrentValue = (0, react_1.useCallback)(() => {
53
+ if (!isEditing)
54
+ return;
55
+ const validationResult = (0, cellValidation_1.validateCellValue)(editValue, column.validation);
56
+ if (validationResult.isFailure()) {
57
+ setValidationError(`Validation failed: ${validationResult.message}`);
58
+ onValidationChange(`Validation failed: ${validationResult.message}`);
59
+ return;
60
+ }
61
+ const result = validationResult.value;
62
+ const error = result.isValid ? null : result.error || null;
63
+ setValidationError(error);
64
+ onValidationChange(error);
65
+ }, [editValue, column.validation, isEditing, onValidationChange]);
66
+ // Validate whenever edit value changes
67
+ (0, react_1.useEffect)(() => {
68
+ validateCurrentValue();
69
+ }, [validateCurrentValue]);
70
+ // Handle input changes
71
+ const handleInputChange = (0, react_1.useCallback)((event) => {
72
+ const newValue = event.target.value;
73
+ setEditValue(newValue);
74
+ onChange(newValue);
75
+ }, [onChange]);
76
+ // Handle key presses
77
+ const handleKeyPress = (0, react_1.useCallback)((event) => {
78
+ if (event.key === 'Enter' && !validationError) {
79
+ onSave(editValue);
80
+ }
81
+ else if (event.key === 'Escape') {
82
+ onCancel();
83
+ }
84
+ }, [editValue, validationError, onSave, onCancel]);
85
+ // Handle save click
86
+ const handleSave = (0, react_1.useCallback)(() => {
87
+ if (!validationError) {
88
+ onSave(editValue);
89
+ }
90
+ }, [editValue, validationError, onSave]);
91
+ if (isEditing) {
92
+ return (react_1.default.createElement("div", { className: "relative" },
93
+ react_1.default.createElement("input", { type: "text", value: editValue, onChange: handleInputChange, onKeyDown: handleKeyPress, onBlur: handleSave, disabled: disabled, autoFocus: true, className: `w-full px-2 py-1 text-sm border rounded focus:outline-none focus:ring-2 ${validationError
94
+ ? 'border-red-500 focus:ring-red-500 bg-red-50'
95
+ : 'border-gray-300 focus:ring-blue-500'}`, placeholder: column.validation?.required ? `${column.title} (required)` : column.title }),
96
+ validationError && (react_1.default.createElement("div", { className: "absolute z-10 mt-1 p-2 bg-red-100 border border-red-200 rounded shadow-sm text-xs text-red-800 max-w-xs" },
97
+ react_1.default.createElement("div", { className: "flex items-center space-x-1" },
98
+ react_1.default.createElement(outline_1.ExclamationCircleIcon, { className: "h-3 w-3 flex-shrink-0" }),
99
+ react_1.default.createElement("span", null, validationError))))));
100
+ }
101
+ // Display mode
102
+ const displayValue = stringValue || (column.validation?.required ? '(required)' : '(empty)');
103
+ const isEmpty = !stringValue;
104
+ const isRequired = column.validation?.required;
105
+ return (react_1.default.createElement("div", { className: `px-3 py-2 text-sm cursor-pointer hover:bg-gray-50 ${isEmpty && isRequired ? 'text-red-600 bg-red-25' : 'text-gray-900'}`, onClick: disabled ? undefined : onStartEdit, title: disabled ? undefined : 'Click to edit' },
106
+ react_1.default.createElement("span", { className: isEmpty ? 'italic' : '' }, displayValue),
107
+ isEmpty && isRequired && react_1.default.createElement(outline_1.ExclamationCircleIcon, { className: "inline-block h-4 w-4 ml-1 text-red-500" })));
108
+ };
109
+ exports.StringCell = StringCell;
110
+ exports.default = exports.StringCell;
111
+ //# sourceMappingURL=StringCell.js.map
@@ -0,0 +1,117 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TriStateCell = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const react_1 = tslib_1.__importStar(require("react"));
6
+ const outline_1 = require("@heroicons/react/24/outline");
7
+ /**
8
+ * TriStateCell component for editing three-state boolean values.
9
+ *
10
+ * Supports true, false, and null/undefined states with two presentation modes:
11
+ * - Checkbox mode: 3-state checkbox (checked, unchecked, indeterminate)
12
+ * - Dropdown mode: Select dropdown with three options
13
+ *
14
+ * @example
15
+ * ```tsx
16
+ * <TriStateCell
17
+ * value={null}
18
+ * resourceId="feature-123"
19
+ * column={{ id: 'enabled', title: 'Feature Enabled' }}
20
+ * presentation="dropdown"
21
+ * onChange={handleChange}
22
+ * onSave={handleSave}
23
+ * onValidationChange={handleValidation}
24
+ * />
25
+ * ```
26
+ * @public
27
+ */
28
+ const TriStateCell = ({ value, resourceId, column, disabled = false, presentation = 'dropdown', labels, onChange, onSave, onValidationChange }) => {
29
+ // Convert value to tri-state boolean
30
+ const triStateValue = (0, react_1.useMemo)(() => {
31
+ if (value === null || value === undefined)
32
+ return null;
33
+ if (typeof value === 'boolean')
34
+ return value;
35
+ if (typeof value === 'string') {
36
+ if (value.toLowerCase() === 'true')
37
+ return true;
38
+ if (value.toLowerCase() === 'false')
39
+ return false;
40
+ return null;
41
+ }
42
+ if (typeof value === 'number') {
43
+ if (value === 1)
44
+ return true;
45
+ if (value === 0)
46
+ return false;
47
+ return null;
48
+ }
49
+ return Boolean(value);
50
+ }, [value]);
51
+ // Handle checkbox change (cycles through states)
52
+ const handleCheckboxChange = (0, react_1.useCallback)(() => {
53
+ let newValue;
54
+ if (triStateValue === null) {
55
+ newValue = true;
56
+ }
57
+ else if (triStateValue === true) {
58
+ newValue = false;
59
+ }
60
+ else {
61
+ newValue = null;
62
+ }
63
+ onChange(newValue);
64
+ onSave(newValue);
65
+ onValidationChange(null);
66
+ }, [triStateValue, onChange, onSave, onValidationChange]);
67
+ // Handle dropdown change
68
+ const handleDropdownChange = (0, react_1.useCallback)((event) => {
69
+ let newValue;
70
+ switch (event.target.value) {
71
+ case 'true':
72
+ newValue = true;
73
+ break;
74
+ case 'false':
75
+ newValue = false;
76
+ break;
77
+ default:
78
+ newValue = null;
79
+ break;
80
+ }
81
+ onChange(newValue);
82
+ onSave(newValue);
83
+ onValidationChange(null);
84
+ }, [onChange, onSave, onValidationChange]);
85
+ if (presentation === 'checkbox') {
86
+ // 3-state checkbox presentation
87
+ const checkboxRef = react_1.default.useRef(null);
88
+ // Update checkbox indeterminate state
89
+ react_1.default.useEffect(() => {
90
+ if (checkboxRef.current) {
91
+ checkboxRef.current.indeterminate = triStateValue === null;
92
+ }
93
+ }, [triStateValue]);
94
+ return (react_1.default.createElement("div", { className: "px-3 py-2 flex items-center justify-center" },
95
+ react_1.default.createElement("label", { className: "inline-flex items-center" },
96
+ react_1.default.createElement("input", { ref: checkboxRef, type: "checkbox", checked: triStateValue === true, onChange: handleCheckboxChange, disabled: disabled, className: `h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded ${disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'}` }),
97
+ react_1.default.createElement("span", { className: "sr-only" }, column.title))));
98
+ }
99
+ // Default labels (can be overridden)
100
+ const defaultLabels = {
101
+ trueLabel: 'Yes',
102
+ falseLabel: 'No',
103
+ undefinedLabel: 'Unset'
104
+ };
105
+ const effectiveLabels = labels || defaultLabels;
106
+ return (react_1.default.createElement("div", { className: "px-3 py-2" },
107
+ react_1.default.createElement("div", { className: "relative" },
108
+ react_1.default.createElement("select", { value: triStateValue === null ? 'null' : String(triStateValue), onChange: handleDropdownChange, disabled: disabled, className: `w-full appearance-none bg-white border border-gray-300 rounded px-3 py-1 pr-8 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${disabled ? 'opacity-50 cursor-not-allowed bg-gray-100' : 'cursor-pointer'}` },
109
+ react_1.default.createElement("option", { value: "null" }, effectiveLabels.undefinedLabel),
110
+ react_1.default.createElement("option", { value: "true" }, effectiveLabels.trueLabel),
111
+ react_1.default.createElement("option", { value: "false" }, effectiveLabels.falseLabel)),
112
+ react_1.default.createElement("div", { className: "absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none" },
113
+ react_1.default.createElement(outline_1.ChevronDownIcon, { className: "h-4 w-4 text-gray-400" })))));
114
+ };
115
+ exports.TriStateCell = TriStateCell;
116
+ exports.default = exports.TriStateCell;
117
+ //# sourceMappingURL=TriStateCell.js.map
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ /**
3
+ * Specialized cell components for GridView.
4
+ *
5
+ * This module exports all the specialized cell types that can be used
6
+ * in grid columns for different data types and editing requirements.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.DropdownCell = exports.TriStateCell = exports.BooleanCell = exports.StringCell = void 0;
10
+ var StringCell_1 = require("./StringCell");
11
+ Object.defineProperty(exports, "StringCell", { enumerable: true, get: function () { return StringCell_1.StringCell; } });
12
+ var BooleanCell_1 = require("./BooleanCell");
13
+ Object.defineProperty(exports, "BooleanCell", { enumerable: true, get: function () { return BooleanCell_1.BooleanCell; } });
14
+ var TriStateCell_1 = require("./TriStateCell");
15
+ Object.defineProperty(exports, "TriStateCell", { enumerable: true, get: function () { return TriStateCell_1.TriStateCell; } });
16
+ var DropdownCell_1 = require("./DropdownCell");
17
+ Object.defineProperty(exports, "DropdownCell", { enumerable: true, get: function () { return DropdownCell_1.DropdownCell; } });
18
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,217 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GridView = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const react_1 = tslib_1.__importStar(require("react"));
6
+ const outline_1 = require("@heroicons/react/24/outline");
7
+ const resourceSelector_1 = require("../../../utils/resourceSelector");
8
+ const QualifierContextControl_1 = require("../../common/QualifierContextControl");
9
+ const UnifiedChangeControls_1 = require("../ResolutionView/UnifiedChangeControls");
10
+ const ResourceGrid_1 = require("./ResourceGrid");
11
+ /**
12
+ * GridView component for displaying multiple resources in a tabular format.
13
+ *
14
+ * Provides a grid-based interface for viewing and editing multiple resources
15
+ * simultaneously, with configurable column mappings and shared context management.
16
+ * Leverages the same state management and batch processing as ResolutionView.
17
+ *
18
+ * **Key Features:**
19
+ * - **Multi-resource display**: View multiple resources in rows with configurable columns
20
+ * - **Column mapping**: Host-defined extraction of properties from resolved resources
21
+ * - **Batch editing**: Edit multiple resource values with unified batch application
22
+ * - **Context integration**: Same context management as ResolutionView
23
+ * - **Resource filtering**: Flexible resource selection via built-in and custom selectors
24
+ * - **Change management**: Leverages existing UnifiedChangeControls for batch operations
25
+ *
26
+ * @example
27
+ * ```tsx
28
+ * import { GridView } from '@fgv/ts-res-ui-components';
29
+ *
30
+ * // Define grid configuration
31
+ * const gridConfig = {
32
+ * id: 'user-messages',
33
+ * title: 'User Messages',
34
+ * resourceSelection: { type: 'prefix', prefix: 'user.' },
35
+ * columnMapping: [{
36
+ * resourceType: 'text-resource',
37
+ * columns: [
38
+ * { id: 'text', title: 'Message Text', dataPath: 'text', editable: true },
39
+ * { id: 'locale', title: 'Locale', dataPath: 'locale' }
40
+ * ]
41
+ * }]
42
+ * };
43
+ *
44
+ * function MyGridApp() {
45
+ * return (
46
+ * <GridView
47
+ * gridConfig={gridConfig}
48
+ * resources={processedResources}
49
+ * resolutionState={resolutionState}
50
+ * resolutionActions={resolutionActions}
51
+ * availableQualifiers={['language', 'territory', 'platform']}
52
+ * />
53
+ * );
54
+ * }
55
+ * ```
56
+ *
57
+ * @public
58
+ */
59
+ const GridView = ({ gridConfig, resources, resolutionState, resolutionActions, availableQualifiers = [], contextOptions, filterState, filterResult, showContextControls = true, showChangeControls = true, onMessage, className = '' }) => {
60
+ // Use filtered resources when filtering is active and successful
61
+ const isFilteringActive = filterState?.enabled && filterResult?.success === true;
62
+ const baseProcessedResources = isFilteringActive ? filterResult?.processedResources : resources;
63
+ // Select resources for this grid based on the configuration
64
+ const selectedResourceIds = (0, react_1.useMemo)(() => {
65
+ if (!baseProcessedResources || !gridConfig.resourceSelection) {
66
+ return [];
67
+ }
68
+ const selectionResult = (0, resourceSelector_1.selectResources)(gridConfig.resourceSelection, baseProcessedResources);
69
+ if (selectionResult.isFailure()) {
70
+ onMessage?.('error', `Resource selection failed: ${selectionResult.message}`);
71
+ return [];
72
+ }
73
+ return selectionResult.value;
74
+ }, [baseProcessedResources, gridConfig.resourceSelection, onMessage]);
75
+ // Resolve all selected resources with current context
76
+ const resourceResolutions = (0, react_1.useMemo)(() => {
77
+ if (!resolutionState?.currentResolver || !selectedResourceIds.length) {
78
+ return new Map();
79
+ }
80
+ const resolutions = new Map();
81
+ const context = resolutionState.contextValues;
82
+ selectedResourceIds.forEach((resourceId) => {
83
+ try {
84
+ const resolver = resolutionState.currentResolver;
85
+ const resourceResult = resolver.resourceManager.getBuiltResource(resourceId);
86
+ if (resourceResult.isSuccess()) {
87
+ const resource = resourceResult.value;
88
+ // Resolve the resource with current context
89
+ const resolveResult = resolver.resolveComposedResourceValue(resourceId);
90
+ if (resolveResult.isSuccess()) {
91
+ resolutions.set(resourceId, {
92
+ success: true,
93
+ resourceId,
94
+ resource,
95
+ composedValue: resolveResult.value
96
+ // Note: For grid view, we mainly need the composed value
97
+ // Full candidate analysis is available but not needed for basic grid display
98
+ });
99
+ }
100
+ else {
101
+ resolutions.set(resourceId, {
102
+ success: false,
103
+ resourceId,
104
+ error: resolveResult.message
105
+ });
106
+ }
107
+ }
108
+ }
109
+ catch (error) {
110
+ resolutions.set(resourceId, {
111
+ success: false,
112
+ resourceId,
113
+ error: error instanceof Error ? error.message : 'Unknown resolution error'
114
+ });
115
+ }
116
+ });
117
+ return resolutions;
118
+ }, [selectedResourceIds, resolutionState?.currentResolver, resolutionState?.contextValues]);
119
+ // Handle context value changes using the shared pattern from ResolutionView
120
+ const handleQualifierChange = (0, react_1.useCallback)((qualifierName, value) => {
121
+ // Don't update context if this qualifier is host-managed
122
+ const qualifierOptions = contextOptions?.qualifierOptions?.[qualifierName];
123
+ const isHostManaged = qualifierOptions?.hostValue !== undefined;
124
+ if (!isHostManaged) {
125
+ resolutionActions?.updateContextValue(qualifierName, value);
126
+ }
127
+ }, [resolutionActions, contextOptions?.qualifierOptions]);
128
+ // Apply host-managed values when they change (same pattern as ResolutionView)
129
+ (0, react_1.useEffect)(() => {
130
+ if (!contextOptions?.hostManagedValues || !resolutionActions?.applyContext)
131
+ return;
132
+ resolutionActions.applyContext(contextOptions.hostManagedValues);
133
+ }, [contextOptions?.hostManagedValues, resolutionActions]);
134
+ // Determine which qualifiers to show
135
+ const visibleQualifiers = (0, react_1.useMemo)(() => {
136
+ if (!contextOptions?.qualifierOptions) {
137
+ return availableQualifiers;
138
+ }
139
+ return availableQualifiers.filter((qualifierName) => {
140
+ const options = contextOptions.qualifierOptions[qualifierName];
141
+ return options?.visible !== false;
142
+ });
143
+ }, [availableQualifiers, contextOptions?.qualifierOptions]);
144
+ // Get effective context values
145
+ const effectiveContextValues = (0, react_1.useMemo)(() => {
146
+ return resolutionState?.contextValues || {};
147
+ }, [resolutionState?.contextValues]);
148
+ if (!resources) {
149
+ return (react_1.default.createElement("div", { className: `p-6 ${className}` },
150
+ react_1.default.createElement("div", { className: "flex items-center space-x-3 mb-6" },
151
+ react_1.default.createElement(outline_1.TableCellsIcon, { className: "h-8 w-8 text-blue-600" }),
152
+ react_1.default.createElement("h2", { className: "text-2xl font-bold text-gray-900" }, gridConfig.title || 'Resource Grid')),
153
+ react_1.default.createElement("div", { className: "bg-white rounded-lg shadow-sm border border-gray-200 p-8 text-center" },
154
+ react_1.default.createElement("div", { className: "max-w-2xl mx-auto" },
155
+ react_1.default.createElement("h3", { className: "text-xl font-semibold text-gray-900 mb-4" }, "No Resources Loaded"),
156
+ react_1.default.createElement("p", { className: "text-gray-600 mb-6" }, "Import resources first to view them in a grid format with customizable columns."),
157
+ react_1.default.createElement("div", { className: "bg-blue-50 rounded-lg p-4" },
158
+ react_1.default.createElement("p", { className: "text-sm text-blue-800" },
159
+ react_1.default.createElement("strong", null, "Grid View:"),
160
+ " Display multiple resources in a table format. Configure columns to extract and edit specific properties from resolved resources."))))));
161
+ }
162
+ return (react_1.default.createElement("div", { className: `p-6 ${className}` },
163
+ react_1.default.createElement("div", { className: "flex items-center space-x-3 mb-6" },
164
+ react_1.default.createElement(outline_1.TableCellsIcon, { className: "h-8 w-8 text-blue-600" }),
165
+ react_1.default.createElement("h2", { className: "text-2xl font-bold text-gray-900" }, gridConfig.title || 'Resource Grid'),
166
+ isFilteringActive && (react_1.default.createElement("span", { className: "inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-purple-100 text-purple-800" }, "Filtered")),
167
+ react_1.default.createElement("span", { className: "inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-gray-100 text-gray-800" },
168
+ selectedResourceIds.length,
169
+ " resource",
170
+ selectedResourceIds.length !== 1 ? 's' : '')),
171
+ gridConfig.description && react_1.default.createElement("p", { className: "text-gray-600 mb-6" }, gridConfig.description),
172
+ react_1.default.createElement("div", { className: "bg-white rounded-lg shadow-sm border border-gray-200 p-6" },
173
+ showContextControls && contextOptions?.showContextControls !== false && (react_1.default.createElement("div", { className: "mb-6" },
174
+ react_1.default.createElement("h3", { className: "text-lg font-semibold text-gray-900 mb-4" }, contextOptions?.contextPanelTitle || 'Context Configuration'),
175
+ react_1.default.createElement("div", { className: `bg-gray-50 rounded-lg p-4 ${contextOptions?.contextPanelClassName || ''}` },
176
+ react_1.default.createElement("div", { className: "mb-4" },
177
+ react_1.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-3" }, visibleQualifiers.map((qualifierName) => {
178
+ const qualifierOptions = contextOptions?.qualifierOptions?.[qualifierName];
179
+ const hostManagedValue = contextOptions?.hostManagedValues?.[qualifierName];
180
+ const globalPlaceholder = typeof contextOptions?.globalPlaceholder === 'function'
181
+ ? contextOptions.globalPlaceholder(qualifierName)
182
+ : contextOptions?.globalPlaceholder;
183
+ const mergedOptions = {
184
+ ...qualifierOptions,
185
+ hostValue: hostManagedValue !== undefined ? hostManagedValue : qualifierOptions?.hostValue
186
+ };
187
+ return (react_1.default.createElement(QualifierContextControl_1.QualifierContextControl, { key: qualifierName, qualifierName: qualifierName, value: resolutionState?.pendingContextValues[qualifierName], onChange: handleQualifierChange, placeholder: globalPlaceholder || `Enter ${qualifierName} value`, resources: baseProcessedResources, options: mergedOptions }));
188
+ }))),
189
+ contextOptions?.showCurrentContext !== false && (react_1.default.createElement("div", { className: "flex items-center justify-between" },
190
+ react_1.default.createElement("div", { className: "text-sm text-gray-600" },
191
+ "Current:",
192
+ ' ',
193
+ Object.entries(effectiveContextValues)
194
+ .map(([key, value]) => `${key}=${value === undefined ? '(undefined)' : value}`)
195
+ .join(', ')),
196
+ contextOptions?.showContextActions !== false && (react_1.default.createElement("div", { className: "flex items-center space-x-2" },
197
+ react_1.default.createElement("button", { onClick: resolutionActions?.resetCache, className: "px-3 py-1 text-xs font-medium text-gray-600 bg-gray-100 rounded hover:bg-gray-200 focus:outline-none focus:ring-2 focus:ring-gray-500", title: "Clear resolution cache" }, "Clear Cache"),
198
+ react_1.default.createElement("button", { onClick: () => resolutionActions?.applyContext(), disabled: !resolutionState?.hasPendingChanges, className: `px-4 py-2 rounded-md text-sm font-medium ${resolutionState?.hasPendingChanges
199
+ ? 'bg-blue-600 text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500'
200
+ : 'bg-gray-300 text-gray-500 cursor-not-allowed'}` }, resolutionState?.hasPendingChanges
201
+ ? 'Apply Changes'
202
+ : resolutionState?.currentResolver
203
+ ? 'Context Applied'
204
+ : 'Apply Context')))))))),
205
+ react_1.default.createElement(ResourceGrid_1.ResourceGrid, { gridConfig: gridConfig, selectedResourceIds: selectedResourceIds, resourceResolutions: resourceResolutions, resolutionActions: resolutionActions, resolutionState: resolutionState, onMessage: onMessage }),
206
+ showChangeControls &&
207
+ (resolutionState?.hasUnsavedEdits || resolutionState?.hasPendingResourceChanges) && (react_1.default.createElement("div", { className: "mt-6" },
208
+ react_1.default.createElement(UnifiedChangeControls_1.UnifiedChangeControls, { editCount: resolutionState?.editedResources?.size || 0, addCount: resolutionState?.pendingResources?.size || 0, deleteCount: resolutionState?.pendingResourceDeletions?.size || 0, isApplying: resolutionState?.isApplyingEdits, disabled: !resolutionState?.currentResolver, onApplyAll: async () => {
209
+ await resolutionActions?.applyPendingResources();
210
+ }, onDiscardAll: () => {
211
+ resolutionActions?.discardEdits?.();
212
+ resolutionActions?.discardPendingResources?.();
213
+ } }))))));
214
+ };
215
+ exports.GridView = GridView;
216
+ exports.default = exports.GridView;
217
+ //# sourceMappingURL=index.js.map
@@ -6,6 +6,7 @@ const react_1 = tslib_1.__importStar(require("react"));
6
6
  const outline_1 = require("@heroicons/react/24/outline");
7
7
  const ts_res_1 = require("@fgv/ts-res");
8
8
  const zipLoader_1 = require("../../../utils/zipLoader");
9
+ const contexts_1 = require("../../../contexts");
9
10
  /**
10
11
  * ImportView component for importing resource files, directories, and bundles.
11
12
  *
@@ -53,7 +54,9 @@ const zipLoader_1 = require("../../../utils/zipLoader");
53
54
  *
54
55
  * @public
55
56
  */
56
- const ImportView = ({ onImport, onBundleImport, onZipImport, acceptedFileTypes = ['.json', '.zip'], onMessage, className = '' }) => {
57
+ const ImportView = ({ onImport, onBundleImport, onZipImport, acceptedFileTypes = ['.json', '.zip'], onMessage, className = '', importError }) => {
58
+ // Get observability context
59
+ const o11y = (0, contexts_1.useObservability)();
57
60
  const [isLoading, setIsLoading] = (0, react_1.useState)(false);
58
61
  const [importStatus, setImportStatus] = (0, react_1.useState)({
59
62
  hasImported: false,
@@ -69,7 +72,7 @@ const ImportView = ({ onImport, onBundleImport, onZipImport, acceptedFileTypes =
69
72
  const isFileSystemAccessSupported = 'showDirectoryPicker' in window || 'showOpenFilePicker' in window;
70
73
  // Helper function to process ZIP files using zip-archive packlet
71
74
  const processZipFile = (0, react_1.useCallback)(async (file) => {
72
- console.log(`[ImportView] Processing ZIP file: ${file.name}`);
75
+ o11y.diag.info(`[ImportView] Processing ZIP file: ${file.name}`);
73
76
  onMessage?.('info', `Processing ZIP file: ${file.name}`);
74
77
  const loader = new ts_res_1.ZipArchive.ZipArchiveLoader();
75
78
  const loadResult = await loader.loadFromFile(file, {
@@ -79,7 +82,7 @@ const ImportView = ({ onImport, onBundleImport, onZipImport, acceptedFileTypes =
79
82
  throw new Error(`Failed to load ZIP: ${loadResult.message}`);
80
83
  }
81
84
  const zipData = loadResult.value;
82
- console.log(`[ImportView] ZIP loaded successfully:`, zipData);
85
+ o11y.diag.info(`[ImportView] ZIP loaded successfully:`, zipData);
83
86
  // Pass the ZIP data to the appropriate handler
84
87
  if (onZipImport) {
85
88
  // Pass both the directory/files and any configuration found
@@ -111,7 +114,7 @@ const ImportView = ({ onImport, onBundleImport, onZipImport, acceptedFileTypes =
111
114
  const file = files[0];
112
115
  // Check if it's a ZIP file first
113
116
  if ((0, zipLoader_1.isZipFile)(file.name)) {
114
- console.log(`[ImportView] ✅ ${file.name} detected as ZIP file`);
117
+ o11y.diag.info(`[ImportView] ✅ ${file.name} detected as ZIP file`);
115
118
  const zipData = await processZipFile(file);
116
119
  setImportStatus({
117
120
  hasImported: true,
@@ -141,10 +144,10 @@ const ImportView = ({ onImport, onBundleImport, onZipImport, acceptedFileTypes =
141
144
  let isCurrentFileBundle = false;
142
145
  try {
143
146
  const parsedData = JSON.parse(content);
144
- console.log(`[ImportView] Checking if ${file.name} is a bundle...`);
147
+ o11y.diag.info(`[ImportView] Checking if ${file.name} is a bundle...`);
145
148
  // Use BundleUtils for proper bundle detection
146
149
  if (ts_res_1.Bundle.BundleUtils.isBundleFile(parsedData)) {
147
- console.log(`[ImportView] ✅ ${file.name} detected as bundle file`);
150
+ o11y.diag.info(`[ImportView] ✅ ${file.name} detected as bundle file`);
148
151
  bundleFile = { ...importedFile, bundle: parsedData };
149
152
  isCurrentFileBundle = true;
150
153
  }
@@ -153,11 +156,11 @@ const ImportView = ({ onImport, onBundleImport, onZipImport, acceptedFileTypes =
153
156
  console.warn(`[ImportView] ⚠️ File ${file.name} appears to be a bundle by name but content doesn't match bundle structure`);
154
157
  }
155
158
  else {
156
- console.log(`[ImportView] ❌ ${file.name} is not a bundle file`);
159
+ o11y.diag.info(`[ImportView] ❌ ${file.name} is not a bundle file`);
157
160
  }
158
161
  }
159
162
  catch (parseError) {
160
- console.log(`[ImportView] ❌ ${file.name} failed JSON parsing:`, parseError);
163
+ o11y.diag.info(`[ImportView] ❌ ${file.name} failed JSON parsing:`, parseError);
161
164
  // Not valid JSON or not a bundle, treat as regular file
162
165
  }
163
166
  // Only add to regular files if this specific file is not a bundle
@@ -167,7 +170,7 @@ const ImportView = ({ onImport, onBundleImport, onZipImport, acceptedFileTypes =
167
170
  }
168
171
  // Process results
169
172
  if (bundleFile) {
170
- console.log(`[ImportView] Processing bundle file: ${bundleFile.name}`, bundleFile.bundle);
173
+ o11y.diag.info(`[ImportView] Processing bundle file: ${bundleFile.name}`, bundleFile.bundle);
171
174
  setImportStatus({
172
175
  hasImported: true,
173
176
  fileCount: 1,
@@ -177,11 +180,11 @@ const ImportView = ({ onImport, onBundleImport, onZipImport, acceptedFileTypes =
177
180
  });
178
181
  onMessage?.('info', `Bundle file detected: ${bundleFile.name}`);
179
182
  if (onBundleImport && bundleFile.bundle) {
180
- console.log(`[ImportView] Calling onBundleImport with bundle data`);
183
+ o11y.diag.info(`[ImportView] Calling onBundleImport with bundle data`);
181
184
  onBundleImport(bundleFile.bundle);
182
185
  }
183
186
  else {
184
- console.warn(`[ImportView] No bundle import handler or bundle data missing`);
187
+ o11y.diag.warn(`[ImportView] No bundle import handler or bundle data missing`);
185
188
  }
186
189
  }
187
190
  else if (importedFiles.length > 0) {
@@ -350,7 +353,7 @@ const ImportView = ({ onImport, onBundleImport, onZipImport, acceptedFileTypes =
350
353
  if (fileHandles.length === 1) {
351
354
  const file = await fileHandles[0].getFile();
352
355
  if ((0, zipLoader_1.isZipFile)(file.name)) {
353
- console.log(`[ImportView] Modern API - ✅ ${file.name} detected as ZIP file`);
356
+ o11y.diag.info(`[ImportView] Modern API - ✅ ${file.name} detected as ZIP file`);
354
357
  const zipData = await processZipFile(file);
355
358
  setImportStatus({
356
359
  hasImported: true,
@@ -383,10 +386,10 @@ const ImportView = ({ onImport, onBundleImport, onZipImport, acceptedFileTypes =
383
386
  let isCurrentFileBundle = false;
384
387
  try {
385
388
  const parsedData = JSON.parse(content);
386
- console.log(`[ImportView] Modern API - Checking if ${file.name} is a bundle...`);
389
+ o11y.diag.info(`[ImportView] Modern API - Checking if ${file.name} is a bundle...`);
387
390
  // Use BundleUtils for proper bundle detection
388
391
  if (ts_res_1.Bundle.BundleUtils.isBundleFile(parsedData)) {
389
- console.log(`[ImportView] Modern API - ✅ ${file.name} detected as bundle file`);
392
+ o11y.diag.info(`[ImportView] Modern API - ✅ ${file.name} detected as bundle file`);
390
393
  bundleFile = { ...importedFile, bundle: parsedData };
391
394
  isCurrentFileBundle = true;
392
395
  }
@@ -394,11 +397,11 @@ const ImportView = ({ onImport, onBundleImport, onZipImport, acceptedFileTypes =
394
397
  console.warn(`[ImportView] Modern API - ⚠️ File ${file.name} appears to be a bundle by name but content doesn't match bundle structure`);
395
398
  }
396
399
  else {
397
- console.log(`[ImportView] Modern API - ❌ ${file.name} is not a bundle file`);
400
+ o11y.diag.info(`[ImportView] Modern API - ❌ ${file.name} is not a bundle file`);
398
401
  }
399
402
  }
400
403
  catch (parseError) {
401
- console.log(`[ImportView] Modern API - ❌ ${file.name} failed JSON parsing:`, parseError);
404
+ o11y.diag.info(`[ImportView] Modern API - ❌ ${file.name} failed JSON parsing:`, parseError);
402
405
  }
403
406
  // Only add to regular files if this specific file is not a bundle
404
407
  if (!isCurrentFileBundle) {
@@ -517,13 +520,13 @@ const ImportView = ({ onImport, onBundleImport, onZipImport, acceptedFileTypes =
517
520
  react_1.default.createElement(outline_1.ArchiveBoxIcon, { className: "w-5 h-5 text-purple-500" }),
518
521
  react_1.default.createElement("span", { className: "text-sm text-purple-900" }, "ZIP archive processed")))),
519
522
  importStatus.hasImported && (react_1.default.createElement("button", { onClick: handleReset, className: "mt-4 px-4 py-2 text-sm bg-gray-100 text-gray-700 rounded-lg hover:bg-gray-200 transition-colors" }, "Clear Import"))),
520
- error && (react_1.default.createElement("div", { className: "bg-white rounded-lg shadow-sm border border-red-200 p-6" },
523
+ (error || importError) && (react_1.default.createElement("div", { className: "bg-white rounded-lg shadow-sm border border-red-200 p-6" },
521
524
  react_1.default.createElement("div", { className: "flex items-start space-x-2" },
522
525
  react_1.default.createElement(outline_1.ExclamationTriangleIcon, { className: "w-5 h-5 text-red-600 mt-0.5" }),
523
526
  react_1.default.createElement("div", { className: "text-sm text-red-800" },
524
527
  react_1.default.createElement("p", { className: "font-medium" }, "Error"),
525
- react_1.default.createElement("p", null, error))))),
526
- importStatus.hasImported && !error && (react_1.default.createElement("div", { className: "bg-white rounded-lg shadow-sm border border-green-200 p-6" },
528
+ react_1.default.createElement("p", null, importError || error))))),
529
+ importStatus.hasImported && !error && !importError && (react_1.default.createElement("div", { className: "bg-white rounded-lg shadow-sm border border-green-200 p-6" },
527
530
  react_1.default.createElement("div", { className: "flex items-start space-x-2" },
528
531
  react_1.default.createElement(outline_1.CheckCircleIcon, { className: "w-5 h-5 text-green-600 mt-0.5" }),
529
532
  react_1.default.createElement("div", { className: "text-sm text-green-800" },
@@ -5,6 +5,7 @@ const tslib_1 = require("tslib");
5
5
  const react_1 = tslib_1.__importStar(require("react"));
6
6
  const outline_1 = require("@heroicons/react/24/outline");
7
7
  const solid_1 = require("@heroicons/react/24/solid");
8
+ const contexts_1 = require("../../../contexts");
8
9
  /**
9
10
  * MessagesWindow component for displaying and managing application messages.
10
11
  *
@@ -99,6 +100,8 @@ const solid_1 = require("@heroicons/react/24/solid");
99
100
  * @public
100
101
  */
101
102
  const MessagesWindow = ({ messages, onClearMessages, className = '' }) => {
103
+ // Get observability context
104
+ const o11y = (0, contexts_1.useObservability)();
102
105
  const [isCollapsed, setIsCollapsed] = (0, react_1.useState)(false);
103
106
  const [filter, setFilter] = (0, react_1.useState)('all');
104
107
  const [searchTerm, setSearchTerm] = (0, react_1.useState)('');
@@ -123,7 +126,7 @@ const MessagesWindow = ({ messages, onClearMessages, className = '' }) => {
123
126
  setTimeout(() => setCopySuccess(false), 2000);
124
127
  })
125
128
  .catch((err) => {
126
- console.error('Failed to copy messages:', err);
129
+ o11y.diag.error('Failed to copy messages:', err);
127
130
  });
128
131
  };
129
132
  if (messages.length === 0) {