-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Users management review #18
Changes from all commits
3176d15
f303549
4bb1853
61a148e
68c6db2
2218a23
4a3fcee
ba97acd
415377a
f85a00a
0f2f256
1fb8e1b
fb05ddf
a4d2ed8
87fdd41
6232e30
7944e6b
a688b03
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { RepoEmptyView } from '@harnessio/ui/views' | ||
|
||
export const RepoEmpty = () => { | ||
return ( | ||
<RepoEmptyView | ||
httpUrl="https://github.com/mock-repo" | ||
repoName="mock-repo" | ||
projName="mock-project" | ||
sshUrl="[email protected]:mock-repo.git" | ||
/> | ||
) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
import { create } from 'zustand' | ||
|
||
import { IAdminListUsersStore, UsersProps } from '@harnessio/ui/views' | ||
import { EActiveTab, IAdminListUsersStore, UsersProps } from '@harnessio/ui/views' | ||
|
||
import { PageResponseHeader } from '../../../types' | ||
|
||
|
@@ -10,7 +10,9 @@ export const useAdminListUsersStore = create<IAdminListUsersStore>(set => ({ | |
page: 1, | ||
password: null, | ||
user: null, | ||
searchQuery: '', | ||
generatePassword: false, | ||
activeTab: EActiveTab.ACTIVE, | ||
setPage: page => | ||
set({ | ||
page | ||
|
@@ -41,5 +43,15 @@ export const useAdminListUsersStore = create<IAdminListUsersStore>(set => ({ | |
set({ | ||
generatePassword | ||
}) | ||
}, | ||
setSearchQuery: (searchQuery: string) => { | ||
set({ | ||
searchQuery | ||
}) | ||
}, | ||
setActiveTab: (activeTab: EActiveTab) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we don't need to keep tab in AdminListUsersStore |
||
set({ | ||
activeTab | ||
}) | ||
} | ||
})) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
import { useEffect, useState } from 'react' | ||
import { useEffect } from 'react' | ||
|
||
import { useQueryClient } from '@tanstack/react-query' | ||
|
||
|
@@ -9,62 +9,18 @@ import { | |
useAdminUpdateUserMutation, | ||
useUpdateUserAdminMutation | ||
} from '@harnessio/code-service-client' | ||
import { | ||
AdminDialog, | ||
CreateUserDialog, | ||
DeleteUserDialog, | ||
DialogLabels, | ||
EditUserDialog, | ||
ResetPasswordDialog, | ||
UserManagementPage, | ||
UsersProps | ||
} from '@harnessio/ui/views' | ||
import { UserManagementPage } from '@harnessio/ui/views' | ||
|
||
import { parseAsInteger, useQueryState } from '../../framework/hooks/useQueryState' | ||
import { useTranslationStore } from '../../i18n/stores/i18n-store' | ||
import { generateAlphaNumericHash } from '../pull-request/pull-request-utils' | ||
import { useAdminListUsersStore } from './stores/admin-list-store' | ||
|
||
export const UserManagementPageContainer = () => { | ||
const [queryPage, setQueryPage] = useQueryState('page', parseAsInteger.withDefault(1)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. for queryPage let's use |
||
const { setUsers, setTotalPages, setPage, page, password, setUser, setPassword, setGeteneratePassword } = | ||
useAdminListUsersStore() | ||
const { setUsers, setTotalPages, setPage, page, password } = useAdminListUsersStore() | ||
const queryClient = useQueryClient() | ||
|
||
const [isDeleteUserDialogOpen, setDeleteUserDialogOpen] = useState(false) | ||
const [isEditUserDialogOpen, setEditUserDialogOpen] = useState(false) | ||
const [isAdminDialogOpen, setAdminDialogOpen] = useState(false) | ||
const [isResetPasswordDialogOpen, setResetPasswordDialogOpen] = useState(false) | ||
const [isCreateUserDialogOpen, setCreateUserDialogOpen] = useState(false) | ||
|
||
const handleDialogOpen = (user: UsersProps | null, dialogTypeLabel: string) => { | ||
if (user) setUser(user) | ||
|
||
switch (dialogTypeLabel) { | ||
case DialogLabels.DELETE_USER: | ||
setDeleteUserDialogOpen(true) | ||
break | ||
case DialogLabels.EDIT_USER: | ||
setEditUserDialogOpen(true) | ||
break | ||
case DialogLabels.TOGGLE_ADMIN: | ||
setAdminDialogOpen(true) | ||
break | ||
case DialogLabels.RESET_PASSWORD: | ||
setGeteneratePassword(false) | ||
setPassword(generateAlphaNumericHash(10)) | ||
setResetPasswordDialogOpen(true) | ||
break | ||
case DialogLabels.CREATE_USER: | ||
setPassword(generateAlphaNumericHash(10)) | ||
setCreateUserDialogOpen(true) | ||
setGeteneratePassword(true) | ||
break | ||
default: | ||
break | ||
} | ||
} | ||
|
||
// TODO: add search functionality by query parameter | ||
const { data: { body: userData, headers } = {} } = useAdminListUsersQuery({ | ||
queryParams: { | ||
page: queryPage | ||
|
@@ -82,13 +38,16 @@ export const UserManagementPageContainer = () => { | |
|
||
useEffect(() => { | ||
setQueryPage(page) | ||
}, [queryPage, page, setPage]) | ||
}, [queryPage, page, setPage, setQueryPage]) | ||
|
||
const { mutate: updateUser, isLoading: isUpdatingUser } = useAdminUpdateUserMutation( | ||
const { | ||
mutate: updateUser, | ||
isLoading: isUpdatingUser, | ||
error: updateUserError | ||
} = useAdminUpdateUserMutation( | ||
{}, | ||
{ | ||
onSuccess: () => { | ||
setEditUserDialogOpen(false) | ||
queryClient.invalidateQueries({ queryKey: ['adminListUsers'] }) | ||
}, | ||
onError: error => { | ||
|
@@ -97,11 +56,14 @@ export const UserManagementPageContainer = () => { | |
} | ||
) | ||
|
||
const { mutate: deleteUser, isLoading: isDeletingUser } = useAdminDeleteUserMutation( | ||
const { | ||
mutate: deleteUser, | ||
isLoading: isDeletingUser, | ||
error: deleteUserError | ||
} = useAdminDeleteUserMutation( | ||
{}, | ||
{ | ||
onSuccess: () => { | ||
setDeleteUserDialogOpen(false) | ||
queryClient.invalidateQueries({ queryKey: ['adminListUsers'] }) | ||
}, | ||
onError: error => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if u use error from query hook, let's remove onError callback |
||
|
@@ -110,11 +72,14 @@ export const UserManagementPageContainer = () => { | |
} | ||
) | ||
|
||
const { mutate: updateUserAdmin, isLoading: isUpdatingUserAdmin } = useUpdateUserAdminMutation( | ||
const { | ||
mutate: updateUserAdmin, | ||
isLoading: isUpdatingUserAdmin, | ||
error: updateUserAdminError | ||
} = useUpdateUserAdminMutation( | ||
{}, | ||
{ | ||
onSuccess: () => { | ||
setAdminDialogOpen(false) | ||
queryClient.invalidateQueries({ queryKey: ['adminListUsers'] }) | ||
}, | ||
onError: error => { | ||
|
@@ -131,8 +96,6 @@ export const UserManagementPageContainer = () => { | |
{}, | ||
{ | ||
onSuccess: () => { | ||
setCreateUserDialogOpen(false) | ||
setResetPasswordDialogOpen(true) | ||
queryClient.invalidateQueries({ queryKey: ['adminListUsers'] }) | ||
}, | ||
onError: error => { | ||
|
@@ -142,7 +105,7 @@ export const UserManagementPageContainer = () => { | |
) | ||
|
||
const handleCreateUser = (data: { uid: string; email: string; display_name: string }) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's create separate types for data in the UI so that we don't have to define them repeatedly in different places. This way, both in component props and here, we can simply specify the type. |
||
createUser({ | ||
return createUser({ | ||
body: { | ||
uid: data.uid, | ||
email: data.email, | ||
|
@@ -153,7 +116,7 @@ export const UserManagementPageContainer = () => { | |
} | ||
|
||
const handleUpdateUser = (data: { email: string; displayName: string; userID: string }) => { | ||
updateUser({ | ||
return updateUser({ | ||
user_uid: data.userID, | ||
body: { | ||
email: data.email, | ||
|
@@ -163,13 +126,13 @@ export const UserManagementPageContainer = () => { | |
} | ||
|
||
const handleDeleteUser = (userUid: string) => { | ||
deleteUser({ | ||
return deleteUser({ | ||
user_uid: userUid | ||
}) | ||
} | ||
|
||
const handleUpdateUserAdmin = (userUid: string, isAdmin: boolean) => { | ||
updateUserAdmin({ | ||
return updateUserAdmin({ | ||
user_uid: userUid, | ||
body: { | ||
admin: isAdmin | ||
|
@@ -178,55 +141,44 @@ export const UserManagementPageContainer = () => { | |
} | ||
|
||
const handleUpdatePassword = (userId: string) => { | ||
updateUser({ | ||
return updateUser({ | ||
user_uid: userId, | ||
body: { | ||
password: password | ||
} | ||
}) | ||
} | ||
|
||
const handlers = { | ||
handleUpdateUser, | ||
handleDeleteUser, | ||
handleUpdateUserAdmin, | ||
handleUpdatePassword, | ||
handleCreateUser | ||
} | ||
|
||
const loadingStates = { | ||
isUpdatingUser, | ||
isDeletingUser, | ||
isUpdatingUserAdmin, | ||
isCreatingUser | ||
} | ||
|
||
const errorStates = { | ||
updateUserError: updateUserError?.message?.toString() ?? '', | ||
deleteUserError: deleteUserError?.message?.toString() ?? '', | ||
updateUserAdminError: updateUserAdminError?.message?.toString() ?? '', | ||
createUserError: createUserError?.message?.toString() ?? '' | ||
} | ||
|
||
return ( | ||
<> | ||
<UserManagementPage | ||
useAdminListUsersStore={useAdminListUsersStore} | ||
useTranslationStore={useTranslationStore} | ||
handleDialogOpen={handleDialogOpen} | ||
/> | ||
|
||
<DeleteUserDialog | ||
open={isDeleteUserDialogOpen} | ||
useAdminListUsersStore={useAdminListUsersStore} | ||
onClose={() => setDeleteUserDialogOpen(false)} | ||
isDeleting={isDeletingUser} | ||
handleDeleteUser={handleDeleteUser} | ||
/> | ||
<EditUserDialog | ||
open={isEditUserDialogOpen} | ||
useAdminListUsersStore={useAdminListUsersStore} | ||
isSubmitting={isUpdatingUser} | ||
onClose={() => setEditUserDialogOpen(false)} | ||
handleUpdateUser={handleUpdateUser} | ||
/> | ||
<AdminDialog | ||
open={isAdminDialogOpen} | ||
useAdminListUsersStore={useAdminListUsersStore} | ||
onClose={() => setAdminDialogOpen(false)} | ||
isLoading={isUpdatingUserAdmin} | ||
updateUserAdmin={handleUpdateUserAdmin} | ||
/> | ||
<ResetPasswordDialog | ||
open={isResetPasswordDialogOpen} | ||
useAdminListUsersStore={useAdminListUsersStore} | ||
onClose={() => setResetPasswordDialogOpen(false)} | ||
handleUpdatePassword={handleUpdatePassword} | ||
/> | ||
<CreateUserDialog | ||
open={isCreateUserDialogOpen} | ||
onClose={() => setCreateUserDialogOpen(false)} | ||
isLoading={isCreatingUser} | ||
apiError={createUserError?.message?.toString() ?? ''} | ||
handleCreateUser={handleCreateUser} | ||
handlers={handlers} | ||
loadingStates={loadingStates} | ||
errorStates={errorStates} | ||
/> | ||
</> | ||
) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we don't need to keep search in AdminListUsersStore