Files
supabase/apps/studio/components/interfaces/ConnectButton/Connect.Commands.test.tsx
Danny White 25c8194579 feat(studio): add Connect sheet shortcut guidance (#46185)
## What kind of change does this PR introduce?

Feature, docs update.

- Resolves FE-3419
- First pass for DEPR-578

## What is the current behaviour?

The Connect sheet can be opened from visible UI and command-menu
actions, but it does not have a direct keyboard shortcut. Studio also
has shortcut conventions in code, but limited agent-facing review
guidance for contributors adding or touching Studio UI.

## What is the new behaviour?

FE-3419:

- Adds `O then C` to open the Connect sheet for active healthy projects.
- Mounts the shortcut from the always-rendered Connect sheet, so it
works without first opening the lazy command menu.
- Surfaces the shortcut on the Connect button tooltip, in the shortcuts
reference sheet, and on the Connect command-menu action.
- Forces the tooltip closed while the sheet is open so Escape closes the
sheet without also driving tooltip state.
- Tracks keyboard shortcut opens with the existing Connect sheet
telemetry event.
- Moves single-item AI Assistant and Inline Editor shortcuts to the
_Global Actions_ section in the cheatsheet.

DEPR-578:

- Adds a short Studio shortcut convention to `.claude/CLAUDE.md`.
- Adds scoped Copilot review guidance for Studio shortcut coverage,
discovery, and collision checks.
- Points the guidance back to the existing shortcut registry,
`useShortcut`, `Shortcut`, and `ShortcutTooltip` implementation context.

| After |
| --- |
| <img width="1576" height="188" alt="CleanShot 2026-05-21 at 11 30
40@2x"
src="https://github.com/user-attachments/assets/ba9d68c8-27ea-4c89-8016-d95d5bcea3ea"
/> |
| <img width="830" height="364" alt="CleanShot 2026-05-21 at 11 48
51@2x-FC627CB5-4A1C-49E2-B748-8AF0A3EBD7BC"
src="https://github.com/user-attachments/assets/d6aa52c1-56b2-4731-8e6b-088e29da43ed"
/> |

Validation:

- `pnpm --dir apps/studio exec vitest --run
components/ui/GlobalShortcuts/ShortcutsReferenceSheet.test.tsx
components/interfaces/ConnectButton/Connect.Commands.test.tsx
components/interfaces/ConnectSheet/useConnectSheetShortcut.test.ts`
- `git diff --check`

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Keyboard shortcut to open the Connect sheet from anywhere; Connect
button displays the shortcut and is enabled only for eligible projects.
* New "Global Actions" group in the shortcuts reference including AI
Assistant, Inline Editor, and Connect.

* **Documentation**
* Added Studio keyboard-shortcuts guidance and linked it in project
instructions.

* **Tests**
* Added tests covering connect shortcut behavior and command
registration.

* **Telemetry**
  * Connect-sheet open events now record keyboard shortcut as a source.

<!-- review_stack_entry_start -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/46185?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)

<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Ali Waseem <waseema393@gmail.com>
2026-05-21 09:32:22 -06:00

71 lines
2.0 KiB
TypeScript

import { renderHook } from '@testing-library/react'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { useConnectCommands } from './Connect.Commands'
import { PROJECT_STATUS } from '@/lib/constants'
const {
mockSetCommandMenuOpen,
mockSetConnectTab,
mockSetShowConnect,
mockUseRegisterCommands,
mockUseSelectedProjectQuery,
} = vi.hoisted(() => ({
mockSetCommandMenuOpen: vi.fn(),
mockSetConnectTab: vi.fn(),
mockSetShowConnect: vi.fn(),
mockUseRegisterCommands: vi.fn(),
mockUseSelectedProjectQuery: vi.fn(),
}))
vi.mock('ui-patterns/CommandMenu', () => ({
useRegisterCommands: mockUseRegisterCommands,
useSetCommandMenuOpen: () => mockSetCommandMenuOpen,
}))
vi.mock('nuqs', () => ({
parseAsBoolean: { withDefault: vi.fn(() => 'showConnectParser') },
parseAsString: 'stringParser',
useQueryState: (key: string) => {
if (key === 'showConnect') return [false, mockSetShowConnect]
if (key === 'connectTab') return [null, mockSetConnectTab]
return [null, vi.fn()]
},
}))
vi.mock('@/hooks/misc/useSelectedProject', () => ({
useSelectedProjectQuery: mockUseSelectedProjectQuery,
}))
describe('useConnectCommands', () => {
beforeEach(() => {
vi.clearAllMocks()
mockUseSelectedProjectQuery.mockReturnValue({
data: { status: PROJECT_STATUS.ACTIVE_HEALTHY },
})
})
it('shows the shortcut badge on the Connect command', () => {
renderHook(() => useConnectCommands())
const [, commands, options] = mockUseRegisterCommands.mock.calls[0]
expect(options.enabled).toBe(true)
expect(commands[0]).toMatchObject({
id: 'connect-to-project',
name: 'Connect to your project',
})
expect(commands[0].badge).toBeTypeOf('function')
})
it('disables the commands when the selected project cannot connect', () => {
mockUseSelectedProjectQuery.mockReturnValue({
data: { status: PROJECT_STATUS.INACTIVE },
})
renderHook(() => useConnectCommands())
expect(mockUseRegisterCommands.mock.calls[0][2].enabled).toBe(false)
})
})