|
|
|
|
@@ -0,0 +1,182 @@
|
|
|
|
|
# Specs — Correctifs UI suite au système de workflow + UX mail/modales
|
|
|
|
|
|
|
|
|
|
> Date : 2026-05-20
|
|
|
|
|
> Contexte : suite à l'introduction des **workflows** (`docs/superpowers/specs/2026-05-19-project-workflows-design.md`),
|
|
|
|
|
> plusieurs régressions UI et points UX sont apparus. Reviews faites par Lucile Schnödt et Tristan Schnödtin.
|
|
|
|
|
> Ce document liste les 7 chantiers à traiter, avec problème, fichiers concernés, solution validée et points ouverts.
|
|
|
|
|
|
|
|
|
|
## Vue d'ensemble
|
|
|
|
|
|
|
|
|
|
| # | Chantier | Type | Décision |
|
|
|
|
|
|---|----------|------|----------|
|
|
|
|
|
| 1 | Drag & drop cassé dans « mes tâches » | régression workflow | Drop = changer de statut (gérer ambiguïté multi-statuts) |
|
|
|
|
|
| 2 | Sélecteur de statut mélange les workflows | régression workflow | Filtrer par le workflow du projet de la tâche |
|
|
|
|
|
| 3 | Cartes de tâche non responsive (tags) | UI | Refonte responsive + troncature |
|
|
|
|
|
| 4 | Couleurs de statut du workflow de base | data/UI | Remettre la palette classique |
|
|
|
|
|
| 5 | Bouton « lier un mail » dans l'onglet mail d'un ticket | UX mail | Supprimer le bouton |
|
|
|
|
|
| 6 | Création de ticket depuis un mail | UX mail | + sélecteur user, + sélecteur statut (remplace priorité), modale agrandie |
|
|
|
|
|
| 7 | Footer collant des modales centrées | UX global | Composant modale réutilisable (header / body scrollable / footer sticky) |
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## 1. Drag & drop cassé dans « mes tâches »
|
|
|
|
|
|
|
|
|
|
**Problème.** Le drag & drop des cartes entre colonnes ne fonctionne plus depuis l'arrivée des workflows.
|
|
|
|
|
|
|
|
|
|
**Fichiers.**
|
|
|
|
|
- `frontend/pages/my-tasks.vue` — colonnes kanban construites sur les **catégories canoniques** fixes (`CATEGORIES = ['todo','in_progress','blocked','review','done']`, ~l.118-127), template kanban ~l.396-424.
|
|
|
|
|
- `frontend/components/task/TaskCard.vue` — `@dragstart` / `@dragend` HTML5 natif (~l.154-162), `dataTransfer` = `task.id`.
|
|
|
|
|
- Pas de librairie externe (HTML5 natif).
|
|
|
|
|
|
|
|
|
|
**Cause racine.** Les colonnes sont des **catégories canoniques** (la vue agrège plusieurs projets/workflows, donc on ne peut pas afficher une colonne par statut d'un workflow précis). Or un workflow peut désormais mapper **plusieurs statuts sur une même catégorie** (ex. deux statuts « in_progress »). Au drop dans une colonne, le statut cible devient ambigu — ce qui a cassé / rendu indéterminé le changement de statut.
|
|
|
|
|
|
|
|
|
|
**Solution retenue.** Drop dans une colonne ⇒ change le statut de la tâche vers un statut de cette catégorie **dans le workflow du projet de la tâche**. Gestion de l'ambiguïté :
|
|
|
|
|
- Récupérer les statuts du workflow du projet de la tâche déposée, filtrés par la catégorie de la colonne cible.
|
|
|
|
|
- **0 statut** dans cette catégorie pour ce workflow → drop refusé (feedback visuel, pas de changement).
|
|
|
|
|
- **1 statut** → appliquer directement.
|
|
|
|
|
- **≥ 2 statuts** → afficher un mini-sélecteur (popover/menu) au point de drop pour choisir le statut exact.
|
|
|
|
|
|
|
|
|
|
**Points ouverts.**
|
|
|
|
|
- ⚠️ **À trancher demain** : confirmer la stratégie de désambiguïsation (popover au drop vs. choisir le statut de plus petite `position` dans la catégorie). Le popover est plus sûr mais plus de travail ; le « plus petite position » est transparent mais peut surprendre.
|
|
|
|
|
- Ajouter les **handlers de drop** sur les colonnes (`@dragover.prevent`, `@drop`) — actuellement absents dans `my-tasks.vue`.
|
|
|
|
|
- Comme la vue est multi-projets, la résolution du statut cible doit se faire **par tâche** (selon son projet → son workflow), pas globalement.
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## 2. Sélecteur de statut mélange les statuts de tous les workflows
|
|
|
|
|
|
|
|
|
|
**Problème.** En ouvrant une tâche (modale), le sélecteur « Statut » liste **tous les statuts globaux**, donc ceux du workflow de base **et** ceux des autres workflows.
|
|
|
|
|
|
|
|
|
|
**Fichiers.**
|
|
|
|
|
- `frontend/components/task/TaskModal.vue` — `<MalioSelect v-model="form.statusId" :options="statusOptions" />` (~l.103-109) ; `statusOptions = props.statuses.map(...)` (~l.674-676).
|
|
|
|
|
- `frontend/pages/my-tasks.vue` — `:statuses="statuses"` (~l.489), chargés via `statusService.getAll()` (~l.132).
|
|
|
|
|
- `frontend/services/task-statuses.ts` — `getAll()` → `GET /task_statuses` (tous les statuts).
|
|
|
|
|
- DTO : `frontend/services/dto/task-status.ts` — le champ `workflow` existe déjà (`{ '@id', id } | string`).
|
|
|
|
|
|
|
|
|
|
**Solution retenue.** Le sélecteur ne doit proposer que les statuts du **workflow du projet de la tâche éditée**.
|
|
|
|
|
- Filtrer `statusOptions` sur `status.workflow` correspondant au workflow du projet de la tâche.
|
|
|
|
|
- Source du filtre : soit filtrer côté front la liste déjà chargée par `workflow.id`, soit charger les statuts du workflow via le service workflow (`useWorkflowService()` existe mais n'est pas utilisé ici).
|
|
|
|
|
- S'assurer que le statut courant de la tâche reste affiché même si édge case (ex. statut hérité d'un ancien workflow).
|
|
|
|
|
|
|
|
|
|
**Points ouverts.**
|
|
|
|
|
- Vérifier que la tâche/le projet expose bien l'`@id`/`id` du workflow côté payload pour faire le filtre sans appel supplémentaire.
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## 3. Cartes de tâche non responsive (tags mal placés / trop gros)
|
|
|
|
|
|
|
|
|
|
**Problème.** Depuis l'ajout d'éléments dans la carte (statut, priorité, effort, tags, deadline, avatars…), les tags débordent ou se chevauchent quand les textes sont longs ; la carte n'est plus responsive.
|
|
|
|
|
|
|
|
|
|
**Fichiers.**
|
|
|
|
|
- `frontend/components/task/TaskCard.vue` — badges statut (~l.43-49) et tags (~l.58-64) : `rounded-full px-2 py-0.5 text-xs font-semibold text-white`, **sans `truncate`, sans `max-w`, sans `line-clamp`** ; conteneur `flex` sans contrainte de largeur (~l.42-106).
|
|
|
|
|
|
|
|
|
|
**Solution retenue.** Refonte du layout de la carte pour rester contenue quelle que soit la longueur des textes :
|
|
|
|
|
- Conteneur des badges en `flex flex-wrap gap-1` (retour à la ligne propre).
|
|
|
|
|
- Tags : `max-w-[...] truncate` (ou `line-clamp-1`) + `title`/tooltip pour le texte complet au survol.
|
|
|
|
|
- Hiérarchiser l'info : titre prioritaire (`line-clamp-2`), badges secondaires qui passent à la ligne ou se condensent.
|
|
|
|
|
- Option : limiter le nombre de tags affichés (ex. 2-3 + « +N »).
|
|
|
|
|
|
|
|
|
|
**Points ouverts.**
|
|
|
|
|
- ⚠️ Choix d'UX à valider : `flex-wrap` (tous les tags visibles, carte plus haute) vs. troncature « +N » (hauteur fixe). Décision visuelle à prendre demain (éventuellement via mockup).
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## 4. Couleurs de statut du workflow de base à remettre
|
|
|
|
|
|
|
|
|
|
**Problème.** Les couleurs « classiques » des statuts du workflow de base ont changé ; il faut remettre les couleurs d'origine.
|
|
|
|
|
|
|
|
|
|
**Investigation faite.** Le commit `4775cbf` (palette élargie 9→18 teintes + couleur perso) ne touche **que** `ColorPicker.vue` et `ProjectDrawer.vue` — il n'a pas modifié les couleurs des statuts. Les couleurs d'origine du **workflow Standard** sont dans les fixtures :
|
|
|
|
|
|
|
|
|
|
| Catégorie | Statut | Hex classique |
|
|
|
|
|
|---|---|---|
|
|
|
|
|
| todo | À faire | `#222783` |
|
|
|
|
|
| in_progress | En cours | `#4A90D9` |
|
|
|
|
|
| blocked | Bloqué | `#C62828` |
|
|
|
|
|
| review | En attente de validation | `#FF8F00` |
|
|
|
|
|
| done | Terminé | `#26A69A` |
|
|
|
|
|
|
|
|
|
|
Source : `src/DataFixtures/AppFixtures.php:101-105` (statuts rattachés au `$standardWorkflow`, ~l.93-116).
|
|
|
|
|
Migration de rattachement : `migrations/Version20260519175114.php` (attache les statuts existants au workflow Standard).
|
|
|
|
|
|
|
|
|
|
**Solution retenue.** Remettre ces 5 couleurs sur les statuts du **workflow Standard/de base**.
|
|
|
|
|
- Vérifier en prod (et en base de dev si dérive) que les statuts du workflow Standard portent bien ces hex ; corriger ceux qui ont dérivé (via l'UI d'admin des statuts, ou un script/migration de correction des couleurs).
|
|
|
|
|
- Ne **pas** toucher aux couleurs des statuts des autres workflows.
|
|
|
|
|
|
|
|
|
|
**Points ouverts.**
|
|
|
|
|
- Confirmer où la dérive a eu lieu (prod vs. nouveaux workflows créés via l'UI avec d'autres couleurs). Si c'est un workflow Standard en prod avec des couleurs erronées → correction data ; si c'est par défaut à la création d'un workflow → ajuster les couleurs proposées par défaut.
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## 5. Supprimer le bouton « lier un mail » dans l'onglet mail d'un ticket
|
|
|
|
|
|
|
|
|
|
**Problème.** En ouvrant un ticket, l'onglet mail propose un bouton « lier un mail » qui n'a pas d'utilité de ce côté.
|
|
|
|
|
|
|
|
|
|
**Fichiers.**
|
|
|
|
|
- `frontend/components/task/TaskModal.vue` — bouton « lier un mail » (~l.486-494, `mail.taskTab.linkButton`, ouvre `showMailPickerModal`) ; `<MailPickerModal>` (~l.498-503), visible si `isEditing && isMailUser`, onglet `mails`.
|
|
|
|
|
- Composant lié : `frontend/components/mail/MailPickerModal.vue`.
|
|
|
|
|
|
|
|
|
|
**Solution retenue.** Supprimer le bouton « lier un mail » de l'onglet mail du ticket.
|
|
|
|
|
- Retirer le bouton et, si plus aucun usage, le `MailPickerModal` associé + l'état `showMailPickerModal` + `handleMailLinked`.
|
|
|
|
|
- Nettoyer la clé i18n `mail.taskTab.linkButton` si elle n'est plus utilisée ailleurs.
|
|
|
|
|
|
|
|
|
|
**Points ouverts.**
|
|
|
|
|
- Vérifier que `MailPickerModal` n'est pas réutilisé ailleurs avant de le supprimer (sinon ne retirer que le bouton).
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## 6. Création d'un ticket depuis un mail
|
|
|
|
|
|
|
|
|
|
**Problème.** Le formulaire de création depuis un mail est incomplet et la modale dépasse de l'écran.
|
|
|
|
|
|
|
|
|
|
**Fichiers.**
|
|
|
|
|
- `frontend/components/mail/MailCreateTaskModal.vue` — champs actuels (~l.119-224) : info source (lecture seule), Projet (requis), Groupe (optionnel), **Priorité** (optionnelle). Footer non sticky (~l.210-224).
|
|
|
|
|
- `frontend/services/mail.ts` — `createTaskFromMail()` (~l.184-192) → `POST /mail/messages/{id}/create-task` avec `{ projectId, taskGroupId, priority }`.
|
|
|
|
|
|
|
|
|
|
**Solution retenue.**
|
|
|
|
|
1. **Sélecteur de user (assigné).** Ajouter un sélecteur d'utilisateur. Un user par défaut est déjà appliqué ; le sélecteur permet d'en choisir un autre. (Charger la liste via le service users.)
|
|
|
|
|
2. **Statut à la place de la priorité.** **Retirer** le sélecteur de priorité, le **remplacer** par un sélecteur de statut. Le statut proposé doit respecter le workflow du projet sélectionné (cf. chantier #2 — réutiliser la même logique de filtrage par workflow). Au changement de projet, recharger les statuts du workflow correspondant.
|
|
|
|
|
3. **Agrandir la modale.** Élargir la largeur (et gérer la hauteur via body scrollable + footer sticky, cf. chantier #7) pour qu'elle ne dépasse plus.
|
|
|
|
|
4. **Backend.** Adapter le payload / l'endpoint `create-task` : accepter `assigneeId` (ou IRI user) et `statusId` (ou IRI statut) ; retirer/garder `priority` selon décision (ici : remplacé par statut côté UI — décider si on garde la priorité par défaut côté backend ou non).
|
|
|
|
|
|
|
|
|
|
**Points ouverts.**
|
|
|
|
|
- Confirmer le statut **par défaut** présélectionné (statut initial du workflow du projet).
|
|
|
|
|
- Décider si la priorité disparaît totalement du payload ou reste à une valeur par défaut côté backend.
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## 7. Footer collant pour les modales centrées
|
|
|
|
|
|
|
|
|
|
**Problème.** Les modales qui s'ouvrent au milieu de l'écran ont leurs boutons d'action en bas, qui défilent avec le contenu et finissent hors écran. On veut un footer **toujours visible**.
|
|
|
|
|
|
|
|
|
|
**Constat.** Il n'existe **aucun composant modale réutilisable** (`MalioModal`/`AppModal`). Chaque modale réimplémente `Teleport` + `Transition` + header/body/footer. Footers actuels en `border-t` mais **non sticky** :
|
|
|
|
|
- `frontend/components/task/TaskModal.vue` (footer ~l.507-549)
|
|
|
|
|
- `frontend/components/mail/MailCreateTaskModal.vue` (~l.210-224)
|
|
|
|
|
- `frontend/components/mail/MailLinkTaskModal.vue` (~l.226-239)
|
|
|
|
|
- `frontend/components/mail/MailPickerModal.vue` (~l.187-201)
|
|
|
|
|
- `frontend/components/ui/ConfirmDeleteTaskModal.vue` (~l.11-24)
|
|
|
|
|
- `frontend/components/project/ProjectWorkflowSwitchModal.vue` (~l.63-76)
|
|
|
|
|
|
|
|
|
|
**Solution retenue (décision : composant réutilisable).** Créer un composant modale réutilisable dans `frontend/components/ui/` (ex. `AppModal.vue` / `MalioModal.vue` local) :
|
|
|
|
|
- Structure : `Teleport to="body"` + `Transition`, overlay `fixed inset-0`, conteneur avec **hauteur max** (`max-h-[90vh]`), en flex-col :
|
|
|
|
|
- **header** (titre + fermeture) fixe en haut,
|
|
|
|
|
- **body** `flex-1 overflow-y-auto`,
|
|
|
|
|
- **footer** sticky en bas (`shrink-0 border-t`), via slot `#footer`.
|
|
|
|
|
- Props : largeur (`sm`/`md`/`lg`/`xl`), titre, `v-model` ouverture ; slots `default` (body) et `footer`.
|
|
|
|
|
- **Migration progressive** des modales existantes vers ce composant (commencer par celles citées par les reviews : TaskModal, MailCreateTaskModal). Ne pas tout migrer d'un coup.
|
|
|
|
|
|
|
|
|
|
**Points ouverts.**
|
|
|
|
|
- Nom et emplacement définitifs du composant.
|
|
|
|
|
- Ordre de migration (au minimum : MailCreateTaskModal #6 et TaskModal #2/#5, qui sont déjà touchées par les autres chantiers).
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## Découpage suggéré pour l'implémentation
|
|
|
|
|
|
|
|
|
|
Regrouper par zone pour limiter les conflits :
|
|
|
|
|
|
|
|
|
|
- **Lot A — Workflow / statuts** : #2 (filtrage statut) → réutilisé par #1 (D&D) et #6 (statut à la création mail).
|
|
|
|
|
- **Lot B — Cartes** : #3 (responsive) + #4 (couleurs classiques).
|
|
|
|
|
- **Lot C — Mail** : #5 (suppr. bouton) + #6 (form création) — dépend de #2 et #7.
|
|
|
|
|
- **Lot D — Modale réutilisable** : #7 (composant) puis migration de TaskModal et MailCreateTaskModal.
|
|
|
|
|
|
|
|
|
|
Ordre conseillé : **#7 (composant modale)** et **#2 (filtrage statut)** d'abord (briques réutilisées), puis #1, #6, #5, puis #3/#4.
|