mirror of
https://github.com/supabase/supabase.git
synced 2026-09-06 09:59:03 +08:00
## Summary - Unify Explorer toolbar actions: 16px / 2px Lucide icons, `text-tertiary-foreground` that becomes `text-foreground` on hover (Analyze icon goes brand on hover). - Soften chat scroll edges with top/bottom fades, and align the composer width with the conversation content (`px-7` + `max-w-3xl`). - Put **Run SQL** first on Explorer home, and rename the tab-bar new-tab item from “New query” to **Run SQL** so it matches. ## Test plan - [ ] Open Explorer and check query, notebook, and chat toolbars: icons are 16px, muted by default, and go to foreground on hover. Analyze on a notebook with cells: icon goes brand on hover; empty notebook still disables Analyze. - [ ] Open a query tab: source menu, result settings, save, and more-options all look like the other toolbar actions (including while the dropdown is open). - [ ] Open Explorer chat: scroll a long thread and confirm top/bottom fades sit on the chat surface. Composer lines up with message width (not inset extra). - [ ] On Explorer home, **Run SQL** is the first card; clicking it still opens a SQL tab. - [ ] From the tab bar **+** menu, the first item is **Run SQL** (not “New query”); it still creates a SQL tab. **New notebook** and **New chat** still work. Made with [Cursor](https://cursor.com) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **UI Improvements** * Standardized Explorer toolbar icons for consistent sizing and visual weight. * Updated toolbar action colors, hover states, and keyboard-focus visibility. * Reordered Explorer home actions so “Run SQL” appears first. * Renamed “New query” to “Run SQL” in the new-tab menu. * Improved query source and settings toolbar controls. * Refined AI assistant chat layout with centered content, decorative gradients, and improved focus styling. * Added hover styling for the notebook Analyze action. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
143 lines
5.0 KiB
TypeScript
143 lines
5.0 KiB
TypeScript
import { Clipboard, MessageSquare, MoreVertical, Settings, Trash } from 'lucide-react'
|
|
import { useState } from 'react'
|
|
import { toast } from 'sonner'
|
|
import {
|
|
copyToClipboard,
|
|
DropdownMenu,
|
|
DropdownMenuContent,
|
|
DropdownMenuItem,
|
|
DropdownMenuSeparator,
|
|
DropdownMenuTrigger,
|
|
} from 'ui'
|
|
import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
|
|
|
|
import {
|
|
ExplorerToolbar,
|
|
ExplorerToolbarAction,
|
|
ExplorerToolbarActions,
|
|
ExplorerToolbarIcon,
|
|
ExplorerToolbarTitle,
|
|
} from './ExplorerToolbar'
|
|
import { AIAssistantMetadataWarning } from '@/components/ui/AIAssistantPanel/AIAssistantMetadataWarning'
|
|
import type { AssistantChatHeaderProps } from '@/components/ui/AIAssistantPanel/AssistantChat'
|
|
import { ShortcutPills } from '@/components/ui/ShortcutTooltip'
|
|
import { useAiAssistantStateSnapshot } from '@/state/ai-assistant-state'
|
|
import { SHORTCUT_DEFINITIONS, SHORTCUT_IDS } from '@/state/shortcuts/registry'
|
|
import { useShortcut } from '@/state/shortcuts/useShortcut'
|
|
|
|
interface ExplorerChatToolbarProps extends AssistantChatHeaderProps {
|
|
chatId: string
|
|
shortcutsEnabled: boolean
|
|
}
|
|
|
|
export const ExplorerChatToolbar = ({
|
|
chatId,
|
|
shortcutsEnabled,
|
|
isChatLoading,
|
|
showMetadataWarning,
|
|
updatedOptInSinceMCP,
|
|
isHipaaProjectDisallowed,
|
|
aiOptInLevel,
|
|
}: ExplorerChatToolbarProps) => {
|
|
const snap = useAiAssistantStateSnapshot()
|
|
const chat = snap.chats[chatId]
|
|
const [isOptInModalOpen, setIsOptInModalOpen] = useState(false)
|
|
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false)
|
|
|
|
const handleCopyChatId = () => {
|
|
copyToClipboard(chatId, () => toast.success(`Copied chat ID for ${chat?.name}`))
|
|
}
|
|
|
|
const handleSaveName = (name: string) => {
|
|
if (name.trim()) snap.renameChat(chatId, name.trim())
|
|
}
|
|
|
|
const handleDeleteChat = () => {
|
|
snap.deleteChat(chatId)
|
|
setIsDeleteModalOpen(false)
|
|
toast.success(`Deleted "${chat?.name}"`)
|
|
}
|
|
|
|
useShortcut(SHORTCUT_IDS.AI_ASSISTANT_COPY_CHAT_ID, handleCopyChatId, {
|
|
enabled: shortcutsEnabled && !isChatLoading,
|
|
})
|
|
useShortcut(SHORTCUT_IDS.AI_ASSISTANT_OPEN_PERMISSIONS, () => setIsOptInModalOpen(true), {
|
|
enabled: shortcutsEnabled && !isChatLoading,
|
|
})
|
|
|
|
return (
|
|
<div className="z-30 sticky top-0">
|
|
<ExplorerToolbar aria-label="Chat toolbar">
|
|
<ExplorerToolbarIcon>
|
|
<MessageSquare size={16} strokeWidth={2} />
|
|
</ExplorerToolbarIcon>
|
|
<ExplorerToolbarTitle onSaveTitle={handleSaveName}>{chat?.name ?? ''}</ExplorerToolbarTitle>
|
|
<ExplorerToolbarActions>
|
|
<DropdownMenu>
|
|
<DropdownMenuTrigger asChild>
|
|
<ExplorerToolbarAction
|
|
aria-label="More options"
|
|
icon={<MoreVertical size={16} strokeWidth={2} />}
|
|
disabled={isChatLoading}
|
|
/>
|
|
</DropdownMenuTrigger>
|
|
<DropdownMenuContent align="end" className="w-60">
|
|
<DropdownMenuItem className="justify-between" onClick={handleCopyChatId}>
|
|
<div className="flex items-center gap-x-2">
|
|
<Clipboard size={14} />
|
|
<span>Copy chat ID</span>
|
|
</div>
|
|
<ShortcutPills
|
|
sequence={SHORTCUT_DEFINITIONS[SHORTCUT_IDS.AI_ASSISTANT_COPY_CHAT_ID].sequence}
|
|
/>
|
|
</DropdownMenuItem>
|
|
<DropdownMenuItem
|
|
className="justify-between"
|
|
onClick={() => setIsOptInModalOpen(true)}
|
|
>
|
|
<div className="flex items-center gap-x-2">
|
|
<Settings size={14} />
|
|
<span>Permission settings</span>
|
|
</div>
|
|
<ShortcutPills
|
|
sequence={
|
|
SHORTCUT_DEFINITIONS[SHORTCUT_IDS.AI_ASSISTANT_OPEN_PERMISSIONS].sequence
|
|
}
|
|
/>
|
|
</DropdownMenuItem>
|
|
<DropdownMenuSeparator />
|
|
<DropdownMenuItem className="gap-x-2" onClick={() => setIsDeleteModalOpen(true)}>
|
|
<Trash size={14} />
|
|
<span>Delete chat</span>
|
|
</DropdownMenuItem>
|
|
</DropdownMenuContent>
|
|
</DropdownMenu>
|
|
</ExplorerToolbarActions>
|
|
</ExplorerToolbar>
|
|
|
|
<AIAssistantMetadataWarning
|
|
visible={isOptInModalOpen}
|
|
onVisibleChange={setIsOptInModalOpen}
|
|
showMetadataWarning={showMetadataWarning}
|
|
updatedOptInSinceMCP={updatedOptInSinceMCP}
|
|
isHipaaProjectDisallowed={isHipaaProjectDisallowed}
|
|
aiOptInLevel={aiOptInLevel}
|
|
/>
|
|
|
|
<ConfirmationModal
|
|
variant="destructive"
|
|
visible={isDeleteModalOpen}
|
|
title={`Delete "${chat?.name}"?`}
|
|
confirmLabel="Delete chat"
|
|
onCancel={() => setIsDeleteModalOpen(false)}
|
|
onConfirm={handleDeleteChat}
|
|
>
|
|
<p className="text-sm text-foreground-light">
|
|
This will permanently delete this chat and its message history. This action cannot be
|
|
undone.
|
|
</p>
|
|
</ConfirmationModal>
|
|
</div>
|
|
)
|
|
}
|