Merge branch 'develop' into settings-zod-schema

This commit is contained in:
karenvicent committed 2026-02-16 00:12:08 -05:00
commit cd501e46cd
62 files changed
+463 -1888

No files matched your search

+2 -1
View File
@@ -3,4 +3,5 @@
.VSCodeCounter
*.sh
mongo
node_modules/
node_modules/
docs/architecture
+5 -3
View File
@@ -2472,11 +2472,13 @@
}
},
"node_modules/axios": {
"version": "1.13.4",
"version": "1.13.5",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.13.5.tgz",
"integrity": "sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==",
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.15.6",
"form-data": "^4.0.4",
"follow-redirects": "^1.15.11",
"form-data": "^4.0.5",
"proxy-from-env": "^1.1.0"
}
},
+1 -9
View File
@@ -1,4 +1,4 @@
import { useEffect, type CSSProperties } from "react";
import { type CSSProperties } from "react";
import { useSelector } from "react-redux";
import "react-toastify/dist/ReactToastify.css";
import { ToastContainer } from "react-toastify";
@@ -6,7 +6,6 @@ import { ThemeProvider } from "@emotion/react";
import lightTheme from "./Utils/Theme/lightTheme";
import darkTheme from "./Utils/Theme/darkTheme";
import { CssBaseline, GlobalStyles } from "@mui/material";
import { logger } from "./Utils/Logger"; // Import the logger
import { Routes } from "./Routes";
import AppLayout from "@/Components/v2/layout/AppLayout";
import type { RootState } from "@/Types/state";
@@ -14,13 +13,6 @@ import type { RootState } from "@/Types/state";
function App() {
const mode = useSelector((state: RootState) => state.ui.mode);
// Cleanup
useEffect(() => {
return () => {
logger.cleanup();
};
}, []);
const theme = mode === "light" ? lightTheme : darkTheme;
return (
@@ -2,7 +2,6 @@ import Stack from "@mui/material/Stack";
import Typography from "@mui/material/Typography";
import Box from "@mui/material/Box";
import { BaseBox } from "@/Components/v2/design-elements";
import Background from "@/assets/Images/background-grid.svg?react";
import { useTranslation } from "react-i18next";
import type { SxProps } from "@mui/material";
@@ -18,6 +17,7 @@ export const BGBox = ({ children, sx }: StatusBoxProps) => {
return (
<BaseBox
sx={{
backgroundColor: theme.palette.background.default,
overflow: "hidden",
position: "relative",
flex: 1,
@@ -27,11 +27,23 @@ export const BGBox = ({ children, sx }: StatusBoxProps) => {
>
<Box
position="absolute"
top="-10%"
left="5%"
>
<Background />
</Box>
top={0}
left={0}
right={0}
bottom={0}
sx={{
pointerEvents: "none",
backgroundImage: `
linear-gradient(${theme.palette.divider} 1px, transparent 1px),
linear-gradient(90deg, ${theme.palette.divider} 1px, transparent 1px)
`,
backgroundSize: "24px 24px",
maskImage:
"linear-gradient(135deg, rgba(0,0,0,0) 0%, rgba(0,0,0,0) 30%, rgba(0,0,0,0.4) 100%)",
WebkitMaskImage:
"linear-gradient(135deg, rgba(0,0,0,0) 0%, rgba(0,0,0,0) 30%, rgba(0,0,0,0.4) 100%)",
}}
/>
{children}
</BaseBox>
);
@@ -1,8 +1,9 @@
import i18n from "../../../Utils/i18n.js";
import i18n from "@/Utils/i18n.js";
import { useSelector } from "react-redux";
import { useEffect } from "react";
import type { RootState } from "@/store";
const I18nLoader = () => {
const language = useSelector((state) => state.ui.language ?? "en");
const language = useSelector((state: RootState) => state.ui.language ?? "en");
useEffect(() => {
if (language && i18n.language !== language) {
@@ -38,11 +38,11 @@ export const ImageUpload = ({
const isValidType = accept.some((type) => file.type.includes(type));
const isValidSize = file.size <= maxSize;
if (!isValidType) {
setLocalError(t("common.errors.invalidFileFormat"));
setLocalError(t("components.imageUpload.errors.invalidFileFormat"));
return;
}
if (!isValidSize) {
setLocalError(t("common.errors.invalidFileSize"));
setLocalError(t("components.imageUpload.errors.invalidFileSize"));
return;
}
setLocalError(null);
@@ -137,15 +137,15 @@ export const ImageUpload = ({
color="primary"
fontWeight={500}
>
{t("common.imageUpload.clickToUpload")}
{t("components.imageUpload.clickToUpload")}
</Typography>{" "}
{t("common.imageUpload.orDragAndDrop")}
{t("components.imageUpload.orDragAndDrop")}
</Typography>
<Typography
variant="caption"
color="text.disabled"
>
{accept.join(", ").toUpperCase()} • {t("common.imageUpload.maxSize")}{" "}
{accept.join(", ").toUpperCase()} • {t("components.imageUpload.maxSize")}{" "}
{Math.round(maxSize / 1024 / 1024)}MB
</Typography>
</Stack>
+4 -1
View File
@@ -41,7 +41,10 @@ export const SliderInput = forwardRef<HTMLSpanElement, SliderInputProps>(
"& .MuiSlider-thumb": {
backgroundColor: "#fff",
"&:hover, &.Mui-focusVisible": {
boxShadow: `0 0 0 8px ${theme.palette.primary.main}20`,
boxShadow: "none",
},
"&:active": {
boxShadow: "none",
},
},
"& .MuiSlider-valueLabel": {
@@ -3,7 +3,7 @@ import Typography from "@mui/material/Typography";
import { BaseChart } from "@/Components/v2/design-elements";
import { useTheme } from "@mui/material/styles";
import { useSelector } from "react-redux";
import { formatDateWithTz } from "@/Utils/timeUtilsLegacy";
import { formatDateWithTz } from "@/Utils/TimeUtils";
import { useTranslation } from "react-i18next";
import { ResponsiveContainer, BarChart, XAxis, Bar, Cell, Tooltip } from "recharts";
import { getResponseTimeColor } from "@/Utils/MonitorUtils";
+1 -15
View File
@@ -12,11 +12,6 @@ interface SidebarState {
collapsed: boolean;
}
interface GreetingState {
index: number;
lastUpdate: string | null;
}
interface UIState {
monitors: TableState;
team: TableState;
@@ -26,7 +21,6 @@ interface UIState {
sidebar: SidebarState;
mode: ThemeMode;
showURL: boolean;
greeting: GreetingState;
timezone: string;
distributedUptimeEnabled: boolean;
language: string;
@@ -60,7 +54,6 @@ const initialState: UIState = {
},
mode: initialMode,
showURL: false,
greeting: { index: 0, lastUpdate: null },
timezone: "America/Toronto",
distributedUptimeEnabled: false,
language: "en",
@@ -94,13 +87,7 @@ const uiSlice = createSlice({
setShowURL: (state, action: PayloadAction<boolean>) => {
state.showURL = action.payload;
},
setGreeting: (
state,
action: PayloadAction<{ index: number; lastUpdate: string | null }>
) => {
state.greeting.index = action.payload.index;
state.greeting.lastUpdate = action.payload.lastUpdate;
},
setTimezone: (state, action: PayloadAction<{ timezone: string }>) => {
state.timezone = action.payload.timezone;
},
@@ -124,7 +111,6 @@ export const {
setCollapsed,
setMode,
setShowURL,
setGreeting,
setTimezone,
setDistributedUptimeEnabled,
setLanguage,
@@ -97,27 +97,27 @@ const SetNewPasswordPage = () => {
/>
<Stack gap={theme.spacing(4)}>
<BulletPointCheck
text={t("auth.common.passwordRules.length")}
text={t("pages.auth.common.passwordRules.length")}
variant={getVariant(hasLength)}
/>
<BulletPointCheck
text={t("auth.common.passwordRules.special")}
text={t("pages.auth.common.passwordRules.special")}
variant={getVariant(hasSpecial)}
/>
<BulletPointCheck
text={t("auth.common.passwordRules.number")}
text={t("pages.auth.common.passwordRules.number")}
variant={getVariant(hasNumber)}
/>
<BulletPointCheck
text={t("auth.common.passwordRules.uppercase")}
text={t("pages.auth.common.passwordRules.uppercase")}
variant={getVariant(hasUppercase)}
/>
<BulletPointCheck
text={t("auth.common.passwordRules.lowercase")}
text={t("pages.auth.common.passwordRules.lowercase")}
variant={getVariant(hasLowercase)}
/>
<BulletPointCheck
text={t("auth.common.passwordRules.match")}
text={t("pages.auth.common.passwordRules.match")}
variant={getVariant(passwordsMatch)}
/>
</Stack>
@@ -127,7 +127,7 @@ const SetNewPasswordPage = () => {
fullWidth
loading={loading}
>
{t("auth.forgotPassword.buttons.resetPassword")}
{t("common.buttons.resetPassword")}
</Button>
<TextLink
alignSelf="center"
+161 -20
View File
@@ -329,11 +329,16 @@ const CreateMonitorPage = () => {
render={({ field, fieldState }) => (
<TextField
{...field}
value={field.value ?? ""}
onChange={(e) => field.onChange(Number(e.target.value) || 0)}
value={field.value === 0 ? "" : field.value}
onChange={(e) => {
const val = e.target.value;
field.onChange(val === "" ? 0 : Number(val));
}}
type="number"
fieldLabel={t("portToMonitor")}
placeholder="5173"
fieldLabel={t("pages.createMonitor.form.general.option.port.label")}
placeholder={t(
"pages.createMonitor.form.general.option.port.placeholder"
)}
fullWidth
error={!!fieldState.error}
helperText={fieldState.error?.message ?? ""}
@@ -351,10 +356,12 @@ const CreateMonitorPage = () => {
<Select
{...field}
value={field.value ?? ""}
fieldLabel={t("chooseGame")}
fieldLabel={t("pages.createMonitor.form.general.option.game.label")}
error={!!fieldState.error}
>
<MenuItem value="">Select a game</MenuItem>
<MenuItem value="">
{t("pages.createMonitor.form.general.option.game.placeholder")}{" "}
</MenuItem>
{games &&
Object.entries(games).map(([key, game]) => (
<MenuItem
@@ -426,22 +433,146 @@ const CreateMonitorPage = () => {
)}
error={!!fieldState.error}
>
<MenuItem value={15000}>{t("time.fifteenSeconds")}</MenuItem>
<MenuItem value={30000}>{t("time.thirtySeconds")}</MenuItem>
<MenuItem value={60000}>{t("time.oneMinute")}</MenuItem>
<MenuItem value={120000}>{t("time.twoMinutes")}</MenuItem>
<MenuItem value={180000}>{t("time.threeMinutes")}</MenuItem>
<MenuItem value={240000}>{t("time.fourMinutes")}</MenuItem>
<MenuItem value={300000}>{t("time.fiveMinutes")}</MenuItem>
<MenuItem value={600000}>{t("time.tenMinutes")}</MenuItem>
<MenuItem value={900000}>{t("time.fifteenMinutes")}</MenuItem>
<MenuItem value={1800000}>{t("time.thirtyMinutes")}</MenuItem>
<MenuItem value={15000}>
{t(
"pages.createMonitor.form.frequency.option.frequency.value.fifteenSeconds"
)}
</MenuItem>
<MenuItem value={30000}>
{t(
"pages.createMonitor.form.frequency.option.frequency.value.thirtySeconds"
)}
</MenuItem>
<MenuItem value={60000}>
{t(
"pages.createMonitor.form.frequency.option.frequency.value.oneMinute"
)}
</MenuItem>
<MenuItem value={120000}>
{t(
"pages.createMonitor.form.frequency.option.frequency.value.twoMinutes"
)}
</MenuItem>
<MenuItem value={180000}>
{t(
"pages.createMonitor.form.frequency.option.frequency.value.threeMinutes"
)}
</MenuItem>
<MenuItem value={240000}>
{t(
"pages.createMonitor.form.frequency.option.frequency.value.fourMinutes"
)}
</MenuItem>
<MenuItem value={300000}>
{t(
"pages.createMonitor.form.frequency.option.frequency.value.fiveMinutes"
)}
</MenuItem>
<MenuItem value={600000}>
{t(
"pages.createMonitor.form.frequency.option.frequency.value.tenMinutes"
)}
</MenuItem>
<MenuItem value={900000}>
{t(
"pages.createMonitor.form.frequency.option.frequency.value.fifteenMinutes"
)}
</MenuItem>
<MenuItem value={1800000}>
{t(
"pages.createMonitor.form.frequency.option.frequency.value.thirtyMinutes"
)}
</MenuItem>
</Select>
)}
/>
}
/>
{/* Alert Thresholds - only for hardware type */}
{generalSettingsConfig.showSecret && (
<ConfigBox
title={t("pages.createMonitor.form.thresholds.title")}
subtitle={t("pages.createMonitor.form.thresholds.description")}
rightContent={
<Stack spacing={theme.spacing(8)}>
<Controller
name="cpuAlertThreshold"
control={control}
render={({ field }) => (
<SliderWithLabel
{...field}
sliderMaxWidth={{ xs: "100%", md: "50%" }}
fieldLabel={t(
"pages.createMonitor.form.thresholds.option.cpuThreshold.label"
)}
min={0}
max={100}
step={1}
valueLabelDisplay="auto"
valueLabelFormat={(value) => `${value}%`}
/>
)}
/>
<Controller
name="memoryAlertThreshold"
control={control}
render={({ field }) => (
<SliderWithLabel
{...field}
sliderMaxWidth={{ xs: "100%", md: "50%" }}
fieldLabel={t(
"pages.createMonitor.form.thresholds.option.memoryThreshold.label"
)}
min={0}
max={100}
step={1}
valueLabelDisplay="auto"
valueLabelFormat={(value) => `${value}%`}
/>
)}
/>
<Controller
name="diskAlertThreshold"
control={control}
render={({ field }) => (
<SliderWithLabel
{...field}
sliderMaxWidth={{ xs: "100%", md: "50%" }}
fieldLabel={t(
"pages.createMonitor.form.thresholds.option.diskThreshold.label"
)}
min={0}
max={100}
step={1}
valueLabelDisplay="auto"
valueLabelFormat={(value) => `${value}%`}
/>
)}
/>
<Controller
name="tempAlertThreshold"
control={control}
render={({ field }) => (
<SliderWithLabel
{...field}
sliderMaxWidth={{ xs: "100%", md: "50%" }}
fieldLabel={t(
"pages.createMonitor.form.thresholds.option.tempThreshold.label"
)}
min={0}
max={100}
step={1}
valueLabelDisplay="auto"
valueLabelFormat={(value) => `${value}°C`}
/>
)}
/>
</Stack>
}
/>
)}
<ConfigBox
title={t("pages.createMonitor.form.incidents.title")}
subtitle={t("pages.createMonitor.form.incidents.description")}
@@ -617,11 +748,21 @@ const CreateMonitorPage = () => {
"pages.createMonitor.form.advanced.option.matchMethod.label"
)}
>
<MenuItem value="equal">{t("matchMethodOptions.equal")}</MenuItem>
<MenuItem value="include">
{t("matchMethodOptions.include")}
<MenuItem value="equal">
{t(
"pages.createMonitor.form.advanced.option.matchMethod.equal"
)}
</MenuItem>
<MenuItem value="include">
{t(
"pages.createMonitor.form.advanced.option.matchMethod.include"
)}
</MenuItem>
<MenuItem value="regex">
{t(
"pages.createMonitor.form.advanced.option.matchMethod.regex"
)}
</MenuItem>
<MenuItem value="regex">{t("matchMethodOptions.regex")}</MenuItem>
</Select>
)}
/>
@@ -46,10 +46,9 @@ export const DialogResolution = ({
return (
<Dialog
open={open}
title={t("incidentsPage.resolveIncidentDialogTitle")}
title={t("pages.incidents.dialog.resolveIncident.title")}
onCancel={handleCancel}
onConfirm={handleConfirm}
confirmText={t("incidentsPage.resolveIncidentDialogConfirm")}
confirmColor="error"
cancelColor="primary"
loading={isResolving}
@@ -58,8 +57,10 @@ export const DialogResolution = ({
>
<Box sx={{ mt: theme.spacing(4) }}>
<TextField
fieldLabel={t("incidentsPage.resolveIncidentDialogCommentLabel")}
placeholder={t("incidentsPage.resolveIncidentDialogCommentPlaceholder")}
fieldLabel={t("pages.incidents.dialog.resolveIncident.option.comment.label")}
placeholder={t(
"pages.incidents.dialog.resolveIncident.option.comment.placeholder"
)}
value={comment}
onChange={(e) => setComment(e.target.value)}
fullWidth
@@ -9,13 +9,13 @@ import type { Monitor } from "@/Types/Monitor";
import type { ActionMenuItem } from "@/Components/v2/actions-menu";
import { useTranslation } from "react-i18next";
import { useNavigate } from "react-router-dom";
import { TypeToPathMap } from "@/Utils/monitorUtilsLegacy.js";
import { formatDateWithTz } from "@/Utils/TimeUtils";
import { useSelector } from "react-redux";
import type { RootState } from "@/Types/state";
import Typography from "@mui/material/Typography";
import { useTheme } from "@mui/material/styles";
import Box from "@mui/material/Box";
import { getMonitorPath } from "@/Utils/MonitorUtils";
interface IncidentsTableProps {
title?: string;
@@ -62,7 +62,7 @@ export const IncidentsTable = ({
label: t("pages.incidents.table.actions.goToMonitor"),
action: () => {
if (monitor) {
const path = TypeToPathMap[monitor.type as keyof typeof TypeToPathMap];
const path = getMonitorPath(monitor.type);
if (path && monitor.id) {
navigate(`/${path}/${monitor.id}`);
}
@@ -196,13 +196,13 @@ export const MaintenanceWindowTable = ({
/>
<DialogInput
open={deleteDialogOpen}
title={t("maintenanceTableActionMenuDialogTitle")}
title={t("common.dialogs.delete.title")}
content={t("common.dialogs.delete.description")}
onCancel={() => {
setDeleteDialogOpen(false);
setSelectedWindow(null);
}}
onConfirm={handleDelete}
confirmText={t("delete")}
loading={deleteLoading}
/>
</Box>
+2 -2
View File
@@ -9,8 +9,8 @@ import { useTheme } from "@mui/material";
import { useTranslation } from "react-i18next";
interface NotFoundProps {
title: string;
desc: string;
title?: string;
desc?: string;
}
const NotFoundPage = ({ title, desc }: NotFoundProps) => {
@@ -64,7 +64,7 @@ export const HeaderStatusPageControls = ({
},
}}
>
{t("publicLink")}
{t("components.headerStatusPageControls.publicLink")}
</Typography>
<Box>
<ExternalLink size={14} />
@@ -96,7 +96,6 @@ const StatusPageView = () => {
}}
/>
)}
<Typography variant="h2">{t("statusPageStatusServiceStatus")}</Typography>
<StatusBar monitors={monitors} />
<MonitorsList
statusPage={statusPage}
@@ -3,6 +3,7 @@ import { ThemeProvider } from "@mui/material";
import { lightTheme, darkTheme } from "@/Utils/Theme/v2Theme";
import { useSelector } from "react-redux";
import type { RootState } from "@/store";
import { Navigate, Route, Routes as LibRoutes } from "react-router";
import RootLayout from "@/Components/v2/layout/RootLayout";
import NotFound from "@/Pages/NotFound";
@@ -59,7 +60,7 @@ import {
import CreateMonitor from "@/Pages/CreateMonitor";
const Routes = () => {
const mode = useSelector((state) => state.ui.mode);
const mode = useSelector((state: RootState) => state.ui.mode);
const v2theme = mode === "light" ? lightTheme : darkTheme;
return (
<LibRoutes>
@@ -390,12 +391,11 @@ const Routes = () => {
/>
<Route
exact
path="/register/:token"
element={
<>
<ThemeProvider theme={v2theme}>
<AuthRegister superAdminExists={true} />
<AuthRegister />
</ThemeProvider>
</>
}
-74
View File
@@ -1,74 +0,0 @@
const LOG_LEVEL = import.meta.env.VITE_APP_LOG_LEVEL || "debug";
const NO_OP = () => {};
class Logger {
constructor() {
let logLevel = LOG_LEVEL;
this.updateLogLevel(logLevel);
// Defer store subscription to avoid circular dependency during HMR
setTimeout(() => {
try {
import("../store").then(({ default: store }) => {
if (store) {
this.unsubscribe = store.subscribe(() => {
logLevel = "debug";
this.updateLogLevel(logLevel);
});
}
});
} catch (e) {
// Store not ready yet, ignore
}
}, 0);
}
updateLogLevel(logLevel) {
if (logLevel === "none") {
this.info = NO_OP;
this.error = NO_OP;
this.warn = NO_OP;
this.log = NO_OP;
return;
}
if (logLevel === "error") {
this.error = console.error.bind(console);
this.info = NO_OP;
this.warn = NO_OP;
this.log = NO_OP;
return;
}
if (logLevel === "warn") {
this.error = console.error.bind(console);
this.warn = console.warn.bind(console);
this.info = NO_OP;
this.log = NO_OP;
return;
}
if (logLevel === "info") {
this.error = console.error.bind(console);
this.warn = console.warn.bind(console);
this.info = console.info.bind(console);
this.log = NO_OP;
return;
}
if (logLevel === "debug") {
this.error = console.error.bind(console);
this.warn = console.warn.bind(console);
this.info = console.info.bind(console);
this.log = console.log.bind(console);
return;
}
}
cleanup() {
if (this.unsubscribe) {
this.unsubscribe();
}
}
}
export const logger = new Logger();
+5 -42
View File
@@ -1,4 +1,4 @@
import type { Monitor, MonitorStatus, MonitorType } from "@/Types/Monitor";
import type { MonitorStatus, MonitorType } from "@/Types/Monitor";
import type { PaletteKey } from "@/Utils/Theme/v2Theme";
import type { ValueType } from "@/Components/v2/design-elements/StatusLabel";
@@ -7,11 +7,11 @@ export const getMonitorPath = (type: MonitorType): string => {
http: "uptime",
port: "uptime",
ping: "uptime",
hardware: "hardware",
pagespeed: "pagespeed",
docker: "docker",
game: "game-servers",
game: "uptime",
unknown: "uptime",
docker: "uptime",
hardware: "infrastructure",
pagespeed: "pagespeed",
};
return pathMap[type];
};
@@ -81,40 +81,3 @@ export const formatUrl = (url: string, maxLength: number = 55) => {
? `${strippedUrl.slice(0, maxLength)}…`
: strippedUrl;
};
export interface IStatusPageHeaderConfig {
paletteKey: PaletteKey;
message: string;
}
export const getStatusPageHeaderConfig = (
monitors: Monitor[],
t: any
): IStatusPageHeaderConfig => {
if (!monitors || monitors.length === 0) {
return { paletteKey: "error", message: "No monitors available" };
}
const allUp = monitors.every((monitor) => monitor.status === "up");
const anyDown = monitors.some((monitor) => monitor.status === "down");
const allDown = monitors.every((monitor) => monitor.status === "down");
if (allUp)
return {
paletteKey: "success",
message: t("statusPage.details.statusHeader.allUp"),
};
if (allDown)
return {
paletteKey: "error",
message: t("statusPage.details.statusHeader.allDown"),
};
if (anyDown)
return {
paletteKey: "warning",
message: t("statusPage.details.statusHeader.anyDown"),
};
return {
paletteKey: "warning",
message: t("statusPage.details.statusHeader.anyDown"),
};
};
-1
View File
@@ -1 +0,0 @@
#Utils folder
-11
View File
@@ -1,11 +0,0 @@
export const formatBytes = (bytes) => {
if (bytes === 0) return "0 Bytes";
const megabytes = bytes / (1024 * 1024);
return megabytes.toFixed(2) + " MB";
};
export const checkImage = (url) => {
const img = new Image();
img.src = url;
return img.naturalWidth !== 0;
};
-197
View File
@@ -1,197 +0,0 @@
import PropTypes from "prop-types";
import { useTheme } from "@emotion/react";
import { Box, Typography } from "@mui/material";
import { useDispatch, useSelector } from "react-redux";
import { useEffect } from "react";
import { useTranslation } from "react-i18next";
import { setGreeting } from "../Features/UI/uiSlice";
const early = [
{
prepend: "Rise and shine",
append: "If you’re up this early, you might as well be a legend!",
emoji: "☕",
},
{
prepend: "Good morning",
append: "The world’s still asleep, but you’re already awesome!",
emoji: "🦉",
},
{
prepend: "Good morning",
append: "Are you a wizard? Only magical people are up at this hour!",
emoji: "🌄",
},
{
prepend: "Up before the roosters",
append: "Ready to tackle the day before it even starts?",
emoji: "🐓",
},
{
prepend: "Early bird special",
append: "Let’s get things done while everyone else is snoozing!",
emoji: "🌟",
},
];
const morning = [
{
prepend: "Good morning",
append: "Is it coffee o’clock yet, or should we start with high fives?",
emoji: "☕",
},
{
prepend: "Morning",
append: "The sun is up, and so are you—time to be amazing!",
emoji: "🌞",
},
{
prepend: "Good morning",
append: "Time to make today the best thing since sliced bread!",
emoji: "🥐",
},
{
prepend: "Morning",
append: "Let’s kick off the day with more energy than a double espresso!",
emoji: "🚀",
},
{
prepend: "Rise and shine",
append: "You’re about to make today so great, even Monday will be jealous!",
emoji: "🌟",
},
];
const afternoon = [
{
prepend: "Good afternoon",
append: "How about a break to celebrate how awesome you’re doing?",
emoji: "🥪",
},
{
prepend: "Afternoon",
append: "If you’re still going strong, you’re officially a rockstar!",
emoji: "🌞",
},
{
prepend: "Hey there",
append: "The afternoon is your playground—let’s make it epic!",
emoji: "🍕",
},
{
prepend: "Good afternoon",
append: "Time to crush the rest of the day like a pro!",
emoji: "🏆",
},
{
prepend: "Afternoon",
append: "Time to turn those afternoon slumps into afternoon triumphs!",
emoji: "🎉",
},
];
const evening = [
{
prepend: "Good evening",
append: "Time to wind down and think about how you crushed today!",
emoji: "🌇",
},
{
prepend: "Evening",
append: "You’ve earned a break—let’s make the most of these evening vibes!",
emoji: "🍹",
},
{
prepend: "Hey there",
append: "Time to relax and bask in the glow of your day’s awesomeness!",
emoji: "🌙",
},
{
prepend: "Good evening",
append: "Ready to trade productivity for chill mode?",
emoji: "🛋️ ",
},
{
prepend: "Evening",
append: "Let’s call it a day and toast to your success!",
emoji: "🕶️",
},
];
/**
* Greeting component that displays a personalized greeting message
* based on the time of day and the user's first name.
*
* @component
* @example
* return <Greeting type={"pagespeed"} />;
*
* @param {Object} props
* @param {string} props.type - The type of monitor to be displayed in the message
* @returns {JSX.Element} The rendered Greeting component
*/
const Greeting = ({ type = "" }) => {
const theme = useTheme();
const dispatch = useDispatch();
const { t } = useTranslation();
const { firstName } = useSelector((state) => state.auth.user);
const index = useSelector((state) => state.ui.greeting?.index ?? 0);
const lastUpdate = useSelector((state) => state.ui.greeting?.lastUpdate ?? null);
const now = new Date();
const hour = now.getHours();
useEffect(() => {
const hourDiff = lastUpdate ? hour - lastUpdate : null;
if (!lastUpdate || hourDiff >= 1) {
let random = Math.floor(Math.random() * 5);
dispatch(setGreeting({ index: random, lastUpdate: hour }));
}
}, [dispatch, hour, lastUpdate]);
let greetingArray =
hour < 6 ? early : hour < 12 ? morning : hour < 18 ? afternoon : evening;
const { prepend, append, emoji } = greetingArray[index];
return (
<Box>
<Typography
component="h1"
variant="h1"
mb={theme.spacing(1)}
>
<Typography
component="span"
fontSize="inherit"
color={theme.palette.primary.contrastTextTertiary}
>
{t("greeting.prepend", { defaultValue: prepend })},{" "}
</Typography>
<Typography
component="span"
fontSize="inherit"
fontWeight="inherit"
color={theme.palette.primary.contrastTextSecondary}
>
{firstName} {emoji}
</Typography>
</Typography>
<Typography
variant="h2"
lineHeight={1}
color={theme.palette.primary.contrastTextTertiary}
>
{t("greeting.append", { defaultValue: append })} —{" "}
{t("greeting.overview", { type: t(`menu.${type}`) })}
</Typography>
</Box>
);
};
Greeting.propTypes = {
type: PropTypes.string,
};
export default Greeting;
@@ -1,16 +1,26 @@
import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import type { Resource } from "i18next";
const primaryLanguage = "en";
// Load all translation files eagerly
const translations = import.meta.glob("../locales/*.json", { eager: true });
interface TranslationModule {
default?: Record<string, unknown>;
[key: string]: unknown;
}
const resources = {};
// Load all translation files eagerly
const translations = import.meta.glob<TranslationModule>("../locales/*.json", {
eager: true,
});
const resources: Resource = {};
Object.keys(translations).forEach((path) => {
const langCode = path.match(/\/([^/]+)\.json$/)[1];
const match = path.match(/\/([^/]+)\.json$/);
if (!match) return;
const langCode = match[1];
resources[langCode] = {
translation: translations[path].default || translations[path],
translation: translations[path].default ?? translations[path],
};
});
-47
View File
@@ -1,47 +0,0 @@
import { capitalizeFirstLetter } from "./stringUtils";
/**
* Helper function to get duration since last check or the last date checked
* @param {Array} checks Array of check objects.
* @param {boolean} duration Whether the function should return the duration since last checked or the date itself
* @returns {number} Timestamp of the most recent check.
*/
export const getLastChecked = (checks, duration = true) => {
if (!checks || checks.length === 0) {
return 0; // Handle case when no checks are available
}
// Data is sorted newest -> oldest, so newest check is the most recent
if (!duration) {
return new Date(checks[0].createdAt);
}
return new Date() - new Date(checks[0].createdAt);
};
export const parseDomainName = (url) => {
url = url.replace(/^https?:\/\//, "");
// Remove leading/trailing dots
url = url.replace(/^\.+|\.+$/g, "");
// Split by dots
const parts = url.split(".");
// Remove common prefixes and empty parts and exclude the last element of the array (the last element should be the TLD)
const cleanParts = parts.filter((part) => part !== "www" && part !== "").slice(0, -1);
// If there's more than one part, append the two words and capitalize the first letters (e.g. ["api", "test"] -> "Api Test")
const domainPart =
cleanParts.length > 1
? cleanParts.map((part) => capitalizeFirstLetter(part)).join(" ")
: capitalizeFirstLetter(cleanParts[0]);
if (domainPart) return domainPart;
return url;
};
export const TypeToPathMap = {
http: "uptime",
port: "uptime",
docker: "uptime",
ping: "uptime",
hardware: "infrastructure",
pagespeed: "pagespeed",
};
-13
View File
@@ -1,13 +0,0 @@
export const ROLES = {
SUPERADMIN: "superadmin",
ADMIN: "admin",
USER: "user",
DEMO: "demo",
};
export const VALID_ROLES = [ROLES.ADMIN, ROLES.USER, ROLES.DEMO];
export const EDITABLE_ROLES = [
{ role: ROLES.ADMIN, _id: ROLES.ADMIN },
{ role: ROLES.USER, _id: ROLES.USER },
];
-46
View File
@@ -1,46 +0,0 @@
/**
* Helper function to get first letter capitalized string
* @param {string} str String whose first letter is to be capitalized
* @returns A string with first letter capitalized
*/
export const capitalizeFirstLetter = (str) => {
if (str === null || str === undefined) {
return "";
}
if (typeof str !== "string") {
throw new TypeError("Input must be a string");
}
if (str.length === 0) {
return "";
}
return str.charAt(0).toUpperCase() + str.slice(1);
};
/**
* Helper function to get first letter as a lower case string
* @param {string} str String whose first letter is to be lower cased
* @returns A string with first letter lower cased
*/
export const toLowerCaseFirstLetter = (str) => {
if (str === null || str === undefined) {
return "";
}
if (typeof str !== "string") {
throw new TypeError("Input must be a string");
}
if (str.length === 0) {
return "";
}
return str.charAt(0).toLowerCase() + str.slice(1);
};
/**
* Checks if a string is null, undefined, or empty (including strings with only whitespace).
* @param {string} str - The string to check.
* @returns {boolean} - Returns true if the string is null, undefined, or empty.
*/
export const isEmpty = (str) => {
// Check if string is null, undefined, or empty (including whitespace only)
return str === null || typeof str === "undefined" || str.trim().length === 0;
};
-167
View File
@@ -1,167 +0,0 @@
import dayjs from "dayjs";
import duration from "dayjs/plugin/duration";
import utc from "dayjs/plugin/utc";
import timezone from "dayjs/plugin/timezone";
import customParseFormat from "dayjs/plugin/customParseFormat";
dayjs.extend(utc);
dayjs.extend(timezone);
dayjs.extend(customParseFormat);
dayjs.extend(duration);
export const MS_PER_SECOND = 1000;
export const MS_PER_MINUTE = 60 * MS_PER_SECOND;
export const MS_PER_HOUR = 60 * MS_PER_MINUTE;
export const MS_PER_DAY = 24 * MS_PER_HOUR;
export const MS_PER_WEEK = MS_PER_DAY * 7;
export const formatDuration = (ms) => {
const seconds = Math.floor(ms / 1000);
const minutes = Math.floor(seconds / 60);
const hours = Math.floor(minutes / 60);
const days = Math.floor(hours / 24);
let dateStr = "";
days && (dateStr += `${days}d `);
hours && (dateStr += `${hours % 24}h `);
minutes && (dateStr += `${minutes % 60}m `);
seconds && (dateStr += `${seconds % 60}s `);
dateStr === "" && (dateStr = "0s");
return dateStr;
};
export const formatDurationRounded = (ms) => {
const seconds = Math.floor(ms / 1000);
const minutes = Math.floor(seconds / 60);
const hours = Math.floor(minutes / 60);
const days = Math.floor(hours / 24);
let time = "";
if (days > 0) {
time += `${days} day${days !== 1 ? "s" : ""}`;
return time;
}
if (hours > 0) {
time += `${hours} hour${hours !== 1 ? "s" : ""}`;
return time;
}
if (minutes > 0) {
time += `${minutes} minute${minutes !== 1 ? "s" : ""}`;
return time;
}
if (seconds > 0) {
time += `${seconds} second${seconds !== 1 ? "s" : ""}`;
return time;
}
return time;
};
export const formatDurationSplit = (ms) => {
const seconds = Math.floor(ms / 1000);
const minutes = Math.floor(seconds / 60);
const hours = Math.floor(minutes / 60);
const days = Math.floor(hours / 24);
return days > 0
? { time: days, format: days === 1 ? "day" : "days" }
: hours > 0
? { time: hours, format: hours === 1 ? "hour" : "hours" }
: minutes > 0
? { time: minutes, format: minutes === 1 ? "minute" : "minutes" }
: seconds > 0
? { time: seconds, format: seconds === 1 ? "second" : "seconds" }
: { time: 0, format: "seconds" };
};
export const getHumanReadableDuration = (ms) => {
const durationObj = dayjs.duration(ms);
const parts = {
days: Math.floor(durationObj.asDays()),
hours: durationObj.hours(),
minutes: durationObj.minutes(),
seconds: durationObj.seconds(),
milliseconds: durationObj.milliseconds(),
};
const result = [];
if (parts.days > 0) {
result.push(`${parts.days}d`);
}
if (parts.hours > 0) {
result.push(`${parts.hours}h`);
}
if (result.length < 2 && parts.minutes > 0) {
result.push(`${parts.minutes}m`);
}
if (result.length < 2 && parts.seconds > 0) {
result.push(`${parts.seconds}s`);
}
if (result.length < 2 && parts.milliseconds > 0 && parts.seconds < 1) {
result.push(`${parts.milliseconds.toFixed(2)}ms`);
}
if (result.length === 0) {
// fallback for durations < 1s
return "0s";
}
return result.join(" ");
};
export const formatDate = (date, customOptions) => {
const options = {
year: "numeric",
month: "long",
day: "numeric",
hour: "numeric",
minute: "numeric",
hour12: true,
...customOptions,
};
// Return the date using the specified options
return date
.toLocaleString("en-US", options)
.replace(/\b(AM|PM)\b/g, (match) => match.toLowerCase());
};
export const formatDateWithTz = (timestamp, format, timezone) => {
const formattedDate = dayjs(timestamp).tz(timezone).format(format);
return formattedDate;
};
export const tickDateFormatLookup = (range) => {
switch (range) {
case "recent":
return "h:mm A";
case "day":
return "h A";
case "week":
return "MMM D";
case "month":
return "MMM D";
default:
return "MMM D, h A";
}
};
export const tooltipDateFormatLookup = (range) => {
switch (range) {
case "recent":
return "MMM D, h:mm A";
case "day":
return "MMM D, h:mm A";
case "week":
return "ddd, MMM D";
case "month":
return "ddd, MMM D";
default:
return "MMM D, h:mm A";
}
};
-15
View File
@@ -1,15 +0,0 @@
export const safelyParseFloat = (value) => {
const parsedValue = parseFloat(value);
if (isNaN(parsedValue)) {
return 0;
}
return parsedValue;
};
export const formatMonitorUrl = (url, maxLength = 55) => {
if (!url) return "";
const strippedUrl = url.replace(/^https?:\/\//, "");
return strippedUrl.length > maxLength
? `${strippedUrl.slice(0, maxLength)}…`
: strippedUrl;
};
-101
View File
@@ -1,101 +0,0 @@
/**
* Update errors if passed id matches the error.details[0].path, otherwise remove
* the error for the id
* @param {*} prev Previous errors *
* @param {*} id ID of the field whose error is to be either updated or removed
* @param {*} error the error object
* @returns the Update Errors with the specific field with id being either removed or updated
*/
const buildErrors = (prev, id, error) => {
const updatedErrors = { ...prev };
if (error && id == error.details[0].path) {
updatedErrors[id] = error.details[0].message ?? "Validation error";
} else {
delete updatedErrors[id];
}
return updatedErrors;
};
/**
* Processes Joi validation errors and returns a filtered object of error messages for fields that have been touched.
*
* @param {Object} validation - The Joi validation result object.
* @param {Object} validation.error - The error property of the validation result containing details of validation failures.
* @param {Object[]} validation.error.details - An array of error details from the Joi validation. Each item contains information about the path and the message.
* @param {Object} touchedErrors - An object representing which fields have been interacted with. Keys are field IDs (field names), and values are booleans indicating whether the field has been touched.
* @returns {Object} - An object where keys are the field IDs (if they exist in `touchedErrors` and are in the error details) and values are their corresponding error messages.
*/
const getTouchedFieldErrors = (validation, touchedErrors) => {
let newErrors = {};
if (validation?.error) {
newErrors = validation.error.details.reduce((errors, detail) => {
const fieldId = detail.path[0];
if (touchedErrors[fieldId] && !(fieldId in errors)) {
errors[fieldId] = detail.message;
}
return errors;
}, {});
}
return newErrors;
};
/**
*
* @param {*} form The form object of the submitted form data
* @param {*} validation The Joi validation rules
* @param {*} setErrors The function used to set the local errors
* @returns true if there is no error or false if there is error after validating the form
* the error will be reset to {} if returns false; otherwise the errors object will be set with
* the new value
*/
const hasValidationErrors = (form, validation, setErrors) => {
const { error } = validation.validate(form, {
abortEarly: false,
});
if (error) {
const newErrors = {};
error.details.forEach((err) => {
if (
![
"clientHost",
"refreshTokenSecret",
"dbConnectionString",
"refreshTokenTTL",
"jwtTTL",
"notify-email-list",
"_id",
"__v",
"createdAt",
"updatedAt",
].includes(err.path[0])
) {
newErrors[err.path[0]] = err.message ?? "Validation error";
}
// Handle conditionally usage number required cases
if (!form.cpu || form.usage_cpu) {
newErrors["usage_cpu"] = null;
}
if (!form.memory || form.usage_memory) {
newErrors["usage_memory"] = null;
}
if (!form.disk || form.usage_disk) {
newErrors["usage_disk"] = null;
}
if (!form.temperature || form.usage_temperature) {
newErrors["usage_temperature"] = null;
}
});
if (Object.values(newErrors).some((v) => v)) {
setErrors(newErrors);
return true;
} else {
setErrors({});
return false;
}
}
setErrors({});
return false;
};
export { buildErrors, hasValidationErrors, getTouchedFieldErrors };
+3 -4
View File
@@ -2,11 +2,10 @@ import { z } from "zod";
export const loginSchema = z.object({
email: z
.string()
.min(1, "auth.common.inputs.email.errors.empty")
.email("auth.common.inputs.email.errors.invalid")
.email("Please enter a valid email address")
.min(1, "Please enter your email address")
.transform((val) => val.toLowerCase().trim()),
password: z.string().min(1, "auth.common.inputs.password.errors.empty"),
password: z.string().min(1, "Please enter your password"),
});
export type LoginFormData = z.infer<typeof loginSchema>;
+2 -3
View File
@@ -2,9 +2,8 @@ import { z } from "zod";
export const recoverySchema = z.object({
email: z
.string()
.min(1, "auth.common.inputs.email.errors.empty")
.email("auth.common.inputs.email.errors.invalid")
.email("Please enter a valid email address")
.min(1, "Please enter your email address")
.transform((val) => val.toLowerCase().trim()),
});
+13 -1
View File
@@ -1,6 +1,18 @@
import joi from "joi";
import dayjs from "dayjs";
import { ROLES } from "../Utils/roleUtils";
export const ROLES = {
SUPERADMIN: "superadmin",
ADMIN: "admin",
USER: "user",
DEMO: "demo",
};
export const VALID_ROLES = [ROLES.ADMIN, ROLES.USER, ROLES.DEMO];
export const EDITABLE_ROLES = [
{ role: ROLES.ADMIN, _id: ROLES.ADMIN },
{ role: ROLES.USER, _id: ROLES.USER },
];
const THRESHOLD_COMMON_BASE_MSG = "Threshold must be a number.";
Binary file not shown.

Before

Width:  |  Height:  |  Size: 853 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

@@ -1,67 +0,0 @@
<svg width="768" height="768" viewBox="0 0 768 768" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_14_2)">
<mask id="mask0_14_2" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="768" height="768">
<path d="M768 0H0V768H768V0Z" fill="url(#paint0_radial_14_2)"/>
</mask>
<g mask="url(#mask0_14_2)">
<mask id="mask1_14_2" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="0" width="768" height="768">
<path d="M768 0H0V768H768V0Z" fill="white"/>
</mask>
<g mask="url(#mask1_14_2)">
<mask id="mask2_14_2" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="0" width="768" height="768">
<path d="M768 0H0V768H768V0Z" fill="white"/>
</mask>
<g mask="url(#mask2_14_2)">
<path d="M0.5 0V768" stroke="#b8b9bd"/>
<path d="M48.5 0V768" stroke="#b8b9bd"/>
<path d="M96.5 0V768" stroke="#b8b9bd"/>
<path d="M144.5 0V768" stroke="#b8b9bd"/>
<path d="M192.5 0V768" stroke="#b8b9bd"/>
<path d="M240.5 0V768" stroke="#b8b9bd"/>
<path d="M288.5 0V768" stroke="#b8b9bd"/>
<path d="M336.5 0V768" stroke="#b8b9bd"/>
<path d="M384.5 0V768" stroke="#b8b9bd"/>
<path d="M432.5 0V768" stroke="#b8b9bd"/>
<path d="M480.5 0V768" stroke="#b8b9bd"/>
<path d="M528.5 0V768" stroke="#b8b9bd"/>
<path d="M576.5 0V768" stroke="#b8b9bd"/>
<path d="M624.5 0V768" stroke="#b8b9bd"/>
<path d="M672.5 0V768" stroke="#b8b9bd"/>
<path d="M720.5 0V768" stroke="#b8b9bd"/>
</g>
<path d="M767.5 0.5H0.5V767.5H767.5V0.5Z" stroke="#b8b9bd"/>
<mask id="mask3_14_2" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="0" width="768" height="768">
<path d="M768 0H0V768H768V0Z" fill="white"/>
</mask>
<g mask="url(#mask3_14_2)">
<path d="M0 47.5H768" stroke="#b8b9bd"/>
<path d="M0 95.5H768" stroke="#b8b9bd"/>
<path d="M0 143.5H768" stroke="#b8b9bd"/>
<path d="M0 191.5H768" stroke="#b8b9bd"/>
<path d="M0 239.5H768" stroke="#b8b9bd"/>
<path d="M0 287.5H768" stroke="#b8b9bd"/>
<path d="M0 335.5H768" stroke="#b8b9bd"/>
<path d="M0 383.5H768" stroke="#b8b9bd"/>
<path d="M0 431.5H768" stroke="#b8b9bd"/>
<path d="M0 479.5H768" stroke="#b8b9bd"/>
<path d="M0 527.5H768" stroke="#b8b9bd"/>
<path d="M0 575.5H768" stroke="#b8b9bd"/>
<path d="M0 623.5H768" stroke="#b8b9bd"/>
<path d="M0 671.5H768" stroke="#b8b9bd"/>
<path d="M0 719.5H768" stroke="#b8b9bd"/>
<path d="M0 767.5H768" stroke="#b8b9bd"/>
</g>
<path d="M767.5 0.5H0.5V767.5H767.5V0.5Z" stroke="#b8b9bd"/>
</g>
</g>
</g>
<defs>
<radialGradient id="paint0_radial_14_2" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(384 384) rotate(90) scale(384)">
<stop/>
<stop offset="1" stop-opacity="0"/>
</radialGradient>
<clipPath id="clip0_14_2">
<rect width="768" height="768" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 2.7 KiB

@@ -1,36 +0,0 @@
<svg width="256" height="170" viewBox="0 0 256 170" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_24_2)">
<path d="M248.196 0.390244H7.80489C3.7099 0.390244 0.390259 3.70989 0.390259 7.80487V161.561C0.390259 165.656 3.7099 168.975 7.80489 168.975H248.196C252.291 168.975 255.61 165.656 255.61 161.561V7.80487C255.61 3.70989 252.291 0.390244 248.196 0.390244Z" fill="#151518"/>
<path d="M248.196 0.390244H7.80489C3.7099 0.390244 0.390259 3.70989 0.390259 7.80487V161.561C0.390259 165.656 3.7099 168.975 7.80489 168.975H248.196C252.291 168.975 255.61 165.656 255.61 161.561V7.80487C255.61 3.70989 252.291 0.390244 248.196 0.390244Z" stroke="#27272A" stroke-width="0.780488"/>
<path d="M234.976 18H21.122C19.3977 18 18 19.3977 18 21.122V69.5122C18 71.2364 19.3977 72.6341 21.122 72.6341H234.976C236.7 72.6341 238.098 71.2364 238.098 69.5122V21.122C238.098 19.3977 236.7 18 234.976 18Z" fill="#27272A" fill-opacity="0.8"/>
<path d="M99.9025 78.8293H21.0732C19.3489 78.8293 17.9512 80.227 17.9512 81.9512V85.0732C17.9512 86.7974 19.3489 88.1952 21.0732 88.1952H99.9025C101.627 88.1952 103.024 86.7974 103.024 85.0732V81.9512C103.024 80.227 101.627 78.8293 99.9025 78.8293Z" fill="#27272A" fill-opacity="0.6"/>
<path d="M234.927 93.6584H21.0732C19.3489 93.6584 17.9512 95.0561 17.9512 96.7803V99.9023C17.9512 101.627 19.3489 103.024 21.0732 103.024H234.927C236.651 103.024 238.049 101.627 238.049 99.9023V96.7803C238.049 95.0561 236.651 93.6584 234.927 93.6584Z" fill="#27272A" fill-opacity="0.3"/>
<path d="M234.927 108.488H21.0732C19.3489 108.488 17.9512 109.886 17.9512 111.61V114.732C17.9512 116.456 19.3489 117.854 21.0732 117.854H234.927C236.651 117.854 238.049 116.456 238.049 114.732V111.61C238.049 109.886 236.651 108.488 234.927 108.488Z" fill="#27272A" fill-opacity="0.3"/>
<g filter="url(#filter0_d_24_2)">
<mask id="mask0_24_2" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="174" y="129" width="65" height="21">
<path d="M234.927 129.561H177.171C175.447 129.561 174.049 130.959 174.049 132.683V146.732C174.049 148.456 175.447 149.854 177.171 149.854H234.927C236.651 149.854 238.049 148.456 238.049 146.732V132.683C238.049 130.959 236.651 129.561 234.927 129.561Z" fill="white"/>
<path d="M177.171 130.061H234.927C236.375 130.061 237.549 131.235 237.549 132.683V146.732C237.549 148.18 236.375 149.354 234.927 149.354H177.171C175.723 149.354 174.549 148.18 174.549 146.732V132.683C174.549 131.235 175.723 130.061 177.171 130.061Z" stroke="white"/>
</mask>
<g mask="url(#mask0_24_2)">
<path d="M234.927 129.561H177.171C175.447 129.561 174.049 130.959 174.049 132.683V146.732C174.049 148.456 175.447 149.854 177.171 149.854H234.927C236.651 149.854 238.049 148.456 238.049 146.732V132.683C238.049 130.959 236.651 129.561 234.927 129.561Z" fill="#27272A" fill-opacity="0.2"/>
<path d="M177.171 130.061H234.927C236.375 130.061 237.549 131.235 237.549 132.683V146.732C237.549 148.18 236.375 149.354 234.927 149.354H177.171C175.723 149.354 174.549 148.18 174.549 146.732V132.683C174.549 131.235 175.723 130.061 177.171 130.061Z" stroke="#27272A" stroke-opacity="0.8"/>
</g>
<path d="M234.927 129.951H177.171C175.662 129.951 174.439 131.174 174.439 132.683V146.731C174.439 148.24 175.662 149.463 177.171 149.463H234.927C236.435 149.463 237.658 148.24 237.658 146.731V132.683C237.658 131.174 236.435 129.951 234.927 129.951Z" stroke="#27272A" stroke-opacity="0.8" stroke-width="0.780488"/>
</g>
</g>
<defs>
<filter id="filter0_d_24_2" x="172.049" y="128.561" width="68.0002" height="24.2929" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="1"/>
<feGaussianBlur stdDeviation="1"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.0627451 0 0 0 0 0.0941176 0 0 0 0 0.156863 0 0 0 0.05 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_24_2"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_24_2" result="shape"/>
</filter>
<clipPath id="clip0_24_2">
<rect width="256" height="170" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 4.2 KiB

@@ -1,29 +0,0 @@
<svg width="256" height="170" viewBox="0 0 256 170" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="0.390244" y="0.390244" width="255.22" height="168.585" rx="7.41463" fill="white"/>
<rect x="0.390244" y="0.390244" width="255.22" height="168.585" rx="7.41463" stroke="#EBEBEB" stroke-width="0.780488"/>
<rect x="17.9512" y="16.3901" width="220.098" height="54.6341" rx="3.12195" fill="#EFF2FF"/>
<rect x="17.9512" y="78.8293" width="85.0732" height="9.36585" rx="3.12195" fill="#D9D9D9"/>
<rect x="17.9512" y="93.6584" width="220.098" height="9.36585" rx="3.12195" fill="#F3F3F3"/>
<rect x="17.9512" y="108.488" width="220.098" height="9.36585" rx="3.12195" fill="#F3F3F3"/>
<g filter="url(#filter0_d_28_7483)">
<g clip-path="url(#clip0_28_7483)">
<rect x="174.049" y="129.561" width="64" height="20.2927" rx="3.12195" fill="#E0F2FE"/>
</g>
<rect x="174.439" y="129.951" width="63.2195" height="19.5122" rx="2.73171" stroke="#D5D9EB" stroke-width="0.780488"/>
</g>
<defs>
<filter id="filter0_d_28_7483" x="172.049" y="128.561" width="68" height="24.2927" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="1"/>
<feGaussianBlur stdDeviation="1"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.0627451 0 0 0 0 0.0941176 0 0 0 0 0.156863 0 0 0 0.05 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_28_7483"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_28_7483" result="shape"/>
</filter>
<clipPath id="clip0_28_7483">
<rect x="174.049" y="129.561" width="64" height="20.2927" rx="3.12195" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

@@ -1,19 +0,0 @@
<svg width="250" height="176" viewBox="0 0 250 176" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M246 72.5H4C2.067 72.5 0.5 74.067 0.5 76V100C0.5 101.933 2.067 103.5 4 103.5H246C247.933 103.5 249.5 101.933 249.5 100V76C249.5 74.067 247.933 72.5 246 72.5Z" fill="white" stroke="#E1E1E1"/>
<path d="M112.5 81H42.5C38.3579 81 35 84.3579 35 88.5C35 92.6421 38.3579 96 42.5 96H112.5C116.642 96 120 92.6421 120 88.5C120 84.3579 116.642 81 112.5 81Z" fill="#F1F1F1"/>
<path d="M25 88.5C25 84.3579 21.6421 81 17.5 81C13.3579 81 10 84.3579 10 88.5C10 92.6421 13.3579 96 17.5 96C21.6421 96 25 92.6421 25 88.5Z" fill="#F1F1F1"/>
<path d="M219 34H31C28.7909 34 27 35.7909 27 38V56C27 58.2091 28.7909 60 31 60H219C221.209 60 223 58.2091 223 56V38C223 35.7909 221.209 34 219 34Z" fill="white"/>
<path d="M219 34.5H31C29.067 34.5 27.5 36.067 27.5 38V56C27.5 57.933 29.067 59.5 31 59.5H219C220.933 59.5 222.5 57.933 222.5 56V38C222.5 36.067 220.933 34.5 219 34.5Z" stroke="#E1E1E1" stroke-opacity="0.71"/>
<path d="M156.5 42H60.5C57.4624 42 55 44.4624 55 47.5C55 50.5376 57.4624 53 60.5 53H156.5C159.538 53 162 50.5376 162 47.5C162 44.4624 159.538 42 156.5 42Z" fill="#F4F4F4"/>
<path d="M41.5 42H40.5C37.4624 42 35 44.4624 35 47.5C35 50.5376 37.4624 53 40.5 53H41.5C44.5376 53 47 50.5376 47 47.5C47 44.4624 44.5376 42 41.5 42Z" fill="#F4F4F4"/>
<path d="M219 116H31C28.7909 116 27 117.791 27 120V138C27 140.209 28.7909 142 31 142H219C221.209 142 223 140.209 223 138V120C223 117.791 221.209 116 219 116Z" fill="white"/>
<path d="M219 116.5H31C29.067 116.5 27.5 118.067 27.5 120V138C27.5 139.933 29.067 141.5 31 141.5H219C220.933 141.5 222.5 139.933 222.5 138V120C222.5 118.067 220.933 116.5 219 116.5Z" stroke="#E1E1E1" stroke-opacity="0.71"/>
<path d="M156.5 124H60.5C57.4624 124 55 126.462 55 129.5C55 132.538 57.4624 135 60.5 135H156.5C159.538 135 162 132.538 162 129.5C162 126.462 159.538 124 156.5 124Z" fill="#F4F4F4"/>
<path d="M41.5 124H40.5C37.4624 124 35 126.462 35 129.5C35 132.538 37.4624 135 40.5 135H41.5C44.5376 135 47 132.538 47 129.5C47 126.462 44.5376 124 41.5 124Z" fill="#F4F4F4"/>
<path d="M176 0.5H59C57.067 0.5 55.5 2.067 55.5 4V18C55.5 19.933 57.067 21.5 59 21.5H176C177.933 21.5 179.5 19.933 179.5 18V4C179.5 2.067 177.933 0.5 176 0.5Z" fill="white" stroke="#F6F6F6"/>
<path d="M136.5 7H77.5C75.0147 7 73 9.01472 73 11.5C73 13.9853 75.0147 16 77.5 16H136.5C138.985 16 141 13.9853 141 11.5C141 9.01472 138.985 7 136.5 7Z" fill="#F6F6F6"/>
<path d="M68 11C68 8.79086 66.2091 7 64 7C61.7909 7 60 8.79086 60 11V12C60 14.2091 61.7909 16 64 16C66.2091 16 68 14.2091 68 12V11Z" fill="#F6F6F6"/>
<path d="M176 154.5H59C57.067 154.5 55.5 156.067 55.5 158V172C55.5 173.933 57.067 175.5 59 175.5H176C177.933 175.5 179.5 173.933 179.5 172V158C179.5 156.067 177.933 154.5 176 154.5Z" fill="white" stroke="#F6F6F6"/>
<path d="M136.5 161H77.5C75.0147 161 73 163.015 73 165.5C73 167.985 75.0147 170 77.5 170H136.5C138.985 170 141 167.985 141 165.5C141 163.015 138.985 161 136.5 161Z" fill="#F6F6F6"/>
<path d="M68 165C68 162.791 66.2091 161 64 161C61.7909 161 60 162.791 60 165V166C60 168.209 61.7909 170 64 170C66.2091 170 68 168.209 68 166V165Z" fill="#F6F6F6"/>
</svg>

Before

Width:  |  Height:  |  Size: 3.1 KiB

@@ -1,19 +0,0 @@
<svg width="250" height="176" viewBox="0 0 250 176" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M246 72.5H4C2.067 72.5 0.5 74.067 0.5 76V100C0.5 101.933 2.067 103.5 4 103.5H246C247.933 103.5 249.5 101.933 249.5 100V76C249.5 74.067 247.933 72.5 246 72.5Z" fill="#151518" stroke="#1F1F23"/>
<path d="M112.5 81H42.5C38.3579 81 35 84.3579 35 88.5C35 92.6421 38.3579 96 42.5 96H112.5C116.642 96 120 92.6421 120 88.5C120 84.3579 116.642 81 112.5 81Z" fill="#1F1F23"/>
<path d="M25 88.5C25 84.3579 21.6421 81 17.5 81C13.3579 81 10 84.3579 10 88.5C10 92.6421 13.3579 96 17.5 96C21.6421 96 25 92.6421 25 88.5Z" fill="#1F1F23"/>
<path d="M219 34H31C28.7909 34 27 35.7909 27 38V56C27 58.2091 28.7909 60 31 60H219C221.209 60 223 58.2091 223 56V38C223 35.7909 221.209 34 219 34Z" fill="#151518"/>
<path d="M219 34.5H31C29.067 34.5 27.5 36.067 27.5 38V56C27.5 57.933 29.067 59.5 31 59.5H219C220.933 59.5 222.5 57.933 222.5 56V38C222.5 36.067 220.933 34.5 219 34.5Z" stroke="#1F1F23" stroke-opacity="0.71"/>
<path d="M156.5 42H60.5C57.4624 42 55 44.4624 55 47.5C55 50.5376 57.4624 53 60.5 53H156.5C159.538 53 162 50.5376 162 47.5C162 44.4624 159.538 42 156.5 42Z" fill="#252529"/>
<path d="M41.5 42H40.5C37.4624 42 35 44.4624 35 47.5C35 50.5376 37.4624 53 40.5 53H41.5C44.5376 53 47 50.5376 47 47.5C47 44.4624 44.5376 42 41.5 42Z" fill="#252529"/>
<path d="M219 116H31C28.7909 116 27 117.791 27 120V138C27 140.209 28.7909 142 31 142H219C221.209 142 223 140.209 223 138V120C223 117.791 221.209 116 219 116Z" fill="#151518"/>
<path d="M219 116.5H31C29.067 116.5 27.5 118.067 27.5 120V138C27.5 139.933 29.067 141.5 31 141.5H219C220.933 141.5 222.5 139.933 222.5 138V120C222.5 118.067 220.933 116.5 219 116.5Z" stroke="#1F1F23" stroke-opacity="0.71"/>
<path d="M156.5 124H60.5C57.4624 124 55 126.462 55 129.5C55 132.538 57.4624 135 60.5 135H156.5C159.538 135 162 132.538 162 129.5C162 126.462 159.538 124 156.5 124Z" fill="#252529"/>
<path d="M41.5 124H40.5C37.4624 124 35 126.462 35 129.5C35 132.538 37.4624 135 40.5 135H41.5C44.5376 135 47 132.538 47 129.5C47 126.462 44.5376 124 41.5 124Z" fill="#252529"/>
<path d="M176 0.5H59C57.067 0.5 55.5 2.067 55.5 4V18C55.5 19.933 57.067 21.5 59 21.5H176C177.933 21.5 179.5 19.933 179.5 18V4C179.5 2.067 177.933 0.5 176 0.5Z" fill="#151518" stroke="#202023"/>
<path d="M136.5 7H77.5C75.0147 7 73 9.01472 73 11.5C73 13.9853 75.0147 16 77.5 16H136.5C138.985 16 141 13.9853 141 11.5C141 9.01472 138.985 7 136.5 7Z" fill="#202023"/>
<path d="M68 11C68 8.79086 66.2091 7 64 7C61.7909 7 60 8.79086 60 11V12C60 14.2091 61.7909 16 64 16C66.2091 16 68 14.2091 68 12V11Z" fill="#202023"/>
<path d="M176 154.5H59C57.067 154.5 55.5 156.067 55.5 158V172C55.5 173.933 57.067 175.5 59 175.5H176C177.933 175.5 179.5 173.933 179.5 172V158C179.5 156.067 177.933 154.5 176 154.5Z" fill="#151518" stroke="#202023"/>
<path d="M136.5 161H77.5C75.0147 161 73 163.015 73 165.5C73 167.985 75.0147 170 77.5 170H136.5C138.985 170 141 167.985 141 165.5C141 163.015 138.985 161 136.5 161Z" fill="#202023"/>
<path d="M68 165C68 162.791 66.2091 161 64 161C61.7909 161 60 162.791 60 165V166C60 168.209 61.7909 170 64 170C66.2091 170 68 168.209 68 166V165Z" fill="#202023"/>
</svg>

Before

Width:  |  Height:  |  Size: 3.1 KiB

@@ -1,35 +0,0 @@
<svg width="104" height="32" viewBox="0 0 104 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3.09074 25.1666C4.44267 27.0471 6.17683 28.6205 8.1795 29.7838C10.1822 30.947 12.4081 31.6738 14.7114 31.9165C13.5264 30.1333 11.8039 28.4928 9.65354 27.2438C7.50318 25.9948 5.22591 25.3125 3.09074 25.1666Z" fill="url(#paint0_linear_13278_146906)"/>
<path d="M12.543 22.2705C8.40015 19.8636 3.91612 19.2502 0.707662 20.3338C1.0174 21.3575 1.42589 22.3487 1.92738 23.2934C4.71498 23.2288 7.75856 23.9859 10.5906 25.6308C13.4227 27.2757 15.5888 29.5459 16.9143 32C17.9839 31.9672 19.0479 31.8309 20.0913 31.5932C19.4426 28.2698 16.6849 24.6779 12.543 22.2705Z" fill="url(#paint1_linear_13278_146906)"/>
<path d="M32.2852 12.5009C31.7585 10.3584 30.8054 8.34403 29.4829 6.57804C28.1604 4.81205 26.4956 3.33067 24.5879 2.22235C22.6802 1.11403 20.5687 0.401504 18.3796 0.12731C16.1904 -0.146884 13.9684 0.02288 11.8463 0.626466C15.3915 1.06033 19.3267 2.39122 23.1859 4.63324C27.0452 6.87525 30.1533 9.63411 32.2852 12.5009Z" fill="url(#paint2_linear_13278_146906)"/>
<path d="M27.1271 20.3583C25.3124 17.3446 22.2038 14.4588 18.3743 12.2342C14.5449 10.0095 10.4991 8.7388 6.98531 8.65474C3.894 8.58152 1.57389 9.48017 0.621548 11.1197C0.616124 11.1294 0.608531 11.1386 0.602566 11.1484C0.516877 11.4559 0.443119 11.7639 0.37587 12.0731C1.70568 11.5481 3.24645 11.2558 4.95969 11.2232C8.76959 11.1517 13.0334 12.3703 16.9681 14.6562C20.9027 16.9422 24.0759 20.0438 25.9003 23.3878C26.7182 24.8944 27.2285 26.3777 27.4308 27.7948C27.6662 27.5844 27.8972 27.3669 28.1212 27.1408C28.1272 27.1305 28.131 27.1196 28.1369 27.1088C29.0893 25.4677 28.721 23.0076 27.1271 20.3583Z" fill="url(#paint3_linear_13278_146906)"/>
<path d="M15.4609 17.2485C9.59662 13.8416 3.11626 13.3079 -5.33621e-07 15.6855C0.00612042 16.4297 0.0630161 17.1726 0.170292 17.9091C1.08699 17.6312 2.03177 17.4562 2.98718 17.3874C6.46951 17.1254 10.3087 18.0957 13.7927 20.1207C17.2766 22.1458 20.023 25.0018 21.5209 28.1543C21.935 29.018 22.2508 29.9254 22.4624 30.8595C23.1555 30.5878 23.8294 30.2694 24.4794 29.9066C25.0011 26.0213 21.3268 20.656 15.4609 17.2485Z" fill="url(#paint4_linear_13278_146906)"/>
<path d="M30.1434 15.3141C28.3082 12.3036 25.1724 9.40969 21.3158 7.17039C17.4593 4.93109 13.3977 3.64033 9.87257 3.53674C7.1853 3.45919 5.10382 4.11053 4.02457 5.34109C8.50588 4.58182 14.4168 5.85794 20.146 9.18625C25.8753 12.5146 29.9135 17.0181 31.4722 21.2868C32.0064 19.7406 31.5416 17.6098 30.1434 15.3141Z" fill="url(#paint5_linear_13278_146906)"/>
<path d="M46.6645 9.90909L49.4003 9.90909L49.4003 19.0369C49.4003 19.8807 49.2107 20.6136 48.8314 21.2358C48.4564 21.858 47.9344 22.3374 47.2654 22.674C46.5963 23.0107 45.8186 23.179 44.9323 23.179C44.1439 23.179 43.428 23.0405 42.7845 22.7635C42.1453 22.4822 41.6382 22.0561 41.2632 21.4851C40.8882 20.9098 40.7029 20.1875 40.7071 19.3182L43.4621 19.3182C43.4706 19.6634 43.5409 19.9595 43.673 20.2067C43.8094 20.4496 43.9948 20.6371 44.2291 20.7692C44.4678 20.897 44.749 20.9609 45.0729 20.9609C45.4138 20.9609 45.7014 20.8885 45.9358 20.7436C46.1745 20.5945 46.3556 20.3771 46.4791 20.0916C46.6027 19.8061 46.6645 19.4545 46.6645 19.0369L46.6645 9.90909ZM57.9337 18.8196L57.9337 13.1818L60.6567 13.1818L60.6567 23L58.0423 23L58.0423 21.2166L57.9401 21.2166C57.7185 21.7919 57.3499 22.2543 56.8343 22.6037C56.3229 22.9531 55.6986 23.1278 54.9614 23.1278C54.3051 23.1278 53.7277 22.9787 53.2291 22.6804C52.7306 22.3821 52.3406 21.9581 52.0594 21.4084C51.7824 20.8587 51.6418 20.2003 51.6375 19.4332L51.6375 13.1818L54.3605 13.1818L54.3605 18.9474C54.3648 19.527 54.5203 19.9851 54.8272 20.3217C55.134 20.6584 55.5452 20.8267 56.0608 20.8267C56.3889 20.8267 56.6958 20.7521 56.9813 20.603C57.2668 20.4496 57.4969 20.2237 57.6716 19.9254C57.8506 19.6271 57.9379 19.2585 57.9337 18.8196ZM62.8348 26.6818L62.8348 13.1818L65.5194 13.1818L65.5194 14.831L65.6409 14.831C65.7602 14.5668 65.9328 14.2983 66.1586 14.0256C66.3888 13.7486 66.6871 13.5185 67.0535 13.3352C67.4243 13.1477 67.8845 13.054 68.4342 13.054C69.1501 13.054 69.8106 13.2415 70.4158 13.6165C71.0209 13.9872 71.5045 14.5476 71.8667 15.2976C72.229 16.0433 72.4101 16.9787 72.4101 18.1037C72.4101 19.1989 72.2332 20.1236 71.8795 20.8778C71.5301 21.6278 71.0528 22.1967 70.4477 22.5845C69.8469 22.968 69.1736 23.1598 68.4278 23.1598C67.8994 23.1598 67.4498 23.0724 67.0791 22.8977C66.7126 22.723 66.4122 22.5036 66.1778 22.2393C65.9435 21.9709 65.7645 21.7003 65.6409 21.4276L65.5578 21.4276L65.5578 26.6818L62.8348 26.6818ZM65.5003 18.0909C65.5003 18.6747 65.5812 19.1839 65.7432 19.6186C65.9051 20.0533 66.1395 20.392 66.4463 20.6349C66.7531 20.8736 67.126 20.9929 67.5649 20.9929C68.0081 20.9929 68.3831 20.8714 68.6899 20.6286C68.9967 20.3814 69.229 20.0405 69.3866 19.6058C69.5486 19.1669 69.6295 18.6619 69.6295 18.0909C69.6295 17.5241 69.5507 17.0256 69.393 16.5952C69.2354 16.1648 69.0031 15.8281 68.6963 15.5852C68.3895 15.3423 68.0123 15.2209 67.5649 15.2209C67.1217 15.2209 66.7467 15.3381 66.4399 15.5724C66.1373 15.8068 65.9051 16.1392 65.7432 16.5696C65.5812 17 65.5003 17.5071 65.5003 18.0909ZM74.2254 23L74.2254 13.1818L76.9484 13.1818L76.9484 23L74.2254 23ZM75.5933 11.9162C75.1885 11.9162 74.8412 11.782 74.5514 11.5135C74.2659 11.2408 74.1231 10.9148 74.1231 10.5355C74.1231 10.1605 74.2659 9.83878 74.5514 9.57031C74.8412 9.29759 75.1885 9.16122 75.5933 9.16122C75.9981 9.16122 76.3433 9.29759 76.6288 9.57031C76.9186 9.83878 77.0635 10.1605 77.0635 10.5355C77.0635 10.9148 76.9186 11.2408 76.6288 11.5135C76.3433 11.782 75.9981 11.9162 75.5933 11.9162ZM84.352 13.1818L84.352 15.2273L78.4394 15.2273L78.4394 13.1818L84.352 13.1818ZM79.7817 10.8295L82.5047 10.8295L82.5047 19.983C82.5047 20.2344 82.5431 20.4304 82.6198 20.571C82.6965 20.7074 82.803 20.8033 82.9394 20.8587C83.08 20.9141 83.2419 20.9418 83.4252 20.9418C83.553 20.9418 83.6808 20.9311 83.8087 20.9098C83.9365 20.8842 84.0345 20.8651 84.1027 20.8523L84.531 22.8786C84.3946 22.9212 84.2029 22.9702 83.9557 23.0256C83.7085 23.0852 83.4081 23.1215 83.0544 23.1342C82.3982 23.1598 81.8229 23.0724 81.3286 22.8722C80.8385 22.6719 80.4571 22.3608 80.1844 21.9389C79.9117 21.517 79.7774 20.9844 79.7817 20.3409L79.7817 10.8295ZM90.4948 23.1918C89.4848 23.1918 88.6155 22.9872 87.8868 22.5781C87.1624 22.1648 86.6041 21.581 86.2121 20.8267C85.82 20.0682 85.624 19.1712 85.624 18.1357C85.624 17.1257 85.82 16.2393 86.2121 15.4766C86.6041 14.7138 87.156 14.1193 87.8676 13.6932C88.5835 13.267 89.423 13.054 90.3861 13.054C91.0338 13.054 91.6368 13.1584 92.195 13.3672C92.7575 13.5717 93.2476 13.8807 93.6652 14.294C94.0871 14.7074 94.4152 15.2273 94.6496 15.8537C94.884 16.4759 95.0012 17.2045 95.0012 18.0398L95.0012 18.7876L86.7107 18.7876L86.7107 17.1001L92.4379 17.1001C92.4379 16.7081 92.3527 16.3608 92.1823 16.0582C92.0118 15.7557 91.7753 15.5192 91.4727 15.3487C91.1745 15.174 90.8272 15.0866 90.4308 15.0866C90.0175 15.0866 89.651 15.1825 89.3314 15.3743C89.0161 15.5618 88.7689 15.8153 88.5899 16.1349C88.411 16.4503 88.3193 16.8018 88.3151 17.1896L88.3151 18.794C88.3151 19.2798 88.4046 19.6996 88.5835 20.0533C88.7668 20.407 89.0246 20.6797 89.357 20.8715C89.6894 21.0632 90.0835 21.1591 90.5395 21.1591C90.8421 21.1591 91.1191 21.1165 91.3705 21.0313C91.6219 20.946 91.8371 20.8182 92.0161 20.6477C92.195 20.4773 92.3314 20.2685 92.4252 20.0213L94.9436 20.1875C94.8158 20.7926 94.5537 21.321 94.1574 21.7727C93.7654 22.2202 93.2583 22.5696 92.6361 22.821C92.0182 23.0682 91.3044 23.1918 90.4948 23.1918ZM96.7781 23L96.7781 13.1818L99.4181 13.1818L99.4181Line truncated
<defs>
<linearGradient id="paint0_linear_13278_146906" x1="21.5" y1="6.5" x2="6.66667" y2="32" gradientUnits="userSpaceOnUse">
<stop offset="0.0001" stop-color="#C7F284"/>
<stop offset="1" stop-color="#00BEF0"/>
</linearGradient>
<linearGradient id="paint1_linear_13278_146906" x1="21.5" y1="6.5" x2="6.66667" y2="32" gradientUnits="userSpaceOnUse">
<stop offset="0.0001" stop-color="#C7F284"/>
<stop offset="1" stop-color="#00BEF0"/>
</linearGradient>
<linearGradient id="paint2_linear_13278_146906" x1="21.5" y1="6.5" x2="6.66667" y2="32" gradientUnits="userSpaceOnUse">
<stop offset="0.0001" stop-color="#C7F284"/>
<stop offset="1" stop-color="#00BEF0"/>
</linearGradient>
<linearGradient id="paint3_linear_13278_146906" x1="21.5" y1="6.5" x2="6.66667" y2="32" gradientUnits="userSpaceOnUse">
<stop offset="0.0001" stop-color="#C7F284"/>
<stop offset="1" stop-color="#00BEF0"/>
</linearGradient>
<linearGradient id="paint4_linear_13278_146906" x1="21.5" y1="6.5" x2="6.66667" y2="32" gradientUnits="userSpaceOnUse">
<stop offset="0.0001" stop-color="#C7F284"/>
<stop offset="1" stop-color="#00BEF0"/>
</linearGradient>
<linearGradient id="paint5_linear_13278_146906" x1="21.5" y1="6.5" x2="6.66667" y2="32" gradientUnits="userSpaceOnUse">
<stop offset="0.0001" stop-color="#C7F284"/>
<stop offset="1" stop-color="#00BEF0"/>
</linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 9.2 KiB

@@ -1,35 +0,0 @@
<svg width="104" height="32" viewBox="0 0 104 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3.09074 25.1666C4.44267 27.0471 6.17683 28.6205 8.1795 29.7838C10.1822 30.947 12.4081 31.6738 14.7114 31.9165C13.5264 30.1333 11.8039 28.4928 9.65354 27.2438C7.50318 25.9948 5.22591 25.3125 3.09074 25.1666Z" fill="url(#paint0_linear_13278_146916)"/>
<path d="M12.543 22.2705C8.40015 19.8636 3.91612 19.2502 0.707662 20.3338C1.0174 21.3575 1.42589 22.3487 1.92738 23.2934C4.71498 23.2288 7.75856 23.9859 10.5906 25.6308C13.4227 27.2757 15.5888 29.5459 16.9143 32C17.9839 31.9672 19.0479 31.8309 20.0913 31.5932C19.4426 28.2698 16.6849 24.6779 12.543 22.2705Z" fill="url(#paint1_linear_13278_146916)"/>
<path d="M32.2852 12.5009C31.7585 10.3584 30.8054 8.34403 29.4829 6.57804C28.1604 4.81205 26.4956 3.33067 24.5879 2.22235C22.6802 1.11403 20.5687 0.401504 18.3796 0.12731C16.1904 -0.146884 13.9684 0.02288 11.8463 0.626466C15.3915 1.06033 19.3267 2.39122 23.1859 4.63324C27.0452 6.87525 30.1533 9.63411 32.2852 12.5009Z" fill="url(#paint2_linear_13278_146916)"/>
<path d="M27.1271 20.3583C25.3124 17.3446 22.2038 14.4588 18.3743 12.2342C14.5449 10.0095 10.4991 8.7388 6.98531 8.65474C3.894 8.58152 1.57389 9.48017 0.621548 11.1197C0.616124 11.1294 0.608531 11.1386 0.602566 11.1484C0.516877 11.4559 0.443119 11.7639 0.37587 12.0731C1.70568 11.5481 3.24645 11.2558 4.95969 11.2232C8.76959 11.1517 13.0334 12.3703 16.9681 14.6562C20.9027 16.9422 24.0759 20.0438 25.9003 23.3878C26.7182 24.8944 27.2285 26.3777 27.4308 27.7948C27.6662 27.5844 27.8972 27.3669 28.1212 27.1408C28.1272 27.1305 28.131 27.1196 28.1369 27.1088C29.0893 25.4677 28.721 23.0076 27.1271 20.3583Z" fill="url(#paint3_linear_13278_146916)"/>
<path d="M15.4609 17.2485C9.59662 13.8416 3.11626 13.3079 -5.33621e-07 15.6855C0.00612042 16.4297 0.0630161 17.1726 0.170292 17.9091C1.08699 17.6312 2.03177 17.4562 2.98718 17.3874C6.46951 17.1254 10.3087 18.0957 13.7927 20.1207C17.2766 22.1458 20.023 25.0018 21.5209 28.1543C21.935 29.018 22.2508 29.9254 22.4624 30.8595C23.1555 30.5878 23.8294 30.2694 24.4794 29.9066C25.0011 26.0213 21.3268 20.656 15.4609 17.2485Z" fill="url(#paint4_linear_13278_146916)"/>
<path d="M30.1434 15.3141C28.3082 12.3036 25.1724 9.40969 21.3158 7.17039C17.4593 4.93109 13.3977 3.64033 9.87257 3.53674C7.1853 3.45919 5.10382 4.11053 4.02457 5.34109C8.50588 4.58182 14.4168 5.85794 20.146 9.18625C25.8753 12.5146 29.9135 17.0181 31.4722 21.2868C32.0064 19.7406 31.5416 17.6098 30.1434 15.3141Z" fill="url(#paint5_linear_13278_146916)"/>
<path d="M46.6645 9.90909L49.4003 9.90909L49.4003 19.0369C49.4003 19.8807 49.2106 20.6136 48.8314 21.2358C48.4564 21.858 47.9344 22.3374 47.2653 22.674C46.5963 23.0107 45.8186 23.179 44.9322 23.179C44.1439 23.179 43.428 23.0405 42.7845 22.7635C42.1453 22.4822 41.6382 22.0561 41.2632 21.4851C40.8882 20.9098 40.7028 20.1875 40.7071 19.3182L43.4621 19.3182C43.4706 19.6634 43.5409 19.9595 43.673 20.2067C43.8094 20.4496 43.9947 20.6371 44.2291 20.7692C44.4677 20.897 44.749 20.9609 45.0729 20.9609C45.4138 20.9609 45.7014 20.8885 45.9358 20.7436C46.1744 20.5945 46.3555 20.3771 46.4791 20.0916C46.6027 19.8061 46.6645 19.4545 46.6645 19.0369L46.6645 9.90909ZM57.9337 18.8196L57.9337 13.1818L60.6567 13.1818L60.6567 23L58.0423 23L58.0423 21.2166L57.94 21.2166C57.7185 21.7919 57.3498 22.2543 56.8342 22.6037C56.3229 22.9531 55.6986 23.1278 54.9614 23.1278C54.3051 23.1278 53.7277 22.9787 53.2291 22.6804C52.7305 22.3821 52.3406 21.9581 52.0594 21.4084C51.7824 20.8587 51.6418 20.2003 51.6375 19.4332L51.6375 13.1818L54.3605 13.1818L54.3605 18.9474C54.3648 19.527 54.5203 19.9851 54.8271 20.3217C55.1339 20.6584 55.5452 20.8267 56.0608 20.8267C56.3889 20.8267 56.6957 20.7521 56.9812 20.603C57.2668 20.4496 57.4969 20.2237 57.6716 19.9254C57.8506 19.6271 57.9379 19.2585 57.9337 18.8196ZM62.8348 26.6818L62.8348 13.1818L65.5194 13.1818L65.5194 14.831L65.6409 14.831C65.7602 14.5668 65.9328 14.2983 66.1586 14.0256C66.3887 13.7486 66.687 13.5185 67.0535 13.3352C67.4242 13.1477 67.8845 13.054 68.4342 13.054C69.1501 13.054 69.8106 13.2415 70.4157 13.6165C71.0208 13.9872 71.5045 14.5476 71.8667 15.2976C72.2289 16.0433 72.41 16.9787 72.41 18.1037C72.41 19.1989 72.2332 20.1236 71.8795 20.8778C71.5301 21.6278 71.0528 22.1967 70.4477 22.5845C69.8468 22.968 69.1735 23.1598 68.4278 23.1598C67.8994 23.1598 67.4498 23.0724 67.0791 22.8977C66.7126 22.723 66.4122 22.5036 66.1778 22.2393C65.9434 21.9709 65.7644 21.7003 65.6409 21.4276L65.5578 21.4276L65.5578 26.6818L62.8348 26.6818ZM65.5002 18.0909C65.5002 18.6747 65.5812 19.1839 65.7431 19.6186C65.9051 20.0533 66.1394 20.392 66.4463 20.6349C66.7531 20.8736 67.1259 20.9929 67.5649 20.9929C68.0081 20.9929 68.3831 20.8714 68.6899 20.6286C68.9967 20.3814 69.2289 20.0405 69.3866 19.6058C69.5485 19.1669 69.6295 18.6619 69.6295 18.0909C69.6295 17.5241 69.5507 17.0256 69.393 16.5952C69.2353 16.1648 69.0031 15.8281 68.6963 15.5852C68.3894 15.3423 68.0123 15.2209 67.5649 15.2209C67.1217 15.2209 66.7467 15.3381 66.4399 15.5724C66.1373 15.8068 65.9051 16.1392 65.7431 16.5696C65.5812 17 65.5002 17.5071 65.5002 18.0909ZM74.2254 23L74.2254 13.1818L76.9484 13.1818L76.9484 23L74.2254 23ZM75.5933 11.9162C75.1884 11.9162 74.8411 11.782 74.5514 11.5135C74.2659 11.2408 74.1231 10.9148 74.1231 10.5355C74.1231 10.1605 74.2659 9.83878 74.5514 9.57031C74.8411 9.29759 75.1884 9.16122 75.5933 9.16122C75.9981 9.16122 76.3433 9.29759 76.6288 9.57031C76.9186 9.83878 77.0634 10.1605 77.0634 10.5355C77.0634 10.9148 76.9186 11.2408 76.6288 11.5135C76.3433 11.782 75.9981 11.9162 75.5933 11.9162ZM84.352 13.1818L84.352 15.2273L78.4393 15.2273L78.4393 13.1818L84.352 13.1818ZM79.7817 10.8295L82.5047 10.8295L82.5047 19.983C82.5047 20.2344 82.543 20.4304 82.6197 20.571C82.6964 20.7074 82.803 20.8033 82.9393 20.8587C83.08 20.9141 83.2419 20.9418 83.4251 20.9418C83.553 20.9418 83.6808 20.9311 83.8087 20.9098C83.9365 20.8842 84.0345 20.8651 84.1027 20.8523L84.531 22.8786C84.3946 22.9212 84.2028 22.9702 83.9557 23.0256C83.7085 23.0852 83.4081 23.1215 83.0544 23.1342C82.3981 23.1598 81.8229 23.0724 81.3285 22.8722C80.8385 22.6719 80.4571 22.3608 80.1844 21.9389C79.9116 21.517 79.7774 20.9844 79.7817 20.3409L79.7817 10.8295ZM90.4947 23.1918C89.4848 23.1918 88.6155 22.9872 87.8868 22.5781C87.1623 22.1648 86.6041 21.581 86.2121 20.8267C85.82 20.0682 85.624 19.1712 85.624 18.1357C85.624 17.1257 85.82 16.2393 86.2121 15.4766C86.6041 14.7138 87.156 14.1193 87.8676 13.6932C88.5835 13.267 89.423 13.054 90.3861 13.054C91.0338 13.054 91.6368 13.1584 92.195 13.3672C92.7575 13.5717 93.2476 13.8807 93.6652 14.294C94.0871 14.7074 94.4152 15.2273 94.6496 15.8537C94.8839 16.4759 95.0011 17.2045 95.0011 18.0398L95.0011 18.7876L86.7106 18.7876L86.7106 17.1001L92.4379 17.1001C92.4379 16.7081 92.3527 16.3608 92.1822 16.0582C92.0118 15.7557 91.7753 15.5192 91.4727 15.3487C91.1744 15.174 90.8271 15.0866 90.4308 15.0866C90.0175 15.0866 89.651 15.1825 89.3314 15.3743C89.016 15.5618 88.7689 15.8153 88.5899 16.1349C88.4109 16.4503 88.3193 16.8018 88.315 17.1896L88.315 18.794C88.315 19.2798 88.4045 19.6996 88.5835 20.0533C88.7668 20.407 89.0246 20.6797 89.3569 20.8715C89.6893 21.0632 90.0835 21.1591 90.5395 21.1591C90.842 21.1591 91.119 21.1165 91.3704 21.0313C91.6219 20.946 91.8371 20.8182 92.016 20.6477C92.195 20.4773 92.3314 20.2685 92.4251 20.0213L94.9436 20.1875C94.8158 20.7926 94.5537 21.321 94.1574 21.7727C93.7653 22.2202 93.2582 22.5696 92.6361 22.821C92.0182 23.0682 91.3044 23.1918 90.4947 23.1918ZM96.7781 23L96.7781 13.1818L99.418 13.1818L99.418 14.8949L99.Line truncated
<defs>
<linearGradient id="paint0_linear_13278_146916" x1="21.5" y1="6.5" x2="6.66667" y2="32" gradientUnits="userSpaceOnUse">
<stop offset="0.0001" stop-color="#A4D756"/>
<stop offset="1" stop-color="#00B6E7"/>
</linearGradient>
<linearGradient id="paint1_linear_13278_146916" x1="21.5" y1="6.5" x2="6.66667" y2="32" gradientUnits="userSpaceOnUse">
<stop offset="0.0001" stop-color="#A4D756"/>
<stop offset="1" stop-color="#00B6E7"/>
</linearGradient>
<linearGradient id="paint2_linear_13278_146916" x1="21.5" y1="6.5" x2="6.66667" y2="32" gradientUnits="userSpaceOnUse">
<stop offset="0.0001" stop-color="#A4D756"/>
<stop offset="1" stop-color="#00B6E7"/>
</linearGradient>
<linearGradient id="paint3_linear_13278_146916" x1="21.5" y1="6.5" x2="6.66667" y2="32" gradientUnits="userSpaceOnUse">
<stop offset="0.0001" stop-color="#A4D756"/>
<stop offset="1" stop-color="#00B6E7"/>
</linearGradient>
<linearGradient id="paint4_linear_13278_146916" x1="21.5" y1="6.5" x2="6.66667" y2="32" gradientUnits="userSpaceOnUse">
<stop offset="0.0001" stop-color="#A4D756"/>
<stop offset="1" stop-color="#00B6E7"/>
</linearGradient>
<linearGradient id="paint5_linear_13278_146916" x1="21.5" y1="6.5" x2="6.66667" y2="32" gradientUnits="userSpaceOnUse">
<stop offset="0.0001" stop-color="#A4D756"/>
<stop offset="1" stop-color="#00B6E7"/>
</linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 9.2 KiB

@@ -1,5 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="300" height="100" viewBox="0 0 300 100">
<rect width="100%" height="100%" fill="#DDDDDD" />
<path fill="#999999"
d="m76.795 37.635-7.38 12.4v7.84h-3.75v-7.84l-7.38-12.4h3.32q.49 0 .78.23.29.24.48.61l3.7 6.76q.32.6.57 1.13.24.53.44 1.07.18-.54.42-1.07.23-.53.54-1.13l3.68-6.76q.16-.31.47-.58.3-.26.78-.26zm7.88 5.65q1.6 0 2.91.52t2.24 1.47 1.43 2.32q.51 1.38.51 3.07 0 1.71-.51 3.08-.5 1.37-1.43 2.34-.93.96-2.24 1.48t-2.91.52q-1.61 0-2.92-.52-1.32-.52-2.25-1.48-.93-.97-1.44-2.34t-.51-3.08q0-1.69.51-3.07.51-1.37 1.44-2.32t2.25-1.47q1.31-.52 2.92-.52m0 12.14q1.8 0 2.66-1.2.86-1.21.86-3.53 0-2.33-.86-3.54-.86-1.22-2.66-1.22-1.82 0-2.69 1.22-.88 1.23-.88 3.54t.88 3.52q.87 1.21 2.69 1.21m18.65-11.91h3.46v14.36h-2.11q-.69 0-.87-.63l-.24-1.15q-.88.9-1.95 1.45-1.06.55-2.5.55-1.18 0-2.08-.4-.9-.39-1.52-1.12t-.93-1.73q-.32-1-.32-2.21v-9.12h3.46v9.12q0 1.32.61 2.04t1.83.72q.89 0 1.68-.4.78-.4 1.48-1.1zm9.93.86.21 1.63q.67-1.29 1.59-2.02.93-.74 2.19-.74.99 0 1.59.43l-.22 2.59q-.07.26-.2.36-.14.11-.36.11-.21 0-.62-.07-.42-.07-.81-.07-.57 0-1.02.16-.45.17-.8.49-.36.31-.63.76-.28.45-.52 1.02v8.85h-3.45v-14.36h2.03q.53 0 .74.18.21.19.28.68m14.24-7.3h3.45v20.8h-3.45zm13.27 6.21q1.59 0 2.9.52t2.24 1.47 1.44 2.32q.5 1.38.5 3.07 0 1.71-.5 3.08-.51 1.37-1.44 2.34-.93.96-2.24 1.48t-2.9.52q-1.61 0-2.93-.52-1.31-.52-2.24-1.48-.94-.97-1.45-2.34t-.51-3.08q0-1.69.51-3.07.51-1.37 1.45-2.32.93-.95 2.24-1.47 1.32-.52 2.93-.52m0 12.14q1.79 0 2.65-1.2.86-1.21.86-3.53 0-2.33-.86-3.54-.86-1.22-2.65-1.22-1.82 0-2.7 1.22-.87 1.23-.87 3.54t.87 3.52q.88 1.21 2.7 1.21m14.98-5.08q.64 0 1.12-.18.47-.17.79-.48.31-.31.48-.74.16-.44.16-.95 0-1.07-.64-1.69t-1.91-.62q-1.28 0-1.91.62-.64.62-.64 1.69 0 .5.16.93.16.44.48.75.31.32.8.49.48.18 1.11.18m3.9 8.17q0-.42-.25-.68-.25-.27-.68-.42-.44-.14-1.02-.21t-1.23-.11l-1.34-.06q-.7-.03-1.36-.11-.57.32-.93.75-.35.44-.35 1.01 0 .38.19.71.18.33.6.57.41.23 1.07.37.66.13 1.61.13.96 0 1.66-.15.7-.14 1.16-.4.45-.26.66-.62t.21-.78m-.68-14.51h4.13v1.28q0 .62-.74.76l-1.29.24q.29.74.29 1.62 0 1.07-.42 1.93-.43.86-1.19 1.46-.75.6-1.78.93t-2.22.33q-.42 0-.81-.04-.4-.04-.77-.11-.68.4-.68.91 0 .43.4.63.4.21 1.06.29t1.5.1q.84.03 1.72.1t1.72.24q.84.18 1.5.55.66.38 1.06 1.03t.4 1.68q0 .95-.47 1.84-.47.9-1.36 1.6t-2.18 1.13q-1.3.42-2.95.42-1.63 0-2.83-.31-1.2-.32-2-.84-.8-.53-1.19-1.21-.39-.69-.39-1.43 0-1.01.61-1.69.6-.68 1.67-1.08-.58-.3-.91-.79-.34-.49-.34-1.28 0-.33.12-.67t.35-.68q.23-.33.58-.64.35-.3.83-.53-1.09-.59-1.72-1.57-.62-.98-.62-2.3 0-1.06.43-1.92.42-.86 1.19-1.47.76-.61 1.8-.93 1.05-.33 2.28-.33.92 0 1.73.19.82.19 1.49.56m12.67-.72q1.59 0 2.9.52t2.24 1.47 1.44 2.32q.5 1.38.5 3.07 0 1.71-.5 3.08-.51 1.37-1.44 2.34-.93.96-2.24 1.48t-2.9.52q-1.61 0-2.93-.52-1.31-.52-2.24-1.48-.94-.97-1.45-2.34t-.51-3.08q0-1.69.51-3.07.51-1.37 1.45-2.32.93-.95 2.24-1.47 1.32-.52 2.93-.52m0 12.14q1.79 0 2.65-1.2.86-1.21.86-3.53 0-2.33-.86-3.54-.86-1.22-2.65-1.22-1.82 0-2.7 1.22-.87 1.23-.87 3.54t.87 3.52q.88 1.21 2.7 1.21m19.99-18.35v7.98q.84-.79 1.85-1.28t2.36-.49q1.18 0 2.09.4t1.52 1.12.92 1.72q.32 1 .32 2.21v9.14h-3.46v-9.14q0-1.32-.6-2.04t-1.84-.72q-.89 0-1.68.41-.78.4-1.48 1.1v10.39h-3.46v-20.8zm15.06 11.97h6.53q0-.68-.19-1.27-.19-.6-.57-1.04-.38-.45-.96-.71t-1.35-.26q-1.5 0-2.36.85-.86.86-1.1 2.43m8.82 2.08h-8.89q.09 1.11.4 1.91.3.81.81 1.33.5.53 1.2.79.69.26 1.53.26t1.45-.2 1.06-.43q.46-.24.8-.44.34-.19.66-.19.44 0 .65.32l.99 1.26q-.57.67-1.29 1.12-.71.46-1.49.73-.77.28-1.58.39-.8.11-1.56.11-1.5 0-2.79-.5-1.28-.49-2.24-1.47-.95-.97-1.49-2.41-.55-1.43-.55-3.32 0-1.47.48-2.77.47-1.29 1.36-2.25t2.17-1.52 2.89-.56q1.36 0 2.51.44 1.15.43 1.97 1.26.83.84 1.3 2.05t.47 2.76q0 .79-.17 1.06t-.65.27m6.46-6.75.21 1.63q.67-1.29 1.59-2.02.93-.74 2.19-.74.99 0 1.59.43l-.22 2.59q-.07.26-.2.36-.14.11-.36.11-.21 0-.62-.07-.42-.07-.81-.07-.57 0-1.02.16-.45.17-.8.49-.36.31-.63.76-.28.45-.52 1.02v8.85h-3.45v-14.36h2.03q.53 0 .74.18.21.19.28.68m10.12 4.67h6.52q0-.68-.18-1.27-.19-.6-.57-1.04-.38-.45-.96-.71t-1.35-.26q-1.5 0-2.36.85-.86.86-1.1 2.43m8.82 2.08h-8.89q.08 1.11.39 1.91.31.81.81 1.33.51.53 1.2.79t1.53.26 1.45-.2 1.07-.43q.45-.24.8-.44.34-.19.66-.19.43 0 .64.32l1 1.26q-.58.67-1.29 1.12-.71.46-1.49.73-.78.28-1.58.39-.81.11-1.56.11-1.5 0-2.79-.5-1.29-.49-2.24-1.47-.95-.97-1.5-2.41-.54-1.43-.54-3.32 0-1.47.47-2.77.48-1.29 1.37-2.25t2.17-1.52 2.89-.56q1.36 0 2.5.44 1.15.43 1.98 1.26.82.84 1.29 2.05t.47 2.76q0 .79-.17 1.06-.16.27-.64.27" />
</svg>

Before

Width:  |  Height:  |  Size: 4.3 KiB

@@ -1,24 +0,0 @@
<svg width="646" height="96" viewBox="0 0 646 96" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1064_606)">
<path d="M108.53 75.6899L90.81 94.6899C90.4267 95.1026 89.9626 95.432 89.4464 95.6573C88.9303 95.8827 88.3732 95.9994 87.81 95.9999H3.81C3.40937 95.9997 3.01749 95.8827 2.68235 95.6631C2.34722 95.4436 2.08338 95.1311 1.92313 94.7639C1.76288 94.3967 1.71318 93.9908 1.78012 93.5958C1.84706 93.2008 2.02772 92.8338 2.3 92.5399L20 73.5399C20.3833 73.1273 20.8474 72.7979 21.3636 72.5725C21.8797 72.3472 22.4368 72.2305 23 72.2299H107C107.404 72.2216 107.802 72.333 108.143 72.5502C108.484 72.7674 108.754 73.0806 108.917 73.4504C109.081 73.8203 109.131 74.2303 109.062 74.6288C108.993 75.0273 108.808 75.3965 108.53 75.6899ZM90.81 37.4199C90.4253 37.0091 89.9608 36.6811 89.445 36.4558C88.9292 36.2306 88.3728 36.1129 87.81 36.11H3.81C3.40937 36.1102 3.01749 36.2272 2.68235 36.4468C2.34722 36.6663 2.08338 36.9788 1.92313 37.346C1.76288 37.7132 1.71318 38.1191 1.78012 38.5141C1.84706 38.9091 2.02772 39.2761 2.3 39.57L20 58.58C20.3847 58.9908 20.8492 59.3188 21.365 59.5441C21.8808 59.7693 22.4372 59.887 23 59.8899H107C107.4 59.8878 107.79 59.7693 108.124 59.5491C108.458 59.3288 108.72 59.0162 108.879 58.6494C109.038 58.2826 109.087 57.8774 109.019 57.4833C108.952 57.0892 108.772 56.7232 108.5 56.43L90.81 37.4199ZM3.81 23.7699H87.81C88.3732 23.7694 88.9303 23.6527 89.4464 23.4273C89.9626 23.202 90.4267 22.8726 90.81 22.4599L108.53 3.45995C108.808 3.16647 108.993 2.79726 109.062 2.39877C109.131 2.00028 109.081 1.59031 108.917 1.22045C108.754 0.850591 108.484 0.537368 108.143 0.320195C107.802 0.103021 107.404 -0.0084012 107 -5.10783e-05H23C22.4368 0.000541762 21.8797 0.117167 21.3636 0.342553C20.8474 0.567938 20.3833 0.897249 20 1.30995L2.3 20.3099C2.02772 20.6038 1.84706 20.9708 1.78012 21.3658C1.71318 21.7608 1.76288 22.1667 1.92313 22.5339C2.08338 22.9011 2.34722 23.2136 2.68235 23.4331C3.01749 23.6527 3.40937 23.7697 3.81 23.7699Z" fill="url(#paint0_linear_1064_606)"/>
<path d="M210.94 40.6002H166V25.8002H222.62V11.0002H165.85C163.91 10.9897 161.988 11.3613 160.192 12.0938C158.396 12.8264 156.761 13.9055 155.383 15.2696C154.004 16.6337 152.907 18.2561 152.155 20.044C151.403 21.832 151.01 23.7506 151 25.6902V40.6902C151.008 42.6315 151.398 44.5523 152.149 46.3425C152.9 48.1328 153.996 49.7575 155.375 51.1237C156.755 52.49 158.39 53.5709 160.187 54.3047C161.984 55.0385 163.909 55.4108 165.85 55.4002H210.85V70.2002H152.07V85.0002H210.94C212.88 85.0108 214.802 84.6391 216.598 83.9066C218.394 83.174 220.029 82.0949 221.407 80.7308C222.786 79.3667 223.883 77.7444 224.635 75.9564C225.387 74.1684 225.78 72.2498 225.79 70.3102V55.3102C225.782 53.3689 225.392 51.4482 224.641 49.6579C223.89 47.8676 222.794 46.2429 221.415 44.8767C220.035 43.5105 218.4 42.4296 216.603 41.6958C214.806 40.962 212.881 40.5897 210.94 40.6002Z" fill="white"/>
<path d="M298 11H252.89C250.947 10.9842 249.02 11.3519 247.219 12.0821C245.419 12.8123 243.78 13.8905 242.397 15.2552C241.013 16.6198 239.913 18.2439 239.159 20.0345C238.404 21.8251 238.01 23.747 238 25.69V70.31C238.01 72.253 238.404 74.1749 239.159 75.9655C239.913 77.7561 241.013 79.3802 242.397 80.7448C243.78 82.1095 245.419 83.1877 247.219 83.9179C249.02 84.6481 250.947 85.0158 252.89 85H298C299.94 85.0105 301.862 84.6389 303.658 83.9064C305.454 83.1738 307.089 82.0947 308.467 80.7306C309.846 79.3665 310.943 77.7441 311.695 75.9562C312.447 74.1682 312.84 72.2496 312.85 70.31V25.69C312.84 23.7504 312.447 21.8318 311.695 20.0438C310.943 18.2559 309.846 16.6335 308.467 15.2694C307.089 13.9053 305.454 12.8262 303.658 12.0936C301.862 11.3611 299.94 10.9895 298 11ZM297.89 70.2H253V25.8H297.87L297.89 70.2Z" fill="white"/>
<path d="M456 11.0001H412C410.06 10.9896 408.138 11.3612 406.342 12.0937C404.546 12.8263 402.911 13.9054 401.533 15.2695C400.154 16.6336 399.057 18.256 398.305 20.0439C397.553 21.8319 397.16 23.7505 397.15 25.6901V85.0001H412.15V60.6901H455.95V85.0001H470.95V25.6901C470.94 23.742 470.544 21.8152 469.786 20.0206C469.027 18.2261 467.922 16.5993 466.532 15.2338C465.143 13.8684 463.497 12.7914 461.689 12.0648C459.881 11.3382 457.948 10.9764 456 11.0001ZM455.89 45.8901H412.09V25.8001H455.89V45.8901Z" fill="white"/>
<path d="M631.15 11.0002H587.15C585.21 10.9897 583.288 11.3613 581.492 12.0938C579.696 12.8264 578.062 13.9055 576.683 15.2696C575.304 16.6337 574.207 18.2561 573.455 20.044C572.703 21.832 572.31 23.7506 572.3 25.6902V85.0002H587.3V60.6902H631V85.0002H646V25.6902C645.99 23.7506 645.597 21.832 644.845 20.044C644.093 18.2561 642.996 16.6337 641.617 15.2696C640.238 13.9055 638.604 12.8264 636.808 12.0938C635.012 11.3613 633.09 10.9897 631.15 11.0002ZM631 45.8902H587.2V25.8002H631V45.8902Z" fill="white"/>
<path d="M544 70.2001H538L516.55 17.2001C515.815 15.3716 514.55 13.8045 512.918 12.6999C511.286 11.5952 509.361 11.0033 507.39 11.0001H494.08C492.786 10.9935 491.504 11.2418 490.307 11.7307C489.109 12.2197 488.02 12.9397 487.1 13.8497C486.181 14.7598 485.45 15.8419 484.949 17.0345C484.448 18.227 484.187 19.5066 484.18 20.8001V85.0001H499.18V25.8001H505.18L526.62 78.8001C527.367 80.6251 528.642 82.1858 530.281 83.283C531.919 84.3803 533.848 84.9641 535.82 84.9601H549.13C550.424 84.9667 551.706 84.7185 552.903 84.2295C554.101 83.7406 555.19 83.0205 556.11 82.1105C557.029 81.2005 557.76 80.1183 558.261 78.9258C558.762 77.7332 559.023 76.4537 559.03 75.1601V11.0001H544V70.2001Z" fill="white"/>
<path d="M341.1 11H326.1V70.31C326.11 72.2539 326.505 74.1766 327.26 75.9678C328.015 77.7591 329.116 79.3836 330.5 80.7484C331.884 82.1132 333.525 83.1912 335.326 83.9208C337.128 84.6504 339.056 85.0171 341 85H386V70.2H341.1V11Z" fill="white"/>
</g>
<defs>
<linearGradient id="paint0_linear_1064_606" x1="10.81" y1="98.29" x2="98.89" y2="-1.01005" gradientUnits="userSpaceOnUse">
<stop offset="0.08" stop-color="#9945FF"/>
<stop offset="0.3" stop-color="#8752F3"/>
<stop offset="0.5" stop-color="#5497D5"/>
<stop offset="0.6" stop-color="#43B4CA"/>
<stop offset="0.72" stop-color="#28E0B9"/>
<stop offset="0.97" stop-color="#19FB9B"/>
</linearGradient>
<clipPath id="clip0_1064_606">
<rect width="646" height="96" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 6.1 KiB

@@ -1,49 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="646" height="96" viewBox="0 0 646 96" fill="none" version="1.1" id="svg36"
sodipodi:docname="solana_logo_banner_dark.svg" inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview id="namedview38" pagecolor="#ffffff" bordercolor="#000000" borderopacity="0.25"
inkscape:showpageshadow="2" inkscape:pageopacity="0.0" inkscape:pagecheckerboard="0" inkscape:deskcolor="#d1d1d1"
showgrid="false" inkscape:zoom="2.0820433" inkscape:cx="324.68104" inkscape:cy="48.02974"
inkscape:window-width="1854" inkscape:window-height="1131" inkscape:window-x="0" inkscape:window-y="0"
inkscape:window-maximized="1" inkscape:current-layer="svg36" />
<g clip-path="url(#clip0_1064_606)" id="g16">
<path
d="M108.53 75.6899L90.81 94.6899C90.4267 95.1026 89.9626 95.432 89.4464 95.6573C88.9303 95.8827 88.3732 95.9994 87.81 95.9999H3.81C3.40937 95.9997 3.01749 95.8827 2.68235 95.6631C2.34722 95.4436 2.08338 95.1311 1.92313 94.7639C1.76288 94.3967 1.71318 93.9908 1.78012 93.5958C1.84706 93.2008 2.02772 92.8338 2.3 92.5399L20 73.5399C20.3833 73.1273 20.8474 72.7979 21.3636 72.5725C21.8797 72.3472 22.4368 72.2305 23 72.2299H107C107.404 72.2216 107.802 72.333 108.143 72.5502C108.484 72.7674 108.754 73.0806 108.917 73.4504C109.081 73.8203 109.131 74.2303 109.062 74.6288C108.993 75.0273 108.808 75.3965 108.53 75.6899ZM90.81 37.4199C90.4253 37.0091 89.9608 36.6811 89.445 36.4558C88.9292 36.2306 88.3728 36.1129 87.81 36.11H3.81C3.40937 36.1102 3.01749 36.2272 2.68235 36.4468C2.34722 36.6663 2.08338 36.9788 1.92313 37.346C1.76288 37.7132 1.71318 38.1191 1.78012 38.5141C1.84706 38.9091 2.02772 39.2761 2.3 39.57L20 58.58C20.3847 58.9908 20.8492 59.3188 21.365 59.5441C21.8808 59.7693 22.4372 59.887 23 59.8899H107C107.4 59.8878 107.79 59.7693 108.124 59.5491C108.458 59.3288 108.72 59.0162 108.879 58.6494C109.038 58.2826 109.087 57.8774 109.019 57.4833C108.952 57.0892 108.772 56.7232 108.5 56.43L90.81 37.4199ZM3.81 23.7699H87.81C88.3732 23.7694 88.9303 23.6527 89.4464 23.4273C89.9626 23.202 90.4267 22.8726 90.81 22.4599L108.53 3.45995C108.808 3.16647 108.993 2.79726 109.062 2.39877C109.131 2.00028 109.081 1.59031 108.917 1.22045C108.754 0.850591 108.484 0.537368 108.143 0.320195C107.802 0.103021 107.404 -0.0084012 107 -5.10783e-05H23C22.4368 0.000541762 21.8797 0.117167 21.3636 0.342553C20.8474 0.567938 20.3833 0.897249 20 1.30995L2.3 20.3099C2.02772 20.6038 1.84706 20.9708 1.78012 21.3658C1.71318 21.7608 1.76288 22.1667 1.92313 22.5339C2.08338 22.9011 2.34722 23.2136 2.68235 23.4331C3.01749 23.6527 3.40937 23.7697 3.81 23.7699Z"
fill="url(#paint0_linear_1064_606)" id="path2" />
<path
d="M210.94 40.6002H166V25.8002H222.62V11.0002H165.85C163.91 10.9897 161.988 11.3613 160.192 12.0938C158.396 12.8264 156.761 13.9055 155.383 15.2696C154.004 16.6337 152.907 18.2561 152.155 20.044C151.403 21.832 151.01 23.7506 151 25.6902V40.6902C151.008 42.6315 151.398 44.5523 152.149 46.3425C152.9 48.1328 153.996 49.7575 155.375 51.1237C156.755 52.49 158.39 53.5709 160.187 54.3047C161.984 55.0385 163.909 55.4108 165.85 55.4002H210.85V70.2002H152.07V85.0002H210.94C212.88 85.0108 214.802 84.6391 216.598 83.9066C218.394 83.174 220.029 82.0949 221.407 80.7308C222.786 79.3667 223.883 77.7444 224.635 75.9564C225.387 74.1684 225.78 72.2498 225.79 70.3102V55.3102C225.782 53.3689 225.392 51.4482 224.641 49.6579C223.89 47.8676 222.794 46.2429 221.415 44.8767C220.035 43.5105 218.4 42.4296 216.603 41.6958C214.806 40.962 212.881 40.5897 210.94 40.6002Z"
fill="white" id="path4" style="fill:#000000;fill-opacity:1" />
<path
d="M298 11H252.89C250.947 10.9842 249.02 11.3519 247.219 12.0821C245.419 12.8123 243.78 13.8905 242.397 15.2552C241.013 16.6198 239.913 18.2439 239.159 20.0345C238.404 21.8251 238.01 23.747 238 25.69V70.31C238.01 72.253 238.404 74.1749 239.159 75.9655C239.913 77.7561 241.013 79.3802 242.397 80.7448C243.78 82.1095 245.419 83.1877 247.219 83.9179C249.02 84.6481 250.947 85.0158 252.89 85H298C299.94 85.0105 301.862 84.6389 303.658 83.9064C305.454 83.1738 307.089 82.0947 308.467 80.7306C309.846 79.3665 310.943 77.7441 311.695 75.9562C312.447 74.1682 312.84 72.2496 312.85 70.31V25.69C312.84 23.7504 312.447 21.8318 311.695 20.0438C310.943 18.2559 309.846 16.6335 308.467 15.2694C307.089 13.9053 305.454 12.8262 303.658 12.0936C301.862 11.3611 299.94 10.9895 298 11ZM297.89 70.2H253V25.8H297.87L297.89 70.2Z"
fill="white" id="path6" style="fill:#000000" />
<path
d="M456 11.0001H412C410.06 10.9896 408.138 11.3612 406.342 12.0937C404.546 12.8263 402.911 13.9054 401.533 15.2695C400.154 16.6336 399.057 18.256 398.305 20.0439C397.553 21.8319 397.16 23.7505 397.15 25.6901V85.0001H412.15V60.6901H455.95V85.0001H470.95V25.6901C470.94 23.742 470.544 21.8152 469.786 20.0206C469.027 18.2261 467.922 16.5993 466.532 15.2338C465.143 13.8684 463.497 12.7914 461.689 12.0648C459.881 11.3382 457.948 10.9764 456 11.0001ZM455.89 45.8901H412.09V25.8001H455.89V45.8901Z"
fill="white" id="path8" style="fill:#000000" />
<path
d="M631.15 11.0002H587.15C585.21 10.9897 583.288 11.3613 581.492 12.0938C579.696 12.8264 578.062 13.9055 576.683 15.2696C575.304 16.6337 574.207 18.2561 573.455 20.044C572.703 21.832 572.31 23.7506 572.3 25.6902V85.0002H587.3V60.6902H631V85.0002H646V25.6902C645.99 23.7506 645.597 21.832 644.845 20.044C644.093 18.2561 642.996 16.6337 641.617 15.2696C640.238 13.9055 638.604 12.8264 636.808 12.0938C635.012 11.3613 633.09 10.9897 631.15 11.0002ZM631 45.8902H587.2V25.8002H631V45.8902Z"
fill="white" id="path10" style="fill:#000000" />
<path
d="M544 70.2001H538L516.55 17.2001C515.815 15.3716 514.55 13.8045 512.918 12.6999C511.286 11.5952 509.361 11.0033 507.39 11.0001H494.08C492.786 10.9935 491.504 11.2418 490.307 11.7307C489.109 12.2197 488.02 12.9397 487.1 13.8497C486.181 14.7598 485.45 15.8419 484.949 17.0345C484.448 18.227 484.187 19.5066 484.18 20.8001V85.0001H499.18V25.8001H505.18L526.62 78.8001C527.367 80.6251 528.642 82.1858 530.281 83.283C531.919 84.3803 533.848 84.9641 535.82 84.9601H549.13C550.424 84.9667 551.706 84.7185 552.903 84.2295C554.101 83.7406 555.19 83.0205 556.11 82.1105C557.029 81.2005 557.76 80.1183 558.261 78.9258C558.762 77.7332 559.023 76.4537 559.03 75.1601V11.0001H544V70.2001Z"
fill="white" id="path12" style="fill:#000000" />
<path
d="M341.1 11H326.1V70.31C326.11 72.2539 326.505 74.1766 327.26 75.9678C328.015 77.7591 329.116 79.3836 330.5 80.7484C331.884 82.1132 333.525 83.1912 335.326 83.9208C337.128 84.6504 339.056 85.0171 341 85H386V70.2H341.1V11Z"
fill="white" id="path14" style="fill:#000000" />
</g>
<defs id="defs34">
<linearGradient id="paint0_linear_1064_606" x1="10.81" y1="98.29" x2="98.89" y2="-1.01005"
gradientUnits="userSpaceOnUse">
<stop offset="0.08" stop-color="#9945FF" id="stop18" />
<stop offset="0.3" stop-color="#8752F3" id="stop20" />
<stop offset="0.5" stop-color="#5497D5" id="stop22" />
<stop offset="0.6" stop-color="#43B4CA" id="stop24" />
<stop offset="0.72" stop-color="#28E0B9" id="stop26" />
<stop offset="0.97" stop-color="#19FB9B" id="stop28" />
</linearGradient>
<clipPath id="clip0_1064_606">
<rect width="646" height="96" fill="white" id="rect31" />
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 7.5 KiB

-8
View File
@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 -28.5 256 256" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid">
<g>
<path d="M216.856339,16.5966031 C200.285002,8.84328665 182.566144,3.2084988 164.041564,0 C161.766523,4.11318106 159.108624,9.64549908 157.276099,14.0464379 C137.583995,11.0849896 118.072967,11.0849896 98.7430163,14.0464379 C96.9108417,9.64549908 94.1925838,4.11318106 91.8971895,0 C73.3526068,3.2084988 55.6133949,8.86399117 39.0420583,16.6376612 C5.61752293,67.146514 -3.4433191,116.400813 1.08711069,164.955721 C23.2560196,181.510915 44.7403634,191.567697 65.8621325,198.148576 C71.0772151,190.971126 75.7283628,183.341335 79.7352139,175.300261 C72.104019,172.400575 64.7949724,168.822202 57.8887866,164.667963 C59.7209612,163.310589 61.5131304,161.891452 63.2445898,160.431257 C105.36741,180.133187 151.134928,180.133187 192.754523,160.431257 C194.506336,161.891452 196.298154,163.310589 198.110326,164.667963 C191.183787,168.842556 183.854737,172.420929 176.223542,175.320965 C180.230393,183.341335 184.861538,190.991831 190.096624,198.16893 C211.238746,191.588051 232.743023,181.531619 254.911949,164.955721 C260.227747,108.668201 245.831087,59.8662432 216.856339,16.5966031 Z M85.4738752,135.09489 C72.8290281,135.09489 62.4592217,123.290155 62.4592217,108.914901 C62.4592217,94.5396472 72.607595,82.7145587 85.4738752,82.7145587 C98.3405064,82.7145587 108.709962,94.5189427 108.488529,108.914901 C108.508531,123.290155 98.3405064,135.09489 85.4738752,135.09489 Z M170.525237,135.09489 C157.88039,135.09489 147.510584,123.290155 147.510584,108.914901 C147.510584,94.5396472 157.658606,82.7145587 170.525237,82.7145587 C183.391518,82.7145587 193.761324,94.5189427 193.539891,108.914901 C193.539891,123.290155 183.391518,135.09489 170.525237,135.09489 Z" fill="#5865F2" fill-rule="nonzero">
␍</path>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.0 KiB

-10
View File
@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
␍<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="none">
␍<g fill-rule="evenodd" clip-rule="evenodd">
␍<path fill="#E01E5A" d="M2.471 11.318a1.474 1.474 0 001.47-1.471v-1.47h-1.47A1.474 1.474 0 001 9.846c.001.811.659 1.469 1.47 1.47zm3.682-2.942a1.474 1.474 0 00-1.47 1.471v3.683c.002.811.66 1.468 1.47 1.47a1.474 1.474 0 001.47-1.47V9.846a1.474 1.474 0 00-1.47-1.47z"/>
␍<path fill="#36C5F0" d="M4.683 2.471c.001.811.659 1.469 1.47 1.47h1.47v-1.47A1.474 1.474 0 006.154 1a1.474 1.474 0 00-1.47 1.47zm2.94 3.682a1.474 1.474 0 00-1.47-1.47H2.47A1.474 1.474 0 001 6.153c.002.812.66 1.469 1.47 1.47h3.684a1.474 1.474 0 001.47-1.47z"/>
␍<path fill="#2EB67D" d="M9.847 7.624a1.474 1.474 0 001.47-1.47V2.47A1.474 1.474 0 009.848 1a1.474 1.474 0 00-1.47 1.47v3.684c.002.81.659 1.468 1.47 1.47zm3.682-2.941a1.474 1.474 0 00-1.47 1.47v1.47h1.47A1.474 1.474 0 0015 6.154a1.474 1.474 0 00-1.47-1.47z"/>
␍<path fill="#ECB22E" d="M8.377 9.847c.002.811.659 1.469 1.47 1.47h3.683A1.474 1.474 0 0015 9.848a1.474 1.474 0 00-1.47-1.47H9.847a1.474 1.474 0 00-1.47 1.47zm2.94 3.682a1.474 1.474 0 00-1.47-1.47h-1.47v1.47c.002.812.659 1.469 1.47 1.47a1.474 1.474 0 001.47-1.47z"/>
␍</g>
␍</svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 428 KiB

-8
View File
@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 0 256 256" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g>
<path d="M128.080089,-0.000183105 C135.311053,0.0131003068 142.422517,0.624138494 149.335663,1.77979593 L149.335663,1.77979593 L149.335663,76.2997796 L202.166953,23.6044907 C208.002065,27.7488446 213.460883,32.3582023 218.507811,37.3926715 C223.557281,42.4271407 228.192318,47.8867213 232.346817,53.7047992 L232.346817,53.7047992 L179.512985,106.400063 L254.227854,106.400063 C255.387249,113.29414 256,120.36111 256,127.587243 L256,127.587243 L256,127.759881 C256,134.986013 255.387249,142.066204 254.227854,148.960282 L254.227854,148.960282 L179.500273,148.960282 L232.346817,201.642324 C228.192318,207.460402 223.557281,212.919983 218.523066,217.954452 L218.523066,217.954452 L218.507811,217.954452 C213.460883,222.988921 208.002065,227.6115 202.182208,231.742607 L202.182208,231.742607 L149.335663,179.04709 L149.335663,253.5672 C142.435229,254.723036 135.323765,255.333244 128.092802,255.348499 L128.092802,255.348499 L127.907197,255.348499 C120.673691,255.333244 113.590195,254.723036 106.677048,253.5672 L106.677048,253.5672 L106.677048,179.04709 L53.8457596,231.742607 C42.1780766,223.466917 31.977435,213.278734 23.6658953,201.642324 L23.6658953,201.642324 L76.4997269,148.960282 L1.78485803,148.960282 C0.612750404,142.052729 0,134.946095 0,127.719963 L0,127.719963 L0,127.349037 C0.0121454869,125.473817 0.134939797,123.182933 0.311311815,120.812834 L0.36577283,120.099764 C0.887996182,113.428547 1.78485803,106.400063 1.78485803,106.400063 L1.78485803,106.400063 L76.4997269,106.400063 L23.6658953,53.7047992 C27.8076812,47.8867213 32.4300059,42.4403618 37.4769335,37.4193681 L37.4769335,37.4193681 L37.5023588,37.3926715 C42.5391163,32.3582023 48.0106469,27.7488446 53.8457596,23.6044907 L53.8457596,23.6044907 L106.677048,76.2997796 L106.677048,1.77979593 C113.590195,0.624138494 120.688946,0.0131003068 127.932622,-0.000183105 L127.932622,-0.000183105 L128.080089,-0.000183105 Z M128.067377,95.7600714 L127.945335,95.7600714 C118.436262,95.7600714 109.32891,97.5001809 100.910584,100.661566 C97.7553011,109.043534 96.0085811,118.129275 95.9958684,127.613685 L95.9958684,127.733184 C96.0085811,137.217594 97.7553011,146.303589 100.923296,154.685303 C109.32891,157.846943 118.436262,159.587052 127.945335,159.587052 L128.067377,159.587052 C137.576449,159.587052 146.683802,157.846943 155.089415,154.685303 C158.257411,146.290368 160.004131,137.217594 160.004131,127.733184 L160.004131,127.613685 C160.004131,118.129275 158.257411,109.043534 155.089415,100.661566 C146.683802,97.5001809 137.576449,95.7600714 128.067377,95.7600714 Z" fill="#FF4A00" fill-rule="nonzero">
␍</path>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.8 KiB

+92 -696
View File
@@ -1,189 +1,4 @@
{
"aboutus": "About Us",
"access": "Access",
"actions": "Actions",
"add": "Add",
"addMonitors": "Add monitors",
"advancedMatching": "Advanced matching",
"area": "Area",
"auth": {
"common": {
"errors": {
"validation": "Error validating data."
},
"fields": {
"role": {
"errors": {
"min": "At least one role is required"
}
}
},
"inputs": {
"email": {
"errors": {
"empty": "To continue, please enter your email address",
"invalid": "Please recheck validity of entered email address"
},
"label": "Email",
"placeholder": "jordan.ellis@domain.com"
},
"firstName": {
"errors": {
"empty": "Please enter your name",
"length": "Name must be less than 50 characters",
"pattern": "Name must contain only letters, spaces, apostrophes, or hyphens"
},
"label": "Name",
"placeholder": "Jordan"
},
"lastName": {
"errors": {
"empty": "Please enter your surname",
"length": "Surname must be less than 50 characters",
"pattern": "Surname must contain only letters, spaces, apostrophes, or hyphens"
},
"label": "Surname",
"placeholder": "Ellis"
},
"password": {
"errors": {
"empty": "Please enter your password",
"length": "Password must be at least 8 characters long",
"lowercase": "Password must contain at least 1 lowercase letter",
"number": "Password must contain at least 1 number",
"special": "Password must contain at least 1 special character (!?@#$%^&*()-_=+[]{}|;:'\",./\\~`)",
"uppercase": "Password must contain at least 1 uppercase letter"
},
"label": "Password",
"rules": {
"length": {
"beginning": "Must be at least",
"highlighted": "8 characters long"
},
"lowercase": {
"beginning": "Must contain at least",
"highlighted": "one lower character"
},
"match": {
"beginning": "Passwords",
"highlighted": "must match"
},
"number": {
"beginning": "Must contain at least",
"highlighted": "one number"
},
"special": {
"beginning": "Must contain at least",
"highlighted": "one special character (!?@#$%^&*()-_=+[]{}|;:'\",./\\~`)"
},
"uppercase": {
"beginning": "Must contain at least",
"highlighted": "one upper character"
}
}
},
"passwordConfirm": {
"errors": {
"different": "Entered passwords don't match, so one of them is probably mistyped",
"empty": "Please enter your password again for confirmation (helps with typos)"
},
"label": "Confirm password",
"placeholder": "Re-enter password to confirm"
}
},
"navigation": {
"continue": "Continue"
},
"passwordRules": {
"length": "Must be at least 8 characters long",
"special": "Must contain at least one special character (!?@#$%^&*()-_=+[]{}|;:'\",./\\~`)",
"number": "Must contain at least one number",
"uppercase": "Must contain at least one upper character",
"lowercase": "Must contain at least one lower character",
"match": "Passwords must match"
}
},
"forgotPassword": {
"buttons": {
"openEmail": "Open email app",
"resetPassword": "Reset password"
},
"heading": "Forgot password?",
"links": {
"login": "Go back to <a>Log In</a>",
"resend": "Didn't receive the email? <a>Click to resend</a>"
},
"subheadings": {
"stepFour": "Your password has been successfully reset. Click below to log in magically.",
"stepOne": "No worries, we'll send you reset instructions.",
"stepThree": "Your new password must be different from previously used passwords.",
"stepTwo": "We sent a password reset link to <email/>"
},
"toasts": {
"emailNotFound": "Email not found.",
"error": "Unable to reset password. Please try again later or contact support.",
"redirect": "Redirecting in <seconds/>...",
"sent": "Instructions sent to <email/>.",
"success": "Your password was reset successfully."
}
},
"login": {
"errors": {
"password": {
"incorrect": "The password you provided does not match our records"
}
},
"heading": "Log in to continue",
"links": {
"forgotPassword": "Forgot password?",
"forgotPasswordLink": "Reset password",
"register": "Do not have an account?",
"registerLink": "Register here"
},
"toasts": {
"incorrectPassword": "Incorrect password",
"success": "Welcome back! You're successfully logged in."
},
"welcome": "Welcome back to Checkmate!"
},
"registration": {
"description": {
"superAdmin": "Create your super admin account to get started",
"user": "Sign up as a user and ask super admin for access to your monitors"
},
"heading": {
"user": "Sign Up"
},
"toasts": {
"success": "Welcome! Your account was created successfully."
},
"welcome": "Welcome to Checkmate!"
}
},
"avgCpuTemperature": "Average CPU Temperature",
"bar": "Bar",
"basicInformation": "Basic Information",
"bulkImport": {
"fallbackPage": "Import a file to upload a list of servers in bulk",
"invalidFileType": "Invalid file type",
"noFileSelected": "No file selected",
"selectFile": "Select File",
"selectFileDescription": "You can download our <template>template</template> or <sample>sample</sample>",
"selectFileTips": "Select CSV file to upload",
"title": "Bulk Import",
"uploadFailed": "Upload failed",
"uploadSuccess": "Monitors created successfully!"
},
"bytesSent": "Bytes Sent",
"addMember": "Add member",
"cancel": "Cancel",
"checkHooks": {
"failureResolveOne": "Failed to resolve incident."
},
"chooseGame": "Choose game",
"city": "CITY",
"ClickUpload": "Click to upload",
"close": "Close",
"common": {
"auth": {
"roles": {
@@ -222,7 +37,8 @@
"testNotifications": "Test notifications",
"toggleTheme": "Toggles light & dark",
"flushQueue": "Flush queue",
"notFound": "Go to the main dashboard"
"notFound": "Go to the main dashboard",
"resetPassword": "Reset password"
},
"charts": {
"labels": {
@@ -290,28 +106,23 @@
"interval": "Interval",
"active": "Active"
}
},
"toasts": {
"checkConnection": "Please check your connection",
"networkError": "Network error",
"unknownError": "Unknown error"
},
}
},
"components": {
"imageUpload": {
"clickToUpload": "Click to upload",
"dragAndDrop": "or drag and drop",
"supportedFormats": "Supported formats",
"maxSize": "Max size",
"orDragAndDrop": "or drag and drop"
"orDragAndDrop": "or drag and drop",
"errors": {
"invalidFileSize": "File size is too large!",
"invalidFileFormat": "Unsupported file format!"
}
},
"headerStatusPageControls": {
"publicLink": "Public link"
},
"errors": {
"invalidFileType": "Invalid file type",
"fileTooLarge": "File too large"
}
},
"commonSave": "Save",
"commonSaving": "Saving...",
"companyName": "Company name",
"components": {
"headerTimeRange": {
"labels": {
"day": "Day",
@@ -376,229 +187,6 @@
"description": "See the latest releases and help grow the community on GitHub"
}
},
"configure": "Configure",
"confirmPassword": "Confirm password",
"cores": "Cores",
"cpu": "CPU",
"cpuFrequency": "CPU Frequency",
"cpuLogical": "CPU (Logical)",
"cpuPhysical": "CPU (Physical)",
"cpuTemperature": "CPU Temperature",
"cpuUsage": "CPU usage",
"createA": "Create a",
"createMaintenance": "Create maintenance",
"createMaintenanceWindow": "Create maintenance window",
"createMonitor": "Create monitor",
"createNew": "Create new",
"delete": "Delete",
"generateToken": "Generate token",
"DeleteAccountButton": "Remove account",
"DeleteAccountTitle": "Remove account",
"DeleteAccountWarning": "Removing your account means you won't be able to sign in again and all your data will be removed. This isn't reversible.",
"DeleteDescriptionText": "This will remove the account and all associated data from the server. This isn't reversible.",
"deleteStatusPage": "Do you want to delete this status page?",
"deleteStatusPageConfirm": "Yes, delete status page",
"deleteStatusPageDescription": "Once deleted, your status page cannot be retrieved.",
"DeleteWarningTitle": "Really remove this account?",
"details": "Details",
"device": "Device",
"diagnosticsPage": {
"diagnosticDescription": "System diagnostics",
"gauges": {
"heapAllocationSubtitle": "% of available memory",
"heapAllocationTitle": "Heap allocation",
"heapUsageSubtitle": "% of available memory",
"heapUsageTitle": "Heap usage",
"heapUtilizationSubtitle": "% of allocated",
"heapUtilizationTitle": "Heap utilization",
"instantCpuUsageSubtitle": "% of 1s used by CPU",
"instantCpuUsageTitle": "Instant CPU usage"
},
"stats": {
"eventLoopDelayTitle": "Event loop delay",
"osMemoryLimitTitle": "OS Memory Limit",
"totalHeapSizeTitle": "Total heap size",
"uptimeTitle": "Uptime",
"usedHeapSizeTitle": "Used heap size"
}
},
"disk": "Disk",
"diskUsage": "Disk Usage",
"displayName": "Display name",
"download": "Download",
"DragandDrop": "drag and drop",
"duration": "Duration",
"edit": "Edit",
"editing": "Editing...",
"editMaintenance": "Edit maintenance",
"editUserPage": {
"form": {
"email": "Email",
"firstName": "First name",
"lastName": "Last name",
"role": "Roles",
"save": "Save"
},
"table": {
"actionHeader": "Action",
"roleHeader": "Role"
},
"title": "Edit user",
"toast": {
"successUserUpdate": "User updated successfully",
"validationErrors": "Validation errors"
}
},
"EmailDescriptionText": "This is your current email address — it cannot be changed.",
"errorPages": {
"serverUnreachable": {
"alertBox": "Server Connection Error",
"description": "We're unable to connect to the server. Please check your internet connection or verify your deployment configuration if the problem persists.",
"retryButton": {
"default": "Retry connection",
"processing": "Connecting..."
},
"toasts": {
"reconnected": "Successfully reconnected to the server.",
"stillUnreachable": "Server is still unreachable. Please try again later."
}
}
},
"errors": "Errors",
"expectedValue": "Expected value",
"failedToSendEmail": "Failed to send email",
"FirstName": "First name",
"frequency": "Frequency",
"friendlyNameInput": "Friendly name",
"friendlyNamePlaceholder": "Maintenance at __ : __ for ___ minutes",
"gb": "GB",
"general": {
"noOptionsFound": "No {{unit}} found"
},
"greeting": {
"append": "The afternoon is your playground—let's make it epic!",
"overview": "Here's an overview of your {{type}} monitors.",
"prepend": "Hey there"
},
"high": "high",
"host": "Host",
"http": "HTTP",
"https": "HTTPS",
"incidentsPage": {
"resolveIncidentDialogCommentLabel": "Comment (optional)",
"resolveIncidentDialogCommentPlaceholder": "Add a comment about the resolution...",
"resolveIncidentDialogConfirm": "Resolve",
"resolveIncidentDialogTitle": "Resolve Incident"
},
"integrations": "Integrations",
"integrationsDiscord": "Discord",
"integrationsDiscordInfo": "Connect with Discord and view incidents directly in a channel",
"integrationsPrism": "Connect Prism to your favorite service.",
"integrationsSlack": "Slack",
"integrationsSlackInfo": "Connect with Slack and see incidents in a channel",
"integrationsZapier": "Zapier",
"integrationsZapierInfo": "Send all incidents to Zapier, and then see them everywhere",
"invalidFileFormat": "Unsupported file format!",
"invalidFileSize": "File size is too large!",
"inviteNoTokenFound": "No invite token found",
"LastName": "Last name",
"logsPage": {
"logLevelSelect": {
"title": "Log level",
"values": {
"all": "All",
"debug": "Debug",
"error": "Error",
"info": "Info",
"warn": "Warn"
}
},
"noLogs": "No logs found",
"table": {
"level": "Level",
"logs": "logs",
"message": "Message",
"method": "Method",
"service": "Service",
"timestamp": "Timestamp"
},
"tabs": {
"diagnostics": "Diagnostics",
"logs": "Server logs",
"queue": "Job queue"
},
"title": "Logs"
},
"low": "low",
"maintenance": "maintenance",
"maintenanceRepeat": "Maintenance Repeat",
"maintenanceTableActionMenuDialogTitle": "Do you really want to remove this maintenance window?",
"maintenanceWindowDescription": "During maintenance windows, all monitoring is suspended for selected monitors. No network checks will be performed, preventing any status updates or notifications from being triggered. Your monitors will appear frozen at their last known status, and status pages will display a maintenance indicator. Once the maintenance window ends, monitoring automatically resumes, and alerts will trigger if issues are detected. Maintenance periods do not count against uptime calculations.",
"maintenanceWindowName": "Maintenance Window Name",
"matchMethod": "Match Method",
"matchMethodOptions": {
"equal": "Equal",
"include": "Include",
"regex": "Regex"
},
"MaxSize": "Maximum Size",
"mb": "MB",
"mem": "Mem",
"memory": "Memory",
"memoryUsage": "Memory usage",
"menu": {
"changelog": "Changelog",
"checks": "Checks",
"discussions": "Discussions",
"docs": "Docs",
"incidents": "Incidents",
"inviteMember": "Invite member",
"infrastructure": "Infrastructure",
"logOut": "Log out",
"logs": "Logs",
"maintenance": "Maintenance",
"notifications": "Notifications",
"pagespeed": "Pagespeed",
"password": "Password",
"profile": "Profile",
"settings": "Settings",
"statusPages": "Status pages",
"support": "Support",
"team": "Team",
"uptime": "Uptime"
},
"message": "Message",
"monitor": "monitor",
"monitorHooks": {
"failureAddDemoMonitors": "Failed to add demo monitors",
"successAddDemoMonitors": "Successfully added demo monitors"
},
"monitors": "monitors",
"monitorsToApply": "Monitors to apply maintenance window to",
"ms": "ms",
"navControls": "Controls",
"network": "Network",
"nextWindow": "Next window",
"notFoundButton": "Go to the main dashboard",
"notifications": {
"fallback": {
"actionButton": "Create notification channel!",
"checks": [
"Alert teams about downtime or performance issues",
"Let engineers know when incidents happen",
"Keep administrators informed of system changes"
],
"title": "A notification channel is used to:"
},
"fetch": {
"failed": "Failed to fetch notifications"
},
"test": {
"success": "Test notification sent successfully"
}
},
"now": "Now",
"os": "OS",
"pages": {
"notFound": {
"title": "Oh no! You dropped your sushi!",
@@ -681,7 +269,32 @@
},
"auth": {
"common": {
"passwordRules": {},
"passwordRules": {
"length": {
"beginning": "Must be at least",
"highlighted": "8 characters long"
},
"lowercase": {
"beginning": "Must contain at least",
"highlighted": "one lower character"
},
"match": {
"beginning": "Passwords",
"highlighted": "must match"
},
"number": {
"beginning": "Must contain at least",
"highlighted": "one number"
},
"special": {
"beginning": "Must contain at least",
"highlighted": "one special character (!?@#$%^&*()-_=+[]{}|;:'\",./\\~`)"
},
"uppercase": {
"beginning": "Must contain at least",
"highlighted": "one upper character"
}
},
"form": {
"option": {
"email": {
@@ -798,7 +411,10 @@
"label": "JSONPath expression"
},
"matchMethod": {
"label": "Match method"
"label": "Match method",
"equal": "Equal",
"include": "Include",
"regex": "Regex"
}
},
"title": "Advanced settings"
@@ -807,7 +423,19 @@
"description": "How often do you want to check the status of this monitor?",
"option": {
"frequency": {
"label": "Check frequency"
"label": "Check frequency",
"value": {
"fifteenMinutes": "15 minutes",
"fifteenSeconds": "15 seconds",
"fiveMinutes": "5 minutes",
"fourMinutes": "4 minutes",
"oneMinute": "1 minute",
"tenMinutes": "10 minutes",
"thirtyMinutes": "30 minutes",
"thirtySeconds": "30 seconds",
"threeMinutes": "3 minutes",
"twoMinutes": "2 minutes"
}
}
},
"title": "Check frequency"
@@ -833,6 +461,14 @@
"url": {
"label": "URL",
"placeholder": "https://www.google.com"
},
"game": {
"label": "Choose game",
"placeholder": "Select a game"
},
"port": {
"label": "Port to monitor",
"placeholder": 80
}
},
"title": "General settings",
@@ -884,6 +520,24 @@
"optionPort": "Port",
"optionPortDescription": "Monitor if a specific port on a server is open.",
"title": "Type"
},
"thresholds": {
"title": "Alert thresholds",
"description": "Define the thresholds at which alerts should be triggered for this hardware monitor.",
"option": {
"cpuThreshold": {
"label": "CPU alert threshold (%)"
},
"memoryThreshold": {
"label": "Memory alert threshold (%)"
},
"diskThreshold": {
"label": "Disk alert threshold (%)"
},
"tempThreshold": {
"label": "Temperature alert threshold (°C)"
}
}
}
}
},
@@ -897,6 +551,15 @@
},
"incidents": {
"dialog": {
"resolveIncident": {
"title": "Resolve incident",
"option": {
"comment": {
"label": "Comment (optional)",
"placeholder": "Add a comment about the resolution..."
}
}
},
"details": {
"analysis": "Incident analysis",
"comment": "Comment:",
@@ -1371,272 +1034,5 @@
"title": "An uptime monitor is used to:"
}
}
},
"pageSpeedAddApiKey": "to add your API key.",
"pageSpeedLearnMoreLink": "Click here",
"pageSpeedWarning": "Warning: You haven't added a Google PageSpeed API key yet. Without it, the PageSpeed monitor won't function.",
"passwordPanel": {
"confirmNewPassword": "Confirm new password",
"currentPassword": "Current password",
"enterCurrentPassword": "Enter your current password",
"enterNewPassword": "Enter your new password",
"newPassword": "New password",
"passwordChangedSuccess": "Your password was changed successfully.",
"passwordInputIncorrect": "Your password input was incorrect.",
"passwordRequirements": "New password must contain at least 8 characters and must have at least one uppercase letter, one lowercase letter, one number and one special character (!?@#$%^&*()-_=+[]{}|;:'\",./\\~`)."
},
"pause": "Pause",
"PhotoDescriptionText": "This photo will be displayed in your profile page.",
"portToMonitor": "Port to monitor",
"publicLink": "Public link",
"queuePage": {
"failedJobTable": {
"failCountHeader": "Fail count",
"failedAtHeader": "Last failed at",
"failReasonHeader": "Fail reason",
"monitorIdHeader": "Monitor ID",
"monitorUrlHeader": "Monitor URL",
"title": "Failed jobs"
},
"flushButton": "Flush queue",
"jobTable": {
"activeHeader": "Active",
"failCountHeader": "Fail count",
"idHeader": "Monitor ID",
"intervalHeader": "Interval",
"lastFinishedAtHeader": "Last finished at",
"lastRunHeader": "Last run at",
"lastRunTookHeader": "Last run took",
"lockedAtHeader": "Locked at",
"runCountHeader": "Run count",
"title": "Jobs currently in queue",
"typeHeader": "Type",
"urlHeader": "URL"
},
"metricsTable": {
"metricHeader": "Metric",
"title": "Queue metrics",
"valueHeader": "Value"
},
"refreshButton": "Refresh"
},
"rate": "Rate",
"remove": "Remove",
"repeat": "Repeat",
"reset": "Reset",
"response": "RESPONSE",
"responseTime": "Response time",
"resume": "Resume",
"roles": {
"admin": "Admin",
"demoUser": "Demo user",
"superAdmin": "Super admin",
"teamMember": "Team member"
},
"save": "Save",
"sendInvite": "Send invite",
"selectAll": "Select all",
"settingsFailedToClearStats": "Failed to clear stats",
"settingsFailedToDeleteMonitors": "Failed to delete all monitors",
"settingsFailedToSave": "Failed to save settings",
"settingsGeneralSettings": "General settings",
"settingsMonitorsDeleted": "Successfully deleted all monitors",
"settingsPage": {
"aboutSettings": {
"labelDevelopedBy": "Developed by Bluewave Labs",
"title": "About"
},
"demoMonitorsSettings": {
"buttonAddMonitors": "Add demo monitors",
"description": "Add sample monitors for demonstration purposes.",
"title": "Demo monitors"
},
"emailSettings": {
"buttonSendTestEmail": "Send test e-mail",
"description": "Configure the email settings for your system. This is used to send notifications and alerts.",
"descriptionTransport": "This builds an SMTP transport for NodeMailer",
"labelAddress": "Email address - Used for authentication",
"labelConnectionHost": "Email connection host - Hostname to use in the HELO/EHLO greeting",
"labelHost": "Email host - Hostname or IP address to connect to",
"labelIgnoreTLS": "Disable STARTTLS: Don't use TLS even if the server supports it",
"labelPassword": "Email password - Password for authentication",
"labelPasswordSet": "Password is set. Click Reset to change it.",
"labelPool": "Enable connection pooling: Reuse existing connections to improve performance",
"labelPort": "Email port - Port to connect to",
"labelRejectUnauthorized": "Reject invalid certificates: Reject connections with self-signed or untrusted certificates",
"labelRequireTLS": "Force STARTTLS: Require TLS upgrade, fail if not supported",
"labelSecure": "Use SSL (recommended): Encrypt the connection using SSL/TLS",
"labelTLSServername": "TLS Servername - Optional Hostname for TLS Validation when host is an IP",
"labelUser": "Email user - Username for authentication, overrides email address if specified",
"linkTransport": "See specifications here",
"placeholderUser": "Leave empty if not required",
"title": "Email",
"toastEmailRequiredFieldsError": "Email address, host, port and password are required"
},
"globalThresholds": {
"description": "Configure global CPU, Memory, Disk, and Temperature thresholds. If a value is provided, it will automatically be enabled for monitoring.",
"title": "Global Thresholds"
},
"pageSpeedSettings": {
"description": "Enter your Google PageSpeed API key to enable Google PageSpeed monitoring. Click Reset to update the key.",
"labelApiKey": "PageSpeed API key",
"labelApiKeySet": "API key is set. Click Reset to change it.",
"title": "Google PageSpeed API key"
},
"saveButtonLabel": "Save",
"statsSettings": {
"clearAllStatsButton": "Clear all stats",
"clearAllStatsDescription": "Clear all stats. This is irreversible.",
"clearAllStatsDialogConfirm": "Yes, clear all stats",
"clearAllStatsDialogDescription": "Once removed, the monitoring history and stats cannot be retrieved.",
"clearAllStatsDialogTitle": "Do you want to clear all stats?",
"description": "Define how long you want to retain historical data. You can also clear all existing data.",
"title": "Monitor history"
},
"systemResetSettings": {
"buttonRemoveAllMonitors": "Remove all monitors",
"description": "Remove all monitors from your system.",
"dialogConfirm": "Yes, remove all monitors",
"dialogTitle": "Do you want to remove all monitors?",
"title": "System reset"
},
"timezoneSettings": {
"description": "Select the timezone used to display dates and times throughout the application.",
"title": "Display timezone"
},
"title": "Settings",
"uiSettings": {
"chartTypeHeatmap": "Heatmap",
"chartTypeHistogram": "Histogram",
"description": "Switch between light and dark mode, or change user interface language.",
"labelChartType": "Chart type",
"labelLanguage": "Language",
"labelTheme": "Theme mode",
"title": "Appearance"
},
"urlSettings": {
"description": "Display the IP address or URL of monitor on the public Status page. If it's disabled, only the monitor name will be shown to protect sensitive information.",
"label": "Display IP/URL on status page",
"selectDisabled": "Disabled",
"selectEnabled": "Enabled",
"title": "Monitor IP/URL on Status Page"
}
},
"settingsStatsCleared": "Stats cleared successfully",
"settingsSuccessSaved": "Settings saved successfully",
"settingsTestEmailFailed": "Failed to send test email",
"settingsTestEmailFailedWithReason": "Failed to send test email: {{reason}}",
"settingsTestEmailSuccess": "Test email sent successfully",
"settingsTestEmailUnknownError": "Unknown error",
"shown": "Shown",
"starPromptDescription": "See the latest releases and help grow the community on GitHub",
"starPromptTitle": "Star Checkmate",
"startTime": "Start time",
"state": "State",
"status": "Status",
"statusCode": "Status code",
"statusPage": {
"contents": "Contents",
"deleteFailed": "Failed to delete status page",
"deleteSuccess": "Status page deleted successfully",
"generalSettings": "General settings",
"details": {
"statusHeader": {
"allUp": "All systems operational",
"allDown": "All systems are experiencing issues",
"anyDown": "Some systems are experiencing issues"
}
}
},
"statusPageCreate": {
"buttonSave": "Save"
},
"statusPageStatusServiceStatus": "Service status",
"submit": "Submit",
"SupportedFormats": "Supported formats",
"teamPanel": {
"addTeamMember": {
"addButton": "Add Member",
"addMemberMenu": "Add Team Member",
"description": "Create a new user and share the credentials with them. This method gives the member immediate access to all monitors.",
"title": "Register new team member"
},
"addMember": "Add member",
"cancel": "Cancel",
"changeTeamPassword": {
"changePasswordMenu": "Reset Password",
"description": "Create a new password for this team member. You will need to share the password with them securely.",
"success": "Password successfully reset. Make sure to provide the credentials to the member in a secure way.",
"title": "Reset team member password"
},
"email": "Email",
"emailToken": "E-mail token",
"filter": {
"all": "All",
"member": "Member"
},
"getToken": "Get token",
"inviteDescription": "When you add a new team member, they will get access to all monitors.",
"inviteLink": "Invite link",
"inviteNewTeamMember": "Invite new team member",
"inviteTeamMember": "Invite a team member",
"noMembers": "There are no team members with this role",
"register": "Register a team member",
"registerTeamMember": {
"auth": {
"common": {
"inputs": {
"role": {
"errors": {
"empty": "Role is required"
}
}
}
}
}
},
"registerToast": {
"success": "User created, share credentials with the member securely."
},
"role": "Role",
"selectRole": "Select role",
"table": {
"created": "Created",
"email": "Email",
"name": "Name",
"role": "Role"
},
"teamMembers": "Team members"
},
"time": {
"fifteenMinutes": "15 minutes",
"fifteenSeconds": "15 seconds",
"fiveMinutes": "5 minutes",
"fourMinutes": "4 minutes",
"oneMinute": "1 minute",
"tenMinutes": "10 minutes",
"thirtyMinutes": "30 minutes",
"thirtySeconds": "30 seconds",
"threeMinutes": "3 minutes",
"twoMinutes": "2 minutes"
},
"timezone": "Timezone",
"timeZoneInfo": "All dates and times are in GMT+0 time zone.",
"title": "Title",
"total": "Total",
"type": "Type",
"update": "Update",
"uptime": "Uptime",
"url": "URL",
"used": "Used",
"window": "window",
"YourPhoto": "Profile photo",
"failedDeleteMonitor": "Failed to delete monitor",
"failedPauseMonitor": "Failed to pause monitor",
"hour": "hour",
"minute": "minute",
"monitorDeleted": "Monitor deleted successfully",
"monitorPaused": "Monitor paused successfully",
"monitorResumed": "Monitor resumed successfully",
"name": "Name"
}
}
+1 -1
View File
@@ -5,7 +5,7 @@ import { BrowserRouter as Router } from "react-router-dom";
import { Provider } from "react-redux";
import { persistor, store } from "@/store.js";
import { PersistGate } from "redux-persist/integration/react";
import I18nLoader from "./Components/v1/I18nLoader/index.jsx";
import I18nLoader from "./Components/v2/i18nLoader";
import { initApiClient } from "./Utils/ApiClient.js";
initApiClient(store);
+43
View File
@@ -0,0 +1,43 @@
#!/usr/bin/env node
const fs = require("fs");
const path = require("path");
function flattenKeys(obj, prefix = "", result = []) {
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
const newKey = prefix ? `${prefix}.${key}` : key;
if (
typeof obj[key] === "object" &&
obj[key] !== null &&
!Array.isArray(obj[key])
) {
flattenKeys(obj[key], newKey, result);
} else {
result.push(newKey);
}
}
}
return result;
}
// Paths
const localesDir = path.join(__dirname, "../client/src/locales");
const inputPath = path.join(localesDir, "en.json");
const outputPath = path.join(localesDir, "keys.json");
try {
const jsonContent = fs.readFileSync(inputPath, "utf8");
const jsonData = JSON.parse(jsonContent);
const flattenedKeys = flattenKeys(jsonData);
flattenedKeys.sort();
fs.writeFileSync(outputPath, JSON.stringify(flattenedKeys, null, 2), "utf8");
console.log(`Keys written to: ${outputPath}`);
} catch (error) {
console.error(error.message);
process.exit(1);
}
+1 -1
View File
@@ -30,7 +30,7 @@ export const initializeControllers = (services: InitializedServices): Initialize
return {
authController: new AuthController(services.userService),
monitorController: new MonitorController(services.monitorService),
settingsController: new SettingsController(services.settingsService, services.emailService, services.db),
settingsController: new SettingsController(services.settingsService, services.emailService),
checkController: new CheckController(services.checkService),
inviteController: new InviteController(services.inviteService),
maintenanceWindowController: new MaintenanceWindowController(services.maintenanceWindowService),
+1 -13
View File
@@ -41,18 +41,6 @@ import crypto from "crypto";
import { games, GameDig } from "gamedig";
import jmespath from "jmespath";
// DB Modules
import { GenerateAvatarImage } from "../utils/imageProcessing.js";
import { ParseBoolean } from "../utils/utils.js";
// Models
import InviteToken from "../db/models/Invite.js";
import Team from "../db/models/Team.js";
import MaintenanceWindow from "../db/models/MaintenanceWindow.js";
import MonitorStats from "../db/models/MonitorStats.js";
import NotificationModel from "../db/models/Notification.js";
import RecoveryToken from "../db/models/RecoveryToken.js";
// repositories
import {
MongoMonitorsRepository,
@@ -176,7 +164,7 @@ export const initializeServices = async ({
const bufferService = new BufferService({ logger, checkService, settingsService });
const statusService = new StatusService({ logger, buffer: bufferService, monitorsRepository });
const statusService = new StatusService(logger, bufferService, monitorsRepository, monitorStatsRepository, checksRepository);
const webhookProvider = new WebhookProvider(logger);
const slackProvider = new SlackProvider(logger);
+1 -3
View File
@@ -8,11 +8,9 @@ class SettingsController {
static SERVICE_NAME = SERVICE_NAME;
private settingsService: any;
private emailService: any;
private db: any;
constructor(settingsService: any, emailService: any, db: any) {
constructor(settingsService: any, emailService: any) {
this.settingsService = settingsService;
this.emailService = emailService;
this.db = db;
}
get serviceName() {
@@ -11,6 +11,7 @@ import type { LatestChecksMap } from "@/repositories/checks/MongoChecksRepistory
export interface IChecksRepository {
// create
create(check: Check): Promise<Check>;
createChecks(checks: Check[]): Promise<Check[]>;
// single fetch
@@ -227,6 +227,11 @@ class MongoChecksRepository implements IChecksRepository {
} as unknown as CheckDocument;
};
create = async (check: Check) => {
const savedCheck = await CheckModel.create(check);
return this.toEntity(savedCheck);
};
createChecks = async (checks: Check[]) => {
const docs = checks.map((check) => this.toDocument(check));
const inserted = await CheckModel.insertMany(docs);
@@ -1,6 +1,7 @@
import type { MonitorStats } from "@/types/index.js";
export interface IMonitorStatsRepository {
// create
create(data: Omit<MonitorStats, "id" | "createdAt" | "updatedAt">): Promise<MonitorStats>;
// single fetch
findByMonitorId(monitorId: string): Promise<MonitorStats>;
// update
@@ -32,6 +32,11 @@ class MongoMonitorStatsRepository implements IMonitorStatsRepository {
};
};
create = async (data: Omit<MonitorStats, "id" | "createdAt" | "updatedAt">): Promise<MonitorStats> => {
const created = await MonitorStatsModel.create(data);
return this.toEntity(created);
};
findByMonitorId = async (monitorId: string): Promise<MonitorStats> => {
const monitorStats = await MonitorStatsModel.findOne({ monitorId: new mongoose.Types.ObjectId(monitorId) });
if (!monitorStats) {
@@ -86,7 +86,15 @@ class SuperSimpleQueueHelper {
// Step 3. Build check
const check = await this.checkService.buildCheck(status);
if (!check) {
this.logger.warn({
message: `No check could be built for monitor ${monitorId}`,
service: SERVICE_NAME,
method: "getMonitorJob",
details: { code: status.code, message: status.message },
});
return;
}
// Step 4 Add check to buffer
this.buffer.addToBuffer({ check });
// Step 4. Update monitor status
@@ -2,7 +2,14 @@ import type { Check } from "@/types/index.js";
const SERVICE_NAME = "BufferService";
class BufferService {
export interface IBufferService {
addToBuffer(check: Check): void;
removeCheckFromBuffer(check: Check): boolean;
scheduleNextFlush(): void;
flushBuffer(): Promise<void>;
}
class BufferService implements IBufferService {
static SERVICE_NAME = SERVICE_NAME;
private BUFFER_TIMEOUT: number;
private logger: any;
@@ -13,7 +20,6 @@ class BufferService {
constructor({ logger, checkService, settingsService }: { logger: any; checkService: any; settingsService: any }) {
this.BUFFER_TIMEOUT = settingsService.getSettings().nodeEnv === "development" ? 10 : 1000 * 60 * 1; // 1 minute
console.log(this.BUFFER_TIMEOUT);
this.logger = logger;
this.checksService = checkService;
this.SERVICE_NAME = SERVICE_NAME;
@@ -30,7 +36,7 @@ class BufferService {
return BufferService.SERVICE_NAME;
}
addToBuffer({ check }: { check: Check }) {
addToBuffer(check: Check) {
try {
this.buffer.push(check);
} catch (error: any) {
@@ -1,6 +1,4 @@
import { IMonitorsRepository } from "@/repositories/index.js";
import MonitorStats from "../../db/models/MonitorStats.js";
import { CheckModel } from "@/db/models/index.js";
import { IChecksRepository, IMonitorsRepository, IMonitorStatsRepository } from "@/repositories/index.js";
import type {
Monitor,
MonitorStatus,
@@ -10,7 +8,9 @@ import type {
HardwareStatusPayload,
PageSpeedStatusPayload,
CheckSnapshot,
MonitorStats,
} from "@/types/index.js";
import { ILogger } from "@/utils/logger.js";
const SERVICE_NAME = "StatusService";
export interface IStatusService {
@@ -27,11 +27,21 @@ export class StatusService implements IStatusService {
private logger: any;
private buffer: any;
private monitorsRepository: IMonitorsRepository;
private monitorStatsRepository: IMonitorStatsRepository;
private checksRepository: IChecksRepository;
constructor({ logger, buffer, monitorsRepository }: { logger: any; buffer: any; monitorsRepository: IMonitorsRepository }) {
constructor(
logger: ILogger,
buffer: any,
monitorsRepository: IMonitorsRepository,
monitorStatsRepository: IMonitorStatsRepository,
checksRepository: IChecksRepository
) {
this.logger = logger;
this.buffer = buffer;
this.monitorsRepository = monitorsRepository;
this.monitorStatsRepository = monitorStatsRepository;
this.checksRepository = checksRepository;
}
get serviceName() {
@@ -42,18 +52,29 @@ export class StatusService implements IStatusService {
try {
const monitorId = monitor.id;
const { responseTime, status } = networkResponse;
// Get stats
let stats = await MonitorStats.findOne({ monitorId });
let stats: Omit<MonitorStats, "id" | "createdAt" | "updatedAt"> | null = null;
stats = await this.monitorStatsRepository
.findByMonitorId(monitorId)
.then((result) => result)
.catch(() => {
this.logger.debug({
service: SERVICE_NAME,
method: "updateRunningStats",
message: `No existing stats found for monitor ${monitorId}, initializing new stats.`,
});
return null;
});
if (!stats) {
stats = new MonitorStats({
stats = {
monitorId,
avgResponseTime: 0,
totalChecks: 0,
totalUpChecks: 0,
totalDownChecks: 0,
uptimePercentage: 0,
lastCheck: null,
});
lastResponseTime: 0,
lastCheckTimestamp: 0,
};
}
// Update stats
@@ -96,8 +117,7 @@ export class StatusService implements IStatusService {
// latest check
stats.lastCheckTimestamp = new Date().getTime();
await stats.save();
await this.monitorStatsRepository.create(stats);
return true;
} catch (error: any) {
this.logger.error({
@@ -112,11 +132,10 @@ export class StatusService implements IStatusService {
handleIncidentForCheck = async (check: Check, monitor: Monitor, action: any, errorContext = "incident handling") => {
try {
let savedCheck;
let savedCheck: Check | null = null;
if (!check.id) {
try {
const checkModel = new CheckModel(check);
savedCheck = await checkModel.save();
savedCheck = await this.checksRepository.create(check);
this.buffer.removeCheckFromBuffer(check);
} catch (checkError: any) {