@devtron-labs/devtron-fe-common-lib 0.0.62-beta-4 → 0.0.62-beta-5

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.
Files changed (29) hide show
  1. package/dist/Common/DraggableWrapper/types.d.ts +4 -1
  2. package/dist/Common/Hooks/useUrlFilters/index.d.ts +1 -1
  3. package/dist/Common/Hooks/useUrlFilters/types.d.ts +54 -1
  4. package/dist/Common/Hooks/useUrlFilters/useUrlFilters.d.ts +2 -14
  5. package/dist/Pages/GlobalConfigurations/Authorization/constants.d.ts +5 -1
  6. package/dist/Pages/GlobalConfigurations/Authorization/index.d.ts +1 -0
  7. package/dist/Pages/GlobalConfigurations/Authorization/types.d.ts +23 -0
  8. package/dist/Shared/Components/BulkSelection/types.d.ts +2 -0
  9. package/dist/Shared/Components/FilterChips/FilterChips.component.d.ts +7 -0
  10. package/dist/Shared/Components/FilterChips/index.d.ts +2 -0
  11. package/dist/Shared/Components/FilterChips/types.d.ts +37 -0
  12. package/dist/Shared/Components/index.d.ts +1 -0
  13. package/dist/index.js +90 -26
  14. package/package.json +1 -1
  15. package/src/Common/DraggableWrapper/types.ts +4 -1
  16. package/src/Common/Helper.tsx +7 -1
  17. package/src/Common/Hooks/useUrlFilters/index.ts +1 -1
  18. package/src/Common/Hooks/useUrlFilters/types.ts +56 -1
  19. package/src/Common/Hooks/useUrlFilters/useUrlFilters.ts +28 -6
  20. package/src/Pages/GlobalConfigurations/Authorization/constants.ts +6 -1
  21. package/src/Pages/GlobalConfigurations/Authorization/index.ts +1 -0
  22. package/src/Pages/GlobalConfigurations/Authorization/types.ts +25 -0
  23. package/src/Shared/Components/BulkSelection/BulkSelection.tsx +2 -2
  24. package/src/Shared/Components/BulkSelection/BulkSelectionProvider.tsx +16 -5
  25. package/src/Shared/Components/BulkSelection/types.tsx +2 -0
  26. package/src/Shared/Components/FilterChips/FilterChips.component.tsx +100 -0
  27. package/src/Shared/Components/FilterChips/index.ts +2 -0
  28. package/src/Shared/Components/FilterChips/types.ts +39 -0
  29. package/src/Shared/Components/index.ts +1 -0
@@ -5,7 +5,10 @@ export declare enum DraggablePositionVariant {
5
5
  }
6
6
  export interface DraggableWrapperProps {
7
7
  children: ReactNode;
8
- zIndex?: number;
8
+ /**
9
+ * Support for passing the direct value or calc functions as well
10
+ */
11
+ zIndex?: number | string;
9
12
  positionVariant?: DraggablePositionVariant;
10
13
  /**
11
14
  * dragSelector (class - (append with .), id, etc) will be used to identify the grabbable button that will grab the div to drag
@@ -1,2 +1,2 @@
1
1
  export { default as useUrlFilters } from './useUrlFilters';
2
- export type { UseUrlFiltersProps } from './types';
2
+ export type { UseUrlFiltersProps, UseUrlFiltersReturnType } from './types';
@@ -1,6 +1,59 @@
1
- export interface UseUrlFiltersProps<T> {
1
+ import { SortingOrder } from '../../Constants';
2
+ export interface UseUrlFiltersProps<T, K> {
2
3
  /**
3
4
  * The key on which the sorting should be applied
4
5
  */
5
6
  initialSortKey?: T;
7
+ /**
8
+ * Callback function for parsing the search params
9
+ */
10
+ parseSearchParams?: (searchParams: URLSearchParams) => K;
6
11
  }
12
+ export type UseUrlFiltersReturnType<T, K = unknown> = K & {
13
+ /**
14
+ * Currently applied page size
15
+ */
16
+ pageSize: number;
17
+ /**
18
+ * Handler for updating the current page
19
+ */
20
+ changePage: (pageNumber: number) => void;
21
+ /**
22
+ * Handler for updating the current page size
23
+ */
24
+ changePageSize: (pageSize: number) => void;
25
+ /**
26
+ * Current search key
27
+ */
28
+ searchKey: string;
29
+ /**
30
+ * Handler for updating the search
31
+ */
32
+ handleSearch: (searchKey: string) => void;
33
+ /**
34
+ * Computed offset using the pageSize and pageNumber
35
+ *
36
+ * Note: Used in pagination component
37
+ */
38
+ offset: number;
39
+ /**
40
+ * Key on which the sorting is applied
41
+ */
42
+ sortBy: T;
43
+ /**
44
+ * Current sort order
45
+ */
46
+ sortOrder: SortingOrder;
47
+ /**
48
+ * Handle the sorting type change / key change
49
+ */
50
+ handleSorting: (sortBy: T) => void;
51
+ /**
52
+ * Clear all the applied filters
53
+ */
54
+ clearFilters: () => void;
55
+ /**
56
+ * Update the search params with the passed object
57
+ */
58
+ updateSearchParams: (paramsToSerialize: K) => void;
59
+ };
@@ -1,5 +1,4 @@
1
- import { SortingOrder } from '../../Constants';
2
- import { UseUrlFiltersProps } from './types';
1
+ import { UseUrlFiltersProps, UseUrlFiltersReturnType } from './types';
3
2
  /**
4
3
  * Generic hook for implementing URL based filters.
5
4
  * eg: pagination, search, sort.
@@ -17,16 +16,5 @@ import { UseUrlFiltersProps } from './types';
17
16
  * ```
18
17
  *
19
18
  */
20
- declare const useUrlFilters: <T = string>({ initialSortKey }?: UseUrlFiltersProps<T>) => {
21
- pageSize: number;
22
- changePage: (page: number) => void;
23
- changePageSize: (_pageSize: number) => void;
24
- searchKey: string;
25
- handleSearch: (searchTerm: string) => void;
26
- offset: number;
27
- sortBy: T;
28
- sortOrder: SortingOrder;
29
- handleSorting: (_sortBy: T) => void;
30
- clearFilters: () => void;
31
- };
19
+ declare const useUrlFilters: <T = string, K = unknown>({ initialSortKey, parseSearchParams, }?: UseUrlFiltersProps<T, K>) => UseUrlFiltersReturnType<T, K>;
32
20
  export default useUrlFilters;
@@ -1,3 +1,7 @@
1
+ export declare enum UserListSortableKeys {
2
+ email = "email_id",
3
+ lastLogin = "last_login"
4
+ }
1
5
  /**
2
6
  * User Status received from the API
3
7
  */
@@ -11,5 +15,5 @@ export declare enum UserStatusDto {
11
15
  export declare enum UserStatus {
12
16
  active = "active",
13
17
  inactive = "inactive",
14
- temporary = "temporary"
18
+ temporary = "temporaryAccess"
15
19
  }
@@ -1 +1,2 @@
1
1
  export * from './constants';
2
+ export * from './types';
@@ -0,0 +1,23 @@
1
+ import { SortingParams } from '../../../Common';
2
+ import { UserListSortableKeys, UserStatus } from './constants';
3
+ export type BaseFilterQueryParams<T> = {
4
+ /**
5
+ * Offset for the list result
6
+ */
7
+ offset?: number;
8
+ /**
9
+ * Number of items required in the list
10
+ */
11
+ size?: number;
12
+ /**
13
+ * Search string (if any)
14
+ */
15
+ searchKey?: string;
16
+ /**
17
+ * If true, all items are returned with any search / filtering applied without pagination
18
+ */
19
+ showAll?: boolean;
20
+ } & SortingParams<T>;
21
+ export type UserListFilterParams = BaseFilterQueryParams<UserListSortableKeys> & {
22
+ status: UserStatus[];
23
+ };
@@ -23,6 +23,8 @@ export interface GetBulkSelectionCheckboxValuesType {
23
23
  export interface UseBulkSelectionReturnType<T> extends GetBulkSelectionCheckboxValuesType {
24
24
  selectedIdentifiers: T;
25
25
  handleBulkSelection: ({ action, data }: HandleBulkSelectionType<T>) => void;
26
+ isBulkSelectionApplied: boolean;
27
+ getSelectedIdentifiersCount: () => number;
26
28
  }
27
29
  export interface BulkSelectionProps {
28
30
  showPagination: boolean;
@@ -0,0 +1,7 @@
1
+ /// <reference types="react" />
2
+ import { FilterChipsProps } from './types';
3
+ /**
4
+ * Component for rendering the applied filter chips
5
+ */
6
+ declare const FilterChips: ({ filterConfig, clearFilters, onRemoveFilter, getFormattedLabel, getFormattedValue, }: FilterChipsProps) => JSX.Element;
7
+ export default FilterChips;
@@ -0,0 +1,2 @@
1
+ export { default as FilterChips } from './FilterChips.component';
2
+ export type { FilterChipsProps } from './types';
@@ -0,0 +1,37 @@
1
+ import { ReactNode } from 'react';
2
+ export interface FilterChipProps {
3
+ /**
4
+ * Filter label
5
+ */
6
+ label: string;
7
+ /**
8
+ * Corresponding value of the filter
9
+ */
10
+ value: unknown;
11
+ /**
12
+ * Callback handler for removing the filter
13
+ */
14
+ handleRemoveFilter: (label: string, valueToRemove: unknown) => void;
15
+ /**
16
+ * If passed, the label will be formatted accordingly
17
+ */
18
+ getFormattedLabel?: (filterKey: string) => ReactNode;
19
+ /**
20
+ * If passed, the label will be formatted accordingly
21
+ */
22
+ getFormattedValue?: (filterKey: string, filterValue: unknown) => ReactNode;
23
+ }
24
+ export interface FilterChipsProps extends Pick<FilterChipProps, 'getFormattedLabel' | 'getFormattedValue'> {
25
+ /**
26
+ * Current filter configuration
27
+ */
28
+ filterConfig: Record<string, unknown>;
29
+ /**
30
+ * Callback handler for removing the filters
31
+ */
32
+ clearFilters: () => void;
33
+ /**
34
+ * Handler for removing a applied filter
35
+ */
36
+ onRemoveFilter: (filterConfig: Record<string, unknown>) => void;
37
+ }
@@ -1,3 +1,4 @@
1
1
  export * from './APIResponseHandler';
2
2
  export * from './ReactSelect';
3
3
  export * from './BulkSelection';
4
+ export * from './FilterChips';
package/dist/index.js CHANGED
@@ -11811,7 +11811,14 @@ var getUrlWithSearchParams = function (url, params) {
11811
11811
  var searchParams = new URLSearchParams();
11812
11812
  Object.keys(params).forEach(function (key) {
11813
11813
  if (params[key]) {
11814
- searchParams.append(key, params[key]);
11814
+ if (Array.isArray(params[key])) {
11815
+ params[key].forEach(function (val) {
11816
+ searchParams.append(key, val);
11817
+ });
11818
+ }
11819
+ else {
11820
+ searchParams.set(key, params[key]);
11821
+ }
11815
11822
  }
11816
11823
  });
11817
11824
  var queryString = searchParams.toString();
@@ -25686,7 +25693,7 @@ var PAGE_SIZE = URL_FILTER_KEYS.PAGE_SIZE, PAGE_NUMBER = URL_FILTER_KEYS.PAGE_NU
25686
25693
  *
25687
25694
  */
25688
25695
  var useUrlFilters = function (_a) {
25689
- var _b = _a === void 0 ? {} : _a, initialSortKey = _b.initialSortKey;
25696
+ var _b = _a === void 0 ? {} : _a, initialSortKey = _b.initialSortKey, parseSearchParams = _b.parseSearchParams;
25690
25697
  var location = reactRouterDom.useLocation();
25691
25698
  var history = reactRouterDom.useHistory();
25692
25699
  var searchParams = new URLSearchParams(location.search);
@@ -25699,6 +25706,7 @@ var useUrlFilters = function (_a) {
25699
25706
  var sortByKey = (_sortBy || initialSortKey || '');
25700
25707
  // Fallback to ascending order
25701
25708
  var sortByOrder = Object.values(exports.SortingOrder).includes(_sortOrder) ? _sortOrder : exports.SortingOrder.ASC;
25709
+ var _parsedParams = parseSearchParams ? parseSearchParams(searchParams) : {};
25702
25710
  return {
25703
25711
  pageSize: Number(_pageSize) || DEFAULT_BASE_PAGE_SIZE,
25704
25712
  pageNumber: Number(_pageNumber) || DEFAULT_PAGE_NUMBER,
@@ -25706,8 +25714,9 @@ var useUrlFilters = function (_a) {
25706
25714
  sortBy: sortByKey,
25707
25715
  // sort order should only be applied if the key is available
25708
25716
  sortOrder: (sortByKey ? sortByOrder : ''),
25717
+ parsedParams: _parsedParams,
25709
25718
  };
25710
- }, [searchParams]), pageSize = _c.pageSize, pageNumber = _c.pageNumber, searchKey = _c.searchKey, sortBy = _c.sortBy, sortOrder = _c.sortOrder;
25719
+ }, [searchParams]), pageSize = _c.pageSize, pageNumber = _c.pageNumber, searchKey = _c.searchKey, sortBy = _c.sortBy, sortOrder = _c.sortOrder, parsedParams = _c.parsedParams;
25711
25720
  /**
25712
25721
  * Used for getting the required result from the API
25713
25722
  */
@@ -25749,23 +25758,26 @@ var useUrlFilters = function (_a) {
25749
25758
  _resetPageNumber();
25750
25759
  };
25751
25760
  var clearFilters = function () {
25752
- Object.values(URL_FILTER_KEYS).forEach(function (key) {
25753
- searchParams.delete(key);
25754
- });
25755
- history.replace({ search: searchParams.toString() });
25761
+ history.replace({ search: '' });
25756
25762
  };
25757
- return {
25758
- pageSize: pageSize,
25759
- changePage: changePage,
25760
- changePageSize: changePageSize,
25761
- searchKey: searchKey,
25762
- handleSearch: handleSearch,
25763
- offset: offset,
25764
- sortBy: sortBy,
25765
- sortOrder: sortOrder,
25766
- handleSorting: handleSorting,
25767
- clearFilters: clearFilters,
25763
+ var updateSearchParams = function (paramsToSerialize) {
25764
+ Object.keys(paramsToSerialize).forEach(function (key) {
25765
+ if (paramsToSerialize[key]) {
25766
+ if (Array.isArray(paramsToSerialize[key])) {
25767
+ searchParams.delete(key);
25768
+ paramsToSerialize[key].forEach(function (val) {
25769
+ searchParams.append(key, val);
25770
+ });
25771
+ }
25772
+ else {
25773
+ searchParams.set(key, paramsToSerialize[key]);
25774
+ }
25775
+ }
25776
+ });
25777
+ // Not replacing the params as it is being done by _resetPageNumber
25778
+ _resetPageNumber();
25768
25779
  };
25780
+ return __assign(__assign({ pageSize: pageSize, changePage: changePage, changePageSize: changePageSize, searchKey: searchKey, handleSearch: handleSearch, offset: offset, sortBy: sortBy, sortOrder: sortOrder, handleSorting: handleSorting, clearFilters: clearFilters }, parsedParams), { updateSearchParams: updateSearchParams });
25769
25781
  };
25770
25782
 
25771
25783
  var StatusConstants = {
@@ -29462,6 +29474,8 @@ var BulkSelectionContext = React.createContext({
29462
29474
  handleBulkSelection: noop$1,
29463
29475
  isChecked: false,
29464
29476
  checkboxValue: exports.CHECKBOX_VALUE.CHECKED,
29477
+ isBulkSelectionApplied: false,
29478
+ getSelectedIdentifiersCount: noop$1,
29465
29479
  });
29466
29480
  var useBulkSelection = function () {
29467
29481
  var context = React.useContext(BulkSelectionContext);
@@ -29473,6 +29487,8 @@ var useBulkSelection = function () {
29473
29487
  var BulkSelectionProvider = function (_a) {
29474
29488
  var children = _a.children, identifiers = _a.identifiers, getSelectAllDialogStatus = _a.getSelectAllDialogStatus;
29475
29489
  var _b = __read(React.useState({}), 2), selectedIdentifiers = _b[0], setSelectedIdentifiers = _b[1];
29490
+ var isBulkSelectionApplied = selectedIdentifiers[SELECT_ALL_ACROSS_PAGES_LOCATOR];
29491
+ var getSelectedIdentifiersCount = function () { return Object.keys(selectedIdentifiers).length; };
29476
29492
  var setIdentifiersAfterClear = function (newIdentifiers, selectedIds) {
29477
29493
  var _newIdentifiers = JSON.parse(JSON.stringify(newIdentifiers));
29478
29494
  selectedIds.forEach(function (id) {
@@ -29483,7 +29499,7 @@ var BulkSelectionProvider = function (_a) {
29483
29499
  var setIdentifiersAfterPageSelection = function (baseObject) {
29484
29500
  var _selectedIdentifiers = JSON.parse(JSON.stringify(selectedIdentifiers));
29485
29501
  // removing bulk selection across pages if present
29486
- if (_selectedIdentifiers[SELECT_ALL_ACROSS_PAGES_LOCATOR]) {
29502
+ if (isBulkSelectionApplied) {
29487
29503
  delete _selectedIdentifiers[SELECT_ALL_ACROSS_PAGES_LOCATOR];
29488
29504
  }
29489
29505
  setSelectedIdentifiers(__assign(__assign({}, _selectedIdentifiers), baseObject));
@@ -29508,10 +29524,13 @@ var BulkSelectionProvider = function (_a) {
29508
29524
  break;
29509
29525
  }
29510
29526
  case exports.BulkSelectionEvents.SELECT_ALL_ACROSS_PAGES: {
29511
- if (selectedIdentifiers[SELECT_ALL_ACROSS_PAGES_LOCATOR]) {
29527
+ if (isBulkSelectionApplied) {
29512
29528
  return;
29513
29529
  }
29514
- var selectedIdentifiersLength = Object.keys(selectedIdentifiers).length;
29530
+ var selectedIdentifiersLength = getSelectedIdentifiersCount();
29531
+ // This is for showing a modal dialog if applicable to confirm if bulk selection is to be applied
29532
+ // Do note that the 'getSelectAllDialogStatus' should be called after the length check explicitly
29533
+ // otherwise the modal will open each time
29515
29534
  if (selectedIdentifiersLength > 0 && getSelectAllDialogStatus() === exports.SelectAllDialogStatus.OPEN) {
29516
29535
  return;
29517
29536
  }
@@ -29549,7 +29568,7 @@ var BulkSelectionProvider = function (_a) {
29549
29568
  };
29550
29569
  }
29551
29570
  // if selectedIdentifiers contains select all across pages locator then it means all are selected
29552
- if (selectedIdentifiers[SELECT_ALL_ACROSS_PAGES_LOCATOR]) {
29571
+ if (isBulkSelectionApplied) {
29553
29572
  return {
29554
29573
  isChecked: true,
29555
29574
  checkboxValue: exports.CHECKBOX_VALUE.BULK_CHECKED,
@@ -29574,7 +29593,9 @@ var BulkSelectionProvider = function (_a) {
29574
29593
  handleBulkSelection: handleBulkSelection,
29575
29594
  isChecked: isChecked,
29576
29595
  checkboxValue: checkboxValue,
29577
- }); }, [selectedIdentifiers, handleBulkSelection, isChecked, checkboxValue]);
29596
+ isBulkSelectionApplied: isBulkSelectionApplied,
29597
+ getSelectedIdentifiersCount: getSelectedIdentifiersCount,
29598
+ }); }, [selectedIdentifiers, handleBulkSelection, isChecked, checkboxValue, getSelectedIdentifiersCount]);
29578
29599
  return jsxRuntime.jsx(BulkSelectionContext.Provider, __assign({ value: value }, { children: children }));
29579
29600
  };
29580
29601
 
@@ -29656,8 +29677,8 @@ var SvgIcClose = function SvgIcClose(props) {
29656
29677
 
29657
29678
  var BulkSelection = function (_a) {
29658
29679
  var showPagination = _a.showPagination;
29659
- var _b = useBulkSelection(), handleBulkSelection = _b.handleBulkSelection, selectedIdentifiers = _b.selectedIdentifiers, isChecked = _b.isChecked, checkboxValue = _b.checkboxValue;
29660
- var areOptionsSelected = Object.keys(selectedIdentifiers).length > 0;
29680
+ var _b = useBulkSelection(), handleBulkSelection = _b.handleBulkSelection, isChecked = _b.isChecked, checkboxValue = _b.checkboxValue, getSelectedIdentifiersCount = _b.getSelectedIdentifiersCount;
29681
+ var areOptionsSelected = getSelectedIdentifiersCount() > 0;
29661
29682
  var BulkSelectionItems = __spreadArray(__spreadArray([
29662
29683
  {
29663
29684
  locator: exports.BulkSelectionEvents.SELECT_ALL_ON_PAGE,
@@ -29687,6 +29708,43 @@ var BulkSelection = function (_a) {
29687
29708
  return (jsxRuntime.jsxs(PopupMenu, __assign({ autoClose: true }, { children: [jsxRuntime.jsxs(PopupMenu.Button, __assign({ isKebab: true, rootClassName: "h-20 flexbox p-0 dc__no-background dc__no-border dc__outline-none-imp", dataTestId: BULK_DROPDOWN_TEST_ID }, { children: [jsxRuntime.jsx(Checkbox$1, { isChecked: isChecked, onChange: noop$1, rootClassName: "icon-dim-20 m-0", value: checkboxValue }), jsxRuntime.jsx(SvgIcChevronDown, { className: "icon-dim-20 fcn-6 dc__no-shrink" })] })), jsxRuntime.jsx(PopupMenu.Body, __assign({ rootClassName: "dc__top-22 w-150 dc__right-0 pt-4 pb-4 pl-0 pr-0 bcn-0 flex column dc__content-start dc__align-start dc__position-abs bcn-0 dc__border dc__border-radius-4-imp" }, { children: BulkSelectionItems.map(function (item) { return (jsxRuntime.jsx(BulkSelectionDropdownItems, { locator: item.locator, label: item.label, isSelected: item.isSelected, icon: item.icon, handleBulkSelection: handleBulkSelection }, item.locator)); }) }))] })));
29688
29709
  };
29689
29710
 
29711
+ var FilterChip = function (_a) {
29712
+ var _b, _c;
29713
+ var label = _a.label, value = _a.value, handleRemoveFilter = _a.handleRemoveFilter, _d = _a.getFormattedLabel, getFormattedLabel = _d === void 0 ? noop$1 : _d, _e = _a.getFormattedValue, getFormattedValue = _e === void 0 ? noop$1 : _e;
29714
+ var removeFilter = function () {
29715
+ handleRemoveFilter(label, value);
29716
+ };
29717
+ var labelToDisplay = (_b = getFormattedLabel(label)) !== null && _b !== void 0 ? _b : label;
29718
+ var valueToDisplay = (_c = getFormattedValue(label, value)) !== null && _c !== void 0 ? _c : value;
29719
+ return (jsxRuntime.jsxs("div", __assign({ className: "flexbox flex-align-center br-4 dc__border dc__bg-n50 pl-6 pr-6 pt-2 pb-2 dc__user-select-none h-24 dc__gap-6 fs-12 lh-20 cn-9 fw-4" }, { children: [jsxRuntime.jsx("span", __assign({ className: "fw-6 dc__capitalize" }, { children: labelToDisplay })), jsxRuntime.jsx("span", { className: "dc__divider h-24" }), jsxRuntime.jsx("span", __assign({ className: "dc__ellipsis-right" }, { children: valueToDisplay })), jsxRuntime.jsx("button", __assign({ type: "button", className: "flex p-0 dc__transparent", onClick: removeFilter, "aria-label": "Remove filter" }, { children: jsxRuntime.jsx(SvgIcClose, { className: "icon-dim-12 icon-use-fill-n6" }) }))] })));
29720
+ };
29721
+ /**
29722
+ * Component for rendering the applied filter chips
29723
+ */
29724
+ var FilterChips = function (_a) {
29725
+ var filterConfig = _a.filterConfig, clearFilters = _a.clearFilters, onRemoveFilter = _a.onRemoveFilter, getFormattedLabel = _a.getFormattedLabel, getFormattedValue = _a.getFormattedValue;
29726
+ var handleRemoveFilter = function (filterKey, valueToRemove) {
29727
+ var _a;
29728
+ var updatedFilterConfig = JSON.parse(JSON.stringify(filterConfig));
29729
+ if (Array.isArray(filterConfig[filterKey])) {
29730
+ onRemoveFilter(__assign(__assign({}, updatedFilterConfig), (_a = {}, _a[filterKey] = updatedFilterConfig[filterKey].filter(function (val) { return val !== valueToRemove; }), _a)));
29731
+ return;
29732
+ }
29733
+ if (filterKey in updatedFilterConfig) {
29734
+ delete updatedFilterConfig[filterKey];
29735
+ onRemoveFilter(updatedFilterConfig);
29736
+ }
29737
+ };
29738
+ var chips = Object.entries(filterConfig).filter(function (_a) {
29739
+ var _b = __read(_a, 2), value = _b[1];
29740
+ return (Array.isArray(value) ? value.length : !!value);
29741
+ });
29742
+ return (chips.length > 0 && (jsxRuntime.jsxs("div", __assign({ className: "flexbox pt-6 pb-6 flex-wrap dc__gap-8" }, { children: [chips.map(function (_a) {
29743
+ var _b = __read(_a, 2), filterKey = _b[0], filterValue = _b[1];
29744
+ return Array.isArray(filterValue) ? (filterValue.map(function (filter) { return (jsxRuntime.jsx(FilterChip, { label: filterKey, value: filter, handleRemoveFilter: handleRemoveFilter, getFormattedLabel: getFormattedLabel, getFormattedValue: getFormattedValue }, "".concat(filterKey, "-").concat(filter))); })) : (jsxRuntime.jsx(FilterChip, { label: filterKey, value: filterValue, handleRemoveFilter: handleRemoveFilter, getFormattedLabel: getFormattedLabel, getFormattedValue: getFormattedValue }, filterKey));
29745
+ }), jsxRuntime.jsx("div", __assign({ className: "flex" }, { children: jsxRuntime.jsx("button", __assign({ type: "button", className: "cta text fs-13 lh-20-imp h-20 p-0-imp", onClick: clearFilters }, { children: "Clear All Filters" })) }))] }))));
29746
+ };
29747
+
29690
29748
  var MESSAGES = {
29691
29749
  PROVIDE_A_NUMBER: 'Please provide a number',
29692
29750
  LOWERCASE_ALPHANUMERIC: 'Only lowercase alphanumeric characters, -, _ or . allowed',
@@ -30218,6 +30276,11 @@ var BuildInfraConfigForm = function (_a) {
30218
30276
  isRequired: true, profileUnitsMap: unitsMap[action.actionType], handleProfileInputChange: handleProfileInputChange, currentUnitName: currentConfigurations[action.actionType].unit, currentValue: currentConfigurations[action.actionType].value }, action.actionType)); }) })) }), field.locator)); }) }))] }))] })));
30219
30277
  };
30220
30278
 
30279
+ exports.UserListSortableKeys = void 0;
30280
+ (function (UserListSortableKeys) {
30281
+ UserListSortableKeys["email"] = "email_id";
30282
+ UserListSortableKeys["lastLogin"] = "last_login";
30283
+ })(exports.UserListSortableKeys || (exports.UserListSortableKeys = {}));
30221
30284
  /**
30222
30285
  * User Status received from the API
30223
30286
  */
@@ -30233,7 +30296,7 @@ exports.UserStatus = void 0;
30233
30296
  (function (UserStatus) {
30234
30297
  UserStatus["active"] = "active";
30235
30298
  UserStatus["inactive"] = "inactive";
30236
- UserStatus["temporary"] = "temporary";
30299
+ UserStatus["temporary"] = "temporaryAccess";
30237
30300
  })(exports.UserStatus || (exports.UserStatus = {}));
30238
30301
 
30239
30302
  exports.APIResponseHandler = APIResponseHandler;
@@ -30289,6 +30352,7 @@ exports.EmptyState = EmptyState;
30289
30352
  exports.ErrorScreenManager = ErrorScreenManager;
30290
30353
  exports.ErrorScreenNotAuthorized = ErrorScreenNotAuthorized;
30291
30354
  exports.FALLBACK_REQUEST_TIMEOUT = FALLBACK_REQUEST_TIMEOUT;
