@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
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
159
|
+
o11y.diag.info(`[ImportView] ❌ ${file.name} is not a bundle file`);
|
|
157
160
|
}
|
|
158
161
|
}
|
|
159
162
|
catch (parseError) {
|
|
160
|
-
|
|
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
|
-
|
|
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
|
-
|
|
183
|
+
o11y.diag.info(`[ImportView] Calling onBundleImport with bundle data`);
|
|
181
184
|
onBundleImport(bundleFile.bundle);
|
|
182
185
|
}
|
|
183
186
|
else {
|
|
184
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
400
|
+
o11y.diag.info(`[ImportView] Modern API - ❌ ${file.name} is not a bundle file`);
|
|
398
401
|
}
|
|
399
402
|
}
|
|
400
403
|
catch (parseError) {
|
|
401
|
-
|
|
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
|
-
|
|
129
|
+
o11y.diag.error('Failed to copy messages:', err);
|
|
127
130
|
});
|
|
128
131
|
};
|
|
129
132
|
if (messages.length === 0) {
|