add yup dependency for validation, fix small bugs
This commit is contained in:
parent
e45be0e144
commit
49e3ce70f4
|
@ -44,7 +44,8 @@
|
||||||
"style-loader": "^3.3.1",
|
"style-loader": "^3.3.1",
|
||||||
"testcafe": "^2.4.0",
|
"testcafe": "^2.4.0",
|
||||||
"typescript": "^4.9.5",
|
"typescript": "^4.9.5",
|
||||||
"web-vitals": "^2.1.4"
|
"web-vitals": "^2.1.4",
|
||||||
|
"yup": "^1.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@formatjs/cli": "^6.0.3",
|
"@formatjs/cli": "^6.0.3",
|
||||||
|
@ -18173,6 +18174,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/property-expr": {
|
||||||
|
"version": "2.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.5.tgz",
|
||||||
|
"integrity": "sha512-IJUkICM5dP5znhCckHSv30Q4b5/JA5enCtkRHYaOVOAocnH/1BQEYTC5NMfT3AVl/iXKdr3aqQbQn9DxyWknwA=="
|
||||||
|
},
|
||||||
"node_modules/protocol-buffers-schema": {
|
"node_modules/protocol-buffers-schema": {
|
||||||
"version": "3.6.0",
|
"version": "3.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz",
|
||||||
|
@ -21580,6 +21586,11 @@
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/tiny-case": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q=="
|
||||||
|
},
|
||||||
"node_modules/tiny-warning": {
|
"node_modules/tiny-warning": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
|
||||||
|
@ -21691,6 +21702,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
||||||
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
|
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/toposort": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg=="
|
||||||
|
},
|
||||||
"node_modules/tough-cookie": {
|
"node_modules/tough-cookie": {
|
||||||
"version": "4.1.2",
|
"version": "4.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz",
|
||||||
|
@ -23353,6 +23369,28 @@
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/yup": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/yup/-/yup-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-CtpEHWiIMwWJBJ+zX8xWImXXdvJ10X/sKkYYTXfVocHj087e9zhP0GNkU7HlXBBI4T9BtHQxs8n2jLzmo/X8Yg==",
|
||||||
|
"dependencies": {
|
||||||
|
"property-expr": "^2.0.5",
|
||||||
|
"tiny-case": "^1.0.3",
|
||||||
|
"toposort": "^2.0.2",
|
||||||
|
"type-fest": "^2.19.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/yup/node_modules/type-fest": {
|
||||||
|
"version": "2.19.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz",
|
||||||
|
"integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.20"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/zustand": {
|
"node_modules/zustand": {
|
||||||
"version": "4.3.3",
|
"version": "4.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/zustand/-/zustand-4.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/zustand/-/zustand-4.3.3.tgz",
|
||||||
|
@ -36715,6 +36753,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"property-expr": {
|
||||||
|
"version": "2.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.5.tgz",
|
||||||
|
"integrity": "sha512-IJUkICM5dP5znhCckHSv30Q4b5/JA5enCtkRHYaOVOAocnH/1BQEYTC5NMfT3AVl/iXKdr3aqQbQn9DxyWknwA=="
|
||||||
|
},
|
||||||
"protocol-buffers-schema": {
|
"protocol-buffers-schema": {
|
||||||
"version": "3.6.0",
|
"version": "3.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz",
|
||||||
|
@ -39376,6 +39419,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/timed-out/-/timed-out-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/timed-out/-/timed-out-2.0.0.tgz",
|
||||||
"integrity": "sha512-pqqJOi1rF5zNs/ps4vmbE4SFCrM4iR7LW+GHAsHqO/EumqbIWceioevYLM5xZRgQSH6gFgL9J/uB7EcJhQ9niQ=="
|
"integrity": "sha512-pqqJOi1rF5zNs/ps4vmbE4SFCrM4iR7LW+GHAsHqO/EumqbIWceioevYLM5xZRgQSH6gFgL9J/uB7EcJhQ9niQ=="
|
||||||
},
|
},
|
||||||
|
"tiny-case": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q=="
|
||||||
|
},
|
||||||
"tiny-warning": {
|
"tiny-warning": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
|
||||||
|
@ -39472,6 +39520,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"toposort": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg=="
|
||||||
|
},
|
||||||
"tough-cookie": {
|
"tough-cookie": {
|
||||||
"version": "4.1.2",
|
"version": "4.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz",
|
||||||
|
@ -40789,6 +40842,24 @@
|
||||||
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
|
||||||
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="
|
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="
|
||||||
},
|
},
|
||||||
|
"yup": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/yup/-/yup-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-CtpEHWiIMwWJBJ+zX8xWImXXdvJ10X/sKkYYTXfVocHj087e9zhP0GNkU7HlXBBI4T9BtHQxs8n2jLzmo/X8Yg==",
|
||||||
|
"requires": {
|
||||||
|
"property-expr": "^2.0.5",
|
||||||
|
"tiny-case": "^1.0.3",
|
||||||
|
"toposort": "^2.0.2",
|
||||||
|
"type-fest": "^2.19.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"type-fest": {
|
||||||
|
"version": "2.19.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz",
|
||||||
|
"integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"zustand": {
|
"zustand": {
|
||||||
"version": "4.3.3",
|
"version": "4.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/zustand/-/zustand-4.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/zustand/-/zustand-4.3.3.tgz",
|
||||||
|
|
|
@ -39,7 +39,8 @@
|
||||||
"style-loader": "^3.3.1",
|
"style-loader": "^3.3.1",
|
||||||
"testcafe": "^2.4.0",
|
"testcafe": "^2.4.0",
|
||||||
"typescript": "^4.9.5",
|
"typescript": "^4.9.5",
|
||||||
"web-vitals": "^2.1.4"
|
"web-vitals": "^2.1.4",
|
||||||
|
"yup": "^1.1.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "react-scripts start",
|
"start": "react-scripts start",
|
||||||
|
|
|
@ -13,6 +13,7 @@ import Users from "./components/Users/Users";
|
||||||
import NavigationButtons from "./components/Layout/NavigationButtons";
|
import NavigationButtons from "./components/Layout/NavigationButtons";
|
||||||
import InstallationPage from "./components/Installations/InstallationPage";
|
import InstallationPage from "./components/Installations/InstallationPage";
|
||||||
import { UserContext } from "./components/Context/UserContextProvider";
|
import { UserContext } from "./components/Context/UserContextProvider";
|
||||||
|
import ResetPassword from "./ResetPassword";
|
||||||
|
|
||||||
const App = () => {
|
const App = () => {
|
||||||
const { token, setToken, removeToken } = useToken();
|
const { token, setToken, removeToken } = useToken();
|
||||||
|
@ -30,10 +31,9 @@ const App = () => {
|
||||||
if (!token) {
|
if (!token) {
|
||||||
return <Login setToken={setToken} setLanguage={setLanguage} />;
|
return <Login setToken={setToken} setLanguage={setLanguage} />;
|
||||||
}
|
}
|
||||||
|
if (token && currentUser?.mustResetPassword) {
|
||||||
/* TODO create reset page if (token && currentUser?.mustResetPassword) {
|
return <ResetPassword />;
|
||||||
return <div>Reset page</div>;
|
}
|
||||||
} */
|
|
||||||
return (
|
return (
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
<IntlProvider
|
<IntlProvider
|
||||||
|
|
|
@ -32,7 +32,8 @@ const Login = ({ setToken, setLanguage }: I_LoginProps) => {
|
||||||
|
|
||||||
const handleSubmit = () => {
|
const handleSubmit = () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
loginUser(username, password).then(({ data }) => {
|
loginUser(username, password)
|
||||||
|
.then(({ data }) => {
|
||||||
// TODO change this if they return err codes from backend
|
// TODO change this if they return err codes from backend
|
||||||
if (data && data.token) {
|
if (data && data.token) {
|
||||||
verifyToken(data.token)
|
verifyToken(data.token)
|
||||||
|
@ -49,11 +50,15 @@ const Login = ({ setToken, setLanguage }: I_LoginProps) => {
|
||||||
}
|
}
|
||||||
setError(data);
|
setError(data);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
setError(err);
|
||||||
|
setLoading(false);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container maxWidth="xs" sx={{ p: 2, alignContent: "center" }}>
|
<Container maxWidth="sm" sx={{ p: 2, alignContent: "center" }}>
|
||||||
<InnovenergyTextfield
|
<InnovenergyTextfield
|
||||||
id="username-textfield"
|
id="username-textfield"
|
||||||
label="Username"
|
label="Username"
|
||||||
|
|
|
@ -1,73 +1,79 @@
|
||||||
import React, { useContext, useState } from "react";
|
import React, { useContext, useState } from "react";
|
||||||
import { Alert, CircularProgress, Grid } from "@mui/material";
|
import { Alert, CircularProgress, Grid, Typography } from "@mui/material";
|
||||||
import Container from "@mui/material/Container";
|
import Container from "@mui/material/Container";
|
||||||
import { axiosConfigWithoutToken } from "./config/axiosConfig";
|
import axiosConfig from "./config/axiosConfig";
|
||||||
import InnovenergyTextfield from "./components/Layout/InnovenergyTextfield";
|
import InnovenergyTextfield from "./components/Layout/InnovenergyTextfield";
|
||||||
import InnovenergyButton from "./components/Layout/InnovenergyButton";
|
import InnovenergyButton from "./components/Layout/InnovenergyButton";
|
||||||
import { UserContext } from "./components/Context/UserContextProvider";
|
import { UserContext } from "./components/Context/UserContextProvider";
|
||||||
|
import { useFormik } from "formik";
|
||||||
|
import { AxiosError } from "axios";
|
||||||
|
import * as Yup from "yup";
|
||||||
|
|
||||||
const loginUser = async (username: string, password: string) => {
|
const ResetPassword = () => {
|
||||||
return axiosConfigWithoutToken.post("/Login", null, {
|
|
||||||
params: { username, password },
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
interface I_LoginProps {
|
|
||||||
setToken: (value: string) => void;
|
|
||||||
setLanguage: (value: string) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ResetPassword = ({ setToken, setLanguage }: I_LoginProps) => {
|
|
||||||
const [username, setUsername] = useState("");
|
|
||||||
const [password, setPassword] = useState("");
|
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [error, setError] = useState();
|
const [error, setError] = useState<AxiosError>();
|
||||||
const { setCurrentUser } = useContext(UserContext);
|
const { setCurrentUser } = useContext(UserContext);
|
||||||
|
|
||||||
const verifyToken = async (token: string) => {
|
const validationSchema = Yup.object().shape({
|
||||||
axiosConfigWithoutToken.get("/GetAllInstallations", {
|
password: Yup.string().required("*Password is required"),
|
||||||
params: { authToken: token },
|
verifyPassword: Yup.string()
|
||||||
|
.oneOf([Yup.ref("password")], "Passwords must match")
|
||||||
|
.required(),
|
||||||
});
|
});
|
||||||
};
|
|
||||||
|
|
||||||
const handleSubmit = () => {
|
const formik = useFormik({
|
||||||
|
initialValues: {
|
||||||
|
password: "",
|
||||||
|
verifyPassword: "",
|
||||||
|
},
|
||||||
|
onSubmit: (formikValues) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
loginUser(username, password).then(({ data }) => {
|
axiosConfig
|
||||||
// TODO change this if they return err codes from backend
|
.put("/UpdatePassword", undefined, {
|
||||||
if (data && data.token) {
|
params: { newPassword: formikValues.verifyPassword },
|
||||||
verifyToken(data.token)
|
|
||||||
.then(() => {
|
|
||||||
setToken(data.token);
|
|
||||||
setCurrentUser(data.user);
|
|
||||||
setLoading(false);
|
|
||||||
setLanguage(data.user.language);
|
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.then((res) => {
|
||||||
setError(err);
|
setCurrentUser(res.data);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
})
|
||||||
|
.catch((err) => setError(err));
|
||||||
|
},
|
||||||
|
validationSchema,
|
||||||
});
|
});
|
||||||
}
|
|
||||||
setError(data);
|
|
||||||
setLoading(false);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container maxWidth="xs" sx={{ p: 2, alignContent: "center" }}>
|
<Container maxWidth="sm" sx={{ p: 2, alignContent: "center" }}>
|
||||||
|
<Typography variant="h6" marginBottom="20px" textAlign="center">
|
||||||
|
Change password
|
||||||
|
</Typography>
|
||||||
|
<form onSubmit={formik.handleSubmit}>
|
||||||
<InnovenergyTextfield
|
<InnovenergyTextfield
|
||||||
id="username-textfield"
|
id="password-textfield"
|
||||||
label="Username"
|
label="Password"
|
||||||
name="email"
|
name="password"
|
||||||
value={username}
|
value={formik.values.password}
|
||||||
handleChange={(e) => setUsername(e.target.value)}
|
handleChange={formik.handleChange}
|
||||||
|
type="password"
|
||||||
/>
|
/>
|
||||||
{error && <Alert severity="error">Incorrect username or password</Alert>}
|
<InnovenergyTextfield
|
||||||
|
id="verify-password-textfield"
|
||||||
|
label="Verify password"
|
||||||
|
name="verifyPassword"
|
||||||
|
value={formik.values.verifyPassword}
|
||||||
|
handleChange={formik.handleChange}
|
||||||
|
type="password"
|
||||||
|
/>
|
||||||
|
{formik.errors.verifyPassword && formik.touched.verifyPassword && (
|
||||||
|
<Alert severity="error">{formik.errors.verifyPassword}</Alert>
|
||||||
|
)}
|
||||||
|
{error && <Alert severity="error">{error.name}</Alert>}
|
||||||
<Grid container justifyContent="flex-end" sx={{ pt: 1 }}>
|
<Grid container justifyContent="flex-end" sx={{ pt: 1 }}>
|
||||||
<InnovenergyButton onClick={handleSubmit} sx={{ my: 1 }}>
|
<InnovenergyButton type="submit" sx={{ my: 1 }}>
|
||||||
Login
|
Submit
|
||||||
</InnovenergyButton>
|
</InnovenergyButton>
|
||||||
</Grid>
|
</Grid>
|
||||||
{loading && <CircularProgress />}
|
{loading && <CircularProgress />}
|
||||||
|
</form>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,10 +1,5 @@
|
||||||
import Plot from "react-plotly.js";
|
import Plot from "react-plotly.js";
|
||||||
import exampleLogData, {
|
import { TimeSeries, timeSeries } from "../ExampleLogData";
|
||||||
Datum,
|
|
||||||
TimeSeries,
|
|
||||||
timeSeries,
|
|
||||||
} from "../ExampleLogData";
|
|
||||||
import { I_GraphData } from "../../../util/types";
|
|
||||||
|
|
||||||
const ScalarGraph = () => {
|
const ScalarGraph = () => {
|
||||||
const transformToGraphData = (timeStampData: TimeSeries) => {
|
const transformToGraphData = (timeStampData: TimeSeries) => {
|
||||||
|
@ -70,6 +65,17 @@ const ScalarGraph = () => {
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
layout={{ width: 1000, height: 500, title: path }}
|
layout={{ width: 1000, height: 500, title: path }}
|
||||||
|
config={{
|
||||||
|
modeBarButtonsToRemove: [
|
||||||
|
"lasso2d",
|
||||||
|
"select2d",
|
||||||
|
"pan2d",
|
||||||
|
"autoScale2d",
|
||||||
|
],
|
||||||
|
}}
|
||||||
|
onUpdate={(figure) => {
|
||||||
|
console.log(figure);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue