diff --git a/frontend/package.json b/frontend/package.json index 345772e136..64624af2f4 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -49,7 +49,7 @@ "@testing-library/jest-dom": "5.16.4", "@testing-library/react": "12.1.5", "@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/deep-diff": "1.0.1", "@types/jest": "28.1.6", @@ -66,7 +66,7 @@ "chart.js": "3.8.2", "chartjs-adapter-date-fns": "2.0.0", "classnames": "2.3.1", - "copy-to-clipboard": "3.3.1", + "copy-to-clipboard": "3.3.2", "cypress": "9.7.0", "date-fns": "2.29.1", "debounce": "1.2.1", @@ -91,7 +91,7 @@ "react-table": "7.8.0", "react-test-renderer": "17.0.2", "react-timeago": "7.1.0", - "sass": "1.54.0", + "sass": "1.54.2", "semver": "7.3.7", "swr": "1.3.0", "tss-react": "3.7.1", @@ -103,7 +103,7 @@ "vitest": "0.20.3", "whatwg-fetch": "^3.6.2", "@codemirror/lang-json": "6.0.0", - "@codemirror/state": "6.1.0", + "@codemirror/state": "6.1.1", "@uiw/react-codemirror": "^4.11.4", "codemirror": "^6.0.1" }, diff --git a/frontend/src/component/admin/groups/Group/Group.tsx b/frontend/src/component/admin/groups/Group/Group.tsx index d7ccb7d91c..a3330c49e6 100644 --- a/frontend/src/component/admin/groups/Group/Group.tsx +++ b/frontend/src/component/admin/groups/Group/Group.tsx @@ -255,7 +255,7 @@ export const Group: VFC = () => { onClick={() => setRemoveOpen(true)} permission={ADMIN} tooltipProps={{ - title: 'Remove group', + title: 'Delete group', }} > diff --git a/frontend/src/component/admin/groups/GroupForm/GroupForm.tsx b/frontend/src/component/admin/groups/GroupForm/GroupForm.tsx index d5ef3190c3..6e6e2d9bb2 100644 --- a/frontend/src/component/admin/groups/GroupForm/GroupForm.tsx +++ b/frontend/src/component/admin/groups/GroupForm/GroupForm.tsx @@ -81,6 +81,7 @@ export const GroupForm: FC = ({ value={name} onChange={e => setName(e.target.value)} data-testid={UG_NAME_ID} + required /> How would you describe your group? diff --git a/frontend/src/component/admin/groups/GroupUserRoleCell/GroupUserRoleCell.tsx b/frontend/src/component/admin/groups/GroupUserRoleCell/GroupUserRoleCell.tsx index 3d26d2d3a5..6382e56dc7 100644 --- a/frontend/src/component/admin/groups/GroupUserRoleCell/GroupUserRoleCell.tsx +++ b/frontend/src/component/admin/groups/GroupUserRoleCell/GroupUserRoleCell.tsx @@ -2,25 +2,11 @@ import { capitalize, MenuItem, Select, styled } from '@mui/material'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { TextCell } from 'component/common/Table/cells/TextCell/TextCell'; import { Role } from 'interfaces/group'; +import { Badge } from 'component/common/Badge/Badge'; +import { StarRounded } from '@mui/icons-material'; -const StyledBadge = styled('div')(({ theme }) => ({ - padding: theme.spacing(0.5, 1), - 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, +const StyledPopupStar = styled(StarRounded)(({ theme }) => ({ + color: theme.palette.warning.main, })); interface IGroupUserRoleCellProps { @@ -35,8 +21,12 @@ export const GroupUserRoleCell = ({ const renderBadge = () => ( {capitalize(value)}} - elseShow={{capitalize(value)}} + show={{capitalize(value)}} + elseShow={ + }> + {capitalize(value)} + + } /> ); diff --git a/frontend/src/component/admin/groups/GroupsList/GroupCard/GroupCard.tsx b/frontend/src/component/admin/groups/GroupsList/GroupCard/GroupCard.tsx index 8373b42d2e..6f9309b624 100644 --- a/frontend/src/component/admin/groups/GroupsList/GroupCard/GroupCard.tsx +++ b/frontend/src/component/admin/groups/GroupsList/GroupCard/GroupCard.tsx @@ -1,6 +1,6 @@ import { styled, Tooltip } from '@mui/material'; 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 { GroupCardAvatars } from './GroupCardAvatars/GroupCardAvatars'; import { Badge } from 'component/common/Badge/Badge'; @@ -20,9 +20,15 @@ const StyledGroupCard = styled('aside')(({ theme }) => ({ border: `1px solid ${theme.palette.dividerAlternative}`, borderRadius: theme.shape.borderRadiusLarge, boxShadow: theme.boxShadows.card, + display: 'flex', + flexDirection: 'column', [theme.breakpoints.up('md')]: { padding: theme.spacing(4), }, + '&:hover': { + transition: 'background-color 0.2s ease-in-out', + backgroundColor: theme.palette.neutral.light, + }, })); const StyledRow = styled('div')(() => ({ @@ -31,6 +37,14 @@ const StyledRow = styled('div')(() => ({ justifyContent: 'space-between', })); +const StyledTitleRow = styled(StyledRow)(() => ({ + alignItems: 'flex-start', +})); + +const StyledBottomRow = styled(StyledRow)(() => ({ + marginTop: 'auto', +})); + const StyledHeaderTitle = styled('h2')(({ theme }) => ({ fontSize: theme.fontSizes.mainHeader, fontWeight: theme.fontWeight.medium, @@ -55,7 +69,13 @@ const StyledCounterDescription = styled('span')(({ theme }) => ({ marginLeft: theme.spacing(1), })); -const ProjectBadgeContainer = styled('div')(() => ({})); +const ProjectBadgeContainer = styled('div')(() => ({ + maxWidth: '50%', +})); + +const StyledBadge = styled(Badge)(() => ({ + marginRight: 0.5, +})); interface IGroupCardProps { group: IGroup; @@ -63,12 +83,12 @@ interface IGroupCardProps { export const GroupCard = ({ group }: IGroupCardProps) => { const [removeOpen, setRemoveOpen] = useState(false); - + const navigate = useNavigate(); return ( <> - + {group.name} { onRemove={() => setRemoveOpen(true)} /> - + {group.description} - + 0} show={} @@ -92,13 +112,26 @@ export const GroupCard = ({ group }: IGroupCardProps) => { 0} show={group.projects.map(project => ( - } - sx={{ marginRight: 0.5 }} + - {project} - + { + e.preventDefault(); + navigate( + `/projects/${project}/access` + ); + }} + color="secondary" + icon={} + > + {project} + + ))} elseShow={ { } /> - + = ({ - Remove group + Delete group diff --git a/frontend/src/component/admin/groups/GroupsList/GroupCard/GroupCardAvatars/GroupCardAvatars.tsx b/frontend/src/component/admin/groups/GroupsList/GroupCard/GroupCardAvatars/GroupCardAvatars.tsx index 73e6245bd0..01933b912f 100644 --- a/frontend/src/component/admin/groups/GroupsList/GroupCard/GroupCardAvatars/GroupCardAvatars.tsx +++ b/frontend/src/component/admin/groups/GroupsList/GroupCard/GroupCardAvatars/GroupCardAvatars.tsx @@ -15,6 +15,9 @@ const StyledAvatars = styled('div')(({ theme }) => ({ const StyledAvatar = styled(UserAvatar)(({ theme }) => ({ outline: `${theme.spacing(0.25)} solid ${theme.palette.background.paper}`, marginLeft: theme.spacing(-1), + '&:hover': { + outlineColor: theme.palette.primary.main, + }, })); interface IGroupCardAvatarsProps { @@ -44,6 +47,7 @@ export const GroupCardAvatars = ({ users }: IGroupCardAvatarsProps) => { {shownUsers.map(user => ( { diff --git a/frontend/src/component/admin/groups/GroupsList/GroupCard/GroupCardAvatars/GroupPopover/GroupPopover.tsx b/frontend/src/component/admin/groups/GroupsList/GroupCard/GroupCardAvatars/GroupPopover/GroupPopover.tsx index 5e59c2e9a5..665ee8bb74 100644 --- a/frontend/src/component/admin/groups/GroupsList/GroupCard/GroupCardAvatars/GroupPopover/GroupPopover.tsx +++ b/frontend/src/component/admin/groups/GroupsList/GroupCard/GroupCardAvatars/GroupPopover/GroupPopover.tsx @@ -1,21 +1,18 @@ -import { Badge, Popover, styled } from '@mui/material'; +import { Popover, styled } from '@mui/material'; import { IGroupUser, Role } from 'interfaces/group'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; -import { Badge as StyledBadge } from 'component/common/Badge/Badge'; -import StarIcon from '@mui/icons-material/Star'; +import { Badge } from 'component/common/Badge/Badge'; +import { StarRounded } from '@mui/icons-material'; const StyledPopover = styled(Popover)(({ theme }) => ({ pointerEvents: 'none', '.MuiPaper-root': { - padding: '12px', + padding: theme.spacing(2), }, })); -const StyledPopupStar = styled(StarIcon)(({ theme }) => ({ +const StyledPopupStar = styled(StarRounded)(({ theme }) => ({ color: theme.palette.warning.main, - fontSize: theme.fontSizes.smallBody, - marginLeft: theme.spacing(0.1), - marginTop: theme.spacing(2), })); const StyledName = styled('div')(({ theme }) => ({ @@ -55,22 +52,10 @@ export const GroupPopover = ({ > {user?.role}} + show={{user?.role}} elseShow={ - } - > - - {user?.role} - + }> + {user?.role} } /> diff --git a/frontend/src/component/admin/groups/GroupsList/GroupEmpty/GroupEmpty.tsx b/frontend/src/component/admin/groups/GroupsList/GroupEmpty/GroupEmpty.tsx new file mode 100644 index 0000000000..768127474d --- /dev/null +++ b/frontend/src/component/admin/groups/GroupsList/GroupEmpty/GroupEmpty.tsx @@ -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 ( + + + No groups available. Get started by adding a new group. + + + + ); +}; diff --git a/frontend/src/component/admin/groups/GroupsList/GroupsList.tsx b/frontend/src/component/admin/groups/GroupsList/GroupsList.tsx index 8f61209922..18d1756406 100644 --- a/frontend/src/component/admin/groups/GroupsList/GroupsList.tsx +++ b/frontend/src/component/admin/groups/GroupsList/GroupsList.tsx @@ -11,6 +11,7 @@ import theme from 'themes/theme'; import { SearchHighlightProvider } from 'component/common/Table/SearchHighlightContext/SearchHighlightContext'; import { TablePlaceholder } from 'component/common/Table'; import { GroupCard } from './GroupCard/GroupCard'; +import { GroupEmpty } from './GroupEmpty/GroupEmpty'; type PageQueryType = Partial>; @@ -123,12 +124,7 @@ export const GroupsList: VFC = () => { ” } - elseShow={ - - No groups available. Get started by adding a new - group. - - } + elseShow={} /> } /> diff --git a/frontend/src/component/admin/groups/RemoveGroup/RemoveGroup.tsx b/frontend/src/component/admin/groups/RemoveGroup/RemoveGroup.tsx index ddf7d5a34d..3dfed93853 100644 --- a/frontend/src/component/admin/groups/RemoveGroup/RemoveGroup.tsx +++ b/frontend/src/component/admin/groups/RemoveGroup/RemoveGroup.tsx @@ -48,10 +48,10 @@ export const RemoveGroup: FC = ({ onClose={() => { setOpen(false); }} - title="Remove group" + title="Delete group" > - Are you sure you wish to remove {group.name}? + Are you sure you wish to delete {group.name}? If this group is currently assigned to one or more projects then users belonging to this group may lose access to those projects. diff --git a/frontend/src/component/common/Badge/Badge.tsx b/frontend/src/component/common/Badge/Badge.tsx index bbcce6fa69..b944542e25 100644 --- a/frontend/src/component/common/Badge/Badge.tsx +++ b/frontend/src/component/common/Badge/Badge.tsx @@ -1,5 +1,5 @@ import { styled, SxProps, Theme } from '@mui/material'; -import { +import React, { cloneElement, FC, ForwardedRef, @@ -17,6 +17,8 @@ interface IBadgeProps { className?: string; sx?: SxProps; children?: ReactNode; + title?: string; + onClick?: (event: React.SyntheticEvent) => void; } interface IBadgeIconProps { diff --git a/frontend/src/component/common/ConstraintAccordion/ConstraintAccordion.styles.ts b/frontend/src/component/common/ConstraintAccordion/ConstraintAccordion.styles.ts index bceadae3df..ad759801b2 100644 --- a/frontend/src/component/common/ConstraintAccordion/ConstraintAccordion.styles.ts +++ b/frontend/src/component/common/ConstraintAccordion/ConstraintAccordion.styles.ts @@ -8,8 +8,7 @@ export const useStyles = makeStyles()(theme => ({ alignItems: 'center', justifyContent: 'center', marginRight: theme.spacing(1), - [theme.breakpoints.down(650)]: { - marginBottom: '1rem', + [theme.breakpoints.down(710)]: { marginRight: 0, }, }, @@ -17,8 +16,8 @@ export const useStyles = makeStyles()(theme => ({ fill: '#fff', }, accordion: { - border: `1px solid ${theme.palette.grey[400]}`, - borderRadius: '8px', + border: `1px solid ${theme.palette.dividerAlternative}`, + borderRadius: theme.shape.borderRadiusMedium, backgroundColor: '#fff', boxShadow: 'none', margin: 0, @@ -27,6 +26,9 @@ export const useStyles = makeStyles()(theme => ({ '&:before': { opacity: '0 !important', }, + '&:first-of-type, &:last-of-type': { + borderRadius: theme.shape.borderRadiusMedium, + }, }, accordionEdit: { backgroundColor: '#F6F6FA', @@ -34,7 +36,10 @@ export const useStyles = makeStyles()(theme => ({ headerMetaInfo: { display: 'flex', alignItems: 'stretch', - [theme.breakpoints.down(710)]: { flexDirection: 'column' }, + [theme.breakpoints.down(710)]: { + flexDirection: 'column', + alignItems: 'center', + }, }, headerContainer: { display: 'flex', @@ -76,6 +81,9 @@ export const useStyles = makeStyles()(theme => ({ minWidth: '152px', paddingRight: '0.5rem', }, + [theme.breakpoints.down(710)]: { + paddingRight: 0, + }, }, editingBadge: { borderRadius: theme.shape.borderRadiusExtraLarge, diff --git a/frontend/src/component/common/MainHeader/MainHeader.tsx b/frontend/src/component/common/MainHeader/MainHeader.tsx index 2711d6df12..2b46d0237b 100644 --- a/frontend/src/component/common/MainHeader/MainHeader.tsx +++ b/frontend/src/component/common/MainHeader/MainHeader.tsx @@ -1,6 +1,7 @@ import { Paper, styled } from '@mui/material'; import { usePageTitle } from 'hooks/usePageTitle'; import { ReactNode } from 'react'; +import { ConditionallyRender } from '../ConditionallyRender/ConditionallyRender'; const StyledMainHeader = styled(Paper)(({ theme }) => ({ borderRadius: theme.shape.borderRadiusLarge, @@ -49,7 +50,15 @@ export const MainHeader = ({ {title} {actions} - Description:{description} + + Description: + {description} + + } + /> ); }; diff --git a/frontend/src/component/common/StrategySeparator/StrategySeparator.tsx b/frontend/src/component/common/StrategySeparator/StrategySeparator.tsx index f513f1548b..30d26b0d69 100644 --- a/frontend/src/component/common/StrategySeparator/StrategySeparator.tsx +++ b/frontend/src/component/common/StrategySeparator/StrategySeparator.tsx @@ -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'; interface IStrategySeparatorProps { @@ -6,14 +6,8 @@ interface IStrategySeparatorProps { sx?: SxProps; } -const StyledContainer = styled('div')(({ theme }) => ({ - height: theme.spacing(1), - position: 'relative', - width: '100%', -})); - const StyledContent = styled('div')(({ theme }) => ({ - padding: theme.spacing(0.75, 1.5), + padding: theme.spacing(0.75, 1), color: theme.palette.text.primary, fontSize: theme.fontSizes.smallerBody, backgroundColor: theme.palette.secondaryContainer, @@ -21,26 +15,39 @@ const StyledContent = styled('div')(({ theme }) => ({ position: 'absolute', zIndex: theme.zIndex.fab, top: '50%', - left: theme.spacing(3), + left: theme.spacing(2), transform: 'translateY(-50%)', + lineHeight: 1, })); const StyledCenteredContent = styled(StyledContent)(({ theme }) => ({ top: '50%', left: '50%', transform: 'translate(-50%, -50%)', - backgroundColor: theme.palette.secondary.light, + backgroundColor: theme.palette.activityIndicators.primary, border: `1px solid ${theme.palette.primary.border}`, + borderRadius: theme.shape.borderRadiusLarge, })); -export const StrategySeparator = ({ text, sx }: IStrategySeparatorProps) => ( - - {text}} - elseShow={() => ( - {text} - )} - /> - -); +export const StrategySeparator = ({ text, sx }: IStrategySeparatorProps) => { + const theme = useTheme(); + + return ( + + {text}} + elseShow={() => ( + {text} + )} + /> + + ); +}; diff --git a/frontend/src/component/common/UserAvatar/UserAvatar.tsx b/frontend/src/component/common/UserAvatar/UserAvatar.tsx index 523cdbab1f..c2ec2288ae 100644 --- a/frontend/src/component/common/UserAvatar/UserAvatar.tsx +++ b/frontend/src/component/common/UserAvatar/UserAvatar.tsx @@ -9,11 +9,11 @@ import { import { IUser } from 'interfaces/user'; import { FC } from 'react'; 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 }) => ({ - width: theme.spacing(4), - height: theme.spacing(4), + width: theme.spacing(3.5), + height: theme.spacing(3.5), margin: 'auto', backgroundColor: theme.palette.secondary.light, color: theme.palette.text.primary, @@ -21,7 +21,7 @@ const StyledAvatar = styled(Avatar)(({ theme }) => ({ fontWeight: theme.fontWeight.bold, })); -const StyledStar = styled(StarIcon)(({ theme }) => ({ +const StyledStar = styled(StarRounded)(({ theme }) => ({ color: theme.palette.warning.main, backgroundColor: theme.palette.background.paper, borderRadius: theme.shape.borderRadiusExtraLarge, diff --git a/frontend/src/component/feature/FeatureStrategy/FeatureStrategyEmpty/FeatureStrategyEmpty.styles.ts b/frontend/src/component/feature/FeatureStrategy/FeatureStrategyEmpty/FeatureStrategyEmpty.styles.ts index fd2b71c21f..5f7fc7bf8c 100644 --- a/frontend/src/component/feature/FeatureStrategy/FeatureStrategyEmpty/FeatureStrategyEmpty.styles.ts +++ b/frontend/src/component/feature/FeatureStrategy/FeatureStrategyEmpty/FeatureStrategyEmpty.styles.ts @@ -6,6 +6,7 @@ export const useStyles = makeStyles()(theme => ({ flexDirection: 'column', alignItems: 'center', justifyContent: 'center', + paddingTop: theme.spacing(2), }, title: { fontSize: theme.fontSizes.bodySize, diff --git a/frontend/src/component/feature/FeatureStrategy/FeatureStrategyEmpty/FeatureStrategyEmpty.tsx b/frontend/src/component/feature/FeatureStrategy/FeatureStrategyEmpty/FeatureStrategyEmpty.tsx index c1490eea47..c604d24b4b 100644 --- a/frontend/src/component/feature/FeatureStrategy/FeatureStrategyEmpty/FeatureStrategyEmpty.tsx +++ b/frontend/src/component/feature/FeatureStrategy/FeatureStrategyEmpty/FeatureStrategyEmpty.tsx @@ -161,7 +161,7 @@ export const FeatureStrategyEmpty = ({ display: 'grid', width: '100%', gap: 2, - gridTemplateColumns: '1fr 1fr', + gridTemplateColumns: { xs: '1fr', sm: '1fr 1fr' }, }} > = ({ {children} - + ({ - title: { - margin: 0, - fontSize: theme.fontSizes.bodySize, - fontWeight: theme.fontWeight.bold, - }, divider: { border: `1px dashed ${theme.palette.divider}`, }, diff --git a/frontend/src/component/feature/FeatureStrategy/FeatureStrategySegment/FeatureStrategySegment.tsx b/frontend/src/component/feature/FeatureStrategy/FeatureStrategySegment/FeatureStrategySegment.tsx index 604dbb7d7c..6320b7238a 100644 --- a/frontend/src/component/feature/FeatureStrategy/FeatureStrategySegment/FeatureStrategySegment.tsx +++ b/frontend/src/component/feature/FeatureStrategy/FeatureStrategySegment/FeatureStrategySegment.tsx @@ -9,7 +9,7 @@ import { FeatureStrategySegmentList } from 'component/feature/FeatureStrategy/Fe import { useStyles } from 'component/feature/FeatureStrategy/FeatureStrategySegment/FeatureStrategySegment.styles'; import { SegmentDocsStrategyWarning } from 'component/segments/SegmentDocs/SegmentDocs'; import { useSegmentLimits } from 'hooks/api/getters/useSegmentLimits/useSegmentLimits'; -import { Divider } from '@mui/material'; +import { Divider, Typography } from '@mui/material'; interface IFeatureStrategySegmentProps { segments: ISegment[]; @@ -53,7 +53,9 @@ export const FeatureStrategySegment = ({ return ( <> -

Segmentation

+ + Segmentation + {atStrategySegmentsLimit && }

Add a predefined segment to constrain this feature toggle:

({ fontSize: theme.fontSizes.smallerBody, border: '1px solid', borderColor: theme.palette.grey[300], - paddingInline: '0.4rem', - marginBlock: '0.2rem', - display: 'grid', + padding: theme.spacing(0.75, 1), + display: 'block', + marginTop: 'auto', + marginBottom: 'auto', alignItems: 'center', borderRadius: theme.shape.borderRadius, + lineHeight: 1, }, selectedSegmentsLabel: { color: theme.palette.text.secondary, diff --git a/frontend/src/component/feature/FeatureView/FeatureLog/FeatureLog.tsx b/frontend/src/component/feature/FeatureView/FeatureLog/FeatureLog.tsx index 4b45e47fef..0c181c80ab 100644 --- a/frontend/src/component/feature/FeatureView/FeatureLog/FeatureLog.tsx +++ b/frontend/src/component/feature/FeatureView/FeatureLog/FeatureLog.tsx @@ -15,7 +15,7 @@ const FeatureLog = () => { return (
- +
); }; diff --git a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyDraggableItem.tsx b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyDraggableItem.tsx index 080e1731e2..be568736a8 100644 --- a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyDraggableItem.tsx +++ b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyDraggableItem.tsx @@ -1,3 +1,4 @@ +import { Box, styled } from '@mui/material'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { StrategySeparator } from 'component/common/StrategySeparator/StrategySeparator'; import { MoveListItem, useDragItem } from 'hooks/useDragItem'; @@ -13,6 +14,18 @@ interface IStrategyDraggableItemProps { 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 = ({ strategy, index, @@ -23,17 +36,20 @@ export const StrategyDraggableItem = ({ const ref = useDragItem(index, onDragAndDrop); return ( -
+ 0} show={} /> - -
+ + {index + 1} + + +
); }; diff --git a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyExecution/ConstraintItem/ConstraintItem.styles.ts b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyExecution/ConstraintItem/ConstraintItem.styles.ts index fb8f37bb11..dc31d5fc97 100644 --- a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyExecution/ConstraintItem/ConstraintItem.styles.ts +++ b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyExecution/ConstraintItem/ConstraintItem.styles.ts @@ -4,7 +4,7 @@ export const useStyles = makeStyles()(theme => ({ container: { width: '100%', padding: theme.spacing(2, 3), - borderRadius: theme.shape.borderRadius, + borderRadius: theme.shape.borderRadiusMedium, border: `1px solid ${theme.palette.divider}`, }, chip: { diff --git a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyExecution/StrategyExecution.styles.ts b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyExecution/StrategyExecution.styles.ts index d1fa29e035..a570236fbd 100644 --- a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyExecution/StrategyExecution.styles.ts +++ b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyExecution/StrategyExecution.styles.ts @@ -4,7 +4,7 @@ export const useStyles = makeStyles()(theme => ({ valueContainer: { padding: theme.spacing(2, 3), border: `1px solid ${theme.palette.dividerAlternative}`, - borderRadius: theme.shape.borderRadius, + borderRadius: theme.shape.borderRadiusMedium, }, valueSeparator: { color: theme.palette.grey[700], diff --git a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyItem.styles.ts b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyItem.styles.ts index 49dae7f772..f0c781ad0d 100644 --- a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyItem.styles.ts +++ b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyItem.styles.ts @@ -17,6 +17,9 @@ export const useStyles = makeStyles()(theme => ({ borderBottom: `1px solid ${theme.palette.divider}`, fontWeight: theme.typography.fontWeightMedium, }, + headerDraggable: { + paddingLeft: theme.spacing(1), + }, icon: { fill: theme.palette.inactiveIcon, }, diff --git a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyItem.tsx b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyItem.tsx index be80809709..e4b0bfcfb9 100644 --- a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyItem.tsx +++ b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyItem/StrategyItem.tsx @@ -1,6 +1,7 @@ import { DragIndicator, Edit } from '@mui/icons-material'; import { styled, useTheme, IconButton } from '@mui/material'; import { Link } from 'react-router-dom'; +import classNames from 'classnames'; import { IFeatureEnvironment } from 'interfaces/featureToggle'; import { IFeatureStrategy } from 'interfaces/strategy'; import { @@ -52,7 +53,11 @@ export const StrategyItem = ({ return (
-
+
( @@ -60,6 +65,7 @@ export const StrategyItem = ({ )} diff --git a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/FeatureOverviewEnvironment.styles.ts b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/FeatureOverviewEnvironment.styles.ts index b5c55e7728..50fe9d44e5 100644 --- a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/FeatureOverviewEnvironment.styles.ts +++ b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/FeatureOverviewEnvironment.styles.ts @@ -28,9 +28,13 @@ export const useStyles = makeStyles()(theme => ({ borderBottomLeftRadius: theme.shape.borderRadiusLarge, borderBottomRightRadius: theme.shape.borderRadiusLarge, borderBottom: `4px solid ${theme.palette.primary.light}`, + + [theme.breakpoints.down('md')]: { + padding: theme.spacing(2, 1), + }, }, accordionDetailsDisabled: { - borderBottom: `4px solid ${theme.palette.dividerAlternative}`, + borderBottom: `4px solid ${theme.palette.neutral.border}`, }, accordionBody: { width: '100%', diff --git a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/FeatureOverviewEnvironment.tsx b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/FeatureOverviewEnvironment.tsx index 1ae3818743..37f86b3e94 100644 --- a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/FeatureOverviewEnvironment.tsx +++ b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewEnvironments/FeatureOverviewEnvironment/FeatureOverviewEnvironment.tsx @@ -85,18 +85,18 @@ const FeatureOverviewEnvironment = ({ maxWidth="100" maxLength={15} /> - - } - />
+ + } + />
({ transform: 'translateY(-50%)', height: 2, width: '100%', - backgroundColor: theme.palette.divider, + backgroundColor: theme.palette.dividerAlternative, }, })); @@ -25,7 +25,7 @@ const SeparatorContent = styled('span')(({ theme }) => ({ background: theme.palette.secondaryContainer, position: 'relative', maxWidth: '80%', - color: theme.palette.text.secondary, + color: theme.palette.text.primary, })); export const SectionSeparator: FC = ({ children }) => ( diff --git a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewSegment/FeatureOverviewSegment.tsx b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewSegment/FeatureOverviewSegment.tsx index d81dcb8bdd..e4ad150dae 100644 --- a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewSegment/FeatureOverviewSegment.tsx +++ b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureOverviewSegment/FeatureOverviewSegment.tsx @@ -3,6 +3,8 @@ import { Link } from 'react-router-dom'; import { DonutLarge } from '@mui/icons-material'; import { useStyles } from 'component/feature/FeatureView/FeatureOverview/FeatureOverviewSegment/FeatureOverviewSegment.styles'; import { useSegments } from 'hooks/api/getters/useSegments/useSegments'; +import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; +import { StrategySeparator } from 'component/common/StrategySeparator/StrategySeparator'; interface IFeatureOverviewSegmentProps { strategyId: string; @@ -20,8 +22,12 @@ export const FeatureOverviewSegment = ({ return ( <> - {segments.map(segment => ( + {segments.map((segment, index) => ( + 0} + show={} + />
Segment:{' '} {name} diff --git a/frontend/src/component/history/EventHistory/EventHistory.tsx b/frontend/src/component/history/EventHistory/EventHistory.tsx index 9370f32030..3bf42f1897 100644 --- a/frontend/src/component/history/EventHistory/EventHistory.tsx +++ b/frontend/src/component/history/EventHistory/EventHistory.tsx @@ -8,5 +8,5 @@ export const EventHistory = () => { return null; } - return ; + return ; }; diff --git a/frontend/src/component/history/EventLog/EventCard/EventCard.jsx b/frontend/src/component/history/EventLog/EventCard/EventCard.tsx similarity index 81% rename from frontend/src/component/history/EventLog/EventCard/EventCard.jsx rename to frontend/src/component/history/EventLog/EventCard/EventCard.tsx index 9a573b33fa..55ec0ed2f3 100644 --- a/frontend/src/component/history/EventLog/EventCard/EventCard.jsx +++ b/frontend/src/component/history/EventLog/EventCard/EventCard.tsx @@ -1,9 +1,14 @@ -import EventDiff from './EventDiff/EventDiff'; - +import EventDiff from 'component/history/EventLog/EventCard/EventDiff/EventDiff'; import { useStyles } from './EventCard.styles'; 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(); return ( @@ -18,7 +23,7 @@ const EventCard = ({ entry, timeFormatted }) => {
Changed by:
{entry.createdBy}
Project:
@@ -27,7 +32,7 @@ const EventCard = ({ entry, timeFormatted }) => { } />
Feature:
diff --git a/frontend/src/component/history/EventLog/EventCard/EventDiff/EventDiff.jsx b/frontend/src/component/history/EventLog/EventCard/EventDiff/EventDiff.tsx similarity index 85% rename from frontend/src/component/history/EventLog/EventCard/EventDiff/EventDiff.jsx rename to frontend/src/component/history/EventLog/EventCard/EventDiff/EventDiff.tsx index 185d247efb..99fb2f5aac 100644 --- a/frontend/src/component/history/EventLog/EventCard/EventDiff/EventDiff.jsx +++ b/frontend/src/component/history/EventLog/EventCard/EventDiff/EventDiff.tsx @@ -1,7 +1,6 @@ -import PropTypes from 'prop-types'; import { diff } from 'deep-diff'; - import { useStyles } from './EventDiff.styles'; +import { IEvent } from 'interfaces/event'; const DIFF_PREFIXES = { A: ' ', @@ -10,7 +9,11 @@ const DIFF_PREFIXES = { N: '+', }; -const EventDiff = ({ entry }) => { +interface IEventDiffProps { + entry: IEvent; +} + +const EventDiff = ({ entry }: IEventDiffProps) => { const { classes: styles } = useStyles(); const KLASSES = { @@ -25,7 +28,7 @@ const EventDiff = ({ entry }) => { ? diff(entry.preData, entry.data) : undefined; - const buildItemDiff = (diff, key) => { + const buildItemDiff = (diff: any, key: string) => { let change; if (diff.lhs !== undefined) { change = ( @@ -48,7 +51,7 @@ const EventDiff = ({ entry }) => { return change; }; - const buildDiff = (diff, idx) => { + const buildDiff = (diff: any, idx: number) => { let change; const key = diff.path.join('.'); @@ -66,7 +69,9 @@ const EventDiff = ({ entry }) => {
); } else { + // @ts-expect-error const spadenClass = KLASSES[diff.kind]; + // @ts-expect-error const prefix = DIFF_PREFIXES[diff.kind]; change = ( @@ -95,15 +100,10 @@ const EventDiff = ({ entry }) => { return (
-            
-                {changes.length === 0 ? '(no changes)' : changes}
-            
+            {/* @ts-expect-error */}
+            {changes.length === 0 ? '(no changes)' : changes}
         
); }; -EventDiff.propTypes = { - entry: PropTypes.object, -}; - export default EventDiff; diff --git a/frontend/src/component/history/EventLog/EventJson/EventJson.jsx b/frontend/src/component/history/EventLog/EventJson/EventJson.tsx similarity index 75% rename from frontend/src/component/history/EventLog/EventJson/EventJson.jsx rename to frontend/src/component/history/EventLog/EventJson/EventJson.tsx index c545f89c51..7f15feeace 100644 --- a/frontend/src/component/history/EventLog/EventJson/EventJson.jsx +++ b/frontend/src/component/history/EventLog/EventJson/EventJson.tsx @@ -1,8 +1,12 @@ import PropTypes from 'prop-types'; - 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 localEventData = JSON.parse(JSON.stringify(entry)); @@ -15,7 +19,7 @@ const EventJson = ({ entry }) => { return (
  • - {prettyPrinted} + {prettyPrinted}
  • ); diff --git a/frontend/src/component/history/EventLog/EventLog.jsx b/frontend/src/component/history/EventLog/EventLog.tsx similarity index 69% rename from frontend/src/component/history/EventLog/EventLog.jsx rename to frontend/src/component/history/EventLog/EventLog.tsx index cd3e75ff7b..b4f9967e85 100644 --- a/frontend/src/component/history/EventLog/EventLog.jsx +++ b/frontend/src/component/history/EventLog/EventLog.tsx @@ -1,35 +1,47 @@ import { List, Switch, FormControlLabel } from '@mui/material'; -import PropTypes from 'prop-types'; -import EventJson from './EventJson/EventJson'; +import EventJson from 'component/history/EventLog/EventJson/EventJson'; import { PageContent } from 'component/common/PageContent/PageContent'; 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 { 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>; + locationSettings: ILocationSettings; + displayInline?: boolean; +} const EventLog = ({ title, - history, + events, eventSettings, setEventSettings, locationSettings, displayInline, -}) => { +}: IEventLogProps) => { const { classes: styles } = useStyles(); const toggleShowDiff = () => { setEventSettings({ showData: !eventSettings.showData }); }; - const formatFulldateTime = v => { + const formatFulldateTime = (v: string) => { return formatDateYMDHMS(v, locationSettings.locale); }; - if (!history || history.length < 0) { + if (!events || events.length < 0) { return null; } let entries; - const renderListItemCards = entry => ( + const renderListItemCards = (entry: IEvent) => (
  • ( + entries = events.map(entry => ( )); } else { - entries = history.map(renderListItemCards); + entries = events.map(renderListItemCards); } 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; diff --git a/frontend/src/component/history/EventLog/index.tsx b/frontend/src/component/history/EventLog/index.tsx index 2709266b51..0f9e64c86e 100644 --- a/frontend/src/component/history/EventLog/index.tsx +++ b/frontend/src/component/history/EventLog/index.tsx @@ -1,10 +1,11 @@ -import EventLog from './EventLog'; +import EventLog from 'component/history/EventLog/EventLog'; import { useEventSettings } from 'hooks/useEventSettings'; import { useLocationSettings } from 'hooks/useLocationSettings'; +import { IEvent } from 'interfaces/event'; interface IEventLogContainerProps { title: string; - history: unknown[]; + events: IEvent[]; displayInline?: boolean; } @@ -15,7 +16,7 @@ const EventLogContainer = (props: IEventLogContainerProps) => { return ( { - const { events } = useFeatureEvents(toggleName); - - if (events.length === 0) { - return null; - } - - return ( - - ); -}; - -FeatureEventHistory.propTypes = { - toggleName: PropTypes.string.isRequired, -}; diff --git a/frontend/src/component/history/FeatureEventHistory/FeatureEventHistory.tsx b/frontend/src/component/history/FeatureEventHistory/FeatureEventHistory.tsx new file mode 100644 index 0000000000..44764a4a58 --- /dev/null +++ b/frontend/src/component/history/FeatureEventHistory/FeatureEventHistory.tsx @@ -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 ; +}; diff --git a/frontend/src/component/history/FeatureEventHistoryPage/FeatureEventHistoryPage.tsx b/frontend/src/component/history/FeatureEventHistoryPage/FeatureEventHistoryPage.tsx index 3abc1277a7..01b61be817 100644 --- a/frontend/src/component/history/FeatureEventHistoryPage/FeatureEventHistoryPage.tsx +++ b/frontend/src/component/history/FeatureEventHistoryPage/FeatureEventHistoryPage.tsx @@ -1,9 +1,9 @@ import React from 'react'; -import { FeatureEventHistory } from '../FeatureEventHistory/FeatureEventHistory'; +import { FeatureEventHistory } from 'component/history/FeatureEventHistory/FeatureEventHistory'; import { useRequiredPathParam } from 'hooks/useRequiredPathParam'; export const FeatureEventHistoryPage = () => { const toggleName = useRequiredPathParam('toggleName'); - return ; + return ; }; diff --git a/frontend/src/component/project/ProjectAccess/ProjectAccessAssign/ProjectRoleDescription/ProjectRoleDescription.tsx b/frontend/src/component/project/ProjectAccess/ProjectAccessAssign/ProjectRoleDescription/ProjectRoleDescription.tsx index d4f66881d8..f9d2276693 100644 --- a/frontend/src/component/project/ProjectAccess/ProjectAccessAssign/ProjectRoleDescription/ProjectRoleDescription.tsx +++ b/frontend/src/component/project/ProjectAccess/ProjectAccessAssign/ProjectRoleDescription/ProjectRoleDescription.tsx @@ -44,27 +44,44 @@ export const ProjectRoleDescription: VFC = ({ const environments = useMemo(() => { const environments = new Set(); role.permissions - ?.filter((permission: any) => permission.environment !== '') + ?.filter((permission: any) => permission.environment) .forEach((permission: any) => { environments.add(permission.environment); }); return [...environments].sort(); }, [role]); + const projectPermissions = useMemo(() => { + return role.permissions?.filter( + (permission: any) => !permission.environment + ); + }, [role]); + return ( - - Project permissions - - - {role.permissions - ?.filter((permission: any) => permission.environment === '') - .map((permission: any) => permission.displayName) - .sort() - .map((permission: any) => ( -

    {permission}

    - ))} -
    + + + Project permissions + + + {role.permissions + ?.filter( + (permission: any) => !permission.environment + ) + .map( + (permission: any) => permission.displayName + ) + .sort() + .map((permission: any) => ( +

    {permission}

    + ))} +
    + + } + /> =3.0.0 <4.0.0" immutable "^4.0.0"