@fgv/ts-res-ui-components 5.0.0-19 → 5.0.0-20
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 +138 -1
- package/config/jest.setup.js +3 -0
- package/dist/ts-res-ui-components.d.ts +116 -156
- package/lib/components/common/QualifierContextControl.js +4 -2
- package/lib/components/common/ResolutionContextOptionsControl.d.ts +8 -0
- package/lib/components/common/ResolutionContextOptionsControl.js +9 -1
- package/lib/components/orchestrator/ResourceOrchestrator.js +11 -0
- package/lib/components/views/ResolutionView/EditableJsonView.d.ts +1 -1
- package/lib/components/views/ResolutionView/EditableJsonView.js +1 -1
- package/lib/components/views/ResolutionView/NewResourceModal.d.ts +21 -0
- package/lib/components/views/ResolutionView/NewResourceModal.js +60 -0
- package/lib/components/views/ResolutionView/UnifiedChangeControls.d.ts +53 -0
- package/lib/components/views/ResolutionView/UnifiedChangeControls.js +71 -0
- package/lib/components/views/ResolutionView/index.js +180 -34
- package/lib/hooks/useResolutionState.js +510 -60
- package/lib/index.js +1 -1
- package/lib/namespaces/ResolutionTools.d.ts +1 -1
- package/lib/namespaces/ResolutionTools.js +1 -1
- package/lib/test/unit/components/ResolutionView.unified.test.d.ts +2 -0
- package/lib/test/unit/hooks/useResolutionState.context.test.d.ts +2 -0
- package/lib/types/index.d.ts +54 -2
- package/lib/utils/resolutionEditing.d.ts +17 -0
- package/lib/utils/resolutionEditing.js +87 -71
- package/lib-commonjs/components/common/QualifierContextControl.js +4 -2
- package/lib-commonjs/components/common/ResolutionContextOptionsControl.js +9 -1
- package/lib-commonjs/components/orchestrator/ResourceOrchestrator.js +11 -0
- package/lib-commonjs/components/views/ResolutionView/EditableJsonView.js +1 -1
- package/lib-commonjs/components/views/ResolutionView/NewResourceModal.js +65 -0
- package/lib-commonjs/components/views/ResolutionView/UnifiedChangeControls.js +76 -0
- package/lib-commonjs/components/views/ResolutionView/index.js +178 -32
- package/lib-commonjs/hooks/useResolutionState.js +509 -59
- package/lib-commonjs/index.js +1 -1
- package/lib-commonjs/namespaces/ResolutionTools.js +3 -3
- package/lib-commonjs/utils/resolutionEditing.js +89 -71
- package/package.json +11 -7
- package/src/components/common/QualifierContextControl.tsx +19 -1
- package/src/components/common/ResolutionContextOptionsControl.tsx +42 -1
- package/src/components/orchestrator/ResourceOrchestrator.tsx +13 -0
- package/src/components/views/ResolutionView/EditableJsonView.tsx +1 -1
- package/src/components/views/ResolutionView/NewResourceModal.tsx +158 -0
- package/src/components/views/ResolutionView/UnifiedChangeControls.tsx +163 -0
- package/src/components/views/ResolutionView/index.tsx +244 -39
- package/src/hooks/useResolutionState.ts +627 -89
- package/src/index.ts +1 -1
- package/src/namespaces/ResolutionTools.ts +1 -1
- package/src/types/index.ts +58 -2
- package/src/utils/resolutionEditing.ts +107 -80
- package/lib/components/views/ResolutionView/ResolutionEditControls.d.ts +0 -152
- package/lib/components/views/ResolutionView/ResolutionEditControls.js +0 -210
- package/lib-commonjs/components/views/ResolutionView/ResolutionEditControls.js +0 -215
- package/src/components/views/ResolutionView/ResolutionEditControls.tsx +0 -303
package/README.md
CHANGED
|
@@ -14,9 +14,11 @@ This packlet is largely AI written, and it shows.
|
|
|
14
14
|
- **🔄 Resource Management**: Import, process, and manage ts-res configurations and bundles
|
|
15
15
|
- **🔍 Advanced Filtering**: Filter resources by context with qualifier reduction
|
|
16
16
|
- **🎯 Resource Resolution**: Test resource resolution with dynamic context values
|
|
17
|
+
- **➕ Resource Creation**: Create new resources with pending/apply workflow and template support
|
|
17
18
|
- **🔒 View Mode Locking**: Lock to single view mode for simplified interfaces
|
|
18
19
|
- **📊 Visualization**: Multiple views for exploring resource structures and compiled output
|
|
19
20
|
- **⚙️ Configuration**: Visual configuration management for qualifier types, qualifiers, and resource types
|
|
21
|
+
- **🎛️ Host Control**: Programmatic control of qualifier values and resource types
|
|
20
22
|
- **📁 File Handling**: Support for directory imports, ZIP files via ts-res zip-archive packlet, and bundle loading
|
|
21
23
|
- **🎨 Modern UI**: Built with Tailwind CSS and Heroicons for a clean, responsive interface
|
|
22
24
|
|
|
@@ -364,7 +366,7 @@ Shows the compiled resource structure with detailed candidate information using
|
|
|
364
366
|
|
|
365
367
|
### ResolutionView
|
|
366
368
|
|
|
367
|
-
Interactive resource resolution testing with context management and support for custom resource editors via the ResourceEditorFactory pattern. Supports locking to a single view mode to simplify the interface for specific use cases.
|
|
369
|
+
Interactive resource resolution testing with context management and support for custom resource editors via the ResourceEditorFactory pattern. Supports locking to a single view mode to simplify the interface for specific use cases. Now includes host-controlled resolution support for programmatic qualifier value management and the ability to create new resources with a pending/apply workflow.
|
|
368
370
|
|
|
369
371
|
> 📚 **[See ResolutionView documentation →](./docs/ts-res-ui-components.resolutionview.md)**
|
|
370
372
|
|
|
@@ -381,9 +383,144 @@ Interactive resource resolution testing with context management and support for
|
|
|
381
383
|
enableSearch: true,
|
|
382
384
|
searchPlaceholder: "Search resources for resolution testing..."
|
|
383
385
|
}}
|
|
386
|
+
// Optional: Host-controlled resolution
|
|
387
|
+
contextOptions={{
|
|
388
|
+
hostManagedValues: {
|
|
389
|
+
language: 'en-US',
|
|
390
|
+
platform: 'web',
|
|
391
|
+
market: 'eastern-europe'
|
|
392
|
+
},
|
|
393
|
+
showContextControls: true // Can hide controls for host-only resolution
|
|
394
|
+
}}
|
|
395
|
+
// Optional: Resource creation with pending/apply workflow
|
|
396
|
+
allowResourceCreation={true}
|
|
397
|
+
defaultResourceType="json" // Optional: Host-controlled resource type
|
|
398
|
+
showPendingResourcesInList={true} // Show pending resources in the picker (default: true)
|
|
399
|
+
onPendingResourcesApplied={(added, deleted) => {
|
|
400
|
+
console.log(`Applied ${added.length} new resources, ${deleted.length} deletions`);
|
|
401
|
+
}}
|
|
384
402
|
/>
|
|
385
403
|
```
|
|
386
404
|
|
|
405
|
+
#### Host-Controlled Resolution
|
|
406
|
+
|
|
407
|
+
The ResolutionView now supports a three-layer context system that allows host applications to programmatically control qualifier values while still allowing user interaction:
|
|
408
|
+
|
|
409
|
+
1. **Host-Managed Values**: Values controlled by the host application that are applied automatically
|
|
410
|
+
2. **Applied User Values**: User values that have been explicitly applied via the "Apply Changes" button
|
|
411
|
+
3. **Pending User Values**: User edits that haven't been applied yet
|
|
412
|
+
|
|
413
|
+
This is particularly useful when:
|
|
414
|
+
- The UI needs to be hidden but resolution still needs to work
|
|
415
|
+
- Certain qualifier values should be controlled by the application logic
|
|
416
|
+
- You want to provide default values that users can optionally override
|
|
417
|
+
|
|
418
|
+
```tsx
|
|
419
|
+
// Example: Host-controlled resolution with hidden UI
|
|
420
|
+
<ResolutionView
|
|
421
|
+
resources={state.processedResources}
|
|
422
|
+
resolutionState={resolutionState}
|
|
423
|
+
resolutionActions={resolutionActions}
|
|
424
|
+
availableQualifiers={['language', 'platform', 'market']}
|
|
425
|
+
contextOptions={{
|
|
426
|
+
hostManagedValues: {
|
|
427
|
+
language: userProfile.language,
|
|
428
|
+
platform: detectPlatform(),
|
|
429
|
+
market: userProfile.region
|
|
430
|
+
},
|
|
431
|
+
showContextControls: false, // Hide the context controls
|
|
432
|
+
qualifierOptions: {
|
|
433
|
+
language: { visible: false }, // Hide specific qualifiers
|
|
434
|
+
platform: { visible: false }
|
|
435
|
+
}
|
|
436
|
+
}}
|
|
437
|
+
/>
|
|
438
|
+
|
|
439
|
+
// Example: Mixed host and user control
|
|
440
|
+
<ResolutionView
|
|
441
|
+
resources={state.processedResources}
|
|
442
|
+
resolutionState={resolutionState}
|
|
443
|
+
resolutionActions={resolutionActions}
|
|
444
|
+
availableQualifiers={availableQualifiers}
|
|
445
|
+
contextOptions={{
|
|
446
|
+
hostManagedValues: {
|
|
447
|
+
platform: 'web' // Platform is always controlled by host
|
|
448
|
+
},
|
|
449
|
+
qualifierOptions: {
|
|
450
|
+
platform: {
|
|
451
|
+
visible: true,
|
|
452
|
+
hostValue: 'web', // Shows as read-only in UI
|
|
453
|
+
disabled: true
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}}
|
|
457
|
+
/>
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
**Key features of host-controlled resolution:**
|
|
461
|
+
- Host values are applied automatically when they change
|
|
462
|
+
- User values require explicit "Apply Changes" action
|
|
463
|
+
- Host values override user values when both are set
|
|
464
|
+
- Flexible UI control - can hide all controls, specific qualifiers, or show as read-only
|
|
465
|
+
- Works seamlessly with the existing resolution state management
|
|
466
|
+
|
|
467
|
+
#### Resource Creation
|
|
468
|
+
|
|
469
|
+
ResolutionView now supports creating new resources directly in the UI with a pending/apply workflow similar to context management:
|
|
470
|
+
|
|
471
|
+
```tsx
|
|
472
|
+
// Basic resource creation - user selects resource type
|
|
473
|
+
<ResolutionView
|
|
474
|
+
resources={state.processedResources}
|
|
475
|
+
resolutionState={resolutionState}
|
|
476
|
+
resolutionActions={resolutionActions}
|
|
477
|
+
allowResourceCreation={true}
|
|
478
|
+
onPendingResourcesApplied={(added, deleted) => {
|
|
479
|
+
// Rebuild resource manager with new resources
|
|
480
|
+
const updatedResources = rebuildWithResources(added, deleted);
|
|
481
|
+
setState({ processedResources: updatedResources });
|
|
482
|
+
}}
|
|
483
|
+
/>
|
|
484
|
+
|
|
485
|
+
// Host-controlled resource type
|
|
486
|
+
<ResolutionView
|
|
487
|
+
resources={state.processedResources}
|
|
488
|
+
resolutionState={resolutionState}
|
|
489
|
+
resolutionActions={resolutionActions}
|
|
490
|
+
allowResourceCreation={true}
|
|
491
|
+
defaultResourceType="json" // Type selector hidden, always creates JSON resources
|
|
492
|
+
onPendingResourcesApplied={(added, deleted) => {
|
|
493
|
+
console.log(`Applied ${added.length} additions, ${deleted.length} deletions`);
|
|
494
|
+
}}
|
|
495
|
+
/>
|
|
496
|
+
|
|
497
|
+
// With custom resource types
|
|
498
|
+
<ResolutionView
|
|
499
|
+
resources={state.processedResources}
|
|
500
|
+
resolutionState={resolutionState}
|
|
501
|
+
resolutionActions={resolutionActions}
|
|
502
|
+
allowResourceCreation={true}
|
|
503
|
+
resourceTypeFactory={[customType1, customType2]} // Provide custom resource types
|
|
504
|
+
showPendingResourcesInList={true} // Show pending resources with visual distinction
|
|
505
|
+
/>
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
**Unified Change Workflow (Edits, Additions, Deletions):**
|
|
509
|
+
1. Click "Add Resource" in the picker header to create new resources (if enabled)
|
|
510
|
+
2. Edit existing resources from the results pane using the JSON or custom editors
|
|
511
|
+
3. Mark resources for deletion where supported
|
|
512
|
+
4. All changes appear in a single "Pending Changes" bar with counts (edits/additions/deletions)
|
|
513
|
+
5. Click "Apply Changes" to commit everything in one atomic rebuild
|
|
514
|
+
6. Or click "Discard Changes" to remove all pending changes
|
|
515
|
+
|
|
516
|
+
**Key features:**
|
|
517
|
+
- **Template-based creation**: Resource types provide default templates for new resources
|
|
518
|
+
- **Pending workflow**: Resources aren't added immediately, allowing review before applying
|
|
519
|
+
- **Host control**: Can specify a default resource type to hide the type selector
|
|
520
|
+
- **Batch operations**: Create multiple resources before applying
|
|
521
|
+
- **Visual feedback**: Pending resources shown with distinct styling
|
|
522
|
+
- **Validation**: Resource IDs are validated for uniqueness
|
|
523
|
+
|
|
387
524
|
#### Custom Resource Editors
|
|
388
525
|
|
|
389
526
|
The ResolutionView supports custom editors for specific resource types through the `ResourceEditorFactory` interface:
|
package/config/jest.setup.js
CHANGED
|
@@ -677,7 +677,7 @@ declare function createTsResSystemFromConfig(systemConfig?: Config.Model.ISystem
|
|
|
677
677
|
* }}
|
|
678
678
|
* />
|
|
679
679
|
*
|
|
680
|
-
* <ResolutionTools.
|
|
680
|
+
* <ResolutionTools.UnifiedChangeControls
|
|
681
681
|
* editCount={state.editedResources.size}
|
|
682
682
|
* isApplying={state.isApplyingEdits}
|
|
683
683
|
* hasEdits={state.hasUnsavedEdits}
|
|
@@ -2135,6 +2135,15 @@ export declare interface OrchestratorActions {
|
|
|
2135
2135
|
clearResourceEdits: () => void;
|
|
2136
2136
|
applyResourceEdits: () => Promise<void>;
|
|
2137
2137
|
discardResourceEdits: () => void;
|
|
2138
|
+
startNewResource: (defaultTypeName?: string) => void;
|
|
2139
|
+
updateNewResourceId: (id: string) => void;
|
|
2140
|
+
selectResourceType: (type: string) => void;
|
|
2141
|
+
saveNewResourceAsPending: () => void;
|
|
2142
|
+
cancelNewResource: () => void;
|
|
2143
|
+
removePendingResource: (resourceId: string) => void;
|
|
2144
|
+
markResourceForDeletion: (resourceId: string) => void;
|
|
2145
|
+
applyPendingResources: () => Promise<void>;
|
|
2146
|
+
discardPendingResources: () => void;
|
|
2138
2147
|
selectResource: (resourceId: string | null) => void;
|
|
2139
2148
|
addMessage: (type: Message['type'], message: string) => void;
|
|
2140
2149
|
clearMessages: () => void;
|
|
@@ -2800,8 +2809,8 @@ declare function readFilesFromInput(files: FileList): Promise<ImportedFile[]>;
|
|
|
2800
2809
|
declare interface ResolutionActions {
|
|
2801
2810
|
/** Update a context value for resolution testing */
|
|
2802
2811
|
updateContextValue: (qualifierName: string, value: string | undefined) => void;
|
|
2803
|
-
/** Apply pending context changes to the resolver */
|
|
2804
|
-
applyContext: () => void;
|
|
2812
|
+
/** Apply pending context changes to the resolver (with optional host-managed values) */
|
|
2813
|
+
applyContext: (hostManagedValues?: Record<string, string | undefined>) => void;
|
|
2805
2814
|
/** Select a resource for detailed resolution testing */
|
|
2806
2815
|
selectResource: (resourceId: string) => void;
|
|
2807
2816
|
/** Change how resolution results are displayed */
|
|
@@ -2820,6 +2829,24 @@ declare interface ResolutionActions {
|
|
|
2820
2829
|
applyEdits: () => Promise<void>;
|
|
2821
2830
|
/** Discard all pending edits */
|
|
2822
2831
|
discardEdits: () => void;
|
|
2832
|
+
/** Start creating a new resource */
|
|
2833
|
+
startNewResource: (defaultTypeName?: string) => void;
|
|
2834
|
+
/** Update the resource ID for the new resource being created */
|
|
2835
|
+
updateNewResourceId: (id: string) => void;
|
|
2836
|
+
/** Select a resource type for the new resource */
|
|
2837
|
+
selectResourceType: (type: string) => void;
|
|
2838
|
+
/** Add the new resource to pending resources (not applied yet) */
|
|
2839
|
+
saveNewResourceAsPending: () => void;
|
|
2840
|
+
/** Cancel the new resource creation */
|
|
2841
|
+
cancelNewResource: () => void;
|
|
2842
|
+
/** Remove a pending resource */
|
|
2843
|
+
removePendingResource: (resourceId: string) => void;
|
|
2844
|
+
/** Mark an existing resource for deletion */
|
|
2845
|
+
markResourceForDeletion: (resourceId: string) => void;
|
|
2846
|
+
/** Apply all pending resource additions and deletions */
|
|
2847
|
+
applyPendingResources: () => Promise<void>;
|
|
2848
|
+
/** Discard all pending resource changes */
|
|
2849
|
+
discardPendingResources: () => void;
|
|
2823
2850
|
}
|
|
2824
2851
|
|
|
2825
2852
|
/**
|
|
@@ -2934,158 +2961,14 @@ declare interface ResolutionContextOptionsControlProps {
|
|
|
2934
2961
|
className?: string;
|
|
2935
2962
|
/** Title for the control section */
|
|
2936
2963
|
title?: string;
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
/**
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
* to prevent accidental data loss.
|
|
2946
|
-
*
|
|
2947
|
-
* @example
|
|
2948
|
-
* ```tsx
|
|
2949
|
-
* import { ResolutionTools } from '@fgv/ts-res-ui-components';
|
|
2950
|
-
*
|
|
2951
|
-
* // Basic usage with resolution state
|
|
2952
|
-
* const ResolutionInterface = () => {
|
|
2953
|
-
* const { state, actions } = useResolutionState(processedResources);
|
|
2954
|
-
*
|
|
2955
|
-
* return (
|
|
2956
|
-
* <div>
|
|
2957
|
-
* <ResolutionTools.ResolutionEditControls
|
|
2958
|
-
* editCount={state.editedResources.size}
|
|
2959
|
-
* isApplying={state.isApplyingEdits}
|
|
2960
|
-
* hasEdits={state.hasUnsavedEdits}
|
|
2961
|
-
* onApplyEdits={actions.applyEdits}
|
|
2962
|
-
* onDiscardEdits={actions.discardEdits}
|
|
2963
|
-
* />
|
|
2964
|
-
* </div>
|
|
2965
|
-
* );
|
|
2966
|
-
* };
|
|
2967
|
-
* ```
|
|
2968
|
-
*
|
|
2969
|
-
* @example
|
|
2970
|
-
* ```tsx
|
|
2971
|
-
* // Advanced usage with custom handlers and state management
|
|
2972
|
-
* const AdvancedResolutionEditor = () => {
|
|
2973
|
-
* const [edits, setEdits] = useState(new Map());
|
|
2974
|
-
* const [isApplying, setIsApplying] = useState(false);
|
|
2975
|
-
*
|
|
2976
|
-
* const handleApplyEdits = async () => {
|
|
2977
|
-
* setIsApplying(true);
|
|
2978
|
-
* try {
|
|
2979
|
-
* // Apply each edit to the resource system
|
|
2980
|
-
* for (const [resourceId, editedValue] of edits.entries()) {
|
|
2981
|
-
* await applyResourceEdit(resourceId, editedValue);
|
|
2982
|
-
* }
|
|
2983
|
-
*
|
|
2984
|
-
* // Rebuild the resource system
|
|
2985
|
-
* await rebuildResourceSystem();
|
|
2986
|
-
*
|
|
2987
|
-
* // Clear edits after successful application
|
|
2988
|
-
* setEdits(new Map());
|
|
2989
|
-
* showSuccess('Edits applied successfully');
|
|
2990
|
-
* } catch (error) {
|
|
2991
|
-
* showError(`Failed to apply edits: ${error.message}`);
|
|
2992
|
-
* } finally {
|
|
2993
|
-
* setIsApplying(false);
|
|
2994
|
-
* }
|
|
2995
|
-
* };
|
|
2996
|
-
*
|
|
2997
|
-
* const handleDiscardEdits = () => {
|
|
2998
|
-
* setEdits(new Map());
|
|
2999
|
-
* showInfo('All pending edits discarded');
|
|
3000
|
-
* };
|
|
3001
|
-
*
|
|
3002
|
-
* return (
|
|
3003
|
-
* <ResolutionTools.ResolutionEditControls
|
|
3004
|
-
* editCount={edits.size}
|
|
3005
|
-
* isApplying={isApplying}
|
|
3006
|
-
* hasEdits={edits.size > 0}
|
|
3007
|
-
* onApplyEdits={handleApplyEdits}
|
|
3008
|
-
* onDiscardEdits={handleDiscardEdits}
|
|
3009
|
-
* className="my-custom-controls"
|
|
3010
|
-
* />
|
|
3011
|
-
* );
|
|
3012
|
-
* };
|
|
3013
|
-
* ```
|
|
3014
|
-
*
|
|
3015
|
-
* @example
|
|
3016
|
-
* ```tsx
|
|
3017
|
-
* // Integration with resource editing workflow
|
|
3018
|
-
* const ResourceEditingWorkflow = () => {
|
|
3019
|
-
* const [selectedResource, setSelectedResource] = useState(null);
|
|
3020
|
-
* const [pendingEdits, setPendingEdits] = useState({});
|
|
3021
|
-
*
|
|
3022
|
-
* const saveResourceEdit = (resourceId, editedValue, originalValue) => {
|
|
3023
|
-
* setPendingEdits(prev => ({
|
|
3024
|
-
* ...prev,
|
|
3025
|
-
* [resourceId]: { editedValue, originalValue, timestamp: new Date() }
|
|
3026
|
-
* }));
|
|
3027
|
-
* };
|
|
3028
|
-
*
|
|
3029
|
-
* const applyAllEdits = async () => {
|
|
3030
|
-
* const resourceManager = getResourceManager();
|
|
3031
|
-
*
|
|
3032
|
-
* // Apply edits as new candidates with current context
|
|
3033
|
-
* for (const [resourceId, edit] of Object.entries(pendingEdits)) {
|
|
3034
|
-
* await resourceManager.addCandidate(resourceId, {
|
|
3035
|
-
* value: edit.editedValue,
|
|
3036
|
-
* conditions: getCurrentResolutionContext(),
|
|
3037
|
-
* metadata: { editedAt: edit.timestamp }
|
|
3038
|
-
* });
|
|
3039
|
-
* }
|
|
3040
|
-
*
|
|
3041
|
-
* // Clear pending edits
|
|
3042
|
-
* setPendingEdits({});
|
|
3043
|
-
* };
|
|
3044
|
-
*
|
|
3045
|
-
* return (
|
|
3046
|
-
* <div className="resolution-workflow">
|
|
3047
|
-
* <ResolutionTools.EditableJsonView
|
|
3048
|
-
* resourceId={selectedResource}
|
|
3049
|
-
* value={getResourceValue(selectedResource)}
|
|
3050
|
-
* onSave={saveResourceEdit}
|
|
3051
|
-
* />
|
|
3052
|
-
*
|
|
3053
|
-
* <ResolutionTools.ResolutionEditControls
|
|
3054
|
-
* editCount={Object.keys(pendingEdits).length}
|
|
3055
|
-
* isApplying={false}
|
|
3056
|
-
* hasEdits={Object.keys(pendingEdits).length > 0}
|
|
3057
|
-
* onApplyEdits={applyAllEdits}
|
|
3058
|
-
* onDiscardEdits={() => setPendingEdits({})}
|
|
3059
|
-
* />
|
|
3060
|
-
* </div>
|
|
3061
|
-
* );
|
|
3062
|
-
* };
|
|
3063
|
-
* ```
|
|
3064
|
-
*
|
|
3065
|
-
* @public
|
|
3066
|
-
*/
|
|
3067
|
-
declare const ResolutionEditControls: React_2.FC<ResolutionEditControlsProps>;
|
|
3068
|
-
|
|
3069
|
-
/**
|
|
3070
|
-
* Props for the ResolutionEditControls component.
|
|
3071
|
-
*
|
|
3072
|
-
* @public
|
|
3073
|
-
*/
|
|
3074
|
-
declare interface ResolutionEditControlsProps {
|
|
3075
|
-
/** Number of unsaved edits */
|
|
3076
|
-
editCount: number;
|
|
3077
|
-
/** Whether edit application is currently in progress */
|
|
3078
|
-
isApplying: boolean;
|
|
3079
|
-
/** Whether any edits exist to operate on */
|
|
3080
|
-
hasEdits: boolean;
|
|
3081
|
-
/** Callback to apply all pending edits */
|
|
3082
|
-
onApplyEdits?: () => Promise<void>;
|
|
3083
|
-
/** Callback to discard all pending edits */
|
|
3084
|
-
onDiscardEdits?: () => void;
|
|
3085
|
-
/** Whether the controls should be disabled */
|
|
3086
|
-
disabled?: boolean;
|
|
3087
|
-
/** Additional CSS classes */
|
|
3088
|
-
className?: string;
|
|
2964
|
+
/** Editing/creation toggle - when provided, show UI to control it */
|
|
2965
|
+
allowResourceCreation?: boolean;
|
|
2966
|
+
/** Callback for editing/creation toggle */
|
|
2967
|
+
onAllowResourceCreationChange?: (allow: boolean) => void;
|
|
2968
|
+
/** Pending resources list visibility - when provided, show UI to control it */
|
|
2969
|
+
showPendingResourcesInList?: boolean;
|
|
2970
|
+
/** Callback for pending resources list visibility */
|
|
2971
|
+
onShowPendingResourcesInListChange?: (show: boolean) => void;
|
|
3089
2972
|
}
|
|
3090
2973
|
|
|
3091
2974
|
/**
|
|
@@ -3324,13 +3207,28 @@ declare interface ResolutionState {
|
|
|
3324
3207
|
hasUnsavedEdits: boolean;
|
|
3325
3208
|
/** Whether edits are currently being applied to the system */
|
|
3326
3209
|
isApplyingEdits: boolean;
|
|
3210
|
+
/** Resources waiting to be added to the system */
|
|
3211
|
+
pendingResources: Map<string, ResourceJson.Json.ILooseResourceDecl>;
|
|
3212
|
+
/** IDs of resources marked for deletion */
|
|
3213
|
+
pendingResourceDeletions: Set<string>;
|
|
3214
|
+
/** Draft of a new resource being created */
|
|
3215
|
+
newResourceDraft?: {
|
|
3216
|
+
resourceId: string;
|
|
3217
|
+
resourceType: string;
|
|
3218
|
+
template: ResourceJson.Json.ILooseResourceDecl;
|
|
3219
|
+
isValid: boolean;
|
|
3220
|
+
};
|
|
3221
|
+
/** Available resource types for creation */
|
|
3222
|
+
availableResourceTypes: ResourceTypes.IResourceType[];
|
|
3223
|
+
/** Whether there are pending resource additions or deletions */
|
|
3224
|
+
hasPendingResourceChanges: boolean;
|
|
3327
3225
|
}
|
|
3328
3226
|
|
|
3329
3227
|
export declare namespace ResolutionTools {
|
|
3330
3228
|
export {
|
|
3331
3229
|
ResolutionView,
|
|
3332
3230
|
EditableJsonView,
|
|
3333
|
-
|
|
3231
|
+
UnifiedChangeControls,
|
|
3334
3232
|
QualifierContextControl,
|
|
3335
3233
|
ResolutionContextOptionsControl,
|
|
3336
3234
|
useResolutionState,
|
|
@@ -3439,6 +3337,16 @@ declare interface ResolutionViewProps extends ViewBaseProps {
|
|
|
3439
3337
|
/** Title for the results section (default: "Results") */
|
|
3440
3338
|
results?: string;
|
|
3441
3339
|
};
|
|
3340
|
+
/** Allow creating new resources in the UI */
|
|
3341
|
+
allowResourceCreation?: boolean;
|
|
3342
|
+
/** Default resource type for new resources (hides type selector if provided) */
|
|
3343
|
+
defaultResourceType?: string;
|
|
3344
|
+
/** Factory for creating custom resource types */
|
|
3345
|
+
resourceTypeFactory?: ResourceTypes.IResourceType[];
|
|
3346
|
+
/** Callback when pending resources are applied */
|
|
3347
|
+
onPendingResourcesApplied?: (added: ResourceJson.Json.ILooseResourceDecl[], deleted: string[]) => void;
|
|
3348
|
+
/** Show pending resources in the resource list with visual distinction */
|
|
3349
|
+
showPendingResourcesInList?: boolean;
|
|
3442
3350
|
}
|
|
3443
3351
|
|
|
3444
3352
|
/**
|
|
@@ -4619,6 +4527,58 @@ export declare namespace TsResTools {
|
|
|
4619
4527
|
}
|
|
4620
4528
|
}
|
|
4621
4529
|
|
|
4530
|
+
/**
|
|
4531
|
+
* Unified change controls for ResolutionView.
|
|
4532
|
+
*
|
|
4533
|
+
* @example
|
|
4534
|
+
* ```tsx
|
|
4535
|
+
* <UnifiedChangeControls
|
|
4536
|
+
* editCount={state.editedResources.size}
|
|
4537
|
+
* addCount={state.pendingResources.size}
|
|
4538
|
+
* deleteCount={state.pendingResourceDeletions.size}
|
|
4539
|
+
* isApplying={state.isApplyingEdits}
|
|
4540
|
+
* disabled={!state.currentResolver}
|
|
4541
|
+
* onApplyAll={actions.applyPendingResources}
|
|
4542
|
+
* onDiscardAll={() => {
|
|
4543
|
+
* actions.discardEdits();
|
|
4544
|
+
* actions.discardPendingResources();
|
|
4545
|
+
* }}
|
|
4546
|
+
* />
|
|
4547
|
+
* ```
|
|
4548
|
+
*
|
|
4549
|
+
* @public
|
|
4550
|
+
*/
|
|
4551
|
+
declare const UnifiedChangeControls: React_2.FC<UnifiedChangeControlsProps>;
|
|
4552
|
+
|
|
4553
|
+
/**
|
|
4554
|
+
* Unified control bar that summarizes all pending changes (edits, additions, deletions)
|
|
4555
|
+
* and provides a single Apply/Discard action.
|
|
4556
|
+
*
|
|
4557
|
+
* Renders chips for the counts of pending edits, additions, and deletions. The Apply button
|
|
4558
|
+
* should commit all pending changes atomically (via a system rebuild), and Discard clears all
|
|
4559
|
+
* pending change buffers. This replaces older separate controls for edits and resource creation.
|
|
4560
|
+
*
|
|
4561
|
+
* @public
|
|
4562
|
+
*/
|
|
4563
|
+
declare interface UnifiedChangeControlsProps {
|
|
4564
|
+
/** Number of pending edits to existing resources */
|
|
4565
|
+
editCount: number;
|
|
4566
|
+
/** Number of pending new resources to be added */
|
|
4567
|
+
addCount: number;
|
|
4568
|
+
/** Number of resources marked for deletion */
|
|
4569
|
+
deleteCount: number;
|
|
4570
|
+
/** Whether an apply operation is in progress (shows spinner and disables buttons) */
|
|
4571
|
+
isApplying?: boolean;
|
|
4572
|
+
/** Disable all actions (e.g., when no resolver/context is active) */
|
|
4573
|
+
disabled?: boolean;
|
|
4574
|
+
/** Optional CSS class names to attach to the container */
|
|
4575
|
+
className?: string;
|
|
4576
|
+
/** Apply all pending changes in one step (typically triggers rebuild) */
|
|
4577
|
+
onApplyAll: () => Promise<void> | void;
|
|
4578
|
+
/** Discard all pending changes (edits, additions, deletions) */
|
|
4579
|
+
onDiscardAll: () => void;
|
|
4580
|
+
}
|
|
4581
|
+
|
|
4622
4582
|
/**
|
|
4623
4583
|
* Hook for managing system configuration state including qualifiers, qualifier types, and resource types.
|
|
4624
4584
|
*
|
|
@@ -192,9 +192,11 @@ export const QualifierContextControl = ({ qualifierName, value, onChange, disabl
|
|
|
192
192
|
}
|
|
193
193
|
return (React.createElement("div", { className: `bg-white rounded border border-gray-200 p-2 ${className} ${customClassName}` },
|
|
194
194
|
React.createElement("div", { className: "flex items-center gap-2" },
|
|
195
|
-
React.createElement("label", { className: "text-sm font-medium text-gray-700 min-w-0 flex-shrink-0" },
|
|
195
|
+
React.createElement("label", { className: "text-sm font-medium text-gray-700 min-w-0 flex-shrink-0 flex items-center gap-1" },
|
|
196
196
|
qualifierName,
|
|
197
|
-
":"
|
|
197
|
+
":",
|
|
198
|
+
isHostManaged && showHostValue && (React.createElement("span", { className: "text-[10px] px-1 py-0.5 rounded bg-blue-100 text-blue-700", title: "Host-managed value" }, "HOST")),
|
|
199
|
+
!isHostManaged && !isEditable && (React.createElement("span", { className: "text-[10px] px-1 py-0.5 rounded bg-gray-200 text-gray-700", title: "Locked by host or configuration" }, "LOCKED"))),
|
|
198
200
|
React.createElement("div", { className: "flex-1 flex items-center gap-1" },
|
|
199
201
|
hasEnumeratedValues ? (
|
|
200
202
|
// Dropdown for enumerated values
|
|
@@ -17,6 +17,14 @@ export interface ResolutionContextOptionsControlProps {
|
|
|
17
17
|
className?: string;
|
|
18
18
|
/** Title for the control section */
|
|
19
19
|
title?: string;
|
|
20
|
+
/** Editing/creation toggle - when provided, show UI to control it */
|
|
21
|
+
allowResourceCreation?: boolean;
|
|
22
|
+
/** Callback for editing/creation toggle */
|
|
23
|
+
onAllowResourceCreationChange?: (allow: boolean) => void;
|
|
24
|
+
/** Pending resources list visibility - when provided, show UI to control it */
|
|
25
|
+
showPendingResourcesInList?: boolean;
|
|
26
|
+
/** Callback for pending resources list visibility */
|
|
27
|
+
onShowPendingResourcesInListChange?: (show: boolean) => void;
|
|
20
28
|
}
|
|
21
29
|
/**
|
|
22
30
|
* Reusable control for configuring ResolutionView context options.
|
|
@@ -36,7 +36,7 @@ import { CogIcon, ChevronDownIcon, ChevronUpIcon, XMarkIcon } from '@heroicons/r
|
|
|
36
36
|
*
|
|
37
37
|
* @public
|
|
38
38
|
*/
|
|
39
|
-
export const ResolutionContextOptionsControl = ({ options, onOptionsChange, availableQualifiers = [], presentation = 'hidden', className = '', title = 'Context Options' }) => {
|
|
39
|
+
export const ResolutionContextOptionsControl = ({ options, onOptionsChange, availableQualifiers = [], presentation = 'hidden', className = '', title = 'Context Options', allowResourceCreation, onAllowResourceCreationChange, showPendingResourcesInList, onShowPendingResourcesInListChange }) => {
|
|
40
40
|
// Early return for hidden presentation
|
|
41
41
|
if (presentation === 'hidden') {
|
|
42
42
|
return null;
|
|
@@ -105,6 +105,14 @@ export const ResolutionContextOptionsControl = ({ options, onOptionsChange, avai
|
|
|
105
105
|
"Use ",
|
|
106
106
|
'{qualifierName}',
|
|
107
107
|
" for dynamic qualifier names"))),
|
|
108
|
+
(allowResourceCreation !== undefined || showPendingResourcesInList !== undefined) && (React.createElement("div", { className: "space-y-3 pt-3 border-t border-gray-200" },
|
|
109
|
+
React.createElement("h4", { className: "text-sm font-medium text-gray-700" }, "Editing & Creation"),
|
|
110
|
+
allowResourceCreation !== undefined && (React.createElement("label", { className: "flex items-center text-xs" },
|
|
111
|
+
React.createElement("input", { type: "checkbox", checked: !!allowResourceCreation, onChange: (e) => onAllowResourceCreationChange?.(e.target.checked), className: "mr-2 rounded" }),
|
|
112
|
+
"Allow Resource Creation")),
|
|
113
|
+
showPendingResourcesInList !== undefined && (React.createElement("label", { className: "flex items-center text-xs" },
|
|
114
|
+
React.createElement("input", { type: "checkbox", checked: !!showPendingResourcesInList, onChange: (e) => onShowPendingResourcesInListChange?.(e.target.checked), className: "mr-2 rounded" }),
|
|
115
|
+
"Show Pending Resources In List")))),
|
|
108
116
|
availableQualifiers.length > 0 && (React.createElement("div", { className: "space-y-3 pt-3 border-t border-gray-200" },
|
|
109
117
|
React.createElement("h4", { className: "text-sm font-medium text-gray-700" }, "Per-Qualifier Settings"),
|
|
110
118
|
React.createElement("div", { className: "space-y-3" }, availableQualifiers.map((qualifierName) => {
|
|
@@ -311,6 +311,17 @@ export const ResourceOrchestrator = ({ children, initialConfiguration, qualifier
|
|
|
311
311
|
clearResourceEdits: resolutionData.actions.clearEdits,
|
|
312
312
|
applyResourceEdits: resolutionData.actions.applyEdits,
|
|
313
313
|
discardResourceEdits: resolutionData.actions.discardEdits,
|
|
314
|
+
// Resource creation actions
|
|
315
|
+
startNewResource: resolutionData.actions.startNewResource,
|
|
316
|
+
updateNewResourceId: resolutionData.actions.updateNewResourceId,
|
|
317
|
+
selectResourceType: resolutionData.actions.selectResourceType,
|
|
318
|
+
saveNewResourceAsPending: resolutionData.actions.saveNewResourceAsPending,
|
|
319
|
+
cancelNewResource: resolutionData.actions.cancelNewResource,
|
|
320
|
+
removePendingResource: resolutionData.actions.removePendingResource,
|
|
321
|
+
markResourceForDeletion: resolutionData.actions.markResourceForDeletion,
|
|
322
|
+
applyPendingResources: resolutionData.actions.applyPendingResources,
|
|
323
|
+
discardPendingResources: resolutionData.actions.discardPendingResources,
|
|
324
|
+
// Combined apply/discard removed; use applyPendingResources/discard* directly
|
|
314
325
|
// UI state management
|
|
315
326
|
selectResource: viewState.selectResource,
|
|
316
327
|
addMessage: viewState.addMessage,
|
|
@@ -172,7 +172,7 @@ export interface EditableJsonViewProps {
|
|
|
172
172
|
* }}
|
|
173
173
|
* />
|
|
174
174
|
*
|
|
175
|
-
* <ResolutionTools.
|
|
175
|
+
* <ResolutionTools.UnifiedChangeControls
|
|
176
176
|
* editCount={state.editedResources.size}
|
|
177
177
|
* isApplying={state.isApplyingEdits}
|
|
178
178
|
* hasEdits={state.hasUnsavedEdits}
|
|
@@ -152,7 +152,7 @@ import { validateEditedResource } from '../../../utils/resolutionEditing';
|
|
|
152
152
|
* }}
|
|
153
153
|
* />
|
|
154
154
|
*
|
|
155
|
-
* <ResolutionTools.
|
|
155
|
+
* <ResolutionTools.UnifiedChangeControls
|
|
156
156
|
* editCount={state.editedResources.size}
|
|
157
157
|
* isApplying={state.isApplyingEdits}
|
|
158
158
|
* hasEdits={state.hasUnsavedEdits}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ResourceTypes } from '@fgv/ts-res';
|
|
3
|
+
interface NewResourceModalProps {
|
|
4
|
+
isOpen: boolean;
|
|
5
|
+
onClose: () => void;
|
|
6
|
+
resourceId: string;
|
|
7
|
+
resourceType: string;
|
|
8
|
+
availableResourceTypes: ResourceTypes.IResourceType[];
|
|
9
|
+
isValid: boolean;
|
|
10
|
+
defaultResourceType?: string;
|
|
11
|
+
onUpdateResourceId: (id: string) => void;
|
|
12
|
+
onSelectResourceType: (type: string) => void;
|
|
13
|
+
onSave: () => void;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Modal dialog for creating new resources with type selection and ID input.
|
|
17
|
+
* Supports host-controlled resource types that hide the type selector.
|
|
18
|
+
*/
|
|
19
|
+
export declare const NewResourceModal: React.FC<NewResourceModalProps>;
|
|
20
|
+
export default NewResourceModal;
|
|
21
|
+
//# sourceMappingURL=NewResourceModal.d.ts.map
|