mirror of
https://github.com/stablyai/orca.git
synced 2026-11-14 01:47:24 +00:00
Use one shared Hide button for chat cards (#38999)
* feat(native-chat): one Hide button and toast for chat cards; PR card setting beside Changed files The opened-PR card now uses the changed-files card's Hide control and Hidden toast through a shared NativeChatCardHideButton, and its switch moves to Settings > Chat UI > Appearance next to Changed files summary, where Reset restores both. The saved key is unchanged. * refactor(native-chat): read the opened-PR card switch through its predicate * test(settings): Reset turns both hidden chat cards back on * Preserve the existing opened pull request Hide aria label * fix(native-chat): keep the gap before the PR card's Hide button
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
import { EyeOff } from 'lucide-react'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'
|
||||
import { translate } from '@/i18n/i18n'
|
||||
import { hideNativeChatCardKind } from './native-chat-card-kind-hidden-toast'
|
||||
import type { GlobalSettings } from '../../../../shared/global-settings-types'
|
||||
|
||||
/** Put on a hideable chat card's outer element so its Hide button reveals on card hover. */
|
||||
export const NATIVE_CHAT_HIDEABLE_CARD_CLASS = 'group/chat-card'
|
||||
|
||||
/** The Hide icon at the end of a chat card's header, shown on card hover or keyboard focus. */
|
||||
export function NativeChatCardHideButton({
|
||||
updates,
|
||||
settingSectionId,
|
||||
hiddenMessage,
|
||||
ariaLabel
|
||||
}: {
|
||||
updates: Partial<GlobalSettings>
|
||||
settingSectionId: string
|
||||
hiddenMessage: string
|
||||
ariaLabel?: string
|
||||
}): React.JSX.Element {
|
||||
const label = translate('components.native-chat.turnDiff.hide', 'Hide')
|
||||
return (
|
||||
// Keep the header one text line tall, as the transcript row-height estimate assumes.
|
||||
<span className="-my-1 ml-auto flex shrink-0 transition-opacity can-hover:pointer-events-none can-hover:opacity-0 group-hover/chat-card:pointer-events-auto group-hover/chat-card:opacity-100 has-[:focus-visible]:pointer-events-auto has-[:focus-visible]:opacity-100">
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon-xs"
|
||||
aria-label={ariaLabel ?? label}
|
||||
onClick={() => void hideNativeChatCardKind(updates, settingSectionId, hiddenMessage)}
|
||||
>
|
||||
<EyeOff aria-hidden className="size-3.5" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="top" sideOffset={4}>
|
||||
{label}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import { defineFixture } from '../../component-fixtures/component-fixture'
|
||||
import { NativeChatOpenedPullRequestCard } from './NativeChatOpenedPullRequestCard'
|
||||
import type { NativeChatOpenedPullRequest } from '../../../../shared/native-chat/tools/native-chat-opened-pull-requests'
|
||||
|
||||
const pullRequest: NativeChatOpenedPullRequest = {
|
||||
provider: 'github',
|
||||
url: 'https://github.com/stablyai/orca/pull/3',
|
||||
slug: { owner: 'stablyai', repo: 'orca' },
|
||||
number: 3
|
||||
}
|
||||
|
||||
// Keyboard focus shows the Hide button, as card hover does, without a pointer in the headless shot.
|
||||
function focusHide(frame: HTMLElement): void {
|
||||
frame.ownerDocument.dispatchEvent(new KeyboardEvent('keydown', { key: 'Tab', bubbles: true }))
|
||||
frame.querySelector<HTMLButtonElement>('button')?.focus()
|
||||
}
|
||||
|
||||
export const card = defineFixture({
|
||||
width: 560,
|
||||
render: () => <NativeChatOpenedPullRequestCard pullRequests={[pullRequest]} />
|
||||
})
|
||||
export const hideShown = defineFixture({
|
||||
width: 560,
|
||||
render: () => <NativeChatOpenedPullRequestCard pullRequests={[pullRequest]} />,
|
||||
interact: focusHide
|
||||
})
|
||||
@@ -10,7 +10,6 @@ import {
|
||||
import { GitPullRequest } from 'lucide-react'
|
||||
import { translate } from '@/i18n/i18n'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { EyeOffDismissButton } from '@/components/dismiss/EyeOffDismissButton'
|
||||
import { getReviewStateIcon } from '@/components/github/review-state-presentation'
|
||||
import { DiffLineCounts } from '@/components/right-sidebar/source-control/listing/diff-line-counts'
|
||||
import type { GitHubIssueOrPRLink } from '../../../../shared/github/links'
|
||||
@@ -20,7 +19,10 @@ import {
|
||||
type NativeChatOpenedPullRequest
|
||||
} from '../../../../shared/native-chat/tools/native-chat-opened-pull-requests'
|
||||
import { NATIVE_CHAT_OPENED_PULL_REQUESTS_SETTING_SECTION_ID } from '../settings/chat/native-chat-opened-pull-requests-setting-target'
|
||||
import { hideNativeChatCardKind } from './native-chat-card-kind-hidden-toast'
|
||||
import {
|
||||
NativeChatCardHideButton,
|
||||
NATIVE_CHAT_HIDEABLE_CARD_CLASS
|
||||
} from './NativeChatCardHideButton'
|
||||
import {
|
||||
githubLinkPreviewKey,
|
||||
loadGitHubLinkPreview,
|
||||
@@ -214,8 +216,10 @@ export function NativeChatOpenedPullRequestCard({
|
||||
const [first] = pullRequests
|
||||
const { githubRepo } = useContext(NativeChatLinkPeekContext)
|
||||
return (
|
||||
<div className="group relative rounded-lg border border-chat-code-border p-2 text-sm">
|
||||
<div className="flex min-w-0 items-center px-1 pb-1 pr-6 text-xs text-chat-foreground-faint">
|
||||
<div
|
||||
className={`${NATIVE_CHAT_HIDEABLE_CARD_CLASS} rounded-lg border border-chat-code-border p-2 text-sm`}
|
||||
>
|
||||
<div className="flex min-w-0 items-center gap-1.5 px-1 pb-1 text-xs text-chat-foreground-faint">
|
||||
<span className="min-w-0 truncate">
|
||||
{pullRequests.length === 1 && first
|
||||
? translate('components.native-chat.openedPullRequests.one', 'Opened {{name}}', {
|
||||
@@ -227,24 +231,19 @@ export function NativeChatOpenedPullRequestCard({
|
||||
{ count: pullRequests.length, defaultValue_one: 'Opened {{count}} pull request' }
|
||||
)}
|
||||
</span>
|
||||
<NativeChatCardHideButton
|
||||
ariaLabel={translate(
|
||||
'components.native-chat.openedPullRequests.hide',
|
||||
"Don't show opened pull requests"
|
||||
)}
|
||||
updates={{ nativeChatOpenedPullRequests: false }}
|
||||
settingSectionId={NATIVE_CHAT_OPENED_PULL_REQUESTS_SETTING_SECTION_ID}
|
||||
hiddenMessage={translate(
|
||||
'components.native-chat.openedPullRequests.hidden',
|
||||
"Orca won't show opened pull requests anymore"
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<EyeOffDismissButton
|
||||
label={translate(
|
||||
'components.native-chat.openedPullRequests.hide',
|
||||
"Don't show opened pull requests"
|
||||
)}
|
||||
onClick={() =>
|
||||
void hideNativeChatCardKind(
|
||||
{ nativeChatOpenedPullRequests: false },
|
||||
NATIVE_CHAT_OPENED_PULL_REQUESTS_SETTING_SECTION_ID,
|
||||
translate(
|
||||
'components.native-chat.openedPullRequests.hidden',
|
||||
"Orca won't show opened pull requests anymore"
|
||||
)
|
||||
)
|
||||
}
|
||||
className="absolute right-1.5 top-1.5 opacity-0 focus-visible:opacity-100 group-focus-within:opacity-100 group-hover:opacity-100"
|
||||
/>
|
||||
<div className="space-y-0.5">
|
||||
{pullRequests.map((pullRequest) => (
|
||||
<OpenedPullRequestRow
|
||||
|
||||
@@ -69,6 +69,15 @@ export const opened = defineFixture({
|
||||
frame.querySelector<HTMLButtonElement>('button')?.click()
|
||||
}
|
||||
})
|
||||
export const hideShown = defineFixture({
|
||||
width: 560,
|
||||
render: () => <NativeChatTurnDiffRollup diff={diff} />,
|
||||
// Keyboard focus shows the Hide button, as card hover does, without a pointer in the headless shot.
|
||||
interact: (frame) => {
|
||||
frame.ownerDocument.dispatchEvent(new KeyboardEvent('keydown', { key: 'Tab', bubbles: true }))
|
||||
frame.querySelector<HTMLButtonElement>('button[aria-label="Hide"]')?.focus()
|
||||
}
|
||||
})
|
||||
|
||||
const session: NativeChatLiveSession = {
|
||||
messages,
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import { ChevronRight, EyeOff } from 'lucide-react'
|
||||
import { ChevronRight } from 'lucide-react'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'
|
||||
import { translate } from '@/i18n/i18n'
|
||||
import { NATIVE_CHAT_TURN_DIFF_SETTING_SECTION_ID } from '../settings/chat/native-chat-turn-diff-setting-target'
|
||||
import { DiffLineCounts } from '../right-sidebar/source-control/listing/diff-line-counts'
|
||||
import { NativeChatDiffCard } from './NativeChatDiffCard'
|
||||
import { NativeChatExpandable } from './NativeChatExpandable'
|
||||
import { hideNativeChatCardKind } from './native-chat-card-kind-hidden-toast'
|
||||
import {
|
||||
NativeChatCardHideButton,
|
||||
NATIVE_CHAT_HIDEABLE_CARD_CLASS
|
||||
} from './NativeChatCardHideButton'
|
||||
import { useNativeChatDisclosure } from './native-chat-disclosure-store'
|
||||
import { nativeChatEditFileBaseName } from '../../../../shared/native-chat/tools/native-chat-edit-model'
|
||||
import {
|
||||
@@ -63,14 +65,6 @@ function TurnDiffFileRow({ file }: { file: NativeChatTurnDiffFile }): React.JSX.
|
||||
)
|
||||
}
|
||||
|
||||
function hideTurnDiffs(): Promise<void> {
|
||||
return hideNativeChatCardKind(
|
||||
{ nativeChatTurnDiffSummary: false },
|
||||
NATIVE_CHAT_TURN_DIFF_SETTING_SECTION_ID,
|
||||
translate('components.native-chat.turnDiff.hidden', "Orca won't show turn diffs anymore")
|
||||
)
|
||||
}
|
||||
|
||||
export function NativeChatTurnDiffRollup({
|
||||
diff
|
||||
}: {
|
||||
@@ -83,7 +77,9 @@ export function NativeChatTurnDiffRollup({
|
||||
const files = showAll ? diff.files : diff.files.slice(0, NATIVE_CHAT_TURN_DIFF_FILE_LIMIT)
|
||||
const remaining = diff.files.length - files.length
|
||||
return (
|
||||
<div className="group/turn-diff rounded-lg border border-chat-code-border p-2 text-xs text-chat-foreground-faint">
|
||||
<div
|
||||
className={`${NATIVE_CHAT_HIDEABLE_CARD_CLASS} rounded-lg border border-chat-code-border p-2 text-xs text-chat-foreground-faint`}
|
||||
>
|
||||
<div className="flex min-w-0 items-center gap-1.5 px-1 pb-1">
|
||||
<span className="min-w-0 truncate">
|
||||
{translate('components.native-chat.turnDiff.changedFiles', '{{count}} changed files', {
|
||||
@@ -95,25 +91,14 @@ export function NativeChatTurnDiffRollup({
|
||||
{diff.truncated ? (
|
||||
<span>{translate('components.native-chat.turnDiff.partial', 'Partial diff')}</span>
|
||||
) : null}
|
||||
{/* Shown on card hover or keyboard focus, like the transcript's other row actions. The
|
||||
negative margin keeps the header one text line tall, as the row-height estimate assumes. */}
|
||||
<span className="-my-1 ml-auto flex shrink-0 transition-opacity can-hover:pointer-events-none can-hover:opacity-0 group-hover/turn-diff:pointer-events-auto group-hover/turn-diff:opacity-100 has-[:focus-visible]:pointer-events-auto has-[:focus-visible]:opacity-100">
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon-xs"
|
||||
aria-label={translate('components.native-chat.turnDiff.hide', 'Hide')}
|
||||
onClick={() => void hideTurnDiffs()}
|
||||
>
|
||||
<EyeOff aria-hidden className="size-3.5" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="top" sideOffset={4}>
|
||||
{translate('components.native-chat.turnDiff.hide', 'Hide')}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</span>
|
||||
<NativeChatCardHideButton
|
||||
updates={{ nativeChatTurnDiffSummary: false }}
|
||||
settingSectionId={NATIVE_CHAT_TURN_DIFF_SETTING_SECTION_ID}
|
||||
hiddenMessage={translate(
|
||||
'components.native-chat.turnDiff.hidden',
|
||||
"Orca won't show turn diffs anymore"
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
{files.map((file) => (
|
||||
|
||||
Reference in New Issue
Block a user