@memberjunction/ng-artifacts 2.107.0 → 2.109.0

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 (27) hide show
  1. package/dist/lib/artifacts.module.d.ts +2 -1
  2. package/dist/lib/artifacts.module.d.ts.map +1 -1
  3. package/dist/lib/artifacts.module.js +7 -3
  4. package/dist/lib/artifacts.module.js.map +1 -1
  5. package/dist/lib/components/artifact-type-plugin-viewer.component.d.ts.map +1 -1
  6. package/dist/lib/components/artifact-type-plugin-viewer.component.js +3 -3
  7. package/dist/lib/components/artifact-type-plugin-viewer.component.js.map +1 -1
  8. package/dist/lib/components/artifact-viewer-panel.component.d.ts +81 -13
  9. package/dist/lib/components/artifact-viewer-panel.component.d.ts.map +1 -1
  10. package/dist/lib/components/artifact-viewer-panel.component.js +609 -314
  11. package/dist/lib/components/artifact-viewer-panel.component.js.map +1 -1
  12. package/dist/lib/components/base-artifact-viewer.component.d.ts +17 -0
  13. package/dist/lib/components/base-artifact-viewer.component.d.ts.map +1 -1
  14. package/dist/lib/components/base-artifact-viewer.component.js +1 -1
  15. package/dist/lib/components/base-artifact-viewer.component.js.map +1 -1
  16. package/dist/lib/components/plugins/component-artifact-viewer.component.d.ts +15 -18
  17. package/dist/lib/components/plugins/component-artifact-viewer.component.d.ts.map +1 -1
  18. package/dist/lib/components/plugins/component-artifact-viewer.component.js +112 -182
  19. package/dist/lib/components/plugins/component-artifact-viewer.component.js.map +1 -1
  20. package/dist/lib/components/plugins/html-artifact-viewer.component.d.ts.map +1 -1
  21. package/dist/lib/components/plugins/html-artifact-viewer.component.js +13 -1
  22. package/dist/lib/components/plugins/html-artifact-viewer.component.js.map +1 -1
  23. package/dist/lib/components/plugins/json-artifact-viewer.component.d.ts +17 -4
  24. package/dist/lib/components/plugins/json-artifact-viewer.component.d.ts.map +1 -1
  25. package/dist/lib/components/plugins/json-artifact-viewer.component.js +229 -44
  26. package/dist/lib/components/plugins/json-artifact-viewer.component.js.map +1 -1
  27. package/package.json +6 -6
@@ -1,17 +1,21 @@
1
- import { Component, Input, Output, EventEmitter, ViewChild } from '@angular/core';
1
+ import { Component, Input, Output, EventEmitter, ViewChild, SecurityContext } from '@angular/core';
2
2
  import { Metadata, RunView, LogError } from '@memberjunction/core';
3
+ import { ParseJSONRecursive } from '@memberjunction/global';
3
4
  import { ArtifactMetadataEngine } from '@memberjunction/core-entities';
4
5
  import { MJNotificationService } from '@memberjunction/ng-notifications';
5
6
  import { Subject } from 'rxjs';
6
7
  import { takeUntil } from 'rxjs/operators';
7
8
  import { ArtifactTypePluginViewerComponent } from './artifact-type-plugin-viewer.component';
9
+ import { marked } from 'marked';
8
10
  import * as i0 from "@angular/core";
9
- import * as i1 from "@angular/common";
10
- import * as i2 from "@angular/forms";
11
+ import * as i1 from "@memberjunction/ng-notifications";
12
+ import * as i2 from "@angular/platform-browser";
11
13
  import * as i3 from "ngx-markdown";
12
14
  import * as i4 from "@memberjunction/ng-code-editor";
13
15
  import * as i5 from "./artifact-type-plugin-viewer.component";
16
+ import * as i6 from "@angular/common";
14
17
  const _forTrack0 = ($index, $item) => $item.ID;
