@trackunit/filters-filter-bar 1.3.210 → 1.3.211
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/index.cjs.js +290 -253
- package/index.esm.js +293 -258
- package/package.json +13 -13
- package/src/lib/FilterBar.d.ts +1 -1
- package/src/lib/components/AppliedFiltersRenderer.d.ts +8 -0
- package/src/lib/components/FilterTooltips/MultipleFilterTooltipLabel.d.ts +2 -2
- package/src/lib/components/FilterTooltips/SingleFilterTooltipLabel.d.ts +2 -2
- package/src/lib/components/index.d.ts +2 -0
- package/src/lib/hooks/mockFilterBar.d.ts +3 -42
- package/src/lib/types/FilterTypes.d.ts +9 -2
package/index.cjs.js
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
4
|
var i18nLibraryTranslation = require('@trackunit/i18n-library-translation');
|
|
5
|
+
var reactFilterComponents = require('@trackunit/react-filter-components');
|
|
5
6
|
var reactComponents = require('@trackunit/react-components');
|
|
6
7
|
var reactCoreHooks = require('@trackunit/react-core-hooks');
|
|
7
|
-
var reactFilterComponents = require('@trackunit/react-filter-components');
|
|
8
8
|
var react = require('react');
|
|
9
9
|
var stringTs = require('string-ts');
|
|
10
10
|
var reactCoreContextsApi = require('@trackunit/react-core-contexts-api');
|
|
@@ -320,6 +320,137 @@ const setupLibraryTranslations = () => {
|
|
|
320
320
|
i18nLibraryTranslation.registerTranslations(translations);
|
|
321
321
|
};
|
|
322
322
|
|
|
323
|
+
/**
|
|
324
|
+
* Returns the two first values, appends counter if more.
|
|
325
|
+
*
|
|
326
|
+
* @param {string[]} [input] Array of values to reduce
|
|
327
|
+
* @returns {*} {string}
|
|
328
|
+
*/
|
|
329
|
+
const reduceFilterText = (input) => {
|
|
330
|
+
if (!Array.isArray(input)) {
|
|
331
|
+
return input;
|
|
332
|
+
}
|
|
333
|
+
// Only first two elements
|
|
334
|
+
const firstTwo = input.slice(0, 2);
|
|
335
|
+
const remainder = input.slice(2, input.length).length;
|
|
336
|
+
const firstTwoJoined = firstTwo.join(", ");
|
|
337
|
+
const remainderStr = remainder > 0 ? `, +${remainder}` : "";
|
|
338
|
+
return firstTwoJoined + remainderStr;
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Filter is a React component that renders a filter element based on the provided filter definition and state.
|
|
343
|
+
*
|
|
344
|
+
* @returns {ReactElement} - Returns the Filter component.
|
|
345
|
+
*/
|
|
346
|
+
const FilterComponent = ({ filter, filterBarActions, filterState, readOnly = false, visualStyle = "button", className, asIcon, size, }) => {
|
|
347
|
+
const values = filterBarActions.getValuesByKey(filter.filterKey);
|
|
348
|
+
const valuesLength = values && Array.isArray(values) ? values.length : undefined;
|
|
349
|
+
const getFilterText = () => {
|
|
350
|
+
if (!values) {
|
|
351
|
+
return undefined;
|
|
352
|
+
}
|
|
353
|
+
if (filter.valueAsText) {
|
|
354
|
+
return reduceFilterText(filter.valueAsText(values));
|
|
355
|
+
}
|
|
356
|
+
else if (filter.type === "valueNameArray") {
|
|
357
|
+
return reduceFilterText(values.map(value => value.name));
|
|
358
|
+
}
|
|
359
|
+
else if (filter.type === "valueName") {
|
|
360
|
+
return values.name;
|
|
361
|
+
}
|
|
362
|
+
return values.toString();
|
|
363
|
+
};
|
|
364
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
365
|
+
const setValue = (callback) => {
|
|
366
|
+
const newValue = callback(filterBarActions.getValuesByKey(filter.filterKey));
|
|
367
|
+
if (filter.type === "string") {
|
|
368
|
+
filterBarActions.setStringValue(filter.filterKey, newValue);
|
|
369
|
+
}
|
|
370
|
+
else if (filter.type === "stringArray") {
|
|
371
|
+
filterBarActions.setArrayValue(filter.filterKey, newValue);
|
|
372
|
+
}
|
|
373
|
+
else if (filter.type === "dateRange") {
|
|
374
|
+
filterBarActions.setDateRange(filter.filterKey, newValue);
|
|
375
|
+
}
|
|
376
|
+
else if (filter.type === "area") {
|
|
377
|
+
filterBarActions.setArea(newValue);
|
|
378
|
+
}
|
|
379
|
+
else if (filter.type === "valueNameArray") {
|
|
380
|
+
filterBarActions.setArrayObjectValue(filter.filterKey, newValue);
|
|
381
|
+
}
|
|
382
|
+
else if (filter.type === "valueName") {
|
|
383
|
+
filterBarActions.setObjectValue(filter.filterKey, newValue);
|
|
384
|
+
}
|
|
385
|
+
else if (filter.type === "minMax") {
|
|
386
|
+
filterBarActions.setMinMaxValue(filter.filterKey, newValue);
|
|
387
|
+
}
|
|
388
|
+
else if (filter.type === "boolean") {
|
|
389
|
+
filterBarActions.setBooleanValue(filter.filterKey, newValue);
|
|
390
|
+
}
|
|
391
|
+
else {
|
|
392
|
+
filterBarActions.setNumberValue(filter.filterKey, newValue);
|
|
393
|
+
}
|
|
394
|
+
};
|
|
395
|
+
const text = getFilterText();
|
|
396
|
+
const activeFilterText = Array.isArray(text) ? text.join(", ") : text;
|
|
397
|
+
const showDirectly = filter.showDirectly || false;
|
|
398
|
+
return showDirectly ? (jsxRuntime.jsx(jsxRuntime.Fragment, { children: filter.component({
|
|
399
|
+
filterDefinition: filter,
|
|
400
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
401
|
+
value: values,
|
|
402
|
+
setValue,
|
|
403
|
+
filterBarActions,
|
|
404
|
+
filterState,
|
|
405
|
+
}) })) : (jsxRuntime.jsx(reactFilterComponents.Filter, { activeLabel: activeFilterText, activeOptionsCount: valuesLength, asIcon: asIcon, className: className, dataTestId: `${filter.filterKey}-filter-button`, isActive: filterBarActions.appliedFilterKeys().includes(filter.filterKey), popoverProps: { placement: visualStyle === "list-item" ? "right-start" : "bottom-start" }, readOnly: readOnly, size: size, title: filter.title, visualStyle: visualStyle, withStickyHeader: true, children: filter.component({
|
|
406
|
+
filterDefinition: filter,
|
|
407
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
408
|
+
value: values,
|
|
409
|
+
setValue,
|
|
410
|
+
filterBarActions,
|
|
411
|
+
filterState,
|
|
412
|
+
}) }));
|
|
413
|
+
};
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* FiltersRenderer renders an array of Filter components from filter definitions
|
|
417
|
+
* It ignores hidden filters.
|
|
418
|
+
*
|
|
419
|
+
* Note: This component does not provide any styling or layout - use a wrapper for proper list styling.
|
|
420
|
+
*
|
|
421
|
+
* @param {object} props - The component props
|
|
422
|
+
* @param {FilterDefinition[]} props.filters - Array of filter definitions to render
|
|
423
|
+
* @param {FilterBarConfig & FilterMapActions & FilterMapGetter} props.filterBarConfig - The filter bar configuration
|
|
424
|
+
* @param {ComponentProps<typeof FilterComponent>["visualStyle"]} [props.visualStyle] - The visual style of the filters
|
|
425
|
+
* @returns {ReactElement[] | null} - Returns an array of Filter components or null
|
|
426
|
+
*/
|
|
427
|
+
const FiltersRenderer = ({ filters, filterBarConfig, visualStyle, }) => {
|
|
428
|
+
return filters.length === 0
|
|
429
|
+
? null
|
|
430
|
+
: filters
|
|
431
|
+
.filter(filter => !filter.isHidden)
|
|
432
|
+
.map(filter => (jsxRuntime.jsx(FilterComponent, { filter: filter, filterBarActions: filterBarConfig, filterState: { values: filterBarConfig.values, setters: filterBarConfig.setters }, visualStyle: visualStyle }, `filter-${filter.filterKey}`)));
|
|
433
|
+
};
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* ResetFiltersButton is a React component that provides a button for resetting filters.
|
|
437
|
+
*
|
|
438
|
+
* @returns {ReactElement | null} The rendered ResetFiltersButton component, or null if no filters have been applied.
|
|
439
|
+
*/
|
|
440
|
+
const ResetFiltersButton = ({ resetFiltersToInitialState, dataTestId, className, }) => {
|
|
441
|
+
const [t] = useTranslation();
|
|
442
|
+
return (jsxRuntime.jsxs(reactComponents.Button, { className: className, dataTestId: dataTestId ?? "reset-filters-button", onClick: () => {
|
|
443
|
+
resetFiltersToInitialState();
|
|
444
|
+
}, size: "small", variant: "ghost", children: [t("filtersBar.resetFilters"), jsxRuntime.jsx("span", { className: "sr-only", children: "Resets all applied filters" })] }));
|
|
445
|
+
};
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
*
|
|
449
|
+
*/
|
|
450
|
+
const AppliedFiltersRenderer = ({ appliedFilters, filterBarConfig, }) => {
|
|
451
|
+
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [appliedFilters.filter(filter => !filter.showDirectly).length > 0 ? (jsxRuntime.jsx("div", { className: "h-4 w-[1px] bg-slate-300", "data-testid": "applied-filters-buttons" })) : null, jsxRuntime.jsx(FiltersRenderer, { filterBarConfig: filterBarConfig, filters: appliedFilters }), filterBarConfig.appliedFilterKeys().length > 0 ? (jsxRuntime.jsx(ResetFiltersButton, { resetFiltersToInitialState: filterBarConfig.resetFiltersToInitialState })) : null] }));
|
|
452
|
+
};
|
|
453
|
+
|
|
323
454
|
/**
|
|
324
455
|
* Events — each with a name, and eventType.
|
|
325
456
|
* Adding a Description is encouraged.
|
|
@@ -664,98 +795,6 @@ const FilterButtonTooltipLabel = ({ filterBarConfig, }) => {
|
|
|
664
795
|
}
|
|
665
796
|
};
|
|
666
797
|
|
|
667
|
-
/**
|
|
668
|
-
* Returns the two first values, appends counter if more.
|
|
669
|
-
*
|
|
670
|
-
* @param {string[]} [input] Array of values to reduce
|
|
671
|
-
* @returns {*} {string}
|
|
672
|
-
*/
|
|
673
|
-
const reduceFilterText = (input) => {
|
|
674
|
-
if (!Array.isArray(input)) {
|
|
675
|
-
return input;
|
|
676
|
-
}
|
|
677
|
-
// Only first two elements
|
|
678
|
-
const firstTwo = input.slice(0, 2);
|
|
679
|
-
const remainder = input.slice(2, input.length).length;
|
|
680
|
-
const firstTwoJoined = firstTwo.join(", ");
|
|
681
|
-
const remainderStr = remainder > 0 ? `, +${remainder}` : "";
|
|
682
|
-
return firstTwoJoined + remainderStr;
|
|
683
|
-
};
|
|
684
|
-
|
|
685
|
-
/**
|
|
686
|
-
* Filter is a React component that renders a filter element based on the provided filter definition and state.
|
|
687
|
-
*
|
|
688
|
-
* @returns {ReactElement} - Returns the Filter component.
|
|
689
|
-
*/
|
|
690
|
-
const FilterComponent = ({ filter, filterBarActions, filterState, readOnly = false, visualStyle = "button", className, asIcon, size, }) => {
|
|
691
|
-
const values = filterBarActions.getValuesByKey(filter.filterKey);
|
|
692
|
-
const valuesLength = values && Array.isArray(values) ? values.length : undefined;
|
|
693
|
-
const getFilterText = () => {
|
|
694
|
-
if (!values) {
|
|
695
|
-
return undefined;
|
|
696
|
-
}
|
|
697
|
-
if (filter.valueAsText) {
|
|
698
|
-
return reduceFilterText(filter.valueAsText(values));
|
|
699
|
-
}
|
|
700
|
-
else if (filter.type === "valueNameArray") {
|
|
701
|
-
return reduceFilterText(values.map(value => value.name));
|
|
702
|
-
}
|
|
703
|
-
else if (filter.type === "valueName") {
|
|
704
|
-
return values.name;
|
|
705
|
-
}
|
|
706
|
-
return values.toString();
|
|
707
|
-
};
|
|
708
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
709
|
-
const setValue = (callback) => {
|
|
710
|
-
const newValue = callback(filterBarActions.getValuesByKey(filter.filterKey));
|
|
711
|
-
if (filter.type === "string") {
|
|
712
|
-
filterBarActions.setStringValue(filter.filterKey, newValue);
|
|
713
|
-
}
|
|
714
|
-
else if (filter.type === "stringArray") {
|
|
715
|
-
filterBarActions.setArrayValue(filter.filterKey, newValue);
|
|
716
|
-
}
|
|
717
|
-
else if (filter.type === "dateRange") {
|
|
718
|
-
filterBarActions.setDateRange(filter.filterKey, newValue);
|
|
719
|
-
}
|
|
720
|
-
else if (filter.type === "area") {
|
|
721
|
-
filterBarActions.setArea(newValue);
|
|
722
|
-
}
|
|
723
|
-
else if (filter.type === "valueNameArray") {
|
|
724
|
-
filterBarActions.setArrayObjectValue(filter.filterKey, newValue);
|
|
725
|
-
}
|
|
726
|
-
else if (filter.type === "valueName") {
|
|
727
|
-
filterBarActions.setObjectValue(filter.filterKey, newValue);
|
|
728
|
-
}
|
|
729
|
-
else if (filter.type === "minMax") {
|
|
730
|
-
filterBarActions.setMinMaxValue(filter.filterKey, newValue);
|
|
731
|
-
}
|
|
732
|
-
else if (filter.type === "boolean") {
|
|
733
|
-
filterBarActions.setBooleanValue(filter.filterKey, newValue);
|
|
734
|
-
}
|
|
735
|
-
else {
|
|
736
|
-
filterBarActions.setNumberValue(filter.filterKey, newValue);
|
|
737
|
-
}
|
|
738
|
-
};
|
|
739
|
-
const text = getFilterText();
|
|
740
|
-
const activeFilterText = Array.isArray(text) ? text.join(", ") : text;
|
|
741
|
-
const showDirectly = filter.showDirectly || false;
|
|
742
|
-
return showDirectly ? (jsxRuntime.jsx(jsxRuntime.Fragment, { children: filter.component({
|
|
743
|
-
filterDefinition: filter,
|
|
744
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
745
|
-
value: values,
|
|
746
|
-
setValue,
|
|
747
|
-
filterBarActions,
|
|
748
|
-
filterState,
|
|
749
|
-
}) })) : (jsxRuntime.jsx(reactFilterComponents.Filter, { activeLabel: activeFilterText, activeOptionsCount: valuesLength, asIcon: asIcon, className: className, dataTestId: `${filter.filterKey}-filter-button`, isActive: filterBarActions.appliedFilterKeys().includes(filter.filterKey), popoverProps: { placement: visualStyle === "list-item" ? "right-start" : "bottom-start" }, readOnly: readOnly, size: size, title: filter.title, visualStyle: visualStyle, withStickyHeader: true, children: filter.component({
|
|
750
|
-
filterDefinition: filter,
|
|
751
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
752
|
-
value: values,
|
|
753
|
-
setValue,
|
|
754
|
-
filterBarActions,
|
|
755
|
-
filterState,
|
|
756
|
-
}) }));
|
|
757
|
-
};
|
|
758
|
-
|
|
759
798
|
/**
|
|
760
799
|
* Custom React hook for grouping and filtering a list of filters.
|
|
761
800
|
*
|
|
@@ -837,26 +876,6 @@ const useFiltersMenu = ({ filterBarDefinition, filterBarConfig, hiddenFilters =
|
|
|
837
876
|
]);
|
|
838
877
|
};
|
|
839
878
|
|
|
840
|
-
/**
|
|
841
|
-
* FiltersRenderer renders an array of Filter components from filter definitions
|
|
842
|
-
* It ignores hidden filters.
|
|
843
|
-
*
|
|
844
|
-
* Note: This component does not provide any styling or layout - use a wrapper for proper list styling.
|
|
845
|
-
*
|
|
846
|
-
* @param {object} props - The component props
|
|
847
|
-
* @param {FilterDefinition[]} props.filters - Array of filter definitions to render
|
|
848
|
-
* @param {FilterBarConfig & FilterMapActions & FilterMapGetter} props.filterBarConfig - The filter bar configuration
|
|
849
|
-
* @param {ComponentProps<typeof FilterComponent>["visualStyle"]} [props.visualStyle] - The visual style of the filters
|
|
850
|
-
* @returns {ReactElement[] | null} - Returns an array of Filter components or null
|
|
851
|
-
*/
|
|
852
|
-
const FiltersRenderer = ({ filters, filterBarConfig, visualStyle, }) => {
|
|
853
|
-
return filters.length === 0
|
|
854
|
-
? null
|
|
855
|
-
: filters
|
|
856
|
-
.filter(filter => !filter.isHidden)
|
|
857
|
-
.map(filter => (jsxRuntime.jsx(FilterComponent, { filter: filter, filterBarActions: filterBarConfig, filterState: { values: filterBarConfig.values, setters: filterBarConfig.setters }, visualStyle: visualStyle }, `filter-${filter.filterKey}`)));
|
|
858
|
-
};
|
|
859
|
-
|
|
860
879
|
/**
|
|
861
880
|
* FiltersList is a React component that displays a list of filters within a filter bar.
|
|
862
881
|
*
|
|
@@ -869,18 +888,6 @@ const GroupedFiltersList = ({ filterBarConfig, filtersGrouped, className, dataTe
|
|
|
869
888
|
}) }));
|
|
870
889
|
};
|
|
871
890
|
|
|
872
|
-
/**
|
|
873
|
-
* ResetFiltersButton is a React component that provides a button for resetting filters.
|
|
874
|
-
*
|
|
875
|
-
* @returns {ReactElement | null} The rendered ResetFiltersButton component, or null if no filters have been applied.
|
|
876
|
-
*/
|
|
877
|
-
const ResetFiltersButton = ({ resetFiltersToInitialState, dataTestId, className, }) => {
|
|
878
|
-
const [t] = useTranslation();
|
|
879
|
-
return (jsxRuntime.jsxs(reactComponents.Button, { className: className, dataTestId: dataTestId ?? "reset-filters-button", onClick: () => {
|
|
880
|
-
resetFiltersToInitialState();
|
|
881
|
-
}, size: "small", variant: "ghost", children: [t("filtersBar.resetFilters"), jsxRuntime.jsx("span", { className: "sr-only", children: "Resets all applied filters" })] }));
|
|
882
|
-
};
|
|
883
|
-
|
|
884
891
|
/**
|
|
885
892
|
*
|
|
886
893
|
*/
|
|
@@ -988,7 +995,7 @@ const MultipleFilterTooltipLabel = ({ filterBarConfig, filterKeys, filters, }) =
|
|
|
988
995
|
}, {});
|
|
989
996
|
switch (appliedFilterKeys.length) {
|
|
990
997
|
case 0:
|
|
991
|
-
return t("filtersBar.appliedFiltersTooltip.none");
|
|
998
|
+
return jsxRuntime.jsx("div", { className: "text-xs font-medium", children: t("filtersBar.appliedFiltersTooltip.none") });
|
|
992
999
|
case 1:
|
|
993
1000
|
return (jsxRuntime.jsx(SingleFilterTooltipLabel, { filter: filtersMap[appliedFilterKeys[0]], filterBarConfig: filterBarConfig, filterKey: appliedFilterKeys[0] }));
|
|
994
1001
|
default:
|
|
@@ -1020,7 +1027,7 @@ const FiltersMenu = ({ filterBarDefinition, filterBarConfig, hiddenFilters = [],
|
|
|
1020
1027
|
}
|
|
1021
1028
|
}, placement: "bottom-start", children: modalState => {
|
|
1022
1029
|
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(reactComponents.PopoverTrigger, { children: jsxRuntime.jsx("div", { "data-testid": "starred-filters-menu-trigger", id: "starred-filters-menu-trigger", children: jsxRuntime.jsx(reactComponents.Tooltip, { disabled: !compact || modalState.isOpen, label: jsxRuntime.jsx(MultipleFilterTooltipLabel, { filterBarConfig: filterBarConfig, filters: appliedFilters }), children: jsxRuntime.jsx(reactComponents.Button, { prefix: jsxRuntime.jsx(reactComponents.Icon, { ariaHidden: true, color: filterBarConfig.appliedFilterKeys().length > 0 ? "primary" : undefined, name: "Filter", size: "small" }), size: "small", suffix: compact && showAppliedFiltersCount && filterBarConfig.appliedFilterKeys().length > 0 && isSm ? (jsxRuntime.jsxs("div", { children: [jsxRuntime.jsxs("span", { "aria-hidden": true, children: ["(", filterBarConfig.appliedFilterKeys().length, ")"] }), jsxRuntime.jsxs("span", { className: "sr-only", children: [filterBarConfig.appliedFilterKeys().length, " filters applied"] })] })) : undefined, variant: "secondary", ...buttonProps, children: title !== "" ? (jsxRuntime.jsx("span", { className: "hidden sm:block", children: title ?? t("filtersBar.filtersHeading") })) : null }) }) }) }), jsxRuntime.jsx(reactComponents.PopoverContent, { cellPadding: 100, children: jsxRuntime.jsx(FiltersMenuContent, { appliedCustomFields: appliedCustomFields, filterBarConfig: filterBarConfig, filterBarDefinitionCount: filterBarDefinitionCount, filtersToShowGrouped: filtersToShowGrouped, hasCustomFields: hasCustomFields, removeCustomFieldsGroup: removeCustomFieldsGroup, searchResultsGrouped: searchResultsGrouped, searchText: searchText, setSearchText: setSearchText, setShowCustomFilters: setShowCustomFilters, showCustomFilters: showCustomFilters }) })] }));
|
|
1023
|
-
} }), showDirectlyFilters.length > 0 ? (jsxRuntime.jsx(FiltersRenderer, { filterBarConfig: filterBarConfig, filters: showDirectlyFilters })) : null, !compact ?
|
|
1030
|
+
} }), showDirectlyFilters.length > 0 ? (jsxRuntime.jsx(FiltersRenderer, { filterBarConfig: filterBarConfig, filters: showDirectlyFilters })) : null, !compact ? jsxRuntime.jsx(AppliedFiltersRenderer, { appliedFilters: appliedFilters, filterBarConfig: filterBarConfig }) : null] }));
|
|
1024
1031
|
};
|
|
1025
1032
|
|
|
1026
1033
|
/**
|
|
@@ -1280,7 +1287,7 @@ const HierarchicalCheckboxFilter = ({ filterDefinition, filterBarActions, option
|
|
|
1280
1287
|
/**
|
|
1281
1288
|
* The FilterBar component serves as a wrapper for managing filters.
|
|
1282
1289
|
*/
|
|
1283
|
-
const FilterBar = ({ hiddenFilters, className, filterBarDefinition, filterBarConfig, compact = true,
|
|
1290
|
+
const FilterBar = ({ hiddenFilters, className, filterBarDefinition, filterBarConfig, compact = true, allowShowFiltersDirectly = true, title, }) => {
|
|
1284
1291
|
return (jsxRuntime.jsx(FiltersMenu, { allowShowFiltersDirectly: allowShowFiltersDirectly, className: className, compact: compact, dataTestId: `${filterBarConfig.name}-filterbar`, filterBarConfig: filterBarConfig, filterBarDefinition: filterBarDefinition, hiddenFilters: hiddenFilters, title: title }));
|
|
1285
1292
|
};
|
|
1286
1293
|
|
|
@@ -1296,6 +1303,7 @@ const mockFilterBar = {
|
|
|
1296
1303
|
getFilterBarName: doNothing,
|
|
1297
1304
|
initialState: { customerType: [] },
|
|
1298
1305
|
name: "test",
|
|
1306
|
+
hasDefaultValue: doNothing,
|
|
1299
1307
|
objectArrayIncludesValue: doNothing,
|
|
1300
1308
|
resetFiltersToInitialState: doNothing,
|
|
1301
1309
|
resetIndividualFilterToInitialState: doNothing,
|
|
@@ -1399,6 +1407,131 @@ const createInitialState = ({ name, mainFilters, setValue, }) => {
|
|
|
1399
1407
|
};
|
|
1400
1408
|
};
|
|
1401
1409
|
|
|
1410
|
+
const areaFilterGeoJsonGeometrySchema = zod.z.union([geoJsonUtils.geoJsonPolygonSchema, geoJsonUtils.geoJsonMultiPolygonSchema]);
|
|
1411
|
+
|
|
1412
|
+
const hasValue = (value) => {
|
|
1413
|
+
if (value === undefined || value === null) {
|
|
1414
|
+
return false;
|
|
1415
|
+
}
|
|
1416
|
+
// eslint-disable-next-line no-autofix/local-rules/prefer-custom-object-keys
|
|
1417
|
+
if (typeof value === "object" && Object.keys(value).length === 0) {
|
|
1418
|
+
return false;
|
|
1419
|
+
}
|
|
1420
|
+
return !(Array.isArray(value) && value.length === 0);
|
|
1421
|
+
};
|
|
1422
|
+
const isNotRightType = (filterDefinition, foundFilter) => {
|
|
1423
|
+
return ((filterDefinition.type === "valueNameArray" && !isValueNameArray(foundFilter)) ||
|
|
1424
|
+
(filterDefinition.type === "valueName" && !isValueName(foundFilter)) ||
|
|
1425
|
+
(filterDefinition.type === "stringArray" && !isStringArrayFilterValue(foundFilter)) ||
|
|
1426
|
+
(filterDefinition.type === "dateRange" && !isDateRangeValue(foundFilter)) ||
|
|
1427
|
+
(filterDefinition.type === "area" && !isAreaFilterValue(foundFilter)) ||
|
|
1428
|
+
(filterDefinition.type === "minMax" && !isMinMaxFilterValue(foundFilter)) ||
|
|
1429
|
+
(filterDefinition.type === "boolean" && !isBooleanValue(foundFilter)) ||
|
|
1430
|
+
(filterDefinition.type === "string" && typeof foundFilter !== "string") ||
|
|
1431
|
+
(filterDefinition.type === "number" && typeof foundFilter !== "number"));
|
|
1432
|
+
};
|
|
1433
|
+
/**
|
|
1434
|
+
*
|
|
1435
|
+
*/
|
|
1436
|
+
const isMinMaxFilterValue = (value) => {
|
|
1437
|
+
return value
|
|
1438
|
+
? // eslint-disable-next-line no-autofix/local-rules/prefer-custom-object-keys
|
|
1439
|
+
typeof value === "object" && (Object.keys(value).includes("min") || Object.keys(value).includes("max"))
|
|
1440
|
+
: false;
|
|
1441
|
+
};
|
|
1442
|
+
/**
|
|
1443
|
+
*
|
|
1444
|
+
*/
|
|
1445
|
+
const isDateRangeValue = (value) => {
|
|
1446
|
+
return value
|
|
1447
|
+
? // eslint-disable-next-line no-autofix/local-rules/prefer-custom-object-keys
|
|
1448
|
+
typeof value === "object" && (Object.keys(value).includes("from") || Object.keys(value).includes("to"))
|
|
1449
|
+
: false;
|
|
1450
|
+
};
|
|
1451
|
+
/**
|
|
1452
|
+
* {
|
|
1453
|
+
type: "Polygon";
|
|
1454
|
+
coordinates: [number, number][][];
|
|
1455
|
+
}
|
|
1456
|
+
*/
|
|
1457
|
+
const isAreaFilterValue = (value) => {
|
|
1458
|
+
return areaFilterGeoJsonGeometrySchema.safeParse(value).success;
|
|
1459
|
+
};
|
|
1460
|
+
/**
|
|
1461
|
+
*
|
|
1462
|
+
*/
|
|
1463
|
+
const isArrayFilterValue = (value) => {
|
|
1464
|
+
return Array.isArray(value);
|
|
1465
|
+
};
|
|
1466
|
+
/**
|
|
1467
|
+
*
|
|
1468
|
+
*/
|
|
1469
|
+
const isStringArrayFilterValue = (value) => {
|
|
1470
|
+
return isArrayFilterValue(value) && value.every(item => typeof item === "string");
|
|
1471
|
+
};
|
|
1472
|
+
/**
|
|
1473
|
+
*
|
|
1474
|
+
*/
|
|
1475
|
+
const isBooleanValue = (value) => {
|
|
1476
|
+
// eslint-disable-next-line no-autofix/local-rules/prefer-custom-object-keys
|
|
1477
|
+
return value ? typeof value === "object" && Object.keys(value).includes("booleanValue") : false;
|
|
1478
|
+
};
|
|
1479
|
+
/**
|
|
1480
|
+
* Type guard to check if a value is a single ValueName object
|
|
1481
|
+
*/
|
|
1482
|
+
const isValueName = (value) => {
|
|
1483
|
+
return (typeof value === "object" &&
|
|
1484
|
+
value !== null &&
|
|
1485
|
+
// eslint-disable-next-line no-autofix/local-rules/prefer-custom-object-keys
|
|
1486
|
+
Object.keys(value).includes("name") &&
|
|
1487
|
+
// eslint-disable-next-line no-autofix/local-rules/prefer-custom-object-keys
|
|
1488
|
+
Object.keys(value).includes("value"));
|
|
1489
|
+
};
|
|
1490
|
+
/**
|
|
1491
|
+
* Type guard to check if a value is an array of ValueName objects
|
|
1492
|
+
*/
|
|
1493
|
+
const isValueNameArray = (value) => {
|
|
1494
|
+
return isArrayFilterValue(value) && value.every(isValueName);
|
|
1495
|
+
};
|
|
1496
|
+
/**
|
|
1497
|
+
* Validates a filter configuration against filter definitions.
|
|
1498
|
+
*
|
|
1499
|
+
* @template TFilterBarDefinition - The type of the filter bar definition.
|
|
1500
|
+
* @param {FilterBarConfig<TFilterBarDefinition>} filter - The filter configuration to validate.
|
|
1501
|
+
* @param {FilterDefinition[]} filterDefinitions - An array of filter definitions to validate against.
|
|
1502
|
+
* @returns {boolean} - Returns `true` if the filter configuration is valid, otherwise `false`.
|
|
1503
|
+
*/
|
|
1504
|
+
const validateFilter = ({ values, starredFilterKeys, filterDefinitions, }) => {
|
|
1505
|
+
const stateKeys = [];
|
|
1506
|
+
let inBadState = false;
|
|
1507
|
+
// eslint-disable-next-line no-autofix/local-rules/prefer-custom-object-keys
|
|
1508
|
+
for (const key of Object.keys(values)) {
|
|
1509
|
+
if (filterDefinitions.find(filterDefinition => filterDefinition.filterKey === key)) {
|
|
1510
|
+
stateKeys.push(key);
|
|
1511
|
+
}
|
|
1512
|
+
else {
|
|
1513
|
+
inBadState = true;
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
filterDefinitions.forEach(filterDefinition => {
|
|
1517
|
+
const foundFilter = values[filterDefinition.filterKey];
|
|
1518
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
1519
|
+
if (foundFilter && hasValue(foundFilter) && isNotRightType(filterDefinition, foundFilter)) {
|
|
1520
|
+
inBadState = true;
|
|
1521
|
+
}
|
|
1522
|
+
});
|
|
1523
|
+
if (starredFilterKeys.length > 0) {
|
|
1524
|
+
const allKeys = filterDefinitions.map(f => f.filterKey);
|
|
1525
|
+
const filteredStarredFilterKeys = starredFilterKeys.filter(key => allKeys.includes(key));
|
|
1526
|
+
if (filteredStarredFilterKeys.length !== starredFilterKeys.length) {
|
|
1527
|
+
inBadState = true;
|
|
1528
|
+
}
|
|
1529
|
+
}
|
|
1530
|
+
stateKeys.sort((a, b) => a.localeCompare(b));
|
|
1531
|
+
const filterKeysNotEqual = !isEqual(stateKeys, filterDefinitions.map(f => f.filterKey).sort((a, b) => a.localeCompare(b)));
|
|
1532
|
+
return !(inBadState || filterKeysNotEqual);
|
|
1533
|
+
};
|
|
1534
|
+
|
|
1402
1535
|
/**
|
|
1403
1536
|
* Custom hook for managing a filter bar's actions .
|
|
1404
1537
|
*
|
|
@@ -1419,6 +1552,33 @@ const useFilterBarActions = ({ name, filterBarConfig, filterBarDefinition, setFi
|
|
|
1419
1552
|
const filter = filterBarConfig.values[key];
|
|
1420
1553
|
return filter?.includes(value) || false;
|
|
1421
1554
|
},
|
|
1555
|
+
hasDefaultValue(key) {
|
|
1556
|
+
// eslint-disable-next-line local-rules/no-typescript-assertion
|
|
1557
|
+
const filterValue = filterBarConfig.values[key];
|
|
1558
|
+
const filterDefinition = filterBarDefinition[key];
|
|
1559
|
+
if (dequal.dequal(filterValue, filterBarDefinition[key]?.defaultValue) || dequal.dequal(filterValue, initialState?.[key])) {
|
|
1560
|
+
return true;
|
|
1561
|
+
}
|
|
1562
|
+
if (filterDefinition && filterDefinition.defaultValue === undefined) {
|
|
1563
|
+
return false;
|
|
1564
|
+
}
|
|
1565
|
+
if (!filterValue) {
|
|
1566
|
+
return true;
|
|
1567
|
+
}
|
|
1568
|
+
if (Array.isArray(filterValue)) {
|
|
1569
|
+
return filterValue.length === 0;
|
|
1570
|
+
}
|
|
1571
|
+
if (isMinMaxFilterValue(filterValue)) {
|
|
1572
|
+
return filterValue.min === undefined && filterValue.max === undefined;
|
|
1573
|
+
}
|
|
1574
|
+
if (isValueName(filterValue)) {
|
|
1575
|
+
return filterValue.value === "";
|
|
1576
|
+
}
|
|
1577
|
+
if (typeof filterValue === "object") {
|
|
1578
|
+
return sharedUtils.objectKeys(filterValue).length === 0;
|
|
1579
|
+
}
|
|
1580
|
+
return false;
|
|
1581
|
+
},
|
|
1422
1582
|
getValuesByKey(key) {
|
|
1423
1583
|
return filterBarConfig.values[key];
|
|
1424
1584
|
},
|
|
@@ -1683,131 +1843,6 @@ const useFilterBarActions = ({ name, filterBarConfig, filterBarDefinition, setFi
|
|
|
1683
1843
|
return react.useMemo(() => ({ filterMapGetter, filterMapActions }), [filterMapGetter, filterMapActions]);
|
|
1684
1844
|
};
|
|
1685
1845
|
|
|
1686
|
-
const areaFilterGeoJsonGeometrySchema = zod.z.union([geoJsonUtils.geoJsonPolygonSchema, geoJsonUtils.geoJsonMultiPolygonSchema]);
|
|
1687
|
-
|
|
1688
|
-
const hasValue = (value) => {
|
|
1689
|
-
if (value === undefined || value === null) {
|
|
1690
|
-
return false;
|
|
1691
|
-
}
|
|
1692
|
-
// eslint-disable-next-line no-autofix/local-rules/prefer-custom-object-keys
|
|
1693
|
-
if (typeof value === "object" && Object.keys(value).length === 0) {
|
|
1694
|
-
return false;
|
|
1695
|
-
}
|
|
1696
|
-
return !(Array.isArray(value) && value.length === 0);
|
|
1697
|
-
};
|
|
1698
|
-
const isNotRightType = (filterDefinition, foundFilter) => {
|
|
1699
|
-
return ((filterDefinition.type === "valueNameArray" && !isValueNameArray(foundFilter)) ||
|
|
1700
|
-
(filterDefinition.type === "valueName" && !isValueName(foundFilter)) ||
|
|
1701
|
-
(filterDefinition.type === "stringArray" && !isStringArrayFilterValue(foundFilter)) ||
|
|
1702
|
-
(filterDefinition.type === "dateRange" && !isDateRangeValue(foundFilter)) ||
|
|
1703
|
-
(filterDefinition.type === "area" && !isAreaFilterValue(foundFilter)) ||
|
|
1704
|
-
(filterDefinition.type === "minMax" && !isMinMaxFilterValue(foundFilter)) ||
|
|
1705
|
-
(filterDefinition.type === "boolean" && !isBooleanValue(foundFilter)) ||
|
|
1706
|
-
(filterDefinition.type === "string" && typeof foundFilter !== "string") ||
|
|
1707
|
-
(filterDefinition.type === "number" && typeof foundFilter !== "number"));
|
|
1708
|
-
};
|
|
1709
|
-
/**
|
|
1710
|
-
*
|
|
1711
|
-
*/
|
|
1712
|
-
const isMinMaxFilterValue = (value) => {
|
|
1713
|
-
return value
|
|
1714
|
-
? // eslint-disable-next-line no-autofix/local-rules/prefer-custom-object-keys
|
|
1715
|
-
typeof value === "object" && (Object.keys(value).includes("min") || Object.keys(value).includes("max"))
|
|
1716
|
-
: false;
|
|
1717
|
-
};
|
|
1718
|
-
/**
|
|
1719
|
-
*
|
|
1720
|
-
*/
|
|
1721
|
-
const isDateRangeValue = (value) => {
|
|
1722
|
-
return value
|
|
1723
|
-
? // eslint-disable-next-line no-autofix/local-rules/prefer-custom-object-keys
|
|
1724
|
-
typeof value === "object" && (Object.keys(value).includes("from") || Object.keys(value).includes("to"))
|
|
1725
|
-
: false;
|
|
1726
|
-
};
|
|
1727
|
-
/**
|
|
1728
|
-
* {
|
|
1729
|
-
type: "Polygon";
|
|
1730
|
-
coordinates: [number, number][][];
|
|
1731
|
-
}
|
|
1732
|
-
*/
|
|
1733
|
-
const isAreaFilterValue = (value) => {
|
|
1734
|
-
return areaFilterGeoJsonGeometrySchema.safeParse(value).success;
|
|
1735
|
-
};
|
|
1736
|
-
/**
|
|
1737
|
-
*
|
|
1738
|
-
*/
|
|
1739
|
-
const isArrayFilterValue = (value) => {
|
|
1740
|
-
return Array.isArray(value);
|
|
1741
|
-
};
|
|
1742
|
-
/**
|
|
1743
|
-
*
|
|
1744
|
-
*/
|
|
1745
|
-
const isStringArrayFilterValue = (value) => {
|
|
1746
|
-
return isArrayFilterValue(value) && value.every(item => typeof item === "string");
|
|
1747
|
-
};
|
|
1748
|
-
/**
|
|
1749
|
-
*
|
|
1750
|
-
*/
|
|
1751
|
-
const isBooleanValue = (value) => {
|
|
1752
|
-
// eslint-disable-next-line no-autofix/local-rules/prefer-custom-object-keys
|
|
1753
|
-
return value ? typeof value === "object" && Object.keys(value).includes("booleanValue") : false;
|
|
1754
|
-
};
|
|
1755
|
-
/**
|
|
1756
|
-
* Type guard to check if a value is a single ValueName object
|
|
1757
|
-
*/
|
|
1758
|
-
const isValueName = (value) => {
|
|
1759
|
-
return (typeof value === "object" &&
|
|
1760
|
-
value !== null &&
|
|
1761
|
-
// eslint-disable-next-line no-autofix/local-rules/prefer-custom-object-keys
|
|
1762
|
-
Object.keys(value).includes("name") &&
|
|
1763
|
-
// eslint-disable-next-line no-autofix/local-rules/prefer-custom-object-keys
|
|
1764
|
-
Object.keys(value).includes("value"));
|
|
1765
|
-
};
|
|
1766
|
-
/**
|
|
1767
|
-
* Type guard to check if a value is an array of ValueName objects
|
|
1768
|
-
*/
|
|
1769
|
-
const isValueNameArray = (value) => {
|
|
1770
|
-
return isArrayFilterValue(value) && value.every(isValueName);
|
|
1771
|
-
};
|
|
1772
|
-
/**
|
|
1773
|
-
* Validates a filter configuration against filter definitions.
|
|
1774
|
-
*
|
|
1775
|
-
* @template TFilterBarDefinition - The type of the filter bar definition.
|
|
1776
|
-
* @param {FilterBarConfig<TFilterBarDefinition>} filter - The filter configuration to validate.
|
|
1777
|
-
* @param {FilterDefinition[]} filterDefinitions - An array of filter definitions to validate against.
|
|
1778
|
-
* @returns {boolean} - Returns `true` if the filter configuration is valid, otherwise `false`.
|
|
1779
|
-
*/
|
|
1780
|
-
const validateFilter = ({ values, starredFilterKeys, filterDefinitions, }) => {
|
|
1781
|
-
const stateKeys = [];
|
|
1782
|
-
let inBadState = false;
|
|
1783
|
-
// eslint-disable-next-line no-autofix/local-rules/prefer-custom-object-keys
|
|
1784
|
-
for (const key of Object.keys(values)) {
|
|
1785
|
-
if (filterDefinitions.find(filterDefinition => filterDefinition.filterKey === key)) {
|
|
1786
|
-
stateKeys.push(key);
|
|
1787
|
-
}
|
|
1788
|
-
else {
|
|
1789
|
-
inBadState = true;
|
|
1790
|
-
}
|
|
1791
|
-
}
|
|
1792
|
-
filterDefinitions.forEach(filterDefinition => {
|
|
1793
|
-
const foundFilter = values[filterDefinition.filterKey];
|
|
1794
|
-
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
1795
|
-
if (foundFilter && hasValue(foundFilter) && isNotRightType(filterDefinition, foundFilter)) {
|
|
1796
|
-
inBadState = true;
|
|
1797
|
-
}
|
|
1798
|
-
});
|
|
1799
|
-
if (starredFilterKeys.length > 0) {
|
|
1800
|
-
const allKeys = filterDefinitions.map(f => f.filterKey);
|
|
1801
|
-
const filteredStarredFilterKeys = starredFilterKeys.filter(key => allKeys.includes(key));
|
|
1802
|
-
if (filteredStarredFilterKeys.length !== starredFilterKeys.length) {
|
|
1803
|
-
inBadState = true;
|
|
1804
|
-
}
|
|
1805
|
-
}
|
|
1806
|
-
stateKeys.sort((a, b) => a.localeCompare(b));
|
|
1807
|
-
const filterKeysNotEqual = !isEqual(stateKeys, filterDefinitions.map(f => f.filterKey).sort((a, b) => a.localeCompare(b)));
|
|
1808
|
-
return !(inBadState || filterKeysNotEqual);
|
|
1809
|
-
};
|
|
1810
|
-
|
|
1811
1846
|
const getPersistenceKey = (name, clientSideUserId) => `filter-${name}-${clientSideUserId}`;
|
|
1812
1847
|
/**
|
|
1813
1848
|
* Custom hook for managing the persistence of filter bar configurations.
|
|
@@ -2097,6 +2132,7 @@ const mergeFilters = (filterBarDefinition, extraFilters) => {
|
|
|
2097
2132
|
*/
|
|
2098
2133
|
setupLibraryTranslations();
|
|
2099
2134
|
|
|
2135
|
+
exports.AppliedFiltersRenderer = AppliedFiltersRenderer;
|
|
2100
2136
|
exports.DefaultCheckboxFilter = DefaultCheckboxFilter;
|
|
2101
2137
|
exports.DefaultDateRangeFilter = DefaultDateRangeFilter;
|
|
2102
2138
|
exports.DefaultMinMaxFilter = DefaultMinMaxFilter;
|
|
@@ -2114,6 +2150,7 @@ exports.FiltersMenuContent = FiltersMenuContent;
|
|
|
2114
2150
|
exports.FiltersRenderer = FiltersRenderer;
|
|
2115
2151
|
exports.GroupedFiltersList = GroupedFiltersList;
|
|
2116
2152
|
exports.HierarchicalCheckboxFilter = HierarchicalCheckboxFilter;
|
|
2153
|
+
exports.MultipleFilterTooltipLabel = MultipleFilterTooltipLabel;
|
|
2117
2154
|
exports.ResetFiltersButton = ResetFiltersButton;
|
|
2118
2155
|
exports.areaFilterGeoJsonGeometrySchema = areaFilterGeoJsonGeometrySchema;
|
|
2119
2156
|
exports.isAreaFilterValue = isAreaFilterValue;
|