ichec-angular-core 0.1.2 → 0.1.4

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.
@@ -2,49 +2,50 @@ import { map, catchError, tap, mergeMap, throwError, BehaviorSubject, mergeAll,
2
2
  import { HttpClient, HttpParams, HttpHeaders } from '@angular/common/http';
3
3
  import * as i0 from '@angular/core';
4
4
  import { InjectionToken, inject, Injectable, input, signal, Component, viewChild, computed, output } from '@angular/core';
5
+ import * as i1$3 from '@angular/forms';
6
+ import { FormControl, Validators, FormGroup, FormsModule, ReactiveFormsModule, FormBuilder } from '@angular/forms';
5
7
  import * as i1 from '@angular/router';
6
8
  import { RouterModule, RouterOutlet, Router, ActivatedRoute } from '@angular/router';
7
9
  import * as i2 from '@angular/material/toolbar';
8
10
  import { MatToolbarModule } from '@angular/material/toolbar';
9
- import * as i3 from '@angular/material/icon';
11
+ import * as i1$1 from '@angular/material/icon';
10
12
  import { MatIconModule } from '@angular/material/icon';
11
13
  import * as i2$1 from '@angular/material/button';
12
14
  import { MatButtonModule } from '@angular/material/button';
13
15
  import * as i5 from '@angular/material/menu';
14
16
  import { MatMenuModule } from '@angular/material/menu';
15
- import * as i1$1 from '@angular/material/sidenav';
17
+ import * as i1$2 from '@angular/material/sidenav';
16
18
  import { MatSidenavContent, MatSidenavModule } from '@angular/material/sidenav';
17
19
  import * as i2$2 from '@angular/material/list';
18
20
  import { MatListModule } from '@angular/material/list';
19
21
  import { NgIf, Location, NgTemplateOutlet, TitleCasePipe } from '@angular/common';
20
- import * as i1$2 from '@angular/forms';
21
- import { FormsModule, FormControl, ReactiveFormsModule, FormBuilder } from '@angular/forms';
22
- import * as i3$2 from '@angular/material/input';
22
+ import * as i3 from '@angular/material/input';
23
23
  import { MatInputModule } from '@angular/material/input';
24
- import * as i3$1 from '@angular/material/form-field';
24
+ import * as i2$3 from '@angular/material/form-field';
25
25
  import { MatFormFieldModule } from '@angular/material/form-field';
26
- import * as i1$3 from '@angular/material/card';
26
+ import * as i1$4 from '@angular/material/card';
27
27
  import { MatCardModule } from '@angular/material/card';
28
- import * as i1$4 from '@angular/material/table';
29
- import { MatTable, MatTableModule } from '@angular/material/table';
28
+ import * as i4 from '@angular/material/checkbox';
29
+ import { MatCheckboxModule } from '@angular/material/checkbox';
30
+ import * as i1$5 from '@angular/material/table';
31
+ import { MatTableModule, MatTable } from '@angular/material/table';
30
32
  import * as i6 from '@angular/material/select';
31
33
  import { MatSelectModule } from '@angular/material/select';
34
+ import * as i4$1 from '@angular/material/tooltip';
35
+ import { MatTooltipModule } from '@angular/material/tooltip';
32
36
  import * as i6$1 from '@angular/material/autocomplete';
33
37
  import { MatAutocompleteModule } from '@angular/material/autocomplete';
34
- import * as i3$3 from '@angular/material/sort';
38
+ import * as i3$1 from '@angular/material/sort';
35
39
  import { MatSort, MatSortModule } from '@angular/material/sort';
36
- import * as i1$5 from '@angular/material/button-toggle';
40
+ import * as i1$6 from '@angular/material/button-toggle';
37
41
  import { MatButtonToggleModule } from '@angular/material/button-toggle';
38
- import * as i2$5 from '@angular/material/progress-spinner';
42
+ import * as i2$6 from '@angular/material/progress-spinner';
39
43
  import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
40
- import * as i4 from '@angular/material/tooltip';
41
- import { MatTooltipModule } from '@angular/material/tooltip';
42
- import * as i2$3 from '@angular/material/paginator';
44
+ import * as i2$4 from '@angular/material/paginator';
43
45
  import { MatPaginator, MatPaginatorModule } from '@angular/material/paginator';
44
- import * as i2$4 from '@angular/cdk/scrolling';
46
+ import * as i2$5 from '@angular/cdk/scrolling';
45
47
  import { ScrollingModule } from '@angular/cdk/scrolling';
46
48
  import { DataSource } from '@angular/cdk/collections';
47
- import { MatCheckboxModule } from '@angular/material/checkbox';
48
49
 
49
50
  class Paginated {
50
51
  count = 0;
@@ -53,31 +54,13 @@ class Paginated {
53
54
  results = [];
54
55
  }
55
56
  class Permission {
56
- id = 0;
57
- url = "";
58
- codename = "";
59
57
  static typename = "permission";
60
58
  static plural = "permissions";
61
- constructor(params = {}) {
62
- Object.assign(this, params);
63
- }
64
59
  }
60
+
65
61
  class PortalMember {
66
62
  static typename = "member";
67
63
  static plural = "members";
68
- id = 0;
69
- url = "";
70
- username = "";
71
- email = "";
72
- first_name = "";
73
- last_name = "";
74
- phone = "";
75
- organization = "";
76
- profile_url = "";
77
- all_permissions = [];
78
- constructor(params = {}) {
79
- Object.assign(this, params);
80
- }
81
64
  static getInitials(member) {
82
65
  let first_initial = "";
83
66
  let second_initial = "";
@@ -94,49 +77,20 @@ class PortalMember {
94
77
  return combined.toUpperCase();
95
78
  }
96
79
  }
80
+
97
81
  class Group {
98
82
  static typename = "group";
99
83
  static plural = "groups";
100
- name = "";
101
- url = "";
102
- id = 0;
103
- constructor(params = {}) {
104
- Object.assign(this, params);
105
- }
106
84
  }
107
85
 
108
- class Address {
109
- static typename = "address";
110
- static plural = "addresses";
111
- id = 0;
112
- url = "";
113
- line1 = "";
114
- line2 = null;
115
- line3 = null;
116
- city = null;
117
- region = "";
118
- postcode = null;
119
- country = "";
120
- country_name = "";
121
- country_flag = "";
122
- constructor(params = {}) {
123
- Object.assign(this, params);
124
- }
125
- }
126
86
  class Organization {
127
87
  static typename = "organization";
128
88
  static plural = "organizations";
129
- id = 0;
130
- url = "";
131
- name = "";
132
- acronym = "";
133
- description = "";
134
- address = "";
135
- website = "";
136
- members = [];
137
- constructor(params = {}) {
138
- Object.assign(this, params);
139
- }
89
+ }
90
+
91
+ class Address {
92
+ static typename = "address";
93
+ static plural = "addresses";
140
94
  }
141
95
 
142
96
  class ItemQuery {
@@ -160,6 +114,15 @@ class ApiError {
160
114
  text = "";
161
115
  }
162
116
 
117
+ const FORM_FIELD_CHOICES = [{ value: "BOOLEAN", display_name: "Boolean" },
118
+ { value: "CHAR", display_name: "Short Text" },
119
+ { value: "TEXT", display_name: "Long Text" },
120
+ { value: "RICH_TEXT", display_name: "Rich Text" },
121
+ { value: "SELECTION", display_name: "Selection" },
122
+ { value: "INTEGER", display_name: "Integer" },
123
+ { value: "FILE", display_name: "File" }
124
+ ];
125
+
163
126
  const ENDPOINT_URL = new InjectionToken("Default endpoint url");
164
127
  class RestService {
165
128
  _url = "";
@@ -292,12 +255,6 @@ class ItemService extends RestService {
292
255
  typePlural() {
293
256
  return this.typenamePlural ? this.typenamePlural : this.typename + "s";
294
257
  }
295
- instantiateType(_) {
296
- throw new Error('Not Implemented');
297
- }
298
- getItem(id) {
299
- return super.getItem(id).pipe(map(x => this.instantiateType(x)));
300
- }
301
258
  }
302
259
 
303
260
  class ResolvedPermission {
@@ -314,9 +271,6 @@ class UserService extends ItemService {
314
271
  _url = PortalMember.plural;
315
272
  typename = PortalMember.typename;
316
273
  permissions = new Map();
317
- instantiateType(item) {
318
- return new PortalMember(item);
319
- }
320
274
  login(username, password) {
321
275
  console.log("Attempting login");
322
276
  const body = new URLSearchParams();
@@ -382,8 +336,8 @@ class UserService extends ItemService {
382
336
  if (!user) {
383
337
  return;
384
338
  }
385
- user.all_permissions.forEach(p => this.permissions.set(this.parsePermission(p).feature, new ResolvedPermission()));
386
- user.all_permissions.forEach(p => {
339
+ user.permissions.forEach(p => this.permissions.set(this.parsePermission(p).feature, new ResolvedPermission()));
340
+ user.permissions.forEach(p => {
387
341
  const permission = this.parsePermission(p);
388
342
  if (permission.capability === "view") {
389
343
  this.permissions.get(permission.feature).canView = true;
@@ -455,9 +409,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.1", ngImpor
455
409
  class AddressService extends ItemWithUserService {
456
410
  _url = Address.plural;
457
411
  typename = Address.typename;
458
- instantiateType(item) {
459
- return new Address(item);
460
- }
461
412
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: AddressService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
462
413
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: AddressService, providedIn: 'root' });
463
414
  }
@@ -475,9 +426,6 @@ class GroupService extends ItemWithUserService {
475
426
  super();
476
427
  this.userService.loggedInUser.subscribe(user => this.refreshUserItems(user));
477
428
  }
478
- instantiateType(item) {
479
- return new Group(item);
480
- }
481
429
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: GroupService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
482
430
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: GroupService, providedIn: 'root' });
483
431
  }
@@ -491,9 +439,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.1", ngImpor
491
439
  class OrganizationService extends ItemWithUserService {
492
440
  _url = Organization.plural;
493
441
  typename = Organization.typename;
494
- instantiateType(item) {
495
- return new Organization(item);
496
- }
497
442
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: OrganizationService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
498
443
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: OrganizationService, providedIn: 'root' });
499
444
  }
@@ -504,6 +449,27 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.1", ngImpor
504
449
  }]
505
450
  }] });
506
451
 
452
+ /* eslint-disable @typescript-eslint/no-explicit-any */
453
+ class FormService {
454
+ toFormGroup(form) {
455
+ const controls = {};
456
+ form.groups.forEach(group => group.fields.forEach(field => {
457
+ controls[field.id.toString()] = field.required
458
+ ? new FormControl(field.default || '', Validators.required)
459
+ : new FormControl(field.default || '');
460
+ }));
461
+ return new FormGroup(controls);
462
+ }
463
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: FormService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
464
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: FormService, providedIn: 'root' });
465
+ }
466
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: FormService, decorators: [{
467
+ type: Injectable,
468
+ args: [{
469
+ providedIn: 'root',
470
+ }]
471
+ }] });
472
+
507
473
  class LeftNavService {
508
474
  activeOptions = new Set();
509
475
  _groups = [];
@@ -577,7 +543,7 @@ class TopBarComponent {
577
543
  return "";
578
544
  }
579
545
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: TopBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
580
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.1", type: TopBarComponent, isStandalone: true, selector: "lib-top-bar", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "\n@if(user(); as user){\n<mat-toolbar style=\"height:60px\">\n <a mat-icon-button aria-label=\"Home\" [routerLink]=\"['home']\">\n <mat-icon>home</mat-icon>\n </a>\n <span>{{title()}}</span>\n <span class=\"topbar-spacer\"></span>\n <span>{{user.username}}</span>\n \n <button mat-icon-button style=\"margin: 5px\" aria-label=\"User Profile\" [matMenuTriggerFor]=\"profile_menu\">\n <mat-icon>person</mat-icon>\n </button>\n\n <mat-menu #profile_menu=\"matMenu\">\n <a mat-menu-item aria-label=\"My Profile\" [routerLink]=\"['/members/detail', user.id]\">\n <mat-icon>manage_accounts</mat-icon>\n <span>My Profile</span>\n </a> \n <a mat-menu-item aria-label=\"Get Support\" [routerLink]=\"['/feedback']\">\n <mat-icon>contact_support</mat-icon>\n <span>Get Support</span>\n </a> \n <button mat-menu-item (click)=\"onLogout()\">\n <mat-icon>logout</mat-icon>\n <span>Log Out</span>\n </button>\n\n </mat-menu>\n</mat-toolbar>\n}\n", styles: [".topbar-spacer{flex:1 1 auto}\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"] }, { kind: "ngmodule", type: MatToolbarModule }, { kind: "component", type: i2.MatToolbar, selector: "mat-toolbar", inputs: ["color"], exportAs: ["matToolbar"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2$1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i5.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i5.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i5.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }] });
546
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.1", type: TopBarComponent, isStandalone: true, selector: "lib-top-bar", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "\n@if(user(); as user){\n<mat-toolbar style=\"height:60px\">\n <a mat-icon-button aria-label=\"Home\" [routerLink]=\"['home']\">\n <mat-icon>home</mat-icon>\n </a>\n <span>{{title()}}</span>\n <span class=\"topbar-spacer\"></span>\n <span>{{user.username}}</span>\n \n <button mat-icon-button style=\"margin: 5px\" aria-label=\"User Profile\" [matMenuTriggerFor]=\"profile_menu\">\n <mat-icon>person</mat-icon>\n </button>\n\n <mat-menu #profile_menu=\"matMenu\">\n <a mat-menu-item aria-label=\"My Profile\" [routerLink]=\"['/members/detail', user.id]\">\n <mat-icon>manage_accounts</mat-icon>\n <span>My Profile</span>\n </a> \n <a mat-menu-item aria-label=\"Get Support\" [routerLink]=\"['/feedback']\">\n <mat-icon>contact_support</mat-icon>\n <span>Get Support</span>\n </a> \n <button mat-menu-item (click)=\"onLogout()\">\n <mat-icon>logout</mat-icon>\n <span>Log Out</span>\n </button>\n\n </mat-menu>\n</mat-toolbar>\n}\n", styles: [".topbar-spacer{flex:1 1 auto}\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"] }, { kind: "ngmodule", type: MatToolbarModule }, { kind: "component", type: i2.MatToolbar, selector: "mat-toolbar", inputs: ["color"], exportAs: ["matToolbar"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2$1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i5.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i5.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i5.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }] });
581
547
  }
582
548
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: TopBarComponent, decorators: [{
583
549
  type: Component,
@@ -595,7 +561,7 @@ class LeftNavComponent {
595
561
  return this._leftNavService.activeOptions;
596
562
  }
597
563
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: LeftNavComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
598
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.1", type: LeftNavComponent, isStandalone: true, selector: "lib-left-nav", viewQueries: [{ propertyName: "sideNavContent", first: true, predicate: MatSidenavContent, descendants: true, isSignal: true }], ngImport: i0, template: "<mat-sidenav-container class=\"leftnav-container\">\n <mat-sidenav mode=\"side\" class=\"leftnav-side\" opened>\n <mat-nav-list>\n @for (option of getOptions(); track option) {\n <a mat-list-item [routerLink]=\"option.route\" [routerLinkActive]=\"['is-active']\">{{ option.name }}</a>\n }\n </mat-nav-list>\n </mat-sidenav>\n <mat-sidenav-content class=\"leftnav-content\"> \n <router-outlet />\n </mat-sidenav-content>\n</mat-sidenav-container>\n", styles: [":host{display:flex;flex-direction:column}.leftnav-container{flex-grow:1;display:flex}.leftnav-content{display:flex;flex-grow:1;height:90vh}.leftnav-side{padding:5px;width:160px}.is-active{background-color:#d3d3d3}\n"], dependencies: [{ kind: "ngmodule", type: MatSidenavModule }, { kind: "component", type: i1$1.MatSidenav, selector: "mat-sidenav", inputs: ["fixedInViewport", "fixedTopGap", "fixedBottomGap"], exportAs: ["matSidenav"] }, { kind: "component", type: i1$1.MatSidenavContainer, selector: "mat-sidenav-container", exportAs: ["matSidenavContainer"] }, { kind: "component", type: i1$1.MatSidenavContent, selector: "mat-sidenav-content" }, { kind: "ngmodule", type: MatListModule }, { kind: "component", type: i2$2.MatNavList, selector: "mat-nav-list", exportAs: ["matNavList"] }, { kind: "component", type: i2$2.MatListItem, selector: "mat-list-item, a[mat-list-item], button[mat-list-item]", inputs: ["activated"], exportAs: ["matListItem"] }, { kind: "directive", type: RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i1.RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }] });
564
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.1", type: LeftNavComponent, isStandalone: true, selector: "lib-left-nav", viewQueries: [{ propertyName: "sideNavContent", first: true, predicate: MatSidenavContent, descendants: true, isSignal: true }], ngImport: i0, template: "<mat-sidenav-container class=\"leftnav-container\">\n <mat-sidenav mode=\"side\" class=\"leftnav-side\" opened>\n <mat-nav-list>\n @for (option of getOptions(); track option) {\n <a mat-list-item [routerLink]=\"option.route\" [routerLinkActive]=\"['is-active']\">{{ option.name }}</a>\n }\n </mat-nav-list>\n </mat-sidenav>\n <mat-sidenav-content class=\"leftnav-content\"> \n <router-outlet />\n </mat-sidenav-content>\n</mat-sidenav-container>\n", styles: [":host{display:flex;flex-direction:column}.leftnav-container{flex-grow:1;display:flex}.leftnav-content{display:flex;flex-grow:1;height:90vh}.leftnav-side{padding:5px;width:160px}.is-active{background-color:#d3d3d3}\n"], dependencies: [{ kind: "ngmodule", type: MatSidenavModule }, { kind: "component", type: i1$2.MatSidenav, selector: "mat-sidenav", inputs: ["fixedInViewport", "fixedTopGap", "fixedBottomGap"], exportAs: ["matSidenav"] }, { kind: "component", type: i1$2.MatSidenavContainer, selector: "mat-sidenav-container", exportAs: ["matSidenavContainer"] }, { kind: "component", type: i1$2.MatSidenavContent, selector: "mat-sidenav-content" }, { kind: "ngmodule", type: MatListModule }, { kind: "component", type: i2$2.MatNavList, selector: "mat-nav-list", exportAs: ["matNavList"] }, { kind: "component", type: i2$2.MatListItem, selector: "mat-list-item, a[mat-list-item], button[mat-list-item]", inputs: ["activated"], exportAs: ["matListItem"] }, { kind: "directive", type: RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i1.RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }] });
599
565
  }
