diff --git a/packages/background/package.json b/packages/background/package.json index 793043fbd..c3c112b05 100644 --- a/packages/background/package.json +++ b/packages/background/package.json @@ -1,6 +1,6 @@ { "name": "@block-wallet/background", - "version": "1.1.23", + "version": "2.0.0", "private": true, "dependencies": { "@block-wallet/chains-assets": "https://github.com/block-wallet/chains-assets#v0.0.53", @@ -91,4 +91,4 @@ "lint": "prettier --check src/ '!**/*.json'", "lint:fix": "prettier --write src/ '!**/*.json'" } -} +} \ No newline at end of file diff --git a/packages/background/src/controllers/AccountTrackerController.ts b/packages/background/src/controllers/AccountTrackerController.ts index 593893241..bed3883d0 100644 --- a/packages/background/src/controllers/AccountTrackerController.ts +++ b/packages/background/src/controllers/AccountTrackerController.ts @@ -28,7 +28,7 @@ import { getAddressBalances as getAddressBalancesFromSingleCallBalancesContract, isSingleCallBalancesContractAvailable, } from '../utils/balance-checker/balanceChecker'; -import { cloneDeep } from 'lodash'; +import { cloneDeep, isEqual } from 'lodash'; import { ACTIONS_TIME_INTERVALS_DEFAULT_VALUES, Network, @@ -1651,7 +1651,7 @@ export class AccountTrackerController extends BaseController { // If any of the following stores were updated trigger the ActivityList update this._transactionsController.UIStore.subscribe(this.onStoreUpdate); this._privacyController.UIStore.subscribe(this.onStoreUpdate); - this._preferencesController.store.subscribe(this.onStoreUpdate); - this._networkController.store.subscribe(this.onStoreUpdate); - this._transactionWatcherController.store.subscribe(this.onStoreUpdate); + this._preferencesController.store.subscribe((newState, oldState) => { + if ( + !compareAddresses( + newState.selectedAddress, + oldState?.selectedAddress + ) + ) { + return this.onStoreUpdate(); + } + }); + this._networkController.store.subscribe((newState, oldState) => { + if (newState.selectedNetwork !== oldState?.selectedNetwork) { + this.onStoreUpdate(); + } + }); + this._transactionWatcherController.store.subscribe( + (newState, oldState) => { + const { selectedAddress } = + this._preferencesController.store.getState(); + + const safeGetTxsHashes = ( + txWatcherState: + | TransactionWatcherControllerState + | undefined + ) => { + if (!txWatcherState) { + return []; + } + return this.parseWatchedTransactions( + this._networkController.network.chainId, + selectedAddress, + txWatcherState.transactions + ) + .filter((tx) => tx.transactionParams.hash) + .map((tx) => tx.transactionParams.hash) + .filter(Boolean); + }; + + const oldTxs = safeGetTxsHashes(oldState); + const newTxs = safeGetTxsHashes(newState); + + //If hashes length has changed, then update the activity list. + if (oldTxs.length !== newTxs.length) { + this.onStoreUpdate(); + } + } + ); this._bridgeController.store.subscribe(this.onStoreUpdate); this.onStoreUpdate(); } @@ -217,11 +264,10 @@ export class ActivityListController extends BaseController { */ private parseWatchedTransactions( chainId: number, - selectedAddress: string + selectedAddress: string, + transactions: TransactionWatcherControllerState['transactions'] = this._transactionWatcherController.store.getState() + .transactions ): TransactionMeta[] { - const { transactions } = - this._transactionWatcherController.store.getState(); - const watchedTransactions: TransactionMeta[] = []; if (chainId in transactions) { diff --git a/packages/background/src/controllers/AddressBookController.ts b/packages/background/src/controllers/AddressBookController.ts index 3e075d083..c9d1d38f0 100644 --- a/packages/background/src/controllers/AddressBookController.ts +++ b/packages/background/src/controllers/AddressBookController.ts @@ -8,6 +8,7 @@ import { TransactionMeta, } from './transactions/utils/types'; import { PreferencesController } from './PreferencesController'; +import { isEqual } from 'lodash'; import { isNativeTokenAddress } from '../utils/token'; import { formatName } from '../utils/account'; @@ -356,15 +357,22 @@ export class AddressBookController extends BaseController { +export default class AppStateController extends BaseController< + AppStateControllerState, + AppStateControllerMemState +> { private _timer: ReturnType | null; + private _stickyStorageTimer: ReturnType | undefined; constructor( initState: AppStateControllerState, private readonly _keyringController: KeyringControllerDerivated, private readonly _transactionController: TransactionController ) { - super(initState); + super(initState, { + idleTimeout: initState.idleTimeout, + isAppUnlocked: initState.isAppUnlocked, + lockedByTimeout: initState.lockedByTimeout, + expiredStickyStorage: false, + }); this._timer = null; @@ -45,6 +63,28 @@ export default class AppStateController extends BaseController { + //To avoid sending the lastActiveTime to the UI, update the UIStore based on the store data. + + if (newState.isAppUnlocked !== oldState?.isAppUnlocked) { + this.UIStore.updateState({ + isAppUnlocked: newState.isAppUnlocked, + lockedByTimeout: newState.lockedByTimeout, + }); + return; + } + + if (newState.idleTimeout !== oldState?.idleTimeout) { + this.UIStore.updateState({ + idleTimeout: newState.idleTimeout, + }); + } + } + ); } /** @@ -54,12 +94,9 @@ export default class AppStateController extends BaseController { this.store.updateState({ lastActiveTime: new Date().getTime() }); this._resetTimer(); + this._resetStickyStorageTimer(); }; - public get lastActiveTime(): number { - return this.lastActiveTime; - } - /** * Set a custom time in minutes for the extension auto block * The idle timeout should be greater than zero @@ -139,6 +176,19 @@ export default class AppStateController extends BaseController { + if (this._stickyStorageTimer) { + clearTimeout(this._stickyStorageTimer); + } + //only update UIStore when it is necessary. + if (this.UIStore.getState().expiredStickyStorage) { + this.UIStore.updateState({ expiredStickyStorage: false }); + } + + this._stickyStorageTimer = setTimeout(() => { + this.UIStore.updateState({ expiredStickyStorage: true }); + }, STICKY_STORAGE_DATA_TTL); + }; public autoUnlock = async (): Promise => { if (isManifestV3()) { const { isAppUnlocked } = this.store.getState(); @@ -176,6 +226,7 @@ export default class AppStateController extends BaseController; private readonly UIStore: ComposedStore; + private readonly exchangeRatesStore: ComposedStore; + private readonly gasPricesStore: ComposedStore; + private readonly activityListStore: ComposedStore; + private readonly STORES: Record>; private readonly _devTools: any; @@ -519,19 +529,28 @@ export default class BlankController extends EventEmitter { CampaignsController: this.campaignsController.store, }); + this.exchangeRatesStore = new ComposedStore({ + ExchangeRatesController: this.exchangeRatesController.store, + }); + + this.gasPricesStore = new ComposedStore({ + GasPricesController: this.gasPricesController.store, + }); + + this.activityListStore = new ComposedStore({ + ActivityListController: this.activityListController.store, + }); + this.UIStore = new ComposedStore({ NetworkController: this.networkController.store, - AppStateController: this.appStateController.store, + AppStateController: this.appStateController.UIStore, OnboardingController: this.onboardingController.store, KeyringController: this.keyringController.memStore, AccountTrackerController: this.accountTrackerController.store, PreferencesController: this.preferencesController.store, TransactionController: this.transactionController.UIStore, - ExchangeRatesController: this.exchangeRatesController.store, - GasPricesController: this.gasPricesController.store, BlankDepositController: this.privacyController.UIStore, TokenController: this.tokenController.store, - ActivityListController: this.activityListController.store, PermissionsController: this.permissionsController.store, AddressBookController: this.addressBookController.store, BlankProviderController: this.blankProviderController.store, @@ -540,6 +559,13 @@ export default class BlankController extends EventEmitter { OnrampController: this.onrampController.store, }); + this.STORES = { + [StateType.APP_STATE]: this.UIStore, + [StateType.EXCHANGE_RATES]: this.exchangeRatesStore, + [StateType.GAS_PRICES]: this.gasPricesStore, + [StateType.ACTIVITY_LIST]: this.activityListStore, + }; + // Check controllers on app lock/unlock this.appStateController.on(AppStateEvents.APP_LOCKED, () => { this.manageControllers(); @@ -967,7 +993,13 @@ export default class BlankController extends EventEmitter { case Messages.STATE.GET_REMOTE_CONFIG: return this.getRemoteConifg(); case Messages.STATE.GET: - return this.getState(); + return this.getState(request as RequestGetState); + case Messages.STATE.SUBSCRIBE: + return this.subscribeState( + id, + port, + (request as RequestSubscribeState).stateType + ); case Messages.TRANSACTION.CONFIRM: return this.confirmTransaction( request as RequestConfirmTransaction @@ -1064,8 +1096,6 @@ export default class BlankController extends EventEmitter { return this.completeSetup(request as RequestCompleteSetup); case Messages.WALLET.REQUEST_SEED_PHRASE: return this.getSeedPhrase(request as RequestSeedPhrase); - case Messages.STATE.SUBSCRIBE: - return this.stateSubscribe(id, port); case Messages.TOKEN.GET_BALANCE: return this.getTokenBalance(request as RequestGetTokenBalance); case Messages.TOKEN.GET_TOKENS: @@ -2202,8 +2232,8 @@ export default class BlankController extends EventEmitter { * Get UI State * */ - private getState(): Flatten { - return this.UIStore.flatState; + private getState(r: RequestGetState): ResponseGetState { + return this.STORES[r.stateType].flatState; } private getRemoteConifg(): RemoteConfigsControllerState { @@ -2847,22 +2877,28 @@ export default class BlankController extends EventEmitter { * State subscription method * */ - private stateSubscribe(id: string, port: browser.Runtime.Port): boolean { + private subscribeState( + id: string, + port: browser.Runtime.Port, + stateType: StateType + ): boolean { + const store = this.STORES[stateType]; + const cb = this.createSubscription( id, port ); const sendState = () => { - const flatState = this.UIStore.flatState; + const flatState = store.flatState; cb(flatState); }; - this.UIStore.subscribe(sendState); + store.subscribe(sendState); port.onDisconnect.addListener((): void => { this.unsubscribe(id); - this.UIStore.unsubscribe(sendState); + store.unsubscribe(sendState); }); return true; diff --git a/packages/background/src/controllers/BridgeController.ts b/packages/background/src/controllers/BridgeController.ts index 7a176d60e..8ad00677c 100644 --- a/packages/background/src/controllers/BridgeController.ts +++ b/packages/background/src/controllers/BridgeController.ts @@ -49,7 +49,10 @@ import { BaseController } from '../infrastructure/BaseController'; import TokenAllowanceController from './erc-20/transactions//TokenAllowanceController'; import { fillTokenData, isNativeTokenAddress } from '../utils/token'; import { AccountTrackerController } from './AccountTrackerController'; +import { pruneTransaction } from './transactions/utils/utils'; import { unixTimestampToJSTimestamp } from '../utils/timestamp'; + +//Constants const TIMEOUT_FETCH_RECEIVING_TX = 2 * HOUR; const STATUS_API_CALLS_DELAY = 30 * SECOND; const BRIDGE_STATUS_INVALID_MAX_COUNT = 10; @@ -712,10 +715,10 @@ export default class BridgeController extends BaseController< }; const chainTx = stateTransactions[chainId] || {}; const addrTransactions = chainTx[address] || {}; - const newTransaction = { + const newTransaction = pruneTransaction({ ...(addrTransactions[txHash] || {}), ...updates, - }; + }); this.store.updateState({ bridgeReceivingTransactions: { ...stateTransactions, diff --git a/packages/background/src/controllers/TransactionWatcherController.ts b/packages/background/src/controllers/TransactionWatcherController.ts index 5c8278dbb..f83235fca 100644 --- a/packages/background/src/controllers/TransactionWatcherController.ts +++ b/packages/background/src/controllers/TransactionWatcherController.ts @@ -32,7 +32,7 @@ import { SignedTransaction } from './erc-20/transactions/SignedTransaction'; import { TransactionArgument } from './transactions/ContractSignatureParser'; import TransactionController from './transactions/TransactionController'; import { fetchBlockWithRetries } from '../utils/blockFetch'; -import { isNil } from 'lodash'; +import { cloneDeep, isNil } from 'lodash'; import { paddedToChecksumAddress } from '../utils/addressUtils'; import { RPCLogsFetcher } from '../utils/rpc/RPCLogsFetcher'; import { EtherscanFetcher } from '../utils/scanner/EtherscanFetcher'; @@ -287,7 +287,7 @@ export class TransactionWatcherController extends BaseController { const transactions = this.store.getState().transactions.map((tx) => { if (tx.id === txId) { + const prunedTx = pruneTransaction(tx); return { - ...tx, + ...prunedTx, ...updates, }; } diff --git a/packages/background/src/controllers/transactions/utils/utils.ts b/packages/background/src/controllers/transactions/utils/utils.ts index 7f5db53b5..cfea97c56 100644 --- a/packages/background/src/controllers/transactions/utils/utils.ts +++ b/packages/background/src/controllers/transactions/utils/utils.ts @@ -358,6 +358,19 @@ export function normalizeEnsName(ensName: string): string | null { return null; } +export function pruneTransaction(tx: TransactionMeta): TransactionMeta { + if (tx.transactionReceipt) { + return { + ...tx, + transactionReceipt: { + ...tx.transactionReceipt, + logs: [], + }, + }; + } + return tx; +} + export function resolveAllownaceParamsFromTransaction( transactionMeta: TransactionMeta ): { spenderAddress: string; tokenAddress: string } | undefined { diff --git a/packages/background/src/infrastructure/stores/migrator/migrations/migration-74.ts b/packages/background/src/infrastructure/stores/migrator/migrations/migration-74.ts new file mode 100644 index 000000000..7093d5098 --- /dev/null +++ b/packages/background/src/infrastructure/stores/migrator/migrations/migration-74.ts @@ -0,0 +1,104 @@ +import { BridgeControllerState } from '@block-wallet/background/controllers/BridgeController'; +import { pruneTransaction } from '../../../../controllers/transactions/utils/utils'; +import { TransactionWatcherControllerState } from '../../../../controllers/TransactionWatcherController'; +import { BlankAppState } from '@block-wallet/background/utils/constants/initialState'; +import { IMigration } from '../IMigration'; +import { WatchedTransactionType } from '../../../../controllers/transactions/utils/types'; + +const pruneBridgeTxs = ( + txs: BridgeControllerState['bridgeReceivingTransactions'] +): BridgeControllerState['bridgeReceivingTransactions'] => { + const newTxs = { ...txs }; + for (const chainId in newTxs) { + const chainTxs = newTxs[chainId]; + if (chainTxs) { + for (const addr in chainTxs) { + const addrTxs = chainTxs[addr]; + if (addrTxs) { + newTxs[chainId][addr] = Object.entries(addrTxs).reduce( + (acc, [txHash, tx]) => { + return { + ...acc, + [txHash]: pruneTransaction(tx), + }; + }, + addrTxs + ); + } + } + } + } + return newTxs; +}; + +const pruneWatchedTxs = ( + txs: TransactionWatcherControllerState['transactions'] +): TransactionWatcherControllerState['transactions'] => { + const newTxs = { ...txs }; + for (const chainId in newTxs) { + const chainTxs = newTxs[chainId]; + if (chainTxs) { + for (const addr in chainTxs) { + const addrTxs = chainTxs[addr]; + if (addrTxs) { + for (const type in addrTxs) { + const typeTxs = addrTxs[type as WatchedTransactionType]; + if (typeTxs && typeTxs.transactions) { + newTxs[chainId][addr][ + type as WatchedTransactionType + ].transactions = Object.entries( + typeTxs.transactions + ).reduce((acc, [txHash, tx]) => { + return { + ...acc, + [txHash]: pruneTransaction(tx), + }; + }, typeTxs.transactions); + } + } + } + } + } + } + return newTxs; +}; + +/** + * This migration fixes zksync block explorer + */ +export default { + migrate: async (persistedState: BlankAppState) => { + const { transactions } = persistedState.TransactionController; + const { bridgeReceivingTransactions } = persistedState.BridgeController; + const { transactions: watchedTx } = + persistedState.TransactionWatcherControllerState; + + const newTxsState = transactions + ? transactions.map(pruneTransaction) + : transactions; + + const newBridgeReceivingTxState = bridgeReceivingTransactions + ? pruneBridgeTxs(bridgeReceivingTransactions) + : bridgeReceivingTransactions; + + const newWatchedTxsState = watchedTx + ? pruneWatchedTxs(watchedTx) + : watchedTx; + + return { + ...persistedState, + TransactionController: { + ...persistedState.TransactionController, + transactions: newTxsState, + }, + BridgeController: { + ...persistedState.BridgeController, + bridgeReceivingTransactions: newBridgeReceivingTxState, + }, + TransactionWatcherControllerState: { + transactions: newWatchedTxsState, + }, + }; + }, + version: '2.0.0', +} as IMigration; diff --git a/packages/background/src/utils/constants/initialState.ts b/packages/background/src/utils/constants/initialState.ts index 0d03d3a87..78b1fbfbc 100644 --- a/packages/background/src/utils/constants/initialState.ts +++ b/packages/background/src/utils/constants/initialState.ts @@ -6,7 +6,10 @@ import { ValuesOf } from '../types/helpers'; import { IObservableStore } from '../../infrastructure/stores/ObservableStore'; import { AccountTrackerState } from '../../controllers/AccountTrackerController'; -import { AppStateControllerState } from '../../controllers/AppStateController'; +import { + AppStateControllerMemState, + AppStateControllerState, +} from '../../controllers/AppStateController'; import { OnboardingControllerState } from '../../controllers/OnboardingController'; import { PreferencesControllerState } from '../../controllers/PreferencesController'; import { ExchangeRatesControllerState } from '../../controllers/ExchangeRatesController'; @@ -77,15 +80,12 @@ export type BlankAppState = { export type BlankAppUIState = { AccountTrackerController: AccountTrackerState; - AppStateController: AppStateControllerState; + AppStateController: AppStateControllerMemState; KeyringController: KeyringControllerMemState; OnboardingController: OnboardingControllerState; PreferencesController: PreferencesControllerState; TransactionController: TransactionVolatileControllerState; BlankDepositController: PrivacyControllerUIStoreState; - ExchangeRatesController: ExchangeRatesControllerState; - GasPricesController: GasPricesControllerState; - ActivityListController: IActivityListState; TokenController: TokenControllerState; PermissionsController: PermissionsControllerState; NetworkController: NetworkControllerState; @@ -96,6 +96,20 @@ export type BlankAppUIState = { OnrampController: OnrampControllerMemState; }; +export type ExchangeRatesUIState = { + ExchangeRatesController: ExchangeRatesControllerState; +}; + +export type GasPricesUIState = { + GasPricesController: GasPricesControllerState; +}; + +export type ActivityListUIState = { + ActivityListController: IActivityListState; +}; + +export type UIState = BlankAppUIState | ExchangeRatesUIState | GasPricesUIState; + export type BlankAppStoreConfig = { [controller in keyof Partial]: IObservableStore>; }; diff --git a/packages/background/src/utils/types/communication.ts b/packages/background/src/utils/types/communication.ts index 099e84f1e..7fee1cf4a 100644 --- a/packages/background/src/utils/types/communication.ts +++ b/packages/background/src/utils/types/communication.ts @@ -1,6 +1,11 @@ /* eslint-disable @typescript-eslint/no-empty-interface */ import { Flatten } from './helpers'; -import { BlankAppUIState } from '../constants/initialState'; +import { + ActivityListUIState, + ExchangeRatesUIState, + GasPricesUIState, + BlankAppUIState, +} from '../constants/initialState'; import { BigNumber } from '@ethersproject/bignumber'; import { AccountInfo, @@ -438,7 +443,16 @@ export interface RequestSignatures { RequestUpdateSitePermissions, boolean ]; - [Messages.STATE.GET]: [undefined, ResponseGetState]; + [Messages.STATE.GET]: [RequestGetState, ResponseGetState]; + [Messages.STATE.SUBSCRIBE]: [ + RequestSubscribeState, + boolean, + StateSubscription + ]; + [Messages.STATE.GET_REMOTE_CONFIG]: [ + undefined, + RemoteConfigsControllerState + ]; [Messages.ENS.RESOLVE_NAME]: [RequestEnsResolve, string | null]; [Messages.ENS.LOOKUP_ADDRESS]: [RequestEnsLookup, string | null]; [Messages.UD.RESOLVE_NAME]: [RequestUDResolve, string | null]; @@ -508,11 +522,6 @@ export interface RequestSignatures { [Messages.WALLET.REQUEST_SEED_PHRASE]: [RequestSeedPhrase, string]; [Messages.WALLET.SETUP_COMPLETE]: [RequestCompleteSetup, void]; [Messages.WALLET.RESET]: [RequestWalletReset, boolean]; - [Messages.STATE.SUBSCRIBE]: [undefined, boolean, StateSubscription]; - [Messages.STATE.GET_REMOTE_CONFIG]: [ - undefined, - RemoteConfigsControllerState - ]; [Messages.TOKEN.GET_BALANCE]: [RequestGetTokenBalance, BigNumber]; [Messages.TOKEN.GET_TOKENS]: [RequestGetTokens, ITokens]; [Messages.TOKEN.GET_USER_TOKENS]: [RequestGetUserTokens, ITokens]; @@ -1151,13 +1160,31 @@ export type ResponseTypes = { export type ResponseType = RequestSignatures[TMessageType][1]; -export type ResponseGetState = Flatten; +export interface ResponseBlankGetWithdrawalGasCost { + estimatedGas: BigNumber; + fee: BigNumber; + total: BigNumber; +} + +export type ResponseGetAppState = Flatten; +export type ResponseGetExchangeRatesState = Flatten; +export type ResponseGetGasPricesState = Flatten; +export type ResponseGetActivityListState = Flatten; + +export type ResponseGetState = + | ResponseGetAppState + | ResponseGetExchangeRatesState + | ResponseGetGasPricesState + | ResponseGetActivityListState; export type SubscriptionMessageTypes = { [MessageType in keyof RequestSignatures]: RequestSignatures[MessageType][2]; }; -export type StateSubscription = Flatten; +export type AppStateSubscription = Flatten; +export type ExchangeRatesStateSubscription = Flatten; +export type GasPricesStateSubscription = Flatten; +export type ActivityListStateSubscription = Flatten; export interface ExternalEventSubscription { eventName: ProviderEvents; @@ -1249,6 +1276,30 @@ export enum BackgroundActions { CLOSE_WINDOW = 'CLOSE_WINDOW', } +export enum StateType { + APP_STATE = 'APP_STATE', + EXCHANGE_RATES = 'EXCHANGE_RATES', + GAS_PRICES = 'GAS_PRICES', + ACTIVITY_LIST = 'ACTIVITY_LIST', +} + +export interface RequestSubscribeState { + stateType: StateType; +} + +export interface RequestGetState { + stateType: StateType; +} + +export type StateSubscription = + | AppStateSubscription + | ExchangeRatesStateSubscription + | GasPricesStateSubscription + | ActivityListStateSubscription; +export interface RequestSetHotkeys { + enabled: boolean; +} + export interface RequestSetHotkeys { enabled: boolean; } diff --git a/packages/background/test/controllers/BlankProviderController.test.ts b/packages/background/test/controllers/BlankProviderController.test.ts index a6f102bae..cf0e199a0 100644 --- a/packages/background/test/controllers/BlankProviderController.test.ts +++ b/packages/background/test/controllers/BlankProviderController.test.ts @@ -195,8 +195,8 @@ describe('Blank Provider Controller', function () { { idleTimeout: defaultIdleTimeout, isAppUnlocked: true, - lastActiveTime: new Date().getTime(), lockedByTimeout: false, + lastActiveTime: new Date().getTime(), }, mockKeyringController, transactionController @@ -416,8 +416,9 @@ describe('Blank Provider Controller', function () { sinon.stub(appStateController.UIStore, 'getState').returns({ isAppUnlocked: true, - lastActiveTime: new Date().getTime(), + expiredStickyStorage: false, lockedByTimeout: false, + idleTimeout: 2000, }); sinon.stub(appStateController.store, 'getState').returns({ isAppUnlocked: true, diff --git a/packages/background/test/controllers/transactions/TransactionController.test.ts b/packages/background/test/controllers/transactions/TransactionController.test.ts index 9a9d55256..0691c9df4 100644 --- a/packages/background/test/controllers/transactions/TransactionController.test.ts +++ b/packages/background/test/controllers/transactions/TransactionController.test.ts @@ -1531,6 +1531,7 @@ describe('Transactions Controller', () => { .transactionReceipt ).to.be.deep.equal({ status: 0, + logs: [], }); }); diff --git a/packages/ui/package.json b/packages/ui/package.json index a21c064f0..4714b36a9 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -36,6 +36,7 @@ "react-router-dom": "^5.2.0", "react-router-last-location": "^2.0.1", "react-transition-group": "^4.4.5", + "react-virtualized": "^9.22.5", "react-virtualized-auto-sizer": "^1.0.20", "react-window": "^1.8.6", "stream-http": "^3.2.0", @@ -65,6 +66,7 @@ "@types/react-modal": "^3.16.0", "@types/react-router-dom": "^5.3.0", "@types/react-transition-group": "^4.4.5", + "@types/react-virtualized": "^9.21.23", "@types/react-virtualized-auto-sizer": "^1.0.1", "@types/react-window": "^1.8.5", "@types/styled-components": "^5.1.9", diff --git a/packages/ui/src/App.tsx b/packages/ui/src/App.tsx index e0f279ee9..9444744b1 100644 --- a/packages/ui/src/App.tsx +++ b/packages/ui/src/App.tsx @@ -7,8 +7,13 @@ import { isPopup } from "./context/util/isPopup" import PopupRouter from "./router/PopupRouter" import TabRouter from "./router/TabRouter" import { WindowIdProvider } from "./context/hooks/useWindowId" +import { Profiler } from "react" +import useMetricCollector from "./util/useMetricCollector" +import { GasPricesStateProvider } from "./context/background/useGasPricesState" +import { ExchangeRatesStateProvider } from "./context/background/useExchangeRatesState" +import { ActivityListStateProvider } from "./context/background/useActivityListState" -const AppLoading = () => { +export const AppLoading = () => { return (
@@ -22,7 +27,17 @@ const App = () => { - {isPopup() ? : } + {isPopup() ? ( + + + + + + + + ) : ( + + )} ) : ( @@ -30,10 +45,15 @@ const App = () => { ) } -const WrappedApp = () => ( - - - -) +const WrappedApp = () => { + const collect = useMetricCollector() + return ( + + + + + + ) +} export default WrappedApp diff --git a/packages/ui/src/components/ActivityList.tsx b/packages/ui/src/components/ActivityList.tsx deleted file mode 100644 index 13299b7cd..000000000 --- a/packages/ui/src/components/ActivityList.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import TransactionsList from "./transactions/TransactionsList" - -// Context -import { useSelectedNetwork } from "../context/hooks/useSelectedNetwork" -import { useSelectedAccount } from "../context/hooks/useSelectedAccount" - -// Utils - -import useTransactions from "../util/hooks/useTransactions" - -const ActivityList = () => { - const { chainId } = useSelectedNetwork() - const { address } = useSelectedAccount() - - const { transactions } = useTransactions() - - return ( -
- -
- ) -} - -export default ActivityList diff --git a/packages/ui/src/components/AssetsList.tsx b/packages/ui/src/components/AssetsList.tsx deleted file mode 100644 index ac16d6703..000000000 --- a/packages/ui/src/components/AssetsList.tsx +++ /dev/null @@ -1,223 +0,0 @@ -import { BigNumber } from "@ethersproject/bignumber" -import { Fragment, FunctionComponent, useEffect, useRef, useState } from "react" -import { useOnMountHistory } from "../context/hooks/useOnMount" -import { Token } from "@block-wallet/background/controllers/erc-20/Token" -import { - TokenList, - useTokenListWithNativeToken, -} from "../context/hooks/useTokensList" -import { formatUnits } from "@ethersproject/units" - -import plus from "../assets/images/icons/plus.svg" -import ChevronRightIcon from "./icons/ChevronRightIcon" -import { formatRounded } from "../util/formatRounded" -import { ActionButton } from "./button/ActionButton" -import AssetsLoadingSkeleton from "./skeleton/AssetsLoadingSkeleton" -import useCurrencyFromatter from "../util/hooks/useCurrencyFormatter" -import { AssetsSortOptions, isNativeTokenAddress } from "../util/tokenUtils" -import { useBlankState } from "../context/background/backgroundHooks" -import TokenLogo from "./token/TokenLogo" -import SearchInput from "./input/SearchInput" -import AssetsSort from "./assets/AssetsSort" -import useTokenSearch from "../util/hooks/token/useTokenSearch" -import AssetsButton from "./assets/AssetsButton" -import order from "../assets/images/icons/order.svg" -import { setTokensSortValue } from "../context/commActions" - -export type AssetItem = { - token: Token - balance: BigNumber -} - -const Asset: FunctionComponent<{ - asset: AssetItem - pushDeleteTokens: Function -}> = ({ asset }) => { - const history: any = useOnMountHistory() - const formatter = useCurrencyFromatter() - return ( -
- history.push({ - pathname: `/asset/details`, - state: { - address: asset.token.address, - transitionDirection: "left", - }, - }) - } - className="flex flex-row items-center justify-between px-6 py-4 -ml-6 transition duration-300 hover:bg-primary-grey-default hover:bg-opacity-50 active:bg-primary-grey-hover active:bg-opacity-50 cursor-pointer" - style={{ width: "calc(100% + 2 * 1.5rem)" }} - role="listitem" - aria-label={asset.token.symbol} - > -
- -
- - {`${formatRounded( - formatUnits( - asset.balance || "0", - asset.token.decimals - ), - 4 - )} - ${asset.token.symbol}`} - - - {formatter.format( - asset.balance || BigNumber.from(0), - asset.token.symbol, - asset.token.decimals, - isNativeTokenAddress(asset.token.address) - )} - -
-
-
- -
-
- ) -} - -const SubAssetList: FunctionComponent<{ assets: TokenList }> = ({ assets }) => { - const { isNetworkChanging } = useBlankState()! - - const [deletedTokens, setDeletedTokens] = useState([] as string[]) - const pushDeleteTokens = (deleteToken: string) => { - setDeletedTokens([...deletedTokens, deleteToken]) - } - - // the action of delete a token is not sync, we include this blick of code for not showing deleted tokens while they are being deleted. - const newDeleted: string[] = [] - deletedTokens.forEach((t) => { - if (assets.map((a) => a.token.address).includes(t)) { - newDeleted.push(t) - } - }) - if (deletedTokens.length !== newDeleted.length) { - setDeletedTokens(newDeleted) - } - - return ( -
- {isNetworkChanging ? ( - - ) : ( - assets - .filter((t) => !deletedTokens.includes(t.token.address)) - .map((a, i) => ( - - {i > 0 ?
: null} - -
- )) - )} -
- ) -} - -const AssetsList = () => { - const { tokensSortValue } = useBlankState()! - // const { chainId } = useSelectedNetwork() - const history = useOnMountHistory() - const [sortValue, setSortValue] = useState( - tokensSortValue as AssetsSortOptions - ) - const currentNetworkTokens = useTokenListWithNativeToken(sortValue) - const searchInputRef = useRef(null) - const { search, tokensResult, onChangeSearch } = - useTokenSearch(currentNetworkTokens) - - useEffect(() => { - const updateSortValue = async () => { - await setTokensSortValue(sortValue) - } - - if (sortValue !== tokensSortValue) { - updateSortValue() - } - }, [sortValue, tokensSortValue]) - - return ( - <> -
-
-
- { - onChangeSearch(e.target.value) - }} - debounced - defaultValue={search} - ref={searchInputRef} - showClearIcon={true} - /> -
- { - history.push({ - pathname: "/settings/tokens/add", - }) - }} - title="Add Token" - icon={plus} - /> - - { - history.push({ - pathname: "/accounts/menu/tokensOrder", - state: { isFromHomePage: true }, - }) - }} - title="Edit Assets Order" - icon={order} - disabled={sortValue !== AssetsSortOptions.CUSTOM} - /> -
-
-
-
- -
-
- -
-
- - ) -} - -export default AssetsList diff --git a/packages/ui/src/components/allowances/AllowanceItem.tsx b/packages/ui/src/components/allowances/AllowanceItem.tsx index 20f62ba37..682e2bf0a 100644 --- a/packages/ui/src/components/allowances/AllowanceItem.tsx +++ b/packages/ui/src/components/allowances/AllowanceItem.tsx @@ -28,12 +28,14 @@ const AllowanceItem = ({ spender, showToken = false, fromAssetDetails = false, + className, }: { allowance: TokenAllowance token: AllowanceDisplayData spender: AllowanceDisplayData showToken?: boolean fromAssetDetails?: boolean + className?: string }) => { const history = useOnMountHistory() const { selectedNetwork, availableNetworks } = useBlankState()! @@ -164,9 +166,10 @@ const AllowanceItem = ({ }} className={classnames( "flex flex-row items-center justify-between py-4 mr-1 transition duration-300 -ml-6 px-6 w-[calc(100%+3rem)]", + className, !isHoveringButton && !open && - "hover:cursor-pointer hover:bg-primary-grey-default hover:bg-opacity-50 active:bg-primary-grey-hover active:bg-opacity-50" + "hover:cursor-pointer hover:bg-primary-grey-default hover:bg-opacity-50 active:bg-primary-grey-hover active:bg-opacity-50 bg-clip-padding" )} > { +const ActivityAllowancesView: FC<{ tokenAddress: string }> = ({ + tokenAddress, +}) => { const history = useOnMountHistory() const [tab, setTab] = useState( history.location.state.tab === TabLabels.ALLOWANCES ? tabs[1] : tabs[0] ) const TabComponent = tab.component - const tokenAddress: string = history.location.state.address const allowances = useAccountAllowances( AllowancesFilters.TOKEN, @@ -44,7 +45,7 @@ const ActivityAllowancesView = () => { } return ( -
+
{ + const { isNetworkChanging } = useBlankState()! const history: any = useOnMountHistory() const tokenAddress: string = history.location.state.address const token = useGetAssetByTokenAddress(tokenAddress)?.token const tokenTransactions = useTokenTransactions(token) return ( - <> +
{tokenTransactions.length > 0 ? ( - + ) : ( You have no transactions. )} - +
) } diff --git a/packages/ui/src/components/assets/AssetAllowances.tsx b/packages/ui/src/components/assets/AssetAllowances.tsx index 941273505..d5a6f80fe 100644 --- a/packages/ui/src/components/assets/AssetAllowances.tsx +++ b/packages/ui/src/components/assets/AssetAllowances.tsx @@ -29,13 +29,18 @@ const AssetAllowances = () => { allowance.displayData.address } > - {index > 0 &&
} + {index > 0 && ( +
+
+
+ )}
)) @@ -44,7 +49,7 @@ const AssetAllowances = () => { {emptyMessage} )} -
+
} label="Manage Allowances" diff --git a/packages/ui/src/components/assets/AssetDetailsPage.tsx b/packages/ui/src/components/assets/AssetDetailsPage.tsx index 81a049834..0b371b878 100644 --- a/packages/ui/src/components/assets/AssetDetailsPage.tsx +++ b/packages/ui/src/components/assets/AssetDetailsPage.tsx @@ -1,6 +1,5 @@ import { formatUnits } from "@ethersproject/units" import { useState } from "react" -import { Link } from "react-router-dom" import { deleteCustomToken } from "../../context/commActions" import { useOnMountHistory } from "../../context/hooks/useOnMount" import { useSelectedAccount } from "../../context/hooks/useSelectedAccount" @@ -11,29 +10,28 @@ import useCurrencyFromatter from "../../util/hooks/useCurrencyFormatter" import useGetAssetByTokenAddress from "../../util/hooks/useGetAssetByTokenAddress" import { useBlankState } from "../../context/background/backgroundHooks" import { generateExplorerLink, getExplorerTitle } from "../../util/getExplorer" -import RoundedIconButton from "../button/RoundedIconButton" -import AnimatedIcon, { AnimatedIconName } from "../../components/AnimatedIcon" -import ArrowHoverAnimation from "../icons/ArrowHoverAnimation" import openExternal from "../../assets/images/icons/open_external.svg" import PopupHeader from "../popup/PopupHeader" import PopupLayout from "../popup/PopupLayout" import TokenSummary from "../token/TokenSummary" - import log from "loglevel" import ConfirmDialog from "../dialog/ConfirmDialog" import { isNativeTokenAddress } from "../../util/tokenUtils" import SuccessDialog from "../dialog/SuccessDialog" import { formatName } from "../../util/formatAccount" import Icon, { IconName } from "../ui/Icon" -import DoubleArrowHoverAnimation from "../icons/DoubleArrowHoverAnimation" +import { useExchangeRatesState } from "../../context/background/useExchangeRatesState" import ActivityAllowancesView from "./ActivityAllowancesView" import TokenLogo from "../token/TokenLogo" +import PanelButtons from "../home/PanelButtons" const AssetDetailsPage = () => { const state = useBlankState()! const history: any = useOnMountHistory() const address = history.location.state.address - + const { + state: { isRatesChangingAfterNetworkChange }, + } = useExchangeRatesState() const { availableNetworks, selectedNetwork } = useBlankState()! const account = useSelectedAccount() @@ -182,6 +180,7 @@ const AssetDetailsPage = () => { { {`${roundedTokenBalance} ${token.symbol}`} - + {currencyFormatter.format( balance, token.symbol, @@ -199,103 +200,38 @@ const AssetDetailsPage = () => { )} - - + - - Send - - + /> {isSwapEnabled && ( - -
- -
- - Swap - - + /> )} {isBridgeEnabled && ( - -
- {disabledActions ? ( - - ) : ( - - )} -
- - Bridge - - + /> )}
- +
) diff --git a/packages/ui/src/components/assets/AssetSelection.tsx b/packages/ui/src/components/assets/AssetSelection.tsx index 60e39da60..68285599e 100644 --- a/packages/ui/src/components/assets/AssetSelection.tsx +++ b/packages/ui/src/components/assets/AssetSelection.tsx @@ -19,7 +19,7 @@ import { searchTokenInAssetsList } from "../../context/commActions" import { useCustomCompareEffect } from "use-custom-compare" import { useSwappedTokenList } from "../../context/hooks/useSwappedTokenList" import AssetDropdownDisplay from "./AssetDropdownDisplay" -import AssetList from "./AssetList" +import AssetsDropdownList from "./AssetsDropdownList" import { Token } from "@block-wallet/background/controllers/erc-20/Token" import { useBlankState } from "../../context/background/backgroundHooks" import { AssetsSortOptions } from "../../util/tokenUtils" @@ -305,7 +305,7 @@ export const AssetSelection: FC = ({ defaultValue={search ?? ""} />
- void onAssetClick: (asset: TokenWithBalance, setActive?: () => void) => void selectedAddress?: string @@ -70,4 +70,4 @@ const AssetList: FC<{ ) } -export default AssetList +export default AssetsDropdownList diff --git a/packages/ui/src/components/button/RoundedIconButton.tsx b/packages/ui/src/components/button/RoundedIconButton.tsx index 521bf2a10..e2650f44b 100644 --- a/packages/ui/src/components/button/RoundedIconButton.tsx +++ b/packages/ui/src/components/button/RoundedIconButton.tsx @@ -1,16 +1,30 @@ import { FC } from "react" import classnames from "classnames" +import AnimatedIcon, { AnimatedIconName } from "../AnimatedIcon" interface RoundedIconButtonProps { Icon: React.ElementType disabled: boolean children: React.ReactNode + isLoading?: boolean +} + +export const RoundedLoadingButton = () => { + return ( +
+ +
+ ) } const RoundedIconButton: FC = ({ children, disabled, Icon, + isLoading, }) => { return ( <> @@ -21,7 +35,7 @@ const RoundedIconButton: FC = ({ )} style={{ transform: "scaleY(-1)" }} > - + {isLoading ? : }
{children} diff --git a/packages/ui/src/components/home/AccountAvatar.tsx b/packages/ui/src/components/home/AccountAvatar.tsx new file mode 100644 index 000000000..af5c96b87 --- /dev/null +++ b/packages/ui/src/components/home/AccountAvatar.tsx @@ -0,0 +1,33 @@ +import { useBlankState } from "../../context/background/backgroundHooks" +import { useSelectedAccount } from "../../context/hooks/useSelectedAccount" +import { formatHash, formatName } from "../../util/formatAccount" +import useCopyToClipboard from "../../util/hooks/useCopyToClipboard" +import CopyTooltip from "../label/СopyToClipboardTooltip" + +const AccountAvatar = () => { + const blankState = useBlankState()! + const accountAddress = blankState.selectedAddress + const account = useSelectedAccount() + const { onCopy, copied } = useCopyToClipboard(accountAddress) + + return ( + + ) +} +export default AccountAvatar diff --git a/packages/ui/src/components/ActivityAssetsView.tsx b/packages/ui/src/components/home/ActivityAssetsView.tsx similarity index 50% rename from packages/ui/src/components/ActivityAssetsView.tsx rename to packages/ui/src/components/home/ActivityAssetsView.tsx index d6c4c6d49..585761226 100644 --- a/packages/ui/src/components/ActivityAssetsView.tsx +++ b/packages/ui/src/components/home/ActivityAssetsView.tsx @@ -1,13 +1,9 @@ +import { FunctionComponent, useState } from "react" import { PopupTabs } from "@block-wallet/background/controllers/PreferencesController" -import { FunctionComponent, useEffect, useState } from "react" -import { useHotkeys } from "react-hotkeys-hook" -import { useBlankState } from "../context/background/backgroundHooks" -import { updatePopupTab } from "../context/commActions" -import { useOnMountHistory } from "../context/hooks/useOnMount" +import { updatePopupTab } from "../../context/commActions" import ActivityList from "./ActivityList" import AssetsList from "./AssetsList" -import HorizontalSelect from "./input/HorizontalSelect" -import { componentsHotkeys } from "../util/hotkeys" +import HorizontalSelect from "../input/HorizontalSelect" const tabs = [ { @@ -23,47 +19,15 @@ const tabs = [ const ActivityAssetsView: FunctionComponent<{ initialTab: PopupTabs }> = ({ initialTab, }) => { - const history = useOnMountHistory() - const { popupTab, hotkeysEnabled } = useBlankState()! const initialTabIndex = initialTab === "activity" ? 0 : 1 const [tab, setTab] = useState(tabs[initialTabIndex]) - const [currentTabLabel, setCurrentTabLabel] = useState(tab.label) const TabComponent = tab.component - const onTabChange = (value: { - label: string - component: () => JSX.Element - }) => { + const onTabChange = async (value: any) => { setTab(value) updatePopupTab(value.label.toLowerCase() as PopupTabs) } - //UseHotkeys changes state.popupTab, we do it to change the tab in real time, otherwise it will change only next time we open the extension - useEffect(() => { - setCurrentTabLabel(popupTab) - if (popupTab !== tab.label.toLocaleLowerCase()) { - const newTab = tabs.find( - (l) => l.label.toLocaleLowerCase() === popupTab - ) - if (newTab) onTabChange(newTab) - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [popupTab]) - - //Adding useHotkey to add new token, only on Assets View - const activityAssetsViewHotkeys = componentsHotkeys.ActivityAssetsView - useHotkeys(activityAssetsViewHotkeys, () => { - if (!hotkeysEnabled) return - if (currentTabLabel.toLocaleLowerCase() === "assets") { - history.push({ - pathname: "/settings/tokens/add", - state: { - from: history.location.pathname, - }, - }) - } - }) - return (
{ + const collect = useMetricCollector() + const { chainId } = useSelectedNetwork() + const { address } = useSelectedAccount() + const { isNetworkChanging } = useBlankState()! + const { transactions } = useActivtyListTransactions() + return ( + +
+ +
+
+ ) +} + +export default ActivityList diff --git a/packages/ui/src/components/home/AssetItem.tsx b/packages/ui/src/components/home/AssetItem.tsx new file mode 100644 index 000000000..27d9e65dd --- /dev/null +++ b/packages/ui/src/components/home/AssetItem.tsx @@ -0,0 +1,90 @@ +import { FC } from "react" +import { BigNumber } from "@ethersproject/bignumber" +import { useOnMountHistory } from "../../context/hooks/useOnMount" +import { Token } from "@block-wallet/background/controllers/erc-20/Token" +import ChevronRightIcon from "../icons/ChevronRightIcon" +import useCurrencyFromatter from "../../util/hooks/useCurrencyFormatter" +import { isNativeTokenAddress } from "../../util/tokenUtils" +import { useExchangeRatesState } from "../../context/background/useExchangeRatesState" +import AnimatedIcon, { AnimatedIconName } from "../AnimatedIcon" +import { formatAssetBalance } from "../../util/balance" +import TokenLogo from "../token/TokenLogo" +import { Classes } from "../../styles" + +export type AsssetData = { + token: Token + balance: BigNumber +} + +const AssetItem: FC<{ + asset: AsssetData + pushDeleteTokens: Function +}> = ({ asset: { balance, token } }) => { + const history: any = useOnMountHistory() + const formatter = useCurrencyFromatter() + const { + state: { isRatesChangingAfterNetworkChange }, + } = useExchangeRatesState() + + return ( +
+ history.push({ + pathname: `/asset/details`, + state: { + address: token.address, + transitionDirection: "left", + }, + }) + } + className="flex flex-row items-center justify-between px-6 py-5 -ml-6 transition duration-300 hover:bg-primary-100 hover:bg-opacity-50 active:bg-primary-200 active:bg-opacity-50 cursor-pointer" + style={{ width: "calc(100% + 2 * 1.5rem)" }} + role="listitem" + aria-label={token.symbol} + > +
+ +
+ + {formatAssetBalance(balance, token, { + rounded: true, + dislpaySymbol: true, + roundedDecimals: 4, + })} + + + {isRatesChangingAfterNetworkChange ? ( + + ) : ( + formatter.format( + balance || BigNumber.from(0), + token.symbol, + token.decimals, + isNativeTokenAddress(token.address) + ) + )} + +
+
+
+ +
+
+ ) +} + +export default AssetItem diff --git a/packages/ui/src/components/home/AssetsList.tsx b/packages/ui/src/components/home/AssetsList.tsx new file mode 100644 index 000000000..e200aa309 --- /dev/null +++ b/packages/ui/src/components/home/AssetsList.tsx @@ -0,0 +1,278 @@ +import { Fragment, FunctionComponent, useState, useEffect, useRef } from "react" +///Hooks +import { useOnMountHistory } from "../../context/hooks/useOnMount" +import { + TokenList, + useTokenListWithNativeToken, +} from "../../context/hooks/useTokensList" +import useCurrencyFromatter from "../../util/hooks/useCurrencyFormatter" +import useTokenSearch from "../../util/hooks/token/useTokenSearch" + +///Icons + Classes +import { Classes } from "../../styles/classes" +import plus from "../../assets/images/icons/plus.svg" +import unknownTokenIcon from "../../assets/images/unknown_token.svg" +import ChevronRightIcon from "../icons/ChevronRightIcon" +import order from "../../assets/images/icons/order.svg" + +///Background +import { Token } from "@block-wallet/background/controllers/erc-20/Token" + +///Utils +import { BigNumber } from "@ethersproject/bignumber" +import { formatUnits } from "@ethersproject/units" +import { formatRounded } from "../../util/formatRounded" +import { AssetsSortOptions, isNativeTokenAddress } from "../../util/tokenUtils" +import AssetsLoadingSkeleton from "./../skeleton/AssetsLoadingSkeleton" +import { useBlankState } from "../../context/background/backgroundHooks" +import SearchInput from "../input/SearchInput" +import AssetsButton from "../assets/AssetsButton" +import AssetsSort from "../assets/AssetsSort" +import { setTokensSortValue } from "../../context/commActions" +import AutoSizer from "react-virtualized/dist/commonjs/AutoSizer" +import List from "react-virtualized/dist/commonjs/List" +export type AssetItem = { + token: Token + balance: BigNumber +} + +export const AssetIcon: FunctionComponent<{ + asset: Partial + filled?: boolean +}> = ({ asset, filled }) => ( +
+ { + { + ;(e.target as any).onerror = null + ;(e.target as any).src = unknownTokenIcon + }} + alt={asset.symbol || ""} + className="rounded-full" + /> + } +
+) + +const Asset: FunctionComponent<{ + asset: AssetItem + pushDeleteTokens: Function +}> = ({ asset }) => { + const history: any = useOnMountHistory() + const formatter = useCurrencyFromatter() + return ( +
+ history.push({ + pathname: `/asset/details`, + state: { + address: asset.token.address, + transitionDirection: "left", + }, + }) + } + className="flex flex-row items-center justify-between px-6 py-5 -ml-6 transition duration-300 hover:bg-primary-100 hover:bg-opacity-50 active:bg-primary-200 active:bg-opacity-50 cursor-pointer" + style={{ width: "calc(100% + 2 * 1.5rem)" }} + role="listitem" + aria-label={asset.token.symbol} + > +
+ +
+ + {` + ${formatRounded( + formatUnits( + asset.balance || "0", + asset.token.decimals + ), + 4 + )} + ${asset.token.symbol} + `} + + + {formatter.format( + asset.balance || BigNumber.from(0), + asset.token.symbol, + asset.token.decimals, + isNativeTokenAddress(asset.token.address) + )} + +
+
+
+ +
+
+ ) +} + +const SubAssetList: FunctionComponent<{ assets: TokenList }> = ({ assets }) => { + const state = useBlankState()! + + const isLoading = state.isNetworkChanging + + const [deletedTokens, setDeletedTokens] = useState([] as string[]) + const [currentAssets, setCurrentAssets] = useState(assets) + const pushDeleteTokens = (deleteToken: string) => { + setDeletedTokens([...deletedTokens, deleteToken]) + } + useEffect(() => { + setCurrentAssets( + assets.filter((t) => !deletedTokens.includes(t.token.address)) + ) + }, [assets, deletedTokens]) + // the action of delete a token is not sync, we include this blick of code for not showing deleted tokens while they are being deleted. + const newDeleted: string[] = [] + deletedTokens.forEach((t) => { + if (assets.map((a) => a.token.address).includes(t)) { + newDeleted.push(t) + } + }) + if (deletedTokens.length !== newDeleted.length) { + setDeletedTokens(newDeleted) + } + + const ref = useRef() + + useEffect(() => { + // react-virtualized does not recompute row height when the underlying transaction data changes. + // thats why we force a height recompution here and adjust tx height based on its state. + ref.current && ref.current.recomputeRowHeights(0) + }, [currentAssets]) + + return ( + <> + {isLoading ? ( +
+ +
+ ) : ( + + {({ width, height }) => ( + ( +
+ {index > 0 ?
: null} + +
+ )} + >
+ )} +
+ )} + + ) +} + +const AssetsList = () => { + const { tokensSortValue } = useBlankState()! + const history = useOnMountHistory() + const [sortValue, setSortValue] = useState( + tokensSortValue as AssetsSortOptions + ) + const currentNetworkTokens = useTokenListWithNativeToken(sortValue) + const searchInputRef = useRef(null) + const { search, tokensResult, onChangeSearch } = + useTokenSearch(currentNetworkTokens) + + useEffect(() => { + const updateSortValue = async () => { + await setTokensSortValue(sortValue) + } + + if (sortValue !== tokensSortValue) { + updateSortValue() + } + }, [sortValue, tokensSortValue]) + + return ( + <> +
+
+
+ { + onChangeSearch(e.target.value) + }} + debounced + defaultValue={search} + ref={searchInputRef} + showClearIcon={true} + /> +
+ { + history.push({ + pathname: "/settings/tokens/add", + }) + }} + title="Add Token" + icon={plus} + /> + + { + history.push({ + pathname: "/accounts/menu/tokensOrder", + state: { isFromHomePage: true }, + }) + }} + title="Edit Assets Order" + icon={order} + disabled={sortValue !== AssetsSortOptions.CUSTOM} + /> +
+
+
+ +
+ + ) +} + +export default AssetsList diff --git a/packages/ui/src/components/home/AssetsOverview.tsx b/packages/ui/src/components/home/AssetsOverview.tsx new file mode 100644 index 000000000..ad2a1bef7 --- /dev/null +++ b/packages/ui/src/components/home/AssetsOverview.tsx @@ -0,0 +1,54 @@ +import { ActionButton } from "../button/ActionButton" +import plus from "../../assets/images/icons/plus.svg" +import AssetsList from "./AssetsList" +import classnames from "classnames" +import { useTokensList } from "../../context/hooks/useTokensList" +import { useBlankState } from "../../context/background/backgroundHooks" +import AssetsLoadingSkeleton from "../skeleton/AssetsLoadingSkeleton" + +const AddTokenButton = ({ fixed }: { fixed: boolean }) => { + return ( +
+
+ +
+
+ ) +} + +const AssetsOverview = () => { + const { currentNetworkTokens, nativeToken } = useTokensList() + const { isNetworkChanging } = useBlankState()! + const tokens = [nativeToken].concat(currentNetworkTokens) + + const displayFixedButton = tokens.length < 3 + + if (isNetworkChanging) { + return ( +
+ +
+ ) + } + + return ( +
+ + +
+ ) +} + +export default AssetsOverview diff --git a/packages/ui/src/components/home/DAppConnection.tsx b/packages/ui/src/components/home/DAppConnection.tsx new file mode 100644 index 000000000..e311a9e0e --- /dev/null +++ b/packages/ui/src/components/home/DAppConnection.tsx @@ -0,0 +1,83 @@ +import { useHistory } from "react-router-dom" +import { useConnectedSite } from "../../context/hooks/useConnectedSite" +import GenericTooltip from "../label/GenericTooltip" +import classnames from "classnames" +import { HiOutlineExclamationCircle } from "react-icons/hi" +import { BiCircle } from "react-icons/bi" +import { session } from "../../context/setup" + +const DAppConnection = () => { + const dAppConnected = useConnectedSite() + const history = useHistory()! + return ( + +

+ {dAppConnected === "connected" ? ( + You are connected to the open site + ) : ( + You are not connected to the open site + )} +

+
+ } + > +
{ + if (dAppConnected !== "not-connected") { + history.push({ + pathname: + "/accounts/menu/connectedSites/accountList", + state: { + origin: session?.origin, + fromRoot: true, + }, + }) + } + }} + className={classnames( + "relative flex flex-row items-center py-1 text-primary-grey-dark rounded-md group border-primary-200 text-xs cursor-pointer", + dAppConnected === "connected" && + "bg-green-100 hover:border-green-300", + dAppConnected === "connected-warning" && + "bg-yellow-100 hover:border-yellow-300", + dAppConnected === "not-connected" && "pointer-events-none" + )} + > + {dAppConnected === "connected" && ( + + )} + + {dAppConnected === "connected-warning" && ( + + )} + + {dAppConnected === "not-connected" && ( + + )} + + + {dAppConnected === "not-connected" + ? "Not connected" + : "Connected"} + +
+ + ) +} + +export default DAppConnection diff --git a/packages/ui/src/components/gas/GasPricesInfo.tsx b/packages/ui/src/components/home/GasPricesInfo.tsx similarity index 98% rename from packages/ui/src/components/gas/GasPricesInfo.tsx rename to packages/ui/src/components/home/GasPricesInfo.tsx index b5f6b8f34..4a4466b4d 100644 --- a/packages/ui/src/components/gas/GasPricesInfo.tsx +++ b/packages/ui/src/components/home/GasPricesInfo.tsx @@ -25,6 +25,7 @@ import { SEND_GAS_COST } from "../../util/constants" import car from "../../assets/images/icons/car.svg" import scooter from "../../assets/images/icons/scooter.svg" import plane from "../../assets/images/icons/plane.svg" +import { useExchangeRatesState } from "../../context/background/useExchangeRatesState" import { useHotkeys } from "react-hotkeys-hook" import { componentsHotkeys } from "../../util/hotkeys" @@ -116,14 +117,10 @@ const GasPricesInfo: FC = () => { const [active, setActive] = useState(false) const [calculateGasCost] = useState<"SEND">("SEND") const { - exchangeRates, - nativeCurrency, - localeInfo, - networkNativeCurrency, - isNetworkChanging, - hotkeysEnabled, - } = useBlankState()! - + state: { exchangeRates, networkNativeCurrency }, + } = useExchangeRatesState() + const { nativeCurrency, localeInfo, isNetworkChanging, hotkeysEnabled } = + useBlankState()! const { showGasLevels, isEIP1559Compatible, diff --git a/packages/ui/src/components/home/HomeBalancePanel.tsx b/packages/ui/src/components/home/HomeBalancePanel.tsx new file mode 100644 index 000000000..419351407 --- /dev/null +++ b/packages/ui/src/components/home/HomeBalancePanel.tsx @@ -0,0 +1,128 @@ +import { useBlankState } from "../../context/background/backgroundHooks" +import { useSelectedNetwork } from "../../context/hooks/useSelectedNetwork" +import TokenSummary from "../token/TokenSummary" +import PanelButtons from "./PanelButtons" +import useNetWorthBalance from "../../context/hooks/useNetWorthBalance" +import { AiFillInfoCircle } from "react-icons/ai" +import Tooltip from "../label/Tooltip" +import { setUserSettings } from "../../context/commActions" +import Icon, { IconName } from "../ui/Icon" + +const HomeBalancePanel = () => { + const { isNetworkChanging, isUserNetworkOnline, nativeCurrency, settings } = + useBlankState()! + const { isSendEnabled, isSwapEnabled, isBridgeEnabled, isOnrampEnabled } = + useSelectedNetwork() + const { + netWorth, + displayNetWorth, + nativeTokenBalance, + nativeTokenBalanceRounded, + nativeCurrencyAmount, + } = useNetWorthBalance() + + const disabledActions = !isSendEnabled || !isUserNetworkOnline + + return ( + <> + + + + {displayNetWorth ? netWorth : nativeTokenBalanceRounded} + + + + + } + className="!-mb-4" + /> + +
+ {displayNetWorth ? "Net Worth" : nativeCurrencyAmount} +
{ + setUserSettings({ + ...settings, + displayNetWorth: !displayNetWorth, + }) + }} + > + +
+ + + + + {isOnrampEnabled && ( + + )} + {isSwapEnabled && ( + + )} + {isBridgeEnabled && ( + + )} + + + + ) +} + +export default HomeBalancePanel diff --git a/packages/ui/src/components/home/PanelButtons.tsx b/packages/ui/src/components/home/PanelButtons.tsx new file mode 100644 index 000000000..7de29672a --- /dev/null +++ b/packages/ui/src/components/home/PanelButtons.tsx @@ -0,0 +1,199 @@ +import { Token } from "@block-wallet/background/controllers/erc-20/Token" +import { Link } from "react-router-dom" +import classnames from "classnames" +import Icon, { IconName } from "../ui/Icon" +import AnimatedIcon, { AnimatedIconName } from "../AnimatedIcon" +import RoundedIconButton, { + RoundedLoadingButton, +} from "../button/RoundedIconButton" +import DoubleArrowHoverAnimation from "../icons/DoubleArrowHoverAnimation" +import ArrowHoverAnimation from "../icons/ArrowHoverAnimation" +import { TokenWithBalance } from "../../context/hooks/useTokensList" +import { BigNumber } from "@ethersproject/bignumber" +import { Currency } from "@block-wallet/background/utils/currency" +import { AccountInfo } from "@block-wallet/background/controllers/AccountTrackerController" + +type BaseRedirectState = { + transitionDirection: "left" | "right" +} + +type PanelButtonProps = { + redirectState?: T + className?: string + disabled: boolean + isLoading?: boolean +} + +interface RedirectBridgeState extends BaseRedirectState { + token: Token + fromAssetPage: boolean +} + +interface RedirectSwapState extends BaseRedirectState { + fromToken: Token + fromTokenBalance: BigNumber + fromAssetPage: boolean +} + +interface RedirectSendState extends BaseRedirectState { + asset: TokenWithBalance +} + +interface RedirectBuyState extends BaseRedirectState { + spend: Currency + receive: Token + arriveTo: AccountInfo +} + +const BridgeButton: React.FC> = ({ + redirectState, + disabled, + isLoading, +}) => { + return ( + +
+ {disabled ? ( + + ) : ( + <> + {isLoading ? ( + + ) : ( + + )} + + )} +
+ Bridge + + ) +} + +const SwapButton: React.FC> = ({ + redirectState, + disabled, + isLoading, +}) => { + return ( + + + Swap + + + ) +} + +const SendButton: React.FC> = ({ + redirectState, + disabled, + isLoading, +}) => { + return ( + + + Send + + + ) +} + +const BuyButton: React.FC> = ({ + redirectState, + disabled, + isLoading, +}) => { + return ( + +
+ {isLoading ? ( +
+ +
+ ) : ( + + )} +
+ Buy + + ) +} + +const PanelButtons: { + Bridge: typeof BridgeButton + Swap: typeof SwapButton + Send: typeof SendButton + Buy: typeof BuyButton +} = { + Bridge: BridgeButton, + Send: SendButton, + Swap: SwapButton, + Buy: BuyButton, +} + +export default PanelButtons diff --git a/packages/ui/src/components/skeleton/AssetsLoadingSkeleton.tsx b/packages/ui/src/components/skeleton/AssetsLoadingSkeleton.tsx index 001be80a2..940b7b413 100644 --- a/packages/ui/src/components/skeleton/AssetsLoadingSkeleton.tsx +++ b/packages/ui/src/components/skeleton/AssetsLoadingSkeleton.tsx @@ -9,7 +9,7 @@ const AssetsLoadingSkeleton = () => {
{index > 0 ?
: null} -
+
{ icon={ AnimatedIconName.GreyLineLoadingSkeleton } - className="mb-2 h-3 w-16 rotate-180" + className="mb-2 h-3 w-24 rotate-180" svgClassName="rounded-md" />
diff --git a/packages/ui/src/components/skeleton/TransactionsLoadingSkeleton.tsx b/packages/ui/src/components/skeleton/TransactionsLoadingSkeleton.tsx index 7db6049e8..7d633f652 100644 --- a/packages/ui/src/components/skeleton/TransactionsLoadingSkeleton.tsx +++ b/packages/ui/src/components/skeleton/TransactionsLoadingSkeleton.tsx @@ -7,7 +7,7 @@ const TransactionsLoadingSkeleton = () => { {[...Array(3)].map((x, index) => (
{index > 0 ?
: null} -
+
- {({ style, data, index }) => ( + rowHeight={60} + rowRenderer={({ + style, + key, + index, + }: { + style: any + key: string + index: number + }) => (
- onClick(data[index]) + onClick( + filteredResults[ + index + ] + ) } >
)} - + /> )}
diff --git a/packages/ui/src/components/token/TokenSummary.tsx b/packages/ui/src/components/token/TokenSummary.tsx index 23ad6f497..0ea93e8a0 100644 --- a/packages/ui/src/components/token/TokenSummary.tsx +++ b/packages/ui/src/components/token/TokenSummary.tsx @@ -1,20 +1,17 @@ import { FC } from "react" import classnames from "classnames" -import { useBlankState } from "../../context/background/backgroundHooks" -import BalanceLoadingSkeleton from "../skeleton/BalanceLoadingSkeleton" +import AnimatedIcon, { AnimatedIconName } from "../AnimatedIcon" +interface TokenSummaryMembersProps { + title?: string + className?: string + children: React.ReactNode + isLoading?: boolean +} interface TokenSummaryMembers { Balances: FC<{ children: React.ReactNode; className?: string }> - TokenBalance: FC<{ - title?: string - children: React.ReactNode - className?: string - }> - ExchangeRateBalance: FC<{ - title?: string - className?: string - children: React.ReactNode - }> + TokenBalance: FC + ExchangeRateBalance: FC TokenName: FC<{ title?: string; children: React.ReactNode }> Actions: FC<{ children: React.ReactNode; className?: string | undefined }> } @@ -44,32 +41,33 @@ const Balances = ({ children: React.ReactNode className?: string }) => { - const state = useBlankState()! - - const isLoading = state.isNetworkChanging - return ( - <> - {isLoading ? ( - - ) : ( -
- {children} -
+
+ > + {children} +
) } -const TokenBalance: FC<{ - title?: string - className?: string - children: React.ReactNode -}> = ({ children, title, className }) => { +const TokenBalance: FC = ({ + children, + title, + className, + isLoading, +}) => { + if (isLoading) { + return ( + + ) + } return ( = ({ children, title, className }) => { +const ExchangeRateBalance: FC = ({ + children, + title, + className, + isLoading, +}) => { + if (isLoading) { + return ( + + ) + } return ( setActive(false)) //State - const { exchangeRates, nativeCurrency, localeInfo, networkNativeCurrency } = - useBlankState()! + const { nativeCurrency, localeInfo } = useBlankState()! + const { + state: { exchangeRates, networkNativeCurrency }, + } = useExchangeRatesState() const { estimatedBaseFee: baseFeePerGas, gasPricesLevels } = useGasPriceData() @@ -617,70 +627,84 @@ const GasPriceComponent: FunctionComponent<{ const [transactionSpeeds, setTransactionSpeeds] = useState(getTransactionSpeeds(gasPricesLevels)) - const getGasOption = (label: string, gasFees: TransactionFeeData) => { - const { - minValue, - maxValue, - minValueNativeCurrency, - maxValueNativeCurrency, - } = calculateGasPricesFromTransactionFees(gasFees, baseFee, { - exchangeRates, - localeInfo: { - currency: nativeCurrency, - language: localeInfo, - }, - networkNativeCurrency: { - symbol: networkNativeCurrency.symbol, - decimals: nativeCurrencyDecimals, - }, - }) - - const minValueFormatted = formatRounded( - formatUnits(minValue.lt(maxValue) ? minValue : maxValue), - 5 - ) + const getGasOption = useCallback( + (label: string, gasFees: TransactionFeeData) => { + const { + minValue, + maxValue, + minValueNativeCurrency, + maxValueNativeCurrency, + } = calculateGasPricesFromTransactionFees(gasFees, baseFee, { + exchangeRates, + localeInfo: { + currency: nativeCurrency, + language: localeInfo, + }, + networkNativeCurrency: { + symbol: networkNativeCurrency.symbol, + decimals: nativeCurrencyDecimals, + }, + }) - const maxValueFormatted = formatRounded( - formatUnits(minValue.gt(maxValue) ? minValue : maxValue), - 5 - ) + const minValueFormatted = formatRounded( + formatUnits(minValue.lt(maxValue) ? minValue : maxValue), + 5 + ) - const networkSymbol = networkNativeCurrency.symbol - - // For parent's label, apply displayOnlyMaxValue flag. Otherwise always display range - const totalETHCost = - (label !== "Custom" || minValue.lte(maxValue)) && - !displayOnlyMaxValue - ? `${minValueFormatted} ${networkSymbol} - ${maxValueFormatted} ${networkSymbol}` - : `${formatRounded(formatUnits(maxValue), 5)} ${networkSymbol}` - - const totalNativeCurrencyCost = - (label !== "Custom" || minValue.lte(maxValue)) && - !displayOnlyMaxValue - ? `${minValueNativeCurrency} - ${maxValueNativeCurrency}` - : maxValueNativeCurrency - - const totalETHCostRange = - label !== "Custom" || minValue.lte(maxValue) - ? `${minValueFormatted} ${networkNativeCurrency.symbol} - ${maxValueFormatted} ${networkNativeCurrency.symbol}` - : `${formatRounded(formatUnits(maxValue), 5)} ${ - networkNativeCurrency.symbol - }` - - const totalNativeCurrencyCostRange = - label !== "Custom" || minValue.lte(maxValue) - ? `${minValueNativeCurrency} - ${maxValueNativeCurrency}` - : maxValueNativeCurrency - - return { - label, - gasFees, - totalETHCost, - totalNativeCurrencyCost, - totalETHCostRange, - totalNativeCurrencyCostRange, - } as GasPriceOption - } + const maxValueFormatted = formatRounded( + formatUnits(minValue.gt(maxValue) ? minValue : maxValue), + 5 + ) + + const networkSymbol = networkNativeCurrency.symbol + + // For parent's label, apply displayOnlyMaxValue flag. Otherwise always display range + const totalETHCost = + (label !== "Custom" || minValue.lte(maxValue)) && + !displayOnlyMaxValue + ? `${minValueFormatted} ${networkSymbol} - ${maxValueFormatted} ${networkSymbol}` + : `${formatRounded( + formatUnits(maxValue), + 5 + )} ${networkSymbol}` + + const totalNativeCurrencyCost = + (label !== "Custom" || minValue.lte(maxValue)) && + !displayOnlyMaxValue + ? `${minValueNativeCurrency} - ${maxValueNativeCurrency}` + : maxValueNativeCurrency + + const totalETHCostRange = + label !== "Custom" || minValue.lte(maxValue) + ? `${minValueFormatted} ${networkNativeCurrency.symbol} - ${maxValueFormatted} ${networkNativeCurrency.symbol}` + : `${formatRounded(formatUnits(maxValue), 5)} ${ + networkNativeCurrency.symbol + }` + + const totalNativeCurrencyCostRange = + label !== "Custom" || minValue.lte(maxValue) + ? `${minValueNativeCurrency} - ${maxValueNativeCurrency}` + : maxValueNativeCurrency + + return { + label, + gasFees, + totalETHCost, + totalNativeCurrencyCost, + totalETHCostRange, + totalNativeCurrencyCostRange, + } as GasPriceOption + }, + [ + baseFee, + displayOnlyMaxValue, + exchangeRates, + localeInfo, + nativeCurrency, + nativeCurrencyDecimals, + networkNativeCurrency.symbol, + ] + ) const [gasOptions, setGasOptions] = useState([]) @@ -755,7 +779,12 @@ const GasPriceComponent: FunctionComponent<{ } } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [isParentLoading, gasPricesLevels, defaultGas.feeData.gasLimit]) + }, [ + isParentLoading, + gasPricesLevels, + defaultGas.feeData.gasLimit, + getGasOption, + ]) useEffect(() => { setBaseFee(BigNumber.from(baseFeePerGas)) diff --git a/packages/ui/src/components/transactions/GasPriceSelector.tsx b/packages/ui/src/components/transactions/GasPriceSelector.tsx index f23cb9102..d711ae761 100644 --- a/packages/ui/src/components/transactions/GasPriceSelector.tsx +++ b/packages/ui/src/components/transactions/GasPriceSelector.tsx @@ -41,6 +41,7 @@ import { formatRounded } from "../../util/formatRounded" import { useBlankState } from "../../context/background/backgroundHooks" import { useSelectedNetwork } from "../../context/hooks/useSelectedNetwork" import { useGasPriceData } from "../../context/hooks/useGasPriceData" +import { useExchangeRatesState } from "../../context/background/useExchangeRatesState" import { updateGasPrices } from "../../context/commActions" import { GAS_PRICE_UPDATE_INTERVAL } from "../../util/constants" @@ -450,8 +451,11 @@ export const GasPriceSelector = (props: GasPriceSelectorProps) => { ) // State variables - const { nativeCurrency, localeInfo, exchangeRates, networkNativeCurrency } = - useBlankState()! + const { nativeCurrency, localeInfo } = useBlankState()! + + const { + state: { exchangeRates, networkNativeCurrency }, + } = useExchangeRatesState() const { gasPricesLevels } = useGasPriceData() diff --git a/packages/ui/src/components/transactions/Price.tsx b/packages/ui/src/components/transactions/Price.tsx index 294c34d6f..cf130a482 100644 --- a/packages/ui/src/components/transactions/Price.tsx +++ b/packages/ui/src/components/transactions/Price.tsx @@ -8,6 +8,7 @@ import formatTransactionValue from "../../util/formatTransactionValue" // Hooks import { useBlankState } from "../../context/background/backgroundHooks" import { getValueByKey } from "../../util/objectUtils" +import { useExchangeRatesState } from "../../context/background/useExchangeRatesState" const Price: FunctionComponent<{ title: string @@ -16,6 +17,9 @@ const Price: FunctionComponent<{ decimals: number }> = ({ title, amount, symbol, decimals }) => { const state = useBlankState()! + const { + state: { exchangeRates }, + } = useExchangeRatesState() const txValue = formatTransactionValue( { @@ -29,7 +33,7 @@ const Price: FunctionComponent<{ const currencyAmount = toCurrencyAmount( amount, - getValueByKey(state.exchangeRates, symbol.toUpperCase(), 0), + getValueByKey(exchangeRates, symbol.toUpperCase(), 0), decimals ) diff --git a/packages/ui/src/components/transactions/TransactionItem.tsx b/packages/ui/src/components/transactions/TransactionItem.tsx index 616df99d1..bb2db35b5 100644 --- a/packages/ui/src/components/transactions/TransactionItem.tsx +++ b/packages/ui/src/components/transactions/TransactionItem.tsx @@ -1,4 +1,4 @@ -import { CSSProperties, useState } from "react" +import { CSSProperties } from "react" import { FaExchangeAlt } from "react-icons/fa" import { FiUpload } from "react-icons/fi" import { RiCopperCoinFill } from "react-icons/ri" @@ -6,6 +6,7 @@ import { AiFillInfoCircle } from "react-icons/ai" import { GiSuspensionBridge } from "react-icons/gi" import { ImSpinner } from "react-icons/im" import { BigNumber } from "@ethersproject/bignumber" +import { formatUnits } from "@ethersproject/units" import classNames from "classnames" import { Classes, classnames } from "../../styles" import Tooltip from "../../components/label/Tooltip" @@ -36,13 +37,12 @@ import { RichedTransactionMeta } from "../../util/transactionUtils" import Dots from "../loading/LoadingDots" import useCurrencyFromatter from "../../util/hooks/useCurrencyFormatter" import useGetBridgeTransactionsData from "../../util/hooks/useGetBridgeTransactionsData" -import BridgeDetails from "../bridge/BridgeDetails" import { BRIDGE_PENDING_STATUS, getBridgePendingMessage, } from "../../util/bridgeUtils" -import TransactionDetails from "./TransactionDetails" -import { formatUnits } from "ethers/lib/utils" +import { useExchangeRatesState } from "../../context/background/useExchangeRatesState" +import AnimatedIcon, { AnimatedIconName } from "../AnimatedIcon" import TokenLogo from "../token/TokenLogo" const TRANSACTION_STATIC_MESSAGES = { @@ -149,7 +149,7 @@ const getTransactionItemStyles = ( return { formattedLabel, typeCss, amountCss } } -const transactionIcons = { +const transactionIcons: Record = { [TransactionCategories.BLANK_DEPOSIT]: blank, [TransactionCategories.BLANK_WITHDRAWAL]: ( BlockWallet @@ -303,10 +303,10 @@ const getTransactionTime = ( ) return [{ color: "text-red-600", label: "Cancelled" }] // If we're here, we're waiting to see if the transaction will be cancelled - else if (metaType === MetaType.REGULAR_CANCELLING) + else if (metaType === MetaType.REGULAR_CANCELLING && !isQueued) return [{ color: "text-primary-grey-dark", label: "Cancelling..." }] // If we're here, we're waiting to see if the transaction will be sped up - else if (metaType === MetaType.REGULAR_SPEEDING_UP) + else if (metaType === MetaType.REGULAR_SPEEDING_UP && !isQueued) return [ { color: "text-primary-grey-dark", label: "Speeding up..." }, ] @@ -423,7 +423,9 @@ const getTransactionTimeOrStatus = ( const TransactionItem: React.FC<{ transaction: RichedTransactionMeta index: number -}> = ({ index, transaction }) => { + itemHeight: number + onClick: () => void +}> = ({ index, transaction, onClick, itemHeight }) => { const { transactionParams: { value, hash }, methodSignature, @@ -445,12 +447,13 @@ const TransactionItem: React.FC<{ const history: any = useOnMountHistory() const formatter = useCurrencyFromatter() + const { + state: { isRatesChangingAfterNetworkChange }, + } = useExchangeRatesState() const { nativeCurrency: networkNativeCurrency, defaultNetworkLogo } = useSelectedNetwork() - const [hasDetails, setHasDetails] = useState(false) - const txHash = hash let transfer = transferType ?? { amount: value ? value : BigNumber.from("0"), @@ -537,40 +540,22 @@ const TransactionItem: React.FC<{ transactionCategory !== TransactionCategories.INCOMING_BRIDGE_PLACEHOLDER && !isBlankWithdraw - - const OperationDetails = - transactionCategory && - [ - TransactionCategories.BRIDGE, - TransactionCategories.INCOMING_BRIDGE_REFUND, - TransactionCategories.INCOMING_BRIDGE, - ].includes(transactionCategory) - ? BridgeDetails - : TransactionDetails - return ( <> - setHasDetails(false)} - /> -
{ if (txHash && transaction.transactionParams.from) { - setHasDetails(true) + onClick() } }} > - {/* Type */}
- - {transferCurrencyAmount} - + {isRatesChangingAfterNetworkChange ? ( + + ) : ( + + {transferCurrencyAmount} + + )}
)} diff --git a/packages/ui/src/components/transactions/TransactionsList.tsx b/packages/ui/src/components/transactions/TransactionsList.tsx index 4c3082645..ba3642c4d 100644 --- a/packages/ui/src/components/transactions/TransactionsList.tsx +++ b/packages/ui/src/components/transactions/TransactionsList.tsx @@ -1,72 +1,149 @@ -import { Fragment, useRef, useState } from "react" -import useDOMElementObserver from "../../util/hooks/useDOMElementObserver" +import { useState, useRef, useEffect } from "react" +import AutoSizer from "react-virtualized/dist/commonjs/AutoSizer" +import List from "react-virtualized/dist/commonjs/List" import { RichedTransactionMeta } from "../../util/transactionUtils" -import dotLoading from "../../assets/images/icons/dot_loading.svg" -import { classnames } from "../../styles" import TransactionItem from "./TransactionItem" -import { useBlankState } from "../../context/background/backgroundHooks" +import { + MetaType, + TransactionCategories, + TransactionStatus, +} from "../../context/commTypes" +import BridgeDetails from "../bridge/BridgeDetails" +import TransactionDetails from "./TransactionDetails" +import { BRIDGE_PENDING_STATUS } from "../../util/bridgeUtils" +import { TransactionMeta } from "@block-wallet/background/controllers/transactions/utils/types" import TransactionsLoadingSkeleton from "../skeleton/TransactionsLoadingSkeleton" -const getInitialCount = (transactions: RichedTransactionMeta[]) => - transactions.length > 10 ? 10 : transactions.length +//Default tx height +const DEFAULT_TX_HEIGHT_IN_PX = 76 + +//Tx with captions (Sped up/Bridge information) +const TX_HEIHG_WITH_CAPTION = 95 + +//Speed-up/Cancel buttons +const TX_HEIGHT_WITH_BUTTONS = 110 + +const pendingSpeedingCancellingMetaTypes = [ + MetaType.REGULAR_SPEEDING_UP, + MetaType.REGULAR_CANCELLING, +] + +const confirmedSpedCancelMetaTypes = [MetaType.SPEED_UP, MetaType.CANCEL] + +const getItemHeightInPx = (tx: TransactionMeta) => { + if (tx.id) { + if ( + tx.status === TransactionStatus.SUBMITTED && + !pendingSpeedingCancellingMetaTypes.includes(tx.metaType) + ) { + return TX_HEIGHT_WITH_BUTTONS + } else if (tx.transactionCategory === TransactionCategories.BRIDGE) { + return BRIDGE_PENDING_STATUS.includes(tx.bridgeParams!.status!) + ? TX_HEIHG_WITH_CAPTION + : DEFAULT_TX_HEIGHT_IN_PX + } else if (confirmedSpedCancelMetaTypes.includes(tx.metaType)) { + return TX_HEIHG_WITH_CAPTION + } + } + return DEFAULT_TX_HEIGHT_IN_PX +} + +interface watchDetailsType { + transaction: TransactionMeta +} const TransactionsList: React.FC<{ transactions: RichedTransactionMeta[] -}> = ({ transactions }) => { - const state = useBlankState()! + isNetworkChanging: boolean +}> = ({ transactions, isNetworkChanging }) => { + const [watchDetails, setWatchDetails] = useState< + watchDetailsType | undefined + >() + const ref = useRef() - const isLoading = state.isNetworkChanging + useEffect(() => { + // react-virtualized does not recompute row height when the underlying transaction data changes. + // thats why we force a height recompution here and adjust tx height based on its state. + ref.current && ref.current.recomputeRowHeights(0) + }, [transactions]) - const [transactionCount, setTransactionCount] = useState(() => - getInitialCount(transactions) - ) - const [isLoadingMoreTransactions, setIsLoadingMoreTransactions] = - useState(false) - const loaderRef = useRef(null) + const OperationDetails = watchDetails + ? watchDetails.transaction.transactionCategory + ? [ + TransactionCategories.BRIDGE, + TransactionCategories.INCOMING_BRIDGE_REFUND, + TransactionCategories.INCOMING_BRIDGE, + ].includes(watchDetails.transaction.transactionCategory) + ? BridgeDetails + : TransactionDetails + : undefined + : undefined - useDOMElementObserver( - loaderRef, - async () => { - const countToLoad = transactions.length - transactionCount - if (countToLoad === 0) return - setIsLoadingMoreTransactions(true) - await new Promise((resolve) => setTimeout(resolve, 300)) - setTransactionCount( - transactionCount + (countToLoad > 10 ? 10 : countToLoad) - ) - setIsLoadingMoreTransactions(false) - }, - [transactionCount, transactions] - ) + if (isNetworkChanging) { + return ( +
+ +
+ ) + } return ( <> - {isLoading ? ( - - ) : ( - <> - {transactions.slice(0, transactionCount).map((t, i) => ( - - {i > 0 ?
: null} - -
- ))} - Loader - + {OperationDetails && watchDetails?.transaction && ( + setWatchDetails(undefined)} + /> )} + + {({ width, height }) => ( + { + return getItemHeightInPx(transactions[index]) + }} // height in px + className="hide-scroll" + rowRenderer={({ + style, + key, + index, + }: { + style: any + key: string + index: number + }) => ( +
+ {index > 0 ? ( +
+
+
+ ) : null} + + setWatchDetails({ + transaction: transactions[index], + }) + } + itemHeight={getItemHeightInPx( + transactions[index] + )} + transaction={transactions[index]} + index={index} + /> +
+ )} + >
+ )} +
) } diff --git a/packages/ui/src/context/background/BackgroundState.tsx b/packages/ui/src/context/background/BackgroundState.tsx index ea917e39c..7b4342fcd 100644 --- a/packages/ui/src/context/background/BackgroundState.tsx +++ b/packages/ui/src/context/background/BackgroundState.tsx @@ -1,11 +1,8 @@ import { Messages } from "../commTypes" import BackgroundReducer from "./backgroundReducer" import { useReducer, useEffect } from "react" -import { - subscribeState, - getState, - subscribeNetworkStatus, -} from "../commActions" +import { subscribeAppState, getAppState } from "../commActions" +import { subscribeNetworkStatus } from "../commActions" import BackgroundContext, { initBackgroundState } from "./backgroundContext" import { isPortConnected } from "../setup" @@ -13,7 +10,6 @@ let isContextInit = false const BackgroundState = (props: any) => { const [state, dispatch] = useReducer(BackgroundReducer, initBackgroundState) - useEffect(() => { initContext() // eslint-disable-next-line @@ -25,14 +21,14 @@ const BackgroundState = (props: any) => { } else { if (!isContextInit) { // Get initial state and dispatch - const initialState = await getState() + const initialState = await getAppState() dispatch({ type: Messages.STATE.SUBSCRIBE, payload: initialState, }) // Subscribe to state updates - subscribeState((state) => { + subscribeAppState((state) => { dispatch({ type: Messages.STATE.SUBSCRIBE, payload: state, diff --git a/packages/ui/src/context/background/backgroundContext.tsx b/packages/ui/src/context/background/backgroundContext.tsx index bd598eae4..2240a7d68 100644 --- a/packages/ui/src/context/background/backgroundContext.tsx +++ b/packages/ui/src/context/background/backgroundContext.tsx @@ -1,8 +1,8 @@ import { createContext } from "react" -import type { ResponseGetState } from "@block-wallet/background/utils/types/communication" +import type { ResponseGetAppState } from "@block-wallet/background/utils/types/communication" export type BackgroundStateType = { - blankState?: ResponseGetState + blankState?: ResponseGetAppState } export const initBackgroundState: BackgroundStateType = {} diff --git a/packages/ui/src/context/background/useActivityListState.tsx b/packages/ui/src/context/background/useActivityListState.tsx new file mode 100644 index 000000000..409e853e6 --- /dev/null +++ b/packages/ui/src/context/background/useActivityListState.tsx @@ -0,0 +1,39 @@ +import { createContext, FC, ReactNode, useContext } from "react" +import { + getActivityListState, + subscribeActivityListState, +} from "../commActions" +import { ResponseGetActivityListState } from "@block-wallet/background/utils/types/communication" +import useSubscription, { SubscriptionContext } from "./useStateSubscription" + +type ContextType = SubscriptionContext + +export const defaultState = { activityList: { pending: [], confirmed: [] } } +export const ActivityListContext = createContext({ + state: defaultState, + isLoading: false, +}) + +export const ActivityListStateProvider: FC<{ children: ReactNode }> = ({ + children, +}) => { + const state = useSubscription( + //state getter + getActivityListState, + //state subcriber + subscribeActivityListState, + //inital state + defaultState, + { name: "ActivityList" } + ) + + return ( + + {children} + + ) +} + +export const useActivityListState = () => { + return useContext(ActivityListContext) as ContextType +} diff --git a/packages/ui/src/context/background/useExchangeRatesState.tsx b/packages/ui/src/context/background/useExchangeRatesState.tsx new file mode 100644 index 000000000..9e0b1a00e --- /dev/null +++ b/packages/ui/src/context/background/useExchangeRatesState.tsx @@ -0,0 +1,48 @@ +import { createContext, FC, ReactNode, useContext } from "react" +import { + getExchangeRatesState, + subscribeExchangeRatesState, +} from "../commActions" +import { ResponseGetExchangeRatesState } from "@block-wallet/background/utils/types/communication" +import useSubscription, { SubscriptionContext } from "./useStateSubscription" + +type ExchangeRatesContextType = + SubscriptionContext + +export const defaultState = { + exchangeRates: {}, + networkNativeCurrency: { + symbol: "ETH", + // Default Coingecko id for ETH rates + coingeckoPlatformId: "ethereum", + }, + isRatesChangingAfterNetworkChange: false, +} + +export const ExchangeRatesContext = createContext({ + isLoading: false, + state: defaultState, +}) + +export const ExchangeRatesStateProvider: FC<{ children: ReactNode }> = ({ + children, +}) => { + const state = useSubscription( + //state getter + getExchangeRatesState, + //state subcriber + subscribeExchangeRatesState, + //inital state + defaultState, + { name: "Exchange rates" } + ) + return ( + + {children} + + ) +} + +export const useExchangeRatesState = () => { + return useContext(ExchangeRatesContext) as ExchangeRatesContextType +} diff --git a/packages/ui/src/context/background/useGasPricesState.tsx b/packages/ui/src/context/background/useGasPricesState.tsx new file mode 100644 index 000000000..c996af284 --- /dev/null +++ b/packages/ui/src/context/background/useGasPricesState.tsx @@ -0,0 +1,43 @@ +import { createContext, FC, ReactNode, useContext } from "react" +import { getGasPricesState, subscribeGasPricesState } from "../commActions" +import { ResponseGetGasPricesState } from "@block-wallet/background/utils/types/communication" +import useSubscription, { SubscriptionContext } from "./useStateSubscription" +import { AppLoading } from "../../App" + +type GasPricesContextType = SubscriptionContext + +const defaultState = { gasPriceData: {} } + +export const GasPricesContext = createContext({ + state: defaultState, + isLoading: true, +}) + +export const GasPricesStateProvider: FC<{ children: ReactNode }> = ({ + children, +}) => { + const state = useSubscription( + //state getter + getGasPricesState, + //state subcriber + subscribeGasPricesState, + //inital state + defaultState, + { + name: "Gas prices", + //initializes the state as loading. + initLoading: true, + } + ) + + return ( + + {/** Multiple components of the app renders as the gas price is already loaded. */} + {state.isLoading ? : children} + + ) +} + +export const useGasPricesState = () => { + return useContext(GasPricesContext) as GasPricesContextType +} diff --git a/packages/ui/src/context/background/useStateSubscription.ts b/packages/ui/src/context/background/useStateSubscription.ts new file mode 100644 index 000000000..f98e353b1 --- /dev/null +++ b/packages/ui/src/context/background/useStateSubscription.ts @@ -0,0 +1,55 @@ +import React, { Dispatch, useEffect, useRef, useState } from "react" + +export interface SubscriptionContext { + state: T + isLoading: boolean +} + +type SubscribeCallback = (cb: (state: T) => void) => Promise + +interface SubscribeOptions { + name?: string + initLoading?: boolean +} + +const defaultOptions = { + name: "", + initLoading: false, +} + +function useStateSubscription( + stateGetter: () => Promise | T, + subscriber: SubscribeCallback | undefined, + initialState: T, + { name, initLoading }: SubscribeOptions = defaultOptions +) { + const initialized = useRef(false) + const [state, setState] = useState(initialState) + const [isLoading, setIsLoading] = useState(initLoading ?? false) + useEffect(() => { + const log = + (callback: Dispatch>) => (newState: T) => { + if (process.env.LOG_LEVEL === "debug") { + console.log(`Updating Store: ${name}`, newState) + } + callback(newState) + } + + async function generateSubscription() { + initialized.current = true + setIsLoading(true) + const initialState = await stateGetter() + setIsLoading(false) + setState(initialState) + if (subscriber) { + subscriber(log(setState)) + } + } + if (!initialized.current) { + generateSubscription() + } + }, [name, stateGetter, subscriber]) + return { state, isLoading } +} + +export default useStateSubscription diff --git a/packages/ui/src/context/commActions.ts b/packages/ui/src/context/commActions.ts index 666021f6e..ae5354a2d 100644 --- a/packages/ui/src/context/commActions.ts +++ b/packages/ui/src/context/commActions.ts @@ -7,17 +7,30 @@ import { MessageTypes, RequestTypes, ResponseTypes, - ResponseGetState, StateSubscription, SubscriptionMessageTypes, RequestAddNetwork, RequestEditNetwork, RequestEditNetworksOrder, + ExchangeRatesStateSubscription, + ResponseGetExchangeRatesState, + GasPricesStateSubscription, + AppStateSubscription, + ResponseGetGasPricesState, + ResponseGetAppState, + ResponseGetActivityListState, + ActivityListStateSubscription, + RequestSwitchProvider, RequestTokensOrder, AddressType, - RequestSwitchProvider, } from "@block-wallet/background/utils/types/communication" -import { Devices, ExchangeType, Messages, TransactionStatus } from "./commTypes" +import { + Devices, + ExchangeType, + Messages, + StateType, + TransactionStatus, +} from "./commTypes" import { IToken, ITokens, @@ -406,10 +419,47 @@ export const verifyPassword = async (password: string): Promise => { * * @returns Background state */ -export const getState = async (): Promise => { - return sendMessage(Messages.STATE.GET) +export const getAppState = async (): Promise => { + return sendMessage(Messages.STATE.GET, { + stateType: StateType.APP_STATE, + }) as Promise } +/** + * Gets the exchange rates state + * + * @returns Exchange rates state + */ +export const getExchangeRatesState = + async (): Promise => { + return sendMessage(Messages.STATE.GET, { + stateType: StateType.EXCHANGE_RATES, + }) as Promise + } + +/** + * Gets the gas prices state + * + * @returns Gas prices state + */ +export const getGasPricesState = + async (): Promise => { + return sendMessage(Messages.STATE.GET, { + stateType: StateType.GAS_PRICES, + }) as Promise + } + +/** + * Gets the activity list state + * + * @returns Activity List state + */ +export const getActivityListState = + async (): Promise => { + return sendMessage(Messages.STATE.GET, { + stateType: StateType.ACTIVITY_LIST, + }) as Promise + } /** * Resolves the address of an ENS name * @@ -945,10 +995,67 @@ export const getSwapTransactionGasLimit = async ( * * @param cb state update handler */ -export const subscribeState = async ( - cb: (state: StateSubscription) => void +export const subscribeExchangeRatesState = async ( + cb: (state: ExchangeRatesStateSubscription) => void +): Promise => { + return sendMessage( + Messages.STATE.SUBSCRIBE, + { + stateType: StateType.EXCHANGE_RATES, + }, + cb as (data: StateSubscription) => void + ) +} + +/** + * Subscribes to gas prices state updates + * + * @param cb state update handler + */ +export const subscribeGasPricesState = async ( + cb: (state: GasPricesStateSubscription) => void ): Promise => { - return sendMessage(Messages.STATE.SUBSCRIBE, undefined, cb) + return sendMessage( + Messages.STATE.SUBSCRIBE, + { + stateType: StateType.GAS_PRICES, + }, + cb as (data: StateSubscription) => void + ) +} + +/** + * Subscribes to activty list state updates + * + * @param cb state update handler + */ +export const subscribeActivityListState = async ( + cb: (state: ActivityListStateSubscription) => void +): Promise => { + return sendMessage( + Messages.STATE.SUBSCRIBE, + { + stateType: StateType.ACTIVITY_LIST, + }, + cb as (data: StateSubscription) => void + ) +} + +/** + * Subscribes to the app state updates + * + * @param cb state update handler + */ +export const subscribeAppState = async ( + cb: (state: AppStateSubscription) => void +): Promise => { + return sendMessage( + Messages.STATE.SUBSCRIBE, + { + stateType: StateType.APP_STATE, + }, + cb as (data: StateSubscription) => void + ) } /** diff --git a/packages/ui/src/context/commTypes.ts b/packages/ui/src/context/commTypes.ts index 5ba0e1010..12bfe791f 100644 --- a/packages/ui/src/context/commTypes.ts +++ b/packages/ui/src/context/commTypes.ts @@ -431,6 +431,13 @@ export enum QuoteFeeStatus { INSUFFICIENT_BALANCE_TO_COVER_FEES = "INSUFFICIENT_BALANCE_TO_COVER_FEES", } +export enum StateType { + APP_STATE = "APP_STATE", + EXCHANGE_RATES = "EXCHANGE_RATES", + GAS_PRICES = "GAS_PRICES", + ACTIVITY_LIST = "ACTIVITY_LIST", +} + export enum TokenAllowanceStatus { UPDATED = "UPDATED", AWAITING_TRANSACTION_RESULT = "AWAITING_TRANSACTION_RESULT", diff --git a/packages/ui/src/context/hooks/useGasPriceData.ts b/packages/ui/src/context/hooks/useGasPriceData.ts index 289593d7f..d66fcf599 100644 --- a/packages/ui/src/context/hooks/useGasPriceData.ts +++ b/packages/ui/src/context/hooks/useGasPriceData.ts @@ -1,9 +1,11 @@ import { GasPriceData } from "@block-wallet/background/controllers/GasPricesController" -import { useBlankState } from "../background/backgroundHooks" +import { useGasPricesState } from "../background/useGasPricesState" import { useSelectedNetwork } from "./useSelectedNetwork" export const useGasPriceData = () => { - const { gasPriceData } = useBlankState()! + const { + state: { gasPriceData }, + } = useGasPricesState() const { chainId } = useSelectedNetwork() if (chainId in gasPriceData) { return gasPriceData[chainId] diff --git a/packages/ui/src/context/hooks/useNetWorthBalance.ts b/packages/ui/src/context/hooks/useNetWorthBalance.ts index d3117b937..6cf4ad8c2 100644 --- a/packages/ui/src/context/hooks/useNetWorthBalance.ts +++ b/packages/ui/src/context/hooks/useNetWorthBalance.ts @@ -6,18 +6,23 @@ import { AccountInfo } from "@block-wallet/background/controllers/AccountTracker import { formatUnits } from "@ethersproject/units" import { BigNumber } from "@ethersproject/bignumber" import { formatRounded } from "../../util/formatRounded" +import { useExchangeRatesState } from "../background/useExchangeRatesState" interface NetWorthBalance { - displayNetWorth: boolean; - nativeCurrencyAmount?: string; - nativeTokenBalance?: string; - nativeTokenBalanceRounded?: string; - netWorth?: string; + displayNetWorth: boolean + nativeCurrencyAmount?: string + nativeTokenBalance?: string + nativeTokenBalanceRounded?: string + netWorth?: string } const useNetWorthBalance = (account?: AccountInfo): NetWorthBalance => { - const { exchangeRates, nativeCurrency, localeInfo, settings } = useBlankState()! - const displayNetWorth = settings.displayNetWorth; + const { + state: { exchangeRates }, + } = useExchangeRatesState() + + const { nativeCurrency, localeInfo, settings } = useBlankState()! + const displayNetWorth = settings.displayNetWorth const assets = useTokensList(account) @@ -25,9 +30,7 @@ const useNetWorthBalance = (account?: AccountInfo): NetWorthBalance => { const nativeToken = assets.nativeToken - if (displayNetWorth) { - let netWorth = toCurrencyAmount( nativeToken.balance, exchangeRates[nativeToken.token.symbol.toUpperCase()], @@ -50,9 +53,8 @@ const useNetWorthBalance = (account?: AccountInfo): NetWorthBalance => { locale_info: localeInfo, returnNonBreakingSpace: true, showSymbol: false, - }) + }), } - } // Native token balance only. i.e.: 0.1 ETH @@ -65,11 +67,8 @@ const useNetWorthBalance = (account?: AccountInfo): NetWorthBalance => { displayNetWorth, nativeCurrencyAmount: formatCurrency( toCurrencyAmount( - nativeToken.balance || - BigNumber.from(0), - exchangeRates[ - nativeToken.token.symbol - ], + nativeToken.balance || BigNumber.from(0), + exchangeRates[nativeToken.token.symbol], nativeToken.token.decimals ), { @@ -80,7 +79,9 @@ const useNetWorthBalance = (account?: AccountInfo): NetWorthBalance => { } ), nativeTokenBalance: `${nativeTokenBalance} ${nativeToken.token.symbol}`, - nativeTokenBalanceRounded: `${formatRounded(nativeTokenBalance, 5)} ${nativeToken.token.symbol}`, + nativeTokenBalanceRounded: `${formatRounded(nativeTokenBalance, 5)} ${ + nativeToken.token.symbol + }`, } } diff --git a/packages/ui/src/context/hooks/useTokensList.ts b/packages/ui/src/context/hooks/useTokensList.ts index b6b965d55..460db8d60 100644 --- a/packages/ui/src/context/hooks/useTokensList.ts +++ b/packages/ui/src/context/hooks/useTokensList.ts @@ -12,6 +12,7 @@ import { isHiddenAccount } from "../../util/account" import { AssetsSortOptions, sortTokensByValue } from "../../util/tokenUtils" import { useMemo } from "react" import { Rates } from "@block-wallet/background/controllers/ExchangeRatesController" +import { useExchangeRatesState } from "../background/useExchangeRatesState" export type TokenWithBalance = { token: Token; balance: BigNumber } @@ -31,13 +32,10 @@ const useGetAccountNetworkTokensBalances = ( accountTokensOrder: AccountTokenOrder exchangeRates: Rates } => { - const { - accounts, - selectedAddress, - hiddenAccounts, - accountTokensOrder, - exchangeRates, - } = useBlankState()! + const { accounts, selectedAddress, hiddenAccounts, accountTokensOrder } = + useBlankState()! + + const { state: exchangeRates } = useExchangeRatesState() let balances = account ? isHiddenAccount(account) @@ -66,7 +64,7 @@ const useGetAccountNetworkTokensBalances = ( balances: balances, chainId: chainId, accountTokensOrder: arrAccountTokensOrder, - exchangeRates: exchangeRates, + exchangeRates: exchangeRates.exchangeRates, } } diff --git a/packages/ui/src/context/hooks/useWindowId.tsx b/packages/ui/src/context/hooks/useWindowId.tsx index 0db406407..a403c4e66 100644 --- a/packages/ui/src/context/hooks/useWindowId.tsx +++ b/packages/ui/src/context/hooks/useWindowId.tsx @@ -1,5 +1,4 @@ import { createContext, useContext, useEffect, useState } from "react" -import LoadingOverlay from "../../components/loading/LoadingOverlay" import { getWindowId } from "../commActions" export const WindowIdContext = createContext({ @@ -23,7 +22,7 @@ const WindowIdProvider = ({ return ( - {!windowId ? : children} + {children} ) } diff --git a/packages/ui/src/mock/MockActivityListState.tsx b/packages/ui/src/mock/MockActivityListState.tsx new file mode 100644 index 000000000..308740da5 --- /dev/null +++ b/packages/ui/src/mock/MockActivityListState.tsx @@ -0,0 +1,36 @@ +import { FunctionComponent, useState } from "react" +import { SubscriptionContext } from "../context/background/useStateSubscription" +import { ResponseGetActivityListState } from "@block-wallet/background/utils/types/communication" +import { + ActivityListContext, + defaultState, +} from "../context/background/useActivityListState" + +export const initActivityListState: SubscriptionContext = + { + isLoading: false, + state: defaultState, + } + +const MockActivityListState: FunctionComponent<{ + assignActivityListState?: Partial + children: React.ReactNode | undefined +}> = ({ assignActivityListState = {}, children }) => { + const [state] = useState({ + ...initActivityListState.state, + ...assignActivityListState, + }) + + return ( + + {children} + + ) +} + +export default MockActivityListState diff --git a/packages/ui/src/mock/MockApp.tsx b/packages/ui/src/mock/MockApp.tsx index 3b05b2562..e4678dc17 100644 --- a/packages/ui/src/mock/MockApp.tsx +++ b/packages/ui/src/mock/MockApp.tsx @@ -4,6 +4,14 @@ import MockBackgroundState from "./MockBackgroundState" import PopupRouter from "../router/PopupRouter" import { BackgroundStateType } from "../context/background/backgroundContext" import TabRouter from "../router/TabRouter" +import MockGasPricesState from "./MockGasPricesState" +import MockActivityListState from "./MockActivityListState" +import MockExchangeRatesState from "./MockExchangeRatesState" +import { + ResponseGetActivityListState, + ResponseGetExchangeRatesState, + ResponseGetGasPricesState, +} from "@block-wallet/background/utils/types/communication" const MockTab: FunctionComponent<{ location: string @@ -32,7 +40,17 @@ const MockPopup: FunctionComponent<{ location: string state?: any // location state assignBlankState?: Partial -}> = ({ location, state, assignBlankState }) => { + assignGasPricesState?: Partial + assignActivityListState?: Partial + assignExchangeRatesState?: Partial +}> = ({ + location, + state, + assignBlankState, + assignGasPricesState, + assignActivityListState, + assignExchangeRatesState, +}) => { const HistoryInjector = () => { const history = useHistory() useEffect(() => { @@ -46,9 +64,23 @@ const MockPopup: FunctionComponent<{ style={{ width: 357, height: 600 }} > - - - + + + + + + + + +
) diff --git a/packages/ui/src/mock/MockBackgroundState.tsx b/packages/ui/src/mock/MockBackgroundState.tsx index 314b1566b..9b01fd6bd 100644 --- a/packages/ui/src/mock/MockBackgroundState.tsx +++ b/packages/ui/src/mock/MockBackgroundState.tsx @@ -137,10 +137,6 @@ export const initBackgroundState: BackgroundStateType = { }, }, recentAddresses: {} as AddressBook, - activityList: { - confirmed: [], - pending: [], - }, hiddenAccounts: {}, accounts: { "0xd7Fd7EDcb7376c490b0e45e391e8040928F73081": { @@ -322,8 +318,7 @@ export const initBackgroundState: BackgroundStateType = { txSignTimeout: 0, unapprovedTransactions: {}, previousWithdrawals: [], - lastActiveTime: 0, - + expiredStickyStorage: false, depositsCount: { eth: [ { @@ -394,41 +389,7 @@ export const initBackgroundState: BackgroundStateType = { isVaultInitialized: true, isImportingDeposits: false, importingErrors: [], - exchangeRates: { ETH: 2300, DAI: 1 }, - networkNativeCurrency: { - symbol: "ETH", - // Default Coingecko id for ETH rates - coingeckoPlatformId: "ethereum", - }, - isRatesChangingAfterNetworkChange: false, isEIP1559Compatible: { 5: true }, - gasPriceData: { - 5: { - blockGasLimit: BigNumber.from(0), - estimatedBaseFee: BigNumber.from(0), - gasPricesLevels: { - slow: { - gasPrice: BigNumber.from(111111111110), - maxPriorityFeePerGas: BigNumber.from(0), - maxFeePerGas: BigNumber.from(0), - lastBaseFeePerGas: null, - }, - average: { - gasPrice: BigNumber.from(111111111110), - maxPriorityFeePerGas: BigNumber.from(0), - maxFeePerGas: BigNumber.from(0), - lastBaseFeePerGas: null, - }, - fast: { - gasPrice: BigNumber.from(111111111110), - maxPriorityFeePerGas: BigNumber.from(0), - maxFeePerGas: BigNumber.from(0), - lastBaseFeePerGas: null, - }, - }, - baseFee: BigNumber.from("0x02540be400"), - }, - }, showTestNetworks: true, showWelcomeMessage: false, showDefaultWalletPreferences: false, diff --git a/packages/ui/src/mock/MockExchangeRatesState.tsx b/packages/ui/src/mock/MockExchangeRatesState.tsx new file mode 100644 index 000000000..b1fa2172e --- /dev/null +++ b/packages/ui/src/mock/MockExchangeRatesState.tsx @@ -0,0 +1,36 @@ +import { FunctionComponent, useState } from "react" +import { SubscriptionContext } from "../context/background/useStateSubscription" +import { ResponseGetExchangeRatesState } from "@block-wallet/background/utils/types/communication" +import { + ExchangeRatesContext, + defaultState, +} from "../context/background/useExchangeRatesState" + +export const initExchangeRatesState: SubscriptionContext = + { + isLoading: false, + state: defaultState, + } + +const MockExchangeRatesState: FunctionComponent<{ + assignExchangeRatesState?: Partial + children: React.ReactNode | undefined +}> = ({ assignExchangeRatesState = {}, children }) => { + const [state] = useState({ + ...initExchangeRatesState.state, + ...assignExchangeRatesState, + }) + + return ( + + {children} + + ) +} + +export default MockExchangeRatesState diff --git a/packages/ui/src/mock/MockGasPricesState.tsx b/packages/ui/src/mock/MockGasPricesState.tsx new file mode 100644 index 000000000..aed08d3d5 --- /dev/null +++ b/packages/ui/src/mock/MockGasPricesState.tsx @@ -0,0 +1,62 @@ +import { FunctionComponent, useState } from "react" +import { BigNumber } from "@ethersproject/bignumber" +import { SubscriptionContext } from "../context/background/useStateSubscription" +import { ResponseGetGasPricesState } from "@block-wallet/background/utils/types/communication" +import { GasPricesContext } from "../context/background/useGasPricesState" + +export const initGasPricesState: SubscriptionContext = + { + isLoading: false, + state: { + gasPriceData: { + 5: { + blockGasLimit: BigNumber.from(0), + estimatedBaseFee: BigNumber.from(0), + gasPricesLevels: { + slow: { + gasPrice: BigNumber.from(111111111110), + maxPriorityFeePerGas: BigNumber.from(0), + maxFeePerGas: BigNumber.from(0), + lastBaseFeePerGas: null, + }, + average: { + gasPrice: BigNumber.from(111111111110), + maxPriorityFeePerGas: BigNumber.from(0), + maxFeePerGas: BigNumber.from(0), + lastBaseFeePerGas: null, + }, + fast: { + gasPrice: BigNumber.from(111111111110), + maxPriorityFeePerGas: BigNumber.from(0), + maxFeePerGas: BigNumber.from(0), + lastBaseFeePerGas: null, + }, + }, + baseFee: BigNumber.from("0x02540be400"), + }, + }, + }, + } + +const MockGasPricesState: FunctionComponent<{ + assignGasPricesState?: Partial + children: React.ReactNode | undefined +}> = ({ assignGasPricesState = {}, children }) => { + const [state] = useState({ + ...initGasPricesState.state, + ...assignGasPricesState, + }) + + return ( + + {children} + + ) +} + +export default MockGasPricesState diff --git a/packages/ui/src/router/PopupRouter.tsx b/packages/ui/src/router/PopupRouter.tsx index 2ded7f91a..12617dd8a 100644 --- a/packages/ui/src/router/PopupRouter.tsx +++ b/packages/ui/src/router/PopupRouter.tsx @@ -1,5 +1,4 @@ import { useEffect, useLayoutEffect, useMemo, useState } from "react" - import { HashRouter, Redirect, Route, useHistory } from "react-router-dom" import { useBlankState } from "../context/background/backgroundHooks" import PendingSetupPage from "../routes/setup/PendingSetupPage" @@ -16,7 +15,6 @@ import IdleComponent from "../components/IdleComponent" import WalletNews from "../components/news/WalletNews" import LocationHolder from "./LocationHolder" import { useLocationRecovery } from "../util/hooks/useLocationRecovery" -import { timeExceedsTTL } from "../util/time" import useClearStickyStorage from "../context/hooks/useClearStickyStorage" import { getNonSubmittedTransactions, @@ -24,9 +22,6 @@ import { } from "../util/getNonSubmittedTransactions" import browser from "webextension-polyfill" -//10 minutes -const LOCAL_STORAGE_DATA_TTL = 60000 * 10 - /** Purpose of this component is to check in Blank State if there is any pending connect to site or transaction confirm * in order to show that page always, whenever the extension is loaded and unlocked. */ @@ -37,7 +32,7 @@ const PopupComponent = () => { permissionRequests, dappRequests, transactions, - lastActiveTime, + expiredStickyStorage, } = useBlankState()! const unapprovedTransactions = getNonSubmittedTransactions( transactions, @@ -61,12 +56,7 @@ const PopupComponent = () => { ) useLayoutEffect(() => { - if ( - showPage || - showUnlock || - (lastActiveTime && - timeExceedsTTL(lastActiveTime, LOCAL_STORAGE_DATA_TTL)) - ) { + if (showPage || showUnlock || expiredStickyStorage) { // If the wallet is locked or if we're in a dApp request // We should get rid of all the localSotrage stuff. clearStickyStorage() diff --git a/packages/ui/src/router/routes.ts b/packages/ui/src/router/routes.ts index 0b106b742..17caa7778 100644 --- a/packages/ui/src/router/routes.ts +++ b/packages/ui/src/router/routes.ts @@ -5,7 +5,7 @@ import ConnectedSitesPage from "../routes/settings/ConnectedSitesPage" import ConnectedSiteAccountsPage from "../routes/settings/ConnectedSiteAccountsPage" import TransactionConfirmPage from "../routes/dApp/TransactionConfirmPage" import AccountsPage from "../routes/account/AccountsPage" -import PopupPage from "../routes/PopupPage" +import PopupPage from "../routes/HomePage" import ReceivePage from "../routes/ReceivePage" import SendConfirmPage from "../routes/send/SendConfirmPage" import SendPage from "../routes/send/SendPage" diff --git a/packages/ui/src/routes/HomePage.tsx b/packages/ui/src/routes/HomePage.tsx new file mode 100644 index 000000000..f374a6a28 --- /dev/null +++ b/packages/ui/src/routes/HomePage.tsx @@ -0,0 +1,162 @@ +import { Profiler, useState } from "react" +import { Link, useHistory } from "react-router-dom" +import GearIcon from "../components/icons/GearIcon" +import QRIcon from "../components/icons/QRIcon" +import NetworkSelect from "../components/input/NetworkSelect" +import ErrorDialog from "../components/dialog/ErrorDialog" +import AccountIcon from "../components/icons/AccountIcon" +import ActivityAssetsView from "../components/home/ActivityAssetsView" +import Tooltip from "../components/label/Tooltip" +import { getAccountColor } from "../util/getAccountColor" +import { useBlankState } from "../context/background/backgroundHooks" +import GasPricesInfo from "../components/home/GasPricesInfo" +import useMetricCollector from "../util/useMetricCollector" +import HomeBalancePanel from "../components/home/HomeBalancePanel" +import DAppConnection from "../components/home/DAppConnection" +import AccountAvatar from "../components/home/AccountAvatar" +import TransparentOverlay from "../components/loading/TransparentOverlay" +import { useSelectedAddressWithChainIdChecksum } from "../util/hooks/useSelectedAddressWithChainIdChecksum" +import PopupLayout from "../components/popup/PopupLayout" +import PopupHeader from "../components/popup/PopupHeader" +import { useSelectedNetwork } from "../context/hooks/useSelectedNetwork" +import { useHotkeys } from "react-hotkeys-hook" +import { componentsHotkeys } from "../util/hotkeys" +import { generateExplorerLink } from "../util/getExplorer" +import ProviderStatus from "../components/chain/ProviderStatus" + +const HomePage = () => { + const collect = useMetricCollector() + const error = (useHistory().location.state as { error: string })?.error + const state = useBlankState()! + const history = useHistory() + const checksumAddress = useSelectedAddressWithChainIdChecksum() + const [hasErrorDialog, setHasErrorDialog] = useState(!!error) + const { isSendEnabled, isSwapEnabled, isBridgeEnabled, showGasLevels } = + useSelectedNetwork() + + const hotkeysPermissions = { + "/home/alt/s": isSendEnabled, //Send + "/home/alt/w": isSwapEnabled, //Swap + "/home/alt/b": isBridgeEnabled !== undefined, //Bridge + "/home/alt/g": showGasLevels, + } + + const popupPageHotkeys = componentsHotkeys.PopupPage + useHotkeys(popupPageHotkeys, () => { + if (!state.hotkeysEnabled) return + + chrome.tabs.create({ + url: generateExplorerLink( + state.availableNetworks, + state.selectedNetwork, + checksumAddress, + "address" + ), + }) + }) + + return ( + + + {state.isNetworkChanging && } +
+
+
+
+ + + + + My Accounts + + } + /> +
+
+ + { + e.preventDefault() + + history.push( + "/accounts/menu/receive" + ) + }} + className="p-2 transition duration-300 rounded-full hover:bg-primary-grey-default hover:text-primary-blue-default" + > + + +
+
+
+ + { + e.preventDefault() + + history.push("/settings") + }} + className="p-2 transition duration-300 rounded-full hover:bg-primary-grey-default hover:text-primary-blue-default" + > + + +
+
+
+ + } + hotkeysPermissions={hotkeysPermissions} + > + { + setHasErrorDialog(false) + }} + onDone={() => setHasErrorDialog(false)} + /> +
+
+ +
+ + +
+ + +
+
+
+
+ ) +} + +export default HomePage diff --git a/packages/ui/src/routes/PopupPage.tsx b/packages/ui/src/routes/PopupPage.tsx deleted file mode 100644 index edb59e144..000000000 --- a/packages/ui/src/routes/PopupPage.tsx +++ /dev/null @@ -1,563 +0,0 @@ -import { useState } from "react" -import classnames from "classnames" -import { Link, useHistory } from "react-router-dom" -import { BiCircle } from "react-icons/bi" - -// Components -import CopyTooltip from "../components/label/СopyToClipboardTooltip" -import GearIcon from "../components/icons/GearIcon" -import QRIcon from "../components/icons/QRIcon" -import NetworkSelect from "../components/input/NetworkSelect" -import ArrowHoverAnimation from "../components/icons/ArrowHoverAnimation" -import ErrorDialog from "../components/dialog/ErrorDialog" -import AccountIcon from "../components/icons/AccountIcon" -import ActivityAssetsView from "../components/ActivityAssetsView" -import GenericTooltip from "../components/label/GenericTooltip" -import AnimatedIcon, { AnimatedIconName } from "../components/AnimatedIcon" -import Tooltip from "../components/label/Tooltip" - -// Utils -import { formatHash, formatName } from "../util/formatAccount" -import { getAccountColor } from "../util/getAccountColor" -import { HiOutlineExclamationCircle } from "react-icons/hi" - -// Context -import { useBlankState } from "../context/background/backgroundHooks" -import { useSelectedAccount } from "../context/hooks/useSelectedAccount" -import { useSelectedNetwork } from "../context/hooks/useSelectedNetwork" -import { session } from "../context/setup" -import { useConnectedSite } from "../context/hooks/useConnectedSite" - -// Utils -import { useSelectedAddressWithChainIdChecksum } from "../util/hooks/useSelectedAddressWithChainIdChecksum" - -// Assets -import TokenSummary from "../components/token/TokenSummary" -import GasPricesInfo from "../components/gas/GasPricesInfo" -import DoubleArrowHoverAnimation from "../components/icons/DoubleArrowHoverAnimation" -import TransparentOverlay from "../components/loading/TransparentOverlay" -import PopupLayout from "../components/popup/PopupLayout" -import PopupHeader from "../components/popup/PopupHeader" -import Icon, { IconName } from "../components/ui/Icon" -import useNetWorthBalance from "../context/hooks/useNetWorthBalance" -import { AiFillInfoCircle } from "react-icons/ai" -import ProviderStatus from "../components/chain/ProviderStatus" -import { useHotkeys } from "react-hotkeys-hook" -import { componentsHotkeys } from "../util/hotkeys" -import { generateExplorerLink } from "../util/getExplorer" -import { setUserSettings } from "../context/commActions" - -import browser from "webextension-polyfill" - -const AccountDisplay = () => { - const accountAddress = useSelectedAddressWithChainIdChecksum() - const account = useSelectedAccount() - const [copied, setCopied] = useState(false) - const copy = async () => { - await navigator.clipboard.writeText(accountAddress) - setCopied(true) - await new Promise((resolve) => setTimeout(resolve, 1000)) - setCopied(false) - } - return ( - - ) -} - -const DAppConnection = () => { - const dAppConnected = useConnectedSite() - const history = useHistory()! - return ( - -

- {dAppConnected === "connected" ? ( - You are connected to the open site - ) : ( - You are not connected to the open site - )} -

-
- } - > -
{ - if (dAppConnected !== "not-connected") { - history.push({ - pathname: - "/accounts/menu/connectedSites/accountList", - state: { - origin: session?.origin, - fromRoot: true, - }, - }) - } - }} - className={classnames( - "relative flex flex-row items-center py-1 text-primary-grey-dark rounded-md group border-primary-200 text-xs cursor-pointer", - dAppConnected === "connected" && - "pl-2 pr-1 bg-green-100 hover:border-green-300", - dAppConnected === "connected-warning" && - "pl-2 pr-1 bg-yellow-100 hover:border-yellow-300", - dAppConnected === "not-connected" && "pointer-events-none" - )} - > - {dAppConnected === "connected" && ( - - )} - - {dAppConnected === "connected-warning" && ( - - )} - - {dAppConnected === "not-connected" && ( - - )} - - - {dAppConnected === "not-connected" - ? "Not connected" - : "Connected"} - -
- - ) -} - -const PopupPage = () => { - const error = (useHistory().location.state as { error: string })?.error - const state = useBlankState()! - const history = useHistory() - const { - displayNetWorth, - netWorth, - nativeTokenBalance, - nativeTokenBalanceRounded, - nativeCurrencyAmount, - } = useNetWorthBalance() - const { - isSendEnabled, - isSwapEnabled, - isBridgeEnabled, - showGasLevels, - isOnrampEnabled, - } = useSelectedNetwork() - - const checksumAddress = useSelectedAddressWithChainIdChecksum() - const [hasErrorDialog, setHasErrorDialog] = useState(!!error) - - const isLoading = state.isNetworkChanging - - const disabledActions = !isSendEnabled || !state.isUserNetworkOnline - const hotkeysPermissions = { - "/home/alt/s": isSendEnabled, //Send - "/home/alt/w": isSwapEnabled, //Swap - "/home/alt/b": isBridgeEnabled, //Bridge - "/home/alt/g": showGasLevels, - "/home/alt/u": isOnrampEnabled, - } - - const popupPageHotkeys = componentsHotkeys.PopupPage - useHotkeys(popupPageHotkeys, () => { - if (!state.hotkeysEnabled) return - - browser.tabs.create({ - url: generateExplorerLink( - state.availableNetworks, - state.selectedNetwork, - checksumAddress, - "address" - ), - }) - }) - - return ( - - {state.isNetworkChanging && } -
-
- - - - - My Accounts - - } - /> -
-
- -
- { - e.preventDefault() - - history.push("/accounts/menu/receive") - }} - className="p-2 transition duration-300 rounded-full hover:bg-primary-grey-default hover:text-primary-blue-default" - > - - - - Receive funds - - } - /> -
-
-
-
- - { - e.preventDefault() - - history.push("/settings") - }} - className="p-2 transition duration-300 rounded-full hover:bg-primary-grey-default hover:text-primary-blue-default" - > - - -
- - } - hotkeysPermissions={hotkeysPermissions} - > - { - setHasErrorDialog(false) - }} - onDone={() => setHasErrorDialog(false)} - /> -
- - {displayNetWorth - ? "Net Worth" - : nativeCurrencyAmount} -
{ - setUserSettings({ - ...state.settings, - displayNetWorth: !displayNetWorth, - }) - }} - > - -
- - - - -
- {isLoading ? ( -
- -
- ) : ( - - )} -
- - Send - - - {isOnrampEnabled && ( - -
- {isLoading ? ( -
- -
- ) : ( - - )} -
- - Buy - - - )} - {isSwapEnabled && ( - -
- {isLoading ? ( -
- -
- ) : ( - - )} -
- - Swap - - - )} - {isBridgeEnabled && ( - -
- {isLoading ? ( -
- -
- ) : ( - <> - {disabledActions ? ( - - ) : ( - - )} - - )} -
- - Bridge - - - )} -
- - -
-
- - ) -} - -export default PopupPage diff --git a/packages/ui/src/routes/bridge/BridgeSetupPage.tsx b/packages/ui/src/routes/bridge/BridgeSetupPage.tsx index 3bbda051b..189324f66 100644 --- a/packages/ui/src/routes/bridge/BridgeSetupPage.tsx +++ b/packages/ui/src/routes/bridge/BridgeSetupPage.tsx @@ -54,6 +54,7 @@ import { populateBridgeTransaction } from "../../util/bridgeUtils" import BridgeErrorMessage, { BridgeErrorType } from "./BridgeErrorMessage" import usePersistedLocalStorageForm from "../../util/hooks/usePersistedLocalStorageForm" import { secondsToEstimatedMinutes } from "../../util/time" +import { useExchangeRatesState } from "../../context/background/useExchangeRatesState" interface SetupBridgePageLocalState { amount?: string @@ -84,11 +85,13 @@ const BridgeSetupPage: FunctionComponent<{}> = () => { selectedAddress, nativeCurrency, localeInfo, - exchangeRates, availableNetworks, selectedNetwork, availableBridgeChains, } = useBlankState()! + const { + state: { exchangeRates }, + } = useExchangeRatesState() const { nativeToken } = useTokensList() const [bridgeDetails, setBridgeDetails] = useState<{ diff --git a/packages/ui/src/routes/buy/BuyPage.tsx b/packages/ui/src/routes/buy/BuyPage.tsx index b95c18158..3fb570f03 100644 --- a/packages/ui/src/routes/buy/BuyPage.tsx +++ b/packages/ui/src/routes/buy/BuyPage.tsx @@ -15,13 +15,15 @@ import { CurrencySelection } from "../../components/currency/CurrencySelection" import { useBlankState } from "../../context/background/backgroundHooks" import { getOnrampCurrencies } from "../../context/commActions" import { ONRAMPER_API_KEY } from "../../util/onrampUtils" +import { useSelectedNetwork } from "../../context/hooks/useSelectedNetwork" const BuyPage = () => { const history = useOnMountHistory() const [selectedToken, setSelectedToken] = useState() const [acceptedTerms, setAcceptedTerms] = useState(false) const currenctAccountInfo = useSelectedAccount() - const { nativeCurrency, networkNativeCurrency } = useBlankState()! + const { nativeCurrency } = useBlankState()! + const networkNativeCurrency = useSelectedNetwork()!.nativeCurrency const [selectedCurrency, setSelectedCurrency] = useState() const [currencyList, setCurrencyList] = useState([]) const [tokenList, setTokenList] = useState([]) diff --git a/packages/ui/src/routes/dApp/TransactionConfirmPage.tsx b/packages/ui/src/routes/dApp/TransactionConfirmPage.tsx index 1b87aa55c..e4897981c 100644 --- a/packages/ui/src/routes/dApp/TransactionConfirmPage.tsx +++ b/packages/ui/src/routes/dApp/TransactionConfirmPage.tsx @@ -78,6 +78,7 @@ import TransactionDetails from "../../components/transactions/TransactionDetails import { useTransactionWaitingDialog } from "../../context/hooks/useTransactionWaitingDialog" import { canUserSubmitTransaction } from "../../util/transactionUtils" import DAppPopupHeader from "../../components/dApp/DAppPopupHeader" +import { useExchangeRatesState } from "../../context/background/useExchangeRatesState" const TransactionConfirmPage = () => { //Retrieves all the transactions to be processed @@ -114,14 +115,16 @@ const TransactionConfirm: React.FC<{ //Hooks const { accounts, - exchangeRates, nativeCurrency, localeInfo, - networkNativeCurrency, selectedAddress, settings, defaultGasOption, } = useBlankState()! + const { + state: { exchangeRates, networkNativeCurrency }, + } = useExchangeRatesState() + const { isEIP1559Compatible, defaultNetworkLogo } = useSelectedNetwork() const [gasPriceThresholdWarning, setGasPriceThresholdWarning] = useState<{ message?: string diff --git a/packages/ui/src/routes/send/SendConfirmPage.tsx b/packages/ui/src/routes/send/SendConfirmPage.tsx index 4ee516e6c..2eee906ca 100644 --- a/packages/ui/src/routes/send/SendConfirmPage.tsx +++ b/packages/ui/src/routes/send/SendConfirmPage.tsx @@ -65,6 +65,7 @@ import { HardwareWalletOpTypes } from "../../context/commTypes" import { useInProgressInternalTransaction } from "../../context/hooks/useInProgressInternalTransaction" import { rejectTransaction } from "../../context/commActions" import { getValueByKey } from "../../util/objectUtils" +import { useExchangeRatesState } from "../../context/background/useExchangeRatesState" import { AddressDisplay } from "../../components/addressBook/AddressDisplay" import { useAccountNameByAddress } from "../../context/hooks/useAccountNameByAddress" import log from "loglevel" @@ -204,6 +205,9 @@ const SendConfirmPage = () => { const { clear: clearLocationRecovery } = useLocationRecovery() const [allowAmountZero, setAllowAmountZero] = useState(true) const blankState = useBlankState()! + const { + state: { exchangeRates }, + } = useExchangeRatesState() const network = useSelectedNetwork() const history: any = useOnMountHistory() const balance = useSelectedAccountBalance() @@ -347,7 +351,7 @@ const SendConfirmPage = () => { setNativeCurrency( toCurrencyAmount( txAmount, - getValueByKey(blankState.exchangeRates, symbol, 0), + getValueByKey(exchangeRates, symbol, 0), decimals ) ) diff --git a/packages/ui/src/routes/settings/ConnectedSiteAccountsPage.tsx b/packages/ui/src/routes/settings/ConnectedSiteAccountsPage.tsx index b4c969342..464cf7a4d 100644 --- a/packages/ui/src/routes/settings/ConnectedSiteAccountsPage.tsx +++ b/packages/ui/src/routes/settings/ConnectedSiteAccountsPage.tsx @@ -25,6 +25,7 @@ import { useSelectedNetwork } from "../../context/hooks/useSelectedNetwork" import { formatHashLastChars, formatName } from "../../util/formatAccount" import Icon, { IconName } from "../../components/ui/Icon" import Dropdown from "../../components/ui/Dropdown/Dropdown" +import { useExchangeRatesState } from "../../context/background/useExchangeRatesState" export type ConnectedSiteAccountsLocationState = { origin: string @@ -48,7 +49,10 @@ const ConnectedSiteAccount: FunctionComponent<{ }) => { const [hasDialog, setHasDialog] = useState(false) - const { selectedAddress, networkNativeCurrency } = useBlankState()! + const { selectedAddress } = useBlankState()! + const { + state: { networkNativeCurrency }, + } = useExchangeRatesState() const { chainId } = useSelectedNetwork() return ( diff --git a/packages/ui/src/routes/swap/SwapConfirmPage.tsx b/packages/ui/src/routes/swap/SwapConfirmPage.tsx index 16d01df7d..e2d839da4 100644 --- a/packages/ui/src/routes/swap/SwapConfirmPage.tsx +++ b/packages/ui/src/routes/swap/SwapConfirmPage.tsx @@ -80,6 +80,7 @@ import WaitingAllowanceTransactionDialog from "../../components/dialog/WaitingAl import ErrorMessage from "../../components/error/ErrorMessage" import Alert from "../../components/ui/Alert" import PriceImpactDialog from "../../components/swaps/PriceImpactDialog" +import { useExchangeRatesState } from "../../context/background/useExchangeRatesState" export interface SwapConfirmPageLocalState { fromToken: Token @@ -103,7 +104,9 @@ const PRICE_IMPACT_THRESHOLD = 0.1 const SwapPageConfirm: FC<{}> = () => { const history = useOnMountHistory() - const { exchangeRates } = useBlankState()! + const { + state: { exchangeRates }, + } = useExchangeRatesState()! const { fromToken, swapQuote, toToken, allowanceTransactionId } = useMemo( () => history.location.state as SwapConfirmPageLocalState, [history.location.state] diff --git a/packages/ui/src/routes/swap/SwapPage.tsx b/packages/ui/src/routes/swap/SwapPage.tsx index e37fc143a..224fecc68 100644 --- a/packages/ui/src/routes/swap/SwapPage.tsx +++ b/packages/ui/src/routes/swap/SwapPage.tsx @@ -37,6 +37,7 @@ import { useCallback } from "react" import { useTokenBalance } from "../../context/hooks/useTokenBalance" import { GetAmountYupSchema } from "../../util/yup/GetAmountSchema" import { ApproveOperation } from "../transaction/ApprovePage" +import { useExchangeRatesState } from "../../context/background/useExchangeRatesState" import { DEFAULT_EXCHANGE_TYPE } from "../../util/exchangeUtils" interface SwapPageLocalState { @@ -70,8 +71,10 @@ const SwapPage = () => { SWAP_QUOTE_REFRESH_TIMEOUT ) - const { selectedAddress, nativeCurrency, localeInfo, exchangeRates } = - useBlankState()! + const { selectedAddress, nativeCurrency, localeInfo } = useBlankState()! + const { + state: { exchangeRates }, + } = useExchangeRatesState() const { nativeToken } = useTokensList() diff --git a/packages/ui/src/util/balance.ts b/packages/ui/src/util/balance.ts new file mode 100644 index 000000000..0104bff68 --- /dev/null +++ b/packages/ui/src/util/balance.ts @@ -0,0 +1,46 @@ +import { BigNumber } from "@ethersproject/bignumber" +import { formatUnits } from "@ethersproject/units" +import { formatRounded } from "./formatRounded" + +interface TokenInfo { + decimals: number + symbol?: string +} + +interface DisplayOptions { + dislpaySymbol?: boolean + rounded?: boolean + roundedDecimals?: number +} + +const defaultOptions: DisplayOptions = { + dislpaySymbol: true, + rounded: true, + roundedDecimals: 4, +} + +export const formatAssetBalance = ( + balance: BigNumber = BigNumber.from(0), + tokenInfo: TokenInfo, + displayOptions: DisplayOptions = defaultOptions +): string => { + const safeOptions = { + ...defaultOptions, + displayOptions, + } + + let formatedBalance = formatUnits(balance || "0", tokenInfo.decimals) + + if (safeOptions.rounded) { + formatedBalance = formatRounded( + formatedBalance, + safeOptions.roundedDecimals + ) + } + + if (safeOptions.dislpaySymbol) { + formatedBalance = `${formatedBalance} ${tokenInfo.symbol}` + } + + return formatedBalance +} diff --git a/packages/ui/src/util/gasPrice.ts b/packages/ui/src/util/gasPrice.ts index ecb581ec8..c16f899f7 100644 --- a/packages/ui/src/util/gasPrice.ts +++ b/packages/ui/src/util/gasPrice.ts @@ -5,7 +5,7 @@ import { DEFAULT_TRANSACTION_GAS_PERCENTAGE_THRESHOLD } from "./constants" import { formatCurrency, toCurrencyAmount } from "./formatCurrency" import { FeeData } from "@ethersproject/abstract-provider" import { formatUnits } from "@ethersproject/units" -import { DisplayGasPricesData } from "../components/gas/GasPricesInfo" +import { DisplayGasPricesData } from "../components/home/GasPricesInfo" interface GasFeesCalculation { minValue: BigNumber diff --git a/packages/ui/src/util/hooks/useTransactions.ts b/packages/ui/src/util/hooks/useActivtyListTransactions.ts similarity index 82% rename from packages/ui/src/util/hooks/useTransactions.ts rename to packages/ui/src/util/hooks/useActivtyListTransactions.ts index 9f067ed7f..448b40f4b 100644 --- a/packages/ui/src/util/hooks/useTransactions.ts +++ b/packages/ui/src/util/hooks/useActivtyListTransactions.ts @@ -1,5 +1,5 @@ import { BigNumber } from "@ethersproject/bignumber" -import { useBlankState } from "../../context/background/backgroundHooks" +import { useActivityListState } from "../../context/background/useActivityListState" import { MetaType, TransactionCategories, @@ -15,8 +15,12 @@ const failedStatuses = [ TransactionStatus.REJECTED, ] -const useTransactions = () => { - const { confirmed, pending } = useBlankState()!.activityList +const useActivtyListTransactions = () => { + const { + state: { + activityList: { confirmed, pending }, + }, + } = useActivityListState() const { nativeCurrency: networkNativeCurrency, defaultNetworkLogo } = useSelectedNetwork() @@ -44,8 +48,9 @@ const useTransactions = () => { t.transactionParams.value && BigNumber.from(t.transactionParams.value).eq(0) && t.transactionCategory === TransactionCategories.INCOMING - ) + ) { return [] + } if (t.metaType === MetaType.REGULAR_SPEEDING_UP) { const speedUpTx = transactions.find( @@ -60,6 +65,8 @@ const useTransactions = () => { return [ { ...t, + //keep speedUp tx status + status: speedUpTx.status, transactionParams: { ...t.transactionParams, hash: @@ -134,10 +141,28 @@ const useTransactions = () => { } return [t] }) + .sort((tx1, tx2) => { + //keep pending txs always to the top + const tx1Pending = + tx1.status === TransactionStatus.SUBMITTED ? 1 : 0 + const tx2Pending = + tx2.status === TransactionStatus.SUBMITTED ? 1 : 0 + + if (tx1Pending && tx2Pending) { + const tx1Nonce = tx1.transactionParams.nonce + const tx2Nonce = tx2.transactionParams.nonce + if (tx1Nonce !== undefined && tx2Nonce !== undefined) { + return tx1Nonce - tx2Nonce + } + return tx1.time - tx2.time + } + + return tx2Pending - tx1Pending + }) return { transactions: flagQueuedTransactions(allTransactions), } } -export default useTransactions +export default useActivtyListTransactions diff --git a/packages/ui/src/util/hooks/useCurrencyFormatter.ts b/packages/ui/src/util/hooks/useCurrencyFormatter.ts index 0a2cdb866..d3f82fc25 100644 --- a/packages/ui/src/util/hooks/useCurrencyFormatter.ts +++ b/packages/ui/src/util/hooks/useCurrencyFormatter.ts @@ -1,10 +1,14 @@ import { BigNumber } from "@ethersproject/bignumber" import { useBlankState } from "../../context/background/backgroundHooks" +import { useExchangeRatesState } from "../../context/background/useExchangeRatesState" import { formatCurrency, toCurrencyAmount } from "../formatCurrency" import { getValueByKey } from "../objectUtils" const useCurrencyFromatter = () => { const state = useBlankState()! + const { + state: { exchangeRates }, + } = useExchangeRatesState() const format = ( amount: BigNumber, tokenSymbol: string, @@ -14,7 +18,7 @@ const useCurrencyFromatter = () => { const currencyAmount = toCurrencyAmount( amount || BigNumber.from(0), getValueByKey( - state.exchangeRates, + exchangeRates, isNativeCurrency ? tokenSymbol.toUpperCase() : tokenSymbol, 0 ), diff --git a/packages/ui/src/util/hooks/useTokenTransactions.ts b/packages/ui/src/util/hooks/useTokenTransactions.ts index 99b74b2dd..e8ef64077 100644 --- a/packages/ui/src/util/hooks/useTokenTransactions.ts +++ b/packages/ui/src/util/hooks/useTokenTransactions.ts @@ -1,16 +1,17 @@ -import { isNativeTokenAddress } from "../tokenUtils" +import { compareAddresses, isNativeTokenAddress } from "../tokenUtils" import { RichedTransactionMeta } from "../transactionUtils" -import useTransactions from "./useTransactions" +import useActivtyListTransactions from "./useActivtyListTransactions" import { Token } from "@block-wallet/background/controllers/erc-20/Token" import { BigNumber } from "@ethersproject/bignumber" const useTokenTransactions = (token: Token | undefined) => { - const { transactions } = useTransactions() + const { transactions } = useActivtyListTransactions() + if (!token) { return [] as RichedTransactionMeta[] } + try { - const contractToLower = token.address.toLowerCase() return transactions.filter( ({ transactionParams, transactionReceipt, transferType }) => { if (isNativeTokenAddress(token.address)) { @@ -23,9 +24,11 @@ const useTokenTransactions = (token: Token | undefined) => { ) } else { return ( - transactionReceipt?.contractAddress?.toLowerCase() === - contractToLower || - transactionParams.to?.toLowerCase() === contractToLower + compareAddresses( + transactionReceipt?.contractAddress, + token.address + ) || + compareAddresses(transactionParams.to, token.address) ) } } diff --git a/packages/ui/src/util/transactionUtils.ts b/packages/ui/src/util/transactionUtils.ts index 015fbcc88..d354166c9 100644 --- a/packages/ui/src/util/transactionUtils.ts +++ b/packages/ui/src/util/transactionUtils.ts @@ -94,20 +94,23 @@ export const getUITransactionParams = ( gasPrice: !isEIP1559Compatible ? BigNumber.from( transaction?.transactionParams.gasPrice ?? - gasPricesLevels.average.gasPrice + gasPricesLevels.average?.gasPrice ?? + 0 ) : undefined, //EIP-1559 maxPriorityFeePerGas: isEIP1559Compatible ? BigNumber.from( transaction?.transactionParams.maxPriorityFeePerGas ?? - gasPricesLevels.average.maxPriorityFeePerGas + gasPricesLevels.average?.maxPriorityFeePerGas ?? + 0 ) : undefined, maxFeePerGas: isEIP1559Compatible ? BigNumber.from( transaction?.transactionParams.maxFeePerGas ?? - gasPricesLevels.average.maxFeePerGas + gasPricesLevels.average?.maxFeePerGas ?? + 0 ) : undefined, } diff --git a/packages/ui/src/util/useMetricCollector.tsx b/packages/ui/src/util/useMetricCollector.tsx new file mode 100644 index 000000000..1cc28d3a3 --- /dev/null +++ b/packages/ui/src/util/useMetricCollector.tsx @@ -0,0 +1,64 @@ +import { useRef, useEffect, useCallback } from "react" + +const defaultData = { + print: true, + timeFrameInMillis: 60000, +} + +const useMetricCollector = ({ print, timeFrameInMillis } = defaultData) => { + const timing = useRef<{ + id: string + actualDuration: number + }>({ + id: "app", + actualDuration: 0, + }) + + useEffect(() => { + let timeRef: NodeJS.Timeout + if (print) { + timeRef = setInterval(() => { + const actualDuration = timing.current.actualDuration + if ( + process.env.NODE_ENV === "development" && + process.env.LOG_LEVEL === "debug" + ) { + console.log( + `Collecting ${timing.current.id}: `, + actualDuration + ) + } + + timing.current = { + id: timing.current.id, + actualDuration: 0, + } + }, timeFrameInMillis) + } + + return () => { + clearInterval(timeRef) + } + }, []) + + const collect = useCallback( + ( + id: string, // the "id" prop of the Profiler tree that has just committed + phase: "mount" | "update", // either "mount" (if the tree just mounted) or "update" (if it re-rendered) + actualDuration: number // time spent rendering the committed update + ) => { + if (phase === "mount") { + return + } + timing.current = { + id, + actualDuration: timing.current.actualDuration + actualDuration, + } + }, + [] + ) + + return collect +} + +export default useMetricCollector diff --git a/packages/ui/yarn.lock b/packages/ui/yarn.lock index 04ae6b73a..27c42d42d 100644 --- a/packages/ui/yarn.lock +++ b/packages/ui/yarn.lock @@ -63,25 +63,25 @@ "@babel/highlight" "^7.22.13" chalk "^2.4.2" -"@babel/compat-data@^7.20.5", "@babel/compat-data@^7.22.20", "@babel/compat-data@^7.22.6", "@babel/compat-data@^7.22.9": - version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.22.20.tgz#8df6e96661209623f1975d66c35ffca66f3306d0" - integrity sha512-BQYjKbpXjoXwFW5jGqiizJQQT/aC7pFm9Ok1OWssonuguICi264lbgMzRp2ZMmRSlfkX6DsWDDcsrctK8Rwfiw== +"@babel/compat-data@^7.22.6", "@babel/compat-data@^7.22.9", "@babel/compat-data@^7.23.2": + version "7.23.2" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.23.2.tgz#6a12ced93455827037bfb5ed8492820d60fc32cc" + integrity sha512-0S9TQMmDHlqAZ2ITT95irXKfxN9bncq8ZCoJhun3nHL/lLUxd2NKBJYoNGWH7S0hz6fRQwWlAWn/ILM0C70KZQ== -"@babel/core@^7.1.0", "@babel/core@^7.11.1", "@babel/core@^7.12.3", "@babel/core@^7.16.0", "@babel/core@^7.21.0", "@babel/core@^7.7.2", "@babel/core@^7.8.0": - version "7.23.0" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.23.0.tgz#f8259ae0e52a123eb40f552551e647b506a94d83" - integrity sha512-97z/ju/Jy1rZmDxybphrBuI+jtJjFVoz7Mr9yUQVVVi+DNZE333uFQeMOqcCIy1x3WYBIbWftUSLmbNXNT7qFQ== +"@babel/core@^7.1.0", "@babel/core@^7.11.1", "@babel/core@^7.12.3", "@babel/core@^7.16.0", "@babel/core@^7.7.2", "@babel/core@^7.8.0": + version "7.23.2" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.23.2.tgz#ed10df0d580fff67c5f3ee70fd22e2e4c90a9f94" + integrity sha512-n7s51eWdaWZ3vGT2tD4T7J6eJs3QoBXydv7vkUM06Bf1cbVD2Kc2UrkzhiQwobfV7NwOnQXYL7UBJ5VPU+RGoQ== dependencies: "@ampproject/remapping" "^2.2.0" "@babel/code-frame" "^7.22.13" "@babel/generator" "^7.23.0" "@babel/helper-compilation-targets" "^7.22.15" "@babel/helper-module-transforms" "^7.23.0" - "@babel/helpers" "^7.23.0" + "@babel/helpers" "^7.23.2" "@babel/parser" "^7.23.0" "@babel/template" "^7.22.15" - "@babel/traverse" "^7.23.0" + "@babel/traverse" "^7.23.2" "@babel/types" "^7.23.0" convert-source-map "^2.0.0" debug "^4.1.0" @@ -122,7 +122,7 @@ dependencies: "@babel/types" "^7.22.15" -"@babel/helper-compilation-targets@^7.20.7", "@babel/helper-compilation-targets@^7.22.15", "@babel/helper-compilation-targets@^7.22.5", "@babel/helper-compilation-targets@^7.22.6": +"@babel/helper-compilation-targets@^7.22.15", "@babel/helper-compilation-targets@^7.22.5", "@babel/helper-compilation-targets@^7.22.6": version "7.22.15" resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz#0698fc44551a26cf29f18d4662d5bf545a6cfc52" integrity sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw== @@ -157,10 +157,10 @@ regexpu-core "^5.3.1" semver "^6.3.1" -"@babel/helper-define-polyfill-provider@^0.4.2": - version "0.4.2" - resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.2.tgz#82c825cadeeeee7aad237618ebbe8fa1710015d7" - integrity sha512-k0qnnOqHn5dK9pZpfD5XXZ9SojAITdCKRn2Lp6rnDGzIbaP0rHyMPk/4wsSxVBVz4RfN0q6VpXWP2pDGIoQ7hw== +"@babel/helper-define-polyfill-provider@^0.4.3": + version "0.4.3" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.3.tgz#a71c10f7146d809f4a256c373f462d9bba8cf6ba" + integrity sha512-WBrLmuPP47n7PNwsZ57pqam6G/RGo1vw/87b0Blc53tZNGZ4x7YvZ6HgQe2vo1W/FR20OgjeZuGXzudPiXHFug== dependencies: "@babel/helper-compilation-targets" "^7.22.6" "@babel/helper-plugin-utils" "^7.22.5" @@ -195,7 +195,7 @@ dependencies: "@babel/types" "^7.23.0" -"@babel/helper-module-imports@^7.10.4", "@babel/helper-module-imports@^7.18.6", "@babel/helper-module-imports@^7.22.15", "@babel/helper-module-imports@^7.22.5": +"@babel/helper-module-imports@^7.10.4", "@babel/helper-module-imports@^7.22.15", "@babel/helper-module-imports@^7.22.5": version "7.22.15" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz#16146307acdc40cc00c3b2c647713076464bdbf0" integrity sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w== @@ -225,7 +225,7 @@ resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz#dd7ee3735e8a313b9f7b05a773d892e88e6d7295" integrity sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg== -"@babel/helper-remap-async-to-generator@^7.22.5", "@babel/helper-remap-async-to-generator@^7.22.9": +"@babel/helper-remap-async-to-generator@^7.22.20", "@babel/helper-remap-async-to-generator@^7.22.5": version "7.22.20" resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.20.tgz#7b68e1cb4fa964d2996fd063723fb48eca8498e0" integrity sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw== @@ -288,13 +288,13 @@ "@babel/template" "^7.22.15" "@babel/types" "^7.22.19" -"@babel/helpers@^7.23.0": - version "7.23.1" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.23.1.tgz#44e981e8ce2b9e99f8f0b703f3326a4636c16d15" - integrity sha512-chNpneuK18yW5Oxsr+t553UZzzAs3aZnFm4bxhebsNTeshrC95yA7l5yl7GBAG+JG1rF0F7zzD2EixK9mWSDoA== +"@babel/helpers@^7.23.2": + version "7.23.2" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.23.2.tgz#2832549a6e37d484286e15ba36a5330483cac767" + integrity sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ== dependencies: "@babel/template" "^7.22.15" - "@babel/traverse" "^7.23.0" + "@babel/traverse" "^7.23.2" "@babel/types" "^7.23.0" "@babel/highlight@^7.22.13": @@ -327,14 +327,7 @@ "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" "@babel/plugin-transform-optional-chaining" "^7.22.15" -"@babel/plugin-external-helpers@^7.18.6": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-external-helpers/-/plugin-external-helpers-7.22.5.tgz#92b0705b74756123f289388320e0e12c407fdf9a" - integrity sha512-ngnNEWxmykPk82mH4ajZT0qTztr3Je6hrMuKAslZVM8G1YZTENJSYwrIGtt6KOtznug3exmAtF4so/nPqJuA4A== - dependencies: - "@babel/helper-plugin-utils" "^7.22.5" - -"@babel/plugin-proposal-class-properties@^7.16.0", "@babel/plugin-proposal-class-properties@^7.18.6": +"@babel/plugin-proposal-class-properties@^7.16.0": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz#b110f59741895f7ec21a6fff696ec46265c446a3" integrity sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ== @@ -343,9 +336,9 @@ "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-proposal-decorators@^7.16.4": - version "7.23.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.23.0.tgz#66d9014173b3267a9ced3e69935138bc64ffb5c8" - integrity sha512-kYsT+f5ARWF6AdFmqoEEp+hpqxEB8vGmRWfw2aj78M2vTwS2uHW91EF58iFm1Z9U8Y/RrLu2XKJn46P9ca1b0w== + version "7.23.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.23.2.tgz#0b345a5754f48309fa50b7cd99075ef0295b12c8" + integrity sha512-eR0gJQc830fJVGz37oKLvt9W9uUIQSAovUl0e9sJ3YeO09dlcoBVYD3CLrjCj4qHdXmfiyTyFt8yeQYSN5fxLg== dependencies: "@babel/helper-create-class-features-plugin" "^7.22.15" "@babel/helper-plugin-utils" "^7.22.5" @@ -369,17 +362,6 @@ "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-syntax-numeric-separator" "^7.10.4" -"@babel/plugin-proposal-object-rest-spread@^7.20.7": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz#aa662940ef425779c75534a5c41e9d936edc390a" - integrity sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg== - dependencies: - "@babel/compat-data" "^7.20.5" - "@babel/helper-compilation-targets" "^7.20.7" - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-transform-parameters" "^7.20.7" - "@babel/plugin-proposal-optional-chaining@^7.16.0": version "7.21.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.21.0.tgz#886f5c8978deb7d30f678b2e24346b287234d3ea" @@ -581,14 +563,14 @@ dependencies: "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-async-generator-functions@^7.22.15": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.22.15.tgz#3b153af4a6b779f340d5b80d3f634f55820aefa3" - integrity sha512-jBm1Es25Y+tVoTi5rfd5t1KLmL8ogLKpXszboWOTTtGFGz2RKnQe2yn7HbZ+kb/B8N0FVSGQo874NSlOU1T4+w== +"@babel/plugin-transform-async-generator-functions@^7.23.2": + version "7.23.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.23.2.tgz#054afe290d64c6f576f371ccc321772c8ea87ebb" + integrity sha512-BBYVGxbDVHfoeXbOwcagAkOQAm9NxoTdMGfTqghu1GrvadSaw6iW3Je6IcL5PNOw8VwjxqBECXy50/iCQSY/lQ== dependencies: - "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-environment-visitor" "^7.22.20" "@babel/helper-plugin-utils" "^7.22.5" - "@babel/helper-remap-async-to-generator" "^7.22.9" + "@babel/helper-remap-async-to-generator" "^7.22.20" "@babel/plugin-syntax-async-generators" "^7.8.4" "@babel/plugin-transform-async-to-generator@^7.22.5": @@ -607,7 +589,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-block-scoping@^7.22.15": +"@babel/plugin-transform-block-scoping@^7.23.0": version "7.23.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.23.0.tgz#8744d02c6c264d82e1a4bc5d2d501fd8aff6f022" integrity sha512-cOsrbmIOXmf+5YbL99/S49Y3j46k/T16b9ml8bm9lP6N9US5iQ2yBK7gpui1pg0V/WMcXdkfKbTb7HXq9u+v4g== @@ -654,7 +636,7 @@ "@babel/helper-plugin-utils" "^7.22.5" "@babel/template" "^7.22.5" -"@babel/plugin-transform-destructuring@^7.22.15": +"@babel/plugin-transform-destructuring@^7.23.0": version "7.23.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.23.0.tgz#6447aa686be48b32eaf65a73e0e2c0bd010a266c" integrity sha512-vaMdgNXFkYrB+8lbgniSYWHsgqK5gjaMNcc84bMIOMRLH0L9AqYq3hwMdvnyqj1OPqea8UtjPEuS/DCenah1wg== @@ -754,7 +736,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-modules-amd@^7.22.5": +"@babel/plugin-transform-modules-amd@^7.23.0": version "7.23.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.23.0.tgz#05b2bc43373faa6d30ca89214731f76f966f3b88" integrity sha512-xWT5gefv2HGSm4QHtgc1sYPbseOyf+FFDo2JbpE25GWl5BqTGO9IMwTYJRoIdjsF85GE+VegHxSCUt5EvoYTAw== @@ -762,7 +744,7 @@ "@babel/helper-module-transforms" "^7.23.0" "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-modules-commonjs@^7.22.15", "@babel/plugin-transform-modules-commonjs@^7.23.0": +"@babel/plugin-transform-modules-commonjs@^7.23.0": version "7.23.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.23.0.tgz#b3dba4757133b2762c00f4f94590cf6d52602481" integrity sha512-32Xzss14/UVc7k9g775yMIvkVK8xwKE0DPdP5JTapr3+Z9w4tzeOuLNY6BXDQR6BdnzIlXnCGAzsk/ICHBLVWQ== @@ -771,7 +753,7 @@ "@babel/helper-plugin-utils" "^7.22.5" "@babel/helper-simple-access" "^7.22.5" -"@babel/plugin-transform-modules-systemjs@^7.22.11": +"@babel/plugin-transform-modules-systemjs@^7.23.0": version "7.23.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.23.0.tgz#77591e126f3ff4132a40595a6cccd00a6b60d160" integrity sha512-qBej6ctXZD2f+DhlOC9yO47yEYgUh5CZNz/aBoH4j/3NOlRfJXJbY7xDQCqQVf9KbrqGzIWER1f23doHGrIHFg== @@ -847,7 +829,7 @@ "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" -"@babel/plugin-transform-optional-chaining@^7.22.15": +"@babel/plugin-transform-optional-chaining@^7.22.15", "@babel/plugin-transform-optional-chaining@^7.23.0": version "7.23.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.23.0.tgz#73ff5fc1cf98f542f09f29c0631647d8ad0be158" integrity sha512-sBBGXbLJjxTzLBF5rFWaikMnOGOk/BmK6vVByIdEggZ7Vn6CvWXZyRkkLFK6WE0IF8jSliyOkUN6SScFgzCM0g== @@ -856,7 +838,7 @@ "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" "@babel/plugin-syntax-optional-chaining" "^7.8.3" -"@babel/plugin-transform-parameters@^7.20.7", "@babel/plugin-transform-parameters@^7.22.15": +"@babel/plugin-transform-parameters@^7.22.15": version "7.22.15" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.22.15.tgz#719ca82a01d177af358df64a514d64c2e3edb114" integrity sha512-hjk7qKIqhyzhhUvRT683TYQOFa/4cQKwQy7ALvTpODswN40MljzNDa0YldevS6tGbxwaEKVn502JmY0dP7qEtQ== @@ -944,15 +926,15 @@ "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-transform-runtime@^7.16.4": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.22.15.tgz#3a625c4c05a39e932d7d34f5d4895cdd0172fdc9" - integrity sha512-tEVLhk8NRZSmwQ0DJtxxhTrCht1HVo8VaMzYT4w6lwyKBuHsgoioAUA7/6eT2fRfc5/23fuGdlwIxXhRVgWr4g== + version "7.23.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.23.2.tgz#c956a3f8d1aa50816ff6c30c6288d66635c12990" + integrity sha512-XOntj6icgzMS58jPVtQpiuF6ZFWxQiJavISGx5KGjRj+3gqZr8+N6Kx+N9BApWzgS+DOjIZfXXj0ZesenOWDyA== dependencies: "@babel/helper-module-imports" "^7.22.15" "@babel/helper-plugin-utils" "^7.22.5" - babel-plugin-polyfill-corejs2 "^0.4.5" - babel-plugin-polyfill-corejs3 "^0.8.3" - babel-plugin-polyfill-regenerator "^0.5.2" + babel-plugin-polyfill-corejs2 "^0.4.6" + babel-plugin-polyfill-corejs3 "^0.8.5" + babel-plugin-polyfill-regenerator "^0.5.3" semver "^6.3.1" "@babel/plugin-transform-shorthand-properties@^7.22.5": @@ -1032,12 +1014,12 @@ "@babel/helper-create-regexp-features-plugin" "^7.22.5" "@babel/helper-plugin-utils" "^7.22.5" -"@babel/preset-env@^7.11.0", "@babel/preset-env@^7.12.1", "@babel/preset-env@^7.16.4", "@babel/preset-env@^7.20.2": - version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.22.20.tgz#de9e9b57e1127ce0a2f580831717f7fb677ceedb" - integrity sha512-11MY04gGC4kSzlPHRfvVkNAZhUxOvm7DCJ37hPDnUENwe06npjIRAfInEMTGSb4LZK5ZgDFkv5hw0lGebHeTyg== +"@babel/preset-env@^7.11.0", "@babel/preset-env@^7.12.1", "@babel/preset-env@^7.16.4": + version "7.23.2" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.23.2.tgz#1f22be0ff0e121113260337dbc3e58fafce8d059" + integrity sha512-BW3gsuDD+rvHL2VO2SjAUNTBe5YrjsTiDyqamPDWY723na3/yPQ65X5oQkFVJZ0o50/2d+svm1rkPoJeR1KxVQ== dependencies: - "@babel/compat-data" "^7.22.20" + "@babel/compat-data" "^7.23.2" "@babel/helper-compilation-targets" "^7.22.15" "@babel/helper-plugin-utils" "^7.22.5" "@babel/helper-validator-option" "^7.22.15" @@ -1063,15 +1045,15 @@ "@babel/plugin-syntax-top-level-await" "^7.14.5" "@babel/plugin-syntax-unicode-sets-regex" "^7.18.6" "@babel/plugin-transform-arrow-functions" "^7.22.5" - "@babel/plugin-transform-async-generator-functions" "^7.22.15" + "@babel/plugin-transform-async-generator-functions" "^7.23.2" "@babel/plugin-transform-async-to-generator" "^7.22.5" "@babel/plugin-transform-block-scoped-functions" "^7.22.5" - "@babel/plugin-transform-block-scoping" "^7.22.15" + "@babel/plugin-transform-block-scoping" "^7.23.0" "@babel/plugin-transform-class-properties" "^7.22.5" "@babel/plugin-transform-class-static-block" "^7.22.11" "@babel/plugin-transform-classes" "^7.22.15" "@babel/plugin-transform-computed-properties" "^7.22.5" - "@babel/plugin-transform-destructuring" "^7.22.15" + "@babel/plugin-transform-destructuring" "^7.23.0" "@babel/plugin-transform-dotall-regex" "^7.22.5" "@babel/plugin-transform-duplicate-keys" "^7.22.5" "@babel/plugin-transform-dynamic-import" "^7.22.11" @@ -1083,9 +1065,9 @@ "@babel/plugin-transform-literals" "^7.22.5" "@babel/plugin-transform-logical-assignment-operators" "^7.22.11" "@babel/plugin-transform-member-expression-literals" "^7.22.5" - "@babel/plugin-transform-modules-amd" "^7.22.5" - "@babel/plugin-transform-modules-commonjs" "^7.22.15" - "@babel/plugin-transform-modules-systemjs" "^7.22.11" + "@babel/plugin-transform-modules-amd" "^7.23.0" + "@babel/plugin-transform-modules-commonjs" "^7.23.0" + "@babel/plugin-transform-modules-systemjs" "^7.23.0" "@babel/plugin-transform-modules-umd" "^7.22.5" "@babel/plugin-transform-named-capturing-groups-regex" "^7.22.5" "@babel/plugin-transform-new-target" "^7.22.5" @@ -1094,7 +1076,7 @@ "@babel/plugin-transform-object-rest-spread" "^7.22.15" "@babel/plugin-transform-object-super" "^7.22.5" "@babel/plugin-transform-optional-catch-binding" "^7.22.11" - "@babel/plugin-transform-optional-chaining" "^7.22.15" + "@babel/plugin-transform-optional-chaining" "^7.23.0" "@babel/plugin-transform-parameters" "^7.22.15" "@babel/plugin-transform-private-methods" "^7.22.5" "@babel/plugin-transform-private-property-in-object" "^7.22.11" @@ -1111,10 +1093,10 @@ "@babel/plugin-transform-unicode-regex" "^7.22.5" "@babel/plugin-transform-unicode-sets-regex" "^7.22.5" "@babel/preset-modules" "0.1.6-no-external-plugins" - "@babel/types" "^7.22.19" - babel-plugin-polyfill-corejs2 "^0.4.5" - babel-plugin-polyfill-corejs3 "^0.8.3" - babel-plugin-polyfill-regenerator "^0.5.2" + "@babel/types" "^7.23.0" + babel-plugin-polyfill-corejs2 "^0.4.6" + babel-plugin-polyfill-corejs3 "^0.8.5" + babel-plugin-polyfill-regenerator "^0.5.3" core-js-compat "^3.31.0" semver "^6.3.1" @@ -1127,7 +1109,7 @@ "@babel/types" "^7.4.4" esutils "^2.0.2" -"@babel/preset-react@^7.12.5", "@babel/preset-react@^7.16.0", "@babel/preset-react@^7.18.6": +"@babel/preset-react@^7.12.5", "@babel/preset-react@^7.16.0": version "7.22.15" resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.22.15.tgz#9a776892b648e13cc8ca2edf5ed1264eea6b6afc" integrity sha512-Csy1IJ2uEh/PecCBXXoZGAZBeCATTuePzCSB7dLYWS0vOEj6CNpjxIhW4duWwZodBNueH7QO14WbGn8YyeuN9w== @@ -1139,10 +1121,10 @@ "@babel/plugin-transform-react-jsx-development" "^7.22.5" "@babel/plugin-transform-react-pure-annotations" "^7.22.5" -"@babel/preset-typescript@^7.16.0", "@babel/preset-typescript@^7.21.0": - version "7.23.0" - resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.23.0.tgz#cc6602d13e7e5b2087c811912b87cf937a9129d9" - integrity sha512-6P6VVa/NM/VlAYj5s2Aq/gdVg8FSENCg3wlZ6Qau9AcPaoF5LbN1nyGlR9DTRIw9PpxI94e+ReydsJHcjwAweg== +"@babel/preset-typescript@^7.16.0": + version "7.23.2" + resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.23.2.tgz#c8de488130b7081f7e1482936ad3de5b018beef4" + integrity sha512-u4UJc1XsS1GhIGteM8rnGiIvf9rJpiVgMEeCnwlLA7WJPC+jcXWJAGxYmeqs5hOZD8BbAfnV5ezBOxQbb4OUxA== dependencies: "@babel/helper-plugin-utils" "^7.22.5" "@babel/helper-validator-option" "^7.22.15" @@ -1155,10 +1137,10 @@ resolved "https://registry.yarnpkg.com/@babel/regjsgen/-/regjsgen-0.8.0.tgz#f0ba69b075e1f05fb2825b7fad991e7adbb18310" integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA== -"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.3", "@babel/runtime@^7.20.7", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": - version "7.23.1" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.1.tgz#72741dc4d413338a91dcb044a86f3c0bc402646d" - integrity sha512-hC2v6p8ZSI/W0HUzh3V8C5g+NwSKzKPtJwSpTjwl0o297GP9+ZLQSkdvHz46CM3LqyoXxq+5G9komY+eSqSO0g== +"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.3", "@babel/runtime@^7.20.7", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": + version "7.23.2" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.2.tgz#062b0ac103261d68a966c4c7baf2ae3e62ec3885" + integrity sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg== dependencies: regenerator-runtime "^0.14.0" @@ -1171,10 +1153,10 @@ "@babel/parser" "^7.22.15" "@babel/types" "^7.22.15" -"@babel/traverse@^7.1.0", "@babel/traverse@^7.21.2", "@babel/traverse@^7.23.0", "@babel/traverse@^7.7.0", "@babel/traverse@^7.7.2": - version "7.23.0" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.0.tgz#18196ddfbcf4ccea324b7f6d3ada00d8c5a99c53" - integrity sha512-t/QaEvyIoIkwzpiZ7aoSKK8kObQYeF7T2v+dazAYCb8SXtp58zEVkWW7zAnju8FNKNdr4ScAOEDmMItbyOmEYw== +"@babel/traverse@^7.1.0", "@babel/traverse@^7.23.2", "@babel/traverse@^7.7.0", "@babel/traverse@^7.7.2": + version "7.23.2" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.2.tgz#329c7a06735e144a506bdb2cad0268b7f46f4ad8" + integrity sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw== dependencies: "@babel/code-frame" "^7.22.13" "@babel/generator" "^7.23.0" @@ -1360,9 +1342,9 @@ eslint-visitor-keys "^3.3.0" "@eslint-community/regexpp@^4.4.0", "@eslint-community/regexpp@^4.5.1", "@eslint-community/regexpp@^4.6.1": - version "4.9.0" - resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.9.0.tgz#7ccb5f58703fa61ffdcbf39e2c604a109e781162" - integrity sha512-zJmuCWj2VLBt4c25CfBIbMZLGLyhkvs7LznyVX5HfpzeocThgIj5XQK4L+g3U36mMcx8bPMhGyPpwCATamC4jQ== + version "4.9.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.9.1.tgz#449dfa81a57a1d755b09aa58d826c1262e4283b4" + integrity sha512-Y27x+MBLjXa+0JWDhykM3+JE+il3kHKAEqabfEWq3SDhZjLYb6/BHL/JKFnH3fe207JaXkyDo685Oc2Glt6ifA== "@eslint/eslintrc@^2.1.2": version "2.1.2" @@ -1379,10 +1361,10 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@8.50.0": - version "8.50.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.50.0.tgz#9e93b850f0f3fa35f5fa59adfd03adae8488e484" - integrity sha512-NCC3zz2+nvYd+Ckfh87rA47zfu2QsQpvc6k1yzTk+b9KzRj0wkGa8LSoGOXN6Zv4lRf/EIoZ80biDh9HOI+RNQ== +"@eslint/js@8.51.0": + version "8.51.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.51.0.tgz#6d419c240cfb2b66da37df230f7e7eef801c32fa" + integrity sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg== "@ethersproject/abi@5.7.0", "@ethersproject/abi@^5.7.0": version "5.7.0" @@ -2140,9 +2122,9 @@ integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== "@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9": - version "0.3.19" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz#f8a3249862f91be48d3127c3cfe992f79b4b8811" - integrity sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw== + version "0.3.20" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz#72e45707cf240fa6b081d0366f8265b0cd10197f" + integrity sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q== dependencies: "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" @@ -2304,9 +2286,9 @@ picomatch "^2.2.2" "@rushstack/eslint-patch@^1.1.0": - version "1.5.0" - resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.5.0.tgz#5143b0da9c536bfe8beddfeb68bb8b5d647cc7a3" - integrity sha512-EF3948ckf3f5uPgYbQ6GhyA56Dmv8yg0+ir+BroRjwdxyZJsekhZzawOecC2rOTPCz173t7ZcR1HHZu0dZgOCw== + version "1.5.1" + resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.5.1.tgz#5f1b518ec5fa54437c0b7c4a821546c64fed6922" + integrity sha512-6i/8UoL0P5y4leBIGzvkZdS85RDMG9y1ihZzmTZQ5LdHUYmZ7pKFoj8X0236s3lusPs1Fa5HTQUpwI+UfTcmeA== "@sinclair/typebox@^0.24.1": version "0.24.51" @@ -2631,9 +2613,9 @@ "@types/estree" "*" "@types/eslint@*", "@types/eslint@^7.29.0 || ^8.4.1": - version "8.44.3" - resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.44.3.tgz#96614fae4875ea6328f56de38666f582d911d962" - integrity sha512-iM/WfkwAhwmPff3wZuPLYiHX18HI24jU8k1ZSH7P8FHwxTjZ2P6CoX2wnF43oprR+YXJM6UUxATkNvyv/JHd+g== + version "8.44.4" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.44.4.tgz#28eaff82e1ca0a96554ec5bb0188f10ae1a74c2f" + integrity sha512-lOzjyfY/D9QR4hY9oblZ76B90MYTB3RrQ4z2vBIJKj9ROCRqdkYl2gSUx1x1a4IWPjKJZLL4Aw1Zfay7eMnmnA== dependencies: "@types/estree" "*" "@types/json-schema" "*" @@ -2659,9 +2641,9 @@ "@types/send" "*" "@types/express@*", "@types/express@^4.17.13": - version "4.17.18" - resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.18.tgz#efabf5c4495c1880df1bdffee604b143b29c4a95" - integrity sha512-Sxv8BSLLgsBYmcnGdGjjEjqET2U+AKAdCRODmMiq02FgjwuV75Ut85DRpvFjyw/Mk0vgUOliGRU0UUmuuZHByQ== + version "4.17.19" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.19.tgz#6ff9b4851fda132c5d3dcd2f89fdb6a7a0031ced" + integrity sha512-UtOfBtzN9OvpZPPbnnYunfjM7XCI4jyk1NvnFhTVz5krYAnW4o5DCoIekvms+8ApqhB4+9wSge1kBijdfTSmfg== dependencies: "@types/body-parser" "*" "@types/express-serve-static-core" "^4.17.33" @@ -2698,9 +2680,9 @@ integrity sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA== "@types/hoist-non-react-statics@*", "@types/hoist-non-react-statics@^3.3.1": - version "3.3.2" - resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#dc1e9ded53375d37603c479cc12c693b0878aa2a" - integrity sha512-YIQtIg4PKr7ZyqNPZObpxfHsHEmuB8dXCxd6qVcGuQVDK2bpsF7bYNnBJ4Nn7giuACZg+WewExgrtAJ3XnA4Xw== + version "3.3.3" + resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.3.tgz#8bb41d9a88164f82dd2745ff05e637e655f34d19" + integrity sha512-Wny3a2UXn5FEA1l7gc6BbpoV5mD1XijZqgkp4TRgDCDL5r3B5ieOFGUX5h3n78Tr1MEG7BfvoM8qeztdvNU0fw== dependencies: "@types/react" "*" hoist-non-react-statics "^3.3.0" @@ -2788,9 +2770,11 @@ integrity sha512-Ys+/St+2VF4+xuY6+kDIXGxbNRO0mesVg0bbxEfB97Od1Vjpjx9KD1qxs64Gcb3CWPirk9Xe+PT4YiiHQ9T+eg== "@types/node@*": - version "20.7.1" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.7.1.tgz#06d732ead0bd5ad978ef0ea9cbdeb24dc8717514" - integrity sha512-LT+OIXpp2kj4E2S/p91BMe+VgGX2+lfO+XTpfXhh+bCk2LkQtHZSub8ewFBMGP5ClysPjTDFa4sMI8Q3n4T0wg== + version "20.8.6" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.8.6.tgz#0dbd4ebcc82ad0128df05d0e6f57e05359ee47fa" + integrity sha512-eWO4K2Ji70QzKUqRy6oyJWUeB7+g2cRagT3T/nxYibYcT4y2BDL8lqolRXjTHmkZCdJfIPaY73KbJAZmcryxTQ== + dependencies: + undici-types "~5.25.1" "@types/normalize-package-data@^2.4.0": version "2.4.2" @@ -2815,9 +2799,9 @@ integrity sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA== "@types/prop-types@*": - version "15.7.7" - resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.7.tgz#f9361f7b87fd5d8188b2c998db0a1f47e9fb391a" - integrity sha512-FbtmBWCcSa2J4zL781Zf1p5YUBXQomPEcep9QZCfRfQgTxz3pJWiDFLebohZ9fFntX5ibzOkSsrJ0TEew8cAog== + version "15.7.8" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.8.tgz#805eae6e8f41bd19e88917d2ea200dc992f405d3" + integrity sha512-kMpQpfZKSCBqltAJwskgePRaYRFukDkm1oItcAbC3gNELR20XIBcN9VRgg4+m8DKsTfkWeA4m4Imp4DDuWy7FQ== "@types/q@^1.5.1": version "1.5.6" @@ -2842,9 +2826,9 @@ integrity sha512-xrO9OoVPqFuYyR/loIHjnbvvyRZREYKLjxV4+dY6v3FQR3stQ9ZxIGkaclF7YhI9hfjpuTbu14hZEy94qKLtOA== "@types/react-dom@^18.0.0", "@types/react-dom@^18.2.7": - version "18.2.8" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.2.8.tgz#338f1b0a646c9f10e0a97208c1d26b9f473dffd6" - integrity sha512-bAIvO5lN/U8sPGvs1Xm61rlRHHaq5rp5N3kp9C+NJ/Q41P8iqjkXSu0+/qu8POsjH9pNWb0OYabFez7taP7omw== + version "18.2.13" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.2.13.tgz#89cd7f9ec8b28c8b6f0392b9591671fb4a9e96b7" + integrity sha512-eJIUv7rPP+EC45uNYp/ThhSpE16k22VJUknt5OLoH9tbXoi8bMhwLf5xRuWMywamNbWzhrSmU7IBJfPup1+3fw== dependencies: "@types/react" "*" @@ -2893,6 +2877,14 @@ dependencies: "@types/react" "*" +"@types/react-virtualized@^9.21.23": + version "9.21.23" + resolved "https://registry.yarnpkg.com/@types/react-virtualized/-/react-virtualized-9.21.23.tgz#62c4b20b796351eca8e2f816c263b39b69ed97d0" + integrity sha512-8GX+P+nUl+c1qlyb3z0lQExQfoHPscBliZiBEUQ90PzMHY76XvkMawmKMyhvAUlCemhlEnvZdvWsyQAK5E/Jeg== + dependencies: + "@types/prop-types" "*" + "@types/react" "*" + "@types/react-window@^1.8.5": version "1.8.6" resolved "https://registry.yarnpkg.com/@types/react-window/-/react-window-1.8.6.tgz#4faba05b86abd36f40b612a5b02e28fadcf95c7c" @@ -2901,9 +2893,9 @@ "@types/react" "*" "@types/react@*", "@types/react@^18.2.22": - version "18.2.23" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.23.tgz#60ad6cf4895e93bed858db0e03bcc4ff97d0410e" - integrity sha512-qHLW6n1q2+7KyBEYnrZpcsAmU/iiCh9WGCKgXvMxx89+TYdJWRjZohVIo9XTcoLhfX3+/hP0Pbulu3bCZQ9PSA== + version "18.2.28" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.28.tgz#86877465c0fcf751659a36c769ecedfcfacee332" + integrity sha512-ad4aa/RaaJS3hyGz0BGegdnSRXQBkd1CCYDCdNjBPg90UUpLgo+WlJqb9fMYUxtehmzF3PJaTWqRZjko6BRzBg== dependencies: "@types/prop-types" "*" "@types/scheduler" "*" @@ -3021,9 +3013,9 @@ integrity sha512-pvEIqAZEbJRzaqTaWq3xlUoMWa3+euZHHz+VZHCzHWW+jOf8qLOq9wXy38U+WiPG3108SJC/wNc1X6vPC5TcjQ== "@types/ws@^8.5.5": - version "8.5.6" - resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.6.tgz#e9ad51f0ab79b9110c50916c9fcbddc36d373065" - integrity sha512-8B5EO9jLVCy+B58PLHvLDuOD8DRVMgQzq8d55SjLCOn9kqGyqOvy27exVaTio1q1nX5zLu8/6N0n2ThSxOM6tg== + version "8.5.7" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.7.tgz#1ca585074fe5d2c81dec7a3d451f244a2a6d83cb" + integrity sha512-6UrLjiDUvn40CMrAubXuIVtj2PEfKDffJS7ychvnPU44j+KVeXmdHHTgqcM/dxLUTHxlXHiFM8Skmb8ozGdTnQ== dependencies: "@types/node" "*" @@ -3047,9 +3039,9 @@ "@types/yargs-parser" "*" "@types/yargs@^17.0.8": - version "17.0.25" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.25.tgz#3edd102803c97356fb4c805b2bbaf7dfc9ab6abc" - integrity sha512-gy7iPgwnzNvxgAEi2bXOHWCVOG6f7xsprVJH4MjlAWeBmJ7vh/Y1kwMtUrs64ztf24zVIRCpr3n/z6gm9QIkgg== + version "17.0.28" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.28.tgz#d106e4301fbacde3d1796ab27374dd16588ec851" + integrity sha512-N3e3fkS86hNhtk6BEnc0rj3zcehaxx8QWhCROJkqpl5Zaoi7nAic3jH8q94jVD3zu5LGk+PUB6KAiDmimYOEQw== dependencies: "@types/yargs-parser" "*" @@ -3070,15 +3062,15 @@ tsutils "^3.21.0" "@typescript-eslint/eslint-plugin@^6.7.2": - version "6.7.3" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.3.tgz#d98046e9f7102d49a93d944d413c6055c47fafd7" - integrity sha512-vntq452UHNltxsaaN+L9WyuMch8bMd9CqJ3zhzTPXXidwbf5mqqKCVXEuvRZUqLJSTLeWE65lQwyXsRGnXkCTA== + version "6.8.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.8.0.tgz#06abe4265e7c82f20ade2dcc0e3403c32d4f148b" + integrity sha512-GosF4238Tkes2SHPQ1i8f6rMtG6zlKwMEB0abqSJ3Npvos+doIlc/ATG+vX1G9coDF3Ex78zM3heXHLyWEwLUw== dependencies: "@eslint-community/regexpp" "^4.5.1" - "@typescript-eslint/scope-manager" "6.7.3" - "@typescript-eslint/type-utils" "6.7.3" - "@typescript-eslint/utils" "6.7.3" - "@typescript-eslint/visitor-keys" "6.7.3" + "@typescript-eslint/scope-manager" "6.8.0" + "@typescript-eslint/type-utils" "6.8.0" + "@typescript-eslint/utils" "6.8.0" + "@typescript-eslint/visitor-keys" "6.8.0" debug "^4.3.4" graphemer "^1.4.0" ignore "^5.2.4" @@ -3116,14 +3108,14 @@ debug "^4.3.4" "@typescript-eslint/parser@^6.7.2": - version "6.7.3" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.7.3.tgz#aaf40092a32877439e5957e18f2d6a91c82cc2fd" - integrity sha512-TlutE+iep2o7R8Lf+yoer3zU6/0EAUc8QIBB3GYBc1KGz4c4TRm83xwXUZVPlZ6YCLss4r77jbu6j3sendJoiQ== - dependencies: - "@typescript-eslint/scope-manager" "6.7.3" - "@typescript-eslint/types" "6.7.3" - "@typescript-eslint/typescript-estree" "6.7.3" - "@typescript-eslint/visitor-keys" "6.7.3" + version "6.8.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.8.0.tgz#bb2a969d583db242f1ee64467542f8b05c2e28cb" + integrity sha512-5tNs6Bw0j6BdWuP8Fx+VH4G9fEPDxnVI7yH1IAPkQH5RUtvKwRoqdecAPdQXv4rSOADAaz1LFBZvZG7VbXivSg== + dependencies: + "@typescript-eslint/scope-manager" "6.8.0" + "@typescript-eslint/types" "6.8.0" + "@typescript-eslint/typescript-estree" "6.8.0" + "@typescript-eslint/visitor-keys" "6.8.0" debug "^4.3.4" "@typescript-eslint/scope-manager@4.33.0": @@ -3142,13 +3134,13 @@ "@typescript-eslint/types" "5.62.0" "@typescript-eslint/visitor-keys" "5.62.0" -"@typescript-eslint/scope-manager@6.7.3": - version "6.7.3" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.7.3.tgz#07e5709c9bdae3eaf216947433ef97b3b8b7d755" - integrity sha512-wOlo0QnEou9cHO2TdkJmzF7DFGvAKEnB82PuPNHpT8ZKKaZu6Bm63ugOTn9fXNJtvuDPanBc78lGUGGytJoVzQ== +"@typescript-eslint/scope-manager@6.8.0": + version "6.8.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.8.0.tgz#5cac7977385cde068ab30686889dd59879811efd" + integrity sha512-xe0HNBVwCph7rak+ZHcFD6A+q50SMsFwcmfdjs9Kz4qDh5hWhaPhFjRs/SODEhroBI5Ruyvyz9LfwUJ624O40g== dependencies: - "@typescript-eslint/types" "6.7.3" - "@typescript-eslint/visitor-keys" "6.7.3" + "@typescript-eslint/types" "6.8.0" + "@typescript-eslint/visitor-keys" "6.8.0" "@typescript-eslint/type-utils@5.62.0": version "5.62.0" @@ -3160,13 +3152,13 @@ debug "^4.3.4" tsutils "^3.21.0" -"@typescript-eslint/type-utils@6.7.3": - version "6.7.3" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.7.3.tgz#c2c165c135dda68a5e70074ade183f5ad68f3400" - integrity sha512-Fc68K0aTDrKIBvLnKTZ5Pf3MXK495YErrbHb1R6aTpfK5OdSFj0rVN7ib6Tx6ePrZ2gsjLqr0s98NG7l96KSQw== +"@typescript-eslint/type-utils@6.8.0": + version "6.8.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.8.0.tgz#50365e44918ca0fd159844b5d6ea96789731e11f" + integrity sha512-RYOJdlkTJIXW7GSldUIHqc/Hkto8E+fZN96dMIFhuTJcQwdRoGN2rEWA8U6oXbLo0qufH7NPElUb+MceHtz54g== dependencies: - "@typescript-eslint/typescript-estree" "6.7.3" - "@typescript-eslint/utils" "6.7.3" + "@typescript-eslint/typescript-estree" "6.8.0" + "@typescript-eslint/utils" "6.8.0" debug "^4.3.4" ts-api-utils "^1.0.1" @@ -3180,10 +3172,10 @@ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.62.0.tgz#258607e60effa309f067608931c3df6fed41fd2f" integrity sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ== -"@typescript-eslint/types@6.7.3": - version "6.7.3" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.7.3.tgz#0402b5628a63f24f2dc9d4a678e9a92cc50ea3e9" - integrity sha512-4g+de6roB2NFcfkZb439tigpAMnvEIg3rIjWQ+EM7IBaYt/CdJt6em9BJ4h4UpdgaBWdmx2iWsafHTrqmgIPNw== +"@typescript-eslint/types@6.8.0": + version "6.8.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.8.0.tgz#1ab5d4fe1d613e3f65f6684026ade6b94f7e3ded" + integrity sha512-p5qOxSum7W3k+llc7owEStXlGmSl8FcGvhYt8Vjy7FqEnmkCVlM3P57XQEGj58oqaBWDQXbJDZxwUWMS/EAPNQ== "@typescript-eslint/typescript-estree@4.33.0": version "4.33.0" @@ -3211,13 +3203,13 @@ semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/typescript-estree@6.7.3": - version "6.7.3" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.3.tgz#ec5bb7ab4d3566818abaf0e4a8fa1958561b7279" - integrity sha512-YLQ3tJoS4VxLFYHTw21oe1/vIZPRqAO91z6Uv0Ss2BKm/Ag7/RVQBcXTGcXhgJMdA4U+HrKuY5gWlJlvoaKZ5g== +"@typescript-eslint/typescript-estree@6.8.0": + version "6.8.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.8.0.tgz#9565f15e0cd12f55cf5aa0dfb130a6cb0d436ba1" + integrity sha512-ISgV0lQ8XgW+mvv5My/+iTUdRmGspducmQcDw5JxznasXNnZn3SKNrTRuMsEXv+V/O+Lw9AGcQCfVaOPCAk/Zg== dependencies: - "@typescript-eslint/types" "6.7.3" - "@typescript-eslint/visitor-keys" "6.7.3" + "@typescript-eslint/types" "6.8.0" + "@typescript-eslint/visitor-keys" "6.8.0" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" @@ -3238,17 +3230,17 @@ eslint-scope "^5.1.1" semver "^7.3.7" -"@typescript-eslint/utils@6.7.3": - version "6.7.3" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.7.3.tgz#96c655816c373135b07282d67407cb577f62e143" - integrity sha512-vzLkVder21GpWRrmSR9JxGZ5+ibIUSudXlW52qeKpzUEQhRSmyZiVDDj3crAth7+5tmN1ulvgKaCU2f/bPRCzg== +"@typescript-eslint/utils@6.8.0": + version "6.8.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.8.0.tgz#d42939c2074c6b59844d0982ce26a51d136c4029" + integrity sha512-dKs1itdE2qFG4jr0dlYLQVppqTE+Itt7GmIf/vX6CSvsW+3ov8PbWauVKyyfNngokhIO9sKZeRGCUo1+N7U98Q== dependencies: "@eslint-community/eslint-utils" "^4.4.0" "@types/json-schema" "^7.0.12" "@types/semver" "^7.5.0" - "@typescript-eslint/scope-manager" "6.7.3" - "@typescript-eslint/types" "6.7.3" - "@typescript-eslint/typescript-estree" "6.7.3" + "@typescript-eslint/scope-manager" "6.8.0" + "@typescript-eslint/types" "6.8.0" + "@typescript-eslint/typescript-estree" "6.8.0" semver "^7.5.4" "@typescript-eslint/visitor-keys@4.33.0": @@ -3267,12 +3259,12 @@ "@typescript-eslint/types" "5.62.0" eslint-visitor-keys "^3.3.0" -"@typescript-eslint/visitor-keys@6.7.3": - version "6.7.3" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.3.tgz#83809631ca12909bd2083558d2f93f5747deebb2" - integrity sha512-HEVXkU9IB+nk9o63CeICMHxFWbHWr3E1mpilIQBe9+7L/lH97rleFLVtYsfnWB+JVMaiFnEaxvknvmIzX+CqVg== +"@typescript-eslint/visitor-keys@6.8.0": + version "6.8.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.8.0.tgz#cffebed56ae99c45eba901c378a6447b06be58b8" + integrity sha512-oqAnbA7c+pgOhW2OhGvxm0t1BULX5peQI/rLsNDpGM78EebV3C9IGbX5HNZabuZ6UQrYveCLjKo8Iy/lLlBkkg== dependencies: - "@typescript-eslint/types" "6.7.3" + "@typescript-eslint/types" "6.8.0" eslint-visitor-keys "^3.4.1" "@webassemblyjs/ast@1.11.6", "@webassemblyjs/ast@^1.11.5": @@ -3962,29 +3954,29 @@ babel-plugin-named-asset-import@^0.3.8: resolved "https://registry.yarnpkg.com/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.8.tgz#6b7fa43c59229685368683c28bc9734f24524cc2" integrity sha512-WXiAc++qo7XcJ1ZnTYGtLxmBCVbddAml3CEXgWaBzNzLNoxtQ8AiGEFDMOhot9XjTCQbvP5E77Fj9Gk924f00Q== -babel-plugin-polyfill-corejs2@^0.4.5: - version "0.4.5" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.5.tgz#8097b4cb4af5b64a1d11332b6fb72ef5e64a054c" - integrity sha512-19hwUH5FKl49JEsvyTcoHakh6BE0wgXLLptIyKZ3PijHc/Ci521wygORCUCCred+E/twuqRyAkE02BAWPmsHOg== +babel-plugin-polyfill-corejs2@^0.4.6: + version "0.4.6" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.6.tgz#b2df0251d8e99f229a8e60fc4efa9a68b41c8313" + integrity sha512-jhHiWVZIlnPbEUKSSNb9YoWcQGdlTLq7z1GHL4AjFxaoOUMuuEVJ+Y4pAaQUGOGk93YsVCKPbqbfw3m0SM6H8Q== dependencies: "@babel/compat-data" "^7.22.6" - "@babel/helper-define-polyfill-provider" "^0.4.2" + "@babel/helper-define-polyfill-provider" "^0.4.3" semver "^6.3.1" -babel-plugin-polyfill-corejs3@^0.8.3: - version "0.8.4" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.4.tgz#1fac2b1dcef6274e72b3c72977ed8325cb330591" - integrity sha512-9l//BZZsPR+5XjyJMPtZSK4jv0BsTO1zDac2GC6ygx9WLGlcsnRd1Co0B2zT5fF5Ic6BZy+9m3HNZ3QcOeDKfg== +babel-plugin-polyfill-corejs3@^0.8.5: + version "0.8.5" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.5.tgz#a75fa1b0c3fc5bd6837f9ec465c0f48031b8cab1" + integrity sha512-Q6CdATeAvbScWPNLB8lzSO7fgUVBkQt6zLgNlfyeCr/EQaEQR+bWiBYYPYAFyE528BMjRhL+1QBMOI4jc/c5TA== dependencies: - "@babel/helper-define-polyfill-provider" "^0.4.2" + "@babel/helper-define-polyfill-provider" "^0.4.3" core-js-compat "^3.32.2" -babel-plugin-polyfill-regenerator@^0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.2.tgz#80d0f3e1098c080c8b5a65f41e9427af692dc326" - integrity sha512-tAlOptU0Xj34V1Y2PNTL4Y0FOJMDB6bZmoW39FeCQIhigGLkqu3Fj6uiXpxIf6Ij274ENdYx64y6Au+ZKlb1IA== +babel-plugin-polyfill-regenerator@^0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.3.tgz#d4c49e4b44614607c13fb769bcd85c72bb26a4a5" + integrity sha512-8sHeDOmXC8csczMrYEOf0UTNa4yE2SxV5JGeT/LP1n0OYVDUUFPxG9vdk2AlDlIit4t+Kf0xCtpgXPBwnn/9pw== dependencies: - "@babel/helper-define-polyfill-provider" "^0.4.2" + "@babel/helper-define-polyfill-provider" "^0.4.3" babel-plugin-transform-react-remove-prop-types@^0.4.24: version "0.4.24" @@ -4285,8 +4277,8 @@ browserslist@^4.0.0, browserslist@^4.14.5, browserslist@^4.18.1, browserslist@^4 resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.22.0.tgz#6adc8116589ccea8a99d0df79c5de2436199abdb" integrity sha512-v+Jcv64L2LbfTC6OnRcaxtqJNJuQAVhZKSJfR/6hn7lhnChUXl4amwVviqN1k411BB+3rRoKMitELRn1CojeRA== dependencies: - caniuse-lite "^1.0.30001539" - electron-to-chromium "^1.4.530" + caniuse-lite "^1.0.30001541" + electron-to-chromium "^1.4.535" node-releases "^2.0.13" update-browserslist-db "^1.0.13" @@ -4451,10 +4443,10 @@ caniuse-api@^3.0.0: lodash.memoize "^4.1.2" lodash.uniq "^4.5.0" -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001538, caniuse-lite@^1.0.30001539: - version "1.0.30001541" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001541.tgz#b1aef0fadd87fb72db4dcb55d220eae17b81cdb1" - integrity sha512-bLOsqxDgTqUBkzxbNlSBt8annkDpQB9NdzdTbO2ooJ+eC/IQcvDspDc058g84ejCelF7vHUx57KIOjEecOHXaw== +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001538, caniuse-lite@^1.0.30001541: + version "1.0.30001549" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001549.tgz#7d1a3dce7ea78c06ed72c32c2743ea364b3615aa" + integrity sha512-qRp48dPYSCYaP+KurZLhDYdVE+yEyht/3NlmcJgVQ2VMGt6JL36ndQ/7rgspdZsJuxDPFIo/OzBT2+GmIJ53BA== capture-exit@^2.0.0: version "2.0.0" @@ -4513,7 +4505,7 @@ check-types@^11.2.3: resolved "https://registry.yarnpkg.com/check-types/-/check-types-11.2.3.tgz#1ffdf68faae4e941fce252840b1787b8edc93b71" integrity sha512-+67P1GkJRaxQD6PKK0Et9DhwQB+vGg3PM5+aavopCpZT1lj9jeqfvpgTLAWErNj8qApkkmXlu/Ug74kmhagkXg== -chokidar@^3.4.0, chokidar@^3.4.2, chokidar@^3.5.3: +chokidar@^3.4.2, chokidar@^3.5.3: version "3.5.3" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== @@ -4539,9 +4531,9 @@ ci-info@^2.0.0: integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== ci-info@^3.2.0: - version "3.8.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.8.0.tgz#81408265a5380c929f0bc665d62256628ce9ef91" - integrity sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw== + version "3.9.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" + integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" @@ -4610,6 +4602,11 @@ clone-deep@^4.0.1: kind-of "^6.0.2" shallow-clone "^3.0.0" +clsx@^1.0.4: + version "1.2.1" + resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12" + integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg== + co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" @@ -4709,7 +4706,7 @@ commander@^2.20.0: resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== -commander@^4.0.0, commander@^4.0.1: +commander@^4.0.0: version "4.1.1" resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== @@ -4817,21 +4814,21 @@ copy-descriptor@^0.1.0: integrity sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw== core-js-compat@^3.31.0, core-js-compat@^3.32.2: - version "3.32.2" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.32.2.tgz#8047d1a8b3ac4e639f0d4f66d4431aa3b16e004c" - integrity sha512-+GjlguTDINOijtVRUxrQOv3kfu9rl+qPNdX2LTbJ/ZyVTuxK+ksVSAGX1nHstu4hrv1En/uPTtWgq2gI5wt4AQ== + version "3.33.0" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.33.0.tgz#24aa230b228406450b2277b7c8bfebae932df966" + integrity sha512-0w4LcLXsVEuNkIqwjjf9rjCoPhK8uqA4tMRh4Ge26vfLtUutshn+aRJU21I9LCJlh2QQHfisNToLjw1XEJLTWw== dependencies: - browserslist "^4.21.10" + browserslist "^4.22.1" core-js-pure@^3.23.3: - version "3.32.2" - resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.32.2.tgz#b7dbdac528625cf87eb0523b532eb61551b9a6d1" - integrity sha512-Y2rxThOuNywTjnX/PgA5vWM6CZ9QB9sz9oGeCixV8MqXZO70z/5SHzf9EeBrEBK0PN36DnEBBu9O/aGWzKuMZQ== + version "3.33.0" + resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.33.0.tgz#938a28754b4d82017a7a8cbd2727b1abecc63591" + integrity sha512-FKSIDtJnds/YFIEaZ4HszRX7hkxGpNKM7FC9aJ9WLJbSd3lD4vOltFuVIBLR8asSx9frkTSqL0dw90SKQxgKrg== core-js@^3.19.2: - version "3.32.2" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.32.2.tgz#172fb5949ef468f93b4be7841af6ab1f21992db7" - integrity sha512-pxXSw1mYZPDGvTQqEc5vgIb83jGQKFGYWY76z4a7weZXUolw3G+OvpZqSRcfYOoOVUQJYEPsWeQK8pKEnUtWxQ== + version "3.33.0" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.33.0.tgz#70366dbf737134761edb017990cf5ce6c6369c40" + integrity sha512-HoZr92+ZjFEKar5HS6MC776gYslNOKHt75mEBKWKnPeFDpZ6nH5OeF3S6HFT1mUAUZKrzkez05VboaX8myjSuw== core-util-is@~1.0.0: version "1.0.3" @@ -5090,9 +5087,9 @@ css.escape@^1.5.1: integrity sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg== cssdb@^7.1.0: - version "7.7.2" - resolved "https://registry.yarnpkg.com/cssdb/-/cssdb-7.7.2.tgz#fbebd90edfc6af129fda4fd986f9dd604a209094" - integrity sha512-pQPYP7/kch4QlkTcLuUNiNL2v/E+O+VIdotT+ug62/+2B2/jkzs5fMM6RHCzGCZ9C82pODEMSIzRRUzJOrl78g== + version "7.8.0" + resolved "https://registry.yarnpkg.com/cssdb/-/cssdb-7.8.0.tgz#ac41fa025371b74eb2ccfe3d41f5c4dbd444fbe3" + integrity sha512-SkeezZOQr5AHt9MgJgSFNyiuJwg1p8AwoVln6JwaQJsyxduRW9QJ+HP/gAQzbsz8SIqINtYvpJKjxTRI67zxLg== cssesc@^3.0.0: version "3.0.0" @@ -5347,9 +5344,9 @@ default-gateway@^6.0.3: execa "^5.0.0" define-data-property@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.0.tgz#0db13540704e1d8d479a0656cf781267531b9451" - integrity sha512-UzGwzcjyv3OtAvolTj1GoyNYzfFR+iqbGjcnBEENZVCpM4/Ng1yhGNvS3lR/xDS74Tb2wGG9WzNSNIOS9UVb2g== + version "1.1.1" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.1.tgz#c35f7cd0ab09883480d12ac5cb213715587800b3" + integrity sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ== dependencies: get-intrinsic "^1.2.1" gopd "^1.0.1" @@ -5551,7 +5548,7 @@ dom-converter@^0.2.0: dependencies: utila "~0.4" -dom-helpers@^5.0.1: +dom-helpers@^5.0.1, dom-helpers@^5.1.3: version "5.2.1" resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.1.tgz#d9400536b2bf8225ad98fe052e029451ac40e902" integrity sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA== @@ -5659,10 +5656,10 @@ ejs@^3.1.6: dependencies: jake "^10.8.5" -electron-to-chromium@^1.4.530: - version "1.4.532" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.532.tgz#44454731e26f2c8c14e88cca0d073f0761784f5e" - integrity sha512-piIR0QFdIGKmOJTSNg5AwxZRNWQSXlRYycqDB9Srstx4lip8KpcmRxVP6zuFWExWziHYZpJ0acX7TxqX95KBpg== +electron-to-chromium@^1.4.535: + version "1.4.557" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.557.tgz#f3941b569c82b7bb909411855c6ff9bfe1507829" + integrity sha512-6x0zsxyMXpnMJnHrondrD3SuAeKcwij9S+83j2qHAQPXbGTDDfgImzzwgGlzrIcXbHQ42tkG4qA6U860cImNhw== elliptic@6.5.4, elliptic@^6.5.3, elliptic@^6.5.4: version "6.5.4" @@ -6122,14 +6119,14 @@ eslint-webpack-plugin@^3.1.1: schema-utils "^4.0.0" eslint@^8.3.0, eslint@^8.9.0: - version "8.50.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.50.0.tgz#2ae6015fee0240fcd3f83e1e25df0287f487d6b2" - integrity sha512-FOnOGSuFuFLv/Sa+FDVRZl4GGVAAFFi8LecRsI5a1tMO5HIE8nCm4ivAlzt4dT3ol/PaaGC0rJEEXQmHJBGoOg== + version "8.51.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.51.0.tgz#4a82dae60d209ac89a5cff1604fea978ba4950f3" + integrity sha512-2WuxRZBrlwnXi+/vFSJyjMqrNjtJqiasMzehF0shoLaW7DzS3/9Yvrmq5JiT66+pNjiX4UBnLDiKHcWAr/OInA== dependencies: "@eslint-community/eslint-utils" "^4.2.0" "@eslint-community/regexpp" "^4.6.1" "@eslint/eslintrc" "^2.1.2" - "@eslint/js" "8.50.0" + "@eslint/js" "8.51.0" "@humanwhocodes/config-array" "^0.11.11" "@humanwhocodes/module-importer" "^1.0.1" "@nodelib/fs.walk" "^1.2.8" @@ -6605,15 +6602,20 @@ find-up@^5.0.0: path-exists "^4.0.0" flat-cache@^3.0.4: - version "3.1.0" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.1.0.tgz#0e54ab4a1a60fe87e2946b6b00657f1c99e1af3f" - integrity sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew== + version "3.1.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.1.1.tgz#a02a15fdec25a8f844ff7cc658f03dd99eb4609b" + integrity sha512-/qM2b3LUIaIgviBQovTLvijfyOQXPtSRnRK26ksj2J7rzPIecePUIpJsZ4T02Qg+xiAEKIs5K8dsHEd+VaKa/Q== dependencies: - flatted "^3.2.7" + flatted "^3.2.9" keyv "^4.5.3" rimraf "^3.0.2" -flatted@^3.2.7: +flat@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" + integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== + +flatted@^3.2.9: version "3.2.9" resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.9.tgz#7eb4c67ca1ba34232ca9d2d93e9886e611ad7daf" integrity sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ== @@ -6669,9 +6671,9 @@ forwarded@0.2.0: integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== fraction.js@^4.3.6: - version "4.3.6" - resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.3.6.tgz#e9e3acec6c9a28cf7bc36cbe35eea4ceb2c5c92d" - integrity sha512-n2aZ9tNfYDwaHhvFTkhFErqOMIb8uyzSQ+vGJBjZyanAKZVbGUQ1sngfk9FdkBw7G26O7AgNjLcecLffD1c7eg== + version "4.3.7" + resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.3.7.tgz#06ca0085157e42fda7f9e726e79fefc4068840f7" + integrity sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew== fragment-cache@^0.2.1: version "0.2.1" @@ -6709,11 +6711,6 @@ fs-monkey@^1.0.4: resolved "https://registry.yarnpkg.com/fs-monkey/-/fs-monkey-1.0.5.tgz#fe450175f0db0d7ea758102e1d84096acb925788" integrity sha512-8uMbBjrhzW76TYgEV27Y5E//W2f/lTFmx78P2w19FZSxarhI/798APGQyuGCwmkNxgwGRhrLfvWyLBvNtuOmew== -fs-readdir-recursive@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz#e32fc030a2ccee44a6b5371308da54be0b397d27" - integrity sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA== - fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -6725,9 +6722,9 @@ fsevents@^2.1.2, fsevents@^2.3.2, fsevents@~2.3.2: integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== function.prototype.name@^1.1.5, function.prototype.name@^1.1.6: version "1.1.6" @@ -6830,7 +6827,7 @@ glob@7.1.6: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@^7.2.0: +glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== @@ -6864,9 +6861,9 @@ globals@^11.1.0: integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== globals@^13.19.0: - version "13.22.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.22.0.tgz#0c9fcb9c48a2494fbb5edbfee644285543eba9d8" - integrity sha512-H1Ddc/PbZHTDVJSnj8kWptIRSD6AM3pK+mKytuIVF4uoBV7rshFlhhvA58ceJ5wp3Er58w6zj7bykMpYXt3ETw== + version "13.23.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.23.0.tgz#ef31673c926a0976e1f61dab4dca57e0c0a8af02" + integrity sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA== dependencies: type-fest "^0.20.2" @@ -6994,11 +6991,9 @@ has-values@^1.0.0: kind-of "^4.0.0" has@^1.0.0, has@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== - dependencies: - function-bind "^1.1.1" + version "1.0.4" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.4.tgz#2eb2860e000011dae4f1406a86fe80e530fb2ec6" + integrity sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ== hash-base@^3.0.0: version "3.1.0" @@ -7467,7 +7462,7 @@ is-color-stop@^1.0.0: rgb-regex "^1.0.1" rgba-regex "^1.0.0" -is-core-module@^2.13.0, is-core-module@^2.9.0: +is-core-module@^2.13.0: version "2.13.0" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.0.tgz#bb52aa6e2cbd49a30c2ba68c42bf3435ba6072db" integrity sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ== @@ -8887,9 +8882,9 @@ keccak@^3.0.0: readable-stream "^3.6.0" keyv@^4.5.3: - version "4.5.3" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.3.tgz#00873d2b046df737963157bd04f294ca818c9c25" - integrity sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug== + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== dependencies: json-buffer "3.0.1" @@ -8948,12 +8943,12 @@ last-call-webpack-plugin@^3.0.0: webpack-sources "^1.1.0" launch-editor@^2.6.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/launch-editor/-/launch-editor-2.6.0.tgz#4c0c1a6ac126c572bd9ff9a30da1d2cae66defd7" - integrity sha512-JpDCcQnyAAzZZaZ7vEiSqL690w7dAEyLao+KC96zBplnYbJS7TYNjvM3M7y3dGz+v7aIsJk3hllWuc0kWAjyRQ== + version "2.6.1" + resolved "https://registry.yarnpkg.com/launch-editor/-/launch-editor-2.6.1.tgz#f259c9ef95cbc9425620bbbd14b468fcdb4ffe3c" + integrity sha512-eB/uXmFVpY4zezmGp5XtU21kwo7GBbKB+EQ+UZeWtGb9yAM5xt/Evk+lYH3eRNAtId+ej4u7TYPFZ07w4s7rRw== dependencies: picocolors "^1.0.0" - shell-quote "^1.7.3" + shell-quote "^1.8.1" leven@^3.1.0: version "3.1.0" @@ -9131,14 +9126,6 @@ magic-string@^0.25.0, magic-string@^0.25.7: dependencies: sourcemap-codec "^1.4.8" -make-dir@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" - integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== - dependencies: - pify "^4.0.1" - semver "^5.6.0" - make-dir@^3.0.2, make-dir@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" @@ -9593,9 +9580,9 @@ object-hash@^3.0.0: integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw== object-inspect@^1.12.3, object-inspect@^1.9.0: - version "1.12.3" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" - integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== + version "1.13.0" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.0.tgz#42695d3879e1cd5bda6df5062164d80c996e23e2" + integrity sha512-HQ4J+ic8hKrgIt3mqk6cVOVrW2ozL4KdvHlqpBv9vDYWx9ysAgENAdvy4FoGF+KFdhR7nQTNm5J0ctAeOwn+3g== object-is@^1.1.5: version "1.1.5" @@ -9987,11 +9974,6 @@ pify@^3.0.0: resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" integrity sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg== -pify@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" - integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== - pirates@^4.0.1, pirates@^4.0.4: version "4.0.6" resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9" @@ -10833,10 +10815,10 @@ postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.27, postcss@^7.0.35: picocolors "^0.2.1" source-map "^0.6.1" -postcss@^8.1.0, postcss@^8.3.5, postcss@^8.4.21, postcss@^8.4.23, postcss@^8.4.4: - version "8.4.30" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.30.tgz#0e0648d551a606ef2192a26da4cabafcc09c1aa7" - integrity sha512-7ZEao1g4kd68l97aWG/etQKPKq07us0ieSZ2TnFDk11i0ZfDW2AwKHYU8qv4MZKqN2fdBfg+7q0ES06UA73C1g== +postcss@^8.1.0, postcss@^8.3.5, postcss@^8.4.21, postcss@^8.4.23, postcss@^8.4.31, postcss@^8.4.4: + version "8.4.31" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.31.tgz#92b451050a9f914da6755af352bdc0192508656d" + integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ== dependencies: nanoid "^3.3.6" picocolors "^1.0.0" @@ -10943,9 +10925,9 @@ prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: react-is "^16.13.1" property-expr@^2.0.4: - version "2.0.5" - resolved "https://registry.yarnpkg.com/property-expr/-/property-expr-2.0.5.tgz#278bdb15308ae16af3e3b9640024524f4dc02cb4" - integrity sha512-IJUkICM5dP5znhCckHSv30Q4b5/JA5enCtkRHYaOVOAocnH/1BQEYTC5NMfT3AVl/iXKdr3aqQbQn9DxyWknwA== + version "2.0.6" + resolved "https://registry.yarnpkg.com/property-expr/-/property-expr-2.0.6.tgz#f77bc00d5928a6c748414ad12882e83f24aec1e8" + integrity sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA== proxy-addr@~2.0.7: version "2.0.7" @@ -11160,9 +11142,9 @@ react-error-overlay@^6.0.11: integrity sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg== react-hook-form@^7.33.1: - version "7.46.2" - resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.46.2.tgz#051e3cb2a73f3e86de739f2198c6042902158c43" - integrity sha512-x1DWmHQchV7x2Rq9l99M/cQHC8JGchAnw9Z0uTz5KrPa0bTl/Inm1NR7ceOARfIrkNuQNAhuSuZPYa6k7QYn3Q== + version "7.47.0" + resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.47.0.tgz#a42f07266bd297ddf1f914f08f4b5f9783262f31" + integrity sha512-F/TroLjTICipmHeFlMrLtNLceO2xr1jU3CyiNla5zdwsGUGu2UOxxR4UyJgLlhMwLW/Wzp4cpJ7CPfgJIeKdSg== react-hotkeys-hook@^4.3.8: version "4.4.1" @@ -11199,7 +11181,7 @@ react-json-view-lite@^0.9.5: resolved "https://registry.yarnpkg.com/react-json-view-lite/-/react-json-view-lite-0.9.8.tgz#d3d91bc16d62ef774a7b5c4ad95ccaaa623362d6" integrity sha512-4D0UgQ5SjanNi2KzgEsEKOb9kj0L9HQz/3IshwIZN5reZsSU62t6sp8c+vskV42lXjGQCi7qGfoXIpNRsON7LA== -react-lifecycles-compat@^3.0.0: +react-lifecycles-compat@^3.0.0, 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== @@ -11334,6 +11316,18 @@ react-virtualized-auto-sizer@^1.0.20: resolved "https://registry.yarnpkg.com/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.20.tgz#d9a907253a7c221c52fa57dc775a6ef40c182645" integrity sha512-OdIyHwj4S4wyhbKHOKM1wLSj/UDXm839Z3Cvfg2a9j+He6yDa6i5p0qQvEiCnyQlGO/HyfSnigQwuxvYalaAXA== +react-virtualized@^9.22.5: + version "9.22.5" + resolved "https://registry.yarnpkg.com/react-virtualized/-/react-virtualized-9.22.5.tgz#bfb96fed519de378b50d8c0064b92994b3b91620" + integrity sha512-YqQMRzlVANBv1L/7r63OHa2b0ZsAaDp1UhVNEdUaXI8A5u6hTpA5NYtUueLH2rFuY/27mTGIBl7ZhqFKzw18YQ== + dependencies: + "@babel/runtime" "^7.7.2" + clsx "^1.0.4" + dom-helpers "^5.1.3" + loose-envify "^1.4.0" + prop-types "^15.7.2" + react-lifecycles-compat "^3.0.4" + react-window@^1.8.6: version "1.8.9" resolved "https://registry.yarnpkg.com/react-window/-/react-window-1.8.9.tgz#24bc346be73d0468cdf91998aac94e32bc7fa6a8" @@ -11624,20 +11618,20 @@ resolve.exports@^1.1.0: integrity sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ== resolve@^1.1.7, resolve@^1.10.0, resolve@^1.12.0, resolve@^1.14.2, resolve@^1.18.1, resolve@^1.19.0, resolve@^1.20.0, resolve@^1.22.2, resolve@^1.22.4: - version "1.22.6" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.6.tgz#dd209739eca3aef739c626fea1b4f3c506195362" - integrity sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw== + version "1.22.8" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" + integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== dependencies: is-core-module "^2.13.0" path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" resolve@^2.0.0-next.4: - version "2.0.0-next.4" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.4.tgz#3d37a113d6429f496ec4752d2a2e58efb1fd4660" - integrity sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ== + version "2.0.0-next.5" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.5.tgz#6b0ec3107e671e52b68cd068ef327173b90dc03c" + integrity sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA== dependencies: - is-core-module "^2.9.0" + is-core-module "^2.13.0" path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" @@ -11879,7 +11873,7 @@ selfsigned@^2.1.1: dependencies: node-forge "^1" -"semver@2 || 3 || 4 || 5", semver@^5.5.0, semver@^5.6.0: +"semver@2 || 3 || 4 || 5", semver@^5.5.0: version "5.7.2" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== @@ -12035,7 +12029,7 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -shell-quote@^1.6.1, shell-quote@^1.7.3: +shell-quote@^1.6.1, shell-quote@^1.7.3, shell-quote@^1.8.1: version "1.8.1" resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.1.tgz#6dbf4db75515ad5bac63b4f1894c3a154c766680" integrity sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA== @@ -12066,11 +12060,6 @@ sisteransi@^1.0.5: resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== -slash@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" - integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== - slash@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" @@ -12212,9 +12201,9 @@ spdx-expression-parse@^3.0.0: spdx-license-ids "^3.0.0" spdx-license-ids@^3.0.0: - version "3.0.15" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.15.tgz#142460aabaca062bc7cd4cc87b7d50725ed6a4ba" - integrity sha512-lpT8hSQp9jAKp9mhtBU4Xjon8LPGBvLIuBiSVhMEtmLecTh2mO0tlqrAMp47tBXzMr13NJMQ2lf7RpQGLJ3HsQ== + version "3.0.16" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.16.tgz#a14f64e0954f6e25cc6587bd4f392522db0d998f" + integrity sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw== spdy-transport@^3.0.0: version "3.0.0" @@ -12487,26 +12476,16 @@ style-loader@^3.3.1: integrity sha512-53BiGLXAcll9maCYtZi2RCQZKa8NQQai5C4horqKyRmHj9H7QmcUyucrH+4KW/gBQbXM2AsB0axoEcFZPlfPcw== styled-components@^6.0.8: - version "6.0.8" - resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-6.0.8.tgz#90617ad60de39772e03a81c8f3b8e66c12f51c44" - integrity sha512-AwI02MTWZwqjzfXgR5QcbmcSn5xVjY4N2TLjSuYnmuBGF3y7GicHz3ysbpUq2EMJP5M8/Nc22vcmF3V3WNZDFA== - dependencies: - "@babel/cli" "^7.21.0" - "@babel/core" "^7.21.0" - "@babel/helper-module-imports" "^7.18.6" - "@babel/plugin-external-helpers" "^7.18.6" - "@babel/plugin-proposal-class-properties" "^7.18.6" - "@babel/plugin-proposal-object-rest-spread" "^7.20.7" - "@babel/preset-env" "^7.20.2" - "@babel/preset-react" "^7.18.6" - "@babel/preset-typescript" "^7.21.0" - "@babel/traverse" "^7.21.2" + version "6.1.0" + resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-6.1.0.tgz#228e3ab9c1ee1daa4b0a06aae30df0ed14fda274" + integrity sha512-VWNfYYBuXzuLS/QYEeoPgMErP26WL+dX9//rEh80B2mmlS1yRxRxuL5eax4m6ybYEUoHWlTy2XOU32767mlMkg== + dependencies: "@emotion/is-prop-valid" "^1.2.1" "@emotion/unitless" "^0.8.0" "@types/stylis" "^4.0.2" css-to-react-native "^3.2.0" csstype "^3.1.2" - postcss "^8.4.23" + postcss "^8.4.31" shallowequal "^1.1.0" stylis "^4.3.0" tslib "^2.5.0" @@ -12695,9 +12674,9 @@ terser-webpack-plugin@^5.2.5, terser-webpack-plugin@^5.3.7: terser "^5.16.8" terser@^5.0.0, terser@^5.10.0, terser@^5.16.8: - version "5.20.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.20.0.tgz#ea42aea62578703e33def47d5c5b93c49772423e" - integrity sha512-e56ETryaQDyebBwJIWYB2TT6f2EZ0fL0sW/JRXNMN26zZdKi2u/E/5my5lG6jNxym6qsrVXfFRmOdV42zlAgLQ== + version "5.22.0" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.22.0.tgz#4f18103f84c5c9437aafb7a14918273310a8a49d" + integrity sha512-hHZVLgRA2z4NWcN6aS5rQDc+7Dcy58HOf2zbYwmFcQ+ua3h6eEFf5lIDKTzbWwlazPyOZsFQO8V80/IjVNExEw== dependencies: "@jridgewell/source-map" "^0.3.3" acorn "^8.8.2" @@ -13031,6 +13010,11 @@ underscore@1.12.1: resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.12.1.tgz#7bb8cc9b3d397e201cf8553336d262544ead829e" integrity sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw== +undici-types@~5.25.1: + version "5.25.3" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.25.3.tgz#e044115914c85f0bcbb229f346ab739f064998c3" + integrity sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA== + unicode-canonical-property-names-ecmascript@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc" @@ -13377,11 +13361,12 @@ webpack-manifest-plugin@^4.0.2: webpack-sources "^2.2.0" webpack-merge@^5.7.3: - version "5.9.0" - resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.9.0.tgz#dc160a1c4cf512ceca515cc231669e9ddb133826" - integrity sha512-6NbRQw4+Sy50vYNTw7EyOn41OZItPiXB8GNv3INSoe3PSFaHJEz3SHTrYVaRm2LilNGnFUzh0FAwqPEmU/CwDg== + version "5.10.0" + resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.10.0.tgz#a3ad5d773241e9c682803abf628d4cd62b8a4177" + integrity sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA== dependencies: clone-deep "^4.0.1" + flat "^5.0.2" wildcard "^2.0.0" webpack-sources@^1.1.0, webpack-sources@^1.4.3: @@ -13406,9 +13391,9 @@ webpack-sources@^3.2.3: integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== webpack@^5.64.4: - version "5.88.2" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.88.2.tgz#f62b4b842f1c6ff580f3fcb2ed4f0b579f4c210e" - integrity sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ== + version "5.89.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.89.0.tgz#56b8bf9a34356e93a6625770006490bf3a7f32dc" + integrity sha512-qyfIC10pOr70V+jkmud8tMfajraGCZMBWJtrmuBymQKCrLTRejBI8STDp1MCyZu/QTdZSeacCQYpYNQVOzX5kw== dependencies: "@types/eslint-scope" "^3.7.3" "@types/estree" "^1.0.0" @@ -13821,9 +13806,9 @@ yaml@^1.10.0, yaml@^1.10.2, yaml@^1.7.2: integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== yaml@^2.1.1: - version "2.3.2" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.2.tgz#f522db4313c671a0ca963a75670f1c12ea909144" - integrity sha512-N/lyzTPaJasoDmfV7YTrYCI0G/3ivm/9wdG0aHuheKowWQwGTsK0Eoiw6utmzAnI6pkJa0DUVygvp3spqqEKXg== + version "2.3.3" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.3.tgz#01f6d18ef036446340007db8e016810e5d64aad9" + integrity sha512-zw0VAJxgeZ6+++/su5AFoqBbZbrEakwu+X0M5HmcwUiBL7AzcuPKjj5we4xfQLp78LkEMpD0cOnUhmgOVy3KdQ== yargs-parser@^18.1.2: version "18.1.3" diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 000000000..fb57ccd13 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,4 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + +