Commit b393e346 authored by Jordan Grossemy's avatar Jordan Grossemy
Browse files

« il y a 1473 min » et « a faire »

Deux façons d'afficher juste et de n'être pas lu.

── Un âge en minutes, sans limite

Le cockpit annonçait « Dernier point · il y a 1473 min ». Le nombre est exact et
personne ne le convertit : à vingt-quatre heures d'une crise, ce qu'on veut
savoir tient dans « il y a un jour ». Continuité formulait déjà cela
correctement, dans une fonction locale ; elle monte au module commun et sert aux
deux. Un âge se dit d'une seule manière dans le produit, sinon deux écrans qui
regardent la même donnée s'en font deux idées.

── Des identifiants montrés pour des libellés

Les statuts d'action s'affichaient par un remplacement du souligné par une
espace : « a faire », « bloquee », « abandonnee ». Un cockpit français qui perd
ses accents en chemin, dans quatre écrans, alors que « LIBELLES_STATUT » existe
depuis l'origine et dit « À faire », « Bloquée », « Abandonnée ».

Le champ passe du « string » au type de l'énumération, ce qui fait que l'oubli ne
se reproduira pas en silence : indexer les libellés avec autre chose que l'un des
cinq statuts ne compile plus.

Co-Authored-By: Claude (RCA)
parent 6dc39e73
Loading
Loading
Loading
Loading
+5 −4
Changes for apps/web/src/coque/Tuiles.tsx: 5 added lines, 4 removed lines.
Original line number Diff line number Diff line
import { useQuery } from "@tanstack/react-query";
import type { Tuile } from "@kastell/shared/cockpit";
import { LIBELLES_STATUT, type StatutAction } from "@kastell/shared";
import { api, type Cockpit } from "../api.js";
import { dateHeure } from "../etat.js";
import { anciennete, dateHeure } from "../etat.js";

