mirror of
https://github.com/Unleash/unleash.git
synced 2025-02-09 00:18:00 +01:00
refactor: port ReportCard to TS/SWR (#674)
* refactor: remove unused reporting code * refactor: port ReportCard to TS/SWR
This commit is contained in:
parent
72acf2309c
commit
234bab6cb4
@ -1,23 +1,19 @@
|
|||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import { Paper } from '@material-ui/core';
|
import { Paper } from '@material-ui/core';
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
import CheckIcon from '@material-ui/icons/Check';
|
import CheckIcon from '@material-ui/icons/Check';
|
||||||
import ReportProblemOutlinedIcon from '@material-ui/icons/ReportProblemOutlined';
|
import ReportProblemOutlinedIcon from '@material-ui/icons/ReportProblemOutlined';
|
||||||
import ConditionallyRender from '../../common/ConditionallyRender/ConditionallyRender';
|
import ConditionallyRender from '../../common/ConditionallyRender/ConditionallyRender';
|
||||||
|
|
||||||
import styles from './ReportCard.module.scss';
|
import styles from './ReportCard.module.scss';
|
||||||
import ReactTimeAgo from 'react-timeago';
|
import ReactTimeAgo from 'react-timeago';
|
||||||
|
import { IProjectHealthReport } from "../../../interfaces/project";
|
||||||
|
|
||||||
const ReportCard = ({
|
interface IReportCardProps {
|
||||||
health,
|
healthReport: IProjectHealthReport
|
||||||
activeCount,
|
}
|
||||||
staleCount,
|
|
||||||
potentiallyStaleCount,
|
export const ReportCard = ({ healthReport }: IReportCardProps) => {
|
||||||
lastUpdate,
|
const healthLessThan50 = healthReport.health < 50;
|
||||||
}) => {
|
const healthLessThan75 = healthReport.health < 75;
|
||||||
const healthLessThan50 = health < 50;
|
|
||||||
const healthLessThan75 = health < 75;
|
|
||||||
|
|
||||||
const healthClasses = classnames(styles.reportCardHealthRating, {
|
const healthClasses = classnames(styles.reportCardHealthRating, {
|
||||||
[styles.healthWarning]: healthLessThan75,
|
[styles.healthWarning]: healthLessThan75,
|
||||||
@ -27,21 +23,21 @@ const ReportCard = ({
|
|||||||
const renderActiveToggles = () => (
|
const renderActiveToggles = () => (
|
||||||
<>
|
<>
|
||||||
<CheckIcon className={styles.check} />
|
<CheckIcon className={styles.check} />
|
||||||
<span>{activeCount} active toggles</span>
|
<span>{healthReport.activeCount} active toggles</span>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
||||||
const renderStaleToggles = () => (
|
const renderStaleToggles = () => (
|
||||||
<>
|
<>
|
||||||
<ReportProblemOutlinedIcon className={styles.danger} />
|
<ReportProblemOutlinedIcon className={styles.danger} />
|
||||||
<span>{staleCount} stale toggles</span>
|
<span>{healthReport.staleCount} stale toggles</span>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
||||||
const renderPotentiallyStaleToggles = () => (
|
const renderPotentiallyStaleToggles = () => (
|
||||||
<>
|
<>
|
||||||
<ReportProblemOutlinedIcon className={styles.danger} />
|
<ReportProblemOutlinedIcon className={styles.danger} />
|
||||||
<span>{potentiallyStaleCount} potentially stale toggles</span>
|
<span>{healthReport.potentiallyStaleCount} potentially stale toggles</span>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -52,14 +48,14 @@ const ReportCard = ({
|
|||||||
<h2 className={styles.header}>Health rating</h2>
|
<h2 className={styles.header}>Health rating</h2>
|
||||||
<div className={styles.reportCardHealthInnerContainer}>
|
<div className={styles.reportCardHealthInnerContainer}>
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={health > -1}
|
condition={healthReport.health > -1}
|
||||||
show={
|
show={
|
||||||
<div>
|
<div>
|
||||||
<p className={healthClasses}>{health}%</p>
|
<p className={healthClasses}>{healthReport.health}%</p>
|
||||||
<p className={styles.lastUpdate}>
|
<p className={styles.lastUpdate}>
|
||||||
Last updated:{' '}
|
Last updated:{' '}
|
||||||
<ReactTimeAgo
|
<ReactTimeAgo
|
||||||
date={lastUpdate}
|
date={healthReport.updatedAt}
|
||||||
live={false}
|
live={false}
|
||||||
/>
|
/>
|
||||||
</p>
|
</p>
|
||||||
@ -73,12 +69,12 @@ const ReportCard = ({
|
|||||||
<ul className={styles.reportCardList}>
|
<ul className={styles.reportCardList}>
|
||||||
<li>
|
<li>
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={activeCount}
|
condition={Boolean(healthReport.activeCount)}
|
||||||
show={renderActiveToggles}
|
show={renderActiveToggles}
|
||||||
/>
|
/>
|
||||||
</li>
|
</li>
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={activeCount}
|
condition={Boolean(healthReport.activeCount)}
|
||||||
show={
|
show={
|
||||||
<p className={styles.reportCardActionText}>
|
<p className={styles.reportCardActionText}>
|
||||||
Also includes potentially stale toggles.
|
Also includes potentially stale toggles.
|
||||||
@ -88,7 +84,7 @@ const ReportCard = ({
|
|||||||
|
|
||||||
<li>
|
<li>
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={staleCount}
|
condition={Boolean(healthReport.staleCount)}
|
||||||
show={renderStaleToggles}
|
show={renderStaleToggles}
|
||||||
/>
|
/>
|
||||||
</li>
|
</li>
|
||||||
@ -101,13 +97,13 @@ const ReportCard = ({
|
|||||||
<ul className={styles.reportCardList}>
|
<ul className={styles.reportCardList}>
|
||||||
<li>
|
<li>
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={potentiallyStaleCount}
|
condition={Boolean(healthReport.potentiallyStaleCount)}
|
||||||
show={renderPotentiallyStaleToggles}
|
show={renderPotentiallyStaleToggles}
|
||||||
/>
|
/>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={potentiallyStaleCount}
|
condition={Boolean(healthReport.potentiallyStaleCount)}
|
||||||
show={
|
show={
|
||||||
<p className={styles.reportCardActionText}>
|
<p className={styles.reportCardActionText}>
|
||||||
Review your feature toggles and delete
|
Review your feature toggles and delete
|
||||||
@ -126,9 +122,3 @@ const ReportCard = ({
|
|||||||
</Paper>
|
</Paper>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
ReportCard.propTypes = {
|
|
||||||
features: PropTypes.array.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ReportCard;
|
|
@ -1,19 +0,0 @@
|
|||||||
import { connect } from 'react-redux';
|
|
||||||
|
|
||||||
import ReportCard from './ReportCard';
|
|
||||||
import { filterByProject } from '../utils';
|
|
||||||
|
|
||||||
const mapStateToProps = (state, ownProps) => {
|
|
||||||
const features = state.features.toJS();
|
|
||||||
|
|
||||||
const sameProject = filterByProject(ownProps.selectedProject);
|
|
||||||
const featuresByProject = features.filter(sameProject);
|
|
||||||
|
|
||||||
return {
|
|
||||||
features: featuresByProject,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const ReportCardContainer = connect(mapStateToProps, null)(ReportCard);
|
|
||||||
|
|
||||||
export default ReportCardContainer;
|
|
@ -1,107 +0,0 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
|
||||||
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
import Select from '../common/select';
|
|
||||||
import ReportCardContainer from './ReportCard/ReportCardContainer';
|
|
||||||
import ReportToggleList from './ReportToggleList/ReportToggleList';
|
|
||||||
|
|
||||||
import ConditionallyRender from '../common/ConditionallyRender/ConditionallyRender';
|
|
||||||
|
|
||||||
import { formatProjectOptions } from './utils';
|
|
||||||
import { REPORTING_SELECT_ID } from '../../testIds';
|
|
||||||
|
|
||||||
import styles from './Reporting.module.scss';
|
|
||||||
import useHealthReport from '../../hooks/api/getters/useHealthReport/useHealthReport';
|
|
||||||
import ApiError from '../common/ApiError/ApiError';
|
|
||||||
import useQueryParams from '../../hooks/useQueryParams';
|
|
||||||
|
|
||||||
const Reporting = ({ projects }) => {
|
|
||||||
const [projectOptions, setProjectOptions] = useState([
|
|
||||||
{ key: 'default', label: 'Default' },
|
|
||||||
]);
|
|
||||||
const [selectedProject, setSelectedProject] = useState('default');
|
|
||||||
const { project, error, refetch } = useHealthReport(selectedProject);
|
|
||||||
|
|
||||||
const params = useQueryParams();
|
|
||||||
const projectId = params.get('project');
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (projectId) {
|
|
||||||
return setSelectedProject(projectId);
|
|
||||||
}
|
|
||||||
setSelectedProject(projects[0].id);
|
|
||||||
|
|
||||||
/* eslint-disable-next-line */
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setProjectOptions(formatProjectOptions(projects));
|
|
||||||
}, [projects]);
|
|
||||||
|
|
||||||
const onChange = e => {
|
|
||||||
const { value } = e.target;
|
|
||||||
|
|
||||||
const selectedProject = projectOptions.find(
|
|
||||||
option => option.key === value
|
|
||||||
);
|
|
||||||
|
|
||||||
setSelectedProject(selectedProject.key);
|
|
||||||
};
|
|
||||||
|
|
||||||
const renderSelect = () => (
|
|
||||||
<div className={styles.projectSelector}>
|
|
||||||
<h1 className={styles.header}>Project</h1>
|
|
||||||
<Select
|
|
||||||
name="project"
|
|
||||||
className={styles.select}
|
|
||||||
options={projectOptions}
|
|
||||||
value={selectedProject}
|
|
||||||
onChange={onChange}
|
|
||||||
inputProps={{ ['data-testid']: REPORTING_SELECT_ID }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
const multipleProjects = projects.length > 1;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<React.Fragment>
|
|
||||||
<ConditionallyRender
|
|
||||||
condition={multipleProjects}
|
|
||||||
show={renderSelect}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<ConditionallyRender
|
|
||||||
condition={error}
|
|
||||||
show={
|
|
||||||
<ApiError
|
|
||||||
data-loading
|
|
||||||
style={{ maxWidth: '500px', marginTop: '1rem' }}
|
|
||||||
onClick={refetch}
|
|
||||||
text={`Could not fetch health rating for ${selectedProject}`}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<ReportCardContainer
|
|
||||||
health={project?.health}
|
|
||||||
staleCount={project?.staleCount}
|
|
||||||
activeCount={project?.activeCount}
|
|
||||||
potentiallyStaleCount={project?.potentiallyStaleCount}
|
|
||||||
selectedProject={selectedProject}
|
|
||||||
/>
|
|
||||||
<ReportToggleList
|
|
||||||
features={project.features}
|
|
||||||
selectedProject={selectedProject}
|
|
||||||
/>
|
|
||||||
</React.Fragment>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
Reporting.propTypes = {
|
|
||||||
fetchFeatureToggles: PropTypes.func.isRequired,
|
|
||||||
projects: PropTypes.array.isRequired,
|
|
||||||
features: PropTypes.array,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Reporting;
|
|
@ -1,176 +0,0 @@
|
|||||||
.header {
|
|
||||||
font-size: var(--h1-size);
|
|
||||||
font-weight: 700;
|
|
||||||
margin: 0 0 0.5rem 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card {
|
|
||||||
width: 100%;
|
|
||||||
padding: var(--card-padding);
|
|
||||||
margin: var(--card-margin-y) 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.projectSelector {
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select {
|
|
||||||
background-color: #fff;
|
|
||||||
border: none;
|
|
||||||
padding: 0.5rem 1rem;
|
|
||||||
position: static;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select select {
|
|
||||||
border: none;
|
|
||||||
min-width: 120px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select select:active {
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** ReportCard **/
|
|
||||||
|
|
||||||
.reportCardContainer {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
|
|
||||||
.reportCardHealthInnerContainer {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
height: 80%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.reportCardHealthRating {
|
|
||||||
font-size: 2rem;
|
|
||||||
font-weight: bold;
|
|
||||||
color: var(--success);
|
|
||||||
}
|
|
||||||
|
|
||||||
.reportCardList {
|
|
||||||
list-style-type: none;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.reportCardList li {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
margin: 0.5rem 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.reportCardList li span {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
margin-left: 0.5rem;
|
|
||||||
font-size: var(--p-size);
|
|
||||||
}
|
|
||||||
|
|
||||||
.check,
|
|
||||||
.danger {
|
|
||||||
margin-right: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.check {
|
|
||||||
color: var(--success);
|
|
||||||
}
|
|
||||||
|
|
||||||
.danger {
|
|
||||||
color: var(--danger);
|
|
||||||
}
|
|
||||||
|
|
||||||
.reportCardActionContainer {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.reportCardActionText {
|
|
||||||
max-width: 300px;
|
|
||||||
font-size: var(--p-size);
|
|
||||||
}
|
|
||||||
|
|
||||||
.reportCardBtn {
|
|
||||||
background-color: #f2f2f2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.healthDanger {
|
|
||||||
color: var(--danger);
|
|
||||||
}
|
|
||||||
|
|
||||||
.healthWarning {
|
|
||||||
color: var(--warning);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** ReportToggleList **/
|
|
||||||
.reportToggleList {
|
|
||||||
width: 100%;
|
|
||||||
margin: var(--card-margin-y) 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bulkAction {
|
|
||||||
background-color: #f2f2f2;
|
|
||||||
font-size: var(--p-size);
|
|
||||||
}
|
|
||||||
|
|
||||||
.sortIcon {
|
|
||||||
margin-left: 8px;
|
|
||||||
transform: translateY(6px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.reportToggleListHeader {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
border-bottom: var(--default-border);
|
|
||||||
padding: 1rem var(--card-padding-x);
|
|
||||||
}
|
|
||||||
|
|
||||||
.reportToggleListInnerContainer {
|
|
||||||
padding: var(--card-padding);
|
|
||||||
}
|
|
||||||
|
|
||||||
.reportToggleListHeading {
|
|
||||||
font-size: var(--h1-size);
|
|
||||||
margin: 0;
|
|
||||||
font-weight: 'bold';
|
|
||||||
}
|
|
||||||
|
|
||||||
.reportingToggleTable {
|
|
||||||
width: 100%;
|
|
||||||
border-spacing: 0 0.8rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.reportingToggleTable th {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.expired {
|
|
||||||
color: var(--danger);
|
|
||||||
}
|
|
||||||
|
|
||||||
.active {
|
|
||||||
color: var(--success);
|
|
||||||
}
|
|
||||||
|
|
||||||
.stale {
|
|
||||||
color: var(--danger);
|
|
||||||
}
|
|
||||||
|
|
||||||
.reportStatus {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.reportIcon {
|
|
||||||
font-size: 1.5rem;
|
|
||||||
margin-right: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tableRow {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
import { connect } from 'react-redux';
|
|
||||||
import { fetchFeatureToggles } from '../../store/feature-toggle/actions';
|
|
||||||
|
|
||||||
import Reporting from './Reporting.jsx';
|
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
|
||||||
projects: state.projects.toJS(),
|
|
||||||
});
|
|
||||||
|
|
||||||
const mapDispatchToProps = {
|
|
||||||
fetchFeatureToggles,
|
|
||||||
};
|
|
||||||
|
|
||||||
const ReportingContainer = connect(
|
|
||||||
mapStateToProps,
|
|
||||||
mapDispatchToProps
|
|
||||||
)(Reporting);
|
|
||||||
|
|
||||||
export default ReportingContainer;
|
|
@ -177,10 +177,3 @@ export const getDates = dateString => {
|
|||||||
|
|
||||||
export const filterByProject = selectedProject => feature =>
|
export const filterByProject = selectedProject => feature =>
|
||||||
feature.project === selectedProject;
|
feature.project === selectedProject;
|
||||||
|
|
||||||
export const isFeatureExpired = feature => {
|
|
||||||
const [date, now] = getDates(feature.createdAt);
|
|
||||||
const diff = getDiffInDays(date, now);
|
|
||||||
|
|
||||||
return expired(diff, feature.type);
|
|
||||||
};
|
|
||||||
|
@ -1,40 +1,38 @@
|
|||||||
import useHealthReport from '../../../../hooks/api/getters/useHealthReport/useHealthReport';
|
import { useHealthReport } from '../../../../hooks/api/getters/useHealthReport/useHealthReport';
|
||||||
import ApiError from '../../../common/ApiError/ApiError';
|
import ApiError from '../../../common/ApiError/ApiError';
|
||||||
import ConditionallyRender from '../../../common/ConditionallyRender';
|
import ConditionallyRender from '../../../common/ConditionallyRender';
|
||||||
import ReportCardContainer from '../../../Reporting/ReportCard/ReportCardContainer';
|
|
||||||
import ReportToggleList from '../../../Reporting/ReportToggleList/ReportToggleList';
|
import ReportToggleList from '../../../Reporting/ReportToggleList/ReportToggleList';
|
||||||
|
import { ReportCard } from '../../../Reporting/ReportCard/ReportCard';
|
||||||
|
|
||||||
interface ProjectHealthProps {
|
interface ProjectHealthProps {
|
||||||
projectId: string;
|
projectId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ProjectHealth = ({ projectId }: ProjectHealthProps) => {
|
const ProjectHealth = ({ projectId }: ProjectHealthProps) => {
|
||||||
const { project, error, refetch } = useHealthReport(projectId);
|
const { healthReport, refetchHealthReport, error } =
|
||||||
|
useHealthReport(projectId);
|
||||||
|
|
||||||
|
if (!healthReport) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={error}
|
condition={Boolean(error)}
|
||||||
show={
|
show={
|
||||||
<ApiError
|
<ApiError
|
||||||
data-loading
|
data-loading
|
||||||
style={{ maxWidth: '500px', marginTop: '1rem' }}
|
style={{ maxWidth: '500px', marginTop: '1rem' }}
|
||||||
onClick={refetch}
|
onClick={refetchHealthReport}
|
||||||
text={`Could not fetch health rating for ${projectId}`}
|
text={`Could not fetch health rating for ${projectId}`}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<ReportCardContainer
|
<ReportCard healthReport={healthReport} />
|
||||||
health={project?.health}
|
|
||||||
staleCount={project?.staleCount}
|
|
||||||
activeCount={project?.activeCount}
|
|
||||||
potentiallyStaleCount={project?.potentiallyStaleCount}
|
|
||||||
selectedProject={project.name}
|
|
||||||
lastUpdate={project.updatedAt}
|
|
||||||
/>
|
|
||||||
<ReportToggleList
|
<ReportToggleList
|
||||||
features={project.features}
|
|
||||||
selectedProject={projectId}
|
selectedProject={projectId}
|
||||||
|
features={healthReport.features}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -1,51 +1,42 @@
|
|||||||
import useSWR, { mutate, SWRConfiguration } from 'swr';
|
import useSWR, { mutate, SWRConfiguration } from 'swr';
|
||||||
import { useState, useEffect } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { IProjectHealthReport } from '../../../../interfaces/project';
|
import { IProjectHealthReport } from '../../../../interfaces/project';
|
||||||
import { fallbackProject } from '../useProject/fallbackProject';
|
|
||||||
import useSort from '../../../useSort';
|
|
||||||
import { formatApiPath } from '../../../../utils/format-path';
|
import { formatApiPath } from '../../../../utils/format-path';
|
||||||
import handleErrorResponses from '../httpErrorResponseHandler';
|
import handleErrorResponses from '../httpErrorResponseHandler';
|
||||||
|
|
||||||
const useHealthReport = (id: string, options: SWRConfiguration = {}) => {
|
interface IUseHealthReportOutput {
|
||||||
const KEY = `api/admin/projects/${id}/health-report`;
|
healthReport: IProjectHealthReport | undefined;
|
||||||
|
refetchHealthReport: () => void;
|
||||||
|
loading: boolean;
|
||||||
|
error?: Error;
|
||||||
|
}
|
||||||
|
|
||||||
const fetcher = () => {
|
export const useHealthReport = (
|
||||||
const path = formatApiPath(`api/admin/projects/${id}/health-report`);
|
projectId: string,
|
||||||
return fetch(path, {
|
options?: SWRConfiguration
|
||||||
method: 'GET',
|
): IUseHealthReportOutput => {
|
||||||
})
|
const path = formatApiPath(`api/admin/projects/${projectId}/health-report`);
|
||||||
|
|
||||||
|
const { data, error } = useSWR<IProjectHealthReport>(
|
||||||
|
path,
|
||||||
|
fetchHealthReport,
|
||||||
|
options
|
||||||
|
);
|
||||||
|
|
||||||
|
const refetchHealthReport = useCallback(() => {
|
||||||
|
mutate(path).catch(console.warn);
|
||||||
|
}, [path]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
healthReport: data,
|
||||||
|
refetchHealthReport,
|
||||||
|
loading: !error && !data,
|
||||||
|
error,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchHealthReport = (path: string): Promise<IProjectHealthReport> => {
|
||||||
|
return fetch(path)
|
||||||
.then(handleErrorResponses('Health report'))
|
.then(handleErrorResponses('Health report'))
|
||||||
.then(res => res.json());
|
.then(res => res.json());
|
||||||
};
|
};
|
||||||
|
|
||||||
const [sort] = useSort();
|
|
||||||
|
|
||||||
const { data, error } = useSWR<IProjectHealthReport>(KEY, fetcher, options);
|
|
||||||
const [loading, setLoading] = useState(!error && !data);
|
|
||||||
|
|
||||||
const refetch = () => {
|
|
||||||
mutate(KEY);
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setLoading(!error && !data);
|
|
||||||
}, [data, error]);
|
|
||||||
|
|
||||||
const sortedData = (
|
|
||||||
data: IProjectHealthReport | undefined
|
|
||||||
): IProjectHealthReport => {
|
|
||||||
if (data) {
|
|
||||||
return { ...data, features: sort(data.features || []) };
|
|
||||||
}
|
|
||||||
return fallbackProject;
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
project: sortedData(data),
|
|
||||||
error,
|
|
||||||
loading,
|
|
||||||
refetch,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export default useHealthReport;
|
|
||||||
|
@ -24,7 +24,7 @@ export interface IProjectHealthReport extends IProject {
|
|||||||
staleCount: number;
|
staleCount: number;
|
||||||
potentiallyStaleCount: number;
|
potentiallyStaleCount: number;
|
||||||
activeCount: number;
|
activeCount: number;
|
||||||
updatedAt: Date;
|
updatedAt: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPermission {
|
export interface IPermission {
|
||||||
|
Loading…
Reference in New Issue
Block a user