/home/techb158/balavpn.abdallabala.com/.next/cache/webpack/server-production
Edit: /home/techb158/balavpn.abdallabala.com/.next/cache/webpack/server-production/12.pack (3307846B)
wpc :y2 §webpack/lib/cache/PackFileCacheStrategyPackContentItems ResolverCachePlugin|normal|default|alias=|false|dependencyType=|esm|modules=[|0=|node_modules|]|fallback=|false|exportsFields=[|0=|exports|]|importsFields=[|0=|imports|]|conditionNames=[|0=|node|1=|import|]|descriptionFiles=[|0=|package.json|]|extensions=[|0=|.js|1=|.json|2=|.node|]|enforceExtensions=|false|symlinks=|true|mainFields=[|0=|main|]|mainFiles=[|0=|index|]|roots=[|]|fullySpecified=|true|preferRelative=|false|preferAbsolute=|false|restrictions=[|]|path=|C:\Users\abd_b\OneDrive\Desktop\COSMIC AI-Risk Dashboard\Step 12 is complete Final QA, Demo Readiness, and Submission Freeze\application\saas-app|request=|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 ResolverCachePlugin|normal|default|alias=[|server-only$=|next/dist/compiled/server-only/empty|client-only$=|next/dist/compiled/client-only/error|next/dist/compiled/server-only$=|next/dist/compiled/server-only/empty|next/dist/compiled/client-only$=|next/dist/compiled/client-only/error|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\head.js=|next/dist/client/components/noop-head|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\image.js=|next/dist/api/image|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\constants.js=|next/dist/api/constants|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\router.js=|next/dist/api/router|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\dynamic.js=|next/dist/api/app-dynamic|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\script.js=|next/dist/api/script|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\link.js=|next/dist/client/app-dir/link|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\form.js=|next/dist/client/app-dir/form|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\navigation.js=|next/dist/api/navigation.react-server|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\headers.js=|next/dist/api/headers|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\og.js=|next/dist/api/og|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\server.js=|next/dist/api/server|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\document.js=|next/dist/api/document|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\app.js=|next/dist/api/app|next=|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|]|dependencyType=|esm|path=|C:\Users\abd_b\OneDrive\Desktop\COSMIC AI-Risk Dashboard\Step 12 is complete Final QA, Demo Readiness, and Submission Freeze\application\saas-app|request=|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§ Compilation/modules|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-loader\index.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[4].use[0]!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|rsc ResolverCachePlugin|normal|default|alias=[|server-only$=|next/dist/compiled/server-only/index|client-only$=|next/dist/compiled/client-only/index|next/dist/compiled/client-only$=|next/dist/compiled/client-only/index|next/dist/compiled/server-only=|next/dist/compiled/server-only/index|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\head.js=|next/dist/client/components/noop-head|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\image.js=|next/dist/api/image|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\constants.js=|next/dist/api/constants|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\router.js=|next/dist/api/router|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\dynamic.js=|next/dist/api/app-dynamic|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\script.js=|next/dist/api/script|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\link.js=|next/dist/client/app-dir/link|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\form.js=|next/dist/client/app-dir/form|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\navigation.js=|next/dist/api/navigation|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\headers.js=|next/dist/api/headers|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\og.js=|next/dist/api/og|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\server.js=|next/dist/api/server|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\document.js=|next/dist/api/document|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\app.js=|next/dist/api/app|next=|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|]|dependencyType=|esm|path=|C:\Users\abd_b\OneDrive\Desktop\COSMIC AI-Risk Dashboard\Step 12 is complete Final QA, Demo Readiness, and Submission Freeze\application\saas-app|request=|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¯ Compilation/modules|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ˇ FlagDependencyExportsPlugin|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× 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|8ec055afadaf2c53|webpack-runtimeCompilation/assets|chunk5105ŽMinifierWebpackPlugin|../app/dashboard/page.jsĨwebpack/lib/cache/ResolverCachePlugin`_ResolverCachePluginCacheMisscontextpathrequest
queryfragmentmoduledirectoryfileinternalfullySpecifieddescriptionFilePathdescriptionFileDatadescriptionFileRootrelativePathŦ 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.jsx0 C:\Users\abd_b\OneDrive\Desktop\COSMIC AI-Risk Dashboard\Step 12 is complete Final QA, Demo Readiness, and Submission Freeze\application\saas-app\package.jsonnameversionprivatedescriptionscriptsdependenciesdevDependenciesenginescosmic-ai-risk-saas
0.1.0˛ Commercial SaaS rebuild of the COSMIC AI-Risk Dashboard with multi-tenant workspaces, PostgreSQL, Prisma, invite-only auth, billing entitlements, and enterprise-ready boundaries.`dev
build
startlinttestprisma:generatedb:migratedb:pushdb:seedcheck:configtest:locallocal:fallbackmock-oidcdev:ssosso:setupnext dev -p 8091next buildnext start -p 8091next lintę node tests/saas-domain.test.js && node tests/tenant-security.test.js && node tests/idempotency.test.js && node tests/metrics.test.js && node tests/oidc.test.js && node tests/rate-limit.test.js && node tests/integration-service.test.jsprisma generateprisma migrate deployprisma db pushnode prisma/seed.jsnode scripts/check-config.jsnode tests/local-server.test.jsnode local-server.jsnode mock-oidc-provider.js¨node mock-oidc-provider.js & npm run devū@prisma/clientbcryptjsnext
reactreact-domstripezod^5.22.0^2.4.3^15.0.3^19.0.0˙^17.3.1^3.23.8eslinteslint-config-nextprisma^9.14.0öônode>=20.11.0 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.jsxwebpack/lib/FileSystemInfoSnapshot@ pŊ?ĸķyB pŊ?ĸķyB`ļĩŖ 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 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 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ø C:\Users\abd_b\OneDrive\Desktop\COSMIC AI-Risk Dashboard\Step 12 is complete Final QA, Demo Readiness, and Submission Freeze\applicationüC:\Users\abd_b\OneDrive\Desktop\COSMIC AI-Risk Dashboard\Step 12 is complete Final QA, Demo Readiness, and Submission Freeze¸C:\Users\abd_b\OneDrive\Desktop\COSMIC AI-Risk DashboardC:\Users\abd_b\OneDrive\DesktopC:\Users\abd_b\OneDriveC:\Users\abd_bC:\UsersC:\safeTimetimestamphash! ŅķyB @ËķyB404ac705cc6d108aũ! āô=ĸķyB Đô=ĸķyB5ccd5cbd07a49194û ú ų ø ÷ ö õ ô ķ ō ņ đ @ ° 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\package.jsonĻ 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\package.jsonĸ 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\package.jsonissuerissuerLayercompilerrscserver
ĘËĖ@ đž?ĸķyBīôwebpack/lib/NormalModuleĢwebpack/lib/util/registerExternalSerializerwebpack-sources/RawSourceT // This file is generated by the Webpack next-flight-loader.
import { registerClientReference } from "react-server-dom-webpack/server";
export default registerClientReference(
function() { throw new Error("Attempted to call the default export of \"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\" from the server, but it's on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component."); },
"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",
"default",
);
exportsTypenamespace
javascript/autoōÅ
aliasmainFieldsconditionNamesp˙˙˙`$server-only$client-only$next/dist/compiled/server-only$next/dist/compiled/client-only$Ģ 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\head.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\image.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\constants.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\router.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\dynamic.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\script.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\link.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\form.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\navigation.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\headers.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\og.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\server.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\document.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\app.jsreact$react/compiler-runtime$react/jsx-dev-runtime$react/jsx-runtime$react-dom$react-dom/client$react-dom/server$react-dom/server.browser$react-dom/server.edge$react-dom/static$react-dom/static.browser$react-dom/static.edge$ react-server-dom-webpack/client$ react-server-dom-webpack/server$Ĩreact-server-dom-webpack/server.node$ react-server-dom-webpack/static$É@vercel/turbopack-ecmascript-runtime/browser/dev/hmr-client/hmr-client.ts¤next/dist/compiled/server-only/empty¤next/dist/compiled/client-only/errorū˙Ĩnext/dist/client/components/noop-headnext/dist/api/imagenext/dist/api/constantsnext/dist/api/routernext/dist/api/app-dynamicnext/dist/api/scriptnext/dist/client/app-dir/linknext/dist/client/app-dir/formĨnext/dist/api/navigation.react-servernext/dist/api/headersnext/dist/api/ognext/dist/api/servernext/dist/api/documentnext/dist/api/appēnext/dist/server/route-modules/app-page/vendored/rsc/reactËnext/dist/server/route-modules/app-page/vendored/rsc/react-compiler-runtimeĘnext/dist/server/route-modules/app-page/vendored/rsc/react-jsx-dev-runtimeÆnext/dist/server/route-modules/app-page/vendored/rsc/react-jsx-runtimežnext/dist/server/route-modules/app-page/vendored/rsc/react-domŖnext/dist/compiled/react-dom/client¨next/dist/compiled/react-dom/server.nodeĢnext/dist/compiled/react-dom/server.browserąnext/dist/build/webpack/alias/react-dom-server.js¨next/dist/compiled/react-dom/static.nodeĢnext/dist/compiled/react-dom/static.browser¨next/dist/compiled/react-dom/static.edgeˇnext/dist/compiled/react-server-dom-webpack/client.nodeÔnext/dist/server/route-modules/app-page/vendored/rsc/react-server-dom-webpack-server˙Ônext/dist/server/route-modules/app-page/vendored/rsc/react-server-dom-webpack-static§next/dist/client/dev/noop-turbopack-hmrŖ 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%˙˙˙mainreact-server...
`cacheableparsedfileDependenciescontextDependenciesmissingDependenciesbuildDependenciesvalueDependencies{˙˙˙assetsassetsInfostrictexportsArgumenttopLevelDeclarationssnapshotwebpack/lib/util/LazySetÚ 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-loader\index.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 webpack/DefinePlugin_hashb5546dede6530496aff90673typeactionIdsclientRefsclientEntryTypeisClientRefclientdefaultauto__webpack_exports__*default* đĨ?ĸķyB ˙˙˙d˙˙˙ˇwebpack/lib/dependencies/HarmonyCompatibilityDependency
d˙ ˙ ũ¨webpack/lib/dependencies/ConstDependency`=@
`Jļwebpack/lib/dependencies/HarmonyExportHeaderDependency A R A S
ēwebpack/lib/dependencies/HarmonyImportSideEffectDependencyreact-server-dom-webpack/server˙
`Jēwebpack/lib/dependencies/HarmonyExportExpressionDependency`úû
šwebpack/lib/dependencies/HarmonyImportSpecifierDependencyaregisterClientReferenceūA Ž ųųū
b&
đū˙˙
i˙˙˙ssrj˙˙˙đū˙˙ ņū˙˙5˙˙˙6˙˙˙7˙˙˙@ Ņ?ĸķyB
Z˙˙˙_˙˙˙ ÃN /* __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, useSearchParams } from 'next/navigation';
import { api } from '../../lib/api-client';
import ErrorBoundary from '../../components/ErrorBoundary';
const TABS = [
'Overview',
'Projects',
'Risks',
'Mitigations',
'Gate',
'Integrations',
'Audit'
];
const PAGE_SIZE = 20;
const DIMENSIONS = [
'Technical',
'Governance',
'Legal',
'Ethical',
'Operational'
];
const LIFECYCLE_PHASES = [
'Design',
'Development',
'Testing',
'Deployment'
];
const RISK_STATUSES = [
'OPEN',
'IN_MITIGATION',
'ACCEPTED',
'CLOSED'
];
const MITIGATION_STATUSES = [
'NOT_STARTED',
'IN_PROGRESS',
'DONE',
'REJECTED'
];
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 FormField({ label, children }) {
return /*#__PURE__*/ _jsxs("div", {
style: {
marginBottom: 10
},
children: [
/*#__PURE__*/ _jsx("label", {
style: {
display: 'block',
fontSize: 12,
color: 'var(--muted)',
marginBottom: 3
},
children: label
}),
children
]
});
}
function InlineInput({ value, onChange, type = 'text', min, max, style: extraStyle }) {
return /*#__PURE__*/ _jsx("input", {
className: "input",
type: type,
value: value,
onChange: (e)=>onChange(e.target.value),
min: min,
max: max,
style: {
width: '100%',
...extraStyle
}
});
}
function InlineSelect({ value, onChange, options }) {
const items = options || [];
return /*#__PURE__*/ _jsxs("select", {
className: "input",
value: value,
onChange: (e)=>onChange(e.target.value),
style: {
width: '100%'
},
children: [
/*#__PURE__*/ _jsx("option", {
value: "",
children: "â Select â"
}),
items.map((o)=>{
const val = typeof o === 'object' ? o.value : o;
const lbl = typeof o === 'object' ? o.label : o;
return /*#__PURE__*/ _jsx("option", {
value: val,
children: lbl
}, val);
})
]
});
}
function ConfirmDelete({ label, onConfirm, onCancel, deleting }) {
return /*#__PURE__*/ _jsx("div", {
className: "modal-overlay",
onClick: onCancel,
children: /*#__PURE__*/ _jsxs("div", {
className: "modal",
onClick: (e)=>e.stopPropagation(),
style: {
maxWidth: 380
},
children: [
/*#__PURE__*/ _jsxs("h3", {
children: [
"Delete ",
label,
"?"
]
}),
/*#__PURE__*/ _jsx("p", {
style: {
fontSize: 13,
color: 'var(--muted)'
},
children: "This cannot be undone."
}),
/*#__PURE__*/ _jsxs("div", {
className: "modal-actions",
children: [
/*#__PURE__*/ _jsx("button", {
className: "button secondary small",
onClick: onCancel,
children: "Cancel"
}),
/*#__PURE__*/ _jsx("button", {
className: "button small",
style: {
background: 'var(--danger)',
color: '#fff'
},
onClick: onConfirm,
disabled: deleting,
children: deleting ? 'Deleting...' : 'Delete'
})
]
})
]
})
});
}
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 RiskFormModal({ project, onClose, onSaved, toast }) {
const [saving, setSaving] = useState(false);
const [form, setForm] = useState({
title: '',
description: '',
dimension: '',
domain: '',
lifecyclePhase: '',
probability: 50,
impact: 50,
detectability: 50,
ownerDisplayName: ''
});
const set = (key)=>(value)=>setForm((f)=>({
...f,
[key]: value
}));
const handleSave = async ()=>{
if (!form.title.trim()) {
toast.add('Title is required', 'error');
return;
}
if (!form.dimension) {
toast.add('Dimension is required', 'error');
return;
}
setSaving(true);
try {
await api.post(`/api/projects/${project.id}/risks`, form);
toast.add('Risk created');
onSaved();
} catch (e) {
toast.add(e.message || 'Failed to create risk', 'error');
} finally{
setSaving(false);
}
};
return /*#__PURE__*/ _jsx("div", {
className: "modal-overlay",
onClick: onClose,
children: /*#__PURE__*/ _jsxs("div", {
className: "modal",
onClick: (e)=>e.stopPropagation(),
style: {
maxWidth: 500
},
children: [
/*#__PURE__*/ _jsx("h2", {
children: "New Risk"
}),
/*#__PURE__*/ _jsx(FormField, {
label: "Title *",
children: /*#__PURE__*/ _jsx(InlineInput, {
value: form.title,
onChange: set('title')
})
}),
/*#__PURE__*/ _jsx(FormField, {
label: "Description",
children: /*#__PURE__*/ _jsx("textarea", {
className: "input",
value: form.description,
onChange: (e)=>set('description')(e.target.value),
rows: 3,
style: {
width: '100%',
resize: 'vertical'
}
})
}),
/*#__PURE__*/ _jsxs("div", {
style: {
display: 'grid',
gridTemplateColumns: '1fr 1fr',
gap: 8
},
children: [
/*#__PURE__*/ _jsx(FormField, {
label: "Dimension *",
children: /*#__PURE__*/ _jsx(InlineSelect, {
value: form.dimension,
onChange: set('dimension'),
options: DIMENSIONS
})
}),
/*#__PURE__*/ _jsx(FormField, {
label: "Domain",
children: /*#__PURE__*/ _jsx(InlineInput, {
value: form.domain,
onChange: set('domain')
})
})
]
}),
/*#__PURE__*/ _jsx(FormField, {
label: "Lifecycle Phase",
children: /*#__PURE__*/ _jsx(InlineSelect, {
value: form.lifecyclePhase,
onChange: set('lifecyclePhase'),
options: LIFECYCLE_PHASES
})
}),
/*#__PURE__*/ _jsxs("div", {
style: {
display: 'grid',
gridTemplateColumns: '1fr 1fr 1fr',
gap: 8
},
children: [
/*#__PURE__*/ _jsx(FormField, {
label: "Probability",
children: /*#__PURE__*/ _jsx(InlineInput, {
type: "number",
min: 0,
max: 100,
value: form.probability,
onChange: set('probability')
})
}),
/*#__PURE__*/ _jsx(FormField, {
label: "Impact",
children: /*#__PURE__*/ _jsx(InlineInput, {
type: "number",
min: 0,
max: 100,
value: form.impact,
onChange: set('impact')
})
}),
/*#__PURE__*/ _jsx(FormField, {
label: "Detectability",
children: /*#__PURE__*/ _jsx(InlineInput, {
type: "number",
min: 0,
max: 100,
value: form.detectability,
onChange: set('detectability')
})
})
]
}),
/*#__PURE__*/ _jsx(FormField, {
label: "Owner",
children: /*#__PURE__*/ _jsx(InlineInput, {
value: form.ownerDisplayName,
onChange: set('ownerDisplayName')
})
}),
/*#__PURE__*/ _jsxs("div", {
className: "modal-actions",
children: [
/*#__PURE__*/ _jsx("button", {
className: "button secondary small",
onClick: onClose,
children: "Cancel"
}),
/*#__PURE__*/ _jsx("button", {
className: "button small",
onClick: handleSave,
disabled: saving,
children: saving ? 'Saving...' : 'Create Risk'
})
]
})
]
})
});
}
function RisksTab({ project, dashboard, toast, onRefresh }) {
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 [showCreate, setShowCreate] = useState(false);
const [editing, setEditing] = useState(false);
const [editForm, setEditForm] = useState({});
const [updating, setUpdating] = useState(null);
const [confirmDelete, setConfirmDelete] = useState(null);
const [deleting, setDeleting] = useState(false);
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 openDetail = (risk)=>{
setSelectedRisk(risk);
setEditForm({
title: risk.title || '',
description: risk.description || '',
dimension: risk.dimension || '',
domain: risk.domain || '',
lifecyclePhase: risk.lifecyclePhase || '',
probability: risk.probability ?? 50,
impact: risk.impact ?? 50,
detectability: risk.detectability ?? 50,
ownerDisplayName: risk.ownerDisplayName || ''
});
setEditing(false);
setConfirmDelete(null);
};
const updateStatus = async (riskId, status)=>{
setUpdating(riskId);
try {
await api.patch(`/api/risks/${riskId}`, {
status
});
toast.add(`Risk status updated to ${status}`);
setSelectedRisk(null);
onRefresh();
} catch (e) {
toast.add(e.message, 'error');
} finally{
setUpdating(null);
}
};
const saveEdit = async ()=>{
if (!editForm.title.trim()) {
toast.add('Title is required', 'error');
return;
}
setUpdating('edit');
try {
await api.patch(`/api/risks/${selectedRisk.id}`, editForm);
toast.add('Risk updated');
setSelectedRisk(null);
onRefresh();
} catch (e) {
toast.add(e.message || 'Failed to update', 'error');
} finally{
setUpdating(null);
}
};
const handleDelete = async ()=>{
setDeleting(true);
try {
await api.del(`/api/risks/${confirmDelete.id}`);
toast.add('Risk deleted');
setConfirmDelete(null);
setSelectedRisk(null);
onRefresh();
} catch (e) {
toast.add(e.message || 'Failed to delete', 'error');
} finally{
setDeleting(false);
}
};
if (!dashboard) return /*#__PURE__*/ _jsx("div", {
className: "empty-state",
children: /*#__PURE__*/ _jsx("p", {
children: "Loading..."
})
});
return /*#__PURE__*/ _jsxs(_Fragment, {
children: [
/*#__PURE__*/ _jsxs("div", {
style: {
display: 'flex',
gap: 8,
marginBottom: 12
},
children: [
/*#__PURE__*/ _jsx(SearchInput, {
value: search,
onChange: setSearch,
placeholder: "Search risks by title, dimension, owner..."
}),
/*#__PURE__*/ _jsx("button", {
className: "button small",
onClick: ()=>setShowCreate(true),
children: "+ New Risk"
})
]
}),
/*#__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: ()=>openDetail(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"
})
}),
showCreate && /*#__PURE__*/ _jsx(RiskFormModal, {
project: project,
onClose: ()=>setShowCreate(false),
onSaved: ()=>{
setShowCreate(false);
onRefresh();
},
toast: toast
}),
selectedRisk && !confirmDelete && /*#__PURE__*/ _jsx("div", {
className: "modal-overlay",
onClick: ()=>setSelectedRisk(null),
children: /*#__PURE__*/ _jsxs("div", {
className: "modal",
onClick: (e)=>e.stopPropagation(),
style: {
maxWidth: 520
},
children: [
/*#__PURE__*/ _jsxs("div", {
style: {
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center'
},
children: [
/*#__PURE__*/ _jsx("h2", {
style: {
margin: 0
},
children: selectedRisk.title
}),
/*#__PURE__*/ _jsx("button", {
className: "button secondary small",
onClick: ()=>setEditing(!editing),
children: editing ? 'View' : 'Edit'
})
]
}),
editing ? /*#__PURE__*/ _jsxs(_Fragment, {
children: [
/*#__PURE__*/ _jsxs("div", {
style: {
marginTop: 12
},
children: [
/*#__PURE__*/ _jsx(FormField, {
label: "Title *",
children: /*#__PURE__*/ _jsx(InlineInput, {
value: editForm.title,
onChange: (v)=>setEditForm((f)=>({
...f,
title: v
}))
})
}),
/*#__PURE__*/ _jsx(FormField, {
label: "Description",
children: /*#__PURE__*/ _jsx("textarea", {
className: "input",
value: editForm.description,
onChange: (e)=>setEditForm((f)=>({
...f,
description: e.target.value
})),
rows: 2,
style: {
width: '100%',
resize: 'vertical'
}
})
}),
/*#__PURE__*/ _jsxs("div", {
style: {
display: 'grid',
gridTemplateColumns: '1fr 1fr',
gap: 8
},
children: [
/*#__PURE__*/ _jsx(FormField, {
label: "Dimension",
children: /*#__PURE__*/ _jsx(InlineSelect, {
value: editForm.dimension,
onChange: (v)=>setEditForm((f)=>({
...f,
dimension: v
})),
options: DIMENSIONS
})
}),
/*#__PURE__*/ _jsx(FormField, {
label: "Domain",
children: /*#__PURE__*/ _jsx(InlineInput, {
value: editForm.domain,
onChange: (v)=>setEditForm((f)=>({
...f,
domain: v
}))
})
})
]
}),
/*#__PURE__*/ _jsx(FormField, {
label: "Lifecycle Phase",
children: /*#__PURE__*/ _jsx(InlineSelect, {
value: editForm.lifecyclePhase,
onChange: (v)=>setEditForm((f)=>({
...f,
lifecyclePhase: v
})),
options: LIFECYCLE_PHASES
})
}),
/*#__PURE__*/ _jsxs("div", {
style: {
display: 'grid',
gridTemplateColumns: '1fr 1fr 1fr',
gap: 8
},
children: [
/*#__PURE__*/ _jsx(FormField, {
label: "Probability",
children: /*#__PURE__*/ _jsx(InlineInput, {
type: "number",
min: 0,
max: 100,
value: editForm.probability,
onChange: (v)=>setEditForm((f)=>({
...f,
probability: Number(v)
}))
})
}),
/*#__PURE__*/ _jsx(FormField, {
label: "Impact",
children: /*#__PURE__*/ _jsx(InlineInput, {
type: "number",
min: 0,
max: 100,
value: editForm.impact,
onChange: (v)=>setEditForm((f)=>({
...f,
impact: Number(v)
}))
})
}),
/*#__PURE__*/ _jsx(FormField, {
label: "Detectability",
children: /*#__PURE__*/ _jsx(InlineInput, {
type: "number",
min: 0,
max: 100,
value: editForm.detectability,
onChange: (v)=>setEditForm((f)=>({
...f,
detectability: Number(v)
}))
})
})
]
}),
/*#__PURE__*/ _jsx(FormField, {
label: "Owner",
children: /*#__PURE__*/ _jsx(InlineInput, {
value: editForm.ownerDisplayName,
onChange: (v)=>setEditForm((f)=>({
...f,
ownerDisplayName: v
}))
})
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "modal-actions",
children: [
/*#__PURE__*/ _jsx("button", {
className: "button secondary small",
onClick: ()=>setSelectedRisk(null),
children: "Cancel"
}),
/*#__PURE__*/ _jsx("button", {
className: "button small",
onClick: saveEdit,
disabled: updating === 'edit',
children: updating === 'edit' ? 'Saving...' : 'Save Changes'
}),
/*#__PURE__*/ _jsx("button", {
className: "button small",
style: {
background: 'var(--danger)',
color: '#fff',
marginLeft: 'auto'
},
onClick: ()=>setConfirmDelete(selectedRisk),
children: "Delete"
})
]
})
]
}) : /*#__PURE__*/ _jsxs(_Fragment, {
children: [
/*#__PURE__*/ _jsxs("div", {
style: {
display: 'grid',
gridTemplateColumns: '1fr 1fr',
gap: 12,
fontSize: 13,
marginTop: 12
},
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: RISK_STATUSES.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"
})
})
]
})
]
})
}),
confirmDelete && /*#__PURE__*/ _jsx(ConfirmDelete, {
label: "this risk",
onConfirm: handleDelete,
onCancel: ()=>setConfirmDelete(null),
deleting: deleting
})
]
});
}
function MitigationFormModal({ project, risks, onClose, onSaved, toast }) {
const [saving, setSaving] = useState(false);
const [form, setForm] = useState({
riskId: '',
title: '',
description: '',
status: 'NOT_STARTED',
progressPercent: 0,
effectivenessPercent: 0,
dueDate: '',
ownerDisplayName: ''
});
const set = (key)=>(value)=>setForm((f)=>({
...f,
[key]: value
}));
const handleSave = async ()=>{
if (!form.title.trim()) {
toast.add('Title is required', 'error');
return;
}
if (!form.riskId) {
toast.add('Please select a risk', 'error');
return;
}
setSaving(true);
try {
const body = {
...form,
progressPercent: Number(form.progressPercent),
effectivenessPercent: Number(form.effectivenessPercent)
};
if (body.dueDate) body.dueDate = new Date(body.dueDate).toISOString();
else delete body.dueDate;
await api.post(`/api/risks/${form.riskId}/mitigations`, body);
toast.add('Mitigation created');
onSaved();
} catch (e) {
toast.add(e.message || 'Failed to create mitigation', 'error');
} finally{
setSaving(false);
}
};
return /*#__PURE__*/ _jsx("div", {
className: "modal-overlay",
onClick: onClose,
children: /*#__PURE__*/ _jsxs("div", {
className: "modal",
onClick: (e)=>e.stopPropagation(),
style: {
maxWidth: 500
},
children: [
/*#__PURE__*/ _jsx("h2", {
children: "New Mitigation"
}),
/*#__PURE__*/ _jsx(FormField, {
label: "Risk *",
children: /*#__PURE__*/ _jsx(InlineSelect, {
value: form.riskId,
onChange: set('riskId'),
options: (risks || []).map((r)=>({
value: r.id,
label: r.title
}))
})
}),
/*#__PURE__*/ _jsx(FormField, {
label: "Title *",
children: /*#__PURE__*/ _jsx(InlineInput, {
value: form.title,
onChange: set('title')
})
}),
/*#__PURE__*/ _jsx(FormField, {
label: "Description",
children: /*#__PURE__*/ _jsx("textarea", {
className: "input",
value: form.description,
onChange: (e)=>set('description')(e.target.value),
rows: 2,
style: {
width: '100%',
resize: 'vertical'
}
})
}),
/*#__PURE__*/ _jsx(FormField, {
label: "Status",
children: /*#__PURE__*/ _jsx(InlineSelect, {
value: form.status,
onChange: set('status'),
options: MITIGATION_STATUSES
})
}),
/*#__PURE__*/ _jsxs("div", {
style: {
display: 'grid',
gridTemplateColumns: '1fr 1fr',
gap: 8
},
children: [
/*#__PURE__*/ _jsx(FormField, {
label: "Progress %",
children: /*#__PURE__*/ _jsx(InlineInput, {
type: "number",
min: 0,
max: 100,
value: form.progressPercent,
onChange: set('progressPercent')
})
}),
/*#__PURE__*/ _jsx(FormField, {
label: "Effectiveness %",
children: /*#__PURE__*/ _jsx(InlineInput, {
type: "number",
min: 0,
max: 100,
value: form.effectivenessPercent,
onChange: set('effectivenessPercent')
})
})
]
}),
/*#__PURE__*/ _jsx(FormField, {
label: "Due Date",
children: /*#__PURE__*/ _jsx(InlineInput, {
type: "date",
value: form.dueDate,
onChange: set('dueDate')
})
}),
/*#__PURE__*/ _jsx(FormField, {
label: "Owner",
children: /*#__PURE__*/ _jsx(InlineInput, {
value: form.ownerDisplayName,
onChange: set('ownerDisplayName')
})
}),
/*#__PURE__*/ _jsxs("div", {
className: "modal-actions",
children: [
/*#__PURE__*/ _jsx("button", {
className: "button secondary small",
onClick: onClose,
children: "Cancel"
}),
/*#__PURE__*/ _jsx("button", {
className: "button small",
onClick: handleSave,
disabled: saving,
children: saving ? 'Saving...' : 'Create Mitigation'
})
]
})
]
})
});
}
function MitigationsTab({ project, dashboard, toast, onRefresh }) {
const [search, setSearch] = useState('');
const [sortKey, setSortKey] = useState('progressPercent');
const [sortDir, setSortDir] = useState('asc');
const [showCreate, setShowCreate] = useState(false);
const [selectedMitigation, setSelectedMitigation] = useState(null);
const [editing, setEditing] = useState(false);
const [editForm, setEditForm] = useState({});
const [updating, setUpdating] = useState(null);
const [confirmDelete, setConfirmDelete] = useState(null);
const [deleting, setDeleting] = useState(false);
const mitigations = useMemo(()=>{
if (!dashboard?.mitigations) return [];
return sortData(dashboard.mitigations, sortKey, sortDir);
}, [
dashboard,
sortKey,
sortDir
]);
const risks = useMemo(()=>{
if (!dashboard?.topRisks) return [];
return dashboard.topRisks;
}, [
dashboard
]);
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');
}
};
const openDetail = (m)=>{
setSelectedMitigation(m);
setEditForm({
title: m.title || '',
description: m.description || '',
status: m.status || 'NOT_STARTED',
progressPercent: m.progressPercent ?? 0,
effectivenessPercent: m.effectivenessPercent ?? 0,
dueDate: m.dueDate ? m.dueDate.slice(0, 10) : '',
ownerDisplayName: m.ownerDisplayName || ''
});
setEditing(true);
setConfirmDelete(null);
};
const saveEdit = async ()=>{
if (!editForm.title.trim()) {
toast.add('Title is required', 'error');
return;
}
setUpdating('edit');
try {
const body = {
...editForm,
progressPercent: Number(editForm.progressPercent),
effectivenessPercent: Number(editForm.effectivenessPercent)
};
if (body.dueDate) body.dueDate = new Date(body.dueDate).toISOString();
else body.dueDate = null;
await api.patch(`/api/mitigations/${selectedMitigation.id}`, body);
toast.add('Mitigation updated');
setSelectedMitigation(null);
onRefresh();
} catch (e) {
toast.add(e.message || 'Failed to update', 'error');
} finally{
setUpdating(null);
}
};
const handleDelete = async ()=>{
setDeleting(true);
try {
await api.del(`/api/mitigations/${confirmDelete.id}`);
toast.add('Mitigation deleted');
setConfirmDelete(null);
setSelectedMitigation(null);
onRefresh();
} catch (e) {
toast.add(e.message || 'Failed to delete', 'error');
} finally{
setDeleting(false);
}
};
if (!dashboard) return /*#__PURE__*/ _jsx("div", {
className: "empty-state",
children: /*#__PURE__*/ _jsx("p", {
children: "Loading..."
})
});
return /*#__PURE__*/ _jsxs(_Fragment, {
children: [
/*#__PURE__*/ _jsxs("div", {
style: {
display: 'flex',
gap: 8,
marginBottom: 12
},
children: [
/*#__PURE__*/ _jsx(SearchInput, {
value: search,
onChange: setSearch,
placeholder: "Search mitigations..."
}),
/*#__PURE__*/ _jsx("button", {
className: "button small",
onClick: ()=>setShowCreate(true),
children: "+ New Mitigation"
})
]
}),
/*#__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", {
onClick: ()=>openDetail(m),
style: {
cursor: 'pointer'
},
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"
})
}),
showCreate && /*#__PURE__*/ _jsx(MitigationFormModal, {
project: project,
risks: risks,
onClose: ()=>setShowCreate(false),
onSaved: ()=>{
setShowCreate(false);
onRefresh();
},
toast: toast
}),
selectedMitigation && !confirmDelete && /*#__PURE__*/ _jsx("div", {
className: "modal-overlay",
onClick: ()=>setSelectedMitigation(null),
children: /*#__PURE__*/ _jsxs("div", {
className: "modal",
onClick: (e)=>e.stopPropagation(),
style: {
maxWidth: 500
},
children: [
/*#__PURE__*/ _jsx("h2", {
style: {
margin: 0
},
children: editing ? 'Edit Mitigation' : selectedMitigation.title
}),
/*#__PURE__*/ _jsxs("div", {
style: {
marginTop: 12
},
children: [
/*#__PURE__*/ _jsx(FormField, {
label: "Title *",
children: /*#__PURE__*/ _jsx(InlineInput, {
value: editForm.title,
onChange: (v)=>setEditForm((f)=>({
...f,
title: v
}))
})
}),
/*#__PURE__*/ _jsx(FormField, {
label: "Description",
children: /*#__PURE__*/ _jsx("textarea", {
className: "input",
value: editForm.description,
onChange: (e)=>setEditForm((f)=>({
...f,
description: e.target.value
})),
rows: 2,
style: {
width: '100%',
resize: 'vertical'
}
})
}),
/*#__PURE__*/ _jsx(FormField, {
label: "Status",
children: /*#__PURE__*/ _jsx(InlineSelect, {
value: editForm.status,
onChange: (v)=>setEditForm((f)=>({
...f,
status: v
})),
options: MITIGATION_STATUSES
})
}),
/*#__PURE__*/ _jsxs("div", {
style: {
display: 'grid',
gridTemplateColumns: '1fr 1fr',
gap: 8
},
children: [
/*#__PURE__*/ _jsx(FormField, {
label: "Progress %",
children: /*#__PURE__*/ _jsx(InlineInput, {
type: "number",
min: 0,
max: 100,
value: editForm.progressPercent,
onChange: (v)=>setEditForm((f)=>({
...f,
progressPercent: Number(v)
}))
})
}),
/*#__PURE__*/ _jsx(FormField, {
label: "Effectiveness %",
children: /*#__PURE__*/ _jsx(InlineInput, {
type: "number",
min: 0,
max: 100,
value: editForm.effectivenessPercent,
onChange: (v)=>setEditForm((f)=>({
...f,
effectivenessPercent: Number(v)
}))
})
})
]
}),
/*#__PURE__*/ _jsx(FormField, {
label: "Due Date",
children: /*#__PURE__*/ _jsx(InlineInput, {
type: "date",
value: editForm.dueDate,
onChange: (v)=>setEditForm((f)=>({
...f,
dueDate: v
}))
})
}),
/*#__PURE__*/ _jsx(FormField, {
label: "Owner",
children: /*#__PURE__*/ _jsx(InlineInput, {
value: editForm.ownerDisplayName,
onChange: (v)=>setEditForm((f)=>({
...f,
ownerDisplayName: v
}))
})
})
]
}),
/*#__PURE__*/ _jsxs("div", {
className: "modal-actions",
children: [
/*#__PURE__*/ _jsx("button", {
className: "button secondary small",
onClick: ()=>setSelectedMitigation(null),
children: "Cancel"
}),
/*#__PURE__*/ _jsx("button", {
className: "button small",
onClick: saveEdit,
disabled: updating === 'edit',
children: updating === 'edit' ? 'Saving...' : 'Save Changes'
}),
/*#__PURE__*/ _jsx("button", {
className: "button small",
style: {
background: 'var(--danger)',
color: '#fff',
marginLeft: 'auto'
},
onClick: ()=>setConfirmDelete(selectedMitigation),
children: "Delete"
})
]
})
]
})
}),
confirmDelete && /*#__PURE__*/ _jsx(ConfirmDelete, {
label: "this mitigation",
onConfirm: handleDelete,
onCancel: ()=>setConfirmDelete(null),
deleting: deleting
})
]
});
}
function GateTab({ project, dashboard, toast, onRefresh }) {
const [evaluating, setEvaluating] = useState(false);
const [showDecision, setShowDecision] = useState(false);
const [decisionForm, setDecisionForm] = useState({
decision: 'APPROVED',
reviewerName: '',
reason: ''
});
const [savingDecision, setSavingDecision] = useState(false);
const criteria = dashboard?.gate?.criteria || [];
const gateStatus = dashboard?.summary?.gateStatus || 'Unknown';
const gateId = dashboard?.gate?.id;
const gateCls = gateStatus === 'Ready' ? 'good' : gateStatus === 'Warning' ? 'warn' : 'bad';
const handleEvaluate = async ()=>{
setEvaluating(true);
try {
await api.post(`/api/projects/${project.id}/gate/evaluate`, {});
toast.add('Gate evaluated');
onRefresh();
} catch (e) {
toast.add(e.message || 'Evaluation failed', 'error');
} finally{
setEvaluating(false);
}
};
const submitDecision = async ()=>{
if (!decisionForm.reviewerName.trim()) {
toast.add('Reviewer name is required', 'error');
return;
}
setSavingDecision(true);
try {
await api.post(`/api/gates/${gateId}/decisions`, decisionForm);
toast.add('Decision submitted');
setShowDecision(false);
onRefresh();
} catch (e) {
toast.add(e.message || 'Failed to submit decision', 'error');
} finally{
setSavingDecision(false);
}
};
if (!dashboard) return /*#__PURE__*/ _jsx("div", {
className: "empty-state",
children: /*#__PURE__*/ _jsx("p", {
children: "Loading..."
})
});
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: "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,
flexWrap: 'wrap'
},
children: [
/*#__PURE__*/ _jsx("button", {
className: "button small",
onClick: handleEvaluate,
disabled: evaluating,
children: evaluating ? 'Evaluating...' : 'Evaluate Gate'
}),
gateId && /*#__PURE__*/ _jsx("button", {
className: "button secondary small",
onClick: ()=>setShowDecision(true),
children: "Add Decision"
}),
/*#__PURE__*/ _jsx("a", {
href: `/api/projects/${project?.id}/gate/history`,
className: "button secondary small",
target: "_blank",
children: "History (API)"
})
]
}),
showDecision && /*#__PURE__*/ _jsx("div", {
className: "modal-overlay",
onClick: ()=>setShowDecision(false),
children: /*#__PURE__*/ _jsxs("div", {
className: "modal",
onClick: (e)=>e.stopPropagation(),
style: {
maxWidth: 400
},
children: [
/*#__PURE__*/ _jsx("h2", {
children: "Gate Decision"
}),
/*#__PURE__*/ _jsx(FormField, {
label: "Decision",
children: /*#__PURE__*/ _jsx(InlineSelect, {
value: decisionForm.decision,
onChange: (v)=>setDecisionForm((f)=>({
...f,
decision: v
})),
options: [
'APPROVED',
'REJECTED',
'ACCEPTED',
'NEEDS_CHANGES'
]
})
}),
/*#__PURE__*/ _jsx(FormField, {
label: "Reviewer Name *",
children: /*#__PURE__*/ _jsx(InlineInput, {
value: decisionForm.reviewerName,
onChange: (v)=>setDecisionForm((f)=>({
...f,
reviewerName: v
}))
})
}),
/*#__PURE__*/ _jsx(FormField, {
label: "Reason",
children: /*#__PURE__*/ _jsx("textarea", {
className: "input",
value: decisionForm.reason,
onChange: (e)=>setDecisionForm((f)=>({
...f,
reason: e.target.value
})),
rows: 3,
style: {
width: '100%',
resize: 'vertical'
}
})
}),
/*#__PURE__*/ _jsxs("div", {
className: "modal-actions",
children: [
/*#__PURE__*/ _jsx("button", {
className: "button secondary small",
onClick: ()=>setShowDecision(false),
children: "Cancel"
}),
/*#__PURE__*/ _jsx("button", {
className: "button small",
onClick: submitDecision,
disabled: savingDecision,
children: savingDecision ? 'Saving...' : 'Submit Decision'
})
]
})
]
})
})
]
});
}
function IntegrationFormModal({ project, dashboard, onClose, onSaved, toast }) {
const [saving, setSaving] = useState(false);
const [form, setForm] = useState({
provider: 'TRELLO',
workspaceName: '',
baseUrl: '',
authMode: 'API_KEY'
});
const set = (key)=>(value)=>setForm((f)=>({
...f,
[key]: value
}));
const wsId = dashboard?.gate?.workspaceId || project?.workspaceId;
const handleSave = async ()=>{
if (!form.workspaceName.trim()) {
toast.add('Workspace name is required', 'error');
return;
}
setSaving(true);
try {
await api.post(`/api/workspaces/${wsId}/integrations`, form);
toast.add('Integration created');
onSaved();
} catch (e) {
toast.add(e.message || 'Failed to create integration', 'error');
} finally{
setSaving(false);
}
};
return /*#__PURE__*/ _jsx("div", {
className: "modal-overlay",
onClick: onClose,
children: /*#__PURE__*/ _jsxs("div", {
className: "modal",
onClick: (e)=>e.stopPropagation(),
style: {
maxWidth: 450
},
children: [
/*#__PURE__*/ _jsx("h2", {
children: "New Integration"
}),
/*#__PURE__*/ _jsx(FormField, {
label: "Provider",
children: /*#__PURE__*/ _jsx(InlineSelect, {
value: form.provider,
onChange: set('provider'),
options: [
'TRELLO',
'JIRA',
'ASANA',
'MICROSOFT_PLANNER'
]
})
}),
/*#__PURE__*/ _jsx(FormField, {
label: "Workspace Name *",
children: /*#__PURE__*/ _jsx(InlineInput, {
value: form.workspaceName,
onChange: set('workspaceName')
})
}),
/*#__PURE__*/ _jsx(FormField, {
label: "Base URL",
children: /*#__PURE__*/ _jsx(InlineInput, {
value: form.baseUrl,
onChange: set('baseUrl')
})
}),
/*#__PURE__*/ _jsx(FormField, {
label: "Auth Mode",
children: /*#__PURE__*/ _jsx(InlineSelect, {
value: form.authMode,
onChange: set('authMode'),
options: [
'API_KEY',
'OAUTH',
'BASIC'
]
})
}),
/*#__PURE__*/ _jsxs("div", {
className: "modal-actions",
children: [
/*#__PURE__*/ _jsx("button", {
className: "button secondary small",
onClick: onClose,
children: "Cancel"
}),
/*#__PURE__*/ _jsx("button", {
className: "button small",
onClick: handleSave,
disabled: saving,
children: saving ? 'Saving...' : 'Create Integration'
})
]
})
]
})
});
}
function IntegrationsTab({ project, dashboard, toast, onRefresh }) {
const [showCreate, setShowCreate] = useState(false);
const integrations = dashboard?.integrations || [];
return /*#__PURE__*/ _jsxs(_Fragment, {
children: [
/*#__PURE__*/ _jsxs("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: "dash-actions",
children: /*#__PURE__*/ _jsx("button", {
className: "button small",
onClick: ()=>setShowCreate(true),
children: "+ New Integration"
})
})
]
}),
/*#__PURE__*/ _jsx("div", {
className: "grid",
style: {
gridTemplateColumns: 'repeat(auto-fit, minmax(240px, 1fr))'
},
children: [
'TRELLO',
'JIRA',
'ASANA',
'MICROSOFT_PLANNER'
].map((provider)=>{
const existing = integrations.find((i)=>i.provider === provider);
return /*#__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: existing ? existing.workspaceName : 'Not configured'
}),
/*#__PURE__*/ _jsx("div", {
style: {
display: 'flex',
gap: 6,
justifyContent: 'center'
},
children: existing ? /*#__PURE__*/ _jsx("a", {
href: `/api/integrations/${existing.id}`,
className: "button secondary small",
target: "_blank",
children: "Manage"
}) : /*#__PURE__*/ _jsx("button", {
className: "button secondary small",
onClick: ()=>setShowCreate(true),
children: "Configure"
})
})
]
}, provider);
})
}),
showCreate && /*#__PURE__*/ _jsx(IntegrationFormModal, {
project: project,
dashboard: dashboard,
onClose: ()=>setShowCreate(false),
onSaved: ()=>{
setShowCreate(false);
onRefresh();
},
toast: toast
}),
!integrations.length && /*#__PURE__*/ _jsx("div", {
style: {
marginTop: 12
},
children: /*#__PURE__*/ _jsx("a", {
href: "/api/integration-providers",
className: "button secondary small",
target: "_blank",
children: "Integration providers (API)"
})
})
]
});
}
function AuditTab({ project, toast }) {
const [events, setEvents] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const load = useCallback(async ()=>{
if (!project) return;
setLoading(true);
setError(null);
try {
const resp = await api.get(`/api/projects/${project.id}/audit`);
setEvents(resp.auditEvents || []);
} catch (e) {
setError(e.message || 'Failed to load audit log');
} finally{
setLoading(false);
}
}, [
project
]);
process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{
load();
}, [
load
]);
if (loading) return /*#__PURE__*/ _jsx("div", {
className: "empty-state",
children: /*#__PURE__*/ _jsx("p", {
children: "Loading audit log..."
})
});
if (error) return /*#__PURE__*/ _jsx("div", {
className: "empty-state",
children: /*#__PURE__*/ _jsx("p", {
children: error
})
});
if (!events.length) return /*#__PURE__*/ _jsx("div", {
className: "empty-state",
children: /*#__PURE__*/ _jsx("p", {
children: "No audit events recorded yet"
})
});
return /*#__PURE__*/ _jsxs(_Fragment, {
children: [
/*#__PURE__*/ _jsxs("div", {
className: "dash-header",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("h1", {
children: "Audit Log"
}),
/*#__PURE__*/ _jsx("p", {
className: "muted",
children: "Project activity history"
})
]
}),
/*#__PURE__*/ _jsx("div", {
className: "dash-actions",
children: /*#__PURE__*/ _jsx("button", {
className: "button secondary small",
onClick: load,
children: "Refresh"
})
})
]
}),
/*#__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: "Date"
}),
/*#__PURE__*/ _jsx("th", {
children: "Action"
}),
/*#__PURE__*/ _jsx("th", {
children: "Entity"
}),
/*#__PURE__*/ _jsx("th", {
children: "Actor"
}),
/*#__PURE__*/ _jsx("th", {
children: "Details"
})
]
})
}),
/*#__PURE__*/ _jsx("tbody", {
children: events.map((e)=>/*#__PURE__*/ _jsxs("tr", {
children: [
/*#__PURE__*/ _jsx("td", {
style: {
fontSize: 12,
whiteSpace: 'nowrap'
},
children: new Date(e.createdAt).toLocaleString()
}),
/*#__PURE__*/ _jsx("td", {
children: /*#__PURE__*/ _jsx(Badge, {
className: e.action?.toLowerCase().replace(/\s+/g, '-'),
children: e.action
})
}),
/*#__PURE__*/ _jsxs("td", {
style: {
fontSize: 12
},
children: [
e.entityType,
" ",
/*#__PURE__*/ _jsxs("span", {
className: "muted",
children: [
"(",
e.entityId?.slice(0, 8),
")"
]
})
]
}),
/*#__PURE__*/ _jsx("td", {
style: {
fontSize: 12
},
children: e.actorUserId || 'system'
}),
/*#__PURE__*/ _jsx("td", {
style: {
fontSize: 12,
maxWidth: 300,
overflow: 'hidden',
textOverflow: 'ellipsis'
},
children: e.afterJson ? JSON.stringify(e.afterJson).slice(0, 80) : '-'
})
]
}, e.id))
})
]
})
})
]
});
}
function ProjectsTab({ projects, workspaceId, currentProjectId, onSwitch, onRefresh, toast }) {
const [deleting, setDeleting] = useState(null);
const [confirmDelete, setConfirmDelete] = useState(null);
const [showNew, setShowNew] = useState(false);
const handleDelete = async ()=>{
setDeleting(true);
try {
await api.del(`/api/projects/${confirmDelete.id}`);
toast.add(`Project "${confirmDelete.name}" deleted`);
setConfirmDelete(null);
onRefresh();
} catch (e) {
toast.add(e.message || 'Failed to delete project', 'error');
} finally{
setDeleting(false);
}
};
return /*#__PURE__*/ _jsxs(_Fragment, {
children: [
/*#__PURE__*/ _jsxs("div", {
className: "dash-header",
children: [
/*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsx("h1", {
children: "All Projects"
}),
/*#__PURE__*/ _jsxs("p", {
className: "muted",
children: [
projects.length,
" project(s) in workspace"
]
})
]
}),
/*#__PURE__*/ _jsx("div", {
className: "dash-actions",
children: /*#__PURE__*/ _jsx("button", {
className: "button small",
onClick: ()=>setShowNew(true),
children: "+ New Project"
})
})
]
}),
/*#__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: "Name"
}),
/*#__PURE__*/ _jsx("th", {
children: "Status"
}),
/*#__PURE__*/ _jsx("th", {
children: "Type"
}),
/*#__PURE__*/ _jsx("th", {
children: "Created"
}),
/*#__PURE__*/ _jsx("th", {
children: "Actions"
})
]
})
}),
/*#__PURE__*/ _jsx("tbody", {
children: [
...projects
].sort((a, b)=>new Date(b.createdAt) - new Date(a.createdAt)).map((p)=>/*#__PURE__*/ _jsxs("tr", {
style: {
background: p.id === currentProjectId ? 'var(--surface-alt)' : ''
},
children: [
/*#__PURE__*/ _jsxs("td", {
children: [
/*#__PURE__*/ _jsx("strong", {
children: p.name
}),
p.id === currentProjectId ? /*#__PURE__*/ _jsx("span", {
className: "muted",
style: {
fontSize: 11,
marginLeft: 6
},
children: "(current)"
}) : '',
p.description ? /*#__PURE__*/ _jsx("div", {
className: "muted",
style: {
fontSize: 11
},
children: p.description
}) : ''
]
}),
/*#__PURE__*/ _jsx("td", {
children: /*#__PURE__*/ _jsx(Badge, {
className: p.status?.toLowerCase(),
children: p.status
})
}),
/*#__PURE__*/ _jsx("td", {
style: {
fontSize: 12
},
children: p.projectType
}),
/*#__PURE__*/ _jsx("td", {
style: {
fontSize: 12
},
children: new Date(p.createdAt).toLocaleDateString()
}),
/*#__PURE__*/ _jsxs("td", {
style: {
textAlign: 'right',
whiteSpace: 'nowrap'
},
children: [
p.id !== currentProjectId && /*#__PURE__*/ _jsx("button", {
className: "button secondary small",
style: {
marginRight: 6
},
onClick: ()=>onSwitch(p.id),
children: "Open"
}),
/*#__PURE__*/ _jsx("button", {
className: "button small",
style: {
background: 'var(--danger)',
color: '#fff'
},
onClick: ()=>setConfirmDelete(p),
disabled: deleting === p.id,
children: "Delete"
})
]
})
]
}, p.id))
})
]
})
}),
!projects.length && /*#__PURE__*/ _jsx("div", {
className: "empty-state",
children: /*#__PURE__*/ _jsx("p", {
children: "No projects yet. Create one to get started."
})
}),
showNew && /*#__PURE__*/ _jsx(NewProjectModal, {
workspaceId: workspaceId,
onClose: ()=>setShowNew(false),
onSaved: ()=>{
setShowNew(false);
onRefresh();
},
toast: toast
}),
confirmDelete && /*#__PURE__*/ _jsx("div", {
className: "modal-overlay",
onClick: ()=>setConfirmDelete(null),
children: /*#__PURE__*/ _jsxs("div", {
className: "modal",
onClick: (e)=>e.stopPropagation(),
style: {
maxWidth: 380
},
children: [
/*#__PURE__*/ _jsxs("h3", {
children: [
'Delete "',
confirmDelete.name,
'"?'
]
}),
/*#__PURE__*/ _jsx("p", {
style: {
fontSize: 13,
color: 'var(--muted)'
},
children: "This permanently deletes the project and all its risks, mitigations, and data."
}),
/*#__PURE__*/ _jsxs("div", {
className: "modal-actions",
children: [
/*#__PURE__*/ _jsx("button", {
className: "button secondary small",
onClick: ()=>setConfirmDelete(null),
children: "Cancel"
}),
/*#__PURE__*/ _jsx("button", {
className: "button small",
style: {
background: 'var(--danger)',
color: '#fff'
},
onClick: handleDelete,
disabled: deleting,
children: deleting ? 'Deleting...' : 'Delete Project'
})
]
})
]
})
})
]
});
}
function ProjectSettingsModal({ project, onClose, onSaved, toast }) {
const [saving, setSaving] = useState(false);
const [form, setForm] = useState({
name: project?.name || '',
description: project?.description || '',
subtitle: project?.subtitle || '',
status: project?.status || 'Active'
});
const handleSave = async ()=>{
if (!form.name.trim()) {
toast.add('Project name is required', 'error');
return;
}
setSaving(true);
try {
await api.patch(`/api/projects/${project.id}`, form);
toast.add('Project updated');
onSaved();
} catch (e) {
toast.add(e.message || 'Failed to update project', 'error');
} finally{
setSaving(false);
}
};
return /*#__PURE__*/ _jsx("div", {
className: "modal-overlay",
onClick: onClose,
children: /*#__PURE__*/ _jsxs("div", {
className: "modal",
onClick: (e)=>e.stopPropagation(),
style: {
maxWidth: 450
},
children: [
/*#__PURE__*/ _jsx("h2", {
children: "Project Settings"
}),
/*#__PURE__*/ _jsx(FormField, {
label: "Name *",
children: /*#__PURE__*/ _jsx(InlineInput, {
value: form.name,
onChange: (v)=>setForm((f)=>({
...f,
name: v
}))
})
}),
/*#__PURE__*/ _jsx(FormField, {
label: "Subtitle",
children: /*#__PURE__*/ _jsx(InlineInput, {
value: form.subtitle,
onChange: (v)=>setForm((f)=>({
...f,
subtitle: v
}))
})
}),
/*#__PURE__*/ _jsx(FormField, {
label: "Description",
children: /*#__PURE__*/ _jsx("textarea", {
className: "input",
value: form.description,
onChange: (e)=>setForm((f)=>({
...f,
description: e.target.value
})),
rows: 3,
style: {
width: '100%',
resize: 'vertical'
}
})
}),
/*#__PURE__*/ _jsx(FormField, {
label: "Status",
children: /*#__PURE__*/ _jsx(InlineSelect, {
value: form.status,
onChange: (v)=>setForm((f)=>({
...f,
status: v
})),
options: [
'Active',
'Archived',
'On Hold'
]
})
}),
/*#__PURE__*/ _jsxs("div", {
className: "modal-actions",
children: [
/*#__PURE__*/ _jsx("button", {
className: "button secondary small",
onClick: onClose,
children: "Cancel"
}),
/*#__PURE__*/ _jsx("button", {
className: "button small",
onClick: handleSave,
disabled: saving,
children: saving ? 'Saving...' : 'Save Changes'
})
]
})
]
})
});
}
function NewProjectModal({ workspaceId, onClose, onSaved, toast }) {
const [saving, setSaving] = useState(false);
const [form, setForm] = useState({
name: '',
description: '',
projectType: 'AI-Enabler'
});
const handleSave = async ()=>{
if (!form.name.trim()) {
toast.add('Project name is required', 'error');
return;
}
setSaving(true);
try {
await api.post(`/api/workspaces/${workspaceId}/projects`, form);
toast.add('Project created');
onSaved();
} catch (e) {
toast.add(e.message || 'Failed to create project', 'error');
} finally{
setSaving(false);
}
};
return /*#__PURE__*/ _jsx("div", {
className: "modal-overlay",
onClick: onClose,
children: /*#__PURE__*/ _jsxs("div", {
className: "modal",
onClick: (e)=>e.stopPropagation(),
style: {
maxWidth: 450
},
children: [
/*#__PURE__*/ _jsx("h2", {
children: "New Project"
}),
/*#__PURE__*/ _jsx(FormField, {
label: "Name *",
children: /*#__PURE__*/ _jsx(InlineInput, {
value: form.name,
onChange: (v)=>setForm((f)=>({
...f,
name: v
}))
})
}),
/*#__PURE__*/ _jsx(FormField, {
label: "Description",
children: /*#__PURE__*/ _jsx("textarea", {
className: "input",
value: form.description,
onChange: (e)=>setForm((f)=>({
...f,
description: e.target.value
})),
rows: 3,
style: {
width: '100%',
resize: 'vertical'
}
})
}),
/*#__PURE__*/ _jsx(FormField, {
label: "Project Type",
children: /*#__PURE__*/ _jsx(InlineSelect, {
value: form.projectType,
onChange: (v)=>setForm((f)=>({
...f,
projectType: v
})),
options: [
'AI-Enabler',
'GENERATIVE_AI',
'ML-Pipeline',
'Automation'
]
})
}),
/*#__PURE__*/ _jsxs("div", {
className: "modal-actions",
children: [
/*#__PURE__*/ _jsx("button", {
className: "button secondary small",
onClick: onClose,
children: "Cancel"
}),
/*#__PURE__*/ _jsx("button", {
className: "button small",
onClick: handleSave,
disabled: saving,
children: saving ? 'Saving...' : 'Create Project'
})
]
})
]
})
});
}
function ProjectManagerModal({ projects, workspaceId, currentProjectId, onClose, onSwitch, onSaved, toast }) {
const [deleting, setDeleting] = useState(null);
const [confirmDelete, setConfirmDelete] = useState(null);
const [showNew, setShowNew] = useState(false);
const handleDelete = async ()=>{
setDeleting(true);
try {
await api.del(`/api/projects/${confirmDelete.id}`);
toast.add(`Project "${confirmDelete.name}" deleted`);
setConfirmDelete(null);
onSaved();
} catch (e) {
toast.add(e.message || 'Failed to delete project', 'error');
} finally{
setDeleting(false);
}
};
return /*#__PURE__*/ _jsxs("div", {
className: "modal-overlay",
onClick: onClose,
children: [
/*#__PURE__*/ _jsxs("div", {
className: "modal",
onClick: (e)=>e.stopPropagation(),
style: {
maxWidth: 700,
maxHeight: '80vh',
overflow: 'auto'
},
children: [
/*#__PURE__*/ _jsxs("div", {
style: {
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center'
},
children: [
/*#__PURE__*/ _jsx("h2", {
style: {
margin: 0
},
children: "All Projects"
}),
/*#__PURE__*/ _jsx("button", {
className: "button small",
onClick: ()=>setShowNew(true),
children: "+ New Project"
})
]
}),
/*#__PURE__*/ _jsxs("p", {
className: "muted",
style: {
fontSize: 12,
marginTop: 4
},
children: [
projects.length,
" project(s) in workspace"
]
}),
/*#__PURE__*/ _jsx("div", {
className: "table-wrap",
style: {
marginTop: 12
},
children: /*#__PURE__*/ _jsxs("table", {
className: "table",
children: [
/*#__PURE__*/ _jsx("thead", {
children: /*#__PURE__*/ _jsxs("tr", {
children: [
/*#__PURE__*/ _jsx("th", {
children: "Name"
}),
/*#__PURE__*/ _jsx("th", {
children: "Status"
}),
/*#__PURE__*/ _jsx("th", {
children: "Type"
}),
/*#__PURE__*/ _jsx("th", {
children: "Created"
}),
/*#__PURE__*/ _jsx("th", {})
]
})
}),
/*#__PURE__*/ _jsx("tbody", {
children: [
...projects
].sort((a, b)=>new Date(b.createdAt) - new Date(a.createdAt)).map((p)=>/*#__PURE__*/ _jsxs("tr", {
style: {
background: p.id === currentProjectId ? 'var(--surface-alt)' : ''
},
children: [
/*#__PURE__*/ _jsxs("td", {
children: [
/*#__PURE__*/ _jsx("strong", {
children: p.name
}),
p.id === currentProjectId ? /*#__PURE__*/ _jsx("span", {
className: "muted",
style: {
fontSize: 11,
marginLeft: 6
},
children: "(current)"
}) : ''
]
}),
/*#__PURE__*/ _jsx("td", {
children: /*#__PURE__*/ _jsx(Badge, {
className: p.status?.toLowerCase(),
children: p.status
})
}),
/*#__PURE__*/ _jsx("td", {
style: {
fontSize: 12
},
children: p.projectType
}),
/*#__PURE__*/ _jsx("td", {
style: {
fontSize: 12
},
children: new Date(p.createdAt).toLocaleDateString()
}),
/*#__PURE__*/ _jsxs("td", {
style: {
textAlign: 'right',
whiteSpace: 'nowrap'
},
children: [
p.id !== currentProjectId && /*#__PURE__*/ _jsx("button", {
className: "button secondary small",
style: {
marginRight: 6
},
onClick: ()=>{
onSwitch(p.id);
onClose();
},
children: "Open"
}),
/*#__PURE__*/ _jsx("button", {
className: "button small",
style: {
background: 'var(--danger)',
color: '#fff'
},
onClick: ()=>setConfirmDelete(p),
disabled: deleting === p.id,
children: "â"
})
]
})
]
}, p.id))
})
]
})
}),
!projects.length && /*#__PURE__*/ _jsx("div", {
className: "empty-state",
children: /*#__PURE__*/ _jsx("p", {
children: "No projects yet"
})
}),
/*#__PURE__*/ _jsx("div", {
className: "modal-actions",
children: /*#__PURE__*/ _jsx("button", {
className: "button secondary small",
onClick: onClose,
children: "Close"
})
})
]
}),
confirmDelete && /*#__PURE__*/ _jsx("div", {
className: "modal-overlay",
onClick: ()=>setConfirmDelete(null),
children: /*#__PURE__*/ _jsxs("div", {
className: "modal",
onClick: (e)=>e.stopPropagation(),
style: {
maxWidth: 380
},
children: [
/*#__PURE__*/ _jsxs("h3", {
children: [
'Delete "',
confirmDelete.name,
'"?'
]
}),
/*#__PURE__*/ _jsx("p", {
style: {
fontSize: 13,
color: 'var(--muted)'
},
children: "This permanently deletes the project and all its risks, mitigations, and data."
}),
/*#__PURE__*/ _jsxs("div", {
className: "modal-actions",
children: [
/*#__PURE__*/ _jsx("button", {
className: "button secondary small",
onClick: ()=>setConfirmDelete(null),
children: "Cancel"
}),
/*#__PURE__*/ _jsx("button", {
className: "button small",
style: {
background: 'var(--danger)',
color: '#fff'
},
onClick: handleDelete,
disabled: deleting,
children: deleting ? 'Deleting...' : 'Delete Project'
})
]
})
]
})
}),
showNew && /*#__PURE__*/ _jsx(NewProjectModal, {
workspaceId: workspaceId,
onClose: ()=>setShowNew(false),
onSaved: ()=>{
setShowNew(false);
onSaved();
},
toast: toast
})
]
});
}
export default function DashboardPage() {
const router = useRouter();
const searchParams = useSearchParams();
const tab = TABS.includes(searchParams.get('tab')) ? searchParams.get('tab') : 'Overview';
const [project, setProject] = useState(null);
const [projects, setProjects] = useState([]);
const [selectedProjectId, setSelectedProjectId] = useState(searchParams.get('projectId') || null);
const [dashboard, setDashboard] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const [retryCount, setRetryCount] = useState(0);
const [showProjectSettings, setShowProjectSettings] = useState(false);
const [showProjectManager, setShowProjectManager] = useState(false);
const [workspaceId, setWorkspaceId] = useState(null);
const { toasts, add } = useToast();
const onRefresh = useCallback(()=>setRetryCount((c)=>c + 1), []);
const loadDashboard = useCallback(async (projectId)=>{
setLoading(true);
setError(null);
try {
const session = await api.get('/api/auth/session');
if (!session?.authenticated) {
setError('Not authenticated.');
setLoading(false);
return;
}
const membership = session.memberships?.[0];
if (!membership) {
setError('No organization membership found.');
setLoading(false);
return;
}
const orgId = membership.organizationId;
const workspacesResp = await api.get(`/api/workspaces?organizationId=${orgId}`);
const ws = workspacesResp.workspaces?.[0];
if (!ws) {
setError('No workspace found â create one to get started.');
setLoading(false);
return;
}
setWorkspaceId(ws.id);
const projectsResp = await api.get(`/api/workspaces/${ws.id}/projects`);
const allProjects = projectsResp.projects || [];
if (!allProjects.length) {
setError('No project found â create a project to get started.');
setLoading(false);
return;
}
setProjects(allProjects);
let proj = projectId ? allProjects.find((p)=>p.id === projectId) : null;
if (!proj) proj = allProjects[0];
setProject(proj);
if (proj.id !== selectedProjectId) {
setSelectedProjectId(proj.id);
const currentTab = new URLSearchParams(window.location.search).get('tab') || 'Overview';
router.replace(`/dashboard?tab=${currentTab}&projectId=${proj.id}`);
}
const dashResp = await api.get(`/api/projects/${proj.id}/dashboard`);
setDashboard(dashResp.dashboard);
setLoading(false);
} catch (e) {
setError(e.message || 'Failed to load dashboard data');
setLoading(false);
}
}, []);
process.env.__NEXT_PRIVATE_MINIMIZE_MACRO_FALSE && useEffect(()=>{
loadDashboard(selectedProjectId);
}, [
loadDashboard,
retryCount,
selectedProjectId
]);
const switchProject = (pid)=>{
setSelectedProjectId(pid);
router.push(`/dashboard?tab=${tab}&projectId=${pid}`);
};
if (loading && tab !== 'Integrations') return /*#__PURE__*/ _jsx("div", {
className: "shell-loading",
children: /*#__PURE__*/ _jsx("div", {
className: "spinner"
})
});
if (error && tab !== 'Integrations') return /*#__PURE__*/ _jsxs("div", {
className: "empty-state",
children: [
/*#__PURE__*/ _jsx("div", {
className: "empty-icon",
children: "!"
}),
/*#__PURE__*/ _jsx("p", {
children: error
}),
/*#__PURE__*/ _jsx("button", {
className: "button secondary small",
style: {
marginTop: 12
},
onClick: ()=>setRetryCount((c)=>c + 1),
children: "Retry"
})
]
});
return /*#__PURE__*/ _jsxs(_Fragment, {
children: [
/*#__PURE__*/ _jsxs("div", {
className: "dash-header",
children: [
/*#__PURE__*/ _jsx("div", {
style: {
display: 'flex',
alignItems: 'center',
gap: 10
},
children: /*#__PURE__*/ _jsxs("div", {
children: [
/*#__PURE__*/ _jsxs("div", {
style: {
display: 'flex',
alignItems: 'center',
gap: 6
},
children: [
/*#__PURE__*/ _jsx("select", {
className: "input",
value: project?.id || '',
onChange: (e)=>switchProject(e.target.value),
style: {
fontSize: 16,
fontWeight: 700,
width: 'auto',
minWidth: 200,
border: 'none',
background: 'transparent',
cursor: 'pointer'
},
children: projects.map((p)=>/*#__PURE__*/ _jsxs("option", {
value: p.id,
children: [
p.name,
" ",
p.status !== 'Active' ? `(${p.status})` : ''
]
}, p.id))
}),
/*#__PURE__*/ _jsx("button", {
className: "button secondary small",
style: {
fontSize: 14,
padding: '2px 8px'
},
onClick: ()=>setShowProjectSettings(true),
title: "Project settings",
children: "â"
}),
/*#__PURE__*/ _jsx("button", {
className: "button secondary small",
onClick: ()=>setShowProjectManager(true),
children: "Projects"
})
]
}),
/*#__PURE__*/ _jsx("p", {
className: "muted",
style: {
margin: 0
},
children: project?.subtitle || project?.description || ''
})
]
})
}),
/*#__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}${project ? `&projectId=${project.id}` : ''}`),
children: t
}, t))
}),
tab === 'Overview' && /*#__PURE__*/ _jsx(ErrorBoundary, {
name: "Overview",
children: /*#__PURE__*/ _jsx(OverviewTab, {
project: project,
dashboard: dashboard
})
}, "overview"),
tab === 'Projects' && /*#__PURE__*/ _jsx(ErrorBoundary, {
name: "Projects",
children: /*#__PURE__*/ _jsx(ProjectsTab, {
projects: projects,
workspaceId: workspaceId,
currentProjectId: project?.id,
onSwitch: switchProject,
onRefresh: onRefresh,
toast: {
add
}
})
}, "projects"),
tab === 'Risks' && /*#__PURE__*/ _jsx(ErrorBoundary, {
name: "Risks",
children: /*#__PURE__*/ _jsx(RisksTab, {
project: project,
dashboard: dashboard,
toast: {
add
},
onRefresh: onRefresh
})
}, "risks"),
tab === 'Mitigations' && /*#__PURE__*/ _jsx(ErrorBoundary, {
name: "Mitigations",
children: /*#__PURE__*/ _jsx(MitigationsTab, {
project: project,
dashboard: dashboard,
toast: {
add
},
onRefresh: onRefresh
})
}, "mitigations"),
tab === 'Gate' && /*#__PURE__*/ _jsx(ErrorBoundary, {
name: "Gate",
children: /*#__PURE__*/ _jsx(GateTab, {
project: project,
dashboard: dashboard,
toast: {
add
},
onRefresh: onRefresh
})
}, "gate"),
tab === 'Integrations' && /*#__PURE__*/ _jsx(ErrorBoundary, {
name: "Integrations",
children: /*#__PURE__*/ _jsx(IntegrationsTab, {
project: project,
dashboard: dashboard,
toast: {
add
},
onRefresh: onRefresh
})
}, "integrations"),
tab === 'Audit' && /*#__PURE__*/ _jsx(ErrorBoundary, {
name: "Audit",
children: /*#__PURE__*/ _jsx(AuditTab, {
project: project,
toast: {
add
}
})
}, "audit"),
showProjectSettings && /*#__PURE__*/ _jsx(ProjectSettingsModal, {
project: project,
onClose: ()=>setShowProjectSettings(false),
onSaved: ()=>{
setShowProjectSettings(false);
onRefresh();
},
toast: {
add
}
}),
showProjectManager && /*#__PURE__*/ _jsx(ProjectManagerModal, {
projects: projects,
workspaceId: workspaceId,
currentProjectId: project?.id,
onClose: ()=>setShowProjectManager(false),
onSwitch: switchProject,
onSaved: ()=>{
setShowProjectManager(false);
onRefresh();
},
toast: {
add
}
}),
/*#__PURE__*/ _jsx(ToastContainer, {
toasts: toasts
})
]
});
}
`
k˙˙˙sideEffectFreej˙˙˙
k˙˙˙ô1˙˙˙
l˙˙˙ßū˙˙m˙˙˙
`$o˙˙˙p˙˙˙r˙˙˙next/dist/compiled/server-onlyr˙˙˙s˙˙˙t˙˙˙u˙˙˙v˙˙˙w˙˙˙x˙˙˙y˙˙˙z˙˙˙{˙˙˙|˙˙˙}˙˙˙~˙˙˙˙˙˙
˙˙˙¤next/dist/compiled/server-only/index¤next/dist/compiled/client-only/index˙ūnext/dist/api/navigationēnext/dist/server/route-modules/app-page/vendored/ssr/reactËnext/dist/server/route-modules/app-page/vendored/ssr/react-compiler-runtimeĘnext/dist/server/route-modules/app-page/vendored/ssr/react-jsx-dev-runtimeÆnext/dist/server/route-modules/app-page/vendored/ssr/react-jsx-runtimežnext/dist/server/route-modules/app-page/vendored/ssr/react-dom ĄĸŖ¤Ônext/dist/server/route-modules/app-page/vendored/ssr/react-server-dom-webpack-clientˇnext/dist/compiled/react-server-dom-webpack/server.node˙ˇnext/dist/compiled/react-server-dom-webpack/static.nodeĨĻ
¨î
šâ 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ēģŧ094f6529d47e5eaf
ŊžÁÂÆ
`useToastToastContainerSearchInputsortData
BadgeFormFieldInlineInputInlineSelectConfirmDeleteOverviewTabRiskFormModalRisksTabMitigationFormModalMitigationsTabGateTabIntegrationFormModalIntegrationsTabAuditTabProjectsTabProjectSettingsModalNewProjectModalProjectManagerModalTABSPAGE_SIZEDIMENSIONSLIFECYCLE_PHASESRISK_STATUSESMITIGATION_STATUSESĢDashboardPage đĨ?ĸķyB˛ū˙˙˙˙˙
d˙ ˙ ũ`=@
a=@ A Ö
`BA×
`=A @
`+AA |
`;A ¤N Aõ ¤N
@Ģ @Ø @c react/jsx-runtime˙
a=@ Îū˙˙Îū˙˙
`Bnext/navigation˙
`=../../lib/api-client˙
`+../../components/ErrorBoundary˙
`;ąwebpack/lib/dependencies/PureExpressionDependencya
A ų
a
A$ x
c
A ×
c
Aī 0 ˙˙˙
c"
AN |˙˙˙
c#(
useStateū
AĘ Ō
v˙˙˙ŗū˙˙ŗū˙˙ũ
c* *(
useCallbackū
Ač ķ
úŽū˙˙Žū˙˙ū
c++
jsx_jsx
Aë ī
j˙˙˙××ũ
c>>
ųú
AO S
ûĶĶū
c@0@4
jsxs
_jsxs
A! &
_˙˙˙ĖĖũ
cGG
îī
A
ûČČū
cJJ
ęë
A
÷ÄÄū
cNN
æį
A˛
ļ
R˙˙˙ŋŋũ
cdd
ėí
AX ]
M˙˙˙ēēũ
cjj
ÜŨ
AÎ Ō
ûļļū
coo
ØŲ
Ak
o
D˙˙˙ąąũ
c}}
Ūß
Aā å
?˙˙˙ŦŦũ
@ `@ `
ÎĪ
Aš Ŋ
û¨¨ū
@ `@ `
ĘË
Aā ä
÷¤¤ū
@ `%@ `)
ÆĮ
AË Ī
2˙˙˙ũ
@¤ `@¤ `
ĖÍ
A8 =
ûū
@§ ` @§ `%
ČÉ
A
÷ū
@Ž `@Ž `#
šē
Aâ æ
ķū
@ĩ `@ĩ `"
ĀÁ
Aß ä
īū
@ŧ `@ŧ `#
ą˛
Ad h
ëū
@ŋ `&@ŋ `*
Ž
AV Z
įū
@Ä `&@Ä `*
useMemoū
A §
˙˙˙Qū˙˙Qū˙˙ũ
@Õ `@Õ `
Ŗ¤
Ag k
û}˙˙˙}˙˙˙ū
@ô `)@ô `-
Aˇ ģ
÷y˙˙˙y˙˙˙ū
@ö ` @ö `$
ϧ
A! &
ķu˙˙˙u˙˙˙ū
@ú `@ú `
Fragment_Fragment
A' 0
4ío˙˙˙o˙˙˙ū
@ú `@ú `(
Ab f
ék˙˙˙k˙˙˙ū
@ü `@ü `
AG L
åg˙˙˙g˙˙˙ū
@ `8@ `=
AÖ Ú
ác˙˙˙c˙˙˙ū
@ `*@ `.
A_! c!
Ũ_˙˙˙_˙˙˙ū
@ `*@ `.
A-" 1"
Ų[˙˙˙[˙˙˙ū
@ `*@ `.
A(# -#
ÕW˙˙˙W˙˙˙ū
@ `@ `
A$ $
ŅS˙˙˙S˙˙˙ū
@ `"@ `'
u˙˙˙v˙˙˙
AŖ$ §$
ÍO˙˙˙O˙˙˙ū
@ `*@ `.
|˙˙˙}˙˙˙
AY% ^%
ÉK˙˙˙K˙˙˙ū
@ `R@ `W
x˙˙˙y˙˙˙
A[&