feat: Diagram integration/Nb Resistant

wip-related-pages
Sébastien Arod 2024-09-20 12:55:26 +02:00
parent 4dba306763
commit b0272d3733
15 changed files with 253 additions and 61 deletions

View File

@ -8,13 +8,15 @@ import { computeELStats } from "./statistiques/v1/computeELStats";
import { computeStatsPenales } from "./statistiques/v2/penales/computeStatsPenales";
import { statsPenalesDesc } from "./statistiques/v2/penales/StatsPenales";
import { computeStatsGenerales } from "./statistiques/v2/generales/computeStatsGenerales";
import { statsGeneralesDesc } from "./statistiques/v2/generales/StatsGenerales";
import { computeStatsSociales } from "./statistiques/v2/sociales/computeStatsSociales";
import { statsSocialesDesc } from "./statistiques/v2/sociales/StatsSociales";
import { checkDbSchemas } from "./notion/fetch/schemaCheck/checkDbSchemas";
import { computeSequencEvtPenalSankeyData } from "./statistiques/v2/penales/computeSankeyData";
import { sankeyDataToMermaidDiagram } from "./statistiques/v2/sankey/sankeyDataToMermaidDiagram";
import { formatDate } from "date-fns";
import { computeStatsGeneralesMensuelles } from "./statistiques/v2/generales/computeStatsGeneralesMensuelles";
import { mermaidDiagramStatsGeneralesMensuelles } from "./statistiques/v2/generales/mermaidDiagramStatsGeneralesMensuelles";
import { publishStatsGenerales } from "./notion/publish/v2/publishStatsGenerales";
type ProcessOptions = {
dryRun: boolean;
@ -75,13 +77,20 @@ function buildProcessOptions(): ProcessOptions {
const elStats = computeELStats(familles, currentDate);
const statsGenerales = computeStatsGenerales(familles);
const statsPenales = computeStatsPenales(familles);
const statsSociales = computeStatsSociales(familles);
const statsGeneralesMensuelles = computeStatsGeneralesMensuelles(familles);
const mermaidDiagramStatsGeneralesMensuellesCode =
mermaidDiagramStatsGeneralesMensuelles(statsGeneralesMensuelles);
writeFileSync(
"./el-stats-penal-sankey-diagram.txt",
sankeyDataToMermaidDiagram(computeSequencEvtPenalSankeyData(familles))
);
writeFileSync(
"./el-stats-stats-generales-mensuel.txt",
mermaidDiagramStatsGeneralesMensuellesCode
);
if (options.dryRun) {
console.log(
"Dry run => Skip Publishing. Stats are dumped in file el-stats-xxx.json"
@ -95,6 +104,7 @@ function buildProcessOptions(): ProcessOptions {
generales: statsGenerales,
penales: statsPenales,
sociales: statsSociales,
StatsGeneralesMensuelles: statsGeneralesMensuelles,
},
null,
" "
@ -109,12 +119,11 @@ function buildProcessOptions(): ProcessOptions {
Dernière mise à jour le ${formatDate(currentDate, "dd/MM/yyyy à HH:mm")}
`;
await publishStatsToPage(
await publishStatsGenerales(
notionClient,
"313751fb-daed-4b33-992f-c86d7ac2de37",
header,
statsGeneralesDesc,
statsGenerales
statsGenerales,
mermaidDiagramStatsGeneralesMensuellesCode
);
await publishStatsToPage(
notionClient,

View File

@ -0,0 +1,6 @@
import { BlockObjectRequest } from "@notionhq/client/build/src/api-endpoints";
export type BulletedListItemBlockObjectRequest = Extract<
BlockObjectRequest,
{ bulleted_list_item: object }
>;

View File

@ -0,0 +1,4 @@
import { BulletedListItemBlockObjectRequest } from "./BulletedListItemBlockObjectRequest";
export type BulletedListItemChildren =
BulletedListItemBlockObjectRequest["bulleted_list_item"]["children"];

View File

@ -0,0 +1,6 @@
import { BlockObjectRequest } from "@notionhq/client/build/src/api-endpoints";
export type ParagraphBlockObjectRequest = Extract<
BlockObjectRequest,
{ paragraph: unknown }
>;

View File

@ -0,0 +1,22 @@
import { BlockObjectRequest } from "@notionhq/client/build/src/api-endpoints";
export function createMermaidCodeBlock(code: string): CodeBlockObjectRequest {
return {
code: {
language: "mermaid",
rich_text: [
{
type: "text",
text: {
content: code,
},
},
],
},
};
}
export type CodeBlockObjectRequest = Extract<
BlockObjectRequest,
{ code: unknown }
>;

View File

@ -0,0 +1,17 @@
import { ParagraphBlockObjectRequest } from "./ParagraphBlockObjectRequest";
export function createParagraphBlock(
content: string
): ParagraphBlockObjectRequest {
return {
paragraph: {
rich_text: [
{
text: {
content: content,
},
},
],
},
};
}

View File

@ -1,11 +1,11 @@
import { BlockObjectRequest } from "@notionhq/client/build/src/api-endpoints";
import {
isStatGroupDesc,
StatDesc,
StatGroupDesc,
StatsType,
} from "../../../statistiques/v2/desc/StatsDesc";
import { formatValue } from "../../../format/formatValue";
import { createStatListItemBlock } from "./createStatListItemBlock";
import { BulletedListItemBlockObjectRequest } from "../blocks/BulletedListItemBlockObjectRequest";
import { BulletedListItemChildren } from "../blocks/BulletedListItemChildren";
export function createStatGroupListItemBlock<D extends StatGroupDesc>(
descriptor: D,
@ -28,14 +28,6 @@ export function createStatGroupListItemBlock<D extends StatGroupDesc>(
};
}
export type BulletedListItemBlockObjectRequest = Extract<
BlockObjectRequest,
{ bulleted_list_item: object }
>;
export type BulletedListItemChildren =
BulletedListItemBlockObjectRequest["bulleted_list_item"]["children"];
export function createStatGroupChildrenListItemBlock<D extends StatGroupDesc>(
descriptor: D,
stats: StatsType<D>
@ -52,21 +44,3 @@ export function createStatGroupChildrenListItemBlock<D extends StatGroupDesc>(
: createStatListItemBlock(childStatDesc, childStatValue as number);
});
}
function createStatListItemBlock(
descriptor: StatDesc,
statValue: number
): BulletedListItemBlockObjectRequest {
return {
bulleted_list_item: {
rich_text: [
{
text: {
content:
descriptor.label + ": " + formatValue(statValue, descriptor),
},
},
],
},
};
}

View File

@ -0,0 +1,21 @@
import { formatValue } from "../../../format/formatValue";
import { StatDesc } from "../../../statistiques/v2/desc/StatsDesc";
import { BulletedListItemBlockObjectRequest } from "../blocks/BulletedListItemBlockObjectRequest";
export function createStatListItemBlock(
descriptor: StatDesc,
statValue: number
): BulletedListItemBlockObjectRequest {
return {
bulleted_list_item: {
rich_text: [
{
text: {
content:
descriptor.label + ": " + formatValue(statValue, descriptor),
},
},
],
},
};
}

View File

@ -0,0 +1,33 @@
import { Client } from "@notionhq/client";
import { createMermaidCodeBlock } from "../blocks/createMermaidCodeBlock";
import { createParagraphBlock } from "../blocks/createParagraphBlock";
import { createStatGroupChildrenListItemBlock } from "./createStatGroupListItemBlock";
import { updatePageContent } from "./updatePageContent";
import {
StatsGenerales,
statsGeneralesDesc,
} from "../../../statistiques/v2/generales/StatsGenerales";
export async function publishStatsGenerales(
notionClient: Client,
header: string,
statsGenerales: StatsGenerales,
mermaidDiagramStatsGeneralesMensuelles: string
) {
const headerBlock = createParagraphBlock(header);
const statsBlocks = createStatGroupChildrenListItemBlock(
statsGeneralesDesc,
statsGenerales
);
const diagramBlock = createMermaidCodeBlock(
mermaidDiagramStatsGeneralesMensuelles
);
const blocks = [headerBlock, ...statsBlocks, diagramBlock];
await updatePageContent(
notionClient,
"313751fb-daed-4b33-992f-c86d7ac2de37",
blocks
);
}

View File

@ -5,7 +5,7 @@ import {
} from "../../../statistiques/v2/desc/StatsDesc";
import { createStatGroupChildrenListItemBlock } from "./createStatGroupListItemBlock";
import { updatePageContent } from "./updatePageContent";
import { BlockObjectRequest } from "@notionhq/client/build/src/api-endpoints";
import { createParagraphBlock } from "../blocks/createParagraphBlock";
export async function publishStatsToPage<D extends StatGroupDesc>(
notionClient: Client,
@ -22,22 +22,3 @@ export async function publishStatsToPage<D extends StatGroupDesc>(
...statsBlocks,
]);
}
type ParagraphBlockObjectRequest = Extract<
BlockObjectRequest,
{ paragraph: unknown }
>;
function createParagraphBlock(content: string): ParagraphBlockObjectRequest {
return {
paragraph: {
rich_text: [
{
text: {
content: content,
},
},
],
},
};
}

View File

@ -1,6 +1,6 @@
import { getMonth, getYear, setMonth, setYear } from "date-fns";
import { IdentifiedPeriod } from "../../period/IdentifiedPeriod";
import { generateConsecutiveIdentifiedPeriods } from "../../period/generateConsecutiveIdentifiedPeriods";
import { IdentifiedPeriod } from "./IdentifiedPeriod";
import { generateConsecutiveIdentifiedPeriods } from "./generateConsecutiveIdentifiedPeriods";
export function generateELMonths(): IdentifiedPeriod[] {
const months = generateConsecutiveIdentifiedPeriods({

View File

@ -1,6 +1,6 @@
import { addYears } from "date-fns/fp";
import { IdentifiedPeriod } from "../../period/IdentifiedPeriod";
import { generateConsecutiveIdentifiedPeriods } from "../../period/generateConsecutiveIdentifiedPeriods";
import { IdentifiedPeriod } from "./IdentifiedPeriod";
import { generateConsecutiveIdentifiedPeriods } from "./generateConsecutiveIdentifiedPeriods";
export function generateELYears(): IdentifiedPeriod[] {
return generateConsecutiveIdentifiedPeriods({

View File

@ -2,8 +2,8 @@ import { Famille } from "../../data/Famille";
import { computeELPeriodStats } from "./computeELPeriodStats";
import { computeELStatsAtDate } from "./computeELStatsAtDate";
import { ELStats } from "./ELStats";
import { generateELMonths } from "./generateELMonths";
import { generateELYears } from "./generateELYears";
import { generateELMonths } from "../../period/generateELMonths";
import { generateELYears } from "../../period/generateELYears";
export function computeELStats(
families: Famille[],

View File

@ -0,0 +1,88 @@
import { Famille, isExResistant, isResistant } from "../../../data/Famille";
import { generateELMonths } from "../../../period/generateELMonths";
import { isPeriodContaining } from "../../../period/isPeriodContaining";
import { Period } from "../../../period/Period";
export type StatsGeneralesMensuelles = {
[month: string]: StatsGeneralesMensuelle;
};
export type StatsGeneralesMensuelle = {
nbEntrees: number;
nbSorties: number;
nbEntreesNet: number;
nbFamillesResistantes: number;
nbFamillesExResistantes: number;
};
export function computeStatsGeneralesMensuelles(
familles: Famille[]
): StatsGeneralesMensuelles {
const months = generateELMonths();
return Object.fromEntries(
months.map((period) => {
const nbEntrees = nbEntreeSurPeriode(familles, period);
const nbSorties = nbSortieSurPeriode(familles, period);
const statsMensuelle: StatsGeneralesMensuelle = {
nbEntrees: nbEntrees,
nbSorties: nbSorties,
nbEntreesNet: nbEntrees - nbSorties,
nbFamillesResistantes: nbFamillesResistanteAFinPeriode(
familles,
period
),
nbFamillesExResistantes: nbFamillesExResistanteAFinPeriode(
familles,
period
),
};
return [period.id, statsMensuelle];
})
);
}
function nbEntreeSurPeriode(familles: Famille[], period: Period): number {
return familles.filter(
(f) =>
(isResistant(f) || isExResistant(f)) &&
f.Integration &&
isPeriodContaining(period, f.Integration)
).length;
}
function nbSortieSurPeriode(familles: Famille[], period: Period): number {
return familles.filter(
(f) =>
(isResistant(f) || isExResistant(f)) &&
f.Sortie &&
isPeriodContaining(period, f.Sortie)
).length;
}
function nbFamillesResistanteAFinPeriode(
familles: Famille[],
period: Period
): number {
return familles.filter(
(f) =>
(isResistant(f) || isExResistant(f)) &&
f.Integration &&
f.Integration < period.end &&
(!f.Sortie || f.Sortie > period.end)
).length;
}
function nbFamillesExResistanteAFinPeriode(
familles: Famille[],
period: Period
): number {
return familles.filter(
(f) =>
(isResistant(f) || isExResistant(f)) &&
f.Integration &&
f.Integration < period.end &&
f.Sortie &&
f.Sortie < period.end
).length;
}

View File

@ -0,0 +1,31 @@
import { StatsGeneralesMensuelles } from "./computeStatsGeneralesMensuelles";
export function mermaidDiagramStatsGeneralesMensuelles(
statsGeneralesMensuelle: StatsGeneralesMensuelles
): string {
const statsEntries = Object.entries(statsGeneralesMensuelle);
const entriesToDisplay = statsEntries.slice(
statsEntries.length - 15,
statsEntries.length
);
const periods = entriesToDisplay.map(([p]) => {
const comp = p.split("-");
// Reformat month as MM/yy
return `"${comp[1]}/${comp[0].substring(2, 4)}"`;
});
return `---
config:
themeVariables:
xyChart:
plotColorPalette: "#1E88E5, #EEEEEE, #C8E6C9, #EF9A9A"
---
xychart-beta
title "Familles: Résist.(bleu), Ex-Résist (gris), Entrées (vert), Sorties (rouge)"
x-axis "Mois" [${periods}]
y-axis "Nb Familles" 0 --> 110
line [${entriesToDisplay.map(([, s]) => s.nbFamillesResistantes)}]
line [${entriesToDisplay.map(([, s]) => s.nbFamillesExResistantes)}]
line [${entriesToDisplay.map(([, s]) => s.nbEntrees)}]
line [${entriesToDisplay.map(([, s]) => s.nbSorties)}]
`;
}