@fgv/ts-res-ui-components 5.0.0-12 → 5.0.0-15
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/lib-commonjs/components/common/QualifierContextControl.js +83 -0
- package/lib-commonjs/components/common/ResourceListView.js +25 -0
- package/lib-commonjs/components/common/ResourceTreeView.js +167 -0
- package/lib-commonjs/components/forms/HierarchyEditor.js +111 -0
- package/lib-commonjs/components/forms/QualifierEditForm.js +211 -0
- package/lib-commonjs/components/forms/QualifierTypeEditForm.js +177 -0
- package/lib-commonjs/components/forms/ResourceTypeEditForm.js +193 -0
- package/lib-commonjs/components/forms/index.js +12 -0
- package/lib-commonjs/components/orchestrator/ResourceOrchestrator.js +322 -0
- package/lib-commonjs/components/views/CompiledView/index.js +637 -0
- package/lib-commonjs/components/views/ConfigurationView/index.js +370 -0
- package/lib-commonjs/components/views/FilterView/index.js +468 -0
- package/lib-commonjs/components/views/ImportView/index.js +519 -0
- package/lib-commonjs/components/views/ResolutionView/EditableJsonView.js +114 -0
- package/lib-commonjs/components/views/ResolutionView/ResolutionEditControls.js +87 -0
- package/lib-commonjs/components/views/ResolutionView/index.js +260 -0
- package/lib-commonjs/components/views/SourceView/index.js +321 -0
- package/lib-commonjs/components/views/ZipLoaderView/index.js +318 -0
- package/lib-commonjs/hooks/useConfigurationState.js +243 -0
- package/lib-commonjs/hooks/useFilterState.js +83 -0
- package/lib-commonjs/hooks/useResolutionState.js +257 -0
- package/lib-commonjs/hooks/useResourceData.js +475 -0
- package/lib-commonjs/hooks/useViewState.js +32 -0
- package/lib-commonjs/index.js +61 -0
- package/lib-commonjs/test/helpers/testDataLoader.js +180 -0
- package/lib-commonjs/types/index.js +3 -0
- package/lib-commonjs/utils/configurationUtils.js +370 -0
- package/lib-commonjs/utils/fileProcessing.js +148 -0
- package/lib-commonjs/utils/filterResources.js +160 -0
- package/lib-commonjs/utils/resolutionEditing.js +255 -0
- package/lib-commonjs/utils/resolutionUtils.js +223 -0
- package/lib-commonjs/utils/tsResIntegration.js +302 -0
- package/lib-commonjs/utils/zipLoader/browserZipLoader.js +254 -0
- package/lib-commonjs/utils/zipLoader/index.js +30 -0
- package/lib-commonjs/utils/zipLoader/nodeZipBuilder.js +105 -0
- package/lib-commonjs/utils/zipLoader/types.js +3 -0
- package/lib-commonjs/utils/zipLoader/zipUtils.js +243 -0
- package/package.json +15 -15
- package/.rush/temp/352205c76acd8e247a1680af51abc95e0524eb82.tar.log +0 -271
- package/.rush/temp/chunked-rush-logs/ts-res-ui-components.build.chunks.jsonl +0 -9
- package/.rush/temp/operation/build/all.log +0 -9
- package/.rush/temp/operation/build/log-chunks.jsonl +0 -9
- package/.rush/temp/operation/build/state.json +0 -3
- package/.rush/temp/shrinkwrap-deps.json +0 -1111
- package/REFACTORING_PLAN.md +0 -171
- package/config/jest.config.json +0 -16
- package/lib/components/common/QualifierContextControl.d.ts.map +0 -1
- package/lib/components/common/QualifierContextControl.js.map +0 -1
- package/lib/components/common/ResourceListView.d.ts.map +0 -1
- package/lib/components/common/ResourceListView.js.map +0 -1
- package/lib/components/common/ResourceTreeView.d.ts.map +0 -1
- package/lib/components/common/ResourceTreeView.js.map +0 -1
- package/lib/components/forms/HierarchyEditor.d.ts.map +0 -1
- package/lib/components/forms/HierarchyEditor.js.map +0 -1
- package/lib/components/forms/QualifierEditForm.d.ts.map +0 -1
- package/lib/components/forms/QualifierEditForm.js.map +0 -1
- package/lib/components/forms/QualifierTypeEditForm.d.ts.map +0 -1
- package/lib/components/forms/QualifierTypeEditForm.js.map +0 -1
- package/lib/components/forms/ResourceTypeEditForm.d.ts.map +0 -1
- package/lib/components/forms/ResourceTypeEditForm.js.map +0 -1
- package/lib/components/forms/index.d.ts.map +0 -1
- package/lib/components/forms/index.js.map +0 -1
- package/lib/components/orchestrator/ResourceOrchestrator.d.ts.map +0 -1
- package/lib/components/orchestrator/ResourceOrchestrator.js.map +0 -1
- package/lib/components/views/CompiledView/index.d.ts.map +0 -1
- package/lib/components/views/CompiledView/index.js.map +0 -1
- package/lib/components/views/ConfigurationView/index.d.ts.map +0 -1
- package/lib/components/views/ConfigurationView/index.js.map +0 -1
- package/lib/components/views/FilterView/index.d.ts.map +0 -1
- package/lib/components/views/FilterView/index.js.map +0 -1
- package/lib/components/views/ImportView/index.d.ts.map +0 -1
- package/lib/components/views/ImportView/index.js.map +0 -1
- package/lib/components/views/ResolutionView/EditableJsonView.d.ts.map +0 -1
- package/lib/components/views/ResolutionView/EditableJsonView.js.map +0 -1
- package/lib/components/views/ResolutionView/ResolutionEditControls.d.ts.map +0 -1
- package/lib/components/views/ResolutionView/ResolutionEditControls.js.map +0 -1
- package/lib/components/views/ResolutionView/index.d.ts.map +0 -1
- package/lib/components/views/ResolutionView/index.js.map +0 -1
- package/lib/components/views/SourceView/index.d.ts.map +0 -1
- package/lib/components/views/SourceView/index.js.map +0 -1
- package/lib/components/views/ZipLoaderView/index.d.ts.map +0 -1
- package/lib/components/views/ZipLoaderView/index.js.map +0 -1
- package/lib/hooks/useConfigurationState.d.ts.map +0 -1
- package/lib/hooks/useConfigurationState.js.map +0 -1
- package/lib/hooks/useFilterState.d.ts.map +0 -1
- package/lib/hooks/useFilterState.js.map +0 -1
- package/lib/hooks/useResolutionState.d.ts.map +0 -1
- package/lib/hooks/useResolutionState.js.map +0 -1
- package/lib/hooks/useResourceData.d.ts.map +0 -1
- package/lib/hooks/useResourceData.js.map +0 -1
- package/lib/hooks/useViewState.d.ts.map +0 -1
- package/lib/hooks/useViewState.js.map +0 -1
- package/lib/index.d.ts.map +0 -1
- package/lib/index.js.map +0 -1
- package/lib/test/helpers/testDataLoader.d.ts.map +0 -1
- package/lib/test/helpers/testDataLoader.js.map +0 -1
- package/lib/test/unit/utils/configurationUtils.test.d.ts.map +0 -1
- package/lib/test/unit/utils/configurationUtils.test.js +0 -497
- package/lib/test/unit/utils/configurationUtils.test.js.map +0 -1
- package/lib/test/unit/utils/fileProcessing.test.d.ts.map +0 -1
- package/lib/test/unit/utils/fileProcessing.test.js +0 -321
- package/lib/test/unit/utils/fileProcessing.test.js.map +0 -1
- package/lib/test/unit/utils/filterResources.test.d.ts.map +0 -1
- package/lib/test/unit/utils/filterResources.test.js +0 -403
- package/lib/test/unit/utils/filterResources.test.js.map +0 -1
- package/lib/test/unit/utils/resolutionEditing.test.d.ts.map +0 -1
- package/lib/test/unit/utils/resolutionEditing.test.js +0 -439
- package/lib/test/unit/utils/resolutionEditing.test.js.map +0 -1
- package/lib/test/unit/utils/resolutionUtils.test.d.ts.map +0 -1
- package/lib/test/unit/utils/resolutionUtils.test.js +0 -397
- package/lib/test/unit/utils/resolutionUtils.test.js.map +0 -1
- package/lib/test/unit/utils/tsResIntegration.test.d.ts.map +0 -1
- package/lib/test/unit/utils/tsResIntegration.test.js +0 -376
- package/lib/test/unit/utils/tsResIntegration.test.js.map +0 -1
- package/lib/types/index.d.ts.map +0 -1
- package/lib/types/index.js.map +0 -1
- package/lib/utils/configurationUtils.d.ts.map +0 -1
- package/lib/utils/configurationUtils.js.map +0 -1
- package/lib/utils/fileProcessing.d.ts.map +0 -1
- package/lib/utils/fileProcessing.js.map +0 -1
- package/lib/utils/filterResources.d.ts.map +0 -1
- package/lib/utils/filterResources.js.map +0 -1
- package/lib/utils/resolutionEditing.d.ts.map +0 -1
- package/lib/utils/resolutionEditing.js.map +0 -1
- package/lib/utils/resolutionUtils.d.ts.map +0 -1
- package/lib/utils/resolutionUtils.js.map +0 -1
- package/lib/utils/tsResIntegration.d.ts.map +0 -1
- package/lib/utils/tsResIntegration.js.map +0 -1
- package/lib/utils/zipLoader/browserZipLoader.d.ts.map +0 -1
- package/lib/utils/zipLoader/browserZipLoader.js.map +0 -1
- package/lib/utils/zipLoader/index.d.ts.map +0 -1
- package/lib/utils/zipLoader/index.js.map +0 -1
- package/lib/utils/zipLoader/nodeZipBuilder.d.ts.map +0 -1
- package/lib/utils/zipLoader/nodeZipBuilder.js.map +0 -1
- package/lib/utils/zipLoader/types.d.ts.map +0 -1
- package/lib/utils/zipLoader/types.js.map +0 -1
- package/lib/utils/zipLoader/zipUtils.d.ts.map +0 -1
- package/lib/utils/zipLoader/zipUtils.js.map +0 -1
- package/rush-logs/ts-res-ui-components.build.cache.log +0 -3
- package/rush-logs/ts-res-ui-components.build.log +0 -9
- package/src/test/helpers/testDataLoader.ts +0 -195
- package/src/test/unit/utils/configurationUtils.test.ts +0 -630
- package/src/test/unit/utils/fileProcessing.test.ts +0 -391
- package/src/test/unit/utils/filterResources.test.ts +0 -574
- package/src/test/unit/utils/resolutionEditing.test.ts +0 -556
- package/src/test/unit/utils/resolutionUtils.test.ts +0 -521
- package/src/test/unit/utils/tsResIntegration.test.ts +0 -433
- package/temp/build/typescript/ts_gZid87Hu.json +0 -1
- package/tsconfig.json +0 -15
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.QualifierContextControl = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const react_1 = tslib_1.__importStar(require("react"));
|
|
6
|
+
const QualifierContextControl = ({ qualifierName, value, onChange, disabled = false, placeholder, resources, className = '' }) => {
|
|
7
|
+
// Extract qualifier type information from system configuration
|
|
8
|
+
const qualifierInfo = (0, react_1.useMemo)(() => {
|
|
9
|
+
if (!resources?.system?.qualifiers) {
|
|
10
|
+
return { hasEnumeratedValues: false, enumeratedValues: [] };
|
|
11
|
+
}
|
|
12
|
+
try {
|
|
13
|
+
// Get qualifier declaration
|
|
14
|
+
const qualifierResult = resources.system.qualifiers.validating.get(qualifierName);
|
|
15
|
+
if (!qualifierResult.isSuccess()) {
|
|
16
|
+
return { hasEnumeratedValues: false, enumeratedValues: [] };
|
|
17
|
+
}
|
|
18
|
+
const qualifier = qualifierResult.value;
|
|
19
|
+
// Access the instantiated qualifier type
|
|
20
|
+
if (qualifier.type) {
|
|
21
|
+
const qualifierType = qualifier.type;
|
|
22
|
+
// Use type assertion to access properties that may exist on specific subtypes
|
|
23
|
+
const qtAny = qualifierType;
|
|
24
|
+
const config = (qtAny.configuration || {});
|
|
25
|
+
// Look for enumerated values in different possible locations
|
|
26
|
+
const enumeratedValues = config.enumeratedValues ||
|
|
27
|
+
config.allowedTerritories ||
|
|
28
|
+
qtAny.enumeratedValues ||
|
|
29
|
+
qtAny.allowedTerritories ||
|
|
30
|
+
[];
|
|
31
|
+
if (enumeratedValues && Array.isArray(enumeratedValues) && enumeratedValues.length > 0) {
|
|
32
|
+
return {
|
|
33
|
+
hasEnumeratedValues: true,
|
|
34
|
+
enumeratedValues: enumeratedValues,
|
|
35
|
+
systemType: qtAny.systemType || 'literal',
|
|
36
|
+
caseSensitive: config.caseSensitive !== false
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return { hasEnumeratedValues: false, enumeratedValues: [] };
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
console.warn(`Failed to extract qualifier type info for ${qualifierName}:`, error);
|
|
44
|
+
return { hasEnumeratedValues: false, enumeratedValues: [] };
|
|
45
|
+
}
|
|
46
|
+
}, [qualifierName, resources?.system?.qualifiers]);
|
|
47
|
+
const handleChange = (newValue) => {
|
|
48
|
+
onChange(qualifierName, newValue || undefined);
|
|
49
|
+
};
|
|
50
|
+
const handleClear = () => {
|
|
51
|
+
onChange(qualifierName, undefined);
|
|
52
|
+
};
|
|
53
|
+
const effectiveValue = value ?? '';
|
|
54
|
+
const hasEnumeratedValues = qualifierInfo.hasEnumeratedValues && qualifierInfo.enumeratedValues.length > 0;
|
|
55
|
+
return (react_1.default.createElement("div", { className: `bg-white rounded border border-gray-200 p-2 ${className}` },
|
|
56
|
+
react_1.default.createElement("div", { className: "flex items-center gap-2" },
|
|
57
|
+
react_1.default.createElement("label", { className: "text-sm font-medium text-gray-700 min-w-0 flex-shrink-0" },
|
|
58
|
+
qualifierName,
|
|
59
|
+
":"),
|
|
60
|
+
react_1.default.createElement("div", { className: "flex-1 flex items-center gap-1" },
|
|
61
|
+
hasEnumeratedValues ? (
|
|
62
|
+
// Dropdown for enumerated values
|
|
63
|
+
react_1.default.createElement("select", { value: effectiveValue, onChange: (e) => handleChange(e.target.value), disabled: disabled, className: `flex-1 px-2 py-1 border border-gray-300 rounded focus:outline-none focus:ring-1 focus:ring-blue-500 focus:border-transparent text-sm min-w-0 ${disabled ? 'bg-gray-100 text-gray-400' : ''}` },
|
|
64
|
+
react_1.default.createElement("option", { value: "" }, disabled
|
|
65
|
+
? 'Disabled'
|
|
66
|
+
: value === undefined
|
|
67
|
+
? '(undefined)'
|
|
68
|
+
: placeholder || 'Select value...'),
|
|
69
|
+
qualifierInfo.enumeratedValues.map((enumValue) => (react_1.default.createElement("option", { key: enumValue, value: enumValue }, enumValue))))) : (
|
|
70
|
+
// Text input for non-enumerated values
|
|
71
|
+
react_1.default.createElement("input", { type: "text", value: effectiveValue, onChange: (e) => handleChange(e.target.value), disabled: disabled, className: `flex-1 px-2 py-1 border border-gray-300 rounded focus:outline-none focus:ring-1 focus:ring-blue-500 focus:border-transparent text-sm min-w-0 ${disabled ? 'bg-gray-100 text-gray-400' : ''}`, placeholder: disabled
|
|
72
|
+
? 'Disabled'
|
|
73
|
+
: value === undefined
|
|
74
|
+
? '(undefined)'
|
|
75
|
+
: placeholder || `Enter ${qualifierName} value` })),
|
|
76
|
+
!disabled && value !== undefined && (react_1.default.createElement("button", { type: "button", onClick: handleClear, className: "px-2 py-1 text-xs text-gray-500 hover:text-gray-700 hover:bg-gray-100 rounded transition-colors", title: "Set to undefined" }, "\u2715")))),
|
|
77
|
+
hasEnumeratedValues && (react_1.default.createElement("div", { className: "mt-1 text-xs text-blue-600" },
|
|
78
|
+
qualifierInfo.enumeratedValues.length,
|
|
79
|
+
" predefined values"))));
|
|
80
|
+
};
|
|
81
|
+
exports.QualifierContextControl = QualifierContextControl;
|
|
82
|
+
exports.default = exports.QualifierContextControl;
|
|
83
|
+
//# sourceMappingURL=QualifierContextControl.js.map
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ResourceListView = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const react_1 = tslib_1.__importDefault(require("react"));
|
|
6
|
+
const outline_1 = require("@heroicons/react/24/outline");
|
|
7
|
+
const ResourceListView = ({ resourceIds, selectedResourceId, onResourceSelect, searchTerm = '', className = '' }) => {
|
|
8
|
+
// Filter and sort resource IDs
|
|
9
|
+
const filteredResourceIds = react_1.default.useMemo(() => {
|
|
10
|
+
const filtered = searchTerm
|
|
11
|
+
? resourceIds.filter((id) => id.toLowerCase().includes(searchTerm.toLowerCase()))
|
|
12
|
+
: resourceIds;
|
|
13
|
+
return filtered.sort();
|
|
14
|
+
}, [resourceIds, searchTerm]);
|
|
15
|
+
if (filteredResourceIds.length === 0) {
|
|
16
|
+
return (react_1.default.createElement("div", { className: `${className} p-4 text-center text-gray-500` },
|
|
17
|
+
react_1.default.createElement("p", null, searchTerm ? 'No resources match your search' : 'No resources available')));
|
|
18
|
+
}
|
|
19
|
+
return (react_1.default.createElement("div", { className: `${className} overflow-y-auto` }, filteredResourceIds.map((resourceId) => (react_1.default.createElement("div", { key: resourceId, className: `flex items-center px-3 py-2 cursor-pointer hover:bg-gray-100 border-b border-gray-100 last:border-b-0 ${selectedResourceId === resourceId ? 'bg-purple-50 border-l-2 border-purple-500' : ''} ${searchTerm && resourceId.toLowerCase().includes(searchTerm.toLowerCase()) ? 'bg-yellow-50' : ''}`, onClick: () => onResourceSelect(resourceId) },
|
|
20
|
+
react_1.default.createElement(outline_1.DocumentTextIcon, { className: "w-4 h-4 text-green-500 mr-2 flex-shrink-0" }),
|
|
21
|
+
react_1.default.createElement("span", { className: `text-sm truncate ${selectedResourceId === resourceId ? 'font-medium text-purple-900' : 'text-gray-700'}`, title: resourceId }, resourceId))))));
|
|
22
|
+
};
|
|
23
|
+
exports.ResourceListView = ResourceListView;
|
|
24
|
+
exports.default = exports.ResourceListView;
|
|
25
|
+
//# sourceMappingURL=ResourceListView.js.map
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ResourceTreeView = 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 ResourceTreeView = ({ resources, selectedResourceId, onResourceSelect, searchTerm = '', className = '' }) => {
|
|
8
|
+
const [expandedNodes, setExpandedNodes] = (0, react_1.useState)(new Set());
|
|
9
|
+
// Build the tree structure from resources
|
|
10
|
+
const treeData = (0, react_1.useMemo)(() => {
|
|
11
|
+
if (!resources)
|
|
12
|
+
return null;
|
|
13
|
+
// Get the tree from the resources
|
|
14
|
+
const treeResult = resources.getBuiltResourceTree();
|
|
15
|
+
if (treeResult.isFailure()) {
|
|
16
|
+
console.error('Failed to build resource tree:', treeResult.message);
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
return treeResult.value;
|
|
20
|
+
}, [resources]);
|
|
21
|
+
// Filter tree based on search term
|
|
22
|
+
const filteredTree = (0, react_1.useMemo)(() => {
|
|
23
|
+
if (!treeData || !searchTerm)
|
|
24
|
+
return treeData;
|
|
25
|
+
// Helper function to check if a node or its descendants match the search
|
|
26
|
+
const markMatchingNodes = (node, searchLower) => {
|
|
27
|
+
const nodeIdLower = node.id.toLowerCase();
|
|
28
|
+
let matches = nodeIdLower.includes(searchLower);
|
|
29
|
+
if (!node.isLeaf && node.children) {
|
|
30
|
+
// Check children recursively
|
|
31
|
+
for (const child of node.children.values()) {
|
|
32
|
+
if (markMatchingNodes(child, searchLower)) {
|
|
33
|
+
matches = true;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return matches;
|
|
38
|
+
};
|
|
39
|
+
// Mark all matching nodes
|
|
40
|
+
const searchLower = searchTerm.toLowerCase();
|
|
41
|
+
for (const child of treeData.children.values()) {
|
|
42
|
+
markMatchingNodes(child, searchLower);
|
|
43
|
+
}
|
|
44
|
+
return treeData;
|
|
45
|
+
}, [treeData, searchTerm]);
|
|
46
|
+
// Toggle node expansion
|
|
47
|
+
const toggleNode = (0, react_1.useCallback)((nodeId) => {
|
|
48
|
+
setExpandedNodes((prev) => {
|
|
49
|
+
const newExpanded = new Set(prev);
|
|
50
|
+
if (newExpanded.has(nodeId)) {
|
|
51
|
+
newExpanded.delete(nodeId);
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
newExpanded.add(nodeId);
|
|
55
|
+
}
|
|
56
|
+
return newExpanded;
|
|
57
|
+
});
|
|
58
|
+
}, []);
|
|
59
|
+
// Expand all nodes that contain search matches
|
|
60
|
+
const expandMatchingNodes = (0, react_1.useCallback)(() => {
|
|
61
|
+
if (!searchTerm || !filteredTree)
|
|
62
|
+
return;
|
|
63
|
+
const searchLower = searchTerm.toLowerCase();
|
|
64
|
+
const nodesToExpand = new Set();
|
|
65
|
+
const checkNode = (node) => {
|
|
66
|
+
if (node.id.toLowerCase().includes(searchLower)) {
|
|
67
|
+
// Expand all parent nodes
|
|
68
|
+
const parts = node.id.split('.');
|
|
69
|
+
for (let i = 1; i < parts.length; i++) {
|
|
70
|
+
nodesToExpand.add(parts.slice(0, i).join('.'));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (!node.isLeaf && node.children) {
|
|
74
|
+
for (const child of node.children.values()) {
|
|
75
|
+
checkNode(child);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
for (const child of filteredTree.children.values()) {
|
|
80
|
+
checkNode(child);
|
|
81
|
+
}
|
|
82
|
+
setExpandedNodes(nodesToExpand);
|
|
83
|
+
}, [searchTerm, filteredTree]);
|
|
84
|
+
// Auto-expand when search term changes
|
|
85
|
+
react_1.default.useEffect(() => {
|
|
86
|
+
if (searchTerm) {
|
|
87
|
+
expandMatchingNodes();
|
|
88
|
+
}
|
|
89
|
+
}, [searchTerm, expandMatchingNodes]);
|
|
90
|
+
// Render a single tree node
|
|
91
|
+
const renderTreeNode = (node, level = 0) => {
|
|
92
|
+
const isExpanded = expandedNodes.has(node.id);
|
|
93
|
+
const isSelected = selectedResourceId === node.id;
|
|
94
|
+
const nodeIdLower = node.id.toLowerCase();
|
|
95
|
+
const searchLower = searchTerm.toLowerCase();
|
|
96
|
+
const matchesSearch = !searchTerm || nodeIdLower.includes(searchLower);
|
|
97
|
+
// Check if any children match
|
|
98
|
+
let hasMatchingChildren = false;
|
|
99
|
+
if (!node.isLeaf && node.children && searchTerm) {
|
|
100
|
+
const checkChildren = (n) => {
|
|
101
|
+
if (n.id.toLowerCase().includes(searchLower))
|
|
102
|
+
return true;
|
|
103
|
+
if (!n.isLeaf && n.children) {
|
|
104
|
+
for (const child of n.children.values()) {
|
|
105
|
+
if (checkChildren(child))
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return false;
|
|
110
|
+
};
|
|
111
|
+
for (const child of node.children.values()) {
|
|
112
|
+
if (checkChildren(child)) {
|
|
113
|
+
hasMatchingChildren = true;
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// Hide nodes that don't match search and don't have matching children
|
|
119
|
+
if (searchTerm && !matchesSearch && !hasMatchingChildren) {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
return (react_1.default.createElement("div", { key: node.id },
|
|
123
|
+
react_1.default.createElement("div", { className: `flex items-center px-2 py-1 cursor-pointer hover:bg-gray-100 ${isSelected ? 'bg-purple-50 border-l-2 border-purple-500' : ''} ${matchesSearch && searchTerm ? 'bg-yellow-50' : ''}`, style: { paddingLeft: `${level * 20 + 8}px` }, onClick: () => {
|
|
124
|
+
if (node.isLeaf) {
|
|
125
|
+
onResourceSelect(node.id);
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
toggleNode(node.id);
|
|
129
|
+
}
|
|
130
|
+
} },
|
|
131
|
+
!node.isLeaf && (react_1.default.createElement("button", { onClick: (e) => {
|
|
132
|
+
e.stopPropagation();
|
|
133
|
+
toggleNode(node.id);
|
|
134
|
+
}, className: "mr-1 p-0.5 hover:bg-gray-200 rounded" }, isExpanded ? (react_1.default.createElement(outline_1.ChevronDownIcon, { className: "w-3 h-3 text-gray-600" })) : (react_1.default.createElement(outline_1.ChevronRightIcon, { className: "w-3 h-3 text-gray-600" })))),
|
|
135
|
+
node.isLeaf ? (react_1.default.createElement(outline_1.DocumentTextIcon, { className: "w-4 h-4 text-green-500 mr-2 flex-shrink-0" })) : isExpanded ? (react_1.default.createElement(outline_1.FolderOpenIcon, { className: "w-4 h-4 text-blue-500 mr-2 flex-shrink-0" })) : (react_1.default.createElement(outline_1.FolderIcon, { className: "w-4 h-4 text-blue-500 mr-2 flex-shrink-0" })),
|
|
136
|
+
react_1.default.createElement("span", { className: `text-sm truncate ${isSelected ? 'font-medium text-purple-900' : 'text-gray-700'} ${matchesSearch && searchTerm ? 'font-medium' : ''}`, title: node.id }, node.name),
|
|
137
|
+
!node.isLeaf && node.children && (react_1.default.createElement("span", { className: "ml-2 text-xs text-gray-500" },
|
|
138
|
+
"(",
|
|
139
|
+
node.children.size,
|
|
140
|
+
")"))),
|
|
141
|
+
!node.isLeaf && node.children && isExpanded && (react_1.default.createElement("div", null, Array.from(node.children.values())
|
|
142
|
+
.sort((a, b) => {
|
|
143
|
+
// Sort folders first, then by name
|
|
144
|
+
if (a.isLeaf !== b.isLeaf) {
|
|
145
|
+
return a.isLeaf ? 1 : -1;
|
|
146
|
+
}
|
|
147
|
+
return a.name.localeCompare(b.name);
|
|
148
|
+
})
|
|
149
|
+
.map((child) => renderTreeNode(child, level + 1))))));
|
|
150
|
+
};
|
|
151
|
+
if (!filteredTree) {
|
|
152
|
+
return (react_1.default.createElement("div", { className: `${className} p-4 text-center text-gray-500` },
|
|
153
|
+
react_1.default.createElement("p", null, "No resources available")));
|
|
154
|
+
}
|
|
155
|
+
return (react_1.default.createElement("div", { className: `${className} overflow-y-auto` }, Array.from(filteredTree.children.values())
|
|
156
|
+
.sort((a, b) => {
|
|
157
|
+
// Sort folders first, then by name
|
|
158
|
+
if (a.isLeaf !== b.isLeaf) {
|
|
159
|
+
return a.isLeaf ? 1 : -1;
|
|
160
|
+
}
|
|
161
|
+
return a.name.localeCompare(b.name);
|
|
162
|
+
})
|
|
163
|
+
.map((child) => renderTreeNode(child))));
|
|
164
|
+
};
|
|
165
|
+
exports.ResourceTreeView = ResourceTreeView;
|
|
166
|
+
exports.default = exports.ResourceTreeView;
|
|
167
|
+
//# sourceMappingURL=ResourceTreeView.js.map
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HierarchyEditor = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const react_1 = tslib_1.__importStar(require("react"));
|
|
6
|
+
const HierarchyEditor = ({ hierarchy, onChange, availableValues, className = '' }) => {
|
|
7
|
+
const [newChild, setNewChild] = (0, react_1.useState)('');
|
|
8
|
+
const [newParent, setNewParent] = (0, react_1.useState)('');
|
|
9
|
+
// Ensure hierarchy is a valid object with string values
|
|
10
|
+
const safeHierarchy = react_1.default.useMemo(() => {
|
|
11
|
+
if (!hierarchy || typeof hierarchy !== 'object') {
|
|
12
|
+
return {};
|
|
13
|
+
}
|
|
14
|
+
// Filter out any non-string values
|
|
15
|
+
const safe = {};
|
|
16
|
+
for (const [key, value] of Object.entries(hierarchy)) {
|
|
17
|
+
if (typeof value === 'string') {
|
|
18
|
+
safe[key] = value;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return safe;
|
|
22
|
+
}, [hierarchy]);
|
|
23
|
+
const handleAddRelationship = () => {
|
|
24
|
+
if (newChild && newParent && newChild !== newParent) {
|
|
25
|
+
const updatedHierarchy = { ...safeHierarchy, [newChild]: newParent };
|
|
26
|
+
onChange(updatedHierarchy);
|
|
27
|
+
setNewChild('');
|
|
28
|
+
setNewParent('');
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
const handleRemoveRelationship = (child) => {
|
|
32
|
+
const updatedHierarchy = { ...safeHierarchy };
|
|
33
|
+
delete updatedHierarchy[child];
|
|
34
|
+
onChange(updatedHierarchy);
|
|
35
|
+
};
|
|
36
|
+
const getHierarchyTree = () => {
|
|
37
|
+
const roots = new Set(availableValues);
|
|
38
|
+
const children = new Set(Object.keys(safeHierarchy));
|
|
39
|
+
const parents = new Set(Object.values(safeHierarchy));
|
|
40
|
+
// Remove children from roots (they have parents)
|
|
41
|
+
children.forEach((child) => roots.delete(child));
|
|
42
|
+
// Add parents that aren't in available values (for display purposes)
|
|
43
|
+
parents.forEach((parent) => {
|
|
44
|
+
if (!availableValues.includes(parent)) {
|
|
45
|
+
roots.add(parent);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
const buildTree = (value, level = 0) => {
|
|
49
|
+
const childrenOfValue = Object.entries(safeHierarchy).filter(([, parent]) => parent === value);
|
|
50
|
+
return {
|
|
51
|
+
value,
|
|
52
|
+
level,
|
|
53
|
+
children: childrenOfValue.map(([child]) => buildTree(child, level + 1))
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
return Array.from(roots).map((root) => buildTree(root));
|
|
57
|
+
};
|
|
58
|
+
const renderTree = (nodes) => {
|
|
59
|
+
return nodes.map((node) => {
|
|
60
|
+
const parentValue = safeHierarchy[node.value];
|
|
61
|
+
return (react_1.default.createElement("div", { key: node.value, className: "ml-4" },
|
|
62
|
+
react_1.default.createElement("div", { className: "flex items-center space-x-2 py-1" },
|
|
63
|
+
react_1.default.createElement("span", { className: "text-sm text-gray-700", style: { marginLeft: `${node.level * 20}px` } },
|
|
64
|
+
node.level > 0 && '└─ ',
|
|
65
|
+
node.value),
|
|
66
|
+
parentValue && react_1.default.createElement("span", { className: "text-xs text-gray-500" },
|
|
67
|
+
"\u2192 ",
|
|
68
|
+
parentValue)),
|
|
69
|
+
node.children.length > 0 && renderTree(node.children)));
|
|
70
|
+
});
|
|
71
|
+
};
|
|
72
|
+
return (react_1.default.createElement("div", { className: className },
|
|
73
|
+
react_1.default.createElement("label", { className: "block text-sm font-medium text-gray-700 mb-2" }, "Value Hierarchy"),
|
|
74
|
+
react_1.default.createElement("div", { className: "border border-gray-300 rounded-md p-3 bg-white" },
|
|
75
|
+
react_1.default.createElement("div", { className: "mb-4 p-3 bg-gray-50 rounded border" },
|
|
76
|
+
react_1.default.createElement("div", { className: "text-sm font-medium text-gray-700 mb-2" }, "Add Parent-Child Relationship"),
|
|
77
|
+
react_1.default.createElement("div", { className: "grid grid-cols-3 gap-2 items-end" },
|
|
78
|
+
react_1.default.createElement("div", null,
|
|
79
|
+
react_1.default.createElement("label", { className: "block text-xs text-gray-600" }, "Child Value"),
|
|
80
|
+
availableValues.length > 0 ? (react_1.default.createElement("select", { value: newChild, onChange: (e) => setNewChild(e.target.value), className: "w-full text-sm rounded border-gray-300 focus:border-blue-500 focus:ring-blue-500" },
|
|
81
|
+
react_1.default.createElement("option", { value: "" }, "Select child..."),
|
|
82
|
+
availableValues.map((value) => (react_1.default.createElement("option", { key: value, value: value }, value))))) : (react_1.default.createElement("input", { type: "text", value: newChild, onChange: (e) => setNewChild(e.target.value), placeholder: "Enter child value", className: "w-full text-sm rounded border-gray-300 focus:border-blue-500 focus:ring-blue-500" }))),
|
|
83
|
+
react_1.default.createElement("div", null,
|
|
84
|
+
react_1.default.createElement("label", { className: "block text-xs text-gray-600" }, "Parent Value"),
|
|
85
|
+
react_1.default.createElement("input", { type: "text", value: newParent, onChange: (e) => setNewParent(e.target.value), placeholder: "Enter parent value", className: "w-full text-sm rounded border-gray-300 focus:border-blue-500 focus:ring-blue-500" })),
|
|
86
|
+
react_1.default.createElement("div", null,
|
|
87
|
+
react_1.default.createElement("button", { onClick: handleAddRelationship, disabled: !newChild || !newParent || newChild === newParent, className: "w-full px-3 py-1 text-sm bg-blue-600 text-white rounded hover:bg-blue-700 disabled:bg-gray-300 disabled:cursor-not-allowed" }, "Add"))),
|
|
88
|
+
react_1.default.createElement("div", { className: "text-xs text-gray-500 mt-1" }, availableValues.length > 0
|
|
89
|
+
? "Define which values are children of other values. The parent doesn't need to be in the enumerated values list."
|
|
90
|
+
: 'Define which values are children of other values. Enter any valid values for this qualifier type.')),
|
|
91
|
+
Object.keys(safeHierarchy).length > 0 && (react_1.default.createElement("div", { className: "mb-4" },
|
|
92
|
+
react_1.default.createElement("div", { className: "text-sm font-medium text-gray-700 mb-2" },
|
|
93
|
+
"Current Relationships (",
|
|
94
|
+
Object.keys(safeHierarchy).length,
|
|
95
|
+
")"),
|
|
96
|
+
react_1.default.createElement("div", { className: "max-h-24 overflow-y-auto border border-gray-200 rounded bg-white p-2" },
|
|
97
|
+
react_1.default.createElement("div", { className: "space-y-1" }, Object.entries(safeHierarchy).map(([child, parent]) => (react_1.default.createElement("div", { key: child, className: "flex items-center justify-between bg-gray-50 px-2 py-1 rounded" },
|
|
98
|
+
react_1.default.createElement("span", { className: "text-sm" },
|
|
99
|
+
react_1.default.createElement("span", { className: "font-medium" }, child),
|
|
100
|
+
" \u2192",
|
|
101
|
+
' ',
|
|
102
|
+
react_1.default.createElement("span", { className: "text-gray-600" }, parent)),
|
|
103
|
+
react_1.default.createElement("button", { onClick: () => handleRemoveRelationship(child), className: "text-red-600 hover:text-red-800 text-xs ml-2 flex-shrink-0" }, "Remove")))))))),
|
|
104
|
+
(availableValues.length > 0 || Object.keys(safeHierarchy).length > 0) && (react_1.default.createElement("div", null,
|
|
105
|
+
react_1.default.createElement("div", { className: "text-sm font-medium text-gray-700 mb-2" }, "Hierarchy Tree"),
|
|
106
|
+
react_1.default.createElement("div", { className: "bg-gray-50 border rounded max-h-32 overflow-y-auto" },
|
|
107
|
+
react_1.default.createElement("div", { className: "p-2 text-sm font-mono" }, getHierarchyTree().length > 0 ? (renderTree(getHierarchyTree())) : (react_1.default.createElement("div", { className: "text-gray-500 text-center py-2" }, "No hierarchy defined. Add relationships above to see the tree structure.")))))))));
|
|
108
|
+
};
|
|
109
|
+
exports.HierarchyEditor = HierarchyEditor;
|
|
110
|
+
exports.default = exports.HierarchyEditor;
|
|
111
|
+
//# sourceMappingURL=HierarchyEditor.js.map
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.QualifierEditForm = 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 ts_utils_1 = require("@fgv/ts-utils");
|
|
8
|
+
const QualifierEditForm = ({ qualifier, qualifierTypes, onSave, onCancel, existingNames = [] }) => {
|
|
9
|
+
const [formData, setFormData] = (0, react_1.useState)(() => {
|
|
10
|
+
if (qualifier) {
|
|
11
|
+
return {
|
|
12
|
+
name: qualifier.name,
|
|
13
|
+
typeName: qualifier.typeName,
|
|
14
|
+
defaultPriority: qualifier.defaultPriority,
|
|
15
|
+
token: qualifier.token || '',
|
|
16
|
+
tokenIsOptional: qualifier.tokenIsOptional || false,
|
|
17
|
+
defaultValue: qualifier.defaultValue || ''
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
name: '',
|
|
22
|
+
typeName: qualifierTypes[0]?.name || '',
|
|
23
|
+
defaultPriority: 50,
|
|
24
|
+
token: '',
|
|
25
|
+
tokenIsOptional: false,
|
|
26
|
+
defaultValue: ''
|
|
27
|
+
};
|
|
28
|
+
});
|
|
29
|
+
const [errors, setErrors] = (0, react_1.useState)({});
|
|
30
|
+
// Get the selected qualifier type for context
|
|
31
|
+
const selectedQualifierType = qualifierTypes.find((qt) => qt.name === formData.typeName);
|
|
32
|
+
// Type-safe extraction of allowContextList property
|
|
33
|
+
const allowsContextList = (() => {
|
|
34
|
+
if (!selectedQualifierType?.configuration)
|
|
35
|
+
return false;
|
|
36
|
+
const result = ts_utils_1.Converters.boolean.convert(selectedQualifierType.configuration.allowContextList);
|
|
37
|
+
return result.isSuccess() ? result.value : false;
|
|
38
|
+
})();
|
|
39
|
+
// Validation
|
|
40
|
+
const validateForm = (0, react_1.useCallback)(() => {
|
|
41
|
+
const newErrors = {};
|
|
42
|
+
if (!formData.name.trim()) {
|
|
43
|
+
newErrors.name = 'Name is required';
|
|
44
|
+
}
|
|
45
|
+
else if (existingNames.includes(formData.name) && formData.name !== qualifier?.name) {
|
|
46
|
+
newErrors.name = 'Name must be unique';
|
|
47
|
+
}
|
|
48
|
+
if (!formData.typeName) {
|
|
49
|
+
newErrors.typeName = 'Qualifier type is required';
|
|
50
|
+
}
|
|
51
|
+
if (formData.defaultPriority < 0 || formData.defaultPriority > 1000) {
|
|
52
|
+
newErrors.defaultPriority = 'Priority must be between 0 and 1000';
|
|
53
|
+
}
|
|
54
|
+
if (formData.token && !/^[a-zA-Z][a-zA-Z0-9_]*$/.test(formData.token)) {
|
|
55
|
+
newErrors.token = 'Token must start with a letter and contain only letters, numbers, and underscores';
|
|
56
|
+
}
|
|
57
|
+
setErrors(newErrors);
|
|
58
|
+
return Object.keys(newErrors).length === 0;
|
|
59
|
+
}, [formData, existingNames, qualifier?.name]);
|
|
60
|
+
const handleSave = (0, react_1.useCallback)(() => {
|
|
61
|
+
if (!validateForm())
|
|
62
|
+
return;
|
|
63
|
+
const result = {
|
|
64
|
+
name: formData.name,
|
|
65
|
+
typeName: formData.typeName,
|
|
66
|
+
defaultPriority: formData.defaultPriority,
|
|
67
|
+
...(formData.token && { token: formData.token }),
|
|
68
|
+
...(formData.token && formData.tokenIsOptional && { tokenIsOptional: true }),
|
|
69
|
+
...(formData.defaultValue && { defaultValue: formData.defaultValue })
|
|
70
|
+
};
|
|
71
|
+
onSave(result);
|
|
72
|
+
}, [formData, validateForm, onSave]);
|
|
73
|
+
const updateField = (0, react_1.useCallback)((field, value) => {
|
|
74
|
+
setFormData((prev) => {
|
|
75
|
+
const updated = { ...prev, [field]: value };
|
|
76
|
+
// Auto-generate token from name if no custom token is set
|
|
77
|
+
if (field === 'name' && !prev.token) {
|
|
78
|
+
updated.token = String(value)
|
|
79
|
+
.toLowerCase()
|
|
80
|
+
.replace(/[^a-zA-Z0-9]/g, '');
|
|
81
|
+
}
|
|
82
|
+
// Clear tokenIsOptional if token is cleared
|
|
83
|
+
if (field === 'token' && !value) {
|
|
84
|
+
updated.tokenIsOptional = false;
|
|
85
|
+
}
|
|
86
|
+
return updated;
|
|
87
|
+
});
|
|
88
|
+
if (errors[field]) {
|
|
89
|
+
setErrors((prev) => ({ ...prev, [field]: '' }));
|
|
90
|
+
}
|
|
91
|
+
}, [errors]);
|
|
92
|
+
const getDefaultValuePlaceholder = () => {
|
|
93
|
+
if (!selectedQualifierType)
|
|
94
|
+
return 'Enter default value';
|
|
95
|
+
switch (selectedQualifierType.systemType) {
|
|
96
|
+
case 'language':
|
|
97
|
+
return allowsContextList ? 'e.g., en-US or en-US,en' : 'e.g., en-US';
|
|
98
|
+
case 'territory':
|
|
99
|
+
return allowsContextList ? 'e.g., US or US,CA' : 'e.g., US';
|
|
100
|
+
case 'literal':
|
|
101
|
+
// Type-safe extraction of enumeratedValues
|
|
102
|
+
const enumValues = (() => {
|
|
103
|
+
if (!selectedQualifierType.configuration)
|
|
104
|
+
return undefined;
|
|
105
|
+
const result = ts_utils_1.Converters.arrayOf(ts_utils_1.Converters.string).convert(selectedQualifierType.configuration.enumeratedValues);
|
|
106
|
+
return result.isSuccess() ? result.value : undefined;
|
|
107
|
+
})();
|
|
108
|
+
if (enumValues && enumValues.length > 0) {
|
|
109
|
+
return allowsContextList
|
|
110
|
+
? `e.g., ${enumValues[0]} or ${enumValues.slice(0, 2).join(',')}`
|
|
111
|
+
: `e.g., ${enumValues[0]}`;
|
|
112
|
+
}
|
|
113
|
+
return allowsContextList ? 'e.g., value or value1,value2' : 'e.g., value';
|
|
114
|
+
default:
|
|
115
|
+
return 'Enter default value';
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
return (react_1.default.createElement("div", { className: "fixed inset-0 bg-gray-600 bg-opacity-50 flex items-center justify-center z-50 p-4" },
|
|
119
|
+
react_1.default.createElement("div", { className: "bg-white rounded-lg shadow-xl max-w-2xl w-full h-full max-h-[calc(100vh-2rem)] flex flex-col" },
|
|
120
|
+
react_1.default.createElement("div", { className: "flex items-center justify-between p-6 border-b flex-shrink-0" },
|
|
121
|
+
react_1.default.createElement("h3", { className: "text-lg font-medium text-gray-900" }, qualifier ? 'Edit Qualifier' : 'Add Qualifier'),
|
|
122
|
+
react_1.default.createElement("button", { onClick: onCancel, className: "text-gray-400 hover:text-gray-600" },
|
|
123
|
+
react_1.default.createElement(outline_1.XMarkIcon, { className: "w-6 h-6" }))),
|
|
124
|
+
react_1.default.createElement("div", { className: "p-6 space-y-6 overflow-y-auto flex-1 min-h-0" },
|
|
125
|
+
react_1.default.createElement("div", { className: "grid grid-cols-2 gap-4" },
|
|
126
|
+
react_1.default.createElement("div", null,
|
|
127
|
+
react_1.default.createElement("label", { className: "block text-sm font-medium text-gray-700 mb-1" }, "Name *"),
|
|
128
|
+
react_1.default.createElement("input", { type: "text", value: formData.name, onChange: (e) => updateField('name', e.target.value), className: `w-full px-3 py-2 border rounded-md shadow-sm focus:outline-none focus:ring-1 focus:ring-blue-500 ${errors.name ? 'border-red-300' : 'border-gray-300'}`, placeholder: "Enter qualifier name" }),
|
|
129
|
+
errors.name && react_1.default.createElement("p", { className: "mt-1 text-sm text-red-600" }, errors.name)),
|
|
130
|
+
react_1.default.createElement("div", null,
|
|
131
|
+
react_1.default.createElement("label", { className: "block text-sm font-medium text-gray-700 mb-1" }, "Qualifier Type *"),
|
|
132
|
+
react_1.default.createElement("select", { value: formData.typeName, onChange: (e) => updateField('typeName', e.target.value), className: `w-full px-3 py-2 border rounded-md shadow-sm focus:outline-none focus:ring-1 focus:ring-blue-500 ${errors.typeName ? 'border-red-300' : 'border-gray-300'}` }, qualifierTypes.length === 0 ? (react_1.default.createElement("option", { value: "" }, "No qualifier types available")) : (qualifierTypes.map((type) => (react_1.default.createElement("option", { key: type.name, value: type.name },
|
|
133
|
+
type.name,
|
|
134
|
+
" (",
|
|
135
|
+
type.systemType,
|
|
136
|
+
")"))))),
|
|
137
|
+
errors.typeName && react_1.default.createElement("p", { className: "mt-1 text-sm text-red-600" }, errors.typeName))),
|
|
138
|
+
react_1.default.createElement("div", { className: "grid grid-cols-2 gap-4" },
|
|
139
|
+
react_1.default.createElement("div", null,
|
|
140
|
+
react_1.default.createElement("label", { className: "block text-sm font-medium text-gray-700 mb-1" }, "Default Priority *"),
|
|
141
|
+
react_1.default.createElement("input", { type: "number", min: "0", max: "1000", value: formData.defaultPriority, onChange: (e) => updateField('defaultPriority', parseInt(e.target.value) || 0), className: `w-full px-3 py-2 border rounded-md shadow-sm focus:outline-none focus:ring-1 focus:ring-blue-500 ${errors.defaultPriority ? 'border-red-300' : 'border-gray-300'}`, placeholder: "50" }),
|
|
142
|
+
errors.defaultPriority && (react_1.default.createElement("p", { className: "mt-1 text-sm text-red-600" }, errors.defaultPriority)),
|
|
143
|
+
react_1.default.createElement("p", { className: "mt-1 text-xs text-gray-500" }, "Higher numbers have higher priority (0-1000)")),
|
|
144
|
+
react_1.default.createElement("div", null,
|
|
145
|
+
react_1.default.createElement("label", { className: "block text-sm font-medium text-gray-700 mb-1" },
|
|
146
|
+
"Token",
|
|
147
|
+
react_1.default.createElement("span", { className: "ml-1 text-gray-500" }, "(optional)")),
|
|
148
|
+
react_1.default.createElement("input", { type: "text", value: formData.token, onChange: (e) => updateField('token', e.target.value), className: `w-full px-3 py-2 border rounded-md shadow-sm focus:outline-none focus:ring-1 focus:ring-blue-500 ${errors.token ? 'border-red-300' : 'border-gray-300'}`, placeholder: "e.g., lang, locale" }),
|
|
149
|
+
errors.token && react_1.default.createElement("p", { className: "mt-1 text-sm text-red-600" }, errors.token),
|
|
150
|
+
react_1.default.createElement("p", { className: "mt-1 text-xs text-gray-500" }, "Used to identify this qualifier in resource names"))),
|
|
151
|
+
formData.token && (react_1.default.createElement("div", { className: "flex items-center" },
|
|
152
|
+
react_1.default.createElement("input", { type: "checkbox", id: "tokenIsOptional", checked: formData.tokenIsOptional, onChange: (e) => updateField('tokenIsOptional', e.target.checked), className: "h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded" }),
|
|
153
|
+
react_1.default.createElement("label", { htmlFor: "tokenIsOptional", className: "ml-2 text-sm text-gray-700" }, "Token is optional in resource names"),
|
|
154
|
+
react_1.default.createElement("div", { className: "ml-2 group relative" },
|
|
155
|
+
react_1.default.createElement(outline_1.InformationCircleIcon, { className: "w-4 h-4 text-gray-400" }),
|
|
156
|
+
react_1.default.createElement("div", { className: "absolute left-0 bottom-6 hidden group-hover:block bg-gray-800 text-white text-xs rounded py-1 px-2 whitespace-nowrap z-10" }, "Allow resources without this qualifier token")))),
|
|
157
|
+
react_1.default.createElement("div", null,
|
|
158
|
+
react_1.default.createElement("label", { className: "block text-sm font-medium text-gray-700 mb-1" },
|
|
159
|
+
"Default Value",
|
|
160
|
+
react_1.default.createElement("span", { className: "ml-1 text-gray-500" }, "(optional)")),
|
|
161
|
+
react_1.default.createElement("input", { type: "text", value: formData.defaultValue, onChange: (e) => updateField('defaultValue', e.target.value), className: "w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-1 focus:ring-blue-500", placeholder: getDefaultValuePlaceholder() }),
|
|
162
|
+
react_1.default.createElement("div", { className: "mt-1 text-xs text-gray-500" }, selectedQualifierType && (react_1.default.createElement("div", null,
|
|
163
|
+
react_1.default.createElement("p", null,
|
|
164
|
+
"Qualifier type: ",
|
|
165
|
+
react_1.default.createElement("span", { className: "font-medium" }, selectedQualifierType.systemType)),
|
|
166
|
+
allowsContextList && (react_1.default.createElement("p", { className: "text-blue-600" }, "This qualifier type supports multiple values (comma-separated)")))))),
|
|
167
|
+
selectedQualifierType && (react_1.default.createElement("div", { className: "p-4 bg-gray-50 rounded-lg" },
|
|
168
|
+
react_1.default.createElement("h4", { className: "font-medium text-gray-900 mb-2" }, "Qualifier Type Information"),
|
|
169
|
+
react_1.default.createElement("div", { className: "text-sm text-gray-600 space-y-1" },
|
|
170
|
+
react_1.default.createElement("p", null,
|
|
171
|
+
react_1.default.createElement("span", { className: "font-medium" }, "System Type:"),
|
|
172
|
+
" ",
|
|
173
|
+
selectedQualifierType.systemType),
|
|
174
|
+
react_1.default.createElement("p", null,
|
|
175
|
+
react_1.default.createElement("span", { className: "font-medium" }, "Supports Context List:"),
|
|
176
|
+
' ',
|
|
177
|
+
allowsContextList ? 'Yes' : 'No'),
|
|
178
|
+
selectedQualifierType.systemType === 'literal' && selectedQualifierType.configuration && (react_1.default.createElement(react_1.default.Fragment, null,
|
|
179
|
+
selectedQualifierType.configuration.caseSensitive !==
|
|
180
|
+
undefined && (react_1.default.createElement("p", null,
|
|
181
|
+
react_1.default.createElement("span", { className: "font-medium" }, "Case Sensitive:"),
|
|
182
|
+
' ',
|
|
183
|
+
selectedQualifierType.configuration
|
|
184
|
+
.caseSensitive
|
|
185
|
+
? 'Yes'
|
|
186
|
+
: 'No')),
|
|
187
|
+
selectedQualifierType.configuration.enumeratedValues && (react_1.default.createElement("p", null,
|
|
188
|
+
react_1.default.createElement("span", { className: "font-medium" }, "Allowed Values:"),
|
|
189
|
+
' ',
|
|
190
|
+
selectedQualifierType.configuration
|
|
191
|
+
.enumeratedValues.join(', '))))),
|
|
192
|
+
selectedQualifierType.systemType === 'territory' && selectedQualifierType.configuration && (react_1.default.createElement(react_1.default.Fragment, null,
|
|
193
|
+
selectedQualifierType.configuration.acceptLowercase !==
|
|
194
|
+
undefined && (react_1.default.createElement("p", null,
|
|
195
|
+
react_1.default.createElement("span", { className: "font-medium" }, "Accept Lowercase:"),
|
|
196
|
+
' ',
|
|
197
|
+
selectedQualifierType.configuration
|
|
198
|
+
.acceptLowercase
|
|
199
|
+
? 'Yes'
|
|
200
|
+
: 'No')),
|
|
201
|
+
selectedQualifierType.configuration.allowedTerritories && (react_1.default.createElement("p", null,
|
|
202
|
+
react_1.default.createElement("span", { className: "font-medium" }, "Allowed Territories:"),
|
|
203
|
+
' ',
|
|
204
|
+
selectedQualifierType.configuration
|
|
205
|
+
.allowedTerritories.join(', '))))))))),
|
|
206
|
+
react_1.default.createElement("div", { className: "flex justify-end space-x-3 px-6 py-4 border-t bg-gray-50 flex-shrink-0" },
|
|
207
|
+
react_1.default.createElement("button", { onClick: onCancel, className: "px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-md hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500" }, "Cancel"),
|
|
208
|
+
react_1.default.createElement("button", { onClick: handleSave, className: "px-4 py-2 text-sm font-medium text-white bg-blue-600 border border-transparent rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500" }, qualifier ? 'Save Changes' : 'Add Qualifier')))));
|
|
209
|
+
};
|
|
210
|
+
exports.QualifierEditForm = QualifierEditForm;
|
|
211
|
+
//# sourceMappingURL=QualifierEditForm.js.map
|