initial commit

This commit is contained in:
gulimabr
2025-11-28 12:33:37 -03:00
commit 5da54393ff
42 changed files with 3251 additions and 0 deletions

View File

@@ -0,0 +1,245 @@
import { useAuth } from '@/hooks'
// Icons as components for cleaner code
const DataServicesIcon = () => (
<svg className="w-16 h-16" viewBox="0 0 64 64" fill="none" stroke="currentColor" strokeWidth="2">
<rect x="12" y="8" width="40" height="48" rx="2" />
<line x1="20" y1="20" x2="44" y2="20" />
<line x1="20" y1="28" x2="44" y2="28" />
<line x1="20" y1="36" x2="44" y2="36" />
<line x1="20" y1="44" x2="36" y2="44" />
<rect x="36" y="40" width="12" height="12" rx="1" />
<line x1="40" y1="44" x2="44" y2="44" />
<line x1="40" y1="48" x2="44" y2="48" />
</svg>
)
const IntegrationIcon = () => (
<svg className="w-16 h-16" viewBox="0 0 64 64" fill="none" stroke="currentColor" strokeWidth="2">
<rect x="8" y="16" width="20" height="14" rx="2" />
<rect x="36" y="16" width="20" height="14" rx="2" />
<rect x="22" y="38" width="20" height="14" rx="2" />
<line x1="18" y1="30" x2="18" y2="38" />
<line x1="18" y1="38" x2="32" y2="38" />
<line x1="46" y1="30" x2="46" y2="38" />
<line x1="46" y1="38" x2="32" y2="38" />
</svg>
)
const IntelligenceIcon = () => (
<svg className="w-16 h-16" viewBox="0 0 64 64" fill="none" stroke="currentColor" strokeWidth="2">
<circle cx="28" cy="28" r="14" />
<line x1="38" y1="38" x2="52" y2="52" strokeWidth="4" strokeLinecap="round" />
<path d="M22 28 L26 32 L34 24" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
</svg>
)
const UserExperienceIcon = () => (
<svg className="w-16 h-16" viewBox="0 0 64 64" fill="none" stroke="currentColor" strokeWidth="2">
<circle cx="32" cy="20" r="8" />
<circle cx="16" cy="36" r="4" />
<circle cx="48" cy="36" r="4" />
<circle cx="24" cy="52" r="4" />
<circle cx="40" cy="52" r="4" />
<line x1="32" y1="28" x2="32" y2="36" />
<line x1="32" y1="36" x2="16" y2="36" />
<line x1="32" y1="36" x2="48" y2="36" />
<line x1="20" y1="40" x2="24" y2="48" />
<line x1="44" y1="40" x2="40" y2="48" />
</svg>
)
const ManagementIcon = () => (
<svg className="w-16 h-16" viewBox="0 0 64 64" fill="none" stroke="currentColor" strokeWidth="2">
<circle cx="32" cy="32" r="12" />
<path d="M32 16 L32 20" />
<path d="M32 44 L32 48" />
<path d="M16 32 L20 32" />
<path d="M44 32 L48 32" />
<path d="M20.7 20.7 L23.5 23.5" />
<path d="M40.5 40.5 L43.3 43.3" />
<path d="M20.7 43.3 L23.5 40.5" />
<path d="M40.5 23.5 L43.3 20.7" />
<rect x="26" y="28" width="12" height="10" rx="1" />
<path d="M29 28 L29 26 L35 26 L35 28" />
<line x1="29" y1="32" x2="35" y2="32" />
</svg>
)
const TrustworthinessIcon = () => (
<svg className="w-16 h-16" viewBox="0 0 64 64" fill="none" stroke="currentColor" strokeWidth="2">
<path d="M12 36 C12 36 20 28 32 36 C44 44 52 36 52 36" strokeLinecap="round" />
<path d="M12 36 L24 48 L32 36" strokeLinecap="round" strokeLinejoin="round" />
<path d="M52 36 L40 48 L32 36" strokeLinecap="round" strokeLinejoin="round" />
</svg>
)
export default function DashboardPage() {
const { user, logout } = useAuth()
return (
<div className="min-h-screen bg-white">
{/* Header */}
<header className="py-6 text-center">
<h1 className="text-3xl font-semibold text-teal-700">
Digital Twin Requirements Tool
</h1>
</header>
{/* Top Bar */}
<div className="border-y border-gray-200 py-3 px-8">
<div className="flex items-center justify-between max-w-7xl mx-auto">
{/* Breadcrumb */}
<div className="text-sm">
<span className="text-gray-600">Projects</span>
<span className="mx-2 text-gray-400">»</span>
<span className="font-semibold text-gray-900">PeTWIN</span>
</div>
{/* Language Toggle */}
<div className="flex items-center gap-2 text-sm text-gray-600">
<span>English</span>
<div className="relative inline-flex h-5 w-10 items-center rounded-full bg-gray-300">
<span className="inline-block h-4 w-4 transform rounded-full bg-white shadow-sm translate-x-0.5" />
</div>
<span>Portuguese</span>
</div>
{/* Admin Panel Button */}
<button className="px-4 py-1.5 border border-gray-400 rounded text-sm font-medium text-gray-700 hover:bg-gray-50">
Admin Panel
</button>
{/* User Info */}
<div className="flex items-center gap-3">
<div className="flex items-center gap-2">
<svg className="w-5 h-5 text-gray-600" fill="currentColor" viewBox="0 0 20 20">
<path fillRule="evenodd" d="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z" clipRule="evenodd" />
</svg>
<span className="text-sm text-gray-700">
{user?.full_name || user?.preferred_username || 'User'}{' '}
<span className="text-gray-500">(admin)</span>
</span>
</div>
<button
onClick={logout}
className="px-3 py-1 border border-gray-400 rounded text-sm text-gray-700 hover:bg-gray-50"
>
Logout
</button>
</div>
</div>
</div>
{/* Main Content */}
<div className="max-w-7xl mx-auto px-8 py-8">
<div className="flex gap-12">
{/* Left Sidebar */}
<div className="w-64 flex-shrink-0">
{/* Requirements Search */}
<div className="mb-8">
<h2 className="text-lg font-bold text-gray-800 mb-1">Requirements Search</h2>
<p className="text-sm text-teal-600">
Search for specific elements by name or symbol.
</p>
</div>
{/* Create a Requirement */}
<div className="mb-8">
<h2 className="text-lg font-bold text-gray-800 mb-1">Create a Requirement</h2>
<p className="text-sm text-teal-600">
Register a new Requirement.
</p>
</div>
{/* Last Viewed Requirement */}
<div className="mb-8">
<h2 className="text-lg font-bold text-gray-800 mb-1">Last Viewed Requirement:</h2>
<p className="text-sm text-gray-600 mb-1">No requirement accessed yet</p>
<a href="#" className="text-sm text-teal-600 hover:underline">
View More
</a>
</div>
{/* My Requirements */}
<div className="mb-8">
<h2 className="text-lg font-bold text-gray-800 mb-1">My Requirements</h2>
<p className="text-sm text-teal-600">
View your requirements and their properties.
</p>
</div>
{/* Requirement Report */}
<div className="mb-8">
<h2 className="text-lg font-bold text-gray-800 mb-1">Requirement Report</h2>
<p className="text-sm text-teal-600">
Generate the current status of this projects requirements in PDF format
</p>
</div>
</div>
{/* Right Content - Quick Search Filters */}
<div className="flex-1">
<h2 className="text-xl font-semibold text-gray-700 mb-6 text-center">
Quick Search Filters
</h2>
{/* Grid Layout matching the screenshot */}
<div className="grid grid-cols-4 gap-0 max-w-2xl mx-auto">
{/* Row 1 */}
{/* Data Services - spans 2 rows */}
<div className="row-span-2 bg-blue-200 border border-blue-300 flex flex-col items-center justify-center p-4 cursor-pointer hover:bg-blue-300 transition-colors min-h-[200px]">
<div className="text-blue-800">
<DataServicesIcon />
</div>
<span className="mt-3 text-sm font-semibold text-blue-900">Data Services</span>
</div>
{/* Integration - 1 row */}
<div className="bg-amber-200 border border-amber-300 flex flex-col items-center justify-center p-4 cursor-pointer hover:bg-amber-300 transition-colors min-h-[100px]">
<div className="text-amber-800">
<IntegrationIcon />
</div>
<span className="mt-2 text-sm font-semibold text-amber-900">Integration</span>
</div>
{/* Intelligence - spans 2 rows */}
<div className="row-span-2 bg-purple-200 border border-purple-300 flex flex-col items-center justify-center p-4 cursor-pointer hover:bg-purple-300 transition-colors min-h-[200px]">
<div className="text-purple-800">
<IntelligenceIcon />
</div>
<span className="mt-3 text-sm font-semibold text-purple-900">Intelligence</span>
</div>
{/* User Experience - spans 2 rows */}
<div className="row-span-2 bg-green-200 border border-green-300 flex flex-col items-center justify-center p-4 cursor-pointer hover:bg-green-300 transition-colors min-h-[200px]">
<div className="text-green-800">
<UserExperienceIcon />
</div>
<span className="mt-3 text-sm font-semibold text-green-900">User Experience</span>
</div>
{/* Row 2 - Management and Trustworthiness */}
{/* Management - 1 row, spans 1 col */}
<div className="bg-red-200 border border-red-300 flex flex-col items-center justify-center p-4 cursor-pointer hover:bg-red-300 transition-colors min-h-[100px]">
<div className="text-red-800">
<ManagementIcon />
</div>
<span className="mt-2 text-sm font-semibold text-red-900">Management</span>
</div>
{/* Trustworthiness - 1 row */}
<div className="bg-green-100 border border-green-300 flex flex-col items-center justify-center p-4 cursor-pointer hover:bg-green-200 transition-colors min-h-[100px]">
<div className="text-red-400">
<TrustworthinessIcon />
</div>
<span className="mt-2 text-sm font-semibold text-red-600">Trustworthiness</span>
</div>
</div>
</div>
</div>
</div>
</div>
)
}

