Skip to content

Commit

Permalink
feat: add recap views (a11y, budget, stats) (#303)
Browse files Browse the repository at this point in the history
  • Loading branch information
revolunet authored Feb 27, 2024
1 parent 3c53080 commit 16599bc
Show file tree
Hide file tree
Showing 6 changed files with 343 additions and 29 deletions.
274 changes: 274 additions & 0 deletions report/www/pages/summary/[id].tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,274 @@
import { useState } from "react";
import type { GetStaticPaths, GetStaticProps } from "next";
import Head from "next/head";

import Badge from "@codegouvfr/react-dsfr/Badge";
import { Select } from "@codegouvfr/react-dsfr/Select";
import { fr } from "@codegouvfr/react-dsfr";
import { DataGrid, GridColDef } from "@mui/x-data-grid";

import dashlordConfig from "@/config.json";
import { isToolEnabled, smallUrl, slugifyUrl } from "../../src/utils";
import Link from "next/link";
import { GradeBadge, IconUnknown } from "../../src/components/GradeBadge";
import {
getLatestPhase,
phaseSeverities,
} from "../../src/components/BetagouvInfo";

const report: DashLordReport = require("../../src/report.json");

type SummaryConfig = {
title: string;
columns: GridColDef[];
};

const defaultColumnsProps = {
sortable: true,
width: 120,
type: "string",
headerAlign: "left" as const,
align: "left" as const,
};

const getPhaseColumn = (): GridColDef => ({
...defaultColumnsProps,
field: "phase",
headerName: `Phase`,
align: "center",
headerAlign: "center",
width: 250,
valueGetter: (params) => {
return (
(params.row.betagouv &&
getLatestPhase(params.row.betagouv.attributes.phases).index) ||
""
);
},
renderCell: (params) => {
if (!isToolEnabled("betagouv", params.row.url)) return <IconUnknown />;
const latestPhase =
params.row.betagouv &&
getLatestPhase(params.row.betagouv.attributes.phases);
if (latestPhase) {
return (
<Badge
severity={phaseSeverities[latestPhase.label.toLowerCase()] || "info"}
noIcon
>
{latestPhase.label}
</Badge>
);
} else {
return <IconUnknown />;
}
},
});

const summaryConfigs: Record<string, SummaryConfig> = {
accessibility: {
title: "Accessibilité",
columns: [
{
...defaultColumnsProps,
align: "center",
headerAlign: "center",
field: "mention",
headerName: `Détection déclaration`,
width: 400,
valueGetter: (params) =>
(params.row["declaration-a11y"] &&
params.row["declaration-a11y"].mention) ||
"",
renderCell: (params) => {
if (params.value) {
const text = params.value.replace(/^Accessibilité : /, "");
if (params.row["declaration-a11y"].declarationUrl) {
return (
<Link
prefetch={false}
title={`Voir la déclaration d'accessiblité de l'url ${slugifyUrl(
params.row.url
)}`}
href={params.row["declaration-a11y"].declarationUrl}
target="_blank"
>
{text}
</Link>
);
}
return text;
}
return <GradeBadge showWarningOnError label="F" />;
},
},
],
},
stats: {
title: "Page de stats",
columns: [
{
...defaultColumnsProps,
align: "center",
headerAlign: "center",
field: "stats",
headerName: `Page de stats`,
width: 400,
valueGetter: (params) =>
(params.row.stats && params.row.stats.grade) || "F",
renderCell: (params) => {
if (params.value === "A") {
return (
<Link
prefetch={false}
title={`Voir la page de stats de l'url ${slugifyUrl(
params.row.url
)}`}
href={params.row.stats.url + "/" + params.row.stats.uri}
target="_blank"
>
/{params.row.stats.uri}
</Link>
);
}
return <GradeBadge showWarningOnError label="F" />;
},
},
],
},
budget: {
title: "Publication du budget",
columns: [
{
...defaultColumnsProps,
align: "center",
headerAlign: "center",
field: "stats",
headerName: `Page de budget`,
width: 400,
valueGetter: (params) =>
(params.row.budget && params.row.budget.grade) || "F",
renderCell: (params) => {
if (params.value === "A") {
return (
<Link
prefetch={false}
title={`Voir la page de budget de l'url ${slugifyUrl(
params.row.url
)}`}
href={params.row.budget.url + "/" + params.row.budget.uri}
target="_blank"
>
/{params.row.budget.uri}
</Link>
);
}
return <GradeBadge showWarningOnError label="F" />;
},
},
],
},
};

const Summary = ({ id }: { id: string }) => {
const [category, setCategory] = useState(null);
const summaryConfig = summaryConfigs[id];
const categories = Array.from(
new Set(report.map((url) => url.category).filter(Boolean))
);

const tableData = category
? report.filter((url) => url.category === category)
: report;

const ROWS_COUNT = 100;

const columns = [
{
...defaultColumnsProps,
field: "url",
headerName: `URL`,
width: 400,
renderCell: (params) => (
<div
style={{
width: "95%",
overflow: "hidden",
whiteSpace: "nowrap",
textOverflow: "ellipsis",
}}
>
<Link
prefetch={false}
title={`Voir les détails de l'url ${slugifyUrl(params.value)}`}
href={`/url/${encodeURIComponent(slugifyUrl(params.value))}`}
>
<i className={fr.cx("fr-icon-search-line", "fr-icon--sm")} />
&nbsp;
{smallUrl(params.value)}
</Link>
</div>
),
},
isToolEnabled("betagouv") && getPhaseColumn(),
...summaryConfig.columns,
].filter(Boolean);
return (
<>
<Head>
<title>
Rapport {summaryConfig.title} - {dashlordConfig.title}
</title>
</Head>
<h1>{summaryConfig.title}</h1>
{categories.length > 1 && (
<Select
label={null}
nativeSelectProps={{
onChange: (event) => setCategory(event.target.value),
}}
>
<option value="">tous les incubateurs</option>
{categories.map((cat) => (
<option value={cat} key={cat}>
{cat}
</option>
))}
</Select>
)}
<DataGrid
rows={tableData}
columns={columns}
sortModel={[{ field: "phase", sort: "desc" }]}
autoHeight={true}
getRowId={(row) => row.url}
disableVirtualization
disableColumnMenu={true}
disableDensitySelector={true}
rowSelection={false}
hideFooterPagination={false}
hideFooter={tableData.length < ROWS_COUNT}
localeText={{
MuiTablePagination: { labelRowsPerPage: "Lignes par page" },
}}
pagination={true}
/>
</>
);
};

// will be passed to the page component as props
export const getStaticProps: GetStaticProps = async ({ params }) => {
const id = params && (params.id as string);
return {
props: { id },
};
};

// return list of urls to generate
export const getStaticPaths: GetStaticPaths = async () => ({
paths: ["/summary/accessibility", "/summary/stats", "/summary/budget"],
fallback: false,
});

export default Summary;
Binary file added report/www/public/logo-betagouv.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
27 changes: 27 additions & 0 deletions report/www/src/__tests__/__snapshots__/Header.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,33 @@ exports[`Should render HeaderSite 1`] = `
Disponibilité (updown.io)
</a>
</li>
<li>
<a
class="fr-nav__link"
href="/summary/accessibility"
id="fr-header-main-navigation-menu-2-link-R_capaccessiblit_-2"
>
Récap accessiblité
</a>
</li>
<li>
<a
class="fr-nav__link"
href="/summary/stats"
id="fr-header-main-navigation-menu-2-link-R_capStats-3"
>
Récap Stats
</a>
</li>
<li>
<a
class="fr-nav__link"
href="/summary/budget"
id="fr-header-main-navigation-menu-2-link-R_capbudget-4"
>
Récap budget
</a>
</li>
</ul>
</div>
</li>
Expand Down
16 changes: 11 additions & 5 deletions report/www/src/components/BetagouvInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,14 @@ type BetagouvPhase = {
};

// return latest phase augmented data if any
const getLatestPhase = (phases: BetagouvReportPhase[]) => {
const sortedPhases = phases.sort(sortPhases);
export const getLatestPhase = (allphases: BetagouvReportPhase[]) => {
const sortedPhases = allphases.sort(sortPhases);
return sortedPhases.length
? getPhase(sortedPhases[sortedPhases.length - 1].name)
: { label: "-", index: 0 }; // fallback
};

const Betagouv: React.FC<BetagouvProps> = ({ data }) => {
export const Betagouv: React.FC<BetagouvProps> = ({ data }) => {
const sortedPhases = data.attributes.phases.sort(sortPhases);
return (
<Panel title="Phases de la SE">
Expand Down Expand Up @@ -86,8 +86,6 @@ const Betagouv: React.FC<BetagouvProps> = ({ data }) => {
);
};

export { Betagouv, getLatestPhase };

// index is used when we have similar timestamps for different phases
const phases = [
{
Expand Down Expand Up @@ -125,6 +123,14 @@ const phases = [
{ id: "alumni", label: "Partenariat terminé", icon: XCircle, index: 6 },
] as BetagouvPhase[];

export const phaseSeverities = {
accélération: "info",
construction: "warning",
"partenariat terminé": "error",
transfert: "success",
succès: "success",
};

const getPhase = (phase: string) => phases.find((f) => f.id === phase);

// sort some input phases
Expand Down
17 changes: 3 additions & 14 deletions report/www/src/components/Dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { DataGrid, GridColDef } from "@mui/x-data-grid";
import { fr } from "@codegouvfr/react-dsfr";

import { isToolEnabled, smallUrl, slugifyUrl } from "../utils";
import { getLatestPhase } from "./BetagouvInfo";
import { getLatestPhase, phaseSeverities } from "./BetagouvInfo";
import { GradeBadge, IconUnknown } from "./GradeBadge";
import dashlordConfig from "@/config.json";

Expand Down Expand Up @@ -63,14 +63,6 @@ export const Dashboard: React.FC<DashboardProps> = ({ report }) => {
return isToolEnabled(tool) && !isColumnDisabled;
};

const phaseSeverities = {
accélération: "info",
construction: "warning",
"partenariat terminé": "error",
transfert: "success",
succès: "success",
};

if (isColumnEnabled("betagouv")) {
columns.push({
...defaultColumnsProps,
Expand Down Expand Up @@ -1021,14 +1013,11 @@ export const Dashboard: React.FC<DashboardProps> = ({ report }) => {

const ROWS_COUNT = 100;

const tableProps = {
rows: tableData,
columns,
};
return (
(report && (
<DataGrid
{...tableProps}
rows={tableData}
columns={columns}
autoHeight={true}
disableVirtualization
disableColumnMenu={true}
Expand Down
Loading

0 comments on commit 16599bc

Please sign in to comment.