docs : add implementation plans for admin clients and time entry multi-type select

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Matthieu
2026-03-13 12:06:58 +01:00
parent bc9471e4ba
commit e5e722c019
2 changed files with 974 additions and 0 deletions

View File

@@ -0,0 +1,158 @@
# Time Entry Multi-Type Selection Implementation Plan
> **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Allow selecting multiple task types in the TimeEntryDrawer, matching the existing multi-select pattern used in TaskDrawer.
**Architecture:** Replace the single-select `MalioSelect` dropdown for types with the checkbox-based colored badge multi-select already used in TaskDrawer. The backend (ManyToMany relation) and DTO (`types: string[]`) already support multiple types — only the frontend form state and template need updating.
**Tech Stack:** Vue 3, TypeScript
---
## Chunk 1: Multi-Type Select in TimeEntryDrawer
### Task 1: Update TimeEntryDrawer to support multiple type selection
**Files:**
- Modify: `frontend/components/time-tracking/TimeEntryDrawer.vue`
- [ ] **Step 1: Change form state from single typeId to typeIds array**
In the `form` reactive object (line 133-142), replace:
```typescript
typeId: null as number | null,
```
with:
```typescript
typeIds: [] as number[],
```
- [ ] **Step 2: Add toggleType function**
Add this function after the `durationLabel` computed (after line 165):
```typescript
function toggleType(id: number) {
const idx = form.typeIds.indexOf(id)
if (idx >= 0) {
form.typeIds.splice(idx, 1)
} else {
form.typeIds.push(id)
}
}
```
- [ ] **Step 3: Remove the typeOptions computed**
Delete the `typeOptions` computed (lines 152-154):
```typescript
const typeOptions = computed(() =>
props.types.map(t => ({ label: t.label, value: t.id }))
)
```
This is no longer needed since we won't use `MalioSelect`.
- [ ] **Step 4: Replace MalioSelect template with multi-select badges**
Replace the `MalioSelect` for type (lines 75-81):
```vue
<MalioSelect
v-model="form.typeId"
:options="typeOptions"
label="Type"
empty-option-label=" Aucun "
min-width="w-full"
/>
```
with:
```vue
<div>
<p class="mb-2 text-sm font-semibold text-neutral-700">Types</p>
<div class="flex flex-wrap gap-2">
<label
v-for="type in types"
:key="type.id"
class="cursor-pointer rounded-full px-3 py-1 text-xs font-semibold transition"
:class="form.typeIds.includes(type.id)
? 'text-white'
: 'bg-neutral-100 text-neutral-600 hover:bg-neutral-200'"
:style="form.typeIds.includes(type.id) ? { backgroundColor: type.color } : {}"
>
<input
type="checkbox"
class="hidden"
:value="type.id"
:checked="form.typeIds.includes(type.id)"
@change="toggleType(type.id)"
/>
{{ type.label }}
</label>
</div>
</div>
```
- [ ] **Step 5: Update populateForm to use typeIds**
In the `populateForm` function, replace (line 194):
```typescript
form.typeId = entry.types?.[0]?.id ?? null
```
with:
```typescript
form.typeIds = entry.types?.map(t => t.id) ?? []
```
And in the else branch (line 203), replace:
```typescript
form.typeId = null
```
with:
```typescript
form.typeIds = []
```
- [ ] **Step 6: Update onSubmit payload to use typeIds**
In the `onSubmit` function, replace (line 233):
```typescript
types: form.typeId ? [`/api/task_types/${form.typeId}`] : [],
```
with:
```typescript
types: form.typeIds.map(id => `/api/task_types/${id}`),
```
- [ ] **Step 7: Verify in browser**
Run: `make dev-nuxt`
1. Open time tracking page
2. Open an existing time entry → verify existing types are pre-selected as colored badges
3. Toggle types on/off → verify visual feedback (colored background when selected)
4. Save → verify types are persisted correctly
5. Create a new time entry with multiple types → verify they save correctly
- [ ] **Step 8: Commit**
```bash
git add frontend/components/time-tracking/TimeEntryDrawer.vue
git commit -m "feat(frontend) : allow multiple type selection in time entry drawer"
```