From 9c0d8ece0e61844da953abe002aba08e7cbd7bb1 Mon Sep 17 00:00:00 2001
From: Gildas Garcia <1122076+djhi@users.noreply.github.com>
Date: Mon, 28 Sep 2026 15:56:15 +0200
Subject: [PATCH] Refactor following types changes + remove app actions
---
.../OAuthApps/OAuthAppsAuthorizedList.tsx | 42 +------
.../OAuthApps/OAuthAppsAuthorizedRow.tsx | 67 +----------
.../OAuthApps/OAuthAppsMemberGrantsDialog.tsx | 105 ------------------
.../OAuthApps/OAuthAppsRevokeDialog.tsx | 103 -----------------
knip.jsonc | 10 ++
5 files changed, 20 insertions(+), 307 deletions(-)
delete mode 100644 apps/studio/components/interfaces/Organization/OAuthApps/OAuthAppsMemberGrantsDialog.tsx
delete mode 100644 apps/studio/components/interfaces/Organization/OAuthApps/OAuthAppsRevokeDialog.tsx
diff --git a/apps/studio/components/interfaces/Organization/OAuthApps/OAuthAppsAuthorizedList.tsx b/apps/studio/components/interfaces/Organization/OAuthApps/OAuthAppsAuthorizedList.tsx
index 35e152baab2..e446a04970e 100644
--- a/apps/studio/components/interfaces/Organization/OAuthApps/OAuthAppsAuthorizedList.tsx
+++ b/apps/studio/components/interfaces/Organization/OAuthApps/OAuthAppsAuthorizedList.tsx
@@ -1,6 +1,5 @@
import { PermissionAction } from '@supabase/shared-types/out/constants'
import { useParams } from 'common'
-import { useState } from 'react'
import { Card, Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from 'ui'
import {
PageSection,
@@ -13,29 +12,20 @@ import {
import { ShimmeringLoader } from 'ui-patterns/ShimmeringLoader'
import { OAuthAppsAuthorizedRow } from './OAuthAppsAuthorizedRow'
-import { OAuthAppsMemberGrantsDialog } from './OAuthAppsMemberGrantsDialog'
-import { OAuthAppsRevokeDialog } from './OAuthAppsRevokeDialog'
import { AlertError } from '@/components/ui/AlertError'
import { NoPermission } from '@/components/ui/NoPermission'
-import { useOAuthAuthorizedAppsQuery } from '@/data/oauth-apps/oauth-apps-authorized-apps-query'
-import type { OAuthAppOverviewItem } from '@/data/oauth-apps/types'
+import { useOAuthApprovalsQuery } from '@/data/oauth-apps/oauth-apps-approvals-query'
import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions'
export const OAuthAppsAuthorizedList = () => {
const { slug } = useParams()
- const [selectedAppForGrants, setSelectedAppForGrants] = useState()
- const [selectedAppToRevoke, setSelectedAppToRevoke] = useState()
const { can: canReadOAuthApps, isLoading: isLoadingPermissions } = useAsyncCheckPermissions(
PermissionAction.READ,
'approved_oauth_apps'
)
- const { can: canRevokeOAuthApps } = useAsyncCheckPermissions(
- PermissionAction.DELETE,
- 'approved_oauth_apps'
- )
- const { data: apps, isPending, isSuccess, isError, error } = useOAuthAuthorizedAppsQuery({ slug })
+ const { data: apps, isPending, isSuccess, isError, error } = useOAuthApprovalsQuery({ slug })
return (
@@ -53,7 +43,6 @@ export const OAuthAppsAuthorizedList = () => {
-
)}
@@ -69,47 +58,26 @@ export const OAuthAppsAuthorizedList = () => {
App
- Status
- Grants
-
- Actions
-
+ Access
{apps.data.length === 0 ? (
-
+
No apps have been authorized in this organization yet.
) : (
- apps.data.map((app) => (
- setSelectedAppForGrants(app)}
- onSelectRevoke={() => setSelectedAppToRevoke(app)}
- />
- ))
+ apps.data.map((app) => )
)}
)}
-
- setSelectedAppForGrants(undefined)}
- />
- setSelectedAppToRevoke(undefined)}
- />
)
}
diff --git a/apps/studio/components/interfaces/Organization/OAuthApps/OAuthAppsAuthorizedRow.tsx b/apps/studio/components/interfaces/Organization/OAuthApps/OAuthAppsAuthorizedRow.tsx
index 0db02335204..06f4a527c39 100644
--- a/apps/studio/components/interfaces/Organization/OAuthApps/OAuthAppsAuthorizedRow.tsx
+++ b/apps/studio/components/interfaces/Organization/OAuthApps/OAuthAppsAuthorizedRow.tsx
@@ -1,35 +1,12 @@
-import { MoreVertical } from 'lucide-react'
-import {
- Badge,
- Button,
- DropdownMenu,
- DropdownMenuContent,
- DropdownMenuItem,
- DropdownMenuTrigger,
- TableCell,
- TableRow,
- Tooltip,
- TooltipContent,
- TooltipTrigger,
-} from 'ui'
+import { TableCell, TableRow } from 'ui'
-import type { OAuthAppOverviewItem } from '@/data/oauth-apps/types'
+import type { OAuthApprovalItem } from '@/data/oauth-apps/types'
export interface OAuthAppsAuthorizedRowProps {
- app: OAuthAppOverviewItem
- canRevoke: boolean
- onSelectViewGrants: () => void
- onSelectRevoke: () => void
+ app: OAuthApprovalItem
}
-export const OAuthAppsAuthorizedRow = ({
- app,
- canRevoke,
- onSelectViewGrants,
- onSelectRevoke,
-}: OAuthAppsAuthorizedRowProps) => {
- const showRevoke = canRevoke && app.status === 'active'
-
+export const OAuthAppsAuthorizedRow = ({ app }: OAuthAppsAuthorizedRowProps) => {
return (
@@ -45,41 +22,7 @@ export const OAuthAppsAuthorizedRow = ({
-
- {app.status.toUpperCase()}
-
- {getGrantsLabel(app)}
-
-
-
-
-
- } className="px-1" aria-label="Actions" />
-
-
- Actions
-
-
- View grants
- {showRevoke && (
-
- Revoke
-
- )}
-
-
-
+ {app.org_grant ? 'Organization' : 'Members'}
)
}
-
-function getStatusVariant(status: OAuthAppOverviewItem['status']) {
- if (status === 'active') return 'success' as const
- return 'warning' as const
-}
-
-function getGrantsLabel(app: OAuthAppOverviewItem) {
- if (app.status === 'legacy') return 'Authorized before project controls'
- if (app.member_grant_count === 1) return '1 member grant'
- return `${app.member_grant_count} member grants`
-}
diff --git a/apps/studio/components/interfaces/Organization/OAuthApps/OAuthAppsMemberGrantsDialog.tsx b/apps/studio/components/interfaces/Organization/OAuthApps/OAuthAppsMemberGrantsDialog.tsx
deleted file mode 100644
index 74dfce5edff..00000000000
--- a/apps/studio/components/interfaces/Organization/OAuthApps/OAuthAppsMemberGrantsDialog.tsx
+++ /dev/null
@@ -1,105 +0,0 @@
-import { useParams } from 'common'
-import { Building2, User } from 'lucide-react'
-import {
- Accordion,
- AccordionContent,
- AccordionItem,
- AccordionTrigger,
- Button,
- Dialog,
- DialogContent,
- DialogFooter,
- DialogHeader,
- DialogTitle,
-} from 'ui'
-
-import { useOAuthAppMemberGrantsQuery } from '@/data/oauth-apps/oauth-apps-member-grants-query'
-import type { OAuthAppOverviewItem, OAuthGrantItem } from '@/data/oauth-apps/types'
-
-export interface OAuthAppsMemberGrantsDialogProps {
- app?: OAuthAppOverviewItem
- onClose: () => void
-}
-
-export const OAuthAppsMemberGrantsDialog = ({ app, onClose }: OAuthAppsMemberGrantsDialogProps) => {
- const { slug } = useParams()
- const { data } = useOAuthAppMemberGrantsQuery({ slug, appId: app?.id }, { enabled: Boolean(app) })
- const grants = data?.data ?? []
-
- const handleClose = () => {
- onClose()
- }
-
- return (
-
- )
-}
-
-function getGrantLabel(grant: OAuthGrantItem) {
- if (grant.user) return grant.user.email
- return 'Organization-wide'
-}
diff --git a/apps/studio/components/interfaces/Organization/OAuthApps/OAuthAppsRevokeDialog.tsx b/apps/studio/components/interfaces/Organization/OAuthApps/OAuthAppsRevokeDialog.tsx
deleted file mode 100644
index a03d8e3581c..00000000000
--- a/apps/studio/components/interfaces/Organization/OAuthApps/OAuthAppsRevokeDialog.tsx
+++ /dev/null
@@ -1,103 +0,0 @@
-import { useParams } from 'common'
-import { toast } from 'sonner'
-import {
- Button,
- Dialog,
- DialogContent,
- DialogFooter,
- DialogHeader,
- DialogSection,
- DialogTitle,
-} from 'ui'
-
-import { useOAuthAppRevokeMutation } from '@/data/oauth-apps/oauth-apps-revoke-mutation'
-import type { OAuthAppOverviewItem } from '@/data/oauth-apps/types'
-
-export interface OAuthAppsRevokeDialogProps {
- app?: OAuthAppOverviewItem
- onClose: () => void
-}
-
-export const OAuthAppsRevokeDialog = ({ app, onClose }: OAuthAppsRevokeDialogProps) => {
- const { slug } = useParams()
- const { mutate: revokeApp, isPending } = useOAuthAppRevokeMutation({
- onSuccess: () => {
- toast.success(`Revoked access for ${app?.name}`)
- onClose()
- },
- })
-
- const memberGrantCount = app?.member_grant_count ?? 0
- const hasOrgGrant = Boolean(app?.org_grant)
-
- return (
-
- )
-}
diff --git a/knip.jsonc b/knip.jsonc
index 7a79952a7e0..717c5fc0285 100644
--- a/knip.jsonc
+++ b/knip.jsonc
@@ -65,6 +65,16 @@
// read are documentation of the valid values, not dead code. Scoped to
// this file so `enumMembers` keeps working everywhere else.
"data/database/constraints-query.ts": ["enumMembers"],
+ // Org settings authorized-apps data layer, landed in #49476 ahead of the
+ // tables that consume it. Scoped to the remaining files rather than the whole
+ // folder so everything else here stays gated.
+ // TODO(FE-4330): remove — used from #50529, drop this entry in that PR.
+ "data/oauth-apps/oauth-apps-approvals-query.ts": ["files"],
+ "data/oauth-apps/oauth-apps-grants-query.ts": ["files"],
+ "data/oauth-apps/oauth-apps-member-grants-query.ts": ["files"],
+ "data/oauth-apps/oauth-apps-preflight-validation-query.ts": ["files"],
+ "data/oauth-apps/oauth-apps-revoke-grant-mutation.ts": ["files"],
+ "data/oauth-apps/oauth-apps-revoke-mutation.ts": ["files"],
"hooks/misc/useTrackExperimentExposure.ts": ["files"],
// Staging-only pinned Postgres image + FDW request payload for creating
// Warehouse test projects by hand. Nothing imports it yet — it's kept