ichec-angular-core 0.3.9 → 0.3.11

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.
@@ -1,4 +1,4 @@
1
- import { BehaviorSubject, map, catchError, mergeMap, throwError, tap, of, debounceTime, distinctUntilChanged, merge, Subscription, finalize } from 'rxjs';
1
+ import { BehaviorSubject, map, catchError, mergeMap, throwError, tap, of, Subscription, finalize, merge, debounceTime, distinctUntilChanged } from 'rxjs';
2
2
  import { HttpClient, HttpParams, HttpHeaders } from '@angular/common/http';
3
3
  import * as i0 from '@angular/core';
4
4
  import { InjectionToken, inject, DOCUMENT, Injectable, signal, Component, computed, input, output, viewChild } from '@angular/core';
@@ -39,11 +39,11 @@ import { MatSort, MatSortModule } from '@angular/material/sort';
39
39
  import { MatButtonToggleModule } from '@angular/material/button-toggle';
40
40
  import * as i1$4 from '@angular/material/progress-spinner';
41
41
  import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
42
+ import { DataSource } from '@angular/cdk/collections';
42
43
  import * as i2$2 from '@angular/material/paginator';
43
44
  import { MatPaginator, MatPaginatorModule } from '@angular/material/paginator';
44
45
  import * as i2$3 from '@angular/cdk/scrolling';
45
46
  import { ScrollingModule } from '@angular/cdk/scrolling';
46
- import { DataSource } from '@angular/cdk/collections';
47
47
  import * as i2$4 from '@angular/material/toolbar';
48
48
  import { MatToolbarModule } from '@angular/material/toolbar';
49
49
  import * as i5$1 from '@angular/material/menu';
@@ -107,7 +107,6 @@ class ItemQuery {
107
107
  page_size = 0;
108
108
  sort_field = "";
109
109
  sort_order = "";
110
- filter_field = "";
111
110
  filter = "";
112
111
  constructor(params = {}) {
113
112
  Object.assign(this, params);
@@ -167,6 +166,26 @@ function getFileFieldIds(form) {
167
166
  }));
168
167
  return ids;
169
168
  }
169
+ class SearchFields {
170
+ filter = { rows: [] };
171
+ sortFields = [];
172
+ defaultQueries = [];
173
+ pageSize = 20;
174
+ pageSizeOptions = [20, 50, 100];
175
+ constructor(params = {}) {
176
+ Object.assign(this, params);
177
+ }
178
+ }
179
+ function getFilter(filters, key) {
180
+ for (const row of filters.rows) {
181
+ for (const filter of row.filters) {
182
+ if (filter.key === key) {
183
+ return filter;
184
+ }
185
+ }
186
+ }
187
+ return null;
188
+ }
170
189
 
171
190
  class FileRecord {
172
191
  name = "";
@@ -219,9 +238,6 @@ class RestService {
219
238
  }
220
239
  params.set('ordering', sort_field);
221
240
  }
222
- if (query.filter_field) {
223
- params.set('search_field', query.filter_field);
224
- }
225
241
  if (query.filter) {
226
242
  params.set('search', query.filter);
227
243
  }
@@ -530,7 +546,7 @@ class ItemWithUserService extends ItemService {
530
546
  return this.userService.hasDeletePermission(this.permissionName());
531
547
  }
532
548
  permissionName() {
533
- return this.typename.replace("_", "");
549
+ return this.typename.replaceAll("_", "");
534
550
  }
535
551
  getUserItems() {
536
552
  if (this.userService.loggedInUser.value) {
@@ -843,7 +859,7 @@ class DetailView {
843
859
  }
844
860
  title() {
845
861
  if (this.itemService.typename) {
846
- return this.itemService.typename.replace("_", " ");
862
+ return this.itemService.typename.replaceAll("_", " ");
847
863
  }
848
864
  return "";
849
865
  }
@@ -940,7 +956,7 @@ class EditView {
940
956
  }
941
957
  getTitle() {
942
958
  if (this.itemService && this.itemService.typename) {
943
- return this.itemService.typename.replace("_", " ");
959
+ return this.itemService.typename.replaceAll("_", " ");
944
960
  }
945
961
  return "";
946
962
  }
@@ -1176,47 +1192,28 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImpor
1176
1192
 
1177
1193
  class SearchBarComponent {
1178
1194
  itemType = input("", ...(ngDevMode ? [{ debugName: "itemType" }] : []));
1179
- sortFields = input([], ...(ngDevMode ? [{ debugName: "sortFields" }] : []));
1180
- sortAscending = signal(true, ...(ngDevMode ? [{ debugName: "sortAscending" }] : []));
1181
- filters = input(null, ...(ngDevMode ? [{ debugName: "filters" }] : []));
1182
- searchChanged = output();
1183
- searchFilter = new FormControl();
1184
1195
  showFilters = signal(false, ...(ngDevMode ? [{ debugName: "showFilters" }] : []));
1185
- fb = inject(FormBuilder);
1186
- filterForm = null;
1187
- ngOnInit() {
1188
- const filters = this.filters();
1189
- if (!filters) {
1190
- return;
1191
- }
1192
- this.filterForm = this.fb.group({});
1193
- for (const row of filters.rows) {
1194
- for (const filter of row.filters) {
1195
- if (filter.type == "boolean") {
1196
- this.filterForm.addControl(filter.key, this.fb.control(filter.default === "true"));
1197
- }
1198
- else if (filter.type == "selection") {
1199
- this.filterForm.addControl(filter.key, this.fb.control(filter.default));
1200
- }
1201
- }
1202
- }
1196
+ form = input.required(...(ngDevMode ? [{ debugName: "form" }] : []));
1197
+ get searchControl() {
1198
+ return this.form().form.controls['search'];
1203
1199
  }
1204
- ngAfterViewInit() {
1205
- this.searchFilter.valueChanges.pipe(debounceTime(150), distinctUntilChanged(), tap(() => {
1206
- this.searchEntered();
1207
- })).subscribe();
1200
+ get sortControl() {
1201
+ return this.form().form.controls['sortAscending'];
1202
+ }
1203
+ clearFilters() {
1204
+ this.form().resetFilters();
1208
1205
  }
1209
1206
  toggleFilterVisibility() {
1210
1207
  this.showFilters.update(value => !value);
1211
1208
  }
1212
1209
  clearSearch() {
1213
- this.searchFilter.setValue("");
1210
+ this.searchControl.setValue("");
1214
1211
  }
1215
- searchEntered() {
1216
- this.searchChanged.emit(this.searchFilter.value);
1212
+ toggleSortOrder() {
1213
+ this.sortControl.setValue(!this.sortControl.value);
1217
1214
  }
1218
1215
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: SearchBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1219
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", 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 }, filters: { classPropertyName: "filters", publicName: "filters", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { searchChanged: "searchChanged" }, ngImport: i0, template: "<div class=\"container\">\n <div class=\"search-row\">\n <mat-form-field class=\"search\" style=\"margin: 5px;width:70%\">\n <mat-label>{{'Search for ' + itemType() | titlecase}}</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(filters(); as filters)\n {\n @if(showFilters())\n {\n <button mat-button=\"tonal\" (click)=\"toggleFilterVisibility()\"><mat-icon>close</mat-icon>Hide Filters</button>\n }\n @else {\n <button mat-button=\"tonal\" (click)=\"toggleFilterVisibility()\"><mat-icon>tune</mat-icon>Filters</button>\n }\n }\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>\n\n <div class=\"filter-container\" style=\"width:100%\">\n @if(filters(); as filters)\n {\n @if(showFilters())\n {\n <div style=\"display: flex; flex-direction: row;\">\n @for(row of filters.rows; track row)\n {\n @for(filter of row.filters; track filter)\n {\n @if(filter.type === \"boolean\")\n {\n <mat-slide-toggle [formControlName]=\"filter.key\">{{filter.display_name}}</mat-slide-toggle>\n }\n }\n }\n </div>\n }\n }\n </div>\n</div>", styles: [":host{flex-grow:1}.container{width:100%;display:flex;flex-wrap:wrap;flex-direction:column;align-items:center;justify-content:center}.search-row{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: "directive", type: i1$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { 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: i5.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i5.MatLabel, selector: "mat-label" }, { kind: "directive", type: i5.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i3$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.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: "component", type: i2.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: MatSlideToggleModule }, { kind: "component", type: i7.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { 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" }] });
1216
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", type: SearchBarComponent, isStandalone: true, selector: "lib-search-bar", inputs: { itemType: { classPropertyName: "itemType", publicName: "itemType", isSignal: true, isRequired: false, transformFunction: null }, form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<div class=\"container\">\n <form [formGroup]=\"form().form\" style=\"width: 100%;max-width:1200px\">\n <div style=\"display: flex; flex-direction: column; align-items: center; justify-content: center; width: 100%;\">\n <div class=\"search-row\">\n <mat-form-field class=\"search\" style=\"width:70%\">\n <mat-label>{{'Search for ' + itemType() | titlecase}}</mat-label>\n <input matInput formControlName=\"search\" placeholder=\"Search {{ itemType() | titlecase }}\" />\n\n @if(searchControl.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(form().searchFields.sortFields.length > 0){\n <div>\n <mat-form-field style=\"margin: 10px\">\n <mat-label>Sort By</mat-label>\n <mat-select formControlName=\"sortField\">\n @for(field of form().searchFields.sortFields; track field)\n {\n <mat-option [value]=\"field.value\">{{field.display_name}}</mat-option>\n }\n </mat-select>\n </mat-form-field>\n\n <button mat-icon-button aria-label=\"Sort Order\" matTooltip=\"Toggle sort order\" (click)=\"toggleSortOrder()\">\n @if(sortControl.value){\n <mat-icon>arrow_upward</mat-icon>\n }\n @else{\n <mat-icon>arrow_downward</mat-icon>\n }\n </button>\n </div>\n }\n </div>\n\n @if(form().searchFields.filter.rows.length > 0)\n {\n @if(showFilters())\n {\n <button mat-button=\"tonal\" (click)=\"toggleFilterVisibility()\"><mat-icon>hide</mat-icon>Hide Filters</button>\n\n <button mat-button=\"tonal\" (click)=\"clearFilters()\"><mat-icon>collapse_all</mat-icon>Clear Filters</button>\n }\n @else {\n <button mat-button=\"tonal\" (click)=\"toggleFilterVisibility()\"><mat-icon>tune</mat-icon>Show Filters</button>\n }\n }\n\n </div>\n\n <div class=\"filter-container\">\n @if(showFilters() && form().searchFields.filter.rows.length > 0)\n {\n <div style=\"display: flex; flex-direction: row;\">\n <form [formGroup]=\"form().form.controls['filters']\" style=\"width: 100%;\">\n @for(row of form().searchFields.filter.rows; track row)\n {\n @for(filter of row.filters; track filter)\n {\n @if(filter.type === \"boolean\")\n {\n <mat-slide-toggle [formControlName]=\"filter.key\">{{filter.display_name}}</mat-slide-toggle>\n }\n @else if (filter.type === \"selection\") {\n <mat-form-field>\n <mat-label>{{filter.display_name}}</mat-label>\n <mat-select [formControlName]=\"filter.key\">\n @for(choice of filter.choices; track choice){\n <mat-option [value]=\"choice.value\">\n {{choice.display_name}}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n }\n }\n }\n </form>\n </div>\n }\n </div>\n </form>\n</div>", styles: [":host{flex-grow:1}.container{width:100%;display:flex;flex-wrap:wrap;flex-direction:column;align-items:center;justify-content:center}.search-row{width:100%;display:flex;flex-wrap:wrap;flex-direction:row;align-items:center;justify-content:center}.filter-container{width:100%;display:flex;flex-direction:column;justify-content:center;align-items:center}\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],[formArray],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: 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: i5.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i5.MatLabel, selector: "mat-label" }, { kind: "directive", type: i5.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i3$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.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: "component", type: i2.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: MatSlideToggleModule }, { kind: "component", type: i7.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { 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" }] });
1220
1217
  }
1221
1218
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: SearchBarComponent, decorators: [{
1222
1219
  type: Component,
@@ -1227,8 +1224,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImpor
1227
1224
  MatSelectModule,
1228
1225
  MatSlideToggleModule,
1229
1226
  MatIconModule,
1230
- TitleCasePipe], template: "<div class=\"container\">\n <div class=\"search-row\">\n <mat-form-field class=\"search\" style=\"margin: 5px;width:70%\">\n <mat-label>{{'Search for ' + itemType() | titlecase}}</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(filters(); as filters)\n {\n @if(showFilters())\n {\n <button mat-button=\"tonal\" (click)=\"toggleFilterVisibility()\"><mat-icon>close</mat-icon>Hide Filters</button>\n }\n @else {\n <button mat-button=\"tonal\" (click)=\"toggleFilterVisibility()\"><mat-icon>tune</mat-icon>Filters</button>\n }\n }\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>\n\n <div class=\"filter-container\" style=\"width:100%\">\n @if(filters(); as filters)\n {\n @if(showFilters())\n {\n <div style=\"display: flex; flex-direction: row;\">\n @for(row of filters.rows; track row)\n {\n @for(filter of row.filters; track filter)\n {\n @if(filter.type === \"boolean\")\n {\n <mat-slide-toggle [formControlName]=\"filter.key\">{{filter.display_name}}</mat-slide-toggle>\n }\n }\n }\n </div>\n }\n }\n </div>\n</div>", styles: [":host{flex-grow:1}.container{width:100%;display:flex;flex-wrap:wrap;flex-direction:column;align-items:center;justify-content:center}.search-row{width:100%;display:flex;flex-wrap:wrap;flex-direction:row;align-items:center;justify-content:center}\n"] }]
1231
- }], propDecorators: { itemType: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemType", required: false }] }], sortFields: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortFields", required: false }] }], filters: [{ type: i0.Input, args: [{ isSignal: true, alias: "filters", required: false }] }], searchChanged: [{ type: i0.Output, args: ["searchChanged"] }] } });
1227
+ TitleCasePipe], template: "<div class=\"container\">\n <form [formGroup]=\"form().form\" style=\"width: 100%;max-width:1200px\">\n <div style=\"display: flex; flex-direction: column; align-items: center; justify-content: center; width: 100%;\">\n <div class=\"search-row\">\n <mat-form-field class=\"search\" style=\"width:70%\">\n <mat-label>{{'Search for ' + itemType() | titlecase}}</mat-label>\n <input matInput formControlName=\"search\" placeholder=\"Search {{ itemType() | titlecase }}\" />\n\n @if(searchControl.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(form().searchFields.sortFields.length > 0){\n <div>\n <mat-form-field style=\"margin: 10px\">\n <mat-label>Sort By</mat-label>\n <mat-select formControlName=\"sortField\">\n @for(field of form().searchFields.sortFields; track field)\n {\n <mat-option [value]=\"field.value\">{{field.display_name}}</mat-option>\n }\n </mat-select>\n </mat-form-field>\n\n <button mat-icon-button aria-label=\"Sort Order\" matTooltip=\"Toggle sort order\" (click)=\"toggleSortOrder()\">\n @if(sortControl.value){\n <mat-icon>arrow_upward</mat-icon>\n }\n @else{\n <mat-icon>arrow_downward</mat-icon>\n }\n </button>\n </div>\n }\n </div>\n\n @if(form().searchFields.filter.rows.length > 0)\n {\n @if(showFilters())\n {\n <button mat-button=\"tonal\" (click)=\"toggleFilterVisibility()\"><mat-icon>hide</mat-icon>Hide Filters</button>\n\n <button mat-button=\"tonal\" (click)=\"clearFilters()\"><mat-icon>collapse_all</mat-icon>Clear Filters</button>\n }\n @else {\n <button mat-button=\"tonal\" (click)=\"toggleFilterVisibility()\"><mat-icon>tune</mat-icon>Show Filters</button>\n }\n }\n\n </div>\n\n <div class=\"filter-container\">\n @if(showFilters() && form().searchFields.filter.rows.length > 0)\n {\n <div style=\"display: flex; flex-direction: row;\">\n <form [formGroup]=\"form().form.controls['filters']\" style=\"width: 100%;\">\n @for(row of form().searchFields.filter.rows; track row)\n {\n @for(filter of row.filters; track filter)\n {\n @if(filter.type === \"boolean\")\n {\n <mat-slide-toggle [formControlName]=\"filter.key\">{{filter.display_name}}</mat-slide-toggle>\n }\n @else if (filter.type === \"selection\") {\n <mat-form-field>\n <mat-label>{{filter.display_name}}</mat-label>\n <mat-select [formControlName]=\"filter.key\">\n @for(choice of filter.choices; track choice){\n <mat-option [value]=\"choice.value\">\n {{choice.display_name}}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n }\n }\n }\n </form>\n </div>\n }\n </div>\n </form>\n</div>", styles: [":host{flex-grow:1}.container{width:100%;display:flex;flex-wrap:wrap;flex-direction:column;align-items:center;justify-content:center}.search-row{width:100%;display:flex;flex-wrap:wrap;flex-direction:row;align-items:center;justify-content:center}.filter-container{width:100%;display:flex;flex-direction:column;justify-content:center;align-items:center}\n"] }]
1228
+ }], propDecorators: { itemType: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemType", required: false }] }], form: [{ type: i0.Input, args: [{ isSignal: true, alias: "form", required: true }] }] } });
1232
1229
 
1233
1230
  class FileUploadComponent {
1234
1231
  control = input.required(...(ngDevMode ? [{ debugName: "control" }] : []));
@@ -2023,6 +2020,107 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImpor
2023
2020
  args: [{ selector: 'lib-populated-form', imports: [MatIconModule, MatButtonModule], template: "@for(value of form().values; track value.id)\n{\n@if(value.field.field_type === \"TEXT\" || value.field.field_type === \"RICH_TEXT\")\n{\n <div class=\"item-field\">\n <h3 style=\"margin-right: 10px\">{{value.field.label}}</h3>\n <p>{{value.value}}</p>\n </div>\n}\n@else if(value.field.field_type === \"CHAR\")\n{\n <div class=\"item-field\">\n <span style=\"margin-right: 10px\"><b>{{value.field.label}}:</b></span>\n <span>{{value.value}}</span>\n </div>\n}\n@else if(value.field.field_type === \"BOOLEAN\")\n{\n <div class=\"item-field\">\n <span style=\"margin-right: 10px\"><b>{{value.field.label}}:</b></span>\n @if(value.value === \"true\")\n {\n <mat-icon>check</mat-icon>\n }\n @else {\n <mat-icon>close_small</mat-icon>\n }\n </div>\n}\n@else if(value.field.field_type === \"SELECTION\")\n{\n <div class=\"item-field\">\n <span style=\"margin-right: 10px\"><b>{{value.field.label}}:</b></span>\n <span>{{value.value}}</span>\n </div>\n}\n@else if(value.field.field_type === \"INTEGER\")\n{\n <div class=\"item-field\">\n <span style=\"margin-right: 10px\"><b>{{value.field.label}}:</b></span>\n <span>{{value.value}}</span>\n </div>\n}\n@else if(value.field.field_type === \"FILE\" && value.asset)\n{\n <div class=\"item-field\">\n <span style=\"margin-right: 10px\"><b>{{value.field.label}}:</b></span>\n <a matFab href=\"value.asset\">\n <mat-icon>download</mat-icon>\n </a>\n </div>\n}\n}" }]
2024
2021
  }], propDecorators: { form: [{ type: i0.Input, args: [{ isSignal: true, alias: "form", required: true }] }] } });
2025
2022
 
