Addition of export.
This commit is contained in:
1 parent
36d8e8c0cf
commit
e9e509ab04
6 files changed
+102
-11
No files matched your search
@@ -3,11 +3,13 @@ import { useNavigate } from "react-router-dom";
|
||||
import PropTypes from "prop-types";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import { useExportMonitors } from "../../Hooks/monitorHooks";
|
||||
|
||||
const CreateMonitorHeader = ({ isAdmin, label, isLoading = true, path, bulkPath }) => {
|
||||
const navigate = useNavigate();
|
||||
const { t } = useTranslation();
|
||||
const theme = useTheme();
|
||||
const [exportMonitors, isExporting] = useExportMonitors()
|
||||
|
||||
// Use the provided label or fall back to the translated default
|
||||
|
||||
@@ -29,16 +31,27 @@ const CreateMonitorHeader = ({ isAdmin, label, isLoading = true, path, bulkPath
|
||||
{label || t("createNew")}
|
||||
</Button>
|
||||
{bulkPath && (
|
||||
<Button
|
||||
loading={isLoading}
|
||||
variant="contained"
|
||||
color="accent"
|
||||
onClick={() => {
|
||||
navigate(`${bulkPath}`);
|
||||
}}
|
||||
>
|
||||
{t("bulkImport.title")}
|
||||
</Button>
|
||||
<>
|
||||
<Button
|
||||
loading={isLoading}
|
||||
variant="contained"
|
||||
color="accent"
|
||||
onClick={() => {
|
||||
navigate(`${bulkPath}`);
|
||||
}}
|
||||
>
|
||||
{t("bulkImport.title")}
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
loading={isExporting}
|
||||
variant="contained"
|
||||
color="accent"
|
||||
onClick={exportMonitors}
|
||||
>
|
||||
{t("export.title")}
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</Stack>
|
||||
);
|
||||
|
||||
@@ -453,6 +453,39 @@ const useCreateBulkMonitors = () => {
|
||||
return [createBulkMonitors, isLoading];
|
||||
};
|
||||
|
||||
const useExportMonitors = () => {
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const exportMonitors = async () => {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const blob = await networkService.exportMonitors();
|
||||
|
||||
// Create a download link
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.setAttribute('download', 'monitors.csv');
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
link.remove();
|
||||
window.URL.revokeObjectURL(url);
|
||||
|
||||
createToast({ body: t('export.success') });
|
||||
return [true, null];
|
||||
} catch (err) {
|
||||
const errorMessage = err?.response?.data?.msg || err.message;
|
||||
createToast({ body: errorMessage || t('export.failed') });
|
||||
return [false, errorMessage];
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return [exportMonitors, isLoading];
|
||||
};
|
||||
|
||||
export {
|
||||
useFetchMonitorsWithSummary,
|
||||
useFetchMonitorsWithChecks,
|
||||
@@ -469,4 +502,5 @@ export {
|
||||
useDeleteAllMonitors,
|
||||
useDeleteMonitorStats,
|
||||
useCreateBulkMonitors,
|
||||
useExportMonitors,
|
||||
};
|
||||
@@ -1022,6 +1022,13 @@ class NetworkService {
|
||||
const { id, notification } = config;
|
||||
return this.axiosInstance.put(`/notifications/${id}`, notification);
|
||||
}
|
||||
|
||||
async exportMonitors() {
|
||||
const response = await this.axiosInstance.get("/monitors/export", {
|
||||
responseType: "blob",
|
||||
});
|
||||
return response.data;
|
||||
}
|
||||
}
|
||||
|
||||
export default NetworkService;
|
||||
|
||||
@@ -739,5 +739,10 @@
|
||||
"ping": "Enter the IP address or hostname to ping (e.g., 192.168.1.100 or example.com) and add a clear display name that appears on the dashboard.",
|
||||
"docker": "Enter the Docker ID of your container. Docker IDs must be the full 64 char Docker ID. You can run docker inspect <short_id> to get the full container ID.",
|
||||
"port": "Enter the URL or IP of the server, the port number and a clear display name that appears on the dashboard."
|
||||
}
|
||||
},
|
||||
"export": {
|
||||
"title": "Export Monitors",
|
||||
"success": "Monitors exported successfully!",
|
||||
"failed": "Failed to export monitors"
|
||||
}
|
||||
}
|
||||
@@ -702,6 +702,33 @@ class MonitorController {
|
||||
next(handleError(error, SERVICE_NAME, "seedDb"));
|
||||
}
|
||||
};
|
||||
|
||||
exportMonitorsToCSV = async (req, res, next) => {
|
||||
try {
|
||||
const { teamId } = req.user;
|
||||
|
||||
const monitors = await this.db.getMonitorsByTeamId({ teamId });
|
||||
const csvData = monitors?.filteredMonitors?.map((monitor) => ({
|
||||
name: monitor.name,
|
||||
description: monitor.description,
|
||||
type: monitor.type,
|
||||
url: monitor.url,
|
||||
interval: monitor.interval,
|
||||
port: monitor.port,
|
||||
ignoreTlsErrors: monitor.ignoreTlsErrors,
|
||||
isActive: monitor.isActive,
|
||||
}));
|
||||
|
||||
const csv = pkg.unparse(csvData);
|
||||
|
||||
res.setHeader("Content-Type", "text/csv");
|
||||
res.setHeader("Content-Disposition", "attachment; filename=monitors.csv");
|
||||
|
||||
res.send(csv);
|
||||
} catch (error) {
|
||||
next(handleError(error, SERVICE_NAME, "exportMonitorsToCSV"));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default MonitorController;
|
||||
@@ -17,6 +17,11 @@ class MonitorRoutes {
|
||||
initRoutes() {
|
||||
this.router.get("/", this.monitorController.getAllMonitors);
|
||||
this.router.get("/uptime", this.monitorController.getAllMonitorsWithUptimeStats);
|
||||
this.router.get(
|
||||
"/export",
|
||||
isAllowed(["admin", "superadmin"]),
|
||||
this.monitorController.exportMonitorsToCSV
|
||||
);
|
||||
this.router.get("/stats/:monitorId", this.monitorController.getMonitorStatsById);
|
||||
this.router.get(
|
||||
"/hardware/details/:monitorId",
|
||||
|
||||
Reference in new issue
Block a user