-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
16 changed files
with
609 additions
and
33 deletions.
There are no files selected for viewing
This file contains 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 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 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,121 @@ | ||
| import React from 'react'; | ||
| import { Button, Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap'; | ||
|
|
||
| import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; | ||
| import { faTrash, faExclamationTriangle } from '@fortawesome/free-solid-svg-icons'; | ||
|
|
||
| import Translate from '../../i18n/components/translate'; | ||
| import { useCurrentUser } from '../../core/user/UserContext'; | ||
|
|
||
| export default function UserManagement({ users, roles, onDelete, onSetRole }) { | ||
|
|
||
| const setUserRole = (user, role) => onSetRole(user, role); | ||
|
|
||
| const currentUser = useCurrentUser(); | ||
|
|
||
| const [modal, setModal] = React.useState(false); | ||
|
|
||
| const toggle = () => setModal(!modal); | ||
|
|
||
| const [deleting, setDeleting] = React.useState(null); | ||
|
|
||
| const deleteUser = (id) => { | ||
| onDelete(deleting); | ||
| setDeleting(null); | ||
| } | ||
|
|
||
| return ( | ||
| <div className="table-responsive mt-3 provider-list"> | ||
| <table className="table table-striped w-100 table-hover"> | ||
| <thead> | ||
| <tr> | ||
| <th scope="col"><Translate value="label.user-id">UserId</Translate></th> | ||
| <th scope="col" ><Translate value="label.name">Name</Translate></th> | ||
| <th scope="col"><Translate value="label.email">Email</Translate></th> | ||
| <th scope="col" ><Translate value="label.role">Role</Translate></th> | ||
| <th scope="col"><Translate value="label.delete">Delete?</Translate></th> | ||
| </tr> | ||
| </thead> | ||
| <tbody> | ||
| {users.map((user, idx) => | ||
| <tr key={idx}> | ||
| <th>{ user.username }</th> | ||
| <td>{ user.firstName } { user.lastName }</td> | ||
| <td>{ user.emailAddress }</td> | ||
| <td> | ||
| <label htmlFor={`role-${user.username}`} className="sr-only"><Translate value="action.user-role">User role</Translate></label> | ||
| <select | ||
| id={`role-${user.username}`} | ||
| name={`role-${user.username}`} | ||
| model="user.role" | ||
| className="form-control" | ||
| onChange={(event) => setUserRole(user, event.target.value) } | ||
| disabled={currentUser.username === user.username}> | ||
| { roles.map((role, ridx) => ( | ||
| <option key={role} value={role}>{ role }</option> | ||
| ))} | ||
|
|
||
| </select> | ||
| </td> | ||
| <td> | ||
| {currentUser.username !== user.username && | ||
| <button className="btn btn-link text-danger" onClick={() => setDeleting(user.username) }> | ||
| <span className="sr-only"> | ||
| <Translate value="label.delete-user">Delete User</Translate> | ||
| </span> | ||
| <FontAwesomeIcon icon={faTrash} /> | ||
| </button> | ||
| } | ||
| </td> | ||
| </tr> | ||
| )} | ||
| </tbody> | ||
| </table> | ||
| <Modal isOpen={!!deleting} toggle={() => setDeleting(null)}> | ||
| <ModalHeader toggle={toggle}><Translate value="message.delete-user-title">Delete User?</Translate></ModalHeader> | ||
| <ModalBody className="d-flex align-content-center"> | ||
| <FontAwesomeIcon className="text-danger mr-4" size="4x" icon={faExclamationTriangle} /> | ||
| <p className="text-danger font-weight-bold mb-0"> | ||
| <Translate value="message.delete-user-body">You are requesting to delete a user. If you complete this process the user will be removed. This cannot be undone. Do you wish to continue?</Translate> | ||
| </p> | ||
| </ModalBody> | ||
| <ModalFooter> | ||
| <Button color="danger" onClick={() => deleteUser(deleting)}> | ||
| <Translate value="action.delete">Delete</Translate> | ||
| </Button>{' '} | ||
| <Button color="secondary" onClick={() => setDeleting(null)}> | ||
| <Translate value="action.cancel">Cancel</Translate> | ||
| </Button> | ||
| </ModalFooter> | ||
| </Modal> | ||
| </div> | ||
| ); | ||
| } | ||
|
|
||
| /* | ||
| <tr *ngFor="let user of users$ | async"> | ||
| <th>{{ user.username }}</th> | ||
| <td>{{ user.firstName }} {{ user.lastName }}</td> | ||
| <td>{{ user.emailAddress }}</td> | ||
| <td> | ||
| <label [for]="'role-' + user.username" | ||
| class="sr-only"><translate-i18n key="action.user-role">User role</translate-i18n></label> | ||
| <select | ||
| [id]="'role-' + user.username" | ||
| [name]="'role-' + user.username" | ||
| [ngModel]="user.role" | ||
| class="form-control" | ||
| (change)="setUserRole(user, $event.target.value)" | ||
| [disabled]="currentUser.username === user.username"> | ||
| <option *ngFor="let role of roles$ | async" [value]="role">{{ role }}</option> | ||
| </select> | ||
| </td> | ||
| <td> | ||
| <button class="btn btn-link" (click)="deleteUser(user.username)" *ngIf="!(currentUser.username === user.username)"> | ||
| <span class="sr-only"> | ||
| <translate-i18n key="label.delete-user">Delete User</translate-i18n> | ||
| </span> | ||
| <i class="fa fa-trash fa-lg text-danger"></i> | ||
| </button> | ||
| </td> | ||
| </tr>*/ |
This file contains 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,8 @@ | ||
| import React from 'react'; | ||
| import { format } from 'date-fns'; | ||
|
|
||
| export default function FormattedDate ({ date }) { | ||
| const formatted = React.useMemo(() => format(new Date(date), 'MMM Lo, Y'), [date]); | ||
|
|
||
| return (<>{ formatted }</>); | ||
| } |
This file contains 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,38 @@ | ||
| import React from "react"; | ||
| import useFetch from 'use-http'; | ||
| import API_BASE_PATH from '../../App.constant'; | ||
|
|
||
| const UserContext = React.createContext(); | ||
|
|
||
| const { Provider, Consumer } = UserContext; | ||
|
|
||
| const path = '/admin/users/current'; | ||
|
|
||
| /*eslint-disable react-hooks/exhaustive-deps*/ | ||
| function UserProvider({ children }) { | ||
|
|
||
| const { get, response } = useFetch(`${API_BASE_PATH}`, { | ||
| cacheLife: 10000, | ||
| cachePolicy: 'cache-first' | ||
| }); | ||
|
|
||
| React.useEffect(() => { loadUser() }, []); | ||
|
|
||
| async function loadUser() { | ||
| const user = await get(`${path}`); | ||
| if (response.ok) setUser(user); | ||
| } | ||
|
|
||
| const [user, setUser] = React.useState({}); | ||
| return ( | ||
| <Provider value={user}>{children}</Provider> | ||
| ); | ||
| } | ||
|
|
||
| function useCurrentUser() { | ||
| const context = React.useContext(UserContext); | ||
| return context; | ||
| } | ||
|
|
||
|
|
||
| export { UserContext, UserProvider, Consumer as UserConsumer, useCurrentUser }; |
This file contains 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,43 @@ | ||
| import React from 'react'; | ||
| import useFetch from 'use-http'; | ||
| import UserManagement from '../../admin/container/UserManagement'; | ||
| import API_BASE_PATH from '../../App.constant'; | ||
|
|
||
| import Translate from '../../i18n/components/translate'; | ||
|
|
||
| export function ActionsTab() { | ||
|
|
||
| return ( | ||
| <> | ||
| <section className="section"> | ||
| <div className="section-body border border-top-0 border-primary"> | ||
| <div className="section-header bg-primary p-2 text-light"> | ||
| <div className="row justify-content-between"> | ||
| <div className="col-12"> | ||
| <span className="lead"><Translate value="label.enable-metadata-sources">Enable Metadata Sources</Translate></span> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| <div className="p-3"> | ||
| {/*<enable-metadata></enable-metadata>*/} | ||
| </div> | ||
| </div> | ||
| </section> | ||
| <section className="section"> | ||
| <div className="section-body border border-top-0 border-primary"> | ||
| <div className="section-header bg-primary p-2 text-light"> | ||
| <div className="row justify-content-between"> | ||
| <div className="col-12"> | ||
| <span className="lead"><Translate value="label.user-access-request">User Access Request</Translate></span> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| {/*<access-request-component></access-request-component>*/} | ||
| </div> | ||
| </section> | ||
| </> | ||
|
|
||
| ); | ||
| } | ||
|
|
||
| export default ActionsTab; |
This file contains 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,70 @@ | ||
| import React from 'react'; | ||
| import useFetch from 'use-http'; | ||
| import UserManagement from '../../admin/container/UserManagement'; | ||
| import API_BASE_PATH from '../../App.constant'; | ||
|
|
||
| import Translate from '../../i18n/components/translate'; | ||
|
|
||
| export function AdminTab () { | ||
|
|
||
| const [users, setUsers] = React.useState([]); | ||
|
|
||
| const { get, patch, del, response } = useFetch(`${API_BASE_PATH}`, {}) | ||
|
|
||
| async function loadUsers() { | ||
| const users = await get('/admin/users') | ||
| if (response.ok) { | ||
| setUsers(users); | ||
| } | ||
| } | ||
| const [roles, setRoles] = React.useState([]); | ||
|
|
||
| async function loadRoles() { | ||
| const roles = await get('/supportedRoles') | ||
| if (response.ok) { | ||
| setRoles(roles); | ||
| } | ||
| } | ||
|
|
||
| async function setUserRole (user, role) { | ||
| const update = await patch(`/admin/users/${user.username}`, { | ||
| ...user, | ||
| role | ||
| }); | ||
| if (response.ok) { | ||
| loadUsers(); | ||
| } | ||
| } | ||
|
|
||
| async function deleteUser(id) { | ||
| const removal = await del(`/admin/users/${id}`); | ||
| if (response.ok) { | ||
| loadUsers(); | ||
| } | ||
| } | ||
|
|
||
| React.useEffect(() => { | ||
| loadUsers(); | ||
| loadRoles(); | ||
| }, []); | ||
|
|
||
|
|
||
| return ( | ||
| <section className="section"> | ||
| <div className="section-body border border-top-0 border-primary"> | ||
| <div className="section-header bg-primary p-2 text-light"> | ||
| <div className="row justify-content-between"> | ||
| <div className="col-12"> | ||
| <span className="lead"><Translate value="label.user-maintenance">User Maintenance</Translate></span> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| <div className="p-3"> | ||
| <UserManagement users={users} roles={roles} onDelete={deleteUser} onSetRole={setUserRole} /> | ||
| </div> | ||
| </div> | ||
| </section> | ||
| ); | ||
| } | ||
|
|
||
| export default AdminTab; |
Oops, something went wrong.