600
566
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: LeftNavComponent, decorators: [{
601
567
  type: Component,
@@ -638,7 +604,7 @@ class LandingComponent {
638
604
  this.router.navigateByUrl("/home");
639
605
  }
640
606
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: LandingComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
641
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.1", type: LandingComponent, isStandalone: true, selector: "lib-landing", inputs: { message: { classPropertyName: "message", publicName: "message", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "\n @if(message(); as message){\n <p>{{message}}</p>\n }\n \n <mat-card style=\"text-align:center;\">\n <form class=\"base-form\" #loginForm=\"ngForm\" (ngSubmit)=\"login()\">\n <mat-card-content>\n <mat-form-field class=\"form-field\">\n <input matInput\n placeholder=\"Username\"\n type=\"text\"\n [(ngModel)]=\"loginUser.name\"\n name=\"username\"\n required>\n </mat-form-field>\n <mat-form-field class=\"form-field\">\n <input matInput\n placeholder=\"Password\"\n type=\"password\"\n [(ngModel)]=\"loginUser.password\"\n name=\"password\"\n required>\n </mat-form-field>\n </mat-card-content>\n <div *ngIf=\"loginError\" class=\"error\">\n <mat-icon>error</mat-icon><p>{{loginError()}}</p>\n </div>\n <button mat-flat-button\n type=\"submit\"\n [disabled]=\"!loginForm.form.valid\">Log In</button>\n </form>\n </mat-card>\n\n\n \n", styles: [":host{display:flex;align-items:center;flex-grow:1;background-color:#a5b3c9;flex-direction:column}.base-form{padding:10px}.form-field{display:flex}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i1$2.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i1$3.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: i1$3.MatCardContent, selector: "mat-card-content" }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i3$1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3$2.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2$1.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
607
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.1", type: LandingComponent, isStandalone: true, selector: "lib-landing", inputs: { message: { classPropertyName: "message", publicName: "message", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "\n @if(message(); as message){\n <p>{{message}}</p>\n }\n \n <mat-card style=\"text-align:center;\">\n <form class=\"base-form\" #loginForm=\"ngForm\" (ngSubmit)=\"login()\">\n <mat-card-content>\n <mat-form-field class=\"form-field\">\n <input matInput\n placeholder=\"Username\"\n type=\"text\"\n [(ngModel)]=\"loginUser.name\"\n name=\"username\"\n required>\n </mat-form-field>\n <mat-form-field class=\"form-field\">\n <input matInput\n placeholder=\"Password\"\n type=\"password\"\n [(ngModel)]=\"loginUser.password\"\n name=\"password\"\n required>\n </mat-form-field>\n </mat-card-content>\n <div *ngIf=\"loginError\" class=\"error\">\n <mat-icon>error</mat-icon><p>{{loginError()}}</p>\n </div>\n <button mat-flat-button\n type=\"submit\"\n [disabled]=\"!loginForm.form.valid\">Log In</button>\n </form>\n </mat-card>\n\n\n \n", styles: [":host{display:flex;align-items:center;flex-grow:1;background-color:#a5b3c9;flex-direction:column}.base-form{padding:10px}.form-field{display:flex}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$3.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i1$3.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i1$4.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: i1$4.MatCardContent, selector: "mat-card-content" }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i2$3.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2$1.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
642
608
  }
643
609
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: LandingComponent, decorators: [{
644
610
  type: Component,
@@ -676,7 +642,10 @@ class DetailView {
676
642
  this.getItem();
677
643
  }
678
644
  title() {
679
- return this.itemService.typename.replace("_", " ");
645
+ if (this.itemService.typename) {
646
+ return this.itemService.typename.replace("_", " ");
647
+ }
648
+ return "";
680
649
  }
681
650
  onItemAvailable(item) {
682
651
  this.item.set(item);
@@ -712,35 +681,39 @@ class EditView {
712
681
  _route = inject(ActivatedRoute);
713
682
  _location = inject(Location);
714
683
  _userService = inject(UserService);
684
+ form;
715
685
  itemService;
716
- constructor(itemService) {
686
+ constructor(itemService, form) {
717
687
  this.itemService = itemService;
688
+ this.form = form;
718
689
  }
719
690
  onInit() {
720
691
  this.getItem();
721
692
  }
722
- onItemAvailable() {
693
+ onItemAvailable(item) {
723
694
  this._userService.loggedInUser.subscribe(user => { if (user) {
724
- this.onItemAndUserAvailable(user);
695
+ this.onItemAndUserAvailable(item, user);
725
696
  } });
726
697
  }
727
- onItemAndUserAvailable(_) {
698
+ onItemAndUserAvailable(_item, _user) {
728
699
  }
729
700
  goBack() {
730
701
  this._location.back();
731
702
  }
732
703
  submit() {
733
- console.log("submit called");
734
- if (this.item()) {
735
- this.save();
736
- }
704
+ this.save();
737
705
  }
738
706
  save() {
739
707
  if (this.createMode()) {
740
- this.createItem();
708
+ this.postItem();
741
709
  }
742
710
  else {
743
- this.updateItem();
711
+ const item = this.item();
712
+ {
713
+ if (item) {
714
+ this.putItem(item);
715
+ }
716
+ }
744
717
  }
745
718
  }
746
719
  cancel() {
@@ -760,16 +733,16 @@ class EditView {
760
733
  onFileRead(_content) {
761
734
  }
762
735
  createItem() {
763
- const item = this.item();
764
- if (item) {
765
- this.itemService.postItem(item).subscribe(item => this.saveFiles(item));
766
- }
736
+ return this.form.createItem();
767
737
  }
768
- updateItem() {
769
- const item = this.item();
770
- if (item) {
771
- this.itemService.putItem(item).subscribe(item => this.saveFiles(item));
772
- }
738
+ updateItem(item) {
739
+ return this.form.updateItem(item);
740
+ }
741
+ postItem() {
742
+ this.itemService.postItem(this.createItem()).subscribe(item => this.saveFiles(item));
743
+ }
744
+ putItem(item) {
745
+ this.itemService.putItem(this.updateItem(item)).subscribe(item => this.saveFiles(item));
773
746
  }
774
747
  saveFiles(item) {
775
748
  this.onItemUpdated(item);
@@ -788,16 +761,14 @@ class EditView {
788
761
  }
789
762
  getItem() {
790
763
  if (this.isCreateRoute()) {
791
- this.item.set(this.getTemplateItem());
792
764
  this.createMode.set(true);
793
- this.onItemAvailable();
794
765
  }
795
766
  else {
796
767
  const id_str = this._route.snapshot.paramMap.get('id');
797
768
  this.itemService.getItem(Number(id_str))
798
769
  .subscribe(item => {
799
770
  this.item.set(item);
800
- this.onItemAvailable();
771
+ this.onItemAvailable(item);
801
772
  });
802
773
  }
803
774
  }
@@ -817,6 +788,509 @@ class EditView {
817
788
  }
818
789
  }
819
790
 
791
+ class FormFieldDetailComponent {
792
+ field = input.required(...(ngDevMode ? [{ debugName: "field" }] : []));
793
+ form = input.required(...(ngDevMode ? [{ debugName: "form" }] : []));
794
+ get isValid() {
795
+ return this.form().controls[this.key].valid;
796
+ }
797
+ get key() {
798
+ return this.field().id.toString();
799
+ }
800
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: FormFieldDetailComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
801
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.1", type: FormFieldDetailComponent, isStandalone: true, selector: "lib-form-field-detail", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<div [formGroup]=\"form()\">\n <label [attr.for]=\"key\">{{ field().label }}</label>\n <div>\n @switch (field().field_type) {\n @case ('TEXT') {\n <mat-form-field class=\"form-field-wide\">\n <mat-label [attr.for]=\"key\">{{ field().label }}</mat-label>\n <textarea matInput\n [placeholder]=\"field().default\"\n type=\"text\"\n style=\"min-height:150px\"\n [formControlName]=\"key\"\n [name]=\"key\"></textarea>\n </mat-form-field>\n }\n @case('BOOLEAN')\n {\n <mat-checkbox\n class=\"form-field\"\n [name]=\"key\"\n [formControlName]=\"key\">\n {{ field().label }}\n </mat-checkbox>\n }\n @case ('INTEGER') {\n <mat-form-field class=\"form-field\">\n <mat-label>{{ field().label }}</mat-label>\n <input matInput\n [placeholder]=\"field().default\"\n type=\"number\"\n max=\"10\" min=\"1\"\n [formControlName]=\"key\"\n name=\"trl_stage\">\n </mat-form-field>\n }\n }\n </div>\n @if (!isValid) {\n <div class=\"errorMessage\">{{ field().label }} is required</div>\n }\n</div>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$3.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$3.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i1$3.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { kind: "directive", type: i1$3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$3.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i2$3.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2$3.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i4.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }] });
802
+ }
803
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: FormFieldDetailComponent, decorators: [{
804
+ type: Component,
805
+ args: [{ selector: 'lib-form-field-detail', imports: [ReactiveFormsModule,
806
+ MatFormFieldModule,
807
+ MatInputModule,
808
+ MatCheckboxModule], template: "<div [formGroup]=\"form()\">\n <label [attr.for]=\"key\">{{ field().label }}</label>\n <div>\n @switch (field().field_type) {\n @case ('TEXT') {\n <mat-form-field class=\"form-field-wide\">\n <mat-label [attr.for]=\"key\">{{ field().label }}</mat-label>\n <textarea matInput\n [placeholder]=\"field().default\"\n type=\"text\"\n style=\"min-height:150px\"\n [formControlName]=\"key\"\n [name]=\"key\"></textarea>\n </mat-form-field>\n }\n @case('BOOLEAN')\n {\n <mat-checkbox\n class=\"form-field\"\n [name]=\"key\"\n [formControlName]=\"key\">\n {{ field().label }}\n </mat-checkbox>\n }\n @case ('INTEGER') {\n <mat-form-field class=\"form-field\">\n <mat-label>{{ field().label }}</mat-label>\n <input matInput\n [placeholder]=\"field().default\"\n type=\"number\"\n max=\"10\" min=\"1\"\n [formControlName]=\"key\"\n name=\"trl_stage\">\n </mat-form-field>\n }\n }\n </div>\n @if (!isValid) {\n <div class=\"errorMessage\">{{ field().label }} is required</div>\n }\n</div>\n" }]
809
+ }] });
810
+
811
+ const FORM_FIELD_TABLE_FULL = [
812
+ { name: 'label', title: 'Label', element_type: 'string' },
813
+ { name: 'field_type', title: 'Type', element_type: 'string' }
814
+ ];
815
+ const FORM_GROUP_TABLE_FULL = [
816
+ { name: 'label', title: 'Label', element_type: 'string' }
817
+ ];
818
+
819
+ class FormFieldListComponent {
820
+ form = input.required(...(ngDevMode ? [{ debugName: "form" }] : []));
821
+ edit = output();
822
+ columns = FORM_FIELD_TABLE_FULL;
823
+ columnNames = computed(() => { const names = this.columns.map(c => c.name); names.push("edit"); return names; }, ...(ngDevMode ? [{ debugName: "columnNames" }] : []));
824
+ onEdit(id) {
825
+ this.edit.emit(id);
826
+ }
827
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: FormFieldListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
828
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.1", type: FormFieldListComponent, isStandalone: true, selector: "lib-form-field-list", inputs: { form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { edit: "edit" }, ngImport: i0, template: "<table mat-table [dataSource]=\"form().controls\" class=\"mat-elevation-z8\">\n @for (column of columns; track column.name) {\n <ng-container matColumnDef=\"{{ column.name }}\">\n <th mat-header-cell mat-sort-header *matHeaderCellDef>\n {{ column.title }}\n </th>\n <td mat-cell *matCellDef=\"let element\">{{ element.value[column.name] }}</td>\n </ng-container>\n }\n\n <ng-container matColumnDef=\"edit\">\n <th mat-header-cell *matHeaderCellDef>Edit\n </th>\n <td mat-cell *matCellDef=\"let idx = index\">\n <button mat-icon-button\n type=\"button\"\n color=\"primary\"\n aria-label=\"Edit an item\"\n (click)=\"onEdit(idx)\">\n <mat-icon>edit\n </mat-icon>\n </button>\n </td>\n </ng-container>\n\n <tr mat-header-row *matHeaderRowDef=\"columnNames()\">\n </tr>\n <tr mat-row *matRowDef=\"let row; columns: columnNames();\">\n </tr>\n</table>\n\n\n", styles: [""], dependencies: [{ kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i1$5.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i1$5.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i1$5.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i1$5.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i1$5.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i1$5.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i1$5.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i1$5.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i1$5.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i1$5.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2$1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }] });
829
+ }
830
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: FormFieldListComponent, decorators: [{
831
+ type: Component,
832
+ args: [{ selector: 'lib-form-field-list', imports: [MatTableModule, MatButtonModule, MatIconModule], template: "<table mat-table [dataSource]=\"form().controls\" class=\"mat-elevation-z8\">\n @for (column of columns; track column.name) {\n <ng-container matColumnDef=\"{{ column.name }}\">\n <th mat-header-cell mat-sort-header *matHeaderCellDef>\n {{ column.title }}\n </th>\n <td mat-cell *matCellDef=\"let element\">{{ element.value[column.name] }}</td>\n </ng-container>\n }\n\n <ng-container matColumnDef=\"edit\">\n <th mat-header-cell *matHeaderCellDef>Edit\n </th>\n <td mat-cell *matCellDef=\"let idx = index\">\n <button mat-icon-button\n type=\"button\"\n color=\"primary\"\n aria-label=\"Edit an item\"\n (click)=\"onEdit(idx)\">\n <mat-icon>edit\n </mat-icon>\n </button>\n </td>\n </ng-container>\n\n <tr mat-header-row *matHeaderRowDef=\"columnNames()\">\n </tr>\n <tr mat-row *matRowDef=\"let row; columns: columnNames();\">\n </tr>\n</table>\n\n\n" }]
833
+ }] });
834
+
835
+ class FileUploadComponent {
836
+ files = input([], ...(ngDevMode ? [{ debugName: "files" }] : []));
837
+ previewLoaded = output();
838
+ fileUploaded = output();
839
+ clearLocal = output();
840
+ onPreviewRead(name, content) {
841
+ this.previewLoaded.emit({ name: name, content: content });
842
+ }
843
+ onFileUpload(name, event) {
844
+ if (!event.target) {
845
+ return;
846
+ }
847
+ const input_element = event.target;
848
+ if (input_element.files && input_element.files.length > 0) {
849
+ const file = input_element.files[0];
850
+ this.fileUploaded.emit({ name: name, file: file });
851
+ const record = this.files().find(f => f.name == name);
852
+ if (record && record.file_type == "image") {
853
+ this.readFile(name, file);
854
+ }
855
+ }
856
+ }
857
+ readFile(name, file) {
858
+ const reader = new FileReader();
859
+ reader.readAsDataURL(file);
860
+ reader.onload = () => {
861
+ if (reader.result) {
862
+ this.previewLoaded.emit({ name: name, content: reader.result });
863
+ }
864
+ ;
865
+ };
866
+ }
867
+ onClearLocal() {
868
+ this.clearLocal.emit();
869
+ }
870
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: FileUploadComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
871
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.1", type: FileUploadComponent, isStandalone: true, selector: "lib-file-upload", inputs: { files: { classPropertyName: "files", publicName: "files", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { previewLoaded: "previewLoaded", fileUploaded: "fileUploaded", clearLocal: "clearLocal" }, ngImport: i0, template: "<div class=\"container\">\n @for( file of files(); track file.name)\n {\n @if (file.local)\n {\n <div class=\"image_holder\">\n <p>Update {{file.display_name}}</p>\n <img alt=\"{{file.display_name}}\" src=\"{{file.local}}\" style=\"height:120px;\">\n <button mat-mini-fab (click)=\"onClearLocal()\" type=\"button\">\n <mat-icon>clear</mat-icon>\n </button>\n </div> \n }\n @else\n {\n @if (file.remote){\n <div class=\"image_holder\">\n <p>Update {{file.display_name}}</p>\n <img alt=\"{{file.display_name}}\" src=\"{{file.remote}}\" style=\"height:120px;\">\n </div>\n }\n @else {\n <div>\n <span>Upload a {{file.display_name}}</span>\n </div> \n }\n \n }\n\n <div class=\"button-row\">\n <button mat-mini-fab (click)=\"fileInput.click()\" type=\"button\">\n <mat-icon>attachment</mat-icon>\n </button>\n <input hidden type=\"file\" #fileInput (change)=\"onFileUpload(file.name, $event)\"/>\n </div> \n } \n</div>\n", styles: [".container{padding:10px;display:flex;justify-content:center;text-align:center;flex-direction:column;max-width:300px}\n"], dependencies: [{ kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2$1.MatMiniFabButton, selector: "button[mat-mini-fab], a[mat-mini-fab], button[matMiniFab], a[matMiniFab]", exportAs: ["matButton", "matAnchor"] }] });
872
+ }
873
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: FileUploadComponent, decorators: [{
874
+ type: Component,
875
+ args: [{ selector: 'lib-file-upload', imports: [MatIconModule, MatButtonModule], template: "<div class=\"container\">\n @for( file of files(); track file.name)\n {\n @if (file.local)\n {\n <div class=\"image_holder\">\n <p>Update {{file.display_name}}</p>\n <img alt=\"{{file.display_name}}\" src=\"{{file.local}}\" style=\"height:120px;\">\n <button mat-mini-fab (click)=\"onClearLocal()\" type=\"button\">\n <mat-icon>clear</mat-icon>\n </button>\n </div> \n }\n @else\n {\n @if (file.remote){\n <div class=\"image_holder\">\n <p>Update {{file.display_name}}</p>\n <img alt=\"{{file.display_name}}\" src=\"{{file.remote}}\" style=\"height:120px;\">\n </div>\n }\n @else {\n <div>\n <span>Upload a {{file.display_name}}</span>\n </div> \n }\n \n }\n\n <div class=\"button-row\">\n <button mat-mini-fab (click)=\"fileInput.click()\" type=\"button\">\n <mat-icon>attachment</mat-icon>\n </button>\n <input hidden type=\"file\" #fileInput (change)=\"onFileUpload(file.name, $event)\"/>\n </div> \n } \n</div>\n", styles: [".container{padding:10px;display:flex;justify-content:center;text-align:center;flex-direction:column;max-width:300px}\n"] }]
876
+ }] });
877
+
878
+ class FormFieldEditComponent {
879
+ availableTypes = FORM_FIELD_CHOICES;
880
+ form = input.required(...(ngDevMode ? [{ debugName: "form" }] : []));
881
+ editMode = input(false, ...(ngDevMode ? [{ debugName: "editMode" }] : []));
882
+ submitted = output();
883
+ cancelled = output();
884
+ get isBoolean() {
885
+ return this.fieldType === "BOOLEAN";
886
+ }
887
+ get isShortText() {
888
+ return this.fieldType === "CHAR";
889
+ }
890
+ get isLongText() {
891
+ return this.fieldType === "TEXT";
892
+ }
893
+ get isRichText() {
894
+ return this.fieldType === "RICH_TEXT";
895
+ }
896
+ get isSelection() {
897
+ return this.fieldType === "SELECTION";
898
+ }
899
+ get isInteger() {
900
+ return this.fieldType === "INTEGER";
901
+ }
902
+ get isFile() {
903
+ return this.fieldType === "FILE";
904
+ }
905
+ get fieldType() {
906
+ return this.form().value.field_type;
907
+ }
908
+ submit() {
909
+ this.submitted.emit();
910
+ }
911
+ cancel() {
912
+ this.cancelled.emit();
913
+ }
914
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: FormFieldEditComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
915
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.1", type: FormFieldEditComponent, isStandalone: true, selector: "lib-form-field-edit", inputs: { form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: true, transformFunction: null }, editMode: { classPropertyName: "editMode", publicName: "editMode", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { submitted: "submitted", cancelled: "cancelled" }, ngImport: i0, template: "<form class=\"form-card\" id=\"app-field-form\" [formGroup]=\"form()\" (ngSubmit)=\"submit()\">\n <mat-form-field class=\"form-field\">\n <mat-label>Label</mat-label>\n <input matInput \n placeholder=\"Label\" \n type=\"text\" \n formControlName=\"label\" \n required \n name=\"label\">\n </mat-form-field>\n\n<mat-form-field class=\"form-field-wide\">\n<mat-label>Description</mat-label>\n<textarea matInput placeholder=\"Description\" style=\"min-height:150px\" type=\"text\" formControlName=\"description\"\n required name=\"description\"></textarea>\n</mat-form-field>\n\n <mat-checkbox class=\"example-margin\" formControlName=\"required\">Required?</mat-checkbox>\n\n<mat-form-field class=\"form-field\">\n <mat-label>Type</mat-label>\n <mat-select formControlName=\"field_type\" name=\"field_type\" required>\n @for(type of availableTypes; track type.value){\n <mat-option [value]=\"type.value\">{{type.display_name}}\n </mat-option>\n }\n </mat-select>\n</mat-form-field>\n \n @if(isBoolean)\n {\n <mat-form-field class=\"form-field\">\n <mat-label>Default</mat-label>\n <mat-select formControlName=\"default\" name=\"default\" required>\n <mat-option [value]=\"'true'\">True</mat-option>\n <mat-option [value]=\"'false'\">False</mat-option>\n </mat-select>\n </mat-form-field>\n }\n @else if(isShortText)\n {\n <mat-form-field class=\"form-field\">\n <mat-label>Default</mat-label>\n <input matInput \n placeholder=\"Default\" \n type=\"text\" \n formControlName=\"default\" \n name=\"default\">\n </mat-form-field>\n }\n @else if(isLongText || isRichText)\n {\n <mat-form-field class=\"form-field-wide\">\n <mat-label>Default</mat-label>\n <textarea matInput placeholder=\"Default\" style=\"min-height:150px\" type=\"text\" \n formControlName=\"default\"\n name=\"default\"></textarea>\n </mat-form-field>\n }\n @else if(isFile)\n {\n <lib-file-upload></lib-file-upload>\n }\n\n <div>\n\n @if(editMode())\n {\n <button mat-fab class=\"form_action_button\" \n type=\"submit\" form=\"app-field-form\" matTooltip=\"Save Field\"\n [disabled]=\"!form().valid\">\n <mat-icon>save</mat-icon>\n </button>\n\n <button mat-fab class=\"form_action_button\" \n matTooltip=\"Cancel Editing Field\" (click)=\"cancel()\">\n <mat-icon>cancel</mat-icon>\n </button> \n }\n @else {\n <button mat-fab class=\"form_action_button\" \n type=\"submit\" form=\"app-field-form\" matTooltip=\"Add Field\"\n [disabled]=\"!form().valid\">\n <mat-icon>add</mat-icon>\n </button>\n <button mat-fab class=\"form_action_button\" \n matTooltip=\"Cancel Adding Field\" (click)=\"cancel()\">\n <mat-icon>cancel</mat-icon>\n </button> \n }\n </div> \n</form>", styles: [""], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$3.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$3.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: RouterModule }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2$1.MatFabButton, selector: "button[mat-fab], a[mat-fab], button[matFab], a[matFab]", inputs: ["extended"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatCardModule }, { kind: "ngmodule", type: MatTableModule }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "component", type: i2$3.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2$3.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i6.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i6.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i4$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i4.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "component", type: FileUploadComponent, selector: "lib-file-upload", inputs: ["files"], outputs: ["previewLoaded", "fileUploaded", "clearLocal"] }] });
916
+ }
917
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: FormFieldEditComponent, decorators: [{
918
+ type: Component,
919
+ args: [{ selector: 'lib-form-field-edit', imports: [ReactiveFormsModule,
920
+ RouterModule,
921
+ MatButtonModule,
922
+ MatCardModule,
923
+ MatTableModule,
924
+ MatInputModule,
925
+ MatFormFieldModule,
926
+ MatIconModule,
927
+ MatSelectModule,
928
+ MatTooltipModule,
929
+ MatCheckboxModule,
930
+ FileUploadComponent], template: "<form class=\"form-card\" id=\"app-field-form\" [formGroup]=\"form()\" (ngSubmit)=\"submit()\">\n <mat-form-field class=\"form-field\">\n <mat-label>Label</mat-label>\n <input matInput \n placeholder=\"Label\" \n type=\"text\" \n formControlName=\"label\" \n required \n name=\"label\">\n </mat-form-field>\n\n<mat-form-field class=\"form-field-wide\">\n<mat-label>Description</mat-label>\n<textarea matInput placeholder=\"Description\" style=\"min-height:150px\" type=\"text\" formControlName=\"description\"\n required name=\"description\"></textarea>\n</mat-form-field>\n\n <mat-checkbox class=\"example-margin\" formControlName=\"required\">Required?</mat-checkbox>\n\n<mat-form-field class=\"form-field\">\n <mat-label>Type</mat-label>\n <mat-select formControlName=\"field_type\" name=\"field_type\" required>\n @for(type of availableTypes; track type.value){\n <mat-option [value]=\"type.value\">{{type.display_name}}\n </mat-option>\n }\n </mat-select>\n</mat-form-field>\n \n @if(isBoolean)\n {\n <mat-form-field class=\"form-field\">\n <mat-label>Default</mat-label>\n <mat-select formControlName=\"default\" name=\"default\" required>\n <mat-option [value]=\"'true'\">True</mat-option>\n <mat-option [value]=\"'false'\">False</mat-option>\n </mat-select>\n </mat-form-field>\n }\n @else if(isShortText)\n {\n <mat-form-field class=\"form-field\">\n <mat-label>Default</mat-label>\n <input matInput \n placeholder=\"Default\" \n type=\"text\" \n formControlName=\"default\" \n name=\"default\">\n </mat-form-field>\n }\n @else if(isLongText || isRichText)\n {\n <mat-form-field class=\"form-field-wide\">\n <mat-label>Default</mat-label>\n <textarea matInput placeholder=\"Default\" style=\"min-height:150px\" type=\"text\" \n formControlName=\"default\"\n name=\"default\"></textarea>\n </mat-form-field>\n }\n @else if(isFile)\n {\n <lib-file-upload></lib-file-upload>\n }\n\n <div>\n\n @if(editMode())\n {\n <button mat-fab class=\"form_action_button\" \n type=\"submit\" form=\"app-field-form\" matTooltip=\"Save Field\"\n [disabled]=\"!form().valid\">\n <mat-icon>save</mat-icon>\n </button>\n\n <button mat-fab class=\"form_action_button\" \n matTooltip=\"Cancel Editing Field\" (click)=\"cancel()\">\n <mat-icon>cancel</mat-icon>\n </button> \n }\n @else {\n <button mat-fab class=\"form_action_button\" \n type=\"submit\" form=\"app-field-form\" matTooltip=\"Add Field\"\n [disabled]=\"!form().valid\">\n <mat-icon>add</mat-icon>\n </button>\n <button mat-fab class=\"form_action_button\" \n matTooltip=\"Cancel Adding Field\" (click)=\"cancel()\">\n <mat-icon>cancel</mat-icon>\n </button> \n }\n </div> \n</form>" }]
931
+ }] });
932
+
933
+ class DynamicFormComponent {
934
+ formService = inject(FormService);
935
+ inputForm = input.required(...(ngDevMode ? [{ debugName: "inputForm" }] : []));
936
+ form = computed(() => this.formService.toFormGroup(this.inputForm()), ...(ngDevMode ? [{ debugName: "form" }] : []));
937
+ payLoad = '';
938
+ onSubmit() {
939
+ this.payLoad = JSON.stringify(this.form().getRawValue());
940
+ }
941
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: DynamicFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
942
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.1", type: DynamicFormComponent, isStandalone: true, selector: "lib-dynamic-form", inputs: { inputForm: { classPropertyName: "inputForm", publicName: "inputForm", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<div>\n <form (ngSubmit)=\"onSubmit()\" [formGroup]=\"form()\">\n\n @for (group of inputForm().groups; track group.id) {\n @for (field of group.fields; track field.id) {\n <div class=\"form-row\">\n <lib-form-field-detail [field]=\"field\" [form]=\"form()\" />\n </div>\n }\n }\n </form>\n @if (payLoad) {\n <div class=\"form-row\"><strong>Saved the following values</strong><br />{{ payLoad }}</div>\n }\n</div>", styles: [""], dependencies: [{ kind: "component", type: FormFieldDetailComponent, selector: "lib-form-field-detail", inputs: ["field", "form"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }] });
943
+ }
944
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: DynamicFormComponent, decorators: [{
945
+ type: Component,
946
+ args: [{ selector: 'lib-dynamic-form', imports: [FormFieldDetailComponent, ReactiveFormsModule, FormFieldDetailComponent], template: "<div>\n <form (ngSubmit)=\"onSubmit()\" [formGroup]=\"form()\">\n\n @for (group of inputForm().groups; track group.id) {\n @for (field of group.fields; track field.id) {\n <div class=\"form-row\">\n <lib-form-field-detail [field]=\"field\" [form]=\"form()\" />\n </div>\n }\n }\n </form>\n @if (payLoad) {\n <div class=\"form-row\"><strong>Saved the following values</strong><br />{{ payLoad }}</div>\n }\n</div>" }]
947
+ }] });
948
+
949
+ class FormFieldForm {
950
+ static createForm(fb) {
951
+ return fb.group({
952
+ label: fb.control('', Validators.required),
953
+ required: fb.control(false, Validators.required),
954
+ description: fb.control('', Validators.required),
955
+ template: fb.control(null),
956
+ options: fb.control(null),
957
+ default: fb.control(''),
958
+ field_type: fb.control("BOOLEAN", Validators.required),
959
+ order: fb.control(0),
960
+ id: fb.control(-1),
961
+ });
962
+ }
963
+ static fromItem(item, builder) {
964
+ const form = this.createForm(builder);
965
+ this.setValue(form, item);
966
+ return form;
967
+ }
968
+ static setValue(form, item) {
969
+ let id = -1;
970
+ if ('id' in item) {
971
+ id = item.id;
972
+ }
973
+ form.setValue({
974
+ label: item.label,
975
+ required: item.required,
976
+ description: item.description,
977
+ template: item.template,
978
+ options: "",
979
+ default: item.default,
980
+ field_type: item.field_type,
981
+ order: item.order,
982
+ id: id
983
+ });
984
+ }
985
+ static createItem(form) {
986
+ const value = form.value;
987
+ return {
988
+ label: value.label || "",
989
+ required: value.required || false,
990
+ description: value.description || "",
991
+ template: value.template || null,
992
+ options: null,
993
+ default: value.default || "",
994
+ field_type: value.field_type || "BOOLEAN",
995
+ order: value.order || 0
996
+ };
997
+ }
998
+ static updateItem(form, item) {
999
+ const value = form.value;
1000
+ item.label = value.label || "";
1001
+ item.required = value.required || false;
1002
+ item.description = value.description || "";
1003
+ item.template = value.template || null;
1004
+ item.options = null;
1005
+ item.default = value.default || "";
1006
+ item.field_type = value.field_type || "BOOLEAN";
1007
+ item.order = value.order || 0;
1008
+ return item;
1009
+ }
1010
+ }
1011
+
1012
+ class FormGroupForm {
1013
+ static createForm(fb) {
1014
+ return fb.group({
1015
+ label: fb.control(''),
1016
+ description: fb.control(''),
1017
+ order: fb.control(0),
1018
+ fields: fb.array([]),
1019
+ id: fb.control(-1)
1020
+ });
1021
+ }
1022
+ static createField(form, field) {
1023
+ const fields = this.getFields(form);
1024
+ field.patchValue({ order: fields.controls.length });
1025
+ fields.push(field);
1026
+ }
1027
+ static deleteField(form, id) {
1028
+ this.getFields(form).removeAt(id);
1029
+ }
1030
+ static fromItem(item, fb) {
1031
+ const form = this.createForm(fb);
1032
+ this.setValue(form, item, fb);
1033
+ return form;
1034
+ }
1035
+ static getLabel(form, id) {
1036
+ if (form.value) {
1037
+ if (form.value.label) {
1038
+ return form.value.label;
1039
+ }
1040
+ else if (form.value.order) {
1041
+ return "Group " + form.value.order.toString();
1042
+ }
1043
+ }
1044
+ return "Group " + id.toString();
1045
+ }
1046
+ static setValue(form, item, fb) {
1047
+ let id = -1;
1048
+ if ('id' in item) {
1049
+ id = item.id;
1050
+ }
1051
+ form.patchValue({
1052
+ label: item.label,
1053
+ description: item.description,
1054
+ order: item.order,
1055
+ id: id
1056
+ });
1057
+ const fields = this.getFields(form);
1058
+ fields.clear();
1059
+ item.fields.map(f => fields.push(FormFieldForm.fromItem(f, fb)));
1060
+ }
1061
+ static getFields(form) {
1062
+ return form.get('fields');
1063
+ }
1064
+ static createItem(form) {
1065
+ const value = form.value;
1066
+ return {
1067
+ label: value.label || "",
1068
+ description: value.description || "",
1069
+ order: value.order || 0,
1070
+ fields: Array.from(this.getFields(form).controls.map(f => FormFieldForm.createItem(f)))
1071
+ };
1072
+ }
1073
+ static createOrUpdateField(form, items) {
1074
+ if (form.value.id && form.value.id >= 0) {
1075
+ const matching_item = items.find(item => "id" in item && item.id == form.value.id);
1076
+ return FormFieldForm.updateItem(form, matching_item);
1077
+ }
1078
+ return FormFieldForm.createItem(form);
1079
+ }
1080
+ static updateItem(form, item) {
1081
+ const value = form.value;
1082
+ item.label = value.label || "";
1083
+ item.description = value.description || "";
1084
+ item.order = value.order || 0;
1085
+ item.fields = Array.from(this.getFields(form).controls.map(f => this.createOrUpdateField(f, item.fields)));
1086
+ return item;
1087
+ }
1088
+ }
1089
+
1090
+ class FormGroupEditComponent {
1091
+ create = input(false, ...(ngDevMode ? [{ debugName: "create" }] : []));
1092
+ form = input.required(...(ngDevMode ? [{ debugName: "form" }] : []));
1093
+ cancelled = output();
1094
+ submitted = output();
1095
+ editingField = signal(-1, ...(ngDevMode ? [{ debugName: "editingField" }] : []));
1096
+ creatingField = signal(false, ...(ngDevMode ? [{ debugName: "creatingField" }] : []));
1097
+ fieldForm = null;
1098
+ builder = inject(FormBuilder);
1099
+ get fields() {
1100
+ return this.form().get('fields');
1101
+ }
1102
+ submit() {
1103
+ this.submitted.emit();
1104
+ }
1105
+ cancel() {
1106
+ this.cancelled.emit();
1107
+ }
1108
+ addField() {
1109
+ this.creatingField.set(true);
1110
+ this.fieldForm = FormFieldForm.createForm(this.builder);
1111
+ }
1112
+ editField(id) {
1113
+ this.editingField.set(id);
1114
+ this.fieldForm = this.fields.controls[this.editingField()];
1115
+ }
1116
+ cancelField() {
1117
+ this.resetField();
1118
+ }
1119
+ resetField() {
1120
+ this.creatingField.set(false);
1121
+ this.fieldForm = null;
1122
+ this.editingField.set(-1);
1123
+ }
1124
+ submitField() {
1125
+ if (this.creatingField() && this.fieldForm && this.form) {
1126
+ FormGroupForm.createField(this.form(), this.fieldForm);
1127
+ }
1128
+ this.resetField();
1129
+ }
1130
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: FormGroupEditComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1131
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.1", type: FormGroupEditComponent, isStandalone: true, selector: "lib-form-group-edit", inputs: { create: { classPropertyName: "create", publicName: "create", isSignal: true, isRequired: false, transformFunction: null }, form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { cancelled: "cancelled", submitted: "submitted" }, ngImport: i0, template: "<div [formGroup]=\"form()\">\n\n @if(fieldForm && fields)\n {\n @if(creatingField())\n {\n <h3>Creating Field</h3>\n }\n @else {\n <h3>Editing Field</h3>\n }\n <lib-form-field-edit [form]=\"fieldForm\" (submitted)=\"submitField()\"\n (cancelled)=\"cancelField()\"></lib-form-field-edit>\n }\n @else{\n\n @if(create())\n {\n <h3>Creating Group</h3>\n }\n @else {\n <h3>Editing Group</h3>\n }\n\n <mat-form-field class=\"form-field-wide\">\n <mat-label for=\"description\">Description</mat-label>\n <textarea matInput placeholder=\"\" type=\"text\" style=\"min-height:150px\" formControlName=\"description\"\n name=\"description\"></textarea>\n </mat-form-field>\n\n <h3>Fields</h3>\n <div>\n <button mat-fab class=\"form_action_button\" (click)=\"addField()\" matTooltip=\"Add a Field\" type=\"button\">\n <mat-icon>add</mat-icon>\n </button>\n\n @if(fields && fields.length > 0){\n <lib-form-field-list [form]=\"fields\" (edit)=\"editField($event)\">\n </lib-form-field-list>\n }\n </div>\n\n <button mat-fab class=\"form-action-button\" (click)=\"submit()\" matTooltip=\"Save Group\" type=\"button\">\n <mat-icon>save</mat-icon>\n </button>\n\n <button mat-fab class=\"form-action-button\" (click)=\"cancel()\" matTooltip=\"Cancel adding Group\" type=\"button\">\n <mat-icon>cancel</mat-icon>\n </button>\n }\n\n\n</div>", styles: [""], dependencies: [{ kind: "component", type: FormFieldEditComponent, selector: "lib-form-field-edit", inputs: ["form", "editMode"], outputs: ["submitted", "cancelled"] }, { kind: "component", type: FormFieldListComponent, selector: "lib-form-field-list", inputs: ["form"], outputs: ["edit"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i2$3.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2$3.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$3.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2$1.MatFabButton, selector: "button[mat-fab], a[mat-fab], button[matFab], a[matFab]", inputs: ["extended"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i4$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }] });
1132
+ }
1133
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: FormGroupEditComponent, decorators: [{
1134
+ type: Component,
1135
+ args: [{ selector: 'lib-form-group-edit', imports: [FormFieldEditComponent,
1136
+ FormFieldListComponent,
1137
+ MatIconModule,
1138
+ MatFormFieldModule,
1139
+ ReactiveFormsModule,
1140
+ MatButtonModule,
1141
+ MatInputModule, MatTooltipModule], template: "<div [formGroup]=\"form()\">\n\n @if(fieldForm && fields)\n {\n @if(creatingField())\n {\n <h3>Creating Field</h3>\n }\n @else {\n <h3>Editing Field</h3>\n }\n <lib-form-field-edit [form]=\"fieldForm\" (submitted)=\"submitField()\"\n (cancelled)=\"cancelField()\"></lib-form-field-edit>\n }\n @else{\n\n @if(create())\n {\n <h3>Creating Group</h3>\n }\n @else {\n <h3>Editing Group</h3>\n }\n\n <mat-form-field class=\"form-field-wide\">\n <mat-label for=\"description\">Description</mat-label>\n <textarea matInput placeholder=\"\" type=\"text\" style=\"min-height:150px\" formControlName=\"description\"\n name=\"description\"></textarea>\n </mat-form-field>\n\n <h3>Fields</h3>\n <div>\n <button mat-fab class=\"form_action_button\" (click)=\"addField()\" matTooltip=\"Add a Field\" type=\"button\">\n <mat-icon>add</mat-icon>\n </button>\n\n @if(fields && fields.length > 0){\n <lib-form-field-list [form]=\"fields\" (edit)=\"editField($event)\">\n </lib-form-field-list>\n }\n </div>\n\n <button mat-fab class=\"form-action-button\" (click)=\"submit()\" matTooltip=\"Save Group\" type=\"button\">\n <mat-icon>save</mat-icon>\n </button>\n\n <button mat-fab class=\"form-action-button\" (click)=\"cancel()\" matTooltip=\"Cancel adding Group\" type=\"button\">\n <mat-icon>cancel</mat-icon>\n </button>\n }\n\n\n</div>" }]
1142
+ }] });
1143
+
1144
+ class FormGroupListComponent {
1145
+ form = input(...(ngDevMode ? [undefined, { debugName: "form" }] : []));
1146
+ edit = output();
1147
+ delete = output();
1148
+ orderUp = output();
1149
+ orderDown = output();
1150
+ add = output();
1151
+ table = viewChild(MatTable, ...(ngDevMode ? [{ debugName: "table" }] : []));
1152
+ columns = FORM_GROUP_TABLE_FULL;
1153
+ columnNames = computed(() => {
1154
+ const names = this.columns.map(c => c.name);
1155
+ names.push("edit");
1156
+ return names;
1157
+ }, ...(ngDevMode ? [{ debugName: "columnNames" }] : []));
1158
+ onEdit(form) {
1159
+ this.edit.emit(form.value.order);
1160
+ }
1161
+ onDelete(form) {
1162
+ this.delete.emit(form.value.order);
1163
+ this.table()?.renderRows();
1164
+ }
1165
+ onOrderUp(form) {
1166
+ this.orderUp.emit(form.value.order);
1167
+ this.table()?.renderRows();
1168
+ }
1169
+ onOrderDown(form) {
1170
+ this.orderDown.emit(form.value.order);
1171
+ this.table()?.renderRows();
1172
+ }
1173
+ onAdd() {
1174
+ this.add.emit();
1175
+ }
1176
+ getLabel(form) {
1177
+ if (form.value.label) {
1178
+ return form.value.label;
1179
+ }
1180
+ else {
1181
+ return "Group " + form.value.order.toString();
1182
+ }
1183
+ }
1184
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: FormGroupListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1185
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.1", type: FormGroupListComponent, isStandalone: true, selector: "lib-form-group-list", inputs: { form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { edit: "edit", delete: "delete", orderUp: "orderUp", orderDown: "orderDown", add: "add" }, viewQueries: [{ propertyName: "table", first: true, predicate: MatTable, descendants: true, isSignal: true }], ngImport: i0, template: "@if(form(); as form){\n\n@if (form.controls.length > 0){\n<table mat-table [dataSource]=\"form.controls\" class=\"mat-elevation-z8\">\n @for (column of columns; track column.name) {\n <ng-container matColumnDef=\"{{ column.name }}\">\n <th mat-header-cell mat-sort-header *matHeaderCellDef>\n {{ column.title }}\n </th>\n <td mat-cell *matCellDef=\"let element;\">\n {{ getLabel(element) }}\n </td>\n </ng-container>\n }\n <ng-container matColumnDef=\"edit\">\n <th mat-header-cell *matHeaderCellDef>Edit\n </th>\n <td mat-cell *matCellDef=\"let element\">\n <div class=\"control\">\n <button mat-icon-button\n type=\"button\"\n color=\"primary\"\n aria-label=\"Edit an item\"\n (click)=\"onEdit(element)\">\n <mat-icon>edit\n </mat-icon>\n </button>\n <button mat-icon-button\n type=\"button\"\n color=\"primary\"\n aria-label=\"Delete an item\"\n (click)=\"onDelete(element)\">\n <mat-icon>delete\n </mat-icon>\n </button>\n <button mat-icon-button\n type=\"button\"\n color=\"primary\"\n aria-label=\"Move Order Up\"\n (click)=\"onOrderUp(element)\">\n <mat-icon>arrow_upward\n </mat-icon>\n </button> \n <button mat-icon-button\n type=\"button\"\n color=\"primary\"\n aria-label=\"Move Order Down\"\n (click)=\"onOrderDown(element)\">\n <mat-icon>arrow_downward\n </mat-icon>\n </button>\n </div>\n </td>\n </ng-container>\n \n <tr mat-header-row *matHeaderRowDef=\"columnNames()\">\n </tr>\n <tr mat-row *matRowDef=\"let row; columns: columnNames();\">\n </tr>\n</table>\n}\n}\n\n<button mat-fab class=\"form-action-button\" \n (click)=\"onAdd()\" matTooltip=\"Add a Group\" type=\"button\">\n<mat-icon>add</mat-icon>\n</button>\n\n", styles: [".control,.mat-row:hover .control{display:block}\n"], dependencies: [{ kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2$1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i2$1.MatFabButton, selector: "button[mat-fab], a[mat-fab], button[matFab], a[matFab]", inputs: ["extended"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i1$5.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i1$5.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i1$5.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i1$5.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i1$5.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i1$5.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i1$5.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i1$5.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i1$5.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i1$5.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i4$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }] });
1186
+ }
1187
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: FormGroupListComponent, decorators: [{
1188
+ type: Component,
1189
+ args: [{ selector: 'lib-form-group-list', imports: [MatIconModule, MatButtonModule, MatTableModule, MatTooltipModule], template: "@if(form(); as form){\n\n@if (form.controls.length > 0){\n<table mat-table [dataSource]=\"form.controls\" class=\"mat-elevation-z8\">\n @for (column of columns; track column.name) {\n <ng-container matColumnDef=\"{{ column.name }}\">\n <th mat-header-cell mat-sort-header *matHeaderCellDef>\n {{ column.title }}\n </th>\n <td mat-cell *matCellDef=\"let element;\">\n {{ getLabel(element) }}\n </td>\n </ng-container>\n }\n <ng-container matColumnDef=\"edit\">\n <th mat-header-cell *matHeaderCellDef>Edit\n </th>\n <td mat-cell *matCellDef=\"let element\">\n <div class=\"control\">\n <button mat-icon-button\n type=\"button\"\n color=\"primary\"\n aria-label=\"Edit an item\"\n (click)=\"onEdit(element)\">\n <mat-icon>edit\n </mat-icon>\n </button>\n <button mat-icon-button\n type=\"button\"\n color=\"primary\"\n aria-label=\"Delete an item\"\n (click)=\"onDelete(element)\">\n <mat-icon>delete\n </mat-icon>\n </button>\n <button mat-icon-button\n type=\"button\"\n color=\"primary\"\n aria-label=\"Move Order Up\"\n (click)=\"onOrderUp(element)\">\n <mat-icon>arrow_upward\n </mat-icon>\n </button> \n <button mat-icon-button\n type=\"button\"\n color=\"primary\"\n aria-label=\"Move Order Down\"\n (click)=\"onOrderDown(element)\">\n <mat-icon>arrow_downward\n </mat-icon>\n </button>\n </div>\n </td>\n </ng-container>\n \n <tr mat-header-row *matHeaderRowDef=\"columnNames()\">\n </tr>\n <tr mat-row *matRowDef=\"let row; columns: columnNames();\">\n </tr>\n</table>\n}\n}\n\n<button mat-fab class=\"form-action-button\" \n (click)=\"onAdd()\" matTooltip=\"Add a Group\" type=\"button\">\n<mat-icon>add</mat-icon>\n</button>\n\n", styles: [".control,.mat-row:hover .control{display:block}\n"] }]
1190
+ }] });
1191
+
1192
+ class DynamicFormBuilderComponent {
1193
+ form = input.required(...(ngDevMode ? [{ debugName: "form" }] : []));
1194
+ handleSubmit = input(false, ...(ngDevMode ? [{ debugName: "handleSubmit" }] : []));
1195
+ submitted = output();
1196
+ editingField = signal(-1, ...(ngDevMode ? [{ debugName: "editingField" }] : []));
1197
+ creatingField = signal(false, ...(ngDevMode ? [{ debugName: "creatingField" }] : []));
1198
+ editingGroup = signal(-1, ...(ngDevMode ? [{ debugName: "editingGroup" }] : []));
1199
+ creatingGroup = signal(false, ...(ngDevMode ? [{ debugName: "creatingGroup" }] : []));
1200
+ dirty = signal(false, ...(ngDevMode ? [{ debugName: "dirty" }] : []));
1201
+ formBuilder = inject(FormBuilder);
1202
+ groupForm = null;
1203
+ addGroup() {
1204
+ this.creatingGroup.set(true);
1205
+ this.groupForm = FormGroupForm.createForm(this.formBuilder);
1206
+ }
1207
+ editGroup(id) {
1208
+ this.editingGroup.set(id);
1209
+ this.groupForm = this.form().groups.controls[id];
1210
+ }
1211
+ deleteGroup(id) {
1212
+ this.form().deleteGroup(id);
1213
+ this.dirty.set(true);
1214
+ this.reset();
1215
+ }
1216
+ submitGroup() {
1217
+ if (this.creatingGroup() && this.groupForm) {
1218
+ this.form().createGroup(this.groupForm);
1219
+ }
1220
+ this.dirty.set(true);
1221
+ this.reset();
1222
+ }
1223
+ cancel() {
1224
+ this.reset();
1225
+ }
1226
+ reset() {
1227
+ this.groupForm = null;
1228
+ this.creatingGroup.set(false);
1229
+ this.editingGroup.set(-1);
1230
+ }
1231
+ onSubmit() {
1232
+ this.submitted.emit();
1233
+ this.dirty.set(false);
1234
+ }
1235
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: DynamicFormBuilderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1236
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.1", type: DynamicFormBuilderComponent, isStandalone: true, selector: "lib-dynamic-form-builder", inputs: { form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: true, transformFunction: null }, handleSubmit: { classPropertyName: "handleSubmit", publicName: "handleSubmit", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { submitted: "submitted" }, ngImport: i0, template: "<h2>Groups</h2>\n\n@if(groupForm)\n{\n<lib-form-group-edit [form]=\"groupForm\" [create]=\"creatingGroup()\" (cancelled)=\"cancel()\" (submitted)=\"submitGroup()\">\n</lib-form-group-edit>\n}\n@else {\n<lib-form-group-list [form]=\"form().groups\" (edit)=\"editGroup($event)\" (add)=\"addGroup()\"\n (delete)=\"deleteGroup($event)\"></lib-form-group-list>\n}\n\n@if(handleSubmit() && dirty())\n{\n <div>\n <button mat-fab class=\"form-action-button\" \n type=\"button\" matTooltip=\"Save Changes\" (click)=\"onSubmit()\">\n <mat-icon>save</mat-icon>\n </button>\n </div>\n}", styles: [""], dependencies: [{ kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2$1.MatFabButton, selector: "button[mat-fab], a[mat-fab], button[matFab], a[matFab]", inputs: ["extended"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: FormGroupEditComponent, selector: "lib-form-group-edit", inputs: ["create", "form"], outputs: ["cancelled", "submitted"] }, { kind: "component", type: FormGroupListComponent, selector: "lib-form-group-list", inputs: ["form"], outputs: ["edit", "delete", "orderUp", "orderDown", "add"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i4$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }] });
1237
+ }
1238
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: DynamicFormBuilderComponent, decorators: [{
1239
+ type: Component,
1240
+ args: [{ selector: 'lib-dynamic-form-builder', imports: [
1241
+ MatIconModule,
1242
+ MatFormFieldModule,
1243
+ ReactiveFormsModule,
1244
+ MatButtonModule, FormGroupEditComponent, FormGroupListComponent, MatTooltipModule
1245
+ ], template: "<h2>Groups</h2>\n\n@if(groupForm)\n{\n<lib-form-group-edit [form]=\"groupForm\" [create]=\"creatingGroup()\" (cancelled)=\"cancel()\" (submitted)=\"submitGroup()\">\n</lib-form-group-edit>\n}\n@else {\n<lib-form-group-list [form]=\"form().groups\" (edit)=\"editGroup($event)\" (add)=\"addGroup()\"\n (delete)=\"deleteGroup($event)\"></lib-form-group-list>\n}\n\n@if(handleSubmit() && dirty())\n{\n <div>\n <button mat-fab class=\"form-action-button\" \n type=\"button\" matTooltip=\"Save Changes\" (click)=\"onSubmit()\">\n <mat-icon>save</mat-icon>\n </button>\n </div>\n}" }]
1246
+ }] });
1247
+
1248
+ class DynamicFormForm {
1249
+ fb = inject(FormBuilder);
1250
+ form;
1251
+ constructor() {
1252
+ this.form = this.fb.group({
1253
+ groups: this.fb.array([])
1254
+ });
1255
+ }
1256
+ get groups() {
1257
+ return this.form.get('groups');
1258
+ }
1259
+ createGroup(group) {
1260
+ group.patchValue({ order: this.groups.controls.length });
1261
+ this.groups.push(group);
1262
+ }
1263
+ deleteGroup(id) {
1264
+ this.groups.removeAt(id);
1265
+ }
1266
+ reset() {
1267
+ this.form = this.fb.group({
1268
+ groups: this.fb.array([])
1269
+ });
1270
+ }
1271
+ setValue(item) {
1272
+ this.groups.clear();
1273
+ item.groups.map(g => this.groups.push(FormGroupForm.fromItem(g, this.fb)));
1274
+ }
1275
+ createItem() {
1276
+ return {
1277
+ groups: Array.from(this.groups.controls.map(g => FormGroupForm.createItem(g)))
1278
+ };
1279
+ }
1280
+ createOrUpdateGroup(form, items) {
1281
+ if (form.value.id && form.value.id >= 0) {
1282
+ const matching_item = items.find(item => "id" in item && item.id == form.value.id);
1283
+ return FormGroupForm.updateItem(form, matching_item);
1284
+ }
1285
+ return FormGroupForm.createItem(form);
1286
+ }
1287
+ updateItem(item) {
1288
+ const item_update = item;
1289
+ item_update.groups = Array.from(this.groups.controls.map(f => this.createOrUpdateGroup(f, item.groups)));
1290
+ return item_update;
1291
+ }
1292
+ }
1293
+
820
1294
  class SelectTableComponent {
821
1295
  itemType = input("", ...(ngDevMode ? [{ debugName: "itemType" }] : []));
822
1296
  selected = input([], ...(ngDevMode ? [{ debugName: "selected" }] : []));
@@ -843,7 +1317,7 @@ class SelectTableComponent {
843
1317
  this.table()?.renderRows();
844
1318
  }
845
1319
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: SelectTableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
846
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.1", type: SelectTableComponent, isStandalone: true, selector: "lib-select-table", inputs: { itemType: { classPropertyName: "itemType", publicName: "itemType", isSignal: true, isRequired: false, transformFunction: null }, selected: { classPropertyName: "selected", publicName: "selected", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemAdded: "itemAdded", itemRemoved: "itemRemoved", searchChanged: "searchChanged" }, viewQueries: [{ propertyName: "table", first: true, predicate: MatTable, descendants: true, isSignal: true }], ngImport: i0, template: "<div class='select-container'>\n <div>\n <mat-form-field>\n <mat-label>Add {{itemType()}}</mat-label>\n <input \n type=\"text\"\n aria-label=\"Selected item\"\n matInput\n [formControl]=\"searchControl\" \n [matAutocomplete]=\"auto\">\n\n <mat-autocomplete #auto=\"matAutocomplete\">\n @for(item of options(); track item.item.id){\n <mat-option [value]=\"item.title\">{{item.title}}\n </mat-option>\n }\n </mat-autocomplete>\n </mat-form-field>\n\n <button mat-mini-fab type=\"button\" class=\"form_action_button\" (click)=\"add()\">\n <mat-icon>add\n </mat-icon>\n </button>\n </div>\n\n @if(selected().length > 0){\n <table mat-table [dataSource]=\"selected()\" class=\"mat-elevation-z8\">\n @for (column of columns(); track column.name) {\n <ng-container matColumnDef=\"{{ column.name }}\">\n <th mat-header-cell mat-sort-header *matHeaderCellDef>\n {{ column.title }}\n </th>\n <td mat-cell *matCellDef=\"let element\">{{ element[column.name] }}</td>\n </ng-container>\n }\n\n <ng-container matColumnDef=\"remove\">\n <th mat-header-cell *matHeaderCellDef>Remove\n </th>\n <td mat-cell *matCellDef=\"let element\">\n <button mat-icon-button\n color=\"primary\"\n aria-label=\"Remove an item\"\n (click)=\"remove(element.id)\">\n <mat-icon>remove\n </mat-icon>\n </button>\n </td>\n </ng-container>\n\n <tr mat-header-row *matHeaderRowDef=\"columnNames()\">\n </tr>\n <tr mat-row *matRowDef=\"let row; columns: columnNames();\">\n </tr>\n </table>\n }\n</div>", styles: [".select-container,.table_container{display:flex;text-align:center;justify-content:center;flex-direction:column}.form_action_button{padding:5px;margin:5px}\n"], dependencies: [{ kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i1$4.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i1$4.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i1$4.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i1$4.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i1$4.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i1$4.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i1$4.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i1$4.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i1$4.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i1$4.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i3$1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3$1.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2$1.MatMiniFabButton, selector: "button[mat-mini-fab], a[mat-mini-fab], button[matMiniFab], a[matMiniFab]", exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i2$1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i6.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatAutocompleteModule }, { kind: "component", type: i6$1.MatAutocomplete, selector: "mat-autocomplete", inputs: ["aria-label", "aria-labelledby", "displayWith", "autoActiveFirstOption", "autoSelectActiveOption", "requireSelection", "panelWidth", "disableRipple", "class", "hideSingleSelectionIndicator"], outputs: ["optionSelected", "opened", "closed", "optionActivated"], exportAs: ["matAutocomplete"] }, { kind: "directive", type: i6$1.MatAutocompleteTrigger, selector: "input[matAutocomplete], textarea[matAutocomplete]", inputs: ["matAutocomplete", "matAutocompletePosition", "matAutocompleteConnectedTo", "autocomplete", "matAutocompleteDisabled"], exportAs: ["matAutocompleteTrigger"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3$2.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }] });
1320
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.1", type: SelectTableComponent, isStandalone: true, selector: "lib-select-table", inputs: { itemType: { classPropertyName: "itemType", publicName: "itemType", isSignal: true, isRequired: false, transformFunction: null }, selected: { classPropertyName: "selected", publicName: "selected", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemAdded: "itemAdded", itemRemoved: "itemRemoved", searchChanged: "searchChanged" }, viewQueries: [{ propertyName: "table", first: true, predicate: MatTable, descendants: true, isSignal: true }], ngImport: i0, template: "<div class='select-container'>\n <div>\n <mat-form-field>\n <mat-label>Add {{itemType()}}</mat-label>\n <input \n type=\"text\"\n aria-label=\"Selected item\"\n matInput\n [formControl]=\"searchControl\" \n [matAutocomplete]=\"auto\">\n\n <mat-autocomplete #auto=\"matAutocomplete\">\n @for(item of options(); track item.item.id){\n <mat-option [value]=\"item.title\">{{item.title}}\n </mat-option>\n }\n </mat-autocomplete>\n </mat-form-field>\n\n <button mat-mini-fab type=\"button\" class=\"form_action_button\" (click)=\"add()\">\n <mat-icon>add\n </mat-icon>\n </button>\n </div>\n\n @if(selected().length > 0){\n <table mat-table [dataSource]=\"selected()\" class=\"mat-elevation-z8\">\n @for (column of columns(); track column.name) {\n <ng-container matColumnDef=\"{{ column.name }}\">\n <th mat-header-cell mat-sort-header *matHeaderCellDef>\n {{ column.title }}\n </th>\n <td mat-cell *matCellDef=\"let element\">{{ element[column.name] }}</td>\n </ng-container>\n }\n\n <ng-container matColumnDef=\"remove\">\n <th mat-header-cell *matHeaderCellDef>Remove\n </th>\n <td mat-cell *matCellDef=\"let element\">\n <button mat-icon-button\n color=\"primary\"\n aria-label=\"Remove an item\"\n (click)=\"remove(element.id)\">\n <mat-icon>remove\n </mat-icon>\n </button>\n </td>\n </ng-container>\n\n <tr mat-header-row *matHeaderRowDef=\"columnNames()\">\n </tr>\n <tr mat-row *matRowDef=\"let row; columns: columnNames();\">\n </tr>\n </table>\n }\n</div>", styles: [".select-container,.table_container{display:flex;text-align:center;justify-content:center;flex-direction:column}.form_action_button{padding:5px;margin:5px}\n"], dependencies: [{ kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i1$5.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i1$5.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i1$5.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i1$5.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i1$5.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i1$5.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i1$5.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i1$5.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i1$5.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i1$5.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i2$3.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2$3.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2$1.MatMiniFabButton, selector: "button[mat-mini-fab], a[mat-mini-fab], button[matMiniFab], a[matMiniFab]", exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i2$1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i6.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatAutocompleteModule }, { kind: "component", type: i6$1.MatAutocomplete, selector: "mat-autocomplete", inputs: ["aria-label", "aria-labelledby", "displayWith", "autoActiveFirstOption", "autoSelectActiveOption", "requireSelection", "panelWidth", "disableRipple", "class", "hideSingleSelectionIndicator"], outputs: ["optionSelected", "opened", "closed", "optionActivated"], exportAs: ["matAutocomplete"] }, { kind: "directive", type: i6$1.MatAutocompleteTrigger, selector: "input[matAutocomplete], textarea[matAutocomplete]", inputs: ["matAutocomplete", "matAutocompletePosition", "matAutocompleteConnectedTo", "autocomplete", "matAutocompleteDisabled"], exportAs: ["matAutocompleteTrigger"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }] });
847
1321
  }
848
1322
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: SelectTableComponent, decorators: [{
849
1323
  type: Component,
@@ -857,6 +1331,50 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.1", ngImpor
857
1331
  MatInputModule], template: "<div class='select-container'>\n <div>\n <mat-form-field>\n <mat-label>Add {{itemType()}}</mat-label>\n <input \n type=\"text\"\n aria-label=\"Selected item\"\n matInput\n [formControl]=\"searchControl\" \n [matAutocomplete]=\"auto\">\n\n <mat-autocomplete #auto=\"matAutocomplete\">\n @for(item of options(); track item.item.id){\n <mat-option [value]=\"item.title\">{{item.title}}\n </mat-option>\n }\n </mat-autocomplete>\n </mat-form-field>\n\n <button mat-mini-fab type=\"button\" class=\"form_action_button\" (click)=\"add()\">\n <mat-icon>add\n </mat-icon>\n </button>\n </div>\n\n @if(selected().length > 0){\n <table mat-table [dataSource]=\"selected()\" class=\"mat-elevation-z8\">\n @for (column of columns(); track column.name) {\n <ng-container matColumnDef=\"{{ column.name }}\">\n <th mat-header-cell mat-sort-header *matHeaderCellDef>\n {{ column.title }}\n </th>\n <td mat-cell *matCellDef=\"let element\">{{ element[column.name] }}</td>\n </ng-container>\n }\n\n <ng-container matColumnDef=\"remove\">\n <th mat-header-cell *matHeaderCellDef>Remove\n </th>\n <td mat-cell *matCellDef=\"let element\">\n <button mat-icon-button\n color=\"primary\"\n aria-label=\"Remove an item\"\n (click)=\"remove(element.id)\">\n <mat-icon>remove\n </mat-icon>\n </button>\n </td>\n </ng-container>\n\n <tr mat-header-row *matHeaderRowDef=\"columnNames()\">\n </tr>\n <tr mat-row *matRowDef=\"let row; columns: columnNames();\">\n </tr>\n </table>\n }\n</div>", styles: [".select-container,.table_container{display:flex;text-align:center;justify-content:center;flex-direction:column}.form_action_button{padding:5px;margin:5px}\n"] }]
858
1332
  }] });
859
1333
 
1334
+ const USER_TABLE_FULL = [
1335
+ { name: 'first_name', title: 'First Name', element_type: 'string' },
1336
+ { name: 'last_name', title: 'Surname', element_type: 'string' },
1337
+ { name: 'username', title: 'Username', element_type: 'string' },
1338
+ { name: 'email', title: 'Email', element_type: 'email' }
1339
+ ];
1340
+
1341
+ class SelectionManager {
1342
+ candidates = signal([], ...(ngDevMode ? [{ debugName: "candidates" }] : []));
1343
+ selected = signal([], ...(ngDevMode ? [{ debugName: "selected" }] : []));
1344
+ columns = USER_TABLE_FULL;
1345
+ userService = inject(UserService);
1346
+ fetchCandidates(item, id) {
1347
+ const queries = new Map([[item, id.toString()]]);
1348
+ const query = new ItemQuery({ queries: queries });
1349
+ this.userService.get(query).subscribe(users => this.selected.set(users.results));
1350
+ this.userService.get().subscribe(users => this.updateCandidates(users));
1351
+ }
1352
+ updateCandidates(users) {
1353
+ this.candidates.set(users.results.map(user => { return { title: user.username, item: user }; }));
1354
+ }
1355
+ onRemoved(id) {
1356
+ const url = this.selected().find(m => m.id == id).url;
1357
+ this.selected.update(members => members.filter(m => m.id != id));
1358
+ return url;
1359
+ }
1360
+ onAdded(title) {
1361
+ const selected = this.candidates().find(m => m.title == title);
1362
+ if (selected) {
1363
+ this.selected.update(members => { members.push(selected.item); return members; });
1364
+ }
1365
+ this.candidates.update(members => members.filter(m => m.title != title));
1366
+ return this.selected().find(m => m.username == title).url;
1367
+ }
1368
+ onSearchChanged(searchTerm) {
1369
+ if (searchTerm) {
1370
+ this.userService.get(new ItemQuery({ filter: searchTerm })).subscribe(users => this.updateCandidates(users));
1371
+ }
1372
+ else {
1373
+ this.userService.get().subscribe(users => this.updateCandidates(users));
1374
+ }
1375
+ }
1376
+ }
1377
+
860
1378
  /* eslint-disable @typescript-eslint/no-explicit-any */
861
1379
  class ListTableViewComponent {
862
1380
  itemType = input("", ...(ngDevMode ? [{ debugName: "itemType" }] : []));
@@ -902,7 +1420,7 @@ class ListTableViewComponent {
902
1420
  }));
903
1421
  }
904
1422
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: ListTableViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
905
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.1", type: ListTableViewComponent, isStandalone: true, selector: "lib-list-table-view", inputs: { itemType: { classPropertyName: "itemType", publicName: "itemType", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, dataSource: { classPropertyName: "dataSource", publicName: "dataSource", isSignal: true, isRequired: false, transformFunction: null }, searchFilter: { classPropertyName: "searchFilter", publicName: "searchFilter", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "sort", first: true, predicate: MatSort, descendants: true, isSignal: true }, { propertyName: "paginator", first: true, predicate: MatPaginator, descendants: true, isSignal: true }], ngImport: i0, template: "@if (dataSource(); as dataSource) {\n <table\n mat-table\n [dataSource]=\"dataSource\"\n matSort\n matSortActive=\"name\"\n matSortDisableClear\n matSortDirection=\"desc\"\n class=\"mat-elevation-z8\"\n >\n @for (column of columns(); track column.name) {\n <ng-container matColumnDef=\"{{ column.name }}\">\n <th mat-header-cell mat-sort-header *matHeaderCellDef>\n {{ column.title }}\n </th>\n <td mat-cell *matCellDef=\"let element\">{{ element[column.name] }}</td>\n </ng-container>\n }\n\n <tr mat-header-row *matHeaderRowDef=\"columnNames()\"></tr>\n <tr\n mat-row\n *matRowDef=\"let row; columns: columnNames()\"\n [routerLink]=\"['/' + itemType() + '/detail/', row.id]\"\n [routerLinkActive]=\"['is-active']\"\n ></tr>\n </table>\n\n <mat-paginator\n [length]=\"dataSource.length()\"\n [pageSize]=\"20\"\n [pageSizeOptions]=\"pageSizeOptions\"\n aria-label=\"Select page\"\n >\n </mat-paginator>\n}\n", styles: [".mat-mdc-row .mat-mdc-cell{border-bottom:1px solid transparent;border-top:1px solid transparent;cursor:pointer}.mat-mdc-row:hover .mat-mdc-cell{border-color:currentColor}.is-active{font-weight:700}\n"], dependencies: [{ kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i1$4.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i1$4.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i1$4.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i1$4.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i1$4.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i1$4.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i1$4.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i1$4.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i1$4.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i1$4.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: MatButtonModule }, { kind: "ngmodule", type: MatInputModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "ngmodule", type: MatPaginatorModule }, { kind: "component", type: i2$3.MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { kind: "ngmodule", type: MatSortModule }, { kind: "directive", type: i3$3.MatSort, selector: "[matSort]", inputs: ["matSortActive", "matSortStart", "matSortDirection", "matSortDisableClear", "matSortDisabled"], outputs: ["matSortChange"], exportAs: ["matSort"] }, { kind: "component", type: i3$3.MatSortHeader, selector: "[mat-sort-header]", inputs: ["mat-sort-header", "arrowPosition", "start", "disabled", "sortActionDescription", "disableClear"], exportAs: ["matSortHeader"] }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i1.RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }] });
1423
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.1", type: ListTableViewComponent, isStandalone: true, selector: "lib-list-table-view", inputs: { itemType: { classPropertyName: "itemType", publicName: "itemType", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, dataSource: { classPropertyName: "dataSource", publicName: "dataSource", isSignal: true, isRequired: false, transformFunction: null }, searchFilter: { classPropertyName: "searchFilter", publicName: "searchFilter", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "sort", first: true, predicate: MatSort, descendants: true, isSignal: true }, { propertyName: "paginator", first: true, predicate: MatPaginator, descendants: true, isSignal: true }], ngImport: i0, template: "@if (dataSource(); as dataSource) {\n <table\n mat-table\n [dataSource]=\"dataSource\"\n matSort\n matSortActive=\"name\"\n matSortDisableClear\n matSortDirection=\"desc\"\n class=\"mat-elevation-z8\"\n >\n @for (column of columns(); track column.name) {\n <ng-container matColumnDef=\"{{ column.name }}\">\n <th mat-header-cell mat-sort-header *matHeaderCellDef>\n {{ column.title }}\n </th>\n <td mat-cell *matCellDef=\"let element\">{{ element[column.name] }}</td>\n </ng-container>\n }\n\n <tr mat-header-row *matHeaderRowDef=\"columnNames()\"></tr>\n <tr\n mat-row\n *matRowDef=\"let row; columns: columnNames()\"\n [routerLink]=\"['/' + itemType() + '/detail/', row.id]\"\n [routerLinkActive]=\"['is-active']\"\n ></tr>\n </table>\n\n <mat-paginator\n [length]=\"dataSource.length()\"\n [pageSize]=\"20\"\n [pageSizeOptions]=\"pageSizeOptions\"\n aria-label=\"Select page\"\n >\n </mat-paginator>\n}\n", styles: [".mat-mdc-row .mat-mdc-cell{border-bottom:1px solid transparent;border-top:1px solid transparent;cursor:pointer}.mat-mdc-row:hover .mat-mdc-cell{border-color:currentColor}.is-active{font-weight:700}\n"], dependencies: [{ kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i1$5.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i1$5.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i1$5.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i1$5.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i1$5.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i1$5.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i1$5.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i1$5.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i1$5.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i1$5.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: MatButtonModule }, { kind: "ngmodule", type: MatInputModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "ngmodule", type: MatPaginatorModule }, { kind: "component", type: i2$4.MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { kind: "ngmodule", type: MatSortModule }, { kind: "directive", type: i3$1.MatSort, selector: "[matSort]", inputs: ["matSortActive", "matSortStart", "matSortDirection", "matSortDisableClear", "matSortDisabled"], outputs: ["matSortChange"], exportAs: ["matSort"] }, { kind: "component", type: i3$1.MatSortHeader, selector: "[mat-sort-header]", inputs: ["mat-sort-header", "arrowPosition", "start", "disabled", "sortActionDescription", "disableClear"], exportAs: ["matSortHeader"] }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i1.RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }] });
906
1424
  }
907
1425
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: ListTableViewComponent, decorators: [{
908
1426
  type: Component,
@@ -934,7 +1452,7 @@ class ListScrollViewComponent {
934
1452
  data_source.reset(this.searchTerm(), this.pageSize());
935
1453
  }
936
1454
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: ListScrollViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
937
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.1.1", type: ListScrollViewComponent, isStandalone: true, selector: "lib-list-scroll-view", inputs: { searchTerm: { classPropertyName: "searchTerm", publicName: "searchTerm", isSignal: true, isRequired: false, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null }, dataSource: { classPropertyName: "dataSource", publicName: "dataSource", isSignal: true, isRequired: false, transformFunction: null }, listItemTemplate: { classPropertyName: "listItemTemplate", publicName: "listItemTemplate", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<mat-nav-list>\n <cdk-virtual-scroll-viewport\n itemSize=\"150\"\n class=\"scrollable-list\"\n style=\"height: 600px; width: 500px\"\n >\n <ng-container *cdkVirtualFor=\"let item of dataSource()\">\n <ng-container\n *ngTemplateOutlet=\"listItemTemplate(); context: { item: item }\"\n >\n </ng-container>\n </ng-container>\n </cdk-virtual-scroll-viewport>\n</mat-nav-list>\n", styles: [":host{flex-grow:1}.mat-mdc-row .mat-mdc-cell{border-bottom:1px solid transparent;border-top:1px solid transparent;cursor:pointer}.mat-mdc-row:hover .mat-mdc-cell{border-color:currentColor}.is-active{font-weight:700}\n"], dependencies: [{ kind: "ngmodule", type: MatListModule }, { kind: "component", type: i2$2.MatNavList, selector: "mat-nav-list", exportAs: ["matNavList"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i2$4.CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i2$4.CdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i2$4.CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }] });
1455
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.1.1", type: ListScrollViewComponent, isStandalone: true, selector: "lib-list-scroll-view", inputs: { searchTerm: { classPropertyName: "searchTerm", publicName: "searchTerm", isSignal: true, isRequired: false, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null }, dataSource: { classPropertyName: "dataSource", publicName: "dataSource", isSignal: true, isRequired: false, transformFunction: null }, listItemTemplate: { classPropertyName: "listItemTemplate", publicName: "listItemTemplate", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<mat-nav-list>\n <cdk-virtual-scroll-viewport\n itemSize=\"150\"\n class=\"scrollable-list\"\n style=\"height: 600px; width: 500px\"\n >\n <ng-container *cdkVirtualFor=\"let item of dataSource()\">\n <ng-container\n *ngTemplateOutlet=\"listItemTemplate(); context: { item: item }\"\n >\n </ng-container>\n </ng-container>\n </cdk-virtual-scroll-viewport>\n</mat-nav-list>\n", styles: [":host{flex-grow:1}.mat-mdc-row .mat-mdc-cell{border-bottom:1px solid transparent;border-top:1px solid transparent;cursor:pointer}.mat-mdc-row:hover .mat-mdc-cell{border-color:currentColor}.is-active{font-weight:700}\n"], dependencies: [{ kind: "ngmodule", type: MatListModule }, { kind: "component", type: i2$2.MatNavList, selector: "mat-nav-list", exportAs: ["matNavList"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i2$5.CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i2$5.CdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i2$5.CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }] });
938
1456
  }
939
1457
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: ListScrollViewComponent, decorators: [{
940
1458
  type: Component,
@@ -949,7 +1467,7 @@ class BackButtonComponent {
949
1467
  this.location.back();
950
1468
  }
951
1469
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: BackButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
952
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.1", type: BackButtonComponent, isStandalone: true, selector: "lib-back-button", ngImport: i0, template: "<a mat-icon-button class=\"padded-button\"\n (click)=\"goBack()\"\n (keydown)=\"goBack()\"\n tabindex=\"0\"\n role=\"button\">\n<mat-icon>arrow_back</mat-icon>\n</a>\n\n", styles: [".padded-button{margin:5px}\n"], dependencies: [{ kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2$1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }] });
1470
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.1", type: BackButtonComponent, isStandalone: true, selector: "lib-back-button", ngImport: i0, template: "<a mat-icon-button class=\"padded-button\"\n (click)=\"goBack()\"\n (keydown)=\"goBack()\"\n tabindex=\"0\"\n role=\"button\">\n<mat-icon>arrow_back</mat-icon>\n</a>\n\n", styles: [".padded-button{margin:5px}\n"], dependencies: [{ kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2$1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }] });
953
1471
  }
954
1472
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: BackButtonComponent, decorators: [{
955
1473
  type: Component,
@@ -974,7 +1492,7 @@ class SearchBarComponent {
974
1492
  this.searchChanged.emit(this.searchFilter.value);
975
1493
  }
976
1494
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: SearchBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
977
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.1", type: SearchBarComponent, isStandalone: true, selector: "lib-search-bar", inputs: { itemType: { classPropertyName: "itemType", publicName: "itemType", isSignal: true, isRequired: false, transformFunction: null }, sortFields: { classPropertyName: "sortFields", publicName: "sortFields", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { searchChanged: "searchChanged" }, ngImport: i0, template: "<div class=\"container\">\n <mat-form-field class=\"search\" style=\"margin: 10px;\">\n <mat-label>Search</mat-label>\n <input matInput [formControl]=\"searchFilter\" placeholder=\"Search {{ itemType() | titlecase }}\" />\n\n @if(searchFilter.value){\n <button matSuffix mat-icon-button aria-label=\"Cancel\" (click)=\"clearSearch()\">\n <mat-icon>cancel</mat-icon>\n </button>\n }\n @else(){\n <button matSuffix mat-icon-button aria-label=\"Search\">\n <mat-icon>search</mat-icon>\n </button>\n }\n </mat-form-field>\n\n @if(sortFields().length > 0){\n <mat-form-field style=\"margin: 10px\">\n <mat-label>Sort By</mat-label>\n <mat-select>\n @for(field of sortFields(); track field)\n {\n <mat-option>{{field}}</mat-option>\n }\n </mat-select>\n </mat-form-field>\n\n <button mat-icon-button aria-label=\"Sort Order\" matTooltip=\"Toggle sort order\">\n <mat-icon>sort</mat-icon>\n </button>\n }\n</div>", styles: [".container{width:100%;display:flex;flex-wrap:wrap;flex-direction:row;align-items:center;justify-content:center}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3$2.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "component", type: i3$1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3$1.MatLabel, selector: "mat-label" }, { kind: "directive", type: i3$1.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i4.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2$1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i6.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i6.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "pipe", type: TitleCasePipe, name: "titlecase" }] });
1495
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.1", type: SearchBarComponent, isStandalone: true, selector: "lib-search-bar", inputs: { itemType: { classPropertyName: "itemType", publicName: "itemType", isSignal: true, isRequired: false, transformFunction: null }, sortFields: { classPropertyName: "sortFields", publicName: "sortFields", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { searchChanged: "searchChanged" }, ngImport: i0, template: "<div class=\"container\">\n <mat-form-field class=\"search\" style=\"margin: 10px;\">\n <mat-label>Search</mat-label>\n <input matInput [formControl]=\"searchFilter\" placeholder=\"Search {{ itemType() | titlecase }}\" />\n\n @if(searchFilter.value){\n <button matSuffix mat-icon-button aria-label=\"Cancel\" (click)=\"clearSearch()\">\n <mat-icon>cancel</mat-icon>\n </button>\n }\n @else(){\n <button matSuffix mat-icon-button aria-label=\"Search\">\n <mat-icon>search</mat-icon>\n </button>\n }\n </mat-form-field>\n\n @if(sortFields().length > 0){\n <mat-form-field style=\"margin: 10px\">\n <mat-label>Sort By</mat-label>\n <mat-select>\n @for(field of sortFields(); track field)\n {\n <mat-option>{{field}}</mat-option>\n }\n </mat-select>\n </mat-form-field>\n\n <button mat-icon-button aria-label=\"Sort Order\" matTooltip=\"Toggle sort order\">\n <mat-icon>sort</mat-icon>\n </button>\n }\n</div>", styles: [".container{width:100%;display:flex;flex-wrap:wrap;flex-direction:row;align-items:center;justify-content:center}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "component", type: i2$3.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2$3.MatLabel, selector: "mat-label" }, { kind: "directive", type: i2$3.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i4$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2$1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i6.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i6.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "pipe", type: TitleCasePipe, name: "titlecase" }] });
978
1496
  }
979
1497
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: SearchBarComponent, decorators: [{
980
1498
  type: Component,
@@ -1001,7 +1519,6 @@ class ListDataSource extends DataSource {
1001
1519
  fetchedPages = new Set();
1002
1520
  constructor(itemService, consumerType = "table") {
1003
1521
  super();
1004
- console.log("created");
1005
1522
  this.itemService = itemService;
1006
1523
  this.consumerType = consumerType;
1007
1524
  }
@@ -1134,7 +1651,7 @@ class ListViewComponent {
1134
1651
  return (url_segments.length == 2) && (url_segments[1].path == "self");
1135
1652
  }
1136
1653
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: ListViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1137
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.1", type: ListViewComponent, isStandalone: true, selector: "lib-list-view", inputs: { viewType: { classPropertyName: "viewType", publicName: "viewType", isSignal: true, isRequired: false, transformFunction: null }, itemService: { classPropertyName: "itemService", publicName: "itemService", isSignal: true, isRequired: false, transformFunction: null }, itemDetailTemplate: { classPropertyName: "itemDetailTemplate", publicName: "itemDetailTemplate", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, sortFields: { classPropertyName: "sortFields", publicName: "sortFields", isSignal: true, isRequired: false, transformFunction: null }, noSelfItemsMessage: { classPropertyName: "noSelfItemsMessage", publicName: "noSelfItemsMessage", isSignal: true, isRequired: false, transformFunction: null }, noItemsCanCreateMessage: { classPropertyName: "noItemsCanCreateMessage", publicName: "noItemsCanCreateMessage", isSignal: true, isRequired: false, transformFunction: null }, noItemsMessage: { classPropertyName: "noItemsMessage", publicName: "noItemsMessage", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "sort", first: true, predicate: MatSort, descendants: true, isSignal: true }], ngImport: i0, template: "<lib-back-button></lib-back-button>\n\n<div class=\"container\">\n <div class=\"header\">\n <h1 class=\"title\">{{ title() | titlecase }}</h1>\n\n @if (canCreate()) {\n <div class=\"button-container\">\n <a mat-fab class=\"padded-button\" aria-label=\"Add new item\" matTooltip=\"Add new item\" [routerLink]=\"['create']\">\n <mat-icon>add</mat-icon></a>\n </div>\n }\n </div>\n\n @if(dataSource)\n {\n <div class=\"controls\" [hidden]=\"dataSource.sourceIsEmpty()\">\n <lib-search-bar [itemType]=\"title()\" [sortFields]=\"sortFields()\"\n (searchChanged)=\"onSearchChange($event)\"></lib-search-bar>\n\n @if(itemDetailTemplate()){\n <div style=\"margin: 10px\">\n <mat-button-toggle-group name=\"viewType\" aria-label=\"View Type\" [value]=\"selectedViewType()\"\n (change)=\"viewChanged($event)\">\n\n <mat-button-toggle value=\"table\" matTooltip=\"Show as table\">\n <mat-icon>table_view</mat-icon>\n </mat-button-toggle>\n\n <mat-button-toggle value=\"scroll\" matTooltip=\"Show as list\">\n <mat-icon>list</mat-icon>\n </mat-button-toggle>\n\n </mat-button-toggle-group>\n </div>\n }\n </div>\n\n @if (dataSource.loading()) {\n <div class=\"spinner-container\">\n <mat-spinner></mat-spinner>\n </div>\n }\n\n <div [hidden]=\"!dataSource.sourceIsEmpty()\">\n @if(isSelfList())\n {\n @if(noSelfItemsMessage())\n {\n <p>{{noSelfItemsMessage()}}</p>\n }\n @else {\n <p>You do not have any {{itemType()}}.</p> \n }\n }\n @else{\n @if(canCreate()){\n @if(noItemsCanCreateMessage())\n {\n <p>{{noItemsCanCreateMessage()}}</p>\n }\n @else{\n <p>There are currently no {{itemType()}}, click above to add one.</p>\n }\n }\n @else{\n @if(noItemsMessage())\n {\n <p>{{noItemsMessage()}}</p>\n }\n @else\n {\n <p>There are currently no {{itemType()}}.</p>\n }\n }\n }\n </div>\n\n <div [hidden]=\"dataSource.sourceIsEmpty()\">\n @if(isTableView()) {\n <lib-list-table-view [itemType]=\"itemType()\" [columns]=\"columns()\" [dataSource]=\"dataSource\">\n </lib-list-table-view>\n } \n @else {\n <lib-list-scroll-view [listItemTemplate]=\"itemDetailTemplate()\" [dataSource]=\"dataSource\"></lib-list-scroll-view>\n }\n\n </div>\n }\n</div>", styles: [":host{flex-grow:1}.container{display:flex;padding:10px;flex-direction:column;justify-content:center;text-align:center;align-items:center}.header{display:flex;flex-direction:row;align-items:center;justify-content:center}.title{text-align:center;padding:10px}.controls{display:flex;align-items:center;justify-content:center;flex-wrap:wrap}.hide-element{display:none}\n"], dependencies: [{ kind: "component", type: ListTableViewComponent, selector: "lib-list-table-view", inputs: ["itemType", "columns", "dataSource", "searchFilter"] }, { kind: "component", type: ListScrollViewComponent, selector: "lib-list-scroll-view", inputs: ["searchTerm", "pageSize", "dataSource", "listItemTemplate"] }, { kind: "component", type: BackButtonComponent, selector: "lib-back-button" }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: MatButtonToggleModule }, { kind: "directive", type: i1$5.MatButtonToggleGroup, selector: "mat-button-toggle-group", inputs: ["appearance", "name", "vertical", "value", "multiple", "disabled", "disabledInteractive", "hideSingleSelectionIndicator", "hideMultipleSelectionIndicator"], outputs: ["valueChange", "change"], exportAs: ["matButtonToggleGroup"] }, { kind: "component", type: i1$5.MatButtonToggle, selector: "mat-button-toggle", inputs: ["aria-label", "aria-labelledby", "id", "name", "value", "tabIndex", "disableRipple", "appearance", "checked", "disabled", "disabledInteractive"], outputs: ["change"], exportAs: ["matButtonToggle"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i2$5.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i4.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2$1.MatFabButton, selector: "button[mat-fab], a[mat-fab], button[matFab], a[matFab]", inputs: ["extended"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: SearchBarComponent, selector: "lib-search-bar", inputs: ["itemType", "sortFields"], outputs: ["searchChanged"] }, { kind: "pipe", type: TitleCasePipe, name: "titlecase" }] });
1654
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.1", type: ListViewComponent, isStandalone: true, selector: "lib-list-view", inputs: { viewType: { classPropertyName: "viewType", publicName: "viewType", isSignal: true, isRequired: false, transformFunction: null }, itemService: { classPropertyName: "itemService", publicName: "itemService", isSignal: true, isRequired: false, transformFunction: null }, itemDetailTemplate: { classPropertyName: "itemDetailTemplate", publicName: "itemDetailTemplate", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, sortFields: { classPropertyName: "sortFields", publicName: "sortFields", isSignal: true, isRequired: false, transformFunction: null }, noSelfItemsMessage: { classPropertyName: "noSelfItemsMessage", publicName: "noSelfItemsMessage", isSignal: true, isRequired: false, transformFunction: null }, noItemsCanCreateMessage: { classPropertyName: "noItemsCanCreateMessage", publicName: "noItemsCanCreateMessage", isSignal: true, isRequired: false, transformFunction: null }, noItemsMessage: { classPropertyName: "noItemsMessage", publicName: "noItemsMessage", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "sort", first: true, predicate: MatSort, descendants: true, isSignal: true }], ngImport: i0, template: "<lib-back-button></lib-back-button>\n\n<div class=\"container\">\n <div class=\"header\">\n <h1 class=\"title\">{{ title() | titlecase }}</h1>\n\n @if (canCreate()) {\n <div class=\"button-container\">\n <a mat-fab class=\"padded-button\" aria-label=\"Add new item\" matTooltip=\"Add new item\" [routerLink]=\"['create']\">\n <mat-icon>add</mat-icon></a>\n </div>\n }\n </div>\n\n @if(dataSource)\n {\n <div class=\"controls\" [hidden]=\"dataSource.sourceIsEmpty()\">\n <lib-search-bar [itemType]=\"title()\" [sortFields]=\"sortFields()\"\n (searchChanged)=\"onSearchChange($event)\"></lib-search-bar>\n\n @if(itemDetailTemplate()){\n <div style=\"margin: 10px\">\n <mat-button-toggle-group name=\"viewType\" aria-label=\"View Type\" [value]=\"selectedViewType()\"\n (change)=\"viewChanged($event)\">\n\n <mat-button-toggle value=\"table\" matTooltip=\"Show as table\">\n <mat-icon>table_view</mat-icon>\n </mat-button-toggle>\n\n <mat-button-toggle value=\"scroll\" matTooltip=\"Show as list\">\n <mat-icon>list</mat-icon>\n </mat-button-toggle>\n\n </mat-button-toggle-group>\n </div>\n }\n </div>\n\n @if (dataSource.loading()) {\n <div class=\"spinner-container\">\n <mat-spinner></mat-spinner>\n </div>\n }\n\n <div [hidden]=\"!dataSource.sourceIsEmpty()\">\n @if(isSelfList())\n {\n @if(noSelfItemsMessage())\n {\n <p>{{noSelfItemsMessage()}}</p>\n }\n @else {\n <p>You do not have any {{itemType()}}.</p> \n }\n }\n @else{\n @if(canCreate()){\n @if(noItemsCanCreateMessage())\n {\n <p>{{noItemsCanCreateMessage()}}</p>\n }\n @else{\n <p>There are currently no {{itemType()}}, click above to add one.</p>\n }\n }\n @else{\n @if(noItemsMessage())\n {\n <p>{{noItemsMessage()}}</p>\n }\n @else\n {\n <p>There are currently no {{itemType()}}.</p>\n }\n }\n }\n </div>\n\n <div [hidden]=\"dataSource.sourceIsEmpty()\">\n @if(isTableView()) {\n <lib-list-table-view [itemType]=\"itemType()\" [columns]=\"columns()\" [dataSource]=\"dataSource\">\n </lib-list-table-view>\n } \n @else {\n <lib-list-scroll-view [listItemTemplate]=\"itemDetailTemplate()\" [dataSource]=\"dataSource\"></lib-list-scroll-view>\n }\n\n </div>\n }\n</div>", styles: [":host{flex-grow:1}.container{display:flex;padding:10px;flex-direction:column;justify-content:center;text-align:center;align-items:center}.header{display:flex;flex-direction:row;align-items:center;justify-content:center}.title{text-align:center;padding:10px}.controls{display:flex;align-items:center;justify-content:center;flex-wrap:wrap}.hide-element{display:none}\n"], dependencies: [{ kind: "component", type: ListTableViewComponent, selector: "lib-list-table-view", inputs: ["itemType", "columns", "dataSource", "searchFilter"] }, { kind: "component", type: ListScrollViewComponent, selector: "lib-list-scroll-view", inputs: ["searchTerm", "pageSize", "dataSource", "listItemTemplate"] }, { kind: "component", type: BackButtonComponent, selector: "lib-back-button" }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: MatButtonToggleModule }, { kind: "directive", type: i1$6.MatButtonToggleGroup, selector: "mat-button-toggle-group", inputs: ["appearance", "name", "vertical", "value", "multiple", "disabled", "disabledInteractive", "hideSingleSelectionIndicator", "hideMultipleSelectionIndicator"], outputs: ["valueChange", "change"], exportAs: ["matButtonToggleGroup"] }, { kind: "component", type: i1$6.MatButtonToggle, selector: "mat-button-toggle", inputs: ["aria-label", "aria-labelledby", "id", "name", "value", "tabIndex", "disableRipple", "appearance", "checked", "disabled", "disabledInteractive"], outputs: ["change"], exportAs: ["matButtonToggle"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i2$6.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i4$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2$1.MatFabButton, selector: "button[mat-fab], a[mat-fab], button[matFab], a[matFab]", inputs: ["extended"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: SearchBarComponent, selector: "lib-search-bar", inputs: ["itemType", "sortFields"], outputs: ["searchChanged"] }, { kind: "pipe", type: TitleCasePipe, name: "titlecase" }] });
1138
1655
  }
1139
1656
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: ListViewComponent, decorators: [{
1140
1657
  type: Component,
@@ -1166,7 +1683,7 @@ class DetailHeaderComponent {
1166
1683
  this.deleteClicked.emit();
1167
1684
  }
1168
1685
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: DetailHeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1169
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.1", type: DetailHeaderComponent, isStandalone: true, selector: "lib-detail-header", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, text: { classPropertyName: "text", publicName: "text", isSignal: true, isRequired: false, transformFunction: null }, route: { classPropertyName: "route", publicName: "route", isSignal: true, isRequired: false, transformFunction: null }, canEdit: { classPropertyName: "canEdit", publicName: "canEdit", isSignal: true, isRequired: false, transformFunction: null }, canDelete: { classPropertyName: "canDelete", publicName: "canDelete", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { deleteClicked: "deleteClicked" }, ngImport: i0, template: "<div class=\"container\">\n\n <h1 class=\"header\">{{text()}}</h1>\n\n <div class=\"controls\">\n @if(canEdit()){\n <a mat-mini-fab class=\"control-button\" matTooltip=\"Edit the item\" title=\"Click to edit this item\" aria-label=\"Click to edit this item\"\n [routerLink]=\"[fullRoute(), id()]\">\n <mat-icon>edit</mat-icon>\n </a>\n }\n\n @if(canDelete()){\n <button mat-mini-fab class=\"control-button\" (click)=\"deleteClick()\" matTooltip=\"Delete the item\" title=\"Click to delete this item\"\n aria-label=\"Click to delete this item\">\n <mat-icon>delete</mat-icon></button>\n }\n </div>\n\n</div>", styles: [".container{width:100%;max-width:500px;padding:5px}.header{width:100%;padding:5px;margin:5px}.controls{display:flex;flex-direction:row;align-content:center;justify-content:center}.control-button{padding:5px;margin:5px}\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"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2$1.MatMiniFabButton, selector: "button[mat-mini-fab], a[mat-mini-fab], button[matMiniFab], a[matMiniFab]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i4.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }] });
1686
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.1", type: DetailHeaderComponent, isStandalone: true, selector: "lib-detail-header", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, text: { classPropertyName: "text", publicName: "text", isSignal: true, isRequired: false, transformFunction: null }, route: { classPropertyName: "route", publicName: "route", isSignal: true, isRequired: false, transformFunction: null }, canEdit: { classPropertyName: "canEdit", publicName: "canEdit", isSignal: true, isRequired: false, transformFunction: null }, canDelete: { classPropertyName: "canDelete", publicName: "canDelete", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { deleteClicked: "deleteClicked" }, ngImport: i0, template: "<div class=\"container\">\n\n <h1 class=\"header\">{{text()}}</h1>\n\n <div class=\"controls\">\n @if(canEdit()){\n <a mat-mini-fab class=\"control-button\" matTooltip=\"Edit the item\" title=\"Click to edit this item\" aria-label=\"Click to edit this item\"\n [routerLink]=\"[fullRoute(), id()]\">\n <mat-icon>edit</mat-icon>\n </a>\n }\n\n @if(canDelete()){\n <button mat-mini-fab class=\"control-button\" (click)=\"deleteClick()\" matTooltip=\"Delete the item\" title=\"Click to delete this item\"\n aria-label=\"Click to delete this item\">\n <mat-icon>delete</mat-icon></button>\n }\n </div>\n\n</div>", styles: [".container{width:100%;max-width:500px;padding:5px}.header{width:100%;padding:5px;margin:5px}.controls{display:flex;flex-direction:row;align-content:center;justify-content:center}.control-button{padding:5px;margin:5px}\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"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2$1.MatMiniFabButton, selector: "button[mat-mini-fab], a[mat-mini-fab], button[matMiniFab], a[matMiniFab]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i4$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }] });
1170
1687
  }
1171
1688
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: DetailHeaderComponent, decorators: [{
1172
1689
  type: Component,
@@ -1175,49 +1692,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.1", ngImpor
1175
1692
  MatIconModule, MatTooltipModule], template: "<div class=\"container\">\n\n <h1 class=\"header\">{{text()}}</h1>\n\n <div class=\"controls\">\n @if(canEdit()){\n <a mat-mini-fab class=\"control-button\" matTooltip=\"Edit the item\" title=\"Click to edit this item\" aria-label=\"Click to edit this item\"\n [routerLink]=\"[fullRoute(), id()]\">\n <mat-icon>edit</mat-icon>\n </a>\n }\n\n @if(canDelete()){\n <button mat-mini-fab class=\"control-button\" (click)=\"deleteClick()\" matTooltip=\"Delete the item\" title=\"Click to delete this item\"\n aria-label=\"Click to delete this item\">\n <mat-icon>delete</mat-icon></button>\n }\n </div>\n\n</div>", styles: [".container{width:100%;max-width:500px;padding:5px}.header{width:100%;padding:5px;margin:5px}.controls{display:flex;flex-direction:row;align-content:center;justify-content:center}.control-button{padding:5px;margin:5px}\n"] }]
1176
1693
  }] });
1177
1694
 
1178
- class FileUploadComponent {
1179
- files = input([], ...(ngDevMode ? [{ debugName: "files" }] : []));
1180
- previewLoaded = output();
1181
- fileUploaded = output();
1182
- clearLocal = output();
1183
- onPreviewRead(name, content) {
1184
- this.previewLoaded.emit({ name: name, content: content });
1185
- }
1186
- onFileUpload(name, event) {
1187
- if (!event.target) {
1188
- return;
1189
- }
1190
- const input_element = event.target;
1191
- if (input_element.files && input_element.files.length > 0) {
1192
- const file = input_element.files[0];
1193
- this.fileUploaded.emit({ name: name, file: file });
1194
- const record = this.files().find(f => f.name == name);
1195
- if (record && record.file_type == "image") {
1196
- this.readFile(name, file);
1197
- }
1198
- }
1199
- }
1200
- readFile(name, file) {
1201
- const reader = new FileReader();
1202
- reader.readAsDataURL(file);
1203
- reader.onload = () => {
1204
- if (reader.result) {
1205
- this.previewLoaded.emit({ name: name, content: reader.result });
1206
- }
1207
- ;
1208
- };
1209
- }
1210
- onClearLocal() {
1211
- this.clearLocal.emit();
1212
- }
1213
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: FileUploadComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1214
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.1", type: FileUploadComponent, isStandalone: true, selector: "lib-file-upload", inputs: { files: { classPropertyName: "files", publicName: "files", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { previewLoaded: "previewLoaded", fileUploaded: "fileUploaded", clearLocal: "clearLocal" }, ngImport: i0, template: "<div class=\"container\">\n @for( file of files(); track file.name)\n {\n @if (file.local)\n {\n <div class=\"image_holder\">\n <p>Update {{file.display_name}}</p>\n <img alt=\"{{file.display_name}}\" src=\"{{file.local}}\" style=\"height:120px;\">\n <button mat-mini-fab (click)=\"onClearLocal()\">\n <mat-icon>clear</mat-icon>\n </button>\n </div> \n }\n @else\n {\n @if (file.remote){\n <div class=\"image_holder\">\n <p>Update {{file.display_name}}</p>\n <img alt=\"{{file.display_name}}\" src=\"{{file.remote}}\" style=\"height:120px;\">\n </div>\n }\n @else {\n <div>\n <span>Upload a {{file.display_name}}</span>\n </div> \n }\n \n }\n\n <div class=\"button-row\">\n <button mat-mini-fab (click)=\"fileInput.click()\">\n <mat-icon>attachment</mat-icon>\n </button>\n <input hidden type=\"file\" #fileInput (change)=\"onFileUpload(file.name, $event)\"/>\n </div> \n } \n</div>\n", styles: [".container{padding:10px;display:flex;justify-content:center;text-align:center;flex-direction:column;max-width:300px}\n"], dependencies: [{ kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2$1.MatMiniFabButton, selector: "button[mat-mini-fab], a[mat-mini-fab], button[matMiniFab], a[matMiniFab]", exportAs: ["matButton", "matAnchor"] }] });
1215
- }
1216
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: FileUploadComponent, decorators: [{
1217
- type: Component,
1218
- args: [{ selector: 'lib-file-upload', imports: [MatIconModule, MatButtonModule], template: "<div class=\"container\">\n @for( file of files(); track file.name)\n {\n @if (file.local)\n {\n <div class=\"image_holder\">\n <p>Update {{file.display_name}}</p>\n <img alt=\"{{file.display_name}}\" src=\"{{file.local}}\" style=\"height:120px;\">\n <button mat-mini-fab (click)=\"onClearLocal()\">\n <mat-icon>clear</mat-icon>\n </button>\n </div> \n }\n @else\n {\n @if (file.remote){\n <div class=\"image_holder\">\n <p>Update {{file.display_name}}</p>\n <img alt=\"{{file.display_name}}\" src=\"{{file.remote}}\" style=\"height:120px;\">\n </div>\n }\n @else {\n <div>\n <span>Upload a {{file.display_name}}</span>\n </div> \n }\n \n }\n\n <div class=\"button-row\">\n <button mat-mini-fab (click)=\"fileInput.click()\">\n <mat-icon>attachment</mat-icon>\n </button>\n <input hidden type=\"file\" #fileInput (change)=\"onFileUpload(file.name, $event)\"/>\n </div> \n } \n</div>\n", styles: [".container{padding:10px;display:flex;justify-content:center;text-align:center;flex-direction:column;max-width:300px}\n"] }]
1219
- }] });
1220
-
1221
1695
  class FileRecord {
1222
1696
  name = "";
1223
1697
  display_name = "";
@@ -1237,6 +1711,15 @@ class UserDetailComponent extends DetailView {
1237
1711
  ngOnInit() {
1238
1712
  this.onInit();
1239
1713
  }
1714
+ canEdit() {
1715
+ if (!this.userService.loggedInUser) {
1716
+ return false;
1717
+ }
1718
+ if (this.item()?.id == this.userService.loggedInUser.value?.id) {
1719
+ return true;
1720
+ }
1721
+ return super.canEdit();
1722
+ }
1240
1723
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: UserDetailComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1241
1724
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.1", type: UserDetailComponent, isStandalone: true, selector: "lib-user-detail", usesInheritance: true, ngImport: i0, template: "<lib-back-button></lib-back-button>\n\n<div class=\"content-container\">\n @if(item(); as item){\n <div class=\"item-detail-container\">\n\n <lib-detail-header\n [text]=\"item.username\"\n [id]=\"item.id\"\n [route]=\"itemService.typePlural()\"\n [canEdit]=\"canEdit()\"\n [canDelete]=\"canDelete()\"\n (onDelete)=\"onDelete()\"></lib-detail-header>\n\n @if(item.profile_url){\n <div class=\"image-holder\">\n <img alt=\"User Profile Image\" src=\"{{item.url}}{{item.profile_url}}\" style=\"height:120px;\">\n </div> \n }\n \n <div class=\"item-field\">\n <span><b>Email: </b></span>\n {{item.email}}\n </div>\n \n <div class=\"item-field\">\n <span><b>First Name: </b></span>\n {{item.first_name}}\n </div>\n \n <div class=\"item-field\">\n <span><b>Last Name: </b></span>\n {{item.last_name}}\n </div>\n \n </div>\n }\n</div>\n", styles: [":host{flex-grow:1}\n"], dependencies: [{ kind: "component", type: BackButtonComponent, selector: "lib-back-button" }, { kind: "component", type: DetailHeaderComponent, selector: "lib-detail-header", inputs: ["id", "text", "route", "canEdit", "canDelete"], outputs: ["deleteClicked"] }] });
1242
1725
  }
@@ -1246,12 +1729,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.1", ngImpor
1246
1729
  DetailHeaderComponent], template: "<lib-back-button></lib-back-button>\n\n<div class=\"content-container\">\n @if(item(); as item){\n <div class=\"item-detail-container\">\n\n <lib-detail-header\n [text]=\"item.username\"\n [id]=\"item.id\"\n [route]=\"itemService.typePlural()\"\n [canEdit]=\"canEdit()\"\n [canDelete]=\"canDelete()\"\n (onDelete)=\"onDelete()\"></lib-detail-header>\n\n @if(item.profile_url){\n <div class=\"image-holder\">\n <img alt=\"User Profile Image\" src=\"{{item.url}}{{item.profile_url}}\" style=\"height:120px;\">\n </div> \n }\n \n <div class=\"item-field\">\n <span><b>Email: </b></span>\n {{item.email}}\n </div>\n \n <div class=\"item-field\">\n <span><b>First Name: </b></span>\n {{item.first_name}}\n </div>\n \n <div class=\"item-field\">\n <span><b>Last Name: </b></span>\n {{item.last_name}}\n </div>\n \n </div>\n }\n</div>\n", styles: [":host{flex-grow:1}\n"] }]
1247
1730
  }], ctorParameters: () => [] });
1248
1731
 
1249
- class UserEditComponent extends EditView {
1250
- files = signal([new FileRecord({
1251
- name: "image",
1252
- display_name: "Profile Image",
1253
- file_type: "image"
1254
- })], ...(ngDevMode ? [{ debugName: "files" }] : []));
1732
+ class UserForm {
1255
1733
  formBuilder = inject(FormBuilder);
1256
1734
  form = this.formBuilder.group({
1257
1735
  username: [''],
@@ -1260,17 +1738,7 @@ class UserEditComponent extends EditView {
1260
1738
  last_name: [''],
1261
1739
  phone: ['']
1262
1740
  });
1263
- constructor() {
1264
- super(inject(UserService));
1265
- }
1266
- ngOnInit() {
1267
- this.onInit();
1268
- }
1269
- onItemAvailable() {
1270
- const item = this.item();
1271
- if (!item) {
1272
- return;
1273
- }
1741
+ setValue(item) {
1274
1742
  this.form.setValue({
1275
1743
  username: item.username,
1276
1744
  email: item.email,
@@ -1278,31 +1746,55 @@ class UserEditComponent extends EditView {
1278
1746
  last_name: item.last_name,
1279
1747
  phone: item.phone
1280
1748
  });
1749
+ }
1750
+ createItem() {
1751
+ const value = this.form.value;
1752
+ return {
1753
+ username: value.username || "",
1754
+ email: value.email || "",
1755
+ first_name: value.first_name || "",
1756
+ last_name: value.last_name || "",
1757
+ phone: value.phone || ""
1758
+ };
1759
+ }
1760
+ updateItem(item) {
1761
+ const value = this.form.value;
1762
+ item.username = value.username || "";
1763
+ item.email = value.email || "";
1764
+ item.first_name = value.first_name || "";
1765
+ item.last_name = value.last_name || "";
1766
+ item.phone = value.phone || "";
1767
+ return item;
1768
+ }
1769
+ }
1770
+
1771
+ class UserEditComponent extends EditView {
1772
+ files = signal([new FileRecord({
1773
+ name: "image",
1774
+ display_name: "Profile Image",
1775
+ file_type: "image"
1776
+ })], ...(ngDevMode ? [{ debugName: "files" }] : []));
1777
+ constructor() {
1778
+ super(inject(UserService), new UserForm());
1779
+ }
1780
+ ngOnInit() {
1781
+ this.onInit();
1782
+ }
1783
+ onItemAvailable(item) {
1784
+ this.form.setValue(item);
1281
1785
  if (item.profile_url) {
1282
1786
  this.files.update(files => { const file = files.find(f => f.name === "image"); if (file) {
1283
1787
  file.remote = item.url + item.profile_url;
1284
1788
  } ; return files; });
1285
1789
  }
1286
- super.onItemAvailable();
1790
+ super.onItemAvailable(item);
1287
1791
  }
1288
1792
  submit() {
1289
1793
  this.item.update((item) => { if (item) {
1290
- item = this.updateFromForm(item);
1794
+ item = this.form.updateItem(item);
1291
1795
  } return item; });
1292
- console.log(this.item());
1293
1796
  super.submit();
1294
1797
  }
1295
- updateFromForm(item) {
1296
- item.username = this.form.value.username || "";
1297
- item.email = this.form.value.email || "";
1298
- item.first_name = this.form.value.first_name || "";
1299
- item.last_name = this.form.value.last_name || "";
1300
- item.phone = this.form.value.phone || "";
1301
- return item;
1302
- }
1303
- getTemplateItem() {
1304
- return new PortalMember();
1305
- }
1306
1798
  onPreviewLoaded(preview) {
1307
1799
  this.files.update(files => { const file = files.find(f => f.name === preview.name); if (file) {
1308
1800
  file.local = preview.content;
@@ -1319,7 +1811,7 @@ class UserEditComponent extends EditView {
1319
1811
  } ; });
1320
1812
  }
1321
1813
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: UserEditComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1322
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.1", type: UserEditComponent, isStandalone: true, selector: "lib-user-edit", usesInheritance: true, ngImport: i0, template: "<lib-back-button></lib-back-button>\n\n<div class=\"content-container\">\n\n @if(item(); as item){\n <div class=\"item-edit-container\">\n\n <h1 class=\"item-edit-header\">{{heading() | titlecase}}</h1>\n\n <form class=\"form-card\" [formGroup]=\"form\" (ngSubmit)=\"submit()\">\n <mat-form-field class=\"form-field-wide\">\n <mat-label>Username</mat-label>\n <input matInput\n placeholder=\"Username\"\n type=\"text\"\n formControlName=\"username\"\n name=\"username\">\n </mat-form-field>\n \n <mat-form-field class=\"form-field-wide\">\n <mat-label>Email</mat-label>\n <input matInput\n placeholder=\"Email\"\n type=\"text\"\n formControlName=\"email\"\n name=\"email\">\n </mat-form-field>\n\n <mat-form-field class=\"form-field\">\n <mat-label>First Name</mat-label>\n <input matInput\n placeholder=\"First Name\"\n type=\"text\"\n formControlName=\"first_name\"\n name=\"first_name\">\n </mat-form-field>\n \n <mat-form-field class=\"form-field\">\n <mat-label>Last Name</mat-label>\n <input matInput\n placeholder=\"Last Name\"\n type=\"text\"\n formControlName=\"last_name\"\n name=\"last_name\">\n </mat-form-field>\n\n <lib-file-upload [files]=\"files()\"\n (previewLoaded)=\"onPreviewLoaded($event)\"\n (fileUploaded)=\"onFileUploaded($event)\"></lib-file-upload>\n </form>\n\n <div class=\"button_group\">\n <button mat-fab\n class=\"form_action_button\"\n type=\"submit\"\n [disabled]=\"!form.valid\">\n <mat-icon>save</mat-icon></button>\n \n <button mat-fab\n class=\"form_action_button\"\n (click)=\"cancel()\">\n <mat-icon>cancel</mat-icon></button>\n </div>\n </div>\n }\n</div>\n", styles: [":host{flex-grow:1}.item_view{display:flex;justify-content:left;align-items:left;flex-direction:column}.checkbox_group{justify-content:left;display:flex;flex-direction:column}.button_group{margin:10px;display:flex;flex-direction:row;justify-content:center}.btn-block{padding:5px}.form_action_button{padding:5px;margin:5px}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2$1.MatFabButton, selector: "button[mat-fab], a[mat-fab], button[matFab], a[matFab]", inputs: ["extended"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: BackButtonComponent, selector: "lib-back-button" }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3$2.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "component", type: i3$1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3$1.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: FileUploadComponent, selector: "lib-file-upload", inputs: ["files"], outputs: ["previewLoaded", "fileUploaded", "clearLocal"] }, { kind: "pipe", type: TitleCasePipe, name: "titlecase" }] });
1814
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.1", type: UserEditComponent, isStandalone: true, selector: "lib-user-edit", usesInheritance: true, ngImport: i0, template: "<lib-back-button></lib-back-button>\n\n<div class=\"content-container\">\n\n <div class=\"item-edit-container\">\n\n <h1 class=\"item-edit-header\">{{heading() | titlecase}}</h1>\n\n <form class=\"form-card\" [formGroup]=\"form.form\" (ngSubmit)=\"submit()\">\n <mat-form-field class=\"form-field-wide\">\n <mat-label>Username</mat-label>\n <input matInput\n placeholder=\"Username\"\n type=\"text\"\n formControlName=\"username\"\n name=\"username\">\n </mat-form-field>\n \n <mat-form-field class=\"form-field-wide\">\n <mat-label>Email</mat-label>\n <input matInput\n placeholder=\"Email\"\n type=\"text\"\n formControlName=\"email\"\n name=\"email\">\n </mat-form-field>\n\n <mat-form-field class=\"form-field\">\n <mat-label>First Name</mat-label>\n <input matInput\n placeholder=\"First Name\"\n type=\"text\"\n formControlName=\"first_name\"\n name=\"first_name\">\n </mat-form-field>\n \n <mat-form-field class=\"form-field\">\n <mat-label>Last Name</mat-label>\n <input matInput\n placeholder=\"Last Name\"\n type=\"text\"\n formControlName=\"last_name\"\n name=\"last_name\">\n </mat-form-field>\n\n <lib-file-upload [files]=\"files()\"\n (previewLoaded)=\"onPreviewLoaded($event)\"\n (fileUploaded)=\"onFileUploaded($event)\"></lib-file-upload>\n\n <div class=\"button_group\">\n <button mat-fab\n class=\"form_action_button\"\n type=\"submit\"\n [disabled]=\"!form.form.valid\">\n <mat-icon>save</mat-icon></button>\n \n <button mat-fab\n class=\"form_action_button\"\n type=\"button\"\n (click)=\"cancel()\">\n <mat-icon>cancel</mat-icon></button>\n </div> \n </form>\n </div>\n</div>\n", styles: [":host{flex-grow:1}.item_view{display:flex;justify-content:left;align-items:left;flex-direction:column}.checkbox_group{justify-content:left;display:flex;flex-direction:column}.button_group{margin:10px;display:flex;flex-direction:row;justify-content:center}.btn-block{padding:5px}.form_action_button{padding:5px;margin:5px}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$3.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2$1.MatFabButton, selector: "button[mat-fab], a[mat-fab], button[matFab], a[matFab]", inputs: ["extended"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: BackButtonComponent, selector: "lib-back-button" }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "component", type: i2$3.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2$3.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: FileUploadComponent, selector: "lib-file-upload", inputs: ["files"], outputs: ["previewLoaded", "fileUploaded", "clearLocal"] }, { kind: "pipe", type: TitleCasePipe, name: "titlecase" }] });
1323
1815
  }
1324
1816
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: UserEditComponent, decorators: [{
1325
1817
  type: Component,
@@ -1332,13 +1824,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.1", ngImpor
1332
1824
  MatIconModule,
1333
1825
  FileUploadComponent,
1334
1826
  TitleCasePipe
1335
- ], template: "<lib-back-button></lib-back-button>\n\n<div class=\"content-container\">\n\n @if(item(); as item){\n <div class=\"item-edit-container\">\n\n <h1 class=\"item-edit-header\">{{heading() | titlecase}}</h1>\n\n <form class=\"form-card\" [formGroup]=\"form\" (ngSubmit)=\"submit()\">\n <mat-form-field class=\"form-field-wide\">\n <mat-label>Username</mat-label>\n <input matInput\n placeholder=\"Username\"\n type=\"text\"\n formControlName=\"username\"\n name=\"username\">\n </mat-form-field>\n \n <mat-form-field class=\"form-field-wide\">\n <mat-label>Email</mat-label>\n <input matInput\n placeholder=\"Email\"\n type=\"text\"\n formControlName=\"email\"\n name=\"email\">\n </mat-form-field>\n\n <mat-form-field class=\"form-field\">\n <mat-label>First Name</mat-label>\n <input matInput\n placeholder=\"First Name\"\n type=\"text\"\n formControlName=\"first_name\"\n name=\"first_name\">\n </mat-form-field>\n \n <mat-form-field class=\"form-field\">\n <mat-label>Last Name</mat-label>\n <input matInput\n placeholder=\"Last Name\"\n type=\"text\"\n formControlName=\"last_name\"\n name=\"last_name\">\n </mat-form-field>\n\n <lib-file-upload [files]=\"files()\"\n (previewLoaded)=\"onPreviewLoaded($event)\"\n (fileUploaded)=\"onFileUploaded($event)\"></lib-file-upload>\n </form>\n\n <div class=\"button_group\">\n <button mat-fab\n class=\"form_action_button\"\n type=\"submit\"\n [disabled]=\"!form.valid\">\n <mat-icon>save</mat-icon></button>\n \n <button mat-fab\n class=\"form_action_button\"\n (click)=\"cancel()\">\n <mat-icon>cancel</mat-icon></button>\n </div>\n </div>\n }\n</div>\n", styles: [":host{flex-grow:1}.item_view{display:flex;justify-content:left;align-items:left;flex-direction:column}.checkbox_group{justify-content:left;display:flex;flex-direction:column}.button_group{margin:10px;display:flex;flex-direction:row;justify-content:center}.btn-block{padding:5px}.form_action_button{padding:5px;margin:5px}\n"] }]
1827
+ ], template: "<lib-back-button></lib-back-button>\n\n<div class=\"content-container\">\n\n <div class=\"item-edit-container\">\n\n <h1 class=\"item-edit-header\">{{heading() | titlecase}}</h1>\n\n <form class=\"form-card\" [formGroup]=\"form.form\" (ngSubmit)=\"submit()\">\n <mat-form-field class=\"form-field-wide\">\n <mat-label>Username</mat-label>\n <input matInput\n placeholder=\"Username\"\n type=\"text\"\n formControlName=\"username\"\n name=\"username\">\n </mat-form-field>\n \n <mat-form-field class=\"form-field-wide\">\n <mat-label>Email</mat-label>\n <input matInput\n placeholder=\"Email\"\n type=\"text\"\n formControlName=\"email\"\n name=\"email\">\n </mat-form-field>\n\n <mat-form-field class=\"form-field\">\n <mat-label>First Name</mat-label>\n <input matInput\n placeholder=\"First Name\"\n type=\"text\"\n formControlName=\"first_name\"\n name=\"first_name\">\n </mat-form-field>\n \n <mat-form-field class=\"form-field\">\n <mat-label>Last Name</mat-label>\n <input matInput\n placeholder=\"Last Name\"\n type=\"text\"\n formControlName=\"last_name\"\n name=\"last_name\">\n </mat-form-field>\n\n <lib-file-upload [files]=\"files()\"\n (previewLoaded)=\"onPreviewLoaded($event)\"\n (fileUploaded)=\"onFileUploaded($event)\"></lib-file-upload>\n\n <div class=\"button_group\">\n <button mat-fab\n class=\"form_action_button\"\n type=\"submit\"\n [disabled]=\"!form.form.valid\">\n <mat-icon>save</mat-icon></button>\n \n <button mat-fab\n class=\"form_action_button\"\n type=\"button\"\n (click)=\"cancel()\">\n <mat-icon>cancel</mat-icon></button>\n </div> \n </form>\n </div>\n</div>\n", styles: [":host{flex-grow:1}.item_view{display:flex;justify-content:left;align-items:left;flex-direction:column}.checkbox_group{justify-content:left;display:flex;flex-direction:column}.button_group{margin:10px;display:flex;flex-direction:row;justify-content:center}.btn-block{padding:5px}.form_action_button{padding:5px;margin:5px}\n"] }]
1336
1828
  }], ctorParameters: () => [] });
