1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-02-04 00:18:01 +01:00

Merge branch 'master' into fix/search-field

This commit is contained in:
Fredrik Strand Oseberg 2021-11-24 14:43:01 +01:00 committed by GitHub
commit dd2b661928
20 changed files with 324 additions and 87 deletions

View File

@ -0,0 +1,13 @@
import { makeStyles } from '@material-ui/core/styles';
export const useStyles = makeStyles(theme => ({
indicator: {
padding: '0.2rem',
borderRadius: '5px',
marginLeft: '0.5rem',
backgroundColor: '#000',
color: '#fff',
fontSize: '0.9rem',
fontWeight: 'bold',
},
}));

View File

@ -0,0 +1,16 @@
import { useStyles } from './DisabledIndicator.styles';
import classnames from 'classnames';
interface IDisabledIndicator {
className?: string;
}
const DisabledIndicator = ({ className }: IDisabledIndicator) => {
const styles = useStyles();
return (
<span className={classnames(styles.indicator, className)}>
disabled
</span>
);
};
export default DisabledIndicator;

View File

@ -0,0 +1,26 @@
import { makeStyles } from '@material-ui/core/styles';
export const useStyles = makeStyles(theme => ({
container: {
display: 'flex',
alignItems: 'center',
position: 'relative',
width: '50px',
height: '100%',
},
vertical: {
borderRadius: '1px',
height: '50px',
width: '50px',
},
circle: {
width: '15px',
height: '15px',
},
pos: {
position: 'absolute',
right: 0,
left: 0,
margin: '0 auto',
},
}));

View File

@ -0,0 +1,24 @@
import FiberManualRecordIcon from '@material-ui/icons/FiberManualRecord';
import Remove from '@material-ui/icons/Remove';
import { useStyles } from './RolloutIcon.styles';
import classnames from 'classnames';
interface IRolloutIconProps {
className?: string;
}
const RolloutIcon = ({ className }: IRolloutIconProps) => {
const styles = useStyles();
return (
<div className={styles.container}>
<Remove
className={classnames(styles.vertical, styles.pos, className)}
/>
<FiberManualRecordIcon
className={classnames(styles.circle, styles.pos, className)}
/>
</div>
);
};
export default RolloutIcon;

View File

