@wertzui/ngx-restworld-client 17.1.1 → 18.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/wertzui-ngx-restworld-client.mjs +1624 -1543
- package/fesm2022/wertzui-ngx-restworld-client.mjs.map +1 -1
- package/index.d.ts +34 -26
- package/index.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Injectable, input, computed, Component, Pipe, forwardRef, model, numberAttribute, booleanAttribute, output, viewChild, contentChild, contentChildren, inject, ViewEncapsulation, ChangeDetectionStrategy,
|
|
2
|
+
import { Injectable, input, computed, Component, Pipe, forwardRef, model, numberAttribute, booleanAttribute, output, viewChild, contentChild, contentChildren, inject, ViewEncapsulation, ChangeDetectionStrategy, signal, resource, viewChildren, effect, Self, Directive, Optional, Host, SkipSelf, Inject, NgModule, untracked, ContentChild, linkedSignal, provideAppInitializer } from '@angular/core';
|
|
3
3
|
import * as i2 from 'primeng/avatar';
|
|
4
4
|
import { AvatarModule } from 'primeng/avatar';
|
|
5
5
|
import * as i3 from 'primeng/tooltip';
|
|
@@ -9,7 +9,7 @@ import { AsyncPipe, CommonModule, NgTemplateOutlet } from '@angular/common';
|
|
|
9
9
|
import * as i1$1 from '@wertzui/ngx-hal-client';
|
|
10
10
|
import { Property, PropertyType, ProblemDetails, ResourceFactory, Link, NumberTemplate, Template, PagedListResource } from '@wertzui/ngx-hal-client';
|
|
11
11
|
import * as i2$3 from '@angular/forms';
|
|
12
|
-
import { FormGroupDirective, ControlContainer, NG_VALUE_ACCESSOR, NgControl, UntypedFormGroup, UntypedFormArray, FormsModule, FormControlName, NG_VALIDATORS, NG_ASYNC_VALIDATORS, DefaultValueAccessor, CheckboxControlValueAccessor, SelectControlValueAccessor, RangeValueAccessor, NumberValueAccessor, NgControlStatus, ReactiveFormsModule, FormGroup, FormControl, Validators
|
|
12
|
+
import { FormGroupDirective, ControlContainer, NG_VALUE_ACCESSOR, NgControl, UntypedFormGroup, UntypedFormArray, FormsModule, FormControlName, NG_VALIDATORS, NG_ASYNC_VALIDATORS, DefaultValueAccessor, CheckboxControlValueAccessor, SelectControlValueAccessor, RangeValueAccessor, NumberValueAccessor, NgControlStatus, ReactiveFormsModule, FormArrayName, FormGroup, FormControl, Validators } from '@angular/forms';
|
|
13
13
|
import * as clrFormat from 'clr-format';
|
|
14
14
|
import * as i2$1 from 'primeng/api';
|
|
15
15
|
import { PrimeTemplate, SharedModule, FilterMatchMode, TranslationKeys } from 'primeng/api';
|
|
@@ -17,17 +17,16 @@ import { BaseComponent } from 'primeng/basecomponent';
|
|
|
17
17
|
import { CheckboxStyle } from 'primeng/checkbox';
|
|
18
18
|
import { HttpHeaders, HttpEventType, HTTP_INTERCEPTORS } from '@angular/common/http';
|
|
19
19
|
import { NgHttpCachingHeaders, withNgHttpCachingLocalStorage, NgHttpCachingStrategy, provideNgHttpCaching } from 'ng-http-caching';
|
|
20
|
-
import { lastValueFrom, merge, map, mergeMap, tap, finalize } from 'rxjs';
|
|
20
|
+
import { lastValueFrom, merge, map, mergeMap, distinctUntilChanged, switchMap, EMPTY, debounceTime, startWith, tap, finalize } from 'rxjs';
|
|
21
21
|
import * as i1$3 from 'primeng/button';
|
|
22
22
|
import { ButtonModule, ButtonDirective } from 'primeng/button';
|
|
23
23
|
import * as i2$2 from 'primeng/fileupload';
|
|
24
24
|
import { FileUploadModule, FileUpload } from 'primeng/fileupload';
|
|
25
25
|
import * as i1$2 from '@angular/platform-browser';
|
|
26
|
-
import * as
|
|
26
|
+
import * as i5 from 'ngx-valdemort';
|
|
27
27
|
import { ValidationErrorsComponent, ValidationErrorDirective } from 'ngx-valdemort';
|
|
28
28
|
import * as i1$4 from 'primeng/message';
|
|
29
29
|
import { MessageModule } from 'primeng/message';
|
|
30
|
-
import * as i3$3 from '@angular/cdk/drag-drop';
|
|
31
30
|
import { DragDropModule } from '@angular/cdk/drag-drop';
|
|
32
31
|
import * as i3$2 from 'primeng/multiselect';
|
|
33
32
|
import { MultiSelect } from 'primeng/multiselect';
|
|
@@ -45,21 +44,21 @@ import { ColorPickerModule } from 'primeng/colorpicker';
|
|
|
45
44
|
import { InputText } from 'primeng/inputtext';
|
|
46
45
|
import { SIGNAL, signalSetFn } from '@angular/core/primitives/signals';
|
|
47
46
|
import { toSignal, toObservable } from '@angular/core/rxjs-interop';
|
|
48
|
-
import * as i6 from 'primeng/progressspinner';
|
|
49
|
-
import { ProgressSpinnerModule } from 'primeng/progressspinner';
|
|
50
|
-
import * as i8 from 'primeng/ripple';
|
|
51
|
-
import { RippleModule } from 'primeng/ripple';
|
|
52
|
-
import * as i3$4 from '@angular/router';
|
|
53
|
-
import { NavigationEnd } from '@angular/router';
|
|
54
|
-
import * as i4$1 from 'primeng/splitbutton';
|
|
55
|
-
import { SplitButtonModule } from 'primeng/splitbutton';
|
|
56
47
|
import { createTraverser, TokenType, defaultParser } from '@odata/parser';
|
|
57
48
|
import { PrimitiveTypeEnum } from '@odata/metadata';
|
|
58
49
|
import * as i7 from 'primeng/contextmenu';
|
|
59
50
|
import { ContextMenuModule } from 'primeng/contextmenu';
|
|
60
|
-
import * as
|
|
51
|
+
import * as i6 from 'primeng/table';
|
|
61
52
|
import { TableModule } from 'primeng/table';
|
|
53
|
+
import * as i4$1 from 'primeng/splitbutton';
|
|
54
|
+
import { SplitButtonModule } from 'primeng/splitbutton';
|
|
55
|
+
import * as i3$3 from '@angular/router';
|
|
56
|
+
import { NavigationEnd } from '@angular/router';
|
|
62
57
|
import * as i4$2 from 'primeng/config';
|
|
58
|
+
import * as i6$1 from 'primeng/progressspinner';
|
|
59
|
+
import { ProgressSpinnerModule } from 'primeng/progressspinner';
|
|
60
|
+
import * as i8 from 'primeng/ripple';
|
|
61
|
+
import { RippleModule } from 'primeng/ripple';
|
|
63
62
|
import { WebTracerProvider, SimpleSpanProcessor, ConsoleSpanExporter, BatchSpanProcessor, AlwaysOnSampler, ParentBasedSampler, TraceIdRatioBasedSampler, AlwaysOffSampler } from '@opentelemetry/sdk-trace-web';
|
|
64
63
|
import { ZoneContextManager } from '@opentelemetry/context-zone-peer-dep';
|
|
65
64
|
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto';
|
|
@@ -67,11 +66,11 @@ import { resourceFromAttributes } from '@opentelemetry/resources';
|
|
|
67
66
|
import { trace, context, SpanKind, propagation, SpanStatusCode } from '@opentelemetry/api';
|
|
68
67
|
import { filter } from 'rxjs/operators';
|
|
69
68
|
import { ATTR_SERVICE_NAME, ATTR_HTTP_REQUEST_HEADER, ATTR_CLIENT_PORT, ATTR_CLIENT_ADDRESS, ATTR_URL_SCHEME, ATTR_URL_QUERY, ATTR_URL_PATH, ATTR_URL_FULL, ATTR_HTTP_REQUEST_METHOD, ATTR_HTTP_RESPONSE_STATUS_CODE, ATTR_HTTP_RESPONSE_HEADER } from '@opentelemetry/semantic-conventions';
|
|
70
|
-
import * as
|
|
69
|
+
import * as i8$1 from 'primeng/confirmdialog';
|
|
71
70
|
import { ConfirmDialogModule } from 'primeng/confirmdialog';
|
|
72
|
-
import * as
|
|
71
|
+
import * as i6$2 from 'primeng/skeleton';
|
|
73
72
|
import { SkeletonModule } from 'primeng/skeleton';
|
|
74
|
-
import * as
|
|
73
|
+
import * as i7$1 from 'primeng/tabs';
|
|
75
74
|
import { TabsModule } from 'primeng/tabs';
|
|
76
75
|
|
|
77
76
|
/**
|
|
@@ -807,8 +806,8 @@ class ProblemService {
|
|
|
807
806
|
* @param defaultTitle The default title to display if the problem details do not contain a title.
|
|
808
807
|
*/
|
|
809
808
|
displayToast(problemDetails, defaultDetail = "Error", defaultTitle = "Error") {
|
|
810
|
-
const summary = problemDetails
|
|
811
|
-
const detail = problemDetails
|
|
809
|
+
const summary = problemDetails?.title ?? defaultTitle;
|
|
810
|
+
const detail = problemDetails?.detail ?? defaultDetail;
|
|
812
811
|
this._messageService.add({ severity: "error", summary: summary, detail: detail, sticky: true });
|
|
813
812
|
}
|
|
814
813
|
/**
|
|
@@ -1559,24 +1558,68 @@ class OptionsManager {
|
|
|
1559
1558
|
_clients;
|
|
1560
1559
|
apiName;
|
|
1561
1560
|
property;
|
|
1562
|
-
|
|
1561
|
+
_selectedValues;
|
|
1563
1562
|
_getLabel;
|
|
1564
1563
|
_getTooltip;
|
|
1565
1564
|
getLabel = computed(() => this._getLabel() ?? ((itemOrValue) => this.getDefaultLabel(itemOrValue)), ...(ngDevMode ? [{ debugName: "getLabel" }] : []));
|
|
1566
1565
|
getTooltip = computed(() => this._getTooltip() ?? ((itemOrValue) => this.getDefaultTooltip(itemOrValue)), ...(ngDevMode ? [{ debugName: "getTooltip" }] : []));
|
|
1567
|
-
items = linkedSignal(() => this.options()?.inline ?? []);
|
|
1568
|
-
loading =
|
|
1566
|
+
// public readonly items = linkedSignal(() => this.options()?.inline as TOptionsItem[] ?? []);
|
|
1567
|
+
loading = computed(() => this.items.isLoading(), ...(ngDevMode ? [{ debugName: "loading" }] : []));
|
|
1569
1568
|
options = computed(() => this.property().options, ...(ngDevMode ? [{ debugName: "options" }] : []));
|
|
1570
1569
|
promptField = computed(() => this.options()?.promptField ?? "prompt", ...(ngDevMode ? [{ debugName: "promptField" }] : []));
|
|
1571
1570
|
valueField = computed(() => this.options()?.valueField ?? "value", ...(ngDevMode ? [{ debugName: "valueField" }] : []));
|
|
1572
1571
|
_client = computed(() => this._clients.getClient(this.apiName()), ...(ngDevMode ? [{ debugName: "_client" }] : []));
|
|
1573
|
-
selectedItems = computed(() => this.selectedValues()?.map(value => this.getItemByValue(this.items(), value) ?? []), ...(ngDevMode ? [{ debugName: "selectedItems" }] : []));
|
|
1574
|
-
|
|
1572
|
+
selectedItems = computed(() => this.selectedValues()?.map(value => this.getItemByValue(this.items.value(), value) ?? []), ...(ngDevMode ? [{ debugName: "selectedItems" }] : []));
|
|
1573
|
+
selectedValues = computed(() => {
|
|
1574
|
+
const values = this._selectedValues();
|
|
1575
|
+
if (values === null || values === undefined)
|
|
1576
|
+
return [];
|
|
1577
|
+
return (Array.isArray(values) ? values : [values]);
|
|
1578
|
+
}, ...(ngDevMode ? [{ debugName: "selectedValues" }] : []));
|
|
1579
|
+
filter = signal(undefined, ...(ngDevMode ? [{ debugName: "filter" }] : []));
|
|
1580
|
+
_lastFilter = undefined;
|
|
1581
|
+
items = resource({
|
|
1582
|
+
params: () => ({ filter: this.filter(), options: this.options(), selectedValues: this.selectedValues() }),
|
|
1583
|
+
loader: async ({ params }) => {
|
|
1584
|
+
const options = params.options;
|
|
1585
|
+
let filter = params.filter;
|
|
1586
|
+
const selectedValues = params.selectedValues;
|
|
1587
|
+
// We have inline options, so we don't need to load them from the server.
|
|
1588
|
+
if (Array.isArray(options?.inline) && options.inline.length > 0)
|
|
1589
|
+
return options.inline;
|
|
1590
|
+
// First load: there might be selected items, but the user has not typed in a filter yet.
|
|
1591
|
+
// In this case, we want to load the selected items to be able to show them in the dropdown.
|
|
1592
|
+
if (filter === undefined && selectedValues.length > 0)
|
|
1593
|
+
filter = `${options.valueField} in (${selectedValues})`;
|
|
1594
|
+
// Only make the call if the filter has changed.
|
|
1595
|
+
// This prevents unnecessary calls when the selected values change but the filter is the same.
|
|
1596
|
+
if (filter === this._lastFilter) {
|
|
1597
|
+
const currentItems = this.items.value();
|
|
1598
|
+
if (currentItems === undefined)
|
|
1599
|
+
return [];
|
|
1600
|
+
return currentItems;
|
|
1601
|
+
}
|
|
1602
|
+
this._lastFilter = filter;
|
|
1603
|
+
const templatedUri = options.link?.href;
|
|
1604
|
+
if (!templatedUri) {
|
|
1605
|
+
this._problemService.displayToast(undefined, `The property ${this.property().name} does not have options with a link href.`);
|
|
1606
|
+
return [];
|
|
1607
|
+
}
|
|
1608
|
+
const headersWithCaching = new HttpHeaders({ [NgHttpCachingHeaders.ALLOW_CACHE]: "1", [NgHttpCachingHeaders.LIFETIME]: "3000" });
|
|
1609
|
+
const response = await this._client().getListByUri(templatedUri, { $filter: filter, $top: 10 }, headersWithCaching);
|
|
1610
|
+
this._problemService.checkResponseDisplayErrorsAndThrow(response, undefined, `An error occurred while getting the selected items for the property ${this.property().name}.`);
|
|
1611
|
+
const oldItems = this.items.value();
|
|
1612
|
+
const newItems = response.body._embedded.items;
|
|
1613
|
+
const combinedItems = this.combineCurrentItemsWithSelected(oldItems, selectedValues, newItems);
|
|
1614
|
+
return combinedItems;
|
|
1615
|
+
}
|
|
1616
|
+
});
|
|
1617
|
+
constructor(_problemService, _clients, apiName, property, _selectedValues, _getLabel, _getTooltip) {
|
|
1575
1618
|
this._problemService = _problemService;
|
|
1576
1619
|
this._clients = _clients;
|
|
1577
1620
|
this.apiName = apiName;
|
|
1578
1621
|
this.property = property;
|
|
1579
|
-
this.
|
|
1622
|
+
this._selectedValues = _selectedValues;
|
|
1580
1623
|
this._getLabel = _getLabel;
|
|
1581
1624
|
this._getTooltip = _getTooltip;
|
|
1582
1625
|
}
|
|
@@ -1589,7 +1632,7 @@ class OptionsManager {
|
|
|
1589
1632
|
return shortened;
|
|
1590
1633
|
}
|
|
1591
1634
|
getItemByValue(items, value) {
|
|
1592
|
-
const foundItem = items
|
|
1635
|
+
const foundItem = items?.find(item => this.getValue(item) === value);
|
|
1593
1636
|
if (foundItem)
|
|
1594
1637
|
return foundItem;
|
|
1595
1638
|
if (value === null || value === undefined)
|
|
@@ -1606,7 +1649,7 @@ class OptionsManager {
|
|
|
1606
1649
|
let item = itemOrValue;
|
|
1607
1650
|
if (itemOrValue === undefined || itemOrValue === null || !itemOrValue.hasOwnProperty(promptField)) {
|
|
1608
1651
|
const value = itemOrValue;
|
|
1609
|
-
item = this.getItemByValue(this.items(), value);
|
|
1652
|
+
item = this.getItemByValue(this.items.value(), value);
|
|
1610
1653
|
}
|
|
1611
1654
|
if (item === undefined || item === null || !item.hasOwnProperty(promptField))
|
|
1612
1655
|
return "";
|
|
@@ -1626,53 +1669,21 @@ class OptionsManager {
|
|
|
1626
1669
|
const item = itemOrValue;
|
|
1627
1670
|
return item[valueField];
|
|
1628
1671
|
}
|
|
1629
|
-
/**
|
|
1630
|
-
* Initializes the options manager.
|
|
1631
|
-
* This will load the initial options for the property.
|
|
1632
|
-
* Call it once in the ngOnInit method of your component.
|
|
1633
|
-
*/
|
|
1634
|
-
async initialize() {
|
|
1635
|
-
const options = this.options();
|
|
1636
|
-
if (!options.link?.href)
|
|
1637
|
-
return;
|
|
1638
|
-
const selectedValues = this.selectedValues() ?? options.selectedValues;
|
|
1639
|
-
const filter = selectedValues === null || selectedValues === undefined ?
|
|
1640
|
-
undefined :
|
|
1641
|
-
`${options.valueField} in (${selectedValues})`;
|
|
1642
|
-
await this.updateItemsFromFilter(filter);
|
|
1643
|
-
}
|
|
1644
1672
|
/**
|
|
1645
1673
|
* Updates the items based on the given filter.
|
|
1646
1674
|
* @param filter The filter to use when getting the items.
|
|
1647
1675
|
*/
|
|
1648
1676
|
async updateItemsFromFilter(filter) {
|
|
1649
|
-
this.
|
|
1650
|
-
try {
|
|
1651
|
-
const options = this.options();
|
|
1652
|
-
const templatedUri = options.link?.href;
|
|
1653
|
-
if (!templatedUri)
|
|
1654
|
-
this._problemService.displayToastAndThrow(undefined, `The property ${this.property().name} does not have options with a link href.`);
|
|
1655
|
-
const headersWithCaching = new HttpHeaders({ [NgHttpCachingHeaders.ALLOW_CACHE]: "1", [NgHttpCachingHeaders.LIFETIME]: "3000" });
|
|
1656
|
-
const response = await this._client().getListByUri(templatedUri, { $filter: filter, $top: 10 }, headersWithCaching);
|
|
1657
|
-
this._problemService.checkResponseDisplayErrorsAndThrow(response, undefined, `An error occurred while getting the selected items for the property ${this.property().name}.`);
|
|
1658
|
-
const items = response.body._embedded.items;
|
|
1659
|
-
const newItems = this.combineCurrentItemsWithSelected(items);
|
|
1660
|
-
this.items.set(newItems);
|
|
1661
|
-
}
|
|
1662
|
-
finally {
|
|
1663
|
-
this.loading.set(false);
|
|
1664
|
-
}
|
|
1677
|
+
this.filter.set(filter);
|
|
1665
1678
|
}
|
|
1666
|
-
combineCurrentItemsWithSelected(
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
const
|
|
1671
|
-
const
|
|
1672
|
-
const
|
|
1673
|
-
|
|
1674
|
-
const newItems = items.concat(itemsToKeep.filter(i => !newValues.includes(this.getValue(i))));
|
|
1675
|
-
return newItems;
|
|
1679
|
+
combineCurrentItemsWithSelected(oldItems, selectedValues, newItems) {
|
|
1680
|
+
if (!oldItems)
|
|
1681
|
+
return newItems;
|
|
1682
|
+
// const selectedValuesAsArray = (Array.isArray(selectedValues) ? selectedValues : [selectedValues]) as ExtractGenericOptionsSelectedValuesType<TProperty>[];
|
|
1683
|
+
const itemsToKeep = oldItems.filter(i => selectedValues.includes(this.getValue(i)));
|
|
1684
|
+
const newValues = newItems.map(i => this.getValue(i));
|
|
1685
|
+
const combinedItems = newItems.concat(itemsToKeep.filter(i => !newValues.includes(this.getValue(i))));
|
|
1686
|
+
return combinedItems;
|
|
1676
1687
|
}
|
|
1677
1688
|
getDefaultLabel(itemOrValue) {
|
|
1678
1689
|
if (itemOrValue === undefined || itemOrValue === null)
|
|
@@ -1864,9 +1875,6 @@ class RestWorldDisplayDropdownComponent {
|
|
|
1864
1875
|
constructor(optionsService) {
|
|
1865
1876
|
this.optionsManager = optionsService.getManager(this.apiName, this.property, this.selectedValues, this.getLabel, this.getTooltip);
|
|
1866
1877
|
}
|
|
1867
|
-
async ngOnInit() {
|
|
1868
|
-
await this.optionsManager.initialize();
|
|
1869
|
-
}
|
|
1870
1878
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: RestWorldDisplayDropdownComponent, deps: [{ token: OptionsService }], target: i0.ɵɵFactoryTarget.Component });
|
|
1871
1879
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.1", type: RestWorldDisplayDropdownComponent, isStandalone: true, selector: "rw-display-dropdown", inputs: { apiName: { classPropertyName: "apiName", publicName: "apiName", isSignal: true, isRequired: true, transformFunction: null }, getLabel: { classPropertyName: "getLabel", publicName: "getLabel", isSignal: true, isRequired: false, transformFunction: null }, getTooltip: { classPropertyName: "getTooltip", publicName: "getTooltip", isSignal: true, isRequired: false, transformFunction: null }, property: { classPropertyName: "property", publicName: "property", isSignal: true, isRequired: true, transformFunction: null }, selectedValues: { classPropertyName: "selectedValues", publicName: "selectedValues", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@for (item of optionsManager.selectedItems(); track item; let last = $last) {\r\n <span [pTooltip]=\"optionsManager.getTooltip()($any(item))\">{{optionsManager.getLabel()($any(item))}}</span>{{last ? \"\" : \", \"}}\r\n}\r\n", styles: [""], dependencies: [{ kind: "directive", type: Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo"] }] });
|
|
1872
1880
|
}
|
|
@@ -2721,1657 +2729,1715 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImpor
|
|
|
2721
2729
|
}] });
|
|
2722
2730
|
|
|
2723
2731
|
/**
|
|
2724
|
-
*
|
|
2732
|
+
* This visitor turns a parsed OData $filter query string represented as a {@link Token} into a map of property names to filter metadata.
|
|
2733
|
+
* The filter metadata is used by the PrimeNG table component to filter the rows of
|
|
2734
|
+
* a table based on the values of the columns.
|
|
2725
2735
|
*/
|
|
2726
|
-
class
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2736
|
+
class OdataVisitor {
|
|
2737
|
+
_filters = new Map();
|
|
2738
|
+
operator;
|
|
2739
|
+
propertyName;
|
|
2740
|
+
value;
|
|
2741
|
+
static correctFilterMatchMode(matchMode, literalValue) {
|
|
2742
|
+
if (literalValue instanceof Date) {
|
|
2743
|
+
switch (matchMode) {
|
|
2744
|
+
case FilterMatchMode.EQUALS:
|
|
2745
|
+
return FilterMatchMode.DATE_IS;
|
|
2746
|
+
case FilterMatchMode.NOT_EQUALS:
|
|
2747
|
+
return FilterMatchMode.DATE_IS_NOT;
|
|
2748
|
+
case FilterMatchMode.LESS_THAN:
|
|
2749
|
+
return FilterMatchMode.DATE_BEFORE;
|
|
2750
|
+
case FilterMatchMode.LESS_THAN_OR_EQUAL_TO:
|
|
2751
|
+
return FilterMatchMode.DATE_BEFORE;
|
|
2752
|
+
case FilterMatchMode.GREATER_THAN:
|
|
2753
|
+
return FilterMatchMode.DATE_AFTER;
|
|
2754
|
+
case FilterMatchMode.GREATER_THAN_OR_EQUAL_TO:
|
|
2755
|
+
return FilterMatchMode.DATE_AFTER;
|
|
2756
|
+
}
|
|
2757
|
+
}
|
|
2758
|
+
return matchMode;
|
|
2759
|
+
}
|
|
2760
|
+
static parseLiteralValue(node) {
|
|
2761
|
+
const type = node.value;
|
|
2762
|
+
switch (type) {
|
|
2763
|
+
case PrimitiveTypeEnum.Binary:
|
|
2764
|
+
case PrimitiveTypeEnum.Boolean:
|
|
2765
|
+
return node.raw === "true";
|
|
2766
|
+
case PrimitiveTypeEnum.Byte:
|
|
2767
|
+
case PrimitiveTypeEnum.Int16:
|
|
2768
|
+
case PrimitiveTypeEnum.Int32:
|
|
2769
|
+
case PrimitiveTypeEnum.Int64:
|
|
2770
|
+
case PrimitiveTypeEnum.SByte:
|
|
2771
|
+
return Number.parseInt(node.raw);
|
|
2772
|
+
case PrimitiveTypeEnum.Date:
|
|
2773
|
+
case PrimitiveTypeEnum.DateTime:
|
|
2774
|
+
case PrimitiveTypeEnum.DateTimeOffset:
|
|
2775
|
+
case PrimitiveTypeEnum.Duration:
|
|
2776
|
+
case PrimitiveTypeEnum.TimeOfDay:
|
|
2777
|
+
return new Date(node.raw);
|
|
2778
|
+
case PrimitiveTypeEnum.Decimal:
|
|
2779
|
+
case PrimitiveTypeEnum.Double:
|
|
2780
|
+
case PrimitiveTypeEnum.Single:
|
|
2781
|
+
return Number.parseFloat(node.raw);
|
|
2782
|
+
default:
|
|
2783
|
+
switch (node.raw) {
|
|
2784
|
+
case "null":
|
|
2785
|
+
return null;
|
|
2786
|
+
default:
|
|
2787
|
+
return node.raw.startsWith("'") ? node.raw.substring(1, node.raw.length - 1) : node.raw;
|
|
2788
|
+
}
|
|
2789
|
+
}
|
|
2790
|
+
}
|
|
2791
|
+
static parseMethodCallExpression(node) {
|
|
2792
|
+
switch (node.value.method) {
|
|
2793
|
+
case 'startswith':
|
|
2794
|
+
return FilterMatchMode.STARTS_WITH;
|
|
2795
|
+
case 'contains':
|
|
2796
|
+
return FilterMatchMode.CONTAINS;
|
|
2797
|
+
case 'not contains':
|
|
2798
|
+
return FilterMatchMode.NOT_CONTAINS;
|
|
2799
|
+
case 'endswith':
|
|
2800
|
+
return FilterMatchMode.ENDS_WITH;
|
|
2801
|
+
default:
|
|
2802
|
+
throw Error(`Unknown method call ${node.value.method}`);
|
|
2803
|
+
}
|
|
2804
|
+
}
|
|
2805
|
+
/***
|
|
2806
|
+
* Parses an OData $filter query string and returns a map of property names to filter metadata.
|
|
2807
|
+
* @param node The root node of the OData $filter query string.
|
|
2808
|
+
* @param logToConsole If true, logs the type and raw value of each token to the console.
|
|
2809
|
+
* @returns A map of property names to filter metadata.
|
|
2734
2810
|
*/
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2811
|
+
parse(node, logToConsole) {
|
|
2812
|
+
if (logToConsole) {
|
|
2813
|
+
const visitLogAll = createTraverser(Object.fromEntries(Object.entries(TokenType)
|
|
2814
|
+
.map(([key, value]) => [key, (node) => console.log(`${node.type}: ${node.raw}`)])), true);
|
|
2815
|
+
visitLogAll(node);
|
|
2816
|
+
}
|
|
2817
|
+
const visit = createTraverser({
|
|
2818
|
+
EqualsExpression: (node) => this.CreateFilter(this.propertyName, this.value, FilterMatchMode.EQUALS),
|
|
2819
|
+
NotEqualsExpression: (node) => this.CreateFilter(this.propertyName, this.value, FilterMatchMode.NOT_EQUALS),
|
|
2820
|
+
GreaterThanExpression: (node) => this.CreateFilter(this.propertyName, this.value, FilterMatchMode.GREATER_THAN),
|
|
2821
|
+
GreaterOrEqualsExpression: (node) => this.CreateFilter(this.propertyName, this.value, FilterMatchMode.GREATER_THAN_OR_EQUAL_TO),
|
|
2822
|
+
LesserThanExpression: (node) => this.CreateFilter(this.propertyName, this.value, FilterMatchMode.LESS_THAN),
|
|
2823
|
+
LesserOrEqualsExpression: (node) => this.CreateFilter(this.propertyName, this.value, FilterMatchMode.LESS_THAN_OR_EQUAL_TO),
|
|
2824
|
+
HasExpression: (node) => this.CreateFilter(this.propertyName, [this.value], FilterMatchMode.EQUALS),
|
|
2825
|
+
ODataIdentifier: (node) => this.propertyName = node.value.name,
|
|
2826
|
+
Literal: (node) => this.value = OdataVisitor.parseLiteralValue(node),
|
|
2827
|
+
AndExpression: (node) => this.operator = "and",
|
|
2828
|
+
OrExpression: (node) => this.operator = "or",
|
|
2829
|
+
BoolParenExpression: (node) => this.SetOperatorForFilters(),
|
|
2830
|
+
MethodCallExpression: (node) => this.visitMethodCallExpression(node, visit),
|
|
2831
|
+
}, true);
|
|
2832
|
+
visit(node);
|
|
2833
|
+
return this._filters;
|
|
2834
|
+
}
|
|
2835
|
+
CreateFilter(propertyName, value, matchMode) {
|
|
2836
|
+
if (propertyName === undefined)
|
|
2837
|
+
throw Error(`Cannot add a filter for the value ${value} and the match mode ${matchMode} without a property name`);
|
|
2838
|
+
matchMode = OdataVisitor.correctFilterMatchMode(matchMode, value);
|
|
2839
|
+
const filter = this._filters.get(propertyName);
|
|
2840
|
+
if (filter === undefined) {
|
|
2841
|
+
this._filters.set(propertyName, [{ value, operator: "and", matchMode: matchMode }]);
|
|
2842
|
+
}
|
|
2843
|
+
else if (filter.length === 1 && Array.isArray(filter[0].value) && Array.isArray(value)) {
|
|
2844
|
+
filter[0].value.push(...value); // Flags enum
|
|
2845
|
+
}
|
|
2846
|
+
else {
|
|
2847
|
+
filter.push({ value, operator: "and", matchMode: matchMode });
|
|
2848
|
+
}
|
|
2849
|
+
}
|
|
2850
|
+
SetOperatorForFilters() {
|
|
2851
|
+
// In this case we are in the outermost expression which is just parantheses around the complete $filter value
|
|
2852
|
+
if (this.propertyName === undefined)
|
|
2853
|
+
return;
|
|
2854
|
+
// If we have not found an operator, or it is "and", we can just stay with the default created with the filter.
|
|
2855
|
+
if (this.operator === undefined || this.operator === "and")
|
|
2856
|
+
return;
|
|
2857
|
+
const filter = this._filters.get(this.propertyName);
|
|
2858
|
+
if (filter === undefined)
|
|
2859
|
+
return;
|
|
2860
|
+
// The operator is "or", so we need to set the operator for all filters to "or"
|
|
2861
|
+
for (const f of filter)
|
|
2862
|
+
f.operator = this.operator;
|
|
2863
|
+
}
|
|
2864
|
+
// The visitor does not correctly implement the MethodCallExpressionToken, so we need to do this manually
|
|
2865
|
+
visitMethodCallExpression(node, visit) {
|
|
2866
|
+
for (const parameter of node.value.parameters)
|
|
2867
|
+
visit(parameter);
|
|
2868
|
+
const matchMode = OdataVisitor.parseMethodCallExpression(node);
|
|
2869
|
+
this.CreateFilter(this.propertyName, this.value, matchMode);
|
|
2870
|
+
}
|
|
2739
2871
|
}
|
|
2740
|
-
|
|
2741
|
-
type: Directive
|
|
2742
|
-
}] });
|
|
2872
|
+
|
|
2743
2873
|
/**
|
|
2744
|
-
*
|
|
2874
|
+
* This class is used to parse an OData $filter string into a Record of filter constraints.
|
|
2745
2875
|
*/
|
|
2746
|
-
class
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2876
|
+
class ODataFilterParser {
|
|
2877
|
+
static parseFilter(filter, properties) {
|
|
2878
|
+
if (!filter)
|
|
2879
|
+
return {};
|
|
2880
|
+
// The parser has a bug where it does not correctly parse cast expressions, so we need to replace them with the first argument
|
|
2881
|
+
// See https://github.com/Soontao/odata-v4-parser/issues/283
|
|
2882
|
+
filter = ODataFilterParser.replaceCastExpressions(filter);
|
|
2883
|
+
const ast = defaultParser.filter(filter);
|
|
2884
|
+
const visitor = new OdataVisitor();
|
|
2885
|
+
const filters = visitor.parse(ast);
|
|
2886
|
+
/// OData needs enum values in pascal case, but JSON and therefor HAL-Forms needs them in camel case
|
|
2887
|
+
ODataFilterParser.MakeEnumValuesCamelCase(filters, properties);
|
|
2888
|
+
return Object.fromEntries(filters);
|
|
2889
|
+
}
|
|
2890
|
+
static MakeEnumValuesCamelCase(filters, properties) {
|
|
2891
|
+
for (const [key, value] of filters) {
|
|
2892
|
+
for (const filter of value) {
|
|
2893
|
+
const options = properties[key]?.options;
|
|
2894
|
+
if (options && !options.link && typeof filter.value === "string") {
|
|
2895
|
+
filter.value = filter.value.charAt(0).toLowerCase() + filter.value.slice(1);
|
|
2896
|
+
}
|
|
2897
|
+
}
|
|
2898
|
+
}
|
|
2899
|
+
}
|
|
2900
|
+
static replaceCastExpressions(input) {
|
|
2901
|
+
// Regular expression to match cast(x, y) and extract x
|
|
2902
|
+
const regex = /cast\(([^,]+),\s*[^)]+\)/g;
|
|
2903
|
+
// Replace matches with the first captured group (x)
|
|
2904
|
+
const result = input.replace(regex, (match, x) => x.trim());
|
|
2905
|
+
return result;
|
|
2906
|
+
}
|
|
2755
2907
|
}
|
|
2756
|
-
|
|
2757
|
-
type: Directive
|
|
2758
|
-
}] });
|
|
2908
|
+
|
|
2759
2909
|
/**
|
|
2760
|
-
* A
|
|
2761
|
-
* This may also be a complex object or a collection in which case multiple and nested input elements may be rendered.
|
|
2762
|
-
* If you want a form element without a label, use {@link RestWorldFormInput} `<rw-input>`.
|
|
2763
|
-
* @example
|
|
2764
|
-
* <rw-form-element [property]="property" [apiName]="apiName"></rw-form-element>
|
|
2910
|
+
* A static class that provides utility methods for creating OData filters, order by clauses, and parameters from {@link TableLazyLoadEvent} objects.
|
|
2765
2911
|
*/
|
|
2766
|
-
class
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
constructor(_formService, _controlContainer) {
|
|
2790
|
-
super();
|
|
2791
|
-
this._formService = _formService;
|
|
2792
|
-
this._controlContainer = _controlContainer;
|
|
2793
|
-
}
|
|
2794
|
-
getCollectionEntryTemplates(property) {
|
|
2795
|
-
if (!property)
|
|
2796
|
-
return [];
|
|
2797
|
-
return Object.entries(property._templates)
|
|
2798
|
-
.filter(([key, value]) => Number.isInteger(Number.parseInt(key)) && Number.isInteger(Number.parseInt(value?.title ?? "")))
|
|
2799
|
-
.map(([, value]) => new NumberTemplate(value));
|
|
2800
|
-
}
|
|
2801
|
-
addNewItemToCollection() {
|
|
2802
|
-
const templates = this.templates();
|
|
2803
|
-
const defaultTemplate = this.defaultTemplate();
|
|
2804
|
-
const maxIndex = Math.max(...Object.keys(templates)
|
|
2805
|
-
.map(key => Number.parseInt(key))
|
|
2806
|
-
.filter(key => Number.isSafeInteger(key)));
|
|
2807
|
-
const nextIndex = maxIndex < 0 ? 0 : maxIndex + 1;
|
|
2808
|
-
const copiedTemplateDto = JSON.parse(JSON.stringify(defaultTemplate));
|
|
2809
|
-
copiedTemplateDto.title = nextIndex.toString();
|
|
2810
|
-
const copiedTemplate = new Template(copiedTemplateDto);
|
|
2811
|
-
this.property.update((property) => { property._templates[nextIndex] = copiedTemplate; return { ...property }; });
|
|
2812
|
-
this.innerFormArray().push(this._formService.createFormGroupFromTemplate(this.defaultTemplate()));
|
|
2813
|
-
}
|
|
2814
|
-
collectionItemDropped($event) {
|
|
2815
|
-
const previousIndex = $event.previousIndex;
|
|
2816
|
-
const currentIndex = $event.currentIndex;
|
|
2817
|
-
const movementDirection = currentIndex > previousIndex ? 1 : -1;
|
|
2818
|
-
// Move in FormArray
|
|
2819
|
-
// We do not need to move the item in the _templates object
|
|
2820
|
-
const innerFormArray = this.innerFormArray();
|
|
2821
|
-
const movedControl = innerFormArray.at(previousIndex);
|
|
2822
|
-
for (let i = previousIndex; i * movementDirection < currentIndex * movementDirection; i = i + movementDirection) {
|
|
2823
|
-
innerFormArray.setControl(i, innerFormArray.at(i + movementDirection));
|
|
2912
|
+
class ODataService {
|
|
2913
|
+
/**
|
|
2914
|
+
* Creates an OData filter string for a given property and filter metadata.
|
|
2915
|
+
* @param property - The property to filter on.
|
|
2916
|
+
* @param filter - The filter metadata to use.
|
|
2917
|
+
* @returns The OData filter string, or undefined if the filter value is falsy.
|
|
2918
|
+
*/
|
|
2919
|
+
static createFilterForProperty(property, filter) {
|
|
2920
|
+
if (filter.matchMode == TranslationKeys.NO_FILTER)
|
|
2921
|
+
return undefined;
|
|
2922
|
+
// Enums are handled differently
|
|
2923
|
+
if (property.options && !property.options.link)
|
|
2924
|
+
return ODataService.createFilterForEnum(property, filter);
|
|
2925
|
+
const oDataOperator = ODataService.createODataOperator(filter.matchMode);
|
|
2926
|
+
const comparisonValue = ODataService.createComparisonValue(property, filter.value);
|
|
2927
|
+
switch (oDataOperator) {
|
|
2928
|
+
case 'contains':
|
|
2929
|
+
case 'not contains':
|
|
2930
|
+
case 'startswith':
|
|
2931
|
+
case 'endswith':
|
|
2932
|
+
return `${oDataOperator}(${property.name}, ${comparisonValue})`;
|
|
2933
|
+
default:
|
|
2934
|
+
return `${property.name} ${oDataOperator} ${comparisonValue}`;
|
|
2824
2935
|
}
|
|
2825
|
-
innerFormArray.setControl(currentIndex, movedControl);
|
|
2826
|
-
}
|
|
2827
|
-
deleteItemFromCollection(template) {
|
|
2828
|
-
const title = template.title;
|
|
2829
|
-
if (title === undefined)
|
|
2830
|
-
throw new Error("Cannot delete a template without a title.");
|
|
2831
|
-
this.property.update((property) => { delete property._templates[title]; return { ...property }; });
|
|
2832
|
-
this.innerFormArray().removeAt(title);
|
|
2833
2936
|
}
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
}
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
* You can also use one of the different RestWorldInput... `<rw-input-...>` elements to render a specific input,
|
|
2849
|
-
* but it is advised to control the rendered input through the passed in property.
|
|
2850
|
-
* @example
|
|
2851
|
-
* <rw-input [property]="property" [apiName]="apiName"></rw-input>
|
|
2852
|
-
*/
|
|
2853
|
-
class RestWorldInputComponent extends RestWorldInputLazyLoadBaseComponent {
|
|
2854
|
-
get PropertyType() {
|
|
2855
|
-
return PropertyType;
|
|
2937
|
+
/**
|
|
2938
|
+
* Creates an OData `$filter` value for an array of {@link FilterMetadata} objects and a given {@link Property}.
|
|
2939
|
+
* @param property - The {@link Property} to filter on.
|
|
2940
|
+
* @param filters - An array of {@link FilterMetadata} objects.
|
|
2941
|
+
* @returns The OData `$filter` value, or undefined if no filters were provided.
|
|
2942
|
+
*/
|
|
2943
|
+
static createFilterForPropertyArray(property, filters) {
|
|
2944
|
+
const filter = filters
|
|
2945
|
+
.map(f => ODataService.createFilterForProperty(property, f))
|
|
2946
|
+
.filter(f => !!f)
|
|
2947
|
+
.join(` ${filters[0].operator} `);
|
|
2948
|
+
if (filter === '')
|
|
2949
|
+
return undefined;
|
|
2950
|
+
return `(${filter})`;
|
|
2856
2951
|
}
|
|
2857
|
-
|
|
2858
|
-
|
|
2952
|
+
/**
|
|
2953
|
+
* Creates an OData `$filter` value from a {@link TableLazyLoadEvent} and an array of {@link Property Properties}.
|
|
2954
|
+
* @param event The {@link TableLazyLoadEvent} containing the filter data.
|
|
2955
|
+
* @param properties An optional array of {@link Property Properties} to filter on.
|
|
2956
|
+
* @returns The OData $`$filter` value, or undefined if no filters were applied or no properties were provided.
|
|
2957
|
+
*/
|
|
2958
|
+
static createFilterFromTableLoadEvent(event, properties) {
|
|
2959
|
+
const eventFilters = event.filters;
|
|
2960
|
+
if (eventFilters === undefined || properties === undefined)
|
|
2961
|
+
return undefined;
|
|
2962
|
+
const filter = properties
|
|
2963
|
+
.map(property => ({ property, filters: eventFilters[property.name] }))
|
|
2964
|
+
.filter(f => f.filters !== undefined)
|
|
2965
|
+
.map(f => ODataService.createFilterForPropertyArray(f.property, f.filters))
|
|
2966
|
+
.filter(f => !!f)
|
|
2967
|
+
.join(' and ');
|
|
2968
|
+
if (filter === '')
|
|
2969
|
+
return undefined;
|
|
2970
|
+
return `(${filter})`;
|
|
2859
2971
|
}
|
|
2860
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: RestWorldInputComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
2861
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.1", type: RestWorldInputComponent, isStandalone: true, selector: "rw-input", usesInheritance: true, ngImport: i0, template: "@if (property()) {\r\n @if (property().options) {\r\n <rw-input-dropdown [apiName]=\"apiName()\" [property]=\"$any(property())\" [useTemplateDrivenForms]=\"useTemplateDrivenForms()\"></rw-input-dropdown>\r\n }\r\n @else {\r\n @switch (property().type) {\r\n @case (PropertyType.Object) {\r\n <rw-input-object [apiName]=\"apiName()\" [property]=\"$any(property())\" [useTemplateDrivenForms]=\"useTemplateDrivenForms()\"></rw-input-object>\r\n }\r\n @case (PropertyType.Collection) {\r\n <rw-input-collection [apiName]=\"apiName()\" [property]=\"$any(property())\" [useTemplateDrivenForms]=\"useTemplateDrivenForms()\"></rw-input-collection>\r\n }\r\n @default {\r\n <rw-input-simple [property]=\"property()\" [useTemplateDrivenForms]=\"useTemplateDrivenForms()\"></rw-input-simple>\r\n }\r\n }\r\n }\r\n\r\n <rw-validation-errors [property]=\"property()\"></rw-validation-errors>\r\n}\r\n", styles: [""], dependencies: [{ kind: "component", type: i0.forwardRef(() => RestWorldInputDropdownComponent), selector: "rw-input-dropdown", inputs: ["caseSensitive", "getLabel", "getTooltip"], outputs: ["onChange"] }, { kind: "component", type: i0.forwardRef(() => RestWorldInputObjectComponent), selector: "rw-input-object" }, { kind: "component", type: i0.forwardRef(() => RestWorldInputSimpleComponent), selector: "rw-input-simple" }, { kind: "component", type: i0.forwardRef(() => RestWorldInputCollectionComponent), selector: "rw-input-collection" }, { kind: "component", type: i0.forwardRef(() => RestWorldValidationErrorsComponent), selector: "rw-validation-errors", inputs: ["form", "property"] }, { kind: "ngmodule", type: i0.forwardRef(() => FormsModule) }], viewProviders: [{ provide: ControlContainer, useExisting: FormGroupDirective }] });
|
|
2862
|
-
}
|
|
2863
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: RestWorldInputComponent, decorators: [{
|
|
2864
|
-
type: Component,
|
|
2865
|
-
args: [{ selector: 'rw-input', standalone: true, viewProviders: [{ provide: ControlContainer, useExisting: FormGroupDirective }], imports: [forwardRef(() => RestWorldInputDropdownComponent), forwardRef(() => RestWorldInputObjectComponent), forwardRef(() => RestWorldInputSimpleComponent), RestWorldInputCollectionComponent, RestWorldValidationErrorsComponent, FormsModule], template: "@if (property()) {\r\n @if (property().options) {\r\n <rw-input-dropdown [apiName]=\"apiName()\" [property]=\"$any(property())\" [useTemplateDrivenForms]=\"useTemplateDrivenForms()\"></rw-input-dropdown>\r\n }\r\n @else {\r\n @switch (property().type) {\r\n @case (PropertyType.Object) {\r\n <rw-input-object [apiName]=\"apiName()\" [property]=\"$any(property())\" [useTemplateDrivenForms]=\"useTemplateDrivenForms()\"></rw-input-object>\r\n }\r\n @case (PropertyType.Collection) {\r\n <rw-input-collection [apiName]=\"apiName()\" [property]=\"$any(property())\" [useTemplateDrivenForms]=\"useTemplateDrivenForms()\"></rw-input-collection>\r\n }\r\n @default {\r\n <rw-input-simple [property]=\"property()\" [useTemplateDrivenForms]=\"useTemplateDrivenForms()\"></rw-input-simple>\r\n }\r\n }\r\n }\r\n\r\n <rw-validation-errors [property]=\"property()\"></rw-validation-errors>\r\n}\r\n" }]
|
|
2866
|
-
}] });
|
|
2867
|
-
/**
|
|
2868
|
-
* A dropdown that is automatically created from the given property.
|
|
2869
|
-
* The dropdown supports searching through a RESTWorld list endpoint on the backend if the `link` of the options is set.
|
|
2870
|
-
* Otherwise the dropdown will use the `inline` of the options.
|
|
2871
|
-
* @remarks It is advised to use {@link RestWorldInputComponent} `<rw-input>` and control the rendered inputs with the passed in property
|
|
2872
|
-
* instead of using this component directly.
|
|
2873
|
-
* @example
|
|
2874
|
-
* <rw-input-dropdown [property]="property" [apiName]="apiName"></rw-input-dropdown>
|
|
2875
|
-
*/
|
|
2876
|
-
class RestWorldInputDropdownComponent extends RestWorldInputLazyLoadBaseComponent {
|
|
2877
|
-
_controlContainer;
|
|
2878
2972
|
/**
|
|
2879
|
-
*
|
|
2880
|
-
* The
|
|
2973
|
+
* Creates a map of property names to filter metadata from an OData $filter string.
|
|
2974
|
+
* @param filter The OData filter string to parse.
|
|
2975
|
+
* @returns A record of property names to filter metadata.
|
|
2881
2976
|
*/
|
|
2882
|
-
|
|
2977
|
+
static createFilterMetadataFromODataFilter(filter, properties) {
|
|
2978
|
+
const filters = ODataFilterParser.parseFilter(filter, properties);
|
|
2979
|
+
return filters;
|
|
2980
|
+
}
|
|
2883
2981
|
/**
|
|
2884
|
-
*
|
|
2885
|
-
*
|
|
2886
|
-
* The value
|
|
2887
|
-
* Overwrite this function to change the label.
|
|
2888
|
-
* @param item The item to get the label for.
|
|
2982
|
+
* Creates a OData `$orderby` value from a {@link TableLazyLoadEvent}.
|
|
2983
|
+
* @param event The {@link TableLazyLoadEvent} to create the `$orderby` value from.
|
|
2984
|
+
* @returns The `$orderby` value created from the {@link TableLazyLoadEvent}.
|
|
2889
2985
|
*/
|
|
2890
|
-
|
|
2986
|
+
static createOrderByFromTableLoadEvent(event) {
|
|
2987
|
+
if (event.multiSortMeta && event.multiSortMeta.length > 0) {
|
|
2988
|
+
return event.multiSortMeta
|
|
2989
|
+
.map(m => `${m.field} ${m.order > 0 ? 'asc' : 'desc'}`)
|
|
2990
|
+
.join(', ');
|
|
2991
|
+
}
|
|
2992
|
+
if (event.sortField) {
|
|
2993
|
+
const order = !event.sortOrder || event.sortOrder > 0 ? 'asc' : 'desc';
|
|
2994
|
+
return `${event.sortField} ${order}`;
|
|
2995
|
+
}
|
|
2996
|
+
return undefined;
|
|
2997
|
+
}
|
|
2891
2998
|
/**
|
|
2892
|
-
*
|
|
2893
|
-
*
|
|
2894
|
-
*
|
|
2895
|
-
*
|
|
2896
|
-
* @param item The item to get the label for.
|
|
2999
|
+
* Creates an {@link ODataParameters} object from a given {@link ActivatedRoute}.
|
|
3000
|
+
* @param route The {@link ActivatedRoute} to create the {@link ODataParameters} from.
|
|
3001
|
+
* @param prefix An optional prefix to use for the query parameter keys.
|
|
3002
|
+
* @returns The {@link ODataParameters} object created from the {@link ActivatedRoute}.
|
|
2897
3003
|
*/
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
3004
|
+
static createParametersFromRoute(route, prefix) {
|
|
3005
|
+
const snapshot = route.snapshot;
|
|
3006
|
+
let oDataParameters = {};
|
|
3007
|
+
const filter = snapshot.queryParamMap.get(`${prefix}$filter`);
|
|
3008
|
+
const orderBy = snapshot.queryParamMap.get(`${prefix}$orderby`);
|
|
3009
|
+
const top = snapshot.queryParamMap.get(`${prefix}$top`);
|
|
3010
|
+
const skip = snapshot.queryParamMap.get(`${prefix}$skip`);
|
|
3011
|
+
if (filter)
|
|
3012
|
+
oDataParameters.$filter = filter;
|
|
3013
|
+
if (orderBy)
|
|
3014
|
+
oDataParameters.$orderby = orderBy;
|
|
3015
|
+
if (top) {
|
|
3016
|
+
const topNumber = Number.parseInt(top);
|
|
3017
|
+
if (Number.isInteger(topNumber))
|
|
3018
|
+
oDataParameters.$top = topNumber;
|
|
3019
|
+
}
|
|
3020
|
+
if (skip) {
|
|
3021
|
+
const skipNumber = Number.parseInt(skip);
|
|
3022
|
+
if (Number.isInteger(skipNumber))
|
|
3023
|
+
oDataParameters.$skip = skipNumber;
|
|
3024
|
+
}
|
|
3025
|
+
return oDataParameters;
|
|
3026
|
+
}
|
|
2902
3027
|
/**
|
|
2903
|
-
*
|
|
3028
|
+
* Creates {@link ODataParameters} from a {@link TableLazyLoadEvent} and an optional {@link Template}.
|
|
3029
|
+
* @param event The {@link TableLazyLoadEvent} to create OData parameters from.
|
|
3030
|
+
* @param template An optional {@link Template} to use for creating the OData parameters.
|
|
3031
|
+
* @returns An {@link ODataParameters} object containing the `$filter`, `$orderby`, `$top`, and `$skip` parameters.
|
|
2904
3032
|
*/
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
// Get the initial value when 'control' changes
|
|
2914
|
-
toObservable(this._formControl).pipe(map((ctl) => ctl.value)),
|
|
2915
|
-
// Get the new value when 'control.value' changes
|
|
2916
|
-
toObservable(this._formControl).pipe(mergeMap((ctl) => ctl.valueChanges))));
|
|
2917
|
-
constructor(_controlContainer, optionsService) {
|
|
2918
|
-
super();
|
|
2919
|
-
this._controlContainer = _controlContainer;
|
|
2920
|
-
//const valueChangesSignal = toSignal(this._formControl.valueChanges);
|
|
2921
|
-
this.optionsManager = optionsService.getManager(this.apiName, this.property, this._valueChangesSignal, this.getLabel, this.getTooltip);
|
|
3033
|
+
static createParametersFromTableLoadEvent(event, template) {
|
|
3034
|
+
const oDataParameters = {
|
|
3035
|
+
$filter: ODataService.createFilterFromTableLoadEvent(event, template?.properties),
|
|
3036
|
+
$orderby: ODataService.createOrderByFromTableLoadEvent(event),
|
|
3037
|
+
$top: ODataService.createTopFromTableLoadEvent(event),
|
|
3038
|
+
$skip: ODataService.createSkipFromTableLoadEvent(event)
|
|
3039
|
+
};
|
|
3040
|
+
return oDataParameters;
|
|
2922
3041
|
}
|
|
2923
|
-
|
|
2924
|
-
|
|
3042
|
+
/**
|
|
3043
|
+
* Creates a OData `$skip` value from a {@link TableLazyLoadEvent}.
|
|
3044
|
+
* @param event The {@link TableLazyLoadEvent} to create the `$skip` value from.
|
|
3045
|
+
* @returns The `$skip` value created from the {@link TableLazyLoadEvent}.
|
|
3046
|
+
*/
|
|
3047
|
+
static createSkipFromTableLoadEvent(event) {
|
|
3048
|
+
return event.first;
|
|
2925
3049
|
}
|
|
2926
|
-
|
|
2927
|
-
|
|
3050
|
+
/**
|
|
3051
|
+
* Creates a OData `$top` value from a {@link TableLazyLoadEvent}.
|
|
3052
|
+
* @param event The {@link TableLazyLoadEvent} to create the `$top` value from.
|
|
3053
|
+
* @returns The `$top` value created from the {@link TableLazyLoadEvent}.
|
|
3054
|
+
*/
|
|
3055
|
+
static createTopFromTableLoadEvent(event) {
|
|
3056
|
+
return event.rows === null ? undefined : event.rows;
|
|
2928
3057
|
}
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
3058
|
+
static createComparisonValue(property, value, isEnum) {
|
|
3059
|
+
if (value === null || value === undefined)
|
|
3060
|
+
return 'null';
|
|
3061
|
+
const type = ODataService.getPropertyType(property, value);
|
|
3062
|
+
switch (type) {
|
|
3063
|
+
case PropertyType.Date:
|
|
3064
|
+
return `cast(${value.toISOString()}, Edm.DateOnly)`;
|
|
3065
|
+
case PropertyType.DatetimeLocal:
|
|
3066
|
+
return `cast(${value.toISOString()}, Edm.DateTime)`;
|
|
3067
|
+
case PropertyType.DatetimeOffset:
|
|
3068
|
+
return `cast(${value.toISOString()}, Edm.DateTimeOffset)`;
|
|
3069
|
+
case PropertyType.Time:
|
|
3070
|
+
return `cast(${value.toISOString()}, Edm.TimeOnly)`;
|
|
3071
|
+
case PropertyType.Duration:
|
|
3072
|
+
return `cast(${value.toISOString()}, Edm.TimeSpan)`;
|
|
3073
|
+
case PropertyType.Bool:
|
|
3074
|
+
case PropertyType.Number:
|
|
3075
|
+
case PropertyType.Currency:
|
|
3076
|
+
case PropertyType.Month:
|
|
3077
|
+
return '' + value;
|
|
3078
|
+
case PropertyType.Percent:
|
|
3079
|
+
return '' + (value / 100);
|
|
3080
|
+
default:
|
|
3081
|
+
return `'${isEnum && typeof value === "string" ? value.charAt(0).toUpperCase() + value.slice(1) : value}'`;
|
|
3082
|
+
}
|
|
3083
|
+
}
|
|
3084
|
+
static createFilterForEnum(property, filter) {
|
|
3085
|
+
if (filter.matchMode == TranslationKeys.NO_FILTER)
|
|
3086
|
+
return undefined;
|
|
3087
|
+
const options = property.options;
|
|
3088
|
+
if (options === undefined)
|
|
3089
|
+
throw Error(`Property ${property.name} has no options`);
|
|
3090
|
+
const maxItems = options.maxItems ?? Number.MAX_SAFE_INTEGER;
|
|
3091
|
+
const oDataOperator = ODataService.createODataOperator(filter.matchMode);
|
|
3092
|
+
// Normal enum
|
|
3093
|
+
if (maxItems === 1) {
|
|
3094
|
+
const comparisonValue = ODataService.createComparisonValue(property, filter.value, true);
|
|
3095
|
+
return `${property.name} ${oDataOperator} ${comparisonValue}`;
|
|
3096
|
+
}
|
|
3097
|
+
// Flags enum
|
|
3098
|
+
if (filter.value === null || filter.value === undefined)
|
|
3099
|
+
return undefined;
|
|
3100
|
+
const values = Array.isArray(filter.value) ? filter.value : [filter.value];
|
|
3101
|
+
const comparisonValues = values.map(v => ODataService.createComparisonValue(property, v, true));
|
|
3102
|
+
const filters = comparisonValues.map(v => `${property.name} has ${v}`);
|
|
3103
|
+
const concatenatedFilters = filters.join(' and ');
|
|
3104
|
+
return `(${concatenatedFilters})`;
|
|
3105
|
+
}
|
|
3106
|
+
static createODataOperator(matchMode) {
|
|
3107
|
+
switch (matchMode) {
|
|
3108
|
+
case FilterMatchMode.STARTS_WITH:
|
|
3109
|
+
return 'startswith';
|
|
3110
|
+
case FilterMatchMode.CONTAINS:
|
|
3111
|
+
return 'contains';
|
|
3112
|
+
case FilterMatchMode.NOT_CONTAINS:
|
|
3113
|
+
return 'not contains';
|
|
3114
|
+
case FilterMatchMode.ENDS_WITH:
|
|
3115
|
+
return 'endswith';
|
|
3116
|
+
case FilterMatchMode.EQUALS:
|
|
3117
|
+
return 'eq';
|
|
3118
|
+
case FilterMatchMode.NOT_EQUALS:
|
|
3119
|
+
return 'ne';
|
|
3120
|
+
case FilterMatchMode.IN:
|
|
3121
|
+
return 'in';
|
|
3122
|
+
case FilterMatchMode.LESS_THAN:
|
|
3123
|
+
return 'lt';
|
|
3124
|
+
case FilterMatchMode.LESS_THAN_OR_EQUAL_TO:
|
|
3125
|
+
return 'le';
|
|
3126
|
+
case FilterMatchMode.GREATER_THAN:
|
|
3127
|
+
return 'gt';
|
|
3128
|
+
case FilterMatchMode.GREATER_THAN_OR_EQUAL_TO:
|
|
3129
|
+
return 'ge';
|
|
3130
|
+
case FilterMatchMode.IS:
|
|
3131
|
+
return 'eq';
|
|
3132
|
+
case FilterMatchMode.IS_NOT:
|
|
3133
|
+
return 'ne';
|
|
3134
|
+
case FilterMatchMode.BEFORE:
|
|
3135
|
+
return 'lt';
|
|
3136
|
+
case FilterMatchMode.AFTER:
|
|
3137
|
+
return 'gt';
|
|
3138
|
+
case FilterMatchMode.DATE_AFTER:
|
|
3139
|
+
return 'ge';
|
|
3140
|
+
case FilterMatchMode.DATE_BEFORE:
|
|
3141
|
+
return 'lt';
|
|
3142
|
+
case FilterMatchMode.DATE_IS:
|
|
3143
|
+
return 'eq';
|
|
3144
|
+
case FilterMatchMode.DATE_IS_NOT:
|
|
3145
|
+
return 'ne';
|
|
3146
|
+
default:
|
|
3147
|
+
throw Error(`Unknown matchMode ${matchMode}`);
|
|
3148
|
+
}
|
|
3149
|
+
}
|
|
3150
|
+
static getPropertyType(property, value) {
|
|
3151
|
+
if (property.options) {
|
|
3152
|
+
if (typeof value === "string" ||
|
|
3153
|
+
Array.isArray(value) && value.every(v => typeof v === "string") ||
|
|
3154
|
+
property.options.inline?.some(o => property.options.valueField !== undefined && typeof o[property.options.valueField] === "string"))
|
|
3155
|
+
return PropertyType.Text;
|
|
3156
|
+
return PropertyType.Number;
|
|
3157
|
+
}
|
|
3158
|
+
return property.type;
|
|
3159
|
+
}
|
|
3160
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: ODataService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
3161
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: ODataService, providedIn: 'root' });
|
|
3162
|
+
}
|
|
3163
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: ODataService, decorators: [{
|
|
3164
|
+
type: Injectable,
|
|
3165
|
+
args: [{
|
|
3166
|
+
providedIn: 'root',
|
|
3167
|
+
}]
|
|
3168
|
+
}] });
|
|
3169
|
+
|
|
3170
|
+
/**
|
|
3171
|
+
* Displays one button for every `MenuItem` given in the items array.
|
|
3172
|
+
* If a `MenuItem` has nested items, a button with a dropdown menu will be displayed.
|
|
3173
|
+
* @example
|
|
3174
|
+
* <rw-menu-button [items]="items"></rw-menu-button>
|
|
3175
|
+
*/
|
|
3176
|
+
class RestWorldMenuButtonComponent {
|
|
3177
|
+
_router;
|
|
3178
|
+
/**
|
|
3179
|
+
* An array of menu items to be displayed.
|
|
3180
|
+
*/
|
|
3181
|
+
items = input.required(...(ngDevMode ? [{ debugName: "items" }] : []));
|
|
3182
|
+
constructor(_router) {
|
|
3183
|
+
this._router = _router;
|
|
3184
|
+
}
|
|
3185
|
+
onClick(event, item) {
|
|
3186
|
+
const openInNewWindow = event.ctrlKey || event.button === 1 || event.metaKey;
|
|
3187
|
+
if (item.url) {
|
|
3188
|
+
window.open(item.url, openInNewWindow ? '_blank' : '_self');
|
|
3189
|
+
}
|
|
3190
|
+
else if (item.routerLink) {
|
|
3191
|
+
if (openInNewWindow) {
|
|
3192
|
+
const tree = this._router.createUrlTree(item.routerLink, {
|
|
3193
|
+
queryParams: item.queryParams,
|
|
3194
|
+
fragment: item.fragment,
|
|
3195
|
+
queryParamsHandling: item.queryParamsHandling,
|
|
3196
|
+
preserveFragment: item.preserveFragment,
|
|
2945
3197
|
});
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
const allAreNumbers = values.every(v => typeof v === "number" && !isNaN(v));
|
|
2949
|
-
const filter = allAreNumbers
|
|
2950
|
-
? `${options.valueField} in (${values.join(',')})`
|
|
2951
|
-
: `contains(${this.makeUpperIfCaseInsensitive(options.promptField, true)}, '${values.join("', '")}')`;
|
|
2952
|
-
if ((options?.link?.href))
|
|
2953
|
-
await this.optionsManager.updateItemsFromFilter(filter);
|
|
2954
|
-
if (currentItems) {
|
|
2955
|
-
const selectedValues = currentItems
|
|
2956
|
-
.map(i => this.optionsManager.getValue(i))
|
|
2957
|
-
.filter(v => values.includes(v));
|
|
2958
|
-
this._formControl().setValue(selectedValues);
|
|
2959
|
-
this.multiSelect()?.resetFilter();
|
|
2960
|
-
}
|
|
3198
|
+
const url = this._router.serializeUrl(tree);
|
|
3199
|
+
window.open(url, '_blank');
|
|
2961
3200
|
}
|
|
2962
3201
|
else {
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
3202
|
+
this._router.navigate(item.routerLink, {
|
|
3203
|
+
queryParams: item.queryParams,
|
|
3204
|
+
fragment: item.fragment,
|
|
3205
|
+
queryParamsHandling: item.queryParamsHandling,
|
|
3206
|
+
preserveFragment: item.preserveFragment,
|
|
3207
|
+
skipLocationChange: item.skipLocationChange,
|
|
3208
|
+
replaceUrl: item.replaceUrl,
|
|
3209
|
+
});
|
|
2969
3210
|
}
|
|
2970
3211
|
}
|
|
3212
|
+
else if (item.command) {
|
|
3213
|
+
item.command({ item: item });
|
|
3214
|
+
}
|
|
2971
3215
|
}
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
return filter;
|
|
2975
|
-
if (isOData)
|
|
2976
|
-
return `toupper(${filter})`;
|
|
2977
|
-
return filter.toUpperCase();
|
|
2978
|
-
}
|
|
2979
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: RestWorldInputDropdownComponent, deps: [{ token: i2$3.ControlContainer }, { token: OptionsService }], target: i0.ɵɵFactoryTarget.Component });
|
|
2980
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.1", type: RestWorldInputDropdownComponent, isStandalone: true, selector: "rw-input-dropdown", inputs: { caseSensitive: { classPropertyName: "caseSensitive", publicName: "caseSensitive", isSignal: true, isRequired: false, transformFunction: null }, getLabel: { classPropertyName: "getLabel", publicName: "getLabel", isSignal: true, isRequired: false, transformFunction: null }, getTooltip: { classPropertyName: "getTooltip", publicName: "getTooltip", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onChange: "onChange" }, queries: [{ propertyName: "inputOptionsMultipleRef", first: true, predicate: ["inputOptionsMultiple"], descendants: true, isSignal: true }, { propertyName: "inputOptionsSingleRef", first: true, predicate: ["inputOptionsSingle"], descendants: true, isSignal: true }], viewQueries: [{ propertyName: "multiSelect", first: true, predicate: MultiSelect, descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<ng-template #defaultInputOptionsSingle let-property=\"property\" let-template=\"template\" let-items=\"items\" let-useTemplateDrivenForms=\"useTemplateDrivenForms\">\n @if (useTemplateDrivenForms()) {\n <p-select\n [propertyAttributes]=\"property()\"\n [(ngModel)]=\"model\"\n [options]=\"optionsManager.items()\"\n (onFilter)=\"onOptionsFiltered($event)\"\n (onChange)=\"onOptionsChanged($event)\"\n styleClass=\"w-full\"\n [panelStyleClass]=\"optionsManager.loading() ? 'loading' : ''\"\n [emptyFilterMessage]=\"optionsManager.loading() ? 'Loading...' : ''\"\n [loading]=\"optionsManager.loading()\"\n >\n <ng-template #selectedItem let-selectedItem>\n <span [pTooltip]=\"optionsManager.getTooltip()(selectedItem)\">{{optionsManager.getLabel()(selectedItem)}}</span>\n </ng-template>\n <ng-template #item let-item>\n <span [pTooltip]=\"optionsManager.getTooltip()(item)\">{{optionsManager.getLabel()(item)}}</span>\n </ng-template>\n </p-select>\n }\n @else {\n <p-select\n [formControlProperty]=\"property()\"\n [options]=\"optionsManager.items()\"\n (onFilter)=\"onOptionsFiltered($event)\"\n (onChange)=\"onOptionsChanged($event)\"\n styleClass=\"w-full\"\n [panelStyleClass]=\"optionsManager.loading() ? 'loading' : ''\"\n [emptyFilterMessage]=\"optionsManager.loading() ? 'Loading...' : ''\"\n [loading]=\"optionsManager.loading()\"\n >\n <ng-template #selectedItem let-selectedItem>\n <span [pTooltip]=\"optionsManager.getTooltip()(selectedItem)\">{{optionsManager.getLabel()(selectedItem)}}</span>\n </ng-template>\n <ng-template #item let-item>\n <span [pTooltip]=\"optionsManager.getTooltip()(item)\">{{optionsManager.getLabel()(item)}}</span>\n </ng-template>\n </p-select>\n }\n</ng-template>\n\n<ng-template #defaultInputOptionsMultiple let-property=\"property\" let-template=\"template\" let-items=\"items\" let-useTemplateDrivenForms=\"useTemplateDrivenForms\">\n @if (useTemplateDrivenForms()) {\n <p-multiSelect\n [propertyAttributes]=\"property()\"\n [(ngModel)]=\"model\"\n [options]=\"optionsManager.items()\"\n (onFilter)=\"onOptionsFiltered($event)\"\n (onChange)=\"onOptionsChanged($event)\"\n styleClass=\"w-full\"\n [panelStyleClass]=\"optionsManager.loading() ? 'loading' : ''\"\n [emptyFilterMessage]=\"optionsManager.loading() ? 'Loading...' : ''\"\n [loading]=\"optionsManager.loading()\"\n >\n <ng-template #selecteditems let-items let-removeChip=\"removeChip\">\n @for (item of items; track item; let i = $index) {\n <p-chip\n [pTooltip]=\"optionsManager.getTooltip()(item)\"\n [label]=\"optionsManager.getLabel()(item)\"\n [removable]=\"true\"\n (onRemove)=\"removeChip(optionsManager.getValue(item), $event)\"\n >\n </p-chip>\n }\n </ng-template>\n <ng-template #item let-item>\n <span [pTooltip]=\"optionsManager.getTooltip()(item)\">{{optionsManager.getLabel()(item)}}</span>\n </ng-template>\n </p-multiSelect>\n }\n @else {\n <p-multiSelect\n [formControlProperty]=\"property()\"\n [options]=\"optionsManager.items()\"\n (onFilter)=\"onOptionsFiltered($event)\"\n (onChange)=\"onOptionsChanged($event)\"\n styleClass=\"w-full\"\n [panelStyleClass]=\"optionsManager.loading() ? 'loading' : ''\"\n [emptyFilterMessage]=\"optionsManager.loading() ? 'Loading...' : ''\"\n [loading]=\"optionsManager.loading()\"\n >\n <ng-template #selecteditems let-items let-removeChip=\"removeChip\">\n @for (item of items; track item; let i = $index) {\n <p-chip\n [pTooltip]=\"optionsManager.getTooltip()(item)\"\n [label]=\"optionsManager.getLabel()(item)\"\n [removable]=\"true\"\n (onRemove)=\"removeChip(optionsManager.getValue(item), $event)\"\n >\n </p-chip>\n }\n </ng-template>\n <ng-template #item let-item>\n <span [pTooltip]=\"optionsManager.getTooltip()(item)\">{{optionsManager.getLabel()(item)}}</span>\n </ng-template>\n </p-multiSelect>\n }\n</ng-template>\n\n@if(!optionsManager.options().maxItems || optionsManager.options().maxItems == 1) {\n <ng-container *ngTemplateOutlet=\"inputOptionsSingleRef() ?? defaultInputOptionsSingle; context: { property: property, apiName: apiName, items: optionsManager.items, useTemplateDrivenForms: useTemplateDrivenForms, model: model }\"></ng-container>\n}\n@else {\n <ng-container *ngTemplateOutlet=\"inputOptionsMultipleRef() ?? defaultInputOptionsMultiple; context: { property: property, apiName: apiName, items: optionsManager.items, useTemplateDrivenForms: useTemplateDrivenForms, model: model }\"></ng-container>\n}\n", styles: ["::ng-deep .p-multiselect-label{display:inline-flex!important}::ng-deep .p-multiselect-label-empty{height:36px}::ng-deep .p-chip{background-color:#eff6ff;color:#1d4ed8}::ng-deep .pi-chip-remove-icon:hover{filter:brightness(.6)}\n"], dependencies: [{ kind: "component", type: Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "component", type: MultiSelect, selector: "p-multiSelect, p-multiselect, p-multi-select", inputs: ["id", "ariaLabel", "styleClass", "panelStyle", "panelStyleClass", "inputId", "readonly", "group", "filter", "filterPlaceHolder", "filterLocale", "overlayVisible", "tabindex", "dataKey", "ariaLabelledBy", "displaySelectedLabel", "maxSelectedLabels", "selectionLimit", "selectedItemsLabel", "showToggleAll", "emptyFilterMessage", "emptyMessage", "resetFilterOnHide", "dropdownIcon", "chipIcon", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "showHeader", "filterBy", "scrollHeight", "lazy", "virtualScroll", "loading", "virtualScrollItemSize", "loadingIcon", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "autofocusFilter", "display", "autocomplete", "showClear", "autofocus", "placeholder", "options", "filterValue", "selectAll", "focusOnHover", "filterFields", "selectOnFocus", "autoOptionFocus", "highlightOnSelect", "size", "variant", "fluid", "appendTo"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onClear", "onPanelShow", "onPanelHide", "onLazyLoad", "onRemove", "onSelectAllChange"] }, { kind: "directive", type: Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo"] }, { kind: "component", type: Chip, selector: "p-chip", inputs: ["label", "icon", "image", "alt", "styleClass", "removable", "removeIcon", "chipProps"], outputs: ["onRemove", "onImageError"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: HalFormsModule }, { kind: "directive", type: FormControlProperty, selector: "[formControlProperty]:not([useTemplateDrivenForms=true])", inputs: ["formControlProperty"] }, { kind: "directive", type: PropertyControlStatus, selector: "[formControlProperty]" }, { kind: "directive", type: PropertySelectAttributes, selector: "p-select[formControlProperty], p-select[propertyAttributes], p-multiSelect[formControlProperty], p-multiSelect[propertyAttributes]", inputs: ["formControlProperty", "propertyAttributes"] }, { kind: "directive", type: PropertyAttributes, selector: "[formControlProperty],[propertyAttributes]", inputs: ["formControlProperty", "propertyAttributes"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }], viewProviders: [{ provide: ControlContainer, useExisting: FormGroupDirective }] });
|
|
3216
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: RestWorldMenuButtonComponent, deps: [{ token: i3$3.Router }], target: i0.ɵɵFactoryTarget.Component });
|
|
3217
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.1", type: RestWorldMenuButtonComponent, isStandalone: true, selector: "rw-menu-button", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "@for (item of items(); track item; let i = $index) {\n @if (!item.items) {\n <p-button\n [label]=\"item.label!\"\n [icon]=\"item.icon!\"\n [disabled]=\"item.disabled!\"\n [style]=\"item.style\"\n [styleClass]=\"item.styleClass!\"\n [pTooltip]=\"item.tooltip!\"\n [tooltipPosition]=\"item.tooltipPosition!\"\n (onClick)=\"onClick($event, item)\"\n [class.ml-2]=\"i > 0\">\n </p-button>\n } \n @else {\n <p-splitButton\n [label]=\"item.label!\"\n [icon]=\"item.icon!\"\n [model]=\"item.items\"\n appendTo=\"body\"\n [disabled]=\"item.disabled!\"\n [style]=\"item.style\"\n [styleClass]=\"item.styleClass!\"\n [pTooltip]=\"item.tooltip!\"\n [tooltipPosition]=\"item.tooltipPosition!\"\n (onClick)=\"onClick($event, item)\"\n [class.ml-2]=\"i > 0\">\n </p-splitButton>\n }\n}\n", styles: [":host{display:flex;justify-content:flex-end}\n"], dependencies: [{ kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$3.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "buttonProps", "autofocus", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i3.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo"] }, { kind: "ngmodule", type: SplitButtonModule }, { kind: "component", type: i4$1.SplitButton, selector: "p-splitbutton, p-splitButton, p-split-button", inputs: ["model", "severity", "raised", "rounded", "text", "outlined", "size", "plain", "icon", "iconPos", "label", "tooltip", "tooltipOptions", "styleClass", "menuStyle", "menuStyleClass", "dropdownIcon", "appendTo", "dir", "expandAriaLabel", "showTransitionOptions", "hideTransitionOptions", "buttonProps", "menuButtonProps", "autofocus", "disabled", "tabindex", "menuButtonDisabled", "buttonDisabled"], outputs: ["onClick", "onMenuHide", "onMenuShow", "onDropdownClick"] }] });
|
|
2981
3218
|
}
|
|
2982
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type:
|
|
3219
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: RestWorldMenuButtonComponent, decorators: [{
|
|
2983
3220
|
type: Component,
|
|
2984
|
-
args: [{ selector: 'rw-
|
|
2985
|
-
}], ctorParameters: () => [{ type:
|
|
3221
|
+
args: [{ selector: 'rw-menu-button', standalone: true, imports: [ButtonModule, TooltipModule, SplitButtonModule], template: "@for (item of items(); track item; let i = $index) {\n @if (!item.items) {\n <p-button\n [label]=\"item.label!\"\n [icon]=\"item.icon!\"\n [disabled]=\"item.disabled!\"\n [style]=\"item.style\"\n [styleClass]=\"item.styleClass!\"\n [pTooltip]=\"item.tooltip!\"\n [tooltipPosition]=\"item.tooltipPosition!\"\n (onClick)=\"onClick($event, item)\"\n [class.ml-2]=\"i > 0\">\n </p-button>\n } \n @else {\n <p-splitButton\n [label]=\"item.label!\"\n [icon]=\"item.icon!\"\n [model]=\"item.items\"\n appendTo=\"body\"\n [disabled]=\"item.disabled!\"\n [style]=\"item.style\"\n [styleClass]=\"item.styleClass!\"\n [pTooltip]=\"item.tooltip!\"\n [tooltipPosition]=\"item.tooltipPosition!\"\n (onClick)=\"onClick($event, item)\"\n [class.ml-2]=\"i > 0\">\n </p-splitButton>\n }\n}\n", styles: [":host{display:flex;justify-content:flex-end}\n"] }]
|
|
3222
|
+
}], ctorParameters: () => [{ type: i3$3.Router }] });
|
|
3223
|
+
|
|
2986
3224
|
/**
|
|
2987
|
-
*
|
|
2988
|
-
*
|
|
2989
|
-
* @remarks It is advised to use {@link RestWorldInputComponent} `<rw-input>` and control the rendered inputs with the passed in property
|
|
2990
|
-
* instead of using this component directly.
|
|
2991
|
-
* @example
|
|
2992
|
-
* <rw-input-object [property]="property" [apiName]="apiName"></rw-input-object>
|
|
3225
|
+
* This component is used to display a filter element for a table column.
|
|
3226
|
+
* It is used internally by the <rw-table> component, but can also be used in the #filter template of a column in the header of a <p-table>.
|
|
2993
3227
|
*/
|
|
2994
|
-
class
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3228
|
+
class RestWorldTableColumnFilterElementComponent {
|
|
3229
|
+
_formService;
|
|
3230
|
+
/**
|
|
3231
|
+
* The filter constraint to update when the value changes.
|
|
3232
|
+
* This is coming from the $context of the #filter template
|
|
3233
|
+
*/
|
|
3234
|
+
filterConstraint = input.required(...(ngDevMode ? [{ debugName: "filterConstraint" }] : []));
|
|
3235
|
+
/**
|
|
3236
|
+
* The HAL-Forms property to filter by.
|
|
3237
|
+
* This is normally the column.
|
|
3238
|
+
*/
|
|
3239
|
+
property = input.required(...(ngDevMode ? [{ debugName: "property" }] : []));
|
|
3240
|
+
/**
|
|
3241
|
+
* The name of the API to use when generating dropdowns.
|
|
3242
|
+
*/
|
|
3243
|
+
apiName = input.required(...(ngDevMode ? [{ debugName: "apiName" }] : []));
|
|
3244
|
+
/**
|
|
3245
|
+
* The initial value of the filter.
|
|
3246
|
+
*/
|
|
3247
|
+
value = input.required(...(ngDevMode ? [{ debugName: "value" }] : []));
|
|
3248
|
+
form = computed(() => this._formService.createFormGroupFromTemplate(this.template()), ...(ngDevMode ? [{ debugName: "form" }] : []));
|
|
3249
|
+
template = computed(() => new Template({
|
|
3250
|
+
properties: [this.property()],
|
|
3251
|
+
}), ...(ngDevMode ? [{ debugName: "template" }] : []));
|
|
3252
|
+
_formValueChangesSubscription;
|
|
3253
|
+
constructor(_formService) {
|
|
3254
|
+
this._formService = _formService;
|
|
3255
|
+
effect(() => {
|
|
3256
|
+
this._formValueChangesSubscription?.unsubscribe();
|
|
3257
|
+
const form = this.form();
|
|
3258
|
+
const property = this.property();
|
|
3259
|
+
const value = untracked(() => this.value());
|
|
3260
|
+
const formControl = form.controls[property.name];
|
|
3261
|
+
this._formValueChangesSubscription = formControl.valueChanges.subscribe(this.setFilterValue.bind(this));
|
|
3262
|
+
formControl.setValue(value);
|
|
3263
|
+
});
|
|
3000
3264
|
}
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3265
|
+
setFilterValue(value) {
|
|
3266
|
+
this.filterConstraint().value = value;
|
|
3267
|
+
}
|
|
3268
|
+
ngOnDestroy() {
|
|
3269
|
+
this._formValueChangesSubscription?.unsubscribe();
|
|
3270
|
+
}
|
|
3271
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: RestWorldTableColumnFilterElementComponent, deps: [{ token: i1$1.FormService }], target: i0.ɵɵFactoryTarget.Component });
|
|
3272
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.1", type: RestWorldTableColumnFilterElementComponent, isStandalone: true, selector: "rw-table-column-filter-element", inputs: { filterConstraint: { classPropertyName: "filterConstraint", publicName: "filterConstraint", isSignal: true, isRequired: true, transformFunction: null }, property: { classPropertyName: "property", publicName: "property", isSignal: true, isRequired: true, transformFunction: null }, apiName: { classPropertyName: "apiName", publicName: "apiName", isSignal: true, isRequired: true, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<form [formGroup]=\"form()\">\r\n <rw-input [property]=\"property()\" [apiName]=\"apiName()\"></rw-input>\r\n</form>\r\n", styles: [""], dependencies: [{ kind: "component", type: RestWorldInputComponent, selector: "rw-input" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2$3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2$3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2$3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }] });
|
|
3007
3273
|
}
|
|
3008
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type:
|
|
3274
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: RestWorldTableColumnFilterElementComponent, decorators: [{
|
|
3009
3275
|
type: Component,
|
|
3010
|
-
args: [{ selector: 'rw-
|
|
3011
|
-
}], ctorParameters: () => [{ type:
|
|
3012
|
-
|
|
3013
|
-
* A simple input element, like a string, a number or a Date that is automatically created from the given property.
|
|
3014
|
-
* @remarks It is advised to use {@link RestWorldInputComponent} `<rw-input>` and control the rendered inputs with the passed in property
|
|
3015
|
-
* instead of using this component directly.
|
|
3016
|
-
* @example
|
|
3017
|
-
* <rw-input-simple [property]="property" [apiName]="apiName"></rw-input-simple>
|
|
3018
|
-
*/
|
|
3019
|
-
class RestWorldInputSimpleComponent extends RestWorldInputBaseComponent {
|
|
3020
|
-
static _dateFormat = new Date(3333, 10, 22) // months start at 0 in JS
|
|
3021
|
-
.toLocaleDateString()
|
|
3022
|
-
.replace("22", "dd")
|
|
3023
|
-
.replace("11", "mm")
|
|
3024
|
-
.replace("3333", "yy")
|
|
3025
|
-
.replace("33", "y");
|
|
3026
|
-
static _timeFormat = new Date(1, 1, 1, 22, 33, 44)
|
|
3027
|
-
.toLocaleTimeString()
|
|
3028
|
-
.replace("22", "hh")
|
|
3029
|
-
.replace("33", "mm")
|
|
3030
|
-
.replace("44", "ss");
|
|
3031
|
-
_inputChild = viewChild("inputElement", ...(ngDevMode ? [{ debugName: "_inputChild" }] : []));
|
|
3032
|
-
_controlChild = viewChild(NG_VALUE_ACCESSOR, ...(ngDevMode ? [{ debugName: "_controlChild" }] : []));
|
|
3033
|
-
constructor() {
|
|
3034
|
-
super();
|
|
3035
|
-
}
|
|
3036
|
-
writeValue(obj) {
|
|
3037
|
-
const controlChild = this._controlChild();
|
|
3038
|
-
const inputChild = this._inputChild();
|
|
3039
|
-
if (controlChild !== undefined)
|
|
3040
|
-
controlChild.writeValue(obj);
|
|
3041
|
-
else if (inputChild !== undefined)
|
|
3042
|
-
inputChild.nativeElement.value = obj;
|
|
3043
|
-
}
|
|
3044
|
-
registerOnChange(fn) {
|
|
3045
|
-
const controlChild = this._controlChild();
|
|
3046
|
-
const inputChild = this._inputChild();
|
|
3047
|
-
if (controlChild !== undefined)
|
|
3048
|
-
controlChild.registerOnChange(fn);
|
|
3049
|
-
else if (inputChild !== undefined)
|
|
3050
|
-
inputChild.nativeElement.oninput = (event) => fn(event.target.value);
|
|
3051
|
-
}
|
|
3052
|
-
registerOnTouched(fn) {
|
|
3053
|
-
const controlChild = this._controlChild();
|
|
3054
|
-
const inputChild = this._inputChild();
|
|
3055
|
-
if (controlChild !== undefined)
|
|
3056
|
-
controlChild.registerOnTouched(fn);
|
|
3057
|
-
else if (inputChild !== undefined)
|
|
3058
|
-
inputChild.nativeElement.onblur = (event) => fn();
|
|
3059
|
-
}
|
|
3060
|
-
setDisabledState(isDisabled) {
|
|
3061
|
-
const controlChild = this._controlChild();
|
|
3062
|
-
const inputChild = this._inputChild();
|
|
3063
|
-
if (controlChild !== undefined && controlChild.setDisabledState !== undefined)
|
|
3064
|
-
controlChild.setDisabledState(isDisabled);
|
|
3065
|
-
else if (inputChild !== undefined) {
|
|
3066
|
-
if (isDisabled)
|
|
3067
|
-
inputChild.nativeElement.setAttribute("disabled", "disabled");
|
|
3068
|
-
else
|
|
3069
|
-
inputChild.nativeElement.removeAttribute("disabled");
|
|
3070
|
-
}
|
|
3071
|
-
}
|
|
3072
|
-
get PropertyType() {
|
|
3073
|
-
return PropertyType;
|
|
3074
|
-
}
|
|
3075
|
-
get PropertyWithImage() {
|
|
3076
|
-
return PropertyWithImage;
|
|
3077
|
-
}
|
|
3078
|
-
get dateFormat() {
|
|
3079
|
-
return RestWorldInputSimpleComponent._dateFormat;
|
|
3080
|
-
}
|
|
3081
|
-
// public readonly formControl = computed(() => {
|
|
3082
|
-
// const formGroup = this._controlContainer.control as FormGroup<any>;
|
|
3083
|
-
// return formGroup.controls[this.property().name] as FormControl<SimpleValue | SimpleValue[]>;
|
|
3084
|
-
// });
|
|
3085
|
-
get timeFormat() {
|
|
3086
|
-
return RestWorldInputSimpleComponent._timeFormat;
|
|
3087
|
-
}
|
|
3088
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: RestWorldInputSimpleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3089
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.1", type: RestWorldInputSimpleComponent, isStandalone: true, selector: "rw-input-simple", providers: [{
|
|
3090
|
-
provide: NG_VALUE_ACCESSOR,
|
|
3091
|
-
useExisting: forwardRef(() => RestWorldInputSimpleComponent),
|
|
3092
|
-
multi: true
|
|
3093
|
-
}], viewQueries: [{ propertyName: "_inputChild", first: true, predicate: ["inputElement"], descendants: true, isSignal: true }, { propertyName: "_controlChild", first: true, predicate: NG_VALUE_ACCESSOR, descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "@switch(property().type) {\r\n @case (PropertyType.Textarea) {\r\n @if (useTemplateDrivenForms()){\r\n <textarea #inputElement [propertyAttributes]=\"property()\" [(ngModel)]=\"model\" pInputTextarea class=\"w-full p-inputtextarea p-inputtext p-component p-element\"></textarea>\r\n }\r\n @else {\r\n <textarea #inputElement [formControlProperty]=\"property()\" pInputTextarea class=\"w-full p-inputtextarea p-inputtext p-component p-element\"></textarea>\r\n }\r\n }\r\n @case (PropertyType.Date) {\r\n @if (useTemplateDrivenForms()) {\r\n <p-datepicker [propertyAttributes]=\"property()\" [(ngModel)]=\"model\" [dateFormat]=\"dateFormat\" [showWeek]=\"true\" [showIcon]=\"true\" styleClass=\"w-full\"></p-datepicker>\r\n }\r\n @else {\r\n <p-datepicker [formControlProperty]=\"property()\" [dateFormat]=\"dateFormat\" [showWeek]=\"true\" [showIcon]=\"true\" styleClass=\"w-full\"></p-datepicker>\r\n }\r\n }\r\n @case (PropertyType.Month) {\r\n @if (useTemplateDrivenForms()) {\r\n <p-datepicker [propertyAttributes]=\"property()\" [(ngModel)]=\"model\" [dateFormat]=\"dateFormat\" [showWeek]=\"false\" view=\"month\" [showIcon]=\"true\" styleClass=\"w-full\"></p-datepicker>\r\n }\r\n @else {\r\n <p-datepicker [formControlProperty]=\"property()\" [dateFormat]=\"dateFormat\" [showWeek]=\"false\" view=\"month\" [showIcon]=\"true\" styleClass=\"w-full\"></p-datepicker>\r\n }\r\n }\r\n @case (PropertyType.Time) {\r\n @if (useTemplateDrivenForms()) {\r\n <p-datepicker [propertyAttributes]=\"property()\" [(ngModel)]=\"model\" [dateFormat]=\"timeFormat\" [showTime]=\"true\" [timeOnly]=\"true\" [showWeek]=\"false\" [showIcon]=\"true\" styleClass=\"w-full\"></p-datepicker>\r\n }\r\n @else {\r\n <p-datepicker [formControlProperty]=\"property()\" [dateFormat]=\"timeFormat\" [showTime]=\"true\" [timeOnly]=\"true\" [showWeek]=\"false\" [showIcon]=\"true\" styleClass=\"w-full\"></p-datepicker>\r\n }\r\n }\r\n @case (PropertyType.DatetimeLocal) {\r\n @if (useTemplateDrivenForms()) {\r\n <p-datepicker [propertyAttributes]=\"property()\" [(ngModel)]=\"model\" [dateFormat]=\"dateFormat\" [showTime]=\"true\" [showWeek]=\"false\" [showIcon]=\"true\" styleClass=\"w-full\"></p-datepicker>\r\n }\r\n @else {\r\n <p-datepicker [formControlProperty]=\"property()\" [dateFormat]=\"dateFormat\" [showTime]=\"true\" [showWeek]=\"false\" [showIcon]=\"true\" styleClass=\"w-full\"></p-datepicker>\r\n }\r\n }\r\n @case (PropertyType.Number) {\r\n @if (useTemplateDrivenForms()) {\r\n <p-inputNumber [propertyAttributes]=\"property()\" [(ngModel)]=\"model\" class=\"w-full\" styleClass=\"w-full\"></p-inputNumber>\r\n }\r\n @else {\r\n <p-inputNumber inputMode=\"decimal\" [formControlProperty]=\"property()\" class=\"w-full\" styleClass=\"w-full\"></p-inputNumber>\r\n }\r\n }\r\n @case (PropertyType.Bool) {\r\n @if (useTemplateDrivenForms()) {\r\n <rw-tri-state-checkbox [propertyAttributes]=\"property()\" [(ngModel)]=\"model\" [required]=\"property().required ?? false\"></rw-tri-state-checkbox>\r\n }\r\n @else {\r\n <rw-tri-state-checkbox [formControlProperty]=\"property()\" [required]=\"property().required\"></rw-tri-state-checkbox>\r\n }\r\n }\r\n @case (PropertyType.DatetimeOffset) {\r\n @if (useTemplateDrivenForms()) {\r\n <p-datepicker [propertyAttributes]=\"property()\" [(ngModel)]=\"model\" [dateFormat]=\"dateFormat\" [showTime]=\"true\" [showWeek]=\"false\" [showIcon]=\"true\" styleClass=\"w-full\"></p-datepicker>\r\n }\r\n @else {\r\n <p-datepicker [formControlProperty]=\"property()\" [dateFormat]=\"dateFormat\" [showTime]=\"true\" [showWeek]=\"false\" [showIcon]=\"true\" styleClass=\"w-full\"></p-datepicker>\r\n }\r\n }\r\n @case (PropertyType.Duration) {\r\n @if (useTemplateDrivenForms()) {\r\n <p-datepicker [propertyAttributes]=\"property()\" [(ngModel)]=\"model\" [dateFormat]=\"timeFormat\" [showTime]=\"true\" [timeOnly]=\"true\" [showWeek]=\"false\" [showIcon]=\"true\" styleClass=\"w-full\"></p-datepicker>\r\n }\r\n @else {\r\n <p-datepicker [formControlProperty]=\"property()\" [dateFormat]=\"timeFormat\" [showTime]=\"true\" [timeOnly]=\"true\" [showWeek]=\"false\" [showIcon]=\"true\" styleClass=\"w-full\"></p-datepicker>\r\n }\r\n }\r\n @case (PropertyType.Image) {\r\n @if (useTemplateDrivenForms()) {\r\n <rw-image [propertyAttributes]=\"property()\" [(ngModel)]=\"model\" [formControlName]=\"property().name\" [property]=\"$any(property())\"></rw-image>\r\n }\r\n @else {\r\n <rw-image [formControlName]=\"property().name\" [property]=\"$any(property())\"></rw-image>\r\n }\r\n }\r\n @case (PropertyType.File) {\r\n @if (useTemplateDrivenForms()) {\r\n <rw-file [propertyAttributes]=\"property()\" [(ngModel)]=\"model\" [formControlName]=\"property().name\" [fileName]=\"property().name\" [accept]=\"$any(property().placeholder)\"></rw-file>\r\n }\r\n @else {\r\n <rw-file [formControlName]=\"property().name\" [fileName]=\"property().name\" [accept]=\"$any(property().placeholder)\"></rw-file>\r\n }\r\n }\r\n @default {\r\n <!-- <input [formControlName]=\"property().name\" [id]=\"property().name\" type=\"text\" pInputText class=\"w-full\" [class.p-disabled]=\"property().readOnly\" /> -->\r\n @if (useTemplateDrivenForms()) {\r\n <input #inputElement [propertyAttributes]=\"property()\" [(ngModel)]=\"model\" pInputText class=\"w-full\" />\r\n }\r\n @else {\r\n <input #inputElement [formControlProperty]=\"property()\" pInputText class=\"w-full\" />\r\n }\r\n }\r\n}\r\n", styles: [".p-inputtext.ng-touched.ng-invalid{border-color:#e24c4c}\n"], dependencies: [{ kind: "component", type: DatePicker, selector: "p-datePicker, p-datepicker, p-date-picker", inputs: ["iconDisplay", "styleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "ariaLabelledBy", "ariaLabel", "iconAriaLabel", "dateFormat", "multipleSeparator", "rangeSeparator", "inline", "showOtherMonths", "selectOtherMonths", "showIcon", "icon", "readonlyInput", "shortYearCutoff", "hourFormat", "timeOnly", "stepHour", "stepMinute", "stepSecond", "showSeconds", "showOnFocus", "showWeek", "startWeekFromFirstDayOfYear", "showClear", "dataType", "selectionMode", "maxDateCount", "showButtonBar", "todayButtonStyleClass", "clearButtonStyleClass", "autofocus", "autoZIndex", "baseZIndex", "panelStyleClass", "panelStyle", "keepInvalid", "hideOnDateTimeSelect", "touchUI", "timeSeparator", "focusTrap", "showTransitionOptions", "hideTransitionOptions", "tabindex", "minDate", "maxDate", "disabledDates", "disabledDays", "showTime", "responsiveOptions", "numberOfMonths", "firstDayOfWeek", "view", "defaultDate", "appendTo"], outputs: ["onFocus", "onBlur", "onClose", "onSelect", "onClear", "onInput", "onTodayClick", "onClearClick", "onMonthChange", "onYearChange", "onClickOutside", "onShow"] }, { kind: "component", type: InputNumber, selector: "p-inputNumber, p-inputnumber, p-input-number", inputs: ["showButtons", "format", "buttonLayout", "inputId", "styleClass", "placeholder", "tabindex", "title", "ariaLabelledBy", "ariaDescribedBy", "ariaLabel", "ariaRequired", "autocomplete", "incrementButtonClass", "decrementButtonClass", "incrementButtonIcon", "decrementButtonIcon", "readonly", "allowEmpty", "locale", "localeMatcher", "mode", "currency", "currencyDisplay", "useGrouping", "minFractionDigits", "maxFractionDigits", "prefix", "suffix", "inputStyle", "inputStyleClass", "showClear", "autofocus"], outputs: ["onInput", "onFocus", "onBlur", "onKeyDown", "onClear"] }, { kind: "component", type: TriStateCheckbox, selector: "p-tri-state-checkbox, p-tri-state-checkBox, p-tri-state-check-box, rw-tri-state-checkbox, rw-tri-state-checkBox, rw-tri-state-check-box", inputs: ["value", "name", "disabled", "ariaLabelledBy", "ariaLabel", "tabindex", "inputId", "style", "inputStyle", "styleClass", "inputClass", "size", "formControl", "checkboxIcon", "readonly", "required", "autofocus", "model", "variant"], outputs: ["disabledChange", "modelChange", "onChange", "onFocus", "onBlur"] }, { kind: "component", type: RestWorldImageComponent, selector: "rw-image", inputs: ["property", "backgroundColor", "displayCropDialog"], outputs: ["backgroundColorChange", "displayCropDialogChange"] }, { kind: "component", type: RestWorldFileComponent, selector: "rw-file", inputs: ["accept", "fileName"] }, { kind: "directive", type: InputText, selector: "[pInputText]", inputs: ["pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: HalFormsModule }, { kind: "directive", type: FormControlProperty, selector: "[formControlProperty]:not([useTemplateDrivenForms=true])", inputs: ["formControlProperty"] }, { kind: "directive", type: DefaultPropertyValueAccessor, selector: "input:not([type=checkbox])[formControlProperty], textarea[formControlProperty], select[formControlProperty]" }, { kind: "directive", type: PropertyControlStatus, selector: "[formControlProperty]" }, { kind: "directive", type: PropertyAttributes, selector: "[formControlProperty],[propertyAttributes]", inputs: ["formControlProperty", "propertyAttributes"] }, { kind: "directive", type: PropertyInputNumberAttributes, selector: "p-inputNumber[formControlProperty], p-inputNumber[propertyAttributes]", inputs: ["formControlProperty", "propertyAttributes"] }, { kind: "directive", type: i2$3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$3.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i2$3.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }], viewProviders: [{ provide: ControlContainer, useExisting: FormGroupDirective }] });
|
|
3094
|
-
}
|
|
3095
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: RestWorldInputSimpleComponent, decorators: [{
|
|
3096
|
-
type: Component,
|
|
3097
|
-
args: [{ selector: 'rw-input-simple', standalone: true, providers: [{
|
|
3098
|
-
provide: NG_VALUE_ACCESSOR,
|
|
3099
|
-
useExisting: forwardRef(() => RestWorldInputSimpleComponent),
|
|
3100
|
-
multi: true
|
|
3101
|
-
}], viewProviders: [{ provide: ControlContainer, useExisting: FormGroupDirective }], imports: [DatePicker, InputNumber, TriStateCheckbox, RestWorldImageComponent, RestWorldFileComponent, InputText, HalFormsModule, FormsModule], template: "@switch(property().type) {\r\n @case (PropertyType.Textarea) {\r\n @if (useTemplateDrivenForms()){\r\n <textarea #inputElement [propertyAttributes]=\"property()\" [(ngModel)]=\"model\" pInputTextarea class=\"w-full p-inputtextarea p-inputtext p-component p-element\"></textarea>\r\n }\r\n @else {\r\n <textarea #inputElement [formControlProperty]=\"property()\" pInputTextarea class=\"w-full p-inputtextarea p-inputtext p-component p-element\"></textarea>\r\n }\r\n }\r\n @case (PropertyType.Date) {\r\n @if (useTemplateDrivenForms()) {\r\n <p-datepicker [propertyAttributes]=\"property()\" [(ngModel)]=\"model\" [dateFormat]=\"dateFormat\" [showWeek]=\"true\" [showIcon]=\"true\" styleClass=\"w-full\"></p-datepicker>\r\n }\r\n @else {\r\n <p-datepicker [formControlProperty]=\"property()\" [dateFormat]=\"dateFormat\" [showWeek]=\"true\" [showIcon]=\"true\" styleClass=\"w-full\"></p-datepicker>\r\n }\r\n }\r\n @case (PropertyType.Month) {\r\n @if (useTemplateDrivenForms()) {\r\n <p-datepicker [propertyAttributes]=\"property()\" [(ngModel)]=\"model\" [dateFormat]=\"dateFormat\" [showWeek]=\"false\" view=\"month\" [showIcon]=\"true\" styleClass=\"w-full\"></p-datepicker>\r\n }\r\n @else {\r\n <p-datepicker [formControlProperty]=\"property()\" [dateFormat]=\"dateFormat\" [showWeek]=\"false\" view=\"month\" [showIcon]=\"true\" styleClass=\"w-full\"></p-datepicker>\r\n }\r\n }\r\n @case (PropertyType.Time) {\r\n @if (useTemplateDrivenForms()) {\r\n <p-datepicker [propertyAttributes]=\"property()\" [(ngModel)]=\"model\" [dateFormat]=\"timeFormat\" [showTime]=\"true\" [timeOnly]=\"true\" [showWeek]=\"false\" [showIcon]=\"true\" styleClass=\"w-full\"></p-datepicker>\r\n }\r\n @else {\r\n <p-datepicker [formControlProperty]=\"property()\" [dateFormat]=\"timeFormat\" [showTime]=\"true\" [timeOnly]=\"true\" [showWeek]=\"false\" [showIcon]=\"true\" styleClass=\"w-full\"></p-datepicker>\r\n }\r\n }\r\n @case (PropertyType.DatetimeLocal) {\r\n @if (useTemplateDrivenForms()) {\r\n <p-datepicker [propertyAttributes]=\"property()\" [(ngModel)]=\"model\" [dateFormat]=\"dateFormat\" [showTime]=\"true\" [showWeek]=\"false\" [showIcon]=\"true\" styleClass=\"w-full\"></p-datepicker>\r\n }\r\n @else {\r\n <p-datepicker [formControlProperty]=\"property()\" [dateFormat]=\"dateFormat\" [showTime]=\"true\" [showWeek]=\"false\" [showIcon]=\"true\" styleClass=\"w-full\"></p-datepicker>\r\n }\r\n }\r\n @case (PropertyType.Number) {\r\n @if (useTemplateDrivenForms()) {\r\n <p-inputNumber [propertyAttributes]=\"property()\" [(ngModel)]=\"model\" class=\"w-full\" styleClass=\"w-full\"></p-inputNumber>\r\n }\r\n @else {\r\n <p-inputNumber inputMode=\"decimal\" [formControlProperty]=\"property()\" class=\"w-full\" styleClass=\"w-full\"></p-inputNumber>\r\n }\r\n }\r\n @case (PropertyType.Bool) {\r\n @if (useTemplateDrivenForms()) {\r\n <rw-tri-state-checkbox [propertyAttributes]=\"property()\" [(ngModel)]=\"model\" [required]=\"property().required ?? false\"></rw-tri-state-checkbox>\r\n }\r\n @else {\r\n <rw-tri-state-checkbox [formControlProperty]=\"property()\" [required]=\"property().required\"></rw-tri-state-checkbox>\r\n }\r\n }\r\n @case (PropertyType.DatetimeOffset) {\r\n @if (useTemplateDrivenForms()) {\r\n <p-datepicker [propertyAttributes]=\"property()\" [(ngModel)]=\"model\" [dateFormat]=\"dateFormat\" [showTime]=\"true\" [showWeek]=\"false\" [showIcon]=\"true\" styleClass=\"w-full\"></p-datepicker>\r\n }\r\n @else {\r\n <p-datepicker [formControlProperty]=\"property()\" [dateFormat]=\"dateFormat\" [showTime]=\"true\" [showWeek]=\"false\" [showIcon]=\"true\" styleClass=\"w-full\"></p-datepicker>\r\n }\r\n }\r\n @case (PropertyType.Duration) {\r\n @if (useTemplateDrivenForms()) {\r\n <p-datepicker [propertyAttributes]=\"property()\" [(ngModel)]=\"model\" [dateFormat]=\"timeFormat\" [showTime]=\"true\" [timeOnly]=\"true\" [showWeek]=\"false\" [showIcon]=\"true\" styleClass=\"w-full\"></p-datepicker>\r\n }\r\n @else {\r\n <p-datepicker [formControlProperty]=\"property()\" [dateFormat]=\"timeFormat\" [showTime]=\"true\" [timeOnly]=\"true\" [showWeek]=\"false\" [showIcon]=\"true\" styleClass=\"w-full\"></p-datepicker>\r\n }\r\n }\r\n @case (PropertyType.Image) {\r\n @if (useTemplateDrivenForms()) {\r\n <rw-image [propertyAttributes]=\"property()\" [(ngModel)]=\"model\" [formControlName]=\"property().name\" [property]=\"$any(property())\"></rw-image>\r\n }\r\n @else {\r\n <rw-image [formControlName]=\"property().name\" [property]=\"$any(property())\"></rw-image>\r\n }\r\n }\r\n @case (PropertyType.File) {\r\n @if (useTemplateDrivenForms()) {\r\n <rw-file [propertyAttributes]=\"property()\" [(ngModel)]=\"model\" [formControlName]=\"property().name\" [fileName]=\"property().name\" [accept]=\"$any(property().placeholder)\"></rw-file>\r\n }\r\n @else {\r\n <rw-file [formControlName]=\"property().name\" [fileName]=\"property().name\" [accept]=\"$any(property().placeholder)\"></rw-file>\r\n }\r\n }\r\n @default {\r\n <!-- <input [formControlName]=\"property().name\" [id]=\"property().name\" type=\"text\" pInputText class=\"w-full\" [class.p-disabled]=\"property().readOnly\" /> -->\r\n @if (useTemplateDrivenForms()) {\r\n <input #inputElement [propertyAttributes]=\"property()\" [(ngModel)]=\"model\" pInputText class=\"w-full\" />\r\n }\r\n @else {\r\n <input #inputElement [formControlProperty]=\"property()\" pInputText class=\"w-full\" />\r\n }\r\n }\r\n}\r\n", styles: [".p-inputtext.ng-touched.ng-invalid{border-color:#e24c4c}\n"] }]
|
|
3102
|
-
}], ctorParameters: () => [] });
|
|
3276
|
+
args: [{ selector: 'rw-table-column-filter-element', imports: [RestWorldInputComponent, ReactiveFormsModule], template: "<form [formGroup]=\"form()\">\r\n <rw-input [property]=\"property()\" [apiName]=\"apiName()\"></rw-input>\r\n</form>\r\n" }]
|
|
3277
|
+
}], ctorParameters: () => [{ type: i1$1.FormService }] });
|
|
3278
|
+
|
|
3103
3279
|
/**
|
|
3104
|
-
*
|
|
3105
|
-
*
|
|
3106
|
-
*
|
|
3280
|
+
* Displays a table based on a search-, an edit-template and a list of items.
|
|
3281
|
+
* The search-template is required and used to display the table columns and to filter and sort the items.
|
|
3282
|
+
* The edit-template is optional and used to edit the items. For the edit capability, the table must be part of a reactive form.
|
|
3283
|
+
* The items are displayed as table rows.
|
|
3284
|
+
* The table supports lazy loading, row selection, row menus, and context menus.
|
|
3285
|
+
*
|
|
3107
3286
|
* @example
|
|
3108
|
-
* <rw-
|
|
3287
|
+
* <rw-table
|
|
3288
|
+
* [apiName]="apiName"
|
|
3289
|
+
* [searchTemplate]="searchTemplate"
|
|
3290
|
+
* [editTemplate]="editTemplate"
|
|
3291
|
+
* [rows]="rows"
|
|
3292
|
+
* [rowsPerPageOptions]="[10, 25, 50]"
|
|
3293
|
+
* [headerMenu]="headerMenu"
|
|
3294
|
+
* [rowMenu]="rowMenu"
|
|
3295
|
+
* [rowStyleClass]="rowStyleClass"
|
|
3296
|
+
* [cellStyleClass]="cellStyleClass"
|
|
3297
|
+
* [totalRecords]="totalRecords"
|
|
3298
|
+
* [multiSortMeta]="multiSortMeta"
|
|
3299
|
+
* [styleClass]="styleClass"
|
|
3300
|
+
* [tableStyle]="tableStyle"
|
|
3301
|
+
* [scrollable]="scrollable"
|
|
3302
|
+
* [scrollHeight]="scrollHeight"
|
|
3303
|
+
* [selectionMode]="selectionMode"
|
|
3304
|
+
* [rowHover]="rowHover"
|
|
3305
|
+
* [selection]="selection"
|
|
3306
|
+
* [contextMenuItems]="contextMenuItems"
|
|
3307
|
+
* [isLoading]="isLoading"
|
|
3308
|
+
* [(selectedRows)]="selectedRows"
|
|
3309
|
+
* [(oDataParameters)]="oDataParameters"
|
|
3310
|
+
* </rw-table>
|
|
3311
|
+
*
|
|
3109
3312
|
*/
|
|
3110
|
-
class
|
|
3313
|
+
class RestWorldTableComponent {
|
|
3314
|
+
_controlContainer;
|
|
3315
|
+
_formService;
|
|
3316
|
+
onSort($event) {
|
|
3317
|
+
if (this.lazy())
|
|
3318
|
+
return;
|
|
3319
|
+
console.log("Sort event:", $event);
|
|
3320
|
+
// sort the form array for the indexes to line up with the sorted rows
|
|
3321
|
+
const formArray = this.formArray();
|
|
3322
|
+
const editTemplate = this.editTemplate();
|
|
3323
|
+
if (!formArray || !editTemplate)
|
|
3324
|
+
return;
|
|
3325
|
+
formArray.controls.sort((a, b) => {
|
|
3326
|
+
for (const sortMeta of $event.multisortmeta) {
|
|
3327
|
+
const field = sortMeta.field;
|
|
3328
|
+
const valueA = a.get(field)?.value;
|
|
3329
|
+
const valueB = b.get(field)?.value;
|
|
3330
|
+
const order = sortMeta.order ?? 1;
|
|
3331
|
+
if (valueA === valueB)
|
|
3332
|
+
continue;
|
|
3333
|
+
if (valueA === undefined || valueA === null)
|
|
3334
|
+
return -1 * order;
|
|
3335
|
+
if (valueB === undefined || valueB === null)
|
|
3336
|
+
return 1 * order;
|
|
3337
|
+
if (valueA < valueB)
|
|
3338
|
+
return -1 * order;
|
|
3339
|
+
if (valueA > valueB)
|
|
3340
|
+
return 1 * order;
|
|
3341
|
+
}
|
|
3342
|
+
return 0;
|
|
3343
|
+
});
|
|
3344
|
+
}
|
|
3345
|
+
PropertyType = PropertyType;
|
|
3111
3346
|
/**
|
|
3112
|
-
* The name of the
|
|
3113
|
-
*
|
|
3114
|
-
* @remarks This is the name of the API as defined in the `RestWorldClientCollection`.
|
|
3347
|
+
* The name of the api.
|
|
3348
|
+
* For the editing capability, you must also set the editTemplate and the formArray.
|
|
3115
3349
|
*/
|
|
3116
3350
|
apiName = input.required(...(ngDevMode ? [{ debugName: "apiName" }] : []));
|
|
3117
3351
|
/**
|
|
3118
|
-
*
|
|
3119
|
-
* @
|
|
3120
|
-
* @
|
|
3352
|
+
* A function that returns the style class for a cell.
|
|
3353
|
+
* @param row The row for which to return the style class.
|
|
3354
|
+
* @param column The column for which to return the style class.
|
|
3355
|
+
* @param rowIndex The index of the row on the currently displayed page.
|
|
3356
|
+
* @param columnIndex The index of the column.
|
|
3357
|
+
* @returns The style class for the cell.
|
|
3121
3358
|
*/
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
}
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
* @example
|
|
3136
|
-
* <rw-form
|
|
3137
|
-
* [template]="template"
|
|
3138
|
-
* apiName="apiName"
|
|
3139
|
-
* rel="rel"
|
|
3140
|
-
* [allowSubmit]="true"
|
|
3141
|
-
* [allowDelete]="true"
|
|
3142
|
-
* [allowReload]="true"
|
|
3143
|
-
* [showSubmit]="true"
|
|
3144
|
-
* [showDelete]="true"
|
|
3145
|
-
* [showReload]="true">
|
|
3146
|
-
* <ng-template #content let-form="form" let-template="template" let-apiName="apiName">
|
|
3147
|
-
* <!-- Custom form content here -->
|
|
3148
|
-
* <!-- This is optional and will replace the default which renders labels and inputs if present -->
|
|
3149
|
-
* </ng-template>
|
|
3150
|
-
* <ng-template #buttons let-form="form" let-template="template" let-apiName="apiName">
|
|
3151
|
-
* <!-- Custom buttons here -->
|
|
3152
|
-
* <!-- This is optional and will replace the default which renders the Save, Reload and Delete buttons if present -->
|
|
3153
|
-
* </ng-template>
|
|
3154
|
-
* </rw-form>
|
|
3155
|
-
*/
|
|
3156
|
-
class RestWorldFormComponent {
|
|
3157
|
-
_clients;
|
|
3158
|
-
_confirmationService;
|
|
3159
|
-
_messageService;
|
|
3160
|
-
_formService;
|
|
3161
|
-
_elementRef;
|
|
3162
|
-
_problemService;
|
|
3359
|
+
cellStyleClass = input(() => "", ...(ngDevMode ? [{ debugName: "cellStyleClass" }] : []));
|
|
3360
|
+
cellStyleClasses = computed(() => this.rows().map((r, ri) => Object.fromEntries(this.columns().map((c, ci) => [c.name, this.cellStyleClass()(r, c, ri, ci)]))), ...(ngDevMode ? [{ debugName: "cellStyleClasses" }] : []));
|
|
3361
|
+
columns = computed(() => this.searchTemplate()?.properties.filter(p => p.type !== PropertyType.Hidden) ?? [], ...(ngDevMode ? [{ debugName: "columns" }] : []));
|
|
3362
|
+
contextMenu = viewChild("contextMenu", ...(ngDevMode ? [{ debugName: "contextMenu" }] : []));
|
|
3363
|
+
primeNgTable = viewChild.required("table");
|
|
3364
|
+
contextMenuItems = signal([], ...(ngDevMode ? [{ debugName: "contextMenuItems" }] : []));
|
|
3365
|
+
dateFormat = new Date(3333, 10, 22) // months start at 0 in JS
|
|
3366
|
+
.toLocaleDateString()
|
|
3367
|
+
.replace("22", "dd")
|
|
3368
|
+
.replace("11", "MM")
|
|
3369
|
+
.replace("3333", "yy")
|
|
3370
|
+
.replace("33", "y");
|
|
3371
|
+
editProperties = computed(() => this.editTemplate()?.propertiesRecord ?? {}, ...(ngDevMode ? [{ debugName: "editProperties" }] : []));
|
|
3163
3372
|
/**
|
|
3164
|
-
*
|
|
3373
|
+
* The template that is used to edit the items.
|
|
3374
|
+
* Bind this to the template that is used to edit the items.
|
|
3375
|
+
* Normally this is returned from the backend as part of the hal-forms resource from a list endpoint.
|
|
3376
|
+
* For the editing capability, you must also set the apiName and the formArray.
|
|
3165
3377
|
*/
|
|
3166
|
-
|
|
3378
|
+
editTemplate = input(...(ngDevMode ? [undefined, { debugName: "editTemplate" }] : []));
|
|
3379
|
+
filters = computed(() => {
|
|
3380
|
+
const filter = this.oDataParameters().$filter;
|
|
3381
|
+
const properties = this.searchTemplate()?.propertiesRecord;
|
|
3382
|
+
if (filter === null || filter === undefined || typeof filter !== "string" || properties === undefined)
|
|
3383
|
+
return {};
|
|
3384
|
+
return ODataService.createFilterMetadataFromODataFilter(filter, properties);
|
|
3385
|
+
}, ...(ngDevMode ? [{ debugName: "filters" }] : []));
|
|
3167
3386
|
/**
|
|
3168
|
-
*
|
|
3387
|
+
* The form array that contains the form groups for the items.
|
|
3388
|
+
* Bind this to the form array that contains the form groups for the items.
|
|
3389
|
+
* Each entry in the array represents one row in the currently displayed page of the table.
|
|
3390
|
+
* For the editing capability, you must also set the apiName and the editTemplate.
|
|
3169
3391
|
*/
|
|
3170
|
-
|
|
3171
|
-
/**
|
|
3172
|
-
* Determines whether to enable the delete button.
|
|
3173
|
-
*/
|
|
3174
|
-
allowDelete = input(true, ...(ngDevMode ? [{ debugName: "allowDelete" }] : []));
|
|
3175
|
-
/**
|
|
3176
|
-
* Determines whether to enable the reload button.
|
|
3177
|
-
*/
|
|
3178
|
-
allowReload = input(true, ...(ngDevMode ? [{ debugName: "allowReload" }] : []));
|
|
3179
|
-
/**
|
|
3180
|
-
* Determines whether to enable the submit button.
|
|
3181
|
-
*/
|
|
3182
|
-
allowSubmit = input(true, ...(ngDevMode ? [{ debugName: "allowSubmit" }] : []));
|
|
3392
|
+
formArray = computed(() => this._controlContainer?.control, ...(ngDevMode ? [{ debugName: "formArray" }] : []));
|
|
3183
3393
|
/**
|
|
3184
|
-
*
|
|
3394
|
+
* An optional menu that is displayed at the top right of the table.
|
|
3395
|
+
* @see RestWorldMenuButtonComponent
|
|
3185
3396
|
*/
|
|
3186
|
-
|
|
3397
|
+
headerMenu = input([], ...(ngDevMode ? [{ debugName: "headerMenu" }] : []));
|
|
3398
|
+
isEditable = computed(() => this.editTemplate() !== undefined && this.formArray() !== undefined && this.apiName() !== undefined, ...(ngDevMode ? [{ debugName: "isEditable" }] : []));
|
|
3187
3399
|
/**
|
|
3188
|
-
*
|
|
3400
|
+
* Indicates whether the table is currently loading.
|
|
3401
|
+
* Set this to true while loading new items from the backend when reacting to the `onFilterOrSortChanged` event.
|
|
3189
3402
|
*/
|
|
3190
|
-
|
|
3191
|
-
this.template() !== undefined &&
|
|
3192
|
-
this.template().target !== undefined &&
|
|
3193
|
-
this.template().method == "PUT" &&
|
|
3194
|
-
this.formGroup() !== undefined &&
|
|
3195
|
-
this.formGroup()?.value.id !== undefined &&
|
|
3196
|
-
this.formGroup()?.value.timestamp !== undefined &&
|
|
3197
|
-
!this.isLoading(), ...(ngDevMode ? [{ debugName: "canDelete" }] : []));
|
|
3403
|
+
isLoading = input(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
|
|
3198
3404
|
/**
|
|
3199
|
-
*
|
|
3405
|
+
* Indicates whether the table is lazy loaded.
|
|
3406
|
+
* If set to true, sorting and filtering needs to be handled by the `load` event.
|
|
3407
|
+
* If set to false, sorting and filtering is handled by the table component itself.
|
|
3408
|
+
* The default is `true`.
|
|
3409
|
+
* @see load
|
|
3200
3410
|
*/
|
|
3201
|
-
|
|
3202
|
-
this.template() !== undefined &&
|
|
3203
|
-
this.template().target !== undefined &&
|
|
3204
|
-
this.template().title !== undefined &&
|
|
3205
|
-
this.template().properties.some(p => p.name === "id" && p.value !== undefined && p.value !== null && p.value !== 0) &&
|
|
3206
|
-
!this.isLoading(), ...(ngDevMode ? [{ debugName: "canReload" }] : []));
|
|
3411
|
+
lazy = input(true, ...(ngDevMode ? [{ debugName: "lazy" }] : []));
|
|
3207
3412
|
/**
|
|
3208
|
-
*
|
|
3413
|
+
* Indicates whether the table has a paginator.
|
|
3414
|
+
* If set to true, the table will display a paginator at the bottom.
|
|
3415
|
+
* If set to false, the table will not display a paginator and all rows will be displayed at once.
|
|
3416
|
+
* The default is `true`.
|
|
3417
|
+
* In order to customize the number of rows per page, you can set the `rowsPerPageOptions` property.
|
|
3418
|
+
* @see rowsPerPageOptions
|
|
3209
3419
|
*/
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
this.
|
|
3213
|
-
|
|
3214
|
-
|
|
3420
|
+
paginator = input(true, ...(ngDevMode ? [{ debugName: "paginator" }] : []));
|
|
3421
|
+
multiSortMeta = computed(() => {
|
|
3422
|
+
const orderBy = this.oDataParameters().$orderby;
|
|
3423
|
+
if (orderBy === null || orderBy === undefined || typeof orderBy !== "string")
|
|
3424
|
+
return undefined;
|
|
3425
|
+
return orderBy
|
|
3426
|
+
.split(",")
|
|
3427
|
+
.map(o => o.trim())
|
|
3428
|
+
.filter(o => o !== "")
|
|
3429
|
+
.map(o => {
|
|
3430
|
+
const [field, order] = o.split(" ");
|
|
3431
|
+
const orderAsNumber = order?.toLowerCase() === "desc" ? -1 : 1;
|
|
3432
|
+
return { field: field, order: orderAsNumber };
|
|
3433
|
+
});
|
|
3434
|
+
}, ...(ngDevMode ? [{ debugName: "multiSortMeta" }] : []));
|
|
3435
|
+
oDataParameters = model({}, ...(ngDevMode ? [{ debugName: "oDataParameters" }] : []));
|
|
3436
|
+
reflectParametersInUrl = input(true, ...(ngDevMode ? [{ debugName: "reflectParametersInUrl" }] : []));
|
|
3215
3437
|
/**
|
|
3216
|
-
*
|
|
3438
|
+
* Indicates whether the table rows are highlighted when the mouse hovers over them.
|
|
3217
3439
|
*/
|
|
3218
|
-
|
|
3219
|
-
isLoading = signal(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
|
|
3440
|
+
rowHover = input(false, ...(ngDevMode ? [{ debugName: "rowHover" }] : []));
|
|
3220
3441
|
/**
|
|
3221
|
-
*
|
|
3442
|
+
* A function that returns the menu for a row.
|
|
3443
|
+
* Based on the openedByRightClick parameter, the function can return different menus.
|
|
3444
|
+
* The menu when it has not been opened by a right click is displayed in an extra column to the right of the table if `showRowMenuAsColumn` is `true`.
|
|
3445
|
+
* The menu when it has been opened by a right click is displayed as a context menu if `showRowMenuOnRightClick` is `true`.
|
|
3446
|
+
* @param row The row for which to return the menu.
|
|
3447
|
+
* @param openedByRightClick Indicates whether the menu was opened by a right click.
|
|
3448
|
+
* @returns The menu for the row.
|
|
3449
|
+
* @see showRowMenuAsColumn
|
|
3450
|
+
* @see showRowMenuOnRightClick
|
|
3451
|
+
*/
|
|
3452
|
+
rowMenu = input(() => [], ...(ngDevMode ? [{ debugName: "rowMenu" }] : []));
|
|
3453
|
+
rowMenus = computed(() => {
|
|
3454
|
+
return this.showRowMenuAsColumn() ? this.rows().map(r => this.rowMenu()(r, false)) : [];
|
|
3455
|
+
}, ...(ngDevMode ? [{ debugName: "rowMenus" }] : []));
|
|
3456
|
+
/**
|
|
3457
|
+
* A function that returns the style class for a row.
|
|
3458
|
+
* @param row The row for which to return the style class.
|
|
3459
|
+
* @param rowIndex The index of the row on the currently displayed page.
|
|
3460
|
+
* @returns The style class for the row.
|
|
3222
3461
|
*/
|
|
3223
|
-
|
|
3462
|
+
rowStyleClass = input(() => "", ...(ngDevMode ? [{ debugName: "rowStyleClass" }] : []));
|
|
3463
|
+
rowStyleClasses = computed(() => this.rows().map((r, i) => this.rowStyleClass()(r, i)), ...(ngDevMode ? [{ debugName: "rowStyleClasses" }] : []));
|
|
3224
3464
|
/**
|
|
3225
|
-
*
|
|
3226
|
-
|
|
3227
|
-
|
|
3465
|
+
* The items that are displayed as table rows.
|
|
3466
|
+
* Bind this to the items that are displayed as table rows.
|
|
3467
|
+
* Normally this is returned from the backend as part of the hal-forms resource from a list endpoint.
|
|
3468
|
+
*/
|
|
3469
|
+
rows = input.required(...(ngDevMode ? [{ debugName: "rows" }] : []));
|
|
3470
|
+
rowsBeforeCurrentPage = computed(() => this.oDataParameters().$skip ?? 0, ...(ngDevMode ? [{ debugName: "rowsBeforeCurrentPage" }] : []));
|
|
3228
3471
|
/**
|
|
3229
|
-
*
|
|
3230
|
-
|
|
3231
|
-
|
|
3472
|
+
* The number of rows per page.
|
|
3473
|
+
* The default is the first element of rowsPerPageOptions.
|
|
3474
|
+
*/
|
|
3475
|
+
rowsPerPage = computed(() => this.oDataParameters().$top ?? this.rowsPerPageOptions()[0], ...(ngDevMode ? [{ debugName: "rowsPerPage" }] : []));
|
|
3232
3476
|
/**
|
|
3233
|
-
*
|
|
3234
|
-
|
|
3235
|
-
|
|
3477
|
+
* The possible values for the number of rows per page.
|
|
3478
|
+
* The default is [10, 25, 50].
|
|
3479
|
+
*/
|
|
3480
|
+
rowsPerPageOptions = input([10, 25, 50], ...(ngDevMode ? [{ debugName: "rowsPerPageOptions" }] : []));
|
|
3236
3481
|
/**
|
|
3237
|
-
* The
|
|
3482
|
+
* The height of the scrollable table.
|
|
3483
|
+
* The default is "flex".
|
|
3238
3484
|
*/
|
|
3239
|
-
|
|
3485
|
+
scrollHeight = input("flex", ...(ngDevMode ? [{ debugName: "scrollHeight" }] : []));
|
|
3240
3486
|
/**
|
|
3241
|
-
*
|
|
3487
|
+
* Indicates whether the table is scrollable.
|
|
3488
|
+
* The default is `true`.
|
|
3242
3489
|
*/
|
|
3243
|
-
|
|
3490
|
+
scrollable = input(true, ...(ngDevMode ? [{ debugName: "scrollable" }] : []));
|
|
3244
3491
|
/**
|
|
3245
|
-
*
|
|
3246
|
-
|
|
3247
|
-
|
|
3492
|
+
* The template that is used to display the table columns and to filter and sort the items.
|
|
3493
|
+
* Bind this to the template that is used to display the table columns and to filter and sort the items.
|
|
3494
|
+
* Normally this is returned from the backend as part of the hal-forms resource from a list endpoint.
|
|
3495
|
+
*/
|
|
3496
|
+
searchTemplate = input.required(...(ngDevMode ? [{ debugName: "searchTemplate" }] : []));
|
|
3248
3497
|
/**
|
|
3249
|
-
*
|
|
3250
|
-
|
|
3251
|
-
|
|
3498
|
+
* The currently selected rows.
|
|
3499
|
+
*/
|
|
3500
|
+
selectedRows = model([], ...(ngDevMode ? [{ debugName: "selectedRows" }] : []));
|
|
3252
3501
|
/**
|
|
3253
|
-
*
|
|
3254
|
-
|
|
3255
|
-
|
|
3502
|
+
* The mode how rows can be selected.
|
|
3503
|
+
* The default is `null` which means rows cannot be selected.
|
|
3504
|
+
*/
|
|
3505
|
+
selectionMode = input(null, ...(ngDevMode ? [{ debugName: "selectionMode" }] : []));
|
|
3506
|
+
showMenuColumn = computed(() => this.headerMenu().length > 0 || (this.showRowMenuAsColumn() && this.rowMenus().some(m => m.length > 0)), ...(ngDevMode ? [{ debugName: "showMenuColumn" }] : []));
|
|
3256
3507
|
/**
|
|
3257
|
-
*
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3508
|
+
* Indicates whether the row menu is displayed as a column to the right of the table.
|
|
3509
|
+
*/
|
|
3510
|
+
showRowMenuAsColumn = input(true, ...(ngDevMode ? [{ debugName: "showRowMenuAsColumn" }] : []));
|
|
3511
|
+
/**
|
|
3512
|
+
* Indicates whether the row menu is displayed as a context menu when the user right clicks on a row.
|
|
3513
|
+
*/
|
|
3514
|
+
showRowMenuOnRightClick = input(true, ...(ngDevMode ? [{ debugName: "showRowMenuOnRightClick" }] : []));
|
|
3515
|
+
/**
|
|
3516
|
+
* The style class for the table.
|
|
3517
|
+
* The default is "".
|
|
3518
|
+
*/
|
|
3519
|
+
styleClass = input("", ...(ngDevMode ? [{ debugName: "styleClass" }] : []));
|
|
3520
|
+
/**
|
|
3521
|
+
* The inline style for the table.
|
|
3522
|
+
*/
|
|
3523
|
+
tableStyle = input(...(ngDevMode ? [undefined, { debugName: "tableStyle" }] : []));
|
|
3524
|
+
totalRecords = input(0, ...(ngDevMode ? [{ debugName: "totalRecords" }] : []));
|
|
3525
|
+
urlParameterPrefix = input("", ...(ngDevMode ? [{ debugName: "urlParameterPrefix" }] : []));
|
|
3526
|
+
// private _formArray?: FormArray<FormGroup<{ [K in keyof TListItem]: AbstractControl<unknown> }>>;
|
|
3527
|
+
_filterMatchModeOptions;
|
|
3528
|
+
timeFormat = new Date(1, 1, 1, 22, 33, 44)
|
|
3529
|
+
.toLocaleTimeString()
|
|
3530
|
+
.replace("22", "hh")
|
|
3531
|
+
.replace("33", "mm")
|
|
3532
|
+
.replace("44", "ss");
|
|
3533
|
+
_initialQueryParamsSet = false;
|
|
3534
|
+
_lastUsedFilters = {};
|
|
3535
|
+
constructor(_controlContainer, _formService, router, activatedRoute, primeNGConfig, filterService) {
|
|
3536
|
+
this._controlContainer = _controlContainer;
|
|
3266
3537
|
this._formService = _formService;
|
|
3267
|
-
this.
|
|
3268
|
-
|
|
3269
|
-
|
|
3538
|
+
this._filterMatchModeOptions = {
|
|
3539
|
+
text: [TranslationKeys.NO_FILTER, ...primeNGConfig.filterMatchModeOptions.text].map(o => ({ label: primeNGConfig.getTranslation(o), value: o })),
|
|
3540
|
+
numeric: [TranslationKeys.NO_FILTER, ...primeNGConfig.filterMatchModeOptions.numeric].map(o => ({ label: primeNGConfig.getTranslation(o), value: o })),
|
|
3541
|
+
date: [TranslationKeys.NO_FILTER, ...primeNGConfig.filterMatchModeOptions.date].map(o => ({ label: primeNGConfig.getTranslation(o), value: o })),
|
|
3542
|
+
boolean: [TranslationKeys.NO_FILTER, TranslationKeys.EQUALS, TranslationKeys.NOT_EQUALS].map(o => ({ label: primeNGConfig.getTranslation(o), value: o })),
|
|
3543
|
+
enum: [TranslationKeys.NO_FILTER, TranslationKeys.EQUALS, TranslationKeys.NOT_EQUALS].map(o => ({ label: primeNGConfig.getTranslation(o), value: o })),
|
|
3544
|
+
};
|
|
3545
|
+
filterService.register(TranslationKeys.NO_FILTER, () => true);
|
|
3546
|
+
// Update the form array on changes
|
|
3270
3547
|
effect(() => {
|
|
3271
|
-
this.
|
|
3272
|
-
const
|
|
3273
|
-
|
|
3274
|
-
this.
|
|
3548
|
+
const formArray = this.formArray();
|
|
3549
|
+
const editTemplate = this.editTemplate();
|
|
3550
|
+
const rows = this.rows();
|
|
3551
|
+
const lazy = this.lazy();
|
|
3552
|
+
if (!this.isEditable() || !formArray || !editTemplate || !lazy)
|
|
3553
|
+
return;
|
|
3554
|
+
formArray.clear();
|
|
3555
|
+
const newControls = rows
|
|
3556
|
+
.map(r => {
|
|
3557
|
+
const formGroup = this._formService.createFormGroupFromTemplate(editTemplate);
|
|
3558
|
+
formGroup.patchValue(r);
|
|
3559
|
+
return formGroup;
|
|
3560
|
+
});
|
|
3561
|
+
for (const control of newControls)
|
|
3562
|
+
formArray.push(control);
|
|
3563
|
+
});
|
|
3564
|
+
// update the url when the oDataParameters change
|
|
3565
|
+
effect(async () => {
|
|
3566
|
+
if (!this.reflectParametersInUrl())
|
|
3567
|
+
return;
|
|
3568
|
+
const urlParameterPrefix = this.urlParameterPrefix();
|
|
3569
|
+
const oDataParameters = this.oDataParameters();
|
|
3570
|
+
// Set the initial query parameters on the first change
|
|
3571
|
+
if (!this._initialQueryParamsSet) {
|
|
3572
|
+
this._initialQueryParamsSet = true;
|
|
3573
|
+
const oDataParametersFromUrl = ODataService.createParametersFromRoute(activatedRoute, urlParameterPrefix);
|
|
3574
|
+
const mergedParameters = { ...oDataParameters, ...oDataParametersFromUrl };
|
|
3575
|
+
this.oDataParameters.set(mergedParameters);
|
|
3576
|
+
return;
|
|
3577
|
+
}
|
|
3578
|
+
// Update the query parameters in the url after the first change
|
|
3579
|
+
const parameters = this.prefixObjectProperties(oDataParameters, urlParameterPrefix);
|
|
3580
|
+
await router.navigate([], { queryParams: parameters, queryParamsHandling: 'merge' });
|
|
3275
3581
|
});
|
|
3276
3582
|
}
|
|
3277
|
-
|
|
3278
|
-
|
|
3583
|
+
getFormGroupAtIndex(indexOnCurrentPage) {
|
|
3584
|
+
const formArray = this.formArray();
|
|
3585
|
+
if (!formArray)
|
|
3586
|
+
return undefined;
|
|
3587
|
+
const finalIndex = this.getAbsoluteIndex(indexOnCurrentPage);
|
|
3588
|
+
return formArray.at(finalIndex);
|
|
3589
|
+
}
|
|
3590
|
+
getAbsoluteIndex(indexOnCurrentPage) {
|
|
3591
|
+
const lazy = this.lazy();
|
|
3592
|
+
if (!lazy)
|
|
3593
|
+
return indexOnCurrentPage;
|
|
3594
|
+
const primeNgTable = this.primeNgTable();
|
|
3595
|
+
if (!primeNgTable)
|
|
3596
|
+
return indexOnCurrentPage;
|
|
3597
|
+
return indexOnCurrentPage - (primeNgTable.first ?? 0);
|
|
3598
|
+
}
|
|
3599
|
+
load(event) {
|
|
3600
|
+
this.fixUserFilterErrors(event.filters);
|
|
3601
|
+
// this.multiSortMeta = event.multiSortMeta;
|
|
3602
|
+
const currentParameters = this.oDataParameters();
|
|
3603
|
+
const searchTemplate = this.searchTemplate();
|
|
3604
|
+
if (!searchTemplate || searchTemplate.properties.length === 0)
|
|
3279
3605
|
return;
|
|
3280
|
-
const
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
if (template === undefined)
|
|
3285
|
-
throw new Error("template cannot be undefined.");
|
|
3286
|
-
// canDelete already checks that the timestamp is present, so the cast is safe.
|
|
3287
|
-
const result = await this._client().deleteByTemplateAndForm(template, formGroup);
|
|
3288
|
-
if (this._problemService.checkResponseAndDisplayErrors(result, formGroup)) {
|
|
3289
|
-
this._messageService.add({ severity: 'success', summary: 'Deleted', detail: 'The resource has been deleted.' });
|
|
3290
|
-
this.afterDelete.emit();
|
|
3291
|
-
}
|
|
3606
|
+
const parameters = ODataService.createParametersFromTableLoadEvent(event, searchTemplate);
|
|
3607
|
+
ODataService.createFilterMetadataFromODataFilter(parameters.$filter, searchTemplate.propertiesRecord);
|
|
3608
|
+
if (currentParameters.$filter !== parameters.$filter || currentParameters.$orderby !== parameters.$orderby || currentParameters.$top !== parameters.$top || currentParameters.$skip !== parameters.$skip)
|
|
3609
|
+
this.oDataParameters.set(parameters);
|
|
3292
3610
|
}
|
|
3293
|
-
|
|
3294
|
-
const
|
|
3295
|
-
|
|
3296
|
-
if (!canReload || template === undefined)
|
|
3611
|
+
openContextMenu(event, row) {
|
|
3612
|
+
const contextMenu = this.contextMenu();
|
|
3613
|
+
if (!this.showRowMenuOnRightClick() || contextMenu === undefined)
|
|
3297
3614
|
return;
|
|
3298
|
-
this.
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
if (this._problemService.checkResponseAndDisplayErrors(response, this.formGroup())) {
|
|
3302
|
-
this.template.set(response.body.getTemplateByTitle(template.title));
|
|
3303
|
-
}
|
|
3304
|
-
}
|
|
3305
|
-
catch (e) {
|
|
3306
|
-
this._messageService.add({ severity: 'error', summary: 'Error', detail: `An unknown error occurred. ${JSON.stringify(e)}`, sticky: true });
|
|
3307
|
-
console.log(e);
|
|
3308
|
-
}
|
|
3309
|
-
this.isLoading.set(false);
|
|
3615
|
+
this.contextMenuItems.set(this.rowMenu()(row, true));
|
|
3616
|
+
contextMenu.show(event);
|
|
3617
|
+
event.stopPropagation();
|
|
3310
3618
|
}
|
|
3311
|
-
|
|
3312
|
-
this.
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
accept: () => this.delete()
|
|
3317
|
-
});
|
|
3619
|
+
showInputField(column) {
|
|
3620
|
+
if (!this.isEditable())
|
|
3621
|
+
return false;
|
|
3622
|
+
const editProperty = this.editProperties()[column.name];
|
|
3623
|
+
return editProperty !== undefined && editProperty.type !== PropertyType.Hidden && !editProperty.readOnly;
|
|
3318
3624
|
}
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3625
|
+
toColumnFilterType(property) {
|
|
3626
|
+
if (!property)
|
|
3627
|
+
return ColumnFilterType.text;
|
|
3628
|
+
const propertyType = property.type;
|
|
3629
|
+
switch (propertyType) {
|
|
3630
|
+
case PropertyType.Number:
|
|
3631
|
+
case PropertyType.Percent:
|
|
3632
|
+
case PropertyType.Currency:
|
|
3633
|
+
case PropertyType.Month:
|
|
3634
|
+
return ColumnFilterType.numeric;
|
|
3635
|
+
case PropertyType.Bool:
|
|
3636
|
+
return ColumnFilterType.boolean;
|
|
3637
|
+
case PropertyType.Date:
|
|
3638
|
+
case PropertyType.DatetimeLocal:
|
|
3639
|
+
case PropertyType.DatetimeOffset:
|
|
3640
|
+
return ColumnFilterType.date;
|
|
3641
|
+
default:
|
|
3642
|
+
return property.options ? property.options.link ? ColumnFilterType.numeric : ColumnFilterType.enum : ColumnFilterType.text;
|
|
3333
3643
|
}
|
|
3334
|
-
|
|
3644
|
+
}
|
|
3645
|
+
toMatchModeOptions(property) {
|
|
3646
|
+
const columnFilterType = this.toColumnFilterType(property);
|
|
3647
|
+
return this._filterMatchModeOptions[columnFilterType];
|
|
3648
|
+
}
|
|
3649
|
+
toMaxFractionDigits(property) {
|
|
3650
|
+
switch (property.type) {
|
|
3651
|
+
case PropertyType.Number:
|
|
3652
|
+
case PropertyType.Percent:
|
|
3653
|
+
case PropertyType.Currency:
|
|
3654
|
+
return property.step?.toString().split(".")[1]?.length ?? 2;
|
|
3655
|
+
case PropertyType.Month:
|
|
3656
|
+
return 0;
|
|
3657
|
+
default:
|
|
3658
|
+
return undefined;
|
|
3659
|
+
}
|
|
3660
|
+
}
|
|
3661
|
+
fixUserFilterError(filterEntry, lastFilterEntry, propertyName) {
|
|
3662
|
+
if (!filterEntry)
|
|
3335
3663
|
return;
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3664
|
+
if (lastFilterEntry !== undefined &&
|
|
3665
|
+
lastFilterEntry.matchMode !== TranslationKeys.NO_FILTER &&
|
|
3666
|
+
filterEntry.matchMode === TranslationKeys.NO_FILTER) {
|
|
3667
|
+
// The user changed the mode from something to no filter
|
|
3668
|
+
// => We reset the value
|
|
3669
|
+
filterEntry.value = null;
|
|
3670
|
+
}
|
|
3671
|
+
else if (filterEntry.matchMode === TranslationKeys.NO_FILTER &&
|
|
3672
|
+
(lastFilterEntry === undefined || lastFilterEntry.value === null) &&
|
|
3673
|
+
filterEntry.value !== null) {
|
|
3674
|
+
// The user entered a value into the filter, but forgot to change the mode
|
|
3675
|
+
// => We set the match mode to the default for the type that is not no filter
|
|
3676
|
+
filterEntry.matchMode = this._filterMatchModeOptions[this.toColumnFilterType(this.searchTemplate().propertiesRecord[propertyName])][1].value;
|
|
3677
|
+
}
|
|
3678
|
+
}
|
|
3679
|
+
fixUserFilterErrors(filters) {
|
|
3680
|
+
if (!filters)
|
|
3681
|
+
return;
|
|
3682
|
+
Object.entries(filters).forEach(([propertyName, filter]) => {
|
|
3683
|
+
const lastFilter = this._lastUsedFilters[propertyName];
|
|
3684
|
+
if (Array.isArray(filter)) {
|
|
3685
|
+
filter.forEach((filterEntry, index) => this.fixUserFilterError(filterEntry, Array.isArray(lastFilter) ? lastFilter[index] : lastFilter, propertyName));
|
|
3349
3686
|
}
|
|
3350
3687
|
else {
|
|
3351
|
-
|
|
3352
|
-
const newTemplate = responseResource.getTemplateByTitle(template.title);
|
|
3353
|
-
this.template.set(newTemplate);
|
|
3354
|
-
this._messageService.add({ severity: 'success', summary: 'Saved', detail: 'The resource has been saved.' });
|
|
3355
|
-
this.afterSubmit.emit({ old: template, new: newTemplate, status: 200 });
|
|
3688
|
+
this.fixUserFilterError(filter, Array.isArray(lastFilter) ? lastFilter[0] : lastFilter, propertyName);
|
|
3356
3689
|
}
|
|
3357
|
-
}
|
|
3358
|
-
|
|
3359
|
-
this._messageService.add({ severity: 'error', summary: 'Error', detail: `An unknown error occurred. ${JSON.stringify(e)}`, sticky: true });
|
|
3360
|
-
console.log(e);
|
|
3361
|
-
}
|
|
3362
|
-
this.isLoading.set(false);
|
|
3690
|
+
});
|
|
3691
|
+
this._lastUsedFilters = JSON.parse(JSON.stringify(filters));
|
|
3363
3692
|
}
|
|
3364
|
-
|
|
3365
|
-
|
|
3693
|
+
prefixObjectProperties(obj, prefix) {
|
|
3694
|
+
return Object.fromEntries(Object.entries(obj).map(([key, value]) => [`${prefix}${key}`, value]));
|
|
3695
|
+
}
|
|
3696
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: RestWorldTableComponent, deps: [{ token: i2$3.ControlContainer }, { token: i1$1.FormService }, { token: i3$3.Router }, { token: i3$3.ActivatedRoute }, { token: i4$2.PrimeNG }, { token: i2$1.FilterService }], target: i0.ɵɵFactoryTarget.Component });
|
|
3697
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.1", type: RestWorldTableComponent, isStandalone: true, selector: "rw-table", inputs: { apiName: { classPropertyName: "apiName", publicName: "apiName", isSignal: true, isRequired: true, transformFunction: null }, cellStyleClass: { classPropertyName: "cellStyleClass", publicName: "cellStyleClass", isSignal: true, isRequired: false, transformFunction: null }, editTemplate: { classPropertyName: "editTemplate", publicName: "editTemplate", isSignal: true, isRequired: false, transformFunction: null }, headerMenu: { classPropertyName: "headerMenu", publicName: "headerMenu", isSignal: true, isRequired: false, transformFunction: null }, isLoading: { classPropertyName: "isLoading", publicName: "isLoading", isSignal: true, isRequired: false, transformFunction: null }, lazy: { classPropertyName: "lazy", publicName: "lazy", isSignal: true, isRequired: false, transformFunction: null }, paginator: { classPropertyName: "paginator", publicName: "paginator", isSignal: true, isRequired: false, transformFunction: null }, oDataParameters: { classPropertyName: "oDataParameters", publicName: "oDataParameters", isSignal: true, isRequired: false, transformFunction: null }, reflectParametersInUrl: { classPropertyName: "reflectParametersInUrl", publicName: "reflectParametersInUrl", isSignal: true, isRequired: false, transformFunction: null }, rowHover: { classPropertyName: "rowHover", publicName: "rowHover", isSignal: true, isRequired: false, transformFunction: null }, rowMenu: { classPropertyName: "rowMenu", publicName: "rowMenu", isSignal: true, isRequired: false, transformFunction: null }, rowStyleClass: { classPropertyName: "rowStyleClass", publicName: "rowStyleClass", isSignal: true, isRequired: false, transformFunction: null }, rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: true, transformFunction: null }, rowsPerPageOptions: { classPropertyName: "rowsPerPageOptions", publicName: "rowsPerPageOptions", isSignal: true, isRequired: false, transformFunction: null }, scrollHeight: { classPropertyName: "scrollHeight", publicName: "scrollHeight", isSignal: true, isRequired: false, transformFunction: null }, scrollable: { classPropertyName: "scrollable", publicName: "scrollable", isSignal: true, isRequired: false, transformFunction: null }, searchTemplate: { classPropertyName: "searchTemplate", publicName: "searchTemplate", isSignal: true, isRequired: true, transformFunction: null }, selectedRows: { classPropertyName: "selectedRows", publicName: "selectedRows", isSignal: true, isRequired: false, transformFunction: null }, selectionMode: { classPropertyName: "selectionMode", publicName: "selectionMode", isSignal: true, isRequired: false, transformFunction: null }, showRowMenuAsColumn: { classPropertyName: "showRowMenuAsColumn", publicName: "showRowMenuAsColumn", isSignal: true, isRequired: false, transformFunction: null }, showRowMenuOnRightClick: { classPropertyName: "showRowMenuOnRightClick", publicName: "showRowMenuOnRightClick", isSignal: true, isRequired: false, transformFunction: null }, styleClass: { classPropertyName: "styleClass", publicName: "styleClass", isSignal: true, isRequired: false, transformFunction: null }, tableStyle: { classPropertyName: "tableStyle", publicName: "tableStyle", isSignal: true, isRequired: false, transformFunction: null }, totalRecords: { classPropertyName: "totalRecords", publicName: "totalRecords", isSignal: true, isRequired: false, transformFunction: null }, urlParameterPrefix: { classPropertyName: "urlParameterPrefix", publicName: "urlParameterPrefix", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { oDataParameters: "oDataParametersChange", selectedRows: "selectedRowsChange" }, viewQueries: [{ propertyName: "contextMenu", first: true, predicate: ["contextMenu"], descendants: true, isSignal: true }, { propertyName: "primeNgTable", first: true, predicate: ["table"], descendants: true, isSignal: true }], ngImport: i0, template: "<p-table\r\n #table\r\n [value]=\"rows()\"\r\n [columns]=\"columns()\"\r\n [lazy]=\"lazy()\"\r\n [lazyLoadOnInit]=\"false\"\r\n (onLazyLoad)=\"load($event)\"\r\n [paginator]=\"paginator()\"\r\n [rowsPerPageOptions]=\"rowsPerPageOptions()\"\r\n [rows]=\"rowsPerPage()\"\r\n [totalRecords]=\"totalRecords()\"\r\n [loading]=\"isLoading()\"\r\n sortMode=\"multiple\"\r\n [multiSortMeta]=\"multiSortMeta()\"\r\n [class]=\"styleClass()\"\r\n [tableStyle]=\"tableStyle()\"\r\n [scrollable]=\"scrollable()\"\r\n [scrollHeight]=\"scrollHeight()\"\r\n [selectionMode]=\"selectionMode()\"\r\n [rowHover]=\"rowHover()\"\r\n [(selection)]=\"selectedRows\"\r\n [filters]=\"$any(filters())\"\r\n [first]=\"rowsBeforeCurrentPage()\"\r\n (onSort)=\"onSort($event)\"\r\n >\r\n\r\n <ng-template pTemplate=\"header\" let-columns>\r\n <tr>\r\n @for (col of columns; track col.name) {\r\n <th [pSortableColumn]=\"col.name\">\r\n <div class=\"p-d-flex p-jc-between p-ai-center gap-1\">\r\n {{col.prompt}}\r\n @if(!col.readOnly) {\r\n <p-sortIcon [field]=\"col.name\"></p-sortIcon>\r\n @if (lazy()) {\r\n <p-columnFilter #f\r\n [type]=\"toColumnFilterType(col.type)\"\r\n [maxFractionDigits]=\"toMaxFractionDigits(col)\"\r\n matchMode=\"noFilter\"\r\n [matchModeOptions]=\"toMatchModeOptions(col)\"\r\n [showMatchModes]=\"true\"\r\n [field]=\"col.name\"\r\n display=\"menu\"\r\n [maxConstraints]=\"100\"\r\n [class.has-filter]=\"f.hasFilter\">\r\n <ng-template #filter let-value let-filterConstraint=\"filterConstraint\" let-field=\"field\">\r\n <rw-table-column-filter-element [property]=\"col\" [value]=\"value\" [apiName]=\"apiName()\" [filterConstraint]=\"filterConstraint\"></rw-table-column-filter-element>\r\n </ng-template>\r\n </p-columnFilter>\r\n }\r\n }\r\n </div>\r\n </th>\r\n }\r\n @if (showMenuColumn()) {\r\n <th>\r\n <rw-menu-button [items]=\"headerMenu()\"></rw-menu-button>\r\n </th>\r\n }\r\n </tr>\r\n </ng-template>\r\n\r\n <ng-template pTemplate=\"body\" let-entity let-columns=\"columns\" let-rowIndex=\"rowIndex\">\r\n <tr (contextmenu)=\"openContextMenu($event, entity)\" [pSelectableRow]=\"entity\" [pSelectableRowDisabled]=\"selectionMode() === null\" [className]=\"rowStyleClasses()[getAbsoluteIndex(rowIndex)]\">\r\n @for (col of columns; track col.name) {\r\n <td [className]=\"cellStyleClasses()[getAbsoluteIndex(rowIndex)][col.name]\">\r\n @let fomrArray = formArray();\r\n @if (showInputField(col) && fomrArray) {\r\n @let formControl = getFormGroupAtIndex(rowIndex);\r\n @if (formControl) {\r\n <ng-container [formGroup]=\"formControl\" >\r\n <rw-input [apiName]=\"apiName()\" [property]=\"editProperties()[col.name]!\"></rw-input>\r\n </ng-container>\r\n }\r\n }\r\n @else {\r\n <rw-display [property]=\"col\" [value]=\"entity[col.name]\" [apiName]=\"apiName()!\"></rw-display>\r\n }\r\n </td>\r\n }\r\n @if (showMenuColumn()) {\r\n <td>\r\n @if (showRowMenuAsColumn()) {\r\n <rw-menu-button [items]=\"rowMenus()[getAbsoluteIndex(rowIndex)]\"></rw-menu-button>\r\n }\r\n </td>\r\n }\r\n </tr>\r\n </ng-template>\r\n</p-table>\r\n\r\n<p-contextMenu #contextMenu appendTo=\"body\" [model]=\"contextMenuItems()\"></p-contextMenu>\r\n", styles: [".p-tooltip{max-width:fit-content}a.p-button{text-decoration:none}::ng-deep rw-table rw-label.md\\:col-2{width:100%;font-weight:600}::ng-deep rw-table .p-d-flex{display:flex}::ng-deep rw-table .p-ai-center{align-items:center}::ng-deep rw-table .has-filter filtericon{color:var(--p-datatable-header-cell-selected-color)}::ng-deep rw-table p-columnfilter .p-datatable-column-filter-button{width:unset;height:23px!important;padding-block-end:0;padding-block-start:0}\n"], dependencies: [{ kind: "ngmodule", type: TableModule }, { kind: "component", type: i6.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "styleClass", "tableStyle", "tableStyleClass", "paginator", "pageLinks", "rowsPerPageOptions", "alwaysShowPaginator", "paginatorPosition", "paginatorStyleClass", "paginatorDropdownAppendTo", "paginatorDropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showJumpToPageDropdown", "showJumpToPageInput", "showFirstLastIcon", "showPageLinks", "defaultSortOrder", "sortMode", "resetPageOnSort", "selectionMode", "selectionPageOnly", "contextMenuSelection", "contextMenuSelectionMode", "dataKey", "metaKeySelection", "rowSelectable", "rowTrackBy", "lazy", "lazyLoadOnInit", "compareSelectionBy", "csvSeparator", "exportFilename", "filters", "globalFilterFields", "filterDelay", "filterLocale", "expandedRowKeys", "editingRowKeys", "rowExpandMode", "scrollable", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "size", "showGridlines", "stripedRows", "groupRowsByOrder", "responsiveLayout", "breakpoint", "paginatorLocale", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "selectAll"], outputs: ["contextMenuSelectionChange", "selectAllChange", "selectionChange", "onRowSelect", "onRowUnselect", "onPage", "onSort", "onFilter", "onLazyLoad", "onRowExpand", "onRowCollapse", "onContextMenuSelect", "onColResize", "onColReorder", "onRowReorder", "onEditInit", "onEditComplete", "onEditCancel", "onHeaderCheckboxToggle", "sortFunction", "firstChange", "rowsChange", "onStateSave", "onStateRestore"] }, { kind: "directive", type: i2$1.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "directive", type: i6.SortableColumn, selector: "[pSortableColumn]", inputs: ["pSortableColumn", "pSortableColumnDisabled"] }, { kind: "directive", type: i6.SelectableRow, selector: "[pSelectableRow]", inputs: ["pSelectableRow", "pSelectableRowIndex", "pSelectableRowDisabled"] }, { kind: "component", type: i6.SortIcon, selector: "p-sortIcon", inputs: ["field"] }, { kind: "component", type: i6.ColumnFilter, selector: "p-columnFilter, p-column-filter, p-columnfilter", inputs: ["field", "type", "display", "showMenu", "matchMode", "operator", "showOperator", "showClearButton", "showApplyButton", "showMatchModes", "showAddButton", "hideOnClear", "placeholder", "matchModeOptions", "maxConstraints", "minFractionDigits", "maxFractionDigits", "prefix", "suffix", "locale", "localeMatcher", "currency", "currencyDisplay", "filterOn", "useGrouping", "showButtons", "ariaLabel", "filterButtonProps"], outputs: ["onShow", "onHide"] }, { kind: "component", type: RestWorldMenuButtonComponent, selector: "rw-menu-button", inputs: ["items"] }, { kind: "component", type: RestWorldInputComponent, selector: "rw-input" }, { kind: "component", type: RestWorldDisplayComponent, selector: "rw-display", inputs: ["apiName", "property", "value"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2$3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2$3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: ContextMenuModule }, { kind: "component", type: i7.ContextMenu, selector: "p-contextMenu, p-contextmenu, p-context-menu", inputs: ["model", "triggerEvent", "target", "global", "style", "styleClass", "autoZIndex", "baseZIndex", "id", "breakpoint", "ariaLabel", "ariaLabelledBy", "pressDelay", "appendTo"], outputs: ["onShow", "onHide"] }, { kind: "component", type: RestWorldTableColumnFilterElementComponent, selector: "rw-table-column-filter-element", inputs: ["filterConstraint", "property", "apiName", "value"] }], viewProviders: [{
|
|
3698
|
+
provide: ControlContainer,
|
|
3699
|
+
deps: [[Optional, FormArrayName]],
|
|
3700
|
+
useFactory: (arrayName) => arrayName,
|
|
3701
|
+
}] });
|
|
3366
3702
|
}
|
|
3367
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type:
|
|
3703
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: RestWorldTableComponent, decorators: [{
|
|
3368
3704
|
type: Component,
|
|
3369
|
-
args: [{ selector: 'rw-
|
|
3370
|
-
|
|
3705
|
+
args: [{ selector: 'rw-table', standalone: true, viewProviders: [{
|
|
3706
|
+
provide: ControlContainer,
|
|
3707
|
+
deps: [[Optional, FormArrayName]],
|
|
3708
|
+
useFactory: (arrayName) => arrayName,
|
|
3709
|
+
}], imports: [TableModule, RestWorldMenuButtonComponent, RestWorldInputComponent, RestWorldDisplayComponent, ReactiveFormsModule, ContextMenuModule, RestWorldTableColumnFilterElementComponent, RestWorldTableColumnFilterElementComponent], template: "<p-table\r\n #table\r\n [value]=\"rows()\"\r\n [columns]=\"columns()\"\r\n [lazy]=\"lazy()\"\r\n [lazyLoadOnInit]=\"false\"\r\n (onLazyLoad)=\"load($event)\"\r\n [paginator]=\"paginator()\"\r\n [rowsPerPageOptions]=\"rowsPerPageOptions()\"\r\n [rows]=\"rowsPerPage()\"\r\n [totalRecords]=\"totalRecords()\"\r\n [loading]=\"isLoading()\"\r\n sortMode=\"multiple\"\r\n [multiSortMeta]=\"multiSortMeta()\"\r\n [class]=\"styleClass()\"\r\n [tableStyle]=\"tableStyle()\"\r\n [scrollable]=\"scrollable()\"\r\n [scrollHeight]=\"scrollHeight()\"\r\n [selectionMode]=\"selectionMode()\"\r\n [rowHover]=\"rowHover()\"\r\n [(selection)]=\"selectedRows\"\r\n [filters]=\"$any(filters())\"\r\n [first]=\"rowsBeforeCurrentPage()\"\r\n (onSort)=\"onSort($event)\"\r\n >\r\n\r\n <ng-template pTemplate=\"header\" let-columns>\r\n <tr>\r\n @for (col of columns; track col.name) {\r\n <th [pSortableColumn]=\"col.name\">\r\n <div class=\"p-d-flex p-jc-between p-ai-center gap-1\">\r\n {{col.prompt}}\r\n @if(!col.readOnly) {\r\n <p-sortIcon [field]=\"col.name\"></p-sortIcon>\r\n @if (lazy()) {\r\n <p-columnFilter #f\r\n [type]=\"toColumnFilterType(col.type)\"\r\n [maxFractionDigits]=\"toMaxFractionDigits(col)\"\r\n matchMode=\"noFilter\"\r\n [matchModeOptions]=\"toMatchModeOptions(col)\"\r\n [showMatchModes]=\"true\"\r\n [field]=\"col.name\"\r\n display=\"menu\"\r\n [maxConstraints]=\"100\"\r\n [class.has-filter]=\"f.hasFilter\">\r\n <ng-template #filter let-value let-filterConstraint=\"filterConstraint\" let-field=\"field\">\r\n <rw-table-column-filter-element [property]=\"col\" [value]=\"value\" [apiName]=\"apiName()\" [filterConstraint]=\"filterConstraint\"></rw-table-column-filter-element>\r\n </ng-template>\r\n </p-columnFilter>\r\n }\r\n }\r\n </div>\r\n </th>\r\n }\r\n @if (showMenuColumn()) {\r\n <th>\r\n <rw-menu-button [items]=\"headerMenu()\"></rw-menu-button>\r\n </th>\r\n }\r\n </tr>\r\n </ng-template>\r\n\r\n <ng-template pTemplate=\"body\" let-entity let-columns=\"columns\" let-rowIndex=\"rowIndex\">\r\n <tr (contextmenu)=\"openContextMenu($event, entity)\" [pSelectableRow]=\"entity\" [pSelectableRowDisabled]=\"selectionMode() === null\" [className]=\"rowStyleClasses()[getAbsoluteIndex(rowIndex)]\">\r\n @for (col of columns; track col.name) {\r\n <td [className]=\"cellStyleClasses()[getAbsoluteIndex(rowIndex)][col.name]\">\r\n @let fomrArray = formArray();\r\n @if (showInputField(col) && fomrArray) {\r\n @let formControl = getFormGroupAtIndex(rowIndex);\r\n @if (formControl) {\r\n <ng-container [formGroup]=\"formControl\" >\r\n <rw-input [apiName]=\"apiName()\" [property]=\"editProperties()[col.name]!\"></rw-input>\r\n </ng-container>\r\n }\r\n }\r\n @else {\r\n <rw-display [property]=\"col\" [value]=\"entity[col.name]\" [apiName]=\"apiName()!\"></rw-display>\r\n }\r\n </td>\r\n }\r\n @if (showMenuColumn()) {\r\n <td>\r\n @if (showRowMenuAsColumn()) {\r\n <rw-menu-button [items]=\"rowMenus()[getAbsoluteIndex(rowIndex)]\"></rw-menu-button>\r\n }\r\n </td>\r\n }\r\n </tr>\r\n </ng-template>\r\n</p-table>\r\n\r\n<p-contextMenu #contextMenu appendTo=\"body\" [model]=\"contextMenuItems()\"></p-contextMenu>\r\n", styles: [".p-tooltip{max-width:fit-content}a.p-button{text-decoration:none}::ng-deep rw-table rw-label.md\\:col-2{width:100%;font-weight:600}::ng-deep rw-table .p-d-flex{display:flex}::ng-deep rw-table .p-ai-center{align-items:center}::ng-deep rw-table .has-filter filtericon{color:var(--p-datatable-header-cell-selected-color)}::ng-deep rw-table p-columnfilter .p-datatable-column-filter-button{width:unset;height:23px!important;padding-block-end:0;padding-block-start:0}\n"] }]
|
|
3710
|
+
}], ctorParameters: () => [{ type: i2$3.ControlContainer }, { type: i1$1.FormService }, { type: i3$3.Router }, { type: i3$3.ActivatedRoute }, { type: i4$2.PrimeNG }, { type: i2$1.FilterService }] });
|
|
3711
|
+
var ColumnFilterType;
|
|
3712
|
+
(function (ColumnFilterType) {
|
|
3713
|
+
ColumnFilterType["text"] = "text";
|
|
3714
|
+
ColumnFilterType["numeric"] = "numeric";
|
|
3715
|
+
ColumnFilterType["boolean"] = "boolean";
|
|
3716
|
+
ColumnFilterType["date"] = "date";
|
|
3717
|
+
ColumnFilterType["enum"] = "enum";
|
|
3718
|
+
})(ColumnFilterType || (ColumnFilterType = {}));
|
|
3371
3719
|
|
|
3372
3720
|
/**
|
|
3373
|
-
*
|
|
3374
|
-
*
|
|
3375
|
-
* @remarks
|
|
3376
|
-
* This component is used to navigate to a resource by its ID. It takes in the API name, the `rel` of the resource, and an optional `urlPrefix` to use for the URL that is returned from the backend. It also provides a form for entering the ID of the resource to navigate to.
|
|
3721
|
+
* A base class for all input components..
|
|
3377
3722
|
*/
|
|
3378
|
-
class
|
|
3379
|
-
_clients;
|
|
3380
|
-
_messageService;
|
|
3381
|
-
_router;
|
|
3382
|
-
_route;
|
|
3383
|
-
apiName = input.required(...(ngDevMode ? [{ debugName: "apiName" }] : []));
|
|
3384
|
-
rel = input.required(...(ngDevMode ? [{ debugName: "rel" }] : []));
|
|
3723
|
+
class RestWorldInputBaseComponent {
|
|
3385
3724
|
/**
|
|
3386
|
-
*
|
|
3387
|
-
*
|
|
3725
|
+
* The property to display.
|
|
3726
|
+
* @required
|
|
3388
3727
|
*/
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
this._router = _router;
|
|
3398
|
-
this._route = _route;
|
|
3399
|
-
}
|
|
3400
|
-
async navigateById() {
|
|
3401
|
-
const rel = this.rel();
|
|
3402
|
-
if (!rel)
|
|
3403
|
-
throw new Error('The "rel" must be set through the uri of this page for the ID navigation to work.');
|
|
3404
|
-
if (!this.idNavigationForm.valid) {
|
|
3405
|
-
this._messageService.add({ detail: 'You must enter a valid ID to naviage to.', severity: 'error' });
|
|
3406
|
-
return;
|
|
3407
|
-
}
|
|
3408
|
-
var idToNavigateTo = this.idNavigationForm.controls.id.value;
|
|
3409
|
-
var client = this._client();
|
|
3410
|
-
var response = await client.getList(rel, { $filter: `id eq ${idToNavigateTo}` });
|
|
3411
|
-
if (!response.ok || ProblemDetails.isProblemDetails(response.body) || !response.body) {
|
|
3412
|
-
this._messageService.add({ severity: 'error', summary: 'Error', detail: 'Error while loading the resources from the API.', data: response });
|
|
3413
|
-
return;
|
|
3414
|
-
}
|
|
3415
|
-
var resource = response.body?._embedded?.items?.[0];
|
|
3416
|
-
if (!resource) {
|
|
3417
|
-
this._messageService.add({ severity: 'error', summary: 'Error', detail: 'No resource found with the specified ID.' });
|
|
3418
|
-
return;
|
|
3419
|
-
}
|
|
3420
|
-
const urlPrefix = this.urlPrefix();
|
|
3421
|
-
if (urlPrefix !== undefined)
|
|
3422
|
-
await this._router.navigate([urlPrefix, resource._links.self[0].href]);
|
|
3423
|
-
else
|
|
3424
|
-
await this._router.navigate(["..", resource._links.self[0].href], { relativeTo: this._route });
|
|
3425
|
-
this.idNavigationForm.reset();
|
|
3426
|
-
}
|
|
3427
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: RestWorldIdNavigationComponent, deps: [{ token: RestWorldClientCollection }, { token: i2$1.MessageService }, { token: i3$4.Router }, { token: i3$4.ActivatedRoute }], target: i0.ɵɵFactoryTarget.Component });
|
|
3428
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.1", type: RestWorldIdNavigationComponent, isStandalone: true, selector: "rw-id-navigation", inputs: { apiName: { classPropertyName: "apiName", publicName: "apiName", isSignal: true, isRequired: true, transformFunction: null }, rel: { classPropertyName: "rel", publicName: "rel", isSignal: true, isRequired: true, transformFunction: null }, urlPrefix: { classPropertyName: "urlPrefix", publicName: "urlPrefix", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<form [formGroup]=\"idNavigationForm\" (ngSubmit)=\"navigateById()\" class=\"mr-3\">\n <div class=\"p-inputgroup\">\n <p-inputNumber formControlName=\"id\" placeholder=\"Navigate by ID\"></p-inputNumber>\n <button type=\"submit\" pButton pRipple icon=\"fa-solid fa-arrow-right\"></button>\n </div>\n</form>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: InputNumberModule }, { kind: "component", type: i1$5.InputNumber, selector: "p-inputNumber, p-inputnumber, p-input-number", inputs: ["showButtons", "format", "buttonLayout", "inputId", "styleClass", "placeholder", "tabindex", "title", "ariaLabelledBy", "ariaDescribedBy", "ariaLabel", "ariaRequired", "autocomplete", "incrementButtonClass", "decrementButtonClass", "incrementButtonIcon", "decrementButtonIcon", "readonly", "allowEmpty", "locale", "localeMatcher", "mode", "currency", "currencyDisplay", "useGrouping", "minFractionDigits", "maxFractionDigits", "prefix", "suffix", "inputStyle", "inputStyleClass", "showClear", "autofocus"], outputs: ["onInput", "onFocus", "onBlur", "onKeyDown", "onClear"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i1$3.ButtonDirective, selector: "[pButton]", inputs: ["iconPos", "loadingIcon", "loading", "severity", "raised", "rounded", "text", "outlined", "size", "plain", "fluid", "label", "icon", "buttonProps"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2$3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2$3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$3.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }] });
|
|
3728
|
+
property = model.required(...(ngDevMode ? [{ debugName: "property" }] : []));
|
|
3729
|
+
/**
|
|
3730
|
+
* Set this to true if the input should use template driven forms instead of the default reactive forms.
|
|
3731
|
+
*/
|
|
3732
|
+
useTemplateDrivenForms = input(false, ...(ngDevMode ? [{ debugName: "useTemplateDrivenForms" }] : []));
|
|
3733
|
+
model = model(...(ngDevMode ? [undefined, { debugName: "model" }] : []));
|
|
3734
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: RestWorldInputBaseComponent, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
3735
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.1", type: RestWorldInputBaseComponent, isStandalone: true, inputs: { property: { classPropertyName: "property", publicName: "property", isSignal: true, isRequired: true, transformFunction: null }, useTemplateDrivenForms: { classPropertyName: "useTemplateDrivenForms", publicName: "useTemplateDrivenForms", isSignal: true, isRequired: false, transformFunction: null }, model: { classPropertyName: "model", publicName: "model", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { property: "propertyChange", model: "modelChange" }, ngImport: i0 });
|
|
3429
3736
|
}
|
|
3430
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type:
|
|
3431
|
-
type:
|
|
3432
|
-
|
|
3433
|
-
}], ctorParameters: () => [{ type: RestWorldClientCollection }, { type: i2$1.MessageService }, { type: i3$4.Router }, { type: i3$4.ActivatedRoute }] });
|
|
3434
|
-
|
|
3737
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: RestWorldInputBaseComponent, decorators: [{
|
|
3738
|
+
type: Directive
|
|
3739
|
+
}] });
|
|
3435
3740
|
/**
|
|
3436
|
-
*
|
|
3437
|
-
* If a `MenuItem` has nested items, a button with a dropdown menu will be displayed.
|
|
3438
|
-
* @example
|
|
3439
|
-
* <rw-menu-button [items]="items"></rw-menu-button>
|
|
3741
|
+
* A base class for all input components which also feature lazy loading, like dropdowns.
|
|
3440
3742
|
*/
|
|
3441
|
-
class
|
|
3442
|
-
_router;
|
|
3743
|
+
class RestWorldInputLazyLoadBaseComponent extends RestWorldInputBaseComponent {
|
|
3443
3744
|
/**
|
|
3444
|
-
*
|
|
3745
|
+
* The name of the API to use for the property.
|
|
3746
|
+
* @required
|
|
3747
|
+
* @remarks This is the name of the API as defined in the `RestWorldClientCollection`.
|
|
3445
3748
|
*/
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
}
|
|
3466
|
-
else {
|
|
3467
|
-
this._router.navigate(item.routerLink, {
|
|
3468
|
-
queryParams: item.queryParams,
|
|
3469
|
-
fragment: item.fragment,
|
|
3470
|
-
queryParamsHandling: item.queryParamsHandling,
|
|
3471
|
-
preserveFragment: item.preserveFragment,
|
|
3472
|
-
skipLocationChange: item.skipLocationChange,
|
|
3473
|
-
replaceUrl: item.replaceUrl,
|
|
3474
|
-
});
|
|
3475
|
-
}
|
|
3476
|
-
}
|
|
3477
|
-
else if (item.command) {
|
|
3478
|
-
item.command({ item: item });
|
|
3479
|
-
}
|
|
3480
|
-
}
|
|
3481
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: RestWorldMenuButtonComponent, deps: [{ token: i3$4.Router }], target: i0.ɵɵFactoryTarget.Component });
|
|
3482
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.1", type: RestWorldMenuButtonComponent, isStandalone: true, selector: "rw-menu-button", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "@for (item of items(); track item; let i = $index) {\n @if (!item.items) {\n <p-button\n [label]=\"item.label!\"\n [icon]=\"item.icon!\"\n [disabled]=\"item.disabled!\"\n [style]=\"item.style\"\n [styleClass]=\"item.styleClass!\"\n [pTooltip]=\"item.tooltip!\"\n [tooltipPosition]=\"item.tooltipPosition!\"\n (onClick)=\"onClick($event, item)\"\n [class.ml-2]=\"i > 0\">\n </p-button>\n } \n @else {\n <p-splitButton\n [label]=\"item.label!\"\n [icon]=\"item.icon!\"\n [model]=\"item.items\"\n appendTo=\"body\"\n [disabled]=\"item.disabled!\"\n [style]=\"item.style\"\n [styleClass]=\"item.styleClass!\"\n [pTooltip]=\"item.tooltip!\"\n [tooltipPosition]=\"item.tooltipPosition!\"\n (onClick)=\"onClick($event, item)\"\n [class.ml-2]=\"i > 0\">\n </p-splitButton>\n }\n}\n", styles: [":host{display:flex;justify-content:flex-end}\n"], dependencies: [{ kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$3.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "buttonProps", "autofocus", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i3.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo"] }, { kind: "ngmodule", type: SplitButtonModule }, { kind: "component", type: i4$1.SplitButton, selector: "p-splitbutton, p-splitButton, p-split-button", inputs: ["model", "severity", "raised", "rounded", "text", "outlined", "size", "plain", "icon", "iconPos", "label", "tooltip", "tooltipOptions", "styleClass", "menuStyle", "menuStyleClass", "dropdownIcon", "appendTo", "dir", "expandAriaLabel", "showTransitionOptions", "hideTransitionOptions", "buttonProps", "menuButtonProps", "autofocus", "disabled", "tabindex", "menuButtonDisabled", "buttonDisabled"], outputs: ["onClick", "onMenuHide", "onMenuShow", "onDropdownClick"] }] });
|
|
3483
|
-
}
|
|
3484
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: RestWorldMenuButtonComponent, decorators: [{
|
|
3749
|
+
apiName = input.required(...(ngDevMode ? [{ debugName: "apiName" }] : []));
|
|
3750
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: RestWorldInputLazyLoadBaseComponent, deps: null, target: i0.ɵɵFactoryTarget.Directive });
|
|
3751
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.1", type: RestWorldInputLazyLoadBaseComponent, isStandalone: true, inputs: { apiName: { classPropertyName: "apiName", publicName: "apiName", isSignal: true, isRequired: true, transformFunction: null } }, usesInheritance: true, ngImport: i0 });
|
|
3752
|
+
}
|
|
3753
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: RestWorldInputLazyLoadBaseComponent, decorators: [{
|
|
3754
|
+
type: Directive
|
|
3755
|
+
}] });
|
|
3756
|
+
/**
|
|
3757
|
+
* A form element with a label that is automatically created from a property in a form template.
|
|
3758
|
+
* This may also be a complex object or a collection in which case multiple and nested input elements may be rendered.
|
|
3759
|
+
* If you want a form element without a label, use {@link RestWorldFormInput} `<rw-input>`.
|
|
3760
|
+
* @example
|
|
3761
|
+
* <rw-form-element [property]="property" [apiName]="apiName"></rw-form-element>
|
|
3762
|
+
*/
|
|
3763
|
+
class RestWorldFormElementComponent extends RestWorldInputLazyLoadBaseComponent {
|
|
3764
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: RestWorldFormElementComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
3765
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.1", type: RestWorldFormElementComponent, isStandalone: true, selector: "rw-form-element", usesInheritance: true, ngImport: i0, template: "<div class=\"grid field\">\r\n <rw-label [property]=\"property()\" class=\"col-12 md:col-2 flex align-items-center\"></rw-label>\r\n <rw-input [apiName]=\"apiName()\" [property]=\"property()\" class=\"col-12 md:col-10\"></rw-input>\r\n</div>\r\n", styles: [""], dependencies: [{ kind: "component", type: i0.forwardRef(() => RestWorldInputComponent), selector: "rw-input" }, { kind: "component", type: i0.forwardRef(() => RestWorldLabelComponent), selector: "rw-label", inputs: ["property"] }], viewProviders: [{ provide: ControlContainer, useExisting: FormGroupDirective }] });
|
|
3766
|
+
}
|
|
3767
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: RestWorldFormElementComponent, decorators: [{
|
|
3485
3768
|
type: Component,
|
|
3486
|
-
args: [{ selector: 'rw-
|
|
3487
|
-
}]
|
|
3488
|
-
|
|
3769
|
+
args: [{ selector: 'rw-form-element', viewProviders: [{ provide: ControlContainer, useExisting: FormGroupDirective }], imports: [forwardRef(() => RestWorldInputComponent), RestWorldLabelComponent], template: "<div class=\"grid field\">\r\n <rw-label [property]=\"property()\" class=\"col-12 md:col-2 flex align-items-center\"></rw-label>\r\n <rw-input [apiName]=\"apiName()\" [property]=\"property()\" class=\"col-12 md:col-10\"></rw-input>\r\n</div>\r\n" }]
|
|
3770
|
+
}] });
|
|
3489
3771
|
/**
|
|
3490
|
-
*
|
|
3491
|
-
* The
|
|
3492
|
-
*
|
|
3772
|
+
* A collection that is automatically created from the given property.
|
|
3773
|
+
* The collection supports drag & drop to re order the elements and can also be nested.
|
|
3774
|
+
* @remarks It is advised to use {@link RestWorldInputComponent} `<rw-input>` and control the rendered inputs with the passed in property
|
|
3775
|
+
* instead of using this component directly.
|
|
3776
|
+
* @example
|
|
3777
|
+
* <rw-input-collection [property]="property" [apiName]="apiName"></rw-input-collection>
|
|
3493
3778
|
*/
|
|
3494
|
-
class
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
|
|
3779
|
+
class RestWorldInputCollectionComponent extends RestWorldInputLazyLoadBaseComponent {
|
|
3780
|
+
_formService;
|
|
3781
|
+
_controlContainer;
|
|
3782
|
+
defaultTemplate = computed(() => this.property()._templates.default, ...(ngDevMode ? [{ debugName: "defaultTemplate" }] : []));
|
|
3783
|
+
innerFormArray = computed(() => this._controlContainer.control?.controls[this.property().name], ...(ngDevMode ? [{ debugName: "innerFormArray" }] : []));
|
|
3784
|
+
templates = computed(() => this.getCollectionEntryTemplates(this.property()), ...(ngDevMode ? [{ debugName: "templates" }] : []));
|
|
3785
|
+
rows = toSignal(merge(
|
|
3786
|
+
// Get the initial value when 'control' changes
|
|
3787
|
+
toObservable(this.innerFormArray).pipe(map((ctl) => ctl.value)),
|
|
3788
|
+
// Get the new value when 'control.value' changes
|
|
3789
|
+
toObservable(this.innerFormArray).pipe(mergeMap((ctl) => ctl.valueChanges))), { initialValue: [] });
|
|
3790
|
+
inputCollectionRef;
|
|
3791
|
+
headerMenu = computed(() => {
|
|
3792
|
+
const isReadOnly = this.property().readOnly;
|
|
3793
|
+
if (isReadOnly)
|
|
3794
|
+
return [];
|
|
3795
|
+
return [
|
|
3796
|
+
{
|
|
3797
|
+
icon: "fas fa-plus",
|
|
3798
|
+
styleClass: "p-button-outlined p-button-info",
|
|
3799
|
+
command: () => this.addNewItemToCollection()
|
|
3514
3800
|
}
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
case PrimitiveTypeEnum.Decimal:
|
|
3537
|
-
case PrimitiveTypeEnum.Double:
|
|
3538
|
-
case PrimitiveTypeEnum.Single:
|
|
3539
|
-
return Number.parseFloat(node.raw);
|
|
3540
|
-
default:
|
|
3541
|
-
switch (node.raw) {
|
|
3542
|
-
case "null":
|
|
3543
|
-
return null;
|
|
3544
|
-
default:
|
|
3545
|
-
return node.raw.startsWith("'") ? node.raw.substring(1, node.raw.length - 1) : node.raw;
|
|
3546
|
-
}
|
|
3547
|
-
}
|
|
3548
|
-
}
|
|
3549
|
-
static parseMethodCallExpression(node) {
|
|
3550
|
-
switch (node.value.method) {
|
|
3551
|
-
case 'startswith':
|
|
3552
|
-
return FilterMatchMode.STARTS_WITH;
|
|
3553
|
-
case 'contains':
|
|
3554
|
-
return FilterMatchMode.CONTAINS;
|
|
3555
|
-
case 'not contains':
|
|
3556
|
-
return FilterMatchMode.NOT_CONTAINS;
|
|
3557
|
-
case 'endswith':
|
|
3558
|
-
return FilterMatchMode.ENDS_WITH;
|
|
3559
|
-
default:
|
|
3560
|
-
throw Error(`Unknown method call ${node.value.method}`);
|
|
3561
|
-
}
|
|
3562
|
-
}
|
|
3563
|
-
/***
|
|
3564
|
-
* Parses an OData $filter query string and returns a map of property names to filter metadata.
|
|
3565
|
-
* @param node The root node of the OData $filter query string.
|
|
3566
|
-
* @param logToConsole If true, logs the type and raw value of each token to the console.
|
|
3567
|
-
* @returns A map of property names to filter metadata.
|
|
3568
|
-
*/
|
|
3569
|
-
parse(node, logToConsole) {
|
|
3570
|
-
if (logToConsole) {
|
|
3571
|
-
const visitLogAll = createTraverser(Object.fromEntries(Object.entries(TokenType)
|
|
3572
|
-
.map(([key, value]) => [key, (node) => console.log(`${node.type}: ${node.raw}`)])), true);
|
|
3573
|
-
visitLogAll(node);
|
|
3574
|
-
}
|
|
3575
|
-
const visit = createTraverser({
|
|
3576
|
-
EqualsExpression: (node) => this.CreateFilter(this.propertyName, this.value, FilterMatchMode.EQUALS),
|
|
3577
|
-
NotEqualsExpression: (node) => this.CreateFilter(this.propertyName, this.value, FilterMatchMode.NOT_EQUALS),
|
|
3578
|
-
GreaterThanExpression: (node) => this.CreateFilter(this.propertyName, this.value, FilterMatchMode.GREATER_THAN),
|
|
3579
|
-
GreaterOrEqualsExpression: (node) => this.CreateFilter(this.propertyName, this.value, FilterMatchMode.GREATER_THAN_OR_EQUAL_TO),
|
|
3580
|
-
LesserThanExpression: (node) => this.CreateFilter(this.propertyName, this.value, FilterMatchMode.LESS_THAN),
|
|
3581
|
-
LesserOrEqualsExpression: (node) => this.CreateFilter(this.propertyName, this.value, FilterMatchMode.LESS_THAN_OR_EQUAL_TO),
|
|
3582
|
-
HasExpression: (node) => this.CreateFilter(this.propertyName, [this.value], FilterMatchMode.EQUALS),
|
|
3583
|
-
ODataIdentifier: (node) => this.propertyName = node.value.name,
|
|
3584
|
-
Literal: (node) => this.value = OdataVisitor.parseLiteralValue(node),
|
|
3585
|
-
AndExpression: (node) => this.operator = "and",
|
|
3586
|
-
OrExpression: (node) => this.operator = "or",
|
|
3587
|
-
BoolParenExpression: (node) => this.SetOperatorForFilters(),
|
|
3588
|
-
MethodCallExpression: (node) => this.visitMethodCallExpression(node, visit),
|
|
3589
|
-
}, true);
|
|
3590
|
-
visit(node);
|
|
3591
|
-
return this._filters;
|
|
3801
|
+
];
|
|
3802
|
+
}, ...(ngDevMode ? [{ debugName: "headerMenu" }] : []));
|
|
3803
|
+
rowMenu = computed(() => (row, openedByRightClick) => {
|
|
3804
|
+
const isReadOnly = this.property().readOnly;
|
|
3805
|
+
if (isReadOnly)
|
|
3806
|
+
return [];
|
|
3807
|
+
return [
|
|
3808
|
+
{
|
|
3809
|
+
icon: "fas fa-trash-alt",
|
|
3810
|
+
label: openedByRightClick ? "Delete" : undefined,
|
|
3811
|
+
tooltip: !openedByRightClick ? "Delete" : undefined,
|
|
3812
|
+
tooltipPosition: "left",
|
|
3813
|
+
styleClass: "p-button-outlined p-button-danger",
|
|
3814
|
+
command: () => this.deleteItemFromCollection(row)
|
|
3815
|
+
}
|
|
3816
|
+
];
|
|
3817
|
+
}, ...(ngDevMode ? [{ debugName: "rowMenu" }] : []));
|
|
3818
|
+
constructor(_formService, _controlContainer) {
|
|
3819
|
+
super();
|
|
3820
|
+
this._formService = _formService;
|
|
3821
|
+
this._controlContainer = _controlContainer;
|
|
3592
3822
|
}
|
|
3593
|
-
|
|
3594
|
-
if (
|
|
3595
|
-
|
|
3596
|
-
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
this._filters.set(propertyName, [{ value, operator: "and", matchMode: matchMode }]);
|
|
3600
|
-
}
|
|
3601
|
-
else if (filter.length === 1 && Array.isArray(filter[0].value) && Array.isArray(value)) {
|
|
3602
|
-
filter[0].value.push(...value); // Flags enum
|
|
3603
|
-
}
|
|
3604
|
-
else {
|
|
3605
|
-
filter.push({ value, operator: "and", matchMode: matchMode });
|
|
3606
|
-
}
|
|
3823
|
+
getCollectionEntryTemplates(property) {
|
|
3824
|
+
if (!property)
|
|
3825
|
+
return [];
|
|
3826
|
+
return Object.entries(property._templates)
|
|
3827
|
+
.filter(([key, value]) => Number.isInteger(Number.parseInt(key)) && Number.isInteger(Number.parseInt(value?.title ?? "")))
|
|
3828
|
+
.map(([, value]) => new NumberTemplate(value));
|
|
3607
3829
|
}
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
const
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
f.operator = this.operator;
|
|
3830
|
+
addNewItemToCollection() {
|
|
3831
|
+
const templates = this.templates();
|
|
3832
|
+
const defaultTemplate = this.defaultTemplate();
|
|
3833
|
+
const maxIndex = Math.max(...Object.keys(templates)
|
|
3834
|
+
.map(key => Number.parseInt(key))
|
|
3835
|
+
.filter(key => Number.isSafeInteger(key)));
|
|
3836
|
+
const nextIndex = maxIndex < 0 ? 0 : maxIndex + 1;
|
|
3837
|
+
const copiedTemplateDto = JSON.parse(JSON.stringify(defaultTemplate));
|
|
3838
|
+
copiedTemplateDto.title = nextIndex.toString();
|
|
3839
|
+
const copiedTemplate = new Template(copiedTemplateDto);
|
|
3840
|
+
this.innerFormArray().push(this._formService.createFormGroupFromTemplate(this.defaultTemplate()));
|
|
3841
|
+
this.property.update((property) => { property._templates[nextIndex] = copiedTemplate; return { ...property }; });
|
|
3621
3842
|
}
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
visit(parameter);
|
|
3626
|
-
const matchMode = OdataVisitor.parseMethodCallExpression(node);
|
|
3627
|
-
this.CreateFilter(this.propertyName, this.value, matchMode);
|
|
3843
|
+
deleteItemFromCollection(row) {
|
|
3844
|
+
const index = this.rows().indexOf(row);
|
|
3845
|
+
this.innerFormArray().removeAt(index);
|
|
3628
3846
|
}
|
|
3847
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: RestWorldInputCollectionComponent, deps: [{ token: i1$1.FormService }, { token: i2$3.ControlContainer }], target: i0.ɵɵFactoryTarget.Component });
|
|
3848
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.1", type: RestWorldInputCollectionComponent, isStandalone: true, selector: "rw-input-collection", queries: [{ propertyName: "inputCollectionRef", first: true, predicate: ["inputCollection"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<rw-table\n [apiName]=\"apiName()\"\n [editTemplate]=\"defaultTemplate()\"\n [formArrayName]=\"property().name\"\n [lazy]=\"false\"\n [rows]=\"rows()\"\n [searchTemplate]=\"defaultTemplate()\"\n [headerMenu]=\"headerMenu()\"\n [rowMenu]=\"rowMenu()\"\n\n >\n</rw-table>\n", styles: [".cdk-drag-handle{cursor:move}.cdk-drag-preview{background-color:#ffffffd0;border:2px dashed rgb(206,212,218);cursor:move}.cdk-drag-placeholder{border:2px dashed rgb(206,212,218);margin:-2px}.brace{align-self:stretch;margin:.2rem .5rem;border-left:1px solid rgb(206,212,218);border-top:1px solid rgb(206,212,218);border-bottom:1px solid rgb(206,212,218);width:1rem}\n"], dependencies: [{ kind: "ngmodule", type: i0.forwardRef(() => DragDropModule) }, { kind: "ngmodule", type: i0.forwardRef(() => ReactiveFormsModule) }, { kind: "directive", type: i0.forwardRef(() => i2$3.NgControlStatusGroup), selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i0.forwardRef(() => i2$3.FormArrayName), selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "component", type: i0.forwardRef(() => RestWorldTableComponent), selector: "rw-table", inputs: ["apiName", "cellStyleClass", "editTemplate", "headerMenu", "isLoading", "lazy", "paginator", "oDataParameters", "reflectParametersInUrl", "rowHover", "rowMenu", "rowStyleClass", "rows", "rowsPerPageOptions", "scrollHeight", "scrollable", "searchTemplate", "selectedRows", "selectionMode", "showRowMenuAsColumn", "showRowMenuOnRightClick", "styleClass", "tableStyle", "totalRecords", "urlParameterPrefix"], outputs: ["oDataParametersChange", "selectedRowsChange"] }], viewProviders: [{ provide: ControlContainer, useExisting: FormGroupDirective }] });
|
|
3629
3849
|
}
|
|
3630
|
-
|
|
3850
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: RestWorldInputCollectionComponent, decorators: [{
|
|
3851
|
+
type: Component,
|
|
3852
|
+
args: [{ selector: 'rw-input-collection', viewProviders: [{ provide: ControlContainer, useExisting: FormGroupDirective }], imports: [forwardRef(() => RestWorldInputTemplateComponent), DragDropModule, ReactiveFormsModule, RestWorldTableComponent], template: "<rw-table\n [apiName]=\"apiName()\"\n [editTemplate]=\"defaultTemplate()\"\n [formArrayName]=\"property().name\"\n [lazy]=\"false\"\n [rows]=\"rows()\"\n [searchTemplate]=\"defaultTemplate()\"\n [headerMenu]=\"headerMenu()\"\n [rowMenu]=\"rowMenu()\"\n\n >\n</rw-table>\n", styles: [".cdk-drag-handle{cursor:move}.cdk-drag-preview{background-color:#ffffffd0;border:2px dashed rgb(206,212,218);cursor:move}.cdk-drag-placeholder{border:2px dashed rgb(206,212,218);margin:-2px}.brace{align-self:stretch;margin:.2rem .5rem;border-left:1px solid rgb(206,212,218);border-top:1px solid rgb(206,212,218);border-bottom:1px solid rgb(206,212,218);width:1rem}\n"] }]
|
|
3853
|
+
}], ctorParameters: () => [{ type: i1$1.FormService }, { type: i2$3.ControlContainer }], propDecorators: { inputCollectionRef: [{
|
|
3854
|
+
type: ContentChild,
|
|
3855
|
+
args: ['inputCollection', { static: false }]
|
|
3856
|
+
}] } });
|
|
3631
3857
|
/**
|
|
3632
|
-
*
|
|
3858
|
+
* A form input element that is automatically created from a property in a form template.
|
|
3859
|
+
* This may also be a complex object or a collection in which case multiple and nested input elements may be rendered.
|
|
3860
|
+
* If you also want a label, use {@link RestWorldFormElement} `<rw-form-element>`.
|
|
3861
|
+
* You can also use one of the different RestWorldInput... `<rw-input-...>` elements to render a specific input,
|
|
3862
|
+
* but it is advised to control the rendered input through the passed in property.
|
|
3863
|
+
* @example
|
|
3864
|
+
* <rw-input [property]="property" [apiName]="apiName"></rw-input>
|
|
3633
3865
|
*/
|
|
3634
|
-
class
|
|
3635
|
-
|
|
3636
|
-
|
|
3637
|
-
return {};
|
|
3638
|
-
// The parser has a bug where it does not correctly parse cast expressions, so we need to replace them with the first argument
|
|
3639
|
-
// See https://github.com/Soontao/odata-v4-parser/issues/283
|
|
3640
|
-
filter = ODataFilterParser.replaceCastExpressions(filter);
|
|
3641
|
-
const ast = defaultParser.filter(filter);
|
|
3642
|
-
const visitor = new OdataVisitor();
|
|
3643
|
-
const filters = visitor.parse(ast);
|
|
3644
|
-
/// OData needs enum values in pascal case, but JSON and therefor HAL-Forms needs them in camel case
|
|
3645
|
-
ODataFilterParser.MakeEnumValuesCamelCase(filters, properties);
|
|
3646
|
-
return Object.fromEntries(filters);
|
|
3866
|
+
class RestWorldInputComponent extends RestWorldInputLazyLoadBaseComponent {
|
|
3867
|
+
get PropertyType() {
|
|
3868
|
+
return PropertyType;
|
|
3647
3869
|
}
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
for (const filter of value) {
|
|
3651
|
-
const options = properties[key]?.options;
|
|
3652
|
-
if (options && !options.link && typeof filter.value === "string") {
|
|
3653
|
-
filter.value = filter.value.charAt(0).toLowerCase() + filter.value.slice(1);
|
|
3654
|
-
}
|
|
3655
|
-
}
|
|
3656
|
-
}
|
|
3657
|
-
}
|
|
3658
|
-
static replaceCastExpressions(input) {
|
|
3659
|
-
// Regular expression to match cast(x, y) and extract x
|
|
3660
|
-
const regex = /cast\(([^,]+),\s*[^)]+\)/g;
|
|
3661
|
-
// Replace matches with the first captured group (x)
|
|
3662
|
-
const result = input.replace(regex, (match, x) => x.trim());
|
|
3663
|
-
return result;
|
|
3870
|
+
get PropertyWithOptions() {
|
|
3871
|
+
return PropertyWithOptions;
|
|
3664
3872
|
}
|
|
3873
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: RestWorldInputComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
3874
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.1", type: RestWorldInputComponent, isStandalone: true, selector: "rw-input", usesInheritance: true, ngImport: i0, template: "@if (property()) {\r\n @if (property().options) {\r\n <rw-input-dropdown [apiName]=\"apiName()\" [property]=\"$any(property())\" [useTemplateDrivenForms]=\"useTemplateDrivenForms()\"></rw-input-dropdown>\r\n }\r\n @else {\r\n @switch (property().type) {\r\n @case (PropertyType.Object) {\r\n <rw-input-object [apiName]=\"apiName()\" [property]=\"$any(property())\" [useTemplateDrivenForms]=\"useTemplateDrivenForms()\"></rw-input-object>\r\n }\r\n @case (PropertyType.Collection) {\r\n <rw-input-collection [apiName]=\"apiName()\" [property]=\"$any(property())\" [useTemplateDrivenForms]=\"useTemplateDrivenForms()\"></rw-input-collection>\r\n }\r\n @default {\r\n <rw-input-simple [property]=\"property()\" [useTemplateDrivenForms]=\"useTemplateDrivenForms()\"></rw-input-simple>\r\n }\r\n }\r\n }\r\n\r\n <rw-validation-errors [property]=\"property()\"></rw-validation-errors>\r\n}\r\n", styles: [""], dependencies: [{ kind: "component", type: i0.forwardRef(() => RestWorldInputDropdownComponent), selector: "rw-input-dropdown", inputs: ["caseSensitive", "getLabel", "getTooltip"], outputs: ["onChange"] }, { kind: "component", type: i0.forwardRef(() => RestWorldInputObjectComponent), selector: "rw-input-object" }, { kind: "component", type: i0.forwardRef(() => RestWorldInputSimpleComponent), selector: "rw-input-simple" }, { kind: "component", type: i0.forwardRef(() => RestWorldInputCollectionComponent), selector: "rw-input-collection" }, { kind: "component", type: i0.forwardRef(() => RestWorldValidationErrorsComponent), selector: "rw-validation-errors", inputs: ["form", "property"] }, { kind: "ngmodule", type: i0.forwardRef(() => FormsModule) }], viewProviders: [{ provide: ControlContainer, useExisting: FormGroupDirective }] });
|
|
3665
3875
|
}
|
|
3666
|
-
|
|
3876
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: RestWorldInputComponent, decorators: [{
|
|
3877
|
+
type: Component,
|
|
3878
|
+
args: [{ selector: 'rw-input', standalone: true, viewProviders: [{ provide: ControlContainer, useExisting: FormGroupDirective }], imports: [forwardRef(() => RestWorldInputDropdownComponent), forwardRef(() => RestWorldInputObjectComponent), forwardRef(() => RestWorldInputSimpleComponent), RestWorldInputCollectionComponent, RestWorldValidationErrorsComponent, FormsModule], template: "@if (property()) {\r\n @if (property().options) {\r\n <rw-input-dropdown [apiName]=\"apiName()\" [property]=\"$any(property())\" [useTemplateDrivenForms]=\"useTemplateDrivenForms()\"></rw-input-dropdown>\r\n }\r\n @else {\r\n @switch (property().type) {\r\n @case (PropertyType.Object) {\r\n <rw-input-object [apiName]=\"apiName()\" [property]=\"$any(property())\" [useTemplateDrivenForms]=\"useTemplateDrivenForms()\"></rw-input-object>\r\n }\r\n @case (PropertyType.Collection) {\r\n <rw-input-collection [apiName]=\"apiName()\" [property]=\"$any(property())\" [useTemplateDrivenForms]=\"useTemplateDrivenForms()\"></rw-input-collection>\r\n }\r\n @default {\r\n <rw-input-simple [property]=\"property()\" [useTemplateDrivenForms]=\"useTemplateDrivenForms()\"></rw-input-simple>\r\n }\r\n }\r\n }\r\n\r\n <rw-validation-errors [property]=\"property()\"></rw-validation-errors>\r\n}\r\n" }]
|
|
3879
|
+
}] });
|
|
3667
3880
|
/**
|
|
3668
|
-
* A
|
|
3881
|
+
* A dropdown that is automatically created from the given property.
|
|
3882
|
+
* The dropdown supports searching through a RESTWorld list endpoint on the backend if the `link` of the options is set.
|
|
3883
|
+
* Otherwise the dropdown will use the `inline` of the options.
|
|
3884
|
+
* @remarks It is advised to use {@link RestWorldInputComponent} `<rw-input>` and control the rendered inputs with the passed in property
|
|
3885
|
+
* instead of using this component directly.
|
|
3886
|
+
* @example
|
|
3887
|
+
* <rw-input-dropdown [property]="property" [apiName]="apiName"></rw-input-dropdown>
|
|
3669
3888
|
*/
|
|
3670
|
-
class
|
|
3889
|
+
class RestWorldInputDropdownComponent extends RestWorldInputLazyLoadBaseComponent {
|
|
3890
|
+
_controlContainer;
|
|
3671
3891
|
/**
|
|
3672
|
-
*
|
|
3673
|
-
*
|
|
3674
|
-
* @param filter - The filter metadata to use.
|
|
3675
|
-
* @returns The OData filter string, or undefined if the filter value is falsy.
|
|
3892
|
+
* A flag that indicates if the search should be case sensitive.
|
|
3893
|
+
* The default is false.
|
|
3676
3894
|
*/
|
|
3677
|
-
|
|
3678
|
-
if (filter.matchMode == TranslationKeys.NO_FILTER)
|
|
3679
|
-
return undefined;
|
|
3680
|
-
// Enums are handled differently
|
|
3681
|
-
if (property.options && !property.options.link)
|
|
3682
|
-
return ODataService.createFilterForEnum(property, filter);
|
|
3683
|
-
const oDataOperator = ODataService.createODataOperator(filter.matchMode);
|
|
3684
|
-
const comparisonValue = ODataService.createComparisonValue(property, filter.value);
|
|
3685
|
-
switch (oDataOperator) {
|
|
3686
|
-
case 'contains':
|
|
3687
|
-
case 'not contains':
|
|
3688
|
-
case 'startswith':
|
|
3689
|
-
case 'endswith':
|
|
3690
|
-
return `${oDataOperator}(${property.name}, ${comparisonValue})`;
|
|
3691
|
-
default:
|
|
3692
|
-
return `${property.name} ${oDataOperator} ${comparisonValue}`;
|
|
3693
|
-
}
|
|
3694
|
-
}
|
|
3895
|
+
caseSensitive = input(false, ...(ngDevMode ? [{ debugName: "caseSensitive" }] : []));
|
|
3695
3896
|
/**
|
|
3696
|
-
*
|
|
3697
|
-
*
|
|
3698
|
-
*
|
|
3699
|
-
*
|
|
3897
|
+
* A function that returns the label for the given item.
|
|
3898
|
+
* The default returns the prompt and optionally the value in brackets.
|
|
3899
|
+
* The value in brackets will only be displayed if the `cols` field of the property is undefined or greater than 1.
|
|
3900
|
+
* Overwrite this function to change the label.
|
|
3901
|
+
* @param item The item to get the label for.
|
|
3700
3902
|
*/
|
|
3701
|
-
|
|
3702
|
-
const filter = filters
|
|
3703
|
-
.map(f => ODataService.createFilterForProperty(property, f))
|
|
3704
|
-
.filter(f => !!f)
|
|
3705
|
-
.join(` ${filters[0].operator} `);
|
|
3706
|
-
if (filter === '')
|
|
3707
|
-
return undefined;
|
|
3708
|
-
return `(${filter})`;
|
|
3709
|
-
}
|
|
3903
|
+
getLabel = input(...(ngDevMode ? [undefined, { debugName: "getLabel" }] : []));
|
|
3710
3904
|
/**
|
|
3711
|
-
*
|
|
3712
|
-
*
|
|
3713
|
-
*
|
|
3714
|
-
*
|
|
3905
|
+
* A function that returns the tooltip for the given item.
|
|
3906
|
+
* The default returns all properties of the item except the ones that start with an underscore or the ones that are in the list of default properties to exclude.
|
|
3907
|
+
* The default properties to exclude are: createdAt, createdBy, lastChangedAt, lastChangedBy, timestamp, promptField, valueField.
|
|
3908
|
+
* Overwrite this function to change the tooltip.
|
|
3909
|
+
* @param item The item to get the label for.
|
|
3715
3910
|
*/
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
const filter = properties
|
|
3721
|
-
.map(property => ({ property, filters: eventFilters[property.name] }))
|
|
3722
|
-
.filter(f => f.filters !== undefined)
|
|
3723
|
-
.map(f => ODataService.createFilterForPropertyArray(f.property, f.filters))
|
|
3724
|
-
.filter(f => !!f)
|
|
3725
|
-
.join(' and ');
|
|
3726
|
-
if (filter === '')
|
|
3727
|
-
return undefined;
|
|
3728
|
-
return `(${filter})`;
|
|
3729
|
-
}
|
|
3911
|
+
getTooltip = input(...(ngDevMode ? [undefined, { debugName: "getTooltip" }] : []));
|
|
3912
|
+
inputOptionsMultipleRef = contentChild("inputOptionsMultiple", ...(ngDevMode ? [{ debugName: "inputOptionsMultipleRef" }] : []));
|
|
3913
|
+
inputOptionsSingleRef = contentChild("inputOptionsSingle", ...(ngDevMode ? [{ debugName: "inputOptionsSingleRef" }] : []));
|
|
3914
|
+
multiSelect = viewChild(MultiSelect, ...(ngDevMode ? [{ debugName: "multiSelect" }] : []));
|
|
3730
3915
|
/**
|
|
3731
|
-
*
|
|
3732
|
-
* @param filter The OData filter string to parse.
|
|
3733
|
-
* @returns A record of property names to filter metadata.
|
|
3916
|
+
* An event that is emitted when the selected value changes.
|
|
3734
3917
|
*/
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3918
|
+
onChange = output();
|
|
3919
|
+
onOptionsFiltered = debounce(this.onOptionsFilteredInternal, 500);
|
|
3920
|
+
optionsManager;
|
|
3921
|
+
_formControl = computed(() => {
|
|
3922
|
+
const formGroup = this._controlContainer.control;
|
|
3923
|
+
return formGroup.controls[this.property().name];
|
|
3924
|
+
}, ...(ngDevMode ? [{ debugName: "_formControl" }] : []));
|
|
3925
|
+
_value = toSignal(toObservable(this._formControl).pipe(distinctUntilChanged(), switchMap(formControl => formControl
|
|
3926
|
+
? formControl.valueChanges.pipe(debounceTime(0), distinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b))).pipe(startWith(formControl.value))
|
|
3927
|
+
: EMPTY)));
|
|
3928
|
+
constructor(_controlContainer, optionsService) {
|
|
3929
|
+
super();
|
|
3930
|
+
this._controlContainer = _controlContainer;
|
|
3931
|
+
this.optionsManager = optionsService.getManager(this.apiName, this.property, this._value, this.getLabel, this.getTooltip);
|
|
3738
3932
|
}
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
* @param event The {@link TableLazyLoadEvent} to create the `$orderby` value from.
|
|
3742
|
-
* @returns The `$orderby` value created from the {@link TableLazyLoadEvent}.
|
|
3743
|
-
*/
|
|
3744
|
-
static createOrderByFromTableLoadEvent(event) {
|
|
3745
|
-
if (event.multiSortMeta && event.multiSortMeta.length > 0) {
|
|
3746
|
-
return event.multiSortMeta
|
|
3747
|
-
.map(m => `${m.field} ${m.order > 0 ? 'asc' : 'desc'}`)
|
|
3748
|
-
.join(', ');
|
|
3749
|
-
}
|
|
3750
|
-
if (event.sortField) {
|
|
3751
|
-
const order = !event.sortOrder || event.sortOrder > 0 ? 'asc' : 'desc';
|
|
3752
|
-
return `${event.sortField} ${order}`;
|
|
3753
|
-
}
|
|
3754
|
-
return undefined;
|
|
3933
|
+
onOptionsChanged(event) {
|
|
3934
|
+
this.onChange.emit(event);
|
|
3755
3935
|
}
|
|
3756
|
-
|
|
3757
|
-
|
|
3758
|
-
|
|
3759
|
-
|
|
3760
|
-
|
|
3761
|
-
|
|
3762
|
-
|
|
3763
|
-
|
|
3764
|
-
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
|
|
3768
|
-
|
|
3769
|
-
|
|
3770
|
-
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
3778
|
-
|
|
3779
|
-
|
|
3780
|
-
|
|
3781
|
-
|
|
3936
|
+
async onOptionsFilteredInternal(event) {
|
|
3937
|
+
const options = this.optionsManager.options();
|
|
3938
|
+
const currentItems = this.optionsManager.items.value();
|
|
3939
|
+
if (!(event.filter) || event.filter === '')
|
|
3940
|
+
return;
|
|
3941
|
+
if (event.originalEvent.type === "input") {
|
|
3942
|
+
const inputEvent = event.originalEvent;
|
|
3943
|
+
if (inputEvent.inputType === "insertFromPaste") {
|
|
3944
|
+
// If the user pasted in multiple ids as comma separated list, we want to get them all and set them as the selected value.
|
|
3945
|
+
var values = event.filter
|
|
3946
|
+
.split(",")
|
|
3947
|
+
.filter(v => v !== '')
|
|
3948
|
+
.map(v => v.trim())
|
|
3949
|
+
.map(v => {
|
|
3950
|
+
const n = Number.parseFloat(v);
|
|
3951
|
+
return Number.isNaN(n) ? this.makeUpperIfCaseInsensitive(v.toUpperCase(), false) : n;
|
|
3952
|
+
});
|
|
3953
|
+
if (!values || values.length === 0)
|
|
3954
|
+
return;
|
|
3955
|
+
const allAreNumbers = values.every(v => typeof v === "number" && !isNaN(v));
|
|
3956
|
+
const filter = allAreNumbers
|
|
3957
|
+
? `${options.valueField} in (${values.join(',')})`
|
|
3958
|
+
: `contains(${this.makeUpperIfCaseInsensitive(options.promptField, true)}, '${values.join("', '")}')`;
|
|
3959
|
+
if ((options?.link?.href))
|
|
3960
|
+
await this.optionsManager.updateItemsFromFilter(filter);
|
|
3961
|
+
if (currentItems) {
|
|
3962
|
+
const selectedValues = currentItems
|
|
3963
|
+
.map(i => this.optionsManager.getValue(i))
|
|
3964
|
+
.filter(v => values.includes(v));
|
|
3965
|
+
this._formControl().setValue(selectedValues);
|
|
3966
|
+
this.multiSelect()?.resetFilter();
|
|
3967
|
+
}
|
|
3968
|
+
}
|
|
3969
|
+
else {
|
|
3970
|
+
// This is the normal case where the user types in a filter.
|
|
3971
|
+
let filter = `contains(${this.makeUpperIfCaseInsensitive(options.promptField, true)}, '${this.makeUpperIfCaseInsensitive(event.filter, false)}')`;
|
|
3972
|
+
if (options.valueField?.toLowerCase() === 'id' && !Number.isNaN(Number.parseInt(event.filter)))
|
|
3973
|
+
filter = `(${options.valueField} eq ${event.filter}) or (${filter})`;
|
|
3974
|
+
if ((options?.link?.href))
|
|
3975
|
+
await this.optionsManager.updateItemsFromFilter(filter);
|
|
3976
|
+
}
|
|
3782
3977
|
}
|
|
3783
|
-
return oDataParameters;
|
|
3784
3978
|
}
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
|
|
3791
|
-
static createParametersFromTableLoadEvent(event, template) {
|
|
3792
|
-
const oDataParameters = {
|
|
3793
|
-
$filter: ODataService.createFilterFromTableLoadEvent(event, template?.properties),
|
|
3794
|
-
$orderby: ODataService.createOrderByFromTableLoadEvent(event),
|
|
3795
|
-
$top: ODataService.createTopFromTableLoadEvent(event),
|
|
3796
|
-
$skip: ODataService.createSkipFromTableLoadEvent(event)
|
|
3797
|
-
};
|
|
3798
|
-
return oDataParameters;
|
|
3979
|
+
makeUpperIfCaseInsensitive(filter, isOData) {
|
|
3980
|
+
if (this.caseSensitive() || typeof filter !== "string")
|
|
3981
|
+
return filter;
|
|
3982
|
+
if (isOData)
|
|
3983
|
+
return `toupper(${filter})`;
|
|
3984
|
+
return filter.toUpperCase();
|
|
3799
3985
|
}
|
|
3800
|
-
|
|
3801
|
-
* Creates a OData `$skip` value from a {@link TableLazyLoadEvent}.
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
3986
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: RestWorldInputDropdownComponent, deps: [{ token: i2$3.ControlContainer }, { token: OptionsService }], target: i0.ɵɵFactoryTarget.Component });
|
|
3987
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.1", type: RestWorldInputDropdownComponent, isStandalone: true, selector: "rw-input-dropdown", inputs: { caseSensitive: { classPropertyName: "caseSensitive", publicName: "caseSensitive", isSignal: true, isRequired: false, transformFunction: null }, getLabel: { classPropertyName: "getLabel", publicName: "getLabel", isSignal: true, isRequired: false, transformFunction: null }, getTooltip: { classPropertyName: "getTooltip", publicName: "getTooltip", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onChange: "onChange" }, queries: [{ propertyName: "inputOptionsMultipleRef", first: true, predicate: ["inputOptionsMultiple"], descendants: true, isSignal: true }, { propertyName: "inputOptionsSingleRef", first: true, predicate: ["inputOptionsSingle"], descendants: true, isSignal: true }], viewQueries: [{ propertyName: "multiSelect", first: true, predicate: MultiSelect, descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<ng-template #defaultInputOptionsSingle let-property=\"property\" let-template=\"template\" let-items=\"items\" let-useTemplateDrivenForms=\"useTemplateDrivenForms\">\n @if (useTemplateDrivenForms()) {\n <p-select\n [propertyAttributes]=\"property()\"\n [(ngModel)]=\"model\"\n [options]=\"optionsManager.items.value()\"\n (onFilter)=\"onOptionsFiltered($event)\"\n (onChange)=\"onOptionsChanged($event)\"\n styleClass=\"w-full\"\n [panelStyleClass]=\"optionsManager.loading() ? 'loading' : ''\"\n [emptyFilterMessage]=\"optionsManager.loading() ? 'Loading...' : ''\"\n [loading]=\"optionsManager.loading()\"\n >\n <ng-template #selectedItem let-selectedItem>\n <span [pTooltip]=\"optionsManager.getTooltip()(selectedItem)\">{{optionsManager.getLabel()(selectedItem)}}</span>\n </ng-template>\n <ng-template #item let-item>\n <span [pTooltip]=\"optionsManager.getTooltip()(item)\">{{optionsManager.getLabel()(item)}}</span>\n </ng-template>\n </p-select>\n }\n @else {\n <p-select\n [formControlProperty]=\"property()\"\n [options]=\"optionsManager.items.value()\"\n (onFilter)=\"onOptionsFiltered($event)\"\n (onChange)=\"onOptionsChanged($event)\"\n styleClass=\"w-full\"\n [panelStyleClass]=\"optionsManager.loading() ? 'loading' : ''\"\n [emptyFilterMessage]=\"optionsManager.loading() ? 'Loading...' : ''\"\n [loading]=\"optionsManager.loading()\"\n >\n <ng-template #selectedItem let-selectedItem>\n <span [pTooltip]=\"optionsManager.getTooltip()(selectedItem)\">{{optionsManager.getLabel()(selectedItem)}}</span>\n </ng-template>\n <ng-template #item let-item>\n <span [pTooltip]=\"optionsManager.getTooltip()(item)\">{{optionsManager.getLabel()(item)}}</span>\n </ng-template>\n </p-select>\n }\n</ng-template>\n\n<ng-template #defaultInputOptionsMultiple let-property=\"property\" let-template=\"template\" let-items=\"items\" let-useTemplateDrivenForms=\"useTemplateDrivenForms\">\n @if (useTemplateDrivenForms()) {\n <p-multiSelect\n [propertyAttributes]=\"property()\"\n [(ngModel)]=\"model\"\n [options]=\"optionsManager.items.value()\"\n (onFilter)=\"onOptionsFiltered($event)\"\n (onChange)=\"onOptionsChanged($event)\"\n styleClass=\"w-full\"\n [panelStyleClass]=\"optionsManager.loading() ? 'loading' : ''\"\n [emptyFilterMessage]=\"optionsManager.loading() ? 'Loading...' : ''\"\n [loading]=\"optionsManager.loading()\"\n >\n <ng-template #selecteditems let-items let-removeChip=\"removeChip\">\n @for (item of items; track item; let i = $index) {\n <p-chip\n [pTooltip]=\"optionsManager.getTooltip()(item)\"\n [label]=\"optionsManager.getLabel()(item)\"\n [removable]=\"true\"\n (onRemove)=\"removeChip(optionsManager.getValue(item), $event)\"\n >\n </p-chip>\n }\n </ng-template>\n <ng-template #item let-item>\n <span [pTooltip]=\"optionsManager.getTooltip()(item)\">{{optionsManager.getLabel()(item)}}</span>\n </ng-template>\n </p-multiSelect>\n }\n @else {\n <p-multiSelect\n [formControlProperty]=\"property()\"\n [options]=\"optionsManager.items.value()\"\n (onFilter)=\"onOptionsFiltered($event)\"\n (onChange)=\"onOptionsChanged($event)\"\n styleClass=\"w-full\"\n [panelStyleClass]=\"optionsManager.loading() ? 'loading' : ''\"\n [emptyFilterMessage]=\"optionsManager.loading() ? 'Loading...' : ''\"\n [loading]=\"optionsManager.loading()\"\n >\n <ng-template #selecteditems let-items let-removeChip=\"removeChip\">\n @for (item of items; track item; let i = $index) {\n <p-chip\n [pTooltip]=\"optionsManager.getTooltip()(item)\"\n [label]=\"optionsManager.getLabel()(item)\"\n [removable]=\"true\"\n (onRemove)=\"removeChip(optionsManager.getValue(item), $event)\"\n >\n </p-chip>\n }\n </ng-template>\n <ng-template #item let-item>\n <span [pTooltip]=\"optionsManager.getTooltip()(item)\">{{optionsManager.getLabel()(item)}}</span>\n </ng-template>\n </p-multiSelect>\n }\n</ng-template>\n\n@if(!optionsManager.options().maxItems || optionsManager.options().maxItems == 1) {\n <ng-container *ngTemplateOutlet=\"inputOptionsSingleRef() ?? defaultInputOptionsSingle; context: { property: property, apiName: apiName, items: optionsManager.items, useTemplateDrivenForms: useTemplateDrivenForms, model: model }\"></ng-container>\n}\n@else {\n <ng-container *ngTemplateOutlet=\"inputOptionsMultipleRef() ?? defaultInputOptionsMultiple; context: { property: property, apiName: apiName, items: optionsManager.items, useTemplateDrivenForms: useTemplateDrivenForms, model: model }\"></ng-container>\n}\n", styles: ["::ng-deep .p-multiselect-label{display:inline-flex!important}::ng-deep .p-multiselect-label-empty{height:36px}::ng-deep .p-chip{background-color:#eff6ff;color:#1d4ed8}::ng-deep .pi-chip-remove-icon:hover{filter:brightness(.6)}\n"], dependencies: [{ kind: "component", type: Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "component", type: MultiSelect, selector: "p-multiSelect, p-multiselect, p-multi-select", inputs: ["id", "ariaLabel", "styleClass", "panelStyle", "panelStyleClass", "inputId", "readonly", "group", "filter", "filterPlaceHolder", "filterLocale", "overlayVisible", "tabindex", "dataKey", "ariaLabelledBy", "displaySelectedLabel", "maxSelectedLabels", "selectionLimit", "selectedItemsLabel", "showToggleAll", "emptyFilterMessage", "emptyMessage", "resetFilterOnHide", "dropdownIcon", "chipIcon", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "showHeader", "filterBy", "scrollHeight", "lazy", "virtualScroll", "loading", "virtualScrollItemSize", "loadingIcon", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "autofocusFilter", "display", "autocomplete", "showClear", "autofocus", "placeholder", "options", "filterValue", "selectAll", "focusOnHover", "filterFields", "selectOnFocus", "autoOptionFocus", "highlightOnSelect", "size", "variant", "fluid", "appendTo"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onClear", "onPanelShow", "onPanelHide", "onLazyLoad", "onRemove", "onSelectAllChange"] }, { kind: "directive", type: Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo"] }, { kind: "component", type: Chip, selector: "p-chip", inputs: ["label", "icon", "image", "alt", "styleClass", "removable", "removeIcon", "chipProps"], outputs: ["onRemove", "onImageError"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: HalFormsModule }, { kind: "directive", type: FormControlProperty, selector: "[formControlProperty]:not([useTemplateDrivenForms=true])", inputs: ["formControlProperty"] }, { kind: "directive", type: PropertyControlStatus, selector: "[formControlProperty]" }, { kind: "directive", type: PropertySelectAttributes, selector: "p-select[formControlProperty], p-select[propertyAttributes], p-multiSelect[formControlProperty], p-multiSelect[propertyAttributes]", inputs: ["formControlProperty", "propertyAttributes"] }, { kind: "directive", type: PropertyAttributes, selector: "[formControlProperty],[propertyAttributes]", inputs: ["formControlProperty", "propertyAttributes"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }], viewProviders: [{ provide: ControlContainer, useExisting: FormGroupDirective }] });
|
|
3988
|
+
}
|
|
3989
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: RestWorldInputDropdownComponent, decorators: [{
|
|
3990
|
+
type: Component,
|
|
3991
|
+
args: [{ selector: 'rw-input-dropdown', standalone: true, viewProviders: [{ provide: ControlContainer, useExisting: FormGroupDirective }], imports: [Select, ReactiveFormsModule, MultiSelect, Tooltip, Chip, NgTemplateOutlet, HalFormsModule, FormsModule], template: "<ng-template #defaultInputOptionsSingle let-property=\"property\" let-template=\"template\" let-items=\"items\" let-useTemplateDrivenForms=\"useTemplateDrivenForms\">\n @if (useTemplateDrivenForms()) {\n <p-select\n [propertyAttributes]=\"property()\"\n [(ngModel)]=\"model\"\n [options]=\"optionsManager.items.value()\"\n (onFilter)=\"onOptionsFiltered($event)\"\n (onChange)=\"onOptionsChanged($event)\"\n styleClass=\"w-full\"\n [panelStyleClass]=\"optionsManager.loading() ? 'loading' : ''\"\n [emptyFilterMessage]=\"optionsManager.loading() ? 'Loading...' : ''\"\n [loading]=\"optionsManager.loading()\"\n >\n <ng-template #selectedItem let-selectedItem>\n <span [pTooltip]=\"optionsManager.getTooltip()(selectedItem)\">{{optionsManager.getLabel()(selectedItem)}}</span>\n </ng-template>\n <ng-template #item let-item>\n <span [pTooltip]=\"optionsManager.getTooltip()(item)\">{{optionsManager.getLabel()(item)}}</span>\n </ng-template>\n </p-select>\n }\n @else {\n <p-select\n [formControlProperty]=\"property()\"\n [options]=\"optionsManager.items.value()\"\n (onFilter)=\"onOptionsFiltered($event)\"\n (onChange)=\"onOptionsChanged($event)\"\n styleClass=\"w-full\"\n [panelStyleClass]=\"optionsManager.loading() ? 'loading' : ''\"\n [emptyFilterMessage]=\"optionsManager.loading() ? 'Loading...' : ''\"\n [loading]=\"optionsManager.loading()\"\n >\n <ng-template #selectedItem let-selectedItem>\n <span [pTooltip]=\"optionsManager.getTooltip()(selectedItem)\">{{optionsManager.getLabel()(selectedItem)}}</span>\n </ng-template>\n <ng-template #item let-item>\n <span [pTooltip]=\"optionsManager.getTooltip()(item)\">{{optionsManager.getLabel()(item)}}</span>\n </ng-template>\n </p-select>\n }\n</ng-template>\n\n<ng-template #defaultInputOptionsMultiple let-property=\"property\" let-template=\"template\" let-items=\"items\" let-useTemplateDrivenForms=\"useTemplateDrivenForms\">\n @if (useTemplateDrivenForms()) {\n <p-multiSelect\n [propertyAttributes]=\"property()\"\n [(ngModel)]=\"model\"\n [options]=\"optionsManager.items.value()\"\n (onFilter)=\"onOptionsFiltered($event)\"\n (onChange)=\"onOptionsChanged($event)\"\n styleClass=\"w-full\"\n [panelStyleClass]=\"optionsManager.loading() ? 'loading' : ''\"\n [emptyFilterMessage]=\"optionsManager.loading() ? 'Loading...' : ''\"\n [loading]=\"optionsManager.loading()\"\n >\n <ng-template #selecteditems let-items let-removeChip=\"removeChip\">\n @for (item of items; track item; let i = $index) {\n <p-chip\n [pTooltip]=\"optionsManager.getTooltip()(item)\"\n [label]=\"optionsManager.getLabel()(item)\"\n [removable]=\"true\"\n (onRemove)=\"removeChip(optionsManager.getValue(item), $event)\"\n >\n </p-chip>\n }\n </ng-template>\n <ng-template #item let-item>\n <span [pTooltip]=\"optionsManager.getTooltip()(item)\">{{optionsManager.getLabel()(item)}}</span>\n </ng-template>\n </p-multiSelect>\n }\n @else {\n <p-multiSelect\n [formControlProperty]=\"property()\"\n [options]=\"optionsManager.items.value()\"\n (onFilter)=\"onOptionsFiltered($event)\"\n (onChange)=\"onOptionsChanged($event)\"\n styleClass=\"w-full\"\n [panelStyleClass]=\"optionsManager.loading() ? 'loading' : ''\"\n [emptyFilterMessage]=\"optionsManager.loading() ? 'Loading...' : ''\"\n [loading]=\"optionsManager.loading()\"\n >\n <ng-template #selecteditems let-items let-removeChip=\"removeChip\">\n @for (item of items; track item; let i = $index) {\n <p-chip\n [pTooltip]=\"optionsManager.getTooltip()(item)\"\n [label]=\"optionsManager.getLabel()(item)\"\n [removable]=\"true\"\n (onRemove)=\"removeChip(optionsManager.getValue(item), $event)\"\n >\n </p-chip>\n }\n </ng-template>\n <ng-template #item let-item>\n <span [pTooltip]=\"optionsManager.getTooltip()(item)\">{{optionsManager.getLabel()(item)}}</span>\n </ng-template>\n </p-multiSelect>\n }\n</ng-template>\n\n@if(!optionsManager.options().maxItems || optionsManager.options().maxItems == 1) {\n <ng-container *ngTemplateOutlet=\"inputOptionsSingleRef() ?? defaultInputOptionsSingle; context: { property: property, apiName: apiName, items: optionsManager.items, useTemplateDrivenForms: useTemplateDrivenForms, model: model }\"></ng-container>\n}\n@else {\n <ng-container *ngTemplateOutlet=\"inputOptionsMultipleRef() ?? defaultInputOptionsMultiple; context: { property: property, apiName: apiName, items: optionsManager.items, useTemplateDrivenForms: useTemplateDrivenForms, model: model }\"></ng-container>\n}\n", styles: ["::ng-deep .p-multiselect-label{display:inline-flex!important}::ng-deep .p-multiselect-label-empty{height:36px}::ng-deep .p-chip{background-color:#eff6ff;color:#1d4ed8}::ng-deep .pi-chip-remove-icon:hover{filter:brightness(.6)}\n"] }]
|
|
3992
|
+
}], ctorParameters: () => [{ type: i2$3.ControlContainer }, { type: OptionsService }] });
|
|
3993
|
+
/**
|
|
3994
|
+
* A complex object with multiple properties that is automatically created from the given property.
|
|
3995
|
+
* The object can also be nested.
|
|
3996
|
+
* @remarks It is advised to use {@link RestWorldInputComponent} `<rw-input>` and control the rendered inputs with the passed in property
|
|
3997
|
+
* instead of using this component directly.
|
|
3998
|
+
* @example
|
|
3999
|
+
* <rw-input-object [property]="property" [apiName]="apiName"></rw-input-object>
|
|
4000
|
+
*/
|
|
4001
|
+
class RestWorldInputObjectComponent extends RestWorldInputLazyLoadBaseComponent {
|
|
4002
|
+
_controlContainer;
|
|
4003
|
+
inputObjectRef = contentChild("inputObject", ...(ngDevMode ? [{ debugName: "inputObjectRef" }] : []));
|
|
4004
|
+
constructor(_controlContainer) {
|
|
4005
|
+
super();
|
|
4006
|
+
this._controlContainer = _controlContainer;
|
|
3807
4007
|
}
|
|
3808
|
-
|
|
3809
|
-
|
|
3810
|
-
|
|
3811
|
-
|
|
3812
|
-
|
|
3813
|
-
static
|
|
3814
|
-
|
|
4008
|
+
innerFormGroup = computed(() => {
|
|
4009
|
+
const formGroup = this._controlContainer.control;
|
|
4010
|
+
return formGroup.controls[this.property().name];
|
|
4011
|
+
}, ...(ngDevMode ? [{ debugName: "innerFormGroup" }] : []));
|
|
4012
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: RestWorldInputObjectComponent, deps: [{ token: i2$3.ControlContainer }], target: i0.ɵɵFactoryTarget.Component });
|
|
4013
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.3.1", type: RestWorldInputObjectComponent, isStandalone: true, selector: "rw-input-object", queries: [{ propertyName: "inputObjectRef", first: true, predicate: ["inputObject"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<ng-template #defaultInputObject let-property=\"property\" let-innerFormGroup=\"innerFormGroup\", let-apiName=\"apiName\">\n <div class=\"flex align-items-center\">\n <div class=\"brace\">\n </div>\n <div class=\"w-full\">\n <rw-input-template [formGroup]=\"innerFormGroup()\" [template]=\"property()._templates.default\" [apiName]=\"apiName()\"></rw-input-template>\n </div>\n </div>\n</ng-template>\n\n<ng-container>\n <ng-container *ngTemplateOutlet=\"inputObjectRef() || defaultInputObject; context: { property: property, innerFormGroup: innerFormGroup, apiName: apiName }\"></ng-container>\n</ng-container>\n", styles: [".brace{align-self:stretch;margin:.2rem .5rem;border-left:1px solid rgb(206,212,218);border-top:1px solid rgb(206,212,218);border-bottom:1px solid rgb(206,212,218);width:1rem}\n"], dependencies: [{ kind: "component", type: i0.forwardRef(() => RestWorldInputTemplateComponent), selector: "rw-input-template", inputs: ["apiName", "template"] }, { kind: "ngmodule", type: i0.forwardRef(() => ReactiveFormsModule) }, { kind: "directive", type: i0.forwardRef(() => i2$3.NgControlStatusGroup), selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i0.forwardRef(() => i2$3.FormGroupDirective), selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i0.forwardRef(() => NgTemplateOutlet), selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], viewProviders: [{ provide: ControlContainer, useExisting: FormGroupDirective }] });
|
|
4014
|
+
}
|
|
4015
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: RestWorldInputObjectComponent, decorators: [{
|
|
4016
|
+
type: Component,
|
|
4017
|
+
args: [{ selector: 'rw-input-object', standalone: true, viewProviders: [{ provide: ControlContainer, useExisting: FormGroupDirective }], imports: [forwardRef(() => RestWorldInputTemplateComponent), ReactiveFormsModule, NgTemplateOutlet], template: "<ng-template #defaultInputObject let-property=\"property\" let-innerFormGroup=\"innerFormGroup\", let-apiName=\"apiName\">\n <div class=\"flex align-items-center\">\n <div class=\"brace\">\n </div>\n <div class=\"w-full\">\n <rw-input-template [formGroup]=\"innerFormGroup()\" [template]=\"property()._templates.default\" [apiName]=\"apiName()\"></rw-input-template>\n </div>\n </div>\n</ng-template>\n\n<ng-container>\n <ng-container *ngTemplateOutlet=\"inputObjectRef() || defaultInputObject; context: { property: property, innerFormGroup: innerFormGroup, apiName: apiName }\"></ng-container>\n</ng-container>\n", styles: [".brace{align-self:stretch;margin:.2rem .5rem;border-left:1px solid rgb(206,212,218);border-top:1px solid rgb(206,212,218);border-bottom:1px solid rgb(206,212,218);width:1rem}\n"] }]
|
|
4018
|
+
}], ctorParameters: () => [{ type: i2$3.ControlContainer }] });
|
|
4019
|
+
/**
|
|
4020
|
+
* A simple input element, like a string, a number or a Date that is automatically created from the given property.
|
|
4021
|
+
* @remarks It is advised to use {@link RestWorldInputComponent} `<rw-input>` and control the rendered inputs with the passed in property
|
|
4022
|
+
* instead of using this component directly.
|
|
4023
|
+
* @example
|
|
4024
|
+
* <rw-input-simple [property]="property" [apiName]="apiName"></rw-input-simple>
|
|
4025
|
+
*/
|
|
4026
|
+
class RestWorldInputSimpleComponent extends RestWorldInputBaseComponent {
|
|
4027
|
+
static _dateFormat = new Date(3333, 10, 22) // months start at 0 in JS
|
|
4028
|
+
.toLocaleDateString()
|
|
4029
|
+
.replace("22", "dd")
|
|
4030
|
+
.replace("11", "mm")
|
|
4031
|
+
.replace("3333", "yy")
|
|
4032
|
+
.replace("33", "y");
|
|
4033
|
+
static _timeFormat = new Date(1, 1, 1, 22, 33, 44)
|
|
4034
|
+
.toLocaleTimeString()
|
|
4035
|
+
.replace("22", "hh")
|
|
4036
|
+
.replace("33", "mm")
|
|
4037
|
+
.replace("44", "ss");
|
|
4038
|
+
_inputChild = viewChild("inputElement", ...(ngDevMode ? [{ debugName: "_inputChild" }] : []));
|
|
4039
|
+
_controlChild = viewChild(NG_VALUE_ACCESSOR, ...(ngDevMode ? [{ debugName: "_controlChild" }] : []));
|
|
4040
|
+
constructor() {
|
|
4041
|
+
super();
|
|
3815
4042
|
}
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
|
|
3823
|
-
|
|
3824
|
-
|
|
3825
|
-
|
|
3826
|
-
|
|
3827
|
-
|
|
3828
|
-
|
|
3829
|
-
|
|
3830
|
-
|
|
3831
|
-
|
|
3832
|
-
|
|
3833
|
-
|
|
3834
|
-
|
|
3835
|
-
|
|
3836
|
-
|
|
3837
|
-
|
|
3838
|
-
|
|
3839
|
-
|
|
4043
|
+
writeValue(obj) {
|
|
4044
|
+
const controlChild = this._controlChild();
|
|
4045
|
+
const inputChild = this._inputChild();
|
|
4046
|
+
if (controlChild !== undefined)
|
|
4047
|
+
controlChild.writeValue(obj);
|
|
4048
|
+
else if (inputChild !== undefined)
|
|
4049
|
+
inputChild.nativeElement.value = obj;
|
|
4050
|
+
}
|
|
4051
|
+
registerOnChange(fn) {
|
|
4052
|
+
const controlChild = this._controlChild();
|
|
4053
|
+
const inputChild = this._inputChild();
|
|
4054
|
+
if (controlChild !== undefined)
|
|
4055
|
+
controlChild.registerOnChange(fn);
|
|
4056
|
+
else if (inputChild !== undefined)
|
|
4057
|
+
inputChild.nativeElement.oninput = (event) => fn(event.target.value);
|
|
4058
|
+
}
|
|
4059
|
+
registerOnTouched(fn) {
|
|
4060
|
+
const controlChild = this._controlChild();
|
|
4061
|
+
const inputChild = this._inputChild();
|
|
4062
|
+
if (controlChild !== undefined)
|
|
4063
|
+
controlChild.registerOnTouched(fn);
|
|
4064
|
+
else if (inputChild !== undefined)
|
|
4065
|
+
inputChild.nativeElement.onblur = (event) => fn();
|
|
4066
|
+
}
|
|
4067
|
+
setDisabledState(isDisabled) {
|
|
4068
|
+
const controlChild = this._controlChild();
|
|
4069
|
+
const inputChild = this._inputChild();
|
|
4070
|
+
if (controlChild !== undefined && controlChild.setDisabledState !== undefined)
|
|
4071
|
+
controlChild.setDisabledState(isDisabled);
|
|
4072
|
+
else if (inputChild !== undefined) {
|
|
4073
|
+
if (isDisabled)
|
|
4074
|
+
inputChild.nativeElement.setAttribute("disabled", "disabled");
|
|
4075
|
+
else
|
|
4076
|
+
inputChild.nativeElement.removeAttribute("disabled");
|
|
3840
4077
|
}
|
|
3841
4078
|
}
|
|
3842
|
-
|
|
3843
|
-
|
|
3844
|
-
return undefined;
|
|
3845
|
-
const options = property.options;
|
|
3846
|
-
if (options === undefined)
|
|
3847
|
-
throw Error(`Property ${property.name} has no options`);
|
|
3848
|
-
const maxItems = options.maxItems ?? Number.MAX_SAFE_INTEGER;
|
|
3849
|
-
const oDataOperator = ODataService.createODataOperator(filter.matchMode);
|
|
3850
|
-
// Normal enum
|
|
3851
|
-
if (maxItems === 1) {
|
|
3852
|
-
const comparisonValue = ODataService.createComparisonValue(property, filter.value, true);
|
|
3853
|
-
return `${property.name} ${oDataOperator} ${comparisonValue}`;
|
|
3854
|
-
}
|
|
3855
|
-
// Flags enum
|
|
3856
|
-
if (filter.value === null || filter.value === undefined)
|
|
3857
|
-
return undefined;
|
|
3858
|
-
const values = Array.isArray(filter.value) ? filter.value : [filter.value];
|
|
3859
|
-
const comparisonValues = values.map(v => ODataService.createComparisonValue(property, v, true));
|
|
3860
|
-
const filters = comparisonValues.map(v => `${property.name} has ${v}`);
|
|
3861
|
-
const concatenatedFilters = filters.join(' and ');
|
|
3862
|
-
return `(${concatenatedFilters})`;
|
|
4079
|
+
get PropertyType() {
|
|
4080
|
+
return PropertyType;
|
|
3863
4081
|
}
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
case FilterMatchMode.STARTS_WITH:
|
|
3867
|
-
return 'startswith';
|
|
3868
|
-
case FilterMatchMode.CONTAINS:
|
|
3869
|
-
return 'contains';
|
|
3870
|
-
case FilterMatchMode.NOT_CONTAINS:
|
|
3871
|
-
return 'not contains';
|
|
3872
|
-
case FilterMatchMode.ENDS_WITH:
|
|
3873
|
-
return 'endswith';
|
|
3874
|
-
case FilterMatchMode.EQUALS:
|
|
3875
|
-
return 'eq';
|
|
3876
|
-
case FilterMatchMode.NOT_EQUALS:
|
|
3877
|
-
return 'ne';
|
|
3878
|
-
case FilterMatchMode.IN:
|
|
3879
|
-
return 'in';
|
|
3880
|
-
case FilterMatchMode.LESS_THAN:
|
|
3881
|
-
return 'lt';
|
|
3882
|
-
case FilterMatchMode.LESS_THAN_OR_EQUAL_TO:
|
|
3883
|
-
return 'le';
|
|
3884
|
-
case FilterMatchMode.GREATER_THAN:
|
|
3885
|
-
return 'gt';
|
|
3886
|
-
case FilterMatchMode.GREATER_THAN_OR_EQUAL_TO:
|
|
3887
|
-
return 'ge';
|
|
3888
|
-
case FilterMatchMode.IS:
|
|
3889
|
-
return 'eq';
|
|
3890
|
-
case FilterMatchMode.IS_NOT:
|
|
3891
|
-
return 'ne';
|
|
3892
|
-
case FilterMatchMode.BEFORE:
|
|
3893
|
-
return 'lt';
|
|
3894
|
-
case FilterMatchMode.AFTER:
|
|
3895
|
-
return 'gt';
|
|
3896
|
-
case FilterMatchMode.DATE_AFTER:
|
|
3897
|
-
return 'ge';
|
|
3898
|
-
case FilterMatchMode.DATE_BEFORE:
|
|
3899
|
-
return 'lt';
|
|
3900
|
-
case FilterMatchMode.DATE_IS:
|
|
3901
|
-
return 'eq';
|
|
3902
|
-
case FilterMatchMode.DATE_IS_NOT:
|
|
3903
|
-
return 'ne';
|
|
3904
|
-
default:
|
|
3905
|
-
throw Error(`Unknown matchMode ${matchMode}`);
|
|
3906
|
-
}
|
|
4082
|
+
get PropertyWithImage() {
|
|
4083
|
+
return PropertyWithImage;
|
|
3907
4084
|
}
|
|
3908
|
-
|
|
3909
|
-
|
|
3910
|
-
if (typeof value === "string" ||
|
|
3911
|
-
Array.isArray(value) && value.every(v => typeof v === "string") ||
|
|
3912
|
-
property.options.inline?.some(o => property.options.valueField !== undefined && typeof o[property.options.valueField] === "string"))
|
|
3913
|
-
return PropertyType.Text;
|
|
3914
|
-
return PropertyType.Number;
|
|
3915
|
-
}
|
|
3916
|
-
return property.type;
|
|
4085
|
+
get dateFormat() {
|
|
4086
|
+
return RestWorldInputSimpleComponent._dateFormat;
|
|
3917
4087
|
}
|
|
3918
|
-
|
|
3919
|
-
|
|
4088
|
+
// public readonly formControl = computed(() => {
|
|
4089
|
+
// const formGroup = this._controlContainer.control as FormGroup<any>;
|
|
4090
|
+
// return formGroup.controls[this.property().name] as FormControl<SimpleValue | SimpleValue[]>;
|
|
4091
|
+
// });
|
|
4092
|
+
get timeFormat() {
|
|
4093
|
+
return RestWorldInputSimpleComponent._timeFormat;
|
|
4094
|
+
}
|
|
4095
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: RestWorldInputSimpleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4096
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.1", type: RestWorldInputSimpleComponent, isStandalone: true, selector: "rw-input-simple", providers: [{
|
|
4097
|
+
provide: NG_VALUE_ACCESSOR,
|
|
4098
|
+
useExisting: forwardRef(() => RestWorldInputSimpleComponent),
|
|
4099
|
+
multi: true
|
|
4100
|
+
}], viewQueries: [{ propertyName: "_inputChild", first: true, predicate: ["inputElement"], descendants: true, isSignal: true }, { propertyName: "_controlChild", first: true, predicate: NG_VALUE_ACCESSOR, descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "@switch(property().type) {\r\n @case (PropertyType.Textarea) {\r\n @if (useTemplateDrivenForms()){\r\n <textarea #inputElement [propertyAttributes]=\"property()\" [(ngModel)]=\"model\" pInputTextarea class=\"w-full p-inputtextarea p-inputtext p-component p-element\"></textarea>\r\n }\r\n @else {\r\n <textarea #inputElement [formControlProperty]=\"property()\" pInputTextarea class=\"w-full p-inputtextarea p-inputtext p-component p-element\"></textarea>\r\n }\r\n }\r\n @case (PropertyType.Date) {\r\n @if (useTemplateDrivenForms()) {\r\n <p-datepicker [propertyAttributes]=\"property()\" [(ngModel)]=\"model\" [dateFormat]=\"dateFormat\" [showWeek]=\"true\" [showIcon]=\"true\" styleClass=\"w-full\"></p-datepicker>\r\n }\r\n @else {\r\n <p-datepicker [formControlProperty]=\"property()\" [dateFormat]=\"dateFormat\" [showWeek]=\"true\" [showIcon]=\"true\" styleClass=\"w-full\"></p-datepicker>\r\n }\r\n }\r\n @case (PropertyType.Month) {\r\n @if (useTemplateDrivenForms()) {\r\n <p-datepicker [propertyAttributes]=\"property()\" [(ngModel)]=\"model\" [dateFormat]=\"dateFormat\" [showWeek]=\"false\" view=\"month\" [showIcon]=\"true\" styleClass=\"w-full\"></p-datepicker>\r\n }\r\n @else {\r\n <p-datepicker [formControlProperty]=\"property()\" [dateFormat]=\"dateFormat\" [showWeek]=\"false\" view=\"month\" [showIcon]=\"true\" styleClass=\"w-full\"></p-datepicker>\r\n }\r\n }\r\n @case (PropertyType.Time) {\r\n @if (useTemplateDrivenForms()) {\r\n <p-datepicker [propertyAttributes]=\"property()\" [(ngModel)]=\"model\" [dateFormat]=\"timeFormat\" [showTime]=\"true\" [timeOnly]=\"true\" [showWeek]=\"false\" [showIcon]=\"true\" styleClass=\"w-full\"></p-datepicker>\r\n }\r\n @else {\r\n <p-datepicker [formControlProperty]=\"property()\" [dateFormat]=\"timeFormat\" [showTime]=\"true\" [timeOnly]=\"true\" [showWeek]=\"false\" [showIcon]=\"true\" styleClass=\"w-full\"></p-datepicker>\r\n }\r\n }\r\n @case (PropertyType.DatetimeLocal) {\r\n @if (useTemplateDrivenForms()) {\r\n <p-datepicker [propertyAttributes]=\"property()\" [(ngModel)]=\"model\" [dateFormat]=\"dateFormat\" [showTime]=\"true\" [showWeek]=\"false\" [showIcon]=\"true\" styleClass=\"w-full\"></p-datepicker>\r\n }\r\n @else {\r\n <p-datepicker [formControlProperty]=\"property()\" [dateFormat]=\"dateFormat\" [showTime]=\"true\" [showWeek]=\"false\" [showIcon]=\"true\" styleClass=\"w-full\"></p-datepicker>\r\n }\r\n }\r\n @case (PropertyType.Number) {\r\n @if (useTemplateDrivenForms()) {\r\n <p-inputNumber [propertyAttributes]=\"property()\" [(ngModel)]=\"model\" class=\"w-full\" styleClass=\"w-full\"></p-inputNumber>\r\n }\r\n @else {\r\n <p-inputNumber inputMode=\"decimal\" [formControlProperty]=\"property()\" class=\"w-full\" styleClass=\"w-full\"></p-inputNumber>\r\n }\r\n }\r\n @case (PropertyType.Bool) {\r\n @if (useTemplateDrivenForms()) {\r\n <rw-tri-state-checkbox [propertyAttributes]=\"property()\" [(ngModel)]=\"model\" [required]=\"property().required ?? false\"></rw-tri-state-checkbox>\r\n }\r\n @else {\r\n <rw-tri-state-checkbox [formControlProperty]=\"property()\" [required]=\"property().required\"></rw-tri-state-checkbox>\r\n }\r\n }\r\n @case (PropertyType.DatetimeOffset) {\r\n @if (useTemplateDrivenForms()) {\r\n <p-datepicker [propertyAttributes]=\"property()\" [(ngModel)]=\"model\" [dateFormat]=\"dateFormat\" [showTime]=\"true\" [showWeek]=\"false\" [showIcon]=\"true\" styleClass=\"w-full\"></p-datepicker>\r\n }\r\n @else {\r\n <p-datepicker [formControlProperty]=\"property()\" [dateFormat]=\"dateFormat\" [showTime]=\"true\" [showWeek]=\"false\" [showIcon]=\"true\" styleClass=\"w-full\"></p-datepicker>\r\n }\r\n }\r\n @case (PropertyType.Duration) {\r\n @if (useTemplateDrivenForms()) {\r\n <p-datepicker [propertyAttributes]=\"property()\" [(ngModel)]=\"model\" [dateFormat]=\"timeFormat\" [showTime]=\"true\" [timeOnly]=\"true\" [showWeek]=\"false\" [showIcon]=\"true\" styleClass=\"w-full\"></p-datepicker>\r\n }\r\n @else {\r\n <p-datepicker [formControlProperty]=\"property()\" [dateFormat]=\"timeFormat\" [showTime]=\"true\" [timeOnly]=\"true\" [showWeek]=\"false\" [showIcon]=\"true\" styleClass=\"w-full\"></p-datepicker>\r\n }\r\n }\r\n @case (PropertyType.Image) {\r\n @if (useTemplateDrivenForms()) {\r\n <rw-image [propertyAttributes]=\"property()\" [(ngModel)]=\"model\" [formControlName]=\"property().name\" [property]=\"$any(property())\"></rw-image>\r\n }\r\n @else {\r\n <rw-image [formControlName]=\"property().name\" [property]=\"$any(property())\"></rw-image>\r\n }\r\n }\r\n @case (PropertyType.File) {\r\n @if (useTemplateDrivenForms()) {\r\n <rw-file [propertyAttributes]=\"property()\" [(ngModel)]=\"model\" [formControlName]=\"property().name\" [fileName]=\"property().name\" [accept]=\"$any(property().placeholder)\"></rw-file>\r\n }\r\n @else {\r\n <rw-file [formControlName]=\"property().name\" [fileName]=\"property().name\" [accept]=\"$any(property().placeholder)\"></rw-file>\r\n }\r\n }\r\n @default {\r\n <!-- <input [formControlName]=\"property().name\" [id]=\"property().name\" type=\"text\" pInputText class=\"w-full\" [class.p-disabled]=\"property().readOnly\" /> -->\r\n @if (useTemplateDrivenForms()) {\r\n <input #inputElement [propertyAttributes]=\"property()\" [(ngModel)]=\"model\" pInputText class=\"w-full\" />\r\n }\r\n @else {\r\n <input #inputElement [formControlProperty]=\"property()\" pInputText class=\"w-full\" />\r\n }\r\n }\r\n}\r\n", styles: [".p-inputtext.ng-touched.ng-invalid{border-color:#e24c4c}\n"], dependencies: [{ kind: "component", type: DatePicker, selector: "p-datePicker, p-datepicker, p-date-picker", inputs: ["iconDisplay", "styleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "ariaLabelledBy", "ariaLabel", "iconAriaLabel", "dateFormat", "multipleSeparator", "rangeSeparator", "inline", "showOtherMonths", "selectOtherMonths", "showIcon", "icon", "readonlyInput", "shortYearCutoff", "hourFormat", "timeOnly", "stepHour", "stepMinute", "stepSecond", "showSeconds", "showOnFocus", "showWeek", "startWeekFromFirstDayOfYear", "showClear", "dataType", "selectionMode", "maxDateCount", "showButtonBar", "todayButtonStyleClass", "clearButtonStyleClass", "autofocus", "autoZIndex", "baseZIndex", "panelStyleClass", "panelStyle", "keepInvalid", "hideOnDateTimeSelect", "touchUI", "timeSeparator", "focusTrap", "showTransitionOptions", "hideTransitionOptions", "tabindex", "minDate", "maxDate", "disabledDates", "disabledDays", "showTime", "responsiveOptions", "numberOfMonths", "firstDayOfWeek", "view", "defaultDate", "appendTo"], outputs: ["onFocus", "onBlur", "onClose", "onSelect", "onClear", "onInput", "onTodayClick", "onClearClick", "onMonthChange", "onYearChange", "onClickOutside", "onShow"] }, { kind: "component", type: InputNumber, selector: "p-inputNumber, p-inputnumber, p-input-number", inputs: ["showButtons", "format", "buttonLayout", "inputId", "styleClass", "placeholder", "tabindex", "title", "ariaLabelledBy", "ariaDescribedBy", "ariaLabel", "ariaRequired", "autocomplete", "incrementButtonClass", "decrementButtonClass", "incrementButtonIcon", "decrementButtonIcon", "readonly", "allowEmpty", "locale", "localeMatcher", "mode", "currency", "currencyDisplay", "useGrouping", "minFractionDigits", "maxFractionDigits", "prefix", "suffix", "inputStyle", "inputStyleClass", "showClear", "autofocus"], outputs: ["onInput", "onFocus", "onBlur", "onKeyDown", "onClear"] }, { kind: "component", type: TriStateCheckbox, selector: "p-tri-state-checkbox, p-tri-state-checkBox, p-tri-state-check-box, rw-tri-state-checkbox, rw-tri-state-checkBox, rw-tri-state-check-box", inputs: ["value", "name", "disabled", "ariaLabelledBy", "ariaLabel", "tabindex", "inputId", "style", "inputStyle", "styleClass", "inputClass", "size", "formControl", "checkboxIcon", "readonly", "required", "autofocus", "model", "variant"], outputs: ["disabledChange", "modelChange", "onChange", "onFocus", "onBlur"] }, { kind: "component", type: RestWorldImageComponent, selector: "rw-image", inputs: ["property", "backgroundColor", "displayCropDialog"], outputs: ["backgroundColorChange", "displayCropDialogChange"] }, { kind: "component", type: RestWorldFileComponent, selector: "rw-file", inputs: ["accept", "fileName"] }, { kind: "directive", type: InputText, selector: "[pInputText]", inputs: ["pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: HalFormsModule }, { kind: "directive", type: FormControlProperty, selector: "[formControlProperty]:not([useTemplateDrivenForms=true])", inputs: ["formControlProperty"] }, { kind: "directive", type: DefaultPropertyValueAccessor, selector: "input:not([type=checkbox])[formControlProperty], textarea[formControlProperty], select[formControlProperty]" }, { kind: "directive", type: PropertyControlStatus, selector: "[formControlProperty]" }, { kind: "directive", type: PropertyAttributes, selector: "[formControlProperty],[propertyAttributes]", inputs: ["formControlProperty", "propertyAttributes"] }, { kind: "directive", type: PropertyInputNumberAttributes, selector: "p-inputNumber[formControlProperty], p-inputNumber[propertyAttributes]", inputs: ["formControlProperty", "propertyAttributes"] }, { kind: "directive", type: i2$3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$3.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i2$3.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }], viewProviders: [{ provide: ControlContainer, useExisting: FormGroupDirective }] });
|
|
3920
4101
|
}
|
|
3921
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type:
|
|
3922
|
-
type:
|
|
3923
|
-
args: [{
|
|
3924
|
-
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
|
|
4102
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: RestWorldInputSimpleComponent, decorators: [{
|
|
4103
|
+
type: Component,
|
|
4104
|
+
args: [{ selector: 'rw-input-simple', standalone: true, providers: [{
|
|
4105
|
+
provide: NG_VALUE_ACCESSOR,
|
|
4106
|
+
useExisting: forwardRef(() => RestWorldInputSimpleComponent),
|
|
4107
|
+
multi: true
|
|
4108
|
+
}], viewProviders: [{ provide: ControlContainer, useExisting: FormGroupDirective }], imports: [DatePicker, InputNumber, TriStateCheckbox, RestWorldImageComponent, RestWorldFileComponent, InputText, HalFormsModule, FormsModule], template: "@switch(property().type) {\r\n @case (PropertyType.Textarea) {\r\n @if (useTemplateDrivenForms()){\r\n <textarea #inputElement [propertyAttributes]=\"property()\" [(ngModel)]=\"model\" pInputTextarea class=\"w-full p-inputtextarea p-inputtext p-component p-element\"></textarea>\r\n }\r\n @else {\r\n <textarea #inputElement [formControlProperty]=\"property()\" pInputTextarea class=\"w-full p-inputtextarea p-inputtext p-component p-element\"></textarea>\r\n }\r\n }\r\n @case (PropertyType.Date) {\r\n @if (useTemplateDrivenForms()) {\r\n <p-datepicker [propertyAttributes]=\"property()\" [(ngModel)]=\"model\" [dateFormat]=\"dateFormat\" [showWeek]=\"true\" [showIcon]=\"true\" styleClass=\"w-full\"></p-datepicker>\r\n }\r\n @else {\r\n <p-datepicker [formControlProperty]=\"property()\" [dateFormat]=\"dateFormat\" [showWeek]=\"true\" [showIcon]=\"true\" styleClass=\"w-full\"></p-datepicker>\r\n }\r\n }\r\n @case (PropertyType.Month) {\r\n @if (useTemplateDrivenForms()) {\r\n <p-datepicker [propertyAttributes]=\"property()\" [(ngModel)]=\"model\" [dateFormat]=\"dateFormat\" [showWeek]=\"false\" view=\"month\" [showIcon]=\"true\" styleClass=\"w-full\"></p-datepicker>\r\n }\r\n @else {\r\n <p-datepicker [formControlProperty]=\"property()\" [dateFormat]=\"dateFormat\" [showWeek]=\"false\" view=\"month\" [showIcon]=\"true\" styleClass=\"w-full\"></p-datepicker>\r\n }\r\n }\r\n @case (PropertyType.Time) {\r\n @if (useTemplateDrivenForms()) {\r\n <p-datepicker [propertyAttributes]=\"property()\" [(ngModel)]=\"model\" [dateFormat]=\"timeFormat\" [showTime]=\"true\" [timeOnly]=\"true\" [showWeek]=\"false\" [showIcon]=\"true\" styleClass=\"w-full\"></p-datepicker>\r\n }\r\n @else {\r\n <p-datepicker [formControlProperty]=\"property()\" [dateFormat]=\"timeFormat\" [showTime]=\"true\" [timeOnly]=\"true\" [showWeek]=\"false\" [showIcon]=\"true\" styleClass=\"w-full\"></p-datepicker>\r\n }\r\n }\r\n @case (PropertyType.DatetimeLocal) {\r\n @if (useTemplateDrivenForms()) {\r\n <p-datepicker [propertyAttributes]=\"property()\" [(ngModel)]=\"model\" [dateFormat]=\"dateFormat\" [showTime]=\"true\" [showWeek]=\"false\" [showIcon]=\"true\" styleClass=\"w-full\"></p-datepicker>\r\n }\r\n @else {\r\n <p-datepicker [formControlProperty]=\"property()\" [dateFormat]=\"dateFormat\" [showTime]=\"true\" [showWeek]=\"false\" [showIcon]=\"true\" styleClass=\"w-full\"></p-datepicker>\r\n }\r\n }\r\n @case (PropertyType.Number) {\r\n @if (useTemplateDrivenForms()) {\r\n <p-inputNumber [propertyAttributes]=\"property()\" [(ngModel)]=\"model\" class=\"w-full\" styleClass=\"w-full\"></p-inputNumber>\r\n }\r\n @else {\r\n <p-inputNumber inputMode=\"decimal\" [formControlProperty]=\"property()\" class=\"w-full\" styleClass=\"w-full\"></p-inputNumber>\r\n }\r\n }\r\n @case (PropertyType.Bool) {\r\n @if (useTemplateDrivenForms()) {\r\n <rw-tri-state-checkbox [propertyAttributes]=\"property()\" [(ngModel)]=\"model\" [required]=\"property().required ?? false\"></rw-tri-state-checkbox>\r\n }\r\n @else {\r\n <rw-tri-state-checkbox [formControlProperty]=\"property()\" [required]=\"property().required\"></rw-tri-state-checkbox>\r\n }\r\n }\r\n @case (PropertyType.DatetimeOffset) {\r\n @if (useTemplateDrivenForms()) {\r\n <p-datepicker [propertyAttributes]=\"property()\" [(ngModel)]=\"model\" [dateFormat]=\"dateFormat\" [showTime]=\"true\" [showWeek]=\"false\" [showIcon]=\"true\" styleClass=\"w-full\"></p-datepicker>\r\n }\r\n @else {\r\n <p-datepicker [formControlProperty]=\"property()\" [dateFormat]=\"dateFormat\" [showTime]=\"true\" [showWeek]=\"false\" [showIcon]=\"true\" styleClass=\"w-full\"></p-datepicker>\r\n }\r\n }\r\n @case (PropertyType.Duration) {\r\n @if (useTemplateDrivenForms()) {\r\n <p-datepicker [propertyAttributes]=\"property()\" [(ngModel)]=\"model\" [dateFormat]=\"timeFormat\" [showTime]=\"true\" [timeOnly]=\"true\" [showWeek]=\"false\" [showIcon]=\"true\" styleClass=\"w-full\"></p-datepicker>\r\n }\r\n @else {\r\n <p-datepicker [formControlProperty]=\"property()\" [dateFormat]=\"timeFormat\" [showTime]=\"true\" [timeOnly]=\"true\" [showWeek]=\"false\" [showIcon]=\"true\" styleClass=\"w-full\"></p-datepicker>\r\n }\r\n }\r\n @case (PropertyType.Image) {\r\n @if (useTemplateDrivenForms()) {\r\n <rw-image [propertyAttributes]=\"property()\" [(ngModel)]=\"model\" [formControlName]=\"property().name\" [property]=\"$any(property())\"></rw-image>\r\n }\r\n @else {\r\n <rw-image [formControlName]=\"property().name\" [property]=\"$any(property())\"></rw-image>\r\n }\r\n }\r\n @case (PropertyType.File) {\r\n @if (useTemplateDrivenForms()) {\r\n <rw-file [propertyAttributes]=\"property()\" [(ngModel)]=\"model\" [formControlName]=\"property().name\" [fileName]=\"property().name\" [accept]=\"$any(property().placeholder)\"></rw-file>\r\n }\r\n @else {\r\n <rw-file [formControlName]=\"property().name\" [fileName]=\"property().name\" [accept]=\"$any(property().placeholder)\"></rw-file>\r\n }\r\n }\r\n @default {\r\n <!-- <input [formControlName]=\"property().name\" [id]=\"property().name\" type=\"text\" pInputText class=\"w-full\" [class.p-disabled]=\"property().readOnly\" /> -->\r\n @if (useTemplateDrivenForms()) {\r\n <input #inputElement [propertyAttributes]=\"property()\" [(ngModel)]=\"model\" pInputText class=\"w-full\" />\r\n }\r\n @else {\r\n <input #inputElement [formControlProperty]=\"property()\" pInputText class=\"w-full\" />\r\n }\r\n }\r\n}\r\n", styles: [".p-inputtext.ng-touched.ng-invalid{border-color:#e24c4c}\n"] }]
|
|
4109
|
+
}], ctorParameters: () => [] });
|
|
3928
4110
|
/**
|
|
3929
|
-
*
|
|
3930
|
-
*
|
|
4111
|
+
* A collection of `<rw-form>` elements automatically created from a template.
|
|
4112
|
+
* Does not have any buttons on its own.
|
|
4113
|
+
* If you want buttons, use {@link RestWorldForm} `<rw-form>`.
|
|
4114
|
+
* @example
|
|
4115
|
+
* <rw-form-collection [template]="template" [apiName]="apiName"></rw-form-collection>
|
|
3931
4116
|
*/
|
|
3932
|
-
class
|
|
3933
|
-
_formService;
|
|
3934
|
-
/**
|
|
3935
|
-
* The filter constraint to update when the value changes.
|
|
3936
|
-
* This is coming from the $context of the #filter template
|
|
3937
|
-
*/
|
|
3938
|
-
filterConstraint = input.required(...(ngDevMode ? [{ debugName: "filterConstraint" }] : []));
|
|
3939
|
-
/**
|
|
3940
|
-
* The HAL-Forms property to filter by.
|
|
3941
|
-
* This is normally the column.
|
|
3942
|
-
*/
|
|
3943
|
-
property = input.required(...(ngDevMode ? [{ debugName: "property" }] : []));
|
|
4117
|
+
class RestWorldInputTemplateComponent {
|
|
3944
4118
|
/**
|
|
3945
|
-
* The name of the API to use
|
|
4119
|
+
* The name of the API to use for the property.
|
|
4120
|
+
* @required
|
|
4121
|
+
* @remarks This is the name of the API as defined in the `RestWorldClientCollection`.
|
|
3946
4122
|
*/
|
|
3947
4123
|
apiName = input.required(...(ngDevMode ? [{ debugName: "apiName" }] : []));
|
|
3948
4124
|
/**
|
|
3949
|
-
* The
|
|
4125
|
+
* The template to display.
|
|
4126
|
+
* @required
|
|
4127
|
+
* @remarks This is the template that defines the properties to display.
|
|
3950
4128
|
*/
|
|
3951
|
-
|
|
3952
|
-
|
|
3953
|
-
|
|
3954
|
-
properties: [this.property()],
|
|
3955
|
-
}), ...(ngDevMode ? [{ debugName: "template" }] : []));
|
|
3956
|
-
_formValueChangesSubscription;
|
|
3957
|
-
constructor(_formService) {
|
|
3958
|
-
this._formService = _formService;
|
|
3959
|
-
effect(() => {
|
|
3960
|
-
this._formValueChangesSubscription?.unsubscribe();
|
|
3961
|
-
const form = this.form();
|
|
3962
|
-
const property = this.property();
|
|
3963
|
-
const value = untracked(() => this.value());
|
|
3964
|
-
const formControl = form.controls[property.name];
|
|
3965
|
-
this._formValueChangesSubscription = formControl.valueChanges.subscribe(this.setFilterValue.bind(this));
|
|
3966
|
-
formControl.setValue(value);
|
|
3967
|
-
});
|
|
3968
|
-
}
|
|
3969
|
-
setFilterValue(value) {
|
|
3970
|
-
this.filterConstraint().value = value;
|
|
3971
|
-
}
|
|
3972
|
-
ngOnDestroy() {
|
|
3973
|
-
this._formValueChangesSubscription?.unsubscribe();
|
|
3974
|
-
}
|
|
3975
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: RestWorldTableColumnFilterElementComponent, deps: [{ token: i1$1.FormService }], target: i0.ɵɵFactoryTarget.Component });
|
|
3976
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.1", type: RestWorldTableColumnFilterElementComponent, isStandalone: true, selector: "rw-table-column-filter-element", inputs: { filterConstraint: { classPropertyName: "filterConstraint", publicName: "filterConstraint", isSignal: true, isRequired: true, transformFunction: null }, property: { classPropertyName: "property", publicName: "property", isSignal: true, isRequired: true, transformFunction: null }, apiName: { classPropertyName: "apiName", publicName: "apiName", isSignal: true, isRequired: true, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<form [formGroup]=\"form()\">\r\n <rw-input [property]=\"property()\" [apiName]=\"apiName()\"></rw-input>\r\n</form>\r\n", styles: [""], dependencies: [{ kind: "component", type: RestWorldInputComponent, selector: "rw-input" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2$3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2$3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2$3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }] });
|
|
4129
|
+
template = input.required(...(ngDevMode ? [{ debugName: "template" }] : []));
|
|
4130
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: RestWorldInputTemplateComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4131
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.1", type: RestWorldInputTemplateComponent, isStandalone: true, selector: "rw-input-template", inputs: { apiName: { classPropertyName: "apiName", publicName: "apiName", isSignal: true, isRequired: true, transformFunction: null }, template: { classPropertyName: "template", publicName: "template", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "@for (property of template().properties; track property.name) {\r\n <rw-form-element [property]=\"property\" [apiName]=\"apiName()\"></rw-form-element>\r\n}\r\n", styles: [""], dependencies: [{ kind: "component", type: RestWorldFormElementComponent, selector: "rw-form-element" }], viewProviders: [{ provide: ControlContainer, useExisting: FormGroupDirective }] });
|
|
3977
4132
|
}
|
|
3978
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type:
|
|
4133
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: RestWorldInputTemplateComponent, decorators: [{
|
|
3979
4134
|
type: Component,
|
|
3980
|
-
args: [{ selector: 'rw-
|
|
3981
|
-
}]
|
|
4135
|
+
args: [{ selector: 'rw-input-template', standalone: true, viewProviders: [{ provide: ControlContainer, useExisting: FormGroupDirective }], imports: [RestWorldFormElementComponent], template: "@for (property of template().properties; track property.name) {\r\n <rw-form-element [property]=\"property\" [apiName]=\"apiName()\"></rw-form-element>\r\n}\r\n" }]
|
|
4136
|
+
}] });
|
|
3982
4137
|
|
|
3983
4138
|
/**
|
|
3984
|
-
*
|
|
3985
|
-
*
|
|
3986
|
-
*
|
|
3987
|
-
* The items are displayed as table rows.
|
|
3988
|
-
* The table supports lazy loading, row selection, row menus, and context menus.
|
|
3989
|
-
*
|
|
4139
|
+
* A form with Save, Reload and Delete buttons.
|
|
4140
|
+
* If you do not want buttons, use RestWorldFormTemplateComponent <rw-form-template>.
|
|
4141
|
+
* You can also provide your own buttons by passing in a template.
|
|
3990
4142
|
* @example
|
|
3991
|
-
* <rw-
|
|
3992
|
-
*
|
|
3993
|
-
*
|
|
3994
|
-
*
|
|
3995
|
-
*
|
|
3996
|
-
*
|
|
3997
|
-
*
|
|
3998
|
-
*
|
|
3999
|
-
*
|
|
4000
|
-
*
|
|
4001
|
-
*
|
|
4002
|
-
*
|
|
4003
|
-
*
|
|
4004
|
-
*
|
|
4005
|
-
*
|
|
4006
|
-
*
|
|
4007
|
-
*
|
|
4008
|
-
*
|
|
4009
|
-
*
|
|
4010
|
-
|
|
4011
|
-
|
|
4012
|
-
|
|
4013
|
-
|
|
4014
|
-
|
|
4015
|
-
|
|
4016
|
-
|
|
4017
|
-
|
|
4018
|
-
_controlContainer;
|
|
4019
|
-
_formService;
|
|
4020
|
-
PropertyType = PropertyType;
|
|
4021
|
-
/**
|
|
4022
|
-
* The name of the api.
|
|
4023
|
-
* For the editing capability, you must also set the editTemplate and the formArray.
|
|
4024
|
-
*/
|
|
4025
|
-
apiName = input.required(...(ngDevMode ? [{ debugName: "apiName" }] : []));
|
|
4026
|
-
/**
|
|
4027
|
-
* A function that returns the style class for a cell.
|
|
4028
|
-
* @param row The row for which to return the style class.
|
|
4029
|
-
* @param column The column for which to return the style class.
|
|
4030
|
-
* @param rowIndex The index of the row on the currently displayed page.
|
|
4031
|
-
* @param columnIndex The index of the column.
|
|
4032
|
-
* @returns The style class for the cell.
|
|
4033
|
-
*/
|
|
4034
|
-
cellStyleClass = input(() => "", ...(ngDevMode ? [{ debugName: "cellStyleClass" }] : []));
|
|
4035
|
-
cellStyleClasses = computed(() => this.rows().map((r, ri) => Object.fromEntries(this.columns().map((c, ci) => [c.name, this.cellStyleClass()(r, c, ri, ci)]))), ...(ngDevMode ? [{ debugName: "cellStyleClasses" }] : []));
|
|
4036
|
-
columns = computed(() => this.searchTemplate()?.properties.filter(p => p.type !== PropertyType.Hidden) ?? [], ...(ngDevMode ? [{ debugName: "columns" }] : []));
|
|
4037
|
-
contextMenu = viewChild("contextMenu", ...(ngDevMode ? [{ debugName: "contextMenu" }] : []));
|
|
4038
|
-
contextMenuItems = signal([], ...(ngDevMode ? [{ debugName: "contextMenuItems" }] : []));
|
|
4039
|
-
dateFormat = new Date(3333, 10, 22) // months start at 0 in JS
|
|
4040
|
-
.toLocaleDateString()
|
|
4041
|
-
.replace("22", "dd")
|
|
4042
|
-
.replace("11", "MM")
|
|
4043
|
-
.replace("3333", "yy")
|
|
4044
|
-
.replace("33", "y");
|
|
4045
|
-
editProperties = computed(() => this.editTemplate()?.propertiesRecord ?? {}, ...(ngDevMode ? [{ debugName: "editProperties" }] : []));
|
|
4143
|
+
* <rw-form
|
|
4144
|
+
* [template]="template"
|
|
4145
|
+
* apiName="apiName"
|
|
4146
|
+
* rel="rel"
|
|
4147
|
+
* [allowSubmit]="true"
|
|
4148
|
+
* [allowDelete]="true"
|
|
4149
|
+
* [allowReload]="true"
|
|
4150
|
+
* [showSubmit]="true"
|
|
4151
|
+
* [showDelete]="true"
|
|
4152
|
+
* [showReload]="true">
|
|
4153
|
+
* <ng-template #content let-form="form" let-template="template" let-apiName="apiName">
|
|
4154
|
+
* <!-- Custom form content here -->
|
|
4155
|
+
* <!-- This is optional and will replace the default which renders labels and inputs if present -->
|
|
4156
|
+
* </ng-template>
|
|
4157
|
+
* <ng-template #buttons let-form="form" let-template="template" let-apiName="apiName">
|
|
4158
|
+
* <!-- Custom buttons here -->
|
|
4159
|
+
* <!-- This is optional and will replace the default which renders the Save, Reload and Delete buttons if present -->
|
|
4160
|
+
* </ng-template>
|
|
4161
|
+
* </rw-form>
|
|
4162
|
+
*/
|
|
4163
|
+
class RestWorldFormComponent {
|
|
4164
|
+
_clients;
|
|
4165
|
+
_confirmationService;
|
|
4166
|
+
_messageService;
|
|
4167
|
+
_formService;
|
|
4168
|
+
_elementRef;
|
|
4169
|
+
_problemService;
|
|
4046
4170
|
/**
|
|
4047
|
-
*
|
|
4048
|
-
* Bind this to the template that is used to edit the items.
|
|
4049
|
-
* Normally this is returned from the backend as part of the hal-forms resource from a list endpoint.
|
|
4050
|
-
* For the editing capability, you must also set the apiName and the formArray.
|
|
4171
|
+
* Emitted after the resource has been deleted.
|
|
4051
4172
|
*/
|
|
4052
|
-
|
|
4053
|
-
filters = computed(() => {
|
|
4054
|
-
const filter = this.oDataParameters().$filter;
|
|
4055
|
-
const properties = this.searchTemplate()?.propertiesRecord;
|
|
4056
|
-
if (filter === null || filter === undefined || typeof filter !== "string" || properties === undefined)
|
|
4057
|
-
return {};
|
|
4058
|
-
return ODataService.createFilterMetadataFromODataFilter(filter, properties);
|
|
4059
|
-
}, ...(ngDevMode ? [{ debugName: "filters" }] : []));
|
|
4173
|
+
afterDelete = output();
|
|
4060
4174
|
/**
|
|
4061
|
-
*
|
|
4062
|
-
* Bind this to the form array that contains the form groups for the items.
|
|
4063
|
-
* Each entry in the array represents one row in the currently displayed page of the table.
|
|
4064
|
-
* For the editing capability, you must also set the apiName and the editTemplate.
|
|
4175
|
+
* Emitted after the form has been submitted.
|
|
4065
4176
|
*/
|
|
4066
|
-
|
|
4177
|
+
afterSubmit = output();
|
|
4067
4178
|
/**
|
|
4068
|
-
*
|
|
4069
|
-
|
|
4070
|
-
|
|
4071
|
-
headerMenu = input([], ...(ngDevMode ? [{ debugName: "headerMenu" }] : []));
|
|
4072
|
-
isEditable = computed(() => this.editTemplate() !== undefined && this.formArray() !== undefined && this.apiName() !== undefined, ...(ngDevMode ? [{ debugName: "isEditable" }] : []));
|
|
4179
|
+
* Determines whether to enable the delete button.
|
|
4180
|
+
*/
|
|
4181
|
+
allowDelete = input(true, ...(ngDevMode ? [{ debugName: "allowDelete" }] : []));
|
|
4073
4182
|
/**
|
|
4074
|
-
*
|
|
4075
|
-
|
|
4076
|
-
|
|
4077
|
-
isLoading = input(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
|
|
4183
|
+
* Determines whether to enable the reload button.
|
|
4184
|
+
*/
|
|
4185
|
+
allowReload = input(true, ...(ngDevMode ? [{ debugName: "allowReload" }] : []));
|
|
4078
4186
|
/**
|
|
4079
|
-
*
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
* The default is `true`.
|
|
4083
|
-
* @see load
|
|
4084
|
-
*/
|
|
4085
|
-
lazy = input(true, ...(ngDevMode ? [{ debugName: "lazy" }] : []));
|
|
4187
|
+
* Determines whether to enable the submit button.
|
|
4188
|
+
*/
|
|
4189
|
+
allowSubmit = input(true, ...(ngDevMode ? [{ debugName: "allowSubmit" }] : []));
|
|
4086
4190
|
/**
|
|
4087
|
-
*
|
|
4088
|
-
* If set to true, the table will display a paginator at the bottom.
|
|
4089
|
-
* If set to false, the table will not display a paginator and all rows will be displayed at once.
|
|
4090
|
-
* The default is `true`.
|
|
4091
|
-
* In order to customize the number of rows per page, you can set the `rowsPerPageOptions` property.
|
|
4092
|
-
* @see rowsPerPageOptions
|
|
4191
|
+
* The name of the API to use.
|
|
4093
4192
|
*/
|
|
4094
|
-
|
|
4095
|
-
multiSortMeta = computed(() => {
|
|
4096
|
-
const orderBy = this.oDataParameters().$orderby;
|
|
4097
|
-
if (orderBy === null || orderBy === undefined || typeof orderBy !== "string")
|
|
4098
|
-
return undefined;
|
|
4099
|
-
return orderBy
|
|
4100
|
-
.split(",")
|
|
4101
|
-
.map(o => o.trim())
|
|
4102
|
-
.filter(o => o !== "")
|
|
4103
|
-
.map(o => {
|
|
4104
|
-
const [field, order] = o.split(" ");
|
|
4105
|
-
const orderAsNumber = order?.toLowerCase() === "desc" ? -1 : 1;
|
|
4106
|
-
return { field: field, order: orderAsNumber };
|
|
4107
|
-
});
|
|
4108
|
-
}, ...(ngDevMode ? [{ debugName: "multiSortMeta" }] : []));
|
|
4109
|
-
oDataParameters = model({}, ...(ngDevMode ? [{ debugName: "oDataParameters" }] : []));
|
|
4110
|
-
reflectParametersInUrl = input(true, ...(ngDevMode ? [{ debugName: "reflectParametersInUrl" }] : []));
|
|
4193
|
+
apiName = input.required(...(ngDevMode ? [{ debugName: "apiName" }] : []));
|
|
4111
4194
|
/**
|
|
4112
|
-
*
|
|
4195
|
+
* Determines whether the resource can be deleted.
|
|
4113
4196
|
*/
|
|
4114
|
-
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
* @returns The menu for the row.
|
|
4123
|
-
* @see showRowMenuAsColumn
|
|
4124
|
-
* @see showRowMenuOnRightClick
|
|
4125
|
-
*/
|
|
4126
|
-
rowMenu = input(() => [], ...(ngDevMode ? [{ debugName: "rowMenu" }] : []));
|
|
4127
|
-
rowMenus = computed(() => {
|
|
4128
|
-
return this.showRowMenuAsColumn() ? this.rows().map(r => this.rowMenu()(r, false)) : [];
|
|
4129
|
-
}, ...(ngDevMode ? [{ debugName: "rowMenus" }] : []));
|
|
4197
|
+
canDelete = computed(() => this.allowDelete() &&
|
|
4198
|
+
this.template() !== undefined &&
|
|
4199
|
+
this.template().target !== undefined &&
|
|
4200
|
+
this.template().method == "PUT" &&
|
|
4201
|
+
this.formGroup() !== undefined &&
|
|
4202
|
+
this.formGroup()?.value.id !== undefined &&
|
|
4203
|
+
this.formGroup()?.value.timestamp !== undefined &&
|
|
4204
|
+
!this.isLoading(), ...(ngDevMode ? [{ debugName: "canDelete" }] : []));
|
|
4130
4205
|
/**
|
|
4131
|
-
*
|
|
4132
|
-
* @param row The row for which to return the style class.
|
|
4133
|
-
* @param rowIndex The index of the row on the currently displayed page.
|
|
4134
|
-
* @returns The style class for the row.
|
|
4206
|
+
* Determines whether the form can be reloaded.
|
|
4135
4207
|
*/
|
|
4136
|
-
|
|
4137
|
-
|
|
4208
|
+
canReload = computed(() => this.allowReload() &&
|
|
4209
|
+
this.template() !== undefined &&
|
|
4210
|
+
this.template().target !== undefined &&
|
|
4211
|
+
this.template().title !== undefined &&
|
|
4212
|
+
this.template().properties.some(p => p.name === "id" && p.value !== undefined && p.value !== null && p.value !== 0) &&
|
|
4213
|
+
!this.isLoading(), ...(ngDevMode ? [{ debugName: "canReload" }] : []));
|
|
4138
4214
|
/**
|
|
4139
|
-
*
|
|
4140
|
-
* Bind this to the items that are displayed as table rows.
|
|
4141
|
-
* Normally this is returned from the backend as part of the hal-forms resource from a list endpoint.
|
|
4215
|
+
* Determines whether the form can be submitted.
|
|
4142
4216
|
*/
|
|
4143
|
-
|
|
4144
|
-
|
|
4217
|
+
canSubmit = computed(() => this.allowSubmit() &&
|
|
4218
|
+
this.template() !== undefined &&
|
|
4219
|
+
this.template().target !== undefined &&
|
|
4220
|
+
!this.isLoading() &&
|
|
4221
|
+
this.formGroup() !== undefined, ...(ngDevMode ? [{ debugName: "canSubmit" }] : []));
|
|
4145
4222
|
/**
|
|
4146
|
-
* The
|
|
4147
|
-
* The default is the first element of rowsPerPageOptions.
|
|
4223
|
+
* The form group that represents the form.
|
|
4148
4224
|
*/
|
|
4149
|
-
|
|
4225
|
+
formGroup = computed(() => this._formService.createFormGroupFromTemplate(this.template()), ...(ngDevMode ? [{ debugName: "formGroup" }] : []));
|
|
4226
|
+
isLoading = signal(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
|
|
4150
4227
|
/**
|
|
4151
|
-
* The
|
|
4152
|
-
* The default is [10, 25, 50].
|
|
4228
|
+
* The rel of the form.
|
|
4153
4229
|
*/
|
|
4154
|
-
|
|
4230
|
+
rel = input.required(...(ngDevMode ? [{ debugName: "rel" }] : []));
|
|
4155
4231
|
/**
|
|
4156
|
-
*
|
|
4157
|
-
|
|
4158
|
-
|
|
4159
|
-
scrollHeight = input("flex", ...(ngDevMode ? [{ debugName: "scrollHeight" }] : []));
|
|
4232
|
+
* Determines whether to show the delete button.
|
|
4233
|
+
*/
|
|
4234
|
+
showDelete = input(true, ...(ngDevMode ? [{ debugName: "showDelete" }] : []));
|
|
4160
4235
|
/**
|
|
4161
|
-
*
|
|
4162
|
-
|
|
4163
|
-
|
|
4164
|
-
scrollable = input(true, ...(ngDevMode ? [{ debugName: "scrollable" }] : []));
|
|
4236
|
+
* Determines whether to show the reload button.
|
|
4237
|
+
*/
|
|
4238
|
+
showReload = input(true, ...(ngDevMode ? [{ debugName: "showReload" }] : []));
|
|
4165
4239
|
/**
|
|
4166
|
-
*
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
*/
|
|
4170
|
-
searchTemplate = input.required(...(ngDevMode ? [{ debugName: "searchTemplate" }] : []));
|
|
4240
|
+
* Determines whether to show the submit button.
|
|
4241
|
+
*/
|
|
4242
|
+
showSubmit = input(true, ...(ngDevMode ? [{ debugName: "showSubmit" }] : []));
|
|
4171
4243
|
/**
|
|
4172
|
-
* The
|
|
4244
|
+
* The template used to render the form.
|
|
4173
4245
|
*/
|
|
4174
|
-
|
|
4246
|
+
template = model.required(...(ngDevMode ? [{ debugName: "template" }] : []));
|
|
4175
4247
|
/**
|
|
4176
|
-
*
|
|
4177
|
-
* The default is `null` which means rows cannot be selected.
|
|
4248
|
+
* Emitted when the form value changes.
|
|
4178
4249
|
*/
|
|
4179
|
-
|
|
4180
|
-
showMenuColumn = computed(() => this.headerMenu().length > 0 || (this.showRowMenuAsColumn() && this.rowMenus().some(m => m.length > 0)), ...(ngDevMode ? [{ debugName: "showMenuColumn" }] : []));
|
|
4250
|
+
valueChanges = output();
|
|
4181
4251
|
/**
|
|
4182
|
-
*
|
|
4183
|
-
|
|
4184
|
-
|
|
4252
|
+
* A reference to a template that can be used to render custom buttons for the form.
|
|
4253
|
+
*/
|
|
4254
|
+
buttonsRef = contentChild('buttons', ...(ngDevMode ? [{ debugName: "buttonsRef" }] : []));
|
|
4185
4255
|
/**
|
|
4186
|
-
*
|
|
4187
|
-
|
|
4188
|
-
|
|
4256
|
+
* A reference to a template that can be used to render content before the default buttons.
|
|
4257
|
+
*/
|
|
4258
|
+
beforeButtonsRef = contentChild('beforeButtons', ...(ngDevMode ? [{ debugName: "beforeButtonsRef" }] : []));
|
|
4189
4259
|
/**
|
|
4190
|
-
*
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
styleClass = input("", ...(ngDevMode ? [{ debugName: "styleClass" }] : []));
|
|
4260
|
+
* A reference to a template that can be used to render content after the default buttons.
|
|
4261
|
+
*/
|
|
4262
|
+
afterButtonsRef = contentChild('afterButtons', ...(ngDevMode ? [{ debugName: "afterButtonsRef" }] : []));
|
|
4194
4263
|
/**
|
|
4195
|
-
*
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
.
|
|
4204
|
-
.
|
|
4205
|
-
.
|
|
4206
|
-
.
|
|
4207
|
-
|
|
4208
|
-
|
|
4209
|
-
|
|
4210
|
-
|
|
4211
|
-
|
|
4212
|
-
|
|
4213
|
-
text: [TranslationKeys.NO_FILTER, ...primeNGConfig.filterMatchModeOptions.text].map(o => ({ label: primeNGConfig.getTranslation(o), value: o })),
|
|
4214
|
-
numeric: [TranslationKeys.NO_FILTER, ...primeNGConfig.filterMatchModeOptions.numeric].map(o => ({ label: primeNGConfig.getTranslation(o), value: o })),
|
|
4215
|
-
date: [TranslationKeys.NO_FILTER, ...primeNGConfig.filterMatchModeOptions.date].map(o => ({ label: primeNGConfig.getTranslation(o), value: o })),
|
|
4216
|
-
boolean: [TranslationKeys.NO_FILTER, TranslationKeys.EQUALS, TranslationKeys.NOT_EQUALS].map(o => ({ label: primeNGConfig.getTranslation(o), value: o })),
|
|
4217
|
-
enum: [TranslationKeys.NO_FILTER, TranslationKeys.EQUALS, TranslationKeys.NOT_EQUALS].map(o => ({ label: primeNGConfig.getTranslation(o), value: o })),
|
|
4218
|
-
};
|
|
4219
|
-
// Update the form array on changes
|
|
4220
|
-
effect(() => {
|
|
4221
|
-
const formArray = this.formArray();
|
|
4222
|
-
const editTemplate = this.editTemplate();
|
|
4223
|
-
const rows = this.rows();
|
|
4224
|
-
if (!this.isEditable() || !formArray || !editTemplate)
|
|
4225
|
-
return;
|
|
4226
|
-
formArray.clear();
|
|
4227
|
-
const newControls = rows
|
|
4228
|
-
.map(r => {
|
|
4229
|
-
const formGroup = this._formService.createFormGroupFromTemplate(editTemplate);
|
|
4230
|
-
formGroup.patchValue(r);
|
|
4231
|
-
return formGroup;
|
|
4232
|
-
});
|
|
4233
|
-
for (const control of newControls)
|
|
4234
|
-
formArray.push(control);
|
|
4235
|
-
});
|
|
4236
|
-
// update the url when the oDataParameters change
|
|
4237
|
-
effect(async () => {
|
|
4238
|
-
if (!this.reflectParametersInUrl())
|
|
4239
|
-
return;
|
|
4240
|
-
const urlParameterPrefix = this.urlParameterPrefix();
|
|
4241
|
-
const oDataParameters = this.oDataParameters();
|
|
4242
|
-
// Set the initial query parameters on the first change
|
|
4243
|
-
if (!this._initialQueryParamsSet) {
|
|
4244
|
-
this._initialQueryParamsSet = true;
|
|
4245
|
-
const oDataParametersFromUrl = ODataService.createParametersFromRoute(activatedRoute, urlParameterPrefix);
|
|
4246
|
-
const mergedParameters = { ...oDataParameters, ...oDataParametersFromUrl };
|
|
4247
|
-
this.oDataParameters.set(mergedParameters);
|
|
4248
|
-
return;
|
|
4249
|
-
}
|
|
4250
|
-
// Update the query parameters in the url after the first change
|
|
4251
|
-
const parameters = this.prefixObjectProperties(oDataParameters, urlParameterPrefix);
|
|
4252
|
-
await router.navigate([], { queryParams: parameters, queryParamsHandling: 'merge' });
|
|
4264
|
+
* A reference to a template that can be used to render custom content inside the <form> element instead of the default form.
|
|
4265
|
+
*/
|
|
4266
|
+
contentRef = contentChild('content', ...(ngDevMode ? [{ debugName: "contentRef" }] : []));
|
|
4267
|
+
_client = computed(() => this._clients.getClient(this.apiName()), ...(ngDevMode ? [{ debugName: "_client" }] : []));
|
|
4268
|
+
_formValueChangesSubscription;
|
|
4269
|
+
constructor(_clients, _confirmationService, _messageService, _formService, _elementRef, _problemService) {
|
|
4270
|
+
this._clients = _clients;
|
|
4271
|
+
this._confirmationService = _confirmationService;
|
|
4272
|
+
this._messageService = _messageService;
|
|
4273
|
+
this._formService = _formService;
|
|
4274
|
+
this._elementRef = _elementRef;
|
|
4275
|
+
this._problemService = _problemService;
|
|
4276
|
+
// Update the form value changes subscription to always track the current form group.
|
|
4277
|
+
effect(() => {
|
|
4278
|
+
this._formValueChangesSubscription?.unsubscribe();
|
|
4279
|
+
const formGroup = this.formGroup();
|
|
4280
|
+
this._formValueChangesSubscription = formGroup?.valueChanges.subscribe(newValue => this.valueChanges.emit(newValue));
|
|
4281
|
+
this.valueChanges.emit(formGroup?.value);
|
|
4253
4282
|
});
|
|
4254
4283
|
}
|
|
4255
|
-
|
|
4256
|
-
this.
|
|
4257
|
-
// this.multiSortMeta = event.multiSortMeta;
|
|
4258
|
-
const currentParameters = this.oDataParameters();
|
|
4259
|
-
const searchTemplate = this.searchTemplate();
|
|
4260
|
-
if (!searchTemplate || searchTemplate.properties.length === 0)
|
|
4261
|
-
return;
|
|
4262
|
-
const parameters = ODataService.createParametersFromTableLoadEvent(event, searchTemplate);
|
|
4263
|
-
ODataService.createFilterMetadataFromODataFilter(parameters.$filter, searchTemplate.propertiesRecord);
|
|
4264
|
-
if (currentParameters.$filter !== parameters.$filter || currentParameters.$orderby !== parameters.$orderby || currentParameters.$top !== parameters.$top || currentParameters.$skip !== parameters.$skip)
|
|
4265
|
-
this.oDataParameters.set(parameters);
|
|
4266
|
-
}
|
|
4267
|
-
openContextMenu(event, row) {
|
|
4268
|
-
const contextMenu = this.contextMenu();
|
|
4269
|
-
if (!this.showRowMenuOnRightClick() || contextMenu === undefined)
|
|
4284
|
+
async delete() {
|
|
4285
|
+
if (!this.canDelete())
|
|
4270
4286
|
return;
|
|
4271
|
-
this.
|
|
4272
|
-
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
|
|
4276
|
-
|
|
4277
|
-
|
|
4278
|
-
const
|
|
4279
|
-
|
|
4280
|
-
|
|
4281
|
-
|
|
4282
|
-
if (!property)
|
|
4283
|
-
return ColumnFilterType.text;
|
|
4284
|
-
const propertyType = property.type;
|
|
4285
|
-
switch (propertyType) {
|
|
4286
|
-
case PropertyType.Number:
|
|
4287
|
-
case PropertyType.Percent:
|
|
4288
|
-
case PropertyType.Currency:
|
|
4289
|
-
case PropertyType.Month:
|
|
4290
|
-
return ColumnFilterType.numeric;
|
|
4291
|
-
case PropertyType.Bool:
|
|
4292
|
-
return ColumnFilterType.boolean;
|
|
4293
|
-
case PropertyType.Date:
|
|
4294
|
-
case PropertyType.DatetimeLocal:
|
|
4295
|
-
case PropertyType.DatetimeOffset:
|
|
4296
|
-
return ColumnFilterType.date;
|
|
4297
|
-
default:
|
|
4298
|
-
return property.options ? property.options.link ? ColumnFilterType.numeric : ColumnFilterType.enum : ColumnFilterType.text;
|
|
4299
|
-
}
|
|
4300
|
-
}
|
|
4301
|
-
toMatchModeOptions(property) {
|
|
4302
|
-
const columnFilterType = this.toColumnFilterType(property);
|
|
4303
|
-
return this._filterMatchModeOptions[columnFilterType];
|
|
4304
|
-
}
|
|
4305
|
-
toMaxFractionDigits(property) {
|
|
4306
|
-
switch (property.type) {
|
|
4307
|
-
case PropertyType.Number:
|
|
4308
|
-
case PropertyType.Percent:
|
|
4309
|
-
case PropertyType.Currency:
|
|
4310
|
-
return property.step?.toString().split(".")[1]?.length ?? 2;
|
|
4311
|
-
case PropertyType.Month:
|
|
4312
|
-
return 0;
|
|
4313
|
-
default:
|
|
4314
|
-
return undefined;
|
|
4287
|
+
const formGroup = this.formGroup();
|
|
4288
|
+
if (formGroup === undefined)
|
|
4289
|
+
throw new Error("formGroup cannot be undefined.");
|
|
4290
|
+
const template = this.template();
|
|
4291
|
+
if (template === undefined)
|
|
4292
|
+
throw new Error("template cannot be undefined.");
|
|
4293
|
+
// canDelete already checks that the timestamp is present, so the cast is safe.
|
|
4294
|
+
const result = await this._client().deleteByTemplateAndForm(template, formGroup);
|
|
4295
|
+
if (this._problemService.checkResponseAndDisplayErrors(result, formGroup)) {
|
|
4296
|
+
this._messageService.add({ severity: 'success', summary: 'Deleted', detail: 'The resource has been deleted.' });
|
|
4297
|
+
this.afterDelete.emit();
|
|
4315
4298
|
}
|
|
4316
4299
|
}
|
|
4317
|
-
|
|
4318
|
-
|
|
4300
|
+
async reload() {
|
|
4301
|
+
const canReload = this.canReload();
|
|
4302
|
+
const template = this.template();
|
|
4303
|
+
if (!canReload || template === undefined)
|
|
4319
4304
|
return;
|
|
4320
|
-
|
|
4321
|
-
|
|
4322
|
-
|
|
4323
|
-
|
|
4324
|
-
|
|
4325
|
-
|
|
4305
|
+
this.isLoading.set(true);
|
|
4306
|
+
try {
|
|
4307
|
+
const response = await this._client().getForm(template.target);
|
|
4308
|
+
if (this._problemService.checkResponseAndDisplayErrors(response, this.formGroup())) {
|
|
4309
|
+
this.template.set(response.body.getTemplateByTitle(template.title));
|
|
4310
|
+
}
|
|
4326
4311
|
}
|
|
4327
|
-
|
|
4328
|
-
(
|
|
4329
|
-
|
|
4330
|
-
// The user entered a value into the filter, but forgot to change the mode
|
|
4331
|
-
// => We set the match mode to the default for the type that is not no filter
|
|
4332
|
-
filterEntry.matchMode = this._filterMatchModeOptions[this.toColumnFilterType(this.searchTemplate().propertiesRecord[propertyName])][1].value;
|
|
4312
|
+
catch (e) {
|
|
4313
|
+
this._messageService.add({ severity: 'error', summary: 'Error', detail: `An unknown error occurred. ${JSON.stringify(e)}`, sticky: true });
|
|
4314
|
+
console.log(e);
|
|
4333
4315
|
}
|
|
4316
|
+
this.isLoading.set(false);
|
|
4334
4317
|
}
|
|
4335
|
-
|
|
4336
|
-
|
|
4318
|
+
showDeleteConfirmatioModal() {
|
|
4319
|
+
this._confirmationService.confirm({
|
|
4320
|
+
message: 'Do you really want to delete this resource?',
|
|
4321
|
+
header: 'Confirm delete',
|
|
4322
|
+
icon: 'far fa-trash-alt',
|
|
4323
|
+
accept: () => this.delete()
|
|
4324
|
+
});
|
|
4325
|
+
}
|
|
4326
|
+
async submit() {
|
|
4327
|
+
const formGroup = this.formGroup();
|
|
4328
|
+
const template = this.template();
|
|
4329
|
+
if (formGroup !== undefined) {
|
|
4330
|
+
formGroup.markAllAsTouched();
|
|
4331
|
+
if (!formGroup.valid) {
|
|
4332
|
+
this._messageService.add({
|
|
4333
|
+
severity: 'error',
|
|
4334
|
+
summary: 'Error',
|
|
4335
|
+
detail: 'Please correct the errors before submitting.',
|
|
4336
|
+
});
|
|
4337
|
+
ProblemService.scrollToFirstValidationError(this._elementRef.nativeElement);
|
|
4338
|
+
return;
|
|
4339
|
+
}
|
|
4340
|
+
}
|
|
4341
|
+
if (!this.canSubmit() || formGroup === undefined || template === undefined)
|
|
4337
4342
|
return;
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4343
|
+
this.isLoading.set(true);
|
|
4344
|
+
try {
|
|
4345
|
+
const response = await this._client().submit(template, formGroup.value);
|
|
4346
|
+
if (!this._problemService.checkResponseAndDisplayErrors(response, formGroup, "Error while saving the resource")) {
|
|
4347
|
+
}
|
|
4348
|
+
else if (response.status == 201) {
|
|
4349
|
+
if (!response.headers.has('Location')) {
|
|
4350
|
+
this._messageService.add({ severity: 'error', summary: 'Error', detail: 'The server returned a 201 Created response, but did not return a Location header.', data: response, sticky: true });
|
|
4351
|
+
return;
|
|
4352
|
+
}
|
|
4353
|
+
this._messageService.add({ severity: 'success', summary: 'Created', detail: 'The resource has been created.' });
|
|
4354
|
+
var createdAtUri = response.headers.get('Location');
|
|
4355
|
+
this.afterSubmit.emit({ location: createdAtUri, status: 201 });
|
|
4342
4356
|
}
|
|
4343
4357
|
else {
|
|
4344
|
-
|
|
4358
|
+
const responseResource = response.body;
|
|
4359
|
+
const newTemplate = responseResource.getTemplateByTitle(template.title);
|
|
4360
|
+
this.template.set(newTemplate);
|
|
4361
|
+
this._messageService.add({ severity: 'success', summary: 'Saved', detail: 'The resource has been saved.' });
|
|
4362
|
+
this.afterSubmit.emit({ old: template, new: newTemplate, status: 200 });
|
|
4345
4363
|
}
|
|
4346
|
-
}
|
|
4347
|
-
|
|
4364
|
+
}
|
|
4365
|
+
catch (e) {
|
|
4366
|
+
this._messageService.add({ severity: 'error', summary: 'Error', detail: `An unknown error occurred. ${JSON.stringify(e)}`, sticky: true });
|
|
4367
|
+
console.log(e);
|
|
4368
|
+
}
|
|
4369
|
+
this.isLoading.set(false);
|
|
4348
4370
|
}
|
|
4349
|
-
|
|
4350
|
-
|
|
4371
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: RestWorldFormComponent, deps: [{ token: RestWorldClientCollection }, { token: i2$1.ConfirmationService }, { token: i2$1.MessageService }, { token: i1$1.FormService }, { token: i0.ElementRef }, { token: ProblemService }], target: i0.ɵɵFactoryTarget.Component });
|
|
4372
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.1", type: RestWorldFormComponent, isStandalone: true, selector: "rw-form", inputs: { allowDelete: { classPropertyName: "allowDelete", publicName: "allowDelete", isSignal: true, isRequired: false, transformFunction: null }, allowReload: { classPropertyName: "allowReload", publicName: "allowReload", isSignal: true, isRequired: false, transformFunction: null }, allowSubmit: { classPropertyName: "allowSubmit", publicName: "allowSubmit", isSignal: true, isRequired: false, transformFunction: null }, apiName: { classPropertyName: "apiName", publicName: "apiName", isSignal: true, isRequired: true, transformFunction: null }, rel: { classPropertyName: "rel", publicName: "rel", isSignal: true, isRequired: true, transformFunction: null }, showDelete: { classPropertyName: "showDelete", publicName: "showDelete", isSignal: true, isRequired: false, transformFunction: null }, showReload: { classPropertyName: "showReload", publicName: "showReload", isSignal: true, isRequired: false, transformFunction: null }, showSubmit: { classPropertyName: "showSubmit", publicName: "showSubmit", isSignal: true, isRequired: false, transformFunction: null }, template: { classPropertyName: "template", publicName: "template", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { afterDelete: "afterDelete", afterSubmit: "afterSubmit", template: "templateChange", valueChanges: "valueChanges" }, queries: [{ propertyName: "buttonsRef", first: true, predicate: ["buttons"], descendants: true, isSignal: true }, { propertyName: "beforeButtonsRef", first: true, predicate: ["beforeButtons"], descendants: true, isSignal: true }, { propertyName: "afterButtonsRef", first: true, predicate: ["afterButtons"], descendants: true, isSignal: true }, { propertyName: "contentRef", first: true, predicate: ["content"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (formGroup() !== undefined && template() !== undefined) {\n <form [formGroup]=\"formGroup()\" (ngSubmit)=\"submit()\">\n <div class=\"blockable-container\">\n <div class=\"blockable-element\">\n <div class=\"grid field\">\n <div class=\"col-12 md:col-10 md:col-offset-2\">\n <rw-validation-errors [form]=\"formGroup()\"></rw-validation-errors>\n </div>\n </div>\n <ng-template #defaultContent>\n <rw-input-template [template]=\"template()\" [apiName]=\"apiName()\"></rw-input-template>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"contentRef() ?? defaultContent; context: { form: formGroup, template: template, apiName: apiName() }\"></ng-container>\n </div>\n @if (isLoading()) {\n <div class=\"blockable-overlay\">\n <p-progressSpinner></p-progressSpinner>\n </div>\n }\n </div>\n\n <div class=\"grid\">\n <div class=\"col\">\n <div class=\"flex justify-content-end w-full\">\n <ng-template #defaultButtons>\n @if (beforeButtonsRef(); as beforeButtons) {\n <ng-container\n *ngTemplateOutlet=\"beforeButtons; context: { form: formGroup, template: template, apiName: apiName() }\"></ng-container>\n }\n <button pButton pRipple type=\"submit\" label=\"Save\" icon=\"far fa-save\" class=\"mx-2 p-button-success\"\n [disabled]=\"!allowSubmit()\"></button>\n <button pButton pRipple type=\"button\" label=\"Reload\" icon=\"fas fa-redo\" class=\"mx-2 p-button-info\"\n (click)=\"reload()\" [disabled]=\"!canReload()\"></button>\n <button pButton pRipple type=\"button\" label=\"Delete\" icon=\"far fa-trash-alt\"\n class=\"ml-2 p-button-danger\" (click)=\"showDeleteConfirmatioModal()\"\n [disabled]=\"!canDelete()\"></button>\n @if (afterButtonsRef(); as afterButtons) {\n <ng-container\n *ngTemplateOutlet=\"afterButtons; context: { form: formGroup, template: template, apiName: apiName() }\"></ng-container>\n }\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"buttonsRef() ?? defaultButtons; context: { form: formGroup, template: template, apiName: apiName() }\"></ng-container>\n </div>\n </div>\n </div>\n </form>\n}\n", styles: [".blockable-container{display:grid;place-items:center;grid-template-areas:\"inner\"}.blockable-element{grid-area:inner;width:100%}.blockable-overlay{grid-area:inner;height:100%;width:100%;background-color:#0006;display:flex;align-items:center;justify-content:center;z-index:1}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2$3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2$3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2$3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: RestWorldValidationErrorsComponent, selector: "rw-validation-errors", inputs: ["form", "property"] }, { kind: "component", type: RestWorldInputTemplateComponent, selector: "rw-input-template", inputs: ["apiName", "template"] }, { kind: "ngmodule", type: ProgressSpinnerModule }, { kind: "component", type: i6$1.ProgressSpinner, selector: "p-progressSpinner, p-progress-spinner, p-progressspinner", inputs: ["styleClass", "strokeWidth", "fill", "animationDuration", "ariaLabel"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i1$3.ButtonDirective, selector: "[pButton]", inputs: ["iconPos", "loadingIcon", "loading", "severity", "raised", "rounded", "text", "outlined", "size", "plain", "fluid", "label", "icon", "buttonProps"] }, { kind: "ngmodule", type: RippleModule }, { kind: "directive", type: i8.Ripple, selector: "[pRipple]" }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
|
|
4373
|
+
}
|
|
4374
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: RestWorldFormComponent, decorators: [{
|
|
4375
|
+
type: Component,
|
|
4376
|
+
args: [{ selector: 'rw-form', standalone: true, imports: [ReactiveFormsModule, RestWorldValidationErrorsComponent, RestWorldInputTemplateComponent, ProgressSpinnerModule, ButtonModule, RippleModule, NgTemplateOutlet], template: "@if (formGroup() !== undefined && template() !== undefined) {\n <form [formGroup]=\"formGroup()\" (ngSubmit)=\"submit()\">\n <div class=\"blockable-container\">\n <div class=\"blockable-element\">\n <div class=\"grid field\">\n <div class=\"col-12 md:col-10 md:col-offset-2\">\n <rw-validation-errors [form]=\"formGroup()\"></rw-validation-errors>\n </div>\n </div>\n <ng-template #defaultContent>\n <rw-input-template [template]=\"template()\" [apiName]=\"apiName()\"></rw-input-template>\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"contentRef() ?? defaultContent; context: { form: formGroup, template: template, apiName: apiName() }\"></ng-container>\n </div>\n @if (isLoading()) {\n <div class=\"blockable-overlay\">\n <p-progressSpinner></p-progressSpinner>\n </div>\n }\n </div>\n\n <div class=\"grid\">\n <div class=\"col\">\n <div class=\"flex justify-content-end w-full\">\n <ng-template #defaultButtons>\n @if (beforeButtonsRef(); as beforeButtons) {\n <ng-container\n *ngTemplateOutlet=\"beforeButtons; context: { form: formGroup, template: template, apiName: apiName() }\"></ng-container>\n }\n <button pButton pRipple type=\"submit\" label=\"Save\" icon=\"far fa-save\" class=\"mx-2 p-button-success\"\n [disabled]=\"!allowSubmit()\"></button>\n <button pButton pRipple type=\"button\" label=\"Reload\" icon=\"fas fa-redo\" class=\"mx-2 p-button-info\"\n (click)=\"reload()\" [disabled]=\"!canReload()\"></button>\n <button pButton pRipple type=\"button\" label=\"Delete\" icon=\"far fa-trash-alt\"\n class=\"ml-2 p-button-danger\" (click)=\"showDeleteConfirmatioModal()\"\n [disabled]=\"!canDelete()\"></button>\n @if (afterButtonsRef(); as afterButtons) {\n <ng-container\n *ngTemplateOutlet=\"afterButtons; context: { form: formGroup, template: template, apiName: apiName() }\"></ng-container>\n }\n </ng-template>\n <ng-container\n *ngTemplateOutlet=\"buttonsRef() ?? defaultButtons; context: { form: formGroup, template: template, apiName: apiName() }\"></ng-container>\n </div>\n </div>\n </div>\n </form>\n}\n", styles: [".blockable-container{display:grid;place-items:center;grid-template-areas:\"inner\"}.blockable-element{grid-area:inner;width:100%}.blockable-overlay{grid-area:inner;height:100%;width:100%;background-color:#0006;display:flex;align-items:center;justify-content:center;z-index:1}\n"] }]
|
|
4377
|
+
}], ctorParameters: () => [{ type: RestWorldClientCollection }, { type: i2$1.ConfirmationService }, { type: i2$1.MessageService }, { type: i1$1.FormService }, { type: i0.ElementRef }, { type: ProblemService }] });
|
|
4378
|
+
|
|
4379
|
+
/**
|
|
4380
|
+
* Component for navigating to a resource by its ID.
|
|
4381
|
+
*
|
|
4382
|
+
* @remarks
|
|
4383
|
+
* This component is used to navigate to a resource by its ID. It takes in the API name, the `rel` of the resource, and an optional `urlPrefix` to use for the URL that is returned from the backend. It also provides a form for entering the ID of the resource to navigate to.
|
|
4384
|
+
*/
|
|
4385
|
+
class RestWorldIdNavigationComponent {
|
|
4386
|
+
_clients;
|
|
4387
|
+
_messageService;
|
|
4388
|
+
_router;
|
|
4389
|
+
_route;
|
|
4390
|
+
apiName = input.required(...(ngDevMode ? [{ debugName: "apiName" }] : []));
|
|
4391
|
+
rel = input.required(...(ngDevMode ? [{ debugName: "rel" }] : []));
|
|
4392
|
+
/**
|
|
4393
|
+
* A prefix to use for the URL that is returned from the backend.
|
|
4394
|
+
* If none is provided, a relative navigation will be performed which means that the last part of the current URL is replaced with the one from the backend.
|
|
4395
|
+
*/
|
|
4396
|
+
urlPrefix = input(...(ngDevMode ? [undefined, { debugName: "urlPrefix" }] : []));
|
|
4397
|
+
idNavigationForm = new FormGroup({
|
|
4398
|
+
id: new FormControl(null, Validators.compose([Validators.min(1), Validators.max(Number.MAX_SAFE_INTEGER)]))
|
|
4399
|
+
});
|
|
4400
|
+
_client = computed(() => this._clients.getClient(this.apiName()), ...(ngDevMode ? [{ debugName: "_client" }] : []));
|
|
4401
|
+
constructor(_clients, _messageService, _router, _route) {
|
|
4402
|
+
this._clients = _clients;
|
|
4403
|
+
this._messageService = _messageService;
|
|
4404
|
+
this._router = _router;
|
|
4405
|
+
this._route = _route;
|
|
4351
4406
|
}
|
|
4352
|
-
|
|
4353
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.1", type: RestWorldTableComponent, isStandalone: true, selector: "rw-table", inputs: { apiName: { classPropertyName: "apiName", publicName: "apiName", isSignal: true, isRequired: true, transformFunction: null }, cellStyleClass: { classPropertyName: "cellStyleClass", publicName: "cellStyleClass", isSignal: true, isRequired: false, transformFunction: null }, editTemplate: { classPropertyName: "editTemplate", publicName: "editTemplate", isSignal: true, isRequired: false, transformFunction: null }, headerMenu: { classPropertyName: "headerMenu", publicName: "headerMenu", isSignal: true, isRequired: false, transformFunction: null }, isLoading: { classPropertyName: "isLoading", publicName: "isLoading", isSignal: true, isRequired: false, transformFunction: null }, lazy: { classPropertyName: "lazy", publicName: "lazy", isSignal: true, isRequired: false, transformFunction: null }, paginator: { classPropertyName: "paginator", publicName: "paginator", isSignal: true, isRequired: false, transformFunction: null }, oDataParameters: { classPropertyName: "oDataParameters", publicName: "oDataParameters", isSignal: true, isRequired: false, transformFunction: null }, reflectParametersInUrl: { classPropertyName: "reflectParametersInUrl", publicName: "reflectParametersInUrl", isSignal: true, isRequired: false, transformFunction: null }, rowHover: { classPropertyName: "rowHover", publicName: "rowHover", isSignal: true, isRequired: false, transformFunction: null }, rowMenu: { classPropertyName: "rowMenu", publicName: "rowMenu", isSignal: true, isRequired: false, transformFunction: null }, rowStyleClass: { classPropertyName: "rowStyleClass", publicName: "rowStyleClass", isSignal: true, isRequired: false, transformFunction: null }, rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: true, transformFunction: null }, rowsPerPageOptions: { classPropertyName: "rowsPerPageOptions", publicName: "rowsPerPageOptions", isSignal: true, isRequired: false, transformFunction: null }, scrollHeight: { classPropertyName: "scrollHeight", publicName: "scrollHeight", isSignal: true, isRequired: false, transformFunction: null }, scrollable: { classPropertyName: "scrollable", publicName: "scrollable", isSignal: true, isRequired: false, transformFunction: null }, searchTemplate: { classPropertyName: "searchTemplate", publicName: "searchTemplate", isSignal: true, isRequired: true, transformFunction: null }, selectedRows: { classPropertyName: "selectedRows", publicName: "selectedRows", isSignal: true, isRequired: false, transformFunction: null }, selectionMode: { classPropertyName: "selectionMode", publicName: "selectionMode", isSignal: true, isRequired: false, transformFunction: null }, showRowMenuAsColumn: { classPropertyName: "showRowMenuAsColumn", publicName: "showRowMenuAsColumn", isSignal: true, isRequired: false, transformFunction: null }, showRowMenuOnRightClick: { classPropertyName: "showRowMenuOnRightClick", publicName: "showRowMenuOnRightClick", isSignal: true, isRequired: false, transformFunction: null }, styleClass: { classPropertyName: "styleClass", publicName: "styleClass", isSignal: true, isRequired: false, transformFunction: null }, tableStyle: { classPropertyName: "tableStyle", publicName: "tableStyle", isSignal: true, isRequired: false, transformFunction: null }, totalRecords: { classPropertyName: "totalRecords", publicName: "totalRecords", isSignal: true, isRequired: false, transformFunction: null }, urlParameterPrefix: { classPropertyName: "urlParameterPrefix", publicName: "urlParameterPrefix", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { oDataParameters: "oDataParametersChange", selectedRows: "selectedRowsChange" }, viewQueries: [{ propertyName: "contextMenu", first: true, predicate: ["contextMenu"], descendants: true, isSignal: true }], ngImport: i0, template: "<p-table\r\n #table\r\n [value]=\"rows()\"\r\n [columns]=\"columns()\"\r\n [lazy]=\"lazy()\"\r\n [lazyLoadOnInit]=\"false\"\r\n (onLazyLoad)=\"load($event)\"\r\n responsiveLayout=\"scroll\"\r\n [paginator]=\"paginator()\"\r\n [rowsPerPageOptions]=\"rowsPerPageOptions()\"\r\n [rows]=\"rowsPerPage()\"\r\n [totalRecords]=\"totalRecords()\"\r\n [loading]=\"isLoading()\"\r\n sortMode=\"multiple\"\r\n [multiSortMeta]=\"multiSortMeta()\"\r\n [styleClass]=\"styleClass()\"\r\n [tableStyle]=\"tableStyle()\"\r\n [scrollable]=\"scrollable()\"\r\n [scrollHeight]=\"scrollHeight()\"\r\n [selectionMode]=\"selectionMode()\"\r\n [rowHover]=\"rowHover()\"\r\n [(selection)]=\"selectedRows\"\r\n [filters]=\"$any(filters())\"\r\n [first]=\"rowsBeforeCurrentPage()\"\r\n >\r\n\r\n <ng-template pTemplate=\"header\" let-columns>\r\n <tr>\r\n @for (col of columns; track col) {\r\n <th [pSortableColumn]=\"col.name\">\r\n <div class=\"p-d-flex p-jc-between p-ai-center gap-1\">\r\n {{col.prompt}}\r\n @if(!col.readOnly) {\r\n <p-sortIcon [field]=\"col.name\"></p-sortIcon>\r\n <p-columnFilter #f\r\n [type]=\"toColumnFilterType(col.type)\"\r\n [maxFractionDigits]=\"toMaxFractionDigits(col)\"\r\n matchMode=\"noFilter\"\r\n [matchModeOptions]=\"toMatchModeOptions(col)\"\r\n [showMatchModes]=\"true\"\r\n [field]=\"col.name\"\r\n display=\"menu\"\r\n [maxConstraints]=\"100\"\r\n [class.has-filter]=\"f.hasFilter\">\r\n <ng-template #filter let-value let-filterConstraint=\"filterConstraint\" let-field=\"field\">\r\n <rw-table-column-filter-element [property]=\"col\" [value]=\"value\" [apiName]=\"apiName()\" [filterConstraint]=\"filterConstraint\"></rw-table-column-filter-element>\r\n </ng-template>\r\n </p-columnFilter>\r\n }\r\n </div>\r\n </th>\r\n }\r\n @if (showMenuColumn()) {\r\n <th>\r\n <rw-menu-button [items]=\"headerMenu()\"></rw-menu-button>\r\n </th>\r\n }\r\n </tr>\r\n </ng-template>\r\n\r\n <ng-template pTemplate=\"body\" let-entity let-columns=\"columns\" let-rowIndex=\"rowIndex\">\r\n <tr (contextmenu)=\"openContextMenu($event, entity)\" [pSelectableRow]=\"entity\" [pSelectableRowDisabled]=\"selectionMode() === null\" [className]=\"rowStyleClasses()[rowIndex - (table.first ?? 0)]\">\r\n @for (col of columns; track col) {\r\n <td [className]=\"cellStyleClasses()[rowIndex - (table.first ?? 0)][col.name]\">\r\n @let fomrArray = formArray();\r\n @if (showInputField(col) && fomrArray) {\r\n <ng-container [formGroup]=\"fomrArray.controls[rowIndex - (table.first ?? 0)]\" >\r\n <rw-input [apiName]=\"apiName()\" [property]=\"editProperties()[col.name]!\"></rw-input>\r\n </ng-container>\r\n }\r\n @else {\r\n <rw-display [property]=\"col\" [value]=\"entity[col.name]\" [apiName]=\"apiName()!\"></rw-display>\r\n }\r\n </td>\r\n }\r\n @if (showMenuColumn()) {\r\n <td>\r\n @if (showRowMenuAsColumn()) {\r\n <rw-menu-button [items]=\"rowMenus()[rowIndex - (table.first ?? 0)]\"></rw-menu-button>\r\n }\r\n </td>\r\n }\r\n </tr>\r\n </ng-template>\r\n</p-table>\r\n\r\n<p-contextMenu #contextMenu appendTo=\"body\" [model]=\"contextMenuItems()\"></p-contextMenu>\r\n", styles: [".p-tooltip{max-width:fit-content}a.p-button{text-decoration:none}::ng-deep rw-table rw-label.md\\:col-2{width:100%;font-weight:600}::ng-deep rw-table .p-d-flex{display:flex}::ng-deep rw-table .p-ai-center{align-items:center}::ng-deep rw-table .has-filter filtericon{color:var(--p-datatable-header-cell-selected-color)}::ng-deep rw-table p-columnfilter .p-datatable-column-filter-button{width:unset;height:23px!important;padding-block-end:0;padding-block-start:0}\n"], dependencies: [{ kind: "ngmodule", type: TableModule }, { kind: "component", type: i5.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "styleClass", "tableStyle", "tableStyleClass", "paginator", "pageLinks", "rowsPerPageOptions", "alwaysShowPaginator", "paginatorPosition", "paginatorStyleClass", "paginatorDropdownAppendTo", "paginatorDropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showJumpToPageDropdown", "showJumpToPageInput", "showFirstLastIcon", "showPageLinks", "defaultSortOrder", "sortMode", "resetPageOnSort", "selectionMode", "selectionPageOnly", "contextMenuSelection", "contextMenuSelectionMode", "dataKey", "metaKeySelection", "rowSelectable", "rowTrackBy", "lazy", "lazyLoadOnInit", "compareSelectionBy", "csvSeparator", "exportFilename", "filters", "globalFilterFields", "filterDelay", "filterLocale", "expandedRowKeys", "editingRowKeys", "rowExpandMode", "scrollable", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "size", "showGridlines", "stripedRows", "groupRowsByOrder", "responsiveLayout", "breakpoint", "paginatorLocale", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "selectAll"], outputs: ["contextMenuSelectionChange", "selectAllChange", "selectionChange", "onRowSelect", "onRowUnselect", "onPage", "onSort", "onFilter", "onLazyLoad", "onRowExpand", "onRowCollapse", "onContextMenuSelect", "onColResize", "onColReorder", "onRowReorder", "onEditInit", "onEditComplete", "onEditCancel", "onHeaderCheckboxToggle", "sortFunction", "firstChange", "rowsChange", "onStateSave", "onStateRestore"] }, { kind: "directive", type: i2$1.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "directive", type: i5.SortableColumn, selector: "[pSortableColumn]", inputs: ["pSortableColumn", "pSortableColumnDisabled"] }, { kind: "directive", type: i5.SelectableRow, selector: "[pSelectableRow]", inputs: ["pSelectableRow", "pSelectableRowIndex", "pSelectableRowDisabled"] }, { kind: "component", type: i5.SortIcon, selector: "p-sortIcon", inputs: ["field"] }, { kind: "component", type: i5.ColumnFilter, selector: "p-columnFilter, p-column-filter, p-columnfilter", inputs: ["field", "type", "display", "showMenu", "matchMode", "operator", "showOperator", "showClearButton", "showApplyButton", "showMatchModes", "showAddButton", "hideOnClear", "placeholder", "matchModeOptions", "maxConstraints", "minFractionDigits", "maxFractionDigits", "prefix", "suffix", "locale", "localeMatcher", "currency", "currencyDisplay", "filterOn", "useGrouping", "showButtons", "ariaLabel", "filterButtonProps"], outputs: ["onShow", "onHide"] }, { kind: "component", type: RestWorldMenuButtonComponent, selector: "rw-menu-button", inputs: ["items"] }, { kind: "component", type: RestWorldInputComponent, selector: "rw-input" }, { kind: "component", type: RestWorldDisplayComponent, selector: "rw-display", inputs: ["apiName", "property", "value"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2$3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2$3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: ContextMenuModule }, { kind: "component", type: i7.ContextMenu, selector: "p-contextMenu, p-contextmenu, p-context-menu", inputs: ["model", "triggerEvent", "target", "global", "style", "styleClass", "autoZIndex", "baseZIndex", "id", "breakpoint", "ariaLabel", "ariaLabelledBy", "pressDelay", "appendTo"], outputs: ["onShow", "onHide"] }, { kind: "component", type: RestWorldTableColumnFilterElementComponent, selector: "rw-table-column-filter-element", inputs: ["filterConstraint", "property", "apiName", "value"] }], viewProviders: [{
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
|
|
4407
|
+
async navigateById() {
|
|
4408
|
+
const rel = this.rel();
|
|
4409
|
+
if (!rel)
|
|
4410
|
+
throw new Error('The "rel" must be set through the uri of this page for the ID navigation to work.');
|
|
4411
|
+
if (!this.idNavigationForm.valid) {
|
|
4412
|
+
this._messageService.add({ detail: 'You must enter a valid ID to naviage to.', severity: 'error' });
|
|
4413
|
+
return;
|
|
4414
|
+
}
|
|
4415
|
+
var idToNavigateTo = this.idNavigationForm.controls.id.value;
|
|
4416
|
+
var client = this._client();
|
|
4417
|
+
var response = await client.getList(rel, { $filter: `id eq ${idToNavigateTo}` });
|
|
4418
|
+
if (!response.ok || ProblemDetails.isProblemDetails(response.body) || !response.body) {
|
|
4419
|
+
this._messageService.add({ severity: 'error', summary: 'Error', detail: 'Error while loading the resources from the API.', data: response });
|
|
4420
|
+
return;
|
|
4421
|
+
}
|
|
4422
|
+
var resource = response.body?._embedded?.items?.[0];
|
|
4423
|
+
if (!resource) {
|
|
4424
|
+
this._messageService.add({ severity: 'error', summary: 'Error', detail: 'No resource found with the specified ID.' });
|
|
4425
|
+
return;
|
|
4426
|
+
}
|
|
4427
|
+
const urlPrefix = this.urlPrefix();
|
|
4428
|
+
if (urlPrefix !== undefined)
|
|
4429
|
+
await this._router.navigate([urlPrefix, resource._links.self[0].href]);
|
|
4430
|
+
else
|
|
4431
|
+
await this._router.navigate(["..", resource._links.self[0].href], { relativeTo: this._route });
|
|
4432
|
+
this.idNavigationForm.reset();
|
|
4433
|
+
}
|
|
4434
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: RestWorldIdNavigationComponent, deps: [{ token: RestWorldClientCollection }, { token: i2$1.MessageService }, { token: i3$3.Router }, { token: i3$3.ActivatedRoute }], target: i0.ɵɵFactoryTarget.Component });
|
|
4435
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.1", type: RestWorldIdNavigationComponent, isStandalone: true, selector: "rw-id-navigation", inputs: { apiName: { classPropertyName: "apiName", publicName: "apiName", isSignal: true, isRequired: true, transformFunction: null }, rel: { classPropertyName: "rel", publicName: "rel", isSignal: true, isRequired: true, transformFunction: null }, urlPrefix: { classPropertyName: "urlPrefix", publicName: "urlPrefix", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<form [formGroup]=\"idNavigationForm\" (ngSubmit)=\"navigateById()\" class=\"mr-3\">\n <div class=\"p-inputgroup\">\n <p-inputNumber formControlName=\"id\" placeholder=\"Navigate by ID\"></p-inputNumber>\n <button type=\"submit\" pButton pRipple icon=\"fa-solid fa-arrow-right\"></button>\n </div>\n</form>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: InputNumberModule }, { kind: "component", type: i1$5.InputNumber, selector: "p-inputNumber, p-inputnumber, p-input-number", inputs: ["showButtons", "format", "buttonLayout", "inputId", "styleClass", "placeholder", "tabindex", "title", "ariaLabelledBy", "ariaDescribedBy", "ariaLabel", "ariaRequired", "autocomplete", "incrementButtonClass", "decrementButtonClass", "incrementButtonIcon", "decrementButtonIcon", "readonly", "allowEmpty", "locale", "localeMatcher", "mode", "currency", "currencyDisplay", "useGrouping", "minFractionDigits", "maxFractionDigits", "prefix", "suffix", "inputStyle", "inputStyleClass", "showClear", "autofocus"], outputs: ["onInput", "onFocus", "onBlur", "onKeyDown", "onClear"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i1$3.ButtonDirective, selector: "[pButton]", inputs: ["iconPos", "loadingIcon", "loading", "severity", "raised", "rounded", "text", "outlined", "size", "plain", "fluid", "label", "icon", "buttonProps"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2$3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2$3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$3.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }] });
|
|
4358
4436
|
}
|
|
4359
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type:
|
|
4437
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: RestWorldIdNavigationComponent, decorators: [{
|
|
4360
4438
|
type: Component,
|
|
4361
|
-
args: [{ selector: 'rw-
|
|
4362
|
-
|
|
4363
|
-
deps: [[Optional, FormArrayName]],
|
|
4364
|
-
useFactory: (arrayName) => arrayName,
|
|
4365
|
-
}], imports: [TableModule, RestWorldMenuButtonComponent, RestWorldInputComponent, RestWorldDisplayComponent, ReactiveFormsModule, ContextMenuModule, RestWorldTableColumnFilterElementComponent, RestWorldTableColumnFilterElementComponent], template: "<p-table\r\n #table\r\n [value]=\"rows()\"\r\n [columns]=\"columns()\"\r\n [lazy]=\"lazy()\"\r\n [lazyLoadOnInit]=\"false\"\r\n (onLazyLoad)=\"load($event)\"\r\n responsiveLayout=\"scroll\"\r\n [paginator]=\"paginator()\"\r\n [rowsPerPageOptions]=\"rowsPerPageOptions()\"\r\n [rows]=\"rowsPerPage()\"\r\n [totalRecords]=\"totalRecords()\"\r\n [loading]=\"isLoading()\"\r\n sortMode=\"multiple\"\r\n [multiSortMeta]=\"multiSortMeta()\"\r\n [styleClass]=\"styleClass()\"\r\n [tableStyle]=\"tableStyle()\"\r\n [scrollable]=\"scrollable()\"\r\n [scrollHeight]=\"scrollHeight()\"\r\n [selectionMode]=\"selectionMode()\"\r\n [rowHover]=\"rowHover()\"\r\n [(selection)]=\"selectedRows\"\r\n [filters]=\"$any(filters())\"\r\n [first]=\"rowsBeforeCurrentPage()\"\r\n >\r\n\r\n <ng-template pTemplate=\"header\" let-columns>\r\n <tr>\r\n @for (col of columns; track col) {\r\n <th [pSortableColumn]=\"col.name\">\r\n <div class=\"p-d-flex p-jc-between p-ai-center gap-1\">\r\n {{col.prompt}}\r\n @if(!col.readOnly) {\r\n <p-sortIcon [field]=\"col.name\"></p-sortIcon>\r\n <p-columnFilter #f\r\n [type]=\"toColumnFilterType(col.type)\"\r\n [maxFractionDigits]=\"toMaxFractionDigits(col)\"\r\n matchMode=\"noFilter\"\r\n [matchModeOptions]=\"toMatchModeOptions(col)\"\r\n [showMatchModes]=\"true\"\r\n [field]=\"col.name\"\r\n display=\"menu\"\r\n [maxConstraints]=\"100\"\r\n [class.has-filter]=\"f.hasFilter\">\r\n <ng-template #filter let-value let-filterConstraint=\"filterConstraint\" let-field=\"field\">\r\n <rw-table-column-filter-element [property]=\"col\" [value]=\"value\" [apiName]=\"apiName()\" [filterConstraint]=\"filterConstraint\"></rw-table-column-filter-element>\r\n </ng-template>\r\n </p-columnFilter>\r\n }\r\n </div>\r\n </th>\r\n }\r\n @if (showMenuColumn()) {\r\n <th>\r\n <rw-menu-button [items]=\"headerMenu()\"></rw-menu-button>\r\n </th>\r\n }\r\n </tr>\r\n </ng-template>\r\n\r\n <ng-template pTemplate=\"body\" let-entity let-columns=\"columns\" let-rowIndex=\"rowIndex\">\r\n <tr (contextmenu)=\"openContextMenu($event, entity)\" [pSelectableRow]=\"entity\" [pSelectableRowDisabled]=\"selectionMode() === null\" [className]=\"rowStyleClasses()[rowIndex - (table.first ?? 0)]\">\r\n @for (col of columns; track col) {\r\n <td [className]=\"cellStyleClasses()[rowIndex - (table.first ?? 0)][col.name]\">\r\n @let fomrArray = formArray();\r\n @if (showInputField(col) && fomrArray) {\r\n <ng-container [formGroup]=\"fomrArray.controls[rowIndex - (table.first ?? 0)]\" >\r\n <rw-input [apiName]=\"apiName()\" [property]=\"editProperties()[col.name]!\"></rw-input>\r\n </ng-container>\r\n }\r\n @else {\r\n <rw-display [property]=\"col\" [value]=\"entity[col.name]\" [apiName]=\"apiName()!\"></rw-display>\r\n }\r\n </td>\r\n }\r\n @if (showMenuColumn()) {\r\n <td>\r\n @if (showRowMenuAsColumn()) {\r\n <rw-menu-button [items]=\"rowMenus()[rowIndex - (table.first ?? 0)]\"></rw-menu-button>\r\n }\r\n </td>\r\n }\r\n </tr>\r\n </ng-template>\r\n</p-table>\r\n\r\n<p-contextMenu #contextMenu appendTo=\"body\" [model]=\"contextMenuItems()\"></p-contextMenu>\r\n", styles: [".p-tooltip{max-width:fit-content}a.p-button{text-decoration:none}::ng-deep rw-table rw-label.md\\:col-2{width:100%;font-weight:600}::ng-deep rw-table .p-d-flex{display:flex}::ng-deep rw-table .p-ai-center{align-items:center}::ng-deep rw-table .has-filter filtericon{color:var(--p-datatable-header-cell-selected-color)}::ng-deep rw-table p-columnfilter .p-datatable-column-filter-button{width:unset;height:23px!important;padding-block-end:0;padding-block-start:0}\n"] }]
|
|
4366
|
-
}], ctorParameters: () => [{ type: i2$3.ControlContainer }, { type: i1$1.FormService }, { type: i3$4.Router }, { type: i3$4.ActivatedRoute }, { type: i4$2.PrimeNG }] });
|
|
4367
|
-
var ColumnFilterType;
|
|
4368
|
-
(function (ColumnFilterType) {
|
|
4369
|
-
ColumnFilterType["text"] = "text";
|
|
4370
|
-
ColumnFilterType["numeric"] = "numeric";
|
|
4371
|
-
ColumnFilterType["boolean"] = "boolean";
|
|
4372
|
-
ColumnFilterType["date"] = "date";
|
|
4373
|
-
ColumnFilterType["enum"] = "enum";
|
|
4374
|
-
})(ColumnFilterType || (ColumnFilterType = {}));
|
|
4439
|
+
args: [{ selector: 'rw-id-navigation', standalone: true, imports: [InputNumberModule, ButtonModule, ReactiveFormsModule], template: "<form [formGroup]=\"idNavigationForm\" (ngSubmit)=\"navigateById()\" class=\"mr-3\">\n <div class=\"p-inputgroup\">\n <p-inputNumber formControlName=\"id\" placeholder=\"Navigate by ID\"></p-inputNumber>\n <button type=\"submit\" pButton pRipple icon=\"fa-solid fa-arrow-right\"></button>\n </div>\n</form>\n" }]
|
|
4440
|
+
}], ctorParameters: () => [{ type: RestWorldClientCollection }, { type: i2$1.MessageService }, { type: i3$3.Router }, { type: i3$3.ActivatedRoute }] });
|
|
4375
4441
|
|
|
4376
4442
|
class RestWorldOptions {
|
|
4377
4443
|
BaseUrl;
|
|
@@ -4677,7 +4743,7 @@ class OpenTelemetryService {
|
|
|
4677
4743
|
getTracer() {
|
|
4678
4744
|
return this._tracer;
|
|
4679
4745
|
}
|
|
4680
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: OpenTelemetryService, deps: [{ token: SettingsService }, { token: i3$
|
|
4746
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: OpenTelemetryService, deps: [{ token: SettingsService }, { token: i3$3.Router }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
4681
4747
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: OpenTelemetryService, providedIn: "root" });
|
|
4682
4748
|
}
|
|
4683
4749
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: OpenTelemetryService, decorators: [{
|
|
@@ -4685,7 +4751,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImpor
|
|
|
4685
4751
|
args: [{
|
|
4686
4752
|
providedIn: "root"
|
|
4687
4753
|
}]
|
|
4688
|
-
}], ctorParameters: () => [{ type: SettingsService }, { type: i3$
|
|
4754
|
+
}], ctorParameters: () => [{ type: SettingsService }, { type: i3$3.Router }] });
|
|
4689
4755
|
|
|
4690
4756
|
/**
|
|
4691
4757
|
* Component for editing a resource in the RESTworld application.
|
|
@@ -4707,14 +4773,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImpor
|
|
|
4707
4773
|
class RESTworldEditViewComponent {
|
|
4708
4774
|
_clients;
|
|
4709
4775
|
_messageService;
|
|
4776
|
+
_problemService;
|
|
4710
4777
|
_router;
|
|
4711
4778
|
extraTabsRef;
|
|
4712
4779
|
idNavigationForm = new FormGroup({
|
|
4713
4780
|
id: new FormControl(null, Validators.compose([Validators.min(1), Validators.max(Number.MAX_SAFE_INTEGER)]))
|
|
4714
4781
|
});
|
|
4715
|
-
constructor(_clients, _messageService, _router, valdemortConfig) {
|
|
4782
|
+
constructor(_clients, _messageService, _problemService, _router, valdemortConfig) {
|
|
4716
4783
|
this._clients = _clients;
|
|
4717
4784
|
this._messageService = _messageService;
|
|
4785
|
+
this._problemService = _problemService;
|
|
4718
4786
|
this._router = _router;
|
|
4719
4787
|
valdemortConfig.errorClasses = "p-error text-sm";
|
|
4720
4788
|
}
|
|
@@ -4733,9 +4801,19 @@ class RESTworldEditViewComponent {
|
|
|
4733
4801
|
* The name of the API to load the resource from.
|
|
4734
4802
|
*/
|
|
4735
4803
|
apiName = input.required(...(ngDevMode ? [{ debugName: "apiName" }] : []));
|
|
4804
|
+
newHref = computed(() => this.resource.value()?.findLink('new')?.href, ...(ngDevMode ? [{ debugName: "newHref" }] : []));
|
|
4736
4805
|
templates = resource({
|
|
4806
|
+
params: () => ({ apiName: this.apiName(), resource: this.resource.value() }),
|
|
4807
|
+
loader: ({ params }) => this.loadTemplatesInternal(params.apiName, params.resource)
|
|
4808
|
+
});
|
|
4809
|
+
resource = resource({
|
|
4737
4810
|
params: () => ({ apiName: this.apiName(), uri: this.uri() }),
|
|
4738
|
-
loader: ({ params }) =>
|
|
4811
|
+
loader: async ({ params }) => {
|
|
4812
|
+
const client = this._clients.getClient(params.apiName);
|
|
4813
|
+
const resourceResponse = await client.getSingleByUri(params.uri);
|
|
4814
|
+
this._problemService.checkResponseDisplayErrorsAndThrow(resourceResponse);
|
|
4815
|
+
return resourceResponse.body;
|
|
4816
|
+
}
|
|
4739
4817
|
});
|
|
4740
4818
|
displayTab = model("Loading", ...(ngDevMode ? [{ debugName: "displayTab" }] : []));
|
|
4741
4819
|
async afterSubmit($event) {
|
|
@@ -4744,14 +4822,17 @@ class RESTworldEditViewComponent {
|
|
|
4744
4822
|
}
|
|
4745
4823
|
}
|
|
4746
4824
|
async afterDelete() {
|
|
4747
|
-
await this._router.navigate(["list", this.apiName, this.rel()]);
|
|
4825
|
+
await this._router.navigate(["list", this.apiName(), this.rel()]);
|
|
4826
|
+
}
|
|
4827
|
+
createNew() {
|
|
4828
|
+
return this._router.navigate(["edit", this.apiName(), this.rel(), this.newHref()]);
|
|
4748
4829
|
}
|
|
4749
|
-
async
|
|
4750
|
-
if (!apiName || !
|
|
4830
|
+
async loadTemplatesInternal(apiName, resource) {
|
|
4831
|
+
if (!apiName || !resource)
|
|
4751
4832
|
return [];
|
|
4752
4833
|
try {
|
|
4753
4834
|
const client = this._clients.getClient(apiName);
|
|
4754
|
-
const templatesOrProblemDetails = await client.
|
|
4835
|
+
const templatesOrProblemDetails = await client.getAllTemplates(resource);
|
|
4755
4836
|
// Check if we got ProblemDetails instead of Templates
|
|
4756
4837
|
if (ProblemDetails.isProblemDetails(templatesOrProblemDetails)) {
|
|
4757
4838
|
this._messageService.add({
|
|
@@ -4778,13 +4859,13 @@ class RESTworldEditViewComponent {
|
|
|
4778
4859
|
return [];
|
|
4779
4860
|
}
|
|
4780
4861
|
}
|
|
4781
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: RESTworldEditViewComponent, deps: [{ token: RestWorldClientCollection }, { token: i2$1.MessageService }, { token: i3$
|
|
4782
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.1", type: RESTworldEditViewComponent, isStandalone: true, selector: "rw-edit", inputs: { rel: { classPropertyName: "rel", publicName: "rel", isSignal: true, isRequired: true, transformFunction: null }, uri: { classPropertyName: "uri", publicName: "uri", isSignal: true, isRequired: true, transformFunction: null }, apiName: { classPropertyName: "apiName", publicName: "apiName", isSignal: true, isRequired: true, transformFunction: null }, displayTab: { classPropertyName: "displayTab", publicName: "displayTab", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { displayTab: "displayTabChange" }, queries: [{ propertyName: "extraTabsRef", first: true, predicate: ["extraTabs"], descendants: true }], ngImport: i0, template: "<div class=\"grid\">\r\n <div class=\"col-12 md:col-10\">\r\n <h1>Edit resource</h1>\r\n </div>\r\n <div class=\"col-12 md:col-2 align-items-center justify-content-end flex\">\r\n <rw-id-navigation [apiName]=\"apiName()\" [rel]=\"rel()\"></rw-id-navigation>\r\n </div>\r\n</div>\r\n\r\n<p-tabs [(value)]=\"displayTab\">\r\n <p-tablist>\r\n @if (templates.isLoading()) {\r\n <p-tab value=\"Loading\">Loading</p-tab>\r\n }\r\n @else {\r\n @for (template of templates.value(); track template; let i = $index) {\r\n <p-tab [value]=\"template.title ?? i\">{{template.title}}</p-tab>\r\n }\r\n @if (extraTabsRef) {\r\n <p-tab value=\"Extra\">Extra</p-tab>\r\n }\r\n }\r\n </p-tablist>\r\n <p-tabpanels>\r\n @if (templates.isLoading()) {\r\n <p-tabpanel value=\"Loading\">\r\n @for(i of [1, 2, 3, 4, 5]; track i) {\r\n <div class=\"grid field\">\r\n <p-skeleton class=\"col-12 mb-2 md:col-2 md:mb-0\" height=\"39px\"></p-skeleton>\r\n <div class=\"col-12 md:col-10\">\r\n <p-skeleton class=\"w-full\" height=\"39px\"></p-skeleton>\r\n </div>\r\n </div>\r\n }\r\n <div class=\"grid\">\r\n <div class=\"col\">\r\n <div class=\"flex justify-content-end w-full\">\r\n <p-skeleton width=\"120px\" height=\"39px\" class=\"mx-2\"></p-skeleton>\r\n <p-skeleton width=\"120px\" height=\"39px\" class=\"mx-2\"></p-skeleton>\r\n <p-skeleton width=\"120px\" height=\"39px\" class=\"mx-2\"></p-skeleton>\r\n </div>\r\n </div>\r\n </div>\r\n </p-tabpanel>\r\n }\r\n @else {\r\n @for (template of templates.value(); track template; let i = $index) {\r\n <p-tabpanel [value]=\"template.title ?? i\">\r\n <rw-form\r\n [template]=\"template\"\r\n [apiName]=\"apiName()\"\r\n [rel]=\"rel()\"\r\n (afterDelete)=\"afterDelete()\"\r\n (afterSubmit)=\"afterSubmit($event)\"\r\n ></rw-form>\r\n </p-tabpanel>\r\n }\r\n @if (extraTabsRef) {\r\n <p-tabpanel value=\"Extra\">\r\n <ng-container *ngTemplateOutlet=\"extraTabsRef\"></ng-container>\r\n </p-tabpanel>\r\n }\r\n }\r\n </p-tabpanels>\r\n</p-tabs>\r\n\r\n<p-confirmDialog></p-confirmDialog>\r\n", styles: ["::ng-deep .p-tooltip{max-width:fit-content!important}.field.grid>label.hasChildren{border-right:1px solid rgba(0,0,0,.1)}\n"], dependencies: [{ kind: "component", type: RestWorldIdNavigationComponent, selector: "rw-id-navigation", inputs: ["apiName", "rel", "urlPrefix"] }, { kind: "ngmodule", type: SkeletonModule }, { kind: "component", type:
|
|
4862
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: RESTworldEditViewComponent, deps: [{ token: RestWorldClientCollection }, { token: i2$1.MessageService }, { token: ProblemService }, { token: i3$3.Router }, { token: i5.ValdemortConfig }], target: i0.ɵɵFactoryTarget.Component });
|
|
4863
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.1", type: RESTworldEditViewComponent, isStandalone: true, selector: "rw-edit", inputs: { rel: { classPropertyName: "rel", publicName: "rel", isSignal: true, isRequired: true, transformFunction: null }, uri: { classPropertyName: "uri", publicName: "uri", isSignal: true, isRequired: true, transformFunction: null }, apiName: { classPropertyName: "apiName", publicName: "apiName", isSignal: true, isRequired: true, transformFunction: null }, displayTab: { classPropertyName: "displayTab", publicName: "displayTab", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { displayTab: "displayTabChange" }, queries: [{ propertyName: "extraTabsRef", first: true, predicate: ["extraTabs"], descendants: true }], ngImport: i0, template: "<div class=\"grid\">\r\n <div class=\"col-12 md:col-10\">\r\n <h1>Edit resource</h1>\r\n </div>\r\n <div class=\"col-12 md:col-2 align-items-center justify-content-end flex\">\r\n <rw-id-navigation [apiName]=\"apiName()\" [rel]=\"rel()\"></rw-id-navigation>\r\n @if (newHref()) {\r\n <button pButton pRipple type=\"button\" icon=\"fas fa-plus\" class=\"p-button-success mr-3\" (click)=\"createNew()\" pTooltip=\"Create new\"></button>\r\n }\r\n </div>\r\n</div>\r\n\r\n<p-tabs [(value)]=\"displayTab\">\r\n <p-tablist>\r\n @if (templates.isLoading()) {\r\n <p-tab value=\"Loading\">Loading</p-tab>\r\n }\r\n @else {\r\n @for (template of templates.value(); track template; let i = $index) {\r\n <p-tab [value]=\"template.title ?? i\">{{template.title}}</p-tab>\r\n }\r\n @if (extraTabsRef) {\r\n <p-tab value=\"Extra\">Extra</p-tab>\r\n }\r\n }\r\n </p-tablist>\r\n <p-tabpanels>\r\n @if (templates.isLoading()) {\r\n <p-tabpanel value=\"Loading\">\r\n @for(i of [1, 2, 3, 4, 5]; track i) {\r\n <div class=\"grid field\">\r\n <p-skeleton class=\"col-12 mb-2 md:col-2 md:mb-0\" height=\"39px\"></p-skeleton>\r\n <div class=\"col-12 md:col-10\">\r\n <p-skeleton class=\"w-full\" height=\"39px\"></p-skeleton>\r\n </div>\r\n </div>\r\n }\r\n <div class=\"grid\">\r\n <div class=\"col\">\r\n <div class=\"flex justify-content-end w-full\">\r\n <p-skeleton width=\"120px\" height=\"39px\" class=\"mx-2\"></p-skeleton>\r\n <p-skeleton width=\"120px\" height=\"39px\" class=\"mx-2\"></p-skeleton>\r\n <p-skeleton width=\"120px\" height=\"39px\" class=\"mx-2\"></p-skeleton>\r\n </div>\r\n </div>\r\n </div>\r\n </p-tabpanel>\r\n }\r\n @else {\r\n @for (template of templates.value(); track template; let i = $index) {\r\n <p-tabpanel [value]=\"template.title ?? i\">\r\n <rw-form\r\n [template]=\"template\"\r\n [apiName]=\"apiName()\"\r\n [rel]=\"rel()\"\r\n (afterDelete)=\"afterDelete()\"\r\n (afterSubmit)=\"afterSubmit($event)\"\r\n ></rw-form>\r\n </p-tabpanel>\r\n }\r\n @if (extraTabsRef) {\r\n <p-tabpanel value=\"Extra\">\r\n <ng-container *ngTemplateOutlet=\"extraTabsRef\"></ng-container>\r\n </p-tabpanel>\r\n }\r\n }\r\n </p-tabpanels>\r\n</p-tabs>\r\n\r\n<p-confirmDialog></p-confirmDialog>\r\n", styles: ["::ng-deep .p-tooltip{max-width:fit-content!important}.field.grid>label.hasChildren{border-right:1px solid rgba(0,0,0,.1)}\n"], dependencies: [{ kind: "component", type: RestWorldIdNavigationComponent, selector: "rw-id-navigation", inputs: ["apiName", "rel", "urlPrefix"] }, { kind: "ngmodule", type: SkeletonModule }, { kind: "component", type: i6$2.Skeleton, selector: "p-skeleton", inputs: ["styleClass", "shape", "animation", "borderRadius", "size", "width", "height"] }, { kind: "ngmodule", type: TabsModule }, { kind: "component", type: i7$1.Tabs, selector: "p-tabs", inputs: ["value", "scrollable", "lazy", "selectOnFocus", "showNavigators", "tabindex"], outputs: ["valueChange"] }, { kind: "component", type: i7$1.TabPanels, selector: "p-tabpanels" }, { kind: "component", type: i7$1.TabPanel, selector: "p-tabpanel", inputs: ["value"], outputs: ["valueChange"] }, { kind: "component", type: i7$1.TabList, selector: "p-tablist" }, { kind: "component", type: i7$1.Tab, selector: "p-tab", inputs: ["value", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: RestWorldFormComponent, selector: "rw-form", inputs: ["allowDelete", "allowReload", "allowSubmit", "apiName", "rel", "showDelete", "showReload", "showSubmit", "template"], outputs: ["afterDelete", "afterSubmit", "templateChange", "valueChanges"] }, { kind: "ngmodule", type: ConfirmDialogModule }, { kind: "component", type: i8$1.ConfirmDialog, selector: "p-confirmDialog, p-confirmdialog, p-confirm-dialog", inputs: ["header", "icon", "message", "style", "styleClass", "maskStyleClass", "acceptIcon", "acceptLabel", "closeAriaLabel", "acceptAriaLabel", "acceptVisible", "rejectIcon", "rejectLabel", "rejectAriaLabel", "rejectVisible", "acceptButtonStyleClass", "rejectButtonStyleClass", "closeOnEscape", "dismissableMask", "blockScroll", "rtl", "closable", "appendTo", "key", "autoZIndex", "baseZIndex", "transitionOptions", "focusTrap", "defaultFocus", "breakpoints", "visible", "position", "draggable"], outputs: ["onHide"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: ButtonDirective, selector: "[pButton]", inputs: ["iconPos", "loadingIcon", "loading", "severity", "raised", "rounded", "text", "outlined", "size", "plain", "fluid", "label", "icon", "buttonProps"] }, { kind: "directive", type: Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo"] }] });
|
|
4783
4864
|
}
|
|
4784
4865
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: RESTworldEditViewComponent, decorators: [{
|
|
4785
4866
|
type: Component,
|
|
4786
|
-
args: [{ selector: "rw-edit", standalone: true, imports: [RestWorldIdNavigationComponent, SkeletonModule, TabsModule, RestWorldFormComponent, ConfirmDialogModule, NgTemplateOutlet], template: "<div class=\"grid\">\r\n <div class=\"col-12 md:col-10\">\r\n <h1>Edit resource</h1>\r\n </div>\r\n <div class=\"col-12 md:col-2 align-items-center justify-content-end flex\">\r\n <rw-id-navigation [apiName]=\"apiName()\" [rel]=\"rel()\"></rw-id-navigation>\r\n </div>\r\n</div>\r\n\r\n<p-tabs [(value)]=\"displayTab\">\r\n <p-tablist>\r\n @if (templates.isLoading()) {\r\n <p-tab value=\"Loading\">Loading</p-tab>\r\n }\r\n @else {\r\n @for (template of templates.value(); track template; let i = $index) {\r\n <p-tab [value]=\"template.title ?? i\">{{template.title}}</p-tab>\r\n }\r\n @if (extraTabsRef) {\r\n <p-tab value=\"Extra\">Extra</p-tab>\r\n }\r\n }\r\n </p-tablist>\r\n <p-tabpanels>\r\n @if (templates.isLoading()) {\r\n <p-tabpanel value=\"Loading\">\r\n @for(i of [1, 2, 3, 4, 5]; track i) {\r\n <div class=\"grid field\">\r\n <p-skeleton class=\"col-12 mb-2 md:col-2 md:mb-0\" height=\"39px\"></p-skeleton>\r\n <div class=\"col-12 md:col-10\">\r\n <p-skeleton class=\"w-full\" height=\"39px\"></p-skeleton>\r\n </div>\r\n </div>\r\n }\r\n <div class=\"grid\">\r\n <div class=\"col\">\r\n <div class=\"flex justify-content-end w-full\">\r\n <p-skeleton width=\"120px\" height=\"39px\" class=\"mx-2\"></p-skeleton>\r\n <p-skeleton width=\"120px\" height=\"39px\" class=\"mx-2\"></p-skeleton>\r\n <p-skeleton width=\"120px\" height=\"39px\" class=\"mx-2\"></p-skeleton>\r\n </div>\r\n </div>\r\n </div>\r\n </p-tabpanel>\r\n }\r\n @else {\r\n @for (template of templates.value(); track template; let i = $index) {\r\n <p-tabpanel [value]=\"template.title ?? i\">\r\n <rw-form\r\n [template]=\"template\"\r\n [apiName]=\"apiName()\"\r\n [rel]=\"rel()\"\r\n (afterDelete)=\"afterDelete()\"\r\n (afterSubmit)=\"afterSubmit($event)\"\r\n ></rw-form>\r\n </p-tabpanel>\r\n }\r\n @if (extraTabsRef) {\r\n <p-tabpanel value=\"Extra\">\r\n <ng-container *ngTemplateOutlet=\"extraTabsRef\"></ng-container>\r\n </p-tabpanel>\r\n }\r\n }\r\n </p-tabpanels>\r\n</p-tabs>\r\n\r\n<p-confirmDialog></p-confirmDialog>\r\n", styles: ["::ng-deep .p-tooltip{max-width:fit-content!important}.field.grid>label.hasChildren{border-right:1px solid rgba(0,0,0,.1)}\n"] }]
|
|
4787
|
-
}], ctorParameters: () => [{ type: RestWorldClientCollection }, { type: i2$1.MessageService }, { type: i3$
|
|
4867
|
+
args: [{ selector: "rw-edit", standalone: true, imports: [RestWorldIdNavigationComponent, SkeletonModule, TabsModule, RestWorldFormComponent, ConfirmDialogModule, NgTemplateOutlet, ButtonDirective, Tooltip], template: "<div class=\"grid\">\r\n <div class=\"col-12 md:col-10\">\r\n <h1>Edit resource</h1>\r\n </div>\r\n <div class=\"col-12 md:col-2 align-items-center justify-content-end flex\">\r\n <rw-id-navigation [apiName]=\"apiName()\" [rel]=\"rel()\"></rw-id-navigation>\r\n @if (newHref()) {\r\n <button pButton pRipple type=\"button\" icon=\"fas fa-plus\" class=\"p-button-success mr-3\" (click)=\"createNew()\" pTooltip=\"Create new\"></button>\r\n }\r\n </div>\r\n</div>\r\n\r\n<p-tabs [(value)]=\"displayTab\">\r\n <p-tablist>\r\n @if (templates.isLoading()) {\r\n <p-tab value=\"Loading\">Loading</p-tab>\r\n }\r\n @else {\r\n @for (template of templates.value(); track template; let i = $index) {\r\n <p-tab [value]=\"template.title ?? i\">{{template.title}}</p-tab>\r\n }\r\n @if (extraTabsRef) {\r\n <p-tab value=\"Extra\">Extra</p-tab>\r\n }\r\n }\r\n </p-tablist>\r\n <p-tabpanels>\r\n @if (templates.isLoading()) {\r\n <p-tabpanel value=\"Loading\">\r\n @for(i of [1, 2, 3, 4, 5]; track i) {\r\n <div class=\"grid field\">\r\n <p-skeleton class=\"col-12 mb-2 md:col-2 md:mb-0\" height=\"39px\"></p-skeleton>\r\n <div class=\"col-12 md:col-10\">\r\n <p-skeleton class=\"w-full\" height=\"39px\"></p-skeleton>\r\n </div>\r\n </div>\r\n }\r\n <div class=\"grid\">\r\n <div class=\"col\">\r\n <div class=\"flex justify-content-end w-full\">\r\n <p-skeleton width=\"120px\" height=\"39px\" class=\"mx-2\"></p-skeleton>\r\n <p-skeleton width=\"120px\" height=\"39px\" class=\"mx-2\"></p-skeleton>\r\n <p-skeleton width=\"120px\" height=\"39px\" class=\"mx-2\"></p-skeleton>\r\n </div>\r\n </div>\r\n </div>\r\n </p-tabpanel>\r\n }\r\n @else {\r\n @for (template of templates.value(); track template; let i = $index) {\r\n <p-tabpanel [value]=\"template.title ?? i\">\r\n <rw-form\r\n [template]=\"template\"\r\n [apiName]=\"apiName()\"\r\n [rel]=\"rel()\"\r\n (afterDelete)=\"afterDelete()\"\r\n (afterSubmit)=\"afterSubmit($event)\"\r\n ></rw-form>\r\n </p-tabpanel>\r\n }\r\n @if (extraTabsRef) {\r\n <p-tabpanel value=\"Extra\">\r\n <ng-container *ngTemplateOutlet=\"extraTabsRef\"></ng-container>\r\n </p-tabpanel>\r\n }\r\n }\r\n </p-tabpanels>\r\n</p-tabs>\r\n\r\n<p-confirmDialog></p-confirmDialog>\r\n", styles: ["::ng-deep .p-tooltip{max-width:fit-content!important}.field.grid>label.hasChildren{border-right:1px solid rgba(0,0,0,.1)}\n"] }]
|
|
4868
|
+
}], ctorParameters: () => [{ type: RestWorldClientCollection }, { type: i2$1.MessageService }, { type: ProblemService }, { type: i3$3.Router }, { type: i5.ValdemortConfig }], propDecorators: { extraTabsRef: [{
|
|
4788
4869
|
type: ContentChild,
|
|
4789
4870
|
args: ["extraTabs", { static: false }]
|
|
4790
4871
|
}] } });
|
|
@@ -4976,13 +5057,13 @@ class RESTworldListViewComponent {
|
|
|
4976
5057
|
return undefined;
|
|
4977
5058
|
return this._clients.getClient(apiName);
|
|
4978
5059
|
}, ...(ngDevMode ? [{ debugName: "_client" }] : []));
|
|
4979
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: RESTworldListViewComponent, deps: [{ token: RestWorldClientCollection }, { token: i2$1.ConfirmationService }, { token: i2$1.MessageService }, { token: AvatarGenerator }, { token: i3$
|
|
4980
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.1", type: RESTworldListViewComponent, isStandalone: true, selector: "rw-list", inputs: { createButtonMenu: { classPropertyName: "createButtonMenu", publicName: "createButtonMenu", isSignal: true, isRequired: false, transformFunction: null }, filter: { classPropertyName: "filter", publicName: "$filter", isSignal: true, isRequired: false, transformFunction: null }, orderby: { classPropertyName: "orderby", publicName: "$orderby", isSignal: true, isRequired: false, transformFunction: null }, skip: { classPropertyName: "skip", publicName: "$skip", isSignal: true, isRequired: false, transformFunction: null }, top: { classPropertyName: "top", publicName: "$top", isSignal: true, isRequired: false, transformFunction: null }, editLink: { classPropertyName: "editLink", publicName: "editLink", isSignal: true, isRequired: false, transformFunction: null }, apiName: { classPropertyName: "apiName", publicName: "apiName", isSignal: true, isRequired: false, transformFunction: null }, rel: { classPropertyName: "rel", publicName: "rel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { filter: "$filterChange", orderby: "$orderbyChange", skip: "$skipChange", top: "$topChange" }, ngImport: i0, template: "@let search = searchTemplate.value();\r\n@let api = apiName();\r\n@if (search && api) {\r\n <rw-table\r\n [apiName]=\"api\"\r\n [searchTemplate]=\"search\"\r\n [rows]=\"items()\"\r\n [headerMenu]=\"headerMenu()\"\r\n [rowMenu]=\"rowMenu()\"\r\n [totalRecords]=\"totalRecords()\"\r\n [isLoading]=\"isLoading()\"\r\n >\r\n </rw-table>\r\n}\r\n<p-confirmDialog></p-confirmDialog>\r\n", styles: [".p-tooltip{max-width:fit-content}a.p-button{text-decoration:none}\n"], dependencies: [{ kind: "component", type: RestWorldTableComponent, selector: "rw-table", inputs: ["apiName", "cellStyleClass", "editTemplate", "headerMenu", "isLoading", "lazy", "paginator", "oDataParameters", "reflectParametersInUrl", "rowHover", "rowMenu", "rowStyleClass", "rows", "rowsPerPageOptions", "scrollHeight", "scrollable", "searchTemplate", "selectedRows", "selectionMode", "showRowMenuAsColumn", "showRowMenuOnRightClick", "styleClass", "tableStyle", "totalRecords", "urlParameterPrefix"], outputs: ["oDataParametersChange", "selectedRowsChange"] }, { kind: "ngmodule", type: ConfirmDialogModule }, { kind: "component", type:
|
|
5060
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: RESTworldListViewComponent, deps: [{ token: RestWorldClientCollection }, { token: i2$1.ConfirmationService }, { token: i2$1.MessageService }, { token: AvatarGenerator }, { token: i3$3.Router }, { token: ProblemService }], target: i0.ɵɵFactoryTarget.Component });
|
|
5061
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.1", type: RESTworldListViewComponent, isStandalone: true, selector: "rw-list", inputs: { createButtonMenu: { classPropertyName: "createButtonMenu", publicName: "createButtonMenu", isSignal: true, isRequired: false, transformFunction: null }, filter: { classPropertyName: "filter", publicName: "$filter", isSignal: true, isRequired: false, transformFunction: null }, orderby: { classPropertyName: "orderby", publicName: "$orderby", isSignal: true, isRequired: false, transformFunction: null }, skip: { classPropertyName: "skip", publicName: "$skip", isSignal: true, isRequired: false, transformFunction: null }, top: { classPropertyName: "top", publicName: "$top", isSignal: true, isRequired: false, transformFunction: null }, editLink: { classPropertyName: "editLink", publicName: "editLink", isSignal: true, isRequired: false, transformFunction: null }, apiName: { classPropertyName: "apiName", publicName: "apiName", isSignal: true, isRequired: false, transformFunction: null }, rel: { classPropertyName: "rel", publicName: "rel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { filter: "$filterChange", orderby: "$orderbyChange", skip: "$skipChange", top: "$topChange" }, ngImport: i0, template: "@let search = searchTemplate.value();\r\n@let api = apiName();\r\n@if (search && api) {\r\n <rw-table\r\n [apiName]=\"api\"\r\n [searchTemplate]=\"search\"\r\n [rows]=\"items()\"\r\n [headerMenu]=\"headerMenu()\"\r\n [rowMenu]=\"rowMenu()\"\r\n [totalRecords]=\"totalRecords()\"\r\n [isLoading]=\"isLoading()\"\r\n >\r\n </rw-table>\r\n}\r\n<p-confirmDialog></p-confirmDialog>\r\n", styles: [".p-tooltip{max-width:fit-content}a.p-button{text-decoration:none}\n"], dependencies: [{ kind: "component", type: RestWorldTableComponent, selector: "rw-table", inputs: ["apiName", "cellStyleClass", "editTemplate", "headerMenu", "isLoading", "lazy", "paginator", "oDataParameters", "reflectParametersInUrl", "rowHover", "rowMenu", "rowStyleClass", "rows", "rowsPerPageOptions", "scrollHeight", "scrollable", "searchTemplate", "selectedRows", "selectionMode", "showRowMenuAsColumn", "showRowMenuOnRightClick", "styleClass", "tableStyle", "totalRecords", "urlParameterPrefix"], outputs: ["oDataParametersChange", "selectedRowsChange"] }, { kind: "ngmodule", type: ConfirmDialogModule }, { kind: "component", type: i8$1.ConfirmDialog, selector: "p-confirmDialog, p-confirmdialog, p-confirm-dialog", inputs: ["header", "icon", "message", "style", "styleClass", "maskStyleClass", "acceptIcon", "acceptLabel", "closeAriaLabel", "acceptAriaLabel", "acceptVisible", "rejectIcon", "rejectLabel", "rejectAriaLabel", "rejectVisible", "acceptButtonStyleClass", "rejectButtonStyleClass", "closeOnEscape", "dismissableMask", "blockScroll", "rtl", "closable", "appendTo", "key", "autoZIndex", "baseZIndex", "transitionOptions", "focusTrap", "defaultFocus", "breakpoints", "visible", "position", "draggable"], outputs: ["onHide"] }] });
|
|
4981
5062
|
}
|
|
4982
5063
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: RESTworldListViewComponent, decorators: [{
|
|
4983
5064
|
type: Component,
|
|
4984
5065
|
args: [{ selector: 'rw-list', standalone: true, imports: [RestWorldTableComponent, ConfirmDialogModule], template: "@let search = searchTemplate.value();\r\n@let api = apiName();\r\n@if (search && api) {\r\n <rw-table\r\n [apiName]=\"api\"\r\n [searchTemplate]=\"search\"\r\n [rows]=\"items()\"\r\n [headerMenu]=\"headerMenu()\"\r\n [rowMenu]=\"rowMenu()\"\r\n [totalRecords]=\"totalRecords()\"\r\n [isLoading]=\"isLoading()\"\r\n >\r\n </rw-table>\r\n}\r\n<p-confirmDialog></p-confirmDialog>\r\n", styles: [".p-tooltip{max-width:fit-content}a.p-button{text-decoration:none}\n"] }]
|
|
4985
|
-
}], ctorParameters: () => [{ type: RestWorldClientCollection }, { type: i2$1.ConfirmationService }, { type: i2$1.MessageService }, { type: AvatarGenerator }, { type: i3$
|
|
5066
|
+
}], ctorParameters: () => [{ type: RestWorldClientCollection }, { type: i2$1.ConfirmationService }, { type: i2$1.MessageService }, { type: AvatarGenerator }, { type: i3$3.Router }, { type: ProblemService }] });
|
|
4986
5067
|
|
|
4987
5068
|
/**
|
|
4988
5069
|
* This is an HttpInterceptor that ensures all HttpClient requests
|