blip toast proxy

master^2
Tudor Stanciu 2024-11-10 01:52:39 +02:00
parent f8d0d7c486
commit c5ba810605
15 changed files with 108 additions and 60 deletions

View File

@ -6,17 +6,16 @@ import AccountBoxIcon from "@mui/icons-material/AccountBox";
import SettingsIcon from "@mui/icons-material/Settings"; import SettingsIcon from "@mui/icons-material/Settings";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { useTuitioClient } from "@flare/tuitio-client-react"; import { useTuitioClient } from "@flare/tuitio-client-react";
import { useToast } from "../../hooks"; import { blip } from "../../utils";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
const ProfileButton = () => { const ProfileButton = () => {
const navigate = useNavigate(); const navigate = useNavigate();
const { error } = useToast();
const { t } = useTranslation(); const { t } = useTranslation();
const { logout } = useTuitioClient({ const { logout } = useTuitioClient({
onLogoutFailed: errorMessage => error(errorMessage), onLogoutFailed: errorMessage => blip.error(errorMessage),
onLogoutError: err => error(err.message) onLogoutError: err => blip.error(err.message)
}); });
const [anchorEl, setAnchorEl] = useState(null); const [anchorEl, setAnchorEl] = useState(null);

View File

@ -1,18 +0,0 @@
import React, { useState, useEffect } from "react";
import SystemVersionComponent from "./SystemVersionComponent";
import { routes, get } from "../../../utils/api";
const SystemVersionContainer = () => {
const [state, setState] = useState({ data: {}, loaded: false });
useEffect(() => {
if (state.loaded) return;
get(routes.systemVersion, {
onCompleted: data => setState({ data, loaded: true })
});
}, [state.loaded]);
return <>{state.loaded && <SystemVersionComponent data={state.data} />}</>;
};
export default SystemVersionContainer;

View File

@ -0,0 +1,26 @@
import React, { useState, useEffect } from "react";
import SystemVersionComponent from "./SystemVersionComponent";
import { routes, get, endpoints } from "../../../utils/api";
import useSWR from "swr";
import { fetcher } from "utils/swr";
import { blip } from "utils";
const SystemVersionContainer: React.FC = () => {
const { data: namespaces } = useSWR<any[], Error>(endpoints.system.version, fetcher, {
revalidateOnFocus: false,
onError: err => blip.error(err.message)
});
const [state, setState] = useState({ data: {}, loaded: false });
useEffect(() => {
if (state.loaded) return;
get(routes.systemVersion, {
onCompleted: (data: any) => setState({ data, loaded: true })
});
}, [state.loaded]);
return <>{state.loaded && <SystemVersionComponent data={state.data} />}</>;
};
export default SystemVersionContainer;

View File

@ -1,6 +1,6 @@
import React, { useState } from "react"; import React, { useState } from "react";
import LoginCard from "./LoginCard"; import LoginCard from "./LoginCard";
import { useToast } from "../../../hooks"; import { blip } from "../../../utils";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useTuitioClient } from "@flare/tuitio-client-react"; import { useTuitioClient } from "@flare/tuitio-client-react";
@ -10,11 +10,10 @@ const LoginContainer = () => {
password: "" password: ""
}); });
const { error } = useToast();
const { t } = useTranslation(); const { t } = useTranslation();
const { login } = useTuitioClient({ const { login } = useTuitioClient({
onLoginFailed: () => error(t("Login.IncorrectCredentials")), onLoginFailed: () => blip.error(t("Login.IncorrectCredentials")),
onLoginError: err => error(err.message) onLoginError: err => blip.error(err.message)
}); });
const handleChange = prop => event => { const handleChange = prop => event => {

View File

@ -3,15 +3,13 @@ import PropTypes from "prop-types";
import MachineTableRow from "./MachineTableRow"; import MachineTableRow from "./MachineTableRow";
import MachineAccordion from "./MachineAccordion"; import MachineAccordion from "./MachineAccordion";
import { ViewModes } from "./ViewModeSelection"; import { ViewModes } from "./ViewModeSelection";
import { useToast } from "../../../hooks"; import { blip } from "../../../utils";
import { LastPage, RotateLeft, Launch, Stop } from "@mui/icons-material"; import { LastPage, RotateLeft, Launch, Stop } from "@mui/icons-material";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { routes, post } from "../../../utils/api"; import { routes, post } from "../../../utils/api";
const MachineContainer = ({ machine, viewMode }) => { const MachineContainer = ({ machine, viewMode }) => {
const [logs, setLogs] = useState([]); const [logs, setLogs] = useState([]);
const { success, error } = useToast();
const { t } = useTranslation(); const { t } = useTranslation();
const addLog = useCallback( const addLog = useCallback(
@ -25,12 +23,12 @@ const MachineContainer = ({ machine, viewMode }) => {
response => { response => {
addLog(`Success: ${response.success}. Status: ${response.status}`); addLog(`Success: ${response.success}. Status: ${response.status}`);
if (response.success) { if (response.success) {
success(response.status); blip.success(response.status);
} else { } else {
error(response.status); blip.error(response.status);
} }
}, },
[error, success, addLog] [addLog]
); );
const pingMachine = useCallback( const pingMachine = useCallback(

View File

@ -3,7 +3,7 @@ import PropTypes from "prop-types";
import { IconButton, Tooltip } from "@mui/material"; import { IconButton, Tooltip } from "@mui/material";
import { PowerSettingsNew } from "@mui/icons-material"; import { PowerSettingsNew } from "@mui/icons-material";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useToast } from "../../../../hooks"; import { blip } from "../../../../utils";
import { msToMinAndSec } from "../../../../utils/time"; import { msToMinAndSec } from "../../../../utils/time";
import { routes, post } from "../../../../utils/api"; import { routes, post } from "../../../../utils/api";
@ -16,7 +16,6 @@ const WakeComponent = ({ machine, addLog, disabled }) => {
const [trigger, setTrigger] = useState(false); const [trigger, setTrigger] = useState(false);
const { t } = useTranslation(); const { t } = useTranslation();
const { success, error } = useToast();
const pingInterval = process.env.REACT_APP_MACHINE_PING_INTERVAL || defaultPingInterval; const pingInterval = process.env.REACT_APP_MACHINE_PING_INTERVAL || defaultPingInterval;
const startingTime = process.env.REACT_APP_MACHINE_STARTING_TIME || defaultStartingTime; const startingTime = process.env.REACT_APP_MACHINE_STARTING_TIME || defaultStartingTime;
@ -40,7 +39,7 @@ const WakeComponent = ({ machine, addLog, disabled }) => {
setState(prev => ({ ...prev, on: result.success })); setState(prev => ({ ...prev, on: result.success }));
log(`[Wake]: Success: ${result.success}. Status: ${result.status}`); log(`[Wake]: Success: ${result.success}. Status: ${result.status}`);
if (result.success) { if (result.success) {
success(result.status); blip.success(result.status);
//retrigger //retrigger
log(`Periodic ping will be re-triggered in ${startingTime} ms [${msToMinAndSec(startingTime)}]`); log(`Periodic ping will be re-triggered in ${startingTime} ms [${msToMinAndSec(startingTime)}]`);
@ -48,12 +47,12 @@ const WakeComponent = ({ machine, addLog, disabled }) => {
setTrigger(prev => !prev); setTrigger(prev => !prev);
}, startingTime); }, startingTime);
} else { } else {
error(result.status); blip.error(result.status);
} }
} }
} }
); );
}, [log, success, error, startingTime, machine.machineId]); }, [log, startingTime, machine.machineId]);
const pingInLoop = useCallback(async () => { const pingInLoop = useCallback(async () => {
if (disabled) return; if (disabled) return;

View File

@ -2,7 +2,7 @@ import React, { useCallback } from "react";
import CacheSettingsComponent from "./CacheSettingsComponent"; import CacheSettingsComponent from "./CacheSettingsComponent";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { routes, post } from "utils/api"; import { routes, post } from "utils/api";
import { info } from "utils/toast"; import { blip } from "utils";
const CacheSettingsContainer = () => { const CacheSettingsContainer = () => {
const { t } = useTranslation(); const { t } = useTranslation();
@ -11,7 +11,7 @@ const CacheSettingsContainer = () => {
routes.resetCache, routes.resetCache,
{}, {},
{ {
onCompleted: () => info(t("Settings.Cache.ResetInfo")) onCompleted: () => blip.info(t("Settings.Cache.ResetInfo"))
} }
); );
}, [t]); }, [t]);

View File

@ -1,6 +1,5 @@
import { useToast } from "./useToast";
import { useSensitiveInfo } from "../providers/SensitiveInfoProvider"; import { useSensitiveInfo } from "../providers/SensitiveInfoProvider";
import { usePermissions } from "../providers/UserPermissionsProvider"; import { usePermissions } from "../providers/UserPermissionsProvider";
import { useClipboard } from "./useClipboard"; import { useClipboard } from "./useClipboard";
export { useToast, useSensitiveInfo, usePermissions, useClipboard }; export { useSensitiveInfo, usePermissions, useClipboard };

View File

@ -1,16 +1,15 @@
import { useCallback } from "react"; import { useCallback } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useToast } from "./useToast"; import { blip } from "../utils";
const useClipboard = () => { const useClipboard = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const { info } = useToast();
const copy = useCallback( const copy = useCallback(
url => () => { url => () => {
navigator.clipboard.writeText(url); navigator.clipboard.writeText(url);
info(t("Generic.CopiedToClipboard")); blip.info(t("Generic.CopiedToClipboard"));
}, },
[info, t] [t]
); );
return { copy }; return { copy };
}; };

