(issue: IssueCardProps)
| 52 | |
| 53 | /** Render ONE Linear issue as a rich Block Kit card. */ |
| 54 | export function IssueCard(issue: IssueCardProps): ChannelNode { |
| 55 | const titleText = issue.url |
| 56 | ? `[**${issue.title}**](${issue.url})` |
| 57 | : `**${issue.title}**`; |
| 58 | |
| 59 | const prio = priorityGlyph(issue.priority); |
| 60 | |
| 61 | const description = issue.description |
| 62 | ? issue.description.length > 600 |
| 63 | ? `${issue.description.slice(0, 600)}…` |
| 64 | : issue.description |
| 65 | : undefined; |
| 66 | |
| 67 | const footer: string[] = []; |
| 68 | if (issue.labels?.length) footer.push(`🏷️ ${issue.labels.join(" ")}`); |
| 69 | if (issue.url) footer.push(`[Open in Linear →](${issue.url})`); |
| 70 | const footerText = footer.length ? footer.join(" · ") : undefined; |
| 71 | |
| 72 | return ( |
| 73 | <Message accent={accentForIssue(issue)}> |
| 74 | <Header> |
| 75 | {`${issue.justCreated ? "✅ " : `${stateGlyph(issue.state)} `}${issue.identifier}`} |
| 76 | </Header> |
| 77 | <Section>{titleText}</Section> |
| 78 | {issue.justCreated ? <Context>{"✨ Filed in Linear"}</Context> : null} |
| 79 | <Fields> |
| 80 | <Field>{`**Status**\n${stateGlyph(issue.state)} ${issue.state ?? "—"}`}</Field> |
| 81 | <Field>{`**Assignee**\n${issue.assignee ?? "_unassigned_"}`}</Field> |
| 82 | {issue.priority ? ( |
| 83 | <Field>{`**Priority**\n${prio ? `${prio} ` : ""}${issue.priority}`}</Field> |
| 84 | ) : null} |
| 85 | {issue.team ? <Field>{`**Team**\n${issue.team}`}</Field> : null} |
| 86 | {issue.cycle ? <Field>{`**Cycle**\n${issue.cycle}`}</Field> : null} |
| 87 | {issue.updated ? ( |
| 88 | <Field>{`**Updated**\n${issue.updated}`}</Field> |
| 89 | ) : null} |
| 90 | </Fields> |
| 91 | {description ? <Divider /> : null} |
| 92 | {description ? <Section>{description}</Section> : null} |
| 93 | {footerText ? <Context>{footerText}</Context> : null} |
| 94 | </Message> |
| 95 | ); |
| 96 | } |
no test coverage detected