Compare commits

..

4 Commits

Author SHA1 Message Date
tristan 62e1b019a1 refactor(catalog) : address Matthieu review on composables (constant + shared helpers)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 1m18s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m0s
- useCategoriesAdmin : extract `HYDRA_NO_PAGINATION = 999` to a named
  constant (was duplicated between fetchAll and fetchTypes) + comment
  the post-M0 server-pagination debt.

- useCategoryForm + useApi + shared/utils/api : drop the local copy of
  `extractErrorMessage` in useCategoryForm (it was duplicating the one
  in useApi), and centralize Hydra error / violation extraction in
  `shared/utils/api.ts` via two new helpers :
    - extractApiErrorMessage(data) : tries hydra:description, detail,
      description, message, error, title, hydra:title — used by both
      useApi.onResponseError and useCategoryForm.handleApiError.
    - extractApiViolations(data) : returns the ApiPlatform 422
      violations as a typed array (handles `violations` and
      `hydra:violations`), letting each caller map them onto its own
      fields. useCategoryForm now uses this helper instead of an
      inline loop, ready for the next form drawer to reuse.

handleApiError keeps a manual fallback toast on non-409/422 errors :
the native useApi toast is disabled by design (`toast: false`) to allow
fine-grained 409/422 mapping, so the catch-all branch must re-emit one
or a 500 would be silent.

No behavior change — 43/43 Vitest tests still pass.
2026-05-29 11:06:31 +02:00
tristan 27ea881738 refactor(catalog) : extract page logic into useCategoriesAdmin and useCategoryForm composables
Extrait la logique fetch/CRUD inline de la page categories (ERP-49) vers
deux composables dedies, conformement au pattern Starseed :

- useCategoriesAdmin : singleton state (categories + types + loading +
  error). Pre-chargement des types au mount de la page (au lieu du
  fetch par ouverture du drawer). Reset au logout via
  onAuthSessionCleared + appel explicite dans logout.vue.

- useCategoryForm : state local par form (pas singleton). Valide
  cote client en miroir des RG back (RG-1.02 / RG-1.04 / RG-1.05),
  mappe les erreurs 409 (doublon RG-1.07) et 422 (violations API
  Platform) sur les bons champs. submitCreate / submitUpdate /
  submitDelete renvoient la ressource ou null pour decoupler la
  decision de fermeture du drawer.

La page et le drawer deviennent purement presentationnels. Aucune
regression UX : meme validations, memes toasts, meme pattern
view -> edit du drawer (via isDirty expose par useCategoryForm).
2026-05-29 11:06:25 +02:00
gitea-actions e0d59962d6 chore: bump version to v0.1.50
Auto Tag Develop / tag (push) Successful in 6s
Build & Push Docker Image / build (push) Successful in 37s
2026-05-29 08:59:54 +00:00
tristan 3ce40a707f [ERP-49] Créer la page Gestion des catégories (datatable + drawer) (#22)
Auto Tag Develop / tag (push) Successful in 7s
## Contexte
Ticket Lesstime : [#49](https://lesstime.malio.fr/tasks/460) — premier ticket front du M0 (Gestion des catégories).
Suit la chaîne back ERP-43..48 mergée sur develop.

## Contenu first draft (Claude Code)
- Page Nuxt `/admin/categories` (`MalioDataTable` + bouton `+ Ajouter`)
- Composant `<CategoryDrawer>` : modes création / consultation / édition, transition auto view → edit à la première modification, validation client miroir RG-1.02 (name requis) / RG-1.04 (longueur 2-120) / RG-1.05 (type requis), mapping erreurs 409 (doublon) et 422 (violations)
- Composant `<CategoryDeleteModal>` : confirmation suppression (soft delete RG-1.12)
- Types TS `Category`, `CategoryType`, `User`
- i18n `admin.categories.*` ajouté dans `fr.json`
- Fix latent en passant : ajout de `'categories'` à `AdminLinkSlug` du Page Object e2e (oublié lors d'ERP-47 quand l'item sidebar a été ajouté)

## Décisions marquantes
- Logique `fetch` inline dans `categories.vue` (sera extraite en composables `useCategoriesAdmin` + `useCategoryForm` au ticket ERP-50 / 0.8)
- Drawer dans composant séparé pour réutilisabilité
- Aucun état de tableau persisté dans l'URL (règle ABSOLUE n°6)
- Tous les composants formulaires sont `Malio*` (`MalioDataTable`, `MalioInputText`, `MalioSelect`, `MalioButton`, `MalioDrawer`)

## Polish à venir (Tristan)
Tristan testera en navigateur et peaufinera : UX, classes Tailwind, animations, icônes, wording de toasts.
Les commits de polish suivront sur la même branche.

## Tests
- `npx nuxi typecheck` : net 0 nouvelle erreur (mêmes erreurs pré-existantes que sur `develop`, infrastructure auto-import) + 1 latente corrigée (AdminLinkSlug)
- `make nuxt-test` : 43/43 passent (0 régression)
- Tests manuels navigateur : voir cahier de test du ticket Lesstime #49

## Note pre-commit hook
Le hook a remonté un échec PHPUnit pré-existant sur `develop` (`CategoryDeleteTest::testPatchOnSoftDeletedReturns404` → 401 au lieu de 404, JWT non initialisé en test runner). Aucun PHP touché dans cette MR. Commit avec `--no-verify` autorisé par Tristan.

## Reviewer suggéré
Matthieu (back ↔ front + permissions).

---------

Co-authored-by: Matthieu <mtholot19@gmail.com>
Reviewed-on: #22
Co-authored-by: tristan <tristan@yuno.malio.fr>
Co-committed-by: tristan <tristan@yuno.malio.fr>
2026-05-29 08:59:47 +00:00
3 changed files with 7 additions and 5 deletions
+1 -1
View File
@@ -1,2 +1,2 @@
parameters:
app.version: '0.1.49'
app.version: '0.1.50'
@@ -7,7 +7,7 @@
@update:model-value="emit('update:modelValue', $event)"
>
<template #header>
<h2 class="text-[24px] font-bold">
<h2 class="text-2xl font-bold">
{{ headerLabel }}
</h2>
</template>
@@ -13,9 +13,11 @@
</template>
</PageHeader>
<!-- Table des categories : tri par defaut sur Nom ASC (RG-1.10).
Tri serveur applique a la requete + pagination front via
MalioDataTable (volumetrie cible <= 300, cf. spec § 4.1). -->
<!-- Table des categories. Affichage exhaustif (volumetrie cible
<= 300, cf. spec § 4.1) tri 100% serveur via CategoryProvider
(name ASC, RG-1.10). La barre de pagination du MalioDataTable
reste cosmetique tant qu'aucun slice client n'est cable : a
traiter cote @malio/layer-ui le jour ou la volumetrie monte. -->
<MalioDataTable
:columns="columns"
:items="categoryItems"