Skip to content

Commit

Permalink
refactor: rename dialog hooks and reorganize file structure
Browse files Browse the repository at this point in the history
- Rename dialog hooks to use kebab-case filenames
- Remove nested index files for dialog hooks
- Simplify export structure for dialog hooks

fix: standardize dialog content width and error text classes

- Remove `w-full` class from Dialog.Content components
- Reorder error text classes for consistency across user management dialogs

fix: adjust user dialog UI details

- Modify info icon positioning in create user dialog
- Reorder error text classes for consistency
- Use useEffect to reset form values in edit user dialog

refactor: remove form components from user management dialogs

- Inline dialog form logic directly into dialog components
- Remove separate form components for create, edit, delete, reset password, and remove admin dialogs
- Simplify dialog structure by consolidating form and dialog logic
- Update locales to support new dialog translations

fixes dialogs width

decapitalize

fix cancels buttons

refactor: standardize import paths in user management components

- Replace relative imports with absolute paths using @/ prefix
- Maintain relative imports in index.ts files
- Update import paths in dialog components and providers

added locales

fixes

added empty state

added error state

added skeleton and nodata

refactor dialogs

added state provider

caption props

added no search results state

paddings refactor

remove unnecesary props drilling

remove classes sorting

refactor remove unnecessary props drilling

fix-margins

first versions of modals

replace text with span

change eslint rule due to conflict between prettier and eslint, prettier already sort classnames

Adds promisifyMutation helper to simplify mutation handling
Updates user management handlers to use the helper
Adds proper typing for handlers using IDataHandlers interface
Removes duplicate type definitions

added search query

make pagination using usePaginationQueryStateWithStore

fixes code-review: remove onErrors callbacks

fix enter

fix pathes

refactoring dialogs

refactoring types

commit: refactor: use store provider for user management hooks
This commit refactors the user management page to use a centralized store provider by:
Creating UserManagementStoreProvider to manage shared hooks
Removing hook props drilling through components
Accessing hooks via useUserManagementStore hook in child components
Splitting UserManagementPage into container and content components
This change improves code organization and reduces prop drilling while maintaining existing functionality.

commit: refactor: move dialog context to providers directory
This commit reorganizes the dialog-related code by:
Moving DialogsProvider from context/ to providers/ directory
Updating import paths across components to use the new location
3. Removing unused context files and types
Consolidating dialog-related code for better maintainability
This is a structural change that improves code organization while maintaining existing functionality.

remove redundant index from dialog

commit: refactor: migrate dialog state management to UI layer
The commit refactors the user management dialog state handling by:
Moving dialog state management from container to UI layer using DialogsProvider
Converting mutation handlers to return Promises for proper async handling
Removing redundant dialog state management code from container
Consolidating error and loading states into dedicated objects
Moving EActiveTab enum to UI package for better organization
This change improves separation of concerns by keeping UI state management in the UI layer while maintaining the same functionality.

refactor: reorganize validation schemas and types

- Move Zod schemas to dedicated schema files
- Update type definitions to use schema inference
- Fix import paths to use absolute imports
- Remove duplicate schema definitions from components
- Centralize types in dedicated type files

refactor(user-management): reorganize dialogs structure

- Move all dialogs to dedicated folders with proper structure
- Add types and index files for each dialog
- Update imports and exports
- Add new translations for empty state
- Improve code organization in UserManagementPage

first version of filters and sorting

remove unnecessary fragment

added tabs

fixes after design review
  • Loading branch information
athens-server committed Jan 31, 2025
1 parent ae80ed0 commit 9d86228
Show file tree
Hide file tree
Showing 77 changed files with 1,523 additions and 793 deletions.
2 changes: 0 additions & 2 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,8 @@
"import/no-unresolved": "off",
"react/prop-types": "off",
"react/react-in-jsx-scope": "off",

"jsx-a11y/click-events-have-key-events": "warn",
"jsx-a11y/no-autofocus": "off",

