address feedback

This commit is contained in:
Alaister Young committed 2023-09-12 22:43:25 +12:00
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()
+2 -1
View File
@@ -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,
+6 -2
View File
@@ -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()
+53 -38
View File
@@ -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>
+14 -1
View File
@@ -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/`)
}
}}
/>
</>
)
}