Skip to content

feat(dashboard): implement Quick Actions card with navigation links#714

Merged
steilerDev merged 4 commits intobetafrom
feat/477-quick-actions
Mar 10, 2026
Merged

feat(dashboard): implement Quick Actions card with navigation links#714
steilerDev merged 4 commits intobetafrom
feat/477-quick-actions

Conversation

@steilerDev
Copy link
Owner

@steilerDev steilerDev commented Mar 10, 2026

Summary

  • QuickActionsCard: Prominent "New Work Item" button + grid of 5 quick navigation links (Work Items, Timeline, Budget, Invoices, Vendors)
  • All links use React Router Link with correct routes and aria-label attributes
  • Responsive grid layout, full dark mode support via design tokens

Fixes #477

Test plan

  • 8 unit tests (link hrefs, aria-labels, keyboard accessibility, no loading states)
  • CI quality gates pass

Co-Authored-By: Claude Opus 4.6 noreply@anthropic.com
Co-Authored-By: Claude frontend-developer (Haiku 4.5) noreply@anthropic.com
Co-Authored-By: Claude qa-integration-tester (Haiku 4.5) noreply@anthropic.com

claude added 4 commits March 10, 2026 06:24
8 tests covering all link hrefs, aria-labels, link count, and absence
of loading/error states for story #477.

Co-Authored-By: Claude qa-integration-tester (Sonnet 4.5) <noreply@anthropic.com>
Adds a new Quick Actions section to the project dashboard that provides
quick access to common application features. Includes a prominent "New Work Item"
button and quick navigation links to Work Items, Timeline, Budget, Invoices,
and Vendors. All elements are keyboard accessible with appropriate aria-labels.

Story #477 acceptance criteria:
- New Work Item button navigates to /project/work-items/new
- Quick links to all key sections (Work Items, Timeline, Budget, Invoices, Vendors)
- Visible on all viewports (desktop, tablet, mobile)
- Keyboard accessible with aria-label attributes
- Dark mode support with design tokens

Co-Authored-By: Claude frontend-developer (Haiku 4.5) <noreply@anthropic.com>
- Use transition tokens (--transition-button, --transition-button-border)
  instead of hardcoded 0.15s ease
- Use --color-bg-hover instead of --color-bg-tertiary for link hover
- Add prefers-reduced-motion guard to disable transitions
- Add min-height: 44px for touch target compliance
- Align aria-labels with visible text to avoid screen reader confusion

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude frontend-developer (Haiku 4.5) <noreply@anthropic.com>
Co-Authored-By: Claude qa-integration-tester (Haiku 4.5) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@steilerDev steilerDev changed the base branch from main to beta March 10, 2026 06:45
Copy link
Owner Author

@steilerDev steilerDev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[security-engineer]

Security review of PR #714 — Story #477 QuickActionsCard.

Verdict: No security findings. Safe to merge.

Checklist

  • No SQL/command/XSS injection vectors — zero dynamic content; all link targets are hardcoded string literals
  • Authentication/authorization — frontend-only component; no new API endpoints introduced; existing dashboard auth gate applies
  • No sensitive data in logs, errors, or client responses — component is stateless and props-free
  • User input — none; component accepts no props and renders no user-supplied data
  • No new dependencies
  • No hardcoded credentials or secrets
  • CORS configuration unaffected
  • Error responses — none; no data fetching in this component

Security Analysis

XSS / Link injection: All six Link to="..." targets are hardcoded string literals (/project/work-items/new, /project/work-items, /schedule, /budget/overview, /budget/invoices, /budget/vendors). No user-controlled input flows into any to prop or rendered text. React Router's Link component generates internal anchor hrefs via the router — no javascript: URI risk. No dangerouslySetInnerHTML, innerHTML, or eval usage anywhere in the component.

Open redirect: Not applicable — React Router Link with a path-only string routes internally; no external URL construction.

DashboardPage integration: The card.id === 'quick-actions' branch unconditionally renders QuickActionsCard with no props — no data-dependent rendering path. The emptyAction.href informational finding from PR #709 is not triggered here (no emptyAction prop is passed for this card).

CSS: Pure CSS Modules, no dynamic class construction from user data.

Copy link
Owner Author

@steilerDev steilerDev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[product-architect] Reviewed -- no issues found. Would approve if not own PR.

Architecture compliance: Component follows established patterns — CSS Modules, design tokens, React Router Link, named export with default re-export. File naming (PascalCase for React components) and directory structure are correct.

Route correctness: All 6 routes verified against App.tsx:

  • /project/work-items/new (line 107)
  • /project/work-items (line 106)
  • /schedule (line 135)
  • /budget/overview, /budget/invoices, /budget/vendors (budget route group, line 119+)

Design token usage: CSS uses only design tokens (--color-primary, --color-primary-hover, --color-primary-text, --color-bg-secondary, --color-bg-tertiary, --color-border, --color-text-primary, --spacing-*, --radius-md, --font-size-sm, --font-weight-medium, --shadow-focus). No hardcoded colors or spacing values.

Integration: DashboardPage integration is minimal and correct — quick-actions card has no data dependency (no loading/error state needed), consistent with the card config at line 72 having no dataSource property.

Test coverage: 8 tests covering all links, route correctness, keyboard accessibility (link count assertion), and absence of loading/error states. Adequate for a static navigation component.

No schema or API contract changes needed (frontend-only).

Copy link
Owner Author

@steilerDev steilerDev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[product-owner] PR #714 reviewed — APPROVED (submitted as comment due to same-account constraint)

Acceptance Criteria Verification

