diff --git a/.github/workflows/distribution-deploy.yml b/.github/workflows/distribution-deploy.yml
index b96a0f3d7..69f3afd73 100644
--- a/.github/workflows/distribution-deploy.yml
+++ b/.github/workflows/distribution-deploy.yml
@@ -11,6 +11,9 @@ jobs:
- name: Checkout code
uses: actions/checkout@v4
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v3
+
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
@@ -36,6 +39,9 @@ jobs:
- name: Checkout code
uses: actions/checkout@v4
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v3
+
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 201199e81..702436b38 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -123,9 +123,15 @@ If one or more of these are missing, we may ask you to update your pull request
## Branching model
+
- Code contributions should go to the `develop` branch.
- `master` is used for stable releases.
- Use descriptive branch names, like `fix/login-error` or `feat/add-alerts`.
+- Make sure that you are using the latest version.
+- Make sure you run the code locally. The Checkmate [documentation](https://docs.checkmate.so) covers it.
+- Find out if the functionality is already covered, maybe by an individual configuration.
+- Perform a [search](/issues) to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one.
+- Find out whether your idea fits with the scope and aims of the project. It's up to you to make a strong case to convince the project's developers of the merits of this feature. Keep in mind that we want features that will be useful to the majority of our users and not just a small subset. If you're just targeting a minority of users, consider writing an add-on/plugin library.
---
@@ -133,8 +139,11 @@ If one or more of these are missing, we may ask you to update your pull request
Thanks for making Checkmate better. We mean it. Whether itโs your first pull request or your 50th, weโre excited to build with you.
+
PS: feel free to introduce yourself on [Discord](https://discord.gg/YOUR-DISCORD-LINK) and say hi.
-- Checkmate team
+Also make sure you read the [document about how to make a good pull request](/PULLREQUESTS.md).
+
diff --git a/README.md b/README.md
index 0830cc3b7..b1330a17a 100644
--- a/README.md
+++ b/README.md
@@ -30,11 +30,11 @@ You can see the latest build of [Checkmate](https://checkmate-demo.bluewavelabs.
## ๐ User's guide
-Usage instructions can be found [here](https://docs.checkmate.so/). It's still WIP and some of the information there might be outdated as we continuously add features weekly. Rest assured, we are doing our best! :)
+Usage instructions can be found [here](https://docs.checkmate.so/checkmate-2.1). It's still WIP and some of the information there might be outdated as we continuously add features weekly. Rest assured, we are doing our best! :)
## ๐ ๏ธ Installation
-See installation instructions in [Checkmate documentation portal](https://docs.checkmate.so/quickstart). Alternatively, you can also use [Coolify](https://coolify.io/) or [Elestio](https://elest.io/open-source/checkmate) for a one-click Docker deployment. If you would like to monitor your server infrastructure, you'll need [Capture agent](https://github.com/bluewave-labs/capture). Capture repository also contains the installation instructions.
+See installation instructions in [Checkmate documentation portal](https://docs.checkmate.so/checkmate-2.1/users-guide/quickstart). Alternatively, you can also use [Coolify](https://coolify.io/) or [Elestio](https://elest.io/open-source/checkmate) for a one-click Docker deployment. If you would like to monitor your server infrastructure, you'll need [Capture agent](https://github.com/bluewave-labs/capture). Capture repository also contains the installation instructions.
## ๐ Translations
@@ -118,7 +118,7 @@ Here's how you can contribute:
0. Star this repo :)
1. Check [Contributor's guideline](https://github.com/bluewave-labs/Checkmate/blob/develop/CONTRIBUTING.md). First timers are encouraged to check `good-first-issue` tag.
-2. Check [project structure](https://docs.checkmate.so/developers-guide/general-project-structure) and [high level overview](https://bluewavelabs.gitbook.io/checkmate/developers-guide/high-level-overview).
+2. Check [project structure](https://docs.checkmate.so/checkmate-2.1/developers-guide/general-project-structure) and [high level overview](https://bluewavelabs.gitbook.io/checkmate/developers-guide/high-level-overview).
3. Read a detailed structure of [Checkmate](https://deepwiki.com/bluewave-labs/Checkmate) if you would like to deep dive into the architecture.
4. Open an issue if you believe you've encountered a bug.
5. Check for good-first-issue's if you are a newcomer.
diff --git a/client/src/Components/MonitorDetailsControlHeader/index.jsx b/client/src/Components/MonitorDetailsControlHeader/index.jsx
new file mode 100644
index 000000000..c4dcf1ffc
--- /dev/null
+++ b/client/src/Components/MonitorDetailsControlHeader/index.jsx
@@ -0,0 +1,94 @@
+import Stack from "@mui/material/Stack";
+import Status from "./status";
+import Skeleton from "./skeleton";
+import Button from "@mui/material/Button";
+import SettingsOutlinedIcon from "@mui/icons-material/SettingsOutlined";
+import PauseOutlinedIcon from "@mui/icons-material/PauseOutlined";
+import PlayArrowOutlinedIcon from "@mui/icons-material/PlayArrowOutlined";
+
+// Utils
+import PropTypes from "prop-types";
+import { useNavigate } from "react-router-dom";
+import { useTheme } from "@mui/material/styles";
+import { usePauseMonitor } from "../../Hooks/useMonitorControls";
+
+/**
+ * MonitorDetailsControlHeader component displays the control header for monitor details.
+ * It includes status display, pause/resume button, and a configure button for admins.
+ *
+ * @component
+ * @param {Object} props - Component props
+ * @param {string} props.path - The base path for navigation
+ * @param {boolean} [props.isLoading=false] - Flag indicating if the data is loading
+ * @param {boolean} [props.isAdmin=false] - Flag indicating if the user is an admin
+ * @param {Object} props.monitor - The monitor object containing details
+ * @param {Function} props.triggerUpdate - Function to trigger an update
+ * @returns {JSX.Element} The rendered component
+ */
+const MonitorDetailsControlHeader = ({
+ path,
+ isLoading = false,
+ isAdmin = false,
+ monitor,
+ triggerUpdate,
+}) => {
+ const navigate = useNavigate();
+ const theme = useTheme();
+ const [pauseMonitor, isPausing, error] = usePauseMonitor({
+ monitorId: monitor?._id,
+ triggerUpdate,
+ });
+
+ if (isLoading) {
+ return ;
+ }
+
+ return (
+
+
+
+
+ :
+ }
+ onClick={() => {
+ pauseMonitor();
+ }}
+ >
+ {monitor?.isActive ? "Pause" : "Resume"}
+
+
+ {isAdmin && (
+ }
+ onClick={() => navigate(`/${path}/configure/${monitor._id}`)}
+ >
+ Configure
+
+ )}
+
+
+ );
+};
+
+MonitorDetailsControlHeader.propTypes = {
+ path: PropTypes.string,
+ isLoading: PropTypes.bool,
+ isAdmin: PropTypes.bool,
+ monitor: PropTypes.object,
+ triggerUpdate: PropTypes.func,
+};
+
+export default MonitorDetailsControlHeader;
diff --git a/client/src/Components/MonitorDetailsControlHeader/skeleton.jsx b/client/src/Components/MonitorDetailsControlHeader/skeleton.jsx
new file mode 100644
index 000000000..64dc0547f
--- /dev/null
+++ b/client/src/Components/MonitorDetailsControlHeader/skeleton.jsx
@@ -0,0 +1,23 @@
+import { Stack, Skeleton } from "@mui/material";
+
+const SkeletonLayout = () => {
+ return (
+
+
+
+
+ );
+};
+
+export default SkeletonLayout;
diff --git a/client/src/Components/MonitorDetailsControlHeader/status.jsx b/client/src/Components/MonitorDetailsControlHeader/status.jsx
new file mode 100644
index 000000000..9e01dd502
--- /dev/null
+++ b/client/src/Components/MonitorDetailsControlHeader/status.jsx
@@ -0,0 +1,56 @@
+// Components
+import Stack from "@mui/material/Stack";
+import PulseDot from "../../Components/Animated/PulseDot";
+import Typography from "@mui/material/Typography";
+import Dot from "../../Components/Dot";
+// Utils
+import { formatDurationRounded } from "../../Utils/timeUtils";
+import PropTypes from "prop-types";
+import { useTheme } from "@emotion/react";
+import useUtils from "../../Pages/Uptime/Monitors/Hooks/useUtils";
+
+/**
+ * Status component displays the status information of a monitor.
+ * It includes the monitor's name, URL, and check interval.
+ *
+ * @component
+ * @param {Object} props - Component props
+ * @param {Object} props.monitor - The monitor object containing details
+ * @param {string} props.monitor.name - The name of the monitor
+ * @param {string} props.monitor.url - The URL of the monitor
+ * @param {number} props.monitor.interval - The interval at which the monitor checks
+ * @returns {JSX.Element} The rendered component
+ */
+const Status = ({ monitor }) => {
+ const theme = useTheme();
+ const { statusColor, determineState } = useUtils();
+
+ return (
+
+ {monitor?.name}
+
+
+
+ {monitor?.url?.replace(/^https?:\/\//, "") || "..."}
+
+
+
+ Checking every {formatDurationRounded(monitor?.interval)}.
+
+
+
+ );
+};
+
+Status.propTypes = {
+ monitor: PropTypes.object,
+};
+
+export default Status;
diff --git a/client/src/Hooks/useFetchUptimeMonitorDetails.js b/client/src/Hooks/useFetchUptimeMonitorDetails.js
index c8cb81e65..3c0ac7ee6 100644
--- a/client/src/Hooks/useFetchUptimeMonitorDetails.js
+++ b/client/src/Hooks/useFetchUptimeMonitorDetails.js
@@ -3,13 +3,12 @@ import { networkService } from "../main";
import { useNavigate } from "react-router-dom";
import { createToast } from "../Utils/toastUtils";
-export const useFetchUptimeMonitorDetails = ({ monitorId, dateRange }) => {
+export const useFetchUptimeMonitorDetails = ({ monitorId, dateRange, trigger }) => {
const [networkError, setNetworkError] = useState(false);
const [isLoading, setIsLoading] = useState(true);
const [monitor, setMonitor] = useState(undefined);
const [monitorStats, setMonitorStats] = useState(undefined);
const navigate = useNavigate();
-
useEffect(() => {
const fetchMonitors = async () => {
try {
@@ -29,7 +28,7 @@ export const useFetchUptimeMonitorDetails = ({ monitorId, dateRange }) => {
}
};
fetchMonitors();
- }, [dateRange, monitorId, navigate]);
+ }, [dateRange, monitorId, navigate, trigger]);
return [monitor, monitorStats, isLoading, networkError];
};
diff --git a/client/src/Hooks/useMonitorControls.js b/client/src/Hooks/useMonitorControls.js
new file mode 100644
index 000000000..b47603b58
--- /dev/null
+++ b/client/src/Hooks/useMonitorControls.js
@@ -0,0 +1,28 @@
+import { useState } from "react";
+import { networkService } from "../main";
+import { createToast } from "../Utils/toastUtils";
+
+const usePauseMonitor = ({ monitorId, triggerUpdate }) => {
+ const [isLoading, setIsLoading] = useState(false);
+ const [error, setError] = useState(undefined);
+ const pauseMonitor = async () => {
+ try {
+ setIsLoading(true);
+ const res = await networkService.pauseMonitorById({ monitorId });
+ createToast({
+ body: res.data.data.isActive
+ ? "Monitor resumed successfully"
+ : "Monitor paused successfully",
+ });
+ triggerUpdate();
+ } catch (error) {
+ setError(error);
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ return [pauseMonitor, isLoading, error];
+};
+
+export { usePauseMonitor };
diff --git a/client/src/Pages/Infrastructure/Monitors/Components/MonitorsTable/index.jsx b/client/src/Pages/Infrastructure/Monitors/Components/MonitorsTable/index.jsx
index 25847b1be..0ec435c60 100644
--- a/client/src/Pages/Infrastructure/Monitors/Components/MonitorsTable/index.jsx
+++ b/client/src/Pages/Infrastructure/Monitors/Components/MonitorsTable/index.jsx
@@ -98,9 +98,6 @@ const MonitorsTable = ({ shouldRender, monitors, isAdmin, handleActionMenuDelete
const mem = (monitor?.checks[0]?.memory.usage_percent ?? 0) * 100;
const disk = (monitor?.checks[0]?.disk[0]?.usage_percent ?? 0) * 100;
const status = determineState(monitor);
- const uptimePercentage = ((monitor?.uptimePercentage ?? 0) * 100)
- .toFixed(2)
- .toString();
const percentageColor =
monitor.uptimePercentage < 0.25
? theme.palette.error.main
@@ -117,7 +114,6 @@ const MonitorsTable = ({ shouldRender, monitors, isAdmin, handleActionMenuDelete
mem,
disk,
status,
- uptimePercentage,
percentageColor,
};
});
diff --git a/client/src/Pages/Settings/SettingsAbout.jsx b/client/src/Pages/Settings/SettingsAbout.jsx
index b2b5df308..5551d8e7c 100644
--- a/client/src/Pages/Settings/SettingsAbout.jsx
+++ b/client/src/Pages/Settings/SettingsAbout.jsx
@@ -15,7 +15,7 @@ const SettingsAbout = () => {
{t("settingsAbout")}
- Checkmate {2.0}
+ Checkmate {2.1}
{t("settingsDevelopedBy")}
diff --git a/client/src/Pages/Settings/SettingsEmail.jsx b/client/src/Pages/Settings/SettingsEmail.jsx
index 694219614..38cc592da 100644
--- a/client/src/Pages/Settings/SettingsEmail.jsx
+++ b/client/src/Pages/Settings/SettingsEmail.jsx
@@ -122,6 +122,15 @@ const SettingsEmail = ({
)}
+
+ {t("settingsEmailConnectionHost")}
+
+