30355
+ exports.FilterChips = FilterChips;
30292
30356
  exports.ForceDeleteDialog = ForceDeleteDialog;
30293
30357
  exports.GenericEmptyState = GenericEmptyState;
30294
30358
  exports.Grid = Grid;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devtron-labs/devtron-fe-common-lib",
3
- "version": "0.0.62-beta-4",
3
+ "version": "0.0.62-beta-5",
4
4
  "description": "Supporting common component library",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -8,7 +8,10 @@ export enum DraggablePositionVariant {
8
8
 
9
9
  export interface DraggableWrapperProps {
10
10
  children: ReactNode
11
- zIndex?: number
11
+ /**
12
+ * Support for passing the direct value or calc functions as well
13
+ */
14
+ zIndex?: number | string
12
15
  positionVariant?: DraggablePositionVariant
13
16
  /**
14
17
  * dragSelector (class - (append with .), id, etc) will be used to identify the grabbable button that will grab the div to drag
@@ -449,7 +449,13 @@ export const getUrlWithSearchParams = (url: string, params: Record<string | numb
449
449
  const searchParams = new URLSearchParams()
450
450
  Object.keys(params).forEach((key) => {
451
451
  if (params[key]) {
452
- searchParams.append(key, params[key])
452
+ if (Array.isArray(params[key])) {
453
+ params[key].forEach((val) => {
454
+ searchParams.append(key, val)
455
+ })
456
+ } else {
457
+ searchParams.set(key, params[key])
458
+ }
453
459
  }
454
460
  })
455
461
  const queryString = searchParams.toString()
@@ -1,2 +1,2 @@
1
1
  export { default as useUrlFilters } from './useUrlFilters'
2
- export type { UseUrlFiltersProps } from './types'
2
+ export type { UseUrlFiltersProps, UseUrlFiltersReturnType } from './types'
@@ -1,6 +1,61 @@
1
- export interface UseUrlFiltersProps<T> {
1
+ import { SortingOrder } from '../../Constants'
2
+
3
+ export interface UseUrlFiltersProps<T, K> {
2
4
  /**
3
5
  * The key on which the sorting should be applied
4
6
  */
5
7
  initialSortKey?: T
8
+ /**
9
+ * Callback function for parsing the search params
10
+ */
11
+ parseSearchParams?: (searchParams: URLSearchParams) => K
12
+ }
13
+
14
+ export type UseUrlFiltersReturnType<T, K = unknown> = K & {
15
+ /**
16
+ * Currently applied page size
17
+ */
18
+ pageSize: number
19
+ /**
20
+ * Handler for updating the current page
21
+ */
22
+ changePage: (pageNumber: number) => void
23
+ /**
24
+ * Handler for updating the current page size
25
+ */
26
+ changePageSize: (pageSize: number) => void
27
+ /**
28
+ * Current search key
29
+ */
30
+ searchKey: string
31
+ /**
32
+ * Handler for updating the search
33
+ */
34
+ handleSearch: (searchKey: string) => void
35
+ /**
36
+ * Computed offset using the pageSize and pageNumber
37
+ *
38
+ * Note: Used in pagination component
39
+ */
40
+ offset: number
41
+ /**
42
+ * Key on which the sorting is applied
43
+ */
44
+ sortBy: T
45
+ /**
46
+ * Current sort order
47
+ */
48
+ sortOrder: SortingOrder
49
+ /**
50
+ * Handle the sorting type change / key change
51
+ */
52
+ handleSorting: (sortBy: T) => void
53
+ /**
54
+ * Clear all the applied filters
55
+ */
56
+ clearFilters: () => void
57
+ /**
58
+ * Update the search params with the passed object
59
+ */
60
+ updateSearchParams: (paramsToSerialize: K) => void
6
61
  }
@@ -2,7 +2,7 @@ import { useMemo } from 'react'
2
2
  import { useHistory, useLocation } from 'react-router-dom'
3
3
  import { DEFAULT_BASE_PAGE_SIZE, SortingOrder } from '../../Constants'
4
4
  import { DEFAULT_PAGE_NUMBER, URL_FILTER_KEYS } from './constants'
5
- import { UseUrlFiltersProps } from './types'
5
+ import { UseUrlFiltersProps, UseUrlFiltersReturnType } from './types'
6
6
 
7
7
  const { PAGE_SIZE, PAGE_NUMBER, SEARCH_KEY, SORT_BY, SORT_ORDER } = URL_FILTER_KEYS
8
8
 
@@ -23,12 +23,15 @@ const { PAGE_SIZE, PAGE_NUMBER, SEARCH_KEY, SORT_BY, SORT_ORDER } = URL_FILTER_K
23
23
  * ```
24
24
  *
25
25
  */
26
- const useUrlFilters = <T = string>({ initialSortKey }: UseUrlFiltersProps<T> = {}) => {
26
+ const useUrlFilters = <T = string, K = unknown>({
27
+ initialSortKey,
28
+ parseSearchParams,
29
+ }: UseUrlFiltersProps<T, K> = {}): UseUrlFiltersReturnType<T, K> => {
27
30
  const location = useLocation()
28
31
  const history = useHistory()
29
32
  const searchParams = new URLSearchParams(location.search)
30
33
 
31
- const { pageSize, pageNumber, searchKey, sortBy, sortOrder } = useMemo(() => {
34
+ const { pageSize, pageNumber, searchKey, sortBy, sortOrder, parsedParams } = useMemo(() => {
32
35
  const _pageSize = searchParams.get(PAGE_SIZE)
33
36
  const _pageNumber = searchParams.get(PAGE_NUMBER)
34
37
  const _searchKey = searchParams.get(SEARCH_KEY)
@@ -39,6 +42,8 @@ const useUrlFilters = <T = string>({ initialSortKey }: UseUrlFiltersProps<T> = {
39
42
  // Fallback to ascending order
40
43
  const sortByOrder = Object.values(SortingOrder).includes(_sortOrder) ? _sortOrder : SortingOrder.ASC
41
44
 
45
+ const _parsedParams = parseSearchParams ? parseSearchParams(searchParams) : ({} as K)
46
+
42
47
  return {
43
48
  pageSize: Number(_pageSize) || DEFAULT_BASE_PAGE_SIZE,
44
49
  pageNumber: Number(_pageNumber) || DEFAULT_PAGE_NUMBER,
@@ -46,6 +51,7 @@ const useUrlFilters = <T = string>({ initialSortKey }: UseUrlFiltersProps<T> = {
46
51
  sortBy: sortByKey,
47
52
  // sort order should only be applied if the key is available
48
53
  sortOrder: (sortByKey ? sortByOrder : '') as SortingOrder,
54
+ parsedParams: _parsedParams,
49
55
  }
50
56
  }, [searchParams])
51
57
 
@@ -98,10 +104,24 @@ const useUrlFilters = <T = string>({ initialSortKey }: UseUrlFiltersProps<T> = {
98
104
  }
99
105
 
100
106
  const clearFilters = () => {
101
- Object.values(URL_FILTER_KEYS).forEach((key) => {
102
- searchParams.delete(key)
107
+ history.replace({ search: '' })
108
+ }
109
+
110
+ const updateSearchParams = (paramsToSerialize: K) => {
111
+ Object.keys(paramsToSerialize).forEach((key) => {
112
+ if (paramsToSerialize[key]) {
113
+ if (Array.isArray(paramsToSerialize[key])) {
114
+ searchParams.delete(key)
115
+ paramsToSerialize[key].forEach((val) => {
116
+ searchParams.append(key, val)
117
+ })
118
+ } else {
119
+ searchParams.set(key, paramsToSerialize[key])
120
+ }
121
+ }
103
122
  })
104
- history.replace({ search: searchParams.toString() })
123
+ // Not replacing the params as it is being done by _resetPageNumber
124
+ _resetPageNumber()
105
125
  }
106
126
 
107
127
  return {
@@ -115,6 +135,8 @@ const useUrlFilters = <T = string>({ initialSortKey }: UseUrlFiltersProps<T> = {
115
135
  sortOrder,
116
136
  handleSorting,
117
137
  clearFilters,
138
+ ...parsedParams,
139
+ updateSearchParams,
118
140
  }
119
141
  }
120
142
 
@@ -1,3 +1,8 @@
1
+ export enum UserListSortableKeys {
2
+ email = 'email_id',
3
+ lastLogin = 'last_login',
4
+ }
5
+
1
6
  /**
2
7
  * User Status received from the API
3
8
  */
@@ -12,5 +17,5 @@ export enum UserStatusDto {
12
17
  export enum UserStatus {
13
18
  active = 'active',
14
19
  inactive = 'inactive',
15
- temporary = 'temporary',
20
+ temporary = 'temporaryAccess',
16
21
  }
@@ -1 +1,2 @@
1
1
  export * from './constants'
2
+ export * from './types'
@@ -0,0 +1,25 @@
1
+ import { SortingParams } from '../../../Common'
2
+ import { UserListSortableKeys, UserStatus } from './constants'
3
+
4
+ export type BaseFilterQueryParams<T> = {
5
+ /**
6
+ * Offset for the list result
7
+ */
8
+ offset?: number
9
+ /**
10
+ * Number of items required in the list
11
+ */
12
+ size?: number
13
+ /**
14
+ * Search string (if any)
15
+ */
16
+ searchKey?: string
17
+ /**
18
+ * If true, all items are returned with any search / filtering applied without pagination
19
+ */
20
+ showAll?: boolean
21
+ } & SortingParams<T>
22
+
23
+ export type UserListFilterParams = BaseFilterQueryParams<UserListSortableKeys> & {
24
+ status: UserStatus[]
25
+ }
@@ -9,8 +9,8 @@ import { ReactComponent as ICCheckAll } from '../../../Assets/Icon/ic-check-all.
9
9
  import { ReactComponent as ICClose } from '../../../Assets/Icon/ic-close.svg'
10
10
 
11
11
  const BulkSelection = <T,>({ showPagination }: BulkSelectionProps) => {
12
- const { handleBulkSelection, selectedIdentifiers, isChecked, checkboxValue } = useBulkSelection<T>()
13
- const areOptionsSelected = Object.keys(selectedIdentifiers).length > 0
12
+ const { handleBulkSelection, isChecked, checkboxValue, getSelectedIdentifiersCount } = useBulkSelection<T>()
13
+ const areOptionsSelected = getSelectedIdentifiersCount() > 0
14
14
  const BulkSelectionItems: BulkSelectionDropdownItemsType[] = [
15
15
  {
16
16
  locator: BulkSelectionEvents.SELECT_ALL_ON_PAGE,
@@ -22,6 +22,8 @@ const BulkSelectionContext = createContext<UseBulkSelectionReturnType<any>>({
22
22
  handleBulkSelection: noop,
23
23
  isChecked: false,
24
24
  checkboxValue: CHECKBOX_VALUE.CHECKED,
25
+ isBulkSelectionApplied: false,
26
+ getSelectedIdentifiersCount: noop,
25
27
  })
26
28
 
27
29
  export const useBulkSelection = <T,>() => {
@@ -39,6 +41,10 @@ export const BulkSelectionProvider = <T,>({
39
41
  }: UseBulkSelectionProps<T>) => {
40
42
  const [selectedIdentifiers, setSelectedIdentifiers] = useState<T>({} as T)
41
43
 
44
+ const isBulkSelectionApplied = selectedIdentifiers[SELECT_ALL_ACROSS_PAGES_LOCATOR]
45
+
46
+ const getSelectedIdentifiersCount = () => Object.keys(selectedIdentifiers).length
47
+
42
48
  const setIdentifiersAfterClear = (newIdentifiers: T, selectedIds: (number | string)[]) => {
43
49
  const _newIdentifiers = JSON.parse(JSON.stringify(newIdentifiers))
44
50
  selectedIds.forEach((id) => {
@@ -50,7 +56,7 @@ export const BulkSelectionProvider = <T,>({
50
56
  const setIdentifiersAfterPageSelection = (baseObject: T) => {
51
57
  const _selectedIdentifiers = JSON.parse(JSON.stringify(selectedIdentifiers))
52
58
  // removing bulk selection across pages if present
53
- if (_selectedIdentifiers[SELECT_ALL_ACROSS_PAGES_LOCATOR]) {
59
+ if (isBulkSelectionApplied) {
54
60
  delete _selectedIdentifiers[SELECT_ALL_ACROSS_PAGES_LOCATOR]
55
61
  }
56
62
 
@@ -81,10 +87,13 @@ export const BulkSelectionProvider = <T,>({
81
87
  }
82
88
 
83
89
  case BulkSelectionEvents.SELECT_ALL_ACROSS_PAGES: {
84
- if (selectedIdentifiers[SELECT_ALL_ACROSS_PAGES_LOCATOR]) {
90
+ if (isBulkSelectionApplied) {
85
91
  return
86
92
  }
87
- const selectedIdentifiersLength = Object.keys(selectedIdentifiers).length
93
+ const selectedIdentifiersLength = getSelectedIdentifiersCount()
94
+ // This is for showing a modal dialog if applicable to confirm if bulk selection is to be applied
95
+ // Do note that the 'getSelectAllDialogStatus' should be called after the length check explicitly
96
+ // otherwise the modal will open each time
88
97
  if (selectedIdentifiersLength > 0 && getSelectAllDialogStatus() === SelectAllDialogStatus.OPEN) {
89
98
  return
90
99
  }
@@ -130,7 +139,7 @@ export const BulkSelectionProvider = <T,>({
130
139
  }
131
140
 
132
141
  // if selectedIdentifiers contains select all across pages locator then it means all are selected
133
- if (selectedIdentifiers[SELECT_ALL_ACROSS_PAGES_LOCATOR]) {
142
+ if (isBulkSelectionApplied) {
134
143
  return {
135
144
  isChecked: true,
136
145
  checkboxValue: CHECKBOX_VALUE.BULK_CHECKED,
@@ -163,8 +172,10 @@ export const BulkSelectionProvider = <T,>({
163
172
  handleBulkSelection,
164
173
  isChecked,
165
174
  checkboxValue,
175
+ isBulkSelectionApplied,
176
+ getSelectedIdentifiersCount,
166
177
  }),
167
- [selectedIdentifiers, handleBulkSelection, isChecked, checkboxValue],
178
+ [selectedIdentifiers, handleBulkSelection, isChecked, checkboxValue, getSelectedIdentifiersCount],
168
179
  )
169
180
 
170
181
  return <BulkSelectionContext.Provider value={value}>{children}</BulkSelectionContext.Provider>
@@ -26,6 +26,8 @@ export interface GetBulkSelectionCheckboxValuesType {
26
26
  export interface UseBulkSelectionReturnType<T> extends GetBulkSelectionCheckboxValuesType {
27
27
  selectedIdentifiers: T
28
28
  handleBulkSelection: ({ action, data }: HandleBulkSelectionType<T>) => void
29
+ isBulkSelectionApplied: boolean
30
+ getSelectedIdentifiersCount: () => number
29
31
  }
30
32
 
31
33
  export interface BulkSelectionProps {
@@ -0,0 +1,100 @@
1
+ import { ReactComponent as CloseIcon } from '../../../Assets/Icon/ic-close.svg'
2
+ import { noop } from '../../../Common'
3
+ import { FilterChipProps, FilterChipsProps } from './types'
4
+
5
+ const FilterChip = ({
6
+ label,
7
+ value,
8
+ handleRemoveFilter,
9
+ getFormattedLabel = noop,
10
+ getFormattedValue = noop,
11
+ }: FilterChipProps) => {
12
+ const removeFilter = () => {
13
+ handleRemoveFilter(label, value)
14
+ }
15
+
16
+ const labelToDisplay = getFormattedLabel(label) ?? label
17
+
18
+ const valueToDisplay = getFormattedValue(label, value) ?? value
19
+
20
+ return (
21
+ <div className="flexbox flex-align-center br-4 dc__border dc__bg-n50 pl-6 pr-6 pt-2 pb-2 dc__user-select-none h-24 dc__gap-6 fs-12 lh-20 cn-9 fw-4">
22
+ <span className="fw-6 dc__capitalize">{labelToDisplay}</span>
23
+ <span className="dc__divider h-24" />
24
+ <span className="dc__ellipsis-right">{valueToDisplay}</span>
25
+ <button
26
+ type="button"
27
+ className="flex p-0 dc__transparent"
28
+ onClick={removeFilter}
29
+ aria-label="Remove filter"
30
+ >
31
+ <CloseIcon className="icon-dim-12 icon-use-fill-n6" />
32
+ </button>
33
+ </div>
34
+ )
35
+ }
36
+
37
+ /**
38
+ * Component for rendering the applied filter chips
39
+ */
40
+ const FilterChips = ({
41
+ filterConfig,
42
+ clearFilters,
43
+ onRemoveFilter,
44
+ getFormattedLabel,
45
+ getFormattedValue,
46
+ }: FilterChipsProps) => {
47
+ const handleRemoveFilter = (filterKey, valueToRemove) => {
48
+ const updatedFilterConfig = JSON.parse(JSON.stringify(filterConfig))
49
+ if (Array.isArray(filterConfig[filterKey])) {
50
+ onRemoveFilter({
51
+ ...updatedFilterConfig,
52
+ [filterKey]: updatedFilterConfig[filterKey].filter((val) => val !== valueToRemove),
53
+ })
54
+ return
55
+ }
56
+ if (filterKey in updatedFilterConfig) {
57
+ delete updatedFilterConfig[filterKey]
58
+ onRemoveFilter(updatedFilterConfig)
59
+ }
60
+ }
61
+
62
+ const chips = Object.entries(filterConfig).filter(([, value]) => (Array.isArray(value) ? value.length : !!value))
63
+
64
+ return (
65
+ chips.length > 0 && (
66
+ <div className="flexbox pt-6 pb-6 flex-wrap dc__gap-8">
67
+ {chips.map(([filterKey, filterValue]) =>
68
+ Array.isArray(filterValue) ? (
69
+ filterValue.map((filter) => (
70
+ <FilterChip
71
+ key={`${filterKey}-${filter}`}
72
+ label={filterKey}
73
+ value={filter}
74
+ handleRemoveFilter={handleRemoveFilter}
75
+ getFormattedLabel={getFormattedLabel}
76
+ getFormattedValue={getFormattedValue}
77
+ />
78
+ ))
79
+ ) : (
80
+ <FilterChip
81
+ key={filterKey}
82
+ label={filterKey}
83
+ value={filterValue}
84
+ handleRemoveFilter={handleRemoveFilter}
85
+ getFormattedLabel={getFormattedLabel}
86
+ getFormattedValue={getFormattedValue}
87
+ />
88
+ ),
89
+ )}
90
+ <div className="flex">
91
+ <button type="button" className="cta text fs-13 lh-20-imp h-20 p-0-imp" onClick={clearFilters}>
92
+ Clear All Filters
93
+ </button>
94
+ </div>
95
+ </div>
96
+ )
97
+ )
98
+ }
99
+
100
+ export default FilterChips
@@ -0,0 +1,2 @@
1
+ export { default as FilterChips } from './FilterChips.component'
2
+ export type { FilterChipsProps } from './types'
@@ -0,0 +1,39 @@
1
+ import { ReactNode } from 'react'
2
+
3
+ export interface FilterChipProps {
4
+ /**
5
+ * Filter label
6
+ */
7
+ label: string
8
+ /**
9
+ * Corresponding value of the filter
10
+ */
11
+ value: unknown
12
+ /**
13
+ * Callback handler for removing the filter
14
+ */
15
+ handleRemoveFilter: (label: string, valueToRemove: unknown) => void
16
+ /**
17
+ * If passed, the label will be formatted accordingly
18
+ */
19
+ getFormattedLabel?: (filterKey: string) => ReactNode
20
+ /**
21
+ * If passed, the label will be formatted accordingly
22
+ */
23
+ getFormattedValue?: (filterKey: string, filterValue: unknown) => ReactNode
24
+ }
25
+
26
+ export interface FilterChipsProps extends Pick<FilterChipProps, 'getFormattedLabel' | 'getFormattedValue'> {
27
+ /**
28
+ * Current filter configuration
29
+ */
30
+ filterConfig: Record<string, unknown>
31
+ /**
32
+ * Callback handler for removing the filters
33
+ */
34
+ clearFilters: () => void
35
+ /**
36
+ * Handler for removing a applied filter
37
+ */
38
+ onRemoveFilter: (filterConfig: Record<string, unknown>) => void
39
+ }
@@ -1,3 +1,4 @@
1
1
  export * from './APIResponseHandler'
2
2
  export * from './ReactSelect'
3
3
  export * from './BulkSelection'
4
+ export * from './FilterChips'