export team incidents
This commit is contained in:
1 parent
36208aacea
commit
e12e198aed
4 files changed
+88
-9
No files matched your search
@@ -14,20 +14,19 @@ const ExportPage = () => {
|
||||
const { get, loading } = useGetOnDemand();
|
||||
const { post, loading: isPosting } = usePost();
|
||||
|
||||
const handleExport = async () => {
|
||||
const res = await get("/monitors/export");
|
||||
if (!res?.data) {
|
||||
return;
|
||||
}
|
||||
const exportJson = async (endpoint: string, filename: string) => {
|
||||
const res = await get(endpoint);
|
||||
const data = (res as any)?.data ?? (res as any);
|
||||
if (!data) return;
|
||||
|
||||
const blob = new Blob([JSON.stringify(res.data, null, 2)], {
|
||||
const blob = new Blob([JSON.stringify(data, null, 2)], {
|
||||
type: "application/json",
|
||||
});
|
||||
const url = URL.createObjectURL(blob);
|
||||
|
||||
const link = document.createElement("a");
|
||||
link.href = url;
|
||||
link.download = "monitors.json";
|
||||
link.download = `${filename}-${Date.now()}.json`;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
@@ -63,6 +62,8 @@ const ExportPage = () => {
|
||||
input.click();
|
||||
};
|
||||
|
||||
// Removed wrapper handlers; call exportJson directly from onClick
|
||||
|
||||
return (
|
||||
<BasePage>
|
||||
<ConfigBox
|
||||
@@ -76,7 +77,7 @@ const ExportPage = () => {
|
||||
loading={loading}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={handleExport}
|
||||
onClick={() => exportJson("/monitors/export", "monitors")}
|
||||
>
|
||||
Export to JSON
|
||||
</Button>
|
||||
@@ -145,6 +146,26 @@ const ExportPage = () => {
|
||||
</Stack>
|
||||
}
|
||||
/>
|
||||
|
||||
<ConfigBox
|
||||
title="Export incidents"
|
||||
subtitle="Export current team's incidents as JSON"
|
||||
rightContent={
|
||||
<Stack gap={theme.spacing(4)}>
|
||||
<Typography>Click here to export your incidents to JSON</Typography>
|
||||
<Box>
|
||||
<Button
|
||||
loading={loading}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={() => exportJson("/incidents/export", "incidents")}
|
||||
>
|
||||
Export to JSON
|
||||
</Button>
|
||||
</Box>
|
||||
</Stack>
|
||||
}
|
||||
/>
|
||||
</BasePage>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -12,6 +12,7 @@ export interface IIncidentsController {
|
||||
getIncidents: (req: Request, res: Response, next: NextFunction) => void;
|
||||
getIncidentById: (req: Request, res: Response, next: NextFunction) => void;
|
||||
resolveIncident: (req: Request, res: Response, next: NextFunction) => void;
|
||||
exportIncidents: (req: Request, res: Response, next: NextFunction) => void;
|
||||
}
|
||||
|
||||
class IncidentsController implements IIncidentsController {
|
||||
@@ -136,6 +137,26 @@ class IncidentsController implements IIncidentsController {
|
||||
next(error);
|
||||
}
|
||||
};
|
||||
|
||||
exportIncidents = async (req: Request, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
const userContext = req.user;
|
||||
if (!userContext) {
|
||||
return res.status(401).json({ message: "Unauthorized" });
|
||||
}
|
||||
|
||||
const teamId = userContext.currentTeamId;
|
||||
if (!teamId) {
|
||||
throw new ApiError("No team ID", 400);
|
||||
}
|
||||
|
||||
const incidents = await this.incidentService.export(teamId);
|
||||
|
||||
return res.status(200).json({ message: "OK", data: incidents });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default IncidentsController;
|
||||
@@ -4,7 +4,10 @@ import { IncidentsController } from "@/controllers/index.js";
|
||||
import { verifyToken } from "@/middleware/VerifyToken.js";
|
||||
import { addUserContext } from "@/middleware/AddUserContext.js";
|
||||
import { validateQuery, validateBody } from "@/middleware/validation.js";
|
||||
import { verifyOrgPermission } from "@/middleware/VerifyPermission.js";
|
||||
import {
|
||||
verifyOrgPermission,
|
||||
verifyTeamPermission,
|
||||
} from "@/middleware/VerifyPermission.js";
|
||||
import { PERMISSIONS } from "@/types/permissions.js";
|
||||
import {
|
||||
getIncidentsQuerySchema,
|
||||
@@ -30,6 +33,14 @@ class IncidentsRoutes {
|
||||
validateQuery(getIncidentsQuerySchema),
|
||||
this.controller.getIncidents
|
||||
);
|
||||
this.router.get(
|
||||
"/export",
|
||||
verifyToken,
|
||||
addUserContext,
|
||||
verifyTeamPermission([PERMISSIONS.incidents.read]),
|
||||
this.controller.exportIncidents
|
||||
);
|
||||
|
||||
this.router.get(
|
||||
"/:id",
|
||||
verifyToken,
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
IMonitor,
|
||||
Monitor,
|
||||
ICheck,
|
||||
IUser,
|
||||
} from "@/db/models/index.js";
|
||||
import type { ResolutionType } from "@/db/models/index.js";
|
||||
import mongoose from "mongoose";
|
||||
@@ -11,6 +12,11 @@ import { getChildLogger } from "@/logger/Logger.js";
|
||||
import ApiError from "@/utils/ApiError.js";
|
||||
import { ThresholdEvaluationResult } from "@/services/infrastructure/StatusService.js";
|
||||
|
||||
type IncidentPopulated = Omit<IIncident, "monitorId" | "resolvedBy"> & {
|
||||
monitorId: IMonitor;
|
||||
resolvedBy?: IUser | null;
|
||||
};
|
||||
|
||||
export interface IIncidentService {
|
||||
handleStatusChange: (
|
||||
updatedMonitor: IMonitor,
|
||||
@@ -48,6 +54,7 @@ export interface IIncidentService {
|
||||
teamId: mongoose.Types.ObjectId,
|
||||
incidentId: mongoose.Types.ObjectId
|
||||
) => Promise<boolean>;
|
||||
export: (teamId: string) => Promise<Array<Record<string, unknown>>>;
|
||||
cleanupOrphanedIncidents: () => Promise<boolean>;
|
||||
}
|
||||
|
||||
@@ -267,6 +274,25 @@ class IncidentService implements IIncidentService {
|
||||
return result.deletedCount === 1;
|
||||
};
|
||||
|
||||
export = async (teamId: string) => {
|
||||
const incidents = await Incident.find({
|
||||
teamId,
|
||||
})
|
||||
.populate("monitorId")
|
||||
.populate("resolvedBy")
|
||||
.lean<IncidentPopulated[]>();
|
||||
|
||||
return incidents.map((incident) => ({
|
||||
monitor: incident.monitorId?.name ?? "",
|
||||
monitorId: incident.monitorId?._id?.toString?.() ?? "",
|
||||
resolved: incident.resolved,
|
||||
resolutionType: incident.resolutionType ?? "Unresolved",
|
||||
startedAt: incident.startedAt,
|
||||
endedAt: incident.endedAt ?? "Ongoing",
|
||||
resolvedBy: incident.resolvedBy ? incident.resolvedBy.email ?? "" : "",
|
||||
}));
|
||||
};
|
||||
|
||||
async cleanupOrphanedIncidents() {
|
||||
try {
|
||||
const monitorIds = await Monitor.find().distinct("_id");
|
||||
|
||||
Reference in new issue
Block a user