Skip to content

feat: CSV issue export from issues list and machine detail pages#1159

Open
timothyfroehlich wants to merge 14 commits intomainfrom
claude/modest-villani
Open

feat: CSV issue export from issues list and machine detail pages#1159
timothyfroehlich wants to merge 14 commits intomainfrom
claude/modest-villani

Conversation

@timothyfroehlich
Copy link
Copy Markdown
Owner

Summary

  • Add CSV export functionality for issues, accessible from two entry points:
    • Issues list page: exports issues matching current filter state (next to View Options button)
    • Machine detail page: exports all issues for that machine (in the issues expando header)
  • Server action generates CSV with 13 columns (Issue ID, Machine, Title, Description, Status, Severity, Priority, Frequency, Reporter, Assigned To, Created, Updated, Closed)
  • Description column uses first paragraph only, with formatting stripped
  • UTF-8 BOM for Excel compatibility, RFC 4180 compliant CSV
  • Loading spinner, empty state toast, error handling

Origin

Discord discussion (Eric E., Becca S., Neil Wilson, Tim) — 2026-03-16. Users wanted to identify which machines have the most issues and spot recurring problems for tournament bank decisions.

Test plan

  • Unit tests: CSV generation utility (6 tests)
  • Unit tests: First-paragraph ProseMirrorDoc extraction (9 tests)
  • 810/810 existing tests still pass
  • TypeScript strict mode clean
  • E2E: Click export on issues list, verify download triggers
  • E2E: Click export on machine detail page, verify download triggers

🤖 Generated with Claude Code

timothyfroehlich and others added 10 commits April 6, 2026 22:29
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Tests click the export-csv-button on the issues list page and machine
detail page, verifying a download event fires with the correct filename pattern.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 8, 2026 02:49
@vercel
Copy link
Copy Markdown

vercel bot commented Apr 8, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
pin-point Ready Ready Preview, Comment Apr 8, 2026 2:53pm

@supabase
Copy link
Copy Markdown

supabase bot commented Apr 8, 2026

Updates to Preview Branch (claude/modest-villani) ↗︎

Deployments Status Updated
Database Wed, 08 Apr 2026 14:52:42 UTC
Services Wed, 08 Apr 2026 14:52:42 UTC
APIs Wed, 08 Apr 2026 14:52:42 UTC

Tasks are run on every commit but only new migration files are pushed.
Close and reopen this PR if you want to apply changes from existing seed or migration files.

Tasks Status Updated
Configurations Wed, 08 Apr 2026 14:52:44 UTC
Migrations Wed, 08 Apr 2026 14:52:44 UTC
Seeding Wed, 08 Apr 2026 14:52:44 UTC
Edge Functions Wed, 08 Apr 2026 14:52:44 UTC

View logs for this Workflow Run ↗︎.
Learn more about Supabase for Git ↗︎.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds CSV export of issues from both the issues list (respecting current filters) and the machine detail page (machine-scoped), using a server action to generate an Excel-friendly CSV and a small client button to trigger downloads.

Changes:

  • Added CSV generation + first-paragraph extraction utilities with unit tests.
  • Added exportIssuesAction server action + Zod schemas to generate and return CSV/filename.
  • Added export UI entry points (issues list + machine detail expando) and Playwright smoke tests for downloads.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
src/lib/tiptap/first-paragraph.ts New utility to extract first-paragraph plain text from ProseMirror JSON for CSV Description.
src/lib/tiptap/first-paragraph.test.ts Unit tests for first-paragraph extraction behavior.
src/lib/export/csv.ts New RFC 4180-style CSV generator with BOM + CRLF endings.
src/lib/export/csv.test.ts Unit tests for quoting/escaping/BOM behavior.
src/components/issues/IssueList.tsx Adds export button to issues list toolbar.
src/components/issues/ExportButton.tsx Client “download CSV” button that calls the server action and triggers a Blob download.
src/app/(app)/m/[initials]/issues-expando.tsx Adds export button to the machine detail issues expando header.
src/app/(app)/issues/export-schema.ts Zod schemas for export inputs and permissive filter parsing.
src/app/(app)/issues/export-action.ts Server action to authenticate, query issues, format rows, and generate CSV + filename.
e2e/smoke/machine-details-redesign.spec.ts Smoke test that clicking export triggers a CSV download on machine detail.
e2e/smoke/issue-list.spec.ts Smoke test that clicking export triggers a CSV download on issues list.
docs/superpowers/specs/2026-04-06-csv-export-design.md Design spec documenting behavior, columns, and approach.
docs/superpowers/plans/2026-04-06-csv-export.md Implementation plan documenting steps and test strategy.

@timothyfroehlich
Copy link
Copy Markdown
Owner Author

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

🤖 Generated with Claude Code

- If this code review was useful, please react with 👍. Otherwise, react with 👎.

…hines, JSON validation

- Add CSV formula injection protection (prefix =, +, -, @ with single quote)
- Set includeInactiveMachines=true for machine-page exports so off-the-floor
  machines can still export their issues
- Return VALIDATION error on malformed filter JSON instead of silently
  falling back to "export all"

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated 3 comments.

The comment said "Recursively" but the function only iterates the
given node array without recursion.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@timothyfroehlich timothyfroehlich added the ready-for-review PR passed CI and has no unresolved review comments label Apr 8, 2026
# Conflicts:
#	src/app/(app)/m/[initials]/issues-expando.tsx
Copilot AI review requested due to automatic review settings April 8, 2026 14:52
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated 2 comments.

Comment on lines +26 to +43
export const exportFiltersSchema = z.object({
q: z.string().optional(),
status: z.array(z.enum(ISSUE_STATUS_VALUES)).optional(),
machine: z.array(z.string()).optional(),
severity: z
.array(z.enum(["cosmetic", "minor", "major", "unplayable"]))
.optional(),
priority: z.array(z.enum(["low", "medium", "high"])).optional(),
frequency: z
.array(z.enum(["intermittent", "frequent", "constant"]))
.optional(),
assignee: z.array(z.string()).optional(),
owner: z.array(z.string()).optional(),
reporter: z.array(z.string()).optional(),
watching: z.boolean().optional(),
includeInactiveMachines: z.boolean().optional(),
sort: z.string().optional(),
});
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

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

exportFiltersSchema doesn’t include the date-range fields (createdFrom, createdTo, updatedFrom, updatedTo) that are part of IssueFilters and are used by buildWhereConditions(). Since ExportButton serializes the current IssueFilters, any active date filters will be silently dropped during parsing and the export won’t match what the user is viewing. Add these fields to the schema (ideally with coercion from ISO strings and a permissive fallback so a single bad date doesn’t cause all filters to be ignored).

Copilot uses AI. Check for mistakes.
Comment on lines +159 to +166
// 6. Generate CSV
const csv = generateCsv(CSV_HEADERS, rows);
const dateStr = format(new Date(), "yyyy-MM-dd");
const fileName = machineInitials
? `pinpoint-${machineInitials.toUpperCase()}-issues-${dateStr}.csv`
: `pinpoint-issues-${dateStr}.csv`;

return ok({ csv, fileName });
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

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

The new export action currently has no integration/unit test that validates CSV headers/row formatting and that filters are applied correctly. The added Playwright checks only assert that a download starts, so regressions in column ordering, description extraction, or filter behavior (e.g., machineInitials export) won’t be caught. Please add at least one integration test around the export action’s query+CSV generation using the existing worker-scoped PGlite pattern.

Copilot generated this review using guidance from repository custom instructions.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-review PR passed CI and has no unresolved review comments

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants