diff --git a/apps/web/src/components/developer/DeveloperDashboardView.tsx b/apps/web/src/components/developer/DeveloperDashboardView.tsx index cdc5f1e50..66a0b9809 100644 --- a/apps/web/src/components/developer/DeveloperDashboardView.tsx +++ b/apps/web/src/components/developer/DeveloperDashboardView.tsx @@ -1,322 +1,50 @@ -import React, { useState, useEffect } from 'react'; -import { Card, CardHeader, CardTitle, CardContent } from '../ui/card'; +/** + * Developer Dashboard — simplified (P2.3) + * API Keys management has no backend yet. This page shows a "Coming soon" message + * and links to the API documentation (Swagger). Webhooks are available at /webhooks. + */ +import React from 'react'; +import { Card, CardContent } from '../ui/card'; import { Button } from '../ui/button'; -import { StatCard } from '../dashboard/StatCard'; -import { CreateAPIKeyModal } from './modals/CreateAPIKeyModal'; -import { - Key, - Activity, - Globe, - Plus, - Trash2, - Eye, - ExternalLink, - FileText, - Copy, - Check, -} from 'lucide-react'; -import { useToast } from '../../components/feedback/ToastProvider'; -import { developerService } from '../../services/developerService'; -import { logger } from '@/utils/logger'; -import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; +import { FileText, ExternalLink } from 'lucide-react'; import { SwaggerUIDoc } from './SwaggerUI'; -import { useCopyToClipboard } from '@/hooks/useCopyToClipboard'; -import { DeveloperDashboardViewSkeleton } from './DeveloperDashboardViewSkeleton'; import { EmptyState } from '../ui/empty-state'; -import { ErrorDisplay } from '../ui/ErrorDisplay'; - -interface ApiKey { - id: string; - name: string; - prefix: string; - created: string; - lastUsed: string; - status: 'active' | 'revoked'; -} export const DeveloperDashboardView: React.FC = () => { - const { addToast } = useToast(); - const { copy } = useCopyToClipboard(); - const [copiedKeyId, setCopiedKeyId] = useState(null); - const [keys, setKeys] = useState([]); - const [loading, setLoading] = useState(true); - const [error, setError] = useState(null); - const [stats, setStats] = useState({}); - const [showCreateModal, setShowCreateModal] = useState(false); - - const handleCopyKey = async (key: ApiKey) => { - await copy(key.prefix); - setCopiedKeyId(key.id); - addToast('Key prefix copied to clipboard', 'success'); - setTimeout(() => setCopiedKeyId(null), 2000); - }; - - const fetchData = async () => { - setLoading(true); - setError(null); - try { - const [keysData, statsData] = await Promise.all([ - developerService.listKeys(), - developerService.getStats(), - ]); - setKeys(keysData); - setStats(statsData); - } catch (e) { - const err = e instanceof Error ? e : new Error(String(e)); - setError(err); - logger.error('Error loading developer dashboard data', { - error: err.message, - stack: err.stack, - }); - } finally { - setLoading(false); - } - }; - - useEffect(() => { - fetchData(); - }, []); - - const handleCreateKey = async (data: { - name: string; - scopes: string[]; - }): Promise<{ key?: string; id: string; name: string; prefix: string }> => { - try { - const newKey = await developerService.createKey(data); - setKeys([newKey, ...keys]); - addToast('API Key created successfully', 'success'); - return newKey; - } catch (e) { - addToast('Failed to create API key', 'error'); - throw e; - } - }; - - const handleRevoke = async (id: string) => { - if (confirm('Are you sure you want to revoke this key?')) { - await developerService.revokeKey(id); - // Refresh list - const updated = await developerService.listKeys(); - setKeys(updated); - addToast('API Key revoked', 'info'); - } - }; - - const handleDelete = async (id: string) => { - if (confirm('Are you sure you want to delete this key permanently?')) { - await developerService.deleteKey(id); - setKeys(keys.filter((k) => k.id !== id)); - addToast('API Key deleted', 'info'); - } - }; - - if (loading) return ; - if (error) - return ( -
- -
- ); - return (
- {/* Header */}

DEVELOPER PORTAL

- Build on top of the Veza Platform. + API & Webhooks — Coming soon. Explore the API documentation below.

-
- - -
+
- - - - - Overview & Keys - - - - API Documentation - - + + + } + title="API Keys — Coming soon" + description="API key management will be available in a future release. In the meantime, use the interactive API documentation below to explore endpoints. Webhooks can be configured from the Webhooks page." + variant="card" + /> + + - - {/* Stats */} -
- } - trend={5.2} - color="cyan" - /> - } - trend={-12} - color="lime" - /> - } - color="gold" - /> -
- - {/* API Keys List */} - - - - Active API Keys - - - {keys.filter(k => k.status === 'active').length} active - - - - {keys.length === 0 ? ( - } - title="No API keys yet" - description="Create your first API key to start building on the Veza Platform." - action={{ - label: 'Create API Key', - onClick: () => setShowCreateModal(true), - variant: 'default', - }} - variant="card" - /> - ) : ( -
- - - - - - - - - - - - - {keys.map((key) => ( - - - - - - - - - ))} - -
NameKey PrefixStatusCreatedLast UsedActions
{key.name} -
- - {key.prefix} - - -
-
- - - {key.status} - - {key.created}{key.lastUsed} - - {key.status === 'active' ? ( - - ) : ( - - )} -
-
- )} -
-
-
- - - - {/* Use iframe mode for better compatibility if JSON fetching has issues CORS/Auth */} - - - -
- - {showCreateModal && ( - setShowCreateModal(false)} - onCreate={handleCreateKey} - /> - )} + + +
); }; diff --git a/apps/web/src/router/routeConfig.tsx b/apps/web/src/router/routeConfig.tsx index e9e522340..3802595f3 100644 --- a/apps/web/src/router/routeConfig.tsx +++ b/apps/web/src/router/routeConfig.tsx @@ -91,12 +91,10 @@ export function getProtectedRoutes(): RouteEntry[] { { path: '/playlists/*', element: wrapProtected() }, { path: '/search', element: wrapProtected() }, { path: '/notifications', element: wrapProtected() }, - { path: '/analytics', element: wrapProtected( {}} />) }, + { path: '/analytics', element: wrapProtected() }, { path: '/webhooks', element: wrapProtected() }, { path: '/admin', element: wrapProtected() }, - { path: '/social', element: wrapProtected( {}} />) }, - // Queue, Developer: connected to backend or client storage - // Ghost features (Education, Gamification, Studio) — FEATURES.EDUCATION/GAMIFICATION/STUDIO = false, no routes + { path: '/social', element: wrapProtected() }, { path: '/queue', element: wrapProtected() }, { path: '/developer', element: wrapProtected() }, // Gear: connected to backend inventory API