Merge branch 'main' of https://github.com/hyperlane-xyz/hyperlane-monorepo into ltyu/zerion-configs
commit
2cbc553ded
@ -1,5 +0,0 @@ |
||||
--- |
||||
'@hyperlane-xyz/sdk': minor |
||||
--- |
||||
|
||||
Enroll new validators for alephzeroevmmainnet, chilizmainnet, flowmainnet, immutablezkevmmainnet, metal, polynomialfi, rarichain, rootstockmainnet, superpositionmainnet, flame, prom, inevm. |
@ -1,5 +0,0 @@ |
||||
--- |
||||
'@hyperlane-xyz/sdk': minor |
||||
--- |
||||
|
||||
Added helpers to Token and token adapters to get bridged supply of tokens" |
@ -1,7 +0,0 @@ |
||||
--- |
||||
'@hyperlane-xyz/infra': minor |
||||
'@hyperlane-xyz/cli': minor |
||||
'@hyperlane-xyz/sdk': minor |
||||
--- |
||||
|
||||
Implements persistent relayer for use in CLI |
@ -1,6 +0,0 @@ |
||||
--- |
||||
'@hyperlane-xyz/widgets': minor |
||||
--- |
||||
|
||||
Props and style update: IconButton and Tooltip |
||||
New Icons: XCircleIcon and SwapIcon |
@ -1 +1 @@ |
||||
3e366eae1d49da4270695b157d7af00bb761156a |
||||
82013508db45dcd55b44d2721414d26817686c8f |
||||
|
@ -0,0 +1,6 @@ |
||||
pub use storage::HyperlaneDbStore; |
||||
|
||||
mod deliveries; |
||||
mod dispatches; |
||||
mod payments; |
||||
mod storage; |
@ -0,0 +1,43 @@ |
||||
use std::collections::HashMap; |
||||
|
||||
use async_trait::async_trait; |
||||
use eyre::Result; |
||||
|
||||
use hyperlane_core::{Delivery, HyperlaneLogStore, Indexed, LogMeta, H512}; |
||||
|
||||
use crate::db::StorableDelivery; |
||||
use crate::store::storage::{HyperlaneDbStore, TxnWithId}; |
||||
|
||||
#[async_trait] |
||||
impl HyperlaneLogStore<Delivery> for HyperlaneDbStore { |
||||
/// Store delivered message ids from the destination mailbox into the database.
|
||||
/// We store only delivered messages ids from blocks and transaction which we could successfully
|
||||
/// insert into database.
|
||||
async fn store_logs(&self, deliveries: &[(Indexed<Delivery>, LogMeta)]) -> Result<u32> { |
||||
if deliveries.is_empty() { |
||||
return Ok(0); |
||||
} |
||||
let txns: HashMap<H512, TxnWithId> = self |
||||
.ensure_blocks_and_txns(deliveries.iter().map(|r| &r.1)) |
||||
.await? |
||||
.map(|t| (t.hash, t)) |
||||
.collect(); |
||||
let storable = deliveries |
||||
.iter() |
||||
.filter_map(|(message_id, meta)| { |
||||
txns.get(&meta.transaction_id) |
||||
.map(|txn| (*message_id.inner(), meta, txn.id)) |
||||
}) |
||||
.map(|(message_id, meta, txn_id)| StorableDelivery { |
||||
message_id, |
||||
meta, |
||||
txn_id, |
||||
}); |
||||
|
||||
let stored = self |
||||
.db |
||||
.store_deliveries(self.domain.id(), self.mailbox_address, storable) |
||||
.await?; |
||||
Ok(stored as u32) |
||||
} |
||||
} |
@ -0,0 +1,64 @@ |
||||
use std::collections::HashMap; |
||||
|
||||
use async_trait::async_trait; |
||||
use eyre::Result; |
||||
|
||||
use hyperlane_core::{ |
||||
unwrap_or_none_result, HyperlaneLogStore, HyperlaneMessage, |
||||
HyperlaneSequenceAwareIndexerStoreReader, Indexed, LogMeta, H512, |
||||
}; |
||||
|
||||
use crate::db::StorableMessage; |
||||
use crate::store::storage::{HyperlaneDbStore, TxnWithId}; |
||||
|
||||
#[async_trait] |
||||
impl HyperlaneLogStore<HyperlaneMessage> for HyperlaneDbStore { |
||||
/// Store dispatched messages from the origin mailbox into the database.
|
||||
/// We store only messages from blocks and transaction which we could successfully insert
|
||||
/// into database.
|
||||
async fn store_logs(&self, messages: &[(Indexed<HyperlaneMessage>, LogMeta)]) -> Result<u32> { |
||||
if messages.is_empty() { |
||||
return Ok(0); |
||||
} |
||||
let txns: HashMap<H512, TxnWithId> = self |
||||
.ensure_blocks_and_txns(messages.iter().map(|r| &r.1)) |
||||
.await? |
||||
.map(|t| (t.hash, t)) |
||||
.collect(); |
||||
let storable = messages |
||||
.iter() |
||||
.filter_map(|(message, meta)| { |
||||
txns.get(&meta.transaction_id) |
||||
.map(|t| (message.inner().clone(), meta, t.id)) |
||||
}) |
||||
.map(|(msg, meta, txn_id)| StorableMessage { msg, meta, txn_id }); |
||||
let stored = self |
||||
.db |
||||
.store_dispatched_messages(self.domain.id(), &self.mailbox_address, storable) |
||||
.await?; |
||||
Ok(stored as u32) |
||||
} |
||||
} |
||||
|
||||
#[async_trait] |
||||
impl HyperlaneSequenceAwareIndexerStoreReader<HyperlaneMessage> for HyperlaneDbStore { |
||||
/// Gets a message by its nonce.
|
||||
async fn retrieve_by_sequence(&self, sequence: u32) -> Result<Option<HyperlaneMessage>> { |
||||
let message = self |
||||
.db |
||||
.retrieve_message_by_nonce(self.domain.id(), &self.mailbox_address, sequence) |
||||
.await?; |
||||
Ok(message) |
||||
} |
||||
|
||||
/// Gets the block number at which the log occurred.
|
||||
async fn retrieve_log_block_number_by_sequence(&self, sequence: u32) -> Result<Option<u64>> { |
||||
let tx_id = unwrap_or_none_result!( |
||||
self.db |
||||
.retrieve_dispatched_tx_id(self.domain.id(), &self.mailbox_address, sequence) |
||||
.await? |
||||
); |
||||
let block_id = unwrap_or_none_result!(self.db.retrieve_block_id(tx_id).await?); |
||||
Ok(self.db.retrieve_block_number(block_id).await?) |
||||
} |
||||
} |
@ -0,0 +1,43 @@ |
||||
use std::collections::HashMap; |
||||
|
||||
use async_trait::async_trait; |
||||
use eyre::Result; |
||||
|
||||
use hyperlane_core::{HyperlaneLogStore, Indexed, InterchainGasPayment, LogMeta, H512}; |
||||
|
||||
use crate::db::StorablePayment; |
||||
use crate::store::storage::HyperlaneDbStore; |
||||
|
||||
#[async_trait] |
||||
impl HyperlaneLogStore<InterchainGasPayment> for HyperlaneDbStore { |
||||
/// Store interchain gas payments into the database.
|
||||
/// We store only interchain gas payments from blocks and transaction which we could
|
||||
/// successfully insert into database.
|
||||
async fn store_logs( |
||||
&self, |
||||
payments: &[(Indexed<InterchainGasPayment>, LogMeta)], |
||||
) -> Result<u32> { |
||||
if payments.is_empty() { |
||||
return Ok(0); |
||||
} |
||||
let txns: HashMap<H512, crate::store::storage::TxnWithId> = self |
||||
.ensure_blocks_and_txns(payments.iter().map(|r| &r.1)) |
||||
.await? |
||||
.map(|t| (t.hash, t)) |
||||
.collect(); |
||||
let storable = payments |
||||
.iter() |
||||
.filter_map(|(payment, meta)| { |
||||
txns.get(&meta.transaction_id) |
||||
.map(|txn| (payment.inner(), meta, txn.id)) |
||||
}) |
||||
.map(|(payment, meta, txn_id)| StorablePayment { |
||||
payment, |
||||
meta, |
||||
txn_id, |
||||
}); |
||||
|
||||
let stored = self.db.store_payments(self.domain.id(), storable).await?; |
||||
Ok(stored as u32) |
||||
} |
||||
} |
@ -1 +1 @@ |
||||
export const VERSION = '7.0.0'; |
||||
export const VERSION = '7.1.0'; |
||||
|
@ -0,0 +1,38 @@ |
||||
{ |
||||
"ethereum": { |
||||
"sender": "0xEd42a7D8559a463722Ca4beD50E0Cc05a386b0e1" |
||||
}, |
||||
"polygon": { |
||||
"sender": "0xF6B99959F0b5e79E1CC7062E12aF632CEb18eF0d" |
||||
}, |
||||
"avalanche": { |
||||
"sender": "0x27FC7D54C893dA63C0AE6d57e1B2B13A70690928" |
||||
}, |
||||
"arbitrum": { |
||||
"sender": "0xCbFB78a3Eeaa611b826E37c80E4126c8787D29f0" |
||||
}, |
||||
"optimism": { |
||||
"sender": "0x48A9FE90bce5EEd790f3F4Ce192d1C0B351fd4Ca" |
||||
}, |
||||
"bsc": { |
||||
"sender": "0x9d33ee6543C9b2C8c183b8fb58fB089266cffA19" |
||||
}, |
||||
"base": { |
||||
"sender": "0x529467C76f234F2bD359d7ecF7c660A2846b04e2" |
||||
}, |
||||
"metis": { |
||||
"sender": "0x6fDaFb26915ABD6065a1E1501a37Ac438D877f70" |
||||
}, |
||||
"gnosis": { |
||||
"sender": "0x8Dc5310fc9D3D7D1Bb3D1F686899c8F082316c9F" |
||||
}, |
||||
"scroll": { |
||||
"sender": "0x03073D3F4769f6b6604d616238fD6c636C99AD0A" |
||||
}, |
||||
"polygonzkevm": { |
||||
"sender": "0xed7e0874526B9BB9E36C7e9472ed7ed324CEeE3B" |
||||
}, |
||||
"celo": { |
||||
"sender": "0x4A5f4b29C0407E5Feb323305e121f563c7bC4d79" |
||||
} |
||||
} |
@ -0,0 +1,8 @@ |
||||
{ |
||||
"optimism": { |
||||
"router": "0xF385603a12Be8b7B885222329c581FDD1C30071D" |
||||
}, |
||||
"mode": { |
||||
"router": "0xF385603a12Be8b7B885222329c581FDD1C30071D" |
||||
} |
||||
} |
@ -0,0 +1,8 @@ |
||||
{ |
||||
"optimism": { |
||||
"router": "0xA7287a56C01ac8Baaf8e7B662bDB41b10889C7A6" |
||||
}, |
||||
"mode": { |
||||
"router": "0xA7287a56C01ac8Baaf8e7B662bDB41b10889C7A6" |
||||
} |
||||
} |
@ -1,6 +1,5 @@ |
||||
import { createAgentKeysIfNotExists } from '../src/agents/key-utils.js'; |
||||
|
||||
import { getAgentConfigsBasedOnArgs } from './agent-utils.js'; |
||||
import { createAgentKeysIfNotExists } from '../../src/agents/key-utils.js'; |
||||
import { getAgentConfigsBasedOnArgs } from '../agent-utils.js'; |
||||
|
||||
async function main() { |
||||
const { agentConfig } = await getAgentConfigsBasedOnArgs(); |
@ -1,6 +1,5 @@ |
||||
import { deleteAgentKeys } from '../src/agents/key-utils.js'; |
||||
|
||||
import { getAgentConfigsBasedOnArgs } from './agent-utils.js'; |
||||
import { deleteAgentKeys } from '../../src/agents/key-utils.js'; |
||||
import { getAgentConfigsBasedOnArgs } from '../agent-utils.js'; |
||||
|
||||
async function main() { |
||||
const { agentConfig } = await getAgentConfigsBasedOnArgs(); |
@ -1,7 +1,6 @@ |
||||
import { getAllCloudAgentKeys } from '../src/agents/key-utils.js'; |
||||
|
||||
import { getArgs, withContext, withProtocol } from './agent-utils.js'; |
||||
import { getConfigsBasedOnArgs } from './core-utils.js'; |
||||
import { getAllCloudAgentKeys } from '../../src/agents/key-utils.js'; |
||||
import { getArgs, withContext, withProtocol } from '../agent-utils.js'; |
||||
import { getConfigsBasedOnArgs } from '../core-utils.js'; |
||||
|
||||
async function main() { |
||||
const argv = await withProtocol(withContext(getArgs())).argv; |
@ -0,0 +1,38 @@ |
||||
import { getCloudAgentKey } from '../../src/agents/key-utils.js'; |
||||
import { |
||||
getArgs, |
||||
withAgentRole, |
||||
withContext, |
||||
withProtocol, |
||||
} from '../agent-utils.js'; |
||||
import { getConfigsBasedOnArgs } from '../core-utils.js'; |
||||
|
||||
async function main() { |
||||
const argv = await withAgentRole(withContext(getArgs())).argv; |
||||
|
||||
const { agentConfig } = await getConfigsBasedOnArgs(argv); |
||||
|
||||
// As a (very rudimentary) security precaution, we don't print the private key directly to
|
||||
// the console if this script is ran directly.
|
||||
// We only write the private key to the console if it is not a tty, e.g. if
|
||||
// this is being called in a subshell or piped to another command.
|
||||
//
|
||||
// E.g. this will print the private key:
|
||||
// $ echo `yarn tsx infra/scripts/keys/get-key.ts -e mainnet3 --role deployer`
|
||||
// or this too:
|
||||
// $ echo $(yarn tsx infra/scripts/keys/get-key.ts -e mainnet3 --role deployer)
|
||||
// and even this:
|
||||
// $ yarn tsx infra/scripts/keys/get-key.ts -e mainnet3 --role deployer | cat
|
||||
//
|
||||
// But this will not print the private key directly to the shell:
|
||||
// $ yarn tsx infra/scripts/keys/get-key.ts -e mainnet3 --role deployer
|
||||
if (process.stdout.isTTY) { |
||||
console.log('<omitted in tty, use in subshell>'); |
||||
} else { |
||||
const key = getCloudAgentKey(agentConfig, argv.role); |
||||
await key.fetch(); |
||||
console.log(key.privateKey); |
||||
} |
||||
} |
||||
|
||||
main().catch(console.error); |
@ -1,11 +1,10 @@ |
||||
import { AccountConfig, InterchainAccount } from '@hyperlane-xyz/sdk'; |
||||
import { Address, eqAddress, isZeroishAddress } from '@hyperlane-xyz/utils'; |
||||
|
||||
import { chainsToSkip } from '../src/config/chain.js'; |
||||
import { isEthereumProtocolChain } from '../src/utils/utils.js'; |
||||
|
||||
import { getArgs as getEnvArgs, withChains } from './agent-utils.js'; |
||||
import { getEnvironmentConfig, getHyperlaneCore } from './core-utils.js'; |
||||
import { chainsToSkip } from '../../src/config/chain.js'; |
||||
import { isEthereumProtocolChain } from '../../src/utils/utils.js'; |
||||
import { getArgs as getEnvArgs, withChains } from '../agent-utils.js'; |
||||
import { getEnvironmentConfig, getHyperlaneCore } from '../core-utils.js'; |
||||
|
||||
function getArgs() { |
||||
return withChains(getEnvArgs()) |
@ -0,0 +1,98 @@ |
||||
import type { AssetList, Chain as CosmosChain } from '@chain-registry/types'; |
||||
import { Chain, defineChain } from 'viem'; |
||||
|
||||
import { test1 } from '../consts/testChains.js'; |
||||
import { |
||||
ChainMetadata, |
||||
getChainIdNumber, |
||||
} from '../metadata/chainMetadataTypes.js'; |
||||
|
||||
export function chainMetadataToViemChain(metadata: ChainMetadata): Chain { |
||||
return defineChain({ |
||||
id: getChainIdNumber(metadata), |
||||
name: metadata.displayName || metadata.name, |
||||
network: metadata.name, |
||||
nativeCurrency: metadata.nativeToken || test1.nativeToken!, |
||||
rpcUrls: { |
||||
public: { http: [metadata.rpcUrls[0].http] }, |
||||
default: { http: [metadata.rpcUrls[0].http] }, |
||||
}, |
||||
blockExplorers: metadata.blockExplorers?.length |
||||
? { |
||||
default: { |
||||
name: metadata.blockExplorers[0].name, |
||||
url: metadata.blockExplorers[0].url, |
||||
}, |
||||
} |
||||
: undefined, |
||||
testnet: !!metadata.isTestnet, |
||||
}); |
||||
} |
||||
|
||||
export function chainMetadataToCosmosChain(metadata: ChainMetadata): { |
||||
chain: CosmosChain; |
||||
assets: AssetList; |
||||
} { |
||||
const { |
||||
name, |
||||
displayName, |
||||
chainId, |
||||
rpcUrls, |
||||
restUrls, |
||||
isTestnet, |
||||
nativeToken, |
||||
bech32Prefix, |
||||
slip44, |
||||
} = metadata; |
||||
|
||||
if (!nativeToken) throw new Error(`Missing native token for ${name}`); |
||||
|
||||
const chain: CosmosChain = { |
||||
chain_name: name, |
||||
chain_type: 'cosmos', |
||||
status: 'live', |
||||
network_type: isTestnet ? 'testnet' : 'mainnet', |
||||
pretty_name: displayName || name, |
||||
chain_id: chainId as string, |
||||
bech32_prefix: bech32Prefix!, |
||||
slip44: slip44!, |
||||
apis: { |
||||
rpc: [{ address: rpcUrls[0].http, provider: displayName || name }], |
||||
rest: restUrls |
||||
? [{ address: restUrls[0].http, provider: displayName || name }] |
||||
: [], |
||||
}, |
||||
fees: { |
||||
fee_tokens: [{ denom: 'token' }], |
||||
}, |
||||
staking: { |
||||
staking_tokens: [{ denom: 'stake' }], |
||||
}, |
||||
}; |
||||
|
||||
const assets: AssetList = { |
||||
chain_name: name, |
||||
assets: [ |
||||
{ |
||||
description: `The native token of ${displayName || name} chain.`, |
||||
denom_units: [{ denom: 'token', exponent: nativeToken.decimals }], |
||||
base: 'token', |
||||
name: 'token', |
||||
display: 'token', |
||||
symbol: 'token', |
||||
type_asset: 'sdk.coin', |
||||
}, |
||||
{ |
||||
description: `The native token of ${displayName || name} chain.`, |
||||
denom_units: [{ denom: 'token', exponent: nativeToken.decimals }], |
||||
base: 'stake', |
||||
name: 'stake', |
||||
display: 'stake', |
||||
symbol: 'stake', |
||||
type_asset: 'sdk.coin', |
||||
}, |
||||
], |
||||
}; |
||||
|
||||
return { chain, assets }; |
||||
} |
@ -1,6 +1,20 @@ |
||||
import { z } from 'zod'; |
||||
import { SafeParseReturnType, z } from 'zod'; |
||||
|
||||
import { rootLogger } from '@hyperlane-xyz/utils'; |
||||
|
||||
export function isCompliant<S extends Zod.Schema>(schema: S) { |
||||
return (config: unknown): config is z.infer<S> => |
||||
schema.safeParse(config).success; |
||||
} |
||||
|
||||
export function validateZodResult<T>( |
||||
result: SafeParseReturnType<T, T>, |
||||
desc: string = 'config', |
||||
): T { |
||||
if (!result.success) { |
||||
rootLogger.warn(`Invalid ${desc}`, result.error); |
||||
throw new Error(`Invalid desc: ${result.error.toString()}`); |
||||
} else { |
||||
return result.data; |
||||
} |
||||
} |
||||
|
@ -1,29 +0,0 @@ |
||||
import { Chain, defineChain } from 'viem'; |
||||
|
||||
import { test1 } from '../consts/testChains.js'; |
||||
import { |
||||
ChainMetadata, |
||||
getChainIdNumber, |
||||
} from '../metadata/chainMetadataTypes.js'; |
||||
|
||||
export function chainMetadataToViemChain(metadata: ChainMetadata): Chain { |
||||
return defineChain({ |
||||
id: getChainIdNumber(metadata), |
||||
name: metadata.displayName || metadata.name, |
||||
network: metadata.name, |
||||
nativeCurrency: metadata.nativeToken || test1.nativeToken!, |
||||
rpcUrls: { |
||||
public: { http: [metadata.rpcUrls[0].http] }, |
||||
default: { http: [metadata.rpcUrls[0].http] }, |
||||
}, |
||||
blockExplorers: metadata.blockExplorers?.length |
||||
? { |
||||
default: { |
||||
name: metadata.blockExplorers[0].name, |
||||
url: metadata.blockExplorers[0].url, |
||||
}, |
||||
} |
||||
: undefined, |
||||
testnet: !!metadata.isTestnet, |
||||
}); |
||||
} |
@ -0,0 +1,32 @@ |
||||
import { expect } from 'chai'; |
||||
|
||||
import { isHttpsUrl, isRelativeUrl, isUrl } from './url.js'; |
||||
|
||||
describe('URL Utilities', () => { |
||||
it('isUrl', () => { |
||||
expect(isUrl(undefined)).to.be.false; |
||||
expect(isUrl(null)).to.be.false; |
||||
expect(isUrl('')).to.be.false; |
||||
expect(isUrl('foobar')).to.be.false; |
||||
expect(isUrl('https://hyperlane.xyz')).to.be.true; |
||||
}); |
||||
|
||||
it('isHttpsUrl', () => { |
||||
expect(isHttpsUrl(undefined)).to.be.false; |
||||
expect(isHttpsUrl(null)).to.be.false; |
||||
expect(isHttpsUrl('')).to.be.false; |
||||
expect(isHttpsUrl('foobar')).to.be.false; |
||||
expect(isHttpsUrl('http://hyperlane.xyz')).to.be.false; |
||||
expect(isHttpsUrl('https://hyperlane.xyz')).to.be.true; |
||||
}); |
||||
|
||||
it('isRelativeUrl', () => { |
||||
expect(isRelativeUrl(undefined)).to.be.false; |
||||
expect(isRelativeUrl(null)).to.be.false; |
||||
expect(isRelativeUrl('')).to.be.false; |
||||
expect(isRelativeUrl('foobar')).to.be.false; |
||||
expect(isRelativeUrl('https://hyperlane.xyz')).to.be.false; |
||||
expect(isRelativeUrl('/foobar')).to.be.true; |
||||
expect(isRelativeUrl('/foo/bar', 'https://hyperlane.xyz')).to.be.true; |
||||
}); |
||||
}); |
@ -1,18 +1,20 @@ |
||||
{ |
||||
"extends": [ |
||||
"eslint:recommended", |
||||
"plugin:@typescript-eslint/recommended", |
||||
"plugin:react/recommended", |
||||
"plugin:react-hooks/recommended", |
||||
"prettier" |
||||
], |
||||
"plugins": ["react", "react-hooks", "@typescript-eslint"], |
||||
"plugins": ["react", "react-hooks"], |
||||
"rules": { |
||||
// TODO use utils rootLogger in widgets lib |
||||
"no-console": ["off"], |
||||
"react/react-in-jsx-scope": "off", |
||||
"react/prop-types": "off", |
||||
"react-hooks/rules-of-hooks": "error", |
||||
"react-hooks/exhaustive-deps": "warn" |
||||
}, |
||||
"settings": { |
||||
"react": { |
||||
"version": "18", |
||||
"defaultVersion": "18" |
||||
} |
||||
} |
||||
} |
||||
|
@ -0,0 +1,48 @@ |
||||
import React, { Component, PropsWithChildren, ReactNode } from 'react'; |
||||
|
||||
import { errorToString } from '@hyperlane-xyz/utils'; |
||||
|
||||
import { ErrorIcon } from '../icons/Error.js'; |
||||
import { widgetLogger } from '../logger.js'; |
||||
|
||||
type Props = PropsWithChildren<{ |
||||
supportLink?: ReactNode; |
||||
}>; |
||||
|
||||
interface State { |
||||
error: any; |
||||
errorInfo: any; |
||||
} |
||||
|
||||
export class ErrorBoundary extends Component<Props, State> { |
||||
constructor(props: Props) { |
||||
super(props); |
||||
this.state = { error: null, errorInfo: null }; |
||||
} |
||||
|
||||
componentDidCatch(error: any, errorInfo: any) { |
||||
this.setState({ |
||||
error, |
||||
errorInfo, |
||||
}); |
||||
widgetLogger.error('Error caught by error boundary', error, errorInfo); |
||||
} |
||||
|
||||
render() { |
||||
const errorInfo = this.state.error || this.state.errorInfo; |
||||
if (errorInfo) { |
||||
const details = errorToString(errorInfo, 1000); |
||||
return ( |
||||
<div className="htw-flex htw-h-screen htw-w-screen htw-items-center htw-justify-center htw-bg-gray-50"> |
||||
<div className="htw-flex htw-flex-col htw-items-center htw-space-y-5"> |
||||
<ErrorIcon width={80} height={80} /> |
||||
<h1 className="htw-text-lg">Fatal Error Occurred</h1> |
||||
<div className="htw-max-w-2xl htw-text-sm">{details}</div> |
||||
{this.props.supportLink} |
||||
</div> |
||||
</div> |
||||
); |
||||
} |
||||
return this.props.children; |
||||
} |
||||
} |
@ -0,0 +1,38 @@ |
||||
import React, { memo } from 'react'; |
||||
|
||||
import { ColorPalette } from '../color.js'; |
||||
|
||||
import { DefaultIconProps } from './types.js'; |
||||
|
||||
type Props = DefaultIconProps & { |
||||
direction?: 'horizontal' | 'vertical'; |
||||
}; |
||||
|
||||
function _EllipsisIcon({ |
||||
color = ColorPalette.Black, |
||||
width = 24, |
||||
height = 6, |
||||
direction = 'horizontal', |
||||
className, |
||||
...rest |
||||
}: Props) { |
||||
return ( |
||||
<svg |
||||
width={width} |
||||
height={height} |
||||
viewBox="0 0 24 6" |
||||
xmlns="http://www.w3.org/2000/svg" |
||||
className={`${ |
||||
direction === 'vertical' ? 'htw-rotate-90' : '' |
||||
} ${className}`}
|
||||
{...rest} |
||||
> |
||||
<path |
||||
d="M3.42836 5.25C2.74638 5.25 2.09232 5.01295 1.61009 4.59099C1.12785 4.16903 0.856934 3.59674 0.856934 3C0.856934 2.40326 1.12785 1.83097 1.61009 1.40901C2.09232 0.987053 2.74638 0.75 3.42836 0.75C4.11035 0.75 4.7644 0.987053 5.24664 1.40901C5.72887 1.83097 5.99979 2.40326 5.99979 3C5.99979 3.59674 5.72887 4.16903 5.24664 4.59099C4.7644 5.01295 4.11035 5.25 3.42836 5.25ZM11.9998 5.25C11.3178 5.25 10.6638 5.01295 10.1815 4.59099C9.69928 4.16903 9.42836 3.59674 9.42836 3C9.42836 2.40326 9.69928 1.83097 10.1815 1.40901C10.6638 0.987053 11.3178 0.75 11.9998 0.75C12.6818 0.75 13.3358 0.987053 13.8181 1.40901C14.3003 1.83097 14.5712 2.40326 14.5712 3C14.5712 3.59674 14.3003 4.16903 13.8181 4.59099C13.3358 5.01295 12.6818 5.25 11.9998 5.25ZM20.5712 5.25C19.8892 5.25 19.2352 5.01295 18.7529 4.59099C18.2707 4.16903 17.9998 3.59674 17.9998 3C17.9998 2.40326 18.2707 1.83097 18.7529 1.40901C19.2352 0.987053 19.8892 0.75 20.5712 0.75C21.2532 0.75 21.9073 0.987053 22.3895 1.40901C22.8717 1.83097 23.1426 2.40326 23.1426 3C23.1426 3.59674 22.8717 4.16903 22.3895 4.59099C21.9073 5.01295 21.2532 5.25 20.5712 5.25Z" |
||||
fill={color} |
||||
/> |
||||
</svg> |
||||
); |
||||
} |
||||
|
||||
export const EllipsisIcon = memo(_EllipsisIcon); |
@ -0,0 +1,18 @@ |
||||
import React, { memo } from 'react'; |
||||
|
||||
import { ColorPalette } from '../color.js'; |
||||
|
||||
import { DefaultIconProps } from './types.js'; |
||||
|
||||
function _Error({ color, ...rest }: DefaultIconProps) { |
||||
return ( |
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" {...rest}> |
||||
<path |
||||
fill={color || ColorPalette.Black} |
||||
d="M24 34q.7 0 1.18-.47.47-.48.47-1.18t-.47-1.18q-.48-.47-1.18-.47t-1.18.47q-.47.48-.47 1.18t.47 1.18Q23.3 34 24 34Zm.15-7.65q.65 0 1.07-.42.43-.43.43-1.08V15.2q0-.65-.42-1.07-.43-.43-1.08-.43-.65 0-1.07.42-.43.43-.43 1.08v9.65q0 .65.42 1.07.43.43 1.08.43ZM24 44q-4.1 0-7.75-1.57-3.65-1.58-6.38-4.3-2.72-2.73-4.3-6.38Q4 28.1 4 23.95q0-4.1 1.57-7.75 1.58-3.65 4.3-6.35 2.73-2.7 6.38-4.28Q19.9 4 24.05 4q4.1 0 7.75 1.57 3.65 1.58 6.35 4.28 2.7 2.7 4.28 6.35Q44 19.85 44 24q0 4.1-1.57 7.75-1.58 3.65-4.28 6.38t-6.35 4.3Q28.15 44 24 44Zm.05-3q7.05 0 12-4.97T41 23.95q0-7.05-4.95-12T24 7q-7.05 0-12.03 4.95Q7 16.9 7 24q0 7.05 4.97 12.03Q16.95 41 24.05 41ZM24 24Z" |
||||
/> |
||||
</svg> |
||||
); |
||||
} |
||||
|
||||
export const ErrorIcon = memo(_Error); |
@ -0,0 +1,29 @@ |
||||
import React, { memo } from 'react'; |
||||
|
||||
import { ColorPalette } from '../color.js'; |
||||
|
||||
import { DefaultIconProps } from './types.js'; |
||||
|
||||
function _LogoutIcon({ |
||||
color = ColorPalette.Black, |
||||
width = 48, |
||||
height = 48, |
||||
...rest |
||||
}: DefaultIconProps) { |
||||
return ( |
||||
<svg |
||||
xmlns="http://www.w3.org/2000/svg" |
||||
viewBox="0 0 48 48" |
||||
height={height} |
||||
width={width} |
||||
{...rest} |
||||
> |
||||
<path |
||||
fill={color} |
||||
d="M9 42q-1.2 0-2.1-.9Q6 40.2 6 39V9q0-1.2.9-2.1Q7.8 6 9 6h14.55v3H9v30h14.55v3Zm24.3-9.25-2.15-2.15 5.1-5.1h-17.5v-3h17.4l-5.1-5.1 2.15-2.15 8.8 8.8Z" |
||||
/> |
||||
</svg> |
||||
); |
||||
} |
||||
|
||||
export const LogoutIcon = memo(_LogoutIcon); |
@ -0,0 +1,30 @@ |
||||
import React, { memo } from 'react'; |
||||
|
||||
import { ColorPalette } from '../color.js'; |
||||
|
||||
import { DefaultIconProps } from './types.js'; |
||||
|
||||
function _WarningIcon({ |
||||
color = ColorPalette.Black, |
||||
width = 18, |
||||
height = 16, |
||||
...rest |
||||
}: DefaultIconProps) { |
||||
return ( |
||||
<svg |
||||
width={width} |
||||
height={height} |
||||
viewBox="0 0 18 16" |
||||
xmlns="http://www.w3.org/2000/svg" |
||||
{...rest} |
||||
> |
||||
<path |
||||
d="M17.7385 12.8424L10.3944 1.37207C10.0899 0.896794 9.56445 0.609344 9.00031 0.609344C8.43613 0.609344 7.9106 0.896794 7.60622 1.37207L0.261512 12.8424C-0.0648531 13.3519 -0.0874155 13.999 0.203235 14.5299C0.493345 15.0604 1.05035 15.3907 1.65552 15.3907H16.3444C16.9496 15.3907 17.5066 15.0607 17.7967 14.5299C18.0875 13.999 18.0649 13.3519 17.7385 12.8424ZM8.07826 5.27148C8.07826 4.76708 8.48727 4.35837 8.99136 4.35837C9.49553 4.35837 9.9045 4.76708 9.9045 5.27148V9.18939C9.9045 9.69379 9.49553 10.1025 8.99136 10.1025C8.48727 10.1025 8.07826 9.69379 8.07826 9.18939V5.27148ZM8.97416 13.4096C8.34403 13.4096 7.83277 12.8986 7.83277 12.2682C7.83277 11.6377 8.34403 11.1268 8.97416 11.1268C9.60433 11.1268 10.1156 11.6377 10.1156 12.2682C10.1155 12.8986 9.60433 13.4096 8.97416 13.4096Z" |
||||
fill={color} |
||||
fillOpacity="0.8" |
||||
/> |
||||
</svg> |
||||
); |
||||
} |
||||
|
||||
export const WarningIcon = memo(_WarningIcon); |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue