@memberjunction/ng-artifacts 6.1.4 → 6.2.0-edge.1

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 (125) hide show
  1. package/dist/lib/components/artifact-message-card.component.d.ts +60 -8
  2. package/dist/lib/components/artifact-message-card.component.d.ts.map +1 -1
  3. package/dist/lib/components/artifact-message-card.component.js +135 -39
  4. package/dist/lib/components/artifact-message-card.component.js.map +1 -1
  5. package/dist/lib/components/artifact-type-plugin-viewer.component.d.ts +58 -6
  6. package/dist/lib/components/artifact-type-plugin-viewer.component.d.ts.map +1 -1
  7. package/dist/lib/components/artifact-type-plugin-viewer.component.js +113 -35
  8. package/dist/lib/components/artifact-type-plugin-viewer.component.js.map +1 -1
  9. package/dist/lib/components/artifact-version-download.d.ts +5 -3
  10. package/dist/lib/components/artifact-version-download.d.ts.map +1 -1
  11. package/dist/lib/components/artifact-version-download.js +11 -7
  12. package/dist/lib/components/artifact-version-download.js.map +1 -1
  13. package/dist/lib/components/artifact-version-history.component.d.ts +74 -8
  14. package/dist/lib/components/artifact-version-history.component.d.ts.map +1 -1
  15. package/dist/lib/components/artifact-version-history.component.js +152 -34
  16. package/dist/lib/components/artifact-version-history.component.js.map +1 -1
  17. package/dist/lib/components/artifact-viewer-panel.component.d.ts +328 -35
  18. package/dist/lib/components/artifact-viewer-panel.component.d.ts.map +1 -1
  19. package/dist/lib/components/artifact-viewer-panel.component.js +701 -213
  20. package/dist/lib/components/artifact-viewer-panel.component.js.map +1 -1
  21. package/dist/lib/components/file-artifact-toolbar.component.d.ts +112 -10
  22. package/dist/lib/components/file-artifact-toolbar.component.d.ts.map +1 -1
  23. package/dist/lib/components/file-artifact-toolbar.component.js +197 -23
  24. package/dist/lib/components/file-artifact-toolbar.component.js.map +1 -1
  25. package/dist/lib/components/plugins/audio-artifact-viewer.component.d.ts +9 -1
  26. package/dist/lib/components/plugins/audio-artifact-viewer.component.d.ts.map +1 -1
  27. package/dist/lib/components/plugins/audio-artifact-viewer.component.js +20 -4
  28. package/dist/lib/components/plugins/audio-artifact-viewer.component.js.map +1 -1
  29. package/dist/lib/components/plugins/code-artifact-viewer.component.d.ts +23 -5
  30. package/dist/lib/components/plugins/code-artifact-viewer.component.d.ts.map +1 -1
  31. package/dist/lib/components/plugins/code-artifact-viewer.component.js +69 -31
  32. package/dist/lib/components/plugins/code-artifact-viewer.component.js.map +1 -1
  33. package/dist/lib/components/plugins/component-artifact-viewer.component.d.ts +136 -18
  34. package/dist/lib/components/plugins/component-artifact-viewer.component.d.ts.map +1 -1
  35. package/dist/lib/components/plugins/component-artifact-viewer.component.js +285 -97
  36. package/dist/lib/components/plugins/component-artifact-viewer.component.js.map +1 -1
  37. package/dist/lib/components/plugins/component-feedback-panel/component-feedback-panel.component.d.ts +2 -2
  38. package/dist/lib/components/plugins/component-feedback-panel/component-feedback-panel.component.js +7 -7
  39. package/dist/lib/components/plugins/component-feedback-panel/component-feedback-panel.component.js.map +1 -1
  40. package/dist/lib/components/plugins/component-permission-evaluation.d.ts +2 -0
  41. package/dist/lib/components/plugins/component-permission-evaluation.d.ts.map +1 -1
  42. package/dist/lib/components/plugins/component-permission-evaluation.js +6 -2
  43. package/dist/lib/components/plugins/component-permission-evaluation.js.map +1 -1
  44. package/dist/lib/components/plugins/data-artifact-viewer.component.d.ts +17 -6
  45. package/dist/lib/components/plugins/data-artifact-viewer.component.d.ts.map +1 -1
  46. package/dist/lib/components/plugins/data-artifact-viewer.component.js +32 -22
  47. package/dist/lib/components/plugins/data-artifact-viewer.component.js.map +1 -1
  48. package/dist/lib/components/plugins/data-requirements-viewer/data-requirements-viewer.component.d.ts +56 -4
  49. package/dist/lib/components/plugins/data-requirements-viewer/data-requirements-viewer.component.d.ts.map +1 -1
  50. package/dist/lib/components/plugins/data-requirements-viewer/data-requirements-viewer.component.js +142 -36
  51. package/dist/lib/components/plugins/data-requirements-viewer/data-requirements-viewer.component.js.map +1 -1
  52. package/dist/lib/components/plugins/docx-artifact-viewer.component.d.ts +14 -2
  53. package/dist/lib/components/plugins/docx-artifact-viewer.component.d.ts.map +1 -1
  54. package/dist/lib/components/plugins/docx-artifact-viewer.component.js +32 -8
  55. package/dist/lib/components/plugins/docx-artifact-viewer.component.js.map +1 -1
  56. package/dist/lib/components/plugins/html-artifact-viewer.component.d.ts +17 -3
  57. package/dist/lib/components/plugins/html-artifact-viewer.component.d.ts.map +1 -1
  58. package/dist/lib/components/plugins/html-artifact-viewer.component.js +36 -8
  59. package/dist/lib/components/plugins/html-artifact-viewer.component.js.map +1 -1
  60. package/dist/lib/components/plugins/image-artifact-viewer.component.d.ts +41 -5
  61. package/dist/lib/components/plugins/image-artifact-viewer.component.d.ts.map +1 -1
  62. package/dist/lib/components/plugins/image-artifact-viewer.component.js +102 -30
  63. package/dist/lib/components/plugins/image-artifact-viewer.component.js.map +1 -1
  64. package/dist/lib/components/plugins/json-artifact-viewer.component.d.ts +33 -5
  65. package/dist/lib/components/plugins/json-artifact-viewer.component.d.ts.map +1 -1
  66. package/dist/lib/components/plugins/json-artifact-viewer.component.js +89 -33
  67. package/dist/lib/components/plugins/json-artifact-viewer.component.js.map +1 -1
  68. package/dist/lib/components/plugins/markdown-artifact-viewer.component.d.ts +12 -2
  69. package/dist/lib/components/plugins/markdown-artifact-viewer.component.d.ts.map +1 -1
  70. package/dist/lib/components/plugins/markdown-artifact-viewer.component.js +28 -8
  71. package/dist/lib/components/plugins/markdown-artifact-viewer.component.js.map +1 -1
  72. package/dist/lib/components/plugins/ml-experiment-results-viewer.component.d.ts +4 -0
  73. package/dist/lib/components/plugins/ml-experiment-results-viewer.component.d.ts.map +1 -1
  74. package/dist/lib/components/plugins/ml-experiment-results-viewer.component.js +14 -6
  75. package/dist/lib/components/plugins/ml-experiment-results-viewer.component.js.map +1 -1
  76. package/dist/lib/components/plugins/pdf-artifact-viewer.component.d.ts +47 -5
  77. package/dist/lib/components/plugins/pdf-artifact-viewer.component.d.ts.map +1 -1
  78. package/dist/lib/components/plugins/pdf-artifact-viewer.component.js +129 -45
  79. package/dist/lib/components/plugins/pdf-artifact-viewer.component.js.map +1 -1
  80. package/dist/lib/components/plugins/save-query-dialog.component.d.ts +5 -1
  81. package/dist/lib/components/plugins/save-query-dialog.component.d.ts.map +1 -1
  82. package/dist/lib/components/plugins/save-query-dialog.component.js +12 -4
  83. package/dist/lib/components/plugins/save-query-dialog.component.js.map +1 -1
  84. package/dist/lib/components/plugins/svg-artifact-viewer.component.d.ts +17 -3
  85. package/dist/lib/components/plugins/svg-artifact-viewer.component.d.ts.map +1 -1
  86. package/dist/lib/components/plugins/svg-artifact-viewer.component.js +36 -8
  87. package/dist/lib/components/plugins/svg-artifact-viewer.component.js.map +1 -1
  88. package/dist/lib/components/plugins/video-artifact-viewer.component.d.ts +9 -1
  89. package/dist/lib/components/plugins/video-artifact-viewer.component.d.ts.map +1 -1
  90. package/dist/lib/components/plugins/video-artifact-viewer.component.js +20 -4
  91. package/dist/lib/components/plugins/video-artifact-viewer.component.js.map +1 -1
  92. package/dist/lib/components/plugins/xlsx-artifact-viewer.component.d.ts +28 -4
  93. package/dist/lib/components/plugins/xlsx-artifact-viewer.component.d.ts.map +1 -1
  94. package/dist/lib/components/plugins/xlsx-artifact-viewer.component.js +64 -16
  95. package/dist/lib/components/plugins/xlsx-artifact-viewer.component.js.map +1 -1
  96. package/dist/lib/components/previews/audio-artifact-preview.component.d.ts +9 -1
  97. package/dist/lib/components/previews/audio-artifact-preview.component.d.ts.map +1 -1
  98. package/dist/lib/components/previews/audio-artifact-preview.component.js +20 -4
  99. package/dist/lib/components/previews/audio-artifact-preview.component.js.map +1 -1
  100. package/dist/lib/components/previews/image-artifact-preview.component.d.ts +16 -2
  101. package/dist/lib/components/previews/image-artifact-preview.component.d.ts.map +1 -1
  102. package/dist/lib/components/previews/image-artifact-preview.component.js +35 -7
  103. package/dist/lib/components/previews/image-artifact-preview.component.js.map +1 -1
  104. package/dist/lib/components/previews/video-artifact-preview.component.d.ts +9 -1
  105. package/dist/lib/components/previews/video-artifact-preview.component.d.ts.map +1 -1
  106. package/dist/lib/components/previews/video-artifact-preview.component.js +20 -4
  107. package/dist/lib/components/previews/video-artifact-preview.component.js.map +1 -1
  108. package/dist/lib/interfaces/artifact-viewer-plugin.interface.js.map +1 -1
  109. package/dist/lib/services/artifact-file.service.d.ts +8 -0
  110. package/dist/lib/services/artifact-file.service.d.ts.map +1 -1
  111. package/dist/lib/services/artifact-file.service.js +22 -6
  112. package/dist/lib/services/artifact-file.service.js.map +1 -1
  113. package/dist/lib/services/artifact-icon.service.d.ts +2 -0
  114. package/dist/lib/services/artifact-icon.service.d.ts.map +1 -1
  115. package/dist/lib/services/artifact-icon.service.js +5 -1
  116. package/dist/lib/services/artifact-icon.service.js.map +1 -1
  117. package/dist/lib/services/artifact-preview-resolver.service.d.ts +2 -0
  118. package/dist/lib/services/artifact-preview-resolver.service.d.ts.map +1 -1
  119. package/dist/lib/services/artifact-preview-resolver.service.js +5 -1
  120. package/dist/lib/services/artifact-preview-resolver.service.js.map +1 -1
  121. package/dist/lib/snapshot-helpers.d.ts +10 -0
  122. package/dist/lib/snapshot-helpers.d.ts.map +1 -1
  123. package/dist/lib/snapshot-helpers.js +25 -5
  124. package/dist/lib/snapshot-helpers.js.map +1 -1
  125. package/package.json +21 -21
