From 94fcb91567b1509f577d5cdfd04cfbf158d53193 Mon Sep 17 00:00:00 2001 From: Saxon Fletcher Date: Thu, 23 Oct 2025 15:05:19 +1000 Subject: [PATCH] more ai spots --- .../DeployEdgeFunctionButton.tsx | 6 ++-- .../interfaces/Home/AdvisorWidget.tsx | 5 ++- .../interfaces/HomeNew/AdvisorSection.tsx | 1 - .../interfaces/Linter/LintDetail.tsx | 5 ++- .../LayoutHeader/HelpPopover.tsx | 5 ++- .../LayoutSidebarProvider.test.tsx | 10 ++---- .../LayoutSidebar/index.test.tsx | 34 +++---------------- .../pages/project/[ref]/functions/new.tsx | 5 ++- 8 files changed, 27 insertions(+), 44 deletions(-) diff --git a/apps/studio/components/interfaces/EdgeFunctions/DeployEdgeFunctionButton.tsx b/apps/studio/components/interfaces/EdgeFunctions/DeployEdgeFunctionButton.tsx index 9412f8ae035..d591e1cb74d 100644 --- a/apps/studio/components/interfaces/EdgeFunctions/DeployEdgeFunctionButton.tsx +++ b/apps/studio/components/interfaces/EdgeFunctions/DeployEdgeFunctionButton.tsx @@ -19,13 +19,15 @@ import { DropdownMenuItem, DropdownMenuTrigger, } from 'ui' +import { SIDEBAR_KEYS } from 'components/layouts/ProjectLayout/LayoutSidebar/LayoutSidebarProvider' +import { useSidebarManagerSnapshot } from 'state/sidebar-manager-state' export const DeployEdgeFunctionButton = () => { const router = useRouter() const { ref } = useParams() const { data: org } = useSelectedOrganizationQuery() const snap = useAiAssistantStateSnapshot() - + const { openSidebar } = useSidebarManagerSnapshot() const { mutate: sendEvent } = useSendEventMutation() return ( @@ -85,9 +87,9 @@ export const DeployEdgeFunctionButton = () => { { + openSidebar(SIDEBAR_KEYS.AI_ASSISTANT) snap.newChat({ name: 'Create new edge function', - open: true, initialInput: `Create a new edge function that ...`, suggestions: { title: diff --git a/apps/studio/components/interfaces/Home/AdvisorWidget.tsx b/apps/studio/components/interfaces/Home/AdvisorWidget.tsx index 102ebdd4229..9a7555a3249 100644 --- a/apps/studio/components/interfaces/Home/AdvisorWidget.tsx +++ b/apps/studio/components/interfaces/Home/AdvisorWidget.tsx @@ -27,6 +27,8 @@ import { TabsTrigger_Shadcn_ as TabsTrigger, } from 'ui' import ShimmeringLoader from 'ui-patterns/ShimmeringLoader' +import { SIDEBAR_KEYS } from 'components/layouts/ProjectLayout/LayoutSidebar/LayoutSidebarProvider' +import { useSidebarManagerSnapshot } from 'state/sidebar-manager-state' interface SlowQuery { rolname: string @@ -45,6 +47,7 @@ export const AdvisorWidget = () => { } ) const snap = useAiAssistantStateSnapshot() + const { openSidebar } = useSidebarManagerSnapshot() const securityLints = useMemo( () => (lints ?? []).filter((lint: Lint) => lint.categories.includes('SECURITY')), @@ -147,9 +150,9 @@ export const AdvisorWidget = () => { onClick={(e) => { e.stopPropagation() e.preventDefault() + openSidebar(SIDEBAR_KEYS.AI_ASSISTANT) snap.newChat({ name: 'Summarize lint', - open: true, initialInput: `Summarize the issue and suggest fixes for the following lint item: Title: ${lintInfoMap.find((item) => item.name === lint.name)?.title ?? lint.title} Entity: ${(lint.metadata && (lint.metadata.entity || (lint.metadata.schema && lint.metadata.name && `${lint.metadata.schema}.${lint.metadata.name}`))) ?? 'N/A'} diff --git a/apps/studio/components/interfaces/HomeNew/AdvisorSection.tsx b/apps/studio/components/interfaces/HomeNew/AdvisorSection.tsx index 8d2e466e4b0..65712114d80 100644 --- a/apps/studio/components/interfaces/HomeNew/AdvisorSection.tsx +++ b/apps/studio/components/interfaces/HomeNew/AdvisorSection.tsx @@ -141,7 +141,6 @@ export const AdvisorSection = () => { e.preventDefault() snap.newChat({ name: 'Summarize lint', - open: true, initialInput: createLintSummaryPrompt(lint), }) if (projectRef && organization?.slug) { diff --git a/apps/studio/components/interfaces/Linter/LintDetail.tsx b/apps/studio/components/interfaces/Linter/LintDetail.tsx index d27463cf257..f5c04d4d806 100644 --- a/apps/studio/components/interfaces/Linter/LintDetail.tsx +++ b/apps/studio/components/interfaces/Linter/LintDetail.tsx @@ -8,6 +8,8 @@ import { ExternalLink } from 'lucide-react' import { useAiAssistantStateSnapshot } from 'state/ai-assistant-state' import { AiIconAnimation, Button } from 'ui' import { EntityTypeIcon, LintCTA, LintEntity } from './Linter.utils' +import { SIDEBAR_KEYS } from 'components/layouts/ProjectLayout/LayoutSidebar/LayoutSidebarProvider' +import { useSidebarManagerSnapshot } from 'state/sidebar-manager-state' interface LintDetailProps { lint: Lint @@ -17,6 +19,7 @@ interface LintDetailProps { const LintDetail = ({ lint, projectRef, onAskAssistant }: LintDetailProps) => { const snap = useAiAssistantStateSnapshot() + const { openSidebar } = useSidebarManagerSnapshot() return (
@@ -41,9 +44,9 @@ const LintDetail = ({ lint, projectRef, onAskAssistant }: LintDetailProps) => { icon={} onClick={() => { onAskAssistant?.() + openSidebar(SIDEBAR_KEYS.AI_ASSISTANT) snap.newChat({ name: 'Summarize lint', - open: true, initialInput: createLintSummaryPrompt(lint), }) }} diff --git a/apps/studio/components/layouts/ProjectLayout/LayoutHeader/HelpPopover.tsx b/apps/studio/components/layouts/ProjectLayout/LayoutHeader/HelpPopover.tsx index cf226207bb2..87a65ed455e 100644 --- a/apps/studio/components/layouts/ProjectLayout/LayoutHeader/HelpPopover.tsx +++ b/apps/studio/components/layouts/ProjectLayout/LayoutHeader/HelpPopover.tsx @@ -20,12 +20,15 @@ import { PopoverTrigger_Shadcn_, Popover_Shadcn_, } from 'ui' +import { SIDEBAR_KEYS } from '../LayoutSidebar/LayoutSidebarProvider' +import { useSidebarManagerSnapshot } from 'state/sidebar-manager-state' export const HelpPopover = () => { const router = useRouter() const { data: project } = useSelectedProjectQuery() const { data: org } = useSelectedOrganizationQuery() const snap = useAiAssistantStateSnapshot() + const { openSidebar } = useSidebarManagerSnapshot() const { mutate: sendEvent } = useSendEventMutation() @@ -69,9 +72,9 @@ export const HelpPopover = () => { size="tiny" icon={} onClick={() => { + openSidebar(SIDEBAR_KEYS.AI_ASSISTANT) snap.newChat({ name: 'Support', - open: true, initialInput: `I need help with my project`, suggestions: { title: diff --git a/apps/studio/components/layouts/ProjectLayout/LayoutSidebar/LayoutSidebarProvider.test.tsx b/apps/studio/components/layouts/ProjectLayout/LayoutSidebar/LayoutSidebarProvider.test.tsx index 951d6c5241b..ec3920d23fc 100644 --- a/apps/studio/components/layouts/ProjectLayout/LayoutSidebar/LayoutSidebarProvider.test.tsx +++ b/apps/studio/components/layouts/ProjectLayout/LayoutSidebar/LayoutSidebarProvider.test.tsx @@ -3,14 +3,8 @@ import { act, fireEvent, render, waitFor } from '@testing-library/react' import { ReactNode } from 'react' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' -import { - getSidebarManagerSnapshot, - sidebarManagerState, -} from 'state/sidebar-manager-state' -import { - LayoutSidebarProvider, - SIDEBAR_KEYS, -} from './LayoutSidebarProvider' +import { getSidebarManagerSnapshot, sidebarManagerState } from 'state/sidebar-manager-state' +import { LayoutSidebarProvider, SIDEBAR_KEYS } from './LayoutSidebarProvider' vi.mock('components/ui/AIAssistantPanel/AIAssistant', () => ({ AIAssistant: () =>
, diff --git a/apps/studio/components/layouts/ProjectLayout/LayoutSidebar/index.test.tsx b/apps/studio/components/layouts/ProjectLayout/LayoutSidebar/index.test.tsx index 00e1b68051a..b3d18a3fe4a 100644 --- a/apps/studio/components/layouts/ProjectLayout/LayoutSidebar/index.test.tsx +++ b/apps/studio/components/layouts/ProjectLayout/LayoutSidebar/index.test.tsx @@ -1,28 +1,17 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { act, render, screen, waitFor } from '@testing-library/react' -import Router from 'next/router' +import router from 'next-router-mock' import { ReactNode } from 'react' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' -import { - LayoutSidebarProvider, - SIDEBAR_KEYS, -} from './LayoutSidebarProvider' import { LayoutSidebar } from './index' +import { LayoutSidebarProvider, SIDEBAR_KEYS } from './LayoutSidebarProvider' import { sidebarManagerState } from 'state/sidebar-manager-state' vi.mock('components/ui/AIAssistantPanel/AIAssistant', () => ({ AIAssistant: () =>
AI Assistant
, })) -vi.mock('next/router', async () => { - const actual = await vi.importActual('next/router') - return { - ...actual, - useRouter: () => Router, - } -}) - const resetSidebarManagerState = () => { Object.keys(sidebarManagerState.sidebars).forEach((id) => { sidebarManagerState.unregisterSidebar(id) @@ -40,21 +29,7 @@ describe('LayoutSidebar', () => { {children} ) - Object.assign(Router, { - isReady: true, - query: {}, - events: { on: vi.fn(), off: vi.fn(), emit: vi.fn() }, - push: vi.fn(), - replace: vi.fn(), - prefetch: vi.fn(), - pathname: '/', - route: '/', - asPath: '/', - basePath: '', - back: vi.fn(), - beforePopState: vi.fn(), - reload: vi.fn(), - }) + router.setCurrentUrl('/') }) afterEach(() => { @@ -62,6 +37,7 @@ describe('LayoutSidebar', () => { queryClient.clear() localStorage.clear() vi.clearAllMocks() + router.setCurrentUrl('/') }) const renderSidebar = () => @@ -93,7 +69,7 @@ describe('LayoutSidebar', () => { }) it('auto-opens when sidebar query param matches a registered sidebar', async () => { - Object.assign(Router, { isReady: true, query: { sidebar: SIDEBAR_KEYS.AI_ASSISTANT } }) + router.setCurrentUrl(`/?sidebar=${SIDEBAR_KEYS.AI_ASSISTANT}`) renderSidebar() diff --git a/apps/studio/pages/project/[ref]/functions/new.tsx b/apps/studio/pages/project/[ref]/functions/new.tsx index c8fa03fb8d0..b813c3babb6 100644 --- a/apps/studio/pages/project/[ref]/functions/new.tsx +++ b/apps/studio/pages/project/[ref]/functions/new.tsx @@ -42,6 +42,8 @@ import { TooltipContent, TooltipTrigger, } from 'ui' +import { SIDEBAR_KEYS } from 'components/layouts/ProjectLayout/LayoutSidebar/LayoutSidebarProvider' +import { useSidebarManagerSnapshot } from 'state/sidebar-manager-state' // Array of adjectives and nouns for random function name generation const ADJECTIVES = [ @@ -104,6 +106,7 @@ const NewFunctionPage = () => { const snap = useAiAssistantStateSnapshot() const { mutate: sendEvent } = useSendEventMutation() const showStripeExample = useIsFeatureEnabled('edge_functions:show_stripe_example') + const { openSidebar } = useSidebarManagerSnapshot() const [files, setFiles] = useState< { id: number; name: string; content: string; selected?: boolean }[] @@ -167,9 +170,9 @@ const NewFunctionPage = () => { const handleChat = () => { const selectedFile = files.find((f) => f.selected) ?? files[0] + openSidebar(SIDEBAR_KEYS.AI_ASSISTANT) snap.newChat({ name: 'Explain edge function', - open: true, sqlSnippets: [selectedFile.content], initialInput: 'Help me understand and improve this edge function...', suggestions: {