mirror of
https://github.com/supabase/supabase.git
synced 2026-10-06 01:45:10 +03:00
Add a toggle for intellisense to the sql editor (#21643)
* Add a toggle for intellisense to the sql editor * Cleanup * Ensure that we dont load suggestions in browser unless intellisense is enabled * Small fix * Lol spelling --------- Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
This commit is contained in:
1 parent
79629b79f0
commit
377cb2dc7c
8 files changed
+181
-76
No files matched your search
@@ -2,16 +2,17 @@ import Editor, { Monaco, OnMount } from '@monaco-editor/react'
|
||||
import { useParams } from 'common'
|
||||
import { debounce } from 'lodash'
|
||||
import { useRouter } from 'next/router'
|
||||
import { MutableRefObject, useEffect, useRef } from 'react'
|
||||
import { MutableRefObject, useEffect, useRef, useState } from 'react'
|
||||
import { cn } from 'ui'
|
||||
|
||||
import { SqlSnippet } from 'data/content/sql-snippets-query'
|
||||
import { useSelectedProject } from 'hooks'
|
||||
import { useLocalStorageQuery, useSelectedProject } from 'hooks'
|
||||
import { useProfile } from 'lib/profile'
|
||||
import { useSqlEditorStateSnapshot } from 'state/sql-editor'
|
||||
import { untitledSnippetTitle } from './SQLEditor.constants'
|
||||
import { IStandaloneCodeEditor } from './SQLEditor.types'
|
||||
import { createSqlSnippetSkeleton } from './SQLEditor.utils'
|
||||
import { LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
|
||||
export type MonacoEditorProps = {
|
||||
id: string
|
||||
@@ -37,6 +38,11 @@ const MonacoEditor = ({
|
||||
const { profile } = useProfile()
|
||||
const project = useSelectedProject()
|
||||
|
||||
const [intellisenseEnabled] = useLocalStorageQuery(
|
||||
LOCAL_STORAGE_KEYS.SQL_EDITOR_INTELLISENSE,
|
||||
typeof window !== 'undefined' ? false : true
|
||||
)
|
||||
|
||||
const snap = useSqlEditorStateSnapshot({ sync: true })
|
||||
const snippet = snap.snippets[id]
|
||||
|
||||
@@ -138,6 +144,36 @@ const MonacoEditor = ({
|
||||
// - https://github.com/microsoft/monaco-editor/issues/2229
|
||||
// - https://github.com/microsoft/monaco-editor/issues/2503
|
||||
// fixedOverflowWidgets: true,
|
||||
suggest: {
|
||||
showMethods: intellisenseEnabled,
|
||||
showFunctions: intellisenseEnabled,
|
||||
showConstructors: intellisenseEnabled,
|
||||
showDeprecated: intellisenseEnabled,
|
||||
showFields: intellisenseEnabled,
|
||||
showVariables: intellisenseEnabled,
|
||||
showClasses: intellisenseEnabled,
|
||||
showStructs: intellisenseEnabled,
|
||||
showInterfaces: intellisenseEnabled,
|
||||
showModules: intellisenseEnabled,
|
||||
showProperties: intellisenseEnabled,
|
||||
showEvents: intellisenseEnabled,
|
||||
showOperators: intellisenseEnabled,
|
||||
showUnits: intellisenseEnabled,
|
||||
showValues: intellisenseEnabled,
|
||||
showConstants: intellisenseEnabled,
|
||||
showEnums: intellisenseEnabled,
|
||||
showEnumMembers: intellisenseEnabled,
|
||||
showKeywords: intellisenseEnabled,
|
||||
showWords: intellisenseEnabled,
|
||||
showColors: intellisenseEnabled,
|
||||
showFiles: intellisenseEnabled,
|
||||
showReferences: intellisenseEnabled,
|
||||
showFolders: intellisenseEnabled,
|
||||
showTypeParameters: intellisenseEnabled,
|
||||
showIssues: intellisenseEnabled,
|
||||
showUsers: intellisenseEnabled,
|
||||
showSnippets: intellisenseEnabled,
|
||||
},
|
||||
}}
|
||||
/>
|
||||
)
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
import { Button, IconHeart } from 'ui'
|
||||
import {
|
||||
Button,
|
||||
IconHeart,
|
||||
TooltipContent_Shadcn_,
|
||||
TooltipTrigger_Shadcn_,
|
||||
Tooltip_Shadcn_,
|
||||
} from 'ui'
|
||||
import { useQueryClient } from '@tanstack/react-query'
|
||||
import { contentKeys } from 'data/content/keys'
|
||||
import { Content, ContentData } from 'data/content/content-query'
|
||||
@@ -75,23 +81,28 @@ const FavoriteButton = ({ id }: FavoriteButtonProps) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{isFavorite ? (
|
||||
<Button
|
||||
type="text"
|
||||
size="tiny"
|
||||
onClick={removeFavorite}
|
||||
icon={<IconHeart size="tiny" fill="#48bb78" />}
|
||||
/>
|
||||
) : (
|
||||
<Button
|
||||
type="text"
|
||||
size="tiny"
|
||||
onClick={addFavorite}
|
||||
icon={<IconHeart size="tiny" fill="gray" />}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
<Tooltip_Shadcn_>
|
||||
<TooltipTrigger_Shadcn_ asChild>
|
||||
{isFavorite ? (
|
||||
<Button
|
||||
type="text"
|
||||
size="tiny"
|
||||
onClick={removeFavorite}
|
||||
className="px-1"
|
||||
icon={<IconHeart size="tiny" fill="#48bb78" />}
|
||||
/>
|
||||
) : (
|
||||
<Button
|
||||
type="text"
|
||||
size="tiny"
|
||||
onClick={addFavorite}
|
||||
className="px-1"
|
||||
icon={<IconHeart size="tiny" fill="gray" />}
|
||||
/>
|
||||
)}
|
||||
</TooltipTrigger_Shadcn_>
|
||||
<TooltipContent_Shadcn_ side="bottom">Add to favorites</TooltipContent_Shadcn_>
|
||||
</Tooltip_Shadcn_>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,32 @@
|
||||
import * as Tooltip from '@radix-ui/react-tooltip'
|
||||
import { IS_PLATFORM } from 'lib/constants'
|
||||
import { IS_PLATFORM, LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
import { detectOS } from 'lib/helpers'
|
||||
import { Button, IconAlignLeft, IconCommand, IconCornerDownLeft } from 'ui'
|
||||
import {
|
||||
Button,
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
IconAlignLeft,
|
||||
IconCheck,
|
||||
IconCommand,
|
||||
IconCornerDownLeft,
|
||||
IconSettings,
|
||||
Toggle_Shadcn,
|
||||
TooltipContent_Shadcn_,
|
||||
TooltipTrigger_Shadcn_,
|
||||
Tooltip_Shadcn_,
|
||||
cn,
|
||||
} from 'ui'
|
||||
|
||||
import { RoleImpersonationPopover } from 'components/interfaces/RoleImpersonationSelector'
|
||||
import DatabaseSelector from 'components/ui/DatabaseSelector'
|
||||
import { useSelectedProject } from 'hooks'
|
||||
import { useLocalStorageQuery, useSelectedProject } from 'hooks'
|
||||
import FavoriteButton from './FavoriteButton'
|
||||
import SavingIndicator from './SavingIndicator'
|
||||
import toast from 'react-hot-toast'
|
||||
import { FileCog, Keyboard, SlidersHorizontal } from 'lucide-react'
|
||||
|
||||
export type UtilityActionsProps = {
|
||||
id: string
|
||||
@@ -29,45 +48,60 @@ const UtilityActions = ({
|
||||
const os = detectOS()
|
||||
const project = useSelectedProject()
|
||||
const showReadReplicasUI = project?.is_read_replicas_enabled
|
||||
const [intellisenseEnabled, setIntellisenseEnabled] = useLocalStorageQuery(
|
||||
LOCAL_STORAGE_KEYS.SQL_EDITOR_INTELLISENSE,
|
||||
typeof window !== 'undefined' ? false : true
|
||||
)
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="inline-flex items-center justify-end gap-x-2">
|
||||
<SavingIndicator id={id} />
|
||||
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
type="text"
|
||||
className="px-1"
|
||||
icon={<Keyboard size={14} className="text-foreground-light" />}
|
||||
/>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="w-48">
|
||||
<DropdownMenuItem
|
||||
className="justify-between"
|
||||
onClick={() => {
|
||||
setIntellisenseEnabled(!intellisenseEnabled)
|
||||
toast.success(
|
||||
`Successfully ${intellisenseEnabled ? 'disabled' : 'enabled'} intellisense. ${intellisenseEnabled ? 'Please refresh your browser for changes to take place.' : ''}`
|
||||
)
|
||||
}}
|
||||
>
|
||||
<p>Intellisense enabled</p>
|
||||
{intellisenseEnabled && <IconCheck className="text-brand" />}
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
|
||||
{IS_PLATFORM && <FavoriteButton id={id} />}
|
||||
|
||||
<Tooltip.Root delayDuration={0}>
|
||||
<Tooltip.Trigger asChild>
|
||||
<Tooltip_Shadcn_>
|
||||
<TooltipTrigger_Shadcn_ asChild>
|
||||
<Button
|
||||
type="text"
|
||||
onClick={() => prettifyQuery()}
|
||||
className="px-1"
|
||||
icon={<IconAlignLeft size="tiny" strokeWidth={2} className="text-gray-1100" />}
|
||||
/>
|
||||
</Tooltip.Trigger>
|
||||
<Tooltip.Portal>
|
||||
<Tooltip.Content side="bottom">
|
||||
<Tooltip.Arrow className="radix-tooltip-arrow" />
|
||||
<div
|
||||
className={[
|
||||
'rounded bg-alternative py-1 px-2 leading-none shadow',
|
||||
'border border-background',
|
||||
].join(' ')}
|
||||
>
|
||||
<span className="text-xs text-foreground">Prettify SQL</span>
|
||||
</div>
|
||||
</Tooltip.Content>
|
||||
</Tooltip.Portal>
|
||||
</Tooltip.Root>
|
||||
</TooltipTrigger_Shadcn_>
|
||||
<TooltipContent_Shadcn_ side="bottom">Prettify SQL</TooltipContent_Shadcn_>
|
||||
</Tooltip_Shadcn_>
|
||||
|
||||
<div className="flex items-center justify-between gap-x-2 mx-2">
|
||||
<div className="flex items-center">
|
||||
{showReadReplicasUI && <DatabaseSelector variant="connected-on-right" />}
|
||||
|
||||
<RoleImpersonationPopover
|
||||
serviceRoleLabel="postgres"
|
||||
variant={showReadReplicasUI ? 'connected-on-both' : 'connected-on-right'}
|
||||
/>
|
||||
|
||||
<Button
|
||||
onClick={() => executeQuery()}
|
||||
disabled={isDisabled || isExecuting}
|
||||
@@ -90,7 +124,7 @@ const UtilityActions = ({
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -23,17 +23,14 @@ const UtilityPanel = ({
|
||||
<>
|
||||
<div className="flex justify-between overflow-visible px-6 py-2 border-b">
|
||||
<ResultsDropdown id={id} isExecuting={isExecuting} />
|
||||
|
||||
<div className="inline-flex items-center justify-end">
|
||||
<UtilityActions
|
||||
id={id}
|
||||
isExecuting={isExecuting}
|
||||
isDisabled={isDisabled}
|
||||
hasSelection={hasSelection}
|
||||
prettifyQuery={prettifyQuery}
|
||||
executeQuery={executeQuery}
|
||||
/>
|
||||
</div>
|
||||
<UtilityActions
|
||||
id={id}
|
||||
isExecuting={isExecuting}
|
||||
isDisabled={isDisabled}
|
||||
hasSelection={hasSelection}
|
||||
prettifyQuery={prettifyQuery}
|
||||
executeQuery={executeQuery}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex-1 p-0 pt-0 pb-0">
|
||||
|
||||
@@ -35,6 +35,7 @@ export const LOCAL_STORAGE_KEYS = {
|
||||
DASHBOARD_HISTORY: (ref: string) => `dashboard-history-${ref}`,
|
||||
UI_PREVIEW_CLS: 'supabase-ui-cls',
|
||||
|
||||
SQL_EDITOR_INTELLISENSE: 'supabase_sql-editor-intellisense-enabled',
|
||||
SQL_EDITOR_SPLIT_SIZE: 'supabase_sql-editor-split-size',
|
||||
LOG_EXPLORER_SPLIT_SIZE: 'supabase_log-explorer-split-size',
|
||||
GRAPHIQL_RLS_BYPASS_WARNING: 'graphiql-rls-bypass-warning-dismissed',
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { useRouter } from 'next/router'
|
||||
import { useMonaco } from '@monaco-editor/react'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { useEffect, useRef } from 'react'
|
||||
import { useParams } from 'common'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useEffect, useRef } from 'react'
|
||||
|
||||
import { useFunctionsQuery } from 'data/database/functions-query'
|
||||
import { useKeywordsQuery } from 'data/database/keywords-query'
|
||||
@@ -16,6 +16,8 @@ import { SQLEditorLayout } from 'components/layouts'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import getPgsqlCompletionProvider from 'components/ui/CodeEditor/Providers/PgSQLCompletionProvider'
|
||||
import getPgsqlSignatureHelpProvider from 'components/ui/CodeEditor/Providers/PgSQLSignatureHelpProvider'
|
||||
import { useLocalStorageQuery } from 'hooks'
|
||||
import { LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
import { useAppStateSnapshot } from 'state/app-state'
|
||||
import { useSnippets, useSqlEditorStateSnapshot } from 'state/sql-editor'
|
||||
|
||||
@@ -31,6 +33,11 @@ const SqlEditor: NextPageWithLayout = () => {
|
||||
const snippets = useSnippets(ref)
|
||||
const { mutateAsync: formatQuery } = useFormatQueryMutation()
|
||||
|
||||
const [intellisenseEnabled] = useLocalStorageQuery(
|
||||
LOCAL_STORAGE_KEYS.SQL_EDITOR_INTELLISENSE,
|
||||
typeof window !== 'undefined' ? false : true
|
||||
)
|
||||
|
||||
async function formatPgsql(value: string) {
|
||||
try {
|
||||
if (!project) throw new Error('No project')
|
||||
@@ -46,29 +53,46 @@ const SqlEditor: NextPageWithLayout = () => {
|
||||
}
|
||||
}
|
||||
|
||||
const { data: keywords, isSuccess: isKeywordsSuccess } = useKeywordsQuery({
|
||||
projectRef: project?.ref,
|
||||
connectionString: project?.connectionString,
|
||||
})
|
||||
const { data: functions, isSuccess: isFunctionsSuccess } = useFunctionsQuery({
|
||||
projectRef: project?.ref,
|
||||
connectionString: project?.connectionString,
|
||||
})
|
||||
const { data: schemas, isSuccess: isSchemasSuccess } = useSchemasQuery({
|
||||
projectRef: project?.ref,
|
||||
connectionString: project?.connectionString,
|
||||
})
|
||||
const { data: tableColumns, isSuccess: isTableColumnsSuccess } = useTableColumnsQuery({
|
||||
projectRef: project?.ref,
|
||||
connectionString: project?.connectionString,
|
||||
})
|
||||
const { data: keywords, isSuccess: isKeywordsSuccess } = useKeywordsQuery(
|
||||
{
|
||||
projectRef: project?.ref,
|
||||
connectionString: project?.connectionString,
|
||||
},
|
||||
{ enabled: intellisenseEnabled }
|
||||
)
|
||||
const { data: functions, isSuccess: isFunctionsSuccess } = useFunctionsQuery(
|
||||
{
|
||||
projectRef: project?.ref,
|
||||
connectionString: project?.connectionString,
|
||||
},
|
||||
{ enabled: intellisenseEnabled }
|
||||
)
|
||||
const { data: schemas, isSuccess: isSchemasSuccess } = useSchemasQuery(
|
||||
{
|
||||
projectRef: project?.ref,
|
||||
connectionString: project?.connectionString,
|
||||
},
|
||||
{ enabled: intellisenseEnabled }
|
||||
)
|
||||
const { data: tableColumns, isSuccess: isTableColumnsSuccess } = useTableColumnsQuery(
|
||||
{
|
||||
projectRef: project?.ref,
|
||||
connectionString: project?.connectionString,
|
||||
},
|
||||
{ enabled: intellisenseEnabled }
|
||||
)
|
||||
|
||||
const pgInfoRef = useRef<any>(null)
|
||||
const formatPgsqlRef = useRef(formatPgsql)
|
||||
formatPgsqlRef.current = formatPgsql
|
||||
|
||||
const isPgInfoReady =
|
||||
isTableColumnsSuccess && isSchemasSuccess && isKeywordsSuccess && isFunctionsSuccess
|
||||
intellisenseEnabled &&
|
||||
isTableColumnsSuccess &&
|
||||
isSchemasSuccess &&
|
||||
isKeywordsSuccess &&
|
||||
isFunctionsSuccess
|
||||
|
||||
if (isPgInfoReady) {
|
||||
if (pgInfoRef.current === null) {
|
||||
pgInfoRef.current = {}
|
||||
|
||||
@@ -207,6 +207,8 @@ export {
|
||||
TooltipContent as TooltipContent_Shadcn_,
|
||||
} from './src/components/shadcn/ui/tooltip'
|
||||
|
||||
export { Toggle as Toggle_Shadcn } from './src/components/shadcn/ui/toggle'
|
||||
|
||||
export { ScrollArea, ScrollBar } from './src/components/shadcn/ui/scroll-area'
|
||||
|
||||
export { Separator } from './src/components/shadcn/ui/separator'
|
||||
|
||||
@@ -7,7 +7,7 @@ import * as React from 'react'
|
||||
import { cn } from '../../../lib/utils/cn'
|
||||
|
||||
const toggleVariants = cva(
|
||||
'inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors data-[state=on]:bg-accent data-[state=on]:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 ring-offset-background hover:bg-muted hover:text-foreground-muted',
|
||||
'inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors data-[state=on]:bg-accent data-[state=on]:bg-surface-300 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 ring-offset-background bg-surface-200 hover:bg-surface-300 px-3 py-1 h-auto text-foreground transition-all',
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
|
||||
Reference in new issue
Block a user