Add placeholder in database functions editor (#27922)

* Add placeholder in database functions editor

* Address feedback

* Don't show placeholder if language is sql

* Fixes

* Fix
This commit is contained in:
Joshen Lim authored and GitHub committed 2024-07-15 14:23:59 +08:00
1 parent e11d2d96bc
commit 2662583d7e
5 files changed
+136 -39

No files matched your search

@@ -185,7 +185,10 @@ const RLSCodeEditor = ({
{placeholder !== undefined && (
<div
id={placeholderId}
className="monaco-placeholder absolute top-[0px] left-[57px] text-sm pointer-events-none font-mono [&>div>p]:text-foreground-lighter [&>div>p]:!m-0 tracking-tighter"
className={cn(
'monaco-placeholder absolute top-[0px] left-[57px] text-sm pointer-events-none font-mono tracking-tighter',
'[&>div>p]:text-foreground-lighter [&>div>p]:!m-0'
)}
style={{ display: 'none' }}
>
<Markdown content={placeholder} />
@@ -9,26 +9,31 @@ import {
Tooltip_Shadcn_,
cn,
} from 'ui'
import CodeEditor from 'components/ui/CodeEditor/CodeEditor'
export const FunctionEditor = ({
field,
language,
focused,
setFocused,
}: {
field: any
language: string
focused: boolean
setFocused: (b: boolean) => void
}) => {
return (
<div className={cn('rounded-md relative group flex-grow')}>
<FormControl_Shadcn_>
<SqlEditor
defaultValue={field.value}
onInputChange={(value: string | undefined) => {
field.onChange(value)
}}
contextmenu={false}
/>
{language !== undefined && (
<CodeEditor
id="database-functions-editor"
language="pgsql"
placeholder={language === 'plpgsql' ? `BEGIN\n\nEND;` : undefined}
value={field.value}
onInputChange={field.onChange}
/>
)}
</FormControl_Shadcn_>
<div
className={cn(
@@ -42,12 +47,12 @@ export const FunctionEditor = ({
type="text"
size="tiny"
className={cn(
'px-2 text-foreground-lighter hover:text-foreground',
'px-1.5 text-foreground-lighter hover:text-foreground',
'transition z-50'
)}
onClick={() => setFocused(!focused)}
icon={focused ? <Minimize2 /> : <Maximize2 />}
></Button>
/>
</TooltipTrigger_Shadcn_>
<TooltipContent_Shadcn_ side="bottom">
{focused ? 'Minimize editor' : 'Maximize editor'}
@@ -39,7 +39,6 @@ import {
SheetSection,
Toggle,
cn,
useWatch_Shadcn_,
} from 'ui'
import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
@@ -82,6 +81,7 @@ const CreateFunction = ({ func, visible, setVisible }: CreateFunctionProps) => {
const form = useForm<z.infer<typeof FormSchema>>({
resolver: zodResolver(FormSchema),
})
const language = form.watch('language')
const { mutate: createDatabaseFunction, isLoading: isCreating } =
useDatabaseFunctionCreateMutation()
@@ -256,11 +256,7 @@ const CreateFunction = ({ func, visible, setVisible }: CreateFunctionProps) => {
</FormLabel_Shadcn_>
<FormDescription_Shadcn_ className="text-sm text-foreground-light">
<p>
The language below should be written in{' '}
<code>
<FormLanguage />
</code>
.
The language below should be written in <code>{language}</code>.
</p>
{!isEditing && <p>Change the language in the Advanced Settings below.</p>}
</FormDescription_Shadcn_>
@@ -273,6 +269,7 @@ const CreateFunction = ({ func, visible, setVisible }: CreateFunctionProps) => {
>
<FunctionEditor
field={field}
language={language}
focused={focusedEditor}
setFocused={setFocusedEditor}
/>
@@ -647,9 +644,3 @@ const FormFieldLanguage = () => {
/>
)
}
const FormLanguage = () => {
const language = useWatch_Shadcn_({ name: 'language' })
return language
}
@@ -1,10 +1,11 @@
import Editor, { EditorProps, OnMount } from '@monaco-editor/react'
import Editor, { EditorProps, Monaco, OnChange, OnMount } from '@monaco-editor/react'
import { merge, noop } from 'lodash'
import { editor } from 'monaco-editor'
import { useRef } from 'react'
import { cn } from 'ui'
import { useEffect, useRef, useState } from 'react'
import { Markdown } from 'components/interfaces/Markdown'
import { timeout } from 'lib/helpers'
import { cn } from 'ui'
import { Loading } from '../Loading'
import { alignEditor } from './CodeEditor.utils'
@@ -21,6 +22,8 @@ interface CodeEditorProps {
loading?: boolean
options?: EditorProps['options']
value?: string
placeholder?: string
disableTabToUsePlaceholder?: boolean
}
const CodeEditor = ({
@@ -36,13 +39,47 @@ const CodeEditor = ({
loading,
options,
value,
placeholder,
disableTabToUsePlaceholder = false,
}: CodeEditorProps) => {
const hasValue = useRef<any>()
const editorRef = useRef<editor.IStandaloneCodeEditor>()
const monacoRef = useRef<Monaco>()
const showPlaceholderDefault = placeholder !== undefined && (value ?? '').trim().length === 0
const [showPlaceholder, setShowPlaceholder] = useState(showPlaceholderDefault)
const onMount: OnMount = async (editor, monaco) => {
editorRef.current = editor
monacoRef.current = monaco
alignEditor(editor)
hasValue.current = editor.createContextKey('hasValue', false)
hasValue.current.set(value !== undefined && value.trim().length > 0)
setShowPlaceholder(showPlaceholderDefault)
if (!disableTabToUsePlaceholder) {
editor.addCommand(
monaco.KeyCode.Tab,
() => {
editor.executeEdits('source', [
{
// @ts-ignore
identifier: 'add-placeholder',
range: new monaco.Range(1, 1, 1, 1),
text: (placeholder ?? '')
.split('\n\n')
.join('\n')
.replaceAll('*', '')
.replaceAll('&nbsp;', ''),
},
])
},
'!hasValue'
)
}
editor.addAction({
id: 'supabase',
label: 'Run Query',
@@ -57,10 +94,22 @@ const CodeEditor = ({
},
})
const model = editor.getModel()
if (model) {
const position = model.getPositionAt((value ?? '').length)
editor.setPosition(position)
}
await timeout(500)
if (autofocus) editor?.focus()
}
const onChangeContent: OnChange = (value) => {
hasValue.current.set((value ?? '').length > 0)
setShowPlaceholder(!value)
onInputChange(value)
}
const optionsMerged = merge(
{
tabSize: 2,
@@ -72,27 +121,73 @@ const CodeEditor = ({
contextmenu: true,
lineNumbers: hideLineNumbers ? 'off' : undefined,
glyphMargin: hideLineNumbers ? false : undefined,
lineNumbersMinChars: hideLineNumbers ? 0 : undefined,
lineNumbersMinChars: hideLineNumbers ? 0 : 4,
folding: hideLineNumbers ? false : undefined,
scrollBeyondLastLine: false,
},
options
)
merge({ cpp: '12' }, { java: '23' }, { python: '35' })
useEffect(() => {
setShowPlaceholder(showPlaceholderDefault)
}, [showPlaceholderDefault])
useEffect(() => {
if (
!disableTabToUsePlaceholder &&
editorRef.current !== undefined &&
monacoRef.current !== undefined
) {
const editor = editorRef.current
const monaco = monacoRef.current
editor.addCommand(
monaco.KeyCode.Tab,
() => {
editor.executeEdits('source', [
{
// @ts-ignore
identifier: 'add-placeholder',
range: new monaco.Range(1, 1, 1, 1),
text: (placeholder ?? ' ')
.split('\n\n')
.join('\n')
.replaceAll('*', '')
.replaceAll('&nbsp;', ''),
},
])
},
'!hasValue'
)
}
}, [placeholder, disableTabToUsePlaceholder])
return (
<Editor
path={id}
theme="supabase"
className={cn(className, 'monaco-editor')}
value={value ?? undefined}
language={language}
defaultValue={defaultValue ?? undefined}
loading={loading || <Loading />}
options={optionsMerged}
onMount={onMount}
onChange={onInputChange}
/>
<>
<Editor
path={id}
theme="supabase"
className={cn(className, 'monaco-editor')}
value={value ?? undefined}
language={language}
defaultValue={defaultValue ?? undefined}
loading={loading || <Loading />}
options={optionsMerged}
onMount={onMount}
onChange={onChangeContent}
/>
{placeholder !== undefined && (
<div
className={cn(
'monaco-placeholder absolute top-[3px] left-[57px] text-sm pointer-events-none font-mono',
'[&>div>p]:text-foreground-lighter [&>div>p]:!m-0 tracking-tighter',
showPlaceholder ? 'block' : 'hidden'
)}
>
<Markdown content={placeholder} />
</div>
)}
</>
)
}
+3
View File
@@ -16,6 +16,9 @@ interface SqlEditorProps {
readOnly?: boolean
}
/**
* @deprecated Use CodeEditor instead
*/
const SqlEditor = ({
queryId,
language = 'pgsql',