From 6e3e7e65abf1159b3bbe77bb315fefea32f39c1a Mon Sep 17 00:00:00 2001 From: Neil <4138956+nwparker@users.noreply.github.com> Date: Thu, 27 Aug 2026 16:57:29 -0700 Subject: [PATCH 01/62] Split Jira issue workspace presentation (#16769) --- config/max-lines-baseline.txt | 1 - .../src/components/JiraIssueWorkspace.tsx | 556 ++---------------- .../jira-issue-workspace-actions.ts | 68 +++ .../jira-issue-workspace-chrome.tsx | 225 +++++++ .../jira-issue-workspace-content.tsx | 289 +++++++++ 5 files changed, 627 insertions(+), 512 deletions(-) create mode 100644 src/renderer/src/components/jira-issue-workspace-actions.ts create mode 100644 src/renderer/src/components/jira-issue-workspace-chrome.tsx create mode 100644 src/renderer/src/components/jira-issue-workspace-content.tsx diff --git a/config/max-lines-baseline.txt b/config/max-lines-baseline.txt index 6df9dddce05..ab1791c1eb7 100644 --- a/config/max-lines-baseline.txt +++ b/config/max-lines-baseline.txt @@ -42,7 +42,6 @@ inline src/relay/git-handler.ts inline src/relay/pty-handler.ts inline src/relay/workspace-space-scan.ts inline src/renderer/src/components/GitLabItemDialog.tsx -inline src/renderer/src/components/JiraIssueWorkspace.tsx inline src/renderer/src/components/LinearItemDrawer.tsx inline src/renderer/src/components/TaskPage.tsx inline src/renderer/src/components/Terminal.tsx diff --git a/src/renderer/src/components/JiraIssueWorkspace.tsx b/src/renderer/src/components/JiraIssueWorkspace.tsx index b1f2078900c..d423fe52799 100644 --- a/src/renderer/src/components/JiraIssueWorkspace.tsx +++ b/src/renderer/src/components/JiraIssueWorkspace.tsx @@ -1,33 +1,13 @@ -/* eslint-disable max-lines -- Why: the Jira drawer co-locates preview, - metadata edits, and comments so the task page has one full issue surface. */ /* oxlint-disable react-doctor/no-adjust-state-on-prop-change -- Why: Jira issue hydration, comments, transitions, priorities, and user options are loaded from provider IPC for the selected issue. */ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { - ArrowRight, - Clipboard, - ExternalLink, - GitBranch, - LoaderCircle, - RefreshCw, - Save, - Send, - X -} from 'lucide-react' import { toast } from 'sonner' import { VisuallyHidden } from 'radix-ui' - -import CommentMarkdown from '@/components/sidebar/CommentMarkdown' -import { JiraIcon } from '@/components/icons/JiraIcon' -import { Button } from '@/components/ui/button' -import { Input } from '@/components/ui/input' -import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover' import { Sheet, SheetContent, SheetDescription, SheetTitle } from '@/components/ui/sheet' -import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip' -import { cn } from '@/lib/utils' import { getCommentBodySubmitState, hasBoundedCommentBodyText } from '@/lib/comment-body-submit-state' + import { createBrowserUuid } from '@/lib/browser-uuid' import { useAppStore } from '@/store' import { @@ -48,7 +28,9 @@ import type { } from '../../../shared/jira-types' import type { TaskSourceContext } from '../../../shared/task-source-context' import { translate } from '@/i18n/i18n' -import { formatUiRelativeTimeFromDate } from '@/i18n/relative-time-format' +import { JiraIssueMetadataBar, JiraIssueWorkspaceHeader } from './jira-issue-workspace-chrome' +import { JiraIssueCommentComposer, JiraIssueWorkspaceContent } from './jira-issue-workspace-content' +import { getJiraIssueWorkspaceActions } from './jira-issue-workspace-actions' type JiraIssueWorkspaceProps = { issue: JiraIssue | null @@ -57,50 +39,6 @@ type JiraIssueWorkspaceProps = { sourceContext?: TaskSourceContext | null } -function formatRelativeTime(input: string): string { - return formatUiRelativeTimeFromDate(input) -} - -function buildJiraBranchName(issue: JiraIssue): string { - const slug = issue.title - .toLowerCase() - .replace(/[^a-z0-9]+/g, '-') - .replace(/^-+|-+$/g, '') - .slice(0, 52) - return `${issue.key.toLowerCase()}${slug ? `-${slug}` : ''}` -} - -function buildJiraPrompt(issue: JiraIssue): string { - return `Complete Jira issue ${issue.key}: ${issue.title}\n\n${issue.url}` -} - -function jiraStatusClass(categoryKey: string): string { - if (categoryKey === 'done') { - return 'border-emerald-500/30 bg-emerald-500/10 text-emerald-700 dark:text-emerald-200' - } - if (categoryKey === 'indeterminate') { - return 'border-sky-500/30 bg-sky-500/10 text-sky-700 dark:text-sky-200' - } - return 'border-border/50 bg-muted/40 text-muted-foreground' -} - -async function copyTextToClipboard(text: string, label: string): Promise { - try { - await window.api.ui.writeClipboardText(text) - toast.success( - translate('auto.components.JiraIssueWorkspace.2ff69a3545', '{{value0}} copied', { - value0: label - }) - ) - } catch { - toast.error( - translate('auto.components.JiraIssueWorkspace.6c41a9bcea', 'Failed to copy {{value0}}', { - value0: label.toLowerCase() - }) - ) - } -} - export default function JiraIssueWorkspace({ issue, onUse, @@ -343,41 +281,10 @@ export default function JiraIssueWorkspace({ }, [commentDraft, commentSubmitting, displayed, providerSettings]) const canSubmitComment = hasBoundedCommentBodyText(commentDraft) - const actionItems = useMemo(() => { - if (!displayed) { - return [] - } - return [ - { - label: translate('auto.components.JiraIssueWorkspace.69da9a208c', 'Open in Jira'), - icon: ExternalLink, - action: () => window.api.shell.openUrl(displayed.url) - }, - { - label: translate('auto.components.JiraIssueWorkspace.779bb91ee0', 'Copy URL'), - icon: Clipboard, - action: () => void copyTextToClipboard(displayed.url, 'URL') - }, - { - label: translate('auto.components.JiraIssueWorkspace.38839801e8', 'Copy key'), - icon: Clipboard, - action: () => void copyTextToClipboard(displayed.key, 'Key') - }, - { - label: translate( - 'auto.components.JiraIssueWorkspace.80efa101c5', - 'Copy suggested branch name' - ), - icon: GitBranch, - action: () => void copyTextToClipboard(buildJiraBranchName(displayed), 'Branch name') - }, - { - label: translate('auto.components.JiraIssueWorkspace.0cc62bd690', 'Copy prompt'), - icon: Clipboard, - action: () => void copyTextToClipboard(buildJiraPrompt(displayed), 'Prompt') - } - ] - }, [displayed]) + const actionItems = useMemo( + () => (displayed ? getJiraIssueWorkspaceActions(displayed) : []), + [displayed] + ) return ( !open && onClose()}> @@ -404,419 +311,46 @@ export default function JiraIssueWorkspace({ {displayed ? (
-
-
-
-
- {displayed.key} - {displayed.siteName ? {displayed.siteName} : null} - {displayed.project.key} - {formatRelativeTime(displayed.updatedAt)} - {issueLoading ? : null} -
-

- {displayed.title} -

-
- - - - - - - {translate('auto.components.JiraIssueWorkspace.7a96985ca0', 'Close')} - - -
-
+ -
- - - - - - {transitions.map((transition) => ( - - ))} - - + - - - - - - - {priorities.map((priority) => ( - - ))} - - + void loadComments(displayed, requestIdRef.current)} + onUse={onUse} + actionItems={actionItems} + /> - - - - - - - {users.map((user) => ( - - ))} - - -
- -
-
-
-
- -
- setTitleDraft(event.target.value)} - onKeyDown={(event) => { - if (event.key === 'Enter' && !event.nativeEvent.isComposing) { - event.preventDefault() - handleSaveTitle() - } - }} - className="h-8 text-xs" - /> - -
- -
- setLabelsDraft(event.target.value)} - placeholder={translate( - 'auto.components.JiraIssueWorkspace.0f3c07a901', - 'backend, bug' - )} - className="h-8 text-xs" - /> - -
-
-
- -
-
- - - {displayed.issueType.name} - - - {displayed.project.key} ·{' '} - {displayed.assignee?.displayName ?? - translate('auto.components.JiraIssueWorkspace.0b6b5646ed', 'Unassigned')} - -
- {displayed.description?.trim() ? ( - - ) : ( -

- {translate( - 'auto.components.JiraIssueWorkspace.c4889a47e4', - 'No description provided.' - )} -

- )} -
- -
-
-
- - {translate('auto.components.JiraIssueWorkspace.9a980b06b9', 'Comments')} - - {comments.length > 0 ? ( - {comments.length} - ) : null} -
- {commentsError ? ( - - ) : null} -
- {commentsError ? ( -
- {commentsError} -
- ) : commentsLoading && comments.length === 0 ? ( -
- -
- ) : comments.length === 0 ? ( -

- {translate( - 'auto.components.JiraIssueWorkspace.9178090e26', - 'No comments yet.' - )} -

- ) : ( -
- {comments.map((comment) => ( -
-
- {comment.user?.avatarUrl ? ( - - ) : null} - - {comment.user?.displayName ?? - translate( - 'auto.components.JiraIssueWorkspace.666cfdd835', - 'Unknown' - )} - - - {formatRelativeTime(comment.createdAt)} - -
-
- {/* Why: Jira comment screenshots need the same preview - affordance without changing compact comment typography. */} - -
-
- ))} -
- )} -
-
- - -
- -
-
-