Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ed8352d857 | ||
|
|
41f64ca9fe | ||
|
|
738e49dc92 | ||
|
|
68a16257c6 | ||
|
|
5dcbae55f4 | ||
|
|
e0d963256c | ||
|
|
2bff4bbd15 | ||
|
|
a0eba89f34 | ||
|
|
4e78de9da2 | ||
|
|
06f49e24c2 | ||
|
|
e598ae45f7 | ||
|
|
ad7f469e06 | ||
|
|
cb57ff5cc2 | ||
|
|
72f070fbcb | ||
|
|
fb0a86d37c | ||
|
|
36402dfefa | ||
|
|
c61874dbdd | ||
|
|
20848f28d5 | ||
|
|
5d23966f00 | ||
|
|
294cc66e4a | ||
|
|
0fd2e7032a | ||
|
|
340b85043e | ||
|
|
1821ae3c2b | ||
|
|
c536cb2afa | ||
|
|
3f79b4c2f6 | ||
|
|
137ba9185e | ||
|
|
2f6a0913dc | ||
|
|
2c7336d440 | ||
|
|
5a022ff3f6 | ||
|
|
fe4855500e | ||
|
|
ce8f5cbe0c | ||
|
|
f01030a47a | ||
|
|
3cbd907c09 | ||
|
|
8fae69b7a4 | ||
|
|
e45dd4240e | ||
|
|
fd951bfdd5 | ||
|
|
27d613b594 | ||
|
|
7c8ab64e34 | ||
|
|
ec7855bd02 | ||
|
|
d401eefd6b |
No files matched your search
@@ -0,0 +1 @@
|
||||
release_notes: false
|
||||
@@ -7,7 +7,7 @@ import { URLSearchParams } from "url";
|
||||
const API_TOKEN = process.env.POEDITOR_API;
|
||||
const PROJECT_ID = process.env.POEDITOR_PROJECT_ID;
|
||||
const LANGUAGES = (
|
||||
process.env.LANGUAGES || "ar,zh-tw,cs,en,fi,fr,de,pt-br,ru,es,tr,ja"
|
||||
process.env.LANGUAGES || "ar,zh-tw,cs,en,fi,fr,de,pt-br,ru,es,tr,ja,zh-cn"
|
||||
).split(",");
|
||||
const EXPORT_FORMAT = process.env.EXPORT_FORMAT || "key_value_json";
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
|
||||
- name: Install client dependencies
|
||||
working-directory: client
|
||||
run: npm ci
|
||||
run: npm install
|
||||
|
||||
- name: Check client formatting
|
||||
working-directory: client
|
||||
@@ -34,7 +34,7 @@ jobs:
|
||||
|
||||
- name: Install server dependencies
|
||||
working-directory: server
|
||||
run: npm ci
|
||||
run: npm install
|
||||
|
||||
- name: Check server formatting
|
||||
working-directory: server
|
||||
|
||||
@@ -7,7 +7,7 @@ on:
|
||||
languages:
|
||||
description: "Languages to synchronize (comma separated, e.g.: tr,en,es)"
|
||||
required: false
|
||||
default: "ar,zh-tw,cs,en,fi,fr,de,pt-br,ru,es,tr,ja"
|
||||
default: "ar,zh-tw,cs,en,fi,fr,de,pt-br,ru,es,tr,ja,zh-cn"
|
||||
format:
|
||||
description: "Export format (key_value_json or json)"
|
||||
required: false
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useTheme } from "@emotion/react";
|
||||
import { Box, Stack, Tooltip, Typography } from "@mui/material";
|
||||
import { formatDateWithTz } from "../../../Utils/timeUtils";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useEffect, useState, forwardRef } from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
@@ -17,26 +17,32 @@ import PropTypes from "prop-types";
|
||||
* @returns {JSX.Element} The Bar component.
|
||||
*/
|
||||
|
||||
const Bar = ({ width, height, backgroundColor, borderRadius, children }) => {
|
||||
const theme = useTheme();
|
||||
const Bar = forwardRef(
|
||||
({ width, height, backgroundColor, borderRadius, children, ...otherProps }, ref) => {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<Box
|
||||
position="relative"
|
||||
width={width}
|
||||
height={height}
|
||||
backgroundColor={backgroundColor}
|
||||
sx={{
|
||||
borderRadius: borderRadius || theme.spacing(1.5),
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
return (
|
||||
<Box
|
||||
ref={ref}
|
||||
position="relative"
|
||||
width={width}
|
||||
height={height}
|
||||
backgroundColor={backgroundColor}
|
||||
sx={{
|
||||
borderRadius: borderRadius || theme.spacing(1.5),
|
||||
}}
|
||||
{...otherProps}
|
||||
>
|
||||
{children}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
Bar.displayName = "Bar";
|
||||
|
||||
Bar.propTypes = {
|
||||
width: PropTypes.string.isRequired,
|
||||
width: PropTypes.oneOfType([PropTypes.string, PropTypes.object]).isRequired,
|
||||
height: PropTypes.string.isRequired,
|
||||
backgroundColor: PropTypes.string.isRequired,
|
||||
borderRadius: PropTypes.string,
|
||||
|
||||
@@ -65,7 +65,7 @@ const Check = ({ text, noHighlightText, variant = "info", outlined = false }) =>
|
||||
};
|
||||
|
||||
Check.propTypes = {
|
||||
text: PropTypes.oneOfType([PropTypes.string, PropTypes.element]).isRequired,
|
||||
text: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
|
||||
noHighlightText: PropTypes.string,
|
||||
variant: PropTypes.oneOf(["info", "error", "success"]),
|
||||
outlined: PropTypes.bool,
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useId } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { Modal, Stack, Typography } from "@mui/material";
|
||||
|
||||
const GenericDialog = ({ title, description, open, onClose, theme, children }) => {
|
||||
const GenericDialog = ({ title, description, open, onClose, theme, children, width }) => {
|
||||
const titleId = useId();
|
||||
const descriptionId = useId();
|
||||
const ariaDescribedBy = description?.length > 0 ? descriptionId : "";
|
||||
@@ -16,6 +16,7 @@ const GenericDialog = ({ title, description, open, onClose, theme, children }) =
|
||||
>
|
||||
<Stack
|
||||
gap={theme.spacing(2)}
|
||||
width={width}
|
||||
sx={{
|
||||
position: "absolute",
|
||||
top: "50%",
|
||||
@@ -39,6 +40,7 @@ const GenericDialog = ({ title, description, open, onClose, theme, children }) =
|
||||
fontSize={16}
|
||||
color={theme.palette.primary.contrastText}
|
||||
fontWeight={600}
|
||||
marginBottom={theme.spacing(4)}
|
||||
>
|
||||
{title}
|
||||
</Typography>
|
||||
@@ -46,6 +48,7 @@ const GenericDialog = ({ title, description, open, onClose, theme, children }) =
|
||||
<Typography
|
||||
id={descriptionId}
|
||||
color={theme.palette.primary.contrastTextTertiary}
|
||||
marginBottom={theme.spacing(4)}
|
||||
>
|
||||
{description}
|
||||
</Typography>
|
||||
@@ -64,6 +67,7 @@ GenericDialog.propTypes = {
|
||||
theme: PropTypes.object.isRequired,
|
||||
children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node])
|
||||
.isRequired,
|
||||
width: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.object]),
|
||||
};
|
||||
|
||||
export { GenericDialog };
|
||||
@@ -14,25 +14,25 @@ const useGetInviteToken = () => {
|
||||
const clearToken = () => {
|
||||
setToken(undefined);
|
||||
};
|
||||
|
||||
const fetchToken = async (email, role) => {
|
||||
const response = await networkService.requestInvitationToken({ email, role });
|
||||
const token = response?.data?.data?.token;
|
||||
if (typeof token === "undefined") {
|
||||
throw new Error(t("inviteNoTokenFound"));
|
||||
}
|
||||
return token;
|
||||
};
|
||||
const getInviteToken = async ({ email, role }) => {
|
||||
try {
|
||||
const response = await networkService.requestInvitationToken({
|
||||
email,
|
||||
role,
|
||||
});
|
||||
const token = response?.data?.data?.token;
|
||||
if (typeof token === "undefined") {
|
||||
throw new Error(t("inviteNoTokenFound"));
|
||||
}
|
||||
|
||||
setIsLoading(true);
|
||||
const token = await fetchToken(email, role);
|
||||
let inviteLink = token;
|
||||
|
||||
if (typeof CLIENT_HOST !== "undefined") {
|
||||
inviteLink = `${CLIENT_HOST}/register/${token}`;
|
||||
}
|
||||
|
||||
setToken(inviteLink);
|
||||
return token;
|
||||
} catch (error) {
|
||||
setError(error);
|
||||
} finally {
|
||||
@@ -40,7 +40,26 @@ const useGetInviteToken = () => {
|
||||
}
|
||||
};
|
||||
|
||||
return [getInviteToken, clearToken, isLoading, error, token];
|
||||
const addTeamMember = async (formData, role) => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const token = await fetchToken(formData.email, role);
|
||||
const toSubmit = {
|
||||
...formData,
|
||||
inviteToken: token,
|
||||
};
|
||||
delete toSubmit.confirm;
|
||||
const responseRegister = await networkService.registerUser(toSubmit);
|
||||
return responseRegister;
|
||||
} catch (error) {
|
||||
setError(error);
|
||||
throw error;
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return [getInviteToken, clearToken, isLoading, error, token, addTeamMember];
|
||||
};
|
||||
|
||||
export { useGetInviteToken };
|
||||
@@ -0,0 +1,68 @@
|
||||
import { useState } from "react";
|
||||
import Button from "@mui/material/Button";
|
||||
import Menu from "@mui/material/Menu";
|
||||
import MenuItem from "@mui/material/MenuItem";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import ArrowDropDownIcon from "@mui/icons-material/ArrowDropDown";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import Proptypes from "prop-types";
|
||||
|
||||
const AddMemberMenu = ({ handleInviteOpen, handleIsRegisterOpen }) => {
|
||||
const [anchorEl, setAnchorEl] = useState(null);
|
||||
const open = Boolean(anchorEl);
|
||||
const { t } = useTranslation();
|
||||
const theme = useTheme();
|
||||
const handleClick = (event) => {
|
||||
setAnchorEl(event.currentTarget);
|
||||
};
|
||||
const handleClose = () => {
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="accent"
|
||||
endIcon={<ArrowDropDownIcon sx={{ color: theme.palette.secondary.light }} />}
|
||||
onClick={handleClick}
|
||||
>
|
||||
{t("teamPanel.addTeamMember.addMemberMenu")}
|
||||
</Button>
|
||||
<Menu
|
||||
anchorEl={anchorEl}
|
||||
open={open}
|
||||
onClose={handleClose}
|
||||
sx={{
|
||||
"& .MuiPaper-root": {
|
||||
minWidth: anchorEl?.offsetWidth || "auto",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<MenuItem
|
||||
onClick={() => {
|
||||
handleClose();
|
||||
handleInviteOpen();
|
||||
}}
|
||||
>
|
||||
{t("teamPanel.inviteTeamMember")}
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
onClick={() => {
|
||||
handleClose();
|
||||
handleIsRegisterOpen(true);
|
||||
}}
|
||||
>
|
||||
{t("teamPanel.register")}
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
AddMemberMenu.propTypes = {
|
||||
handleInviteOpen: Proptypes.func.isRequired,
|
||||
handleIsRegisterOpen: Proptypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default AddMemberMenu;
|
||||
@@ -0,0 +1,48 @@
|
||||
import { useState } from "react";
|
||||
import { newOrChangedCredentials } from "../../../../../Validation/validation";
|
||||
import { useTranslation } from "react-i18next";
|
||||
const useAddTeamMember = () => {
|
||||
const { t } = useTranslation();
|
||||
const [errors, setErrors] = useState({});
|
||||
|
||||
const clearErrors = () => setErrors({});
|
||||
|
||||
const validateFields = (name, value, formData) => {
|
||||
const { error } = newOrChangedCredentials.validate(
|
||||
{ [name]: value },
|
||||
{ abortEarly: false, context: { password: formData.password } }
|
||||
);
|
||||
|
||||
setErrors((prev) => ({
|
||||
...prev,
|
||||
[name]: error?.details?.[0]?.message || "",
|
||||
}));
|
||||
};
|
||||
|
||||
const validateForm = (formData, role) => {
|
||||
const { error } = newOrChangedCredentials.validate(formData, {
|
||||
abortEarly: false,
|
||||
context: { password: formData.password },
|
||||
});
|
||||
const formErrors = {};
|
||||
if (error) {
|
||||
for (const err of error.details) {
|
||||
formErrors[err.path[0]] = err.message;
|
||||
}
|
||||
}
|
||||
if (!role[0] || role.length === 0) {
|
||||
formErrors.role = t(
|
||||
"teamPanel.registerTeamMember.auth.common.inputs.role.errors.empty"
|
||||
);
|
||||
}
|
||||
if (Object.keys(formErrors).length > 0) {
|
||||
setErrors(formErrors);
|
||||
return false;
|
||||
}
|
||||
setErrors({});
|
||||
return true;
|
||||
};
|
||||
|
||||
return { errors, setErrors, clearErrors, validateFields, validateForm };
|
||||
};
|
||||
export default useAddTeamMember;
|
||||
@@ -0,0 +1,213 @@
|
||||
import { Button, Stack } from "@mui/material";
|
||||
import { GenericDialog } from "../../../../Components/Dialog/genericDialog";
|
||||
import TextInput from "../../../../Components/Inputs/TextInput";
|
||||
import Select from "../../../../Components/Inputs/Select";
|
||||
import { useGetInviteToken } from "../../../../Hooks/inviteHooks";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { createToast } from "../../../../Utils/toastUtils";
|
||||
import { useState } from "react";
|
||||
import PasswordTooltip from "../../../Auth/components/PasswordTooltip";
|
||||
import useAddTeamMember from "./hooks/useAddTeamMember";
|
||||
import usePasswordFeedback from "../../../Auth/hooks/usePasswordFeedback";
|
||||
import { PasswordEndAdornment } from "../../../../Components/Inputs/TextInput/Adornments";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
const INITIAL_FORM_STATE = {
|
||||
firstName: "",
|
||||
lastName: "",
|
||||
email: "",
|
||||
password: "",
|
||||
confirm: "",
|
||||
teamId: "",
|
||||
};
|
||||
|
||||
const INITIAL_ROLE_STATE = ["user"];
|
||||
const AddTeamMember = ({ handleIsRegisterOpen, isRegisterOpen, onMemberAdded }) => {
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation();
|
||||
const { errors, setErrors, clearErrors, validateFields, validateForm } =
|
||||
useAddTeamMember();
|
||||
const { feedback, handlePasswordFeedback } = usePasswordFeedback();
|
||||
const [getInviteToken, clearToken, isLoading, error, token, addTeamMember] =
|
||||
useGetInviteToken();
|
||||
const [form, setForm] = useState(INITIAL_FORM_STATE);
|
||||
const [role, setRole] = useState(INITIAL_ROLE_STATE);
|
||||
const [isLoadingSubmit, setIsLoadingSubmit] = useState(false);
|
||||
const closeAddMemberModal = () => {
|
||||
handleIsRegisterOpen(false);
|
||||
setForm(INITIAL_FORM_STATE);
|
||||
setRole(INITIAL_ROLE_STATE);
|
||||
clearErrors();
|
||||
clearToken();
|
||||
};
|
||||
|
||||
const onChange = (e) => {
|
||||
let { name, value } = e.target;
|
||||
if (name === "email") value = value.toLowerCase();
|
||||
const updatedForm = { ...form, [name]: value };
|
||||
validateFields(name, value, updatedForm);
|
||||
setForm(updatedForm);
|
||||
|
||||
if (name === "password" || name === "confirm") {
|
||||
handlePasswordFeedback(updatedForm, name, value, form, errors, setErrors);
|
||||
}
|
||||
};
|
||||
|
||||
const onsubmitAddMember = async (event) => {
|
||||
event.preventDefault();
|
||||
if (!validateForm(form, role)) return;
|
||||
try {
|
||||
setIsLoadingSubmit(true);
|
||||
await addTeamMember(form, role);
|
||||
createToast({
|
||||
body: t("teamPanel.registerToast.success"),
|
||||
});
|
||||
onMemberAdded();
|
||||
closeAddMemberModal();
|
||||
} catch (error) {
|
||||
const errorMsg = error.response?.data?.msg || error.message || "unknownError";
|
||||
createToast({
|
||||
type: "error",
|
||||
body: t(errorMsg),
|
||||
});
|
||||
} finally {
|
||||
setIsLoadingSubmit(false);
|
||||
}
|
||||
};
|
||||
const tErr = (key) => (key ? t([`teamPanel.registerTeamMember.${key}`, key]) : "");
|
||||
return (
|
||||
<>
|
||||
<GenericDialog
|
||||
title={t("teamPanel.addTeamMember.title")}
|
||||
description={t("teamPanel.addTeamMember.description")}
|
||||
open={isRegisterOpen}
|
||||
onClose={closeAddMemberModal}
|
||||
theme={theme}
|
||||
width={{ sm: "55%", md: "50%", lg: "40%", xl: "30%" }}
|
||||
>
|
||||
<TextInput
|
||||
name="firstName"
|
||||
label={t("auth.common.inputs.firstName.label")}
|
||||
isRequired={true}
|
||||
gap={theme.spacing(4)}
|
||||
placeholder={t("auth.common.inputs.firstName.placeholder")}
|
||||
value={form.firstName}
|
||||
onChange={onChange}
|
||||
error={errors.firstName ? true : false}
|
||||
helperText={errors.firstName ? tErr(errors.firstName) : null}
|
||||
sx={{ mb: errors.firstName ? theme.spacing(15) : theme.spacing(5) }}
|
||||
/>
|
||||
|
||||
<TextInput
|
||||
name="lastName"
|
||||
label={t("auth.common.inputs.lastName.label")}
|
||||
isRequired={true}
|
||||
gap={theme.spacing(4)}
|
||||
placeholder={t("auth.common.inputs.lastName.placeholder")}
|
||||
value={form.lastName}
|
||||
onChange={onChange}
|
||||
error={errors.lastName ? true : false}
|
||||
helperText={errors.lastName ? tErr(errors.lastName) : null}
|
||||
sx={{ mb: errors.lastName ? theme.spacing(15) : theme.spacing(5) }}
|
||||
/>
|
||||
|
||||
<TextInput
|
||||
type="email"
|
||||
label={t("auth.common.inputs.email.label")}
|
||||
name="email"
|
||||
gap={theme.spacing(4)}
|
||||
isRequired={true}
|
||||
id="input-team-member"
|
||||
placeholder={t("teamPanel.email")}
|
||||
value={form.email}
|
||||
onChange={onChange}
|
||||
error={errors.email ? true : false}
|
||||
helperText={errors.email ? tErr(errors.email) : null}
|
||||
sx={{ mb: errors.email ? theme.spacing(15) : theme.spacing(5) }}
|
||||
/>
|
||||
|
||||
<Select
|
||||
label={t("teamPanel.role")}
|
||||
id="team-member-role"
|
||||
name="role"
|
||||
required={true}
|
||||
placeholder={t("teamPanel.selectRole")}
|
||||
isHidden={true}
|
||||
value={role[0] || ""}
|
||||
sx={{ mb: theme.spacing(5) }}
|
||||
onChange={(event) => setRole([event.target.value])}
|
||||
items={[
|
||||
{ _id: "admin", name: t("roles.admin") },
|
||||
{ _id: "user", name: t("roles.teamMember") },
|
||||
]}
|
||||
/>
|
||||
|
||||
<PasswordTooltip
|
||||
feedback={feedback}
|
||||
form={form}
|
||||
>
|
||||
<TextInput
|
||||
type="password"
|
||||
id="register-password-input"
|
||||
name="password"
|
||||
label={t("auth.common.inputs.password.label")}
|
||||
isRequired={true}
|
||||
placeholder="••••••••••"
|
||||
value={form.password}
|
||||
onChange={onChange}
|
||||
error={errors.password && errors.password[0] ? true : false}
|
||||
endAdornment={<PasswordEndAdornment />}
|
||||
sx={{ mb: theme.spacing(5) }}
|
||||
/>
|
||||
</PasswordTooltip>
|
||||
<TextInput
|
||||
type="password"
|
||||
id="register-confirm-input"
|
||||
name="confirm"
|
||||
label={t("auth.common.inputs.passwordConfirm.label")}
|
||||
gap={theme.spacing(4)}
|
||||
isRequired={true}
|
||||
placeholder={t("auth.common.inputs.passwordConfirm.placeholder")}
|
||||
autoComplete="current-password"
|
||||
value={form.confirm}
|
||||
onChange={onChange}
|
||||
error={errors.confirm && errors.confirm[0] ? true : false}
|
||||
endAdornment={<PasswordEndAdornment />}
|
||||
sx={{ mb: theme.spacing(5) }}
|
||||
/>
|
||||
|
||||
<Stack
|
||||
direction="row"
|
||||
spacing={theme.spacing(10)}
|
||||
mt={theme.spacing(8)}
|
||||
justifyContent="flex-end"
|
||||
>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="error"
|
||||
onClick={closeAddMemberModal}
|
||||
disabled={isLoadingSubmit}
|
||||
>
|
||||
{t("teamPanel.cancel")}
|
||||
</Button>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="accent"
|
||||
onClick={onsubmitAddMember}
|
||||
disabled={isLoadingSubmit}
|
||||
>
|
||||
{t("teamPanel.addTeamMember.addButton")}
|
||||
</Button>
|
||||
</Stack>
|
||||
</GenericDialog>
|
||||
</>
|
||||
);
|
||||
};
|
||||
AddTeamMember.propTypes = {
|
||||
handleIsRegisterOpen: PropTypes.func.isRequired,
|
||||
isRegisterOpen: PropTypes.bool.isRequired,
|
||||
onMemberAdded: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default AddTeamMember;
|
||||
@@ -9,10 +9,12 @@ import { networkService } from "../../../main";
|
||||
import { createToast } from "../../../Utils/toastUtils";
|
||||
import Select from "../../../Components/Inputs/Select";
|
||||
import { GenericDialog } from "../../../Components/Dialog/genericDialog";
|
||||
import AddTeamMember from "../components/AddTeamMember";
|
||||
import DataTable from "../../../Components/Table";
|
||||
import { useGetInviteToken } from "../../../Hooks/inviteHooks";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { useIsSuperAdmin } from "../../../Hooks/useIsAdmin";
|
||||
import AddMemberMenu from "./AddMemberMenu";
|
||||
/**
|
||||
* TeamPanel component manages the organization and team members,
|
||||
* providing functionalities like renaming the organization, managing team members,
|
||||
@@ -65,7 +67,10 @@ const TeamPanel = () => {
|
||||
render: (row) => row.role,
|
||||
},
|
||||
];
|
||||
|
||||
const [refreshTrigger, setRefreshTrigger] = useState(false);
|
||||
const refreshTeamList = () => {
|
||||
setRefreshTrigger((prev) => !prev);
|
||||
};
|
||||
useEffect(() => {
|
||||
const fetchTeam = async () => {
|
||||
try {
|
||||
@@ -79,7 +84,7 @@ const TeamPanel = () => {
|
||||
};
|
||||
|
||||
fetchTeam();
|
||||
}, []);
|
||||
}, [refreshTrigger]);
|
||||
|
||||
useEffect(() => {
|
||||
const ROLE_MAP = {
|
||||
@@ -109,6 +114,10 @@ const TeamPanel = () => {
|
||||
setIsDisabled(Object.keys(errors).length !== 0 || toInvite.email === "");
|
||||
}, [errors, toInvite.email]);
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [isRegisterOpen, setIsRegisterOpen] = useState(false);
|
||||
const handleIsRegisterOpen = (open) => {
|
||||
setIsRegisterOpen(open);
|
||||
};
|
||||
|
||||
const handleChange = (event) => {
|
||||
const { value } = event.target;
|
||||
@@ -138,7 +147,6 @@ const TeamPanel = () => {
|
||||
const handleGetToken = async () => {
|
||||
await getInviteToken({ email: toInvite.email, role: toInvite.role });
|
||||
};
|
||||
|
||||
const handleInviteMember = async () => {
|
||||
if (!toInvite.email) {
|
||||
setErrors((prev) => ({ ...prev, email: "Email is required." }));
|
||||
@@ -239,13 +247,16 @@ const TeamPanel = () => {
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</Stack>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="accent"
|
||||
onClick={() => setIsOpen(true)}
|
||||
>
|
||||
{t("teamPanel.inviteTeamMember")}
|
||||
</Button>
|
||||
|
||||
<AddTeamMember
|
||||
handleIsRegisterOpen={handleIsRegisterOpen}
|
||||
isRegisterOpen={isRegisterOpen}
|
||||
onMemberAdded={refreshTeamList}
|
||||
/>
|
||||
<AddMemberMenu
|
||||
handleInviteOpen={() => setIsOpen(true)}
|
||||
handleIsRegisterOpen={handleIsRegisterOpen}
|
||||
/>
|
||||
</Stack>
|
||||
|
||||
<DataTable
|
||||
@@ -264,7 +275,6 @@ const TeamPanel = () => {
|
||||
}}
|
||||
/>
|
||||
</Stack>
|
||||
|
||||
<GenericDialog
|
||||
title={t("teamPanel.inviteNewTeamMember")}
|
||||
description={t("teamPanel.inviteDescription")}
|
||||
|
||||
@@ -93,14 +93,14 @@ const PasswordTooltip = ({ feedback, form, children }) => {
|
||||
},
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
<span style={{ display: "inline-block", width: "100%" }}>{children}</span>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
PasswordTooltip.propTypes = {
|
||||
feedback: PropTypes.shape({
|
||||
length: PropTypes.string.isRequired,
|
||||
length: PropTypes.string,
|
||||
special: PropTypes.string,
|
||||
number: PropTypes.string,
|
||||
uppercase: PropTypes.string,
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
import { useState } from "react";
|
||||
import { newOrChangedCredentials } from "../../../Validation/validation";
|
||||
|
||||
const usePasswordFeedback = () => {
|
||||
const [feedback, setFeedback] = useState({});
|
||||
const getFeedbackStatus = (form, errors, field, criteria) => {
|
||||
const fieldErrors = errors?.[field];
|
||||
const isFieldEmpty = form?.[field]?.length === 0;
|
||||
const hasError = fieldErrors?.includes(criteria) || fieldErrors?.includes("empty");
|
||||
const isCorrect = !isFieldEmpty && !hasError;
|
||||
|
||||
if (isCorrect) {
|
||||
return "success";
|
||||
} else if (hasError) {
|
||||
return "error";
|
||||
} else {
|
||||
return "info";
|
||||
}
|
||||
};
|
||||
|
||||
const handlePasswordFeedback = (updatedForm, name, value, form, errors, setErrors) => {
|
||||
const validateValue = { [name]: value };
|
||||
const validateOptions = { abortEarly: false, context: { password: form.password } };
|
||||
if (name === "password" && form.confirm.length > 0) {
|
||||
validateValue.confirm = form.confirm;
|
||||
validateOptions.context = { password: value };
|
||||
} else if (name === "confirm") {
|
||||
validateValue.password = form.password;
|
||||
}
|
||||
const { error } = newOrChangedCredentials.validate(validateValue, validateOptions);
|
||||
|
||||
const pwdErrors = error?.details.map((error) => ({
|
||||
path: error.path[0],
|
||||
type: error.type,
|
||||
}));
|
||||
|
||||
const errorsByPath =
|
||||
pwdErrors &&
|
||||
pwdErrors.reduce((acc, { path, type }) => {
|
||||
if (!acc[path]) {
|
||||
acc[path] = [];
|
||||
}
|
||||
acc[path].push(type);
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
const oldErrors = { ...errors };
|
||||
if (name === "password") {
|
||||
oldErrors.password = undefined;
|
||||
} else if (name === "confirm") {
|
||||
oldErrors.confirm = undefined;
|
||||
}
|
||||
const newErrors = { ...oldErrors, ...errorsByPath };
|
||||
|
||||
setErrors(newErrors);
|
||||
|
||||
const newFeedback = {
|
||||
length: getFeedbackStatus(updatedForm, errorsByPath, "password", "string.min"),
|
||||
special: getFeedbackStatus(updatedForm, errorsByPath, "password", "special"),
|
||||
number: getFeedbackStatus(updatedForm, errorsByPath, "password", "number"),
|
||||
uppercase: getFeedbackStatus(updatedForm, errorsByPath, "password", "uppercase"),
|
||||
lowercase: getFeedbackStatus(updatedForm, errorsByPath, "password", "lowercase"),
|
||||
confirm: getFeedbackStatus(updatedForm, errorsByPath, "confirm", "different"),
|
||||
};
|
||||
|
||||
setFeedback(newFeedback);
|
||||
};
|
||||
return { feedback, handlePasswordFeedback, getFeedbackStatus };
|
||||
};
|
||||
|
||||
export default usePasswordFeedback;
|
||||
@@ -11,7 +11,12 @@ import PropTypes from "prop-types";
|
||||
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
const MonitorsList = ({ isLoading = false, shouldRender = true, monitors = [] }) => {
|
||||
const MonitorsList = ({
|
||||
isLoading = false,
|
||||
shouldRender = true,
|
||||
monitors = [],
|
||||
statusPage = {},
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
const { determineState } = useMonitorUtils();
|
||||
|
||||
@@ -40,10 +45,12 @@ const MonitorsList = ({ isLoading = false, shouldRender = true, monitors = [] })
|
||||
alignItems="center"
|
||||
gap={theme.spacing(20)}
|
||||
>
|
||||
<Box flex={9}>
|
||||
<StatusPageBarChart checks={monitor?.checks?.slice().reverse()} />
|
||||
</Box>
|
||||
<Box flex={1}>
|
||||
{statusPage.showCharts !== false && (
|
||||
<Box flex={9}>
|
||||
<StatusPageBarChart checks={monitor?.checks?.slice().reverse()} />
|
||||
</Box>
|
||||
)}
|
||||
<Box flex={statusPage.showCharts !== false ? 1 : 10}>
|
||||
<StatusLabel
|
||||
status={status}
|
||||
text={status}
|
||||
@@ -60,6 +67,7 @@ const MonitorsList = ({ isLoading = false, shouldRender = true, monitors = [] })
|
||||
|
||||
MonitorsList.propTypes = {
|
||||
monitors: PropTypes.array.isRequired,
|
||||
statusPage: PropTypes.object,
|
||||
};
|
||||
|
||||
export default MonitorsList;
|
||||
@@ -154,7 +154,10 @@ const PublicStatus = () => {
|
||||
/>
|
||||
<Typography variant="h2">{t("statusPageStatusServiceStatus")}</Typography>
|
||||
<StatusBar monitors={monitors} />
|
||||
<MonitorsList monitors={monitors} />
|
||||
<MonitorsList
|
||||
monitors={monitors}
|
||||
statusPage={statusPage}
|
||||
/>
|
||||
{link}
|
||||
</Stack>
|
||||
);
|
||||
|
||||
@@ -223,7 +223,7 @@ const Routes = () => {
|
||||
<Route
|
||||
exact
|
||||
path="/register/:token"
|
||||
element={<AuthRegister />}
|
||||
element={<AuthRegister superAdminExists={true} />}
|
||||
/>
|
||||
|
||||
<Route
|
||||
|
||||
@@ -360,6 +360,12 @@
|
||||
"demoUser": "Demo user"
|
||||
},
|
||||
"teamPanel": {
|
||||
"addTeamMember": {
|
||||
"addMemberMenu": "Add Team Member",
|
||||
"title": "Register new team member",
|
||||
"description": "Create a new user and share the credentials with them. This method gives the member immediate access to all monitors.",
|
||||
"addButton": "Add Member"
|
||||
},
|
||||
"teamMembers": "Team members",
|
||||
"filter": {
|
||||
"all": "All",
|
||||
@@ -375,6 +381,45 @@
|
||||
"noMembers": "There are no team members with this role",
|
||||
"getToken": "Get token",
|
||||
"emailToken": "E-mail token",
|
||||
"register": "Register a team member",
|
||||
"registerToast": {
|
||||
"success": "User created, share credentials with the member securely.",
|
||||
"dbUserExists": "User already exists.",
|
||||
"unknownError": "Unknown error occurred."
|
||||
},
|
||||
"registerTeamMember": {
|
||||
"title": "Register team member",
|
||||
"auth": {
|
||||
"common": {
|
||||
"inputs": {
|
||||
"firstName": {
|
||||
"errors": {
|
||||
"empty": "Please enter a name",
|
||||
"pattern": "Name must contain only letters, spaces, apostrophes, or hyphens"
|
||||
}
|
||||
},
|
||||
"lastName": {
|
||||
"errors": {
|
||||
"empty": "Please enter a surname",
|
||||
"pattern": "Surname must contain only letters, spaces, apostrophes, or hyphens"
|
||||
}
|
||||
},
|
||||
"email": {
|
||||
"errors": {
|
||||
"empty": "To continue, please enter an email address",
|
||||
"invalid": "Please recheck validity of entered email address"
|
||||
}
|
||||
},
|
||||
"role": {
|
||||
"errors": {
|
||||
"empty": "Role is required"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"role": "Role",
|
||||
"table": {
|
||||
"name": "Name",
|
||||
"email": "Email",
|
||||
|
||||
@@ -5,7 +5,7 @@ import { execSync } from "child_process";
|
||||
|
||||
export default defineConfig(({ mode }) => {
|
||||
const env = loadEnv(mode, process.cwd(), "");
|
||||
let version = "3.1.5";
|
||||
let version = "3.1.7";
|
||||
|
||||
return {
|
||||
base: "/",
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
FROM node:20-slim
|
||||
|
||||
# Install ping
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y iputils-ping \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY ../../package*.json ./
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
FROM node:20-slim
|
||||
|
||||
# Install ping
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y iputils-ping \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY ./server/package*.json ./
|
||||
|
||||
@@ -2,6 +2,7 @@ services:
|
||||
server:
|
||||
image: ghcr.io/bluewave-labs/checkmate-backend-mono-multiarch:latest
|
||||
restart: always
|
||||
pull_policy: always
|
||||
ports:
|
||||
- "52345:52345"
|
||||
environment:
|
||||
@@ -16,7 +17,7 @@ services:
|
||||
mongodb:
|
||||
image: mongo:4.4.18
|
||||
restart: always
|
||||
command: ["mongod", "--quiet", --bind_ip_all"]
|
||||
command: ["mongod", "--quiet", "--bind_ip_all"]
|
||||
ports:
|
||||
- "27017:27017"
|
||||
volumes:
|
||||
|
||||
@@ -1,30 +1,35 @@
|
||||
# ---------------------
|
||||
# Frontend build stage
|
||||
# ---------------------
|
||||
FROM --platform=$BUILDPLATFORM node:24-slim AS frontend-build
|
||||
FROM node:24-slim AS frontend-build
|
||||
|
||||
# Install ping
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y iputils-ping \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /app/client
|
||||
|
||||
COPY client/package*.json ./
|
||||
COPY client/package.json ./
|
||||
|
||||
RUN npm ci
|
||||
RUN npm install
|
||||
|
||||
RUN npm install esbuild@0.25.5 --build-from-source
|
||||
|
||||
COPY client ./
|
||||
|
||||
RUN npm rebuild esbuild
|
||||
|
||||
RUN npm run build
|
||||
|
||||
# ---------------------
|
||||
# Backend stage
|
||||
# ---------------------
|
||||
FROM --platform=$BUILDPLATFORM node:24-slim AS backend
|
||||
FROM node:24-slim AS backend
|
||||
|
||||
WORKDIR /app/server
|
||||
|
||||
COPY server/package*.json ./
|
||||
COPY server/package.json ./
|
||||
|
||||
RUN npm ci
|
||||
RUN npm install
|
||||
|
||||
COPY server ./
|
||||
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
FROM node:20-slim AS frontend-build
|
||||
|
||||
# Install ping
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y iputils-ping \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /app/client
|
||||
|
||||
COPY client/package*.json ./
|
||||
|
||||
Vendored
+5
@@ -1,5 +1,10 @@
|
||||
FROM node:20-slim
|
||||
|
||||
# Install ping
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y iputils-ping \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY ./server/package*.json ./
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
FROM node:20-slim
|
||||
|
||||
# Install ping
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y iputils-ping \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ENV NODE_OPTIONS="--max-old-space-size=2048"
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
FROM node:20-slim
|
||||
|
||||
# Install ping
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y iputils-ping \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ENV NODE_OPTIONS="--max-old-space-size=2048"
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
Generated
+448
-42
@@ -39,7 +39,7 @@
|
||||
"ping": "0.4.4",
|
||||
"sharp": "0.33.5",
|
||||
"ssl-checker": "2.0.10",
|
||||
"super-simple-scheduler": "1.4.0",
|
||||
"super-simple-scheduler": "1.4.1",
|
||||
"swagger-ui-express": "5.0.1",
|
||||
"winston": "^3.13.0"
|
||||
},
|
||||
@@ -248,10 +248,20 @@
|
||||
"kuler": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@emnapi/runtime": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.5.0.tgz",
|
||||
"integrity": "sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint-community/eslint-utils": {
|
||||
"version": "4.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz",
|
||||
"integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==",
|
||||
"version": "4.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.8.0.tgz",
|
||||
"integrity": "sha512-MJQFqrZgcW0UNYLGOuQpey/oTN59vyWwplvCGZztn1cKz9agZPPYpJB7h2OMmuu7VLqkvEjN8feFZJmxNF9D+Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -459,33 +469,19 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@humanfs/node": {
|
||||
"version": "0.16.6",
|
||||
"resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz",
|
||||
"integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==",
|
||||
"version": "0.16.7",
|
||||
"resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz",
|
||||
"integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@humanfs/core": "^0.19.1",
|
||||
"@humanwhocodes/retry": "^0.3.0"
|
||||
"@humanwhocodes/retry": "^0.4.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.18.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": {
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz",
|
||||
"integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=18.18"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/nzakas"
|
||||
}
|
||||
},
|
||||
"node_modules/@humanwhocodes/module-importer": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
|
||||
@@ -514,6 +510,130 @@
|
||||
"url": "https://github.com/sponsors/nzakas"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-darwin-arm64": {
|
||||
"version": "0.33.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz",
|
||||
"integrity": "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-darwin-arm64": "1.0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-darwin-x64": {
|
||||
"version": "0.33.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz",
|
||||
"integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-darwin-x64": "1.0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-darwin-arm64": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz",
|
||||
"integrity": "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "LGPL-3.0-or-later",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-darwin-x64": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz",
|
||||
"integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "LGPL-3.0-or-later",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-linux-arm": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz",
|
||||
"integrity": "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"license": "LGPL-3.0-or-later",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-linux-arm64": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz",
|
||||
"integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "LGPL-3.0-or-later",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-linux-s390x": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz",
|
||||
"integrity": "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"license": "LGPL-3.0-or-later",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-linux-x64": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz",
|
||||
@@ -530,6 +650,104 @@
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-linuxmusl-arm64": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz",
|
||||
"integrity": "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "LGPL-3.0-or-later",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-linuxmusl-x64": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz",
|
||||
"integrity": "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "LGPL-3.0-or-later",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-linux-arm": {
|
||||
"version": "0.33.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz",
|
||||
"integrity": "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linux-arm": "1.0.5"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-linux-arm64": {
|
||||
"version": "0.33.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz",
|
||||
"integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linux-arm64": "1.0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-linux-s390x": {
|
||||
"version": "0.33.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz",
|
||||
"integrity": "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linux-s390x": "1.0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-linux-x64": {
|
||||
"version": "0.33.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz",
|
||||
@@ -552,6 +770,107 @@
|
||||
"@img/sharp-libvips-linux-x64": "1.0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-linuxmusl-arm64": {
|
||||
"version": "0.33.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz",
|
||||
"integrity": "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linuxmusl-arm64": "1.0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-linuxmusl-x64": {
|
||||
"version": "0.33.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz",
|
||||
"integrity": "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linuxmusl-x64": "1.0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-wasm32": {
|
||||
"version": "0.33.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz",
|
||||
"integrity": "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==",
|
||||
"cpu": [
|
||||
"wasm32"
|
||||
],
|
||||
"license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@emnapi/runtime": "^1.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-win32-ia32": {
|
||||
"version": "0.33.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz",
|
||||
"integrity": "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"license": "Apache-2.0 AND LGPL-3.0-or-later",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-win32-x64": {
|
||||
"version": "0.33.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz",
|
||||
"integrity": "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "Apache-2.0 AND LGPL-3.0-or-later",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@ioredis/commands": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.3.1.tgz",
|
||||
@@ -632,6 +951,58 @@
|
||||
"sparse-bitfield": "^3.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.3.tgz",
|
||||
"integrity": "sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
]
|
||||
},
|
||||
"node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.3.tgz",
|
||||
"integrity": "sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
]
|
||||
},
|
||||
"node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.3.tgz",
|
||||
"integrity": "sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.3.tgz",
|
||||
"integrity": "sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.3.tgz",
|
||||
@@ -645,6 +1016,19 @@
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.3.tgz",
|
||||
"integrity": "sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@pkgjs/parseargs": {
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
|
||||
@@ -886,6 +1270,12 @@
|
||||
"undici-types": "~7.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/relateurl": {
|
||||
"version": "0.2.33",
|
||||
"resolved": "https://registry.npmjs.org/@types/relateurl/-/relateurl-0.2.33.tgz",
|
||||
"integrity": "sha512-bTQCKsVbIdzLqZhLkF5fcJQreE4y1ro4DIyVrlDNSCJRRwHhB8Z+4zXXa8jN6eDvc2HbRsEYgbvrnGvi54EpSw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/triple-beam": {
|
||||
"version": "1.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz",
|
||||
@@ -1515,9 +1905,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001737",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001737.tgz",
|
||||
"integrity": "sha512-BiloLiXtQNrY5UyF0+1nSJLXUENuhka2pzy2Fx5pGxqavdrxSCW4U6Pn/PoG3Efspi2frRbHpBV2XsrPE6EDlw==",
|
||||
"version": "1.0.30001739",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001739.tgz",
|
||||
"integrity": "sha512-y+j60d6ulelrNSwpPyrHdl+9mJnQzHBr08xm48Qno0nSk4h3Qojh+ziv2qE6rXf4k3tadF4o1J/1tAbVm1NtnA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
@@ -2630,9 +3020,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
"version": "1.5.211",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.211.tgz",
|
||||
"integrity": "sha512-IGBvimJkotaLzFnwIVgW9/UD/AOJ2tByUmeOrtqBfACSbAw5b1G0XpvdaieKyc7ULmbwXVx+4e4Be8pOPBrYkw==",
|
||||
"version": "1.5.213",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.213.tgz",
|
||||
"integrity": "sha512-xr9eRzSLNa4neDO0xVFrkXu3vyIzG4Ay08dApecw42Z1NbmCt+keEpXdvlYGVe0wtvY5dhW0Ay0lY0IOfsCg0Q==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/emitter-component": {
|
||||
@@ -3441,6 +3831,20 @@
|
||||
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/function-bind": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||
@@ -3891,11 +4295,12 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/htmlnano": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/htmlnano/-/htmlnano-2.1.2.tgz",
|
||||
"integrity": "sha512-8Fst+0bhAfU362S6oHVb4wtJj/UYEFr0qiCLAEi8zioqmp1JYBQx5crZAADlFVX0Ly/6s/IQz6G7PL9/hgoJaQ==",
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/htmlnano/-/htmlnano-2.1.3.tgz",
|
||||
"integrity": "sha512-mzTUHhxdfDw80X36rv5qFvjvor7r0uCwXI5mzo8CW61tImbe5Jpvl3JzPAetVh54wUYVuoa8x3qw8LFn8B3gHQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/relateurl": "^0.2.33",
|
||||
"cosmiconfig": "^9.0.0",
|
||||
"posthtml": "^0.16.5"
|
||||
},
|
||||
@@ -5801,13 +6206,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/nise/node_modules/path-to-regexp": {
|
||||
"version": "8.2.0",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz",
|
||||
"integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==",
|
||||
"version": "8.3.0",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz",
|
||||
"integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/express"
|
||||
}
|
||||
},
|
||||
"node_modules/node-abort-controller": {
|
||||
@@ -7865,9 +8271,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/super-simple-scheduler": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/super-simple-scheduler/-/super-simple-scheduler-1.4.0.tgz",
|
||||
"integrity": "sha512-DO8HTrrx+23Cz2RPCuniPZ9IhHx2lgtF8ZJiBV4JfUhqDqxuJ2leQ+l3gZ+vniy4DfpMki7s6bZwM3u8norQEA==",
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/super-simple-scheduler/-/super-simple-scheduler-1.4.1.tgz",
|
||||
"integrity": "sha512-jKVwxdRBXOHrUstA2pvO4jBZIA3CUinKiQ6k5C2Wn5tscoV3srppPxW0zG3VNKTCaGxo3yPn6Zaf3IDVBcAwRA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"uuid": "11.1.0",
|
||||
@@ -7939,9 +8345,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/swagger-ui-dist": {
|
||||
"version": "5.28.0",
|
||||
"resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.28.0.tgz",
|
||||
"integrity": "sha512-I9ibQtr77BPzT28WFWMVktzQOtWzoSS2J99L0Att8gDar1atl1YTRI7NUFSr4kj8VvWICgylanYHIoHjITc7iA==",
|
||||
"version": "5.28.1",
|
||||
"resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.28.1.tgz",
|
||||
"integrity": "sha512-IvPrtNi8MvjiuDgoSmPYgg27Lvu38fnLD1OSd8Y103xXsPAqezVNnNeHnVCZ/d+CMXJblflGaIyHxAYIF3O71w==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@scarf/scarf": "=1.4.0"
|
||||
|
||||
+1
-1
@@ -46,7 +46,7 @@
|
||||
"ping": "0.4.4",
|
||||
"sharp": "0.33.5",
|
||||
"ssl-checker": "2.0.10",
|
||||
"super-simple-scheduler": "1.4.0",
|
||||
"super-simple-scheduler": "1.4.1",
|
||||
"swagger-ui-express": "5.0.1",
|
||||
"winston": "^3.13.0"
|
||||
},
|
||||
|
||||
@@ -162,6 +162,14 @@ class StatusPageModule {
|
||||
as: "monitors.checks",
|
||||
},
|
||||
},
|
||||
{
|
||||
$lookup: {
|
||||
from: "monitorstats",
|
||||
localField: "monitors._id",
|
||||
foreignField: "monitorId",
|
||||
as: "monitors.stats",
|
||||
},
|
||||
},
|
||||
{
|
||||
$addFields: {
|
||||
"monitors.orderIndex": {
|
||||
@@ -181,6 +189,9 @@ class StatusPageModule {
|
||||
},
|
||||
},
|
||||
},
|
||||
"monitors.uptimePercentage": {
|
||||
$arrayElemAt: ["$monitors.stats.uptimePercentage", 0],
|
||||
},
|
||||
},
|
||||
},
|
||||
{ $match: { "monitors.orderIndex": { $ne: -1 } } },
|
||||
|
||||
@@ -75,6 +75,9 @@ class NetworkService {
|
||||
const { response, responseTime, error } = await this.timeRequest(() => this.ping.promise.probe(monitor.url));
|
||||
|
||||
if (!response) {
|
||||
if (error) {
|
||||
throw error;
|
||||
}
|
||||
throw new Error("Ping failed - no result returned");
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user