Merge pull request #1913 from SkynetLabs/dashboard-v2-auth-pages-login

Dashboard v2 auth pages login
This commit is contained in:
Karol Wypchło 2022-03-25 11:19:36 +01:00 committed by GitHub
commit 662565e870
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 357 additions and 6 deletions

View File

@ -8,3 +8,18 @@ This is a Gatsby application. To run it locally, all you need is:
- `yarn install`
- `yarn start`
## Accessing remote APIs
To be able to log in on a local environment with your production credentials, you'll need to make the browser believe you're actually on the same domain, otherwise the browser will block the session cookie.
To do the trick, edit your `/etc/hosts` file and add a record like this:
```
127.0.0.1 local.skynetpro.net
```
then run `yarn develop:secure` -- it will run `gatsby develop` with `--https --host=local.skynetpro.net -p=443` options.
If you're on macOS, you may need to `sudo` the command to successfully bind to port `443`.
> **NOTE:** This should become easier once we have a docker image for the new dashboard.

View File

@ -9,6 +9,7 @@
],
"scripts": {
"develop": "gatsby develop",
"develop:secure": "gatsby develop --https --host=local.skynetpro.net -p=443",
"start": "gatsby develop",
"build": "gatsby build",
"serve": "gatsby serve",
@ -24,9 +25,11 @@
"classnames": "^2.3.1",
"copy-text-to-clipboard": "^3.0.1",
"dayjs": "^1.10.8",
"formik": "^2.2.9",
"gatsby": "^4.6.2",
"gatsby-plugin-postcss": "^5.7.0",
"http-status-codes": "^2.2.0",
"ky": "^0.30.0",
"nanoid": "^3.3.1",
"path-browserify": "^1.0.1",
"postcss": "^8.4.6",
@ -38,7 +41,8 @@
"react-use": "^17.3.2",
"skynet-js": "^3.0.2",
"swr": "^1.2.2",
"tailwindcss": "^3.0.23"
"tailwindcss": "^3.0.23",
"yup": "^0.32.11"
},
"devDependencies": {
"@babel/core": "^7.17.4",

View File

@ -5,8 +5,8 @@ import styled from "styled-components";
/**
* Primary UI component for user interaction
*/
export const Button = styled.button.attrs(({ disabled, $primary }) => ({
type: "button",
export const Button = styled.button.attrs(({ disabled, $primary, type }) => ({
type,
className: cn("px-6 py-2.5 rounded-full font-sans uppercase text-xs tracking-wide transition-[opacity_filter]", {
"bg-primary text-palette-600": $primary,
"bg-white border-2 border-black text-palette-600": !$primary,
@ -14,6 +14,7 @@ export const Button = styled.button.attrs(({ disabled, $primary }) => ({
"hover:brightness-90": !disabled,
}),
}))``;
Button.propTypes = {
/**
* Is this the principal call to action on the page?
@ -23,9 +24,14 @@ Button.propTypes = {
* Prevent interaction on the button
*/
disabled: PropTypes.bool,
/**
* Type of button (button / submit)
*/
type: PropTypes.oneOf(["button", "submit"]),
};
Button.defaultProps = {
$primary: false,
disabled: false,
type: "button",
};

View File

@ -0,0 +1,56 @@
import PropTypes from "prop-types";
import cn from "classnames";
import { Field } from "formik";
export const TextField = ({ id, label, name, error, touched, ...props }) => {
return (
<div className="flex flex-col w-full gap-1">
{label && (
<label className="font-sans uppercase text-palette-300 text-xs" htmlFor={id}>
{label}
</label>
)}
<Field
id={id}
name={name}
className={cn("w-full py-2 px-4 bg-palette-100 rounded-sm placeholder:text-palette-200 outline-1", {
"focus:outline outline-palette-200": !error || !touched,
"outline outline-error": touched && error,
})}
{...props}
/>
{touched && error && (
<div className="text-error">
<small>{error}</small>
</div>
)}
</div>
);
};
/** Besides noted properties, it accepts all props accepted by:
* - a regular <input> element
* - Formik's <Field> component
*/
TextField.propTypes = {
/**
* ID for the field. Used to couple <label> and <input> elements
*/
id: PropTypes.string,
/**
* Label for the field
*/
label: PropTypes.string,
/**
* Name of the field
*/
name: PropTypes.string.isRequired,
/**
* Validation error message
*/
error: PropTypes.string,
/**
* Indicates wether or not the user touched the field already.
*/
touched: PropTypes.bool,
};

View File

@ -0,0 +1 @@
export * from "./TextField";

View File

@ -0,0 +1,6 @@
import { Link } from "gatsby";
import styled from "styled-components";
export default styled(Link).attrs({
className: "text-primary underline-offset-3 decoration-dotted hover:text-primary-light hover:underline",
})``;

View File

@ -1,4 +1,4 @@
import { Link } from "gatsby";
import { Link, navigate } from "gatsby";
import styled from "styled-components";
import { screen } from "../../lib/cssHelpers";
@ -7,6 +7,7 @@ import { CogIcon, LockClosedIcon, SkynetLogoIcon } from "../Icons";
import { PageContainer } from "../PageContainer";
import { NavBarLink, NavBarSection } from ".";
import accountsService from "../../services/accountsService";
const NavBarContainer = styled.div.attrs({
className: `grid sticky top-0 bg-white z-10 shadow-sm`,
@ -77,9 +78,13 @@ export const NavBar = () => (
partiallyActive
/>
<DropdownMenuLink
to="/logout"
as={Link}
onClick={async () => {
await accountsService.post("logout");
navigate("/auth/login");
// TODO: handle errors
}}
activeClassName="text-primary"
className="cursor-pointer"
icon={LockClosedIcon}
label="Log out"
/>

View File

@ -0,0 +1,95 @@
import { useState } from "react";
import PropTypes from "prop-types";
import { Formik, Form } from "formik";
import { Link } from "gatsby";
import * as Yup from "yup";
import HighlightedLink from "../HighlightedLink";
import { TextField } from "../Form/TextField";
import { Button } from "../Button";
import accountsService from "../../services/accountsService";
const loginSchema = Yup.object().shape({
email: Yup.string().required("Email is required").email("Please provide a valid email address"),
password: Yup.string().required("Password is required"),
});
const INVALID_CREDENTIALS_ERRORS = ["password mismatch", "user not found"];
export const LoginForm = ({ onSuccess }) => {
const [error, setError] = useState(null);
return (
<Formik
initialValues={{
email: "",
password: "",
}}
validationSchema={loginSchema}
onSubmit={async (values) => {
try {
await accountsService.post("login", {
json: values,
});
onSuccess();
} catch (err) {
if (err.response) {
const data = await err.response.json();
if (INVALID_CREDENTIALS_ERRORS.includes(data.message)) {
setError("Invalid email address or password.");
} else {
setError(data.message);
}
} else {
setError("An error occured when logging you in. Please try again.");
}
}
}}
>
{({ errors, touched }) => (
<Form className="flex flex-col gap-4">
<h3 className="mt-4 mb-4">Log in to your account</h3>
{error && <p className="px-4 py-3 rounded border border-error bg-red-50 text-error mb-4">{error}</p>}
<TextField
type="text"
id="email"
name="email"
label="Email address"
error={errors.email}
touched={touched.email}
/>
<TextField
type="password"
id="password"
name="password"
label="Password"
error={errors.password}
touched={touched.password}
/>
<div>
<Link to="/auth/recover" className="text-sm inline transition-colors hover:text-primary">
Forgot your password?
</Link>
</div>
<div className="flex w-full justify-center mt-4">
<Button type="submit" className="px-12" $primary>
Log in
</Button>
</div>
<p className="text-sm text-center mt-8">
Don't have an account? <HighlightedLink to="/auth/signup">Sign up</HighlightedLink>
</p>
</Form>
)}
</Formik>
);
};
LoginForm.propTypes = {
onSuccess: PropTypes.func.isRequired,
};

View File

@ -0,0 +1 @@
export * from "./LoginForm";

View File

@ -0,0 +1,45 @@
import * as React from "react";
import styled from "styled-components";
import { SWRConfig } from "swr";
import { UserProvider } from "../contexts/user";
import { guestsOnly } from "../lib/swrConfig";
const Layout = styled.div.attrs({
className: "h-screen w-screen bg-black flex",
})`
background-image: url(/images/auth-bg.svg);
background-repeat: no-repeat;
background-position: center center;
`;
const SloganContainer = styled.div.attrs({
className: "hidden md:flex lg:w-7/12 grow justify-center items-center relative overflow-hidden",
})``;
const Content = styled.div.attrs({
className: "w-full md:w-5/12 md:max-w-[680px] shrink-0",
})``;
const AuthLayout = ({ children }) => {
return (
<>
<SWRConfig value={guestsOnly}>
<UserProvider>
<Layout>
<SloganContainer className="pl-20 pr-20 lg:pr-30 xl:pr-40">
<div className="">
<h1 className="text-4xl lg:text-5xl xl:text-6xl text-white">
The decentralized <span className="text-primary">revolution</span> starts with decentralized storage
</h1>
</div>
</SloganContainer>
<Content>{children}</Content>
</Layout>
</UserProvider>
</SWRConfig>
</>
);
};
export default AuthLayout;

View File

@ -0,0 +1,23 @@
import { navigate } from "gatsby";
import AuthLayout from "../../layouts/AuthLayout";
import { LoginForm } from "../../components/forms";
const LoginPage = ({ location }) => {
const query = new URLSearchParams(location.search);
const redirectTo = query.get("return_to");
return (
<div className="bg-white px-8 py-10 md:py-32 lg:px-16 xl:px-28 h-screen">
<div className="mb-16">
<img src="/images/logo-black-text.svg" alt="Skynet" />
</div>
<LoginForm onSuccess={() => navigate(redirectTo || "/")} />
</div>
);
};
LoginPage.Layout = AuthLayout;
export default LoginPage;

View File

@ -0,0 +1,3 @@
import ky from "ky";
export default ky.create({ prefixUrl: "/api" });

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -0,0 +1,19 @@
<svg xmlns="http://www.w3.org/2000/svg" width="155" height="41" viewBox="0 0 155 41">
<defs>
<filter id="9uejgo84sa">
<feColorMatrix in="SourceGraphic" values="0 0 0 0 0.050980 0 0 0 0 0.050980 0 0 0 0 0.050980 0 0 0 1.000000 0"/>
</filter>
</defs>
<g fill="none" fill-rule="evenodd">
<g>
<g>
<path fill="#00C65E" d="M0 8.762L43.44 31.68c1.14.596 1.347 2.137.406 3.012h-.022c-1.365 1.235-2.89 2.28-4.536 3.106C25.25 44.845 8.84 34.069 9.75 18.402l5.809 4.007c1.738 9.146 11.411 14.423 20.054 10.941L0 8.762zm17.563 6.392l29.176 11.52c.846.332 1.303 1.25 1.056 2.124v.037c-.313 1.09-1.558 1.61-2.554 1.065L17.563 15.154zM28.306.065c5.502-.472 12.377 1.596 16.474 6.872 3.45 4.453 4.162 9.894 3.919 15.513v-.015c-.097 1.192-1.32 1.95-2.432 1.511l-19.832-7.83 18.411 4.933c.316-3.24-.446-6.494-2.168-9.258-6.029-9.672-20.279-9.2-25.65.853-.308.579-.578 1.177-.809 1.791l-4.937-2.628c.14-.207.287-.402.435-.601.236-.49.49-.988.771-1.475C15.762 4.07 21.242.736 27.021.201z" transform="translate(-247 -96) translate(247 96)"/>
<g filter="url(#9uejgo84sa)" transform="translate(-247 -96) translate(247 96)">
<g>
<path fill="#333" fill-rule="nonzero" d="M7.758 19.892c1.552 0 2.901-.25 4.048-.75 1.146-.499 2.03-1.2 2.65-2.105.62-.904.931-1.95.931-3.139 0-1.12-.28-2.075-.84-2.867-.56-.792-1.35-1.421-2.366-1.886-1.018-.465-2.199-.75-3.543-.852l-1.656-.155c-.93-.07-1.612-.323-2.043-.763-.43-.439-.646-.951-.646-1.537 0-.482.12-.93.362-1.343.241-.413.603-.74 1.086-.982.483-.24 1.086-.361 1.81-.361.759 0 1.384.133 1.875.4.492.267.862.62 1.112 1.06.25.438.375.916.375 1.433h3.595c0-1.223-.284-2.286-.853-3.19-.57-.905-1.371-1.606-2.405-2.106C10.215.25 8.982 0 7.55 0 6.172 0 4.97.237 3.944.71c-1.026.474-1.823 1.146-2.392 2.015-.57.87-.854 1.908-.854 3.113 0 1.602.539 2.89 1.617 3.862 1.077.973 2.521 1.538 4.331 1.693l1.655.129c1.19.103 2.07.357 2.638.762.57.404.854.943.854 1.614 0 .534-.147 1.012-.44 1.434-.293.422-.741.762-1.345 1.02-.603.259-1.353.388-2.25.388-1 0-1.806-.146-2.418-.44-.612-.292-1.056-.675-1.332-1.149-.275-.473-.413-.96-.413-1.46H0c0 1.189.302 2.252.905 3.191.604.939 1.479 1.675 2.625 2.209 1.147.534 2.556.8 4.228.8zm14.51-.491v-6.562h1.526l4.706 6.562h4.06l-5.913-8.047 4.776-5.98h-3.75l-5.405 6.755V.543h-3.595V19.4h3.595zm14.225 5.528c1.155 0 2.125-.138 2.91-.413.784-.276 1.426-.728 1.926-1.356.5-.629.888-1.46 1.164-2.493l4.164-15.294h-3.44L40.389 16.25h-.55L36.417 5.373h-3.621l4.552 13.718h2.302l-.208.8c-.108.435-.259.792-.451 1.072l-.066.091c-.224.293-.504.5-.84.62-.337.12-.755.181-1.255.181h-2.637v3.074h2.301zm16.45-5.528V11.16c0-.913.27-1.64.814-2.183.543-.542 1.254-.814 2.134-.814.862 0 1.538.267 2.03.801.491.534.737 1.232.737 2.093V19.4h3.594v-8.034c0-2.136-.43-3.742-1.293-4.818-.862-1.077-2.129-1.615-3.801-1.615h-.155c-1.121 0-2.056.241-2.806.723-.75.483-1.315 1.202-1.694 2.158-.106.265-.196.549-.272.85l-.039.16V5.373h-2.844v14.028h3.594zm19.655.49c1.156 0 2.186-.197 3.09-.593.906-.397 1.652-.956 2.238-1.68.586-.723.982-1.567 1.19-2.531h-3.31c-.156.516-.51.951-1.061 1.304-.552.353-1.267.53-2.147.53-.879 0-1.603-.194-2.172-.581-.569-.388-.991-.922-1.267-1.602-.17-.419-.287-.875-.353-1.368l-.014-.117h10.556V11.96c0-1.24-.259-2.398-.776-3.475-.517-1.076-1.288-1.946-2.314-2.609s-2.298-.994-3.815-.994c-1.155 0-2.172.202-3.051.607-.88.404-1.617.947-2.211 1.627-.595.68-1.044 1.455-1.345 2.325-.302.87-.453 1.77-.453 2.7v.49c0 .896.151 1.774.453 2.636.301.86.75 1.64 1.345 2.337.594.698 1.344 1.253 2.25 1.667.905.413 1.96.62 3.167.62zm3.316-8.834h-7.058l.028-.15c.059-.284.135-.55.229-.8l.059-.148c.284-.68.702-1.201 1.254-1.563.552-.362 1.224-.543 2.017-.543.793 0 1.453.173 1.979.517.525.344.918.835 1.176 1.473.13.318.227.669.291 1.052l.025.162zm14.763 8.525v-3.075h-2.198c-.69 0-1.22-.185-1.59-.555-.371-.37-.557-.9-.557-1.589l.013-6.355h4.332V5.373H86.35l.008-3.952h-3.362l-.008 3.952h-2.242v2.635h2.237l-.013 6.123c0 1.292.187 2.332.56 3.12l.061.122c.414.8 1.039 1.37 1.875 1.705.836.336 1.9.504 3.194.504h2.017z" transform="translate(64 11)"/>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@ -3373,6 +3373,11 @@
dependencies:
"@types/node" "*"
"@types/lodash@^4.14.175":
version "4.14.180"
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.180.tgz#4ab7c9ddfc92ec4a887886483bc14c79fb380670"
integrity sha512-XOKXa1KIxtNXgASAnwj7cnttJxS4fksBRywK/9LzRV5YxrF80BXZIGeQSuoESQ/VkUj30Ae0+YcuHc15wJCB2g==
"@types/lodash@^4.14.92":
version "4.14.178"
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.178.tgz#341f6d2247db528d4a13ddbb374bcdc80406f4f8"
@ -6366,6 +6371,11 @@ deep-object-diff@^1.1.0:
resolved "https://registry.yarnpkg.com/deep-object-diff/-/deep-object-diff-1.1.7.tgz#348b3246f426427dd633eaa50e1ed1fc2eafc7e4"
integrity sha512-QkgBca0mL08P6HiOjoqvmm6xOAl2W6CT2+34Ljhg0OeFan8cwlcdq8jrLKsBBuUFAZLsN5b6y491KdKEoSo9lg==
deepmerge@^2.1.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.2.1.tgz#5d3ff22a01c00f645405a2fbc17d0778a1801170"
integrity sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA==
deepmerge@^4.0.0, deepmerge@^4.2.2:
version "4.2.2"
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955"
@ -7951,6 +7961,19 @@ format@^0.2.0:
resolved "https://registry.yarnpkg.com/format/-/format-0.2.2.tgz#d6170107e9efdc4ed30c9dc39016df942b5cb58b"
integrity sha1-1hcBB+nv3E7TDJ3DkBbflCtctYs=
formik@^2.2.9:
version "2.2.9"
resolved "https://registry.yarnpkg.com/formik/-/formik-2.2.9.tgz#8594ba9c5e2e5cf1f42c5704128e119fc46232d0"
integrity sha512-LQLcISMmf1r5at4/gyJigGn0gOwFbeEAlji+N9InZF6LIMXnFNkO42sCI8Jt84YZggpD4cPWObAZaxpEFtSzNA==
dependencies:
deepmerge "^2.1.1"
hoist-non-react-statics "^3.3.0"
lodash "^4.17.21"
lodash-es "^4.17.21"
react-fast-compare "^2.0.1"
tiny-warning "^1.0.2"
tslib "^1.10.0"
forwarded@0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
@ -10357,6 +10380,11 @@ klona@^2.0.4:
resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.5.tgz#d166574d90076395d9963aa7a928fabb8d76afbc"
integrity sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==
ky@^0.30.0:
version "0.30.0"
resolved "https://registry.yarnpkg.com/ky/-/ky-0.30.0.tgz#a3d293e4f6c4604a9a4694eceb6ce30e73d27d64"
integrity sha512-X/u76z4JtDVq10u1JA5UQfatPxgPaVDMYTrgHyiTpGN2z4TMEJkIHsoSBBSg9SWZEIXTKsi9kHgiQ9o3Y/4yog==
language-subtag-registry@~0.3.2:
version "0.3.21"
resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz#04ac218bea46f04cb039084602c6da9e788dd45a"
@ -10510,6 +10538,11 @@ lock@^1.1.0:
resolved "https://registry.yarnpkg.com/lock/-/lock-1.1.0.tgz#53157499d1653b136ca66451071fca615703fa55"
integrity sha1-UxV0mdFlOxNspmRRBx/KYVcD+lU=
lodash-es@^4.17.21:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee"
integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==
lodash.clonedeep@4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
@ -11183,6 +11216,11 @@ nano-css@^5.3.1:
stacktrace-js "^2.0.2"
stylis "^4.0.6"
nanoclone@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/nanoclone/-/nanoclone-0.2.1.tgz#dd4090f8f1a110d26bb32c49ed2f5b9235209ed4"
integrity sha512-wynEP02LmIbLpcYw8uBKpcfF6dmg2vcpKqxeH5UcoKEYdExslsdUA4ugFauuaeYdTB76ez6gJW8XAZ6CgkXYxA==
nanoid@^3.1.23, nanoid@^3.2.0, nanoid@^3.3.1:
version "3.3.1"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.1.tgz#6347a18cac88af88f58af0b3594b723d5e99bb35"
@ -12647,6 +12685,11 @@ proper-lockfile@^4.1.2:
retry "^0.12.0"
signal-exit "^3.0.2"
property-expr@^2.0.4:
version "2.0.5"
resolved "https://registry.yarnpkg.com/property-expr/-/property-expr-2.0.5.tgz#278bdb15308ae16af3e3b9640024524f4dc02cb4"
integrity sha512-IJUkICM5dP5znhCckHSv30Q4b5/JA5enCtkRHYaOVOAocnH/1BQEYTC5NMfT3AVl/iXKdr3aqQbQn9DxyWknwA==
property-information@^5.0.0, property-information@^5.3.0:
version "5.6.0"
resolved "https://registry.yarnpkg.com/property-information/-/property-information-5.6.0.tgz#61675545fb23002f245c6540ec46077d4da3ed69"
@ -12942,6 +12985,11 @@ react-error-overlay@^6.0.9:
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.10.tgz#0fe26db4fa85d9dbb8624729580e90e7159a59a6"
integrity sha512-mKR90fX7Pm5seCOfz8q9F+66VCc1PGsWSBxKbITjfKVQHMNF2zudxHnMdJiB1fRCb+XsbQV9sO9DCkgsMQgBIA==
react-fast-compare@^2.0.1:
version "2.0.4"
resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-2.0.4.tgz#e84b4d455b0fec113e0402c329352715196f81f9"
integrity sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==
react-fast-compare@^3.0.1, react-fast-compare@^3.1.1, react-fast-compare@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb"
@ -14830,6 +14878,11 @@ timsort@^0.3.0:
resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4"
integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=
tiny-warning@^1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754"
integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==
tinycolor2@^1.4.1:
version "1.4.2"
resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.2.tgz#3f6a4d1071ad07676d7fa472e1fac40a719d8803"
@ -14929,6 +14982,11 @@ token-types@^4.1.1:
"@tokenizer/token" "^0.3.0"
ieee754 "^1.2.1"
toposort@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/toposort/-/toposort-2.0.2.tgz#ae21768175d1559d48bef35420b2f4962f09c330"
integrity sha1-riF2gXXRVZ1IvvNUILL0li8JwzA=
tr46@~0.0.3:
version "0.0.3"
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
@ -16036,6 +16094,19 @@ yoga-layout-prebuilt@^1.10.0:
dependencies:
"@types/yoga-layout" "1.9.2"
yup@^0.32.11:
version "0.32.11"
resolved "https://registry.yarnpkg.com/yup/-/yup-0.32.11.tgz#d67fb83eefa4698607982e63f7ca4c5ed3cf18c5"
integrity sha512-Z2Fe1bn+eLstG8DRR6FTavGD+MeAwyfmouhHsIUgaADz8jvFKbO/fXc2trJKZg+5EBjh4gGm3iU/t3onKlXHIg==
dependencies:
"@babel/runtime" "^7.15.4"
"@types/lodash" "^4.14.175"
lodash "^4.17.21"
lodash-es "^4.17.21"
nanoclone "^0.2.1"
property-expr "^2.0.4"
toposort "^2.0.2"
yurnalist@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/yurnalist/-/yurnalist-2.1.0.tgz#44cf7ea5a33a8fab4968cc8c2970489f93760902"