@fgv/ts-res-ui-components 5.0.0-18 → 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.
Files changed (72) hide show
  1. package/README.md +404 -1
  2. package/config/jest.setup.js +3 -0
  3. package/dist/ts-res-ui-components.d.ts +338 -136
  4. package/lib/components/common/QualifierContextControl.d.ts +59 -1
  5. package/lib/components/common/QualifierContextControl.js +105 -19
  6. package/lib/components/common/ResolutionContextOptionsControl.d.ts +67 -0
  7. package/lib/components/common/ResolutionContextOptionsControl.js +190 -0
  8. package/lib/components/orchestrator/ResourceOrchestrator.d.ts +5 -1
  9. package/lib/components/orchestrator/ResourceOrchestrator.js +16 -2
  10. package/lib/components/views/FilterView/index.js +56 -11
  11. package/lib/components/views/ResolutionView/EditableJsonView.d.ts +1 -1
  12. package/lib/components/views/ResolutionView/EditableJsonView.js +1 -1
  13. package/lib/components/views/ResolutionView/NewResourceModal.d.ts +21 -0
  14. package/lib/components/views/ResolutionView/NewResourceModal.js +60 -0
  15. package/lib/components/views/ResolutionView/UnifiedChangeControls.d.ts +53 -0
  16. package/lib/components/views/ResolutionView/UnifiedChangeControls.js +71 -0
  17. package/lib/components/views/ResolutionView/index.js +240 -38
  18. package/lib/hooks/useResolutionState.js +510 -60
  19. package/lib/hooks/useResourceData.d.ts +14 -2
  20. package/lib/hooks/useResourceData.js +24 -34
  21. package/lib/index.js +1 -1
  22. package/lib/namespaces/ResolutionTools.d.ts +4 -2
  23. package/lib/namespaces/ResolutionTools.js +2 -1
  24. package/lib/test/unit/components/ResolutionView.unified.test.d.ts +2 -0
  25. package/lib/test/unit/hooks/useResolutionState.context.test.d.ts +2 -0
  26. package/lib/types/index.d.ts +158 -2
  27. package/lib/utils/configurationUtils.d.ts +4 -4
  28. package/lib/utils/configurationUtils.js +36 -269
  29. package/lib/utils/resolutionEditing.d.ts +17 -0
  30. package/lib/utils/resolutionEditing.js +87 -71
  31. package/lib/utils/tsResIntegration.d.ts +3 -3
  32. package/lib/utils/tsResIntegration.js +9 -6
  33. package/lib/utils/zipLoader/zipProcessingHelpers.js +3 -15
  34. package/lib-commonjs/components/common/QualifierContextControl.js +105 -19
  35. package/lib-commonjs/components/common/ResolutionContextOptionsControl.js +195 -0
  36. package/lib-commonjs/components/orchestrator/ResourceOrchestrator.js +16 -2
  37. package/lib-commonjs/components/views/FilterView/index.js +56 -11
  38. package/lib-commonjs/components/views/ResolutionView/EditableJsonView.js +1 -1
  39. package/lib-commonjs/components/views/ResolutionView/NewResourceModal.js +65 -0
  40. package/lib-commonjs/components/views/ResolutionView/UnifiedChangeControls.js +76 -0
  41. package/lib-commonjs/components/views/ResolutionView/index.js +238 -36
  42. package/lib-commonjs/hooks/useResolutionState.js +509 -59
  43. package/lib-commonjs/hooks/useResourceData.js +24 -34
  44. package/lib-commonjs/index.js +1 -1
  45. package/lib-commonjs/namespaces/ResolutionTools.js +5 -3
  46. package/lib-commonjs/utils/configurationUtils.js +36 -269
  47. package/lib-commonjs/utils/resolutionEditing.js +89 -71
  48. package/lib-commonjs/utils/tsResIntegration.js +9 -6
  49. package/lib-commonjs/utils/zipLoader/zipProcessingHelpers.js +2 -14
  50. package/package.json +11 -7
  51. package/src/components/common/QualifierContextControl.tsx +131 -20
  52. package/src/components/common/ResolutionContextOptionsControl.tsx +450 -0
  53. package/src/components/orchestrator/ResourceOrchestrator.tsx +32 -11
  54. package/src/components/views/FilterView/index.tsx +115 -38
  55. package/src/components/views/ResolutionView/EditableJsonView.tsx +1 -1
  56. package/src/components/views/ResolutionView/NewResourceModal.tsx +158 -0
  57. package/src/components/views/ResolutionView/UnifiedChangeControls.tsx +163 -0
  58. package/src/components/views/ResolutionView/index.tsx +389 -83
  59. package/src/hooks/useConfigurationState.ts +0 -1
  60. package/src/hooks/useResolutionState.ts +627 -89
  61. package/src/hooks/useResourceData.ts +58 -32
  62. package/src/index.ts +1 -1
  63. package/src/namespaces/ResolutionTools.ts +6 -2
  64. package/src/types/index.ts +168 -2
  65. package/src/utils/configurationUtils.ts +38 -276
  66. package/src/utils/resolutionEditing.ts +107 -80
  67. package/src/utils/tsResIntegration.ts +35 -6
  68. package/src/utils/zipLoader/zipProcessingHelpers.ts +6 -12
  69. package/lib/components/views/ResolutionView/ResolutionEditControls.d.ts +0 -152
  70. package/lib/components/views/ResolutionView/ResolutionEditControls.js +0 -210
  71. package/lib-commonjs/components/views/ResolutionView/ResolutionEditControls.js +0 -215
  72. package/src/components/views/ResolutionView/ResolutionEditControls.tsx +0 -303