@@ -606,52 +606,308 @@ export class ArtifactViewerPanelComponent extends BaseAngularComponent {
606
606
  artifactIconService;
607
607
  artifactFileService;
608
608
  artifactId;
609
- currentUser;
610
- environmentId;
611
- versionNumber; // Version to display
612
- showSaveToCollection = true; // Control whether Save to Collection button is shown
613
- showHeader = true; // Control whether the header section is shown
614
- showTabs = true; // Control whether the tab navigation is shown (false = show only Display tab content)
615
- showCloseButton = true; // Control whether the close button is shown in header
616
- showMaximizeButton = true; // Control whether the maximize/restore button is shown in header
617
- refreshTrigger;
618
- viewContext = null; // Where artifact is being viewed
619
- contextCollectionId; // If viewing in collection, which collection
609
+ CurrentUser;
610
+ /** @deprecated Use {@link CurrentUser}. */
611
+ set currentUser(value) {
612
+ this.CurrentUser = value;
613
+ }
614
+ /** @deprecated Use {@link CurrentUser}. */
615
+ get currentUser() {
616
+ return this.CurrentUser;
617
+ }
618
+ EnvironmentId;
619
+ /** @deprecated Use {@link EnvironmentId}. */
620
+ set environmentId(value) {
621
+ this.EnvironmentId = value;
622
+ }
623
+ /** @deprecated Use {@link EnvironmentId}. */
624
+ get environmentId() {
625
+ return this.EnvironmentId;
626
+ }
627
+ VersionNumber;
628
+ /** @deprecated Use {@link VersionNumber}. */
629
+ set versionNumber(value) {
630
+ this.VersionNumber = value;
631
+ }
632
+ /** @deprecated Use {@link VersionNumber}. */
633
+ get versionNumber() {
634
+ return this.VersionNumber;
635
+ } // Version to display
636
+ ShowSaveToCollection = true;
637
+ /** @deprecated Use {@link ShowSaveToCollection}. */
638
+ set showSaveToCollection(value) {
639
+ this.ShowSaveToCollection = value;
640
+ }
641
+ /** @deprecated Use {@link ShowSaveToCollection}. */
642
+ get showSaveToCollection() {
643
+ return this.ShowSaveToCollection;
644
+ } // Control whether Save to Collection button is shown
645
+ ShowHeader = true;
646
+ /** @deprecated Use {@link ShowHeader}. */
647
+ set showHeader(value) {
648
+ this.ShowHeader = value;
649
+ }
650
+ /** @deprecated Use {@link ShowHeader}. */
651
+ get showHeader() {
652
+ return this.ShowHeader;
653
+ } // Control whether the header section is shown
654
+ ShowTabs = true;
655
+ /** @deprecated Use {@link ShowTabs}. */
656
+ set showTabs(value) {
657
+ this.ShowTabs = value;
658
+ }
659
+ /** @deprecated Use {@link ShowTabs}. */
660
+ get showTabs() {
661
+ return this.ShowTabs;
662
+ } // Control whether the tab navigation is shown (false = show only Display tab content)
663
+ ShowCloseButton = true;
664
+ /** @deprecated Use {@link ShowCloseButton}. */
665
+ set showCloseButton(value) {
666
+ this.ShowCloseButton = value;
667
+ }
668
+ /** @deprecated Use {@link ShowCloseButton}. */
669
+ get showCloseButton() {
670
+ return this.ShowCloseButton;
671
+ } // Control whether the close button is shown in header
672
+ ShowMaximizeButton = true;
673
+ /** @deprecated Use {@link ShowMaximizeButton}. */
674
+ set showMaximizeButton(value) {
675
+ this.ShowMaximizeButton = value;
676
+ }
677
+ /** @deprecated Use {@link ShowMaximizeButton}. */
678
+ get showMaximizeButton() {
679
+ return this.ShowMaximizeButton;
680
+ } // Control whether the maximize/restore button is shown in header
681
+ RefreshTrigger;
682
+ /** @deprecated Use {@link RefreshTrigger}. */
683
+ set refreshTrigger(value) {
684
+ this.RefreshTrigger = value;
685
+ }
686
+ /** @deprecated Use {@link RefreshTrigger}. */
687
+ get refreshTrigger() {
688
+ return this.RefreshTrigger;
689
+ }
690
+ ViewContext = null;
691
+ /** @deprecated Use {@link ViewContext}. */
692
+ set viewContext(value) {
693
+ this.ViewContext = value;
694
+ }
695
+ /** @deprecated Use {@link ViewContext}. */
696
+ get viewContext() {
697
+ return this.ViewContext;
698
+ } // Where artifact is being viewed
699
+ ContextCollectionId;
700
+ /** @deprecated Use {@link ContextCollectionId}. */
701
+ set contextCollectionId(value) {
702
+ this.ContextCollectionId = value;
703
+ }
704
+ /** @deprecated Use {@link ContextCollectionId}. */
705
+ get contextCollectionId() {
706
+ return this.ContextCollectionId;
707
+ } // If viewing in collection, which collection
620
708
  canShare; // Whether user can share this artifact
621
709
  canEdit; // Whether user can edit this artifact
622
- isMaximized = false; // Whether the panel is currently maximized
623
- closed = new EventEmitter();
624
- saveToCollectionRequested = new EventEmitter();
625
- navigateToLink = new EventEmitter();
626
- shareRequested = new EventEmitter(); // Emits artifactId when share is clicked
627
- maximizeToggled = new EventEmitter(); // Emits when user clicks maximize/restore button
628
- openEntityRecord = new EventEmitter();
710
+ IsMaximized = false;
711
+ /** @deprecated Use {@link IsMaximized}. */
712
+ set isMaximized(value) {
713
+ this.IsMaximized = value;
714
+ }
715
+ /** @deprecated Use {@link IsMaximized}. */
716
+ get isMaximized() {
717
+ return this.IsMaximized;
718
+ } // Whether the panel is currently maximized
719
+ Closed = new EventEmitter();
720
+ /**
721
+ * @deprecated Use {@link Closed}.
722
+ *
723
+ * The same emitter under the old binding name, so a template still binding
724
+ * (closed) keeps working. Must stay AFTER Closed: class fields
725
+ * initialise in order, and the other way round this captures undefined.
726
+ */
727
+ closed = this.Closed;
728
+ SaveToCollectionRequested = new EventEmitter();
729
+ /**
730
+ * @deprecated Use {@link SaveToCollectionRequested}.
731
+ *
732
+ * The same emitter under the old binding name, so a template still binding
733
+ * (saveToCollectionRequested) keeps working. Must stay AFTER SaveToCollectionRequested: class fields
734
+ * initialise in order, and the other way round this captures undefined.
735
+ */
736
+ saveToCollectionRequested = this.SaveToCollectionRequested;
737
+ NavigateToLink = new EventEmitter();
738
+ /**
739
+ * @deprecated Use {@link NavigateToLink}.
740
+ *
741
+ * The same emitter under the old binding name, so a template still binding
742
+ * (navigateToLink) keeps working. Must stay AFTER NavigateToLink: class fields
743
+ * initialise in order, and the other way round this captures undefined.
744
+ */
745
+ navigateToLink = this.NavigateToLink;
746
+ ShareRequested = new EventEmitter();
747
+ /**
748
+ * @deprecated Use {@link ShareRequested}.
749
+ *
750
+ * The same emitter under the old binding name, so a template still binding
751
+ * (shareRequested) keeps working. Must stay AFTER ShareRequested: class fields
752
+ * initialise in order, and the other way round this captures undefined.
753
+ */
754
+ shareRequested = this.ShareRequested; // Emits artifactId when share is clicked
755
+ MaximizeToggled = new EventEmitter();
756
+ /**
757
+ * @deprecated Use {@link MaximizeToggled}.
758
+ *
759
+ * The same emitter under the old binding name, so a template still binding
760
+ * (maximizeToggled) keeps working. Must stay AFTER MaximizeToggled: class fields
761
+ * initialise in order, and the other way round this captures undefined.
762
+ */
763
+ maximizeToggled = this.MaximizeToggled; // Emits when user clicks maximize/restore button
764
+ OpenEntityRecord = new EventEmitter();
765
+ /**
766
+ * @deprecated Use {@link OpenEntityRecord}.
767
+ *
768
+ * The same emitter under the old binding name, so a template still binding
769
+ * (openEntityRecord) keeps working. Must stay AFTER OpenEntityRecord: class fields
770
+ * initialise in order, and the other way round this captures undefined.
771
+ */
772
+ openEntityRecord = this.OpenEntityRecord;
629
773
  navigationRequest = new EventEmitter();
630
- analyzeRequested = new EventEmitter();
774
+ AnalyzeRequested = new EventEmitter();
775
+ /**
776
+ * @deprecated Use {@link AnalyzeRequested}.
777
+ *
778
+ * The same emitter under the old binding name, so a template still binding
779
+ * (analyzeRequested) keeps working. Must stay AFTER AnalyzeRequested: class fields
780
+ * initialise in order, and the other way round this captures undefined.
781
+ */
782
+ analyzeRequested = this.AnalyzeRequested;
631
783
  /**
632
784
  * "Apply to my form" — bubbled from the form-aware component-artifact-viewer
633
785
  * branch. Carries the spec + entity. Consumer (chat message card, etc.)
634
786
  * confirms and invokes the Create-or-Modify Interactive Form action.
635
787
  */
636
- applyFormRequested = new EventEmitter();
637
- pluginViewer;
788
+ ApplyFormRequested = new EventEmitter();
789
+ /**
790
+ * @deprecated Use {@link ApplyFormRequested}.
791
+ *
792
+ * The same emitter under the old binding name, so a template still binding
793
+ * (applyFormRequested) keeps working. Must stay AFTER ApplyFormRequested: class fields
794
+ * initialise in order, and the other way round this captures undefined.
795
+ */
796
+ applyFormRequested = this.ApplyFormRequested;
797
+ PluginViewer;
798
+ /** @deprecated Use {@link PluginViewer}. */
799
+ get pluginViewer() {
800
+ return this.PluginViewer;
801
+ }
802
+ /** @deprecated Use {@link PluginViewer}. */
803
+ set pluginViewer(value) {
804
+ this.PluginViewer = value;
805
+ }
638
806
  destroy$ = new Subject();
639
807
  artifactLoadToken = 0;
640
- artifact = null;
808
+ Artifact = null;
809
+ /** @deprecated Use {@link Artifact}. */
810
+ get artifact() {
811
+ return this.Artifact;
812
+ }
813
+ /** @deprecated Use {@link Artifact}. */
814
+ set artifact(value) {
815
+ this.Artifact = value;
816
+ }
641
817
  artifactVersion = null;
642
- allVersions = [];
643
- selectedVersionNumber = 1;
818
+ AllVersions = [];
819
+ /** @deprecated Use {@link AllVersions}. */
820
+ get allVersions() {
821
+ return this.AllVersions;
822
+ }
823
+ /** @deprecated Use {@link AllVersions}. */
824
+ set allVersions(value) {
825
+ this.AllVersions = value;
826
+ }
827
+ SelectedVersionNumber = 1;
828
+ /** @deprecated Use {@link SelectedVersionNumber}. */
829
+ get selectedVersionNumber() {
830
+ return this.SelectedVersionNumber;
831
+ }
832
+ /** @deprecated Use {@link SelectedVersionNumber}. */
833
+ set selectedVersionNumber(value) {
834
+ this.SelectedVersionNumber = value;
835
+ }
644
836
  isLoading = true;
645
837
  error = null;
646
- jsonContent = '';
647
- showVersionDropdown = false;
648
- artifactCollections = []; // All collections for ALL versions
649
- currentVersionCollections = []; // Collections containing CURRENT version only
650
- primaryCollection = null;
838
+ JsonContent = '';
839
+ /** @deprecated Use {@link JsonContent}. */
840
+ get jsonContent() {
841
+ return this.JsonContent;
842
+ }
843
+ /** @deprecated Use {@link JsonContent}. */
844
+ set jsonContent(value) {
845
+ this.JsonContent = value;
846
+ }
847
+ ShowVersionDropdown = false;
848
+ /** @deprecated Use {@link ShowVersionDropdown}. */
849
+ get showVersionDropdown() {
850
+ return this.ShowVersionDropdown;
851
+ }
852
+ /** @deprecated Use {@link ShowVersionDropdown}. */
853
+ set showVersionDropdown(value) {
854
+ this.ShowVersionDropdown = value;
855
+ }
856
+ ArtifactCollections = [];
857
+ /** @deprecated Use {@link ArtifactCollections}. */
858
+ get artifactCollections() {
859
+ return this.ArtifactCollections;
860
+ }
861
+ /** @deprecated Use {@link ArtifactCollections}. */
862
+ set artifactCollections(value) {
863
+ this.ArtifactCollections = value;
864
+ } // All collections for ALL versions
865
+ CurrentVersionCollections = [];
866
+ /** @deprecated Use {@link CurrentVersionCollections}. */
867
+ get currentVersionCollections() {
868
+ return this.CurrentVersionCollections;
869
+ }
870
+ /** @deprecated Use {@link CurrentVersionCollections}. */
871
+ set currentVersionCollections(value) {
872
+ this.CurrentVersionCollections = value;
873
+ } // Collections containing CURRENT version only
874
+ PrimaryCollection = null;
875
+ /** @deprecated Use {@link PrimaryCollection}. */
876
+ get primaryCollection() {
877
+ return this.PrimaryCollection;
878
+ }
879
+ /** @deprecated Use {@link PrimaryCollection}. */
880
+ set primaryCollection(value) {
881
+ this.PrimaryCollection = value;
882
+ }
651
883
  // Tabbed interface
652
- activeTab = 'display'; // Changed to string to support dynamic tabs
653
- displayMarkdown = null;
654
- displayHtml = null;
884
+ ActiveTab = 'display';
885
+ /** @deprecated Use {@link ActiveTab}. */
886
+ get activeTab() {
887
+ return this.ActiveTab;
888
+ }
889
+ /** @deprecated Use {@link ActiveTab}. */
890
+ set activeTab(value) {
891
+ this.ActiveTab = value;
892
+ } // Changed to string to support dynamic tabs
893
+ DisplayMarkdown = null;
894
+ /** @deprecated Use {@link DisplayMarkdown}. */
895
+ get displayMarkdown() {
896
+ return this.DisplayMarkdown;
897
+ }
898
+ /** @deprecated Use {@link DisplayMarkdown}. */
899
+ set displayMarkdown(value) {
900
+ this.DisplayMarkdown = value;
901
+ }
902
+ DisplayHtml = null;
903
+ /** @deprecated Use {@link DisplayHtml}. */
904
+ get displayHtml() {
905
+ return this.DisplayHtml;
906
+ }
907
+ /** @deprecated Use {@link DisplayHtml}. */
908
+ set displayHtml(value) {
909
+ this.DisplayHtml = value;
910
+ }
655
911
  /**
656
912
  * The no-plugin fallback. An artifact type with no viewer plugin (CSV today) used to render an empty
657
913
  * pane: the display tab only knew the extracted markdown/HTML attributes, and a file-backed version
@@ -659,35 +915,99 @@ export class ArtifactViewerPanelComponent extends BaseAngularComponent {
659
915
  * text-like content (text/*, JSON, CSV) is fetched and shown as plain text — capped, so a large file
660
916
  * is downloaded rather than rendered.
661
917
  */
662
- fallbackText = null;
663
- fallbackTextTruncated = false;
664
- fallbackBusy = false;
918
+ FallbackText = null;
919
+ /** @deprecated Use {@link FallbackText}. */
920
+ get fallbackText() {
921
+ return this.FallbackText;
922
+ }
923
+ /** @deprecated Use {@link FallbackText}. */
924
+ set fallbackText(value) {
925
+ this.FallbackText = value;
926
+ }
927
+ FallbackTextTruncated = false;
928
+ /** @deprecated Use {@link FallbackTextTruncated}. */
929
+ get fallbackTextTruncated() {
930
+ return this.FallbackTextTruncated;
931
+ }
932
+ /** @deprecated Use {@link FallbackTextTruncated}. */
933
+ set fallbackTextTruncated(value) {
934
+ this.FallbackTextTruncated = value;
935
+ }
936
+ FallbackBusy = false;
937
+ /** @deprecated Use {@link FallbackBusy}. */
938
+ get fallbackBusy() {
939
+ return this.FallbackBusy;
940
+ }
941
+ /** @deprecated Use {@link FallbackBusy}. */
942
+ set fallbackBusy(value) {
943
+ this.FallbackBusy = value;
944
+ }
665
945
  static FALLBACK_TEXT_MAX_CHARS = 200_000;
666
- versionAttributes = [];
946
+ VersionAttributes = [];
947
+ /** @deprecated Use {@link VersionAttributes}. */
948
+ get versionAttributes() {
949
+ return this.VersionAttributes;
950
+ }
951
+ /** @deprecated Use {@link VersionAttributes}. */
952
+ set versionAttributes(value) {
953
+ this.VersionAttributes = value;
954
+ }
667
955
  artifactTypeDriverClass = null;
668
956
  /** Populated from ArtifactType.ContentCategory. Used to suppress the JSON tab for
669
957
  * binary file-type artifacts — driven by metadata, not hardcoded plugin overrides. */
670
958
  artifactContentCategory = null;
671
959
  // Links tab data
672
- originConversation = null;
673
- allCollections = [];
674
- hasAccessToOriginConversation = false;
675
- originConversationVersionId = null; // Version ID that came from origin conversation
960
+ OriginConversation = null;
961
+ /** @deprecated Use {@link OriginConversation}. */
962
+ get originConversation() {
963
+ return this.OriginConversation;
964
+ }
965
+ /** @deprecated Use {@link OriginConversation}. */
966
+ set originConversation(value) {
967
+ this.OriginConversation = value;
968
+ }
969
+ AllCollections = [];
970
+ /** @deprecated Use {@link AllCollections}. */
971
+ get allCollections() {
972
+ return this.AllCollections;
973
+ }
974
+ /** @deprecated Use {@link AllCollections}. */
975
+ set allCollections(value) {
976
+ this.AllCollections = value;
977
+ }
978
+ HasAccessToOriginConversation = false;
979
+ /** @deprecated Use {@link HasAccessToOriginConversation}. */
980
+ get hasAccessToOriginConversation() {
981
+ return this.HasAccessToOriginConversation;
982
+ }
983
+ /** @deprecated Use {@link HasAccessToOriginConversation}. */
984
+ set hasAccessToOriginConversation(value) {
985
+ this.HasAccessToOriginConversation = value;
986
+ }
987
+ OriginConversationVersionId = null;
988
+ /** @deprecated Use {@link OriginConversationVersionId}. */
989
+ get originConversationVersionId() {
990
+ return this.OriginConversationVersionId;
991
+ }
992
+ /** @deprecated Use {@link OriginConversationVersionId}. */
993
+ set originConversationVersionId(value) {
994
+ this.OriginConversationVersionId = value;
995
+ } // Version ID that came from origin conversation
676
996
  // Dynamic tabs from plugin
677
- get allTabs() {
997
+ get AllTabs() {
678
998
  const tabs = [];
679
999
  // Only add Display tab if there's content to display
680
- if (this.hasDisplayTab) {
1000
+ if (this.HasDisplayTab) {
681
1001
  tabs.push('Display');
682
1002
  }
683
1003
  // Get plugin tabs directly from plugin instance (no caching needed - plugin always exists)
684
- if (this.pluginViewer?.pluginInstance?.GetAdditionalTabs) {
685
- const pluginTabs = this.pluginViewer.pluginInstance.GetAdditionalTabs();
1004
+ if (this.PluginViewer?.pluginInstance?.GetAdditionalTabs) {
1005
+ const pluginTabs = this.PluginViewer.pluginInstance.GetAdditionalTabs();
686
1006
  const pluginTabLabels = pluginTabs.map((t) => t.label);
687
1007
  tabs.push(...pluginTabLabels);
688
1008
  }
689
1009
  // Get tabs to remove from plugin (case-insensitive)
690
- const removals = this.pluginViewer?.pluginInstance?.GetStandardTabRemovals?.() || [];
1010
+ const removals = this.PluginViewer?.pluginInstance?.GetStandardTabRemovals?.() || [];
691
1011
  const removalsLower = removals.map(r => r.toLowerCase());
692
1012
  // File-category artifacts (PDF, Excel, Word) have binary content — the JSON tab
693
1013
  // would show a base64 blob or a storage reference, which is meaningless. Suppress it
@@ -701,19 +1021,23 @@ export class ArtifactViewerPanelComponent extends BaseAngularComponent {
701
1021
  tabs.push('Details');
702
1022
  }
703
1023
  // Only add Links tab if there are links to show (unless plugin explicitly removes it)
704
- if (!removalsLower.includes('links') && this.linksToShow.length > 0) {
1024
+ if (!removalsLower.includes('links') && this.LinksToShow.length > 0) {
705
1025
  tabs.push('Links');
706
1026
  }
707
1027
  return tabs;
708
1028
  }
1029
+ /** @deprecated Use {@link AllTabs}. */
1030
+ get allTabs() {
1031
+ return this.AllTabs;
1032
+ }
709
1033
  /**
710
1034
  * Get the full tab definition for a given tab name.
711
1035
  * Returns the ArtifactViewerTab which may include component info for custom component tabs.
712
1036
  */
713
1037
  GetTabDefinition(tabName) {
714
1038
  // Check if this is a plugin-provided tab
715
- if (this.pluginViewer?.pluginInstance?.GetAdditionalTabs) {
716
- const pluginTabs = this.pluginViewer.pluginInstance.GetAdditionalTabs();
1039
+ if (this.PluginViewer?.pluginInstance?.GetAdditionalTabs) {
1040
+ const pluginTabs = this.PluginViewer.pluginInstance.GetAdditionalTabs();
717
1041
  const pluginTab = pluginTabs.find((t) => t.label.toLowerCase() === tabName.toLowerCase());
718
1042
  if (pluginTab) {
719
1043
  return pluginTab;
@@ -722,9 +1046,9 @@ export class ArtifactViewerPanelComponent extends BaseAngularComponent {
722
1046
  // Handle base tabs
723
1047
  switch (tabName.toLowerCase()) {
724
1048
  case 'json':
725
- return { label: 'JSON', contentType: 'json', content: this.jsonContent, language: 'json' };
1049
+ return { label: 'JSON', contentType: 'json', content: this.JsonContent, language: 'json' };
726
1050
  case 'details':
727
- return { label: 'Details', contentType: 'html', content: this.displayMarkdown || this.displayHtml || '' };
1051
+ return { label: 'Details', contentType: 'html', content: this.DisplayMarkdown || this.DisplayHtml || '' };
728
1052
  default:
729
1053
  return null;
730
1054
  }
@@ -792,8 +1116,8 @@ export class ArtifactViewerPanelComponent extends BaseAngularComponent {
792
1116
  }
793
1117
  async ngOnInit() {
794
1118
  // Subscribe to refresh trigger for dynamic version changes
795
- if (this.refreshTrigger) {
796
- this.refreshTrigger.pipe(takeUntil(this.destroy$)).subscribe(async (data) => {
1119
+ if (this.RefreshTrigger) {
1120
+ this.RefreshTrigger.pipe(takeUntil(this.destroy$)).subscribe(async (data) => {
797
1121
  // UUIDsEqual, not ===: SQL Server hands back upper-case UUIDs and PostgreSQL lower-case, so
798
1122
  // a raw comparison silently drops a legitimate refresh whenever the emitting side and this
799
1123
  // input picked up the id from differently-cased sources.
@@ -810,9 +1134,9 @@ export class ArtifactViewerPanelComponent extends BaseAngularComponent {
810
1134
  // Using setTimeout(0) instead of Promise.resolve() because we need a fresh
811
1135
  // macrotask boundary — microtasks can still drain inside Angular's CD cycle.
812
1136
  setTimeout(async () => {
813
- await this.loadArtifact(this.versionNumber);
1137
+ await this.loadArtifact(this.VersionNumber);
814
1138
  // Track that user viewed this artifact (deferred so it runs after the load)
815
- if (this.artifactVersion?.ID && this.currentUser) {
1139
+ if (this.artifactVersion?.ID && this.CurrentUser) {
816
1140
  this.trackArtifactUsage('Viewed');
817
1141
  // Also log to User Record Logs for recents feature (fire-and-forget)
818
1142
  this.recentAccessService.logAccess('MJ: Artifacts', this.artifactId, 'artifact');
@@ -822,7 +1146,7 @@ export class ArtifactViewerPanelComponent extends BaseAngularComponent {
822
1146
  async ngOnChanges(changes) {
823
1147
  // Reload artifact when artifactId changes
824
1148
  if (changes['artifactId'] && !changes['artifactId'].firstChange) {
825
- await this.loadArtifact(this.versionNumber);
1149
+ await this.loadArtifact(this.VersionNumber);
826
1150
  // `loadArtifact` already honored the (possibly also-changed) versionNumber, so the branch
827
1151
  // below has nothing left to do. Angular delivers both inputs in ONE SimpleChanges when a
828
1152
  // caller switches artifact and version together, and these are two independent `if`s: the
@@ -837,14 +1161,14 @@ export class ArtifactViewerPanelComponent extends BaseAngularComponent {
837
1161
  const newVersionNumber = changes['versionNumber'].currentValue;
838
1162
  if (newVersionNumber != null) {
839
1163
  // Check if we have metadata for this version (allVersions has lightweight metadata)
840
- const targetVersion = this.allVersions.find(v => v.VersionNumber === newVersionNumber);
1164
+ const targetVersion = this.AllVersions.find(v => v.VersionNumber === newVersionNumber);
841
1165
  if (targetVersion) {
842
- this.selectedVersionNumber = targetVersion.VersionNumber || 1;
1166
+ this.SelectedVersionNumber = targetVersion.VersionNumber || 1;
843
1167
  // Load full content for the selected version
844
1168
  const fullVersion = await this.loadVersionContent(targetVersion.ID);
845
1169
  if (fullVersion) {
846
1170
  this.artifactVersion = fullVersion;
847
- this.jsonContent = this.FormatJSON(fullVersion.Content || '{}');
1171
+ this.JsonContent = this.formatJSON(fullVersion.Content || '{}');
848
1172
  }
849
1173
  // Load attributes and collection data in parallel
850
1174
  await Promise.all([
@@ -869,18 +1193,18 @@ export class ArtifactViewerPanelComponent extends BaseAngularComponent {
869
1193
  return loadToken === this.artifactLoadToken && UUIDsEqual(artifactId, this.artifactId);
870
1194
  }
871
1195
  clearLoadedArtifactState() {
872
- this.artifact = null;
1196
+ this.Artifact = null;
873
1197
  this.artifactVersion = null;
874
- this.allVersions = [];
875
- this.versionAttributes = [];
876
- this.jsonContent = '';
877
- this.displayMarkdown = null;
878
- this.displayHtml = null;
879
- this.fallbackText = null;
880
- this.fallbackTextTruncated = false;
881
- this.artifactCollections = [];
882
- this.currentVersionCollections = [];
883
- this.primaryCollection = null;
1198
+ this.AllVersions = [];
1199
+ this.VersionAttributes = [];
1200
+ this.JsonContent = '';
1201
+ this.DisplayMarkdown = null;
1202
+ this.DisplayHtml = null;
1203
+ this.FallbackText = null;
1204
+ this.FallbackTextTruncated = false;
1205
+ this.ArtifactCollections = [];
1206
+ this.CurrentVersionCollections = [];
1207
+ this.PrimaryCollection = null;
884
1208
  this.artifactTypeDriverClass = null;
885
1209
  this.artifactContentCategory = null;
886
1210
  this.clearLinksData();
@@ -895,7 +1219,7 @@ export class ArtifactViewerPanelComponent extends BaseAngularComponent {
895
1219
  this.clearLoadedArtifactState();
896
1220
  const md = this.ProviderToUse;
897
1221
  // Load artifact — assign to local first to avoid mid-cycle icon flicker
898
- const artifactEntity = await md.GetEntityObject('MJ: Artifacts', this.currentUser);
1222
+ const artifactEntity = await md.GetEntityObject('MJ: Artifacts', this.CurrentUser);
899
1223
  const loaded = await artifactEntity.Load(artifactId);
900
1224
  if (!isCurrentLoad()) {
901
1225
  return;
@@ -935,7 +1259,7 @@ export class ArtifactViewerPanelComponent extends BaseAngularComponent {
935
1259
  MaxRows: 1,
936
1260
  ResultType: 'simple'
937
1261
  }
938
- ], this.currentUser);
1262
+ ], this.CurrentUser);
939
1263
  if (!isCurrentLoad()) {
940
1264
  return;
941
1265
  }
@@ -944,8 +1268,8 @@ export class ArtifactViewerPanelComponent extends BaseAngularComponent {
944
1268
  this.error = 'No artifact version found';
945
1269
  return;
946
1270
  }
947
- this.artifact = artifactEntity;
948
- this.allVersions = versionsResult.Results;
1271
+ this.Artifact = artifactEntity;
1272
+ this.AllVersions = versionsResult.Results;
949
1273
  // Determine which version to display
950
1274
  let selectedVersion;
951
1275
  if (targetVersionNumber) {
@@ -953,7 +1277,7 @@ export class ArtifactViewerPanelComponent extends BaseAngularComponent {
953
1277
  }
954
1278
  // Fall back to latest version (first in DESC order)
955
1279
  const versionToLoad = selectedVersion || versionsResult.Results[0];
956
- this.selectedVersionNumber = versionToLoad.VersionNumber || 1;
1280
+ this.SelectedVersionNumber = versionToLoad.VersionNumber || 1;
957
1281
  // PERF: Start artifact type resolution and selected version content load in parallel
958
1282
  const [, selectedVersionEntity] = await Promise.all([
959
1283
  this.loadArtifactType(artifactEntity.Type, artifactId, loadToken),
@@ -964,7 +1288,7 @@ export class ArtifactViewerPanelComponent extends BaseAngularComponent {
964
1288
  }
965
1289
  if (selectedVersionEntity) {
966
1290
  this.artifactVersion = selectedVersionEntity;
967
- this.jsonContent = this.FormatJSON(selectedVersionEntity.Content || '{}');
1291
+ this.JsonContent = this.formatJSON(selectedVersionEntity.Content || '{}');
968
1292
  }
969
1293
  else {
970
1294
  this.error = 'Failed to load artifact version content';
@@ -1004,7 +1328,7 @@ export class ArtifactViewerPanelComponent extends BaseAngularComponent {
1004
1328
  async loadVersionContent(versionId) {
1005
1329
  try {
1006
1330
  const md = this.ProviderToUse;
1007
- const versionEntity = await md.GetEntityObject('MJ: Artifact Versions', this.currentUser);
1331
+ const versionEntity = await md.GetEntityObject('MJ: Artifact Versions', this.CurrentUser);
1008
1332
  const loaded = await versionEntity.Load(versionId);
1009
1333
  return loaded ? versionEntity : null;
1010
1334
  }
@@ -1017,12 +1341,12 @@ export class ArtifactViewerPanelComponent extends BaseAngularComponent {
1017
1341
  * Clear all links-related data to prevent stale data when switching artifacts
1018
1342
  */
1019
1343
  clearLinksData() {
1020
- this.allCollections = [];
1021
- this.originConversation = null;
1022
- this.hasAccessToOriginConversation = false;
1023
- this.originConversationVersionId = null;
1344
+ this.AllCollections = [];
1345
+ this.OriginConversation = null;
1346
+ this.HasAccessToOriginConversation = false;
1347
+ this.OriginConversationVersionId = null;
1024
1348
  }
1025
- async loadArtifactType(artifactTypeName = this.artifact?.Type, artifactId = this.artifactId, loadToken = this.artifactLoadToken) {
1349
+ async loadArtifactType(artifactTypeName = this.Artifact?.Type, artifactId = this.artifactId, loadToken = this.artifactLoadToken) {
1026
1350
  const isCurrentLoad = () => this.isCurrentArtifactLoad(artifactId, loadToken);
1027
1351
  this.artifactTypeDriverClass = null;
1028
1352
  this.artifactContentCategory = null;
@@ -1030,7 +1354,7 @@ export class ArtifactViewerPanelComponent extends BaseAngularComponent {
1030
1354
  return;
1031
1355
  }
1032
1356
  try {
1033
- await ArtifactMetadataEngine.Instance.Config(false, this.currentUser);
1357
+ await ArtifactMetadataEngine.Instance.Config(false, this.CurrentUser);
1034
1358
  if (!isCurrentLoad()) {
1035
1359
  return;
1036
1360
  }
@@ -1060,21 +1384,21 @@ export class ArtifactViewerPanelComponent extends BaseAngularComponent {
1060
1384
  EntityName: 'MJ: Artifact Version Attributes',
1061
1385
  ExtraFilter: `ArtifactVersionID='${this.artifactVersion.ID}'`,
1062
1386
  ResultType: 'simple'
1063
- }, this.currentUser);
1387
+ }, this.CurrentUser);
1064
1388
  if (!isCurrentLoad()) {
1065
1389
  return;
1066
1390
  }
1067
1391
  if (result.Success && result.Results) {
1068
- this.versionAttributes = result.Results;
1392
+ this.VersionAttributes = result.Results;
1069
1393
  // Check for displayMarkdown or displayHtml attributes
1070
- const displayMarkdownAttr = this.versionAttributes.find(a => a.Name?.toLowerCase() === 'displaymarkdown');
1071
- const displayHtmlAttr = this.versionAttributes.find(a => a.Name?.toLowerCase() === 'displayhtml');
1394
+ const displayMarkdownAttr = this.VersionAttributes.find(a => a.Name?.toLowerCase() === 'displaymarkdown');
1395
+ const displayHtmlAttr = this.VersionAttributes.find(a => a.Name?.toLowerCase() === 'displayhtml');
1072
1396
  // Parse values - they might be JSON-encoded strings
1073
- this.displayMarkdown = this.parseAttributeValue(displayMarkdownAttr?.Value);
1074
- this.displayHtml = this.parseAttributeValue(displayHtmlAttr?.Value);
1397
+ this.DisplayMarkdown = this.parseAttributeValue(displayMarkdownAttr?.Value);
1398
+ this.DisplayHtml = this.parseAttributeValue(displayHtmlAttr?.Value);
1075
1399
  // Clean up double-escaped characters in HTML (from LLM generation)
1076
- if (this.displayHtml) {
1077
- this.displayHtml = this.cleanEscapedCharacters(this.displayHtml);
1400
+ if (this.DisplayHtml) {
1401
+ this.DisplayHtml = this.cleanEscapedCharacters(this.DisplayHtml);
1078
1402
  }
1079
1403
  // Set active tab to the first available tab
1080
1404
  this.setActiveTabToFirstAvailable();
@@ -1097,15 +1421,19 @@ export class ArtifactViewerPanelComponent extends BaseAngularComponent {
1097
1421
  if (this.artifactVersion?.Name) {
1098
1422
  return this.artifactVersion.Name;
1099
1423
  }
1100
- return this.artifact?.Name || 'Artifact';
1424
+ return this.Artifact?.Name || 'Artifact';
1101
1425
  }
1102
- get displayDescription() {
1426
+ get DisplayDescription() {
1103
1427
  if (this.artifactVersion?.Description) {
1104
1428
  return this.artifactVersion.Description;
1105
1429
  }
1106
- return this.artifact?.Description || null;
1430
+ return this.Artifact?.Description || null;
1107
1431
  }
1108
- get hasDisplayTab() {
1432
+ /** @deprecated Use {@link DisplayDescription}. */
1433
+ get displayDescription() {
1434
+ return this.DisplayDescription;
1435
+ }
1436
+ get HasDisplayTab() {
1109
1437
  // Show Display tab if:
1110
1438
  // 1. We have a plugin AND it reports having content to display, OR
1111
1439
  // 2. We have displayMarkdown or displayHtml attributes from extract rules
@@ -1113,19 +1441,31 @@ export class ArtifactViewerPanelComponent extends BaseAngularComponent {
1113
1441
  // Note: hasDisplayContent defaults to false in base class, so plugins must
1114
1442
  // explicitly opt-in by overriding to return true when they have content.
1115
1443
  // This prevents showing Display tab before plugin loads or when plugin has no content.
1116
- const pluginHasContent = this.pluginViewer?.pluginInstance?.hasDisplayContent ?? false;
1117
- return pluginHasContent || !!this.displayMarkdown || !!this.displayHtml;
1444
+ const pluginHasContent = this.PluginViewer?.pluginInstance?.hasDisplayContent ?? false;
1445
+ return pluginHasContent || !!this.DisplayMarkdown || !!this.DisplayHtml;
1446
+ }
1447
+ /** @deprecated Use {@link HasDisplayTab}. */
1448
+ get hasDisplayTab() {
1449
+ return this.HasDisplayTab;
1118
1450
  }
1119
1451
  /** True when the display tab has nothing better than the file card to show. */
1452
+ get ShowFileFallback() {
1453
+ return !this.HasPlugin && !!this.artifactVersion && !this.DisplayMarkdown && !this.DisplayHtml;
1454
+ }
1455
+ /** @deprecated Use {@link ShowFileFallback}. */
1120
1456
  get showFileFallback() {
1121
- return !this.hasPlugin && !!this.artifactVersion && !this.displayMarkdown && !this.displayHtml;
1457
+ return this.ShowFileFallback;
1122
1458
  }
1123
1459
  /** The file name shown on the fallback card. */
1460
+ get FallbackFileName() {
1461
+ return this.artifactVersion?.FileName || this.Artifact?.Name || 'file';
1462
+ }
1463
+ /** @deprecated Use {@link FallbackFileName}. */
1124
1464
  get fallbackFileName() {
1125
- return this.artifactVersion?.FileName || this.artifact?.Name || 'file';
1465
+ return this.FallbackFileName;
1126
1466
  }
1127
1467
  /** Human file size for the fallback card, when the version knows it. */
1128
- get fallbackSize() {
1468
+ get FallbackSize() {
1129
1469
  const content = this.artifactVersion?.Content;
1130
1470
  if (this.artifactVersion?.ContentMode === 'Text' && content?.startsWith('data:')) {
1131
1471
  const b64 = content.slice(content.indexOf(',') + 1);
@@ -1133,6 +1473,10 @@ export class ArtifactViewerPanelComponent extends BaseAngularComponent {
1133
1473
  }
1134
1474
  return null;
1135
1475
  }
1476
+ /** @deprecated Use {@link FallbackSize}. */
1477
+ get fallbackSize() {
1478
+ return this.FallbackSize;
1479
+ }
1136
1480
  /** Text-like MIME types are shown inline on the fallback card; everything else is download-only. */
1137
1481
  isTextLike(mime) {
1138
1482
  const m = (mime ?? '').toLowerCase();
@@ -1143,10 +1487,10 @@ export class ArtifactViewerPanelComponent extends BaseAngularComponent {
1143
1487
  * inline: the data URL. Silent on failure — the Download action still works.
1144
1488
  */
1145
1489
  async prepareNoPluginFallback(isCurrentLoad) {
1146
- this.fallbackText = null;
1147
- this.fallbackTextTruncated = false;
1490
+ this.FallbackText = null;
1491
+ this.FallbackTextTruncated = false;
1148
1492
  const version = this.artifactVersion;
1149
- if (!this.showFileFallback || !version || !this.isTextLike(version.MimeType))
1493
+ if (!this.ShowFileFallback || !version || !this.isTextLike(version.MimeType))
1150
1494
  return;
1151
1495
  try {
1152
1496
  let text = null;
@@ -1166,9 +1510,9 @@ export class ArtifactViewerPanelComponent extends BaseAngularComponent {
1166
1510
  return;
1167
1511
  if (text.length > ArtifactViewerPanelComponent.FALLBACK_TEXT_MAX_CHARS) {
1168
1512
  text = text.slice(0, ArtifactViewerPanelComponent.FALLBACK_TEXT_MAX_CHARS);
1169
- this.fallbackTextTruncated = true;
1513
+ this.FallbackTextTruncated = true;
1170
1514
  }
1171
- this.fallbackText = text;
1515
+ this.FallbackText = text;
1172
1516
  this.cdr.markForCheck();
1173
1517
  }
1174
1518
  catch (err) {
@@ -1176,11 +1520,11 @@ export class ArtifactViewerPanelComponent extends BaseAngularComponent {
1176
1520
  }
1177
1521
  }
1178
1522
  /** Download the artifact's file: file-backed via MJ's URL (fetched to a blob so the browser saves it), inline via the data URL. */
1179
- async downloadArtifactFile() {
1523
+ async DownloadArtifactFile() {
1180
1524
  const version = this.artifactVersion;
1181
- if (!version || this.fallbackBusy)
1525
+ if (!version || this.FallbackBusy)
1182
1526
  return;
1183
- this.fallbackBusy = true;
1527
+ this.FallbackBusy = true;
1184
1528
  try {
1185
1529
  let objectUrl = null;
1186
1530
  if (version.ContentMode === 'File') {
@@ -1206,7 +1550,7 @@ export class ArtifactViewerPanelComponent extends BaseAngularComponent {
1206
1550
  return;
1207
1551
  const a = document.createElement('a');
1208
1552
  a.href = objectUrl;
1209
- a.download = this.fallbackFileName;
1553
+ a.download = this.FallbackFileName;
1210
1554
  a.rel = 'noopener';
1211
1555
  document.body.appendChild(a);
1212
1556
  a.click();
@@ -1214,10 +1558,14 @@ export class ArtifactViewerPanelComponent extends BaseAngularComponent {
1214
1558
  setTimeout(() => URL.revokeObjectURL(objectUrl), 60_000);
1215
1559
  }
1216
1560
  finally {
1217
- this.fallbackBusy = false;
1561
+ this.FallbackBusy = false;
1218
1562
  this.cdr.markForCheck();
1219
1563
  }
1220
1564
  }
1565
+ /** @deprecated Use {@link DownloadArtifactFile}. */
1566
+ async downloadArtifactFile() {
1567
+ return this.DownloadArtifactFile();
1568
+ }
1221
1569
  formatBytes(n) {
1222
1570
  if (n < 1024)
1223
1571
  return `${n} B`;
@@ -1225,50 +1573,70 @@ export class ArtifactViewerPanelComponent extends BaseAngularComponent {
1225
1573
  return `${(n / 1024).toFixed(1)} KB`;
1226
1574
  return `${(n / (1024 * 1024)).toFixed(1)} MB`;
1227
1575
  }
1228
- get hasPlugin() {
1576
+ get HasPlugin() {
1229
1577
  // Check if the artifact type has a DriverClass configured
1230
1578
  // If DriverClass is set, we have a plugin available
1231
1579
  return !!this.artifactTypeDriverClass;
1232
1580
  }
1233
- get hasJsonTab() {
1581
+ /** @deprecated Use {@link HasPlugin}. */
1582
+ get hasPlugin() {
1583
+ return this.HasPlugin;
1584
+ }
1585
+ get HasJsonTab() {
1234
1586
  // Query plugin directly (no cache needed - plugin always exists when it should)
1235
- const pluginInstance = this.pluginViewer?.pluginInstance;
1587
+ const pluginInstance = this.PluginViewer?.pluginInstance;
1236
1588
  return pluginInstance?.parentShouldShowRawContent || false;
1237
1589
  }
1590
+ /** @deprecated Use {@link HasJsonTab}. */
1591
+ get hasJsonTab() {
1592
+ return this.HasJsonTab;
1593
+ }
1594
+ get ArtifactTypeName() {
1595
+ return this.Artifact?.Type || '';
1596
+ }
1597
+ /** @deprecated Use {@link ArtifactTypeName}. */
1238
1598
  get artifactTypeName() {
1239
- return this.artifact?.Type || '';
1599
+ return this.ArtifactTypeName;
1240
1600
  }
1241
- get contentType() {
1601
+ get ContentType() {
1242
1602
  // Try to get content type from artifact type or attributes
1243
- const contentTypeAttr = this.versionAttributes.find(a => a.Name?.toLowerCase() === 'contenttype');
1603
+ const contentTypeAttr = this.VersionAttributes.find(a => a.Name?.toLowerCase() === 'contenttype');
1244
1604
  return contentTypeAttr?.Value || undefined;
1245
1605
  }
1246
- get filteredAttributes() {
1606
+ /** @deprecated Use {@link ContentType}. */
1607
+ get contentType() {
1608
+ return this.ContentType;
1609
+ }
1610
+ get FilteredAttributes() {
1247
1611
  // Filter out displayMarkdown and displayHtml as they're shown in the Display tab
1248
- return this.versionAttributes.filter(attr => {
1612
+ return this.VersionAttributes.filter(attr => {
1249
1613
  const name = attr.Name?.toLowerCase();
1250
1614
  return name !== 'displaymarkdown' && name !== 'displayhtml';
1251
1615
  });
1252
1616
  }
1617
+ /** @deprecated Use {@link FilteredAttributes}. */
1618
+ get filteredAttributes() {
1619
+ return this.FilteredAttributes;
1620
+ }
1253
1621
  setActiveTab(tab) {
1254
- this.activeTab = tab;
1622
+ this.ActiveTab = tab;
1255
1623
  }
1256
1624
  /**
1257
1625
  * Sets the active tab to the first available tab in the list.
1258
1626
  * Called when tabs change or when the currently active tab becomes unavailable.
1259
1627
  */
1260
1628
  setActiveTabToFirstAvailable() {
1261
- const tabs = this.allTabs;
1629
+ const tabs = this.AllTabs;
1262
1630
  if (tabs.length > 0) {
1263
1631
  // If current tab is still available, keep it; otherwise switch to first
1264
- const currentTabStillAvailable = tabs.some(t => t.toLowerCase() === this.activeTab.toLowerCase());
1632
+ const currentTabStillAvailable = tabs.some(t => t.toLowerCase() === this.ActiveTab.toLowerCase());
1265
1633
  if (!currentTabStillAvailable) {
1266
- this.activeTab = tabs[0].toLowerCase();
1634
+ this.ActiveTab = tabs[0].toLowerCase();
1267
1635
  }
1268
1636
  }
1269
1637
  else {
1270
1638
  // Fallback to details if no tabs available (shouldn't happen)
1271
- this.activeTab = 'details';
1639
+ this.ActiveTab = 'details';
1272
1640
  }
1273
1641
  }
1274
1642
  /**
@@ -1276,28 +1644,36 @@ export class ArtifactViewerPanelComponent extends BaseAngularComponent {
1276
1644
  * the full spec from the registry after initial render with a stripped spec).
1277
1645
  * Forces re-evaluation of allTabs so new tab labels render correctly.
1278
1646
  */
1279
- onTabsChanged() {
1647
+ OnTabsChanged() {
1280
1648
  // If Display tab just became available (e.g., after plugin async load),
1281
1649
  // switch to it — it should be the default when present.
1282
- const tabs = this.allTabs;
1283
- if (tabs.length > 0 && tabs[0].toLowerCase() === 'display' && this.activeTab !== 'display') {
1284
- this.activeTab = 'display';
1650
+ const tabs = this.AllTabs;
1651
+ if (tabs.length > 0 && tabs[0].toLowerCase() === 'display' && this.ActiveTab !== 'display') {
1652
+ this.ActiveTab = 'display';
1285
1653
  }
1286
1654
  this.cdr.detectChanges(); // zone.js 0.15: plugin emitted tabsChanged, force CD to re-evaluate allTabs
1287
1655
  }
1656
+ /** @deprecated Use {@link OnTabsChanged}. */
1657
+ onTabsChanged() {
1658
+ return this.OnTabsChanged();
1659
+ }
1288
1660
  /**
1289
1661
  * Called when the plugin viewer finishes loading.
1290
1662
  * Selects the first available tab now that plugin tabs are available.
1291
1663
  */
1292
- onPluginLoaded() {
1664
+ OnPluginLoaded() {
1293
1665
  // Now that plugin is loaded, we have accurate tab information
1294
1666
  // Always select the first tab since this is the initial load
1295
- const tabs = this.allTabs;
1667
+ const tabs = this.AllTabs;
1296
1668
  if (tabs.length > 0) {
1297
- this.activeTab = tabs[0].toLowerCase();
1669
+ this.ActiveTab = tabs[0].toLowerCase();
1298
1670
  }
1299
1671
  this.cdr.detectChanges(); // zone.js 0.15: plugin loaded via async callback, force CD
1300
1672
  }
1673
+ /** @deprecated Use {@link OnPluginLoaded}. */
1674
+ onPluginLoaded() {
1675
+ return this.OnPluginLoaded();
1676
+ }
1301
1677
  parseAttributeValue(value) {
1302
1678
  if (!value)
1303
1679
  return null;
@@ -1352,42 +1728,42 @@ export class ArtifactViewerPanelComponent extends BaseAngularComponent {
1352
1728
  )`,
1353
1729
  Fields: ['ID', 'CollectionID', 'ArtifactVersionID', 'Sequence'],
1354
1730
  ResultType: 'simple'
1355
- }, this.currentUser);
1731
+ }, this.CurrentUser);
1356
1732
  collectionRows = (result.Success ? result.Results : []);
1357
1733
  }
1358
1734
  if (!isCurrentLoad()) {
1359
1735
  return;
1360
1736
  }
1361
1737
  // Store as simple objects — these are read-only display data
1362
- this.artifactCollections = collectionRows;
1738
+ this.ArtifactCollections = collectionRows;
1363
1739
  // Filter to get only collections containing the CURRENT version
1364
1740
  const currentVersionId = this.artifactVersion?.ID;
1365
1741
  if (currentVersionId) {
1366
1742
  const currentIdStr = String(currentVersionId).toLowerCase();
1367
- this.currentVersionCollections = collectionRows.filter(ca => {
1743
+ this.CurrentVersionCollections = collectionRows.filter(ca => {
1368
1744
  const versionIdStr = String(ca['ArtifactVersionID'] || ca.ArtifactVersionID || '').toLowerCase();
1369
1745
  return versionIdStr && currentIdStr && versionIdStr === currentIdStr;
1370
1746
  });
1371
1747
  }
1372
1748
  else {
1373
- this.currentVersionCollections = [];
1749
+ this.CurrentVersionCollections = [];
1374
1750
  }
1375
1751
  // Load the primary collection details if exists
1376
- if (this.artifactCollections.length > 0) {
1752
+ if (this.ArtifactCollections.length > 0) {
1377
1753
  const collectionId = collectionRows[0].CollectionID ||
1378
- this.artifactCollections[0].CollectionID;
1754
+ this.ArtifactCollections[0].CollectionID;
1379
1755
  if (collectionId) {
1380
1756
  const md = this.ProviderToUse;
1381
- const primaryCollection = await md.GetEntityObject('MJ: Collections', this.currentUser);
1757
+ const primaryCollection = await md.GetEntityObject('MJ: Collections', this.CurrentUser);
1382
1758
  await primaryCollection.Load(collectionId);
1383
1759
  if (!isCurrentLoad()) {
1384
1760
  return;
1385
1761
  }
1386
- this.primaryCollection = primaryCollection;
1762
+ this.PrimaryCollection = primaryCollection;
1387
1763
  }
1388
1764
  }
1389
1765
  else {
1390
- this.primaryCollection = null;
1766
+ this.PrimaryCollection = null;
1391
1767
  }
1392
1768
  }
1393
1769
  catch (err) {
@@ -1409,53 +1785,69 @@ export class ArtifactViewerPanelComponent extends BaseAngularComponent {
1409
1785
  async loadCollectionAssociations() {
1410
1786
  return this.processCollectionAssociations();
1411
1787
  }
1788
+ get IsInCollection() {
1789
+ return this.CurrentVersionCollections.length > 0;
1790
+ }
1791
+ /** @deprecated Use {@link IsInCollection}. */
1412
1792
  get isInCollection() {
1413
- return this.currentVersionCollections.length > 0;
1793
+ return this.IsInCollection;
1414
1794
  }
1415
1795
  /**
1416
1796
  * Get collection IDs that already contain the current version
1417
1797
  * Used to exclude them from the save picker
1418
1798
  */
1799
+ get CurrentVersionCollectionIds() {
1800
+ return this.CurrentVersionCollections.map(ca => ca.CollectionID);
1801
+ }
1802
+ /** @deprecated Use {@link CurrentVersionCollectionIds}. */
1419
1803
  get currentVersionCollectionIds() {
1420
- return this.currentVersionCollections.map(ca => ca.CollectionID);
1804
+ return this.CurrentVersionCollectionIds;
1421
1805
  }
1422
- onCopyToClipboard() {
1806
+ OnCopyToClipboard() {
1423
1807
  // Get content from the currently active tab instead of always copying jsonContent
1424
- const tabData = this.GetTabContent(this.activeTab);
1808
+ const tabData = this.GetTabContent(this.ActiveTab);
1425
1809
  if (tabData?.content) {
1426
1810
  navigator.clipboard.writeText(tabData.content);
1427
1811
  }
1428
- else if (this.jsonContent) {
1812
+ else if (this.JsonContent) {
1429
1813
  // Fallback to jsonContent if tab content not found
1430
- navigator.clipboard.writeText(this.jsonContent);
1814
+ navigator.clipboard.writeText(this.JsonContent);
1431
1815
  }
1432
1816
  }
1433
- onCopyDisplayContent() {
1434
- const content = this.displayHtml || this.displayMarkdown;
1817
+ /** @deprecated Use {@link OnCopyToClipboard}. */
1818
+ onCopyToClipboard() {
1819
+ return this.OnCopyToClipboard();
1820
+ }
1821
+ OnCopyDisplayContent() {
1822
+ const content = this.DisplayHtml || this.DisplayMarkdown;
1435
1823
  if (content) {
1436
1824
  navigator.clipboard.writeText(content).catch(err => {
1437
1825
  console.error('Failed to copy to clipboard:', err);
1438
1826
  });
1439
1827
  }
1440
1828
  }
1441
- onPrintDisplayContent() {
1829
+ /** @deprecated Use {@link OnCopyDisplayContent}. */
1830
+ onCopyDisplayContent() {
1831
+ return this.OnCopyDisplayContent();
1832
+ }
1833
+ OnPrintDisplayContent() {
1442
1834
  // Try to delegate to the plugin viewer's print method
1443
- if (this.pluginViewer?.pluginInstance) {
1444
- const plugin = this.pluginViewer.pluginInstance;
1835
+ if (this.PluginViewer?.pluginInstance) {
1836
+ const plugin = this.PluginViewer.pluginInstance;
1445
1837
  if (typeof plugin.printHtml === 'function') {
1446
1838
  plugin.printHtml();
1447
1839
  return;
1448
1840
  }
1449
1841
  }
1450
1842
  // Fallback: create a temporary print window with displayHtml or displayMarkdown
1451
- const content = this.displayHtml || this.displayMarkdown;
1843
+ const content = this.DisplayHtml || this.DisplayMarkdown;
1452
1844
  if (content) {
1453
1845
  const printWindow = window.open('', '_blank');
1454
1846
  if (printWindow) {
1455
- if (this.displayHtml) {
1847
+ if (this.DisplayHtml) {
1456
1848
  printWindow.document.write(content);
1457
1849
  }
1458
- else if (this.displayMarkdown) {
1850
+ else if (this.DisplayMarkdown) {
1459
1851
  // Wrap markdown in basic HTML for printing
1460
1852
  printWindow.document.write(`
1461
1853
  <!DOCTYPE html>
@@ -1482,19 +1874,27 @@ export class ArtifactViewerPanelComponent extends BaseAngularComponent {
1482
1874
  }
1483
1875
  }
1484
1876
  }
1485
- toggleVersionDropdown() {
1486
- if (this.allVersions.length > 1) {
1487
- this.showVersionDropdown = !this.showVersionDropdown;
1877
+ /** @deprecated Use {@link OnPrintDisplayContent}. */
1878
+ onPrintDisplayContent() {
1879
+ return this.OnPrintDisplayContent();
1880
+ }
1881
+ ToggleVersionDropdown() {
1882
+ if (this.AllVersions.length > 1) {
1883
+ this.ShowVersionDropdown = !this.ShowVersionDropdown;
1488
1884
  }
1489
1885
  }
1490
- async selectVersion(version) {
1491
- this.selectedVersionNumber = version.VersionNumber || 1;
1492
- this.showVersionDropdown = false;
1886
+ /** @deprecated Use {@link ToggleVersionDropdown}. */
1887
+ toggleVersionDropdown() {
1888
+ return this.ToggleVersionDropdown();
1889
+ }
1890
+ async SelectVersion(version) {
1891
+ this.SelectedVersionNumber = version.VersionNumber || 1;
1892
+ this.ShowVersionDropdown = false;
1493
1893
  // Load full content for the selected version (allVersions only has metadata)
1494
1894
  const fullVersion = await this.loadVersionContent(version.ID);
1495
1895
  if (fullVersion) {
1496
1896
  this.artifactVersion = fullVersion;
1497
- this.jsonContent = this.FormatJSON(fullVersion.Content || '{}');
1897
+ this.JsonContent = this.formatJSON(fullVersion.Content || '{}');
1498
1898
  }
1499
1899
  // Load attributes and collection data in parallel
1500
1900
  await Promise.all([
@@ -1504,22 +1904,34 @@ export class ArtifactViewerPanelComponent extends BaseAngularComponent {
1504
1904
  ]);
1505
1905
  this.cdr.detectChanges();
1506
1906
  }
1507
- async onSaveToLibrary() {
1907
+ /** @deprecated Use {@link SelectVersion}. */
1908
+ async selectVersion(version) {
1909
+ return this.SelectVersion(version);
1910
+ }
1911
+ async OnSaveToLibrary() {
1508
1912
  // Always show the collection picker modal
1509
1913
  // Artifacts can be saved to multiple collections
1510
- this.saveToCollectionRequested.emit({
1914
+ this.SaveToCollectionRequested.emit({
1511
1915
  artifactId: this.artifactId,
1512
- excludedCollectionIds: this.excludedCollectionIds
1916
+ excludedCollectionIds: this.ExcludedCollectionIds
1513
1917
  });
1514
1918
  }
1515
- get excludedCollectionIds() {
1919
+ /** @deprecated Use {@link OnSaveToLibrary}. */
1920
+ async onSaveToLibrary() {
1921
+ return this.OnSaveToLibrary();
1922
+ }
1923
+ get ExcludedCollectionIds() {
1516
1924
  // Return IDs of collections that already contain the CURRENT VERSION
1517
1925
  // This allows saving different versions to the same collection
1518
- const excluded = this.currentVersionCollections
1926
+ const excluded = this.CurrentVersionCollections
1519
1927
  .filter(ca => ca.CollectionID)
1520
1928
  .map(ca => String(ca.CollectionID));
1521
1929
  return excluded;
1522
1930
  }
1931
+ /** @deprecated Use {@link ExcludedCollectionIds}. */
1932
+ get excludedCollectionIds() {
1933
+ return this.ExcludedCollectionIds;
1934
+ }
1523
1935
  /**
1524
1936
  * Reload the cached set of collections that contain the *current version* of this artifact.
1525
1937
  * Called by the chat-area after the collection picker reports successful saves so the bookmark
@@ -1555,12 +1967,12 @@ export class ArtifactViewerPanelComponent extends BaseAngularComponent {
1555
1967
  EntityName: 'MJ: Collection Artifacts',
1556
1968
  ExtraFilter: `CollectionID='${collectionId}' AND ArtifactVersionID='${currentVersionId}'`,
1557
1969
  ResultType: 'entity_object'
1558
- }, this.currentUser);
1970
+ }, this.CurrentUser);
1559
1971
  if (existingResult.Success && existingResult.Results && existingResult.Results.length > 0) {
1560
1972
  continue;
1561
1973
  }
1562
1974
  // Create junction record with version ID
1563
- const collectionArtifact = await md.GetEntityObject('MJ: Collection Artifacts', this.currentUser);
1975
+ const collectionArtifact = await md.GetEntityObject('MJ: Collection Artifacts', this.CurrentUser);
1564
1976
  collectionArtifact.CollectionID = collectionId;
1565
1977
  collectionArtifact.ArtifactVersionID = currentVersionId;
1566
1978
  collectionArtifact.Sequence = 0;
@@ -1616,7 +2028,7 @@ export class ArtifactViewerPanelComponent extends BaseAngularComponent {
1616
2028
  )`,
1617
2029
  Fields: ['ID', 'CollectionID', 'ArtifactVersionID'],
1618
2030
  ResultType: 'simple'
1619
- }, this.currentUser);
2031
+ }, this.CurrentUser);
1620
2032
  collectionRows = (result.Success ? result.Results : []);
1621
2033
  }
1622
2034
  if (!isCurrentLoad()) {
@@ -1631,12 +2043,12 @@ export class ArtifactViewerPanelComponent extends BaseAngularComponent {
1631
2043
  ExtraFilter: collectionsFilter,
1632
2044
  Fields: ['ID', 'Name', 'UserID', 'Description'],
1633
2045
  ResultType: 'simple'
1634
- }, this.currentUser);
2046
+ }, this.CurrentUser);
1635
2047
  if (!isCurrentLoad()) {
1636
2048
  return;
1637
2049
  }
1638
2050
  if (collectionsEntityResult.Success && collectionsEntityResult.Results) {
1639
- this.allCollections = collectionsEntityResult.Results;
2051
+ this.AllCollections = collectionsEntityResult.Results;
1640
2052
  }
1641
2053
  }
1642
2054
  // Use pre-fetched conversation detail artifact data or fetch if not provided
@@ -1645,7 +2057,7 @@ export class ArtifactViewerPanelComponent extends BaseAngularComponent {
1645
2057
  convDetailRows = convDetailResult.Results;
1646
2058
  }
1647
2059
  else {
1648
- const versionIds = this.allVersions.map(v => v.ID);
2060
+ const versionIds = this.AllVersions.map(v => v.ID);
1649
2061
  if (versionIds.length > 0) {
1650
2062
  const versionFilter = versionIds.map(id => `ArtifactVersionID='${id}'`).join(' OR ');
1651
2063
  const result = await rv.RunView({
@@ -1654,7 +2066,7 @@ export class ArtifactViewerPanelComponent extends BaseAngularComponent {
1654
2066
  Fields: ['ID', 'ConversationDetailID', 'ArtifactVersionID'],
1655
2067
  MaxRows: 1,
1656
2068
  ResultType: 'simple'
1657
- }, this.currentUser);
2069
+ }, this.CurrentUser);
1658
2070
  convDetailRows = (result.Success ? result.Results : []);
1659
2071
  }
1660
2072
  }
@@ -1668,37 +2080,37 @@ export class ArtifactViewerPanelComponent extends BaseAngularComponent {
1668
2080
  if (!isCurrentLoad()) {
1669
2081
  return;
1670
2082
  }
1671
- this.originConversationVersionId = artifactVersionId;
2083
+ this.OriginConversationVersionId = artifactVersionId;
1672
2084
  // Load conversation detail to get conversation ID
1673
- const conversationDetail = await md.GetEntityObject('MJ: Conversation Details', this.currentUser);
2085
+ const conversationDetail = await md.GetEntityObject('MJ: Conversation Details', this.CurrentUser);
1674
2086
  const detailLoaded = await conversationDetail.Load(conversationDetailId);
1675
2087
  if (!isCurrentLoad()) {
1676
2088
  return;
1677
2089
  }
1678
2090
  if (detailLoaded && conversationDetail.ConversationID) {
1679
- const conversation = await md.GetEntityObject('MJ: Conversations', this.currentUser);
2091
+ const conversation = await md.GetEntityObject('MJ: Conversations', this.CurrentUser);
1680
2092
  const loaded = await conversation.Load(conversationDetail.ConversationID);
1681
2093
  if (!isCurrentLoad()) {
1682
2094
  return;
1683
2095
  }
1684
2096
  if (loaded) {
1685
2097
  // Check if user has access (is owner or participant)
1686
- const userIsOwner = UUIDsEqual(conversation.UserID, this.currentUser.ID);
2098
+ const userIsOwner = UUIDsEqual(conversation.UserID, this.CurrentUser.ID);
1687
2099
  const participantResult = await rv.RunView({
1688
2100
  EntityName: 'MJ: Conversation Details',
1689
- ExtraFilter: `ConversationID='${conversation.ID}' AND UserID='${this.currentUser.ID}'`,
2101
+ ExtraFilter: `ConversationID='${conversation.ID}' AND UserID='${this.CurrentUser.ID}'`,
1690
2102
  MaxRows: 1,
1691
2103
  Fields: ['ID'],
1692
2104
  ResultType: 'simple'
1693
- }, this.currentUser);
2105
+ }, this.CurrentUser);
1694
2106
  if (!isCurrentLoad()) {
1695
2107
  return;
1696
2108
  }
1697
2109
  const userIsParticipant = participantResult.Success &&
1698
2110
  participantResult.Results &&
1699
2111
  participantResult.Results.length > 0;
1700
- this.originConversation = conversation;
1701
- this.hasAccessToOriginConversation = userIsOwner || userIsParticipant;
2112
+ this.OriginConversation = conversation;
2113
+ this.HasAccessToOriginConversation = userIsOwner || userIsParticipant;
1702
2114
  }
1703
2115
  }
1704
2116
  }
@@ -1721,15 +2133,15 @@ export class ArtifactViewerPanelComponent extends BaseAngularComponent {
1721
2133
  async loadLinksData() {
1722
2134
  return this.processLinksData();
1723
2135
  }
1724
- get linksToShow() {
2136
+ get LinksToShow() {
1725
2137
  const links = [];
1726
2138
  // Get current version ID being viewed
1727
2139
  const currentVersionId = this.artifactVersion?.ID;
1728
2140
  // RULE: In conversation context, show ONLY collection links
1729
2141
  // RULE: In collection context, show ONLY conversation links
1730
- if (this.viewContext === 'conversation') {
2142
+ if (this.ViewContext === 'conversation') {
1731
2143
  // Show all collections containing this artifact (any version)
1732
- for (const collection of this.allCollections) {
2144
+ for (const collection of this.AllCollections) {
1733
2145
  links.push({
1734
2146
  type: 'collection',
1735
2147
  id: collection.ID,
@@ -1738,60 +2150,88 @@ export class ArtifactViewerPanelComponent extends BaseAngularComponent {
1738
2150
  });
1739
2151
  }
1740
2152
  }
1741
- else if (this.viewContext === 'collection') {
2153
+ else if (this.ViewContext === 'collection') {
1742
2154
  // Show origin conversation if it exists
1743
2155
  // Show for ALL versions of the artifact, not just the original version that was added
1744
- if (this.originConversation) {
2156
+ if (this.OriginConversation) {
1745
2157
  links.push({
1746
2158
  type: 'conversation',
1747
- id: this.originConversation.ID,
1748
- name: this.originConversation.Name || 'Untitled Conversation',
1749
- hasAccess: this.hasAccessToOriginConversation
2159
+ id: this.OriginConversation.ID,
2160
+ name: this.OriginConversation.Name || 'Untitled Conversation',
2161
+ hasAccess: this.HasAccessToOriginConversation
1750
2162
  });
1751
2163
  }
1752
2164
  }
1753
2165
  // If viewContext is null, show nothing (no links)
1754
2166
  return links;
1755
2167
  }
2168
+ /** @deprecated Use {@link LinksToShow}. */
2169
+ get linksToShow() {
2170
+ return this.LinksToShow;
2171
+ }
1756
2172
  /**
1757
2173
  * Navigate to a linked conversation or collection
1758
2174
  */
1759
- onNavigateToLink(link) {
2175
+ OnNavigateToLink(link) {
1760
2176
  if (!link.hasAccess) {
1761
2177
  return;
1762
2178
  }
1763
2179
  // Include artifact ID, version number, and version ID so destination can show the artifact with correct URL
1764
- this.navigateToLink.emit({
2180
+ this.NavigateToLink.emit({
1765
2181
  type: link.type,
1766
2182
  id: link.id,
1767
2183
  artifactId: this.artifactId,
1768
- versionNumber: this.selectedVersionNumber,
2184
+ versionNumber: this.SelectedVersionNumber,
1769
2185
  versionId: this.artifactVersion?.ID
1770
2186
  });
1771
2187
  }
2188
+ /** @deprecated Use {@link OnNavigateToLink}. */
2189
+ onNavigateToLink(link) {
2190
+ return this.OnNavigateToLink(link);
2191
+ }
2192
+ OnClose() {
2193
+ this.Closed.emit();
2194
+ }
2195
+ /** @deprecated Use {@link OnClose}. */
1772
2196
  onClose() {
1773
- this.closed.emit();
2197
+ return this.OnClose();
1774
2198
  }
2199
+ OnShare() {
2200
+ this.ShareRequested.emit(this.artifactId);
2201
+ }
2202
+ /** @deprecated Use {@link OnShare}. */
1775
2203
  onShare() {
1776
- this.shareRequested.emit(this.artifactId);
2204
+ return this.OnShare();
2205
+ }
2206
+ OnMaximizeToggle() {
2207
+ this.MaximizeToggled.emit();
1777
2208
  }
2209
+ /** @deprecated Use {@link OnMaximizeToggle}. */
1778
2210
  onMaximizeToggle() {
1779
- this.maximizeToggled.emit();
2211
+ return this.OnMaximizeToggle();
1780
2212
  }
1781
2213
  /**
1782
2214
  * Handle entity record open request from artifact viewer plugin (React component)
1783
2215
  * Propagates the event up to parent components
1784
2216
  */
2217
+ OnOpenEntityRecord(event) {
2218
+ this.OpenEntityRecord.emit(event);
2219
+ }
2220
+ /** @deprecated Use {@link OnOpenEntityRecord}. */
1785
2221
  onOpenEntityRecord(event) {
1786
- this.openEntityRecord.emit(event);
2222
+ return this.OnOpenEntityRecord(event);
1787
2223
  }
1788
2224
  /**
1789
2225
  * Handle navigation request from artifact viewer plugin.
1790
2226
  * Propagates the event up to parent components for app-level navigation.
1791
2227
  */
1792
- onNavigationRequest(event) {
2228
+ OnNavigationRequest(event) {
1793
2229
  this.navigationRequest.emit(event);
1794
2230
  }
2231
+ /** @deprecated Use {@link OnNavigationRequest}. */
2232
+ onNavigationRequest(event) {
2233
+ return this.OnNavigationRequest(event);
2234
+ }
1795
2235
  /**
1796
2236
  * Resolves the DriverClass for an artifact type by traversing up the parent hierarchy.
1797
2237
  * Returns the first DriverClass found, or null if none found in the hierarchy.
@@ -1818,7 +2258,7 @@ export class ArtifactViewerPanelComponent extends BaseAngularComponent {
1818
2258
  async getArtifactTypeById(id) {
1819
2259
  try {
1820
2260
  const md = this.ProviderToUse;
1821
- const artifactType = await md.GetEntityObject('MJ: Artifact Types', this.currentUser);
2261
+ const artifactType = await md.GetEntityObject('MJ: Artifact Types', this.CurrentUser);
1822
2262
  const loaded = await artifactType.Load(id);
1823
2263
  if (loaded) {
1824
2264
  return artifactType;
@@ -1833,7 +2273,7 @@ export class ArtifactViewerPanelComponent extends BaseAngularComponent {
1833
2273
  /**
1834
2274
  * Format JSON content using ParseJSONRecursive for deep parsing and formatting
1835
2275
  */
1836
- FormatJSON(content) {
2276
+ formatJSON(content) {
1837
2277
  try {
1838
2278
  // First parse the JSON string to an object
1839
2279
  const obj = JSON.parse(content);
@@ -1875,7 +2315,7 @@ export class ArtifactViewerPanelComponent extends BaseAngularComponent {
1875
2315
  return baseIcons[tabName];
1876
2316
  }
1877
2317
  // Check plugin tabs
1878
- const plugin = this.pluginViewer?.pluginInstance;
2318
+ const plugin = this.PluginViewer?.pluginInstance;
1879
2319
  if (plugin?.GetAdditionalTabs) {
1880
2320
  const pluginTab = plugin.GetAdditionalTabs().find((t) => t.label === tabName);
1881
2321
  if (pluginTab?.icon) {
@@ -1888,24 +2328,24 @@ export class ArtifactViewerPanelComponent extends BaseAngularComponent {
1888
2328
  * Set active tab
1889
2329
  */
1890
2330
  SetActiveTab(tabName) {
1891
- this.activeTab = tabName.toLowerCase();
2331
+ this.ActiveTab = tabName.toLowerCase();
1892
2332
  }
1893
2333
  /**
1894
2334
  * Track artifact usage event
1895
2335
  */
1896
2336
  async trackArtifactUsage(usageType) {
1897
2337
  try {
1898
- if (!this.artifactVersion?.ID || !this.currentUser?.ID) {
2338
+ if (!this.artifactVersion?.ID || !this.CurrentUser?.ID) {
1899
2339
  return;
1900
2340
  }
1901
2341
  const md = this.ProviderToUse;
1902
2342
  const usage = await md.GetEntityObject('MJ: Artifact Uses');
1903
2343
  usage.ArtifactVersionID = this.artifactVersion.ID;
1904
- usage.UserID = this.currentUser.ID;
2344
+ usage.UserID = this.CurrentUser.ID;
1905
2345
  usage.UsageType = usageType;
1906
2346
  usage.UsageContext = JSON.stringify({
1907
- viewContext: this.viewContext,
1908
- contextCollectionId: this.contextCollectionId,
2347
+ viewContext: this.ViewContext,
2348
+ contextCollectionId: this.ContextCollectionId,
1909
2349
  timestamp: new Date().toISOString()
1910
2350
  });
1911
2351
  // Save asynchronously - don't block UI
@@ -1922,11 +2362,19 @@ export class ArtifactViewerPanelComponent extends BaseAngularComponent {
1922
2362
  * Fallback priority: Plugin icon > Metadata icon > Hardcoded mapping > Generic icon
1923
2363
  */
1924
2364
  /** Cached icon class — set once after artifact loads to avoid mid-cycle flicker */
1925
- artifactIcon = 'fa-file';
2365
+ ArtifactIcon = 'fa-file';
2366
+ /** @deprecated Use {@link ArtifactIcon}. */
2367
+ get artifactIcon() {
2368
+ return this.ArtifactIcon;
2369
+ }
2370
+ /** @deprecated Use {@link ArtifactIcon}. */
2371
+ set artifactIcon(value) {
2372
+ this.ArtifactIcon = value;
2373
+ }
1926
2374
  /** Update the cached icon from the loaded artifact */
1927
2375
  updateArtifactIcon() {
1928
- this.artifactIcon = this.artifact
1929
- ? this.artifactIconService.getArtifactIcon(this.artifact)
2376
+ this.ArtifactIcon = this.Artifact
2377
+ ? this.artifactIconService.getArtifactIcon(this.Artifact)
1930
2378
  : 'fa-file';
1931
2379
  }
1932
2380
  /**
@@ -1935,9 +2383,9 @@ export class ArtifactViewerPanelComponent extends BaseAngularComponent {
1935
2383
  */
1936
2384
  OnAnalyze() {
1937
2385
  const snapshot = this.GetCurrentStateSnapshot();
1938
- if (snapshot && this.artifact) {
1939
- this.analyzeRequested.emit({
1940
- artifactId: this.artifact.ID,
2386
+ if (snapshot && this.Artifact) {
2387
+ this.AnalyzeRequested.emit({
2388
+ artifactId: this.Artifact.ID,
1941
2389
  snapshot
1942
2390
  });
1943
2391
  }
@@ -1950,15 +2398,15 @@ export class ArtifactViewerPanelComponent extends BaseAngularComponent {
1950
2398
  * Returns null if no plugin is loaded or the plugin has no snapshot.
1951
2399
  */
1952
2400
  GetCurrentStateSnapshot() {
1953
- return this.pluginViewer?.pluginInstance?.GetCurrentStateSnapshot() ?? null;
2401
+ return this.PluginViewer?.pluginInstance?.GetCurrentStateSnapshot() ?? null;
1954
2402
  }
1955
2403
  static ɵfac = function ArtifactViewerPanelComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ArtifactViewerPanelComponent)(i0.ɵɵdirectiveInject(i0.ChangeDetectorRef), i0.ɵɵdirectiveInject(i1.MJNotificationService), i0.ɵɵdirectiveInject(i2.DomSanitizer), i0.ɵɵdirectiveInject(i3.ArtifactIconService), i0.ɵɵdirectiveInject(i4.ArtifactFileService)); };
1956
2404
  static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ArtifactViewerPanelComponent, selectors: [["mj-artifact-viewer-panel"]], viewQuery: function ArtifactViewerPanelComponent_Query(rf, ctx) { if (rf & 1) {
1957
2405
  i0.ɵɵviewQuery(ArtifactTypePluginViewerComponent, 5);
1958
2406
  } if (rf & 2) {
1959
2407
  let _t;
1960
- i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.pluginViewer = _t.first);
1961
- } }, inputs: { artifactId: "artifactId", currentUser: "currentUser", environmentId: "environmentId", versionNumber: "versionNumber", showSaveToCollection: "showSaveToCollection", showHeader: "showHeader", showTabs: "showTabs", showCloseButton: "showCloseButton", showMaximizeButton: "showMaximizeButton", refreshTrigger: "refreshTrigger", viewContext: "viewContext", contextCollectionId: "contextCollectionId", canShare: "canShare", canEdit: "canEdit", isMaximized: "isMaximized" }, outputs: { closed: "closed", saveToCollectionRequested: "saveToCollectionRequested", navigateToLink: "navigateToLink", shareRequested: "shareRequested", maximizeToggled: "maximizeToggled", openEntityRecord: "openEntityRecord", navigationRequest: "navigationRequest", analyzeRequested: "analyzeRequested", applyFormRequested: "applyFormRequested" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature, i0.ɵɵNgOnChangesFeature], decls: 6, vars: 6, consts: [[1, "artifact-viewer-panel"], [1, "panel-header"], [1, "panel-content"], [1, "loading-state"], ["Variant", "error", "Icon", "fa-solid fa-triangle-exclamation", "Title", "Couldn't load artifact", "Size", "compact", 3, "Message"], [1, "artifact-content-wrapper", 3, "no-tabs"], [1, "panel-header-left"], [1, "fas", 3, "ngClass"], [1, "header-description"], [1, "panel-header-right"], [1, "version-selector", 3, "click"], [1, "fas", "fa-history"], [1, "version-label"], [1, "fas", "fa-chevron-down", "dropdown-icon", 3, "open"], [1, "version-dropdown"], ["title", "Inspect & rate components", 1, "feedback-btn"], [1, "save-to-collection-btn", 3, "in-collection", "title"], ["title", "Share", 1, "share-btn"], ["title", "Analyze this artifact with AI", 1, "analyze-btn", 3, "click"], [1, "fas", "fa-magnifying-glass-chart"], [1, "maximize-btn", 3, "title"], ["title", "Close", 1, "close-btn"], [1, "fas", "fa-chevron-down", "dropdown-icon"], [1, "version-dropdown", 3, "click"], [1, "version-option", 3, "selected"], [1, "version-option", 3, "click"], [1, "version-number"], [1, "version-date"], [1, "fas", "fa-check"], ["title", "Inspect & rate components", 1, "feedback-btn", 3, "click"], [1, "fas", "fa-star-half-stroke"], [1, "save-to-collection-btn", 3, "click", "title"], ["title", "Share", 1, "share-btn", 3, "click"], [1, "fas", "fa-share-nodes"], [1, "maximize-btn", 3, "click", "title"], ["title", "Close", 1, "close-btn", 3, "click"], [1, "fas", "fa-times"], [1, "fas", "fa-spinner", "fa-spin"], [1, "artifact-content-wrapper"], [1, "tab-navigation"], [1, "tab-content"], [1, "plugin-container", 3, "plugin-hidden"], [1, "display-content"], [1, "details-content"], [1, "artifact-meta"], [1, "meta-item"], [1, "meta-item", "full-width"], [1, "attributes-section"], [1, "links-container"], [1, "links-section"], ["Icon", "fa-solid fa-link", "Title", "No links available", "Size", "compact"], [1, "tab-btn", 3, "active"], [1, "tab-btn", 3, "click"], [3, "class"], [1, "plugin-container"], [3, "openEntityRecord", "navigationRequest", "pluginLoaded", "tabsChanged", "applyFormRequested", "artifactVersion", "artifactTypeName", "contentType", "readonly"], ["data-testid", "file-fallback", 1, "file-fallback"], [1, "display-toolbar"], ["title", "Print", 1, "btn-icon", 3, "click"], [1, "fas", "fa-print"], ["title", "Copy Content", 1, "btn-icon", 3, "click"], [1, "fas", "fa-copy"], [1, "markdown-content"], [1, "html-content", 3, "innerHTML"], [3, "data", "enableCollapsibleHeadings", "enableLineNumbers", "enableSmartypants", "enableHtml"], [1, "file-fallback-card"], ["aria-hidden", "true", 1, "fas", 3, "ngClass"], [1, "file-fallback-meta"], [1, "file-fallback-name"], [1, "file-fallback-sub"], ["type", "button", "title", "Download", 1, "btn-icon", "btn-primary", 3, "click", "disabled"], [1, "fas", "fa-download"], [1, "plaintext-viewer", "file-fallback-text"], [1, "attributes-list"], [1, "attribute-item"], [1, "attribute-empty-pill"], [1, "link-item", 3, "disabled", "clickable", "title"], [1, "link-item", 3, "click", "title"], [1, "link-icon"], [1, "fas", "fa-comments"], [1, "fas", "fa-folder"], [1, "link-content"], [1, "link-name"], [1, "link-type"], [1, "link-actions"], [1, "fas", "fa-arrow-right"], [1, "component-tab-content"], [4, "ngComponentOutlet", "ngComponentOutletInputs"], [1, "dynamic-tab-content"], [1, "markdown-viewer"], [1, "json-viewer"], [1, "code-viewer"], [1, "html-viewer", 3, "innerHTML"], [1, "plaintext-viewer"], [1, "json-toolbar"], ["title", "Copy JSON", 1, "btn-icon", 3, "click"], [1, "json-editor-container"], [2, "width", "100%", "height", "100%", 3, "value", "language", "readonly", "lineWrapping"], [1, "code-toolbar"], ["title", "Copy Code", 1, "btn-icon", 3, "click"], [1, "code-editor-container"]], template: function ArtifactViewerPanelComponent_Template(rf, ctx) { if (rf & 1) {
2408
+ i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.PluginViewer = _t.first);
2409
+ } }, inputs: { artifactId: "artifactId", CurrentUser: "CurrentUser", currentUser: "currentUser", EnvironmentId: "EnvironmentId", environmentId: "environmentId", VersionNumber: "VersionNumber", versionNumber: "versionNumber", ShowSaveToCollection: "ShowSaveToCollection", showSaveToCollection: "showSaveToCollection", ShowHeader: "ShowHeader", showHeader: "showHeader", ShowTabs: "ShowTabs", showTabs: "showTabs", ShowCloseButton: "ShowCloseButton", showCloseButton: "showCloseButton", ShowMaximizeButton: "ShowMaximizeButton", showMaximizeButton: "showMaximizeButton", RefreshTrigger: "RefreshTrigger", refreshTrigger: "refreshTrigger", ViewContext: "ViewContext", viewContext: "viewContext", ContextCollectionId: "ContextCollectionId", contextCollectionId: "contextCollectionId", canShare: "canShare", canEdit: "canEdit", IsMaximized: "IsMaximized", isMaximized: "isMaximized" }, outputs: { Closed: "Closed", closed: "closed", SaveToCollectionRequested: "SaveToCollectionRequested", saveToCollectionRequested: "saveToCollectionRequested", NavigateToLink: "NavigateToLink", navigateToLink: "navigateToLink", ShareRequested: "ShareRequested", shareRequested: "shareRequested", MaximizeToggled: "MaximizeToggled", maximizeToggled: "maximizeToggled", OpenEntityRecord: "OpenEntityRecord", openEntityRecord: "openEntityRecord", navigationRequest: "navigationRequest", AnalyzeRequested: "AnalyzeRequested", analyzeRequested: "analyzeRequested", ApplyFormRequested: "ApplyFormRequested", applyFormRequested: "applyFormRequested" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature, i0.ɵɵNgOnChangesFeature], decls: 6, vars: 6, consts: [[1, "artifact-viewer-panel"], [1, "panel-header"], [1, "panel-content"], [1, "loading-state"], ["Variant", "error", "Icon", "fa-solid fa-triangle-exclamation", "Title", "Couldn't load artifact", "Size", "compact", 3, "Message"], [1, "artifact-content-wrapper", 3, "no-tabs"], [1, "panel-header-left"], [1, "fas", 3, "ngClass"], [1, "header-description"], [1, "panel-header-right"], [1, "version-selector", 3, "click"], [1, "fas", "fa-history"], [1, "version-label"], [1, "fas", "fa-chevron-down", "dropdown-icon", 3, "open"], [1, "version-dropdown"], ["title", "Inspect & rate components", 1, "feedback-btn"], [1, "save-to-collection-btn", 3, "in-collection", "title"], ["title", "Share", 1, "share-btn"], ["title", "Analyze this artifact with AI", 1, "analyze-btn", 3, "click"], [1, "fas", "fa-magnifying-glass-chart"], [1, "maximize-btn", 3, "title"], ["title", "Close", 1, "close-btn"], [1, "fas", "fa-chevron-down", "dropdown-icon"], [1, "version-dropdown", 3, "click"], [1, "version-option", 3, "selected"], [1, "version-option", 3, "click"], [1, "version-number"], [1, "version-date"], [1, "fas", "fa-check"], ["title", "Inspect & rate components", 1, "feedback-btn", 3, "click"], [1, "fas", "fa-star-half-stroke"], [1, "save-to-collection-btn", 3, "click", "title"], ["title", "Share", 1, "share-btn", 3, "click"], [1, "fas", "fa-share-nodes"], [1, "maximize-btn", 3, "click", "title"], ["title", "Close", 1, "close-btn", 3, "click"], [1, "fas", "fa-times"], [1, "fas", "fa-spinner", "fa-spin"], [1, "artifact-content-wrapper"], [1, "tab-navigation"], [1, "tab-content"], [1, "plugin-container", 3, "plugin-hidden"], [1, "display-content"], [1, "details-content"], [1, "artifact-meta"], [1, "meta-item"], [1, "meta-item", "full-width"], [1, "attributes-section"], [1, "links-container"], [1, "links-section"], ["Icon", "fa-solid fa-link", "Title", "No links available", "Size", "compact"], [1, "tab-btn", 3, "active"], [1, "tab-btn", 3, "click"], [3, "class"], [1, "plugin-container"], [3, "openEntityRecord", "navigationRequest", "pluginLoaded", "tabsChanged", "applyFormRequested", "artifactVersion", "artifactTypeName", "contentType", "readonly"], ["data-testid", "file-fallback", 1, "file-fallback"], [1, "display-toolbar"], ["title", "Print", 1, "btn-icon", 3, "click"], [1, "fas", "fa-print"], ["title", "Copy Content", 1, "btn-icon", 3, "click"], [1, "fas", "fa-copy"], [1, "markdown-content"], [1, "html-content", 3, "innerHTML"], [3, "data", "enableCollapsibleHeadings", "enableLineNumbers", "enableSmartypants", "enableHtml"], [1, "file-fallback-card"], ["aria-hidden", "true", 1, "fas", 3, "ngClass"], [1, "file-fallback-meta"], [1, "file-fallback-name"], [1, "file-fallback-sub"], ["type", "button", "title", "Download", 1, "btn-icon", "btn-primary", 3, "click", "disabled"], [1, "fas", "fa-download"], [1, "plaintext-viewer", "file-fallback-text"], [1, "attributes-list"], [1, "attribute-item"], [1, "attribute-empty-pill"], [1, "link-item", 3, "disabled", "clickable", "title"], [1, "link-item", 3, "click", "title"], [1, "link-icon"], [1, "fas", "fa-comments"], [1, "fas", "fa-folder"], [1, "link-content"], [1, "link-name"], [1, "link-type"], [1, "link-actions"], [1, "fas", "fa-arrow-right"], [1, "component-tab-content"], [4, "ngComponentOutlet", "ngComponentOutletInputs"], [1, "dynamic-tab-content"], [1, "markdown-viewer"], [1, "json-viewer"], [1, "code-viewer"], [1, "html-viewer", 3, "innerHTML"], [1, "plaintext-viewer"], [1, "json-toolbar"], ["title", "Copy JSON", 1, "btn-icon", 3, "click"], [1, "json-editor-container"], [2, "width", "100%", "height", "100%", 3, "value", "language", "readonly", "lineWrapping"], [1, "code-toolbar"], ["title", "Copy Code", 1, "btn-icon", 3, "click"], [1, "code-editor-container"]], template: function ArtifactViewerPanelComponent_Template(rf, ctx) { if (rf & 1) {
1962
2410
  i0.ɵɵelementStart(0, "div", 0);
1963
2411
  i0.ɵɵconditionalCreate(1, ArtifactViewerPanelComponent_Conditional_1_Template, 20, 13, "div", 1);
1964
2412
  i0.ɵɵelementStart(2, "div", 2);
@@ -1983,53 +2431,93 @@ export class ArtifactViewerPanelComponent extends BaseAngularComponent {
1983
2431
  args: [{ standalone: false, selector: 'mj-artifact-viewer-panel', template: "<div class=\"artifact-viewer-panel\" [class.no-header]=\"!showHeader\">\n @if (showHeader) {\n <div class=\"panel-header\">\n <div class=\"panel-header-left\">\n <h3>\n <i class=\"fas\" [ngClass]=\"artifactIcon\"></i>\n {{ displayName }}\n </h3>\n @if (displayDescription) {\n <p class=\"header-description\">{{ displayDescription }}</p>\n }\n </div>\n <div class=\"panel-header-right\">\n <div class=\"version-selector\"\n [class.clickable]=\"allVersions.length > 1 && viewContext !== 'collection'\"\n (click)=\"viewContext !== 'collection' && toggleVersionDropdown()\">\n <i class=\"fas fa-history\"></i>\n <span class=\"version-label\">v{{ selectedVersionNumber }}</span>\n @if (allVersions.length > 1 && viewContext !== 'collection') {\n <i class=\"fas fa-chevron-down dropdown-icon\" [class.open]=\"showVersionDropdown\"></i>\n }\n @if (showVersionDropdown) {\n <div class=\"version-dropdown\" (click)=\"$event.stopPropagation()\">\n @for (version of allVersions; track version.ID) {\n <div class=\"version-option\"\n [class.selected]=\"version.VersionNumber === selectedVersionNumber\"\n (click)=\"selectVersion(version); $event.stopPropagation()\">\n <span class=\"version-number\">v{{ version.VersionNumber }}</span>\n <span class=\"version-date\">{{ version.__mj_CreatedAt | date:'short' }}</span>\n @if (version.VersionNumber === selectedVersionNumber) {\n <i class=\"fas fa-check\"></i>\n }\n </div>\n }\n </div>\n }\n </div>\n @if (pluginViewer?.SupportsFeedback) {\n <button class=\"feedback-btn\"\n (click)=\"pluginViewer?.AskUserForFeedback()\"\n title=\"Inspect & rate components\">\n <i class=\"fas fa-star-half-stroke\"></i>\n </button>\n }\n @if (showSaveToCollection) {\n <button class=\"save-to-collection-btn\"\n [class.in-collection]=\"isInCollection\"\n (click)=\"onSaveToLibrary()\"\n [title]=\"isInCollection ? 'Current version saved to ' + currentVersionCollections.length + ' collection(s)' : 'Save to Collection'\">\n <i [class]=\"isInCollection ? 'fas fa-bookmark' : 'far fa-bookmark'\"></i>\n </button>\n }\n @if (canShare) {\n <button class=\"share-btn\"\n (click)=\"onShare()\"\n title=\"Share\">\n <i class=\"fas fa-share-nodes\"></i>\n </button>\n }\n <button class=\"analyze-btn\"\n (click)=\"OnAnalyze()\"\n title=\"Analyze this artifact with AI\">\n <i class=\"fas fa-magnifying-glass-chart\"></i>\n </button>\n @if (showMaximizeButton) {\n <button class=\"maximize-btn\"\n (click)=\"onMaximizeToggle()\"\n [title]=\"isMaximized ? 'Restore Width' : 'Maximize Width'\">\n <i class=\"fas\" [ngClass]=\"isMaximized ? 'fa-compress-arrows-alt' : 'fa-arrows-left-right'\"></i>\n </button>\n }\n @if (showCloseButton) {\n <button class=\"close-btn\" (click)=\"onClose()\" title=\"Close\">\n <i class=\"fas fa-times\"></i>\n </button>\n }\n </div>\n </div>\n }\n\n <div class=\"panel-content\">\n @if (isLoading) {\n <div class=\"loading-state\">\n <i class=\"fas fa-spinner fa-spin\"></i>\n <span>Loading artifact...</span>\n </div>\n }\n\n @if (error) {\n <mj-empty-state\n Variant=\"error\"\n Icon=\"fa-solid fa-triangle-exclamation\"\n Title=\"Couldn't load artifact\"\n [Message]=\"error\"\n Size=\"compact\" />\n }\n\n @if (!isLoading && !error && artifact) {\n <div class=\"artifact-content-wrapper\" [class.no-tabs]=\"!showTabs\">\n <!-- Tab Navigation (Dynamic) - Hidden when showTabs is false -->\n @if (showTabs) {\n <div class=\"tab-navigation\">\n @for (tab of allTabs; track tab) {\n <button class=\"tab-btn\"\n [class.active]=\"activeTab === tab.toLowerCase()\"\n (click)=\"SetActiveTab(tab)\">\n @if (GetTabIcon(tab)) {\n <i [class]=\"GetTabIcon(tab)!\"></i>\n }\n {{ tab }}\n </button>\n }\n </div>\n }\n\n <!-- Tab Content (Dynamic) -->\n <div class=\"tab-content\">\n <!-- Plugin Viewer - Created once, kept alive, shown/hidden with CSS -->\n @if (hasPlugin && artifactVersion && artifactTypeName) {\n <div class=\"plugin-container\" [class.plugin-hidden]=\"activeTab !== 'display'\">\n <mj-artifact-type-plugin-viewer\n [artifactVersion]=\"artifactVersion\"\n [artifactTypeName]=\"artifactTypeName\"\n [contentType]=\"contentType\"\n [readonly]=\"true\"\n (openEntityRecord)=\"onOpenEntityRecord($event)\"\n (navigationRequest)=\"onNavigationRequest($event)\"\n (pluginLoaded)=\"onPluginLoaded()\"\n (tabsChanged)=\"onTabsChanged()\"\n (applyFormRequested)=\"applyFormRequested.emit($event)\">\n </mj-artifact-type-plugin-viewer>\n </div>\n }\n\n <!-- Display Tab - Fallback content when no plugin -->\n @if (activeTab === 'display' && (!hasPlugin || !artifactVersion)) {\n <div class=\"display-content\">\n @if (displayMarkdown || displayHtml) {\n <!-- Fallback to extracted markdown/HTML attributes -->\n <div class=\"display-toolbar\">\n <button class=\"btn-icon\" title=\"Print\" (click)=\"onPrintDisplayContent()\">\n <i class=\"fas fa-print\"></i> Print\n </button>\n <button class=\"btn-icon\" title=\"Copy Content\" (click)=\"onCopyDisplayContent()\">\n <i class=\"fas fa-copy\"></i> Copy\n </button>\n </div>\n @if (displayMarkdown) {\n <div class=\"markdown-content\">\n <mj-markdown [data]=\"displayMarkdown\"\n [enableCollapsibleHeadings]=\"true\"\n [enableLineNumbers]=\"true\"\n [enableSmartypants]=\"true\"\n [enableHtml]=\"true\"></mj-markdown>\n </div>\n } @else if (displayHtml) {\n <div class=\"html-content\" [innerHTML]=\"displayHtml\"></div>\n }\n } @else if (showFileFallback) {\n <!-- No viewer plugin for this type: a file card with a real Download, plus the text for text-like content -->\n <div class=\"file-fallback\" data-testid=\"file-fallback\">\n <div class=\"file-fallback-card\">\n <i class=\"fas\" [ngClass]=\"artifactIcon\" aria-hidden=\"true\"></i>\n <div class=\"file-fallback-meta\">\n <div class=\"file-fallback-name\">{{ fallbackFileName }}</div>\n <div class=\"file-fallback-sub\">{{ artifactVersion?.MimeType || artifact.Type }}@if (fallbackSize) { \u00B7 {{ fallbackSize }}}</div>\n </div>\n <button class=\"btn-icon btn-primary\" type=\"button\" (click)=\"downloadArtifactFile()\" [disabled]=\"fallbackBusy\" title=\"Download\">\n <i class=\"fas fa-download\"></i> {{ fallbackBusy ? 'Preparing\u2026' : 'Download' }}\n </button>\n </div>\n @if (fallbackText !== null) {\n <pre class=\"plaintext-viewer file-fallback-text\">{{ fallbackText }}</pre>\n @if (fallbackTextTruncated) {\n <div class=\"file-fallback-sub\">Showing the first part only \u2014 download the file for all of it.</div>\n }\n }\n </div>\n }\n </div>\n }\n\n <!-- Details Tab - Artifact metadata (always in DOM, hidden with CSS) -->\n <div class=\"details-content\" [class.tab-hidden]=\"activeTab !== 'details'\">\n <div class=\"artifact-meta\">\n <div class=\"meta-item\">\n <label>Type</label>\n <span>{{ artifact.Type }}</span>\n </div>\n <div class=\"meta-item\">\n <label>Version</label>\n <span>{{ artifactVersion?.VersionNumber || 1 }}</span>\n </div>\n <div class=\"meta-item\">\n <label>Created</label>\n <span>{{ artifact.__mj_CreatedAt | date:'short' }}</span>\n </div>\n <div class=\"meta-item\">\n <label>Updated</label>\n <span>{{ artifactVersion?.__mj_UpdatedAt | date:'short' }}</span>\n </div>\n @if (artifact.Description) {\n <div class=\"meta-item full-width\">\n <label>Artifact Description</label>\n <span>{{ artifact.Description }}</span>\n </div>\n }\n @if (artifactVersion?.Description && artifact.Description && artifactVersion?.Description !== artifact.Description) {\n <div class=\"meta-item full-width\">\n <label>Version Description</label>\n <span>{{ artifactVersion?.Description }}</span>\n </div>\n }\n </div>\n\n <!-- Version Attributes -->\n @if (filteredAttributes.length > 0) {\n <div class=\"attributes-section\">\n <h4>Version Attributes</h4>\n <div class=\"attributes-list\">\n @for (attr of filteredAttributes; track attr.ID) {\n <div class=\"attribute-item\">\n <label>{{ attr.Name }}</label>\n @if (attr.Value) {\n <span>{{ attr.Value }}</span>\n } @else {\n <span class=\"attribute-empty-pill\">Empty</span>\n }\n </div>\n }\n </div>\n </div>\n }\n </div>\n\n <!-- Links Tab - Conversations and Collections (always in DOM, hidden with CSS) -->\n <div class=\"links-container\" [class.tab-hidden]=\"activeTab !== 'links'\">\n @if (linksToShow.length > 0) {\n <div class=\"links-section\">\n @for (link of linksToShow; track link.id) {\n <div class=\"link-item\"\n [class.disabled]=\"!link.hasAccess\"\n [class.clickable]=\"link.hasAccess\"\n (click)=\"link.hasAccess ? onNavigateToLink(link) : null\"\n [title]=\"link.hasAccess ? 'Click to open' : 'No access'\">\n <div class=\"link-icon\">\n @if (link.type === 'conversation') {\n <i class=\"fas fa-comments\"></i>\n } @else {\n <i class=\"fas fa-folder\"></i>\n }\n </div>\n <div class=\"link-content\">\n <div class=\"link-name\">{{ link.name }}</div>\n <div class=\"link-type\">{{ link.type === 'conversation' ? 'Conversation' : 'Collection' }}</div>\n </div>\n <div class=\"link-actions\">\n <i class=\"fas fa-arrow-right\"></i>\n </div>\n </div>\n }\n </div>\n } @else {\n <mj-empty-state\n Icon=\"fa-solid fa-link\"\n Title=\"No links available\"\n Size=\"compact\" />\n }\n </div>\n\n <!-- Dynamic Plugin Tabs and Base Tabs (JSON, etc.) -->\n @if (activeTab !== 'display' && activeTab !== 'details' && activeTab !== 'links') {\n <!-- Check if this is a component tab -->\n @if (GetComponentTabType(activeTab); as componentType) {\n <div class=\"component-tab-content\">\n <ng-container *ngComponentOutlet=\"componentType; inputs: GetComponentInputs(activeTab)\"></ng-container>\n </div>\n } @else {\n @if (GetTabContent(activeTab); as tabData) {\n <div class=\"dynamic-tab-content\">\n @switch (tabData.type) {\n @case ('markdown') {\n <div class=\"markdown-viewer\">\n <mj-markdown [data]=\"tabData.content\"\n [enableCollapsibleHeadings]=\"true\"\n [enableLineNumbers]=\"true\"\n [enableSmartypants]=\"true\"\n [enableHtml]=\"true\"></mj-markdown>\n </div>\n }\n @case ('json') {\n <div class=\"json-viewer\">\n <div class=\"json-toolbar\">\n <button class=\"btn-icon\" title=\"Copy JSON\" (click)=\"onCopyToClipboard()\">\n <i class=\"fas fa-copy\"></i> Copy\n </button>\n </div>\n <div class=\"json-editor-container\">\n <mj-code-editor\n [value]=\"tabData.content\"\n [language]=\"'json'\"\n [readonly]=\"true\"\n [lineWrapping]=\"true\"\n style=\"width: 100%; height: 100%;\">\n </mj-code-editor>\n </div>\n </div>\n }\n @case ('code') {\n <div class=\"code-viewer\">\n <div class=\"code-toolbar\">\n <button class=\"btn-icon\" title=\"Copy Code\" (click)=\"onCopyToClipboard()\">\n <i class=\"fas fa-copy\"></i> Copy\n </button>\n </div>\n <div class=\"code-editor-container\">\n <mj-code-editor\n [value]=\"tabData.content\"\n [language]=\"tabData.language || 'typescript'\"\n [readonly]=\"true\"\n [lineWrapping]=\"true\"\n style=\"width: 100%; height: 100%;\">\n </mj-code-editor>\n </div>\n </div>\n }\n @case ('html') {\n <div class=\"html-viewer\" [innerHTML]=\"tabData.content\"></div>\n }\n @case ('plaintext') {\n <pre class=\"plaintext-viewer\">{{ tabData.content }}</pre>\n }\n }\n </div>\n }\n }\n }\n </div>\n </div>\n }\n </div>\n</div>\n\n", styles: [".artifact-viewer-panel {\n width: 100%;\n height: 100%;\n background: var(--mj-bg-surface);\n border-left: 1px solid var(--mj-border-default);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n box-sizing: border-box;\n}\n\n.panel-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n padding: 12px 16px;\n border-bottom: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n flex-shrink: 0;\n width: 100%;\n box-sizing: border-box;\n}\n\n.panel-header-left {\n flex: 1;\n min-width: 0;\n margin-right: 16px;\n}\n\n.panel-header h3 {\n margin: 0;\n font-size: 14px;\n font-weight: 600;\n display: flex;\n align-items: flex-start;\n gap: 8px;\n word-wrap: break-word;\n overflow-wrap: break-word;\n}\n\n.panel-header h3 i {\n color: var(--mj-brand-primary);\n flex-shrink: 0;\n margin-top: 2px;\n}\n\n.header-description {\n margin: 4px 0 0 0;\n font-size: 12px;\n color: var(--mj-text-muted);\n font-weight: normal;\n word-wrap: break-word;\n overflow-wrap: break-word;\n}\n\n.panel-header-right {\n display: flex;\n align-items: center;\n gap: 12px;\n flex-shrink: 0;\n}\n\n.version-selector {\n position: relative;\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 4px 10px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 12px;\n font-size: 12px;\n color: var(--mj-text-muted);\n font-weight: 500;\n transition: all 0.2s;\n}\n\n.version-selector.clickable {\n cursor: pointer;\n}\n\n.version-selector.clickable:hover {\n background: var(--mj-border-default);\n}\n\n.version-selector i {\n font-size: 11px;\n}\n\n.version-selector .dropdown-icon {\n margin-left: 2px;\n transition: transform 0.2s;\n}\n\n.version-selector .dropdown-icon.open {\n transform: rotate(180deg);\n}\n\n.version-label {\n font-family: monospace;\n}\n\n.version-dropdown {\n position: absolute;\n top: calc(100% + 4px);\n right: 0;\n min-width: 200px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n box-shadow: var(--mj-shadow-md);\n z-index: 1000;\n overflow: hidden;\n}\n\n.version-option {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 12px;\n cursor: pointer;\n transition: background 0.15s;\n font-size: 13px;\n}\n\n.version-option:hover {\n background: var(--mj-bg-surface-sunken);\n}\n\n.version-option.selected {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.version-option .version-number {\n font-family: monospace;\n font-weight: 600;\n min-width: 35px;\n}\n\n.version-option .version-date {\n flex: 1;\n color: var(--mj-text-muted);\n font-size: 12px;\n}\n\n.version-option i.fa-check {\n color: var(--mj-status-success);\n margin-left: auto;\n}\n\n.feedback-btn {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--mj-text-disabled);\n padding: 6px;\n border-radius: 4px;\n transition: all 0.2s;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n}\n\n.feedback-btn:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-brand-primary);\n}\n\n.feedback-btn i {\n font-size: 14px;\n}\n\n.save-to-collection-btn {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--mj-text-disabled);\n padding: 6px;\n border-radius: 4px;\n transition: all 0.2s;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n}\n\n.save-to-collection-btn:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n}\n\n.save-to-collection-btn i {\n font-size: 14px;\n}\n\n.save-to-collection-btn.in-collection {\n color: var(--mj-brand-primary);\n}\n\n.save-to-collection-btn.in-collection:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.share-btn {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--mj-text-disabled);\n padding: 6px;\n border-radius: 4px;\n transition: all 0.2s;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n}\n\n.share-btn:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-brand-primary);\n}\n\n.share-btn i {\n font-size: 14px;\n}\n\n.analyze-btn {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--mj-text-disabled);\n padding: 6px;\n border-radius: 4px;\n transition: all 0.2s;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.analyze-btn:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.analyze-btn i {\n font-size: 14px;\n}\n\n.maximize-btn {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--mj-text-muted);\n padding: 6px;\n border-radius: 4px;\n transition: all 0.2s;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n}\n\n.maximize-btn:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-primary);\n}\n\n.maximize-btn i {\n font-size: 14px;\n}\n\n.close-btn {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--mj-text-muted);\n padding: 6px;\n border-radius: 4px;\n transition: all 0.2s;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n}\n\n.close-btn:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-primary);\n}\n\n.close-btn i {\n font-size: 14px;\n}\n\n.panel-content {\n flex: 1;\n overflow: hidden;\n min-height: 0;\n display: flex;\n flex-direction: column;\n width: 100%;\n box-sizing: border-box;\n}\n\n.artifact-content-wrapper {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n min-height: 0;\n width: 100%;\n box-sizing: border-box;\n}\n\n.loading-state {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 12px;\n padding: 40px 20px;\n color: var(--mj-text-muted);\n}\n\n.loading-state i {\n font-size: 24px;\n}\n\n.artifact-meta {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));\n gap: 16px;\n margin-bottom: 16px;\n padding: 16px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n flex-shrink: 0;\n}\n\n.meta-item {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.meta-item label {\n font-size: 12px;\n font-weight: 500;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.meta-item span {\n font-size: 14px;\n color: var(--mj-text-primary);\n}\n\n.artifact-description {\n padding: 12px;\n margin-bottom: 16px;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n border-left: 3px solid var(--mj-brand-primary);\n border-radius: 4px;\n color: var(--mj-brand-primary);\n font-size: 14px;\n flex-shrink: 0;\n}\n\n.json-viewer {\n flex: 1;\n display: flex;\n flex-direction: column;\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n overflow: hidden;\n min-height: 0;\n}\n\n.json-editor-container {\n flex: 1;\n overflow: hidden;\n min-height: 0;\n}\n\n.json-toolbar {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n padding: 8px 12px;\n background: var(--mj-bg-surface-sunken);\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n.btn-icon {\n display: flex;\n align-items: center;\n gap: 6px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-strong);\n border-radius: 4px;\n padding: 6px 12px;\n cursor: pointer;\n color: var(--mj-text-secondary);\n font-size: 14px;\n transition: all 0.2s;\n}\n\n.btn-icon:hover {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-text-disabled);\n}\n\n.btn-icon.btn-primary {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n\n.btn-icon.btn-primary:hover {\n background: var(--mj-brand-primary-hover);\n border-color: var(--mj-brand-primary-hover);\n}\n\n.btn-icon i {\n font-size: 14px;\n}\n\n/* Library Dialog Styles */\n.modal-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: var(--mj-bg-overlay);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10000;\n}\n\n.modal-content {\n background: var(--mj-bg-surface);\n border-radius: 12px;\n box-shadow: var(--mj-shadow-lg);\n max-width: 500px;\n width: 90%;\n max-height: 90vh;\n display: flex;\n flex-direction: column;\n}\n\n.modal-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 16px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.modal-header h3 {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.modal-header h3 i {\n color: var(--mj-status-warning);\n}\n\n.modal-body {\n padding: 20px;\n overflow-y: auto;\n}\n\n.modal-footer {\n display: flex;\n justify-content: flex-end;\n gap: 12px;\n padding: 16px 20px;\n border-top: 1px solid var(--mj-border-default);\n}\n\n.form-section {\n margin-bottom: 20px;\n}\n\n.form-section label {\n display: block;\n margin-bottom: 8px;\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n}\n\n.form-select,\n.form-input {\n width: 100%;\n padding: 10px 12px;\n border: 1px solid var(--mj-border-strong);\n border-radius: 6px;\n font-size: 14px;\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface);\n transition: border-color 0.2s;\n}\n\n.form-select:focus,\n.form-input:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n\n.divider {\n display: flex;\n align-items: center;\n margin: 24px 0;\n color: var(--mj-text-disabled);\n font-size: 12px;\n font-weight: 500;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.divider::before,\n.divider::after {\n content: '';\n flex: 1;\n height: 1px;\n background: var(--mj-border-default);\n}\n\n.divider span {\n padding: 0 12px;\n}\n\n.create-collection-row {\n display: flex;\n gap: 8px;\n}\n\n.create-collection-row .form-input {\n flex: 1;\n}\n\n.btn {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 16px;\n border: none;\n border-radius: 6px;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s;\n white-space: nowrap;\n}\n\n.btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.btn-primary {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n\n.btn-primary:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover);\n}\n\n.btn-secondary {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-strong);\n color: var(--mj-text-secondary);\n}\n\n.btn-secondary:hover:not(:disabled) {\n background: var(--mj-bg-surface-sunken);\n}\n\n/* Tab Navigation */\n.tab-navigation {\n display: flex;\n gap: 0;\n border-bottom: 2px solid var(--mj-border-default);\n padding: 0 16px;\n background: var(--mj-bg-surface);\n}\n\n.tab-btn {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 12px 20px;\n background: transparent;\n border: none;\n border-bottom: 2px solid transparent;\n margin-bottom: -2px;\n color: var(--mj-text-muted);\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 150ms ease;\n}\n\n.tab-btn:hover {\n color: var(--mj-brand-primary);\n background: var(--mj-bg-surface-sunken);\n}\n\n.tab-btn.active {\n color: var(--mj-brand-primary);\n border-bottom-color: var(--mj-brand-primary);\n}\n\n.tab-btn i {\n font-size: 14px;\n}\n\n/* Tab Content */\n.tab-content {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: auto;\n width: 100%;\n box-sizing: border-box;\n margin-bottom: 5px;\n min-width: 0;\n min-height: 0;\n}\n\n/* Plugin Container */\n.plugin-container {\n width: 100%;\n height: 100%;\n min-height: 0;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n.plugin-container.plugin-hidden,\n.tab-hidden {\n display: none;\n}\n\n/* Ensure artifact viewer component takes full height */\n.plugin-container mj-artifact-type-plugin-viewer {\n display: flex;\n flex-direction: column;\n flex: 1;\n min-height: 0;\n width: 100%;\n}\n\n.display-content {\n flex: 1;\n display: flex;\n flex-direction: column;\n position: relative;\n width: 100%;\n box-sizing: border-box;\n overflow: hidden;\n min-height: 0;\n min-width: 0;\n padding: 7px;\n}\n\n.display-toolbar {\n position: absolute;\n top: 12px;\n right: 12px;\n display: flex;\n gap: 8px;\n z-index: 10;\n}\n\n.markdown-content,\n.html-content {\n flex: 1;\n font-size: 14px;\n line-height: 1.6;\n width: 100%;\n padding: 20px 10px 5px 20px; /* top right bottom left */\n box-sizing: border-box;\n overflow: auto;\n min-height: 0;\n}\n\n.details-content {\n padding: 20px;\n width: 100%;\n box-sizing: border-box;\n}\n\n.details-content .artifact-meta {\n margin-bottom: 0;\n padding: 20px;\n}\n\n.details-content .meta-item.full-width {\n grid-column: 1 / -1;\n}\n\n.attributes-section {\n margin-top: 24px;\n padding: 24px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n}\n\n.attributes-section h4 {\n margin: 0 0 16px 0;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.attributes-list {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));\n gap: 16px;\n}\n\n.attribute-item {\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 12px;\n background: var(--mj-bg-surface);\n border-radius: 6px;\n border: 1px solid var(--mj-border-default);\n}\n\n.attribute-item label {\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.attribute-item span {\n font-size: 13px;\n color: var(--mj-text-primary);\n word-break: break-word;\n}\n\n.attribute-empty-pill {\n display: inline-block;\n padding: 2px 8px;\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-disabled);\n font-size: 11px;\n font-weight: 500;\n border-radius: 4px;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n/* Links Tab */\n.links-container {\n padding: 20px;\n}\n\n.links-section {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.link-item {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px;\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n transition: all 0.15s;\n}\n\n.link-item.clickable {\n cursor: pointer;\n}\n\n.link-item.clickable:hover {\n border-color: var(--mj-brand-primary);\n box-shadow: var(--mj-shadow-sm);\n background: var(--mj-bg-surface-sunken);\n}\n\n.link-item.disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.link-item:hover {\n border-color: var(--mj-brand-primary);\n box-shadow: var(--mj-shadow-sm);\n}\n\n.link-icon {\n width: 40px;\n height: 40px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--mj-bg-surface);\n border-radius: 8px;\n flex-shrink: 0;\n}\n\n.link-icon i {\n font-size: 18px;\n color: var(--mj-brand-primary);\n}\n\n.link-content {\n flex: 1;\n min-width: 0;\n}\n\n.link-name {\n font-size: 14px;\n font-weight: 500;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.link-type {\n font-size: 12px;\n color: var(--mj-text-muted);\n margin-top: 2px;\n}\n\n.link-actions {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n flex-shrink: 0;\n}\n\n.link-actions i {\n font-size: 14px;\n color: var(--mj-text-muted);\n transition: all 0.15s;\n}\n\n.link-item.clickable:hover .link-actions i {\n color: var(--mj-brand-primary);\n transform: translateX(2px);\n}\n\n/* Dynamic Tab Content Styles */\n.dynamic-tab-content {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n padding: 16px;\n}\n\n/* Custom component tab content */\n.component-tab-content {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: auto;\n padding: 16px;\n}\n\n.markdown-viewer {\n flex: 1;\n overflow: auto;\n padding: 20px;\n background: var(--mj-bg-surface);\n line-height: 1.6;\n}\n\n.markdown-viewer h1, .markdown-viewer h2, .markdown-viewer h3 {\n margin-top: 24px;\n margin-bottom: 12px;\n font-weight: 600;\n}\n\n.markdown-viewer h1 { font-size: 24px; }\n.markdown-viewer h2 { font-size: 20px; }\n.markdown-viewer h3 { font-size: 18px; }\n\n.markdown-viewer p {\n margin-bottom: 12px;\n}\n\n.markdown-viewer ul, .markdown-viewer ol {\n margin-bottom: 12px;\n padding-left: 24px;\n}\n\n.markdown-viewer code {\n background: var(--mj-bg-surface-sunken);\n padding: 2px 6px;\n border-radius: 3px;\n font-family: 'Courier New', monospace;\n font-size: 13px;\n}\n\n.markdown-viewer pre {\n background: var(--mj-bg-surface-sunken);\n padding: 12px;\n border-radius: 6px;\n overflow-x: auto;\n margin-bottom: 12px;\n}\n\n.markdown-viewer pre code {\n background: none;\n padding: 0;\n}\n\n.code-viewer {\n flex: 1;\n display: flex;\n flex-direction: column;\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n overflow: hidden;\n min-height: 0;\n}\n\n.code-toolbar {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n padding: 8px 12px;\n background: var(--mj-bg-surface-sunken);\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n.code-editor-container {\n flex: 1;\n overflow: hidden;\n min-height: 0;\n}\n\n.plaintext-viewer {\n flex: 1;\n overflow: auto;\n padding: 12px;\n background: var(--mj-bg-surface-sunken);\n font-family: 'Courier New', monospace;\n font-size: 13px;\n white-space: pre-wrap;\n}\n\n.html-viewer {\n flex: 1;\n overflow: auto;\n padding: 20px;\n background: var(--mj-bg-surface);\n}\n\n/* Mobile adjustments: 481px - 768px */\n@media (max-width: 768px) {\n /* Add top border with slight visual separation from top nav */\n .artifact-viewer-panel {\n border-top: 3px solid var(--mj-brand-primary);\n position: relative;\n }\n\n /* Create a small dark strip above the blue border to separate from top nav */\n .artifact-viewer-panel::before {\n content: '';\n position: absolute;\n top: -8px;\n left: 0;\n right: 0;\n height: 8px;\n background: var(--mj-brand-secondary);\n }\n\n .tab-navigation {\n padding: 0 8px;\n overflow-x: auto;\n overflow-y: hidden;\n -webkit-overflow-scrolling: touch;\n scrollbar-width: none;\n }\n\n .tab-navigation::-webkit-scrollbar {\n display: none;\n }\n\n .tab-btn {\n padding: 10px 12px;\n font-size: 12px;\n white-space: nowrap;\n flex-shrink: 0;\n }\n\n .tab-btn i {\n font-size: 13px;\n }\n\n .panel-header {\n padding: 12px;\n }\n\n .dynamic-tab-content {\n padding: 12px;\n }\n\n .markdown-viewer {\n padding: 12px;\n }\n}\n\n/* Small Phone adjustments: <= 480px */\n@media (max-width: 480px) {\n .tab-navigation {\n padding: 0 4px;\n }\n\n .tab-btn {\n padding: 8px 10px;\n font-size: 11px;\n gap: 4px;\n }\n\n .tab-btn i {\n font-size: 12px;\n }\n\n .panel-header {\n padding: 8px;\n }\n\n .dynamic-tab-content {\n padding: 8px;\n }\n\n .markdown-viewer {\n padding: 8px;\n }\n}\n\n/* No-plugin fallback: a file card with a download action, text underneath when it is text-like */\n.file-fallback { display: flex; flex-direction: column; gap: var(--mj-space-3, 12px); padding: var(--mj-space-4, 16px); }\n.file-fallback-card {\n display: flex; align-items: center; gap: var(--mj-space-3, 12px);\n padding: var(--mj-space-3, 12px) var(--mj-space-4, 16px);\n border: 1px solid var(--mj-border-default); border-radius: var(--mj-radius-md, 8px);\n background: var(--mj-bg-surface-card, var(--mj-bg-surface));\n}\n.file-fallback-card > i { font-size: 1.5rem; color: var(--mj-brand-primary); }\n.file-fallback-meta { flex: 1; min-width: 0; }\n.file-fallback-name { font-weight: var(--mj-font-semibold, 600); color: var(--mj-text-primary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.file-fallback-sub { font-size: var(--mj-text-sm, 0.85rem); color: var(--mj-text-muted); }\n.file-fallback-text { max-height: 60vh; overflow: auto; margin: 0; }\n"] }]
1984
2432
  }], () => [{ type: i0.ChangeDetectorRef }, { type: i1.MJNotificationService }, { type: i2.DomSanitizer }, { type: i3.ArtifactIconService }, { type: i4.ArtifactFileService }], { artifactId: [{
1985
2433
  type: Input
2434
+ }], CurrentUser: [{
2435
+ type: Input
1986
2436
  }], currentUser: [{
1987
2437
  type: Input
2438
+ }], EnvironmentId: [{
2439
+ type: Input
1988
2440
  }], environmentId: [{
1989
2441
  type: Input
2442
+ }], VersionNumber: [{
2443
+ type: Input
1990
2444
  }], versionNumber: [{
1991
2445
  type: Input
2446
+ }], ShowSaveToCollection: [{
2447
+ type: Input
1992
2448
  }], showSaveToCollection: [{
1993
2449
  type: Input
2450
+ }], ShowHeader: [{
2451
+ type: Input
1994
2452
  }], showHeader: [{
1995
2453
  type: Input
2454
+ }], ShowTabs: [{
2455
+ type: Input
1996
2456
  }], showTabs: [{
1997
2457
  type: Input
2458
+ }], ShowCloseButton: [{
2459
+ type: Input
1998
2460
  }], showCloseButton: [{
1999
2461
  type: Input
2462
+ }], ShowMaximizeButton: [{
2463
+ type: Input
2000
2464
  }], showMaximizeButton: [{
2001
2465
  type: Input
2466
+ }], RefreshTrigger: [{
2467
+ type: Input
2002
2468
  }], refreshTrigger: [{
2003
2469
  type: Input
2470
+ }], ViewContext: [{
2471
+ type: Input
2004
2472
  }], viewContext: [{
2005
2473
  type: Input
2474
+ }], ContextCollectionId: [{
2475
+ type: Input
2006
2476
  }], contextCollectionId: [{
2007
2477
  type: Input
2008
2478
  }], canShare: [{
2009
2479
  type: Input
2010
2480
  }], canEdit: [{
2011
2481
  type: Input
2482
+ }], IsMaximized: [{
2483
+ type: Input
2012
2484
  }], isMaximized: [{
2013
2485
  type: Input
2486
+ }], Closed: [{
2487
+ type: Output
2014
2488
  }], closed: [{
2015
2489
  type: Output
2490
+ }], SaveToCollectionRequested: [{
2491
+ type: Output
2016
2492
  }], saveToCollectionRequested: [{
2017
2493
  type: Output
2494
+ }], NavigateToLink: [{
2495
+ type: Output
2018
2496
  }], navigateToLink: [{
2019
2497
  type: Output
2498
+ }], ShareRequested: [{
2499
+ type: Output
2020
2500
  }], shareRequested: [{
2021
2501
  type: Output
2502
+ }], MaximizeToggled: [{
2503
+ type: Output
2022
2504
  }], maximizeToggled: [{
2023
2505
  type: Output
2506
+ }], OpenEntityRecord: [{
2507
+ type: Output
2024
2508
  }], openEntityRecord: [{
2025
2509
  type: Output
2026
2510
  }], navigationRequest: [{
2027
2511
  type: Output
2512
+ }], AnalyzeRequested: [{
2513
+ type: Output
2028
2514
  }], analyzeRequested: [{
2029
2515
  type: Output
2516
+ }], ApplyFormRequested: [{
2517
+ type: Output
2030
2518
  }], applyFormRequested: [{
2031
2519
  type: Output
2032
- }], pluginViewer: [{
2520
+ }], PluginViewer: [{
2033
2521
  type: ViewChild,
2034
2522
  args: [ArtifactTypePluginViewerComponent]
2035
2523
  }] }); })();