View File

@ -1,5 +0,0 @@
import { info, success, warning, error, dark } from "utils/toast";
export const useToast = () => {
return { info, success, warning, error, dark };
};

View File

@ -2,10 +2,12 @@ import * as axios from "../utils/axios";
import { toast } from "react-toastify"; import { toast } from "react-toastify";
import env from "../utils/env"; import env from "../utils/env";
const networkRoute = `${env.REACT_APP_NETWORK_RESURRECTOR_API_URL}/network`; const apiHost = env.REACT_APP_NETWORK_RESURRECTOR_API_URL;
const systemRoute = `${env.REACT_APP_NETWORK_RESURRECTOR_API_URL}/system`;
const powerActionsRoute = `${env.REACT_APP_NETWORK_RESURRECTOR_API_URL}/resurrector`; const networkRoute = `${apiHost}/network`;
const securityRoute = `${env.REACT_APP_NETWORK_RESURRECTOR_API_URL}/security`; const systemRoute = `${apiHost}/system`;
const powerActionsRoute = `${apiHost}/resurrector`;
const securityRoute = `${apiHost}/security`;
const routes = { const routes = {
permissions: `${securityRoute}/permissions`, permissions: `${securityRoute}/permissions`,
@ -16,7 +18,12 @@ const routes = {
wakeMachine: `${powerActionsRoute}/wake`, wakeMachine: `${powerActionsRoute}/wake`,
pingMachine: `${powerActionsRoute}/ping`, pingMachine: `${powerActionsRoute}/ping`,
shutdownMachine: `${powerActionsRoute}/shutdown`, shutdownMachine: `${powerActionsRoute}/shutdown`,
restartMachine: `${powerActionsRoute}/restart` restartMachine: `${powerActionsRoute}/restart`,
system: {
version: `${systemRoute}/version`,
releaseNotes: `${systemRoute}/release-notes`,
resetCache: `${systemRoute}/reset-cache`
}
}; };
const handleError = err => { const handleError = err => {
@ -64,4 +71,6 @@ const post = (route, data, options) => {
return promise; return promise;
}; };
export { routes, get, post }; const endpoints = routes;
export { routes, get, post, endpoints };

View File

@ -6,4 +6,6 @@ const warning = message => toast.warning(message);
const error = message => toast.error(message); const error = message => toast.error(message);
const dark = message => toast.dark(message); const dark = message => toast.dark(message);
export { info, success, warning, error, dark }; const blip = { info, success, warning, error, dark };
export { blip };
export default blip;

View File

@ -1,3 +0,0 @@
import { getRandomElement } from "./random";
export { getRandomElement };

View File

@ -0,0 +1,4 @@
import { getRandomElement } from "./random";
import blip from "./blip";
export { getRandomElement, blip };

40
frontend/src/utils/swr.ts Normal file
View File

@ -0,0 +1,40 @@
import i18next from "i18next";
import { acquire as fetchTuitioData } from "@flare/tuitio-client";
const getHeaders = (): HeadersInit => {
const { token } = fetchTuitioData();
const language = i18next.language;
const headers: HeadersInit = {
"Content-Type": "application/json"
};
if (token) {
headers.Authorization = `Tuitio ${token}`;
}
if (language) {
headers["Accept-Language"] = language;
}
return headers;
};
const fetcher = (url: string) => fetch(url, { method: "GET", headers: getHeaders() }).then(res => res.json());
async function mutationFetcher<Command>(url: string, { arg }: { arg: Command }) {
return fetch(url, {
method: "POST",
headers: getHeaders(),
body: JSON.stringify(arg)
}).then(res => res.json());
}
// async function deleteFetcher<Command>(url: string, { arg }: { arg: Command }) {
// return fetch(combine(url, arg as number), {
// method: "DELETE",
// headers: getHeaders()
// }).then(res => res.json());
// }
export { fetcher, mutationFetcher };