Improve empty state

This commit is contained in:
Joshen Lim committed 2023-06-21 15:11:45 +08:00
1 parent d99b672b8d
commit 424d6ec2ac
4 files changed
+188 -48

No files matched your search

@@ -9,6 +9,7 @@ import ShimmeringLoader from 'components/ui/ShimmeringLoader'
import { DatabaseMigration, useMigrationsQuery } from 'data/database/migrations-query'
import { Editor } from '@monaco-editor/react'
import CodeEditor from 'components/ui/CodeEditor'
import MigrationsEmptyState from './MigrationsEmptyState'
const Wrappers = () => {
const [search, setSearch] = useState('')
@@ -24,6 +25,8 @@ const Wrappers = () => {
? data?.result ?? []
: data?.result.filter((migration) => migration.version.includes(search)) ?? []
console.log({ data })
return (
<>
<div>
@@ -80,51 +83,52 @@ const Wrappers = () => {
)}
{isSuccess && (
<div>
<div className="w-80 mb-4">
<Input
size="small"
placeholder="Search for a migration"
value={search}
onChange={(e: any) => setSearch(e.target.value)}
icon={<IconSearch size="tiny" />}
/>
</div>
{data.result.length <= 0 && <div>No migrations state...</div>}
{data.result.length <= 0 && <MigrationsEmptyState />}
{data.result.length > 0 && (
<Table
head={[
<Table.th key="version">Version</Table.th>,
<Table.th key="buttons"></Table.th>,
]}
body={
migrations.length > 0 ? (
migrations.map((migration) => (
<Table.tr key={migration.version}>
<Table.td>{migration.version}</Table.td>
<Table.td align="right">
<Button
type="default"
onClick={() => setSelectedMigration(migration)}
>
View migration SQL
</Button>
<>
<div className="w-80 mb-4">
<Input
size="small"
placeholder="Search for a migration"
value={search}
onChange={(e: any) => setSearch(e.target.value)}
icon={<IconSearch size="tiny" />}
/>
</div>
<Table
head={[
<Table.th key="version">Version</Table.th>,
<Table.th key="buttons"></Table.th>,
]}
body={
migrations.length > 0 ? (
migrations.map((migration) => (
<Table.tr key={migration.version}>
<Table.td>{migration.version}</Table.td>
<Table.td align="right">
<Button
type="default"
onClick={() => setSelectedMigration(migration)}
>
View migration SQL
</Button>
</Table.td>
</Table.tr>
))
) : (
<Table.tr>
<Table.td>
<p className="text-sm text-scale-1200">No results found</p>
<p className="text-sm text-scale-1100">
Your search for "{search}" did not return any results
</p>
</Table.td>
</Table.tr>
))
) : (
<Table.tr>
<Table.td>
<p className="text-sm text-scale-1200">No results found</p>
<p className="text-sm text-scale-1100">
Your search for "{search}" did not return any results
</p>
</Table.td>
</Table.tr>
)
}
/>
)
}
/>
</>
)}
</div>
)}
@@ -0,0 +1,111 @@
import clsx from 'clsx'
import Link from 'next/link'
import { useState } from 'react'
import {
Button,
Collapsible,
IconExternalLink,
IconMaximize2,
IconMinimize2,
IconTerminal,
} from 'ui'
import CommandRender from 'components/interfaces/Functions/CommandRender'
import { useParams } from 'common'
const MigrationsEmptyState = () => {
const { ref } = useParams()
const [showInstructions, setShowInstructions] = useState(false)
const commands = [
{
comment: 'Link your project',
command: `supabase link --project-ref ${ref}`,
jsx: () => {
return (
<>
<span className="text-brand-1100">supabase</span> link --project-ref {ref}
</>
)
},
},
{
comment: 'Create a new migration called "new-migration"',
command: `supabase migration new new-migration`,
jsx: () => {
return (
<>
<span className="text-brand-1100">supabase</span> migration new new-migration
</>
)
},
},
{
comment: 'Run all migrations against this project',
command: `supabase db push`,
jsx: () => {
return (
<>
<span className="text-brand-1100">supabase</span> db push
</>
)
},
},
]
return (
<div className="w-full px-12 py-12 bg-white bg-no-repeat border rounded dark:bg-scale-200 border-scale-500">
<div className="space-y-8">
<div className="space-y-2 w-4/5">
<h4 className="text-lg">Database migrations</h4>
<p className="text-sm text-scale-1100">
Database changes are managed through "migrations" and they are a common way of tracking
changes to your database over time. You can run migrations against your project's
database via the Supabase CLI.
</p>
</div>
<Collapsible open={showInstructions} onOpenChange={setShowInstructions}>
<Collapsible.Trigger asChild>
<button
type="button"
className={clsx(
'flex w-full items-center justify-between rounded py-3 px-6 text-scale-1200 border bg-scale-100 dark:bg-scale-300',
showInstructions && 'rounded-b-none'
)}
>
<div className="flex items-center justify-between gap-3 w-full">
<div className="flex items-center gap-3">
<div className="flex items-center justify-center w-8 h-8 p-2 border rounded bg-scale-100">
<IconTerminal strokeWidth={2} />
</div>
<h4>Terminal instructions</h4>
</div>
{showInstructions ? (
<IconMinimize2
className="text-scale-800 transition data-open-parent:rotate-0 data-closed-parent:rotate-180"
strokeWidth={2}
width={14}
/>
) : (
<IconMaximize2
className="text-scale-800 transition data-open-parent:rotate-0 data-closed-parent:rotate-180"
strokeWidth={2}
width={14}
/>
)}
</div>
</button>
</Collapsible.Trigger>
<Collapsible.Content>
<div className="border border-t-0 bg-scale-100 dark:bg-scale-300 rounded-b py-3 px-6">
<CommandRender commands={commands} />
</div>
</Collapsible.Content>
</Collapsible>
</div>
</div>
)
}
export default MigrationsEmptyState
+10
View File
@@ -36,6 +36,16 @@ export const useMigrationsQuery = <TData extends MigrationsData = MigrationsData
connectionString,
sql: getMigrationsQuery(),
queryKey: ['migrations'],
handleError: (error: { code: number; message: string; requestId: string }) => {
if (
error.code === 400 &&
error.message.includes('relation "supabase_migrations.schema_migrations" does not exist')
) {
return { result: [] }
} else {
throw error
}
},
},
options
)
+22 -7
View File
@@ -10,12 +10,16 @@ import { post } from 'lib/common/fetch'
import { API_URL } from 'lib/constants'
import { useCallback } from 'react'
import { sqlKeys } from './keys'
import { noop } from 'lodash'
export type Error = { code: number; message: string; requestId: string }
export type ExecuteSqlVariables = {
projectRef?: string
connectionString?: string
sql: string
queryKey?: QueryKey
handleError?: (error: { code: number; message: string; requestId: string }) => any
}
export async function executeSql(
@@ -24,7 +28,11 @@ export async function executeSql(
connectionString,
sql,
queryKey,
}: Pick<ExecuteSqlVariables, 'projectRef' | 'connectionString' | 'sql' | 'queryKey'>,
handleError,
}: Pick<
ExecuteSqlVariables,
'projectRef' | 'connectionString' | 'sql' | 'queryKey' | 'handleError'
>,
signal?: AbortSignal
) {
if (!projectRef) {
@@ -44,8 +52,13 @@ export async function executeSql(
{ query: sql },
{ headers: Object.fromEntries(headers), signal }
)
if (response.error) {
throw response.error
if (handleError !== undefined) {
return handleError(response.error)
} else {
throw response.error
}
}
return { result: response }
@@ -55,21 +68,22 @@ export type ExecuteSqlData = Awaited<ReturnType<typeof executeSql>>
export type ExecuteSqlError = unknown
export const useExecuteSqlQuery = <TData = ExecuteSqlData>(
{ projectRef, connectionString, sql, queryKey }: ExecuteSqlVariables,
{ projectRef, connectionString, sql, queryKey, handleError }: ExecuteSqlVariables,
{ enabled = true, ...options }: UseQueryOptions<ExecuteSqlData, ExecuteSqlError, TData> = {}
) =>
useQuery<ExecuteSqlData, ExecuteSqlError, TData>(
sqlKeys.query(projectRef, queryKey ?? [md5(sql)]),
({ signal }) => executeSql({ projectRef, connectionString, sql, queryKey }, signal),
({ signal }) =>
executeSql({ projectRef, connectionString, sql, queryKey, handleError }, signal),
{ enabled: enabled && typeof projectRef !== 'undefined', ...options }
)
export const prefetchExecuteSql = (
client: QueryClient,
{ projectRef, connectionString, sql, queryKey }: ExecuteSqlVariables
{ projectRef, connectionString, sql, queryKey, handleError }: ExecuteSqlVariables
) => {
return client.prefetchQuery(sqlKeys.query(projectRef, queryKey ?? [md5(sql)]), ({ signal }) =>
executeSql({ projectRef, connectionString, sql, queryKey }, signal)
executeSql({ projectRef, connectionString, sql, queryKey, handleError }, signal)
)
}
@@ -89,13 +103,14 @@ export const useExecuteSqlPrefetch = () => {
const client = useQueryClient()
return useCallback(
({ projectRef, connectionString, sql, queryKey }: ExecuteSqlVariables) => {
({ projectRef, connectionString, sql, queryKey, handleError }: ExecuteSqlVariables) => {
if (projectRef) {
return prefetchExecuteSql(client, {
projectRef,
connectionString,
sql,
queryKey,
handleError,
})
}