@sinequa/atomic-angular 0.4.37 → 0.4.46
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.
|
@@ -812,14 +812,19 @@ class OperatorPipe {
|
|
|
812
812
|
return `> ${new Intl.DateTimeFormat(locale).format(new Date(start))} ≤ ${new Intl.DateTimeFormat(locale).format(new Date(end))}`;
|
|
813
813
|
}
|
|
814
814
|
if (filter?.operator === 'and') {
|
|
815
|
-
const
|
|
816
|
-
const
|
|
817
|
-
|
|
818
|
-
|
|
815
|
+
const filters = filter.filters;
|
|
816
|
+
const from = filters?.find((f) => f.operator === 'gte')?.value;
|
|
817
|
+
const to = filters?.find((f) => f.operator === 'lte')?.value;
|
|
818
|
+
if (from && to) {
|
|
819
|
+
return `≥ ${new Intl.DateTimeFormat(locale).format(new Date(from))} ≤ ${new Intl.DateTimeFormat(locale).format(new Date(to))}`;
|
|
819
820
|
}
|
|
820
|
-
|
|
821
|
-
return new Intl.DateTimeFormat(locale).format(
|
|
821
|
+
if (from) {
|
|
822
|
+
return `≥ ${new Intl.DateTimeFormat(locale).format(new Date(from))}`;
|
|
823
|
+
}
|
|
824
|
+
if (to) {
|
|
825
|
+
return `≤ ${new Intl.DateTimeFormat(locale).format(new Date(to))}`;
|
|
822
826
|
}
|
|
827
|
+
return filter?.display ?? filter?.value ?? '';
|
|
823
828
|
}
|
|
824
829
|
const date = new Date(filter?.value || '');
|
|
825
830
|
if (isNaN(date.getTime())) {
|
|
@@ -2814,13 +2819,34 @@ function withUserSettingsFeatures() {
|
|
|
2814
2819
|
alerts: [],
|
|
2815
2820
|
assistants: {},
|
|
2816
2821
|
language: undefined,
|
|
2817
|
-
collapseAssistant: undefined
|
|
2822
|
+
collapseAssistant: undefined,
|
|
2823
|
+
agents: { isDebugMode: false }
|
|
2818
2824
|
});
|
|
2819
2825
|
}
|
|
2820
2826
|
})));
|
|
2821
2827
|
}
|
|
2822
2828
|
|
|
2823
|
-
|
|
2829
|
+
function withAgentsFeatures() {
|
|
2830
|
+
return signalStoreFeature(withState({
|
|
2831
|
+
agents: { isDebugMode: false }
|
|
2832
|
+
}), withComputed((store) => ({
|
|
2833
|
+
isDebugMode: computed(() => store.agents()?.isDebugMode ?? false)
|
|
2834
|
+
})), withMethods((store) => ({
|
|
2835
|
+
async setDebugMode(value) {
|
|
2836
|
+
try {
|
|
2837
|
+
await patchUserSettings({ agents: { ...store.agents(), isDebugMode: value } }, { type: 'Agent_DebugMode_Toggle' });
|
|
2838
|
+
patchState(store, (state) => ({
|
|
2839
|
+
agents: { ...state.agents, isDebugMode: value }
|
|
2840
|
+
}));
|
|
2841
|
+
}
|
|
2842
|
+
catch (e) {
|
|
2843
|
+
error('setDebugMode failed', e);
|
|
2844
|
+
}
|
|
2845
|
+
}
|
|
2846
|
+
})));
|
|
2847
|
+
}
|
|
2848
|
+
|
|
2849
|
+
const UserSettingsStore = signalStore({ providedIn: 'root' }, withDevtools('UserSettings'), withBookmarkFeatures(), withRecentSearchesFeatures(), withSavedSearchesFeatures(), withBasketsFeatures(), withAssistantFeatures(), withUserSettingsFeatures(), withAlertsFeatures(), withAgentsFeatures(), withDarkModeFeatures());
|
|
2824
2850
|
|
|
2825
2851
|
class QueryService {
|
|
2826
2852
|
http = inject(HttpClient);
|
|
@@ -3656,18 +3682,26 @@ class ApplicationService {
|
|
|
3656
3682
|
}
|
|
3657
3683
|
const { light, dark, alt } = general.logo || {};
|
|
3658
3684
|
document.documentElement.style.setProperty("--logo-alt-text", `'${alt || general.name}'`);
|
|
3685
|
+
// light mode logo configuration
|
|
3659
3686
|
if (light?.small) {
|
|
3660
3687
|
document.documentElement.style.setProperty("--logo-light-small", `url('${light.small}')`);
|
|
3661
3688
|
}
|
|
3662
3689
|
if (light?.large) {
|
|
3663
3690
|
document.documentElement.style.setProperty("--logo-light-large", `url('${light.large}')`);
|
|
3664
3691
|
}
|
|
3692
|
+
if (light?.sidebar) {
|
|
3693
|
+
document.documentElement.style.setProperty("--logo-light-sidebar", `url('${light.sidebar}')`);
|
|
3694
|
+
}
|
|
3695
|
+
// dark mode logo configuration
|
|
3665
3696
|
if (dark?.small) {
|
|
3666
3697
|
document.documentElement.style.setProperty("--logo-dark-small", `url('${dark.small}')`);
|
|
3667
3698
|
}
|
|
3668
3699
|
if (dark?.large) {
|
|
3669
3700
|
document.documentElement.style.setProperty("--logo-dark-large", `url('${dark.large}')`);
|
|
3670
3701
|
}
|
|
3702
|
+
if (dark?.sidebar) {
|
|
3703
|
+
document.documentElement.style.setProperty("--logo-dark-sidebar", `url('${dark.sidebar}')`);
|
|
3704
|
+
}
|
|
3671
3705
|
}
|
|
3672
3706
|
/**
|
|
3673
3707
|
* Sets the document title with optional application name prefix.
|
|
@@ -5397,10 +5431,13 @@ class MissingTermsComponent {
|
|
|
5397
5431
|
return this.article()
|
|
5398
5432
|
.termspresence?.filter(tp => tp.presence === 'missing')
|
|
5399
5433
|
.map(tp => {
|
|
5400
|
-
const
|
|
5434
|
+
const bracketMatch = tp.term.match(/^\[(.+)\]$/);
|
|
5435
|
+
const cleanTerm = bracketMatch ? bracketMatch[1] : tp.term;
|
|
5436
|
+
const escapedTerm = cleanTerm.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
5437
|
+
const text = (query.text || '').replace(new RegExp(`\\b${escapedTerm}\\b`, 'gi'), '').replace(/\s+/g, ' ').trim();
|
|
5401
5438
|
return {
|
|
5402
|
-
value:
|
|
5403
|
-
queryParams: { q: `${text} +[${
|
|
5439
|
+
value: cleanTerm,
|
|
5440
|
+
queryParams: { q: `${text} +[${cleanTerm}]` }
|
|
5404
5441
|
};
|
|
5405
5442
|
});
|
|
5406
5443
|
}, ...(ngDevMode ? [{ debugName: "missingTerms" }] : []));
|
|
@@ -5532,7 +5569,7 @@ class CollectionsDialog {
|
|
|
5532
5569
|
{{ collection.name }}
|
|
5533
5570
|
</li>
|
|
5534
5571
|
} @empty {
|
|
5535
|
-
<li class="py-4 text-center text-neutral-500">
|
|
5572
|
+
<li class="list-none py-4 text-center text-neutral-500">
|
|
5536
5573
|
{{ 'collections.noCollections' | transloco }}
|
|
5537
5574
|
</li>
|
|
5538
5575
|
}
|
|
@@ -5616,7 +5653,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
5616
5653
|
{{ collection.name }}
|
|
5617
5654
|
</li>
|
|
5618
5655
|
} @empty {
|
|
5619
|
-
<li class="py-4 text-center text-neutral-500">
|
|
5656
|
+
<li class="list-none py-4 text-center text-neutral-500">
|
|
5620
5657
|
{{ 'collections.noCollections' | transloco }}
|
|
5621
5658
|
</li>
|
|
5622
5659
|
}
|
|
@@ -7147,6 +7184,7 @@ class NavbarTabsComponent {
|
|
|
7147
7184
|
[noTruncate]="noTruncate()"
|
|
7148
7185
|
[style.--tab-min-width]="minTabWidth()"
|
|
7149
7186
|
[attr.aria-selected]="this.currentPath() === tab.path"
|
|
7187
|
+
[attr.disabled]="showCount() && tab.count === 0 ? '' : null"
|
|
7150
7188
|
[active]="this.currentPath() === tab.path"
|
|
7151
7189
|
[routerLink]="[tab.routerLink]"
|
|
7152
7190
|
[queryParams]="{ n: tab.queryName, q: searchText(), t: tab.wsQueryTab, f: undefined, sort: undefined, id: undefined, page: undefined }"
|
|
@@ -7239,6 +7277,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
7239
7277
|
[noTruncate]="noTruncate()"
|
|
7240
7278
|
[style.--tab-min-width]="minTabWidth()"
|
|
7241
7279
|
[attr.aria-selected]="this.currentPath() === tab.path"
|
|
7280
|
+
[attr.disabled]="showCount() && tab.count === 0 ? '' : null"
|
|
7242
7281
|
[active]="this.currentPath() === tab.path"
|
|
7243
7282
|
[routerLink]="[tab.routerLink]"
|
|
7244
7283
|
[queryParams]="{ n: tab.queryName, q: searchText(), t: tab.wsQueryTab, f: undefined, sort: undefined, id: undefined, page: undefined }"
|
|
@@ -8486,6 +8525,7 @@ class AggregationListComponent {
|
|
|
8486
8525
|
aggregationsService = inject(AggregationsService);
|
|
8487
8526
|
el = inject(ElementRef);
|
|
8488
8527
|
injector = inject(Injector);
|
|
8528
|
+
destroyRef = inject(DestroyRef);
|
|
8489
8529
|
class = input("", ...(ngDevMode ? [{ debugName: "class" }] : []));
|
|
8490
8530
|
/**
|
|
8491
8531
|
* The name of the <details> element. When you provide the same id, the component work as an accordion
|
|
@@ -8653,6 +8693,15 @@ class AggregationListComponent {
|
|
|
8653
8693
|
const suggests = (await withFetch(() => fetchSuggestField(this.normalizedSearchText(), [this.aggregation()?.column || ""], query), this.injector)) || [];
|
|
8654
8694
|
this.suggests.set(suggests);
|
|
8655
8695
|
});
|
|
8696
|
+
this.destroyRef.onDestroy(() => {
|
|
8697
|
+
// If the popover is closed with unapplied selections, reset $selected to undefined
|
|
8698
|
+
// so that processAggregation can recompute it from active filters on next open
|
|
8699
|
+
if (this.selection()) {
|
|
8700
|
+
this.aggregation()?.items?.forEach(item => {
|
|
8701
|
+
item.$selected = undefined;
|
|
8702
|
+
});
|
|
8703
|
+
}
|
|
8704
|
+
});
|
|
8656
8705
|
}
|
|
8657
8706
|
/**
|
|
8658
8707
|
* Clears the current filter for the aggregation column.
|
|
@@ -8761,8 +8810,10 @@ class AggregationListComponent {
|
|
|
8761
8810
|
* If the item is deselected, the selection count is decremented by 1.
|
|
8762
8811
|
*/
|
|
8763
8812
|
select() {
|
|
8764
|
-
this.
|
|
8765
|
-
this.
|
|
8813
|
+
const selectedItems = this.items().filter(item => item.$selected);
|
|
8814
|
+
this.onSelect.emit(selectedItems);
|
|
8815
|
+
// Keep apply visible if items are selected, or if active filters exist (user may be deselecting to clear)
|
|
8816
|
+
this.selection.set(selectedItems.length > 0 || this.hasFilters());
|
|
8766
8817
|
}
|
|
8767
8818
|
/**
|
|
8768
8819
|
* Updates the collapsed status on header click if the component is collapsible.
|
|
@@ -8881,13 +8932,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
8881
8932
|
}, template: "@if (aggregation()?.isTree) {\r\n <div class=\"p-2 text-sm text-red-500\">\r\n <i class=\"fa-fw fas fa-triangle-exclamation mr-1\"></i>\r\n The aggregation component no longer supports tree aggregations. Please use\r\n the <AggregationTree /> component instead.\r\n </div>\r\n}\r\n<details\r\n [attr.open]=\"expanded()\"\r\n [attr.name]=\"id()\"\r\n class=\"group space-y-2\"\r\n (toggle)=\"onToggle($event)\">\r\n <summary\r\n [class.cursor-pointer]=\"collapsible() && !isEmpty()\"\r\n [class.text-muted-foreground]=\"isEmpty()\"\r\n class=\"m-0 mt-1 flex h-8 w-full items-center gap-1 pl-1 font-semibold select-none\"\r\n (click)=\"onHeaderClick($event)\">\r\n <ng-content select=\"label\">\r\n @if (aggregation()?.icon) {\r\n <i class=\"fa-fw {{ aggregation()?.icon }} mr-1\" aria-hidden=\"true\"></i>\r\n }\r\n <span class=\"grow truncate\">{{\r\n aggregation()?.display | syslang | transloco\r\n }}</span>\r\n </ng-content>\r\n\r\n @if (showFiltersCount() && filtersCount() > 0) {\r\n <!-- count -->\r\n <Badge size=\"xs\" class=\"ml-1 pb-0.5\">\r\n {{ filtersCount() }}\r\n </Badge>\r\n }\r\n <!-- apply filter block -->\r\n @if (!isCollapsed()) {\r\n <ButtonGroup>\r\n @if (hasFilters()) {\r\n <button\r\n variant=\"outline\"\r\n size=\"icon\"\r\n class=\"size-6\"\r\n [attr.title]=\"'filters.clearFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.clearFilters' | transloco\"\r\n (click)=\"$event.stopPropagation(); clear()\">\r\n <i class=\"fa-fw far fa-filter-circle-xmark\"></i>\r\n <span class=\"sr-only\">{{\r\n \"filters.clearFilters\" | transloco\r\n }}</span>\r\n </button>\r\n }\r\n @if (selection()) {\r\n <button\r\n variant=\"primary\"\r\n size=\"xs\"\r\n [attr.title]=\"'filters.applyFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.applyFilters' | transloco\"\r\n (click)=\"$event.stopPropagation(); apply()\"\r\n class=\"h-4 px-1\">\r\n <FilterIcon class=\"size-4\" />\r\n {{ \"filters.apply\" | transloco }}\r\n </button>\r\n }\r\n\r\n <!-- select / unselect all -->\r\n @if (isAllSelected()) {\r\n <button\r\n variant=\"outline\"\r\n size=\"icon\"\r\n class=\"size-6\"\r\n [attr.title]=\"'filters.unselectAllFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.unselectAllFilters' | transloco\"\r\n (click)=\"$event.stopPropagation(); unselectAll()\">\r\n <i class=\"fa-fw far fa-check-square\"></i>\r\n <span class=\"sr-only\">{{\r\n \"filters.unselectAllFilters\" | transloco\r\n }}</span>\r\n </button>\r\n } @else {\r\n <button\r\n variant=\"outline\"\r\n size=\"icon\"\r\n class=\"size-6\"\r\n [attr.title]=\"'filters.selectAllFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.selectAllFilters' | transloco\"\r\n (click)=\"$event.stopPropagation(); selectAll()\">\r\n <i class=\"fa-fw far fa-square\"></i>\r\n <span class=\"sr-only\">{{\r\n \"filters.selectAllFilters\" | transloco\r\n }}</span>\r\n </button>\r\n }\r\n </ButtonGroup>\r\n }\r\n\r\n @if (collapsible()) {\r\n <button\r\n variant=\"none\"\r\n title=\"Open/Close\"\r\n class=\"cursor-pointer [&_svg]:transition-transform [&_svg]:duration-150 group-open:[&_svg]:rotate-90\">\r\n <chevronright />\r\n <span class=\"sr-only\">{{ \"filters.toggle\" | transloco }}</span>\r\n </button>\r\n }\r\n </summary>\r\n\r\n <!-- content wrapper -->\r\n @if (aggregation()?.searchable && items().length) {\r\n <InputGroup class=\"group/item mt-1\">\r\n <input\r\n #searchInput\r\n input-group\r\n id=\"aggregation-input-{{ column() }}\"\r\n type=\"text\"\r\n [attr.placeholder]=\"'search' | transloco\"\r\n [(ngModel)]=\"searchText\"\r\n class=\"mt-1\" />\r\n <InputGroupAddon>\r\n <SearchIcon\r\n class=\"text-foreground size-4 rotate-0 transition-[rotate] duration-500 group-focus-within/item:rotate-90\" />\r\n </InputGroupAddon>\r\n </InputGroup>\r\n }\r\n\r\n <div\r\n #scrollElement\r\n class=\"scrollbar-thin max-h-[calc(var(--height,100%)-100px)] w-full overflow-auto\">\r\n <div\r\n class=\"relative w-full\"\r\n [style.height]=\"virtualizer.getTotalSize() + 'px'\"\r\n role=\"list\"\r\n [attr.aria-label]=\"aggregation()?.display | syslang | transloco\">\r\n @for (vItem of virtualizer.getVirtualItems(); track vItem.index) {\r\n @let item = items()[vItem.index];\r\n <div\r\n class=\"absolute w-full\"\r\n [style.transform]=\"'translateY(' + vItem.start + 'px)'\"\r\n role=\"listitem\">\r\n <AggregationListItem\r\n [node]=\"item\"\r\n [field]=\"aggregation()?.column\"\r\n (onSelect)=\"select()\"\r\n (onFilter)=\"apply()\" />\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n @if (aggregation()?.$hasMore && this.searchedItems().length === 0) {\r\n <button\r\n variant=\"link\"\r\n class=\"mt-1 flex w-full justify-center\"\r\n [attr.aria-label]=\"'loadMore' | transloco\"\r\n (click)=\"loadMore()\">\r\n {{ \"loadMore\" | transloco }}\r\n </button>\r\n }\r\n</details>\r\n", styles: ["AggregationItem:has(+AggregationItem){margin-bottom:var(--agg-item-gap, 0)}\n"] }]
|
|
8882
8933
|
}], ctorParameters: () => [], propDecorators: { scrollElement: [{ type: i0.ViewChild, args: ["scrollElement", { isSignal: true }] }], searchInput: [{ type: i0.ViewChild, args: ["searchInput", { isSignal: true }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: true }] }], column: [{ type: i0.Input, args: [{ isSignal: true, alias: "column", required: true }] }], onSelect: [{ type: i0.Output, args: ["onSelect"] }], onApply: [{ type: i0.Output, args: ["onApply"] }], onClear: [{ type: i0.Output, args: ["onClear"] }], collapsible: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsible", required: false }] }], collapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsed", required: false }] }], searchable: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchable", required: false }] }], showFiltersCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "showFiltersCount", required: false }] }], searchText: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchText", required: false }] }, { type: i0.Output, args: ["searchTextChange"] }] } });
|
|
8883
8934
|
|
|
8935
|
+
const options = {
|
|
8936
|
+
year: 'numeric',
|
|
8937
|
+
month: '2-digit',
|
|
8938
|
+
day: '2-digit'
|
|
8939
|
+
};
|
|
8884
8940
|
class AggregationDateComponent extends AggregationListComponent {
|
|
8885
|
-
destroyRef;
|
|
8886
8941
|
dateRangeDialog = viewChild(AggregationDateRangeDialogComponent, ...(ngDevMode ? [{ debugName: "dateRangeDialog" }] : []));
|
|
8887
8942
|
title = input({ label: "Date", icon: "far fa-calendar-day" }, ...(ngDevMode ? [{ debugName: "title" }] : []));
|
|
8888
8943
|
displayEmptyDistributionIntervals = input(false, ...(ngDevMode ? [{ debugName: "displayEmptyDistributionIntervals" }] : []));
|
|
8889
8944
|
allowCustomRange = inject(FILTER_DATE_ALLOW_CUSTOM_RANGE);
|
|
8890
8945
|
transloco = inject(TranslocoService);
|
|
8946
|
+
name = input(null, ...(ngDevMode ? [{ debugName: "name" }] : []));
|
|
8891
8947
|
dateOptions = computed(() => translateAggregationToDateOptions(this.aggregation(), this.displayEmptyDistributionIntervals()), ...(ngDevMode ? [{ debugName: "dateOptions" }] : []));
|
|
8892
8948
|
form = new FormGroup({
|
|
8893
8949
|
option: new FormControl(null),
|
|
@@ -8900,26 +8956,28 @@ class AggregationDateComponent extends AggregationListComponent {
|
|
|
8900
8956
|
lang = signal(this.transloco.getActiveLang(), ...(ngDevMode ? [{ debugName: "lang" }] : []));
|
|
8901
8957
|
validSelection = signal(false, ...(ngDevMode ? [{ debugName: "validSelection" }] : []));
|
|
8902
8958
|
formValue = toSignal(this.form.valueChanges, { initialValue: this.form.value });
|
|
8903
|
-
|
|
8904
|
-
const
|
|
8905
|
-
|
|
8906
|
-
|
|
8907
|
-
|
|
8908
|
-
const
|
|
8909
|
-
return
|
|
8910
|
-
}, ...(ngDevMode ? [{ debugName: "
|
|
8911
|
-
constructor(
|
|
8959
|
+
customRangeFrom = computed(() => {
|
|
8960
|
+
const from = this.formValue().customRange?.from;
|
|
8961
|
+
return from ? new Date(from).toLocaleDateString(this.lang()) : "";
|
|
8962
|
+
}, ...(ngDevMode ? [{ debugName: "customRangeFrom" }] : []));
|
|
8963
|
+
customRangeTo = computed(() => {
|
|
8964
|
+
const to = this.formValue().customRange?.to;
|
|
8965
|
+
return to ? new Date(to).toLocaleDateString(this.lang()) : "";
|
|
8966
|
+
}, ...(ngDevMode ? [{ debugName: "customRangeTo" }] : []));
|
|
8967
|
+
constructor() {
|
|
8912
8968
|
super();
|
|
8913
|
-
this.destroyRef = destroyRef;
|
|
8914
8969
|
this.transloco.langChanges$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((lang) => {
|
|
8915
8970
|
this.lang.set(lang);
|
|
8916
8971
|
});
|
|
8917
8972
|
// apply current date filter from queryParamsStore
|
|
8918
8973
|
effect(() => {
|
|
8919
|
-
this.
|
|
8920
|
-
|
|
8921
|
-
|
|
8922
|
-
|
|
8974
|
+
const agg = this.aggregation();
|
|
8975
|
+
if (agg) {
|
|
8976
|
+
this.updateForm(this.queryParamsStore.getFilter({
|
|
8977
|
+
field: agg.column,
|
|
8978
|
+
name: agg.name
|
|
8979
|
+
}));
|
|
8980
|
+
}
|
|
8923
8981
|
});
|
|
8924
8982
|
this.form.valueChanges.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((changes) => {
|
|
8925
8983
|
this.validSelection.set(!!changes.option &&
|
|
@@ -8937,6 +8995,9 @@ class AggregationDateComponent extends AggregationListComponent {
|
|
|
8937
8995
|
}
|
|
8938
8996
|
return null;
|
|
8939
8997
|
}, ...(ngDevMode ? [{ debugName: "aggregation" }] : []));
|
|
8998
|
+
select() {
|
|
8999
|
+
this.selection.set(true);
|
|
9000
|
+
}
|
|
8940
9001
|
apply() {
|
|
8941
9002
|
try {
|
|
8942
9003
|
const filter = this.getFormValueFilter();
|
|
@@ -8965,7 +9026,12 @@ class AggregationDateComponent extends AggregationListComponent {
|
|
|
8965
9026
|
this.onClear.emit();
|
|
8966
9027
|
}
|
|
8967
9028
|
}
|
|
9029
|
+
selectAndOpenDialog() {
|
|
9030
|
+
this.select();
|
|
9031
|
+
this.dateRangeDialog()?.open();
|
|
9032
|
+
}
|
|
8968
9033
|
onRangeSelected(range) {
|
|
9034
|
+
console.log("Selected range:", range);
|
|
8969
9035
|
this.form.patchValue({
|
|
8970
9036
|
option: "custom-range",
|
|
8971
9037
|
customRange: { from: range.from, to: range.to }
|
|
@@ -8993,6 +9059,12 @@ class AggregationDateComponent extends AggregationListComponent {
|
|
|
8993
9059
|
from = filter.start;
|
|
8994
9060
|
to = filter.end;
|
|
8995
9061
|
break;
|
|
9062
|
+
case "and": {
|
|
9063
|
+
const filters = filter.filters;
|
|
9064
|
+
from = filters?.find((f) => f.operator === "gte")?.value ?? null;
|
|
9065
|
+
to = filters?.find((f) => f.operator === "lte")?.value ?? null;
|
|
9066
|
+
break;
|
|
9067
|
+
}
|
|
8996
9068
|
}
|
|
8997
9069
|
}
|
|
8998
9070
|
const formValue = {
|
|
@@ -9013,13 +9085,15 @@ class AggregationDateComponent extends AggregationListComponent {
|
|
|
9013
9085
|
if (value.option !== "custom-range") {
|
|
9014
9086
|
const dateOption = this.dateOptions().find((option) => option.display === value.option);
|
|
9015
9087
|
const aggregation = this.aggregation();
|
|
9016
|
-
|
|
9088
|
+
const name = aggregation?.name ?? this.name() ?? undefined;
|
|
9089
|
+
const column = aggregation?.column ?? this.column() ?? undefined;
|
|
9090
|
+
if (!name && !column) {
|
|
9017
9091
|
throw new Error("filters.aggregationNotFound");
|
|
9018
9092
|
}
|
|
9019
9093
|
return {
|
|
9020
|
-
name:
|
|
9094
|
+
name: name,
|
|
9021
9095
|
operator: dateOption?.operator || "eq",
|
|
9022
|
-
field:
|
|
9096
|
+
field: column,
|
|
9023
9097
|
display: dateOption?.display ?? "",
|
|
9024
9098
|
filters: dateOption?.filters,
|
|
9025
9099
|
value: dateOption?.value
|
|
@@ -9030,26 +9104,41 @@ class AggregationDateComponent extends AggregationListComponent {
|
|
|
9030
9104
|
// if from is null, operator is lte
|
|
9031
9105
|
// if both are not null, operator is between
|
|
9032
9106
|
const aggregation = this.aggregation();
|
|
9033
|
-
|
|
9107
|
+
const name = aggregation?.name ?? this.name() ?? undefined;
|
|
9108
|
+
const column = aggregation?.column ?? this.column() ?? undefined;
|
|
9109
|
+
if (!name && !column) {
|
|
9034
9110
|
throw new Error("filters.aggregationNotFound");
|
|
9035
9111
|
}
|
|
9036
9112
|
const filter = {
|
|
9037
|
-
name:
|
|
9038
|
-
field:
|
|
9113
|
+
name: name,
|
|
9114
|
+
field: column,
|
|
9039
9115
|
display: value.option
|
|
9040
9116
|
};
|
|
9117
|
+
// "en-CA" produces ISO 8601 date strings (YYYY-MM-DD) regardless of the user's locale.
|
|
9118
|
+
// This format is required by the query engine and avoids ambiguity caused by locale-specific
|
|
9119
|
+
// separators or month/day ordering (e.g. "04/09/2026" vs "09/04/2026").
|
|
9041
9120
|
if (value.customRange.from && value.customRange.to) {
|
|
9042
|
-
filter.operator = "
|
|
9043
|
-
filter.
|
|
9044
|
-
|
|
9121
|
+
filter.operator = "and";
|
|
9122
|
+
filter.filters = [
|
|
9123
|
+
{
|
|
9124
|
+
field: column,
|
|
9125
|
+
operator: "gte",
|
|
9126
|
+
value: new Date(value.customRange.from).toLocaleDateString("en-CA", options)
|
|
9127
|
+
},
|
|
9128
|
+
{
|
|
9129
|
+
field: column,
|
|
9130
|
+
operator: "lte",
|
|
9131
|
+
value: new Date(value.customRange.to).toLocaleDateString("en-CA", options)
|
|
9132
|
+
}
|
|
9133
|
+
];
|
|
9045
9134
|
}
|
|
9046
9135
|
else if (value.customRange.from) {
|
|
9047
9136
|
filter.operator = "gte";
|
|
9048
|
-
filter.value = value.customRange.from;
|
|
9137
|
+
filter.value = new Date(value.customRange.from).toLocaleDateString("en-CA", options);
|
|
9049
9138
|
}
|
|
9050
9139
|
else if (value.customRange.to) {
|
|
9051
9140
|
filter.operator = "lte";
|
|
9052
|
-
filter.value = value.customRange.to;
|
|
9141
|
+
filter.value = new Date(value.customRange.to).toLocaleDateString("en-CA", options);
|
|
9053
9142
|
}
|
|
9054
9143
|
else {
|
|
9055
9144
|
throw new Error("filters.customRangeInvalid");
|
|
@@ -9058,12 +9147,13 @@ class AggregationDateComponent extends AggregationListComponent {
|
|
|
9058
9147
|
}
|
|
9059
9148
|
throw new Error("filters.filterInvalid");
|
|
9060
9149
|
}
|
|
9061
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: AggregationDateComponent, deps: [
|
|
9062
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: AggregationDateComponent, isStandalone: true, selector: "aggregation-date, AggregationDate, aggregationdate", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, displayEmptyDistributionIntervals: { classPropertyName: "displayEmptyDistributionIntervals", publicName: "displayEmptyDistributionIntervals", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "@container" }, providers: [provideTranslocoScope("filters")], viewQueries: [{ propertyName: "dateRangeDialog", first: true, predicate: AggregationDateRangeDialogComponent, descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<details [attr.open]=\"expanded()\" [attr.name]=\"id()\" class=\"group space-y-2\">\r\n <summary\r\n [class.cursor-pointer]=\"collapsible()\"\r\n class=\"m-0 flex h-8 w-full items-center pl-1 font-semibold select-none\"\r\n (click)=\"onHeaderClick($event)\">\r\n <ng-content select=\"label\">\r\n @if (aggregation()?.icon) {\r\n <i class=\"fa-fw {{ aggregation()?.icon }} mr-1\" aria-hidden=\"true\"></i>\r\n }\r\n <span class=\"grow\">{{\r\n aggregation()?.display | syslang | transloco\r\n }}</span>\r\n </ng-content>\r\n\r\n @if (hasFilters()) {\r\n <button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n [attr.title]=\"'filters.clearFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.clearFilters' | transloco\"\r\n (click)=\"clear()\"\r\n (keydown.enter)=\"clear()\">\r\n <i class=\"fa-fw far fa-filter-circle-xmark\" aria-hidden=\"true\"></i>\r\n <span class=\"sr-only\">{{ \"filters.clearFilters\" | transloco }}</span>\r\n </button>\r\n }\r\n\r\n @if (selection() && validSelection()) {\r\n <button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n [attr.title]=\"'filters.applyFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.applyFilters' | transloco\"\r\n (click)=\"apply()\"\r\n (keydown.enter)=\"apply()\">\r\n <i class=\"fa-fw far fa-filter\" aria-hidden=\"true\"></i>\r\n <span class=\"sr-only\">{{ \"filters.applyFilters\" | transloco }}</span>\r\n </button>\r\n }\r\n @if (collapsible()) {\r\n <button\r\n variant=\"none\"\r\n title=\"Open/Close\"\r\n class=\"cursor-pointer [&_svg]:transition-transform [&_svg]:duration-150 group-open:[&_svg]:rotate-90\">\r\n <chevronright />\r\n </button>\r\n }\r\n </summary>\r\n\r\n <!-- content wrapper -->\r\n <form [formGroup]=\"form\">\r\n <ul\r\n class=\"scrollbar-thin flex max-h-[calc(var(--height,100%)-100px)] snap-y snap-start flex-col gap-1 overflow-auto pt-2\"\r\n role=\"list\">\r\n @for (option of dateOptions(); track $index) {\r\n <li\r\n role=\"listitem\"\r\n tabindex=\"0\"\r\n (click)=\"radio.click()\"\r\n [attr.aria-label]=\"option.display | syslang | transloco\"\r\n [class]=\"\r\n cn(\r\n 'flex p-0 px-2 leading-7',\r\n form.get('option')?.value === option.display && 'bg-accent',\r\n option.hidden && 'hidden',\r\n option.disabled && 'disabled pointer-events-none text-neutral-300'\r\n )\r\n \"\r\n [attr.aria-hidden]=\"option.disabled\">\r\n <input\r\n #radio\r\n type=\"radio\"\r\n formControlName=\"option\"\r\n id=\"date-filter-{{ option.display }}\"\r\n [attr.disabled]=\"option.disabled ? true : null\"\r\n [attr.aria-disabled]=\"option.disabled\"\r\n (click)=\"select()\"\r\n value=\"{{ option.display }}\" />\r\n\r\n <label\r\n for=\"date-filter-{{ option.display }}\"\r\n class=\"grow cursor-pointer p-1\">\r\n {{ option.display | syslang | transloco }}\r\n </label>\r\n </li>\r\n }\r\n\r\n @if (allowCustomRange) {\r\n <li\r\n role=\"listitem\"\r\n aria-label=\"open date range picker\"\r\n class=\"flex px-2 leading-7\"\r\n [class.select]=\"form.get('option')?.value === 'custom-range'\">\r\n <input\r\n type=\"radio\"\r\n formControlName=\"option\"\r\n id=\"date-filter-range-dialog\"\r\n value=\"custom-range\"\r\n (click)=\"select()\" />\r\n
|
|
9150
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: AggregationDateComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
9151
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: AggregationDateComponent, isStandalone: true, selector: "aggregation-date, AggregationDate, aggregationdate", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, displayEmptyDistributionIntervals: { classPropertyName: "displayEmptyDistributionIntervals", publicName: "displayEmptyDistributionIntervals", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "@container" }, providers: [provideTranslocoScope("filters")], viewQueries: [{ propertyName: "dateRangeDialog", first: true, predicate: AggregationDateRangeDialogComponent, descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<details [attr.open]=\"expanded()\" [attr.name]=\"id()\" class=\"group space-y-2\">\r\n <summary\r\n [class.cursor-pointer]=\"collapsible()\"\r\n class=\"m-0 flex h-8 w-full items-center pl-1 font-semibold select-none\"\r\n (click)=\"onHeaderClick($event)\">\r\n <ng-content select=\"label\">\r\n @if (aggregation()?.icon) {\r\n <i class=\"fa-fw {{ aggregation()?.icon }} mr-1\" aria-hidden=\"true\"></i>\r\n }\r\n <span class=\"grow\">{{\r\n aggregation()?.display | syslang | transloco\r\n }}</span>\r\n </ng-content>\r\n\r\n @if (hasFilters()) {\r\n <button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n [attr.title]=\"'filters.clearFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.clearFilters' | transloco\"\r\n (click)=\"clear()\"\r\n (keydown.enter)=\"clear()\">\r\n <i class=\"fa-fw far fa-filter-circle-xmark\" aria-hidden=\"true\"></i>\r\n <span class=\"sr-only\">{{ \"filters.clearFilters\" | transloco }}</span>\r\n </button>\r\n }\r\n\r\n @if (selection() && validSelection()) {\r\n <button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n [attr.title]=\"'filters.applyFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.applyFilters' | transloco\"\r\n (click)=\"apply()\"\r\n (keydown.enter)=\"apply()\">\r\n <i class=\"fa-fw far fa-filter\" aria-hidden=\"true\"></i>\r\n <span class=\"sr-only\">{{ \"filters.applyFilters\" | transloco }}</span>\r\n </button>\r\n }\r\n @if (collapsible()) {\r\n <button\r\n variant=\"none\"\r\n title=\"Open/Close\"\r\n class=\"cursor-pointer [&_svg]:transition-transform [&_svg]:duration-150 group-open:[&_svg]:rotate-90\">\r\n <chevronright />\r\n </button>\r\n }\r\n </summary>\r\n\r\n <!-- content wrapper -->\r\n <form [formGroup]=\"form\">\r\n <ul\r\n class=\"scrollbar-thin flex max-h-[calc(var(--height,100%)-100px)] snap-y snap-start flex-col gap-1 overflow-auto pt-2\"\r\n role=\"list\">\r\n @for (option of dateOptions(); track $index) {\r\n <li\r\n role=\"listitem\"\r\n tabindex=\"0\"\r\n (click)=\"radio.click()\"\r\n [attr.aria-label]=\"option.display | syslang | transloco\"\r\n [class]=\"\r\n cn(\r\n 'flex p-0 px-2 leading-7',\r\n form.get('option')?.value === option.display && 'bg-accent',\r\n option.hidden && 'hidden',\r\n option.disabled && 'disabled pointer-events-none text-neutral-300'\r\n )\r\n \"\r\n [attr.aria-hidden]=\"option.disabled\">\r\n <input\r\n #radio\r\n type=\"radio\"\r\n formControlName=\"option\"\r\n id=\"date-filter-{{ option.display }}\"\r\n [attr.disabled]=\"option.disabled ? true : null\"\r\n [attr.aria-disabled]=\"option.disabled\"\r\n (click)=\"select()\"\r\n value=\"{{ option.display }}\" />\r\n\r\n <label\r\n for=\"date-filter-{{ option.display }}\"\r\n class=\"grow cursor-pointer p-1\">\r\n {{ option.display | syslang | transloco }}\r\n </label>\r\n </li>\r\n }\r\n\r\n @if (allowCustomRange) {\r\n <li\r\n role=\"listitem\"\r\n aria-label=\"open date range picker\"\r\n class=\"flex px-2 leading-7\"\r\n [class.select]=\"form.get('option')?.value === 'custom-range'\">\r\n <input\r\n type=\"radio\"\r\n formControlName=\"option\"\r\n id=\"date-filter-range-dialog\"\r\n value=\"custom-range\"\r\n (click)=\"select()\" />\r\n <div\r\n class=\"@container flex grow justify-end gap-1 p-1 @max-[340px]:flex-wrap\">\r\n <div class=\"flex gap-1\">\r\n <label for=\"datepicker-range-start\" class=\"min-w-10 truncate\">{{\r\n \"filters.from\" | transloco\r\n }}</label>\r\n <input\r\n id=\"datepicker-range-start\"\r\n name=\"start\"\r\n type=\"text\"\r\n readonly\r\n class=\"h-8 max-w-[13ch] min-w-[13ch]\"\r\n [value]=\"customRangeFrom()\"\r\n (click)=\"selectAndOpenDialog()\" />\r\n </div>\r\n <div class=\"flex gap-1\">\r\n <label\r\n for=\"datepicker-range-end\"\r\n class=\"min-w-10 truncate text-right\"\r\n >{{ \"filters.to\" | transloco }}</label\r\n >\r\n <input\r\n id=\"datepicker-range-end\"\r\n name=\"end\"\r\n type=\"text\"\r\n readonly\r\n class=\"h-8 max-w-[13ch] min-w-[13ch]\"\r\n [value]=\"customRangeTo()\"\r\n (click)=\"selectAndOpenDialog()\" />\r\n </div>\r\n </div>\r\n </li>\r\n }\r\n </ul>\r\n </form>\r\n</details>\r\n\r\n<aggregation-date-range-dialog\r\n [lang]=\"lang()\"\r\n [useDateRange]=\"false\"\r\n [min]=\"form.get('customRange.from')?.value || undefined\"\r\n [max]=\"form.get('customRange.to')?.value || undefined\"\r\n (rangeSelected)=\"onRangeSelected($event)\" />\r\n", styles: [":host{display:block;min-width:200px}ul[role=list]{scrollbar-width:thin}\n"], dependencies: [{ kind: "directive", type: InputComponent, selector: "input[type=\"text\"], input[type=\"email\"], input[type=\"number\"], input[type=\"password\"], input[type=\"tel\"], input[type=\"url\"], input[type=\"time\"], input[type=\"file\"]", inputs: ["class", "variant", "decoration"] }, { kind: "directive", type: ButtonComponent, selector: "button", inputs: ["class", "variant", "decoration", "scheme", "iconOnly", "size"] }, { kind: "directive", type: ListItemComponent, selector: "[role=\"listitem\"], [role=\"option\"]", inputs: ["class", "variant", "decoration"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.RadioControlValueAccessor, selector: "input[type=radio][formControlName],input[type=radio][formControl],input[type=radio][ngModel]", inputs: ["name", "formControlName", "value"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: ChevronRightIcon, selector: "chevron-right, ChevronRight, chevronright, ChevronRightIcon", inputs: ["class"] }, { kind: "component", type: AggregationDateRangeDialogComponent, selector: "aggregation-date-range-dialog", inputs: ["min", "max", "lang", "useDateRange"], outputs: ["rangeSelected"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }, { kind: "pipe", type: SyslangPipe, name: "syslang" }] });
|
|
9063
9152
|
}
|
|
9064
9153
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: AggregationDateComponent, decorators: [{
|
|
9065
9154
|
type: Component,
|
|
9066
9155
|
args: [{ selector: "aggregation-date, AggregationDate, aggregationdate", standalone: true, providers: [provideTranslocoScope("filters")], imports: [
|
|
9156
|
+
InputComponent,
|
|
9067
9157
|
ButtonComponent,
|
|
9068
9158
|
ListItemComponent,
|
|
9069
9159
|
ReactiveFormsModule,
|
|
@@ -9073,8 +9163,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
9073
9163
|
AggregationDateRangeDialogComponent
|
|
9074
9164
|
], host: {
|
|
9075
9165
|
class: "@container"
|
|
9076
|
-
}, template: "<details [attr.open]=\"expanded()\" [attr.name]=\"id()\" class=\"group space-y-2\">\r\n <summary\r\n [class.cursor-pointer]=\"collapsible()\"\r\n class=\"m-0 flex h-8 w-full items-center pl-1 font-semibold select-none\"\r\n (click)=\"onHeaderClick($event)\">\r\n <ng-content select=\"label\">\r\n @if (aggregation()?.icon) {\r\n <i class=\"fa-fw {{ aggregation()?.icon }} mr-1\" aria-hidden=\"true\"></i>\r\n }\r\n <span class=\"grow\">{{\r\n aggregation()?.display | syslang | transloco\r\n }}</span>\r\n </ng-content>\r\n\r\n @if (hasFilters()) {\r\n <button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n [attr.title]=\"'filters.clearFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.clearFilters' | transloco\"\r\n (click)=\"clear()\"\r\n (keydown.enter)=\"clear()\">\r\n <i class=\"fa-fw far fa-filter-circle-xmark\" aria-hidden=\"true\"></i>\r\n <span class=\"sr-only\">{{ \"filters.clearFilters\" | transloco }}</span>\r\n </button>\r\n }\r\n\r\n @if (selection() && validSelection()) {\r\n <button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n [attr.title]=\"'filters.applyFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.applyFilters' | transloco\"\r\n (click)=\"apply()\"\r\n (keydown.enter)=\"apply()\">\r\n <i class=\"fa-fw far fa-filter\" aria-hidden=\"true\"></i>\r\n <span class=\"sr-only\">{{ \"filters.applyFilters\" | transloco }}</span>\r\n </button>\r\n }\r\n @if (collapsible()) {\r\n <button\r\n variant=\"none\"\r\n title=\"Open/Close\"\r\n class=\"cursor-pointer [&_svg]:transition-transform [&_svg]:duration-150 group-open:[&_svg]:rotate-90\">\r\n <chevronright />\r\n </button>\r\n }\r\n </summary>\r\n\r\n <!-- content wrapper -->\r\n <form [formGroup]=\"form\">\r\n <ul\r\n class=\"scrollbar-thin flex max-h-[calc(var(--height,100%)-100px)] snap-y snap-start flex-col gap-1 overflow-auto pt-2\"\r\n role=\"list\">\r\n @for (option of dateOptions(); track $index) {\r\n <li\r\n role=\"listitem\"\r\n tabindex=\"0\"\r\n (click)=\"radio.click()\"\r\n [attr.aria-label]=\"option.display | syslang | transloco\"\r\n [class]=\"\r\n cn(\r\n 'flex p-0 px-2 leading-7',\r\n form.get('option')?.value === option.display && 'bg-accent',\r\n option.hidden && 'hidden',\r\n option.disabled && 'disabled pointer-events-none text-neutral-300'\r\n )\r\n \"\r\n [attr.aria-hidden]=\"option.disabled\">\r\n <input\r\n #radio\r\n type=\"radio\"\r\n formControlName=\"option\"\r\n id=\"date-filter-{{ option.display }}\"\r\n [attr.disabled]=\"option.disabled ? true : null\"\r\n [attr.aria-disabled]=\"option.disabled\"\r\n (click)=\"select()\"\r\n value=\"{{ option.display }}\" />\r\n\r\n <label\r\n for=\"date-filter-{{ option.display }}\"\r\n class=\"grow cursor-pointer p-1\">\r\n {{ option.display | syslang | transloco }}\r\n </label>\r\n </li>\r\n }\r\n\r\n @if (allowCustomRange) {\r\n <li\r\n role=\"listitem\"\r\n aria-label=\"open date range picker\"\r\n class=\"flex px-2 leading-7\"\r\n [class.select]=\"form.get('option')?.value === 'custom-range'\">\r\n <input\r\n type=\"radio\"\r\n formControlName=\"option\"\r\n id=\"date-filter-range-dialog\"\r\n value=\"custom-range\"\r\n (click)=\"select()\" />\r\n
|
|
9077
|
-
}], ctorParameters: () => [
|
|
9166
|
+
}, template: "<details [attr.open]=\"expanded()\" [attr.name]=\"id()\" class=\"group space-y-2\">\r\n <summary\r\n [class.cursor-pointer]=\"collapsible()\"\r\n class=\"m-0 flex h-8 w-full items-center pl-1 font-semibold select-none\"\r\n (click)=\"onHeaderClick($event)\">\r\n <ng-content select=\"label\">\r\n @if (aggregation()?.icon) {\r\n <i class=\"fa-fw {{ aggregation()?.icon }} mr-1\" aria-hidden=\"true\"></i>\r\n }\r\n <span class=\"grow\">{{\r\n aggregation()?.display | syslang | transloco\r\n }}</span>\r\n </ng-content>\r\n\r\n @if (hasFilters()) {\r\n <button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n [attr.title]=\"'filters.clearFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.clearFilters' | transloco\"\r\n (click)=\"clear()\"\r\n (keydown.enter)=\"clear()\">\r\n <i class=\"fa-fw far fa-filter-circle-xmark\" aria-hidden=\"true\"></i>\r\n <span class=\"sr-only\">{{ \"filters.clearFilters\" | transloco }}</span>\r\n </button>\r\n }\r\n\r\n @if (selection() && validSelection()) {\r\n <button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n [attr.title]=\"'filters.applyFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.applyFilters' | transloco\"\r\n (click)=\"apply()\"\r\n (keydown.enter)=\"apply()\">\r\n <i class=\"fa-fw far fa-filter\" aria-hidden=\"true\"></i>\r\n <span class=\"sr-only\">{{ \"filters.applyFilters\" | transloco }}</span>\r\n </button>\r\n }\r\n @if (collapsible()) {\r\n <button\r\n variant=\"none\"\r\n title=\"Open/Close\"\r\n class=\"cursor-pointer [&_svg]:transition-transform [&_svg]:duration-150 group-open:[&_svg]:rotate-90\">\r\n <chevronright />\r\n </button>\r\n }\r\n </summary>\r\n\r\n <!-- content wrapper -->\r\n <form [formGroup]=\"form\">\r\n <ul\r\n class=\"scrollbar-thin flex max-h-[calc(var(--height,100%)-100px)] snap-y snap-start flex-col gap-1 overflow-auto pt-2\"\r\n role=\"list\">\r\n @for (option of dateOptions(); track $index) {\r\n <li\r\n role=\"listitem\"\r\n tabindex=\"0\"\r\n (click)=\"radio.click()\"\r\n [attr.aria-label]=\"option.display | syslang | transloco\"\r\n [class]=\"\r\n cn(\r\n 'flex p-0 px-2 leading-7',\r\n form.get('option')?.value === option.display && 'bg-accent',\r\n option.hidden && 'hidden',\r\n option.disabled && 'disabled pointer-events-none text-neutral-300'\r\n )\r\n \"\r\n [attr.aria-hidden]=\"option.disabled\">\r\n <input\r\n #radio\r\n type=\"radio\"\r\n formControlName=\"option\"\r\n id=\"date-filter-{{ option.display }}\"\r\n [attr.disabled]=\"option.disabled ? true : null\"\r\n [attr.aria-disabled]=\"option.disabled\"\r\n (click)=\"select()\"\r\n value=\"{{ option.display }}\" />\r\n\r\n <label\r\n for=\"date-filter-{{ option.display }}\"\r\n class=\"grow cursor-pointer p-1\">\r\n {{ option.display | syslang | transloco }}\r\n </label>\r\n </li>\r\n }\r\n\r\n @if (allowCustomRange) {\r\n <li\r\n role=\"listitem\"\r\n aria-label=\"open date range picker\"\r\n class=\"flex px-2 leading-7\"\r\n [class.select]=\"form.get('option')?.value === 'custom-range'\">\r\n <input\r\n type=\"radio\"\r\n formControlName=\"option\"\r\n id=\"date-filter-range-dialog\"\r\n value=\"custom-range\"\r\n (click)=\"select()\" />\r\n <div\r\n class=\"@container flex grow justify-end gap-1 p-1 @max-[340px]:flex-wrap\">\r\n <div class=\"flex gap-1\">\r\n <label for=\"datepicker-range-start\" class=\"min-w-10 truncate\">{{\r\n \"filters.from\" | transloco\r\n }}</label>\r\n <input\r\n id=\"datepicker-range-start\"\r\n name=\"start\"\r\n type=\"text\"\r\n readonly\r\n class=\"h-8 max-w-[13ch] min-w-[13ch]\"\r\n [value]=\"customRangeFrom()\"\r\n (click)=\"selectAndOpenDialog()\" />\r\n </div>\r\n <div class=\"flex gap-1\">\r\n <label\r\n for=\"datepicker-range-end\"\r\n class=\"min-w-10 truncate text-right\"\r\n >{{ \"filters.to\" | transloco }}</label\r\n >\r\n <input\r\n id=\"datepicker-range-end\"\r\n name=\"end\"\r\n type=\"text\"\r\n readonly\r\n class=\"h-8 max-w-[13ch] min-w-[13ch]\"\r\n [value]=\"customRangeTo()\"\r\n (click)=\"selectAndOpenDialog()\" />\r\n </div>\r\n </div>\r\n </li>\r\n }\r\n </ul>\r\n </form>\r\n</details>\r\n\r\n<aggregation-date-range-dialog\r\n [lang]=\"lang()\"\r\n [useDateRange]=\"false\"\r\n [min]=\"form.get('customRange.from')?.value || undefined\"\r\n [max]=\"form.get('customRange.to')?.value || undefined\"\r\n (rangeSelected)=\"onRangeSelected($event)\" />\r\n", styles: [":host{display:block;min-width:200px}ul[role=list]{scrollbar-width:thin}\n"] }]
|
|
9167
|
+
}], ctorParameters: () => [], propDecorators: { dateRangeDialog: [{ type: i0.ViewChild, args: [i0.forwardRef(() => AggregationDateRangeDialogComponent), { isSignal: true }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], displayEmptyDistributionIntervals: [{ type: i0.Input, args: [{ isSignal: true, alias: "displayEmptyDistributionIntervals", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }] } });
|
|
9078
9168
|
|
|
9079
9169
|
/**
|
|
9080
9170
|
* Component that allows users to select a date or a date range for filtering search results.
|
|
@@ -9083,7 +9173,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
9083
9173
|
*/
|
|
9084
9174
|
class DateComponent extends AggregationDateComponent {
|
|
9085
9175
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: DateComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
9086
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: DateComponent, isStandalone: true, selector: "date-filter,DateFilter", host: { classAttribute: "@container" }, providers: [provideTranslocoScope("filters")], usesInheritance: true, ngImport: i0, template: "<details [attr.open]=\"expanded()\" [attr.name]=\"id()\" class=\"group space-y-2\">\r\n <summary\r\n [class.cursor-pointer]=\"collapsible()\"\r\n class=\"m-0 flex h-8 w-full items-center pl-1 font-semibold select-none\"\r\n (click)=\"onHeaderClick($event)\">\r\n <ng-content select=\"label\">\r\n @if (aggregation()?.icon) {\r\n <i class=\"fa-fw {{ aggregation()?.icon }} mr-1\" aria-hidden=\"true\"></i>\r\n }\r\n <span class=\"grow\">{{\r\n aggregation()?.display | syslang | transloco\r\n }}</span>\r\n </ng-content>\r\n\r\n @if (hasFilters()) {\r\n <button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n [attr.title]=\"'filters.clearFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.clearFilters' | transloco\"\r\n (click)=\"clear()\"\r\n (keydown.enter)=\"clear()\">\r\n <i class=\"fa-fw far fa-filter-circle-xmark\" aria-hidden=\"true\"></i>\r\n <span class=\"sr-only\">{{ \"filters.clearFilters\" | transloco }}</span>\r\n </button>\r\n }\r\n\r\n @if (selection() && validSelection()) {\r\n <button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n [attr.title]=\"'filters.applyFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.applyFilters' | transloco\"\r\n (click)=\"apply()\"\r\n (keydown.enter)=\"apply()\">\r\n <i class=\"fa-fw far fa-filter\" aria-hidden=\"true\"></i>\r\n <span class=\"sr-only\">{{ \"filters.applyFilters\" | transloco }}</span>\r\n </button>\r\n }\r\n @if (collapsible()) {\r\n <button\r\n variant=\"none\"\r\n title=\"Open/Close\"\r\n class=\"cursor-pointer [&_svg]:transition-transform [&_svg]:duration-150 group-open:[&_svg]:rotate-90\">\r\n <chevronright />\r\n </button>\r\n }\r\n </summary>\r\n\r\n <!-- content wrapper -->\r\n <form [formGroup]=\"form\">\r\n <ul\r\n class=\"scrollbar-thin flex max-h-[calc(var(--height,100%)-100px)] snap-y snap-start flex-col gap-1 overflow-auto pt-2\"\r\n role=\"list\">\r\n @for (option of dateOptions(); track $index) {\r\n <li\r\n role=\"listitem\"\r\n tabindex=\"0\"\r\n (click)=\"radio.click()\"\r\n [attr.aria-label]=\"option.display | syslang | transloco\"\r\n [class]=\"\r\n cn(\r\n 'flex p-0 px-2 leading-7',\r\n form.get('option')?.value === option.display && 'bg-accent',\r\n option.hidden && 'hidden',\r\n option.disabled && 'disabled pointer-events-none text-neutral-300'\r\n )\r\n \"\r\n [attr.aria-hidden]=\"option.disabled\">\r\n <input\r\n #radio\r\n type=\"radio\"\r\n formControlName=\"option\"\r\n id=\"date-filter-{{ option.display }}\"\r\n [attr.disabled]=\"option.disabled ? true : null\"\r\n [attr.aria-disabled]=\"option.disabled\"\r\n (click)=\"select()\"\r\n value=\"{{ option.display }}\" />\r\n\r\n <label\r\n for=\"date-filter-{{ option.display }}\"\r\n class=\"grow cursor-pointer p-1\">\r\n {{ option.display | syslang | transloco }}\r\n </label>\r\n </li>\r\n }\r\n\r\n @if (allowCustomRange) {\r\n <li\r\n role=\"listitem\"\r\n aria-label=\"open date range picker\"\r\n class=\"flex px-2 leading-7\"\r\n [class.select]=\"form.get('option')?.value === 'custom-range'\">\r\n <input\r\n type=\"radio\"\r\n formControlName=\"option\"\r\n id=\"date-filter-range-dialog\"\r\n value=\"custom-range\"\r\n (click)=\"select()\" />\r\n
|
|
9176
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: DateComponent, isStandalone: true, selector: "date-filter,DateFilter", host: { classAttribute: "@container" }, providers: [provideTranslocoScope("filters")], usesInheritance: true, ngImport: i0, template: "<details [attr.open]=\"expanded()\" [attr.name]=\"id()\" class=\"group space-y-2\">\r\n <summary\r\n [class.cursor-pointer]=\"collapsible()\"\r\n class=\"m-0 flex h-8 w-full items-center pl-1 font-semibold select-none\"\r\n (click)=\"onHeaderClick($event)\">\r\n <ng-content select=\"label\">\r\n @if (aggregation()?.icon) {\r\n <i class=\"fa-fw {{ aggregation()?.icon }} mr-1\" aria-hidden=\"true\"></i>\r\n }\r\n <span class=\"grow\">{{\r\n aggregation()?.display | syslang | transloco\r\n }}</span>\r\n </ng-content>\r\n\r\n @if (hasFilters()) {\r\n <button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n [attr.title]=\"'filters.clearFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.clearFilters' | transloco\"\r\n (click)=\"clear()\"\r\n (keydown.enter)=\"clear()\">\r\n <i class=\"fa-fw far fa-filter-circle-xmark\" aria-hidden=\"true\"></i>\r\n <span class=\"sr-only\">{{ \"filters.clearFilters\" | transloco }}</span>\r\n </button>\r\n }\r\n\r\n @if (selection() && validSelection()) {\r\n <button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n [attr.title]=\"'filters.applyFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.applyFilters' | transloco\"\r\n (click)=\"apply()\"\r\n (keydown.enter)=\"apply()\">\r\n <i class=\"fa-fw far fa-filter\" aria-hidden=\"true\"></i>\r\n <span class=\"sr-only\">{{ \"filters.applyFilters\" | transloco }}</span>\r\n </button>\r\n }\r\n @if (collapsible()) {\r\n <button\r\n variant=\"none\"\r\n title=\"Open/Close\"\r\n class=\"cursor-pointer [&_svg]:transition-transform [&_svg]:duration-150 group-open:[&_svg]:rotate-90\">\r\n <chevronright />\r\n </button>\r\n }\r\n </summary>\r\n\r\n <!-- content wrapper -->\r\n <form [formGroup]=\"form\">\r\n <ul\r\n class=\"scrollbar-thin flex max-h-[calc(var(--height,100%)-100px)] snap-y snap-start flex-col gap-1 overflow-auto pt-2\"\r\n role=\"list\">\r\n @for (option of dateOptions(); track $index) {\r\n <li\r\n role=\"listitem\"\r\n tabindex=\"0\"\r\n (click)=\"radio.click()\"\r\n [attr.aria-label]=\"option.display | syslang | transloco\"\r\n [class]=\"\r\n cn(\r\n 'flex p-0 px-2 leading-7',\r\n form.get('option')?.value === option.display && 'bg-accent',\r\n option.hidden && 'hidden',\r\n option.disabled && 'disabled pointer-events-none text-neutral-300'\r\n )\r\n \"\r\n [attr.aria-hidden]=\"option.disabled\">\r\n <input\r\n #radio\r\n type=\"radio\"\r\n formControlName=\"option\"\r\n id=\"date-filter-{{ option.display }}\"\r\n [attr.disabled]=\"option.disabled ? true : null\"\r\n [attr.aria-disabled]=\"option.disabled\"\r\n (click)=\"select()\"\r\n value=\"{{ option.display }}\" />\r\n\r\n <label\r\n for=\"date-filter-{{ option.display }}\"\r\n class=\"grow cursor-pointer p-1\">\r\n {{ option.display | syslang | transloco }}\r\n </label>\r\n </li>\r\n }\r\n\r\n @if (allowCustomRange) {\r\n <li\r\n role=\"listitem\"\r\n aria-label=\"open date range picker\"\r\n class=\"flex px-2 leading-7\"\r\n [class.select]=\"form.get('option')?.value === 'custom-range'\">\r\n <input\r\n type=\"radio\"\r\n formControlName=\"option\"\r\n id=\"date-filter-range-dialog\"\r\n value=\"custom-range\"\r\n (click)=\"select()\" />\r\n <div\r\n class=\"@container flex grow justify-end gap-1 p-1 @max-[340px]:flex-wrap\">\r\n <div class=\"flex gap-1\">\r\n <label for=\"datepicker-range-start\" class=\"min-w-10 truncate\">{{\r\n \"filters.from\" | transloco\r\n }}</label>\r\n <input\r\n id=\"datepicker-range-start\"\r\n name=\"start\"\r\n type=\"text\"\r\n readonly\r\n class=\"h-8 max-w-[13ch] min-w-[13ch]\"\r\n [value]=\"customRangeFrom()\"\r\n (click)=\"selectAndOpenDialog()\" />\r\n </div>\r\n <div class=\"flex gap-1\">\r\n <label\r\n for=\"datepicker-range-end\"\r\n class=\"min-w-10 truncate text-right\"\r\n >{{ \"filters.to\" | transloco }}</label\r\n >\r\n <input\r\n id=\"datepicker-range-end\"\r\n name=\"end\"\r\n type=\"text\"\r\n readonly\r\n class=\"h-8 max-w-[13ch] min-w-[13ch]\"\r\n [value]=\"customRangeTo()\"\r\n (click)=\"selectAndOpenDialog()\" />\r\n </div>\r\n </div>\r\n </li>\r\n }\r\n </ul>\r\n </form>\r\n</details>\r\n\r\n<aggregation-date-range-dialog\r\n [lang]=\"lang()\"\r\n [useDateRange]=\"false\"\r\n [min]=\"form.get('customRange.from')?.value || undefined\"\r\n [max]=\"form.get('customRange.to')?.value || undefined\"\r\n (rangeSelected)=\"onRangeSelected($event)\" />\r\n", styles: [":host{display:block;min-width:200px}ul[role=list]{scrollbar-width:thin}\n"], dependencies: [{ kind: "directive", type: ButtonComponent, selector: "button", inputs: ["class", "variant", "decoration", "scheme", "iconOnly", "size"] }, { kind: "directive", type: ListItemComponent, selector: "[role=\"listitem\"], [role=\"option\"]", inputs: ["class", "variant", "decoration"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.RadioControlValueAccessor, selector: "input[type=radio][formControlName],input[type=radio][formControl],input[type=radio][ngModel]", inputs: ["name", "formControlName", "value"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: ChevronRightIcon, selector: "chevron-right, ChevronRight, chevronright, ChevronRightIcon", inputs: ["class"] }, { kind: "component", type: AggregationDateRangeDialogComponent, selector: "aggregation-date-range-dialog", inputs: ["min", "max", "lang", "useDateRange"], outputs: ["rangeSelected"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }, { kind: "pipe", type: SyslangPipe, name: "syslang" }] });
|
|
9087
9177
|
}
|
|
9088
9178
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: DateComponent, decorators: [{
|
|
9089
9179
|
type: Component,
|
|
@@ -9097,7 +9187,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
9097
9187
|
AggregationDateRangeDialogComponent
|
|
9098
9188
|
], host: {
|
|
9099
9189
|
class: "@container"
|
|
9100
|
-
}, template: "<details [attr.open]=\"expanded()\" [attr.name]=\"id()\" class=\"group space-y-2\">\r\n <summary\r\n [class.cursor-pointer]=\"collapsible()\"\r\n class=\"m-0 flex h-8 w-full items-center pl-1 font-semibold select-none\"\r\n (click)=\"onHeaderClick($event)\">\r\n <ng-content select=\"label\">\r\n @if (aggregation()?.icon) {\r\n <i class=\"fa-fw {{ aggregation()?.icon }} mr-1\" aria-hidden=\"true\"></i>\r\n }\r\n <span class=\"grow\">{{\r\n aggregation()?.display | syslang | transloco\r\n }}</span>\r\n </ng-content>\r\n\r\n @if (hasFilters()) {\r\n <button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n [attr.title]=\"'filters.clearFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.clearFilters' | transloco\"\r\n (click)=\"clear()\"\r\n (keydown.enter)=\"clear()\">\r\n <i class=\"fa-fw far fa-filter-circle-xmark\" aria-hidden=\"true\"></i>\r\n <span class=\"sr-only\">{{ \"filters.clearFilters\" | transloco }}</span>\r\n </button>\r\n }\r\n\r\n @if (selection() && validSelection()) {\r\n <button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n [attr.title]=\"'filters.applyFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.applyFilters' | transloco\"\r\n (click)=\"apply()\"\r\n (keydown.enter)=\"apply()\">\r\n <i class=\"fa-fw far fa-filter\" aria-hidden=\"true\"></i>\r\n <span class=\"sr-only\">{{ \"filters.applyFilters\" | transloco }}</span>\r\n </button>\r\n }\r\n @if (collapsible()) {\r\n <button\r\n variant=\"none\"\r\n title=\"Open/Close\"\r\n class=\"cursor-pointer [&_svg]:transition-transform [&_svg]:duration-150 group-open:[&_svg]:rotate-90\">\r\n <chevronright />\r\n </button>\r\n }\r\n </summary>\r\n\r\n <!-- content wrapper -->\r\n <form [formGroup]=\"form\">\r\n <ul\r\n class=\"scrollbar-thin flex max-h-[calc(var(--height,100%)-100px)] snap-y snap-start flex-col gap-1 overflow-auto pt-2\"\r\n role=\"list\">\r\n @for (option of dateOptions(); track $index) {\r\n <li\r\n role=\"listitem\"\r\n tabindex=\"0\"\r\n (click)=\"radio.click()\"\r\n [attr.aria-label]=\"option.display | syslang | transloco\"\r\n [class]=\"\r\n cn(\r\n 'flex p-0 px-2 leading-7',\r\n form.get('option')?.value === option.display && 'bg-accent',\r\n option.hidden && 'hidden',\r\n option.disabled && 'disabled pointer-events-none text-neutral-300'\r\n )\r\n \"\r\n [attr.aria-hidden]=\"option.disabled\">\r\n <input\r\n #radio\r\n type=\"radio\"\r\n formControlName=\"option\"\r\n id=\"date-filter-{{ option.display }}\"\r\n [attr.disabled]=\"option.disabled ? true : null\"\r\n [attr.aria-disabled]=\"option.disabled\"\r\n (click)=\"select()\"\r\n value=\"{{ option.display }}\" />\r\n\r\n <label\r\n for=\"date-filter-{{ option.display }}\"\r\n class=\"grow cursor-pointer p-1\">\r\n {{ option.display | syslang | transloco }}\r\n </label>\r\n </li>\r\n }\r\n\r\n @if (allowCustomRange) {\r\n <li\r\n role=\"listitem\"\r\n aria-label=\"open date range picker\"\r\n class=\"flex px-2 leading-7\"\r\n [class.select]=\"form.get('option')?.value === 'custom-range'\">\r\n <input\r\n type=\"radio\"\r\n formControlName=\"option\"\r\n id=\"date-filter-range-dialog\"\r\n value=\"custom-range\"\r\n (click)=\"select()\" />\r\n
|
|
9190
|
+
}, template: "<details [attr.open]=\"expanded()\" [attr.name]=\"id()\" class=\"group space-y-2\">\r\n <summary\r\n [class.cursor-pointer]=\"collapsible()\"\r\n class=\"m-0 flex h-8 w-full items-center pl-1 font-semibold select-none\"\r\n (click)=\"onHeaderClick($event)\">\r\n <ng-content select=\"label\">\r\n @if (aggregation()?.icon) {\r\n <i class=\"fa-fw {{ aggregation()?.icon }} mr-1\" aria-hidden=\"true\"></i>\r\n }\r\n <span class=\"grow\">{{\r\n aggregation()?.display | syslang | transloco\r\n }}</span>\r\n </ng-content>\r\n\r\n @if (hasFilters()) {\r\n <button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n [attr.title]=\"'filters.clearFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.clearFilters' | transloco\"\r\n (click)=\"clear()\"\r\n (keydown.enter)=\"clear()\">\r\n <i class=\"fa-fw far fa-filter-circle-xmark\" aria-hidden=\"true\"></i>\r\n <span class=\"sr-only\">{{ \"filters.clearFilters\" | transloco }}</span>\r\n </button>\r\n }\r\n\r\n @if (selection() && validSelection()) {\r\n <button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n [attr.title]=\"'filters.applyFilters' | transloco\"\r\n [attr.aria-label]=\"'filters.applyFilters' | transloco\"\r\n (click)=\"apply()\"\r\n (keydown.enter)=\"apply()\">\r\n <i class=\"fa-fw far fa-filter\" aria-hidden=\"true\"></i>\r\n <span class=\"sr-only\">{{ \"filters.applyFilters\" | transloco }}</span>\r\n </button>\r\n }\r\n @if (collapsible()) {\r\n <button\r\n variant=\"none\"\r\n title=\"Open/Close\"\r\n class=\"cursor-pointer [&_svg]:transition-transform [&_svg]:duration-150 group-open:[&_svg]:rotate-90\">\r\n <chevronright />\r\n </button>\r\n }\r\n </summary>\r\n\r\n <!-- content wrapper -->\r\n <form [formGroup]=\"form\">\r\n <ul\r\n class=\"scrollbar-thin flex max-h-[calc(var(--height,100%)-100px)] snap-y snap-start flex-col gap-1 overflow-auto pt-2\"\r\n role=\"list\">\r\n @for (option of dateOptions(); track $index) {\r\n <li\r\n role=\"listitem\"\r\n tabindex=\"0\"\r\n (click)=\"radio.click()\"\r\n [attr.aria-label]=\"option.display | syslang | transloco\"\r\n [class]=\"\r\n cn(\r\n 'flex p-0 px-2 leading-7',\r\n form.get('option')?.value === option.display && 'bg-accent',\r\n option.hidden && 'hidden',\r\n option.disabled && 'disabled pointer-events-none text-neutral-300'\r\n )\r\n \"\r\n [attr.aria-hidden]=\"option.disabled\">\r\n <input\r\n #radio\r\n type=\"radio\"\r\n formControlName=\"option\"\r\n id=\"date-filter-{{ option.display }}\"\r\n [attr.disabled]=\"option.disabled ? true : null\"\r\n [attr.aria-disabled]=\"option.disabled\"\r\n (click)=\"select()\"\r\n value=\"{{ option.display }}\" />\r\n\r\n <label\r\n for=\"date-filter-{{ option.display }}\"\r\n class=\"grow cursor-pointer p-1\">\r\n {{ option.display | syslang | transloco }}\r\n </label>\r\n </li>\r\n }\r\n\r\n @if (allowCustomRange) {\r\n <li\r\n role=\"listitem\"\r\n aria-label=\"open date range picker\"\r\n class=\"flex px-2 leading-7\"\r\n [class.select]=\"form.get('option')?.value === 'custom-range'\">\r\n <input\r\n type=\"radio\"\r\n formControlName=\"option\"\r\n id=\"date-filter-range-dialog\"\r\n value=\"custom-range\"\r\n (click)=\"select()\" />\r\n <div\r\n class=\"@container flex grow justify-end gap-1 p-1 @max-[340px]:flex-wrap\">\r\n <div class=\"flex gap-1\">\r\n <label for=\"datepicker-range-start\" class=\"min-w-10 truncate\">{{\r\n \"filters.from\" | transloco\r\n }}</label>\r\n <input\r\n id=\"datepicker-range-start\"\r\n name=\"start\"\r\n type=\"text\"\r\n readonly\r\n class=\"h-8 max-w-[13ch] min-w-[13ch]\"\r\n [value]=\"customRangeFrom()\"\r\n (click)=\"selectAndOpenDialog()\" />\r\n </div>\r\n <div class=\"flex gap-1\">\r\n <label\r\n for=\"datepicker-range-end\"\r\n class=\"min-w-10 truncate text-right\"\r\n >{{ \"filters.to\" | transloco }}</label\r\n >\r\n <input\r\n id=\"datepicker-range-end\"\r\n name=\"end\"\r\n type=\"text\"\r\n readonly\r\n class=\"h-8 max-w-[13ch] min-w-[13ch]\"\r\n [value]=\"customRangeTo()\"\r\n (click)=\"selectAndOpenDialog()\" />\r\n </div>\r\n </div>\r\n </li>\r\n }\r\n </ul>\r\n </form>\r\n</details>\r\n\r\n<aggregation-date-range-dialog\r\n [lang]=\"lang()\"\r\n [useDateRange]=\"false\"\r\n [min]=\"form.get('customRange.from')?.value || undefined\"\r\n [max]=\"form.get('customRange.to')?.value || undefined\"\r\n (rangeSelected)=\"onRangeSelected($event)\" />\r\n", styles: [":host{display:block;min-width:200px}ul[role=list]{scrollbar-width:thin}\n"] }]
|
|
9101
9191
|
}] });
|
|
9102
9192
|
|
|
9103
9193
|
class ArticleEntities {
|
|
@@ -10050,6 +10140,7 @@ class ChangePasswordComponent {
|
|
|
10050
10140
|
principalStore = inject(PrincipalStore);
|
|
10051
10141
|
applicationService = inject(ApplicationService);
|
|
10052
10142
|
location = inject(Location);
|
|
10143
|
+
auditService = inject(AuditService);
|
|
10053
10144
|
currentPassword = model("", ...(ngDevMode ? [{ debugName: "currentPassword" }] : []));
|
|
10054
10145
|
newPassword = model("", ...(ngDevMode ? [{ debugName: "newPassword" }] : []));
|
|
10055
10146
|
confirmPassword = model("", ...(ngDevMode ? [{ debugName: "confirmPassword" }] : []));
|
|
@@ -10095,11 +10186,13 @@ class ChangePasswordComponent {
|
|
|
10095
10186
|
const msg = res.message ?? this.transloco.translate("login.passwordChangeFailed");
|
|
10096
10187
|
this.errorMsg.set(msg);
|
|
10097
10188
|
notify.error(msg, { duration: 2500 });
|
|
10189
|
+
this.auditService.notify({ type: 'Change_Password_Failed' });
|
|
10098
10190
|
return;
|
|
10099
10191
|
}
|
|
10100
10192
|
notify.success(this.transloco.translate("login.passwordChanged"), {
|
|
10101
10193
|
duration: 2000
|
|
10102
10194
|
});
|
|
10195
|
+
this.auditService.notify({ type: 'Change_Password_Success_Form' });
|
|
10103
10196
|
const username = this.effectiveUsername();
|
|
10104
10197
|
if (!username) {
|
|
10105
10198
|
notify.info(this.transloco.translate("login.loginAfterPasswordChangeMissingUser"), { duration: 3000 });
|
|
@@ -10388,6 +10481,7 @@ class ForgotPasswordComponent {
|
|
|
10388
10481
|
cancel = output();
|
|
10389
10482
|
success = output();
|
|
10390
10483
|
transloco = inject(TranslocoService);
|
|
10484
|
+
auditService = inject(AuditService);
|
|
10391
10485
|
userName = model("", ...(ngDevMode ? [{ debugName: "userName" }] : []));
|
|
10392
10486
|
pending = signal(false, ...(ngDevMode ? [{ debugName: "pending" }] : []));
|
|
10393
10487
|
errorMsg = signal(null, ...(ngDevMode ? [{ debugName: "errorMsg" }] : []));
|
|
@@ -10400,6 +10494,9 @@ class ForgotPasswordComponent {
|
|
|
10400
10494
|
notify.success(this.transloco.translate("login.resetEmailSent", {
|
|
10401
10495
|
email: res.email ?? ""
|
|
10402
10496
|
}));
|
|
10497
|
+
this.auditService.notify({
|
|
10498
|
+
type: 'Send_Reset_Password_Link'
|
|
10499
|
+
});
|
|
10403
10500
|
this.success.emit();
|
|
10404
10501
|
}
|
|
10405
10502
|
catch (e) {
|
|
@@ -10536,6 +10633,7 @@ class SignInComponent {
|
|
|
10536
10633
|
applicationService = inject(ApplicationService);
|
|
10537
10634
|
principalStore = inject(PrincipalStore);
|
|
10538
10635
|
transloco = inject(TranslocoService);
|
|
10636
|
+
auditService = inject(AuditService);
|
|
10539
10637
|
authenticated = signal(isAuthenticated(), ...(ngDevMode ? [{ debugName: "authenticated" }] : []));
|
|
10540
10638
|
user = signal(getState(this.principalStore), ...(ngDevMode ? [{ debugName: "user" }] : []));
|
|
10541
10639
|
expiresSoonNotified = signal(false, ...(ngDevMode ? [{ debugName: "expiresSoonNotified" }] : []));
|
|
@@ -10586,8 +10684,13 @@ class SignInComponent {
|
|
|
10586
10684
|
this.router.navigate(["/login"]);
|
|
10587
10685
|
}
|
|
10588
10686
|
async handleLogin() {
|
|
10589
|
-
login().
|
|
10687
|
+
login().then((result) => {
|
|
10688
|
+
if (result) {
|
|
10689
|
+
this.auditService.notifyLogin();
|
|
10690
|
+
}
|
|
10691
|
+
}).catch(error => {
|
|
10590
10692
|
warn("An error occurred while logging in", error);
|
|
10693
|
+
this.auditService.notify({ type: 'Login_Denied' });
|
|
10591
10694
|
this.router.navigate(["error"]);
|
|
10592
10695
|
});
|
|
10593
10696
|
}
|
|
@@ -10596,8 +10699,11 @@ class SignInComponent {
|
|
|
10596
10699
|
return;
|
|
10597
10700
|
try {
|
|
10598
10701
|
const response = await login(this.credentials());
|
|
10599
|
-
if (!response)
|
|
10702
|
+
if (!response) {
|
|
10703
|
+
this.auditService.notify({ type: 'Login_Denied' });
|
|
10600
10704
|
return;
|
|
10705
|
+
}
|
|
10706
|
+
this.auditService.notifyLogin();
|
|
10601
10707
|
const { createRoutes = false } = globalConfig;
|
|
10602
10708
|
await this.applicationService.initialize(createRoutes);
|
|
10603
10709
|
this.checkPasswordExpiresSoon();
|
|
@@ -10605,7 +10711,7 @@ class SignInComponent {
|
|
|
10605
10711
|
this.router.navigateByUrl(url);
|
|
10606
10712
|
}
|
|
10607
10713
|
catch (err) {
|
|
10608
|
-
const { status, errorMessage } = err;
|
|
10714
|
+
const { status, errorMessage, message } = err;
|
|
10609
10715
|
if (status === 401 &&
|
|
10610
10716
|
errorMessage?.toLowerCase().includes("password expired")) {
|
|
10611
10717
|
sessionStorage.setItem("passwordExpiredFlow", "true");
|
|
@@ -10618,7 +10724,8 @@ class SignInComponent {
|
|
|
10618
10724
|
});
|
|
10619
10725
|
return;
|
|
10620
10726
|
}
|
|
10621
|
-
|
|
10727
|
+
// For other errors, show a generic error message
|
|
10728
|
+
notify.error("Login", { description: message ?? errorMessage });
|
|
10622
10729
|
}
|
|
10623
10730
|
}
|
|
10624
10731
|
handleBack() {
|
|
@@ -10634,7 +10741,7 @@ class SignInComponent {
|
|
|
10634
10741
|
cdkTrapFocusAutoCapture="true"
|
|
10635
10742
|
class="bg-card rounded-xl shadow-sm">
|
|
10636
10743
|
<CardHeader class="flex flex-col items-center gap-3 text-center">
|
|
10637
|
-
<img class="h-12 content-(--logo-large
|
|
10744
|
+
<img class="h-12 content-(--logo-large)" alt="logo" />
|
|
10638
10745
|
</CardHeader>
|
|
10639
10746
|
|
|
10640
10747
|
<CardContent class="grid gap-4">
|
|
@@ -10714,7 +10821,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
10714
10821
|
cdkTrapFocusAutoCapture="true"
|
|
10715
10822
|
class="bg-card rounded-xl shadow-sm">
|
|
10716
10823
|
<CardHeader class="flex flex-col items-center gap-3 text-center">
|
|
10717
|
-
<img class="h-12 content-(--logo-large
|
|
10824
|
+
<img class="h-12 content-(--logo-large)" alt="logo" />
|
|
10718
10825
|
</CardHeader>
|
|
10719
10826
|
|
|
10720
10827
|
<CardContent class="grid gap-4">
|
|
@@ -10986,7 +11093,7 @@ class BookmarksComponent {
|
|
|
10986
11093
|
this.range.set(this.range() + (this.config.itemsPerPage ?? 10));
|
|
10987
11094
|
}
|
|
10988
11095
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: BookmarksComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
10989
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: BookmarksComponent, isStandalone: true, selector: "bookmarks, Bookmarks", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null } }, providers: [provideTranslocoScope("bookmarks")], ngImport: i0, template: "@if (floating) {\r\n <div class=\"p-2\">\r\n <label class=\"text-xl font-bold\">{{ \"bookmarks.label\" | transloco }}</label>\r\n <Separator />\r\n </div>\r\n}\r\n\r\n<ul class=\"flex max-h-[460px] flex-col overflow-auto\" role=\"list\">\r\n @for (bookmark of paginatedBookmarks(); track $index) {\r\n <li\r\n role=\"listitem\"\r\n class=\"group h-10\"\r\n tabindex=\"0\"\r\n (click)=\"onClick(bookmark)\"\r\n (keydown.enter)=\"onClick(bookmark)\">\r\n <BookmarkIcon solid class=\"shrink-0\" />\r\n\r\n <p class=\"line-clamp-1\">{{ bookmark.label }}</p>\r\n\r\n @if (bookmark.author) {\r\n <Badge variant=\"ghost\" class=\"text-grey-500 text-xs\">\r\n <UserIcon class=\"size-3\" />\r\n <span class=\"line-clamp-1\">{{ bookmark.author }}</span>\r\n </Badge>\r\n }\r\n @if (bookmark.parentFolder) {\r\n <Badge variant=\"ghost\" class=\"text-grey-500 text-xs\">\r\n <FolderIcon class=\"size-3\" />\r\n <span class=\"line-clamp-1\">{{ bookmark.parentFolder }}</span>\r\n </Badge>\r\n }\r\n\r\n <button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n title=\"{{ 'bookmarks.openBookmark' | transloco }}\"\r\n class=\"text-destructive ms-auto group-hover:visible\"\r\n [attr.title]=\"'bookmarks.removeBookmark' | transloco\"\r\n [attr.aria-label]=\"'bookmarks.removeBookmark' | transloco\"\r\n (click)=\"onDelete(bookmark, $event)\">\r\n <TrashIcon />\r\n </button>\r\n </li>\r\n } @empty {\r\n <li class=\"py-4 text-center text-neutral-500\">\r\n {{ \"bookmarks.noBookmarks\" | transloco }}\r\n </li>\r\n }\r\n</ul>\r\n\r\n<div class=\"flex flex-col px-2\">\r\n @if (hasMore() && config.showLoadMore) {\r\n <button\r\n variant=\"ghost\"\r\n class=\"w-full\"\r\n tabindex=\"0\"\r\n [attr.title]=\"'loadMore' | transloco\"\r\n (click)=\"loadMore($event)\">\r\n {{ \"loadMore\" | transloco }}\r\n </button>\r\n }\r\n <button\r\n variant=\"link\"\r\n class=\"ml-auto\"\r\n [attr.title]=\"'seeMore' | transloco\"\r\n [routerLink]=\"[config.routerLink]\">\r\n {{ \"seeMore\" | transloco }}\r\n </button>\r\n</div>\r\n", styles: [":host ul{scrollbar-width:thin}\n"], dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: ListItemComponent, selector: "[role=\"listitem\"], [role=\"option\"]", inputs: ["class", "variant", "decoration"] }, { kind: "directive", type: ButtonComponent, selector: "button", inputs: ["class", "variant", "decoration", "scheme", "iconOnly", "size"] }, { kind: "directive", type: Separator, selector: "separator, Separator", inputs: ["class", "orientation"] }, { kind: "component", type: BookmarkIcon, selector: "bookmark-icon, BookmarkIcon", inputs: ["class", "solid"] }, { kind: "component", type: UserIcon, selector: "user-icon, UserIcon", inputs: ["class"] }, { kind: "component", type: TrashIcon, selector: "trash-icon, TrashIcon", inputs: ["class"] }, { kind: "component", type: FolderIcon, selector: "folder-icon, FolderIcon", inputs: ["class"] }, { kind: "directive", type: BadgeComponent, selector: "badge, Badge", inputs: ["class", "variant", "size"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
|
|
11096
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: BookmarksComponent, isStandalone: true, selector: "bookmarks, Bookmarks", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null } }, providers: [provideTranslocoScope("bookmarks")], ngImport: i0, template: "@if (floating) {\r\n <div class=\"p-2\">\r\n <label class=\"text-xl font-bold\">{{ \"bookmarks.label\" | transloco }}</label>\r\n <Separator />\r\n </div>\r\n}\r\n\r\n<ul class=\"flex max-h-[460px] flex-col overflow-auto\" role=\"list\">\r\n @for (bookmark of paginatedBookmarks(); track $index) {\r\n <li\r\n role=\"listitem\"\r\n class=\"group h-10\"\r\n tabindex=\"0\"\r\n (click)=\"onClick(bookmark)\"\r\n (keydown.enter)=\"onClick(bookmark)\">\r\n <BookmarkIcon solid class=\"shrink-0\" />\r\n\r\n <p class=\"line-clamp-1\">{{ bookmark.label }}</p>\r\n\r\n @if (bookmark.author) {\r\n <Badge variant=\"ghost\" class=\"text-grey-500 text-xs\">\r\n <UserIcon class=\"size-3\" />\r\n <span class=\"line-clamp-1\">{{ bookmark.author }}</span>\r\n </Badge>\r\n }\r\n @if (bookmark.parentFolder) {\r\n <Badge variant=\"ghost\" class=\"text-grey-500 text-xs\">\r\n <FolderIcon class=\"size-3\" />\r\n <span class=\"line-clamp-1\">{{ bookmark.parentFolder }}</span>\r\n </Badge>\r\n }\r\n\r\n <button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n title=\"{{ 'bookmarks.openBookmark' | transloco }}\"\r\n class=\"text-destructive ms-auto group-hover:visible\"\r\n [attr.title]=\"'bookmarks.removeBookmark' | transloco\"\r\n [attr.aria-label]=\"'bookmarks.removeBookmark' | transloco\"\r\n (click)=\"onDelete(bookmark, $event)\">\r\n <TrashIcon />\r\n </button>\r\n </li>\r\n } @empty {\r\n <li class=\"list-none py-4 text-center text-neutral-500\">\r\n {{ \"bookmarks.noBookmarks\" | transloco }}\r\n </li>\r\n }\r\n</ul>\r\n\r\n<div class=\"flex flex-col px-2\">\r\n @if (hasMore() && config.showLoadMore) {\r\n <button\r\n variant=\"ghost\"\r\n class=\"w-full\"\r\n tabindex=\"0\"\r\n [attr.title]=\"'loadMore' | transloco\"\r\n (click)=\"loadMore($event)\">\r\n {{ \"loadMore\" | transloco }}\r\n </button>\r\n }\r\n <button\r\n variant=\"link\"\r\n class=\"ml-auto\"\r\n [attr.title]=\"'seeMore' | transloco\"\r\n [routerLink]=\"[config.routerLink]\">\r\n {{ \"seeMore\" | transloco }}\r\n </button>\r\n</div>\r\n", styles: [":host ul{scrollbar-width:thin}\n"], dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: ListItemComponent, selector: "[role=\"listitem\"], [role=\"option\"]", inputs: ["class", "variant", "decoration"] }, { kind: "directive", type: ButtonComponent, selector: "button", inputs: ["class", "variant", "decoration", "scheme", "iconOnly", "size"] }, { kind: "directive", type: Separator, selector: "separator, Separator", inputs: ["class", "orientation"] }, { kind: "component", type: BookmarkIcon, selector: "bookmark-icon, BookmarkIcon", inputs: ["class", "solid"] }, { kind: "component", type: UserIcon, selector: "user-icon, UserIcon", inputs: ["class"] }, { kind: "component", type: TrashIcon, selector: "trash-icon, TrashIcon", inputs: ["class"] }, { kind: "component", type: FolderIcon, selector: "folder-icon, FolderIcon", inputs: ["class"] }, { kind: "directive", type: BadgeComponent, selector: "badge, Badge", inputs: ["class", "variant", "size"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
|
|
10990
11097
|
}
|
|
10991
11098
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: BookmarksComponent, decorators: [{
|
|
10992
11099
|
type: Component,
|
|
@@ -11001,7 +11108,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
11001
11108
|
TrashIcon,
|
|
11002
11109
|
FolderIcon,
|
|
11003
11110
|
BadgeComponent
|
|
11004
|
-
], providers: [provideTranslocoScope("bookmarks")], template: "@if (floating) {\r\n <div class=\"p-2\">\r\n <label class=\"text-xl font-bold\">{{ \"bookmarks.label\" | transloco }}</label>\r\n <Separator />\r\n </div>\r\n}\r\n\r\n<ul class=\"flex max-h-[460px] flex-col overflow-auto\" role=\"list\">\r\n @for (bookmark of paginatedBookmarks(); track $index) {\r\n <li\r\n role=\"listitem\"\r\n class=\"group h-10\"\r\n tabindex=\"0\"\r\n (click)=\"onClick(bookmark)\"\r\n (keydown.enter)=\"onClick(bookmark)\">\r\n <BookmarkIcon solid class=\"shrink-0\" />\r\n\r\n <p class=\"line-clamp-1\">{{ bookmark.label }}</p>\r\n\r\n @if (bookmark.author) {\r\n <Badge variant=\"ghost\" class=\"text-grey-500 text-xs\">\r\n <UserIcon class=\"size-3\" />\r\n <span class=\"line-clamp-1\">{{ bookmark.author }}</span>\r\n </Badge>\r\n }\r\n @if (bookmark.parentFolder) {\r\n <Badge variant=\"ghost\" class=\"text-grey-500 text-xs\">\r\n <FolderIcon class=\"size-3\" />\r\n <span class=\"line-clamp-1\">{{ bookmark.parentFolder }}</span>\r\n </Badge>\r\n }\r\n\r\n <button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n title=\"{{ 'bookmarks.openBookmark' | transloco }}\"\r\n class=\"text-destructive ms-auto group-hover:visible\"\r\n [attr.title]=\"'bookmarks.removeBookmark' | transloco\"\r\n [attr.aria-label]=\"'bookmarks.removeBookmark' | transloco\"\r\n (click)=\"onDelete(bookmark, $event)\">\r\n <TrashIcon />\r\n </button>\r\n </li>\r\n } @empty {\r\n <li class=\"py-4 text-center text-neutral-500\">\r\n {{ \"bookmarks.noBookmarks\" | transloco }}\r\n </li>\r\n }\r\n</ul>\r\n\r\n<div class=\"flex flex-col px-2\">\r\n @if (hasMore() && config.showLoadMore) {\r\n <button\r\n variant=\"ghost\"\r\n class=\"w-full\"\r\n tabindex=\"0\"\r\n [attr.title]=\"'loadMore' | transloco\"\r\n (click)=\"loadMore($event)\">\r\n {{ \"loadMore\" | transloco }}\r\n </button>\r\n }\r\n <button\r\n variant=\"link\"\r\n class=\"ml-auto\"\r\n [attr.title]=\"'seeMore' | transloco\"\r\n [routerLink]=\"[config.routerLink]\">\r\n {{ \"seeMore\" | transloco }}\r\n </button>\r\n</div>\r\n", styles: [":host ul{scrollbar-width:thin}\n"] }]
|
|
11111
|
+
], providers: [provideTranslocoScope("bookmarks")], template: "@if (floating) {\r\n <div class=\"p-2\">\r\n <label class=\"text-xl font-bold\">{{ \"bookmarks.label\" | transloco }}</label>\r\n <Separator />\r\n </div>\r\n}\r\n\r\n<ul class=\"flex max-h-[460px] flex-col overflow-auto\" role=\"list\">\r\n @for (bookmark of paginatedBookmarks(); track $index) {\r\n <li\r\n role=\"listitem\"\r\n class=\"group h-10\"\r\n tabindex=\"0\"\r\n (click)=\"onClick(bookmark)\"\r\n (keydown.enter)=\"onClick(bookmark)\">\r\n <BookmarkIcon solid class=\"shrink-0\" />\r\n\r\n <p class=\"line-clamp-1\">{{ bookmark.label }}</p>\r\n\r\n @if (bookmark.author) {\r\n <Badge variant=\"ghost\" class=\"text-grey-500 text-xs\">\r\n <UserIcon class=\"size-3\" />\r\n <span class=\"line-clamp-1\">{{ bookmark.author }}</span>\r\n </Badge>\r\n }\r\n @if (bookmark.parentFolder) {\r\n <Badge variant=\"ghost\" class=\"text-grey-500 text-xs\">\r\n <FolderIcon class=\"size-3\" />\r\n <span class=\"line-clamp-1\">{{ bookmark.parentFolder }}</span>\r\n </Badge>\r\n }\r\n\r\n <button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n title=\"{{ 'bookmarks.openBookmark' | transloco }}\"\r\n class=\"text-destructive ms-auto group-hover:visible\"\r\n [attr.title]=\"'bookmarks.removeBookmark' | transloco\"\r\n [attr.aria-label]=\"'bookmarks.removeBookmark' | transloco\"\r\n (click)=\"onDelete(bookmark, $event)\">\r\n <TrashIcon />\r\n </button>\r\n </li>\r\n } @empty {\r\n <li class=\"list-none py-4 text-center text-neutral-500\">\r\n {{ \"bookmarks.noBookmarks\" | transloco }}\r\n </li>\r\n }\r\n</ul>\r\n\r\n<div class=\"flex flex-col px-2\">\r\n @if (hasMore() && config.showLoadMore) {\r\n <button\r\n variant=\"ghost\"\r\n class=\"w-full\"\r\n tabindex=\"0\"\r\n [attr.title]=\"'loadMore' | transloco\"\r\n (click)=\"loadMore($event)\">\r\n {{ \"loadMore\" | transloco }}\r\n </button>\r\n }\r\n <button\r\n variant=\"link\"\r\n class=\"ml-auto\"\r\n [attr.title]=\"'seeMore' | transloco\"\r\n [routerLink]=\"[config.routerLink]\">\r\n {{ \"seeMore\" | transloco }}\r\n </button>\r\n</div>\r\n", styles: [":host ul{scrollbar-width:thin}\n"] }]
|
|
11005
11112
|
}], ctorParameters: () => [], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }] } });
|
|
11006
11113
|
|
|
11007
11114
|
class DeleteCollectionDialog {
|
|
@@ -11126,11 +11233,11 @@ class CollectionsComponent {
|
|
|
11126
11233
|
this.range.set(this.range() + (this.config.itemsPerPage ?? 10));
|
|
11127
11234
|
}
|
|
11128
11235
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: CollectionsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
11129
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: CollectionsComponent, isStandalone: true, selector: "app-collections", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null } }, providers: [provideTranslocoScope("collections")], viewQueries: [{ propertyName: "deleteCollectionDialog", first: true, predicate: DeleteCollectionDialog, descendants: true, isSignal: true }], ngImport: i0, template: "@if (floating) {\r\n <div class=\"p-2\">\r\n <label class=\"text-xl font-bold\">{{\r\n \"collections.label\" | transloco\r\n }}</label>\r\n <Separator />\r\n </div>\r\n}\r\n\r\n<ul class=\"flex max-h-[460px] flex-col overflow-auto\">\r\n @for (collection of paginatedCollections(); track $index) {\r\n <li\r\n role=\"listitem\"\r\n class=\"group grid grid-cols-[min-content_auto_min-content] items-center\"\r\n tabindex=\"0\"\r\n (click)=\"onClick(collection)\"\r\n (keydown.enter)=\"onClick(collection)\">\r\n <i class=\"fas fa-inbox ps-2\"></i>\r\n\r\n <p class=\"mx-2 line-clamp-1\">{{ collection.name }}</p>\r\n\r\n <button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n class=\"text-destructive invisible group-hover:visible\"\r\n title=\"{{ 'collections.deleteCollection' | transloco }}\"\r\n [attr.aria-label]=\"'collections.deleteCollection' | transloco\"\r\n (click)=\"onDelete(collection, $index, $event)\">\r\n <TrashIcon />\r\n </button>\r\n </li>\r\n } @empty {\r\n <li class=\"list-none py-4 text-center text-neutral-500\">\r\n {{ \"collections.noCollections\" | transloco }}\r\n </li>\r\n }\r\n</ul>\r\n\r\n<div class=\"flex flex-col px-2\">\r\n @if (hasMore() && config.showLoadMore) {\r\n <button\r\n variant=\"outline\"\r\n class=\"w-full\"\r\n tabindex=\"0\"\r\n [attr.title]=\"'loadMore' | transloco\"\r\n (click)=\"loadMore($event)\">\r\n {{ \"loadMore\" | transloco }}\r\n </button>\r\n }\r\n <button\r\n variant=\"link\"\r\n class=\"ml-auto\"\r\n [attr.title]=\"'seeMore' | transloco\"\r\n [routerLink]=\"[config.routerLink]\">\r\n {{ \"seeMore\" | transloco }}\r\n </button>\r\n</div>\r\n\r\n<delete-collection-dialog />\r\n", dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: DeleteCollectionDialog, selector: "delete-collection-dialog" }, { kind: "directive", type: ButtonComponent, selector: "button", inputs: ["class", "variant", "decoration", "scheme", "iconOnly", "size"] }, { kind: "directive", type: ListItemComponent, selector: "[role=\"listitem\"], [role=\"option\"]", inputs: ["class", "variant", "decoration"] }, { kind: "directive", type: Separator, selector: "separator, Separator", inputs: ["class", "orientation"] }, { kind: "component", type: TrashIcon, selector: "trash-icon, TrashIcon", inputs: ["class"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
|
|
11236
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: CollectionsComponent, isStandalone: true, selector: "app-collections, collections", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null } }, providers: [provideTranslocoScope("collections")], viewQueries: [{ propertyName: "deleteCollectionDialog", first: true, predicate: DeleteCollectionDialog, descendants: true, isSignal: true }], ngImport: i0, template: "@if (floating) {\r\n <div class=\"p-2\">\r\n <label class=\"text-xl font-bold\">{{\r\n \"collections.label\" | transloco\r\n }}</label>\r\n <Separator />\r\n </div>\r\n}\r\n\r\n<ul class=\"flex max-h-[460px] flex-col overflow-auto\">\r\n @for (collection of paginatedCollections(); track $index) {\r\n <li\r\n role=\"listitem\"\r\n class=\"group grid grid-cols-[min-content_auto_min-content] items-center\"\r\n tabindex=\"0\"\r\n (click)=\"onClick(collection)\"\r\n (keydown.enter)=\"onClick(collection)\">\r\n <i class=\"fas fa-inbox ps-2\"></i>\r\n\r\n <p class=\"mx-2 line-clamp-1\">{{ collection.name }}</p>\r\n\r\n <button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n class=\"text-destructive invisible group-hover:visible\"\r\n title=\"{{ 'collections.deleteCollection' | transloco }}\"\r\n [attr.aria-label]=\"'collections.deleteCollection' | transloco\"\r\n (click)=\"onDelete(collection, $index, $event)\">\r\n <TrashIcon />\r\n </button>\r\n </li>\r\n } @empty {\r\n <li class=\"list-none py-4 text-center text-neutral-500\">\r\n {{ \"collections.noCollections\" | transloco }}\r\n </li>\r\n }\r\n</ul>\r\n\r\n<div class=\"flex flex-col px-2\">\r\n @if (hasMore() && config.showLoadMore) {\r\n <button\r\n variant=\"outline\"\r\n class=\"w-full\"\r\n tabindex=\"0\"\r\n [attr.title]=\"'loadMore' | transloco\"\r\n (click)=\"loadMore($event)\">\r\n {{ \"loadMore\" | transloco }}\r\n </button>\r\n }\r\n <button\r\n variant=\"link\"\r\n class=\"ml-auto\"\r\n [attr.title]=\"'seeMore' | transloco\"\r\n [routerLink]=\"[config.routerLink]\">\r\n {{ \"seeMore\" | transloco }}\r\n </button>\r\n</div>\r\n\r\n<delete-collection-dialog />\r\n", dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: DeleteCollectionDialog, selector: "delete-collection-dialog" }, { kind: "directive", type: ButtonComponent, selector: "button", inputs: ["class", "variant", "decoration", "scheme", "iconOnly", "size"] }, { kind: "directive", type: ListItemComponent, selector: "[role=\"listitem\"], [role=\"option\"]", inputs: ["class", "variant", "decoration"] }, { kind: "directive", type: Separator, selector: "separator, Separator", inputs: ["class", "orientation"] }, { kind: "component", type: TrashIcon, selector: "trash-icon, TrashIcon", inputs: ["class"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }] });
|
|
11130
11237
|
}
|
|
11131
11238
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: CollectionsComponent, decorators: [{
|
|
11132
11239
|
type: Component,
|
|
11133
|
-
args: [{ selector: "app-collections", standalone: true, imports: [
|
|
11240
|
+
args: [{ selector: "app-collections, collections", standalone: true, imports: [
|
|
11134
11241
|
TranslocoPipe,
|
|
11135
11242
|
RouterLink,
|
|
11136
11243
|
DeleteCollectionDialog,
|
|
@@ -13012,6 +13119,7 @@ class AggregationTreeComponent {
|
|
|
13012
13119
|
aggregationsService = inject(AggregationsService);
|
|
13013
13120
|
el = inject(ElementRef);
|
|
13014
13121
|
injector = inject(Injector);
|
|
13122
|
+
destroyRef = inject(DestroyRef);
|
|
13015
13123
|
class = input("", ...(ngDevMode ? [{ debugName: "class" }] : []));
|
|
13016
13124
|
/**
|
|
13017
13125
|
* The name of the <details> element. When you provide the same id, the component work as an accordion
|
|
@@ -13200,6 +13308,21 @@ class AggregationTreeComponent {
|
|
|
13200
13308
|
effect(() => {
|
|
13201
13309
|
this.filters.set(this.getFilters());
|
|
13202
13310
|
});
|
|
13311
|
+
this.destroyRef.onDestroy(() => {
|
|
13312
|
+
// If the popover is closed with unapplied selections, reset state so it doesn't persist when reopening
|
|
13313
|
+
if (this.selection()) {
|
|
13314
|
+
sessionStorage.removeItem(`agg-${this.aggregation()?.column}`);
|
|
13315
|
+
const unselect = (items) => {
|
|
13316
|
+
items.forEach((item) => {
|
|
13317
|
+
item.$selected = false;
|
|
13318
|
+
item.$selectedVisually = false;
|
|
13319
|
+
if (item.items)
|
|
13320
|
+
unselect(item.items);
|
|
13321
|
+
});
|
|
13322
|
+
};
|
|
13323
|
+
unselect(this.items());
|
|
13324
|
+
}
|
|
13325
|
+
});
|
|
13203
13326
|
}
|
|
13204
13327
|
// compare currentItems and updatedItems to add the new sub items
|
|
13205
13328
|
// from updatedItems into currentItems to not alter the already loaded items
|
|
@@ -13349,8 +13472,10 @@ class AggregationTreeComponent {
|
|
|
13349
13472
|
* If the item is deselected, the selection count is decremented by 1.
|
|
13350
13473
|
*/
|
|
13351
13474
|
select() {
|
|
13352
|
-
this.
|
|
13353
|
-
this.
|
|
13475
|
+
const selectedItems = this.getFlattenTreeItems().filter(item => item.$selected);
|
|
13476
|
+
this.onSelect.emit(selectedItems);
|
|
13477
|
+
// Keep apply visible if items are selected, or if active filters exist (user may be deselecting to clear)
|
|
13478
|
+
this.selection.set(selectedItems.length > 0 || this.hasFilters());
|
|
13354
13479
|
this.verifySelected();
|
|
13355
13480
|
sessionStorage.setItem(`agg-${this.aggregation()?.column}`, JSON.stringify([...this.items()]));
|
|
13356
13481
|
}
|
|
@@ -13805,7 +13930,7 @@ class AggregationComponent {
|
|
|
13805
13930
|
(onClear)="onClear.emit($event)"
|
|
13806
13931
|
/>
|
|
13807
13932
|
}
|
|
13808
|
-
`, isInline: true, dependencies: [{ kind: "component", type: AggregationListComponent, selector: "AggregationList, aggregation-list, aggregationlist", inputs: ["class", "id", "name", "column", "collapsible", "collapsed", "searchable", "showFiltersCount", "searchText"], outputs: ["onSelect", "onApply", "onClear", "searchTextChange"] }, { kind: "component", type: AggregationTreeComponent, selector: "AggregationTree, aggregation-tree, aggregationtree", inputs: ["class", "id", "name", "column", "expandedLevel", "collapsible", "collapsed", "searchable", "showFiltersCount", "searchText"], outputs: ["onSelect", "onApply", "onClear", "searchTextChange"] }, { kind: "component", type: AggregationDateComponent, selector: "aggregation-date, AggregationDate, aggregationdate", inputs: ["title", "displayEmptyDistributionIntervals"] }] });
|
|
13933
|
+
`, isInline: true, dependencies: [{ kind: "component", type: AggregationListComponent, selector: "AggregationList, aggregation-list, aggregationlist", inputs: ["class", "id", "name", "column", "collapsible", "collapsed", "searchable", "showFiltersCount", "searchText"], outputs: ["onSelect", "onApply", "onClear", "searchTextChange"] }, { kind: "component", type: AggregationTreeComponent, selector: "AggregationTree, aggregation-tree, aggregationtree", inputs: ["class", "id", "name", "column", "expandedLevel", "collapsible", "collapsed", "searchable", "showFiltersCount", "searchText"], outputs: ["onSelect", "onApply", "onClear", "searchTextChange"] }, { kind: "component", type: AggregationDateComponent, selector: "aggregation-date, AggregationDate, aggregationdate", inputs: ["title", "displayEmptyDistributionIntervals", "name"] }] });
|
|
13809
13934
|
}
|
|
13810
13935
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: AggregationComponent, decorators: [{
|
|
13811
13936
|
type: Component,
|
|
@@ -13911,7 +14036,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
13911
14036
|
}], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }] } });
|
|
13912
14037
|
|
|
13913
14038
|
class FilterButtonComponent {
|
|
13914
|
-
name = input
|
|
14039
|
+
name = input(...(ngDevMode ? [undefined, { debugName: "name" }] : []));
|
|
13915
14040
|
column = input.required(...(ngDevMode ? [{ debugName: "column" }] : []));
|
|
13916
14041
|
position = input("bottom-start", ...(ngDevMode ? [{ debugName: "position" }] : []));
|
|
13917
14042
|
offset = input(8, ...(ngDevMode ? [{ debugName: "offset" }] : []));
|
|
@@ -13934,15 +14059,20 @@ class FilterButtonComponent {
|
|
|
13934
14059
|
appStore = inject(AppStore);
|
|
13935
14060
|
constructor() {
|
|
13936
14061
|
effect(() => {
|
|
13937
|
-
const
|
|
13938
|
-
const
|
|
14062
|
+
const name = this.name();
|
|
14063
|
+
const column = this.column();
|
|
14064
|
+
let agg = undefined;
|
|
14065
|
+
if (name) {
|
|
14066
|
+
agg = this.aggregationsStore.getAggregation(name);
|
|
14067
|
+
if (!agg)
|
|
14068
|
+
return;
|
|
14069
|
+
}
|
|
14070
|
+
const f = this.queryParamsStore.getFilter({ name: name, field: column });
|
|
13939
14071
|
const count = f?.count || 0;
|
|
13940
|
-
if (!agg)
|
|
13941
|
-
return;
|
|
13942
14072
|
// retrieve customization fron the custom JSON provided by the server
|
|
13943
|
-
const { icon, hidden = false, display } = this.appStore.getAggregationCustomization(
|
|
14073
|
+
const { icon, hidden = false, display } = this.appStore.getAggregationCustomization(column, name) || {};
|
|
13944
14074
|
const r = {
|
|
13945
|
-
name
|
|
14075
|
+
name,
|
|
13946
14076
|
column: this.column(),
|
|
13947
14077
|
icon,
|
|
13948
14078
|
hidden,
|
|
@@ -13954,6 +14084,10 @@ class FilterButtonComponent {
|
|
|
13954
14084
|
// to be able to display the date range
|
|
13955
14085
|
legacyFilter: this.isDate(this.column()) ? f : undefined
|
|
13956
14086
|
};
|
|
14087
|
+
if (this.isDate(this.column())) {
|
|
14088
|
+
// for date filters, we want to display the date range in the button
|
|
14089
|
+
r.disabled = false; // date filters should never be disabled, even if they have no items, because they can still be applied with a custom range
|
|
14090
|
+
}
|
|
13957
14091
|
this.filter.set(r);
|
|
13958
14092
|
});
|
|
13959
14093
|
effect(() => {
|
|
@@ -13971,7 +14105,7 @@ class FilterButtonComponent {
|
|
|
13971
14105
|
return this.appStore.isDateColumn(column);
|
|
13972
14106
|
}
|
|
13973
14107
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: FilterButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
13974
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: FilterButtonComponent, isStandalone: true, selector: "filter-button, FilterButton", inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired:
|
|
14108
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: FilterButtonComponent, isStandalone: true, selector: "filter-button, FilterButton", inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, column: { classPropertyName: "column", publicName: "column", isSignal: true, isRequired: true, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, offset: { classPropertyName: "offset", publicName: "offset", isSignal: true, isRequired: false, transformFunction: null }, expandedLevel: { classPropertyName: "expandedLevel", publicName: "expandedLevel", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "listitem" }, properties: { "class.hidden": "filter().hidden" } }, viewQueries: [{ propertyName: "popoverRef", first: true, predicate: PopoverComponent, descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
13975
14109
|
<Popover [disabled]="filter().disabled" class="group">
|
|
13976
14110
|
<button
|
|
13977
14111
|
[variant]="variant()"
|
|
@@ -13994,11 +14128,7 @@ class FilterButtonComponent {
|
|
|
13994
14128
|
}
|
|
13995
14129
|
|
|
13996
14130
|
<!-- show the count of selected items -->
|
|
13997
|
-
@if (filter().
|
|
13998
|
-
<Badge size="xs" >
|
|
13999
|
-
{{ filter().count }}
|
|
14000
|
-
</Badge>
|
|
14001
|
-
} @else if (filter().count > 1) {
|
|
14131
|
+
@if (filter().count > 1) {
|
|
14002
14132
|
<Badge size="xs" class="pb-0.5">+{{ filter().count - 1 }}</Badge>
|
|
14003
14133
|
}
|
|
14004
14134
|
</button>
|
|
@@ -14009,15 +14139,23 @@ class FilterButtonComponent {
|
|
|
14009
14139
|
[offset]="offset()"
|
|
14010
14140
|
>
|
|
14011
14141
|
@if(contentRef.isVisible) {
|
|
14142
|
+
@let name = filter().name;
|
|
14143
|
+
@let column = filter().column;
|
|
14144
|
+
@if(name) {
|
|
14012
14145
|
<Aggregation
|
|
14013
14146
|
class="w-60 [--height:19lh]"
|
|
14014
14147
|
id="filter-{{ filter().column }}"
|
|
14015
|
-
[name]="
|
|
14016
|
-
[column]="
|
|
14148
|
+
[name]="name"
|
|
14149
|
+
[column]="column"
|
|
14017
14150
|
[expandedLevel]="expandedLevel()"
|
|
14018
14151
|
(onApply)="popoverRef()?.close()"
|
|
14019
14152
|
(onClear)="popoverRef()?.close()"
|
|
14020
14153
|
/>
|
|
14154
|
+
} @else {
|
|
14155
|
+
<div class="p-4 text-sm text-foreground/60">
|
|
14156
|
+
{{ 'INVALID_FILTER_NAME' | transloco }}
|
|
14157
|
+
</div>
|
|
14158
|
+
}
|
|
14021
14159
|
}
|
|
14022
14160
|
</PopoverContent>
|
|
14023
14161
|
</Popover>
|
|
@@ -14061,11 +14199,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
14061
14199
|
}
|
|
14062
14200
|
|
|
14063
14201
|
<!-- show the count of selected items -->
|
|
14064
|
-
@if (filter().
|
|
14065
|
-
<Badge size="xs" >
|
|
14066
|
-
{{ filter().count }}
|
|
14067
|
-
</Badge>
|
|
14068
|
-
} @else if (filter().count > 1) {
|
|
14202
|
+
@if (filter().count > 1) {
|
|
14069
14203
|
<Badge size="xs" class="pb-0.5">+{{ filter().count - 1 }}</Badge>
|
|
14070
14204
|
}
|
|
14071
14205
|
</button>
|
|
@@ -14076,15 +14210,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
14076
14210
|
[offset]="offset()"
|
|
14077
14211
|
>
|
|
14078
14212
|
@if(contentRef.isVisible) {
|
|
14213
|
+
@let name = filter().name;
|
|
14214
|
+
@let column = filter().column;
|
|
14215
|
+
@if(name) {
|
|
14079
14216
|
<Aggregation
|
|
14080
14217
|
class="w-60 [--height:19lh]"
|
|
14081
14218
|
id="filter-{{ filter().column }}"
|
|
14082
|
-
[name]="
|
|
14083
|
-
[column]="
|
|
14219
|
+
[name]="name"
|
|
14220
|
+
[column]="column"
|
|
14084
14221
|
[expandedLevel]="expandedLevel()"
|
|
14085
14222
|
(onApply)="popoverRef()?.close()"
|
|
14086
14223
|
(onClear)="popoverRef()?.close()"
|
|
14087
14224
|
/>
|
|
14225
|
+
} @else {
|
|
14226
|
+
<div class="p-4 text-sm text-foreground/60">
|
|
14227
|
+
{{ 'INVALID_FILTER_NAME' | transloco }}
|
|
14228
|
+
</div>
|
|
14229
|
+
}
|
|
14088
14230
|
}
|
|
14089
14231
|
</PopoverContent>
|
|
14090
14232
|
</Popover>
|
|
@@ -14094,7 +14236,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
14094
14236
|
role: "listitem"
|
|
14095
14237
|
}
|
|
14096
14238
|
}]
|
|
14097
|
-
}], ctorParameters: () => [], propDecorators: { name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required:
|
|
14239
|
+
}], ctorParameters: () => [], propDecorators: { name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], column: [{ type: i0.Input, args: [{ isSignal: true, alias: "column", required: true }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], offset: [{ type: i0.Input, args: [{ isSignal: true, alias: "offset", required: false }] }], expandedLevel: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandedLevel", required: false }] }], popoverRef: [{ type: i0.ViewChild, args: [i0.forwardRef(() => PopoverComponent), { isSignal: true }] }] } });
|
|
14098
14240
|
|
|
14099
14241
|
const FILTERS_BREAKPOINT = new InjectionToken('FILTERS_BREAKPOINT', { factory: () => 5 });
|
|
14100
14242
|
|