1
0
mirror of https://github.com/Unleash/unleash.git synced 2024-12-22 19:07:54 +01:00

Merge branch 'master' into fix/environment-guidance

This commit is contained in:
Youssef Khedher 2021-12-09 00:37:53 +01:00 committed by GitHub
commit e2a2944450
10 changed files with 196 additions and 52 deletions

View File

@ -1,4 +1,3 @@
import React from 'react';
import classnames from 'classnames';
import { Paper } from '@material-ui/core';
import PropTypes from 'prop-types';
@ -8,12 +7,14 @@ import ReportProblemOutlinedIcon from '@material-ui/icons/ReportProblemOutlined'
import ConditionallyRender from '../../common/ConditionallyRender/ConditionallyRender';
import styles from './ReportCard.module.scss';
import ReactTimeAgo from 'react-timeago';
const ReportCard = ({
health,
activeCount,
staleCount,
potentiallyStaleCount,
lastUpdate,
}) => {
const healthLessThan50 = health < 50;
const healthLessThan75 = health < 75;
@ -52,11 +53,22 @@ const ReportCard = ({
<div className={styles.reportCardHealthInnerContainer}>
<ConditionallyRender
condition={health > -1}
show={<p className={healthClasses}>{health}%</p>}
show={
<div>
<p className={healthClasses}>{health}%</p>
<p className={styles.lastUpdate}>
Last updated:{' '}
<ReactTimeAgo
date={lastUpdate}
live={false}
/>
</p>
</div>
}
/>
</div>
</div>
<div className={styles.reportCardListContainer}>
<div className={styles.reportCardToggle}>
<h2 className={styles.header}>Toggle report</h2>
<ul className={styles.reportCardList}>
<li>
@ -65,28 +77,49 @@ const ReportCard = ({
show={renderActiveToggles}
/>
</li>
<ConditionallyRender
condition={activeCount}
show={
<p className={styles.reportCardActionText}>
Also includes potentially stale toggles.
</p>
}
/>
<li>
<ConditionallyRender
condition={staleCount}
show={renderStaleToggles}
/>
</li>
<li>
<ConditionallyRender
condition={potentiallyStaleCount}
show={renderPotentiallyStaleToggles}
/>
</li>
</ul>
</div>
<div className={styles.reportCardAction}>
<h2 className={styles.header}>Potential actions</h2>
<div className={styles.reportCardActionContainer}>
<p className={styles.reportCardActionText}>
Review your feature toggles and delete unused
toggles.
</p>
<ul className={styles.reportCardList}>
<li>
<ConditionallyRender
condition={potentiallyStaleCount}
show={renderPotentiallyStaleToggles}
/>
</li>
</ul>
<ConditionallyRender
condition={potentiallyStaleCount}
show={
<p className={styles.reportCardActionText}>
Review your feature toggles and delete
unused toggles.
</p>
}
elseShow={
<p className={styles.reportCardNoActionText}>
No action is required
</p>
}
/>
</div>
</div>
</div>

View File

@ -2,6 +2,8 @@
width: 100%;
padding: var(--card-padding);
margin: var(--card-margin-y) 0;
border-radius: 10px;
box-shadow: none;
}
.header {
@ -14,9 +16,19 @@
display: flex;
justify-content: space-between;
}
.reportCardHealth {
padding: 10px;
}
.reportCardAction {
padding: 10px;
}
.reportCardToggle {
padding: 10px;
}
.reportCardHealthInnerContainer {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
align-items: center;
@ -70,6 +82,12 @@
.reportCardActionText {
max-width: 300px;
font-size: var(--p-size);
margin-left: 35px;
}
.reportCardNoActionText {
max-width: 300px;
font-size: var(--p-size);
margin-left: 15px;
}
.reportCardBtn {
@ -83,3 +101,16 @@
.healthWarning {
color: var(--warning);
}
.lastUpdate {
color: #585858;
}
@media (max-width: 600px) {
.reportCardContainer {
flex-wrap: wrap;
}
.reportCardToggle {
margin: 10px 5px;
flex-basis: 100%;
}
}

View File

@ -1,6 +1,8 @@
.reportToggleList {
width: 100%;
margin: var(--card-margin-y) 0;
border-radius: 10px;
box-shadow: none;
}
.bulkAction {
@ -65,7 +67,31 @@
cursor: pointer;
}
.tableRow:hover {
background-color: #eeeeee;
}
.checkbox {
margin: 0;
padding: 0;
}
@media only screen and (max-width: 800px) {
.hideColumn {
display: none;
}
th {
min-width: 120px;
}
}
@media only screen and (max-width: 550px) {
.hideColumnStatus {
display: none;
}
}
@media only screen and (max-width: 425px) {
.hideColumnLastSeen {
display: none;
}
}

View File

@ -5,11 +5,23 @@ import PropTypes from 'prop-types';
import ConditionallyRender from '../../../common/ConditionallyRender/ConditionallyRender';
import { NAME, LAST_SEEN, CREATED, EXPIRED, STATUS, REPORT } from '../../constants';
import {
NAME,
LAST_SEEN,
CREATED,
EXPIRED,
STATUS,
REPORT,
} from '../../constants';
import styles from '../ReportToggleList.module.scss';
const ReportToggleListHeader = ({ handleCheckAll, checkAll, setSortData, bulkActionsOn }) => {
const ReportToggleListHeader = ({
handleCheckAll,
checkAll,
setSortData,
bulkActionsOn,
}) => {
const handleSort = type => {
setSortData(prev => ({
sortKey: type,
@ -34,27 +46,56 @@ const ReportToggleListHeader = ({ handleCheckAll, checkAll, setSortData, bulkAct
}
/>
<th role="button" tabIndex={0} style={{ width: '150px' }} onClick={() => handleSort(NAME)}>
<th
role="button"
tabIndex={0}
style={{ width: '150px' }}
onClick={() => handleSort(NAME)}
>
Name
<UnfoldMoreOutlinedIcon className={styles.sortIcon} />
</th>
<th role="button" tabIndex={0} onClick={() => handleSort(LAST_SEEN)}>
<th
role="button"
className={styles.hideColumnLastSeen}
tabIndex={0}
onClick={() => handleSort(LAST_SEEN)}
>
Last seen
<UnfoldMoreOutlinedIcon className={styles.sortIcon} />
</th>
<th role="button" tabIndex={0} onClick={() => handleSort(CREATED)}>
<th
role="button"
tabIndex={0}
className={styles.hideColumn}
onClick={() => handleSort(CREATED)}
>
Created
<UnfoldMoreOutlinedIcon className={styles.sortIcon} />
</th>
<th role="button" tabIndex={0} onClick={() => handleSort(EXPIRED)}>
<th
role="button"
tabIndex={0}
className={styles.hideColumn}
onClick={() => handleSort(EXPIRED)}
>
Expired
<UnfoldMoreOutlinedIcon className={styles.sortIcon} />
</th>
<th role="button" tabIndex={0} onClick={() => handleSort(STATUS)}>
<th
role="button"
tabIndex={0}
className={styles.hideColumnStatus}
onClick={() => handleSort(STATUS)}
>
Status
<UnfoldMoreOutlinedIcon className={styles.sortIcon} />
</th>
<th role="button" tabIndex={0} onClick={() => handleSort(REPORT)}>
<th
role="button"
tabIndex={0}
onClick={() => handleSort(REPORT)}
>
Report
<UnfoldMoreOutlinedIcon className={styles.sortIcon} />
</th>

View File

@ -7,6 +7,7 @@ import { Checkbox } from '@material-ui/core';
import CheckIcon from '@material-ui/icons/Check';
import ReportProblemOutlinedIcon from '@material-ui/icons/ReportProblemOutlined';
import ConditionallyRender from '../../../common/ConditionallyRender/ConditionallyRender';
import FeatureStatus from '../../../feature/FeatureView2/FeatureStatus/FeatureStatus';
import {
pluralize,
@ -75,20 +76,13 @@ const ReportToggleListItem = ({
return pluralize(result, 'day');
}
return 'N/A';
};
const formatLastSeenAt = () => {
if (!lastSeenAt) return 'Never';
const [date, now] = getDates(lastSeenAt);
const diff = getDiffInDays(date, now);
if (diff === 0) return '1 day';
if (diff) {
return pluralize(diff, 'day');
}
return '1 day';
return (
<FeatureStatus lastSeenAt={lastSeenAt} tooltipPlacement="bottom" />
);
};
const renderStatus = (icon, text) => (
@ -126,7 +120,7 @@ const ReportToggleListItem = ({
history.push(getTogglePath(project, name));
};
const statusClasses = classnames(styles.active, {
const statusClasses = classnames(styles.active, styles.hideColumnStatus, {
[styles.stale]: stale,
});
@ -151,9 +145,11 @@ const ReportToggleListItem = ({
}
/>
<td>{name}</td>
<td>{formatLastSeenAt()}</td>
<td>{formatCreatedAt()}</td>
<td className={styles.expired}>{formatExpiredAt()}</td>
<td className={styles.hideColumnLastSeen}>{formatLastSeenAt()}</td>
<td className={styles.hideColumn}>{formatCreatedAt()}</td>
<td className={`${styles.expired} ${styles.hideColumn}`}>
{formatExpiredAt()}
</td>
<td className={statusClasses}>{stale ? 'Stale' : 'Active'}</td>
<td>{formatReportStatus()}</td>
</tr>

View File

@ -58,7 +58,10 @@ const FeatureToggleListItem = ({
className={classnames(styles.listItem, rest.className)}
>
<span className={styles.listItemMetric}>
<FeatureStatus lastSeenAt={lastSeenAt} />
<FeatureStatus
lastSeenAt={lastSeenAt}
tooltipPlacement="left"
/>
</span>
<span
className={classnames(

View File

@ -95,7 +95,10 @@ const FeatureToggleListNewItem = ({
align="left"
onClick={onClick}
>
<FeatureStatus lastSeenAt={lastSeenAt} />
<FeatureStatus
lastSeenAt={lastSeenAt}
tooltipPlacement="left"
/>
</TableCell>
<TableCell
className={classNames(

View File

@ -47,16 +47,20 @@ function getColor(unit?: string): string {
interface FeatureStatusProps {
lastSeenAt?: Date;
tooltipPlacement?: string;
}
const FeatureStatus = ({ lastSeenAt }: FeatureStatusProps) => {
const FeatureStatus = ({
lastSeenAt,
tooltipPlacement,
}: FeatureStatusProps) => {
const styles = useStyles();
const Wrapper = (
props: React.PropsWithChildren<{ color: string; toolTip: string }>
) => {
return (
<Tooltip title={props.toolTip} arrow placement="left">
<Tooltip title={props.toolTip} arrow placement={tooltipPlacement}>
<div
className={styles.container}
style={{ background: props.color, fontSize: '0.8rem' }}
@ -83,7 +87,9 @@ const FeatureStatus = ({ lastSeenAt }: FeatureStatusProps) => {
) => {
return (
<Wrapper
toolTip={`Last usage reported ${value} ${unit}${value !== 1 ? 's' : ''} ${suffix}`}
toolTip={`Last usage reported ${value} ${unit}${
value !== 1 ? 's' : ''
} ${suffix}`}
color={getColor(unit)}
>
{value}
@ -94,7 +100,10 @@ const FeatureStatus = ({ lastSeenAt }: FeatureStatusProps) => {
/>
}
elseShow={
<Wrapper toolTip="No usage reported from connected applications" color={getColor()}>
<Wrapper
toolTip="No usage reported from connected applications"
color={getColor()}
>
<span style={{ fontSize: '1.4rem' }}></span>
</Wrapper>
}

View File

@ -1,8 +1,8 @@
import useHealthReport from '../../../../hooks/api/getters/useHealthReport/useHealthReport';
import ApiError from '../../../common/ApiError/ApiError';
import ConditionallyRender from '../../../common/ConditionallyRender';
import ReportCardContainer from '../../../Reporting/ReportCard/ReportCardContainer'
import ReportToggleList from '../../../Reporting/ReportToggleList/ReportToggleList'
import ReportCardContainer from '../../../Reporting/ReportCard/ReportCardContainer';
import ReportToggleList from '../../../Reporting/ReportToggleList/ReportToggleList';
interface ProjectHealthProps {
projectId: string;
@ -25,18 +25,19 @@ const ProjectHealth = ({ projectId }: ProjectHealthProps) => {
}
/>
<ReportCardContainer
health={project?.health}
staleCount={project?.staleCount}
activeCount={project?.activeCount}
potentiallyStaleCount={project?.potentiallyStaleCount}
selectedProject={project.name}
health={project?.health}
staleCount={project?.staleCount}
activeCount={project?.activeCount}
potentiallyStaleCount={project?.potentiallyStaleCount}
selectedProject={project.name}
lastUpdate={project.updatedAt}
/>
<ReportToggleList
features={project.features}
selectedProject={projectId}
/>
</div>
)
}
);
};
export default ProjectHealth;
export default ProjectHealth;

View File

@ -24,4 +24,5 @@ export interface IProjectHealthReport extends IProject {
staleCount: number;
potentiallyStaleCount: number;
activeCount: number;
updatedAt: Date;
}