mirror of
https://github.com/Unleash/unleash.git
synced 2025-05-17 01:17:29 +02:00
feat: new contexts table (#998)
* feat: new contexts table * improve context list actions * refactor: disabled icon colors * fix: update snapshots * fix: icons * fix: context fields typo
This commit is contained in:
parent
c28cdab6e8
commit
6d130f61f6
@ -10,9 +10,6 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
textAlign: 'left',
|
textAlign: 'left',
|
||||||
maxWidth: '300px',
|
maxWidth: '300px',
|
||||||
},
|
},
|
||||||
icon: {
|
|
||||||
color: theme.palette.grey[600],
|
|
||||||
},
|
|
||||||
description: {
|
description: {
|
||||||
textAlign: 'left',
|
textAlign: 'left',
|
||||||
maxWidth: '300px',
|
maxWidth: '300px',
|
||||||
|
@ -2,7 +2,7 @@ import { useStyles } from './ProjectRoleListItem.styles';
|
|||||||
import { TableCell, TableRow, Typography } from '@mui/material';
|
import { TableCell, TableRow, Typography } from '@mui/material';
|
||||||
import { Delete, Edit } from '@mui/icons-material';
|
import { Delete, Edit } from '@mui/icons-material';
|
||||||
import { ADMIN } from 'component/providers/AccessProvider/permissions';
|
import { ADMIN } from 'component/providers/AccessProvider/permissions';
|
||||||
import SupervisedUserCircleIcon from '@mui/icons-material/SupervisedUserCircle';
|
import { SupervisedUserCircle } from '@mui/icons-material';
|
||||||
import PermissionIconButton from 'component/common/PermissionIconButton/PermissionIconButton';
|
import PermissionIconButton from 'component/common/PermissionIconButton/PermissionIconButton';
|
||||||
import { IProjectRole } from 'interfaces/role';
|
import { IProjectRole } from 'interfaces/role';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
@ -34,7 +34,7 @@ const RoleListItem = ({
|
|||||||
<>
|
<>
|
||||||
<TableRow className={styles.tableRow}>
|
<TableRow className={styles.tableRow}>
|
||||||
<TableCell className={styles.hideXS}>
|
<TableCell className={styles.hideXS}>
|
||||||
<SupervisedUserCircleIcon className={styles.icon} />
|
<SupervisedUserCircle color="disabled" />
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className={styles.leftTableCell}>
|
<TableCell className={styles.leftTableCell}>
|
||||||
<Typography variant="body2" data-loading>
|
<Typography variant="body2" data-loading>
|
||||||
|
@ -154,7 +154,7 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
height: '32.5px',
|
height: '32.5px',
|
||||||
width: '32.5px',
|
width: '32.5px',
|
||||||
marginRight: '0.5rem',
|
marginRight: '0.5rem',
|
||||||
fill: theme.palette.grey[600],
|
fill: theme.palette.inactiveIcon,
|
||||||
},
|
},
|
||||||
singleValueView: {
|
singleValueView: {
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
|
@ -14,7 +14,7 @@ const EnvironmentIcon = ({ enabled, className }: IEnvironmentIcon) => {
|
|||||||
const container = {
|
const container = {
|
||||||
backgroundColor: enabled
|
backgroundColor: enabled
|
||||||
? theme.palette.primary.light
|
? theme.palette.primary.light
|
||||||
: theme.palette.grey[600],
|
: theme.palette.inactiveIcon,
|
||||||
borderRadius: '50%',
|
borderRadius: '50%',
|
||||||
width: '28px',
|
width: '28px',
|
||||||
height: '28px',
|
height: '28px',
|
||||||
|
@ -17,6 +17,6 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
},
|
},
|
||||||
icon: {
|
icon: {
|
||||||
fontSize: '1rem',
|
fontSize: '1rem',
|
||||||
color: theme.palette.grey[600],
|
color: theme.palette.inactiveIcon,
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
@ -55,9 +55,11 @@ const PermissionIconButton = ({
|
|||||||
title={formatAccessText(access, tooltipProps?.title)}
|
title={formatAccessText(access, tooltipProps?.title)}
|
||||||
arrow
|
arrow
|
||||||
>
|
>
|
||||||
<IconButton {...rest} disabled={!access} size="large">
|
<div>
|
||||||
{children}
|
<IconButton {...rest} disabled={!access} size="large">
|
||||||
</IconButton>
|
{children}
|
||||||
|
</IconButton>
|
||||||
|
</div>
|
||||||
</TooltipResolver>
|
</TooltipResolver>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -20,7 +20,7 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
},
|
},
|
||||||
searchIcon: {
|
searchIcon: {
|
||||||
marginRight: 8,
|
marginRight: 8,
|
||||||
color: theme.palette.grey[600],
|
color: theme.palette.inactiveIcon,
|
||||||
},
|
},
|
||||||
inputRoot: {
|
inputRoot: {
|
||||||
width: '100%',
|
width: '100%',
|
||||||
|
@ -55,4 +55,16 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
alignLeft: {
|
||||||
|
justifyContent: 'flex-start',
|
||||||
|
textAlign: 'left',
|
||||||
|
},
|
||||||
|
alignRight: {
|
||||||
|
justifyContent: 'flex-end',
|
||||||
|
textAlign: 'right',
|
||||||
|
},
|
||||||
|
alignCenter: {
|
||||||
|
justifyContent: 'center',
|
||||||
|
textAlign: 'center',
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
|
@ -58,18 +58,18 @@ export const CellSortable: FC<ICellSortableProps> = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const justifyContent = useMemo(() => {
|
const alignClass = useMemo(() => {
|
||||||
switch (align) {
|
switch (align) {
|
||||||
case 'left':
|
case 'left':
|
||||||
return 'flex-start';
|
return styles.alignLeft;
|
||||||
case 'center':
|
case 'center':
|
||||||
return 'center';
|
return styles.alignCenter;
|
||||||
case 'right':
|
case 'right':
|
||||||
return 'flex-end';
|
return styles.alignRight;
|
||||||
default:
|
default:
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
}, [align]);
|
}, [align, styles]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const updateTitle = () => {
|
const updateTitle = () => {
|
||||||
@ -102,10 +102,10 @@ export const CellSortable: FC<ICellSortableProps> = ({
|
|||||||
<button
|
<button
|
||||||
className={classnames(
|
className={classnames(
|
||||||
isSorted && styles.sortedButton,
|
isSorted && styles.sortedButton,
|
||||||
styles.sortButton
|
styles.sortButton,
|
||||||
|
alignClass
|
||||||
)}
|
)}
|
||||||
onClick={onSortClick}
|
onClick={onSortClick}
|
||||||
style={{ justifyContent }}
|
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className={styles.label}
|
className={styles.label}
|
||||||
@ -122,7 +122,7 @@ export const CellSortable: FC<ICellSortableProps> = ({
|
|||||||
</button>
|
</button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
}
|
}
|
||||||
elseShow={children}
|
elseShow={<div className={alignClass}>{children}</div>}
|
||||||
/>
|
/>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
);
|
);
|
||||||
|
@ -28,7 +28,9 @@ export const SortableTableHeader: VFC<ISortableTableHeaderProps> = ({
|
|||||||
return (
|
return (
|
||||||
<CellSortable
|
<CellSortable
|
||||||
{...column.getHeaderProps(
|
{...column.getHeaderProps(
|
||||||
column.getSortByToggleProps()
|
column.canSort
|
||||||
|
? column.getSortByToggleProps()
|
||||||
|
: undefined
|
||||||
)}
|
)}
|
||||||
ariaTitle={
|
ariaTitle={
|
||||||
typeof content === 'string'
|
typeof content === 'string'
|
||||||
|
@ -25,7 +25,7 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
},
|
},
|
||||||
searchIcon: {
|
searchIcon: {
|
||||||
marginRight: 8,
|
marginRight: 8,
|
||||||
color: theme.palette.grey[600],
|
color: theme.palette.inactiveIcon,
|
||||||
},
|
},
|
||||||
clearContainer: {
|
clearContainer: {
|
||||||
width: '30px',
|
width: '30px',
|
||||||
@ -34,8 +34,6 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
clearIcon: {
|
clearIcon: {
|
||||||
// color: theme.palette.grey[700],
|
|
||||||
color: 'red',
|
|
||||||
fontSize: '18px',
|
fontSize: '18px',
|
||||||
},
|
},
|
||||||
inputRoot: {
|
inputRoot: {
|
||||||
|
@ -25,7 +25,7 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
},
|
},
|
||||||
searchIcon: {
|
searchIcon: {
|
||||||
marginRight: 8,
|
marginRight: 8,
|
||||||
color: theme.palette.grey[600],
|
color: theme.palette.inactiveIcon,
|
||||||
},
|
},
|
||||||
clearContainer: {
|
clearContainer: {
|
||||||
width: '30px',
|
width: '30px',
|
||||||
|
@ -1,60 +0,0 @@
|
|||||||
import { FC } from 'react';
|
|
||||||
import { Link, Typography } from '@mui/material';
|
|
||||||
import { Link as RouterLink } from 'react-router-dom';
|
|
||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
|
||||||
import { useStyles } from './FeatureLinkCell.styles';
|
|
||||||
import { Highlighter } from 'component/common/Highlighter/Highlighter';
|
|
||||||
import { useSearchHighlightContext } from 'component/common/Table/SearchHighlightContext/SearchHighlightContext';
|
|
||||||
|
|
||||||
interface IFeatureLinkCellProps {
|
|
||||||
title?: string;
|
|
||||||
to: string;
|
|
||||||
subtitle?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const FeatureLinkCell: FC<IFeatureLinkCellProps> = ({
|
|
||||||
title,
|
|
||||||
to,
|
|
||||||
subtitle,
|
|
||||||
}) => {
|
|
||||||
const { classes: styles } = useStyles();
|
|
||||||
const search = useSearchHighlightContext();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Link
|
|
||||||
component={RouterLink}
|
|
||||||
to={to}
|
|
||||||
underline="hover"
|
|
||||||
className={styles.wrapper}
|
|
||||||
>
|
|
||||||
<div className={styles.container}>
|
|
||||||
<span
|
|
||||||
data-loading
|
|
||||||
className={styles.title}
|
|
||||||
style={{
|
|
||||||
WebkitLineClamp: Boolean(subtitle) ? 1 : 2,
|
|
||||||
lineClamp: Boolean(subtitle) ? 1 : 2,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Highlighter search={search}>{title}</Highlighter>
|
|
||||||
</span>
|
|
||||||
<ConditionallyRender
|
|
||||||
condition={Boolean(subtitle)}
|
|
||||||
show={
|
|
||||||
<>
|
|
||||||
<Typography
|
|
||||||
className={styles.description}
|
|
||||||
component="span"
|
|
||||||
data-loading
|
|
||||||
>
|
|
||||||
<Highlighter search={search}>
|
|
||||||
{subtitle}
|
|
||||||
</Highlighter>
|
|
||||||
</Typography>
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Link>
|
|
||||||
);
|
|
||||||
};
|
|
@ -8,6 +8,6 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
},
|
},
|
||||||
icon: {
|
icon: {
|
||||||
color: theme.palette.grey[600],
|
color: theme.palette.inactiveIcon,
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
@ -9,6 +9,8 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
minHeight: '62px',
|
minHeight: '62px',
|
||||||
|
},
|
||||||
|
link: {
|
||||||
'&:hover, &:focus': {
|
'&:hover, &:focus': {
|
||||||
textDecoration: 'none',
|
textDecoration: 'none',
|
||||||
'& > div > span:first-of-type': {
|
'& > div > span:first-of-type': {
|
@ -0,0 +1,63 @@
|
|||||||
|
import { FC } from 'react';
|
||||||
|
import { Link, Typography } from '@mui/material';
|
||||||
|
import { Link as RouterLink } from 'react-router-dom';
|
||||||
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||||
|
import { useStyles } from './LinkCell.styles';
|
||||||
|
import { Highlighter } from 'component/common/Highlighter/Highlighter';
|
||||||
|
import { useSearchHighlightContext } from 'component/common/Table/SearchHighlightContext/SearchHighlightContext';
|
||||||
|
import classnames from 'classnames';
|
||||||
|
|
||||||
|
interface ILinkCellProps {
|
||||||
|
title?: string;
|
||||||
|
to?: string;
|
||||||
|
subtitle?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const LinkCell: FC<ILinkCellProps> = ({ title, to, subtitle }) => {
|
||||||
|
const { classes: styles } = useStyles();
|
||||||
|
const search = useSearchHighlightContext();
|
||||||
|
|
||||||
|
const content = (
|
||||||
|
<div className={styles.container}>
|
||||||
|
<span
|
||||||
|
data-loading
|
||||||
|
className={styles.title}
|
||||||
|
style={{
|
||||||
|
WebkitLineClamp: Boolean(subtitle) ? 1 : 2,
|
||||||
|
lineClamp: Boolean(subtitle) ? 1 : 2,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Highlighter search={search}>{title}</Highlighter>
|
||||||
|
</span>
|
||||||
|
<ConditionallyRender
|
||||||
|
condition={Boolean(subtitle)}
|
||||||
|
show={
|
||||||
|
<>
|
||||||
|
<Typography
|
||||||
|
className={styles.description}
|
||||||
|
component="span"
|
||||||
|
data-loading
|
||||||
|
>
|
||||||
|
<Highlighter search={search}>
|
||||||
|
{subtitle}
|
||||||
|
</Highlighter>
|
||||||
|
</Typography>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
return to ? (
|
||||||
|
<Link
|
||||||
|
component={RouterLink}
|
||||||
|
to={to}
|
||||||
|
underline="hover"
|
||||||
|
className={classnames(styles.wrapper, styles.link)}
|
||||||
|
>
|
||||||
|
{content}
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<span className={styles.wrapper}>{content}</span>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,45 @@
|
|||||||
|
import { useContext, VFC } from 'react';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
import { Button, IconButton, Tooltip, useMediaQuery } from '@mui/material';
|
||||||
|
import { Add } from '@mui/icons-material';
|
||||||
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||||
|
import AccessContext from 'contexts/AccessContext';
|
||||||
|
import { CREATE_CONTEXT_FIELD } from 'component/providers/AccessProvider/permissions';
|
||||||
|
|
||||||
|
interface IAddContextButtonProps {}
|
||||||
|
|
||||||
|
export const AddContextButton: VFC<IAddContextButtonProps> = () => {
|
||||||
|
const smallScreen = useMediaQuery('(max-width:700px)');
|
||||||
|
const { hasAccess } = useContext(AccessContext);
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ConditionallyRender
|
||||||
|
condition={hasAccess(CREATE_CONTEXT_FIELD)}
|
||||||
|
show={
|
||||||
|
<ConditionallyRender
|
||||||
|
condition={smallScreen}
|
||||||
|
show={
|
||||||
|
<Tooltip title="Add context type" arrow>
|
||||||
|
<IconButton
|
||||||
|
onClick={() => navigate('/context/create')}
|
||||||
|
size="large"
|
||||||
|
>
|
||||||
|
<Add />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
}
|
||||||
|
elseShow={
|
||||||
|
<Button
|
||||||
|
onClick={() => navigate('/context/create')}
|
||||||
|
color="primary"
|
||||||
|
variant="contained"
|
||||||
|
>
|
||||||
|
New context field
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,54 @@
|
|||||||
|
import { VFC } from 'react';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
import { Delete, Edit } from '@mui/icons-material';
|
||||||
|
import { Box } from '@mui/material';
|
||||||
|
import {
|
||||||
|
DELETE_CONTEXT_FIELD,
|
||||||
|
UPDATE_CONTEXT_FIELD,
|
||||||
|
} from 'component/providers/AccessProvider/permissions';
|
||||||
|
import PermissionIconButton from 'component/common/PermissionIconButton/PermissionIconButton';
|
||||||
|
|
||||||
|
interface IContextActionsCellProps {
|
||||||
|
name: string;
|
||||||
|
onDelete: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ContextActionsCell: VFC<IContextActionsCellProps> = ({
|
||||||
|
name,
|
||||||
|
onDelete,
|
||||||
|
}) => {
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
px: 2,
|
||||||
|
justifyContent: 'flex-end',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<PermissionIconButton
|
||||||
|
permission={UPDATE_CONTEXT_FIELD}
|
||||||
|
onClick={() => navigate(`/context/edit/${name}`)}
|
||||||
|
data-loading
|
||||||
|
aria-label="edit"
|
||||||
|
tooltipProps={{
|
||||||
|
title: 'Edit context field',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Edit />
|
||||||
|
</PermissionIconButton>
|
||||||
|
<PermissionIconButton
|
||||||
|
permission={DELETE_CONTEXT_FIELD}
|
||||||
|
onClick={onDelete}
|
||||||
|
data-loading
|
||||||
|
aria-label="delete"
|
||||||
|
tooltipProps={{
|
||||||
|
title: 'Delete context field',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Delete />
|
||||||
|
</PermissionIconButton>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
@ -1,42 +1,133 @@
|
|||||||
import { useContext, useState, VFC } from 'react';
|
import { useContext, useMemo, useState, VFC } from 'react';
|
||||||
import { Add, Album, Delete, Edit } from '@mui/icons-material';
|
import { useGlobalFilter, useSortBy, useTable } from 'react-table';
|
||||||
import { Link, useNavigate } from 'react-router-dom';
|
|
||||||
import {
|
import {
|
||||||
Button,
|
Table,
|
||||||
IconButton,
|
SortableTableHeader,
|
||||||
List,
|
TableBody,
|
||||||
ListItem,
|
TableCell,
|
||||||
ListItemIcon,
|
TableRow,
|
||||||
ListItemText,
|
TablePlaceholder,
|
||||||
Tooltip,
|
TableSearch,
|
||||||
useMediaQuery,
|
} from 'component/common/Table';
|
||||||
} from '@mui/material';
|
|
||||||
import { PageContent } from 'component/common/PageContent/PageContent';
|
import { PageContent } from 'component/common/PageContent/PageContent';
|
||||||
import { PageHeader } from 'component/common/PageHeader/PageHeader';
|
import { PageHeader } from 'component/common/PageHeader/PageHeader';
|
||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||||
import {
|
import { UPDATE_CONTEXT_FIELD } from 'component/providers/AccessProvider/permissions';
|
||||||
CREATE_CONTEXT_FIELD,
|
|
||||||
DELETE_CONTEXT_FIELD,
|
|
||||||
UPDATE_CONTEXT_FIELD,
|
|
||||||
} from 'component/providers/AccessProvider/permissions';
|
|
||||||
import { Dialogue as ConfirmDialogue } from 'component/common/Dialogue/Dialogue';
|
import { Dialogue as ConfirmDialogue } from 'component/common/Dialogue/Dialogue';
|
||||||
import AccessContext from 'contexts/AccessContext';
|
import AccessContext from 'contexts/AccessContext';
|
||||||
import useUnleashContext from 'hooks/api/getters/useUnleashContext/useUnleashContext';
|
import useUnleashContext from 'hooks/api/getters/useUnleashContext/useUnleashContext';
|
||||||
import useContextsApi from 'hooks/api/actions/useContextsApi/useContextsApi';
|
import useContextsApi from 'hooks/api/actions/useContextsApi/useContextsApi';
|
||||||
import useToast from 'hooks/useToast';
|
import useToast from 'hooks/useToast';
|
||||||
import { formatUnknownError } from 'utils/formatUnknownError';
|
import { formatUnknownError } from 'utils/formatUnknownError';
|
||||||
import { useStyles } from './styles';
|
import { AddContextButton } from './AddContextButton/AddContextButton';
|
||||||
|
import { SearchHighlightProvider } from 'component/common/Table/SearchHighlightContext/SearchHighlightContext';
|
||||||
|
import { sortTypes } from 'utils/sortTypes';
|
||||||
|
import { LinkCell } from 'component/common/Table/cells/LinkCell/LinkCell';
|
||||||
|
import { ContextActionsCell } from './ContextActionsCell/ContextActionsCell';
|
||||||
|
import { Adjust } from '@mui/icons-material';
|
||||||
|
import { Box } from '@mui/material';
|
||||||
|
|
||||||
const ContextList: VFC = () => {
|
const ContextList: VFC = () => {
|
||||||
const { hasAccess } = useContext(AccessContext);
|
const { hasAccess } = useContext(AccessContext);
|
||||||
const [showDelDialogue, setShowDelDialogue] = useState(false);
|
const [showDelDialogue, setShowDelDialogue] = useState(false);
|
||||||
const smallScreen = useMediaQuery('(max-width:700px)');
|
|
||||||
const [name, setName] = useState<string>();
|
const [name, setName] = useState<string>();
|
||||||
const { context, refetchUnleashContext } = useUnleashContext();
|
const { context, refetchUnleashContext, loading } = useUnleashContext();
|
||||||
const { removeContext } = useContextsApi();
|
const { removeContext } = useContextsApi();
|
||||||
const { setToastData, setToastApiError } = useToast();
|
const { setToastData, setToastApiError } = useToast();
|
||||||
const navigate = useNavigate();
|
const data = useMemo(() => {
|
||||||
const { classes: styles } = useStyles();
|
if (loading) {
|
||||||
|
return Array(5).fill({
|
||||||
|
name: 'Context name',
|
||||||
|
description: 'Context description when loading',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return context
|
||||||
|
.map(({ name, description, sortOrder }) => ({
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
sortOrder,
|
||||||
|
}))
|
||||||
|
.sort((a, b) => a.sortOrder - b.sortOrder);
|
||||||
|
}, [context, loading]);
|
||||||
|
|
||||||
|
const columns = useMemo(
|
||||||
|
() => [
|
||||||
|
{
|
||||||
|
id: 'Icon',
|
||||||
|
Cell: () => (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
pl: 2,
|
||||||
|
pr: 1,
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Adjust color="disabled" />
|
||||||
|
</Box>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Header: 'Name',
|
||||||
|
accessor: 'name',
|
||||||
|
width: '90%',
|
||||||
|
Cell: ({
|
||||||
|
row: {
|
||||||
|
original: { name, description },
|
||||||
|
},
|
||||||
|
}: any) => (
|
||||||
|
<LinkCell
|
||||||
|
title={name}
|
||||||
|
to={
|
||||||
|
hasAccess(UPDATE_CONTEXT_FIELD)
|
||||||
|
? `/context/edit/${name}`
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
subtitle={description}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
sortType: 'alphanumeric',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Header: 'Actions',
|
||||||
|
id: 'Actions',
|
||||||
|
align: 'center',
|
||||||
|
Cell: ({
|
||||||
|
row: {
|
||||||
|
original: { name },
|
||||||
|
},
|
||||||
|
}: any) => (
|
||||||
|
<ContextActionsCell
|
||||||
|
name={name}
|
||||||
|
onDelete={() => {
|
||||||
|
setName(name);
|
||||||
|
setShowDelDialogue(true);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
width: 150,
|
||||||
|
disableSortBy: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessor: 'description',
|
||||||
|
disableSortBy: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessor: 'sortOrder',
|
||||||
|
sortType: 'number',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[hasAccess]
|
||||||
|
);
|
||||||
|
|
||||||
|
const initialState = useMemo(
|
||||||
|
() => ({
|
||||||
|
sortBy: [{ id: 'name', desc: false }],
|
||||||
|
hiddenColumns: ['description', 'sortOrder'],
|
||||||
|
}),
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
const onDeleteContext = async () => {
|
const onDeleteContext = async () => {
|
||||||
try {
|
try {
|
||||||
@ -57,103 +148,86 @@ const ContextList: VFC = () => {
|
|||||||
setShowDelDialogue(false);
|
setShowDelDialogue(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const contextList = () =>
|
const {
|
||||||
context.map(field => (
|
getTableProps,
|
||||||
<ListItem key={field.name} classes={{ root: styles.listItem }}>
|
getTableBodyProps,
|
||||||
<ListItemIcon>
|
headerGroups,
|
||||||
<Album />
|
rows,
|
||||||
</ListItemIcon>
|
prepareRow,
|
||||||
<ListItemText
|
state: { globalFilter },
|
||||||
primary={
|
setGlobalFilter,
|
||||||
<ConditionallyRender
|
} = useTable(
|
||||||
condition={hasAccess(UPDATE_CONTEXT_FIELD)}
|
{
|
||||||
show={
|
columns: columns as any[], // TODO: fix after `react-table` v8 update
|
||||||
<Link to={`/context/edit/${field.name}`}>
|
data,
|
||||||
<strong>{field.name}</strong>
|
initialState,
|
||||||
</Link>
|
sortTypes,
|
||||||
}
|
autoResetGlobalFilter: false,
|
||||||
elseShow={<strong>{field.name}</strong>}
|
autoResetSortBy: false,
|
||||||
/>
|
disableSortRemove: true,
|
||||||
}
|
},
|
||||||
secondary={field.description}
|
useGlobalFilter,
|
||||||
/>
|
useSortBy
|
||||||
<ConditionallyRender
|
|
||||||
condition={hasAccess(UPDATE_CONTEXT_FIELD)}
|
|
||||||
show={
|
|
||||||
<Tooltip title="Edit context field" arrow>
|
|
||||||
<IconButton
|
|
||||||
onClick={() =>
|
|
||||||
navigate(`/context/edit/${field.name}`)
|
|
||||||
}
|
|
||||||
size="large"
|
|
||||||
>
|
|
||||||
<Edit />
|
|
||||||
</IconButton>
|
|
||||||
</Tooltip>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<ConditionallyRender
|
|
||||||
condition={hasAccess(DELETE_CONTEXT_FIELD)}
|
|
||||||
show={
|
|
||||||
<Tooltip title="Delete context field" arrow>
|
|
||||||
<IconButton
|
|
||||||
aria-label="delete"
|
|
||||||
onClick={() => {
|
|
||||||
setName(field.name);
|
|
||||||
setShowDelDialogue(true);
|
|
||||||
}}
|
|
||||||
size="large"
|
|
||||||
>
|
|
||||||
<Delete />
|
|
||||||
</IconButton>
|
|
||||||
</Tooltip>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</ListItem>
|
|
||||||
));
|
|
||||||
const headerButton = () => (
|
|
||||||
<ConditionallyRender
|
|
||||||
condition={hasAccess(CREATE_CONTEXT_FIELD)}
|
|
||||||
show={
|
|
||||||
<ConditionallyRender
|
|
||||||
condition={smallScreen}
|
|
||||||
show={
|
|
||||||
<Tooltip title="Add context type" arrow>
|
|
||||||
<IconButton
|
|
||||||
onClick={() => navigate('/context/create')}
|
|
||||||
size="large"
|
|
||||||
>
|
|
||||||
<Add />
|
|
||||||
</IconButton>
|
|
||||||
</Tooltip>
|
|
||||||
}
|
|
||||||
elseShow={
|
|
||||||
<Button
|
|
||||||
onClick={() => navigate('/context/create')}
|
|
||||||
color="primary"
|
|
||||||
variant="contained"
|
|
||||||
>
|
|
||||||
New context field
|
|
||||||
</Button>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageContent
|
<PageContent
|
||||||
header={
|
header={
|
||||||
<PageHeader actions={headerButton()} title={'Context fields'} />
|
<PageHeader
|
||||||
|
title="Context fields"
|
||||||
|
actions={
|
||||||
|
<>
|
||||||
|
<TableSearch
|
||||||
|
initialValue={globalFilter}
|
||||||
|
onChange={setGlobalFilter}
|
||||||
|
/>
|
||||||
|
<PageHeader.Divider />
|
||||||
|
<AddContextButton />
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
/>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<List>
|
<SearchHighlightProvider value={globalFilter}>
|
||||||
<ConditionallyRender
|
<Table {...getTableProps()}>
|
||||||
condition={context.length > 0}
|
<SortableTableHeader headerGroups={headerGroups} />
|
||||||
show={contextList}
|
<TableBody {...getTableBodyProps()}>
|
||||||
elseShow={<ListItem>No context fields defined</ListItem>}
|
{rows.map(row => {
|
||||||
/>
|
prepareRow(row);
|
||||||
</List>
|
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 contexts found matching “
|
||||||
|
{globalFilter}
|
||||||
|
”
|
||||||
|
</TablePlaceholder>
|
||||||
|
}
|
||||||
|
elseShow={
|
||||||
|
<TablePlaceholder>
|
||||||
|
No contexts available. Get started by adding
|
||||||
|
one.
|
||||||
|
</TablePlaceholder>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
<ConfirmDialogue
|
<ConfirmDialogue
|
||||||
open={showDelDialogue}
|
open={showDelDialogue}
|
||||||
onClick={onDeleteContext}
|
onClick={onDeleteContext}
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
import { makeStyles } from 'tss-react/mui';
|
|
||||||
|
|
||||||
export const useStyles = makeStyles()({
|
|
||||||
listItem: {
|
|
||||||
padding: 0,
|
|
||||||
'& a': {
|
|
||||||
textDecoration: 'none',
|
|
||||||
color: 'inherit',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
@ -11,7 +11,7 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
minWidth: '450px',
|
minWidth: '450px',
|
||||||
},
|
},
|
||||||
icon: {
|
icon: {
|
||||||
fill: theme.palette.grey[600],
|
fill: theme.palette.inactiveIcon,
|
||||||
marginRight: '0.5rem',
|
marginRight: '0.5rem',
|
||||||
},
|
},
|
||||||
header: {
|
header: {
|
||||||
|
@ -13,7 +13,7 @@ import {
|
|||||||
} from 'component/common/Table';
|
} from 'component/common/Table';
|
||||||
import { SearchHighlightProvider } from 'component/common/Table/SearchHighlightContext/SearchHighlightContext';
|
import { SearchHighlightProvider } from 'component/common/Table/SearchHighlightContext/SearchHighlightContext';
|
||||||
import { DateCell } from '../../../common/Table/cells/DateCell/DateCell';
|
import { DateCell } from '../../../common/Table/cells/DateCell/DateCell';
|
||||||
import { FeatureLinkCell } from 'component/common/Table/cells/FeatureLinkCell/FeatureLinkCell';
|
import { LinkCell } from 'component/common/Table/cells/LinkCell/LinkCell';
|
||||||
import { FeatureSeenCell } from 'component/common/Table/cells/FeatureSeenCell/FeatureSeenCell';
|
import { FeatureSeenCell } from 'component/common/Table/cells/FeatureSeenCell/FeatureSeenCell';
|
||||||
import { FeatureTypeCell } from 'component/common/Table/cells/FeatureTypeCell/FeatureTypeCell';
|
import { FeatureTypeCell } from 'component/common/Table/cells/FeatureTypeCell/FeatureTypeCell';
|
||||||
import { FeatureStaleCell } from './FeatureStaleCell/FeatureStaleCell';
|
import { FeatureStaleCell } from './FeatureStaleCell/FeatureStaleCell';
|
||||||
@ -53,7 +53,7 @@ const columns = [
|
|||||||
original: { name, description, project },
|
original: { name, description, project },
|
||||||
},
|
},
|
||||||
}) => (
|
}) => (
|
||||||
<FeatureLinkCell
|
<LinkCell
|
||||||
title={name}
|
title={name}
|
||||||
subtitle={description}
|
subtitle={description}
|
||||||
to={`/projects/${project}/features/${name}`}
|
to={`/projects/${project}/features/${name}`}
|
||||||
@ -71,7 +71,7 @@ const columns = [
|
|||||||
Header: 'Project ID',
|
Header: 'Project ID',
|
||||||
accessor: 'project',
|
accessor: 'project',
|
||||||
Cell: ({ value }: { value: string }) => (
|
Cell: ({ value }: { value: string }) => (
|
||||||
<FeatureLinkCell title={value} to={`/projects/${value}`} />
|
<LinkCell title={value} to={`/projects/${value}`} />
|
||||||
),
|
),
|
||||||
sortType: 'alphanumeric',
|
sortType: 'alphanumeric',
|
||||||
},
|
},
|
||||||
|
@ -116,7 +116,7 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
strategyIcon: {
|
strategyIcon: {
|
||||||
fill: theme.palette.grey[600],
|
fill: theme.palette.inactiveIcon,
|
||||||
},
|
},
|
||||||
container: {
|
container: {
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
|
@ -16,7 +16,7 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
borderBottom: `1px solid ${theme.palette.grey[300]}`,
|
borderBottom: `1px solid ${theme.palette.grey[300]}`,
|
||||||
},
|
},
|
||||||
icon: {
|
icon: {
|
||||||
fill: theme.palette.grey[600],
|
fill: theme.palette.inactiveIcon,
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
marginLeft: 'auto',
|
marginLeft: 'auto',
|
||||||
|
@ -2,6 +2,6 @@ import { makeStyles } from 'tss-react/mui';
|
|||||||
|
|
||||||
export const useStyles = makeStyles()(theme => ({
|
export const useStyles = makeStyles()(theme => ({
|
||||||
icon: {
|
icon: {
|
||||||
color: theme.palette.grey[600],
|
color: theme.palette.inactiveIcon,
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
@ -32,6 +32,6 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
},
|
},
|
||||||
closeIcon: {
|
closeIcon: {
|
||||||
fontSize: '1.5rem',
|
fontSize: '1.5rem',
|
||||||
color: theme.palette.grey[600],
|
color: theme.palette.inactiveIcon,
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
@ -14,7 +14,7 @@ import {
|
|||||||
useMediaQuery,
|
useMediaQuery,
|
||||||
useTheme,
|
useTheme,
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import ViewColumnIcon from '@mui/icons-material/ViewColumn';
|
import ColumnIcon from '@mui/icons-material/ViewWeek';
|
||||||
import CloseIcon from '@mui/icons-material/Close';
|
import CloseIcon from '@mui/icons-material/Close';
|
||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||||
import { useStyles } from './ColumnsMenu.styles';
|
import { useStyles } from './ColumnsMenu.styles';
|
||||||
@ -105,7 +105,7 @@ export const ColumnsMenu: VFC<IColumnsMenuProps> = ({
|
|||||||
className={classes.button}
|
className={classes.button}
|
||||||
data-loading
|
data-loading
|
||||||
>
|
>
|
||||||
<ViewColumnIcon />
|
<ColumnIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ import { CREATE_FEATURE } from 'component/providers/AccessProvider/permissions';
|
|||||||
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
||||||
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
|
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
|
||||||
import { DateCell } from 'component/common/Table/cells/DateCell/DateCell';
|
import { DateCell } from 'component/common/Table/cells/DateCell/DateCell';
|
||||||
import { FeatureLinkCell } from 'component/common/Table/cells/FeatureLinkCell/FeatureLinkCell';
|
import { LinkCell } from 'component/common/Table/cells/LinkCell/LinkCell';
|
||||||
import { FeatureSeenCell } from 'component/common/Table/cells/FeatureSeenCell/FeatureSeenCell';
|
import { FeatureSeenCell } from 'component/common/Table/cells/FeatureSeenCell/FeatureSeenCell';
|
||||||
import { FeatureTypeCell } from 'component/common/Table/cells/FeatureTypeCell/FeatureTypeCell';
|
import { FeatureTypeCell } from 'component/common/Table/cells/FeatureTypeCell/FeatureTypeCell';
|
||||||
import { sortTypes } from 'utils/sortTypes';
|
import { sortTypes } from 'utils/sortTypes';
|
||||||
@ -176,7 +176,7 @@ export const ProjectFeatureToggles = ({
|
|||||||
Header: 'Feature toggle name',
|
Header: 'Feature toggle name',
|
||||||
accessor: 'name',
|
accessor: 'name',
|
||||||
Cell: ({ value }: { value: string }) => (
|
Cell: ({ value }: { value: string }) => (
|
||||||
<FeatureLinkCell
|
<LinkCell
|
||||||
title={value}
|
title={value}
|
||||||
to={`/projects/${projectId}/features/${value}`}
|
to={`/projects/${projectId}/features/${value}`}
|
||||||
/>
|
/>
|
||||||
@ -271,6 +271,7 @@ export const ProjectFeatureToggles = ({
|
|||||||
() => filters?.find(filterRow => filterRow?.id === 'name')?.value || '',
|
() => filters?.find(filterRow => filterRow?.id === 'name')?.value || '',
|
||||||
[filters]
|
[filters]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageContent
|
<PageContent
|
||||||
isLoading={loading}
|
isLoading={loading}
|
||||||
|
@ -11,7 +11,7 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
maxWidth: '300px',
|
maxWidth: '300px',
|
||||||
},
|
},
|
||||||
icon: {
|
icon: {
|
||||||
color: theme.palette.grey[600],
|
color: theme.palette.inactiveIcon,
|
||||||
},
|
},
|
||||||
descriptionCell: {
|
descriptionCell: {
|
||||||
textAlign: 'left',
|
textAlign: 'left',
|
||||||
|
@ -255,7 +255,7 @@ export const StrategiesList = () => {
|
|||||||
strategies.map(strategy => (
|
strategies.map(strategy => (
|
||||||
<ListItem key={strategy.name} className={styles.listItem}>
|
<ListItem key={strategy.name} className={styles.listItem}>
|
||||||
<ListItemAvatar>
|
<ListItemAvatar>
|
||||||
<Extension style={{ color: '#0000008a' }} />
|
<Extension color="disabled" />
|
||||||
</ListItemAvatar>
|
</ListItemAvatar>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary={strategyLink(strategy?.name, strategy?.deprecated)}
|
primary={strategyLink(strategy?.name, strategy?.deprecated)}
|
||||||
|
@ -80,14 +80,9 @@ exports[`renders correctly 1`] = `
|
|||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
aria-hidden={true}
|
aria-hidden={true}
|
||||||
className="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium mui-i4bv87-MuiSvgIcon-root"
|
className="MuiSvgIcon-root MuiSvgIcon-colorDisabled MuiSvgIcon-fontSizeMedium mui-1db085k-MuiSvgIcon-root"
|
||||||
data-testid="ExtensionIcon"
|
data-testid="ExtensionIcon"
|
||||||
focusable="false"
|
focusable="false"
|
||||||
style={
|
|
||||||
{
|
|
||||||
"color": "#0000008a",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
>
|
>
|
||||||
<path
|
<path
|
||||||
@ -117,44 +112,53 @@ exports[`renders correctly 1`] = `
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<button
|
<div
|
||||||
aria-label="Deprecate strategy"
|
aria-label="Deprecate strategy"
|
||||||
aria-labelledby={null}
|
aria-labelledby={null}
|
||||||
className="MuiButtonBase-root MuiIconButton-root MuiIconButton-sizeLarge mui-mf1cb5-MuiButtonBase-root-MuiIconButton-root"
|
className=""
|
||||||
data-mui-internal-clone-element={true}
|
data-mui-internal-clone-element={true}
|
||||||
disabled={false}
|
|
||||||
onBlur={[Function]}
|
onBlur={[Function]}
|
||||||
onClick={[Function]}
|
|
||||||
onContextMenu={[Function]}
|
|
||||||
onDragLeave={[Function]}
|
|
||||||
onFocus={[Function]}
|
onFocus={[Function]}
|
||||||
onKeyDown={[Function]}
|
|
||||||
onKeyUp={[Function]}
|
|
||||||
onMouseDown={[Function]}
|
|
||||||
onMouseLeave={[Function]}
|
onMouseLeave={[Function]}
|
||||||
onMouseOver={[Function]}
|
onMouseOver={[Function]}
|
||||||
onMouseUp={[Function]}
|
|
||||||
onTouchEnd={[Function]}
|
onTouchEnd={[Function]}
|
||||||
onTouchMove={[Function]}
|
|
||||||
onTouchStart={[Function]}
|
onTouchStart={[Function]}
|
||||||
tabIndex={0}
|
|
||||||
type="button"
|
|
||||||
>
|
>
|
||||||
<svg
|
<button
|
||||||
aria-hidden={true}
|
className="MuiButtonBase-root MuiIconButton-root MuiIconButton-sizeLarge mui-mf1cb5-MuiButtonBase-root-MuiIconButton-root"
|
||||||
className="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium mui-i4bv87-MuiSvgIcon-root"
|
disabled={false}
|
||||||
data-testid="VisibilityIcon"
|
onBlur={[Function]}
|
||||||
focusable="false"
|
onClick={[Function]}
|
||||||
viewBox="0 0 24 24"
|
onContextMenu={[Function]}
|
||||||
|
onDragLeave={[Function]}
|
||||||
|
onFocus={[Function]}
|
||||||
|
onKeyDown={[Function]}
|
||||||
|
onKeyUp={[Function]}
|
||||||
|
onMouseDown={[Function]}
|
||||||
|
onMouseLeave={[Function]}
|
||||||
|
onMouseUp={[Function]}
|
||||||
|
onTouchEnd={[Function]}
|
||||||
|
onTouchMove={[Function]}
|
||||||
|
onTouchStart={[Function]}
|
||||||
|
tabIndex={0}
|
||||||
|
type="button"
|
||||||
>
|
>
|
||||||
<path
|
<svg
|
||||||
d="M12 4.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5zM12 17c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z"
|
aria-hidden={true}
|
||||||
|
className="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium mui-i4bv87-MuiSvgIcon-root"
|
||||||
|
data-testid="VisibilityIcon"
|
||||||
|
focusable="false"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M12 4.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5zM12 17c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
<span
|
||||||
|
className="MuiTouchRipple-root mui-8je8zh-MuiTouchRipple-root"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</button>
|
||||||
<span
|
</div>
|
||||||
className="MuiTouchRipple-root mui-8je8zh-MuiTouchRipple-root"
|
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
aria-label="You cannot delete a built-in strategy"
|
aria-label="You cannot delete a built-in strategy"
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import useSWR, { mutate, SWRConfiguration } from 'swr';
|
import useSWR, { SWRConfiguration } from 'swr';
|
||||||
import { useState, useEffect } from 'react';
|
|
||||||
import { formatApiPath } from 'utils/formatPath';
|
import { formatApiPath } from 'utils/formatPath';
|
||||||
import handleErrorResponses from '../httpErrorResponseHandler';
|
import handleErrorResponses from '../httpErrorResponseHandler';
|
||||||
import { IUnleashContextDefinition } from 'interfaces/context';
|
import { IUnleashContextDefinition } from 'interfaces/context';
|
||||||
@ -9,7 +8,6 @@ interface IUnleashContextOutput {
|
|||||||
refetchUnleashContext: () => void;
|
refetchUnleashContext: () => void;
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
error?: Error;
|
error?: Error;
|
||||||
CONTEXT_CACHE_KEY: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const useUnleashContext = (
|
const useUnleashContext = (
|
||||||
@ -30,24 +28,17 @@ const useUnleashContext = (
|
|||||||
|
|
||||||
const CONTEXT_CACHE_KEY = 'api/admin/context';
|
const CONTEXT_CACHE_KEY = 'api/admin/context';
|
||||||
|
|
||||||
const { data, error } = useSWR(CONTEXT_CACHE_KEY, fetcher, options);
|
const { data, mutate, error, isValidating } = useSWR(
|
||||||
|
CONTEXT_CACHE_KEY,
|
||||||
const [loading, setLoading] = useState(!error && !data);
|
fetcher,
|
||||||
|
options
|
||||||
const refetchUnleashContext = () => {
|
);
|
||||||
mutate(CONTEXT_CACHE_KEY);
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setLoading(!error && !data);
|
|
||||||
}, [data, error]);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
context: data || [],
|
context: data || [],
|
||||||
error,
|
error,
|
||||||
loading,
|
loading: isValidating && !error && !data,
|
||||||
refetchUnleashContext,
|
refetchUnleashContext: mutate,
|
||||||
CONTEXT_CACHE_KEY,
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -100,6 +100,7 @@ export default createTheme({
|
|||||||
inactive: colors.orange[200],
|
inactive: colors.orange[200],
|
||||||
abandoned: colors.red[200],
|
abandoned: colors.red[200],
|
||||||
},
|
},
|
||||||
|
inactiveIcon: colors.grey[600],
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
MuiLink: {
|
MuiLink: {
|
||||||
@ -244,5 +245,12 @@ export default createTheme({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
MuiIcon: {
|
||||||
|
styleOverrides: {
|
||||||
|
colorDisabled: {
|
||||||
|
color: colors.grey[600],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -61,6 +61,14 @@ declare module '@mui/material/styles' {
|
|||||||
* For sidebar container background.
|
* For sidebar container background.
|
||||||
*/
|
*/
|
||||||
sidebarContainer: string;
|
sidebarContainer: string;
|
||||||
|
/**
|
||||||
|
* Icon that doesn't have an action (visual only, no click handler).
|
||||||
|
*
|
||||||
|
* @deprecated use `<YourIcon color="disabled" />`.
|
||||||
|
* ⚠️ `color` only works with `import { YourIcon } from "@mui/icons"`
|
||||||
|
* and not with `import YourIcon from "@mui/icons/YourIcon"`.
|
||||||
|
*/
|
||||||
|
inactiveIcon: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Theme extends CustomTheme {}
|
interface Theme extends CustomTheme {}
|
||||||
|
Loading…
Reference in New Issue
Block a user