From 8a9b46250a67bfa1742fb9076b5f8b442bd05c2f Mon Sep 17 00:00:00 2001 From: phamhieu Date: Mon, 23 May 2022 17:03:38 +0700 Subject: [PATCH] refactor: auth policies page - remove mobx local store - filter table policies from meta.policies - clean up --- .../Policies/PolicyTableRow/index.tsx | 74 +++++----- .../layouts/AuthLayout/AuthLayout.tsx | 1 + studio/pages/project/[ref]/auth/policies.tsx | 137 ++++++------------ 3 files changed, 88 insertions(+), 124 deletions(-) diff --git a/studio/components/interfaces/Authentication/Policies/PolicyTableRow/index.tsx b/studio/components/interfaces/Authentication/Policies/PolicyTableRow/index.tsx index e65be554d8e..68b16f06484 100644 --- a/studio/components/interfaces/Authentication/Policies/PolicyTableRow/index.tsx +++ b/studio/components/interfaces/Authentication/Policies/PolicyTableRow/index.tsx @@ -1,5 +1,7 @@ import { FC } from 'react' import { PostgresTable, PostgresPolicy } from '@supabase/postgres-meta' +import { observer } from 'mobx-react-lite' +import { useStore } from 'hooks' import PolicyTableRowHeader from './PolicyTableRowHeader' import PolicyRow from './PolicyRow' @@ -13,40 +15,44 @@ interface Props { onSelectDeletePolicy: (policy: PostgresPolicy) => void } -const PolicyTableRow: FC = ({ - table, - onSelectToggleRLS = () => {}, - onSelectCreatePolicy = () => {}, - onSelectEditPolicy = () => {}, - onSelectDeletePolicy = () => {}, -}) => { - return ( - - } - > - {table.policies.length === 0 && ( -
-

No policies created yet

-
- )} +const PolicyTableRow: FC = observer( + ({ + table, + onSelectToggleRLS = () => {}, + onSelectCreatePolicy = () => {}, + onSelectEditPolicy = () => {}, + onSelectDeletePolicy = () => {}, + }) => { + const { meta } = useStore() + const policies = meta.policies.list((x: PostgresPolicy) => x.table === table.name) + return ( + + } + > + {policies.length === 0 && ( +
+

No policies created yet

+
+ )} - {/* @ts-ignore */} - {table.policies.map((policy) => ( - - ))} -
- ) -} + {/* @ts-ignore */} + {policies.map((policy) => ( + + ))} +
+ ) + } +) export default PolicyTableRow diff --git a/studio/components/layouts/AuthLayout/AuthLayout.tsx b/studio/components/layouts/AuthLayout/AuthLayout.tsx index 39b42050208..4a7c47379e9 100644 --- a/studio/components/layouts/AuthLayout/AuthLayout.tsx +++ b/studio/components/layouts/AuthLayout/AuthLayout.tsx @@ -25,6 +25,7 @@ const AuthLayout: FC = ({ title, children }) => { useEffect(() => { if (ui.selectedProject) { + meta.policies.load() meta.tables.load() meta.roles.load() } diff --git a/studio/pages/project/[ref]/auth/policies.tsx b/studio/pages/project/[ref]/auth/policies.tsx index 7596eb7ed57..dcdf2495acc 100644 --- a/studio/pages/project/[ref]/auth/policies.tsx +++ b/studio/pages/project/[ref]/auth/policies.tsx @@ -1,82 +1,50 @@ +import React, { useState, PropsWithChildren, FC } from 'react' import { isEmpty } from 'lodash' -import React, { createContext, useContext, useState, useEffect, PropsWithChildren } from 'react' import { Button, IconSearch, Input } from '@supabase/ui' -import { observer, useLocalObservable } from 'mobx-react-lite' - +import { observer } from 'mobx-react-lite' import { useStore } from 'hooks' import { AuthLayout } from 'components/layouts' -import ConfirmModal from 'components/ui/Dialogs/ConfirmDialog' -import NoTableState from 'components/ui/States/NoTableState' import { NextPageWithLayout } from 'types' import { PolicyEditorModal, PolicyTableRow } from 'components/interfaces/Authentication/Policies' - -import NoSearchResults from 'components/to-be-cleaned/NoSearchResults' import { PostgresRole } from '@supabase/postgres-meta' -const PageContext = createContext(null) +import ConfirmModal from 'components/ui/Dialogs/ConfirmDialog' +import NoTableState from 'components/ui/States/NoTableState' +import NoSearchResults from 'components/to-be-cleaned/NoSearchResults' const AuthPoliciesLayout = ({ children }: PropsWithChildren<{}>) => { - const PageState: any = useLocalObservable(() => ({ - meta: null, - project: null, - policiesFilter: '', - selectedTableId: null, - tables: [], - tablesLoading: true, - get filteredTables() { - if (!PageState.policiesFilter) - return PageState.tables.slice().sort((a: any, b: any) => a.name.localeCompare(b.name)) - else { - let filter = PageState.policiesFilter.toLowerCase() - let stringSearch = (s: string) => s.toLowerCase().indexOf(filter) != -1 - return PageState.tables - .slice() - .filter((x: any) => { - let searchTableName = stringSearch(x.name) - let searchPolicyName = x.policies.some((p: any) => stringSearch(p.name)) - return searchTableName || searchPolicyName - }) - .sort((a: any, b: any) => a.name.localeCompare(b.name)) - } - }, - get selectedTable() { - if (!PageState.selectedTableId) return null - for (let i = 0; i < PageState.tables.length; i++) { - const element: any = PageState.tables[i] - if (element.id == PageState.selectedTableId) return element - } - }, - onTableUpdated(table: any) { - for (let i = 0; i < PageState.tables.length; i++) { - let el: any = PageState.tables[i] - if (el.id == table.id) { - PageState.tables[i] = { ...el, ...table } - } - } - }, - })) + return
{children}
+} - const { meta, ui } = useStore() - PageState.meta = meta as any - PageState.project = ui.selectedProject as any - - return ( - -
{children}
-
- ) +const onFilterTables = ( + tables: { + name: string + policies: { + name: string + }[] + }[], + keywords?: string +) => { + if (!keywords) return tables.slice().sort((a: any, b: any) => a.name.localeCompare(b.name)) + else { + let filter = keywords.toLowerCase() + let stringSearch = (s: string) => s.toLowerCase().indexOf(filter) != -1 + return tables + .slice() + .filter((x: any) => { + let searchTableName = stringSearch(x.name) + let searchPolicyName = x.policies.some((p: any) => stringSearch(p.name)) + return searchTableName || searchPolicyName + }) + .sort((a: any, b: any) => a.name.localeCompare(b.name)) + } } const AuthPoliciesPage: NextPageWithLayout = () => { - const PageState: any = useContext(PageContext) - const { meta } = useStore() - const tables = meta.tables.list((table: any) => table.schema === 'public') - - useEffect(() => { - PageState.tablesLoading = false - PageState.tables = tables.sort((a: any, b: any) => a.name.localeCompare(b.name)) - }, []) + const [policiesFilter, setPoliciesFilter] = useState(undefined) + const publicTables = meta.tables.list((table: { schema: string }) => table.schema === 'public') + const filteredTables = onFilterTables(publicTables, policiesFilter) return ( <> @@ -87,8 +55,8 @@ const AuthPoliciesPage: NextPageWithLayout = () => { size="small" placeholder="Filter tables" className="block w-full text-sm placeholder-gray-400" - value={PageState.policiesFilter} - onChange={(e) => (PageState.policiesFilter = e.target.value)} + value={policiesFilter} + onChange={(e) => setPoliciesFilter(e.target.value)} icon={} /> @@ -103,7 +71,7 @@ const AuthPoliciesPage: NextPageWithLayout = () => {
- + 0} tables={filteredTables} />
) @@ -117,10 +85,12 @@ AuthPoliciesPage.getLayout = (page) => ( export default observer(AuthPoliciesPage) -const AuthPoliciesTables = observer(() => { +interface AuthPoliciesTablesProps { + hasPublicTables: boolean + tables: any[] +} +const AuthPoliciesTables: FC = observer(({ tables, hasPublicTables }) => { const { ui, meta } = useStore() - const PageState: any = useContext(PageContext) - const roles = meta.roles.list((role: PostgresRole) => !meta.roles.systemRoles.includes(role.name)) const [selectedSchemaAndTable, setSelectedSchemaAndTable] = useState({}) @@ -157,18 +127,10 @@ const AuthPoliciesTables = observer(() => { const onSavePolicySuccess = async () => { ui.setNotification({ category: 'success', message: 'Policy successfully saved!' }) - await refreshTables() closePolicyEditorModal() } // Methods that involve some API - - const refreshTables = async () => { - await meta.tables.load() - const res: any = meta.tables.list((table: any) => table.schema === 'public') - if (!res.error) PageState.tables.replace(res) - } - const onToggleRLS = async () => { const payload = { id: selectedTableToToggleRLS.id, @@ -176,21 +138,17 @@ const AuthPoliciesTables = observer(() => { } const res: any = await meta.tables.update(payload.id, payload) - // const url = `${API_URL}/database/${router.query.ref}/tables?id=${payload.id}` - // const res = await patch(url, payload) if (res.error) { ui.setNotification({ category: 'error', message: `Failed to toggle RLS: ${res.error.message}`, }) - } else { - PageState.onTableUpdated(res) } closeConfirmModal() } const onCreatePolicy = async (payload: any) => { - const res = await PageState.meta.policies.create(payload) + const res = await meta.policies.create(payload) if (res.error) { ui.setNotification({ category: 'error', @@ -202,7 +160,7 @@ const AuthPoliciesTables = observer(() => { } const onUpdatePolicy = async (payload: any) => { - const res = await PageState.meta.policies.update(payload.id, payload) + const res = await meta.policies.update(payload.id, payload) if (res.error) { ui.setNotification({ category: 'error', @@ -214,8 +172,8 @@ const AuthPoliciesTables = observer(() => { } const onDeletePolicy = async () => { - const res = await PageState.meta.policies.del(selectedPolicyToDelete.id) - if (res.error) { + const res = await meta.policies.del(selectedPolicyToDelete.id) + if (typeof res !== 'boolean' && res.error) { ui.setNotification({ category: 'error', message: `Error deleting policy: ${res.error.message}`, @@ -223,14 +181,13 @@ const AuthPoliciesTables = observer(() => { } else { ui.setNotification({ category: 'success', message: 'Successfully deleted policy!' }) } - await refreshTables() closeConfirmModal() } return (
- {PageState.filteredTables.length > 0 ? ( - PageState.filteredTables.map((table: any) => ( + {tables.length > 0 ? ( + tables.map((table: any) => (
{ />
)) - ) : PageState.tables.length > 0 ? ( + ) : hasPublicTables ? ( ) : (