components/ideas/idea-timeline.tsx:
- Chronological merge of IdeaLog + ClaudeQuestion (sorted desc by created_at)
- Per-entry icon by log-type (DECISION/NOTE/GRILL_RESULT/PLAN_RESULT/
STATUS_CHANGE/JOB_EVENT) + question-status label
- MD3-tokens, vertical timeline rail (border-left + dots)
- Question entries show options + answer (border-left highlight)
- Metadata expansion via <details> for log entries
components/ideas/idea-pbi-link-card.tsx:
- PLANNED + pbi present: green status-done card with PBI link
- PLANNED + pbi removed (FK SetNull): blocked-color banner with
"Plan opnieuw beschikbaar maken" → relinkIdeaPlanAction
- Demo blocked on relink
components/ideas/download-md-button.tsx:
- Calls downloadIdeaMdAction → builds Blob + anchor + click()
- Filename: {idea.code}-{kind}.md
- Demo MAY use it (read-only)
components/ideas/idea-detail-layout.tsx:
- Replaces inline placeholders with extracted components
- Md tabs gain Download (.md) button + Edit button row
Tests: 546/546 still green.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
55 lines
1.4 KiB
TypeScript
55 lines
1.4 KiB
TypeScript
'use client'
|
|
|
|
// DownloadMdButton — download grill_md of plan_md als .md-bestand.
|
|
// Demo MAG downloaden (read-only). Server-action returnt md-string; client
|
|
// bouwt een Blob + anchor + click().
|
|
|
|
import { useTransition } from 'react'
|
|
import { Download } from 'lucide-react'
|
|
import { toast } from 'sonner'
|
|
|
|
import { Button } from '@/components/ui/button'
|
|
import { downloadIdeaMdAction } from '@/actions/ideas'
|
|
|
|
interface Props {
|
|
ideaId: string
|
|
kind: 'grill' | 'plan'
|
|
hasContent: boolean
|
|
}
|
|
|
|
export function DownloadMdButton({ ideaId, kind, hasContent }: Props) {
|
|
const [pending, startTransition] = useTransition()
|
|
|
|
function handleClick() {
|
|
startTransition(async () => {
|
|
const r = await downloadIdeaMdAction(ideaId, kind)
|
|
if ('error' in r) {
|
|
toast.error(r.error)
|
|
return
|
|
}
|
|
if (!r.data) return
|
|
const blob = new Blob([r.data.markdown], { type: 'text/markdown;charset=utf-8' })
|
|
const url = URL.createObjectURL(blob)
|
|
const a = document.createElement('a')
|
|
a.href = url
|
|
a.download = r.data.filename
|
|
document.body.appendChild(a)
|
|
a.click()
|
|
a.remove()
|
|
URL.revokeObjectURL(url)
|
|
})
|
|
}
|
|
|
|
return (
|
|
<Button
|
|
size="sm"
|
|
variant="ghost"
|
|
onClick={handleClick}
|
|
disabled={pending || !hasContent}
|
|
title={hasContent ? `Download ${kind}_md` : 'Geen content'}
|
|
>
|
|
<Download className="size-3.5 mr-1" />
|
|
.md
|
|
</Button>
|
|
)
|
|
}
|