Skip to content

Commit dedb5f2

Browse files
h4x0rclaude
andcommitted
feat(export): implement ExportButton component
Dropdown with Tasks as JSON, Tasks as CSV, optional Metrics as JSON. All 8 tests pass. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 657fbf2 commit dedb5f2

1 file changed

Lines changed: 41 additions & 4 deletions

File tree

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,46 @@
1-
// RED STUB
2-
import React from "react";
3-
import type { MetricsExport } from "../../lib/export";
1+
import React, { useState } from "react";
2+
import { useStore } from "../../store";
3+
import { exportTasksAsJson, exportTasksAsCsv, exportMetricsAsJson, triggerDownload, type MetricsExport } from "../../lib/export";
44

55
interface Props {
66
metrics?: MetricsExport;
77
}
88

9-
export const ExportButton: React.FC<Props> = () => null;
9+
export const ExportButton: React.FC<Props> = ({ metrics }) => {
10+
const [open, setOpen] = useState(false);
11+
const tasks = useStore((s) => Object.values(s.tasks));
12+
13+
const handleJson = () => {
14+
triggerDownload(exportTasksAsJson(tasks), `shepherd-tasks-${Date.now()}.json`, "application/json");
15+
setOpen(false);
16+
};
17+
const handleCsv = () => {
18+
triggerDownload(exportTasksAsCsv(tasks), `shepherd-tasks-${Date.now()}.csv`, "text/csv");
19+
setOpen(false);
20+
};
21+
const handleMetrics = () => {
22+
if (!metrics) return;
23+
triggerDownload(exportMetricsAsJson(metrics), `shepherd-metrics-${Date.now()}.json`, "application/json");
24+
setOpen(false);
25+
};
26+
27+
return (
28+
<div className="relative">
29+
<button
30+
onClick={() => setOpen((o) => !o)}
31+
className="text-sm px-3 py-1.5 bg-shepherd-surface border border-shepherd-border rounded text-shepherd-text hover:bg-shepherd-hover"
32+
>
33+
Export
34+
</button>
35+
{open && (
36+
<div className="absolute right-0 mt-1 w-44 bg-shepherd-surface border border-shepherd-border rounded shadow-lg z-10">
37+
<button onClick={handleJson} className="block w-full text-left px-3 py-2 text-sm hover:bg-shepherd-hover">Tasks as JSON</button>
38+
<button onClick={handleCsv} className="block w-full text-left px-3 py-2 text-sm hover:bg-shepherd-hover">Tasks as CSV</button>
39+
{metrics && (
40+
<button onClick={handleMetrics} className="block w-full text-left px-3 py-2 text-sm hover:bg-shepherd-hover">Metrics as JSON</button>
41+
)}
42+
</div>
43+
)}
44+
</div>
45+
);
46+
};

0 commit comments

Comments
 (0)