From 0a7b4f320bcceb7ed77e4021f185cb04cdce4de6 Mon Sep 17 00:00:00 2001 From: defiQUG Date: Wed, 25 Mar 2026 21:16:08 -0700 Subject: [PATCH] portal: strict ESLint (typescript-eslint, a11y, import order) - 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 --- portal/.eslintrc.json | 36 +++++++++-- portal/src/app/admin/page.tsx | 7 ++- portal/src/app/analytics/page.tsx | 1 + .../src/app/api/auth/[...nextauth]/route.ts | 1 + portal/src/app/api/auth/error/page.tsx | 2 +- portal/src/app/argocd/page.tsx | 3 +- portal/src/app/crossplane/page.tsx | 3 +- portal/src/app/dashboard/business/page.tsx | 9 +-- portal/src/app/dashboard/developer/page.tsx | 5 +- portal/src/app/dashboard/page.tsx | 3 +- portal/src/app/dashboard/technical/page.tsx | 9 +-- portal/src/app/developer/page.tsx | 7 ++- .../src/app/developer/webhooks/test/page.tsx | 45 ++++++++++---- portal/src/app/error.tsx | 8 +-- portal/src/app/infrastructure/page.tsx | 24 +++++--- portal/src/app/kubernetes/page.tsx | 3 +- portal/src/app/layout.tsx | 13 ++-- portal/src/app/monitoring/page.tsx | 3 +- portal/src/app/not-found.tsx | 4 +- portal/src/app/onboarding/page.tsx | 4 +- portal/src/app/page.tsx | 1 + portal/src/app/partner/page.tsx | 7 ++- portal/src/app/resources/page.tsx | 11 ++-- portal/src/app/settings/2fa/page.tsx | 21 ++++--- portal/src/app/settings/page.tsx | 19 +++--- portal/src/app/unauthorized.tsx | 4 +- portal/src/app/vms/page.tsx | 1 + portal/src/components/Dashboard.tsx | 21 ++++--- .../components/KeyboardShortcutsProvider.tsx | 2 + portal/src/components/ResourceExplorer.tsx | 18 ++++-- portal/src/components/VMList.tsx | 5 +- .../src/components/ai/OptimizationEngine.tsx | 5 +- .../analytics/AdvancedAnalytics.tsx | 3 +- .../components/argocd/ArgoCDApplications.tsx | 10 +-- .../crossplane/CrossplaneResourceBrowser.tsx | 41 ++++++++----- .../src/components/dashboard/APIKeysTile.tsx | 3 +- .../src/components/dashboard/APIUsageTile.tsx | 3 +- .../src/components/dashboard/BillingTile.tsx | 3 +- .../dashboard/ComplianceStatusTile.tsx | 3 +- .../dashboard/CostForecastingTile.tsx | 3 +- .../components/dashboard/CostOverviewTile.tsx | 3 +- .../dashboard/DashboardCustomizer.tsx | 5 +- .../components/dashboard/DataPipelineTile.tsx | 3 +- .../components/dashboard/DeploymentsTile.tsx | 3 +- .../dashboard/IntegrationStatusTile.tsx | 3 +- portal/src/components/dashboard/LazyTile.tsx | 9 +-- .../dashboard/PhoenixHealthTile.tsx | 5 +- .../dashboard/QuickActionsPanel.tsx | 8 ++- .../dashboard/ResourceUsageTile.tsx | 3 +- .../dashboard/ResourceUtilizationTile.tsx | 3 +- .../dashboard/ServiceAdoptionTile.tsx | 3 +- .../components/dashboard/SystemHealthTile.tsx | 24 +++++--- .../dashboard/TestEnvironmentsTile.tsx | 3 +- .../fairness/FairnessOrchestrationWizard.tsx | 61 ++++++++++++------- .../kubernetes/KubernetesClusters.tsx | 8 ++- .../components/layout/MobileNavigation.tsx | 6 +- .../components/layout/PortalBreadcrumbs.tsx | 2 +- portal/src/components/layout/PortalHeader.tsx | 2 +- .../src/components/layout/PortalSidebar.tsx | 5 +- .../components/monitoring/LokiLogViewer.tsx | 12 ++-- .../onboarding/OnboardingWizard.tsx | 7 ++- .../onboarding/steps/PreferencesStep.tsx | 5 +- .../onboarding/steps/ProfileStep.tsx | 10 ++- .../onboarding/steps/WelcomeStep.tsx | 2 +- portal/src/components/ui/Button.tsx | 1 + portal/src/components/ui/Input.tsx | 1 + portal/src/components/ui/Tabs.tsx | 3 +- portal/src/components/ui/alert.tsx | 1 + portal/src/components/ui/badge.tsx | 1 + portal/src/components/ui/checkbox.tsx | 1 + portal/src/components/ui/label.tsx | 2 + portal/src/components/ui/select.tsx | 3 +- portal/src/components/vms/VMList.tsx | 10 +-- portal/src/hooks/useDashboardData.ts | 7 ++- portal/src/hooks/useKeyboardShortcuts.ts | 2 +- portal/src/hooks/usePhoenixRailing.ts | 17 +++--- portal/src/lib/argocd-client.ts | 32 +++++----- portal/src/lib/kubernetes-client.ts | 39 +++++++----- portal/src/lib/phoenix-api-client.ts | 30 ++++++--- portal/src/lib/test-utils.tsx | 4 +- portal/src/types/next-auth.d.ts | 2 + 81 files changed, 461 insertions(+), 264 deletions(-) diff --git a/portal/.eslintrc.json b/portal/.eslintrc.json index 5145767..36be866 100644 --- a/portal/.eslintrc.json +++ b/portal/.eslintrc.json @@ -1,11 +1,35 @@ { - "extends": "next/core-web-vitals", + "root": true, + "extends": ["next/core-web-vitals", "plugin:@typescript-eslint/recommended"], + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaVersion": 2022, + "sourceType": "module", + "ecmaFeatures": { "jsx": true } + }, + "plugins": ["@typescript-eslint"], "rules": { - "@typescript-eslint/no-explicit-any": "warn", - "no-console": "warn", + "@typescript-eslint/no-explicit-any": "error", + "@typescript-eslint/no-unused-vars": [ + "warn", + { "argsIgnorePattern": "^_", "varsIgnorePattern": "^_" } + ], "@typescript-eslint/no-empty-object-type": "off", - "jsx-a11y/label-has-associated-control": "warn", - "react/no-unescaped-entities": "warn", - "import/order": "warn" + "@typescript-eslint/no-require-imports": "off", + "no-console": "error", + "jsx-a11y/label-has-associated-control": "error", + "react/no-unescaped-entities": "error", + "import/order": [ + "error", + { + "groups": ["builtin", "external", "internal", "parent", "sibling", "index"], + "newlines-between": "always", + "alphabetize": { "order": "asc", "caseInsensitive": true }, + "pathGroups": [ + { "pattern": "@/**", "group": "internal", "position": "after" } + ], + "pathGroupsExcludedImportTypes": ["builtin"] + } + ] } } diff --git a/portal/src/app/admin/page.tsx b/portal/src/app/admin/page.tsx index f013187..75bba77 100644 --- a/portal/src/app/admin/page.tsx +++ b/portal/src/app/admin/page.tsx @@ -1,10 +1,11 @@ 'use client'; -import { useSession } from 'next-auth/react'; -import { signIn } from 'next-auth/react'; -import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card'; import { Building2, Users, CreditCard, Shield, ArrowRight } from 'lucide-react'; import Link from 'next/link'; +import { useSession } from 'next-auth/react'; +import { signIn } from 'next-auth/react'; + +import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card'; export default function AdminPortalPage() { const { data: session, status } = useSession(); diff --git a/portal/src/app/analytics/page.tsx b/portal/src/app/analytics/page.tsx index 94b0a9c..7cb0b73 100644 --- a/portal/src/app/analytics/page.tsx +++ b/portal/src/app/analytics/page.tsx @@ -2,6 +2,7 @@ import { useSession } from 'next-auth/react'; import { signIn } from 'next-auth/react'; + import { AdvancedAnalytics } from '@/components/analytics/AdvancedAnalytics'; export default function AnalyticsPage() { diff --git a/portal/src/app/api/auth/[...nextauth]/route.ts b/portal/src/app/api/auth/[...nextauth]/route.ts index 802bebd..ad645a9 100644 --- a/portal/src/app/api/auth/[...nextauth]/route.ts +++ b/portal/src/app/api/auth/[...nextauth]/route.ts @@ -1,4 +1,5 @@ import NextAuth from 'next-auth'; + import { authOptions } from '@/lib/auth'; const handler = NextAuth(authOptions); diff --git a/portal/src/app/api/auth/error/page.tsx b/portal/src/app/api/auth/error/page.tsx index 8a6f55e..0415a5b 100644 --- a/portal/src/app/api/auth/error/page.tsx +++ b/portal/src/app/api/auth/error/page.tsx @@ -1,7 +1,7 @@ 'use client'; -import { useSearchParams } from 'next/navigation'; import Link from 'next/link'; +import { useSearchParams } from 'next/navigation'; import { Suspense } from 'react'; function AuthErrorContent() { diff --git a/portal/src/app/argocd/page.tsx b/portal/src/app/argocd/page.tsx index 0c2cb6b..0874b94 100644 --- a/portal/src/app/argocd/page.tsx +++ b/portal/src/app/argocd/page.tsx @@ -1,7 +1,8 @@ 'use client' -import { useSession } from 'next-auth/react' import { redirect } from 'next/navigation' +import { useSession } from 'next-auth/react' + import ArgoCDApplications from '@/components/argocd/ArgoCDApplications' export default function ArgoCDPage() { diff --git a/portal/src/app/crossplane/page.tsx b/portal/src/app/crossplane/page.tsx index 244bcf3..28d2cdd 100644 --- a/portal/src/app/crossplane/page.tsx +++ b/portal/src/app/crossplane/page.tsx @@ -1,7 +1,8 @@ 'use client' -import { useSession } from 'next-auth/react' import { redirect } from 'next/navigation' +import { useSession } from 'next-auth/react' + import CrossplaneResourceBrowser from '@/components/crossplane/CrossplaneResourceBrowser' export default function CrossplanePage() { diff --git a/portal/src/app/dashboard/business/page.tsx b/portal/src/app/dashboard/business/page.tsx index 68695ee..bda7b2e 100644 --- a/portal/src/app/dashboard/business/page.tsx +++ b/portal/src/app/dashboard/business/page.tsx @@ -2,13 +2,14 @@ import { useSession } from 'next-auth/react'; import { signIn } from 'next-auth/react'; -import { CostOverviewTile } from '@/components/dashboard/CostOverviewTile'; -import { CostForecastingTile } from '@/components/dashboard/CostForecastingTile'; -import { ResourceUsageTile } from '@/components/dashboard/ResourceUsageTile'; + import { BillingTile } from '@/components/dashboard/BillingTile'; -import { ServiceAdoptionTile } from '@/components/dashboard/ServiceAdoptionTile'; import { ComplianceStatusTile } from '@/components/dashboard/ComplianceStatusTile'; +import { CostForecastingTile } from '@/components/dashboard/CostForecastingTile'; +import { CostOverviewTile } from '@/components/dashboard/CostOverviewTile'; import { QuickActionsPanel } from '@/components/dashboard/QuickActionsPanel'; +import { ResourceUsageTile } from '@/components/dashboard/ResourceUsageTile'; +import { ServiceAdoptionTile } from '@/components/dashboard/ServiceAdoptionTile'; export default function BusinessDashboardPage() { const { status } = useSession(); diff --git a/portal/src/app/dashboard/developer/page.tsx b/portal/src/app/dashboard/developer/page.tsx index 403d754..ea7adaf 100644 --- a/portal/src/app/dashboard/developer/page.tsx +++ b/portal/src/app/dashboard/developer/page.tsx @@ -2,11 +2,12 @@ import { useSession } from 'next-auth/react'; import { signIn } from 'next-auth/react'; + +import { APIKeysTile } from '@/components/dashboard/APIKeysTile'; import { APIUsageTile } from '@/components/dashboard/APIUsageTile'; import { DeploymentsTile } from '@/components/dashboard/DeploymentsTile'; -import { TestEnvironmentsTile } from '@/components/dashboard/TestEnvironmentsTile'; -import { APIKeysTile } from '@/components/dashboard/APIKeysTile'; import { QuickActionsPanel } from '@/components/dashboard/QuickActionsPanel'; +import { TestEnvironmentsTile } from '@/components/dashboard/TestEnvironmentsTile'; export default function DeveloperDashboardPage() { const { status } = useSession(); diff --git a/portal/src/app/dashboard/page.tsx b/portal/src/app/dashboard/page.tsx index 672c9e7..163cd44 100644 --- a/portal/src/app/dashboard/page.tsx +++ b/portal/src/app/dashboard/page.tsx @@ -1,9 +1,10 @@ 'use client'; +import { useRouter } from 'next/navigation'; import { useSession } from 'next-auth/react'; import { signIn } from 'next-auth/react'; -import { useRouter } from 'next/navigation'; import { useEffect } from 'react'; + import { getDashboardRoute } from '@/lib/roles'; export default function DashboardPage() { diff --git a/portal/src/app/dashboard/technical/page.tsx b/portal/src/app/dashboard/technical/page.tsx index 8743c1d..3ad8905 100644 --- a/portal/src/app/dashboard/technical/page.tsx +++ b/portal/src/app/dashboard/technical/page.tsx @@ -2,12 +2,13 @@ import { useSession } from 'next-auth/react'; import { signIn } from 'next-auth/react'; -import { SystemHealthTile } from '@/components/dashboard/SystemHealthTile'; -import { IntegrationStatusTile } from '@/components/dashboard/IntegrationStatusTile'; -import { DataPipelineTile } from '@/components/dashboard/DataPipelineTile'; -import { ResourceUtilizationTile } from '@/components/dashboard/ResourceUtilizationTile'; + import { OptimizationEngine } from '@/components/ai/OptimizationEngine'; +import { DataPipelineTile } from '@/components/dashboard/DataPipelineTile'; +import { IntegrationStatusTile } from '@/components/dashboard/IntegrationStatusTile'; import { QuickActionsPanel } from '@/components/dashboard/QuickActionsPanel'; +import { ResourceUtilizationTile } from '@/components/dashboard/ResourceUtilizationTile'; +import { SystemHealthTile } from '@/components/dashboard/SystemHealthTile'; export default function TechnicalDashboardPage() { const { status } = useSession(); diff --git a/portal/src/app/developer/page.tsx b/portal/src/app/developer/page.tsx index e8cc24c..15e33e8 100644 --- a/portal/src/app/developer/page.tsx +++ b/portal/src/app/developer/page.tsx @@ -1,10 +1,11 @@ 'use client'; -import { useSession } from 'next-auth/react'; -import { signIn } from 'next-auth/react'; -import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card'; import { Key, Book, TestTube, BarChart3, Webhook, Download, ArrowRight } from 'lucide-react'; import Link from 'next/link'; +import { useSession } from 'next-auth/react'; +import { signIn } from 'next-auth/react'; + +import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card'; export default function DeveloperPortalPage() { const { status } = useSession(); diff --git a/portal/src/app/developer/webhooks/test/page.tsx b/portal/src/app/developer/webhooks/test/page.tsx index 42d4d66..6bd7f7c 100644 --- a/portal/src/app/developer/webhooks/test/page.tsx +++ b/portal/src/app/developer/webhooks/test/page.tsx @@ -1,15 +1,26 @@ 'use client'; -import { useState } from 'react'; -import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card'; import { Send, CheckCircle, XCircle } from 'lucide-react'; +import { useState } from 'react'; + +import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card'; + +interface WebhookTestResult { + success: boolean; + status?: number; + statusText?: string; + responseTime?: number; + response?: unknown; + error?: string; + timestamp: string; +} export default function WebhookTestingPage() { const [url, setUrl] = useState(''); const [method, setMethod] = useState('POST'); const [headers, setHeaders] = useState('{"Content-Type": "application/json"}'); const [payload, setPayload] = useState('{"event": "test", "data": {}}'); - const [testResult, setTestResult] = useState(null); + const [testResult, setTestResult] = useState(null); const [isTesting, setIsTesting] = useState(false); const testWebhook = async () => { @@ -39,10 +50,10 @@ export default function WebhookTestingPage() { response: data, timestamp: new Date().toISOString(), }); - } catch (error: any) { + } catch (error: unknown) { setTestResult({ success: false, - error: error.message, + error: error instanceof Error ? error.message : 'Request failed', timestamp: new Date().toISOString(), }); } finally { @@ -64,8 +75,11 @@ export default function WebhookTestingPage() {
- + setUrl(e.target.value)} @@ -75,8 +89,11 @@ export default function WebhookTestingPage() {
- +