merchant-backoffice

ZZZ: Inactive/Deprecated
Log | Files | Refs | Submodules | README

commit d37369bbdeb9ff471cee42e794076a3d7d7eda45
parent 5002a444a7d207295457cf6c21e5192c5c49c59c
Author: Sebastian <sebasjm@gmail.com>
Date:   Wed, 17 Feb 2021 10:25:09 -0300

several changes detailed in TODO file, 50% of tasks done. ref #5859

Diffstat:
ATODO | 32++++++++++++++++++++++++++++++++
Mpackage.json | 1+
Mpreact.config.js | 12++++++------
Asrc/assets/logo.jpeg | 0
Msrc/components/auth/LoginPage.tsx | 42+++++++++++++++++++++++++++++++++---------
Msrc/components/hooks/backend.ts | 59+++++++++++++++++++++++++++--------------------------------
Asrc/components/hooks/useBackend.ts | 23+++++++++++++++++++++++
Asrc/components/hooks/useLang.ts | 6++++++
Asrc/components/hooks/useLocalStorage.ts | 37+++++++++++++++++++++++++++++++++++++
Msrc/components/navbar/index.tsx | 63++++++++++++++++++++++++++++++++++++++++++++-------------------
Msrc/components/notifications/index.tsx | 1-
Asrc/components/yup/YupField.tsx | 178+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/components/yup/YupInput.tsx | 40----------------------------------------
Msrc/declaration.d.ts | 29+++++++++++++++++++++++++----
Msrc/hooks/notifications.ts | 2+-
Msrc/i18n/index.ts | 81++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Msrc/routes/index.tsx | 10+++++-----
Dsrc/routes/instanceDetail/index.tsx | 7-------
Msrc/routes/instances/CardTable.tsx | 2+-
Asrc/routes/instances/Create.stories.tsx | 16++++++++++++++++
Asrc/routes/instances/Create.tsx | 91+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/routes/instances/CreateModal.stories.tsx | 16----------------
Dsrc/routes/instances/CreateModal.tsx | 41-----------------------------------------
Asrc/routes/instances/Update.tsx | 91+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/routes/instances/UpdateModal.tsx | 18++++--------------
Msrc/routes/instances/View.tsx | 27+++++++--------------------
Msrc/routes/instances/index.tsx | 59++++++++++++++++++++++++++++++++++++++++++++---------------
Msrc/schemas/index.ts | 82+++++++++++++++++++++++++++++++++++++++++--------------------------------------
Msrc/scss/main.scss | 2++
Dtemplate.env | 1-
Mtests/hooks/notification.test.ts | 3+--
Myarn.lock | 485++++---------------------------------------------------------------------------
32 files changed, 819 insertions(+), 738 deletions(-)

diff --git a/TODO b/TODO @@ -0,0 +1,32 @@ +TODO + +Already done: + * take the url where the spa was loaded as a default backend url + * let the user change the backend url when ask for the auth token + * button of the form to the right + * refactor the popup to be a page + * add supported currency for Amount fields (like taler bank) + * rename name to business name + * change auth field to have a checkbox that activate the validation and show an input to set the token + * rename PayTo URI to bank account + * change id input to reflect that is going to be use in the url (prepend the backend url as a non editable and put the input after) + * refactor create page + * add the information popup into the fields to help with the description (like https://b2b.dab-bank.de/smartbroker/) + * take default lang from the browser for localization + * take the currency from merchant-backend + +Next to do: + * implement proper error handling + * change the input PayTO URI to a string field with a + button to add more + * refactor update page + +Queue: + * replace Yup and type definition with a taler-library for the purpose (first wait Florian to refactor wallet core) + * replace default exports for named exports + * implement pnpm + * add copyright headers to every source file + * add more doc style comments + * check the field names in forms dont break spaces + * add default values to some fields: default_max_deposit_fee, default_max_wire_fee, default_wire_fee_amortization, default_pay_delay, default_wire_transfer_delay + * Login button should be centered + * update spanish lang diff --git a/package.json b/package.json @@ -37,6 +37,7 @@ "devDependencies": { "@babel/core": "^7.12.13", "@babel/plugin-transform-react-jsx-source": "^7.12.13", + "@creativebulma/bulma-tooltip": "^1.2.0", "@storybook/addon-a11y": "^6.1.17", "@storybook/addon-actions": "^6.1.16", "@storybook/addon-essentials": "^6.1.16", diff --git a/preact.config.js b/preact.config.js @@ -1,14 +1,14 @@ -import { DefinePlugin } from 'webpack'; +// import { DefinePlugin } from 'webpack'; import { config } from 'dotenv'; const { parsed } = config(); export default { webpack(config, env, helpers, options) { config.node.process = 'mock' - config.plugins.push( - new DefinePlugin({ - 'process.env.BACKEND_ENDPOINT': JSON.stringify(parsed['BACKEND_ENDPOINT']), - }), - ); + // config.plugins.push( + // new DefinePlugin({ + // // 'process.env.BACKEND_ENDPOINT': JSON.stringify(parsed['BACKEND_ENDPOINT']), + // }), + // ); } } diff --git a/src/assets/logo.jpeg b/src/assets/logo.jpeg Binary files differ. diff --git a/src/components/auth/LoginPage.tsx b/src/components/auth/LoginPage.tsx @@ -1,13 +1,17 @@ import { h, VNode } from "preact"; import { useState } from "preact/hooks"; +import useBackend from "../hooks/useBackend"; interface Props { - onLogIn: (token: string) => void; + onConfirm?: () => void; } -export default function LoginPage({ onLogIn }: Props): VNode { - const [token, update] = useState('') - +export default function LoginPage({ onConfirm }: Props): VNode { + const [backend, setBackend] = useBackend() + const [url, setUrl] = useState(backend.url) + const [token, setToken] = useState(backend.token) + const [changeToken, setChangeToken] = useState(false) + return <div class="modal is-active is-clipped"> <div class="modal-background" /> <div class="modal-card"> @@ -15,22 +19,42 @@ export default function LoginPage({ onLogIn }: Props): VNode { <p class="modal-card-title">Authentication required</p> </header> <section class="modal-card-body"> - Please enter your auth id, it sould start with "secret-token:" + Please enter your auth token. Token should have "secret-token:" and start with Bearer or ApiKey + <div class="field is-horizontal"> + <div class="field-label is-normal"> + <label class="label">Change Token</label> + </div> + <div class="field-body"> + <div class="field has-addons"> + <label class="b-checkbox checkbox"> + <input type="checkbox" checked={changeToken} onClick={(): void => setChangeToken(!changeToken)} /> + <span class="check" /> + </label> + + <p class="control is-expanded"> + <input class="input" type="text" placeholder={changeToken ? "set new token" : "hidden token value"} disabled={!changeToken} name="id" value={token} onInput={(e): void => setToken(e?.currentTarget.value)} /> + </p> + </div> + </div> + </div> <div class="field is-horizontal"> <div class="field-label is-normal"> - <label class="label">Id</label> + <label class="label">URL</label> </div> <div class="field-body"> <div class="field"> - <p class="control is-expanded has-icons-left"> - <input class="input" type="text" placeholder="abcdef" name="id" value={token} onInput={(e): void => update(e?.currentTarget.value)} /> + <p class="control is-expanded"> + <input class="input" type="text" placeholder="set new url" name="id" value={url} onInput={(e): void => setUrl(e?.currentTarget.value)} /> </p> </div> </div> </div> </section> <footer class="modal-card-foot"> - <button class="button is-info" onClick={(): void => onLogIn(token)} >Confirm</button> + <button class="button is-info" onClick={(): void => { + setBackend({token, url}); + onConfirm && onConfirm(); + }} >Confirm</button> </footer> </div> </div> diff --git a/src/components/hooks/backend.ts b/src/components/hooks/backend.ts @@ -1,4 +1,4 @@ -import useSWR, { mutate as globalMutate } from 'swr'; +import useSWR, { mutate } from 'swr'; import axios from 'axios' import { MerchantBackend } from '../../declaration'; @@ -13,29 +13,27 @@ interface HttpResponseError<T> { error: Error; } -const BACKEND = process.env.BACKEND_ENDPOINT -const TOKEN_KEY = 'backend-token' type Methods = 'get' | 'post' | 'patch' | 'delete' | 'put'; async function request(url: string, method?: Methods, data?: object): Promise<any> { - const token = localStorage.getItem(TOKEN_KEY) - const headers = token ? { Authorization: `Bearer ${token}` } : undefined + const backend = localStorage.getItem('backend-url') + const token = localStorage.getItem('backend-token') + const headers = token ? { Authorization: `${token}` } : undefined try { const res = await axios({ method: method || 'get', - url: `${BACKEND}/private${url}`, + url: `${backend}${url}`, responseType: 'json', headers, data }) return res.data } catch (e) { - const error = new Error('An error occurred while fetching the data.') - const info = e.response.data - const status = e.response.status - throw { info, status, ...error } + const info = e.response?.data + const status = e.response?.status + throw { info, status, error:e, backend, hasToken: !!token } } } @@ -44,15 +42,6 @@ async function fetcher(url: string): Promise<any> { return request(url, 'get') } -export function updateToken(token: string | null): void { - if (token) { - localStorage.setItem(TOKEN_KEY, token) - } else { - localStorage.removeItem(TOKEN_KEY) - } - globalMutate('/instances', null) -} - interface WithCreate<T> { create: (data: T) => Promise<void>; } @@ -64,32 +53,38 @@ interface WithDelete { } export function useBackendInstances(): HttpResponse<MerchantBackend.Instances.InstancesResponse> & WithCreate<MerchantBackend.Instances.InstanceConfigurationMessage> { - const { data, error, mutate } = useSWR<MerchantBackend.Instances.InstancesResponse>('/instances', fetcher) + const { data, error } = useSWR<MerchantBackend.Instances.InstancesResponse>('/private/instances', fetcher) - const create = async (instance: MerchantBackend.Instances.InstanceConfigurationMessage) => { - await request('/instances', 'post', instance) + const create = async (instance: MerchantBackend.Instances.InstanceConfigurationMessage): Promise<void> => { + await request('/private/instances', 'post', instance) - globalMutate('/instances') + mutate('/private/instances') } return { data, needsAuth: error?.status === 401, error, create } } export function useBackendInstance(id: string | null): HttpResponse<MerchantBackend.Instances.QueryInstancesResponse> & WithUpdate<MerchantBackend.Instances.InstanceReconfigurationMessage> & WithDelete { - const { data, error } = useSWR<MerchantBackend.Instances.QueryInstancesResponse>(id ? `/instances/${id}` : null, fetcher) + const { data, error } = useSWR<MerchantBackend.Instances.QueryInstancesResponse>(id ? `/private/instances/${id}` : null, fetcher) - const update = async (updateId: string, instance: MerchantBackend.Instances.InstanceReconfigurationMessage) => { - await request(`/instances/${updateId}`, 'patch', instance) + const update = async (updateId: string, instance: MerchantBackend.Instances.InstanceReconfigurationMessage): Promise<void> => { + await request(`/private/instances/${updateId}`, 'patch', instance) - globalMutate('/instances', null) - globalMutate(`/instances/${updateId}`, null) + mutate('/private/instances', null) + mutate(`/private/instances/${updateId}`, null) }; - const _delete = async (deleteId: string) => { - await request(`/instances/${deleteId}`, 'delete') + const _delete = async (deleteId: string): Promise<void> => { + await request(`/private/instances/${deleteId}`, 'delete') - globalMutate('/instances', null) - globalMutate(`/instances/${deleteId}`, null) + mutate('/private/instances', null) + mutate(`/private/instances/${deleteId}`, null) } return { data, needsAuth: error?.status === 401, error, update, delete: _delete } } + +export function useBackendConfig(): HttpResponse<MerchantBackend.VersionResponse> { + const { data, error } = useSWR<MerchantBackend.VersionResponse>(`/config`, fetcher) + + return { data, needsAuth: error?.status === 401, error } +} diff --git a/src/components/hooks/useBackend.ts b/src/components/hooks/useBackend.ts @@ -0,0 +1,23 @@ +import { StateUpdater } from "preact/hooks"; +import {useLocalStorage} from "./useLocalStorage"; +import { mutate } from 'swr'; + +interface State { + token?: string; + url: string; +} + +export default function useBackend(): [State, StateUpdater<State>] { + const [url, setUrl] = useLocalStorage('backend-url', window.location.origin) + const [token, setToken] = useLocalStorage('backend-token') + + const updater: StateUpdater<State> = (value:State | ((value: State) => State)) => { + const valueToStore = value instanceof Function ? value({token, url: url || window.location.origin}) : value; + setUrl(valueToStore.url) + setToken(valueToStore.token) + + mutate('/private/instances', null) + } + + return [{token, url: url || window.location.origin}, updater] +} diff --git a/src/components/hooks/useLang.ts b/src/components/hooks/useLang.ts @@ -0,0 +1,6 @@ +import { StateUpdater } from "preact/hooks"; +import { useNotNullLocalStorage } from "./useLocalStorage"; + +export default function useLang(): [string, StateUpdater<string>] { + return useNotNullLocalStorage('lang-preference', navigator.language || (navigator as any).userLanguage ) +} diff --git a/src/components/hooks/useLocalStorage.ts b/src/components/hooks/useLocalStorage.ts @@ -0,0 +1,37 @@ +import { StateUpdater, useState } from "preact/hooks"; + +export function useLocalStorage(key: string, initialValue?: string): [string | undefined, StateUpdater<string | undefined>] { + const [storedValue, setStoredValue] = useState<string | undefined>((): string | undefined => { + return window.localStorage.getItem(key) || initialValue; + }); + + const setValue = (value?: string | ((val?: string) => string | undefined)) => { + const valueToStore = value instanceof Function ? value(storedValue) : value; + setStoredValue(valueToStore); + if (!valueToStore) { + window.localStorage.removeItem(key) + } else { + window.localStorage.setItem(key, valueToStore); + } + }; + + return [storedValue, setValue]; +} + +export function useNotNullLocalStorage(key: string, initialValue: string): [string, StateUpdater<string>] { + const [storedValue, setStoredValue] = useState<string>((): string => { + return window.localStorage.getItem(key) || initialValue; + }); + + const setValue = (value: string | ((val: string) => string)) => { + const valueToStore = value instanceof Function ? value(storedValue) : value; + setStoredValue(valueToStore); + if (!valueToStore) { + window.localStorage.removeItem(key) + } else { + window.localStorage.setItem(key, valueToStore); + } + }; + + return [storedValue, setValue]; +} diff --git a/src/components/navbar/index.tsx b/src/components/navbar/index.tsx @@ -1,25 +1,50 @@ import { h, VNode } from 'preact'; -import { updateToken } from '../hooks/backend'; +import { useState } from 'preact/hooks'; +import LoginPage from '../auth/LoginPage'; +import i18n from '../../i18n' +import logo from '../../assets/logo.jpeg' -export default function NavigationBar(): VNode { - return ( - <nav id="navbar-main" class="navbar is-fixed-top"> - <div class="navbar-brand"> - <a class="navbar-item is-hidden-desktop jb-aside-mobile-toggle"> - <span class="icon"><i class="mdi mdi-forwardburger mdi-24px" /></span> - </a> - <div class="navbar-item has-control"> - {/* <div class="control"><input placeholder="Search everywhere..." class="input" /></div> */} +interface Props { + lang: string; + setLang: (l: string) => void; +} + +export default function NavigationBar({ lang, setLang }: Props): VNode { + const [showLogin, setShowLogin] = useState(false) + return (<nav class="navbar is-fixed-top" role="navigation" aria-label="main navigation"> + <div class="navbar-brand"> + <a class="navbar-item" href="https://taler.net"> + <img src={logo} style={{height: 50, maxHeight: 50}} /> + </a> + + <a role="button" class="navbar-burger" aria-label="menu" aria-expanded="false" data-target="navbarBasicExample"> + <span aria-hidden="true" /> + <span aria-hidden="true" /> + <span aria-hidden="true" /> + </a> + </div> + + <div class="navbar-menu"> + + <div class="navbar-end"> + <div class="navbar-item"> + <div class="control has-icons-left"> + <div class="select"> + <select onChange={(e): void => setLang(e.currentTarget.value)}> + {Object.keys(i18n).map(l => <option selected={lang === l} value={l}>{l}</option>)} + </select> + </div> + <div class="icon is-small is-left"> + <i class="mdi mdi-web" /> + </div> + </div> + </div> + <div class="navbar-item"> + <button class="button is-primary" onClick={(): void => setShowLogin(true)}>Change access</button> </div> </div> - <div class="navbar-brand is-right"> - <a class="navbar-item is-hidden-desktop jb-navbar-menu-toggle"> - <span class="icon"><i class="mdi mdi-dots-vertical" /></span> - </a> - </div> - <div class="navbar-menu navbar-end"> - <button class="button is-primary" onClick={ () => updateToken(null) }>Log out</button> - </div> - </nav> + </div> + {showLogin && <LoginPage onConfirm={(): void => setShowLogin(false)} />} + </nav> ); } \ No newline at end of file diff --git a/src/components/notifications/index.tsx b/src/components/notifications/index.tsx @@ -21,7 +21,6 @@ export default function Notifications({ notifications }: Props): VNode { {notifications.map(n => <article class={messageStyle(n.type)}> <div class="message-header"> <p><Text id={`notification.${n.messageId}.title`} /> </p> - <button class="delete" aria-label="delete" /> </div> <div class="message-body"> <Text id={`notification.${n.messageId}.description`} fields={n.params} /> diff --git a/src/components/yup/YupField.tsx b/src/components/yup/YupField.tsx @@ -0,0 +1,178 @@ +import { h, VNode } from "preact"; +import { Localizer, Text, useText } from "preact-i18n"; +import { useState } from "preact/hooks"; +import { KeyValue } from "../../declaration"; +import { useBackendConfig } from "../hooks/backend"; +import useBackend from "../hooks/useBackend"; + +interface Props { + name: string; + value: string; + readonly?: boolean; + errors: any; + onChange: any; +} + +interface Props2 { + name: string; + info: any; + value: any; + errors: any; + onChange: any; +} + + +export default function YupField(name: string, field: string, errors: any, object: any, valueHandler: any, info: any): VNode { + const updateField = (f: string) => (v: string): void => valueHandler((prev: any) => ({ ...prev, [f]: v })) + const values = { + name, errors, + readonly: info?.meta?.readonly, + value: object && object[field], + onChange: updateField(field) + } + const [backend] = useBackend() + const {data} = useBackendConfig() + + switch (info.meta?.type) { + case 'group': return <YupObjectInput name={name} + info={info} errors={errors} + value={object && object[field]} + onChange={(updater: any): void => valueHandler((prev: any) => ({ ...prev, [field]: updater(prev[field]) }))} + /> + case 'amount': return <YupInputWithAddon {...values} addon={data?.currency || ''} />; + case 'url': return <YupInputWithAddon {...values} addon={`${backend.url}/private/instances/`} />; + case 'secured': return <YupInputSecured {...values} />; + case 'duration': return <YupInput {...values} value={object && object[field]?.d_ms} />; + default: return <YupInput {...values} />; + + } +} + +function YupObjectInput({ name, info, value, errors, onChange }: Props2): VNode { + const [active, setActive] = useState(false) + return <div class="card"> + <header class="card-header"> + <p class="card-header-title"> + <Text id={`fields.instance.${name}.label`} /> + </p> + <button class="card-header-icon" aria-label="more options" onClick={(): void => setActive(!active)}> + <span class="icon"> + { active ? + <i class="mdi mdi-arrow-up" /> : + <i class="mdi mdi-arrow-down" /> } + </span> + </button> + </header> + <div class={active ? "card-content" : "is-hidden"}> + <div class="content"> + {Object.keys(info.fields).map(f => YupField(`${name}.${f}`, f, errors, value, onChange, info.fields[f]))} + </div> + </div> + </div> +} + +function YupInput({ name, readonly, value, errors, onChange }: Props): VNode { + const dict = useText({ + placeholder: `fields.instance.${name}.placeholder`, + tooltip: `fields.instance.${name}.tooltip`, + }) + + return <div class="field is-horizontal"> + <div class="field-label is-normal"> + <label class="label"> + <Text id={`fields.instance.${name}.label`} /> + {dict.tooltip && <span class="icon" data-tooltip={dict.tooltip}> + <i class="mdi mdi-information" /> + </span>} + </label> + </div> + <div class="field-body"> + <div class="field"> + <p class="control"> + <input class={errors[name] ? "input is-danger" : "input"} type="text" + placeholder={dict['placeholder']} readonly={readonly} + name={name} value={value} + onChange={(e): void => onChange(e.currentTarget.value)} /> + <Text id={`fields.instance.${name}.help`} /> + </p> + {errors[name] ? <p class="help is-danger"> + <Text id={`validation.${errors[name].type}`} fields={errors[name].params}>{errors[name].message}</Text> + </p> : null} + </div> + </div> + </div> +} + +function YupInputWithAddon({ name, readonly, value, errors, onChange, addon }: Props & { addon: string }): VNode { + const dict = useText({ + placeholder: `fields.instance.${name}.placeholder`, + tooltip: `fields.instance.${name}.tooltip`, + }) + + return <div class="field is-horizontal"> + <div class="field-label is-normal"> + <label class="label"> + <Text id={`fields.instance.${name}.label`} /> + {dict.tooltip && <span class="icon" data-tooltip={dict.tooltip}> + <i class="mdi mdi-information" /> + </span>} + </label> + </div> + <div class="field-body"> + <div class="field"> + <div class="field has-addons"> + <div class="control"> + <a class="button is-static">{addon}</a> + </div> + <p class="control is-expanded"> + <input class={errors[name] ? "input is-danger" : "input"} type="text" + placeholder={dict['placeholder']} readonly={readonly} + name={name} value={value} + onChange={(e): void => onChange(e.currentTarget.value)} /> + <Text id={`fields.instance.${name}.help`} /> + </p> + </div> + {errors[name] ? <p class="help is-danger"><Text id={`validation.${errors[name].type}`} fields={errors[name].params}>{errors[name].message}</Text></p> : null} + </div> + </div> + </div> +} + +function YupInputSecured({ name, readonly, value, errors, onChange }: Props): VNode { + const dict = useText({ + placeholder: `fields.instance.${name}.placeholder`, + tooltip: `fields.instance.${name}.tooltip`, + }) + + const [active, setActive] = useState(false) + + return <div class="field is-horizontal"> + <div class="field-label is-normal"> + <label class="label"> + <Text id={`fields.instance.${name}.label`} /> + {dict.tooltip && <span class="icon" data-tooltip={dict.tooltip}> + <i class="mdi mdi-information" /> + </span>} + </label> + </div> + <div class="field-body"> + <div class="field"> + <div class="field has-addons"> + <label class="b-checkbox checkbox"> + <input type="checkbox" checked={active} onClick={(): void => { onChange(''); setActive(!active) }} /> + <span class="check" /> + </label> + <p class="control"> + <input class="input" type="text" + placeholder={dict.placeholder} readonly={readonly || !active} + disabled={readonly || !active} + name={name} value={value} + onChange={(e): void => onChange(e.currentTarget.value)} /> + <Text id={`fields.instance.${name}.help`} /> + </p> + </div> + {errors[name] ? <p class="help is-danger"><Text id={`validation.${errors[name].type}`} fields={errors[name].params}>{errors[name].message}</Text></p> : null} + </div> + </div> + </div> +} diff --git a/src/components/yup/YupInput.tsx b/src/components/yup/YupInput.tsx @@ -1,40 +0,0 @@ -import { h, VNode } from "preact"; -import { Text, useText } from "preact-i18n"; - -interface Props { - name: string; - object: any; - info: any; - errors: any; - valueHandler: any; -} - -function convert(object: any, name: string, type?: string): any { - switch (type) { - case 'duration': return object[name]?.d_ms; - default: return object[name]; - } -} - -export default function YupInput({ name, info, object, errors, valueHandler }: Props): VNode { - const dict = useText({ placeholder: `fields.instance.${name}.placeholder` }) - const value = convert(object, name, info.meta?.type) - - return <div class="field is-horizontal"> - <div class="field-label is-normal"> - <label class="label"><Text id={`fields.instance.${name}.label`} /></label> - </div> - <div class="field-body"> - <div class="field"> - <p class="control is-expanded has-icons-left"> - <input class="input" type="text" - placeholder={dict['placeholder']} readonly={info?.meta?.readonly} - name={name} value={value} - onChange={(e): void => valueHandler((prev: any) => ({ ...prev, [name]: e.currentTarget.value }))} /> - <Text id={`fields.instance.${name}.help`} /> - </p> - {errors[name] ? <p class="help is-danger"><Text id={`validation.${errors[name].type}`} fields={errors[name].params}>{errors[name].message}</Text></p> : null} - </div> - </div> - </div> -} diff --git a/src/declaration.d.ts b/src/declaration.d.ts @@ -4,19 +4,27 @@ declare module "*.css" { const mapping: Record<string, string>; export default mapping; } +declare module "*.jpeg" { + const mapping: Record<string, string>; + export default mapping; +} declare module "*.scss" { const mapping: Record<string, string>; export default mapping; } +interface KeyValue { + [key: string]: string; +} + interface Notification { messageId: string; type: MessageType; params?: any; - } - - type MessageType = 'INFO' | 'WARN' | 'ERROR' | 'SUCCESS' - +} + +type MessageType = 'INFO' | 'WARN' | 'ERROR' | 'SUCCESS' + type EddsaPublicKey = string; type RelativeTime = Duration; interface Timestamp { @@ -50,6 +58,19 @@ export namespace MerchantBackend { tax: Amount; } + interface VersionResponse { + // libtool-style representation of the Merchant protocol version, see + // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning + // The format is "current:revision:age". + version: string; + + // Name of the protocol. + name: "taler-merchant"; + + // Currency supported by this backend. + currency: string; + + } interface Location { // Nation with its own government. country?: string; diff --git a/src/hooks/notifications.ts b/src/hooks/notifications.ts @@ -6,7 +6,7 @@ interface Result { pushNotification: (n: Notification) => void; } -export function useNotifications(timeout = 2000): Result { +export function useNotifications(timeout = 3000): Result { const [notifications, setNotifications] = useState<(Notification & { since: Date })[]>([]) const pushNotification = (n: Notification): void => { const entry = { ...n, since: new Date() } diff --git a/src/i18n/index.ts b/src/i18n/index.ts @@ -55,7 +55,7 @@ export default { payto_uris: { label: 'PaytTO URI', placeholder: 'valores separados por coma', - help: 'payto://x-taler-bank/bank.taler:5882/blogger', + help: 'example: payto://<authority>/<path>/<name>', }, default_max_deposit_fee: { label: 'Máximo pago por depósito', @@ -100,6 +100,10 @@ export default { title: 'unauthorized access', description: 'backend has denied access' }, + error: { + title: 'Error query the backend', + description: 'Got message: "{{error.message}}" from: {{backend}} (hasToken: {{hasToken}})' + }, create_error: { title: 'create error', description: 'the create process went wrong, server says: {{info.hint}}' @@ -132,6 +136,9 @@ export default { id: { label: 'Id', }, + auth_token: { + label: 'Auth Token', + }, merchant_pub: { label: 'Public Key' }, @@ -139,10 +146,11 @@ export default { label: 'Payment targets', }, name: { - label: 'Name', + label: 'Business Name', + tooltip: 'the name of the merchant instance' }, payto_uris: { - label: 'PaytTO URI', + label: 'Bank accounts', placeholder: 'comma separated values', help: 'payto://x-taler-bank/bank.taler:5882/blogger', }, @@ -161,6 +169,72 @@ export default { default_wire_transfer_delay: { label: 'Wire transfer delay' }, + address: { + label: 'Address', + country: { + label: 'Country', + }, + country_subdivision: { + label: 'Country subdivision', + }, + town: { + label: 'Town', + }, + district: { + label: 'District', + }, + town_location: { + label: 'Town Location', + }, + post_code: { + label: 'Post code', + }, + street: { + label: 'Street', + }, + building_name: { + label: 'Building name', + }, + building_number: { + label: 'Building number', + }, + address_lines: { + label: 'Address lines', + } + }, + jurisdiction: { + label: 'Jurisdiction', + country: { + label: 'Country', + }, + country_subdivision: { + label: 'Country subdivision', + }, + town: { + label: 'Town', + }, + district: { + label: 'District', + }, + town_location: { + label: 'Town Location', + }, + post_code: { + label: 'Post code', + }, + street: { + label: 'Street', + }, + building_name: { + label: 'Building name', + }, + building_number: { + label: 'Building number', + }, + address_lines: { + label: 'Address lines', + } + } } }, validation: { @@ -172,6 +246,7 @@ export default { instances: 'Instances', merchant: 'Merchant', list_of_configured_instances: 'List of configured instances', + create_new_instance: 'Create new instance', instance: { empty_list: 'No instance configured yet, setup one pressing the + button', diff --git a/src/routes/index.tsx b/src/routes/index.tsx @@ -7,23 +7,23 @@ import Instances from './instances'; import Footer from '../components/footer'; import Sidebar from '../components/sidebar'; import NavigationBar from '../components/navbar'; -import InstanceDetail from './instanceDetail'; import Notifications from '../components/notifications'; import { useNotifications } from '../hooks/notifications'; -import lang from '../i18n'; +import i18n from '../i18n'; +import useLang from '../components/hooks/useLang'; export default function PageRouter(): VNode { const { notifications, pushNotification } = useNotifications() + const [lang, setLang] = useLang() return ( - <IntlProvider definition={lang.en}> + <IntlProvider definition={(i18n as any)[lang] || i18n.en }> <div id="app"> - <NavigationBar /> + <NavigationBar lang={lang} setLang={setLang} /> <Sidebar /> <Notifications notifications={notifications} /> <Router> <Route path="/" component={Instances} pushNotification={pushNotification} /> - <Route path="/i/:instance" component={InstanceDetail} /> <NotFoundPage default /> </Router> <Footer /> diff --git a/src/routes/instanceDetail/index.tsx b/src/routes/instanceDetail/index.tsx @@ -1,6 +0,0 @@ -import { h, VNode } from 'preact'; - - -export default function InstanceDetail({ instance }: any): VNode { - return <div>hola {instance}</div> -} -\ No newline at end of file diff --git a/src/routes/instances/CardTable.tsx b/src/routes/instances/CardTable.tsx @@ -50,7 +50,7 @@ export default function CardTable({ instances, onCreate, onSelect, selected }: P <header class="card-header"> <p class="card-header-title"><span class="icon"><i class="mdi mdi-account-multiple" /></span><Text id="text.instances" /></p> - <button class={rowSelection.length > 0 ? "card-header-icon" : "card-header-icon is-hidden"} + <button class={rowSelection.length > 0 ? "card-header-icon" : "is-hidden"} type="button" onClick={(): void => actionQueueHandler(buildActions(instances, rowSelection, 'DELETE'))} > <span class="icon"><i class="mdi mdi-trash-can" /></span> diff --git a/src/routes/instances/Create.stories.tsx b/src/routes/instances/Create.stories.tsx @@ -0,0 +1,16 @@ +/* eslint-disable @typescript-eslint/camelcase */ +import { h, VNode } from 'preact'; +import Create from './Create' + + +export default { + title: 'Instances/CreateModal', + component: Create, + argTypes: { + element: { control: 'object' }, + onCancel: { action: 'onCancel' }, + onConfirm: { action: 'onConfirm' }, + } +}; + +export const Example = (a: any): VNode => <Create {...a} />; diff --git a/src/routes/instances/Create.tsx b/src/routes/instances/Create.tsx @@ -0,0 +1,90 @@ +import { h, VNode } from "preact"; +import { useState } from "preact/hooks"; +import { MerchantBackend } from "../../declaration"; +import * as yup from 'yup'; +import YupField from "../../components/yup/YupField" +import { InstanceCreateSchema as schema } from '../../schemas' +import { Text } from "preact-i18n"; + +interface Props { + onCreate: (d: MerchantBackend.Instances.InstanceConfigurationMessage) => void; + isLoading: boolean; + goBack: () => void; +} + +interface KeyValue { + [key: string]: string; +} + +function with_defaults(): Partial<MerchantBackend.Instances.InstanceConfigurationMessage> { + return { + default_pay_delay: { d_ms: 1000 }, + default_wire_fee_amortization: 10, + default_wire_transfer_delay: { d_ms: 2000 }, + }; +} + +export default function CreateModal({ onCreate, isLoading, goBack }: Props): VNode { + const [value, valueHandler] = useState(with_defaults()) + const [errors, setErrors] = useState<KeyValue>({}) + + const submit = (): void => { + try { + schema.validateSync(value, { abortEarly: false }) + onCreate(schema.cast(value) as MerchantBackend.Instances.InstanceConfigurationMessage); + goBack() + } catch (err) { + const errors = err.inner as yup.ValidationError[] + const pathMessages = errors.reduce((prev, cur) => !cur.path ? prev : ({ ...prev, [cur.path]: { type: cur.type, params: cur.params, message: cur.message } }), {}) + setErrors(pathMessages) + } + } + + return <div> + <section class="section is-title-bar"> + + <div class="level"> + <div class="level-left"> + <div class="level-item"> + <ul> + <li><Text id="text.merchant" /></li> + <li><Text id="text.instances" /></li> + </ul> + </div> + </div> + </div> + </section> + + <section class={isLoading ? "hero is-hero-bar" : "hero is-hero-bar is-loading"}> + <div class="hero-body"> + <div class="level"> + <div class="level-left"> + <div class="level-item"> + <h1 class="title"> + <Text id="text.create_new_instances" /> + </h1> + </div> + </div> + <div class="level-right" style="display: none;"> + <div class="level-item" /> + </div> + </div> + </div> + </section> + + <section class="section is-main-section"> + <div class="columns"> + <div class="column" /> + <div class="column is-two-thirds"> + {Object.keys(schema.fields).map(f => YupField(f, f, errors, value, valueHandler, schema.fields[f].describe()))} + <div class="buttons is-right"> + <button class="button" onClick={goBack} ><Text id="cancel" /></button> + <button class="button is-success" onClick={submit} ><Text id="confirm" /></button> + </div> + </div> + <div class="column" /> + </div> + </section> + + </div> +} +\ No newline at end of file diff --git a/src/routes/instances/CreateModal.stories.tsx b/src/routes/instances/CreateModal.stories.tsx @@ -1,16 +0,0 @@ -/* eslint-disable @typescript-eslint/camelcase */ -import { h, VNode } from 'preact'; -import CreateModal from './CreateModal' - - -export default { - title: 'Instances/CreateModal', - component: CreateModal, - argTypes: { - element: { control: 'object' }, - onCancel: { action: 'onCancel' }, - onConfirm: { action: 'onConfirm' }, - } -}; - -export const Example = (a: any): VNode => <CreateModal {...a} />; diff --git a/src/routes/instances/CreateModal.tsx b/src/routes/instances/CreateModal.tsx @@ -1,40 +0,0 @@ -import { h, VNode } from "preact"; -import { useState } from "preact/hooks"; -import { MerchantBackend } from "../../declaration"; -import * as yup from 'yup'; -import ConfirmModal from "../../components/modal"; -import YupInput from "../../components/yup/YupInput" -import { InstanceCreateSchema as schema } from '../../schemas' - -interface Props { - onCancel: () => void; - onConfirm: (i: MerchantBackend.Instances.InstanceConfigurationMessage) => void; -} - -interface KeyValue { - [key: string]: string; -} - -export default function CreateModal({ onCancel, onConfirm }: Props): VNode { - const [value, valueHandler] = useState({} as any) - const [errors, setErrors] = useState<KeyValue>({}) - - const submit = (): void => { - try { - schema.validateSync(value, { abortEarly: false }) - onConfirm({ ...schema.cast(value), address: {}, jurisdiction: {}, default_wire_transfer_delay: { d_ms: 6000 }, default_pay_delay: { d_ms: 3000 } } as MerchantBackend.Instances.InstanceConfigurationMessage); - } catch (err) { - const errors = err.inner as yup.ValidationError[] - const pathMessages = errors.reduce((prev, cur) => !cur.path ? prev : ({ ...prev, [cur.path]: { type: cur.type, params: cur.params, message: cur.message } }), {}) - setErrors(pathMessages) - } - } - - return <ConfirmModal description="create_instance" active onConfirm={submit} onCancel={onCancel}> - {Object.keys(schema.fields).map(f => { - const info = schema.fields[f].describe() - return <YupInput name={f} info={info} errors={errors} object={value} valueHandler={valueHandler} /> - })} - - </ConfirmModal> -} -\ No newline at end of file diff --git a/src/routes/instances/Update.tsx b/src/routes/instances/Update.tsx @@ -0,0 +1,90 @@ +import { h, VNode } from "preact"; +import { useState } from "preact/hooks"; +import { MerchantBackend, WidthId } from "../../declaration"; +import * as yup from 'yup'; +import YupField from "../../components/yup/YupField" +import { InstanceUpdateSchema as schema } from '../../schemas' +import { Text } from "preact-i18n"; + +interface Props { + onUpdate: (id: string, d: MerchantBackend.Instances.InstanceReconfigurationMessage) => void; + selected: MerchantBackend.Instances.QueryInstancesResponse & WidthId; + isLoading: boolean; + goBack: () => void; +} + +interface KeyValue { + [key: string]: string; +} + +function convert(from: MerchantBackend.Instances.QueryInstancesResponse): MerchantBackend.Instances.InstanceReconfigurationMessage { + const payto_uris = from.accounts.map(a => a.payto_uri) + return {default_pay_delay: { d_ms: 1000 }, ...from, payto_uris, }; +} + +export default function UpdateModal({ onUpdate, isLoading, selected, goBack }: Props): VNode { + const [value, valueHandler] = useState(convert(selected)) + const [errors, setErrors] = useState<KeyValue>({}) + + const submit = (): void => { + try { + schema.validateSync(value, { abortEarly: false }) + onUpdate(selected.id, schema.cast(value)); + goBack() + } catch (err) { + const errors = err.inner as yup.ValidationError[] + const pathMessages = errors.reduce((prev, cur) => !cur.path ? prev : ({ ...prev, [cur.path]: { type: cur.type, params: cur.params, message: cur.message } }), {}) + setErrors(pathMessages) + } + } + + return <div> + <section class="section is-title-bar"> + + <div class="level"> + <div class="level-left"> + <div class="level-item"> + <ul> + <li><Text id="text.merchant" /></li> + <li><Text id="text.instances" /></li> + </ul> + </div> + </div> + </div> + </section> + + <section class={isLoading ? "hero is-hero-bar" : "hero is-hero-bar is-loading"}> + <div class="hero-body"> + <div class="level"> + <div class="level-left"> + <div class="level-item"> + <h1 class="title"> + <Text id="text.create_new_instances" /> + </h1> + </div> + </div> + <div class="level-right" style="display: none;"> + <div class="level-item" /> + </div> + </div> + </div> + </section> + + <section class="section is-main-section"> + <div class="columns"> + <div class="column" /> + <div class="column is-two-thirds"> + {Object.keys(schema.fields).map(f => YupField(f, f, errors, value, valueHandler, schema.fields[f].describe()))} + <div class="buttons is-right"> + <button class="button" onClick={goBack} ><Text id="cancel" /></button> + <button class="button is-success" onClick={submit} ><Text id="confirm" /></button> + </div> + </div> + <div class="column" /> + </div> + </section> + + </div> + + // </ConfirmModal> +} +\ No newline at end of file diff --git a/src/routes/instances/UpdateModal.tsx b/src/routes/instances/UpdateModal.tsx @@ -1,9 +1,9 @@ import { h, VNode } from "preact"; import { useState } from "preact/hooks"; -import { MerchantBackend } from "../../declaration"; +import { KeyValue, MerchantBackend } from "../../declaration"; import * as yup from 'yup'; import ConfirmModal from '../../components/modal' -import YupInput from "../../components/yup/YupInput"; +import YupField from "../../components/yup/YupField"; import { InstanceUpdateSchema as schema } from '../../schemas' interface Props { @@ -12,10 +12,6 @@ interface Props { onConfirm: (i: MerchantBackend.Instances.InstanceReconfigurationMessage) => void; } -interface KeyValue { - [key: string]: string; -} - export default function UpdateModal({ element, onCancel, onConfirm }: Props): VNode { const copy: any = !element ? {} : Object.keys(schema.fields).reduce((prev, cur) => ({ ...prev, [cur]: (element as any)[cur] }), {}) @@ -26,7 +22,7 @@ export default function UpdateModal({ element, onCancel, onConfirm }: Props): VN try { schema.validateSync(value, { abortEarly: false }) - onConfirm({ ...schema.cast(value), address: {}, jurisdiction: {} } as MerchantBackend.Instances.InstanceReconfigurationMessage); + onConfirm(schema.cast(value) as MerchantBackend.Instances.InstanceReconfigurationMessage); } catch (err) { const errors = err.inner as yup.ValidationError[] const pathMessages = errors.reduce((prev, cur) => !cur.path ? prev : ({ ...prev, [cur.path]: { type: cur.type, params: cur.params, message: cur.message } }), {}) @@ -35,12 +31,6 @@ export default function UpdateModal({ element, onCancel, onConfirm }: Props): VN } return <ConfirmModal description="update_instance" active={element != null} onConfirm={submit} onCancel={onCancel}> - {Object.keys(schema.fields).map(f => { - - const info = schema.fields[f].describe() - return <YupInput name={f} info={info} errors={errors} object={value} valueHandler={valueHandler} /> - - })} - + {Object.keys(schema.fields).map(f => YupField(f, f, errors, value, valueHandler, schema.fields[f].describe()))} </ConfirmModal> } \ No newline at end of file diff --git a/src/routes/instances/View.tsx b/src/routes/instances/View.tsx @@ -3,14 +3,12 @@ import { useState } from "preact/hooks"; import { MerchantBackend, WidthId } from "../../declaration"; import Table from './CardTable'; import DeleteModal from './DeleteModal' -import UpdateModal from './UpdateModal' -import CreateModal from './CreateModal' import { Text } from "preact-i18n"; interface Props { instances: MerchantBackend.Instances.Instance[]; - onCreate: (d: MerchantBackend.Instances.InstanceConfigurationMessage) => void; - onUpdate: (id: string, d: MerchantBackend.Instances.InstanceReconfigurationMessage) => void; + onCreate: (s: boolean) => void; + onUpdate: (s: boolean) => void; onDelete: (id: string) => void; onSelect: (id: string | null) => void; selected: MerchantBackend.Instances.QueryInstancesResponse & WidthId | undefined; @@ -18,12 +16,12 @@ interface Props { } export default function View({ instances, isLoading, onCreate, onDelete, onSelect, onUpdate, selected }: Props): VNode { - const [create, setCreate] = useState<boolean>(false) const [action, setAction] = useState<'UPDATE' | 'DELETE' | null>(null) const onSelectAction = (id: string | null, action?: 'UPDATE' | 'DELETE'): void => { onSelect(id) setAction(action || null) + if (action === 'UPDATE') onUpdate(true) } return <div id="app"> @@ -46,7 +44,9 @@ export default function View({ instances, isLoading, onCreate, onDelete, onSelec <div class="level"> <div class="level-left"> <div class="level-item"> - <h1 class="title"><Text id="text.list_of_configured_instances" /></h1> + <h1 class="title"> + <Text id="text.list_of_configured_instances" /> + </h1> </div> </div> <div class="level-right" style="display: none;"> @@ -56,7 +56,7 @@ export default function View({ instances, isLoading, onCreate, onDelete, onSelec </div> </section> <section class="section is-main-section"> - <Table instances={instances} onSelect={onSelectAction} selected={selected} onCreate={(): void => setCreate(true)} /> + <Table instances={instances} onSelect={onSelectAction} selected={selected} onCreate={(): void => onCreate(true)} /> </section> {selected && action === 'DELETE' ? @@ -67,18 +67,5 @@ export default function View({ instances, isLoading, onCreate, onDelete, onSelec /> : null} - {selected && action === 'UPDATE' ? - <UpdateModal element={selected} onCancel={(): void => onSelectAction(null)} onConfirm={(i): void => { - onUpdate(selected.id, i); - onSelectAction(null); - }} - /> - : null} - - {create ? <CreateModal onCancel={(): void => setCreate(false)} onConfirm={(i): void => { - onCreate(i) - setCreate(false); - }} /> : null} - </div > } \ No newline at end of file diff --git a/src/routes/instances/index.tsx b/src/routes/instances/index.tsx @@ -1,9 +1,11 @@ import { h, VNode } from 'preact'; import View from './View'; import LoginPage from '../../components/auth/LoginPage'; -import { updateToken, useBackendInstance, useBackendInstances } from '../../components/hooks/backend'; +import { useBackendInstance, useBackendInstances } from '../../components/hooks/backend'; import { useEffect, useState } from 'preact/hooks'; import { Notification } from '../../declaration'; +import CreatePage from './Create'; +import UpdatePage from './Update'; interface Props { pushNotification: (n: Notification) => void; @@ -13,33 +15,60 @@ export default function Instances({ pushNotification }: Props): VNode { const list = useBackendInstances() const [selectedId, select] = useState<string | null>(null) const details = useBackendInstance(selectedId) + const [create, setCreate] = useState<boolean>(false) + const [update, setUpdate] = useState<boolean>(false) const requiresToken = (!list.data && list.needsAuth) || (selectedId != null && !details.data && details.needsAuth) const isLoadingTheList = (!list.data && !list.error) const isLoadingTheDetails = (!details.data && !details.error) - + + const genericError = !list.data && list.error || !details.data && details.error + useEffect(() => { - if (requiresToken) pushNotification({messageId: 'unauthorized', type: 'ERROR' }) - }, [requiresToken]) + if (requiresToken) { + pushNotification({ messageId: 'unauthorized', type: 'ERROR' }) + } else if (genericError) { + pushNotification({messageId: 'error', params: genericError, type: 'ERROR'}) + } + }, [requiresToken, genericError]) + if (requiresToken) { - return <LoginPage onLogIn={updateToken} /> + return <LoginPage /> + } + + if (create) { + return <CreatePage + goBack={() => setCreate(false)} + isLoading={false} + + onCreate={(d): Promise<void> => list.create(d) + .then((): void => pushNotification({ messageId: 'create_success', type: 'SUCCESS' })) + .catch((error): void => pushNotification({ messageId: 'create_error', type: 'ERROR', params: error })) + } + /> + } + + if (update && details.data && selectedId) { + return <UpdatePage + goBack={() => setUpdate(false)} + isLoading={false} + selected={{ ...details.data, id: selectedId }} + onUpdate={(id, d): Promise<void> => details.update(id, d) + .then((): void => pushNotification({ messageId: 'update_success', type: 'SUCCESS' })) + .catch((error): void => pushNotification({ messageId: 'update_error', type: 'ERROR', params: error })) + } + /> } return <View instances={list.data?.instances || []} isLoading={isLoadingTheList || isLoadingTheDetails} - onCreate={(d): Promise<void> => list.create(d) - .then((): void => pushNotification({messageId: 'create_success', type:'SUCCESS'})) - .catch((error): void => pushNotification({messageId: 'create_error', type:'ERROR', params: error})) - } - onUpdate={(id, d): Promise<void> => details.update(id, d) - .then((): void => pushNotification({messageId: 'update_success', type:'SUCCESS'})) - .catch((error): void => pushNotification({messageId: 'update_error', type:'ERROR', params: error})) - } + onCreate={setCreate} + onUpdate={setUpdate} onDelete={(id): Promise<void> => details.delete(id) - .then((): void => pushNotification({messageId: 'delete_success', type:'SUCCESS'})) - .catch((error): void => pushNotification({messageId: 'delete_error', type:'ERROR', params: error})) + .then((): void => pushNotification({ messageId: 'delete_success', type: 'SUCCESS' })) + .catch((error): void => pushNotification({ messageId: 'delete_error', type: 'ERROR', params: error })) } onSelect={select} selected={!details.data || !selectedId ? undefined : { ...details.data, id: selectedId }} diff --git a/src/schemas/index.ts b/src/schemas/index.ts @@ -7,8 +7,8 @@ yup.setLocale({ default: 'field_invalid', }, number: { - min: ({ min }) => ({ key: 'field_too_short', values: { min } }), - max: ({ max }) => ({ key: 'field_too_big', values: { max } }), + min: ({ min }: any) => ({ key: 'field_too_short', values: { min } }), + max: ({ max }: any) => ({ key: 'field_too_big', values: { max } }), }, }); @@ -23,63 +23,67 @@ function listOfPayToUrisAreValid(values?: (string | undefined)[]): boolean { function numberToDuration(this: yup.AnySchema, current: any, original: string): Duration { if (this.isType(current)) return current; - const d_ms = parseInt(original, 10) + const d_ms = parseInt(original, 10) * 1000 return { d_ms } } function currencyWithAmountIsValid(value?: string): boolean { return !!value && AMOUNT_REGEX.test(value) } - -export const InstanceUpdateSchema = yup.object().shape({ - name: yup.string().required(), - payto_uris: yup.array().of(yup.string()) - .min(1) - .transform(stringToArray) - .test('payto', '{path} is not valid', listOfPayToUrisAreValid), - default_max_deposit_fee: yup.string() - .required() - .test('amount', '{path} is not valid', currencyWithAmountIsValid), - default_max_wire_fee: yup.string() - .required() - .test('amount', '{path} is not valid', currencyWithAmountIsValid), - default_wire_fee_amortization: yup.number() - .required(), - default_pay_delay: yup.object() - .shape({d_ms: yup.number() }) - .required() - .meta({type:'duration'}) - .transform(numberToDuration), - default_wire_transfer_delay: yup.object() - .shape({d_ms: yup.number() }) - .required() - .meta({type:'duration'}) - .transform(numberToDuration), -}); - -export const InstanceCreateSchema = yup.object().shape({ - id: yup.string().required(), +const InstanceSchema = yup.object().shape({ + id: yup.string().required().meta({type: 'url'}), name: yup.string().required(), + auth_token: yup.string().min(8).max(20).optional().meta({type: 'secured'}), payto_uris: yup.array().of(yup.string()) .min(1) .transform(stringToArray) .test('payto', '{path} is not valid', listOfPayToUrisAreValid), default_max_deposit_fee: yup.string() .required() - .test('amount', '{path} is not valid', currencyWithAmountIsValid), + .test('amount', '{path} is not valid', currencyWithAmountIsValid) + .meta({type: 'amount'}), default_max_wire_fee: yup.string() .required() - .test('amount', '{path} is not valid', currencyWithAmountIsValid), + .test('amount', '{path} is not valid', currencyWithAmountIsValid) + .meta({type: 'amount'}), default_wire_fee_amortization: yup.number() .required(), + address: yup.object().shape({ + country: yup.string().optional(), + country_subdivision: yup.string().optional(), + district: yup.string().optional(), + town: yup.string(), + town_location: yup.string().optional(), + post_code: yup.string().optional(), + street: yup.string().optional(), + building_name: yup.string().optional(), + building_number: yup.string().optional(), + address_lines: yup.array().of(yup.string()).max(7).optional(), + }).meta({type:'group'}), + jurisdiction: yup.object().shape({ + country: yup.string().optional(), + country_subdivision: yup.string().optional(), + district: yup.string().optional(), + town: yup.string(), + town_location: yup.string().optional(), + post_code: yup.string().optional(), + street: yup.string().optional(), + building_name: yup.string().optional(), + building_number: yup.string().optional(), + address_lines: yup.array().of(yup.string()).max(7).optional(), + }).meta({type:'group'}), default_pay_delay: yup.object() - .shape({d_ms: yup.number() }) + .shape({ d_ms: yup.number() }) .required() - .meta({type:'duration'}) + .meta({ type: 'duration' }) .transform(numberToDuration), default_wire_transfer_delay: yup.object() - .shape({d_ms: yup.number() }) + .shape({ d_ms: yup.number() }) .required() - .meta({type:'duration'}) + .meta({ type: 'duration' }) .transform(numberToDuration), -}); +}) + +export const InstanceUpdateSchema = InstanceSchema.clone().omit(['id']); +export const InstanceCreateSchema = InstanceSchema.clone(); + diff --git a/src/scss/main.scss b/src/scss/main.scss @@ -24,6 +24,8 @@ @import "fonts/nunito.css"; @import "icons/materialdesignicons-4.9.95.min.css"; +@import "../../node_modules/@creativebulma/bulma-tooltip/dist/bulma-tooltip.min.css"; + .toast { position: fixed; right: 10px; diff --git a/template.env b/template.env @@ -1 +0,0 @@ -BACKEND_ENDPOINT=http://localhost:9965 diff --git a/tests/hooks/notification.test.ts b/tests/hooks/notification.test.ts @@ -13,8 +13,7 @@ test('notification should disapear after timeout', () => { act(() => { result.current?.pushNotification({ - description: 'desc', - title: 'title', + messageId: 'some_id', type: 'INFO' }); }); diff --git a/yarn.lock b/yarn.lock @@ -968,7 +968,7 @@ core-js-pure "^3.0.0" regenerator-runtime "^0.13.4" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.5", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": +"@babel/runtime@^7.0.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.5", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.13.tgz#0a21452352b02542db0ffb928ac2d3ca7cb6d66d" integrity sha512-8+3UMPBrjFa/6TtKi/7sehPKqfAm4g6K+YQjyyFOLUTxzOngcRZTlAVY8sc2CORJYqdHQY8gRPHmn+qo15rCBw== @@ -1026,6 +1026,11 @@ exec-sh "^0.3.2" minimist "^1.2.0" +"@creativebulma/bulma-tooltip@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@creativebulma/bulma-tooltip/-/bulma-tooltip-1.2.0.tgz#84dcdd59d94c09c2975fadbec1d3d765ae29c471" + integrity sha512-ooImbeXEBxf77cttbzA7X5rC5aAWm9UsXIGViFOnsqB+6M944GkB28S5R4UWRqjFd2iW4zGEkEifAU+q43pt2w== + "@emotion/cache@^10.0.27": version "10.0.29" resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-10.0.29.tgz#87e7e64f412c060102d589fe7c6dc042e6f9d1e0" @@ -1036,7 +1041,7 @@ "@emotion/utils" "0.11.3" "@emotion/weak-memoize" "0.2.5" -"@emotion/core@^10.0.9", "@emotion/core@^10.1.1": +"@emotion/core@^10.1.1": version "10.1.1" resolved "https://registry.yarnpkg.com/@emotion/core/-/core-10.1.1.tgz#c956c1365f2f2481960064bcb8c4732e5fb612c3" integrity sha512-ZMLG6qpXR8x031NXD8HJqugy/AZSkAuMxxqB46pmAR7ze47MhNJ56cdoX243QPZdGctrdfo+s08yZTiwaUcRKA== @@ -1100,7 +1105,7 @@ "@emotion/serialize" "^0.11.15" "@emotion/utils" "0.11.3" -"@emotion/styled@^10.0.23", "@emotion/styled@^10.0.7": +"@emotion/styled@^10.0.23": version "10.0.27" resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-10.0.27.tgz#12cb67e91f7ad7431e1875b1d83a94b814133eaf" integrity sha512-iK/8Sh7+NLJzyp9a5+vIQIXTYxfT4yB/OJbjzQanB2RZpvmzBQOHZWhpAMZWYEKRNNbsD6WfBw5sVWkb6WzS/Q== @@ -1460,7 +1465,7 @@ "@prefresh/core" "^0.8.1" "@prefresh/utils" "^0.3.1" -"@reach/router@^1.2.1", "@reach/router@^1.3.3": +"@reach/router@^1.3.3": version "1.3.4" resolved "https://registry.yarnpkg.com/@reach/router/-/router-1.3.4.tgz#d2574b19370a70c80480ed91f3da840136d10f8c" integrity sha512-+mtn9wjlB9NN2CNnnC/BRYtwdKBfSyyasPYraNAyvaV1occr/5NnB4CVzjEZipNHwYebQwcndGUmpFzxAUoqSA== @@ -1709,18 +1714,6 @@ prop-types "^15.7.2" regenerator-runtime "^0.13.7" -"@storybook/addons@5.1.9": - version "5.1.9" - resolved "https://registry.yarnpkg.com/@storybook/addons/-/addons-5.1.9.tgz#ecf218d08508b97ca5e6e0f1ed361081385bd3ff" - integrity sha512-1bavbcS/NiE65DwyKj8c0DmWmz9VekOinB+has2Pqt2bOffZoZwVnbmepcz9hH3GUyvp5fQBYbxTEmTDvF2lLA== - dependencies: - "@storybook/api" "5.1.9" - "@storybook/channels" "5.1.9" - "@storybook/client-logger" "5.1.9" - core-js "^3.0.1" - global "^4.3.2" - util-deprecate "^1.0.2" - "@storybook/addons@6.1.17": version "6.1.17" resolved "https://registry.yarnpkg.com/@storybook/addons/-/addons-6.1.17.tgz#ab0666446acb9fc19c94d7204dc9aafdefb6c7c2" @@ -1736,29 +1729,6 @@ global "^4.3.2" regenerator-runtime "^0.13.7" -"@storybook/api@5.1.9": - version "5.1.9" - resolved "https://registry.yarnpkg.com/@storybook/api/-/api-5.1.9.tgz#eec5b2f775392ce0803930104c6ce14fa4931e8b" - integrity sha512-d1HhpOkW+706/WJ9lP5nCqOrp/icvbm0o+6jFFOGJ35AW5O9D8vDBxzvgMEO45jjN4I+rtbcNHQCxshSbPvP9w== - dependencies: - "@storybook/channels" "5.1.9" - "@storybook/client-logger" "5.1.9" - "@storybook/core-events" "5.1.9" - "@storybook/router" "5.1.9" - "@storybook/theming" "5.1.9" - core-js "^3.0.1" - fast-deep-equal "^2.0.1" - global "^4.3.2" - lodash "^4.17.11" - memoizerific "^1.11.3" - prop-types "^15.6.2" - react "^16.8.3" - semver "^6.0.0" - shallow-equal "^1.1.0" - store2 "^2.7.1" - telejson "^2.2.1" - util-deprecate "^1.0.2" - "@storybook/api@6.1.17": version "6.1.17" resolved "https://registry.yarnpkg.com/@storybook/api/-/api-6.1.17.tgz#50393ce9b718063b67680212df895eceacc0c11d" @@ -1797,13 +1767,6 @@ qs "^6.6.0" telejson "^5.0.2" -"@storybook/channels@5.1.9": - version "5.1.9" - resolved "https://registry.yarnpkg.com/@storybook/channels/-/channels-5.1.9.tgz#003cfca0b9f1ba6cf47ce68304aedd71bdb55e74" - integrity sha512-R6i7859FsXgY9XFFErVe7gS37wGYpQEEWsO1LzUW7YptGuFTUa8yLgKkNkgfy7Zs61Xm+GiBq8PvS/CWxjotPw== - dependencies: - core-js "^3.0.1" - "@storybook/channels@6.1.17": version "6.1.17" resolved "https://registry.yarnpkg.com/@storybook/channels/-/channels-6.1.17.tgz#2cc89a6b9727d19c24b15fa3cb15569b469db864" @@ -1813,24 +1776,6 @@ ts-dedent "^2.0.0" util-deprecate "^1.0.2" -"@storybook/client-api@5.1.9": - version "5.1.9" - resolved "https://registry.yarnpkg.com/@storybook/client-api/-/client-api-5.1.9.tgz#b598efe4ab07bffaeb4cb9e30ed9c21add739df1" - integrity sha512-J5HDtOS7x5YRpF/CMiHdxywV5NIh1i/03Xh2RhG15lmPy87VStIGpLzhF71uCRPLEJinYelcjuXRNAJgRzUOlg== - dependencies: - "@storybook/addons" "5.1.9" - "@storybook/client-logger" "5.1.9" - "@storybook/core-events" "5.1.9" - "@storybook/router" "5.1.9" - common-tags "^1.8.0" - core-js "^3.0.1" - eventemitter3 "^3.1.0" - global "^4.3.2" - is-plain-object "^3.0.0" - lodash "^4.17.11" - memoizerific "^1.11.3" - qs "^6.6.0" - "@storybook/client-api@6.1.17": version "6.1.17" resolved "https://registry.yarnpkg.com/@storybook/client-api/-/client-api-6.1.17.tgz#3ced22f08a47af70ccf8929111bc44b79e9e8ec0" @@ -1855,13 +1800,6 @@ ts-dedent "^2.0.0" util-deprecate "^1.0.2" -"@storybook/client-logger@5.1.9": - version "5.1.9" - resolved "https://registry.yarnpkg.com/@storybook/client-logger/-/client-logger-5.1.9.tgz#87e2f7578416269adeccd407584010bc353f14d3" - integrity sha512-1+Otcn0EFgWNviDPNCR5LtUViADlboz9fmpZc7UY7bgaY5FVNIUO01E4T43tO7fduiRZoEvdltwTuQRm260Vjw== - dependencies: - core-js "^3.0.1" - "@storybook/client-logger@6.1.17": version "6.1.17" resolved "https://registry.yarnpkg.com/@storybook/client-logger/-/client-logger-6.1.17.tgz#0d89aaf824457f19bf9aa585bbcada57595e7d01" @@ -1870,30 +1808,6 @@ core-js "^3.0.1" global "^4.3.2" -"@storybook/components@5.1.9": - version "5.1.9" - resolved "https://registry.yarnpkg.com/@storybook/components/-/components-5.1.9.tgz#2a5258780fff07172d103287759946dbb4b13e2d" - integrity sha512-F4xcRlifSAfqkuFWtCKRvQDahXyfWBWV2Wa+kYy4YGwEfm3kKtIHVlgdgARL22g9BdYpRFEOJ+42juOu5YvIeQ== - dependencies: - "@storybook/client-logger" "5.1.9" - "@storybook/theming" "5.1.9" - core-js "^3.0.1" - global "^4.3.2" - markdown-to-jsx "^6.9.1" - memoizerific "^1.11.3" - polished "^3.3.1" - popper.js "^1.14.7" - prop-types "^15.7.2" - react "^16.8.3" - react-dom "^16.8.3" - react-focus-lock "^1.18.3" - react-helmet-async "^1.0.2" - react-popper-tooltip "^2.8.3" - react-syntax-highlighter "^8.0.1" - react-textarea-autosize "^7.1.0" - recompose "^0.30.0" - simplebar-react "^1.0.0-alpha.6" - "@storybook/components@6.1.17": version "6.1.17" resolved "https://registry.yarnpkg.com/@storybook/components/-/components-6.1.17.tgz#f92d36e370ec6039d8c7cee9ef13dda866eed3da" @@ -1920,13 +1834,6 @@ react-textarea-autosize "^8.1.1" ts-dedent "^2.0.0" -"@storybook/core-events@5.1.9": - version "5.1.9" - resolved "https://registry.yarnpkg.com/@storybook/core-events/-/core-events-5.1.9.tgz#441a6297e2ccfa743e15d1db1f4ac445b91f40d8" - integrity sha512-jHe2uyoLj9i6fntHtOj5azfGdLOb75LF0e1xXE8U2SX7Zp3uwbLAcfJ+dPStdc/q+f/wBiip3tH1dIjaNuUiMw== - dependencies: - core-js "^3.0.1" - "@storybook/core-events@6.1.17": version "6.1.17" resolved "https://registry.yarnpkg.com/@storybook/core-events/-/core-events-6.1.17.tgz#697ed916fcb2a411bc9f8bdbfacd0eb9d394eb58" @@ -2087,17 +1994,6 @@ resolved "https://registry.yarnpkg.com/@storybook/preset-scss/-/preset-scss-1.0.3.tgz#8ac834545c642dada0f64f510ef08dfb882e9737" integrity sha512-o9Iz6wxPeNENrQa2mKlsDKynBfqU2uWaRP80HeWp4TkGgf7/x3DVF2O7yi9N0x/PI1qzzTTpxlQ90D62XmpiTw== -"@storybook/router@5.1.9": - version "5.1.9" - resolved "https://registry.yarnpkg.com/@storybook/router/-/router-5.1.9.tgz#8cd97bea4f2acf8ec5f6694d06fb0633dde33417" - integrity sha512-eAmeerE/OTIwCV7WBnb1BPINVN1GTSMsUXLNWpqSISuyWJ+NZAJlObFkvXoc57QSQlv0cvXlm1FMkmRt8ku1Hw== - dependencies: - "@reach/router" "^1.2.1" - core-js "^3.0.1" - global "^4.3.2" - memoizerific "^1.11.3" - qs "^6.6.0" - "@storybook/router@6.1.17": version "6.1.17" resolved "https://registry.yarnpkg.com/@storybook/router/-/router-6.1.17.tgz#96746878c50c6c97c7de5a1b23a9503c5d648775" @@ -2135,24 +2031,6 @@ regenerator-runtime "^0.13.7" source-map "^0.7.3" -"@storybook/theming@5.1.9": - version "5.1.9" - resolved "https://registry.yarnpkg.com/@storybook/theming/-/theming-5.1.9.tgz#c425f5867fae0db79e01112853b1808332a5f1a2" - integrity sha512-4jIFJwTWVf9tsv27noLoFHlKC2Jl9DHV3q+rxGPU8bTNbufCu4oby82SboO5GAKuS3eu1cxL1YY9pYad9WxfHg== - dependencies: - "@emotion/core" "^10.0.9" - "@emotion/styled" "^10.0.7" - "@storybook/client-logger" "5.1.9" - common-tags "^1.8.0" - core-js "^3.0.1" - deep-object-diff "^1.1.0" - emotion-theming "^10.0.9" - global "^4.3.2" - memoizerific "^1.11.3" - polished "^3.3.1" - prop-types "^15.7.2" - resolve-from "^5.0.0" - "@storybook/theming@6.1.17": version "6.1.17" resolved "https://registry.yarnpkg.com/@storybook/theming/-/theming-6.1.17.tgz#99cc120a230c30458d833b40c806b9b4dff7b34a" @@ -3160,11 +3038,6 @@ arrify@^2.0.1: resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa" integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug== -asap@~2.0.3: - version "2.0.6" - resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" - integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= - asn1.js@^5.2.0: version "5.4.1" resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07" @@ -3663,7 +3536,7 @@ babel-preset-jest@^26.6.2: babel-plugin-transform-undefined-to-void "^6.9.4" lodash "^4.17.11" -babel-runtime@^6.18.0, babel-runtime@^6.26.0: +babel-runtime@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4= @@ -4199,11 +4072,6 @@ camelcase@^6.0.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809" integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg== -can-use-dom@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/can-use-dom/-/can-use-dom-0.1.0.tgz#22cc4a34a0abc43950f42c6411024a3f6366b45a" - integrity sha1-IsxKNKCrxDlQ9CxkEQJKP2NmtFo= - caniuse-api@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0" @@ -4286,11 +4154,6 @@ chalk@^4.0.0, chalk@^4.1.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -change-emitter@^0.1.2: - version "0.1.6" - resolved "https://registry.yarnpkg.com/change-emitter/-/change-emitter-0.1.6.tgz#e8b2fe3d7f1ab7d69a32199aff91ea6931409515" - integrity sha1-6LL+PX8at9aaMhma/5HqaTFAlRU= - char-regex@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" @@ -4833,11 +4696,6 @@ core-js-pure@^3.0.0, core-js-pure@^3.0.1: resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.8.3.tgz#10e9e3b2592ecaede4283e8f3ad7020811587c02" integrity sha512-V5qQZVAr9K0xu7jXg1M7qTEwuxUgqr7dUOezGaNa7i+Xn9oXAU/d1fzqD9ObuwpVQOaorO5s70ckyi1woP9lVA== -core-js@^1.0.0: - version "1.2.7" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" - integrity sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY= - core-js@^2.4.0: version "2.6.12" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec" @@ -4930,7 +4788,7 @@ create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: safe-buffer "^5.0.1" sha.js "^2.4.8" -create-react-context@0.3.0, create-react-context@^0.3.0: +create-react-context@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/create-react-context/-/create-react-context-0.3.0.tgz#546dede9dc422def0d3fc2fe03afe0bc0f4f7d8c" integrity sha512-dNldIoSuNSvlTJ7slIKC/ZFGKexBMBrrcc+TTe1NdmROnaASuLPvqpwj9v4XS4uXZ8+YPu0sNmShX2rXI5LNsw== @@ -5313,7 +5171,7 @@ decompress-response@^3.3.0: dependencies: mimic-response "^1.0.0" -deep-equal@^1.0.1, deep-equal@^1.1.1: +deep-equal@^1.0.1: version "1.1.1" resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.1.tgz#b5c98c942ceffaf7cb051e24e1434a25a2e6076a" integrity sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g== @@ -5814,7 +5672,7 @@ emojis-list@^3.0.0: resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== -emotion-theming@^10.0.19, emotion-theming@^10.0.9: +emotion-theming@^10.0.19: version "10.0.27" resolved "https://registry.yarnpkg.com/emotion-theming/-/emotion-theming-10.0.27.tgz#1887baaec15199862c89b1b984b79806f2b9ab10" integrity sha512-MlF1yu/gYh8u+sLUqA0YuA9JX0P4Hb69WlKc/9OLo+WCXuX6sy/KoIa+qJimgmr2dWqnypYKYPX37esjDBbhdw== @@ -5828,13 +5686,6 @@ encodeurl@~1.0.2: resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= -encoding@^0.1.11: - version "0.1.13" - resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" - integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A== - dependencies: - iconv-lite "^0.6.2" - end-of-stream@^1.0.0, end-of-stream@^1.1.0: version "1.4.4" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" @@ -6241,11 +6092,6 @@ etag@~1.8.1: resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= -eventemitter3@^3.1.0: - version "3.1.2" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.2.tgz#2d3d48f9c346698fce83a85d7d664e98535df6e7" - integrity sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q== - eventemitter3@^4.0.0: version "4.0.7" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" @@ -6431,11 +6277,6 @@ fast-async@^6.3.7: nodent-compiler "^3.2.10" nodent-runtime ">=3.2.1" -fast-deep-equal@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" - integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= - fast-deep-equal@^3.1.1: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" @@ -6463,7 +6304,7 @@ fast-levenshtein@~2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= -fault@^1.0.0, fault@^1.0.2: +fault@^1.0.0: version "1.0.4" resolved "https://registry.yarnpkg.com/fault/-/fault-1.0.4.tgz#eafcfc0a6d214fc94601e170df29954a4f842f13" integrity sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA== @@ -6484,19 +6325,6 @@ fb-watchman@^2.0.0: dependencies: bser "2.1.1" -fbjs@^0.8.1: - version "0.8.17" - resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.17.tgz#c4d598ead6949112653d6588b01a5cdcd9f90fdd" - integrity sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90= - dependencies: - core-js "^1.0.0" - isomorphic-fetch "^2.1.1" - loose-envify "^1.0.0" - object-assign "^4.1.0" - promise "^7.1.1" - setimmediate "^1.0.5" - ua-parser-js "^0.7.18" - figgy-pudding@^3.5.1: version "3.5.2" resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.2.tgz#b4eee8148abb01dcf1d1ac34367d59e12fa61d6e" @@ -6653,11 +6481,6 @@ flush-write-stream@^1.0.0: inherits "^2.0.3" readable-stream "^2.3.6" -focus-lock@^0.6.3: - version "0.6.8" - resolved "https://registry.yarnpkg.com/focus-lock/-/focus-lock-0.6.8.tgz#61985fadfa92f02f2ee1d90bc738efaf7f3c9f46" - integrity sha512-vkHTluRCoq9FcsrldC0ulQHiyBYgVJB2CX53I8r0nTC6KnEij7Of0jpBspjt3/CuNb6fyoj3aOh9J2HgQUM0og== - follow-redirects@^1.0.0, follow-redirects@^1.10.0: version "1.13.2" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.2.tgz#dd73c8effc12728ba5cf4259d760ea5fb83e3147" @@ -7347,16 +7170,6 @@ hast-util-to-parse5@^6.0.0: xtend "^4.0.0" zwitch "^1.0.0" -hastscript@^5.0.0: - version "5.1.2" - resolved "https://registry.yarnpkg.com/hastscript/-/hastscript-5.1.2.tgz#bde2c2e56d04c62dd24e8c5df288d050a355fb8a" - integrity sha512-WlztFuK+Lrvi3EggsqOkQ52rKbxkXL3RwB6t5lwoa8QLMemoWfBuL43eDrwOamJyR7uKQKdmKYaBH1NZBiIRrQ== - dependencies: - comma-separated-tokens "^1.0.0" - hast-util-parse-selector "^2.0.0" - property-information "^5.0.0" - space-separated-tokens "^1.0.0" - hastscript@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/hastscript/-/hastscript-6.0.0.tgz#e8768d7eac56c3fdeac8a92830d58e811e5bf640" @@ -7388,11 +7201,6 @@ highlight.js@~10.5.0: resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.5.0.tgz#3f09fede6a865757378f2d9ebdcbc15ba268f98f" integrity sha512-xTmvd9HiIHR6L53TMC7TKolEj65zG1XU+Onr8oi86mYa+nLcIbxTTWkpW7CsEwv/vK7u1zb8alZIMLDqqN6KTw== -highlight.js@~9.12.0: - version "9.12.0" - resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.12.0.tgz#e6d9dbe57cbefe60751f02af336195870c90c01e" - integrity sha1-5tnb5Xy+/mB1HwKvM2GVhwyQwB4= - hmac-drbg@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" @@ -7402,11 +7210,6 @@ hmac-drbg@^1.0.1: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" -hoist-non-react-statics@^2.3.1: - version "2.5.5" - resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz#c5903cf409c0dfd908f388e619d86b9c1174cb47" - integrity sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw== - hoist-non-react-statics@^3.3.0: version "3.3.2" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" @@ -7664,13 +7467,6 @@ iconv-lite@0.4.24, iconv-lite@^0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" -iconv-lite@^0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.2.tgz#ce13d1875b0c3a674bd6a04b7f76b01b1b6ded01" - integrity sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ== - dependencies: - safer-buffer ">= 2.1.2 < 3.0.0" - icss-utils@^4.0.0, icss-utils@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-4.1.1.tgz#21170b53789ee27447c2f47dd683081403f9a467" @@ -8133,7 +7929,7 @@ is-fullwidth-code-point@^3.0.0: resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== -is-function@^1.0.1, is-function@^1.0.2: +is-function@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.2.tgz#4f097f30abf6efadac9833b17ca5dc03f8144e08" integrity sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ== @@ -8268,7 +8064,7 @@ is-plain-obj@^2.0.0: resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== -is-plain-object@3.0.1, is-plain-object@^3.0.0: +is-plain-object@3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-3.0.1.tgz#662d92d24c0aa4302407b0d45d21f2251c85f85b" integrity sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g== @@ -8313,7 +8109,7 @@ is-set@^2.0.2: resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.2.tgz#90755fa4c2562dc1c5d4024760d6119b94ca18ec" integrity sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g== -is-stream@^1.0.1, is-stream@^1.1.0: +is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= @@ -8426,14 +8222,6 @@ isobject@^4.0.0: resolved "https://registry.yarnpkg.com/isobject/-/isobject-4.0.0.tgz#3f1c9155e73b192022a80819bacd0343711697b0" integrity sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA== -isomorphic-fetch@^2.1.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9" - integrity sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk= - dependencies: - node-fetch "^1.0.1" - whatwg-fetch ">=0.10.0" - isomorphic-unfetch@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/isomorphic-unfetch/-/isomorphic-unfetch-3.1.0.tgz#87341d5f4f7b63843d468438128cb087b7c3e98f" @@ -9316,11 +9104,6 @@ lodash._reinterpolate@^3.0.0: resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0= -lodash.debounce@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" - integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= - lodash.escape@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-4.0.1.tgz#c9044690c21e04294beaa517712fded1fa88de98" @@ -9361,11 +9144,6 @@ lodash.templatesettings@^4.0.0: dependencies: lodash._reinterpolate "^3.0.0" -lodash.throttle@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" - integrity sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ= - lodash.uniq@4.5.0, lodash.uniq@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" @@ -9433,14 +9211,6 @@ lowlight@^1.14.0: fault "^1.0.0" highlight.js "~10.5.0" -lowlight@~1.9.1: - version "1.9.2" - resolved "https://registry.yarnpkg.com/lowlight/-/lowlight-1.9.2.tgz#0b9127e3cec2c3021b7795dd81005c709a42fdd1" - integrity sha512-Ek18ElVCf/wF/jEm1b92gTnigh94CtBNWiZ2ad+vTgW7cTmQxUY3I98BjHK68gZAJEWmybGBZgx9qv3QxLQB/Q== - dependencies: - fault "^1.0.2" - highlight.js "~9.12.0" - lru-cache@^4.0.1: version "4.1.5" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" @@ -9524,7 +9294,7 @@ markdown-escapes@^1.0.0: resolved "https://registry.yarnpkg.com/markdown-escapes/-/markdown-escapes-1.0.4.tgz#c95415ef451499d7602b91095f3c8e8975f78535" integrity sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg== -markdown-to-jsx@^6.11.4, markdown-to-jsx@^6.9.1: +markdown-to-jsx@^6.11.4: version "6.11.4" resolved "https://registry.yarnpkg.com/markdown-to-jsx/-/markdown-to-jsx-6.11.4.tgz#b4528b1ab668aef7fe61c1535c27e837819392c5" integrity sha512-3lRCD5Sh+tfA52iGgfs/XZiw33f7fFX9Bn55aNnVNUd2GzLDkOWyKYYD8Yju2B1Vn+feiEdgJs8T6Tg0xNokPw== @@ -10007,14 +9777,6 @@ no-case@^3.0.4: lower-case "^2.0.2" tslib "^2.0.3" -node-fetch@^1.0.1: - version "1.7.3" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" - integrity sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ== - dependencies: - encoding "^0.1.11" - is-stream "^1.0.1" - node-fetch@^2.6.0, node-fetch@^2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" @@ -10612,18 +10374,6 @@ parse-asn1@^5.0.0, parse-asn1@^5.1.5: pbkdf2 "^3.0.3" safe-buffer "^5.1.1" -parse-entities@^1.1.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-1.2.2.tgz#c31bf0f653b6661354f8973559cb86dd1d5edf50" - integrity sha512-NzfpbxW/NPrzZ/yYSoQxyqUZMZXIdCfE0OIN4ESsnptHJECoUk3FZktxNuzQf4tjt5UEopnxpYJbvYuxIFDdsg== - dependencies: - character-entities "^1.0.0" - character-entities-legacy "^1.0.0" - character-reference-invalid "^1.0.0" - is-alphanumerical "^1.0.0" - is-decimal "^1.0.0" - is-hexadecimal "^1.0.0" - parse-entities@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-2.0.0.tgz#53c6eb5b9314a1f4ec99fa0fdf7ce01ecda0cbe8" @@ -10872,7 +10622,7 @@ pnp-webpack-plugin@1.6.4: dependencies: ts-pnp "^1.1.6" -polished@^3.3.1, polished@^3.4.4: +polished@^3.4.4: version "3.7.0" resolved "https://registry.yarnpkg.com/polished/-/polished-3.7.0.tgz#ece3368df30d33082bc8a957aa212d3f98119278" integrity sha512-1tnvQ2wsxfR/DyPE2Xu9sRbnLAwXAarCWiZJ8Hfirw59bTigqjbzEWSAmzYizT6ocQW995V8n7RP48jq50DjJA== @@ -10880,11 +10630,6 @@ polished@^3.3.1, polished@^3.4.4: "@babel/runtime" "^7.12.5" "@scarf/scarf" "^1.1.0" -popper.js@^1.14.4, popper.js@^1.14.7: - version "1.16.1" - resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.1.tgz#2a223cb3dc7b6213d740e40372be40de43e65b1b" - integrity sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ== - portfinder@^1.0.26: version "1.0.28" resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.28.tgz#67c4622852bd5374dd1dd900f779f53462fac778" @@ -11419,20 +11164,13 @@ pretty-hrtime@^1.0.3: resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1" integrity sha1-t+PqQkNaTJsnWdmeDyAesZWALuE= -prismjs@^1.21.0, prismjs@^1.8.4, prismjs@~1.23.0: +prismjs@^1.21.0, prismjs@~1.23.0: version "1.23.0" resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.23.0.tgz#d3b3967f7d72440690497652a9d40ff046067f33" integrity sha512-c29LVsqOaLbBHuIbsTxaKENh1N2EQBOHaWv7gkHN4dgRbxSREqDnDbtFJYdpPauS4YCplMSNCABQ6Eeor69bAA== optionalDependencies: clipboard "^2.0.0" -prismjs@~1.17.0: - version "1.17.1" - resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.17.1.tgz#e669fcbd4cdd873c35102881c33b14d0d68519be" - integrity sha512-PrEDJAFdUGbOP6xK/UsfkC5ghJsPJviKgnQOoxaDbBjwc8op68Quupwt1DeAFoG8GImPhiKXAvvsH7wDSLsu1Q== - optionalDependencies: - clipboard "^2.0.0" - process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" @@ -11487,13 +11225,6 @@ promise.prototype.finally@^3.1.0: es-abstract "^1.17.0-next.0" function-bind "^1.1.1" -promise@^7.1.1: - version "7.3.1" - resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" - integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg== - dependencies: - asap "~2.0.3" - prompts@^2.0.1, prompts@^2.2.1: version "2.4.0" resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.0.tgz#4aa5de0723a231d1ee9121c40fdf663df73f61d7" @@ -11721,13 +11452,6 @@ rc@^1.2.8: minimist "^1.2.0" strip-json-comments "~2.0.1" -react-clientside-effect@^1.2.0: - version "1.2.4" - resolved "https://registry.yarnpkg.com/react-clientside-effect/-/react-clientside-effect-1.2.4.tgz#42cca8bd3b8aec29b811b0f30ab7674d8da9d3d2" - integrity sha512-rJEnS+TKyrznJlzJ4XPoWBLITpfJ5ez1t2OqhE9gIiicLlEypgtvhQqksfuh5sq+0n3kCoGGkY9rN3SKu+aGKQ== - dependencies: - "@babel/runtime" "^7.12.13" - react-color@^2.17.0: version "2.19.3" resolved "https://registry.yarnpkg.com/react-color/-/react-color-2.19.3.tgz#ec6c6b4568312a3c6a18420ab0472e146aa5683d" @@ -11781,16 +11505,6 @@ react-dom@16.13.1: prop-types "^15.6.2" scheduler "^0.19.1" -react-dom@^16.8.3: - version "16.14.0" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.14.0.tgz#7ad838ec29a777fb3c75c3a190f661cf92ab8b89" - integrity sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - prop-types "^15.6.2" - scheduler "^0.19.1" - react-draggable@^4.0.3: version "4.4.3" resolved "https://registry.yarnpkg.com/react-draggable/-/react-draggable-4.4.3.tgz#0727f2cae5813e36b0e4962bf11b2f9ef2b406f3" @@ -11817,16 +11531,6 @@ react-fast-compare@^3.0.1, react-fast-compare@^3.2.0: resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb" integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA== -react-focus-lock@^1.18.3: - version "1.19.1" - resolved "https://registry.yarnpkg.com/react-focus-lock/-/react-focus-lock-1.19.1.tgz#2f3429793edaefe2d077121f973ce5a3c7a0651a" - integrity sha512-TPpfiack1/nF4uttySfpxPk4rGZTLXlaZl7ncZg/ELAk24Iq2B1UUaUioID8H8dneUXqznT83JTNDHDj+kwryw== - dependencies: - "@babel/runtime" "^7.0.0" - focus-lock "^0.6.3" - prop-types "^15.6.2" - react-clientside-effect "^1.2.0" - react-helmet-async@^1.0.2: version "1.0.7" resolved "https://registry.yarnpkg.com/react-helmet-async/-/react-helmet-async-1.0.7.tgz#b988fbc3abdc4b704982bb74b9cb4a08fcf062c1" @@ -11864,19 +11568,11 @@ react-is@^17.0.1: resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.1.tgz#5b3531bd76a645a4c9fb6e693ed36419e3301339" integrity sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA== -react-lifecycles-compat@^3.0.2, react-lifecycles-compat@^3.0.4: +react-lifecycles-compat@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== -react-popper-tooltip@^2.8.3: - version "2.11.1" - resolved "https://registry.yarnpkg.com/react-popper-tooltip/-/react-popper-tooltip-2.11.1.tgz#3c4bdfd8bc10d1c2b9a162e859bab8958f5b2644" - integrity sha512-04A2f24GhyyMicKvg/koIOQ5BzlrRbKiAgP6L+Pdj1MVX3yJ1NeZ8+EidndQsbejFT55oW1b++wg2Z8KlAyhfQ== - dependencies: - "@babel/runtime" "^7.9.2" - react-popper "^1.3.7" - react-popper-tooltip@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/react-popper-tooltip/-/react-popper-tooltip-3.1.1.tgz#329569eb7b287008f04fcbddb6370452ad3f9eac" @@ -11886,19 +11582,6 @@ react-popper-tooltip@^3.1.1: "@popperjs/core" "^2.5.4" react-popper "^2.2.4" -react-popper@^1.3.7: - version "1.3.7" - resolved "https://registry.yarnpkg.com/react-popper/-/react-popper-1.3.7.tgz#f6a3471362ef1f0d10a4963673789de1baca2324" - integrity sha512-nmqYTx7QVjCm3WUZLeuOomna138R1luC4EqkW3hxJUrAe+3eNz3oFCLYdnPwILfn0mX1Ew2c3wctrjlUMYYUww== - dependencies: - "@babel/runtime" "^7.1.2" - create-react-context "^0.3.0" - deep-equal "^1.1.1" - popper.js "^1.14.4" - prop-types "^15.6.1" - typed-styles "^0.0.7" - warning "^4.0.2" - react-popper@^2.2.4: version "2.2.4" resolved "https://registry.yarnpkg.com/react-popper/-/react-popper-2.2.4.tgz#d2ad3d2474ac9f1abf93df3099d408e5aa6a2e22" @@ -11933,25 +11616,6 @@ react-syntax-highlighter@^13.5.0: prismjs "^1.21.0" refractor "^3.1.0" -react-syntax-highlighter@^8.0.1: - version "8.1.0" - resolved "https://registry.yarnpkg.com/react-syntax-highlighter/-/react-syntax-highlighter-8.1.0.tgz#59103ff17a828a27ed7c8f035ae2558f09b6b78c" - integrity sha512-G2bkZxmF3VOa4atEdXIDSfwwCqjw6ZQX5znfTaHcErA1WqHIS0o6DaSCDKFPVaOMXQEB9Hf1UySYQvuJmV8CXg== - dependencies: - babel-runtime "^6.18.0" - highlight.js "~9.12.0" - lowlight "~1.9.1" - prismjs "^1.8.4" - refractor "^2.4.1" - -react-textarea-autosize@^7.1.0: - version "7.1.2" - resolved "https://registry.yarnpkg.com/react-textarea-autosize/-/react-textarea-autosize-7.1.2.tgz#70fdb333ef86bcca72717e25e623e90c336e2cda" - integrity sha512-uH3ORCsCa3C6LHxExExhF4jHoXYCQwE5oECmrRsunlspaDAbS4mGKNlWZqjLfInWtFQcf0o1n1jC/NGXFdUBCg== - dependencies: - "@babel/runtime" "^7.1.2" - prop-types "^15.6.0" - react-textarea-autosize@^8.1.1: version "8.3.0" resolved "https://registry.yarnpkg.com/react-textarea-autosize/-/react-textarea-autosize-8.3.0.tgz#e6e2fd186d9f61bb80ac6e2dcb4c55504f93c2fa" @@ -11970,15 +11634,6 @@ react@16.13.1: object-assign "^4.1.1" prop-types "^15.6.2" -react@^16.8.1, react@^16.8.3: - version "16.14.0" - resolved "https://registry.yarnpkg.com/react/-/react-16.14.0.tgz#94d776ddd0aaa37da3eda8fc5b6b18a4c9a3114d" - integrity sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - prop-types "^15.6.2" - reactcss@^1.2.0: version "1.2.3" resolved "https://registry.yarnpkg.com/reactcss/-/reactcss-1.2.3.tgz#c00013875e557b1cf0dfd9a368a1c3dab3b548dd" @@ -12067,18 +11722,6 @@ rechoir@^0.6.2: dependencies: resolve "^1.1.6" -recompose@^0.30.0: - version "0.30.0" - resolved "https://registry.yarnpkg.com/recompose/-/recompose-0.30.0.tgz#82773641b3927e8c7d24a0d87d65aeeba18aabd0" - integrity sha512-ZTrzzUDa9AqUIhRk4KmVFihH0rapdCSMFXjhHbNrjAWxBuUD/guYlyysMnuHjlZC/KRiOKRtB4jf96yYSkKE8w== - dependencies: - "@babel/runtime" "^7.0.0" - change-emitter "^0.1.2" - fbjs "^0.8.1" - hoist-non-react-statics "^2.3.1" - react-lifecycles-compat "^3.0.2" - symbol-observable "^1.0.4" - recursive-readdir@2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/recursive-readdir/-/recursive-readdir-2.2.2.tgz#9946fb3274e1628de6e36b2f6714953b4845094f" @@ -12094,15 +11737,6 @@ redent@^1.0.0: indent-string "^2.1.0" strip-indent "^1.0.1" -refractor@^2.4.1: - version "2.10.1" - resolved "https://registry.yarnpkg.com/refractor/-/refractor-2.10.1.tgz#166c32f114ed16fd96190ad21d5193d3afc7d34e" - integrity sha512-Xh9o7hQiQlDbxo5/XkOX6H+x/q8rmlmZKr97Ie1Q8ZM32IRRd3B/UxuA/yXDW79DBSXGWxm2yRTbcTVmAciJRw== - dependencies: - hastscript "^5.0.0" - parse-entities "^1.1.2" - prismjs "~1.17.0" - refractor@^3.1.0: version "3.3.1" resolved "https://registry.yarnpkg.com/refractor/-/refractor-3.3.1.tgz#ebbc04b427ea81dc25ad333f7f67a0b5f4f0be3a" @@ -12373,11 +12007,6 @@ requires-port@^1.0.0: resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= -resize-observer-polyfill@^1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464" - integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg== - resolve-cwd@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" @@ -12580,7 +12209,7 @@ safe-regex@^1.1.0: dependencies: ret "~0.1.10" -"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: +"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== @@ -12814,7 +12443,7 @@ set-value@^2.0.0, set-value@^2.0.1: is-plain-object "^2.0.3" split-string "^3.0.1" -setimmediate@^1.0.4, setimmediate@^1.0.5: +setimmediate@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= @@ -12837,11 +12466,6 @@ sha.js@^2.4.0, sha.js@^2.4.8: inherits "^2.0.1" safe-buffer "^5.0.1" -shallow-equal@^1.1.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/shallow-equal/-/shallow-equal-1.2.1.tgz#4c16abfa56043aa20d050324efa68940b0da79da" - integrity sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA== - shallowequal@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8" @@ -12911,26 +12535,6 @@ simple-swizzle@^0.2.2: dependencies: is-arrayish "^0.3.1" -simplebar-react@^1.0.0-alpha.6: - version "1.2.3" - resolved "https://registry.yarnpkg.com/simplebar-react/-/simplebar-react-1.2.3.tgz#bd81fa9827628470e9470d06caef6ece15e1c882" - integrity sha512-1EOWJzFC7eqHUp1igD1/tb8GBv5aPQA5ZMvpeDnVkpNJ3jAuvmrL2kir3HuijlxhG7njvw9ssxjjBa89E5DrJg== - dependencies: - prop-types "^15.6.1" - simplebar "^4.2.3" - -simplebar@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/simplebar/-/simplebar-4.2.3.tgz#dac40aced299c17928329eab3d5e6e795fafc10c" - integrity sha512-9no0pK7/1y+8/oTF3sy/+kx0PjQ3uk4cYwld5F1CJGk2gx+prRyUq8GRfvcVLq5niYWSozZdX73a2wIr1o9l/g== - dependencies: - can-use-dom "^0.1.0" - core-js "^3.0.1" - lodash.debounce "^4.0.8" - lodash.memoize "^4.1.2" - lodash.throttle "^4.1.1" - resize-observer-polyfill "^1.5.1" - sirv-cli@^1.0.0-next.3: version "1.0.11" resolved "https://registry.yarnpkg.com/sirv-cli/-/sirv-cli-1.0.11.tgz#a3f4bed53b7c09306ed7f16ebea6e1e7be676c74" @@ -13259,16 +12863,6 @@ store2@^2.7.1: resolved "https://registry.yarnpkg.com/store2/-/store2-2.12.0.tgz#e1f1b7e1a59b6083b2596a8d067f6ee88fd4d3cf" integrity sha512-7t+/wpKLanLzSnQPX8WAcuLCCeuSHoWdQuh9SB3xD0kNOM38DNf+0Oa+wmvxmYueRzkmh6IcdKFtvTa+ecgPDw== -storybook-addon-i18n@^5.1.13: - version "5.1.13" - resolved "https://registry.yarnpkg.com/storybook-addon-i18n/-/storybook-addon-i18n-5.1.13.tgz#3dc70c12bae47de3f2d6ce3f6ecc0230e8ade00b" - integrity sha512-qbHygTbB52Bgz9llV3F/fkGf7SNfp1OIX/c9CAWcXDa/xirfLPFTWDSiEWqb/862KxlgmOvAPTPhctoEpWsKSg== - dependencies: - "@storybook/addons" "5.1.9" - "@storybook/client-api" "5.1.9" - "@storybook/components" "5.1.9" - react "^16.8.1" - stream-browserify@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b" @@ -13587,11 +13181,6 @@ swr@^0.4.1: dependencies: dequal "2.0.2" -symbol-observable@^1.0.4: - version "1.2.0" - resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" - integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== - symbol-tree@^3.2.2, symbol-tree@^3.2.4: version "3.2.4" resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" @@ -13647,19 +13236,6 @@ tar@^6.0.2: mkdirp "^1.0.3" yallist "^4.0.0" -telejson@^2.2.1: - version "2.2.2" - resolved "https://registry.yarnpkg.com/telejson/-/telejson-2.2.2.tgz#d61d721d21849a6e4070d547aab302a9bd22c720" - integrity sha512-YyNwnKY0ilabOwYgC/J754En1xOe5PBIUIw+C9e0+5HjVVcnQE5/gdu2yET2pmSbp5bxIDqYNjvndj2PUkIiYA== - dependencies: - global "^4.3.2" - is-function "^1.0.1" - is-regex "^1.0.4" - is-symbol "^1.0.2" - isobject "^3.0.1" - lodash "^4.17.11" - memoizerific "^1.11.3" - telejson@^5.0.2: version "5.1.0" resolved "https://registry.yarnpkg.com/telejson/-/telejson-5.1.0.tgz#cc04e4c2a355f9eb6af557e37acd6449feb1d146" @@ -14045,11 +13621,6 @@ type-is@~1.6.17, type-is@~1.6.18: media-typer "0.3.0" mime-types "~2.1.24" -typed-styles@^0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/typed-styles/-/typed-styles-0.0.7.tgz#93392a008794c4595119ff62dde6809dbc40a3d9" - integrity sha512-pzP0PWoZUhsECYjABgCGQlRGL1n7tOHsgwYv3oIiEpJwGhFTuty/YNeduxQYzXXa3Ge5BdT6sHYIQYpl4uJ+5Q== - typedarray-to-buffer@^3.1.5: version "3.1.5" resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" @@ -14072,11 +13643,6 @@ typescript@^4.1.3: resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.1.3.tgz#519d582bd94cba0cf8934c7d8e8467e473f53bb7" integrity sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg== -ua-parser-js@^0.7.18: - version "0.7.23" - resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.23.tgz#704d67f951e13195fbcd3d78818577f5bc1d547b" - integrity sha512-m4hvMLxgGHXG3O3fQVAyyAQpZzDOvwnhOTjYz5Xmr7r/+LpkNy3vJXdVRWgd1TkAb7NGROZuSy96CrlNVjA7KA== - uglify-js@3.4.x: version "3.4.10" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.10.tgz#9ad9563d8eb3acdfb8d38597d2af1d815f6a755f" @@ -14762,11 +14328,6 @@ whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.5: dependencies: iconv-lite "0.4.24" -whatwg-fetch@>=0.10.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.5.0.tgz#605a2cd0a7146e5db141e29d1c62ab84c0c4c868" - integrity sha512-jXkLtsR42xhXg7akoDKvKWE40eJeI+2KZqcp2h3NsOrRnDvtWX36KcKl30dy+hxECivdk2BVUHVNrPtoMBUx6A== - whatwg-mimetype@^2.2.0, whatwg-mimetype@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf"