@fhss-web-team/frontend-utils 1.9.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/fhss-web-team-frontend-utils.mjs +47 -206
- package/fesm2022/fhss-web-team-frontend-utils.mjs.map +1 -1
- package/lib/guards/{role/role.guard.d.ts → permission/permission.guard.d.ts} +1 -1
- package/lib/services/auth/auth.service.d.ts +20 -90
- package/package.json +1 -1
- package/public-api.d.ts +1 -2
- package/lib/pages/auth-callback/auth-callback.page.d.ts +0 -8
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Component,
|
|
2
|
+
import { Component, inject, signal, computed, Injectable, input, effect, Injector, model, linkedSignal, InjectionToken, untracked } from '@angular/core';
|
|
3
3
|
import * as i1 from '@angular/router';
|
|
4
4
|
import { Router, RouterModule, RedirectCommand } from '@angular/router';
|
|
5
|
-
import { KEYCLOAK_EVENT_SIGNAL, KeycloakEventType, typeEventArgs } from 'keycloak-angular';
|
|
6
|
-
import Keycloak from 'keycloak-js';
|
|
7
5
|
import { isTRPCClientError } from '@trpc/client';
|
|
8
6
|
import * as i1$1 from '@angular/material/table';
|
|
9
7
|
import { MatTableModule } from '@angular/material/table';
|
|
@@ -37,195 +35,49 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImpo
|
|
|
37
35
|
args: [{ selector: 'byu-footer', imports: [], template: "<footer>\n <p class=\"title\"><a href=\"https://www.byu.edu/\">BRIGHAM YOUNG UNIVERSITY</a></p>\n <p>Provo, UT 84602, USA | \u00A9 {{ currentYear }} All rights reserved.</p>\n <p>\n <a href=\"https://privacy.byu.edu/privacy-notice\">Privacy Notice</a> |\n <a href=\"https://privacy.byu.edu/cookie-prefs\">Cookie Preferences</a>\n </p>\n</footer>\n \n\n", styles: ["footer{font-family:HCo Ringside Narrow SSm,Open Sans,Helvetica,Arial,sans-serif;font-weight:400;font-size:14px;color:#fff;background-color:#002e5d;text-align:center;padding:10px 20px}p{margin:8px 0}a{text-decoration:none;color:inherit}a:hover{text-decoration:underline}.title{font-family:HCo Ringside Narrow SSm Bold,Open Sans,Helvetica,Arial,sans-serif;font-weight:700;font-size:20px;letter-spacing:5px;margin-bottom:18px}.title a:hover{text-decoration:none}\n"] }]
|
|
38
36
|
}] });
|
|
39
37
|
|
|
40
|
-
const FHSS_CONFIG = new InjectionToken('FHSS_CONFIG');
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* AuthService provides a wrapper around the Keycloak JavaScript adapter, exposing its properties and methods
|
|
44
|
-
* as Angular signals for reactive programming. It simplifies authentication, token management, and role-based access control.
|
|
45
|
-
*/
|
|
46
38
|
class AuthService {
|
|
47
|
-
keycloak = inject(Keycloak);
|
|
48
|
-
keycloakSignal = inject(KEYCLOAK_EVENT_SIGNAL);
|
|
49
39
|
router = inject(Router);
|
|
50
|
-
config = inject(FHSS_CONFIG);
|
|
51
|
-
nextUriKey = 'nextUri';
|
|
52
|
-
injector = inject(Injector);
|
|
53
|
-
/**
|
|
54
|
-
* Signal indicating whether the user is authenticated.
|
|
55
|
-
* Returns `true` if authenticated, `false` otherwise.
|
|
56
|
-
*/
|
|
57
40
|
authenticated = signal(false);
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
41
|
+
userId = signal(undefined);
|
|
42
|
+
preferredFirstName = signal(undefined);
|
|
43
|
+
preferredLastName = signal(undefined);
|
|
44
|
+
roles = signal(undefined);
|
|
45
|
+
permissions = signal(undefined);
|
|
46
|
+
preferredName = computed(() => {
|
|
47
|
+
const prefLast = this.preferredLastName();
|
|
48
|
+
return `${this.preferredFirstName() ?? ''}${prefLast ? ` ${prefLast}` : ''}`;
|
|
49
|
+
});
|
|
50
|
+
resetAuthState() {
|
|
51
|
+
this.authenticated.set(false);
|
|
52
|
+
this.userId.set(undefined);
|
|
53
|
+
this.preferredFirstName.set(undefined);
|
|
54
|
+
this.preferredLastName.set(undefined);
|
|
55
|
+
this.roles.set(undefined);
|
|
56
|
+
this.permissions.set(undefined);
|
|
70
57
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
this.keycloak.login({
|
|
80
|
-
redirectUri: window.location.origin + '/auth-callback',
|
|
81
|
-
});
|
|
82
|
-
};
|
|
83
|
-
/**
|
|
84
|
-
* Gets the user's role home route
|
|
85
|
-
*
|
|
86
|
-
* @returns the user's role's home route,
|
|
87
|
-
* or null if there isn't one
|
|
88
|
-
*/
|
|
89
|
-
getRoleHomeRoute = () => {
|
|
90
|
-
if (!this.authenticated())
|
|
91
|
-
return null;
|
|
92
|
-
const userRoles = new Set(this.realmAccess()?.roles);
|
|
93
|
-
for (const role in this.config.roleHomePages) {
|
|
94
|
-
if (userRoles.has(role)) {
|
|
95
|
-
return this.config.roleHomePages[role];
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
return null;
|
|
99
|
-
};
|
|
100
|
-
/**
|
|
101
|
-
* Handles user provisioning.
|
|
102
|
-
*
|
|
103
|
-
* @returns the uri to which the application should navigate
|
|
104
|
-
*/
|
|
105
|
-
handleAuthCallback = async () => {
|
|
58
|
+
login(nextUri) {
|
|
59
|
+
this.router.navigate(['/login']);
|
|
60
|
+
}
|
|
61
|
+
logout(nextUri) {
|
|
62
|
+
this.resetAuthState();
|
|
63
|
+
this.router.navigate(['/logout']);
|
|
64
|
+
}
|
|
65
|
+
async whoAmI() {
|
|
106
66
|
try {
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
});
|
|
116
|
-
if (!res.ok)
|
|
117
|
-
throw new Error('User provisioning failed');
|
|
118
|
-
const customRoute = res.status === 200 ? (await res.json()).next : null;
|
|
119
|
-
const userHomeRoute = this.getRoleHomeRoute();
|
|
120
|
-
const nextRoute = customRoute ?? savedRoute ?? userHomeRoute ?? '/';
|
|
121
|
-
this.router.navigate([nextRoute]);
|
|
67
|
+
const res = await fetch('/sys/who-am-i');
|
|
68
|
+
const user = await res.json();
|
|
69
|
+
this.userId.set(user.id);
|
|
70
|
+
this.preferredFirstName.set(user.preferredFirstName);
|
|
71
|
+
this.preferredLastName.set(user.preferredLastName);
|
|
72
|
+
this.roles.set(user.roles);
|
|
73
|
+
this.permissions.set(user.permissions);
|
|
74
|
+
return user;
|
|
122
75
|
}
|
|
123
|
-
catch (
|
|
124
|
-
console.error(
|
|
125
|
-
|
|
76
|
+
catch (error) {
|
|
77
|
+
console.error(error);
|
|
78
|
+
return null;
|
|
126
79
|
}
|
|
127
|
-
}
|
|
128
|
-
/**
|
|
129
|
-
* Logs the user out of the application.
|
|
130
|
-
*/
|
|
131
|
-
logout = (nextUri) => this.keycloak.logout({
|
|
132
|
-
redirectUri: window.location.origin + (nextUri ?? '/'),
|
|
133
|
-
});
|
|
134
|
-
/**
|
|
135
|
-
* Signal for the base64-encoded token used in the `Authorization` header.
|
|
136
|
-
*/
|
|
137
|
-
token = computed(() => {
|
|
138
|
-
this.keycloakSignal();
|
|
139
|
-
return this.keycloak.token;
|
|
140
|
-
});
|
|
141
|
-
/**
|
|
142
|
-
* Signal for the Bearer token, prefixed with "Bearer ".
|
|
143
|
-
*/
|
|
144
|
-
bearerToken = computed(() => this.token() ? 'Bearer ' + this.token() : undefined);
|
|
145
|
-
/**
|
|
146
|
-
* Signal for the parsed token as a JavaScript object.
|
|
147
|
-
*/
|
|
148
|
-
tokenParsed = computed(() => {
|
|
149
|
-
this.keycloakSignal();
|
|
150
|
-
return this.keycloak.tokenParsed;
|
|
151
|
-
});
|
|
152
|
-
/**
|
|
153
|
-
* Signal for the user ID (Keycloak subject).
|
|
154
|
-
*/
|
|
155
|
-
userId = computed(() => {
|
|
156
|
-
this.keycloakSignal();
|
|
157
|
-
return this.keycloak.subject;
|
|
158
|
-
});
|
|
159
|
-
/**
|
|
160
|
-
* Signal for the base64-encoded ID token.
|
|
161
|
-
*/
|
|
162
|
-
idToken = computed(() => {
|
|
163
|
-
this.keycloakSignal();
|
|
164
|
-
return this.keycloak.idToken;
|
|
165
|
-
});
|
|
166
|
-
/**
|
|
167
|
-
* Signal for the parsed ID token as a JavaScript object.
|
|
168
|
-
*/
|
|
169
|
-
idTokenParsed = computed(() => {
|
|
170
|
-
this.keycloakSignal();
|
|
171
|
-
return this.keycloak.idTokenParsed;
|
|
172
|
-
});
|
|
173
|
-
/**
|
|
174
|
-
* Signal for the realm roles associated with the token.
|
|
175
|
-
*/
|
|
176
|
-
realmAccess = computed(() => {
|
|
177
|
-
this.keycloakSignal();
|
|
178
|
-
return this.keycloak.realmAccess;
|
|
179
|
-
});
|
|
180
|
-
/**
|
|
181
|
-
* Signal for the resource roles associated with the token.
|
|
182
|
-
*/
|
|
183
|
-
resourceAccess = computed(() => {
|
|
184
|
-
this.keycloakSignal();
|
|
185
|
-
return this.keycloak.resourceAccess;
|
|
186
|
-
});
|
|
187
|
-
/**
|
|
188
|
-
* Signal for the base64-encoded refresh token.
|
|
189
|
-
*/
|
|
190
|
-
refreshToken = computed(() => {
|
|
191
|
-
this.keycloakSignal();
|
|
192
|
-
return this.keycloak.refreshToken;
|
|
193
|
-
});
|
|
194
|
-
/**
|
|
195
|
-
* Signal for the parsed refresh token as a JavaScript object.
|
|
196
|
-
*/
|
|
197
|
-
refreshTokenParsed = computed(() => {
|
|
198
|
-
this.keycloakSignal();
|
|
199
|
-
return this.keycloak.refreshTokenParsed;
|
|
200
|
-
});
|
|
201
|
-
/**
|
|
202
|
-
* Signal for the estimated time difference between the browser and Keycloak server in seconds.
|
|
203
|
-
*/
|
|
204
|
-
timeSkew = computed(() => {
|
|
205
|
-
this.keycloakSignal();
|
|
206
|
-
return this.keycloak.timeSkew;
|
|
207
|
-
});
|
|
208
|
-
/**
|
|
209
|
-
* Signal for the response mode passed during initialization.
|
|
210
|
-
*/
|
|
211
|
-
responseMode = computed(() => {
|
|
212
|
-
this.keycloakSignal();
|
|
213
|
-
return this.keycloak.responseMode;
|
|
214
|
-
});
|
|
215
|
-
/**
|
|
216
|
-
* Signal for the flow type used during initialization.
|
|
217
|
-
*/
|
|
218
|
-
flow = computed(() => {
|
|
219
|
-
this.keycloakSignal();
|
|
220
|
-
return this.keycloak.flow;
|
|
221
|
-
});
|
|
222
|
-
/**
|
|
223
|
-
* Signal for the response type sent to Keycloak during login requests.
|
|
224
|
-
*/
|
|
225
|
-
responseType = computed(() => {
|
|
226
|
-
this.keycloakSignal();
|
|
227
|
-
return this.keycloak.responseType;
|
|
228
|
-
});
|
|
80
|
+
}
|
|
229
81
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AuthService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
230
82
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AuthService, providedIn: 'root' });
|
|
231
83
|
}
|
|
@@ -234,7 +86,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImpo
|
|
|
234
86
|
args: [{
|
|
235
87
|
providedIn: 'root',
|
|
236
88
|
}]
|
|
237
|
-
}]
|
|
89
|
+
}] });
|
|
238
90
|
|
|
239
91
|
class ByuHeaderComponent {
|
|
240
92
|
auth = inject(AuthService);
|
|
@@ -253,11 +105,11 @@ class ByuHeaderComponent {
|
|
|
253
105
|
return this.openDropdownText === text;
|
|
254
106
|
}
|
|
255
107
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ByuHeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
256
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: ByuHeaderComponent, isStandalone: true, selector: "byu-header", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, 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.
|
|
108
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: ByuHeaderComponent, isStandalone: true, selector: "byu-header", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, 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.preferredName() }}</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"], dependencies: [{ kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }] });
|
|
257
109
|
}
|
|
258
110
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ByuHeaderComponent, decorators: [{
|
|
259
111
|
type: Component,
|
|
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.
|
|
112
|
+
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.preferredName() }}</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"] }]
|
|
261
113
|
}] });
|
|
262
114
|
|
|
263
115
|
function trpcResource(procedure, input, options) {
|
|
@@ -455,6 +307,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImpo
|
|
|
455
307
|
], 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\" subscriptSizing=\"dynamic\">\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 || key }}\n @if (config().columns[key].individualFilter) {\n <mat-form-field appearance=\"outline\" 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 @if (isBoolean(row[key])) {\n <mat-checkbox [checked]=\"row[key]\" [disabled]=\"true\" />\n } @else {\n {{ row[key] }}\n }\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;padding:10px 0}.mat-column-table-checkbox-column{width:fit-content}.no-data{width:fit-content;margin:auto}\n"] }]
|
|
456
308
|
}] });
|
|
457
309
|
|
|
310
|
+
const FHSS_CONFIG = new InjectionToken('FHSS_CONFIG');
|
|
311
|
+
|
|
458
312
|
const provideFhss = (config) => ({
|
|
459
313
|
provide: FHSS_CONFIG,
|
|
460
314
|
useValue: config,
|
|
@@ -486,7 +340,7 @@ const authGuard = (route, state) => {
|
|
|
486
340
|
* ];
|
|
487
341
|
* ```
|
|
488
342
|
*/
|
|
489
|
-
const
|
|
343
|
+
const permissionGuardFactory = (...requiredPermissions) => {
|
|
490
344
|
return (_route, state) => {
|
|
491
345
|
const authService = inject(AuthService);
|
|
492
346
|
const router = inject(Router);
|
|
@@ -494,25 +348,12 @@ const roleGuardFactory = (...allowedRoles) => {
|
|
|
494
348
|
authService.login(state.url);
|
|
495
349
|
return false;
|
|
496
350
|
}
|
|
497
|
-
const
|
|
498
|
-
const
|
|
499
|
-
return
|
|
351
|
+
const userPermissions = authService.permissions();
|
|
352
|
+
const hasAccess = userPermissions?.some((role) => requiredPermissions.includes(role)) ?? false;
|
|
353
|
+
return hasAccess || new RedirectCommand(router.parseUrl('/forbidden'));
|
|
500
354
|
};
|
|
501
355
|
};
|
|
502
356
|
|
|
503
|
-
class AuthCallbackPage {
|
|
504
|
-
auth = inject(AuthService);
|
|
505
|
-
constructor() {
|
|
506
|
-
this.auth.handleAuthCallback();
|
|
507
|
-
}
|
|
508
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AuthCallbackPage, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
509
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: AuthCallbackPage, isStandalone: true, selector: "app-auth-callback", ngImport: i0, template: "<div class=\"container\">\n <p>Logging you in...</p>\n</div>", styles: [":host{height:100vh;display:flex;flex-direction:column}.container{flex:1;display:flex;align-items:center;justify-content:center;text-align:center;padding-bottom:3em}\n"] });
|
|
510
|
-
}
|
|
511
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AuthCallbackPage, decorators: [{
|
|
512
|
-
type: Component,
|
|
513
|
-
args: [{ selector: 'app-auth-callback', imports: [], template: "<div class=\"container\">\n <p>Logging you in...</p>\n</div>", styles: [":host{height:100vh;display:flex;flex-direction:column}.container{flex:1;display:flex;align-items:center;justify-content:center;text-align:center;padding-bottom:3em}\n"] }]
|
|
514
|
-
}], ctorParameters: () => [] });
|
|
515
|
-
|
|
516
357
|
class AuthErrorPage {
|
|
517
358
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AuthErrorPage, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
518
359
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: AuthErrorPage, isStandalone: true, selector: "fhss-auth-error", ngImport: i0, template: "<byu-header />\n\n<div class=\"container\">\n <div class=\"not-found\">\n <img src=\"/sad-duck.jpg\" alt=\"sad duck\" />\n <h1>Login Failed</h1>\n <p>Something went wrong while trying to log you in.</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}.container .not-found img{width:25%}\n"], dependencies: [{ kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1$2.MatAnchor, selector: "a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button]", exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: ByuHeaderComponent, selector: "byu-header", inputs: ["config"] }, { kind: "component", type: ByuFooterComponent, selector: "byu-footer" }] });
|
|
@@ -744,5 +585,5 @@ fetchSignal.delete.arrayBuffer = createHelper('DELETE', arrayBufferTransformer);
|
|
|
744
585
|
* Generated bundle index. Do not edit.
|
|
745
586
|
*/
|
|
746
587
|
|
|
747
|
-
export {
|
|
588
|
+
export { AuthErrorPage, AuthService, ByuFooterComponent, ByuHeaderComponent, FHSS_CONFIG, FhssTableComponent, ForbiddenPage, NotFoundPage, authGuard, debounced, debugTrpcResource, fetchSignal, makeTableConfig, permissionGuardFactory, provideFhss, trpcResource };
|
|
748
589
|
//# sourceMappingURL=fhss-web-team-frontend-utils.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fhss-web-team-frontend-utils.mjs","sources":["../../../projects/frontend-utils/src/lib/components/byu-footer/byu-footer.component.ts","../../../projects/frontend-utils/src/lib/components/byu-footer/byu-footer.component.html","../../../projects/frontend-utils/src/lib/config/lib.config.ts","../../../projects/frontend-utils/src/lib/services/auth/auth.service.ts","../../../projects/frontend-utils/src/lib/components/byu-header/byu-header.component.ts","../../../projects/frontend-utils/src/lib/components/byu-header/byu-header.component.html","../../../projects/frontend-utils/src/lib/signals/trpcResource/trpcResource.ts","../../../projects/frontend-utils/src/lib/signals/debounced/debounced.ts","../../../projects/frontend-utils/src/lib/components/fhss-table/fhss-table.types.ts","../../../projects/frontend-utils/src/lib/components/fhss-table/fhss-table.component.ts","../../../projects/frontend-utils/src/lib/components/fhss-table/fhss-table.component.html","../../../projects/frontend-utils/src/lib/config/utils.config.ts","../../../projects/frontend-utils/src/lib/guards/auth/auth.guard.ts","../../../projects/frontend-utils/src/lib/guards/role/role.guard.ts","../../../projects/frontend-utils/src/lib/pages/auth-callback/auth-callback.page.ts","../../../projects/frontend-utils/src/lib/pages/auth-callback/auth-callback.page.html","../../../projects/frontend-utils/src/lib/pages/auth-error/auth-error.page.ts","../../../projects/frontend-utils/src/lib/pages/auth-error/auth-error.page.html","../../../projects/frontend-utils/src/lib/pages/forbidden/forbidden.page.ts","../../../projects/frontend-utils/src/lib/pages/forbidden/forbidden.page.html","../../../projects/frontend-utils/src/lib/pages/not-found/not-found.page.ts","../../../projects/frontend-utils/src/lib/pages/not-found/not-found.page.html","../../../projects/frontend-utils/src/lib/signals/fetch-signal/fetch-signal.ts","../../../projects/frontend-utils/src/public-api.ts","../../../projects/frontend-utils/src/fhss-web-team-frontend-utils.ts"],"sourcesContent":["import { Component } from '@angular/core';\n\n@Component({\n selector: 'byu-footer',\n imports: [],\n templateUrl: './byu-footer.component.html',\n styleUrl: './byu-footer.component.scss'\n})\nexport class ByuFooterComponent {\n currentYear: number = new Date().getFullYear(); // Automatically updates the year\n}\n","<footer>\n <p class=\"title\"><a href=\"https://www.byu.edu/\">BRIGHAM YOUNG UNIVERSITY</a></p>\n <p>Provo, UT 84602, USA | © {{ currentYear }} All rights reserved.</p>\n <p>\n <a href=\"https://privacy.byu.edu/privacy-notice\">Privacy Notice</a> |\n <a href=\"https://privacy.byu.edu/cookie-prefs\">Cookie Preferences</a>\n </p>\n</footer>\n \n\n","import { InjectionToken } from '@angular/core';\n\nexport const FHSS_CONFIG = new InjectionToken<FhssConfig>('FHSS_CONFIG');\n\nexport interface FhssConfig {\n roleHomePages: Record<string, string>;\n}\n","import {\n Injectable,\n inject,\n computed,\n afterNextRender,\n effect,\n Injector,\n signal,\n} from '@angular/core';\nimport { Router } from '@angular/router';\nimport {\n KEYCLOAK_EVENT_SIGNAL,\n KeycloakEventType,\n ReadyArgs,\n typeEventArgs,\n} from 'keycloak-angular';\nimport Keycloak, {\n KeycloakFlow,\n KeycloakResourceAccess,\n KeycloakResponseMode,\n KeycloakResponseType,\n KeycloakRoles,\n KeycloakTokenParsed,\n} from 'keycloak-js';\nimport { FHSS_CONFIG } from '../../config/lib.config';\n\n@Injectable({\n providedIn: 'root',\n})\n/**\n * AuthService provides a wrapper around the Keycloak JavaScript adapter, exposing its properties and methods\n * as Angular signals for reactive programming. It simplifies authentication, token management, and role-based access control.\n */\nexport class AuthService {\n private keycloak = inject(Keycloak);\n private keycloakSignal = inject(KEYCLOAK_EVENT_SIGNAL);\n private router = inject(Router);\n private config = inject(FHSS_CONFIG);\n\n private readonly nextUriKey = 'nextUri';\n private readonly injector = inject(Injector);\n\n /**\n * Signal indicating whether the user is authenticated.\n * Returns `true` if authenticated, `false` otherwise.\n */\n authenticated = signal(false);\n\n constructor() {\n afterNextRender(() => {\n effect(\n () => {\n const kcEvent = this.keycloakSignal();\n if (kcEvent.type === KeycloakEventType.Ready) {\n this.authenticated.set(typeEventArgs<ReadyArgs>(kcEvent.args));\n }\n if (kcEvent.type === KeycloakEventType.AuthLogout) {\n this.authenticated.set(false);\n }\n },\n { injector: this.injector },\n );\n });\n }\n\n /**\n * Initiates the login process. Optionally stores a route to redirect to after login.\n * @param nextUri - The route to navigate to after successful login.\n */\n login = (nextUri?: string) => {\n if (nextUri) {\n sessionStorage.setItem(this.nextUriKey, nextUri);\n }\n this.keycloak.login({\n redirectUri: window.location.origin + '/auth-callback',\n });\n };\n\n /**\n * Gets the user's role home route\n *\n * @returns the user's role's home route,\n * or null if there isn't one\n */\n getRoleHomeRoute = () => {\n if (!this.authenticated()) return null;\n\n const userRoles = new Set(this.realmAccess()?.roles);\n for (const role in this.config.roleHomePages) {\n if (userRoles.has(role)) {\n return this.config.roleHomePages[role];\n }\n }\n return null;\n };\n\n /**\n * Handles user provisioning.\n *\n * @returns the uri to which the application should navigate\n */\n handleAuthCallback = async (): Promise<void> => {\n try {\n const savedRoute = sessionStorage.getItem(this.nextUriKey);\n sessionStorage.removeItem(this.nextUriKey);\n\n if (!this.authenticated()) {\n this.router.navigate(['/']);\n return;\n }\n\n const res = await fetch(window.location.origin + '/api/auth/callback', {\n headers: { Authorization: this.bearerToken() ?? '' },\n });\n\n if (!res.ok) throw new Error('User provisioning failed');\n const customRoute: string | null =\n res.status === 200 ? (await res.json()).next : null;\n\n const userHomeRoute = this.getRoleHomeRoute();\n\n const nextRoute = customRoute ?? savedRoute ?? userHomeRoute ?? '/';\n this.router.navigate([nextRoute]);\n } catch (err) {\n console.error(err);\n this.logout('/auth-error');\n }\n };\n\n /**\n * Logs the user out of the application.\n */\n logout = (nextUri?: string) =>\n this.keycloak.logout({\n redirectUri: window.location.origin + (nextUri ?? '/'),\n });\n\n /**\n * Signal for the base64-encoded token used in the `Authorization` header.\n */\n token = computed<string | undefined>(() => {\n this.keycloakSignal();\n return this.keycloak.token;\n });\n\n /**\n * Signal for the Bearer token, prefixed with \"Bearer \".\n */\n bearerToken = computed<string | undefined>(() =>\n this.token() ? 'Bearer ' + this.token() : undefined,\n );\n\n /**\n * Signal for the parsed token as a JavaScript object.\n */\n tokenParsed = computed<KeycloakTokenParsed | undefined>(() => {\n this.keycloakSignal();\n return this.keycloak.tokenParsed;\n });\n\n /**\n * Signal for the user ID (Keycloak subject).\n */\n userId = computed<string | undefined>(() => {\n this.keycloakSignal();\n return this.keycloak.subject;\n });\n\n /**\n * Signal for the base64-encoded ID token.\n */\n idToken = computed<string | undefined>(() => {\n this.keycloakSignal();\n return this.keycloak.idToken;\n });\n\n /**\n * Signal for the parsed ID token as a JavaScript object.\n */\n idTokenParsed = computed<KeycloakTokenParsed | undefined>(() => {\n this.keycloakSignal();\n return this.keycloak.idTokenParsed;\n });\n\n /**\n * Signal for the realm roles associated with the token.\n */\n realmAccess = computed<KeycloakRoles | undefined>(() => {\n this.keycloakSignal();\n return this.keycloak.realmAccess;\n });\n\n /**\n * Signal for the resource roles associated with the token.\n */\n resourceAccess = computed<KeycloakResourceAccess | undefined>(() => {\n this.keycloakSignal();\n return this.keycloak.resourceAccess;\n });\n\n /**\n * Signal for the base64-encoded refresh token.\n */\n refreshToken = computed<string | undefined>(() => {\n this.keycloakSignal();\n return this.keycloak.refreshToken;\n });\n\n /**\n * Signal for the parsed refresh token as a JavaScript object.\n */\n refreshTokenParsed = computed<KeycloakTokenParsed | undefined>(() => {\n this.keycloakSignal();\n return this.keycloak.refreshTokenParsed;\n });\n\n /**\n * Signal for the estimated time difference between the browser and Keycloak server in seconds.\n */\n timeSkew = computed<number | undefined>(() => {\n this.keycloakSignal();\n return this.keycloak.timeSkew;\n });\n\n /**\n * Signal for the response mode passed during initialization.\n */\n responseMode = computed<KeycloakResponseMode | undefined>(() => {\n this.keycloakSignal();\n return this.keycloak.responseMode;\n });\n\n /**\n * Signal for the flow type used during initialization.\n */\n flow = computed<KeycloakFlow | undefined>(() => {\n this.keycloakSignal();\n return this.keycloak.flow;\n });\n\n /**\n * Signal for the response type sent to Keycloak during login requests.\n */\n responseType = computed<KeycloakResponseType | undefined>(() => {\n this.keycloakSignal();\n return this.keycloak.responseType;\n });\n}\n","import { Component, input, inject } from '@angular/core';\nimport { RouterModule } from '@angular/router';\nimport { AuthService } from '../../services/auth/auth.service';\n\ntype HeaderLink = {\n text: string;\n path: string;\n};\n\n// A HeaderMenu can be either a simple link with path,\n// OR a menu group with nested items\ntype HeaderMenu = HeaderLink | {\n text: string;\n items: HeaderLink[];\n}\n\nexport type HeaderConfig = {\n title: HeaderLink;\n subtitle?: HeaderLink;\n breadcrumbs?: HeaderLink[];\n menu?: HeaderMenu[];\n}\n\n@Component({\n selector: 'byu-header',\n imports: [RouterModule],\n templateUrl: './byu-header.component.html',\n styleUrl: './byu-header.component.scss'\n})\nexport class ByuHeaderComponent {\n auth = inject(AuthService)\n config = input<HeaderConfig>();\n\n isHeaderLink(item: HeaderMenu): item is HeaderLink {\n return 'path' in item;\n }\n\n // Track which dropdown is open (null means none are open)\n openDropdownText: string | null = null;\n \n // Toggle function — if clicking the same dropdown, close it; otherwise open it\n toggleDropdown(text: string) {\n this.openDropdownText = this.openDropdownText === text ? null : text;\n }\n \n // Check if a given dropdown is currently open\n isOpen(text: string): boolean {\n return this.openDropdownText === text;\n }\n}\n","<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","import { computed, effect, EffectRef, inject, Injector, signal } from \"@angular/core\";\nimport { isTRPCClientError, Resolver } from \"@trpc/client\";\nimport { ResolverDef, TrpcResource ,TrpcResourceOptions } from \"./trpcResource.types\";\n\nfunction trpcResource<TDef extends ResolverDef>(procedure: Resolver<TDef>, input: () => TDef['input'], options?: TrpcResourceOptions<TDef['output']>): TrpcResource<TDef> {\n const currentInput = computed(input);\n\n const value = signal<TDef['output'] | undefined>(options?.defaultValue, { equal: options?.equal });\n const error = signal<TDef['errorShape'] | undefined>(undefined);\n const isLoading = signal<boolean>(false);\n\n if (options?.autoRefresh) {\n const effectRef = effect((onCleanup) => {\n // pass abort signal to refresh on cleanup of effect\n const controller = new AbortController();\n onCleanup(() => controller.abort());\n\n // call refresh with this abort controller\n // refresh reads currentInput which triggers the effect\n refresh(controller.signal, true);\n }, { injector: options?.injector || inject(Injector)});\n }\n\n const refresh = async (\n abortSignal?: AbortSignal,\n keepLoadingThroughAbort: boolean = true,\n ) => {\n // Reset signals for a fresh request.\n isLoading.set(true);\n error.set(undefined);\n\n try {\n value.set(await procedure(currentInput(), {\n signal: abortSignal\n }));\n error.set(undefined)\n } catch (err) {\n if (isTRPCClientError(err)) {\n // if the trpc request was aborted\n // we check if we would like to continue loading (the next request)\n // if so then we just leave this refresh in an undefined state\n // else we error as usual\n if (err.cause?.name === 'AbortError' && keepLoadingThroughAbort) {\n return;\n }\n error.set(err);\n } else {\n // Fallback for non-Error values\n console.error(\"A non-tRPC error has occured on this trpcResource: \", String(err));\n }\n value.set(options?.defaultValue);\n }\n isLoading.set(false);\n }\n\n return {\n value,\n error,\n isLoading,\n refresh\n };\n}\n\nfunction debugTrpcResource<TDef extends ResolverDef>(_trpcResource: TrpcResource<TDef>) {\n return {\n value: _trpcResource.value(),\n error: _trpcResource.error(),\n isLoading: _trpcResource.isLoading(),\n }\n}\n\nexport { debugTrpcResource, trpcResource };","import { effect, signal, Signal } from \"@angular/core\";\n\nexport const debounced = <T>(inputSignal: Signal<T>, wait: number = 400) => {\n const debouncedSignal = signal<T>(inputSignal());\n const setSignal = debounce((value) => debouncedSignal.set(value), wait);\n\n effect(() => {\n setSignal(inputSignal())\n })\n\n return debouncedSignal;\n}\n\nconst debounce = (callback: (...args: any[]) => void, wait: number) => {\n let timeoutId: number | undefined;\n return (...args: any[]) => {\n window.clearTimeout(timeoutId);\n timeoutId = window.setTimeout(() => {\n callback(...args);\n }, wait);\n };\n}","import { Resolver } from '@trpc/client';\nimport { ResolverDef } from '../../signals/trpcResource/trpcResource.types';\nimport { trpcResource } from '../../signals/trpcResource/trpcResource';\n\nexport type FhssTableConfig<TDef extends ResolverDef> = {\n procedure: Resolver<TDef>;\n columns: {\n [K in keyof TDef['output']['data'][number]]: {\n hide?: boolean;\n header?: string;\n allowSort?: boolean;\n individualFilter?: boolean;\n };\n };\n showSearch?: boolean;\n sorting: {\n defaultSortBy: Extract<keyof TDef['output']['data'][number], string>;\n defaultSortDirection?: 'asc' | 'desc';\n };\n pagination: {\n pageSize: number;\n hideControls?: boolean;\n };\n interaction?:\n | {\n type: 'click';\n onClick: (obj: TDef['output']['data'][number]) => void;\n }\n | {\n type: 'select';\n multi?: boolean;\n };\n};\n\nexport const makeTableConfig = <TDef extends ResolverDef>(\n config: FhssTableConfig<TDef>,\n) => config;\n\nexport type AnyResolver = {\n input: any;\n output: { totalCount: number; data: any[] };\n transformer: any;\n errorShape: {\n code: any;\n message: string;\n data: any;\n };\n};\n\nexport type AnyResource = ReturnType<typeof trpcResource<AnyResolver>>;\n","import {\n Component,\n inject,\n Injector,\n input,\n linkedSignal,\n model,\n OnInit,\n signal,\n} from '@angular/core';\nimport { trpcResource } from '../../signals/trpcResource/trpcResource';\nimport { debounced } from '../../signals/debounced/debounced';\nimport { FhssTableConfig, AnyResolver, AnyResource } from './fhss-table.types';\nexport { makeTableConfig } from './fhss-table.types';\n\nimport { MatTableModule } from '@angular/material/table';\nimport { MatProgressSpinnerModule } from '@angular/material/progress-spinner';\nimport { MatPaginatorModule, PageEvent } from '@angular/material/paginator';\nimport { MatInputModule } from '@angular/material/input';\nimport { FormsModule } from '@angular/forms';\nimport { MatButtonModule } from '@angular/material/button';\nimport { MatSortModule, Sort } from '@angular/material/sort';\nimport { MatIconModule } from '@angular/material/icon';\nimport { MatRippleModule } from '@angular/material/core';\nimport { MatCheckboxModule } from '@angular/material/checkbox';\nimport { SelectionModel } from '@angular/cdk/collections';\n\n@Component({\n selector: 'fhss-table',\n imports: [\n MatTableModule,\n MatProgressSpinnerModule,\n MatPaginatorModule,\n MatInputModule,\n FormsModule,\n MatButtonModule,\n MatSortModule,\n MatIconModule,\n MatRippleModule,\n MatCheckboxModule,\n ],\n templateUrl: './fhss-table.component.html',\n styleUrl: './fhss-table.component.scss',\n})\nexport class FhssTableComponent implements OnInit {\n private injector = inject(Injector);\n\n config = input.required<FhssTableConfig<AnyResolver>>();\n miscParams = input<Record<string, any>>({});\n\n columnKeys: string[] = [];\n columnsToDisplay: string[] = [];\n selection: SelectionModel<any> | undefined;\n selectedValues = model<any[]>([]);\n\n dataResource!: AnyResource;\n\n ngOnInit() {\n const cfg = this.config();\n\n this.columnKeys = Object.keys(cfg.columns);\n this.columnsToDisplay = this.columnKeys.filter((k) => !cfg.columns[k].hide);\n\n if (cfg.interaction?.type === 'select') {\n this.columnsToDisplay.unshift('table-checkbox-column');\n this.selection = new SelectionModel<any>(\n cfg.interaction.multi,\n undefined,\n undefined,\n (o1, o2) => o1.id === o2.id,\n );\n }\n\n this.dataResource = trpcResource(\n this.config().procedure,\n () => ({\n search: this.debouncedSearch(),\n filters: this.debouncedFilters(),\n sort: {\n property: this.sortBy(),\n direction: this.sortDirection(),\n },\n page: {\n size: this.config().pagination.pageSize,\n index: this.pageIndex(),\n },\n ...this.miscParams(),\n }),\n {\n autoRefresh: true,\n injector: this.injector,\n },\n );\n }\n\n search = signal('');\n debouncedSearch = debounced(this.search);\n filters = signal<Record<string, string>>({});\n debouncedFilters = debounced(this.filters);\n\n sortBy = linkedSignal(() => this.config().sorting.defaultSortBy);\n sortDirection = linkedSignal<'asc' | 'desc'>(\n () => this.config().sorting.defaultSortDirection ?? 'asc',\n );\n\n pageIndex = linkedSignal(() => {\n this.search();\n return 0;\n });\n\n onFilterChange(col: string, val: string) {\n this.filters.update((f) => ({ ...f, [col]: val }));\n }\n onPaginationChange(e: PageEvent) {\n this.pageIndex.set(e.pageIndex);\n }\n onSortChange(sort: Sort) {\n this.sortBy.set(sort.active || this.config().sorting.defaultSortBy);\n this.sortDirection.set(\n sort.direction || this.config().sorting.defaultSortDirection || 'asc',\n );\n this.pageIndex.set(0);\n }\n onSelectionChange() {\n this.selectedValues.set(this.selection?.selected ?? []);\n }\n\n onRowClick(row: any) {\n const interaction = this.config().interaction;\n if (!interaction) return;\n\n if (interaction.type === 'click') {\n interaction.onClick(row);\n } else if (interaction.type === 'select') {\n this.selection?.toggle(row);\n }\n this.onSelectionChange();\n }\n\n isAllSelected() {\n if (!this.selection) return false;\n const numSelected = this.selection.selected.length;\n const numRows = this.dataResource.value()?.data?.length ?? 0;\n return numSelected === numRows;\n }\n\n toggleAllRows() {\n if (!this.selection) return;\n if (this.isAllSelected()) {\n this.selection.clear();\n } else {\n this.selection.select(...(this.dataResource.value()?.data ?? []));\n }\n this.onSelectionChange();\n }\n\n checkboxLabel(row?: any): string {\n if (!this.selection) return '';\n if (!row) {\n return `${this.isAllSelected() ? 'deselect' : 'select'} all`;\n }\n return `${this.selection.isSelected(row) ? 'deselect' : 'select'} row ${row.position + 1}`;\n }\n\n protected isBoolean = (val: unknown) => typeof val === 'boolean';\n}\n","<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\" subscriptSizing=\"dynamic\">\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 || key }}\n @if (config().columns[key].individualFilter) {\n <mat-form-field appearance=\"outline\" 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 @if (isBoolean(row[key])) {\n <mat-checkbox [checked]=\"row[key]\" [disabled]=\"true\" />\n } @else {\n {{ row[key] }}\n }\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","import { Provider } from \"@angular/core\";\nimport { FHSS_CONFIG, FhssConfig } from \"./lib.config\";\n\nexport const provideFhss = (config: FhssConfig): Provider => ({\n provide: FHSS_CONFIG,\n useValue: config,\n});\n","import { inject } from '@angular/core';\nimport { CanActivateFn } from '@angular/router';\nimport { AuthService } from '../../services/auth/auth.service';\n\n/**\n * This guard checks if the client is authenticated, redirecting to login if not.\n */\nexport const authGuard: CanActivateFn = (route, state) => {\n const authService = inject(AuthService);\n if(!authService.authenticated()){\n authService.login(state.url);\n return false;\n }\n return true;\n};\n","import { CanActivateFn, RedirectCommand, Router } from '@angular/router';\nimport { FHSS_CONFIG } from '../../config/lib.config';\nimport { AuthService } from '../../services/auth/auth.service';\nimport { inject } from '@angular/core';\n\n/**\n * Generates a guard function to determine if a user has the required roles to access a route.\n *\n * @example\n * ```typescript\n * const routes: Routes = [\n * {\n * path: 'admin',\n * component: AdminPage,\n * canActivate: [roleGuardFactory(Roles.admin)],\n * },\n * ];\n * ```\n */\nexport const roleGuardFactory: (...allowedRoles: string[]) => CanActivateFn = (...allowedRoles) => {\n return (_route, state) => {\n const authService = inject(AuthService);\n const router = inject(Router);\n\n if (!authService.authenticated()) {\n authService.login(state.url);\n return false;\n }\n\n const userRoles = authService.realmAccess()?.roles;\n const hasRole =\n userRoles?.some((role) => allowedRoles.includes(role)) ?? false;\n\n return hasRole || new RedirectCommand(router.parseUrl('/forbidden'));\n };\n};\n","import { Component, inject } from '@angular/core';\nimport { AuthService } from '../../services/auth/auth.service';\n\n@Component({\n selector: 'app-auth-callback',\n imports: [],\n templateUrl: './auth-callback.page.html',\n styleUrl: './auth-callback.page.scss',\n})\nexport class AuthCallbackPage {\n auth = inject(AuthService)\n\n constructor() {\n this.auth.handleAuthCallback();\n }\n}\n","<div class=\"container\">\n <p>Logging you in...</p>\n</div>","import { Component } from '@angular/core';\nimport { ByuFooterComponent } from '../../components/byu-footer/byu-footer.component';\nimport { ByuHeaderComponent } from '../../components/byu-header/byu-header.component';\nimport { MatButtonModule } from '@angular/material/button';\n\n@Component({\n selector: 'fhss-auth-error',\n imports: [MatButtonModule, ByuHeaderComponent, ByuFooterComponent],\n templateUrl: './auth-error.page.html',\n styleUrl: './auth-error.page.scss'\n})\nexport class AuthErrorPage {\n\n}\n","<byu-header />\n\n<div class=\"container\">\n <div class=\"not-found\">\n <img src=\"/sad-duck.jpg\" alt=\"sad duck\" />\n <h1>Login Failed</h1>\n <p>Something went wrong while trying to log you in.</p>\n <a mat-flat-button href=\"/\">Go back to home</a>\n </div>\n</div>\n\n<byu-footer />\n","import { Component } from '@angular/core';\nimport { MatButtonModule } from '@angular/material/button';\nimport { ByuFooterComponent } from '../../components/byu-footer/byu-footer.component';\nimport { ByuHeaderComponent } from '../../components/byu-header/byu-header.component';\n\n@Component({\n selector: 'fhss-forbidden',\n imports: [MatButtonModule, ByuHeaderComponent, ByuFooterComponent],\n templateUrl: './forbidden.page.html',\n styleUrl: './forbidden.page.scss',\n})\nexport class ForbiddenPage {}\n","<byu-header />\n\n<div class=\"container\">\n <div class=\"not-found\">\n <img src=\"/police-duck.jpg\" alt=\"\" />\n <h1>403 - Forbidden</h1>\n <p>You don't have permission to access this page.</p>\n <a mat-flat-button href=\"/\">Go back to home</a>\n </div>\n</div>\n\n<byu-footer />\n","import { Component } from '@angular/core';\nimport { MatButtonModule } from '@angular/material/button';\nimport { ByuFooterComponent } from '../../components/byu-footer/byu-footer.component';\nimport { ByuHeaderComponent } from '../../components/byu-header/byu-header.component';\n\n@Component({\n selector: 'fhss-not-found',\n imports: [MatButtonModule, ByuHeaderComponent, ByuFooterComponent],\n templateUrl: './not-found.page.html',\n styleUrl: './not-found.page.scss',\n})\nexport class NotFoundPage {}\n","<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","import { computed, effect, EffectRef, inject, Injector, signal, untracked } from '@angular/core';\nimport { FetchSignal, FetchSignalFactory, FetchSignalOptions, FetchSignalRequest, FetchSignalStatus, HttpMethod, Json, ResponseTransformer } from './fetch-signal.types';\n\n\n/**\n * Creates a reactive fetch signal.\n *\n * The request function can include Signals for properties. These are unwrapped in the refresh function.\n */\nfunction createFetchSignal<Response, ErrorResponse, RawResponse>(\n request: () => FetchSignalRequest,\n method: HttpMethod,\n transform: ResponseTransformer<Response>,\n options?: FetchSignalOptions<Response, RawResponse>,\n): FetchSignal<Response, ErrorResponse> {\n // Use a computed signal so that any changes to Signals in the request object trigger updates.\n const currentRequest = computed<FetchSignalRequest>(request);\n\n const value = signal<Response | undefined>(options?.defaultValue, { equal: options?.equal });\n const errorResponse = signal<ErrorResponse | undefined>(undefined);\n const isLoading = signal<boolean>(false);\n const statusCode = signal<number | undefined>(undefined);\n const headers = signal<Record<string, string> | undefined>(undefined);\n\n const status = signal<FetchSignalStatus>('idle');\n const error = signal<Error | undefined>(undefined);\n\n const injector = inject(Injector);\n let effectRef: EffectRef | undefined = undefined;\n if (options?.autoRefresh) {\n effectRef = effect((onCleanup) => {\n // pass abort signal to refresh on cleanup of effect\n const controller = new AbortController();\n onCleanup(() => controller.abort());\n\n // call refresh with this abort controller\n refresh(controller.signal, true);\n }, { injector: options?.injector || injector});\n }\n\n const refresh = async (\n abortSignal?: AbortSignal,\n keepLoadingThroughAbort?: boolean,\n ) => {\n // if the fetchSignal has been destroyed, do nothing\n if (untracked(status) === 'destroyed') return;\n\n // Reset signals for a fresh request.\n isLoading.set(true);\n errorResponse.set(undefined);\n statusCode.set(undefined);\n headers.set(undefined);\n status.set('loading');\n error.set(undefined);\n\n // Unwrap the current request.\n const req = currentRequest();\n const url = req.url;\n const params = req.params;\n const requestHeaders = req.headers;\n const body = req.body;\n\n // Build URL with query parameters.\n let uri = url;\n if (params) {\n const searchParams = new URLSearchParams();\n for (const key in params) {\n if (params[key] !== undefined)\n searchParams.append(key, String(params[key]));\n }\n uri += (uri.includes('?') ? '&' : '?') + searchParams.toString();\n }\n \n // Filter out undefined header values\n const filteredHeaders = requestHeaders\n ? Object.fromEntries(\n Object.entries(requestHeaders).filter(\n ([, value]) => value !== undefined\n ) as [string, string][]\n )\n : undefined;\n \n try {\n // send the request\n const response = await fetch(uri, {\n method,\n headers: filteredHeaders,\n // Only include a body if one is provided.\n body: body,\n signal: abortSignal,\n });\n\n // set the status code\n statusCode.set(response.status);\n\n // Extract response headers.\n const headersObj: Record<string, string> = {};\n response.headers.forEach((val, key) => {\n headersObj[key] = val;\n });\n headers.set(headersObj);\n\n // if the response is ok, transform the body\n if (response.ok) {\n value.set(await transform(response));\n status.set('resolved');\n } else {\n // try to parse the error as json\n try {\n errorResponse.set(await response.json());\n value.set(undefined);\n status.set('resolved');\n } catch {\n throw new Error('Unable to parse error response.')\n }\n }\n } catch (err: any) {\n if (err instanceof Error) {\n // if the fetch request was aborted\n // we check if we would like to continue loading (the next request)\n // if so then we just leave this refresh in an undefined state\n // else we error as usual\n if (err.name === 'AbortError' && keepLoadingThroughAbort) {\n return;\n }\n error.set(err);\n } else {\n // Fallback for non-Error values\n error.set(new Error(String(err)));\n }\n value.set(undefined);\n status.set('error');\n }\n isLoading.set(false);\n };\n\n const destroy = () => {\n // if the fetchSignal has been destroyed, do nothing\n if (status() === 'destroyed') return;\n\n if (effectRef) {\n effectRef.destroy();\n }\n status.set('destroyed');\n value.set(undefined);\n errorResponse.set(undefined);\n isLoading.set(false);\n statusCode.set(undefined);\n headers.set(undefined);\n error.set(undefined);\n }\n\n return {\n value,\n errorResponse,\n isLoading,\n statusCode,\n headers,\n status,\n error,\n refresh,\n destroy\n };\n}\n\n//\n// Helpers for attaching response transforms.\n//\nconst createHelper = <Response, Error>(method: HttpMethod, transform: ResponseTransformer<Response>) =>\n (request: () => FetchSignalRequest, options?: FetchSignalOptions<Response, any>): FetchSignal<Response, Error> =>\n createFetchSignal<Response, Error, any>(request, method, transform, options);\n\n// Transforms\nconst jsonTransformer: ResponseTransformer<any> = (response: Response) => response.json();\nconst textTransformer: ResponseTransformer<string> = (response: Response) => response.text();\nconst blobTransformer: ResponseTransformer<Blob> = (response: Response) => response.blob();\nconst arrayBufferTransformer: ResponseTransformer<ArrayBuffer> = (response: Response) => response.arrayBuffer();\n\n//\n// Build the defaults - GET chain\n//\nconst fetchSignal = createHelper('GET', jsonTransformer) as FetchSignalFactory;\nfetchSignal.json = createHelper('GET', jsonTransformer);\nfetchSignal.text = createHelper('GET', textTransformer);\nfetchSignal.blob = createHelper('GET', blobTransformer);\nfetchSignal.arrayBuffer = createHelper('GET', arrayBufferTransformer);\n\n//\n// Build the GET chain\n//\nfetchSignal.get = createHelper(\n 'GET',\n jsonTransformer,\n) as FetchSignalFactory['get'];\nfetchSignal.get.json = createHelper('GET', jsonTransformer);\nfetchSignal.get.text = createHelper('GET', textTransformer);\nfetchSignal.get.blob = createHelper('GET', blobTransformer);\nfetchSignal.get.arrayBuffer = createHelper('GET', arrayBufferTransformer);\n\n//\n// Build the POST chain.\n//\nfetchSignal.post = createHelper(\n 'POST',\n jsonTransformer,\n) as FetchSignalFactory['post'];\nfetchSignal.post.json = createHelper('POST', jsonTransformer);\nfetchSignal.post.text = createHelper('POST', textTransformer);\nfetchSignal.post.blob = createHelper('POST', blobTransformer);\nfetchSignal.post.arrayBuffer = createHelper('POST', arrayBufferTransformer);\n\n//\n// Build the PUT chain.\n//\nfetchSignal.put = createHelper(\n 'PUT',\n jsonTransformer,\n) as FetchSignalFactory['put'];\nfetchSignal.put.json = createHelper('PUT', jsonTransformer);\nfetchSignal.put.text = createHelper('PUT', textTransformer);\nfetchSignal.put.blob = createHelper('PUT', blobTransformer);\nfetchSignal.put.arrayBuffer = createHelper('PUT', arrayBufferTransformer);\n\n//\n// Build the PATCH chain.\n//\nfetchSignal.patch = createHelper(\n 'PATCH',\n jsonTransformer,\n) as FetchSignalFactory['patch'];\nfetchSignal.patch.json = createHelper('PATCH', jsonTransformer);\nfetchSignal.patch.text = createHelper('PATCH', textTransformer);\nfetchSignal.patch.blob = createHelper('PATCH', blobTransformer);\nfetchSignal.patch.arrayBuffer = createHelper('PATCH', arrayBufferTransformer);\n\n//\n// Build the DELETE chain\n//\nfetchSignal.delete = createHelper(\n 'DELETE',\n jsonTransformer,\n) as FetchSignalFactory['delete'];\nfetchSignal.delete.json = createHelper('DELETE', jsonTransformer);\nfetchSignal.delete.text = createHelper('DELETE', textTransformer);\nfetchSignal.delete.blob = createHelper('DELETE', blobTransformer);\nfetchSignal.delete.arrayBuffer = createHelper('DELETE', arrayBufferTransformer);\n\nexport { fetchSignal };\nexport type { Json };\n\n","/**\n * Components\n */\nexport * from './lib/components/byu-footer/byu-footer.component'\nexport * from './lib/components/byu-header/byu-header.component'\nexport * from './lib/components/fhss-table/fhss-table.component'\n\n/**\n * Config\n */\nexport * from './lib/config/lib.config'\nexport * from './lib/config/utils.config'\n\n/**\n * Guards\n */\nexport * from './lib/guards/auth/auth.guard'\nexport * from './lib/guards/role/role.guard'\n\n/**\n * Pages\n */\nexport * from './lib/pages/auth-callback/auth-callback.page'\nexport * from './lib/pages/auth-error/auth-error.page'\nexport * from './lib/pages/forbidden/forbidden.page'\nexport * from './lib/pages/not-found/not-found.page'\n\n/**\n * Services\n */\nexport * from './lib/services/auth/auth.service'\n\n/**\n * Signals\n */\nexport * from './lib/signals/trpcResource/trpcResource'\nexport * from './lib/signals/fetch-signal/fetch-signal'\nexport * from './lib/signals/debounced/debounced'","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i6","i1"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAQa,kBAAkB,CAAA;IAC7B,WAAW,GAAW,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;wGADpC,kBAAkB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAlB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,kBAAkB,sECR/B,6WAUA,EAAA,MAAA,EAAA,CAAA,+cAAA,CAAA,EAAA,CAAA;;4FDFa,kBAAkB,EAAA,UAAA,EAAA,CAAA;kBAN9B,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,YAAY,WACb,EAAE,EAAA,QAAA,EAAA,6WAAA,EAAA,MAAA,EAAA,CAAA,+cAAA,CAAA,EAAA;;;MEFA,WAAW,GAAG,IAAI,cAAc,CAAa,aAAa;;AC2BvE;;;AAGG;MACU,WAAW,CAAA;AACd,IAAA,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;AAC3B,IAAA,cAAc,GAAG,MAAM,CAAC,qBAAqB,CAAC;AAC9C,IAAA,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;AACvB,IAAA,MAAM,GAAG,MAAM,CAAC,WAAW,CAAC;IAEnB,UAAU,GAAG,SAAS;AACtB,IAAA,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;AAE5C;;;AAGG;AACH,IAAA,aAAa,GAAG,MAAM,CAAC,KAAK,CAAC;AAE7B,IAAA,WAAA,GAAA;QACE,eAAe,CAAC,MAAK;YACnB,MAAM,CACJ,MAAK;AACH,gBAAA,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,EAAE;gBACrC,IAAI,OAAO,CAAC,IAAI,KAAK,iBAAiB,CAAC,KAAK,EAAE;AAC5C,oBAAA,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,aAAa,CAAY,OAAO,CAAC,IAAI,CAAC,CAAC;;gBAEhE,IAAI,OAAO,CAAC,IAAI,KAAK,iBAAiB,CAAC,UAAU,EAAE;AACjD,oBAAA,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC;;aAEhC,EACD,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAC5B;AACH,SAAC,CAAC;;AAGJ;;;AAGG;AACH,IAAA,KAAK,GAAG,CAAC,OAAgB,KAAI;QAC3B,IAAI,OAAO,EAAE;YACX,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC;;AAElD,QAAA,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;AAClB,YAAA,WAAW,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,gBAAgB;AACvD,SAAA,CAAC;AACJ,KAAC;AAED;;;;;AAKG;IACH,gBAAgB,GAAG,MAAK;AACtB,QAAA,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE;AAAE,YAAA,OAAO,IAAI;AAEtC,QAAA,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,KAAK,CAAC;QACpD,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE;AAC5C,YAAA,IAAI,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;gBACvB,OAAO,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC;;;AAG1C,QAAA,OAAO,IAAI;AACb,KAAC;AAED;;;;AAIG;IACH,kBAAkB,GAAG,YAA0B;AAC7C,QAAA,IAAI;YACF,MAAM,UAAU,GAAG,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC;AAC1D,YAAA,cAAc,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC;AAE1C,YAAA,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE;gBACzB,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC;gBAC3B;;AAGF,YAAA,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,oBAAoB,EAAE;gBACrE,OAAO,EAAE,EAAE,aAAa,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,EAAE,EAAE;AACrD,aAAA,CAAC;YAEF,IAAI,CAAC,GAAG,CAAC,EAAE;AAAE,gBAAA,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC;YACxD,MAAM,WAAW,GACf,GAAG,CAAC,MAAM,KAAK,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,EAAE,IAAI,GAAG,IAAI;AAErD,YAAA,MAAM,aAAa,GAAG,IAAI,CAAC,gBAAgB,EAAE;YAE7C,MAAM,SAAS,GAAG,WAAW,IAAI,UAAU,IAAI,aAAa,IAAI,GAAG;YACnE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC;;QACjC,OAAO,GAAG,EAAE;AACZ,YAAA,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC;AAClB,YAAA,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC;;AAE9B,KAAC;AAED;;AAEG;IACH,MAAM,GAAG,CAAC,OAAgB,KACxB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;QACnB,WAAW,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,IAAI,OAAO,IAAI,GAAG,CAAC;AACvD,KAAA,CAAC;AAEJ;;AAEG;AACH,IAAA,KAAK,GAAG,QAAQ,CAAqB,MAAK;QACxC,IAAI,CAAC,cAAc,EAAE;AACrB,QAAA,OAAO,IAAI,CAAC,QAAQ,CAAC,KAAK;AAC5B,KAAC,CAAC;AAEF;;AAEG;IACH,WAAW,GAAG,QAAQ,CAAqB,MACzC,IAAI,CAAC,KAAK,EAAE,GAAG,SAAS,GAAG,IAAI,CAAC,KAAK,EAAE,GAAG,SAAS,CACpD;AAED;;AAEG;AACH,IAAA,WAAW,GAAG,QAAQ,CAAkC,MAAK;QAC3D,IAAI,CAAC,cAAc,EAAE;AACrB,QAAA,OAAO,IAAI,CAAC,QAAQ,CAAC,WAAW;AAClC,KAAC,CAAC;AAEF;;AAEG;AACH,IAAA,MAAM,GAAG,QAAQ,CAAqB,MAAK;QACzC,IAAI,CAAC,cAAc,EAAE;AACrB,QAAA,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO;AAC9B,KAAC,CAAC;AAEF;;AAEG;AACH,IAAA,OAAO,GAAG,QAAQ,CAAqB,MAAK;QAC1C,IAAI,CAAC,cAAc,EAAE;AACrB,QAAA,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO;AAC9B,KAAC,CAAC;AAEF;;AAEG;AACH,IAAA,aAAa,GAAG,QAAQ,CAAkC,MAAK;QAC7D,IAAI,CAAC,cAAc,EAAE;AACrB,QAAA,OAAO,IAAI,CAAC,QAAQ,CAAC,aAAa;AACpC,KAAC,CAAC;AAEF;;AAEG;AACH,IAAA,WAAW,GAAG,QAAQ,CAA4B,MAAK;QACrD,IAAI,CAAC,cAAc,EAAE;AACrB,QAAA,OAAO,IAAI,CAAC,QAAQ,CAAC,WAAW;AAClC,KAAC,CAAC;AAEF;;AAEG;AACH,IAAA,cAAc,GAAG,QAAQ,CAAqC,MAAK;QACjE,IAAI,CAAC,cAAc,EAAE;AACrB,QAAA,OAAO,IAAI,CAAC,QAAQ,CAAC,cAAc;AACrC,KAAC,CAAC;AAEF;;AAEG;AACH,IAAA,YAAY,GAAG,QAAQ,CAAqB,MAAK;QAC/C,IAAI,CAAC,cAAc,EAAE;AACrB,QAAA,OAAO,IAAI,CAAC,QAAQ,CAAC,YAAY;AACnC,KAAC,CAAC;AAEF;;AAEG;AACH,IAAA,kBAAkB,GAAG,QAAQ,CAAkC,MAAK;QAClE,IAAI,CAAC,cAAc,EAAE;AACrB,QAAA,OAAO,IAAI,CAAC,QAAQ,CAAC,kBAAkB;AACzC,KAAC,CAAC;AAEF;;AAEG;AACH,IAAA,QAAQ,GAAG,QAAQ,CAAqB,MAAK;QAC3C,IAAI,CAAC,cAAc,EAAE;AACrB,QAAA,OAAO,IAAI,CAAC,QAAQ,CAAC,QAAQ;AAC/B,KAAC,CAAC;AAEF;;AAEG;AACH,IAAA,YAAY,GAAG,QAAQ,CAAmC,MAAK;QAC7D,IAAI,CAAC,cAAc,EAAE;AACrB,QAAA,OAAO,IAAI,CAAC,QAAQ,CAAC,YAAY;AACnC,KAAC,CAAC;AAEF;;AAEG;AACH,IAAA,IAAI,GAAG,QAAQ,CAA2B,MAAK;QAC7C,IAAI,CAAC,cAAc,EAAE;AACrB,QAAA,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI;AAC3B,KAAC,CAAC;AAEF;;AAEG;AACH,IAAA,YAAY,GAAG,QAAQ,CAAmC,MAAK;QAC7D,IAAI,CAAC,cAAc,EAAE;AACrB,QAAA,OAAO,IAAI,CAAC,QAAQ,CAAC,YAAY;AACnC,KAAC,CAAC;wGArNS,WAAW,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAAX,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAW,cANV,MAAM,EAAA,CAAA;;4FAMP,WAAW,EAAA,UAAA,EAAA,CAAA;kBAPvB,UAAU;AAAC,YAAA,IAAA,EAAA,CAAA;AACV,oBAAA,UAAU,EAAE,MAAM;AACnB,iBAAA;;;MCCY,kBAAkB,CAAA;AAC7B,IAAA,IAAI,GAAG,MAAM,CAAC,WAAW,CAAC;IAC1B,MAAM,GAAG,KAAK,EAAgB;AAE9B,IAAA,YAAY,CAAC,IAAgB,EAAA;QAC3B,OAAO,MAAM,IAAI,IAAI;;;IAIvB,gBAAgB,GAAkB,IAAI;;AAGtC,IAAA,cAAc,CAAC,IAAY,EAAA;AACzB,QAAA,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,gBAAgB,KAAK,IAAI,GAAG,IAAI,GAAG,IAAI;;;AAItE,IAAA,MAAM,CAAC,IAAY,EAAA;AACjB,QAAA,OAAO,IAAI,CAAC,gBAAgB,KAAK,IAAI;;wGAlB5B,kBAAkB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;4FAAlB,kBAAkB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,YAAA,EAAA,MAAA,EAAA,EAAA,MAAA,EAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,UAAA,EAAA,QAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EC7B/B,0uEAmDA,EAAA,MAAA,EAAA,CAAA,0pEAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,ED1BY,YAAY,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,UAAA,EAAA,QAAA,EAAA,cAAA,EAAA,MAAA,EAAA,CAAA,QAAA,EAAA,aAAA,EAAA,UAAA,EAAA,qBAAA,EAAA,OAAA,EAAA,MAAA,EAAA,YAAA,EAAA,kBAAA,EAAA,oBAAA,EAAA,YAAA,EAAA,YAAA,CAAA,EAAA,CAAA,EAAA,CAAA;;4FAIX,kBAAkB,EAAA,UAAA,EAAA,CAAA;kBAN9B,SAAS;+BACE,YAAY,EAAA,OAAA,EACb,CAAC,YAAY,CAAC,EAAA,QAAA,EAAA,0uEAAA,EAAA,MAAA,EAAA,CAAA,0pEAAA,CAAA,EAAA;;;AErBzB,SAAS,YAAY,CAA2B,SAAyB,EAAE,KAA0B,EAAE,OAA6C,EAAA;AAClJ,IAAA,MAAM,YAAY,GAAG,QAAQ,CAAC,KAAK,CAAC;AAEpC,IAAA,MAAM,KAAK,GAAG,MAAM,CAA6B,OAAO,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AAClG,IAAA,MAAM,KAAK,GAAG,MAAM,CAAiC,SAAS,CAAC;AAC/D,IAAA,MAAM,SAAS,GAAG,MAAM,CAAU,KAAK,CAAC;AAExC,IAAA,IAAI,OAAO,EAAE,WAAW,EAAE;AACxB,QAAA,MAAM,SAAS,GAAG,MAAM,CAAC,CAAC,SAAS,KAAI;;AAErC,YAAA,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE;YACxC,SAAS,CAAC,MAAM,UAAU,CAAC,KAAK,EAAE,CAAC;;;AAInC,YAAA,OAAO,CAAC,UAAU,CAAC,MAAM,EAAE,IAAI,CAAC;AAClC,SAAC,EAAE,EAAE,QAAQ,EAAG,OAAO,EAAE,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,EAAC,CAAC;;IAGzD,MAAM,OAAO,GAAG,OACd,WAAyB,EACzB,uBAAA,GAAmC,IAAI,KACrC;;AAEF,QAAA,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;AACnB,QAAA,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC;AAEpB,QAAA,IAAI;YACF,KAAK,CAAC,GAAG,CAAC,MAAM,SAAS,CAAC,YAAY,EAAE,EAAE;AACxC,gBAAA,MAAM,EAAE;AACT,aAAA,CAAC,CAAC;AACH,YAAA,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC;;QACpB,OAAO,GAAG,EAAE;AACZ,YAAA,IAAI,iBAAiB,CAAC,GAAG,CAAC,EAAE;;;;;gBAK1B,IAAI,GAAG,CAAC,KAAK,EAAE,IAAI,KAAK,YAAY,IAAI,uBAAuB,EAAE;oBAC/D;;AAEF,gBAAA,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC;;iBACT;;gBAEL,OAAO,CAAC,KAAK,CAAC,qDAAqD,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC;;AAEnF,YAAA,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,YAAY,CAAC;;AAElC,QAAA,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC;AACtB,KAAC;IAED,OAAO;QACL,KAAK;QACL,KAAK;QACL,SAAS;QACT;KACD;AACH;AAEA,SAAS,iBAAiB,CAA2B,aAAiC,EAAA;IACpF,OAAO;AACL,QAAA,KAAK,EAAE,aAAa,CAAC,KAAK,EAAE;AAC5B,QAAA,KAAK,EAAE,aAAa,CAAC,KAAK,EAAE;AAC5B,QAAA,SAAS,EAAE,aAAa,CAAC,SAAS,EAAE;KACrC;AACH;;ACnEa,MAAA,SAAS,GAAG,CAAI,WAAsB,EAAE,IAAA,GAAe,GAAG,KAAI;AACzE,IAAA,MAAM,eAAe,GAAG,MAAM,CAAI,WAAW,EAAE,CAAC;AAChD,IAAA,MAAM,SAAS,GAAG,QAAQ,CAAC,CAAC,KAAK,KAAK,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC;IAEvE,MAAM,CAAC,MAAK;AACV,QAAA,SAAS,CAAC,WAAW,EAAE,CAAC;AAC1B,KAAC,CAAC;AAEF,IAAA,OAAO,eAAe;AACxB;AAEA,MAAM,QAAQ,GAAG,CAAC,QAAkC,EAAE,IAAY,KAAI;AACpE,IAAA,IAAI,SAA6B;AACjC,IAAA,OAAO,CAAC,GAAG,IAAW,KAAI;AACxB,QAAA,MAAM,CAAC,YAAY,CAAC,SAAS,CAAC;AAC9B,QAAA,SAAS,GAAG,MAAM,CAAC,UAAU,CAAC,MAAK;AACjC,YAAA,QAAQ,CAAC,GAAG,IAAI,CAAC;SAClB,EAAE,IAAI,CAAC;AACV,KAAC;AACH,CAAC;;ACaY,MAAA,eAAe,GAAG,CAC7B,MAA6B,KAC1B;;MCQQ,kBAAkB,CAAA;AACrB,IAAA,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;AAEnC,IAAA,MAAM,GAAG,KAAK,CAAC,QAAQ,EAAgC;AACvD,IAAA,UAAU,GAAG,KAAK,CAAsB,EAAE,CAAC;IAE3C,UAAU,GAAa,EAAE;IACzB,gBAAgB,GAAa,EAAE;AAC/B,IAAA,SAAS;AACT,IAAA,cAAc,GAAG,KAAK,CAAQ,EAAE,CAAC;AAEjC,IAAA,YAAY;IAEZ,QAAQ,GAAA;AACN,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE;QAEzB,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC;QAC1C,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAE3E,IAAI,GAAG,CAAC,WAAW,EAAE,IAAI,KAAK,QAAQ,EAAE;AACtC,YAAA,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,uBAAuB,CAAC;AACtD,YAAA,IAAI,CAAC,SAAS,GAAG,IAAI,cAAc,CACjC,GAAG,CAAC,WAAW,CAAC,KAAK,EACrB,SAAS,EACT,SAAS,EACT,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAC5B;;AAGH,QAAA,IAAI,CAAC,YAAY,GAAG,YAAY,CAC9B,IAAI,CAAC,MAAM,EAAE,CAAC,SAAS,EACvB,OAAO;AACL,YAAA,MAAM,EAAE,IAAI,CAAC,eAAe,EAAE;AAC9B,YAAA,OAAO,EAAE,IAAI,CAAC,gBAAgB,EAAE;AAChC,YAAA,IAAI,EAAE;AACJ,gBAAA,QAAQ,EAAE,IAAI,CAAC,MAAM,EAAE;AACvB,gBAAA,SAAS,EAAE,IAAI,CAAC,aAAa,EAAE;AAChC,aAAA;AACD,YAAA,IAAI,EAAE;gBACJ,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,UAAU,CAAC,QAAQ;AACvC,gBAAA,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE;AACxB,aAAA;YACD,GAAG,IAAI,CAAC,UAAU,EAAE;AACrB,SAAA,CAAC,EACF;AACE,YAAA,WAAW,EAAE,IAAI;YACjB,QAAQ,EAAE,IAAI,CAAC,QAAQ;AACxB,SAAA,CACF;;AAGH,IAAA,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;AACnB,IAAA,eAAe,GAAG,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC;AACxC,IAAA,OAAO,GAAG,MAAM,CAAyB,EAAE,CAAC;AAC5C,IAAA,gBAAgB,GAAG,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC;AAE1C,IAAA,MAAM,GAAG,YAAY,CAAC,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,aAAa,CAAC;AAChE,IAAA,aAAa,GAAG,YAAY,CAC1B,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,oBAAoB,IAAI,KAAK,CAC1D;AAED,IAAA,SAAS,GAAG,YAAY,CAAC,MAAK;QAC5B,IAAI,CAAC,MAAM,EAAE;AACb,QAAA,OAAO,CAAC;AACV,KAAC,CAAC;IAEF,cAAc,CAAC,GAAW,EAAE,GAAW,EAAA;QACrC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,GAAG,EAAE,CAAC,CAAC;;AAEpD,IAAA,kBAAkB,CAAC,CAAY,EAAA;QAC7B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;;AAEjC,IAAA,YAAY,CAAC,IAAU,EAAA;AACrB,QAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,aAAa,CAAC;QACnE,IAAI,CAAC,aAAa,CAAC,GAAG,CACpB,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,oBAAoB,IAAI,KAAK,CACtE;AACD,QAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;;IAEvB,iBAAiB,GAAA;AACf,QAAA,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,IAAI,EAAE,CAAC;;AAGzD,IAAA,UAAU,CAAC,GAAQ,EAAA;QACjB,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,WAAW;AAC7C,QAAA,IAAI,CAAC,WAAW;YAAE;AAElB,QAAA,IAAI,WAAW,CAAC,IAAI,KAAK,OAAO,EAAE;AAChC,YAAA,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC;;AACnB,aAAA,IAAI,WAAW,CAAC,IAAI,KAAK,QAAQ,EAAE;AACxC,YAAA,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC;;QAE7B,IAAI,CAAC,iBAAiB,EAAE;;IAG1B,aAAa,GAAA;QACX,IAAI,CAAC,IAAI,CAAC,SAAS;AAAE,YAAA,OAAO,KAAK;QACjC,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM;AAClD,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC;QAC5D,OAAO,WAAW,KAAK,OAAO;;IAGhC,aAAa,GAAA;QACX,IAAI,CAAC,IAAI,CAAC,SAAS;YAAE;AACrB,QAAA,IAAI,IAAI,CAAC,aAAa,EAAE,EAAE;AACxB,YAAA,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE;;aACjB;AACL,YAAA,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC;;QAEnE,IAAI,CAAC,iBAAiB,EAAE;;AAG1B,IAAA,aAAa,CAAC,GAAS,EAAA;QACrB,IAAI,CAAC,IAAI,CAAC,SAAS;AAAE,YAAA,OAAO,EAAE;QAC9B,IAAI,CAAC,GAAG,EAAE;AACR,YAAA,OAAO,CAAG,EAAA,IAAI,CAAC,aAAa,EAAE,GAAG,UAAU,GAAG,QAAQ,MAAM;;QAE9D,OAAO,CAAA,EAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,UAAU,GAAG,QAAQ,CAAQ,KAAA,EAAA,GAAG,CAAC,QAAQ,GAAG,CAAC,CAAA,CAAE;;IAGlF,SAAS,GAAG,CAAC,GAAY,KAAK,OAAO,GAAG,KAAK,SAAS;wGAxHrD,kBAAkB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;4FAAlB,kBAAkB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,YAAA,EAAA,MAAA,EAAA,EAAA,MAAA,EAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,UAAA,EAAA,QAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,iBAAA,EAAA,YAAA,EAAA,UAAA,EAAA,YAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,cAAA,EAAA,EAAA,iBAAA,EAAA,gBAAA,EAAA,UAAA,EAAA,gBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,OAAA,EAAA,EAAA,cAAA,EAAA,sBAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EC5C/B,oiJAkJA,EDpHI,MAAA,EAAA,CAAA,2dAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,cAAc,inCACd,wBAAwB,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,kBAAA,EAAA,QAAA,EAAA,mCAAA,EAAA,MAAA,EAAA,CAAA,OAAA,EAAA,MAAA,EAAA,OAAA,EAAA,UAAA,EAAA,aAAA,CAAA,EAAA,QAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EACxB,kBAAkB,EAClB,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,YAAA,EAAA,QAAA,EAAA,eAAA,EAAA,MAAA,EAAA,CAAA,OAAA,EAAA,WAAA,EAAA,QAAA,EAAA,UAAA,EAAA,iBAAA,EAAA,cAAA,EAAA,sBAAA,EAAA,cAAA,EAAA,UAAA,CAAA,EAAA,OAAA,EAAA,CAAA,MAAA,CAAA,EAAA,QAAA,EAAA,CAAA,cAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,cAAc,6sBACd,WAAW,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,oBAAA,EAAA,QAAA,EAAA,8MAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,eAAA,EAAA,QAAA,EAAA,2CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,OAAA,EAAA,QAAA,EAAA,qDAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,UAAA,EAAA,SAAA,EAAA,gBAAA,CAAA,EAAA,OAAA,EAAA,CAAA,eAAA,CAAA,EAAA,QAAA,EAAA,CAAA,SAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EACX,eAAe,EACf,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAAA,IAAA,CAAA,SAAA,EAAA,QAAA,EAAA,6GAAA,EAAA,QAAA,EAAA,CAAA,WAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAAA,IAAA,CAAA,aAAA,EAAA,QAAA,EAAA,yBAAA,EAAA,QAAA,EAAA,CAAA,WAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,aAAa,idACb,aAAa,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,OAAA,EAAA,QAAA,EAAA,UAAA,EAAA,MAAA,EAAA,CAAA,OAAA,EAAA,QAAA,EAAA,SAAA,EAAA,SAAA,EAAA,UAAA,CAAA,EAAA,QAAA,EAAA,CAAA,SAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EACb,eAAe,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,SAAA,EAAA,QAAA,EAAA,2BAAA,EAAA,MAAA,EAAA,CAAA,gBAAA,EAAA,oBAAA,EAAA,mBAAA,EAAA,iBAAA,EAAA,oBAAA,EAAA,mBAAA,EAAA,kBAAA,CAAA,EAAA,QAAA,EAAA,CAAA,WAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EACf,iBAAiB,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,GAAA,CAAA,WAAA,EAAA,QAAA,EAAA,cAAA,EAAA,MAAA,EAAA,CAAA,YAAA,EAAA,iBAAA,EAAA,kBAAA,EAAA,eAAA,EAAA,eAAA,EAAA,WAAA,EAAA,IAAA,EAAA,UAAA,EAAA,eAAA,EAAA,MAAA,EAAA,OAAA,EAAA,eAAA,EAAA,UAAA,EAAA,OAAA,EAAA,qBAAA,EAAA,SAAA,EAAA,UAAA,EAAA,eAAA,CAAA,EAAA,OAAA,EAAA,CAAA,QAAA,EAAA,qBAAA,CAAA,EAAA,QAAA,EAAA,CAAA,aAAA,CAAA,EAAA,CAAA,EAAA,CAAA;;4FAKR,kBAAkB,EAAA,UAAA,EAAA,CAAA;kBAjB9B,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,YAAY,EACb,OAAA,EAAA;wBACP,cAAc;wBACd,wBAAwB;wBACxB,kBAAkB;wBAClB,cAAc;wBACd,WAAW;wBACX,eAAe;wBACf,aAAa;wBACb,aAAa;wBACb,eAAe;wBACf,iBAAiB;AAClB,qBAAA,EAAA,QAAA,EAAA,oiJAAA,EAAA,MAAA,EAAA,CAAA,2dAAA,CAAA,EAAA;;;MErCU,WAAW,GAAG,CAAC,MAAkB,MAAgB;AAC5D,IAAA,OAAO,EAAE,WAAW;AACpB,IAAA,QAAQ,EAAE,MAAM;AACjB,CAAA;;ACFD;;AAEG;MACU,SAAS,GAAkB,CAAC,KAAK,EAAE,KAAK,KAAI;AACvD,IAAA,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;AACvC,IAAA,IAAG,CAAC,WAAW,CAAC,aAAa,EAAE,EAAC;AAC9B,QAAA,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;AAC5B,QAAA,OAAO,KAAK;;AAEd,IAAA,OAAO,IAAI;AACb;;ACTA;;;;;;;;;;;;;AAaG;MACU,gBAAgB,GAAiD,CAAC,GAAG,YAAY,KAAI;AAChG,IAAA,OAAO,CAAC,MAAM,EAAE,KAAK,KAAI;AACvB,QAAA,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;AACvC,QAAA,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;AAE7B,QAAA,IAAI,CAAC,WAAW,CAAC,aAAa,EAAE,EAAE;AAChC,YAAA,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;AAC5B,YAAA,OAAO,KAAK;;QAGd,MAAM,SAAS,GAAG,WAAW,CAAC,WAAW,EAAE,EAAE,KAAK;QAClD,MAAM,OAAO,GACX,SAAS,EAAE,IAAI,CAAC,CAAC,IAAI,KAAK,YAAY,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK;AAEjE,QAAA,OAAO,OAAO,IAAI,IAAI,eAAe,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;AACtE,KAAC;AACH;;MC1Ba,gBAAgB,CAAA;AAC3B,IAAA,IAAI,GAAG,MAAM,CAAC,WAAW,CAAC;AAE1B,IAAA,WAAA,GAAA;AACE,QAAA,IAAI,CAAC,IAAI,CAAC,kBAAkB,EAAE;;wGAJrB,gBAAgB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAhB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,gBAAgB,6ECT7B,+DAEM,EAAA,MAAA,EAAA,CAAA,wKAAA,CAAA,EAAA,CAAA;;4FDOO,gBAAgB,EAAA,UAAA,EAAA,CAAA;kBAN5B,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,mBAAmB,WACpB,EAAE,EAAA,QAAA,EAAA,+DAAA,EAAA,MAAA,EAAA,CAAA,wKAAA,CAAA,EAAA;;;MEMA,aAAa,CAAA;wGAAb,aAAa,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAb,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,aAAa,2ECX1B,mTAYA,EAAA,MAAA,EAAA,CAAA,kOAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EDLY,eAAe,EAAE,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAAC,IAAA,CAAA,SAAA,EAAA,QAAA,EAAA,gFAAA,EAAA,QAAA,EAAA,CAAA,WAAA,EAAA,WAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,kBAAkB,2EAAE,kBAAkB,EAAA,QAAA,EAAA,YAAA,EAAA,CAAA,EAAA,CAAA;;4FAItD,aAAa,EAAA,UAAA,EAAA,CAAA;kBANzB,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,iBAAiB,WAClB,CAAC,eAAe,EAAE,kBAAkB,EAAE,kBAAkB,CAAC,EAAA,QAAA,EAAA,mTAAA,EAAA,MAAA,EAAA,CAAA,kOAAA,CAAA,EAAA;;;MEIvD,aAAa,CAAA;wGAAb,aAAa,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAb,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,aAAa,0ECX1B,+SAYA,EAAA,MAAA,EAAA,CAAA,kOAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EDLY,eAAe,EAAE,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAAA,IAAA,CAAA,SAAA,EAAA,QAAA,EAAA,gFAAA,EAAA,QAAA,EAAA,CAAA,WAAA,EAAA,WAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,kBAAkB,2EAAE,kBAAkB,EAAA,QAAA,EAAA,YAAA,EAAA,CAAA,EAAA,CAAA;;4FAItD,aAAa,EAAA,UAAA,EAAA,CAAA;kBANzB,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,gBAAgB,WACjB,CAAC,eAAe,EAAE,kBAAkB,EAAE,kBAAkB,CAAC,EAAA,QAAA,EAAA,+SAAA,EAAA,MAAA,EAAA,CAAA,kOAAA,CAAA,EAAA;;;MEIvD,YAAY,CAAA;wGAAZ,YAAY,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAZ,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,YAAY,0ECXzB,wUAYA,EAAA,MAAA,EAAA,CAAA,8LAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EDLY,eAAe,EAAE,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAAA,IAAA,CAAA,SAAA,EAAA,QAAA,EAAA,gFAAA,EAAA,QAAA,EAAA,CAAA,WAAA,EAAA,WAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,kBAAkB,2EAAE,kBAAkB,EAAA,QAAA,EAAA,YAAA,EAAA,CAAA,EAAA,CAAA;;4FAItD,YAAY,EAAA,UAAA,EAAA,CAAA;kBANxB,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,gBAAgB,WACjB,CAAC,eAAe,EAAE,kBAAkB,EAAE,kBAAkB,CAAC,EAAA,QAAA,EAAA,wUAAA,EAAA,MAAA,EAAA,CAAA,8LAAA,CAAA,EAAA;;;AEHpE;;;;AAIG;AACH,SAAS,iBAAiB,CACxB,OAAiC,EACjC,MAAkB,EAClB,SAAwC,EACxC,OAAmD,EAAA;;AAGnD,IAAA,MAAM,cAAc,GAAG,QAAQ,CAAqB,OAAO,CAAC;AAE5D,IAAA,MAAM,KAAK,GAAG,MAAM,CAAuB,OAAO,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AAC5F,IAAA,MAAM,aAAa,GAAG,MAAM,CAA4B,SAAS,CAAC;AAClE,IAAA,MAAM,SAAS,GAAG,MAAM,CAAU,KAAK,CAAC;AACxC,IAAA,MAAM,UAAU,GAAG,MAAM,CAAqB,SAAS,CAAC;AACxD,IAAA,MAAM,OAAO,GAAG,MAAM,CAAqC,SAAS,CAAC;AAErE,IAAA,MAAM,MAAM,GAAG,MAAM,CAAoB,MAAM,CAAC;AAChD,IAAA,MAAM,KAAK,GAAG,MAAM,CAAoB,SAAS,CAAC;AAElD,IAAA,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;IACjC,IAAI,SAAS,GAA0B,SAAS;AAChD,IAAA,IAAI,OAAO,EAAE,WAAW,EAAE;AACxB,QAAA,SAAS,GAAG,MAAM,CAAC,CAAC,SAAS,KAAI;;AAE/B,YAAA,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE;YACxC,SAAS,CAAC,MAAM,UAAU,CAAC,KAAK,EAAE,CAAC;;AAGnC,YAAA,OAAO,CAAC,UAAU,CAAC,MAAM,EAAE,IAAI,CAAC;SACjC,EAAE,EAAE,QAAQ,EAAG,OAAO,EAAE,QAAQ,IAAI,QAAQ,EAAC,CAAC;;IAGjD,MAAM,OAAO,GAAG,OACd,WAAyB,EACzB,uBAAiC,KAC/B;;AAEF,QAAA,IAAI,SAAS,CAAC,MAAM,CAAC,KAAK,WAAW;YAAE;;AAGvC,QAAA,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;AACnB,QAAA,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC;AAC5B,QAAA,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC;AACzB,QAAA,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC;AACtB,QAAA,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC;AACrB,QAAA,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC;;AAGpB,QAAA,MAAM,GAAG,GAAG,cAAc,EAAE;AAC5B,QAAA,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG;AACnB,QAAA,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM;AACzB,QAAA,MAAM,cAAc,GAAG,GAAG,CAAC,OAAO;AAClC,QAAA,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI;;QAGrB,IAAI,GAAG,GAAG,GAAG;QACb,IAAI,MAAM,EAAE;AACV,YAAA,MAAM,YAAY,GAAG,IAAI,eAAe,EAAE;AAC1C,YAAA,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE;AACxB,gBAAA,IAAI,MAAM,CAAC,GAAG,CAAC,KAAK,SAAS;AAC3B,oBAAA,YAAY,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;;YAEjD,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,IAAI,YAAY,CAAC,QAAQ,EAAE;;;QAIlE,MAAM,eAAe,GAAG;cACtB,MAAM,CAAC,WAAW,CAClB,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,MAAM,CACnC,CAAC,GAAG,KAAK,CAAC,KAAK,KAAK,KAAK,SAAS,CACb;cAEvB,SAAS;AAEX,QAAA,IAAI;;AAEF,YAAA,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;gBAChC,MAAM;AACN,gBAAA,OAAO,EAAE,eAAe;;AAExB,gBAAA,IAAI,EAAE,IAAI;AACV,gBAAA,MAAM,EAAE,WAAW;AACpB,aAAA,CAAC;;AAGF,YAAA,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC;;YAG/B,MAAM,UAAU,GAA2B,EAAE;YAC7C,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,GAAG,KAAI;AACpC,gBAAA,UAAU,CAAC,GAAG,CAAC,GAAG,GAAG;AACvB,aAAC,CAAC;AACF,YAAA,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC;;AAGvB,YAAA,IAAI,QAAQ,CAAC,EAAE,EAAE;gBACf,KAAK,CAAC,GAAG,CAAC,MAAM,SAAS,CAAC,QAAQ,CAAC,CAAC;AACpC,gBAAA,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC;;iBACjB;;AAEL,gBAAA,IAAI;oBACF,aAAa,CAAC,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;AACxC,oBAAA,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC;AACpB,oBAAA,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC;;AACtB,gBAAA,MAAM;AACN,oBAAA,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC;;;;QAGtD,OAAO,GAAQ,EAAE;AACjB,YAAA,IAAI,GAAG,YAAY,KAAK,EAAE;;;;;gBAKxB,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY,IAAI,uBAAuB,EAAE;oBACxD;;AAEF,gBAAA,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC;;iBACT;;AAEL,gBAAA,KAAK,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;;AAEnC,YAAA,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC;AACpB,YAAA,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC;;AAErB,QAAA,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC;AACtB,KAAC;IAED,MAAM,OAAO,GAAG,MAAK;;QAEnB,IAAI,MAAM,EAAE,KAAK,WAAW;YAAE;QAE9B,IAAI,SAAS,EAAE;YACb,SAAS,CAAC,OAAO,EAAE;;AAErB,QAAA,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC;AACvB,QAAA,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC;AACpB,QAAA,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC;AAC5B,QAAA,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC;AACpB,QAAA,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC;AACzB,QAAA,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC;AACtB,QAAA,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC;AACtB,KAAC;IAED,OAAO;QACL,KAAK;QACL,aAAa;QACb,SAAS;QACT,UAAU;QACV,OAAO;QACP,MAAM;QACN,KAAK;QACL,OAAO;QACP;KACD;AACH;AAEA;AACA;AACA;AACA,MAAM,YAAY,GAAG,CAAkB,MAAkB,EAAE,SAAwC,KACjG,CAAC,OAAiC,EAAE,OAA2C,KAC7E,iBAAiB,CAAuB,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC;AAEhF;AACA,MAAM,eAAe,GAA6B,CAAC,QAAkB,KAAK,QAAQ,CAAC,IAAI,EAAE;AACzF,MAAM,eAAe,GAAgC,CAAC,QAAkB,KAAK,QAAQ,CAAC,IAAI,EAAE;AAC5F,MAAM,eAAe,GAA8B,CAAC,QAAkB,KAAK,QAAQ,CAAC,IAAI,EAAE;AAC1F,MAAM,sBAAsB,GAAqC,CAAC,QAAkB,KAAK,QAAQ,CAAC,WAAW,EAAE;AAE/G;AACA;AACA;AACM,MAAA,WAAW,GAAG,YAAY,CAAC,KAAK,EAAE,eAAe;AACvD,WAAW,CAAC,IAAI,GAAG,YAAY,CAAC,KAAK,EAAE,eAAe,CAAC;AACvD,WAAW,CAAC,IAAI,GAAG,YAAY,CAAC,KAAK,EAAE,eAAe,CAAC;AACvD,WAAW,CAAC,IAAI,GAAG,YAAY,CAAC,KAAK,EAAE,eAAe,CAAC;AACvD,WAAW,CAAC,WAAW,GAAG,YAAY,CAAC,KAAK,EAAE,sBAAsB,CAAC;AAErE;AACA;AACA;AACA,WAAW,CAAC,GAAG,GAAG,YAAY,CAC5B,KAAK,EACL,eAAe,CACa;AAC9B,WAAW,CAAC,GAAG,CAAC,IAAI,GAAG,YAAY,CAAC,KAAK,EAAE,eAAe,CAAC;AAC3D,WAAW,CAAC,GAAG,CAAC,IAAI,GAAG,YAAY,CAAC,KAAK,EAAE,eAAe,CAAC;AAC3D,WAAW,CAAC,GAAG,CAAC,IAAI,GAAG,YAAY,CAAC,KAAK,EAAE,eAAe,CAAC;AAC3D,WAAW,CAAC,GAAG,CAAC,WAAW,GAAG,YAAY,CAAC,KAAK,EAAE,sBAAsB,CAAC;AAEzE;AACA;AACA;AACA,WAAW,CAAC,IAAI,GAAG,YAAY,CAC7B,MAAM,EACN,eAAe,CACc;AAC/B,WAAW,CAAC,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC,MAAM,EAAE,eAAe,CAAC;AAC7D,WAAW,CAAC,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC,MAAM,EAAE,eAAe,CAAC;AAC7D,WAAW,CAAC,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC,MAAM,EAAE,eAAe,CAAC;AAC7D,WAAW,CAAC,IAAI,CAAC,WAAW,GAAG,YAAY,CAAC,MAAM,EAAE,sBAAsB,CAAC;AAE3E;AACA;AACA;AACA,WAAW,CAAC,GAAG,GAAG,YAAY,CAC5B,KAAK,EACL,eAAe,CACa;AAC9B,WAAW,CAAC,GAAG,CAAC,IAAI,GAAG,YAAY,CAAC,KAAK,EAAE,eAAe,CAAC;AAC3D,WAAW,CAAC,GAAG,CAAC,IAAI,GAAG,YAAY,CAAC,KAAK,EAAE,eAAe,CAAC;AAC3D,WAAW,CAAC,GAAG,CAAC,IAAI,GAAG,YAAY,CAAC,KAAK,EAAE,eAAe,CAAC;AAC3D,WAAW,CAAC,GAAG,CAAC,WAAW,GAAG,YAAY,CAAC,KAAK,EAAE,sBAAsB,CAAC;AAEzE;AACA;AACA;AACA,WAAW,CAAC,KAAK,GAAG,YAAY,CAC9B,OAAO,EACP,eAAe,CACe;AAChC,WAAW,CAAC,KAAK,CAAC,IAAI,GAAG,YAAY,CAAC,OAAO,EAAE,eAAe,CAAC;AAC/D,WAAW,CAAC,KAAK,CAAC,IAAI,GAAG,YAAY,CAAC,OAAO,EAAE,eAAe,CAAC;AAC/D,WAAW,CAAC,KAAK,CAAC,IAAI,GAAG,YAAY,CAAC,OAAO,EAAE,eAAe,CAAC;AAC/D,WAAW,CAAC,KAAK,CAAC,WAAW,GAAG,YAAY,CAAC,OAAO,EAAE,sBAAsB,CAAC;AAE7E;AACA;AACA;AACA,WAAW,CAAC,MAAM,GAAG,YAAY,CAC/B,QAAQ,EACR,eAAe,CACgB;AACjC,WAAW,CAAC,MAAM,CAAC,IAAI,GAAG,YAAY,CAAC,QAAQ,EAAE,eAAe,CAAC;AACjE,WAAW,CAAC,MAAM,CAAC,IAAI,GAAG,YAAY,CAAC,QAAQ,EAAE,eAAe,CAAC;AACjE,WAAW,CAAC,MAAM,CAAC,IAAI,GAAG,YAAY,CAAC,QAAQ,EAAE,eAAe,CAAC;AACjE,WAAW,CAAC,MAAM,CAAC,WAAW,GAAG,YAAY,CAAC,QAAQ,EAAE,sBAAsB,CAAC;;ACrP/E;;AAEG;;ACFH;;AAEG;;;;"}
|
|
1
|
+
{"version":3,"file":"fhss-web-team-frontend-utils.mjs","sources":["../../../projects/frontend-utils/src/lib/components/byu-footer/byu-footer.component.ts","../../../projects/frontend-utils/src/lib/components/byu-footer/byu-footer.component.html","../../../projects/frontend-utils/src/lib/services/auth/auth.service.ts","../../../projects/frontend-utils/src/lib/components/byu-header/byu-header.component.ts","../../../projects/frontend-utils/src/lib/components/byu-header/byu-header.component.html","../../../projects/frontend-utils/src/lib/signals/trpcResource/trpcResource.ts","../../../projects/frontend-utils/src/lib/signals/debounced/debounced.ts","../../../projects/frontend-utils/src/lib/components/fhss-table/fhss-table.types.ts","../../../projects/frontend-utils/src/lib/components/fhss-table/fhss-table.component.ts","../../../projects/frontend-utils/src/lib/components/fhss-table/fhss-table.component.html","../../../projects/frontend-utils/src/lib/config/lib.config.ts","../../../projects/frontend-utils/src/lib/config/utils.config.ts","../../../projects/frontend-utils/src/lib/guards/auth/auth.guard.ts","../../../projects/frontend-utils/src/lib/guards/permission/permission.guard.ts","../../../projects/frontend-utils/src/lib/pages/auth-error/auth-error.page.ts","../../../projects/frontend-utils/src/lib/pages/auth-error/auth-error.page.html","../../../projects/frontend-utils/src/lib/pages/forbidden/forbidden.page.ts","../../../projects/frontend-utils/src/lib/pages/forbidden/forbidden.page.html","../../../projects/frontend-utils/src/lib/pages/not-found/not-found.page.ts","../../../projects/frontend-utils/src/lib/pages/not-found/not-found.page.html","../../../projects/frontend-utils/src/lib/signals/fetch-signal/fetch-signal.ts","../../../projects/frontend-utils/src/public-api.ts","../../../projects/frontend-utils/src/fhss-web-team-frontend-utils.ts"],"sourcesContent":["import { Component } from '@angular/core';\n\n@Component({\n selector: 'byu-footer',\n imports: [],\n templateUrl: './byu-footer.component.html',\n styleUrl: './byu-footer.component.scss'\n})\nexport class ByuFooterComponent {\n currentYear: number = new Date().getFullYear(); // Automatically updates the year\n}\n","<footer>\n <p class=\"title\"><a href=\"https://www.byu.edu/\">BRIGHAM YOUNG UNIVERSITY</a></p>\n <p>Provo, UT 84602, USA | © {{ currentYear }} All rights reserved.</p>\n <p>\n <a href=\"https://privacy.byu.edu/privacy-notice\">Privacy Notice</a> |\n <a href=\"https://privacy.byu.edu/cookie-prefs\">Cookie Preferences</a>\n </p>\n</footer>\n \n\n","import { computed, inject, Injectable, signal } from '@angular/core';\nimport { Router } from '@angular/router';\n\ntype WhoAmI = {\n id: string;\n preferredFirstName: string;\n preferredLastName: string;\n roles: string[];\n permissions: string[];\n};\n\n@Injectable({\n providedIn: 'root',\n})\nexport class AuthService {\n readonly router = inject(Router);\n\n authenticated = signal(false);\n userId = signal<string | undefined>(undefined);\n preferredFirstName = signal<string | undefined>(undefined);\n preferredLastName = signal<string | undefined>(undefined);\n roles = signal<string[] | undefined>(undefined);\n permissions = signal<string[] | undefined>(undefined);\n\n preferredName = computed(() => {\n const prefLast = this.preferredLastName();\n return `${this.preferredFirstName() ?? ''}${prefLast ? ` ${prefLast}` : ''}`;\n });\n\n private resetAuthState() {\n this.authenticated.set(false);\n this.userId.set(undefined);\n this.preferredFirstName.set(undefined);\n this.preferredLastName.set(undefined);\n this.roles.set(undefined);\n this.permissions.set(undefined);\n }\n\n login(nextUri?: string) {\n this.router.navigate(['/login']);\n }\n\n logout(nextUri?: string) {\n this.resetAuthState();\n this.router.navigate(['/logout']);\n }\n\n async whoAmI(): Promise<WhoAmI | null> {\n try {\n const res = await fetch('/sys/who-am-i');\n const user = await res.json();\n this.userId.set(user.id);\n this.preferredFirstName.set(user.preferredFirstName);\n this.preferredLastName.set(user.preferredLastName);\n this.roles.set(user.roles);\n this.permissions.set(user.permissions);\n return user;\n } catch (error) {\n console.error(error);\n return null;\n }\n }\n}\n","import { Component, input, inject } from '@angular/core';\nimport { RouterModule } from '@angular/router';\nimport { AuthService } from '../../services/auth/auth.service';\n\ntype HeaderLink = {\n text: string;\n path: string;\n};\n\n// A HeaderMenu can be either a simple link with path,\n// OR a menu group with nested items\ntype HeaderMenu = HeaderLink | {\n text: string;\n items: HeaderLink[];\n}\n\nexport type HeaderConfig = {\n title: HeaderLink;\n subtitle?: HeaderLink;\n breadcrumbs?: HeaderLink[];\n menu?: HeaderMenu[];\n}\n\n@Component({\n selector: 'byu-header',\n imports: [RouterModule],\n templateUrl: './byu-header.component.html',\n styleUrl: './byu-header.component.scss'\n})\nexport class ByuHeaderComponent {\n auth = inject(AuthService)\n config = input<HeaderConfig>();\n\n isHeaderLink(item: HeaderMenu): item is HeaderLink {\n return 'path' in item;\n }\n\n // Track which dropdown is open (null means none are open)\n openDropdownText: string | null = null;\n \n // Toggle function — if clicking the same dropdown, close it; otherwise open it\n toggleDropdown(text: string) {\n this.openDropdownText = this.openDropdownText === text ? null : text;\n }\n \n // Check if a given dropdown is currently open\n isOpen(text: string): boolean {\n return this.openDropdownText === text;\n }\n}\n","<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.preferredName() }}</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","import { computed, effect, EffectRef, inject, Injector, signal } from \"@angular/core\";\nimport { isTRPCClientError, Resolver } from \"@trpc/client\";\nimport { ResolverDef, TrpcResource ,TrpcResourceOptions } from \"./trpcResource.types\";\n\nfunction trpcResource<TDef extends ResolverDef>(procedure: Resolver<TDef>, input: () => TDef['input'], options?: TrpcResourceOptions<TDef['output']>): TrpcResource<TDef> {\n const currentInput = computed(input);\n\n const value = signal<TDef['output'] | undefined>(options?.defaultValue, { equal: options?.equal });\n const error = signal<TDef['errorShape'] | undefined>(undefined);\n const isLoading = signal<boolean>(false);\n\n if (options?.autoRefresh) {\n const effectRef = effect((onCleanup) => {\n // pass abort signal to refresh on cleanup of effect\n const controller = new AbortController();\n onCleanup(() => controller.abort());\n\n // call refresh with this abort controller\n // refresh reads currentInput which triggers the effect\n refresh(controller.signal, true);\n }, { injector: options?.injector || inject(Injector)});\n }\n\n const refresh = async (\n abortSignal?: AbortSignal,\n keepLoadingThroughAbort: boolean = true,\n ) => {\n // Reset signals for a fresh request.\n isLoading.set(true);\n error.set(undefined);\n\n try {\n value.set(await procedure(currentInput(), {\n signal: abortSignal\n }));\n error.set(undefined)\n } catch (err) {\n if (isTRPCClientError(err)) {\n // if the trpc request was aborted\n // we check if we would like to continue loading (the next request)\n // if so then we just leave this refresh in an undefined state\n // else we error as usual\n if (err.cause?.name === 'AbortError' && keepLoadingThroughAbort) {\n return;\n }\n error.set(err);\n } else {\n // Fallback for non-Error values\n console.error(\"A non-tRPC error has occured on this trpcResource: \", String(err));\n }\n value.set(options?.defaultValue);\n }\n isLoading.set(false);\n }\n\n return {\n value,\n error,\n isLoading,\n refresh\n };\n}\n\nfunction debugTrpcResource<TDef extends ResolverDef>(_trpcResource: TrpcResource<TDef>) {\n return {\n value: _trpcResource.value(),\n error: _trpcResource.error(),\n isLoading: _trpcResource.isLoading(),\n }\n}\n\nexport { debugTrpcResource, trpcResource };","import { effect, signal, Signal } from \"@angular/core\";\n\nexport const debounced = <T>(inputSignal: Signal<T>, wait: number = 400) => {\n const debouncedSignal = signal<T>(inputSignal());\n const setSignal = debounce((value) => debouncedSignal.set(value), wait);\n\n effect(() => {\n setSignal(inputSignal())\n })\n\n return debouncedSignal;\n}\n\nconst debounce = (callback: (...args: any[]) => void, wait: number) => {\n let timeoutId: number | undefined;\n return (...args: any[]) => {\n window.clearTimeout(timeoutId);\n timeoutId = window.setTimeout(() => {\n callback(...args);\n }, wait);\n };\n}","import { Resolver } from '@trpc/client';\nimport { ResolverDef } from '../../signals/trpcResource/trpcResource.types';\nimport { trpcResource } from '../../signals/trpcResource/trpcResource';\n\nexport type FhssTableConfig<TDef extends ResolverDef> = {\n procedure: Resolver<TDef>;\n columns: {\n [K in keyof TDef['output']['data'][number]]: {\n hide?: boolean;\n header?: string;\n allowSort?: boolean;\n individualFilter?: boolean;\n };\n };\n showSearch?: boolean;\n sorting: {\n defaultSortBy: Extract<keyof TDef['output']['data'][number], string>;\n defaultSortDirection?: 'asc' | 'desc';\n };\n pagination: {\n pageSize: number;\n hideControls?: boolean;\n };\n interaction?:\n | {\n type: 'click';\n onClick: (obj: TDef['output']['data'][number]) => void;\n }\n | {\n type: 'select';\n multi?: boolean;\n };\n};\n\nexport const makeTableConfig = <TDef extends ResolverDef>(\n config: FhssTableConfig<TDef>,\n) => config;\n\nexport type AnyResolver = {\n input: any;\n output: { totalCount: number; data: any[] };\n transformer: any;\n errorShape: {\n code: any;\n message: string;\n data: any;\n };\n};\n\nexport type AnyResource = ReturnType<typeof trpcResource<AnyResolver>>;\n","import {\n Component,\n inject,\n Injector,\n input,\n linkedSignal,\n model,\n OnInit,\n signal,\n} from '@angular/core';\nimport { trpcResource } from '../../signals/trpcResource/trpcResource';\nimport { debounced } from '../../signals/debounced/debounced';\nimport { FhssTableConfig, AnyResolver, AnyResource } from './fhss-table.types';\nexport { makeTableConfig } from './fhss-table.types';\n\nimport { MatTableModule } from '@angular/material/table';\nimport { MatProgressSpinnerModule } from '@angular/material/progress-spinner';\nimport { MatPaginatorModule, PageEvent } from '@angular/material/paginator';\nimport { MatInputModule } from '@angular/material/input';\nimport { FormsModule } from '@angular/forms';\nimport { MatButtonModule } from '@angular/material/button';\nimport { MatSortModule, Sort } from '@angular/material/sort';\nimport { MatIconModule } from '@angular/material/icon';\nimport { MatRippleModule } from '@angular/material/core';\nimport { MatCheckboxModule } from '@angular/material/checkbox';\nimport { SelectionModel } from '@angular/cdk/collections';\n\n@Component({\n selector: 'fhss-table',\n imports: [\n MatTableModule,\n MatProgressSpinnerModule,\n MatPaginatorModule,\n MatInputModule,\n FormsModule,\n MatButtonModule,\n MatSortModule,\n MatIconModule,\n MatRippleModule,\n MatCheckboxModule,\n ],\n templateUrl: './fhss-table.component.html',\n styleUrl: './fhss-table.component.scss',\n})\nexport class FhssTableComponent implements OnInit {\n private injector = inject(Injector);\n\n config = input.required<FhssTableConfig<AnyResolver>>();\n miscParams = input<Record<string, any>>({});\n\n columnKeys: string[] = [];\n columnsToDisplay: string[] = [];\n selection: SelectionModel<any> | undefined;\n selectedValues = model<any[]>([]);\n\n dataResource!: AnyResource;\n\n ngOnInit() {\n const cfg = this.config();\n\n this.columnKeys = Object.keys(cfg.columns);\n this.columnsToDisplay = this.columnKeys.filter((k) => !cfg.columns[k].hide);\n\n if (cfg.interaction?.type === 'select') {\n this.columnsToDisplay.unshift('table-checkbox-column');\n this.selection = new SelectionModel<any>(\n cfg.interaction.multi,\n undefined,\n undefined,\n (o1, o2) => o1.id === o2.id,\n );\n }\n\n this.dataResource = trpcResource(\n this.config().procedure,\n () => ({\n search: this.debouncedSearch(),\n filters: this.debouncedFilters(),\n sort: {\n property: this.sortBy(),\n direction: this.sortDirection(),\n },\n page: {\n size: this.config().pagination.pageSize,\n index: this.pageIndex(),\n },\n ...this.miscParams(),\n }),\n {\n autoRefresh: true,\n injector: this.injector,\n },\n );\n }\n\n search = signal('');\n debouncedSearch = debounced(this.search);\n filters = signal<Record<string, string>>({});\n debouncedFilters = debounced(this.filters);\n\n sortBy = linkedSignal(() => this.config().sorting.defaultSortBy);\n sortDirection = linkedSignal<'asc' | 'desc'>(\n () => this.config().sorting.defaultSortDirection ?? 'asc',\n );\n\n pageIndex = linkedSignal(() => {\n this.search();\n return 0;\n });\n\n onFilterChange(col: string, val: string) {\n this.filters.update((f) => ({ ...f, [col]: val }));\n }\n onPaginationChange(e: PageEvent) {\n this.pageIndex.set(e.pageIndex);\n }\n onSortChange(sort: Sort) {\n this.sortBy.set(sort.active || this.config().sorting.defaultSortBy);\n this.sortDirection.set(\n sort.direction || this.config().sorting.defaultSortDirection || 'asc',\n );\n this.pageIndex.set(0);\n }\n onSelectionChange() {\n this.selectedValues.set(this.selection?.selected ?? []);\n }\n\n onRowClick(row: any) {\n const interaction = this.config().interaction;\n if (!interaction) return;\n\n if (interaction.type === 'click') {\n interaction.onClick(row);\n } else if (interaction.type === 'select') {\n this.selection?.toggle(row);\n }\n this.onSelectionChange();\n }\n\n isAllSelected() {\n if (!this.selection) return false;\n const numSelected = this.selection.selected.length;\n const numRows = this.dataResource.value()?.data?.length ?? 0;\n return numSelected === numRows;\n }\n\n toggleAllRows() {\n if (!this.selection) return;\n if (this.isAllSelected()) {\n this.selection.clear();\n } else {\n this.selection.select(...(this.dataResource.value()?.data ?? []));\n }\n this.onSelectionChange();\n }\n\n checkboxLabel(row?: any): string {\n if (!this.selection) return '';\n if (!row) {\n return `${this.isAllSelected() ? 'deselect' : 'select'} all`;\n }\n return `${this.selection.isSelected(row) ? 'deselect' : 'select'} row ${row.position + 1}`;\n }\n\n protected isBoolean = (val: unknown) => typeof val === 'boolean';\n}\n","<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\" subscriptSizing=\"dynamic\">\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 || key }}\n @if (config().columns[key].individualFilter) {\n <mat-form-field appearance=\"outline\" 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 @if (isBoolean(row[key])) {\n <mat-checkbox [checked]=\"row[key]\" [disabled]=\"true\" />\n } @else {\n {{ row[key] }}\n }\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","import { InjectionToken } from '@angular/core';\n\nexport const FHSS_CONFIG = new InjectionToken<FhssConfig>('FHSS_CONFIG');\n\nexport interface FhssConfig {\n roleHomePages: Record<string, string>;\n}\n","import { Provider } from \"@angular/core\";\nimport { FHSS_CONFIG, FhssConfig } from \"./lib.config\";\n\nexport const provideFhss = (config: FhssConfig): Provider => ({\n provide: FHSS_CONFIG,\n useValue: config,\n});\n","import { inject } from '@angular/core';\nimport { CanActivateFn } from '@angular/router';\nimport { AuthService } from '../../services/auth/auth.service';\n\n/**\n * This guard checks if the client is authenticated, redirecting to login if not.\n */\nexport const authGuard: CanActivateFn = (route, state) => {\n const authService = inject(AuthService);\n if(!authService.authenticated()){\n authService.login(state.url);\n return false;\n }\n return true;\n};\n","import { CanActivateFn, RedirectCommand, Router } from '@angular/router';\nimport { FHSS_CONFIG } from '../../config/lib.config';\nimport { AuthService } from '../../services/auth/auth.service';\nimport { inject } from '@angular/core';\n\n/**\n * Generates a guard function to determine if a user has the required roles to access a route.\n *\n * @example\n * ```typescript\n * const routes: Routes = [\n * {\n * path: 'admin',\n * component: AdminPage,\n * canActivate: [roleGuardFactory(Roles.admin)],\n * },\n * ];\n * ```\n */\nexport const permissionGuardFactory: (...requiredPermissions: string[]) => CanActivateFn = (...requiredPermissions) => {\n return (_route, state) => {\n const authService = inject(AuthService);\n const router = inject(Router);\n\n if (!authService.authenticated()) {\n authService.login(state.url);\n return false;\n }\n\n const userPermissions = authService.permissions();\n const hasAccess =\n userPermissions?.some((role) => requiredPermissions.includes(role)) ?? false;\n\n return hasAccess || new RedirectCommand(router.parseUrl('/forbidden'));\n };\n};\n","import { Component } from '@angular/core';\nimport { ByuFooterComponent } from '../../components/byu-footer/byu-footer.component';\nimport { ByuHeaderComponent } from '../../components/byu-header/byu-header.component';\nimport { MatButtonModule } from '@angular/material/button';\n\n@Component({\n selector: 'fhss-auth-error',\n imports: [MatButtonModule, ByuHeaderComponent, ByuFooterComponent],\n templateUrl: './auth-error.page.html',\n styleUrl: './auth-error.page.scss'\n})\nexport class AuthErrorPage {\n\n}\n","<byu-header />\n\n<div class=\"container\">\n <div class=\"not-found\">\n <img src=\"/sad-duck.jpg\" alt=\"sad duck\" />\n <h1>Login Failed</h1>\n <p>Something went wrong while trying to log you in.</p>\n <a mat-flat-button href=\"/\">Go back to home</a>\n </div>\n</div>\n\n<byu-footer />\n","import { Component } from '@angular/core';\nimport { MatButtonModule } from '@angular/material/button';\nimport { ByuFooterComponent } from '../../components/byu-footer/byu-footer.component';\nimport { ByuHeaderComponent } from '../../components/byu-header/byu-header.component';\n\n@Component({\n selector: 'fhss-forbidden',\n imports: [MatButtonModule, ByuHeaderComponent, ByuFooterComponent],\n templateUrl: './forbidden.page.html',\n styleUrl: './forbidden.page.scss',\n})\nexport class ForbiddenPage {}\n","<byu-header />\n\n<div class=\"container\">\n <div class=\"not-found\">\n <img src=\"/police-duck.jpg\" alt=\"\" />\n <h1>403 - Forbidden</h1>\n <p>You don't have permission to access this page.</p>\n <a mat-flat-button href=\"/\">Go back to home</a>\n </div>\n</div>\n\n<byu-footer />\n","import { Component } from '@angular/core';\nimport { MatButtonModule } from '@angular/material/button';\nimport { ByuFooterComponent } from '../../components/byu-footer/byu-footer.component';\nimport { ByuHeaderComponent } from '../../components/byu-header/byu-header.component';\n\n@Component({\n selector: 'fhss-not-found',\n imports: [MatButtonModule, ByuHeaderComponent, ByuFooterComponent],\n templateUrl: './not-found.page.html',\n styleUrl: './not-found.page.scss',\n})\nexport class NotFoundPage {}\n","<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","import { computed, effect, EffectRef, inject, Injector, signal, untracked } from '@angular/core';\nimport { FetchSignal, FetchSignalFactory, FetchSignalOptions, FetchSignalRequest, FetchSignalStatus, HttpMethod, Json, ResponseTransformer } from './fetch-signal.types';\n\n\n/**\n * Creates a reactive fetch signal.\n *\n * The request function can include Signals for properties. These are unwrapped in the refresh function.\n */\nfunction createFetchSignal<Response, ErrorResponse, RawResponse>(\n request: () => FetchSignalRequest,\n method: HttpMethod,\n transform: ResponseTransformer<Response>,\n options?: FetchSignalOptions<Response, RawResponse>,\n): FetchSignal<Response, ErrorResponse> {\n // Use a computed signal so that any changes to Signals in the request object trigger updates.\n const currentRequest = computed<FetchSignalRequest>(request);\n\n const value = signal<Response | undefined>(options?.defaultValue, { equal: options?.equal });\n const errorResponse = signal<ErrorResponse | undefined>(undefined);\n const isLoading = signal<boolean>(false);\n const statusCode = signal<number | undefined>(undefined);\n const headers = signal<Record<string, string> | undefined>(undefined);\n\n const status = signal<FetchSignalStatus>('idle');\n const error = signal<Error | undefined>(undefined);\n\n const injector = inject(Injector);\n let effectRef: EffectRef | undefined = undefined;\n if (options?.autoRefresh) {\n effectRef = effect((onCleanup) => {\n // pass abort signal to refresh on cleanup of effect\n const controller = new AbortController();\n onCleanup(() => controller.abort());\n\n // call refresh with this abort controller\n refresh(controller.signal, true);\n }, { injector: options?.injector || injector});\n }\n\n const refresh = async (\n abortSignal?: AbortSignal,\n keepLoadingThroughAbort?: boolean,\n ) => {\n // if the fetchSignal has been destroyed, do nothing\n if (untracked(status) === 'destroyed') return;\n\n // Reset signals for a fresh request.\n isLoading.set(true);\n errorResponse.set(undefined);\n statusCode.set(undefined);\n headers.set(undefined);\n status.set('loading');\n error.set(undefined);\n\n // Unwrap the current request.\n const req = currentRequest();\n const url = req.url;\n const params = req.params;\n const requestHeaders = req.headers;\n const body = req.body;\n\n // Build URL with query parameters.\n let uri = url;\n if (params) {\n const searchParams = new URLSearchParams();\n for (const key in params) {\n if (params[key] !== undefined)\n searchParams.append(key, String(params[key]));\n }\n uri += (uri.includes('?') ? '&' : '?') + searchParams.toString();\n }\n \n // Filter out undefined header values\n const filteredHeaders = requestHeaders\n ? Object.fromEntries(\n Object.entries(requestHeaders).filter(\n ([, value]) => value !== undefined\n ) as [string, string][]\n )\n : undefined;\n \n try {\n // send the request\n const response = await fetch(uri, {\n method,\n headers: filteredHeaders,\n // Only include a body if one is provided.\n body: body,\n signal: abortSignal,\n });\n\n // set the status code\n statusCode.set(response.status);\n\n // Extract response headers.\n const headersObj: Record<string, string> = {};\n response.headers.forEach((val, key) => {\n headersObj[key] = val;\n });\n headers.set(headersObj);\n\n // if the response is ok, transform the body\n if (response.ok) {\n value.set(await transform(response));\n status.set('resolved');\n } else {\n // try to parse the error as json\n try {\n errorResponse.set(await response.json());\n value.set(undefined);\n status.set('resolved');\n } catch {\n throw new Error('Unable to parse error response.')\n }\n }\n } catch (err: any) {\n if (err instanceof Error) {\n // if the fetch request was aborted\n // we check if we would like to continue loading (the next request)\n // if so then we just leave this refresh in an undefined state\n // else we error as usual\n if (err.name === 'AbortError' && keepLoadingThroughAbort) {\n return;\n }\n error.set(err);\n } else {\n // Fallback for non-Error values\n error.set(new Error(String(err)));\n }\n value.set(undefined);\n status.set('error');\n }\n isLoading.set(false);\n };\n\n const destroy = () => {\n // if the fetchSignal has been destroyed, do nothing\n if (status() === 'destroyed') return;\n\n if (effectRef) {\n effectRef.destroy();\n }\n status.set('destroyed');\n value.set(undefined);\n errorResponse.set(undefined);\n isLoading.set(false);\n statusCode.set(undefined);\n headers.set(undefined);\n error.set(undefined);\n }\n\n return {\n value,\n errorResponse,\n isLoading,\n statusCode,\n headers,\n status,\n error,\n refresh,\n destroy\n };\n}\n\n//\n// Helpers for attaching response transforms.\n//\nconst createHelper = <Response, Error>(method: HttpMethod, transform: ResponseTransformer<Response>) =>\n (request: () => FetchSignalRequest, options?: FetchSignalOptions<Response, any>): FetchSignal<Response, Error> =>\n createFetchSignal<Response, Error, any>(request, method, transform, options);\n\n// Transforms\nconst jsonTransformer: ResponseTransformer<any> = (response: Response) => response.json();\nconst textTransformer: ResponseTransformer<string> = (response: Response) => response.text();\nconst blobTransformer: ResponseTransformer<Blob> = (response: Response) => response.blob();\nconst arrayBufferTransformer: ResponseTransformer<ArrayBuffer> = (response: Response) => response.arrayBuffer();\n\n//\n// Build the defaults - GET chain\n//\nconst fetchSignal = createHelper('GET', jsonTransformer) as FetchSignalFactory;\nfetchSignal.json = createHelper('GET', jsonTransformer);\nfetchSignal.text = createHelper('GET', textTransformer);\nfetchSignal.blob = createHelper('GET', blobTransformer);\nfetchSignal.arrayBuffer = createHelper('GET', arrayBufferTransformer);\n\n//\n// Build the GET chain\n//\nfetchSignal.get = createHelper(\n 'GET',\n jsonTransformer,\n) as FetchSignalFactory['get'];\nfetchSignal.get.json = createHelper('GET', jsonTransformer);\nfetchSignal.get.text = createHelper('GET', textTransformer);\nfetchSignal.get.blob = createHelper('GET', blobTransformer);\nfetchSignal.get.arrayBuffer = createHelper('GET', arrayBufferTransformer);\n\n//\n// Build the POST chain.\n//\nfetchSignal.post = createHelper(\n 'POST',\n jsonTransformer,\n) as FetchSignalFactory['post'];\nfetchSignal.post.json = createHelper('POST', jsonTransformer);\nfetchSignal.post.text = createHelper('POST', textTransformer);\nfetchSignal.post.blob = createHelper('POST', blobTransformer);\nfetchSignal.post.arrayBuffer = createHelper('POST', arrayBufferTransformer);\n\n//\n// Build the PUT chain.\n//\nfetchSignal.put = createHelper(\n 'PUT',\n jsonTransformer,\n) as FetchSignalFactory['put'];\nfetchSignal.put.json = createHelper('PUT', jsonTransformer);\nfetchSignal.put.text = createHelper('PUT', textTransformer);\nfetchSignal.put.blob = createHelper('PUT', blobTransformer);\nfetchSignal.put.arrayBuffer = createHelper('PUT', arrayBufferTransformer);\n\n//\n// Build the PATCH chain.\n//\nfetchSignal.patch = createHelper(\n 'PATCH',\n jsonTransformer,\n) as FetchSignalFactory['patch'];\nfetchSignal.patch.json = createHelper('PATCH', jsonTransformer);\nfetchSignal.patch.text = createHelper('PATCH', textTransformer);\nfetchSignal.patch.blob = createHelper('PATCH', blobTransformer);\nfetchSignal.patch.arrayBuffer = createHelper('PATCH', arrayBufferTransformer);\n\n//\n// Build the DELETE chain\n//\nfetchSignal.delete = createHelper(\n 'DELETE',\n jsonTransformer,\n) as FetchSignalFactory['delete'];\nfetchSignal.delete.json = createHelper('DELETE', jsonTransformer);\nfetchSignal.delete.text = createHelper('DELETE', textTransformer);\nfetchSignal.delete.blob = createHelper('DELETE', blobTransformer);\nfetchSignal.delete.arrayBuffer = createHelper('DELETE', arrayBufferTransformer);\n\nexport { fetchSignal };\nexport type { Json };\n\n","/**\n * Components\n */\nexport * from './lib/components/byu-footer/byu-footer.component'\nexport * from './lib/components/byu-header/byu-header.component'\nexport * from './lib/components/fhss-table/fhss-table.component'\n\n/**\n * Config\n */\nexport * from './lib/config/lib.config'\nexport * from './lib/config/utils.config'\n\n/**\n * Guards\n */\nexport * from './lib/guards/auth/auth.guard'\nexport * from './lib/guards/permission/permission.guard'\n\n/**\n * Pages\n */\nexport * from './lib/pages/auth-error/auth-error.page'\nexport * from './lib/pages/forbidden/forbidden.page'\nexport * from './lib/pages/not-found/not-found.page'\n\n/**\n * Services\n */\nexport * from './lib/services/auth/auth.service'\n\n/**\n * Signals\n */\nexport * from './lib/signals/trpcResource/trpcResource'\nexport * from './lib/signals/fetch-signal/fetch-signal'\nexport * from './lib/signals/debounced/debounced'","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i6","i1"],"mappings":"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"}
|
|
@@ -1,96 +1,26 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Router } from '@angular/router';
|
|
2
2
|
import * as i0 from "@angular/core";
|
|
3
|
+
type WhoAmI = {
|
|
4
|
+
id: string;
|
|
5
|
+
preferredFirstName: string;
|
|
6
|
+
preferredLastName: string;
|
|
7
|
+
roles: string[];
|
|
8
|
+
permissions: string[];
|
|
9
|
+
};
|
|
3
10
|
export declare class AuthService {
|
|
4
|
-
|
|
5
|
-
private keycloakSignal;
|
|
6
|
-
private router;
|
|
7
|
-
private config;
|
|
8
|
-
private readonly nextUriKey;
|
|
9
|
-
private readonly injector;
|
|
10
|
-
/**
|
|
11
|
-
* Signal indicating whether the user is authenticated.
|
|
12
|
-
* Returns `true` if authenticated, `false` otherwise.
|
|
13
|
-
*/
|
|
11
|
+
readonly router: Router;
|
|
14
12
|
authenticated: import("@angular/core").WritableSignal<boolean>;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
* or null if there isn't one
|
|
26
|
-
*/
|
|
27
|
-
getRoleHomeRoute: () => string | null;
|
|
28
|
-
/**
|
|
29
|
-
* Handles user provisioning.
|
|
30
|
-
*
|
|
31
|
-
* @returns the uri to which the application should navigate
|
|
32
|
-
*/
|
|
33
|
-
handleAuthCallback: () => Promise<void>;
|
|
34
|
-
/**
|
|
35
|
-
* Logs the user out of the application.
|
|
36
|
-
*/
|
|
37
|
-
logout: (nextUri?: string) => Promise<void>;
|
|
38
|
-
/**
|
|
39
|
-
* Signal for the base64-encoded token used in the `Authorization` header.
|
|
40
|
-
*/
|
|
41
|
-
token: import("@angular/core").Signal<string | undefined>;
|
|
42
|
-
/**
|
|
43
|
-
* Signal for the Bearer token, prefixed with "Bearer ".
|
|
44
|
-
*/
|
|
45
|
-
bearerToken: import("@angular/core").Signal<string | undefined>;
|
|
46
|
-
/**
|
|
47
|
-
* Signal for the parsed token as a JavaScript object.
|
|
48
|
-
*/
|
|
49
|
-
tokenParsed: import("@angular/core").Signal<KeycloakTokenParsed | undefined>;
|
|
50
|
-
/**
|
|
51
|
-
* Signal for the user ID (Keycloak subject).
|
|
52
|
-
*/
|
|
53
|
-
userId: import("@angular/core").Signal<string | undefined>;
|
|
54
|
-
/**
|
|
55
|
-
* Signal for the base64-encoded ID token.
|
|
56
|
-
*/
|
|
57
|
-
idToken: import("@angular/core").Signal<string | undefined>;
|
|
58
|
-
/**
|
|
59
|
-
* Signal for the parsed ID token as a JavaScript object.
|
|
60
|
-
*/
|
|
61
|
-
idTokenParsed: import("@angular/core").Signal<KeycloakTokenParsed | undefined>;
|
|
62
|
-
/**
|
|
63
|
-
* Signal for the realm roles associated with the token.
|
|
64
|
-
*/
|
|
65
|
-
realmAccess: import("@angular/core").Signal<KeycloakRoles | undefined>;
|
|
66
|
-
/**
|
|
67
|
-
* Signal for the resource roles associated with the token.
|
|
68
|
-
*/
|
|
69
|
-
resourceAccess: import("@angular/core").Signal<KeycloakResourceAccess | undefined>;
|
|
70
|
-
/**
|
|
71
|
-
* Signal for the base64-encoded refresh token.
|
|
72
|
-
*/
|
|
73
|
-
refreshToken: import("@angular/core").Signal<string | undefined>;
|
|
74
|
-
/**
|
|
75
|
-
* Signal for the parsed refresh token as a JavaScript object.
|
|
76
|
-
*/
|
|
77
|
-
refreshTokenParsed: import("@angular/core").Signal<KeycloakTokenParsed | undefined>;
|
|
78
|
-
/**
|
|
79
|
-
* Signal for the estimated time difference between the browser and Keycloak server in seconds.
|
|
80
|
-
*/
|
|
81
|
-
timeSkew: import("@angular/core").Signal<number | undefined>;
|
|
82
|
-
/**
|
|
83
|
-
* Signal for the response mode passed during initialization.
|
|
84
|
-
*/
|
|
85
|
-
responseMode: import("@angular/core").Signal<KeycloakResponseMode | undefined>;
|
|
86
|
-
/**
|
|
87
|
-
* Signal for the flow type used during initialization.
|
|
88
|
-
*/
|
|
89
|
-
flow: import("@angular/core").Signal<KeycloakFlow | undefined>;
|
|
90
|
-
/**
|
|
91
|
-
* Signal for the response type sent to Keycloak during login requests.
|
|
92
|
-
*/
|
|
93
|
-
responseType: import("@angular/core").Signal<KeycloakResponseType | undefined>;
|
|
13
|
+
userId: import("@angular/core").WritableSignal<string | undefined>;
|
|
14
|
+
preferredFirstName: import("@angular/core").WritableSignal<string | undefined>;
|
|
15
|
+
preferredLastName: import("@angular/core").WritableSignal<string | undefined>;
|
|
16
|
+
roles: import("@angular/core").WritableSignal<string[] | undefined>;
|
|
17
|
+
permissions: import("@angular/core").WritableSignal<string[] | undefined>;
|
|
18
|
+
preferredName: import("@angular/core").Signal<string>;
|
|
19
|
+
private resetAuthState;
|
|
20
|
+
login(nextUri?: string): void;
|
|
21
|
+
logout(nextUri?: string): void;
|
|
22
|
+
whoAmI(): Promise<WhoAmI | null>;
|
|
94
23
|
static ɵfac: i0.ɵɵFactoryDeclaration<AuthService, never>;
|
|
95
24
|
static ɵprov: i0.ɵɵInjectableDeclaration<AuthService>;
|
|
96
25
|
}
|
|
26
|
+
export {};
|
package/package.json
CHANGED
package/public-api.d.ts
CHANGED
|
@@ -13,11 +13,10 @@ export * from './lib/config/utils.config';
|
|
|
13
13
|
* Guards
|
|
14
14
|
*/
|
|
15
15
|
export * from './lib/guards/auth/auth.guard';
|
|
16
|
-
export * from './lib/guards/
|
|
16
|
+
export * from './lib/guards/permission/permission.guard';
|
|
17
17
|
/**
|
|
18
18
|
* Pages
|
|
19
19
|
*/
|
|
20
|
-
export * from './lib/pages/auth-callback/auth-callback.page';
|
|
21
20
|
export * from './lib/pages/auth-error/auth-error.page';
|
|
22
21
|
export * from './lib/pages/forbidden/forbidden.page';
|
|
23
22
|
export * from './lib/pages/not-found/not-found.page';
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { AuthService } from '../../services/auth/auth.service';
|
|
2
|
-
import * as i0 from "@angular/core";
|
|
3
|
-
export declare class AuthCallbackPage {
|
|
4
|
-
auth: AuthService;
|
|
5
|
-
constructor();
|
|
6
|
-
static ɵfac: i0.ɵɵFactoryDeclaration<AuthCallbackPage, never>;
|
|
7
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<AuthCallbackPage, "app-auth-callback", never, {}, {}, never, never, true, never>;
|
|
8
|
-
}
|