diff --git a/typescript/Frontend/package-lock.json b/typescript/Frontend/package-lock.json index a2c709fef..c02df11a5 100644 --- a/typescript/Frontend/package-lock.json +++ b/typescript/Frontend/package-lock.json @@ -44,7 +44,8 @@ "style-loader": "^3.3.1", "testcafe": "^2.4.0", "typescript": "^4.9.5", - "web-vitals": "^2.1.4" + "web-vitals": "^2.1.4", + "yup": "^1.1.0" }, "devDependencies": { "@formatjs/cli": "^6.0.3", @@ -18173,6 +18174,11 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "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": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz", @@ -21580,6 +21586,11 @@ "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": { "version": "1.0.3", "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", "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": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz", @@ -23353,6 +23369,28 @@ "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": { "version": "4.3.3", "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": { "version": "3.6.0", "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", "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": { "version": "1.0.3", "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": { "version": "4.1.2", "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", "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": { "version": "4.3.3", "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.3.3.tgz", diff --git a/typescript/Frontend/package.json b/typescript/Frontend/package.json index c818ec3d8..7f6499cb8 100644 --- a/typescript/Frontend/package.json +++ b/typescript/Frontend/package.json @@ -39,7 +39,8 @@ "style-loader": "^3.3.1", "testcafe": "^2.4.0", "typescript": "^4.9.5", - "web-vitals": "^2.1.4" + "web-vitals": "^2.1.4", + "yup": "^1.1.0" }, "scripts": { "start": "react-scripts start", diff --git a/typescript/Frontend/src/App.tsx b/typescript/Frontend/src/App.tsx index d4812b767..586cf423d 100644 --- a/typescript/Frontend/src/App.tsx +++ b/typescript/Frontend/src/App.tsx @@ -13,6 +13,7 @@ import Users from "./components/Users/Users"; import NavigationButtons from "./components/Layout/NavigationButtons"; import InstallationPage from "./components/Installations/InstallationPage"; import { UserContext } from "./components/Context/UserContextProvider"; +import ResetPassword from "./ResetPassword"; const App = () => { const { token, setToken, removeToken } = useToken(); @@ -30,10 +31,9 @@ const App = () => { if (!token) { return ; } - - /* TODO create reset page if (token && currentUser?.mustResetPassword) { - return
Reset page
; - } */ + if (token && currentUser?.mustResetPassword) { + return ; + } return ( { const handleSubmit = () => { setLoading(true); - loginUser(username, password).then(({ data }) => { - // TODO change this if they return err codes from backend - if (data && data.token) { - verifyToken(data.token) - .then(() => { - setToken(data.token); - setCurrentUser(data.user); - setLoading(false); - setLanguage(data.user.language); - }) - .catch((err) => { - setError(err); - setLoading(false); - }); - } - setError(data); - setLoading(false); - }); + loginUser(username, password) + .then(({ data }) => { + // TODO change this if they return err codes from backend + if (data && data.token) { + verifyToken(data.token) + .then(() => { + setToken(data.token); + setCurrentUser(data.user); + setLoading(false); + setLanguage(data.user.language); + }) + .catch((err) => { + setError(err); + setLoading(false); + }); + } + setError(data); + setLoading(false); + }) + .catch((err) => { + setError(err); + setLoading(false); + }); }; return ( - + { - 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 ResetPassword = () => { const [loading, setLoading] = useState(false); - const [error, setError] = useState(); + const [error, setError] = useState(); const { setCurrentUser } = useContext(UserContext); - const verifyToken = async (token: string) => { - axiosConfigWithoutToken.get("/GetAllInstallations", { - params: { authToken: token }, - }); - }; + const validationSchema = Yup.object().shape({ + password: Yup.string().required("*Password is required"), + verifyPassword: Yup.string() + .oneOf([Yup.ref("password")], "Passwords must match") + .required(), + }); - const handleSubmit = () => { - setLoading(true); - loginUser(username, password).then(({ data }) => { - // TODO change this if they return err codes from backend - if (data && data.token) { - verifyToken(data.token) - .then(() => { - setToken(data.token); - setCurrentUser(data.user); - setLoading(false); - setLanguage(data.user.language); - }) - .catch((err) => { - setError(err); - setLoading(false); - }); - } - setError(data); - setLoading(false); - }); - }; + const formik = useFormik({ + initialValues: { + password: "", + verifyPassword: "", + }, + onSubmit: (formikValues) => { + setLoading(true); + axiosConfig + .put("/UpdatePassword", undefined, { + params: { newPassword: formikValues.verifyPassword }, + }) + .then((res) => { + setCurrentUser(res.data); + setLoading(false); + }) + .catch((err) => setError(err)); + }, + validationSchema, + }); return ( - - setUsername(e.target.value)} - /> - {error && Incorrect username or password} - - - Login - - - {loading && } + + + Change password + +
+ + + {formik.errors.verifyPassword && formik.touched.verifyPassword && ( + {formik.errors.verifyPassword} + )} + {error && {error.name}} + + + Submit + + + {loading && } +
); }; diff --git a/typescript/Frontend/src/components/Installations/Log/ScalarGraph.tsx b/typescript/Frontend/src/components/Installations/Log/ScalarGraph.tsx index 414aab9b2..7a6fa4b87 100644 --- a/typescript/Frontend/src/components/Installations/Log/ScalarGraph.tsx +++ b/typescript/Frontend/src/components/Installations/Log/ScalarGraph.tsx @@ -1,10 +1,5 @@ import Plot from "react-plotly.js"; -import exampleLogData, { - Datum, - TimeSeries, - timeSeries, -} from "../ExampleLogData"; -import { I_GraphData } from "../../../util/types"; +import { TimeSeries, timeSeries } from "../ExampleLogData"; const ScalarGraph = () => { const transformToGraphData = (timeStampData: TimeSeries) => { @@ -70,6 +65,17 @@ const ScalarGraph = () => { }, ]} layout={{ width: 1000, height: 500, title: path }} + config={{ + modeBarButtonsToRemove: [ + "lasso2d", + "select2d", + "pan2d", + "autoScale2d", + ], + }} + onUpdate={(figure) => { + console.log(figure); + }} /> ); });