Merge branch 'develop' into feat/fe/wallet-adapter

This commit is contained in:
Alexander Holliday authored and GitHub committed 2025-02-13 11:03:29 -08:00
commit 106d49850c
60 files changed
+1706 -438

No files matched your search

+2 -3
View File
@@ -1,17 +1,16 @@
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { Box, MenuItem, Select, Stack } from "@mui/material";
import { useTheme } from "@emotion/react";
import "flag-icons/css/flag-icons.min.css";
import { useSelector } from "react-redux";
const LanguageSelector = () => {
const { i18n } = useTranslation();
const theme = useTheme();
const [language, setLanguage] = useState(i18n.language || "gb");
const { language } = useSelector((state) => state.ui);
const handleChange = (event) => {
const newLang = event.target.value;
setLanguage(newLang);
i18n.changeLanguage(newLang);
};
@@ -0,0 +1,14 @@
import { Stack, Skeleton } from "@mui/material";
export const SkeletonLayout = () => {
return (
<Stack>
<Skeleton
variant="rectangular"
height={"90vh"}
/>
</Stack>
);
};
export default SkeletonLayout;
+5
View File
@@ -23,6 +23,7 @@ const initialState = {
greeting: { index: 0, lastUpdate: null },
timezone: "America/Toronto",
distributedUptimeEnabled: false,
language: "gb",
};
const uiSlice = createSlice({
@@ -51,6 +52,9 @@ const uiSlice = createSlice({
setTimezone(state, action) {
state.timezone = action.payload.timezone;
},
setLanguage(state, action) {
state.language = action.payload;
},
},
});
@@ -62,4 +66,5 @@ export const {
setGreeting,
setTimezone,
setDistributedUptimeEnabled,
setLanguage,
} = uiSlice.actions;
@@ -92,7 +92,7 @@ export const updateUptimeMonitor = createAsyncThunk(
const res = await networkService.updateMonitor({
authToken: authToken,
monitorId: monitor._id,
updatedFields: updatedFields,
monitor,
});
return res.data;
} catch (error) {
@@ -0,0 +1,33 @@
import { useState } from "react";
import { networkService } from "../../../../main";
import { useSelector } from "react-redux";
import { createToast } from "../../../../Utils/toastUtils";
const useCreateDistributedUptimeMonitor = ({ isCreate, monitorId }) => {
const { authToken, user } = useSelector((state) => state.auth);
const [isLoading, setIsLoading] = useState(false);
const [networkError, setNetworkError] = useState(false);
const createDistributedUptimeMonitor = async ({ form }) => {
setIsLoading(true);
try {
if (isCreate) {
await networkService.createMonitor({ authToken, monitor: form });
} else {
await networkService.updateMonitor({ authToken, monitor: form, monitorId });
}
return true;
} catch (error) {
setNetworkError(true);
createToast({ body: error?.response?.data?.msg ?? error.message });
return false;
} finally {
setIsLoading(false);
}
};
return [createDistributedUptimeMonitor, isLoading, networkError];
};
export { useCreateDistributedUptimeMonitor };
@@ -0,0 +1,32 @@
import { useEffect, useState } from "react";
import { networkService } from "../../../../main";
import { createToast } from "../../../../Utils/toastUtils";
export const useMonitorFetch = ({ authToken, monitorId, isCreate }) => {
const [networkError, setNetworkError] = useState(false);
const [isLoading, setIsLoading] = useState(true);
const [monitor, setMonitor] = useState(undefined);
useEffect(() => {
const fetchMonitors = async () => {
try {
if (isCreate) return;
const res = await networkService.getUptimeDetailsById({
authToken: authToken,
monitorId: monitorId,
normalize: true,
});
setMonitor(res?.data?.data ?? {});
} catch (error) {
setNetworkError(true);
createToast({ body: error.message });
} finally {
setIsLoading(false);
}
};
fetchMonitors();
}, [authToken, monitorId, isCreate]);
return [monitor, isLoading, networkError];
};
export default useMonitorFetch;
@@ -13,18 +13,15 @@ import { createToast } from "../../../Utils/toastUtils";
// Utility
import { useTheme } from "@emotion/react";
import { useState } from "react";
import { useState, useEffect } from "react";
import { useNavigate } from "react-router-dom";
import { useSelector, useDispatch } from "react-redux";
import { useSelector } from "react-redux";
import { monitorValidation } from "../../../Validation/validation";
import { createUptimeMonitor } from "../../../Features/UptimeMonitors/uptimeMonitorsSlice";
import { useLocation } from "react-router-dom";
import { useParams } from "react-router-dom";
import { useCreateDistributedUptimeMonitor } from "./Hooks/useCreateDistributedUptimeMonitor";
import { useMonitorFetch } from "./Hooks/useMonitorFetch";
// Constants
const BREADCRUMBS = [
{ name: `distributed uptime`, path: "/distributed-uptime" },
{ name: "create", path: `/distributed-uptime/create` },
];
const MS_PER_MINUTE = 60000;
const SELECT_VALUES = [
{ _id: 1, name: "1 minute" },
@@ -34,18 +31,30 @@ const SELECT_VALUES = [
{ _id: 5, name: "5 minutes" },
];
const parseUrl = (url) => {
try {
return new URL(url);
} catch (error) {
return null;
}
};
const CreateDistributedUptime = () => {
const location = useLocation();
const isCreate = location.pathname.startsWith("/distributed-uptime/create");
const { monitorId } = useParams();
const isCreate = typeof monitorId === "undefined";
const BREADCRUMBS = [
{ name: `distributed uptime`, path: "/distributed-uptime" },
{ name: isCreate ? "create" : "configure", path: `` },
];
// Redux state
const { user, authToken } = useSelector((state) => state.auth);
const isLoading = useSelector((state) => state.uptimeMonitors.isLoading);
// Local state
const [https, setHttps] = useState(true);
const [notifications, setNotifications] = useState([]);
const [monitor, setMonitor] = useState({
const [form, setForm] = useState({
type: "distributed_http",
name: "",
url: "",
@@ -55,12 +64,37 @@ const CreateDistributedUptime = () => {
//utils
const theme = useTheme();
const dispatch = useDispatch();
const navigate = useNavigate();
const [createDistributedUptimeMonitor, isLoading, networkError] =
useCreateDistributedUptimeMonitor({ isCreate, monitorId });
const [monitor, monitorIsLoading, monitorNetworkError] = useMonitorFetch({
authToken,
monitorId,
isCreate,
});
// Effect to set monitor to fetched monitor
useEffect(() => {
if (typeof monitor !== "undefined") {
const parsedUrl = parseUrl(monitor?.url);
const protocol = parsedUrl?.protocol?.replace(":", "") || "";
setHttps(protocol === "https");
const newForm = {
name: monitor.name,
interval: monitor.interval / MS_PER_MINUTE,
url: parsedUrl.host,
type: monitor.type,
};
setForm(newForm);
}
}, [monitor]);
// Handlers
const handleCreateMonitor = async (event) => {
const monitorToSubmit = { ...monitor };
const handleCreateMonitor = async () => {
const monitorToSubmit = { ...form };
// Prepend protocol to url
monitorToSubmit.url = `http${https ? "s" : ""}://` + monitorToSubmit.url;
@@ -68,7 +102,6 @@ const CreateDistributedUptime = () => {
const { error } = monitorValidation.validate(monitorToSubmit, {
abortEarly: false,
});
if (error) {
const newErrors = {};
error.details.forEach((err) => {
@@ -80,16 +113,14 @@ const CreateDistributedUptime = () => {
}
// Append needed fields
monitorToSubmit.description = monitor.name;
monitorToSubmit.interval = monitor.interval * MS_PER_MINUTE;
monitorToSubmit.description = form.name;
monitorToSubmit.interval = form.interval * MS_PER_MINUTE;
monitorToSubmit.teamId = user.teamId;
monitorToSubmit.userId = user._id;
monitorToSubmit.notifications = notifications;
const action = await dispatch(
createUptimeMonitor({ authToken, monitor: monitorToSubmit })
);
if (action.meta.requestStatus === "fulfilled") {
const success = await createDistributedUptimeMonitor({ form: monitorToSubmit });
if (success) {
createToast({ body: "Monitor created successfully!" });
navigate("/distributed-uptime");
} else {
@@ -98,9 +129,10 @@ const CreateDistributedUptime = () => {
};
const handleChange = (event) => {
const { name, value } = event.target;
setMonitor({
...monitor,
let { name, value } = event.target;
setForm({
...form,
[name]: value,
});
const { error } = monitorValidation.validate(
@@ -178,7 +210,8 @@ const CreateDistributedUptime = () => {
label="URL to monitor"
https={https}
placeholder={"www.google.com"}
value={monitor.url}
disabled={!isCreate}
value={form.url}
name="url"
onChange={handleChange}
error={errors["url"] ? true : false}
@@ -190,7 +223,7 @@ const CreateDistributedUptime = () => {
label="Display name"
isOptional={true}
placeholder={"Google"}
value={monitor.name}
value={form.name}
name="name"
onChange={handleChange}
error={errors["name"] ? true : false}
@@ -217,8 +250,11 @@ const CreateDistributedUptime = () => {
checked={true}
onChange={handleChange}
/>
{monitor.type === "http" || monitor.type === "distributed_http" ? (
<ButtonGroup sx={{ ml: theme.spacing(16) }}>
{form.type === "http" || form.type === "distributed_http" ? (
<ButtonGroup
disabled={!isCreate}
sx={{ ml: theme.spacing(16) }}
>
<Button
variant="group"
filled={https.toString()}
@@ -282,7 +318,7 @@ const CreateDistributedUptime = () => {
id="monitor-interval"
label="Check frequency"
name="interval"
value={monitor.interval || 1}
value={form.interval}
onChange={handleChange}
items={SELECT_VALUES}
/>
@@ -299,7 +335,7 @@ const CreateDistributedUptime = () => {
disabled={!Object.values(errors).every((value) => value === undefined)}
loading={isLoading}
>
Create monitor
{isCreate ? "Create monitor" : "Configure monitor"}
</LoadingButton>
</Stack>
</Stack>
@@ -0,0 +1,91 @@
// Components
import { Box, Stack, Typography, Button } from "@mui/material";
import Image from "../../../../../Components/Image";
import SettingsIcon from "../../../../../assets/icons/settings-bold.svg?react";
//Utils
import { useTheme } from "@mui/material/styles";
import { useNavigate } from "react-router-dom";
import { useLocation } from "react-router-dom";
import PropTypes from "prop-types";
const Controls = ({ isDeleteOpen, setIsDeleteOpen, isDeleting, monitorId }) => {
const theme = useTheme();
const navigate = useNavigate();
return (
<Stack
direction="row"
gap={theme.spacing(2)}
>
<Box>
<Button
variant="contained"
color="error"
onClick={() => setIsDeleteOpen(!isDeleteOpen)}
loading={isDeleting}
>
Delete
</Button>
</Box>
<Box>
<Button
variant="contained"
color="secondary"
onClick={() => {
navigate(`/distributed-uptime/configure/${monitorId}`);
}}
sx={{
px: theme.spacing(5),
"& svg": {
mr: theme.spacing(3),
"& path": {
stroke: theme.palette.secondary.contrastText,
},
},
}}
>
<SettingsIcon /> Configure
</Button>
</Box>
</Stack>
);
};
Controls.propTypes = {
isDeleting: PropTypes.bool,
monitorId: PropTypes.string,
isDeleteOpen: PropTypes.bool.isRequired,
setIsDeleteOpen: PropTypes.func.isRequired,
};
const ControlsHeader = ({ isDeleting, isDeleteOpen, setIsDeleteOpen, monitorId }) => {
const theme = useTheme();
return (
<Stack
alignSelf="flex-start"
direction="row"
width="100%"
gap={theme.spacing(2)}
justifyContent="flex-end"
alignItems="flex-end"
>
<Controls
isDeleting={isDeleting}
isDeleteOpen={isDeleteOpen}
setIsDeleteOpen={setIsDeleteOpen}
monitorId={monitorId}
/>
</Stack>
);
};
ControlsHeader.propTypes = {
monitorId: PropTypes.string,
isDeleting: PropTypes.bool,
isDeleteOpen: PropTypes.bool.isRequired,
setIsDeleteOpen: PropTypes.func.isRequired,
};
export default ControlsHeader;
@@ -0,0 +1,27 @@
import { useSelector } from "react-redux";
import { useState } from "react";
import { networkService } from "../../../../main";
import { createToast } from "../../../../Utils/toastUtils";
const useDeleteMonitor = ({ monitorId }) => {
const [isLoading, setIsLoading] = useState(false);
const { authToken } = useSelector((state) => state.auth);
const deleteMonitor = async () => {
try {
setIsLoading(true);
await networkService.deleteMonitorById({ authToken, monitorId });
return true;
} catch (error) {
createToast({
body: error.message,
});
return false;
} finally {
setIsLoading(false);
}
};
return [deleteMonitor, isLoading];
};
export { useDeleteMonitor };
@@ -12,23 +12,31 @@ import MonitorTimeFrameHeader from "../../../Components/MonitorTimeFrameHeader";
import GenericFallback from "../../../Components/GenericFallback";
import MonitorCreateHeader from "../../../Components/MonitorCreateHeader";
import SkeletonLayout from "./Components/Skeleton";
import ControlsHeader from "./Components/ControlsHeader";
import Dialog from "../../../Components/Dialog";
//Utils
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 { useDeleteMonitor } from "./Hooks/useDeleteMonitor";
import { useNavigate } from "react-router-dom";
const DistributedUptimeDetails = () => {
const { monitorId } = useParams();
// Local State
const [dateRange, setDateRange] = useState("day");
const [isDeleteOpen, setIsDeleteOpen] = useState(false);
// Utils
const theme = useTheme();
const isAdmin = useIsAdmin();
const navigate = useNavigate();
const [isLoading, networkError, connectionStatus, monitor, lastUpdateTrigger] =
useSubscribeToDetails({ monitorId, dateRange });
const [deleteMonitor, isDeleting] = useDeleteMonitor({ monitorId });
// Constants
const BREADCRUMBS = [
{ name: "Distributed Uptime", path: "/distributed-uptime" },
@@ -76,6 +84,12 @@ const DistributedUptimeDetails = () => {
isAdmin={isAdmin}
path={`/status/distributed/create/${monitorId}`}
/>
<ControlsHeader
isDeleting={isDeleting}
isDeleteOpen={isDeleteOpen}
setIsDeleteOpen={setIsDeleteOpen}
monitorId={monitorId}
/>
<MonitorHeader monitor={monitor} />
<StatBoxes
monitor={monitor}
@@ -107,6 +121,21 @@ const DistributedUptimeDetails = () => {
/>
</Stack>
<Footer />
<Dialog
title="Do you want to delete this monitor?"
onConfirm={() => {
deleteMonitor();
setIsDeleteOpen(false);
navigate("/distributed-uptime");
}}
onCancel={() => {
setIsDeleteOpen(false);
}}
open={isDeleteOpen}
confirmationButtonLabel="Yes, delete monitor"
description="Once deleted, your monitor cannot be retrieved."
isLoading={isDeleting || isLoading}
/>
</Stack>
);
};
@@ -29,7 +29,7 @@ const MonitorTable = ({ isLoading, monitors }) => {
<Host
key={row._id}
url={row.url}
title={row.title}
title={row.name}
percentageColor={row.percentageColor}
percentage={row.percentage}
/>
@@ -41,7 +41,7 @@ const DistributedUptimeMonitors = () => {
);
}
if (typeof monitorsSummary !== "undefined" && monitorsSummary.totalMonitors === 0) {
if (typeof monitorsSummary === "undefined" || monitorsSummary.totalMonitors === 0) {
return (
<Fallback
vowelStart={false}
@@ -13,7 +13,6 @@ import { useState, useEffect } from "react";
import { useParams } from "react-router-dom";
import { useStatusPageFetch } from "../../StatusPage/Status/Hooks/useStatusPageFetch";
import { useCreateStatusPage } from "../../StatusPage/Create/Hooks/useCreateStatusPage";
import { useLocation } from "react-router-dom";
import { statusPageValidation } from "../../../Validation/validation";
import { buildErrors } from "../../../Validation/error";
import { createToast } from "../../../Utils/toastUtils";
@@ -23,8 +22,7 @@ const CreateStatus = () => {
const theme = useTheme();
const { monitorId, url } = useParams();
const navigate = useNavigate();
const location = useLocation();
const isCreate = location.pathname.startsWith("/status/distributed/create");
const isCreate = typeof url === "undefined";
const [createStatusPage, isLoading, networkError] = useCreateStatusPage(isCreate);
const [statusPage, statusPageMonitors, statusPageIsLoading, statusPageNetworkError] =
@@ -75,9 +75,9 @@ const DistributedUptimeStatus = () => {
marginY={theme.spacing(4)}
color={theme.palette.primary.contrastTextTertiary}
>
A public status page is not set up.
A status page is not set up.
</Typography>
<Typography>Please contact to your administrator</Typography>
<Typography>Please contact your administrator</Typography>
</GenericFallback>
</Stack>
);
@@ -34,7 +34,6 @@ const MaintenanceTable = ({
updateCallback,
}) => {
const { rowsPerPage } = useSelector((state) => state.ui.maintenance);
console.log(rowsPerPage);
const dispatch = useDispatch();
const handleChangePage = (event, newPage) => {
@@ -175,8 +174,6 @@ const MaintenanceTable = ({
setSort({ field, order });
};
console.log(handleChangePage);
return (
<>
<DataTable
+6 -4
View File
@@ -12,7 +12,6 @@ import { useMonitorsFetch } from "./Hooks/useMonitorsFetch";
import { useCreateStatusPage } from "./Hooks/useCreateStatusPage";
import { createToast } from "../../../Utils/toastUtils";
import { useNavigate } from "react-router-dom";
import { useLocation } from "react-router-dom";
import { useStatusPageFetch } from "../Status/Hooks/useStatusPageFetch";
import { useParams } from "react-router-dom";
@@ -47,8 +46,7 @@ const CreateStatusPage = () => {
const intervalRef = useRef(null);
// Setup
const location = useLocation();
const isCreate = location.pathname === "/status/uptime/create";
const isCreate = typeof url === "undefined";
//Utils
const theme = useTheme();
@@ -134,7 +132,11 @@ const CreateStatusPage = () => {
if (typeof error === "undefined") {
const success = await createStatusPage({ form });
if (success) {
createToast({ body: "Status page created successfully" });
createToast({
body: isCreate
? "Status page created successfully"
: "Status page updated successfully",
});
navigate(`/status/uptime/${form.url}`);
}
return;
@@ -0,0 +1,85 @@
import DataTable from "../../../../../Components/Table";
import { useTheme } from "@emotion/react";
import { useNavigate } from "react-router-dom";
import { ColoredLabel } from "../../../../../Components/Label";
import ArrowOutwardIcon from "@mui/icons-material/ArrowOutward";
import { Stack, Typography } from "@mui/material";
const StatusPagesTable = ({ data }) => {
const theme = useTheme();
const navigate = useNavigate();
const headers = [
{
id: "name",
content: "Status page name",
render: (row) => {
return row.companyName;
},
},
{
id: "url",
content: "URL",
render: (row) => {
return (
<Stack
direction="row"
alignItems="center"
gap={theme.spacing(2)}
>
<Typography>{`/${row.url}`}</Typography>
<ArrowOutwardIcon />
</Stack>
);
},
},
{
id: "type",
content: "Type",
render: (row) => {
return row.type;
},
},
{
id: "status",
content: "Status",
render: (row) => {
return (
<ColoredLabel
label={row.isPublished ? "Published" : "Unpublished"}
color={
row.isPublished ? theme.palette.success.main : theme.palette.warning.main
}
/>
);
},
},
];
const handleRowClick = (statusPage) => {
if (statusPage.type === "distributed") {
navigate(`/status/distributed/${statusPage.url}`);
} else if (statusPage.type === "uptime") {
navigate(`/status/uptime/${statusPage.url}`);
}
};
return (
<DataTable
config={{
rowSX: {
cursor: "pointer",
"&:hover td": {
backgroundColor: theme.palette.tertiary.main,
transition: "background-color .3s ease",
},
},
onRowClick: (row) => {
handleRowClick(row);
},
}}
headers={headers}
data={data}
/>
);
};
export default StatusPagesTable;
@@ -20,7 +20,9 @@ const useStatusPagesFetch = () => {
setStatusPages(res?.data?.data);
} catch (error) {
setNetworkError(true);
createToast(error.message, "error");
createToast({
body: error.message,
});
} finally {
setIsLoading(false);
}
@@ -4,11 +4,12 @@ import Breadcrumbs from "../../../Components/Breadcrumbs";
import Fallback from "../../../Components/Fallback";
import MonitorCreateHeader from "../../../Components/MonitorCreateHeader";
import GenericFallback from "../../../Components/GenericFallback";
import StatusPagesTable from "./Components/StatusPagesTable";
import SkeletonLayout from "../../../Components/Skeletons/FullPage";
// Utils
import { useTheme } from "@emotion/react";
import { useStatusPagesFetch } from "./Hooks/useStatusPagesFetch";
import { useIsAdmin } from "../../../Hooks/useIsAdmin";
import { useNavigate } from "react-router";
const BREADCRUMBS = [{ name: `Status Pages`, path: "" }];
const StatusPages = () => {
@@ -16,29 +17,9 @@ const StatusPages = () => {
const theme = useTheme();
const isAdmin = useIsAdmin();
const [isLoading, networkError, statusPages] = useStatusPagesFetch();
const navigate = useNavigate();
// Handlers
const handleStatusPageClick = (statusPage) => {
if (statusPage.type === "distributed") {
navigate(`/status/distributed/${statusPage.url}`);
} else if (statusPage.type === "uptime") {
navigate(`/status/uptime/${statusPage.url}`);
}
};
if (!isLoading && typeof statusPages === "undefined") {
return (
<Fallback
title="status page"
checks={[
"Display a list of monitors to track",
"Share your monitors with the public",
]}
link="/status/uptime/create"
isAdmin={isAdmin}
/>
);
if (isLoading) {
return <SkeletonLayout />;
}
if (networkError === true) {
@@ -55,6 +36,21 @@ const StatusPages = () => {
</GenericFallback>
);
}
if (!isLoading && typeof statusPages !== "undefined" && statusPages.length === 0) {
return (
<Fallback
title="status page"
checks={[
"Monitor and display the health of your services in real time",
"Track multiple services and share their status",
"Keep users informed about outages and performance",
]}
link="/status/uptime/create"
isAdmin={isAdmin}
/>
);
}
return (
<Stack gap={theme.spacing(10)}>
<Breadcrumbs list={BREADCRUMBS} />
@@ -63,19 +59,7 @@ const StatusPages = () => {
isAdmin={isAdmin}
path="/status/uptime/create"
/>
{statusPages?.map((statusPage) => {
return (
<Stack
key={statusPage._id}
onClick={() => handleStatusPageClick(statusPage)}
sx={{ cursor: "pointer" }}
>
<Typography variant="h2">Company Name: {statusPage.companyName}</Typography>
<Typography variant="h2">Status page URL: {statusPage.url}</Typography>
<Typography variant="h2">Type: {statusPage.type}</Typography>
</Stack>
);
})}
<StatusPagesTable data={statusPages} />
</Stack>
);
};
@@ -85,9 +85,9 @@ const ResponseGaugeChart = ({ avgResponseTime }) => {
</text>
<text
x="50%"
y="55%"
y="70%"
textAnchor="middle"
dominantBaseline="hanging"
alignmentBaseline="hanging"
fontSize={25}
>
<tspan fontWeight={600}>{responseTime}</tspan> <tspan opacity={0.8}>ms</tspan>
@@ -101,7 +101,7 @@ const UptimeDataTable = ({
<Host
key={row._id}
url={row.url}
title={row.title}
title={row.name}
percentageColor={row.percentageColor}
percentage={row.percentage}
/>
+8
View File
@@ -107,6 +107,14 @@ const Routes = () => {
</ProtectedDistributedUptimeRoute>
}
/>
<Route
path="/distributed-uptime/configure/:monitorId"
element={
<ProtectedDistributedUptimeRoute>
<CreateDistributedUptime />
</ProtectedDistributedUptimeRoute>
}
/>
<Route
path="/distributed-uptime/:monitorId"
element={
+15 -5
View File
@@ -99,9 +99,11 @@ class NetworkService {
* @returns {Promise<AxiosResponse>} The response from the axios POST request.
*/
async createMonitor(config) {
return this.axiosInstance.post(`/monitors`, config.monitor, {
const { authToken, monitor } = config;
return this.axiosInstance.post(`/monitors`, monitor, {
headers: {
Authorization: `Bearer ${config.authToken}`,
Authorization: `Bearer ${authToken}`,
"Content-Type": "application/json",
},
});
@@ -284,9 +286,16 @@ class NetworkService {
* @returns {Promise<AxiosResponse>} The response from the axios PUT request.
*/
async updateMonitor(config) {
return this.axiosInstance.put(`/monitors/${config.monitorId}`, config.updatedFields, {
const { authToken, monitorId, monitor } = config;
const updatedFields = {
name: monitor.name,
description: monitor.description,
interval: monitor.interval,
notifications: monitor.notifications,
};
return this.axiosInstance.put(`/monitors/${monitorId}`, updatedFields, {
headers: {
Authorization: `Bearer ${config.authToken}`,
Authorization: `Bearer ${authToken}`,
"Content-Type": "application/json",
},
});
@@ -1015,11 +1024,12 @@ class NetworkService {
async createStatusPage(config) {
const { authToken, user, form, isCreate } = config;
const fd = new FormData();
fd.append("teamId", user.teamId);
fd.append("userId", user._id);
fd.append("type", form.type);
form.isPublished && fd.append("isPublished", form.isPublished);
form.isPublished !== undefined && fd.append("isPublished", form.isPublished);
form.companyName && fd.append("companyName", form.companyName);
form.url && fd.append("url", form.url);
form.timezone && fd.append("timezone", form.timezone);
+6 -3
View File
@@ -1,5 +1,7 @@
import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import { setLanguage } from "../Features/UI/uiSlice";
import store from "../store";
const primaryLanguage = "gb";
@@ -13,11 +15,12 @@ Object.keys(translations).forEach((path) => {
};
});
const savedLanguage = localStorage.getItem("language") || primaryLanguage;
const savedLanguage = store.getState()?.ui?.language;
const initialLanguage = savedLanguage || primaryLanguage;
i18n.use(initReactI18next).init({
resources,
lng: savedLanguage,
lng: initialLanguage,
fallbackLng: primaryLanguage,
debug: import.meta.env.MODE === "development",
ns: ["translation"],
@@ -28,7 +31,7 @@ i18n.use(initReactI18next).init({
});
i18n.on("languageChanged", (lng) => {
localStorage.setItem("language", lng);
store.dispatch(setLanguage(lng));
});
export default i18n;