@devtron-labs/devtron-fe-common-lib 0.0.62-beta-2 → 0.0.62-beta-3

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 (36) 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 +19 -1
  4. package/dist/Common/Hooks/useUrlFilters/useUrlFilters.d.ts +2 -14
  5. package/dist/Common/Types.d.ts +3 -3
  6. package/dist/Pages/GlobalConfigurations/Authorization/constants.d.ts +1 -1
  7. package/dist/Shared/Components/BulkSelection/BulkSelection.d.ts +4 -0
  8. package/dist/Shared/Components/BulkSelection/BulkSelectionDropdownItems.d.ts +4 -0
  9. package/dist/Shared/Components/BulkSelection/BulkSelectionProvider.d.ts +4 -0
  10. package/dist/Shared/Components/BulkSelection/constants.d.ts +9 -0
  11. package/dist/Shared/Components/BulkSelection/index.d.ts +4 -0
  12. package/dist/Shared/Components/BulkSelection/types.d.ts +56 -0
  13. package/dist/Shared/Components/index.d.ts +1 -0
  14. package/dist/Shared/index.d.ts +1 -0
  15. package/dist/index.d.ts +1 -0
  16. package/dist/index.js +462 -167
  17. package/package.json +1 -1
  18. package/src/Assets/Icon/ic-check-all.svg +5 -0
  19. package/src/Assets/Icon/ic-check-square.svg +4 -0
  20. package/src/Assets/Icon/ic-close.svg +9 -0
  21. package/src/Common/DraggableWrapper/types.ts +4 -1
  22. package/src/Common/Helper.tsx +7 -1
  23. package/src/Common/Hooks/useUrlFilters/index.ts +1 -1
  24. package/src/Common/Hooks/useUrlFilters/types.ts +21 -1
  25. package/src/Common/Hooks/useUrlFilters/useUrlFilters.ts +28 -6
  26. package/src/Common/Types.ts +3 -2
  27. package/src/Pages/GlobalConfigurations/Authorization/constants.ts +1 -1
  28. package/src/Shared/Components/BulkSelection/BulkSelection.tsx +77 -0
  29. package/src/Shared/Components/BulkSelection/BulkSelectionDropdownItems.tsx +31 -0
  30. package/src/Shared/Components/BulkSelection/BulkSelectionProvider.tsx +171 -0
  31. package/src/Shared/Components/BulkSelection/constants.tsx +13 -0
  32. package/src/Shared/Components/BulkSelection/index.ts +4 -0
  33. package/src/Shared/Components/BulkSelection/types.tsx +67 -0
  34. package/src/Shared/Components/index.ts +1 -0
  35. package/src/Shared/index.ts +1 -0
  36. package/src/index.ts +1 -0
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-2",
3
+ "version": "0.0.62-beta-3",
4
4
  "description": "Supporting common component library",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -0,0 +1,5 @@
1
+ <svg width="17" height="17" viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <rect x="2" y="2" width="11.2" height="11.2" rx="2" stroke="#596168" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
3
+ <path d="M15.4667 5.86621V11.4662C15.4667 13.6754 13.6758 15.4662 11.4667 15.4662H5.8667" stroke="#596168" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
4
+ <path d="M10.35 5.84961L6.85004 9.34945L5.10004 7.59961" stroke="#596168" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
5
+ </svg>
@@ -0,0 +1,4 @@
1
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <rect x="2" y="2" width="12" height="12" rx="2" stroke="#596168" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
3
+ <path d="M11.2083 5.95801L7.12498 10.0412L5.08331 7.99967" stroke="#596168" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
4
+ </svg>
@@ -0,0 +1,9 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
2
+ <defs>
3
+ <path id="a" class="stroke-color" d="M18.295 5.705a.997.997 0 0 0-1.41 0L12 10.59 7.115 5.705a.997.997 0 1 0-1.41 1.41L10.59 12l-4.885 4.885a.997.997 0 1 0 1.41 1.41L12 13.41l4.885 4.885a.997.997 0 0 0 1.41-1.41L13.41 12l4.885-4.885a.997.997 0 0 0 0-1.41z"/>
4
+ </defs>
5
+ <g fill="none" fill-rule="evenodd">
6
+ <path d=""/>
7
+ <use fill="#999" xlink:href="#a"/>
8
+ </g>
9
+ </svg>
@@ -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,26 @@
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
+ pageSize: number
16
+ changePage: (pageNumber: number) => void
17
+ changePageSize: (pageSize: number) => void
18
+ searchKey: string
19
+ handleSearch: (searchKey: string) => void
20
+ offset: number
21
+ sortBy: T
22
+ sortOrder: SortingOrder
23
+ handleSorting: (sortBy: T) => void
24
+ clearFilters: () => void
25
+ updateSearchParams: (paramsToSerialize: K) => void
6
26
  }
