diff --git a/frontend/src/component/admin/apiToken/ApiTokenTable/ApiTokenTable.tsx b/frontend/src/component/admin/apiToken/ApiTokenTable/ApiTokenTable.tsx
index 273ca43376..013ea29f3a 100644
--- a/frontend/src/component/admin/apiToken/ApiTokenTable/ApiTokenTable.tsx
+++ b/frontend/src/component/admin/apiToken/ApiTokenTable/ApiTokenTable.tsx
@@ -18,18 +18,19 @@ import { CopyApiTokenButton } from 'component/admin/apiToken/CopyApiTokenButton/
import { RemoveApiTokenButton } from 'component/admin/apiToken/RemoveApiTokenButton/RemoveApiTokenButton';
import { DateCell } from 'component/common/Table/cells/DateCell/DateCell';
import { sortTypes } from 'utils/sortTypes';
-import { useEffect, useMemo } from 'react';
+import { useMemo } from 'react';
import theme from 'themes/theme';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import { ProjectsList } from 'component/admin/apiToken/ProjectsList/ProjectsList';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { HighlightCell } from 'component/common/Table/cells/HighlightCell/HighlightCell';
import { Search } from 'component/common/Search/Search';
+import useHiddenColumns from 'hooks/useHiddenColumns';
export const ApiTokenTable = () => {
const { tokens, loading } = useApiTokens();
- const hiddenColumns = useHiddenColumns();
const initialState = useMemo(() => ({ sortBy: [{ id: 'createdAt' }] }), []);
+ const { uiConfig } = useUiConfig();
const {
getTableProps,
@@ -52,9 +53,16 @@ export const ApiTokenTable = () => {
useSortBy
);
- useEffect(() => {
- setHiddenColumns(hiddenColumns);
- }, [setHiddenColumns, hiddenColumns]);
+ useHiddenColumns(
+ setHiddenColumns,
+ ['Icon', 'createdAt'],
+ useMediaQuery(theme.breakpoints.down('md'))
+ );
+ useHiddenColumns(
+ setHiddenColumns,
+ ['projects', 'environment'],
+ !uiConfig.flags.E
+ );
return (
{
);
};
-const useHiddenColumns = (): string[] => {
- const { uiConfig } = useUiConfig();
- const isMediumScreen = useMediaQuery(theme.breakpoints.down('md'));
-
- return useMemo(() => {
- const hidden: string[] = [];
-
- if (!uiConfig.flags.E) {
- hidden.push('projects');
- hidden.push('environment');
- }
-
- if (isMediumScreen) {
- hidden.push('Icon');
- hidden.push('createdAt');
- }
-
- return hidden;
- }, [uiConfig, isMediumScreen]);
-};
-
const COLUMNS = [
{
id: 'Icon',
diff --git a/frontend/src/component/admin/groups/Group/Group.tsx b/frontend/src/component/admin/groups/Group/Group.tsx
index 6a40d812ca..8ded2867ec 100644
--- a/frontend/src/component/admin/groups/Group/Group.tsx
+++ b/frontend/src/component/admin/groups/Group/Group.tsx
@@ -1,13 +1,12 @@
import { useEffect, useMemo, useState, VFC } from 'react';
import {
- Button,
IconButton,
styled,
Tooltip,
useMediaQuery,
useTheme,
} from '@mui/material';
-import { useSearchParams } from 'react-router-dom';
+import { useSearchParams, Link } from 'react-router-dom';
import { SortingRule, useFlexLayout, useSortBy, useTable } from 'react-table';
import { TablePlaceholder, VirtualizedTable } from 'component/common/Table';
import { useGroup } from 'hooks/api/getters/useGroup/useGroup';
@@ -26,17 +25,17 @@ import { HighlightCell } from 'component/common/Table/cells/HighlightCell/Highli
import { TimeAgoCell } from 'component/common/Table/cells/TimeAgoCell/TimeAgoCell';
import { GroupUserRoleCell } from 'component/admin/groups/GroupUserRoleCell/GroupUserRoleCell';
import PermissionIconButton from 'component/common/PermissionIconButton/PermissionIconButton';
-import { Delete, Edit } from '@mui/icons-material';
+import { Add, Delete, Edit } from '@mui/icons-material';
import { ADMIN } from 'component/providers/AccessProvider/permissions';
import { MainHeader } from 'component/common/MainHeader/MainHeader';
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
import { RemoveGroup } from 'component/admin/groups/RemoveGroup/RemoveGroup';
-import { Link } from 'react-router-dom';
import { ActionCell } from 'component/common/Table/cells/ActionCell/ActionCell';
import { AddGroupUser } from './AddGroupUser/AddGroupUser';
import { EditGroupUser } from './EditGroupUser/EditGroupUser';
import { RemoveGroupUser } from './RemoveGroupUser/RemoveGroupUser';
import { UserAvatar } from 'component/common/UserAvatar/UserAvatar';
+import ResponsiveButton from 'component/common/ResponsiveButton/ResponsiveButton';
import {
UG_EDIT_BTN_ID,
UG_DELETE_BTN_ID,
@@ -140,30 +139,36 @@ export const Group: VFC = () => {
Cell: ({ row: { original: rowUser } }: any) => (
- {
- setSelectedUser(rowUser);
- setEditUserOpen(true);
- }}
- >
-
-
+
+ {
+ setSelectedUser(rowUser);
+ setEditUserOpen(true);
+ }}
+ >
+
+
+
- {
- setSelectedUser(rowUser);
- setRemoveUserOpen(true);
- }}
- >
-
-
+
+ {
+ setSelectedUser(rowUser);
+ setRemoveUserOpen(true);
+ }}
+ >
+
+
+
),
@@ -171,7 +176,7 @@ export const Group: VFC = () => {
disableSortBy: true,
},
],
- [setSelectedUser, setRemoveUserOpen]
+ [setSelectedUser, setRemoveUserOpen, group?.users.length]
);
const [searchParams, setSearchParams] = useSearchParams();
@@ -306,16 +311,17 @@ export const Group: VFC = () => {
>
}
/>
-
+
>
}
>
@@ -376,13 +382,13 @@ export const Group: VFC = () => {
diff --git a/frontend/src/component/admin/groups/GroupForm/GroupFormUsersTable/GroupFormUsersTable.tsx b/frontend/src/component/admin/groups/GroupForm/GroupFormUsersTable/GroupFormUsersTable.tsx
index b25d8cf80c..c9193a329d 100644
--- a/frontend/src/component/admin/groups/GroupForm/GroupFormUsersTable/GroupFormUsersTable.tsx
+++ b/frontend/src/component/admin/groups/GroupForm/GroupFormUsersTable/GroupFormUsersTable.tsx
@@ -1,5 +1,5 @@
import { useMemo, VFC } from 'react';
-import { IconButton, Tooltip } from '@mui/material';
+import { IconButton, Tooltip, useMediaQuery } from '@mui/material';
import { TextCell } from 'component/common/Table/cells/TextCell/TextCell';
import { IGroupUser } from 'interfaces/group';
import { HighlightCell } from 'component/common/Table/cells/HighlightCell/HighlightCell';
@@ -11,6 +11,8 @@ import { VirtualizedTable } from 'component/common/Table';
import { useFlexLayout, useSortBy, useTable } from 'react-table';
import { sortTypes } from 'utils/sortTypes';
import { UserAvatar } from 'component/common/UserAvatar/UserAvatar';
+import theme from 'themes/theme';
+import useHiddenColumns from 'hooks/useHiddenColumns';
interface IGroupFormUsersTableProps {
users: IGroupUser[];
@@ -106,7 +108,7 @@ export const GroupFormUsersTable: VFC = ({
[setUsers]
);
- const { headerGroups, rows, prepareRow } = useTable(
+ const { headerGroups, rows, prepareRow, setHiddenColumns } = useTable(
{
columns: columns as any[],
data: users as any[],
@@ -119,6 +121,12 @@ export const GroupFormUsersTable: VFC = ({
useFlexLayout
);
+ useHiddenColumns(
+ setHiddenColumns,
+ ['imageUrl', 'name'],
+ useMediaQuery(theme.breakpoints.down('md'))
+ );
+
return (
0}
diff --git a/frontend/src/component/admin/groups/GroupsList/GroupsList.tsx b/frontend/src/component/admin/groups/GroupsList/GroupsList.tsx
index 7cc52ddd9c..8c4b063bff 100644
--- a/frontend/src/component/admin/groups/GroupsList/GroupsList.tsx
+++ b/frontend/src/component/admin/groups/GroupsList/GroupsList.tsx
@@ -1,6 +1,6 @@
import { useEffect, useMemo, useState, VFC } from 'react';
import { useGroups } from 'hooks/api/getters/useGroups/useGroups';
-import { Link, useSearchParams } from 'react-router-dom';
+import { Link, useNavigate, useSearchParams } from 'react-router-dom';
import { IGroup } from 'interfaces/group';
import { PageContent } from 'component/common/PageContent/PageContent';
import { PageHeader } from 'component/common/PageHeader/PageHeader';
@@ -12,6 +12,9 @@ import { SearchHighlightProvider } from 'component/common/Table/SearchHighlightC
import { TablePlaceholder } from 'component/common/Table';
import { GroupCard } from './GroupCard/GroupCard';
import { GroupEmpty } from './GroupEmpty/GroupEmpty';
+import ResponsiveButton from 'component/common/ResponsiveButton/ResponsiveButton';
+import { ADMIN } from 'component/providers/AccessProvider/permissions';
+import { Add } from '@mui/icons-material';
import { NAVIGATE_TO_CREATE_GROUP } from 'utils/testIds';
type PageQueryType = Partial>;
@@ -33,6 +36,7 @@ const groupsSearch = (group: IGroup, searchValue: string) => {
};
export const GroupsList: VFC = () => {
+ const navigate = useNavigate();
const { groups = [], loading } = useGroups();
const [searchParams, setSearchParams] = useSearchParams();
const [searchValue, setSearchValue] = useState(
@@ -81,15 +85,17 @@ export const GroupsList: VFC = () => {
>
}
/>
-
+
>
}
>
diff --git a/frontend/src/component/common/MainHeader/MainHeader.tsx b/frontend/src/component/common/MainHeader/MainHeader.tsx
index 2b46d0237b..9c5464bfdb 100644
--- a/frontend/src/component/common/MainHeader/MainHeader.tsx
+++ b/frontend/src/component/common/MainHeader/MainHeader.tsx
@@ -13,7 +13,7 @@ const StyledMainHeader = styled(Paper)(({ theme }) => ({
const StyledTitleHeader = styled('div')(({ theme }) => ({
display: 'flex',
- alignItems: 'center',
+ alignItems: 'flex-start',
justifyContent: 'space-between',
}));
diff --git a/frontend/src/component/project/ProjectAccess/ProjectAccessAssign/ProjectAccessAssign.tsx b/frontend/src/component/project/ProjectAccess/ProjectAccessAssign/ProjectAccessAssign.tsx
index 3cdb95adf3..ddb8d64ce5 100644
--- a/frontend/src/component/project/ProjectAccess/ProjectAccessAssign/ProjectAccessAssign.tsx
+++ b/frontend/src/component/project/ProjectAccess/ProjectAccessAssign/ProjectAccessAssign.tsx
@@ -47,8 +47,8 @@ const StyledAutocompleteWrapper = styled('div')(({ theme }) => ({
},
}));
-const StyledButtonContainer = styled('div')(() => ({
- marginTop: 'auto',
+const StyledButtonContainer = styled('div')(({ theme }) => ({
+ marginTop: theme.spacing(6),
display: 'flex',
justifyContent: 'flex-end',
}));
diff --git a/frontend/src/component/project/ProjectAccess/ProjectAccessAssign/ProjectRoleDescription/ProjectRoleDescription.tsx b/frontend/src/component/project/ProjectAccess/ProjectAccessAssign/ProjectRoleDescription/ProjectRoleDescription.tsx
index f9d2276693..75c9090270 100644
--- a/frontend/src/component/project/ProjectAccess/ProjectAccessAssign/ProjectRoleDescription/ProjectRoleDescription.tsx
+++ b/frontend/src/component/project/ProjectAccess/ProjectAccessAssign/ProjectRoleDescription/ProjectRoleDescription.tsx
@@ -9,7 +9,7 @@ const StyledDescription = styled('div')(({ theme }) => ({
padding: theme.spacing(3),
backgroundColor: theme.palette.neutral.light,
color: theme.palette.text.secondary,
- fontSize: theme.fontSizes.smallerBody,
+ fontSize: theme.fontSizes.smallBody,
borderRadius: theme.shape.borderRadiusMedium,
}));
diff --git a/frontend/src/component/project/ProjectAccess/ProjectAccessTable/ProjectAccessTable.tsx b/frontend/src/component/project/ProjectAccess/ProjectAccessTable/ProjectAccessTable.tsx
index 01ddcb5828..29754c44d8 100644
--- a/frontend/src/component/project/ProjectAccess/ProjectAccessTable/ProjectAccessTable.tsx
+++ b/frontend/src/component/project/ProjectAccess/ProjectAccessTable/ProjectAccessTable.tsx
@@ -1,8 +1,8 @@
import { useEffect, useMemo, useState, VFC } from 'react';
import { SortingRule, useFlexLayout, useSortBy, useTable } from 'react-table';
import { VirtualizedTable, TablePlaceholder } from 'component/common/Table';
-import { Button, useMediaQuery, useTheme } from '@mui/material';
-import { Delete, Edit } from '@mui/icons-material';
+import { styled, useMediaQuery, useTheme } from '@mui/material';
+import { Add, Delete, Edit } from '@mui/icons-material';
import { sortTypes } from 'utils/sortTypes';
import useProjectAccess, {
ENTITY_TYPE,
@@ -38,9 +38,11 @@ import { IUser } from 'interfaces/user';
import { IGroup } from 'interfaces/group';
import { LinkCell } from 'component/common/Table/cells/LinkCell/LinkCell';
import { UserAvatar } from 'component/common/UserAvatar/UserAvatar';
+import ResponsiveButton from 'component/common/ResponsiveButton/ResponsiveButton';
import { ProjectAccessCreate } from 'component/project/ProjectAccess/ProjectAccessCreate/ProjectAccessCreate';
import { ProjectAccessEditUser } from 'component/project/ProjectAccess/ProjectAccessEditUser/ProjectAccessEditUser';
import { ProjectAccessEditGroup } from 'component/project/ProjectAccess/ProjectAccessEditGroup/ProjectAccessEditGroup';
+import useHiddenColumns from 'hooks/useHiddenColumns';
export type PageQueryType = Partial<
Record<'sort' | 'order' | 'search', string>
@@ -53,6 +55,20 @@ const { value: storedParams, setValue: setStoredParams } = createLocalStorage(
defaultSort
);
+const StyledUserAvatars = styled('div')(({ theme }) => ({
+ display: 'inline-flex',
+ alignItems: 'center',
+ flexWrap: 'wrap',
+ marginLeft: theme.spacing(1),
+}));
+
+const StyledEmptyAvatar = styled(UserAvatar)(({ theme }) => ({
+ marginRight: theme.spacing(-3.5),
+}));
+const StyledGroupAvatar = styled(UserAvatar)(({ theme }) => ({
+ outline: `${theme.spacing(0.25)} solid ${theme.palette.background.paper}`,
+}));
+
export const ProjectAccessTable: VFC = () => {
const projectId = useRequiredPathParam('projectId');
@@ -77,11 +93,15 @@ export const ProjectAccessTable: VFC = () => {
Header: 'Avatar',
accessor: 'imageUrl',
Cell: ({ row: { original: row } }: any) => (
-
-
+
+ }
+ />
+
{row.entity.users?.length}
-
-
+
+
),
maxWidth: 85,
disableSortBy: true,
@@ -124,6 +144,7 @@ export const ProjectAccessTable: VFC = () => {
searchable: true,
},
{
+ id: 'role',
Header: 'Role',
accessor: (row: IProjectAccess) =>
access?.roles.find(({ id }) => id === row.entity.roleId)
@@ -145,6 +166,7 @@ export const ProjectAccessTable: VFC = () => {
maxWidth: 150,
},
{
+ id: 'lastLogin',
Header: 'Last login',
accessor: (row: IProjectAccess) => {
if (row.type === ENTITY_TYPE.USER) {
@@ -240,6 +262,7 @@ export const ProjectAccessTable: VFC = () => {
headerGroups,
rows,
prepareRow,
+ setHiddenColumns,
state: { sortBy },
} = useTable(
{
@@ -258,6 +281,12 @@ export const ProjectAccessTable: VFC = () => {
useFlexLayout
);
+ useHiddenColumns(
+ setHiddenColumns,
+ ['imageUrl', 'username', 'role', 'added', 'lastLogin'],
+ isSmallScreen
+ );
+
useEffect(() => {
const tableState: PageQueryType = {};
tableState.sort = sortBy[0].id;
@@ -332,14 +361,15 @@ export const ProjectAccessTable: VFC = () => {
>
}
/>
-
+
>
}
>
diff --git a/frontend/src/component/project/ProjectAccess/ProjectGroupView/ProjectGroupView.tsx b/frontend/src/component/project/ProjectAccess/ProjectGroupView/ProjectGroupView.tsx
index 39a2c954f2..57a54187fc 100644
--- a/frontend/src/component/project/ProjectAccess/ProjectGroupView/ProjectGroupView.tsx
+++ b/frontend/src/component/project/ProjectAccess/ProjectGroupView/ProjectGroupView.tsx
@@ -20,17 +20,22 @@ import { IGroup, IGroupUser } from 'interfaces/group';
import { VFC, useState } from 'react';
import { SortingRule, useFlexLayout, useSortBy, useTable } from 'react-table';
import { sortTypes } from 'utils/sortTypes';
+import useHiddenColumns from 'hooks/useHiddenColumns';
const StyledPageContent = styled(PageContent)(({ theme }) => ({
height: '100vh',
overflow: 'auto',
padding: theme.spacing(7.5, 6),
+ [theme.breakpoints.down('md')]: {
+ padding: theme.spacing(4, 2),
+ },
'& .header': {
padding: theme.spacing(0, 0, 2, 0),
},
'& .body': {
padding: theme.spacing(3, 0, 0, 0),
},
+ borderRadius: `${theme.spacing(1.5, 0, 0, 1.5)} !important`,
}));
const StyledTitle = styled('div')(({ theme }) => ({
@@ -38,7 +43,7 @@ const StyledTitle = styled('div')(({ theme }) => ({
flexDirection: 'column',
'& > span': {
color: theme.palette.text.secondary,
- fontSize: theme.fontSizes.smallBody,
+ fontSize: theme.fontSizes.bodySize,
},
}));
@@ -80,6 +85,7 @@ const columns = [
filterName: 'type',
},
{
+ id: 'joined',
Header: 'Joined',
accessor: 'joinedAt',
Cell: DateCell,
@@ -87,6 +93,7 @@ const columns = [
maxWidth: 150,
},
{
+ id: 'lastLogin',
Header: 'Last login',
accessor: (row: IGroupUser) => row.seenAt || '',
Cell: ({ row: { original: user } }: any) => (
@@ -135,7 +142,7 @@ export const ProjectGroupView: VFC = ({
group?.users ?? []
);
- const { headerGroups, rows, prepareRow } = useTable(
+ const { headerGroups, rows, prepareRow, setHiddenColumns } = useTable(
{
columns: columns as any[],
data,
@@ -149,6 +156,12 @@ export const ProjectGroupView: VFC = ({
useFlexLayout
);
+ useHiddenColumns(
+ setHiddenColumns,
+ ['imageUrl', 'name', 'joined', 'lastLogin'],
+ useMediaQuery(theme.breakpoints.down('md'))
+ );
+
return (
(param: Array>) => void,
+ hiddenColumns: string[],
+ condition: boolean
+) => {
+ useEffect(() => {
+ const hidden = condition ? hiddenColumns : [];
+ setHiddenColumns(hidden);
+ }, [setHiddenColumns, condition]);
+};
+
+export default useHiddenColumns;