mirror of
https://github.com/stablyai/orca.git
synced 2026-10-31 00:57:45 +00:00
feat(feature-tips): make Enable Now the full-width action beside a plain Leave Off (#28199)
Drop the 'New agent tabs still open in the terminal' line and the taller frame it needed.
This commit is contained in:
@@ -29,6 +29,7 @@ export function FeatureTipActions({
|
||||
onPrimaryAction: () => void
|
||||
onSkip: () => void
|
||||
showSkip?: boolean
|
||||
/** Fills the footer row, or what a sibling button leaves of it. */
|
||||
fullWidth?: boolean
|
||||
primaryButtonRef?: Ref<HTMLButtonElement>
|
||||
/** Overrides the tip's CTA for tips whose button changes with their state. */
|
||||
@@ -43,7 +44,7 @@ export function FeatureTipActions({
|
||||
) : null}
|
||||
<Button
|
||||
ref={primaryButtonRef}
|
||||
className={fullWidth ? 'w-full' : undefined}
|
||||
className={fullWidth ? 'w-full flex-1' : undefined}
|
||||
onClick={onPrimaryAction}
|
||||
disabled={primaryBusy}
|
||||
>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import type { ComponentProps, JSX, ReactNode } from 'react'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Dialog, DialogContent } from '@/components/ui/dialog'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
/** Shared two-column tip layout: copy and actions on the left, a feature visual on the right. */
|
||||
export function FeatureTipDialogFrame({
|
||||
@@ -9,25 +8,19 @@ export function FeatureTipDialogFrame({
|
||||
onOpenChange,
|
||||
onOpenAutoFocus,
|
||||
visual,
|
||||
tall = false,
|
||||
children
|
||||
}: {
|
||||
open: boolean
|
||||
onOpenChange: (open: boolean) => void
|
||||
onOpenAutoFocus: ComponentProps<typeof DialogContent>['onOpenAutoFocus']
|
||||
visual: ReactNode
|
||||
/** Room for an extra row of copy without scrolling. */
|
||||
tall?: boolean
|
||||
children: ReactNode
|
||||
}): JSX.Element {
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||
<DialogContent
|
||||
surface="feature-tip"
|
||||
className={cn(
|
||||
'!flex max-h-[calc(100vh-2rem)] flex-col overflow-hidden sm:max-w-4xl md:!flex-row',
|
||||
tall ? 'md:!h-[min(33rem,calc(100vh-2rem))]' : 'md:!h-[min(27rem,calc(100vh-2rem))]'
|
||||
)}
|
||||
className="!flex max-h-[calc(100vh-2rem)] flex-col overflow-hidden sm:max-w-4xl md:!h-[min(27rem,calc(100vh-2rem))] md:!flex-row"
|
||||
showCloseButton
|
||||
onOpenAutoFocus={onOpenAutoFocus}
|
||||
>
|
||||
|
||||
@@ -84,30 +84,26 @@ describe('NativeChatUpgradeTipDialog', () => {
|
||||
it('shows only Got It when chat mode is already on', () => {
|
||||
const html = renderDialog(true)
|
||||
const text = textOf(html)
|
||||
expect(text).not.toContain('New agent tabs still open in the terminal')
|
||||
expect(text).not.toContain('Turn on chat mode')
|
||||
expect(text).not.toContain('Enable Now')
|
||||
expect(text).not.toContain('Okay')
|
||||
expect(text).not.toContain('Leave Off')
|
||||
expect(html).not.toContain('role="switch"')
|
||||
expect(html).toContain('27rem')
|
||||
expect(html).not.toContain('33rem')
|
||||
})
|
||||
|
||||
it('offers Okay and Enable Now when chat mode is off, without a switch', () => {
|
||||
it('offers Leave Off and Enable Now when chat mode is off, without a switch', () => {
|
||||
const html = renderDialog(false)
|
||||
const text = textOf(html)
|
||||
expect(text).toContain('New agent tabs still open in the terminal, as before.')
|
||||
expect(text).toContain('Okay')
|
||||
expect(text).toContain('Leave Off')
|
||||
expect(text).toContain('Enable Now')
|
||||
expect(text).not.toContain('Got It')
|
||||
expect(text).not.toContain('Turn on chat mode')
|
||||
expect(html).not.toContain('role="switch"')
|
||||
expect(html).toContain('33rem')
|
||||
expect(html).toContain('27rem')
|
||||
// The way back to the terminal stays in the tip.
|
||||
expect(text).toContain('Resume in New CLI copies a Claude or Codex chat')
|
||||
})
|
||||
|
||||
it('dismisses with Okay and runs the primary action only with Enable Now', () => {
|
||||
it('dismisses with Leave Off and runs the primary action only with Enable Now', () => {
|
||||
const onPrimaryAction = vi.fn()
|
||||
const onOpenChange = vi.fn()
|
||||
const container = document.createElement('div')
|
||||
@@ -115,10 +111,14 @@ describe('NativeChatUpgradeTipDialog', () => {
|
||||
act(() => root.render(dialog(false, onPrimaryAction, onOpenChange)))
|
||||
const buttons = container.querySelectorAll<HTMLButtonElement>('footer button')
|
||||
expect(buttons).toHaveLength(2)
|
||||
expect(buttons[0]?.textContent).toBe('Okay')
|
||||
expect(buttons[0]?.getAttribute('data-variant')).toBe('ghost')
|
||||
expect(buttons[0]?.textContent).toBe('Leave Off')
|
||||
// Leave Off is plain text, not a Button primitive.
|
||||
expect(buttons[0]?.hasAttribute('data-variant')).toBe(false)
|
||||
expect(buttons[1]?.textContent).toBe('Enable Now')
|
||||
expect(buttons[1]?.getAttribute('data-variant')).toBe('default')
|
||||
// Enable Now takes the row width Leave Off leaves.
|
||||
expect(buttons[1]?.classList.contains('flex-1')).toBe(true)
|
||||
expect(buttons[0]?.classList.contains('flex-1')).toBe(false)
|
||||
act(() => buttons[0]?.click())
|
||||
expect(onOpenChange).toHaveBeenCalledWith(false)
|
||||
expect(onPrimaryAction).not.toHaveBeenCalled()
|
||||
@@ -134,7 +134,6 @@ describe('NativeChatUpgradeTipDialog', () => {
|
||||
expect(container.querySelectorAll('footer button')).toHaveLength(1)
|
||||
expect(container.querySelector('footer button')?.textContent).toBe('Got It')
|
||||
expect(container.querySelector('[role="switch"]')).toBeNull()
|
||||
expect(container.textContent).not.toContain('New agent tabs still open in the terminal')
|
||||
act(() => root.unmount())
|
||||
})
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ import { useRef, type JSX } from 'react'
|
||||
import { MessagesSquare, SquareTerminal, type LucideIcon } from 'lucide-react'
|
||||
import type { FeatureTip } from '../../../../shared/feature-tips'
|
||||
import { DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { translate } from '@/i18n/i18n'
|
||||
import { FeatureTipActions } from './FeatureTipActions'
|
||||
import {
|
||||
@@ -83,7 +82,6 @@ export function NativeChatUpgradeTipDialog({
|
||||
primaryButtonRef.current?.focus({ preventScroll: true })
|
||||
}}
|
||||
visual={<NativeChatUpgradeFeatureTipVisual />}
|
||||
tall={offerChatMode}
|
||||
>
|
||||
<DialogHeader className="text-left">
|
||||
<div>
|
||||
@@ -91,14 +89,6 @@ export function NativeChatUpgradeTipDialog({
|
||||
<DialogTitle size="display">
|
||||
{translate('featureTips.nativeChatUpgrade.title', 'Native chat got an upgrade')}
|
||||
</DialogTitle>
|
||||
{offerChatMode ? (
|
||||
<p className="mt-3 text-sm leading-relaxed text-muted-foreground">
|
||||
{translate(
|
||||
'featureTips.nativeChatUpgrade.chatModeNote',
|
||||
'New agent tabs still open in the terminal, as before.'
|
||||
)}
|
||||
</p>
|
||||
) : null}
|
||||
<DialogDescription className="mt-3 max-w-2xl">
|
||||
<span className="block space-y-3 leading-relaxed">
|
||||
<span className="block">
|
||||
@@ -156,11 +146,17 @@ export function NativeChatUpgradeTipDialog({
|
||||
</div>
|
||||
</DialogHeader>
|
||||
|
||||
<DialogFooter className="mt-8 flex sm:justify-end">
|
||||
<DialogFooter className="mt-8 flex flex-row items-center">
|
||||
{offerChatMode ? (
|
||||
<Button variant="ghost" onClick={() => onOpenChange(false)} disabled={primaryBusy}>
|
||||
{translate('featureTips.nativeChatUpgrade.okay', 'Okay')}
|
||||
</Button>
|
||||
// Why: plain text, flush with the copy, so Enable Now reads as the only button.
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => onOpenChange(false)}
|
||||
disabled={primaryBusy}
|
||||
className="mr-4 shrink-0 cursor-pointer rounded-sm text-sm font-medium whitespace-nowrap text-muted-foreground transition-colors outline-none hover:text-foreground focus-visible:text-foreground focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50"
|
||||
>
|
||||
{translate('featureTips.nativeChatUpgrade.leaveOff', 'Leave Off')}
|
||||
</button>
|
||||
) : null}
|
||||
<FeatureTipActions
|
||||
currentTip={tip}
|
||||
@@ -168,7 +164,7 @@ export function NativeChatUpgradeTipDialog({
|
||||
onPrimaryAction={onPrimaryAction}
|
||||
onSkip={() => onOpenChange(false)}
|
||||
showSkip={false}
|
||||
fullWidth={!offerChatMode}
|
||||
fullWidth
|
||||
primaryButtonRef={primaryButtonRef}
|
||||
label={
|
||||
offerChatMode
|
||||
|
||||
@@ -19232,8 +19232,7 @@
|
||||
"nativeChatUpgrade": {
|
||||
"eyebrow": "New",
|
||||
"title": "Native chat got an upgrade",
|
||||
"chatModeNote": "New agent tabs still open in the terminal, as before.",
|
||||
"okay": "Okay",
|
||||
"leaveOff": "Leave Off",
|
||||
"enableNow": "Enable Now",
|
||||
"enableError": "Could not enable chat mode.",
|
||||
"intro": "New chats with supported agents now open in the upgraded chat view. To move between chat and CLI, open {{panel}} in the right sidebar:",
|
||||
|
||||
@@ -19073,7 +19073,6 @@
|
||||
"nativeChatUpgrade": {
|
||||
"eyebrow": "Nuevo",
|
||||
"title": "El chat nativo mejora",
|
||||
"chatModeNote": "Las pestañas de agente nuevas siguen abriéndose en la terminal, como antes.",
|
||||
"intro": "Los chats nuevos de agentes compatibles usan la vista de chat mejorada. Para alternar entre chat y CLI, abre {{panel}} (barra lateral derecha):",
|
||||
"resumeInNativeChat": "{{action}} abre una conversación de CLI compatible en el chat nativo.",
|
||||
"resumeInCli": "{{action}} copia un chat de Claude/Codex a una CLI nueva sin tocar el original.",
|
||||
|
||||
@@ -19050,7 +19050,6 @@
|
||||
"nativeChatUpgrade": {
|
||||
"eyebrow": "Nouveau",
|
||||
"title": "Le chat natif évolue",
|
||||
"chatModeNote": "Les nouveaux onglets d'agent s'ouvrent toujours dans le terminal, comme avant.",
|
||||
"intro": "Les nouveaux chats des agents compatibles utilisent la vue améliorée. Pour alterner entre chat et CLI, ouvrez {{panel}} (barre latérale droite) :",
|
||||
"resumeInNativeChat": "{{action}} ouvre une conversation CLI compatible dans le chat natif.",
|
||||
"resumeInCli": "{{action}} copie un chat Claude/Codex dans une CLI neuve ; l'original reste intact.",
|
||||
|
||||
@@ -19101,7 +19101,6 @@
|
||||
"nativeChatUpgrade": {
|
||||
"eyebrow": "新機能",
|
||||
"title": "ネイティブチャットを刷新",
|
||||
"chatModeNote": "新しい Agent タブは、これまでどおりターミナルで開きます。",
|
||||
"intro": "対応 Agent の新しいチャットはアップグレード版のチャットビューで開きます。チャットと CLI の切り替えは右サイドバーの{{panel}}から:",
|
||||
"resumeInNativeChat": "{{action}}: 対応する CLI の会話をネイティブチャットで開きます。",
|
||||
"resumeInCli": "{{action}}: Claude/Codex のチャットを新しい CLI セッションに複製します。元のチャットは残ります。",
|
||||
|
||||
@@ -19131,7 +19131,6 @@
|
||||
"nativeChatUpgrade": {
|
||||
"eyebrow": "새 기능",
|
||||
"title": "기본 채팅이 업그레이드되었습니다",
|
||||
"chatModeNote": "새 Agent 탭은 이전처럼 터미널에서 열립니다.",
|
||||
"intro": "이제 지원되는 Agent의 새 채팅은 업그레이드된 채팅 보기에서 열립니다. 채팅과 CLI 사이를 오가려면 오른쪽 사이드바에서 {{panel}}을 여세요:",
|
||||
"resumeInNativeChat": "{{action}}: 지원되는 CLI 대화를 기본 채팅에서 엽니다.",
|
||||
"resumeInCli": "{{action}}: Claude 또는 Codex 채팅을 새 CLI 세션으로 복사합니다. 원래 채팅은 그대로 유지됩니다.",
|
||||
|
||||
@@ -19115,7 +19115,6 @@
|
||||
"nativeChatUpgrade": {
|
||||
"eyebrow": "新功能",
|
||||
"title": "本机聊天已升级",
|
||||
"chatModeNote": "新的智能体标签页仍像以前一样在终端中打开。",
|
||||
"intro": "受支持智能体的新聊天现在会在升级后的聊天视图中打开。要在聊天和 CLI 之间切换,请打开右侧边栏中的{{panel}}:",
|
||||
"resumeInNativeChat": "{{action}}:在本机聊天中打开受支持的 CLI 对话。",
|
||||
"resumeInCli": "{{action}}:将 Claude 或 Codex 聊天复制到新的 CLI 会话中。原始聊天保持不变。",
|
||||
|
||||
Reference in New Issue
Block a user