@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
|
@@ -1,493 +0,0 @@
|
|
|
1
|
-
import React, { useState, useEffect } from 'react';
|
|
2
|
-
import { ResourceDetailData } from '../../../types';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Props for the SourceResourceDetail component.
|
|
6
|
-
*
|
|
7
|
-
* @public
|
|
8
|
-
*/
|
|
9
|
-
export interface SourceResourceDetailProps {
|
|
10
|
-
/** The resource ID to display details for */
|
|
11
|
-
resourceId: string;
|
|
12
|
-
/** Processed resources containing the resource data */
|
|
13
|
-
processedResources: any;
|
|
14
|
-
/** Optional callback for handling component messages */
|
|
15
|
-
onMessage?: (type: 'info' | 'warning' | 'error' | 'success', message: string) => void;
|
|
16
|
-
/** Optional CSS classes to apply to the container */
|
|
17
|
-
className?: string;
|
|
18
|
-
/** Optional title for the detail panel */
|
|
19
|
-
title?: string;
|
|
20
|
-
// Dual-resource comparison mode props
|
|
21
|
-
/** Optional original resources for comparison mode */
|
|
22
|
-
originalProcessedResources?: any;
|
|
23
|
-
/** Optional filter context for comparison */
|
|
24
|
-
filterContext?: Record<string, string | undefined>;
|
|
25
|
-
/** Whether to show comparison view */
|
|
26
|
-
showComparison?: boolean;
|
|
27
|
-
// Configurable toggle labels
|
|
28
|
-
/** Label for primary resource view (default: 'Current') */
|
|
29
|
-
primaryLabel?: string;
|
|
30
|
-
/** Label for secondary resource view (default: 'Original') */
|
|
31
|
-
secondaryLabel?: string;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* A comprehensive component for displaying detailed information about a specific resource.
|
|
36
|
-
*
|
|
37
|
-
* SourceResourceDetail provides an in-depth view of a resource's properties, candidates,
|
|
38
|
-
* conditions, and metadata. It supports both single resource display and comparison mode
|
|
39
|
-
* for viewing differences between filtered and original resources. The component automatically
|
|
40
|
-
* extracts and presents resource information in a structured, readable format.
|
|
41
|
-
*
|
|
42
|
-
* @example
|
|
43
|
-
* ```tsx
|
|
44
|
-
* import { SourceResourceDetail } from '@fgv/ts-res-ui-components';
|
|
45
|
-
*
|
|
46
|
-
* function ResourceInspector() {
|
|
47
|
-
* const [selectedResourceId, setSelectedResourceId] = useState<string>('user.welcome');
|
|
48
|
-
* const processedResources = useProcessedResources();
|
|
49
|
-
*
|
|
50
|
-
* return (
|
|
51
|
-
* <SourceResourceDetail
|
|
52
|
-
* resourceId={selectedResourceId}
|
|
53
|
-
* processedResources={processedResources}
|
|
54
|
-
* title="Resource Inspector"
|
|
55
|
-
* onMessage={(type, msg) => console.log(`${type}: ${msg}`)}
|
|
56
|
-
* className="border rounded-lg p-4"
|
|
57
|
-
* />
|
|
58
|
-
* );
|
|
59
|
-
* }
|
|
60
|
-
* ```
|
|
61
|
-
*
|
|
62
|
-
* @example
|
|
63
|
-
* ```tsx
|
|
64
|
-
* // Using comparison mode to show filtered vs original resources
|
|
65
|
-
* import { SourceResourceDetail, FilterTools } from '@fgv/ts-res-ui-components';
|
|
66
|
-
*
|
|
67
|
-
* function FilteredResourceComparison() {
|
|
68
|
-
* const { state: filterState } = FilterTools.useFilterState();
|
|
69
|
-
* const originalResources = useOriginalResources();
|
|
70
|
-
* const filteredResources = filterState.filteredResources;
|
|
71
|
-
* const [selectedId, setSelectedId] = useState<string | null>(null);
|
|
72
|
-
*
|
|
73
|
-
* if (!selectedId) {
|
|
74
|
-
* return <div>Select a resource to compare</div>;
|
|
75
|
-
* }
|
|
76
|
-
*
|
|
77
|
-
* return (
|
|
78
|
-
* <SourceResourceDetail
|
|
79
|
-
* resourceId={selectedId}
|
|
80
|
-
* processedResources={filteredResources}
|
|
81
|
-
* originalProcessedResources={originalResources}
|
|
82
|
-
* filterContext={filterState.appliedValues}
|
|
83
|
-
* showComparison={true}
|
|
84
|
-
* primaryLabel="Filtered"
|
|
85
|
-
* secondaryLabel="Original"
|
|
86
|
-
* title="Resource Comparison"
|
|
87
|
-
* className="comparison-panel"
|
|
88
|
-
* />
|
|
89
|
-
* );
|
|
90
|
-
* }
|
|
91
|
-
* ```
|
|
92
|
-
*
|
|
93
|
-
* @example
|
|
94
|
-
* ```tsx
|
|
95
|
-
* // Integration with orchestrator for comprehensive resource details
|
|
96
|
-
* import { SourceResourceDetail, ResourceTools } from '@fgv/ts-res-ui-components';
|
|
97
|
-
*
|
|
98
|
-
* function OrchestratorResourceDetail() {
|
|
99
|
-
* const { state, actions } = ResourceTools.useResourceData();
|
|
100
|
-
*
|
|
101
|
-
* if (!state.selectedResourceId || !state.resources) {
|
|
102
|
-
* return <div className="p-4 text-gray-500">No resource selected</div>;
|
|
103
|
-
* }
|
|
104
|
-
*
|
|
105
|
-
* return (
|
|
106
|
-
* <div className="resource-detail-container">
|
|
107
|
-
* <div className="detail-header">
|
|
108
|
-
* <h2>Resource: {state.selectedResourceId}</h2>
|
|
109
|
-
* <button onClick={() => actions.selectResource(null)}>Clear</button>
|
|
110
|
-
* </div>
|
|
111
|
-
* <SourceResourceDetail
|
|
112
|
-
* resourceId={state.selectedResourceId}
|
|
113
|
-
* processedResources={state.resources}
|
|
114
|
-
* originalProcessedResources={state.filterResult ? state.resources : undefined}
|
|
115
|
-
* filterContext={state.filterState.appliedValues}
|
|
116
|
-
* showComparison={!!state.filterResult}
|
|
117
|
-
* title="Resource Details"
|
|
118
|
-
* onMessage={actions.addMessage}
|
|
119
|
-
* className="detail-content"
|
|
120
|
-
* />
|
|
121
|
-
* </div>
|
|
122
|
-
* );
|
|
123
|
-
* }
|
|
124
|
-
* ```
|
|
125
|
-
*
|
|
126
|
-
* @public
|
|
127
|
-
*/
|
|
128
|
-
export const SourceResourceDetail: React.FC<SourceResourceDetailProps> = ({
|
|
129
|
-
resourceId,
|
|
130
|
-
processedResources,
|
|
131
|
-
onMessage,
|
|
132
|
-
className = '',
|
|
133
|
-
title = 'Resource Details',
|
|
134
|
-
originalProcessedResources,
|
|
135
|
-
filterContext,
|
|
136
|
-
showComparison = false,
|
|
137
|
-
primaryLabel = 'Current',
|
|
138
|
-
secondaryLabel = 'Original'
|
|
139
|
-
}) => {
|
|
140
|
-
const [resourceDetail, setResourceDetail] = useState<ResourceDetailData | null>(null);
|
|
141
|
-
const [originalResourceDetail, setOriginalResourceDetail] = useState<ResourceDetailData | null>(null);
|
|
142
|
-
const [isLoading, setIsLoading] = useState(false);
|
|
143
|
-
const [error, setError] = useState<string | null>(null);
|
|
144
|
-
const [showFilteredView, setShowFilteredView] = useState(true);
|
|
145
|
-
|
|
146
|
-
useEffect(() => {
|
|
147
|
-
const loadResourceDetail = () => {
|
|
148
|
-
setIsLoading(true);
|
|
149
|
-
setError(null);
|
|
150
|
-
|
|
151
|
-
try {
|
|
152
|
-
// Helper function to extract resource detail from processed resources
|
|
153
|
-
const extractResourceDetail = (resources: any, isOriginal = false): ResourceDetailData | null => {
|
|
154
|
-
const resourceManager = resources.system.resourceManager;
|
|
155
|
-
const resourceResult = resourceManager.getBuiltResource(resourceId);
|
|
156
|
-
|
|
157
|
-
if (!resourceResult.isSuccess()) {
|
|
158
|
-
return null;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
const resource = resourceResult.value;
|
|
162
|
-
let candidateDetails: any[] = [];
|
|
163
|
-
|
|
164
|
-
// Check if candidates have conditions property (ResourceManagerBuilder format)
|
|
165
|
-
if (resource.candidates.length > 0 && 'conditions' in resource.candidates[0]) {
|
|
166
|
-
// ResourceManagerBuilder format with full condition details
|
|
167
|
-
candidateDetails = resource.candidates.map((candidate: any) => ({
|
|
168
|
-
json: candidate.json,
|
|
169
|
-
conditions:
|
|
170
|
-
candidate.conditions?.conditions?.map((condition: any) => ({
|
|
171
|
-
qualifier: condition.qualifier.name,
|
|
172
|
-
operator: condition.operator,
|
|
173
|
-
value: condition.value,
|
|
174
|
-
priority: condition.priority,
|
|
175
|
-
scoreAsDefault: condition.scoreAsDefault
|
|
176
|
-
})) || [],
|
|
177
|
-
isPartial: candidate.isPartial,
|
|
178
|
-
mergeMethod: candidate.mergeMethod
|
|
179
|
-
}));
|
|
180
|
-
} else {
|
|
181
|
-
// IResourceManager format - extract conditions from compiled collection
|
|
182
|
-
const compiledCollection = resources.compiledCollection;
|
|
183
|
-
const compiledResource = compiledCollection?.resources?.find((r: any) => r.id === resourceId);
|
|
184
|
-
|
|
185
|
-
candidateDetails = resource.candidates.map((candidate: any, index: number) => {
|
|
186
|
-
// Try to get conditions from the compiled collection
|
|
187
|
-
let conditions: any[] = [];
|
|
188
|
-
|
|
189
|
-
if (compiledResource && compiledCollection) {
|
|
190
|
-
const decision = compiledCollection.decisions?.[compiledResource.decision];
|
|
191
|
-
if (decision?.conditionSets && index < decision.conditionSets.length) {
|
|
192
|
-
const conditionSetIndex = decision.conditionSets[index];
|
|
193
|
-
const conditionSet = compiledCollection.conditionSets?.[conditionSetIndex];
|
|
194
|
-
|
|
195
|
-
if (conditionSet?.conditions) {
|
|
196
|
-
conditions = conditionSet.conditions
|
|
197
|
-
.map((condIndex: number) => {
|
|
198
|
-
const condition = compiledCollection.conditions?.[condIndex];
|
|
199
|
-
const qualifier = compiledCollection.qualifiers?.[condition?.qualifierIndex];
|
|
200
|
-
return condition && qualifier
|
|
201
|
-
? {
|
|
202
|
-
qualifier: qualifier.name,
|
|
203
|
-
operator: condition.operator || 'eq',
|
|
204
|
-
value: condition.value,
|
|
205
|
-
priority: condition.priority || qualifier.defaultPriority || 500,
|
|
206
|
-
scoreAsDefault: condition.scoreAsDefault
|
|
207
|
-
}
|
|
208
|
-
: null;
|
|
209
|
-
})
|
|
210
|
-
.filter(Boolean);
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
return {
|
|
216
|
-
json: candidate.json,
|
|
217
|
-
conditions: conditions,
|
|
218
|
-
isPartial: candidate.isPartial,
|
|
219
|
-
mergeMethod: candidate.mergeMethod
|
|
220
|
-
};
|
|
221
|
-
});
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
return {
|
|
225
|
-
id: resource.id,
|
|
226
|
-
resourceType: resource.resourceType.key || resource.resourceType.name || 'unknown',
|
|
227
|
-
candidateCount: resource.candidates.length,
|
|
228
|
-
candidates: candidateDetails
|
|
229
|
-
};
|
|
230
|
-
};
|
|
231
|
-
|
|
232
|
-
// Load current/filtered resource detail
|
|
233
|
-
const currentDetail = extractResourceDetail(processedResources, false);
|
|
234
|
-
if (currentDetail) {
|
|
235
|
-
setResourceDetail(currentDetail);
|
|
236
|
-
} else {
|
|
237
|
-
setError(`Failed to load resource details for: ${resourceId}`);
|
|
238
|
-
onMessage?.('error', `Failed to load resource details for: ${resourceId}`);
|
|
239
|
-
return;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
// Load original resource detail if in comparison mode
|
|
243
|
-
if (showComparison && originalProcessedResources) {
|
|
244
|
-
const originalDetail = extractResourceDetail(originalProcessedResources, true);
|
|
245
|
-
if (originalDetail) {
|
|
246
|
-
setOriginalResourceDetail(originalDetail);
|
|
247
|
-
}
|
|
248
|
-
} else {
|
|
249
|
-
setOriginalResourceDetail(null);
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
onMessage?.('info', `Loaded details for resource: ${resourceId}`);
|
|
253
|
-
} catch (err) {
|
|
254
|
-
const errorMsg = `Error loading resource details: ${
|
|
255
|
-
err instanceof Error ? err.message : String(err)
|
|
256
|
-
}`;
|
|
257
|
-
setError(errorMsg);
|
|
258
|
-
onMessage?.('error', errorMsg);
|
|
259
|
-
} finally {
|
|
260
|
-
setIsLoading(false);
|
|
261
|
-
}
|
|
262
|
-
};
|
|
263
|
-
|
|
264
|
-
loadResourceDetail();
|
|
265
|
-
}, [resourceId, processedResources, originalProcessedResources, showComparison, onMessage]);
|
|
266
|
-
|
|
267
|
-
if (isLoading) {
|
|
268
|
-
return (
|
|
269
|
-
<div className={`flex flex-col h-full ${className}`}>
|
|
270
|
-
<h3 className="text-lg font-semibold text-gray-900 mb-4">{title}</h3>
|
|
271
|
-
<div className="flex-1 flex items-center justify-center border border-gray-200 rounded-lg bg-gray-50">
|
|
272
|
-
<div className="text-center">
|
|
273
|
-
<div className="animate-spin h-8 w-8 border-4 border-blue-600 border-t-transparent rounded-full mx-auto mb-4"></div>
|
|
274
|
-
<p className="text-gray-500">Loading resource details...</p>
|
|
275
|
-
</div>
|
|
276
|
-
</div>
|
|
277
|
-
</div>
|
|
278
|
-
);
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
if (error) {
|
|
282
|
-
return (
|
|
283
|
-
<div className={`flex flex-col h-full ${className}`}>
|
|
284
|
-
<h3 className="text-lg font-semibold text-gray-900 mb-4">{title}</h3>
|
|
285
|
-
<div className="flex-1 border border-gray-200 rounded-lg p-4 bg-red-50">
|
|
286
|
-
<div className="text-center">
|
|
287
|
-
<p className="text-red-600 font-medium mb-2">Error Loading Resource</p>
|
|
288
|
-
<p className="text-red-500 text-sm">{error}</p>
|
|
289
|
-
</div>
|
|
290
|
-
</div>
|
|
291
|
-
</div>
|
|
292
|
-
);
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
if (!resourceDetail) {
|
|
296
|
-
return (
|
|
297
|
-
<div className={`flex flex-col h-full ${className}`}>
|
|
298
|
-
<h3 className="text-lg font-semibold text-gray-900 mb-4">{title}</h3>
|
|
299
|
-
<div className="flex-1 flex items-center justify-center border border-gray-200 rounded-lg bg-gray-50">
|
|
300
|
-
<p className="text-gray-500">No resource details available</p>
|
|
301
|
-
</div>
|
|
302
|
-
</div>
|
|
303
|
-
);
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
// Determine which resource detail to show and comparison state
|
|
307
|
-
const currentDetail =
|
|
308
|
-
showComparison && !showFilteredView && originalResourceDetail ? originalResourceDetail : resourceDetail;
|
|
309
|
-
const isShowingPrimary = !showComparison || showFilteredView;
|
|
310
|
-
|
|
311
|
-
return (
|
|
312
|
-
<div className={`flex flex-col h-full ${className}`}>
|
|
313
|
-
<div className="flex items-center justify-between mb-4">
|
|
314
|
-
<h3 className="text-lg font-semibold text-gray-900">{title}</h3>
|
|
315
|
-
{showComparison && originalResourceDetail && (
|
|
316
|
-
<div className="flex items-center space-x-2">
|
|
317
|
-
<span className="text-xs text-gray-500">View:</span>
|
|
318
|
-
<button
|
|
319
|
-
onClick={() => setShowFilteredView(false)}
|
|
320
|
-
className={`px-2 py-1 text-xs rounded ${
|
|
321
|
-
!showFilteredView
|
|
322
|
-
? 'bg-blue-100 text-blue-800 font-medium'
|
|
323
|
-
: 'text-gray-600 hover:bg-gray-100'
|
|
324
|
-
}`}
|
|
325
|
-
>
|
|
326
|
-
{secondaryLabel} ({originalResourceDetail.candidateCount})
|
|
327
|
-
</button>
|
|
328
|
-
<button
|
|
329
|
-
onClick={() => setShowFilteredView(true)}
|
|
330
|
-
className={`px-2 py-1 text-xs rounded ${
|
|
331
|
-
showFilteredView
|
|
332
|
-
? 'bg-purple-100 text-purple-800 font-medium'
|
|
333
|
-
: 'text-gray-600 hover:bg-gray-100'
|
|
334
|
-
}`}
|
|
335
|
-
>
|
|
336
|
-
{primaryLabel} ({resourceDetail.candidateCount})
|
|
337
|
-
</button>
|
|
338
|
-
</div>
|
|
339
|
-
)}
|
|
340
|
-
</div>
|
|
341
|
-
|
|
342
|
-
<div className="flex-1 overflow-y-auto border border-gray-200 rounded-lg p-4 bg-gray-50">
|
|
343
|
-
<div className="space-y-6">
|
|
344
|
-
{/* Resource Overview */}
|
|
345
|
-
<div>
|
|
346
|
-
<h4 className="font-medium text-gray-700 mb-3">Resource Overview</h4>
|
|
347
|
-
<div className="bg-white p-4 rounded-lg border space-y-3">
|
|
348
|
-
<div>
|
|
349
|
-
<span className="text-sm font-medium text-gray-600">Fully Qualified ID:</span>
|
|
350
|
-
<code className="text-sm bg-gray-100 px-2 py-1 rounded ml-2 break-all">
|
|
351
|
-
{currentDetail.id}
|
|
352
|
-
</code>
|
|
353
|
-
</div>
|
|
354
|
-
<div>
|
|
355
|
-
<span className="text-sm font-medium text-gray-600">Resource Type:</span>
|
|
356
|
-
<span className="ml-2 text-sm">{currentDetail.resourceType}</span>
|
|
357
|
-
</div>
|
|
358
|
-
<div>
|
|
359
|
-
<span className="text-sm font-medium text-gray-600">Candidate Count:</span>
|
|
360
|
-
<span
|
|
361
|
-
className={`ml-2 text-sm font-medium ${
|
|
362
|
-
showComparison && originalResourceDetail
|
|
363
|
-
? currentDetail.candidateCount === 0
|
|
364
|
-
? 'text-red-600'
|
|
365
|
-
: currentDetail.candidateCount <
|
|
366
|
-
(isShowingPrimary
|
|
367
|
-
? originalResourceDetail.candidateCount
|
|
368
|
-
: resourceDetail.candidateCount)
|
|
369
|
-
? 'text-amber-600'
|
|
370
|
-
: 'text-green-600'
|
|
371
|
-
: 'text-blue-600'
|
|
372
|
-
}`}
|
|
373
|
-
>
|
|
374
|
-
{currentDetail.candidateCount}
|
|
375
|
-
{showComparison &&
|
|
376
|
-
originalResourceDetail &&
|
|
377
|
-
currentDetail.candidateCount !==
|
|
378
|
-
(isShowingPrimary
|
|
379
|
-
? originalResourceDetail.candidateCount
|
|
380
|
-
: resourceDetail.candidateCount) && (
|
|
381
|
-
<span className="text-gray-400 ml-1">
|
|
382
|
-
(was{' '}
|
|
383
|
-
{isShowingPrimary
|
|
384
|
-
? originalResourceDetail.candidateCount
|
|
385
|
-
: resourceDetail.candidateCount}
|
|
386
|
-
)
|
|
387
|
-
</span>
|
|
388
|
-
)}
|
|
389
|
-
</span>
|
|
390
|
-
</div>
|
|
391
|
-
{showComparison && filterContext && (
|
|
392
|
-
<div>
|
|
393
|
-
<span className="text-sm font-medium text-gray-600">Filter Context:</span>
|
|
394
|
-
<span className="ml-2 text-sm text-purple-700">
|
|
395
|
-
{Object.entries(filterContext)
|
|
396
|
-
.filter(([, value]) => value !== undefined && value !== '')
|
|
397
|
-
.map(([key, value]) => `${key}=${value}`)
|
|
398
|
-
.join(', ') || 'No filters'}
|
|
399
|
-
</span>
|
|
400
|
-
</div>
|
|
401
|
-
)}
|
|
402
|
-
</div>
|
|
403
|
-
</div>
|
|
404
|
-
|
|
405
|
-
{/* Candidates */}
|
|
406
|
-
<div>
|
|
407
|
-
<h4 className="font-medium text-gray-700 mb-3">
|
|
408
|
-
{showComparison && !isShowingPrimary
|
|
409
|
-
? `${secondaryLabel} `
|
|
410
|
-
: showComparison && isShowingPrimary
|
|
411
|
-
? `${primaryLabel} `
|
|
412
|
-
: ''}
|
|
413
|
-
Candidates ({currentDetail.candidates.length})
|
|
414
|
-
</h4>
|
|
415
|
-
{currentDetail.candidates.length > 0 ? (
|
|
416
|
-
<div className="space-y-4">
|
|
417
|
-
{currentDetail.candidates.map((candidate, index) => (
|
|
418
|
-
<div key={index} className="bg-white p-4 rounded-lg border">
|
|
419
|
-
<div className="flex items-center justify-between mb-3">
|
|
420
|
-
<h5 className="font-medium text-gray-800">Candidate {index + 1}</h5>
|
|
421
|
-
<div className="flex items-center space-x-2 text-xs">
|
|
422
|
-
{candidate.isPartial && (
|
|
423
|
-
<span className="bg-yellow-100 text-yellow-800 px-2 py-1 rounded">Partial</span>
|
|
424
|
-
)}
|
|
425
|
-
<span className="bg-gray-100 text-gray-700 px-2 py-1 rounded">
|
|
426
|
-
{candidate.mergeMethod}
|
|
427
|
-
</span>
|
|
428
|
-
</div>
|
|
429
|
-
</div>
|
|
430
|
-
|
|
431
|
-
{/* Conditions */}
|
|
432
|
-
{candidate.conditions.length > 0 && (
|
|
433
|
-
<div className="mb-3">
|
|
434
|
-
<h6 className="text-sm font-medium text-gray-600 mb-2">Conditions:</h6>
|
|
435
|
-
<div className="space-y-1">
|
|
436
|
-
{candidate.conditions.map((condition, condIndex) => (
|
|
437
|
-
<div
|
|
438
|
-
key={condIndex}
|
|
439
|
-
className="flex items-center text-xs bg-blue-50 px-2 py-1 rounded"
|
|
440
|
-
>
|
|
441
|
-
<span className="font-medium text-blue-800">{condition.qualifier}</span>
|
|
442
|
-
<span className="mx-1 text-blue-600">{condition.operator}</span>
|
|
443
|
-
<span className="text-blue-700">{condition.value}</span>
|
|
444
|
-
<div className="ml-auto flex items-center space-x-2">
|
|
445
|
-
<span className="text-blue-500">priority: {condition.priority}</span>
|
|
446
|
-
{condition.scoreAsDefault !== undefined && (
|
|
447
|
-
<span className="text-amber-600 font-medium">
|
|
448
|
-
default: {condition.scoreAsDefault}
|
|
449
|
-
</span>
|
|
450
|
-
)}
|
|
451
|
-
</div>
|
|
452
|
-
</div>
|
|
453
|
-
))}
|
|
454
|
-
</div>
|
|
455
|
-
</div>
|
|
456
|
-
)}
|
|
457
|
-
|
|
458
|
-
{candidate.conditions.length === 0 && (
|
|
459
|
-
<div className="mb-3">
|
|
460
|
-
<span className="text-xs text-gray-500 bg-gray-100 px-2 py-1 rounded">
|
|
461
|
-
No conditions (default candidate)
|
|
462
|
-
</span>
|
|
463
|
-
</div>
|
|
464
|
-
)}
|
|
465
|
-
|
|
466
|
-
{/* JSON Content */}
|
|
467
|
-
<div>
|
|
468
|
-
<h6 className="text-sm font-medium text-gray-600 mb-2">Content:</h6>
|
|
469
|
-
<pre className="text-xs bg-gray-50 p-3 rounded border overflow-x-auto max-h-40">
|
|
470
|
-
{JSON.stringify(candidate.json, null, 2)}
|
|
471
|
-
</pre>
|
|
472
|
-
</div>
|
|
473
|
-
</div>
|
|
474
|
-
))}
|
|
475
|
-
</div>
|
|
476
|
-
) : (
|
|
477
|
-
<div className="bg-red-50 border border-red-200 p-4 rounded-lg">
|
|
478
|
-
<p className="text-sm text-red-700 font-medium">No candidates available</p>
|
|
479
|
-
<p className="text-xs text-red-600 mt-1">
|
|
480
|
-
{showComparison
|
|
481
|
-
? 'This resource has been completely filtered out. Consider adjusting your filter criteria.'
|
|
482
|
-
: 'This resource has no candidates defined.'}
|
|
483
|
-
</p>
|
|
484
|
-
</div>
|
|
485
|
-
)}
|
|
486
|
-
</div>
|
|
487
|
-
</div>
|
|
488
|
-
</div>
|
|
489
|
-
</div>
|
|
490
|
-
);
|
|
491
|
-
};
|
|
492
|
-
|
|
493
|
-
export default SourceResourceDetail;
|