18
+ const _forTrack1 = ($index, $item) => $item.id;
15
19
  function ArtifactViewerPanelComponent_Conditional_6_Template(rf, ctx) { if (rf & 1) {
16
20
  i0.ɵɵelementStart(0, "p", 4);
17
21
  i0.ɵɵtext(1);
@@ -22,26 +26,26 @@ function ArtifactViewerPanelComponent_Conditional_6_Template(rf, ctx) { if (rf &
22
26
  i0.ɵɵtextInterpolate(ctx_r0.displayDescription);
23
27
  } }
24
28
  function ArtifactViewerPanelComponent_Conditional_12_Template(rf, ctx) { if (rf & 1) {
25
- i0.ɵɵelement(0, "i", 19);
29
+ i0.ɵɵelement(0, "i", 18);
26
30
  } if (rf & 2) {
27
31
  const ctx_r0 = i0.ɵɵnextContext();
28
32
  i0.ɵɵclassProp("open", ctx_r0.showVersionDropdown);
29
33
  } }
30
34
  function ArtifactViewerPanelComponent_Conditional_13_For_2_Conditional_6_Template(rf, ctx) { if (rf & 1) {
31
- i0.ɵɵelement(0, "i", 25);
35
+ i0.ɵɵelement(0, "i", 24);
32
36
  } }
33
37
  function ArtifactViewerPanelComponent_Conditional_13_For_2_Template(rf, ctx) { if (rf & 1) {
34
38
  const _r3 = i0.ɵɵgetCurrentView();
35
- i0.ɵɵelementStart(0, "div", 22);
39
+ i0.ɵɵelementStart(0, "div", 21);
36
40
  i0.ɵɵlistener("click", function ArtifactViewerPanelComponent_Conditional_13_For_2_Template_div_click_0_listener($event) { const version_r4 = i0.ɵɵrestoreView(_r3).$implicit; const ctx_r0 = i0.ɵɵnextContext(2); ctx_r0.selectVersion(version_r4); return i0.ɵɵresetView($event.stopPropagation()); });
37
- i0.ɵɵelementStart(1, "span", 23);
41
+ i0.ɵɵelementStart(1, "span", 22);
38
42
  i0.ɵɵtext(2);
39
43
  i0.ɵɵelementEnd();
40
- i0.ɵɵelementStart(3, "span", 24);
44
+ i0.ɵɵelementStart(3, "span", 23);
41
45
  i0.ɵɵtext(4);
42
46
  i0.ɵɵpipe(5, "date");
43
47
  i0.ɵɵelementEnd();
44
- i0.ɵɵtemplate(6, ArtifactViewerPanelComponent_Conditional_13_For_2_Conditional_6_Template, 1, 0, "i", 25);
48
+ i0.ɵɵtemplate(6, ArtifactViewerPanelComponent_Conditional_13_For_2_Conditional_6_Template, 1, 0, "i", 24);
45
49
  i0.ɵɵelementEnd();
46
50
  } if (rf & 2) {
47
51
  const version_r4 = ctx.$implicit;
@@ -56,9 +60,9 @@ function ArtifactViewerPanelComponent_Conditional_13_For_2_Template(rf, ctx) { i
56
60
  } }
57
61
  function ArtifactViewerPanelComponent_Conditional_13_Template(rf, ctx) { if (rf & 1) {
58
62
  const _r2 = i0.ɵɵgetCurrentView();
59
- i0.ɵɵelementStart(0, "div", 20);
63
+ i0.ɵɵelementStart(0, "div", 19);
60
64
  i0.ɵɵlistener("click", function ArtifactViewerPanelComponent_Conditional_13_Template_div_click_0_listener($event) { i0.ɵɵrestoreView(_r2); return i0.ɵɵresetView($event.stopPropagation()); });
61
- i0.ɵɵrepeaterCreate(1, ArtifactViewerPanelComponent_Conditional_13_For_2_Template, 7, 8, "div", 21, _forTrack0);
65
+ i0.ɵɵrepeaterCreate(1, ArtifactViewerPanelComponent_Conditional_13_For_2_Template, 7, 8, "div", 20, _forTrack0);
62
66
  i0.ɵɵelementEnd();
63
67
  } if (rf & 2) {
64
68
  const ctx_r0 = i0.ɵɵnextContext();
@@ -67,27 +71,21 @@ function ArtifactViewerPanelComponent_Conditional_13_Template(rf, ctx) { if (rf
67
71
  } }
68
72
  function ArtifactViewerPanelComponent_Conditional_14_Template(rf, ctx) { if (rf & 1) {
69
73
  const _r5 = i0.ɵɵgetCurrentView();
70
- i0.ɵɵelementStart(0, "button", 26);
74
+ i0.ɵɵelementStart(0, "button", 25);
71
75
  i0.ɵɵlistener("click", function ArtifactViewerPanelComponent_Conditional_14_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r5); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onSaveToLibrary()); });
72
- i0.ɵɵelement(1, "i", 27);
76
+ i0.ɵɵelement(1, "i", 26);
73
77
  i0.ɵɵelementEnd();
74
- } if (rf & 2) {
75
- const ctx_r0 = i0.ɵɵnextContext();
76
- i0.ɵɵclassProp("in-collection", ctx_r0.isInCollection);
77
- i0.ɵɵproperty("title", ctx_r0.isInCollection ? "View in Collection" : "Save to Collection");
78
- i0.ɵɵadvance();
79
- i0.ɵɵproperty("ngClass", ctx_r0.isInCollection ? "fas fa-bookmark" : "far fa-bookmark");
80
78
  } }
81
79
  function ArtifactViewerPanelComponent_Conditional_18_Template(rf, ctx) { if (rf & 1) {
82
80
  i0.ɵɵelementStart(0, "div", 15);
83
- i0.ɵɵelement(1, "i", 28);
81
+ i0.ɵɵelement(1, "i", 27);
84
82
  i0.ɵɵelementStart(2, "span");
85
83
  i0.ɵɵtext(3, "Loading artifact...");
86
84
  i0.ɵɵelementEnd()();
87
85
  } }
88
86
  function ArtifactViewerPanelComponent_Conditional_19_Template(rf, ctx) { if (rf & 1) {
89
87
  i0.ɵɵelementStart(0, "div", 16);
90
- i0.ɵɵelement(1, "i", 29);
88
+ i0.ɵɵelement(1, "i", 28);
91
89
  i0.ɵɵelementStart(2, "span");
92
90
  i0.ɵɵtext(3);
93
91
  i0.ɵɵelementEnd()();
@@ -96,89 +94,79 @@ function ArtifactViewerPanelComponent_Conditional_19_Template(rf, ctx) { if (rf
96
94
  i0.ɵɵadvance(3);
97
95
  i0.ɵɵtextInterpolate(ctx_r0.error);
98
96
  } }
99
- function ArtifactViewerPanelComponent_Conditional_20_Conditional_2_Template(rf, ctx) { if (rf & 1) {
100
- const _r7 = i0.ɵɵgetCurrentView();
101
- i0.ɵɵelementStart(0, "button", 32);
102
- i0.ɵɵlistener("click", function ArtifactViewerPanelComponent_Conditional_20_Conditional_2_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r7); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.setActiveTab("display")); });
103
- i0.ɵɵelement(1, "i", 38);
104
- i0.ɵɵtext(2, " Display ");
105
- i0.ɵɵelementEnd();
97
+ function ArtifactViewerPanelComponent_Conditional_20_For_3_Conditional_1_Template(rf, ctx) { if (rf & 1) {
98
+ i0.ɵɵelement(0, "i");
106
99
  } if (rf & 2) {
100
+ const tab_r7 = i0.ɵɵnextContext().$implicit;
107
101
  const ctx_r0 = i0.ɵɵnextContext(2);
108
- i0.ɵɵclassProp("active", ctx_r0.activeTab === "display");
102
+ i0.ɵɵclassMap(ctx_r0.GetTabIcon(tab_r7));
109
103
  } }
110
- function ArtifactViewerPanelComponent_Conditional_20_Conditional_3_Template(rf, ctx) { if (rf & 1) {
111
- const _r8 = i0.ɵɵgetCurrentView();
112
- i0.ɵɵelementStart(0, "button", 32);
113
- i0.ɵɵlistener("click", function ArtifactViewerPanelComponent_Conditional_20_Conditional_3_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r8); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.setActiveTab("json")); });
114
- i0.ɵɵelement(1, "i", 39);
115
- i0.ɵɵtext(2, " JSON ");
104
+ function ArtifactViewerPanelComponent_Conditional_20_For_3_Template(rf, ctx) { if (rf & 1) {
105
+ const _r6 = i0.ɵɵgetCurrentView();
106
+ i0.ɵɵelementStart(0, "button", 35);
107
+ i0.ɵɵlistener("click", function ArtifactViewerPanelComponent_Conditional_20_For_3_Template_button_click_0_listener() { const tab_r7 = i0.ɵɵrestoreView(_r6).$implicit; const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.SetActiveTab(tab_r7)); });
108
+ i0.ɵɵtemplate(1, ArtifactViewerPanelComponent_Conditional_20_For_3_Conditional_1_Template, 1, 2, "i", 36);
109
+ i0.ɵɵtext(2);
116
110
  i0.ɵɵelementEnd();
117
111
  } if (rf & 2) {
112
+ const tab_r7 = ctx.$implicit;
118
113
  const ctx_r0 = i0.ɵɵnextContext(2);
119
- i0.ɵɵclassProp("active", ctx_r0.activeTab === "json");
114
+ i0.ɵɵclassProp("active", ctx_r0.activeTab === tab_r7.toLowerCase());
115
+ i0.ɵɵadvance();
116
+ i0.ɵɵconditional(ctx_r0.GetTabIcon(tab_r7) ? 1 : -1);
117
+ i0.ɵɵadvance();
118
+ i0.ɵɵtextInterpolate1(" ", tab_r7, " ");
120
119
  } }
121
- function ArtifactViewerPanelComponent_Conditional_20_Conditional_8_Conditional_1_Template(rf, ctx) { if (rf & 1) {
122
- i0.ɵɵelement(0, "mj-artifact-type-plugin-viewer", 40);
120
+ function ArtifactViewerPanelComponent_Conditional_20_Conditional_5_Conditional_1_Template(rf, ctx) { if (rf & 1) {
121
+ i0.ɵɵelement(0, "mj-artifact-type-plugin-viewer", 37);
123
122
  } if (rf & 2) {
124
123
  const ctx_r0 = i0.ɵɵnextContext(3);
125
124
  i0.ɵɵproperty("artifactVersion", ctx_r0.artifactVersion)("artifactTypeName", ctx_r0.artifactTypeName)("contentType", ctx_r0.contentType)("readonly", true);
126
125
  } }
127
- function ArtifactViewerPanelComponent_Conditional_20_Conditional_8_Conditional_2_Conditional_4_Template(rf, ctx) { if (rf & 1) {
128
- i0.ɵɵelementStart(0, "div", 44);
129
- i0.ɵɵelement(1, "markdown", 46);
126
+ function ArtifactViewerPanelComponent_Conditional_20_Conditional_5_Conditional_2_Conditional_7_Template(rf, ctx) { if (rf & 1) {
127
+ i0.ɵɵelementStart(0, "div", 43);
128
+ i0.ɵɵelement(1, "markdown", 45);
130
129
  i0.ɵɵelementEnd();
131
130
  } if (rf & 2) {
132
131
  const ctx_r0 = i0.ɵɵnextContext(4);
133
132
  i0.ɵɵadvance();
134
133
  i0.ɵɵproperty("data", ctx_r0.displayMarkdown);
135
134
  } }
136
- function ArtifactViewerPanelComponent_Conditional_20_Conditional_8_Conditional_2_Conditional_5_Template(rf, ctx) { if (rf & 1) {
137
- i0.ɵɵelement(0, "div", 45);
135
+ function ArtifactViewerPanelComponent_Conditional_20_Conditional_5_Conditional_2_Conditional_8_Template(rf, ctx) { if (rf & 1) {
136
+ i0.ɵɵelement(0, "div", 44);
138
137
  } if (rf & 2) {
139
138
  const ctx_r0 = i0.ɵɵnextContext(4);
140
139
  i0.ɵɵproperty("innerHTML", ctx_r0.displayHtml, i0.ɵɵsanitizeHtml);
141
140
  } }
142
- function ArtifactViewerPanelComponent_Conditional_20_Conditional_8_Conditional_2_Template(rf, ctx) { if (rf & 1) {
143
- const _r9 = i0.ɵɵgetCurrentView();
144
- i0.ɵɵelementStart(0, "div", 41)(1, "button", 42);
145
- i0.ɵɵlistener("click", function ArtifactViewerPanelComponent_Conditional_20_Conditional_8_Conditional_2_Template_button_click_1_listener() { i0.ɵɵrestoreView(_r9); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.onCopyDisplayContent()); });
146
- i0.ɵɵelement(2, "i", 43);
147
- i0.ɵɵtext(3, " Copy ");
141
+ function ArtifactViewerPanelComponent_Conditional_20_Conditional_5_Conditional_2_Template(rf, ctx) { if (rf & 1) {
142
+ const _r8 = i0.ɵɵgetCurrentView();
143
+ i0.ɵɵelementStart(0, "div", 38)(1, "button", 39);
144
+ i0.ɵɵlistener("click", function ArtifactViewerPanelComponent_Conditional_20_Conditional_5_Conditional_2_Template_button_click_1_listener() { i0.ɵɵrestoreView(_r8); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.onPrintDisplayContent()); });
145
+ i0.ɵɵelement(2, "i", 40);
146
+ i0.ɵɵtext(3, " Print ");
147
+ i0.ɵɵelementEnd();
148
+ i0.ɵɵelementStart(4, "button", 41);
149
+ i0.ɵɵlistener("click", function ArtifactViewerPanelComponent_Conditional_20_Conditional_5_Conditional_2_Template_button_click_4_listener() { i0.ɵɵrestoreView(_r8); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.onCopyDisplayContent()); });
150
+ i0.ɵɵelement(5, "i", 42);
151
+ i0.ɵɵtext(6, " Copy ");
148
152
  i0.ɵɵelementEnd()();
149
- i0.ɵɵtemplate(4, ArtifactViewerPanelComponent_Conditional_20_Conditional_8_Conditional_2_Conditional_4_Template, 2, 1, "div", 44)(5, ArtifactViewerPanelComponent_Conditional_20_Conditional_8_Conditional_2_Conditional_5_Template, 1, 1, "div", 45);
153
+ i0.ɵɵtemplate(7, ArtifactViewerPanelComponent_Conditional_20_Conditional_5_Conditional_2_Conditional_7_Template, 2, 1, "div", 43)(8, ArtifactViewerPanelComponent_Conditional_20_Conditional_5_Conditional_2_Conditional_8_Template, 1, 1, "div", 44);
150
154
  } if (rf & 2) {
151
155
  const ctx_r0 = i0.ɵɵnextContext(3);
152
- i0.ɵɵadvance(4);
153
- i0.ɵɵconditional(ctx_r0.displayMarkdown ? 4 : ctx_r0.displayHtml ? 5 : -1);
156
+ i0.ɵɵadvance(7);
157
+ i0.ɵɵconditional(ctx_r0.displayMarkdown ? 7 : ctx_r0.displayHtml ? 8 : -1);
154
158
  } }
155
- function ArtifactViewerPanelComponent_Conditional_20_Conditional_8_Template(rf, ctx) { if (rf & 1) {
156
- i0.ɵɵelementStart(0, "div", 35);
157
- i0.ɵɵtemplate(1, ArtifactViewerPanelComponent_Conditional_20_Conditional_8_Conditional_1_Template, 1, 4, "mj-artifact-type-plugin-viewer", 40)(2, ArtifactViewerPanelComponent_Conditional_20_Conditional_8_Conditional_2_Template, 6, 1);
159
+ function ArtifactViewerPanelComponent_Conditional_20_Conditional_5_Template(rf, ctx) { if (rf & 1) {
160
+ i0.ɵɵelementStart(0, "div", 32);
161
+ i0.ɵɵtemplate(1, ArtifactViewerPanelComponent_Conditional_20_Conditional_5_Conditional_1_Template, 1, 4, "mj-artifact-type-plugin-viewer", 37)(2, ArtifactViewerPanelComponent_Conditional_20_Conditional_5_Conditional_2_Template, 9, 1);
158
162
  i0.ɵɵelementEnd();
159
163
  } if (rf & 2) {
160
164
  const ctx_r0 = i0.ɵɵnextContext(2);
161
165
  i0.ɵɵadvance();
162
166
  i0.ɵɵconditional(ctx_r0.hasPlugin && ctx_r0.artifactVersion && ctx_r0.artifactTypeName ? 1 : ctx_r0.displayMarkdown || ctx_r0.displayHtml ? 2 : -1);
163
167
  } }
164
- function ArtifactViewerPanelComponent_Conditional_20_Conditional_9_Template(rf, ctx) { if (rf & 1) {
165
- const _r10 = i0.ɵɵgetCurrentView();
166
- i0.ɵɵelementStart(0, "div", 36)(1, "div", 47)(2, "button", 48);
167
- i0.ɵɵlistener("click", function ArtifactViewerPanelComponent_Conditional_20_Conditional_9_Template_button_click_2_listener() { i0.ɵɵrestoreView(_r10); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.onCopyToClipboard()); });
168
- i0.ɵɵelement(3, "i", 43);
169
- i0.ɵɵtext(4, " Copy ");
170
- i0.ɵɵelementEnd()();
171
- i0.ɵɵelementStart(5, "div", 49)(6, "mj-code-editor", 50);
172
- i0.ɵɵtwoWayListener("ngModelChange", function ArtifactViewerPanelComponent_Conditional_20_Conditional_9_Template_mj_code_editor_ngModelChange_6_listener($event) { i0.ɵɵrestoreView(_r10); const ctx_r0 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r0.jsonContent, $event) || (ctx_r0.jsonContent = $event); return i0.ɵɵresetView($event); });
173
- i0.ɵɵelementEnd()()();
174
- } if (rf & 2) {
175
- const ctx_r0 = i0.ɵɵnextContext(2);
176
- i0.ɵɵadvance(6);
177
- i0.ɵɵtwoWayProperty("ngModel", ctx_r0.jsonContent);
178
- i0.ɵɵproperty("language", "json")("readonly", true);
179
- } }
180
- function ArtifactViewerPanelComponent_Conditional_20_Conditional_10_Conditional_24_Template(rf, ctx) { if (rf & 1) {
181
- i0.ɵɵelementStart(0, "div", 53)(1, "label");
168
+ function ArtifactViewerPanelComponent_Conditional_20_Conditional_6_Conditional_24_Template(rf, ctx) { if (rf & 1) {
169
+ i0.ɵɵelementStart(0, "div", 48)(1, "label");
182
170
  i0.ɵɵtext(2, "Artifact Description");
183
171
  i0.ɵɵelementEnd();
184
172
  i0.ɵɵelementStart(3, "span");
@@ -189,8 +177,8 @@ function ArtifactViewerPanelComponent_Conditional_20_Conditional_10_Conditional_
189
177
  i0.ɵɵadvance(4);
190
178
  i0.ɵɵtextInterpolate(ctx_r0.artifact.Description);
191
179
  } }
192
- function ArtifactViewerPanelComponent_Conditional_20_Conditional_10_Conditional_25_Template(rf, ctx) { if (rf & 1) {
193
- i0.ɵɵelementStart(0, "div", 53)(1, "label");
180
+ function ArtifactViewerPanelComponent_Conditional_20_Conditional_6_Conditional_25_Template(rf, ctx) { if (rf & 1) {
181
+ i0.ɵɵelementStart(0, "div", 48)(1, "label");
194
182
  i0.ɵɵtext(2, "Version Description");
195
183
  i0.ɵɵelementEnd();
196
184
  i0.ɵɵelementStart(3, "span");
@@ -201,75 +189,75 @@ function ArtifactViewerPanelComponent_Conditional_20_Conditional_10_Conditional_
201
189
  i0.ɵɵadvance(4);
202
190
  i0.ɵɵtextInterpolate(ctx_r0.artifactVersion == null ? null : ctx_r0.artifactVersion.Description);
203
191
  } }
204
- function ArtifactViewerPanelComponent_Conditional_20_Conditional_10_Conditional_26_For_5_Conditional_3_Template(rf, ctx) { if (rf & 1) {
192
+ function ArtifactViewerPanelComponent_Conditional_20_Conditional_6_Conditional_26_For_5_Conditional_3_Template(rf, ctx) { if (rf & 1) {
205
193
  i0.ɵɵelementStart(0, "span");
206
194
  i0.ɵɵtext(1);
207
195
  i0.ɵɵelementEnd();
208
196
  } if (rf & 2) {
209
- const attr_r11 = i0.ɵɵnextContext().$implicit;
197
+ const attr_r9 = i0.ɵɵnextContext().$implicit;
210
198
  i0.ɵɵadvance();
211
- i0.ɵɵtextInterpolate(attr_r11.Value);
199
+ i0.ɵɵtextInterpolate(attr_r9.Value);
212
200
  } }
213
- function ArtifactViewerPanelComponent_Conditional_20_Conditional_10_Conditional_26_For_5_Conditional_4_Template(rf, ctx) { if (rf & 1) {
214
- i0.ɵɵelementStart(0, "span", 57);
201
+ function ArtifactViewerPanelComponent_Conditional_20_Conditional_6_Conditional_26_For_5_Conditional_4_Template(rf, ctx) { if (rf & 1) {
202
+ i0.ɵɵelementStart(0, "span", 52);
215
203
  i0.ɵɵtext(1, "Empty");
216
204
  i0.ɵɵelementEnd();
217
205
  } }
218
- function ArtifactViewerPanelComponent_Conditional_20_Conditional_10_Conditional_26_For_5_Template(rf, ctx) { if (rf & 1) {
219
- i0.ɵɵelementStart(0, "div", 56)(1, "label");
206
+ function ArtifactViewerPanelComponent_Conditional_20_Conditional_6_Conditional_26_For_5_Template(rf, ctx) { if (rf & 1) {
207
+ i0.ɵɵelementStart(0, "div", 51)(1, "label");
220
208
  i0.ɵɵtext(2);
221
209
  i0.ɵɵelementEnd();
222
- i0.ɵɵtemplate(3, ArtifactViewerPanelComponent_Conditional_20_Conditional_10_Conditional_26_For_5_Conditional_3_Template, 2, 1, "span")(4, ArtifactViewerPanelComponent_Conditional_20_Conditional_10_Conditional_26_For_5_Conditional_4_Template, 2, 0, "span", 57);
210
+ i0.ɵɵtemplate(3, ArtifactViewerPanelComponent_Conditional_20_Conditional_6_Conditional_26_For_5_Conditional_3_Template, 2, 1, "span")(4, ArtifactViewerPanelComponent_Conditional_20_Conditional_6_Conditional_26_For_5_Conditional_4_Template, 2, 0, "span", 52);
223
211
  i0.ɵɵelementEnd();
224
212
  } if (rf & 2) {
225
- const attr_r11 = ctx.$implicit;
213
+ const attr_r9 = ctx.$implicit;
226
214
  i0.ɵɵadvance(2);
227
- i0.ɵɵtextInterpolate(attr_r11.Name);
215
+ i0.ɵɵtextInterpolate(attr_r9.Name);
228
216
  i0.ɵɵadvance();
229
- i0.ɵɵconditional(attr_r11.Value ? 3 : 4);
217
+ i0.ɵɵconditional(attr_r9.Value ? 3 : 4);
230
218
  } }
231
- function ArtifactViewerPanelComponent_Conditional_20_Conditional_10_Conditional_26_Template(rf, ctx) { if (rf & 1) {
232
- i0.ɵɵelementStart(0, "div", 54)(1, "h4");
219
+ function ArtifactViewerPanelComponent_Conditional_20_Conditional_6_Conditional_26_Template(rf, ctx) { if (rf & 1) {
220
+ i0.ɵɵelementStart(0, "div", 49)(1, "h4");
233
221
  i0.ɵɵtext(2, "Version Attributes");
234
222
  i0.ɵɵelementEnd();
235
- i0.ɵɵelementStart(3, "div", 55);
236
- i0.ɵɵrepeaterCreate(4, ArtifactViewerPanelComponent_Conditional_20_Conditional_10_Conditional_26_For_5_Template, 5, 2, "div", 56, _forTrack0);
223
+ i0.ɵɵelementStart(3, "div", 50);
224
+ i0.ɵɵrepeaterCreate(4, ArtifactViewerPanelComponent_Conditional_20_Conditional_6_Conditional_26_For_5_Template, 5, 2, "div", 51, _forTrack0);
237
225
  i0.ɵɵelementEnd()();
238
226
  } if (rf & 2) {
239
227
  const ctx_r0 = i0.ɵɵnextContext(3);
240
228
  i0.ɵɵadvance(4);
241
229
  i0.ɵɵrepeater(ctx_r0.filteredAttributes);
242
230
  } }
243
- function ArtifactViewerPanelComponent_Conditional_20_Conditional_10_Template(rf, ctx) { if (rf & 1) {
244
- i0.ɵɵelementStart(0, "div", 37)(1, "div", 51)(2, "div", 52)(3, "label");
231
+ function ArtifactViewerPanelComponent_Conditional_20_Conditional_6_Template(rf, ctx) { if (rf & 1) {
232
+ i0.ɵɵelementStart(0, "div", 33)(1, "div", 46)(2, "div", 47)(3, "label");
245
233
  i0.ɵɵtext(4, "Type");
246
234
  i0.ɵɵelementEnd();
247
235
  i0.ɵɵelementStart(5, "span");
248
236
  i0.ɵɵtext(6);
249
237
  i0.ɵɵelementEnd()();
250
- i0.ɵɵelementStart(7, "div", 52)(8, "label");
238
+ i0.ɵɵelementStart(7, "div", 47)(8, "label");
251
239
  i0.ɵɵtext(9, "Version");
252
240
  i0.ɵɵelementEnd();
253
241
  i0.ɵɵelementStart(10, "span");
254
242
  i0.ɵɵtext(11);
255
243
  i0.ɵɵelementEnd()();
256
- i0.ɵɵelementStart(12, "div", 52)(13, "label");
244
+ i0.ɵɵelementStart(12, "div", 47)(13, "label");
257
245
  i0.ɵɵtext(14, "Created");
258
246
  i0.ɵɵelementEnd();
259
247
  i0.ɵɵelementStart(15, "span");
260
248
  i0.ɵɵtext(16);
261
249
  i0.ɵɵpipe(17, "date");
262
250
  i0.ɵɵelementEnd()();
263
- i0.ɵɵelementStart(18, "div", 52)(19, "label");
251
+ i0.ɵɵelementStart(18, "div", 47)(19, "label");
264
252
  i0.ɵɵtext(20, "Updated");
265
253
  i0.ɵɵelementEnd();
266
254
  i0.ɵɵelementStart(21, "span");
267
255
  i0.ɵɵtext(22);
268
256
  i0.ɵɵpipe(23, "date");
269
257
  i0.ɵɵelementEnd()();
270
- i0.ɵɵtemplate(24, ArtifactViewerPanelComponent_Conditional_20_Conditional_10_Conditional_24_Template, 5, 1, "div", 53)(25, ArtifactViewerPanelComponent_Conditional_20_Conditional_10_Conditional_25_Template, 5, 1, "div", 53);
258
+ i0.ɵɵtemplate(24, ArtifactViewerPanelComponent_Conditional_20_Conditional_6_Conditional_24_Template, 5, 1, "div", 48)(25, ArtifactViewerPanelComponent_Conditional_20_Conditional_6_Conditional_25_Template, 5, 1, "div", 48);
271
259
  i0.ɵɵelementEnd();
272
- i0.ɵɵtemplate(26, ArtifactViewerPanelComponent_Conditional_20_Conditional_10_Conditional_26_Template, 6, 0, "div", 54);
260
+ i0.ɵɵtemplate(26, ArtifactViewerPanelComponent_Conditional_20_Conditional_6_Conditional_26_Template, 6, 0, "div", 49);
273
261
  i0.ɵɵelementEnd();
274
262
  } if (rf & 2) {
275
263
  const ctx_r0 = i0.ɵɵnextContext(2);
@@ -288,131 +276,159 @@ function ArtifactViewerPanelComponent_Conditional_20_Conditional_10_Template(rf,
288
276
  i0.ɵɵadvance();
289
277
  i0.ɵɵconditional(ctx_r0.filteredAttributes.length > 0 ? 26 : -1);
290
278
  } }
291
- function ArtifactViewerPanelComponent_Conditional_20_Template(rf, ctx) { if (rf & 1) {
292
- const _r6 = i0.ɵɵgetCurrentView();
293
- i0.ɵɵelementStart(0, "div", 17)(1, "div", 30);
294
- i0.ɵɵtemplate(2, ArtifactViewerPanelComponent_Conditional_20_Conditional_2_Template, 3, 2, "button", 31)(3, ArtifactViewerPanelComponent_Conditional_20_Conditional_3_Template, 3, 2, "button", 31);
295
- i0.ɵɵelementStart(4, "button", 32);
296
- i0.ɵɵlistener("click", function ArtifactViewerPanelComponent_Conditional_20_Template_button_click_4_listener() { i0.ɵɵrestoreView(_r6); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.setActiveTab("details")); });
297
- i0.ɵɵelement(5, "i", 33);
298
- i0.ɵɵtext(6, " Details ");
299
- i0.ɵɵelementEnd()();
300
- i0.ɵɵelementStart(7, "div", 34);
301
- i0.ɵɵtemplate(8, ArtifactViewerPanelComponent_Conditional_20_Conditional_8_Template, 3, 1, "div", 35)(9, ArtifactViewerPanelComponent_Conditional_20_Conditional_9_Template, 7, 3, "div", 36)(10, ArtifactViewerPanelComponent_Conditional_20_Conditional_10_Template, 27, 13, "div", 37);
279
+ function ArtifactViewerPanelComponent_Conditional_20_Conditional_7_Conditional_1_For_2_Conditional_2_Template(rf, ctx) { if (rf & 1) {
280
+ i0.ɵɵelement(0, "i", 57);
281
+ } }
282
+ function ArtifactViewerPanelComponent_Conditional_20_Conditional_7_Conditional_1_For_2_Conditional_3_Template(rf, ctx) { if (rf & 1) {
283
+ i0.ɵɵelement(0, "i", 58);
284
+ } }
285
+ function ArtifactViewerPanelComponent_Conditional_20_Conditional_7_Conditional_1_For_2_Template(rf, ctx) { if (rf & 1) {
286
+ const _r10 = i0.ɵɵgetCurrentView();
287
+ i0.ɵɵelementStart(0, "div", 55)(1, "div", 56);
288
+ i0.ɵɵtemplate(2, ArtifactViewerPanelComponent_Conditional_20_Conditional_7_Conditional_1_For_2_Conditional_2_Template, 1, 0, "i", 57)(3, ArtifactViewerPanelComponent_Conditional_20_Conditional_7_Conditional_1_For_2_Conditional_3_Template, 1, 0, "i", 58);
289
+ i0.ɵɵelementEnd();
290
+ i0.ɵɵelementStart(4, "div", 59)(5, "div", 60);
291
+ i0.ɵɵtext(6);
292
+ i0.ɵɵelementEnd();
293
+ i0.ɵɵelementStart(7, "div", 61);
294
+ i0.ɵɵtext(8);
302
295
  i0.ɵɵelementEnd()();
296
+ i0.ɵɵelementStart(9, "div", 62)(10, "button", 63);
297
+ i0.ɵɵlistener("click", function ArtifactViewerPanelComponent_Conditional_20_Conditional_7_Conditional_1_For_2_Template_button_click_10_listener() { const link_r11 = i0.ɵɵrestoreView(_r10).$implicit; const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.onNavigateToLink(link_r11)); });
298
+ i0.ɵɵelement(11, "i", 64);
299
+ i0.ɵɵelementEnd()()();
303
300
  } if (rf & 2) {
304
- const ctx_r0 = i0.ɵɵnextContext();
301
+ const link_r11 = ctx.$implicit;
305
302
  i0.ɵɵadvance(2);
306
- i0.ɵɵconditional(ctx_r0.hasDisplayTab ? 2 : -1);
307
- i0.ɵɵadvance();
308
- i0.ɵɵconditional(ctx_r0.hasJsonTab ? 3 : -1);
309
- i0.ɵɵadvance();
310
- i0.ɵɵclassProp("active", ctx_r0.activeTab === "details");
303
+ i0.ɵɵconditional(link_r11.type === "conversation" ? 2 : 3);
311
304
  i0.ɵɵadvance(4);
312
- i0.ɵɵconditional(ctx_r0.activeTab === "display" && ctx_r0.hasDisplayTab ? 8 : -1);
313
- i0.ɵɵadvance();
314
- i0.ɵɵconditional(ctx_r0.activeTab === "json" && ctx_r0.hasJsonTab ? 9 : -1);
315
- i0.ɵɵadvance();
316
- i0.ɵɵconditional(ctx_r0.activeTab === "details" ? 10 : -1);
305
+ i0.ɵɵtextInterpolate(link_r11.name);
306
+ i0.ɵɵadvance(2);
307
+ i0.ɵɵtextInterpolate(link_r11.type === "conversation" ? "Conversation" : "Collection");
308
+ i0.ɵɵadvance(2);
309
+ i0.ɵɵproperty("disabled", !link_r11.hasAccess)("title", link_r11.hasAccess ? "Open" : "No access");
317
310
  } }
318
- function ArtifactViewerPanelComponent_Conditional_21_For_16_Template(rf, ctx) { if (rf & 1) {
319
- i0.ɵɵelementStart(0, "option", 66);
320
- i0.ɵɵtext(1);
311
+ function ArtifactViewerPanelComponent_Conditional_20_Conditional_7_Conditional_1_Template(rf, ctx) { if (rf & 1) {
312
+ i0.ɵɵelementStart(0, "div", 53);
313
+ i0.ɵɵrepeaterCreate(1, ArtifactViewerPanelComponent_Conditional_20_Conditional_7_Conditional_1_For_2_Template, 12, 5, "div", 55, _forTrack1);
321
314
  i0.ɵɵelementEnd();
322
315
  } if (rf & 2) {
323
- const collection_r13 = ctx.$implicit;
324
- i0.ɵɵproperty("ngValue", collection_r13.ID);
316
+ const ctx_r0 = i0.ɵɵnextContext(3);
325
317
  i0.ɵɵadvance();
326
- i0.ɵɵtextInterpolate(collection_r13.Name);
327
- } }
328
- function ArtifactViewerPanelComponent_Conditional_21_Conditional_26_Template(rf, ctx) { if (rf & 1) {
329
- i0.ɵɵelement(0, "i", 28);
330
- } }
331
- function ArtifactViewerPanelComponent_Conditional_21_Conditional_27_Template(rf, ctx) { if (rf & 1) {
332
- i0.ɵɵelement(0, "i", 71);
333
- } }
334
- function ArtifactViewerPanelComponent_Conditional_21_Conditional_33_Template(rf, ctx) { if (rf & 1) {
335
- i0.ɵɵelement(0, "i", 28);
336
- i0.ɵɵtext(1, " Saving... ");
337
- } }
338
- function ArtifactViewerPanelComponent_Conditional_21_Conditional_34_Template(rf, ctx) { if (rf & 1) {
339
- i0.ɵɵelement(0, "i", 75);
340
- i0.ɵɵtext(1, " Save to Collection ");
341
- } }
342
- function ArtifactViewerPanelComponent_Conditional_21_Template(rf, ctx) { if (rf & 1) {
343
- const _r12 = i0.ɵɵgetCurrentView();
344
- i0.ɵɵelementStart(0, "div", 58);
345
- i0.ɵɵlistener("click", function ArtifactViewerPanelComponent_Conditional_21_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r12); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.cancelLibraryDialog()); });
346
- i0.ɵɵelementStart(1, "div", 59);
347
- i0.ɵɵlistener("click", function ArtifactViewerPanelComponent_Conditional_21_Template_div_click_1_listener($event) { i0.ɵɵrestoreView(_r12); return i0.ɵɵresetView($event.stopPropagation()); });
348
- i0.ɵɵelementStart(2, "div", 60)(3, "h3");
349
- i0.ɵɵelement(4, "i", 61);
350
- i0.ɵɵtext(5, " Save to Collection ");
351
- i0.ɵɵelementEnd();
352
- i0.ɵɵelementStart(6, "button", 62);
353
- i0.ɵɵlistener("click", function ArtifactViewerPanelComponent_Conditional_21_Template_button_click_6_listener() { i0.ɵɵrestoreView(_r12); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.cancelLibraryDialog()); });
354
- i0.ɵɵelement(7, "i", 13);
318
+ i0.ɵɵrepeater(ctx_r0.linksToShow);
319
+ } }
320
+ function ArtifactViewerPanelComponent_Conditional_20_Conditional_7_Conditional_2_Template(rf, ctx) { if (rf & 1) {
321
+ i0.ɵɵelementStart(0, "div", 54);
322
+ i0.ɵɵelement(1, "i", 65);
323
+ i0.ɵɵelementStart(2, "p");
324
+ i0.ɵɵtext(3, "No links available");
355
325
  i0.ɵɵelementEnd()();
356
- i0.ɵɵelementStart(8, "div", 63)(9, "div", 64)(10, "label");
357
- i0.ɵɵtext(11, "Select Collection");
358
- i0.ɵɵelementEnd();
359
- i0.ɵɵelementStart(12, "select", 65);
360
- i0.ɵɵtwoWayListener("ngModelChange", function ArtifactViewerPanelComponent_Conditional_21_Template_select_ngModelChange_12_listener($event) { i0.ɵɵrestoreView(_r12); const ctx_r0 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r0.selectedCollectionId, $event) || (ctx_r0.selectedCollectionId = $event); return i0.ɵɵresetView($event); });
361
- i0.ɵɵelementStart(13, "option", 66);
362
- i0.ɵɵtext(14, "-- Choose a collection --");
326
+ } }
327
+ function ArtifactViewerPanelComponent_Conditional_20_Conditional_7_Template(rf, ctx) { if (rf & 1) {
328
+ i0.ɵɵelementStart(0, "div", 34);
329
+ i0.ɵɵtemplate(1, ArtifactViewerPanelComponent_Conditional_20_Conditional_7_Conditional_1_Template, 3, 0, "div", 53)(2, ArtifactViewerPanelComponent_Conditional_20_Conditional_7_Conditional_2_Template, 4, 0, "div", 54);
363
330
  i0.ɵɵelementEnd();
364
- i0.ɵɵrepeaterCreate(15, ArtifactViewerPanelComponent_Conditional_21_For_16_Template, 2, 2, "option", 66, _forTrack0);
331
+ } if (rf & 2) {
332
+ const ctx_r0 = i0.ɵɵnextContext(2);
333
+ i0.ɵɵadvance();
334
+ i0.ɵɵconditional(ctx_r0.linksToShow.length > 0 ? 1 : 2);
335
+ } }
336
+ function ArtifactViewerPanelComponent_Conditional_20_Conditional_8_Conditional_0_Case_1_Template(rf, ctx) { if (rf & 1) {
337
+ i0.ɵɵelement(0, "div", 67);
338
+ } if (rf & 2) {
339
+ const tabData_r12 = i0.ɵɵnextContext();
340
+ const ctx_r0 = i0.ɵɵnextContext(3);
341
+ i0.ɵɵproperty("innerHTML", ctx_r0.RenderMarkdown(tabData_r12.content), i0.ɵɵsanitizeHtml);
342
+ } }
343
+ function ArtifactViewerPanelComponent_Conditional_20_Conditional_8_Conditional_0_Case_2_Template(rf, ctx) { if (rf & 1) {
344
+ const _r13 = i0.ɵɵgetCurrentView();
345
+ i0.ɵɵelementStart(0, "div", 68)(1, "div", 72)(2, "button", 73);
346
+ i0.ɵɵlistener("click", function ArtifactViewerPanelComponent_Conditional_20_Conditional_8_Conditional_0_Case_2_Template_button_click_2_listener() { i0.ɵɵrestoreView(_r13); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.onCopyToClipboard()); });
347
+ i0.ɵɵelement(3, "i", 42);
348
+ i0.ɵɵtext(4, " Copy ");
365
349
  i0.ɵɵelementEnd()();
366
- i0.ɵɵelementStart(17, "div", 67)(18, "span");
367
- i0.ɵɵtext(19, "OR");
350
+ i0.ɵɵelementStart(5, "div", 74);
351
+ i0.ɵɵelement(6, "mj-code-editor", 75);
368
352
  i0.ɵɵelementEnd()();
369
- i0.ɵɵelementStart(20, "div", 64)(21, "label");
370
- i0.ɵɵtext(22, "Create New Collection");
353
+ } if (rf & 2) {
354
+ const tabData_r12 = i0.ɵɵnextContext();
355
+ i0.ɵɵadvance(6);
356
+ i0.ɵɵproperty("value", tabData_r12.content)("language", "json")("readonly", true)("lineWrapping", true);
357
+ } }
358
+ function ArtifactViewerPanelComponent_Conditional_20_Conditional_8_Conditional_0_Case_3_Template(rf, ctx) { if (rf & 1) {
359
+ i0.ɵɵelementStart(0, "div", 69);
360
+ i0.ɵɵelement(1, "mj-code-editor", 75);
371
361
  i0.ɵɵelementEnd();
372
- i0.ɵɵelementStart(23, "div", 68)(24, "input", 69);
373
- i0.ɵɵtwoWayListener("ngModelChange", function ArtifactViewerPanelComponent_Conditional_21_Template_input_ngModelChange_24_listener($event) { i0.ɵɵrestoreView(_r12); const ctx_r0 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r0.newCollectionName, $event) || (ctx_r0.newCollectionName = $event); return i0.ɵɵresetView($event); });
374
- i0.ɵɵlistener("keyup.enter", function ArtifactViewerPanelComponent_Conditional_21_Template_input_keyup_enter_24_listener() { i0.ɵɵrestoreView(_r12); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.createNewCollection()); });
362
+ } if (rf & 2) {
363
+ const tabData_r12 = i0.ɵɵnextContext();
364
+ i0.ɵɵadvance();
365
+ i0.ɵɵproperty("value", tabData_r12.content)("language", tabData_r12.language || "typescript")("readonly", true)("lineWrapping", true);
366
+ } }
367
+ function ArtifactViewerPanelComponent_Conditional_20_Conditional_8_Conditional_0_Case_4_Template(rf, ctx) { if (rf & 1) {
368
+ i0.ɵɵelement(0, "div", 70);
369
+ } if (rf & 2) {
370
+ const tabData_r12 = i0.ɵɵnextContext();
371
+ i0.ɵɵproperty("innerHTML", tabData_r12.content, i0.ɵɵsanitizeHtml);
372
+ } }
373
+ function ArtifactViewerPanelComponent_Conditional_20_Conditional_8_Conditional_0_Case_5_Template(rf, ctx) { if (rf & 1) {
374
+ i0.ɵɵelementStart(0, "pre", 71);
375
+ i0.ɵɵtext(1);
375
376
  i0.ɵɵelementEnd();
376
- i0.ɵɵelementStart(25, "button", 70);
377
- i0.ɵɵlistener("click", function ArtifactViewerPanelComponent_Conditional_21_Template_button_click_25_listener() { i0.ɵɵrestoreView(_r12); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.createNewCollection()); });
378
- i0.ɵɵtemplate(26, ArtifactViewerPanelComponent_Conditional_21_Conditional_26_Template, 1, 0, "i", 28)(27, ArtifactViewerPanelComponent_Conditional_21_Conditional_27_Template, 1, 0, "i", 71);
379
- i0.ɵɵtext(28, " Create ");
380
- i0.ɵɵelementEnd()()()();
381
- i0.ɵɵelementStart(29, "div", 72)(30, "button", 73);
382
- i0.ɵɵlistener("click", function ArtifactViewerPanelComponent_Conditional_21_Template_button_click_30_listener() { i0.ɵɵrestoreView(_r12); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.cancelLibraryDialog()); });
383
- i0.ɵɵtext(31, " Cancel ");
377
+ } if (rf & 2) {
378
+ const tabData_r12 = i0.ɵɵnextContext();
379
+ i0.ɵɵadvance();
380
+ i0.ɵɵtextInterpolate(tabData_r12.content);
381
+ } }
382
+ function ArtifactViewerPanelComponent_Conditional_20_Conditional_8_Conditional_0_Template(rf, ctx) { if (rf & 1) {
383
+ i0.ɵɵelementStart(0, "div", 66);
384
+ i0.ɵɵtemplate(1, ArtifactViewerPanelComponent_Conditional_20_Conditional_8_Conditional_0_Case_1_Template, 1, 1, "div", 67)(2, ArtifactViewerPanelComponent_Conditional_20_Conditional_8_Conditional_0_Case_2_Template, 7, 4, "div", 68)(3, ArtifactViewerPanelComponent_Conditional_20_Conditional_8_Conditional_0_Case_3_Template, 2, 4, "div", 69)(4, ArtifactViewerPanelComponent_Conditional_20_Conditional_8_Conditional_0_Case_4_Template, 1, 1, "div", 70)(5, ArtifactViewerPanelComponent_Conditional_20_Conditional_8_Conditional_0_Case_5_Template, 2, 1, "pre", 71);
384
385
  i0.ɵɵelementEnd();
385
- i0.ɵɵelementStart(32, "button", 74);
386
- i0.ɵɵlistener("click", function ArtifactViewerPanelComponent_Conditional_21_Template_button_click_32_listener() { i0.ɵɵrestoreView(_r12); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.saveToSelectedCollection()); });
387
- i0.ɵɵtemplate(33, ArtifactViewerPanelComponent_Conditional_21_Conditional_33_Template, 2, 0)(34, ArtifactViewerPanelComponent_Conditional_21_Conditional_34_Template, 2, 0);
388
- i0.ɵɵelementEnd()()()();
389
386
  } if (rf & 2) {
390
- const ctx_r0 = i0.ɵɵnextContext();
391
- i0.ɵɵadvance(12);
392
- i0.ɵɵtwoWayProperty("ngModel", ctx_r0.selectedCollectionId);
387
+ let tmp_4_0;
393
388
  i0.ɵɵadvance();
394
- i0.ɵɵproperty("ngValue", null);
389
+ i0.ɵɵconditional((tmp_4_0 = ctx.type) === "markdown" ? 1 : tmp_4_0 === "json" ? 2 : tmp_4_0 === "code" ? 3 : tmp_4_0 === "html" ? 4 : tmp_4_0 === "plaintext" ? 5 : -1);
390
+ } }
391
+ function ArtifactViewerPanelComponent_Conditional_20_Conditional_8_Template(rf, ctx) { if (rf & 1) {
392
+ i0.ɵɵtemplate(0, ArtifactViewerPanelComponent_Conditional_20_Conditional_8_Conditional_0_Template, 6, 1, "div", 66);
393
+ } if (rf & 2) {
394
+ let tmp_2_0;
395
+ const ctx_r0 = i0.ɵɵnextContext(2);
396
+ i0.ɵɵconditional((tmp_2_0 = ctx_r0.GetTabContent(ctx_r0.activeTab)) ? 0 : -1, tmp_2_0);
397
+ } }
398
+ function ArtifactViewerPanelComponent_Conditional_20_Template(rf, ctx) { if (rf & 1) {
399
+ i0.ɵɵelementStart(0, "div", 17)(1, "div", 29);
400
+ i0.ɵɵrepeaterCreate(2, ArtifactViewerPanelComponent_Conditional_20_For_3_Template, 3, 4, "button", 30, i0.ɵɵrepeaterTrackByIdentity);
401
+ i0.ɵɵelementEnd();
402
+ i0.ɵɵelementStart(4, "div", 31);
403
+ i0.ɵɵtemplate(5, ArtifactViewerPanelComponent_Conditional_20_Conditional_5_Template, 3, 1, "div", 32)(6, ArtifactViewerPanelComponent_Conditional_20_Conditional_6_Template, 27, 13, "div", 33)(7, ArtifactViewerPanelComponent_Conditional_20_Conditional_7_Template, 3, 1, "div", 34)(8, ArtifactViewerPanelComponent_Conditional_20_Conditional_8_Template, 1, 1);
404
+ i0.ɵɵelementEnd()();
405
+ } if (rf & 2) {
406
+ const ctx_r0 = i0.ɵɵnextContext();
395
407
  i0.ɵɵadvance(2);
396
- i0.ɵɵrepeater(ctx_r0.collections);
397
- i0.ɵɵadvance(9);
398
- i0.ɵɵtwoWayProperty("ngModel", ctx_r0.newCollectionName);
408
+ i0.ɵɵrepeater(ctx_r0.allTabs);
409
+ i0.ɵɵadvance(3);
410
+ i0.ɵɵconditional(ctx_r0.activeTab === "display" ? 5 : -1);
399
411
  i0.ɵɵadvance();
400
- i0.ɵɵproperty("disabled", ctx_r0.isCreatingCollection || !ctx_r0.newCollectionName.trim());
412
+ i0.ɵɵconditional(ctx_r0.activeTab === "details" ? 6 : -1);
401
413
  i0.ɵɵadvance();
402
- i0.ɵɵconditional(ctx_r0.isCreatingCollection ? 26 : 27);
403
- i0.ɵɵadvance(6);
404
- i0.ɵɵproperty("disabled", !ctx_r0.selectedCollectionId || ctx_r0.isSavingToLibrary);
414
+ i0.ɵɵconditional(ctx_r0.activeTab === "links" ? 7 : -1);
405
415
  i0.ɵɵadvance();
406
- i0.ɵɵconditional(ctx_r0.isSavingToLibrary ? 33 : 34);
416
+ i0.ɵɵconditional(ctx_r0.activeTab !== "display" && ctx_r0.activeTab !== "details" && ctx_r0.activeTab !== "links" ? 8 : -1);
407
417
  } }
408
418
  export class ArtifactViewerPanelComponent {
419
+ notificationService;
420
+ sanitizer;
409
421
  artifactId;
410
422
  currentUser;
411
423
  environmentId;
412
424
  versionNumber; // Version to display
413
425
  showSaveToCollection = true; // Control whether Save to Collection button is shown
414
426
  refreshTrigger;
427
+ viewContext = null; // Where artifact is being viewed
428
+ contextCollectionId; // If viewing in collection, which collection
415
429
  closed = new EventEmitter();
430
+ saveToCollectionRequested = new EventEmitter();
431
+ navigateToLink = new EventEmitter();
416
432
  pluginViewer;
417
433
  destroy$ = new Subject();
418
434
  artifact = null;
@@ -423,23 +439,79 @@ export class ArtifactViewerPanelComponent {
423
439
  error = null;
424
440
  jsonContent = '';
425
441
  showVersionDropdown = false;
426
- showLibraryDialog = false;
427
- collections = [];
428
- selectedCollectionId = null;
429
- newCollectionName = '';
430
- isCreatingCollection = false;
431
- isSavingToLibrary = false;
432
442
  artifactCollections = [];
433
443
  primaryCollection = null;
434
444
  // Tabbed interface
435
- activeTab = 'display';
445
+ activeTab = 'display'; // Changed to string to support dynamic tabs
436
446
  displayMarkdown = null;
437
447
  displayHtml = null;
438
448
  versionAttributes = [];
439
449
  artifactTypeDriverClass = null;
450
+ // Links tab data
451
+ originConversation = null;
452
+ allCollections = [];
453
+ hasAccessToOriginConversation = false;
440
454
  // Cache plugin state to avoid losing it when switching tabs
441
455
  cachedPluginShouldShowRaw = false;
442
456
  cachedPluginIsElevated = false;
457
+ // Cache plugin tabs (populated once when plugin loads)
458
+ cachedPluginTabs = [];
459
+ // Dynamic tabs from plugin
460
+ get allTabs() {
461
+ // Start with Display tab
462
+ const tabs = ['Display'];
463
+ // Add cached plugin tabs
464
+ if (this.cachedPluginTabs.length > 0) {
465
+ const pluginTabLabels = this.cachedPluginTabs.map((t) => t.label);
466
+ tabs.push(...pluginTabLabels);
467
+ }
468
+ // Add base tabs
469
+ tabs.push('JSON', 'Details');
470
+ // Conditionally add Links tab if there are links to show
471
+ if (this.hasLinksTab) {
472
+ tabs.push('Links');
473
+ }
474
+ return tabs;
475
+ }
476
+ /**
477
+ * Called when plugin is loaded/changed to cache its tabs (avoids binding issues)
478
+ */
479
+ CachePluginTabs() {
480
+ const plugin = this.pluginViewer?.pluginInstance;
481
+ if (plugin?.GetAdditionalTabs) {
482
+ this.cachedPluginTabs = plugin.GetAdditionalTabs();
483
+ }
484
+ else {
485
+ this.cachedPluginTabs = [];
486
+ }
487
+ }
488
+ GetTabContent(tabName) {
489
+ // Check if this is a plugin-provided tab (use cached tabs - case-insensitive match)
490
+ const pluginTab = this.cachedPluginTabs.find((t) => t.label.toLowerCase() === tabName.toLowerCase());
491
+ if (pluginTab) {
492
+ const content = typeof pluginTab.content === 'function'
493
+ ? pluginTab.content()
494
+ : pluginTab.content;
495
+ return {
496
+ type: pluginTab.contentType,
497
+ content: content,
498
+ language: pluginTab.language
499
+ };
500
+ }
501
+ // Handle base tabs
502
+ switch (tabName.toLowerCase()) {
503
+ case 'json':
504
+ return { type: 'json', content: this.jsonContent, language: 'json' };
505
+ case 'details':
506
+ return { type: 'html', content: this.displayMarkdown || this.displayHtml || '' };
507
+ default:
508
+ return null;
509
+ }
510
+ }
511
+ constructor(notificationService, sanitizer) {
512
+ this.notificationService = notificationService;
513
+ this.sanitizer = sanitizer;
514
+ }
443
515
  async ngOnInit() {
444
516
  // Subscribe to refresh trigger for dynamic version changes
445
517
  if (this.refreshTrigger) {
@@ -470,7 +542,7 @@ export class ArtifactViewerPanelComponent {
470
542
  // Just switch to the version we already have
471
543
  this.artifactVersion = targetVersion;
472
544
  this.selectedVersionNumber = targetVersion.VersionNumber || 1;
473
- this.jsonContent = targetVersion.Content || '{}';
545
+ this.jsonContent = this.FormatJSON(targetVersion.Content || '{}');
474
546
  console.log(`📦 Switched to cached version ${this.selectedVersionNumber}`);
475
547
  // Load version attributes
476
548
  await this.loadVersionAttributes();
@@ -520,26 +592,28 @@ export class ArtifactViewerPanelComponent {
520
592
  console.log(`📦 Loading specified version ${targetVersionNumber}`);
521
593
  this.artifactVersion = targetVersion;
522
594
  this.selectedVersionNumber = targetVersion.VersionNumber || 1;
523
- this.jsonContent = targetVersion.Content || '{}';
595
+ this.jsonContent = this.FormatJSON(targetVersion.Content || '{}');
524
596
  }
525
597
  else {
526
598
  console.warn(`📦 Version ${targetVersionNumber} not found, defaulting to latest`);
527
599
  // Target version not found, default to latest
528
600
  this.artifactVersion = result.Results[0];
529
601
  this.selectedVersionNumber = this.artifactVersion.VersionNumber || 1;
530
- this.jsonContent = this.artifactVersion.Content || '{}';
602
+ this.jsonContent = this.FormatJSON(this.artifactVersion.Content || '{}');
531
603
  }
532
604
  }
533
605
  else {
534
606
  // No target version, default to latest version (first in DESC order)
535
607
  this.artifactVersion = result.Results[0];
536
608
  this.selectedVersionNumber = this.artifactVersion.VersionNumber || 1;
537
- this.jsonContent = this.artifactVersion.Content || '{}';
609
+ this.jsonContent = this.FormatJSON(this.artifactVersion.Content || '{}');
538
610
  }
539
611
  // Load version attributes
540
612
  await this.loadVersionAttributes();
541
613
  // Load collection associations
542
614
  await this.loadCollectionAssociations();
615
+ // Load links data
616
+ await this.loadLinksData();
543
617
  console.log(`📦 Loaded ${this.allVersions.length} versions for artifact ${this.artifactId}, showing v${this.selectedVersionNumber}`);
544
618
  }
545
619
  else {
@@ -552,6 +626,10 @@ export class ArtifactViewerPanelComponent {
552
626
  }
553
627
  finally {
554
628
  this.isLoading = false;
629
+ // Cache plugin tabs after loading (use setTimeout to ensure plugin is fully initialized)
630
+ setTimeout(() => {
631
+ this.CachePluginTabs();
632
+ }, 100);
555
633
  }
556
634
  }
557
635
  async loadArtifactType() {
@@ -590,6 +668,10 @@ export class ArtifactViewerPanelComponent {
590
668
  // Parse values - they might be JSON-encoded strings
591
669
  this.displayMarkdown = this.parseAttributeValue(displayMarkdownAttr?.Value);
592
670
  this.displayHtml = this.parseAttributeValue(displayHtmlAttr?.Value);
671
+ // Clean up double-escaped characters in HTML (from LLM generation)
672
+ if (this.displayHtml) {
673
+ this.displayHtml = this.cleanEscapedCharacters(this.displayHtml);
674
+ }
593
675
  // Default to display tab if we have a plugin or extracted display content
594
676
  // Otherwise default to JSON tab for JSON types, or Details tab as last resort
595
677
  if (this.hasDisplayTab) {
@@ -676,6 +758,22 @@ export class ArtifactViewerPanelComponent {
676
758
  }
677
759
  return value;
678
760
  }
761
+ /**
762
+ * Clean up double-escaped characters that appear in LLM-generated HTML
763
+ * Removes literal "\\n" and "\\t" which cause rendering issues
764
+ */
765
+ cleanEscapedCharacters(html) {
766
+ // Remove escaped newlines (\\n becomes nothing)
767
+ // HTML doesn't need whitespace for formatting, and these cause display issues
768
+ let cleaned = html.replace(/\\n/g, '');
769
+ // Remove escaped tabs
770
+ cleaned = cleaned.replace(/\\t/g, '');
771
+ // Remove double-escaped tabs
772
+ cleaned = cleaned.replace(/\\\\t/g, '');
773
+ // Remove double-escaped newlines
774
+ cleaned = cleaned.replace(/\\\\n/g, '');
775
+ return cleaned;
776
+ }
679
777
  async loadCollectionAssociations() {
680
778
  if (!this.artifactId)
681
779
  return;
@@ -714,7 +812,7 @@ export class ArtifactViewerPanelComponent {
714
812
  }
715
813
  }
716
814
  onCopyDisplayContent() {
717
- const content = this.displayMarkdown || this.displayHtml;
815
+ const content = this.displayHtml || this.displayMarkdown;
718
816
  if (content) {
719
817
  navigator.clipboard.writeText(content).then(() => {
720
818
  console.log('✅ Copied display content to clipboard');
@@ -723,6 +821,50 @@ export class ArtifactViewerPanelComponent {
723
821
  });
724
822
  }
725
823
  }
824
+ onPrintDisplayContent() {
825
+ // Try to delegate to the plugin viewer's print method
826
+ if (this.pluginViewer?.pluginInstance) {
827
+ const plugin = this.pluginViewer.pluginInstance;
828
+ if (typeof plugin.printHtml === 'function') {
829
+ plugin.printHtml();
830
+ return;
831
+ }
832
+ }
833
+ // Fallback: create a temporary print window with displayHtml or displayMarkdown
834
+ const content = this.displayHtml || this.displayMarkdown;
835
+ if (content) {
836
+ const printWindow = window.open('', '_blank');
837
+ if (printWindow) {
838
+ if (this.displayHtml) {
839
+ printWindow.document.write(content);
840
+ }
841
+ else if (this.displayMarkdown) {
842
+ // Wrap markdown in basic HTML for printing
843
+ printWindow.document.write(`
844
+ <!DOCTYPE html>
845
+ <html>
846
+ <head>
847
+ <title>Print</title>
848
+ <style>
849
+ body { font-family: sans-serif; padding: 20px; }
850
+ pre { background: #f5f5f5; padding: 10px; border-radius: 4px; }
851
+ </style>
852
+ </head>
853
+ <body>
854
+ <pre>${content}</pre>
855
+ </body>
856
+ </html>
857
+ `);
858
+ }
859
+ printWindow.document.close();
860
+ printWindow.focus();
861
+ setTimeout(() => {
862
+ printWindow.print();
863
+ printWindow.close();
864
+ }, 250);
865
+ }
866
+ }
867
+ }
726
868
  toggleVersionDropdown() {
727
869
  if (this.allVersions.length > 1) {
728
870
  this.showVersionDropdown = !this.showVersionDropdown;
@@ -731,134 +873,209 @@ export class ArtifactViewerPanelComponent {
731
873
  async selectVersion(version) {
732
874
  this.artifactVersion = version;
733
875
  this.selectedVersionNumber = version.VersionNumber || 1;
734
- this.jsonContent = version.Content || '{}';
876
+ this.jsonContent = this.FormatJSON(version.Content || '{}');
735
877
  this.showVersionDropdown = false;
736
878
  // Load attributes for the selected version
737
879
  await this.loadVersionAttributes();
738
- console.log(`📦 Switched to version ${this.selectedVersionNumber}`);
880
+ // Recache plugin tabs (version may have different metadata)
881
+ setTimeout(() => {
882
+ this.CachePluginTabs();
883
+ }, 100);
739
884
  }
740
885
  async onSaveToLibrary() {
741
- // If already in a collection, navigate to that collection
742
- if (this.isInCollection && this.primaryCollection) {
743
- // TODO: Implement navigation to collection view
744
- // For now, just log - will need ConversationStateService or similar to navigate
745
- console.log('Navigate to collection:', this.primaryCollection.Name, this.primaryCollection.ID);
746
- MJNotificationService.Instance.CreateSimpleNotification(`This artifact is saved in collection: ${this.primaryCollection.Name}`, 'info', 3000);
747
- return;
748
- }
749
- // If not in a collection, show the save dialog
750
- try {
751
- // Load user's collections
752
- const rv = new RunView();
753
- const result = await rv.RunView({
754
- EntityName: 'MJ: Collections',
755
- ExtraFilter: `EnvironmentID='${this.environmentId}'`,
756
- OrderBy: 'Name',
757
- ResultType: 'entity_object'
758
- }, this.currentUser);
759
- if (result.Success) {
760
- this.collections = result.Results || [];
761
- this.showLibraryDialog = true;
762
- }
763
- else {
764
- console.error('Failed to load collections:', result.ErrorMessage);
765
- MJNotificationService.Instance.CreateSimpleNotification('Failed to load collections. Please try again.', 'error');
766
- }
767
- }
768
- catch (err) {
769
- console.error('Error loading collections:', err);
770
- MJNotificationService.Instance.CreateSimpleNotification('Error loading collections. Please try again.', 'error');
771
- }
886
+ // Always show the collection picker modal
887
+ // Artifacts can be saved to multiple collections
888
+ this.saveToCollectionRequested.emit({
889
+ artifactId: this.artifactId,
890
+ excludedCollectionIds: this.excludedCollectionIds
891
+ });
772
892
  }
773
- async createNewCollection() {
774
- if (!this.newCollectionName.trim()) {
775
- MJNotificationService.Instance.CreateSimpleNotification('Please enter a collection name', 'warning', 2000);
776
- return;
893
+ get excludedCollectionIds() {
894
+ // Return IDs of collections that already contain this artifact
895
+ return this.artifactCollections.map(ca => ca.CollectionID);
896
+ }
897
+ /**
898
+ * Called by parent component after user selects collections in the picker.
899
+ * Saves the artifact to the selected collections.
900
+ */
901
+ async saveToCollections(collectionIds) {
902
+ if (!this.artifactId || collectionIds.length === 0) {
903
+ return false;
777
904
  }
778
905
  try {
779
- this.isCreatingCollection = true;
780
906
  const md = new Metadata();
781
- const collection = await md.GetEntityObject('MJ: Collections', this.currentUser);
782
- collection.EnvironmentID = this.environmentId;
783
- collection.Name = this.newCollectionName.trim();
784
- collection.Description = 'Created from conversation';
785
- const saved = await collection.Save();
786
- if (saved) {
787
- this.collections.push(collection);
788
- this.selectedCollectionId = collection.ID;
789
- this.newCollectionName = '';
790
- console.log('✅ Created new collection:', collection.Name);
791
- MJNotificationService.Instance.CreateSimpleNotification(`Collection "${collection.Name}" created successfully!`, 'success', 3000);
907
+ let successCount = 0;
908
+ // Save artifact to each selected collection
909
+ for (const collectionId of collectionIds) {
910
+ // Double check it doesn't already exist
911
+ const rv = new RunView();
912
+ const existingResult = await rv.RunView({
913
+ EntityName: 'MJ: Collection Artifacts',
914
+ ExtraFilter: `CollectionID='${collectionId}' AND ArtifactID='${this.artifactId}'`,
915
+ ResultType: 'entity_object'
916
+ }, this.currentUser);
917
+ if (existingResult.Success && existingResult.Results && existingResult.Results.length > 0) {
918
+ console.log(`Artifact already in collection ${collectionId}, skipping`);
919
+ continue;
920
+ }
921
+ // Create junction record
922
+ const collectionArtifact = await md.GetEntityObject('MJ: Collection Artifacts', this.currentUser);
923
+ collectionArtifact.CollectionID = collectionId;
924
+ collectionArtifact.ArtifactID = this.artifactId;
925
+ collectionArtifact.Sequence = 0;
926
+ const saved = await collectionArtifact.Save();
927
+ if (saved) {
928
+ successCount++;
929
+ }
930
+ else {
931
+ console.error(`Failed to save artifact to collection ${collectionId}`);
932
+ }
933
+ }
934
+ if (successCount > 0) {
935
+ console.log(`✅ Saved artifact to ${successCount} collection(s)`);
936
+ MJNotificationService.Instance.CreateSimpleNotification(`Artifact saved to ${successCount} collection(s) successfully!`, 'success', 3000);
937
+ // Reload collection associations to update the bookmark icon state
938
+ await this.loadCollectionAssociations();
939
+ return true;
792
940
  }
793
941
  else {
794
- MJNotificationService.Instance.CreateSimpleNotification('Failed to create collection. Please try again.', 'error');
942
+ MJNotificationService.Instance.CreateSimpleNotification('Failed to save artifact to any collections', 'error');
943
+ return false;
795
944
  }
796
945
  }
797
946
  catch (err) {
798
- console.error('Error creating collection:', err);
947
+ console.error('Error saving to collections:', err);
799
948
  LogError(err);
800
- MJNotificationService.Instance.CreateSimpleNotification('Error creating collection. Please try again.', 'error');
801
- }
802
- finally {
803
- this.isCreatingCollection = false;
949
+ MJNotificationService.Instance.CreateSimpleNotification('Error saving artifact to collections. Please try again.', 'error');
950
+ return false;
804
951
  }
805
952
  }
806
- async saveToSelectedCollection() {
807
- if (!this.selectedCollectionId) {
808
- MJNotificationService.Instance.CreateSimpleNotification('Please select a collection', 'warning', 2000);
809
- return;
810
- }
811
- if (!this.artifactId) {
812
- MJNotificationService.Instance.CreateSimpleNotification('No artifact to save', 'error');
953
+ /**
954
+ * Load links data: origin conversation and all collections containing this artifact
955
+ */
956
+ async loadLinksData() {
957
+ if (!this.artifactId)
813
958
  return;
814
- }
815
959
  try {
816
- this.isSavingToLibrary = true;
817
- // Check if artifact already exists in this collection
960
+ const md = new Metadata();
818
961
  const rv = new RunView();
819
- const existingResult = await rv.RunView({
962
+ // Load all collections containing this artifact
963
+ const collArtifactsResult = await rv.RunView({
820
964
  EntityName: 'MJ: Collection Artifacts',
821
- ExtraFilter: `CollectionID='${this.selectedCollectionId}' AND ArtifactID='${this.artifactId}'`,
965
+ ExtraFilter: `ArtifactID='${this.artifactId}'`,
822
966
  ResultType: 'entity_object'
823
967
  }, this.currentUser);
824
- if (existingResult.Success && existingResult.Results && existingResult.Results.length > 0) {
825
- MJNotificationService.Instance.CreateSimpleNotification('This artifact is already in the selected collection', 'info', 3000);
826
- this.showLibraryDialog = false;
827
- return;
828
- }
829
- // Create junction record
830
- const md = new Metadata();
831
- const collectionArtifact = await md.GetEntityObject('MJ: Collection Artifacts', this.currentUser);
832
- collectionArtifact.CollectionID = this.selectedCollectionId;
833
- collectionArtifact.ArtifactID = this.artifactId;
834
- collectionArtifact.Sequence = 0; // Could calculate max sequence + 1 if needed
835
- const saved = await collectionArtifact.Save();
836
- if (saved) {
837
- const collectionName = this.collections.find(c => c.ID === this.selectedCollectionId)?.Name || 'collection';
838
- console.log(`✅ Saved artifact to ${collectionName}`);
839
- MJNotificationService.Instance.CreateSimpleNotification(`Artifact saved to ${collectionName} successfully!`, 'success', 3000);
840
- this.showLibraryDialog = false;
841
- this.selectedCollectionId = null;
842
- // Reload collection associations to update the bookmark icon state
843
- await this.loadCollectionAssociations();
968
+ if (collArtifactsResult.Success && collArtifactsResult.Results) {
969
+ // Get unique collection IDs
970
+ const collectionIds = [...new Set(collArtifactsResult.Results.map(ca => ca.CollectionID))];
971
+ if (collectionIds.length > 0) {
972
+ const collectionsFilter = collectionIds.map(id => `ID='${id}'`).join(' OR ');
973
+ const collectionsResult = await rv.RunView({
974
+ EntityName: 'MJ: Collections',
975
+ ExtraFilter: collectionsFilter,
976
+ ResultType: 'entity_object'
977
+ }, this.currentUser);
978
+ if (collectionsResult.Success && collectionsResult.Results) {
979
+ this.allCollections = collectionsResult.Results;
980
+ }
981
+ }
844
982
  }
845
- else {
846
- MJNotificationService.Instance.CreateSimpleNotification('Failed to save artifact to collection. Please try again.', 'error');
983
+ // Load origin conversation (if artifact came from conversation)
984
+ // Artifacts are linked to conversations via ConversationDetailArtifact -> ConversationDetail -> Conversation
985
+ // Get all version IDs for this artifact
986
+ const versionIds = this.allVersions.map(v => v.ID);
987
+ if (versionIds.length > 0) {
988
+ const versionFilter = versionIds.map(id => `ArtifactVersionID='${id}'`).join(' OR ');
989
+ const convDetailArtifactsResult = await rv.RunView({
990
+ EntityName: 'MJ: Conversation Detail Artifacts',
991
+ ExtraFilter: versionFilter,
992
+ MaxRows: 1,
993
+ ResultType: 'entity_object'
994
+ }, this.currentUser);
995
+ if (convDetailArtifactsResult.Success && convDetailArtifactsResult.Results && convDetailArtifactsResult.Results.length > 0) {
996
+ const conversationDetailId = convDetailArtifactsResult.Results[0].ConversationDetailID;
997
+ // Load the conversation detail to get the conversation ID
998
+ const conversationDetail = await md.GetEntityObject('Conversation Details', this.currentUser);
999
+ const detailLoaded = await conversationDetail.Load(conversationDetailId);
1000
+ if (detailLoaded && conversationDetail.ConversationID) {
1001
+ const conversation = await md.GetEntityObject('Conversations', this.currentUser);
1002
+ const loaded = await conversation.Load(conversationDetail.ConversationID);
1003
+ if (loaded) {
1004
+ this.originConversation = conversation;
1005
+ // Check if user has access (is owner or participant)
1006
+ const userIsOwner = conversation.UserID === this.currentUser.ID;
1007
+ // Check if user is a participant
1008
+ const participantResult = await rv.RunView({
1009
+ EntityName: 'Conversation Details',
1010
+ ExtraFilter: `ConversationID='${conversation.ID}' AND UserID='${this.currentUser.ID}'`,
1011
+ MaxRows: 1,
1012
+ ResultType: 'simple'
1013
+ }, this.currentUser);
1014
+ const userIsParticipant = participantResult.Success &&
1015
+ participantResult.Results &&
1016
+ participantResult.Results.length > 0;
1017
+ this.hasAccessToOriginConversation = userIsOwner || userIsParticipant;
1018
+ }
1019
+ }
1020
+ }
847
1021
  }
1022
+ console.log(`🔗 Loaded links: ${this.allCollections.length} collections, origin conversation: ${this.originConversation?.Name || 'none'}`);
848
1023
  }
849
- catch (err) {
850
- console.error('Error saving to collection:', err);
851
- LogError(err);
852
- MJNotificationService.Instance.CreateSimpleNotification('Error saving artifact to collection. Please try again.', 'error');
1024
+ catch (error) {
1025
+ console.error('Error loading links data:', error);
853
1026
  }
854
- finally {
855
- this.isSavingToLibrary = false;
1027
+ }
1028
+ get hasLinksTab() {
1029
+ // Show links tab if:
1030
+ // 1. Viewing in collection and there's an origin conversation OR other collections
1031
+ // 2. Viewing in conversation and there are any collections
1032
+ if (this.viewContext === 'collection') {
1033
+ // Show if there's an origin conversation, or more than 1 collection (current + others)
1034
+ return !!this.originConversation || this.allCollections.length > 1;
856
1035
  }
1036
+ else if (this.viewContext === 'conversation') {
1037
+ // Show if there are any collections
1038
+ return this.allCollections.length > 0;
1039
+ }
1040
+ return false;
857
1041
  }
858
- cancelLibraryDialog() {
859
- this.showLibraryDialog = false;
860
- this.selectedCollectionId = null;
861
- this.newCollectionName = '';
1042
+ get linksToShow() {
1043
+ const links = [];
1044
+ // Add origin conversation if viewing in collection
1045
+ if (this.viewContext === 'collection' && this.originConversation) {
1046
+ links.push({
1047
+ type: 'conversation',
1048
+ id: this.originConversation.ID,
1049
+ name: this.originConversation.Name || 'Untitled Conversation',
1050
+ hasAccess: this.hasAccessToOriginConversation
1051
+ });
1052
+ }
1053
+ // Add all collections (excluding current context if applicable)
1054
+ for (const collection of this.allCollections) {
1055
+ if (this.viewContext === 'collection' && collection.ID === this.contextCollectionId) {
1056
+ // Skip current collection
1057
+ continue;
1058
+ }
1059
+ links.push({
1060
+ type: 'collection',
1061
+ id: collection.ID,
1062
+ name: collection.Name,
1063
+ hasAccess: true // User can see it, so they have access
1064
+ });
1065
+ }
1066
+ return links;
1067
+ }
1068
+ /**
1069
+ * Navigate to a linked conversation or collection
1070
+ */
1071
+ onNavigateToLink(link) {
1072
+ if (!link.hasAccess) {
1073
+ return;
1074
+ }
1075
+ this.navigateToLink.emit({
1076
+ type: link.type,
1077
+ id: link.id
1078
+ });
862
1079
  }
863
1080
  onClose() {
864
1081
  this.closed.emit();
@@ -907,13 +1124,86 @@ export class ArtifactViewerPanelComponent {
907
1124
  return null;
908
1125
  }
909
1126
  }
910
- static ɵfac = function ArtifactViewerPanelComponent_Factory(t) { return new (t || ArtifactViewerPanelComponent)(); };
1127
+ /**
1128
+ * Format JSON content using ParseJSONRecursive for deep parsing and formatting
1129
+ */
1130
+ FormatJSON(content) {
1131
+ try {
1132
+ // First parse the JSON string to an object
1133
+ const obj = JSON.parse(content);
1134
+ // Then use ParseJSONRecursive to extract any inline JSON strings
1135
+ const parseOptions = {
1136
+ extractInlineJson: true,
1137
+ maxDepth: 100,
1138
+ debug: false
1139
+ };
1140
+ const parsed = ParseJSONRecursive(obj, parseOptions);
1141
+ // Finally stringify with formatting
1142
+ return JSON.stringify(parsed, null, 2);
1143
+ }
1144
+ catch (e) {
1145
+ // Fallback to simple parse/stringify if ParseJSONRecursive fails
1146
+ try {
1147
+ const obj = JSON.parse(content);
1148
+ return JSON.stringify(obj, null, 2);
1149
+ }
1150
+ catch (e2) {
1151
+ // If even simple parse fails, return as-is
1152
+ return content;
1153
+ }
1154
+ }
1155
+ }
1156
+ /**
1157
+ * Get icon class for a tab
1158
+ */
1159
+ GetTabIcon(tabName) {
1160
+ // Base tabs
1161
+ const baseIcons = {
1162
+ 'Display': 'fas fa-eye',
1163
+ 'Code': 'fas fa-code',
1164
+ 'JSON': 'fas fa-file-code',
1165
+ 'Details': 'fas fa-info-circle',
1166
+ 'Links': 'fas fa-link'
1167
+ };
1168
+ if (baseIcons[tabName]) {
1169
+ return baseIcons[tabName];
1170
+ }
1171
+ // Check plugin tabs
1172
+ const plugin = this.pluginViewer?.pluginInstance;
1173
+ if (plugin?.GetAdditionalTabs) {
1174
+ const pluginTab = plugin.GetAdditionalTabs().find((t) => t.label === tabName);
1175
+ if (pluginTab?.icon) {
1176
+ return 'fas ' + pluginTab.icon; // Ensure full Font Awesome class
1177
+ }
1178
+ }
1179
+ return null;
1180
+ }
1181
+ /**
1182
+ * Render markdown to HTML (for markdown tabs)
1183
+ */
1184
+ RenderMarkdown(markdown) {
1185
+ try {
1186
+ const html = marked.parse(markdown);
1187
+ return this.sanitizer.sanitize(SecurityContext.HTML, html) || '';
1188
+ }
1189
+ catch (e) {
1190
+ console.error('Failed to render markdown:', e);
1191
+ return markdown;
1192
+ }
1193
+ }
1194
+ /**
1195
+ * Set active tab
1196
+ */
1197
+ SetActiveTab(tabName) {
1198
+ this.activeTab = tabName.toLowerCase();
1199
+ }
1200
+ static ɵfac = function ArtifactViewerPanelComponent_Factory(t) { return new (t || ArtifactViewerPanelComponent)(i0.ɵɵdirectiveInject(i1.MJNotificationService), i0.ɵɵdirectiveInject(i2.DomSanitizer)); };
911
1201
  static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ArtifactViewerPanelComponent, selectors: [["mj-artifact-viewer-panel"]], viewQuery: function ArtifactViewerPanelComponent_Query(rf, ctx) { if (rf & 1) {
912
1202
  i0.ɵɵviewQuery(ArtifactTypePluginViewerComponent, 5);
913
1203
  } if (rf & 2) {
914
1204
  let _t;
915
1205
  i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.pluginViewer = _t.first);
916
- } }, inputs: { artifactId: "artifactId", currentUser: "currentUser", environmentId: "environmentId", versionNumber: "versionNumber", showSaveToCollection: "showSaveToCollection", refreshTrigger: "refreshTrigger" }, outputs: { closed: "closed" }, features: [i0.ɵɵNgOnChangesFeature], decls: 22, vars: 12, consts: [[1, "artifact-viewer-panel"], [1, "panel-header"], [1, "panel-header-left"], [1, "fas", "fa-cube"], [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"], [1, "save-to-collection-btn", 3, "in-collection", "title"], ["title", "Close", 1, "close-btn", 3, "click"], [1, "fas", "fa-times"], [1, "panel-content"], [1, "loading-state"], [1, "error-state"], [1, "artifact-content-wrapper"], [1, "modal-overlay"], [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"], [1, "save-to-collection-btn", 3, "click", "title"], [3, "ngClass"], [1, "fas", "fa-spinner", "fa-spin"], [1, "fas", "fa-exclamation-triangle"], [1, "tab-navigation"], [1, "tab-btn", 3, "active"], [1, "tab-btn", 3, "click"], [1, "fas", "fa-info-circle"], [1, "tab-content"], [1, "display-content"], [1, "json-viewer"], [1, "details-content"], [1, "fas", "fa-eye"], [1, "fas", "fa-code"], [3, "artifactVersion", "artifactTypeName", "contentType", "readonly"], [1, "display-toolbar"], ["title", "Copy Content", 1, "btn-icon", 3, "click"], [1, "fas", "fa-copy"], [1, "markdown-content"], [1, "html-content", 3, "innerHTML"], [3, "data"], [1, "json-toolbar"], ["title", "Copy JSON", 1, "btn-icon", 3, "click"], [1, "json-editor-container"], [2, "width", "100%", "height", "100%", 3, "ngModelChange", "ngModel", "language", "readonly"], [1, "artifact-meta"], [1, "meta-item"], [1, "meta-item", "full-width"], [1, "attributes-section"], [1, "attributes-list"], [1, "attribute-item"], [1, "attribute-empty-pill"], [1, "modal-overlay", 3, "click"], [1, "modal-content", "library-modal", 3, "click"], [1, "modal-header"], [1, "fas", "fa-bookmark"], [1, "close-btn", 3, "click"], [1, "modal-body"], [1, "form-section"], [1, "form-select", 3, "ngModelChange", "ngModel"], [3, "ngValue"], [1, "divider"], [1, "create-collection-row"], ["type", "text", "placeholder", "Enter collection name", 1, "form-input", 3, "ngModelChange", "keyup.enter", "ngModel"], [1, "btn", "btn-secondary", 3, "click", "disabled"], [1, "fas", "fa-plus"], [1, "modal-footer"], [1, "btn", "btn-secondary", 3, "click"], [1, "btn", "btn-primary", 3, "click", "disabled"], [1, "fas", "fa-save"]], template: function ArtifactViewerPanelComponent_Template(rf, ctx) { if (rf & 1) {
1206
+ } }, inputs: { artifactId: "artifactId", currentUser: "currentUser", environmentId: "environmentId", versionNumber: "versionNumber", showSaveToCollection: "showSaveToCollection", refreshTrigger: "refreshTrigger", viewContext: "viewContext", contextCollectionId: "contextCollectionId" }, outputs: { closed: "closed", saveToCollectionRequested: "saveToCollectionRequested", navigateToLink: "navigateToLink" }, features: [i0.ɵɵNgOnChangesFeature], decls: 21, vars: 11, consts: [[1, "artifact-viewer-panel"], [1, "panel-header"], [1, "panel-header-left"], [1, "fas", "fa-cube"], [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", "Save to Collection", 1, "save-to-collection-btn"], ["title", "Close", 1, "close-btn", 3, "click"], [1, "fas", "fa-times"], [1, "panel-content"], [1, "loading-state"], [1, "error-state"], [1, "artifact-content-wrapper"], [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", "Save to Collection", 1, "save-to-collection-btn", 3, "click"], [1, "far", "fa-bookmark"], [1, "fas", "fa-spinner", "fa-spin"], [1, "fas", "fa-exclamation-triangle"], [1, "tab-navigation"], [1, "tab-btn", 3, "active"], [1, "tab-content"], [1, "display-content"], [1, "details-content"], [1, "links-container"], [1, "tab-btn", 3, "click"], [3, "class"], [3, "artifactVersion", "artifactTypeName", "contentType", "readonly"], [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"], [1, "artifact-meta"], [1, "meta-item"], [1, "meta-item", "full-width"], [1, "attributes-section"], [1, "attributes-list"], [1, "attribute-item"], [1, "attribute-empty-pill"], [1, "links-section"], [1, "empty-state"], [1, "link-item"], [1, "link-icon"], [1, "fas", "fa-comments"], [1, "fas", "fa-folder"], [1, "link-content"], [1, "link-name"], [1, "link-type"], [1, "link-actions"], [1, "link-action-btn", 3, "click", "disabled", "title"], [1, "fas", "fa-arrow-right"], [1, "fas", "fa-link"], [1, "dynamic-tab-content"], [1, "markdown-viewer", 3, "innerHTML"], [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"]], template: function ArtifactViewerPanelComponent_Template(rf, ctx) { if (rf & 1) {
917
1207
  i0.ɵɵelementStart(0, "div", 0)(1, "div", 1)(2, "div", 2)(3, "h3");
918
1208
  i0.ɵɵelement(4, "i", 3);
919
1209
  i0.ɵɵtext(5);
@@ -928,15 +1218,14 @@ export class ArtifactViewerPanelComponent {
928
1218
  i0.ɵɵelementEnd();
929
1219
  i0.ɵɵtemplate(12, ArtifactViewerPanelComponent_Conditional_12_Template, 1, 2, "i", 9)(13, ArtifactViewerPanelComponent_Conditional_13_Template, 3, 0, "div", 10);
930
1220
  i0.ɵɵelementEnd();
931
- i0.ɵɵtemplate(14, ArtifactViewerPanelComponent_Conditional_14_Template, 2, 4, "button", 11);
1221
+ i0.ɵɵtemplate(14, ArtifactViewerPanelComponent_Conditional_14_Template, 2, 0, "button", 11);
932
1222
  i0.ɵɵelementStart(15, "button", 12);
933
1223
  i0.ɵɵlistener("click", function ArtifactViewerPanelComponent_Template_button_click_15_listener() { return ctx.onClose(); });
934
1224
  i0.ɵɵelement(16, "i", 13);
935
1225
  i0.ɵɵelementEnd()()();
936
1226
  i0.ɵɵelementStart(17, "div", 14);
937
- i0.ɵɵtemplate(18, ArtifactViewerPanelComponent_Conditional_18_Template, 4, 0, "div", 15)(19, ArtifactViewerPanelComponent_Conditional_19_Template, 4, 1, "div", 16)(20, ArtifactViewerPanelComponent_Conditional_20_Template, 11, 7, "div", 17);
1227
+ i0.ɵɵtemplate(18, ArtifactViewerPanelComponent_Conditional_18_Template, 4, 0, "div", 15)(19, ArtifactViewerPanelComponent_Conditional_19_Template, 4, 1, "div", 16)(20, ArtifactViewerPanelComponent_Conditional_20_Template, 9, 4, "div", 17);
938
1228
  i0.ɵɵelementEnd()();
939
- i0.ɵɵtemplate(21, ArtifactViewerPanelComponent_Conditional_21_Template, 35, 7, "div", 18);
940
1229
  } if (rf & 2) {
941
1230
  i0.ɵɵadvance(5);
942
1231
  i0.ɵɵtextInterpolate1(" ", ctx.displayName, " ");
@@ -958,14 +1247,12 @@ export class ArtifactViewerPanelComponent {
958
1247
  i0.ɵɵconditional(ctx.error ? 19 : -1);
959
1248
  i0.ɵɵadvance();
960
1249
  i0.ɵɵconditional(!ctx.isLoading && !ctx.error && ctx.artifact ? 20 : -1);
961
- i0.ɵɵadvance();
962
- i0.ɵɵconditional(ctx.showLibraryDialog ? 21 : -1);
963
- } }, dependencies: [i1.NgClass, i2.NgSelectOption, i2.ɵNgSelectMultipleOption, i2.DefaultValueAccessor, i2.SelectControlValueAccessor, i2.NgControlStatus, i2.NgModel, i3.MarkdownComponent, i4.CodeEditorComponent, i5.ArtifactTypePluginViewerComponent, i1.DatePipe], styles: [".artifact-viewer-panel[_ngcontent-%COMP%] {\n height: 100%;\n background: white;\n border-left: 1px solid #E5E7EB;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n.panel-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 12px 16px;\n border-bottom: 1px solid #E5E7EB;\n background: white;\n flex-shrink: 0;\n}\n\n.panel-header-left[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.panel-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n font-weight: 600;\n display: flex;\n align-items: center;\n gap: 8px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.panel-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #6366F1;\n flex-shrink: 0;\n}\n\n.header-description[_ngcontent-%COMP%] {\n margin: 4px 0 0 0;\n font-size: 12px;\n color: #6B7280;\n font-weight: normal;\n}\n\n.panel-header-right[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n flex-shrink: 0;\n}\n\n.version-selector[_ngcontent-%COMP%] {\n position: relative;\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 4px 10px;\n background: #F3F4F6;\n border-radius: 12px;\n font-size: 12px;\n color: #6B7280;\n font-weight: 500;\n transition: all 0.2s;\n}\n\n.version-selector.clickable[_ngcontent-%COMP%] {\n cursor: pointer;\n}\n\n.version-selector.clickable[_ngcontent-%COMP%]:hover {\n background: #E5E7EB;\n}\n\n.version-selector[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 11px;\n}\n\n.version-selector[_ngcontent-%COMP%] .dropdown-icon[_ngcontent-%COMP%] {\n margin-left: 2px;\n transition: transform 0.2s;\n}\n\n.version-selector[_ngcontent-%COMP%] .dropdown-icon.open[_ngcontent-%COMP%] {\n transform: rotate(180deg);\n}\n\n.version-label[_ngcontent-%COMP%] {\n font-family: monospace;\n}\n\n.version-dropdown[_ngcontent-%COMP%] {\n position: absolute;\n top: calc(100% + 4px);\n right: 0;\n min-width: 200px;\n background: white;\n border: 1px solid #E5E7EB;\n border-radius: 8px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);\n z-index: 1000;\n overflow: hidden;\n}\n\n.version-option[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%]:hover {\n background: #F9FAFB;\n}\n\n.version-option.selected[_ngcontent-%COMP%] {\n background: #EEF2FF;\n color: #4F46E5;\n}\n\n.version-option[_ngcontent-%COMP%] .version-number[_ngcontent-%COMP%] {\n font-family: monospace;\n font-weight: 600;\n min-width: 35px;\n}\n\n.version-option[_ngcontent-%COMP%] .version-date[_ngcontent-%COMP%] {\n flex: 1;\n color: #6B7280;\n font-size: 12px;\n}\n\n.version-option[_ngcontent-%COMP%] i.fa-check[_ngcontent-%COMP%] {\n color: #10B981;\n margin-left: auto;\n}\n\n.save-to-collection-btn[_ngcontent-%COMP%] {\n background: none;\n border: none;\n cursor: pointer;\n color: #9CA3AF;\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[_ngcontent-%COMP%]:hover {\n background: #F3F4F6;\n color: #6B7280;\n}\n\n.save-to-collection-btn.in-collection[_ngcontent-%COMP%] {\n color: #F59E0B;\n}\n\n.save-to-collection-btn.in-collection[_ngcontent-%COMP%]:hover {\n background: #FEF3C7;\n color: #D97706;\n}\n\n.save-to-collection-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n.close-btn[_ngcontent-%COMP%] {\n background: none;\n border: none;\n cursor: pointer;\n color: #6B7280;\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[_ngcontent-%COMP%]:hover {\n background: #F3F4F6;\n color: #111827;\n}\n\n.close-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n.panel-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n min-height: 0;\n display: flex;\n flex-direction: column;\n}\n\n.artifact-content-wrapper[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n min-height: 0;\n}\n\n.loading-state[_ngcontent-%COMP%], \n.error-state[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 12px;\n padding: 40px 20px;\n color: #6B7280;\n}\n\n.error-state[_ngcontent-%COMP%] {\n color: #DC2626;\n}\n\n.loading-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 24px;\n}\n\n.artifact-meta[_ngcontent-%COMP%] {\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: #F9FAFB;\n border-radius: 8px;\n flex-shrink: 0;\n}\n\n.meta-item[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.meta-item[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 500;\n color: #6B7280;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.meta-item[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n font-size: 14px;\n color: #111827;\n}\n\n.artifact-description[_ngcontent-%COMP%] {\n padding: 12px;\n margin-bottom: 16px;\n background: #EFF6FF;\n border-left: 3px solid #3B82F6;\n border-radius: 4px;\n color: #1E40AF;\n font-size: 14px;\n flex-shrink: 0;\n}\n\n.json-viewer[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n border: 1px solid #E5E7EB;\n border-radius: 8px;\n overflow: hidden;\n min-height: 0;\n}\n\n.json-editor-container[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n min-height: 0;\n}\n\n.json-toolbar[_ngcontent-%COMP%] {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n padding: 8px 12px;\n background: #F9FAFB;\n border-bottom: 1px solid #E5E7EB;\n flex-shrink: 0;\n}\n\n.btn-icon[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n background: white;\n border: 1px solid #D1D5DB;\n border-radius: 4px;\n padding: 6px 12px;\n cursor: pointer;\n color: #374151;\n font-size: 14px;\n transition: all 0.2s;\n}\n\n.btn-icon[_ngcontent-%COMP%]:hover {\n background: #F3F4F6;\n border-color: #9CA3AF;\n}\n\n.btn-icon.btn-primary[_ngcontent-%COMP%] {\n background: #4F46E5;\n border-color: #4F46E5;\n color: white;\n}\n\n.btn-icon.btn-primary[_ngcontent-%COMP%]:hover {\n background: #4338CA;\n border-color: #4338CA;\n}\n\n.btn-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n\n\n.modal-overlay[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10000;\n}\n\n.modal-content[_ngcontent-%COMP%] {\n background: white;\n border-radius: 12px;\n box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2);\n max-width: 500px;\n width: 90%;\n max-height: 90vh;\n display: flex;\n flex-direction: column;\n}\n\n.modal-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 16px 20px;\n border-bottom: 1px solid #E5E7EB;\n}\n\n.modal-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #F59E0B;\n}\n\n.modal-body[_ngcontent-%COMP%] {\n padding: 20px;\n overflow-y: auto;\n}\n\n.modal-footer[_ngcontent-%COMP%] {\n display: flex;\n justify-content: flex-end;\n gap: 12px;\n padding: 16px 20px;\n border-top: 1px solid #E5E7EB;\n}\n\n.form-section[_ngcontent-%COMP%] {\n margin-bottom: 20px;\n}\n\n.form-section[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\n display: block;\n margin-bottom: 8px;\n font-size: 14px;\n font-weight: 500;\n color: #374151;\n}\n\n.form-select[_ngcontent-%COMP%], \n.form-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 10px 12px;\n border: 1px solid #D1D5DB;\n border-radius: 6px;\n font-size: 14px;\n color: #111827;\n background: white;\n transition: border-color 0.2s;\n}\n\n.form-select[_ngcontent-%COMP%]:focus, \n.form-input[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: #4F46E5;\n box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1);\n}\n\n.divider[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n margin: 24px 0;\n color: #9CA3AF;\n font-size: 12px;\n font-weight: 500;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.divider[_ngcontent-%COMP%]::before, \n.divider[_ngcontent-%COMP%]::after {\n content: '';\n flex: 1;\n height: 1px;\n background: #E5E7EB;\n}\n\n.divider[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n padding: 0 12px;\n}\n\n.create-collection-row[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n}\n\n.create-collection-row[_ngcontent-%COMP%] .form-input[_ngcontent-%COMP%] {\n flex: 1;\n}\n\n.btn[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%]:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.btn-primary[_ngcontent-%COMP%] {\n background: #4F46E5;\n color: white;\n}\n\n.btn-primary[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: #4338CA;\n}\n\n.btn-secondary[_ngcontent-%COMP%] {\n background: white;\n border: 1px solid #D1D5DB;\n color: #374151;\n}\n\n.btn-secondary[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: #F3F4F6;\n}\n\n\n\n.tab-navigation[_ngcontent-%COMP%] {\n display: flex;\n gap: 0;\n border-bottom: 2px solid #E5E7EB;\n padding: 0 16px;\n background: white;\n}\n\n.tab-btn[_ngcontent-%COMP%] {\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: #6B7280;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 150ms ease;\n}\n\n.tab-btn[_ngcontent-%COMP%]:hover {\n color: #1e40af;\n background: #F9FAFB;\n}\n\n.tab-btn.active[_ngcontent-%COMP%] {\n color: #1e40af;\n border-bottom-color: #1e40af;\n}\n\n.tab-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n\n\n.tab-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow: auto;\n width: 100%;\n}\n\n.display-content[_ngcontent-%COMP%] {\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}\n\n.display-toolbar[_ngcontent-%COMP%] {\n position: absolute;\n top: 12px;\n right: 12px;\n display: flex;\n gap: 8px;\n z-index: 10;\n}\n\n.markdown-content[_ngcontent-%COMP%], \n.html-content[_ngcontent-%COMP%] {\n flex: 1;\n font-size: 14px;\n line-height: 1.6;\n width: 100%;\n padding: 20px;\n box-sizing: border-box;\n overflow: auto;\n min-height: 0;\n}\n\n.details-content[_ngcontent-%COMP%] {\n padding: 20px;\n width: 100%;\n box-sizing: border-box;\n}\n\n.details-content[_ngcontent-%COMP%] .artifact-meta[_ngcontent-%COMP%] {\n margin-bottom: 0;\n padding: 20px;\n}\n\n.details-content[_ngcontent-%COMP%] .meta-item.full-width[_ngcontent-%COMP%] {\n grid-column: 1 / -1;\n}\n\n.attributes-section[_ngcontent-%COMP%] {\n margin-top: 24px;\n padding: 24px;\n background: #F9FAFB;\n border-radius: 8px;\n}\n\n.attributes-section[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] {\n margin: 0 0 16px 0;\n font-size: 14px;\n font-weight: 600;\n color: #111827;\n}\n\n.attributes-list[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));\n gap: 16px;\n}\n\n.attribute-item[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 12px;\n background: white;\n border-radius: 6px;\n border: 1px solid #E5E7EB;\n}\n\n.attribute-item[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\n font-size: 11px;\n font-weight: 600;\n color: #6B7280;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.attribute-item[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n font-size: 13px;\n color: #111827;\n word-break: break-word;\n}\n\n.attribute-empty-pill[_ngcontent-%COMP%] {\n display: inline-block;\n padding: 2px 8px;\n background: #F3F4F6;\n color: #9CA3AF;\n font-size: 11px;\n font-weight: 500;\n border-radius: 4px;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}"] });
1250
+ } }, dependencies: [i3.MarkdownComponent, i4.CodeEditorComponent, i5.ArtifactTypePluginViewerComponent, i6.DatePipe], styles: [".artifact-viewer-panel[_ngcontent-%COMP%] {\n width: 100%;\n height: 100%;\n background: white;\n border-left: 1px solid #E5E7EB;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n box-sizing: border-box;\n}\n\n.panel-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n padding: 12px 16px;\n border-bottom: 1px solid #E5E7EB;\n background: white;\n flex-shrink: 0;\n width: 100%;\n box-sizing: border-box;\n}\n\n.panel-header-left[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n margin-right: 16px;\n}\n\n.panel-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #6366F1;\n flex-shrink: 0;\n margin-top: 2px;\n}\n\n.header-description[_ngcontent-%COMP%] {\n margin: 4px 0 0 0;\n font-size: 12px;\n color: #6B7280;\n font-weight: normal;\n word-wrap: break-word;\n overflow-wrap: break-word;\n}\n\n.panel-header-right[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n flex-shrink: 0;\n}\n\n.version-selector[_ngcontent-%COMP%] {\n position: relative;\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 4px 10px;\n background: #F3F4F6;\n border-radius: 12px;\n font-size: 12px;\n color: #6B7280;\n font-weight: 500;\n transition: all 0.2s;\n}\n\n.version-selector.clickable[_ngcontent-%COMP%] {\n cursor: pointer;\n}\n\n.version-selector.clickable[_ngcontent-%COMP%]:hover {\n background: #E5E7EB;\n}\n\n.version-selector[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 11px;\n}\n\n.version-selector[_ngcontent-%COMP%] .dropdown-icon[_ngcontent-%COMP%] {\n margin-left: 2px;\n transition: transform 0.2s;\n}\n\n.version-selector[_ngcontent-%COMP%] .dropdown-icon.open[_ngcontent-%COMP%] {\n transform: rotate(180deg);\n}\n\n.version-label[_ngcontent-%COMP%] {\n font-family: monospace;\n}\n\n.version-dropdown[_ngcontent-%COMP%] {\n position: absolute;\n top: calc(100% + 4px);\n right: 0;\n min-width: 200px;\n background: white;\n border: 1px solid #E5E7EB;\n border-radius: 8px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);\n z-index: 1000;\n overflow: hidden;\n}\n\n.version-option[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%]:hover {\n background: #F9FAFB;\n}\n\n.version-option.selected[_ngcontent-%COMP%] {\n background: #EEF2FF;\n color: #4F46E5;\n}\n\n.version-option[_ngcontent-%COMP%] .version-number[_ngcontent-%COMP%] {\n font-family: monospace;\n font-weight: 600;\n min-width: 35px;\n}\n\n.version-option[_ngcontent-%COMP%] .version-date[_ngcontent-%COMP%] {\n flex: 1;\n color: #6B7280;\n font-size: 12px;\n}\n\n.version-option[_ngcontent-%COMP%] i.fa-check[_ngcontent-%COMP%] {\n color: #10B981;\n margin-left: auto;\n}\n\n.save-to-collection-btn[_ngcontent-%COMP%] {\n background: none;\n border: none;\n cursor: pointer;\n color: #9CA3AF;\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[_ngcontent-%COMP%]:hover {\n background: #F3F4F6;\n color: #6B7280;\n}\n\n.save-to-collection-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n.close-btn[_ngcontent-%COMP%] {\n background: none;\n border: none;\n cursor: pointer;\n color: #6B7280;\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[_ngcontent-%COMP%]:hover {\n background: #F3F4F6;\n color: #111827;\n}\n\n.close-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n.panel-content[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%], \n.error-state[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 12px;\n padding: 40px 20px;\n color: #6B7280;\n}\n\n.error-state[_ngcontent-%COMP%] {\n color: #DC2626;\n}\n\n.loading-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 24px;\n}\n\n.artifact-meta[_ngcontent-%COMP%] {\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: #F9FAFB;\n border-radius: 8px;\n flex-shrink: 0;\n}\n\n.meta-item[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.meta-item[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 500;\n color: #6B7280;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.meta-item[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n font-size: 14px;\n color: #111827;\n}\n\n.artifact-description[_ngcontent-%COMP%] {\n padding: 12px;\n margin-bottom: 16px;\n background: #EFF6FF;\n border-left: 3px solid #3B82F6;\n border-radius: 4px;\n color: #1E40AF;\n font-size: 14px;\n flex-shrink: 0;\n}\n\n.json-viewer[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n border: 1px solid #E5E7EB;\n border-radius: 8px;\n overflow: hidden;\n min-height: 0;\n}\n\n.json-editor-container[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n min-height: 0;\n}\n\n.json-toolbar[_ngcontent-%COMP%] {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n padding: 8px 12px;\n background: #F9FAFB;\n border-bottom: 1px solid #E5E7EB;\n flex-shrink: 0;\n}\n\n.btn-icon[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n background: white;\n border: 1px solid #D1D5DB;\n border-radius: 4px;\n padding: 6px 12px;\n cursor: pointer;\n color: #374151;\n font-size: 14px;\n transition: all 0.2s;\n}\n\n.btn-icon[_ngcontent-%COMP%]:hover {\n background: #F3F4F6;\n border-color: #9CA3AF;\n}\n\n.btn-icon.btn-primary[_ngcontent-%COMP%] {\n background: #4F46E5;\n border-color: #4F46E5;\n color: white;\n}\n\n.btn-icon.btn-primary[_ngcontent-%COMP%]:hover {\n background: #4338CA;\n border-color: #4338CA;\n}\n\n.btn-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n\n\n.modal-overlay[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10000;\n}\n\n.modal-content[_ngcontent-%COMP%] {\n background: white;\n border-radius: 12px;\n box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2);\n max-width: 500px;\n width: 90%;\n max-height: 90vh;\n display: flex;\n flex-direction: column;\n}\n\n.modal-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 16px 20px;\n border-bottom: 1px solid #E5E7EB;\n}\n\n.modal-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #F59E0B;\n}\n\n.modal-body[_ngcontent-%COMP%] {\n padding: 20px;\n overflow-y: auto;\n}\n\n.modal-footer[_ngcontent-%COMP%] {\n display: flex;\n justify-content: flex-end;\n gap: 12px;\n padding: 16px 20px;\n border-top: 1px solid #E5E7EB;\n}\n\n.form-section[_ngcontent-%COMP%] {\n margin-bottom: 20px;\n}\n\n.form-section[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\n display: block;\n margin-bottom: 8px;\n font-size: 14px;\n font-weight: 500;\n color: #374151;\n}\n\n.form-select[_ngcontent-%COMP%], \n.form-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 10px 12px;\n border: 1px solid #D1D5DB;\n border-radius: 6px;\n font-size: 14px;\n color: #111827;\n background: white;\n transition: border-color 0.2s;\n}\n\n.form-select[_ngcontent-%COMP%]:focus, \n.form-input[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: #4F46E5;\n box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1);\n}\n\n.divider[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n margin: 24px 0;\n color: #9CA3AF;\n font-size: 12px;\n font-weight: 500;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.divider[_ngcontent-%COMP%]::before, \n.divider[_ngcontent-%COMP%]::after {\n content: '';\n flex: 1;\n height: 1px;\n background: #E5E7EB;\n}\n\n.divider[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n padding: 0 12px;\n}\n\n.create-collection-row[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n}\n\n.create-collection-row[_ngcontent-%COMP%] .form-input[_ngcontent-%COMP%] {\n flex: 1;\n}\n\n.btn[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%]:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.btn-primary[_ngcontent-%COMP%] {\n background: #4F46E5;\n color: white;\n}\n\n.btn-primary[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: #4338CA;\n}\n\n.btn-secondary[_ngcontent-%COMP%] {\n background: white;\n border: 1px solid #D1D5DB;\n color: #374151;\n}\n\n.btn-secondary[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: #F3F4F6;\n}\n\n\n\n.tab-navigation[_ngcontent-%COMP%] {\n display: flex;\n gap: 0;\n border-bottom: 2px solid #E5E7EB;\n padding: 0 16px;\n background: white;\n}\n\n.tab-btn[_ngcontent-%COMP%] {\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: #6B7280;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 150ms ease;\n}\n\n.tab-btn[_ngcontent-%COMP%]:hover {\n color: #1e40af;\n background: #F9FAFB;\n}\n\n.tab-btn.active[_ngcontent-%COMP%] {\n color: #1e40af;\n border-bottom-color: #1e40af;\n}\n\n.tab-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n\n\n.tab-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow: auto;\n width: 100%;\n box-sizing: border-box;\n margin-bottom: 5px;\n min-width: 0;\n}\n\n.display-content[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n position: absolute;\n top: 12px;\n right: 12px;\n display: flex;\n gap: 8px;\n z-index: 10;\n}\n\n.markdown-content[_ngcontent-%COMP%], \n.html-content[_ngcontent-%COMP%] {\n flex: 1;\n font-size: 14px;\n line-height: 1.6;\n width: 100%;\n padding: 20px 10px 5px 20px; \n\n box-sizing: border-box;\n overflow: auto;\n min-height: 0;\n}\n\n.details-content[_ngcontent-%COMP%] {\n padding: 20px;\n width: 100%;\n box-sizing: border-box;\n}\n\n.details-content[_ngcontent-%COMP%] .artifact-meta[_ngcontent-%COMP%] {\n margin-bottom: 0;\n padding: 20px;\n}\n\n.details-content[_ngcontent-%COMP%] .meta-item.full-width[_ngcontent-%COMP%] {\n grid-column: 1 / -1;\n}\n\n.attributes-section[_ngcontent-%COMP%] {\n margin-top: 24px;\n padding: 24px;\n background: #F9FAFB;\n border-radius: 8px;\n}\n\n.attributes-section[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] {\n margin: 0 0 16px 0;\n font-size: 14px;\n font-weight: 600;\n color: #111827;\n}\n\n.attributes-list[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));\n gap: 16px;\n}\n\n.attribute-item[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 12px;\n background: white;\n border-radius: 6px;\n border: 1px solid #E5E7EB;\n}\n\n.attribute-item[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\n font-size: 11px;\n font-weight: 600;\n color: #6B7280;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.attribute-item[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n font-size: 13px;\n color: #111827;\n word-break: break-word;\n}\n\n.attribute-empty-pill[_ngcontent-%COMP%] {\n display: inline-block;\n padding: 2px 8px;\n background: #F3F4F6;\n color: #9CA3AF;\n font-size: 11px;\n font-weight: 500;\n border-radius: 4px;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n\n\n.links-container[_ngcontent-%COMP%] {\n padding: 20px;\n}\n\n.links-section[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.link-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px;\n background: #F9FAFB;\n border: 1px solid #E5E7EB;\n border-radius: 8px;\n transition: all 0.15s;\n}\n\n.link-item[_ngcontent-%COMP%]:hover {\n border-color: #1e40af;\n box-shadow: 0 2px 4px rgba(0,0,0,0.05);\n}\n\n.link-icon[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: white;\n border-radius: 8px;\n flex-shrink: 0;\n}\n\n.link-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 18px;\n color: #1e40af;\n}\n\n.link-content[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.link-name[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 500;\n color: #111827;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.link-type[_ngcontent-%COMP%] {\n font-size: 12px;\n color: #6B7280;\n margin-top: 2px;\n}\n\n.link-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n}\n\n.link-action-btn[_ngcontent-%COMP%] {\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: white;\n border: 1px solid #D1D5DB;\n border-radius: 6px;\n color: #1e40af;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.link-action-btn[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: #EFF6FF;\n border-color: #1e40af;\n}\n\n.link-action-btn[_ngcontent-%COMP%]:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n color: #9CA3AF;\n}\n\n.links-container[_ngcontent-%COMP%] .empty-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 48px 24px;\n color: #9CA3AF;\n text-align: center;\n}\n\n.links-container[_ngcontent-%COMP%] .empty-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 48px;\n margin-bottom: 16px;\n opacity: 0.3;\n}\n\n.links-container[_ngcontent-%COMP%] .empty-state[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n}\n\n\n\n.dynamic-tab-content[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n padding: 16px;\n}\n\n.markdown-viewer[_ngcontent-%COMP%] {\n flex: 1;\n overflow: auto;\n padding: 20px;\n background: white;\n line-height: 1.6;\n}\n\n.markdown-viewer[_ngcontent-%COMP%] h1[_ngcontent-%COMP%], .markdown-viewer[_ngcontent-%COMP%] h2[_ngcontent-%COMP%], .markdown-viewer[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin-top: 24px;\n margin-bottom: 12px;\n font-weight: 600;\n}\n\n.markdown-viewer[_ngcontent-%COMP%] h1[_ngcontent-%COMP%] { font-size: 24px; }\n.markdown-viewer[_ngcontent-%COMP%] h2[_ngcontent-%COMP%] { font-size: 20px; }\n.markdown-viewer[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] { font-size: 18px; }\n\n.markdown-viewer[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin-bottom: 12px;\n}\n\n.markdown-viewer[_ngcontent-%COMP%] ul[_ngcontent-%COMP%], .markdown-viewer[_ngcontent-%COMP%] ol[_ngcontent-%COMP%] {\n margin-bottom: 12px;\n padding-left: 24px;\n}\n\n.markdown-viewer[_ngcontent-%COMP%] code[_ngcontent-%COMP%] {\n background: #f3f4f6;\n padding: 2px 6px;\n border-radius: 3px;\n font-family: 'Courier New', monospace;\n font-size: 13px;\n}\n\n.markdown-viewer[_ngcontent-%COMP%] pre[_ngcontent-%COMP%] {\n background: #f3f4f6;\n padding: 12px;\n border-radius: 6px;\n overflow-x: auto;\n margin-bottom: 12px;\n}\n\n.markdown-viewer[_ngcontent-%COMP%] pre[_ngcontent-%COMP%] code[_ngcontent-%COMP%] {\n background: none;\n padding: 0;\n}\n\n.code-viewer[_ngcontent-%COMP%], .plaintext-viewer[_ngcontent-%COMP%] {\n flex: 1;\n overflow: auto;\n padding: 12px;\n background: #f9fafb;\n font-family: 'Courier New', monospace;\n font-size: 13px;\n white-space: pre-wrap;\n}\n\n.html-viewer[_ngcontent-%COMP%] {\n flex: 1;\n overflow: auto;\n padding: 20px;\n background: white;\n}"] });
964
1251
  }
965
1252
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ArtifactViewerPanelComponent, [{
966
1253
  type: Component,
967
- args: [{ selector: 'mj-artifact-viewer-panel', template: "<div class=\"artifact-viewer-panel\">\n <div class=\"panel-header\">\n <div class=\"panel-header-left\">\n <h3>\n <i class=\"fas fa-cube\"></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\" [class.clickable]=\"allVersions.length > 1\" (click)=\"toggleVersionDropdown()\">\n <i class=\"fas fa-history\"></i>\n <span class=\"version-label\">v{{ selectedVersionNumber }}</span>\n @if (allVersions.length > 1) {\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 (showSaveToCollection) {\n <button class=\"save-to-collection-btn\"\n [class.in-collection]=\"isInCollection\"\n (click)=\"onSaveToLibrary()\"\n [title]=\"isInCollection ? 'View in Collection' : 'Save to Collection'\">\n <i [ngClass]=\"isInCollection ? 'fas fa-bookmark' : 'far fa-bookmark'\"></i>\n </button>\n }\n <button class=\"close-btn\" (click)=\"onClose()\" title=\"Close\">\n <i class=\"fas fa-times\"></i>\n </button>\n </div>\n </div>\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 <div class=\"error-state\">\n <i class=\"fas fa-exclamation-triangle\"></i>\n <span>{{ error }}</span>\n </div>\n }\n\n @if (!isLoading && !error && artifact) {\n <div class=\"artifact-content-wrapper\">\n <!-- Tab Navigation -->\n <div class=\"tab-navigation\">\n @if (hasDisplayTab) {\n <button class=\"tab-btn\" [class.active]=\"activeTab === 'display'\" (click)=\"setActiveTab('display')\">\n <i class=\"fas fa-eye\"></i> Display\n </button>\n }\n @if (hasJsonTab) {\n <button class=\"tab-btn\" [class.active]=\"activeTab === 'json'\" (click)=\"setActiveTab('json')\">\n <i class=\"fas fa-code\"></i> JSON\n </button>\n }\n <button class=\"tab-btn\" [class.active]=\"activeTab === 'details'\" (click)=\"setActiveTab('details')\">\n <i class=\"fas fa-info-circle\"></i> Details\n </button>\n </div>\n\n <!-- Tab Content -->\n <div class=\"tab-content\">\n <!-- Display Tab (uses plugin system OR extracted attributes) -->\n @if (activeTab === 'display' && hasDisplayTab) {\n <div class=\"display-content\">\n @if (hasPlugin && artifactVersion && artifactTypeName) {\n <!-- Use plugin viewer if available -->\n <mj-artifact-type-plugin-viewer\n [artifactVersion]=\"artifactVersion\"\n [artifactTypeName]=\"artifactTypeName\"\n [contentType]=\"contentType\"\n [readonly]=\"true\">\n </mj-artifact-type-plugin-viewer>\n } @else if (displayMarkdown || displayHtml) {\n <!-- Fallback to extracted markdown/HTML attributes -->\n <div class=\"display-toolbar\">\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 <markdown [data]=\"displayMarkdown\"></markdown>\n </div>\n } @else if (displayHtml) {\n <div class=\"html-content\" [innerHTML]=\"displayHtml\"></div>\n }\n }\n </div>\n }\n\n <!-- JSON Tab (only shown for elevated displays with JSON content) -->\n @if (activeTab === 'json' && hasJsonTab) {\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 [(ngModel)]=\"jsonContent\"\n [language]=\"'json'\"\n [readonly]=\"true\"\n style=\"width: 100%; height: 100%;\">\n </mj-code-editor>\n </div>\n </div>\n }\n\n <!-- Details Tab -->\n @if (activeTab === 'details') {\n <div class=\"details-content\">\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 </div>\n </div>\n }\n </div>\n</div>\n\n<!-- Save to Collection Dialog -->\n@if (showLibraryDialog) {\n <div class=\"modal-overlay\" (click)=\"cancelLibraryDialog()\">\n <div class=\"modal-content library-modal\" (click)=\"$event.stopPropagation()\">\n <div class=\"modal-header\">\n <h3>\n <i class=\"fas fa-bookmark\"></i>\n Save to Collection\n </h3>\n <button class=\"close-btn\" (click)=\"cancelLibraryDialog()\">\n <i class=\"fas fa-times\"></i>\n </button>\n </div>\n <div class=\"modal-body\">\n <div class=\"form-section\">\n <label>Select Collection</label>\n <select [(ngModel)]=\"selectedCollectionId\" class=\"form-select\">\n <option [ngValue]=\"null\">-- Choose a collection --</option>\n @for (collection of collections; track collection.ID) {\n <option [ngValue]=\"collection.ID\">{{ collection.Name }}</option>\n }\n </select>\n </div>\n\n <div class=\"divider\">\n <span>OR</span>\n </div>\n\n <div class=\"form-section\">\n <label>Create New Collection</label>\n <div class=\"create-collection-row\">\n <input\n type=\"text\"\n [(ngModel)]=\"newCollectionName\"\n placeholder=\"Enter collection name\"\n class=\"form-input\"\n (keyup.enter)=\"createNewCollection()\">\n <button\n class=\"btn btn-secondary\"\n (click)=\"createNewCollection()\"\n [disabled]=\"isCreatingCollection || !newCollectionName.trim()\">\n @if (isCreatingCollection) {\n <i class=\"fas fa-spinner fa-spin\"></i>\n } @else {\n <i class=\"fas fa-plus\"></i>\n }\n Create\n </button>\n </div>\n </div>\n </div>\n <div class=\"modal-footer\">\n <button class=\"btn btn-secondary\" (click)=\"cancelLibraryDialog()\">\n Cancel\n </button>\n <button\n class=\"btn btn-primary\"\n (click)=\"saveToSelectedCollection()\"\n [disabled]=\"!selectedCollectionId || isSavingToLibrary\">\n @if (isSavingToLibrary) {\n <i class=\"fas fa-spinner fa-spin\"></i> Saving...\n } @else {\n <i class=\"fas fa-save\"></i> Save to Collection\n }\n </button>\n </div>\n </div>\n </div>\n}\n", styles: [".artifact-viewer-panel {\n height: 100%;\n background: white;\n border-left: 1px solid #E5E7EB;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n.panel-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 12px 16px;\n border-bottom: 1px solid #E5E7EB;\n background: white;\n flex-shrink: 0;\n}\n\n.panel-header-left {\n flex: 1;\n min-width: 0;\n}\n\n.panel-header h3 {\n margin: 0;\n font-size: 14px;\n font-weight: 600;\n display: flex;\n align-items: center;\n gap: 8px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.panel-header h3 i {\n color: #6366F1;\n flex-shrink: 0;\n}\n\n.header-description {\n margin: 4px 0 0 0;\n font-size: 12px;\n color: #6B7280;\n font-weight: normal;\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: #F3F4F6;\n border-radius: 12px;\n font-size: 12px;\n color: #6B7280;\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: #E5E7EB;\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: white;\n border: 1px solid #E5E7EB;\n border-radius: 8px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);\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: #F9FAFB;\n}\n\n.version-option.selected {\n background: #EEF2FF;\n color: #4F46E5;\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: #6B7280;\n font-size: 12px;\n}\n\n.version-option i.fa-check {\n color: #10B981;\n margin-left: auto;\n}\n\n.save-to-collection-btn {\n background: none;\n border: none;\n cursor: pointer;\n color: #9CA3AF;\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: #F3F4F6;\n color: #6B7280;\n}\n\n.save-to-collection-btn.in-collection {\n color: #F59E0B;\n}\n\n.save-to-collection-btn.in-collection:hover {\n background: #FEF3C7;\n color: #D97706;\n}\n\n.save-to-collection-btn i {\n font-size: 14px;\n}\n\n.close-btn {\n background: none;\n border: none;\n cursor: pointer;\n color: #6B7280;\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: #F3F4F6;\n color: #111827;\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}\n\n.artifact-content-wrapper {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n min-height: 0;\n}\n\n.loading-state,\n.error-state {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 12px;\n padding: 40px 20px;\n color: #6B7280;\n}\n\n.error-state {\n color: #DC2626;\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: #F9FAFB;\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: #6B7280;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.meta-item span {\n font-size: 14px;\n color: #111827;\n}\n\n.artifact-description {\n padding: 12px;\n margin-bottom: 16px;\n background: #EFF6FF;\n border-left: 3px solid #3B82F6;\n border-radius: 4px;\n color: #1E40AF;\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 #E5E7EB;\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: #F9FAFB;\n border-bottom: 1px solid #E5E7EB;\n flex-shrink: 0;\n}\n\n.btn-icon {\n display: flex;\n align-items: center;\n gap: 6px;\n background: white;\n border: 1px solid #D1D5DB;\n border-radius: 4px;\n padding: 6px 12px;\n cursor: pointer;\n color: #374151;\n font-size: 14px;\n transition: all 0.2s;\n}\n\n.btn-icon:hover {\n background: #F3F4F6;\n border-color: #9CA3AF;\n}\n\n.btn-icon.btn-primary {\n background: #4F46E5;\n border-color: #4F46E5;\n color: white;\n}\n\n.btn-icon.btn-primary:hover {\n background: #4338CA;\n border-color: #4338CA;\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: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10000;\n}\n\n.modal-content {\n background: white;\n border-radius: 12px;\n box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2);\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 #E5E7EB;\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: #F59E0B;\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 #E5E7EB;\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: #374151;\n}\n\n.form-select,\n.form-input {\n width: 100%;\n padding: 10px 12px;\n border: 1px solid #D1D5DB;\n border-radius: 6px;\n font-size: 14px;\n color: #111827;\n background: white;\n transition: border-color 0.2s;\n}\n\n.form-select:focus,\n.form-input:focus {\n outline: none;\n border-color: #4F46E5;\n box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1);\n}\n\n.divider {\n display: flex;\n align-items: center;\n margin: 24px 0;\n color: #9CA3AF;\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: #E5E7EB;\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: #4F46E5;\n color: white;\n}\n\n.btn-primary:hover:not(:disabled) {\n background: #4338CA;\n}\n\n.btn-secondary {\n background: white;\n border: 1px solid #D1D5DB;\n color: #374151;\n}\n\n.btn-secondary:hover:not(:disabled) {\n background: #F3F4F6;\n}\n\n/* Tab Navigation */\n.tab-navigation {\n display: flex;\n gap: 0;\n border-bottom: 2px solid #E5E7EB;\n padding: 0 16px;\n background: white;\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: #6B7280;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 150ms ease;\n}\n\n.tab-btn:hover {\n color: #1e40af;\n background: #F9FAFB;\n}\n\n.tab-btn.active {\n color: #1e40af;\n border-bottom-color: #1e40af;\n}\n\n.tab-btn i {\n font-size: 14px;\n}\n\n/* Tab Content */\n.tab-content {\n flex: 1;\n overflow: auto;\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}\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;\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: #F9FAFB;\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: #111827;\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: white;\n border-radius: 6px;\n border: 1px solid #E5E7EB;\n}\n\n.attribute-item label {\n font-size: 11px;\n font-weight: 600;\n color: #6B7280;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.attribute-item span {\n font-size: 13px;\n color: #111827;\n word-break: break-word;\n}\n\n.attribute-empty-pill {\n display: inline-block;\n padding: 2px 8px;\n background: #F3F4F6;\n color: #9CA3AF;\n font-size: 11px;\n font-weight: 500;\n border-radius: 4px;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n"] }]
968
- }], null, { artifactId: [{
1254
+ args: [{ selector: 'mj-artifact-viewer-panel', template: "<div class=\"artifact-viewer-panel\">\n <div class=\"panel-header\">\n <div class=\"panel-header-left\">\n <h3>\n <i class=\"fas fa-cube\"></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\" [class.clickable]=\"allVersions.length > 1\" (click)=\"toggleVersionDropdown()\">\n <i class=\"fas fa-history\"></i>\n <span class=\"version-label\">v{{ selectedVersionNumber }}</span>\n @if (allVersions.length > 1) {\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 (showSaveToCollection) {\n <button class=\"save-to-collection-btn\"\n (click)=\"onSaveToLibrary()\"\n title=\"Save to Collection\">\n <i class=\"far fa-bookmark\"></i>\n </button>\n }\n <button class=\"close-btn\" (click)=\"onClose()\" title=\"Close\">\n <i class=\"fas fa-times\"></i>\n </button>\n </div>\n </div>\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 <div class=\"error-state\">\n <i class=\"fas fa-exclamation-triangle\"></i>\n <span>{{ error }}</span>\n </div>\n }\n\n @if (!isLoading && !error && artifact) {\n <div class=\"artifact-content-wrapper\">\n <!-- Tab Navigation (Dynamic) -->\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 <!-- Tab Content (Dynamic) -->\n <div class=\"tab-content\">\n <!-- Display Tab - Special case for plugin rendering -->\n @if (activeTab === 'display') {\n <div class=\"display-content\">\n @if (hasPlugin && artifactVersion && artifactTypeName) {\n <!-- Use plugin viewer if available -->\n <mj-artifact-type-plugin-viewer\n [artifactVersion]=\"artifactVersion\"\n [artifactTypeName]=\"artifactTypeName\"\n [contentType]=\"contentType\"\n [readonly]=\"true\">\n </mj-artifact-type-plugin-viewer>\n } @else 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 <markdown [data]=\"displayMarkdown\"></markdown>\n </div>\n } @else if (displayHtml) {\n <div class=\"html-content\" [innerHTML]=\"displayHtml\"></div>\n }\n }\n </div>\n }\n\n <!-- Details Tab - Artifact metadata -->\n @if (activeTab === 'details') {\n <div class=\"details-content\">\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\n <!-- Links Tab - Conversations and Collections -->\n @if (activeTab === 'links') {\n <div class=\"links-container\">\n @if (linksToShow.length > 0) {\n <div class=\"links-section\">\n @for (link of linksToShow; track link.id) {\n <div class=\"link-item\">\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 <button\n class=\"link-action-btn\"\n [disabled]=\"!link.hasAccess\"\n [title]=\"link.hasAccess ? 'Open' : 'No access'\"\n (click)=\"onNavigateToLink(link)\">\n <i class=\"fas fa-arrow-right\"></i>\n </button>\n </div>\n </div>\n }\n </div>\n } @else {\n <div class=\"empty-state\">\n <i class=\"fas fa-link\"></i>\n <p>No links available</p>\n </div>\n }\n </div>\n }\n\n <!-- Dynamic Plugin Tabs and Base Tabs (JSON, etc.) -->\n @if (activeTab !== 'display' && activeTab !== 'details' && activeTab !== 'links') {\n @if (GetTabContent(activeTab); as tabData) {\n <div class=\"dynamic-tab-content\">\n @switch (tabData.type) {\n @case ('markdown') {\n <div class=\"markdown-viewer\" [innerHTML]=\"RenderMarkdown(tabData.content)\"></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 <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 }\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 </div>\n </div>\n }\n </div>\n</div>\n\n", styles: [".artifact-viewer-panel {\n width: 100%;\n height: 100%;\n background: white;\n border-left: 1px solid #E5E7EB;\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 #E5E7EB;\n background: white;\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: #6366F1;\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: #6B7280;\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: #F3F4F6;\n border-radius: 12px;\n font-size: 12px;\n color: #6B7280;\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: #E5E7EB;\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: white;\n border: 1px solid #E5E7EB;\n border-radius: 8px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);\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: #F9FAFB;\n}\n\n.version-option.selected {\n background: #EEF2FF;\n color: #4F46E5;\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: #6B7280;\n font-size: 12px;\n}\n\n.version-option i.fa-check {\n color: #10B981;\n margin-left: auto;\n}\n\n.save-to-collection-btn {\n background: none;\n border: none;\n cursor: pointer;\n color: #9CA3AF;\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: #F3F4F6;\n color: #6B7280;\n}\n\n.save-to-collection-btn i {\n font-size: 14px;\n}\n\n.close-btn {\n background: none;\n border: none;\n cursor: pointer;\n color: #6B7280;\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: #F3F4F6;\n color: #111827;\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.error-state {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 12px;\n padding: 40px 20px;\n color: #6B7280;\n}\n\n.error-state {\n color: #DC2626;\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: #F9FAFB;\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: #6B7280;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.meta-item span {\n font-size: 14px;\n color: #111827;\n}\n\n.artifact-description {\n padding: 12px;\n margin-bottom: 16px;\n background: #EFF6FF;\n border-left: 3px solid #3B82F6;\n border-radius: 4px;\n color: #1E40AF;\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 #E5E7EB;\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: #F9FAFB;\n border-bottom: 1px solid #E5E7EB;\n flex-shrink: 0;\n}\n\n.btn-icon {\n display: flex;\n align-items: center;\n gap: 6px;\n background: white;\n border: 1px solid #D1D5DB;\n border-radius: 4px;\n padding: 6px 12px;\n cursor: pointer;\n color: #374151;\n font-size: 14px;\n transition: all 0.2s;\n}\n\n.btn-icon:hover {\n background: #F3F4F6;\n border-color: #9CA3AF;\n}\n\n.btn-icon.btn-primary {\n background: #4F46E5;\n border-color: #4F46E5;\n color: white;\n}\n\n.btn-icon.btn-primary:hover {\n background: #4338CA;\n border-color: #4338CA;\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: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10000;\n}\n\n.modal-content {\n background: white;\n border-radius: 12px;\n box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2);\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 #E5E7EB;\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: #F59E0B;\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 #E5E7EB;\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: #374151;\n}\n\n.form-select,\n.form-input {\n width: 100%;\n padding: 10px 12px;\n border: 1px solid #D1D5DB;\n border-radius: 6px;\n font-size: 14px;\n color: #111827;\n background: white;\n transition: border-color 0.2s;\n}\n\n.form-select:focus,\n.form-input:focus {\n outline: none;\n border-color: #4F46E5;\n box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1);\n}\n\n.divider {\n display: flex;\n align-items: center;\n margin: 24px 0;\n color: #9CA3AF;\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: #E5E7EB;\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: #4F46E5;\n color: white;\n}\n\n.btn-primary:hover:not(:disabled) {\n background: #4338CA;\n}\n\n.btn-secondary {\n background: white;\n border: 1px solid #D1D5DB;\n color: #374151;\n}\n\n.btn-secondary:hover:not(:disabled) {\n background: #F3F4F6;\n}\n\n/* Tab Navigation */\n.tab-navigation {\n display: flex;\n gap: 0;\n border-bottom: 2px solid #E5E7EB;\n padding: 0 16px;\n background: white;\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: #6B7280;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 150ms ease;\n}\n\n.tab-btn:hover {\n color: #1e40af;\n background: #F9FAFB;\n}\n\n.tab-btn.active {\n color: #1e40af;\n border-bottom-color: #1e40af;\n}\n\n.tab-btn i {\n font-size: 14px;\n}\n\n/* Tab Content */\n.tab-content {\n flex: 1;\n overflow: auto;\n width: 100%;\n box-sizing: border-box;\n margin-bottom: 5px;\n min-width: 0;\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: #F9FAFB;\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: #111827;\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: white;\n border-radius: 6px;\n border: 1px solid #E5E7EB;\n}\n\n.attribute-item label {\n font-size: 11px;\n font-weight: 600;\n color: #6B7280;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.attribute-item span {\n font-size: 13px;\n color: #111827;\n word-break: break-word;\n}\n\n.attribute-empty-pill {\n display: inline-block;\n padding: 2px 8px;\n background: #F3F4F6;\n color: #9CA3AF;\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: #F9FAFB;\n border: 1px solid #E5E7EB;\n border-radius: 8px;\n transition: all 0.15s;\n}\n\n.link-item:hover {\n border-color: #1e40af;\n box-shadow: 0 2px 4px rgba(0,0,0,0.05);\n}\n\n.link-icon {\n width: 40px;\n height: 40px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: white;\n border-radius: 8px;\n flex-shrink: 0;\n}\n\n.link-icon i {\n font-size: 18px;\n color: #1e40af;\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: #111827;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.link-type {\n font-size: 12px;\n color: #6B7280;\n margin-top: 2px;\n}\n\n.link-actions {\n display: flex;\n gap: 8px;\n}\n\n.link-action-btn {\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: white;\n border: 1px solid #D1D5DB;\n border-radius: 6px;\n color: #1e40af;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.link-action-btn:hover:not(:disabled) {\n background: #EFF6FF;\n border-color: #1e40af;\n}\n\n.link-action-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n color: #9CA3AF;\n}\n\n.links-container .empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 48px 24px;\n color: #9CA3AF;\n text-align: center;\n}\n\n.links-container .empty-state i {\n font-size: 48px;\n margin-bottom: 16px;\n opacity: 0.3;\n}\n\n.links-container .empty-state p {\n margin: 0;\n font-size: 14px;\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.markdown-viewer {\n flex: 1;\n overflow: auto;\n padding: 20px;\n background: white;\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: #f3f4f6;\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: #f3f4f6;\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, .plaintext-viewer {\n flex: 1;\n overflow: auto;\n padding: 12px;\n background: #f9fafb;\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: white;\n}\n"] }]
1255
+ }], () => [{ type: i1.MJNotificationService }, { type: i2.DomSanitizer }], { artifactId: [{
969
1256
  type: Input
970
1257
  }], currentUser: [{
971
1258
  type: Input
@@ -977,11 +1264,19 @@ export class ArtifactViewerPanelComponent {
977
1264
  type: Input
978
1265
  }], refreshTrigger: [{
979
1266
  type: Input
1267
+ }], viewContext: [{
1268
+ type: Input
1269
+ }], contextCollectionId: [{
1270
+ type: Input
980
1271
  }], closed: [{
981
1272
  type: Output
1273
+ }], saveToCollectionRequested: [{
1274
+ type: Output
1275
+ }], navigateToLink: [{
1276
+ type: Output
982
1277
  }], pluginViewer: [{
983
1278
  type: ViewChild,
984
1279
  args: [ArtifactTypePluginViewerComponent]
985
1280
  }] }); })();
986
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ArtifactViewerPanelComponent, { className: "ArtifactViewerPanelComponent", filePath: "src/lib/components/artifact-viewer-panel.component.ts", lineNumber: 14 }); })();
1281
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ArtifactViewerPanelComponent, { className: "ArtifactViewerPanelComponent", filePath: "src/lib/components/artifact-viewer-panel.component.ts", lineNumber: 18 }); })();
987
1282
  //# sourceMappingURL=artifact-viewer-panel.component.js.map