Skip to content

stripe #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions apps/dashboard/src/api/endpoints/incidents/incidents.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import client from "../../client";

/*
Shared
*/

export interface Incident {
id: string;
teamId: number;
monitorId: number;
title: string;
description: string;
createdAt: string;
}

/*
Get Team Incidents
*/

export interface GetIncidentsResponse {
incidents: Incident[];
}

export async function getIncidents(
teamId: number,
offset?: number,
limit?: number,
): Promise<GetIncidentsResponse> {
const response = await client.get(`/v1/teams/${teamId}/incidents`,
{
params: {
offset,
limit,
},
},
);

return response?.data;
}
1 change: 1 addition & 0 deletions apps/dashboard/src/api/endpoints/incidents/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./incidents";
31 changes: 31 additions & 0 deletions apps/dashboard/src/api/endpoints/monitors/checks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,37 @@ export async function getMonitorChecks(
return response?.data;
}

export interface GetMonitorsIncidentsResponse {
monitors: MonitorsWithIncidents[];
}

export interface MonitorsWithIncidents {
id: number;
teamId: number;
state: string;
name: string;
createdAt: string;
updatedAt: string;
incidents: Incident[];
}
export interface Incident {
id: number;
createdAt: string;
updatedAt: string;
MonitorAssertionID: number;
}


export async function getMonitorsIncidents(
teamId: number,
): Promise<GetMonitorsIncidentsResponse> {
const response = await client.get(
`/v1/teams/${teamId}/monitors/incidents`,
);

return response?.data;
}

/*
Get Monitor Check
*/
Expand Down
25 changes: 25 additions & 0 deletions apps/dashboard/src/hooks/incidents.query.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { useMutation, useQuery } from "@tanstack/react-query";
import * as IncidentsAPI from "../api/endpoints/incidents";
import useAuthenticationStore from "./authentication.store";
import { getQueryClient } from "./client.query";

const queryClient = getQueryClient();


export const useIncidents = (offset = 0, limit = 5) => {
const teamId = useAuthenticationStore((state) => state.currentTeamId);

return useQuery(["team", teamId, "checks",
{
offset,
limit,
},
], () => {
if (!teamId) {
return Promise.resolve(null);
}

return IncidentsAPI.getIncidents(teamId, offset, limit);
});
};

13 changes: 13 additions & 0 deletions apps/dashboard/src/hooks/monitors.query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,19 @@ export const useMonitorChecks = (monitorId?: number, offset = 0, limit = 5) => {
);
};

export const useMonitorsIncidents = () => {
const teamId = useAuthenticationStore((state) => state.currentTeamId);

return useQuery(["teams", teamId, "monitors", "incidents"], () => {
if (!teamId) {
return Promise.resolve(null);
}

return MonitorsAPI.getMonitorsIncidents(teamId);
});
}


export const useLatestMonitorCheck = (monitorId?: number) => {
const teamId = useAuthenticationStore((state) => state.currentTeamId);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import {
Box,
Button,
Card,
Chip,
Grid,
Stack,
Tooltip,
Typography,
} from "@mui/material";
import { FunctionComponent } from "react";
import { IoOpenOutline, IoStatsChart } from "react-icons/io5";
import { useNavigate } from "react-router-dom";
import { MonitorsWithIncidents } from "../../../../../src/api/endpoints/monitors";

interface MonitorIncidentPageOverviewListProps {
monitors?: MonitorsWithIncidents[];
}

const IncidentPageOverviewList: FunctionComponent<
MonitorIncidentPageOverviewListProps
> = ({
monitors
}) => {
return (
<Stack spacing={2}>
{monitors?.map((monitor) => (
<OverviewListItem monitor={monitor} />
))}
</Stack>
);
};

interface OverviewListItemProps {
monitor: MonitorsWithIncidents;
}

const OverviewListItem: FunctionComponent<OverviewListItemProps> = (
{
monitor,
}
) => {
const navigate = useNavigate();

return (
<Stack direction="row" spacing={0.5}>
<Card
component={Button}
sx={{
display: "block",
textAlign: "left",
padding: 0,
flex: 1,
}}
>
<Stack direction="row">
<Grid
container
alignItems="center"
p={2}
columns={{ xs: 1, md: 2 }}
justifyContent="space-between"
gap={{ xs: 2, md: 4 }}
onClick={() => navigate("/status-pages/1")}
>
<Grid item>
<Stack spacing={1}>
<Typography variant="body2">{monitor.name}</Typography>

<Stack direction="row" spacing={1}>
<Chip size="small" label="api" color="info" />
<Chip size="small" label="login" color="info" />
<Chip size="small" label="monitors" color="info" />
<Chip size="small" label="foo" color="info" />
<Chip size="small" label="bar" color="info" />
</Stack>
</Stack>
</Grid>

<Grid
item
direction="row"
display="flex"
justifyContent="flex-end"
alignItems="center"
gap={2}
>
<Stack textAlign={{ xs: "left", md: "right" }}>
<Typography variant="body2" color="text.secondary">
{monitor.incidents.length} active incidents
</Typography>
</Stack>

<Box sx={{ display: { xs: "none", md: "block" } }}>
<IoStatsChart size={38} />
</Box>
</Grid>
</Grid>
</Stack>
</Card>

<Tooltip title="Open in a new tab">
<Card component={Button} color="primary">
<IoOpenOutline size={18} />
</Card>
</Tooltip>
</Stack>
);
};

export default IncidentPageOverviewList;
17 changes: 16 additions & 1 deletion apps/dashboard/src/pages/Dashboard/Incidents/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,20 @@ import { FunctionComponent } from "react";
import { Helmet } from "react-helmet";
import Container from "../../../components/Container";
import Placeholder from "../../../components/Placeholder";
import IncidentOverviewList from "./components/OverviewList";
// import { useIncidents } from "../../../hooks/incidents.query";
import { useMonitorsIncidents } from "../../../hooks/monitors.query";



const IncidentsView: FunctionComponent = () => {

// Get incidents
const {
data: monitorsIncidents,
error: incidentsError,
isLoading: incidentsAreLoading,
} = useMonitorsIncidents();
return (
<>
<Helmet>
Expand All @@ -14,7 +26,10 @@ const IncidentsView: FunctionComponent = () => {
header="Incidents"
description="An overview active and resolved incidents across your infrastructure."
>
<Placeholder />
{incidentsAreLoading ? (<Placeholder />) :
( <IncidentOverviewList monitors={monitorsIncidents?.monitors} />)
}

</Container>
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const AverageResponseTimeCard: FunctionComponent<
return (
<Card sx={{ flex: 1 }}>
<CardContent>
<Typography sx={{ opacity: 0.5 }}>Average response time</Typography>
<Typography sx={{ opacity: 0.5 }}>Average response time (24-hour)</Typography>

<Conditional value={isLoading}>
<Skeleton variant="text" width={100} height={28} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const UptimeCard: FunctionComponent<UptimeCardProps> = ({ monitorId }) => {
return (
<Card sx={{ flex: 1 }}>
<CardContent>
<Typography sx={{ opacity: 0.5 }}>Uptime</Typography>
<Typography sx={{ opacity: 0.5 }}>Uptime (24-hour)</Typography>
<Conditional value={isLoading}>
<Skeleton variant="text" width={100} height={28} />
</Conditional>
Expand Down
Loading