Skip to content

Commit f9333f1

Browse files
committed
feat(site): add connection log page
1 parent 33d8acb commit f9333f1

23 files changed

+1371
-41
lines changed

site/src/api/api.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1802,6 +1802,14 @@ class ApiMethods {
18021802
return response.data;
18031803
};
18041804

1805+
getConnectionLogs = async (
1806+
options: TypesGen.ConnectionLogsRequest,
1807+
): Promise<TypesGen.ConnectionLogResponse> => {
1808+
const url = getURLWithSearchParams("/api/v2/connectionlogs", options);
1809+
const response = await this.axios.get(url);
1810+
return response.data;
1811+
};
1812+
18051813
getTemplateDAUs = async (
18061814
templateId: string,
18071815
): Promise<TypesGen.DAUsResponse> => {

site/src/api/queries/connectionlog.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { API } from "api/api";
2+
import type { ConnectionLogResponse } from "api/typesGenerated";
3+
import { useFilterParamsKey } from "components/Filter/Filter";
4+
import type { UsePaginatedQueryOptions } from "hooks/usePaginatedQuery";
5+
6+
export function paginatedConnectionLogs(
7+
searchParams: URLSearchParams,
8+
): UsePaginatedQueryOptions<ConnectionLogResponse, string> {
9+
return {
10+
searchParams,
11+
queryPayload: () => searchParams.get(useFilterParamsKey) ?? "",
12+
queryKey: ({ payload, pageNumber }) => {
13+
return ["connectionLogs", payload, pageNumber] as const;
14+
},
15+
queryFn: ({ payload, limit, offset }) => {
16+
return API.getConnectionLogs({
17+
offset,
18+
limit,
19+
q: payload,
20+
});
21+
},
22+
prefetch: false,
23+
};
24+
}

site/src/components/Filter/UserFilter.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,14 +82,15 @@ export type UserFilterMenu = ReturnType<typeof useUserFilterMenu>;
8282

8383
interface UserMenuProps {
8484
menu: UserFilterMenu;
85+
placeholder?: string;
8586
width?: number;
8687
}
8788

88-
export const UserMenu: FC<UserMenuProps> = ({ menu, width }) => {
89+
export const UserMenu: FC<UserMenuProps> = ({ menu, width, placeholder }) => {
8990
return (
9091
<SelectFilter
9192
label="Select user"
92-
placeholder="All users"
93+
placeholder={placeholder ?? "All users"}
9394
emptyText="No users found"
9495
options={menu.searchOptions}
9596
onSelect={menu.selectOption}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { Pill } from "components/Pill/Pill";
2+
import {
3+
Tooltip,
4+
TooltipContent,
5+
TooltipProvider,
6+
TooltipTrigger,
7+
} from "components/Tooltip/Tooltip";
8+
import type { FC } from "react";
9+
import { httpStatusColor } from "utils/http";
10+
11+
interface StatusPillProps {
12+
code: number;
13+
isHttpCode: boolean;
14+
label?: string;
15+
}
16+
17+
export const StatusPill: FC<StatusPillProps> = ({ code, isHttpCode, label }) => {
18+
const pill = (
19+
<Pill
20+
className="text-[10px] h-5 px-2.5 font-semibold"
21+
type={isHttpCode ? httpStatusColor(code) : code === 0 ? "success" : "error"}
22+
>
23+
{code.toString()}
24+
</Pill>
25+
);
26+
if (!label) {
27+
return pill;
28+
}
29+
return (
30+
<TooltipProvider>
31+
<Tooltip delayDuration={150}>
32+
<TooltipTrigger asChild>{pill}</TooltipTrigger>
33+
<TooltipContent>{label}</TooltipContent>
34+
</Tooltip>
35+
</TooltipProvider>
36+
);
37+
};

site/src/modules/dashboard/Navbar/DeploymentDropdown.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,22 @@ interface DeploymentDropdownProps {
1616
canViewDeployment: boolean;
1717
canViewOrganizations: boolean;
1818
canViewAuditLog: boolean;
19+
canViewConnectionLog: boolean;
1920
canViewHealth: boolean;
2021
}
2122

2223
export const DeploymentDropdown: FC<DeploymentDropdownProps> = ({
2324
canViewDeployment,
2425
canViewOrganizations,
2526
canViewAuditLog,
27+
canViewConnectionLog,
2628
canViewHealth,
2729
}) => {
2830
const theme = useTheme();
2931

3032
if (
3133
!canViewAuditLog &&
34+
!canViewConnectionLog &&
3235
!canViewOrganizations &&
3336
!canViewDeployment &&
3437
!canViewHealth
@@ -59,6 +62,7 @@ export const DeploymentDropdown: FC<DeploymentDropdownProps> = ({
5962
canViewDeployment={canViewDeployment}
6063
canViewOrganizations={canViewOrganizations}
6164
canViewAuditLog={canViewAuditLog}
65+
canViewConnectionLog={canViewConnectionLog}
6266
canViewHealth={canViewHealth}
6367
/>
6468
</PopoverContent>
@@ -71,6 +75,7 @@ const DeploymentDropdownContent: FC<DeploymentDropdownProps> = ({
7175
canViewOrganizations,
7276
canViewAuditLog,
7377
canViewHealth,
78+
canViewConnectionLog,
7479
}) => {
7580
const popover = usePopover();
7681

@@ -108,6 +113,16 @@ const DeploymentDropdownContent: FC<DeploymentDropdownProps> = ({
108113
Audit Logs
109114
</MenuItem>
110115
)}
116+
{canViewConnectionLog && (
117+
<MenuItem
118+
component={NavLink}
119+
to="/connectionlog"
120+
css={styles.menuItem}
121+
onClick={onPopoverClose}
122+
>
123+
Connection Logs
124+
</MenuItem>
125+
)}
111126
{canViewHealth && (
112127
<MenuItem
113128
component={NavLink}

site/src/modules/dashboard/Navbar/Navbar.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ export const Navbar: FC = () => {
2222
const canViewHealth = permissions.viewDebugInfo;
2323
const canViewAuditLog =
2424
featureVisibility.audit_log && permissions.viewAnyAuditLog;
25+
const canViewConnectionLog =
26+
featureVisibility.connection_log && permissions.viewAnyConnectionLog;
2527

2628
return (
2729
<NavbarView
@@ -34,6 +36,7 @@ export const Navbar: FC = () => {
3436
canViewOrganizations={canViewOrganizations}
3537
canViewHealth={canViewHealth}
3638
canViewAuditLog={canViewAuditLog}
39+
canViewConnectionLog={canViewConnectionLog}
3740
proxyContextValue={proxyContextValue}
3841
/>
3942
);

site/src/modules/dashboard/Navbar/NavbarView.test.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ describe("NavbarView", () => {
3333
canViewOrganizations
3434
canViewHealth
3535
canViewAuditLog
36+
canViewConnectionLog
3637
/>,
3738
);
3839
const workspacesLink =
@@ -50,6 +51,7 @@ describe("NavbarView", () => {
5051
canViewOrganizations
5152
canViewHealth
5253
canViewAuditLog
54+
canViewConnectionLog
5355
/>,
5456
);
5557
const templatesLink =
@@ -67,6 +69,7 @@ describe("NavbarView", () => {
6769
canViewOrganizations
6870
canViewHealth
6971
canViewAuditLog
72+
canViewConnectionLog
7073
/>,
7174
);
7275
const deploymentMenu = await screen.findByText("Admin settings");
@@ -85,6 +88,7 @@ describe("NavbarView", () => {
8588
canViewOrganizations
8689
canViewHealth
8790
canViewAuditLog
91+
canViewConnectionLog
8892
/>,
8993
);
9094
const deploymentMenu = await screen.findByText("Admin settings");

site/src/modules/dashboard/Navbar/NavbarView.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ interface NavbarViewProps {
2424
canViewDeployment: boolean;
2525
canViewOrganizations: boolean;
2626
canViewAuditLog: boolean;
27+
canViewConnectionLog: boolean;
2728
canViewHealth: boolean;
2829
proxyContextValue?: ProxyContextValue;
2930
}
@@ -44,6 +45,7 @@ export const NavbarView: FC<NavbarViewProps> = ({
4445
canViewOrganizations,
4546
canViewHealth,
4647
canViewAuditLog,
48+
canViewConnectionLog,
4749
proxyContextValue,
4850
}) => {
4951
const webPush = useWebpushNotifications();
@@ -73,6 +75,7 @@ export const NavbarView: FC<NavbarViewProps> = ({
7375
canViewOrganizations={canViewOrganizations}
7476
canViewDeployment={canViewDeployment}
7577
canViewHealth={canViewHealth}
78+
canViewConnectionLog={canViewConnectionLog}
7679
/>
7780
</div>
7881

site/src/modules/permissions/index.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,13 @@ export const permissionChecks = {
156156
},
157157
action: "read",
158158
},
159+
viewAnyConnectionLog: {
160+
object: {
161+
resource_type: "connection_log",
162+
any_org: true,
163+
},
164+
action: "read",
165+
},
159166
viewDebugInfo: {
160167
object: {
161168
resource_type: "debug_info",

site/src/pages/AuditPage/AuditLogRow/AuditLogRow.tsx

Lines changed: 2 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,13 @@ import Tooltip from "@mui/material/Tooltip";
66
import type { AuditLog } from "api/typesGenerated";
77
import { Avatar } from "components/Avatar/Avatar";
88
import { DropdownArrow } from "components/DropdownArrow/DropdownArrow";
9-
import { Pill } from "components/Pill/Pill";
109
import { Stack } from "components/Stack/Stack";
10+
import { StatusPill } from "components/StatusPill/StatusPill";
1111
import { TimelineEntry } from "components/Timeline/TimelineEntry";
1212
import { InfoIcon } from "lucide-react";
1313
import { NetworkIcon } from "lucide-react";
1414
import { type FC, useState } from "react";
1515
import { Link as RouterLink } from "react-router-dom";
16-
import type { ThemeRole } from "theme/roles";
1716
import userAgentParser from "ua-parser-js";
1817
import { AuditLogDescription } from "./AuditLogDescription/AuditLogDescription";
1918
import { AuditLogDiff } from "./AuditLogDiff/AuditLogDiff";
@@ -22,21 +21,6 @@ import {
2221
determineIdPSyncMappingDiff,
2322
} from "./AuditLogDiff/auditUtils";
2423

25-
const httpStatusColor = (httpStatus: number): ThemeRole => {
26-
// Treat server errors (500) as errors
27-
if (httpStatus >= 500) {
28-
return "error";
29-
}
30-
31-
// Treat client errors (400) as warnings
32-
if (httpStatus >= 400) {
33-
return "warning";
34-
}
35-
36-
// OK (200) and redirects (300) are successful
37-
return "success";
38-
};
39-
4024
interface AuditLogRowProps {
4125
auditLog: AuditLog;
4226
// Useful for Storybook
@@ -139,7 +123,7 @@ export const AuditLogRow: FC<AuditLogRowProps> = ({
139123
</Stack>
140124

141125
<Stack direction="row" alignItems="center">
142-
<StatusPill code={auditLog.status_code} />
126+
<StatusPill isHttpCode={true} code={auditLog.status_code} />
143127

144128
{/* With multi-org, there is not enough space so show
145129
everything in a tooltip. */}
@@ -243,19 +227,6 @@ export const AuditLogRow: FC<AuditLogRowProps> = ({
243227
);
244228
};
245229

246-
function StatusPill({ code }: { code: number }) {
247-
const isHttp = code >= 100;
248-
249-
return (
250-
<Pill
251-
css={styles.statusCodePill}
252-
type={isHttp ? httpStatusColor(code) : code === 0 ? "success" : "error"}
253-
>
254-
{code.toString()}
255-
</Pill>
256-
);
257-
}
258-
259230
const styles = {
260231
auditLogCell: {
261232
padding: "0 !important",
@@ -311,14 +282,6 @@ const styles = {
311282
width: "100%",
312283
},
313284

314-
statusCodePill: {
315-
fontSize: 10,
316-
height: 20,
317-
paddingLeft: 10,
318-
paddingRight: 10,
319-
fontWeight: 600,
320-
},
321-
322285
deletedLabel: (theme) => ({
323286
...(theme.typography.caption as CSSObject),
324287
color: theme.palette.text.secondary,

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy