From 84eb1dce1e380facf27ef6244ba8915c805ebac9 Mon Sep 17 00:00:00 2001 From: Trezy Date: Wed, 22 Apr 2026 09:01:18 -0500 Subject: [PATCH] fix: remove linked accounts page --- .../app/dashboard/settings/accounts/page.tsx | 435 ------------------ web/src/components/app-sidebar.tsx | 6 - 2 files changed, 441 deletions(-) delete mode 100644 web/src/app/dashboard/settings/accounts/page.tsx diff --git a/web/src/app/dashboard/settings/accounts/page.tsx b/web/src/app/dashboard/settings/accounts/page.tsx deleted file mode 100644 index 65c3400..0000000 --- a/web/src/app/dashboard/settings/accounts/page.tsx +++ /dev/null @@ -1,435 +0,0 @@ -"use client"; - -import { useCallback, useEffect, useState } from "react"; -import { Link2, Unlink, RefreshCw, ExternalLink, Key } from "lucide-react"; - -import { - getExternalProviders, - getLinkedAccounts, - authorizeExternal, - syncExternal, - unlinkExternal, - connectWithConfig, -} from "@/lib/api"; -import type { ExternalProvider, LinkedAccount } from "@/types/external-accounts"; -import { Input } from "@/components/ui/input"; -import { Label } from "@/components/ui/label"; -import { SiteHeader } from "@/components/site-header"; -import { Button } from "@/components/ui/button"; -import { Badge } from "@/components/ui/badge"; -import { - ResponsiveDialog, - ResponsiveDialogClose, - ResponsiveDialogContent, - ResponsiveDialogDescription, - ResponsiveDialogFooter, - ResponsiveDialogHeader, - ResponsiveDialogTitle, -} from "@/components/ui/responsive-dialog"; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from "@/components/ui/table"; -import { - Card, - CardContent, - CardDescription, - CardHeader, - CardTitle, -} from "@/components/ui/card"; - -export default function LinkedAccountsPage() { - const [providers, setProviders] = useState([]); - const [accounts, setAccounts] = useState([]); - const [error, setError] = useState(null); - const [unlinkId, setUnlinkId] = useState(null); - const [unlinking, setUnlinking] = useState(false); - const [syncing, setSyncing] = useState(null); - const [syncResult, setSyncResult] = useState<{ pluginId: string; written: number } | null>(null); - // API key config dialog state - const [configProvider, setConfigProvider] = useState(null); - const [configValues, setConfigValues] = useState>({}); - const [connecting, setConnecting] = useState(false); - - const load = useCallback(async () => { - try { - const [providerList, accountList] = await Promise.all([ - getExternalProviders(), - getLinkedAccounts(), - ]); - setProviders(providerList); - setAccounts(accountList); - setError(null); - } catch (e) { - setError(e instanceof Error ? e.message : String(e)); - } - }, []); - - useEffect(() => { - load(); - }, [load]); - - async function handleConnect(pluginId: string) { - const provider = providers.find((p) => p.id === pluginId); - if (!provider) return; - - // For API key auth, show config dialog instead of redirecting - if (provider.auth_type === "api_key" && provider.config_schema) { - setConfigProvider(provider); - setConfigValues({}); - return; - } - - // For OAuth/OpenID, redirect to provider - try { - const redirectUri = window.location.href; - const result = await authorizeExternal(pluginId, redirectUri); - window.location.href = result.authorize_url; - } catch (e) { - setError(e instanceof Error ? e.message : String(e)); - } - } - - async function handleConfigSubmit() { - if (!configProvider) return; - - setConnecting(true); - setError(null); - try { - await connectWithConfig(configProvider.id, configValues); - setConfigProvider(null); - setConfigValues({}); - load(); - } catch (e) { - setError(e instanceof Error ? e.message : String(e)); - } finally { - setConnecting(false); - } - } - - async function handleSync(pluginId: string) { - setSyncing(pluginId); - setSyncResult(null); - try { - const result = await syncExternal(pluginId); - setSyncResult({ pluginId, written: result.written }); - setError(null); - } catch (e) { - setError(e instanceof Error ? e.message : String(e)); - } finally { - setSyncing(null); - } - } - - async function handleUnlink(pluginId: string) { - setUnlinking(true); - try { - await unlinkExternal(pluginId); - setUnlinkId(null); - load(); - } catch (e) { - setError(e instanceof Error ? e.message : String(e)); - } finally { - setUnlinking(false); - } - } - - // Build a map of linked accounts by plugin_id - const linkedByPlugin = new Map(accounts.map((a) => [a.plugin_id, a])); - - return ( - <> - -
- {error &&

{error}

} - - {syncResult && ( -
-

- Sync complete: {syncResult.written} records written to your PDS -

-
- )} - -
-

External Account Providers

-

- Connect external platforms to sync data to your AT Protocol repository. -

-
- - {providers.length === 0 ? ( - - - No Providers Available - - No external account plugins are currently loaded. Contact your - administrator to install plugins. - - - - ) : ( -
- {providers.map((provider) => { - const linked = linkedByPlugin.get(provider.id); - const isSyncing = syncing === provider.id; - - return ( - - -
- - {provider.icon_url && ( - - )} - {provider.name} - - {linked && ( - - Connected - - )} -
-
- - {linked ? ( -
-
- Account ID:{" "} - {linked.account_id} -
-
- Connected {new Date(linked.created_at).toLocaleDateString()} -
-
- - -
-
- ) : ( - - )} -
-
- ); - })} -
- )} - - {accounts.length > 0 && ( - <> -
-

Connected Accounts

-

- Your linked external accounts and their sync status. -

-
- -
- - - - Provider - Account ID - Connected - Last Updated - - - - - {accounts.map((account) => { - const provider = providers.find( - (p) => p.id === account.plugin_id - ); - const isSyncing = syncing === account.plugin_id; - - return ( - - - {provider?.name ?? account.plugin_id} - - - {account.account_id} - - - {new Date(account.created_at).toLocaleString()} - - - {new Date(account.updated_at).toLocaleString()} - - -
- - -
-
-
- ); - })} -
-
-
- - )} -
- - { - if (!open) setUnlinkId(null); - }} - > - - - Unlink account? - - This will disconnect your external account and remove the stored - credentials. You can reconnect at any time. - - - {unlinkId && ( -

- Provider:{" "} - - {providers.find((p) => p.id === unlinkId)?.name ?? unlinkId} - -

- )} - - - - - - -
-
- - {/* API Key / Config Dialog */} - { - if (!open) { - setConfigProvider(null); - setConfigValues({}); - } - }} - > - - - - {configProvider?.icon_url && ( - - )} - Connect {configProvider?.name} - - - Enter your credentials to connect this account. - - - - {configProvider?.config_schema && ( -
- {Object.entries(configProvider.config_schema.properties).map( - ([key, prop]) => ( -
- - - setConfigValues((prev) => ({ - ...prev, - [key]: e.target.value, - })) - } - /> - {prop.description && ( -

- {prop.description} -

- )} -
- ) - )} -
- )} - - - - - - - -
-
- - ); -} diff --git a/web/src/components/app-sidebar.tsx b/web/src/components/app-sidebar.tsx index 6a11367..53bff67 100644 --- a/web/src/components/app-sidebar.tsx +++ b/web/src/components/app-sidebar.tsx @@ -12,7 +12,6 @@ import { IconKey, IconVariable, IconTag, - IconLink, IconPuzzle, IconSettings, IconInfoCircle, @@ -90,11 +89,6 @@ const integrationItems: NavItem[] = [ icon: IconPuzzle, requiredPermissions: ["plugins:read"], }, - { - title: "Linked Accounts", - url: "/dashboard/settings/accounts", - icon: IconLink, - }, { title: "Labelers", url: "/dashboard/settings/labelers", -- 2.51.2