2023
+ class ListDataSource extends DataSource {
2024
+ length = signal(0, ...(ngDevMode ? [{ debugName: "length" }] : []));
2025
+ loading = signal(true, ...(ngDevMode ? [{ debugName: "loading" }] : []));
2026
+ activeQuery = signal(new ItemQuery(), ...(ngDevMode ? [{ debugName: "activeQuery" }] : []));
2027
+ hasFetched = signal(false, ...(ngDevMode ? [{ debugName: "hasFetched" }] : []));
2028
+ sourceIsEmpty = computed(() => this.length() == 0 && this.hasFetched() && !this.activeQuery().filter, ...(ngDevMode ? [{ debugName: "sourceIsEmpty" }] : []));
2029
+ consumerType;
2030
+ items = new BehaviorSubject([]);
2031
+ itemService;
2032
+ subscription = new Subscription();
2033
+ fetchedPages = new Set();
2034
+ defaultQueries = [];
2035
+ constructor(itemService, consumerType = "table", defaultQueries = []) {
2036
+ super();
2037
+ this.itemService = itemService;
2038
+ this.consumerType = consumerType;
2039
+ this.defaultQueries = defaultQueries;
2040
+ }
2041
+ connect(collectionViewer) {
2042
+ if (!this.hasTableConsumer()) {
2043
+ this.subscription.add(collectionViewer.viewChange.subscribe((range) => this.onRange(range)));
2044
+ }
2045
+ return this.items.asObservable();
2046
+ }
2047
+ hasTableConsumer() {
2048
+ return this.consumerType === "table";
2049
+ }
2050
+ onRange(range) {
2051
+ const start_page = Math.floor(range.start / this.activeQuery().page_size);
2052
+ const end_page = Math.floor(range.end / this.activeQuery().page_size);
2053
+ for (let idx = start_page; idx <= end_page; idx++) {
2054
+ this.fetchPage(idx);
2055
+ }
2056
+ }
2057
+ reset(query) {
2058
+ this.fetchedPages = new Set();
2059
+ this.length.set(0);
2060
+ this.activeQuery.set(query);
2061
+ this.loading.set(true);
2062
+ this.items.next([]);
2063
+ this.fetchPage(0);
2064
+ }
2065
+ fetchPage(idx) {
2066
+ if (this.fetchedPages.has(idx)) {
2067
+ return;
2068
+ }
2069
+ this.fetchedPages.add(idx);
2070
+ let queries = new Map([]);
2071
+ this.defaultQueries.forEach(q => queries.set(q.key, q.value));
2072
+ queries = new Map([...this.activeQuery().queries, ...queries]);
2073
+ this.fetch(new ItemQuery({ page: idx + 1,
2074
+ page_size: this.activeQuery().page_size,
2075
+ queries: queries,
2076
+ sort_field: this.activeQuery().sort_field,
2077
+ sort_order: this.activeQuery().sort_order,
2078
+ filter: this.activeQuery().filter }));
2079
+ }
2080
+ fetch(query) {
2081
+ this.loading.set(true);
2082
+ this.itemService.get(query).pipe(catchError(() => of(new Paginated())), finalize(() => this.loading.set(false))).subscribe(response => this.onResponse(response));
2083
+ }
2084
+ onResponse(response) {
2085
+ this.length.set(response.count);
2086
+ this.hasFetched.set(true);
2087
+ if (this.hasTableConsumer()) {
2088
+ this.items.next(response.results);
2089
+ }
2090
+ else {
2091
+ this.items.next([...this.items.value, ...response.results]);
2092
+ }
2093
+ }
2094
+ disconnect() {
2095
+ this.items.complete();
2096
+ if (this.subscription) {
2097
+ this.subscription.unsubscribe();
2098
+ }
2099
+ }
2100
+ }
2101
+
2102
+ class ListHeaderComponent {
2103
+ itemType = input.required(...(ngDevMode ? [{ debugName: "itemType" }] : []));
2104
+ canCreate = input.required(...(ngDevMode ? [{ debugName: "canCreate" }] : []));
2105
+ showControls = input.required(...(ngDevMode ? [{ debugName: "showControls" }] : []));
2106
+ embedded = input(false, ...(ngDevMode ? [{ debugName: "embedded" }] : []));
2107
+ searchForm = input.required(...(ngDevMode ? [{ debugName: "searchForm" }] : []));
2108
+ title() {
2109
+ return this.itemType().replaceAll("_", " ");
2110
+ }
2111
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: ListHeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2112
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", type: ListHeaderComponent, isStandalone: true, selector: "lib-list-header", inputs: { itemType: { classPropertyName: "itemType", publicName: "itemType", isSignal: true, isRequired: true, transformFunction: null }, canCreate: { classPropertyName: "canCreate", publicName: "canCreate", isSignal: true, isRequired: true, transformFunction: null }, showControls: { classPropertyName: "showControls", publicName: "showControls", isSignal: true, isRequired: true, transformFunction: null }, embedded: { classPropertyName: "embedded", publicName: "embedded", isSignal: true, isRequired: false, transformFunction: null }, searchForm: { classPropertyName: "searchForm", publicName: "searchForm", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<div class=\"container\">\n\n @if(!embedded()){\n <div class=\"title-container\">\n <h1 class=\"title\">{{ title() | titlecase }}</h1>\n\n @if (canCreate()) {\n <div class=\"button-container\">\n <a mat-mini-fab aria-label=\"Add new item\" [matTooltip]=\"'Add new ' + title()\"\n [routerLink]=\"['/' + itemType(), 'create']\">\n <mat-icon>add</mat-icon></a>\n </div>\n }\n </div>\n}\n\n <div class=\"controls\" [hidden]=\"!showControls()\">\n <lib-search-bar style=\"width:70%\" [itemType]=\"title()\" [form]=\"searchForm()\"></lib-search-bar>\n </div>\n</div>", styles: [":host{flex-grow:1}.container{display:flex;flex-direction:column;align-items:center;justify-content:center}.title-container{width:100%;display:flex;flex-direction:row;align-items:center;justify-content:center}.title{text-align:center;padding:5px;margin:0}.controls{display:flex;align-items:center;justify-content:center;flex-wrap:wrap;width:100%}\n"], dependencies: [{ kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i1$3.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { 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.MatMiniFabButton, selector: "button[mat-mini-fab], a[mat-mini-fab], button[matMiniFab], a[matMiniFab]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i3$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: SearchBarComponent, selector: "lib-search-bar", inputs: ["itemType", "form"] }, { kind: "pipe", type: TitleCasePipe, name: "titlecase" }] });
2113
+ }
2114
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: ListHeaderComponent, decorators: [{
2115
+ type: Component,
2116
+ args: [{ selector: 'lib-list-header', imports: [TitleCasePipe,
2117
+ RouterModule,
2118
+ MatIconModule,
2119
+ MatButtonModule,
2120
+ MatTooltipModule,
2121
+ SearchBarComponent], template: "<div class=\"container\">\n\n @if(!embedded()){\n <div class=\"title-container\">\n <h1 class=\"title\">{{ title() | titlecase }}</h1>\n\n @if (canCreate()) {\n <div class=\"button-container\">\n <a mat-mini-fab aria-label=\"Add new item\" [matTooltip]=\"'Add new ' + title()\"\n [routerLink]=\"['/' + itemType(), 'create']\">\n <mat-icon>add</mat-icon></a>\n </div>\n }\n </div>\n}\n\n <div class=\"controls\" [hidden]=\"!showControls()\">\n <lib-search-bar style=\"width:70%\" [itemType]=\"title()\" [form]=\"searchForm()\"></lib-search-bar>\n </div>\n</div>", styles: [":host{flex-grow:1}.container{display:flex;flex-direction:column;align-items:center;justify-content:center}.title-container{width:100%;display:flex;flex-direction:row;align-items:center;justify-content:center}.title{text-align:center;padding:5px;margin:0}.controls{display:flex;align-items:center;justify-content:center;flex-wrap:wrap;width:100%}\n"] }]
2122
+ }], propDecorators: { itemType: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemType", required: true }] }], canCreate: [{ type: i0.Input, args: [{ isSignal: true, alias: "canCreate", required: true }] }], showControls: [{ type: i0.Input, args: [{ isSignal: true, alias: "showControls", required: true }] }], embedded: [{ type: i0.Input, args: [{ isSignal: true, alias: "embedded", required: false }] }], searchForm: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchForm", required: true }] }] } });
2123
+
2026
2124
  /* eslint-disable @typescript-eslint/no-explicit-any */
2027
2125
  class ListTableViewComponent {
2028
2126
  itemType = input("", ...(ngDevMode ? [{ debugName: "itemType" }] : []));
@@ -2088,8 +2186,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImpor
2088
2186
  // Datasource needs any
2089
2187
  /* eslint-disable @typescript-eslint/no-explicit-any */
2090
2188
  class ListScrollViewComponent {
2091
- searchTerm = input("", ...(ngDevMode ? [{ debugName: "searchTerm" }] : []));
2092
- pageSize = input(20, ...(ngDevMode ? [{ debugName: "pageSize" }] : []));
2093
2189
  itemHeight = input(100, ...(ngDevMode ? [{ debugName: "itemHeight" }] : []));
2094
2190
  itemWidth = input("200", ...(ngDevMode ? [{ debugName: "itemWidth" }] : []));
2095
2191
  dataSource = input(...(ngDevMode ? [undefined, { debugName: "dataSource" }] : []));
@@ -2097,133 +2193,77 @@ class ListScrollViewComponent {
2097
2193
  routerMode = input(false, ...(ngDevMode ? [{ debugName: "routerMode" }] : []));
2098
2194
  selection = signal(null, ...(ngDevMode ? [{ debugName: "selection" }] : []));
2099
2195
  selected = output();
2100
- reset() {
2101
- const data_source = this.dataSource();
2102
- if (!data_source) {
2103
- return;
2104
- }
2105
- // sort_order: this.sort!.direction,
2106
- // sort_field: this.sort!.active,
2107
- data_source.reset(this.searchTerm(), this.pageSize());
2108
- }
2109
2196
  onSelected(id) {
2110
2197
  this.selection.set(id);
2111
2198
  this.selected.emit(id);
2112
2199
  }
2113
2200
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: ListScrollViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2114
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", 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 }, itemHeight: { classPropertyName: "itemHeight", publicName: "itemHeight", isSignal: true, isRequired: false, transformFunction: null }, itemWidth: { classPropertyName: "itemWidth", publicName: "itemWidth", 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 }, routerMode: { classPropertyName: "routerMode", publicName: "routerMode", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selected: "selected" }, ngImport: i0, template: "<mat-nav-list class=\"scrollable-container\">\n <cdk-virtual-scroll-viewport\n itemSize=\"itemHeight()\"\n class=\"scrollable-list\"\n style=\"width: 100%;\">\n <ng-container *cdkVirtualFor=\"let item of dataSource(); let even = even;\">\n @if(routerMode())\n {\n <ng-container\n *ngTemplateOutlet=\"listItemTemplate(); context: { item: item, even: even, selected: item.id === selection()}\" \n >\n </ng-container>\n }\n @else \n {\n <div\n (click)=\"onSelected(item.id)\" \n (keydown)=\"onSelected(item.id)\"\n tabindex=\"0\"\n style=\"width: 100%; margin-right: 5px; margin-bottom: 2px;\"\n role=\"button\">\n <ng-container\n *ngTemplateOutlet=\"listItemTemplate(); context: { item: item, even: even, selected: item.id === selection()}\" \n >\n </ng-container> \n </div> \n }\n </ng-container>\n </cdk-virtual-scroll-viewport>\n</mat-nav-list>\n", styles: [":host{flex-grow:1}.scrollable-container{padding:0;display:flex;justify-content:center}.scrollable-list{height:540px;padding:5px;width:100%}\n"], dependencies: [{ kind: "ngmodule", type: MatListModule }, { kind: "component", type: i2$1.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$3.CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i2$3.CdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i2$3.CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }] });
2201
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", type: ListScrollViewComponent, isStandalone: true, selector: "lib-list-scroll-view", inputs: { itemHeight: { classPropertyName: "itemHeight", publicName: "itemHeight", isSignal: true, isRequired: false, transformFunction: null }, itemWidth: { classPropertyName: "itemWidth", publicName: "itemWidth", 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 }, routerMode: { classPropertyName: "routerMode", publicName: "routerMode", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selected: "selected" }, ngImport: i0, template: "<mat-nav-list class=\"scrollable-container\">\n <cdk-virtual-scroll-viewport\n itemSize=\"itemHeight()\"\n class=\"scrollable-list\"\n style=\"width: 100%;\">\n <ng-container *cdkVirtualFor=\"let item of dataSource(); let even = even;\">\n @if(routerMode())\n {\n <ng-container\n *ngTemplateOutlet=\"listItemTemplate(); context: { item: item, even: even, selected: item.id === selection()}\" \n >\n </ng-container>\n }\n @else \n {\n <div\n (click)=\"onSelected(item.id)\" \n (keydown)=\"onSelected(item.id)\"\n tabindex=\"0\"\n style=\"width: 100%; margin-right: 5px; margin-bottom: 2px;\"\n role=\"button\">\n <ng-container\n *ngTemplateOutlet=\"listItemTemplate(); context: { item: item, even: even, selected: item.id === selection()}\" \n >\n </ng-container> \n </div> \n }\n </ng-container>\n </cdk-virtual-scroll-viewport>\n</mat-nav-list>\n", styles: [":host{flex-grow:1}.scrollable-container{padding:0;display:flex;justify-content:center}.scrollable-list{height:540px;padding:5px;width:100%}\n"], dependencies: [{ kind: "ngmodule", type: MatListModule }, { kind: "component", type: i2$1.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$3.CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i2$3.CdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i2$3.CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }] });
2115
2202
  }
2116
2203
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: ListScrollViewComponent, decorators: [{
2117
2204
  type: Component,
2118
2205
  args: [{ selector: 'lib-list-scroll-view', imports: [MatListModule,
2119
2206
  NgTemplateOutlet,
2120
2207
  ScrollingModule], template: "<mat-nav-list class=\"scrollable-container\">\n <cdk-virtual-scroll-viewport\n itemSize=\"itemHeight()\"\n class=\"scrollable-list\"\n style=\"width: 100%;\">\n <ng-container *cdkVirtualFor=\"let item of dataSource(); let even = even;\">\n @if(routerMode())\n {\n <ng-container\n *ngTemplateOutlet=\"listItemTemplate(); context: { item: item, even: even, selected: item.id === selection()}\" \n >\n </ng-container>\n }\n @else \n {\n <div\n (click)=\"onSelected(item.id)\" \n (keydown)=\"onSelected(item.id)\"\n tabindex=\"0\"\n style=\"width: 100%; margin-right: 5px; margin-bottom: 2px;\"\n role=\"button\">\n <ng-container\n *ngTemplateOutlet=\"listItemTemplate(); context: { item: item, even: even, selected: item.id === selection()}\" \n >\n </ng-container> \n </div> \n }\n </ng-container>\n </cdk-virtual-scroll-viewport>\n</mat-nav-list>\n", styles: [":host{flex-grow:1}.scrollable-container{padding:0;display:flex;justify-content:center}.scrollable-list{height:540px;padding:5px;width:100%}\n"] }]
2121
- }], propDecorators: { searchTerm: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchTerm", required: false }] }], pageSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSize", required: false }] }], itemHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemHeight", required: false }] }], itemWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemWidth", required: false }] }], dataSource: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataSource", required: false }] }], listItemTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "listItemTemplate", required: false }] }], routerMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "routerMode", required: false }] }], selected: [{ type: i0.Output, args: ["selected"] }] } });
2208
+ }], propDecorators: { itemHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemHeight", required: false }] }], itemWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemWidth", required: false }] }], dataSource: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataSource", required: false }] }], listItemTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "listItemTemplate", required: false }] }], routerMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "routerMode", required: false }] }], selected: [{ type: i0.Output, args: ["selected"] }] } });
2122
2209
 
2123
- class ListDataSource extends DataSource {
2124
- length = signal(0, ...(ngDevMode ? [{ debugName: "length" }] : []));
2125
- loading = signal(true, ...(ngDevMode ? [{ debugName: "loading" }] : []));
2126
- searchTerm = signal("", ...(ngDevMode ? [{ debugName: "searchTerm" }] : []));
2127
- pageSize = signal(20, ...(ngDevMode ? [{ debugName: "pageSize" }] : []));
2128
- hasFetched = signal(false, ...(ngDevMode ? [{ debugName: "hasFetched" }] : []));
2129
- sourceIsEmpty = computed(() => this.length() == 0 && this.hasFetched() && !this.searchTerm(), ...(ngDevMode ? [{ debugName: "sourceIsEmpty" }] : []));
2130
- consumerType;
2131
- items = new BehaviorSubject([]);
2132
- itemService;
2133
- subscription = new Subscription();
2134
- fetchedPages = new Set();
2135
- defaultQueries = [];
2136
- constructor(itemService, consumerType = "table", defaultQueries = []) {
2137
- super();
2138
- this.itemService = itemService;
2139
- this.consumerType = consumerType;
2140
- this.defaultQueries = defaultQueries;
2141
- }
2142
- connect(collectionViewer) {
2143
- if (!this.hasTableConsumer()) {
2144
- this.subscription.add(collectionViewer.viewChange.subscribe((range) => this.onRange(range)));
2145
- }
2146
- return this.items.asObservable();
2147
- }
2148
- hasTableConsumer() {
2149
- return this.consumerType === "table";
2150
- }
2151
- onRange(range) {
2152
- const start_page = Math.floor(range.start / this.pageSize());
2153
- const end_page = Math.floor(range.end / this.pageSize());
2154
- for (let idx = start_page; idx <= end_page; idx++) {
2155
- this.fetchPage(idx);
2156
- }
2157
- }
2158
- reset(searchTerm = "", pageSize = 20) {
2159
- this.fetchedPages = new Set();
2160
- this.length.set(0);
2161
- this.searchTerm.set(searchTerm);
2162
- this.pageSize.set(pageSize);
2163
- this.loading.set(true);
2164
- this.items.next([]);
2165
- this.fetchPage(0);
2166
- }
2167
- fetchPage(idx) {
2168
- if (this.fetchedPages.has(idx)) {
2169
- return;
2210
+ class SearchForm {
2211
+ form;
2212
+ searchFields;
2213
+ constructor(searchFields, fb) {
2214
+ this.searchFields = searchFields;
2215
+ const filter_group = fb.group({});
2216
+ for (const row of this.searchFields.filter.rows) {
2217
+ for (const filter of row.filters) {
2218
+ if (filter.type == "boolean") {
2219
+ filter_group.addControl(filter.key, fb.control(filter.default === "true"));
2220
+ }
2221
+ else if (filter.type == "selection") {
2222
+ filter_group.addControl(filter.key, fb.control(filter.default || ""));
2223
+ }
2224
+ }
2170
2225
  }
2171
- this.fetchedPages.add(idx);
2172
- const queries = new Map([]);
2173
- this.defaultQueries.forEach(q => queries.set(q.key, q.value));
2174
- this.fetch(new ItemQuery({ page: idx + 1,
2175
- page_size: this.pageSize(),
2176
- queries: queries,
2177
- filter: this.searchTerm() }));
2226
+ this.form = fb.group({
2227
+ sortAscending: fb.control(true),
2228
+ sortField: fb.control(''),
2229
+ search: fb.control(''),
2230
+ pageSize: fb.control(this.searchFields.pageSize),
2231
+ filters: filter_group
2232
+ });
2178
2233
  }
2179
- fetch(query) {
2180
- this.loading.set(true);
2181
- this.itemService.get(query).pipe(catchError(() => of(new Paginated())), finalize(() => this.loading.set(false))).subscribe(response => this.onResponse(response));
2234
+ get filterControls() {
2235
+ return this.form.controls['filters'].controls;
2182
2236
  }
2183
- onResponse(response) {
2184
- this.length.set(response.count);
2185
- this.hasFetched.set(true);
2186
- if (this.hasTableConsumer()) {
2187
- this.items.next(response.results);
2188
- }
2189
- else {
2190
- this.items.next([...this.items.value, ...response.results]);
2237
+ resetFilters() {
2238
+ for (const control_name of Object.keys(this.filterControls)) {
2239
+ this.filterControls[control_name].reset("");
2191
2240
  }
2192
2241
  }
2193
- disconnect() {
2194
- this.items.complete();
2195
- if (this.subscription) {
2196
- this.subscription.unsubscribe();
2242
+ toQuery() {
2243
+ const value = this.form.value;
2244
+ const query = new ItemQuery({ sort_field: value.sortField || "",
2245
+ sort_order: value.sortAscending ? "asc" : "desc",
2246
+ filter: value.search || "",
2247
+ page_size: value.pageSize || 20
2248
+ });
2249
+ if (value.filters) {
2250
+ for (const control_name of Object.keys(value.filters)) {
2251
+ let control_value = value.filters[control_name];
2252
+ const filter = getFilter(this.searchFields.filter, control_name);
2253
+ if (!filter) {
2254
+ continue;
2255
+ }
2256
+ const valid_default = filter.default != null && filter.default != "";
2257
+ if ((control_value === null || control_value === undefined) && valid_default) {
2258
+ control_value = filter.default;
2259
+ }
2260
+ query.queries.set(control_name, control_value);
2261
+ }
2197
2262
  }
2263
+ return query;
2198
2264
  }
2199
2265
  }
2200
2266
 
2201
- class ListHeaderComponent {
2202
- itemType = input.required(...(ngDevMode ? [{ debugName: "itemType" }] : []));
2203
- canCreate = input.required(...(ngDevMode ? [{ debugName: "canCreate" }] : []));
2204
- showControls = input.required(...(ngDevMode ? [{ debugName: "showControls" }] : []));
2205
- sortFields = input.required(...(ngDevMode ? [{ debugName: "sortFields" }] : []));
2206
- filters = input(null, ...(ngDevMode ? [{ debugName: "filters" }] : []));
2207
- searchChanged = output();
2208
- title() {
2209
- return this.itemType().replace("_", " ");
2210
- }
2211
- onSearchChange(value) {
2212
- this.searchChanged.emit(value);
2213
- }
2214
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: ListHeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2215
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", type: ListHeaderComponent, isStandalone: true, selector: "lib-list-header", inputs: { itemType: { classPropertyName: "itemType", publicName: "itemType", isSignal: true, isRequired: true, transformFunction: null }, canCreate: { classPropertyName: "canCreate", publicName: "canCreate", isSignal: true, isRequired: true, transformFunction: null }, showControls: { classPropertyName: "showControls", publicName: "showControls", isSignal: true, isRequired: true, transformFunction: null }, sortFields: { classPropertyName: "sortFields", publicName: "sortFields", isSignal: true, isRequired: true, transformFunction: null }, filters: { classPropertyName: "filters", publicName: "filters", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { searchChanged: "searchChanged" }, ngImport: i0, template: "<div class=\"container\">\n\n <div class=\"title-container\">\n <h1 class=\"title\">{{ title() | titlecase }}</h1>\n\n @if (canCreate()) {\n <div class=\"button-container\">\n <a mat-mini-fab aria-label=\"Add new item\" [matTooltip]=\"'Add new ' + title()\"\n [routerLink]=\"['/' + itemType(), 'create']\">\n <mat-icon>add</mat-icon></a>\n </div>\n }\n </div>\n\n <div class=\"controls\" [hidden]=\"!showControls()\">\n <lib-search-bar style=\"width:70%\" [itemType]=\"title()\" [filters]=\"filters()\" [sortFields]=\"sortFields()\"\n (searchChanged)=\"onSearchChange($event)\"></lib-search-bar>\n </div>\n</div>", styles: [":host{flex-grow:1}.container{display:flex;flex-direction:column;align-items:center;justify-content:center}.title-container{width:100%;display:flex;flex-direction:row;align-items:center;justify-content:center}.title{text-align:center;padding:5px;margin:0}.controls{display:flex;align-items:center;justify-content:center;flex-wrap:wrap;width:100%}\n"], dependencies: [{ kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i1$3.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { 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.MatMiniFabButton, selector: "button[mat-mini-fab], a[mat-mini-fab], button[matMiniFab], a[matMiniFab]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i3$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: SearchBarComponent, selector: "lib-search-bar", inputs: ["itemType", "sortFields", "filters"], outputs: ["searchChanged"] }, { kind: "pipe", type: TitleCasePipe, name: "titlecase" }] });
2216
- }
2217
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: ListHeaderComponent, decorators: [{
2218
- type: Component,
2219
- args: [{ selector: 'lib-list-header', imports: [TitleCasePipe,
2220
- RouterModule,
2221
- MatIconModule,
2222
- MatButtonModule,
2223
- MatTooltipModule,
2224
- SearchBarComponent], template: "<div class=\"container\">\n\n <div class=\"title-container\">\n <h1 class=\"title\">{{ title() | titlecase }}</h1>\n\n @if (canCreate()) {\n <div class=\"button-container\">\n <a mat-mini-fab aria-label=\"Add new item\" [matTooltip]=\"'Add new ' + title()\"\n [routerLink]=\"['/' + itemType(), 'create']\">\n <mat-icon>add</mat-icon></a>\n </div>\n }\n </div>\n\n <div class=\"controls\" [hidden]=\"!showControls()\">\n <lib-search-bar style=\"width:70%\" [itemType]=\"title()\" [filters]=\"filters()\" [sortFields]=\"sortFields()\"\n (searchChanged)=\"onSearchChange($event)\"></lib-search-bar>\n </div>\n</div>", styles: [":host{flex-grow:1}.container{display:flex;flex-direction:column;align-items:center;justify-content:center}.title-container{width:100%;display:flex;flex-direction:row;align-items:center;justify-content:center}.title{text-align:center;padding:5px;margin:0}.controls{display:flex;align-items:center;justify-content:center;flex-wrap:wrap;width:100%}\n"] }]
2225
- }], propDecorators: { itemType: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemType", required: true }] }], canCreate: [{ type: i0.Input, args: [{ isSignal: true, alias: "canCreate", required: true }] }], showControls: [{ type: i0.Input, args: [{ isSignal: true, alias: "showControls", required: true }] }], sortFields: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortFields", required: true }] }], filters: [{ type: i0.Input, args: [{ isSignal: true, alias: "filters", required: false }] }], searchChanged: [{ type: i0.Output, args: ["searchChanged"] }] } });
2226
-
2227
2267
  class ListViewComponent {
2228
2268
  viewType = input("table", ...(ngDevMode ? [{ debugName: "viewType" }] : []));
2229
2269
  itemService = input(...(ngDevMode ? [undefined, { debugName: "itemService" }] : []));
@@ -2232,22 +2272,19 @@ class ListViewComponent {
2232
2272
  itemHeight = input(100, ...(ngDevMode ? [{ debugName: "itemHeight" }] : []));
2233
2273
  itemWidth = input(300, ...(ngDevMode ? [{ debugName: "itemWidth" }] : []));
2234
2274
  columns = input([], ...(ngDevMode ? [{ debugName: "columns" }] : []));
2235
- sortFields = input([], ...(ngDevMode ? [{ debugName: "sortFields" }] : []));
2236
2275
  noSelfItemsMessage = input(...(ngDevMode ? [undefined, { debugName: "noSelfItemsMessage" }] : []));
2237
2276
  noItemsCanCreateMessage = input(...(ngDevMode ? [undefined, { debugName: "noItemsCanCreateMessage" }] : []));
2238
2277
  noItemsMessage = input(...(ngDevMode ? [undefined, { debugName: "noItemsMessage" }] : []));
2239
- defaultQueries = input([], ...(ngDevMode ? [{ debugName: "defaultQueries" }] : []));
2240
- filters = input(null, ...(ngDevMode ? [{ debugName: "filters" }] : []));
2278
+ searchFields = input.required(...(ngDevMode ? [{ debugName: "searchFields" }] : []));
2241
2279
  embeddedMode = input(false, ...(ngDevMode ? [{ debugName: "embeddedMode" }] : []));
2242
2280
  selectedViewType = signal("table", ...(ngDevMode ? [{ debugName: "selectedViewType" }] : []));
2243
2281
  selected = output();
2244
- pageSize = 20;
2245
- pageSizeOptions = [20, 50, 100];
2246
2282
  route = inject(ActivatedRoute);
2247
2283
  dataSource = undefined;
2248
2284
  sort = viewChild(MatSort, ...(ngDevMode ? [{ debugName: "sort" }] : []));
2249
2285
  columnNames = computed(() => this.columns().map(c => c.name), ...(ngDevMode ? [{ debugName: "columnNames" }] : []));
2250
- searchTerm = "";
2286
+ fb = inject(FormBuilder);
2287
+ searchForm = signal(new SearchForm(new SearchFields(), this.fb), ...(ngDevMode ? [{ debugName: "searchForm" }] : []));
2251
2288
  get resolvedItemWidth() {
2252
2289
  if (this.itemDetailTemplate() && this.dataSource !== undefined && !this.dataSource.sourceIsEmpty()) {
2253
2290
  return (this.itemWidth() + 50).toString() + "px";
@@ -2258,6 +2295,7 @@ class ListViewComponent {
2258
2295
  }
2259
2296
  ngOnInit() {
2260
2297
  this.selectedViewType.set(this.viewType());
2298
+ this.searchForm.set(new SearchForm(this.searchFields(), this.fb));
2261
2299
  this.resetDataSource();
2262
2300
  }
2263
2301
  ngAfterViewInit() {
@@ -2265,14 +2303,13 @@ class ListViewComponent {
2265
2303
  if (sort) {
2266
2304
  sort.sortChange.pipe(tap(() => this.reset())).subscribe();
2267
2305
  }
2306
+ this.searchForm().form.valueChanges.pipe(debounceTime(150), distinctUntilChanged(), tap(() => {
2307
+ this.reset();
2308
+ })).subscribe();
2268
2309
  }
2269
2310
  showControls() {
2270
2311
  return this.dataSource != undefined && !this.dataSource.sourceIsEmpty();
2271
2312
  }
2272
- onSearchChange(value) {
2273
- this.searchTerm = value;
2274
- this.reset();
2275
- }
2276
2313
  canCreate() {
2277
2314
  const item_service = this.itemService();
2278
2315
  if (item_service) {
@@ -2288,7 +2325,7 @@ class ListViewComponent {
2288
2325
  return "";
2289
2326
  }
2290
2327
  title() {
2291
- return this.itemType().replace("_", " ");
2328
+ return this.itemType().replaceAll("_", " ");
2292
2329
  }
2293
2330
  isTableView() {
2294
2331
  return this.selectedViewType() === "table";
@@ -2296,13 +2333,13 @@ class ListViewComponent {
2296
2333
  resetDataSource() {
2297
2334
  const item_service = this.itemService();
2298
2335
  if (item_service) {
2299
- this.dataSource = new ListDataSource(item_service, this.selectedViewType(), this.defaultQueries());
2336
+ this.dataSource = new ListDataSource(item_service, this.selectedViewType(), this.searchFields().defaultQueries);
2300
2337
  }
2301
2338
  this.reset();
2302
2339
  }
2303
2340
  reset() {
2304
2341
  if (this.dataSource) {
2305
- this.dataSource.reset(this.searchTerm, this.pageSize);
2342
+ this.dataSource.reset(this.searchForm().toQuery());
2306
2343
  }
2307
2344
  }
2308
2345
  viewChanged(event) {
@@ -2320,7 +2357,7 @@ class ListViewComponent {
2320
2357
  return (url_segments.length == 2) && (url_segments[1].path == "self");
2321
2358
  }
2322
2359
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: ListViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2323
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", 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 }, listItemTemplate: { classPropertyName: "listItemTemplate", publicName: "listItemTemplate", isSignal: true, isRequired: false, transformFunction: null }, itemDetailTemplate: { classPropertyName: "itemDetailTemplate", publicName: "itemDetailTemplate", isSignal: true, isRequired: false, transformFunction: null }, itemHeight: { classPropertyName: "itemHeight", publicName: "itemHeight", isSignal: true, isRequired: false, transformFunction: null }, itemWidth: { classPropertyName: "itemWidth", publicName: "itemWidth", 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 }, defaultQueries: { classPropertyName: "defaultQueries", publicName: "defaultQueries", isSignal: true, isRequired: false, transformFunction: null }, filters: { classPropertyName: "filters", publicName: "filters", isSignal: true, isRequired: false, transformFunction: null }, embeddedMode: { classPropertyName: "embeddedMode", publicName: "embeddedMode", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selected: "selected" }, viewQueries: [{ propertyName: "sort", first: true, predicate: MatSort, descendants: true, isSignal: true }], ngImport: i0, template: "@if(!embeddedMode()){\n<lib-back-button></lib-back-button>\n}\n\n<div class=\"container\">\n <lib-list-header style=\"width:100%\" [itemType]=\"itemType()\" [canCreate]=\"canCreate()\" [showControls]=\"showControls()\" [filters]=\"filters()\"\n [sortFields]=\"sortFields()\" (searchChanged)=\"onSearchChange($event)\"></lib-list-header>\n\n <div class=\"content-container\" style=\"padding: 0px\">\n @if(dataSource)\n {\n <div class=\"result-container\" [style.width]=\"resolvedItemWidth\">\n\n @if (dataSource.loading()) {\n <div class=\"spinner-container\">\n <mat-spinner></mat-spinner>\n </div>\n }\n\n @if(!embeddedMode()){\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\n <div style=\"width: 100%\" [hidden]=\"dataSource.sourceIsEmpty()\">\n @if(isTableView()) {\n <div style=\"width: 100%; display: flex; flex-direction: row; justify-content: center; align-items: center;\">\n <lib-list-table-view style=\"width:100%; max-width:800px; display: block;\" [itemType]=\"itemType()\" [columns]=\"columns()\" [dataSource]=\"dataSource\">\n </lib-list-table-view>\n </div>\n }\n @else {\n <div class=\"scroll-container\">\n <h3>Results: {{dataSource.length()}}</h3>\n <lib-list-scroll-view [listItemTemplate]=\"listItemTemplate()\" [itemHeight]=\"itemHeight()\"\n [itemWidth]=\"itemWidth().toString()\" [dataSource]=\"dataSource\"\n (selected)=\"onSelection($event)\"></lib-list-scroll-view>\n </div>\n }\n </div>\n </div>\n @if(itemDetailTemplate()){\n <div class=\"detail-container\">\n <ng-container *ngTemplateOutlet=\"itemDetailTemplate()\">\n </ng-container>\n </div>\n }\n }\n </div>\n</div>", styles: [":host{flex-grow:1}.container{display:flex;padding-left:5px;padding-right:5px;flex-direction:column;justify-content:center;text-align:left;align-items:center}.content-container{display:flex;flex-direction:row;justify-content:left;align-items:start;width:100%}.hide-element{display:none}h3{margin-bottom:5px;margin-top:0;padding:0;text-align:center}.scroll-container{display:flex;flex-direction:column;width:100%}.detail-container{width:100%;display:flex;flex-grow:1;height:100%;min-width:400px}\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", "itemHeight", "itemWidth", "dataSource", "listItemTemplate", "routerMode"], outputs: ["selected"] }, { kind: "component", type: BackButtonComponent, selector: "lib-back-button" }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: MatButtonToggleModule }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i1$4.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: RouterModule }, { kind: "ngmodule", type: MatInputModule }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: ListHeaderComponent, selector: "lib-list-header", inputs: ["itemType", "canCreate", "showControls", "sortFields", "filters"], outputs: ["searchChanged"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
2360
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", 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 }, listItemTemplate: { classPropertyName: "listItemTemplate", publicName: "listItemTemplate", isSignal: true, isRequired: false, transformFunction: null }, itemDetailTemplate: { classPropertyName: "itemDetailTemplate", publicName: "itemDetailTemplate", isSignal: true, isRequired: false, transformFunction: null }, itemHeight: { classPropertyName: "itemHeight", publicName: "itemHeight", isSignal: true, isRequired: false, transformFunction: null }, itemWidth: { classPropertyName: "itemWidth", publicName: "itemWidth", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", 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 }, searchFields: { classPropertyName: "searchFields", publicName: "searchFields", isSignal: true, isRequired: true, transformFunction: null }, embeddedMode: { classPropertyName: "embeddedMode", publicName: "embeddedMode", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selected: "selected" }, viewQueries: [{ propertyName: "sort", first: true, predicate: MatSort, descendants: true, isSignal: true }], ngImport: i0, template: "@if(!embeddedMode()){\n<lib-back-button></lib-back-button>\n}\n\n<div class=\"container\">\n <lib-list-header style=\"width:100%\" \n [itemType]=\"itemType()\" \n [canCreate]=\"canCreate()\" \n [showControls]=\"showControls()\" \n [searchForm]=\"searchForm()\"\n [embedded]=\"embeddedMode()\"></lib-list-header>\n <div class=\"content-container\" style=\"padding: 0px\">\n @if(dataSource)\n {\n <div class=\"result-container\" [style.width]=\"resolvedItemWidth\">\n\n @if (dataSource.loading()) {\n <div class=\"spinner-container\">\n <mat-spinner></mat-spinner>\n </div>\n }\n\n @if(!embeddedMode()){\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\n <div style=\"width: 100%\" [hidden]=\"dataSource.sourceIsEmpty()\">\n @if(isTableView()) {\n <div style=\"width: 100%; display: flex; flex-direction: row; justify-content: center; align-items: center;\">\n <lib-list-table-view style=\"width:100%; max-width:800px; display: block;\" [itemType]=\"itemType()\" [columns]=\"columns()\" [dataSource]=\"dataSource\">\n </lib-list-table-view>\n </div>\n }\n @else {\n <div class=\"scroll-container\">\n <h3>Results: {{dataSource.length()}}</h3>\n <lib-list-scroll-view [listItemTemplate]=\"listItemTemplate()\" [itemHeight]=\"itemHeight()\"\n [itemWidth]=\"itemWidth().toString()\" [dataSource]=\"dataSource\"\n (selected)=\"onSelection($event)\"></lib-list-scroll-view>\n </div>\n }\n </div>\n </div>\n @if(itemDetailTemplate()){\n <div class=\"detail-container\">\n <ng-container *ngTemplateOutlet=\"itemDetailTemplate()\">\n </ng-container>\n </div>\n }\n }\n </div>\n</div>", styles: [":host{flex-grow:1}.container{display:flex;padding-left:5px;padding-right:5px;flex-direction:column;justify-content:center;text-align:left;align-items:center}.content-container{display:flex;flex-direction:row;justify-content:left;align-items:start;width:100%}.hide-element{display:none}h3{margin-bottom:5px;margin-top:0;padding:0;text-align:center}.scroll-container{display:flex;flex-direction:column;width:100%}.detail-container{width:100%;display:flex;flex-grow:1;height:100%;min-width:400px}\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: ["itemHeight", "itemWidth", "dataSource", "listItemTemplate", "routerMode"], outputs: ["selected"] }, { kind: "component", type: BackButtonComponent, selector: "lib-back-button" }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: MatButtonToggleModule }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i1$4.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: RouterModule }, { kind: "ngmodule", type: MatInputModule }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: ListHeaderComponent, selector: "lib-list-header", inputs: ["itemType", "canCreate", "showControls", "embedded", "searchForm"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
2324
2361
  }
2325
2362
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: ListViewComponent, decorators: [{
2326
2363
  type: Component,
@@ -2337,8 +2374,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImpor
2337
2374
  MatTooltipModule,
2338
2375
  MatButtonModule,
2339
2376
  ListHeaderComponent,
2340
- NgTemplateOutlet], template: "@if(!embeddedMode()){\n<lib-back-button></lib-back-button>\n}\n\n<div class=\"container\">\n <lib-list-header style=\"width:100%\" [itemType]=\"itemType()\" [canCreate]=\"canCreate()\" [showControls]=\"showControls()\" [filters]=\"filters()\"\n [sortFields]=\"sortFields()\" (searchChanged)=\"onSearchChange($event)\"></lib-list-header>\n\n <div class=\"content-container\" style=\"padding: 0px\">\n @if(dataSource)\n {\n <div class=\"result-container\" [style.width]=\"resolvedItemWidth\">\n\n @if (dataSource.loading()) {\n <div class=\"spinner-container\">\n <mat-spinner></mat-spinner>\n </div>\n }\n\n @if(!embeddedMode()){\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\n <div style=\"width: 100%\" [hidden]=\"dataSource.sourceIsEmpty()\">\n @if(isTableView()) {\n <div style=\"width: 100%; display: flex; flex-direction: row; justify-content: center; align-items: center;\">\n <lib-list-table-view style=\"width:100%; max-width:800px; display: block;\" [itemType]=\"itemType()\" [columns]=\"columns()\" [dataSource]=\"dataSource\">\n </lib-list-table-view>\n </div>\n }\n @else {\n <div class=\"scroll-container\">\n <h3>Results: {{dataSource.length()}}</h3>\n <lib-list-scroll-view [listItemTemplate]=\"listItemTemplate()\" [itemHeight]=\"itemHeight()\"\n [itemWidth]=\"itemWidth().toString()\" [dataSource]=\"dataSource\"\n (selected)=\"onSelection($event)\"></lib-list-scroll-view>\n </div>\n }\n </div>\n </div>\n @if(itemDetailTemplate()){\n <div class=\"detail-container\">\n <ng-container *ngTemplateOutlet=\"itemDetailTemplate()\">\n </ng-container>\n </div>\n }\n }\n </div>\n</div>", styles: [":host{flex-grow:1}.container{display:flex;padding-left:5px;padding-right:5px;flex-direction:column;justify-content:center;text-align:left;align-items:center}.content-container{display:flex;flex-direction:row;justify-content:left;align-items:start;width:100%}.hide-element{display:none}h3{margin-bottom:5px;margin-top:0;padding:0;text-align:center}.scroll-container{display:flex;flex-direction:column;width:100%}.detail-container{width:100%;display:flex;flex-grow:1;height:100%;min-width:400px}\n"] }]
2341
- }], propDecorators: { viewType: [{ type: i0.Input, args: [{ isSignal: true, alias: "viewType", required: false }] }], itemService: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemService", required: false }] }], listItemTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "listItemTemplate", required: false }] }], itemDetailTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemDetailTemplate", required: false }] }], itemHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemHeight", required: false }] }], itemWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemWidth", required: false }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: false }] }], sortFields: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortFields", required: false }] }], noSelfItemsMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "noSelfItemsMessage", required: false }] }], noItemsCanCreateMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "noItemsCanCreateMessage", required: false }] }], noItemsMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "noItemsMessage", required: false }] }], defaultQueries: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultQueries", required: false }] }], filters: [{ type: i0.Input, args: [{ isSignal: true, alias: "filters", required: false }] }], embeddedMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "embeddedMode", required: false }] }], selected: [{ type: i0.Output, args: ["selected"] }], sort: [{ type: i0.ViewChild, args: [i0.forwardRef(() => MatSort), { isSignal: true }] }] } });
2377
+ NgTemplateOutlet], template: "@if(!embeddedMode()){\n<lib-back-button></lib-back-button>\n}\n\n<div class=\"container\">\n <lib-list-header style=\"width:100%\" \n [itemType]=\"itemType()\" \n [canCreate]=\"canCreate()\" \n [showControls]=\"showControls()\" \n [searchForm]=\"searchForm()\"\n [embedded]=\"embeddedMode()\"></lib-list-header>\n <div class=\"content-container\" style=\"padding: 0px\">\n @if(dataSource)\n {\n <div class=\"result-container\" [style.width]=\"resolvedItemWidth\">\n\n @if (dataSource.loading()) {\n <div class=\"spinner-container\">\n <mat-spinner></mat-spinner>\n </div>\n }\n\n @if(!embeddedMode()){\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\n <div style=\"width: 100%\" [hidden]=\"dataSource.sourceIsEmpty()\">\n @if(isTableView()) {\n <div style=\"width: 100%; display: flex; flex-direction: row; justify-content: center; align-items: center;\">\n <lib-list-table-view style=\"width:100%; max-width:800px; display: block;\" [itemType]=\"itemType()\" [columns]=\"columns()\" [dataSource]=\"dataSource\">\n </lib-list-table-view>\n </div>\n }\n @else {\n <div class=\"scroll-container\">\n <h3>Results: {{dataSource.length()}}</h3>\n <lib-list-scroll-view [listItemTemplate]=\"listItemTemplate()\" [itemHeight]=\"itemHeight()\"\n [itemWidth]=\"itemWidth().toString()\" [dataSource]=\"dataSource\"\n (selected)=\"onSelection($event)\"></lib-list-scroll-view>\n </div>\n }\n </div>\n </div>\n @if(itemDetailTemplate()){\n <div class=\"detail-container\">\n <ng-container *ngTemplateOutlet=\"itemDetailTemplate()\">\n </ng-container>\n </div>\n }\n }\n </div>\n</div>", styles: [":host{flex-grow:1}.container{display:flex;padding-left:5px;padding-right:5px;flex-direction:column;justify-content:center;text-align:left;align-items:center}.content-container{display:flex;flex-direction:row;justify-content:left;align-items:start;width:100%}.hide-element{display:none}h3{margin-bottom:5px;margin-top:0;padding:0;text-align:center}.scroll-container{display:flex;flex-direction:column;width:100%}.detail-container{width:100%;display:flex;flex-grow:1;height:100%;min-width:400px}\n"] }]
2378
+ }], propDecorators: { viewType: [{ type: i0.Input, args: [{ isSignal: true, alias: "viewType", required: false }] }], itemService: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemService", required: false }] }], listItemTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "listItemTemplate", required: false }] }], itemDetailTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemDetailTemplate", required: false }] }], itemHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemHeight", required: false }] }], itemWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemWidth", required: false }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: false }] }], noSelfItemsMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "noSelfItemsMessage", required: false }] }], noItemsCanCreateMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "noItemsCanCreateMessage", required: false }] }], noItemsMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "noItemsMessage", required: false }] }], searchFields: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchFields", required: true }] }], embeddedMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "embeddedMode", required: false }] }], selected: [{ type: i0.Output, args: ["selected"] }], sort: [{ type: i0.ViewChild, args: [i0.forwardRef(() => MatSort), { isSignal: true }] }] } });
2342
2379
 
