From 5de56256e19b3becf5124ff31fdc3220fa256926 Mon Sep 17 00:00:00 2001 From: Youssef Khedher Date: Tue, 14 Dec 2021 10:36:19 +0100 Subject: [PATCH] feat: RBAC environment role list (#558) * fix: move admin to components and add ProjectRoles route * feat: fetch project roles and create project roles list * fix: add pagination and update tests * update projectRoles folder name Co-authored-by: Fredrik Strand Oseberg --- .../ProjectRolesv1/ProjectRoles.styles.ts | 10 +++ .../admin/ProjectRolesv1/ProjectRoles.tsx | 63 +++++++++++++++++++ .../admin/ProjectRolesv1/RolesList.tsx | 63 +++++++++++++++++++ .../RolesListItem/RoleListItem.styles.ts | 13 ++++ .../RolesListItem/RoleListItem.tsx | 61 ++++++++++++++++++ .../{page => component}/admin/admin-menu.jsx | 19 +++++- .../ApiTokenCreate/ApiTokenCreate.tsx | 16 ++--- .../api-token/ApiTokenCreate/styles.js | 0 .../ApiTokenList/ApiTokenList.styles.ts | 0 .../api-token/ApiTokenList/ApiTokenList.tsx | 28 ++++----- .../api-token/ApiTokenList/secret.jsx | 0 .../{page => component}/admin/api/index.js | 4 +- .../auth/AutoCreateForm/AutoCreateForm.tsx | 0 .../admin/auth/authentication.jsx | 6 +- .../admin/auth/google-auth-container.js | 2 +- .../admin/auth/google-auth.jsx | 4 +- .../{page => component}/admin/auth/index.js | 0 .../admin/auth/oidc-auth-container.js | 0 .../admin/auth/oidc-auth.jsx | 4 +- .../admin/auth/saml-auth-container.js | 2 +- .../admin/auth/saml-auth.jsx | 4 +- .../src/{page => component}/admin/index.js | 0 .../admin/invoice/index.js | 4 +- .../admin/invoice/invoice-container.js | 0 .../admin/invoice/invoice-list.jsx | 8 +-- .../admin/users/AddUser/AddUser.tsx | 2 +- .../users/AddUser/AddUserForm/AddUserForm.jsx | 4 +- .../AddUser/AddUserForm/AddUserForm.styles.js | 0 .../ConfirmUserAdded/ConfirmUserAdded.tsx | 0 .../ConfirmUserEmail.styles.ts | 0 .../ConfirmUserEmail/ConfirmUserEmail.tsx | 2 +- .../ConfirmUserLink/ConfirmUserLink.tsx | 2 +- .../UserInviteLink/UserInviteLink.tsx | 0 .../UserListItem/UserListItem.styles.ts | 0 .../UsersList/UserListItem/UserListItem.tsx | 6 +- .../admin/users/UsersList/UsersList.jsx | 6 +- .../admin/users/UsersList/index.js | 0 .../admin/users/UsersList/loadingData.ts | 0 .../admin/users/change-password-component.jsx | 10 +-- .../admin/users/del-user-component.jsx | 4 +- .../{page => component}/admin/users/index.js | 0 .../admin/users/index.styles.js | 0 .../admin/users/update-user-component.jsx | 2 +- .../{page => component}/admin/users/util.js | 0 .../__snapshots__/routes-test.jsx.snap | 11 ++++ frontend/src/component/menu/routes.js | 20 ++++-- .../useProjectRoles/useProjectRoles.ts | 35 +++++++++++ 47 files changed, 349 insertions(+), 66 deletions(-) create mode 100644 frontend/src/component/admin/ProjectRolesv1/ProjectRoles.styles.ts create mode 100644 frontend/src/component/admin/ProjectRolesv1/ProjectRoles.tsx create mode 100644 frontend/src/component/admin/ProjectRolesv1/RolesList.tsx create mode 100644 frontend/src/component/admin/ProjectRolesv1/RolesListItem/RoleListItem.styles.ts create mode 100644 frontend/src/component/admin/ProjectRolesv1/RolesListItem/RoleListItem.tsx rename frontend/src/{page => component}/admin/admin-menu.jsx (75%) rename frontend/src/component/{ => admin}/api-token/ApiTokenCreate/ApiTokenCreate.tsx (91%) rename frontend/src/component/{ => admin}/api-token/ApiTokenCreate/styles.js (100%) rename frontend/src/component/{ => admin}/api-token/ApiTokenList/ApiTokenList.styles.ts (100%) rename frontend/src/component/{ => admin}/api-token/ApiTokenList/ApiTokenList.tsx (93%) rename frontend/src/component/{ => admin}/api-token/ApiTokenList/secret.jsx (100%) rename frontend/src/{page => component}/admin/api/index.js (79%) rename frontend/src/{page => component}/admin/auth/AutoCreateForm/AutoCreateForm.tsx (100%) rename frontend/src/{page => component}/admin/auth/authentication.jsx (91%) rename frontend/src/{page => component}/admin/auth/google-auth-container.js (78%) rename frontend/src/{page => component}/admin/auth/google-auth.jsx (98%) rename frontend/src/{page => component}/admin/auth/index.js (100%) rename frontend/src/{page => component}/admin/auth/oidc-auth-container.js (100%) rename frontend/src/{page => component}/admin/auth/oidc-auth.jsx (98%) rename frontend/src/{page => component}/admin/auth/saml-auth-container.js (78%) rename frontend/src/{page => component}/admin/auth/saml-auth.jsx (98%) rename frontend/src/{page => component}/admin/index.js (100%) rename frontend/src/{page => component}/admin/invoice/index.js (84%) rename frontend/src/{page => component}/admin/invoice/invoice-container.js (100%) rename frontend/src/{page => component}/admin/invoice/invoice-list.jsx (91%) rename frontend/src/{page => component}/admin/users/AddUser/AddUser.tsx (97%) rename frontend/src/{page => component}/admin/users/AddUser/AddUserForm/AddUserForm.jsx (98%) rename frontend/src/{page => component}/admin/users/AddUser/AddUserForm/AddUserForm.styles.js (100%) rename frontend/src/{page => component}/admin/users/ConfirmUserAdded/ConfirmUserAdded.tsx (100%) rename frontend/src/{page => component}/admin/users/ConfirmUserAdded/ConfirmUserEmail/ConfirmUserEmail.styles.ts (100%) rename frontend/src/{page => component}/admin/users/ConfirmUserAdded/ConfirmUserEmail/ConfirmUserEmail.tsx (95%) rename frontend/src/{page => component}/admin/users/ConfirmUserAdded/ConfirmUserLink/ConfirmUserLink.tsx (96%) rename frontend/src/{page => component}/admin/users/ConfirmUserAdded/ConfirmUserLink/UserInviteLink/UserInviteLink.tsx (100%) rename frontend/src/{page => component}/admin/users/UsersList/UserListItem/UserListItem.styles.ts (100%) rename frontend/src/{page => component}/admin/users/UsersList/UserListItem/UserListItem.tsx (93%) rename frontend/src/{page => component}/admin/users/UsersList/UsersList.jsx (96%) rename frontend/src/{page => component}/admin/users/UsersList/index.js (100%) rename frontend/src/{page => component}/admin/users/UsersList/loadingData.ts (100%) rename frontend/src/{page => component}/admin/users/change-password-component.jsx (91%) rename frontend/src/{page => component}/admin/users/del-user-component.jsx (94%) rename frontend/src/{page => component}/admin/users/index.js (100%) rename frontend/src/{page => component}/admin/users/index.styles.js (100%) rename frontend/src/{page => component}/admin/users/update-user-component.jsx (96%) rename frontend/src/{page => component}/admin/users/util.js (100%) create mode 100644 frontend/src/hooks/api/getters/useProjectRoles/useProjectRoles.ts diff --git a/frontend/src/component/admin/ProjectRolesv1/ProjectRoles.styles.ts b/frontend/src/component/admin/ProjectRolesv1/ProjectRoles.styles.ts new file mode 100644 index 0000000000..6bedaa56e3 --- /dev/null +++ b/frontend/src/component/admin/ProjectRolesv1/ProjectRoles.styles.ts @@ -0,0 +1,10 @@ +import { makeStyles } from '@material-ui/styles'; + +export const useStyles = makeStyles(theme => ({ + rolesListBody: { + paddingBottom: '4rem', + minHeight: '50vh', + position: 'relative', + }, +})); + diff --git a/frontend/src/component/admin/ProjectRolesv1/ProjectRoles.tsx b/frontend/src/component/admin/ProjectRolesv1/ProjectRoles.tsx new file mode 100644 index 0000000000..03464d6bb8 --- /dev/null +++ b/frontend/src/component/admin/ProjectRolesv1/ProjectRoles.tsx @@ -0,0 +1,63 @@ +import { Button } from '@material-ui/core'; +import { Alert } from '@material-ui/lab'; +import { useContext } from 'react'; +import { useHistory } from 'react-router-dom'; +import AccessContext from '../../../contexts/AccessContext'; +import ConditionallyRender from '../../common/ConditionallyRender'; +import HeaderTitle from '../../common/HeaderTitle'; +import PageContent from '../../common/PageContent'; +import { ADMIN } from '../../providers/AccessProvider/permissions'; +import AdminMenu from '../admin-menu'; +import { useStyles } from './ProjectRoles.styles'; +import RolesList from './RolesList'; + +const ProjectRoles = () => { + const { hasAccess } = useContext(AccessContext); + const styles = useStyles(); + const history = useHistory(); + + return ( +
+ + console.log('hi')} + > + New Project role + + } + elseShow={ + + PS! Only admins can add/remove roles. + + } + /> + } + /> + } + > + } + elseShow={ + + You need instance admin to access this section. + + } + /> + +
+ ); +}; + +export default ProjectRoles; diff --git a/frontend/src/component/admin/ProjectRolesv1/RolesList.tsx b/frontend/src/component/admin/ProjectRolesv1/RolesList.tsx new file mode 100644 index 0000000000..fdbda0289f --- /dev/null +++ b/frontend/src/component/admin/ProjectRolesv1/RolesList.tsx @@ -0,0 +1,63 @@ +import { useContext } from 'react'; +import { + Table, + TableBody, + TableCell, + TableHead, + TableRow, +} from '@material-ui/core'; +import AccessContext from '../../../contexts/AccessContext'; +import usePagination from '../../../hooks/usePagination'; +import { ADMIN } from '../../providers/AccessProvider/permissions'; +import PaginateUI from '../../common/PaginateUI/PaginateUI'; +import RoleListItem from './RolesListItem/RoleListItem'; +import useProjectRoles from '../../../hooks/api/getters/useProjectRoles/useProjectRoles'; + +const RolesList = () => { + const { hasAccess } = useContext(AccessContext); + const { roles } = useProjectRoles(); + const { page, pages, nextPage, prevPage, setPageIndex, pageIndex } = + usePagination(roles, 10); + + const renderRoles = () => { + return page.map(role => { + return ( + + ); + }); + }; + + if (!roles) return null; + + return ( +
+ + + + + Project Role + Description + + {hasAccess(ADMIN) ? 'Action' : ''} + + + + {renderRoles()} + +
+
+
+ ); +}; + +export default RolesList; diff --git a/frontend/src/component/admin/ProjectRolesv1/RolesListItem/RoleListItem.styles.ts b/frontend/src/component/admin/ProjectRolesv1/RolesListItem/RoleListItem.styles.ts new file mode 100644 index 0000000000..d6ab74eb03 --- /dev/null +++ b/frontend/src/component/admin/ProjectRolesv1/RolesListItem/RoleListItem.styles.ts @@ -0,0 +1,13 @@ +import { makeStyles } from '@material-ui/core/styles'; + +export const useStyles = makeStyles(theme => ({ + tableRow: { + '&:hover': { + backgroundColor: theme.palette.grey[200], + }, + }, + leftTableCell:{ + textAlign: 'left', + maxWidth: '300px' + } +})); diff --git a/frontend/src/component/admin/ProjectRolesv1/RolesListItem/RoleListItem.tsx b/frontend/src/component/admin/ProjectRolesv1/RolesListItem/RoleListItem.tsx new file mode 100644 index 0000000000..c12b250b1a --- /dev/null +++ b/frontend/src/component/admin/ProjectRolesv1/RolesListItem/RoleListItem.tsx @@ -0,0 +1,61 @@ +import { useStyles } from './RoleListItem.styles'; +import { TableRow, TableCell, Typography } from '@material-ui/core'; +import { Edit, Delete } from '@material-ui/icons'; +import { ADMIN } from '../../../providers/AccessProvider/permissions'; +import SupervisedUserCircleIcon from '@material-ui/icons/SupervisedUserCircle'; +import PermissionIconButton from '../../../common/PermissionIconButton/PermissionIconButton'; + +interface IRoleListItemProps { + key: number; + name: string; + description: string; +} + +const RoleListItem = ({ key, name, description }: IRoleListItemProps) => { + const styles = useStyles(); + + return ( + + + + + + + {name} + + + + + {description} + + + + + { + console.log('hi'); + }} + permission={ADMIN} + > + + + { + console.log('hi'); + }} + permission={ADMIN} + > + + + + + ); +}; + +export default RoleListItem; diff --git a/frontend/src/page/admin/admin-menu.jsx b/frontend/src/component/admin/admin-menu.jsx similarity index 75% rename from frontend/src/page/admin/admin-menu.jsx rename to frontend/src/component/admin/admin-menu.jsx index a513bd9b60..9e90069983 100644 --- a/frontend/src/page/admin/admin-menu.jsx +++ b/frontend/src/component/admin/admin-menu.jsx @@ -19,6 +19,8 @@ const activeNavLinkStyle = { }; function AdminMenu({ history }) { + const SHOW_PROJECT_ROLES = false; + const { location } = history; const { pathname } = location; return ( @@ -36,6 +38,21 @@ function AdminMenu({ history }) { } > + {SHOW_PROJECT_ROLES && ( + + PROJECT ROLES + + } + > + )} + - Single Sign-On + Single Sign-On } > diff --git a/frontend/src/component/api-token/ApiTokenCreate/ApiTokenCreate.tsx b/frontend/src/component/admin/api-token/ApiTokenCreate/ApiTokenCreate.tsx similarity index 91% rename from frontend/src/component/api-token/ApiTokenCreate/ApiTokenCreate.tsx rename to frontend/src/component/admin/api-token/ApiTokenCreate/ApiTokenCreate.tsx index 0624936db1..90bf6abb53 100644 --- a/frontend/src/component/api-token/ApiTokenCreate/ApiTokenCreate.tsx +++ b/frontend/src/component/admin/api-token/ApiTokenCreate/ApiTokenCreate.tsx @@ -1,14 +1,14 @@ import { TextField } from '@material-ui/core'; import classNames from 'classnames'; import React, { useState, useEffect } from 'react'; -import { styles as commonStyles } from '../../../component/common'; -import { IApiTokenCreate } from '../../../hooks/api/actions/useApiTokensApi/useApiTokensApi'; -import useEnvironments from '../../../hooks/api/getters/useEnvironments/useEnvironments'; -import useProjects from '../../../hooks/api/getters/useProjects/useProjects'; -import useUiConfig from '../../../hooks/api/getters/useUiConfig/useUiConfig'; -import ConditionallyRender from '../../common/ConditionallyRender'; -import Dialogue from '../../common/Dialogue'; -import GeneralSelect from '../../common/GeneralSelect/GeneralSelect'; +import { styles as commonStyles } from '../../../common'; +import { IApiTokenCreate } from '../../../../hooks/api/actions/useApiTokensApi/useApiTokensApi'; +import useEnvironments from '../../../../hooks/api/getters/useEnvironments/useEnvironments'; +import useProjects from '../../../../hooks/api/getters/useProjects/useProjects'; +import useUiConfig from '../../../../hooks/api/getters/useUiConfig/useUiConfig'; +import ConditionallyRender from '../../../common/ConditionallyRender'; +import Dialogue from '../../../common/Dialogue'; +import GeneralSelect from '../../../common/GeneralSelect/GeneralSelect'; import { useStyles } from './styles'; diff --git a/frontend/src/component/api-token/ApiTokenCreate/styles.js b/frontend/src/component/admin/api-token/ApiTokenCreate/styles.js similarity index 100% rename from frontend/src/component/api-token/ApiTokenCreate/styles.js rename to frontend/src/component/admin/api-token/ApiTokenCreate/styles.js diff --git a/frontend/src/component/api-token/ApiTokenList/ApiTokenList.styles.ts b/frontend/src/component/admin/api-token/ApiTokenList/ApiTokenList.styles.ts similarity index 100% rename from frontend/src/component/api-token/ApiTokenList/ApiTokenList.styles.ts rename to frontend/src/component/admin/api-token/ApiTokenList/ApiTokenList.styles.ts diff --git a/frontend/src/component/api-token/ApiTokenList/ApiTokenList.tsx b/frontend/src/component/admin/api-token/ApiTokenList/ApiTokenList.tsx similarity index 93% rename from frontend/src/component/api-token/ApiTokenList/ApiTokenList.tsx rename to frontend/src/component/admin/api-token/ApiTokenList/ApiTokenList.tsx index 5d92200787..6d998f2c0a 100644 --- a/frontend/src/component/api-token/ApiTokenList/ApiTokenList.tsx +++ b/frontend/src/component/admin/api-token/ApiTokenList/ApiTokenList.tsx @@ -9,29 +9,29 @@ import { TableHead, TableRow, } from '@material-ui/core'; -import AccessContext from '../../../contexts/AccessContext'; -import useToast from '../../../hooks/useToast'; -import useLoading from '../../../hooks/useLoading'; -import useApiTokens from '../../../hooks/api/getters/useApiTokens/useApiTokens'; -import useUiConfig from '../../../hooks/api/getters/useUiConfig/useUiConfig'; +import AccessContext from '../../../../contexts/AccessContext'; +import useToast from '../../../../hooks/useToast'; +import useLoading from '../../../../hooks/useLoading'; +import useApiTokens from '../../../../hooks/api/getters/useApiTokens/useApiTokens'; +import useUiConfig from '../../../../hooks/api/getters/useUiConfig/useUiConfig'; import useApiTokensApi, { IApiTokenCreate, -} from '../../../hooks/api/actions/useApiTokensApi/useApiTokensApi'; -import ApiError from '../../common/ApiError/ApiError'; -import PageContent from '../../common/PageContent'; -import HeaderTitle from '../../common/HeaderTitle'; -import ConditionallyRender from '../../common/ConditionallyRender'; +} from '../../../../hooks/api/actions/useApiTokensApi/useApiTokensApi'; +import ApiError from '../../../common/ApiError/ApiError'; +import PageContent from '../../../common/PageContent'; +import HeaderTitle from '../../../common/HeaderTitle'; +import ConditionallyRender from '../../../common/ConditionallyRender'; import { CREATE_API_TOKEN, DELETE_API_TOKEN, -} from '../../providers/AccessProvider/permissions'; +} from '../../../providers/AccessProvider/permissions'; import { useStyles } from './ApiTokenList.styles'; -import { formatDateWithLocale } from '../../common/util'; +import { formatDateWithLocale } from '../../../common/util'; import Secret from './secret'; import { Delete, FileCopy } from '@material-ui/icons'; import ApiTokenCreate from '../ApiTokenCreate/ApiTokenCreate'; -import Dialogue from '../../common/Dialogue'; -import { CREATE_API_TOKEN_BUTTON } from '../../../testIds'; +import Dialogue from '../../../common/Dialogue'; +import { CREATE_API_TOKEN_BUTTON } from '../../../../testIds'; import { Alert } from '@material-ui/lab'; import copy from 'copy-to-clipboard'; diff --git a/frontend/src/component/api-token/ApiTokenList/secret.jsx b/frontend/src/component/admin/api-token/ApiTokenList/secret.jsx similarity index 100% rename from frontend/src/component/api-token/ApiTokenList/secret.jsx rename to frontend/src/component/admin/api-token/ApiTokenList/secret.jsx diff --git a/frontend/src/page/admin/api/index.js b/frontend/src/component/admin/api/index.js similarity index 79% rename from frontend/src/page/admin/api/index.js rename to frontend/src/component/admin/api/index.js index 92350ac88b..23cad0056a 100644 --- a/frontend/src/page/admin/api/index.js +++ b/frontend/src/component/admin/api/index.js @@ -1,9 +1,9 @@ import PropTypes from 'prop-types'; -import ApiTokenList from '../../../component/api-token/ApiTokenList/ApiTokenList'; +import ApiTokenList from '../api-token/ApiTokenList/ApiTokenList'; import AdminMenu from '../admin-menu'; import usePermissions from '../../../hooks/usePermissions'; -import ConditionallyRender from '../../../component/common/ConditionallyRender'; +import ConditionallyRender from '../../common/ConditionallyRender'; const ApiPage = ({ history, location }) => { const { isAdmin } = usePermissions(); diff --git a/frontend/src/page/admin/auth/AutoCreateForm/AutoCreateForm.tsx b/frontend/src/component/admin/auth/AutoCreateForm/AutoCreateForm.tsx similarity index 100% rename from frontend/src/page/admin/auth/AutoCreateForm/AutoCreateForm.tsx rename to frontend/src/component/admin/auth/AutoCreateForm/AutoCreateForm.tsx diff --git a/frontend/src/page/admin/auth/authentication.jsx b/frontend/src/component/admin/auth/authentication.jsx similarity index 91% rename from frontend/src/page/admin/auth/authentication.jsx rename to frontend/src/component/admin/auth/authentication.jsx index a1a187482d..e2301abf93 100644 --- a/frontend/src/page/admin/auth/authentication.jsx +++ b/frontend/src/component/admin/auth/authentication.jsx @@ -5,9 +5,9 @@ import { Alert } from '@material-ui/lab'; import GoogleAuth from './google-auth-container'; import SamlAuth from './saml-auth-container'; import OidcAuth from './oidc-auth-container'; -import TabNav from '../../../component/common/TabNav/TabNav'; -import PageContent from '../../../component/common/PageContent/PageContent'; -import ConditionallyRender from '../../../component/common/ConditionallyRender/ConditionallyRender'; +import TabNav from '../../common/TabNav/TabNav'; +import PageContent from '../../common/PageContent/PageContent'; +import ConditionallyRender from '../../common/ConditionallyRender/ConditionallyRender'; function AdminAuthPage({ authenticationType, history }) { const tabs = [ diff --git a/frontend/src/page/admin/auth/google-auth-container.js b/frontend/src/component/admin/auth/google-auth-container.js similarity index 78% rename from frontend/src/page/admin/auth/google-auth-container.js rename to frontend/src/component/admin/auth/google-auth-container.js index d1a25ed616..9cc583aa52 100644 --- a/frontend/src/page/admin/auth/google-auth-container.js +++ b/frontend/src/component/admin/auth/google-auth-container.js @@ -1,6 +1,6 @@ import { connect } from 'react-redux'; import GoogleAuth from './google-auth'; -import { getGoogleConfig, updateGoogleConfig } from './../../../store/e-admin-auth/actions'; +import { getGoogleConfig, updateGoogleConfig } from '../../../store/e-admin-auth/actions'; const mapStateToProps = state => ({ config: state.authAdmin.get('google'), diff --git a/frontend/src/page/admin/auth/google-auth.jsx b/frontend/src/component/admin/auth/google-auth.jsx similarity index 98% rename from frontend/src/page/admin/auth/google-auth.jsx rename to frontend/src/component/admin/auth/google-auth.jsx index cec55b9145..52342bd4da 100644 --- a/frontend/src/page/admin/auth/google-auth.jsx +++ b/frontend/src/component/admin/auth/google-auth.jsx @@ -8,9 +8,9 @@ import { TextField, } from '@material-ui/core'; import { Alert } from '@material-ui/lab'; -import PageContent from '../../../component/common/PageContent/PageContent'; +import PageContent from '../../common/PageContent/PageContent'; import AccessContext from '../../../contexts/AccessContext'; -import { ADMIN } from '../../../component/providers/AccessProvider/permissions'; +import { ADMIN } from '../../providers/AccessProvider/permissions'; const initialState = { enabled: false, diff --git a/frontend/src/page/admin/auth/index.js b/frontend/src/component/admin/auth/index.js similarity index 100% rename from frontend/src/page/admin/auth/index.js rename to frontend/src/component/admin/auth/index.js diff --git a/frontend/src/page/admin/auth/oidc-auth-container.js b/frontend/src/component/admin/auth/oidc-auth-container.js similarity index 100% rename from frontend/src/page/admin/auth/oidc-auth-container.js rename to frontend/src/component/admin/auth/oidc-auth-container.js diff --git a/frontend/src/page/admin/auth/oidc-auth.jsx b/frontend/src/component/admin/auth/oidc-auth.jsx similarity index 98% rename from frontend/src/page/admin/auth/oidc-auth.jsx rename to frontend/src/component/admin/auth/oidc-auth.jsx index 8170e5df49..306495df17 100644 --- a/frontend/src/page/admin/auth/oidc-auth.jsx +++ b/frontend/src/component/admin/auth/oidc-auth.jsx @@ -8,9 +8,9 @@ import { TextField, } from '@material-ui/core'; import { Alert } from '@material-ui/lab'; -import PageContent from '../../../component/common/PageContent/PageContent'; +import PageContent from '../../common/PageContent/PageContent'; import AccessContext from '../../../contexts/AccessContext'; -import { ADMIN } from '../../../component/providers/AccessProvider/permissions'; +import { ADMIN } from '../../providers/AccessProvider/permissions'; import AutoCreateForm from './AutoCreateForm/AutoCreateForm'; const initialState = { diff --git a/frontend/src/page/admin/auth/saml-auth-container.js b/frontend/src/component/admin/auth/saml-auth-container.js similarity index 78% rename from frontend/src/page/admin/auth/saml-auth-container.js rename to frontend/src/component/admin/auth/saml-auth-container.js index 29e410e84d..1d1fe9ac3a 100644 --- a/frontend/src/page/admin/auth/saml-auth-container.js +++ b/frontend/src/component/admin/auth/saml-auth-container.js @@ -1,6 +1,6 @@ import { connect } from 'react-redux'; import SamlAuth from './saml-auth'; -import { getSamlConfig, updateSamlConfig } from './../../../store/e-admin-auth/actions'; +import { getSamlConfig, updateSamlConfig } from '../../../store/e-admin-auth/actions'; const mapStateToProps = state => ({ config: state.authAdmin.get('saml'), diff --git a/frontend/src/page/admin/auth/saml-auth.jsx b/frontend/src/component/admin/auth/saml-auth.jsx similarity index 98% rename from frontend/src/page/admin/auth/saml-auth.jsx rename to frontend/src/component/admin/auth/saml-auth.jsx index d0d703cb79..521500deec 100644 --- a/frontend/src/page/admin/auth/saml-auth.jsx +++ b/frontend/src/component/admin/auth/saml-auth.jsx @@ -8,9 +8,9 @@ import { TextField, } from '@material-ui/core'; import { Alert } from '@material-ui/lab'; -import PageContent from '../../../component/common/PageContent/PageContent'; +import PageContent from '../../common/PageContent/PageContent'; import AccessContext from '../../../contexts/AccessContext'; -import { ADMIN } from '../../../component/providers/AccessProvider/permissions'; +import { ADMIN } from '../../providers/AccessProvider/permissions'; import AutoCreateForm from './AutoCreateForm/AutoCreateForm'; const initialState = { diff --git a/frontend/src/page/admin/index.js b/frontend/src/component/admin/index.js similarity index 100% rename from frontend/src/page/admin/index.js rename to frontend/src/component/admin/index.js diff --git a/frontend/src/page/admin/invoice/index.js b/frontend/src/component/admin/invoice/index.js similarity index 84% rename from frontend/src/page/admin/invoice/index.js rename to frontend/src/component/admin/invoice/index.js index 43ea093daf..53f3a37bcf 100644 --- a/frontend/src/page/admin/invoice/index.js +++ b/frontend/src/component/admin/invoice/index.js @@ -2,8 +2,8 @@ import { useContext } from 'react'; import PropTypes from 'prop-types'; import InvoiceList from './invoice-container'; import AccessContext from '../../../contexts/AccessContext'; -import { ADMIN } from '../../../component/providers/AccessProvider/permissions'; -import ConditionallyRender from '../../../component/common/ConditionallyRender'; +import { ADMIN } from '../../providers/AccessProvider/permissions'; +import ConditionallyRender from '../../common/ConditionallyRender'; import { Alert } from '@material-ui/lab'; const InvoiceAdminPage = ({ history }) => { diff --git a/frontend/src/page/admin/invoice/invoice-container.js b/frontend/src/component/admin/invoice/invoice-container.js similarity index 100% rename from frontend/src/page/admin/invoice/invoice-container.js rename to frontend/src/component/admin/invoice/invoice-container.js diff --git a/frontend/src/page/admin/invoice/invoice-list.jsx b/frontend/src/component/admin/invoice/invoice-list.jsx similarity index 91% rename from frontend/src/page/admin/invoice/invoice-list.jsx rename to frontend/src/component/admin/invoice/invoice-list.jsx index 79a9822af3..76b51f60de 100644 --- a/frontend/src/page/admin/invoice/invoice-list.jsx +++ b/frontend/src/component/admin/invoice/invoice-list.jsx @@ -9,10 +9,10 @@ import { Button, } from '@material-ui/core'; import OpenInNew from '@material-ui/icons/OpenInNew'; -import { formatDateWithLocale } from '../../../component/common/util'; -import PageContent from '../../../component/common/PageContent'; -import HeaderTitle from '../../../component/common/HeaderTitle'; -import ConditionallyRender from '../../../component/common/ConditionallyRender'; +import { formatDateWithLocale } from '../../common/util'; +import PageContent from '../../common/PageContent'; +import HeaderTitle from '../../common/HeaderTitle'; +import ConditionallyRender from '../../common/ConditionallyRender'; import { formatApiPath } from '../../../utils/format-path'; const PORTAL_URL = formatApiPath('api/admin/invoices/portal'); diff --git a/frontend/src/page/admin/users/AddUser/AddUser.tsx b/frontend/src/component/admin/users/AddUser/AddUser.tsx similarity index 97% rename from frontend/src/page/admin/users/AddUser/AddUser.tsx rename to frontend/src/component/admin/users/AddUser/AddUser.tsx index 1c5ec2075d..e2a9d363b8 100644 --- a/frontend/src/page/admin/users/AddUser/AddUser.tsx +++ b/frontend/src/component/admin/users/AddUser/AddUser.tsx @@ -1,5 +1,5 @@ import { useState } from 'react'; -import Dialogue from '../../../../component/common/Dialogue'; +import Dialogue from '../../../common/Dialogue'; import { IUserApiErrors } from '../../../../hooks/api/actions/useAdminUsersApi/useAdminUsersApi'; import IRole from '../../../../interfaces/role'; diff --git a/frontend/src/page/admin/users/AddUser/AddUserForm/AddUserForm.jsx b/frontend/src/component/admin/users/AddUser/AddUserForm/AddUserForm.jsx similarity index 98% rename from frontend/src/page/admin/users/AddUser/AddUserForm/AddUserForm.jsx rename to frontend/src/component/admin/users/AddUser/AddUserForm/AddUserForm.jsx index cb3e867341..9cc53fed5e 100644 --- a/frontend/src/page/admin/users/AddUser/AddUserForm/AddUserForm.jsx +++ b/frontend/src/component/admin/users/AddUser/AddUserForm/AddUserForm.jsx @@ -11,9 +11,9 @@ import { Typography, } from '@material-ui/core'; -import { trim } from '../../../../../component/common/util'; +import { trim } from '../../../../common/util'; import { useCommonStyles } from '../../../../../common.styles'; -import ConditionallyRender from '../../../../../component/common/ConditionallyRender'; +import ConditionallyRender from '../../../../common/ConditionallyRender'; import { useStyles } from './AddUserForm.styles'; import useLoading from '../../../../../hooks/useLoading'; import { diff --git a/frontend/src/page/admin/users/AddUser/AddUserForm/AddUserForm.styles.js b/frontend/src/component/admin/users/AddUser/AddUserForm/AddUserForm.styles.js similarity index 100% rename from frontend/src/page/admin/users/AddUser/AddUserForm/AddUserForm.styles.js rename to frontend/src/component/admin/users/AddUser/AddUserForm/AddUserForm.styles.js diff --git a/frontend/src/page/admin/users/ConfirmUserAdded/ConfirmUserAdded.tsx b/frontend/src/component/admin/users/ConfirmUserAdded/ConfirmUserAdded.tsx similarity index 100% rename from frontend/src/page/admin/users/ConfirmUserAdded/ConfirmUserAdded.tsx rename to frontend/src/component/admin/users/ConfirmUserAdded/ConfirmUserAdded.tsx diff --git a/frontend/src/page/admin/users/ConfirmUserAdded/ConfirmUserEmail/ConfirmUserEmail.styles.ts b/frontend/src/component/admin/users/ConfirmUserAdded/ConfirmUserEmail/ConfirmUserEmail.styles.ts similarity index 100% rename from frontend/src/page/admin/users/ConfirmUserAdded/ConfirmUserEmail/ConfirmUserEmail.styles.ts rename to frontend/src/component/admin/users/ConfirmUserAdded/ConfirmUserEmail/ConfirmUserEmail.styles.ts diff --git a/frontend/src/page/admin/users/ConfirmUserAdded/ConfirmUserEmail/ConfirmUserEmail.tsx b/frontend/src/component/admin/users/ConfirmUserAdded/ConfirmUserEmail/ConfirmUserEmail.tsx similarity index 95% rename from frontend/src/page/admin/users/ConfirmUserAdded/ConfirmUserEmail/ConfirmUserEmail.tsx rename to frontend/src/component/admin/users/ConfirmUserAdded/ConfirmUserEmail/ConfirmUserEmail.tsx index 872bed7ee5..99575f7008 100644 --- a/frontend/src/page/admin/users/ConfirmUserAdded/ConfirmUserEmail/ConfirmUserEmail.tsx +++ b/frontend/src/component/admin/users/ConfirmUserAdded/ConfirmUserEmail/ConfirmUserEmail.tsx @@ -1,5 +1,5 @@ import { Typography } from '@material-ui/core'; -import Dialogue from '../../../../../component/common/Dialogue'; +import Dialogue from '../../../../common/Dialogue'; import { ReactComponent as EmailIcon } from '../../../../../assets/icons/email.svg'; import { useStyles } from './ConfirmUserEmail.styles'; diff --git a/frontend/src/page/admin/users/ConfirmUserAdded/ConfirmUserLink/ConfirmUserLink.tsx b/frontend/src/component/admin/users/ConfirmUserAdded/ConfirmUserLink/ConfirmUserLink.tsx similarity index 96% rename from frontend/src/page/admin/users/ConfirmUserAdded/ConfirmUserLink/ConfirmUserLink.tsx rename to frontend/src/component/admin/users/ConfirmUserAdded/ConfirmUserLink/ConfirmUserLink.tsx index c799c919e2..2299dbf287 100644 --- a/frontend/src/page/admin/users/ConfirmUserAdded/ConfirmUserLink/ConfirmUserLink.tsx +++ b/frontend/src/component/admin/users/ConfirmUserAdded/ConfirmUserLink/ConfirmUserLink.tsx @@ -1,7 +1,7 @@ import { Typography } from '@material-ui/core'; import { Alert } from '@material-ui/lab'; import { useCommonStyles } from '../../../../../common.styles'; -import Dialogue from '../../../../../component/common/Dialogue'; +import Dialogue from '../../../../common/Dialogue'; import UserInviteLink from './UserInviteLink/UserInviteLink'; interface IConfirmUserLink { diff --git a/frontend/src/page/admin/users/ConfirmUserAdded/ConfirmUserLink/UserInviteLink/UserInviteLink.tsx b/frontend/src/component/admin/users/ConfirmUserAdded/ConfirmUserLink/UserInviteLink/UserInviteLink.tsx similarity index 100% rename from frontend/src/page/admin/users/ConfirmUserAdded/ConfirmUserLink/UserInviteLink/UserInviteLink.tsx rename to frontend/src/component/admin/users/ConfirmUserAdded/ConfirmUserLink/UserInviteLink/UserInviteLink.tsx diff --git a/frontend/src/page/admin/users/UsersList/UserListItem/UserListItem.styles.ts b/frontend/src/component/admin/users/UsersList/UserListItem/UserListItem.styles.ts similarity index 100% rename from frontend/src/page/admin/users/UsersList/UserListItem/UserListItem.styles.ts rename to frontend/src/component/admin/users/UsersList/UserListItem/UserListItem.styles.ts diff --git a/frontend/src/page/admin/users/UsersList/UserListItem/UserListItem.tsx b/frontend/src/component/admin/users/UsersList/UserListItem/UserListItem.tsx similarity index 93% rename from frontend/src/page/admin/users/UsersList/UserListItem/UserListItem.tsx rename to frontend/src/component/admin/users/UsersList/UserListItem/UserListItem.tsx index a94262e22d..523913e258 100644 --- a/frontend/src/page/admin/users/UsersList/UserListItem/UserListItem.tsx +++ b/frontend/src/component/admin/users/UsersList/UserListItem/UserListItem.tsx @@ -7,9 +7,9 @@ import { } from '@material-ui/core'; import { Edit, Lock, Delete } from '@material-ui/icons'; import { SyntheticEvent, useContext } from 'react'; -import { ADMIN } from '../../../../../component/providers/AccessProvider/permissions'; -import ConditionallyRender from '../../../../../component/common/ConditionallyRender'; -import { formatDateWithLocale } from '../../../../../component/common/util'; +import { ADMIN } from '../../../../providers/AccessProvider/permissions'; +import ConditionallyRender from '../../../../common/ConditionallyRender'; +import { formatDateWithLocale } from '../../../../common/util'; import AccessContext from '../../../../../contexts/AccessContext'; import { IUser } from '../../../../../interfaces/user'; import { useStyles } from './UserListItem.styles'; diff --git a/frontend/src/page/admin/users/UsersList/UsersList.jsx b/frontend/src/component/admin/users/UsersList/UsersList.jsx similarity index 96% rename from frontend/src/page/admin/users/UsersList/UsersList.jsx rename to frontend/src/component/admin/users/UsersList/UsersList.jsx index e85a23c786..1ee8288299 100644 --- a/frontend/src/page/admin/users/UsersList/UsersList.jsx +++ b/frontend/src/component/admin/users/UsersList/UsersList.jsx @@ -12,9 +12,9 @@ import AddUser from '../AddUser/AddUser'; import ChangePassword from '../change-password-component'; import UpdateUser from '../update-user-component'; import DelUser from '../del-user-component'; -import ConditionallyRender from '../../../../component/common/ConditionallyRender/ConditionallyRender'; +import ConditionallyRender from '../../../common/ConditionallyRender/ConditionallyRender'; import AccessContext from '../../../../contexts/AccessContext'; -import { ADMIN } from '../../../../component/providers/AccessProvider/permissions'; +import { ADMIN } from '../../../providers/AccessProvider/permissions'; import ConfirmUserAdded from '../ConfirmUserAdded/ConfirmUserAdded'; import useUsers from '../../../../hooks/api/getters/useUsers/useUsers'; import useAdminUsersApi from '../../../../hooks/api/actions/useAdminUsersApi/useAdminUsersApi'; @@ -22,7 +22,7 @@ import UserListItem from './UserListItem/UserListItem'; import loadingData from './loadingData'; import useLoading from '../../../../hooks/useLoading'; import usePagination from '../../../../hooks/usePagination'; -import PaginateUI from '../../../../component/common/PaginateUI/PaginateUI'; +import PaginateUI from '../../../common/PaginateUI/PaginateUI'; function UsersList({ location, closeDialog, showDialog }) { const { users, roles, refetch, loading } = useUsers(); diff --git a/frontend/src/page/admin/users/UsersList/index.js b/frontend/src/component/admin/users/UsersList/index.js similarity index 100% rename from frontend/src/page/admin/users/UsersList/index.js rename to frontend/src/component/admin/users/UsersList/index.js diff --git a/frontend/src/page/admin/users/UsersList/loadingData.ts b/frontend/src/component/admin/users/UsersList/loadingData.ts similarity index 100% rename from frontend/src/page/admin/users/UsersList/loadingData.ts rename to frontend/src/component/admin/users/UsersList/loadingData.ts diff --git a/frontend/src/page/admin/users/change-password-component.jsx b/frontend/src/component/admin/users/change-password-component.jsx similarity index 91% rename from frontend/src/page/admin/users/change-password-component.jsx rename to frontend/src/component/admin/users/change-password-component.jsx index 8c97fe4c4d..cb040e043b 100644 --- a/frontend/src/page/admin/users/change-password-component.jsx +++ b/frontend/src/component/admin/users/change-password-component.jsx @@ -2,13 +2,13 @@ import { useState } from 'react'; import PropTypes from 'prop-types'; import classnames from 'classnames'; import { TextField, Typography, Avatar } from '@material-ui/core'; -import { trim } from '../../../component/common/util'; +import { trim } from '../../common/util'; import { modalStyles } from './util'; -import Dialogue from '../../../component/common/Dialogue/Dialogue'; -import PasswordChecker from '../../../component/user/common/ResetPasswordForm/PasswordChecker/PasswordChecker'; +import Dialogue from '../../common/Dialogue/Dialogue'; +import PasswordChecker from '../../user/common/ResetPasswordForm/PasswordChecker/PasswordChecker'; import { useCommonStyles } from '../../../common.styles'; -import PasswordMatcher from '../../../component/user/common/ResetPasswordForm/PasswordMatcher/PasswordMatcher'; -import ConditionallyRender from '../../../component/common/ConditionallyRender'; +import PasswordMatcher from '../../user/common/ResetPasswordForm/PasswordMatcher/PasswordMatcher'; +import ConditionallyRender from '../../common/ConditionallyRender'; import { Alert } from '@material-ui/lab'; function ChangePassword({ diff --git a/frontend/src/page/admin/users/del-user-component.jsx b/frontend/src/component/admin/users/del-user-component.jsx similarity index 94% rename from frontend/src/page/admin/users/del-user-component.jsx rename to frontend/src/component/admin/users/del-user-component.jsx index fddbc7aae4..24001f34d2 100644 --- a/frontend/src/page/admin/users/del-user-component.jsx +++ b/frontend/src/component/admin/users/del-user-component.jsx @@ -1,6 +1,6 @@ import React from 'react'; -import Dialogue from '../../../component/common/Dialogue/Dialogue'; -import ConditionallyRender from '../../../component/common/ConditionallyRender/ConditionallyRender'; +import Dialogue from '../../common/Dialogue/Dialogue'; +import ConditionallyRender from '../../common/ConditionallyRender/ConditionallyRender'; import propTypes from 'prop-types'; import { REMOVE_USER_ERROR } from '../../../hooks/api/actions/useAdminUsersApi/useAdminUsersApi'; import { Alert } from '@material-ui/lab'; diff --git a/frontend/src/page/admin/users/index.js b/frontend/src/component/admin/users/index.js similarity index 100% rename from frontend/src/page/admin/users/index.js rename to frontend/src/component/admin/users/index.js diff --git a/frontend/src/page/admin/users/index.styles.js b/frontend/src/component/admin/users/index.styles.js similarity index 100% rename from frontend/src/page/admin/users/index.styles.js rename to frontend/src/component/admin/users/index.styles.js diff --git a/frontend/src/page/admin/users/update-user-component.jsx b/frontend/src/component/admin/users/update-user-component.jsx similarity index 96% rename from frontend/src/page/admin/users/update-user-component.jsx rename to frontend/src/component/admin/users/update-user-component.jsx index 787d498718..5332ce84a0 100644 --- a/frontend/src/page/admin/users/update-user-component.jsx +++ b/frontend/src/component/admin/users/update-user-component.jsx @@ -1,6 +1,6 @@ import { useState, useEffect } from 'react'; import PropTypes from 'prop-types'; -import Dialogue from '../../../component/common/Dialogue'; +import Dialogue from '../../common/Dialogue'; import UserForm from './AddUser/AddUserForm/AddUserForm'; function AddUser({ diff --git a/frontend/src/page/admin/users/util.js b/frontend/src/component/admin/users/util.js similarity index 100% rename from frontend/src/page/admin/users/util.js rename to frontend/src/component/admin/users/util.js diff --git a/frontend/src/component/menu/__tests__/__snapshots__/routes-test.jsx.snap b/frontend/src/component/menu/__tests__/__snapshots__/routes-test.jsx.snap index ad801ba46d..f19b34f97b 100644 --- a/frontend/src/component/menu/__tests__/__snapshots__/routes-test.jsx.snap +++ b/frontend/src/component/menu/__tests__/__snapshots__/routes-test.jsx.snap @@ -376,6 +376,17 @@ Array [ "title": "Single Sign-On", "type": "protected", }, + Object { + "component": [Function], + "layout": "main", + "menu": Object { + "adminSettings": true, + }, + "parent": "/admin", + "path": "/admin/roles", + "title": "Project Roles", + "type": "protected", + }, Object { "component": [Function], "hidden": false, diff --git a/frontend/src/component/menu/routes.js b/frontend/src/component/menu/routes.js index d5c562a03e..e26bdbdfa2 100644 --- a/frontend/src/component/menu/routes.js +++ b/frontend/src/component/menu/routes.js @@ -23,11 +23,11 @@ import CreateTag from '../../page/tags/create'; import Addons from '../../page/addons'; import AddonsCreate from '../../page/addons/create'; import AddonsEdit from '../../page/addons/edit'; -import Admin from '../../page/admin'; -import AdminApi from '../../page/admin/api'; -import AdminUsers from '../../page/admin/users'; -import AdminInvoice from '../../page/admin/invoice'; -import AdminAuth from '../../page/admin/auth'; +import Admin from '../admin'; +import AdminApi from '../admin/api'; +import AdminUsers from '../admin/users'; +import AdminInvoice from '../admin/invoice'; +import AdminAuth from '../admin/auth'; import Login from '../user/Login/Login'; import { P, C, E, EEA } from '../common/flags'; import NewUser from '../user/NewUser'; @@ -41,6 +41,7 @@ import EnvironmentList from '../environments/EnvironmentList/EnvironmentList'; import CreateEnvironment from '../environments/CreateEnvironment/CreateEnvironment'; import FeatureView2 from '../feature/FeatureView2/FeatureView2'; import FeatureCreate from '../feature/FeatureCreate/FeatureCreate'; +import ProjectRoles from '../admin/ProjectRolesv1/ProjectRoles'; export const routes = [ // Project @@ -418,6 +419,15 @@ export const routes = [ layout: 'main', menu: { adminSettings: true }, }, + { + path: '/admin/roles', + parent: '/admin', + title: 'Project Roles', + component: ProjectRoles, + type: 'protected', + layout: 'main', + menu: { adminSettings: true }, + }, { path: '/admin', title: 'Admin', diff --git a/frontend/src/hooks/api/getters/useProjectRoles/useProjectRoles.ts b/frontend/src/hooks/api/getters/useProjectRoles/useProjectRoles.ts new file mode 100644 index 0000000000..c1e5e6dab2 --- /dev/null +++ b/frontend/src/hooks/api/getters/useProjectRoles/useProjectRoles.ts @@ -0,0 +1,35 @@ +import useSWR, { mutate, SWRConfiguration } from 'swr'; +import { useState, useEffect } from 'react'; +import { formatApiPath } from '../../../../utils/format-path'; +import handleErrorResponses from '../httpErrorResponseHandler'; + +const useProjectRoles = (options: SWRConfiguration = {}) => { + const fetcher = () => { + const path = formatApiPath(`api/admin/roles`); + return fetch(path, { + method: 'GET', + }) + .then(handleErrorResponses('project roles')) + .then(res => res.json()); + }; + + const { data, error } = useSWR(`api/admin/roles`, fetcher, options); + const [loading, setLoading] = useState(!error && !data); + + const refetch = () => { + mutate(`api/admin/roles`); + }; + + useEffect(() => { + setLoading(!error && !data); + }, [data, error]); + + return { + roles: data?.roles || [], + error, + loading, + refetch, + }; +}; + +export default useProjectRoles;