package/README.md CHANGED
@@ -14,8 +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
18
+ - **🔒 View Mode Locking**: Lock to single view mode for simplified interfaces
17
19
  - **📊 Visualization**: Multiple views for exploring resource structures and compiled output
18
20
  - **⚙️ Configuration**: Visual configuration management for qualifier types, qualifiers, and resource types
21
+ - **🎛️ Host Control**: Programmatic control of qualifier values and resource types
19
22
  - **📁 File Handling**: Support for directory imports, ZIP files via ts-res zip-archive packlet, and bundle loading
20
23
  - **🎨 Modern UI**: Built with Tailwind CSS and Heroicons for a clean, responsive interface
21
24
 
@@ -363,7 +366,7 @@ Shows the compiled resource structure with detailed candidate information using
363
366
 
364
367
  ### ResolutionView
365
368
 
366
- Interactive resource resolution testing with context management and support for custom resource editors via the ResourceEditorFactory pattern.
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.
367
370
 
368
371
  > 📚 **[See ResolutionView documentation →](./docs/ts-res-ui-components.resolutionview.md)**
369
372
 
@@ -380,9 +383,144 @@ Interactive resource resolution testing with context management and support for
380
383
  enableSearch: true,
381
384
  searchPlaceholder: "Search resources for resolution testing..."
382
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
+ }}
402
+ />
403
+ ```
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
383
505
  />
384
506
  ```
385
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
+
386
524
  #### Custom Resource Editors
387
525
 
388
526
  The ResolutionView supports custom editors for specific resource types through the `ResourceEditorFactory` interface:
@@ -442,6 +580,271 @@ const editorFactory = new MyResourceEditorFactory();
442
580
  - **Extensible**: Easy to add new editors for new resource types
443
581
  - **Error Handling**: Factory failures are caught and reported to users
444
582
 
