@sinequa/atomic-angular 2.3.0 → 2.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +299 -139
- package/fesm2022/sinequa-atomic-angular-document-workspaces.mjs +10 -80
- package/fesm2022/sinequa-atomic-angular-document-workspaces.mjs.map +1 -1
- package/fesm2022/sinequa-atomic-angular.mjs +105 -72
- package/fesm2022/sinequa-atomic-angular.mjs.map +1 -1
- package/package.json +2 -2
- package/types/sinequa-atomic-angular-document-workspaces.d.ts +15 -16
- package/types/sinequa-atomic-angular.d.ts +176 -17
|
@@ -3354,7 +3354,8 @@ const QUERY_PARAMS_DEFAULTS = {
|
|
|
3354
3354
|
aggregations: void 0,
|
|
3355
3355
|
orderBy: "",
|
|
3356
3356
|
groupBy: "",
|
|
3357
|
-
neuralSearch: void 0
|
|
3357
|
+
neuralSearch: void 0,
|
|
3358
|
+
aggregation_overrides: void 0
|
|
3358
3359
|
};
|
|
3359
3360
|
const QueryParamsStore = signalStore({ providedIn: "root" }, withDevtools("QueryParams"), withQueryParamsFeatures());
|
|
3360
3361
|
function withQueryParamsFeatures() {
|
|
@@ -3578,7 +3579,7 @@ function withQueryParamsFeatures() {
|
|
|
3578
3579
|
};
|
|
3579
3580
|
},
|
|
3580
3581
|
getQuery() {
|
|
3581
|
-
const { filters: allFilters = [], sort, tab, basket, text: queryText = "", spellingCorrectionMode } = getState(store);
|
|
3582
|
+
const { filters: allFilters = [], sort, tab, basket, text: queryText = "", spellingCorrectionMode, aggregation_overrides } = getState(store);
|
|
3582
3583
|
let { name } = getState(store);
|
|
3583
3584
|
if (!name) name = (route.snapshot.firstChild?.children[0]?.data)?.["queryName"] || appStore.getDefaultQuery()?.name || "";
|
|
3584
3585
|
let text = queryText;
|
|
@@ -3599,7 +3600,8 @@ function withQueryParamsFeatures() {
|
|
|
3599
3600
|
spellingCorrectionMode,
|
|
3600
3601
|
tab,
|
|
3601
3602
|
text,
|
|
3602
|
-
basket
|
|
3603
|
+
basket,
|
|
3604
|
+
aggregation_overrides
|
|
3603
3605
|
}));
|
|
3604
3606
|
}
|
|
3605
3607
|
})));
|
|
@@ -9983,20 +9985,12 @@ var AdvancedSearchTabs = class AdvancedSearchTabs {
|
|
|
9983
9985
|
executeSearch() {
|
|
9984
9986
|
this.selectionStore.update({ queryText: this.queryText() });
|
|
9985
9987
|
}
|
|
9986
|
-
constructor(destroyRef) {
|
|
9987
|
-
const host = inject(ElementRef).nativeElement;
|
|
9988
|
-
const onKeydownCapture = (event) => {
|
|
9989
|
-
if (event.key === "Enter") this.executeSearch();
|
|
9990
|
-
};
|
|
9991
|
-
host.addEventListener("keydown", onKeydownCapture, true);
|
|
9992
|
-
destroyRef.onDestroy(() => host.removeEventListener("keydown", onKeydownCapture, true));
|
|
9993
|
-
}
|
|
9994
9988
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
9995
9989
|
minVersion: "12.0.0",
|
|
9996
9990
|
version: "22.2.1",
|
|
9997
9991
|
ngImport: i0,
|
|
9998
9992
|
type: AdvancedSearchTabs,
|
|
9999
|
-
deps: [
|
|
9993
|
+
deps: [],
|
|
10000
9994
|
target: i0.ɵɵFactoryTarget.Component
|
|
10001
9995
|
});
|
|
10002
9996
|
static ɵcmp = i0.ɵɵngDeclareComponent({
|
|
@@ -10032,24 +10026,12 @@ var AdvancedSearchTabs = class AdvancedSearchTabs {
|
|
|
10032
10026
|
host: { classAttribute: "flex min-h-0 flex-col overflow-x-hidden text-(length:--size-xs)" },
|
|
10033
10027
|
providers: [provideTranslocoScope("drawers")],
|
|
10034
10028
|
ngImport: i0,
|
|
10035
|
-
template: "@if (article()) {\n <section class=\"mx-3 mt-3 mb-3 flex shrink-0 flex-col gap-4\">\n <!-- Enter submits
|
|
10029
|
+
template: "@if (article()) {\n <section class=\"mx-3 mt-3 mb-3 flex shrink-0 flex-col gap-4\">\n <!-- Enter submits through (keydown.enter), the send button through (search). No debounce: same \"submit on\n Enter/send, not on every keystroke\" contract as the previous input-group implementation. -->\n <SearchBar\n size=\"small\"\n [placeholder]=\"'drawers.inputPlaceholder' | transloco\"\n [aria-label]=\"'drawers.inputPlaceholder' | transloco\"\n [(value)]=\"queryText\"\n (keydown.enter)=\"executeSearch()\"\n (search)=\"executeSearch()\" />\n </section>\n\n <!-- flex-1/min-h-0: this is what lets the panel content below be the only thing that scrolls —\n the search bar/tab list above are shrink-0, never pushed off or scrolled themselves. -->\n <Tabs class=\"flex min-h-0 flex-1 flex-col\">\n <!-- noTruncate skips the default `truncate` branch (whose `has-[span]:[&>span]:truncate` would\n otherwise force this span back to single-line ellipsis, defeating the wrap below); overriding\n its own `min-w-fit` with `min-w-[auto]` restores the flex item's normal \"automatic minimum\n size\" instead — for content that can wrap, that floor is the longest word (min-content), not\n the full unwrapped label (max-content, what `fit-content` resolves to here with nothing\n constraining the available space). A single-word label has nothing to wrap, so min-content ==\n max-content and it can't be squeezed below its own readable width — the flex-shrink deficit\n falls on the multi-word labels that actually have room to give, which wrap onto the span's\n line-clamp-2 instead of being cut with an ellipsis (appropriate for a single-line pill, not\n for a tab bar where \"Similar documents\"/\"Match locations\" routinely don't fit on one line).\n h-9 (fixed, not h-auto) + items-center on every tab keeps the row visually even whether a\n given label wraps onto 2 lines or stays on 1. No horizontal scroll/truncation fallback here on\n purpose — see preview-actions.ts's [matchTriggerWidth]=\"false\" on the search popover: it's the\n popover itself that grows (shrink-to-fit, up to max-w-xl) to make room for this row instead of\n this row squeezing to fit a fixed popover width. -->\n <TabList\n class=\"mx-3 shrink-0\"\n variant=\"inner\"\n [selectedTab]=\"selectedTab()\"\n (selectedTabChange)=\"activeTab.set($event)\">\n <Tab\n variant=\"secondary\"\n size=\"sm\"\n value=\"extracts\"\n noTruncate\n class=\"h-9 min-w-[auto] items-center\">\n <span\n class=\"line-clamp-2 text-center leading-tight whitespace-normal\"\n >{{ \"extracts\" | transloco }}</span\n >\n </Tab>\n @if (entities.hasContent()) {\n <Tab\n variant=\"secondary\"\n size=\"sm\"\n value=\"entities\"\n noTruncate\n class=\"h-9 min-w-[auto] items-center\">\n <span\n class=\"line-clamp-2 text-center leading-tight whitespace-normal\"\n >{{ \"drawers.entitiesTab\" | transloco }}</span\n >\n </Tab>\n }\n @if (matchLocations.hasContent()) {\n <Tab\n variant=\"secondary\"\n size=\"sm\"\n value=\"matchlocations\"\n noTruncate\n class=\"h-9 min-w-[auto] items-center\">\n <span\n class=\"line-clamp-2 text-center leading-tight whitespace-normal\"\n >{{ \"column.matchlocations\" | transloco }}</span\n >\n </Tab>\n }\n @if (labels.hasContent()) {\n <Tab\n variant=\"secondary\"\n size=\"sm\"\n value=\"labels\"\n noTruncate\n class=\"h-9 min-w-[auto] items-center\">\n <span\n class=\"line-clamp-2 text-center leading-tight whitespace-normal\"\n >{{ \"labels\" | transloco }}</span\n >\n </Tab>\n }\n @if (similar.hasContent()) {\n <Tab\n variant=\"secondary\"\n size=\"sm\"\n value=\"similar\"\n noTruncate\n class=\"h-9 min-w-[auto] items-center\">\n <span\n class=\"line-clamp-2 text-center leading-tight whitespace-normal\"\n >{{ \"drawers.similarDocuments\" | transloco }}</span\n >\n </Tab>\n }\n </TabList>\n\n <!-- The single scroll container: each TabPanel is `absolute inset-0` (only the active one\n visible, per TabPanelComponent's own `[class.hidden]`), so they all share this one\n min-h-0/flex-1/overflow-y-auto region instead of the whole component scrolling. -->\n <div class=\"relative m-3 min-h-0 flex-1 scrollbar-thin overflow-y-auto\">\n <!-- Every TabPanel below cedes its own tab stop to its content (TabPanelComponent's `tabIndex`\n doc, ui/tabs/tabs.ts): the APG makes a tabpanel focusable only when it holds no focusable\n child, otherwise Tab from the tab lands on the empty container instead of the first row.\n `extracts` is always rendered (own empty/loading states, per the class doc above) so its\n tabindex is computed from whether it currently has any focusable row;\n `entities`/`matchlocations`/`labels`/`similar` are only ever mounted via `hasContent()`,\n which — per their `injectXState` — guarantees at least one row, so a static -1 is safe there. -->\n <TabPanel\n value=\"extracts\"\n [tabindex]=\"\n extracts.loading() || extracts.extracts().length === 0 ? 0 : -1\n \"\n class=\"absolute inset-0\">\n <article-extracts-tab-panel [state]=\"extracts\" />\n </TabPanel>\n @if (entities.hasContent()) {\n <TabPanel value=\"entities\" tabindex=\"-1\" class=\"absolute inset-0\">\n <article-entities-tab-panel [state]=\"entities\" />\n </TabPanel>\n }\n @if (matchLocations.hasContent()) {\n <TabPanel value=\"matchlocations\" tabindex=\"-1\" class=\"absolute inset-0\">\n <article-match-locations-tab-panel [state]=\"matchLocations\" />\n </TabPanel>\n }\n @if (labels.hasContent()) {\n <TabPanel value=\"labels\" tabindex=\"-1\" class=\"absolute inset-0\">\n <article-labels-tab-panel [article]=\"article()\" [state]=\"labels\" />\n </TabPanel>\n }\n @if (similar.hasContent()) {\n <TabPanel value=\"similar\" tabindex=\"-1\" class=\"absolute inset-0\">\n <article-similar-documents-tab-panel\n [article]=\"article()\"\n [strategy]=\"previewStrategy()\"\n [state]=\"similar\"\n (selected)=\"selected.emit($event)\" />\n </TabPanel>\n }\n </div>\n </Tabs>\n}\n",
|
|
10036
10030
|
dependencies: [
|
|
10037
10031
|
{
|
|
10038
10032
|
kind: "component",
|
|
10039
10033
|
type: SearchBarComponent,
|
|
10040
|
-
selector: "SearchBar, search-bar, searchbar"
|
|
10041
|
-
inputs: [
|
|
10042
|
-
"value",
|
|
10043
|
-
"placeholder",
|
|
10044
|
-
"ariaLabel",
|
|
10045
|
-
"clearLabel",
|
|
10046
|
-
"sendLabel",
|
|
10047
|
-
"disabled",
|
|
10048
|
-
"hotkey",
|
|
10049
|
-
"size",
|
|
10050
|
-
"class"
|
|
10051
|
-
],
|
|
10052
|
-
outputs: ["valueChange", "search"]
|
|
10034
|
+
selector: "SearchBar:not([suggestions]), search-bar:not([suggestions]), searchbar:not([suggestions])"
|
|
10053
10035
|
},
|
|
10054
10036
|
{
|
|
10055
10037
|
kind: "directive",
|
|
@@ -10147,10 +10129,9 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
10147
10129
|
ArticleMatchLocationsTabPanel,
|
|
10148
10130
|
ArticleSimilarDocumentsTabPanel
|
|
10149
10131
|
],
|
|
10150
|
-
template: "@if (article()) {\n <section class=\"mx-3 mt-3 mb-3 flex shrink-0 flex-col gap-4\">\n <!-- Enter submits
|
|
10132
|
+
template: "@if (article()) {\n <section class=\"mx-3 mt-3 mb-3 flex shrink-0 flex-col gap-4\">\n <!-- Enter submits through (keydown.enter), the send button through (search). No debounce: same \"submit on\n Enter/send, not on every keystroke\" contract as the previous input-group implementation. -->\n <SearchBar\n size=\"small\"\n [placeholder]=\"'drawers.inputPlaceholder' | transloco\"\n [aria-label]=\"'drawers.inputPlaceholder' | transloco\"\n [(value)]=\"queryText\"\n (keydown.enter)=\"executeSearch()\"\n (search)=\"executeSearch()\" />\n </section>\n\n <!-- flex-1/min-h-0: this is what lets the panel content below be the only thing that scrolls —\n the search bar/tab list above are shrink-0, never pushed off or scrolled themselves. -->\n <Tabs class=\"flex min-h-0 flex-1 flex-col\">\n <!-- noTruncate skips the default `truncate` branch (whose `has-[span]:[&>span]:truncate` would\n otherwise force this span back to single-line ellipsis, defeating the wrap below); overriding\n its own `min-w-fit` with `min-w-[auto]` restores the flex item's normal \"automatic minimum\n size\" instead — for content that can wrap, that floor is the longest word (min-content), not\n the full unwrapped label (max-content, what `fit-content` resolves to here with nothing\n constraining the available space). A single-word label has nothing to wrap, so min-content ==\n max-content and it can't be squeezed below its own readable width — the flex-shrink deficit\n falls on the multi-word labels that actually have room to give, which wrap onto the span's\n line-clamp-2 instead of being cut with an ellipsis (appropriate for a single-line pill, not\n for a tab bar where \"Similar documents\"/\"Match locations\" routinely don't fit on one line).\n h-9 (fixed, not h-auto) + items-center on every tab keeps the row visually even whether a\n given label wraps onto 2 lines or stays on 1. No horizontal scroll/truncation fallback here on\n purpose — see preview-actions.ts's [matchTriggerWidth]=\"false\" on the search popover: it's the\n popover itself that grows (shrink-to-fit, up to max-w-xl) to make room for this row instead of\n this row squeezing to fit a fixed popover width. -->\n <TabList\n class=\"mx-3 shrink-0\"\n variant=\"inner\"\n [selectedTab]=\"selectedTab()\"\n (selectedTabChange)=\"activeTab.set($event)\">\n <Tab\n variant=\"secondary\"\n size=\"sm\"\n value=\"extracts\"\n noTruncate\n class=\"h-9 min-w-[auto] items-center\">\n <span\n class=\"line-clamp-2 text-center leading-tight whitespace-normal\"\n >{{ \"extracts\" | transloco }}</span\n >\n </Tab>\n @if (entities.hasContent()) {\n <Tab\n variant=\"secondary\"\n size=\"sm\"\n value=\"entities\"\n noTruncate\n class=\"h-9 min-w-[auto] items-center\">\n <span\n class=\"line-clamp-2 text-center leading-tight whitespace-normal\"\n >{{ \"drawers.entitiesTab\" | transloco }}</span\n >\n </Tab>\n }\n @if (matchLocations.hasContent()) {\n <Tab\n variant=\"secondary\"\n size=\"sm\"\n value=\"matchlocations\"\n noTruncate\n class=\"h-9 min-w-[auto] items-center\">\n <span\n class=\"line-clamp-2 text-center leading-tight whitespace-normal\"\n >{{ \"column.matchlocations\" | transloco }}</span\n >\n </Tab>\n }\n @if (labels.hasContent()) {\n <Tab\n variant=\"secondary\"\n size=\"sm\"\n value=\"labels\"\n noTruncate\n class=\"h-9 min-w-[auto] items-center\">\n <span\n class=\"line-clamp-2 text-center leading-tight whitespace-normal\"\n >{{ \"labels\" | transloco }}</span\n >\n </Tab>\n }\n @if (similar.hasContent()) {\n <Tab\n variant=\"secondary\"\n size=\"sm\"\n value=\"similar\"\n noTruncate\n class=\"h-9 min-w-[auto] items-center\">\n <span\n class=\"line-clamp-2 text-center leading-tight whitespace-normal\"\n >{{ \"drawers.similarDocuments\" | transloco }}</span\n >\n </Tab>\n }\n </TabList>\n\n <!-- The single scroll container: each TabPanel is `absolute inset-0` (only the active one\n visible, per TabPanelComponent's own `[class.hidden]`), so they all share this one\n min-h-0/flex-1/overflow-y-auto region instead of the whole component scrolling. -->\n <div class=\"relative m-3 min-h-0 flex-1 scrollbar-thin overflow-y-auto\">\n <!-- Every TabPanel below cedes its own tab stop to its content (TabPanelComponent's `tabIndex`\n doc, ui/tabs/tabs.ts): the APG makes a tabpanel focusable only when it holds no focusable\n child, otherwise Tab from the tab lands on the empty container instead of the first row.\n `extracts` is always rendered (own empty/loading states, per the class doc above) so its\n tabindex is computed from whether it currently has any focusable row;\n `entities`/`matchlocations`/`labels`/`similar` are only ever mounted via `hasContent()`,\n which — per their `injectXState` — guarantees at least one row, so a static -1 is safe there. -->\n <TabPanel\n value=\"extracts\"\n [tabindex]=\"\n extracts.loading() || extracts.extracts().length === 0 ? 0 : -1\n \"\n class=\"absolute inset-0\">\n <article-extracts-tab-panel [state]=\"extracts\" />\n </TabPanel>\n @if (entities.hasContent()) {\n <TabPanel value=\"entities\" tabindex=\"-1\" class=\"absolute inset-0\">\n <article-entities-tab-panel [state]=\"entities\" />\n </TabPanel>\n }\n @if (matchLocations.hasContent()) {\n <TabPanel value=\"matchlocations\" tabindex=\"-1\" class=\"absolute inset-0\">\n <article-match-locations-tab-panel [state]=\"matchLocations\" />\n </TabPanel>\n }\n @if (labels.hasContent()) {\n <TabPanel value=\"labels\" tabindex=\"-1\" class=\"absolute inset-0\">\n <article-labels-tab-panel [article]=\"article()\" [state]=\"labels\" />\n </TabPanel>\n }\n @if (similar.hasContent()) {\n <TabPanel value=\"similar\" tabindex=\"-1\" class=\"absolute inset-0\">\n <article-similar-documents-tab-panel\n [article]=\"article()\"\n [strategy]=\"previewStrategy()\"\n [state]=\"similar\"\n (selected)=\"selected.emit($event)\" />\n </TabPanel>\n }\n </div>\n </Tabs>\n}\n"
|
|
10151
10133
|
}]
|
|
10152
10134
|
}],
|
|
10153
|
-
ctorParameters: () => [{ type: i0.DestroyRef }],
|
|
10154
10135
|
propDecorators: {
|
|
10155
10136
|
article: [{
|
|
10156
10137
|
type: i0.Input,
|
|
@@ -10821,7 +10802,8 @@ var PreviewActionsComponent = class PreviewActionsComponent {
|
|
|
10821
10802
|
"offset",
|
|
10822
10803
|
"config",
|
|
10823
10804
|
"lockPosition",
|
|
10824
|
-
"matchTriggerWidth"
|
|
10805
|
+
"matchTriggerWidth",
|
|
10806
|
+
"hideWhenTriggerHidden"
|
|
10825
10807
|
],
|
|
10826
10808
|
exportAs: ["popover", "dropdown"]
|
|
10827
10809
|
},
|
|
@@ -20468,6 +20450,7 @@ var FeatureFlagsDialogComponent = class FeatureFlagsDialogComponent {
|
|
|
20468
20450
|
"aria-label",
|
|
20469
20451
|
"aria-labelledby",
|
|
20470
20452
|
"presentational",
|
|
20453
|
+
"compact",
|
|
20471
20454
|
"tabIndex"
|
|
20472
20455
|
],
|
|
20473
20456
|
outputs: ["checkedChange"]
|
|
@@ -22849,6 +22832,7 @@ var AggregationDateComponent = class AggregationDateComponent {
|
|
|
22849
22832
|
onClear = output();
|
|
22850
22833
|
selectionChange = output();
|
|
22851
22834
|
filtersChange = output();
|
|
22835
|
+
aggregationOverridesChange = output();
|
|
22852
22836
|
isCollapsed = linkedSignal(() => this.collapsed(), ...ngDevMode ? [{ debugName: "isCollapsed" }] : /* istanbul ignore next */ []);
|
|
22853
22837
|
expanded = computed(() => this.isCollapsed() ? null : "", ...ngDevMode ? [{ debugName: "expanded" }] : /* istanbul ignore next */ []);
|
|
22854
22838
|
searchText = model("", ...ngDevMode ? [{ debugName: "searchText" }] : /* istanbul ignore next */ []);
|
|
@@ -22972,15 +22956,58 @@ var AggregationDateComponent = class AggregationDateComponent {
|
|
|
22972
22956
|
kind: "option",
|
|
22973
22957
|
option: this.optionToItemValue(option) ?? option
|
|
22974
22958
|
} : this.toRangeSelection(filter));
|
|
22959
|
+
this.aggregationOverridesChange.emit(this.overridesWithMask(this.selectedMask()));
|
|
22975
22960
|
this.filtersChange.emit(legacyFilterToFilter(filter));
|
|
22976
22961
|
}
|
|
22962
|
+
selectedMask() {
|
|
22963
|
+
const option = this.dateModel().option;
|
|
22964
|
+
if (!option || option === "custom-range") return void 0;
|
|
22965
|
+
return this.dateOptions().find((o) => o.display === option)?.mask;
|
|
22966
|
+
}
|
|
22967
|
+
currentOverrides() {
|
|
22968
|
+
return this.isControlled() ? this.controlledQuery()?.aggregation_overrides : this.queryParamsStore.aggregation_overrides?.();
|
|
22969
|
+
}
|
|
22970
|
+
overridesWithMask(mask) {
|
|
22971
|
+
const key = this.aggregation()?.name ?? this.name();
|
|
22972
|
+
const overrides = { ...this.currentOverrides() };
|
|
22973
|
+
if (key) {
|
|
22974
|
+
if (mask) overrides[key] = { mask };
|
|
22975
|
+
else delete overrides[key];
|
|
22976
|
+
}
|
|
22977
|
+
return Object.keys(overrides).length > 0 ? overrides : void 0;
|
|
22978
|
+
}
|
|
22979
|
+
storeMask(mask) {
|
|
22980
|
+
const next = this.overridesWithMask(mask);
|
|
22981
|
+
if (JSON.stringify(next) === JSON.stringify(this.currentOverrides())) return;
|
|
22982
|
+
this.queryParamsStore.patch({ aggregation_overrides: next }, void 0, { syncUrl: false });
|
|
22983
|
+
}
|
|
22984
|
+
maskedLabel(option) {
|
|
22985
|
+
if (!option.mask || !option.value || option.display !== option.value) return void 0;
|
|
22986
|
+
const [year, month] = option.value.split("-").map(Number);
|
|
22987
|
+
const format = option.mask === "YYYY" ? { year: "numeric" } : {
|
|
22988
|
+
year: "numeric",
|
|
22989
|
+
month: "long"
|
|
22990
|
+
};
|
|
22991
|
+
try {
|
|
22992
|
+
return new Intl.DateTimeFormat(this.lang(), {
|
|
22993
|
+
...format,
|
|
22994
|
+
timeZone: "UTC"
|
|
22995
|
+
}).format(new Date(Date.UTC(year, (month ?? 1) - 1, 1)));
|
|
22996
|
+
} catch {
|
|
22997
|
+
return;
|
|
22998
|
+
}
|
|
22999
|
+
}
|
|
22977
23000
|
select() {
|
|
22978
23001
|
this.selection.set(true);
|
|
22979
23002
|
}
|
|
22980
23003
|
apply() {
|
|
22981
23004
|
try {
|
|
22982
23005
|
if (this.isControlled()) this.emitCurrentSelection();
|
|
22983
|
-
else
|
|
23006
|
+
else {
|
|
23007
|
+
const filter = this.getFormValueFilter();
|
|
23008
|
+
this.storeMask(this.selectedMask());
|
|
23009
|
+
this.queryParamsStore.updateFilter(filter, void 0, { syncUrl: this.syncUrl() });
|
|
23010
|
+
}
|
|
22984
23011
|
this.selection.set(false);
|
|
22985
23012
|
this.onApply.emit();
|
|
22986
23013
|
} catch (err) {
|
|
@@ -23000,8 +23027,12 @@ var AggregationDateComponent = class AggregationDateComponent {
|
|
|
23000
23027
|
if (agg && notify) {
|
|
23001
23028
|
if (this.isControlled()) {
|
|
23002
23029
|
this.selectionChange.emit({ kind: "range" });
|
|
23030
|
+
this.aggregationOverridesChange.emit(this.overridesWithMask(void 0));
|
|
23003
23031
|
this.filtersChange.emit(void 0);
|
|
23004
|
-
} else
|
|
23032
|
+
} else {
|
|
23033
|
+
this.storeMask(void 0);
|
|
23034
|
+
this.queryParamsStore.removeFilterByName(agg.name, void 0, { syncUrl: this.syncUrl() });
|
|
23035
|
+
}
|
|
23005
23036
|
this.onClear.emit();
|
|
23006
23037
|
}
|
|
23007
23038
|
}
|
|
@@ -23060,8 +23091,8 @@ var AggregationDateComponent = class AggregationDateComponent {
|
|
|
23060
23091
|
this.clear(false);
|
|
23061
23092
|
return;
|
|
23062
23093
|
}
|
|
23063
|
-
const { operator
|
|
23064
|
-
const code = this.
|
|
23094
|
+
const { operator } = filter;
|
|
23095
|
+
const code = this.findPresetCode(filter) ?? "custom-range";
|
|
23065
23096
|
let from = null, to = null;
|
|
23066
23097
|
if (code === "custom-range") switch (operator) {
|
|
23067
23098
|
case "lte":
|
|
@@ -23074,12 +23105,7 @@ var AggregationDateComponent = class AggregationDateComponent {
|
|
|
23074
23105
|
from = filter.start;
|
|
23075
23106
|
to = filter.end;
|
|
23076
23107
|
break;
|
|
23077
|
-
case "and": {
|
|
23078
|
-
const filters = filter.filters;
|
|
23079
|
-
from = filters?.find((f) => f.operator === "gte")?.value ?? null;
|
|
23080
|
-
to = filters?.find((f) => f.operator === "lte")?.value ?? null;
|
|
23081
|
-
break;
|
|
23082
|
-
}
|
|
23108
|
+
case "and": ({from, to} = this.toBounds(filter.filters));
|
|
23083
23109
|
}
|
|
23084
23110
|
const formValue = {
|
|
23085
23111
|
option: code,
|
|
@@ -23090,6 +23116,29 @@ var AggregationDateComponent = class AggregationDateComponent {
|
|
|
23090
23116
|
};
|
|
23091
23117
|
this.setModel(formValue);
|
|
23092
23118
|
}
|
|
23119
|
+
findPresetCode(filter) {
|
|
23120
|
+
const options = this.dateOptions();
|
|
23121
|
+
const exact = options.find((option) => option.operator === filter.operator && option.value === filter.value);
|
|
23122
|
+
if (exact) return exact.display;
|
|
23123
|
+
if (filter.operator !== "and") return void 0;
|
|
23124
|
+
const { from, to } = this.toBounds(filter.filters);
|
|
23125
|
+
if (!from || !to) return void 0;
|
|
23126
|
+
return options.find((option) => {
|
|
23127
|
+
if (option.operator !== "and") return false;
|
|
23128
|
+
const bounds = this.toBounds(option.filters);
|
|
23129
|
+
return bounds.from === from && bounds.to === to;
|
|
23130
|
+
})?.display;
|
|
23131
|
+
}
|
|
23132
|
+
toBounds(filters) {
|
|
23133
|
+
const bound = (...operators) => {
|
|
23134
|
+
const value = filters?.find((f) => operators.includes(f.operator))?.value;
|
|
23135
|
+
return value === void 0 || value === null ? null : String(value);
|
|
23136
|
+
};
|
|
23137
|
+
return {
|
|
23138
|
+
from: bound("gte"),
|
|
23139
|
+
to: bound("lte", "lt")
|
|
23140
|
+
};
|
|
23141
|
+
}
|
|
23093
23142
|
updateFormFromSelection(sel) {
|
|
23094
23143
|
if (sel?.kind === "option") {
|
|
23095
23144
|
const code = this.itemValueToOption(sel.option);
|
|
@@ -23151,11 +23200,11 @@ var AggregationDateComponent = class AggregationDateComponent {
|
|
|
23151
23200
|
to: filter.end
|
|
23152
23201
|
};
|
|
23153
23202
|
case "and": {
|
|
23154
|
-
const
|
|
23203
|
+
const { from, to } = this.toBounds(filter.filters);
|
|
23155
23204
|
return {
|
|
23156
23205
|
kind: "range",
|
|
23157
|
-
from:
|
|
23158
|
-
to:
|
|
23206
|
+
from: from ?? void 0,
|
|
23207
|
+
to: to ?? void 0
|
|
23159
23208
|
};
|
|
23160
23209
|
}
|
|
23161
23210
|
default: return {
|
|
@@ -23344,12 +23393,13 @@ var AggregationDateComponent = class AggregationDateComponent {
|
|
|
23344
23393
|
onClear: "onClear",
|
|
23345
23394
|
selectionChange: "selectionChange",
|
|
23346
23395
|
filtersChange: "filtersChange",
|
|
23396
|
+
aggregationOverridesChange: "aggregationOverridesChange",
|
|
23347
23397
|
searchText: "searchTextChange"
|
|
23348
23398
|
},
|
|
23349
23399
|
host: { properties: { "class": "cn(\"@container block\", isEmpty() && \"hidden\")" } },
|
|
23350
23400
|
providers: [provideTranslocoScope("filters")],
|
|
23351
23401
|
ngImport: i0,
|
|
23352
|
-
template: "<!-- `<details>`/`<summary>` stay native (open/close, the `name`-based exclusive accordion). A facet is a\n disclosure, not a grid row: see `aggregation-panel.html` for the why (same pattern, duplicated here\n since this facet type doesn't go through `AggregationPanelComponent`). The `<summary>` itself is\n `tabindex=\"-1\"`: the header's buttons (apply, clear, chevron) are the keyboard stops, see the\n chevron below. -->\n<details [attr.open]=\"expanded()\" [attr.name]=\"id()\" class=\"group space-y-2\">\n <!-- scroll-mb-3/scroll-mt-16: see aggregation-panel-row.html for the full rationale\n (bottom margin against the container's edge, much bigger top margin to also clear\n <More>'s sticky facet-name search box when navigating ArrowUp). -->\n <summary\n tabindex=\"-1\"\n [class.cursor-pointer]=\"collapsible()\"\n [class]=\"rowStateClass\"\n class=\"m-0 flex h-8 w-full scroll-mt-16 scroll-mb-3 items-center gap-1 pl-1 font-semibold select-none\"\n (click)=\"onHeaderClick($event)\">\n <ng-content select=\"label\">\n @let icon = aggregation()?.icon;\n @if (icon) {\n <FaIcon [faClass]=\"icon\" class=\"mr-1 shrink-0\" />\n }\n <span class=\"grow\">{{\n aggregation()?.display | syslang | transloco\n }}</span>\n </ng-content>\n\n @if (hasFilters()) {\n @let clearLabel = \"filters.clearFilters\" | transloco;\n <button\n type=\"button\"\n variant=\"tertiary\"\n [iconOnly]=\"true\"\n size=\"sm\"\n class=\"shrink-0\"\n [aria-label]=\"clearLabel\"\n [tooltip]=\"clearLabel\"\n (click)=\"$event.stopPropagation(); clear()\">\n <filter-x-icon class=\"shrink-0\" />\n </button>\n }\n\n @if (\n (!isControlled() || emitOn() === \"apply\") &&\n selection() &&\n validSelection()\n ) {\n @let label = \"filters.apply\" | transloco;\n <button\n type=\"button\"\n variant=\"accent\"\n size=\"sm\"\n class=\"overflow-hidden\"\n [aria-label]=\"label\"\n [tooltip]=\"label\"\n (click)=\"$event.stopPropagation(); apply()\">\n <FilterIcon class=\"shrink-0\" />\n <span class=\"truncate\">{{ label }}</span>\n </button>\n }\n @if (collapsible()) {\n <!-- The `<summary>` is out of the tab order (`tabindex=\"-1\"`), so this button is the keyboard way to\n collapse the facet. Its click bubbles to the `<summary>`, whose handler does the toggle, and it\n exposes `aria-expanded`. -->\n <button\n type=\"button\"\n variant=\"tertiary\"\n [iconOnly]=\"true\"\n size=\"sm\"\n [aria-label]=\"'filters.toggle' | transloco\"\n [attr.aria-expanded]=\"!isCollapsed()\"\n [tooltip]=\"'filters.toggle' | transloco\"\n class=\"shrink-0 cursor-pointer [&_svg]:transition-transform [&_svg]:duration-150 group-open:[&_svg]:rotate-90\">\n <chevron-right class=\"shrink-0\" />\n </button>\n }\n </summary>\n\n <!-- content wrapper -->\n <!-- RGAA 11.5 / WCAG 1.3.1: the radios below all share one `name`, so they are one set\n and have to be exposed as one. `role=\"group\"` here rather than `role=\"radiogroup\"`\n on the list: a radiogroup owns its radios directly, and the <li> in between would be\n invalid owned children — the list would also stop announcing how many options it\n holds. The name is the aggregation's own title, the words the header already shows;\n with no title the group stays unnamed rather than carrying an empty label. -->\n @let groupName = aggregation()?.display;\n <form (keydown.enter)=\"onOptionEnter($event)\">\n <div\n role=\"group\"\n [attr.aria-label]=\"groupName ? (groupName | syslang | transloco) : null\">\n <ul\n class=\"flex max-h-(--scroll-height,20rem) snap-y snap-start scrollbar-thin flex-col gap-0.5 overflow-auto pt-2\"\n role=\"list\">\n @for (option of dateOptions(); track
|
|
23402
|
+
template: "<!-- `<details>`/`<summary>` stay native (open/close, the `name`-based exclusive accordion). A facet is a\n disclosure, not a grid row: see `aggregation-panel.html` for the why (same pattern, duplicated here\n since this facet type doesn't go through `AggregationPanelComponent`). The `<summary>` itself is\n `tabindex=\"-1\"`: the header's buttons (apply, clear, chevron) are the keyboard stops, see the\n chevron below. -->\n<details [attr.open]=\"expanded()\" [attr.name]=\"id()\" class=\"group space-y-2\">\n <!-- scroll-mb-3/scroll-mt-16: see aggregation-panel-row.html for the full rationale\n (bottom margin against the container's edge, much bigger top margin to also clear\n <More>'s sticky facet-name search box when navigating ArrowUp). -->\n <summary\n tabindex=\"-1\"\n [class.cursor-pointer]=\"collapsible()\"\n [class]=\"rowStateClass\"\n class=\"m-0 flex h-8 w-full scroll-mt-16 scroll-mb-3 items-center gap-1 pl-1 font-semibold select-none\"\n (click)=\"onHeaderClick($event)\">\n <ng-content select=\"label\">\n @let icon = aggregation()?.icon;\n @if (icon) {\n <FaIcon [faClass]=\"icon\" class=\"mr-1 shrink-0\" />\n }\n <span class=\"grow\">{{\n aggregation()?.display | syslang | transloco\n }}</span>\n </ng-content>\n\n @if (hasFilters()) {\n @let clearLabel = \"filters.clearFilters\" | transloco;\n <button\n type=\"button\"\n variant=\"tertiary\"\n [iconOnly]=\"true\"\n size=\"sm\"\n class=\"shrink-0\"\n [aria-label]=\"clearLabel\"\n [tooltip]=\"clearLabel\"\n (click)=\"$event.stopPropagation(); clear()\">\n <filter-x-icon class=\"shrink-0\" />\n </button>\n }\n\n @if (\n (!isControlled() || emitOn() === \"apply\") &&\n selection() &&\n validSelection()\n ) {\n @let label = \"filters.apply\" | transloco;\n <button\n type=\"button\"\n variant=\"accent\"\n size=\"sm\"\n class=\"overflow-hidden\"\n [aria-label]=\"label\"\n [tooltip]=\"label\"\n (click)=\"$event.stopPropagation(); apply()\">\n <FilterIcon class=\"shrink-0\" />\n <span class=\"truncate\">{{ label }}</span>\n </button>\n }\n @if (collapsible()) {\n <!-- The `<summary>` is out of the tab order (`tabindex=\"-1\"`), so this button is the keyboard way to\n collapse the facet. Its click bubbles to the `<summary>`, whose handler does the toggle, and it\n exposes `aria-expanded`. -->\n <button\n type=\"button\"\n variant=\"tertiary\"\n [iconOnly]=\"true\"\n size=\"sm\"\n [aria-label]=\"'filters.toggle' | transloco\"\n [attr.aria-expanded]=\"!isCollapsed()\"\n [tooltip]=\"'filters.toggle' | transloco\"\n class=\"shrink-0 cursor-pointer [&_svg]:transition-transform [&_svg]:duration-150 group-open:[&_svg]:rotate-90\">\n <chevron-right class=\"shrink-0\" />\n </button>\n }\n </summary>\n\n <!-- content wrapper -->\n <!-- RGAA 11.5 / WCAG 1.3.1: the radios below all share one `name`, so they are one set\n and have to be exposed as one. `role=\"group\"` here rather than `role=\"radiogroup\"`\n on the list: a radiogroup owns its radios directly, and the <li> in between would be\n invalid owned children — the list would also stop announcing how many options it\n holds. The name is the aggregation's own title, the words the header already shows;\n with no title the group stays unnamed rather than carrying an empty label. -->\n @let groupName = aggregation()?.display;\n <form (keydown.enter)=\"onOptionEnter($event)\">\n <div\n role=\"group\"\n [attr.aria-label]=\"groupName ? (groupName | syslang | transloco) : null\">\n <ul\n class=\"flex max-h-(--scroll-height,20rem) snap-y snap-start scrollbar-thin flex-col gap-0.5 overflow-auto pt-2\"\n role=\"list\">\n @for (option of dateOptions(); track option.display) {\n <li\n role=\"listitem\"\n [attr.aria-label]=\"\n maskedLabel(option) ?? (option.display | syslang | transloco)\n \"\n [class]=\"\n cn(\n itemStateClass,\n 'flex cursor-pointer items-center p-2 text-sm text-(--font-neutral-base) select-none',\n dateModel().option === option.display &&\n 'bg-(--bg-primary-lighter)',\n option.hidden && 'hidden',\n option.disabled && 'pointer-events-none opacity-40'\n )\n \"\n [attr.aria-hidden]=\"option.disabled\">\n <radio\n name=\"date-filter\"\n class=\"grow\"\n [checked]=\"dateModel().option === option.display\"\n [disabled]=\"option.disabled\"\n (checkedChange)=\"selectOption(option.display)\">\n {{\n maskedLabel(option) ?? (option.display | syslang | transloco)\n }}\n </radio>\n </li>\n }\n\n @if (allowCustomRange) {\n <li\n role=\"listitem\"\n aria-label=\"open date range picker\"\n [class]=\"\n cn(\n itemStateClass,\n 'flex cursor-pointer items-center gap-(--spacing-xs) p-2 text-sm text-(--font-neutral-base) select-none',\n dateModel().option === 'custom-range' &&\n 'bg-(--bg-primary-lighter)'\n )\n \">\n <radio\n name=\"date-filter\"\n class=\"grow items-center\"\n [checked]=\"dateModel().option === 'custom-range'\"\n (checkedChange)=\"selectOption('custom-range')\">\n <div class=\"flex flex-wrap items-center gap-x-1 gap-y-1\">\n <div class=\"flex items-center gap-1\">\n <label\n [attr.for]=\"startId\"\n class=\"radio-label min-w-8 truncate\"\n >{{ \"filters.from\" | transloco }}</label\n >\n <input-group\n class=\"h-8 max-w-[18ch] min-w-[18ch] has-[[readonly]]:border-(--stroke-primary-muted)\">\n <input\n input-control\n [id]=\"startId\"\n name=\"start\"\n type=\"text\"\n readonly\n [value]=\"customRangeFrom()\"\n (click)=\"selectAndOpenDialog()\"\n (keydown.enter)=\"onRangeInputEnter($event)\" />\n </input-group>\n </div>\n <div class=\"flex items-center gap-1\">\n <label\n [attr.for]=\"endId\"\n class=\"radio-label min-w-8 truncate text-right\"\n >{{ \"filters.to\" | transloco }}</label\n >\n <input-group\n class=\"h-8 max-w-[18ch] min-w-[18ch] has-[[readonly]]:border-(--stroke-primary-muted)\">\n <input\n input-control\n [id]=\"endId\"\n name=\"end\"\n type=\"text\"\n readonly\n [value]=\"customRangeTo()\"\n (click)=\"selectAndOpenDialog()\"\n (keydown.enter)=\"onRangeInputEnter($event)\" />\n </input-group>\n </div>\n </div>\n </radio>\n </li>\n }\n </ul>\n </div>\n </form>\n</details>\n",
|
|
23353
23403
|
styles: [":host{min-width:200px}ul[role=list]{scrollbar-width:thin}\n"],
|
|
23354
23404
|
dependencies: [
|
|
23355
23405
|
{
|
|
@@ -23484,7 +23534,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
23484
23534
|
TooltipDirective
|
|
23485
23535
|
],
|
|
23486
23536
|
host: { "[class]": "cn(\"@container block\", isEmpty() && \"hidden\")" },
|
|
23487
|
-
template: "<!-- `<details>`/`<summary>` stay native (open/close, the `name`-based exclusive accordion). A facet is a\n disclosure, not a grid row: see `aggregation-panel.html` for the why (same pattern, duplicated here\n since this facet type doesn't go through `AggregationPanelComponent`). The `<summary>` itself is\n `tabindex=\"-1\"`: the header's buttons (apply, clear, chevron) are the keyboard stops, see the\n chevron below. -->\n<details [attr.open]=\"expanded()\" [attr.name]=\"id()\" class=\"group space-y-2\">\n <!-- scroll-mb-3/scroll-mt-16: see aggregation-panel-row.html for the full rationale\n (bottom margin against the container's edge, much bigger top margin to also clear\n <More>'s sticky facet-name search box when navigating ArrowUp). -->\n <summary\n tabindex=\"-1\"\n [class.cursor-pointer]=\"collapsible()\"\n [class]=\"rowStateClass\"\n class=\"m-0 flex h-8 w-full scroll-mt-16 scroll-mb-3 items-center gap-1 pl-1 font-semibold select-none\"\n (click)=\"onHeaderClick($event)\">\n <ng-content select=\"label\">\n @let icon = aggregation()?.icon;\n @if (icon) {\n <FaIcon [faClass]=\"icon\" class=\"mr-1 shrink-0\" />\n }\n <span class=\"grow\">{{\n aggregation()?.display | syslang | transloco\n }}</span>\n </ng-content>\n\n @if (hasFilters()) {\n @let clearLabel = \"filters.clearFilters\" | transloco;\n <button\n type=\"button\"\n variant=\"tertiary\"\n [iconOnly]=\"true\"\n size=\"sm\"\n class=\"shrink-0\"\n [aria-label]=\"clearLabel\"\n [tooltip]=\"clearLabel\"\n (click)=\"$event.stopPropagation(); clear()\">\n <filter-x-icon class=\"shrink-0\" />\n </button>\n }\n\n @if (\n (!isControlled() || emitOn() === \"apply\") &&\n selection() &&\n validSelection()\n ) {\n @let label = \"filters.apply\" | transloco;\n <button\n type=\"button\"\n variant=\"accent\"\n size=\"sm\"\n class=\"overflow-hidden\"\n [aria-label]=\"label\"\n [tooltip]=\"label\"\n (click)=\"$event.stopPropagation(); apply()\">\n <FilterIcon class=\"shrink-0\" />\n <span class=\"truncate\">{{ label }}</span>\n </button>\n }\n @if (collapsible()) {\n <!-- The `<summary>` is out of the tab order (`tabindex=\"-1\"`), so this button is the keyboard way to\n collapse the facet. Its click bubbles to the `<summary>`, whose handler does the toggle, and it\n exposes `aria-expanded`. -->\n <button\n type=\"button\"\n variant=\"tertiary\"\n [iconOnly]=\"true\"\n size=\"sm\"\n [aria-label]=\"'filters.toggle' | transloco\"\n [attr.aria-expanded]=\"!isCollapsed()\"\n [tooltip]=\"'filters.toggle' | transloco\"\n class=\"shrink-0 cursor-pointer [&_svg]:transition-transform [&_svg]:duration-150 group-open:[&_svg]:rotate-90\">\n <chevron-right class=\"shrink-0\" />\n </button>\n }\n </summary>\n\n <!-- content wrapper -->\n <!-- RGAA 11.5 / WCAG 1.3.1: the radios below all share one `name`, so they are one set\n and have to be exposed as one. `role=\"group\"` here rather than `role=\"radiogroup\"`\n on the list: a radiogroup owns its radios directly, and the <li> in between would be\n invalid owned children — the list would also stop announcing how many options it\n holds. The name is the aggregation's own title, the words the header already shows;\n with no title the group stays unnamed rather than carrying an empty label. -->\n @let groupName = aggregation()?.display;\n <form (keydown.enter)=\"onOptionEnter($event)\">\n <div\n role=\"group\"\n [attr.aria-label]=\"groupName ? (groupName | syslang | transloco) : null\">\n <ul\n class=\"flex max-h-(--scroll-height,20rem) snap-y snap-start scrollbar-thin flex-col gap-0.5 overflow-auto pt-2\"\n role=\"list\">\n @for (option of dateOptions(); track
|
|
23537
|
+
template: "<!-- `<details>`/`<summary>` stay native (open/close, the `name`-based exclusive accordion). A facet is a\n disclosure, not a grid row: see `aggregation-panel.html` for the why (same pattern, duplicated here\n since this facet type doesn't go through `AggregationPanelComponent`). The `<summary>` itself is\n `tabindex=\"-1\"`: the header's buttons (apply, clear, chevron) are the keyboard stops, see the\n chevron below. -->\n<details [attr.open]=\"expanded()\" [attr.name]=\"id()\" class=\"group space-y-2\">\n <!-- scroll-mb-3/scroll-mt-16: see aggregation-panel-row.html for the full rationale\n (bottom margin against the container's edge, much bigger top margin to also clear\n <More>'s sticky facet-name search box when navigating ArrowUp). -->\n <summary\n tabindex=\"-1\"\n [class.cursor-pointer]=\"collapsible()\"\n [class]=\"rowStateClass\"\n class=\"m-0 flex h-8 w-full scroll-mt-16 scroll-mb-3 items-center gap-1 pl-1 font-semibold select-none\"\n (click)=\"onHeaderClick($event)\">\n <ng-content select=\"label\">\n @let icon = aggregation()?.icon;\n @if (icon) {\n <FaIcon [faClass]=\"icon\" class=\"mr-1 shrink-0\" />\n }\n <span class=\"grow\">{{\n aggregation()?.display | syslang | transloco\n }}</span>\n </ng-content>\n\n @if (hasFilters()) {\n @let clearLabel = \"filters.clearFilters\" | transloco;\n <button\n type=\"button\"\n variant=\"tertiary\"\n [iconOnly]=\"true\"\n size=\"sm\"\n class=\"shrink-0\"\n [aria-label]=\"clearLabel\"\n [tooltip]=\"clearLabel\"\n (click)=\"$event.stopPropagation(); clear()\">\n <filter-x-icon class=\"shrink-0\" />\n </button>\n }\n\n @if (\n (!isControlled() || emitOn() === \"apply\") &&\n selection() &&\n validSelection()\n ) {\n @let label = \"filters.apply\" | transloco;\n <button\n type=\"button\"\n variant=\"accent\"\n size=\"sm\"\n class=\"overflow-hidden\"\n [aria-label]=\"label\"\n [tooltip]=\"label\"\n (click)=\"$event.stopPropagation(); apply()\">\n <FilterIcon class=\"shrink-0\" />\n <span class=\"truncate\">{{ label }}</span>\n </button>\n }\n @if (collapsible()) {\n <!-- The `<summary>` is out of the tab order (`tabindex=\"-1\"`), so this button is the keyboard way to\n collapse the facet. Its click bubbles to the `<summary>`, whose handler does the toggle, and it\n exposes `aria-expanded`. -->\n <button\n type=\"button\"\n variant=\"tertiary\"\n [iconOnly]=\"true\"\n size=\"sm\"\n [aria-label]=\"'filters.toggle' | transloco\"\n [attr.aria-expanded]=\"!isCollapsed()\"\n [tooltip]=\"'filters.toggle' | transloco\"\n class=\"shrink-0 cursor-pointer [&_svg]:transition-transform [&_svg]:duration-150 group-open:[&_svg]:rotate-90\">\n <chevron-right class=\"shrink-0\" />\n </button>\n }\n </summary>\n\n <!-- content wrapper -->\n <!-- RGAA 11.5 / WCAG 1.3.1: the radios below all share one `name`, so they are one set\n and have to be exposed as one. `role=\"group\"` here rather than `role=\"radiogroup\"`\n on the list: a radiogroup owns its radios directly, and the <li> in between would be\n invalid owned children — the list would also stop announcing how many options it\n holds. The name is the aggregation's own title, the words the header already shows;\n with no title the group stays unnamed rather than carrying an empty label. -->\n @let groupName = aggregation()?.display;\n <form (keydown.enter)=\"onOptionEnter($event)\">\n <div\n role=\"group\"\n [attr.aria-label]=\"groupName ? (groupName | syslang | transloco) : null\">\n <ul\n class=\"flex max-h-(--scroll-height,20rem) snap-y snap-start scrollbar-thin flex-col gap-0.5 overflow-auto pt-2\"\n role=\"list\">\n @for (option of dateOptions(); track option.display) {\n <li\n role=\"listitem\"\n [attr.aria-label]=\"\n maskedLabel(option) ?? (option.display | syslang | transloco)\n \"\n [class]=\"\n cn(\n itemStateClass,\n 'flex cursor-pointer items-center p-2 text-sm text-(--font-neutral-base) select-none',\n dateModel().option === option.display &&\n 'bg-(--bg-primary-lighter)',\n option.hidden && 'hidden',\n option.disabled && 'pointer-events-none opacity-40'\n )\n \"\n [attr.aria-hidden]=\"option.disabled\">\n <radio\n name=\"date-filter\"\n class=\"grow\"\n [checked]=\"dateModel().option === option.display\"\n [disabled]=\"option.disabled\"\n (checkedChange)=\"selectOption(option.display)\">\n {{\n maskedLabel(option) ?? (option.display | syslang | transloco)\n }}\n </radio>\n </li>\n }\n\n @if (allowCustomRange) {\n <li\n role=\"listitem\"\n aria-label=\"open date range picker\"\n [class]=\"\n cn(\n itemStateClass,\n 'flex cursor-pointer items-center gap-(--spacing-xs) p-2 text-sm text-(--font-neutral-base) select-none',\n dateModel().option === 'custom-range' &&\n 'bg-(--bg-primary-lighter)'\n )\n \">\n <radio\n name=\"date-filter\"\n class=\"grow items-center\"\n [checked]=\"dateModel().option === 'custom-range'\"\n (checkedChange)=\"selectOption('custom-range')\">\n <div class=\"flex flex-wrap items-center gap-x-1 gap-y-1\">\n <div class=\"flex items-center gap-1\">\n <label\n [attr.for]=\"startId\"\n class=\"radio-label min-w-8 truncate\"\n >{{ \"filters.from\" | transloco }}</label\n >\n <input-group\n class=\"h-8 max-w-[18ch] min-w-[18ch] has-[[readonly]]:border-(--stroke-primary-muted)\">\n <input\n input-control\n [id]=\"startId\"\n name=\"start\"\n type=\"text\"\n readonly\n [value]=\"customRangeFrom()\"\n (click)=\"selectAndOpenDialog()\"\n (keydown.enter)=\"onRangeInputEnter($event)\" />\n </input-group>\n </div>\n <div class=\"flex items-center gap-1\">\n <label\n [attr.for]=\"endId\"\n class=\"radio-label min-w-8 truncate text-right\"\n >{{ \"filters.to\" | transloco }}</label\n >\n <input-group\n class=\"h-8 max-w-[18ch] min-w-[18ch] has-[[readonly]]:border-(--stroke-primary-muted)\">\n <input\n input-control\n [id]=\"endId\"\n name=\"end\"\n type=\"text\"\n readonly\n [value]=\"customRangeTo()\"\n (click)=\"selectAndOpenDialog()\"\n (keydown.enter)=\"onRangeInputEnter($event)\" />\n </input-group>\n </div>\n </div>\n </radio>\n </li>\n }\n </ul>\n </div>\n </form>\n</details>\n",
|
|
23488
23538
|
styles: [":host{min-width:200px}ul[role=list]{scrollbar-width:thin}\n"]
|
|
23489
23539
|
}]
|
|
23490
23540
|
}],
|
|
@@ -23622,6 +23672,10 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
23622
23672
|
type: i0.Output,
|
|
23623
23673
|
args: ["filtersChange"]
|
|
23624
23674
|
}],
|
|
23675
|
+
aggregationOverridesChange: [{
|
|
23676
|
+
type: i0.Output,
|
|
23677
|
+
args: ["aggregationOverridesChange"]
|
|
23678
|
+
}],
|
|
23625
23679
|
searchText: [{
|
|
23626
23680
|
type: i0.Input,
|
|
23627
23681
|
args: [{
|
|
@@ -23866,19 +23920,7 @@ var AggregationPanelComponent = class AggregationPanelComponent {
|
|
|
23866
23920
|
{
|
|
23867
23921
|
kind: "component",
|
|
23868
23922
|
type: SearchInputComponent,
|
|
23869
|
-
selector: "SearchInput, search-input, searchinput"
|
|
23870
|
-
inputs: [
|
|
23871
|
-
"value",
|
|
23872
|
-
"placeholder",
|
|
23873
|
-
"disabled",
|
|
23874
|
-
"aria-label",
|
|
23875
|
-
"hotkey",
|
|
23876
|
-
"clearLabel",
|
|
23877
|
-
"class",
|
|
23878
|
-
"size",
|
|
23879
|
-
"textSize"
|
|
23880
|
-
],
|
|
23881
|
-
outputs: ["valueChange"]
|
|
23923
|
+
selector: "SearchInput:not([suggestions]), search-input:not([suggestions]), searchinput:not([suggestions])"
|
|
23882
23924
|
},
|
|
23883
23925
|
{
|
|
23884
23926
|
kind: "component",
|
|
@@ -26474,6 +26516,7 @@ var AggregationComponent = class AggregationComponent {
|
|
|
26474
26516
|
"onClear",
|
|
26475
26517
|
"selectionChange",
|
|
26476
26518
|
"filtersChange",
|
|
26519
|
+
"aggregationOverridesChange",
|
|
26477
26520
|
"searchTextChange"
|
|
26478
26521
|
]
|
|
26479
26522
|
}
|
|
@@ -27691,7 +27734,8 @@ var FilterButtonComponent = class FilterButtonComponent {
|
|
|
27691
27734
|
"offset",
|
|
27692
27735
|
"config",
|
|
27693
27736
|
"lockPosition",
|
|
27694
|
-
"matchTriggerWidth"
|
|
27737
|
+
"matchTriggerWidth",
|
|
27738
|
+
"hideWhenTriggerHidden"
|
|
27695
27739
|
],
|
|
27696
27740
|
exportAs: ["popover", "dropdown"]
|
|
27697
27741
|
},
|
|
@@ -28112,19 +28156,7 @@ var MoreComponent = class MoreComponent {
|
|
|
28112
28156
|
{
|
|
28113
28157
|
kind: "component",
|
|
28114
28158
|
type: SearchInputComponent,
|
|
28115
|
-
selector: "SearchInput, search-input, searchinput"
|
|
28116
|
-
inputs: [
|
|
28117
|
-
"value",
|
|
28118
|
-
"placeholder",
|
|
28119
|
-
"disabled",
|
|
28120
|
-
"aria-label",
|
|
28121
|
-
"hotkey",
|
|
28122
|
-
"clearLabel",
|
|
28123
|
-
"class",
|
|
28124
|
-
"size",
|
|
28125
|
-
"textSize"
|
|
28126
|
-
],
|
|
28127
|
-
outputs: ["valueChange"]
|
|
28159
|
+
selector: "SearchInput:not([suggestions]), search-input:not([suggestions]), searchinput:not([suggestions])"
|
|
28128
28160
|
},
|
|
28129
28161
|
{
|
|
28130
28162
|
kind: "pipe",
|
|
@@ -28538,7 +28570,8 @@ var MoreButtonComponent = class MoreButtonComponent {
|
|
|
28538
28570
|
"offset",
|
|
28539
28571
|
"config",
|
|
28540
28572
|
"lockPosition",
|
|
28541
|
-
"matchTriggerWidth"
|
|
28573
|
+
"matchTriggerWidth",
|
|
28574
|
+
"hideWhenTriggerHidden"
|
|
28542
28575
|
],
|
|
28543
28576
|
exportAs: ["popover", "dropdown"]
|
|
28544
28577
|
},
|