Skip to content

Commit 2601821

Browse files
authored
Merge pull request #1596 from devtron-labs/feat/inactive-user-ent
feat: add support for user status in permission list view
2 parents b11ddf8 + 524d850 commit 2601821

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+395
-428
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"private": true,
55
"homepage": "/dashboard",
66
"dependencies": {
7-
"@devtron-labs/devtron-fe-common-lib": "0.0.58",
7+
"@devtron-labs/devtron-fe-common-lib": "0.0.58-beta-6",
88
"@rjsf/core": "^5.13.3",
99
"@rjsf/utils": "^5.13.3",
1010
"@rjsf/validator-ajv8": "^5.13.3",

src/Pages/GlobalConfigurations/Authorization/APITokens/CreateAPIToken.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
TippyCustomized,
1414
TippyTheme,
1515
CustomInput,
16+
OptionType,
1617
} from '@devtron-labs/devtron-fe-common-lib'
1718
import { FormType, GenerateTokenType } from './authorization.type'
1819
import { createGeneratedAPIToken } from './service'
@@ -28,7 +29,6 @@ import {
2829
ChartGroupPermissionsFilter,
2930
DirectPermissionsRoleFilter,
3031
EntityTypes,
31-
OptionType,
3232
} from '../shared/components/userGroups/userGroups.types'
3333
import GroupPermission from './GroupPermission'
3434
import { mainContext } from '../../../../components/common/navigation/NavigationRoutes'

src/Pages/GlobalConfigurations/Authorization/APITokens/EditAPIToken.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
copyToClipboard,
1111
CustomInput,
1212
noop,
13+
OptionType,
1314
} from '@devtron-labs/devtron-fe-common-lib'
1415
import { useHistory, useRouteMatch, useParams } from 'react-router-dom'
1516
import moment from 'moment'
@@ -31,7 +32,6 @@ import {
3132
ChartGroupPermissionsFilter,
3233
DirectPermissionsRoleFilter,
3334
EntityTypes,
34-
OptionType,
3535
} from '../shared/components/userGroups/userGroups.types'
3636
import { mainContext } from '../../../../components/common/navigation/NavigationRoutes'
3737
import DeleteAPITokenModal from './DeleteAPITokenModal'

src/Pages/GlobalConfigurations/Authorization/APITokens/authorization.utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1+
import { OptionType } from '@devtron-labs/devtron-fe-common-lib'
12
import { ACCESS_TYPE_MAP, SERVER_MODE } from '../../../../config'
23
import {
34
ActionTypes,
45
ChartGroupPermissionsFilter,
56
DirectPermissionsRoleFilter,
67
EntityTypes,
7-
OptionType,
88
ViewChartGroupPermission,
99
} from '../shared/components/userGroups/userGroups.types'
1010
import { UserCreateOrUpdatePayload } from '../types'

src/Pages/GlobalConfigurations/Authorization/PermissionGroups/List/PermissionGroupList.component.tsx

Lines changed: 80 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,28 @@
1-
import React, { useCallback, useMemo } from 'react'
1+
import React, { useCallback, useMemo, useRef } from 'react'
22
import {
3+
SortingOrder,
4+
SortableTableHeaderCell,
35
ErrorScreenNotAuthorized,
46
ERROR_EMPTY_SCREEN,
57
noop,
68
Pagination,
79
Reload,
810
TOAST_ACCESS_DENIED,
911
useAsync,
12+
DEFAULT_BASE_PAGE_SIZE,
13+
useUrlFilters,
1014
} from '@devtron-labs/devtron-fe-common-lib'
11-
import { API_STATUS_CODES, DEFAULT_BASE_PAGE_SIZE, SortingOrder } from '../../../../../config'
15+
import { API_STATUS_CODES } from '../../../../../config'
1216

1317
import { getPermissionGroupList } from '../../authorization.service'
1418
import { permissionGroupLoading, SortableKeys } from './constants'
1519
import PermissionGroupListHeader from './PermissionGroupListHeader'
1620
import PermissionGroupRow from './PermissionGroupRow'
1721
import { useAuthorizationContext } from '../../AuthorizationProvider'
1822
import { importComponentFromFELibrary } from '../../../../../components/common'
19-
import useUrlFilters from '../../shared/hooks/useUrlFilters'
20-
import SortableTableHeaderCell from '../../../../../components/common/SortableTableHeaderCell'
2123
import FiltersEmptyState from '../../shared/components/FilterEmptyState/FilterEmptyState.component'
2224
import NoPermissionGroups from './NoPermissionGroups'
25+
import { abortPreviousRequests, getIsRequestAborted } from '../../utils'
2326

2427
const PermissionGroupInfoBar = importComponentFromFELibrary('PermissionGroupInfoBar', noop, 'function')
2528

@@ -46,9 +49,19 @@ const PermissionGroupList = () => {
4649
}),
4750
[pageSize, offset, searchKey, sortBy, sortOrder],
4851
)
49-
const [isLoading, result, error, reload] = useAsync(() => getPermissionGroupList(filterConfig), [filterConfig])
52+
const abortControllerRef = useRef(new AbortController())
53+
const [isLoading, result, error, reload] = useAsync(
54+
() =>
55+
abortPreviousRequests(
56+
() => getPermissionGroupList(filterConfig, abortControllerRef.current.signal),
57+
abortControllerRef,
58+
),
59+
[filterConfig],
60+
)
5061
const { isAutoAssignFlowEnabled } = useAuthorizationContext()
5162