@@ -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
 
@@ -51,11 +51,13 @@ export interface Teams {
51
51
  export enum CHECKBOX_VALUE {
52
52
  CHECKED = 'CHECKED',
53
53
  INTERMEDIATE = 'INTERMEDIATE',
54
+ BULK_CHECKED = 'BULK_CHECKED',
54
55
  }
55
56
  export interface CheckboxProps {
56
57
  onChange: (event) => void
57
58
  isChecked: boolean
58
- value: 'CHECKED' | 'INTERMEDIATE'
59
+ // FIXME: Need to replace this CHECKBOX_VALUE enum, and replace string instances in dashboard
60
+ value: 'CHECKED' | 'INTERMEDIATE' | 'BULK_CHECKED'
59
61
  disabled?: boolean
60
62
  tabIndex?: number
61
63
  rootClassName?: string
@@ -373,7 +375,6 @@ export interface CommonNodeAttr {
373
375
  }
374
376
  appReleaseTagNames?: string[]
375
377
  tagsEditable?: boolean
376
- isGitOpsRepoNotConfigured?: boolean
377
378
  deploymentAppCreated?: boolean
378
379
  isLast?: boolean
379
380
  downstreamEnvironments?: DownstreamNodesEnvironmentsType[]
@@ -12,5 +12,5 @@ export enum UserStatusDto {
12
12
  export enum UserStatus {
13
13
  active = 'active',
14
14
  inactive = 'inactive',
15
- temporary = 'temporary',
15
+ temporary = 'temporaryAccess',
16
16
  }
@@ -0,0 +1,77 @@
1
+ import BulkSelectionDropdownItems from './BulkSelectionDropdownItems'
2
+ import { CHECKBOX_VALUE, Checkbox, PopupMenu, noop } from '../../../Common'
3
+ import { useBulkSelection } from './BulkSelectionProvider'
4
+ import { BulkSelectionDropdownItemsType, BulkSelectionEvents, BulkSelectionProps } from './types'
5
+ import { BULK_DROPDOWN_TEST_ID, BulkSelectionOptionsLabels } from './constants'
6
+ import { ReactComponent as ICChevronDown } from '../../../Assets/Icon/ic-chevron-down.svg'
7
+ import { ReactComponent as ICCheckSquare } from '../../../Assets/Icon/ic-check-square.svg'
8
+ import { ReactComponent as ICCheckAll } from '../../../Assets/Icon/ic-check-all.svg'
9
+ import { ReactComponent as ICClose } from '../../../Assets/Icon/ic-close.svg'
10
+
11
+ const BulkSelection = <T,>({ showPagination }: BulkSelectionProps) => {
12
+ const { handleBulkSelection, isChecked, checkboxValue, getSelectedIdentifiersCount } = useBulkSelection<T>()
13
+ const areOptionsSelected = getSelectedIdentifiersCount() > 0
14
+ const BulkSelectionItems: BulkSelectionDropdownItemsType[] = [
15
+ {
16
+ locator: BulkSelectionEvents.SELECT_ALL_ON_PAGE,
17
+ label: BulkSelectionOptionsLabels[BulkSelectionEvents.SELECT_ALL_ON_PAGE],
18
+ isSelected: isChecked && checkboxValue === CHECKBOX_VALUE.CHECKED,
19
+ icon: ICCheckSquare,
20
+ },
21
+ ...(showPagination
22
+ ? [
23
+ {
24
+ locator: BulkSelectionEvents.SELECT_ALL_ACROSS_PAGES,
25
+ label: BulkSelectionOptionsLabels[BulkSelectionEvents.SELECT_ALL_ACROSS_PAGES],
26
+ isSelected: isChecked && checkboxValue === CHECKBOX_VALUE.BULK_CHECKED,
27
+ icon: ICCheckAll,
28
+ },
29
+ ]
30
+ : []),
31
+ ...(areOptionsSelected
32
+ ? [
33
+ {
34
+ locator: BulkSelectionEvents.CLEAR_ALL_SELECTIONS,
35
+ label: BulkSelectionOptionsLabels[BulkSelectionEvents.CLEAR_ALL_SELECTIONS],
36
+ isSelected: false,
37
+ icon: ICClose,
38
+ },
39
+ ]
40
+ : []),
41
+ ]
42
+
43
+ return (
44
+ <PopupMenu autoClose>
45
+ <PopupMenu.Button
46
+ isKebab
47
+ rootClassName="h-20 flexbox p-0 dc__no-background dc__no-border dc__outline-none-imp"
48
+ dataTestId={BULK_DROPDOWN_TEST_ID}
49
+ >
50
+ <Checkbox
51
+ isChecked={isChecked}
52
+ onChange={noop}
53
+ rootClassName="icon-dim-20 m-0"
54
+ value={checkboxValue}
55
+ // Ideally should be disabled but was giving issue with cursor
56
+ />
57
+
58
+ <ICChevronDown className="icon-dim-20 fcn-6 dc__no-shrink" />
59
+ </PopupMenu.Button>
60
+
61
+ <PopupMenu.Body 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">
62
+ {BulkSelectionItems.map((item) => (
63
+ <BulkSelectionDropdownItems<T>
64
+ key={item.locator}
65
+ locator={item.locator}
66
+ label={item.label}
67
+ isSelected={item.isSelected}
68
+ icon={item.icon}
69
+ handleBulkSelection={handleBulkSelection}
70
+ />
71
+ ))}
72
+ </PopupMenu.Body>
73
+ </PopupMenu>
74
+ )
75
+ }
76
+
77
+ export default BulkSelection
@@ -0,0 +1,31 @@
1
+ import { BulkSelectionDropdownItemsProps } from './types'
2
+
3
+ const BulkSelectionDropdownItems = <T,>({
4
+ locator,
5
+ label,
6
+ isSelected,
7
+ handleBulkSelection,
8
+ icon: Icon,
9
+ }: BulkSelectionDropdownItemsProps<T>) => {
10
+ const handleSelect = () => {
11
+ handleBulkSelection({
12
+ action: locator,
13
+ })
14
+ }
15
+
16
+ return (
17
+ <button
18
+ data-testid={`bulk-action-${locator}`}
19
+ onClick={handleSelect}
20
+ className={`dc__no-border dc__outline-none-imp w-100 flexbox h-32 dc__align-items-center pt-6 pr-8 pb-6 pl-8 dc__gap-8 ${
21
+ isSelected ? 'cb-5 bcb-2 fs-13 fw-6 lh-20' : 'dc__no-background cn-9 fs-13 fw-4 lh-20 dc__hover-n50'
22
+ }`}
23
+ type="button"
24
+ >
25
+ <Icon className="icon-dim-16" />
26
+ {label}
27
+ </button>
28
+ )
29
+ }
30
+
31
+ export default BulkSelectionDropdownItems
@@ -0,0 +1,171 @@
1
+ import { createContext, useContext, useMemo, useState } from 'react'
2
+ import { BULK_SELECTION_CONTEXT_ERROR, SELECT_ALL_ACROSS_PAGES_LOCATOR, getInvalidActionMessage } from './constants'
3
+ import {
4
+ BulkSelectionEvents,
5
+ GetBulkSelectionCheckboxValuesType,
6
+ HandleBulkSelectionType,
7
+ SelectAllDialogStatus,
8
+ UseBulkSelectionProps,
9
+ UseBulkSelectionReturnType,
10
+ } from './types'
11
+ import { CHECKBOX_VALUE, noop } from '../../../Common'
12
+
13
+ // giving type any here since not exporting this context, rather using it through useBulkSelection hook which is typed
14
+ const BulkSelectionContext = createContext<UseBulkSelectionReturnType<any>>({
15
+ selectedIdentifiers: {},
16
+ handleBulkSelection: noop,
17
+ isChecked: false,
18
+ checkboxValue: CHECKBOX_VALUE.CHECKED,
19
+ isBulkSelectionApplied: false,
20
+ getSelectedIdentifiersCount: noop,
21
+ })
22
+
23
+ export const useBulkSelection = <T,>() => {
24
+ const context = useContext<UseBulkSelectionReturnType<T>>(BulkSelectionContext)
25
+ if (!context) {
26
+ throw new Error(BULK_SELECTION_CONTEXT_ERROR)
27
+ }
28
+ return context
29
+ }
30
+
31
+ export const BulkSelectionProvider = <T,>({
32
+ children,
33
+ identifiers,
34
+ getSelectAllDialogStatus,
35
+ }: UseBulkSelectionProps<T>) => {
36
+ const [selectedIdentifiers, setSelectedIdentifiers] = useState<T>({} as T)
37
+
38
+ const isBulkSelectionApplied = selectedIdentifiers[SELECT_ALL_ACROSS_PAGES_LOCATOR]
39
+
40
+ const getSelectedIdentifiersCount = () => Object.keys(selectedIdentifiers).length
41
+
42
+ const setIdentifiersAfterClear = (newIdentifiers: T, selectedIds: (number | string)[]) => {
43
+ const _newIdentifiers = JSON.parse(JSON.stringify(newIdentifiers))
44
+ selectedIds.forEach((id) => {
45
+ delete _newIdentifiers[id]
46
+ })
47
+ setSelectedIdentifiers(_newIdentifiers)
48
+ }
49
+
50
+ const setIdentifiersAfterPageSelection = (baseObject: T) => {
51
+ const _selectedIdentifiers = JSON.parse(JSON.stringify(selectedIdentifiers))
52
+ // removing bulk selection across pages if present
53
+ if (isBulkSelectionApplied) {
54
+ delete _selectedIdentifiers[SELECT_ALL_ACROSS_PAGES_LOCATOR]
55
+ }
56
+
57
+ setSelectedIdentifiers({
58
+ ..._selectedIdentifiers,
59
+ ...baseObject,
60
+ })
61
+ }
62
+
63
+ const handleBulkSelection = ({ action, data }: HandleBulkSelectionType<T>) => {
64
+ const selectedIds = data?.identifierIds ?? []
65
+ const identifierObject = data?.identifierObject ?? {}
66
+
67
+ switch (action) {
68
+ case BulkSelectionEvents.CLEAR_ALL_SELECTIONS:
69
+ setSelectedIdentifiers({} as T)
70
+ break
71
+
72
+ case BulkSelectionEvents.CLEAR_IDENTIFIERS_AFTER_ACROSS_SELECTION: {
73
+ setIdentifiersAfterClear(identifiers, selectedIds)
74
+ break
75
+ }
76
+
77
+ case BulkSelectionEvents.CLEAR_IDENTIFIERS: {
78
+ setIdentifiersAfterClear(selectedIdentifiers, selectedIds)
79
+ break
80
+ }
81
+
82
+ case BulkSelectionEvents.SELECT_ALL_ACROSS_PAGES: {
83
+ if (isBulkSelectionApplied) {
84
+ return
85
+ }
86
+ const selectedIdentifiersLength = getSelectedIdentifiersCount()
87
+ // This is for showing a modal dialog if applicable to confirm if bulk selection is to be applied
88
+ // Do note that the 'getSelectAllDialogStatus' should be called after the length check explicitly
89
+ // otherwise the modal will open each time
90
+ if (selectedIdentifiersLength > 0 && getSelectAllDialogStatus() === SelectAllDialogStatus.OPEN) {
91
+ return
92
+ }
93
+
94
+ setSelectedIdentifiers({
95
+ [SELECT_ALL_ACROSS_PAGES_LOCATOR]: true,
96
+ } as unknown as T)
97
+ break
98
+ }
99
+
100
+ case BulkSelectionEvents.CLEAR_SELECTIONS_AND_SELECT_ALL_ACROSS_PAGES:
101
+ setSelectedIdentifiers({
102
+ [SELECT_ALL_ACROSS_PAGES_LOCATOR]: true,
103
+ } as unknown as T)
104
+ break
105
+
106
+ case BulkSelectionEvents.SELECT_ALL_ON_PAGE: {
107
+ setIdentifiersAfterPageSelection(identifiers)
108
+ break
109
+ }
110
+
111
+ case BulkSelectionEvents.SELECT_IDENTIFIER: {
112
+ setIdentifiersAfterPageSelection(identifierObject as T)
113
+ break
114
+ }
115
+
116
+ default:
117
+ throw new Error(getInvalidActionMessage(action))
118
+ }
119
+ }
120
+
121
+ const getBulkSelectionCheckboxValues = (): GetBulkSelectionCheckboxValuesType => {
122
+ const selectedIdentifiersArray = Object.keys(selectedIdentifiers)
123
+ if (selectedIdentifiersArray.length === 0) {
124
+ return {
125
+ isChecked: false,
126
+ checkboxValue: CHECKBOX_VALUE.CHECKED,
127
+ }
128
+ }
129
+
130
+ // if selectedIdentifiers contains select all across pages locator then it means all are selected
131
+ if (isBulkSelectionApplied) {
132
+ return {
133
+ isChecked: true,
134
+ checkboxValue: CHECKBOX_VALUE.BULK_CHECKED,
135
+ }
136
+ }
137
+
138
+ // if all the identifiers are selected then CHECKED else intermediate
139
+ const areAllPresentIdentifiersSelected = Object.keys(identifiers).every(
140
+ (identifierId) => selectedIdentifiers[identifierId],
141
+ )
142
+
143
+ if (areAllPresentIdentifiersSelected) {
144
+ return {
145
+ isChecked: true,
146
+ checkboxValue: CHECKBOX_VALUE.CHECKED,
147
+ }
148
+ }
149
+
150
+ return {
151
+ isChecked: true,
152
+ checkboxValue: CHECKBOX_VALUE.INTERMEDIATE,
153
+ }
154
+ }
155
+
156
+ const { isChecked, checkboxValue } = getBulkSelectionCheckboxValues()
157
+
158
+ const value = useMemo(
159
+ () => ({
160
+ selectedIdentifiers,
161
+ handleBulkSelection,
162
+ isChecked,
163
+ checkboxValue,
164
+ isBulkSelectionApplied,
165
+ getSelectedIdentifiersCount,
166
+ }),
167
+ [selectedIdentifiers, handleBulkSelection, isChecked, checkboxValue, getSelectedIdentifiersCount],
168
+ )
169
+
170
+ return <BulkSelectionContext.Provider value={value}>{children}</BulkSelectionContext.Provider>
171
+ }
@@ -0,0 +1,13 @@
1
+ import { BulkSelectionEvents } from './types'
2
+
3
+ export const BULK_DROPDOWN_TEST_ID = 'bulk-selection-pop-up-menu' as const
4
+ export const BulkSelectionOptionsLabels = {
5
+ [BulkSelectionEvents.SELECT_ALL_ON_PAGE]: 'All on this page',
6
+ [BulkSelectionEvents.SELECT_ALL_ACROSS_PAGES]: 'All across pages',
7
+ [BulkSelectionEvents.CLEAR_ALL_SELECTIONS]: 'Clear selection',
8
+ } as const
9
+
10
+ // Considering application can not be named as *
11
+ export const SELECT_ALL_ACROSS_PAGES_LOCATOR = '*' as const
12
+ export const getInvalidActionMessage = (action: string) => `Invalid action ${action} passed to useBulkSelection`
13
+ export const BULK_SELECTION_CONTEXT_ERROR = 'useBulkSelection must be used within BulkSelectionContext'
@@ -0,0 +1,4 @@
1
+ export { default as BulkSelection } from './BulkSelection'
2
+ export * from './BulkSelectionProvider'
3
+ export * from './types'
4
+ export * from './constants'
@@ -0,0 +1,67 @@
1
+ import { CHECKBOX_VALUE } from '../../../Common'
2
+
3
+ export enum BulkSelectionEvents {
4
+ CLEAR_ALL_SELECTIONS = 'CLEAR_ALL_SELECTIONS',
5
+ CLEAR_IDENTIFIERS = 'CLEAR_IDENTIFIERS',
6
+ SELECT_ALL_ACROSS_PAGES = 'SELECT_ALL_ACROSS_PAGES',
7
+ SELECT_ALL_ON_PAGE = 'SELECT_ALL_ON_PAGE',
8
+ SELECT_IDENTIFIER = 'SELECT_IDENTIFIER',
9
+ CLEAR_IDENTIFIERS_AFTER_ACROSS_SELECTION = 'CLEAR_IDENTIFIERS_AFTER_ACROSS_SELECTION',
10
+ CLEAR_SELECTIONS_AND_SELECT_ALL_ACROSS_PAGES = 'CLEAR_SELECTIONS_AND_SELECT_ALL_ACROSS_PAGES',
11
+ }
12
+
13
+ export interface HandleBulkSelectionType<T> {
14
+ action: BulkSelectionEvents
15
+ data?: {
16
+ identifierIds?: (number | string)[]
17
+ identifierObject?: T
18
+ }
19
+ }
20
+
21
+ export interface GetBulkSelectionCheckboxValuesType {
22
+ isChecked: boolean
23
+ checkboxValue: CHECKBOX_VALUE
24
+ }
25
+
26
+ export interface UseBulkSelectionReturnType<T> extends GetBulkSelectionCheckboxValuesType {
27
+ selectedIdentifiers: T
28
+ handleBulkSelection: ({ action, data }: HandleBulkSelectionType<T>) => void
29
+ isBulkSelectionApplied: boolean
30
+ getSelectedIdentifiersCount: () => number
31
+ }
32
+
33
+ export interface BulkSelectionProps {
34
+ showPagination: boolean
35
+ }
36
+
37
+ export interface BulkSelectionDropdownItemsType {
38
+ locator: BulkSelectionEvents
39
+ label: string
40
+ isSelected: boolean
41
+ icon: React.FunctionComponent<React.SVGProps<SVGSVGElement>>
42
+ }
43
+
44
+ export interface BulkSelectionDropdownItemsProps<T>
45
+ extends BulkSelectionDropdownItemsType,
46
+ Pick<UseBulkSelectionReturnType<T>, 'handleBulkSelection'> {}
47
+
48
+ export enum SelectAllDialogStatus {
49
+ OPEN = 'OPEN',
50
+ CLOSED = 'CLOSED',
51
+ }
52
+
53
+ // This type is intended to be used with UseBulkSelectionProps, e.g, UseBulkSelectionProps<BulkSelectionIdentifiersType<boolean>>
54
+ export type BulkSelectionIdentifiersType<T> = Record<string | number, T>
55
+
56
+ export interface UseBulkSelectionProps<T> {
57
+ /**
58
+ * Response from API, assuming structure to be array of objects with key and values
59
+ * This will the given ids on current page
60
+ */
61
+ identifiers: T
62
+ /**
63
+ * Act as buffer between select all across pages and select all on page state
64
+ */
65
+ getSelectAllDialogStatus: () => SelectAllDialogStatus
66
+ children?: React.ReactNode
67
+ }
@@ -0,0 +1 @@
1
+ export * from './BulkSelection'
@@ -0,0 +1 @@
1
+ export * from './Components'
package/src/index.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export * from './Common'
2
2
  export * from './Pages'
3
+ export * from './Shared'