Suite au retour utilisateur sur le plan « onglet Sources » livré
précédemment (#44-#48) : navigation transparente, page recette pour un
item externe, comportement d'ajout au planning déjà importé.
L'onglet « Sources » (RecipesPage) reste un onglet à part (décision
explicite : pas de fusion des listes perso/foyer/publique/externe) —
mais son affichage se comporte désormais « comme si c'était importé » :
- `SourceItemPreviewPanel` est supprimé, fusionné dans
`RecipeDetailPanel` lui-même (nouvel état `"loaded-draft"`) : un item
pas encore importé se voit exactement comme une vraie recette — même
en-tête, même mise en page description/étapes — la seule différence
étant les actions proposées (« Importer cette recette » là où une
vraie recette montre Modifier/Supprimer). La liste brute des
ingrédients et l'indice « non résolu » disparaissent de cette vue :
cette complexité reste réservée à l'écran de revue d'import
(ImportRecipePage), pas à un simple aperçu.
- Un item pas encore importé gagne une vraie URL adressable —
`/recettes/sources/:sourceKey/:externalId` (nouvelle route,
RecipesPage) — au même titre qu'une vraie recette a `/recettes/:id`.
Avant, le sélectionner ne changeait que de l'état React local dans
`RecipeSourcesPanel`, sans URL propre : ni lien direct, ni retour
arrière/rafraîchissement possibles. `RecipeSourcesPanel` gagne
`initialSelection`/`onItemSelected` pour rester piloté par cette URL
sans avoir à connaître le routage lui-même — `RecipePickerDialog`
(qui prévisualise dans une modale sans URL propre) laisse les deux
non renseignés et garde son comportement inchangé.
- `onSelectImportedRecipe` (déjà présent) continue de traiter un item
déjà importé exactement comme une vraie recette — c'est justement ce
qui rend la navigation transparente pour ce cas.
Le troisième point du retour (vérifier si la recette est déjà en base
avant de l'ajouter au planning, ne rien faire si oui, l'importer sinon)
était déjà le comportement de #48 — inchangé ici, aucune régression:
`RecipePickerDialog` résout un item déjà importé vers sa vraie recette
sans ré-import, et n'importe que les items qui ne le sont pas encore.
Aucun changement backend.
Tests :
- Cypress : nouvelle assertion d'URL dans le scénario « Previews a
not-yet-imported item » de recipe-sources.feature, et nouveau
scénario « Deep-links straight to a not-yet-imported item's own
page » — la CI confirmera.
- `pnpm --filter api test` — 282 tests toujours au vert (aucun
changement backend).
- `pnpm exec tsc -b --force` (web) — propre.
- `pnpm exec biome check` — propre.
- `pnpm -r build` — propre.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Dernière étape du plan « onglet Sources » : le sélecteur de recette du
planning (`RecipePickerDialog`) gagne l'onglet « Sources », jusqu'ici
volontairement exclu faute d'écran de revue à qui transmettre un item
choisi (voir étape 3, #47).
- Sélectionner un item déjà importé se comporte exactement comme
choisir cette même recette depuis un onglet normal (résolue via
`GET /recipes/:id`, direction vers l'étape « combien de portions ? »
du dialogue, sans navigation).
- Sélectionner un item pas encore importé bascule vers l'écran de
revue existant (`ImportRecipePage`), avec le créneau du planning
porté par la query string (`?planningDate=&planningWeekDay=&planningMeal=`).
Un import réussi y ajoute alors automatiquement la recette
fraîchement créée à ce créneau (`POST /planning/items`, avec les
portions du formulaire) avant de revenir sur le planning — plutôt que
d'atterrir sur la page de la recette comme le fait un import « classique ».
- `RecipeSourcesPanel`/`SourceItemPreviewPanel` généralisés en
conséquence : la première ne navigue plus elle-même vers la recette
déjà importée (`onSelectImportedRecipe` renvoie l'id, chaque appelant
décide), la seconde propage le créneau optionnel sur son lien
d'import.
Aucun changement backend : `POST /sources/:sourceKey/import/:externalId`
et `POST /planning/items` existaient déjà et suffisent tels quels — une
fois la recette importée, `GET /sources/:sourceKey/browse` la marque
déjà `alreadyImported` automatiquement (logique déjà couverte par
`sources.test.ts`). 282 tests API toujours au vert, aucune régression.
Tests :
- Cypress : nouveau scénario Gherkin bout-en-bout
(`cypress/e2e/planning.feature`/`planning.ts`) — ouvrir le
sélecteur depuis un créneau vide, parcourir Sources, importer un
item non résolu (ingrédient à compléter compris), vérifier que la
requête d'ajout au planning porte bien le bon créneau/les bonnes
portions, que la recette apparaît dans la bonne case de la grille
après le retour sur "/", puis que rebrowser la source la marque
désormais comme déjà importée.
Suite : plan « onglet Sources » terminé (étapes 1 à 4).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Deuxième étape du chantier "onglet Sources" : l'UI de parcours, construite
contre les endpoints backend de l'étape 1 (#45). L'onglet désactivé
placeholder de RecipeTabs devient un vrai onglet fonctionnel.
- RecipeTabs.tsx : nouveau type RecipesPageTab (RecipeTab | "sources") —
gardé hors du type partagé RecipeTab puisque l'API n'a pas de
tab=sources à valider. Un prop `tabs` optionnel restreint quels onglets
s'affichent — RecipePickerDialog (choix d'une recette pour un planning)
s'y restreint aux 4 onglets réels, parcourir des sources externes en
plein milieu de ce dialogue n'a pas de sens sans le flux de revue/import.
- Nouveau RecipeSourcesPanel.tsx : contenu de l'onglet "Sources" —
autonome (son propre master-detail), ne partage pas le fetching
RecipeTab de RecipesPage puisqu'il parcourt le catalogue *live* d'une
source (GET /sources/:key/browse), pas la table Recipe sauvegardée.
Sélecteur de source si le foyer en a activé plusieurs ; sélectionner un
item déjà importé navigue directement vers la vraie recette
(SourceItemTable + navigate), un item pas encore importé affiche un
aperçu en lecture seule (SourceItemPreviewPanel, réutilise
StepDescription — les tech steps sont donc déjà surlignés dans
l'aperçu).
- Bug trouvé et corrigé en écrivant le scénario Cypress : cliquer un item
déjà importé changeait l'URL mais restait affiché sur l'onglet Sources
(RecipesPage ne rend RecipeDetailPanel/RecipeTable qu'en dehors de
l'onglet "sources"). RecipeSourcesPanel prend maintenant un callback
`onViewImportedRecipe` pour repasser sur un onglet réel avant de
naviguer.
Tests : nouveau recipe-sources.feature (parcours utilisateur complet —
onglet vide, parcours avec items importés/non importés, aperçu avec
surlignage de technique) ; recipes.cy.ts corrigé (assertion obsolète sur
l'ancien placeholder désactivé). Étape suivante (3/4) : écran de revue
(corriger les ingrédients non résolus) + finalisation de l'import.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>