AC Criterion Verdict
1 "New Work Item" button navigates to /work-items/new PASSLink to="/project/work-items/new" uses the correct actual route (AC text says /work-items/new but the real app route includes the /project prefix).
2 Quick links to Work Items, Timeline, Budget Overview, Invoices, Vendors PASS — All 5 links present: /project/work-items, /schedule, /budget/overview, /budget/invoices, /budget/vendors.
3 Visible on all viewports without being hidden or collapsed PASS — CSS uses flex + CSS Grid auto-fill with no media queries hiding content. Grid reflows naturally on smaller viewports.
4 Keyboard accessible with appropriate aria-label attributes PASS — All 5 quick links have aria-label. Primary action uses descriptive link text ("New Work Item") which serves as its accessible name. :focus-visible styles defined on both .primaryAction and .quickLink.
5 Dark mode with appropriate color tokens PASS — All colors use semantic CSS custom properties (--color-primary, --color-bg-secondary, --color-border, etc.). No hardcoded color values.

Additional Checks

  • Scope: Clean — only QuickActionsCard component, CSS module, tests, and DashboardPage integration. No scope creep.
  • Security review: Present (COMMENTED, no findings).
  • UX review: Present (APPROVED).
  • Test authorship: Tests co-authored by qa-integration-tester (Haiku 4.5) — correct per CLAUDE.md.
  • Test coverage: 8 unit tests covering all links, hrefs, aria-labels, and rendering behavior.

All 5 acceptance criteria pass. CI checks are still running at time of review — merge after CI is green.

Copy link
Owner Author

@steilerDev steilerDev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[ux-designer]

PR #714 — QuickActionsCard design review.

Summary

The component is structurally clean: all color tokens are correct semantic Layer 2 references, box-shadow: var(--shadow-focus) is applied consistently on both interactive elements, and the grid layout is appropriate. However, there are two medium-severity token adherence issues and two low-severity gaps that need to be addressed before merge.


Findings

Medium — Hardcoded transition durations (lines 19, 50–52)

.primaryAction and .quickLink both use hardcoded 0.15s ease instead of transition tokens.

Line 19 (.primaryAction):

/* current */
transition: background-color 0.15s ease;

/* correct — use composite token */
transition: var(--transition-button);

Lines 50–52 (.quickLink):

/* current */
transition:
  border-color 0.15s ease,
  background-color 0.15s ease;

/* correct — the composite token exists for exactly this case */
transition: var(--transition-button-border);

--transition-button-border is defined in tokens.css as background-color var(--transition-normal), border-color var(--transition-normal), which matches the intent here precisely.


Medium — Wrong semantic token for hover background (line 58)

.quickLink:hover sets background-color: var(--color-bg-tertiary).

The Style Guide documents --color-bg-tertiary as "Code blocks, inset regions" — it is not the hover background. The correct token is --color-bg-hover.

/* current */
.quickLink:hover {
  border-color: var(--color-primary);
  background-color: var(--color-bg-tertiary);
}

/* correct */
.quickLink:hover {
  border-color: var(--color-primary);
  background-color: var(--color-bg-hover);
}

In dark mode: --color-bg-tertiary resolves to #1e293b (slate-600) while --color-bg-hover resolves to the same #1e293b (also slate-600 in the current token file). However, in light mode they differ: --color-bg-tertiary is #f3f4f6 (gray-100) and --color-bg-hover is #f9fafb (gray-50). Using the semantic token with the correct purpose is required regardless of whether the visual difference is visible in one mode.


Low — No prefers-reduced-motion guard

Both transitions are unconditional. Add a reduced-motion guard:

@media (prefers-reduced-motion: reduce) {
  .primaryAction,
  .quickLink {
    transition: none;
  }
}

This is a recurring pattern gap noted in PR #380 and PR #413 reviews. Every CSS module with transitions must include this guard.


Low — Missing mobile touch targets

Neither .primaryAction nor .quickLink enforces the 44px minimum touch target on mobile. The Style Guide requires a min-height: 44px guard at the mobile/tablet breakpoint:

@media (max-width: 768px) {
  .primaryAction,
  .quickLink {
    min-height: 44px;
  }
}

Informational — aria-label / visible text mismatch on quick links

The quick links carry aria-label values that diverge from visible text:

  • Visible: "Work Items" → aria-label: "View work items"
  • Visible: "Timeline" → aria-label: "View timeline"
  • etc.

For <a> elements, the visible text content is already the accessible name. Adding a divergent aria-label overrides it, which can cause confusion when a screen reader reads "View work items" but the sighted label says "Work Items". The recommended fix is one of:

  • Remove the aria-label attributes and let visible text serve as the accessible name (simplest), or
  • Make aria-label and visible text identical if additional context is genuinely needed.

What passes

  • All color tokens: --color-primary, --color-primary-text, --color-primary-hover, --color-bg-secondary, --color-border, --color-text-primary — all correct Layer 2 semantic tokens.
  • Focus visible: outline: none; box-shadow: var(--shadow-focus) — correct pattern on both interactive elements. No outline: regression.
  • No hardcoded hex values anywhere in the CSS module.
  • No dark mode component-level overrides needed — all colors are semantic and switch automatically.
  • Grid layout with auto-fill minmax(120px, 1fr) is appropriate for the card context.

@steilerDev steilerDev enabled auto-merge (squash) March 10, 2026 06:49
@steilerDev steilerDev merged commit f70763c into beta Mar 10, 2026
13 checks passed
@github-actions
Copy link
Contributor

🎉 This PR is included in version 1.15.0-beta.7 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants