mirror of
https://github.com/alkimake/paperclip.git
synced 2026-06-14 01:50:39 +09:00
Move sub-issues inline and remove sub-issues tab
- When no sub-issues exist, show "Add sub-issue" button alongside "Upload attachment" and "New document" in the action row - When sub-issues exist, show them in a dedicated section above Documents with "Sub-issues" header and "Add sub-issue" button - Remove the sub-issues tab from the comments/activity tabs Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
parent
1b55474a9b
commit
c414790404
1 changed files with 56 additions and 48 deletions
|
|
@ -1487,6 +1487,50 @@ export function IssueDetail() {
|
|||
missingBehavior="placeholder"
|
||||
/>
|
||||
|
||||
{childIssues.length > 0 && (
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<h3 className="text-sm font-medium text-muted-foreground">Sub-issues</h3>
|
||||
<Button variant="outline" size="sm" onClick={openNewSubIssue} className="shadow-none">
|
||||
<ListTree className="h-3.5 w-3.5 mr-1.5" />
|
||||
<span className="hidden sm:inline">Add sub-issue</span>
|
||||
<span className="sm:hidden">Sub-issue</span>
|
||||
</Button>
|
||||
</div>
|
||||
<div className="border border-border rounded-lg divide-y divide-border">
|
||||
{childIssues.map((child) => (
|
||||
<Link
|
||||
key={child.id}
|
||||
to={createIssueDetailPath(child.identifier ?? child.id)}
|
||||
state={resolvedIssueDetailState ?? location.state}
|
||||
onClickCapture={() =>
|
||||
rememberIssueDetailLocationState(
|
||||
child.identifier ?? child.id,
|
||||
resolvedIssueDetailState ?? location.state,
|
||||
location.search,
|
||||
)}
|
||||
className="flex items-center justify-between px-3 py-2 text-sm hover:bg-accent/20 transition-colors"
|
||||
>
|
||||
<div className="flex items-center gap-2 min-w-0">
|
||||
<StatusIcon status={child.status} />
|
||||
<PriorityIcon priority={child.priority} />
|
||||
<span className="font-mono text-muted-foreground shrink-0">
|
||||
{child.identifier ?? child.id.slice(0, 8)}
|
||||
</span>
|
||||
<span className="truncate">{child.title}</span>
|
||||
</div>
|
||||
{child.assigneeAgentId && (() => {
|
||||
const name = agentMap.get(child.assigneeAgentId)?.name;
|
||||
return name
|
||||
? <Identity name={name} size="sm" />
|
||||
: <span className="text-muted-foreground font-mono">{child.assigneeAgentId.slice(0, 8)}</span>;
|
||||
})()}
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<IssueDocumentsSection
|
||||
issue={issue}
|
||||
canDeleteDocuments={Boolean(session?.user?.id)}
|
||||
|
|
@ -1508,7 +1552,18 @@ export function IssueDetail() {
|
|||
sharingPreferenceAtSubmit: feedbackDataSharingPreference,
|
||||
});
|
||||
}}
|
||||
extraActions={!hasAttachments ? attachmentUploadButton : undefined}
|
||||
extraActions={
|
||||
<>
|
||||
{!hasAttachments && attachmentUploadButton}
|
||||
{childIssues.length === 0 && (
|
||||
<Button variant="outline" size="sm" onClick={openNewSubIssue} className="shadow-none">
|
||||
<ListTree className="h-3.5 w-3.5 mr-1.5" />
|
||||
<span className="hidden sm:inline">Add sub-issue</span>
|
||||
<span className="sm:hidden">Sub-issue</span>
|
||||
</Button>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
/>
|
||||
|
||||
{hasAttachments ? (
|
||||
|
|
@ -1662,10 +1717,6 @@ export function IssueDetail() {
|
|||
<MessageSquare className="h-3.5 w-3.5" />
|
||||
Comments
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="subissues" className="gap-1.5">
|
||||
<ListTree className="h-3.5 w-3.5" />
|
||||
Sub-issues
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="activity" className="gap-1.5">
|
||||
<ActivityIcon className="h-3.5 w-3.5" />
|
||||
Activity
|
||||
|
|
@ -1738,49 +1789,6 @@ export function IssueDetail() {
|
|||
/>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="subissues">
|
||||
<div className="mb-3 flex items-center justify-end">
|
||||
<Button variant="outline" size="sm" onClick={openNewSubIssue}>
|
||||
Add sub-issue
|
||||
</Button>
|
||||
</div>
|
||||
{childIssues.length === 0 ? (
|
||||
<p className="text-xs text-muted-foreground">No sub-issues.</p>
|
||||
) : (
|
||||
<div className="border border-border rounded-lg divide-y divide-border">
|
||||
{childIssues.map((child) => (
|
||||
<Link
|
||||
key={child.id}
|
||||
to={createIssueDetailPath(child.identifier ?? child.id)}
|
||||
state={resolvedIssueDetailState ?? location.state}
|
||||
onClickCapture={() =>
|
||||
rememberIssueDetailLocationState(
|
||||
child.identifier ?? child.id,
|
||||
resolvedIssueDetailState ?? location.state,
|
||||
location.search,
|
||||
)}
|
||||
className="flex items-center justify-between px-3 py-2 text-sm hover:bg-accent/20 transition-colors"
|
||||
>
|
||||
<div className="flex items-center gap-2 min-w-0">
|
||||
<StatusIcon status={child.status} />
|
||||
<PriorityIcon priority={child.priority} />
|
||||
<span className="font-mono text-muted-foreground shrink-0">
|
||||
{child.identifier ?? child.id.slice(0, 8)}
|
||||
</span>
|
||||
<span className="truncate">{child.title}</span>
|
||||
</div>
|
||||
{child.assigneeAgentId && (() => {
|
||||
const name = agentMap.get(child.assigneeAgentId)?.name;
|
||||
return name
|
||||
? <Identity name={name} size="sm" />
|
||||
: <span className="text-muted-foreground font-mono">{child.assigneeAgentId.slice(0, 8)}</span>;
|
||||
})()}
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="activity">
|
||||
{linkedApprovals && linkedApprovals.length > 0 && (
|
||||
<div className="mb-3 space-y-3">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue