Skip to content

Commit b9d50d0

Browse files
HarshHarsh
authored andcommitted
fix conflicts
2 parents feb6c90 + 87561a1 commit b9d50d0

File tree

8 files changed

+151
-58
lines changed

8 files changed

+151
-58
lines changed

Clients/src/presentation/components/Layout/PageHeaderExtended.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,9 @@ export function PageHeaderExtended({
8080
)}
8181
</Stack>
8282
)}
83-
{children}
83+
<Stack gap="16px" sx={{ mt: "16px" }}>
84+
{children}
85+
</Stack>
8486
</>
8587
)}
8688
</Stack>

Clients/src/presentation/components/UserGuide/WhatsNewSection.tsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,23 @@ interface ChangelogEntry {
1010
}
1111

1212
const CHANGELOG: ChangelogEntry[] = [
13+
{
14+
version: 'v2.2',
15+
date: 'April 2, 2026',
16+
title: 'AI Gateway, Policy Radar, and CI/CD scanning',
17+
summary:
18+
'Major release introducing the AI Gateway for centralized LLM traffic control with guardrails, spend tracking, and virtual keys. Adds Policy Radar for automated vendor policy monitoring, incremental AI detection scans, GitHub webhook CI/CD integration, super admin management, and intake form builder for use case registration.',
19+
items: [
20+
'AI Gateway — proxy all LLM traffic through a single control plane with spend dashboards, request/response logging, and per-endpoint analytics',
21+
'AI Gateway guardrails — PII detection (Presidio) and content filtering with block/mask actions on any endpoint',
22+
'AI Gateway virtual keys — scoped API keys with model/provider access controls and budget limits',
23+
'AI Gateway prompt library — save, version, and reuse prompt templates across endpoints',
24+
'Incremental AI detection scans — scan only changed files between two commits, carrying forward baseline findings',
25+
'GitHub webhook CI/CD integration — trigger AI detection scans automatically on push events with status reporting',
26+
'Super admin panel — manage organizations, users, and platform settings across all tenants',
27+
'Intake form builder — create custom use case registration forms with public submission links',
28+
],
29+
},
1330
{
1431
version: 'v2.1',
1532
date: 'February 19, 2026',

Clients/src/presentation/components/breadcrumbs/routeMapping.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import {
3636
Bot,
3737
Database,
3838
FileSearch,
39+
FolderGit2,
3940
Search,
4041
History,
4142
Eye,
@@ -124,6 +125,7 @@ export const routeMapping: Record<string, string> = {
124125
"/ai-detection/scan": "Scan repository",
125126
"/ai-detection/history": "Scan history",
126127
"/ai-detection/scans": "Scan history",
128+
"/ai-detection/repositories": "Repositories",
127129
"/ai-detection/settings": "Settings",
128130

129131
// AI Gateway
@@ -270,6 +272,7 @@ export const routeIconMapping: Record<string, () => React.ReactNode> = {
270272
"/ai-detection/scan": () => React.createElement(Search, { size: 14, strokeWidth: 1.5 }),
271273
"/ai-detection/history": () => React.createElement(History, { size: 14, strokeWidth: 1.5 }),
272274
"/ai-detection/scans": () => React.createElement(History, { size: 14, strokeWidth: 1.5 }),
275+
"/ai-detection/repositories": () => React.createElement(FolderGit2, { size: 14, strokeWidth: 1.5 }),
273276
"/ai-detection/settings": () => React.createElement(Settings, { size: 14, strokeWidth: 1.5 }),
274277

275278
// Intake forms

Clients/src/presentation/pages/AIDetection/AddRepositoryModal.tsx

Lines changed: 39 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -244,29 +244,34 @@ export default function AddRepositoryModal({
244244
placeholder="main"
245245
value={defaultBranch}
246246
onChange={(e) => setDefaultBranch(e.target.value)}
247-
sx={{ width: 160 }}
247+
sx={{ flex: 1 }}
248248
/>
249249
</Stack>
250250
</Stack>
251251

252252
{/* Schedule section */}
253253
<Stack spacing={4}>
254-
<Stack
255-
direction="row"
256-
alignItems="center"
257-
justifyContent="space-between"
258-
>
259-
<Typography
260-
variant="subtitle2"
261-
sx={{ fontWeight: 600, color: theme.palette.text.primary }}
254+
<Stack spacing={1}>
255+
<Stack
256+
direction="row"
257+
alignItems="center"
258+
spacing={4}
262259
>
263-
Scheduled scans
260+
<Toggle
261+
checked={scheduleEnabled}
262+
onChange={() => setScheduleEnabled(!scheduleEnabled)}
263+
size="small"
264+
/>
265+
<Typography
266+
variant="subtitle2"
267+
sx={{ fontWeight: 600, color: theme.palette.text.primary }}
268+
>
269+
Scheduled scans
270+
</Typography>
271+
</Stack>
272+
<Typography variant="caption" sx={{ color: theme.palette.text.secondary }}>
273+
Automatically scan this repository on a recurring schedule.
264274
</Typography>
265-
<Toggle
266-
checked={scheduleEnabled}
267-
onChange={() => setScheduleEnabled(!scheduleEnabled)}
268-
size="small"
269-
/>
270275
</Stack>
271276

272277
{scheduleEnabled && (
@@ -328,22 +333,27 @@ export default function AddRepositoryModal({
328333

329334
{/* CI/CD Integration section */}
330335
<Stack spacing={4}>
331-
<Stack
332-
direction="row"
333-
alignItems="center"
334-
justifyContent="space-between"
335-
>
336-
<Typography
337-
variant="subtitle2"
338-
sx={{ fontWeight: 600, color: theme.palette.text.primary }}
336+
<Stack spacing={1}>
337+
<Stack
338+
direction="row"
339+
alignItems="center"
340+
spacing={4}
339341
>
340-
CI/CD Integration
342+
<Toggle
343+
checked={ciEnabled}
344+
onChange={() => setCiEnabled(!ciEnabled)}
345+
size="small"
346+
/>
347+
<Typography
348+
variant="subtitle2"
349+
sx={{ fontWeight: 600, color: theme.palette.text.primary }}
350+
>
351+
CI/CD Integration
352+
</Typography>
353+
</Stack>
354+
<Typography variant="caption" sx={{ color: theme.palette.text.secondary }}>
355+
Run scans on pull requests and block merges that exceed risk thresholds.
341356
</Typography>
342-
<Toggle
343-
checked={ciEnabled}
344-
onChange={() => setCiEnabled(!ciEnabled)}
345-
size="small"
346-
/>
347357
</Stack>
348358

349359
{ciEnabled && (

Clients/src/presentation/pages/AIDetection/RepositoriesPage.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import EmptyStateTip from "../../components/EmptyState/EmptyStateTip";
3232
import TablePaginationActions from "../../components/TablePagination";
3333
import ConfirmationModal from "../../components/Dialogs/ConfirmationModal";
3434
import { PageHeaderExtended } from "../../components/Layout/PageHeaderExtended";
35-
import { Play, Pencil, Trash2, Loader2, GitBranch, Shield, RefreshCw } from "lucide-react";
35+
import { Play, Pencil, Trash2, Loader2, GitBranch, GitFork, Shield, RefreshCw } from "lucide-react";
3636
import axios from "axios";
3737
import {
3838
getRepositories,
@@ -422,7 +422,7 @@ export default function RepositoriesPage() {
422422
message="No repositories added yet. Add a repository to start detecting AI components."
423423
>
424424
<EmptyStateTip
425-
icon={GitBranch}
425+
icon={GitFork}
426426
title="Connect your GitHub repositories"
427427
description="Paste a GitHub repository URL and the system will scan its codebase for AI/ML libraries, model files, and inference endpoints."
428428
/>

Clients/src/presentation/pages/AIDetection/ScanPage.tsx

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import {
1919
} from "@mui/material";
2020
import {
2121
Search,
22-
GitBranch as GithubIcon,
22+
GitFork,
2323
AlertCircle,
2424
CheckCircle2,
2525
XCircle,
@@ -310,8 +310,8 @@ export default function ScanPage() {
310310
}
311311
>
312312

313-
{/* Statistics Cards - 6 cards in 3x2 grid (only show if there are scans) */}
314-
{!isCheckingActive && scanState === "idle" && !statsLoading && stats && stats.total_scans > 0 && (
313+
{/* Statistics Cards - 6 cards in 3x2 grid */}
314+
{!isCheckingActive && scanState === "idle" && !statsLoading && stats && (
315315
<Box
316316
sx={{
317317
display: "grid",
@@ -397,10 +397,7 @@ export default function ScanPage() {
397397
{!isCheckingActive && scanState === "idle" && (
398398
<Box
399399
sx={{
400-
backgroundColor: palette.background.main,
401-
border: `1px solid ${palette.border.dark}`,
402-
borderRadius: "4px",
403-
p: 2,
400+
pt: "16px",
404401
}}
405402
>
406403
{/* Repository URL section */}
@@ -452,11 +449,11 @@ export default function ScanPage() {
452449
InputProps={{
453450
startAdornment: (
454451
<InputAdornment position="start">
455-
<GithubIcon size={16} color={palette.text.tertiary} />
452+
<GitFork size={16} color={palette.text.tertiary} />
456453
</InputAdornment>
457454
),
458455
}}
459-
sx={{ mb: 0 }}
456+
sx={{ mb: 0, maxWidth: "480px" }}
460457
/>
461458
</Box>
462459

Clients/src/presentation/pages/AIDetection/SettingsPage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ export default function SettingsPage() {
293293
{
294294
label: "GitHub integration",
295295
value: "github",
296-
icon: "GitBranch",
296+
icon: "GitFork",
297297
tooltip: "Connect a GitHub token to scan private repositories",
298298
},
299299
{

Clients/src/presentation/pages/AIGateway/Logs/index.tsx

Lines changed: 80 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ import { sectionTitleSx, useCardSx, formatEntityType } from "../shared";
3838

3939
const AUTO_REFRESH_INTERVAL_MS = 10_000;
4040
const SEARCH_DEBOUNCE_MS = 300;
41-
const GR_PAGE_SIZE = 50;
41+
const GR_DEFAULT_PAGE_SIZE = 25;
4242

4343
type StatusFilter = "all" | "success" | "error";
4444
type SourceFilter = "all" | "playground" | "virtual-key";
@@ -162,12 +162,15 @@ export default function LogsPage() {
162162
const [grLogs, setGrLogs] = useState<any[]>([]);
163163
const [grTotal, setGrTotal] = useState(0);
164164
const [grPage, setGrPage] = useState(0);
165+
const [grRowsPerPage, setGrRowsPerPage] = useState(() =>
166+
getPaginationRowCount("aiGatewayGuardrailLogs", GR_DEFAULT_PAGE_SIZE)
167+
);
165168
const [grLoading, setGrLoading] = useState(false);
166169

167170
const loadGuardrailLogs = useCallback(async () => {
168171
setGrLoading(true);
169172
try {
170-
const res = await apiServices.get<Record<string, any>>(`/ai-gateway/guardrails/logs?limit=${GR_PAGE_SIZE}&offset=${grPage * GR_PAGE_SIZE}`);
173+
const res = await apiServices.get<Record<string, any>>(`/ai-gateway/guardrails/logs?limit=${grRowsPerPage}&offset=${grPage * grRowsPerPage}`);
171174
const data = res?.data || {};
172175
setGrLogs(data.logs || data?.data?.logs || []);
173176
setGrTotal(data.total || data.logs?.length || 0);
@@ -176,7 +179,7 @@ export default function LogsPage() {
176179
} finally {
177180
setGrLoading(false);
178181
}
179-
}, [grPage]);
182+
}, [grPage, grRowsPerPage]);
180183

181184
useEffect(() => {
182185
if (activeLogTab === "guardrails") loadGuardrailLogs();
@@ -308,9 +311,9 @@ export default function LogsPage() {
308311
</Typography>
309312
</Stack>
310313
<CustomizableButton
311-
text={loading ? "Loading..." : "Refresh"}
314+
text={(activeLogTab === "requests" ? loading : grLoading) ? "Loading..." : "Refresh"}
312315
icon={<RefreshCw size={14} strokeWidth={1.5} />}
313-
onClick={() => loadLogs(page, rowsPerPage)}
316+
onClick={() => activeLogTab === "requests" ? loadLogs(page, rowsPerPage) : loadGuardrailLogs()}
314317
/>
315318
</Stack>
316319
}
@@ -776,17 +779,78 @@ export default function LogsPage() {
776779
))}
777780

778781
{/* Pagination */}
779-
{grTotal > GR_PAGE_SIZE && (
780-
<Stack direction="row" justifyContent="space-between" alignItems="center" sx={{ pt: "12px" }}>
781-
<Typography sx={{ fontSize: 12, color: palette.text.tertiary }}>
782-
Page {grPage + 1} of {Math.ceil(grTotal / GR_PAGE_SIZE)} ({grTotal} total)
783-
</Typography>
784-
<Stack direction="row" gap="8px">
785-
<CustomizableButton text="Previous" variant="outlined" onClick={() => setGrPage(Math.max(0, grPage - 1))} isDisabled={grPage === 0} />
786-
<CustomizableButton text="Next" variant="outlined" onClick={() => setGrPage(grPage + 1)} isDisabled={(grPage + 1) * GR_PAGE_SIZE >= grTotal} />
787-
</Stack>
788-
</Stack>
789-
)}
782+
<Table>
783+
<TableBody>
784+
<TableRow>
785+
<TablePagination
786+
count={grTotal}
787+
page={grPage}
788+
onPageChange={(_, newPage) => setGrPage(newPage)}
789+
rowsPerPage={grRowsPerPage}
790+
rowsPerPageOptions={[10, 25, 50]}
791+
onRowsPerPageChange={(e) => {
792+
const rpp = parseInt(e.target.value, 10);
793+
setGrRowsPerPage(rpp);
794+
setGrPage(0);
795+
setPaginationRowCount("aiGatewayGuardrailLogs", rpp);
796+
}}
797+
ActionsComponent={(props) => <TablePaginationActions {...props} />}
798+
labelRowsPerPage="Rows per page"
799+
labelDisplayedRows={({ page, count }) =>
800+
`Page ${page + 1} of ${Math.max(1, Math.ceil(count / grRowsPerPage))}`
801+
}
802+
slotProps={{
803+
select: {
804+
MenuProps: {
805+
keepMounted: true,
806+
PaperProps: {
807+
className: "pagination-dropdown",
808+
sx: { mt: 0, mb: theme.spacing(2) },
809+
},
810+
transformOrigin: { vertical: "bottom", horizontal: "left" },
811+
anchorOrigin: { vertical: "top", horizontal: "left" },
812+
sx: { mt: theme.spacing(-2) },
813+
},
814+
inputProps: { id: "gr-pagination-dropdown" },
815+
IconComponent: () => <ChevronsUpDown size={16} />,
816+
sx: {
817+
ml: theme.spacing(4),
818+
mr: theme.spacing(12),
819+
minWidth: theme.spacing(20),
820+
textAlign: "left",
821+
"&.Mui-focused > div": {
822+
backgroundColor: theme.palette.background.main,
823+
},
824+
},
825+
},
826+
}}
827+
sx={{
828+
backgroundColor: theme.palette.grey[50],
829+
border: `1px solid ${theme.palette.border.light}`,
830+
borderTop: "none",
831+
borderRadius: `0 0 ${theme.shape.borderRadius}px ${theme.shape.borderRadius}px`,
832+
color: theme.palette.text.secondary,
833+
height: "50px",
834+
minHeight: "50px",
835+
"& .MuiTablePagination-toolbar": {
836+
minHeight: "50px",
837+
paddingTop: "4px",
838+
paddingBottom: "4px",
839+
},
840+
"& .MuiSelect-icon": {
841+
width: "24px",
842+
height: "fit-content",
843+
},
844+
"& .MuiSelect-select": {
845+
width: theme.spacing(10),
846+
borderRadius: theme.shape.borderRadius,
847+
border: `1px solid ${theme.palette.border.light}`,
848+
},
849+
}}
850+
/>
851+
</TableRow>
852+
</TableBody>
853+
</Table>
790854
</Stack>
791855
)}
792856
</Stack>

0 commit comments

Comments
 (0)