2343
2380
  class TopBarComponent {
2344
2381
  title = input(...(ngDevMode ? [undefined, { debugName: "title" }] : []));
@@ -2631,19 +2668,40 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImpor
2631
2668
  class UserComponent {
2632
2669
  itemService = inject(UserService);
2633
2670
  detailView = viewChild(UserDetailComponent, ...(ngDevMode ? [{ debugName: "detailView" }] : []));
2671
+ searchFields = new SearchFields({
2672
+ filter: {
2673
+ rows: [{
2674
+ filters: [{
2675
+ display_name: "Status",
2676
+ key: "verified",
2677
+ type: "selection",
2678
+ tooltip: "Is this user verified?",
2679
+ choices: [{ display_name: "Verified", value: 'true' },
2680
+ { display_name: "Invited", value: 'false' }
2681
+ ],
2682
+ default: "",
2683
+ include_if_null: false
2684
+ }]
2685
+ }]
2686
+ },
2687
+ sortFields: [{ display_name: "Join Date", value: "created_at" },
2688
+ { display_name: "User Name", value: "username" },
2689
+ { display_name: "Email", value: "email" }
2690
+ ]
2691
+ });
2634
2692
  onSelected(id) {
2635
2693
  if (id) {
2636
2694
  this.detailView()?.onSelection(id);
2637
2695
  }
2638
2696
  }
2639
2697
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: UserComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2640
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.0.3", type: UserComponent, isStandalone: true, selector: "lib-user", viewQueries: [{ propertyName: "detailView", first: true, predicate: UserDetailComponent, descendants: true, isSignal: true }], ngImport: i0, template: "<lib-list-view\n [itemService]=\"itemService\"\n [listItemTemplate]=\"listItemTemplate\"\n [itemDetailTemplate]=\"itemDetailTemplate\"\n [viewType]=\"'list'\"\n [itemHeight]=\"62\"\n [itemWidth]=\"400\"\n (selected)=\"onSelected($event)\"\n >\n <ng-template #listItemTemplate let-item=\"item\" let-even=\"even\" let-selected=\"selected\">\n <lib-user-list-detail [item]=\"item\" [even]=\"even\" [selected]=\"selected\"></lib-user-list-detail>\n </ng-template>\n\n <ng-template #itemDetailTemplate>\n <lib-user-detail [showBack]='false'></lib-user-detail>\n </ng-template>\n\n</lib-list-view>\n\n", styles: [":host{flex-grow:1}\n"], dependencies: [{ kind: "component", type: ListViewComponent, selector: "lib-list-view", inputs: ["viewType", "itemService", "listItemTemplate", "itemDetailTemplate", "itemHeight", "itemWidth", "columns", "sortFields", "noSelfItemsMessage", "noItemsCanCreateMessage", "noItemsMessage", "defaultQueries", "filters", "embeddedMode"], outputs: ["selected"] }, { kind: "component", type: UserListDetailComponent, selector: "lib-user-list-detail", inputs: ["item", "even", "selected"] }, { kind: "component", type: UserDetailComponent, selector: "lib-user-detail", inputs: ["showBack"] }] });
2698
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.0.3", type: UserComponent, isStandalone: true, selector: "lib-user", viewQueries: [{ propertyName: "detailView", first: true, predicate: UserDetailComponent, descendants: true, isSignal: true }], ngImport: i0, template: "<lib-list-view\n [itemService]=\"itemService\"\n [listItemTemplate]=\"listItemTemplate\"\n [itemDetailTemplate]=\"itemDetailTemplate\"\n [searchFields]=\"searchFields\"\n [viewType]=\"'list'\"\n [itemHeight]=\"62\"\n [itemWidth]=\"400\"\n (selected)=\"onSelected($event)\"\n >\n <ng-template #listItemTemplate let-item=\"item\" let-even=\"even\" let-selected=\"selected\">\n <lib-user-list-detail [item]=\"item\" [even]=\"even\" [selected]=\"selected\"></lib-user-list-detail>\n </ng-template>\n\n <ng-template #itemDetailTemplate>\n <lib-user-detail [showBack]='false'></lib-user-detail>\n </ng-template>\n\n</lib-list-view>\n\n", styles: [":host{flex-grow:1}\n"], dependencies: [{ kind: "component", type: ListViewComponent, selector: "lib-list-view", inputs: ["viewType", "itemService", "listItemTemplate", "itemDetailTemplate", "itemHeight", "itemWidth", "columns", "noSelfItemsMessage", "noItemsCanCreateMessage", "noItemsMessage", "searchFields", "embeddedMode"], outputs: ["selected"] }, { kind: "component", type: UserListDetailComponent, selector: "lib-user-list-detail", inputs: ["item", "even", "selected"] }, { kind: "component", type: UserDetailComponent, selector: "lib-user-detail", inputs: ["showBack"] }] });
2641
2699
  }
2642
2700
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: UserComponent, decorators: [{
2643
2701
  type: Component,
2644
2702
  args: [{ selector: 'lib-user', imports: [ListViewComponent,
2645
2703
  UserListDetailComponent,
2646
- UserDetailComponent], template: "<lib-list-view\n [itemService]=\"itemService\"\n [listItemTemplate]=\"listItemTemplate\"\n [itemDetailTemplate]=\"itemDetailTemplate\"\n [viewType]=\"'list'\"\n [itemHeight]=\"62\"\n [itemWidth]=\"400\"\n (selected)=\"onSelected($event)\"\n >\n <ng-template #listItemTemplate let-item=\"item\" let-even=\"even\" let-selected=\"selected\">\n <lib-user-list-detail [item]=\"item\" [even]=\"even\" [selected]=\"selected\"></lib-user-list-detail>\n </ng-template>\n\n <ng-template #itemDetailTemplate>\n <lib-user-detail [showBack]='false'></lib-user-detail>\n </ng-template>\n\n</lib-list-view>\n\n", styles: [":host{flex-grow:1}\n"] }]
2704
+ UserDetailComponent], template: "<lib-list-view\n [itemService]=\"itemService\"\n [listItemTemplate]=\"listItemTemplate\"\n [itemDetailTemplate]=\"itemDetailTemplate\"\n [searchFields]=\"searchFields\"\n [viewType]=\"'list'\"\n [itemHeight]=\"62\"\n [itemWidth]=\"400\"\n (selected)=\"onSelected($event)\"\n >\n <ng-template #listItemTemplate let-item=\"item\" let-even=\"even\" let-selected=\"selected\">\n <lib-user-list-detail [item]=\"item\" [even]=\"even\" [selected]=\"selected\"></lib-user-list-detail>\n </ng-template>\n\n <ng-template #itemDetailTemplate>\n <lib-user-detail [showBack]='false'></lib-user-detail>\n </ng-template>\n\n</lib-list-view>\n\n", styles: [":host{flex-grow:1}\n"] }]
2647
2705
  }], propDecorators: { detailView: [{ type: i0.ViewChild, args: [i0.forwardRef(() => UserDetailComponent), { isSignal: true }] }] } });
2648
2706
 
2649
2707
  class GroupDetailComponent extends DetailView {
@@ -2734,17 +2792,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImpor
2734
2792
  class GroupComponent {
2735
2793
  itemService = inject(GroupService);
2736
2794
  detailView = viewChild(GroupDetailComponent, ...(ngDevMode ? [{ debugName: "detailView" }] : []));
2795
+ searchFields = new SearchFields();
2737
2796
  onSelected(id) {
2738
2797
  if (id) {
2739
2798
  this.detailView()?.onSelection(id);
2740
2799
  }
2741
2800
  }
2742
2801
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: GroupComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2743
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.0.3", type: GroupComponent, isStandalone: true, selector: "lib-group", viewQueries: [{ propertyName: "detailView", first: true, predicate: GroupDetailComponent, descendants: true, isSignal: true }], ngImport: i0, template: "<lib-list-view\n [itemService]=\"itemService\"\n [listItemTemplate]=\"listItemTemplate\"\n [itemDetailTemplate]=\"itemDetailTemplate\"\n [viewType]=\"'list'\"\n [itemHeight]=\"42\"\n (selected)=\"onSelected($event)\"\n >\n <ng-template #listItemTemplate let-item=\"item\" let-even=\"even\" let-selected=\"selected\">\n\n <div mat-list-item class=\"container\" [class.even]=\"even && !selected\" [class.selected]=\"selected\">\n <div class=\"text-container\">\n <p matListItemTitle style=\"margin-bottom: 0px; margin-top: 0px\">{{item.name}}</p>\n </div>\n </div>\n\n </ng-template>\n\n <ng-template #itemDetailTemplate>\n <lib-group-detail [showBack]='false'></lib-group-detail>\n </ng-template>\n\n</lib-list-view>\n\n", styles: [":host{flex-grow:1}.container{height:40px;padding-top:5px;padding-left:5px;width:100%;display:flex;flex-direction:row;border-radius:6px;background-color:var(--mat-sys-surface-container-lowest)}.container:hover{background-color:var(--mat-sys-surface-container-high);cursor:pointer}.even{background-color:var(--mat-sys-surface-container-low)}.selected{background-color:var(--mat-sys-primary-container);color:var(--mat-sys-on-primary-container)}\n"], dependencies: [{ kind: "component", type: ListViewComponent, selector: "lib-list-view", inputs: ["viewType", "itemService", "listItemTemplate", "itemDetailTemplate", "itemHeight", "itemWidth", "columns", "sortFields", "noSelfItemsMessage", "noItemsCanCreateMessage", "noItemsMessage", "defaultQueries", "filters", "embeddedMode"], outputs: ["selected"] }, { kind: "component", type: GroupDetailComponent, selector: "lib-group-detail", inputs: ["showBack"] }, { kind: "ngmodule", type: MatListModule }, { kind: "directive", type: i2$1.MatListItemTitle, selector: "[matListItemTitle]" }] });
2802
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.0.3", type: GroupComponent, isStandalone: true, selector: "lib-group", viewQueries: [{ propertyName: "detailView", first: true, predicate: GroupDetailComponent, descendants: true, isSignal: true }], ngImport: i0, template: "<lib-list-view\n [itemService]=\"itemService\"\n [listItemTemplate]=\"listItemTemplate\"\n [itemDetailTemplate]=\"itemDetailTemplate\"\n [viewType]=\"'list'\"\n [itemHeight]=\"42\"\n [searchFields]=\"searchFields\"\n (selected)=\"onSelected($event)\"\n >\n <ng-template #listItemTemplate let-item=\"item\" let-even=\"even\" let-selected=\"selected\">\n\n <div mat-list-item class=\"container\" [class.even]=\"even && !selected\" [class.selected]=\"selected\">\n <div class=\"text-container\">\n <p matListItemTitle style=\"margin-bottom: 0px; margin-top: 0px\">{{item.name}}</p>\n </div>\n </div>\n\n </ng-template>\n\n <ng-template #itemDetailTemplate>\n <lib-group-detail [showBack]='false'></lib-group-detail>\n </ng-template>\n\n</lib-list-view>\n\n", styles: [":host{flex-grow:1}.container{height:40px;padding-top:5px;padding-left:5px;width:100%;display:flex;flex-direction:row;border-radius:6px;background-color:var(--mat-sys-surface-container-lowest)}.container:hover{background-color:var(--mat-sys-surface-container-high);cursor:pointer}.even{background-color:var(--mat-sys-surface-container-low)}.selected{background-color:var(--mat-sys-primary-container);color:var(--mat-sys-on-primary-container)}\n"], dependencies: [{ kind: "component", type: ListViewComponent, selector: "lib-list-view", inputs: ["viewType", "itemService", "listItemTemplate", "itemDetailTemplate", "itemHeight", "itemWidth", "columns", "noSelfItemsMessage", "noItemsCanCreateMessage", "noItemsMessage", "searchFields", "embeddedMode"], outputs: ["selected"] }, { kind: "component", type: GroupDetailComponent, selector: "lib-group-detail", inputs: ["showBack"] }, { kind: "ngmodule", type: MatListModule }, { kind: "directive", type: i2$1.MatListItemTitle, selector: "[matListItemTitle]" }] });
2744
2803
  }
2745
2804
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: GroupComponent, decorators: [{
2746
2805
  type: Component,
2747
- args: [{ selector: 'lib-group', imports: [ListViewComponent, GroupDetailComponent, MatListModule], template: "<lib-list-view\n [itemService]=\"itemService\"\n [listItemTemplate]=\"listItemTemplate\"\n [itemDetailTemplate]=\"itemDetailTemplate\"\n [viewType]=\"'list'\"\n [itemHeight]=\"42\"\n (selected)=\"onSelected($event)\"\n >\n <ng-template #listItemTemplate let-item=\"item\" let-even=\"even\" let-selected=\"selected\">\n\n <div mat-list-item class=\"container\" [class.even]=\"even && !selected\" [class.selected]=\"selected\">\n <div class=\"text-container\">\n <p matListItemTitle style=\"margin-bottom: 0px; margin-top: 0px\">{{item.name}}</p>\n </div>\n </div>\n\n </ng-template>\n\n <ng-template #itemDetailTemplate>\n <lib-group-detail [showBack]='false'></lib-group-detail>\n </ng-template>\n\n</lib-list-view>\n\n", styles: [":host{flex-grow:1}.container{height:40px;padding-top:5px;padding-left:5px;width:100%;display:flex;flex-direction:row;border-radius:6px;background-color:var(--mat-sys-surface-container-lowest)}.container:hover{background-color:var(--mat-sys-surface-container-high);cursor:pointer}.even{background-color:var(--mat-sys-surface-container-low)}.selected{background-color:var(--mat-sys-primary-container);color:var(--mat-sys-on-primary-container)}\n"] }]
2806
+ args: [{ selector: 'lib-group', imports: [ListViewComponent, GroupDetailComponent, MatListModule], template: "<lib-list-view\n [itemService]=\"itemService\"\n [listItemTemplate]=\"listItemTemplate\"\n [itemDetailTemplate]=\"itemDetailTemplate\"\n [viewType]=\"'list'\"\n [itemHeight]=\"42\"\n [searchFields]=\"searchFields\"\n (selected)=\"onSelected($event)\"\n >\n <ng-template #listItemTemplate let-item=\"item\" let-even=\"even\" let-selected=\"selected\">\n\n <div mat-list-item class=\"container\" [class.even]=\"even && !selected\" [class.selected]=\"selected\">\n <div class=\"text-container\">\n <p matListItemTitle style=\"margin-bottom: 0px; margin-top: 0px\">{{item.name}}</p>\n </div>\n </div>\n\n </ng-template>\n\n <ng-template #itemDetailTemplate>\n <lib-group-detail [showBack]='false'></lib-group-detail>\n </ng-template>\n\n</lib-list-view>\n\n", styles: [":host{flex-grow:1}.container{height:40px;padding-top:5px;padding-left:5px;width:100%;display:flex;flex-direction:row;border-radius:6px;background-color:var(--mat-sys-surface-container-lowest)}.container:hover{background-color:var(--mat-sys-surface-container-high);cursor:pointer}.even{background-color:var(--mat-sys-surface-container-low)}.selected{background-color:var(--mat-sys-primary-container);color:var(--mat-sys-on-primary-container)}\n"] }]
2748
2807
  }], propDecorators: { detailView: [{ type: i0.ViewChild, args: [i0.forwardRef(() => GroupDetailComponent), { isSignal: true }] }] } });
2749
2808
 
