Apply Composer changes: comprehensive API updates, migrations, middleware, and infrastructure improvements
- Add comprehensive database migrations (001-024) for schema evolution - Enhance API schema with expanded type definitions and resolvers - Add new middleware: audit logging, rate limiting, MFA enforcement, security, tenant auth - Implement new services: AI optimization, billing, blockchain, compliance, marketplace - Add adapter layer for cloud integrations (Cloudflare, Kubernetes, Proxmox, storage) - Update Crossplane provider with enhanced VM management capabilities - Add comprehensive test suite for API endpoints and services - Update frontend components with improved GraphQL subscriptions and real-time updates - Enhance security configurations and headers (CSP, CORS, etc.) - Update documentation and configuration files - Add new CI/CD workflows and validation scripts - Implement design system improvements and UI enhancements
This commit is contained in:
116
src/components/infrastructure/ComplianceMapView.tsx
Normal file
116
src/components/infrastructure/ComplianceMapView.tsx
Normal file
@@ -0,0 +1,116 @@
|
||||
'use client'
|
||||
|
||||
import { useState, useCallback } from 'react'
|
||||
import Map, { Marker, Popup, Layer, Source } from 'react-map-gl'
|
||||
import 'mapbox-gl/dist/mapbox-gl.css'
|
||||
import type { ComplianceRequirement } from '@/lib/types/infrastructure'
|
||||
import { Card, CardContent } from '@/components/ui/card'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
|
||||
interface ComplianceMapViewProps {
|
||||
requirements: ComplianceRequirement[]
|
||||
onCountryClick?: (country: string) => void
|
||||
}
|
||||
|
||||
const statusColors: Record<string, string> = {
|
||||
Compliant: '#10b981',
|
||||
Partial: '#f59e0b',
|
||||
Pending: '#3b82f6',
|
||||
'Non-Compliant': '#ef4444',
|
||||
}
|
||||
|
||||
// Basic country coordinates (in production, use a proper geocoding service)
|
||||
const countryCoordinates: Record<string, { lat: number; lng: number }> = {
|
||||
Italy: { lat: 41.9028, lng: 12.4964 },
|
||||
Germany: { lat: 51.1657, lng: 10.4515 },
|
||||
France: { lat: 46.2276, lng: 2.2137 },
|
||||
Spain: { lat: 40.4637, lng: -3.7492 },
|
||||
// Add more as needed
|
||||
}
|
||||
|
||||
export function ComplianceMapView({ requirements, onCountryClick }: ComplianceMapViewProps) {
|
||||
const [popupInfo, setPopupInfo] = useState<ComplianceRequirement | null>(null)
|
||||
const [viewState, setViewState] = useState({
|
||||
longitude: 12.4964,
|
||||
latitude: 41.9028,
|
||||
zoom: 3,
|
||||
})
|
||||
|
||||
const handleMarkerClick = useCallback(
|
||||
(requirement: ComplianceRequirement) => {
|
||||
setPopupInfo(requirement)
|
||||
onCountryClick?.(requirement.country)
|
||||
},
|
||||
[onCountryClick]
|
||||
)
|
||||
|
||||
const mapboxToken = process.env.NEXT_PUBLIC_MAPBOX_TOKEN || ''
|
||||
|
||||
if (!mapboxToken) {
|
||||
return (
|
||||
<Card>
|
||||
<CardContent className="p-8 text-center">
|
||||
<p className="text-studio-medium">
|
||||
Mapbox token not configured. Please set NEXT_PUBLIC_MAPBOX_TOKEN in your environment
|
||||
variables.
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="w-full h-96 rounded-lg overflow-hidden border border-studio-medium">
|
||||
<Map
|
||||
{...viewState}
|
||||
onMove={(evt) => setViewState(evt.viewState)}
|
||||
mapboxAccessToken={mapboxToken}
|
||||
style={{ width: '100%', height: '100%' }}
|
||||
mapStyle="mapbox://styles/mapbox/dark-v10"
|
||||
>
|
||||
{requirements.map((req) => {
|
||||
const coords = countryCoordinates[req.country]
|
||||
if (!coords) return null
|
||||
|
||||
return (
|
||||
<Marker
|
||||
key={req.country}
|
||||
longitude={coords.lng}
|
||||
latitude={coords.lat}
|
||||
anchor="bottom"
|
||||
onClick={() => handleMarkerClick(req)}
|
||||
>
|
||||
<div
|
||||
className="w-4 h-4 rounded-full border-2 border-white cursor-pointer"
|
||||
style={{ backgroundColor: statusColors[req.status] || '#6b7280' }}
|
||||
/>
|
||||
</Marker>
|
||||
)
|
||||
})}
|
||||
|
||||
{popupInfo && (
|
||||
<Popup
|
||||
longitude={countryCoordinates[popupInfo.country]?.lng || 0}
|
||||
latitude={countryCoordinates[popupInfo.country]?.lat || 0}
|
||||
anchor="top"
|
||||
onClose={() => setPopupInfo(null)}
|
||||
closeButton
|
||||
closeOnClick={false}
|
||||
>
|
||||
<div className="p-2 min-w-[200px]">
|
||||
<h3 className="font-semibold text-sm mb-2">{popupInfo.country}</h3>
|
||||
<Badge className={statusColors[popupInfo.status] ? `bg-${statusColors[popupInfo.status]}/20 text-${statusColors[popupInfo.status]}` : ''}>
|
||||
{popupInfo.status}
|
||||
</Badge>
|
||||
<div className="mt-2 text-xs">
|
||||
<div>Frameworks: {popupInfo.frameworks.join(', ')}</div>
|
||||
<div>Requirements: {popupInfo.requirements.length}</div>
|
||||
</div>
|
||||
</div>
|
||||
</Popup>
|
||||
)}
|
||||
</Map>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user