fix: Migrate SQL editor and Log explrorer to use ShadCN Resizable (#21454)
* Add resizable component to ui package. * Migrate the LogExplorer to use the new resizable component. * Migrate the SQL editor to use the new component. * Remove react-split.
This commit is contained in:
@@ -4,7 +4,6 @@ import { AnimatePresence, motion } from 'framer-motion'
|
||||
import dynamic from 'next/dynamic'
|
||||
import { useRouter } from 'next/router'
|
||||
import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import Split from 'react-split'
|
||||
import { format } from 'sql-formatter'
|
||||
|
||||
import ConfirmModal from 'components/ui/Dialogs/ConfirmDialog'
|
||||
@@ -20,7 +19,6 @@ import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-que
|
||||
import { isError } from 'data/utils/error-check'
|
||||
import {
|
||||
useFlag,
|
||||
useLocalStorage,
|
||||
useLocalStorageQuery,
|
||||
useSelectedOrganization,
|
||||
useSelectedProject,
|
||||
@@ -50,6 +48,9 @@ import {
|
||||
IconSettings,
|
||||
IconX,
|
||||
Input_Shadcn_,
|
||||
ResizableHandle,
|
||||
ResizablePanel,
|
||||
ResizablePanelGroup,
|
||||
cn,
|
||||
} from 'ui'
|
||||
import { subscriptionHasHipaaAddon } from '../Billing/Subscription/Subscription.utils'
|
||||
@@ -178,13 +179,6 @@ const SQLEditor = () => {
|
||||
|
||||
const isDiffOpen = !!sqlDiff
|
||||
|
||||
const [savedSplitSize, setSavedSplitSize] = useLocalStorage(
|
||||
LOCAL_STORAGE_KEYS.SQL_EDITOR_SPLIT_SIZE,
|
||||
`[50, 50]`
|
||||
)
|
||||
|
||||
const splitSize = savedSplitSize ? JSON.parse(savedSplitSize) : undefined
|
||||
|
||||
const { mutate: execute, isLoading: isExecuting } = useExecuteSqlMutation({
|
||||
onSuccess(data) {
|
||||
if (id) snap.addResult(id, data.result)
|
||||
@@ -230,20 +224,10 @@ const SQLEditor = () => {
|
||||
},
|
||||
})
|
||||
|
||||
const minSize = 44
|
||||
const snippet = id ? snap.snippets[id] : null
|
||||
const snapOffset = 50
|
||||
|
||||
const isLoading = urlId === 'new' ? false : !(id && ref && snap.loaded[ref])
|
||||
|
||||
const onDragEnd = useCallback(
|
||||
(sizes: number[]) => {
|
||||
if (id) snap.setSplitSizes(id, sizes)
|
||||
setSavedSplitSize(JSON.stringify(sizes))
|
||||
},
|
||||
[id]
|
||||
)
|
||||
|
||||
const editorRef = useRef<IStandaloneCodeEditor | null>(null)
|
||||
const monacoRef = useRef<Monaco | null>(null)
|
||||
const diffEditorRef = useRef<IStandaloneDiffEditor | null>(null)
|
||||
@@ -866,19 +850,12 @@ const SQLEditor = () => {
|
||||
</motion.div>
|
||||
</AISchemaSuggestionPopover>
|
||||
)}
|
||||
<Split
|
||||
style={{ height: '100%' }}
|
||||
<ResizablePanelGroup
|
||||
className="h-full"
|
||||
direction="vertical"
|
||||
gutterSize={2}
|
||||
sizes={
|
||||
(splitSize ? splitSize : (snippet?.splitSizes as number[] | undefined)) ?? [50, 50]
|
||||
}
|
||||
minSize={minSize}
|
||||
snapOffset={snapOffset}
|
||||
expandToMin={true}
|
||||
onDragEnd={onDragEnd}
|
||||
autoSaveId={LOCAL_STORAGE_KEYS.SQL_EDITOR_SPLIT_SIZE}
|
||||
>
|
||||
<div className="flex-grow overflow-y-auto border-b">
|
||||
<ResizablePanel collapsible collapsedSize={10} minSize={20}>
|
||||
{!isAiOpen && (
|
||||
<motion.button
|
||||
layoutId="ask-ai-input-icon"
|
||||
@@ -1006,8 +983,9 @@ const SQLEditor = () => {
|
||||
</motion.div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex flex-col">
|
||||
</ResizablePanel>
|
||||
<ResizableHandle withHandle />
|
||||
<ResizablePanel collapsible collapsedSize={10} minSize={20}>
|
||||
{isLoading ? (
|
||||
<div className="flex h-full w-full items-center justify-center">Loading...</div>
|
||||
) : (
|
||||
@@ -1020,8 +998,8 @@ const SQLEditor = () => {
|
||||
executeQuery={executeQuery}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</Split>
|
||||
</ResizablePanel>
|
||||
</ResizablePanelGroup>
|
||||
</div>
|
||||
</SQLEditorContext.Provider>
|
||||
)
|
||||
|
||||
@@ -36,6 +36,7 @@ export const LOCAL_STORAGE_KEYS = {
|
||||
UI_PREVIEW_CLS: 'supabase-ui-cls',
|
||||
|
||||
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',
|
||||
CLS_DIFF_WARNING: 'cls-diff-warning-dismissed',
|
||||
CLS_SELECT_STAR_WARNING: 'cls-select-star-warning-dismissed',
|
||||
|
||||
@@ -87,7 +87,6 @@
|
||||
"react-intersection-observer": "^9.5.3",
|
||||
"react-markdown": "^8.0.3",
|
||||
"react-simple-maps": "4.0.0-beta.6",
|
||||
"react-split": "^2.0.13",
|
||||
"react-tracked": "^1.7.11",
|
||||
"react-virtualized-auto-sizer": "^1.0.20",
|
||||
"react-window": "^1.8.6",
|
||||
|
||||
@@ -1,20 +1,28 @@
|
||||
import { useParams } from 'common/hooks'
|
||||
import dayjs from 'dayjs'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { Button, Form, Input, Modal } from 'ui'
|
||||
import Split from 'react-split'
|
||||
import { useParams } from 'common/hooks'
|
||||
import {
|
||||
Button,
|
||||
Form,
|
||||
Input,
|
||||
Modal,
|
||||
ResizableHandle,
|
||||
ResizablePanel,
|
||||
ResizablePanelGroup,
|
||||
} from 'ui'
|
||||
|
||||
import {
|
||||
DatePickerToFrom,
|
||||
LogsQueryPanel,
|
||||
LogsTableName,
|
||||
LogsWarning,
|
||||
LOGS_LARGE_DATE_RANGE_DAYS_THRESHOLD,
|
||||
LogTable,
|
||||
LogTemplate,
|
||||
maybeShowUpgradePrompt,
|
||||
LogsQueryPanel,
|
||||
LogsTableName,
|
||||
LogsWarning,
|
||||
TEMPLATES,
|
||||
maybeShowUpgradePrompt,
|
||||
useEditorHints,
|
||||
} from 'components/interfaces/Settings/Logs'
|
||||
import UpgradePrompt from 'components/interfaces/Settings/Logs/UpgradePrompt'
|
||||
@@ -23,12 +31,13 @@ import CodeEditor from 'components/ui/CodeEditor'
|
||||
import LoadingOpacity from 'components/ui/LoadingOpacity'
|
||||
import ShimmerLine from 'components/ui/ShimmerLine'
|
||||
import { useContentInsertMutation } from 'data/content/content-insert-mutation'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useLocalStorage, useSelectedOrganization, useStore } from 'hooks'
|
||||
import useLogsQuery from 'hooks/analytics/useLogsQuery'
|
||||
import { useUpgradePrompt } from 'hooks/misc/useUpgradePrompt'
|
||||
import { LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
import { uuidv4 } from 'lib/helpers'
|
||||
import { LogSqlSnippets, NextPageWithLayout } from 'types'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
|
||||
const PLACEHOLDER_QUERY =
|
||||
'select\n cast(timestamp as datetime) as timestamp,\n event_message, metadata \nfrom edge_logs \nlimit 5'
|
||||
@@ -187,17 +196,12 @@ export const LogsExplorerPage: NextPageWithLayout = () => {
|
||||
|
||||
return (
|
||||
<div className="w-full h-full mx-auto">
|
||||
<Split
|
||||
className="w-full"
|
||||
style={{ height: '100%' }}
|
||||
<ResizablePanelGroup
|
||||
className="w-full h-full"
|
||||
direction="vertical"
|
||||
gutterSize={2}
|
||||
sizes={[50, 50]}
|
||||
minSize={44}
|
||||
snapOffset={50}
|
||||
expandToMin={true}
|
||||
autoSaveId={LOCAL_STORAGE_KEYS.LOG_EXPLORER_SPLIT_SIZE}
|
||||
>
|
||||
<div className="flex-grow overflow-y-auto border-b">
|
||||
<ResizablePanel collapsible minSize={5}>
|
||||
<LogsQueryPanel
|
||||
defaultFrom={params.iso_timestamp_start || ''}
|
||||
defaultTo={params.iso_timestamp_end || ''}
|
||||
@@ -220,8 +224,9 @@ export const LogsExplorerPage: NextPageWithLayout = () => {
|
||||
onInputChange={(v) => setEditorValue(v || '')}
|
||||
onInputRun={handleRun}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col flex-grow">
|
||||
</ResizablePanel>
|
||||
<ResizableHandle withHandle />
|
||||
<ResizablePanel collapsible minSize={5} className="flex flex-col flex-grow">
|
||||
<LoadingOpacity active={isLoading}>
|
||||
<div className="flex flex-grow">
|
||||
<LogTable
|
||||
@@ -238,8 +243,8 @@ export const LogsExplorerPage: NextPageWithLayout = () => {
|
||||
<div className="flex flex-row justify-end mt-2">
|
||||
<UpgradePrompt show={showUpgradePrompt} setShowUpgradePrompt={setShowUpgradePrompt} />
|
||||
</div>
|
||||
</div>
|
||||
</Split>
|
||||
</ResizablePanel>
|
||||
</ResizablePanelGroup>
|
||||
|
||||
<Modal
|
||||
size="medium"
|
||||
|
||||
@@ -126,7 +126,7 @@ const SqlEditor: NextPageWithLayout = () => {
|
||||
}, [isPgInfoReady])
|
||||
|
||||
return (
|
||||
<div className="SQLTabContainer flex-1">
|
||||
<div className="flex-1">
|
||||
<SQLEditor />
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -3,11 +3,6 @@
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
|
||||
.gutter {
|
||||
@apply bg-border-control;
|
||||
cursor: row-resize;
|
||||
}
|
||||
|
||||
.grid-monaco-editor,
|
||||
.monaco-editor p,
|
||||
label,
|
||||
|
||||
@@ -349,14 +349,6 @@
|
||||
scrollbar-width: none; // auto | thin | none | <length>;
|
||||
}
|
||||
|
||||
.SQLTabContainer {
|
||||
height: calc(100vh - 3rem);
|
||||
min-height: calc(100vh - 3rem);
|
||||
.gutter {
|
||||
cursor: row-resize;
|
||||
}
|
||||
}
|
||||
|
||||
.radix-tooltip-arrow {
|
||||
polygon {
|
||||
@apply fill-background-alternative [[data-theme*=dark]_&]:fill-background-alternative;
|
||||
|
||||
10
package-lock.json
generated
10
package-lock.json
generated
@@ -30149,6 +30149,15 @@
|
||||
"react": ">= 16.3"
|
||||
}
|
||||
},
|
||||
"node_modules/react-resizable-panels": {
|
||||
"version": "2.0.9",
|
||||
"resolved": "https://registry.npmjs.org/react-resizable-panels/-/react-resizable-panels-2.0.9.tgz",
|
||||
"integrity": "sha512-ZylBvs7oG7Y/INWw3oYGolqgpFvoPW8MPeg9l1fURDeKpxrmUuCHBUmPj47BdZ11MODImu3kZYXG85rbySab7w==",
|
||||
"peerDependencies": {
|
||||
"react": "^16.14.0 || ^17.0.0 || ^18.0.0",
|
||||
"react-dom": "^16.14.0 || ^17.0.0 || ^18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-resize-detector": {
|
||||
"version": "8.1.0",
|
||||
"license": "MIT",
|
||||
@@ -37364,6 +37373,7 @@
|
||||
"react-hook-form": "^7.45.0",
|
||||
"react-hot-toast": "^2.4.1",
|
||||
"react-markdown": "^8.0.3",
|
||||
"react-resizable-panels": "^2.0.9",
|
||||
"react-syntax-highlighter": "^15.5.0",
|
||||
"react-tooltip": "^4.2.17",
|
||||
"reactflow": "^11.10.1",
|
||||
|
||||
@@ -206,6 +206,8 @@ export { ScrollArea, ScrollBar } from './src/components/shadcn/ui/scroll-area'
|
||||
|
||||
export { Separator } from './src/components/shadcn/ui/separator'
|
||||
|
||||
export * from './src/components/shadcn/ui/resizable'
|
||||
|
||||
// links
|
||||
|
||||
export * from './src/components/TextLink'
|
||||
|
||||
@@ -74,6 +74,7 @@
|
||||
"react-hook-form": "^7.45.0",
|
||||
"react-hot-toast": "^2.4.1",
|
||||
"react-markdown": "^8.0.3",
|
||||
"react-resizable-panels": "^2.0.9",
|
||||
"react-syntax-highlighter": "^15.5.0",
|
||||
"react-tooltip": "^4.2.17",
|
||||
"reactflow": "^11.10.1",
|
||||
|
||||
39
packages/ui/src/components/shadcn/ui/resizable.tsx
Normal file
39
packages/ui/src/components/shadcn/ui/resizable.tsx
Normal file
@@ -0,0 +1,39 @@
|
||||
import { GripVertical } from 'lucide-react'
|
||||
import * as ResizablePrimitive from 'react-resizable-panels'
|
||||
import { cn } from '../../../lib/utils/cn'
|
||||
|
||||
const ResizablePanelGroup = ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof ResizablePrimitive.PanelGroup>) => (
|
||||
<ResizablePrimitive.PanelGroup
|
||||
className={cn('flex h-full w-full data-[panel-group-direction=vertical]:flex-col', className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
|
||||
const ResizablePanel = ResizablePrimitive.Panel
|
||||
|
||||
const ResizableHandle = ({
|
||||
withHandle,
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof ResizablePrimitive.PanelResizeHandle> & {
|
||||
withHandle?: boolean
|
||||
}) => (
|
||||
<ResizablePrimitive.PanelResizeHandle
|
||||
className={cn(
|
||||
'relative flex w-px items-center justify-center bg-border after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:-translate-y-1/2 data-[panel-group-direction=vertical]:after:translate-x-0 [&[data-panel-group-direction=vertical]>div]:rotate-90',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{withHandle && (
|
||||
<div className="z-10 flex h-4 w-3 items-center justify-center rounded-sm border bg-border">
|
||||
<GripVertical className="h-2.5 w-2.5" />
|
||||
</div>
|
||||
)}
|
||||
</ResizablePrimitive.PanelResizeHandle>
|
||||
)
|
||||
|
||||
export { ResizableHandle, ResizablePanel, ResizablePanelGroup }
|
||||
Reference in New Issue
Block a user