1337
1829
 
1338
1830
  class UserListDetailComponent {
1339
1831
  item = input(...(ngDevMode ? [undefined, { debugName: "item" }] : []));
1340
1832
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: UserListDetailComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1341
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.1", type: UserListDetailComponent, isStandalone: true, selector: "lib-user-list-detail", inputs: { item: { classPropertyName: "item", publicName: "item", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<mat-card mat-list-item class=\"item-card\">\n @if(item(); as item){\n <mat-card-header>\n <mat-card-title-group style=\"padding: 5px\">\n <mat-card-title\n >{{ item.first_name }} {{ item.last_name }}</mat-card-title\n >\n <mat-card-subtitle>{{ item.username }}</mat-card-subtitle>\n </mat-card-title-group>\n </mat-card-header>\n\n <mat-card-content>\n <p>Email: {{ item.email }}</p>\n </mat-card-content>\n }\n</mat-card>\n", styles: [":host{flex-grow:1}.mat-mdc-row .mat-mdc-cell{border-bottom:1px solid transparent;border-top:1px solid transparent;cursor:pointer}.mat-mdc-row:hover .mat-mdc-cell{border-color:currentColor}.is-active{font-weight:700}\n"], dependencies: [{ kind: "ngmodule", type: MatListModule }, { kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i1$3.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: i1$3.MatCardContent, selector: "mat-card-content" }, { kind: "component", type: i1$3.MatCardHeader, selector: "mat-card-header" }, { kind: "directive", type: i1$3.MatCardSubtitle, selector: "mat-card-subtitle, [mat-card-subtitle], [matCardSubtitle]" }, { kind: "directive", type: i1$3.MatCardTitle, selector: "mat-card-title, [mat-card-title], [matCardTitle]" }, { kind: "component", type: i1$3.MatCardTitleGroup, selector: "mat-card-title-group" }] });
1833
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.1", type: UserListDetailComponent, isStandalone: true, selector: "lib-user-list-detail", inputs: { item: { classPropertyName: "item", publicName: "item", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<mat-card mat-list-item class=\"item-card\">\n @if(item(); as item){\n <mat-card-header>\n <mat-card-title-group style=\"padding: 5px\">\n <mat-card-title\n >{{ item.first_name }} {{ item.last_name }}</mat-card-title\n >\n <mat-card-subtitle>{{ item.username }}</mat-card-subtitle>\n </mat-card-title-group>\n </mat-card-header>\n\n <mat-card-content>\n <p>Email: {{ item.email }}</p>\n </mat-card-content>\n }\n</mat-card>\n", styles: [":host{flex-grow:1}.mat-mdc-row .mat-mdc-cell{border-bottom:1px solid transparent;border-top:1px solid transparent;cursor:pointer}.mat-mdc-row:hover .mat-mdc-cell{border-color:currentColor}.is-active{font-weight:700}\n"], dependencies: [{ kind: "ngmodule", type: MatListModule }, { kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i1$4.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: i1$4.MatCardContent, selector: "mat-card-content" }, { kind: "component", type: i1$4.MatCardHeader, selector: "mat-card-header" }, { kind: "directive", type: i1$4.MatCardSubtitle, selector: "mat-card-subtitle, [mat-card-subtitle], [matCardSubtitle]" }, { kind: "directive", type: i1$4.MatCardTitle, selector: "mat-card-title, [mat-card-title], [matCardTitle]" }, { kind: "component", type: i1$4.MatCardTitleGroup, selector: "mat-card-title-group" }] });
1342
1834
  }
1343
1835
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: UserListDetailComponent, decorators: [{
1344
1836
  type: Component,
@@ -1346,13 +1838,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.1", ngImpor
1346
1838
  MatCardModule], template: "<mat-card mat-list-item class=\"item-card\">\n @if(item(); as item){\n <mat-card-header>\n <mat-card-title-group style=\"padding: 5px\">\n <mat-card-title\n >{{ item.first_name }} {{ item.last_name }}</mat-card-title\n >\n <mat-card-subtitle>{{ item.username }}</mat-card-subtitle>\n </mat-card-title-group>\n </mat-card-header>\n\n <mat-card-content>\n <p>Email: {{ item.email }}</p>\n </mat-card-content>\n }\n</mat-card>\n", styles: [":host{flex-grow:1}.mat-mdc-row .mat-mdc-cell{border-bottom:1px solid transparent;border-top:1px solid transparent;cursor:pointer}.mat-mdc-row:hover .mat-mdc-cell{border-color:currentColor}.is-active{font-weight:700}\n"] }]
1347
1839
  }] });
1348
1840
 
1349
- const USER_TABLE_FULL = [
1350
- { name: 'first_name', title: 'First Name', element_type: 'string' },
1351
- { name: 'last_name', title: 'Surname', element_type: 'string' },
1352
- { name: 'username', title: 'Username', element_type: 'string' },
1353
- { name: 'email', title: 'Email', element_type: 'email' }
1354
- ];
1355
-
1356
1841
  class UserComponent {
1357
1842
  viewType = signal("list", ...(ngDevMode ? [{ debugName: "viewType" }] : []));
1358
1843
  itemService = inject(UserService);
@@ -1396,7 +1881,7 @@ class AddressEditComponent {
1396
1881
  countryOptions = input([], ...(ngDevMode ? [{ debugName: "countryOptions" }] : []));
1397
1882
  form = input(...(ngDevMode ? [undefined, { debugName: "form" }] : []));
1398
1883
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: AddressEditComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1399
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.1", type: AddressEditComponent, isStandalone: true, selector: "lib-address-edit", inputs: { countryOptions: { classPropertyName: "countryOptions", publicName: "countryOptions", isSignal: true, isRequired: false, transformFunction: null }, form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if(form(); as form){\n<div [formGroup]=\"form\" style=\"display: flex; flex-direction: column; width:100%\">\n <mat-form-field class=\"form-field-wide\">\n <mat-label for=\"line1\">Line 1</mat-label>\n <input matInput placeholder=\"Address Line 1\" type=\"text\" id=\"line1\" formControlName=\"line1\" name=\"line1\"\n required>\n </mat-form-field>\n\n <mat-form-field class=\"form-field-wide\">\n <mat-label for=\"line2\">Line 2</mat-label>\n <input matInput placeholder=\"Address Line 2\" type=\"text\" id=\"line2\" formControlName=\"line2\" name=\"line1\">\n </mat-form-field>\n\n <mat-form-field class=\"form-field-wide\">\n <mat-label for=\"line3\">Line 3</mat-label>\n <input matInput placeholder=\"Address Line 3\" type=\"text\" id=\"line3\" formControlName=\"line3\" name=\"line3\">\n </mat-form-field>\n\n <mat-form-field class=\"form-field\">\n <mat-label for=\"city\">City</mat-label>\n <input matInput placeholder=\"City\" type=\"text\" id=\"city\" formControlName=\"city\" name=\"city\">\n </mat-form-field>\n\n <mat-form-field class=\"form-field\">\n <mat-label for=\"region\">Region</mat-label>\n <input matInput placeholder=\"Region\" type=\"text\" id=\"region\" formControlName=\"region\" name=\"region\" required>\n </mat-form-field>\n\n <mat-form-field class=\"form-field\">\n <mat-label for=\"line1\">Post Code</mat-label>\n <input matInput placeholder=\"Post Code\" type=\"text\" id=\"postcode\" formControlName=\"postcode\" name=\"postcode\">\n </mat-form-field>\n\n <mat-form-field class=\"form-field\">\n <mat-label for=\"country\">Country</mat-label>\n <mat-select formControlName=\"country\" name=\"country\" id=\"country\" required>\n @for(country of countryOptions(); track $index){\n <mat-option [value]=\"country.code\">{{country.name}}</mat-option>\n }\n </mat-select>\n </mat-form-field>\n</div>\n}", styles: [""], dependencies: [{ kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i3$1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3$1.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i6.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i6.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3$2.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }] });
1884
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.1", type: AddressEditComponent, isStandalone: true, selector: "lib-address-edit", inputs: { countryOptions: { classPropertyName: "countryOptions", publicName: "countryOptions", isSignal: true, isRequired: false, transformFunction: null }, form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if(form(); as form){\n<div [formGroup]=\"form\" style=\"display: flex; flex-direction: column; width:100%\">\n <mat-form-field class=\"form-field-wide\">\n <mat-label for=\"line1\">Line 1</mat-label>\n <input matInput placeholder=\"Address Line 1\" type=\"text\" id=\"line1\" formControlName=\"line1\" name=\"line1\"\n required>\n </mat-form-field>\n\n <mat-form-field class=\"form-field-wide\">\n <mat-label for=\"line2\">Line 2</mat-label>\n <input matInput placeholder=\"Address Line 2\" type=\"text\" id=\"line2\" formControlName=\"line2\" name=\"line1\">\n </mat-form-field>\n\n <mat-form-field class=\"form-field-wide\">\n <mat-label for=\"line3\">Line 3</mat-label>\n <input matInput placeholder=\"Address Line 3\" type=\"text\" id=\"line3\" formControlName=\"line3\" name=\"line3\">\n </mat-form-field>\n\n <mat-form-field class=\"form-field\">\n <mat-label for=\"city\">City</mat-label>\n <input matInput placeholder=\"City\" type=\"text\" id=\"city\" formControlName=\"city\" name=\"city\">\n </mat-form-field>\n\n <mat-form-field class=\"form-field\">\n <mat-label for=\"region\">Region</mat-label>\n <input matInput placeholder=\"Region\" type=\"text\" id=\"region\" formControlName=\"region\" name=\"region\" required>\n </mat-form-field>\n\n <mat-form-field class=\"form-field\">\n <mat-label for=\"line1\">Post Code</mat-label>\n <input matInput placeholder=\"Post Code\" type=\"text\" id=\"postcode\" formControlName=\"postcode\" name=\"postcode\">\n </mat-form-field>\n\n <mat-form-field class=\"form-field\">\n <mat-label for=\"country\">Country</mat-label>\n <mat-select formControlName=\"country\" name=\"country\" id=\"country\" required>\n @for(country of countryOptions(); track $index){\n <mat-option [value]=\"country.code\">{{country.name}}</mat-option>\n }\n </mat-select>\n </mat-form-field>\n</div>\n}", styles: [""], dependencies: [{ kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i2$3.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2$3.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i6.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i6.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$3.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$3.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }] });
1400
1885
  }
1401
1886
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: AddressEditComponent, decorators: [{
1402
1887
  type: Component,
@@ -1439,6 +1924,16 @@ class AddressForm {
1439
1924
  country: item.country
1440
1925
  });
1441
1926
  }
1927
+ createItem() {
1928
+ const value = this.form.value;
1929
+ return { line1: value.line1 || "",
1930
+ line2: value.line2 || null,
1931
+ line3: value.line3 || null,
1932
+ city: value.city || null,
1933
+ region: value.region || "",
1934
+ postcode: value.postcode || null,
1935
+ country: value.country || "" };
1936
+ }
1442
1937
  updateItem(item) {
1443
1938
  const value = this.form.value;
1444
1939
  item.line1 = value.line1 || "";
@@ -1468,63 +1963,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.1", ngImpor
1468
1963
  }] });
1469
1964
 
1470
1965
  class OrganizationDetailComponent extends DetailView {
1471
- address = signal(null, ...(ngDevMode ? [{ debugName: "address" }] : []));
1472
- addressService = inject(AddressService);
1473
1966
  constructor() {
1474
1967
  super(inject(OrganizationService));
1475
1968
  }
1476
1969
  ngOnInit() {
1477
1970
  this.onInit();
1478
1971
  }
1479
- onItemAndUserAvailable(item, _user) {
1480
- this.addressService.getUrl(item.address).subscribe(address => this.address.set(address));
1481
- }
1482
1972
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: OrganizationDetailComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1483
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.1", type: OrganizationDetailComponent, isStandalone: true, selector: "lib-organization-detail", usesInheritance: true, ngImport: i0, template: "<lib-back-button></lib-back-button>\n\n<div class=\"content-container\">\n\n @if(item(); as item){\n <div class=\"item-detail-container\">\n\n <lib-detail-header\n [text]=\"item.name\"\n [id]=\"item.id\"\n [canEdit]=\"itemService.canEdit()\"\n [canDelete]=\"itemService.canDelete()\"\n [route]=\"itemService.typePlural()\"></lib-detail-header>\n\n <div class=\"item-field\">\n {{item.description}}\n </div>\n \n @if(address(); as address)\n {\n <h3>Address</h3>\n <lib-address-detail [address]=\"address\"></lib-address-detail>\n }\n <div class=\"item-field\">\n <h3>Website</h3>{{item.website}}\n </div>\n </div>\n }\n</div>\n", styles: [":host{flex-grow:1}.padded_button{padding:5px}\n"], dependencies: [{ kind: "component", type: BackButtonComponent, selector: "lib-back-button" }, { kind: "component", type: DetailHeaderComponent, selector: "lib-detail-header", inputs: ["id", "text", "route", "canEdit", "canDelete"], outputs: ["deleteClicked"] }, { kind: "component", type: AddressDetailComponent, selector: "lib-address-detail", inputs: ["address"] }] });
1973
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.1", type: OrganizationDetailComponent, isStandalone: true, selector: "lib-organization-detail", usesInheritance: true, ngImport: i0, template: "<lib-back-button></lib-back-button>\n\n<div class=\"content-container\">\n\n @if(item(); as item){\n <div class=\"item-detail-container\">\n\n <lib-detail-header\n [text]=\"item.name\"\n [id]=\"item.id\"\n [canEdit]=\"itemService.canEdit()\"\n [canDelete]=\"itemService.canDelete()\"\n [route]=\"itemService.typePlural()\"></lib-detail-header>\n\n <div class=\"item-field\">\n {{item.description}}\n </div>\n \n <h3>Address</h3>\n <lib-address-detail [address]=\"item.address\"></lib-address-detail>\n\n <div class=\"item-field\">\n <h3>Website</h3>{{item.website}}\n </div>\n </div>\n }\n</div>\n", styles: [":host{flex-grow:1}.padded_button{padding:5px}\n"], dependencies: [{ kind: "component", type: BackButtonComponent, selector: "lib-back-button" }, { kind: "component", type: DetailHeaderComponent, selector: "lib-detail-header", inputs: ["id", "text", "route", "canEdit", "canDelete"], outputs: ["deleteClicked"] }, { kind: "component", type: AddressDetailComponent, selector: "lib-address-detail", inputs: ["address"] }] });
1484
1974
  }
1485
1975
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: OrganizationDetailComponent, decorators: [{
1486
1976
  type: Component,
1487
1977
  args: [{ selector: 'lib-organization-detail', imports: [BackButtonComponent,
1488
- DetailHeaderComponent, AddressDetailComponent], template: "<lib-back-button></lib-back-button>\n\n<div class=\"content-container\">\n\n @if(item(); as item){\n <div class=\"item-detail-container\">\n\n <lib-detail-header\n [text]=\"item.name\"\n [id]=\"item.id\"\n [canEdit]=\"itemService.canEdit()\"\n [canDelete]=\"itemService.canDelete()\"\n [route]=\"itemService.typePlural()\"></lib-detail-header>\n\n <div class=\"item-field\">\n {{item.description}}\n </div>\n \n @if(address(); as address)\n {\n <h3>Address</h3>\n <lib-address-detail [address]=\"address\"></lib-address-detail>\n }\n <div class=\"item-field\">\n <h3>Website</h3>{{item.website}}\n </div>\n </div>\n }\n</div>\n", styles: [":host{flex-grow:1}.padded_button{padding:5px}\n"] }]
1978
+ DetailHeaderComponent, AddressDetailComponent], template: "<lib-back-button></lib-back-button>\n\n<div class=\"content-container\">\n\n @if(item(); as item){\n <div class=\"item-detail-container\">\n\n <lib-detail-header\n [text]=\"item.name\"\n [id]=\"item.id\"\n [canEdit]=\"itemService.canEdit()\"\n [canDelete]=\"itemService.canDelete()\"\n [route]=\"itemService.typePlural()\"></lib-detail-header>\n\n <div class=\"item-field\">\n {{item.description}}\n </div>\n \n <h3>Address</h3>\n <lib-address-detail [address]=\"item.address\"></lib-address-detail>\n\n <div class=\"item-field\">\n <h3>Website</h3>{{item.website}}\n </div>\n </div>\n }\n</div>\n", styles: [":host{flex-grow:1}.padded_button{padding:5px}\n"] }]
1489
1979
  }], ctorParameters: () => [] });
