feat(governance): Frontend integration and pages

- Integrate GovernanceRolesBlock into AgentCabinet
- Add ReportButton component for creating incidents
- Add GovernancePage with tabs (City/Audit/Incidents)
- Add /governance route to App.tsx
- Export governance components from index.ts
This commit is contained in:
Apple
2025-11-29 16:06:17 -08:00
parent e233d32ae7
commit bef55b2aa6
5 changed files with 433 additions and 0 deletions

View File

@@ -0,0 +1,116 @@
/**
* Governance Page
* Main governance dashboard with tabs for City, Audit, Incidents
*/
import React, { useState } from 'react';
import { useSearchParams } from 'react-router-dom';
import { CityGovernancePanel } from '../features/governance/components/CityGovernancePanel';
import { AuditDashboard } from '../features/governance/components/AuditDashboard';
import { IncidentsList } from '../features/governance/components/IncidentsList';
type Tab = 'city' | 'audit' | 'incidents';
export function GovernancePage() {
const [searchParams, setSearchParams] = useSearchParams();
const initialTab = (searchParams.get('tab') as Tab) || 'city';
const [activeTab, setActiveTab] = useState<Tab>(initialTab);
const handleTabChange = (tab: Tab) => {
setActiveTab(tab);
setSearchParams({ tab });
};
// TODO: Get actual actorDaisId from auth context
const actorDaisId = 'dais-demo-user';
return (
<div className="min-h-screen bg-slate-950 text-white">
{/* Header */}
<div className="bg-gradient-to-r from-slate-900 to-slate-800 border-b border-slate-700">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
<h1 className="text-3xl font-bold text-white flex items-center gap-3">
🏛 DAARION.city Governance
</h1>
<p className="text-slate-400 mt-2">
Управління агентами, ролями, інцидентами та аудит подій
</p>
</div>
</div>
{/* Tabs */}
<div className="bg-slate-900 border-b border-slate-700 sticky top-0 z-10">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex gap-1">
<TabButton
active={activeTab === 'city'}
onClick={() => handleTabChange('city')}
icon="🏛️"
label="City Governance"
/>
<TabButton
active={activeTab === 'audit'}
onClick={() => handleTabChange('audit')}
icon="📊"
label="Audit"
/>
<TabButton
active={activeTab === 'incidents'}
onClick={() => handleTabChange('incidents')}
icon="⚠️"
label="Incidents"
/>
</div>
</div>
</div>
{/* Content */}
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
{activeTab === 'city' && (
<CityGovernancePanel actorId={actorDaisId} />
)}
{activeTab === 'audit' && (
<AuditDashboard />
)}
{activeTab === 'incidents' && (
<IncidentsList
actorDaisId={actorDaisId}
showCreateButton
/>
)}
</div>
</div>
);
}
// Tab Button Component
function TabButton({
active,
onClick,
icon,
label
}: {
active: boolean;
onClick: () => void;
icon: string;
label: string;
}) {
return (
<button
onClick={onClick}
className={`px-6 py-4 text-sm font-medium flex items-center gap-2 border-b-2 transition-colors ${
active
? 'text-white border-purple-500 bg-slate-800/50'
: 'text-slate-400 border-transparent hover:text-white hover:bg-slate-800/30'
}`}
>
<span>{icon}</span>
<span>{label}</span>
</button>
);
}
export default GovernancePage;