74 lines
4.1 KiB
Markdown
74 lines
4.1 KiB
Markdown
# Dependency chain display — Design
|
|
|
|
**Date:** 2026-08-11
|
|
**Status:** approved, not implemented
|
|
|
|
## Problem
|
|
|
|
`DependsOnTaskId` is invisible in the UI. `TaskRowViewModel` has no `DependsOnTaskId` property
|
|
and `TaskRowView.axaml` renders nothing for it — a chained task looks exactly like an unrelated
|
|
one. The execution order the user declared is not readable anywhere in the list.
|
|
|
|
## Target
|
|
|
|
A chain renders as a group: the head full width, its dependents indented behind a vertical rail,
|
|
each carrying a small circular step badge on the rail.
|
|
|
|
```
|
|
┌──────────────────────────────────────────┐
|
|
│ chain head (full width, no badge) │
|
|
└──────────────────────────────────────────┘
|
|
╷ ┌────────────────────────────────────┐
|
|
(1)│ first dependent │
|
|
╷ └────────────────────────────────────┘
|
|
╷ ┌────────────────────────────────────┐
|
|
(2)│ second │
|
|
╷ └────────────────────────────────────┘
|
|
╷ ┌────────────────────────────────────┐
|
|
(2)│ parallel to the second │
|
|
╷ └────────────────────────────────────┘
|
|
╷ ┌────────────────────────────────────┐
|
|
(3)│ third │
|
|
└────────────────────────────────────┘
|
|
```
|
|
|
|
## Model reading
|
|
|
|
- **Step number = hop distance from the chain head**, not a running counter. `DependsOnTaskId` is
|
|
a single FK, so several tasks may share one predecessor → same depth → **same number**. Two
|
|
rows showing `2` means "these two are both unblocked by step 1", which is the intended reading.
|
|
- **Chain head** = a task with no `DependsOnTaskId` that at least one other task points at. A task
|
|
with no dependents and no dependency is not a chain and renders exactly as today.
|
|
- Cycles are impossible (`TaskStateService.SetDependsOnAsync` rejects them), so the depth walk
|
|
always terminates. Still cap the walk defensively.
|
|
|
|
## Decisions
|
|
|
|
**One indent level only — parent wins.** The 24 px indent track already exists for planning
|
|
children (`TaskRowView.axaml:22-28`, gated on `ShowAsChild`). A planning child that *also* has a
|
|
`DependsOnTaskId` keeps the parent indent and shows its chain membership as a small inline
|
|
chip (`after #123`) instead of a second indent level. No nesting, no 48 px rows.
|
|
|
|
**The group is pulled together; the head carries it.** Chain members are re-ordered to sit
|
|
directly under their head regardless of `SortOrder`, so displayed order always equals execution
|
|
order. Dragging the head moves the whole group; members are not individually draggable.
|
|
|
|
**Head not in view → no orphan rails.** Exact precedent exists: `ParentInView` /`ShowAsChild`
|
|
(`TaskRowViewModel.cs:75`, computed in `Regroup` at `TasksIslandViewModel.cs:543`). Same
|
|
treatment — if the head is filtered out (other list, My Day, completed group), the row renders
|
|
flat with the `after #123` chip instead of a dangling rail.
|
|
|
|
**Badge has no `#`.** If task numbers (`2026-08-11-task-numbers-design.md`) also land, a row
|
|
would show a rail badge and a `#412` title prefix. The rail badge is a step position, not an
|
|
identity — render it bare (`2`), never `#2`.
|
|
|
|
## Slices
|
|
|
|
| # | Slice | Depends on |
|
|
|---|---|---|
|
|
| 1 | VM: `DependsOnTaskId` + depth/head computation in `Regroup`, group pull-together, drag semantics | — |
|
|
| 2 | View: rail, step badge, `after …` chip, locale keys | 1 |
|
|
|
|
Slice 1 exposes the contract Slice 2 binds to: `ShowAsChainMember`, `ChainStep`,
|
|
`ChainAfterLabel`.
|