/**
 * Les tuiles du cockpit (§6.3).
@@ -106,7 +107,7 @@ function Cellules({ cockpit }: ContexteTuile) {
            <div className="fait" style={{ fontSize: 13 }}>
              <span className="discret">Dernier point</span>
              <span className="valeur">
                {c.dernier_point_at ? `il y a ${c.anciennete_minutes} min` : "jamais"}
                {c.dernier_point_at ? anciennete(c.anciennete_minutes) : "jamais"}
              </span>
            </div>
            <div className="fait" style={{ fontSize: 13 }}>
@@ -300,7 +301,7 @@ function EcheanceReglementaire({ criseId, aller }: ContexteTuile) {

interface ActionListee {
  id: string; intitule: string; responsable_libelle: string | null;
  statut: string; echeance: string | null; cellule_id: string | null;
  statut: StatutAction; echeance: string | null; cellule_id: string | null;
}

function ActionsCellule({ criseId, celluleId, aller }: ContexteTuile) {
@@ -330,7 +331,7 @@ function ActionsCellule({ criseId, celluleId, aller }: ContexteTuile) {
              <tr key={a.id}>
                <td>{a.intitule}</td>
                <td className="discret">{a.responsable_libelle ?? "non attribuée"}</td>
                <td className="discret">{a.statut.replace("_", " ")}</td>
                <td className="discret">{LIBELLES_STATUT[a.statut]}</td>
              </tr>
            ))}
          </tbody>
+3 −2
Changes for apps/web/src/ecrans/Conduite.tsx: 3 added lines, 2 removed lines.
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@ import { ChoixPorteur, SANS_RESPONSABLE, type Affectation }
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { api, ErreurApi, type Entree } from "../api.js";
import { dateHeure } from "../etat.js";
import { LIBELLES_STATUT, STATUTS_ACTION } from "@kastell/shared";
import { Historique } from "../coque/Historique.js";
import { ActionDetail } from "./ActionDetail.js";

@@ -240,8 +241,8 @@ export function Conduite({
                              { statut: e.target.value })
                              .then(() => client.invalidateQueries(
                                { queryKey: ["actions", criseId] }))}>
                            {["a_faire", "en_cours", "bloquee", "faite", "abandonnee"]
                              .map((s) => <option key={s} value={s}>{s.replace("_", " ")}</option>)}
                            {STATUTS_ACTION.map((s) => (
                              <option key={s} value={s}>{LIBELLES_STATUT[s]}</option>))}
                          </select>
                        </td>
                        <td>
+3 −8
Changes for apps/web/src/ecrans/Continuite.tsx: 3 added lines, 8 removed lines.
Original line number Diff line number Diff line
import { useState } from "react";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { api, ErreurApi } from "../api.js";
import { dateHeure } from "../etat.js";
import { anciennete, dateHeure } from "../etat.js";

interface Ligne {
  application_id: string; nom: string;
@@ -21,12 +21,7 @@ const ETATS = {
  inconnu: { libelle: "Non constaté", classe: "neutre" },
} as const;

const age = (m: number | null) => {
  if (m === null) return "jamais";
  if (m < 60) return `il y a ${m} min`;
  const h = Math.floor(m / 60);
  return h < 24 ? `il y a ${h} h` : `il y a ${Math.floor(h / 24)} j`;
};


/**
 * Continuité d’activité (§6.12).
@@ -289,7 +284,7 @@ export function Continuite({ criseId, lectureSeule }: {
                <td className="discret" style={{ fontSize: 13 }}>
                  {/* La fraîcheur d'abord : c'est elle qui fait la valeur du tableau. */}
                  <span className={a.perime ? "pastille alerte" : undefined}>
                    {age(a.age_minutes)}
                    {anciennete(a.age_minutes)}
                  </span>
                  {a.constate_par_nom && (
                    <div style={{ fontSize: 12.5 }}>
+3 −2
Changes for apps/web/src/ecrans/MesActions.tsx: 3 added lines, 2 removed lines.
Original line number Diff line number Diff line
import { useQuery } from "@tanstack/react-query";
import { api } from "../api.js";
import { dateHeure } from "../etat.js";
import { LIBELLES_STATUT, type StatutAction } from "@kastell/shared";
import { useRoute } from "../routeur.js";

interface Incombance {
  id: string;
  crise_id: string;
  intitule: string;
  statut: string;
  statut: StatutAction;
  echeance: string | null;
  crise_intitule: string;
  crise_gravite: string;
@@ -71,7 +72,7 @@ export function MesActions() {
              <div className="ligne" style={{ gap: 12, marginTop: 6, fontSize: 13,
                color: "var(--encre-2)", flexWrap: "wrap" }}>
                <span>{a.crise_intitule}</span>
                <span>{a.statut.replace("_", " ")}</span>
                <span>{LIBELLES_STATUT[a.statut]}</span>
                <span style={enRetard(a) ? { color: "var(--crit)" } : undefined}>
                  {a.echeance ? dateHeure(a.echeance) : "sans échéance"}
                </span>
+3 −2
Changes for apps/web/src/ecrans/preparation/ActionsPreparation.tsx: 3 added lines, 2 removed lines.
Original line number Diff line number Diff line
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { api } from "../../api.js";
import { dateHeure } from "../../etat.js";
import { LIBELLES_STATUT, type StatutAction } from "@kastell/shared";

interface ActionPreparation {
  id: string;
@@ -12,7 +13,7 @@ interface ActionPreparation {
  cree_at: string;
}

const STATUTS = ["a_faire", "en_cours", "faite", "abandonnee"] as const;
const STATUTS: StatutAction[] = ["a_faire", "en_cours", "faite", "abandonnee"];

/**
 * Ce que le retour d'expérience a produit (EF-1206).
@@ -95,7 +96,7 @@ export function ActionsPreparation({ organisationId }: { organisationId: string
                          .then(() => client.invalidateQueries(
                            { queryKey: ["actions-preparation", organisationId] }))}>
                        {STATUTS.map((s) => (
                          <option key={s} value={s}>{s.replace("_", " ")}</option>
                          <option key={s} value={s}>{LIBELLES_STATUT[s]}</option>
                        ))}
                      </select>
                    </td>
Loading