583
+ #### Context Control Extensibility
584
+
585
+ ResolutionView provides comprehensive control over the context configuration UI, allowing hosts to customize which qualifiers are editable, provide external values, and control the presentation. This is especially useful for applications that need to drive context externally or provide selective user control.
586
+
587
+ **Hide Context UI Entirely (Host-Driven Context):**
588
+ ```tsx
589
+ <ResolutionView
590
+ resources={processedResources}
591
+ resolutionState={resolutionState}
592
+ resolutionActions={resolutionActions}
593
+ contextOptions={{
594
+ showContextControls: false // Hide all context UI
595
+ }}
596
+ />
597
+ ```
598
+
599
+ **Lock to Single View Mode:**
600
+ ```tsx
601
+ <ResolutionView
602
+ resources={processedResources}
603
+ resolutionState={resolutionState}
604
+ resolutionActions={resolutionActions}
605
+ lockedViewMode="composed" // Lock to composed view, hide view selector
606
+ />
607
+ ```
608
+
609
+ **Lock to Best View Mode:**
610
+ ```tsx
611
+ <ResolutionView
612
+ resources={processedResources}
613
+ resolutionState={resolutionState}
614
+ resolutionActions={resolutionActions}
615
+ lockedViewMode="best" // Lock to best view, hide view selector
616
+ />
617
+ ```
618
+
619
+ **Custom Section Titles:**
620
+ ```tsx
621
+ <ResolutionView
622
+ resources={processedResources}
623
+ resolutionState={resolutionState}
624
+ resolutionActions={resolutionActions}
625
+ sectionTitles={{
626
+ resources: "Available Items", // Custom title for resources picker
627
+ results: "Resolution Output" // Custom title for results section
628
+ }}
629
+ />
630
+ ```
631
+
632
+ **Fine-Grained Qualifier Control:**
633
+ ```tsx
634
+ <ResolutionView
635
+ resources={processedResources}
636
+ resolutionState={resolutionState}
637
+ resolutionActions={resolutionActions}
638
+ contextOptions={{
639
+ // Panel visibility control
640
+ showContextControls: true,
641
+ showCurrentContext: true,
642
+ showContextActions: true,
643
+
644
+ // Per-qualifier configuration
645
+ qualifierOptions: {
646
+ language: {
647
+ editable: true,
648
+ placeholder: "Select language..."
649
+ },
650
+ platform: {
651
+ editable: false,
652
+ hostValue: "web",
653
+ showHostValue: true
654
+ },
655
+ environment: {
656
+ visible: false // Hidden from UI entirely
657
+ }
658
+ },
659
+
660
+ // Host-managed values (invisible but active in context)
661
+ hostManagedValues: {
662
+ environment: "production",
663
+ deployment: "us-east-1"
664
+ },
665
+
666
+ // Appearance customization
667
+ contextPanelTitle: "Resolution Context",
668
+ globalPlaceholder: "Enter {qualifierName}..."
669
+ }}
670
+ />
671
+ ```
672
+
673
+ **Visual Indicators:**
674
+ - **🔵 Blue border + light blue background** - Host-managed qualifiers have subtle visual styling
675
+ - **🖱️ Hover tooltip** - "Host-managed value - controlled externally" appears on hover
676
+ - **🎯 Actual values displayed** - Shows real host values instead of generic "Disabled" text
677
+ - **📋 Current context** - Displays combined user + host-managed values
678
+
679
+ **Development & Debug Controls:**
680
+ Enable the context options gear icon during development for interactive configuration:
681
+
682
+ ```tsx
683
+ <ResolutionView
684
+ resources={processedResources}
685
+ pickerOptionsPresentation="collapsible" // Shows both picker & context gear icons
686
+ resolutionState={resolutionState}
687
+ resolutionActions={resolutionActions}
688
+ />
689
+ ```
690
+
691
+ The gear icon provides a live configuration interface for:
692
+ - **Context Panel Visibility** - Show/hide controls, current context display, action buttons
693
+ - **Global Defaults** - Set default visibility and editability for all qualifiers
694
+ - **Per-Qualifier Settings** - Configure visibility, editability, host values, and custom placeholders
695
+ - **Host-Managed Values** - Set external values that override user input
696
+
697
+ This extensibility is perfect for:
698
+ - **Embedded applications** where the host drives context from sidebar controls
699
+ - **Guided workflows** where only specific qualifiers should be user-editable
700
+ - **Multi-tenant applications** where some context is determined by tenant configuration
701
+ - **Progressive disclosure** where advanced qualifiers are hidden from basic users
702
+
703
+ ### FilterView
704
+
705
+ Provides context-based resource filtering with candidate count analysis and export functionality.
706
+
707
+ > 📚 **[See FilterView documentation →](./docs/ts-res-ui-components.filterview.md)**
708
+
709
+ ```tsx
710
+ import { FilterView, ResourceTools } from '@fgv/ts-res-ui-components';
711
+
712
+ function MyFilterTool() {
713
+ const { state, actions } = ResourceTools.useResourceData();
714
+
715
+ return (
716
+ <FilterView
717
+ resources={state.resources}
718
+ filterState={state.filterState}
719
+ filterActions={{
720
+ updateFilterEnabled: (enabled) => actions.updateFilterState({ enabled }),
721
+ updateFilterValues: (values) => actions.updateFilterState({ values }),
722
+ applyFilterValues: () => actions.applyFilter(),
723
+ resetFilterValues: () => actions.resetFilter(),
724
+ updateReduceQualifiers: (reduce) => actions.updateFilterState({ reduceQualifiers: reduce })
725
+ }}
726
+ filterResult={state.filterResult}
727
+ onMessage={(type, message) => console.log(`${type}: ${message}`)}
728
+ />
729
+ );
730
+ }
731
+ ```
732
+
733
+ #### FilterView Context Control Extensibility
734
+
735
+ FilterView provides the same comprehensive context control features as ResolutionView, allowing hosts to customize which qualifiers are editable for filtering, provide external values, and control the presentation. This is especially useful for filtering applications that need to drive filter context externally or provide selective user control.
736
+
737
+ **Hide Context UI Entirely (Host-Driven Filtering):**
738
+ ```tsx
739
+ <FilterView
740
+ resources={processedResources}
741
+ filterState={filterState}
742
+ filterActions={filterActions}
743
+ filterResult={filterResult}
744
+ contextOptions={{
745
+ showContextControls: false // Hide all context filter controls
746
+ }}
747
+ />
748
+ ```
749
+
750
+ **Fine-Grained Filter Context Control:**
751
+ ```tsx
752
+ <FilterView
753
+ resources={processedResources}
754
+ filterState={filterState}
755
+ filterActions={filterActions}
756
+ filterResult={filterResult}
757
+ contextOptions={{
758
+ // Panel appearance
759
+ contextPanelTitle: "Filter Criteria",
760
+ globalPlaceholder: "Filter by {qualifierName}...",
761
+
762
+ // Per-qualifier configuration
763
+ qualifierOptions: {
764
+ language: {
765
+ editable: true,
766
+ placeholder: "Filter by language..."
767
+ },
768
+ platform: {
769
+ editable: false,
770
+ hostValue: "web",
771
+ showHostValue: true
772
+ },
773
+ environment: {
774
+ visible: false // Hidden from filter UI entirely
775
+ }
776
+ },
777
+
778
+ // Host-managed filter values (invisible but active in filter context)
779
+ hostManagedValues: {
780
+ environment: "production",
781
+ deployment: "us-east-1"
782
+ },
783
+
784
+ // UI visibility control
785
+ showCurrentContext: true, // Show pending/applied filter summary
786
+ showContextActions: true // Show filter reset/apply buttons
787
+ }}
788
+ />
789
+ ```
790
+
791
+ **Combined with External Filter Logic:**
792
+ ```tsx
793
+ function SmartFilterView() {
794
+ const [externalContext, setExternalContext] = useState({
795
+ userRole: 'admin',
796
+ tenant: 'enterprise'
797
+ });
798
+
799
+ return (
800
+ <FilterView
801
+ resources={processedResources}
802
+ filterState={filterState}
803
+ filterActions={filterActions}
804
+ contextOptions={{
805
+ contextPanelTitle: "Available Filters",
806
+ qualifierOptions: {
807
+ // Hide sensitive qualifiers from basic users
808
+ environment: {
809
+ visible: externalContext.userRole === 'admin'
810
+ },
811
+ // Lock tenant-specific qualifiers
812
+ tenant: {
813
+ editable: false,
814
+ hostValue: externalContext.tenant
815
+ }
816
+ }
817
+ }}
818
+ />
819
+ );
820
+ }
821
+ ```
822
+
823
+ **Development & Debug Controls:**
824
+ Enable the context options gear icon during development for interactive filter configuration:
825
+
826
+ ```tsx
827
+ <FilterView
828
+ resources={processedResources}
829
+ pickerOptionsPresentation="collapsible" // Shows both picker & context gear icons
830
+ filterState={filterState}
831
+ filterActions={filterActions}
832
+ />
833
+ ```
834
+
835
+ The gear icon provides a live configuration interface for:
836
+ - **Context Panel Visibility** - Show/hide filter controls, current context display, action buttons
837
+ - **Global Defaults** - Set default visibility and editability for all filter qualifiers
838
+ - **Per-Qualifier Settings** - Configure visibility, editability, host values, and custom placeholders
839
+ - **Host-Managed Values** - Set external filter values that override user input
840
+
841
+ This filter extensibility is perfect for:
842
+ - **Dashboard applications** where filters are driven from external controls
843
+ - **Multi-tenant systems** where filter options vary by tenant or user role
844
+ - **Guided filter workflows** where only specific criteria should be user-selectable
845
+ - **Advanced/basic user modes** where filter complexity adapts to user expertise
846
+ - **Integration scenarios** where filter context comes from external systems
847
+
445
848
  ### MessagesWindow
446
849
 
447
850
  Displays and manages application messages with filtering, search, and copy functionality. Perfect for debugging interfaces and development tools where message visibility is critical.
@@ -50,6 +50,9 @@ global.URL = {
50
50
  revokeObjectURL: jest.fn()
51
51
  };
52
52
 
53
+ // Extend jest matchers (toBeInTheDocument, etc.)
54
+ require('@testing-library/jest-dom');
55
+
53
56
  // Mock document methods for file export
54
57
  global.document = {
55
58
  createElement: jest.fn(() => ({