View File

@@ -0,0 +1,151 @@
import { useAuth } from '@/hooks'
export default function HomePage() {
const { isAuthenticated, login, isLoading } = useAuth()
if (isLoading) {
return (
<div className="flex min-h-[60vh] items-center justify-center">
<div className="h-12 w-12 animate-spin rounded-full border-4 border-primary-200 border-t-primary-600" />
</div>
)
}
return (
<div className="flex min-h-[60vh] flex-col items-center justify-center">
<div className="text-center">
<h1 className="text-4xl font-bold tracking-tight text-gray-900 sm:text-5xl md:text-6xl">
Welcome to{' '}
<span className="text-primary-600">Keycloak Auth</span>
</h1>
<p className="mx-auto mt-6 max-w-2xl text-lg text-gray-600">
A secure authentication system powered by Keycloak and FastAPI. Login
with your Keycloak credentials to access protected resources.
</p>
{!isAuthenticated && (
<div className="mt-10">
<button
onClick={login}
className="inline-flex items-center gap-2 rounded-lg bg-primary-600 px-8 py-4 text-lg font-semibold text-white shadow-lg transition-all hover:bg-primary-700 hover:shadow-xl focus:outline-none focus:ring-4 focus:ring-primary-300"
>
<svg
className="h-6 w-6"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
strokeWidth={2}
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M11 16l-4-4m0 0l4-4m-4 4h14m-5 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h7a3 3 0 013 3v1"
/>
</svg>
Login with Keycloak
</button>
</div>
)}
{isAuthenticated && (
<div className="mt-10">
<a
href="/dashboard"
className="inline-flex items-center gap-2 rounded-lg bg-primary-600 px-8 py-4 text-lg font-semibold text-white shadow-lg transition-all hover:bg-primary-700 hover:shadow-xl focus:outline-none focus:ring-4 focus:ring-primary-300"
>
<svg
className="h-6 w-6"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
strokeWidth={2}
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6zM14 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6zM4 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2zM14 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z"
/>
</svg>
Go to Dashboard
</a>
</div>
)}
</div>
{/* Features Section */}
<div className="mt-20 grid gap-8 sm:grid-cols-2 lg:grid-cols-3">
<div className="rounded-lg border border-gray-200 bg-white p-6 shadow-sm">
<div className="mb-4 flex h-12 w-12 items-center justify-center rounded-lg bg-primary-100">
<svg
className="h-6 w-6 text-primary-600"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
strokeWidth={2}
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"
/>
</svg>
</div>
<h3 className="mb-2 text-lg font-semibold text-gray-900">
Secure Authentication
</h3>
<p className="text-gray-600">
HTTP-only cookies protect your tokens from XSS attacks.
</p>
</div>
<div className="rounded-lg border border-gray-200 bg-white p-6 shadow-sm">
<div className="mb-4 flex h-12 w-12 items-center justify-center rounded-lg bg-primary-100">
<svg
className="h-6 w-6 text-primary-600"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
strokeWidth={2}
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"
/>
</svg>
</div>
<h3 className="mb-2 text-lg font-semibold text-gray-900">
Keycloak Integration
</h3>
<p className="text-gray-600">
Enterprise-grade identity management with Keycloak SSO.
</p>
</div>
<div className="rounded-lg border border-gray-200 bg-white p-6 shadow-sm">
<div className="mb-4 flex h-12 w-12 items-center justify-center rounded-lg bg-primary-100">
<svg
className="h-6 w-6 text-primary-600"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
strokeWidth={2}
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M13 10V3L4 14h7v7l9-11h-7z"
/>
</svg>
</div>
<h3 className="mb-2 text-lg font-semibold text-gray-900">
FastAPI Backend
</h3>
<p className="text-gray-600">
High-performance Python backend with automatic API documentation.
</p>
</div>
</div>
</div>
)
}

View File

@@ -0,0 +1,2 @@
export { default as HomePage } from './HomePage'
export { default as DashboardPage } from './DashboardPage'