Merge remote-tracking branch 'upstream/develop' into feat/handleTestNotification
This commit is contained in:
commit
b1194ebd48
36 files changed
+670
-406
No files matched your search
@@ -13,7 +13,11 @@ Mention the issue number(s) this PR addresses (e.g., #123).
|
||||
- [ ] (Do not skip this or your PR will be closed) I deployed the application locally.
|
||||
- [ ] (Do not skip this or your PR will be closed) I have performed a self-review and testing of my code.
|
||||
- [ ] I have included the issue # in the PR.
|
||||
- [ ] I have labelled the PR correctly.
|
||||
- [ ] I have added i18n support to visible strings (instead of `<div>Add</div>`, use):
|
||||
```Javascript
|
||||
const { t } = useTranslation();
|
||||
<div>{t('add')}</div>
|
||||
```
|
||||
- [ ] The issue I am working on is assigned to me.
|
||||
- [ ] I didn't use any hardcoded values (otherwise it will not scale, and will make it difficult to maintain consistency across the application).
|
||||
- [ ] I made sure font sizes, color choices etc are all referenced from the theme. I have no hardcoded dimensions.
|
||||
|
||||
@@ -57,11 +57,12 @@ async function downloadTranslations() {
|
||||
});
|
||||
}
|
||||
|
||||
// Save file
|
||||
const outputPath = path.join(process.cwd(), 'temp', `${language}.json`);
|
||||
// Determine the output filename based on language
|
||||
const filename = language === 'en' ? 'gb.json' : `${language}.json`;
|
||||
const outputPath = path.join(process.cwd(), 'temp', filename);
|
||||
await fs.writeJson(outputPath, formattedTranslations, { spaces: 2 });
|
||||
|
||||
console.log(`Translations for ${language} language successfully downloaded and saved: ${outputPath}`);
|
||||
console.log(`Translations for ${language} language successfully downloaded and saved as: ${filename}`);
|
||||
}
|
||||
|
||||
console.log('All translations successfully downloaded!');
|
||||
|
||||
@@ -17,15 +17,24 @@ on:
|
||||
schedule:
|
||||
- cron: "0 0 * * *"
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
sync-translations:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v3
|
||||
@@ -83,10 +92,27 @@ jobs:
|
||||
cp -r temp/* src/locales/
|
||||
echo "Translation files copied to src/locales/"
|
||||
|
||||
- name: Commit changes
|
||||
run: |
|
||||
git config --local user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git config --local user.name "github-actions[bot]"
|
||||
git add src/locales/*.json
|
||||
git diff --staged --quiet || git commit -m "Translations updated from POEditor"
|
||||
git push
|
||||
- name: Get current date
|
||||
id: date
|
||||
run: echo "date=$(date +'%Y-%m-%d %H:%M:%S')" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
commit-message: "feat: translations updated from POEditor"
|
||||
title: "🌐 Updated Translations from POEditor"
|
||||
body: |
|
||||
This PR contains the latest translations from POEditor.
|
||||
|
||||
📅 Update Date: ${{ steps.date.outputs.date }}
|
||||
🔄 Updated Languages: ${{ github.event.inputs.languages || 'tr,en' }}
|
||||
|
||||
⚠️ Please review the translations and approve the PR if everything looks correct.
|
||||
branch: translation-update-${{ github.run_number }}
|
||||
delete-branch: true
|
||||
base: develop
|
||||
add-paths: |
|
||||
src/locales/*.json
|
||||
committer: GitHub Action <github-actions[bot]@users.noreply.github.com>
|
||||
author: GitHub Action <github-actions[bot]@users.noreply.github.com>
|
||||
@@ -51,14 +51,26 @@ jobs:
|
||||
id: changed-files
|
||||
if: github.event_name == 'pull_request'
|
||||
run: |
|
||||
# Get list of changed files in src/locales directory
|
||||
CHANGED_FILES=$(git diff --name-only ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }} -- src/locales/*.json)
|
||||
echo "Changed files: $CHANGED_FILES"
|
||||
# Get base and head commits
|
||||
BASE_SHA=${{ github.event.pull_request.base.sha }}
|
||||
HEAD_SHA=${{ github.event.pull_request.head.sha }}
|
||||
|
||||
# Create a JSON array of changed files with language codes
|
||||
echo "CHANGED_FILES<<EOF" >> $GITHUB_ENV
|
||||
echo "$CHANGED_FILES" >> $GITHUB_ENV
|
||||
echo "EOF" >> $GITHUB_ENV
|
||||
echo "Base SHA: $BASE_SHA"
|
||||
echo "Head SHA: $HEAD_SHA"
|
||||
|
||||
# Get list of changed files in src/locales directory
|
||||
CHANGED_FILES=$(git diff --name-only $BASE_SHA..$HEAD_SHA -- 'src/locales/*.json' || git ls-files 'src/locales/*.json')
|
||||
|
||||
if [ -z "$CHANGED_FILES" ]; then
|
||||
echo "No changes detected in locale files"
|
||||
echo "CHANGED_FILES=" >> $GITHUB_ENV
|
||||
else
|
||||
echo "Changed files:"
|
||||
echo "$CHANGED_FILES"
|
||||
echo "CHANGED_FILES<<EOF" >> $GITHUB_ENV
|
||||
echo "$CHANGED_FILES" >> $GITHUB_ENV
|
||||
echo "EOF" >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
- name: Upload changed translations to POEditor
|
||||
if: env.CHANGED_FILES != ''
|
||||
|
||||
@@ -71,7 +71,6 @@ If you have any questions, suggestions or comments, please use our [Discord chan
|
||||
- Status pages (**in progress**) https://github.com/bluewave-labs/Checkmate/issues/1131
|
||||
- Translations (i18n) (**in progress**)
|
||||
- Better notification options (Webhooks, Discord, Telegram, Slack) (**in progress**) https://github.com/bluewave-labs/Checkmate/issues/1545
|
||||
- Command line interface (CLI) (**in progress**) https://github.com/bluewave-labs/Checkmate/issues/1558
|
||||
- JSON query monitoring https://github.com/bluewave-labs/Checkmate/issues/1573
|
||||
- Tagging/grouping monitors https://github.com/bluewave-labs/Checkmate/issues/1546
|
||||
- More configuration options
|
||||
@@ -107,7 +106,9 @@ If you have any questions, suggestions or comments, please use our [Discord chan
|
||||
|
||||
## 🤝 Contributing
|
||||
|
||||
We pride ourselves on building strong connections with contributors at every level. Despite being a young project, Checkmate has already earned 4.4K+ stars and attracted 50+ contributors from around the globe.
|
||||
We are [@ajhollid](http://github.com/ajhollid) (team lead), [@vishnusn77](http://github.com/vishnusn77), [@mohicody](http://github.com/mohicody), [@gorkem-bwl](http://github.com/gorkem-bwl/) and [@Owaiseimdad](http://github.com/Owaiseimdad), helping individuals and businesses monitor their infra and servers.
|
||||
|
||||
We pride ourselves on building strong connections with contributors at every level. Despite being a young project, Checkmate has already earned 4.6K+ stars and attracted 60 contributors from around the globe.
|
||||
|
||||
Our repo is starred by employees from **Google, Microsoft, Intel, Cisco, Tencent, Electronic Arts, ByteDance, JP Morgan Chase, Deloitte, Accenture, Foxconn, Broadcom, China Telecom, Barclays, Capgemini, Wipro, Cloudflare, Dassault Systèmes and NEC**, so don’t hold back — jump in, contribute and learn with us!
|
||||
|
||||
|
||||
Generated
+11
-10
@@ -1973,9 +1973,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/runtime": {
|
||||
"version": "7.26.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.7.tgz",
|
||||
"integrity": "sha512-AOPI3D+a8dXnja+iwsUqGRjr1BbZIe771sXdapOtYI531gSqpi92vXivKcq2asu/DFpdl1ceFAKZyRzK2PCVcQ==",
|
||||
"version": "7.26.10",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.10.tgz",
|
||||
"integrity": "sha512-2WJMeRQPHKSPemqk/awGrAiuFfzBmOIPXKizAsVhWH9YJqLZ0H+HS4c8loHGgW6utJ3E/ejXQUsiGaQy2NZ9Fw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"regenerator-runtime": "^0.14.0"
|
||||
@@ -9189,9 +9189,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.8.2",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.8.2.tgz",
|
||||
"integrity": "sha512-ls4GYBm5aig9vWx8AWDSGLpnpDQRtWAfrjU+EuytuODrFBkqesN2RkOQCBzrA1RQNHw1SmRMSDDDSwzNAYQ6Rg==",
|
||||
"version": "1.8.3",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.8.3.tgz",
|
||||
"integrity": "sha512-iP4DebzoNlP/YN2dpwCgb8zoCmhtkajzS48JvwmkSkXvPI3DHc7m+XYL5tGnSlJtR6nImXZmdCuN5aP8dh1d8A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.6",
|
||||
@@ -12525,9 +12525,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/i18next": {
|
||||
"version": "24.2.2",
|
||||
"resolved": "https://registry.npmjs.org/i18next/-/i18next-24.2.2.tgz",
|
||||
"integrity": "sha512-NE6i86lBCKRYZa5TaUDkU5S4HFgLIEJRLr3Whf2psgaxBleQ2LC1YW1Vc+SCgkAW7VEzndT6al6+CzegSUHcTQ==",
|
||||
"version": "24.2.3",
|
||||
"resolved": "https://registry.npmjs.org/i18next/-/i18next-24.2.3.tgz",
|
||||
"integrity": "sha512-lfbf80OzkocvX7nmZtu7nSTNbrTYR52sLWxPtlXX1zAhVw8WEnFk4puUkCR4B1dNQwbSpEHHHemcZu//7EcB7A==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@@ -12542,8 +12542,9 @@
|
||||
"url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.23.2"
|
||||
"@babel/runtime": "^7.26.10"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "^5"
|
||||
|
||||
@@ -58,7 +58,7 @@ const BarChart = ({ checks = [] }) => {
|
||||
<>
|
||||
<Typography>
|
||||
{formatDateWithTz(
|
||||
check.createdAt,
|
||||
check.updatedAt,
|
||||
"ddd, MMMM D, YYYY, HH:mm A",
|
||||
uiTimezone
|
||||
)}
|
||||
|
||||
@@ -15,6 +15,14 @@ Pagination.propTypes = {
|
||||
|
||||
const ROWS_PER_PAGE_OPTIONS = [5, 10, 15, 25];
|
||||
|
||||
// Determine whether pagination buttons should be shown
|
||||
const shouldShowPaginationButtons = (itemCount, rowsPerPage) => {
|
||||
return Math.ceil(itemCount / rowsPerPage) > 1;
|
||||
};
|
||||
|
||||
// Empty action component for pagination (no-op component)
|
||||
const EmptyPaginationActions = () => <div />;
|
||||
|
||||
/**
|
||||
* Pagination component for table navigation with customized styling and behavior.
|
||||
*
|
||||
@@ -41,6 +49,8 @@ function Pagination({
|
||||
const end = Math.min(page * rowsPerPage + rowsPerPage, itemCount);
|
||||
const range = `${start} - ${end}`;
|
||||
|
||||
const showPaginationButtons = shouldShowPaginationButtons(itemCount, rowsPerPage);
|
||||
|
||||
return (
|
||||
<Stack
|
||||
direction="row"
|
||||
@@ -64,7 +74,9 @@ function Pagination({
|
||||
rowsPerPage={rowsPerPage}
|
||||
rowsPerPageOptions={ROWS_PER_PAGE_OPTIONS}
|
||||
onRowsPerPageChange={handleChangeRowsPerPage}
|
||||
ActionsComponent={TablePaginationActions}
|
||||
ActionsComponent={
|
||||
showPaginationButtons ? TablePaginationActions : EmptyPaginationActions
|
||||
}
|
||||
labelRowsPerPage="Rows per page"
|
||||
labelDisplayedRows={({ page, count }) =>
|
||||
`Page ${page + 1} of ${Math.max(0, Math.ceil(count / rowsPerPage))}`
|
||||
|
||||
+6
-6
@@ -1,11 +1,11 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { networkService } from "../../../../main";
|
||||
import { createToast } from "../../../../Utils/toastUtils";
|
||||
import { networkService } from "../main";
|
||||
import { createToast } from "../Utils/toastUtils";
|
||||
import { useSelector } from "react-redux";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import { useMonitorUtils } from "../../../../Hooks/useMonitorUtils";
|
||||
import { useMonitorUtils } from "./useMonitorUtils";
|
||||
|
||||
const useDUStatusPageFetchByUrl = ({ url, timeFrame, isCreate = false }) => {
|
||||
const useFetchDepinStatusPage = ({ url, timeFrame, isCreate = false }) => {
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [networkError, setNetworkError] = useState(false);
|
||||
const [statusPage, setStatusPage] = useState(undefined);
|
||||
@@ -50,9 +50,9 @@ const useDUStatusPageFetchByUrl = ({ url, timeFrame, isCreate = false }) => {
|
||||
}
|
||||
};
|
||||
fetchStatusPageByUrl();
|
||||
}, [authToken, url, getMonitorWithPercentage, theme, timeFrame]);
|
||||
}, [authToken, url, getMonitorWithPercentage, theme, timeFrame, isCreate]);
|
||||
|
||||
return [isLoading, networkError, statusPage, monitorId, isPublished];
|
||||
};
|
||||
|
||||
export { useDUStatusPageFetchByUrl };
|
||||
export { useFetchDepinStatusPage };
|
||||
@@ -0,0 +1,70 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { networkService } from "../main";
|
||||
import { createToast } from "../Utils/toastUtils";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import { useMonitorUtils } from "./useMonitorUtils";
|
||||
|
||||
export const useFetchMonitorsWithChecks = ({
|
||||
teamId,
|
||||
types,
|
||||
limit,
|
||||
page,
|
||||
rowsPerPage,
|
||||
filter,
|
||||
field,
|
||||
order,
|
||||
}) => {
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [count, setCount] = useState(undefined);
|
||||
const [monitors, setMonitors] = useState(undefined);
|
||||
const [networkError, setNetworkError] = useState(false);
|
||||
|
||||
const theme = useTheme();
|
||||
const { getMonitorWithPercentage } = useMonitorUtils();
|
||||
useEffect(() => {
|
||||
const fetchMonitors = async () => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const res = await networkService.getMonitorsWithChecksByTeamId({
|
||||
teamId,
|
||||
limit,
|
||||
types,
|
||||
page,
|
||||
rowsPerPage,
|
||||
filter,
|
||||
field,
|
||||
order,
|
||||
});
|
||||
const { count, monitors } = res?.data?.data ?? {};
|
||||
const mappedMonitors = monitors.map((monitor) =>
|
||||
getMonitorWithPercentage(monitor, theme)
|
||||
);
|
||||
setMonitors(mappedMonitors);
|
||||
setCount(count?.monitorsCount ?? 0);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
setNetworkError(true);
|
||||
createToast({
|
||||
body: error.message,
|
||||
});
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
fetchMonitors();
|
||||
}, [
|
||||
field,
|
||||
filter,
|
||||
getMonitorWithPercentage,
|
||||
limit,
|
||||
order,
|
||||
page,
|
||||
rowsPerPage,
|
||||
teamId,
|
||||
theme,
|
||||
types,
|
||||
]);
|
||||
return [monitors, count, isLoading, networkError];
|
||||
};
|
||||
|
||||
export default useFetchMonitorsWithChecks;
|
||||
@@ -0,0 +1,37 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { networkService } from "../main";
|
||||
import { createToast } from "../Utils/toastUtils";
|
||||
|
||||
export const useFetchMonitorsWithSummary = ({ teamId, types }) => {
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [monitors, setMonitors] = useState(undefined);
|
||||
const [monitorsSummary, setMonitorsSummary] = useState(undefined);
|
||||
const [networkError, setNetworkError] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchMonitors = async () => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const res = await networkService.getMonitorsWithSummaryByTeamId({
|
||||
teamId,
|
||||
types,
|
||||
});
|
||||
const { monitors, summary } = res?.data?.data ?? {};
|
||||
setMonitors(monitors);
|
||||
setMonitorsSummary(summary);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
setNetworkError(true);
|
||||
createToast({
|
||||
body: error.message,
|
||||
});
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
fetchMonitors();
|
||||
}, [teamId, types]);
|
||||
return [monitors, monitorsSummary, isLoading, networkError];
|
||||
};
|
||||
|
||||
export default useFetchMonitorsWithSummary;
|
||||
+4
-4
@@ -1,8 +1,8 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { networkService } from "../../../../main";
|
||||
import { createToast } from "../../../../Utils/toastUtils";
|
||||
import { networkService } from "../main";
|
||||
import { createToast } from "../Utils/toastUtils";
|
||||
|
||||
const useSubscribeToDetails = ({ monitorId, isPublic, isPublished, dateRange }) => {
|
||||
const useSubscribeToDepinDetails = ({ monitorId, isPublic, isPublished, dateRange }) => {
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [connectionStatus, setConnectionStatus] = useState(undefined);
|
||||
const [retryCount, setRetryCount] = useState(0);
|
||||
@@ -92,4 +92,4 @@ const useSubscribeToDetails = ({ monitorId, isPublic, isPublished, dateRange })
|
||||
return [isLoading, networkError, connectionStatus, monitor, lastUpdateTrigger];
|
||||
};
|
||||
|
||||
export { useSubscribeToDetails };
|
||||
export { useSubscribeToDepinDetails };
|
||||
+16
-21
@@ -1,20 +1,19 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { networkService } from "../../../../main";
|
||||
import { networkService } from "../main";
|
||||
import { useSelector } from "react-redux";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import { useMonitorUtils } from "../../../../Hooks/useMonitorUtils";
|
||||
import { createToast } from "../../../../Utils/toastUtils";
|
||||
import { useMonitorUtils } from "./useMonitorUtils";
|
||||
import { createToast } from "../Utils/toastUtils";
|
||||
|
||||
const useSubscribeToMonitors = (page, rowsPerPage) => {
|
||||
const useSubscribeToDepinMonitors = (page, rowsPerPage) => {
|
||||
// Redux
|
||||
const { user } = useSelector((state) => state.auth);
|
||||
|
||||
// Local state
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [networkError, setNetworkError] = useState(false);
|
||||
const [count, setCount] = useState(undefined);
|
||||
const [monitors, setMonitors] = useState(undefined);
|
||||
const [monitorsSummary, setMonitorsSummary] = useState(undefined);
|
||||
const [filteredMonitors, setFilteredMonitors] = useState(undefined);
|
||||
|
||||
const theme = useTheme();
|
||||
const { getMonitorWithPercentage } = useMonitorUtils();
|
||||
@@ -29,18 +28,17 @@ const useSubscribeToMonitors = (page, rowsPerPage) => {
|
||||
page,
|
||||
rowsPerPage,
|
||||
});
|
||||
|
||||
const { count, monitors } = initialDataRes?.data?.data ?? {};
|
||||
const responseData = initialDataRes?.data?.data;
|
||||
if (typeof responseData === "undefined") throw new Error("No data");
|
||||
|
||||
const { monitors, filteredMonitors, summary } = responseData;
|
||||
|
||||
const mappedMonitors = filteredMonitors?.map((monitor) =>
|
||||
const mappedMonitors = monitors?.map((monitor) =>
|
||||
getMonitorWithPercentage(monitor, theme)
|
||||
);
|
||||
|
||||
setMonitors(monitors);
|
||||
setMonitorsSummary(summary);
|
||||
setFilteredMonitors(mappedMonitors);
|
||||
setMonitors(mappedMonitors);
|
||||
setCount(count?.monitorsCount ?? 0);
|
||||
} catch (error) {
|
||||
setNetworkError(true);
|
||||
createToast({
|
||||
@@ -71,15 +69,12 @@ const useSubscribeToMonitors = (page, rowsPerPage) => {
|
||||
if (isLoading === true) {
|
||||
setIsLoading(false);
|
||||
}
|
||||
|
||||
const res = data.monitors;
|
||||
const { monitors, filteredMonitors, summary } = res;
|
||||
const mappedMonitors = filteredMonitors.map((monitor) =>
|
||||
const { count, monitors } = data;
|
||||
const mappedMonitors = monitors.map((monitor) =>
|
||||
getMonitorWithPercentage(monitor, theme)
|
||||
);
|
||||
setMonitors(monitors);
|
||||
setMonitorsSummary(summary);
|
||||
setFilteredMonitors(mappedMonitors);
|
||||
setMonitors(mappedMonitors);
|
||||
setCount(count?.monitorsCount ?? 0);
|
||||
},
|
||||
onError: () => {
|
||||
setIsLoading(false);
|
||||
@@ -94,6 +89,6 @@ const useSubscribeToMonitors = (page, rowsPerPage) => {
|
||||
setNetworkError(true);
|
||||
}
|
||||
}, [user, getMonitorWithPercentage, theme, isLoading, page, rowsPerPage]);
|
||||
return [isLoading, networkError, monitors, monitorsSummary, filteredMonitors];
|
||||
return [monitors, count, isLoading, networkError];
|
||||
};
|
||||
export { useSubscribeToMonitors };
|
||||
export { useSubscribeToDepinMonitors };
|
||||
@@ -142,7 +142,7 @@ const Login = () => {
|
||||
overflow="hidden"
|
||||
sx={{
|
||||
"& h1": {
|
||||
color: theme.palette.primary.main,
|
||||
color: theme.palette.primary.contrastText,
|
||||
fontWeight: 600,
|
||||
fontSize: 28,
|
||||
},
|
||||
|
||||
@@ -35,7 +35,7 @@ const LandingPage = ({ isSuperAdmin, onSignup }) => {
|
||||
textAlign="center"
|
||||
>
|
||||
<Box>
|
||||
<Typography component="h1">{t("signUP")}</Typography>
|
||||
<Typography component="h1">{t("signUp")}</Typography>
|
||||
<Typography>
|
||||
{isSuperAdmin
|
||||
? t("authRegisterCreateSuperAdminAccount")
|
||||
@@ -83,9 +83,9 @@ const LandingPage = ({ isSuperAdmin, onSignup }) => {
|
||||
},
|
||||
}}
|
||||
>
|
||||
Terms of Service
|
||||
{t("authRegisterTerms")}
|
||||
</Typography>{" "}
|
||||
and{" "}
|
||||
{t("and")}{" "}
|
||||
<Typography
|
||||
component="span"
|
||||
onClick={() => {
|
||||
@@ -101,7 +101,7 @@ const LandingPage = ({ isSuperAdmin, onSignup }) => {
|
||||
},
|
||||
}}
|
||||
>
|
||||
Privacy Policy.
|
||||
{t("authRegisterPrivacy")}
|
||||
</Typography>
|
||||
</Typography>
|
||||
</Box>
|
||||
@@ -283,7 +283,7 @@ const Register = ({ isSuperAdmin }) => {
|
||||
overflow="hidden"
|
||||
sx={{
|
||||
"& h1": {
|
||||
color: theme.palette.primary.main,
|
||||
color: theme.palette.primary.contrastText,
|
||||
fontWeight: 600,
|
||||
fontSize: 28,
|
||||
},
|
||||
@@ -370,7 +370,7 @@ const Register = ({ isSuperAdmin }) => {
|
||||
p={theme.spacing(12)}
|
||||
>
|
||||
<Typography display="inline-block">
|
||||
{t("authRegisterAlreadyHaveAccount")} -
|
||||
{t("authRegisterAlreadyHaveAccount")}
|
||||
</Typography>
|
||||
<Typography
|
||||
component="span"
|
||||
@@ -378,7 +378,7 @@ const Register = ({ isSuperAdmin }) => {
|
||||
onClick={() => {
|
||||
navigate("/login");
|
||||
}}
|
||||
sx={{ userSelect: "none", color: theme.palette.primary.main }}
|
||||
sx={{ userSelect: "none", color: theme.palette.accent.main }}
|
||||
>
|
||||
{t("authLoginTitle")}
|
||||
</Typography>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { useSelector } from "react-redux";
|
||||
import { useState } from "react";
|
||||
import { networkService } from "../../../../main";
|
||||
import { createToast } from "../../../../Utils/toastUtils";
|
||||
|
||||
@@ -19,7 +19,7 @@ import { useTheme } from "@mui/material/styles";
|
||||
import { useState } from "react";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useIsAdmin } from "../../../Hooks/useIsAdmin";
|
||||
import { useSubscribeToDetails } from "./Hooks/useSubscribeToDetails";
|
||||
import { useSubscribeToDepinDetails } from "../../../Hooks/useSubscribeToDepinDetails";
|
||||
import { useDeleteMonitor } from "./Hooks/useDeleteMonitor";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { useTranslation } from "react-i18next";
|
||||
@@ -36,7 +36,7 @@ const DistributedUptimeDetails = () => {
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
const [isLoading, networkError, connectionStatus, monitor, lastUpdateTrigger] =
|
||||
useSubscribeToDetails({ monitorId, dateRange });
|
||||
useSubscribeToDepinDetails({ monitorId, dateRange });
|
||||
|
||||
const [deleteMonitor, isDeleting] = useDeleteMonitor({ monitorId });
|
||||
// Constants
|
||||
|
||||
@@ -11,7 +11,7 @@ import GenericFallback from "../../../Components/GenericFallback";
|
||||
import { useState } from "react";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import { useIsAdmin } from "../../../Hooks/useIsAdmin";
|
||||
import { useSubscribeToMonitors } from "./Hooks/useSubscribeToMonitors";
|
||||
import { useSubscribeToDepinMonitors } from "../../../Hooks/useSubscribeToDepinMonitors";
|
||||
import SkeletonLayout from "./Components/Skeleton";
|
||||
import { useTranslation } from "react-i18next";
|
||||
// Constants
|
||||
@@ -26,8 +26,10 @@ const DistributedUptimeMonitors = () => {
|
||||
const theme = useTheme();
|
||||
const isAdmin = useIsAdmin();
|
||||
const { t } = useTranslation();
|
||||
const [isLoading, networkError, monitors, monitorsSummary, filteredMonitors] =
|
||||
useSubscribeToMonitors(page, rowsPerPage);
|
||||
const [monitors, count, isLoading, networkError] = useSubscribeToDepinMonitors(
|
||||
page,
|
||||
rowsPerPage
|
||||
);
|
||||
// Handlers
|
||||
const handleChangePage = (event, newPage) => {
|
||||
setPage(newPage);
|
||||
@@ -57,7 +59,7 @@ const DistributedUptimeMonitors = () => {
|
||||
);
|
||||
}
|
||||
|
||||
if (typeof monitorsSummary === "undefined" || monitorsSummary.totalMonitors === 0) {
|
||||
if (count === 0) {
|
||||
return (
|
||||
<Fallback
|
||||
vowelStart={false}
|
||||
@@ -83,10 +85,10 @@ const DistributedUptimeMonitors = () => {
|
||||
/>
|
||||
<MonitorTable
|
||||
isLoading={isLoading}
|
||||
monitors={filteredMonitors}
|
||||
monitors={monitors}
|
||||
/>
|
||||
<Pagination
|
||||
itemCount={monitorsSummary?.totalMonitors ?? 0}
|
||||
itemCount={count}
|
||||
paginationLabel="monitors"
|
||||
page={page}
|
||||
rowsPerPage={rowsPerPage}
|
||||
|
||||
@@ -19,18 +19,19 @@ import { buildErrors } from "../../../Validation/error";
|
||||
import { createToast } from "../../../Utils/toastUtils";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { useMonitorsFetch } from "../../StatusPage/Create/Hooks/useMonitorsFetch";
|
||||
import { useDUStatusPageFetchByUrl } from "../Status/Hooks/useDUStatusPageFetchByUrl";
|
||||
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useFetchDepinStatusPage } from "../../../Hooks/useFetchDepinStatusPage";
|
||||
const CreateStatus = () => {
|
||||
const theme = useTheme();
|
||||
const { monitorId, url } = useParams();
|
||||
const navigate = useNavigate();
|
||||
const { t } = useTranslation();
|
||||
const isCreate = typeof url === "undefined";
|
||||
|
||||
const [createStatusPage, isLoading, networkError] = useCreateStatusPage(isCreate);
|
||||
|
||||
const [statusPageIsLoading, statusPageNetworkError, statusPage, _, isPublished] =
|
||||
useDUStatusPageFetchByUrl({
|
||||
useFetchDepinStatusPage({
|
||||
url,
|
||||
timeFrame: 30,
|
||||
isCreate,
|
||||
@@ -176,7 +177,9 @@ const CreateStatus = () => {
|
||||
component="span"
|
||||
fontSize="inherit"
|
||||
>
|
||||
{isCreate ? "Create your" : "Edit your"}{" "}
|
||||
{isCreate
|
||||
? t("distributedUptimeStatusCreateYour")
|
||||
: t("distributedUptimeStatusEditYour")}{" "}
|
||||
</Typography>
|
||||
<Typography
|
||||
component="span"
|
||||
@@ -184,21 +187,23 @@ const CreateStatus = () => {
|
||||
fontSize="inherit"
|
||||
fontWeight="inherit"
|
||||
>
|
||||
status page
|
||||
{t("distributedUptimeStatusCreateStatusPage")}
|
||||
</Typography>
|
||||
</Typography>
|
||||
<ConfigBox>
|
||||
<Stack>
|
||||
<Typography component="h2">Access</Typography>
|
||||
<Typography component="h2">
|
||||
{t("distributedUptimeStatusCreateStatusPageAccess")}
|
||||
</Typography>
|
||||
<Typography component="p">
|
||||
If your status page is ready, you can mark it as published.
|
||||
{t("distributedUptimeStatusCreateStatusPageReady")}
|
||||
</Typography>
|
||||
</Stack>
|
||||
<Stack gap={theme.spacing(18)}>
|
||||
<Checkbox
|
||||
id="publish"
|
||||
name="isPublished"
|
||||
label={`Published and visible to the public`}
|
||||
label={t("distributedUptimeStatusPublishedLabel")}
|
||||
isChecked={form.isPublished}
|
||||
onChange={handleFormChange}
|
||||
/>
|
||||
@@ -206,9 +211,11 @@ const CreateStatus = () => {
|
||||
</ConfigBox>
|
||||
<ConfigBox>
|
||||
<Stack gap={theme.spacing(6)}>
|
||||
<Typography component="h2">Basic Information</Typography>
|
||||
<Typography component="h2">
|
||||
{t("distributedUptimeStatusBasicInfoHeader")}
|
||||
</Typography>
|
||||
<Typography component="p">
|
||||
Define company name and the subdomain that your status page points to.
|
||||
{t("distributedUptimeStatusBasicInfoDescription")}
|
||||
</Typography>
|
||||
</Stack>
|
||||
<Stack gap={theme.spacing(18)}>
|
||||
@@ -216,7 +223,7 @@ const CreateStatus = () => {
|
||||
id="companyName"
|
||||
name="companyName"
|
||||
type="text"
|
||||
label="Company name"
|
||||
label={t("distributedUptimeStatusCompanyNameLabel")}
|
||||
placeholder="Company name"
|
||||
value={form.companyName}
|
||||
onChange={handleFormChange}
|
||||
@@ -227,7 +234,7 @@ const CreateStatus = () => {
|
||||
id="url"
|
||||
name="url"
|
||||
type="url"
|
||||
label="Your status page address"
|
||||
label={t("distributedUptimeStatusPageAddressLabel")}
|
||||
disabled={!isCreate}
|
||||
value={form.url}
|
||||
onChange={handleFormChange}
|
||||
@@ -238,8 +245,10 @@ const CreateStatus = () => {
|
||||
</ConfigBox>
|
||||
<ConfigBox>
|
||||
<Stack gap={theme.spacing(6)}>
|
||||
<Typography component="h2">Logo</Typography>
|
||||
<Typography component="p">Upload a logo for your status page </Typography>
|
||||
<Typography component="h2">{t("distributedUptimeStatusLogoHeader")}</Typography>
|
||||
<Typography component="p">
|
||||
{t("distributedUptimeStatusLogoDescription")}{" "}
|
||||
</Typography>
|
||||
</Stack>
|
||||
<Stack
|
||||
gap={theme.spacing(18)}
|
||||
@@ -262,7 +271,7 @@ const CreateStatus = () => {
|
||||
color="accent"
|
||||
tabIndex={-1}
|
||||
>
|
||||
Upload logo
|
||||
{t("distributedUptimeStatusLogoUploadButton")}
|
||||
<VisuallyHiddenInput onChange={handleImageUpload} />
|
||||
</Button>
|
||||
</Box>
|
||||
@@ -270,9 +279,11 @@ const CreateStatus = () => {
|
||||
</ConfigBox>
|
||||
<ConfigBox>
|
||||
<Stack>
|
||||
<Typography component="h2">Standard Monitors</Typography>
|
||||
<Typography component="h2">
|
||||
{t("distributedUptimeStatusStandardMonitorsHeader")}
|
||||
</Typography>
|
||||
<Typography component="p">
|
||||
Attach standard monitors to your status page.
|
||||
{t("distributedUptimeStatusStandardMonitorsDescription")}
|
||||
</Typography>
|
||||
</Stack>
|
||||
<Stack gap={theme.spacing(18)}>
|
||||
@@ -301,7 +312,7 @@ const CreateStatus = () => {
|
||||
color="accent"
|
||||
onClick={handleSubmit}
|
||||
>
|
||||
Save
|
||||
{t("settingsSave")}
|
||||
</Button>
|
||||
</Stack>
|
||||
</Stack>
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { Stack, Button, ButtonGroup } from "@mui/material";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const TimeFrameHeader = ({ timeFrame, setTimeFrame, sx, ...props }) => {
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<Stack
|
||||
direction="row"
|
||||
@@ -16,21 +18,21 @@ const TimeFrameHeader = ({ timeFrame, setTimeFrame, sx, ...props }) => {
|
||||
filled={(timeFrame === 30).toString()}
|
||||
onClick={() => setTimeFrame(30)}
|
||||
>
|
||||
30 days
|
||||
{t("distributedUptimeStatus30Days")}
|
||||
</Button>
|
||||
<Button
|
||||
variant="group"
|
||||
filled={(timeFrame === 60).toString()}
|
||||
onClick={() => setTimeFrame(60)}
|
||||
>
|
||||
60 days
|
||||
{t("distributedUptimeStatus60Days")}
|
||||
</Button>
|
||||
<Button
|
||||
variant="group"
|
||||
filled={(timeFrame === 90).toString()}
|
||||
onClick={() => setTimeFrame(90)}
|
||||
>
|
||||
90 days
|
||||
{t("distributedUptimeStatus90Days")}
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</Stack>
|
||||
|
||||
@@ -23,8 +23,8 @@ import { RowContainer } from "../../../Components/StandardContainer";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import { useState, useEffect, useRef } from "react";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useSubscribeToDetails } from "../../DistributedUptime/Details/Hooks/useSubscribeToDetails";
|
||||
import { useDUStatusPageFetchByUrl } from "./Hooks/useDUStatusPageFetchByUrl";
|
||||
import { useFetchDepinStatusPage } from "../../../Hooks/useFetchDepinStatusPage";
|
||||
import { useSubscribeToDepinDetails } from "../../../Hooks/useSubscribeToDepinDetails";
|
||||
import { useStatusPageDelete } from "../../StatusPage/Status/Hooks/useStatusPageDelete";
|
||||
import TimeFrameHeader from "./Components/TimeframeHeader";
|
||||
import SubHeader from "../../../Components/Subheader";
|
||||
@@ -64,13 +64,13 @@ const DistributedUptimeStatus = () => {
|
||||
statusPage,
|
||||
monitorId,
|
||||
isPublished,
|
||||
] = useDUStatusPageFetchByUrl({
|
||||
] = useFetchDepinStatusPage({
|
||||
url,
|
||||
timeFrame,
|
||||
});
|
||||
|
||||
const [isLoading, networkError, connectionStatus, monitor, lastUpdateTrigger] =
|
||||
useSubscribeToDetails({ monitorId, dateRange, isPublic, isPublished });
|
||||
useSubscribeToDepinDetails({ monitorId, dateRange, isPublic, isPublished });
|
||||
|
||||
const [deleteStatusPage, isDeleting] = useStatusPageDelete(() => {
|
||||
navigate("/distributed-uptime");
|
||||
@@ -124,9 +124,9 @@ const DistributedUptimeStatus = () => {
|
||||
marginY={theme.spacing(4)}
|
||||
color={theme.palette.primary.contrastTextTertiary}
|
||||
>
|
||||
A status page is not set up.
|
||||
{t("distributedUptimeStatusPageNotSetUp")}
|
||||
</Typography>
|
||||
<Typography>Please contact your administrator</Typography>
|
||||
<Typography>{t("distributedUptimeStatusContactAdmin")}</Typography>
|
||||
</GenericFallback>
|
||||
</Stack>
|
||||
);
|
||||
@@ -137,7 +137,7 @@ const DistributedUptimeStatus = () => {
|
||||
return (
|
||||
<Stack sx={sx}>
|
||||
<GenericFallback>
|
||||
<Typography>This status page is not public.</Typography>
|
||||
<Typography>{t("distributedUptimeStatusPageNotPublic")}</Typography>
|
||||
</GenericFallback>
|
||||
</Stack>
|
||||
);
|
||||
@@ -155,9 +155,9 @@ const DistributedUptimeStatus = () => {
|
||||
marginY={theme.spacing(4)}
|
||||
color={theme.palette.primary.contrastTextTertiary}
|
||||
>
|
||||
Network error
|
||||
{t("networkError")}
|
||||
</Typography>
|
||||
<Typography>Please check your connection</Typography>
|
||||
<Typography>{t("checkConnection")}</Typography>
|
||||
</GenericFallback>
|
||||
);
|
||||
}
|
||||
@@ -171,7 +171,7 @@ const DistributedUptimeStatus = () => {
|
||||
<Stack gap={theme.spacing(10)}>
|
||||
<Breadcrumbs list={BREADCRUMBS} />
|
||||
<GenericFallback>
|
||||
<Typography>There is no check history for this monitor yet.</Typography>
|
||||
<Typography>{t("distributedUptimeDetailsNoMonitorHistory")}</Typography>
|
||||
</GenericFallback>
|
||||
</Stack>
|
||||
);
|
||||
@@ -246,17 +246,21 @@ const DistributedUptimeStatus = () => {
|
||||
gap={theme.spacing(8)}
|
||||
>
|
||||
<InfoBox
|
||||
heading="Devices"
|
||||
heading={t("distributedUptimeStatusDevices")}
|
||||
subHeading={monitor?.totalChecks ?? 0}
|
||||
icon={PeopleAltOutlinedIcon}
|
||||
alt="Upt Logo"
|
||||
sx={{ width: "50%" }}
|
||||
/>
|
||||
<InfoBox
|
||||
heading={isSmallScreen ? "UPT" : "UPT Burned"}
|
||||
heading={
|
||||
isSmallScreen
|
||||
? t("distributedUptimeStatusUpt")
|
||||
: t("distributedUptimeStatusUptBurned")
|
||||
}
|
||||
subHeading={safelyParseFloat(monitor?.uptBurnt).toFixed(4)}
|
||||
img={UptLogo}
|
||||
alt="Upt Logo"
|
||||
alt={t("distributedUptimeStatusUptLogo")}
|
||||
sx={{ width: "50%" }}
|
||||
/>
|
||||
</Stack>
|
||||
@@ -295,7 +299,7 @@ const DistributedUptimeStatus = () => {
|
||||
<Footer />
|
||||
<Dialog
|
||||
// open={isOpen.deleteStats}
|
||||
title="Do you want to delete this status page?"
|
||||
title={t("distributedUptimeStatusPageDeleteDialog")}
|
||||
onConfirm={() => {
|
||||
deleteStatusPage();
|
||||
setIsDeleteOpen(false);
|
||||
@@ -304,8 +308,8 @@ const DistributedUptimeStatus = () => {
|
||||
setIsDeleteOpen(false);
|
||||
}}
|
||||
open={isDeleteOpen}
|
||||
confirmationButtonLabel="Yes, delete status page"
|
||||
description="Once deleted, your status page cannot be retrieved."
|
||||
confirmationButtonLabel={t("distributedUptimeStatusPageDeleteConfirm")}
|
||||
description={t("distributedUptimeStatusPageDeleteDescription")}
|
||||
isLoading={isDeleting || isLoading}
|
||||
/>
|
||||
</Stack>
|
||||
|
||||
@@ -13,6 +13,7 @@ import { useSelector } from "react-redux";
|
||||
import { useState } from "react";
|
||||
import useChecksFetch from "../../Hooks/useChecksFetch";
|
||||
import PropTypes from "prop-types";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const IncidentTable = ({
|
||||
shouldRender,
|
||||
@@ -38,6 +39,8 @@ const IncidentTable = ({
|
||||
rowsPerPage,
|
||||
});
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
//Handlers
|
||||
const handleChangePage = (_, newPage) => {
|
||||
setPage(newPage);
|
||||
@@ -50,12 +53,12 @@ const IncidentTable = ({
|
||||
const headers = [
|
||||
{
|
||||
id: "monitorName",
|
||||
content: "Monitor Name",
|
||||
content: t("incidentsTableMonitorName"),
|
||||
render: (row) => monitors[row.monitorId]?.name ?? "N/A",
|
||||
},
|
||||
{
|
||||
id: "status",
|
||||
content: "Status",
|
||||
content: t("incidentsTableStatus"),
|
||||
render: (row) => {
|
||||
const status = row.status === true ? "up" : "down";
|
||||
return (
|
||||
@@ -69,7 +72,7 @@ const IncidentTable = ({
|
||||
},
|
||||
{
|
||||
id: "dateTime",
|
||||
content: "Date & Time",
|
||||
content: t("incidentsTableDateTime"),
|
||||
render: (row) => {
|
||||
const formattedDate = formatDateWithTz(
|
||||
row.createdAt,
|
||||
@@ -81,10 +84,10 @@ const IncidentTable = ({
|
||||
},
|
||||
{
|
||||
id: "statusCode",
|
||||
content: "Status Code",
|
||||
content: t("incidentsTableStatusCode"),
|
||||
render: (row) => <HttpStatusLabel status={row.statusCode} />,
|
||||
},
|
||||
{ id: "message", content: "Message", render: (row) => row.message },
|
||||
{ id: "message", content: t("incidentsTableMessage"), render: (row) => row.message },
|
||||
];
|
||||
|
||||
if (!shouldRender || isLoading) return <TableSkeleton />;
|
||||
@@ -98,7 +101,7 @@ const IncidentTable = ({
|
||||
}
|
||||
|
||||
if (!isLoading && typeof checksCount === "undefined") {
|
||||
return <GenericFallback>No incidents recorded</GenericFallback>;
|
||||
return <GenericFallback>{t("incidentsTableNoIncidents")}</GenericFallback>;
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -108,7 +111,7 @@ const IncidentTable = ({
|
||||
data={checks}
|
||||
/>
|
||||
<Pagination
|
||||
paginationLabel="incidents"
|
||||
paginationLabel={t("incidentsTablePaginationLabel")}
|
||||
itemCount={checksCount}
|
||||
page={page}
|
||||
rowsPerPage={rowsPerPage}
|
||||
|
||||
@@ -6,6 +6,7 @@ import PropTypes from "prop-types";
|
||||
//Utils
|
||||
import { useTheme } from "@emotion/react";
|
||||
import SkeletonLayout from "./skeleton";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const OptionsHeader = ({
|
||||
shouldRender,
|
||||
@@ -18,6 +19,7 @@ const OptionsHeader = ({
|
||||
setDateRange,
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation();
|
||||
const monitorNames = typeof monitors !== "undefined" ? Object.values(monitors) : [];
|
||||
|
||||
// The stacks below which are three in number have the same style so
|
||||
@@ -40,11 +42,11 @@ const OptionsHeader = ({
|
||||
component="h1"
|
||||
color={theme.palette.primary.contrastTextSecondary}
|
||||
>
|
||||
Incidents for:
|
||||
{t("incidentsOptionsHeader")}
|
||||
</Typography>
|
||||
<Select
|
||||
id="incidents-select-monitor"
|
||||
placeholder="All servers"
|
||||
placeholder={t("incidentsOptionsPlaceholderAllServers")}
|
||||
value={selectedMonitor}
|
||||
onChange={(e) => setSelectedMonitor(e.target.value)}
|
||||
items={monitorNames}
|
||||
@@ -61,7 +63,7 @@ const OptionsHeader = ({
|
||||
component="h1"
|
||||
color={theme.palette.primary.contrastTextSecondary}
|
||||
>
|
||||
Filter by:
|
||||
{t("incidentsOptionsHeaderFilterBy")}
|
||||
</Typography>
|
||||
<ButtonGroup>
|
||||
<Button
|
||||
@@ -69,21 +71,21 @@ const OptionsHeader = ({
|
||||
filled={(filter === "all").toString()}
|
||||
onClick={() => setFilter("all")}
|
||||
>
|
||||
All
|
||||
{t("incidentsOptionsHeaderFilterAll")}
|
||||
</Button>
|
||||
<Button
|
||||
variant="group"
|
||||
filled={(filter === "down").toString()}
|
||||
onClick={() => setFilter("down")}
|
||||
>
|
||||
Down
|
||||
{t("incidentsOptionsHeaderFilterDown")}
|
||||
</Button>
|
||||
<Button
|
||||
variant="group"
|
||||
filled={(filter === "resolve").toString()}
|
||||
onClick={() => setFilter("resolve")}
|
||||
>
|
||||
Cannot resolve
|
||||
{t("incidentsOptionsHeaderFilterCannotResolve")}
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</Stack>
|
||||
@@ -93,7 +95,7 @@ const OptionsHeader = ({
|
||||
component="h1"
|
||||
color={theme.palette.primary.contrastTextSecondary}
|
||||
>
|
||||
Show:
|
||||
{t("incidentsOptionsHeaderShow")}
|
||||
</Typography>
|
||||
<ButtonGroup>
|
||||
<Button
|
||||
@@ -101,28 +103,28 @@ const OptionsHeader = ({
|
||||
filled={(dateRange === "hour").toString()}
|
||||
onClick={() => setDateRange("hour")}
|
||||
>
|
||||
Last hour
|
||||
{t("incidentsOptionsHeaderLastHour")}
|
||||
</Button>
|
||||
<Button
|
||||
variant="group"
|
||||
filled={(dateRange === "day").toString()}
|
||||
onClick={() => setDateRange("day")}
|
||||
>
|
||||
Last day
|
||||
{t("incidentsOptionsHeaderLastDay")}
|
||||
</Button>
|
||||
<Button
|
||||
variant="group"
|
||||
filled={(dateRange === "week").toString()}
|
||||
onClick={() => setDateRange("week")}
|
||||
>
|
||||
Last week
|
||||
{t("incidentsOptionsHeaderLastWeek")}
|
||||
</Button>
|
||||
<Button
|
||||
variant="group"
|
||||
filled={(dateRange === "all").toString()}
|
||||
onClick={() => setDateRange("all")}
|
||||
>
|
||||
All
|
||||
{t("incidentsOptionsHeaderFilterAll")}
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</Stack>
|
||||
|
||||
@@ -8,6 +8,7 @@ import { useSelector, useDispatch } from "react-redux";
|
||||
import { infrastructureMonitorValidation } from "../../../Validation/validation";
|
||||
import { createInfrastructureMonitor } from "../../../Features/InfrastructureMonitors/infrastructureMonitorsSlice";
|
||||
import { capitalizeFirstLetter } from "../../../Utils/stringUtils";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
// MUI
|
||||
import { Box, Stack, Typography, Button, ButtonGroup } from "@mui/material";
|
||||
@@ -52,6 +53,7 @@ const CreateInfrastructureMonitor = () => {
|
||||
const monitorState = useSelector((state) => state.infrastructureMonitor);
|
||||
const dispatch = useDispatch();
|
||||
const navigate = useNavigate();
|
||||
const { t } = useTranslation();
|
||||
|
||||
// State
|
||||
const [errors, setErrors] = useState({});
|
||||
@@ -233,7 +235,7 @@ const CreateInfrastructureMonitor = () => {
|
||||
component="span"
|
||||
fontSize="inherit"
|
||||
>
|
||||
Create your{" "}
|
||||
{t("infrastructureCreateYour")}{" "}
|
||||
</Typography>
|
||||
<Typography
|
||||
component="span"
|
||||
@@ -241,18 +243,17 @@ const CreateInfrastructureMonitor = () => {
|
||||
fontSize="inherit"
|
||||
fontWeight="inherit"
|
||||
>
|
||||
monitor
|
||||
{t("monitor")}
|
||||
</Typography>
|
||||
</Typography>
|
||||
<ConfigBox>
|
||||
<Stack gap={theme.spacing(6)}>
|
||||
<Typography component="h2">General settings</Typography>
|
||||
<Typography component="h2">{t("settingsGeneralSettings")}</Typography>
|
||||
<Typography component="p">
|
||||
Here you can select the URL of the host, together with the friendly name and
|
||||
authorization secret to connect to the server agent.
|
||||
{t("infrastructureCreateGeneralSettingsDescription")}
|
||||
</Typography>
|
||||
<Typography component="p">
|
||||
The server you are monitoring must be running the{" "}
|
||||
{t("infrastructureServerRequirement")}{" "}
|
||||
<Link
|
||||
level="primary"
|
||||
url="https://github.com/bluewave-labs/checkmate-agent"
|
||||
@@ -267,7 +268,7 @@ const CreateInfrastructureMonitor = () => {
|
||||
name="url"
|
||||
startAdornment={<HttpAdornment https={https} />}
|
||||
placeholder={"localhost:59232/api/v1/metrics"}
|
||||
label="Server URL"
|
||||
label={t("infrastructureServerUrlLabel")}
|
||||
https={https}
|
||||
value={infrastructureMonitor.url}
|
||||
onChange={handleChange}
|
||||
@@ -275,21 +276,21 @@ const CreateInfrastructureMonitor = () => {
|
||||
helperText={errors["url"]}
|
||||
/>
|
||||
<Box>
|
||||
<Typography component="p">Protocol</Typography>
|
||||
<Typography component="p">{t("infrastructureProtocol")}</Typography>
|
||||
<ButtonGroup>
|
||||
<Button
|
||||
variant="group"
|
||||
filled={https.toString()}
|
||||
onClick={() => setHttps(true)}
|
||||
>
|
||||
HTTPS
|
||||
{t("https")}
|
||||
</Button>
|
||||
<Button
|
||||
variant="group"
|
||||
filled={(!https).toString()}
|
||||
onClick={() => setHttps(false)}
|
||||
>
|
||||
HTTP
|
||||
{t("http")}
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</Box>
|
||||
@@ -297,7 +298,7 @@ const CreateInfrastructureMonitor = () => {
|
||||
type="text"
|
||||
id="name"
|
||||
name="name"
|
||||
label="Display name"
|
||||
label={t("infrastructureDisplayNameLabel")}
|
||||
placeholder="Google"
|
||||
isOptional={true}
|
||||
value={infrastructureMonitor.name}
|
||||
@@ -308,7 +309,7 @@ const CreateInfrastructureMonitor = () => {
|
||||
type="text"
|
||||
id="secret"
|
||||
name="secret"
|
||||
label="Authorization secret"
|
||||
label={t("infrastructureAuthorizationSecretLabel")}
|
||||
value={infrastructureMonitor.secret}
|
||||
onChange={handleChange}
|
||||
error={errors["secret"] ? true : false}
|
||||
@@ -318,9 +319,9 @@ const CreateInfrastructureMonitor = () => {
|
||||
</ConfigBox>
|
||||
<ConfigBox>
|
||||
<Box>
|
||||
<Typography component="h2">Incident notifications</Typography>
|
||||
<Typography component="h2">{t("distributedUptimeCreateIncidentNotification")}</Typography>
|
||||
<Typography component="p">
|
||||
When there is an incident, notify users.
|
||||
{t("distributedUptimeCreateIncidentDescription")}
|
||||
</Typography>
|
||||
</Box>
|
||||
<Stack gap={theme.spacing(6)}>
|
||||
@@ -337,10 +338,9 @@ const CreateInfrastructureMonitor = () => {
|
||||
</ConfigBox>
|
||||
<ConfigBox>
|
||||
<Box>
|
||||
<Typography component="h2">Customize alerts</Typography>
|
||||
<Typography component="h2">{t("infrastructureCustomizeAlerts")}</Typography>
|
||||
<Typography component="p">
|
||||
Send a notification to user(s) when thresholds exceed a specified
|
||||
percentage.
|
||||
{t("infrastructureAlertNotificationDescription")}
|
||||
</Typography>
|
||||
</Box>
|
||||
<Stack gap={theme.spacing(6)}>
|
||||
@@ -385,7 +385,7 @@ const CreateInfrastructureMonitor = () => {
|
||||
</ConfigBox>
|
||||
<ConfigBox>
|
||||
<Box>
|
||||
<Typography component="h2">Advanced settings</Typography>
|
||||
<Typography component="h2">{t("distributedUptimeCreateAdvancedSettings")}</Typography>
|
||||
</Box>
|
||||
<Stack gap={theme.spacing(12)}>
|
||||
<Select
|
||||
@@ -408,7 +408,7 @@ const CreateInfrastructureMonitor = () => {
|
||||
onClick={handleCreateInfrastructureMonitor}
|
||||
loading={monitorState?.isLoading}
|
||||
>
|
||||
Create infrastructure monitor
|
||||
{t("infrastructureCreateMonitor")}
|
||||
</Button>
|
||||
</Stack>
|
||||
</Stack>
|
||||
|
||||
@@ -12,8 +12,10 @@ import {
|
||||
} from "../../../../../Components/Charts/Utils/chartUtils";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import { useHardwareUtils } from "../../Hooks/useHardwareUtils";
|
||||
import { useTranslation } from "react-i18next";
|
||||
const AreaChartBoxes = ({ shouldRender, monitor, dateRange }) => {
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation();
|
||||
const { buildTemps } = useHardwareUtils();
|
||||
|
||||
if (!shouldRender) {
|
||||
@@ -31,10 +33,10 @@ const AreaChartBoxes = ({ shouldRender, monitor, dateRange }) => {
|
||||
type: "memory",
|
||||
data: checks,
|
||||
dataKeys: ["avgMemoryUsage"],
|
||||
heading: "Memory usage",
|
||||
heading: t("memoryUsage"),
|
||||
strokeColor: theme.palette.accent.main, // CAIO_REVIEW
|
||||
gradientStartColor: theme.palette.accent.main, // CAIO_REVIEW
|
||||
yLabel: "Memory usage",
|
||||
yLabel: t("memoryUsage"),
|
||||
yDomain: [0, 1],
|
||||
yTick: <PercentTick />,
|
||||
xTick: <TzTick dateRange={dateRange} />,
|
||||
@@ -51,10 +53,10 @@ const AreaChartBoxes = ({ shouldRender, monitor, dateRange }) => {
|
||||
type: "cpu",
|
||||
data: checks,
|
||||
dataKeys: ["avgCpuUsage"],
|
||||
heading: "CPU usage",
|
||||
heading: t("cpuUsage"),
|
||||
strokeColor: theme.palette.success.main,
|
||||
gradientStartColor: theme.palette.success.main,
|
||||
yLabel: "CPU usage",
|
||||
yLabel: t("cpuUsage"),
|
||||
yDomain: [0, 1],
|
||||
yTick: <PercentTick />,
|
||||
xTick: <TzTick dateRange={dateRange} />,
|
||||
@@ -73,7 +75,7 @@ const AreaChartBoxes = ({ shouldRender, monitor, dateRange }) => {
|
||||
dataKeys: tempKeys,
|
||||
strokeColor: theme.palette.error.main,
|
||||
gradientStartColor: theme.palette.error.main,
|
||||
heading: "CPU Temperature",
|
||||
heading: t("cpuTemperature"),
|
||||
yLabel: "Temperature",
|
||||
xTick: <TzTick dateRange={dateRange} />,
|
||||
yDomain: [
|
||||
@@ -96,7 +98,7 @@ const AreaChartBoxes = ({ shouldRender, monitor, dateRange }) => {
|
||||
heading: `Disk${idx} usage`,
|
||||
strokeColor: theme.palette.warning.main,
|
||||
gradientStartColor: theme.palette.warning.main,
|
||||
yLabel: "Disk Usage",
|
||||
yLabel: t("diskUsage"),
|
||||
yDomain: [0, 1],
|
||||
yTick: <PercentTick />,
|
||||
xTick: <TzTick dateRange={dateRange} />,
|
||||
|
||||
@@ -6,10 +6,12 @@ import SkeletonLayout from "./skeleton";
|
||||
// Utils
|
||||
import { useHardwareUtils } from "../../Hooks/useHardwareUtils";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const Gauges = ({ shouldRender, monitor }) => {
|
||||
const { decimalToPercentage, formatBytes } = useHardwareUtils();
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation();
|
||||
|
||||
if (!shouldRender) {
|
||||
return <SkeletonLayout />;
|
||||
@@ -28,19 +30,19 @@ const Gauges = ({ shouldRender, monitor }) => {
|
||||
{
|
||||
type: "memory",
|
||||
value: decimalToPercentage(memoryUsagePercent),
|
||||
heading: "Memory usage",
|
||||
metricOne: "Used",
|
||||
heading: t("memoryUsage"),
|
||||
metricOne: t("used"),
|
||||
valueOne: formatBytes(memoryUsedBytes, true),
|
||||
metricTwo: "Total",
|
||||
metricTwo: t("total"),
|
||||
valueTwo: formatBytes(memoryTotalBytes, true),
|
||||
},
|
||||
{
|
||||
type: "cpu",
|
||||
value: decimalToPercentage(cpuUsagePercent),
|
||||
heading: "CPU usage",
|
||||
metricOne: "Cores",
|
||||
heading: t("cpuUsage"),
|
||||
metricOne: t("cores"),
|
||||
valueOne: cpuPhysicalCores ?? 0,
|
||||
metricTwo: "Frequency",
|
||||
metricTwo: t("frequency"),
|
||||
valueTwo: `${(cpuFrequency / 1000).toFixed(2)} Ghz`,
|
||||
},
|
||||
...(latestCheck?.disk ?? []).map((disk, idx) => ({
|
||||
@@ -48,9 +50,9 @@ const Gauges = ({ shouldRender, monitor }) => {
|
||||
diskIndex: idx,
|
||||
value: decimalToPercentage(disk.usage_percent),
|
||||
heading: `Disk${idx} usage`,
|
||||
metricOne: "Used",
|
||||
metricOne: t("used"),
|
||||
valueOne: formatBytes(disk.total_bytes - disk.free_bytes, true),
|
||||
metricTwo: "Total",
|
||||
metricTwo: t("total"),
|
||||
valueTwo: formatBytes(disk.total_bytes, true),
|
||||
})),
|
||||
];
|
||||
|
||||
@@ -6,11 +6,13 @@ import StatBox from "../../../../../Components/StatBox";
|
||||
//Utils
|
||||
import useUtils from "../../../../../Pages/Uptime/Monitors/Hooks/useUtils";
|
||||
import { useHardwareUtils } from "../../Hooks/useHardwareUtils";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const InfraStatBoxes = ({ shouldRender, monitor }) => {
|
||||
// Utils
|
||||
const { formatBytes } = useHardwareUtils();
|
||||
const { statusStyles, determineState } = useUtils();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { stats, uptimePercentage } = monitor ?? {};
|
||||
const latestCheck = stats?.aggregateData?.latestCheck;
|
||||
@@ -40,11 +42,11 @@ const InfraStatBoxes = ({ shouldRender, monitor }) => {
|
||||
>
|
||||
<StatBox
|
||||
sx={statusStyles[determineState(monitor)]}
|
||||
heading="Status"
|
||||
heading={t("status")}
|
||||
subHeading={determineState(monitor)}
|
||||
/>
|
||||
<StatBox
|
||||
heading="CPU (Physical)"
|
||||
heading={t("cpuPhysical")}
|
||||
subHeading={
|
||||
<>
|
||||
{physicalCores}
|
||||
@@ -54,7 +56,7 @@ const InfraStatBoxes = ({ shouldRender, monitor }) => {
|
||||
/>
|
||||
<StatBox
|
||||
key={2}
|
||||
heading="CPU (Logical)"
|
||||
heading={t("cpuLogical")}
|
||||
subHeading={
|
||||
<>
|
||||
{logicalCores}
|
||||
@@ -63,7 +65,7 @@ const InfraStatBoxes = ({ shouldRender, monitor }) => {
|
||||
}
|
||||
/>
|
||||
<StatBox
|
||||
heading="CPU Frequency"
|
||||
heading={t("cpuFrequency")}
|
||||
subHeading={
|
||||
<>
|
||||
{(cpuFrequency / 1000).toFixed(2)}
|
||||
@@ -72,7 +74,7 @@ const InfraStatBoxes = ({ shouldRender, monitor }) => {
|
||||
}
|
||||
/>
|
||||
<StatBox
|
||||
heading="Average CPU Temperature"
|
||||
heading={t("avgCpuTemperature")}
|
||||
subHeading={
|
||||
<>
|
||||
{cpuTemperature.toFixed(2)}
|
||||
@@ -81,15 +83,15 @@ const InfraStatBoxes = ({ shouldRender, monitor }) => {
|
||||
}
|
||||
/>
|
||||
<StatBox
|
||||
heading="Memory"
|
||||
heading={t("memory")}
|
||||
subHeading={formatBytes(memoryTotalBytes)}
|
||||
/>
|
||||
<StatBox
|
||||
heading="Disk"
|
||||
heading={t("disk")}
|
||||
subHeading={formatBytes(diskTotalBytes)}
|
||||
/>
|
||||
<StatBox
|
||||
heading="Uptime"
|
||||
heading={t("uptime")}
|
||||
subHeading={
|
||||
<>
|
||||
{(uptimePercentage * 100).toFixed(2)}
|
||||
@@ -99,7 +101,7 @@ const InfraStatBoxes = ({ shouldRender, monitor }) => {
|
||||
/>
|
||||
<StatBox
|
||||
key={8}
|
||||
heading="OS"
|
||||
heading={t("os")}
|
||||
subHeading={osPlatform}
|
||||
/>
|
||||
</StatusBoxes>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Typography } from "@mui/material";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
// Constants
|
||||
const BASE_BOX_PADDING_VERTICAL = 4;
|
||||
@@ -9,6 +10,7 @@ const CHART_CONTAINER_HEIGHT = 300;
|
||||
|
||||
const useHardwareUtils = () => {
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const getDimensions = () => {
|
||||
const totalTypographyPadding = parseInt(theme.spacing(TYPOGRAPHY_PADDING), 10) * 2;
|
||||
@@ -29,7 +31,7 @@ const useHardwareUtils = () => {
|
||||
<>
|
||||
{0}
|
||||
{space ? " " : ""}
|
||||
<Typography component="span">GB</Typography>
|
||||
<Typography component="span">{t("gb")}</Typography>
|
||||
</>
|
||||
);
|
||||
if (typeof bytes !== "number")
|
||||
@@ -37,7 +39,7 @@ const useHardwareUtils = () => {
|
||||
<>
|
||||
{0}
|
||||
{space ? " " : ""}
|
||||
<Typography component="span">GB</Typography>
|
||||
<Typography component="span">{t("gb")}</Typography>
|
||||
</>
|
||||
);
|
||||
if (bytes === 0)
|
||||
@@ -45,7 +47,7 @@ const useHardwareUtils = () => {
|
||||
<>
|
||||
{0}
|
||||
{space ? " " : ""}
|
||||
<Typography component="span">GB</Typography>
|
||||
<Typography component="span">{t("gb")}</Typography>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -57,7 +59,7 @@ const useHardwareUtils = () => {
|
||||
<>
|
||||
{Number(GB.toFixed(0))}
|
||||
{space ? " " : ""}
|
||||
<Typography component="span">GB</Typography>
|
||||
<Typography component="span">{t("gb")}</Typography>
|
||||
</>
|
||||
);
|
||||
} else {
|
||||
@@ -65,7 +67,7 @@ const useHardwareUtils = () => {
|
||||
<>
|
||||
{Number(MB.toFixed(0))}
|
||||
{space ? " " : ""}
|
||||
<Typography component="span">MB</Typography>
|
||||
<Typography component="span">{t("mb")}</Typography>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import { useTheme } from "@emotion/react";
|
||||
import { useIsAdmin } from "../../../Hooks/useIsAdmin";
|
||||
import { useHardwareMonitorsFetch } from "./Hooks/useHardwareMonitorsFetch";
|
||||
import { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useParams } from "react-router-dom";
|
||||
|
||||
// Constants
|
||||
@@ -29,6 +30,7 @@ const InfrastructureDetails = () => {
|
||||
// Utils
|
||||
const theme = useTheme();
|
||||
const { monitorId } = useParams();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { isLoading, networkError, monitor } = useHardwareMonitorsFetch({
|
||||
monitorId,
|
||||
@@ -43,9 +45,9 @@ const InfrastructureDetails = () => {
|
||||
marginY={theme.spacing(4)}
|
||||
color={theme.palette.primary.contrastTextTertiary}
|
||||
>
|
||||
Network error
|
||||
{t("networkError")}
|
||||
</Typography>
|
||||
<Typography>Please check your connection</Typography>
|
||||
<Typography>{t("checkConnection")}</Typography>
|
||||
</GenericFallback>
|
||||
);
|
||||
}
|
||||
@@ -61,7 +63,7 @@ const InfrastructureDetails = () => {
|
||||
monitor={monitor}
|
||||
/>
|
||||
<GenericFallback>
|
||||
<Typography>No check history for this monitor yet.</Typography>
|
||||
<Typography>{t("distributedUptimeDetailsNoMonitorHistory")}</Typography>
|
||||
</GenericFallback>
|
||||
</Stack>
|
||||
);
|
||||
|
||||
@@ -13,10 +13,12 @@ import { useTheme } from "@emotion/react";
|
||||
import useUtils from "../../../../Uptime/Monitors/Hooks/useUtils";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import PropTypes from "prop-types";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const MonitorsTable = ({ shouldRender, monitors, isAdmin, handleActionMenuDelete }) => {
|
||||
// Utils
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation();
|
||||
const { determineState } = useUtils();
|
||||
const navigate = useNavigate();
|
||||
|
||||
@@ -27,7 +29,7 @@ const MonitorsTable = ({ shouldRender, monitors, isAdmin, handleActionMenuDelete
|
||||
const headers = [
|
||||
{
|
||||
id: "host",
|
||||
content: "Host",
|
||||
content: t("host"),
|
||||
render: (row) => (
|
||||
<Host
|
||||
title={row.name}
|
||||
@@ -39,7 +41,7 @@ const MonitorsTable = ({ shouldRender, monitors, isAdmin, handleActionMenuDelete
|
||||
},
|
||||
{
|
||||
id: "status",
|
||||
content: "Status",
|
||||
content: t("incidentsTableStatus"),
|
||||
render: (row) => (
|
||||
<StatusLabel
|
||||
status={row.status}
|
||||
@@ -49,7 +51,7 @@ const MonitorsTable = ({ shouldRender, monitors, isAdmin, handleActionMenuDelete
|
||||
},
|
||||
{
|
||||
id: "frequency",
|
||||
content: "Frequency",
|
||||
content: t("frequency"),
|
||||
render: (row) => (
|
||||
<Stack
|
||||
direction={"row"}
|
||||
@@ -65,12 +67,12 @@ const MonitorsTable = ({ shouldRender, monitors, isAdmin, handleActionMenuDelete
|
||||
</Stack>
|
||||
),
|
||||
},
|
||||
{ id: "cpu", content: "CPU", render: (row) => <CustomGauge progress={row.cpu} /> },
|
||||
{ id: "mem", content: "Mem", render: (row) => <CustomGauge progress={row.mem} /> },
|
||||
{ id: "disk", content: "Disk", render: (row) => <CustomGauge progress={row.disk} /> },
|
||||
{ id: "cpu", content: t("cpu"), render: (row) => <CustomGauge progress={row.cpu} /> },
|
||||
{ id: "mem", content: t("mem"), render: (row) => <CustomGauge progress={row.mem} /> },
|
||||
{ id: "disk", content: t("disk"), render: (row) => <CustomGauge progress={row.disk} /> },
|
||||
{
|
||||
id: "actions",
|
||||
content: "Actions",
|
||||
content: t("actions"),
|
||||
render: (row) => (
|
||||
<InfrastructureMenu
|
||||
monitor={row}
|
||||
|
||||
@@ -12,6 +12,7 @@ import { useTheme } from "@emotion/react";
|
||||
import { useMonitorFetch } from "./Hooks/useMonitorFetch";
|
||||
import { useState } from "react";
|
||||
import { useIsAdmin } from "../../../Hooks/useIsAdmin";
|
||||
import { useTranslation } from "react-i18next";
|
||||
// Constants
|
||||
const BREADCRUMBS = [{ name: `infrastructure`, path: "/infrastructure" }];
|
||||
|
||||
@@ -24,6 +25,7 @@ const InfrastructureMonitors = () => {
|
||||
// Utils
|
||||
const theme = useTheme();
|
||||
const isAdmin = useIsAdmin();
|
||||
const { t } = useTranslation();
|
||||
|
||||
// Handlers
|
||||
const handleActionMenuDelete = () => {
|
||||
@@ -52,9 +54,9 @@ const InfrastructureMonitors = () => {
|
||||
marginY={theme.spacing(4)}
|
||||
color={theme.palette.primary.contrastTextTertiary}
|
||||
>
|
||||
Network error
|
||||
{t("networkError")}
|
||||
</Typography>
|
||||
<Typography>Please check your connection</Typography>
|
||||
<Typography>{t("checkConnection")}</Typography>
|
||||
</GenericFallback>
|
||||
);
|
||||
}
|
||||
@@ -96,7 +98,7 @@ const InfrastructureMonitors = () => {
|
||||
/>
|
||||
<Pagination
|
||||
itemCount={summary?.totalMonitors}
|
||||
paginationLabel="monitors"
|
||||
paginationLabel={t("monitors")}
|
||||
page={page}
|
||||
rowsPerPage={rowsPerPage}
|
||||
handleChangePage={handleChangePage}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useTheme } from "@emotion/react";
|
||||
import Discord from "../../assets/icons/discord-icon.svg?react";
|
||||
import Slack from "../../assets/icons/slack-icon.svg?react";
|
||||
import Zapier from "../../assets/icons/zapier-icon.svg?react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import "./index.css";
|
||||
|
||||
@@ -18,6 +19,7 @@ import "./index.css";
|
||||
*/
|
||||
const IntegrationsComponent = ({ icon, header, info, onClick }) => {
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<Grid
|
||||
@@ -59,7 +61,7 @@ const IntegrationsComponent = ({ icon, header, info, onClick }) => {
|
||||
sx={{ alignSelf: "center" }}
|
||||
disabled={true}
|
||||
>
|
||||
Add
|
||||
{t("add")}
|
||||
</Button>
|
||||
</Stack>
|
||||
</Grid>
|
||||
@@ -81,6 +83,7 @@ IntegrationsComponent.propTypes = {
|
||||
|
||||
const Integrations = () => {
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const integrations = [
|
||||
{
|
||||
@@ -90,8 +93,8 @@ const Integrations = () => {
|
||||
style={{ width: "45px", height: "45px", alignSelf: "center" }}
|
||||
/>
|
||||
),
|
||||
header: "Slack",
|
||||
info: "Connect with Slack and see incidents in a channel",
|
||||
header: t("integrationsSlack"),
|
||||
info: t("integrationsSlackInfo"),
|
||||
onClick: () => {},
|
||||
},
|
||||
{
|
||||
@@ -101,8 +104,8 @@ const Integrations = () => {
|
||||
style={{ width: "42px", height: "42px", alignSelf: "center" }}
|
||||
/>
|
||||
),
|
||||
header: "Discord",
|
||||
info: "Connect with Discord and view incidents directly in a channel",
|
||||
header: t("integrationsDiscord"),
|
||||
info: t("integrationsDiscordInfo"),
|
||||
onClick: () => {},
|
||||
},
|
||||
{
|
||||
@@ -112,8 +115,8 @@ const Integrations = () => {
|
||||
style={{ width: "42px", height: "42px", alignSelf: "center" }}
|
||||
/>
|
||||
),
|
||||
header: "Zapier",
|
||||
info: "Send all incidents to Zapier, and then see them everywhere",
|
||||
header: t("integrationsZapier"),
|
||||
info: t("integrationsZapierInfo"),
|
||||
onClick: () => {},
|
||||
},
|
||||
// Add more integrations as needed
|
||||
@@ -130,9 +133,9 @@ const Integrations = () => {
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Typography component="h1">Integrations</Typography>
|
||||
<Typography component="h1">{t("integrations")}</Typography>
|
||||
<Typography mb={theme.spacing(12)}>
|
||||
Connect Prism to your favorite service.
|
||||
{t("integrationsPrism")}
|
||||
</Typography>
|
||||
<Grid
|
||||
container
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
// Required Data
|
||||
// 1. Monitor summary
|
||||
// 2. List of monitors filtered by search term with 25 checks each
|
||||
// 2a.List of monitors must have the total number of monitors that match.
|
||||
|
||||
// Components
|
||||
import Breadcrumbs from "../../../Components/Breadcrumbs";
|
||||
import Greeting from "../../../Utils/greeting";
|
||||
@@ -23,9 +28,11 @@ import useMonitorsFetch from "./Hooks/useMonitorsFetch";
|
||||
import { useSelector, useDispatch } from "react-redux";
|
||||
import { setRowsPerPage } from "../../../Features/UI/uiSlice";
|
||||
import PropTypes from "prop-types";
|
||||
import useFetchMonitorsWithSummary from "../../../Hooks/useFetchMonitorsWithSummary";
|
||||
import useFetchMonitorsWithChecks from "../../../Hooks/useFetchMonitorsWithChecks";
|
||||
|
||||
const BREADCRUMBS = [{ name: `Uptime`, path: "/uptime" }];
|
||||
|
||||
const TYPES = ["http", "ping", "docker", "port"];
|
||||
const CreateMonitorButton = ({ shouldRender }) => {
|
||||
// Utils
|
||||
const navigate = useNavigate();
|
||||
@@ -89,23 +96,32 @@ const UptimeMonitors = () => {
|
||||
}, []);
|
||||
|
||||
const teamId = user.teamId;
|
||||
const {
|
||||
monitorsAreLoading,
|
||||
monitors,
|
||||
filteredMonitors,
|
||||
monitorsSummary,
|
||||
networkError,
|
||||
} = useMonitorsFetch({
|
||||
|
||||
const [monitors, monitorsSummary, monitorsWithSummaryIsLoading, networkError] =
|
||||
useFetchMonitorsWithSummary({
|
||||
teamId,
|
||||
types: TYPES,
|
||||
});
|
||||
|
||||
const [
|
||||
monitorsWithChecks,
|
||||
monitorsWithChecksCount,
|
||||
monitorsWithChecksIsLoading,
|
||||
monitorsWithChecksNetworkError,
|
||||
] = useFetchMonitorsWithChecks({
|
||||
teamId,
|
||||
types: TYPES,
|
||||
limit: 25,
|
||||
page: page,
|
||||
rowsPerPage: rowsPerPage,
|
||||
filter: search,
|
||||
field: sort?.field,
|
||||
order: sort?.order,
|
||||
triggerUpdate: monitorUpdateTrigger,
|
||||
triggerUpdate,
|
||||
});
|
||||
const totalMonitors = monitorsSummary?.totalMonitors;
|
||||
|
||||
const isLoading = monitorsWithSummaryIsLoading || monitorsWithChecksIsLoading;
|
||||
|
||||
if (networkError) {
|
||||
return (
|
||||
<GenericFallback>
|
||||
@@ -121,8 +137,9 @@ const UptimeMonitors = () => {
|
||||
);
|
||||
}
|
||||
if (
|
||||
!monitorsAreLoading &&
|
||||
(totalMonitors === 0 || typeof totalMonitors === "undefined")
|
||||
!isLoading &&
|
||||
(monitorsSummary?.totalMonitors === 0 ||
|
||||
typeof monitorsSummary?.totalMonitors === "undefined")
|
||||
) {
|
||||
return (
|
||||
<Fallback
|
||||
@@ -147,19 +164,19 @@ const UptimeMonitors = () => {
|
||||
<Breadcrumbs list={BREADCRUMBS} />
|
||||
<CreateMonitorHeader
|
||||
isAdmin={isAdmin}
|
||||
shouldRender={!monitorsAreLoading}
|
||||
shouldRender={!isLoading}
|
||||
path="/uptime/create"
|
||||
/>
|
||||
<Greeting type="uptime" />
|
||||
<StatusBoxes
|
||||
monitorsSummary={monitorsSummary}
|
||||
shouldRender={!monitorsAreLoading}
|
||||
shouldRender={!monitorsWithSummaryIsLoading}
|
||||
/>
|
||||
|
||||
<Stack direction={"row"}>
|
||||
<MonitorCountHeader
|
||||
shouldRender={monitors?.length > 0 && !monitorsAreLoading}
|
||||
monitorCount={totalMonitors}
|
||||
shouldRender={monitors?.length > 0 && !monitorsWithSummaryIsLoading}
|
||||
monitorCount={monitorsSummary?.totalMonitors}
|
||||
heading={"Uptime monitors"}
|
||||
></MonitorCountHeader>
|
||||
<SearchComponent
|
||||
@@ -170,19 +187,14 @@ const UptimeMonitors = () => {
|
||||
</Stack>
|
||||
<UptimeDataTable
|
||||
isAdmin={isAdmin}
|
||||
isLoading={monitorsAreLoading}
|
||||
filteredMonitors={filteredMonitors}
|
||||
monitors={monitors}
|
||||
monitorCount={totalMonitors}
|
||||
isSearching={isSearching}
|
||||
filteredMonitors={monitorsWithChecks}
|
||||
sort={sort}
|
||||
setSort={setSort}
|
||||
setSearch={setSearch}
|
||||
isSearching={isSearching}
|
||||
monitorsAreLoading={monitorsAreLoading}
|
||||
triggerUpdate={triggerUpdate}
|
||||
monitorsAreLoading={monitorsWithChecksIsLoading}
|
||||
/>
|
||||
<Pagination
|
||||
itemCount={totalMonitors}
|
||||
itemCount={monitorsWithChecksCount}
|
||||
paginationLabel="monitors"
|
||||
page={page}
|
||||
rowsPerPage={rowsPerPage}
|
||||
|
||||
@@ -1033,6 +1033,58 @@ class NetworkService {
|
||||
|
||||
return this.axiosInstance.delete(`/status-page/${encodedUrl}`, {});
|
||||
}
|
||||
|
||||
// ************************************
|
||||
// Fetch monitors with summary by TeamID
|
||||
// ************************************
|
||||
async getMonitorsWithSummaryByTeamId(config) {
|
||||
const { teamId, types } = config;
|
||||
const params = new URLSearchParams();
|
||||
|
||||
if (types) {
|
||||
types.forEach((type) => {
|
||||
params.append("type", type);
|
||||
});
|
||||
}
|
||||
|
||||
return this.axiosInstance.get(
|
||||
`/monitors/summary/team/${teamId}?${params.toString()}`,
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// ************************************
|
||||
// Fetch monitors with checks by TeamID
|
||||
// ************************************
|
||||
async getMonitorsWithChecksByTeamId(config) {
|
||||
const { teamId, limit, types, page, rowsPerPage, filter, field, order } = config;
|
||||
const params = new URLSearchParams();
|
||||
|
||||
if (limit) params.append("limit", limit);
|
||||
if (types) {
|
||||
types.forEach((type) => {
|
||||
params.append("type", type);
|
||||
});
|
||||
}
|
||||
if (page) params.append("page", page);
|
||||
if (rowsPerPage) params.append("rowsPerPage", rowsPerPage);
|
||||
if (filter) params.append("filter", filter);
|
||||
if (field) params.append("field", field);
|
||||
if (order) params.append("order", order);
|
||||
|
||||
return this.axiosInstance.get(
|
||||
`/monitors/team/${teamId}/with-checks?${params.toString()}`,
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default NetworkService;
|
||||
|
||||
+177
-176
@@ -1,178 +1,179 @@
|
||||
{
|
||||
"dontHaveAccount": "Don't have account",
|
||||
"https": "HTTPS",
|
||||
"http": "HTTP",
|
||||
"monitor": "monitor",
|
||||
"aboutus": "About Us",
|
||||
"email": "E-mail",
|
||||
"forgotPassword": "Forgot Password",
|
||||
"password": "password",
|
||||
"signUp": "Sign up",
|
||||
"signUP": "Sign Up",
|
||||
"submit": "Submit",
|
||||
"title": "Title",
|
||||
"continue": "Continue",
|
||||
"now": "Now",
|
||||
"delete": "Delete",
|
||||
"configure": "Configure",
|
||||
"networkError": "Network error",
|
||||
"responseTime": "Response time:",
|
||||
"ms": "ms",
|
||||
"bar": "Bar",
|
||||
"area": "Area",
|
||||
"country": "COUNTRY",
|
||||
"city": "CITY",
|
||||
"response": "RESPONSE",
|
||||
"checkConnection": "Please check your connection",
|
||||
"enterEmail": "Enter your email",
|
||||
"authLoginTitle": "Log In",
|
||||
"authLoginEnterPassword": "Enter your password",
|
||||
"commonPassword": "Password",
|
||||
"createPassword": "Create your password",
|
||||
"createAPassword": "Create a password",
|
||||
"commonBack": "Back",
|
||||
"authForgotPasswordTitle": "Forgot password?",
|
||||
"authForgotPasswordResetPassword": "Reset password",
|
||||
"passwordreset": "Password Reset",
|
||||
"authRegisterAlreadyHaveAccount": "Already have an account?",
|
||||
"commonAppName": "Checkmate",
|
||||
"authLoginEnterEmail": "Enter your email",
|
||||
"authRegisterTitle": "Create an account",
|
||||
"authRegisterStepOneTitle": "Create your account",
|
||||
"authRegisterStepOnePersonalDetails": "Enter your personal details",
|
||||
"authRegisterStepOneDescription": "Enter your details to get started",
|
||||
"authRegisterStepTwoTitle": "Set up your profile",
|
||||
"authRegisterStepTwoDescription": "Tell us more about yourself",
|
||||
"authRegisterStepThreeTitle": "Almost done!",
|
||||
"authRegisterStepThreeDescription": "Review your information",
|
||||
"authForgotPasswordDescription": "No worries, we'll send you reset instructions.",
|
||||
"authForgotPasswordSendInstructions": "Send instructions",
|
||||
"authForgotPasswordBackTo": "Back to",
|
||||
"authCheckEmailTitle": "Check your email",
|
||||
"authCheckEmailDescription": "We sent a password reset link to",
|
||||
"authCheckEmailResendEmail": "Resend email",
|
||||
"authCheckEmailBackTo": "Back to",
|
||||
"authCheckEmailOpenEmailButton": "Open email app",
|
||||
"goBackTo": "Go back to",
|
||||
"authCheckEmailDidntReceiveEmail": "Didn't receive the email?",
|
||||
"authCheckEmailClickToResend": "Click to resend",
|
||||
"authSetNewPasswordTitle": "Set new password",
|
||||
"authSetNewPasswordDescription": "Your new password must be different from previously used passwords.",
|
||||
"authSetNewPasswordNewPassword": "New password",
|
||||
"authSetNewPasswordConfirmPassword": "Confirm password",
|
||||
"confirmPassword": "Confirm your password",
|
||||
"authSetNewPasswordResetPassword": "Reset password",
|
||||
"authNewPasswordConfirmed": "Your password has been successfully reset. Click below to log in magically.",
|
||||
"authSetNewPasswordBackTo": "Back to",
|
||||
"authPasswordMustBeAtLeast": "Must be at least",
|
||||
"authPasswordCharactersLong": "8 characters long",
|
||||
"authPasswordMustContainAtLeast": "Must contain at least",
|
||||
"authPasswordSpecialCharacter": "one special character",
|
||||
"authPasswordOneNumber": "one number",
|
||||
"authPasswordUpperCharacter": "one upper character",
|
||||
"authPasswordLowerCharacter": "one lower character",
|
||||
"authPasswordConfirmAndPassword": "Confirm password and password",
|
||||
"authPasswordMustMatch": "must match",
|
||||
"authRegisterCreateAccount": "Create your account to get started",
|
||||
"authRegisterCreateSuperAdminAccount": "Create your Super admin account to get started",
|
||||
"authRegisterSignUpWithEmail": "Sign up with Email",
|
||||
"authRegisterBySigningUp": "By signing up, you agree to our",
|
||||
"monitorStatusUp": "Monitor {name} ({url}) is now UP and responding",
|
||||
"monitorStatusDown": "Monitor {name} ({url}) is DOWN and not responding",
|
||||
"webhookSendSuccess": "Webhook notification sent successfully",
|
||||
"webhookSendError": "Error sending webhook notification to {platform}",
|
||||
"webhookUnsupportedPlatform": "Unsupported platform: {platform}",
|
||||
"distributedStatusHeaderText": "Real-time, real-device coverage",
|
||||
"distributedStatusSubHeaderText": "Powered by millions devices worldwide, view a system performance by global region, country or city",
|
||||
"distributedRightCategoryTitle": "Monitor",
|
||||
"distributedStatusServerMonitors": "Server Monitors",
|
||||
"distributedStatusServerMonitorsDescription": "Monitor status of related servers",
|
||||
"distributedUptimeCreateSelectURL": "Here you can select the URL of the host, together with the type of monitor.",
|
||||
"distributedUptimeCreateChecks": "Checks to perform",
|
||||
"distributedUptimeCreateChecksDescription": "You can always add or remove checks after adding your site.",
|
||||
"distributedUptimeCreateIncidentNotification": "Incident notifications",
|
||||
"distributedUptimeCreateIncidentDescription": "When there is an incident, notify users.",
|
||||
"distributedUptimeCreateAdvancedSettings": "Advanced settings",
|
||||
"distributedUptimeDetailsNoMonitorHistory": "There is no check history for this monitor yet.",
|
||||
"distributedUptimeDetailsFooterHeading": "Made with ❤️ by UpRock & Bluewave Labs",
|
||||
"distributedUptimeDetailsFooterBuilt": "Built on",
|
||||
"distributedUptimeDetailsFooterSolana": "Solana",
|
||||
"distributedUptimeDetailsMonitorHeader": "Distributed Uptime Monitoring powered by DePIN",
|
||||
"distributedUptimeDetailsStatusHeaderUptime": "Uptime:",
|
||||
"distributedUptimeDetailsStatusHeaderLastUpdate": "Last updated",
|
||||
|
||||
"settingsGeneralSettings": "General settings",
|
||||
"settingsDisplayTimezone": "Display timezone",
|
||||
"settingsDisplayTimezoneDescription": "The timezone of the dashboard you publicly display.",
|
||||
"settingsAppearance": "Appearance",
|
||||
"settingsAppearanceDescription": "Switch between light and dark mode, or change user interface language",
|
||||
"settingsThemeMode": "Theme Mode",
|
||||
"settingsLanguage": "Language",
|
||||
"settingsDistributedUptime": "Distributed uptime",
|
||||
"settingsDistributedUptimeDescription": "Enable/disable distributed uptime monitoring.",
|
||||
"settingsEnabled": "Enabled",
|
||||
"settingsDisabled": "Disabled",
|
||||
"settingsHistoryAndMonitoring": "History and monitoring",
|
||||
"settingsHistoryAndMonitoringDescription": "Define here for how long you want to keep the data. You can also remove all past data.",
|
||||
"settingsTTLLabel": "The days you want to keep monitoring history.",
|
||||
"settingsTTLOptionalLabel": "0 for infinite",
|
||||
"settingsClearAllStats": "Clear all stats. This is irreversible.",
|
||||
"settingsClearAllStatsButton": "Clear all stats",
|
||||
"settingsClearAllStatsDialogTitle": "Do you want to clear all stats?",
|
||||
"settingsClearAllStatsDialogDescription": "Once deleted, your monitors cannot be retrieved.",
|
||||
"settingsClearAllStatsDialogConfirm": "Yes, clear all stats",
|
||||
"settingsDemoMonitors": "Demo monitors",
|
||||
"settingsDemoMonitorsDescription": "Here you can add and remove demo monitors.",
|
||||
"settingsAddDemoMonitors": "Add demo monitors",
|
||||
"settingsAddDemoMonitorsButton": "Add demo monitors",
|
||||
"settingsRemoveAllMonitors": "Remove all monitors",
|
||||
"settingsRemoveAllMonitorsButton": "Remove all monitors",
|
||||
"settingsRemoveAllMonitorsDialogTitle": "Do you want to remove all monitors?",
|
||||
"settingsRemoveAllMonitorsDialogConfirm": "Yes, clear all monitors",
|
||||
"settingsWallet": "Wallet",
|
||||
"settingsWalletDescription": "Connect your wallet here. This is required for the Distributed Uptime monitor to connect to multiple nodes globally.",
|
||||
"settingsAbout": "About",
|
||||
"settingsDevelopedBy": "Developed by Bluewave Labs.",
|
||||
"settingsSave": "Save",
|
||||
"settingsSuccessSaved": "Settings saved successfully",
|
||||
"settingsFailedToSave": "Failed to save settings",
|
||||
"settingsStatsCleared": "Stats cleared successfully",
|
||||
"settingsFailedToClearStats": "Failed to clear stats",
|
||||
"settingsDemoMonitorsAdded": "Successfully added demo monitors",
|
||||
"settingsFailedToAddDemoMonitors": "Failed to add demo monitors",
|
||||
"settingsMonitorsDeleted": "Successfully deleted all monitors",
|
||||
"settingsFailedToDeleteMonitors": "Failed to delete all monitors",
|
||||
"starPromptTitle": "Star Checkmate",
|
||||
"starPromptDescription": "See the latest releases and help grow the community on GitHub",
|
||||
"notifications": {
|
||||
"enableNotifications": "Enable {{platform}} notifications",
|
||||
"testNotification": "Test notification",
|
||||
"addOrEditNotifications": "Add or edit notifications",
|
||||
"slack": {
|
||||
"label": "Slack",
|
||||
"description": "To enable Slack notifications, create a Slack app and enable incoming webhooks. After that, simply provide the webhook URL here.",
|
||||
"webhookLabel": "Webhook URL",
|
||||
"webhookPlaceholder": "https://hooks.slack.com/services/..."
|
||||
},
|
||||
"discord": {
|
||||
"label": "Discord",
|
||||
"description": "To send data to a Discord channel from Checkmate via Discord notifications using webhooks, you can use Discord's incoming Webhooks feature.",
|
||||
"webhookLabel": "Discord Webhook URL",
|
||||
"webhookPlaceholder": "https://discord.com/api/webhooks/..."
|
||||
},
|
||||
"telegram": {
|
||||
"label": "Telegram",
|
||||
"description": "To enable Telegram notifications, create a Telegram bot using BotFather, an official bot for creating and managing Telegram bots. Then, get the API token and chat ID and write them down here.",
|
||||
"tokenLabel": "Your bot token",
|
||||
"tokenPlaceholder": "123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11",
|
||||
"chatIdLabel": "Your Chat ID",
|
||||
"chatIdPlaceholder": "-1001234567890"
|
||||
},
|
||||
"webhook": {
|
||||
"label": "Webhooks",
|
||||
"description": "You can set up a custom webhook to receive notifications when incidents occur.",
|
||||
"urlLabel": "Webhook URL",
|
||||
"urlPlaceholder": "https://your-server.com/webhook"
|
||||
}
|
||||
}
|
||||
"dontHaveAccount": "Don't have account",
|
||||
"email": "E-mail",
|
||||
"forgotPassword": "Forgot Password",
|
||||
"password": "password",
|
||||
"signUp": "Sign up",
|
||||
"submit": "Submit",
|
||||
"title": "Title",
|
||||
"continue": "Continue",
|
||||
"enterEmail": "Enter your email",
|
||||
"authLoginTitle": "Log In",
|
||||
"authLoginEnterPassword": "Enter your password",
|
||||
"commonPassword": "Password",
|
||||
"commonBack": "Back",
|
||||
"authForgotPasswordTitle": "Forgot password?",
|
||||
"authForgotPasswordResetPassword": "Reset password",
|
||||
"createPassword": "Create your password",
|
||||
"createAPassword": "Create a password",
|
||||
"authRegisterAlreadyHaveAccount": "Already have an account?",
|
||||
"commonAppName": "Checkmate",
|
||||
"authLoginEnterEmail": "Enter your email",
|
||||
"authRegisterTitle": "Create an account",
|
||||
"authRegisterStepOneTitle": "Create your account",
|
||||
"authRegisterStepOneDescription": "Enter your details to get started",
|
||||
"authRegisterStepTwoTitle": "Set up your profile",
|
||||
"authRegisterStepTwoDescription": "Tell us more about yourself",
|
||||
"authRegisterStepThreeTitle": "Almost done!",
|
||||
"authRegisterStepThreeDescription": "Review your information",
|
||||
"authForgotPasswordDescription": "No worries, we'll send you reset instructions.",
|
||||
"authForgotPasswordSendInstructions": "Send instructions",
|
||||
"authForgotPasswordBackTo": "Back to",
|
||||
"authCheckEmailTitle": "Check your email",
|
||||
"authCheckEmailDescription": "We sent a password reset link to",
|
||||
"authCheckEmailResendEmail": "Resend email",
|
||||
"authCheckEmailBackTo": "Back to",
|
||||
"goBackTo": "Go back to",
|
||||
"authCheckEmailDidntReceiveEmail": "Didn't receive the email?",
|
||||
"authCheckEmailClickToResend": "Click to resend",
|
||||
"authSetNewPasswordTitle": "Set new password",
|
||||
"authSetNewPasswordDescription": "Your new password must be different from previously used passwords.",
|
||||
"authSetNewPasswordNewPassword": "New password",
|
||||
"authSetNewPasswordConfirmPassword": "Confirm password",
|
||||
"confirmPassword": "Confirm your password",
|
||||
"authSetNewPasswordResetPassword": "Reset password",
|
||||
"authSetNewPasswordBackTo": "Back to",
|
||||
"authPasswordMustBeAtLeast": "Must be at least",
|
||||
"authPasswordCharactersLong": "8 characters long",
|
||||
"authPasswordMustContainAtLeast": "Must contain at least",
|
||||
"authPasswordSpecialCharacter": "one special character",
|
||||
"authPasswordOneNumber": "one number",
|
||||
"authPasswordUpperCharacter": "one upper character",
|
||||
"authPasswordLowerCharacter": "one lower character",
|
||||
"authPasswordConfirmAndPassword": "Confirm password and password",
|
||||
"authPasswordMustMatch": "must match",
|
||||
"authRegisterCreateAccount": "Create your account to get started",
|
||||
"authRegisterCreateSuperAdminAccount": "Create your Super admin account to get started",
|
||||
"authRegisterSignUpWithEmail": "Sign up with Email",
|
||||
"authRegisterBySigningUp": "By signing up, you agree to our",
|
||||
"distributedStatusHeaderText": "Real-time, real-device coverage",
|
||||
"distributedStatusSubHeaderText": "Powered by millions devices worldwide, view a system performance by global region, country or city",
|
||||
"settingsGeneralSettings": "General settings",
|
||||
"settingsDisplayTimezone": "Display timezone",
|
||||
"settingsDisplayTimezoneDescription": "The timezone of the dashboard you publicly display.",
|
||||
"settingsAppearance": "Appearance",
|
||||
"settingsAppearanceDescription": "Switch between light and dark mode, or change user interface language",
|
||||
"settingsThemeMode": "Theme Mode",
|
||||
"settingsLanguage": "Language",
|
||||
"settingsDistributedUptime": "Distributed uptime",
|
||||
"settingsDistributedUptimeDescription": "Enable/disable distributed uptime monitoring.",
|
||||
"settingsEnabled": "Enabled",
|
||||
"settingsDisabled": "Disabled",
|
||||
"settingsHistoryAndMonitoring": "History and monitoring",
|
||||
"settingsHistoryAndMonitoringDescription": "Define here for how long you want to keep the data. You can also remove all past data.",
|
||||
"settingsTTLLabel": "The days you want to keep monitoring history.",
|
||||
"settingsTTLOptionalLabel": "0 for infinite",
|
||||
"settingsClearAllStats": "Clear all stats. This is irreversible.",
|
||||
"settingsClearAllStatsButton": "Clear all stats",
|
||||
"settingsClearAllStatsDialogTitle": "Do you want to clear all stats?",
|
||||
"settingsClearAllStatsDialogDescription": "Once deleted, your monitors cannot be retrieved.",
|
||||
"settingsClearAllStatsDialogConfirm": "Yes, clear all stats",
|
||||
"settingsDemoMonitors": "Demo monitors",
|
||||
"settingsDemoMonitorsDescription": "Here you can add and remove demo monitors.",
|
||||
"settingsAddDemoMonitors": "Add demo monitors",
|
||||
"settingsAddDemoMonitorsButton": "Add demo monitors",
|
||||
"settingsRemoveAllMonitors": "Remove all monitors",
|
||||
"settingsRemoveAllMonitorsButton": "Remove all monitors",
|
||||
"settingsRemoveAllMonitorsDialogTitle": "Do you want to remove all monitors?",
|
||||
"settingsRemoveAllMonitorsDialogConfirm": "Yes, clear all monitors",
|
||||
"settingsWallet": "Wallet",
|
||||
"settingsWalletDescription": "Connect your wallet here. This is required for the Distributed Uptime monitor to connect to multiple nodes globally.",
|
||||
"settingsAbout": "About",
|
||||
"settingsDevelopedBy": "Developed by Bluewave Labs.",
|
||||
"settingsSave": "Save",
|
||||
"settingsSuccessSaved": "Settings saved successfully",
|
||||
"settingsFailedToSave": "Failed to save settings",
|
||||
"settingsStatsCleared": "Stats cleared successfully",
|
||||
"settingsFailedToClearStats": "Failed to clear stats",
|
||||
"settingsDemoMonitorsAdded": "Successfully added demo monitors",
|
||||
"settingsFailedToAddDemoMonitors": "Failed to add demo monitors",
|
||||
"settingsMonitorsDeleted": "Successfully deleted all monitors",
|
||||
"settingsFailedToDeleteMonitors": "Failed to delete all monitors",
|
||||
"starPromptTitle": "Star Checkmate",
|
||||
"starPromptDescription": "See the latest releases and help grow the community on GitHub",
|
||||
"https": "HTTPS",
|
||||
"http": "HTTP",
|
||||
"monitor": "monitor",
|
||||
"aboutus": "About Us",
|
||||
"signUP": "Sign Up",
|
||||
"now": "Now",
|
||||
"delete": "Delete",
|
||||
"configure": "Configure",
|
||||
"networkError": "Network error",
|
||||
"responseTime": "Response time:",
|
||||
"ms": "ms",
|
||||
"bar": "Bar",
|
||||
"area": "Area",
|
||||
"country": "COUNTRY",
|
||||
"city": "CITY",
|
||||
"response": "RESPONSE",
|
||||
"checkConnection": "Please check your connection",
|
||||
"passwordreset": "Password Reset",
|
||||
"authRegisterStepOnePersonalDetails": "Enter your personal details",
|
||||
"authCheckEmailOpenEmailButton": "Open email app",
|
||||
"authNewPasswordConfirmed": "Your password has been successfully reset. Click below to log in magically.",
|
||||
"monitorStatusUp": "Monitor {name} ({url}) is now UP and responding",
|
||||
"monitorStatusDown": "Monitor {name} ({url}) is DOWN and not responding",
|
||||
"webhookSendSuccess": "Webhook notification sent successfully",
|
||||
"webhookSendError": "Error sending webhook notification to {platform}",
|
||||
"webhookUnsupportedPlatform": "Unsupported platform: {platform}",
|
||||
"distributedRightCategoryTitle": "Monitor",
|
||||
"distributedStatusServerMonitors": "Server Monitors",
|
||||
"distributedStatusServerMonitorsDescription": "Monitor status of related servers",
|
||||
"distributedUptimeCreateSelectURL": "Here you can select the URL of the host, together with the type of monitor.",
|
||||
"distributedUptimeCreateChecks": "Checks to perform",
|
||||
"distributedUptimeCreateChecksDescription": "You can always add or remove checks after adding your site.",
|
||||
"distributedUptimeCreateIncidentNotification": "Incident notifications",
|
||||
"distributedUptimeCreateIncidentDescription": "When there is an incident, notify users.",
|
||||
"distributedUptimeCreateAdvancedSettings": "Advanced settings",
|
||||
"distributedUptimeDetailsNoMonitorHistory": "There is no check history for this monitor yet.",
|
||||
"distributedUptimeDetailsFooterHeading": "Made with ❤️ by UpRock & Bluewave Labs",
|
||||
"distributedUptimeDetailsFooterBuilt": "Built on",
|
||||
"distributedUptimeDetailsFooterSolana": "Solana",
|
||||
"distributedUptimeDetailsMonitorHeader": "Distributed Uptime Monitoring powered by DePIN",
|
||||
"distributedUptimeDetailsStatusHeaderUptime": "Uptime:",
|
||||
"distributedUptimeDetailsStatusHeaderLastUpdate": "Last updated",
|
||||
"notifications": {
|
||||
"enableNotifications": "Enable {{platform}} notifications",
|
||||
"testNotification": "Test notification",
|
||||
"addOrEditNotifications": "Add or edit notifications",
|
||||
"slack": {
|
||||
"label": "Slack",
|
||||
"description": "To enable Slack notifications, create a Slack app and enable incoming webhooks. After that, simply provide the webhook URL here.",
|
||||
"webhookLabel": "Webhook URL",
|
||||
"webhookPlaceholder": "https://hooks.slack.com/services/..."
|
||||
},
|
||||
"discord": {
|
||||
"label": "Discord",
|
||||
"description": "To send data to a Discord channel from Checkmate via Discord notifications using webhooks, you can use Discord's incoming Webhooks feature.",
|
||||
"webhookLabel": "Discord Webhook URL",
|
||||
"webhookPlaceholder": "https://discord.com/api/webhooks/..."
|
||||
},
|
||||
"telegram": {
|
||||
"label": "Telegram",
|
||||
"description": "To enable Telegram notifications, create a Telegram bot using BotFather, an official bot for creating and managing Telegram bots. Then, get the API token and chat ID and write them down here.",
|
||||
"tokenLabel": "Your bot token",
|
||||
"tokenPlaceholder": "123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11",
|
||||
"chatIdLabel": "Your Chat ID",
|
||||
"chatIdPlaceholder": "-1001234567890"
|
||||
},
|
||||
"webhook": {
|
||||
"label": "Webhooks",
|
||||
"description": "You can set up a custom webhook to receive notifications when incidents occur.",
|
||||
"urlLabel": "Webhook URL",
|
||||
"urlPlaceholder": "https://your-server.com/webhook"
|
||||
},
|
||||
"testNotificationDevelop": "Test notification 2"
|
||||
},
|
||||
"testLocale": ""
|
||||
}
|
||||
+1
-1
@@ -175,5 +175,5 @@
|
||||
},
|
||||
"testNotificationDevelop": ""
|
||||
},
|
||||
"testLocale": "TEST4 UPLOAD"
|
||||
"testLocale": "TEST11 UPLOAD"
|
||||
}
|
||||
Reference in new issue
Block a user