@fhss-web-team/frontend-utils 1.7.3 → 1.7.5
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/fesm2022/fhss-web-team-frontend-utils.mjs +239 -313
- package/fesm2022/fhss-web-team-frontend-utils.mjs.map +1 -1
- package/lib/components/fhss-table/fhss-table.component.d.ts +5 -4
- package/lib/components/fhss-table/fhss-table.types.d.ts +8 -7
- package/package.json +1 -1
- package/public-api.d.ts +0 -1
- package/lib/components/user-management/user-management.component.d.ts +0 -26
- package/lib/components/user-management/user-management.service.d.ts +0 -28
- package/lib/components/user-management/user-management.types.d.ts +0 -15
|
@@ -1,27 +1,24 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Component, InjectionToken, inject, Injector, signal, afterNextRender, effect, computed, Injectable, input,
|
|
2
|
+
import { Component, InjectionToken, inject, Injector, signal, afterNextRender, effect, computed, Injectable, input, model, linkedSignal, untracked } from '@angular/core';
|
|
3
3
|
import * as i1 from '@angular/router';
|
|
4
4
|
import { Router, RouterModule, RedirectCommand } from '@angular/router';
|
|
5
5
|
import { KEYCLOAK_EVENT_SIGNAL, KeycloakEventType, typeEventArgs } from 'keycloak-angular';
|
|
6
6
|
import Keycloak from 'keycloak-js';
|
|
7
|
+
import { isTRPCClientError } from '@trpc/client';
|
|
7
8
|
import * as i1$1 from '@angular/material/table';
|
|
8
9
|
import { MatTableModule } from '@angular/material/table';
|
|
10
|
+
import * as i2 from '@angular/material/progress-spinner';
|
|
11
|
+
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
|
9
12
|
import * as i3 from '@angular/material/paginator';
|
|
10
|
-
import { MatPaginatorModule
|
|
11
|
-
import * as
|
|
12
|
-
import {
|
|
13
|
-
import
|
|
14
|
-
import * as i4 from '@angular/forms';
|
|
13
|
+
import { MatPaginatorModule } from '@angular/material/paginator';
|
|
14
|
+
import * as i4 from '@angular/material/input';
|
|
15
|
+
import { MatInputModule } from '@angular/material/input';
|
|
16
|
+
import * as i5 from '@angular/forms';
|
|
15
17
|
import { FormsModule } from '@angular/forms';
|
|
16
|
-
import * as i5 from '@angular/material/input';
|
|
17
|
-
import { MatInputModule, MatFormField } from '@angular/material/input';
|
|
18
|
-
import * as i6 from '@angular/material/select';
|
|
19
|
-
import { MatSelectModule } from '@angular/material/select';
|
|
20
|
-
import { isTRPCClientError } from '@trpc/client';
|
|
21
|
-
import * as i2$1 from '@angular/material/progress-spinner';
|
|
22
|
-
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
|
23
18
|
import * as i1$2 from '@angular/material/button';
|
|
24
19
|
import { MatButtonModule } from '@angular/material/button';
|
|
20
|
+
import * as i7 from '@angular/material/sort';
|
|
21
|
+
import { MatSortModule } from '@angular/material/sort';
|
|
25
22
|
import * as i8 from '@angular/material/icon';
|
|
26
23
|
import { MatIconModule } from '@angular/material/icon';
|
|
27
24
|
import * as i9 from '@angular/material/core';
|
|
@@ -263,290 +260,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImpo
|
|
|
263
260
|
args: [{ selector: 'byu-header', imports: [RouterModule], template: "<header>\n <div class=\"top\" >\n <img class=\"logo\" src=\"/BYU_monogram_white@2x.png\" alt=\"BYU\">\n <div class=\"titles\"> \n <div class=\"breadcrumbs\">\n @for (breadcrumb of config()?.breadcrumbs; track breadcrumb.text){\n <a [href]=\"breadcrumb.path\" >{{ breadcrumb.text }}</a>\n }\n </div>\n <a [routerLink]=\"config()?.title?.path\" class=\"title\">{{ config()?.title?.text }}</a>\n <a [routerLink]=\"config()?.subtitle?.path\" class=\"subtitle\">{{ config()?.subtitle?.text }}</a>\n </div>\n <div class=\"signin\">\n <p>{{ this.auth.tokenParsed()?.['given_name'] ?? '' }}</p>\n <svg class=\"signin-icon\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 100 100\">\n <path fill=\"currentcolor\" d=\"M50 95c-26 0-34-18-34-18 3-12 8-18 17-18 5 5 10 7 17 7s12-2 17-7c9 0 14 6 17 18 0 0-7 18-34 18z\"></path>\n <circle cx=\"50\" cy=\"50\" r=\"45\" fill=\"none\" stroke=\"currentcolor\" stroke-width=\"10\"></circle>\n <circle fill=\"currentcolor\" cx=\"50\" cy=\"40\" r=\"20\"></circle>\n </svg>\n @if (auth.authenticated()) {\n <a class=\"signin-link\" (click)=\"auth.logout()\">Sign Out</a>\n } @else {\n <a class=\"signin-link\" (click)=\"auth.login()\">Sign In</a>\n }\n </div>\n </div>\n <div class=\"bottom\">\n <nav>\n @for (menuItem of config()?.menu; track menuItem.text){\n @if (isHeaderLink(menuItem)) {\n <li class = \"nav-item\">\n <a class=\"nav-item-content\" [routerLink]=\"menuItem.path\">{{ menuItem.text }}</a>\n </li>\n } @else {\n <li class=\"nav-item dropdown\" (click)=\"toggleDropdown(menuItem.text)\">\n <div class=\"nav-item-content\" >{{ menuItem.text }}</div>\n @if (openDropdownText === menuItem.text) {\n <ul class = \"dropdown-item-menu\"> \n @for(dropItem of menuItem.items; track dropItem.text){\n <li class = \"dropdown-item\">\n <a class=\"dropdown-item-content\" [routerLink]=\"dropItem.path\">{{ dropItem.text }}</a>\n </li>\n }\n </ul>\n }\n </li>\n }\n }\n </nav>\n </div>\n</header>\n", styles: ["header{font-family:HCo Ringside Narrow SSm,Open Sans,Helvetica,Arial,sans-serif;color:#fff}header .top{background-color:#002e5d;display:flex;align-items:center;padding:13px 16px;gap:16px}header .top .logo{width:100px}header .top .titles{display:flex;flex-direction:column;gap:8px;padding-left:30px;border-left:1px solid rgba(255,255,255,.25)}header .top .titles .breadcrumbs{display:flex;flex-direction:row}header .top .titles .breadcrumbs a{color:#a6abb1;text-decoration:none;font-size:16px}header .top .titles .breadcrumbs a:not(:first-child){padding-left:10px}header .top .titles .breadcrumbs a:not(:last-child){padding-right:10px;border-right:1px solid rgba(255,255,255,.25)}header .top .titles .breadcrumbs a:hover{color:#fff}header .top .titles .title{color:inherit;font-size:24px;font-weight:500;text-decoration:none}header .top .titles .subtitle{color:inherit;font-size:16px;font-weight:500;text-decoration:none}header .top .signin{display:flex;align-items:center;gap:10px;font-size:16px;margin-left:auto}header .top .signin .signin-icon{display:flex;margin-left:auto;margin-right:0;align-items:center;height:20px;width:20px}header .top .signin .signin-link{color:#fff;text-decoration:none;cursor:pointer}header .bottom{box-shadow:0 3px 10px #ccc5c580}header .bottom nav{display:flex;flex-direction:row;padding-left:124px}header .bottom nav .nav-item{display:block;list-style:none;transition:all .25s;text-decoration:none}header .bottom nav .nav-item:hover{box-shadow:inset 0 -5px #002e5d;background-color:#f1f1f1}header .bottom nav .nav-item .nav-item-content{margin:5px;display:inline-block;padding:11px 22px;text-decoration:none;color:#002e5d}header .bottom nav .nav-item.dropdown{position:relative}header .bottom nav .nav-item.dropdown .dropdown-item-menu{position:absolute;background:#fff;z-index:1000;top:100%;width:min-content;margin:-5px;padding:0;box-shadow:0 3px 3px #ccc5c5bf}header .bottom nav .nav-item.dropdown .dropdown-item-menu .dropdown-item:hover{background-color:#f1f1f1}header .bottom nav .nav-item.dropdown .dropdown-item-menu .dropdown-item .dropdown-item-content{margin:10px;display:inline-block;text-decoration:none;text-wrap:nowrap;color:#002e5d;padding:11px 22px}\n"] }]
|
|
264
261
|
}] });
|
|
265
262
|
|
|
266
|
-
const debounced = (inputSignal, wait = 400) => {
|
|
267
|
-
const debouncedSignal = signal(inputSignal());
|
|
268
|
-
const setSignal = debounce((value) => debouncedSignal.set(value), wait);
|
|
269
|
-
effect(() => {
|
|
270
|
-
setSignal(inputSignal());
|
|
271
|
-
});
|
|
272
|
-
return debouncedSignal;
|
|
273
|
-
};
|
|
274
|
-
const debounce = (callback, wait) => {
|
|
275
|
-
let timeoutId;
|
|
276
|
-
return (...args) => {
|
|
277
|
-
window.clearTimeout(timeoutId);
|
|
278
|
-
timeoutId = window.setTimeout(() => {
|
|
279
|
-
callback(...args);
|
|
280
|
-
}, wait);
|
|
281
|
-
};
|
|
282
|
-
};
|
|
283
|
-
|
|
284
|
-
/**
|
|
285
|
-
* Creates a reactive fetch signal.
|
|
286
|
-
*
|
|
287
|
-
* The request function can include Signals for properties. These are unwrapped in the refresh function.
|
|
288
|
-
*/
|
|
289
|
-
function createFetchSignal(request, method, transform, options) {
|
|
290
|
-
// Use a computed signal so that any changes to Signals in the request object trigger updates.
|
|
291
|
-
const currentRequest = computed(request);
|
|
292
|
-
const value = signal(options?.defaultValue, { equal: options?.equal });
|
|
293
|
-
const errorResponse = signal(undefined);
|
|
294
|
-
const isLoading = signal(false);
|
|
295
|
-
const statusCode = signal(undefined);
|
|
296
|
-
const headers = signal(undefined);
|
|
297
|
-
const status = signal('idle');
|
|
298
|
-
const error = signal(undefined);
|
|
299
|
-
const injector = inject(Injector);
|
|
300
|
-
let effectRef = undefined;
|
|
301
|
-
if (options?.autoRefresh) {
|
|
302
|
-
effectRef = effect((onCleanup) => {
|
|
303
|
-
// pass abort signal to refresh on cleanup of effect
|
|
304
|
-
const controller = new AbortController();
|
|
305
|
-
onCleanup(() => controller.abort());
|
|
306
|
-
// call refresh with this abort controller
|
|
307
|
-
refresh(controller.signal, true);
|
|
308
|
-
}, { injector: options?.injector || injector });
|
|
309
|
-
}
|
|
310
|
-
const refresh = async (abortSignal, keepLoadingThroughAbort) => {
|
|
311
|
-
// if the fetchSignal has been destroyed, do nothing
|
|
312
|
-
if (untracked(status) === 'destroyed')
|
|
313
|
-
return;
|
|
314
|
-
// Reset signals for a fresh request.
|
|
315
|
-
isLoading.set(true);
|
|
316
|
-
errorResponse.set(undefined);
|
|
317
|
-
statusCode.set(undefined);
|
|
318
|
-
headers.set(undefined);
|
|
319
|
-
status.set('loading');
|
|
320
|
-
error.set(undefined);
|
|
321
|
-
// Unwrap the current request.
|
|
322
|
-
const req = currentRequest();
|
|
323
|
-
const url = req.url;
|
|
324
|
-
const params = req.params;
|
|
325
|
-
const requestHeaders = req.headers;
|
|
326
|
-
const body = req.body;
|
|
327
|
-
// Build URL with query parameters.
|
|
328
|
-
let uri = url;
|
|
329
|
-
if (params) {
|
|
330
|
-
const searchParams = new URLSearchParams();
|
|
331
|
-
for (const key in params) {
|
|
332
|
-
if (params[key] !== undefined)
|
|
333
|
-
searchParams.append(key, String(params[key]));
|
|
334
|
-
}
|
|
335
|
-
uri += (uri.includes('?') ? '&' : '?') + searchParams.toString();
|
|
336
|
-
}
|
|
337
|
-
// Filter out undefined header values
|
|
338
|
-
const filteredHeaders = requestHeaders
|
|
339
|
-
? Object.fromEntries(Object.entries(requestHeaders).filter(([, value]) => value !== undefined))
|
|
340
|
-
: undefined;
|
|
341
|
-
try {
|
|
342
|
-
// send the request
|
|
343
|
-
const response = await fetch(uri, {
|
|
344
|
-
method,
|
|
345
|
-
headers: filteredHeaders,
|
|
346
|
-
// Only include a body if one is provided.
|
|
347
|
-
body: body,
|
|
348
|
-
signal: abortSignal,
|
|
349
|
-
});
|
|
350
|
-
// set the status code
|
|
351
|
-
statusCode.set(response.status);
|
|
352
|
-
// Extract response headers.
|
|
353
|
-
const headersObj = {};
|
|
354
|
-
response.headers.forEach((val, key) => {
|
|
355
|
-
headersObj[key] = val;
|
|
356
|
-
});
|
|
357
|
-
headers.set(headersObj);
|
|
358
|
-
// if the response is ok, transform the body
|
|
359
|
-
if (response.ok) {
|
|
360
|
-
value.set(await transform(response));
|
|
361
|
-
status.set('resolved');
|
|
362
|
-
}
|
|
363
|
-
else {
|
|
364
|
-
// try to parse the error as json
|
|
365
|
-
try {
|
|
366
|
-
errorResponse.set(await response.json());
|
|
367
|
-
value.set(undefined);
|
|
368
|
-
status.set('resolved');
|
|
369
|
-
}
|
|
370
|
-
catch {
|
|
371
|
-
throw new Error('Unable to parse error response.');
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
catch (err) {
|
|
376
|
-
if (err instanceof Error) {
|
|
377
|
-
// if the fetch request was aborted
|
|
378
|
-
// we check if we would like to continue loading (the next request)
|
|
379
|
-
// if so then we just leave this refresh in an undefined state
|
|
380
|
-
// else we error as usual
|
|
381
|
-
if (err.name === 'AbortError' && keepLoadingThroughAbort) {
|
|
382
|
-
return;
|
|
383
|
-
}
|
|
384
|
-
error.set(err);
|
|
385
|
-
}
|
|
386
|
-
else {
|
|
387
|
-
// Fallback for non-Error values
|
|
388
|
-
error.set(new Error(String(err)));
|
|
389
|
-
}
|
|
390
|
-
value.set(undefined);
|
|
391
|
-
status.set('error');
|
|
392
|
-
}
|
|
393
|
-
isLoading.set(false);
|
|
394
|
-
};
|
|
395
|
-
const destroy = () => {
|
|
396
|
-
// if the fetchSignal has been destroyed, do nothing
|
|
397
|
-
if (status() === 'destroyed')
|
|
398
|
-
return;
|
|
399
|
-
if (effectRef) {
|
|
400
|
-
effectRef.destroy();
|
|
401
|
-
}
|
|
402
|
-
status.set('destroyed');
|
|
403
|
-
value.set(undefined);
|
|
404
|
-
errorResponse.set(undefined);
|
|
405
|
-
isLoading.set(false);
|
|
406
|
-
statusCode.set(undefined);
|
|
407
|
-
headers.set(undefined);
|
|
408
|
-
error.set(undefined);
|
|
409
|
-
};
|
|
410
|
-
return {
|
|
411
|
-
value,
|
|
412
|
-
errorResponse,
|
|
413
|
-
isLoading,
|
|
414
|
-
statusCode,
|
|
415
|
-
headers,
|
|
416
|
-
status,
|
|
417
|
-
error,
|
|
418
|
-
refresh,
|
|
419
|
-
destroy
|
|
420
|
-
};
|
|
421
|
-
}
|
|
422
|
-
//
|
|
423
|
-
// Helpers for attaching response transforms.
|
|
424
|
-
//
|
|
425
|
-
const createHelper = (method, transform) => (request, options) => createFetchSignal(request, method, transform, options);
|
|
426
|
-
// Transforms
|
|
427
|
-
const jsonTransformer = (response) => response.json();
|
|
428
|
-
const textTransformer = (response) => response.text();
|
|
429
|
-
const blobTransformer = (response) => response.blob();
|
|
430
|
-
const arrayBufferTransformer = (response) => response.arrayBuffer();
|
|
431
|
-
//
|
|
432
|
-
// Build the defaults - GET chain
|
|
433
|
-
//
|
|
434
|
-
const fetchSignal = createHelper('GET', jsonTransformer);
|
|
435
|
-
fetchSignal.json = createHelper('GET', jsonTransformer);
|
|
436
|
-
fetchSignal.text = createHelper('GET', textTransformer);
|
|
437
|
-
fetchSignal.blob = createHelper('GET', blobTransformer);
|
|
438
|
-
fetchSignal.arrayBuffer = createHelper('GET', arrayBufferTransformer);
|
|
439
|
-
//
|
|
440
|
-
// Build the GET chain
|
|
441
|
-
//
|
|
442
|
-
fetchSignal.get = createHelper('GET', jsonTransformer);
|
|
443
|
-
fetchSignal.get.json = createHelper('GET', jsonTransformer);
|
|
444
|
-
fetchSignal.get.text = createHelper('GET', textTransformer);
|
|
445
|
-
fetchSignal.get.blob = createHelper('GET', blobTransformer);
|
|
446
|
-
fetchSignal.get.arrayBuffer = createHelper('GET', arrayBufferTransformer);
|
|
447
|
-
//
|
|
448
|
-
// Build the POST chain.
|
|
449
|
-
//
|
|
450
|
-
fetchSignal.post = createHelper('POST', jsonTransformer);
|
|
451
|
-
fetchSignal.post.json = createHelper('POST', jsonTransformer);
|
|
452
|
-
fetchSignal.post.text = createHelper('POST', textTransformer);
|
|
453
|
-
fetchSignal.post.blob = createHelper('POST', blobTransformer);
|
|
454
|
-
fetchSignal.post.arrayBuffer = createHelper('POST', arrayBufferTransformer);
|
|
455
|
-
//
|
|
456
|
-
// Build the PUT chain.
|
|
457
|
-
//
|
|
458
|
-
fetchSignal.put = createHelper('PUT', jsonTransformer);
|
|
459
|
-
fetchSignal.put.json = createHelper('PUT', jsonTransformer);
|
|
460
|
-
fetchSignal.put.text = createHelper('PUT', textTransformer);
|
|
461
|
-
fetchSignal.put.blob = createHelper('PUT', blobTransformer);
|
|
462
|
-
fetchSignal.put.arrayBuffer = createHelper('PUT', arrayBufferTransformer);
|
|
463
|
-
//
|
|
464
|
-
// Build the PATCH chain.
|
|
465
|
-
//
|
|
466
|
-
fetchSignal.patch = createHelper('PATCH', jsonTransformer);
|
|
467
|
-
fetchSignal.patch.json = createHelper('PATCH', jsonTransformer);
|
|
468
|
-
fetchSignal.patch.text = createHelper('PATCH', textTransformer);
|
|
469
|
-
fetchSignal.patch.blob = createHelper('PATCH', blobTransformer);
|
|
470
|
-
fetchSignal.patch.arrayBuffer = createHelper('PATCH', arrayBufferTransformer);
|
|
471
|
-
//
|
|
472
|
-
// Build the DELETE chain
|
|
473
|
-
//
|
|
474
|
-
fetchSignal.delete = createHelper('DELETE', jsonTransformer);
|
|
475
|
-
fetchSignal.delete.json = createHelper('DELETE', jsonTransformer);
|
|
476
|
-
fetchSignal.delete.text = createHelper('DELETE', textTransformer);
|
|
477
|
-
fetchSignal.delete.blob = createHelper('DELETE', blobTransformer);
|
|
478
|
-
fetchSignal.delete.arrayBuffer = createHelper('DELETE', arrayBufferTransformer);
|
|
479
|
-
|
|
480
|
-
class UserManagementService {
|
|
481
|
-
auth = inject(AuthService);
|
|
482
|
-
getUsers(search, accountTypes, sortBy, sortDirection, pageCount, pageOffset, createdAfter, createdBefore) {
|
|
483
|
-
return fetchSignal(() => ({
|
|
484
|
-
url: '/api/user-management',
|
|
485
|
-
params: {
|
|
486
|
-
search: search(),
|
|
487
|
-
account_types: accountTypes().join(','),
|
|
488
|
-
sort_by: sortBy(),
|
|
489
|
-
sort_direction: sortDirection(),
|
|
490
|
-
page_count: pageCount(),
|
|
491
|
-
page_offset: pageOffset(),
|
|
492
|
-
created_after: createdAfter && createdAfter().toISOString(),
|
|
493
|
-
created_before: createdBefore && createdBefore().toISOString(),
|
|
494
|
-
},
|
|
495
|
-
headers: {
|
|
496
|
-
Authorization: this.auth.bearerToken()
|
|
497
|
-
}
|
|
498
|
-
}), { autoRefresh: true });
|
|
499
|
-
}
|
|
500
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: UserManagementService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
501
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: UserManagementService, providedIn: 'root' });
|
|
502
|
-
}
|
|
503
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: UserManagementService, decorators: [{
|
|
504
|
-
type: Injectable,
|
|
505
|
-
args: [{
|
|
506
|
-
providedIn: 'root'
|
|
507
|
-
}]
|
|
508
|
-
}] });
|
|
509
|
-
|
|
510
|
-
class UserManagementComponent {
|
|
511
|
-
api = inject(UserManagementService);
|
|
512
|
-
displayedColumns = ['netId', 'preferredFirstName', 'preferredLastName', 'roles', 'accountType', 'created'];
|
|
513
|
-
accountTypeOptions = ['NonBYU', 'Student', 'Employee'];
|
|
514
|
-
paginator;
|
|
515
|
-
sort;
|
|
516
|
-
search = signal('');
|
|
517
|
-
accountTypes = signal(['NonBYU', 'Student', 'Employee']);
|
|
518
|
-
sortBy = signal('netId');
|
|
519
|
-
sortDirection = signal('asc');
|
|
520
|
-
pageCount = signal(5);
|
|
521
|
-
pageOffset = signal(0);
|
|
522
|
-
getUsers = this.api.getUsers(debounced(this.search), this.accountTypes, this.sortBy, this.sortDirection, this.pageCount, this.pageOffset);
|
|
523
|
-
ngAfterViewInit() {
|
|
524
|
-
// write the observables from the sort and the paging to the signals
|
|
525
|
-
this.sort.sortChange.subscribe(({ active, direction }) => {
|
|
526
|
-
this.sortBy.set(active);
|
|
527
|
-
this.sortDirection.set(direction);
|
|
528
|
-
this.pageOffset.set(0);
|
|
529
|
-
this.paginator.pageIndex = 0;
|
|
530
|
-
});
|
|
531
|
-
this.paginator.page.subscribe(({ pageIndex, pageSize }) => {
|
|
532
|
-
this.pageOffset.set(pageIndex * pageSize);
|
|
533
|
-
this.pageCount.set(pageSize);
|
|
534
|
-
});
|
|
535
|
-
}
|
|
536
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: UserManagementComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
537
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: UserManagementComponent, isStandalone: true, selector: "app-user-management", viewQueries: [{ propertyName: "paginator", first: true, predicate: MatPaginator, descendants: true }, { propertyName: "sort", first: true, predicate: MatSort, descendants: true }], ngImport: i0, template: "<mat-form-field>\n <mat-label>Search for User</mat-label>\n <input matInput [(ngModel)]=\"search\">\n</mat-form-field>\n<mat-form-field>\n <mat-label>Account Type</mat-label>\n <mat-select multiple [(ngModel)]=\"accountTypes\">\n @for (accountType of accountTypeOptions; track accountType) {\n <mat-option [value]=\"accountType\">{{accountType}}</mat-option>\n }\n </mat-select>\n</mat-form-field>\n\n<table mat-table [dataSource]=\"getUsers.value()?.data ?? []\" matSort matSortActive=\"netId\" matSortDisableClear matSortDirection=\"asc\">\n <!-- NetID Column -->\n <ng-container matColumnDef=\"netId\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header>NetID</th>\n <td mat-cell *matCellDef=\"let user\">{{user.netId}}</td>\n </ng-container>\n\n <!-- First Name Column -->\n <ng-container matColumnDef=\"preferredFirstName\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header>First Name</th>\n <td mat-cell *matCellDef=\"let user\">{{user.preferredFirstName}}</td>\n </ng-container>\n\n <!-- Last Name Column -->\n <ng-container matColumnDef=\"preferredLastName\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header>Last Name</th>\n <td mat-cell *matCellDef=\"let user\">{{user.preferredLastName}}</td>\n </ng-container>\n\n <!-- Roles Column -->\n <ng-container matColumnDef=\"roles\">\n <th mat-header-cell *matHeaderCellDef>Roles</th>\n <td mat-cell *matCellDef=\"let user\">{{user.roles.join(', ')}}</td>\n </ng-container>\n\n <!-- Account Type Column -->\n <ng-container matColumnDef=\"accountType\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header>Account Type</th>\n <td mat-cell *matCellDef=\"let user\">{{user.accountType}}</td>\n </ng-container>\n\n <!-- Created Column -->\n <ng-container matColumnDef=\"created\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header>\n Created\n </th>\n <td mat-cell *matCellDef=\"let user\">{{user.created | date}}</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\n<mat-paginator [length]=\"getUsers.value()?.totalCount\" [pageSize]=\"pageCount()\" [pageSizeOptions]=\"[5, 10, 20]\" showFirstLastButtons></mat-paginator>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i1$1.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i1$1.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i1$1.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i1$1.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i1$1.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i1$1.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i1$1.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i1$1.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i1$1.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i1$1.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "ngmodule", type: MatSortModule }, { kind: "directive", type: i2.MatSort, selector: "[matSort]", inputs: ["matSortActive", "matSortStart", "matSortDirection", "matSortDisableClear", "matSortDisabled"], outputs: ["matSortChange"], exportAs: ["matSort"] }, { kind: "component", type: i2.MatSortHeader, selector: "[mat-sort-header]", inputs: ["mat-sort-header", "arrowPosition", "start", "disabled", "sortActionDescription", "disableClear"], exportAs: ["matSortHeader"] }, { kind: "ngmodule", type: MatPaginatorModule }, { kind: "component", type: i3.MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { kind: "pipe", type: DatePipe, name: "date" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i4.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: i4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i5.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "component", type: i5.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i5.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i6.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i6.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }] });
|
|
538
|
-
}
|
|
539
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: UserManagementComponent, decorators: [{
|
|
540
|
-
type: Component,
|
|
541
|
-
args: [{ selector: 'app-user-management', imports: [MatTableModule, MatSortModule, MatPaginatorModule, DatePipe, FormsModule, MatInputModule, MatSelectModule], template: "<mat-form-field>\n <mat-label>Search for User</mat-label>\n <input matInput [(ngModel)]=\"search\">\n</mat-form-field>\n<mat-form-field>\n <mat-label>Account Type</mat-label>\n <mat-select multiple [(ngModel)]=\"accountTypes\">\n @for (accountType of accountTypeOptions; track accountType) {\n <mat-option [value]=\"accountType\">{{accountType}}</mat-option>\n }\n </mat-select>\n</mat-form-field>\n\n<table mat-table [dataSource]=\"getUsers.value()?.data ?? []\" matSort matSortActive=\"netId\" matSortDisableClear matSortDirection=\"asc\">\n <!-- NetID Column -->\n <ng-container matColumnDef=\"netId\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header>NetID</th>\n <td mat-cell *matCellDef=\"let user\">{{user.netId}}</td>\n </ng-container>\n\n <!-- First Name Column -->\n <ng-container matColumnDef=\"preferredFirstName\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header>First Name</th>\n <td mat-cell *matCellDef=\"let user\">{{user.preferredFirstName}}</td>\n </ng-container>\n\n <!-- Last Name Column -->\n <ng-container matColumnDef=\"preferredLastName\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header>Last Name</th>\n <td mat-cell *matCellDef=\"let user\">{{user.preferredLastName}}</td>\n </ng-container>\n\n <!-- Roles Column -->\n <ng-container matColumnDef=\"roles\">\n <th mat-header-cell *matHeaderCellDef>Roles</th>\n <td mat-cell *matCellDef=\"let user\">{{user.roles.join(', ')}}</td>\n </ng-container>\n\n <!-- Account Type Column -->\n <ng-container matColumnDef=\"accountType\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header>Account Type</th>\n <td mat-cell *matCellDef=\"let user\">{{user.accountType}}</td>\n </ng-container>\n\n <!-- Created Column -->\n <ng-container matColumnDef=\"created\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header>\n Created\n </th>\n <td mat-cell *matCellDef=\"let user\">{{user.created | date}}</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\n<mat-paginator [length]=\"getUsers.value()?.totalCount\" [pageSize]=\"pageCount()\" [pageSizeOptions]=\"[5, 10, 20]\" showFirstLastButtons></mat-paginator>\n" }]
|
|
542
|
-
}], propDecorators: { paginator: [{
|
|
543
|
-
type: ViewChild,
|
|
544
|
-
args: [MatPaginator]
|
|
545
|
-
}], sort: [{
|
|
546
|
-
type: ViewChild,
|
|
547
|
-
args: [MatSort]
|
|
548
|
-
}] } });
|
|
549
|
-
|
|
550
263
|
function trpcResource(procedure, input, options) {
|
|
551
264
|
const currentInput = computed(input);
|
|
552
265
|
const value = signal(options?.defaultValue, { equal: options?.equal });
|
|
@@ -606,26 +319,44 @@ function debugTrpcResource(_trpcResource) {
|
|
|
606
319
|
};
|
|
607
320
|
}
|
|
608
321
|
|
|
322
|
+
const debounced = (inputSignal, wait = 400) => {
|
|
323
|
+
const debouncedSignal = signal(inputSignal());
|
|
324
|
+
const setSignal = debounce((value) => debouncedSignal.set(value), wait);
|
|
325
|
+
effect(() => {
|
|
326
|
+
setSignal(inputSignal());
|
|
327
|
+
});
|
|
328
|
+
return debouncedSignal;
|
|
329
|
+
};
|
|
330
|
+
const debounce = (callback, wait) => {
|
|
331
|
+
let timeoutId;
|
|
332
|
+
return (...args) => {
|
|
333
|
+
window.clearTimeout(timeoutId);
|
|
334
|
+
timeoutId = window.setTimeout(() => {
|
|
335
|
+
callback(...args);
|
|
336
|
+
}, wait);
|
|
337
|
+
};
|
|
338
|
+
};
|
|
339
|
+
|
|
609
340
|
const makeTableConfig = (config) => config;
|
|
610
341
|
|
|
611
342
|
class FhssTableComponent {
|
|
612
343
|
injector = inject(Injector);
|
|
613
344
|
config = input.required();
|
|
614
345
|
miscParams = input({});
|
|
615
|
-
columnKeys =
|
|
616
|
-
|
|
617
|
-
if (this.config().displayIdColumn) {
|
|
618
|
-
return keys;
|
|
619
|
-
}
|
|
620
|
-
return keys.filter((k) => k !== 'id');
|
|
621
|
-
});
|
|
346
|
+
columnKeys = [];
|
|
347
|
+
columnsToDisplay = [];
|
|
622
348
|
selection;
|
|
623
349
|
selectedValues = model([]);
|
|
624
350
|
dataResource;
|
|
625
351
|
ngOnInit() {
|
|
626
|
-
const
|
|
627
|
-
|
|
628
|
-
|
|
352
|
+
const cfg = this.config();
|
|
353
|
+
this.columnKeys = Object.keys(cfg.columns);
|
|
354
|
+
this.columnsToDisplay = cfg.displayIdColumn
|
|
355
|
+
? this.columnKeys
|
|
356
|
+
: this.columnKeys.filter((k) => k !== 'id');
|
|
357
|
+
if (cfg.interaction?.type === 'select') {
|
|
358
|
+
this.columnsToDisplay.unshift('table-checkbox-column');
|
|
359
|
+
this.selection = new SelectionModel(cfg.interaction.multi, undefined, undefined, (o1, o2) => o1.id === o2.id);
|
|
629
360
|
}
|
|
630
361
|
this.dataResource = trpcResource(this.config().procedure, () => ({
|
|
631
362
|
search: this.debouncedSearch(),
|
|
@@ -649,7 +380,7 @@ class FhssTableComponent {
|
|
|
649
380
|
filters = signal({});
|
|
650
381
|
debouncedFilters = debounced(this.filters);
|
|
651
382
|
sortBy = linkedSignal(() => this.config().sorting.defaultSortBy);
|
|
652
|
-
sortDirection = linkedSignal(() => this.config().sorting.defaultSortDirection);
|
|
383
|
+
sortDirection = linkedSignal(() => this.config().sorting.defaultSortDirection ?? 'asc');
|
|
653
384
|
pageIndex = linkedSignal(() => {
|
|
654
385
|
this.search();
|
|
655
386
|
return 0;
|
|
@@ -662,7 +393,7 @@ class FhssTableComponent {
|
|
|
662
393
|
}
|
|
663
394
|
onSortChange(sort) {
|
|
664
395
|
this.sortBy.set(sort.active || this.config().sorting.defaultSortBy);
|
|
665
|
-
this.sortDirection.set(sort.direction || this.config().sorting.defaultSortDirection);
|
|
396
|
+
this.sortDirection.set(sort.direction || this.config().sorting.defaultSortDirection || 'asc');
|
|
666
397
|
this.pageIndex.set(0);
|
|
667
398
|
}
|
|
668
399
|
onSelectionChange() {
|
|
@@ -707,7 +438,7 @@ class FhssTableComponent {
|
|
|
707
438
|
return `${this.selection.isSelected(row) ? 'deselect' : 'select'} row ${row.position + 1}`;
|
|
708
439
|
}
|
|
709
440
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: FhssTableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
710
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: FhssTableComponent, isStandalone: true, selector: "fhss-table", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null }, miscParams: { classPropertyName: "miscParams", publicName: "miscParams", isSignal: true, isRequired: false, transformFunction: null }, selectedValues: { classPropertyName: "selectedValues", publicName: "selectedValues", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectedValues: "selectedValuesChange" }, ngImport: i0, template: "@if (dataResource.isLoading()) {\n <div class=\"shade\">\n <mat-spinner />\n </div>\n}\n@if (dataResource.error()) {\n <div class=\"shade\">\n <div class=\"error-msg\">There was an error retrieving this data</div>\n <button mat-button (click)=\"this.dataResource.refresh()\">Retry</button>\n </div>\n}\n\n@if (config().showSearch) {\n <mat-form-field>\n <input matInput [(ngModel)]=\"search\" placeholder=\"Find...\" />\n @if (search()) {\n <button\n matSuffix\n mat-icon-button\n aria-label=\"Clear\"\n (click)=\"search.set('')\"\n >\n <mat-icon>close</mat-icon>\n </button>\n }\n </mat-form-field>\n}\n\n<table\n mat-table\n [dataSource]=\"dataResource.value()?.data ?? []\"\n matSort\n [matSortActive]=\"sortBy()\"\n [matSortDirection]=\"sortDirection()\"\n (matSortChange)=\"onSortChange($event)\"\n matSortDisableClear\n>\n @if (selection) {\n <ng-container matColumnDef=\"select\">\n <th mat-header-cell *matHeaderCellDef>\n @if (selection.isMultipleSelection()) {\n <mat-checkbox\n (change)=\"$event ? toggleAllRows() : null\"\n [checked]=\"selection.hasValue() && isAllSelected()\"\n [indeterminate]=\"selection.hasValue() && !isAllSelected()\"\n [aria-label]=\"checkboxLabel()\"\n />\n }\n </th>\n <td mat-cell *matCellDef=\"let row\">\n <mat-checkbox\n (click)=\"$event.stopPropagation()\"\n (change)=\"$event ? onRowClick(row) : null\"\n [checked]=\"selection.isSelected(row)\"\n [aria-label]=\"checkboxLabel(row)\"\n />\n </td>\n </ng-container>\n }\n\n @for (key of columnKeys(); track key) {\n <ng-container [matColumnDef]=\"key\">\n <mat-header-cell\n *matHeaderCellDef\n mat-sort-header\n [disabled]=\"!config().columns[key].allowSort\"\n >\n {{ config().columns[key].header }}\n @if (config().columns[key].individualFilter) {\n <mat-form-field>\n <input\n matInput\n [ngModel]=\"filters()[key] || ''\"\n (ngModelChange)=\"onFilterChange(key, $event)\"\n placeholder=\"Filter...\"\n />\n @if (filters()[key]) {\n <button\n matSuffix\n mat-icon-button\n aria-label=\"Clear\"\n (click)=\"onFilterChange(key, '')\"\n >\n <mat-icon>close</mat-icon>\n </button>\n }\n </mat-form-field>\n }\n </mat-header-cell>\n <mat-cell *matCellDef=\"let row\">\n {{ row[key] }}\n </mat-cell>\n </ng-container>\n }\n\n <mat-header-row *matHeaderRowDef=\"columnKeys()\"></mat-header-row>\n @if (config().interaction) {\n <mat-row\n matRipple\n (click)=\"onRowClick(row)\"\n *matRowDef=\"let row; columns: columnKeys()\"\n ></mat-row>\n } @else {\n <mat-row *matRowDef=\"let row; columns: columnKeys()\"></mat-row>\n }\n\n <mat-row *matNoDataRow>\n <mat-cell colspan=\"4\">No data found</mat-cell>\n <button mat-button (click)=\"this.dataResource.refresh()\">Retry</button>\n </mat-row>\n</table>\n\n@if (!config().pagination.hideControls) {\n <mat-paginator\n [length]=\"dataResource.value()?.totalCount\"\n [showFirstLastButtons]=\"true\"\n [pageSize]=\"config().pagination.pageSize\"\n [hidePageSize]=\"true\"\n [pageIndex]=\"pageIndex()\"\n [disabled]=\"dataResource.isLoading()\"\n (page)=\"onPaginationChange($event)\"\n />\n}\n", styles: [".shade{position:absolute;inset:0 0 56px;background:#00000026;z-index:1;display:flex;align-items:center;justify-content:center}\n"], dependencies: [{ kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i1$1.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i1$1.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i1$1.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i1$1.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i1$1.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i1$1.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i1$1.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i1$1.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i1$1.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i1$1.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "directive", type: i1$1.MatNoDataRow, selector: "ng-template[matNoDataRow]" }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i2$1.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "ngmodule", type: MatPaginatorModule }, { kind: "component", type: i3.MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i5.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "component", type: i5.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i5.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i4.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: i4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1$2.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i1$2.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatSortModule }, { kind: "directive", type: i2.MatSort, selector: "[matSort]", inputs: ["matSortActive", "matSortStart", "matSortDirection", "matSortDisableClear", "matSortDisabled"], outputs: ["matSortChange"], exportAs: ["matSort"] }, { kind: "component", type: i2.MatSortHeader, selector: "[mat-sort-header]", inputs: ["mat-sort-header", "arrowPosition", "start", "disabled", "sortActionDescription", "disableClear"], exportAs: ["matSortHeader"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i8.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatRippleModule }, { kind: "directive", type: i9.MatRipple, selector: "[mat-ripple], [matRipple]", inputs: ["matRippleColor", "matRippleUnbounded", "matRippleCentered", "matRippleRadius", "matRippleAnimation", "matRippleDisabled", "matRippleTrigger"], exportAs: ["matRipple"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i10.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }] });
|
|
441
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: FhssTableComponent, isStandalone: true, selector: "fhss-table", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null }, miscParams: { classPropertyName: "miscParams", publicName: "miscParams", isSignal: true, isRequired: false, transformFunction: null }, selectedValues: { classPropertyName: "selectedValues", publicName: "selectedValues", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectedValues: "selectedValuesChange" }, ngImport: i0, template: "<div class=\"table-container\">\n @if (dataResource.isLoading() || dataResource.error()) {\n <div class=\"shade\">\n @if (dataResource.isLoading()) {\n <mat-spinner />\n }\n @if (dataResource.error()) {\n <div class=\"msg-bkgd\">\n <div class=\"error-msg\">There was an error retrieving this data</div>\n <button mat-button (click)=\"this.dataResource.refresh()\">\n Retry\n </button>\n </div>\n }\n </div>\n }\n\n @if (config().showSearch) {\n <mat-form-field class=\"search\">\n <input matInput [(ngModel)]=\"search\" placeholder=\"Find...\" />\n @if (search()) {\n <button\n matSuffix\n mat-icon-button\n aria-label=\"Clear\"\n (click)=\"search.set('')\"\n >\n <mat-icon>close</mat-icon>\n </button>\n }\n </mat-form-field>\n }\n\n <div class=\"other-controls\">\n <ng-content />\n </div>\n\n <table\n mat-table\n [dataSource]=\"dataResource.value()?.data ?? []\"\n matSort\n [matSortActive]=\"sortBy()\"\n [matSortDirection]=\"sortDirection()\"\n (matSortChange)=\"onSortChange($event)\"\n matSortDisableClear\n >\n @if (selection) {\n <ng-container matColumnDef=\"table-checkbox-column\">\n <mat-header-cell *matHeaderCellDef>\n @if (selection.isMultipleSelection()) {\n <mat-checkbox\n (change)=\"$event ? toggleAllRows() : null\"\n [checked]=\"selection.hasValue() && isAllSelected()\"\n [indeterminate]=\"selection.hasValue() && !isAllSelected()\"\n [aria-label]=\"checkboxLabel()\"\n />\n }\n </mat-header-cell>\n <mat-cell *matCellDef=\"let row\">\n <mat-checkbox\n (click)=\"$event.stopPropagation()\"\n (change)=\"$event ? onRowClick(row) : null\"\n [checked]=\"selection.isSelected(row)\"\n [aria-label]=\"checkboxLabel(row)\"\n />\n </mat-cell>\n </ng-container>\n }\n\n @for (key of columnKeys; track key) {\n <ng-container [matColumnDef]=\"key\">\n <mat-header-cell\n *matHeaderCellDef\n mat-sort-header\n [disabled]=\"!config().columns[key].allowSort\"\n >\n <div class=\"header\">\n {{ config().columns[key].header }}\n @if (config().columns[key].individualFilter) {\n <mat-form-field subscriptSizing=\"dynamic\">\n <input\n matInput\n (click)=\"$event.stopPropagation()\"\n [ngModel]=\"filters()[key] || ''\"\n (ngModelChange)=\"onFilterChange(key, $event)\"\n placeholder=\"Filter...\"\n />\n @if (filters()[key]) {\n <button\n matSuffix\n mat-icon-button\n aria-label=\"Clear\"\n (click)=\"onFilterChange(key, '')\"\n >\n <mat-icon>close</mat-icon>\n </button>\n }\n </mat-form-field>\n }\n </div>\n </mat-header-cell>\n <mat-cell *matCellDef=\"let row\">\n {{ row[key] }}\n </mat-cell>\n </ng-container>\n }\n\n <mat-header-row *matHeaderRowDef=\"columnsToDisplay\"></mat-header-row>\n @if (config().interaction) {\n <mat-row\n matRipple\n (click)=\"onRowClick(row)\"\n *matRowDef=\"let row; columns: columnsToDisplay\"\n ></mat-row>\n } @else {\n <mat-row *matRowDef=\"let row; columns: columnsToDisplay\"></mat-row>\n }\n\n <tr class=\"mat-row\" *matNoDataRow>\n <td class=\"mat-cell\">\n <div class=\"no-data\">\n No data found\n <button mat-button (click)=\"this.dataResource.refresh()\">\n Retry\n </button>\n </div>\n </td>\n </tr>\n </table>\n\n @if (!config().pagination.hideControls) {\n <mat-paginator\n [length]=\"dataResource.value()?.totalCount\"\n [showFirstLastButtons]=\"true\"\n [pageSize]=\"config().pagination.pageSize\"\n [hidePageSize]=\"true\"\n [pageIndex]=\"pageIndex()\"\n [disabled]=\"dataResource.isLoading()\"\n (page)=\"onPaginationChange($event)\"\n />\n }\n</div>\n", styles: [".table-container{position:relative}.shade{position:absolute;inset:0;background:#00000026;z-index:99;display:flex;align-items:center;justify-content:center}.msg-bkgd{background:#fff;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:15px 15px 5px}.search{background:#faf9fd;width:100%}.other-controls:not(:empty){background:#faf9fd}.mat-column-table-checkbox-column{background:#686868}.no-data{width:fit-content;margin:auto}\n"], dependencies: [{ kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i1$1.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i1$1.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i1$1.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i1$1.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i1$1.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i1$1.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i1$1.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i1$1.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i1$1.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i1$1.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "directive", type: i1$1.MatNoDataRow, selector: "ng-template[matNoDataRow]" }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i2.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "ngmodule", type: MatPaginatorModule }, { kind: "component", type: i3.MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i4.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "component", type: i4.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i5.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: i5.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i5.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1$2.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i1$2.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatSortModule }, { kind: "directive", type: i7.MatSort, selector: "[matSort]", inputs: ["matSortActive", "matSortStart", "matSortDirection", "matSortDisableClear", "matSortDisabled"], outputs: ["matSortChange"], exportAs: ["matSort"] }, { kind: "component", type: i7.MatSortHeader, selector: "[mat-sort-header]", inputs: ["mat-sort-header", "arrowPosition", "start", "disabled", "sortActionDescription", "disableClear"], exportAs: ["matSortHeader"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i8.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatRippleModule }, { kind: "directive", type: i9.MatRipple, selector: "[mat-ripple], [matRipple]", inputs: ["matRippleColor", "matRippleUnbounded", "matRippleCentered", "matRippleRadius", "matRippleAnimation", "matRippleDisabled", "matRippleTrigger"], exportAs: ["matRipple"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i10.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }] });
|
|
711
442
|
}
|
|
712
443
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: FhssTableComponent, decorators: [{
|
|
713
444
|
type: Component,
|
|
@@ -721,9 +452,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImpo
|
|
|
721
452
|
MatSortModule,
|
|
722
453
|
MatIconModule,
|
|
723
454
|
MatRippleModule,
|
|
724
|
-
MatFormField,
|
|
725
455
|
MatCheckboxModule,
|
|
726
|
-
], template: "@if (dataResource.isLoading()) {\n
|
|
456
|
+
], template: "<div class=\"table-container\">\n @if (dataResource.isLoading() || dataResource.error()) {\n <div class=\"shade\">\n @if (dataResource.isLoading()) {\n <mat-spinner />\n }\n @if (dataResource.error()) {\n <div class=\"msg-bkgd\">\n <div class=\"error-msg\">There was an error retrieving this data</div>\n <button mat-button (click)=\"this.dataResource.refresh()\">\n Retry\n </button>\n </div>\n }\n </div>\n }\n\n @if (config().showSearch) {\n <mat-form-field class=\"search\">\n <input matInput [(ngModel)]=\"search\" placeholder=\"Find...\" />\n @if (search()) {\n <button\n matSuffix\n mat-icon-button\n aria-label=\"Clear\"\n (click)=\"search.set('')\"\n >\n <mat-icon>close</mat-icon>\n </button>\n }\n </mat-form-field>\n }\n\n <div class=\"other-controls\">\n <ng-content />\n </div>\n\n <table\n mat-table\n [dataSource]=\"dataResource.value()?.data ?? []\"\n matSort\n [matSortActive]=\"sortBy()\"\n [matSortDirection]=\"sortDirection()\"\n (matSortChange)=\"onSortChange($event)\"\n matSortDisableClear\n >\n @if (selection) {\n <ng-container matColumnDef=\"table-checkbox-column\">\n <mat-header-cell *matHeaderCellDef>\n @if (selection.isMultipleSelection()) {\n <mat-checkbox\n (change)=\"$event ? toggleAllRows() : null\"\n [checked]=\"selection.hasValue() && isAllSelected()\"\n [indeterminate]=\"selection.hasValue() && !isAllSelected()\"\n [aria-label]=\"checkboxLabel()\"\n />\n }\n </mat-header-cell>\n <mat-cell *matCellDef=\"let row\">\n <mat-checkbox\n (click)=\"$event.stopPropagation()\"\n (change)=\"$event ? onRowClick(row) : null\"\n [checked]=\"selection.isSelected(row)\"\n [aria-label]=\"checkboxLabel(row)\"\n />\n </mat-cell>\n </ng-container>\n }\n\n @for (key of columnKeys; track key) {\n <ng-container [matColumnDef]=\"key\">\n <mat-header-cell\n *matHeaderCellDef\n mat-sort-header\n [disabled]=\"!config().columns[key].allowSort\"\n >\n <div class=\"header\">\n {{ config().columns[key].header }}\n @if (config().columns[key].individualFilter) {\n <mat-form-field subscriptSizing=\"dynamic\">\n <input\n matInput\n (click)=\"$event.stopPropagation()\"\n [ngModel]=\"filters()[key] || ''\"\n (ngModelChange)=\"onFilterChange(key, $event)\"\n placeholder=\"Filter...\"\n />\n @if (filters()[key]) {\n <button\n matSuffix\n mat-icon-button\n aria-label=\"Clear\"\n (click)=\"onFilterChange(key, '')\"\n >\n <mat-icon>close</mat-icon>\n </button>\n }\n </mat-form-field>\n }\n </div>\n </mat-header-cell>\n <mat-cell *matCellDef=\"let row\">\n {{ row[key] }}\n </mat-cell>\n </ng-container>\n }\n\n <mat-header-row *matHeaderRowDef=\"columnsToDisplay\"></mat-header-row>\n @if (config().interaction) {\n <mat-row\n matRipple\n (click)=\"onRowClick(row)\"\n *matRowDef=\"let row; columns: columnsToDisplay\"\n ></mat-row>\n } @else {\n <mat-row *matRowDef=\"let row; columns: columnsToDisplay\"></mat-row>\n }\n\n <tr class=\"mat-row\" *matNoDataRow>\n <td class=\"mat-cell\">\n <div class=\"no-data\">\n No data found\n <button mat-button (click)=\"this.dataResource.refresh()\">\n Retry\n </button>\n </div>\n </td>\n </tr>\n </table>\n\n @if (!config().pagination.hideControls) {\n <mat-paginator\n [length]=\"dataResource.value()?.totalCount\"\n [showFirstLastButtons]=\"true\"\n [pageSize]=\"config().pagination.pageSize\"\n [hidePageSize]=\"true\"\n [pageIndex]=\"pageIndex()\"\n [disabled]=\"dataResource.isLoading()\"\n (page)=\"onPaginationChange($event)\"\n />\n }\n</div>\n", styles: [".table-container{position:relative}.shade{position:absolute;inset:0;background:#00000026;z-index:99;display:flex;align-items:center;justify-content:center}.msg-bkgd{background:#fff;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:15px 15px 5px}.search{background:#faf9fd;width:100%}.other-controls:not(:empty){background:#faf9fd}.mat-column-table-checkbox-column{background:#686868}.no-data{width:fit-content;margin:auto}\n"] }]
|
|
727
457
|
}] });
|
|
728
458
|
|
|
729
459
|
const provideFhss = (config) => ({
|
|
@@ -811,6 +541,202 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImpo
|
|
|
811
541
|
args: [{ selector: 'fhss-not-found', imports: [MatButtonModule, ByuHeaderComponent, ByuFooterComponent], template: "<byu-header />\n\n<div class=\"container\">\n <div class=\"not-found\">\n <img src=\"/confused-duck.png\" alt=\"\" />\n <h1>404 - Page not found</h1>\n <p>The page you are looking for doesn't exist or it may have moved.</p>\n <a mat-flat-button href=\"/\">Go back to home</a>\n </div>\n</div>\n\n<byu-footer />\n", styles: [":host{height:100vh;display:flex;flex-direction:column}.container{flex:1;display:flex;align-items:center;justify-content:center}.container .not-found{text-align:center;padding-bottom:3em}\n"] }]
|
|
812
542
|
}] });
|
|
813
543
|
|
|
544
|
+
/**
|
|
545
|
+
* Creates a reactive fetch signal.
|
|
546
|
+
*
|
|
547
|
+
* The request function can include Signals for properties. These are unwrapped in the refresh function.
|
|
548
|
+
*/
|
|
549
|
+
function createFetchSignal(request, method, transform, options) {
|
|
550
|
+
// Use a computed signal so that any changes to Signals in the request object trigger updates.
|
|
551
|
+
const currentRequest = computed(request);
|
|
552
|
+
const value = signal(options?.defaultValue, { equal: options?.equal });
|
|
553
|
+
const errorResponse = signal(undefined);
|
|
554
|
+
const isLoading = signal(false);
|
|
555
|
+
const statusCode = signal(undefined);
|
|
556
|
+
const headers = signal(undefined);
|
|
557
|
+
const status = signal('idle');
|
|
558
|
+
const error = signal(undefined);
|
|
559
|
+
const injector = inject(Injector);
|
|
560
|
+
let effectRef = undefined;
|
|
561
|
+
if (options?.autoRefresh) {
|
|
562
|
+
effectRef = effect((onCleanup) => {
|
|
563
|
+
// pass abort signal to refresh on cleanup of effect
|
|
564
|
+
const controller = new AbortController();
|
|
565
|
+
onCleanup(() => controller.abort());
|
|
566
|
+
// call refresh with this abort controller
|
|
567
|
+
refresh(controller.signal, true);
|
|
568
|
+
}, { injector: options?.injector || injector });
|
|
569
|
+
}
|
|
570
|
+
const refresh = async (abortSignal, keepLoadingThroughAbort) => {
|
|
571
|
+
// if the fetchSignal has been destroyed, do nothing
|
|
572
|
+
if (untracked(status) === 'destroyed')
|
|
573
|
+
return;
|
|
574
|
+
// Reset signals for a fresh request.
|
|
575
|
+
isLoading.set(true);
|
|
576
|
+
errorResponse.set(undefined);
|
|
577
|
+
statusCode.set(undefined);
|
|
578
|
+
headers.set(undefined);
|
|
579
|
+
status.set('loading');
|
|
580
|
+
error.set(undefined);
|
|
581
|
+
// Unwrap the current request.
|
|
582
|
+
const req = currentRequest();
|
|
583
|
+
const url = req.url;
|
|
584
|
+
const params = req.params;
|
|
585
|
+
const requestHeaders = req.headers;
|
|
586
|
+
const body = req.body;
|
|
587
|
+
// Build URL with query parameters.
|
|
588
|
+
let uri = url;
|
|
589
|
+
if (params) {
|
|
590
|
+
const searchParams = new URLSearchParams();
|
|
591
|
+
for (const key in params) {
|
|
592
|
+
if (params[key] !== undefined)
|
|
593
|
+
searchParams.append(key, String(params[key]));
|
|
594
|
+
}
|
|
595
|
+
uri += (uri.includes('?') ? '&' : '?') + searchParams.toString();
|
|
596
|
+
}
|
|
597
|
+
// Filter out undefined header values
|
|
598
|
+
const filteredHeaders = requestHeaders
|
|
599
|
+
? Object.fromEntries(Object.entries(requestHeaders).filter(([, value]) => value !== undefined))
|
|
600
|
+
: undefined;
|
|
601
|
+
try {
|
|
602
|
+
// send the request
|
|
603
|
+
const response = await fetch(uri, {
|
|
604
|
+
method,
|
|
605
|
+
headers: filteredHeaders,
|
|
606
|
+
// Only include a body if one is provided.
|
|
607
|
+
body: body,
|
|
608
|
+
signal: abortSignal,
|
|
609
|
+
});
|
|
610
|
+
// set the status code
|
|
611
|
+
statusCode.set(response.status);
|
|
612
|
+
// Extract response headers.
|
|
613
|
+
const headersObj = {};
|
|
614
|
+
response.headers.forEach((val, key) => {
|
|
615
|
+
headersObj[key] = val;
|
|
616
|
+
});
|
|
617
|
+
headers.set(headersObj);
|
|
618
|
+
// if the response is ok, transform the body
|
|
619
|
+
if (response.ok) {
|
|
620
|
+
value.set(await transform(response));
|
|
621
|
+
status.set('resolved');
|
|
622
|
+
}
|
|
623
|
+
else {
|
|
624
|
+
// try to parse the error as json
|
|
625
|
+
try {
|
|
626
|
+
errorResponse.set(await response.json());
|
|
627
|
+
value.set(undefined);
|
|
628
|
+
status.set('resolved');
|
|
629
|
+
}
|
|
630
|
+
catch {
|
|
631
|
+
throw new Error('Unable to parse error response.');
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
catch (err) {
|
|
636
|
+
if (err instanceof Error) {
|
|
637
|
+
// if the fetch request was aborted
|
|
638
|
+
// we check if we would like to continue loading (the next request)
|
|
639
|
+
// if so then we just leave this refresh in an undefined state
|
|
640
|
+
// else we error as usual
|
|
641
|
+
if (err.name === 'AbortError' && keepLoadingThroughAbort) {
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
644
|
+
error.set(err);
|
|
645
|
+
}
|
|
646
|
+
else {
|
|
647
|
+
// Fallback for non-Error values
|
|
648
|
+
error.set(new Error(String(err)));
|
|
649
|
+
}
|
|
650
|
+
value.set(undefined);
|
|
651
|
+
status.set('error');
|
|
652
|
+
}
|
|
653
|
+
isLoading.set(false);
|
|
654
|
+
};
|
|
655
|
+
const destroy = () => {
|
|
656
|
+
// if the fetchSignal has been destroyed, do nothing
|
|
657
|
+
if (status() === 'destroyed')
|
|
658
|
+
return;
|
|
659
|
+
if (effectRef) {
|
|
660
|
+
effectRef.destroy();
|
|
661
|
+
}
|
|
662
|
+
status.set('destroyed');
|
|
663
|
+
value.set(undefined);
|
|
664
|
+
errorResponse.set(undefined);
|
|
665
|
+
isLoading.set(false);
|
|
666
|
+
statusCode.set(undefined);
|
|
667
|
+
headers.set(undefined);
|
|
668
|
+
error.set(undefined);
|
|
669
|
+
};
|
|
670
|
+
return {
|
|
671
|
+
value,
|
|
672
|
+
errorResponse,
|
|
673
|
+
isLoading,
|
|
674
|
+
statusCode,
|
|
675
|
+
headers,
|
|
676
|
+
status,
|
|
677
|
+
error,
|
|
678
|
+
refresh,
|
|
679
|
+
destroy
|
|
680
|
+
};
|
|
681
|
+
}
|
|
682
|
+
//
|
|
683
|
+
// Helpers for attaching response transforms.
|
|
684
|
+
//
|
|
685
|
+
const createHelper = (method, transform) => (request, options) => createFetchSignal(request, method, transform, options);
|
|
686
|
+
// Transforms
|
|
687
|
+
const jsonTransformer = (response) => response.json();
|
|
688
|
+
const textTransformer = (response) => response.text();
|
|
689
|
+
const blobTransformer = (response) => response.blob();
|
|
690
|
+
const arrayBufferTransformer = (response) => response.arrayBuffer();
|
|
691
|
+
//
|
|
692
|
+
// Build the defaults - GET chain
|
|
693
|
+
//
|
|
694
|
+
const fetchSignal = createHelper('GET', jsonTransformer);
|
|
695
|
+
fetchSignal.json = createHelper('GET', jsonTransformer);
|
|
696
|
+
fetchSignal.text = createHelper('GET', textTransformer);
|
|
697
|
+
fetchSignal.blob = createHelper('GET', blobTransformer);
|
|
698
|
+
fetchSignal.arrayBuffer = createHelper('GET', arrayBufferTransformer);
|
|
699
|
+
//
|
|
700
|
+
// Build the GET chain
|
|
701
|
+
//
|
|
702
|
+
fetchSignal.get = createHelper('GET', jsonTransformer);
|
|
703
|
+
fetchSignal.get.json = createHelper('GET', jsonTransformer);
|
|
704
|
+
fetchSignal.get.text = createHelper('GET', textTransformer);
|
|
705
|
+
fetchSignal.get.blob = createHelper('GET', blobTransformer);
|
|
706
|
+
fetchSignal.get.arrayBuffer = createHelper('GET', arrayBufferTransformer);
|
|
707
|
+
//
|
|
708
|
+
// Build the POST chain.
|
|
709
|
+
//
|
|
710
|
+
fetchSignal.post = createHelper('POST', jsonTransformer);
|
|
711
|
+
fetchSignal.post.json = createHelper('POST', jsonTransformer);
|
|
712
|
+
fetchSignal.post.text = createHelper('POST', textTransformer);
|
|
713
|
+
fetchSignal.post.blob = createHelper('POST', blobTransformer);
|
|
714
|
+
fetchSignal.post.arrayBuffer = createHelper('POST', arrayBufferTransformer);
|
|
715
|
+
//
|
|
716
|
+
// Build the PUT chain.
|
|
717
|
+
//
|
|
718
|
+
fetchSignal.put = createHelper('PUT', jsonTransformer);
|
|
719
|
+
fetchSignal.put.json = createHelper('PUT', jsonTransformer);
|
|
720
|
+
fetchSignal.put.text = createHelper('PUT', textTransformer);
|
|
721
|
+
fetchSignal.put.blob = createHelper('PUT', blobTransformer);
|
|
722
|
+
fetchSignal.put.arrayBuffer = createHelper('PUT', arrayBufferTransformer);
|
|
723
|
+
//
|
|
724
|
+
// Build the PATCH chain.
|
|
725
|
+
//
|
|
726
|
+
fetchSignal.patch = createHelper('PATCH', jsonTransformer);
|
|
727
|
+
fetchSignal.patch.json = createHelper('PATCH', jsonTransformer);
|
|
728
|
+
fetchSignal.patch.text = createHelper('PATCH', textTransformer);
|
|
729
|
+
fetchSignal.patch.blob = createHelper('PATCH', blobTransformer);
|
|
730
|
+
fetchSignal.patch.arrayBuffer = createHelper('PATCH', arrayBufferTransformer);
|
|
731
|
+
//
|
|
732
|
+
// Build the DELETE chain
|
|
733
|
+
//
|
|
734
|
+
fetchSignal.delete = createHelper('DELETE', jsonTransformer);
|
|
735
|
+
fetchSignal.delete.json = createHelper('DELETE', jsonTransformer);
|
|
736
|
+
fetchSignal.delete.text = createHelper('DELETE', textTransformer);
|
|
737
|
+
fetchSignal.delete.blob = createHelper('DELETE', blobTransformer);
|
|
738
|
+
fetchSignal.delete.arrayBuffer = createHelper('DELETE', arrayBufferTransformer);
|
|
739
|
+
|
|
814
740
|
/**
|
|
815
741
|
* Components
|
|
816
742
|
*/
|
|
@@ -819,5 +745,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImpo
|
|
|
819
745
|
* Generated bundle index. Do not edit.
|
|
820
746
|
*/
|
|
821
747
|
|
|
822
|
-
export { AuthCallbackPage, AuthErrorPage, AuthService, ByuFooterComponent, ByuHeaderComponent, FHSS_CONFIG, FhssTableComponent, ForbiddenPage, NotFoundPage,
|
|
748
|
+
export { AuthCallbackPage, AuthErrorPage, AuthService, ByuFooterComponent, ByuHeaderComponent, FHSS_CONFIG, FhssTableComponent, ForbiddenPage, NotFoundPage, authGuard, debounced, debugTrpcResource, fetchSignal, makeTableConfig, provideFhss, roleGuardFactory, trpcResource };
|
|
823
749
|
//# sourceMappingURL=fhss-web-team-frontend-utils.mjs.map
|