http-request-manager 18.16.1 → 18.16.3
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.
|
@@ -190,19 +190,32 @@ class UtilsService {
|
|
|
190
190
|
switch (type) {
|
|
191
191
|
case 'y':
|
|
192
192
|
const years = parseInt(str.slice(0, -1));
|
|
193
|
-
|
|
193
|
+
const dateY = new Date();
|
|
194
|
+
dateY.setFullYear(dateY.getFullYear() + years, 0, 1);
|
|
195
|
+
dateY.setHours(0, 0, 0, 0);
|
|
196
|
+
value = Math.floor(dateY.getTime() / 1000);
|
|
194
197
|
break;
|
|
195
198
|
case 'm':
|
|
196
199
|
const months = parseInt(str.slice(0, -1));
|
|
197
|
-
|
|
200
|
+
const dateM = new Date();
|
|
201
|
+
dateM.setMonth(dateM.getMonth() + months, 1);
|
|
202
|
+
dateM.setHours(0, 0, 0, 0);
|
|
203
|
+
value = Math.floor(dateM.getTime() / 1000);
|
|
198
204
|
break;
|
|
199
205
|
case 'w':
|
|
200
206
|
const weeks = parseInt(str.slice(0, -1));
|
|
201
|
-
|
|
207
|
+
const dateW = new Date();
|
|
208
|
+
const daysUntilSunday = (7 - dateW.getDay()) % 7;
|
|
209
|
+
dateW.setDate(dateW.getDate() + daysUntilSunday + 1 + (weeks - 1) * 7);
|
|
210
|
+
dateW.setHours(0, 0, 0, 0);
|
|
211
|
+
value = Math.floor(dateW.getTime() / 1000);
|
|
202
212
|
break;
|
|
203
213
|
case 'd':
|
|
204
214
|
const days = parseInt(str.slice(0, -1));
|
|
205
|
-
|
|
215
|
+
const dateD = new Date();
|
|
216
|
+
dateD.setDate(dateD.getDate() + days);
|
|
217
|
+
dateD.setHours(0, 0, 0, 0);
|
|
218
|
+
value = Math.floor(dateD.getTime() / 1000);
|
|
206
219
|
break;
|
|
207
220
|
case 'hr':
|
|
208
221
|
const hrs = parseInt(str.slice(0, -2));
|
|
@@ -1859,6 +1872,7 @@ class WebSocketManagerService {
|
|
|
1859
1872
|
this.maxRetries$ = WebSocketManagerService.maxRetriesSubject.asObservable();
|
|
1860
1873
|
this.messages$ = WebSocketManagerService.messages.asObservable();
|
|
1861
1874
|
this.connectionStatus$ = WebSocketManagerService.connectionStatus.asObservable();
|
|
1875
|
+
this.connectionError$ = WebSocketManagerService.connectionError.asObservable();
|
|
1862
1876
|
this.subscribedChannels$ = WebSocketManagerService.subscribedChannels.asObservable();
|
|
1863
1877
|
this.onReconnect$ = WebSocketManagerService.onReconnect.asObservable();
|
|
1864
1878
|
}
|
|
@@ -1884,6 +1898,7 @@ class WebSocketManagerService {
|
|
|
1884
1898
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
1885
1899
|
static { this.messages = new BehaviorSubject(null); }
|
|
1886
1900
|
static { this.connectionStatus = new BehaviorSubject(false); }
|
|
1901
|
+
static { this.connectionError = new BehaviorSubject(null); }
|
|
1887
1902
|
static { this.isSubscribed = false; }
|
|
1888
1903
|
// Track currently subscribed channels
|
|
1889
1904
|
static { this.subscribedChannels = new BehaviorSubject(new Set()); }
|
|
@@ -1926,6 +1941,7 @@ class WebSocketManagerService {
|
|
|
1926
1941
|
// Cancel any pending retry timer before attempting a new connection
|
|
1927
1942
|
WebSocketManagerService.retrySubscription?.unsubscribe();
|
|
1928
1943
|
WebSocketManagerService.retrySubscription = null;
|
|
1944
|
+
WebSocketManagerService.connectionError.next(null);
|
|
1929
1945
|
// Check if connection already exists and is open
|
|
1930
1946
|
if (WebSocketManagerService.socket) {
|
|
1931
1947
|
if (WebSocketManagerService.socket.readyState === WebSocket.OPEN) {
|
|
@@ -1994,9 +2010,11 @@ class WebSocketManagerService {
|
|
|
1994
2010
|
const data = JSON.parse(event.data);
|
|
1995
2011
|
if (data.error) {
|
|
1996
2012
|
WebSocketManagerService.messages.next(data);
|
|
1997
|
-
// Log the server error and close — onclose will drive the retry logic
|
|
1998
2013
|
if (data.error === 'JWT_INVALID' || data.error === 'AUTH_BLOCKED') {
|
|
1999
|
-
console.error(`🚫 ${data.error}: ${data.message || 'Authentication error'} —
|
|
2014
|
+
console.error(`🚫 ${data.error}: ${data.message || 'Authentication error'} — stopping, no retry`);
|
|
2015
|
+
WebSocketManagerService.lastOptions = null;
|
|
2016
|
+
WebSocketManagerService.connectionError.next('Invalid or Expired JWT');
|
|
2017
|
+
WebSocketManagerService.connectionStatus.next(false);
|
|
2000
2018
|
}
|
|
2001
2019
|
else {
|
|
2002
2020
|
console.error(`❌ Server error: ${data.error} — will retry`);
|
|
@@ -2029,6 +2047,11 @@ class WebSocketManagerService {
|
|
|
2029
2047
|
WebSocketManagerService.connectionReadyNotified = false;
|
|
2030
2048
|
WebSocketManagerService.socket = null;
|
|
2031
2049
|
WebSocketManagerService.subscribedChannels.next(new Set());
|
|
2050
|
+
if (event.code === 4000 || event.code === 4001 || event.code === 4003) {
|
|
2051
|
+
WebSocketManagerService.connectionError.next('Invalid or Expired JWT');
|
|
2052
|
+
WebSocketManagerService.connectionStatus.next(false);
|
|
2053
|
+
return;
|
|
2054
|
+
}
|
|
2032
2055
|
const maxRetries = WebSocketManagerService.maxRetries;
|
|
2033
2056
|
const retryDelay = WebSocketManagerService.retryDelay;
|
|
2034
2057
|
if (WebSocketManagerService.lastOptions && WebSocketManagerService.retryCount < maxRetries) {
|
|
@@ -3773,6 +3796,7 @@ class HTTPManagerService extends RequestService {
|
|
|
3773
3796
|
this.subscribedChannels$ = this.wsManager.subscribedChannels$;
|
|
3774
3797
|
this.retryCount$ = this.wsManager.retryCount$;
|
|
3775
3798
|
this.maxRetries$ = this.wsManager.maxRetries$;
|
|
3799
|
+
this.connectionError$ = this.wsManager.connectionError$;
|
|
3776
3800
|
this.countdown = new BehaviorSubject(0);
|
|
3777
3801
|
this.countdown$ = this.countdown.asObservable();
|
|
3778
3802
|
this.error = new BehaviorSubject(false);
|
|
@@ -3930,13 +3954,15 @@ class HTTPManagerService extends RequestService {
|
|
|
3930
3954
|
return this.createObservable(updatedOptions, requests, func.name)
|
|
3931
3955
|
.pipe(tap(data => {
|
|
3932
3956
|
this.data.next(data);
|
|
3933
|
-
if (updatedOptions.displaySuccess)
|
|
3957
|
+
if (updatedOptions.displaySuccess && !updatedOptions.stream)
|
|
3934
3958
|
this.handleSuccessWithSnackBar(updatedOptions.successMessage);
|
|
3935
3959
|
}), finalize(() => {
|
|
3936
3960
|
this.streamProgress.next({
|
|
3937
3961
|
...this.streamProgress.value,
|
|
3938
3962
|
stage: 'complete'
|
|
3939
3963
|
});
|
|
3964
|
+
if (updatedOptions.displaySuccess && updatedOptions.stream)
|
|
3965
|
+
this.handleSuccessWithSnackBar(updatedOptions.successMessage);
|
|
3940
3966
|
this.isPending.next(false);
|
|
3941
3967
|
}), catchError((err) => {
|
|
3942
3968
|
if (updatedOptions.displayError)
|
|
@@ -4366,7 +4392,9 @@ class RequestSignalsService extends WebsocketService {
|
|
|
4366
4392
|
}
|
|
4367
4393
|
requestStreamingOperator(options) {
|
|
4368
4394
|
return (source$) => {
|
|
4369
|
-
return source$.pipe(
|
|
4395
|
+
return source$.pipe(tap(output => {
|
|
4396
|
+
this.progress.set(output.progress.received);
|
|
4397
|
+
}), map(output => {
|
|
4370
4398
|
const data = output.data;
|
|
4371
4399
|
if (!data || (Array.isArray(data) && data.length === 0)) {
|
|
4372
4400
|
return data;
|
|
@@ -4726,9 +4754,13 @@ class HTTPManagerSignalsService extends RequestSignalsService {
|
|
|
4726
4754
|
const requests = this.createRequest(func, updatedOptions);
|
|
4727
4755
|
return this.createObservable(updatedOptions, requests, func.name).pipe(tap(data => {
|
|
4728
4756
|
this.data.set(data);
|
|
4729
|
-
if (updatedOptions.displaySuccess)
|
|
4757
|
+
if (updatedOptions.displaySuccess && !updatedOptions.stream)
|
|
4730
4758
|
this.handleSuccessWithSnackBar(updatedOptions.successMessage);
|
|
4731
|
-
}), finalize(() =>
|
|
4759
|
+
}), finalize(() => {
|
|
4760
|
+
if (updatedOptions.displaySuccess && updatedOptions.stream)
|
|
4761
|
+
this.handleSuccessWithSnackBar(updatedOptions.successMessage);
|
|
4762
|
+
this.isPending.set(false);
|
|
4763
|
+
}), catchError((err) => {
|
|
4732
4764
|
if (updatedOptions.displayError)
|
|
4733
4765
|
this.handleErrorWithSnackBar(err, updatedOptions.errorMessage || err?.message);
|
|
4734
4766
|
this.isPending.set(false);
|
|
@@ -6471,19 +6503,16 @@ class DatabaseManagerService extends DbService {
|
|
|
6471
6503
|
}
|
|
6472
6504
|
clearTable(table) {
|
|
6473
6505
|
const tableName = this.cleanTableName(table);
|
|
6506
|
+
this.localStorageManager.deleteStore({ name: tableName });
|
|
6474
6507
|
try {
|
|
6475
6508
|
const tableInstance = this.table(tableName);
|
|
6476
6509
|
if (!tableInstance) {
|
|
6477
6510
|
console.warn(`clearTable: Table '${tableName}' not found`);
|
|
6478
6511
|
return of([]);
|
|
6479
6512
|
}
|
|
6480
|
-
// console.log(`clearTable: Clearing table '${tableName}'...`);
|
|
6481
|
-
// Use table.clear() directly and wrap in Observable
|
|
6482
6513
|
return from(Promise.resolve().then(() => {
|
|
6483
6514
|
return tableInstance.clear();
|
|
6484
|
-
})).pipe(
|
|
6485
|
-
// tap(() => console.log(`clearTable: ✅ Table '${tableName}' cleared successfully`)),
|
|
6486
|
-
map(() => []));
|
|
6515
|
+
})).pipe(map(() => []));
|
|
6487
6516
|
}
|
|
6488
6517
|
catch (error) {
|
|
6489
6518
|
console.error(`clearTable: ❌ Error:`, error);
|
|
@@ -6631,6 +6660,7 @@ class HTTPManagerStateService extends ComponentStore {
|
|
|
6631
6660
|
this.connectionStatus$ = this.httpManagerService.connectionStatus$;
|
|
6632
6661
|
this.wsRetryCount$ = this.httpManagerService.retryCount$;
|
|
6633
6662
|
this.wsMaxRetries$ = this.httpManagerService.maxRetries$;
|
|
6663
|
+
this.connectionError$ = this.httpManagerService.connectionError$;
|
|
6634
6664
|
// WebSocket
|
|
6635
6665
|
this.initWS = this.effect((wsOptions$) => wsOptions$.pipe(switchMap((wsOptions) => merge(this.httpManagerService.connectionStatus$.pipe(tap((isConnected) => {
|
|
6636
6666
|
if (isConnected) {
|
|
@@ -8110,7 +8140,6 @@ class HTTPManagerStateService extends ComponentStore {
|
|
|
8110
8140
|
this._requestCachePaths.set(tableName, this.resolvePath(options?.path).filter(p => typeof p === 'string' || typeof p === 'number').map(String));
|
|
8111
8141
|
this.localStorageManagerService.store$(tableName).pipe(take(1), tap((storeData) => {
|
|
8112
8142
|
const currentCache = storeData?.requestCache || {};
|
|
8113
|
-
const currentEntry = currentCache[type] || {};
|
|
8114
8143
|
this.localStorageManagerService.updateStore({
|
|
8115
8144
|
name: tableName,
|
|
8116
8145
|
data: {
|
|
@@ -8118,13 +8147,11 @@ class HTTPManagerStateService extends ComponentStore {
|
|
|
8118
8147
|
requestCache: {
|
|
8119
8148
|
...currentCache,
|
|
8120
8149
|
[type]: {
|
|
8121
|
-
...
|
|
8150
|
+
...(currentCache[type] || {}),
|
|
8122
8151
|
signature,
|
|
8123
8152
|
savedAt: Date.now(),
|
|
8124
8153
|
path: this.resolvePath(options?.path),
|
|
8125
|
-
headers: this.filterHeaders(options?.headers)
|
|
8126
|
-
queryParams: currentEntry.queryParams,
|
|
8127
|
-
queryParamsExpires: currentEntry.queryParamsExpires,
|
|
8154
|
+
headers: this.filterHeaders(options?.headers)
|
|
8128
8155
|
}
|
|
8129
8156
|
}
|
|
8130
8157
|
}
|
|
@@ -8266,53 +8293,12 @@ class HTTPManagerStateService extends ComponentStore {
|
|
|
8266
8293
|
const ignoreQueryParams = Array.isArray(options?.ignoreQueryParams) ? options.ignoreQueryParams : [];
|
|
8267
8294
|
if (!normalized.hasQuery) {
|
|
8268
8295
|
const meta = this.getRequestCacheMetadata(storeData, type);
|
|
8269
|
-
if (!meta) {
|
|
8270
|
-
// No prior cache entry — record that we're tracking this request
|
|
8271
|
-
this.setCachedRequestSignature(tableName, type, '');
|
|
8272
|
-
this.localStorageManagerService.store$(tableName).pipe(take(1), tap((s) => {
|
|
8273
|
-
const currentCache = s?.requestCache || {};
|
|
8274
|
-
this.localStorageManagerService.updateStore({
|
|
8275
|
-
name: tableName,
|
|
8276
|
-
data: {
|
|
8277
|
-
...(s || {}),
|
|
8278
|
-
requestCache: {
|
|
8279
|
-
...currentCache,
|
|
8280
|
-
[type]: {
|
|
8281
|
-
...(currentCache[type] || {}),
|
|
8282
|
-
active: true,
|
|
8283
|
-
}
|
|
8284
|
-
}
|
|
8285
|
-
}
|
|
8286
|
-
});
|
|
8287
|
-
})).subscribe();
|
|
8288
|
-
}
|
|
8289
8296
|
return of(!meta);
|
|
8290
8297
|
}
|
|
8291
8298
|
const filtered = this.trackerFilterQuery(normalized.query, ignoreQueryParams);
|
|
8292
8299
|
const keys = Object.keys(filtered);
|
|
8293
8300
|
if (keys.length === 0) {
|
|
8294
|
-
|
|
8295
|
-
const meta = this.getRequestCacheMetadata(storeData, type);
|
|
8296
|
-
if (!meta) {
|
|
8297
|
-
this.setCachedRequestSignature(tableName, type, '');
|
|
8298
|
-
this.localStorageManagerService.store$(tableName).pipe(take(1), tap((s) => {
|
|
8299
|
-
const currentCache = s?.requestCache || {};
|
|
8300
|
-
this.localStorageManagerService.updateStore({
|
|
8301
|
-
name: tableName,
|
|
8302
|
-
data: {
|
|
8303
|
-
...(s || {}),
|
|
8304
|
-
requestCache: {
|
|
8305
|
-
...currentCache,
|
|
8306
|
-
[type]: {
|
|
8307
|
-
...(currentCache[type] || {}),
|
|
8308
|
-
active: true,
|
|
8309
|
-
}
|
|
8310
|
-
}
|
|
8311
|
-
}
|
|
8312
|
-
});
|
|
8313
|
-
})).subscribe();
|
|
8314
|
-
}
|
|
8315
|
-
return of(!meta);
|
|
8301
|
+
return of(!this.getRequestCacheMetadata(storeData, type));
|
|
8316
8302
|
}
|
|
8317
8303
|
const meta = this.getRequestCacheMetadata(storeData, type) || {};
|
|
8318
8304
|
const now = Math.floor(Date.now() / 1000);
|
|
@@ -9027,7 +9013,7 @@ class QueryPlanner {
|
|
|
9027
9013
|
}
|
|
9028
9014
|
else {
|
|
9029
9015
|
const projected = columns
|
|
9030
|
-
.filter((c) => c.expr?.type === 'column_ref')
|
|
9016
|
+
.filter((c) => c.expr?.type === 'column_ref' && c.expr?.column !== '*')
|
|
9031
9017
|
.map((c) => c.expr.column);
|
|
9032
9018
|
plan.projection = projected.length > 0 ? projected : null;
|
|
9033
9019
|
}
|
|
@@ -12433,6 +12419,7 @@ class RequestManagerWsDemoComponent {
|
|
|
12433
12419
|
this.retryCount$ = this.stateService.wsRetryCount$;
|
|
12434
12420
|
this.maxRetries$ = this.stateService.wsMaxRetries$;
|
|
12435
12421
|
this.connectionStatus$ = this.stateService.connectionStatus$;
|
|
12422
|
+
this.connectionError$ = this.stateService.connectionError$;
|
|
12436
12423
|
this.data$ = this.stateService.data$;
|
|
12437
12424
|
this.isPending$ = this.stateService.isPending$;
|
|
12438
12425
|
}
|
|
@@ -12440,11 +12427,11 @@ class RequestManagerWsDemoComponent {
|
|
|
12440
12427
|
this.stateService.updateConnection(this.server, this.wsServer, this.jwtToken, this.user, this.path);
|
|
12441
12428
|
}
|
|
12442
12429
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: RequestManagerWsDemoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
12443
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: RequestManagerWsDemoComponent, selector: "app-request-manager-ws-demo", inputs: { server: "server", wsServer: "wsServer", jwtToken: "jwtToken", user: "user", path: "path" }, ngImport: i0, template: "<div style=\"margin: 2rem;\">\n\n <h2 style=\"display: flex;\">\n <span style=\"flex:1\">HTTP Request State Manager - Websockets</span>\n @if ((connectionStatus$ | async); as connected) {\n <span>\n WS -\n <span style=\"color: green;\">Connected</span>\n </span>\n } @else {\n <span style=\"color: red;\">Disconnected {{ retryCount$ | async }} / {{ maxRetries$ | async }}</span>\n }\n </h2>\n\n <div>\n\n @if ((user$ | async); as userInfo) {\n <div>\n <mat-toolbar>\n <div style=\"display: flex; flex:1\">\n <div style=\"flex:1\">{{ userInfo.name }}</div>\n <div>({{ userInfo.ldap }})</div>\n </div>\n </mat-toolbar>\n </div>\n }\n\n @if (!(connectionStatus$ | async) && ((retryCount$ | async) ?? 0) < ((maxRetries$ | async) ?? 0)) {\n <div>\n <mat-progress-bar mode=\"indeterminate\"></mat-progress-bar>\n </div>\n }\n\n <mat-tab-group animationDuration=\"0ms\" [selectedIndex]=\"1\">\n\n <mat-tab label=\"WS - Data Control\" [disabled]=\"!(connectionStatus$ | async)\">\n <!-- DATA CONTROL -->\n <app-ws-data-control\n [server]=\"server\"\n [wsServer]=\"wsServer\"\n [jwtToken]=\"jwtToken\"\n [user]=\"user\"\n [path]=\"path\"\n ></app-ws-data-control>\n\n </mat-tab>\n\n <mat-tab label=\"WS - Messaging\" [disabled]=\"!(connectionStatus$ | async)\">\n <!-- MESSAGING -->\n <app-ws-messaging\n [server]=\"server\"\n [wsServer]=\"wsServer\"\n [jwtToken]=\"jwtToken\"\n [user]=\"user\"\n [path]=\"path\"\n ></app-ws-messaging>\n\n </mat-tab>\n\n <mat-tab label=\"WS - Notifications\" [disabled]=\"!(connectionStatus$ | async)\">\n <!-- WS - Notifications -->\n <app-ws-notifications\n [server]=\"server\"\n [wsServer]=\"wsServer\"\n [jwtToken]=\"jwtToken\"\n [user]=\"user\"\n ></app-ws-notifications>\n </mat-tab>\n\n <mat-tab label=\"WS - Chats\" [disabled]=\"true\">\n <!-- WS - Chats -->\n <app-ws-chats></app-ws-chats>\n </mat-tab>\n\n <mat-tab label=\"WS - AI Messaging\" [disabled]=\"true\">\n <!-- WS - AI Messaging -->\n <app-ws-ai-messaging></app-ws-ai-messaging>\n </mat-tab>\n\n </mat-tab-group>\n</div>\n\n</div>\n\n", styles: [""], dependencies: [{ kind: "component", type: i1$2.MatTab, selector: "mat-tab", inputs: ["disabled", "label", "aria-label", "aria-labelledby", "labelClass", "bodyClass"], exportAs: ["matTab"] }, { kind: "component", type: i1$2.MatTabGroup, selector: "mat-tab-group", inputs: ["color", "fitInkBarToContent", "mat-stretch-tabs", "dynamicHeight", "selectedIndex", "headerPosition", "animationDuration", "contentTabIndex", "disablePagination", "disableRipple", "preserveContent", "backgroundColor", "aria-label", "aria-labelledby"], outputs: ["selectedIndexChange", "focusChange", "animationDone", "selectedTabChange"], exportAs: ["matTabGroup"] }, { kind: "component", type: i8$1.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { kind: "component", type: i3$2.MatToolbar, selector: "mat-toolbar", inputs: ["color"], exportAs: ["matToolbar"] }, { kind: "component", type: WsDataControlComponent, selector: "app-ws-data-control", inputs: ["server", "wsServer", "jwtToken", "user", "path"] }, { kind: "component", type: WsMessagingComponent, selector: "app-ws-messaging", inputs: ["server", "wsServer", "jwtToken", "user", "path"] }, { kind: "component", type: WsNotificationsComponent, selector: "app-ws-notifications", inputs: ["server", "wsServer", "jwtToken", "user"] }, { kind: "component", type: WsAiMessagingComponent, selector: "app-ws-ai-messaging" }, { kind: "component", type: WsChatsComponent, selector: "app-ws-chats" }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }] }); }
|
|
12430
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: RequestManagerWsDemoComponent, selector: "app-request-manager-ws-demo", inputs: { server: "server", wsServer: "wsServer", jwtToken: "jwtToken", user: "user", path: "path" }, ngImport: i0, template: "<div style=\"margin: 2rem;\">\n\n <h2 style=\"display: flex;\">\n <span style=\"flex:1\">HTTP Request State Manager - Websockets</span>\n @if ((connectionStatus$ | async); as connected) {\n <span>\n WS -\n <span style=\"color: green;\">Connected</span>\n </span>\n } @else {\n <span style=\"color: red;\">Disconnected {{ retryCount$ | async }} / {{ maxRetries$ | async }}</span>\n }\n </h2>\n\n <div>\n\n @if ((user$ | async); as userInfo) {\n <div>\n <mat-toolbar>\n <div style=\"display: flex; flex:1\">\n <div style=\"flex:1\">{{ userInfo.name }}</div>\n <div>({{ userInfo.ldap }})</div>\n </div>\n </mat-toolbar>\n </div>\n }\n\n @if (!(connectionStatus$ | async) && !(connectionError$ | async) && ((retryCount$ | async) ?? 0) < ((maxRetries$ | async) ?? 0)) {\n <div>\n <mat-progress-bar mode=\"indeterminate\"></mat-progress-bar>\n </div>\n }\n\n @if (connectionError$ | async; as errorMsg) {\n <div style=\"padding: 0.75rem 1rem; background: #fdecea; color: #b00020; border-left: 4px solid #b00020; border-radius: 2px; margin-bottom: 0.5rem;\">\n {{ errorMsg }}\n </div>\n }\n\n <mat-tab-group animationDuration=\"0ms\" [selectedIndex]=\"1\">\n\n <mat-tab label=\"WS - Data Control\" [disabled]=\"!(connectionStatus$ | async)\">\n <!-- DATA CONTROL -->\n <app-ws-data-control\n [server]=\"server\"\n [wsServer]=\"wsServer\"\n [jwtToken]=\"jwtToken\"\n [user]=\"user\"\n [path]=\"path\"\n ></app-ws-data-control>\n\n </mat-tab>\n\n <mat-tab label=\"WS - Messaging\" [disabled]=\"!(connectionStatus$ | async)\">\n <!-- MESSAGING -->\n <app-ws-messaging\n [server]=\"server\"\n [wsServer]=\"wsServer\"\n [jwtToken]=\"jwtToken\"\n [user]=\"user\"\n [path]=\"path\"\n ></app-ws-messaging>\n\n </mat-tab>\n\n <mat-tab label=\"WS - Notifications\" [disabled]=\"!(connectionStatus$ | async)\">\n <!-- WS - Notifications -->\n <app-ws-notifications\n [server]=\"server\"\n [wsServer]=\"wsServer\"\n [jwtToken]=\"jwtToken\"\n [user]=\"user\"\n ></app-ws-notifications>\n </mat-tab>\n\n <mat-tab label=\"WS - Chats\" [disabled]=\"true\">\n <!-- WS - Chats -->\n <app-ws-chats></app-ws-chats>\n </mat-tab>\n\n <mat-tab label=\"WS - AI Messaging\" [disabled]=\"true\">\n <!-- WS - AI Messaging -->\n <app-ws-ai-messaging></app-ws-ai-messaging>\n </mat-tab>\n\n </mat-tab-group>\n</div>\n\n</div>\n\n", styles: [""], dependencies: [{ kind: "component", type: i1$2.MatTab, selector: "mat-tab", inputs: ["disabled", "label", "aria-label", "aria-labelledby", "labelClass", "bodyClass"], exportAs: ["matTab"] }, { kind: "component", type: i1$2.MatTabGroup, selector: "mat-tab-group", inputs: ["color", "fitInkBarToContent", "mat-stretch-tabs", "dynamicHeight", "selectedIndex", "headerPosition", "animationDuration", "contentTabIndex", "disablePagination", "disableRipple", "preserveContent", "backgroundColor", "aria-label", "aria-labelledby"], outputs: ["selectedIndexChange", "focusChange", "animationDone", "selectedTabChange"], exportAs: ["matTabGroup"] }, { kind: "component", type: i8$1.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { kind: "component", type: i3$2.MatToolbar, selector: "mat-toolbar", inputs: ["color"], exportAs: ["matToolbar"] }, { kind: "component", type: WsDataControlComponent, selector: "app-ws-data-control", inputs: ["server", "wsServer", "jwtToken", "user", "path"] }, { kind: "component", type: WsMessagingComponent, selector: "app-ws-messaging", inputs: ["server", "wsServer", "jwtToken", "user", "path"] }, { kind: "component", type: WsNotificationsComponent, selector: "app-ws-notifications", inputs: ["server", "wsServer", "jwtToken", "user"] }, { kind: "component", type: WsAiMessagingComponent, selector: "app-ws-ai-messaging" }, { kind: "component", type: WsChatsComponent, selector: "app-ws-chats" }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }] }); }
|
|
12444
12431
|
}
|
|
12445
12432
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: RequestManagerWsDemoComponent, decorators: [{
|
|
12446
12433
|
type: Component,
|
|
12447
|
-
args: [{ selector: 'app-request-manager-ws-demo', standalone: false, template: "<div style=\"margin: 2rem;\">\n\n <h2 style=\"display: flex;\">\n <span style=\"flex:1\">HTTP Request State Manager - Websockets</span>\n @if ((connectionStatus$ | async); as connected) {\n <span>\n WS -\n <span style=\"color: green;\">Connected</span>\n </span>\n } @else {\n <span style=\"color: red;\">Disconnected {{ retryCount$ | async }} / {{ maxRetries$ | async }}</span>\n }\n </h2>\n\n <div>\n\n @if ((user$ | async); as userInfo) {\n <div>\n <mat-toolbar>\n <div style=\"display: flex; flex:1\">\n <div style=\"flex:1\">{{ userInfo.name }}</div>\n <div>({{ userInfo.ldap }})</div>\n </div>\n </mat-toolbar>\n </div>\n }\n\n @if (!(connectionStatus$ | async) && ((retryCount$ | async) ?? 0) < ((maxRetries$ | async) ?? 0)) {\n <div>\n <mat-progress-bar mode=\"indeterminate\"></mat-progress-bar>\n </div>\n }\n\n <mat-tab-group animationDuration=\"0ms\" [selectedIndex]=\"1\">\n\n <mat-tab label=\"WS - Data Control\" [disabled]=\"!(connectionStatus$ | async)\">\n <!-- DATA CONTROL -->\n <app-ws-data-control\n [server]=\"server\"\n [wsServer]=\"wsServer\"\n [jwtToken]=\"jwtToken\"\n [user]=\"user\"\n [path]=\"path\"\n ></app-ws-data-control>\n\n </mat-tab>\n\n <mat-tab label=\"WS - Messaging\" [disabled]=\"!(connectionStatus$ | async)\">\n <!-- MESSAGING -->\n <app-ws-messaging\n [server]=\"server\"\n [wsServer]=\"wsServer\"\n [jwtToken]=\"jwtToken\"\n [user]=\"user\"\n [path]=\"path\"\n ></app-ws-messaging>\n\n </mat-tab>\n\n <mat-tab label=\"WS - Notifications\" [disabled]=\"!(connectionStatus$ | async)\">\n <!-- WS - Notifications -->\n <app-ws-notifications\n [server]=\"server\"\n [wsServer]=\"wsServer\"\n [jwtToken]=\"jwtToken\"\n [user]=\"user\"\n ></app-ws-notifications>\n </mat-tab>\n\n <mat-tab label=\"WS - Chats\" [disabled]=\"true\">\n <!-- WS - Chats -->\n <app-ws-chats></app-ws-chats>\n </mat-tab>\n\n <mat-tab label=\"WS - AI Messaging\" [disabled]=\"true\">\n <!-- WS - AI Messaging -->\n <app-ws-ai-messaging></app-ws-ai-messaging>\n </mat-tab>\n\n </mat-tab-group>\n</div>\n\n</div>\n\n" }]
|
|
12434
|
+
args: [{ selector: 'app-request-manager-ws-demo', standalone: false, template: "<div style=\"margin: 2rem;\">\n\n <h2 style=\"display: flex;\">\n <span style=\"flex:1\">HTTP Request State Manager - Websockets</span>\n @if ((connectionStatus$ | async); as connected) {\n <span>\n WS -\n <span style=\"color: green;\">Connected</span>\n </span>\n } @else {\n <span style=\"color: red;\">Disconnected {{ retryCount$ | async }} / {{ maxRetries$ | async }}</span>\n }\n </h2>\n\n <div>\n\n @if ((user$ | async); as userInfo) {\n <div>\n <mat-toolbar>\n <div style=\"display: flex; flex:1\">\n <div style=\"flex:1\">{{ userInfo.name }}</div>\n <div>({{ userInfo.ldap }})</div>\n </div>\n </mat-toolbar>\n </div>\n }\n\n @if (!(connectionStatus$ | async) && !(connectionError$ | async) && ((retryCount$ | async) ?? 0) < ((maxRetries$ | async) ?? 0)) {\n <div>\n <mat-progress-bar mode=\"indeterminate\"></mat-progress-bar>\n </div>\n }\n\n @if (connectionError$ | async; as errorMsg) {\n <div style=\"padding: 0.75rem 1rem; background: #fdecea; color: #b00020; border-left: 4px solid #b00020; border-radius: 2px; margin-bottom: 0.5rem;\">\n {{ errorMsg }}\n </div>\n }\n\n <mat-tab-group animationDuration=\"0ms\" [selectedIndex]=\"1\">\n\n <mat-tab label=\"WS - Data Control\" [disabled]=\"!(connectionStatus$ | async)\">\n <!-- DATA CONTROL -->\n <app-ws-data-control\n [server]=\"server\"\n [wsServer]=\"wsServer\"\n [jwtToken]=\"jwtToken\"\n [user]=\"user\"\n [path]=\"path\"\n ></app-ws-data-control>\n\n </mat-tab>\n\n <mat-tab label=\"WS - Messaging\" [disabled]=\"!(connectionStatus$ | async)\">\n <!-- MESSAGING -->\n <app-ws-messaging\n [server]=\"server\"\n [wsServer]=\"wsServer\"\n [jwtToken]=\"jwtToken\"\n [user]=\"user\"\n [path]=\"path\"\n ></app-ws-messaging>\n\n </mat-tab>\n\n <mat-tab label=\"WS - Notifications\" [disabled]=\"!(connectionStatus$ | async)\">\n <!-- WS - Notifications -->\n <app-ws-notifications\n [server]=\"server\"\n [wsServer]=\"wsServer\"\n [jwtToken]=\"jwtToken\"\n [user]=\"user\"\n ></app-ws-notifications>\n </mat-tab>\n\n <mat-tab label=\"WS - Chats\" [disabled]=\"true\">\n <!-- WS - Chats -->\n <app-ws-chats></app-ws-chats>\n </mat-tab>\n\n <mat-tab label=\"WS - AI Messaging\" [disabled]=\"true\">\n <!-- WS - AI Messaging -->\n <app-ws-ai-messaging></app-ws-ai-messaging>\n </mat-tab>\n\n </mat-tab-group>\n</div>\n\n</div>\n\n" }]
|
|
12448
12435
|
}], propDecorators: { server: [{
|
|
12449
12436
|
type: Input
|
|
12450
12437
|
}], wsServer: [{
|
|
@@ -12674,11 +12661,11 @@ class DatabaseDataDemoComponent {
|
|
|
12674
12661
|
});
|
|
12675
12662
|
}
|
|
12676
12663
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: DatabaseDataDemoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
12677
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: DatabaseDataDemoComponent, selector: "app-database-data-demo", ngImport: i0, template: "<div style=\"padding: 2rem;\">\n\n <h2>\n Database Manager Service Demo\n </h2>\n\n <div style=\"margin-bottom: 1rem; display: flex; gap: 1rem;\">\n <button mat-stroked-button\n color=\"primary\"\n (click)=\"clearAllData()\"\n >\n Clear Data\n </button>\n <button mat-stroked-button\n color=\"primary\"\n (click)=\"updateData()\"\n >\n Update Data\n </button>\n <div style=\"flex:1\"></div>\n <button\n mat-stroked-button\n color=\"warn\"\n [disabled]=\"!dataToDisplay.length\"\n (click)=\"removeData()\"\n >\n Remove Data\n </button>\n <button mat-stroked-button\n color=\"primary\"\n (click)=\"addData()\"\n >\n Add Data\n </button>\n </div>\n\n <div class=\"table-container\">\n <table mat-table [dataSource]=\"dataSource\">\n\n <ng-container matColumnDef=\"id\">\n <th mat-header-cell *matHeaderCellDef>ID</th>\n <td mat-cell *matCellDef=\"let element\">{{element.id}}</td>\n </ng-container>\n\n <ng-container matColumnDef=\"last_name\">\n <th mat-header-cell *matHeaderCellDef>Last Name</th>\n <td mat-cell *matCellDef=\"let element\">{{element.last_name}}</td>\n </ng-container>\n\n <ng-container matColumnDef=\"age\">\n <th mat-header-cell *matHeaderCellDef>Age</th>\n <td mat-cell *matCellDef=\"let element\">{{element.age}}</td>\n </ng-container>\n\n <ng-container matColumnDef=\"amount\">\n <th mat-header-cell *matHeaderCellDef>Amount</th>\n <td mat-cell *matCellDef=\"let element\">{{element.amount | currency}}</td>\n </ng-container>\n\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns;\"></tr>\n </table>\n </div>\n\n <!-- \u2500\u2500 SQL Query Section \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <mat-divider style=\"margin: 2rem 0;\"></mat-divider>\n\n <h3 style=\"margin-bottom: 1rem;\">SQL Query with DexieJS</h3>\n\n <div style=\"display: flex; gap: 1rem; align-items: flex-start;\">\n <mat-form-field style=\"flex: 1;\" appearance=\"outline\">\n <mat-label>SQL Query</mat-label>\n <textarea\n matInput\n [(ngModel)]=\"sqlQuery\"\n rows=\"3\"\n placeholder=\"e.g. SELECT * FROM sample_table WHERE age > 20\"\n (keydown.control.enter)=\"runSqlQuery()\"\n ></textarea>\n
|
|
12664
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: DatabaseDataDemoComponent, selector: "app-database-data-demo", ngImport: i0, template: "<div style=\"padding: 2rem;\">\n\n <h2>\n Database Manager Service Demo\n </h2>\n\n <div style=\"margin-bottom: 1rem; display: flex; gap: 1rem;\">\n <button mat-stroked-button\n color=\"primary\"\n (click)=\"clearAllData()\"\n >\n Clear Data\n </button>\n <button mat-stroked-button\n color=\"primary\"\n (click)=\"updateData()\"\n >\n Update Data\n </button>\n <div style=\"flex:1\"></div>\n <button\n mat-stroked-button\n color=\"warn\"\n [disabled]=\"!dataToDisplay.length\"\n (click)=\"removeData()\"\n >\n Remove Data\n </button>\n <button mat-stroked-button\n color=\"primary\"\n (click)=\"addData()\"\n >\n Add Data\n </button>\n </div>\n\n <div class=\"table-container\">\n <table mat-table [dataSource]=\"dataSource\">\n\n <ng-container matColumnDef=\"id\">\n <th mat-header-cell *matHeaderCellDef>ID</th>\n <td mat-cell *matCellDef=\"let element\">{{element.id}}</td>\n </ng-container>\n\n <ng-container matColumnDef=\"last_name\">\n <th mat-header-cell *matHeaderCellDef>Last Name</th>\n <td mat-cell *matCellDef=\"let element\">{{element.last_name}}</td>\n </ng-container>\n\n <ng-container matColumnDef=\"age\">\n <th mat-header-cell *matHeaderCellDef>Age</th>\n <td mat-cell *matCellDef=\"let element\">{{element.age}}</td>\n </ng-container>\n\n <ng-container matColumnDef=\"amount\">\n <th mat-header-cell *matHeaderCellDef>Amount</th>\n <td mat-cell *matCellDef=\"let element\">{{element.amount | currency}}</td>\n </ng-container>\n\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns;\"></tr>\n </table>\n </div>\n\n <!-- \u2500\u2500 SQL Query Section \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <mat-divider style=\"margin: 2rem 0;\"></mat-divider>\n\n <h3 style=\"margin-bottom: 1rem;\">SQL Query with DexieJS</h3>\n\n <div style=\"display: flex; gap: 1rem; align-items: flex-start;\">\n <mat-form-field style=\"flex: 1;\" appearance=\"outline\">\n <mat-label>SQL Query</mat-label>\n <textarea\n matInput\n [(ngModel)]=\"sqlQuery\"\n rows=\"3\"\n placeholder=\"e.g. SELECT * FROM sample_table WHERE age > 20\"\n (keydown.control.enter)=\"runSqlQuery()\"\n ></textarea>\n </mat-form-field>\n </div>\n\n <div style=\"display: flex;\">\n <div style=\"flex:1\"></div>\n <button\n mat-flat-button\n color=\"primary\"\n style=\"margin-top: 4px;\"\n [disabled]=\"sqlLoading || !sqlQuery.trim()\"\n (click)=\"runSqlQuery()\"\n >\n {{ sqlLoading ? 'Running\u2026' : 'Execute' }}\n </button>\n </div>\n\n <div style=\"margin-top: 1rem;\">\n <mat-divider></mat-divider>\n </div>\n\n <!-- Error -->\n <div *ngIf=\"sqlError\" style=\"color: #d32f2f; margin: 0.5rem 0 1rem; font-size: 0.875rem;\">\n <mat-icon style=\"vertical-align: middle; font-size: 16px; height: 16px; width: 16px;\">error</mat-icon>\n {{ sqlError }}\n </div>\n\n <!-- Results table (dynamic columns) -->\n <div *ngIf=\"!sqlLoading && sqlResults.length > 0\" class=\"table-container\" style=\"margin-top: 1rem;\">\n <div>\n {{ sqlResults | json }}\n </div>\n <p style=\"font-size: 0.8rem; color: #666; margin-top: 0.5rem;\">\n {{ sqlResults.length }} row{{ sqlResults.length === 1 ? '' : 's' }} returned\n </p>\n </div>\n\n <!-- Empty state -->\n <p *ngIf=\"!sqlLoading && !sqlError && sqlResults.length === 0 && sqlQuery.trim()\"\n style=\"color: #888; font-size: 0.875rem; margin-top: 0.5rem;\">\n No results to display. Execute a query above.\n </p>\n\n</div>\n", styles: [""], dependencies: [{ kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i3.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i4.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4.MatLabel, selector: "mat-label" }, { kind: "component", type: i8.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i9.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i9.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i9.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i9.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i9.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i9.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i9.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i9.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i9.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i9.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "component", type: i12.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "directive", type: i13.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "pipe", type: i1$1.JsonPipe, name: "json" }, { kind: "pipe", type: i1$1.CurrencyPipe, name: "currency" }] }); }
|
|
12678
12665
|
}
|
|
12679
12666
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: DatabaseDataDemoComponent, decorators: [{
|
|
12680
12667
|
type: Component,
|
|
12681
|
-
args: [{ selector: 'app-database-data-demo', standalone: false, template: "<div style=\"padding: 2rem;\">\n\n <h2>\n Database Manager Service Demo\n </h2>\n\n <div style=\"margin-bottom: 1rem; display: flex; gap: 1rem;\">\n <button mat-stroked-button\n color=\"primary\"\n (click)=\"clearAllData()\"\n >\n Clear Data\n </button>\n <button mat-stroked-button\n color=\"primary\"\n (click)=\"updateData()\"\n >\n Update Data\n </button>\n <div style=\"flex:1\"></div>\n <button\n mat-stroked-button\n color=\"warn\"\n [disabled]=\"!dataToDisplay.length\"\n (click)=\"removeData()\"\n >\n Remove Data\n </button>\n <button mat-stroked-button\n color=\"primary\"\n (click)=\"addData()\"\n >\n Add Data\n </button>\n </div>\n\n <div class=\"table-container\">\n <table mat-table [dataSource]=\"dataSource\">\n\n <ng-container matColumnDef=\"id\">\n <th mat-header-cell *matHeaderCellDef>ID</th>\n <td mat-cell *matCellDef=\"let element\">{{element.id}}</td>\n </ng-container>\n\n <ng-container matColumnDef=\"last_name\">\n <th mat-header-cell *matHeaderCellDef>Last Name</th>\n <td mat-cell *matCellDef=\"let element\">{{element.last_name}}</td>\n </ng-container>\n\n <ng-container matColumnDef=\"age\">\n <th mat-header-cell *matHeaderCellDef>Age</th>\n <td mat-cell *matCellDef=\"let element\">{{element.age}}</td>\n </ng-container>\n\n <ng-container matColumnDef=\"amount\">\n <th mat-header-cell *matHeaderCellDef>Amount</th>\n <td mat-cell *matCellDef=\"let element\">{{element.amount | currency}}</td>\n </ng-container>\n\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns;\"></tr>\n </table>\n </div>\n\n <!-- \u2500\u2500 SQL Query Section \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <mat-divider style=\"margin: 2rem 0;\"></mat-divider>\n\n <h3 style=\"margin-bottom: 1rem;\">SQL Query with DexieJS</h3>\n\n <div style=\"display: flex; gap: 1rem; align-items: flex-start;\">\n <mat-form-field style=\"flex: 1;\" appearance=\"outline\">\n <mat-label>SQL Query</mat-label>\n <textarea\n matInput\n [(ngModel)]=\"sqlQuery\"\n rows=\"3\"\n placeholder=\"e.g. SELECT * FROM sample_table WHERE age > 20\"\n (keydown.control.enter)=\"runSqlQuery()\"\n ></textarea>\n
|
|
12668
|
+
args: [{ selector: 'app-database-data-demo', standalone: false, template: "<div style=\"padding: 2rem;\">\n\n <h2>\n Database Manager Service Demo\n </h2>\n\n <div style=\"margin-bottom: 1rem; display: flex; gap: 1rem;\">\n <button mat-stroked-button\n color=\"primary\"\n (click)=\"clearAllData()\"\n >\n Clear Data\n </button>\n <button mat-stroked-button\n color=\"primary\"\n (click)=\"updateData()\"\n >\n Update Data\n </button>\n <div style=\"flex:1\"></div>\n <button\n mat-stroked-button\n color=\"warn\"\n [disabled]=\"!dataToDisplay.length\"\n (click)=\"removeData()\"\n >\n Remove Data\n </button>\n <button mat-stroked-button\n color=\"primary\"\n (click)=\"addData()\"\n >\n Add Data\n </button>\n </div>\n\n <div class=\"table-container\">\n <table mat-table [dataSource]=\"dataSource\">\n\n <ng-container matColumnDef=\"id\">\n <th mat-header-cell *matHeaderCellDef>ID</th>\n <td mat-cell *matCellDef=\"let element\">{{element.id}}</td>\n </ng-container>\n\n <ng-container matColumnDef=\"last_name\">\n <th mat-header-cell *matHeaderCellDef>Last Name</th>\n <td mat-cell *matCellDef=\"let element\">{{element.last_name}}</td>\n </ng-container>\n\n <ng-container matColumnDef=\"age\">\n <th mat-header-cell *matHeaderCellDef>Age</th>\n <td mat-cell *matCellDef=\"let element\">{{element.age}}</td>\n </ng-container>\n\n <ng-container matColumnDef=\"amount\">\n <th mat-header-cell *matHeaderCellDef>Amount</th>\n <td mat-cell *matCellDef=\"let element\">{{element.amount | currency}}</td>\n </ng-container>\n\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns;\"></tr>\n </table>\n </div>\n\n <!-- \u2500\u2500 SQL Query Section \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <mat-divider style=\"margin: 2rem 0;\"></mat-divider>\n\n <h3 style=\"margin-bottom: 1rem;\">SQL Query with DexieJS</h3>\n\n <div style=\"display: flex; gap: 1rem; align-items: flex-start;\">\n <mat-form-field style=\"flex: 1;\" appearance=\"outline\">\n <mat-label>SQL Query</mat-label>\n <textarea\n matInput\n [(ngModel)]=\"sqlQuery\"\n rows=\"3\"\n placeholder=\"e.g. SELECT * FROM sample_table WHERE age > 20\"\n (keydown.control.enter)=\"runSqlQuery()\"\n ></textarea>\n </mat-form-field>\n </div>\n\n <div style=\"display: flex;\">\n <div style=\"flex:1\"></div>\n <button\n mat-flat-button\n color=\"primary\"\n style=\"margin-top: 4px;\"\n [disabled]=\"sqlLoading || !sqlQuery.trim()\"\n (click)=\"runSqlQuery()\"\n >\n {{ sqlLoading ? 'Running\u2026' : 'Execute' }}\n </button>\n </div>\n\n <div style=\"margin-top: 1rem;\">\n <mat-divider></mat-divider>\n </div>\n\n <!-- Error -->\n <div *ngIf=\"sqlError\" style=\"color: #d32f2f; margin: 0.5rem 0 1rem; font-size: 0.875rem;\">\n <mat-icon style=\"vertical-align: middle; font-size: 16px; height: 16px; width: 16px;\">error</mat-icon>\n {{ sqlError }}\n </div>\n\n <!-- Results table (dynamic columns) -->\n <div *ngIf=\"!sqlLoading && sqlResults.length > 0\" class=\"table-container\" style=\"margin-top: 1rem;\">\n <div>\n {{ sqlResults | json }}\n </div>\n <p style=\"font-size: 0.8rem; color: #666; margin-top: 0.5rem;\">\n {{ sqlResults.length }} row{{ sqlResults.length === 1 ? '' : 's' }} returned\n </p>\n </div>\n\n <!-- Empty state -->\n <p *ngIf=\"!sqlLoading && !sqlError && sqlResults.length === 0 && sqlQuery.trim()\"\n style=\"color: #888; font-size: 0.875rem; margin-top: 0.5rem;\">\n No results to display. Execute a query above.\n </p>\n\n</div>\n" }]
|
|
12682
12669
|
}], ctorParameters: () => [] });
|
|
12683
12670
|
class DatabaseDataSource extends DataSource {
|
|
12684
12671
|
constructor(initialData) {
|