mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	feat: review your draft sidebar (#2305)
* refactor playground status chip component * fix: update change request sidebar * refactor: status badge cleanup * fix: prettier formatting
This commit is contained in:
		
							parent
							
								
									2f1f9cecc2
								
							
						
					
					
						commit
						0a855604af
					
				| @ -4,18 +4,18 @@ import { ChangeRequestFeatureToggleChange } from '../ChangeRequestOverview/Chang | |||||||
| import { objectId } from 'utils/objectId'; | import { objectId } from 'utils/objectId'; | ||||||
| import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; | import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; | ||||||
| import { ToggleStatusChange } from '../ChangeRequestOverview/ChangeRequestFeatureToggleChange/ToggleStatusChange'; | import { ToggleStatusChange } from '../ChangeRequestOverview/ChangeRequestFeatureToggleChange/ToggleStatusChange'; | ||||||
| import type { IChangeRequestResponse } from 'hooks/api/getters/useChangeRequestDraft/useChangeRequestDraft'; |  | ||||||
| import { useChangeRequestApi } from 'hooks/api/actions/useChangeRequestApi/useChangeRequestApi'; | import { useChangeRequestApi } from 'hooks/api/actions/useChangeRequestApi/useChangeRequestApi'; | ||||||
| import { formatUnknownError } from 'utils/formatUnknownError'; | import { formatUnknownError } from 'utils/formatUnknownError'; | ||||||
| import useToast from 'hooks/useToast'; | import useToast from 'hooks/useToast'; | ||||||
|  | import type { IChangeRequest } from '../changeRequest.types'; | ||||||
| 
 | 
 | ||||||
| interface IChangeRequest { | interface IChangeRequestProps { | ||||||
|     changeRequest: IChangeRequestResponse; |     changeRequest: IChangeRequest; | ||||||
|     onRefetch?: () => void; |     onRefetch?: () => void; | ||||||
|     onNavigate?: () => void; |     onNavigate?: () => void; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export const ChangeRequest: VFC<IChangeRequest> = ({ | export const ChangeRequest: VFC<IChangeRequestProps> = ({ | ||||||
|     changeRequest, |     changeRequest, | ||||||
|     onRefetch, |     onRefetch, | ||||||
|     onNavigate, |     onNavigate, | ||||||
| @ -41,7 +41,6 @@ export const ChangeRequest: VFC<IChangeRequest> = ({ | |||||||
| 
 | 
 | ||||||
|     return ( |     return ( | ||||||
|         <Box> |         <Box> | ||||||
|             Changes |  | ||||||
|             {changeRequest.features?.map(featureToggleChange => ( |             {changeRequest.features?.map(featureToggleChange => ( | ||||||
|                 <ChangeRequestFeatureToggleChange |                 <ChangeRequestFeatureToggleChange | ||||||
|                     key={featureToggleChange.name} |                     key={featureToggleChange.name} | ||||||
| @ -55,6 +54,7 @@ export const ChangeRequest: VFC<IChangeRequest> = ({ | |||||||
|                                 condition={change.action === 'updateEnabled'} |                                 condition={change.action === 'updateEnabled'} | ||||||
|                                 show={ |                                 show={ | ||||||
|                                     <ToggleStatusChange |                                     <ToggleStatusChange | ||||||
|  |                                         // @ts-expect-error TODO: fix types
 | ||||||
|                                         enabled={change?.payload?.enabled} |                                         enabled={change?.payload?.enabled} | ||||||
|                                         onDiscard={onDiscard(change.id)} |                                         onDiscard={onDiscard(change.id)} | ||||||
|                                     /> |                                     /> | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| import { VFC } from 'react'; | import { VFC } from 'react'; | ||||||
| import { Link, Box, Typography } from '@mui/material'; | import { Link, Box } from '@mui/material'; | ||||||
| import { PlaygroundResultChip } from 'component/playground/Playground/PlaygroundResultsTable/PlaygroundResultChip/PlaygroundResultChip'; |  | ||||||
| import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; | import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; | ||||||
|  | import { Badge } from 'component/common/Badge/Badge'; | ||||||
| 
 | 
 | ||||||
| interface IPlaygroundResultsTable { | interface IPlaygroundResultsTable { | ||||||
|     enabled: boolean; |     enabled: boolean; | ||||||
| @ -16,11 +16,9 @@ export const ToggleStatusChange: VFC<IPlaygroundResultsTable> = ({ | |||||||
|         <Box sx={{ p: 1, display: 'flex', justifyContent: 'space-between' }}> |         <Box sx={{ p: 1, display: 'flex', justifyContent: 'space-between' }}> | ||||||
|             <Box> |             <Box> | ||||||
|                 New status:{' '} |                 New status:{' '} | ||||||
|                 <PlaygroundResultChip |                 <Badge color={enabled ? 'success' : 'error'}> | ||||||
|                     showIcon={false} |                     {enabled ? ' Enabled' : 'Disabled'} | ||||||
|                     label={enabled ? ' Enabled' : 'Disabled'} |                 </Badge> | ||||||
|                     enabled={enabled} |  | ||||||
|                 /> |  | ||||||
|             </Box> |             </Box> | ||||||
|             <ConditionallyRender |             <ConditionallyRender | ||||||
|                 condition={Boolean(onDiscard)} |                 condition={Boolean(onDiscard)} | ||||||
|  | |||||||
| @ -2,8 +2,8 @@ import { Box } from '@mui/material'; | |||||||
| import { FC } from 'react'; | import { FC } from 'react'; | ||||||
| import { Typography } from '@mui/material'; | import { Typography } from '@mui/material'; | ||||||
| import TimeAgo from 'react-timeago'; | import TimeAgo from 'react-timeago'; | ||||||
| import { resolveChangeRequestStatusIcon } from 'component/changeRequest/changeRequest.utils'; |  | ||||||
| import { IChangeRequest } from 'component/changeRequest/changeRequest.types'; | import { IChangeRequest } from 'component/changeRequest/changeRequest.types'; | ||||||
|  | import { ChangeRequestStatusBadge } from 'component/changeRequest/ChangeRequestStatusBadge/ChangeRequestStatusBadge'; | ||||||
| import { | import { | ||||||
|     StyledPaper, |     StyledPaper, | ||||||
|     StyledContainer, |     StyledContainer, | ||||||
| @ -22,7 +22,7 @@ export const ChangeRequestHeader: FC<{ changeRequest: IChangeRequest }> = ({ | |||||||
|                 <StyledHeader variant="h1"> |                 <StyledHeader variant="h1"> | ||||||
|                     Change request #{changeRequest.id} |                     Change request #{changeRequest.id} | ||||||
|                 </StyledHeader> |                 </StyledHeader> | ||||||
|                 {resolveChangeRequestStatusIcon(changeRequest.state)} |                 <ChangeRequestStatusBadge state={changeRequest.state} />; | ||||||
|             </StyledContainer> |             </StyledContainer> | ||||||
|             <StyledInnerContainer> |             <StyledInnerContainer> | ||||||
|                 <Typography variant="body2" sx={{ margin: 'auto 0' }}> |                 <Typography variant="body2" sx={{ margin: 'auto 0' }}> | ||||||
|  | |||||||
| @ -65,6 +65,7 @@ export const ChangeRequestOverview: FC = () => { | |||||||
|                             padding: theme.spacing(2), |                             padding: theme.spacing(2), | ||||||
|                         })} |                         })} | ||||||
|                     > |                     > | ||||||
|  |                         Changes | ||||||
|                         <ChangeRequest changeRequest={changeRequest} /> |                         <ChangeRequest changeRequest={changeRequest} /> | ||||||
|                         <ChangeRequestReviewStatus |                         <ChangeRequestReviewStatus | ||||||
|                             approved={ |                             approved={ | ||||||
| @ -72,7 +73,6 @@ export const ChangeRequestOverview: FC = () => { | |||||||
|                                 changeRequest.state === 'Applied' |                                 changeRequest.state === 'Applied' | ||||||
|                             } |                             } | ||||||
|                         /> |                         /> | ||||||
| 
 |  | ||||||
|                         <Button |                         <Button | ||||||
|                             variant="contained" |                             variant="contained" | ||||||
|                             sx={{ marginTop: 2 }} |                             sx={{ marginTop: 2 }} | ||||||
|  | |||||||
| @ -1,19 +1,29 @@ | |||||||
| import { VFC } from 'react'; | import { VFC } from 'react'; | ||||||
| import { Box, Button, Typography, styled, Tooltip } from '@mui/material'; | import { | ||||||
|  |     Box, | ||||||
|  |     Button, | ||||||
|  |     Typography, | ||||||
|  |     styled, | ||||||
|  |     Tooltip, | ||||||
|  |     Divider, | ||||||
|  | } from '@mui/material'; | ||||||
| import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; | import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; | ||||||
| import { SidebarModal } from 'component/common/SidebarModal/SidebarModal'; | import { SidebarModal } from 'component/common/SidebarModal/SidebarModal'; | ||||||
| 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 { HelpOutline } from '@mui/icons-material'; | import { HelpOutline } from '@mui/icons-material'; | ||||||
|  | import EnvironmentIcon from 'component/common/EnvironmentIcon/EnvironmentIcon'; | ||||||
| import { ChangeRequest } from '../ChangeRequest/ChangeRequest'; | import { ChangeRequest } from '../ChangeRequest/ChangeRequest'; | ||||||
| import { useChangeRequestDraft } from 'hooks/api/getters/useChangeRequestDraft/useChangeRequestDraft'; | import { useChangeRequestDraft } from 'hooks/api/getters/useChangeRequestDraft/useChangeRequestDraft'; | ||||||
| import { useChangeRequestApi } from 'hooks/api/actions/useChangeRequestApi/useChangeRequestApi'; | import { useChangeRequestApi } from 'hooks/api/actions/useChangeRequestApi/useChangeRequestApi'; | ||||||
|  | import { ChangeRequestStatusBadge } from '../ChangeRequestStatusBadge/ChangeRequestStatusBadge'; | ||||||
| 
 | 
 | ||||||
| interface IChangeRequestSidebarProps { | interface IChangeRequestSidebarProps { | ||||||
|     open: boolean; |     open: boolean; | ||||||
|     project: string; |     project: string; | ||||||
|     onClose: () => void; |     onClose: () => void; | ||||||
| } | } | ||||||
|  | 
 | ||||||
| const StyledPageContent = styled(PageContent)(({ theme }) => ({ | const StyledPageContent = styled(PageContent)(({ theme }) => ({ | ||||||
|     height: '100vh', |     height: '100vh', | ||||||
|     overflow: 'auto', |     overflow: 'auto', | ||||||
| @ -41,6 +51,11 @@ const StyledHeaderHint = styled('div')(({ theme }) => ({ | |||||||
|     fontSize: theme.fontSizes.smallBody, |     fontSize: theme.fontSizes.smallBody, | ||||||
| })); | })); | ||||||
| 
 | 
 | ||||||
|  | const BackButton = styled(Button)(({ theme }) => ({ | ||||||
|  |     marginTop: theme.spacing(2), | ||||||
|  |     marginLeft: 'auto', | ||||||
|  | })); | ||||||
|  | 
 | ||||||
| export const ChangeRequestSidebar: VFC<IChangeRequestSidebarProps> = ({ | export const ChangeRequestSidebar: VFC<IChangeRequestSidebarProps> = ({ | ||||||
|     open, |     open, | ||||||
|     project, |     project, | ||||||
| @ -85,6 +100,7 @@ export const ChangeRequestSidebar: VFC<IChangeRequestSidebarProps> = ({ | |||||||
|                 > |                 > | ||||||
|                     There are no changes to review. |                     There are no changes to review. | ||||||
|                     {/* FIXME: empty state */} |                     {/* FIXME: empty state */} | ||||||
|  |                     <BackButton onClick={onClose}>Close</BackButton> | ||||||
|                 </StyledPageContent> |                 </StyledPageContent> | ||||||
|             </SidebarModal> |             </SidebarModal> | ||||||
|         ); |         ); | ||||||
| @ -126,13 +142,23 @@ export const ChangeRequestSidebar: VFC<IChangeRequestSidebarProps> = ({ | |||||||
|                                 `${theme.shape.borderRadiusLarge}px`, |                                 `${theme.shape.borderRadiusLarge}px`, | ||||||
|                         }} |                         }} | ||||||
|                     > |                     > | ||||||
|                         <Typography> |                         <Box sx={{ display: 'flex', alignItems: 'center' }}> | ||||||
|                             env: {environmentChangeRequest?.environment} |                             <Box sx={{ display: 'flex' }}> | ||||||
|  |                                 <EnvironmentIcon enabled={true} /> | ||||||
|  |                                 <Typography component="span" variant="h2"> | ||||||
|  |                                     {environmentChangeRequest?.environment} | ||||||
|  |                                 </Typography> | ||||||
|  |                             </Box> | ||||||
|  |                             <Box sx={{ ml: 'auto' }}> | ||||||
|  |                                 <ChangeRequestStatusBadge | ||||||
|  |                                     state={environmentChangeRequest?.state} | ||||||
|  |                                 /> | ||||||
|  |                             </Box> | ||||||
|  |                         </Box> | ||||||
|  |                         <Divider sx={{ my: 3 }} /> | ||||||
|  |                         <Typography variant="body1" color="text.secondary"> | ||||||
|  |                             You request changes for these feature toggles: | ||||||
|                         </Typography> |                         </Typography> | ||||||
|                         <Typography> |  | ||||||
|                             state: {environmentChangeRequest?.state} |  | ||||||
|                         </Typography> |  | ||||||
|                         <hr /> |  | ||||||
|                         <ChangeRequest |                         <ChangeRequest | ||||||
|                             changeRequest={environmentChangeRequest} |                             changeRequest={environmentChangeRequest} | ||||||
|                             onNavigate={() => { |                             onNavigate={() => { | ||||||
| @ -144,20 +170,21 @@ export const ChangeRequestSidebar: VFC<IChangeRequestSidebarProps> = ({ | |||||||
|                             <ConditionallyRender |                             <ConditionallyRender | ||||||
|                                 condition={ |                                 condition={ | ||||||
|                                     environmentChangeRequest?.state === |                                     environmentChangeRequest?.state === | ||||||
|                                     'APPROVED' |                                     'Approved' | ||||||
|                                 } |  | ||||||
|                                 show={<Typography>Applied</Typography>} |  | ||||||
|                             /> |  | ||||||
|                             <ConditionallyRender |  | ||||||
|                                 condition={ |  | ||||||
|                                     environmentChangeRequest?.state === 'CLOSED' |  | ||||||
|                                 } |                                 } | ||||||
|                                 show={<Typography>Applied</Typography>} |                                 show={<Typography>Applied</Typography>} | ||||||
|                             /> |                             /> | ||||||
|                             <ConditionallyRender |                             <ConditionallyRender | ||||||
|                                 condition={ |                                 condition={ | ||||||
|                                     environmentChangeRequest?.state === |                                     environmentChangeRequest?.state === | ||||||
|                                     'APPROVED' |                                     'Applied' | ||||||
|  |                                 } | ||||||
|  |                                 show={<Typography>Applied</Typography>} | ||||||
|  |                             /> | ||||||
|  |                             <ConditionallyRender | ||||||
|  |                                 condition={ | ||||||
|  |                                     environmentChangeRequest?.state === | ||||||
|  |                                     'Approved' | ||||||
|                                 } |                                 } | ||||||
|                                 show={ |                                 show={ | ||||||
|                                     <> |                                     <> | ||||||
| @ -201,6 +228,7 @@ export const ChangeRequestSidebar: VFC<IChangeRequestSidebarProps> = ({ | |||||||
|                         </Box> |                         </Box> | ||||||
|                     </Box> |                     </Box> | ||||||
|                 ))} |                 ))} | ||||||
|  |                 <BackButton onClick={onClose}>Close</BackButton> | ||||||
|             </StyledPageContent> |             </StyledPageContent> | ||||||
|         </SidebarModal> |         </SidebarModal> | ||||||
|     ); |     ); | ||||||
|  | |||||||
| @ -1,18 +1,26 @@ | |||||||
| import { ChangeRequestState } from './changeRequest.types'; | import { VFC } from 'react'; | ||||||
|  | import { ChangeRequestState } from '../changeRequest.types'; | ||||||
| import { Badge } from 'component/common/Badge/Badge'; | import { Badge } from 'component/common/Badge/Badge'; | ||||||
| import { Check, CircleOutlined, Close } from '@mui/icons-material'; | import { Check, CircleOutlined, Close } from '@mui/icons-material'; | ||||||
| 
 | 
 | ||||||
| export const resolveChangeRequestStatusIcon = (state: ChangeRequestState) => { | interface IChangeRequestStatusBadgeProps { | ||||||
|     const reviewRequired = ( |     state: ChangeRequestState; | ||||||
|         <Badge color="secondary" icon={<CircleOutlined fontSize={'small'} />}> | } | ||||||
|             Review required | 
 | ||||||
|         </Badge> | const ReviewRequiredBadge: VFC = () => ( | ||||||
|     ); |     <Badge color="secondary" icon={<CircleOutlined fontSize={'small'} />}> | ||||||
|  |         Review required | ||||||
|  |     </Badge> | ||||||
|  | ); | ||||||
|  | 
 | ||||||
|  | export const ChangeRequestStatusBadge: VFC<IChangeRequestStatusBadgeProps> = ({ | ||||||
|  |     state, | ||||||
|  | }) => { | ||||||
|     switch (state) { |     switch (state) { | ||||||
|         case 'Draft': |         case 'Draft': | ||||||
|             return reviewRequired; |             return <ReviewRequiredBadge />; | ||||||
|         case 'In review': |         case 'In review': | ||||||
|             return reviewRequired; |             return <ReviewRequiredBadge />; | ||||||
|         case 'Approved': |         case 'Approved': | ||||||
|             return ( |             return ( | ||||||
|                 <Badge color="success" icon={<Check fontSize={'small'} />}> |                 <Badge color="success" icon={<Check fontSize={'small'} />}> | ||||||
| @ -35,6 +43,6 @@ export const resolveChangeRequestStatusIcon = (state: ChangeRequestState) => { | |||||||
|                 </Badge> |                 </Badge> | ||||||
|             ); |             ); | ||||||
|         default: |         default: | ||||||
|             return reviewRequired; |             return <ReviewRequiredBadge />; | ||||||
|     } |     } | ||||||
| }; | }; | ||||||
| @ -1,10 +1,10 @@ | |||||||
| import { VFC } from 'react'; | import { VFC } from 'react'; | ||||||
| import { TextCell } from 'component/common/Table/cells/TextCell/TextCell'; | import { TextCell } from 'component/common/Table/cells/TextCell/TextCell'; | ||||||
| import { resolveChangeRequestStatusIcon } from 'component/changeRequest/changeRequest.utils'; |  | ||||||
| import { ChangeRequestState } from 'component/changeRequest/changeRequest.types'; | import { ChangeRequestState } from 'component/changeRequest/changeRequest.types'; | ||||||
|  | import { ChangeRequestStatusBadge } from 'component/changeRequest/ChangeRequestStatusBadge/ChangeRequestStatusBadge'; | ||||||
| 
 | 
 | ||||||
| interface IChangeRequestStatusCellProps { | interface IChangeRequestStatusCellProps { | ||||||
|     value?: string | null; |     value?: string | null; // FIXME: proper type
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export const ChangeRequestStatusCell: VFC<IChangeRequestStatusCellProps> = ({ | export const ChangeRequestStatusCell: VFC<IChangeRequestStatusCellProps> = ({ | ||||||
| @ -12,7 +12,7 @@ export const ChangeRequestStatusCell: VFC<IChangeRequestStatusCellProps> = ({ | |||||||
| }) => { | }) => { | ||||||
|     const renderState = () => { |     const renderState = () => { | ||||||
|         if (!value) return null; |         if (!value) return null; | ||||||
|         return resolveChangeRequestStatusIcon(value as ChangeRequestState); |         return <ChangeRequestStatusBadge state={value as ChangeRequestState} />; | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     if (!value) { |     if (!value) { | ||||||
|  | |||||||
| @ -1,12 +1,15 @@ | |||||||
| import { Chip } from '@mui/material'; | import { Chip } from '@mui/material'; | ||||||
| import { useStyles } from './StatusChip.styles'; | import { useStyles } from './FeatureStatusChip.styles'; | ||||||
| 
 | 
 | ||||||
| interface IStatusChip { | interface IStatusChip { | ||||||
|     stale: boolean; |     stale: boolean; | ||||||
|     showActive?: boolean; |     showActive?: boolean; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const StatusChip = ({ stale, showActive = true }: IStatusChip) => { | export const FeatureStatusChip = ({ | ||||||
|  |     stale, | ||||||
|  |     showActive = true, | ||||||
|  | }: IStatusChip) => { | ||||||
|     const { classes: styles } = useStyles(); |     const { classes: styles } = useStyles(); | ||||||
| 
 | 
 | ||||||
|     if (!stale && !showActive) { |     if (!stale && !showActive) { | ||||||
| @ -30,5 +33,3 @@ const StatusChip = ({ stale, showActive = true }: IStatusChip) => { | |||||||
|         </div> |         </div> | ||||||
|     ); |     ); | ||||||
| }; | }; | ||||||
| 
 |  | ||||||
| export default StatusChip; |  | ||||||
| @ -1,208 +0,0 @@ | |||||||
| import { memo } from 'react'; |  | ||||||
| import classnames from 'classnames'; |  | ||||||
| import { Link } from 'react-router-dom'; |  | ||||||
| import { Chip, ListItem, Tooltip } from '@mui/material'; |  | ||||||
| import { Undo } from '@mui/icons-material'; |  | ||||||
| import TimeAgo from 'react-timeago'; |  | ||||||
| import { IAccessContext } from 'contexts/AccessContext'; |  | ||||||
| import StatusChip from 'component/common/StatusChip/StatusChip'; |  | ||||||
| import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; |  | ||||||
| import { UPDATE_FEATURE } from 'component/providers/AccessProvider/permissions'; |  | ||||||
| import { IFlags } from 'interfaces/uiConfig'; |  | ||||||
| import { getTogglePath } from 'utils/routePathHelpers'; |  | ||||||
| import FeatureStatus from 'component/feature/FeatureView/FeatureStatus/FeatureStatus'; |  | ||||||
| import FeatureType from 'component/feature/FeatureView/FeatureType/FeatureType'; |  | ||||||
| import useProjects from 'hooks/api/getters/useProjects/useProjects'; |  | ||||||
| import PermissionIconButton from 'component/common/PermissionIconButton/PermissionIconButton'; |  | ||||||
| import { FeatureSchema } from 'openapi'; |  | ||||||
| import { styles as themeStyles } from 'component/common'; |  | ||||||
| import { useStyles } from './styles'; |  | ||||||
| 
 |  | ||||||
| interface IFeatureToggleListItemProps { |  | ||||||
|     feature: FeatureSchema; |  | ||||||
|     onRevive?: (id: string) => void; |  | ||||||
|     hasAccess: IAccessContext['hasAccess']; |  | ||||||
|     flags?: IFlags; |  | ||||||
|     inProject?: boolean; |  | ||||||
|     className?: string; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * @deprecated |  | ||||||
|  */ |  | ||||||
| export const FeatureToggleListItem = memo<IFeatureToggleListItemProps>( |  | ||||||
|     ({ |  | ||||||
|         feature, |  | ||||||
|         onRevive, |  | ||||||
|         hasAccess, |  | ||||||
|         flags = {}, |  | ||||||
|         inProject, |  | ||||||
|         className, |  | ||||||
|         ...rest |  | ||||||
|     }) => { |  | ||||||
|         const { classes: styles } = useStyles(); |  | ||||||
| 
 |  | ||||||
|         const { projects } = useProjects(); |  | ||||||
|         const isArchive = Boolean(onRevive); |  | ||||||
| 
 |  | ||||||
|         const { |  | ||||||
|             name, |  | ||||||
|             description, |  | ||||||
|             type, |  | ||||||
|             stale, |  | ||||||
|             createdAt, |  | ||||||
|             project, |  | ||||||
|             lastSeenAt, |  | ||||||
|         } = feature; |  | ||||||
| 
 |  | ||||||
|         const projectExists = () => { |  | ||||||
|             let projectExist = projects.find(proj => proj.id === project); |  | ||||||
|             if (projectExist) { |  | ||||||
|                 return true; |  | ||||||
|             } |  | ||||||
|             return false; |  | ||||||
|         }; |  | ||||||
| 
 |  | ||||||
|         const reviveFeature = () => { |  | ||||||
|             if (projectExists() && onRevive) { |  | ||||||
|                 onRevive(feature.name); |  | ||||||
|             } |  | ||||||
|         }; |  | ||||||
| 
 |  | ||||||
|         return ( |  | ||||||
|             <ListItem |  | ||||||
|                 {...rest} |  | ||||||
|                 className={classnames(styles.listItem, className)} |  | ||||||
|             > |  | ||||||
|                 <span className={styles.listItemMetric}> |  | ||||||
|                     <FeatureStatus |  | ||||||
|                         lastSeenAt={lastSeenAt} |  | ||||||
|                         tooltipPlacement="left" |  | ||||||
|                     /> |  | ||||||
|                 </span> |  | ||||||
|                 <span |  | ||||||
|                     className={classnames( |  | ||||||
|                         styles.listItemType, |  | ||||||
|                         themeStyles.hideLt600 |  | ||||||
|                     )} |  | ||||||
|                 > |  | ||||||
|                     <FeatureType type={type as string} /> |  | ||||||
|                 </span> |  | ||||||
|                 <span className={classnames(styles.listItemLink)}> |  | ||||||
|                     <ConditionallyRender |  | ||||||
|                         condition={!isArchive} |  | ||||||
|                         show={ |  | ||||||
|                             <Link |  | ||||||
|                                 to={getTogglePath(feature.project!, name)} |  | ||||||
|                                 className={classnames( |  | ||||||
|                                     themeStyles.listLink, |  | ||||||
|                                     themeStyles.truncate |  | ||||||
|                                 )} |  | ||||||
|                             > |  | ||||||
|                                 <Tooltip title={description || ''} arrow> |  | ||||||
|                                     <span className={themeStyles.toggleName}> |  | ||||||
|                                         {name}  |  | ||||||
|                                     </span> |  | ||||||
|                                 </Tooltip> |  | ||||||
|                                 {/* <span className={styles.listItemToggle}></span> */} |  | ||||||
|                                 <span></span> |  | ||||||
|                                 <small> |  | ||||||
|                                     <ConditionallyRender |  | ||||||
|                                         condition={Boolean(createdAt)} |  | ||||||
|                                         show={() => ( |  | ||||||
|                                             <TimeAgo |  | ||||||
|                                                 date={createdAt as Date} |  | ||||||
|                                                 live={false} |  | ||||||
|                                             /> |  | ||||||
|                                         )} |  | ||||||
|                                     /> |  | ||||||
|                                 </small> |  | ||||||
|                                 <div> |  | ||||||
|                                     <span className={themeStyles.truncate}> |  | ||||||
|                                         <small>{description}</small> |  | ||||||
|                                     </span> |  | ||||||
|                                 </div> |  | ||||||
|                             </Link> |  | ||||||
|                         } |  | ||||||
|                         elseShow={ |  | ||||||
|                             <> |  | ||||||
|                                 <Tooltip title={description || ''} arrow> |  | ||||||
|                                     <span className={themeStyles.toggleName}> |  | ||||||
|                                         {name} {' '} |  | ||||||
|                                     </span> |  | ||||||
|                                 </Tooltip> |  | ||||||
|                                 {/* <span className={styles.listItemToggle}></span> */} |  | ||||||
|                                 <span></span> |  | ||||||
|                                 <small> |  | ||||||
|                                     <ConditionallyRender |  | ||||||
|                                         condition={Boolean(createdAt)} |  | ||||||
|                                         show={() => ( |  | ||||||
|                                             <TimeAgo |  | ||||||
|                                                 date={createdAt as Date} |  | ||||||
|                                                 live={false} |  | ||||||
|                                             /> |  | ||||||
|                                         )} |  | ||||||
|                                     /> |  | ||||||
|                                 </small> |  | ||||||
|                                 <div> |  | ||||||
|                                     <span className={themeStyles.truncate}> |  | ||||||
|                                         <small>{description}</small> |  | ||||||
|                                     </span> |  | ||||||
|                                 </div> |  | ||||||
|                             </> |  | ||||||
|                         } |  | ||||||
|                     /> |  | ||||||
|                 </span> |  | ||||||
|                 <span |  | ||||||
|                     className={classnames( |  | ||||||
|                         styles.listItemStrategies, |  | ||||||
|                         themeStyles.hideLt920 |  | ||||||
|                     )} |  | ||||||
|                 > |  | ||||||
|                     <StatusChip stale={Boolean(stale)} showActive={false} /> |  | ||||||
|                     <ConditionallyRender |  | ||||||
|                         condition={!inProject} |  | ||||||
|                         show={ |  | ||||||
|                             <Link |  | ||||||
|                                 to={`/projects/${project}`} |  | ||||||
|                                 style={{ textDecoration: 'none' }} |  | ||||||
|                                 className={classnames({ |  | ||||||
|                                     [`${styles.disabledLink}`]: |  | ||||||
|                                         !projectExists(), |  | ||||||
|                                 })} |  | ||||||
|                             > |  | ||||||
|                                 <Chip |  | ||||||
|                                     color="primary" |  | ||||||
|                                     variant="outlined" |  | ||||||
|                                     style={{ |  | ||||||
|                                         marginLeft: '8px', |  | ||||||
|                                         cursor: 'pointer', |  | ||||||
|                                     }} |  | ||||||
|                                     title={`Project: ${project}`} |  | ||||||
|                                     label={project} |  | ||||||
|                                 /> |  | ||||||
|                             </Link> |  | ||||||
|                         } |  | ||||||
|                     /> |  | ||||||
|                 </span> |  | ||||||
|                 <ConditionallyRender |  | ||||||
|                     condition={isArchive} |  | ||||||
|                     show={ |  | ||||||
|                         <PermissionIconButton |  | ||||||
|                             permission={UPDATE_FEATURE} |  | ||||||
|                             projectId={project} |  | ||||||
|                             disabled={ |  | ||||||
|                                 !hasAccess(UPDATE_FEATURE, project) || |  | ||||||
|                                 !projectExists() |  | ||||||
|                             } |  | ||||||
|                             onClick={reviveFeature} |  | ||||||
|                             tooltipProps={{ title: 'Revive feature toggle' }} |  | ||||||
|                         > |  | ||||||
|                             <Undo /> |  | ||||||
|                         </PermissionIconButton> |  | ||||||
|                     } |  | ||||||
|                 /> |  | ||||||
|             </ListItem> |  | ||||||
|         ); |  | ||||||
|     } |  | ||||||
| ); |  | ||||||
| @ -1,291 +0,0 @@ | |||||||
| // Vitest Snapshot v1 |  | ||||||
| 
 |  | ||||||
| exports[`renders correctly with one feature 1`] = ` |  | ||||||
| [ |  | ||||||
|   <li |  | ||||||
|     className="MuiListItem-root makeStyles-listItem-1 MuiListItem-gutters" |  | ||||||
|     disabled={false} |  | ||||||
|   > |  | ||||||
|     <span |  | ||||||
|       className="makeStyles-listItemMetric-2" |  | ||||||
|     > |  | ||||||
|       <div |  | ||||||
|         aria-describedby={null} |  | ||||||
|         className="makeStyles-container-8" |  | ||||||
|         onBlur={[Function]} |  | ||||||
|         onFocus={[Function]} |  | ||||||
|         onMouseLeave={[Function]} |  | ||||||
|         onMouseOver={[Function]} |  | ||||||
|         onTouchEnd={[Function]} |  | ||||||
|         onTouchStart={[Function]} |  | ||||||
|         style={ |  | ||||||
|           { |  | ||||||
|             "background": "#EDF0F1", |  | ||||||
|             "fontSize": "0.8rem", |  | ||||||
|           } |  | ||||||
|         } |  | ||||||
|         title="No usage reported from connected applications" |  | ||||||
|       > |  | ||||||
|         <span |  | ||||||
|           style={ |  | ||||||
|             { |  | ||||||
|               "fontSize": "1.4rem", |  | ||||||
|             } |  | ||||||
|           } |  | ||||||
|         > |  | ||||||
|           ⊕ |  | ||||||
|         </span> |  | ||||||
|       </div> |  | ||||||
|     </span> |  | ||||||
|     <span |  | ||||||
|       className="makeStyles-listItemType-3 _hideLt600_1yorl_42" |  | ||||||
|     > |  | ||||||
|       <svg |  | ||||||
|         aria-describedby={null} |  | ||||||
|         aria-hidden={true} |  | ||||||
|         className="MuiSvgIcon-root makeStyles-icon-9" |  | ||||||
|         data-loading={true} |  | ||||||
|         focusable="false" |  | ||||||
|         onBlur={[Function]} |  | ||||||
|         onFocus={[Function]} |  | ||||||
|         onMouseLeave={[Function]} |  | ||||||
|         onMouseOver={[Function]} |  | ||||||
|         onTouchEnd={[Function]} |  | ||||||
|         onTouchStart={[Function]} |  | ||||||
|         title="This is a \\"\\" toggle" |  | ||||||
|         viewBox="0 0 24 24" |  | ||||||
|       > |  | ||||||
|         <path |  | ||||||
|           d="M12 4V1L8 5l4 4V6c3.31 0 6 2.69 6 6 0 1.01-.25 1.97-.7 2.8l1.46 1.46C19.54 15.03 20 13.57 20 12c0-4.42-3.58-8-8-8zm0 14c-3.31 0-6-2.69-6-6 0-1.01.25-1.97.7-2.8L5.24 7.74C4.46 8.97 4 10.43 4 12c0 4.42 3.58 8 8 8v3l4-4-4-4v3z" |  | ||||||
|         /> |  | ||||||
|       </svg> |  | ||||||
|     </span> |  | ||||||
|     <span |  | ||||||
|       className="makeStyles-listItemLink-5" |  | ||||||
|     > |  | ||||||
|       <a |  | ||||||
|         className="_listLink_1yorl_25 _truncate_1yorl_2" |  | ||||||
|         href="/projects/default/features/Another" |  | ||||||
|         onClick={[Function]} |  | ||||||
|       > |  | ||||||
|         <span |  | ||||||
|           aria-describedby={null} |  | ||||||
|           className="_toggleName_1yorl_84" |  | ||||||
|           onBlur={[Function]} |  | ||||||
|           onFocus={[Function]} |  | ||||||
|           onMouseLeave={[Function]} |  | ||||||
|           onMouseOver={[Function]} |  | ||||||
|           onTouchEnd={[Function]} |  | ||||||
|           onTouchStart={[Function]} |  | ||||||
|           title="another's description" |  | ||||||
|         > |  | ||||||
|           Another |  | ||||||
|             |  | ||||||
|         </span> |  | ||||||
|         <span /> |  | ||||||
|         <small> |  | ||||||
|           <time |  | ||||||
|             dateTime="2018-02-04T20:27:52.127Z" |  | ||||||
|             title="2018-02-04T20:27:52.127Z" |  | ||||||
|           > |  | ||||||
|             4 years ago |  | ||||||
|           </time> |  | ||||||
|         </small> |  | ||||||
|         <div> |  | ||||||
|           <span |  | ||||||
|             className="_truncate_1yorl_2" |  | ||||||
|           > |  | ||||||
|             <small> |  | ||||||
|               another's description |  | ||||||
|             </small> |  | ||||||
|           </span> |  | ||||||
|         </div> |  | ||||||
|       </a> |  | ||||||
|     </span> |  | ||||||
|     <span |  | ||||||
|       className="makeStyles-listItemStrategies-6 _hideLt920_1yorl_37" |  | ||||||
|     > |  | ||||||
|       <a |  | ||||||
|         className="makeStyles-disabledLink-7" |  | ||||||
|         href="/projects/default" |  | ||||||
|         onClick={[Function]} |  | ||||||
|         style={ |  | ||||||
|           { |  | ||||||
|             "textDecoration": "none", |  | ||||||
|           } |  | ||||||
|         } |  | ||||||
|       > |  | ||||||
|         <div |  | ||||||
|           className="MuiChip-root MuiChip-colorPrimary MuiChip-outlined MuiChip-outlinedPrimary" |  | ||||||
|           onKeyDown={[Function]} |  | ||||||
|           onKeyUp={[Function]} |  | ||||||
|           style={ |  | ||||||
|             { |  | ||||||
|               "cursor": "pointer", |  | ||||||
|               "marginLeft": "8px", |  | ||||||
|             } |  | ||||||
|           } |  | ||||||
|           title="Project: default" |  | ||||||
|         > |  | ||||||
|           <span |  | ||||||
|             className="MuiChip-label" |  | ||||||
|           > |  | ||||||
|             default |  | ||||||
|           </span> |  | ||||||
|         </div> |  | ||||||
|       </a> |  | ||||||
|     </span> |  | ||||||
|   </li>, |  | ||||||
|   <div |  | ||||||
|     aria-atomic={true} |  | ||||||
|     aria-live="polite" |  | ||||||
|     className="makeStyles-container-11" |  | ||||||
|     data-testid="ANNOUNCER_ELEMENT_TEST_ID" |  | ||||||
|     role="status" |  | ||||||
|   />, |  | ||||||
| ] |  | ||||||
| `; |  | ||||||
| 
 |  | ||||||
| exports[`renders correctly with one feature without permission 1`] = ` |  | ||||||
| [ |  | ||||||
|   <li |  | ||||||
|     className="MuiListItem-root makeStyles-listItem-1 MuiListItem-gutters" |  | ||||||
|     disabled={false} |  | ||||||
|   > |  | ||||||
|     <span |  | ||||||
|       className="makeStyles-listItemMetric-2" |  | ||||||
|     > |  | ||||||
|       <div |  | ||||||
|         aria-describedby={null} |  | ||||||
|         className="makeStyles-container-8" |  | ||||||
|         onBlur={[Function]} |  | ||||||
|         onFocus={[Function]} |  | ||||||
|         onMouseLeave={[Function]} |  | ||||||
|         onMouseOver={[Function]} |  | ||||||
|         onTouchEnd={[Function]} |  | ||||||
|         onTouchStart={[Function]} |  | ||||||
|         style={ |  | ||||||
|           { |  | ||||||
|             "background": "#EDF0F1", |  | ||||||
|             "fontSize": "0.8rem", |  | ||||||
|           } |  | ||||||
|         } |  | ||||||
|         title="No usage reported from connected applications" |  | ||||||
|       > |  | ||||||
|         <span |  | ||||||
|           style={ |  | ||||||
|             { |  | ||||||
|               "fontSize": "1.4rem", |  | ||||||
|             } |  | ||||||
|           } |  | ||||||
|         > |  | ||||||
|           ⊕ |  | ||||||
|         </span> |  | ||||||
|       </div> |  | ||||||
|     </span> |  | ||||||
|     <span |  | ||||||
|       className="makeStyles-listItemType-3 _hideLt600_1yorl_42" |  | ||||||
|     > |  | ||||||
|       <svg |  | ||||||
|         aria-describedby={null} |  | ||||||
|         aria-hidden={true} |  | ||||||
|         className="MuiSvgIcon-root makeStyles-icon-9" |  | ||||||
|         data-loading={true} |  | ||||||
|         focusable="false" |  | ||||||
|         onBlur={[Function]} |  | ||||||
|         onFocus={[Function]} |  | ||||||
|         onMouseLeave={[Function]} |  | ||||||
|         onMouseOver={[Function]} |  | ||||||
|         onTouchEnd={[Function]} |  | ||||||
|         onTouchStart={[Function]} |  | ||||||
|         title="This is a \\"\\" toggle" |  | ||||||
|         viewBox="0 0 24 24" |  | ||||||
|       > |  | ||||||
|         <path |  | ||||||
|           d="M12 4V1L8 5l4 4V6c3.31 0 6 2.69 6 6 0 1.01-.25 1.97-.7 2.8l1.46 1.46C19.54 15.03 20 13.57 20 12c0-4.42-3.58-8-8-8zm0 14c-3.31 0-6-2.69-6-6 0-1.01.25-1.97.7-2.8L5.24 7.74C4.46 8.97 4 10.43 4 12c0 4.42 3.58 8 8 8v3l4-4-4-4v3z" |  | ||||||
|         /> |  | ||||||
|       </svg> |  | ||||||
|     </span> |  | ||||||
|     <span |  | ||||||
|       className="makeStyles-listItemLink-5" |  | ||||||
|     > |  | ||||||
|       <a |  | ||||||
|         className="_listLink_1yorl_25 _truncate_1yorl_2" |  | ||||||
|         href="/projects/undefined/features/Another" |  | ||||||
|         onClick={[Function]} |  | ||||||
|       > |  | ||||||
|         <span |  | ||||||
|           aria-describedby={null} |  | ||||||
|           className="_toggleName_1yorl_84" |  | ||||||
|           onBlur={[Function]} |  | ||||||
|           onFocus={[Function]} |  | ||||||
|           onMouseLeave={[Function]} |  | ||||||
|           onMouseOver={[Function]} |  | ||||||
|           onTouchEnd={[Function]} |  | ||||||
|           onTouchStart={[Function]} |  | ||||||
|           title="another's description" |  | ||||||
|         > |  | ||||||
|           Another |  | ||||||
|             |  | ||||||
|         </span> |  | ||||||
|         <span /> |  | ||||||
|         <small> |  | ||||||
|           <time |  | ||||||
|             dateTime="2018-02-04T20:27:52.127Z" |  | ||||||
|             title="2018-02-04T20:27:52.127Z" |  | ||||||
|           > |  | ||||||
|             4 years ago |  | ||||||
|           </time> |  | ||||||
|         </small> |  | ||||||
|         <div> |  | ||||||
|           <span |  | ||||||
|             className="_truncate_1yorl_2" |  | ||||||
|           > |  | ||||||
|             <small> |  | ||||||
|               another's description |  | ||||||
|             </small> |  | ||||||
|           </span> |  | ||||||
|         </div> |  | ||||||
|       </a> |  | ||||||
|     </span> |  | ||||||
|     <span |  | ||||||
|       className="makeStyles-listItemStrategies-6 _hideLt920_1yorl_37" |  | ||||||
|     > |  | ||||||
|       <a |  | ||||||
|         className="makeStyles-disabledLink-7" |  | ||||||
|         href="/projects/undefined" |  | ||||||
|         onClick={[Function]} |  | ||||||
|         style={ |  | ||||||
|           { |  | ||||||
|             "textDecoration": "none", |  | ||||||
|           } |  | ||||||
|         } |  | ||||||
|       > |  | ||||||
|         <div |  | ||||||
|           className="MuiChip-root MuiChip-colorPrimary MuiChip-outlined MuiChip-outlinedPrimary" |  | ||||||
|           onKeyDown={[Function]} |  | ||||||
|           onKeyUp={[Function]} |  | ||||||
|           style={ |  | ||||||
|             { |  | ||||||
|               "cursor": "pointer", |  | ||||||
|               "marginLeft": "8px", |  | ||||||
|             } |  | ||||||
|           } |  | ||||||
|           title="Project: undefined" |  | ||||||
|         > |  | ||||||
|           <span |  | ||||||
|             className="MuiChip-label" |  | ||||||
|           /> |  | ||||||
|         </div> |  | ||||||
|       </a> |  | ||||||
|     </span> |  | ||||||
|   </li>, |  | ||||||
|   <div |  | ||||||
|     aria-atomic={true} |  | ||||||
|     aria-live="polite" |  | ||||||
|     className="makeStyles-container-11" |  | ||||||
|     data-testid="ANNOUNCER_ELEMENT_TEST_ID" |  | ||||||
|     role="status" |  | ||||||
|   />, |  | ||||||
| ] |  | ||||||
| `; |  | ||||||
| @ -1,37 +0,0 @@ | |||||||
| import { makeStyles } from 'tss-react/mui'; |  | ||||||
| 
 |  | ||||||
| export const useStyles = makeStyles()(theme => ({ |  | ||||||
|     listItem: { |  | ||||||
|         padding: '0', |  | ||||||
|         margin: '1rem 0', |  | ||||||
|         '&:hover': { |  | ||||||
|             backgroundColor: theme.palette.grey[200], |  | ||||||
|         }, |  | ||||||
|     }, |  | ||||||
|     listItemMetric: { |  | ||||||
|         width: '40px', |  | ||||||
|         marginRight: '0.25rem', |  | ||||||
|         flexShrink: 0, |  | ||||||
|     }, |  | ||||||
|     listItemType: { |  | ||||||
|         width: '40px', |  | ||||||
|         textAlign: 'center', |  | ||||||
|         marginRight: '0', |  | ||||||
|         flexShrink: 0, |  | ||||||
|     }, |  | ||||||
|     listItemSvg: { |  | ||||||
|         fill: theme.palette.grey[300], |  | ||||||
|     }, |  | ||||||
|     listItemLink: { |  | ||||||
|         marginLeft: '0.25rem', |  | ||||||
|         minWidth: '0', |  | ||||||
|     }, |  | ||||||
|     listItemStrategies: { |  | ||||||
|         marginLeft: 'auto', |  | ||||||
|         display: 'flex', |  | ||||||
|         alignItems: 'center', |  | ||||||
|     }, |  | ||||||
|     disabledLink: { |  | ||||||
|         pointerEvents: 'none', |  | ||||||
|     }, |  | ||||||
| })); |  | ||||||
| @ -86,7 +86,7 @@ const FeatureOverviewEnvSwitch = ({ | |||||||
|     const toggleEnvironment = async (e: React.ChangeEvent) => { |     const toggleEnvironment = async (e: React.ChangeEvent) => { | ||||||
|         if (uiConfig?.flags?.changeRequests && env.name === 'production') { |         if (uiConfig?.flags?.changeRequests && env.name === 'production') { | ||||||
|             e.preventDefault(); |             e.preventDefault(); | ||||||
|             onChangeRequestToggle(featureId, env.name, env.enabled); |             onChangeRequestToggle(featureId, env.name, !env.enabled); | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|         if (env.enabled) { |         if (env.enabled) { | ||||||
|  | |||||||
| @ -26,7 +26,7 @@ import useLoading from 'hooks/useLoading'; | |||||||
| import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; | import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; | ||||||
| import { FeatureStaleDialog } from 'component/common/FeatureStaleDialog/FeatureStaleDialog'; | import { FeatureStaleDialog } from 'component/common/FeatureStaleDialog/FeatureStaleDialog'; | ||||||
| import AddTagDialog from './FeatureOverview/AddTagDialog/AddTagDialog'; | import AddTagDialog from './FeatureOverview/AddTagDialog/AddTagDialog'; | ||||||
| import StatusChip from 'component/common/StatusChip/StatusChip'; | import { FeatureStatusChip } from 'component/common/FeatureStatusChip/FeatureStatusChip'; | ||||||
| import { FeatureNotFound } from 'component/feature/FeatureView/FeatureNotFound/FeatureNotFound'; | import { FeatureNotFound } from 'component/feature/FeatureView/FeatureNotFound/FeatureNotFound'; | ||||||
| import { useRequiredPathParam } from 'hooks/useRequiredPathParam'; | import { useRequiredPathParam } from 'hooks/useRequiredPathParam'; | ||||||
| import { FeatureArchiveDialog } from '../../common/FeatureArchiveDialog/FeatureArchiveDialog'; | import { FeatureArchiveDialog } from '../../common/FeatureArchiveDialog/FeatureArchiveDialog'; | ||||||
| @ -111,7 +111,7 @@ export const FeatureView = () => { | |||||||
|                                     <ConditionallyRender |                                     <ConditionallyRender | ||||||
|                                         condition={!smallScreen} |                                         condition={!smallScreen} | ||||||
|                                         show={ |                                         show={ | ||||||
|                                             <StatusChip |                                             <FeatureStatusChip | ||||||
|                                                 stale={feature?.stale} |                                                 stale={feature?.stale} | ||||||
|                                             /> |                                             /> | ||||||
|                                         } |                                         } | ||||||
|  | |||||||
| @ -1,10 +1,10 @@ | |||||||
| import { VFC } from 'react'; | import { VFC } from 'react'; | ||||||
| import { Chip, styled, useTheme } from '@mui/material'; | import { useTheme } from '@mui/material'; | ||||||
| import { colors } from 'themes/colors'; |  | ||||||
| import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; | import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; | ||||||
| import { ReactComponent as FeatureEnabledIcon } from 'assets/icons/isenabled-true.svg'; | import { ReactComponent as FeatureEnabledIcon } from 'assets/icons/isenabled-true.svg'; | ||||||
| import { ReactComponent as FeatureDisabledIcon } from 'assets/icons/isenabled-false.svg'; | import { ReactComponent as FeatureDisabledIcon } from 'assets/icons/isenabled-false.svg'; | ||||||
| import { WarningOutlined } from '@mui/icons-material'; | import { WarningOutlined } from '@mui/icons-material'; | ||||||
|  | import { Badge } from 'component/common/Badge/Badge'; | ||||||
| 
 | 
 | ||||||
| interface IResultChipProps { | interface IResultChipProps { | ||||||
|     enabled: boolean | 'unevaluated' | 'unknown'; |     enabled: boolean | 'unevaluated' | 'unknown'; | ||||||
| @ -13,51 +13,6 @@ interface IResultChipProps { | |||||||
|     showIcon?: boolean; |     showIcon?: boolean; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export const StyledChip = styled(Chip)(({ theme, icon }) => ({ |  | ||||||
|     padding: theme.spacing(0, 1), |  | ||||||
|     height: 24, |  | ||||||
|     borderRadius: theme.shape.borderRadius, |  | ||||||
|     fontWeight: theme.typography.fontWeightMedium, |  | ||||||
|     ['& .MuiChip-label']: { |  | ||||||
|         padding: 0, |  | ||||||
|         paddingLeft: Boolean(icon) ? theme.spacing(0.5) : 0, |  | ||||||
|     }, |  | ||||||
| })); |  | ||||||
| 
 |  | ||||||
| export const StyledFalseChip = styled(StyledChip)(({ theme }) => ({ |  | ||||||
|     border: `1px solid ${theme.palette.error.main}`, |  | ||||||
|     backgroundColor: colors.red['200'], |  | ||||||
|     ['& .MuiChip-label']: { |  | ||||||
|         color: theme.palette.error.main, |  | ||||||
|     }, |  | ||||||
|     ['& .MuiChip-icon']: { |  | ||||||
|         color: theme.palette.error.main, |  | ||||||
|     }, |  | ||||||
| })); |  | ||||||
| 
 |  | ||||||
| export const StyledTrueChip = styled(StyledChip)(({ theme }) => ({ |  | ||||||
|     border: `1px solid ${theme.palette.success.main}`, |  | ||||||
|     backgroundColor: colors.green['100'], |  | ||||||
|     ['& .MuiChip-label']: { |  | ||||||
|         color: theme.palette.success.main, |  | ||||||
|     }, |  | ||||||
|     ['& .MuiChip-icon']: { |  | ||||||
|         color: theme.palette.success.main, |  | ||||||
|         marginRight: 0, |  | ||||||
|     }, |  | ||||||
| })); |  | ||||||
| 
 |  | ||||||
| export const StyledUnknownChip = styled(StyledChip)(({ theme }) => ({ |  | ||||||
|     border: `1px solid ${theme.palette.warning.main}`, |  | ||||||
|     backgroundColor: colors.orange['100'], |  | ||||||
|     ['& .MuiChip-label']: { |  | ||||||
|         color: theme.palette.warning.main, |  | ||||||
|     }, |  | ||||||
|     ['& .MuiChip-icon']: { |  | ||||||
|         color: theme.palette.warning.main, |  | ||||||
|     }, |  | ||||||
| })); |  | ||||||
| 
 |  | ||||||
| export const PlaygroundResultChip: VFC<IResultChipProps> = ({ | export const PlaygroundResultChip: VFC<IResultChipProps> = ({ | ||||||
|     enabled, |     enabled, | ||||||
|     label, |     label, | ||||||
| @ -92,25 +47,25 @@ export const PlaygroundResultChip: VFC<IResultChipProps> = ({ | |||||||
|         <ConditionallyRender |         <ConditionallyRender | ||||||
|             condition={enabled === 'unknown' || enabled === 'unevaluated'} |             condition={enabled === 'unknown' || enabled === 'unevaluated'} | ||||||
|             show={ |             show={ | ||||||
|                 <StyledUnknownChip |                 <Badge icon={showIcon ? icon : undefined} color="warning"> | ||||||
|                     icon={showIcon ? icon : undefined} |                     {label} | ||||||
|                     label={label} |                 </Badge> | ||||||
|                 /> |  | ||||||
|             } |             } | ||||||
|             elseShow={ |             elseShow={ | ||||||
|                 <ConditionallyRender |                 <ConditionallyRender | ||||||
|                     condition={typeof enabled === 'boolean' && Boolean(enabled)} |                     condition={typeof enabled === 'boolean' && Boolean(enabled)} | ||||||
|                     show={ |                     show={ | ||||||
|                         <StyledTrueChip |                         <Badge | ||||||
|  |                             color="success" | ||||||
|                             icon={showIcon ? icon : undefined} |                             icon={showIcon ? icon : undefined} | ||||||
|                             label={label} |                         > | ||||||
|                         /> |                             {label} | ||||||
|  |                         </Badge> | ||||||
|                     } |                     } | ||||||
|                     elseShow={ |                     elseShow={ | ||||||
|                         <StyledFalseChip |                         <Badge color="error" icon={showIcon ? icon : undefined}> | ||||||
|                             icon={showIcon ? icon : undefined} |                             {label} | ||||||
|                             label={label} |                         </Badge> | ||||||
|                         /> |  | ||||||
|                     } |                     } | ||||||
|                 /> |                 /> | ||||||
|             } |             } | ||||||
|  | |||||||
| @ -2,37 +2,10 @@ import useSWR from 'swr'; | |||||||
| import { useMemo } from 'react'; | import { useMemo } from 'react'; | ||||||
| import { formatApiPath } from 'utils/formatPath'; | import { formatApiPath } from 'utils/formatPath'; | ||||||
| import handleErrorResponses from '../httpErrorResponseHandler'; | import handleErrorResponses from '../httpErrorResponseHandler'; | ||||||
| 
 | import { | ||||||
| interface IChange { |     ChangeRequestState, | ||||||
|     id: number; |     IChangeRequest, | ||||||
|     action: string; | } from 'component/changeRequest/changeRequest.types'; | ||||||
|     payload: { |  | ||||||
|         enabled: boolean; // FIXME: add other action types
 |  | ||||||
|     }; |  | ||||||
|     createdAt: Date; |  | ||||||
|     createdBy: { |  | ||||||
|         id: number; |  | ||||||
|         username?: any; |  | ||||||
|         imageUrl?: any; |  | ||||||
|     }; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| export interface IChangeRequestResponse { |  | ||||||
|     id: number; |  | ||||||
|     environment: string; |  | ||||||
|     state: string; |  | ||||||
|     project: string; |  | ||||||
|     createdBy: { |  | ||||||
|         id: number; |  | ||||||
|         username?: any; |  | ||||||
|         imageUrl?: any; |  | ||||||
|     }; |  | ||||||
|     createdAt: Date; |  | ||||||
|     features: Array<{ |  | ||||||
|         name: string; |  | ||||||
|         changes: IChange[]; |  | ||||||
|     }>; |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| const fetcher = (path: string) => { | const fetcher = (path: string) => { | ||||||
|     return fetch(path) |     return fetch(path) | ||||||
| @ -41,7 +14,7 @@ const fetcher = (path: string) => { | |||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| export const useChangeRequestDraft = (project: string) => { | export const useChangeRequestDraft = (project: string) => { | ||||||
|     const { data, error, mutate } = useSWR<IChangeRequestResponse[]>( |     const { data, error, mutate } = useSWR<IChangeRequest[]>( | ||||||
|         formatApiPath(`api/admin/projects/${project}/change-requests/draft`), |         formatApiPath(`api/admin/projects/${project}/change-requests/draft`), | ||||||
|         fetcher |         fetcher | ||||||
|     ); |     ); | ||||||
|  | |||||||
| @ -28,6 +28,10 @@ export default createTheme({ | |||||||
|             fontSize: '1.5rem', |             fontSize: '1.5rem', | ||||||
|             lineHeight: 1.875, |             lineHeight: 1.875, | ||||||
|         }, |         }, | ||||||
|  |         h2: { | ||||||
|  |             fontSize: `${20 / 16}rem`, | ||||||
|  |             fontWeight: '700', | ||||||
|  |         }, | ||||||
|         h3: { |         h3: { | ||||||
|             fontSize: '1rem', |             fontSize: '1rem', | ||||||
|             fontWeight: '700', |             fontWeight: '700', | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user