Keep 'Not now' as the safe dismiss; demote 'Don't show again' to a muted link

This modal auto-opens unsolicited (first activation of a Linear-linked
worktree with the skill missing), so the reflexive dismiss must be
non-destructive. Removing 'Not now' left the permanent 'Don't show again'
as the only labeled footer button — the reflexive target — which would
nuke a useful prompt forever.

Restore 'Not now' (session snooze) as a quiet ghost — the easy, safe
dismiss, matching Neil's original ask ('not now is fine, just not the
CTA'). Demote 'Don't show again' to a muted text link so permanent
suppression takes intent. Install stays the filled primary.

Restores onSnoozeForSession wiring + notNow i18n key (all locales);
tests exercise the Not now snooze path again.
This commit is contained in:
Brennan Benson
2026-07-20 19:17:31 -07:00
parent 24e60e556d
commit 9468b00959
9 changed files with 31 additions and 16 deletions
@@ -35,6 +35,7 @@ type LinearAgentSkillSetupDialogProps = {
onRecheck: AgentSkillSetupPanelProps['onRecheck']
onOpenChange: (open: boolean) => void
onDismissPermanently: () => void
onSnoozeForSession: () => void
onDone: () => void
}
@@ -54,6 +55,7 @@ export function LinearAgentSkillSetupDialog({
onRecheck,
onOpenChange,
onDismissPermanently,
onSnoozeForSession,
onDone
}: LinearAgentSkillSetupDialogProps): React.JSX.Element {
return (
@@ -152,17 +154,26 @@ export function LinearAgentSkillSetupDialog({
onBeforeOpenTerminal={onBeforeOpenTerminal}
onRecheck={onRecheck}
/>
{/* Why: the dialog's × already dismisses-for-session (onOpenChange), so a
separate "Not now" button was redundant and, styled as the footer CTA,
read as the primary action over Install. Keep only the distinct
permanent-dismiss action. */}
<DialogFooter className="px-6 pb-6">
<Button type="button" variant="ghost" size="sm" onClick={onDismissPermanently}>
{/* Why: this modal auto-opens unsolicited, so the reflexive dismiss must be
the non-destructive one. "Not now" (session snooze, same as the ×) is the
easy ghost target; permanent "Don't show again" is demoted to a quiet muted
link so nuking the prompt takes intent. Install stays the filled primary. */}
<DialogFooter className="px-6 pb-6 sm:items-center sm:justify-between">
<Button
type="button"
variant="link"
size="sm"
className="h-auto p-0 text-muted-foreground hover:text-foreground"
onClick={onDismissPermanently}
>
{translate(
'auto.components.sidebar.LinearAgentSkillSetupPrompt.dontShowAgain',
"Don't show again"
)}
</Button>
<Button type="button" variant="ghost" size="sm" onClick={onSnoozeForSession}>
{translate('auto.components.sidebar.LinearAgentSkillSetupPrompt.notNow', 'Not now')}
</Button>
</DialogFooter>
</>
)}
@@ -143,9 +143,8 @@ async function snoozeInitialModal(
props: ComponentProps<typeof LinearAgentSkillSetupPrompt>
): Promise<void> {
await renderPrompt(props)
// Why: "Not now" was removed; the dialog's × drives the session snooze now.
await act(async () => {
findBodyButton('Close')?.dispatchEvent(new MouseEvent('click', { bubbles: true }))
findBodyButton('Not now')?.dispatchEvent(new MouseEvent('click', { bubbles: true }))
})
await unmountPrompt()
}
@@ -204,7 +203,7 @@ describe('LinearAgentSkillSetupPrompt reminder toast', () => {
Reflect.deleteProperty(window, 'api')
})
it('shows a warning toast on a later modal-only activation after a casual close', async () => {
it('shows a warning toast on a later modal-only activation after Not now', async () => {
await snoozeInitialModal({ linked: true, remote: false, surface: 'modal' })
await renderPrompt({ linked: true, remote: false, surface: 'modal' })
@@ -452,7 +452,7 @@ describe('LinearAgentSkillSetupPrompt', () => {
)
})
it('auto-opens as a modal-only prompt and treats the × close as a casual snooze', async () => {
it('auto-opens as a modal-only prompt and treats Not now as a casual snooze', async () => {
await renderPrompt({ linked: true, remote: false, surface: 'modal' })
expect(container?.textContent).not.toContain('Set up Linear agent skill')
@@ -461,20 +461,19 @@ describe('LinearAgentSkillSetupPrompt', () => {
)
expect(document.body.textContent).toContain('Orca CLI and Linear agent skill are missing.')
expect(document.body.textContent).toContain('Mock install')
expect(document.body.textContent).not.toContain('Not now')
expect(mocks.panelProps.at(-1)).toEqual(
expect.objectContaining({
preInstallNotice: 'CLI registration notice'
})
)
// Why: "Not now" was removed; the dialog's × is the casual dismiss and must snooze
// (session-only) rather than persist a permanent dismissal.
const closeButton = Array.from(document.body.querySelectorAll('button')).find(
(button) => button.textContent === 'Close'
// Why: the unsolicited modal's labeled dismiss is the non-destructive one, so
// "Not now" must snooze for the session, not persist a permanent dismissal.
const notNowButton = Array.from(document.body.querySelectorAll('button')).find(
(button) => button.textContent === 'Not now'
)
await act(async () => {
closeButton?.dispatchEvent(new MouseEvent('click', { bubbles: true }))
notNowButton?.dispatchEvent(new MouseEvent('click', { bubbles: true }))
})
expect(window.localStorage.getItem(HOST_DISMISS_STORAGE_KEY)).toBeNull()
@@ -338,6 +338,7 @@ export function LinearAgentSkillSetupPrompt({
setSetupDialogOpen(false)
}}
onDismissPermanently={dismissPermanently}
onSnoozeForSession={snoozeForSession}
onDone={closeSuccessModal}
/>
)
+1
View File
@@ -4672,6 +4672,7 @@
"modalDescription": "Install the Linear skill from a terminal.",
"modalPrompt": "Enable agents to read and edit the attached Linear ticket.",
"dontShowAgain": "Don't show again",
"notNow": "Not now",
"missingBoth": "Orca CLI and Linear agent skill are missing.",
"missingCli": "Orca CLI is missing.",
"missingSkill": "Linear agent skill is missing.",
+1
View File
@@ -4584,6 +4584,7 @@
"modalDescription": "Instala el skill de Linear desde una terminal.",
"modalPrompt": "Permite que los Agents lean y editen el issue de Linear adjunto.",
"dontShowAgain": "No volver a mostrar",
"notNow": "Ahora no",
"missingBoth": "Faltan la CLI de Orca y el skill de Linear para Agents.",
"missingCli": "Falta la CLI de Orca.",
"missingSkill": "Falta el skill de Linear para Agents.",
+1
View File
@@ -4584,6 +4584,7 @@
"modalDescription": "terminal から Linear スキルをインストールします。",
"modalPrompt": "Agents が添付された Linear チケットを読み書きできるようにします。",
"dontShowAgain": "今後表示しない",
"notNow": "後で",
"missingBoth": "Orca CLI と Linear agent スキルがありません。",
"missingCli": "Orca CLI がありません。",
"missingSkill": "Linear agent スキルがありません。",
+1
View File
@@ -4584,6 +4584,7 @@
"modalDescription": "terminal에서 Linear 스킬을 설치합니다.",
"modalPrompt": "agents가 첨부된 Linear 티켓을 읽고 편집할 수 있게 합니다.",
"dontShowAgain": "다시 표시하지 않음",
"notNow": "나중에",
"missingBoth": "Orca CLI와 Linear agent 스킬이 없습니다.",
"missingCli": "Orca CLI가 없습니다.",
"missingSkill": "Linear agent 스킬이 없습니다.",
+1
View File
@@ -4584,6 +4584,7 @@
"modalDescription": "从终端安装 Linear 技能。",
"modalPrompt": "允许智能体读取和编辑已附加的 Linear ticket。",
"dontShowAgain": "不再显示",
"notNow": "暂不",
"missingBoth": "缺少 Orca CLI 和 Linear 智能体技能。",
"missingCli": "缺少 Orca CLI。",
"missingSkill": "缺少 Linear 智能体技能。",