-
Notifications
You must be signed in to change notification settings - Fork 1
Implement Admin management UI #48
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
Merged
Merged
Changes from 5 commits
Commits
Show all changes
23 commits
Select commit
Hold shift + click to select a range
733b249
Add input/display fields to the modal according to the action
NicoBiernat e233aa7
Change user state type to non-optional
NicoBiernat 3be4b3c
Only show password field description on edit action
NicoBiernat ddb2bed
Split UserModal into different modals for Add, Details, Edit and Delete
NicoBiernat 180cc79
Merge branch 'main' into user-role-key-management
NicoBiernat 4932d26
Wrap callbacks in useCallback and refactor
NicoBiernat e2dba42
Merge branch 'main' into user-role-key-management
NicoBiernat c2a342d
Make fields in types required
NicoBiernat 65b4ba7
Add api implementation for user CRUD
NicoBiernat 14d545b
Fix ModelContext use getAllUsers instead of getPublicUsers
NicoBiernat b6510e2
Fetch data and access the API
NicoBiernat e20ba74
Implement remaining API routes in AuthContext
NicoBiernat efe5934
Add views for roles and registration keys
NicoBiernat 097b589
Fix request loop caused by useEffect dependency on user that also set…
NicoBiernat 202ba32
Hide unused options card
NicoBiernat c125b9e
Fix error handling when fetching metrics
NicoBiernat 9c12d88
Add mouse input toggle
NicoBiernat 99a400e
Hide admin area in sidebar from normal users and rename Monitor -> Mo…
NicoBiernat d7633e4
Add roles field to the generated API user type and convert the roles …
NicoBiernat baf9a36
Implement mouse events (and dragging) with window coordinates
NicoBiernat ca03b48
Implement the monitoring view to display the metrics data interactively
NicoBiernat 324a0bc
Handle error when fetching metrics
NicoBiernat c70f765
Merge main
NicoBiernat File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,105 @@ | ||
| import { User } from '@luna/api/auth/types'; | ||
| import { | ||
| Button, | ||
| Checkbox, | ||
| Input, | ||
| Modal, | ||
| ModalBody, | ||
| ModalContent, | ||
| ModalFooter, | ||
| ModalHeader, | ||
| } from '@nextui-org/react'; | ||
| import { useEffect, useState } from 'react'; | ||
|
|
||
| export interface UserAddModalProps { | ||
| show: boolean; | ||
| setShow: (show: boolean) => void; | ||
| } | ||
|
|
||
| export function UserAddModal({ show, setShow }: UserAddModalProps) { | ||
| const [user, setUser] = useState<User>({ username: '' }); | ||
| const [password, setPassword] = useState(''); | ||
|
|
||
| // initialize/reset modal state | ||
| useEffect(() => { | ||
| setUser({ | ||
| username: '', | ||
| }); | ||
| setPassword(''); | ||
| }, [show]); | ||
NicoBiernat marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| const addUser = () => { | ||
| const payload = { | ||
| username: user.username, | ||
| password, | ||
| email: user.email, | ||
| permanent_api_token: user.permanentApiToken, | ||
| }; | ||
| console.log('adding user:', payload); | ||
| // TODO: call POST /users | ||
| // TODO: feedback from the request (success, error) | ||
| onOpenChange(false); | ||
| }; | ||
NicoBiernat marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| const onOpenChange = (isOpen: boolean) => { | ||
| if (!isOpen) { | ||
| setUser({ username: '' }); | ||
| setPassword(''); | ||
| } | ||
NicoBiernat marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| setShow(isOpen); | ||
| }; | ||
NicoBiernat marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| return ( | ||
| <Modal isOpen={show} onOpenChange={onOpenChange}> | ||
| <ModalContent> | ||
| {onClose => ( | ||
| <> | ||
| <ModalHeader>Add User</ModalHeader> | ||
| <ModalBody> | ||
| <Input | ||
| label="Username" | ||
| value={user.username} | ||
| onValueChange={username => { | ||
| if (!user) return; | ||
| setUser({ ...user, username }); | ||
| }} | ||
| /> | ||
| <Input | ||
| type="password" | ||
| label="Password" | ||
| value={password} | ||
| onValueChange={setPassword} | ||
| /> | ||
| <Input | ||
| label="E-Mail" | ||
| value={user.email} | ||
| onValueChange={email => { | ||
| if (!user) return; | ||
| setUser({ ...user, email }); | ||
| }} | ||
| /> | ||
| <Checkbox | ||
| isSelected={user.permanentApiToken} | ||
| onValueChange={permanentApiToken => { | ||
| if (!user) return; | ||
| setUser({ | ||
| ...user, | ||
| permanentApiToken, | ||
| }); | ||
| }} | ||
| > | ||
| Permanent API Token | ||
| </Checkbox> | ||
| </ModalBody> | ||
| <ModalFooter> | ||
| <Button color="success" onPress={addUser}> | ||
| Add | ||
| </Button> | ||
| <Button onPress={onClose}>Cancel</Button> | ||
| </ModalFooter> | ||
| </> | ||
| )} | ||
| </ModalContent> | ||
| </Modal> | ||
| ); | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,149 @@ | ||
| import { | ||
| newUninitializedUser, | ||
| RegistrationKey, | ||
| Role, | ||
| User, | ||
| } from '@luna/api/auth/types'; | ||
| import { | ||
| Button, | ||
| Checkbox, | ||
| Input, | ||
| Modal, | ||
| ModalBody, | ||
| ModalContent, | ||
| ModalFooter, | ||
| ModalHeader, | ||
| } from '@nextui-org/react'; | ||
| import { useEffect, useState } from 'react'; | ||
|
|
||
| export interface UserDeleteModalProps { | ||
| id: number; | ||
| show: boolean; | ||
| setShow: (show: boolean) => void; | ||
| } | ||
|
|
||
| export function UserDeleteModal({ id, show, setShow }: UserDeleteModalProps) { | ||
| const [user, setUser] = useState<User>(newUninitializedUser()); | ||
|
|
||
| // initialize modal state | ||
| useEffect(() => { | ||
| // only initialize when the modal is shown | ||
| if (!show) return; | ||
|
|
||
| // TODO: remove test data and query the API | ||
| const now = new Date(); | ||
| // TODO: call GET /users/<id>/roles | ||
| const roles: Role[] = [ | ||
| { | ||
| id: 1, | ||
| name: 'Testrole', | ||
| createdAt: now, | ||
| updatedAt: now, | ||
| }, | ||
| ]; | ||
| // TODO: call GET /users/<id> | ||
| const registrationKey: RegistrationKey = { | ||
| id: 1, | ||
| key: 'Test-Registration-Key', | ||
| description: 'Test-Registration-Key for testing purposes', | ||
| createdAt: now, | ||
| updatedAt: now, | ||
| expiresAt: now, | ||
| permanent: false, | ||
| }; | ||
| const user: User = { | ||
| username: 'Testuser', | ||
| email: 'test@example.com', | ||
| roles, | ||
| createdAt: now, | ||
| updatedAt: now, | ||
| lastSeen: now, | ||
| permanentApiToken: false, | ||
| registrationKey, | ||
| }; | ||
|
|
||
| setUser(user); | ||
| }, [id, show]); | ||
|
|
||
| const deleteUser = () => { | ||
NicoBiernat marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| console.log('deleting user with id', id); | ||
| // TODO: call DELETE /users/<id> | ||
| // TODO: feedback from the request (success, error) | ||
| onOpenChange(false); | ||
| }; | ||
|
|
||
| const onOpenChange = (isOpen: boolean) => { | ||
| if (!isOpen) { | ||
| setUser(newUninitializedUser()); | ||
| } | ||
| setShow(isOpen); | ||
| }; | ||
|
|
||
| return ( | ||
| <Modal isOpen={show} onOpenChange={onOpenChange}> | ||
| <ModalContent> | ||
| {onClose => ( | ||
| <> | ||
| <ModalHeader>Delete User</ModalHeader> | ||
| <ModalBody> | ||
| <Input label="ID" value={id.toString()} isDisabled /> | ||
|
|
||
| <Input | ||
| label="Username" | ||
| value={user.username} | ||
| onValueChange={username => { | ||
| if (!user) return; | ||
| setUser({ ...user, username }); | ||
| }} | ||
| isDisabled | ||
| /> | ||
| <Input | ||
| label="E-Mail" | ||
| value={user.email} | ||
| onValueChange={email => { | ||
| if (!user) return; | ||
| setUser({ ...user, email }); | ||
| }} | ||
| isDisabled | ||
| /> | ||
| <Input | ||
| label="Created At" | ||
| value={user.createdAt?.toLocaleString()} | ||
| isDisabled | ||
| /> | ||
| <Input | ||
| label="Updated At" | ||
| value={user.updatedAt?.toLocaleString()} | ||
| isDisabled | ||
| /> | ||
| <Input | ||
| label="Last Login" | ||
| value={user.lastSeen?.toLocaleString()} | ||
| isDisabled | ||
| /> | ||
| <Checkbox | ||
| isSelected={user.permanentApiToken} | ||
| onValueChange={permanentApiToken => { | ||
| if (!user) return; | ||
| setUser({ | ||
| ...user, | ||
| permanentApiToken, | ||
| }); | ||
| }} | ||
| isDisabled | ||
| > | ||
| Permanent API Token | ||
| </Checkbox> | ||
| </ModalBody> | ||
| <ModalFooter> | ||
| <Button color="danger" onPress={deleteUser}> | ||
| Delete | ||
| </Button> | ||
| <Button onPress={onClose}>Cancel</Button> | ||
| </ModalFooter> | ||
| </> | ||
| )} | ||
| </ModalContent> | ||
| </Modal> | ||
| ); | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.