@memberjunction/ng-explorer-core 2.98.0 → 2.99.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.
- package/dist/lib/query-browser-component/query-browser.component.d.ts +64 -8
- package/dist/lib/query-browser-component/query-browser.component.d.ts.map +1 -1
- package/dist/lib/query-browser-component/query-browser.component.js +867 -48
- package/dist/lib/query-browser-component/query-browser.component.js.map +1 -1
- package/dist/lib/resource-browser/resource-browser.component.d.ts.map +1 -1
- package/dist/lib/resource-browser/resource-browser.component.js +3 -2
- package/dist/lib/resource-browser/resource-browser.component.js.map +1 -1
- package/dist/lib/single-query/single-query.component.d.ts +0 -1
- package/dist/lib/single-query/single-query.component.d.ts.map +1 -1
- package/dist/lib/single-query/single-query.component.js +9 -15
- package/dist/lib/single-query/single-query.component.js.map +1 -1
- package/package.json +25 -25
|
@@ -5,77 +5,896 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
7
|
import { Component } from '@angular/core';
|
|
8
|
-
import { ItemType } from '../../generic/Item.types';
|
|
9
8
|
import { BaseNavigationComponent } from '@memberjunction/ng-shared';
|
|
10
|
-
import {
|
|
11
|
-
import { Metadata } from '@memberjunction/core';
|
|
9
|
+
import { Metadata, RunView } from '@memberjunction/core';
|
|
12
10
|
import { RegisterClass } from '@memberjunction/global';
|
|
11
|
+
import { Subject } from 'rxjs';
|
|
12
|
+
import { debounceTime, takeUntil } from 'rxjs/operators';
|
|
13
13
|
import * as i0 from "@angular/core";
|
|
14
14
|
import * as i1 from "@angular/router";
|
|
15
15
|
import * as i2 from "@memberjunction/ng-shared";
|
|
16
|
-
import * as i3 from "
|
|
17
|
-
|
|
16
|
+
import * as i3 from "@angular/forms";
|
|
17
|
+
import * as i4 from "@progress/kendo-angular-dropdowns";
|
|
18
|
+
const _forTrack0 = ($index, $item) => $item.id;
|
|
19
|
+
const _forTrack1 = ($index, $item) => $item.ID;
|
|
20
|
+
function QueryBrowserComponent_Conditional_29_Template(rf, ctx) { if (rf & 1) {
|
|
21
|
+
const _r1 = i0.ɵɵgetCurrentView();
|
|
22
|
+
i0.ɵɵelementStart(0, "button", 27);
|
|
23
|
+
i0.ɵɵlistener("click", function QueryBrowserComponent_Conditional_29_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.clearAllFilters()); });
|
|
24
|
+
i0.ɵɵelement(1, "i", 28);
|
|
25
|
+
i0.ɵɵtext(2, " Clear Filters ");
|
|
26
|
+
i0.ɵɵelementEnd();
|
|
27
|
+
} }
|
|
28
|
+
function QueryBrowserComponent_Conditional_30_Template(rf, ctx) { if (rf & 1) {
|
|
29
|
+
i0.ɵɵelementStart(0, "div", 22);
|
|
30
|
+
i0.ɵɵelement(1, "i", 29);
|
|
31
|
+
i0.ɵɵtext(2, " Loading queries... ");
|
|
32
|
+
i0.ɵɵelementEnd();
|
|
33
|
+
} }
|
|
34
|
+
function QueryBrowserComponent_Conditional_32_For_5_Template(rf, ctx) { if (rf & 1) {
|
|
35
|
+
const _r4 = i0.ɵɵgetCurrentView();
|
|
36
|
+
i0.ɵɵelement(0, "i", 35);
|
|
37
|
+
i0.ɵɵelementStart(1, "span", 31);
|
|
38
|
+
i0.ɵɵlistener("click", function QueryBrowserComponent_Conditional_32_For_5_Template_span_click_1_listener() { const pathItem_r5 = i0.ɵɵrestoreView(_r4).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.navigateToCategory(pathItem_r5.id)); });
|
|
39
|
+
i0.ɵɵtext(2);
|
|
40
|
+
i0.ɵɵelementEnd();
|
|
41
|
+
} if (rf & 2) {
|
|
42
|
+
const pathItem_r5 = ctx.$implicit;
|
|
43
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
44
|
+
i0.ɵɵadvance();
|
|
45
|
+
i0.ɵɵclassProp("current", pathItem_r5.id === ctx_r1.currentCategoryId);
|
|
46
|
+
i0.ɵɵadvance();
|
|
47
|
+
i0.ɵɵtextInterpolate1(" ", pathItem_r5.name, " ");
|
|
48
|
+
} }
|
|
49
|
+
function QueryBrowserComponent_Conditional_32_Conditional_6_For_6_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
50
|
+
i0.ɵɵelementStart(0, "span", 43);
|
|
51
|
+
i0.ɵɵtext(1);
|
|
52
|
+
i0.ɵɵelementEnd();
|
|
53
|
+
} if (rf & 2) {
|
|
54
|
+
const category_r7 = i0.ɵɵnextContext().$implicit;
|
|
55
|
+
i0.ɵɵadvance();
|
|
56
|
+
i0.ɵɵtextInterpolate(category_r7.QueryCount);
|
|
57
|
+
} }
|
|
58
|
+
function QueryBrowserComponent_Conditional_32_Conditional_6_For_6_Template(rf, ctx) { if (rf & 1) {
|
|
59
|
+
const _r6 = i0.ɵɵgetCurrentView();
|
|
60
|
+
i0.ɵɵelementStart(0, "div", 40);
|
|
61
|
+
i0.ɵɵlistener("click", function QueryBrowserComponent_Conditional_32_Conditional_6_For_6_Template_div_click_0_listener() { const category_r7 = i0.ɵɵrestoreView(_r6).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.navigateToCategory(category_r7.ID)); });
|
|
62
|
+
i0.ɵɵelement(1, "i", 41);
|
|
63
|
+
i0.ɵɵelementStart(2, "span", 42);
|
|
64
|
+
i0.ɵɵtext(3);
|
|
65
|
+
i0.ɵɵelementEnd();
|
|
66
|
+
i0.ɵɵtemplate(4, QueryBrowserComponent_Conditional_32_Conditional_6_For_6_Conditional_4_Template, 2, 1, "span", 43);
|
|
67
|
+
i0.ɵɵelementEnd();
|
|
68
|
+
} if (rf & 2) {
|
|
69
|
+
const category_r7 = ctx.$implicit;
|
|
70
|
+
i0.ɵɵproperty("title", category_r7.Description || category_r7.Name);
|
|
71
|
+
i0.ɵɵadvance(3);
|
|
72
|
+
i0.ɵɵtextInterpolate(category_r7.Name);
|
|
73
|
+
i0.ɵɵadvance();
|
|
74
|
+
i0.ɵɵconditional(category_r7.QueryCount && category_r7.QueryCount > 0 ? 4 : -1);
|
|
75
|
+
} }
|
|
76
|
+
function QueryBrowserComponent_Conditional_32_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
77
|
+
i0.ɵɵelementStart(0, "div", 32)(1, "h4", 36);
|
|
78
|
+
i0.ɵɵelement(2, "i", 37);
|
|
79
|
+
i0.ɵɵtext(3, " Categories ");
|
|
80
|
+
i0.ɵɵelementEnd();
|
|
81
|
+
i0.ɵɵelementStart(4, "div", 38);
|
|
82
|
+
i0.ɵɵrepeaterCreate(5, QueryBrowserComponent_Conditional_32_Conditional_6_For_6_Template, 5, 3, "div", 39, _forTrack1);
|
|
83
|
+
i0.ɵɵelementEnd()();
|
|
84
|
+
} if (rf & 2) {
|
|
85
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
86
|
+
i0.ɵɵadvance(5);
|
|
87
|
+
i0.ɵɵrepeater(ctx_r1.filteredCategories);
|
|
88
|
+
} }
|
|
89
|
+
function QueryBrowserComponent_Conditional_32_Conditional_7_For_8_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
90
|
+
i0.ɵɵelementStart(0, "div", 53);
|
|
91
|
+
i0.ɵɵtext(1);
|
|
92
|
+
i0.ɵɵelementEnd();
|
|
93
|
+
} if (rf & 2) {
|
|
94
|
+
const query_r9 = i0.ɵɵnextContext().$implicit;
|
|
95
|
+
i0.ɵɵadvance();
|
|
96
|
+
i0.ɵɵtextInterpolate(query_r9.Description);
|
|
97
|
+
} }
|
|
98
|
+
function QueryBrowserComponent_Conditional_32_Conditional_7_For_8_Template(rf, ctx) { if (rf & 1) {
|
|
99
|
+
const _r8 = i0.ɵɵgetCurrentView();
|
|
100
|
+
i0.ɵɵelementStart(0, "div", 48);
|
|
101
|
+
i0.ɵɵlistener("click", function QueryBrowserComponent_Conditional_32_Conditional_7_For_8_Template_div_click_0_listener() { const query_r9 = i0.ɵɵrestoreView(_r8).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.selectQuery(query_r9)); });
|
|
102
|
+
i0.ɵɵelementStart(1, "div", 49);
|
|
103
|
+
i0.ɵɵelement(2, "i", 50);
|
|
104
|
+
i0.ɵɵelementEnd();
|
|
105
|
+
i0.ɵɵelementStart(3, "div", 51)(4, "div", 52);
|
|
106
|
+
i0.ɵɵtext(5);
|
|
107
|
+
i0.ɵɵelementEnd();
|
|
108
|
+
i0.ɵɵtemplate(6, QueryBrowserComponent_Conditional_32_Conditional_7_For_8_Conditional_6_Template, 2, 1, "div", 53);
|
|
109
|
+
i0.ɵɵelementEnd();
|
|
110
|
+
i0.ɵɵelementStart(7, "div", 54);
|
|
111
|
+
i0.ɵɵtext(8);
|
|
112
|
+
i0.ɵɵelementEnd()();
|
|
113
|
+
} if (rf & 2) {
|
|
114
|
+
const query_r9 = ctx.$implicit;
|
|
115
|
+
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
116
|
+
i0.ɵɵclassProp("selected", (ctx_r1.selectedQuery == null ? null : ctx_r1.selectedQuery.ID) === query_r9.ID);
|
|
117
|
+
i0.ɵɵadvance(5);
|
|
118
|
+
i0.ɵɵtextInterpolate(query_r9.Name);
|
|
119
|
+
i0.ɵɵadvance();
|
|
120
|
+
i0.ɵɵconditional(query_r9.Description ? 6 : -1);
|
|
121
|
+
i0.ɵɵadvance();
|
|
122
|
+
i0.ɵɵclassMap("status-" + (query_r9.Status || "pending").toLowerCase());
|
|
123
|
+
i0.ɵɵadvance();
|
|
124
|
+
i0.ɵɵtextInterpolate1(" ", query_r9.Status || "Pending", " ");
|
|
125
|
+
} }
|
|
126
|
+
function QueryBrowserComponent_Conditional_32_Conditional_7_Template(rf, ctx) { if (rf & 1) {
|
|
127
|
+
i0.ɵɵelementStart(0, "div", 33)(1, "h4", 36);
|
|
128
|
+
i0.ɵɵelement(2, "i", 44);
|
|
129
|
+
i0.ɵɵtext(3, " Queries ");
|
|
130
|
+
i0.ɵɵelementStart(4, "span", 45);
|
|
131
|
+
i0.ɵɵtext(5);
|
|
132
|
+
i0.ɵɵelementEnd()();
|
|
133
|
+
i0.ɵɵelementStart(6, "div", 46);
|
|
134
|
+
i0.ɵɵrepeaterCreate(7, QueryBrowserComponent_Conditional_32_Conditional_7_For_8_Template, 9, 7, "div", 47, _forTrack1);
|
|
135
|
+
i0.ɵɵelementEnd()();
|
|
136
|
+
} if (rf & 2) {
|
|
137
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
138
|
+
i0.ɵɵadvance(5);
|
|
139
|
+
i0.ɵɵtextInterpolate1("(", ctx_r1.filteredQueries.length, ")");
|
|
140
|
+
i0.ɵɵadvance(2);
|
|
141
|
+
i0.ɵɵrepeater(ctx_r1.filteredQueries);
|
|
142
|
+
} }
|
|
143
|
+
function QueryBrowserComponent_Conditional_32_Conditional_8_Template(rf, ctx) { if (rf & 1) {
|
|
144
|
+
i0.ɵɵelementStart(0, "div", 34);
|
|
145
|
+
i0.ɵɵelement(1, "i", 55);
|
|
146
|
+
i0.ɵɵelementStart(2, "p");
|
|
147
|
+
i0.ɵɵtext(3, "No categories or queries found");
|
|
148
|
+
i0.ɵɵelementEnd()();
|
|
149
|
+
} }
|
|
150
|
+
function QueryBrowserComponent_Conditional_32_Template(rf, ctx) { if (rf & 1) {
|
|
151
|
+
const _r3 = i0.ɵɵgetCurrentView();
|
|
152
|
+
i0.ɵɵelementStart(0, "div", 24)(1, "div", 30)(2, "span", 31);
|
|
153
|
+
i0.ɵɵlistener("click", function QueryBrowserComponent_Conditional_32_Template_span_click_2_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.navigateToRoot()); });
|
|
154
|
+
i0.ɵɵtext(3, " ./ ");
|
|
155
|
+
i0.ɵɵelementEnd();
|
|
156
|
+
i0.ɵɵrepeaterCreate(4, QueryBrowserComponent_Conditional_32_For_5_Template, 3, 3, null, null, _forTrack0);
|
|
157
|
+
i0.ɵɵelementEnd();
|
|
158
|
+
i0.ɵɵtemplate(6, QueryBrowserComponent_Conditional_32_Conditional_6_Template, 7, 0, "div", 32)(7, QueryBrowserComponent_Conditional_32_Conditional_7_Template, 9, 1, "div", 33)(8, QueryBrowserComponent_Conditional_32_Conditional_8_Template, 4, 0, "div", 34);
|
|
159
|
+
i0.ɵɵelementEnd();
|
|
160
|
+
} if (rf & 2) {
|
|
161
|
+
const ctx_r1 = i0.ɵɵnextContext();
|
|
162
|
+
i0.ɵɵadvance(4);
|
|
163
|
+
i0.ɵɵrepeater(ctx_r1.currentCategoryPath);
|
|
164
|
+
i0.ɵɵadvance(2);
|
|
165
|
+
i0.ɵɵconditional(ctx_r1.filteredCategories.length > 0 ? 6 : -1);
|
|
166
|
+
i0.ɵɵadvance();
|
|
167
|
+
i0.ɵɵconditional(ctx_r1.filteredQueries.length > 0 ? 7 : -1);
|
|
168
|
+
i0.ɵɵadvance();
|
|
169
|
+
i0.ɵɵconditional(ctx_r1.filteredCategories.length === 0 && ctx_r1.filteredQueries.length === 0 ? 8 : -1);
|
|
170
|
+
} }
|
|
171
|
+
function QueryBrowserComponent_Conditional_33_Conditional_1_For_15_Template(rf, ctx) { if (rf & 1) {
|
|
172
|
+
const _r10 = i0.ɵɵgetCurrentView();
|
|
173
|
+
i0.ɵɵelementStart(0, "div", 65);
|
|
174
|
+
i0.ɵɵlistener("click", function QueryBrowserComponent_Conditional_33_Conditional_1_For_15_Template_div_click_0_listener() { const query_r11 = i0.ɵɵrestoreView(_r10).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.selectQuery(query_r11)); });
|
|
175
|
+
i0.ɵɵelementStart(1, "div", 57);
|
|
176
|
+
i0.ɵɵelement(2, "i", 50);
|
|
177
|
+
i0.ɵɵtext(3);
|
|
178
|
+
i0.ɵɵelementEnd();
|
|
179
|
+
i0.ɵɵelementStart(4, "div", 58);
|
|
180
|
+
i0.ɵɵtext(5);
|
|
181
|
+
i0.ɵɵelementEnd();
|
|
182
|
+
i0.ɵɵelementStart(6, "div", 59);
|
|
183
|
+
i0.ɵɵtext(7);
|
|
184
|
+
i0.ɵɵelementEnd();
|
|
185
|
+
i0.ɵɵelementStart(8, "div", 60)(9, "span", 66);
|
|
186
|
+
i0.ɵɵtext(10);
|
|
187
|
+
i0.ɵɵelementEnd()();
|
|
188
|
+
i0.ɵɵelementStart(11, "div", 61);
|
|
189
|
+
i0.ɵɵtext(12);
|
|
190
|
+
i0.ɵɵelementEnd();
|
|
191
|
+
i0.ɵɵelementStart(13, "div", 62)(14, "button", 67);
|
|
192
|
+
i0.ɵɵlistener("click", function QueryBrowserComponent_Conditional_33_Conditional_1_For_15_Template_button_click_14_listener($event) { const query_r11 = i0.ɵɵrestoreView(_r10).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.runQuery(query_r11, $event)); });
|
|
193
|
+
i0.ɵɵelement(15, "i", 68);
|
|
194
|
+
i0.ɵɵelementEnd();
|
|
195
|
+
i0.ɵɵelementStart(16, "button", 69);
|
|
196
|
+
i0.ɵɵlistener("click", function QueryBrowserComponent_Conditional_33_Conditional_1_For_15_Template_button_click_16_listener($event) { const query_r11 = i0.ɵɵrestoreView(_r10).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.deleteQuery(query_r11, $event)); });
|
|
197
|
+
i0.ɵɵelement(17, "i", 70);
|
|
198
|
+
i0.ɵɵelementEnd()()();
|
|
199
|
+
} if (rf & 2) {
|
|
200
|
+
const query_r11 = ctx.$implicit;
|
|
201
|
+
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
202
|
+
i0.ɵɵclassProp("selected", (ctx_r1.selectedQuery == null ? null : ctx_r1.selectedQuery.ID) === query_r11.ID);
|
|
203
|
+
i0.ɵɵadvance(3);
|
|
204
|
+
i0.ɵɵtextInterpolate1(" ", query_r11.Name, " ");
|
|
205
|
+
i0.ɵɵadvance(2);
|
|
206
|
+
i0.ɵɵtextInterpolate1(" ", query_r11.Description || "-", " ");
|
|
207
|
+
i0.ɵɵadvance(2);
|
|
208
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r1.getCategoryName(query_r11.CategoryID) || "-", " ");
|
|
209
|
+
i0.ɵɵadvance(2);
|
|
210
|
+
i0.ɵɵclassMap("status-" + (query_r11.Status || "pending").toLowerCase());
|
|
211
|
+
i0.ɵɵadvance();
|
|
212
|
+
i0.ɵɵtextInterpolate1(" ", query_r11.Status || "Pending", " ");
|
|
213
|
+
i0.ɵɵadvance(2);
|
|
214
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r1.formatDate(query_r11.__mj_UpdatedAt), " ");
|
|
215
|
+
} }
|
|
216
|
+
function QueryBrowserComponent_Conditional_33_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
217
|
+
i0.ɵɵelementStart(0, "div", 56)(1, "div", 57);
|
|
218
|
+
i0.ɵɵtext(2, "Name");
|
|
219
|
+
i0.ɵɵelementEnd();
|
|
220
|
+
i0.ɵɵelementStart(3, "div", 58);
|
|
221
|
+
i0.ɵɵtext(4, "Description");
|
|
222
|
+
i0.ɵɵelementEnd();
|
|
223
|
+
i0.ɵɵelementStart(5, "div", 59);
|
|
224
|
+
i0.ɵɵtext(6, "Category");
|
|
225
|
+
i0.ɵɵelementEnd();
|
|
226
|
+
i0.ɵɵelementStart(7, "div", 60);
|
|
227
|
+
i0.ɵɵtext(8, "Status");
|
|
228
|
+
i0.ɵɵelementEnd();
|
|
229
|
+
i0.ɵɵelementStart(9, "div", 61);
|
|
230
|
+
i0.ɵɵtext(10, "Last Updated");
|
|
231
|
+
i0.ɵɵelementEnd();
|
|
232
|
+
i0.ɵɵelementStart(11, "div", 62);
|
|
233
|
+
i0.ɵɵtext(12, "Actions");
|
|
234
|
+
i0.ɵɵelementEnd()();
|
|
235
|
+
i0.ɵɵelementStart(13, "div", 63);
|
|
236
|
+
i0.ɵɵrepeaterCreate(14, QueryBrowserComponent_Conditional_33_Conditional_1_For_15_Template, 18, 9, "div", 64, _forTrack1);
|
|
237
|
+
i0.ɵɵelementEnd();
|
|
238
|
+
} if (rf & 2) {
|
|
239
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
240
|
+
i0.ɵɵadvance(14);
|
|
241
|
+
i0.ɵɵrepeater(ctx_r1.filteredQueries);
|
|
242
|
+
} }
|
|
243
|
+
function QueryBrowserComponent_Conditional_33_Conditional_2_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
244
|
+
i0.ɵɵelementStart(0, "p", 71);
|
|
245
|
+
i0.ɵɵtext(1, "Try adjusting your filters");
|
|
246
|
+
i0.ɵɵelementEnd();
|
|
247
|
+
} }
|
|
248
|
+
function QueryBrowserComponent_Conditional_33_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
249
|
+
i0.ɵɵelementStart(0, "div", 34);
|
|
250
|
+
i0.ɵɵelement(1, "i", 4);
|
|
251
|
+
i0.ɵɵelementStart(2, "p");
|
|
252
|
+
i0.ɵɵtext(3, "No queries found");
|
|
253
|
+
i0.ɵɵelementEnd();
|
|
254
|
+
i0.ɵɵtemplate(4, QueryBrowserComponent_Conditional_33_Conditional_2_Conditional_4_Template, 2, 0, "p", 71);
|
|
255
|
+
i0.ɵɵelementEnd();
|
|
256
|
+
} if (rf & 2) {
|
|
257
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
258
|
+
i0.ɵɵadvance(4);
|
|
259
|
+
i0.ɵɵconditional(ctx_r1.searchText || ctx_r1.selectedStatus !== "all" ? 4 : -1);
|
|
260
|
+
} }
|
|
261
|
+
function QueryBrowserComponent_Conditional_33_Template(rf, ctx) { if (rf & 1) {
|
|
262
|
+
i0.ɵɵelementStart(0, "div", 25);
|
|
263
|
+
i0.ɵɵtemplate(1, QueryBrowserComponent_Conditional_33_Conditional_1_Template, 16, 0)(2, QueryBrowserComponent_Conditional_33_Conditional_2_Template, 5, 1, "div", 34);
|
|
264
|
+
i0.ɵɵelementEnd();
|
|
265
|
+
} if (rf & 2) {
|
|
266
|
+
const ctx_r1 = i0.ɵɵnextContext();
|
|
267
|
+
i0.ɵɵadvance();
|
|
268
|
+
i0.ɵɵconditional(ctx_r1.filteredQueries.length > 0 ? 1 : 2);
|
|
269
|
+
} }
|
|
270
|
+
function QueryBrowserComponent_Conditional_34_Conditional_1_For_2_Conditional_7_Template(rf, ctx) { if (rf & 1) {
|
|
271
|
+
i0.ɵɵelementStart(0, "div", 77);
|
|
272
|
+
i0.ɵɵtext(1);
|
|
273
|
+
i0.ɵɵelementEnd();
|
|
274
|
+
} if (rf & 2) {
|
|
275
|
+
const query_r13 = i0.ɵɵnextContext().$implicit;
|
|
276
|
+
i0.ɵɵadvance();
|
|
277
|
+
i0.ɵɵtextInterpolate1(" ", query_r13.Description, " ");
|
|
278
|
+
} }
|
|
279
|
+
function QueryBrowserComponent_Conditional_34_Conditional_1_For_2_Conditional_15_Template(rf, ctx) { if (rf & 1) {
|
|
280
|
+
i0.ɵɵelementStart(0, "span", 83);
|
|
281
|
+
i0.ɵɵelement(1, "i", 37);
|
|
282
|
+
i0.ɵɵtext(2);
|
|
283
|
+
i0.ɵɵelementEnd();
|
|
284
|
+
} if (rf & 2) {
|
|
285
|
+
const query_r13 = i0.ɵɵnextContext().$implicit;
|
|
286
|
+
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
287
|
+
i0.ɵɵadvance(2);
|
|
288
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r1.getCategoryName(query_r13.CategoryID), " ");
|
|
289
|
+
} }
|
|
290
|
+
function QueryBrowserComponent_Conditional_34_Conditional_1_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
291
|
+
const _r12 = i0.ɵɵgetCurrentView();
|
|
292
|
+
i0.ɵɵelementStart(0, "div", 74);
|
|
293
|
+
i0.ɵɵlistener("click", function QueryBrowserComponent_Conditional_34_Conditional_1_For_2_Template_div_click_0_listener() { const query_r13 = i0.ɵɵrestoreView(_r12).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.selectQuery(query_r13)); });
|
|
294
|
+
i0.ɵɵelementStart(1, "div", 75)(2, "div", 76);
|
|
295
|
+
i0.ɵɵelement(3, "i", 50);
|
|
296
|
+
i0.ɵɵtext(4);
|
|
297
|
+
i0.ɵɵelementEnd();
|
|
298
|
+
i0.ɵɵelementStart(5, "span", 66);
|
|
299
|
+
i0.ɵɵtext(6);
|
|
300
|
+
i0.ɵɵelementEnd()();
|
|
301
|
+
i0.ɵɵtemplate(7, QueryBrowserComponent_Conditional_34_Conditional_1_For_2_Conditional_7_Template, 2, 1, "div", 77);
|
|
302
|
+
i0.ɵɵelementStart(8, "div", 78)(9, "div", 79);
|
|
303
|
+
i0.ɵɵtext(10, "SQL Preview:");
|
|
304
|
+
i0.ɵɵelementEnd();
|
|
305
|
+
i0.ɵɵelementStart(11, "pre", 80);
|
|
306
|
+
i0.ɵɵtext(12);
|
|
307
|
+
i0.ɵɵelementEnd()();
|
|
308
|
+
i0.ɵɵelementStart(13, "div", 81)(14, "div", 82);
|
|
309
|
+
i0.ɵɵtemplate(15, QueryBrowserComponent_Conditional_34_Conditional_1_For_2_Conditional_15_Template, 3, 1, "span", 83);
|
|
310
|
+
i0.ɵɵelementStart(16, "span", 83);
|
|
311
|
+
i0.ɵɵelement(17, "i", 84);
|
|
312
|
+
i0.ɵɵtext(18);
|
|
313
|
+
i0.ɵɵelementEnd()();
|
|
314
|
+
i0.ɵɵelementStart(19, "div", 85)(20, "button", 67);
|
|
315
|
+
i0.ɵɵlistener("click", function QueryBrowserComponent_Conditional_34_Conditional_1_For_2_Template_button_click_20_listener($event) { const query_r13 = i0.ɵɵrestoreView(_r12).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.runQuery(query_r13, $event)); });
|
|
316
|
+
i0.ɵɵelement(21, "i", 68);
|
|
317
|
+
i0.ɵɵelementEnd()()()();
|
|
318
|
+
} if (rf & 2) {
|
|
319
|
+
const query_r13 = ctx.$implicit;
|
|
320
|
+
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
321
|
+
i0.ɵɵclassProp("selected", (ctx_r1.selectedQuery == null ? null : ctx_r1.selectedQuery.ID) === query_r13.ID);
|
|
322
|
+
i0.ɵɵadvance(4);
|
|
323
|
+
i0.ɵɵtextInterpolate1(" ", query_r13.Name, " ");
|
|
324
|
+
i0.ɵɵadvance();
|
|
325
|
+
i0.ɵɵclassMap("status-" + (query_r13.Status || "pending").toLowerCase());
|
|
326
|
+
i0.ɵɵadvance();
|
|
327
|
+
i0.ɵɵtextInterpolate1(" ", query_r13.Status || "Pending", " ");
|
|
328
|
+
i0.ɵɵadvance();
|
|
329
|
+
i0.ɵɵconditional(query_r13.Description ? 7 : -1);
|
|
330
|
+
i0.ɵɵadvance(5);
|
|
331
|
+
i0.ɵɵtextInterpolate(ctx_r1.getQueryPreview(query_r13.SQL));
|
|
332
|
+
i0.ɵɵadvance(3);
|
|
333
|
+
i0.ɵɵconditional(query_r13.CategoryID ? 15 : -1);
|
|
334
|
+
i0.ɵɵadvance(3);
|
|
335
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r1.formatDate(query_r13.__mj_UpdatedAt), " ");
|
|
336
|
+
} }
|
|
337
|
+
function QueryBrowserComponent_Conditional_34_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
338
|
+
i0.ɵɵelementStart(0, "div", 72);
|
|
339
|
+
i0.ɵɵrepeaterCreate(1, QueryBrowserComponent_Conditional_34_Conditional_1_For_2_Template, 22, 10, "div", 73, _forTrack1);
|
|
340
|
+
i0.ɵɵelementEnd();
|
|
341
|
+
} if (rf & 2) {
|
|
342
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
343
|
+
i0.ɵɵadvance();
|
|
344
|
+
i0.ɵɵrepeater(ctx_r1.filteredQueries);
|
|
345
|
+
} }
|
|
346
|
+
function QueryBrowserComponent_Conditional_34_Conditional_2_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
347
|
+
i0.ɵɵelementStart(0, "p", 71);
|
|
348
|
+
i0.ɵɵtext(1, "Try adjusting your filters");
|
|
349
|
+
i0.ɵɵelementEnd();
|
|
350
|
+
} }
|
|
351
|
+
function QueryBrowserComponent_Conditional_34_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
352
|
+
i0.ɵɵelementStart(0, "div", 34);
|
|
353
|
+
i0.ɵɵelement(1, "i", 15);
|
|
354
|
+
i0.ɵɵelementStart(2, "p");
|
|
355
|
+
i0.ɵɵtext(3, "No queries to display");
|
|
356
|
+
i0.ɵɵelementEnd();
|
|
357
|
+
i0.ɵɵtemplate(4, QueryBrowserComponent_Conditional_34_Conditional_2_Conditional_4_Template, 2, 0, "p", 71);
|
|
358
|
+
i0.ɵɵelementEnd();
|
|
359
|
+
} if (rf & 2) {
|
|
360
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
361
|
+
i0.ɵɵadvance(4);
|
|
362
|
+
i0.ɵɵconditional(ctx_r1.searchText || ctx_r1.selectedStatus !== "all" ? 4 : -1);
|
|
363
|
+
} }
|
|
364
|
+
function QueryBrowserComponent_Conditional_34_Template(rf, ctx) { if (rf & 1) {
|
|
365
|
+
i0.ɵɵelementStart(0, "div", 26);
|
|
366
|
+
i0.ɵɵtemplate(1, QueryBrowserComponent_Conditional_34_Conditional_1_Template, 3, 0, "div", 72)(2, QueryBrowserComponent_Conditional_34_Conditional_2_Template, 5, 1, "div", 34);
|
|
367
|
+
i0.ɵɵelementEnd();
|
|
368
|
+
} if (rf & 2) {
|
|
369
|
+
const ctx_r1 = i0.ɵɵnextContext();
|
|
370
|
+
i0.ɵɵadvance();
|
|
371
|
+
i0.ɵɵconditional(ctx_r1.filteredQueries.length > 0 ? 1 : 2);
|
|
372
|
+
} }
|
|
373
|
+
let QueryBrowserComponent = class QueryBrowserComponent extends BaseNavigationComponent {
|
|
18
374
|
router;
|
|
19
375
|
route;
|
|
20
376
|
sharedService;
|
|
21
|
-
|
|
377
|
+
// View mode state
|
|
378
|
+
viewMode = 'list';
|
|
379
|
+
// Data
|
|
380
|
+
allQueries = [];
|
|
381
|
+
allCategories = [];
|
|
382
|
+
filteredQueries = [];
|
|
383
|
+
filteredCategories = [];
|
|
384
|
+
// Selection state
|
|
385
|
+
selectedQuery = null;
|
|
386
|
+
currentCategoryId = null;
|
|
387
|
+
currentCategoryPath = [];
|
|
388
|
+
// Filter state
|
|
389
|
+
searchText = '';
|
|
390
|
+
selectedStatus = 'all';
|
|
391
|
+
selectedSort = 'updated-desc';
|
|
392
|
+
activeFilters = [];
|
|
393
|
+
// Loading state
|
|
394
|
+
isLoading = false;
|
|
395
|
+
// Category counts cache
|
|
396
|
+
categoryCounts = new Map();
|
|
397
|
+
// Options for dropdowns
|
|
398
|
+
statusOptions = [
|
|
399
|
+
{ text: 'All Statuses', value: 'all' },
|
|
400
|
+
{ text: 'Pending', value: 'Pending' },
|
|
401
|
+
{ text: 'Approved', value: 'Approved' },
|
|
402
|
+
{ text: 'Rejected', value: 'Rejected' },
|
|
403
|
+
{ text: 'Expired', value: 'Expired' }
|
|
404
|
+
];
|
|
405
|
+
sortOptions = [
|
|
406
|
+
{ text: 'Name (A-Z)', value: 'name-asc' },
|
|
407
|
+
{ text: 'Name (Z-A)', value: 'name-desc' },
|
|
408
|
+
{ text: 'Recently Updated', value: 'updated-desc' },
|
|
409
|
+
{ text: 'Oldest Updated', value: 'updated-asc' },
|
|
410
|
+
{ text: 'Status', value: 'status' }
|
|
411
|
+
];
|
|
412
|
+
// Search debouncing
|
|
413
|
+
searchSubject = new Subject();
|
|
414
|
+
destroy$ = new Subject();
|
|
22
415
|
constructor(router, route, sharedService) {
|
|
23
416
|
super();
|
|
24
417
|
this.router = router;
|
|
25
418
|
this.route = route;
|
|
26
419
|
this.sharedService = sharedService;
|
|
27
|
-
this.pageName = "Queries";
|
|
28
|
-
this.routeName = "queries";
|
|
29
|
-
this.routeNameSingular = "query";
|
|
30
|
-
this.itemEntityName = "Queries";
|
|
31
|
-
this.categoryEntityName = "Query Categories";
|
|
32
|
-
const params = this.router.getCurrentNavigation()?.extractedUrl.queryParams;
|
|
33
|
-
super.InitPathAndQueryData(params, this.route);
|
|
34
420
|
}
|
|
35
421
|
async ngOnInit() {
|
|
36
|
-
//
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
this.
|
|
422
|
+
// Set up search debouncing
|
|
423
|
+
this.searchSubject
|
|
424
|
+
.pipe(debounceTime(300), takeUntil(this.destroy$))
|
|
425
|
+
.subscribe(searchText => {
|
|
426
|
+
this.performSearch(searchText);
|
|
427
|
+
});
|
|
428
|
+
// Load initial data
|
|
429
|
+
await this.loadData();
|
|
430
|
+
// Check for view mode from route params
|
|
431
|
+
this.route.queryParams.subscribe(params => {
|
|
432
|
+
if (params['view'] && ['category', 'list', 'panel'].includes(params['view'])) {
|
|
433
|
+
this.viewMode = params['view'];
|
|
434
|
+
// Reapply filters when view mode changes from route
|
|
435
|
+
this.applyFilters();
|
|
436
|
+
}
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
ngOnDestroy() {
|
|
440
|
+
this.destroy$.next();
|
|
441
|
+
this.destroy$.complete();
|
|
442
|
+
}
|
|
443
|
+
async loadData() {
|
|
444
|
+
this.isLoading = true;
|
|
445
|
+
try {
|
|
41
446
|
const md = new Metadata();
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
447
|
+
const rv = new RunView();
|
|
448
|
+
// Load queries and categories in parallel
|
|
449
|
+
const [queriesResult, categoriesResult] = await Promise.all([
|
|
450
|
+
rv.RunView({
|
|
451
|
+
EntityName: 'Queries',
|
|
452
|
+
OrderBy: '__mj_UpdatedAt DESC',
|
|
453
|
+
ResultType: 'entity_object'
|
|
454
|
+
}),
|
|
455
|
+
rv.RunView({
|
|
456
|
+
EntityName: 'Query Categories',
|
|
457
|
+
OrderBy: 'Name',
|
|
458
|
+
ResultType: 'entity_object'
|
|
459
|
+
})
|
|
460
|
+
]);
|
|
461
|
+
if (queriesResult.Success) {
|
|
462
|
+
this.allQueries = queriesResult.Results || [];
|
|
463
|
+
}
|
|
464
|
+
if (categoriesResult.Success) {
|
|
465
|
+
this.allCategories = categoriesResult.Results || [];
|
|
466
|
+
this.calculateCategoryCounts();
|
|
467
|
+
}
|
|
468
|
+
// Apply initial filters
|
|
469
|
+
this.applyFilters();
|
|
470
|
+
}
|
|
471
|
+
catch (error) {
|
|
472
|
+
console.error('Error loading data:', error);
|
|
473
|
+
this.sharedService.CreateSimpleNotification('Error loading queries', 'error', 3000);
|
|
474
|
+
}
|
|
475
|
+
finally {
|
|
476
|
+
this.isLoading = false;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
calculateCategoryCounts() {
|
|
480
|
+
// Count queries per category
|
|
481
|
+
const counts = new Map();
|
|
482
|
+
for (const query of this.allQueries) {
|
|
483
|
+
if (query.CategoryID) {
|
|
484
|
+
const current = counts.get(query.CategoryID) || 0;
|
|
485
|
+
counts.set(query.CategoryID, current + 1);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
// Count queries recursively for each category (including subcategories)
|
|
489
|
+
const getRecursiveCount = (categoryId) => {
|
|
490
|
+
let count = counts.get(categoryId) || 0;
|
|
491
|
+
// Add counts from all child categories
|
|
492
|
+
const children = this.allCategories.filter(c => c.ParentID === categoryId);
|
|
493
|
+
for (const child of children) {
|
|
494
|
+
count += getRecursiveCount(child.ID);
|
|
495
|
+
}
|
|
496
|
+
return count;
|
|
497
|
+
};
|
|
498
|
+
// Don't set filteredCategories here - let applyFilters handle it
|
|
499
|
+
// Just store the counts for later use
|
|
500
|
+
this.categoryCounts = new Map();
|
|
501
|
+
for (const cat of this.allCategories) {
|
|
502
|
+
this.categoryCounts.set(cat.ID, getRecursiveCount(cat.ID));
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
setViewMode(mode) {
|
|
506
|
+
this.viewMode = mode;
|
|
507
|
+
// Update URL with view mode
|
|
508
|
+
this.router.navigate([], {
|
|
509
|
+
relativeTo: this.route,
|
|
510
|
+
queryParams: { view: mode },
|
|
511
|
+
queryParamsHandling: 'merge'
|
|
512
|
+
});
|
|
513
|
+
// Reapply filters to update the view
|
|
514
|
+
this.applyFilters();
|
|
515
|
+
}
|
|
516
|
+
onSearchChange(searchText) {
|
|
517
|
+
this.searchSubject.next(searchText);
|
|
518
|
+
}
|
|
519
|
+
performSearch(searchText) {
|
|
520
|
+
this.searchText = searchText;
|
|
521
|
+
this.applyFilters();
|
|
522
|
+
}
|
|
523
|
+
// New clean filter/sort handlers
|
|
524
|
+
getSelectedStatusOption() {
|
|
525
|
+
return this.statusOptions.find(opt => opt.value === this.selectedStatus) || this.statusOptions[0];
|
|
526
|
+
}
|
|
527
|
+
getSelectedSortOption() {
|
|
528
|
+
return this.sortOptions.find(opt => opt.value === this.selectedSort) || this.sortOptions[2];
|
|
529
|
+
}
|
|
530
|
+
handleStatusChange(option) {
|
|
531
|
+
if (option && option.value !== undefined) {
|
|
532
|
+
this.selectedStatus = option.value;
|
|
533
|
+
this.applyFilters();
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
handleSortChange(option) {
|
|
537
|
+
if (option && option.value !== undefined) {
|
|
538
|
+
this.selectedSort = option.value;
|
|
539
|
+
this.applySortAndFilter();
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
hasActiveFilters() {
|
|
543
|
+
return this.searchText !== '' || this.selectedStatus !== 'all';
|
|
544
|
+
}
|
|
545
|
+
clearAllFilters() {
|
|
546
|
+
this.searchText = '';
|
|
547
|
+
this.selectedStatus = 'all';
|
|
548
|
+
this.applyFilters();
|
|
549
|
+
}
|
|
550
|
+
applyFilters() {
|
|
551
|
+
// Start with all queries
|
|
552
|
+
let filtered = [...this.allQueries];
|
|
553
|
+
// Clear active filters tracking
|
|
554
|
+
this.activeFilters = [];
|
|
555
|
+
// 1. Apply search filter if present
|
|
556
|
+
if (this.searchText && this.searchText.trim() !== '') {
|
|
557
|
+
const searchLower = this.searchText.toLowerCase().trim();
|
|
558
|
+
filtered = filtered.filter(q => {
|
|
559
|
+
const nameMatch = q.Name?.toLowerCase().includes(searchLower) || false;
|
|
560
|
+
const descMatch = q.Description?.toLowerCase().includes(searchLower) || false;
|
|
561
|
+
const sqlMatch = q.SQL?.toLowerCase().includes(searchLower) || false;
|
|
562
|
+
return nameMatch || descMatch || sqlMatch;
|
|
50
563
|
});
|
|
564
|
+
this.activeFilters.push(`Search: ${this.searchText}`);
|
|
565
|
+
}
|
|
566
|
+
// 2. Apply status filter if not "all"
|
|
567
|
+
if (this.selectedStatus && this.selectedStatus !== 'all') {
|
|
568
|
+
filtered = filtered.filter(q => q.Status === this.selectedStatus);
|
|
569
|
+
this.activeFilters.push(`Status: ${this.selectedStatus}`);
|
|
570
|
+
}
|
|
571
|
+
// 3. Apply category-based filtering in category view mode
|
|
572
|
+
if (this.viewMode === 'category') {
|
|
573
|
+
filtered = filtered.filter(q => {
|
|
574
|
+
if (this.currentCategoryId === null) {
|
|
575
|
+
// At root: show only queries without a category
|
|
576
|
+
return !q.CategoryID || q.CategoryID === null || q.CategoryID === '';
|
|
577
|
+
}
|
|
578
|
+
else {
|
|
579
|
+
// Inside a category: show only queries in this specific category
|
|
580
|
+
return q.CategoryID === this.currentCategoryId;
|
|
581
|
+
}
|
|
582
|
+
});
|
|
583
|
+
}
|
|
584
|
+
// Set the filtered queries
|
|
585
|
+
this.filteredQueries = filtered;
|
|
586
|
+
// Update categories for category view
|
|
587
|
+
this.updateFilteredCategories();
|
|
588
|
+
// Apply sorting to the filtered results
|
|
589
|
+
this.applySort();
|
|
590
|
+
}
|
|
591
|
+
updateFilteredCategories() {
|
|
592
|
+
// Filter categories based on current parent
|
|
593
|
+
let filtered = this.allCategories.filter(cat => {
|
|
594
|
+
if (this.currentCategoryId === null) {
|
|
595
|
+
// At root: show categories with no parent
|
|
596
|
+
return !cat.ParentID;
|
|
597
|
+
}
|
|
598
|
+
else {
|
|
599
|
+
// In a category: show child categories
|
|
600
|
+
return cat.ParentID === this.currentCategoryId;
|
|
601
|
+
}
|
|
602
|
+
});
|
|
603
|
+
// Apply search to categories if in category mode
|
|
604
|
+
if (this.searchText && this.viewMode === 'category') {
|
|
605
|
+
const search = this.searchText.toLowerCase();
|
|
606
|
+
filtered = filtered.filter(cat => cat.Name?.toLowerCase().includes(search) ||
|
|
607
|
+
cat.Description?.toLowerCase().includes(search));
|
|
608
|
+
}
|
|
609
|
+
// Convert to CategoryWithCount and use cached counts
|
|
610
|
+
this.filteredCategories = filtered.map(cat => {
|
|
611
|
+
const count = this.categoryCounts.get(cat.ID) || 0;
|
|
612
|
+
return {
|
|
613
|
+
...cat.GetAll(), // Use GetAll() to get plain object with all properties
|
|
614
|
+
QueryCount: count
|
|
615
|
+
};
|
|
616
|
+
});
|
|
617
|
+
}
|
|
618
|
+
applySort() {
|
|
619
|
+
// Create a copy to avoid mutation issues
|
|
620
|
+
const queries = [...this.filteredQueries];
|
|
621
|
+
switch (this.selectedSort) {
|
|
622
|
+
case 'name-asc':
|
|
623
|
+
queries.sort((a, b) => {
|
|
624
|
+
const nameA = a.Name || '';
|
|
625
|
+
const nameB = b.Name || '';
|
|
626
|
+
return nameA.localeCompare(nameB);
|
|
627
|
+
});
|
|
628
|
+
break;
|
|
629
|
+
case 'name-desc':
|
|
630
|
+
queries.sort((a, b) => {
|
|
631
|
+
const nameA = a.Name || '';
|
|
632
|
+
const nameB = b.Name || '';
|
|
633
|
+
return nameB.localeCompare(nameA);
|
|
634
|
+
});
|
|
635
|
+
break;
|
|
636
|
+
case 'updated-desc':
|
|
637
|
+
queries.sort((a, b) => {
|
|
638
|
+
const dateA = a.__mj_UpdatedAt ? new Date(a.__mj_UpdatedAt).getTime() : 0;
|
|
639
|
+
const dateB = b.__mj_UpdatedAt ? new Date(b.__mj_UpdatedAt).getTime() : 0;
|
|
640
|
+
return dateB - dateA;
|
|
641
|
+
});
|
|
642
|
+
break;
|
|
643
|
+
case 'updated-asc':
|
|
644
|
+
queries.sort((a, b) => {
|
|
645
|
+
const dateA = a.__mj_UpdatedAt ? new Date(a.__mj_UpdatedAt).getTime() : 0;
|
|
646
|
+
const dateB = b.__mj_UpdatedAt ? new Date(b.__mj_UpdatedAt).getTime() : 0;
|
|
647
|
+
return dateA - dateB;
|
|
648
|
+
});
|
|
649
|
+
break;
|
|
650
|
+
case 'status':
|
|
651
|
+
queries.sort((a, b) => {
|
|
652
|
+
const statusA = a.Status || 'Pending';
|
|
653
|
+
const statusB = b.Status || 'Pending';
|
|
654
|
+
return statusA.localeCompare(statusB);
|
|
655
|
+
});
|
|
656
|
+
break;
|
|
657
|
+
default:
|
|
658
|
+
// Default to recent updates
|
|
659
|
+
queries.sort((a, b) => {
|
|
660
|
+
const dateA = a.__mj_UpdatedAt ? new Date(a.__mj_UpdatedAt).getTime() : 0;
|
|
661
|
+
const dateB = b.__mj_UpdatedAt ? new Date(b.__mj_UpdatedAt).getTime() : 0;
|
|
662
|
+
return dateB - dateA;
|
|
663
|
+
});
|
|
664
|
+
break;
|
|
665
|
+
}
|
|
666
|
+
// Assign the sorted array
|
|
667
|
+
this.filteredQueries = queries;
|
|
668
|
+
}
|
|
669
|
+
// Helper to apply both sort and filter
|
|
670
|
+
applySortAndFilter() {
|
|
671
|
+
this.applyFilters(); // This calls applySort internally
|
|
672
|
+
}
|
|
673
|
+
navigateToRoot() {
|
|
674
|
+
this.currentCategoryId = null;
|
|
675
|
+
this.currentCategoryPath = [];
|
|
676
|
+
this.applyFilters();
|
|
677
|
+
}
|
|
678
|
+
navigateToCategory(categoryId) {
|
|
679
|
+
if (categoryId === null) {
|
|
680
|
+
this.navigateToRoot();
|
|
681
|
+
return;
|
|
682
|
+
}
|
|
683
|
+
this.currentCategoryId = categoryId;
|
|
684
|
+
this.buildBreadcrumb(categoryId);
|
|
685
|
+
this.applyFilters();
|
|
686
|
+
}
|
|
687
|
+
buildBreadcrumb(categoryId) {
|
|
688
|
+
const path = [];
|
|
689
|
+
let currentId = categoryId;
|
|
690
|
+
while (currentId) {
|
|
691
|
+
const category = this.allCategories.find(c => c.ID === currentId);
|
|
692
|
+
if (category) {
|
|
693
|
+
path.unshift({
|
|
694
|
+
id: category.ID,
|
|
695
|
+
name: category.Name
|
|
696
|
+
});
|
|
697
|
+
currentId = category.ParentID;
|
|
698
|
+
}
|
|
699
|
+
else {
|
|
700
|
+
break;
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
this.currentCategoryPath = path;
|
|
704
|
+
}
|
|
705
|
+
selectQuery(query) {
|
|
706
|
+
// Strip quotes from ID if present
|
|
707
|
+
let queryId = query.ID;
|
|
708
|
+
if (queryId && typeof queryId === 'string') {
|
|
709
|
+
queryId = queryId.replace(/^['"]|['"]$/g, '');
|
|
710
|
+
}
|
|
711
|
+
// Navigate to the entity form using the resource/record pattern
|
|
712
|
+
// Format: /resource/record/ID|{queryId}?Entity=Queries
|
|
713
|
+
const routeSegment = `ID|${queryId}`;
|
|
714
|
+
this.router.navigate(['resource', 'record', routeSegment], {
|
|
715
|
+
queryParams: {
|
|
716
|
+
Entity: 'Queries',
|
|
717
|
+
viewMode: this.viewMode // Preserve the current view mode
|
|
718
|
+
}
|
|
719
|
+
});
|
|
720
|
+
}
|
|
721
|
+
async runQuery(query, event) {
|
|
722
|
+
event.stopPropagation();
|
|
723
|
+
let queryId = query.ID;
|
|
724
|
+
if (queryId && typeof queryId === 'string') {
|
|
725
|
+
queryId = queryId.replace(/^['\"]|['\"]$/g, '');
|
|
726
|
+
}
|
|
727
|
+
// Navigate to the query form with run=true parameter
|
|
728
|
+
// This will trigger the run dialog in the query form component
|
|
729
|
+
const routeSegment = `ID|${queryId}`;
|
|
730
|
+
this.router.navigate(['resource', 'record', routeSegment], {
|
|
731
|
+
queryParams: {
|
|
732
|
+
Entity: 'Queries',
|
|
733
|
+
run: 'true' // This will trigger the run dialog to open
|
|
734
|
+
}
|
|
51
735
|
});
|
|
52
736
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
let
|
|
60
|
-
|
|
737
|
+
async deleteQuery(query, event) {
|
|
738
|
+
event.stopPropagation();
|
|
739
|
+
if (!confirm(`Are you sure you want to delete "${query.Name}"?`)) {
|
|
740
|
+
return;
|
|
741
|
+
}
|
|
742
|
+
try {
|
|
743
|
+
let result = false;
|
|
744
|
+
// First try to delete directly if the query has a Delete method
|
|
745
|
+
if (query && typeof query.Delete === 'function') {
|
|
746
|
+
result = await query.Delete();
|
|
747
|
+
}
|
|
748
|
+
else {
|
|
749
|
+
// If not, load the entity properly and then delete
|
|
750
|
+
const md = new Metadata();
|
|
751
|
+
const queryEntity = await md.GetEntityObject('Queries');
|
|
752
|
+
// Load the existing record
|
|
753
|
+
const loaded = await queryEntity.Load(query.ID);
|
|
754
|
+
if (!loaded) {
|
|
755
|
+
this.sharedService.CreateSimpleNotification('Query not found', 'error', 3000);
|
|
756
|
+
return;
|
|
757
|
+
}
|
|
758
|
+
// Now delete the loaded entity
|
|
759
|
+
result = await queryEntity.Delete();
|
|
760
|
+
}
|
|
761
|
+
if (result) {
|
|
762
|
+
this.sharedService.CreateSimpleNotification('Query deleted successfully', 'success', 3000);
|
|
763
|
+
await this.loadData();
|
|
764
|
+
}
|
|
765
|
+
else {
|
|
766
|
+
// Check if there's a specific error message
|
|
767
|
+
const errorMsg = query.LatestResult?.Message || 'Failed to delete query';
|
|
768
|
+
this.sharedService.CreateSimpleNotification(errorMsg, 'error', 5000);
|
|
769
|
+
console.error('Delete failed:', query.LatestResult);
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
catch (error) {
|
|
773
|
+
console.error('Error deleting query:', error);
|
|
774
|
+
const errorMessage = error instanceof Error ? error.message : 'Error deleting query';
|
|
775
|
+
this.sharedService.CreateSimpleNotification(errorMessage, 'error', 5000);
|
|
61
776
|
}
|
|
62
|
-
super.Navigate(item, this.router, dataID);
|
|
63
777
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
778
|
+
async createNewQuery() {
|
|
779
|
+
// Navigate to the query form with an empty primary key for new record
|
|
780
|
+
// Using empty string as the third parameter to match MJ's convention
|
|
781
|
+
const queryParams = {
|
|
782
|
+
Entity: 'Queries'
|
|
783
|
+
};
|
|
784
|
+
// Include category context if we're in category view
|
|
785
|
+
// This can be used to pre-populate the CategoryID field
|
|
786
|
+
if (this.viewMode === 'category' && this.currentCategoryId) {
|
|
787
|
+
// Pass initial field values in query params
|
|
788
|
+
queryParams.NewRecordValues = `CategoryID|${this.currentCategoryId}`;
|
|
789
|
+
}
|
|
790
|
+
// Navigate with empty string as third param for new record
|
|
791
|
+
this.router.navigate(['resource', 'record', ''], // Empty string indicates new record
|
|
792
|
+
{ queryParams });
|
|
793
|
+
}
|
|
794
|
+
getCategoryName(categoryId) {
|
|
795
|
+
if (!categoryId)
|
|
796
|
+
return '';
|
|
797
|
+
const category = this.allCategories.find(c => c.ID === categoryId);
|
|
798
|
+
return category?.Name || '';
|
|
799
|
+
}
|
|
800
|
+
formatDate(date) {
|
|
801
|
+
if (!date)
|
|
802
|
+
return '-';
|
|
803
|
+
const d = typeof date === 'string' ? new Date(date) : date;
|
|
804
|
+
if (isNaN(d.getTime()))
|
|
805
|
+
return '-';
|
|
806
|
+
// Format as MM/DD/YYYY HH:MM
|
|
807
|
+
return d.toLocaleDateString() + ' ' + d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
|
|
808
|
+
}
|
|
809
|
+
getQueryPreview(sql) {
|
|
810
|
+
if (!sql)
|
|
811
|
+
return 'No SQL query defined';
|
|
812
|
+
// Get first 3 lines or 150 characters, whichever is shorter
|
|
813
|
+
const lines = sql.split('\n').slice(0, 3);
|
|
814
|
+
let preview = lines.join('\n');
|
|
815
|
+
if (preview.length > 150) {
|
|
816
|
+
preview = preview.substring(0, 150) + '...';
|
|
817
|
+
}
|
|
818
|
+
else if (sql.length > preview.length) {
|
|
819
|
+
preview += '\n...';
|
|
820
|
+
}
|
|
821
|
+
return preview;
|
|
69
822
|
}
|
|
70
823
|
static ɵfac = function QueryBrowserComponent_Factory(t) { return new (t || QueryBrowserComponent)(i0.ɵɵdirectiveInject(i1.Router), i0.ɵɵdirectiveInject(i1.ActivatedRoute), i0.ɵɵdirectiveInject(i2.SharedService)); };
|
|
71
|
-
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: QueryBrowserComponent, selectors: [["mj-query-browser"]], features: [i0.ɵɵInheritDefinitionFeature], decls:
|
|
72
|
-
|
|
73
|
-
i0.ɵɵ
|
|
74
|
-
i0.ɵɵ
|
|
824
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: QueryBrowserComponent, selectors: [["mj-query-browser"]], features: [i0.ɵɵInheritDefinitionFeature], decls: 35, vars: 22, consts: [[1, "query-browser-container"], [1, "query-browser-header"], [1, "header-left"], [1, "page-title"], [1, "fa-solid", "fa-database"], [1, "header-right"], [1, "search-container"], [1, "fa-solid", "fa-search", "search-icon"], ["type", "text", "placeholder", "Search queries...", 1, "search-input", 3, "ngModelChange", "ngModel"], [1, "view-mode-toggles"], ["title", "Category View", 1, "view-mode-btn", 3, "click"], [1, "fa-solid", "fa-folder-tree"], ["title", "List View", 1, "view-mode-btn", 3, "click"], [1, "fa-solid", "fa-list"], ["title", "Panel View", 1, "view-mode-btn", 3, "click"], [1, "fa-solid", "fa-grip"], [1, "btn", "btn-primary", "create-query-btn", 3, "click"], [1, "fa-solid", "fa-plus"], [1, "filter-bar"], [1, "filter-group"], ["textField", "text", "valueField", "value", 3, "valueChange", "data", "value"], [1, "clear-filters-btn"], [1, "loading-container"], [1, "query-browser-content"], [1, "category-view"], [1, "list-view"], [1, "panel-view"], [1, "clear-filters-btn", 3, "click"], [1, "fa-solid", "fa-times"], [1, "fa-solid", "fa-spinner", "fa-spin"], [1, "breadcrumb"], [1, "breadcrumb-item", 3, "click"], [1, "category-folders"], [1, "category-queries"], [1, "empty-state"], [1, "fa-solid", "fa-chevron-right", "breadcrumb-separator"], [1, "section-title"], [1, "fa-solid", "fa-folder"], [1, "folder-grid"], [1, "folder-item", 3, "title"], [1, "folder-item", 3, "click", "title"], [1, "fa-solid", "fa-folder", "folder-icon"], [1, "folder-name"], [1, "item-count"], [1, "fa-solid", "fa-file-code"], [1, "count"], [1, "query-list"], [1, "query-list-item", 3, "selected"], [1, "query-list-item", 3, "click"], [1, "query-icon"], [1, "fa-solid", "fa-code"], [1, "query-info"], [1, "query-name"], [1, "query-description"], [1, "query-status"], [1, "fa-solid", "fa-folder-open"], [1, "list-header"], [1, "col-name"], [1, "col-description"], [1, "col-category"], [1, "col-status"], [1, "col-updated"], [1, "col-actions"], [1, "list-body"], [1, "list-row", 3, "selected"], [1, "list-row", 3, "click"], [1, "status-badge"], ["title", "Run", 1, "action-btn", 3, "click"], [1, "fa-solid", "fa-play"], ["title", "Delete", 1, "action-btn", "danger", 3, "click"], [1, "fa-solid", "fa-trash"], [1, "empty-hint"], [1, "panel-grid"], [1, "query-panel", 3, "selected"], [1, "query-panel", 3, "click"], [1, "panel-header"], [1, "panel-title"], [1, "panel-description"], [1, "panel-sql-preview"], [1, "sql-label"], [1, "sql-code"], [1, "panel-footer"], [1, "panel-meta"], [1, "meta-item"], [1, "fa-solid", "fa-clock"], [1, "panel-actions"]], template: function QueryBrowserComponent_Template(rf, ctx) { if (rf & 1) {
|
|
825
|
+
i0.ɵɵelementStart(0, "div", 0)(1, "div", 1)(2, "div", 2)(3, "h2", 3);
|
|
826
|
+
i0.ɵɵelement(4, "i", 4);
|
|
827
|
+
i0.ɵɵtext(5, " Queries ");
|
|
828
|
+
i0.ɵɵelementEnd()();
|
|
829
|
+
i0.ɵɵelementStart(6, "div", 5)(7, "div", 6);
|
|
830
|
+
i0.ɵɵelement(8, "i", 7);
|
|
831
|
+
i0.ɵɵelementStart(9, "input", 8);
|
|
832
|
+
i0.ɵɵtwoWayListener("ngModelChange", function QueryBrowserComponent_Template_input_ngModelChange_9_listener($event) { i0.ɵɵtwoWayBindingSet(ctx.searchText, $event) || (ctx.searchText = $event); return $event; });
|
|
833
|
+
i0.ɵɵlistener("ngModelChange", function QueryBrowserComponent_Template_input_ngModelChange_9_listener($event) { return ctx.onSearchChange($event); });
|
|
834
|
+
i0.ɵɵelementEnd()();
|
|
835
|
+
i0.ɵɵelementStart(10, "div", 9)(11, "button", 10);
|
|
836
|
+
i0.ɵɵlistener("click", function QueryBrowserComponent_Template_button_click_11_listener() { return ctx.setViewMode("category"); });
|
|
837
|
+
i0.ɵɵelement(12, "i", 11);
|
|
838
|
+
i0.ɵɵelementEnd();
|
|
839
|
+
i0.ɵɵelementStart(13, "button", 12);
|
|
840
|
+
i0.ɵɵlistener("click", function QueryBrowserComponent_Template_button_click_13_listener() { return ctx.setViewMode("list"); });
|
|
841
|
+
i0.ɵɵelement(14, "i", 13);
|
|
842
|
+
i0.ɵɵelementEnd();
|
|
843
|
+
i0.ɵɵelementStart(15, "button", 14);
|
|
844
|
+
i0.ɵɵlistener("click", function QueryBrowserComponent_Template_button_click_15_listener() { return ctx.setViewMode("panel"); });
|
|
845
|
+
i0.ɵɵelement(16, "i", 15);
|
|
846
|
+
i0.ɵɵelementEnd()();
|
|
847
|
+
i0.ɵɵelementStart(17, "button", 16);
|
|
848
|
+
i0.ɵɵlistener("click", function QueryBrowserComponent_Template_button_click_17_listener() { return ctx.createNewQuery(); });
|
|
849
|
+
i0.ɵɵelement(18, "i", 17);
|
|
850
|
+
i0.ɵɵtext(19, " New Query ");
|
|
851
|
+
i0.ɵɵelementEnd()()();
|
|
852
|
+
i0.ɵɵelementStart(20, "div", 18)(21, "div", 19)(22, "label");
|
|
853
|
+
i0.ɵɵtext(23, "Status:");
|
|
854
|
+
i0.ɵɵelementEnd();
|
|
855
|
+
i0.ɵɵelementStart(24, "kendo-dropdownlist", 20);
|
|
856
|
+
i0.ɵɵlistener("valueChange", function QueryBrowserComponent_Template_kendo_dropdownlist_valueChange_24_listener($event) { return ctx.handleStatusChange($event); });
|
|
857
|
+
i0.ɵɵelementEnd()();
|
|
858
|
+
i0.ɵɵelementStart(25, "div", 19)(26, "label");
|
|
859
|
+
i0.ɵɵtext(27, "Sort by:");
|
|
860
|
+
i0.ɵɵelementEnd();
|
|
861
|
+
i0.ɵɵelementStart(28, "kendo-dropdownlist", 20);
|
|
862
|
+
i0.ɵɵlistener("valueChange", function QueryBrowserComponent_Template_kendo_dropdownlist_valueChange_28_listener($event) { return ctx.handleSortChange($event); });
|
|
863
|
+
i0.ɵɵelementEnd()();
|
|
864
|
+
i0.ɵɵtemplate(29, QueryBrowserComponent_Conditional_29_Template, 3, 0, "button", 21);
|
|
75
865
|
i0.ɵɵelementEnd();
|
|
866
|
+
i0.ɵɵtemplate(30, QueryBrowserComponent_Conditional_30_Template, 3, 0, "div", 22);
|
|
867
|
+
i0.ɵɵelementStart(31, "div", 23);
|
|
868
|
+
i0.ɵɵtemplate(32, QueryBrowserComponent_Conditional_32_Template, 9, 3, "div", 24)(33, QueryBrowserComponent_Conditional_33_Template, 3, 1, "div", 25)(34, QueryBrowserComponent_Conditional_34_Template, 3, 1, "div", 26);
|
|
869
|
+
i0.ɵɵelementEnd()();
|
|
76
870
|
} if (rf & 2) {
|
|
77
|
-
i0.ɵɵ
|
|
78
|
-
|
|
871
|
+
i0.ɵɵadvance(9);
|
|
872
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx.searchText);
|
|
873
|
+
i0.ɵɵadvance(2);
|
|
874
|
+
i0.ɵɵclassProp("active", ctx.viewMode === "category");
|
|
875
|
+
i0.ɵɵadvance(2);
|
|
876
|
+
i0.ɵɵclassProp("active", ctx.viewMode === "list");
|
|
877
|
+
i0.ɵɵadvance(2);
|
|
878
|
+
i0.ɵɵclassProp("active", ctx.viewMode === "panel");
|
|
879
|
+
i0.ɵɵadvance(9);
|
|
880
|
+
i0.ɵɵstyleProp("width", 150, "px");
|
|
881
|
+
i0.ɵɵproperty("data", ctx.statusOptions)("value", ctx.getSelectedStatusOption());
|
|
882
|
+
i0.ɵɵadvance(4);
|
|
883
|
+
i0.ɵɵstyleProp("width", 200, "px");
|
|
884
|
+
i0.ɵɵproperty("data", ctx.sortOptions)("value", ctx.getSelectedSortOption());
|
|
885
|
+
i0.ɵɵadvance();
|
|
886
|
+
i0.ɵɵconditional(ctx.hasActiveFilters() ? 29 : -1);
|
|
887
|
+
i0.ɵɵadvance();
|
|
888
|
+
i0.ɵɵconditional(ctx.isLoading ? 30 : -1);
|
|
889
|
+
i0.ɵɵadvance();
|
|
890
|
+
i0.ɵɵclassProp("loading", ctx.isLoading);
|
|
891
|
+
i0.ɵɵadvance();
|
|
892
|
+
i0.ɵɵconditional(ctx.viewMode === "category" && !ctx.isLoading ? 32 : -1);
|
|
893
|
+
i0.ɵɵadvance();
|
|
894
|
+
i0.ɵɵconditional(ctx.viewMode === "list" && !ctx.isLoading ? 33 : -1);
|
|
895
|
+
i0.ɵɵadvance();
|
|
896
|
+
i0.ɵɵconditional(ctx.viewMode === "panel" && !ctx.isLoading ? 34 : -1);
|
|
897
|
+
} }, dependencies: [i3.DefaultValueAccessor, i3.NgControlStatus, i3.NgModel, i4.DropDownListComponent], styles: ["\n\n.query-browser-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: #f5f5f5;\n}\n\n\n\n.query-browser-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 1rem 1.5rem;\n background: white;\n border-bottom: 1px solid #e0e0e0;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);\n}\n\n.header-left[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n}\n\n.page-title[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 1.5rem;\n font-weight: 600;\n color: #333;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n}\n\n.page-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #4a90e2;\n}\n\n.header-right[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 1rem;\n}\n\n\n\n.search-container[_ngcontent-%COMP%] {\n position: relative;\n width: 300px;\n}\n\n.search-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 0.5rem 1rem 0.5rem 2.5rem;\n border: 1px solid #ddd;\n border-radius: 4px;\n font-size: 0.875rem;\n transition: border-color 0.2s;\n}\n\n.search-input[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: #4a90e2;\n box-shadow: 0 0 0 3px rgba(74, 144, 226, 0.1);\n}\n\n.search-icon[_ngcontent-%COMP%] {\n position: absolute;\n left: 0.75rem;\n top: 50%;\n transform: translateY(-50%);\n color: #999;\n font-size: 0.875rem;\n}\n\n\n\n.view-mode-toggles[_ngcontent-%COMP%] {\n display: flex;\n background: #f8f8f8;\n border: 1px solid #ddd;\n border-radius: 4px;\n overflow: hidden;\n}\n\n.view-mode-btn[_ngcontent-%COMP%] {\n padding: 0.5rem 1rem;\n background: transparent;\n border: none;\n color: #666;\n cursor: pointer;\n font-size: 1rem;\n transition: all 0.2s;\n border-right: 1px solid #ddd;\n}\n\n.view-mode-btn[_ngcontent-%COMP%]:last-child {\n border-right: none;\n}\n\n.view-mode-btn[_ngcontent-%COMP%]:hover {\n background: #e8e8e8;\n color: #333;\n}\n\n.view-mode-btn.active[_ngcontent-%COMP%] {\n background: #4a90e2;\n color: white;\n}\n\n\n\n.create-query-btn[_ngcontent-%COMP%] {\n padding: 0.5rem 1rem;\n background: #4a90e2;\n color: white;\n border: none;\n border-radius: 4px;\n font-size: 0.875rem;\n font-weight: 500;\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n transition: background 0.2s;\n}\n\n.create-query-btn[_ngcontent-%COMP%]:hover {\n background: #357abd;\n}\n\n\n\n.filter-bar[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 1.5rem;\n padding: 1rem 1.5rem;\n background: white;\n border-bottom: 1px solid #e0e0e0;\n}\n\n.filter-group[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n}\n\n.filter-group[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\n font-size: 0.875rem;\n font-weight: 500;\n color: #666;\n}\n\n.clear-filters-btn[_ngcontent-%COMP%] {\n margin-left: auto;\n padding: 0.375rem 0.75rem;\n background: #f44336;\n color: white;\n border: none;\n border-radius: 4px;\n font-size: 0.875rem;\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 0.375rem;\n transition: background 0.2s;\n}\n\n.clear-filters-btn[_ngcontent-%COMP%]:hover {\n background: #d32f2f;\n}\n\n\n\n.loading-container[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 0.75rem;\n padding: 3rem;\n color: #666;\n font-size: 1rem;\n}\n\n.loading-container[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 1.25rem;\n color: #4a90e2;\n}\n\n\n\n.query-browser-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow: auto;\n padding: 1.5rem;\n transition: opacity 0.2s;\n}\n\n.query-browser-content.loading[_ngcontent-%COMP%] {\n opacity: 0.5;\n pointer-events: none;\n}\n\n\n\n.category-view[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n}\n\n\n\n.breadcrumb[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.75rem;\n background: white;\n border-radius: 4px;\n font-size: 0.875rem;\n}\n\n.breadcrumb-item[_ngcontent-%COMP%] {\n color: #4a90e2;\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 0.375rem;\n transition: color 0.2s;\n}\n\n.breadcrumb-item[_ngcontent-%COMP%]:hover {\n color: #357abd;\n text-decoration: underline;\n}\n\n.breadcrumb-item.current[_ngcontent-%COMP%] {\n color: #666;\n cursor: default;\n text-decoration: none;\n}\n\n.breadcrumb-separator[_ngcontent-%COMP%] {\n color: #999;\n font-size: 0.75rem;\n}\n\n\n\n.category-folders[_ngcontent-%COMP%] {\n background: white;\n border-radius: 8px;\n padding: 1.5rem;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);\n}\n\n.section-title[_ngcontent-%COMP%] {\n margin: 0 0 1rem 0;\n font-size: 1.125rem;\n font-weight: 600;\n color: #333;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n}\n\n.section-title[_ngcontent-%COMP%] .count[_ngcontent-%COMP%] {\n font-weight: normal;\n color: #666;\n font-size: 0.875rem;\n}\n\n.folder-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));\n gap: 1rem;\n}\n\n.folder-item[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 1.5rem 1rem;\n background: #f8f8f8;\n border: 1px solid #e0e0e0;\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s;\n position: relative;\n}\n\n.folder-item[_ngcontent-%COMP%]:hover {\n background: #e8f4fd;\n border-color: #4a90e2;\n transform: translateY(-2px);\n box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);\n}\n\n.folder-icon[_ngcontent-%COMP%] {\n font-size: 2.5rem;\n color: #ffa726;\n margin-bottom: 0.5rem;\n}\n\n.folder-name[_ngcontent-%COMP%] {\n font-size: 0.875rem;\n font-weight: 500;\n color: #333;\n text-align: center;\n word-break: break-word;\n}\n\n.item-count[_ngcontent-%COMP%] {\n position: absolute;\n top: 0.5rem;\n right: 0.5rem;\n background: #4a90e2;\n color: white;\n font-size: 0.75rem;\n padding: 0.125rem 0.375rem;\n border-radius: 12px;\n min-width: 20px;\n text-align: center;\n}\n\n\n\n.category-queries[_ngcontent-%COMP%] {\n background: white;\n border-radius: 8px;\n padding: 1.5rem;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);\n}\n\n.query-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\n.query-list-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n padding: 1rem;\n background: #f8f8f8;\n border: 1px solid #e0e0e0;\n border-radius: 4px;\n cursor: pointer;\n transition: all 0.2s;\n}\n\n.query-list-item[_ngcontent-%COMP%]:hover {\n background: #e8f4fd;\n border-color: #4a90e2;\n}\n\n.query-list-item.selected[_ngcontent-%COMP%] {\n background: #e3f2fd;\n border-color: #2196f3;\n}\n\n.query-icon[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 40px;\n height: 40px;\n background: white;\n border-radius: 4px;\n margin-right: 1rem;\n color: #4a90e2;\n font-size: 1.25rem;\n}\n\n.query-info[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.query-name[_ngcontent-%COMP%] {\n font-size: 1rem;\n font-weight: 500;\n color: #333;\n margin-bottom: 0.25rem;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.query-description[_ngcontent-%COMP%] {\n font-size: 0.875rem;\n color: #666;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.query-status[_ngcontent-%COMP%] {\n padding: 0.25rem 0.75rem;\n border-radius: 4px;\n font-size: 0.75rem;\n font-weight: 600;\n text-transform: uppercase;\n white-space: nowrap;\n}\n\n\n\n.list-view[_ngcontent-%COMP%] {\n background: white;\n border-radius: 8px;\n overflow: hidden;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);\n}\n\n.list-header[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: 2fr 2fr 1.5fr 1fr 1.5fr 120px;\n padding: 1rem 1.5rem;\n background: #f8f8f8;\n border-bottom: 2px solid #e0e0e0;\n font-size: 0.875rem;\n font-weight: 600;\n color: #666;\n}\n\n.list-body[_ngcontent-%COMP%] {\n max-height: calc(100vh - 300px);\n overflow-y: auto;\n}\n\n.list-row[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: 2fr 2fr 1.5fr 1fr 1.5fr 120px;\n padding: 1rem 1.5rem;\n border-bottom: 1px solid #e0e0e0;\n font-size: 0.875rem;\n cursor: pointer;\n transition: background 0.2s;\n align-items: center;\n}\n\n.list-row[_ngcontent-%COMP%]:hover {\n background: #f8f8f8;\n}\n\n.list-row.selected[_ngcontent-%COMP%] {\n background: #e3f2fd;\n}\n\n.col-name[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n font-weight: 500;\n color: #333;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.col-name[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #4a90e2;\n font-size: 1rem;\n}\n\n.col-description[_ngcontent-%COMP%], \n.col-category[_ngcontent-%COMP%] {\n color: #666;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.col-updated[_ngcontent-%COMP%] {\n color: #666;\n font-size: 0.8125rem;\n}\n\n.col-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 0.5rem;\n justify-content: flex-end;\n}\n\n.action-btn[_ngcontent-%COMP%] {\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: #f8f8f8;\n border: 1px solid #ddd;\n border-radius: 4px;\n color: #666;\n cursor: pointer;\n transition: all 0.2s;\n}\n\n.action-btn[_ngcontent-%COMP%]:hover {\n background: #4a90e2;\n border-color: #4a90e2;\n color: white;\n}\n\n.action-btn.danger[_ngcontent-%COMP%]:hover {\n background: #f44336;\n border-color: #f44336;\n}\n\n\n\n.panel-view[_ngcontent-%COMP%] {\n background: transparent;\n}\n\n.panel-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));\n gap: 1.5rem;\n}\n\n.query-panel[_ngcontent-%COMP%] {\n background: white;\n border: 1px solid #e0e0e0;\n border-radius: 8px;\n padding: 1.5rem;\n cursor: pointer;\n transition: all 0.2s;\n display: flex;\n flex-direction: column;\n gap: 1rem;\n}\n\n.query-panel[_ngcontent-%COMP%]:hover {\n border-color: #4a90e2;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);\n transform: translateY(-2px);\n}\n\n.query-panel.selected[_ngcontent-%COMP%] {\n border-color: #2196f3;\n box-shadow: 0 0 0 3px rgba(33, 150, 243, 0.1);\n}\n\n.panel-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n gap: 1rem;\n}\n\n.panel-title[_ngcontent-%COMP%] {\n font-size: 1.125rem;\n font-weight: 600;\n color: #333;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n flex: 1;\n}\n\n.panel-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #4a90e2;\n}\n\n.panel-description[_ngcontent-%COMP%] {\n font-size: 0.875rem;\n color: #666;\n line-height: 1.4;\n}\n\n.panel-sql-preview[_ngcontent-%COMP%] {\n background: #f8f8f8;\n border: 1px solid #e0e0e0;\n border-radius: 4px;\n padding: 0.75rem;\n}\n\n.sql-label[_ngcontent-%COMP%] {\n font-size: 0.75rem;\n font-weight: 600;\n color: #666;\n margin-bottom: 0.5rem;\n text-transform: uppercase;\n}\n\n.sql-code[_ngcontent-%COMP%] {\n font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;\n font-size: 0.8125rem;\n color: #333;\n background: white;\n padding: 0.5rem;\n border-radius: 2px;\n margin: 0;\n overflow-x: auto;\n white-space: pre-wrap;\n word-break: break-word;\n}\n\n.panel-footer[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding-top: 1rem;\n border-top: 1px solid #e0e0e0;\n}\n\n.panel-meta[_ngcontent-%COMP%] {\n display: flex;\n gap: 1rem;\n font-size: 0.8125rem;\n color: #666;\n}\n\n.meta-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n}\n\n.meta-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 0.875rem;\n color: #999;\n}\n\n.panel-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 0.5rem;\n}\n\n\n\n.status-badge[_ngcontent-%COMP%] {\n padding: 0.25rem 0.75rem;\n border-radius: 4px;\n font-size: 0.75rem;\n font-weight: 600;\n text-transform: uppercase;\n white-space: nowrap;\n}\n\n.status-badge.status-pending[_ngcontent-%COMP%], \n.query-status.status-pending[_ngcontent-%COMP%] {\n background: #fff3cd;\n color: #856404;\n border: 1px solid #ffc107;\n}\n\n.status-badge.status-approved[_ngcontent-%COMP%], \n.query-status.status-approved[_ngcontent-%COMP%] {\n background: #d4edda;\n color: #155724;\n border: 1px solid #28a745;\n}\n\n.status-badge.status-rejected[_ngcontent-%COMP%], \n.query-status.status-rejected[_ngcontent-%COMP%] {\n background: #f8d7da;\n color: #721c24;\n border: 1px solid #dc3545;\n}\n\n.status-badge.status-expired[_ngcontent-%COMP%], \n.query-status.status-expired[_ngcontent-%COMP%] {\n background: #e0e0e0;\n color: #666;\n border: 1px solid #999;\n}\n\n\n\n.empty-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 4rem 2rem;\n color: #999;\n background: white;\n border-radius: 8px;\n text-align: center;\n}\n\n.empty-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 4rem;\n margin-bottom: 1rem;\n color: #ddd;\n}\n\n.empty-state[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0.5rem 0;\n font-size: 1.125rem;\n color: #666;\n}\n\n.empty-hint[_ngcontent-%COMP%] {\n font-size: 0.875rem;\n color: #999;\n}\n\n\n\n@media (max-width: 1200px) {\n .panel-grid[_ngcontent-%COMP%] {\n grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));\n }\n \n .list-header[_ngcontent-%COMP%], \n .list-row[_ngcontent-%COMP%] {\n grid-template-columns: 2fr 1.5fr 1fr 1fr 120px;\n }\n \n .col-description[_ngcontent-%COMP%] {\n display: none;\n }\n}\n\n@media (max-width: 768px) {\n .query-browser-header[_ngcontent-%COMP%] {\n flex-direction: column;\n gap: 1rem;\n padding: 1rem;\n }\n \n .header-right[_ngcontent-%COMP%] {\n width: 100%;\n flex-wrap: wrap;\n }\n \n .search-container[_ngcontent-%COMP%] {\n width: 100%;\n }\n \n .filter-bar[_ngcontent-%COMP%] {\n flex-direction: column;\n align-items: stretch;\n gap: 1rem;\n }\n \n .filter-group[_ngcontent-%COMP%] {\n flex-direction: column;\n align-items: stretch;\n }\n \n .panel-grid[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n \n .folder-grid[_ngcontent-%COMP%] {\n grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));\n }\n \n .list-header[_ngcontent-%COMP%], \n .list-row[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n gap: 0.5rem;\n }\n \n .list-header[_ngcontent-%COMP%] > *[_ngcontent-%COMP%]:not(.col-name), \n .list-row[_ngcontent-%COMP%] > *[_ngcontent-%COMP%]:not(.col-name) {\n display: none;\n }\n}\n\n\n\n.query-browser-content[_ngcontent-%COMP%]::-webkit-scrollbar, \n.list-body[_ngcontent-%COMP%]::-webkit-scrollbar {\n width: 8px;\n height: 8px;\n}\n\n.query-browser-content[_ngcontent-%COMP%]::-webkit-scrollbar-track, \n.list-body[_ngcontent-%COMP%]::-webkit-scrollbar-track {\n background: #f1f1f1;\n}\n\n.query-browser-content[_ngcontent-%COMP%]::-webkit-scrollbar-thumb, \n.list-body[_ngcontent-%COMP%]::-webkit-scrollbar-thumb {\n background: #888;\n border-radius: 4px;\n}\n\n.query-browser-content[_ngcontent-%COMP%]::-webkit-scrollbar-thumb:hover, \n.list-body[_ngcontent-%COMP%]::-webkit-scrollbar-thumb:hover {\n background: #555;\n}\n\n\n\n.k-card-body[_ngcontent-%COMP%] {\n height: 80px;\n}"] });
|
|
79
898
|
};
|
|
80
899
|
QueryBrowserComponent = __decorate([
|
|
81
900
|
RegisterClass(BaseNavigationComponent, 'Queries')
|
|
@@ -83,7 +902,7 @@ QueryBrowserComponent = __decorate([
|
|
|
83
902
|
export { QueryBrowserComponent };
|
|
84
903
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(QueryBrowserComponent, [{
|
|
85
904
|
type: Component,
|
|
86
|
-
args: [{ selector: 'mj-query-browser', template: "<mj-resource-browser\n #resourceBrowserQueries\n ResourceTypeName=\"Queries\"\n [EnableCategories]=\"false\"\n [EnableItemEdit]=\"false\"\n [EnableItemDelete]=\"false\"\n [CurrentCategoryID]=\"selectedFolderID\"\n Title=\"Queries\"\n DisplayMode=\"Tile\"\n [NewItemOptions]=\"NewItemOptions\"\n (ResourceSelected)=\"itemClick($event)\"\n (EditItemEvent)=\"onBeforeUpdateItemEvent($event)\"\n/>\n<!--\n<app-generic-browser-list \ntitle=\"Queries\" \nitemType=\"query\"\niconName=\"data\" \n[items]=\"items\"\naddText=\"Create New Query\"\nItemEntityName=\"Queries\"\nCategoryEntityName=\"Query Categories\"\n(itemClickEvent)=\"itemClick($event)\"\n(AfterAddFolderEvent)=\"onEvent($event)\"\n(AfterAddItemEvent)=\"onEvent($event)\"\n(AfterDeleteItemEvent)=\"onEvent($event)\"\n(AfterDeleteFolderEvent)=\"onEvent($event)\"\n[selectedFolderID]=\"selectedFolderID\"\n[showLoader]=\"showLoader\"\n[disableEditButton]=\"true\"\n(viewModeChangeEvent)=\"onViewModeChange($event)\"\n(BeforeUpdateItemEvent)=\"onBeforeUpdateItemEvent($event)\"\n/>\n-->", styles: [".k-card-body {\n height: 80px;\n }"] }]
|
|
905
|
+
args: [{ selector: 'mj-query-browser', template: "<div class=\"query-browser-container\">\n <!-- Header with Title and View Mode Toggles -->\n <div class=\"query-browser-header\">\n <div class=\"header-left\">\n <h2 class=\"page-title\">\n <i class=\"fa-solid fa-database\"></i>\n Queries\n </h2>\n </div>\n \n <div class=\"header-right\">\n <!-- Search Bar -->\n <div class=\"search-container\">\n <i class=\"fa-solid fa-search search-icon\"></i>\n <input \n type=\"text\" \n class=\"search-input\" \n placeholder=\"Search queries...\" \n [(ngModel)]=\"searchText\"\n (ngModelChange)=\"onSearchChange($event)\"\n />\n </div>\n\n <!-- View Mode Toggles -->\n <div class=\"view-mode-toggles\">\n <button \n class=\"view-mode-btn\"\n [class.active]=\"viewMode === 'category'\"\n (click)=\"setViewMode('category')\"\n title=\"Category View\"\n >\n <i class=\"fa-solid fa-folder-tree\"></i>\n </button>\n <button \n class=\"view-mode-btn\"\n [class.active]=\"viewMode === 'list'\"\n (click)=\"setViewMode('list')\"\n title=\"List View\"\n >\n <i class=\"fa-solid fa-list\"></i>\n </button>\n <button \n class=\"view-mode-btn\"\n [class.active]=\"viewMode === 'panel'\"\n (click)=\"setViewMode('panel')\"\n title=\"Panel View\"\n >\n <i class=\"fa-solid fa-grip\"></i>\n </button>\n </div>\n\n <!-- Create New Query Button -->\n <button class=\"btn btn-primary create-query-btn\" (click)=\"createNewQuery()\">\n <i class=\"fa-solid fa-plus\"></i>\n New Query\n </button>\n </div>\n </div>\n\n <!-- Filter Bar -->\n <div class=\"filter-bar\">\n <div class=\"filter-group\">\n <label>Status:</label>\n <kendo-dropdownlist\n [data]=\"statusOptions\"\n [value]=\"getSelectedStatusOption()\"\n textField=\"text\"\n valueField=\"value\"\n (valueChange)=\"handleStatusChange($event)\"\n [style.width.px]=\"150\"\n >\n </kendo-dropdownlist>\n </div>\n\n <div class=\"filter-group\">\n <label>Sort by:</label>\n <kendo-dropdownlist\n [data]=\"sortOptions\"\n [value]=\"getSelectedSortOption()\"\n textField=\"text\"\n valueField=\"value\"\n (valueChange)=\"handleSortChange($event)\"\n [style.width.px]=\"200\"\n >\n </kendo-dropdownlist>\n </div>\n\n @if (hasActiveFilters()) {\n <button class=\"clear-filters-btn\" (click)=\"clearAllFilters()\">\n <i class=\"fa-solid fa-times\"></i>\n Clear Filters\n </button>\n }\n </div>\n\n <!-- Loading Indicator -->\n @if (isLoading) {\n <div class=\"loading-container\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n Loading queries...\n </div>\n }\n\n <!-- Content Area -->\n <div class=\"query-browser-content\" [class.loading]=\"isLoading\">\n <!-- Category Path Mode -->\n @if (viewMode === 'category' && !isLoading) {\n <div class=\"category-view\">\n <!-- Breadcrumb -->\n <div class=\"breadcrumb\">\n <span class=\"breadcrumb-item\" (click)=\"navigateToRoot()\">\n ./\n </span>\n @for (pathItem of currentCategoryPath; track pathItem.id) {\n <i class=\"fa-solid fa-chevron-right breadcrumb-separator\"></i>\n <span \n class=\"breadcrumb-item\" \n [class.current]=\"pathItem.id === currentCategoryId\"\n (click)=\"navigateToCategory(pathItem.id)\"\n >\n {{ pathItem.name }}\n </span>\n }\n </div>\n\n <!-- Categories (Folders) -->\n @if (filteredCategories.length > 0) {\n <div class=\"category-folders\">\n <h4 class=\"section-title\">\n <i class=\"fa-solid fa-folder\"></i>\n Categories\n </h4>\n <div class=\"folder-grid\">\n @for (category of filteredCategories; track category.ID) {\n <div \n class=\"folder-item\"\n (click)=\"navigateToCategory(category.ID)\"\n [title]=\"category.Description || category.Name\"\n >\n <i class=\"fa-solid fa-folder folder-icon\"></i>\n <span class=\"folder-name\">{{ category.Name }}</span>\n @if (category.QueryCount && category.QueryCount > 0) {\n <span class=\"item-count\">{{ category.QueryCount }}</span>\n }\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Queries in Current Category -->\n @if (filteredQueries.length > 0) {\n <div class=\"category-queries\">\n <h4 class=\"section-title\">\n <i class=\"fa-solid fa-file-code\"></i>\n Queries\n <span class=\"count\">({{ filteredQueries.length }})</span>\n </h4>\n <div class=\"query-list\">\n @for (query of filteredQueries; track query.ID) {\n <div \n class=\"query-list-item\"\n (click)=\"selectQuery(query)\"\n [class.selected]=\"selectedQuery?.ID === query.ID\"\n >\n <div class=\"query-icon\">\n <i class=\"fa-solid fa-code\"></i>\n </div>\n <div class=\"query-info\">\n <div class=\"query-name\">{{ query.Name }}</div>\n @if (query.Description) {\n <div class=\"query-description\">{{ query.Description }}</div>\n }\n </div>\n <div class=\"query-status\" [class]=\"'status-' + (query.Status || 'pending').toLowerCase()\">\n {{ query.Status || 'Pending' }}\n </div>\n </div>\n }\n </div>\n </div>\n }\n\n @if (filteredCategories.length === 0 && filteredQueries.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-folder-open\"></i>\n <p>No categories or queries found</p>\n </div>\n }\n </div>\n }\n\n <!-- List Mode -->\n @if (viewMode === 'list' && !isLoading) {\n <div class=\"list-view\">\n @if (filteredQueries.length > 0) {\n <div class=\"list-header\">\n <div class=\"col-name\">Name</div>\n <div class=\"col-description\">Description</div>\n <div class=\"col-category\">Category</div>\n <div class=\"col-status\">Status</div>\n <div class=\"col-updated\">Last Updated</div>\n <div class=\"col-actions\">Actions</div>\n </div>\n <div class=\"list-body\">\n @for (query of filteredQueries; track query.ID) {\n <div \n class=\"list-row\"\n (click)=\"selectQuery(query)\"\n [class.selected]=\"selectedQuery?.ID === query.ID\"\n >\n <div class=\"col-name\">\n <i class=\"fa-solid fa-code\"></i>\n {{ query.Name }}\n </div>\n <div class=\"col-description\">\n {{ query.Description || '-' }}\n </div>\n <div class=\"col-category\">\n {{ getCategoryName(query.CategoryID) || '-' }}\n </div>\n <div class=\"col-status\">\n <span class=\"status-badge\" [class]=\"'status-' + (query.Status || 'pending').toLowerCase()\">\n {{ query.Status || 'Pending' }}\n </span>\n </div>\n <div class=\"col-updated\">\n {{ formatDate(query.__mj_UpdatedAt) }}\n </div>\n <div class=\"col-actions\">\n <button \n class=\"action-btn\"\n (click)=\"runQuery(query, $event)\"\n title=\"Run\"\n >\n <i class=\"fa-solid fa-play\"></i>\n </button>\n <button \n class=\"action-btn danger\"\n (click)=\"deleteQuery(query, $event)\"\n title=\"Delete\"\n >\n <i class=\"fa-solid fa-trash\"></i>\n </button>\n </div>\n </div>\n }\n </div>\n } @else {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-database\"></i>\n <p>No queries found</p>\n @if (searchText || selectedStatus !== 'all') {\n <p class=\"empty-hint\">Try adjusting your filters</p>\n }\n </div>\n }\n </div>\n }\n\n <!-- Panel Mode -->\n @if (viewMode === 'panel' && !isLoading) {\n <div class=\"panel-view\">\n @if (filteredQueries.length > 0) {\n <div class=\"panel-grid\">\n @for (query of filteredQueries; track query.ID) {\n <div \n class=\"query-panel\"\n (click)=\"selectQuery(query)\"\n [class.selected]=\"selectedQuery?.ID === query.ID\"\n >\n <div class=\"panel-header\">\n <div class=\"panel-title\">\n <i class=\"fa-solid fa-code\"></i>\n {{ query.Name }}\n </div>\n <span class=\"status-badge\" [class]=\"'status-' + (query.Status || 'pending').toLowerCase()\">\n {{ query.Status || 'Pending' }}\n </span>\n </div>\n \n @if (query.Description) {\n <div class=\"panel-description\">\n {{ query.Description }}\n </div>\n }\n \n <div class=\"panel-sql-preview\">\n <div class=\"sql-label\">SQL Preview:</div>\n <pre class=\"sql-code\">{{ getQueryPreview(query.SQL) }}</pre>\n </div>\n \n <div class=\"panel-footer\">\n <div class=\"panel-meta\">\n @if (query.CategoryID) {\n <span class=\"meta-item\">\n <i class=\"fa-solid fa-folder\"></i>\n {{ getCategoryName(query.CategoryID) }}\n </span>\n }\n <span class=\"meta-item\">\n <i class=\"fa-solid fa-clock\"></i>\n {{ formatDate(query.__mj_UpdatedAt) }}\n </span>\n </div>\n <div class=\"panel-actions\">\n <button \n class=\"action-btn\"\n (click)=\"runQuery(query, $event)\"\n title=\"Run\"\n >\n <i class=\"fa-solid fa-play\"></i>\n </button>\n </div>\n </div>\n </div>\n }\n </div>\n } @else {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-grip\"></i>\n <p>No queries to display</p>\n @if (searchText || selectedStatus !== 'all') {\n <p class=\"empty-hint\">Try adjusting your filters</p>\n }\n </div>\n }\n </div>\n }\n </div>\n</div>", styles: ["/* Container Styles */\n.query-browser-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: #f5f5f5;\n}\n\n/* Header Styles */\n.query-browser-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 1rem 1.5rem;\n background: white;\n border-bottom: 1px solid #e0e0e0;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);\n}\n\n.header-left {\n display: flex;\n align-items: center;\n}\n\n.page-title {\n margin: 0;\n font-size: 1.5rem;\n font-weight: 600;\n color: #333;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n}\n\n.page-title i {\n color: #4a90e2;\n}\n\n.header-right {\n display: flex;\n align-items: center;\n gap: 1rem;\n}\n\n/* Search Bar */\n.search-container {\n position: relative;\n width: 300px;\n}\n\n.search-input {\n width: 100%;\n padding: 0.5rem 1rem 0.5rem 2.5rem;\n border: 1px solid #ddd;\n border-radius: 4px;\n font-size: 0.875rem;\n transition: border-color 0.2s;\n}\n\n.search-input:focus {\n outline: none;\n border-color: #4a90e2;\n box-shadow: 0 0 0 3px rgba(74, 144, 226, 0.1);\n}\n\n.search-icon {\n position: absolute;\n left: 0.75rem;\n top: 50%;\n transform: translateY(-50%);\n color: #999;\n font-size: 0.875rem;\n}\n\n/* View Mode Toggles */\n.view-mode-toggles {\n display: flex;\n background: #f8f8f8;\n border: 1px solid #ddd;\n border-radius: 4px;\n overflow: hidden;\n}\n\n.view-mode-btn {\n padding: 0.5rem 1rem;\n background: transparent;\n border: none;\n color: #666;\n cursor: pointer;\n font-size: 1rem;\n transition: all 0.2s;\n border-right: 1px solid #ddd;\n}\n\n.view-mode-btn:last-child {\n border-right: none;\n}\n\n.view-mode-btn:hover {\n background: #e8e8e8;\n color: #333;\n}\n\n.view-mode-btn.active {\n background: #4a90e2;\n color: white;\n}\n\n/* Create Button */\n.create-query-btn {\n padding: 0.5rem 1rem;\n background: #4a90e2;\n color: white;\n border: none;\n border-radius: 4px;\n font-size: 0.875rem;\n font-weight: 500;\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n transition: background 0.2s;\n}\n\n.create-query-btn:hover {\n background: #357abd;\n}\n\n/* Filter Bar */\n.filter-bar {\n display: flex;\n align-items: center;\n gap: 1.5rem;\n padding: 1rem 1.5rem;\n background: white;\n border-bottom: 1px solid #e0e0e0;\n}\n\n.filter-group {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n}\n\n.filter-group label {\n font-size: 0.875rem;\n font-weight: 500;\n color: #666;\n}\n\n.clear-filters-btn {\n margin-left: auto;\n padding: 0.375rem 0.75rem;\n background: #f44336;\n color: white;\n border: none;\n border-radius: 4px;\n font-size: 0.875rem;\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 0.375rem;\n transition: background 0.2s;\n}\n\n.clear-filters-btn:hover {\n background: #d32f2f;\n}\n\n/* Loading State */\n.loading-container {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 0.75rem;\n padding: 3rem;\n color: #666;\n font-size: 1rem;\n}\n\n.loading-container i {\n font-size: 1.25rem;\n color: #4a90e2;\n}\n\n/* Content Area */\n.query-browser-content {\n flex: 1;\n overflow: auto;\n padding: 1.5rem;\n transition: opacity 0.2s;\n}\n\n.query-browser-content.loading {\n opacity: 0.5;\n pointer-events: none;\n}\n\n/* Category View Styles */\n.category-view {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n}\n\n/* Breadcrumb */\n.breadcrumb {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.75rem;\n background: white;\n border-radius: 4px;\n font-size: 0.875rem;\n}\n\n.breadcrumb-item {\n color: #4a90e2;\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 0.375rem;\n transition: color 0.2s;\n}\n\n.breadcrumb-item:hover {\n color: #357abd;\n text-decoration: underline;\n}\n\n.breadcrumb-item.current {\n color: #666;\n cursor: default;\n text-decoration: none;\n}\n\n.breadcrumb-separator {\n color: #999;\n font-size: 0.75rem;\n}\n\n/* Category Folders */\n.category-folders {\n background: white;\n border-radius: 8px;\n padding: 1.5rem;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);\n}\n\n.section-title {\n margin: 0 0 1rem 0;\n font-size: 1.125rem;\n font-weight: 600;\n color: #333;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n}\n\n.section-title .count {\n font-weight: normal;\n color: #666;\n font-size: 0.875rem;\n}\n\n.folder-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));\n gap: 1rem;\n}\n\n.folder-item {\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 1.5rem 1rem;\n background: #f8f8f8;\n border: 1px solid #e0e0e0;\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s;\n position: relative;\n}\n\n.folder-item:hover {\n background: #e8f4fd;\n border-color: #4a90e2;\n transform: translateY(-2px);\n box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);\n}\n\n.folder-icon {\n font-size: 2.5rem;\n color: #ffa726;\n margin-bottom: 0.5rem;\n}\n\n.folder-name {\n font-size: 0.875rem;\n font-weight: 500;\n color: #333;\n text-align: center;\n word-break: break-word;\n}\n\n.item-count {\n position: absolute;\n top: 0.5rem;\n right: 0.5rem;\n background: #4a90e2;\n color: white;\n font-size: 0.75rem;\n padding: 0.125rem 0.375rem;\n border-radius: 12px;\n min-width: 20px;\n text-align: center;\n}\n\n/* Category Queries */\n.category-queries {\n background: white;\n border-radius: 8px;\n padding: 1.5rem;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);\n}\n\n.query-list {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\n.query-list-item {\n display: flex;\n align-items: center;\n padding: 1rem;\n background: #f8f8f8;\n border: 1px solid #e0e0e0;\n border-radius: 4px;\n cursor: pointer;\n transition: all 0.2s;\n}\n\n.query-list-item:hover {\n background: #e8f4fd;\n border-color: #4a90e2;\n}\n\n.query-list-item.selected {\n background: #e3f2fd;\n border-color: #2196f3;\n}\n\n.query-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 40px;\n height: 40px;\n background: white;\n border-radius: 4px;\n margin-right: 1rem;\n color: #4a90e2;\n font-size: 1.25rem;\n}\n\n.query-info {\n flex: 1;\n min-width: 0;\n}\n\n.query-name {\n font-size: 1rem;\n font-weight: 500;\n color: #333;\n margin-bottom: 0.25rem;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.query-description {\n font-size: 0.875rem;\n color: #666;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.query-status {\n padding: 0.25rem 0.75rem;\n border-radius: 4px;\n font-size: 0.75rem;\n font-weight: 600;\n text-transform: uppercase;\n white-space: nowrap;\n}\n\n/* List View Styles */\n.list-view {\n background: white;\n border-radius: 8px;\n overflow: hidden;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);\n}\n\n.list-header {\n display: grid;\n grid-template-columns: 2fr 2fr 1.5fr 1fr 1.5fr 120px;\n padding: 1rem 1.5rem;\n background: #f8f8f8;\n border-bottom: 2px solid #e0e0e0;\n font-size: 0.875rem;\n font-weight: 600;\n color: #666;\n}\n\n.list-body {\n max-height: calc(100vh - 300px);\n overflow-y: auto;\n}\n\n.list-row {\n display: grid;\n grid-template-columns: 2fr 2fr 1.5fr 1fr 1.5fr 120px;\n padding: 1rem 1.5rem;\n border-bottom: 1px solid #e0e0e0;\n font-size: 0.875rem;\n cursor: pointer;\n transition: background 0.2s;\n align-items: center;\n}\n\n.list-row:hover {\n background: #f8f8f8;\n}\n\n.list-row.selected {\n background: #e3f2fd;\n}\n\n.col-name {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n font-weight: 500;\n color: #333;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.col-name i {\n color: #4a90e2;\n font-size: 1rem;\n}\n\n.col-description,\n.col-category {\n color: #666;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.col-updated {\n color: #666;\n font-size: 0.8125rem;\n}\n\n.col-actions {\n display: flex;\n gap: 0.5rem;\n justify-content: flex-end;\n}\n\n.action-btn {\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: #f8f8f8;\n border: 1px solid #ddd;\n border-radius: 4px;\n color: #666;\n cursor: pointer;\n transition: all 0.2s;\n}\n\n.action-btn:hover {\n background: #4a90e2;\n border-color: #4a90e2;\n color: white;\n}\n\n.action-btn.danger:hover {\n background: #f44336;\n border-color: #f44336;\n}\n\n/* Panel View Styles */\n.panel-view {\n background: transparent;\n}\n\n.panel-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));\n gap: 1.5rem;\n}\n\n.query-panel {\n background: white;\n border: 1px solid #e0e0e0;\n border-radius: 8px;\n padding: 1.5rem;\n cursor: pointer;\n transition: all 0.2s;\n display: flex;\n flex-direction: column;\n gap: 1rem;\n}\n\n.query-panel:hover {\n border-color: #4a90e2;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);\n transform: translateY(-2px);\n}\n\n.query-panel.selected {\n border-color: #2196f3;\n box-shadow: 0 0 0 3px rgba(33, 150, 243, 0.1);\n}\n\n.panel-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n gap: 1rem;\n}\n\n.panel-title {\n font-size: 1.125rem;\n font-weight: 600;\n color: #333;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n flex: 1;\n}\n\n.panel-title i {\n color: #4a90e2;\n}\n\n.panel-description {\n font-size: 0.875rem;\n color: #666;\n line-height: 1.4;\n}\n\n.panel-sql-preview {\n background: #f8f8f8;\n border: 1px solid #e0e0e0;\n border-radius: 4px;\n padding: 0.75rem;\n}\n\n.sql-label {\n font-size: 0.75rem;\n font-weight: 600;\n color: #666;\n margin-bottom: 0.5rem;\n text-transform: uppercase;\n}\n\n.sql-code {\n font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;\n font-size: 0.8125rem;\n color: #333;\n background: white;\n padding: 0.5rem;\n border-radius: 2px;\n margin: 0;\n overflow-x: auto;\n white-space: pre-wrap;\n word-break: break-word;\n}\n\n.panel-footer {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding-top: 1rem;\n border-top: 1px solid #e0e0e0;\n}\n\n.panel-meta {\n display: flex;\n gap: 1rem;\n font-size: 0.8125rem;\n color: #666;\n}\n\n.meta-item {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n}\n\n.meta-item i {\n font-size: 0.875rem;\n color: #999;\n}\n\n.panel-actions {\n display: flex;\n gap: 0.5rem;\n}\n\n/* Status Badge Styles */\n.status-badge {\n padding: 0.25rem 0.75rem;\n border-radius: 4px;\n font-size: 0.75rem;\n font-weight: 600;\n text-transform: uppercase;\n white-space: nowrap;\n}\n\n.status-badge.status-pending,\n.query-status.status-pending {\n background: #fff3cd;\n color: #856404;\n border: 1px solid #ffc107;\n}\n\n.status-badge.status-approved,\n.query-status.status-approved {\n background: #d4edda;\n color: #155724;\n border: 1px solid #28a745;\n}\n\n.status-badge.status-rejected,\n.query-status.status-rejected {\n background: #f8d7da;\n color: #721c24;\n border: 1px solid #dc3545;\n}\n\n.status-badge.status-expired,\n.query-status.status-expired {\n background: #e0e0e0;\n color: #666;\n border: 1px solid #999;\n}\n\n/* Empty State */\n.empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 4rem 2rem;\n color: #999;\n background: white;\n border-radius: 8px;\n text-align: center;\n}\n\n.empty-state i {\n font-size: 4rem;\n margin-bottom: 1rem;\n color: #ddd;\n}\n\n.empty-state p {\n margin: 0.5rem 0;\n font-size: 1.125rem;\n color: #666;\n}\n\n.empty-hint {\n font-size: 0.875rem;\n color: #999;\n}\n\n/* Responsive Design */\n@media (max-width: 1200px) {\n .panel-grid {\n grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));\n }\n \n .list-header,\n .list-row {\n grid-template-columns: 2fr 1.5fr 1fr 1fr 120px;\n }\n \n .col-description {\n display: none;\n }\n}\n\n@media (max-width: 768px) {\n .query-browser-header {\n flex-direction: column;\n gap: 1rem;\n padding: 1rem;\n }\n \n .header-right {\n width: 100%;\n flex-wrap: wrap;\n }\n \n .search-container {\n width: 100%;\n }\n \n .filter-bar {\n flex-direction: column;\n align-items: stretch;\n gap: 1rem;\n }\n \n .filter-group {\n flex-direction: column;\n align-items: stretch;\n }\n \n .panel-grid {\n grid-template-columns: 1fr;\n }\n \n .folder-grid {\n grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));\n }\n \n .list-header,\n .list-row {\n grid-template-columns: 1fr;\n gap: 0.5rem;\n }\n \n .list-header > *:not(.col-name),\n .list-row > *:not(.col-name) {\n display: none;\n }\n}\n\n/* Scrollbar Styles */\n.query-browser-content::-webkit-scrollbar,\n.list-body::-webkit-scrollbar {\n width: 8px;\n height: 8px;\n}\n\n.query-browser-content::-webkit-scrollbar-track,\n.list-body::-webkit-scrollbar-track {\n background: #f1f1f1;\n}\n\n.query-browser-content::-webkit-scrollbar-thumb,\n.list-body::-webkit-scrollbar-thumb {\n background: #888;\n border-radius: 4px;\n}\n\n.query-browser-content::-webkit-scrollbar-thumb:hover,\n.list-body::-webkit-scrollbar-thumb:hover {\n background: #555;\n}\n\n/* Legacy k-card style - keep for backward compatibility */\n.k-card-body {\n height: 80px;\n}"] }]
|
|
87
906
|
}], () => [{ type: i1.Router }, { type: i1.ActivatedRoute }, { type: i2.SharedService }], null); })();
|
|
88
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(QueryBrowserComponent, { className: "QueryBrowserComponent", filePath: "src/lib/query-browser-component/query-browser.component.ts", lineNumber:
|
|
907
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(QueryBrowserComponent, { className: "QueryBrowserComponent", filePath: "src/lib/query-browser-component/query-browser.component.ts", lineNumber: 28 }); })();
|
|
89
908
|
//# sourceMappingURL=query-browser.component.js.map
|