mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 17:35:10 +03:00
address feedback
This commit is contained in:
1 parent
f0a90120c5
commit
2796f5ef5f
12 files changed
+127
-89
No files matched your search
@@ -5,6 +5,7 @@ import { useState } from 'react'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import NoSearchResults from 'components/to-be-cleaned/NoSearchResults'
|
||||
import Table from 'components/to-be-cleaned/Table'
|
||||
import AlertError from 'components/ui/AlertError'
|
||||
import InformationBox from 'components/ui/InformationBox'
|
||||
import Connecting from 'components/ui/Loading/Loading'
|
||||
import { useTablesQuery } from 'data/tables/tables-query'
|
||||
@@ -31,6 +32,8 @@ const PublicationsTables = ({ selectedPublication, onSelectBack }: PublicationsT
|
||||
data: tables,
|
||||
isLoading,
|
||||
isSuccess,
|
||||
isError,
|
||||
error,
|
||||
} = useTablesQuery(
|
||||
{
|
||||
projectRef: project?.ref,
|
||||
@@ -110,6 +113,9 @@ const PublicationsTables = ({ selectedPublication, onSelectBack }: PublicationsT
|
||||
<Connecting />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isError && <AlertError error={error} subject="Failed to retrieve tables" />}
|
||||
|
||||
{isSuccess &&
|
||||
(tables.length === 0 ? (
|
||||
<NoSearchResults />
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import dagre from '@dagrejs/dagre'
|
||||
import clsx from 'clsx'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { uniqBy } from 'lodash'
|
||||
import { Diamond, Fingerprint } from 'lucide-react'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { useEffect, useMemo } from 'react'
|
||||
import ReactFlow, {
|
||||
Background,
|
||||
@@ -17,11 +18,10 @@ import ReactFlow, {
|
||||
|
||||
import { PostgresTable } from '@supabase/postgres-meta'
|
||||
import { useTheme } from 'common/Providers'
|
||||
import { useStore } from 'hooks'
|
||||
import { IconHash, IconKey, IconLoader, IconLock } from 'ui'
|
||||
import { Diamond, Fingerprint } from 'lucide-react'
|
||||
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import { useTablesQuery } from 'data/tables/tables-query'
|
||||
import 'reactflow/dist/style.css'
|
||||
import { IconHash, IconKey, IconLoader, IconLock } from 'ui'
|
||||
|
||||
type TableNodeData = {
|
||||
name: string
|
||||
@@ -347,23 +347,32 @@ const TablesGraph = ({ tables }: { tables: PostgresTable[] }) => {
|
||||
}
|
||||
|
||||
const SchemaGraph = ({ schema }: { schema: string }) => {
|
||||
const { meta } = useStore()
|
||||
const tables = meta.tables.list((table: { schema: string }) => table.schema === schema)
|
||||
const { project } = useProjectContext()
|
||||
const {
|
||||
data: tables,
|
||||
isLoading,
|
||||
isError,
|
||||
error,
|
||||
} = useTablesQuery({
|
||||
projectRef: project?.ref,
|
||||
connectionString: project?.connectionString,
|
||||
schema,
|
||||
})
|
||||
|
||||
if (meta.tables.isLoading) {
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="flex h-full w-full items-center justify-center space-x-2">
|
||||
<IconLoader className="animate-spin" size={14} />
|
||||
<p className="text-sm text-scale-1000">Loading schemas...</p>
|
||||
<p className="text-sm text-scale-1000">Loading table...</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
if (meta.tables.hasError) {
|
||||
if (isError) {
|
||||
return (
|
||||
<div className="px-6 py-4 text-scale-1000">
|
||||
<p>Error connecting to API</p>
|
||||
<p>{`${meta.tables.error?.message ?? 'Unknown error'}`}</p>
|
||||
<p>{`${error?.message ?? 'Unknown error'}`}</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import {
|
||||
Input,
|
||||
Listbox,
|
||||
} from 'ui'
|
||||
import AlertError from 'components/ui/AlertError'
|
||||
|
||||
interface TableListProps {
|
||||
onAddTable: () => void
|
||||
@@ -58,6 +59,8 @@ const TableList = ({
|
||||
data: tables,
|
||||
isLoading,
|
||||
isSuccess,
|
||||
isError,
|
||||
error,
|
||||
} = useTablesQuery(
|
||||
{
|
||||
projectRef: project?.ref,
|
||||
@@ -180,6 +183,8 @@ const TableList = ({
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isError && <AlertError error={error} subject="Failed to retrieve tables" />}
|
||||
|
||||
{isSuccess &&
|
||||
(tables.length === 0 ? (
|
||||
<NoSearchResults />
|
||||
@@ -323,21 +328,6 @@ const TableList = ({
|
||||
</Tooltip.Portal>
|
||||
)}
|
||||
</Tooltip.Root>
|
||||
|
||||
{/* <Button
|
||||
type="text"
|
||||
icon={<IconEdit3 />}
|
||||
style={{ padding: 5 }}
|
||||
disabled={isLocked}
|
||||
onClick={() => onEditTable(x)}
|
||||
/>
|
||||
<Button
|
||||
type="text"
|
||||
icon={<IconTrash />}
|
||||
style={{ padding: 5 }}
|
||||
disabled={isLocked}
|
||||
onClick={() => onDeleteTable(x)}
|
||||
/> */}
|
||||
</div>
|
||||
</Table.td>
|
||||
</Table.tr>
|
||||
|
||||
@@ -6,21 +6,24 @@ import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectConte
|
||||
import ConfirmationModal from 'components/ui/ConfirmationModal'
|
||||
import { entityTypeKeys } from 'data/entity-types/keys'
|
||||
import { sqlKeys } from 'data/sql/keys'
|
||||
import { tableKeys } from 'data/tables/keys'
|
||||
import { useGetTables } from 'data/tables/tables-query'
|
||||
import { useStore, useUrlState } from 'hooks'
|
||||
import { TableLike } from 'hooks/misc/useTable'
|
||||
import { noop } from 'lib/void'
|
||||
import { useTableEditorStateSnapshot } from 'state/table-editor'
|
||||
import { Alert, Button, Checkbox, IconExternalLink, Modal } from 'ui'
|
||||
import { tableKeys } from 'data/tables/keys'
|
||||
|
||||
export type DeleteConfirmationDialogsProps = {
|
||||
projectRef?: string
|
||||
selectedTable?: TableLike
|
||||
onAfterDeleteTable?: (tables: TableLike[]) => void
|
||||
}
|
||||
|
||||
const DeleteConfirmationDialogs = ({
|
||||
projectRef,
|
||||
selectedTable,
|
||||
onAfterDeleteTable = noop,
|
||||
}: DeleteConfirmationDialogsProps) => {
|
||||
const { project } = useProjectContext()
|
||||
const snap = useTableEditorStateSnapshot()
|
||||
@@ -117,12 +120,8 @@ const DeleteConfirmationDialogs = ({
|
||||
|
||||
await queryClient.invalidateQueries(entityTypeKeys.list(projectRef))
|
||||
|
||||
// For simplicity for now, we just open the first table within the same schema
|
||||
if (tables.length > 0) {
|
||||
router.push(`/project/${projectRef}/editor/${tables[0].id}`)
|
||||
} else {
|
||||
router.push(`/project/${projectRef}/editor/`)
|
||||
}
|
||||
onAfterDeleteTable(tables)
|
||||
|
||||
ui.setNotification({
|
||||
category: 'success',
|
||||
message: `Successfully deleted table "${selectedTableToDelete.name}"`,
|
||||
|
||||
@@ -331,7 +331,10 @@ const SidePanelEditor = ({
|
||||
duplicateTable,
|
||||
})
|
||||
|
||||
await queryClient.invalidateQueries(entityTypeKeys.list(project?.ref))
|
||||
await Promise.all([
|
||||
queryClient.invalidateQueries(tableKeys.list(project?.ref, table.schema)),
|
||||
queryClient.invalidateQueries(entityTypeKeys.list(project?.ref)),
|
||||
])
|
||||
|
||||
ui.setNotification({
|
||||
id: toastId,
|
||||
@@ -355,7 +358,10 @@ const SidePanelEditor = ({
|
||||
importContent
|
||||
)
|
||||
|
||||
await queryClient.invalidateQueries(entityTypeKeys.list(project?.ref))
|
||||
await Promise.all([
|
||||
queryClient.invalidateQueries(tableKeys.list(project?.ref, table.schema)),
|
||||
queryClient.invalidateQueries(entityTypeKeys.list(project?.ref)),
|
||||
])
|
||||
|
||||
ui.setNotification({
|
||||
id: toastId,
|
||||
@@ -398,6 +404,7 @@ const SidePanelEditor = ({
|
||||
])
|
||||
),
|
||||
queryClient.invalidateQueries(entityTypeKeys.list(project?.ref)),
|
||||
queryClient.invalidateQueries(tableKeys.table(project?.ref, table.schema)),
|
||||
])
|
||||
|
||||
ui.setNotification({
|
||||
|
||||
@@ -7,9 +7,7 @@ import { useCheckPermissions, useStore } from 'hooks'
|
||||
import { ProjectLayoutWithAuth } from '../'
|
||||
import TableEditorMenu from './TableEditorMenu'
|
||||
|
||||
export interface TableEditorLayoutProps {}
|
||||
|
||||
const TableEditorLayout = ({ children }: PropsWithChildren<TableEditorLayoutProps>) => {
|
||||
const TableEditorLayout = ({ children }: PropsWithChildren<{}>) => {
|
||||
const { vault, meta, ui } = useStore()
|
||||
|
||||
const canReadTables = useCheckPermissions(PermissionAction.TENANT_SQL_ADMIN_READ, 'tables')
|
||||
|
||||
@@ -28,9 +28,7 @@ import {
|
||||
import { useProjectContext } from '../ProjectLayout/ProjectContext'
|
||||
import EntityListItem from './EntityListItem'
|
||||
|
||||
export interface TableEditorMenuProps {}
|
||||
|
||||
const TableEditorMenu = ({}: TableEditorMenuProps) => {
|
||||
const TableEditorMenu = () => {
|
||||
const { id } = useParams()
|
||||
const snap = useTableEditorStateSnapshot()
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import { useQuery, useQueryClient, UseQueryOptions } from '@tanstack/react-query
|
||||
import { get } from 'lib/common/fetch'
|
||||
import { API_URL } from 'lib/constants'
|
||||
import { useCallback } from 'react'
|
||||
import { ResponseError } from 'types'
|
||||
import { tableKeys } from './keys'
|
||||
import { Table } from './table-query'
|
||||
|
||||
@@ -45,7 +46,7 @@ export async function getTables(
|
||||
}
|
||||
|
||||
export type TablesData = Awaited<ReturnType<typeof getTables>>
|
||||
export type TablesError = unknown
|
||||
export type TablesError = ResponseError
|
||||
|
||||
export const useTablesQuery = <TData = TablesData>(
|
||||
{ projectRef, connectionString, schema }: TablesVariables,
|
||||
|
||||
@@ -8,8 +8,9 @@ import { useParams } from 'common/hooks'
|
||||
import { Policies } from 'components/interfaces/Auth/Policies'
|
||||
import { AuthLayout } from 'components/layouts'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import Connecting from 'components/ui/Loading/Loading'
|
||||
import AlertError from 'components/ui/AlertError'
|
||||
import NoPermission from 'components/ui/NoPermission'
|
||||
import { GenericSkeletonLoader } from 'components/ui/ShimmeringLoader'
|
||||
import { useSchemasQuery } from 'data/database/schemas-query'
|
||||
import { useTablesQuery } from 'data/tables/tables-query'
|
||||
import { useCheckPermissions, useStore } from 'hooks'
|
||||
@@ -80,6 +81,8 @@ const AuthPoliciesPage: NextPageWithLayout = () => {
|
||||
data: tables,
|
||||
isLoading,
|
||||
isSuccess,
|
||||
isError,
|
||||
error,
|
||||
} = useTablesQuery({
|
||||
projectRef: project?.ref,
|
||||
connectionString: project?.connectionString,
|
||||
@@ -168,7 +171,8 @@ const AuthPoliciesPage: NextPageWithLayout = () => {
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{isLoading && <Connecting />}
|
||||
{isLoading && <GenericSkeletonLoader />}
|
||||
{isError && <AlertError error={error} subject="Failed to retrieve tables" />}
|
||||
{isSuccess && (
|
||||
<Policies tables={filteredTables} hasTables={tables.length > 0} isLocked={isLocked} />
|
||||
)}
|
||||
|
||||
@@ -5,15 +5,13 @@ import { useEffect, useState } from 'react'
|
||||
import { CreateFunction, DeleteFunction } from 'components/interfaces/Database'
|
||||
import FunctionsList from 'components/interfaces/Database/Functions/FunctionsList/FunctionsList'
|
||||
import { DatabaseLayout } from 'components/layouts'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import { ScaffoldContainer, ScaffoldSection } from 'components/layouts/Scaffold'
|
||||
import NoPermission from 'components/ui/NoPermission'
|
||||
import { useCheckPermissions, useStore } from 'hooks'
|
||||
import { NextPageWithLayout } from 'types'
|
||||
import { ScaffoldContainer, ScaffoldSection } from 'components/layouts/Scaffold'
|
||||
|
||||
const FunctionsPage: NextPageWithLayout = () => {
|
||||
const { meta } = useStore()
|
||||
const { project } = useProjectContext()
|
||||
const { ui, meta } = useStore()
|
||||
const [selectedFunction, setSelectedFunction] = useState<any>()
|
||||
const [showCreateFunctionForm, setShowCreateFunctionForm] = useState<boolean>(false)
|
||||
const [showDeleteFunctionForm, setShowDeleteFunctionForm] = useState<boolean>(false)
|
||||
@@ -21,10 +19,10 @@ const FunctionsPage: NextPageWithLayout = () => {
|
||||
const canReadFunctions = useCheckPermissions(PermissionAction.TENANT_SQL_ADMIN_READ, 'functions')
|
||||
|
||||
useEffect(() => {
|
||||
if (project?.ref) {
|
||||
if (ui.selectedProjectRef) {
|
||||
fetchFunctions()
|
||||
}
|
||||
}, [project?.ref])
|
||||
}, [ui.selectedProjectRef])
|
||||
|
||||
const fetchFunctions = async () => {
|
||||
meta.functions.load()
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useState } from 'react'
|
||||
import SchemaGraph from 'components/interfaces/Database/Schemas/SchemaGraph'
|
||||
import { DatabaseLayout } from 'components/layouts'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import AlertError from 'components/ui/AlertError'
|
||||
import { useSchemasQuery } from 'data/database/schemas-query'
|
||||
import { EXCLUDED_SCHEMAS } from 'lib/constants/schemas'
|
||||
import { NextPageWithLayout } from 'types'
|
||||
@@ -11,7 +12,13 @@ import { IconLock, Listbox } from 'ui'
|
||||
|
||||
const SchemasPage: NextPageWithLayout = () => {
|
||||
const { project } = useProjectContext()
|
||||
const { data: schemas } = useSchemasQuery({
|
||||
const {
|
||||
data: schemas,
|
||||
isSuccess,
|
||||
isLoading,
|
||||
isError,
|
||||
error,
|
||||
} = useSchemasQuery({
|
||||
projectRef: project?.ref,
|
||||
connectionString: project?.connectionString,
|
||||
})
|
||||
@@ -26,45 +33,53 @@ const SchemasPage: NextPageWithLayout = () => {
|
||||
<>
|
||||
<div className="flex w-full h-full flex-col">
|
||||
<div className="p-4 border-b border-scale-500">
|
||||
<Listbox
|
||||
className="w-[260px]"
|
||||
size="small"
|
||||
value={selectedSchema}
|
||||
onChange={setSelectedSchema}
|
||||
icon={isLocked && <IconLock size={14} strokeWidth={2} />}
|
||||
>
|
||||
<Listbox.Option disabled key="normal-schemas" value="normal-schemas" label="Schemas">
|
||||
<p className="text-sm">Schemas</p>
|
||||
</Listbox.Option>
|
||||
{openSchemas.map((schema) => (
|
||||
<Listbox.Option
|
||||
key={schema.id}
|
||||
value={schema.name}
|
||||
label={schema.name}
|
||||
addOnBefore={() => <span className="text-scale-900">schema</span>}
|
||||
>
|
||||
<span className="text-scale-1200 text-sm">{schema.name}</span>
|
||||
</Listbox.Option>
|
||||
))}
|
||||
<Listbox.Option
|
||||
disabled
|
||||
key="protected-schemas"
|
||||
value="protected-schemas"
|
||||
label="Protected schemas"
|
||||
{isLoading && (
|
||||
<div className="h-[34px] w-[260px] bg-scale-1000 rounded shimmering-loader" />
|
||||
)}
|
||||
|
||||
{isError && <AlertError error={error} subject="Failed to retrieve schemas" />}
|
||||
|
||||
{isSuccess && (
|
||||
<Listbox
|
||||
className="w-[260px]"
|
||||
size="small"
|
||||
value={selectedSchema}
|
||||
onChange={setSelectedSchema}
|
||||
icon={isLocked && <IconLock size={14} strokeWidth={2} />}
|
||||
>
|
||||
<p className="text-sm">Protected schemas</p>
|
||||
</Listbox.Option>
|
||||
{protectedSchemas.map((schema) => (
|
||||
<Listbox.Option
|
||||
key={schema.id}
|
||||
value={schema.name}
|
||||
label={schema.name}
|
||||
addOnBefore={() => <span className="text-scale-900">schema</span>}
|
||||
>
|
||||
<span className="text-scale-1200 text-sm">{schema.name}</span>
|
||||
<Listbox.Option disabled key="normal-schemas" value="normal-schemas" label="Schemas">
|
||||
<p className="text-sm">Schemas</p>
|
||||
</Listbox.Option>
|
||||
))}
|
||||
</Listbox>
|
||||
{openSchemas.map((schema) => (
|
||||
<Listbox.Option
|
||||
key={schema.id}
|
||||
value={schema.name}
|
||||
label={schema.name}
|
||||
addOnBefore={() => <span className="text-scale-900">schema</span>}
|
||||
>
|
||||
<span className="text-scale-1200 text-sm">{schema.name}</span>
|
||||
</Listbox.Option>
|
||||
))}
|
||||
<Listbox.Option
|
||||
disabled
|
||||
key="protected-schemas"
|
||||
value="protected-schemas"
|
||||
label="Protected schemas"
|
||||
>
|
||||
<p className="text-sm">Protected schemas</p>
|
||||
</Listbox.Option>
|
||||
{protectedSchemas.map((schema) => (
|
||||
<Listbox.Option
|
||||
key={schema.id}
|
||||
value={schema.name}
|
||||
label={schema.name}
|
||||
addOnBefore={() => <span className="text-scale-900">schema</span>}
|
||||
>
|
||||
<span className="text-scale-1200 text-sm">{schema.name}</span>
|
||||
</Listbox.Option>
|
||||
))}
|
||||
</Listbox>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<SchemaGraph schema={selectedSchema}></SchemaGraph>
|
||||
|
||||
@@ -5,9 +5,11 @@ import DeleteConfirmationDialogs from 'components/interfaces/TableGridEditor/Del
|
||||
import { TableEditorLayout } from 'components/layouts'
|
||||
import { ProjectContextFromParamsProvider } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import useTable from 'hooks/misc/useTable'
|
||||
import { useRouter } from 'next/router'
|
||||
import { NextPageWithLayout } from 'types'
|
||||
|
||||
const TableEditorPage: NextPageWithLayout = () => {
|
||||
const router = useRouter()
|
||||
const { isDarkMode } = useTheme()
|
||||
const { id: _id, ref: projectRef } = useParams()
|
||||
const id = _id ? Number(_id) : undefined
|
||||
@@ -21,7 +23,18 @@ const TableEditorPage: NextPageWithLayout = () => {
|
||||
selectedTable={selectedTable}
|
||||
theme={isDarkMode ? 'dark' : 'light'}
|
||||
/>
|
||||
<DeleteConfirmationDialogs projectRef={projectRef} selectedTable={selectedTable} />
|
||||
<DeleteConfirmationDialogs
|
||||
projectRef={projectRef}
|
||||
selectedTable={selectedTable}
|
||||
onAfterDeleteTable={(tables) => {
|
||||
// For simplicity for now, we just open the first table within the same schema
|
||||
if (tables.length > 0) {
|
||||
router.push(`/project/${projectRef}/editor/${tables[0].id}`)
|
||||
} else {
|
||||
router.push(`/project/${projectRef}/editor/`)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user