mirror of
https://github.com/Unleash/unleash.git
synced 2025-07-31 13:47:02 +02:00
feat: Admin project roles table (#1030)
* feat: new admin project roles table * small fixes * replace Box in defaultColumn Cell with the new TextCell * refactor: slight adjustments * misc improvements * add HighlightCell * fix: description width * Update src/component/admin/projectRoles/ProjectRoles/ProjectRoleList/ProjectRoleList.tsx Co-authored-by: Tymoteusz Czech <2625371+Tymek@users.noreply.github.com> * address PR comments, small tooltip fixes * fix: prettier fmt Co-authored-by: Tymoteusz Czech <2625371+Tymek@users.noreply.github.com>
This commit is contained in:
parent
9ac962da45
commit
b61980e71b
@ -79,8 +79,6 @@ export const AddonList = () => {
|
|||||||
condition={addons.length > 0}
|
condition={addons.length > 0}
|
||||||
show={<ConfiguredAddons />}
|
show={<ConfiguredAddons />}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<br />
|
|
||||||
<AvailableAddons loading={loading} providers={providers} />
|
<AvailableAddons loading={loading} providers={providers} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
@ -1,19 +1,12 @@
|
|||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { Box, Table, TableBody, TableCell, TableRow } from '@mui/material';
|
import { Table, TableBody, TableCell, TableRow } from 'component/common/Table';
|
||||||
import { Delete, Edit, Visibility, VisibilityOff } from '@mui/icons-material';
|
|
||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||||
import {
|
|
||||||
DELETE_ADDON,
|
|
||||||
UPDATE_ADDON,
|
|
||||||
} from 'component/providers/AccessProvider/permissions';
|
|
||||||
import { useNavigate } from 'react-router-dom';
|
|
||||||
import { PageContent } from 'component/common/PageContent/PageContent';
|
import { PageContent } from 'component/common/PageContent/PageContent';
|
||||||
import useAddons from 'hooks/api/getters/useAddons/useAddons';
|
import useAddons from 'hooks/api/getters/useAddons/useAddons';
|
||||||
import useToast from 'hooks/useToast';
|
import useToast from 'hooks/useToast';
|
||||||
import useAddonsApi from 'hooks/api/actions/useAddonsApi/useAddonsApi';
|
import useAddonsApi from 'hooks/api/actions/useAddonsApi/useAddonsApi';
|
||||||
import { useState, useCallback } from 'react';
|
import { useState, useCallback } from 'react';
|
||||||
import { IAddon } from 'interfaces/addons';
|
import { IAddon } from 'interfaces/addons';
|
||||||
import PermissionIconButton from 'component/common/PermissionIconButton/PermissionIconButton';
|
|
||||||
import { Dialogue } from 'component/common/Dialogue/Dialogue';
|
import { Dialogue } from 'component/common/Dialogue/Dialogue';
|
||||||
import { formatUnknownError } from 'utils/formatUnknownError';
|
import { formatUnknownError } from 'utils/formatUnknownError';
|
||||||
import { LinkCell } from 'component/common/Table/cells/LinkCell/LinkCell';
|
import { LinkCell } from 'component/common/Table/cells/LinkCell/LinkCell';
|
||||||
@ -169,6 +162,7 @@ export const ConfiguredAddons = () => {
|
|||||||
<PageContent
|
<PageContent
|
||||||
isLoading={loading}
|
isLoading={loading}
|
||||||
header={<PageHeader title="Configured addons" />}
|
header={<PageHeader title="Configured addons" />}
|
||||||
|
sx={theme => ({ marginBottom: theme.spacing(2) })}
|
||||||
>
|
>
|
||||||
<Table {...getTableProps()}>
|
<Table {...getTableProps()}>
|
||||||
<SortableTableHeader headerGroups={headerGroups} />
|
<SortableTableHeader headerGroups={headerGroups} />
|
||||||
|
@ -59,7 +59,7 @@ function AdminMenu() {
|
|||||||
to="/admin/roles"
|
to="/admin/roles"
|
||||||
style={createNavLinkStyle}
|
style={createNavLinkStyle}
|
||||||
>
|
>
|
||||||
<span>Project Roles</span>
|
<span>Project roles</span>
|
||||||
</NavLink>
|
</NavLink>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
@ -69,7 +69,7 @@ function AdminMenu() {
|
|||||||
value="/admin/api"
|
value="/admin/api"
|
||||||
label={
|
label={
|
||||||
<NavLink to="/admin/api" style={createNavLinkStyle}>
|
<NavLink to="/admin/api" style={createNavLinkStyle}>
|
||||||
API Access
|
API access
|
||||||
</NavLink>
|
</NavLink>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
@ -77,7 +77,7 @@ function AdminMenu() {
|
|||||||
value="/admin/auth"
|
value="/admin/auth"
|
||||||
label={
|
label={
|
||||||
<NavLink to="/admin/auth" style={createNavLinkStyle}>
|
<NavLink to="/admin/auth" style={createNavLinkStyle}>
|
||||||
Single Sign-On
|
Single sign-on
|
||||||
</NavLink>
|
</NavLink>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
@ -1,37 +1,47 @@
|
|||||||
import { useContext, useState } from 'react';
|
import { useEffect, useMemo, useState } from 'react';
|
||||||
import {
|
import {
|
||||||
Table,
|
Table,
|
||||||
|
SortableTableHeader,
|
||||||
TableBody,
|
TableBody,
|
||||||
TableCell,
|
TableCell,
|
||||||
TableHead,
|
|
||||||
TableRow,
|
TableRow,
|
||||||
} from '@mui/material';
|
TablePlaceholder,
|
||||||
import AccessContext from 'contexts/AccessContext';
|
TableSearch,
|
||||||
import usePagination from 'hooks/usePagination';
|
} from 'component/common/Table';
|
||||||
|
import { useTable, useGlobalFilter, useSortBy } from 'react-table';
|
||||||
import { ADMIN } from 'component/providers/AccessProvider/permissions';
|
import { ADMIN } from 'component/providers/AccessProvider/permissions';
|
||||||
import PaginateUI from 'component/common/PaginateUI/PaginateUI';
|
|
||||||
import ProjectRoleListItem from './ProjectRoleListItem/ProjectRoleListItem';
|
|
||||||
import useProjectRoles from 'hooks/api/getters/useProjectRoles/useProjectRoles';
|
import useProjectRoles from 'hooks/api/getters/useProjectRoles/useProjectRoles';
|
||||||
import IRole, { IProjectRole } from 'interfaces/role';
|
import IRole, { IProjectRole } from 'interfaces/role';
|
||||||
import useProjectRolesApi from 'hooks/api/actions/useProjectRolesApi/useProjectRolesApi';
|
import useProjectRolesApi from 'hooks/api/actions/useProjectRolesApi/useProjectRolesApi';
|
||||||
import useToast from 'hooks/useToast';
|
import useToast from 'hooks/useToast';
|
||||||
import ProjectRoleDeleteConfirm from '../ProjectRoleDeleteConfirm/ProjectRoleDeleteConfirm';
|
import ProjectRoleDeleteConfirm from '../ProjectRoleDeleteConfirm/ProjectRoleDeleteConfirm';
|
||||||
import { formatUnknownError } from 'utils/formatUnknownError';
|
import { formatUnknownError } from 'utils/formatUnknownError';
|
||||||
import { useStyles } from './ProjectRoleListItem/ProjectRoleListItem.styles';
|
import { Box, Button, useMediaQuery } from '@mui/material';
|
||||||
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||||
|
import PermissionIconButton from 'component/common/PermissionIconButton/PermissionIconButton';
|
||||||
|
import { Delete, Edit, SupervisedUserCircle } from '@mui/icons-material';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
import { PageContent } from 'component/common/PageContent/PageContent';
|
||||||
|
import { SearchHighlightProvider } from 'component/common/Table/SearchHighlightContext/SearchHighlightContext';
|
||||||
|
import { PageHeader } from 'component/common/PageHeader/PageHeader';
|
||||||
|
import { sortTypes } from 'utils/sortTypes';
|
||||||
|
import { HighlightCell } from 'component/common/Table/cells/HighlightCell/HighlightCell';
|
||||||
|
import theme from 'themes/theme';
|
||||||
|
import { IconCell } from 'component/common/Table/cells/IconCell/IconCell';
|
||||||
|
|
||||||
const ROOTROLE = 'root';
|
const ROOTROLE = 'root';
|
||||||
|
const BUILTIN_ROLE_TYPE = 'project';
|
||||||
|
|
||||||
const ProjectRoleList = () => {
|
const ProjectRoleList = () => {
|
||||||
const { hasAccess } = useContext(AccessContext);
|
const navigate = useNavigate();
|
||||||
const { roles } = useProjectRoles();
|
const { roles, refetch, loading } = useProjectRoles();
|
||||||
const { classes: styles } = useStyles();
|
|
||||||
|
const isExtraSmallScreen = useMediaQuery(theme.breakpoints.down('sm'));
|
||||||
|
|
||||||
const paginationFilter = (role: IRole) => role?.type !== ROOTROLE;
|
const paginationFilter = (role: IRole) => role?.type !== ROOTROLE;
|
||||||
|
const data = roles.filter(paginationFilter);
|
||||||
|
|
||||||
const { page, pages, nextPage, prevPage, setPageIndex, pageIndex } =
|
|
||||||
usePagination(roles, 10, paginationFilter);
|
|
||||||
const { deleteRole } = useProjectRolesApi();
|
const { deleteRole } = useProjectRolesApi();
|
||||||
const { refetch } = useProjectRoles();
|
|
||||||
const [currentRole, setCurrentRole] = useState<IProjectRole | null>(null);
|
const [currentRole, setCurrentRole] = useState<IProjectRole | null>(null);
|
||||||
const [delDialog, setDelDialog] = useState(false);
|
const [delDialog, setDelDialog] = useState(false);
|
||||||
const [confirmName, setConfirmName] = useState('');
|
const [confirmName, setConfirmName] = useState('');
|
||||||
@ -54,60 +64,198 @@ const ProjectRoleList = () => {
|
|||||||
setConfirmName('');
|
setConfirmName('');
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderRoles = () => {
|
const columns = useMemo(
|
||||||
return page.map((role: IProjectRole) => {
|
() => [
|
||||||
return (
|
{
|
||||||
<ProjectRoleListItem
|
id: 'Icon',
|
||||||
key={role.id}
|
Cell: () => (
|
||||||
id={role.id}
|
<IconCell
|
||||||
name={role.name}
|
icon={<SupervisedUserCircle color="disabled" />}
|
||||||
type={role.type}
|
/>
|
||||||
description={role.description}
|
),
|
||||||
// @ts-expect-error
|
},
|
||||||
setCurrentRole={setCurrentRole}
|
{
|
||||||
setDelDialog={setDelDialog}
|
Header: 'Project role',
|
||||||
/>
|
accessor: 'name',
|
||||||
);
|
},
|
||||||
});
|
{
|
||||||
};
|
Header: 'Description',
|
||||||
|
accessor: 'description',
|
||||||
|
width: '90%',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Header: 'Actions',
|
||||||
|
id: 'Actions',
|
||||||
|
align: 'center',
|
||||||
|
Cell: ({
|
||||||
|
row: {
|
||||||
|
original: { id, type, name, description },
|
||||||
|
},
|
||||||
|
}: any) => (
|
||||||
|
<Box sx={{ display: 'flex', justifyContent: 'center' }}>
|
||||||
|
<PermissionIconButton
|
||||||
|
data-loading
|
||||||
|
disabled={type === BUILTIN_ROLE_TYPE}
|
||||||
|
onClick={() => {
|
||||||
|
navigate(`/admin/roles/${id}/edit`);
|
||||||
|
}}
|
||||||
|
permission={ADMIN}
|
||||||
|
tooltipProps={{
|
||||||
|
title:
|
||||||
|
type === BUILTIN_ROLE_TYPE
|
||||||
|
? 'You cannot edit role'
|
||||||
|
: 'Edit role',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Edit />
|
||||||
|
</PermissionIconButton>
|
||||||
|
<PermissionIconButton
|
||||||
|
data-loading
|
||||||
|
disabled={type === BUILTIN_ROLE_TYPE}
|
||||||
|
onClick={() => {
|
||||||
|
setCurrentRole({
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
} as IProjectRole);
|
||||||
|
setDelDialog(true);
|
||||||
|
}}
|
||||||
|
permission={ADMIN}
|
||||||
|
tooltipProps={{
|
||||||
|
title:
|
||||||
|
type === BUILTIN_ROLE_TYPE
|
||||||
|
? 'You cannot remove role'
|
||||||
|
: 'Remove role',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Delete />
|
||||||
|
</PermissionIconButton>
|
||||||
|
</Box>
|
||||||
|
),
|
||||||
|
width: 100,
|
||||||
|
disableSortBy: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[navigate]
|
||||||
|
);
|
||||||
|
|
||||||
if (!roles) return null;
|
const initialState = useMemo(
|
||||||
|
() => ({
|
||||||
|
sortBy: [{ id: 'name', desc: false }],
|
||||||
|
}),
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
|
const {
|
||||||
|
getTableProps,
|
||||||
|
getTableBodyProps,
|
||||||
|
headerGroups,
|
||||||
|
rows,
|
||||||
|
prepareRow,
|
||||||
|
state: { globalFilter },
|
||||||
|
setGlobalFilter,
|
||||||
|
setHiddenColumns,
|
||||||
|
} = useTable(
|
||||||
|
{
|
||||||
|
columns: columns as any[], // TODO: fix after `react-table` v8 update
|
||||||
|
data,
|
||||||
|
initialState,
|
||||||
|
sortTypes,
|
||||||
|
autoResetGlobalFilter: false,
|
||||||
|
autoResetSortBy: false,
|
||||||
|
disableSortRemove: true,
|
||||||
|
defaultColumn: {
|
||||||
|
Cell: HighlightCell,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
useGlobalFilter,
|
||||||
|
useSortBy
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setHiddenColumns([]);
|
||||||
|
if (isExtraSmallScreen) {
|
||||||
|
setHiddenColumns(['Icon']);
|
||||||
|
}
|
||||||
|
}, [setHiddenColumns, isExtraSmallScreen]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<PageContent
|
||||||
<Table>
|
isLoading={loading}
|
||||||
<TableHead>
|
header={
|
||||||
<TableRow>
|
<PageHeader
|
||||||
<TableCell className={styles.hideXS}></TableCell>
|
title="Project roles"
|
||||||
<TableCell>Project Role</TableCell>
|
actions={
|
||||||
<TableCell className={styles.hideSM}>
|
<>
|
||||||
Description
|
<TableSearch
|
||||||
</TableCell>
|
initialValue={globalFilter}
|
||||||
<TableCell align="right">
|
onChange={setGlobalFilter}
|
||||||
{hasAccess(ADMIN) ? 'Action' : ''}
|
/>
|
||||||
</TableCell>
|
<PageHeader.Divider />
|
||||||
</TableRow>
|
<Button
|
||||||
</TableHead>
|
variant="contained"
|
||||||
<TableBody>{renderRoles()}</TableBody>
|
color="primary"
|
||||||
<PaginateUI
|
onClick={() =>
|
||||||
pages={pages}
|
navigate('/admin/create-project-role')
|
||||||
pageIndex={pageIndex}
|
}
|
||||||
setPageIndex={setPageIndex}
|
>
|
||||||
nextPage={nextPage}
|
New project role
|
||||||
prevPage={prevPage}
|
</Button>
|
||||||
|
</>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</Table>
|
}
|
||||||
<br />
|
>
|
||||||
|
<SearchHighlightProvider value={globalFilter}>
|
||||||
|
<Table {...getTableProps()}>
|
||||||
|
<SortableTableHeader headerGroups={headerGroups} />
|
||||||
|
<TableBody {...getTableBodyProps()}>
|
||||||
|
{rows.map(row => {
|
||||||
|
prepareRow(row);
|
||||||
|
return (
|
||||||
|
<TableRow hover {...row.getRowProps()}>
|
||||||
|
{row.cells.map(cell => (
|
||||||
|
<TableCell {...cell.getCellProps()}>
|
||||||
|
{cell.render('Cell')}
|
||||||
|
</TableCell>
|
||||||
|
))}
|
||||||
|
</TableRow>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</SearchHighlightProvider>
|
||||||
|
<ConditionallyRender
|
||||||
|
condition={rows.length === 0}
|
||||||
|
show={
|
||||||
|
<ConditionallyRender
|
||||||
|
condition={globalFilter?.length > 0}
|
||||||
|
show={
|
||||||
|
<TablePlaceholder>
|
||||||
|
No project roles found matching “
|
||||||
|
{globalFilter}
|
||||||
|
”
|
||||||
|
</TablePlaceholder>
|
||||||
|
}
|
||||||
|
elseShow={
|
||||||
|
<TablePlaceholder>
|
||||||
|
No project roles available. Get started by
|
||||||
|
adding one.
|
||||||
|
</TablePlaceholder>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
<ProjectRoleDeleteConfirm
|
<ProjectRoleDeleteConfirm
|
||||||
// @ts-expect-error
|
role={currentRole!}
|
||||||
role={currentRole}
|
|
||||||
open={delDialog}
|
open={delDialog}
|
||||||
setDeldialogue={setDelDialog}
|
setDeldialogue={setDelDialog}
|
||||||
handleDeleteRole={deleteProjectRole}
|
handleDeleteRole={deleteProjectRole}
|
||||||
confirmName={confirmName}
|
confirmName={confirmName}
|
||||||
setConfirmName={setConfirmName}
|
setConfirmName={setConfirmName}
|
||||||
/>
|
/>
|
||||||
</div>
|
</PageContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,61 +1,22 @@
|
|||||||
import { Button } from '@mui/material';
|
|
||||||
import { useContext } from 'react';
|
import { useContext } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
|
||||||
import AccessContext from 'contexts/AccessContext';
|
import AccessContext from 'contexts/AccessContext';
|
||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||||
import { PageHeader } from 'component/common/PageHeader/PageHeader';
|
|
||||||
import { PageContent } from 'component/common/PageContent/PageContent';
|
|
||||||
import { ADMIN } from 'component/providers/AccessProvider/permissions';
|
import { ADMIN } from 'component/providers/AccessProvider/permissions';
|
||||||
import AdminMenu from 'component/admin/menu/AdminMenu';
|
import AdminMenu from 'component/admin/menu/AdminMenu';
|
||||||
import { useStyles } from './ProjectRoles.styles';
|
|
||||||
import ProjectRoleList from './ProjectRoleList/ProjectRoleList';
|
import ProjectRoleList from './ProjectRoleList/ProjectRoleList';
|
||||||
import { AdminAlert } from 'component/common/AdminAlert/AdminAlert';
|
import { AdminAlert } from 'component/common/AdminAlert/AdminAlert';
|
||||||
|
|
||||||
const ProjectRoles = () => {
|
const ProjectRoles = () => {
|
||||||
const { hasAccess } = useContext(AccessContext);
|
const { hasAccess } = useContext(AccessContext);
|
||||||
const { classes: styles } = useStyles();
|
|
||||||
const navigate = useNavigate();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<AdminMenu />
|
<AdminMenu />
|
||||||
<PageContent
|
<ConditionallyRender
|
||||||
bodyClass={styles.rolesListBody}
|
condition={hasAccess(ADMIN)}
|
||||||
header={
|
show={<ProjectRoleList />}
|
||||||
<PageHeader
|
elseShow={<AdminAlert />}
|
||||||
title="Project Roles"
|
/>
|
||||||
actions={
|
|
||||||
<ConditionallyRender
|
|
||||||
condition={hasAccess(ADMIN)}
|
|
||||||
show={
|
|
||||||
<Button
|
|
||||||
variant="contained"
|
|
||||||
color="primary"
|
|
||||||
onClick={() =>
|
|
||||||
navigate(
|
|
||||||
'/admin/create-project-role'
|
|
||||||
)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
New Project role
|
|
||||||
</Button>
|
|
||||||
}
|
|
||||||
elseShow={
|
|
||||||
<small>
|
|
||||||
PS! Only admins can add/remove roles.
|
|
||||||
</small>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<ConditionallyRender
|
|
||||||
condition={hasAccess(ADMIN)}
|
|
||||||
show={<ProjectRoleList />}
|
|
||||||
elseShow={<AdminAlert />}
|
|
||||||
/>
|
|
||||||
</PageContent>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -0,0 +1,29 @@
|
|||||||
|
import { VFC } from 'react';
|
||||||
|
import { Box } from '@mui/material';
|
||||||
|
import { Highlighter } from 'component/common/Highlighter/Highlighter';
|
||||||
|
import { useSearchHighlightContext } from 'component/common/Table/SearchHighlightContext/SearchHighlightContext';
|
||||||
|
|
||||||
|
interface IHighlightCellProps {
|
||||||
|
value?: string | null;
|
||||||
|
children?: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const HighlightCell: VFC<IHighlightCellProps> = ({
|
||||||
|
value,
|
||||||
|
children,
|
||||||
|
}) => {
|
||||||
|
const { searchQuery } = useSearchHighlightContext();
|
||||||
|
|
||||||
|
const text = children ?? value;
|
||||||
|
if (!text) {
|
||||||
|
return <Box sx={{ py: 1.5, px: 2 }} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box sx={{ py: 1.5, px: 2 }}>
|
||||||
|
<span data-loading role="tooltip">
|
||||||
|
<Highlighter search={searchQuery}>{text}</Highlighter>
|
||||||
|
</span>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
@ -138,7 +138,14 @@ export const EnvironmentActionCell = ({
|
|||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={updatePermission}
|
condition={updatePermission}
|
||||||
show={
|
show={
|
||||||
<Tooltip title="Edit environment" arrow>
|
<Tooltip
|
||||||
|
title={
|
||||||
|
environment.protected
|
||||||
|
? 'You cannot edit environment'
|
||||||
|
: 'Edit environment'
|
||||||
|
}
|
||||||
|
arrow
|
||||||
|
>
|
||||||
<span id={editId}>
|
<span id={editId}>
|
||||||
<IconButton
|
<IconButton
|
||||||
aria-describedby={editId}
|
aria-describedby={editId}
|
||||||
@ -159,7 +166,14 @@ export const EnvironmentActionCell = ({
|
|||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={hasAccess(DELETE_ENVIRONMENT)}
|
condition={hasAccess(DELETE_ENVIRONMENT)}
|
||||||
show={
|
show={
|
||||||
<Tooltip title="Delete environment" arrow>
|
<Tooltip
|
||||||
|
title={
|
||||||
|
environment.protected
|
||||||
|
? 'You cannot delete environment'
|
||||||
|
: 'Delete environment'
|
||||||
|
}
|
||||||
|
arrow
|
||||||
|
>
|
||||||
<span id={deleteId}>
|
<span id={deleteId}>
|
||||||
<IconButton
|
<IconButton
|
||||||
aria-describedby={deleteId}
|
aria-describedby={deleteId}
|
||||||
|
@ -2,6 +2,8 @@ import { TextCell } from 'component/common/Table/cells/TextCell/TextCell';
|
|||||||
import { IEnvironment } from 'interfaces/environments';
|
import { IEnvironment } from 'interfaces/environments';
|
||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||||
import { StatusBadge } from 'component/common/StatusBadge/StatusBadge';
|
import { StatusBadge } from 'component/common/StatusBadge/StatusBadge';
|
||||||
|
import { Highlighter } from 'component/common/Highlighter/Highlighter';
|
||||||
|
import { useSearchHighlightContext } from 'component/common/Table/SearchHighlightContext/SearchHighlightContext';
|
||||||
|
|
||||||
interface IEnvironmentNameCellProps {
|
interface IEnvironmentNameCellProps {
|
||||||
environment: IEnvironment;
|
environment: IEnvironment;
|
||||||
@ -10,9 +12,11 @@ interface IEnvironmentNameCellProps {
|
|||||||
export const EnvironmentNameCell = ({
|
export const EnvironmentNameCell = ({
|
||||||
environment,
|
environment,
|
||||||
}: IEnvironmentNameCellProps) => {
|
}: IEnvironmentNameCellProps) => {
|
||||||
|
const { searchQuery } = useSearchHighlightContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TextCell>
|
<TextCell>
|
||||||
{environment.name}
|
<Highlighter search={searchQuery}>{environment.name}</Highlighter>
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={!environment.enabled}
|
condition={!environment.enabled}
|
||||||
show={<StatusBadge severity="warning">Disabled</StatusBadge>}
|
show={<StatusBadge severity="warning">Disabled</StatusBadge>}
|
||||||
|
Loading…
Reference in New Issue
Block a user