1490
1980
 
1491
- class SelectionManager {
1492
- candidates = signal([], ...(ngDevMode ? [{ debugName: "candidates" }] : []));
1493
- selected = signal([], ...(ngDevMode ? [{ debugName: "selected" }] : []));
1494
- columns = USER_TABLE_FULL;
1495
- userService = inject(UserService);
1496
- fetchCandidates(item, id) {
1497
- const queries = new Map([[item, id.toString()]]);
1498
- const query = new ItemQuery({ queries: queries });
1499
- this.userService.get(query).subscribe(users => this.selected.set(users.results));
1500
- this.userService.get().subscribe(users => this.updateCandidates(users));
1501
- }
1502
- updateCandidates(users) {
1503
- this.candidates.set(users.results.map(user => { return { title: user.username, item: user }; }));
1504
- }
1505
- onRemoved(id) {
1506
- const url = this.selected().find(m => m.id == id).url;
1507
- this.selected.update(members => members.filter(m => m.id != id));
1508
- return url;
1509
- }
1510
- onAdded(title) {
1511
- const selected = this.candidates().find(m => m.title == title);
1512
- if (selected) {
1513
- this.selected.update(members => { members.push(selected.item); return members; });
1514
- }
1515
- this.candidates.update(members => members.filter(m => m.title != title));
1516
- return this.selected().find(m => m.username == title).url;
1517
- }
1518
- onSearchChanged(searchTerm) {
1519
- if (searchTerm) {
1520
- this.userService.get(new ItemQuery({ filter: searchTerm })).subscribe(users => this.updateCandidates(users));
1521
- }
1522
- else {
1523
- this.userService.get().subscribe(users => this.updateCandidates(users));
1524
- }
1525
- }
1526
- }
1527
-
1528
1981
  class OrganizationForm {
1529
1982
  formBuilder = inject(FormBuilder);
1530
1983
  form;
@@ -1538,7 +1991,8 @@ class OrganizationForm {
1538
1991
  address: [this.address.form]
1539
1992
  });
1540
1993
  }
1541
- updateFromItem(item) {
1994
+ setValue(item) {
1995
+ this.address.setValue(item.address);
1542
1996
  this.form.setValue({
1543
1997
  name: item.name,
1544
1998
  acronym: item.acronym,
@@ -1547,75 +2001,54 @@ class OrganizationForm {
1547
2001
  address: this.address.form
1548
2002
  });
1549
2003
  }
2004
+ createItem() {
2005
+ const value = this.form.value;
2006
+ return {
2007
+ name: value.name || "",
2008
+ acronym: value.acronym || "",
2009
+ description: value.description || "",
2010
+ website: value.website || "",
2011
+ address: this.address.createItem(),
2012
+ members: []
2013
+ };
2014
+ }
1550
2015
  updateItem(item) {
1551
2016
  item.name = this.form.value.name || "";
1552
2017
  item.acronym = this.form.value.acronym || "";
1553
2018
  item.description = this.form.value.description || "";
1554
2019
  item.website = this.form.value.website || "";
2020
+ item.address = this.address.updateItem(item.address);
1555
2021
  return item;
1556
2022
  }
1557
2023
  }
1558
2024
 
1559
2025
  class OrganizationEditComponent extends EditView {
1560
2026
  countryOptions = signal([], ...(ngDevMode ? [{ debugName: "countryOptions" }] : []));
1561
- selectionManager = new SelectionManager();
1562
- form = new OrganizationForm();
1563
- address = new Address();
1564
2027
  addressService = inject(AddressService);
2028
+ selectionManager = new SelectionManager();
1565
2029
  constructor() {
1566
- super(inject(OrganizationService));
2030
+ super(inject(OrganizationService), new OrganizationForm());
1567
2031
  }
1568
2032
  ngOnInit() {
1569
2033
  this.onInit();
1570
2034
  this.addressService.getOptions().subscribe(options => this.onOptions(options));
1571
2035
  }
1572
- onItemAndUserAvailable(_) {
1573
- const item = this.item();
1574
- if (item) {
1575
- this.fetchAddress(item.address);
1576
- this.form.updateFromItem(item);
1577
- this.selectionManager.fetchCandidates(this.itemService.typename, item.id);
1578
- }
1579
- }
1580
- submit() {
1581
- this.syncFromForm();
1582
- if (this.createMode()) {
1583
- this.createAddress().subscribe(_ => super.submit());
1584
- }
1585
- else {
1586
- this.updateAddress();
1587
- super.submit();
1588
- }
1589
- }
1590
- fetchAddress(url) {
1591
- if (url) {
1592
- this.addressService.getUrl(url).subscribe(address => this.onAddressUpdated(address));
1593
- }
1594
- }
1595
- updateAddress() {
1596
- this.addressService.putItem(this.address).subscribe(address => this.onAddressUpdated(address));
1597
- }
1598
- createAddress() {
1599
- return this.addressService.postItem(this.address).pipe(tap(address => { this.onAddressCreated(address); }));
2036
+ addressForm() {
2037
+ return this.form.address.form;
1600
2038
  }
1601
- onAddressUpdated(address) {
1602
- this.address = address;
1603
- this.form.address.setValue(this.address);
1604
- }
1605
- onAddressCreated(address) {
1606
- this.onAddressUpdated(address);
1607
- this.item.update(item => { if (item) {
1608
- item.address = address.url;
1609
- } return item; });
2039
+ createItem() {
2040
+ const item = this.form.createItem();
2041
+ item.members = this.selectionManager.selected().map(m => m.url);
2042
+ return item;
1610
2043
  }
1611
- syncFromForm() {
1612
- this.address = this.form.address.updateItem(this.address);
1613
- this.item.update((item) => { if (item) {
1614
- item = this.form.updateItem(item);
1615
- } return item; });
2044
+ updateItem(item) {
2045
+ item = this.form.updateItem(item);
2046
+ item.members = this.selectionManager.selected().map(m => m.url);
2047
+ return item;
1616
2048
  }
1617
- getTemplateItem() {
1618
- return new Organization();
2049
+ onItemAndUserAvailable(item, _) {
2050
+ this.form.setValue(item);
2051
+ this.selectionManager.fetchCandidates(this.itemService.typename, item.id);
1619
2052
  }
1620
2053
  onPostActions(actions) {
1621
2054
  if ('country' in actions && actions['country'].choices) {
@@ -1625,24 +2058,8 @@ class OrganizationEditComponent extends EditView {
1625
2058
  onCountryChoices(choices) {
1626
2059
  this.countryOptions.update(() => choices.map(c => { return { name: c.display_name, code: c.value, flag: "" }; }));
1627
2060
  }
1628
- addMember(url) {
1629
- this.item.update(item => { if (item) {
1630
- item.members.push(url);
1631
- } return item; });
1632
- }
1633
- removeMember(url) {
1634
- this.item.update(item => { if (item) {
1635
- item.members.filter(m => m != url);
1636
- } return item; });
1637
- }
1638
- onMemberRemoved(id) {
1639
- this.removeMember(this.selectionManager.onRemoved(id));
1640
- }
1641
- onMemberAdded(title) {
1642
- this.addMember(this.selectionManager.onAdded(title));
1643
- }
1644
2061
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: OrganizationEditComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1645
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.1", type: OrganizationEditComponent, isStandalone: true, selector: "lib-organization-edit", usesInheritance: true, ngImport: i0, template: "<lib-back-button></lib-back-button>\n\n<div class=\"content-container\">\n\n @if(item(); as item){\n <div class=\"item-edit-container\">\n \n <h1 class=\"item-edit-header\">{{heading() | titlecase}}</h1>\n\n <form class=\"form-card\" [formGroup]=\"form.form\" (ngSubmit)=\"submit()\">\n\n <mat-form-field class=\"form-field-wide\">\n <mat-label for=\"name\">Name</mat-label>\n <input matInput placeholder=\"Name\"\n type=\"text\"\n id=\"name\"\n formControlName=\"name\"\n name=\"name\"\n required>\n </mat-form-field>\n \n <mat-form-field class=\"form-field\">\n <mat-label for=\"acronym\">Acronym</mat-label> \n <input matInput placeholder=\"Acronym\"\n type=\"text\"\n id=\"acronym\"\n formControlName=\"acronym\"\n name=\"acronym\">\n </mat-form-field>\n \n <mat-form-field class=\"form-field-wide\">\n <mat-label for=\"description\">Description</mat-label>\n <textarea matInput placeholder=\"Description\"\n type=\"text\"\n id=\"description\"\n formControlName=\"description\"\n name=\"description\"\n class=\"medium-textarea\"\n required></textarea>\n </mat-form-field>\n\n <h3>Address</h3>\n <lib-address-edit \n [countryOptions]=\"countryOptions()\"\n [form]=\"form.address.form\"\n ></lib-address-edit>\n\n <h3>Members</h3>\n <lib-select-table [selected]=\"selectionManager.selected()\"\n [itemType]=\"'Members'\"\n [columns]=\"selectionManager.columns\"\n [options]=\"selectionManager.candidates()\"\n (itemAdded)=\"onMemberAdded($event)\"\n (itemRemoved)=\"onMemberRemoved($event)\"\n (searchChanged)=\"selectionManager.onSearchChanged($event)\">\n </lib-select-table>\n\n </form>\n <div class=\"button_group\">\n <button mat-fab\n class=\"form_action_button\"\n type=\"submit\"\n [disabled]=\"!form.form.valid\">\n <mat-icon>save</mat-icon>\n </button>\n \n <button mat-fab\n class=\"form_action_button\"\n (click)=\"cancel()\">\n <mat-icon>cancel</mat-icon>\n </button>\n </div>\n\n </div>\n }\n</div>\n", styles: [":host{flex-grow:1}.medium-textarea{min-height:150px}.checkbox_group{justify-content:left;display:flex;flex-direction:column}.button_group{margin:10px;display:flex;flex-direction:row;justify-content:center}.btn-block{padding:5px}.form_action_button{padding:5px;margin:5px}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2$1.MatFabButton, selector: "button[mat-fab], a[mat-fab], button[matFab], a[matFab]", inputs: ["extended"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3$2.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "component", type: i3$1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3$1.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatSelectModule }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: BackButtonComponent, selector: "lib-back-button" }, { kind: "component", type: AddressEditComponent, selector: "lib-address-edit", inputs: ["countryOptions", "form"] }, { kind: "component", type: SelectTableComponent, selector: "lib-select-table", inputs: ["itemType", "selected", "options", "columns"], outputs: ["itemAdded", "itemRemoved", "searchChanged"] }, { kind: "pipe", type: TitleCasePipe, name: "titlecase" }] });
2062
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.1", type: OrganizationEditComponent, isStandalone: true, selector: "lib-organization-edit", usesInheritance: true, ngImport: i0, template: "<lib-back-button></lib-back-button>\n\n<div class=\"content-container\">\n\n <div class=\"item-edit-container\">\n \n <h1 class=\"item-edit-header\">{{heading() | titlecase}}</h1>\n\n <form class=\"form-card\" [formGroup]=\"form.form\" (ngSubmit)=\"submit()\">\n\n <mat-form-field class=\"form-field-wide\">\n <mat-label for=\"name\">Name</mat-label>\n <input matInput placeholder=\"Name\"\n type=\"text\"\n id=\"name\"\n formControlName=\"name\"\n name=\"name\"\n required>\n </mat-form-field>\n \n <mat-form-field class=\"form-field\">\n <mat-label for=\"acronym\">Acronym</mat-label> \n <input matInput placeholder=\"Acronym\"\n type=\"text\"\n id=\"acronym\"\n formControlName=\"acronym\"\n name=\"acronym\">\n </mat-form-field>\n \n <mat-form-field class=\"form-field-wide\">\n <mat-label for=\"description\">Description</mat-label>\n <textarea matInput placeholder=\"Description\"\n type=\"text\"\n id=\"description\"\n formControlName=\"description\"\n name=\"description\"\n class=\"medium-textarea\"\n required></textarea>\n </mat-form-field>\n\n <h3>Address</h3>\n <lib-address-edit \n [countryOptions]=\"countryOptions()\"\n [form]=\"addressForm()\"\n ></lib-address-edit>\n\n <h3>Members</h3>\n <lib-select-table [selected]=\"selectionManager.selected()\"\n [itemType]=\"'Members'\"\n [columns]=\"selectionManager.columns\"\n [options]=\"selectionManager.candidates()\"\n (itemAdded)=\"selectionManager.onAdded($event)\"\n (itemRemoved)=\"selectionManager.onRemoved($event)\"\n (searchChanged)=\"selectionManager.onSearchChanged($event)\">\n </lib-select-table>\n\n <div class=\"button_group\">\n <button mat-fab\n class=\"form_action_button\"\n type=\"submit\"\n [disabled]=\"!form.form.valid\">\n <mat-icon>save</mat-icon>\n </button>\n \n <button mat-fab\n type=\"button\"\n class=\"form_action_button\"\n (click)=\"cancel()\">\n <mat-icon>cancel</mat-icon>\n </button>\n </div>\n </form>\n </div>\n</div>\n", styles: [":host{flex-grow:1}.medium-textarea{min-height:150px}.checkbox_group{justify-content:left;display:flex;flex-direction:column}.button_group{margin:10px;display:flex;flex-direction:row;justify-content:center}.btn-block{padding:5px}.form_action_button{padding:5px;margin:5px}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$3.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$3.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2$1.MatFabButton, selector: "button[mat-fab], a[mat-fab], button[matFab], a[matFab]", inputs: ["extended"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "component", type: i2$3.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2$3.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatSelectModule }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: BackButtonComponent, selector: "lib-back-button" }, { kind: "component", type: AddressEditComponent, selector: "lib-address-edit", inputs: ["countryOptions", "form"] }, { kind: "component", type: SelectTableComponent, selector: "lib-select-table", inputs: ["itemType", "selected", "options", "columns"], outputs: ["itemAdded", "itemRemoved", "searchChanged"] }, { kind: "pipe", type: TitleCasePipe, name: "titlecase" }] });
1646
2063
  }
1647
2064
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.1", ngImport: i0, type: OrganizationEditComponent, decorators: [{
1648
2065
  type: Component,
@@ -1658,7 +2075,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.1", ngImpor
1658
2075
  AddressEditComponent,
1659
2076
  SelectTableComponent,
1660
2077
  TitleCasePipe
1661
- ], template: "<lib-back-button></lib-back-button>\n\n<div class=\"content-container\">\n\n @if(item(); as item){\n <div class=\"item-edit-container\">\n \n <h1 class=\"item-edit-header\">{{heading() | titlecase}}</h1>\n\n <form class=\"form-card\" [formGroup]=\"form.form\" (ngSubmit)=\"submit()\">\n\n <mat-form-field class=\"form-field-wide\">\n <mat-label for=\"name\">Name</mat-label>\n <input matInput placeholder=\"Name\"\n type=\"text\"\n id=\"name\"\n formControlName=\"name\"\n name=\"name\"\n required>\n </mat-form-field>\n \n <mat-form-field class=\"form-field\">\n <mat-label for=\"acronym\">Acronym</mat-label> \n <input matInput placeholder=\"Acronym\"\n type=\"text\"\n id=\"acronym\"\n formControlName=\"acronym\"\n name=\"acronym\">\n </mat-form-field>\n \n <mat-form-field class=\"form-field-wide\">\n <mat-label for=\"description\">Description</mat-label>\n <textarea matInput placeholder=\"Description\"\n type=\"text\"\n id=\"description\"\n formControlName=\"description\"\n name=\"description\"\n class=\"medium-textarea\"\n required></textarea>\n </mat-form-field>\n\n <h3>Address</h3>\n <lib-address-edit \n [countryOptions]=\"countryOptions()\"\n [form]=\"form.address.form\"\n ></lib-address-edit>\n\n <h3>Members</h3>\n <lib-select-table [selected]=\"selectionManager.selected()\"\n [itemType]=\"'Members'\"\n [columns]=\"selectionManager.columns\"\n [options]=\"selectionManager.candidates()\"\n (itemAdded)=\"onMemberAdded($event)\"\n (itemRemoved)=\"onMemberRemoved($event)\"\n (searchChanged)=\"selectionManager.onSearchChanged($event)\">\n </lib-select-table>\n\n </form>\n <div class=\"button_group\">\n <button mat-fab\n class=\"form_action_button\"\n type=\"submit\"\n [disabled]=\"!form.form.valid\">\n <mat-icon>save</mat-icon>\n </button>\n \n <button mat-fab\n class=\"form_action_button\"\n (click)=\"cancel()\">\n <mat-icon>cancel</mat-icon>\n </button>\n </div>\n\n </div>\n }\n</div>\n", styles: [":host{flex-grow:1}.medium-textarea{min-height:150px}.checkbox_group{justify-content:left;display:flex;flex-direction:column}.button_group{margin:10px;display:flex;flex-direction:row;justify-content:center}.btn-block{padding:5px}.form_action_button{padding:5px;margin:5px}\n"] }]
2078
+ ], template: "<lib-back-button></lib-back-button>\n\n<div class=\"content-container\">\n\n <div class=\"item-edit-container\">\n \n <h1 class=\"item-edit-header\">{{heading() | titlecase}}</h1>\n\n <form class=\"form-card\" [formGroup]=\"form.form\" (ngSubmit)=\"submit()\">\n\n <mat-form-field class=\"form-field-wide\">\n <mat-label for=\"name\">Name</mat-label>\n <input matInput placeholder=\"Name\"\n type=\"text\"\n id=\"name\"\n formControlName=\"name\"\n name=\"name\"\n required>\n </mat-form-field>\n \n <mat-form-field class=\"form-field\">\n <mat-label for=\"acronym\">Acronym</mat-label> \n <input matInput placeholder=\"Acronym\"\n type=\"text\"\n id=\"acronym\"\n formControlName=\"acronym\"\n name=\"acronym\">\n </mat-form-field>\n \n <mat-form-field class=\"form-field-wide\">\n <mat-label for=\"description\">Description</mat-label>\n <textarea matInput placeholder=\"Description\"\n type=\"text\"\n id=\"description\"\n formControlName=\"description\"\n name=\"description\"\n class=\"medium-textarea\"\n required></textarea>\n </mat-form-field>\n\n <h3>Address</h3>\n <lib-address-edit \n [countryOptions]=\"countryOptions()\"\n [form]=\"addressForm()\"\n ></lib-address-edit>\n\n <h3>Members</h3>\n <lib-select-table [selected]=\"selectionManager.selected()\"\n [itemType]=\"'Members'\"\n [columns]=\"selectionManager.columns\"\n [options]=\"selectionManager.candidates()\"\n (itemAdded)=\"selectionManager.onAdded($event)\"\n (itemRemoved)=\"selectionManager.onRemoved($event)\"\n (searchChanged)=\"selectionManager.onSearchChanged($event)\">\n </lib-select-table>\n\n <div class=\"button_group\">\n <button mat-fab\n class=\"form_action_button\"\n type=\"submit\"\n [disabled]=\"!form.form.valid\">\n <mat-icon>save</mat-icon>\n </button>\n \n <button mat-fab\n type=\"button\"\n class=\"form_action_button\"\n (click)=\"cancel()\">\n <mat-icon>cancel</mat-icon>\n </button>\n </div>\n </form>\n </div>\n</div>\n", styles: [":host{flex-grow:1}.medium-textarea{min-height:150px}.checkbox_group{justify-content:left;display:flex;flex-direction:column}.button_group{margin:10px;display:flex;flex-direction:row;justify-content:center}.btn-block{padding:5px}.form_action_button{padding:5px;margin:5px}\n"] }]
1662
2079
  }], ctorParameters: () => [] });
1663
2080
 
1664
2081
  /*
@@ -1669,5 +2086,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.1", ngImpor
1669
2086
  * Generated bundle index. Do not edit.
1670
2087
  */
1671
2088
 
1672
- export { Address, AddressDetailComponent, AddressEditComponent, AddressForm, AddressService, ApiError, AvatarComponent, BackButtonComponent, DetailHeaderComponent, DetailView, ENDPOINT_URL, EditView, ErrorCode, FeedbackComponent, FileRecord, FileUploadComponent, Group, GroupComponent, GroupDetailComponent, GroupService, ItemQuery, ItemService, ItemWithUserService, LOGIN_USER, LandingComponent, LeftNavComponent, LeftNavService, ListTableViewComponent, ListViewComponent, MockItemService, Organization, OrganizationComponent, OrganizationDetailComponent, OrganizationEditComponent, OrganizationService, Paginated, Permission, PortalMember, ResolvedPermission, RestService, SearchBarComponent, SelectTableComponent, TopBarComponent, UserComponent, UserDetailComponent, UserEditComponent, UserService };
2089
+ export { Address, AddressDetailComponent, AddressEditComponent, AddressForm, AddressService, ApiError, AvatarComponent, BackButtonComponent, DetailHeaderComponent, DetailView, DynamicFormBuilderComponent, DynamicFormComponent, DynamicFormForm, ENDPOINT_URL, EditView, ErrorCode, FORM_FIELD_CHOICES, FeedbackComponent, FileRecord, FileUploadComponent, FormFieldDetailComponent, FormFieldEditComponent, FormFieldListComponent, FormService, Group, GroupComponent, GroupDetailComponent, GroupService, ItemQuery, ItemService, ItemWithUserService, LOGIN_USER, LandingComponent, LeftNavComponent, LeftNavService, ListTableViewComponent, ListViewComponent, MockItemService, Organization, OrganizationComponent, OrganizationDetailComponent, OrganizationEditComponent, OrganizationService, Paginated, Permission, PortalMember, ResolvedPermission, RestService, SearchBarComponent, SelectTableComponent, SelectionManager, TopBarComponent, UserComponent, UserDetailComponent, UserEditComponent, UserService };
1673
2090
  //# sourceMappingURL=ichec-angular-core.mjs.map