portal: strict ESLint (typescript-eslint, a11y, import order)
Some checks failed
API CI / API Lint (push) Has been cancelled
API CI / API Type Check (push) Has been cancelled
API CI / API Test (push) Has been cancelled
API CI / API Build (push) Has been cancelled
CD Pipeline / Deploy to Staging (push) Has been cancelled
CI Pipeline / Lint and Type Check (push) Has been cancelled
CI Pipeline / Test Backend (push) Has been cancelled
CI Pipeline / Test Frontend (push) Has been cancelled
CI Pipeline / Security Scan (push) Has been cancelled
Deploy to Staging / Deploy to Staging (push) Has been cancelled
Portal CI / Portal Lint (push) Has been cancelled
Portal CI / Portal Type Check (push) Has been cancelled
Portal CI / Portal Test (push) Has been cancelled
Portal CI / Portal Build (push) Has been cancelled
Test Suite / frontend-tests (push) Has been cancelled
Test Suite / api-tests (push) Has been cancelled
Test Suite / blockchain-tests (push) Has been cancelled
Type Check / type-check (map[directory:. name:root]) (push) Has been cancelled
Type Check / type-check (map[directory:api name:api]) (push) Has been cancelled
Type Check / type-check (map[directory:portal name:portal]) (push) Has been cancelled
API CI / Build Docker Image (push) Has been cancelled
CD Pipeline / Deploy to Production (push) Has been cancelled
CI Pipeline / Build (push) Has been cancelled
Some checks failed
API CI / API Lint (push) Has been cancelled
API CI / API Type Check (push) Has been cancelled
API CI / API Test (push) Has been cancelled
API CI / API Build (push) Has been cancelled
CD Pipeline / Deploy to Staging (push) Has been cancelled
CI Pipeline / Lint and Type Check (push) Has been cancelled
CI Pipeline / Test Backend (push) Has been cancelled
CI Pipeline / Test Frontend (push) Has been cancelled
CI Pipeline / Security Scan (push) Has been cancelled
Deploy to Staging / Deploy to Staging (push) Has been cancelled
Portal CI / Portal Lint (push) Has been cancelled
Portal CI / Portal Type Check (push) Has been cancelled
Portal CI / Portal Test (push) Has been cancelled
Portal CI / Portal Build (push) Has been cancelled
Test Suite / frontend-tests (push) Has been cancelled
Test Suite / api-tests (push) Has been cancelled
Test Suite / blockchain-tests (push) Has been cancelled
Type Check / type-check (map[directory:. name:root]) (push) Has been cancelled
Type Check / type-check (map[directory:api name:api]) (push) Has been cancelled
Type Check / type-check (map[directory:portal name:portal]) (push) Has been cancelled
API CI / Build Docker Image (push) Has been cancelled
CD Pipeline / Deploy to Production (push) Has been cancelled
CI Pipeline / Build (push) Has been cancelled
- root .eslintrc with recommended TS rules; eslint --fix import order project-wide - Replace any/unknown in lib clients (ArgoCD, K8s, Phoenix), hooks, and key components - Form labels: htmlFor+id; escape apostrophes; remove or gate console (error boundary keep) - Crossplane VM status typing; webhook test result interface; infrastructure/resources maps typed Made-with: Cursor
This commit is contained in:
@@ -1,14 +1,17 @@
|
||||
'use client';
|
||||
|
||||
import { useSession } from 'next-auth/react';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { createCrossplaneClient, VM } from '@/lib/crossplane-client';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from './ui/Card';
|
||||
import { Server, Activity, AlertCircle, CheckCircle, Loader2 } from 'lucide-react';
|
||||
import { PhoenixHealthTile } from './dashboard/PhoenixHealthTile';
|
||||
import { Badge } from './ui/badge';
|
||||
import { gql } from '@apollo/client';
|
||||
import { useQuery as useApolloQuery } from '@apollo/client';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { Server, Activity, AlertCircle, CheckCircle, Loader2 } from 'lucide-react';
|
||||
import { useSession } from 'next-auth/react';
|
||||
|
||||
import { createCrossplaneClient, VM } from '@/lib/crossplane-client';
|
||||
|
||||
import { PhoenixHealthTile } from './dashboard/PhoenixHealthTile';
|
||||
import { Badge } from './ui/badge';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from './ui/Card';
|
||||
|
||||
|
||||
interface ActivityItem {
|
||||
id: string;
|
||||
@@ -65,11 +68,11 @@ export default function Dashboard() {
|
||||
// Get recent activity from resources (last 10 created/updated)
|
||||
const recentActivity: ActivityItem[] = resources
|
||||
?.slice(0, 10)
|
||||
.map((resource: any) => ({
|
||||
.map((resource: { id: string; type: string; name: string; status: string; updatedAt?: string; createdAt?: string }) => ({
|
||||
id: resource.id,
|
||||
type: resource.type,
|
||||
description: `${resource.name} - ${resource.status}`,
|
||||
timestamp: new Date(resource.updatedAt || resource.createdAt),
|
||||
timestamp: new Date(resource.updatedAt || resource.createdAt || Date.now()),
|
||||
}))
|
||||
.sort((a: ActivityItem, b: ActivityItem) => b.timestamp.getTime() - a.timestamp.getTime()) || [];
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
'use client';
|
||||
|
||||
import { ReactNode } from 'react';
|
||||
|
||||
import { useGlobalKeyboardShortcuts } from '@/hooks/useKeyboardShortcuts';
|
||||
|
||||
import { KeyboardShortcutsHelp } from './KeyboardShortcutsHelp';
|
||||
|
||||
export function KeyboardShortcutsProvider({ children }: { children: ReactNode }) {
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
'use client'
|
||||
|
||||
import { useState, type ChangeEvent } from 'react'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { useState, type ChangeEvent } from 'react'
|
||||
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card'
|
||||
import { Input } from '@/components/ui/Input'
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
|
||||
interface Resource {
|
||||
id: string
|
||||
@@ -41,7 +42,7 @@ export function ResourceExplorer() {
|
||||
}
|
||||
`
|
||||
|
||||
const variables: any = {}
|
||||
const variables: Record<string, string> = {}
|
||||
if (filterProvider !== 'all') {
|
||||
variables.provider = filterProvider
|
||||
}
|
||||
@@ -71,7 +72,16 @@ export function ResourceExplorer() {
|
||||
}
|
||||
|
||||
// Transform GraphQL response to component format
|
||||
return (result.data?.resourceInventory || []).map((item: any) => ({
|
||||
return (result.data?.resourceInventory || []).map(
|
||||
(item: {
|
||||
id: string
|
||||
name: string
|
||||
resourceType: string
|
||||
provider: string
|
||||
region?: string
|
||||
tags?: string[]
|
||||
metadata?: { status?: string }
|
||||
}) => ({
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
type: item.resourceType,
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
'use client'
|
||||
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card'
|
||||
import { Button } from '@/components/ui/Button'
|
||||
import { Server, Play, Pause, Trash2 } from 'lucide-react'
|
||||
|
||||
import { Button } from '@/components/ui/Button'
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card'
|
||||
|
||||
interface VM {
|
||||
id: string
|
||||
name: string
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card';
|
||||
import { Sparkles, TrendingDown, TrendingUp } from 'lucide-react';
|
||||
import { useState } from 'react';
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card';
|
||||
|
||||
export function OptimizationEngine() {
|
||||
const [recommendations] = useState([
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
'use client';
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card';
|
||||
import { BarChart3, TrendingUp, Users, DollarSign } from 'lucide-react';
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card';
|
||||
|
||||
export function AdvancedAnalytics() {
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
'use client'
|
||||
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
|
||||
import { useSession } from 'next-auth/react'
|
||||
import { createArgoCDClient, type ArgoCDApplication } from '@/lib/argocd-client'
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '../ui/Card'
|
||||
import { Button } from '../ui/Button'
|
||||
import { CheckCircle, XCircle, AlertCircle, RefreshCw, GitBranch } from 'lucide-react'
|
||||
import { useSession } from 'next-auth/react'
|
||||
|
||||
import { createArgoCDClient, type ArgoCDApplication } from '@/lib/argocd-client'
|
||||
|
||||
import { Button } from '../ui/Button'
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '../ui/Card'
|
||||
|
||||
export default function ArgoCDApplications() {
|
||||
const { data: session } = useSession()
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
'use client'
|
||||
|
||||
import { useState } from 'react'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { Server, Database, Network, HardDrive } from 'lucide-react'
|
||||
import { useSession } from 'next-auth/react'
|
||||
import { useState } from 'react'
|
||||
|
||||
import { createCrossplaneClient } from '@/lib/crossplane-client'
|
||||
|
||||
import { Badge } from '../ui/badge'
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '../ui/Card'
|
||||
import { Input } from '../ui/Input'
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../ui/select'
|
||||
import { Badge } from '../ui/badge'
|
||||
import { Server, Database, Network, HardDrive } from 'lucide-react'
|
||||
|
||||
|
||||
interface CrossplaneResource {
|
||||
apiVersion: string
|
||||
@@ -20,8 +23,8 @@ interface CrossplaneResource {
|
||||
creationTimestamp: string
|
||||
labels?: Record<string, string>
|
||||
}
|
||||
spec?: any
|
||||
status?: any
|
||||
spec?: unknown
|
||||
status?: unknown
|
||||
}
|
||||
|
||||
export default function CrossplaneResourceBrowser() {
|
||||
@@ -54,8 +57,7 @@ export default function CrossplaneResourceBrowser() {
|
||||
spec: vm.spec,
|
||||
status: vm.status,
|
||||
}))
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch Crossplane resources:', error)
|
||||
} catch {
|
||||
return []
|
||||
}
|
||||
},
|
||||
@@ -78,10 +80,11 @@ export default function CrossplaneResourceBrowser() {
|
||||
return <Server className="h-5 w-5 text-gray-500" />
|
||||
}
|
||||
|
||||
const getResourceStatusColor = (status: Record<string, unknown> | undefined) => {
|
||||
if (!status) return 'bg-gray-500'
|
||||
|
||||
const state = String(status.state ?? status.phase ?? 'Unknown')
|
||||
const getResourceStatusColor = (status: unknown) => {
|
||||
if (!status || typeof status !== 'object') return 'bg-gray-500'
|
||||
|
||||
const o = status as Record<string, unknown>
|
||||
const state = String(o.state ?? o.phase ?? 'Unknown')
|
||||
switch (state.toLowerCase()) {
|
||||
case 'running':
|
||||
case 'ready':
|
||||
@@ -172,7 +175,9 @@ export default function CrossplaneResourceBrowser() {
|
||||
</div>
|
||||
<div
|
||||
className={`h-3 w-3 rounded-full ${getResourceStatusColor(resource.status)}`}
|
||||
title={resource.status?.state || 'Unknown'}
|
||||
title={String(
|
||||
(resource.status as Record<string, unknown> | undefined)?.state ?? 'Unknown'
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</CardHeader>
|
||||
@@ -190,16 +195,20 @@ export default function CrossplaneResourceBrowser() {
|
||||
<span className="text-sm text-gray-500">API Version:</span>
|
||||
<span className="text-sm text-gray-400">{resource.apiVersion}</span>
|
||||
</div>
|
||||
{resource.status?.state && (
|
||||
{Boolean((resource.status as Record<string, unknown> | undefined)?.state) && (
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-sm text-gray-500">State:</span>
|
||||
<Badge variant="outline">{resource.status.state}</Badge>
|
||||
<Badge variant="outline">
|
||||
{String((resource.status as Record<string, unknown>).state)}
|
||||
</Badge>
|
||||
</div>
|
||||
)}
|
||||
{resource.status?.ipAddress && (
|
||||
{Boolean((resource.status as Record<string, unknown> | undefined)?.ipAddress) && (
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-sm text-gray-500">IP Address:</span>
|
||||
<span className="text-sm font-mono">{resource.status.ipAddress}</span>
|
||||
<span className="text-sm font-mono">
|
||||
{String((resource.status as Record<string, unknown>).ipAddress)}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{resource.metadata.labels && Object.keys(resource.metadata.labels).length > 0 && (
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
'use client';
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card';
|
||||
import { Key, AlertCircle } from 'lucide-react';
|
||||
import Link from 'next/link';
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card';
|
||||
|
||||
export function APIKeysTile() {
|
||||
// Mock data - in production, this would come from API
|
||||
const apiKeys = {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
'use client';
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card';
|
||||
import { Activity, AlertCircle } from 'lucide-react';
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card';
|
||||
|
||||
export function APIUsageTile() {
|
||||
// Mock data - in production, this would come from API
|
||||
const usage = {
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
'use client';
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card';
|
||||
import { CreditCard, FileText } from 'lucide-react';
|
||||
import Link from 'next/link';
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card';
|
||||
|
||||
export function BillingTile() {
|
||||
// Mock data - in production, this would come from API
|
||||
const billing = {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
'use client';
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card';
|
||||
import { Shield, CheckCircle, AlertCircle } from 'lucide-react';
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card';
|
||||
|
||||
export function ComplianceStatusTile() {
|
||||
// Mock data - in production, this would come from API
|
||||
const compliance = {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
'use client';
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card';
|
||||
import { TrendingUp, TrendingDown, DollarSign } from 'lucide-react';
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card';
|
||||
|
||||
export function CostForecastingTile() {
|
||||
// Mock data - in production, this would come from API
|
||||
const forecast = {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
'use client';
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card';
|
||||
import { DollarSign, TrendingUp, TrendingDown } from 'lucide-react';
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card';
|
||||
|
||||
export function CostOverviewTile() {
|
||||
// Mock data - in production, this would come from API
|
||||
const costData = {
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card';
|
||||
import { GripVertical, Plus } from 'lucide-react';
|
||||
import { useState } from 'react';
|
||||
import { DragDropContext, Droppable, Draggable, DropResult } from 'react-beautiful-dnd';
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card';
|
||||
|
||||
interface DashboardTile {
|
||||
id: string;
|
||||
component: string;
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
'use client';
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card';
|
||||
import { GitBranch, PlayCircle, PauseCircle, AlertCircle } from 'lucide-react';
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card';
|
||||
|
||||
export function DataPipelineTile() {
|
||||
// Mock data - in production, this would come from API
|
||||
const pipelines = {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
'use client';
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card';
|
||||
import { Rocket, CheckCircle, Clock, XCircle } from 'lucide-react';
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card';
|
||||
|
||||
export function DeploymentsTile() {
|
||||
// Mock data - in production, this would come from API
|
||||
const deployments = {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
'use client';
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card';
|
||||
import { Link2, CheckCircle, AlertCircle, Clock } from 'lucide-react';
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card';
|
||||
|
||||
export function IntegrationStatusTile() {
|
||||
// Mock data - in production, this would come from API
|
||||
const integrations = {
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
'use client';
|
||||
|
||||
import { Suspense, lazy, ComponentType } from 'react';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card';
|
||||
import { Loader2 } from 'lucide-react';
|
||||
import { Suspense, lazy, ComponentType } from 'react';
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card';
|
||||
|
||||
interface LazyTileProps {
|
||||
component: ComponentType<any>;
|
||||
props?: any;
|
||||
component: ComponentType<Record<string, unknown>>;
|
||||
props?: Record<string, unknown>;
|
||||
fallback?: React.ReactNode;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
'use client';
|
||||
|
||||
import { usePhoenixHealthSummary } from '@/hooks/usePhoenixRailing';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card';
|
||||
import { Activity, CheckCircle, AlertCircle } from 'lucide-react';
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card';
|
||||
import { usePhoenixHealthSummary } from '@/hooks/usePhoenixRailing';
|
||||
|
||||
export function PhoenixHealthTile() {
|
||||
const { data, isLoading, error } = usePhoenixHealthSummary();
|
||||
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
'use client';
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card';
|
||||
import Link from 'next/link';
|
||||
import type { LucideIcon } from 'lucide-react';
|
||||
import { Plus, Link as LinkIcon, FileText, Settings, Key, Rocket, Book, CreditCard, HelpCircle, Download } from 'lucide-react';
|
||||
import Link from 'next/link';
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card';
|
||||
|
||||
interface QuickAction {
|
||||
label: string;
|
||||
@@ -14,7 +16,7 @@ interface QuickActionsPanelProps {
|
||||
actions: QuickAction[];
|
||||
}
|
||||
|
||||
const iconMap: Record<string, any> = {
|
||||
const iconMap: Record<string, LucideIcon> = {
|
||||
Plus,
|
||||
Link: LinkIcon,
|
||||
FileText,
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
'use client';
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card';
|
||||
import { BarChart3 } from 'lucide-react';
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card';
|
||||
|
||||
export function ResourceUsageTile() {
|
||||
// Mock data - in production, this would come from API
|
||||
const usageByDivision = [
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
'use client';
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card';
|
||||
import { Cpu, HardDrive, Activity } from 'lucide-react';
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card';
|
||||
|
||||
export function ResourceUtilizationTile() {
|
||||
// Mock data - in production, this would come from API
|
||||
const utilization = {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
'use client';
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card';
|
||||
import { TrendingUp } from 'lucide-react';
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card';
|
||||
|
||||
export function ServiceAdoptionTile() {
|
||||
// Mock data - in production, this would come from API
|
||||
const services = [
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
'use client';
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card';
|
||||
import { Activity, CheckCircle, AlertCircle, XCircle, Globe, Server } from 'lucide-react';
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card';
|
||||
import { useSystemHealth } from '@/hooks/useDashboardData';
|
||||
|
||||
type HealthSite = { status?: string };
|
||||
type HealthResource = { status?: string };
|
||||
|
||||
export function SystemHealthTile() {
|
||||
const { data, loading, error } = useSystemHealth();
|
||||
|
||||
@@ -11,21 +15,21 @@ export function SystemHealthTile() {
|
||||
const healthData = data ? {
|
||||
regions: {
|
||||
total: data.sites?.length || 0,
|
||||
healthy: data.sites?.filter((s: any) => s.status === 'ACTIVE').length || 0,
|
||||
warning: data.sites?.filter((s: any) => s.status === 'MAINTENANCE').length || 0,
|
||||
critical: data.sites?.filter((s: any) => s.status === 'INACTIVE').length || 0,
|
||||
healthy: data.sites?.filter((s: HealthSite) => s.status === 'ACTIVE').length || 0,
|
||||
warning: data.sites?.filter((s: HealthSite) => s.status === 'MAINTENANCE').length || 0,
|
||||
critical: data.sites?.filter((s: HealthSite) => s.status === 'INACTIVE').length || 0,
|
||||
},
|
||||
clusters: {
|
||||
total: data.resources?.length || 0,
|
||||
healthy: data.resources?.filter((r: any) => r.status === 'RUNNING').length || 0,
|
||||
warning: data.resources?.filter((r: any) => r.status === 'PROVISIONING').length || 0,
|
||||
critical: data.resources?.filter((r: any) => r.status === 'ERROR').length || 0,
|
||||
healthy: data.resources?.filter((r: HealthResource) => r.status === 'RUNNING').length || 0,
|
||||
warning: data.resources?.filter((r: HealthResource) => r.status === 'PROVISIONING').length || 0,
|
||||
critical: data.resources?.filter((r: HealthResource) => r.status === 'ERROR').length || 0,
|
||||
},
|
||||
nodes: {
|
||||
total: data.resources?.length || 0,
|
||||
healthy: data.resources?.filter((r: any) => r.status === 'RUNNING').length || 0,
|
||||
warning: data.resources?.filter((r: any) => r.status === 'PROVISIONING').length || 0,
|
||||
critical: data.resources?.filter((r: any) => r.status === 'ERROR').length || 0,
|
||||
healthy: data.resources?.filter((r: HealthResource) => r.status === 'RUNNING').length || 0,
|
||||
warning: data.resources?.filter((r: HealthResource) => r.status === 'PROVISIONING').length || 0,
|
||||
critical: data.resources?.filter((r: HealthResource) => r.status === 'ERROR').length || 0,
|
||||
},
|
||||
} : {
|
||||
regions: { total: 0, healthy: 0, warning: 0, critical: 0 },
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
'use client';
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card';
|
||||
import { TestTube, PlayCircle, PauseCircle } from 'lucide-react';
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card';
|
||||
|
||||
export function TestEnvironmentsTile() {
|
||||
// Mock data - in production, this would come from API
|
||||
const environments = {
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
'use client';
|
||||
|
||||
import { InfoIcon, AlertTriangleIcon, CheckCircleIcon } from 'lucide-react';
|
||||
import { useState, useMemo } from 'react';
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/Card';
|
||||
|
||||
import { Alert, AlertDescription } from '@/components/ui/alert';
|
||||
import { Button } from '@/components/ui/Button';
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/Card';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import { Input } from '@/components/ui/Input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||
import { Alert, AlertDescription } from '@/components/ui/alert';
|
||||
import { InfoIcon, AlertTriangleIcon, CheckCircleIcon } from 'lucide-react';
|
||||
|
||||
// Import orchestration engine (would be from API in production)
|
||||
import type { OrchestrationRequest, InputSpec, TimelineSpec } from '@/lib/fairness-orchestration';
|
||||
import { orchestrate, getAvailableOutputs, getUserMessage } from '@/lib/fairness-orchestration';
|
||||
|
||||
@@ -122,24 +121,42 @@ export default function FairnessOrchestrationWizard() {
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Label htmlFor="dateRange">Date Range (Optional)</Label>
|
||||
<p className="text-sm font-medium mb-2">Date range (optional)</p>
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
<Input
|
||||
type="date"
|
||||
value={inputSpec.dateRange?.start || ''}
|
||||
onChange={(e) => setInputSpec(prev => ({
|
||||
...prev,
|
||||
dateRange: { ...prev.dateRange, start: e.target.value } as any
|
||||
}))}
|
||||
/>
|
||||
<Input
|
||||
type="date"
|
||||
value={inputSpec.dateRange?.end || ''}
|
||||
onChange={(e) => setInputSpec(prev => ({
|
||||
...prev,
|
||||
dateRange: { ...prev.dateRange, end: e.target.value } as any
|
||||
}))}
|
||||
/>
|
||||
<div>
|
||||
<Label htmlFor="fairness-date-start">Start</Label>
|
||||
<Input
|
||||
id="fairness-date-start"
|
||||
type="date"
|
||||
value={inputSpec.dateRange?.start || ''}
|
||||
onChange={(e) =>
|
||||
setInputSpec((prev) => ({
|
||||
...prev,
|
||||
dateRange: {
|
||||
start: e.target.value,
|
||||
end: prev.dateRange?.end ?? '',
|
||||
},
|
||||
}))
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Label htmlFor="fairness-date-end">End</Label>
|
||||
<Input
|
||||
id="fairness-date-end"
|
||||
type="date"
|
||||
value={inputSpec.dateRange?.end || ''}
|
||||
onChange={(e) =>
|
||||
setInputSpec((prev) => ({
|
||||
...prev,
|
||||
dateRange: {
|
||||
start: prev.dateRange?.start ?? '',
|
||||
end: e.target.value,
|
||||
},
|
||||
}))
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
'use client'
|
||||
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { useSession } from 'next-auth/react'
|
||||
import { createKubernetesClient } from '@/lib/kubernetes-client'
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '../ui/Card'
|
||||
import { Server, CheckCircle, XCircle } from 'lucide-react'
|
||||
import { useSession } from 'next-auth/react'
|
||||
|
||||
import { createKubernetesClient } from '@/lib/kubernetes-client'
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '../ui/Card'
|
||||
|
||||
export default function KubernetesClusters() {
|
||||
const { data: session } = useSession()
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import { usePathname } from 'next/navigation';
|
||||
import Link from 'next/link';
|
||||
import {
|
||||
LayoutDashboard,
|
||||
Server,
|
||||
@@ -15,6 +12,9 @@ import {
|
||||
Menu,
|
||||
X,
|
||||
} from 'lucide-react';
|
||||
import Link from 'next/link';
|
||||
import { usePathname } from 'next/navigation';
|
||||
import { useState } from 'react';
|
||||
|
||||
const navigation = [
|
||||
{ name: 'Dashboard', href: '/dashboard', icon: LayoutDashboard },
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
'use client'
|
||||
|
||||
import { ChevronRight, Home } from 'lucide-react'
|
||||
import Link from 'next/link'
|
||||
import { usePathname } from 'next/navigation'
|
||||
import { ChevronRight, Home } from 'lucide-react'
|
||||
|
||||
export function PortalBreadcrumbs() {
|
||||
const pathname = usePathname()
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
'use client'
|
||||
|
||||
import { Search, Bell, Settings, User, LogOut } from 'lucide-react'
|
||||
import Link from 'next/link'
|
||||
import { useSession } from 'next-auth/react'
|
||||
import { Search, Bell, Settings, User, LogOut } from 'lucide-react'
|
||||
import { signOut } from 'next-auth/react'
|
||||
|
||||
export function PortalHeader() {
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
'use client'
|
||||
|
||||
import Link from 'next/link'
|
||||
import { usePathname } from 'next/navigation'
|
||||
import {
|
||||
LayoutDashboard,
|
||||
Server,
|
||||
@@ -14,6 +12,9 @@ import {
|
||||
Shield,
|
||||
HelpCircle
|
||||
} from 'lucide-react'
|
||||
import Link from 'next/link'
|
||||
import { usePathname } from 'next/navigation'
|
||||
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const navigation = [
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
'use client'
|
||||
|
||||
import { useState, useEffect } from 'react'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '../ui/Card'
|
||||
import { Button } from '../ui/Button'
|
||||
import { Input } from '../ui/Input'
|
||||
import { RefreshCw, Search, Download } from 'lucide-react'
|
||||
import axios from 'axios'
|
||||
import { RefreshCw, Search, Download } from 'lucide-react'
|
||||
import { useState, useEffect } from 'react'
|
||||
|
||||
import { Button } from '../ui/Button'
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '../ui/Card'
|
||||
import { Input } from '../ui/Input'
|
||||
|
||||
|
||||
interface LogEntry {
|
||||
stream: Record<string, string>
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card';
|
||||
import { CheckCircle, ArrowRight, ArrowLeft } from 'lucide-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useState } from 'react';
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card';
|
||||
|
||||
interface OnboardingStep {
|
||||
id: string;
|
||||
title: string;
|
||||
description: string;
|
||||
component: React.ComponentType<any>;
|
||||
component: React.ComponentType<{ onComplete: () => void }>;
|
||||
}
|
||||
|
||||
interface OnboardingWizardProps {
|
||||
|
||||
@@ -26,8 +26,11 @@ export function PreferencesStep({ onComplete }: { onComplete: () => void }) {
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm text-gray-300 mb-2">Theme</label>
|
||||
<label htmlFor="onboarding-theme" className="block text-sm text-gray-300 mb-2">
|
||||
Theme
|
||||
</label>
|
||||
<select
|
||||
id="onboarding-theme"
|
||||
value={theme}
|
||||
onChange={(e) => setTheme(e.target.value)}
|
||||
className="w-full px-4 py-2 bg-gray-900 border border-gray-700 rounded text-white"
|
||||
|
||||
@@ -15,8 +15,11 @@ export function ProfileStep({ onComplete }: { onComplete: () => void }) {
|
||||
return (
|
||||
<form onSubmit={handleSubmit} className="space-y-4">
|
||||
<div>
|
||||
<label className="block text-sm text-gray-300 mb-2">Full Name</label>
|
||||
<label htmlFor="onboarding-full-name" className="block text-sm text-gray-300 mb-2">
|
||||
Full Name
|
||||
</label>
|
||||
<input
|
||||
id="onboarding-full-name"
|
||||
type="text"
|
||||
value={name}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
@@ -25,8 +28,11 @@ export function ProfileStep({ onComplete }: { onComplete: () => void }) {
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm text-gray-300 mb-2">Role</label>
|
||||
<label htmlFor="onboarding-role" className="block text-sm text-gray-300 mb-2">
|
||||
Role
|
||||
</label>
|
||||
<select
|
||||
id="onboarding-role"
|
||||
value={role}
|
||||
onChange={(e) => setRole(e.target.value)}
|
||||
className="w-full px-4 py-2 bg-gray-900 border border-gray-700 rounded text-white"
|
||||
|
||||
@@ -17,7 +17,7 @@ export function WelcomeStep({ onComplete }: { onComplete: () => void }) {
|
||||
Welcome to Sankofa Phoenix Nexus Console
|
||||
</h2>
|
||||
<p className="text-gray-400 mb-6">
|
||||
Let's get you set up in just a few steps. This will only take a minute.
|
||||
Let's get you set up in just a few steps. This will only take a minute.
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as React from 'react'
|
||||
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as React from 'react'
|
||||
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import * as React from 'react'
|
||||
import * as TabsPrimitive from '@radix-ui/react-tabs'
|
||||
import * as React from 'react'
|
||||
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const Tabs = TabsPrimitive.Root
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as React from 'react'
|
||||
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
interface AlertProps {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as React from 'react'
|
||||
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
export interface BadgeProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
'use client'
|
||||
|
||||
import * as React from 'react'
|
||||
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
export interface CheckboxProps {
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/* eslint-disable jsx-a11y/label-has-associated-control -- Primitive; pair htmlFor with inputs at call sites */
|
||||
import * as React from 'react'
|
||||
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
export interface LabelProps extends React.LabelHTMLAttributes<HTMLLabelElement> {}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import * as React from 'react'
|
||||
import * as SelectPrimitive from '@radix-ui/react-select'
|
||||
import { Check, ChevronDown } from 'lucide-react'
|
||||
import * as React from 'react'
|
||||
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const Select = SelectPrimitive.Root
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
'use client';
|
||||
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { useSession } from 'next-auth/react';
|
||||
import { createCrossplaneClient } from '@/lib/crossplane-client';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '../ui/Card';
|
||||
import { Play, Square, Trash2, Plus } from 'lucide-react';
|
||||
import { useSession } from 'next-auth/react';
|
||||
|
||||
import { createCrossplaneClient, type VM } from '@/lib/crossplane-client';
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '../ui/Card';
|
||||
|
||||
export default function VMList() {
|
||||
const { data: session } = useSession();
|
||||
@@ -39,7 +41,7 @@ export default function VMList() {
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
{vms.map((vm: any) => (
|
||||
{vms.map((vm: VM) => (
|
||||
<Card key={vm.metadata.name}>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-lg">{vm.metadata.name}</CardTitle>
|
||||
|
||||
Reference in New Issue
Block a user