mirror of
https://github.com/Unleash/unleash.git
synced 2025-05-31 01:16:01 +02:00
Merge branch 'main' into task/Add_strategy_information_to_playground_results
# Conflicts: # src/component/common/StrategySeparator/StrategySeparator.tsx
This commit is contained in:
commit
13a536904f
@ -49,7 +49,7 @@
|
|||||||
"@testing-library/jest-dom": "5.16.4",
|
"@testing-library/jest-dom": "5.16.4",
|
||||||
"@testing-library/react": "12.1.5",
|
"@testing-library/react": "12.1.5",
|
||||||
"@testing-library/react-hooks": "^7.0.2",
|
"@testing-library/react-hooks": "^7.0.2",
|
||||||
"@testing-library/user-event": "14.3.0",
|
"@testing-library/user-event": "14.4.1",
|
||||||
"@types/debounce": "1.2.1",
|
"@types/debounce": "1.2.1",
|
||||||
"@types/deep-diff": "1.0.1",
|
"@types/deep-diff": "1.0.1",
|
||||||
"@types/jest": "28.1.6",
|
"@types/jest": "28.1.6",
|
||||||
@ -66,7 +66,7 @@
|
|||||||
"chart.js": "3.8.2",
|
"chart.js": "3.8.2",
|
||||||
"chartjs-adapter-date-fns": "2.0.0",
|
"chartjs-adapter-date-fns": "2.0.0",
|
||||||
"classnames": "2.3.1",
|
"classnames": "2.3.1",
|
||||||
"copy-to-clipboard": "3.3.1",
|
"copy-to-clipboard": "3.3.2",
|
||||||
"cypress": "9.7.0",
|
"cypress": "9.7.0",
|
||||||
"date-fns": "2.29.1",
|
"date-fns": "2.29.1",
|
||||||
"debounce": "1.2.1",
|
"debounce": "1.2.1",
|
||||||
@ -91,7 +91,7 @@
|
|||||||
"react-table": "7.8.0",
|
"react-table": "7.8.0",
|
||||||
"react-test-renderer": "17.0.2",
|
"react-test-renderer": "17.0.2",
|
||||||
"react-timeago": "7.1.0",
|
"react-timeago": "7.1.0",
|
||||||
"sass": "1.54.0",
|
"sass": "1.54.2",
|
||||||
"semver": "7.3.7",
|
"semver": "7.3.7",
|
||||||
"swr": "1.3.0",
|
"swr": "1.3.0",
|
||||||
"tss-react": "3.7.1",
|
"tss-react": "3.7.1",
|
||||||
@ -103,7 +103,7 @@
|
|||||||
"vitest": "0.20.3",
|
"vitest": "0.20.3",
|
||||||
"whatwg-fetch": "^3.6.2",
|
"whatwg-fetch": "^3.6.2",
|
||||||
"@codemirror/lang-json": "6.0.0",
|
"@codemirror/lang-json": "6.0.0",
|
||||||
"@codemirror/state": "6.1.0",
|
"@codemirror/state": "6.1.1",
|
||||||
"@uiw/react-codemirror": "^4.11.4",
|
"@uiw/react-codemirror": "^4.11.4",
|
||||||
"codemirror": "^6.0.1"
|
"codemirror": "^6.0.1"
|
||||||
},
|
},
|
||||||
|
@ -255,7 +255,7 @@ export const Group: VFC = () => {
|
|||||||
onClick={() => setRemoveOpen(true)}
|
onClick={() => setRemoveOpen(true)}
|
||||||
permission={ADMIN}
|
permission={ADMIN}
|
||||||
tooltipProps={{
|
tooltipProps={{
|
||||||
title: 'Remove group',
|
title: 'Delete group',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<StyledDelete />
|
<StyledDelete />
|
||||||
|
@ -81,6 +81,7 @@ export const GroupForm: FC<IGroupForm> = ({
|
|||||||
value={name}
|
value={name}
|
||||||
onChange={e => setName(e.target.value)}
|
onChange={e => setName(e.target.value)}
|
||||||
data-testid={UG_NAME_ID}
|
data-testid={UG_NAME_ID}
|
||||||
|
required
|
||||||
/>
|
/>
|
||||||
<StyledInputDescription>
|
<StyledInputDescription>
|
||||||
How would you describe your group?
|
How would you describe your group?
|
||||||
|
@ -2,25 +2,11 @@ import { capitalize, MenuItem, Select, styled } from '@mui/material';
|
|||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||||
import { TextCell } from 'component/common/Table/cells/TextCell/TextCell';
|
import { TextCell } from 'component/common/Table/cells/TextCell/TextCell';
|
||||||
import { Role } from 'interfaces/group';
|
import { Role } from 'interfaces/group';
|
||||||
|
import { Badge } from 'component/common/Badge/Badge';
|
||||||
|
import { StarRounded } from '@mui/icons-material';
|
||||||
|
|
||||||
const StyledBadge = styled('div')(({ theme }) => ({
|
const StyledPopupStar = styled(StarRounded)(({ theme }) => ({
|
||||||
padding: theme.spacing(0.5, 1),
|
color: theme.palette.warning.main,
|
||||||
textDecoration: 'none',
|
|
||||||
color: theme.palette.text.secondary,
|
|
||||||
border: `1px solid ${theme.palette.dividerAlternative}`,
|
|
||||||
background: theme.palette.activityIndicators.unknown,
|
|
||||||
display: 'inline-block',
|
|
||||||
borderRadius: theme.shape.borderRadius,
|
|
||||||
marginLeft: theme.spacing(1.5),
|
|
||||||
fontSize: theme.fontSizes.smallerBody,
|
|
||||||
fontWeight: theme.fontWeight.bold,
|
|
||||||
lineHeight: 1,
|
|
||||||
}));
|
|
||||||
|
|
||||||
const StyledOwnerBadge = styled(StyledBadge)(({ theme }) => ({
|
|
||||||
color: theme.palette.success.dark,
|
|
||||||
border: `1px solid ${theme.palette.success.border}`,
|
|
||||||
background: theme.palette.success.light,
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
interface IGroupUserRoleCellProps {
|
interface IGroupUserRoleCellProps {
|
||||||
@ -35,8 +21,12 @@ export const GroupUserRoleCell = ({
|
|||||||
const renderBadge = () => (
|
const renderBadge = () => (
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={value === Role.Member}
|
condition={value === Role.Member}
|
||||||
show={<StyledBadge>{capitalize(value)}</StyledBadge>}
|
show={<Badge>{capitalize(value)}</Badge>}
|
||||||
elseShow={<StyledOwnerBadge>{capitalize(value)}</StyledOwnerBadge>}
|
elseShow={
|
||||||
|
<Badge color="success" icon={<StyledPopupStar />}>
|
||||||
|
{capitalize(value)}
|
||||||
|
</Badge>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { styled, Tooltip } from '@mui/material';
|
import { styled, Tooltip } from '@mui/material';
|
||||||
import { IGroup } from 'interfaces/group';
|
import { IGroup } from 'interfaces/group';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link, useNavigate } from 'react-router-dom';
|
||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||||
import { GroupCardAvatars } from './GroupCardAvatars/GroupCardAvatars';
|
import { GroupCardAvatars } from './GroupCardAvatars/GroupCardAvatars';
|
||||||
import { Badge } from 'component/common/Badge/Badge';
|
import { Badge } from 'component/common/Badge/Badge';
|
||||||
@ -20,9 +20,15 @@ const StyledGroupCard = styled('aside')(({ theme }) => ({
|
|||||||
border: `1px solid ${theme.palette.dividerAlternative}`,
|
border: `1px solid ${theme.palette.dividerAlternative}`,
|
||||||
borderRadius: theme.shape.borderRadiusLarge,
|
borderRadius: theme.shape.borderRadiusLarge,
|
||||||
boxShadow: theme.boxShadows.card,
|
boxShadow: theme.boxShadows.card,
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
[theme.breakpoints.up('md')]: {
|
[theme.breakpoints.up('md')]: {
|
||||||
padding: theme.spacing(4),
|
padding: theme.spacing(4),
|
||||||
},
|
},
|
||||||
|
'&:hover': {
|
||||||
|
transition: 'background-color 0.2s ease-in-out',
|
||||||
|
backgroundColor: theme.palette.neutral.light,
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const StyledRow = styled('div')(() => ({
|
const StyledRow = styled('div')(() => ({
|
||||||
@ -31,6 +37,14 @@ const StyledRow = styled('div')(() => ({
|
|||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
const StyledTitleRow = styled(StyledRow)(() => ({
|
||||||
|
alignItems: 'flex-start',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StyledBottomRow = styled(StyledRow)(() => ({
|
||||||
|
marginTop: 'auto',
|
||||||
|
}));
|
||||||
|
|
||||||
const StyledHeaderTitle = styled('h2')(({ theme }) => ({
|
const StyledHeaderTitle = styled('h2')(({ theme }) => ({
|
||||||
fontSize: theme.fontSizes.mainHeader,
|
fontSize: theme.fontSizes.mainHeader,
|
||||||
fontWeight: theme.fontWeight.medium,
|
fontWeight: theme.fontWeight.medium,
|
||||||
@ -55,7 +69,13 @@ const StyledCounterDescription = styled('span')(({ theme }) => ({
|
|||||||
marginLeft: theme.spacing(1),
|
marginLeft: theme.spacing(1),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const ProjectBadgeContainer = styled('div')(() => ({}));
|
const ProjectBadgeContainer = styled('div')(() => ({
|
||||||
|
maxWidth: '50%',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StyledBadge = styled(Badge)(() => ({
|
||||||
|
marginRight: 0.5,
|
||||||
|
}));
|
||||||
|
|
||||||
interface IGroupCardProps {
|
interface IGroupCardProps {
|
||||||
group: IGroup;
|
group: IGroup;
|
||||||
@ -63,12 +83,12 @@ interface IGroupCardProps {
|
|||||||
|
|
||||||
export const GroupCard = ({ group }: IGroupCardProps) => {
|
export const GroupCard = ({ group }: IGroupCardProps) => {
|
||||||
const [removeOpen, setRemoveOpen] = useState(false);
|
const [removeOpen, setRemoveOpen] = useState(false);
|
||||||
|
const navigate = useNavigate();
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<StyledLink key={group.id} to={`/admin/groups/${group.id}`}>
|
<StyledLink key={group.id} to={`/admin/groups/${group.id}`}>
|
||||||
<StyledGroupCard>
|
<StyledGroupCard>
|
||||||
<StyledRow>
|
<StyledTitleRow>
|
||||||
<StyledHeaderTitle>{group.name}</StyledHeaderTitle>
|
<StyledHeaderTitle>{group.name}</StyledHeaderTitle>
|
||||||
<StyledHeaderActions>
|
<StyledHeaderActions>
|
||||||
<GroupCardActions
|
<GroupCardActions
|
||||||
@ -76,9 +96,9 @@ export const GroupCard = ({ group }: IGroupCardProps) => {
|
|||||||
onRemove={() => setRemoveOpen(true)}
|
onRemove={() => setRemoveOpen(true)}
|
||||||
/>
|
/>
|
||||||
</StyledHeaderActions>
|
</StyledHeaderActions>
|
||||||
</StyledRow>
|
</StyledTitleRow>
|
||||||
<StyledDescription>{group.description}</StyledDescription>
|
<StyledDescription>{group.description}</StyledDescription>
|
||||||
<StyledRow>
|
<StyledBottomRow>
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={group.users?.length > 0}
|
condition={group.users?.length > 0}
|
||||||
show={<GroupCardAvatars users={group.users} />}
|
show={<GroupCardAvatars users={group.users} />}
|
||||||
@ -92,13 +112,26 @@ export const GroupCard = ({ group }: IGroupCardProps) => {
|
|||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={group.projects.length > 0}
|
condition={group.projects.length > 0}
|
||||||
show={group.projects.map(project => (
|
show={group.projects.map(project => (
|
||||||
<Badge
|
<Tooltip
|
||||||
color="secondary"
|
key={project}
|
||||||
icon={<TopicOutlinedIcon />}
|
title="View project"
|
||||||
sx={{ marginRight: 0.5 }}
|
arrow
|
||||||
|
placement="bottom-end"
|
||||||
|
describeChild
|
||||||
>
|
>
|
||||||
{project}
|
<StyledBadge
|
||||||
</Badge>
|
onClick={e => {
|
||||||
|
e.preventDefault();
|
||||||
|
navigate(
|
||||||
|
`/projects/${project}/access`
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
color="secondary"
|
||||||
|
icon={<TopicOutlinedIcon />}
|
||||||
|
>
|
||||||
|
{project}
|
||||||
|
</StyledBadge>
|
||||||
|
</Tooltip>
|
||||||
))}
|
))}
|
||||||
elseShow={
|
elseShow={
|
||||||
<Tooltip
|
<Tooltip
|
||||||
@ -111,7 +144,7 @@ export const GroupCard = ({ group }: IGroupCardProps) => {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</ProjectBadgeContainer>
|
</ProjectBadgeContainer>
|
||||||
</StyledRow>
|
</StyledBottomRow>
|
||||||
</StyledGroupCard>
|
</StyledGroupCard>
|
||||||
</StyledLink>
|
</StyledLink>
|
||||||
<RemoveGroup
|
<RemoveGroup
|
||||||
|
@ -97,7 +97,7 @@ export const GroupCardActions: FC<IGroupCardActions> = ({
|
|||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText>
|
<ListItemText>
|
||||||
<Typography variant="body2">
|
<Typography variant="body2">
|
||||||
Remove group
|
Delete group
|
||||||
</Typography>
|
</Typography>
|
||||||
</ListItemText>
|
</ListItemText>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
@ -15,6 +15,9 @@ const StyledAvatars = styled('div')(({ theme }) => ({
|
|||||||
const StyledAvatar = styled(UserAvatar)(({ theme }) => ({
|
const StyledAvatar = styled(UserAvatar)(({ theme }) => ({
|
||||||
outline: `${theme.spacing(0.25)} solid ${theme.palette.background.paper}`,
|
outline: `${theme.spacing(0.25)} solid ${theme.palette.background.paper}`,
|
||||||
marginLeft: theme.spacing(-1),
|
marginLeft: theme.spacing(-1),
|
||||||
|
'&:hover': {
|
||||||
|
outlineColor: theme.palette.primary.main,
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
interface IGroupCardAvatarsProps {
|
interface IGroupCardAvatarsProps {
|
||||||
@ -44,6 +47,7 @@ export const GroupCardAvatars = ({ users }: IGroupCardAvatarsProps) => {
|
|||||||
<StyledAvatars>
|
<StyledAvatars>
|
||||||
{shownUsers.map(user => (
|
{shownUsers.map(user => (
|
||||||
<StyledAvatar
|
<StyledAvatar
|
||||||
|
key={user.id}
|
||||||
user={user}
|
user={user}
|
||||||
star={user.role === Role.Owner}
|
star={user.role === Role.Owner}
|
||||||
onMouseEnter={event => {
|
onMouseEnter={event => {
|
||||||
|
@ -1,21 +1,18 @@
|
|||||||
import { Badge, Popover, styled } from '@mui/material';
|
import { Popover, styled } from '@mui/material';
|
||||||
import { IGroupUser, Role } from 'interfaces/group';
|
import { IGroupUser, Role } from 'interfaces/group';
|
||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||||
import { Badge as StyledBadge } from 'component/common/Badge/Badge';
|
import { Badge } from 'component/common/Badge/Badge';
|
||||||
import StarIcon from '@mui/icons-material/Star';
|
import { StarRounded } from '@mui/icons-material';
|
||||||
|
|
||||||
const StyledPopover = styled(Popover)(({ theme }) => ({
|
const StyledPopover = styled(Popover)(({ theme }) => ({
|
||||||
pointerEvents: 'none',
|
pointerEvents: 'none',
|
||||||
'.MuiPaper-root': {
|
'.MuiPaper-root': {
|
||||||
padding: '12px',
|
padding: theme.spacing(2),
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const StyledPopupStar = styled(StarIcon)(({ theme }) => ({
|
const StyledPopupStar = styled(StarRounded)(({ theme }) => ({
|
||||||
color: theme.palette.warning.main,
|
color: theme.palette.warning.main,
|
||||||
fontSize: theme.fontSizes.smallBody,
|
|
||||||
marginLeft: theme.spacing(0.1),
|
|
||||||
marginTop: theme.spacing(2),
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const StyledName = styled('div')(({ theme }) => ({
|
const StyledName = styled('div')(({ theme }) => ({
|
||||||
@ -55,22 +52,10 @@ export const GroupPopover = ({
|
|||||||
>
|
>
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={user?.role === Role.Member}
|
condition={user?.role === Role.Member}
|
||||||
show={<StyledBadge color="success">{user?.role}</StyledBadge>}
|
show={<Badge>{user?.role}</Badge>}
|
||||||
elseShow={
|
elseShow={
|
||||||
<Badge
|
<Badge color="success" icon={<StyledPopupStar />}>
|
||||||
overlap="circular"
|
{user?.role}
|
||||||
anchorOrigin={{
|
|
||||||
vertical: 'top',
|
|
||||||
horizontal: 'left',
|
|
||||||
}}
|
|
||||||
badgeContent={<StyledPopupStar />}
|
|
||||||
>
|
|
||||||
<StyledBadge
|
|
||||||
color="success"
|
|
||||||
sx={{ paddingLeft: '16px' }}
|
|
||||||
>
|
|
||||||
{user?.role}
|
|
||||||
</StyledBadge>
|
|
||||||
</Badge>
|
</Badge>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
@ -0,0 +1,35 @@
|
|||||||
|
import { Button, styled, Typography } from '@mui/material';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
|
export const GroupEmpty = () => {
|
||||||
|
const StyledContainerDiv = styled('div')(({ theme }) => ({
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
margin: theme.spacing(6),
|
||||||
|
marginLeft: 'auto',
|
||||||
|
marginRight: 'auto',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StyledTitle = styled(Typography)(({ theme }) => ({
|
||||||
|
fontSize: theme.fontSizes.bodySize,
|
||||||
|
marginBottom: theme.spacing(2.5),
|
||||||
|
}));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StyledContainerDiv>
|
||||||
|
<StyledTitle>
|
||||||
|
No groups available. Get started by adding a new group.
|
||||||
|
</StyledTitle>
|
||||||
|
<Button
|
||||||
|
to="/admin/groups/create-group"
|
||||||
|
component={Link}
|
||||||
|
variant="outlined"
|
||||||
|
color="secondary"
|
||||||
|
>
|
||||||
|
Create your first group
|
||||||
|
</Button>
|
||||||
|
</StyledContainerDiv>
|
||||||
|
);
|
||||||
|
};
|
@ -11,6 +11,7 @@ import theme from 'themes/theme';
|
|||||||
import { SearchHighlightProvider } from 'component/common/Table/SearchHighlightContext/SearchHighlightContext';
|
import { SearchHighlightProvider } from 'component/common/Table/SearchHighlightContext/SearchHighlightContext';
|
||||||
import { TablePlaceholder } from 'component/common/Table';
|
import { TablePlaceholder } from 'component/common/Table';
|
||||||
import { GroupCard } from './GroupCard/GroupCard';
|
import { GroupCard } from './GroupCard/GroupCard';
|
||||||
|
import { GroupEmpty } from './GroupEmpty/GroupEmpty';
|
||||||
|
|
||||||
type PageQueryType = Partial<Record<'search', string>>;
|
type PageQueryType = Partial<Record<'search', string>>;
|
||||||
|
|
||||||
@ -123,12 +124,7 @@ export const GroupsList: VFC = () => {
|
|||||||
”
|
”
|
||||||
</TablePlaceholder>
|
</TablePlaceholder>
|
||||||
}
|
}
|
||||||
elseShow={
|
elseShow={<GroupEmpty />}
|
||||||
<TablePlaceholder>
|
|
||||||
No groups available. Get started by adding a new
|
|
||||||
group.
|
|
||||||
</TablePlaceholder>
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
@ -48,10 +48,10 @@ export const RemoveGroup: FC<IRemoveGroupProps> = ({
|
|||||||
onClose={() => {
|
onClose={() => {
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
}}
|
}}
|
||||||
title="Remove group"
|
title="Delete group"
|
||||||
>
|
>
|
||||||
<Typography>
|
<Typography>
|
||||||
Are you sure you wish to remove <strong>{group.name}</strong>?
|
Are you sure you wish to delete <strong>{group.name}</strong>?
|
||||||
If this group is currently assigned to one or more projects then
|
If this group is currently assigned to one or more projects then
|
||||||
users belonging to this group may lose access to those projects.
|
users belonging to this group may lose access to those projects.
|
||||||
</Typography>
|
</Typography>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { styled, SxProps, Theme } from '@mui/material';
|
import { styled, SxProps, Theme } from '@mui/material';
|
||||||
import {
|
import React, {
|
||||||
cloneElement,
|
cloneElement,
|
||||||
FC,
|
FC,
|
||||||
ForwardedRef,
|
ForwardedRef,
|
||||||
@ -17,6 +17,8 @@ interface IBadgeProps {
|
|||||||
className?: string;
|
className?: string;
|
||||||
sx?: SxProps<Theme>;
|
sx?: SxProps<Theme>;
|
||||||
children?: ReactNode;
|
children?: ReactNode;
|
||||||
|
title?: string;
|
||||||
|
onClick?: (event: React.SyntheticEvent) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IBadgeIconProps {
|
interface IBadgeIconProps {
|
||||||
|
@ -8,8 +8,7 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
marginRight: theme.spacing(1),
|
marginRight: theme.spacing(1),
|
||||||
[theme.breakpoints.down(650)]: {
|
[theme.breakpoints.down(710)]: {
|
||||||
marginBottom: '1rem',
|
|
||||||
marginRight: 0,
|
marginRight: 0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -17,8 +16,8 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
fill: '#fff',
|
fill: '#fff',
|
||||||
},
|
},
|
||||||
accordion: {
|
accordion: {
|
||||||
border: `1px solid ${theme.palette.grey[400]}`,
|
border: `1px solid ${theme.palette.dividerAlternative}`,
|
||||||
borderRadius: '8px',
|
borderRadius: theme.shape.borderRadiusMedium,
|
||||||
backgroundColor: '#fff',
|
backgroundColor: '#fff',
|
||||||
boxShadow: 'none',
|
boxShadow: 'none',
|
||||||
margin: 0,
|
margin: 0,
|
||||||
@ -27,6 +26,9 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
'&:before': {
|
'&:before': {
|
||||||
opacity: '0 !important',
|
opacity: '0 !important',
|
||||||
},
|
},
|
||||||
|
'&:first-of-type, &:last-of-type': {
|
||||||
|
borderRadius: theme.shape.borderRadiusMedium,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
accordionEdit: {
|
accordionEdit: {
|
||||||
backgroundColor: '#F6F6FA',
|
backgroundColor: '#F6F6FA',
|
||||||
@ -34,7 +36,10 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
headerMetaInfo: {
|
headerMetaInfo: {
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'stretch',
|
alignItems: 'stretch',
|
||||||
[theme.breakpoints.down(710)]: { flexDirection: 'column' },
|
[theme.breakpoints.down(710)]: {
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
headerContainer: {
|
headerContainer: {
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
@ -76,6 +81,9 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
minWidth: '152px',
|
minWidth: '152px',
|
||||||
paddingRight: '0.5rem',
|
paddingRight: '0.5rem',
|
||||||
},
|
},
|
||||||
|
[theme.breakpoints.down(710)]: {
|
||||||
|
paddingRight: 0,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
editingBadge: {
|
editingBadge: {
|
||||||
borderRadius: theme.shape.borderRadiusExtraLarge,
|
borderRadius: theme.shape.borderRadiusExtraLarge,
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { Paper, styled } from '@mui/material';
|
import { Paper, styled } from '@mui/material';
|
||||||
import { usePageTitle } from 'hooks/usePageTitle';
|
import { usePageTitle } from 'hooks/usePageTitle';
|
||||||
import { ReactNode } from 'react';
|
import { ReactNode } from 'react';
|
||||||
|
import { ConditionallyRender } from '../ConditionallyRender/ConditionallyRender';
|
||||||
|
|
||||||
const StyledMainHeader = styled(Paper)(({ theme }) => ({
|
const StyledMainHeader = styled(Paper)(({ theme }) => ({
|
||||||
borderRadius: theme.shape.borderRadiusLarge,
|
borderRadius: theme.shape.borderRadiusLarge,
|
||||||
@ -49,7 +50,15 @@ export const MainHeader = ({
|
|||||||
<StyledTitle>{title}</StyledTitle>
|
<StyledTitle>{title}</StyledTitle>
|
||||||
<StyledActions>{actions}</StyledActions>
|
<StyledActions>{actions}</StyledActions>
|
||||||
</StyledTitleHeader>
|
</StyledTitleHeader>
|
||||||
Description:<StyledDescription>{description}</StyledDescription>
|
<ConditionallyRender
|
||||||
|
condition={Boolean(description?.length)}
|
||||||
|
show={
|
||||||
|
<>
|
||||||
|
Description:
|
||||||
|
<StyledDescription>{description}</StyledDescription>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
/>
|
||||||
</StyledMainHeader>
|
</StyledMainHeader>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { styled, SxProps, Theme } from '@mui/material';
|
import { Box, styled, useTheme, SxProps, Theme } from '@mui/material';
|
||||||
import { ConditionallyRender } from '../ConditionallyRender/ConditionallyRender';
|
import { ConditionallyRender } from '../ConditionallyRender/ConditionallyRender';
|
||||||
|
|
||||||
interface IStrategySeparatorProps {
|
interface IStrategySeparatorProps {
|
||||||
@ -6,14 +6,8 @@ interface IStrategySeparatorProps {
|
|||||||
sx?: SxProps<Theme>;
|
sx?: SxProps<Theme>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const StyledContainer = styled('div')(({ theme }) => ({
|
|
||||||
height: theme.spacing(1),
|
|
||||||
position: 'relative',
|
|
||||||
width: '100%',
|
|
||||||
}));
|
|
||||||
|
|
||||||
const StyledContent = styled('div')(({ theme }) => ({
|
const StyledContent = styled('div')(({ theme }) => ({
|
||||||
padding: theme.spacing(0.75, 1.5),
|
padding: theme.spacing(0.75, 1),
|
||||||
color: theme.palette.text.primary,
|
color: theme.palette.text.primary,
|
||||||
fontSize: theme.fontSizes.smallerBody,
|
fontSize: theme.fontSizes.smallerBody,
|
||||||
backgroundColor: theme.palette.secondaryContainer,
|
backgroundColor: theme.palette.secondaryContainer,
|
||||||
@ -21,26 +15,39 @@ const StyledContent = styled('div')(({ theme }) => ({
|
|||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
zIndex: theme.zIndex.fab,
|
zIndex: theme.zIndex.fab,
|
||||||
top: '50%',
|
top: '50%',
|
||||||
left: theme.spacing(3),
|
left: theme.spacing(2),
|
||||||
transform: 'translateY(-50%)',
|
transform: 'translateY(-50%)',
|
||||||
|
lineHeight: 1,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const StyledCenteredContent = styled(StyledContent)(({ theme }) => ({
|
const StyledCenteredContent = styled(StyledContent)(({ theme }) => ({
|
||||||
top: '50%',
|
top: '50%',
|
||||||
left: '50%',
|
left: '50%',
|
||||||
transform: 'translate(-50%, -50%)',
|
transform: 'translate(-50%, -50%)',
|
||||||
backgroundColor: theme.palette.secondary.light,
|
backgroundColor: theme.palette.activityIndicators.primary,
|
||||||
border: `1px solid ${theme.palette.primary.border}`,
|
border: `1px solid ${theme.palette.primary.border}`,
|
||||||
|
borderRadius: theme.shape.borderRadiusLarge,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const StrategySeparator = ({ text, sx }: IStrategySeparatorProps) => (
|
export const StrategySeparator = ({ text, sx }: IStrategySeparatorProps) => {
|
||||||
<StyledContainer sx={sx}>
|
const theme = useTheme();
|
||||||
<ConditionallyRender
|
|
||||||
condition={text === 'AND'}
|
return (
|
||||||
show={() => <StyledContent>{text}</StyledContent>}
|
<Box
|
||||||
elseShow={() => (
|
sx={{
|
||||||
<StyledCenteredContent>{text}</StyledCenteredContent>
|
height: theme.spacing(text === 'AND' ? 1 : 1.5),
|
||||||
)}
|
position: 'relative',
|
||||||
/>
|
width: '100%',
|
||||||
</StyledContainer>
|
..sx
|
||||||
);
|
}}
|
||||||
|
>
|
||||||
|
<ConditionallyRender
|
||||||
|
condition={text === 'AND'}
|
||||||
|
show={() => <StyledContent>{text}</StyledContent>}
|
||||||
|
elseShow={() => (
|
||||||
|
<StyledCenteredContent>{text}</StyledCenteredContent>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
@ -9,11 +9,11 @@ import {
|
|||||||
import { IUser } from 'interfaces/user';
|
import { IUser } from 'interfaces/user';
|
||||||
import { FC } from 'react';
|
import { FC } from 'react';
|
||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||||
import StarIcon from '@mui/icons-material/Star';
|
import { StarRounded } from '@mui/icons-material';
|
||||||
|
|
||||||
const StyledAvatar = styled(Avatar)(({ theme }) => ({
|
const StyledAvatar = styled(Avatar)(({ theme }) => ({
|
||||||
width: theme.spacing(4),
|
width: theme.spacing(3.5),
|
||||||
height: theme.spacing(4),
|
height: theme.spacing(3.5),
|
||||||
margin: 'auto',
|
margin: 'auto',
|
||||||
backgroundColor: theme.palette.secondary.light,
|
backgroundColor: theme.palette.secondary.light,
|
||||||
color: theme.palette.text.primary,
|
color: theme.palette.text.primary,
|
||||||
@ -21,7 +21,7 @@ const StyledAvatar = styled(Avatar)(({ theme }) => ({
|
|||||||
fontWeight: theme.fontWeight.bold,
|
fontWeight: theme.fontWeight.bold,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const StyledStar = styled(StarIcon)(({ theme }) => ({
|
const StyledStar = styled(StarRounded)(({ theme }) => ({
|
||||||
color: theme.palette.warning.main,
|
color: theme.palette.warning.main,
|
||||||
backgroundColor: theme.palette.background.paper,
|
backgroundColor: theme.palette.background.paper,
|
||||||
borderRadius: theme.shape.borderRadiusExtraLarge,
|
borderRadius: theme.shape.borderRadiusExtraLarge,
|
||||||
|
@ -6,6 +6,7 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
|
paddingTop: theme.spacing(2),
|
||||||
},
|
},
|
||||||
title: {
|
title: {
|
||||||
fontSize: theme.fontSizes.bodySize,
|
fontSize: theme.fontSizes.bodySize,
|
||||||
|
@ -161,7 +161,7 @@ export const FeatureStrategyEmpty = ({
|
|||||||
display: 'grid',
|
display: 'grid',
|
||||||
width: '100%',
|
width: '100%',
|
||||||
gap: 2,
|
gap: 2,
|
||||||
gridTemplateColumns: '1fr 1fr',
|
gridTemplateColumns: { xs: '1fr', sm: '1fr 1fr' },
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<PresetCard
|
<PresetCard
|
||||||
|
@ -40,7 +40,14 @@ export const PresetCard: FC<IPresetCardProps> = ({
|
|||||||
{children}
|
{children}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<Box sx={{ ml: 'auto', mt: 'auto', pt: 1 }}>
|
<Box
|
||||||
|
sx={{
|
||||||
|
ml: 'auto',
|
||||||
|
mt: 'auto',
|
||||||
|
pt: 1,
|
||||||
|
mr: { xs: 'auto', sm: 0 },
|
||||||
|
}}
|
||||||
|
>
|
||||||
<PermissionButton
|
<PermissionButton
|
||||||
permission={CREATE_FEATURE_STRATEGY}
|
permission={CREATE_FEATURE_STRATEGY}
|
||||||
projectId={projectId}
|
projectId={projectId}
|
||||||
|
@ -1,11 +1,6 @@
|
|||||||
import { makeStyles } from 'tss-react/mui';
|
import { makeStyles } from 'tss-react/mui';
|
||||||
|
|
||||||
export const useStyles = makeStyles()(theme => ({
|
export const useStyles = makeStyles()(theme => ({
|
||||||
title: {
|
|
||||||
margin: 0,
|
|
||||||
fontSize: theme.fontSizes.bodySize,
|
|
||||||
fontWeight: theme.fontWeight.bold,
|
|
||||||
},
|
|
||||||
divider: {
|
divider: {
|
||||||
border: `1px dashed ${theme.palette.divider}`,
|
border: `1px dashed ${theme.palette.divider}`,
|
||||||
},
|
},
|
||||||
|
@ -9,7 +9,7 @@ import { FeatureStrategySegmentList } from 'component/feature/FeatureStrategy/Fe
|
|||||||
import { useStyles } from 'component/feature/FeatureStrategy/FeatureStrategySegment/FeatureStrategySegment.styles';
|
import { useStyles } from 'component/feature/FeatureStrategy/FeatureStrategySegment/FeatureStrategySegment.styles';
|
||||||
import { SegmentDocsStrategyWarning } from 'component/segments/SegmentDocs/SegmentDocs';
|
import { SegmentDocsStrategyWarning } from 'component/segments/SegmentDocs/SegmentDocs';
|
||||||
import { useSegmentLimits } from 'hooks/api/getters/useSegmentLimits/useSegmentLimits';
|
import { useSegmentLimits } from 'hooks/api/getters/useSegmentLimits/useSegmentLimits';
|
||||||
import { Divider } from '@mui/material';
|
import { Divider, Typography } from '@mui/material';
|
||||||
|
|
||||||
interface IFeatureStrategySegmentProps {
|
interface IFeatureStrategySegmentProps {
|
||||||
segments: ISegment[];
|
segments: ISegment[];
|
||||||
@ -53,7 +53,9 @@ export const FeatureStrategySegment = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<h3 className={styles.title}>Segmentation</h3>
|
<Typography component="h3" sx={{ m: 0 }} variant="h3">
|
||||||
|
Segmentation
|
||||||
|
</Typography>
|
||||||
{atStrategySegmentsLimit && <SegmentDocsStrategyWarning />}
|
{atStrategySegmentsLimit && <SegmentDocsStrategyWarning />}
|
||||||
<p>Add a predefined segment to constrain this feature toggle:</p>
|
<p>Add a predefined segment to constrain this feature toggle:</p>
|
||||||
<AutocompleteBox
|
<AutocompleteBox
|
||||||
|
@ -16,11 +16,13 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
fontSize: theme.fontSizes.smallerBody,
|
fontSize: theme.fontSizes.smallerBody,
|
||||||
border: '1px solid',
|
border: '1px solid',
|
||||||
borderColor: theme.palette.grey[300],
|
borderColor: theme.palette.grey[300],
|
||||||
paddingInline: '0.4rem',
|
padding: theme.spacing(0.75, 1),
|
||||||
marginBlock: '0.2rem',
|
display: 'block',
|
||||||
display: 'grid',
|
marginTop: 'auto',
|
||||||
|
marginBottom: 'auto',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
borderRadius: theme.shape.borderRadius,
|
borderRadius: theme.shape.borderRadius,
|
||||||
|
lineHeight: 1,
|
||||||
},
|
},
|
||||||
selectedSegmentsLabel: {
|
selectedSegmentsLabel: {
|
||||||
color: theme.palette.text.secondary,
|
color: theme.palette.text.secondary,
|
||||||
|
@ -15,7 +15,7 @@ const FeatureLog = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
<FeatureEventHistory toggleName={feature.name} />
|
<FeatureEventHistory featureId={feature.name} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { Box, styled } from '@mui/material';
|
||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||||
import { StrategySeparator } from 'component/common/StrategySeparator/StrategySeparator';
|
import { StrategySeparator } from 'component/common/StrategySeparator/StrategySeparator';
|
||||||
import { MoveListItem, useDragItem } from 'hooks/useDragItem';
|
import { MoveListItem, useDragItem } from 'hooks/useDragItem';
|
||||||
@ -13,6 +14,18 @@ interface IStrategyDraggableItemProps {
|
|||||||
onDragAndDrop: MoveListItem;
|
onDragAndDrop: MoveListItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const StyledIndexLabel = styled('div')(({ theme }) => ({
|
||||||
|
fontSize: theme.typography.fontSize,
|
||||||
|
color: theme.palette.text.secondary,
|
||||||
|
position: 'absolute',
|
||||||
|
display: 'none',
|
||||||
|
right: 'calc(100% + 6px)',
|
||||||
|
top: theme.spacing(2.5),
|
||||||
|
[theme.breakpoints.up('md')]: {
|
||||||
|
display: 'block',
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
export const StrategyDraggableItem = ({
|
export const StrategyDraggableItem = ({
|
||||||
strategy,
|
strategy,
|
||||||
index,
|
index,
|
||||||
@ -23,17 +36,20 @@ export const StrategyDraggableItem = ({
|
|||||||
const ref = useDragItem(index, onDragAndDrop);
|
const ref = useDragItem(index, onDragAndDrop);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={strategy.id} ref={ref}>
|
<Box key={strategy.id} ref={ref}>
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={index > 0}
|
condition={index > 0}
|
||||||
show={<StrategySeparator text="OR" />}
|
show={<StrategySeparator text="OR" />}
|
||||||
/>
|
/>
|
||||||
<StrategyItem
|
<Box sx={{ position: 'relative' }}>
|
||||||
strategy={strategy}
|
<StyledIndexLabel>{index + 1}</StyledIndexLabel>
|
||||||
environmentId={environmentName}
|
<StrategyItem
|
||||||
otherEnvironments={otherEnvironments}
|
strategy={strategy}
|
||||||
isDraggable
|
environmentId={environmentName}
|
||||||
/>
|
otherEnvironments={otherEnvironments}
|
||||||
</div>
|
isDraggable
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -4,7 +4,7 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
container: {
|
container: {
|
||||||
width: '100%',
|
width: '100%',
|
||||||
padding: theme.spacing(2, 3),
|
padding: theme.spacing(2, 3),
|
||||||
borderRadius: theme.shape.borderRadius,
|
borderRadius: theme.shape.borderRadiusMedium,
|
||||||
border: `1px solid ${theme.palette.divider}`,
|
border: `1px solid ${theme.palette.divider}`,
|
||||||
},
|
},
|
||||||
chip: {
|
chip: {
|
||||||
|
@ -4,7 +4,7 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
valueContainer: {
|
valueContainer: {
|
||||||
padding: theme.spacing(2, 3),
|
padding: theme.spacing(2, 3),
|
||||||
border: `1px solid ${theme.palette.dividerAlternative}`,
|
border: `1px solid ${theme.palette.dividerAlternative}`,
|
||||||
borderRadius: theme.shape.borderRadius,
|
borderRadius: theme.shape.borderRadiusMedium,
|
||||||
},
|
},
|
||||||
valueSeparator: {
|
valueSeparator: {
|
||||||
color: theme.palette.grey[700],
|
color: theme.palette.grey[700],
|
||||||
|
@ -17,6 +17,9 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
borderBottom: `1px solid ${theme.palette.divider}`,
|
borderBottom: `1px solid ${theme.palette.divider}`,
|
||||||
fontWeight: theme.typography.fontWeightMedium,
|
fontWeight: theme.typography.fontWeightMedium,
|
||||||
},
|
},
|
||||||
|
headerDraggable: {
|
||||||
|
paddingLeft: theme.spacing(1),
|
||||||
|
},
|
||||||
icon: {
|
icon: {
|
||||||
fill: theme.palette.inactiveIcon,
|
fill: theme.palette.inactiveIcon,
|
||||||
},
|
},
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { DragIndicator, Edit } from '@mui/icons-material';
|
import { DragIndicator, Edit } from '@mui/icons-material';
|
||||||
import { styled, useTheme, IconButton } from '@mui/material';
|
import { styled, useTheme, IconButton } from '@mui/material';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
import classNames from 'classnames';
|
||||||
import { IFeatureEnvironment } from 'interfaces/featureToggle';
|
import { IFeatureEnvironment } from 'interfaces/featureToggle';
|
||||||
import { IFeatureStrategy } from 'interfaces/strategy';
|
import { IFeatureStrategy } from 'interfaces/strategy';
|
||||||
import {
|
import {
|
||||||
@ -52,7 +53,11 @@ export const StrategyItem = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
<div className={styles.header}>
|
<div
|
||||||
|
className={classNames(styles.header, {
|
||||||
|
[styles.headerDraggable]: isDraggable,
|
||||||
|
})}
|
||||||
|
>
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={Boolean(isDraggable)}
|
condition={Boolean(isDraggable)}
|
||||||
show={() => (
|
show={() => (
|
||||||
@ -60,6 +65,7 @@ export const StrategyItem = ({
|
|||||||
<DragIndicator
|
<DragIndicator
|
||||||
titleAccess="Drag to reorder"
|
titleAccess="Drag to reorder"
|
||||||
cursor="grab"
|
cursor="grab"
|
||||||
|
sx={{ color: 'neutral.main' }}
|
||||||
/>
|
/>
|
||||||
</DragIcon>
|
</DragIcon>
|
||||||
)}
|
)}
|
||||||
|
@ -28,9 +28,13 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
borderBottomLeftRadius: theme.shape.borderRadiusLarge,
|
borderBottomLeftRadius: theme.shape.borderRadiusLarge,
|
||||||
borderBottomRightRadius: theme.shape.borderRadiusLarge,
|
borderBottomRightRadius: theme.shape.borderRadiusLarge,
|
||||||
borderBottom: `4px solid ${theme.palette.primary.light}`,
|
borderBottom: `4px solid ${theme.palette.primary.light}`,
|
||||||
|
|
||||||
|
[theme.breakpoints.down('md')]: {
|
||||||
|
padding: theme.spacing(2, 1),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
accordionDetailsDisabled: {
|
accordionDetailsDisabled: {
|
||||||
borderBottom: `4px solid ${theme.palette.dividerAlternative}`,
|
borderBottom: `4px solid ${theme.palette.neutral.border}`,
|
||||||
},
|
},
|
||||||
accordionBody: {
|
accordionBody: {
|
||||||
width: '100%',
|
width: '100%',
|
||||||
|
@ -85,18 +85,18 @@ const FeatureOverviewEnvironment = ({
|
|||||||
maxWidth="100"
|
maxWidth="100"
|
||||||
maxLength={15}
|
maxLength={15}
|
||||||
/>
|
/>
|
||||||
<ConditionallyRender
|
|
||||||
condition={!env.enabled}
|
|
||||||
show={
|
|
||||||
<Chip
|
|
||||||
size="small"
|
|
||||||
variant="outlined"
|
|
||||||
label="Disabled"
|
|
||||||
sx={{ ml: 1 }}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
<ConditionallyRender
|
||||||
|
condition={!env.enabled}
|
||||||
|
show={
|
||||||
|
<Chip
|
||||||
|
size="small"
|
||||||
|
variant="outlined"
|
||||||
|
label="Disabled"
|
||||||
|
sx={{ ml: 1 }}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
<FeatureStrategyMenu
|
<FeatureStrategyMenu
|
||||||
|
@ -14,7 +14,7 @@ const SeparatorContainer = styled('div')(({ theme }) => ({
|
|||||||
transform: 'translateY(-50%)',
|
transform: 'translateY(-50%)',
|
||||||
height: 2,
|
height: 2,
|
||||||
width: '100%',
|
width: '100%',
|
||||||
backgroundColor: theme.palette.divider,
|
backgroundColor: theme.palette.dividerAlternative,
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -25,7 +25,7 @@ const SeparatorContent = styled('span')(({ theme }) => ({
|
|||||||
background: theme.palette.secondaryContainer,
|
background: theme.palette.secondaryContainer,
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
maxWidth: '80%',
|
maxWidth: '80%',
|
||||||
color: theme.palette.text.secondary,
|
color: theme.palette.text.primary,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const SectionSeparator: FC = ({ children }) => (
|
export const SectionSeparator: FC = ({ children }) => (
|
||||||
|
@ -3,6 +3,8 @@ import { Link } from 'react-router-dom';
|
|||||||
import { DonutLarge } from '@mui/icons-material';
|
import { DonutLarge } from '@mui/icons-material';
|
||||||
import { useStyles } from 'component/feature/FeatureView/FeatureOverview/FeatureOverviewSegment/FeatureOverviewSegment.styles';
|
import { useStyles } from 'component/feature/FeatureView/FeatureOverview/FeatureOverviewSegment/FeatureOverviewSegment.styles';
|
||||||
import { useSegments } from 'hooks/api/getters/useSegments/useSegments';
|
import { useSegments } from 'hooks/api/getters/useSegments/useSegments';
|
||||||
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||||
|
import { StrategySeparator } from 'component/common/StrategySeparator/StrategySeparator';
|
||||||
|
|
||||||
interface IFeatureOverviewSegmentProps {
|
interface IFeatureOverviewSegmentProps {
|
||||||
strategyId: string;
|
strategyId: string;
|
||||||
@ -20,8 +22,12 @@ export const FeatureOverviewSegment = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{segments.map(segment => (
|
{segments.map((segment, index) => (
|
||||||
<Fragment key={segment.id}>
|
<Fragment key={segment.id}>
|
||||||
|
<ConditionallyRender
|
||||||
|
condition={index > 0}
|
||||||
|
show={<StrategySeparator text="AND" />}
|
||||||
|
/>
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
<DonutLarge color="secondary" sx={{ mr: 1 }} /> Segment:{' '}
|
<DonutLarge color="secondary" sx={{ mr: 1 }} /> Segment:{' '}
|
||||||
<Link
|
<Link
|
||||||
|
@ -81,9 +81,9 @@ const RolloutSlider = ({
|
|||||||
<div className={classes.slider}>
|
<div className={classes.slider}>
|
||||||
<Typography
|
<Typography
|
||||||
id="discrete-slider-always"
|
id="discrete-slider-always"
|
||||||
variant="subtitle2"
|
variant="h3"
|
||||||
gutterBottom
|
gutterBottom
|
||||||
component="h2"
|
component="h3"
|
||||||
>
|
>
|
||||||
{name}
|
{name}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
@ -8,5 +8,5 @@ export const EventHistory = () => {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <EventLog history={events} title="Event log" />;
|
return <EventLog events={events} title="Event log" />;
|
||||||
};
|
};
|
||||||
|
@ -1,9 +1,14 @@
|
|||||||
import EventDiff from './EventDiff/EventDiff';
|
import EventDiff from 'component/history/EventLog/EventCard/EventDiff/EventDiff';
|
||||||
|
|
||||||
import { useStyles } from './EventCard.styles';
|
import { useStyles } from './EventCard.styles';
|
||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||||
|
import { IEvent } from 'interfaces/event';
|
||||||
|
|
||||||
const EventCard = ({ entry, timeFormatted }) => {
|
interface IEventCardProps {
|
||||||
|
entry: IEvent;
|
||||||
|
timeFormatted: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const EventCard = ({ entry, timeFormatted }: IEventCardProps) => {
|
||||||
const { classes: styles } = useStyles();
|
const { classes: styles } = useStyles();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -18,7 +23,7 @@ const EventCard = ({ entry, timeFormatted }) => {
|
|||||||
<dt className={styles.eventLogHeader}>Changed by: </dt>
|
<dt className={styles.eventLogHeader}>Changed by: </dt>
|
||||||
<dd title={entry.createdBy}>{entry.createdBy}</dd>
|
<dd title={entry.createdBy}>{entry.createdBy}</dd>
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={entry.project}
|
condition={Boolean(entry.project)}
|
||||||
show={
|
show={
|
||||||
<>
|
<>
|
||||||
<dt className={styles.eventLogHeader}>Project: </dt>
|
<dt className={styles.eventLogHeader}>Project: </dt>
|
||||||
@ -27,7 +32,7 @@ const EventCard = ({ entry, timeFormatted }) => {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={entry.featureName}
|
condition={Boolean(entry.featureName)}
|
||||||
show={
|
show={
|
||||||
<>
|
<>
|
||||||
<dt className={styles.eventLogHeader}>Feature: </dt>
|
<dt className={styles.eventLogHeader}>Feature: </dt>
|
@ -1,7 +1,6 @@
|
|||||||
import PropTypes from 'prop-types';
|
|
||||||
import { diff } from 'deep-diff';
|
import { diff } from 'deep-diff';
|
||||||
|
|
||||||
import { useStyles } from './EventDiff.styles';
|
import { useStyles } from './EventDiff.styles';
|
||||||
|
import { IEvent } from 'interfaces/event';
|
||||||
|
|
||||||
const DIFF_PREFIXES = {
|
const DIFF_PREFIXES = {
|
||||||
A: ' ',
|
A: ' ',
|
||||||
@ -10,7 +9,11 @@ const DIFF_PREFIXES = {
|
|||||||
N: '+',
|
N: '+',
|
||||||
};
|
};
|
||||||
|
|
||||||
const EventDiff = ({ entry }) => {
|
interface IEventDiffProps {
|
||||||
|
entry: IEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
const EventDiff = ({ entry }: IEventDiffProps) => {
|
||||||
const { classes: styles } = useStyles();
|
const { classes: styles } = useStyles();
|
||||||
|
|
||||||
const KLASSES = {
|
const KLASSES = {
|
||||||
@ -25,7 +28,7 @@ const EventDiff = ({ entry }) => {
|
|||||||
? diff(entry.preData, entry.data)
|
? diff(entry.preData, entry.data)
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
const buildItemDiff = (diff, key) => {
|
const buildItemDiff = (diff: any, key: string) => {
|
||||||
let change;
|
let change;
|
||||||
if (diff.lhs !== undefined) {
|
if (diff.lhs !== undefined) {
|
||||||
change = (
|
change = (
|
||||||
@ -48,7 +51,7 @@ const EventDiff = ({ entry }) => {
|
|||||||
return change;
|
return change;
|
||||||
};
|
};
|
||||||
|
|
||||||
const buildDiff = (diff, idx) => {
|
const buildDiff = (diff: any, idx: number) => {
|
||||||
let change;
|
let change;
|
||||||
const key = diff.path.join('.');
|
const key = diff.path.join('.');
|
||||||
|
|
||||||
@ -66,7 +69,9 @@ const EventDiff = ({ entry }) => {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
// @ts-expect-error
|
||||||
const spadenClass = KLASSES[diff.kind];
|
const spadenClass = KLASSES[diff.kind];
|
||||||
|
// @ts-expect-error
|
||||||
const prefix = DIFF_PREFIXES[diff.kind];
|
const prefix = DIFF_PREFIXES[diff.kind];
|
||||||
|
|
||||||
change = (
|
change = (
|
||||||
@ -95,15 +100,10 @@ const EventDiff = ({ entry }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<pre style={{ overflowX: 'auto', overflowY: 'hidden' }} tabIndex={0}>
|
<pre style={{ overflowX: 'auto', overflowY: 'hidden' }} tabIndex={0}>
|
||||||
<code className="smalltext man">
|
{/* @ts-expect-error */}
|
||||||
{changes.length === 0 ? '(no changes)' : changes}
|
<code>{changes.length === 0 ? '(no changes)' : changes}</code>
|
||||||
</code>
|
|
||||||
</pre>
|
</pre>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
EventDiff.propTypes = {
|
|
||||||
entry: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default EventDiff;
|
export default EventDiff;
|
@ -1,8 +1,12 @@
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import { useStyles } from './EventJson.styles';
|
import { useStyles } from './EventJson.styles';
|
||||||
|
import { IEvent } from 'interfaces/event';
|
||||||
|
|
||||||
const EventJson = ({ entry }) => {
|
interface IEventJsonProps {
|
||||||
|
entry: IEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
const EventJson = ({ entry }: IEventJsonProps) => {
|
||||||
const { classes: styles } = useStyles();
|
const { classes: styles } = useStyles();
|
||||||
|
|
||||||
const localEventData = JSON.parse(JSON.stringify(entry));
|
const localEventData = JSON.parse(JSON.stringify(entry));
|
||||||
@ -15,7 +19,7 @@ const EventJson = ({ entry }) => {
|
|||||||
return (
|
return (
|
||||||
<li className={styles.historyItem}>
|
<li className={styles.historyItem}>
|
||||||
<div>
|
<div>
|
||||||
<code className="JSON smalltext man">{prettyPrinted}</code>
|
<code>{prettyPrinted}</code>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
@ -1,35 +1,47 @@
|
|||||||
import { List, Switch, FormControlLabel } from '@mui/material';
|
import { List, Switch, FormControlLabel } from '@mui/material';
|
||||||
import PropTypes from 'prop-types';
|
import EventJson from 'component/history/EventLog/EventJson/EventJson';
|
||||||
import EventJson from './EventJson/EventJson';
|
|
||||||
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 EventCard from './EventCard/EventCard';
|
import EventCard from 'component/history/EventLog/EventCard/EventCard';
|
||||||
import { useStyles } from './EventLog.styles';
|
import { useStyles } from './EventLog.styles';
|
||||||
import { formatDateYMDHMS } from 'utils/formatDate';
|
import { formatDateYMDHMS } from 'utils/formatDate';
|
||||||
|
import { IEventSettings } from 'hooks/useEventSettings';
|
||||||
|
import { IEvent } from 'interfaces/event';
|
||||||
|
import React from 'react';
|
||||||
|
import { ILocationSettings } from 'hooks/useLocationSettings';
|
||||||
|
|
||||||
|
interface IEventLogProps {
|
||||||
|
title: string;
|
||||||
|
events: IEvent[];
|
||||||
|
eventSettings: IEventSettings;
|
||||||
|
setEventSettings: React.Dispatch<React.SetStateAction<IEventSettings>>;
|
||||||
|
locationSettings: ILocationSettings;
|
||||||
|
displayInline?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
const EventLog = ({
|
const EventLog = ({
|
||||||
title,
|
title,
|
||||||
history,
|
events,
|
||||||
eventSettings,
|
eventSettings,
|
||||||
setEventSettings,
|
setEventSettings,
|
||||||
locationSettings,
|
locationSettings,
|
||||||
displayInline,
|
displayInline,
|
||||||
}) => {
|
}: IEventLogProps) => {
|
||||||
const { classes: styles } = useStyles();
|
const { classes: styles } = useStyles();
|
||||||
const toggleShowDiff = () => {
|
const toggleShowDiff = () => {
|
||||||
setEventSettings({ showData: !eventSettings.showData });
|
setEventSettings({ showData: !eventSettings.showData });
|
||||||
};
|
};
|
||||||
const formatFulldateTime = v => {
|
const formatFulldateTime = (v: string) => {
|
||||||
return formatDateYMDHMS(v, locationSettings.locale);
|
return formatDateYMDHMS(v, locationSettings.locale);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!history || history.length < 0) {
|
if (!events || events.length < 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
let entries;
|
let entries;
|
||||||
|
|
||||||
const renderListItemCards = entry => (
|
const renderListItemCards = (entry: IEvent) => (
|
||||||
<li key={entry.id} className={styles.eventEntry}>
|
<li key={entry.id} className={styles.eventEntry}>
|
||||||
<EventCard
|
<EventCard
|
||||||
entry={entry}
|
entry={entry}
|
||||||
@ -39,11 +51,11 @@ const EventLog = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (eventSettings.showData) {
|
if (eventSettings.showData) {
|
||||||
entries = history.map(entry => (
|
entries = events.map(entry => (
|
||||||
<EventJson key={`log${entry.id}`} entry={entry} />
|
<EventJson key={`log${entry.id}`} entry={entry} />
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
entries = history.map(renderListItemCards);
|
entries = events.map(renderListItemCards);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -75,13 +87,4 @@ const EventLog = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
EventLog.propTypes = {
|
|
||||||
history: PropTypes.array,
|
|
||||||
eventSettings: PropTypes.object.isRequired,
|
|
||||||
setEventSettings: PropTypes.func.isRequired,
|
|
||||||
locationSettings: PropTypes.object.isRequired,
|
|
||||||
title: PropTypes.string,
|
|
||||||
displayInline: PropTypes.bool,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default EventLog;
|
export default EventLog;
|
@ -1,10 +1,11 @@
|
|||||||
import EventLog from './EventLog';
|
import EventLog from 'component/history/EventLog/EventLog';
|
||||||
import { useEventSettings } from 'hooks/useEventSettings';
|
import { useEventSettings } from 'hooks/useEventSettings';
|
||||||
import { useLocationSettings } from 'hooks/useLocationSettings';
|
import { useLocationSettings } from 'hooks/useLocationSettings';
|
||||||
|
import { IEvent } from 'interfaces/event';
|
||||||
|
|
||||||
interface IEventLogContainerProps {
|
interface IEventLogContainerProps {
|
||||||
title: string;
|
title: string;
|
||||||
history: unknown[];
|
events: IEvent[];
|
||||||
displayInline?: boolean;
|
displayInline?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -15,7 +16,7 @@ const EventLogContainer = (props: IEventLogContainerProps) => {
|
|||||||
return (
|
return (
|
||||||
<EventLog
|
<EventLog
|
||||||
title={props.title}
|
title={props.title}
|
||||||
history={props.history}
|
events={props.events}
|
||||||
eventSettings={eventSettings}
|
eventSettings={eventSettings}
|
||||||
setEventSettings={setEventSettings}
|
setEventSettings={setEventSettings}
|
||||||
locationSettings={locationSettings}
|
locationSettings={locationSettings}
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
import PropTypes from 'prop-types';
|
|
||||||
import EventLog from '../EventLog';
|
|
||||||
import { useFeatureEvents } from 'hooks/api/getters/useFeatureEvents/useFeatureEvents';
|
|
||||||
|
|
||||||
export const FeatureEventHistory = ({ toggleName }) => {
|
|
||||||
const { events } = useFeatureEvents(toggleName);
|
|
||||||
|
|
||||||
if (events.length === 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<EventLog history={events} hideName title="Event log" displayInline />
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
FeatureEventHistory.propTypes = {
|
|
||||||
toggleName: PropTypes.string.isRequired,
|
|
||||||
};
|
|
@ -0,0 +1,18 @@
|
|||||||
|
import EventLog from '../EventLog';
|
||||||
|
import { useFeatureEvents } from 'hooks/api/getters/useFeatureEvents/useFeatureEvents';
|
||||||
|
|
||||||
|
interface IFeatureEventHistoryProps {
|
||||||
|
featureId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FeatureEventHistory = ({
|
||||||
|
featureId,
|
||||||
|
}: IFeatureEventHistoryProps) => {
|
||||||
|
const { events } = useFeatureEvents(featureId);
|
||||||
|
|
||||||
|
if (events.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return <EventLog events={events} title="Event log" displayInline />;
|
||||||
|
};
|
@ -1,9 +1,9 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { FeatureEventHistory } from '../FeatureEventHistory/FeatureEventHistory';
|
import { FeatureEventHistory } from 'component/history/FeatureEventHistory/FeatureEventHistory';
|
||||||
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
|
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
|
||||||
|
|
||||||
export const FeatureEventHistoryPage = () => {
|
export const FeatureEventHistoryPage = () => {
|
||||||
const toggleName = useRequiredPathParam('toggleName');
|
const toggleName = useRequiredPathParam('toggleName');
|
||||||
|
|
||||||
return <FeatureEventHistory toggleName={toggleName} />;
|
return <FeatureEventHistory featureId={toggleName} />;
|
||||||
};
|
};
|
||||||
|
@ -44,27 +44,44 @@ export const ProjectRoleDescription: VFC<IProjectRoleDescriptionProps> = ({
|
|||||||
const environments = useMemo(() => {
|
const environments = useMemo(() => {
|
||||||
const environments = new Set<string>();
|
const environments = new Set<string>();
|
||||||
role.permissions
|
role.permissions
|
||||||
?.filter((permission: any) => permission.environment !== '')
|
?.filter((permission: any) => permission.environment)
|
||||||
.forEach((permission: any) => {
|
.forEach((permission: any) => {
|
||||||
environments.add(permission.environment);
|
environments.add(permission.environment);
|
||||||
});
|
});
|
||||||
return [...environments].sort();
|
return [...environments].sort();
|
||||||
}, [role]);
|
}, [role]);
|
||||||
|
|
||||||
|
const projectPermissions = useMemo(() => {
|
||||||
|
return role.permissions?.filter(
|
||||||
|
(permission: any) => !permission.environment
|
||||||
|
);
|
||||||
|
}, [role]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledDescription>
|
<StyledDescription>
|
||||||
<StyledDescriptionHeader>
|
<ConditionallyRender
|
||||||
Project permissions
|
condition={Boolean(projectPermissions?.length)}
|
||||||
</StyledDescriptionHeader>
|
show={
|
||||||
<StyledDescriptionBlock>
|
<>
|
||||||
{role.permissions
|
<StyledDescriptionHeader>
|
||||||
?.filter((permission: any) => permission.environment === '')
|
Project permissions
|
||||||
.map((permission: any) => permission.displayName)
|
</StyledDescriptionHeader>
|
||||||
.sort()
|
<StyledDescriptionBlock>
|
||||||
.map((permission: any) => (
|
{role.permissions
|
||||||
<p key={permission}>{permission}</p>
|
?.filter(
|
||||||
))}
|
(permission: any) => !permission.environment
|
||||||
</StyledDescriptionBlock>
|
)
|
||||||
|
.map(
|
||||||
|
(permission: any) => permission.displayName
|
||||||
|
)
|
||||||
|
.sort()
|
||||||
|
.map((permission: any) => (
|
||||||
|
<p key={permission}>{permission}</p>
|
||||||
|
))}
|
||||||
|
</StyledDescriptionBlock>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
/>
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={Boolean(environments.length)}
|
condition={Boolean(environments.length)}
|
||||||
show={
|
show={
|
||||||
|
@ -26,6 +26,10 @@ export default createTheme({
|
|||||||
fontSize: '1.5rem',
|
fontSize: '1.5rem',
|
||||||
lineHeight: 1.875,
|
lineHeight: 1.875,
|
||||||
},
|
},
|
||||||
|
h3: {
|
||||||
|
fontSize: '1rem',
|
||||||
|
fontWeight: '700',
|
||||||
|
},
|
||||||
caption: {
|
caption: {
|
||||||
fontSize: `${12 / 16}rem`,
|
fontSize: `${12 / 16}rem`,
|
||||||
},
|
},
|
||||||
@ -128,6 +132,7 @@ export default createTheme({
|
|||||||
recent: colors.green[100],
|
recent: colors.green[100],
|
||||||
inactive: colors.orange[200],
|
inactive: colors.orange[200],
|
||||||
abandoned: colors.red[200],
|
abandoned: colors.red[200],
|
||||||
|
primary: colors.purple[100],
|
||||||
},
|
},
|
||||||
inactiveIcon: colors.grey[600],
|
inactiveIcon: colors.grey[600],
|
||||||
},
|
},
|
||||||
|
@ -46,13 +46,14 @@ declare module '@mui/material/styles' {
|
|||||||
background: string;
|
background: string;
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* For 'Seen' column on feature toggles list.
|
* For 'Seen' column on feature toggles list and other.
|
||||||
*/
|
*/
|
||||||
activityIndicators: {
|
activityIndicators: {
|
||||||
unknown: string;
|
unknown: string;
|
||||||
recent: string;
|
recent: string;
|
||||||
inactive: string;
|
inactive: string;
|
||||||
abandoned: string;
|
abandoned: string;
|
||||||
|
primary: string;
|
||||||
};
|
};
|
||||||
dividerAlternative: string;
|
dividerAlternative: string;
|
||||||
/**
|
/**
|
||||||
|
@ -1318,7 +1318,12 @@
|
|||||||
"@codemirror/view" "^6.0.0"
|
"@codemirror/view" "^6.0.0"
|
||||||
crelt "^1.0.5"
|
crelt "^1.0.5"
|
||||||
|
|
||||||
"@codemirror/state@6.1.0", "@codemirror/state@^6.0.0":
|
"@codemirror/state@6.1.1":
|
||||||
|
version "6.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@codemirror/state/-/state-6.1.1.tgz#4f512e5e34ea23a5e10b2c1fe43f6195e90417bb"
|
||||||
|
integrity sha512-2s+aXsxmAwnR3Rd+JDHPG/1lw0YsA9PEwl7Re88gHJHGfxyfEzKBmsN4rr53RyPIR4lzbbhJX0DCq0WlqlBIRw==
|
||||||
|
|
||||||
|
"@codemirror/state@^6.0.0":
|
||||||
version "6.1.0"
|
version "6.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/@codemirror/state/-/state-6.1.0.tgz#c0f1d80f61908c9dcf5e2a3fe931e9dd78f3df8a"
|
resolved "https://registry.yarnpkg.com/@codemirror/state/-/state-6.1.0.tgz#c0f1d80f61908c9dcf5e2a3fe931e9dd78f3df8a"
|
||||||
integrity sha512-qbUr94DZTe6/V1VS7LDLz11rM/1t/nJxR1El4I6UaxDEdc0aZZvq6JCLJWiRmUf95NRAnDH6fhXn+PWp9wGCIg==
|
integrity sha512-qbUr94DZTe6/V1VS7LDLz11rM/1t/nJxR1El4I6UaxDEdc0aZZvq6JCLJWiRmUf95NRAnDH6fhXn+PWp9wGCIg==
|
||||||
@ -1993,10 +1998,10 @@
|
|||||||
"@testing-library/dom" "^8.0.0"
|
"@testing-library/dom" "^8.0.0"
|
||||||
"@types/react-dom" "<18.0.0"
|
"@types/react-dom" "<18.0.0"
|
||||||
|
|
||||||
"@testing-library/user-event@14.3.0":
|
"@testing-library/user-event@14.4.1":
|
||||||
version "14.3.0"
|
version "14.4.1"
|
||||||
resolved "https://registry.yarnpkg.com/@testing-library/user-event/-/user-event-14.3.0.tgz#0a6750b94b40e4739706d41e8efc2ccf64d2aad9"
|
resolved "https://registry.yarnpkg.com/@testing-library/user-event/-/user-event-14.4.1.tgz#dfa1cceef4833f5288a4090d1b85dce5d8dc20b6"
|
||||||
integrity sha512-P02xtBBa8yMaLhK8CzJCIns8rqwnF6FxhR9zs810flHOBXUYCFjLd8Io1rQrAkQRWEmW2PGdZIEdMxf/KLsqFA==
|
integrity sha512-Gr20dje1RaNxZ1ehHGPvFkLswfetBQKCfRD/lo6sUJQ52X2TV/QnqUpkjoShfEebrB2KiTPfQkcONwdQiofLhg==
|
||||||
|
|
||||||
"@tootallnate/once@2":
|
"@tootallnate/once@2":
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
@ -3139,10 +3144,10 @@ cookie@^0.4.2:
|
|||||||
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432"
|
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432"
|
||||||
integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==
|
integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==
|
||||||
|
|
||||||
copy-to-clipboard@3.3.1:
|
copy-to-clipboard@3.3.2:
|
||||||
version "3.3.1"
|
version "3.3.2"
|
||||||
resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.3.1.tgz#115aa1a9998ffab6196f93076ad6da3b913662ae"
|
resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.3.2.tgz#5b263ec2366224b100181dded7ce0579b340c107"
|
||||||
integrity sha512-i13qo6kIHTTpCm8/Wup+0b1mVWETvu2kIMzKoK8FpkLkFxlt0znUAHcMzox+T8sPlqtZXq3CulEjQHsYiGFJUw==
|
integrity sha512-Vme1Z6RUDzrb6xAI7EZlVZ5uvOk2F//GaxKUxajDqm9LhOVM1inxNAD2vy+UZDYsd0uyA9s7b3/FVZPSxqrCfg==
|
||||||
dependencies:
|
dependencies:
|
||||||
toggle-selection "^1.0.6"
|
toggle-selection "^1.0.6"
|
||||||
|
|
||||||
@ -6092,10 +6097,10 @@ safe-buffer@~5.1.1:
|
|||||||
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
|
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
|
||||||
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
|
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
|
||||||
|
|
||||||
sass@1.54.0:
|
sass@1.54.2:
|
||||||
version "1.54.0"
|
version "1.54.2"
|
||||||
resolved "https://registry.yarnpkg.com/sass/-/sass-1.54.0.tgz#24873673265e2a4fe3d3a997f714971db2fba1f4"
|
resolved "https://registry.yarnpkg.com/sass/-/sass-1.54.2.tgz#574cad83814c930ef2475921b9cb5d8203ae8867"
|
||||||
integrity sha512-C4zp79GCXZfK0yoHZg+GxF818/aclhp9F48XBu/+bm9vXEVAYov9iU3FBVRMq3Hx3OA4jfKL+p2K9180mEh0xQ==
|
integrity sha512-wbVV26sejsCIbBScZZtNkvnrB/bVCQ8hSlZ01D9nzsVh9zLqCkWrlpvTb3YEb6xsuNi9cx75hncqwikHFSz7tw==
|
||||||
dependencies:
|
dependencies:
|
||||||
chokidar ">=3.0.0 <4.0.0"
|
chokidar ">=3.0.0 <4.0.0"
|
||||||
immutable "^4.0.0"
|
immutable "^4.0.0"
|
||||||
|
Loading…
Reference in New Issue
Block a user