63+
const showLoadingState = isLoading || getIsRequestAborted(error)
64+
5265
const getPermissionGroupDataForExport = useCallback(
5366
() =>
5467
getPermissionGroupList({
@@ -62,7 +75,7 @@ const PermissionGroupList = () => {
6275
[filterConfig],
6376
)
6477

65-
if (!isLoading) {
78+
if (!showLoadingState) {
6679
if (error) {
6780
if ([API_STATUS_CODES.PERMISSION_DENIED, API_STATUS_CODES.UNAUTHORIZED].includes(error.code)) {
6881
return (
@@ -72,7 +85,7 @@ const PermissionGroupList = () => {
7285
/>
7386
)
7487
}
75-
return <Reload reload={reload} />
88+
return <Reload reload={reload} className="flex-grow-1" />
7689
}
7790

7891
// The null state is shown only when filters are not applied
@@ -81,78 +94,79 @@ const PermissionGroupList = () => {
8194
}
8295
}
8396

97+
// Disable the filter actions
98+
const isActionsDisabled = showLoadingState || !(result.totalCount && result.permissionGroups.length)
99+
84100
const sortByName = () => {
85101
handleSorting(SortableKeys.name)
86102
}
87103

88-
const handleClearFilters = () => {
89-
clearFilters()
90-
}
91-
92104
return (
93105
<div className="flexbox-col dc__gap-8 flex-grow-1">
94106
<PermissionGroupListHeader
95-
disabled={isLoading || !(result.totalCount && result.permissionGroups.length)}
107+
disabled={isActionsDisabled}
96108
handleSearch={handleSearch}
97109
initialSearchText={searchKey}
98110
getDataToExport={getPermissionGroupDataForExport}
99111
/>
100-
{isAutoAssignFlowEnabled && <PermissionGroupInfoBar />}
101-
<div className="flexbox-col flex-grow-1">
102-
<div className="user-permission__header cn-7 fs-12 fw-6 lh-20 dc__uppercase pl-20 pr-20 dc__border-bottom">
103-
<span />
104-
<SortableTableHeaderCell
105-
title="Name"
106-
sortOrder={sortOrder}
107-
isSorted={sortBy === SortableKeys.name}
108-
triggerSorting={sortByName}
109-
disabled={isLoading}
110-
/>
111-
<span>Description</span>
112-
<span />
112+
{isAutoAssignFlowEnabled && (
113+
<div className="pl-20 pr-20">
114+
<PermissionGroupInfoBar />
113115
</div>
114-
{isLoading || (result.totalCount && result.permissionGroups.length) ? (
115-
<>
116-
{isLoading ? (
117-
permissionGroupLoading.map((permissionGroup) => (
118-
<div
119-
className="user-permission__row pl-20 pr-20 show-shimmer-loading"
120-
key={`permission-group-list-${permissionGroup.id}`}
121-
>
122-
<span className="child child-shimmer-loading" />
123-
<span className="child child-shimmer-loading" />
124-
<span className="child child-shimmer-loading" />
125-
</div>
126-
))
127-
) : (
128-
<>
129-
<div className="fs-13 fw-4 lh-20 cn-9 flex-grow-1">
130-
{result.permissionGroups.map((permissionGroup, index) => (
131-
<PermissionGroupRow
132-
{...permissionGroup}
133-
index={index}
134-
key={`permission-group-${permissionGroup.id}`}
135-
refetchPermissionGroupList={reload}
136-
/>
137-
))}
138-
</div>
139-
{result.totalCount > DEFAULT_BASE_PAGE_SIZE && (
140-
<Pagination
141-
rootClassName="flex dc__content-space pl-20 pr-20 dc__border-top"
142-
size={result.totalCount}
143-
offset={offset}
144-
pageSize={pageSize}
145-
changePage={changePage}
146-
changePageSize={changePageSize}
116+
)}
117+
{isLoading || (result.totalCount && result.permissionGroups.length) ? (
118+
<div className="flexbox-col flex-grow-1">
119+
<div className="user-permission__header cn-7 fs-12 fw-6 lh-20 dc__uppercase pl-20 pr-20 dc__border-bottom">
120+
<span />
121+
<SortableTableHeaderCell
122+
title="Name"
123+
sortOrder={sortOrder}
124+
isSorted={sortBy === SortableKeys.name}
125+
triggerSorting={sortByName}
126+
disabled={isActionsDisabled}
127+
/>
128+
<span>Description</span>
129+
<span />
130+
</div>
131+
{showLoadingState ? (
132+
permissionGroupLoading.map((permissionGroup) => (
133+
<div
134+
className="user-permission__row pl-20 pr-20 show-shimmer-loading"
135+
key={`permission-group-list-${permissionGroup.id}`}
136+
>
137+
<span className="child child-shimmer-loading" />
138+
<span className="child child-shimmer-loading" />
139+
<span className="child child-shimmer-loading" />
140+
</div>
141+
))
142+
) : (
143+
<>
144+
<div className="fs-13 fw-4 lh-20 cn-9 flex-grow-1">
145+
{result.permissionGroups.map((permissionGroup, index) => (
146+
<PermissionGroupRow
147+
{...permissionGroup}
148+
index={index}
149+
key={`permission-group-${permissionGroup.id}`}
150+
refetchPermissionGroupList={reload}
147151
/>
148-
)}
149-
</>
150-
)}
151-
</>
152-
) : (
153-
<FiltersEmptyState clearFilters={handleClearFilters} />
154-
)}
155-
</div>
152+
))}
153+
</div>
154+
{result.totalCount > DEFAULT_BASE_PAGE_SIZE && (
155+
<Pagination
156+
rootClassName="flex dc__content-space pl-20 pr-20 dc__border-top"
157+
size={result.totalCount}
158+
offset={offset}
159+
pageSize={pageSize}
160+
changePage={changePage}
161+
changePageSize={changePageSize}
162+
/>
163+
)}
164+
</>
165+
)}
166+
</div>
167+
) : (
168+
<FiltersEmptyState clearFilters={clearFilters} />
169+
)}
156170
</div>
157171
)
158172
}

src/Pages/GlobalConfigurations/Authorization/PermissionGroups/List/PermissionGroupRow.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const PermissionGroupRow = ({ id, name, description, index, refetchPermissionGro
2121
setIsModalLoading(true)
2222
try {
2323
await deletePermissionGroup(id)
24-
toast.success('User deleted')
24+
toast.success('Group deleted')
2525
refetchPermissionGroupList()
2626
setIsDeleteModalOpen(false)
2727
} catch (err) {

src/Pages/GlobalConfigurations/Authorization/UserAndGroupPermissions.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ const UserAndGroupPermissions = () => {
216216
const [userGroups, projects, environments, chartGroups, envClustersList, customRolesList] = data
217217

218218
return (
219-
<div className="flexbox-col flex-grow-1 h-100 w-100">
219+
<div className="flexbox-col flex-grow-1 h-100 w-100 dc__content-center">
220220
<AuthorizationProvider
221221
// TODO (v3): Simplify and move these to API service instead
222222
value={{

src/Pages/GlobalConfigurations/Authorization/UserPermissions/AddEdit/UserForm.tsx

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
RadioGroup,
1212
RadioGroupItem,
1313
ServerErrors,
14+
OptionType,
1415
} from '@devtron-labs/devtron-fe-common-lib'
1516
import Creatable from 'react-select/creatable'
1617
import Select from 'react-select'
@@ -21,7 +22,6 @@ import {
2122
ChartGroupPermissionsFilter,
2223
EntityTypes,
2324
ActionTypes,
24-
OptionType,
2525
ViewChartGroupPermission,
2626
} from '../../shared/components/userGroups/userGroups.types'
2727
import { mapByKey, validateEmail, deepEqual, importComponentFromFELibrary } from '../../../../../components/common'
@@ -63,9 +63,6 @@ const CreatableChipStyle = {
6363
}),
6464
}
6565

66-
// TODO (v1): Replace with enterprise check
67-
const showStatus = false
68-
6966
const UserForm = ({ isAddMode, userData = null }: { isAddMode: boolean; userData: User }) => {
7067
const { serverMode } = useMainContext()
7168

@@ -390,9 +387,8 @@ const UserForm = ({ isAddMode, userData = null }: { isAddMode: boolean; userData
390387
<span className="cn-5">/</span>
391388
<span className="cn-9 fw-6 dc__ellipsis-right">{isAddMode ? 'Add User' : userData.emailId}</span>
392389
</div>
393-
{(showStatus || !isAddMode) && (
390+
{!isAddMode && (
394391
<div className="flex dc__content-start dc__gap-12">
395-
{showStatus && <div>status</div>}
396392
{!isAddMode && (
397393
<button
398394
disabled={submitting}

src/Pages/GlobalConfigurations/Authorization/UserPermissions/List/ExportUserPermissionsToCsv.tsx

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ import ExportToCsv from '../../../../../components/common/ExportToCsv/ExportToCs
77
import { FILE_NAMES, USER_EXPORT_HEADER_ROW } from '../../../../../components/common/ExportToCsv/constants'
88
import { useAuthorizationContext } from '../../AuthorizationProvider'
99
import { getRoleFiltersToExport } from '../../utils'
10+
import { LAST_LOGIN_TIME_NULL_STATE } from '../constants'
11+
import { importComponentFromFELibrary } from '../../../../../components/common'
12+
13+
const getStatusExportText = importComponentFromFELibrary('getStatusExportText', null, 'function')
14+
const showStatus = !!getStatusExportText
1015

1116
const ExportUserPermissionsToCsv = ({
1217
disabled,
@@ -34,10 +39,15 @@ const ExportUserPermissionsToCsv = ({
3439
const _userData = {
3540
emailId: _user.emailId,
3641
userId: _user.id,
37-
// TODO (v1): Add support for status column
38-
lastLoginTime: _user.lastLoginTime
39-
? `${moment.utc(_user.lastLoginTime).format(Moment12HourExportFormat)} (UTC)`
40-
: 'Never',
42+
...(showStatus
43+
? {
44+
status: getStatusExportText(_user.userStatus, _user.timeToLive),
45+
}
46+
: {}),
47+
lastLoginTime:
48+
_user.lastLoginTime === LAST_LOGIN_TIME_NULL_STATE
49+
? _user.lastLoginTime
50+
: `${moment.utc(_user.lastLoginTime).format(Moment12HourExportFormat)} (UTC)`,
4151
superAdmin: _user.superAdmin,
4252
groups: '-',
4353
project: '-',

0 commit comments

Comments
 (0)