2750
2809
  class AddressEditComponent {
@@ -2847,7 +2906,25 @@ class OrganizationComponent {
2847
2906
  columns = [{ name: 'name', title: 'Name', element_type: 'string' },
2848
2907
  { name: 'website', title: 'Website', element_type: 'url' },
2849
2908
  { name: 'is_partner', title: 'Is Partner', element_type: 'boolean' }];
2850
- filters = null;
2909
+ searchFields = new SearchFields({
2910
+ filter: {
2911
+ rows: [{
2912
+ filters: [{
2913
+ display_name: "Country",
2914
+ key: "country_name",
2915
+ type: "selection",
2916
+ tooltip: "",
2917
+ choices: [],
2918
+ default: "",
2919
+ include_if_null: false
2920
+ }]
2921
+ }]
2922
+ },
2923
+ sortFields: [{ display_name: "Age", value: "created_at" },
2924
+ { display_name: "Last Updated", value: "updated_at" },
2925
+ { display_name: "Name", value: "name" }
2926
+ ]
2927
+ });
2851
2928
  detailView = viewChild(OrganizationDetailComponent, ...(ngDevMode ? [{ debugName: "detailView" }] : []));
2852
2929
  onSelected(id) {
2853
2930
  if (id) {
@@ -2855,14 +2932,14 @@ class OrganizationComponent {
2855
2932
  }
2856
2933
  }
2857
2934
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: OrganizationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2858
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", type: OrganizationComponent, isStandalone: true, selector: "lib-organization", viewQueries: [{ propertyName: "detailView", first: true, predicate: OrganizationDetailComponent, descendants: true, isSignal: true }], ngImport: i0, template: "<lib-list-view\n [itemService]=\"itemService\"\n [listItemTemplate]=\"listItemTemplate\"\n [itemDetailTemplate]=\"itemDetailTemplate\"\n [viewType]=\"'list'\"\n [itemHeight]=\"82\"\n [itemWidth]=\"400\"\n [filters]=\"filters\"\n (selected)=\"onSelected($event)\"\n >\n <ng-template #listItemTemplate let-item=\"item\" let-even=\"even\" let-selected=\"selected\">\n <div mat-list-item class=\"container\" [class.even]=\"even && !selected\" [class.selected]=\"selected\">\n <div class=\"text-container\">\n <p matListItemTitle style=\"margin-bottom: 0px; margin-top: 0px\">{{item.name}}</p>\n @if(item.address.region && item.address.country_name){\n <p matListItemLine style=\"margin-bottom: 0px; margin-top: 0px\">\n {{item.address.region}}, {{item.address.country_name}}\n </p>\n }\n </div>\n </div>\n </ng-template>\n\n <ng-template #itemDetailTemplate>\n <lib-organization-detail [showBack]='false'></lib-organization-detail>\n </ng-template>\n\n</lib-list-view>\n\n\n\n", styles: [":host{flex-grow:1}.container{height:80px;padding-left:5px;padding-top:5px;border-radius:12px;width:100%;display:flex;flex-direction:row;background-color:var(--mat-sys-surface-container-lowest)}.container:hover{background-color:var(--mat-sys-surface-container-high);cursor:pointer}.even{background-color:var(--mat-sys-surface-container-low)}.selected{background-color:var(--mat-sys-primary-container);color:var(--mat-sys-on-primary-container)}\n"], dependencies: [{ kind: "component", type: ListViewComponent, selector: "lib-list-view", inputs: ["viewType", "itemService", "listItemTemplate", "itemDetailTemplate", "itemHeight", "itemWidth", "columns", "sortFields", "noSelfItemsMessage", "noItemsCanCreateMessage", "noItemsMessage", "defaultQueries", "filters", "embeddedMode"], outputs: ["selected"] }, { kind: "component", type: OrganizationDetailComponent, selector: "lib-organization-detail", inputs: ["showBack"] }] });
2935
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", type: OrganizationComponent, isStandalone: true, selector: "lib-organization", viewQueries: [{ propertyName: "detailView", first: true, predicate: OrganizationDetailComponent, descendants: true, isSignal: true }], ngImport: i0, template: "<lib-list-view\n [itemService]=\"itemService\"\n [listItemTemplate]=\"listItemTemplate\"\n [itemDetailTemplate]=\"itemDetailTemplate\"\n [viewType]=\"'list'\"\n [itemHeight]=\"82\"\n [itemWidth]=\"400\"\n [searchFields]=\"searchFields\"\n (selected)=\"onSelected($event)\"\n >\n <ng-template #listItemTemplate let-item=\"item\" let-even=\"even\" let-selected=\"selected\">\n <div mat-list-item class=\"container\" [class.even]=\"even && !selected\" [class.selected]=\"selected\">\n <div class=\"text-container\">\n <p matListItemTitle style=\"margin-bottom: 0px; margin-top: 0px\">{{item.name}}</p>\n @if(item.address.region && item.address.country_name){\n <p matListItemLine style=\"margin-bottom: 0px; margin-top: 0px\">\n {{item.address.region}}, {{item.address.country_name}}\n </p>\n }\n </div>\n </div>\n </ng-template>\n\n <ng-template #itemDetailTemplate>\n <lib-organization-detail [showBack]='false'></lib-organization-detail>\n </ng-template>\n\n</lib-list-view>\n\n\n\n", styles: [":host{flex-grow:1}.container{height:80px;padding-left:5px;padding-top:5px;border-radius:12px;width:100%;display:flex;flex-direction:row;background-color:var(--mat-sys-surface-container-lowest)}.container:hover{background-color:var(--mat-sys-surface-container-high);cursor:pointer}.even{background-color:var(--mat-sys-surface-container-low)}.selected{background-color:var(--mat-sys-primary-container);color:var(--mat-sys-on-primary-container)}\n"], dependencies: [{ kind: "component", type: ListViewComponent, selector: "lib-list-view", inputs: ["viewType", "itemService", "listItemTemplate", "itemDetailTemplate", "itemHeight", "itemWidth", "columns", "noSelfItemsMessage", "noItemsCanCreateMessage", "noItemsMessage", "searchFields", "embeddedMode"], outputs: ["selected"] }, { kind: "component", type: OrganizationDetailComponent, selector: "lib-organization-detail", inputs: ["showBack"] }] });
2859
2936
  }
2860
2937
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: OrganizationComponent, decorators: [{
2861
2938
  type: Component,
2862
2939
  args: [{ selector: 'lib-organization', imports: [
2863
2940
  ListViewComponent,
2864
2941
  OrganizationDetailComponent
2865
- ], template: "<lib-list-view\n [itemService]=\"itemService\"\n [listItemTemplate]=\"listItemTemplate\"\n [itemDetailTemplate]=\"itemDetailTemplate\"\n [viewType]=\"'list'\"\n [itemHeight]=\"82\"\n [itemWidth]=\"400\"\n [filters]=\"filters\"\n (selected)=\"onSelected($event)\"\n >\n <ng-template #listItemTemplate let-item=\"item\" let-even=\"even\" let-selected=\"selected\">\n <div mat-list-item class=\"container\" [class.even]=\"even && !selected\" [class.selected]=\"selected\">\n <div class=\"text-container\">\n <p matListItemTitle style=\"margin-bottom: 0px; margin-top: 0px\">{{item.name}}</p>\n @if(item.address.region && item.address.country_name){\n <p matListItemLine style=\"margin-bottom: 0px; margin-top: 0px\">\n {{item.address.region}}, {{item.address.country_name}}\n </p>\n }\n </div>\n </div>\n </ng-template>\n\n <ng-template #itemDetailTemplate>\n <lib-organization-detail [showBack]='false'></lib-organization-detail>\n </ng-template>\n\n</lib-list-view>\n\n\n\n", styles: [":host{flex-grow:1}.container{height:80px;padding-left:5px;padding-top:5px;border-radius:12px;width:100%;display:flex;flex-direction:row;background-color:var(--mat-sys-surface-container-lowest)}.container:hover{background-color:var(--mat-sys-surface-container-high);cursor:pointer}.even{background-color:var(--mat-sys-surface-container-low)}.selected{background-color:var(--mat-sys-primary-container);color:var(--mat-sys-on-primary-container)}\n"] }]
2942
+ ], template: "<lib-list-view\n [itemService]=\"itemService\"\n [listItemTemplate]=\"listItemTemplate\"\n [itemDetailTemplate]=\"itemDetailTemplate\"\n [viewType]=\"'list'\"\n [itemHeight]=\"82\"\n [itemWidth]=\"400\"\n [searchFields]=\"searchFields\"\n (selected)=\"onSelected($event)\"\n >\n <ng-template #listItemTemplate let-item=\"item\" let-even=\"even\" let-selected=\"selected\">\n <div mat-list-item class=\"container\" [class.even]=\"even && !selected\" [class.selected]=\"selected\">\n <div class=\"text-container\">\n <p matListItemTitle style=\"margin-bottom: 0px; margin-top: 0px\">{{item.name}}</p>\n @if(item.address.region && item.address.country_name){\n <p matListItemLine style=\"margin-bottom: 0px; margin-top: 0px\">\n {{item.address.region}}, {{item.address.country_name}}\n </p>\n }\n </div>\n </div>\n </ng-template>\n\n <ng-template #itemDetailTemplate>\n <lib-organization-detail [showBack]='false'></lib-organization-detail>\n </ng-template>\n\n</lib-list-view>\n\n\n\n", styles: [":host{flex-grow:1}.container{height:80px;padding-left:5px;padding-top:5px;border-radius:12px;width:100%;display:flex;flex-direction:row;background-color:var(--mat-sys-surface-container-lowest)}.container:hover{background-color:var(--mat-sys-surface-container-high);cursor:pointer}.even{background-color:var(--mat-sys-surface-container-low)}.selected{background-color:var(--mat-sys-primary-container);color:var(--mat-sys-on-primary-container)}\n"] }]
2866
2943
  }], propDecorators: { detailView: [{ type: i0.ViewChild, args: [i0.forwardRef(() => OrganizationDetailComponent), { isSignal: true }] }] } });
2867
2944
 
2868
2945
  class OrganizationForm {
@@ -2981,5 +3058,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImpor
2981
3058
  * Generated bundle index. Do not edit.
2982
3059
  */
2983
3060
 
2984
- export { Address, AddressDetailComponent, AddressEditComponent, AddressForm, ApiError, AvatarComponent, BackButtonComponent, DetailHeaderComponent, DetailView, DynamicFormBuilderComponent, DynamicFormComponent, DynamicFormForm, EditView, ErrorCode, FORM_FIELD_CHOICES, FeedbackComponent, FieldType, FileRecord, FileUploadComponent, FormFieldDetailComponent, FormFieldEditComponent, FormFieldValueForm, FormService, Group, GroupComponent, GroupDetailComponent, GroupEditComponent, GroupService, ItemQuery, ItemService, ItemWithUserService, LeftNavComponent, LeftNavService, ListTableViewComponent, ListViewComponent, MemberSelectionManager, MockItemService, Organization, OrganizationComponent, OrganizationDetailComponent, OrganizationEditComponent, OrganizationService, Paginated, Permission, PopulatedFormComponent, PopulatedFormForm, PortalMember, REST_SERVICE_CONFIG, ResolvedPermission, RestService, SearchBarComponent, SelectTableComponent, SelectionManager, TopBarComponent, UserComponent, UserCreateComponent, UserDetailComponent, UserEditComponent, UserService, getFieldTypeFromKey, getFileFieldIds };
3061
+ export { Address, AddressDetailComponent, AddressEditComponent, AddressForm, ApiError, AvatarComponent, BackButtonComponent, DetailHeaderComponent, DetailView, DynamicFormBuilderComponent, DynamicFormComponent, DynamicFormForm, EditView, ErrorCode, FORM_FIELD_CHOICES, FeedbackComponent, FieldType, FileRecord, FileUploadComponent, FormFieldDetailComponent, FormFieldEditComponent, FormFieldValueForm, FormService, Group, GroupComponent, GroupDetailComponent, GroupEditComponent, GroupService, ItemQuery, ItemService, ItemWithUserService, LeftNavComponent, LeftNavService, ListTableViewComponent, ListViewComponent, MemberSelectionManager, MockItemService, Organization, OrganizationComponent, OrganizationDetailComponent, OrganizationEditComponent, OrganizationService, Paginated, Permission, PopulatedFormComponent, PopulatedFormForm, PortalMember, REST_SERVICE_CONFIG, ResolvedPermission, RestService, SearchBarComponent, SearchFields, SelectTableComponent, SelectionManager, TopBarComponent, UserComponent, UserCreateComponent, UserCreateForm, UserDetailComponent, UserEditComponent, UserService, getFieldTypeFromKey, getFileFieldIds, getFilter };
2985
3062
  //# sourceMappingURL=ichec-angular-core.mjs.map