@ -23,6 +23,7 @@ import {
} from '../../../providers/AccessProvider/permissions'; } from '../../../providers/AccessProvider/permissions';
import { useDrag, useDrop, DropTargetMonitor } from 'react-dnd'; import { useDrag, useDrop, DropTargetMonitor } from 'react-dnd';
import { XYCoord } from 'dnd-core'; import { XYCoord } from 'dnd-core';
import DisabledIndicator from '../../../common/DisabledIndicator/DisabledIndicator';
interface IEnvironmentListItemProps { interface IEnvironmentListItemProps {
env: IEnvironment; env: IEnvironment;
@ -118,7 +119,7 @@ const EnvironmentListItem = ({
if (updatePermission) { if (updatePermission) {
drag(drop(ref)); drag(drop(ref));
} }
return ( return (
<ListItem <ListItem
style={{ position: 'relative', opacity }} style={{ position: 'relative', opacity }}
@ -134,20 +135,7 @@ const EnvironmentListItem = ({
<strong>{env.name}</strong> <strong>{env.name}</strong>
<ConditionallyRender <ConditionallyRender
condition={!env.enabled} condition={!env.enabled}
show={ show={<DisabledIndicator />}
<span
style={{
padding: '0.2rem',
borderRadius: '5px',
marginLeft: '0.5rem',
backgroundColor: '#000',
color: '#fff',
fontWeight: 'bold',
}}
>
disabled
</span>
}
/> />
</> </>
} }

View File

@ -21,7 +21,7 @@ export const useStyles = makeStyles(theme => ({
cursor: 'pointer', cursor: 'pointer',
}, },
tableCellStatus: { tableCellStatus: {
width: '50px', width: '60px',
}, },
tableCellName: { tableCellName: {
paddingLeft: '10px', paddingLeft: '10px',
@ -44,9 +44,9 @@ export const useStyles = makeStyles(theme => ({
display: 'none', display: 'none',
}, },
}, },
link:{ link: {
textDecoration: 'none', textDecoration: 'none',
color: 'inherit' color: 'inherit',
}, },
envName: { envName: {
display: 'inline-block', display: 'inline-block',
@ -54,5 +54,5 @@ export const useStyles = makeStyles(theme => ({
textOverflow: 'ellipsis', textOverflow: 'ellipsis',
overflow: 'hidden', overflow: 'hidden',
whiteSpace: 'nowrap', whiteSpace: 'nowrap',
} },
})); }));

View File

@ -1,4 +1,4 @@
import { useState, useEffect} from 'react'; import { useState, useEffect } from 'react';
import { import {
Table, Table,
TableBody, TableBody,
@ -25,12 +25,12 @@ interface IFeatureToggleListNewProps {
//@ts-ignore //@ts-ignore
const sortList = (list, sortOpt) => { const sortList = (list, sortOpt) => {
if(!list) { if (!list) {
return list; return list;
} }
if(!sortOpt.field) { if (!sortOpt.field) {
return list; return list;
} }
if (sortOpt.type === 'string') { if (sortOpt.type === 'string') {
//@ts-ignore //@ts-ignore
return list.sort((a, b) => { return list.sort((a, b) => {
@ -45,7 +45,7 @@ const sortList = (list, sortOpt) => {
return direction === 0 ? 1 : -1; return direction === 0 ? 1 : -1;
} }
return 0; return 0;
}) });
} }
if (sortOpt.type === 'date') { if (sortOpt.type === 'date') {
//@ts-ignore //@ts-ignore
@ -60,10 +60,10 @@ const sortList = (list, sortOpt) => {
return sortOpt.direction === 0 ? -1 : 1; return sortOpt.direction === 0 ? -1 : 1;
} }
return 0; return 0;
}) });
} }
return list; return list;
} };
const FeatureToggleListNew = ({ const FeatureToggleListNew = ({
features, features,
@ -76,32 +76,33 @@ const FeatureToggleListNew = ({
type: 'string', type: 'string',
direction: 0, direction: 0,
}); });
const [sortedFeatures, setSortedFeatures] = useState(sortList([...features], sortOpt)); const [sortedFeatures, setSortedFeatures] = useState(
sortList([...features], sortOpt)
);
const { page, pages, nextPage, prevPage, setPageIndex, pageIndex } = const { page, pages, nextPage, prevPage, setPageIndex, pageIndex } =
usePagination(sortedFeatures, 50); usePagination(sortedFeatures, 50);
useEffect(() => { useEffect(() => {
setSortedFeatures(sortList([...features], sortOpt)) setSortedFeatures(sortList([...features], sortOpt));
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [features]) }, [features]);
const updateSort = (field: string) => { const updateSort = (field: string) => {
let newSortOpt; let newSortOpt;
if(field === sortOpt.field) { if (field === sortOpt.field) {
newSortOpt = {...sortOpt, direction: (sortOpt.direction + 1) % 2}; newSortOpt = { ...sortOpt, direction: (sortOpt.direction + 1) % 2 };
} } else if (['createdAt', 'lastSeenAt'].includes(field)) {
else if(['createdAt', 'lastSeenAt'].includes(field)) {
newSortOpt = { newSortOpt = {
field, field,
type: 'date', type: 'date',
direction: 0 direction: 0,
}; };
} else { } else {
newSortOpt = { newSortOpt = {
field, field,
type: 'string', type: 'string',
direction: 0 direction: 0,
}; };
} }
setSortOpt(newSortOpt); setSortOpt(newSortOpt);
@ -164,44 +165,64 @@ const FeatureToggleListNew = ({
styles.tableCell, styles.tableCell,
styles.tableCellStatus, styles.tableCellStatus,
styles.tableCellHeader, styles.tableCellHeader,
styles.tableCellHeaderSortable, styles.tableCellHeaderSortable
)} )}
align="left" align="left"
> >
<span data-loading onClick={() => updateSort('lastSeenAt')}>Status</span> <span
data-loading
onClick={() => updateSort('lastSeenAt')}
>
Last use
</span>
</TableCell> </TableCell>
<TableCell <TableCell
className={classnames( className={classnames(
styles.tableCell, styles.tableCell,
styles.tableCellType, styles.tableCellType,
styles.tableCellHeader, styles.tableCellHeader,
styles.tableCellHeaderSortable, styles.tableCellHeaderSortable
)} )}
align="center" align="center"
> >
<span data-loading onClick={() => updateSort('type')}>Type</span> <span
data-loading
onClick={() => updateSort('type')}
>
Type
</span>
</TableCell> </TableCell>
<TableCell <TableCell
className={classnames( className={classnames(
styles.tableCell, styles.tableCell,
styles.tableCellName, styles.tableCellName,
styles.tableCellHeader, styles.tableCellHeader,
styles.tableCellHeaderSortable, styles.tableCellHeaderSortable
)} )}
align="left" align="left"
> >
<span data-loading onClick={() => updateSort('name')}>Name</span> <span
data-loading
onClick={() => updateSort('name')}
>
Name
</span>
</TableCell> </TableCell>
<TableCell <TableCell
className={classnames( className={classnames(
styles.tableCell, styles.tableCell,
styles.tableCellCreated, styles.tableCellCreated,
styles.tableCellHeader, styles.tableCellHeader,
styles.tableCellHeaderSortable, styles.tableCellHeaderSortable
)} )}
align="left" align="left"
> >
<span data-loading onClick={() => updateSort('createdAt')}>Created</span> <span
data-loading
onClick={() => updateSort('createdAt')}
>
Created
</span>
</TableCell> </TableCell>
{getEnvironments().map((env: any) => { {getEnvironments().map((env: any) => {
return ( return (
@ -211,12 +232,15 @@ const FeatureToggleListNew = ({
styles.tableCell, styles.tableCell,
styles.tableCellEnv, styles.tableCellEnv,
styles.tableCellHeader, styles.tableCellHeader,
styles.tableCellHeaderSortable, styles.tableCellHeaderSortable
)} )}
align="center" align="center"
> >
<span data-loading className={styles.envName} > <span
{env.name} data-loading
className={styles.envName}
>
{env.name}
</span> </span>
</TableCell> </TableCell>
); );

View File

@ -23,6 +23,11 @@ export const useStyles = makeStyles(theme => ({
display: 'flex', display: 'flex',
alignItems: 'center', alignItems: 'center',
}, },
disabledIndicatorPos: {
position: 'absolute',
top: '15px',
left: '20px',
},
iconContainer: { iconContainer: {
backgroundColor: theme.palette.primary.light, backgroundColor: theme.palette.primary.light,
borderRadius: '50%', borderRadius: '50%',
@ -118,6 +123,9 @@ export const useStyles = makeStyles(theme => ({
}, },
}, },
[theme.breakpoints.down(560)]: { [theme.breakpoints.down(560)]: {
disabledIndicatorPos: {
top: '-8px',
},
headerTitle: { headerTitle: {
flexDirection: 'column', flexDirection: 'column',
}, },

View File

@ -10,6 +10,8 @@ import useFeatureMetrics from '../../../../../../hooks/api/getters/useFeatureMet
import { IFeatureEnvironment } from '../../../../../../interfaces/featureToggle'; import { IFeatureEnvironment } from '../../../../../../interfaces/featureToggle';
import { IFeatureViewParams } from '../../../../../../interfaces/params'; import { IFeatureViewParams } from '../../../../../../interfaces/params';
import { getFeatureMetrics } from '../../../../../../utils/get-feature-metrics'; import { getFeatureMetrics } from '../../../../../../utils/get-feature-metrics';
import ConditionallyRender from '../../../../../common/ConditionallyRender';
import DisabledIndicator from '../../../../../common/DisabledIndicator/DisabledIndicator';
import EnvironmentIcon from '../../../../../common/EnvironmentIcon/EnvironmentIcon'; import EnvironmentIcon from '../../../../../common/EnvironmentIcon/EnvironmentIcon';
import StringTruncator from '../../../../../common/StringTruncator/StringTruncator'; import StringTruncator from '../../../../../common/StringTruncator/StringTruncator';
@ -64,6 +66,14 @@ const FeatureOverviewEnvironment = ({
className={styles.truncator} className={styles.truncator}
maxWidth="120" maxWidth="120"
/> />
<ConditionallyRender
condition={!env.enabled}
show={
<DisabledIndicator
className={styles.disabledIndicatorPos}
/>
}
/>
</div> </div>
<FeatureOverviewEnvironmentMetrics <FeatureOverviewEnvironmentMetrics

View File

@ -15,7 +15,6 @@ export const useStyles = makeStyles(theme => ({
}, },
icon: { icon: {
fill: theme.palette.grey[600], fill: theme.palette.grey[600],
marginRight: '0.5rem',
}, },
editStrategy: { editStrategy: {
marginLeft: 'auto', marginLeft: 'auto',

View File

@ -40,9 +40,8 @@ export const useStyles = makeStyles(theme => ({
marginLeft: 'auto', marginLeft: 'auto',
}, },
icon: { icon: {
marginRight: '0.5rem',
fill: theme.palette.primary.main, fill: theme.palette.primary.main,
minWidth: '35px', minWidth: '50px',
}, },
rollout: { rollout: {
fontSize: theme.fontSizes.smallBody, fontSize: theme.fontSizes.smallBody,

View File

@ -65,6 +65,7 @@ const FeatureStrategyAccordion: React.FC<IFeatureStrategyAccordionProps> = ({
> >
<div className={styles.accordionSummary}> <div className={styles.accordionSummary}>
<Icon className={styles.icon} /> <Icon className={styles.icon} />
<p className={styles.accordionHeader}>{strategyName}</p> <p className={styles.accordionHeader}>{strategyName}</p>
<ConditionallyRender <ConditionallyRender

View File

@ -14,7 +14,11 @@ export const useStyles = makeStyles(theme => ({
borderRadius: '10px', borderRadius: '10px',
marginBottom: '1rem', marginBottom: '1rem',
}, },
innerContainer: { padding: '2rem' }, innerContainer: {
padding: '1rem 2rem',
display: 'flex',
alignItems: 'center',
},
separator: { separator: {
width: '100%', width: '100%',
backgroundColor: theme.palette.grey[200], backgroundColor: theme.palette.grey[200],

View File

@ -5,7 +5,7 @@ import useLoading from '../../../hooks/useLoading';
import ApiError from '../../common/ApiError/ApiError'; import ApiError from '../../common/ApiError/ApiError';
import ConditionallyRender from '../../common/ConditionallyRender'; import ConditionallyRender from '../../common/ConditionallyRender';
import { useStyles } from './Project.styles'; import { useStyles } from './Project.styles';
import { IconButton, Tab, Tabs } from '@material-ui/core'; import { Tab, Tabs } from '@material-ui/core';
import { Edit } from '@material-ui/icons'; import { Edit } from '@material-ui/icons';
import useToast from '../../../hooks/useToast'; import useToast from '../../../hooks/useToast';
import useQueryParams from '../../../hooks/useQueryParams'; import useQueryParams from '../../../hooks/useQueryParams';
@ -17,9 +17,11 @@ import EditProject from '../edit-project-container';
import ProjectEnvironment from '../ProjectEnvironment/ProjectEnvironment'; import ProjectEnvironment from '../ProjectEnvironment/ProjectEnvironment';
import ProjectOverview from './ProjectOverview'; import ProjectOverview from './ProjectOverview';
import ProjectHealth from './ProjectHealth/ProjectHealth'; import ProjectHealth from './ProjectHealth/ProjectHealth';
import { UPDATE_PROJECT } from '../../../store/project/actions';
import PermissionIconButton from '../../common/PermissionIconButton/PermissionIconButton';
const Project = () => { const Project = () => {
const { id, activeTab } = useParams<{ id: string, activeTab: string }>(); const { id, activeTab } = useParams<{ id: string; activeTab: string }>();
const params = useQueryParams(); const params = useQueryParams();
const { project, error, loading, refetch } = useProject(id); const { project, error, loading, refetch } = useProject(id);
const ref = useLoading(loading); const ref = useLoading(loading);
@ -52,18 +54,24 @@ const Project = () => {
}, },
{ {
title: 'Environments', title: 'Environments',
component: <ProjectEnvironment projectId={id} />, component: <ProjectEnvironment projectId={id} />,
path: `${basePath}/environments`, path: `${basePath}/environments`,
name: 'environments', name: 'environments',
}, },
{ {
title: 'Settings', title: 'Settings',
// @ts-ignore (fix later) // @ts-ignore (fix later)
component: <EditProject projectId={id} history={history} title="Edit project" />, component: (
<EditProject
projectId={id}
history={history}
title="Edit project"
/>
),
path: `${basePath}/settings`, path: `${basePath}/settings`,
name: 'settings', name: 'settings',
}, },
] ];
useEffect(() => { useEffect(() => {
const created = params.get('created'); const created = params.get('created');
@ -85,32 +93,29 @@ const Project = () => {
useEffect(() => { useEffect(() => {
const tabIdx = tabData.findIndex(tab => tab.name === activeTab); const tabIdx = tabData.findIndex(tab => tab.name === activeTab);
if(tabIdx > 0) { if (tabIdx > 0) {
setActiveTab(tabIdx); setActiveTab(tabIdx);
} else { } else {
setActiveTab(0); setActiveTab(0);
} }
/* eslint-disable-next-line */ /* eslint-disable-next-line */
}, []); }, []);
const goToTabWithName = (name: string) => { const goToTabWithName = (name: string) => {
const index = tabData.findIndex(t => t.name === name); const index = tabData.findIndex(t => t.name === name);
if(index >= 0) { if (index >= 0) {
const tab = tabData[index]; const tab = tabData[index];
history.push(tab.path); history.push(tab.path);
setActiveTab(index); setActiveTab(index);
} }
} };
const renderTabs = () => { const renderTabs = () => {
return tabData.map((tab, index) => { return tabData.map((tab, index) => {
return ( return (
<Tab <Tab
data-loading data-loading
key={tab.title} key={tab.title}
label={tab.title} label={tab.title}
{...a11yProps(index)} {...a11yProps(index)}
@ -134,18 +139,26 @@ const Project = () => {
}); });
}; };
return ( return (
<div ref={ref}> <div ref={ref}>
<div className={styles.header}> <div className={styles.header}>
<div className={styles.innerContainer}> <div className={styles.innerContainer}>
<h2 data-loading className={commonStyles.title} style={{margin: 0}}> <h2
data-loading
className={commonStyles.title}
style={{ margin: 0 }}
>
Project: {project?.name}{' '} Project: {project?.name}{' '}
<IconButton onClick={() => goToTabWithName('settings')}> <PermissionIconButton
permission={UPDATE_PROJECT}
tooltip={'Edit description'}
projectId={project?.id}
onClick={() => goToTabWithName('settings')}
data-loading
>
<Edit /> <Edit />
</IconButton> </PermissionIconButton>
</h2> </h2>
<p data-loading>{project?.description}</p>
</div> </div>
<ConditionallyRender <ConditionallyRender
condition={error} condition={error}

View File

@ -14,6 +14,7 @@ export const useStyles = makeStyles(theme => ({
width: 'inherit', width: 'inherit',
}, },
}, },
bodyClass: { padding: '0.5rem 1rem' }, bodyClass: { padding: '0.5rem 1rem' },
header: { header: {
padding: '1rem', padding: '1rem',

View File

@ -39,7 +39,7 @@ const ProjectFeatureToggles = ({
headerContent={ headerContent={
<HeaderTitle <HeaderTitle
className={styles.title} className={styles.title}
title="Feature toggles" title={`Feature toggles (${features.length})`}
actions={ actions={
<> <>
<ConditionallyRender <ConditionallyRender
@ -55,11 +55,14 @@ const ProjectFeatureToggles = ({
</IconButton> </IconButton>
} }
/> />
<ResponsiveButton <ResponsiveButton
onClick={() => onClick={() =>
history.push( history.push(
getCreateTogglePath(id, uiConfig.flags.E) getCreateTogglePath(
id,
uiConfig.flags.E
)
) )
} }
maxWidth="700px" maxWidth="700px"
@ -93,7 +96,10 @@ const ProjectFeatureToggles = ({
condition={hasAccess(CREATE_FEATURE, id)} condition={hasAccess(CREATE_FEATURE, id)}
show={ show={
<Link <Link
to={getCreateTogglePath(id, uiConfig.flags.E)} to={getCreateTogglePath(
id,
uiConfig.flags.E
)}
className={styles.link} className={styles.link}
data-loading data-loading
> >

View File

@ -14,6 +14,18 @@ export const useStyles = makeStyles(theme => ({
marginBottom: '1rem', marginBottom: '1rem',
}, },
}, },
description: {
textAlign: 'left',
marginBottom: '0.5rem',
},
descriptionContainer: {
display: 'flex',
justifyContent: 'space-between',
},
idContainer: {
display: 'flex',
width: '100%',
},
percentageContainer: { percentageContainer: {
display: 'flex', display: 'flex',
justifyContent: 'center', justifyContent: 'center',
@ -66,6 +78,9 @@ export const useStyles = makeStyles(theme => ({
color: '#635dc5', color: '#635dc5',
marginLeft: '0.5rem', marginLeft: '0.5rem',
}, },
permissionButtonShortDesc: {
transform: `translateY(-10px)`,
},
infoLink: { infoLink: {
textDecoration: 'none', textDecoration: 'none',
color: '#635dc5', color: '#635dc5',
@ -74,6 +89,15 @@ export const useStyles = makeStyles(theme => ({
bottom: '5px', bottom: '5px',
}, },
}, },
accordion: {
boxShadow: 'none',
textAlign: 'left',
},
accordionBody: { padding: '0' },
accordionActions: {
padding: '0',
justifyContent: 'flex-start',
},
linkText: { linkText: {
[theme.breakpoints.down('sm')]: { [theme.breakpoints.down('sm')]: {
display: 'none', display: 'none',

View File

@ -2,23 +2,34 @@ import { useStyles } from './ProjectInfo.styles';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import ArrowForwardIcon from '@material-ui/icons/ArrowForward'; import ArrowForwardIcon from '@material-ui/icons/ArrowForward';
import classnames from 'classnames'; import classnames from 'classnames';
import { Edit, ExpandMore } from '@material-ui/icons';
import { useCommonStyles } from '../../../../common.styles'; import { useCommonStyles } from '../../../../common.styles';
import useUiConfig from '../../../../hooks/api/getters/useUiConfig/useUiConfig'; import useUiConfig from '../../../../hooks/api/getters/useUiConfig/useUiConfig';
import PercentageCircle from '../../../common/PercentageCircle/PercentageCircle'; import PercentageCircle from '../../../common/PercentageCircle/PercentageCircle';
import PermissionIconButton from '../../../common/PermissionIconButton/PermissionIconButton';
import { UPDATE_PROJECT } from '../../../../store/project/actions';
import ConditionallyRender from '../../../common/ConditionallyRender';
import {
Accordion,
AccordionActions,
AccordionDetails,
AccordionSummary,
} from '@material-ui/core';
interface IProjectInfoProps { interface IProjectInfoProps {
id: string; id: string;
memberCount: number; memberCount: number;
featureCount: number; featureCount: number;
health: number; health: number;
description: string;
} }
const ProjectInfo = ({ const ProjectInfo = ({
id, id,
memberCount, memberCount,
featureCount,
health, health,
description,
}: IProjectInfoProps) => { }: IProjectInfoProps) => {
const commonStyles = useCommonStyles(); const commonStyles = useCommonStyles();
const styles = useStyles(); const styles = useStyles();
@ -30,9 +41,87 @@ const ProjectInfo = ({
link = `/projects/${id}/access`; link = `/projects/${id}/access`;
} }
const LONG_DESCRIPTION = 100;
const permissionButtonClass = classnames({
[styles.permissionButtonShortDesc]:
description.length < LONG_DESCRIPTION,
});
const permissionButton = (
<PermissionIconButton
permission={UPDATE_PROJECT}
tooltip={'Edit description'}
projectId={id}
component={Link}
className={permissionButtonClass}
data-loading
to={`/projects/${id}/settings`}
>
<Edit />
</PermissionIconButton>
);
return ( return (
<aside> <aside>
<div className={styles.projectInfo}> <div className={styles.projectInfo}>
<div className={styles.infoSection}>
<div className={styles.descriptionContainer}>
<ConditionallyRender
condition={Boolean(description)}
show={
<ConditionallyRender
condition={
description.length < LONG_DESCRIPTION
}
show={
<p
data-loading
className={styles.description}
>
{description}
</p>
}
elseShow={
<Accordion className={styles.accordion}>
<AccordionSummary
expandIcon={<ExpandMore />}
className={styles.accordionBody}
>
Description
</AccordionSummary>
<AccordionDetails
className={styles.accordionBody}
>
{description}
</AccordionDetails>
<AccordionActions
className={
styles.accordionActions
}
>
Edit description{' '}
{permissionButton}
</AccordionActions>
</Accordion>
}
/>
}
elseShow={
<p data-loading className={styles.description}>
No description
</p>
}
/>
<ConditionallyRender
condition={description.length < LONG_DESCRIPTION}
show={permissionButton}
/>
</div>
<div className={styles.idContainer}>
<p data-loading>projectId: {id}</p>
</div>
</div>
<div className={styles.infoSection}> <div className={styles.infoSection}>
<div data-loading className={styles.percentageContainer}> <div data-loading className={styles.percentageContainer}>
<PercentageCircle percentage={health} /> <PercentageCircle percentage={health} />
@ -62,15 +151,6 @@ const ProjectInfo = ({
</Link> </Link>
</div> </div>
<div className={styles.infoSection}>
<p className={styles.subtitle} data-loading>
Feature toggles
</p>
<p className={styles.emphazisedText} data-loading>
{featureCount}
</p>
</div>
<div <div
className={styles.infoSection} className={styles.infoSection}
style={{ marginBottom: '0' }} style={{ marginBottom: '0' }}

View File

@ -11,7 +11,7 @@ const ProjectOverview = ({ projectId }: ProjectOverviewProps) => {
const { project, loading } = useProject(projectId, { const { project, loading } = useProject(projectId, {
refreshInterval: 10000, refreshInterval: 10000,
}); });
const { members, features, health } = project; const { members, features, health, description } = project;
const styles = useStyles(); const styles = useStyles();
return ( return (
@ -19,6 +19,7 @@ const ProjectOverview = ({ projectId }: ProjectOverviewProps) => {
<div className={styles.containerStyles}> <div className={styles.containerStyles}>
<ProjectInfo <ProjectInfo
id={projectId} id={projectId}
description={description}
memberCount={members} memberCount={members}
health={health} health={health}
featureCount={features?.length} featureCount={features?.length}

View File

@ -2,7 +2,7 @@ import LocationOnIcon from '@material-ui/icons/LocationOn';
import PeopleIcon from '@material-ui/icons/People'; import PeopleIcon from '@material-ui/icons/People';
import LanguageIcon from '@material-ui/icons/Language'; import LanguageIcon from '@material-ui/icons/Language';
import MapIcon from '@material-ui/icons/Map'; import MapIcon from '@material-ui/icons/Map';
import { DonutLarge } from '@material-ui/icons'; import RolloutIcon from '../component/common/RolloutIcon/RolloutIcon';
const nameMapping = { const nameMapping = {
applicationHostname: { applicationHostname: {
@ -61,7 +61,7 @@ export const getFeatureStrategyIcon = strategyName => {
case 'remoteAddress': case 'remoteAddress':
return LanguageIcon; return LanguageIcon;
case 'flexibleRollout': case 'flexibleRollout':
return DonutLarge; return RolloutIcon;
case 'userWithId': case 'userWithId':
return PeopleIcon; return PeopleIcon;
case 'applicationHostname': case 'applicationHostname':