"@typescript-eslint/no-unused-vars": [
"error",
{
Expand Down
195 changes: 73 additions & 122 deletions apps/gitness/src/pages-v2/user-management/user-management-container.tsx
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'

Expand All @@ -9,65 +9,32 @@ import {
useAdminUpdateUserMutation,
useUpdateUserAdminMutation
} from '@harnessio/code-service-client'
import {
AdminDialog,
CreateUserDialog,
DeleteUserDialog,
DialogLabels,
EditUserDialog,
ResetPasswordDialog,
UserManagementPage,
UsersProps
} from '@harnessio/ui/views'

import { parseAsInteger, useQueryState } from '../../framework/hooks/useQueryState'
import { IDataHandlers, UserManagementPage } from '@harnessio/ui/views'

import { useQueryState } from '../../framework/hooks/useQueryState'
import usePaginationQueryStateWithStore from '../../hooks/use-pagination-query-state-with-store'
import { useTranslationStore } from '../../i18n/stores/i18n-store'
import { generateAlphaNumericHash } from '../pull-request/pull-request-utils'
import { useAdminListUsersStore } from './stores/admin-list-store'
import { promisifyMutation } from './utils/promisify-mutation'

export const UserManagementPageContainer = () => {
const [queryPage, setQueryPage] = useQueryState('page', parseAsInteger.withDefault(1))
const { setUsers, setTotalPages, setPage, page, password, setUser, setPassword, setGeteneratePassword } =
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
}
}
const { setUsers, setTotalPages, setPage, page, password } = useAdminListUsersStore()

const { data: { body: userData, headers } = {} } = useAdminListUsersQuery({
const [query, setQuery] = useQueryState('query')
const { queryPage } = usePaginationQueryStateWithStore({ page, setPage })

const {
isFetching,
error,
data: { body: userData, headers } = {}
} = useAdminListUsersQuery({
queryParams: {
page: queryPage
page: queryPage,
// TODO: add search functionality by query parameter
//@ts-expect-error - query is not typed
query: query ?? ''
}
})

Expand All @@ -80,45 +47,41 @@ export const UserManagementPageContainer = () => {
}
}, [userData, setUsers, setTotalPages, headers])

useEffect(() => {
setQueryPage(page)
}, [queryPage, page, setPage])

const { mutate: updateUser, isLoading: isUpdatingUser } = useAdminUpdateUserMutation(
const {
mutate: updateUser,
isLoading: isUpdatingUser,
error: updateUserError
} = useAdminUpdateUserMutation(
{},
{
onSuccess: () => {
setEditUserDialogOpen(false)
queryClient.invalidateQueries({ queryKey: ['adminListUsers'] })
},
onError: error => {
console.error(error)
}
}
)

const { mutate: deleteUser, isLoading: isDeletingUser } = useAdminDeleteUserMutation(
const {
mutate: deleteUser,
isLoading: isDeletingUser,
error: deleteUserError
} = useAdminDeleteUserMutation(
{},
{
onSuccess: () => {
setDeleteUserDialogOpen(false)
queryClient.invalidateQueries({ queryKey: ['adminListUsers'] })
},
onError: error => {
console.error(error)
}
}
)

const { mutate: updateUserAdmin, isLoading: isUpdatingUserAdmin } = useUpdateUserAdminMutation(
const {
mutate: updateUserAdmin,
isLoading: isUpdatingUserAdmin,
error: updateUserAdminError
} = useUpdateUserAdminMutation(
{},
{
onSuccess: () => {
setAdminDialogOpen(false)
queryClient.invalidateQueries({ queryKey: ['adminListUsers'] })
},
onError: error => {
console.error(error)
}
}
)
Expand All @@ -131,18 +94,13 @@ export const UserManagementPageContainer = () => {
{},
{
onSuccess: () => {
setCreateUserDialogOpen(false)
setResetPasswordDialogOpen(true)
queryClient.invalidateQueries({ queryKey: ['adminListUsers'] })
},
onError: error => {
console.error(error)
}
}
)

const handleCreateUser = (data: { uid: string; email: string; display_name: string }) => {
createUser({
const handleCreateUser: IDataHandlers['handleCreateUser'] = data => {
return promisifyMutation(createUser, {
body: {
uid: data.uid,
email: data.email,
Expand All @@ -152,8 +110,8 @@ export const UserManagementPageContainer = () => {
})
}

const handleUpdateUser = (data: { email: string; displayName: string; userID: string }) => {
updateUser({
const handleUpdateUser: IDataHandlers['handleUpdateUser'] = data => {
return promisifyMutation(updateUser, {
user_uid: data.userID,
body: {
email: data.email,
Expand All @@ -162,71 +120,64 @@ export const UserManagementPageContainer = () => {
})
}

const handleDeleteUser = (userUid: string) => {
deleteUser({
const handleDeleteUser: IDataHandlers['handleDeleteUser'] = userUid => {
return promisifyMutation(deleteUser, {
user_uid: userUid
})
}

const handleUpdateUserAdmin = (userUid: string, isAdmin: boolean) => {
updateUserAdmin({
const handleUpdateUserAdmin: IDataHandlers['handleUpdateUserAdmin'] = (userUid, isAdmin) => {
return promisifyMutation(updateUserAdmin, {
user_uid: userUid,
body: {
admin: isAdmin
}
})
}

const handleUpdatePassword = (userId: string) => {
updateUser({
const handleUpdatePassword: IDataHandlers['handleUpdatePassword'] = userId => {
return promisifyMutation(updateUser, {
user_uid: userId,
body: {
password: password
}
})
}

const handlers = {
handleUpdateUser,
handleDeleteUser,
handleUpdateUserAdmin,
handleUpdatePassword,
handleCreateUser
}

const loadingStates = {
isFetchingUsers: isFetching,
isUpdatingUser,
isDeletingUser,
isUpdatingUserAdmin,
isCreatingUser
}

const errorStates = {
fetchUsersError: error?.message?.toString() ?? '',
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}
searchQuery={query}
setSearchQuery={setQuery}
/>
</>
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export type MutationFn<T> = (params: T, options: { onSuccess: () => void; onError: (error: any) => void }) => void

export const promisifyMutation = <T>(mutation: MutationFn<T>, params: T): Promise<void> => {
return new Promise<void>((resolve, reject) => {
mutation(params, {
onSuccess: () => resolve(),
onError: error => reject(error)
})
})
}
Loading

0 comments on commit 9d86228

Please sign in to comment.