mirror of
https://github.com/stablyai/orca.git
synced 2026-10-16 08:03:09 +00:00
Unify folder workspace card identity
Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
@@ -30,6 +30,7 @@ vi.mock('@/store', () => ({
|
||||
linearIssueCache: {},
|
||||
openModal,
|
||||
openTaskPage: vi.fn(),
|
||||
projectGroups: [],
|
||||
ptyIdsByTabId: {},
|
||||
remoteBranchConflictByWorktreeId: {},
|
||||
renamingWorktreeId: null,
|
||||
|
||||
@@ -17,6 +17,7 @@ const setWorkspacePortScanRefreshing = vi.fn()
|
||||
|
||||
let worktreeCardProperties: WorktreeCardProperty[] = ['status', 'ports']
|
||||
let hostedReviewCache: Record<string, unknown> = {}
|
||||
let projectGroups: unknown[] = []
|
||||
let workspacePortScan: { key: string; result: WorkspacePortScanResult } | null = null
|
||||
let settings: Partial<GlobalSettings> | null = { compactWorktreeCards: true }
|
||||
|
||||
@@ -35,6 +36,7 @@ vi.mock('@/store', () => ({
|
||||
linearIssueCache: {},
|
||||
openModal,
|
||||
openTaskPage,
|
||||
projectGroups,
|
||||
ptyIdsByTabId: {},
|
||||
recordFeatureInteraction,
|
||||
remoteBranchConflictByWorktreeId: {},
|
||||
@@ -172,6 +174,7 @@ describe('WorktreeCard compact hover details', () => {
|
||||
vi.clearAllMocks()
|
||||
worktreeCardProperties = ['status', 'ports']
|
||||
hostedReviewCache = {}
|
||||
projectGroups = []
|
||||
workspacePortScan = null
|
||||
settings = { compactWorktreeCards: true }
|
||||
})
|
||||
@@ -561,6 +564,78 @@ describe('WorktreeCard compact hover details', () => {
|
||||
expect(markup).toContain('text-[13px] leading-5')
|
||||
})
|
||||
|
||||
it('does not show a folder path row in new-card mode when no project groups exist', async () => {
|
||||
settings = { compactWorktreeCards: false, experimentalNewWorktreeCardStyle: true }
|
||||
worktreeCardProperties = ['status', 'branch']
|
||||
const { default: WorktreeCard } = await import('./WorktreeCard')
|
||||
|
||||
const markup = renderToStaticMarkup(
|
||||
<WorktreeCard
|
||||
worktree={makeWorktree({
|
||||
displayName: 'Docs folder',
|
||||
branch: '',
|
||||
path: ' /Users/x/projects/my-app '
|
||||
})}
|
||||
repo={{ ...makeRepo(), kind: 'folder' }}
|
||||
isActive={false}
|
||||
hideRepoBadge
|
||||
/>
|
||||
)
|
||||
|
||||
expect(markup).not.toContain('data-worktree-card-meta-row=""')
|
||||
expect(markup).toContain('Docs folder')
|
||||
expect(markup).not.toContain('/Users/x/projects/my-app')
|
||||
})
|
||||
|
||||
it('shows a folder path row in new-card mode through the branch setting when project groups exist', async () => {
|
||||
settings = { compactWorktreeCards: false, experimentalNewWorktreeCardStyle: true }
|
||||
worktreeCardProperties = ['status', 'branch']
|
||||
projectGroups = [{ id: 'group-1' }]
|
||||
const { default: WorktreeCard } = await import('./WorktreeCard')
|
||||
|
||||
const markup = renderToStaticMarkup(
|
||||
<WorktreeCard
|
||||
worktree={makeWorktree({
|
||||
displayName: 'Docs folder',
|
||||
branch: '',
|
||||
path: ' /Users/x/projects/my-app '
|
||||
})}
|
||||
repo={{ ...makeRepo(), kind: 'folder' }}
|
||||
isActive={false}
|
||||
hideRepoBadge
|
||||
/>
|
||||
)
|
||||
|
||||
expect(markup).toContain('data-worktree-card-meta-row=""')
|
||||
expect(markup).toContain(' /Users/x/projects/my-app ')
|
||||
expect(markup).not.toContain('>Folder</span>')
|
||||
})
|
||||
|
||||
it('keeps hidden folder path identity available from the new-card hover', async () => {
|
||||
settings = { compactWorktreeCards: false, experimentalNewWorktreeCardStyle: true }
|
||||
worktreeCardProperties = ['status']
|
||||
projectGroups = [{ id: 'group-1' }]
|
||||
const { default: WorktreeCard } = await import('./WorktreeCard')
|
||||
|
||||
const markup = renderToStaticMarkup(
|
||||
<WorktreeCard
|
||||
worktree={makeWorktree({
|
||||
displayName: 'Docs folder',
|
||||
branch: '',
|
||||
path: '/Users/x/projects/my-app'
|
||||
})}
|
||||
repo={{ ...makeRepo(), kind: 'folder' }}
|
||||
isActive={false}
|
||||
hideRepoBadge
|
||||
/>
|
||||
)
|
||||
|
||||
expect(markup).not.toContain('data-worktree-card-meta-row=""')
|
||||
expect(markup).toContain('data-hover-open-delay="100"')
|
||||
expect(markup).toContain('/Users/x/projects/my-app')
|
||||
expect(markup).toContain('Docs folder')
|
||||
})
|
||||
|
||||
it('shows the branch row for migrated Default cards with branch enabled', async () => {
|
||||
settings = { compactWorktreeCards: false }
|
||||
worktreeCardProperties = ['status', 'branch']
|
||||
|
||||
@@ -33,6 +33,7 @@ vi.mock('@/store', () => ({
|
||||
issueCache: {},
|
||||
linearIssueCache: {},
|
||||
openModal,
|
||||
projectGroups: [],
|
||||
remoteBranchConflictByWorktreeId: {},
|
||||
settings: { experimentalNewWorktreeCardStyle: true },
|
||||
sshConnectionStates: new Map(),
|
||||
|
||||
@@ -24,6 +24,7 @@ vi.mock('@/store', () => ({
|
||||
issueCache: {},
|
||||
linearIssueCache: {},
|
||||
openModal,
|
||||
projectGroups: [],
|
||||
remoteBranchConflictByWorktreeId: {},
|
||||
settings: null,
|
||||
sshConnectionStates: new Map(),
|
||||
|
||||
@@ -25,6 +25,7 @@ vi.mock('@/store', () => ({
|
||||
issueCache: {},
|
||||
linearIssueCache: {},
|
||||
openModal,
|
||||
projectGroups: [],
|
||||
remoteBranchConflictByWorktreeId: {},
|
||||
settings,
|
||||
sshConnectionStates: new Map(),
|
||||
|
||||
@@ -29,6 +29,7 @@ vi.mock('@/store', () => ({
|
||||
issueCache: {},
|
||||
linearIssueCache: {},
|
||||
openModal,
|
||||
projectGroups: [],
|
||||
remoteBranchConflictByWorktreeId: {},
|
||||
settings,
|
||||
sshConnectionStates: new Map(),
|
||||
|
||||
@@ -35,6 +35,7 @@ vi.mock('@/store', () => ({
|
||||
hostedReviewCache: {},
|
||||
issueCache: {},
|
||||
openModal,
|
||||
projectGroups: [],
|
||||
remoteBranchConflictByWorktreeId: {},
|
||||
settings,
|
||||
sshConnectionStates: new Map(),
|
||||
@@ -181,7 +182,7 @@ describe('WorktreeCard quick actions', () => {
|
||||
expect(markup).not.toContain('bg-black/[0.08]')
|
||||
})
|
||||
|
||||
it('renders folder kind and directory in the detailed metadata row', () => {
|
||||
it('renders folder directory name in the detailed metadata row without a Folder badge', () => {
|
||||
const markup = renderToStaticMarkup(
|
||||
<WorktreeCard
|
||||
worktree={makeWorktree({ displayName: 'Docs folder', branch: '' })}
|
||||
@@ -191,12 +192,12 @@ describe('WorktreeCard quick actions', () => {
|
||||
)
|
||||
|
||||
expect(markup).toContain('Docs folder')
|
||||
expect(markup).toContain('>Folder</span>')
|
||||
expect(markup).not.toContain('>Folder</span>')
|
||||
expect(markup).toContain('>quick-action</span>')
|
||||
expect(markup).toContain('data-worktree-card-meta-row=""')
|
||||
})
|
||||
|
||||
it('renders synthetic folder workspace directory in the detailed metadata row', () => {
|
||||
it('renders synthetic folder workspace directory name in the detailed metadata row without a Folder badge', () => {
|
||||
const markup = renderToStaticMarkup(
|
||||
<WorktreeCard
|
||||
worktree={makeWorktree({
|
||||
@@ -211,7 +212,7 @@ describe('WorktreeCard quick actions', () => {
|
||||
)
|
||||
|
||||
expect(markup).toContain('Docs folder')
|
||||
expect(markup).toContain('>Folder</span>')
|
||||
expect(markup).not.toContain('>Folder</span>')
|
||||
expect(markup).toContain('>quick-action</span>')
|
||||
expect(markup).toContain('data-worktree-card-meta-row=""')
|
||||
})
|
||||
|
||||
@@ -28,6 +28,7 @@ vi.mock('@/store', () => ({
|
||||
issueCache: {},
|
||||
linearIssueCache: {},
|
||||
openModal,
|
||||
projectGroups: [],
|
||||
remoteBranchConflictByWorktreeId: {},
|
||||
runtimeStatusByEnvironmentId,
|
||||
settings: null,
|
||||
|
||||
@@ -26,7 +26,7 @@ import WorktreeCardAgents from './WorktreeCardAgents'
|
||||
import { WorktreeCardStatusSlot } from './WorktreeCardStatusSlot'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { activateWorktreeFromSidebar } from '@/lib/sidebar-worktree-activation'
|
||||
import { getRepoKindLabel, isFolderRepo } from '../../../../shared/repo-kind'
|
||||
import { isFolderRepo } from '../../../../shared/repo-kind'
|
||||
import type { HostedReviewInfo } from '../../../../shared/hosted-review'
|
||||
import type {
|
||||
GitHubWorkItem,
|
||||
@@ -222,6 +222,7 @@ const WorktreeCard = React.memo(function WorktreeCard({
|
||||
const fetchIssue = useAppStore((s) => s.fetchIssue)
|
||||
const fetchLinearIssue = useAppStore((s) => s.fetchLinearIssue)
|
||||
const cardProps = useAppStore((s) => s.worktreeCardProperties)
|
||||
const projectGroups = useAppStore((s) => s.projectGroups)
|
||||
const newCardStyle = settings?.experimentalNewWorktreeCardStyle === true
|
||||
const compactCards = !newCardStyle && settings?.compactWorktreeCards === true
|
||||
const activeSurfaceIsSecondary = isActiveSurface && activeSurfaceVariant === 'secondary'
|
||||
@@ -361,6 +362,22 @@ const WorktreeCard = React.memo(function WorktreeCard({
|
||||
const folderWorkspaceId =
|
||||
workspaceScope?.type === 'folder' ? workspaceScope.folderWorkspaceId : null
|
||||
const isFolder = repo ? isFolderRepo(repo) : folderWorkspaceId !== null
|
||||
const hasProjectGroups = projectGroups.length > 0
|
||||
const branchIdentityDisplay = !isFolder && branch.length > 0 ? branch : undefined
|
||||
const folderPathIdentityDisplay =
|
||||
isFolder && hasProjectGroups && worktree.path.trim().length > 0 ? worktree.path : undefined
|
||||
const identityDisplay = branchIdentityDisplay ?? folderPathIdentityDisplay
|
||||
const hasPathIdentityEnabled = cardProps.includes('branch')
|
||||
const showIdentityInNewCard = newCardStyle && hasPathIdentityEnabled && Boolean(identityDisplay)
|
||||
const folderMetaRowContent = newCardStyle
|
||||
? hasPathIdentityEnabled && Boolean(folderPathIdentityDisplay)
|
||||
: isFolder
|
||||
const statusIdentityLabel = hasProjectGroups
|
||||
? translate(
|
||||
'auto.components.sidebar.WorktreeCard.branchFolderPathIdentity',
|
||||
'Branch or folder path'
|
||||
)
|
||||
: translate('auto.components.sidebar.WorktreeCard.branchIdentity', 'Branch')
|
||||
const hostedReviewCacheKey =
|
||||
repo && branch
|
||||
? getHostedReviewCacheKey(
|
||||
@@ -1044,7 +1061,8 @@ const WorktreeCard = React.memo(function WorktreeCard({
|
||||
const showBranch =
|
||||
!isFolder &&
|
||||
branch.length > 0 &&
|
||||
(newCardStyle ? cardProps.includes('branch') : !compactCards || branch !== worktree.displayName)
|
||||
!newCardStyle &&
|
||||
(!compactCards || branch !== worktree.displayName)
|
||||
// Why: rebases already surface in source control; keep dense cards from
|
||||
// carrying a persistent rebase chip while preserving other interruption cues.
|
||||
const showConflictOperationBadge =
|
||||
@@ -1063,30 +1081,28 @@ const WorktreeCard = React.memo(function WorktreeCard({
|
||||
const hasDetailedMetaRowContent = Boolean(
|
||||
(showRepoBadgeInMetaRow && repo) ||
|
||||
showHostContextBadge ||
|
||||
isFolder ||
|
||||
folderMetaRowContent ||
|
||||
showBranch ||
|
||||
showIdentityInNewCard ||
|
||||
showDetachedHeadInMetaRow ||
|
||||
showConflictOperationBadge ||
|
||||
cacheStartedAt != null ||
|
||||
showMetaRowDetails
|
||||
)
|
||||
const hasMetaRow = compactCards
|
||||
? hasMetadataBadge || (newCardStyle && showBranch) || cacheStartedAt != null
|
||||
? hasMetadataBadge || cacheStartedAt != null
|
||||
: hasDetailedMetaRowContent
|
||||
const showHeaderActions = showTitleRowPrimary || showDeleteQuickAction
|
||||
// Why: the hover owns full identity when the row truncates; normalize once
|
||||
// so title/branch de-dupe and identity-only hover eligibility stay in sync.
|
||||
const trimmedVisibleCardTitle = visibleCardTitle.trim()
|
||||
const showBranchIdentityHover = newCardStyle
|
||||
? !isFolder &&
|
||||
branch.length > 0 &&
|
||||
? Boolean(identityDisplay) &&
|
||||
!cardProps.includes('branch') &&
|
||||
branch !== trimmedVisibleCardTitle
|
||||
identityDisplay !== trimmedVisibleCardTitle
|
||||
: compactCards && showBranch
|
||||
const hoverBranchName = newCardStyle
|
||||
? !isFolder && branch.length > 0
|
||||
? branch
|
||||
: undefined
|
||||
? identityDisplay
|
||||
: showBranchIdentityHover
|
||||
? branch
|
||||
: undefined
|
||||
@@ -1244,7 +1260,8 @@ const WorktreeCard = React.memo(function WorktreeCard({
|
||||
onToggleUnread={handleToggleUnreadQuick}
|
||||
prDisplay={hoverReview}
|
||||
newCardStyle={newCardStyle}
|
||||
hasBranchIdentity={!isFolder && branch.length > 0}
|
||||
hasBranchIdentity={Boolean(identityDisplay)}
|
||||
branchIdentityLabel={statusIdentityLabel}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
@@ -1357,17 +1374,6 @@ const WorktreeCard = React.memo(function WorktreeCard({
|
||||
}
|
||||
/>
|
||||
|
||||
{isFolder && (
|
||||
<Badge
|
||||
variant="secondary"
|
||||
className="h-[16px] px-1.5 text-[10px] font-medium rounded shrink-0 text-muted-foreground bg-accent border border-border dark:bg-accent/80 dark:border-border/50 leading-none"
|
||||
>
|
||||
{repo
|
||||
? getRepoKindLabel(repo)
|
||||
: translate('auto.components.sidebar.WorktreeCard.93aebe4529', 'Folder')}
|
||||
</Badge>
|
||||
)}
|
||||
|
||||
{typeof worktree.firstAgentMessageRenameError === 'string' &&
|
||||
worktree.firstAgentMessageRenameError.length > 0 &&
|
||||
!titleRenaming ? (
|
||||
@@ -1527,7 +1533,13 @@ const WorktreeCard = React.memo(function WorktreeCard({
|
||||
</Badge>
|
||||
)}
|
||||
|
||||
{isFolder ? (
|
||||
{showIdentityInNewCard ? (
|
||||
<TruncatedSidebarLabel
|
||||
text={identityDisplay!}
|
||||
className="text-[11px] text-muted-foreground leading-none"
|
||||
tooltipEnabled={!hasHoverDetails}
|
||||
/>
|
||||
) : isFolder && !newCardStyle ? (
|
||||
<span
|
||||
className="min-w-0 truncate font-mono text-[11px] leading-none text-muted-foreground"
|
||||
title={worktree.path}
|
||||
|
||||
@@ -11,6 +11,7 @@ const setWorktreeCardProperties = vi.fn()
|
||||
const setAgentActivityDisplayMode = vi.fn()
|
||||
|
||||
let settings = { compactWorktreeCards: false, experimentalNewWorktreeCardStyle: false }
|
||||
let projectGroups: unknown[] = []
|
||||
let worktreeCardProperties = [
|
||||
'status',
|
||||
'unread',
|
||||
@@ -27,6 +28,7 @@ vi.mock('@/store', () => ({
|
||||
useAppStore: (selector: (state: unknown) => unknown) =>
|
||||
selector({
|
||||
agentActivityDisplayMode: 'compact',
|
||||
projectGroups,
|
||||
setAgentActivityDisplayMode,
|
||||
setWorktreeCardMode,
|
||||
setWorktreeCardProperties,
|
||||
@@ -112,6 +114,7 @@ function renderMenu(): void {
|
||||
|
||||
beforeEach(() => {
|
||||
settings = { compactWorktreeCards: false, experimentalNewWorktreeCardStyle: false }
|
||||
projectGroups = []
|
||||
worktreeCardProperties = [
|
||||
'status',
|
||||
'unread',
|
||||
@@ -153,4 +156,23 @@ describe('WorktreeCardDisplayMenuSection', () => {
|
||||
|
||||
expect(setWorktreeCardMode).toHaveBeenCalledWith('Compact')
|
||||
})
|
||||
|
||||
it('keeps branch-only copy when project groups are unavailable', () => {
|
||||
settings = { compactWorktreeCards: false, experimentalNewWorktreeCardStyle: true }
|
||||
|
||||
renderMenu()
|
||||
|
||||
expect(container?.textContent).toContain('Branch name')
|
||||
expect(container?.textContent).not.toContain('Branch / folder path')
|
||||
})
|
||||
|
||||
it('mentions folder paths when project groups can create folder workspaces', () => {
|
||||
settings = { compactWorktreeCards: false, experimentalNewWorktreeCardStyle: true }
|
||||
projectGroups = [{ id: 'group-1' }]
|
||||
|
||||
renderMenu()
|
||||
|
||||
expect(container?.textContent).toContain('Branch / folder path')
|
||||
expect(container?.textContent).not.toContain('Branch name')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -32,6 +32,7 @@ export function WorktreeCardDisplayMenuSection({
|
||||
const setWorktreeCardMode = useAppStore((s) => s.setWorktreeCardMode)
|
||||
const agentActivityDisplayMode = useAppStore((s) => s.agentActivityDisplayMode)
|
||||
const setAgentActivityDisplayMode = useAppStore((s) => s.setAgentActivityDisplayMode)
|
||||
const projectGroups = useAppStore((s) => s.projectGroups)
|
||||
const newCardStyle = settings?.experimentalNewWorktreeCardStyle === true
|
||||
const cardLayout = settings?.compactWorktreeCards ? 'compact' : 'detailed'
|
||||
const cardLayoutLabel =
|
||||
@@ -39,9 +40,10 @@ export function WorktreeCardDisplayMenuSection({
|
||||
const visiblePropertyCount = PROPERTY_OPTIONS.filter((opt) =>
|
||||
worktreeCardProperties.includes(opt.id)
|
||||
).length
|
||||
const hasProjectGroups = projectGroups.length > 0
|
||||
const worktreeCardPropertyOptions = useMemo(
|
||||
() => getWorktreeCardPropertyOptions({ newCardStyle }),
|
||||
[newCardStyle]
|
||||
() => getWorktreeCardPropertyOptions({ newCardStyle, hasProjectGroups }),
|
||||
[newCardStyle, hasProjectGroups]
|
||||
)
|
||||
const handleWorktreeCardPropertyChange = useCallback(
|
||||
(properties: readonly WorktreeCardProperty[], checked: boolean): void => {
|
||||
|
||||
@@ -205,7 +205,7 @@ describe('WorktreeCardStatusSlot', () => {
|
||||
expect(markup).not.toContain('bg-neutral-500/40')
|
||||
})
|
||||
|
||||
it('uses a branch icon instead of the quiet active dot when new card style has no review', () => {
|
||||
it('uses a branch icon with branch-only tooltip copy by default', () => {
|
||||
const markup = renderToStaticMarkup(
|
||||
<WorktreeCardStatusSlot
|
||||
worktreeId="wt-1"
|
||||
@@ -221,12 +221,33 @@ describe('WorktreeCardStatusSlot', () => {
|
||||
)
|
||||
|
||||
expect(markup).toContain('Branch')
|
||||
expect(markup).not.toContain('Branch or folder path')
|
||||
expect(markup).toContain('lucide-git-branch')
|
||||
expect(markup).toContain('size-[13px] translate-x-px text-muted-foreground/70')
|
||||
expect(markup).toContain('text-muted-foreground/70')
|
||||
expect(markup).not.toContain('bg-emerald-500')
|
||||
})
|
||||
|
||||
it('uses context-aware branch or folder path tooltip copy', () => {
|
||||
const markup = renderToStaticMarkup(
|
||||
<WorktreeCardStatusSlot
|
||||
worktreeId="wt-1"
|
||||
showStatus
|
||||
showUnreadAction={false}
|
||||
isUnread={false}
|
||||
unreadTooltip="Mark as unread"
|
||||
onPointerDown={vi.fn()}
|
||||
onToggleUnread={vi.fn()}
|
||||
newCardStyle
|
||||
hasBranchIdentity
|
||||
branchIdentityLabel="Branch or folder path"
|
||||
/>
|
||||
)
|
||||
|
||||
expect(markup).toContain('Branch or folder path')
|
||||
expect(markup).toContain('lucide-git-branch')
|
||||
})
|
||||
|
||||
it('keeps the quiet dot when the row has no branch identity', () => {
|
||||
const markup = renderToStaticMarkup(
|
||||
<WorktreeCardStatusSlot
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React from 'react'
|
||||
import { Bell, GitBranch } from 'lucide-react'
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'
|
||||
import { translate } from '@/i18n/i18n'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { getWorktreeStatusLabel, type WorktreeStatus } from '@/lib/worktree-status'
|
||||
import { FilledBellIcon } from './WorktreeCardHelpers'
|
||||
@@ -20,13 +21,16 @@ type WorktreeCardStatusSlotProps = {
|
||||
prDisplay?: WorktreeCardPrDisplay | null
|
||||
newCardStyle?: boolean
|
||||
hasBranchIdentity?: boolean
|
||||
branchIdentityLabel?: string
|
||||
className?: string
|
||||
}
|
||||
|
||||
const QUIET_REVIEW_REPLACEABLE_STATUSES = new Set<WorktreeStatus>(['active', 'done', 'inactive'])
|
||||
// Why: a missing review display can also mean provider state is unavailable,
|
||||
// so the passive label names the branch cue without claiming no review exists.
|
||||
const BRANCH_STATUS_LABEL = 'Branch'
|
||||
// so the passive label names the identity cue without claiming no review exists.
|
||||
function getDefaultBranchIdentityLabel(): string {
|
||||
return translate('auto.components.sidebar.WorktreeCardStatusSlot.branchIdentity', 'Branch')
|
||||
}
|
||||
// Why: branch-style SVGs are optically left-heavy; this keeps them aligned with
|
||||
// the centered activity dots in the shared status column.
|
||||
const compactReviewAndBranchStatusIconClassName = 'size-[13px] translate-x-px'
|
||||
@@ -93,6 +97,7 @@ export function WorktreeCardStatusSlot({
|
||||
prDisplay = null,
|
||||
newCardStyle = false,
|
||||
hasBranchIdentity = false,
|
||||
branchIdentityLabel,
|
||||
className
|
||||
}: WorktreeCardStatusSlotProps): React.JSX.Element | null {
|
||||
const status = useWorktreeActivityStatus(worktreeId)
|
||||
@@ -112,7 +117,7 @@ export function WorktreeCardStatusSlot({
|
||||
canShowReviewStatus && prDisplay
|
||||
? getReviewStatusTooltip(prDisplay)
|
||||
: canShowBranchStatus
|
||||
? BRANCH_STATUS_LABEL
|
||||
? (branchIdentityLabel ?? getDefaultBranchIdentityLabel())
|
||||
: statusLabel
|
||||
const passiveStatusTooltip =
|
||||
newCardStyle && isUnread ? `${passiveStatusLabel} · Unread` : passiveStatusLabel
|
||||
|
||||
@@ -36,4 +36,30 @@ describe('worktree card property options', () => {
|
||||
expect(options.map((option) => option.label)).toContain('Linear issues')
|
||||
expect(options.map((option) => option.label)).toContain('Automation')
|
||||
})
|
||||
|
||||
it('uses branch-only copy by default and without project groups', () => {
|
||||
const defaultOptions = getWorktreeCardPropertyOptions()
|
||||
const newCardOptions = getWorktreeCardPropertyOptions({
|
||||
newCardStyle: true,
|
||||
hasProjectGroups: false
|
||||
})
|
||||
|
||||
expect(defaultOptions.find((option) => option.id === 'branch')?.label).toBe('Branch name')
|
||||
expect(newCardOptions.find((option) => option.id === 'branch')?.label).toBe('Branch name')
|
||||
})
|
||||
|
||||
it('keeps branch-only copy for legacy cards even with project groups', () => {
|
||||
const options = getWorktreeCardPropertyOptions({ hasProjectGroups: true })
|
||||
|
||||
expect(options.find((option) => option.id === 'branch')?.label).toBe('Branch name')
|
||||
})
|
||||
|
||||
it('mentions folder paths only for new card style with project groups', () => {
|
||||
const options = getWorktreeCardPropertyOptions({
|
||||
newCardStyle: true,
|
||||
hasProjectGroups: true
|
||||
})
|
||||
|
||||
expect(options.find((option) => option.id === 'branch')?.label).toBe('Branch / folder path')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -158,21 +158,36 @@ const ISSUE_WORKTREE_CARD_PROPERTY_OPTIONS: WorktreeCardPropertyOption[] = [
|
||||
|
||||
type WorktreeCardPropertyOptionsInput = {
|
||||
newCardStyle?: boolean
|
||||
hasProjectGroups?: boolean
|
||||
}
|
||||
|
||||
export function getWorktreeCardPropertyOptions({
|
||||
newCardStyle = false
|
||||
newCardStyle = false,
|
||||
hasProjectGroups = false
|
||||
}: WorktreeCardPropertyOptionsInput = {}): WorktreeCardPropertyOption[] {
|
||||
const issueOptions = newCardStyle
|
||||
? ISSUE_WORKTREE_CARD_PROPERTY_OPTIONS
|
||||
: [TASK_WORKTREE_CARD_PROPERTY_OPTION]
|
||||
const branchOption: WorktreeCardPropertyOption = {
|
||||
id: 'branch',
|
||||
properties: ['branch'],
|
||||
get label() {
|
||||
return newCardStyle && hasProjectGroups
|
||||
? translate(
|
||||
'auto.components.sidebar.SidebarWorkspaceOptionsMenu.folderPathIdentity',
|
||||
'Branch / folder path'
|
||||
)
|
||||
: translate('auto.components.sidebar.SidebarWorkspaceOptionsMenu.219ebf1961', 'Branch name')
|
||||
}
|
||||
}
|
||||
if (newCardStyle) {
|
||||
return [...issueOptions, ...BASE_WORKTREE_CARD_PROPERTY_OPTIONS.slice(1)]
|
||||
return [...issueOptions, ...BASE_WORKTREE_CARD_PROPERTY_OPTIONS.slice(1, -1), branchOption]
|
||||
}
|
||||
return [
|
||||
BASE_WORKTREE_CARD_PROPERTY_OPTIONS[0],
|
||||
...issueOptions,
|
||||
...BASE_WORKTREE_CARD_PROPERTY_OPTIONS.slice(1)
|
||||
...BASE_WORKTREE_CARD_PROPERTY_OPTIONS.slice(1, -1),
|
||||
branchOption
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -3750,7 +3750,8 @@
|
||||
"8d62c68b35": "Notes",
|
||||
"2d74665a56": "Ports",
|
||||
"65a9820bd1": "Agent statuses",
|
||||
"219ebf1961": "Branch name"
|
||||
"219ebf1961": "Branch name",
|
||||
"folderPathIdentity": "Branch / folder path"
|
||||
},
|
||||
"SshDisconnectedDialog": {
|
||||
"ca4a7892af": "Connecting...",
|
||||
@@ -3826,7 +3827,9 @@
|
||||
"021538e1d1": "SSH disconnected",
|
||||
"runtimeHostDisconnected": "Server disconnected",
|
||||
"runtimeHostProject": "Project on Orca server",
|
||||
"automationCreated": "Created by automation"
|
||||
"automationCreated": "Created by automation",
|
||||
"branchIdentity": "Branch",
|
||||
"branchFolderPathIdentity": "Branch or folder path"
|
||||
},
|
||||
"WorktreeCardAgents": {
|
||||
"1b0a156717": "Agents"
|
||||
@@ -4264,6 +4267,9 @@
|
||||
"current": "Current",
|
||||
"searchPlaceholder": "Search worktrees...",
|
||||
"empty": "No matching eligible worktrees."
|
||||
},
|
||||
"WorktreeCardStatusSlot": {
|
||||
"branchIdentity": "Branch"
|
||||
}
|
||||
},
|
||||
"shared": {
|
||||
|
||||
@@ -3736,7 +3736,8 @@
|
||||
"automation": "Automation",
|
||||
"2d74665a56": "Puertos",
|
||||
"65a9820bd1": "Estados del agente",
|
||||
"219ebf1961": "Nombre de rama"
|
||||
"219ebf1961": "Nombre de rama",
|
||||
"folderPathIdentity": "Rama / ruta de carpeta"
|
||||
},
|
||||
"SshDisconnectedDialog": {
|
||||
"ca4a7892af": "Conectando...",
|
||||
@@ -3812,7 +3813,9 @@
|
||||
"021538e1d1": "SSH desconectado",
|
||||
"runtimeHostDisconnected": "Server disconnected",
|
||||
"runtimeHostProject": "Project on Orca server",
|
||||
"automationCreated": "Created by automation"
|
||||
"automationCreated": "Created by automation",
|
||||
"branchIdentity": "Rama",
|
||||
"branchFolderPathIdentity": "Rama o ruta de carpeta"
|
||||
},
|
||||
"WorktreeCardAgents": {
|
||||
"1b0a156717": "Agents"
|
||||
@@ -4264,6 +4267,9 @@
|
||||
"current": "Actual",
|
||||
"searchPlaceholder": "Buscar árboles de trabajo...",
|
||||
"empty": "No hay árboles de trabajo elegibles que coincidan."
|
||||
},
|
||||
"WorktreeCardStatusSlot": {
|
||||
"branchIdentity": "Rama"
|
||||
}
|
||||
},
|
||||
"shared": {
|
||||
@@ -6217,19 +6223,19 @@
|
||||
"29154326bb": "en",
|
||||
"ab20575a8a": "apagado",
|
||||
"ab3a1f9068": "wsl.exe",
|
||||
"ask_before_closing_running_terminals_title": "Ask Before Closing Running Terminals",
|
||||
"ask_before_closing_running_terminals_description": "Show a confirmation before closing a terminal that has a running command or agent.",
|
||||
"ask_before_closing_running_terminals_title": "Preguntar antes de cerrar terminales en ejecución",
|
||||
"ask_before_closing_running_terminals_description": "Muestra una confirmación antes de cerrar un terminal que tiene un comando o agente en ejecución.",
|
||||
"scrollSpeed": {
|
||||
"title": "Scroll Speed",
|
||||
"description": "Tune normal terminal scrollback, fast modifier scrolling, and full-screen TUI wheel speed.",
|
||||
"helper": "Adjust how wheel input feels in scrollback and in mouse-aware terminal apps.",
|
||||
"reset": "Reset",
|
||||
"title": "Velocidad de desplazamiento",
|
||||
"description": "Ajusta el desplazamiento normal del terminal, el desplazamiento rápido con modificador y la velocidad de rueda en TUI de pantalla completa.",
|
||||
"helper": "Ajusta cómo se siente la entrada de la rueda en el historial de desplazamiento y en apps de terminal compatibles con el ratón.",
|
||||
"reset": "Restablecer",
|
||||
"normal": "Normal",
|
||||
"normalDescription": "Scrollback wheel multiplier.",
|
||||
"fast": "Fast",
|
||||
"fastDescription": "Extra multiplier while scrolling with a modifier key.",
|
||||
"normalDescription": "Multiplicador de la rueda en el historial.",
|
||||
"fast": "Rápido",
|
||||
"fastDescription": "Multiplicador extra al desplazarse con una tecla modificadora.",
|
||||
"tui": "TUI",
|
||||
"tuiDescription": "Discrete wheel reports for full-screen terminal apps."
|
||||
"tuiDescription": "Informes discretos de rueda para apps de terminal de pantalla completa."
|
||||
}
|
||||
},
|
||||
"TerminalSettingsPreview": {
|
||||
@@ -7865,11 +7871,11 @@
|
||||
"keyword_yaml": "yaml",
|
||||
"keyword_custom": "custom"
|
||||
},
|
||||
"ask_before_closing_running_terminals_title": "Ask Before Closing Running Terminals",
|
||||
"ask_before_closing_running_terminals_description": "Show a confirmation before closing a terminal that has a running command or agent.",
|
||||
"ask_before_closing_running_terminals_title": "Preguntar antes de cerrar terminales en ejecución",
|
||||
"ask_before_closing_running_terminals_description": "Muestra una confirmación antes de cerrar un terminal que tiene un comando o agente en ejecución.",
|
||||
"scrollSpeed": {
|
||||
"title": "Scroll Speed",
|
||||
"description": "Tune normal terminal scrollback, fast modifier scrolling, and full-screen TUI wheel speed."
|
||||
"title": "Velocidad de desplazamiento",
|
||||
"description": "Ajusta el desplazamiento normal del terminal, el desplazamiento rápido con modificador y la velocidad de rueda en TUI de pantalla completa."
|
||||
}
|
||||
},
|
||||
"windows": {
|
||||
|
||||
@@ -3717,7 +3717,8 @@
|
||||
"2d74665a56": "ポート",
|
||||
"65a9820bd1": "Agent ステータス",
|
||||
"219ebf1961": "ブランチ名",
|
||||
"automation": "Automation"
|
||||
"automation": "Automation",
|
||||
"folderPathIdentity": "ブランチ / フォルダパス"
|
||||
},
|
||||
"SshDisconnectedDialog": {
|
||||
"ca4a7892af": "接続中...",
|
||||
@@ -3793,7 +3794,9 @@
|
||||
"021538e1d1": "SSH が切断されました",
|
||||
"runtimeHostDisconnected": "Server disconnected",
|
||||
"runtimeHostProject": "Project on Orca server",
|
||||
"automationCreated": "Created by automation"
|
||||
"automationCreated": "Created by automation",
|
||||
"branchIdentity": "ブランチ",
|
||||
"branchFolderPathIdentity": "ブランチまたはフォルダパス"
|
||||
},
|
||||
"WorktreeCardAgents": {
|
||||
"1b0a156717": "Agents"
|
||||
@@ -4264,6 +4267,9 @@
|
||||
"current": "現在",
|
||||
"searchPlaceholder": "ワークツリーを検索...",
|
||||
"empty": "一致する対象ワークツリーがありません。"
|
||||
},
|
||||
"WorktreeCardStatusSlot": {
|
||||
"branchIdentity": "ブランチ"
|
||||
}
|
||||
},
|
||||
"shared": {
|
||||
@@ -6239,19 +6245,19 @@
|
||||
"29154326bb": "の上",
|
||||
"ab20575a8a": "オフ",
|
||||
"ab3a1f9068": "wsl.exe",
|
||||
"ask_before_closing_running_terminals_title": "Ask Before Closing Running Terminals",
|
||||
"ask_before_closing_running_terminals_description": "Show a confirmation before closing a terminal that has a running command or agent.",
|
||||
"ask_before_closing_running_terminals_title": "実行中のターミナルを閉じる前に確認",
|
||||
"ask_before_closing_running_terminals_description": "実行中のコマンドまたはエージェントがあるターミナルを閉じる前に確認を表示します。",
|
||||
"scrollSpeed": {
|
||||
"title": "Scroll Speed",
|
||||
"description": "Tune normal terminal scrollback, fast modifier scrolling, and full-screen TUI wheel speed.",
|
||||
"helper": "Adjust how wheel input feels in scrollback and in mouse-aware terminal apps.",
|
||||
"reset": "Reset",
|
||||
"normal": "Normal",
|
||||
"normalDescription": "Scrollback wheel multiplier.",
|
||||
"fast": "Fast",
|
||||
"fastDescription": "Extra multiplier while scrolling with a modifier key.",
|
||||
"title": "スクロール速度",
|
||||
"description": "通常のターミナルスクロールバック、修飾キー付き高速スクロール、全画面 TUI のホイール速度を調整します。",
|
||||
"helper": "スクロールバックやマウス対応ターミナルアプリでのホイール操作の感触を調整します。",
|
||||
"reset": "リセット",
|
||||
"normal": "通常",
|
||||
"normalDescription": "スクロールバックのホイール倍率。",
|
||||
"fast": "高速",
|
||||
"fastDescription": "修飾キーを押しながらスクロールするときの追加倍率。",
|
||||
"tui": "TUI",
|
||||
"tuiDescription": "Discrete wheel reports for full-screen terminal apps."
|
||||
"tuiDescription": "全画面ターミナルアプリ向けの離散的なホイール通知。"
|
||||
}
|
||||
},
|
||||
"TerminalSettingsPreview": {
|
||||
@@ -7887,11 +7893,11 @@
|
||||
"33031c1465": "文字サイズ",
|
||||
"0fe0073f0c": "新規ペインとライブ アップデートのデフォルトの terminal フォント サイズ。",
|
||||
"5930244899": "フォントサイズ",
|
||||
"ask_before_closing_running_terminals_title": "Ask Before Closing Running Terminals",
|
||||
"ask_before_closing_running_terminals_description": "Show a confirmation before closing a terminal that has a running command or agent.",
|
||||
"ask_before_closing_running_terminals_title": "実行中のターミナルを閉じる前に確認",
|
||||
"ask_before_closing_running_terminals_description": "実行中のコマンドまたはエージェントがあるターミナルを閉じる前に確認を表示します。",
|
||||
"scrollSpeed": {
|
||||
"title": "Scroll Speed",
|
||||
"description": "Tune normal terminal scrollback, fast modifier scrolling, and full-screen TUI wheel speed."
|
||||
"title": "スクロール速度",
|
||||
"description": "通常のターミナルスクロールバック、修飾キー付き高速スクロール、全画面 TUI のホイール速度を調整します。"
|
||||
}
|
||||
},
|
||||
"windows": {
|
||||
|
||||
@@ -3717,7 +3717,8 @@
|
||||
"2d74665a56": "포트",
|
||||
"65a9820bd1": "Agent 상태",
|
||||
"219ebf1961": "브랜치 이름",
|
||||
"automation": "자동화"
|
||||
"automation": "자동화",
|
||||
"folderPathIdentity": "브랜치 / 폴더 경로"
|
||||
},
|
||||
"SshDisconnectedDialog": {
|
||||
"ca4a7892af": "연결 중...",
|
||||
@@ -3793,7 +3794,9 @@
|
||||
"021538e1d1": "SSH 연결이 끊어졌습니다.",
|
||||
"runtimeHostDisconnected": "Server disconnected",
|
||||
"runtimeHostProject": "Project on Orca server",
|
||||
"automationCreated": "Created by automation"
|
||||
"automationCreated": "Created by automation",
|
||||
"branchIdentity": "브랜치",
|
||||
"branchFolderPathIdentity": "브랜치 또는 폴더 경로"
|
||||
},
|
||||
"WorktreeCardAgents": {
|
||||
"1b0a156717": "Agents"
|
||||
@@ -4264,6 +4267,9 @@
|
||||
"current": "현재",
|
||||
"searchPlaceholder": "워크트리 검색...",
|
||||
"empty": "일치하는 적격 워크트리가 없습니다."
|
||||
},
|
||||
"WorktreeCardStatusSlot": {
|
||||
"branchIdentity": "브랜치"
|
||||
}
|
||||
},
|
||||
"shared": {
|
||||
@@ -6205,16 +6211,16 @@
|
||||
"ask_before_closing_running_terminals_title": "실행 중인 Terminals을 닫기 전에 확인",
|
||||
"ask_before_closing_running_terminals_description": "실행 중인 명령이나 agent가 있는 terminal을 닫기 전에 확인 창을 표시합니다.",
|
||||
"scrollSpeed": {
|
||||
"title": "Scroll Speed",
|
||||
"description": "Tune normal terminal scrollback, fast modifier scrolling, and full-screen TUI wheel speed.",
|
||||
"helper": "Adjust how wheel input feels in scrollback and in mouse-aware terminal apps.",
|
||||
"reset": "Reset",
|
||||
"normal": "Normal",
|
||||
"normalDescription": "Scrollback wheel multiplier.",
|
||||
"fast": "Fast",
|
||||
"fastDescription": "Extra multiplier while scrolling with a modifier key.",
|
||||
"title": "스크롤 속도",
|
||||
"description": "일반 터미널 스크롤백, 수정 키 빠른 스크롤, 전체 화면 TUI 휠 속도를 조정합니다.",
|
||||
"helper": "스크롤백과 마우스 지원 터미널 앱에서 휠 입력의 느낌을 조정합니다.",
|
||||
"reset": "재설정",
|
||||
"normal": "일반",
|
||||
"normalDescription": "스크롤백 휠 배율.",
|
||||
"fast": "빠름",
|
||||
"fastDescription": "수정 키로 스크롤할 때의 추가 배율.",
|
||||
"tui": "TUI",
|
||||
"tuiDescription": "Discrete wheel reports for full-screen terminal apps."
|
||||
"tuiDescription": "전체 화면 터미널 앱을 위한 개별 휠 보고."
|
||||
}
|
||||
},
|
||||
"TerminalSettingsPreview": {
|
||||
@@ -7853,8 +7859,8 @@
|
||||
"ask_before_closing_running_terminals_title": "실행 중인 Terminals을 닫기 전에 확인",
|
||||
"ask_before_closing_running_terminals_description": "실행 중인 명령이나 agent가 있는 terminal을 닫기 전에 확인을 표시합니다.",
|
||||
"scrollSpeed": {
|
||||
"title": "Scroll Speed",
|
||||
"description": "Tune normal terminal scrollback, fast modifier scrolling, and full-screen TUI wheel speed."
|
||||
"title": "스크롤 속도",
|
||||
"description": "일반 터미널 스크롤백, 수정 키 빠른 스크롤, 전체 화면 TUI 휠 속도를 조정합니다."
|
||||
}
|
||||
},
|
||||
"windows": {
|
||||
|
||||
@@ -3717,7 +3717,8 @@
|
||||
"2d74665a56": "端口",
|
||||
"65a9820bd1": "Agent 状态",
|
||||
"219ebf1961": "分支名称",
|
||||
"automation": "Automation"
|
||||
"automation": "Automation",
|
||||
"folderPathIdentity": "分支 / 文件夹路径"
|
||||
},
|
||||
"SshDisconnectedDialog": {
|
||||
"ca4a7892af": "正在连接...",
|
||||
@@ -3793,7 +3794,9 @@
|
||||
"021538e1d1": "SSH 已断开连接",
|
||||
"runtimeHostDisconnected": "Server disconnected",
|
||||
"runtimeHostProject": "Project on Orca server",
|
||||
"automationCreated": "Created by automation"
|
||||
"automationCreated": "Created by automation",
|
||||
"branchIdentity": "分支",
|
||||
"branchFolderPathIdentity": "分支或文件夹路径"
|
||||
},
|
||||
"WorktreeCardAgents": {
|
||||
"1b0a156717": "Agents"
|
||||
@@ -4264,6 +4267,9 @@
|
||||
"current": "当前",
|
||||
"searchPlaceholder": "搜索工作树...",
|
||||
"empty": "没有匹配的可用工作树。"
|
||||
},
|
||||
"WorktreeCardStatusSlot": {
|
||||
"branchIdentity": "分支"
|
||||
}
|
||||
},
|
||||
"shared": {
|
||||
@@ -6205,16 +6211,16 @@
|
||||
"ask_before_closing_running_terminals_title": "关闭运行中的 Terminal 前询问",
|
||||
"ask_before_closing_running_terminals_description": "在关闭有运行中命令或 agent 的 terminal 前显示确认。",
|
||||
"scrollSpeed": {
|
||||
"title": "Scroll Speed",
|
||||
"description": "Tune normal terminal scrollback, fast modifier scrolling, and full-screen TUI wheel speed.",
|
||||
"helper": "Adjust how wheel input feels in scrollback and in mouse-aware terminal apps.",
|
||||
"reset": "Reset",
|
||||
"normal": "Normal",
|
||||
"normalDescription": "Scrollback wheel multiplier.",
|
||||
"fast": "Fast",
|
||||
"fastDescription": "Extra multiplier while scrolling with a modifier key.",
|
||||
"title": "滚动速度",
|
||||
"description": "调整普通终端回滚、修饰键快速滚动以及全屏 TUI 鼠标滚轮速度。",
|
||||
"helper": "调整在回滚区域和支持鼠标的终端应用中的滚轮输入手感。",
|
||||
"reset": "重置",
|
||||
"normal": "普通",
|
||||
"normalDescription": "回滚滚轮倍率。",
|
||||
"fast": "快速",
|
||||
"fastDescription": "按住修饰键滚动时的额外倍率。",
|
||||
"tui": "TUI",
|
||||
"tuiDescription": "Discrete wheel reports for full-screen terminal apps."
|
||||
"tuiDescription": "面向全屏终端应用的离散滚轮报告。"
|
||||
}
|
||||
},
|
||||
"TerminalSettingsPreview": {
|
||||
@@ -7853,8 +7859,8 @@
|
||||
"ask_before_closing_running_terminals_title": "关闭运行中的 Terminal 前询问",
|
||||
"ask_before_closing_running_terminals_description": "在关闭有运行中命令或 agent 的 terminal 前显示确认。",
|
||||
"scrollSpeed": {
|
||||
"title": "Scroll Speed",
|
||||
"description": "Tune normal terminal scrollback, fast modifier scrolling, and full-screen TUI wheel speed."
|
||||
"title": "滚动速度",
|
||||
"description": "调整普通终端回滚、修饰键快速滚动以及全屏 TUI 鼠标滚轮速度。"
|
||||
}
|
||||
},
|
||||
"windows": {
|
||||
|
||||
Reference in New Issue
Block a user