/home/techb158/balavpn.abdallabala.com/.next/cache/webpack/server-production
Edit: /home/techb158/balavpn.abdallabala.com/.next/cache/webpack/server-production/7.pack (186309B)
wpc ¹× §webpack/lib/cache/PackFileCacheStrategyPackContentItems€Æ Compilation/codeGeneration|javascript/auto|C:\Users\abd_b\OneDrive\Desktop\COSMIC AI-Risk Dashboard\Step 12 is complete Final QA, Demo Readiness, and Submission Freeze\application\saas-app\node_modules\next\dist\build\webpack\loaders\next-flight-client-module-loader.js!C:\Users\abd_b\OneDrive\Desktop\COSMIC AI-Risk Dashboard\Step 12 is complete Final QA, Demo Readiness, and Submission Freeze\application\saas-app\node_modules\next\dist\build\webpack\loaders\next-swc-loader.js??ruleSet[1].rules[16].oneOf[7].use[1]!C:\Users\abd_b\OneDrive\Desktop\COSMIC AI-Risk Dashboard\Step 12 is complete Final QA, Demo Readiness, and Submission Freeze\application\saas-app\src\app\dashboard\page.jsx|ssr|webpack-runtime€€‡sources“runtimeRequirements„dataŠjavascript«webpack/lib/util/registerExternalSerializerœwebpack-sources/CachedSource VÖ «webpack/lib/util/registerExternalSerializerœwebpack-sources/ConcatSource€«webpack/lib/util/registerExternalSerializer™webpack-sources/RawSource… __webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ DashboardPage)
/* harmony export */ });
/* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1124);
/* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(8301);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var next_navigation__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(2378);
/* harmony import */ var _lib_api_client__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(4194);
«webpack/lib/util/registerExternalSerializerwebpack-sources/ReplaceSource*Æ /* __next_internal_client_entry_do_not_use__ default auto */ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import { useEffect, useState, useCallback, useMemo } from 'react';
import { useRouter } from 'next/navigation';
import { api } from '../../lib/api-client';
const TABS = [
'Overview',
'Risks',
'Mitigations',
'Gate',
'Integrations'
];
const PAGE_SIZE = 20;
function useToast() {
const [toasts, setToasts] = useState([]);
const add = useCallback((message, type = 'success')=>{
const id = Date.now() + Math.random();
setToasts((prev)=>[
...prev,
{
id,
message,
type
}
]);
setTimeout(()=>setToasts((prev)=>prev.filter((t)=>t.id !== id)), 3000);
}, []);
return {
toasts,
add
};
}
function ToastContainer({ toasts }) {
if (!toasts.length) return null;
return /*#__PURE__*/ _jsx("div", {
className: "toast-container",
children: toasts.map((t)=>/*#__PURE__*/ _jsx("div", {
className: `toast ${t.type}`,
children: t.message
}, t.id))
});
}
function SearchInput({ value, onChange, placeholder }) {
return /*#__PURE__*/ _jsxs("div", {
className: "search-wrap",
children: [
/*#__PURE__*/ _jsx("span", {
className: "search-icon",
children: "⌕"
}),
/*#__PURE__*/ _jsx("input", {
className: "input",
value: value,
onChange: (e)=>onChange(e.target.value),
placeholder: placeholder || 'Search...'
})
]
});
}
function sortData(list, sortKey, sortDir) {
if (!sortKey) return list;
return [
...list
].sort((a, b)=>{
const va = a[sortKey], vb = b[sortKey];
if (va == null) return 1;
if (vb == null) return -1;
const cmp = typeof va === 'number' ? va - vb : String(va).localeCompare(String(vb));
return sortDir === 'asc' ? cmp : -cmp;
});
}
function Badge({ children, className }) {
return /*#__PURE__*/ _jsx("span", {
className: `badge ${className || ''}`,
children: children
});
}
function OverviewTab({ project, dashboard }) {
const panels = useMemo(()=>{
if (!dashboard) return [];
return [
{
label: 'Overall Score',
value: dashboard.summary?.overallScore ?? '-',
cls: dashboard.summary?.overallScore >= 75 ? 'bad' : dashboard.summary?.overallScore >= 50 ? 'warn' : 'good',
sub: `Risk level: ${dashboard.summary?.riskLevel || '-'}`
},
{
label: 'Deployment Gate',
value: dashboard.summary?.gateStatus ?? '-',
cls: dashboard.summary?.gateStatus === 'Ready' ? 'good' : dashboard.summary?.gateStatus === 'Warning' ? 'warn' : 'bad',
sub: dashboard.gate?.message || ''
},
{
label: 'Open Risks',
value: dashboard.summary?.openRisks ?? 0,
cls: (dashboard.summary?.openRisks || 0) > 5 ? 'bad' : (dashboard.summary?.openRisks || 0) > 2 ? 'warn' : 'good',
sub: `${dashboard.summary?.totalRisks || 0} total risks`
},
{
label: 'Mitigation',
value: `${dashboard.summary?.mitigationCompletion ?? 0}%`,
cls: (dashboard.summary?.mitigationCompletion || 0) < 40 ? 'bad' : (dashboard.summary?.mitigationCompletion || 0) < 70 ? 'warn' : 'good',
sub: 'Average active-risk completion'
}
];
}, [
dashboard
]);
if (!dashboard) return /*#__PURE__*/ _jsx("div", {
className: "empty-state",
children: /*#__PURE__*/ _jsx("p", {
children: "Loading dashboard data..."
})
});
return /*#__PURE__*/ _jsxs(_Fragment, {
children: [
/*#__PURE__*/ _jsx("div", {
className: "grid",
style: {
gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))'
},
children: panels.map((p)=>/*#__PURE__*/ _jsxs("div", {
className: "metric-card",
children: [
/*#__PURE__*/ _jsx("h3", {
children: p.label
}),
/*#__PURE__*/ _jsx("div", {
className: `metric-value ${p.cls}`,
children: p.value
}),
/*#__PURE__*/ _jsx("div", {
className: "metric-sub",
children: p.sub
})
]
}, p.label))
}),
/*#__PURE__*/ _jsxs("div", {
className: "grid",
style: {
gridTemplateColumns: '1fr 1fr',
marginTop: 18
},
children: [
/*#__PURE__*/ _jsxs("div", {
className: "panel",
children: [
/*#__PURE__*/ _jsx("h2", {
children: "Dimensions"
}),
(dashboard.dimensions || []).map((dim)=>/*#__PURE__*/ _jsxs("div", {
style: {
marginBottom: 12
},
children: [
/*#__PURE__*/ _jsxs("div", {
style: {
display: 'flex',
justifyContent: 'space-between',
marginBottom: 4
},
children: [
/*#__PURE__*/ _jsx("span", {
style: {
fontSize: 13
},
children: dim.name
}),
/*#__PURE__*/ _jsx("strong", {
style: {
fontSize: 13
},
children: dim.score
})
]
}),
/*#__PURE__*/ _jsx("div", {
className: "bar-wrap",
children: /*#__PURE__*/ _jsx("div", {
className: "bar-fill",
style: {
width: `${Math.min(dim.score, 100)}%`,
background: dim.score >= 50 ? 'var(--danger)' : dim.score >= 25 ? 'var(--warn)' : 'var(--accent)'
}
})
})
]
}, dim.name))
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "panel",
children: [
/*#__PURE__*/ _jsx("h2", {
children: "Lifecycle"
}),
(dashboard.lifecycle || []).map((phase)=>/*#__PURE__*/ _jsxs("div", {
style: {
marginBottom: 12
},
children: [
/*#__PURE__*/ _jsxs("div", {
style: {
display: 'flex',
justifyContent: 'space-between',
marginBottom: 4
},
children: [
/*#__PURE__*/ _jsx("span", {
style: {
fontSize: 13
},
children: phase.name
}),
/*#__PURE__*/ _jsxs("span", {
className: "muted",
style: {
fontSize: 12
},
children: [
phase.openRisks,
" open"
]
})
]
}),
/*#__PURE__*/ _jsx("div", {
className: "bar-wrap",
children: /*#__PURE__*/ _jsx("div", {
className: "bar-fill",
style: {
width: `${Math.min(phase.riskScore || 0, 100)}%`,
background: (phase.riskScore || 0) >= 50 ? 'var(--danger)' : (phase.riskScore || 0) >= 25 ? 'var(--warn)' : 'var(--accent)'
}
})
})
]
}, phase.name))
]
})
]
})
]
});
}
function RisksTab({ project, dashboard, toast }) {
const [search, setSearch] = useState('');
const [sortKey, setSortKey] = useState('normalizedScore');
const [sortDir, setSortDir] = useState('desc');
const [page, setPage] = useState(0);
const [selectedRisk, setSelectedRisk] = useState(null);
const [updating, setUpdating] = useState(null);
const risks = useMemo(()=>{
if (!dashboard?.topRisks) return [];
return sortData(dashboard.topRisks, sortKey, sortDir);
}, [
dashboard,
sortKey,
sortDir
]);
const filtered = useMemo(()=>{
if (!search) return risks;
const q = search.toLowerCase();
return risks.filter((r)=>(r.title || '').toLowerCase().includes(q) || (r.dimension || '').toLowerCase().includes(q) || (r.ownerDisplayName || '').toLowerCase().includes(q));
}, [
risks,
search
]);
const paged = filtered.slice(0, (page + 1) * PAGE_SIZE);
const handleSort = (key)=>{
if (sortKey === key) setSortDir((d)=>d === 'asc' ? 'desc' : 'asc');
else {
setSortKey(key);
setSortDir('asc');
}
};
const updateStatus = async (riskId, status)=>{
setUpdating(riskId);
try {
await api.patch(`/api/risks/${riskId}`, {
status
});
toast.add(`Risk status updated to ${status}`);
setSelectedRisk(null);
} catch (e) {
toast.add(e.message, 'error');
} finally{
setUpdating(null);
}
};
if (!dashboard) return /*#__PURE__*/ _jsx("div", {
className: "empty-state",
children: /*#__PURE__*/ _jsx("p", {
children: "Loading..."
})
});
return /*#__PURE__*/ _jsxs(_Fragment, {
children: [
/*#__PURE__*/ _jsx(SearchInput, {
value: search,
onChange: setSearch,
placeholder: "Search risks by title, dimension, owner..."
}),
/*#__PURE__*/ _jsx("div", {
className: "table-wrap",
children: /*#__PURE__*/ _jsxs("table", {
className: "table",
children: [
/*#__PURE__*/ _jsx("thead", {
children: /*#__PURE__*/ _jsx("tr", {
children: [
{
key: 'id',
label: 'ID'
},
{
key: 'title',
label: 'Risk'
},
{
key: 'dimension',
label: 'Dimension'
},
{
key: 'lifecyclePhase',
label: 'Phase'
},
{
key: 'normalizedScore',
label: 'Score'
},
{
key: 'residualScore',
label: 'Residual'
},
{
key: 'status',
label: 'Status'
},
{
key: 'ownerDisplayName',
label: 'Owner'
}
].map((col)=>/*#__PURE__*/ _jsxs("th", {
className: "sortable",
onClick: ()=>handleSort(col.key),
children: [
col.label,
" ",
sortKey === col.key ? sortDir === 'asc' ? 'â–²' : 'â–¼' : ''
]
}, col.key))
})
}),
/*#__PURE__*/ _jsx("tbody", {
children: paged.map((risk)=>/*#__PURE__*/ _jsxs("tr", {
onClick: ()=>setSelectedRisk(risk),
children: [
/*#__PURE__*/ _jsx("td", {
style: {
fontFamily: 'monospace',
fontSize: 12
},
children: risk.id?.slice(0, 8)
}),
/*#__PURE__*/ _jsx("td", {
children: /*#__PURE__*/ _jsx("strong", {
children: risk.title
})
}),
/*#__PURE__*/ _jsx("td", {
children: /*#__PURE__*/ _jsx(Badge, {
className: risk.dimension?.toLowerCase(),
children: risk.dimension
})
}),
/*#__PURE__*/ _jsx("td", {
style: {
fontSize: 12
},
children: risk.lifecyclePhase
}),
/*#__PURE__*/ _jsx("td", {
children: /*#__PURE__*/ _jsx("strong", {
children: risk.normalizedScore
})
}),
/*#__PURE__*/ _jsx("td", {
children: /*#__PURE__*/ _jsx("span", {
style: {
color: risk.residualScore >= 50 ? 'var(--danger)' : risk.residualScore >= 25 ? 'var(--warn)' : 'var(--accent)'
},
children: risk.residualScore
})
}),
/*#__PURE__*/ _jsx("td", {
children: /*#__PURE__*/ _jsx(Badge, {
className: risk.status?.toLowerCase().replace(/\s+/g, '-'),
children: risk.status
})
}),
/*#__PURE__*/ _jsx("td", {
children: /*#__PURE__*/ _jsx("span", {
className: "muted",
children: risk.ownerDisplayName || '-'
})
})
]
}, risk.id))
})
]
})
}),
filtered.length > paged.length && /*#__PURE__*/ _jsx("div", {
style: {
textAlign: 'center',
marginTop: 12
},
children: /*#__PURE__*/ _jsxs("button", {
className: "button secondary small",
onClick: ()=>setPage((p)=>p + 1),
children: [
"Show more (",
filtered.length - paged.length,
" remaining)"
]
})
}),
!filtered.length && /*#__PURE__*/ _jsx("div", {
className: "empty-state",
children: /*#__PURE__*/ _jsx("p", {
children: "No risks match your search"
})
}),
selectedRisk && /*#__PURE__*/ _jsx("div", {
className: "modal-overlay",
onClick: ()=>setSelectedRisk(null),
children: /*#__PURE__*/ _jsxs("div", {
className: "modal",
onClick: (e)=>e.stopPropagation(),
children: [
/*#__PURE__*/ _jsx("h2", {
children: selectedRisk.title
}),
/*#__PURE__*/ _jsxs("div", {
style: {
display: 'grid',
gridTemplateColumns: '1fr 1fr',
gap: 12,
fontSize: 13
},
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("span", {
className: "muted",
children: "Dimension"
}),
/*#__PURE__*/ _jsx("br", {}),
selectedRisk.dimension
]
}),
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("span", {
className: "muted",
children: "Phase"
}),
/*#__PURE__*/ _jsx("br", {}),
selectedRisk.lifecyclePhase
]
}),
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("span", {
className: "muted",
children: "Probability"
}),
/*#__PURE__*/ _jsx("br", {}),
selectedRisk.probability
]
}),
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("span", {
className: "muted",
children: "Impact"
}),
/*#__PURE__*/ _jsx("br", {}),
selectedRisk.impact
]
}),
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("span", {
className: "muted",
children: "Detectability"
}),
/*#__PURE__*/ _jsx("br", {}),
selectedRisk.detectability
]
}),
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("span", {
className: "muted",
children: "Score"
}),
/*#__PURE__*/ _jsx("br", {}),
/*#__PURE__*/ _jsx("strong", {
children: selectedRisk.normalizedScore
})
]
}),
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("span", {
className: "muted",
children: "Residual"
}),
/*#__PURE__*/ _jsx("br", {}),
selectedRisk.residualScore
]
}),
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("span", {
className: "muted",
children: "Owner"
}),
/*#__PURE__*/ _jsx("br", {}),
selectedRisk.ownerDisplayName || '-'
]
})
]
}),
selectedRisk.description && /*#__PURE__*/ _jsxs("div", {
style: {
marginTop: 12,
fontSize: 13
},
children: [
/*#__PURE__*/ _jsx("span", {
className: "muted",
children: "Description"
}),
/*#__PURE__*/ _jsx("br", {}),
selectedRisk.description
]
}),
/*#__PURE__*/ _jsxs("div", {
style: {
marginTop: 16
},
children: [
/*#__PURE__*/ _jsx("span", {
className: "muted",
style: {
fontSize: 12
},
children: "Update status:"
}),
/*#__PURE__*/ _jsx("div", {
style: {
display: 'flex',
gap: 6,
marginTop: 6,
flexWrap: 'wrap'
},
children: [
'OPEN',
'IN_MITIGATION',
'ACCEPTED',
'CLOSED'
].map((s)=>/*#__PURE__*/ _jsx("button", {
className: `button small ${s === 'OPEN' ? 'secondary' : ''}`,
onClick: ()=>updateStatus(selectedRisk.id, s),
disabled: updating === selectedRisk.id,
children: s.replace('_', ' ')
}, s))
})
]
}),
/*#__PURE__*/ _jsx("div", {
className: "modal-actions",
children: /*#__PURE__*/ _jsx("button", {
className: "button secondary small",
onClick: ()=>setSelectedRisk(null),
children: "Close"
})
})
]
})
})
]
});
}
function MitigationsTab({ project, dashboard, toast }) {
const [search, setSearch] = useState('');
const [sortKey, setSortKey] = useState('progressPercent');
const [sortDir, setSortDir] = useState('asc');
const mitigations = useMemo(()=>{
if (!dashboard?.mitigations) return [];
return sortData(dashboard.mitigations, sortKey, sortDir);
}, [
dashboard,
sortKey,
sortDir
]);
const filtered = useMemo(()=>{
if (!search) return mitigations;
const q = search.toLowerCase();
return mitigations.filter((m)=>(m.title || '').toLowerCase().includes(q) || (m.riskTitle || '').toLowerCase().includes(q));
}, [
mitigations,
search
]);
const handleSort = (key)=>{
if (sortKey === key) setSortDir((d)=>d === 'asc' ? 'desc' : 'asc');
else {
setSortKey(key);
setSortDir('asc');
}
};
if (!dashboard) return /*#__PURE__*/ _jsx("div", {
className: "empty-state",
children: /*#__PURE__*/ _jsx("p", {
children: "Loading..."
})
});
return /*#__PURE__*/ _jsxs(_Fragment, {
children: [
/*#__PURE__*/ _jsx(SearchInput, {
value: search,
onChange: setSearch,
placeholder: "Search mitigations..."
}),
/*#__PURE__*/ _jsx("div", {
className: "table-wrap",
children: /*#__PURE__*/ _jsxs("table", {
className: "table",
children: [
/*#__PURE__*/ _jsx("thead", {
children: /*#__PURE__*/ _jsx("tr", {
children: [
{
key: 'title',
label: 'Title'
},
{
key: 'riskTitle',
label: 'Risk'
},
{
key: 'status',
label: 'Status'
},
{
key: 'progressPercent',
label: 'Progress'
},
{
key: 'effectivenessPercent',
label: 'Effectiveness'
},
{
key: 'ownerDisplayName',
label: 'Owner'
}
].map((col)=>/*#__PURE__*/ _jsxs("th", {
className: "sortable",
onClick: ()=>handleSort(col.key),
children: [
col.label,
" ",
sortKey === col.key ? sortDir === 'asc' ? 'â–²' : 'â–¼' : ''
]
}, col.key))
})
}),
/*#__PURE__*/ _jsx("tbody", {
children: filtered.slice(0, 50).map((m)=>/*#__PURE__*/ _jsxs("tr", {
children: [
/*#__PURE__*/ _jsx("td", {
children: /*#__PURE__*/ _jsx("strong", {
children: m.title
})
}),
/*#__PURE__*/ _jsx("td", {
children: /*#__PURE__*/ _jsx("span", {
className: "muted",
children: m.riskTitle
})
}),
/*#__PURE__*/ _jsx("td", {
children: /*#__PURE__*/ _jsx(Badge, {
className: m.status?.toLowerCase().replace(/\s+/g, '-'),
children: m.status
})
}),
/*#__PURE__*/ _jsx("td", {
children: /*#__PURE__*/ _jsxs("div", {
style: {
display: 'flex',
alignItems: 'center',
gap: 8
},
children: [
/*#__PURE__*/ _jsx("div", {
className: "bar-wrap",
style: {
flex: 1,
maxWidth: 80
},
children: /*#__PURE__*/ _jsx("div", {
className: "bar-fill",
style: {
width: `${m.progressPercent || 0}%`,
background: (m.progressPercent || 0) >= 80 ? 'var(--accent)' : (m.progressPercent || 0) >= 30 ? 'var(--warn)' : 'var(--danger)'
}
})
}),
m.progressPercent || 0,
"%"
]
})
}),
/*#__PURE__*/ _jsxs("td", {
children: [
m.effectivenessPercent || 0,
"%"
]
}),
/*#__PURE__*/ _jsx("td", {
children: /*#__PURE__*/ _jsx("span", {
className: "muted",
children: m.ownerDisplayName || '-'
})
})
]
}, m.id))
})
]
})
}),
!filtered.length && /*#__PURE__*/ _jsx("div", {
className: "empty-state",
children: /*#__PURE__*/ _jsx("p", {
children: "No mitigations found"
})
})
]
});
}
function GateTab({ project, dashboard }) {
if (!dashboard) return /*#__PURE__*/ _jsx("div", {
className: "empty-state",
children: /*#__PURE__*/ _jsx("p", {
children: "Loading..."
})
});
const criteria = dashboard.gate?.criteria || [];
const gateStatus = dashboard.summary?.gateStatus || 'Unknown';
const gateCls = gateStatus === 'Ready' ? 'good' : gateStatus === 'Warning' ? 'warn' : 'bad';
return /*#__PURE__*/ _jsxs(_Fragment, {
children: [
/*#__PURE__*/ _jsxs("div", {
className: "dash-header",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("h1", {
children: "Deployment Gate"
}),
/*#__PURE__*/ _jsx("p", {
className: "muted",
children: "Nine-criteria gate evaluation for AI deployment readiness"
})
]
}),
/*#__PURE__*/ _jsx("div", {
className: "dash-actions",
children: /*#__PURE__*/ _jsx("div", {
className: `metric-value ${gateCls}`,
style: {
fontSize: 28
},
children: gateStatus
})
})
]
}),
/*#__PURE__*/ _jsx("div", {
className: "table-wrap",
children: /*#__PURE__*/ _jsxs("table", {
className: "table",
children: [
/*#__PURE__*/ _jsx("thead", {
children: /*#__PURE__*/ _jsxs("tr", {
children: [
/*#__PURE__*/ _jsx("th", {
children: "Criterion"
}),
/*#__PURE__*/ _jsx("th", {
children: "Required"
}),
/*#__PURE__*/ _jsx("th", {
children: "Actual"
}),
/*#__PURE__*/ _jsx("th", {
children: "Status"
})
]
})
}),
/*#__PURE__*/ _jsx("tbody", {
children: criteria.map((c)=>/*#__PURE__*/ _jsxs("tr", {
children: [
/*#__PURE__*/ _jsx("td", {
children: /*#__PURE__*/ _jsx("strong", {
children: c.name
})
}),
/*#__PURE__*/ _jsx("td", {
children: c.required
}),
/*#__PURE__*/ _jsx("td", {
children: c.actual
}),
/*#__PURE__*/ _jsx("td", {
children: /*#__PURE__*/ _jsx(Badge, {
className: c.status?.toLowerCase(),
children: c.status
})
})
]
}, c.name))
})
]
})
}),
!criteria.length && /*#__PURE__*/ _jsx("div", {
className: "empty-state",
children: /*#__PURE__*/ _jsx("p", {
children: "No gate criteria evaluated yet"
})
}),
/*#__PURE__*/ _jsxs("div", {
style: {
marginTop: 16,
display: 'flex',
gap: 8
},
children: [
/*#__PURE__*/ _jsx("a", {
href: `/api/projects/${project?.id}/gate/evaluate`,
className: "button secondary small",
target: "_blank",
children: "Evaluate (API)"
}),
/*#__PURE__*/ _jsx("a", {
href: `/api/projects/${project?.id}/gate/history`,
className: "button secondary small",
target: "_blank",
children: "History (API)"
})
]
})
]
});
}
function IntegrationsTab({ project, dashboard }) {
return /*#__PURE__*/ _jsxs(_Fragment, {
children: [
/*#__PURE__*/ _jsx("div", {
className: "dash-header",
children: /*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("h1", {
children: "Integrations"
}),
/*#__PURE__*/ _jsx("p", {
className: "muted",
children: "Connect Trello, Jira, Asana, or Microsoft Planner"
})
]
})
}),
/*#__PURE__*/ _jsx("div", {
className: "grid",
style: {
gridTemplateColumns: 'repeat(auto-fit, minmax(240px, 1fr))'
},
children: [
'TRELLO',
'JIRA',
'ASANA',
'MICROSOFT_PLANNER'
].map((provider)=>/*#__PURE__*/ _jsxs("div", {
className: "panel",
style: {
textAlign: 'center'
},
children: [
/*#__PURE__*/ _jsx("div", {
style: {
fontSize: 32,
marginBottom: 8
},
children: provider === 'TRELLO' ? '⊞' : provider === 'JIRA' ? '◆' : provider === 'ASANA' ? '◇' : '▣'
}),
/*#__PURE__*/ _jsx("h3", {
style: {
margin: '0 0 4px'
},
children: provider.replace('_', ' ')
}),
/*#__PURE__*/ _jsx("p", {
className: "muted",
style: {
fontSize: 12,
margin: '0 0 12px'
},
children: "Project management sync"
}),
/*#__PURE__*/ _jsxs("div", {
style: {
display: 'flex',
gap: 6,
justifyContent: 'center'
},
children: [
/*#__PURE__*/ _jsx("a", {
href: `/api/integration-providers`,
className: "button secondary small",
children: "Configure"
}),
/*#__PURE__*/ _jsx("a", {
href: `/api/integrations`,
className: "button secondary small",
children: "Manage"
})
]
})
]
}, provider))
}),
/*#__PURE__*/ _jsx("div", {
style: {
marginTop: 12
},
children: /*#__PURE__*/ _jsx("a", {
href: "/api/integration-providers",
className: "button secondary small",
target: "_blank",
children: "Integration providers (API)"
})
})
]
});
}
export default function DashboardPage() {
const router = useRouter();
const [tab, setTab] = useState('Overview');
const [project, setProject] = useState(null);
const [dashboard, setDashboard] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const { toasts, add } = useToast();
process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{
const params = new URLSearchParams(window.location.search);
const t = params.get('tab');
if (t && TABS.includes(t)) setTab(t);
}, []);
process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{
(async ()=>{
try {
const workspaces = await api.get('/api/workspaces');
const ws = workspaces?.[0];
if (!ws) {
setError('No workspace found');
setLoading(false);
return;
}
const projects = await api.get(`/api/workspaces/${ws.id}/projects`);
const proj = projects?.[0];
if (!proj) {
setError('No project found');
setLoading(false);
return;
}
setProject(proj);
const dash = await api.get(`/api/projects/${proj.id}/dashboard`);
setDashboard(dash);
setLoading(false);
} catch (e) {
setError(e.message);
setLoading(false);
}
})();
}, []);
if (loading) return /*#__PURE__*/ _jsx("div", {
className: "shell-loading",
children: /*#__PURE__*/ _jsx("div", {
className: "spinner"
})
});
if (error) return /*#__PURE__*/ _jsxs("div", {
className: "empty-state",
children: [
/*#__PURE__*/ _jsx("div", {
className: "empty-icon",
children: "!"
}),
/*#__PURE__*/ _jsx("p", {
children: error
})
]
});
return /*#__PURE__*/ _jsxs(_Fragment, {
children: [
/*#__PURE__*/ _jsxs("div", {
className: "dash-header",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("h1", {
children: project?.name || 'Dashboard'
}),
/*#__PURE__*/ _jsx("p", {
className: "muted",
children: project?.subtitle || ''
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "dash-actions",
children: [
/*#__PURE__*/ _jsx("a", {
href: `/api/projects/${project?.id}/reports/executive.html`,
className: "button secondary small",
target: "_blank",
children: "Report"
}),
/*#__PURE__*/ _jsx("a", {
href: `/api/projects/${project?.id}/reports/risk-register.csv`,
className: "button secondary small",
target: "_blank",
children: "CSV"
})
]
})
]
}),
/*#__PURE__*/ _jsx("div", {
className: "tabs",
children: TABS.map((t)=>/*#__PURE__*/ _jsx("button", {
className: `tab ${tab === t ? 'active' : ''}`,
onClick: ()=>router.push(`/dashboard?tab=${t}`),
children: t
}, t))
}),
tab === 'Overview' && /*#__PURE__*/ _jsx(OverviewTab, {
project: project,
dashboard: dashboard
}),
tab === 'Risks' && /*#__PURE__*/ _jsx(RisksTab, {
project: project,
dashboard: dashboard,
toast: {
add
}
}),
tab === 'Mitigations' && /*#__PURE__*/ _jsx(MitigationsTab, {
project: project,
dashboard: dashboard,
toast: {
add
}
}),
tab === 'Gate' && /*#__PURE__*/ _jsx(GateTab, {
project: project,
dashboard: dashboard
}),
tab === 'Integrations' && /*#__PURE__*/ _jsx(IntegrationsTab, {
project: project,
dashboard: dashboard
}),
/*#__PURE__*/ _jsx(ToastContainer, {
toasts: toasts
})
]
});
}
@å `=_’ ” Õ × . Ý ä û þ b e 4 8 “ – Å È j p 1 4 „ ë ï ñ _ù , / £ ) , ÷ ú ò ö ä è m p # ' % ) à ã a d 6 9 Ë Î ~ ‚ _
½ Á ¿! Ã! z# }# ý$ % Ð' Ó' e( h( ¤+ «+ Ô+ Û+ , , A, H, z, , ®, µ, Ð, Ö, ¤- ª- W0 Y0 1 _°1 ý1 2 X2 \2 ^2 f2 ™2 œ2 e3 h3 Ä3 È3 C4 F4 ‡4 Š4 ö: ú: J= M= = ¤= \> _> @ @ Q@ T@ 8A ;A ‰A _ŒA ËB ÎB %D (D vD yD gE jE ¸E »E ´G ·G H H VI YI §I ªI ŽK ‘K ;L ?L ÈM ËM (N +N ¼N ¿N RO VO P _ P ŽP ’P þQ R sR vR fS iS -T 1T ¢T ¥T ‘U ”U ]V aV ÒV ÕV ÇW ÊW X ”X Y Y õY øY ¹Z ½Z .[ 1[ %\ _(\ ð\ ô\ e] h] T^ W^ š^ ^ ¡_ ¥_ ` ` a a Óa ×a Hb Kb 7c :c Yd ]d ^e ae 3f 6f Üf àf ³g ¶g i _i ‰k Œk ¯m ²m )n ,n Ôo Ûo p p Cp Jp lp rp Fq Lq Os Rs Ÿs ¢s ús þs t t ;t >t òt õt Qu Uu Ðu _Óu v v { { k} n} Î} Ò} B~ E~ “~ –~ w z È Ë ò€ õ€ C F Ž‚ ‘‚ ß‚ ã‚ ¢„ ¥„ Y† \† Š Š s‹ _v‹ Ä‹ Ç‹ — š ÷ ú ÂŽ ÅŽ F J L T ‡ ‹ þ ‘ [‘ ^‘ î‘ ñ‘ “
“ x“ {“ Ø” Û” 7• ;• ¶• _¹• ú• þ• f– i– — — ¯— ²— Q˜ T˜ C™ F™ ™™ ™
š š ^š aš A› D› ñ› ô› Ÿœ ¢œ ðœ óœ Þ Æž #Ÿ &Ÿ