Tasks: UI Empty State & Submit Entry Point¶
Input: Design documents from specs/004-ui-empty-state-submit/
Prerequisites: plan.md ✅, spec.md ✅, research.md ✅
Files changed:
- ui/src/views/MySubmissionsView.vue — primary change
- ui/tests/unit/MySubmissionsView.spec.ts — new (Test-First per Principle II)
Note: No Setup or Foundational phases needed — all infrastructure, routes, stores, and definitions already exist. All tasks target a single existing view file plus one new test file.
Phase 1: User Story 1 — Submit CTA (Priority: P1) 🎯 MVP¶
Goal: A visible "Submit new document" button appears in the page header whenever the authenticated user is an initiator and at least one workflow definition is available. The button navigates directly to the submission form in one click.
Independent Test: Open the app as an initiator → see the CTA button in the "My Submissions"
header → click it → SubmitFlowView loads with the document-approval form.
Tests for User Story 1 (Principle II: write first, ensure RED before implementation)¶
- [X] T001 [US1] Create
ui/tests/unit/MySubmissionsView.spec.tswith vitest + @vue/test-utils boilerplate, mockinguseAuthStore,useFlows, and stubbing Onyx components - [X] T002 [US1] Write test: initiator user with N > 0 existing submissions →
OnyxButton[label="Submit new document"]rendered in header area (and noOnyxEmptyvisible) inui/tests/unit/MySubmissionsView.spec.ts - [X] T003 [US1] Write test: initiator user with N existing submissions → header CTA
OnyxButtonstill rendered (FR-002) inui/tests/unit/MySubmissionsView.spec.ts - [X] T004 [US1] Write test: non-initiator user → no
OnyxButtonCTA rendered at all (FR-006) inui/tests/unit/MySubmissionsView.spec.ts - [X] T004b [US1] Write test: user in both initiator and reviewer groups → header CTA
OnyxButtonstill rendered (spec edge case: dual-group membership does not suppress CTA) inui/tests/unit/MySubmissionsView.spec.ts - [X] T005 [US1] Write test: loading state active → header CTA
OnyxButtonstill visible (spec edge case) inui/tests/unit/MySubmissionsView.spec.ts
Implementation for User Story 1¶
- [X] T006 [US1] Add imports to
ui/src/views/MySubmissionsView.vue:useAuthStorefrom@/stores/auth,AVAILABLE_DEFINITIONSfrom@/api/definitions,OnyxButtonfromsit-onyx - [X] T007 [US1] Add computed values to
<script setup>inui/src/views/MySubmissionsView.vue:auth = useAuthStore(),firstDefinition = computed(() => AVAILABLE_DEFINITIONS[0]),canSubmit = computed(() => !!firstDefinition.value && auth.isInGroup(firstDefinition.value.initiatorGroup)) - [X] T008 [US1] Replace
<h1>My Submissions</h1>with a<header class="submissions-view__header">flex container containing the<h1>and a conditional<OnyxButton v-if="canSubmit" label="Submit new document" color="primary" :link="submitLink" />inui/src/views/MySubmissionsView.vue - [X] T009 [US1] Add
.submissions-view__headerCSS rule (display: flex; align-items: center; justify-content: space-between; margin-bottom: 1.5rem;) and remove the existingh1margin rule inui/src/views/MySubmissionsView.vue
Checkpoint: Run mise run ui:test — T001–T005 must now pass GREEN. The CTA is reachable in one click from "My Submissions".
Phase 2: User Story 2 — Welcoming Empty State (Priority: P2)¶
Goal: When the user has no submissions, a descriptive message explains the section's purpose and a secondary CTA guides them toward their first submission — not a bare "No submissions yet." dead end.
Independent Test: Log in as a first-time initiator with zero flows → "My Submissions"
shows OnyxEmpty with an explanatory message and a "Submit new document" button inside it.
Tests for User Story 2 (Principle II: write first, ensure RED before implementation)¶
- [X] T010 [US2] Write test: initiator with 0 submissions →
OnyxEmptyrendered with headline text containing "not submitted" and a secondaryOnyxButtoninui/tests/unit/MySubmissionsView.spec.ts - [X] T011 [US2] Write test: no definitions available →
OnyxEmptyrendered, noOnyxButton, description contains "no submission types" (FR-007) inui/tests/unit/MySubmissionsView.spec.ts - [X] T012 [US2] Write test: non-initiator with 0 submissions →
OnyxEmptyrendered, noOnyxButton, description contains "permission" inui/tests/unit/MySubmissionsView.spec.ts
Implementation for User Story 2¶
- [X] T013 [US2] Add
OnyxEmptyto the imports fromsit-onyxinui/src/views/MySubmissionsView.vue - [X] T014 [US2] Replace
<p v-else class="submissions-view__empty">No submissions yet.</p>with<OnyxEmpty v-else>block inui/src/views/MySubmissionsView.vue: default slot text "You have not submitted any documents for approval yet.",#descriptionslot with three conditional<span>branches (canSubmit / no definitions / no permission),#buttonsslot with conditionalOnyxButton(same props as header CTA, only whencanSubmit) - [X] T015 [US2] Remove the now-unused
.submissions-view__emptyCSS rule fromui/src/views/MySubmissionsView.vue
Checkpoint: Run mise run ui:test — T010–T012 must now pass GREEN. Empty state is informative and guides users.
Phase 3: Polish & Validation¶
Purpose: Full quality gate before push.
- [X] T016 Run
mise run ui:checkfrom repo root (lint + typecheck + all unit tests + production build) — must exit 0 - [ ] T017 [P] Verify visually: start
mise run ui:dev, open/submissionsas a mock initiator, confirm header CTA is visible and navigates to/submit/document-approval - [ ] T018 [P] Verify visually: with
submittedFlowsmocked as empty, confirmOnyxEmptyrenders with message and secondary CTA button
Dependencies & Execution Order¶
Phase Dependencies¶
- Phase 1 (US1): Start immediately — no prerequisites beyond the existing codebase
- Phase 2 (US2): Start after Phase 1 implementation is complete (same file; sequential edits are safer)
- Phase 3 (Polish): After both US phases complete
Within Each User Story¶
- Write ALL tests for the story first (RED)
- Implement until tests pass (GREEN)
- Run
mise run ui:testto confirm before moving to next phase
Parallel Opportunities¶
Within Phase 1 tests: T002–T005 can be written in parallel (all in the same file but independent test cases). Within Phase 2 tests: T010–T012 can be written in parallel. T017 and T018 (visual checks) can run in parallel.
Implementation Strategy¶
MVP (User Story 1 Only)¶
- Complete Phase 1 (T001–T009)
- Run
mise run ui:check - Validate: CTA visible in header, one-click navigation works
- US1 alone satisfies FR-001, FR-002, FR-003, FR-006
Full Feature¶
- Complete Phase 1 → Phase 2 → Phase 3
- All 6 FRs satisfied
mise run ui:checkexits 0 before push (Principle VI)
Notes¶
- All tasks are in
ui/— no backend, no Kotlin, no Gradle changes OnyxButtonwith:linkprop renders as a router-aware anchor — no@click+router.pushneededOnyxEmptyis not globally registered; must be imported fromsit-onyx- Constitution Principle II: tests written before implementation — they MUST fail (RED) before T006
- Constitution Principle VI:
mise run ui:checkmust pass beforegit push