feat(campaigns): audit timeline UI and manager role in role pickers

This commit is contained in:
kitos
2026-07-03 17:09:56 +02:00
parent aeaf1cf243
commit 83b4d2578a
4 changed files with 87 additions and 0 deletions
+17
View File
@@ -30,11 +30,13 @@ import {
listCampaignModificationRequests,
approveModificationRequest,
rejectModificationRequest,
getCampaignTimeline,
type Campaign,
type CampaignHistoryEntry,
} from "../api/campaigns";
import { useAuth } from "../context/AuthContext";
import CampaignTimeline from "../components/CampaignTimeline";
import CampaignAuditTimeline from "../components/CampaignAuditTimeline";
import JiraLinkPanel from "../components/JiraLinkPanel";
import CampaignTimingPanel from "../components/CampaignTimingPanel";
import AddTestToCampaignModal from "../components/AddTestToCampaignModal";
@@ -104,6 +106,7 @@ export default function CampaignDetailPage() {
mutationFn: () => submitCampaignForApproval(campaignId!),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["campaign", campaignId] });
queryClient.invalidateQueries({ queryKey: ["campaign-timeline", campaignId] });
showToast("Campaign submitted for approval", "success");
},
onError: (err: Error) => showToast(err.message, "error"),
@@ -113,6 +116,7 @@ export default function CampaignDetailPage() {
mutationFn: () => approveCampaign(campaignId!, approveStartDate),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["campaign", campaignId] });
queryClient.invalidateQueries({ queryKey: ["campaign-timeline", campaignId] });
setApproveModalOpen(false);
setApproveStartDate("");
showToast("Campaign approved and activated", "success");
@@ -124,6 +128,7 @@ export default function CampaignDetailPage() {
mutationFn: () => rejectCampaign(campaignId!, rejectReason),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["campaign", campaignId] });
queryClient.invalidateQueries({ queryKey: ["campaign-timeline", campaignId] });
setRejectModalOpen(false);
setRejectReason("");
showToast("Campaign rejected", "success");
@@ -183,6 +188,12 @@ export default function CampaignDetailPage() {
enabled: !!campaignId,
});
const { data: timeline = [], isLoading: isTimelineLoading } = useQuery({
queryKey: ["campaign-timeline", campaignId],
queryFn: () => getCampaignTimeline(campaignId!),
enabled: !!campaignId,
});
const approveModRequestMutation = useMutation({
mutationFn: (requestId: string) => approveModificationRequest(requestId),
onSuccess: () => {
@@ -802,6 +813,12 @@ export default function CampaignDetailPage() {
</div>
)}
{/* Timeline */}
<div className="rounded-xl border border-gray-800 bg-gray-900 p-6">
<h2 className="mb-4 text-lg font-semibold text-white">Timeline</h2>
<CampaignAuditTimeline entries={timeline} isLoading={isTimelineLoading} />
</div>
{/* Jira */}
<JiraLinkPanel entityType="campaign" entityId={campaignId!} readOnly label={campaign.name} />
+1
View File
@@ -1217,6 +1217,7 @@ const AZURE_ROLES = [
{ value: "admin", label: "Aegis Admin", desc: "Full platform access including system settings" },
{ value: "red_lead", label: "Aegis Red Lead", desc: "Red team lead — manage tests, campaigns and templates" },
{ value: "blue_lead", label: "Aegis Blue Lead", desc: "Blue team lead — validate tests and manage coverage" },
{ value: "manager", label: "Aegis Manager", desc: "Approves campaigns and campaign changes" },
{ value: "red_tech", label: "Aegis Red Tech", desc: "Red team technician — execute tests" },
{ value: "blue_tech", label: "Aegis Blue Tech", desc: "Blue team technician — review detections" },
{ value: "viewer", label: "Aegis Viewer", desc: "Read-only access to dashboards and reports" },
+2
View File
@@ -20,6 +20,7 @@ const ROLES = [
{ value: "blue_tech", label: "Blue Tech" },
{ value: "red_lead", label: "Red Lead" },
{ value: "blue_lead", label: "Blue Lead" },
{ value: "manager", label: "Manager" },
{ value: "admin", label: "Admin" },
];
@@ -29,6 +30,7 @@ const roleBadgeColors: Record<string, string> = {
blue_tech: "bg-blue-900/50 text-blue-400 border-blue-500/30",
red_lead: "bg-orange-900/50 text-orange-400 border-orange-500/30",
blue_lead: "bg-cyan-900/50 text-cyan-400 border-cyan-500/30",
manager: "bg-amber-900/50 text-amber-400 border-amber-500/30",
viewer: "bg-gray-800/50 text-gray-400 border-gray-600/30",
};