diff --git a/apps/studio/components/layouts/ProjectLayout/LayoutHeader/HelpPopover.tsx b/apps/studio/components/layouts/ProjectLayout/LayoutHeader/HelpPopover.tsx index 6b0f47d34af..17ddf0d1462 100644 --- a/apps/studio/components/layouts/ProjectLayout/LayoutHeader/HelpPopover.tsx +++ b/apps/studio/components/layouts/ProjectLayout/LayoutHeader/HelpPopover.tsx @@ -1,9 +1,3 @@ -import { Activity, BookOpen, HelpCircle, Mail, Wrench } from 'lucide-react' -import Image from 'next/legacy/image' -import { useRouter } from 'next/router' -import { useState } from 'react' -import SVG from 'react-inlinesvg' - import { IS_PLATFORM } from 'common' import type { SupportFormUrlKeys } from 'components/interfaces/Support/SupportForm.utils' import { SupportLink } from 'components/interfaces/Support/SupportLink' @@ -13,6 +7,11 @@ import { useSendEventMutation } from 'data/telemetry/send-event-mutation' import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization' import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject' import { DOCS_URL } from 'lib/constants' +import { Activity, BookOpen, HelpCircle, Mail, Wrench } from 'lucide-react' +import Image from 'next/legacy/image' +import { useRouter } from 'next/router' +import { useState } from 'react' +import SVG from 'react-inlinesvg' import { useAiAssistantStateSnapshot } from 'state/ai-assistant-state' import { useSidebarManagerSnapshot } from 'state/sidebar-manager-state' import { @@ -21,29 +20,19 @@ import { ButtonGroup, ButtonGroupItem, cn, - Popover, Popover_Shadcn_, PopoverContent_Shadcn_, PopoverTrigger_Shadcn_, + Separator, } from 'ui' +import styleHandler from 'ui/src/lib/theme/styleHandler' export const HelpPopover = () => { - const router = useRouter() const { data: project } = useSelectedProjectQuery() const { data: org } = useSelectedOrganizationQuery() - const snap = useAiAssistantStateSnapshot() - const { openSidebar } = useSidebarManagerSnapshot() const { mutate: sendEvent } = useSendEventMutation() const [isOpen, setIsOpen] = useState(false) - const projectRef = project?.parent_project_ref ?? (router.query.ref as string | undefined) - let supportLinkQueryParams: Partial | undefined = undefined - if (projectRef) { - supportLinkQueryParams = { projectRef } - } else if (org?.slug) { - supportLinkQueryParams = { orgSlug: org.slug } - } - return ( @@ -73,128 +62,149 @@ export const HelpPopover = () => { /> - -
-
-
Need help with your project?
-

- Start with our {projectRef ? 'Assistant, docs,' : 'docs'} or community. -

-
- -
- - {projectRef && ( - } - onClick={() => { - openSidebar(SIDEBAR_KEYS.AI_ASSISTANT) - snap.newChat({ - name: 'Support', - initialInput: `I need help with my project`, - suggestions: { - title: - 'I can help you with your project, here are some example prompts to get you started:', - prompts: [ - { - label: 'Database Health', - description: 'Summarise my database health and performance', - }, - { - label: 'Debug Logs', - description: 'View and debug my edge function logs', - }, - { - label: 'RLS Setup', - description: 'Implement row level security for my tables', - }, - ], - }, - }) - }} - > - Supabase Assistant - - )} - } asChild> - - Docs - - - } asChild> - - Troubleshooting - - - {IS_PLATFORM && ( - <> - } - > - - Supabase status - - - - }> - setIsOpen(false)} - > - Contact support - - - - )} - -
-
- -
-
-
Community support
-

- Our Discord community can help with code-related issues. Many questions are answered - in minutes. -

-
- -
+ + setIsOpen(false)} />
) } + +export const HelpContent = ({ onClose }: { onClose: () => void }) => { + const snap = useAiAssistantStateSnapshot() + const { openSidebar } = useSidebarManagerSnapshot() + const router = useRouter() + const { data: project } = useSelectedProjectQuery() + const { data: org } = useSelectedOrganizationQuery() + + const projectRef = project?.parent_project_ref ?? (router.query.ref as string | undefined) + let supportLinkQueryParams: Partial | undefined = undefined + if (projectRef) { + supportLinkQueryParams = { projectRef } + } else if (org?.slug) { + supportLinkQueryParams = { orgSlug: org.slug } + } + + const __styles = styleHandler('popover') + + return ( + <> +
+
+
Need help with your project?
+

+ Start with our {projectRef ? 'Assistant, docs,' : 'docs'} or community. +

+
+ +
+ + {projectRef && ( + } + onClick={() => { + openSidebar(SIDEBAR_KEYS.AI_ASSISTANT) + snap.newChat({ + name: 'Support', + initialInput: `I need help with my project`, + suggestions: { + title: + 'I can help you with your project, here are some example prompts to get you started:', + prompts: [ + { + label: 'Database Health', + description: 'Summarise my database health and performance', + }, + { + label: 'Debug Logs', + description: 'View and debug my edge function logs', + }, + { + label: 'RLS Setup', + description: 'Implement row level security for my tables', + }, + ], + }, + }) + }} + > + Supabase Assistant + + )} + } asChild> + + Docs + + + } asChild> + + Troubleshooting + + + {IS_PLATFORM && ( + <> + } + > + + Supabase status + + + + }> + + Contact support + + + + )} + +
+
+ +
+
+
Community support
+

+ Our Discord community can help with code-related issues. Many questions are answered in + minutes. +

+
+
+ +
+
+ + ) +} diff --git a/apps/studio/components/layouts/ProjectLayout/LayoutSidebar/LayoutSidebarProvider.tsx b/apps/studio/components/layouts/ProjectLayout/LayoutSidebar/LayoutSidebarProvider.tsx index f653c316d49..782775713ac 100644 --- a/apps/studio/components/layouts/ProjectLayout/LayoutSidebar/LayoutSidebarProvider.tsx +++ b/apps/studio/components/layouts/ProjectLayout/LayoutSidebar/LayoutSidebarProvider.tsx @@ -6,6 +6,7 @@ import { LOCAL_STORAGE_KEYS } from 'common' import { AdvisorPanel } from 'components/ui/AdvisorPanel/AdvisorPanel' import { AIAssistant } from 'components/ui/AIAssistantPanel/AIAssistant' import { EditorPanel } from 'components/ui/EditorPanel/EditorPanel' +import { HelpPanel } from 'components/ui/HelpPanel/HelpPanel' import { useSendEventMutation } from 'data/telemetry/send-event-mutation' import useLatest from 'hooks/misc/useLatest' import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage' @@ -17,6 +18,7 @@ export const SIDEBAR_KEYS = { AI_ASSISTANT: 'ai-assistant', EDITOR_PANEL: 'editor-panel', ADVISOR_PANEL: 'advisor-panel', + HELP_PANEL: 'help-panel', } as const export const LayoutSidebarProvider = ({ children }: PropsWithChildren) => { @@ -36,6 +38,7 @@ export const LayoutSidebarProvider = ({ children }: PropsWithChildren) => { useRegisterSidebar(SIDEBAR_KEYS.AI_ASSISTANT, () => , {}, 'i', !!project) useRegisterSidebar(SIDEBAR_KEYS.EDITOR_PANEL, () => , {}, 'e', !!project) useRegisterSidebar(SIDEBAR_KEYS.ADVISOR_PANEL, () => , {}, undefined, true) + useRegisterSidebar(SIDEBAR_KEYS.HELP_PANEL, () => , {}, undefined, true) useEffect(() => { if (!!project) { diff --git a/apps/studio/components/layouts/ProjectLayout/SidebarToolbar/SidebarToolbar.tsx b/apps/studio/components/layouts/ProjectLayout/SidebarToolbar/SidebarToolbar.tsx index a9993b59a7f..3d537d383b1 100644 --- a/apps/studio/components/layouts/ProjectLayout/SidebarToolbar/SidebarToolbar.tsx +++ b/apps/studio/components/layouts/ProjectLayout/SidebarToolbar/SidebarToolbar.tsx @@ -1,7 +1,8 @@ import { useParams } from 'common' import { IS_PLATFORM } from 'lib/constants' -import { ToolbarButton } from './ToolbarButton' + import { generateToolbarItems } from './SidebarToolbar.utils' +import { ToolbarButton } from './ToolbarButton' export const SidebarToolbar = () => { const { ref: projectRef } = useParams() @@ -16,7 +17,7 @@ export const SidebarToolbar = () => { const enabledItems = toolbarItems.filter((item) => item.enabled) return ( -
+
{enabledItems.map((item) => ( diff --git a/apps/studio/components/layouts/ProjectLayout/SidebarToolbar/SidebarToolbar.utils.tsx b/apps/studio/components/layouts/ProjectLayout/SidebarToolbar/SidebarToolbar.utils.tsx index dbfa437d4e5..59f3a836596 100644 --- a/apps/studio/components/layouts/ProjectLayout/SidebarToolbar/SidebarToolbar.utils.tsx +++ b/apps/studio/components/layouts/ProjectLayout/SidebarToolbar/SidebarToolbar.utils.tsx @@ -1,6 +1,6 @@ import { SIDEBAR_KEYS } from 'components/layouts/ProjectLayout/LayoutSidebar/LayoutSidebarProvider' import { SqlEditor } from 'icons' -import { Lightbulb } from 'lucide-react' +import { Lightbulb, HelpCircle } from 'lucide-react' import { AiIconAnimation, cn } from 'ui' import { AdvisorBadge } from './AdvisorBadge' @@ -82,5 +82,25 @@ export const generateToolbarItems = (options: GenerateToolbarItemsOptions = {}): badge: , }, }, + { + key: 'help', + label: 'Help & Support', + enabled: isPlatform, + config: { + id: 'help-trigger', + sidebarKey: SIDEBAR_KEYS.HELP_PANEL, + icon: (isOpen) => ( + + ), + tooltipText: 'Help & Support', + }, + }, ] } diff --git a/apps/studio/components/layouts/ProjectLayout/SidebarToolbar/ToolbarButton.tsx b/apps/studio/components/layouts/ProjectLayout/SidebarToolbar/ToolbarButton.tsx index 06bca7c29ea..a31c9ea4a37 100644 --- a/apps/studio/components/layouts/ProjectLayout/SidebarToolbar/ToolbarButton.tsx +++ b/apps/studio/components/layouts/ProjectLayout/SidebarToolbar/ToolbarButton.tsx @@ -47,12 +47,13 @@ export const ToolbarButton = ({ id={id} className={cn( 'rounded-full w-[32px] h-[32px] flex items-center justify-center p-0 text-foreground-light hover:text-foreground group', + 'border-transparent', isOpen && 'bg-foreground text-background hover:text-background' )} onClick={handleClick} tooltip={{ content: { - className: 'p-1 pl-2.5', + className: shouldShowShortcut ? 'p-1 pl-2.5' : 'py-1.5 px-2.5', side: 'left', text: shouldShowShortcut ? (
diff --git a/apps/studio/components/ui/EditorPanel/EditorPanel.tsx b/apps/studio/components/ui/EditorPanel/EditorPanel.tsx index fe8f8debfa3..1c99cba5cf3 100644 --- a/apps/studio/components/ui/EditorPanel/EditorPanel.tsx +++ b/apps/studio/components/ui/EditorPanel/EditorPanel.tsx @@ -22,22 +22,22 @@ import { useSidebarManagerSnapshot } from 'state/sidebar-manager-state' import { useSqlEditorV2StateSnapshot } from 'state/sql-editor-v2' import { Button, + cn, CodeBlock, + Command_Shadcn_, CommandEmpty_Shadcn_, CommandGroup_Shadcn_, CommandInput_Shadcn_, CommandItem_Shadcn_, CommandList_Shadcn_, - Command_Shadcn_, + HoverCard_Shadcn_, HoverCardContent_Shadcn_, HoverCardTrigger_Shadcn_, - HoverCard_Shadcn_, KeyboardShortcut, + Popover_Shadcn_, PopoverContent_Shadcn_, PopoverTrigger_Shadcn_, - Popover_Shadcn_, SQL_ICON, - cn, } from 'ui' import { Admonition } from 'ui-patterns' diff --git a/apps/studio/components/ui/HelpPanel/HelpPanel.tsx b/apps/studio/components/ui/HelpPanel/HelpPanel.tsx new file mode 100644 index 00000000000..de2f33668b3 --- /dev/null +++ b/apps/studio/components/ui/HelpPanel/HelpPanel.tsx @@ -0,0 +1,31 @@ +import { HelpContent } from 'components/layouts/ProjectLayout/LayoutHeader/HelpPopover' +import { SIDEBAR_KEYS } from 'components/layouts/ProjectLayout/LayoutSidebar/LayoutSidebarProvider' +import { ButtonTooltip } from 'components/ui/ButtonTooltip' +import { X } from 'lucide-react' +import { useSidebarManagerSnapshot } from 'state/sidebar-manager-state' + +export const HelpPanel = () => { + const { closeSidebar } = useSidebarManagerSnapshot() + + const handleClose = () => { + closeSidebar(SIDEBAR_KEYS.HELP_PANEL) + } + + return ( +
+
+

Help & Support

+ } + onClick={handleClose} + tooltip={{ content: { side: 'bottom', text: 'Close Help & Support' } }} + /> +
+
+ +
+
+ ) +}