@memberjunction/ng-artifacts 5.1.0 → 5.3.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 (33) hide show
  1. package/dist/lib/artifacts.module.d.ts +13 -8
  2. package/dist/lib/artifacts.module.d.ts.map +1 -1
  3. package/dist/lib/artifacts.module.js +27 -6
  4. package/dist/lib/artifacts.module.js.map +1 -1
  5. package/dist/lib/components/artifact-type-plugin-viewer.component.d.ts +4 -2
  6. package/dist/lib/components/artifact-type-plugin-viewer.component.d.ts.map +1 -1
  7. package/dist/lib/components/artifact-type-plugin-viewer.component.js +19 -1
  8. package/dist/lib/components/artifact-type-plugin-viewer.component.js.map +1 -1
  9. package/dist/lib/components/artifact-viewer-panel.component.d.ts +14 -2
  10. package/dist/lib/components/artifact-viewer-panel.component.d.ts.map +1 -1
  11. package/dist/lib/components/artifact-viewer-panel.component.js +39 -3
  12. package/dist/lib/components/artifact-viewer-panel.component.js.map +1 -1
  13. package/dist/lib/components/base-artifact-viewer.component.d.ts +34 -1
  14. package/dist/lib/components/base-artifact-viewer.component.d.ts.map +1 -1
  15. package/dist/lib/components/base-artifact-viewer.component.js +16 -1
  16. package/dist/lib/components/base-artifact-viewer.component.js.map +1 -1
  17. package/dist/lib/components/plugins/component-artifact-viewer.component.d.ts +6 -0
  18. package/dist/lib/components/plugins/component-artifact-viewer.component.d.ts.map +1 -1
  19. package/dist/lib/components/plugins/component-artifact-viewer.component.js +14 -3
  20. package/dist/lib/components/plugins/component-artifact-viewer.component.js.map +1 -1
  21. package/dist/lib/components/plugins/data-artifact-viewer.component.d.ts +207 -0
  22. package/dist/lib/components/plugins/data-artifact-viewer.component.d.ts.map +1 -0
  23. package/dist/lib/components/plugins/data-artifact-viewer.component.js +826 -0
  24. package/dist/lib/components/plugins/data-artifact-viewer.component.js.map +1 -0
  25. package/dist/lib/components/plugins/save-query-dialog.component.d.ts +57 -0
  26. package/dist/lib/components/plugins/save-query-dialog.component.d.ts.map +1 -0
  27. package/dist/lib/components/plugins/save-query-dialog.component.js +563 -0
  28. package/dist/lib/components/plugins/save-query-dialog.component.js.map +1 -0
  29. package/dist/public-api.d.ts +1 -0
  30. package/dist/public-api.d.ts.map +1 -1
  31. package/dist/public-api.js +1 -0
  32. package/dist/public-api.js.map +1 -1
  33. package/package.json +18 -12
@@ -0,0 +1,826 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { Component, Output, EventEmitter } from '@angular/core';
8
+ import { RegisterClass } from '@memberjunction/global';
9
+ import { Metadata, RunQuery, CompositeKey, KeyValuePair } from '@memberjunction/core';
10
+ import { QueryEngine, ArtifactMetadataEngine } from '@memberjunction/core-entities';
11
+ import { resolveTargetEntity } from '@memberjunction/ng-query-viewer';
12
+ import { BaseArtifactViewerPluginComponent } from '../base-artifact-viewer.component';
13
+ import * as i0 from "@angular/core";
14
+ import * as i1 from "@angular/common";
15
+ import * as i2 from "@memberjunction/ng-markdown";
16
+ import * as i3 from "@memberjunction/ng-query-viewer";
17
+ import * as i4 from "@memberjunction/ng-shared-generic";
18
+ import * as i5 from "./save-query-dialog.component";
19
+ function DataArtifactViewerComponent_Conditional_1_Conditional_0_Conditional_5_Template(rf, ctx) { if (rf & 1) {
20
+ i0.ɵɵelementStart(0, "span", 7);
21
+ i0.ɵɵtext(1, "Live");
22
+ i0.ɵɵelementEnd();
23
+ } }
24
+ function DataArtifactViewerComponent_Conditional_1_Conditional_0_Conditional_6_Template(rf, ctx) { if (rf & 1) {
25
+ i0.ɵɵelementStart(0, "span", 8);
26
+ i0.ɵɵtext(1);
27
+ i0.ɵɵelementEnd();
28
+ } if (rf & 2) {
29
+ const ctx_r0 = i0.ɵɵnextContext(3);
30
+ i0.ɵɵadvance();
31
+ i0.ɵɵtextInterpolate1("", ctx_r0.DisplayRowCount, " rows");
32
+ } }
33
+ function DataArtifactViewerComponent_Conditional_1_Conditional_0_Conditional_7_Template(rf, ctx) { if (rf & 1) {
34
+ i0.ɵɵelementStart(0, "span", 9);
35
+ i0.ɵɵtext(1);
36
+ i0.ɵɵelementEnd();
37
+ } if (rf & 2) {
38
+ const ctx_r0 = i0.ɵɵnextContext(3);
39
+ i0.ɵɵadvance();
40
+ i0.ɵɵtextInterpolate1("", ctx_r0.DisplayExecutionTime, "ms");
41
+ } }
42
+ function DataArtifactViewerComponent_Conditional_1_Conditional_0_Conditional_9_Template(rf, ctx) { if (rf & 1) {
43
+ const _r2 = i0.ɵɵgetCurrentView();
44
+ i0.ɵɵelementStart(0, "button", 17);
45
+ i0.ɵɵlistener("click", function DataArtifactViewerComponent_Conditional_1_Conditional_0_Conditional_9_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.OnRefresh()); });
46
+ i0.ɵɵelement(1, "i", 18);
47
+ i0.ɵɵtext(2, " Refresh ");
48
+ i0.ɵɵelementEnd();
49
+ } if (rf & 2) {
50
+ const ctx_r0 = i0.ɵɵnextContext(3);
51
+ i0.ɵɵproperty("disabled", ctx_r0.IsLoading);
52
+ i0.ɵɵadvance();
53
+ i0.ɵɵclassProp("fa-spin", ctx_r0.IsLoading);
54
+ } }
55
+ function DataArtifactViewerComponent_Conditional_1_Conditional_0_Case_10_Template(rf, ctx) { if (rf & 1) {
56
+ const _r3 = i0.ɵɵgetCurrentView();
57
+ i0.ɵɵelementStart(0, "button", 19);
58
+ i0.ɵɵlistener("click", function DataArtifactViewerComponent_Conditional_1_Conditional_0_Case_10_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.OnShowSaveDialog()); });
59
+ i0.ɵɵelement(1, "i", 20);
60
+ i0.ɵɵtext(2, " Save Query ");
61
+ i0.ɵɵelementEnd();
62
+ } }
63
+ function DataArtifactViewerComponent_Conditional_1_Conditional_0_Case_11_Template(rf, ctx) { if (rf & 1) {
64
+ const _r4 = i0.ɵɵgetCurrentView();
65
+ i0.ɵɵelementStart(0, "span", 21);
66
+ i0.ɵɵelement(1, "i", 22);
67
+ i0.ɵɵtext(2);
68
+ i0.ɵɵelementEnd();
69
+ i0.ɵɵelementStart(3, "button", 23);
70
+ i0.ɵɵlistener("click", function DataArtifactViewerComponent_Conditional_1_Conditional_0_Case_11_Template_button_click_3_listener() { i0.ɵɵrestoreView(_r4); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.OnOpenSavedQuery()); });
71
+ i0.ɵɵelement(4, "i", 24);
72
+ i0.ɵɵtext(5, " Open Query ");
73
+ i0.ɵɵelementEnd();
74
+ } if (rf & 2) {
75
+ const ctx_r0 = i0.ɵɵnextContext(3);
76
+ i0.ɵɵadvance(2);
77
+ i0.ɵɵtextInterpolate1(" Saved at v", ctx_r0.SavedAtVersion, " ");
78
+ } }
79
+ function DataArtifactViewerComponent_Conditional_1_Conditional_0_Case_12_Conditional_8_Template(rf, ctx) { if (rf & 1) {
80
+ const _r6 = i0.ɵɵgetCurrentView();
81
+ i0.ɵɵelementStart(0, "div", 31);
82
+ i0.ɵɵlistener("click", function DataArtifactViewerComponent_Conditional_1_Conditional_0_Case_12_Conditional_8_Template_div_click_0_listener($event) { i0.ɵɵrestoreView(_r6); return i0.ɵɵresetView($event.stopPropagation()); });
83
+ i0.ɵɵelementStart(1, "div", 32);
84
+ i0.ɵɵlistener("click", function DataArtifactViewerComponent_Conditional_1_Conditional_0_Case_12_Conditional_8_Template_div_click_1_listener() { i0.ɵɵrestoreView(_r6); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.OnUpdateExistingQuery()); });
85
+ i0.ɵɵelement(2, "i", 33);
86
+ i0.ɵɵelementStart(3, "div")(4, "div", 34);
87
+ i0.ɵɵtext(5);
88
+ i0.ɵɵelementEnd();
89
+ i0.ɵɵelementStart(6, "div", 35);
90
+ i0.ɵɵtext(7, "Replace saved query SQL with this version's SQL");
91
+ i0.ɵɵelementEnd()()();
92
+ i0.ɵɵelementStart(8, "div", 32);
93
+ i0.ɵɵlistener("click", function DataArtifactViewerComponent_Conditional_1_Conditional_0_Case_12_Conditional_8_Template_div_click_8_listener() { i0.ɵɵrestoreView(_r6); const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.OnSaveAsNewQuery()); });
94
+ i0.ɵɵelement(9, "i", 36);
95
+ i0.ɵɵelementStart(10, "div")(11, "div", 34);
96
+ i0.ɵɵtext(12, "Save as New Query");
97
+ i0.ɵɵelementEnd();
98
+ i0.ɵɵelementStart(13, "div", 35);
99
+ i0.ɵɵtext(14, "Create a new query, keep the original unchanged");
100
+ i0.ɵɵelementEnd()()();
101
+ i0.ɵɵelementStart(15, "div", 32);
102
+ i0.ɵɵlistener("click", function DataArtifactViewerComponent_Conditional_1_Conditional_0_Case_12_Conditional_8_Template_div_click_15_listener() { i0.ɵɵrestoreView(_r6); const ctx_r0 = i0.ɵɵnextContext(4); ctx_r0.OnOpenSavedQuery(); return i0.ɵɵresetView(ctx_r0.OnCloseDropdown()); });
103
+ i0.ɵɵelement(16, "i", 37);
104
+ i0.ɵɵelementStart(17, "div")(18, "div", 34);
105
+ i0.ɵɵtext(19, "Open Saved Query");
106
+ i0.ɵɵelementEnd();
107
+ i0.ɵɵelementStart(20, "div", 35);
108
+ i0.ɵɵtext(21);
109
+ i0.ɵɵelementEnd()()()();
110
+ } if (rf & 2) {
111
+ const ctx_r0 = i0.ɵɵnextContext(4);
112
+ i0.ɵɵadvance(5);
113
+ i0.ɵɵtextInterpolate1("Update \"", ctx_r0.SavedQueryDisplayName, "\"");
114
+ i0.ɵɵadvance(16);
115
+ i0.ɵɵtextInterpolate2("View \"", ctx_r0.SavedQueryDisplayName, "\" (saved at v", ctx_r0.SavedAtVersion, ")");
116
+ } }
117
+ function DataArtifactViewerComponent_Conditional_1_Conditional_0_Case_12_Template(rf, ctx) { if (rf & 1) {
118
+ const _r5 = i0.ɵɵgetCurrentView();
119
+ i0.ɵɵelementStart(0, "span", 25);
120
+ i0.ɵɵelement(1, "i", 26);
121
+ i0.ɵɵtext(2);
122
+ i0.ɵɵelementEnd();
123
+ i0.ɵɵelementStart(3, "div", 27)(4, "button", 28);
124
+ i0.ɵɵlistener("click", function DataArtifactViewerComponent_Conditional_1_Conditional_0_Case_12_Template_button_click_4_listener() { i0.ɵɵrestoreView(_r5); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.OnToggleUpdateDropdown()); });
125
+ i0.ɵɵelement(5, "i", 20);
126
+ i0.ɵɵtext(6, " Update Query ");
127
+ i0.ɵɵelement(7, "i", 29);
128
+ i0.ɵɵelementEnd();
129
+ i0.ɵɵconditionalCreate(8, DataArtifactViewerComponent_Conditional_1_Conditional_0_Case_12_Conditional_8_Template, 22, 3, "div", 30);
130
+ i0.ɵɵelementEnd();
131
+ } if (rf & 2) {
132
+ const ctx_r0 = i0.ɵɵnextContext(3);
133
+ i0.ɵɵadvance(2);
134
+ i0.ɵɵtextInterpolate1(" Saved at v", ctx_r0.SavedAtVersion, " ");
135
+ i0.ɵɵadvance(6);
136
+ i0.ɵɵconditional(ctx_r0.ShowUpdateDropdown ? 8 : -1);
137
+ } }
138
+ function DataArtifactViewerComponent_Conditional_1_Conditional_0_Case_13_Template(rf, ctx) { if (rf & 1) {
139
+ const _r7 = i0.ɵɵgetCurrentView();
140
+ i0.ɵɵelementStart(0, "span", 38);
141
+ i0.ɵɵelement(1, "i", 39);
142
+ i0.ɵɵtext(2);
143
+ i0.ɵɵelementEnd();
144
+ i0.ɵɵelementStart(3, "button", 40);
145
+ i0.ɵɵlistener("click", function DataArtifactViewerComponent_Conditional_1_Conditional_0_Case_13_Template_button_click_3_listener() { i0.ɵɵrestoreView(_r7); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.OnOpenSavedQuery()); });
146
+ i0.ɵɵelement(4, "i", 24);
147
+ i0.ɵɵtext(5, " Open Query ");
148
+ i0.ɵɵelementEnd();
149
+ } if (rf & 2) {
150
+ const ctx_r0 = i0.ɵɵnextContext(3);
151
+ i0.ɵɵadvance(2);
152
+ i0.ɵɵtextInterpolate1(" Query updated at v", ctx_r0.SavedAtVersion, " ");
153
+ } }
154
+ function DataArtifactViewerComponent_Conditional_1_Conditional_0_Case_14_Template(rf, ctx) { if (rf & 1) {
155
+ const _r8 = i0.ɵɵgetCurrentView();
156
+ i0.ɵɵelementStart(0, "span", 38);
157
+ i0.ɵɵelement(1, "i", 39);
158
+ i0.ɵɵtext(2);
159
+ i0.ɵɵelementEnd();
160
+ i0.ɵɵelementStart(3, "button", 40);
161
+ i0.ɵɵlistener("click", function DataArtifactViewerComponent_Conditional_1_Conditional_0_Case_14_Template_button_click_3_listener() { i0.ɵɵrestoreView(_r8); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.OnOpenSavedQuery()); });
162
+ i0.ɵɵelement(4, "i", 24);
163
+ i0.ɵɵtext(5, " Open Query ");
164
+ i0.ɵɵelementEnd();
165
+ } if (rf & 2) {
166
+ const ctx_r0 = i0.ɵɵnextContext(3);
167
+ i0.ɵɵadvance(2);
168
+ i0.ɵɵtextInterpolate1(" Saved at v", ctx_r0.SavedAtVersion, " ");
169
+ } }
170
+ function DataArtifactViewerComponent_Conditional_1_Conditional_0_Case_15_Template(rf, ctx) { }
171
+ function DataArtifactViewerComponent_Conditional_1_Conditional_0_Conditional_17_Template(rf, ctx) { if (rf & 1) {
172
+ i0.ɵɵelementStart(0, "div", 14);
173
+ i0.ɵɵelement(1, "mj-loading", 41);
174
+ i0.ɵɵelementEnd();
175
+ } if (rf & 2) {
176
+ const ctx_r0 = i0.ɵɵnextContext(3);
177
+ i0.ɵɵadvance();
178
+ i0.ɵɵproperty("text", ctx_r0.SavingMessage);
179
+ } }
180
+ function DataArtifactViewerComponent_Conditional_1_Conditional_0_Conditional_18_Template(rf, ctx) { if (rf & 1) {
181
+ i0.ɵɵelement(0, "mj-loading", 15);
182
+ } }
183
+ function DataArtifactViewerComponent_Conditional_1_Conditional_0_Conditional_19_Template(rf, ctx) { if (rf & 1) {
184
+ const _r9 = i0.ɵɵgetCurrentView();
185
+ i0.ɵɵelementStart(0, "div", 42);
186
+ i0.ɵɵelement(1, "i", 43);
187
+ i0.ɵɵelementStart(2, "span");
188
+ i0.ɵɵtext(3);
189
+ i0.ɵɵelementEnd();
190
+ i0.ɵɵelementStart(4, "span", 44);
191
+ i0.ɵɵtext(5, "(Showing cached data)");
192
+ i0.ɵɵelementEnd()();
193
+ i0.ɵɵelementStart(6, "mj-query-data-grid", 45);
194
+ i0.ɵɵlistener("EntityLinkClick", function DataArtifactViewerComponent_Conditional_1_Conditional_0_Conditional_19_Template_mj_query_data_grid_EntityLinkClick_6_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.OnEntityLinkClick($event)); });
195
+ i0.ɵɵelementEnd();
196
+ } if (rf & 2) {
197
+ const ctx_r0 = i0.ɵɵnextContext(3);
198
+ i0.ɵɵadvance(3);
199
+ i0.ɵɵtextInterpolate(ctx_r0.ErrorMessage);
200
+ i0.ɵɵadvance(3);
201
+ i0.ɵɵproperty("ColumnConfigs", ctx_r0.GridColumnConfigs)("Data", ctx_r0.GridData)("ShowToolbar", false)("ShowRefresh", false)("PersistState", false)("SelectionMode", "none");
202
+ } }
203
+ function DataArtifactViewerComponent_Conditional_1_Conditional_0_Conditional_20_Template(rf, ctx) { if (rf & 1) {
204
+ i0.ɵɵelementStart(0, "div", 1);
205
+ i0.ɵɵelement(1, "i", 43);
206
+ i0.ɵɵelementStart(2, "p");
207
+ i0.ɵɵtext(3);
208
+ i0.ɵɵelementEnd()();
209
+ } if (rf & 2) {
210
+ const ctx_r0 = i0.ɵɵnextContext(3);
211
+ i0.ɵɵadvance(3);
212
+ i0.ɵɵtextInterpolate(ctx_r0.ErrorMessage);
213
+ } }
214
+ function DataArtifactViewerComponent_Conditional_1_Conditional_0_Conditional_21_Template(rf, ctx) { if (rf & 1) {
215
+ const _r10 = i0.ɵɵgetCurrentView();
216
+ i0.ɵɵelementStart(0, "mj-query-data-grid", 45);
217
+ i0.ɵɵlistener("EntityLinkClick", function DataArtifactViewerComponent_Conditional_1_Conditional_0_Conditional_21_Template_mj_query_data_grid_EntityLinkClick_0_listener($event) { i0.ɵɵrestoreView(_r10); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.OnEntityLinkClick($event)); });
218
+ i0.ɵɵelementEnd();
219
+ } if (rf & 2) {
220
+ const ctx_r0 = i0.ɵɵnextContext(3);
221
+ i0.ɵɵproperty("ColumnConfigs", ctx_r0.GridColumnConfigs)("Data", ctx_r0.GridData)("ShowToolbar", false)("ShowRefresh", false)("PersistState", false)("SelectionMode", "none");
222
+ } }
223
+ function DataArtifactViewerComponent_Conditional_1_Conditional_0_Template(rf, ctx) { if (rf & 1) {
224
+ i0.ɵɵelementStart(0, "div", 4)(1, "div", 5);
225
+ i0.ɵɵelement(2, "i", 6);
226
+ i0.ɵɵelementStart(3, "span");
227
+ i0.ɵɵtext(4);
228
+ i0.ɵɵelementEnd();
229
+ i0.ɵɵconditionalCreate(5, DataArtifactViewerComponent_Conditional_1_Conditional_0_Conditional_5_Template, 2, 0, "span", 7);
230
+ i0.ɵɵconditionalCreate(6, DataArtifactViewerComponent_Conditional_1_Conditional_0_Conditional_6_Template, 2, 1, "span", 8);
231
+ i0.ɵɵconditionalCreate(7, DataArtifactViewerComponent_Conditional_1_Conditional_0_Conditional_7_Template, 2, 1, "span", 9);
232
+ i0.ɵɵelementEnd();
233
+ i0.ɵɵelementStart(8, "div", 10);
234
+ i0.ɵɵconditionalCreate(9, DataArtifactViewerComponent_Conditional_1_Conditional_0_Conditional_9_Template, 3, 3, "button", 11);
235
+ i0.ɵɵconditionalCreate(10, DataArtifactViewerComponent_Conditional_1_Conditional_0_Case_10_Template, 3, 0, "button", 12)(11, DataArtifactViewerComponent_Conditional_1_Conditional_0_Case_11_Template, 6, 1)(12, DataArtifactViewerComponent_Conditional_1_Conditional_0_Case_12_Template, 9, 2)(13, DataArtifactViewerComponent_Conditional_1_Conditional_0_Case_13_Template, 6, 1)(14, DataArtifactViewerComponent_Conditional_1_Conditional_0_Case_14_Template, 6, 1)(15, DataArtifactViewerComponent_Conditional_1_Conditional_0_Case_15_Template, 0, 0);
236
+ i0.ɵɵelementEnd()();
237
+ i0.ɵɵelementStart(16, "div", 13);
238
+ i0.ɵɵconditionalCreate(17, DataArtifactViewerComponent_Conditional_1_Conditional_0_Conditional_17_Template, 2, 1, "div", 14);
239
+ i0.ɵɵconditionalCreate(18, DataArtifactViewerComponent_Conditional_1_Conditional_0_Conditional_18_Template, 1, 0, "mj-loading", 15)(19, DataArtifactViewerComponent_Conditional_1_Conditional_0_Conditional_19_Template, 7, 7)(20, DataArtifactViewerComponent_Conditional_1_Conditional_0_Conditional_20_Template, 4, 1, "div", 1)(21, DataArtifactViewerComponent_Conditional_1_Conditional_0_Conditional_21_Template, 1, 6, "mj-query-data-grid", 16);
240
+ i0.ɵɵelementEnd();
241
+ } if (rf & 2) {
242
+ let tmp_7_0;
243
+ const ctx_r0 = i0.ɵɵnextContext(2);
244
+ i0.ɵɵadvance(4);
245
+ i0.ɵɵtextInterpolate(ctx_r0.spec.title || "Data Results");
246
+ i0.ɵɵadvance();
247
+ i0.ɵɵconditional(ctx_r0.IsLive ? 5 : -1);
248
+ i0.ɵɵadvance();
249
+ i0.ɵɵconditional(ctx_r0.DisplayRowCount != null ? 6 : -1);
250
+ i0.ɵɵadvance();
251
+ i0.ɵɵconditional(ctx_r0.DisplayExecutionTime != null ? 7 : -1);
252
+ i0.ɵɵadvance(2);
253
+ i0.ɵɵconditional(ctx_r0.IsLive ? 9 : -1);
254
+ i0.ɵɵadvance();
255
+ i0.ɵɵconditional((tmp_7_0 = ctx_r0.QuerySyncState) === "no-query-latest" ? 10 : tmp_7_0 === "synced" ? 11 : tmp_7_0 === "outdated-latest" ? 12 : tmp_7_0 === "query-ahead" ? 13 : tmp_7_0 === "query-behind" ? 14 : tmp_7_0 === "no-query-older" ? 15 : -1);
256
+ i0.ɵɵadvance(7);
257
+ i0.ɵɵconditional(ctx_r0.IsSaving ? 17 : -1);
258
+ i0.ɵɵadvance();
259
+ i0.ɵɵconditional(ctx_r0.IsLoading ? 18 : ctx_r0.HasError && ctx_r0.HasData ? 19 : ctx_r0.HasError ? 20 : 21);
260
+ } }
261
+ function DataArtifactViewerComponent_Conditional_1_Conditional_1_Template(rf, ctx) { if (rf & 1) {
262
+ i0.ɵɵelementStart(0, "div", 4)(1, "div", 5);
263
+ i0.ɵɵelement(2, "i", 46);
264
+ i0.ɵɵelementStart(3, "span");
265
+ i0.ɵɵtext(4);
266
+ i0.ɵɵelementEnd()()();
267
+ i0.ɵɵelementStart(5, "div", 47);
268
+ i0.ɵɵelement(6, "mj-markdown", 48);
269
+ i0.ɵɵelementEnd();
270
+ } if (rf & 2) {
271
+ const ctx_r0 = i0.ɵɵnextContext(2);
272
+ i0.ɵɵadvance(4);
273
+ i0.ɵɵtextInterpolate(ctx_r0.spec.title || "Query Plan");
274
+ i0.ɵɵadvance(2);
275
+ i0.ɵɵproperty("data", ctx_r0.spec.plan)("enableMermaid", true)("enableHighlight", true)("enableCollapsibleHeadings", false)("enableSmartypants", true);
276
+ } }
277
+ function DataArtifactViewerComponent_Conditional_1_Conditional_2_Template(rf, ctx) { if (rf & 1) {
278
+ i0.ɵɵelementStart(0, "div", 2);
279
+ i0.ɵɵelement(1, "i", 49);
280
+ i0.ɵɵelementStart(2, "p");
281
+ i0.ɵɵtext(3, "No data to display");
282
+ i0.ɵɵelementEnd()();
283
+ } }
284
+ function DataArtifactViewerComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
285
+ i0.ɵɵconditionalCreate(0, DataArtifactViewerComponent_Conditional_1_Conditional_0_Template, 22, 8)(1, DataArtifactViewerComponent_Conditional_1_Conditional_1_Template, 7, 6)(2, DataArtifactViewerComponent_Conditional_1_Conditional_2_Template, 4, 0, "div", 2);
286
+ } if (rf & 2) {
287
+ const ctx_r0 = i0.ɵɵnextContext();
288
+ i0.ɵɵconditional(ctx_r0.HasData || ctx_r0.IsLoading ? 0 : ctx_r0.spec.plan ? 1 : 2);
289
+ } }
290
+ function DataArtifactViewerComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) {
291
+ i0.ɵɵelementStart(0, "div", 1);
292
+ i0.ɵɵelement(1, "i", 43);
293
+ i0.ɵɵelementStart(2, "p");
294
+ i0.ɵɵtext(3);
295
+ i0.ɵɵelementEnd()();
296
+ } if (rf & 2) {
297
+ const ctx_r0 = i0.ɵɵnextContext();
298
+ i0.ɵɵadvance(3);
299
+ i0.ɵɵtextInterpolate(ctx_r0.ErrorMessage);
300
+ } }
301
+ function DataArtifactViewerComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) {
302
+ i0.ɵɵelementStart(0, "div", 2);
303
+ i0.ɵɵelement(1, "i", 49);
304
+ i0.ɵɵelementStart(2, "p");
305
+ i0.ɵɵtext(3, "No data to display");
306
+ i0.ɵɵelementEnd()();
307
+ } }
308
+ function DataArtifactViewerComponent_Conditional_4_Template(rf, ctx) { if (rf & 1) {
309
+ const _r11 = i0.ɵɵgetCurrentView();
310
+ i0.ɵɵelementStart(0, "mj-save-query-panel", 50);
311
+ i0.ɵɵlistener("Saved", function DataArtifactViewerComponent_Conditional_4_Template_mj_save_query_panel_Saved_0_listener($event) { i0.ɵɵrestoreView(_r11); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.OnQuerySaved($event)); })("Cancelled", function DataArtifactViewerComponent_Conditional_4_Template_mj_save_query_panel_Cancelled_0_listener() { i0.ɵɵrestoreView(_r11); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.ShowSaveDialog = false); });
312
+ i0.ɵɵelementEnd();
313
+ } if (rf & 2) {
314
+ const ctx_r0 = i0.ɵɵnextContext();
315
+ i0.ɵɵproperty("QueryName", (ctx_r0.spec == null ? null : ctx_r0.spec.title) || "Untitled Query")("QueryDescription", "")("SQL", (ctx_r0.spec == null ? null : ctx_r0.spec.metadata == null ? null : ctx_r0.spec.metadata.sql) || "");
316
+ } }
317
+ /**
318
+ * Viewer component for Data artifacts.
319
+ *
320
+ * Displays tabular data using AG Grid via mj-query-data-grid. Supports two modes:
321
+ * 1. **Live data**: When metadata.sql is present, executes the query dynamically via RunQuery({ SQL })
322
+ * to fetch fresh data on each view. Falls back to inline rows on error.
323
+ * 2. **Inline data**: Rows embedded directly in the artifact JSON (backward compat with older artifacts)
324
+ *
325
+ * The Query Builder agent emits artifacts with metadata.sql for live execution.
326
+ */
327
+ let DataArtifactViewerComponent = class DataArtifactViewerComponent extends BaseArtifactViewerPluginComponent {
328
+ cdr;
329
+ openEntityRecord = new EventEmitter();
330
+ navigationRequest = new EventEmitter();
331
+ tabsChanged = new EventEmitter();
332
+ spec = null;
333
+ GridData = [];
334
+ GridColumnConfigs = null;
335
+ IsLoading = false;
336
+ IsLive = false;
337
+ HasError = false;
338
+ ErrorMessage = '';
339
+ ShowSaveDialog = false;
340
+ ShowUpdateDropdown = false;
341
+ IsSaving = false;
342
+ SavingMessage = '';
343
+ /** Query sync state — drives the toolbar UI for saved query actions */
344
+ QuerySyncState = 'no-query-latest';
345
+ /** Latest version number for this artifact (from cache) */
346
+ LatestVersionNumber = 0;
347
+ /** Metadata from live execution (overrides spec.metadata when live) */
348
+ liveRowCount = null;
349
+ liveExecutionTime = null;
350
+ /** SQL from the saved query record (for comparison) */
351
+ savedQuerySql = null;
352
+ constructor(cdr) {
353
+ super();
354
+ this.cdr = cdr;
355
+ }
356
+ get hasDisplayContent() {
357
+ return this.spec != null && (this.HasData || this.IsLoading);
358
+ }
359
+ get parentShouldShowRawContent() {
360
+ return true;
361
+ }
362
+ get HasData() {
363
+ return this.GridData.length > 0;
364
+ }
365
+ get HasInlineData() {
366
+ return !!(this.spec?.rows && this.spec.rows.length > 0);
367
+ }
368
+ get DisplayRowCount() {
369
+ return this.liveRowCount ?? this.spec?.metadata?.rowCount ?? null;
370
+ }
371
+ get DisplayExecutionTime() {
372
+ return this.liveExecutionTime ?? this.spec?.metadata?.executionTimeMs ?? null;
373
+ }
374
+ /** Current artifact version number */
375
+ get CurrentVersionNumber() {
376
+ return this.artifactVersion?.VersionNumber || 1;
377
+ }
378
+ /** Whether this is the latest version of the artifact */
379
+ get IsLatestVersion() {
380
+ return this.CurrentVersionNumber === this.LatestVersionNumber;
381
+ }
382
+ /**
383
+ * The effective version number at which the query was last saved/updated.
384
+ * When viewing an older version, this looks ahead through newer versions
385
+ * to find the most recent savedAtVersionNumber for the same query,
386
+ * giving the user accurate context (e.g., "Query updated at v3" instead
387
+ * of the stale "Saved at v1" from this version's snapshot).
388
+ */
389
+ EffectiveSavedAtVersion = null;
390
+ /** Alias used by the template */
391
+ get SavedAtVersion() {
392
+ return this.EffectiveSavedAtVersion;
393
+ }
394
+ /** Display name for the saved query */
395
+ get SavedQueryDisplayName() {
396
+ return this.spec?.savedQueryName || 'Saved Query';
397
+ }
398
+ async ngOnInit() {
399
+ try {
400
+ this.spec = this.parseJsonContent();
401
+ if (!this.spec) {
402
+ this.HasError = true;
403
+ this.ErrorMessage = 'Failed to parse data artifact content';
404
+ return;
405
+ }
406
+ // Build enriched column configs from agent metadata (if available)
407
+ this.GridColumnConfigs = this.BuildColumnConfigs();
408
+ // Set loading early (synchronously) so hasDisplayContent is true immediately.
409
+ // This ensures the Display tab is available when onPluginLoaded fires,
410
+ // showing a loading indicator instead of briefly flashing the Plan tab.
411
+ if (this.spec.metadata?.sql || this.HasInlineData) {
412
+ this.IsLoading = true;
413
+ }
414
+ // Load cached metadata and resolve query sync state
415
+ await this.InitQuerySyncState();
416
+ // If SQL is available, execute it live
417
+ if (this.spec.metadata?.sql) {
418
+ await this.LoadLiveData();
419
+ }
420
+ else if (this.HasInlineData) {
421
+ // Fall back to embedded rows
422
+ this.GridData = this.spec.rows;
423
+ this.IsLoading = false;
424
+ }
425
+ // Signal parent that tabs/display content may have changed after async load
426
+ this.tabsChanged.emit();
427
+ }
428
+ catch (error) {
429
+ this.HasError = true;
430
+ this.ErrorMessage = error instanceof Error ? error.message : 'Failed to load data';
431
+ }
432
+ }
433
+ /**
434
+ * Re-execute the live SQL query
435
+ */
436
+ async OnRefresh() {
437
+ if (this.spec?.metadata?.sql) {
438
+ await this.LoadLiveData();
439
+ }
440
+ }
441
+ /**
442
+ * Handle entity link click from the grid and bubble up as openEntityRecord.
443
+ * Converts the grid's recordId string into a CompositeKey for the artifact viewer pipeline.
444
+ */
445
+ OnEntityLinkClick(event) {
446
+ const compositeKey = new CompositeKey([
447
+ new KeyValuePair('ID', event.recordId)
448
+ ]);
449
+ this.openEntityRecord.emit({
450
+ entityName: event.entityName,
451
+ compositeKey
452
+ });
453
+ }
454
+ /**
455
+ * Execute the SQL query via RunQuery and populate the grid.
456
+ * Falls back to inline data on error.
457
+ */
458
+ async LoadLiveData() {
459
+ this.IsLoading = true;
460
+ this.HasError = false;
461
+ this.cdr.detectChanges();
462
+ try {
463
+ const rq = new RunQuery();
464
+ const result = await rq.RunQuery({ SQL: this.spec.metadata.sql });
465
+ if (result.Success) {
466
+ this.GridData = result.Results;
467
+ this.liveRowCount = result.RowCount;
468
+ this.liveExecutionTime = result.ExecutionTime;
469
+ this.IsLive = true;
470
+ }
471
+ else {
472
+ this.HandleQueryError(result.ErrorMessage || 'Query execution failed');
473
+ }
474
+ }
475
+ catch (error) {
476
+ this.HandleQueryError(error instanceof Error ? error.message : 'Query execution failed');
477
+ }
478
+ finally {
479
+ this.IsLoading = false;
480
+ this.cdr.detectChanges();
481
+ }
482
+ }
483
+ /**
484
+ * Build QueryGridColumnConfig[] from enriched artifact column metadata.
485
+ * Returns null if columns have no entity metadata (grid falls back to auto-inference).
486
+ */
487
+ BuildColumnConfigs() {
488
+ if (!this.spec?.columns?.length)
489
+ return null;
490
+ // Only build if at least one column has entity metadata or type info
491
+ const hasMetadata = this.spec.columns.some(c => c.sourceEntity || c.sqlBaseType);
492
+ if (!hasMetadata)
493
+ return null;
494
+ const md = new Metadata();
495
+ return this.spec.columns.map((col, index) => {
496
+ const target = resolveTargetEntity(col.sourceEntity, col.sourceFieldName, md);
497
+ const isEntityLink = !!(target.targetEntityName && (target.isPrimaryKey || target.isForeignKey));
498
+ const baseType = (col.sqlBaseType || 'nvarchar').toLowerCase();
499
+ let align = 'left';
500
+ if (['int', 'bigint', 'decimal', 'numeric', 'float', 'money', 'smallmoney', 'real'].includes(baseType)) {
501
+ align = 'right';
502
+ }
503
+ else if (baseType === 'bit') {
504
+ align = 'center';
505
+ }
506
+ return {
507
+ field: col.field,
508
+ title: col.headerName || col.field,
509
+ visible: true,
510
+ sortable: true,
511
+ resizable: true,
512
+ reorderable: true,
513
+ sqlBaseType: col.sqlBaseType || 'nvarchar',
514
+ sqlFullType: col.sqlBaseType || 'nvarchar',
515
+ align,
516
+ order: index,
517
+ sourceEntityName: col.sourceEntity,
518
+ sourceFieldName: col.sourceFieldName,
519
+ isEntityLink,
520
+ targetEntityName: target.targetEntityName,
521
+ targetEntityId: target.targetEntityId,
522
+ targetEntityIcon: target.targetEntityIcon,
523
+ isPrimaryKey: target.isPrimaryKey,
524
+ isForeignKey: target.isForeignKey,
525
+ pinned: null,
526
+ };
527
+ });
528
+ }
529
+ /**
530
+ * Handle a query error by setting error state and falling back to inline data
531
+ */
532
+ HandleQueryError(message) {
533
+ this.HasError = true;
534
+ this.ErrorMessage = message;
535
+ if (this.HasInlineData) {
536
+ this.GridData = this.spec.rows;
537
+ }
538
+ }
539
+ // ─── Query Sync State ────────────────────────────────────────────
540
+ /**
541
+ * Initialize query sync state by loading cached metadata.
542
+ * Resolves the latest version number and compares saved query SQL.
543
+ */
544
+ async InitQuerySyncState() {
545
+ // Ensure artifact cache is loaded (not registered for startup)
546
+ await ArtifactMetadataEngine.Instance.Config(false);
547
+ this.LatestVersionNumber = this.resolveLatestVersionNumber();
548
+ // If cache is stale (doesn't know about the version we're viewing),
549
+ // force-refresh and re-resolve. This happens when new versions are
550
+ // created during a conversation after the cache was first loaded.
551
+ if (this.LatestVersionNumber < this.CurrentVersionNumber) {
552
+ await ArtifactMetadataEngine.Instance.Config(true);
553
+ this.LatestVersionNumber = this.resolveLatestVersionNumber();
554
+ }
555
+ this.EffectiveSavedAtVersion = this.resolveEffectiveSavedAtVersion();
556
+ await this.resolveSavedQuerySql();
557
+ this.QuerySyncState = this.computeQuerySyncState();
558
+ }
559
+ /**
560
+ * Determine the latest version number for this artifact from cache.
561
+ * Falls back to current version if cache miss.
562
+ */
563
+ resolveLatestVersionNumber() {
564
+ if (!this.artifactVersion?.ArtifactID) {
565
+ return this.CurrentVersionNumber;
566
+ }
567
+ const versions = ArtifactMetadataEngine.Instance.GetVersionsForArtifact(this.artifactVersion.ArtifactID);
568
+ if (versions.length > 0) {
569
+ // GetVersionsForArtifact returns DESC sorted
570
+ return versions[0].VersionNumber || 1;
571
+ }
572
+ // Cache miss — current version is our best guess
573
+ return this.CurrentVersionNumber;
574
+ }
575
+ /**
576
+ * Scan all versions of this artifact to find the most recent savedAtVersionNumber
577
+ * for the same savedQueryId. When viewing an older version, this tells the user
578
+ * where the query was *actually* last updated, not just what this version's
579
+ * snapshot recorded at the time.
580
+ */
581
+ resolveEffectiveSavedAtVersion() {
582
+ const queryId = this.spec?.savedQueryId;
583
+ if (!queryId)
584
+ return null;
585
+ // Start with this version's own value
586
+ let effective = this.spec?.savedAtVersionNumber ?? null;
587
+ if (!this.artifactVersion?.ArtifactID)
588
+ return effective;
589
+ // GetVersionsForArtifact returns DESC sorted — scan all versions
590
+ const versions = ArtifactMetadataEngine.Instance.GetVersionsForArtifact(this.artifactVersion.ArtifactID);
591
+ for (const v of versions) {
592
+ try {
593
+ if (!v.Content)
594
+ continue;
595
+ const content = typeof v.Content === 'string' ? JSON.parse(v.Content) : v.Content;
596
+ if (content.savedQueryId === queryId && content.savedAtVersionNumber != null) {
597
+ const vSavedAt = content.savedAtVersionNumber;
598
+ if (effective == null || vSavedAt > effective) {
599
+ effective = vSavedAt;
600
+ }
601
+ }
602
+ }
603
+ catch {
604
+ // Skip versions with unparseable content
605
+ }
606
+ }
607
+ return effective;
608
+ }
609
+ /**
610
+ * Look up the saved query's SQL from QueryEngine cache for comparison.
611
+ * Only fetches if savedQueryId is present.
612
+ */
613
+ async resolveSavedQuerySql() {
614
+ if (!this.spec?.savedQueryId) {
615
+ this.savedQuerySql = null;
616
+ return;
617
+ }
618
+ // QueryEngine is registered for startup, should already be loaded
619
+ let query = QueryEngine.Instance.FindQueryByID(this.spec.savedQueryId);
620
+ if (!query) {
621
+ // Cache miss — force refresh and retry
622
+ await QueryEngine.Instance.Config(true);
623
+ query = QueryEngine.Instance.FindQueryByID(this.spec.savedQueryId);
624
+ }
625
+ this.savedQuerySql = query?.SQL ?? null;
626
+ }
627
+ /**
628
+ * Compute the query sync state from current spec, version, and saved query SQL.
629
+ * Implements the decision tree from the UX design.
630
+ */
631
+ computeQuerySyncState() {
632
+ const hasSavedQuery = !!this.spec?.savedQueryId;
633
+ const isLatest = this.IsLatestVersion;
634
+ if (!hasSavedQuery) {
635
+ return isLatest ? 'no-query-latest' : 'no-query-older';
636
+ }
637
+ // Compare SQL (normalize whitespace for reliable comparison)
638
+ const specSql = this.normalizeSql(this.spec?.metadata?.sql);
639
+ const querySql = this.normalizeSql(this.savedQuerySql);
640
+ const sqlMatches = specSql != null && querySql != null && specSql === querySql;
641
+ // Only truly synced if SQL matches AND this is the version it was saved at.
642
+ // Even with identical SQL, a newer version should show the dropdown so the
643
+ // user can update the version association (re-save at current version).
644
+ const savedAtCurrent = this.EffectiveSavedAtVersion === this.CurrentVersionNumber;
645
+ if (sqlMatches && savedAtCurrent) {
646
+ return 'synced';
647
+ }
648
+ // SQL differs — determine position relative to saved version
649
+ if (isLatest) {
650
+ return 'outdated-latest';
651
+ }
652
+ // Use effective saved-at (looks ahead through newer versions)
653
+ const savedAt = this.EffectiveSavedAtVersion;
654
+ if (savedAt != null && this.CurrentVersionNumber < savedAt) {
655
+ return 'query-ahead'; // query was updated at a newer version
656
+ }
657
+ return 'query-behind'; // ahead of saved but not latest
658
+ }
659
+ /** Normalize SQL for comparison: trim and collapse whitespace */
660
+ normalizeSql(sql) {
661
+ if (sql == null)
662
+ return null;
663
+ return sql.trim().replace(/\s+/g, ' ');
664
+ }
665
+ // ─── Actions ────────────────────────────────────────────────────
666
+ /** Navigate to the saved query in the Data Explorer's Queries browser */
667
+ OnOpenSavedQuery() {
668
+ if (!this.spec?.savedQueryId)
669
+ return;
670
+ this.navigationRequest.emit({
671
+ appName: 'Data Explorer',
672
+ navItemName: 'Queries',
673
+ queryParams: { queryId: this.spec.savedQueryId }
674
+ });
675
+ }
676
+ /** Show the save panel for creating a brand-new query */
677
+ OnShowSaveDialog() {
678
+ this.ShowSaveDialog = true;
679
+ this.ShowUpdateDropdown = false;
680
+ }
681
+ /** Toggle the update query dropdown */
682
+ OnToggleUpdateDropdown() {
683
+ this.ShowUpdateDropdown = !this.ShowUpdateDropdown;
684
+ }
685
+ /** Close the dropdown (e.g., on outside click) */
686
+ OnCloseDropdown() {
687
+ this.ShowUpdateDropdown = false;
688
+ }
689
+ /**
690
+ * Update the existing saved query's SQL to match this version.
691
+ * Only available from the latest version (Scenario 3).
692
+ */
693
+ async OnUpdateExistingQuery() {
694
+ this.ShowUpdateDropdown = false;
695
+ if (!this.spec?.savedQueryId || !this.spec.metadata?.sql)
696
+ return;
697
+ this.IsSaving = true;
698
+ this.SavingMessage = `Updating "${this.SavedQueryDisplayName}"...`;
699
+ this.cdr.detectChanges();
700
+ try {
701
+ const md = new Metadata();
702
+ const query = await md.GetEntityObject('MJ: Queries');
703
+ const loaded = await query.Load(this.spec.savedQueryId);
704
+ if (!loaded) {
705
+ console.error('Failed to load saved query for update');
706
+ return;
707
+ }
708
+ query.SQL = this.spec.metadata.sql;
709
+ const saved = await query.Save();
710
+ if (saved) {
711
+ // Update spec with new version tracking
712
+ this.spec.savedAtVersionNumber = this.CurrentVersionNumber;
713
+ await this.PersistArtifactContent();
714
+ // Refresh caches so future lookups see the updated data
715
+ await QueryEngine.Instance.Config(true);
716
+ await ArtifactMetadataEngine.Instance.Config(true);
717
+ await md.Refresh();
718
+ this.savedQuerySql = this.spec.metadata.sql;
719
+ this.EffectiveSavedAtVersion = this.CurrentVersionNumber;
720
+ this.QuerySyncState = 'synced';
721
+ }
722
+ }
723
+ catch (error) {
724
+ console.error('Failed to update saved query:', error);
725
+ }
726
+ finally {
727
+ this.IsSaving = false;
728
+ this.cdr.detectChanges();
729
+ }
730
+ }
731
+ /**
732
+ * Save as a new query (from the dropdown).
733
+ * Opens the save dialog which creates a fresh query record.
734
+ */
735
+ OnSaveAsNewQuery() {
736
+ this.ShowUpdateDropdown = false;
737
+ this.ShowSaveDialog = true;
738
+ }
739
+ /** Handle successful save from the dialog (both initial save and "save as new") */
740
+ async OnQuerySaved(event) {
741
+ this.ShowSaveDialog = false;
742
+ this.IsSaving = true;
743
+ this.SavingMessage = 'Saving query...';
744
+ this.cdr.detectChanges();
745
+ try {
746
+ // Update spec with saved query info and version tracking
747
+ this.spec.savedQueryId = event.queryId;
748
+ this.spec.savedQueryName = event.queryName;
749
+ this.spec.savedAtVersionNumber = this.CurrentVersionNumber;
750
+ // Persist and refresh caches
751
+ await this.PersistArtifactContent();
752
+ await QueryEngine.Instance.Config(true);
753
+ await ArtifactMetadataEngine.Instance.Config(true);
754
+ await new Metadata().Refresh();
755
+ this.savedQuerySql = this.spec.metadata?.sql ?? null;
756
+ this.EffectiveSavedAtVersion = this.CurrentVersionNumber;
757
+ this.QuerySyncState = 'synced';
758
+ }
759
+ catch (error) {
760
+ console.error('Failed to save query:', error);
761
+ }
762
+ finally {
763
+ this.IsSaving = false;
764
+ this.cdr.detectChanges();
765
+ }
766
+ }
767
+ /** Persist updated spec back to the artifact version entity */
768
+ async PersistArtifactContent() {
769
+ if (!this.artifactVersion || !this.spec)
770
+ return;
771
+ this.artifactVersion.Content = JSON.stringify(this.spec);
772
+ await this.artifactVersion.Save();
773
+ }
774
+ // ─── Tabs ───────────────────────────────────────────────────────
775
+ /**
776
+ * Provide Plan tab (markdown) and SQL tab (code) when available
777
+ */
778
+ GetAdditionalTabs() {
779
+ const tabs = [];
780
+ if (this.spec?.plan) {
781
+ tabs.push({
782
+ label: 'Plan',
783
+ icon: 'fa-diagram-project',
784
+ contentType: 'markdown',
785
+ content: this.spec.plan
786
+ });
787
+ }
788
+ if (this.spec?.metadata?.sql) {
789
+ tabs.push({
790
+ label: 'SQL',
791
+ icon: 'fa-database',
792
+ contentType: 'code',
793
+ language: 'sql',
794
+ content: this.spec.metadata.sql
795
+ });
796
+ }
797
+ return tabs;
798
+ }
799
+ static ɵfac = function DataArtifactViewerComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || DataArtifactViewerComponent)(i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); };
800
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: DataArtifactViewerComponent, selectors: [["mj-data-artifact-viewer"]], outputs: { openEntityRecord: "openEntityRecord", navigationRequest: "navigationRequest" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 5, vars: 3, consts: [[1, "data-artifact-viewer", 3, "ngClass"], [1, "error-state"], [1, "empty-state"], [3, "QueryName", "QueryDescription", "SQL"], [1, "data-toolbar"], [1, "data-title"], [1, "fas", "fa-table"], [1, "live-badge"], [1, "row-count"], [1, "exec-time"], [1, "data-actions"], ["title", "Refresh data", 1, "btn-icon", 3, "disabled"], ["title", "Save as reusable query", 1, "btn-icon", "btn-save"], [1, "grid-container"], [1, "saving-overlay"], ["text", "Loading data..."], ["Height", "100%", 3, "ColumnConfigs", "Data", "ShowToolbar", "ShowRefresh", "PersistState", "SelectionMode"], ["title", "Refresh data", 1, "btn-icon", 3, "click", "disabled"], [1, "fas", "fa-sync-alt"], ["title", "Save as reusable query", 1, "btn-icon", "btn-save", 3, "click"], [1, "fas", "fa-save"], [1, "query-badge", "query-badge-synced"], [1, "fas", "fa-check"], ["title", "Open saved query record", 1, "btn-icon", "btn-open", 3, "click"], [1, "fas", "fa-external-link-alt"], [1, "query-badge", "query-badge-outdated"], [1, "fas", "fa-circle-exclamation"], [1, "dropdown-wrapper"], ["title", "Update or save query", 1, "btn-icon", "btn-warning", 3, "click"], [1, "fas", "fa-caret-down"], [1, "query-dropdown"], [1, "query-dropdown", 3, "click"], [1, "query-dropdown-item", 3, "click"], [1, "fas", "fa-arrow-up-from-bracket", 2, "color", "#d97706"], [1, "dropdown-label"], [1, "dropdown-desc"], [1, "fas", "fa-plus", 2, "color", "#16a34a"], [1, "fas", "fa-external-link-alt", 2, "color", "#6c757d"], [1, "query-badge", "query-badge-muted"], [1, "fas", "fa-clock-rotate-left"], ["title", "Open saved query record", 1, "btn-icon", "btn-muted", 3, "click"], [3, "text"], [1, "error-banner"], [1, "fas", "fa-exclamation-triangle"], [1, "fallback-note"], ["Height", "100%", 3, "EntityLinkClick", "ColumnConfigs", "Data", "ShowToolbar", "ShowRefresh", "PersistState", "SelectionMode"], [1, "fas", "fa-diagram-project"], [1, "plan-content"], [3, "data", "enableMermaid", "enableHighlight", "enableCollapsibleHeadings", "enableSmartypants"], [1, "fas", "fa-inbox"], [3, "Saved", "Cancelled", "QueryName", "QueryDescription", "SQL"]], template: function DataArtifactViewerComponent_Template(rf, ctx) { if (rf & 1) {
801
+ i0.ɵɵelementStart(0, "div", 0);
802
+ i0.ɵɵconditionalCreate(1, DataArtifactViewerComponent_Conditional_1_Template, 3, 1)(2, DataArtifactViewerComponent_Conditional_2_Template, 4, 1, "div", 1)(3, DataArtifactViewerComponent_Conditional_3_Template, 4, 0, "div", 2);
803
+ i0.ɵɵconditionalCreate(4, DataArtifactViewerComponent_Conditional_4_Template, 1, 3, "mj-save-query-panel", 3);
804
+ i0.ɵɵelementEnd();
805
+ } if (rf & 2) {
806
+ i0.ɵɵproperty("ngClass", ctx.cssClass);
807
+ i0.ɵɵadvance();
808
+ i0.ɵɵconditional(ctx.spec ? 1 : ctx.HasError ? 2 : 3);
809
+ i0.ɵɵadvance(3);
810
+ i0.ɵɵconditional(ctx.ShowSaveDialog ? 4 : -1);
811
+ } }, dependencies: [i1.NgClass, i2.MarkdownComponent, i3.QueryDataGridComponent, i4.LoadingComponent, i5.SaveQueryPanelComponent], styles: [".data-artifact-viewer[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n}\n\n.data-toolbar[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 8px 12px;\n background: #f8f9fa;\n border-bottom: 1px solid #dee2e6;\n}\n\n.data-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n font-weight: 600;\n font-size: 13px;\n color: #333;\n}\n\n.data-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #6c757d;\n}\n\n.row-count[_ngcontent-%COMP%] {\n padding: 2px 8px;\n background: #e9ecef;\n border-radius: 10px;\n font-size: 11px;\n font-weight: 500;\n color: #495057;\n}\n\n.exec-time[_ngcontent-%COMP%] {\n padding: 2px 8px;\n background: #d4edda;\n border-radius: 10px;\n font-size: 11px;\n font-weight: 500;\n color: #155724;\n}\n\n.live-badge[_ngcontent-%COMP%] {\n padding: 2px 8px;\n background: #cce5ff;\n border-radius: 10px;\n font-size: 11px;\n font-weight: 600;\n color: #004085;\n}\n\n.data-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 6px;\n}\n\n.btn-icon[_ngcontent-%COMP%] {\n padding: 4px 10px;\n background: white;\n border: 1px solid #ced4da;\n border-radius: 4px;\n cursor: pointer;\n font-size: 11px;\n display: flex;\n align-items: center;\n gap: 4px;\n color: #495057;\n}\n\n.btn-icon[_ngcontent-%COMP%]:hover {\n background: #e9ecef;\n border-color: #adb5bd;\n}\n\n.btn-icon[_ngcontent-%COMP%]:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.btn-icon.btn-save[_ngcontent-%COMP%] {\n color: #16a34a;\n border-color: #86efac;\n}\n\n.btn-icon.btn-save[_ngcontent-%COMP%]:hover {\n background: #f0fdf4;\n border-color: #16a34a;\n}\n\n.btn-icon.btn-open[_ngcontent-%COMP%] {\n color: #2563eb;\n border-color: #93c5fd;\n}\n\n.btn-icon.btn-open[_ngcontent-%COMP%]:hover {\n background: #eff6ff;\n border-color: #2563eb;\n}\n\n.grid-container[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n min-height: 200px;\n height: 500px;\n position: relative;\n}\n\n\n\n.saving-overlay[_ngcontent-%COMP%] {\n position: absolute;\n inset: 0;\n background: rgba(255, 255, 255, 0.8);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 50;\n}\n\n.error-banner[_ngcontent-%COMP%] {\n padding: 8px 12px;\n background: #fff3cd;\n border-bottom: 1px solid #ffc107;\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 12px;\n color: #856404;\n}\n\n.fallback-note[_ngcontent-%COMP%] {\n font-style: italic;\n color: #6c757d;\n}\n\n.empty-state[_ngcontent-%COMP%], .error-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 200px;\n color: #6c757d;\n text-align: center;\n gap: 12px;\n}\n\n.empty-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%], .error-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 32px;\n}\n\n.error-state[_ngcontent-%COMP%] {\n color: #dc3545;\n}\n\n.plan-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow: auto;\n padding: 16px;\n}\n\n\n\n.query-badge[_ngcontent-%COMP%] {\n padding: 2px 8px;\n border-radius: 10px;\n font-size: 11px;\n font-weight: 600;\n display: inline-flex;\n align-items: center;\n gap: 4px;\n white-space: nowrap;\n}\n\n.query-badge-synced[_ngcontent-%COMP%] {\n background: #d1fae5;\n color: #065f46;\n}\n\n.query-badge-outdated[_ngcontent-%COMP%] {\n background: #fff3cd;\n color: #856404;\n}\n\n.query-badge-muted[_ngcontent-%COMP%] {\n background: #f3f4f6;\n color: #9ca3af;\n}\n\n\n\n.dropdown-wrapper[_ngcontent-%COMP%] {\n position: relative;\n}\n\n.btn-icon.btn-warning[_ngcontent-%COMP%] {\n color: #d97706;\n border-color: #fcd34d;\n}\n\n.btn-icon.btn-warning[_ngcontent-%COMP%]:hover {\n background: #fffbeb;\n border-color: #d97706;\n}\n\n.btn-icon.btn-muted[_ngcontent-%COMP%] {\n color: #9ca3af;\n border-color: #e5e7eb;\n}\n\n\n\n.query-dropdown[_ngcontent-%COMP%] {\n position: absolute;\n top: 100%;\n right: 0;\n margin-top: 4px;\n background: white;\n border: 1px solid #dee2e6;\n border-radius: 8px;\n box-shadow: 0 4px 16px rgba(0,0,0,0.12);\n overflow: hidden;\n min-width: 280px;\n z-index: 100;\n}\n\n.query-dropdown-item[_ngcontent-%COMP%] {\n padding: 10px 14px;\n display: flex;\n align-items: center;\n gap: 10px;\n font-size: 12px;\n cursor: pointer;\n border-bottom: 1px solid #f0f0f0;\n transition: background 0.1s;\n}\n\n.query-dropdown-item[_ngcontent-%COMP%]:last-child {\n border-bottom: none;\n}\n\n.query-dropdown-item[_ngcontent-%COMP%]:hover {\n background: #f8f9fa;\n}\n\n.query-dropdown-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n width: 16px;\n text-align: center;\n flex-shrink: 0;\n}\n\n.dropdown-label[_ngcontent-%COMP%] {\n font-weight: 500;\n}\n\n.dropdown-desc[_ngcontent-%COMP%] {\n font-size: 11px;\n color: #6c757d;\n margin-top: 2px;\n}"] });
812
+ };
813
+ DataArtifactViewerComponent = __decorate([
814
+ RegisterClass(BaseArtifactViewerPluginComponent, 'DataArtifactViewerPlugin')
815
+ ], DataArtifactViewerComponent);
816
+ export { DataArtifactViewerComponent };
817
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(DataArtifactViewerComponent, [{
818
+ type: Component,
819
+ args: [{ standalone: false, selector: 'mj-data-artifact-viewer', template: "<div class=\"data-artifact-viewer\" [ngClass]=\"cssClass\">\n @if (spec) {\n @if (HasData || IsLoading) {\n <!-- Toolbar -->\n <div class=\"data-toolbar\">\n <div class=\"data-title\">\n <i class=\"fas fa-table\"></i>\n <span>{{ spec.title || 'Data Results' }}</span>\n @if (IsLive) {\n <span class=\"live-badge\">Live</span>\n }\n @if (DisplayRowCount != null) {\n <span class=\"row-count\">{{ DisplayRowCount }} rows</span>\n }\n @if (DisplayExecutionTime != null) {\n <span class=\"exec-time\">{{ DisplayExecutionTime }}ms</span>\n }\n </div>\n <div class=\"data-actions\">\n @if (IsLive) {\n <button class=\"btn-icon\" title=\"Refresh data\" (click)=\"OnRefresh()\" [disabled]=\"IsLoading\">\n <i class=\"fas fa-sync-alt\" [class.fa-spin]=\"IsLoading\"></i> Refresh\n </button>\n }\n\n @switch (QuerySyncState) {\n <!-- S1: No saved query, latest version \u2192 Save Query -->\n @case ('no-query-latest') {\n <button class=\"btn-icon btn-save\" title=\"Save as reusable query\"\n (click)=\"OnShowSaveDialog()\">\n <i class=\"fas fa-save\"></i> Save Query\n </button>\n }\n\n <!-- S2: SQL matches \u2192 green badge + Open -->\n @case ('synced') {\n <span class=\"query-badge query-badge-synced\">\n <i class=\"fas fa-check\"></i> Saved at v{{ SavedAtVersion }}\n </span>\n <button class=\"btn-icon btn-open\" title=\"Open saved query record\"\n (click)=\"OnOpenSavedQuery()\">\n <i class=\"fas fa-external-link-alt\"></i> Open Query\n </button>\n }\n\n <!-- S3: SQL differs, latest version \u2192 amber badge + dropdown -->\n @case ('outdated-latest') {\n <span class=\"query-badge query-badge-outdated\">\n <i class=\"fas fa-circle-exclamation\"></i> Saved at v{{ SavedAtVersion }}\n </span>\n <div class=\"dropdown-wrapper\">\n <button class=\"btn-icon btn-warning\" title=\"Update or save query\"\n (click)=\"OnToggleUpdateDropdown()\">\n <i class=\"fas fa-save\"></i> Update Query <i class=\"fas fa-caret-down\"></i>\n </button>\n @if (ShowUpdateDropdown) {\n <div class=\"query-dropdown\" (click)=\"$event.stopPropagation()\">\n <div class=\"query-dropdown-item\" (click)=\"OnUpdateExistingQuery()\">\n <i class=\"fas fa-arrow-up-from-bracket\" style=\"color:#d97706\"></i>\n <div>\n <div class=\"dropdown-label\">Update \"{{ SavedQueryDisplayName }}\"</div>\n <div class=\"dropdown-desc\">Replace saved query SQL with this version's SQL</div>\n </div>\n </div>\n <div class=\"query-dropdown-item\" (click)=\"OnSaveAsNewQuery()\">\n <i class=\"fas fa-plus\" style=\"color:#16a34a\"></i>\n <div>\n <div class=\"dropdown-label\">Save as New Query</div>\n <div class=\"dropdown-desc\">Create a new query, keep the original unchanged</div>\n </div>\n </div>\n <div class=\"query-dropdown-item\" (click)=\"OnOpenSavedQuery(); OnCloseDropdown()\">\n <i class=\"fas fa-external-link-alt\" style=\"color:#6c757d\"></i>\n <div>\n <div class=\"dropdown-label\">Open Saved Query</div>\n <div class=\"dropdown-desc\">View \"{{ SavedQueryDisplayName }}\" (saved at v{{ SavedAtVersion }})</div>\n </div>\n </div>\n </div>\n }\n </div>\n }\n\n <!-- S4: Older version, query was updated ahead -->\n @case ('query-ahead') {\n <span class=\"query-badge query-badge-muted\">\n <i class=\"fas fa-clock-rotate-left\"></i> Query updated at v{{ SavedAtVersion }}\n </span>\n <button class=\"btn-icon btn-muted\" title=\"Open saved query record\"\n (click)=\"OnOpenSavedQuery()\">\n <i class=\"fas fa-external-link-alt\"></i> Open Query\n </button>\n }\n\n <!-- S5: Middle version, saved at older, not latest -->\n @case ('query-behind') {\n <span class=\"query-badge query-badge-muted\">\n <i class=\"fas fa-clock-rotate-left\"></i> Saved at v{{ SavedAtVersion }}\n </span>\n <button class=\"btn-icon btn-muted\" title=\"Open saved query record\"\n (click)=\"OnOpenSavedQuery()\">\n <i class=\"fas fa-external-link-alt\"></i> Open Query\n </button>\n }\n\n <!-- S6: No saved query, older version \u2192 no actions -->\n @case ('no-query-older') {\n <!-- No query actions available on older versions -->\n }\n }\n </div>\n </div>\n\n <!-- Grid -->\n <div class=\"grid-container\">\n <!-- Saving overlay -->\n @if (IsSaving) {\n <div class=\"saving-overlay\">\n <mj-loading [text]=\"SavingMessage\"></mj-loading>\n </div>\n }\n @if (IsLoading) {\n <mj-loading text=\"Loading data...\"></mj-loading>\n } @else if (HasError && HasData) {\n <div class=\"error-banner\">\n <i class=\"fas fa-exclamation-triangle\"></i>\n <span>{{ ErrorMessage }}</span>\n <span class=\"fallback-note\">(Showing cached data)</span>\n </div>\n <mj-query-data-grid\n [ColumnConfigs]=\"GridColumnConfigs\"\n [Data]=\"GridData\"\n [ShowToolbar]=\"false\"\n [ShowRefresh]=\"false\"\n [PersistState]=\"false\"\n [SelectionMode]=\"'none'\"\n (EntityLinkClick)=\"OnEntityLinkClick($event)\"\n Height=\"100%\">\n </mj-query-data-grid>\n } @else if (HasError) {\n <div class=\"error-state\">\n <i class=\"fas fa-exclamation-triangle\"></i>\n <p>{{ ErrorMessage }}</p>\n </div>\n } @else {\n <mj-query-data-grid\n [ColumnConfigs]=\"GridColumnConfigs\"\n [Data]=\"GridData\"\n [ShowToolbar]=\"false\"\n [ShowRefresh]=\"false\"\n [PersistState]=\"false\"\n [SelectionMode]=\"'none'\"\n (EntityLinkClick)=\"OnEntityLinkClick($event)\"\n Height=\"100%\">\n </mj-query-data-grid>\n }\n </div>\n } @else if (spec.plan) {\n <!-- Plan-only view (no results yet) -->\n <div class=\"data-toolbar\">\n <div class=\"data-title\">\n <i class=\"fas fa-diagram-project\"></i>\n <span>{{ spec.title || 'Query Plan' }}</span>\n </div>\n </div>\n <div class=\"plan-content\">\n <mj-markdown\n [data]=\"spec.plan\"\n [enableMermaid]=\"true\"\n [enableHighlight]=\"true\"\n [enableCollapsibleHeadings]=\"false\"\n [enableSmartypants]=\"true\">\n </mj-markdown>\n </div>\n } @else {\n <!-- No data and no plan -->\n <div class=\"empty-state\">\n <i class=\"fas fa-inbox\"></i>\n <p>No data to display</p>\n </div>\n }\n } @else if (HasError) {\n <div class=\"error-state\">\n <i class=\"fas fa-exclamation-triangle\"></i>\n <p>{{ ErrorMessage }}</p>\n </div>\n } @else {\n <div class=\"empty-state\">\n <i class=\"fas fa-inbox\"></i>\n <p>No data to display</p>\n </div>\n }\n\n <!-- Save Query Panel (slide-in) -->\n @if (ShowSaveDialog) {\n <mj-save-query-panel\n [QueryName]=\"spec?.title || 'Untitled Query'\"\n [QueryDescription]=\"''\"\n [SQL]=\"spec?.metadata?.sql || ''\"\n (Saved)=\"OnQuerySaved($event)\"\n (Cancelled)=\"ShowSaveDialog = false\">\n </mj-save-query-panel>\n }\n</div>\n", styles: [".data-artifact-viewer {\n display: flex;\n flex-direction: column;\n height: 100%;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n}\n\n.data-toolbar {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 8px 12px;\n background: #f8f9fa;\n border-bottom: 1px solid #dee2e6;\n}\n\n.data-title {\n display: flex;\n align-items: center;\n gap: 8px;\n font-weight: 600;\n font-size: 13px;\n color: #333;\n}\n\n.data-title i {\n color: #6c757d;\n}\n\n.row-count {\n padding: 2px 8px;\n background: #e9ecef;\n border-radius: 10px;\n font-size: 11px;\n font-weight: 500;\n color: #495057;\n}\n\n.exec-time {\n padding: 2px 8px;\n background: #d4edda;\n border-radius: 10px;\n font-size: 11px;\n font-weight: 500;\n color: #155724;\n}\n\n.live-badge {\n padding: 2px 8px;\n background: #cce5ff;\n border-radius: 10px;\n font-size: 11px;\n font-weight: 600;\n color: #004085;\n}\n\n.data-actions {\n display: flex;\n gap: 6px;\n}\n\n.btn-icon {\n padding: 4px 10px;\n background: white;\n border: 1px solid #ced4da;\n border-radius: 4px;\n cursor: pointer;\n font-size: 11px;\n display: flex;\n align-items: center;\n gap: 4px;\n color: #495057;\n}\n\n.btn-icon:hover {\n background: #e9ecef;\n border-color: #adb5bd;\n}\n\n.btn-icon:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.btn-icon.btn-save {\n color: #16a34a;\n border-color: #86efac;\n}\n\n.btn-icon.btn-save:hover {\n background: #f0fdf4;\n border-color: #16a34a;\n}\n\n.btn-icon.btn-open {\n color: #2563eb;\n border-color: #93c5fd;\n}\n\n.btn-icon.btn-open:hover {\n background: #eff6ff;\n border-color: #2563eb;\n}\n\n.grid-container {\n flex: 1;\n overflow: hidden;\n min-height: 200px;\n height: 500px;\n position: relative;\n}\n\n/* Saving overlay \u2014 semi-transparent panel over the grid */\n.saving-overlay {\n position: absolute;\n inset: 0;\n background: rgba(255, 255, 255, 0.8);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 50;\n}\n\n.error-banner {\n padding: 8px 12px;\n background: #fff3cd;\n border-bottom: 1px solid #ffc107;\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 12px;\n color: #856404;\n}\n\n.fallback-note {\n font-style: italic;\n color: #6c757d;\n}\n\n.empty-state, .error-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 200px;\n color: #6c757d;\n text-align: center;\n gap: 12px;\n}\n\n.empty-state i, .error-state i {\n font-size: 32px;\n}\n\n.error-state {\n color: #dc3545;\n}\n\n.plan-content {\n flex: 1;\n overflow: auto;\n padding: 16px;\n}\n\n/* Query sync badges */\n.query-badge {\n padding: 2px 8px;\n border-radius: 10px;\n font-size: 11px;\n font-weight: 600;\n display: inline-flex;\n align-items: center;\n gap: 4px;\n white-space: nowrap;\n}\n\n.query-badge-synced {\n background: #d1fae5;\n color: #065f46;\n}\n\n.query-badge-outdated {\n background: #fff3cd;\n color: #856404;\n}\n\n.query-badge-muted {\n background: #f3f4f6;\n color: #9ca3af;\n}\n\n/* Dropdown wrapper */\n.dropdown-wrapper {\n position: relative;\n}\n\n.btn-icon.btn-warning {\n color: #d97706;\n border-color: #fcd34d;\n}\n\n.btn-icon.btn-warning:hover {\n background: #fffbeb;\n border-color: #d97706;\n}\n\n.btn-icon.btn-muted {\n color: #9ca3af;\n border-color: #e5e7eb;\n}\n\n/* Query actions dropdown */\n.query-dropdown {\n position: absolute;\n top: 100%;\n right: 0;\n margin-top: 4px;\n background: white;\n border: 1px solid #dee2e6;\n border-radius: 8px;\n box-shadow: 0 4px 16px rgba(0,0,0,0.12);\n overflow: hidden;\n min-width: 280px;\n z-index: 100;\n}\n\n.query-dropdown-item {\n padding: 10px 14px;\n display: flex;\n align-items: center;\n gap: 10px;\n font-size: 12px;\n cursor: pointer;\n border-bottom: 1px solid #f0f0f0;\n transition: background 0.1s;\n}\n\n.query-dropdown-item:last-child {\n border-bottom: none;\n}\n\n.query-dropdown-item:hover {\n background: #f8f9fa;\n}\n\n.query-dropdown-item i {\n width: 16px;\n text-align: center;\n flex-shrink: 0;\n}\n\n.dropdown-label {\n font-weight: 500;\n}\n\n.dropdown-desc {\n font-size: 11px;\n color: #6c757d;\n margin-top: 2px;\n}\n"] }]
820
+ }], () => [{ type: i0.ChangeDetectorRef }], { openEntityRecord: [{
821
+ type: Output
822
+ }], navigationRequest: [{
823
+ type: Output
824
+ }] }); })();
825
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(DataArtifactViewerComponent, { className: "DataArtifactViewerComponent", filePath: "src/lib/components/plugins/data-artifact-viewer.component.ts", lineNumber: 108 }); })();
826
+ //# sourceMappingURL=data-artifact-viewer.component.js.map