mirror of
https://github.com/status-im/safe-react.git
synced 2025-02-22 22:48:07 +00:00
Development (#355)
* Adds cookie permissions to localStorage/redux state * Adds action * Adds files to git * (fix) linting issues * (update) flow-typed * (update) .eslint and .flowconfig * (add) cookie banner * Finish cookie banner implementation * (Add) checkbox's disabled style. * Removes redux for cookiesStorage * Fix cookieStore deletion * Fixs cookies acceptance * Fixs cookies banner verbiage Fix "x" in wrong place for snackbar messages * (remove) unused library * Adds cookies utils Replaces localStorage with cookies Adds js-cookie * (fix) added correct polished library and import, updated flow-typed * (update) removed polish flow type, added js-cookie flow type * Add link to cookie policy, use generic links for legal docs * Remove link to cookie policy from sidebar, link cookie policy in the banner * Let the user re-open the cookie banner * remove withMutations from cookies reducer, move utils/cookies to logic/cookies * Now the sidebar closes when the cookie banner is toggled * Feature #169: Intercom (#301) * Implements intercom Adds REACT_APP_INTERCOM_ID_MAINNET and REACT_APP_INTERCOM_ID_RINKEBY env vars * Adds .env.example * Adds intercom env vars * Updates env vars Replaces "rinkeby" and "mainnet" with "non-production" and "production" * Now loads intercom after the user accepted the analytics * Add env variable for production intercom id * Update .env.example * Removes react-intercom Fixs getIntercomId with default dev appID Now loads intercom as script * Renegerate flow-types * Remove 'Hide zero balances' (#310) * Use medium font size for 'select an asset' label (#312) * Feature #272: Google Analytics (#299) * Adds google analytics tracking for every route * Adds cookies acceptance check before tracking * Fix react-ga dependency * Fix cookieStore deletion * Merge with #189-cookie-banner * Fixs react ga version Refactored HOC with hooks * Fix TYPO * Fix path for cookies utils * Fix imports * remove flow type definition for polish * Add GA ID log * Fix load GA After cookies acceptance * Feature #224: Activate tokens automatically (#300) * Replace 'Manage Tokens' with 'Manage List' * prevent 301 redirects * Add `BLACKLISTED_TOKENS` key to persist through immortal * Add store/action to extract _activate tokens by its balance_ - keeps already activated tokens - discards blacklisted tokens - adds tokens whose vales are bigger than zero and are not blacklisted * Add `blacklistedTokens` list to safe's store * Display activeTokensByBalance in 'Balances' screen * Enable token's blacklisting functionality in Tokens List * Retrieve balance from API * Rename action to `activateTokensByBalance` * Fix linting errors - line too long - required return * Do not persist a separate list into `BLACKLISTED_TOKENS` * Typo fix (#326) * Fix security vulnerability: Remove uglifyjs, use terser plugin (#327) * Remove uglifyjs, use terser plugin * fix css-loader config * Feature #256: Sticky header (#308) * Add sticky header * Remove react-headroom, set position to fixed for header * Regenerate yarn lock * Remove unused headroom style from root.scss * Pull from dev, conflict fixes * Update welcome text (#323) * Feature #137: Tx list improvements (#222) * Fix swapOwners threshold displayed as hex in tx list * Refactor spinner in empty table * Fix number of rows per page in table pagination * Add use of EtherscanLink component * Set short version of strings in tx list * Adjust styles in tx list * Add more styles to table * WIP * An attempt to fix #204 by showing UNKNOWN instead of failed to fetch token symbol * Table pagination style fixes * Show confirm transaction button in owner list * Update dependencies * Add confirmation icons to owner list in tx list * exclude unneeded stuff from travis.yml * Adds cookie permissions to localStorage/redux state * Update dependencies * Adds action * Adds files to git * (fix) linting issues * (update) flow-typed * (update) .eslint and .flowconfig * (add) cookie banner * Finish cookie banner implementation * (Add) checkbox's disabled style. * Removes redux for cookiesStorage * Fix cookieStore deletion * Increase TO_EXP for bignumber.js * Fixs cookies acceptance * Fixs cookies banner verbiage Fix "x" in wrong place for snackbar messages * (fix) added correct polished library and import, updated flow-typed * (update) removed polish flow type, added js-cookie flow type * Add link to cookie policy, use generic links for legal docs * Remove link to cookie policy from sidebar, link cookie policy in the banner * Mock Safe creation transaction * Format code * Fix break statement * Remove deployment of storybook * Let the user re-open the cookie banner * Update tx status messages and visual confirmation progress * Fix svg in tx confirmation progress * Add styles to tx type in tx list * Replace nonce in tx list with tx id * Update opacity of cancelled tx * Fix short version of address * remove withMutations from cookies reducer, move utils/cookies to logic/cookies * Now the sidebar closes when the cookie banner is toggled * Fix styles in tx list * Add Pending status in tx description * (remove) unused library * Adds cookies utils Replaces localStorage with cookies Adds js-cookie * Set 25 rows per page in tx list by default * Align tx table * Adjust tx table and tx details borders * Fix fetching transactions to show Safe creation tx alone * Fix failed Safe creation transaction * Add styles to tx data * Refactor and fix owner list in transaction * Refactor use of theme variables * Remove storybook files * Update dependencies * Fix warnings * Fix dependencies * Update file-loader config * Fix owner colors in the tx confirmation progress * Fix transaction type icon height * Tx list adjustments * Update readme * (Feature) Etherscan button icon (#331) * (add) new open on etherscan button icon * (remove) unused asset * (fix) icon background * Feature #239: Replace early access label with network label (#311) * Remove early access label * Revert "Remove early access label" This reverts commit 34682f0f6d9c1974a6e45c2a31358864931d9c1e. * Replace early access label with network label * Capitalzie first letter of the network name * Adds threshold update on checkAndUpdateSafe (#320) * Feature #159: Pending transaction that requires user confirmation (#330) * Creates a new notification: waitingConfirmation Adds key as optional parameter for notification Implemented getAwaitingTransactions to get the transactions that needs to be confirmed by the current user Not fetchTransactions action also dispatch a notification for awaiting transactions Improved performance of routes/safe/container/index to avoid re-rendering * Removes notification logic on fetchTransactions Adds notificationsMiddleware * Moves fetchTransaction to container * Removes unused param on fetchTransactions * Fixs null safe check * Fixs middleware declaration * Removes lodash * Changes cancelled transaction detection logic * Feature #122: Multisig migration (#315) * Adds query-string package.json Parses query string on open layout * Implements load all the values on openSafe view from param querys * Adds query params validation * Moves query parse logic to open.jsx * Changes default no metamask component on open page * Replaces global isNaN * Fix threshold parsing validation * Updates the welcome component with new verbiage for open * Renames isOpenSafe to isOldMultisigMigration * Merge branch 'development' of https://github.com/gnosis/safe-react into 122-multisig-migration # Conflicts: # src/routes/open/components/Layout.jsx * Merge branch 'development' of https://github.com/gnosis/safe-react into 159-pending-transactions # Conflicts: # src/routes/safe/components/Transactions/index.jsx # yarn.lock * set anonymizeIp to true (#335) * Feature #180: Predict transaction nonce (#293) * Dep bump * Fetch transactions when safe view is mounted * eslint fix * Calculate new tx nonce from latest tx in service * Fix tx cancellation, allow passing nonce to createTransaction * dep bump * Refactor createTransaction/processTransaction to use object as argument * Adopting transactions table to new send tx flow with predicted nonces * dep bump, disable esModule in file-loader options after new v5 release * Don't show older tx annotation for already executed txs * sort tx by nonce * get new safe nonce after tx execution * Bugfixes * remove whitespace for showOlderTxAnnotation * Feature #329: Rename to Multisig (#334) * Rename to Multisig * migration text fix * replace safe for teams with multisig * Fixs race condition (#341) Fixs typo * (Feature) Incoming transactions (#333) * Add `blockNumber` to transactions model * Create `incomingTransaction` node in store and load it along with `transactions` * Add incoming transfers to the Transactions table * Rename `transactionHash` to `executionTxHash` for better incoming/outgoing txs unification in Transactions table * Add incoming transactions details * Add transaction type icon in table row * Add snackbar notification for incoming txs * Make incoming transaction snackbar to show on any tab * Use makeStyles hooks * Fix incoming amounts conversion from wei * Make concurrent promise calls * Use date to calculate transactions ids * Prevent repeating messages - also move logic to display snack bar into the notifications middleware * Merge transactions and incomingTxs to the transactions selector * Show 'Multiple incoming transfers' if they are more than 3 * Prevent incoming transactions snack bar for first-timer users * Set ID as the default order * Use constant for _incoming_ type * Feature #154: Fiat Balances (#290) * Adds DropdownCurrency Adds redux store for currencyValues Adds Value column on the assets table Adds mocked currency values * (add) base currency dropdown * (add) dropdown styles * Refactors data fetching of the balances list Now uses the endpoint * Fix column value styling * Adds support for ECB currency values * Fixs list overflow * Changes endpoint url Adds decimals for balance values * (fix) remove inline style * (add) currencies dropdown search field * (fix) list items' hover color * Implements filter search * Fix warning on dropdown template * Saves selected currency in localStorage * Remove spaces on curly braces Add alt Renames rowItem to cellItem Improves fetchCurrenciesRates handling * Removes withMutations * Removes middleware Export style to another file for dropdownCurrency * Adds classNames * Fix incomming transactions fetching (#346) * Feature: Activate fortmatic (#339) * Add fortmatic integration to web3connect * add fortmatic * Safe open form improvements: limit calling initContracts to 1 time * update .env.example * Feature #336: Confirmation required notification for non-owners fix (#338) * Refactors grantedSelector with isUserOwner function Checks if the user is owner of the safe before sending notification * Adds safeParamAddressFromStateSelector Refactors notificationsMiddleware with new selector * Remove old size check * safe notifications middleware fixes * add apt-get update to travis yml * (Fix) Incoming transactions inline-styles (#344) * Remove inline styles * Replace ternary with logical && operator * use cn as shortcut for classnames
This commit is contained in:
parent
405d8ba336
commit
fff057d8e6
@ -9,3 +9,7 @@ REACT_APP_GOOGLE_ANALYTICS_ID_MAINNET=
|
||||
|
||||
# For production environments
|
||||
REACT_APP_INTERCOM_ID=
|
||||
REACT_APP_PORTIS_ID=
|
||||
REACT_APP_SQUARELINK_ID=
|
||||
REACT_APP_FORTMATIC_KEY=
|
||||
|
||||
|
@ -3,7 +3,6 @@
|
||||
<PROJECT_ROOT>/contracts/**/.*
|
||||
<PROJECT_ROOT>/scripts/**/.*
|
||||
<PROJECT_ROOT>/public/**/.*
|
||||
<PROJECT_ROOT>/src/test/**/.*
|
||||
<PROJECT_ROOT>/babel.config.js
|
||||
<PROJECT_ROOT>/jest.config.js
|
||||
<PROJECT_ROOT>/truffle.js
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,6 +1,5 @@
|
||||
node_modules/
|
||||
build_webpack/
|
||||
build_storybook/
|
||||
.DS_Store
|
||||
build/
|
||||
yarn-error.log
|
||||
|
@ -1,3 +0,0 @@
|
||||
import '@storybook/addon-actions/register'
|
||||
import '@storybook/addon-links/register'
|
||||
import '@storybook/addon-knobs/register'
|
@ -1,35 +0,0 @@
|
||||
import 'babel-polyfill'
|
||||
import { addDecorator, configure } from '@storybook/react'
|
||||
import { withKnobs } from '@storybook/addon-knobs'
|
||||
import { MuiThemeProvider } from '@material-ui/core/styles'
|
||||
import * as React from 'react'
|
||||
import { Provider } from 'react-redux'
|
||||
import StoryRouter from 'storybook-router'
|
||||
import { store } from '~/store'
|
||||
import theme from '~/theme/mui'
|
||||
import 'index.scss'
|
||||
|
||||
(function (global) {
|
||||
//Useful for adding data and libraries to window object.
|
||||
})(typeof window !== 'undefined' ? window : {});
|
||||
|
||||
addDecorator(withKnobs);
|
||||
addDecorator(StoryRouter())
|
||||
|
||||
addDecorator((story) => (
|
||||
<Provider store={store}>
|
||||
<MuiThemeProvider theme={theme}>
|
||||
{ story() }
|
||||
</MuiThemeProvider>
|
||||
</Provider>
|
||||
))
|
||||
|
||||
const components = require.context('../src/components', true, /\.stories\.((js|ts)x?)$/)
|
||||
const routes = require.context('../src/routes', true, /\.stories\.((js|ts)x?)$/)
|
||||
|
||||
function loadStories() {
|
||||
components.keys().forEach((filename) => components(filename))
|
||||
routes.keys().forEach((filename) => routes(filename))
|
||||
}
|
||||
|
||||
configure(loadStories, module)
|
@ -1 +0,0 @@
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
|
@ -1,13 +0,0 @@
|
||||
|
||||
process.env.NODE_ENV = 'development'
|
||||
const prodConfig = require('../config/webpack.config.dev');
|
||||
|
||||
module.exports = function(storybookConfig, configType) {
|
||||
|
||||
const config = Object.assign({}, prodConfig);
|
||||
|
||||
storybookConfig.module.rules = storybookConfig.module.rules.concat(config.module.rules)
|
||||
storybookConfig.resolve = config.resolve;
|
||||
|
||||
return storybookConfig;
|
||||
};
|
@ -21,6 +21,7 @@ matrix:
|
||||
- REACT_APP_NETWORK='rinkeby'
|
||||
before_install:
|
||||
# Needed to deploy pull request and releases
|
||||
- sudo apt-get update
|
||||
- sudo apt-get -y install python-pip python-dev
|
||||
- pip install awscli --upgrade --user
|
||||
# Install truffle
|
||||
|
@ -133,6 +133,7 @@ module.exports = {
|
||||
{
|
||||
loader: 'file-loader',
|
||||
options: {
|
||||
esModule: false,
|
||||
name: 'img/[hash].[ext]',
|
||||
esModule: false
|
||||
},
|
||||
|
122
flow-typed/npm/@sambego/storybook-state_vx.x.x.js
vendored
122
flow-typed/npm/@sambego/storybook-state_vx.x.x.js
vendored
@ -1,122 +0,0 @@
|
||||
// flow-typed signature: 9e597e3161a1342a9e77ec9437783354
|
||||
// flow-typed version: <<STUB>>/@sambego/storybook-state_v^1.3.6/flow_v0.112.0
|
||||
|
||||
/**
|
||||
* This is an autogenerated libdef stub for:
|
||||
*
|
||||
* '@sambego/storybook-state'
|
||||
*
|
||||
* Fill this stub out by replacing all the `any` types.
|
||||
*
|
||||
* Once filled out, we encourage you to share your work with the
|
||||
* community by sending a pull request to:
|
||||
* https://github.com/flowtype/flow-typed
|
||||
*/
|
||||
|
||||
declare module '@sambego/storybook-state' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* We include stubs for each file inside this npm package in case you need to
|
||||
* require those files directly. Feel free to delete any files that aren't
|
||||
* needed.
|
||||
*/
|
||||
declare module '@sambego/storybook-state/dist' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@sambego/storybook-state/dist/State' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@sambego/storybook-state/dist/StateDecorator' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@sambego/storybook-state/dist/Store' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@sambego/storybook-state/enzyme.config' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@sambego/storybook-state/jest.config' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@sambego/storybook-state/src' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@sambego/storybook-state/src/State' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@sambego/storybook-state/src/StateDecorator' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@sambego/storybook-state/src/Store' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@sambego/storybook-state/tests/State.test' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@sambego/storybook-state/tests/StateDecorator.test' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@sambego/storybook-state/tests/Store.test' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
// Filename aliases
|
||||
declare module '@sambego/storybook-state/dist/index' {
|
||||
declare module.exports: $Exports<'@sambego/storybook-state/dist'>;
|
||||
}
|
||||
declare module '@sambego/storybook-state/dist/index.js' {
|
||||
declare module.exports: $Exports<'@sambego/storybook-state/dist'>;
|
||||
}
|
||||
declare module '@sambego/storybook-state/dist/State.js' {
|
||||
declare module.exports: $Exports<'@sambego/storybook-state/dist/State'>;
|
||||
}
|
||||
declare module '@sambego/storybook-state/dist/StateDecorator.js' {
|
||||
declare module.exports: $Exports<'@sambego/storybook-state/dist/StateDecorator'>;
|
||||
}
|
||||
declare module '@sambego/storybook-state/dist/Store.js' {
|
||||
declare module.exports: $Exports<'@sambego/storybook-state/dist/Store'>;
|
||||
}
|
||||
declare module '@sambego/storybook-state/enzyme.config.js' {
|
||||
declare module.exports: $Exports<'@sambego/storybook-state/enzyme.config'>;
|
||||
}
|
||||
declare module '@sambego/storybook-state/jest.config.js' {
|
||||
declare module.exports: $Exports<'@sambego/storybook-state/jest.config'>;
|
||||
}
|
||||
declare module '@sambego/storybook-state/src/index' {
|
||||
declare module.exports: $Exports<'@sambego/storybook-state/src'>;
|
||||
}
|
||||
declare module '@sambego/storybook-state/src/index.js' {
|
||||
declare module.exports: $Exports<'@sambego/storybook-state/src'>;
|
||||
}
|
||||
declare module '@sambego/storybook-state/src/State.js' {
|
||||
declare module.exports: $Exports<'@sambego/storybook-state/src/State'>;
|
||||
}
|
||||
declare module '@sambego/storybook-state/src/StateDecorator.js' {
|
||||
declare module.exports: $Exports<'@sambego/storybook-state/src/StateDecorator'>;
|
||||
}
|
||||
declare module '@sambego/storybook-state/src/Store.js' {
|
||||
declare module.exports: $Exports<'@sambego/storybook-state/src/Store'>;
|
||||
}
|
||||
declare module '@sambego/storybook-state/tests/State.test.js' {
|
||||
declare module.exports: $Exports<'@sambego/storybook-state/tests/State.test'>;
|
||||
}
|
||||
declare module '@sambego/storybook-state/tests/StateDecorator.test.js' {
|
||||
declare module.exports: $Exports<'@sambego/storybook-state/tests/StateDecorator.test'>;
|
||||
}
|
||||
declare module '@sambego/storybook-state/tests/Store.test.js' {
|
||||
declare module.exports: $Exports<'@sambego/storybook-state/tests/Store.test'>;
|
||||
}
|
187
flow-typed/npm/@storybook/addon-actions_vx.x.x.js
vendored
187
flow-typed/npm/@storybook/addon-actions_vx.x.x.js
vendored
@ -1,187 +0,0 @@
|
||||
// flow-typed signature: 64c369e4ed0c4a705b2f36b522874cac
|
||||
// flow-typed version: <<STUB>>/@storybook/addon-actions_v5.2.6/flow_v0.112.0
|
||||
|
||||
/**
|
||||
* This is an autogenerated libdef stub for:
|
||||
*
|
||||
* '@storybook/addon-actions'
|
||||
*
|
||||
* Fill this stub out by replacing all the `any` types.
|
||||
*
|
||||
* Once filled out, we encourage you to share your work with the
|
||||
* community by sending a pull request to:
|
||||
* https://github.com/flowtype/flow-typed
|
||||
*/
|
||||
|
||||
declare module '@storybook/addon-actions' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* We include stubs for each file inside this npm package in case you need to
|
||||
* require those files directly. Feel free to delete any files that aren't
|
||||
* needed.
|
||||
*/
|
||||
declare module '@storybook/addon-actions/dist/components/ActionLogger' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-actions/dist/components/ActionLogger/style' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-actions/dist/constants' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-actions/dist/containers/ActionLogger' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-actions/dist' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-actions/dist/manager' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-actions/dist/models/ActionDisplay' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-actions/dist/models/ActionOptions' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-actions/dist/models/ActionsFunction' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-actions/dist/models/ActionsMap' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-actions/dist/models/DecoratorFunction' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-actions/dist/models/HandlerFunction' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-actions/dist/models' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-actions/dist/preview/action' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-actions/dist/preview/actions' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-actions/dist/preview/configureActions' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-actions/dist/preview/decorateAction' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-actions/dist/preview' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-actions/dist/preview/withActions' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-actions/dist/typings.d' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-actions/register' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
// Filename aliases
|
||||
declare module '@storybook/addon-actions/dist/components/ActionLogger/index' {
|
||||
declare module.exports: $Exports<'@storybook/addon-actions/dist/components/ActionLogger'>;
|
||||
}
|
||||
declare module '@storybook/addon-actions/dist/components/ActionLogger/index.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-actions/dist/components/ActionLogger'>;
|
||||
}
|
||||
declare module '@storybook/addon-actions/dist/components/ActionLogger/style.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-actions/dist/components/ActionLogger/style'>;
|
||||
}
|
||||
declare module '@storybook/addon-actions/dist/constants.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-actions/dist/constants'>;
|
||||
}
|
||||
declare module '@storybook/addon-actions/dist/containers/ActionLogger/index' {
|
||||
declare module.exports: $Exports<'@storybook/addon-actions/dist/containers/ActionLogger'>;
|
||||
}
|
||||
declare module '@storybook/addon-actions/dist/containers/ActionLogger/index.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-actions/dist/containers/ActionLogger'>;
|
||||
}
|
||||
declare module '@storybook/addon-actions/dist/index' {
|
||||
declare module.exports: $Exports<'@storybook/addon-actions/dist'>;
|
||||
}
|
||||
declare module '@storybook/addon-actions/dist/index.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-actions/dist'>;
|
||||
}
|
||||
declare module '@storybook/addon-actions/dist/manager.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-actions/dist/manager'>;
|
||||
}
|
||||
declare module '@storybook/addon-actions/dist/models/ActionDisplay.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-actions/dist/models/ActionDisplay'>;
|
||||
}
|
||||
declare module '@storybook/addon-actions/dist/models/ActionOptions.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-actions/dist/models/ActionOptions'>;
|
||||
}
|
||||
declare module '@storybook/addon-actions/dist/models/ActionsFunction.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-actions/dist/models/ActionsFunction'>;
|
||||
}
|
||||
declare module '@storybook/addon-actions/dist/models/ActionsMap.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-actions/dist/models/ActionsMap'>;
|
||||
}
|
||||
declare module '@storybook/addon-actions/dist/models/DecoratorFunction.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-actions/dist/models/DecoratorFunction'>;
|
||||
}
|
||||
declare module '@storybook/addon-actions/dist/models/HandlerFunction.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-actions/dist/models/HandlerFunction'>;
|
||||
}
|
||||
declare module '@storybook/addon-actions/dist/models/index' {
|
||||
declare module.exports: $Exports<'@storybook/addon-actions/dist/models'>;
|
||||
}
|
||||
declare module '@storybook/addon-actions/dist/models/index.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-actions/dist/models'>;
|
||||
}
|
||||
declare module '@storybook/addon-actions/dist/preview/action.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-actions/dist/preview/action'>;
|
||||
}
|
||||
declare module '@storybook/addon-actions/dist/preview/actions.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-actions/dist/preview/actions'>;
|
||||
}
|
||||
declare module '@storybook/addon-actions/dist/preview/configureActions.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-actions/dist/preview/configureActions'>;
|
||||
}
|
||||
declare module '@storybook/addon-actions/dist/preview/decorateAction.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-actions/dist/preview/decorateAction'>;
|
||||
}
|
||||
declare module '@storybook/addon-actions/dist/preview/index' {
|
||||
declare module.exports: $Exports<'@storybook/addon-actions/dist/preview'>;
|
||||
}
|
||||
declare module '@storybook/addon-actions/dist/preview/index.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-actions/dist/preview'>;
|
||||
}
|
||||
declare module '@storybook/addon-actions/dist/preview/withActions.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-actions/dist/preview/withActions'>;
|
||||
}
|
||||
declare module '@storybook/addon-actions/dist/typings.d.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-actions/dist/typings.d'>;
|
||||
}
|
||||
declare module '@storybook/addon-actions/register.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-actions/register'>;
|
||||
}
|
283
flow-typed/npm/@storybook/addon-knobs_vx.x.x.js
vendored
283
flow-typed/npm/@storybook/addon-knobs_vx.x.x.js
vendored
@ -1,283 +0,0 @@
|
||||
// flow-typed signature: 90624ef390fe4c5befd27eedd08d7ad2
|
||||
// flow-typed version: <<STUB>>/@storybook/addon-knobs_v5.2.6/flow_v0.112.0
|
||||
|
||||
/**
|
||||
* This is an autogenerated libdef stub for:
|
||||
*
|
||||
* '@storybook/addon-knobs'
|
||||
*
|
||||
* Fill this stub out by replacing all the `any` types.
|
||||
*
|
||||
* Once filled out, we encourage you to share your work with the
|
||||
* community by sending a pull request to:
|
||||
* https://github.com/flowtype/flow-typed
|
||||
*/
|
||||
|
||||
declare module '@storybook/addon-knobs' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* We include stubs for each file inside this npm package in case you need to
|
||||
* require those files directly. Feel free to delete any files that aren't
|
||||
* needed.
|
||||
*/
|
||||
declare module '@storybook/addon-knobs/angular' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-knobs/dist/__types__/knob-test-cases' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-knobs/dist/components/Panel' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-knobs/dist/components/PropForm' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-knobs/dist/components/types/Array' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-knobs/dist/components/types/Boolean' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-knobs/dist/components/types/Button' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-knobs/dist/components/types/Checkboxes' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-knobs/dist/components/types/Color' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-knobs/dist/components/types/Date' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-knobs/dist/components/types/Files' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-knobs/dist/components/types' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-knobs/dist/components/types/Number' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-knobs/dist/components/types/Object' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-knobs/dist/components/types/Options' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-knobs/dist/components/types/Radio' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-knobs/dist/components/types/Select' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-knobs/dist/components/types/Text' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-knobs/dist/components/types/types' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-knobs/dist/converters' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-knobs/dist/deprecated' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-knobs/dist' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-knobs/dist/KnobManager' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-knobs/dist/KnobStore' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-knobs/dist/register' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-knobs/dist/registerKnobs' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-knobs/dist/shared' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-knobs/dist/type-defs' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-knobs/dist/typings.d' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-knobs/html' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-knobs/marko' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-knobs/mithril' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-knobs/polymer' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-knobs/react' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-knobs/register' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-knobs/vue' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
// Filename aliases
|
||||
declare module '@storybook/addon-knobs/angular.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-knobs/angular'>;
|
||||
}
|
||||
declare module '@storybook/addon-knobs/dist/__types__/knob-test-cases.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/__types__/knob-test-cases'>;
|
||||
}
|
||||
declare module '@storybook/addon-knobs/dist/components/Panel.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/components/Panel'>;
|
||||
}
|
||||
declare module '@storybook/addon-knobs/dist/components/PropForm.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/components/PropForm'>;
|
||||
}
|
||||
declare module '@storybook/addon-knobs/dist/components/types/Array.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/components/types/Array'>;
|
||||
}
|
||||
declare module '@storybook/addon-knobs/dist/components/types/Boolean.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/components/types/Boolean'>;
|
||||
}
|
||||
declare module '@storybook/addon-knobs/dist/components/types/Button.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/components/types/Button'>;
|
||||
}
|
||||
declare module '@storybook/addon-knobs/dist/components/types/Checkboxes.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/components/types/Checkboxes'>;
|
||||
}
|
||||
declare module '@storybook/addon-knobs/dist/components/types/Color.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/components/types/Color'>;
|
||||
}
|
||||
declare module '@storybook/addon-knobs/dist/components/types/Date.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/components/types/Date'>;
|
||||
}
|
||||
declare module '@storybook/addon-knobs/dist/components/types/Files.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/components/types/Files'>;
|
||||
}
|
||||
declare module '@storybook/addon-knobs/dist/components/types/index' {
|
||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/components/types'>;
|
||||
}
|
||||
declare module '@storybook/addon-knobs/dist/components/types/index.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/components/types'>;
|
||||
}
|
||||
declare module '@storybook/addon-knobs/dist/components/types/Number.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/components/types/Number'>;
|
||||
}
|
||||
declare module '@storybook/addon-knobs/dist/components/types/Object.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/components/types/Object'>;
|
||||
}
|
||||
declare module '@storybook/addon-knobs/dist/components/types/Options.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/components/types/Options'>;
|
||||
}
|
||||
declare module '@storybook/addon-knobs/dist/components/types/Radio.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/components/types/Radio'>;
|
||||
}
|
||||
declare module '@storybook/addon-knobs/dist/components/types/Select.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/components/types/Select'>;
|
||||
}
|
||||
declare module '@storybook/addon-knobs/dist/components/types/Text.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/components/types/Text'>;
|
||||
}
|
||||
declare module '@storybook/addon-knobs/dist/components/types/types.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/components/types/types'>;
|
||||
}
|
||||
declare module '@storybook/addon-knobs/dist/converters.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/converters'>;
|
||||
}
|
||||
declare module '@storybook/addon-knobs/dist/deprecated.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/deprecated'>;
|
||||
}
|
||||
declare module '@storybook/addon-knobs/dist/index' {
|
||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist'>;
|
||||
}
|
||||
declare module '@storybook/addon-knobs/dist/index.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist'>;
|
||||
}
|
||||
declare module '@storybook/addon-knobs/dist/KnobManager.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/KnobManager'>;
|
||||
}
|
||||
declare module '@storybook/addon-knobs/dist/KnobStore.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/KnobStore'>;
|
||||
}
|
||||
declare module '@storybook/addon-knobs/dist/register.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/register'>;
|
||||
}
|
||||
declare module '@storybook/addon-knobs/dist/registerKnobs.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/registerKnobs'>;
|
||||
}
|
||||
declare module '@storybook/addon-knobs/dist/shared.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/shared'>;
|
||||
}
|
||||
declare module '@storybook/addon-knobs/dist/type-defs.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/type-defs'>;
|
||||
}
|
||||
declare module '@storybook/addon-knobs/dist/typings.d.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-knobs/dist/typings.d'>;
|
||||
}
|
||||
declare module '@storybook/addon-knobs/html.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-knobs/html'>;
|
||||
}
|
||||
declare module '@storybook/addon-knobs/marko.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-knobs/marko'>;
|
||||
}
|
||||
declare module '@storybook/addon-knobs/mithril.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-knobs/mithril'>;
|
||||
}
|
||||
declare module '@storybook/addon-knobs/polymer.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-knobs/polymer'>;
|
||||
}
|
||||
declare module '@storybook/addon-knobs/react.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-knobs/react'>;
|
||||
}
|
||||
declare module '@storybook/addon-knobs/register.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-knobs/register'>;
|
||||
}
|
||||
declare module '@storybook/addon-knobs/vue.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-knobs/vue'>;
|
||||
}
|
101
flow-typed/npm/@storybook/addon-links_vx.x.x.js
vendored
101
flow-typed/npm/@storybook/addon-links_vx.x.x.js
vendored
@ -1,101 +0,0 @@
|
||||
// flow-typed signature: f6f4916ab4d700d3db6ac07b4264aa7e
|
||||
// flow-typed version: <<STUB>>/@storybook/addon-links_v5.2.6/flow_v0.112.0
|
||||
|
||||
/**
|
||||
* This is an autogenerated libdef stub for:
|
||||
*
|
||||
* '@storybook/addon-links'
|
||||
*
|
||||
* Fill this stub out by replacing all the `any` types.
|
||||
*
|
||||
* Once filled out, we encourage you to share your work with the
|
||||
* community by sending a pull request to:
|
||||
* https://github.com/flowtype/flow-typed
|
||||
*/
|
||||
|
||||
declare module '@storybook/addon-links' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* We include stubs for each file inside this npm package in case you need to
|
||||
* require those files directly. Feel free to delete any files that aren't
|
||||
* needed.
|
||||
*/
|
||||
declare module '@storybook/addon-links/dist/constants' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-links/dist' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-links/dist/manager' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-links/dist/preview' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-links/dist/react/components/link' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-links/dist/react/components/RoutedLink' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-links/dist/react' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-links/dist/typings.d' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-links/react' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module '@storybook/addon-links/register' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
// Filename aliases
|
||||
declare module '@storybook/addon-links/dist/constants.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-links/dist/constants'>;
|
||||
}
|
||||
declare module '@storybook/addon-links/dist/index' {
|
||||
declare module.exports: $Exports<'@storybook/addon-links/dist'>;
|
||||
}
|
||||
declare module '@storybook/addon-links/dist/index.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-links/dist'>;
|
||||
}
|
||||
declare module '@storybook/addon-links/dist/manager.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-links/dist/manager'>;
|
||||
}
|
||||
declare module '@storybook/addon-links/dist/preview.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-links/dist/preview'>;
|
||||
}
|
||||
declare module '@storybook/addon-links/dist/react/components/link.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-links/dist/react/components/link'>;
|
||||
}
|
||||
declare module '@storybook/addon-links/dist/react/components/RoutedLink.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-links/dist/react/components/RoutedLink'>;
|
||||
}
|
||||
declare module '@storybook/addon-links/dist/react/index' {
|
||||
declare module.exports: $Exports<'@storybook/addon-links/dist/react'>;
|
||||
}
|
||||
declare module '@storybook/addon-links/dist/react/index.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-links/dist/react'>;
|
||||
}
|
||||
declare module '@storybook/addon-links/dist/typings.d.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-links/dist/typings.d'>;
|
||||
}
|
||||
declare module '@storybook/addon-links/react.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-links/react'>;
|
||||
}
|
||||
declare module '@storybook/addon-links/register.js' {
|
||||
declare module.exports: $Exports<'@storybook/addon-links/register'>;
|
||||
}
|
61
flow-typed/npm/@storybook/react_v5.x.x.js
vendored
61
flow-typed/npm/@storybook/react_v5.x.x.js
vendored
@ -1,61 +0,0 @@
|
||||
// flow-typed signature: e484579841f3cb1e8f57a768abc4642d
|
||||
// flow-typed version: c6154227d1/@storybook/react_v5.x.x/flow_>=v0.104.x
|
||||
|
||||
type NodeModule = typeof module;
|
||||
|
||||
declare module '@storybook/react' {
|
||||
declare type Context = {
|
||||
kind: string,
|
||||
story: string,
|
||||
...
|
||||
};
|
||||
declare type Renderable =
|
||||
| string
|
||||
| number
|
||||
| React$Element<any>
|
||||
| Iterable<?Renderable>;
|
||||
declare type RenderCallback = (
|
||||
context: Context
|
||||
) => Renderable;
|
||||
declare type RenderFunction = () => Renderable;
|
||||
|
||||
declare type StoryDecorator = (
|
||||
story: RenderFunction,
|
||||
context: Context
|
||||
) => Renderable;
|
||||
|
||||
declare type DecoratorParameters = { [key: string]: any, ... };
|
||||
|
||||
declare interface Story {
|
||||
+kind: string;
|
||||
add(
|
||||
storyName: string,
|
||||
callback: RenderCallback,
|
||||
parameters?: DecoratorParameters
|
||||
): Story;
|
||||
addDecorator(decorator: StoryDecorator): Story;
|
||||
addParameters(parameters: DecoratorParameters): Story;
|
||||
}
|
||||
|
||||
declare interface StoryObject {
|
||||
name: string;
|
||||
render: RenderFunction;
|
||||
}
|
||||
|
||||
declare interface StoryBucket {
|
||||
kind: string;
|
||||
filename: string;
|
||||
stories: Array<StoryObject>;
|
||||
}
|
||||
|
||||
declare function addDecorator(decorator: StoryDecorator): void;
|
||||
declare function addParameters(parameters: DecoratorParameters): void;
|
||||
declare function clearDecorators(): void;
|
||||
declare function configure(fn: () => void, module: NodeModule): void;
|
||||
declare function setAddon(addon: Object): void;
|
||||
declare function storiesOf(name: string, module: NodeModule): Story;
|
||||
declare function storiesOf<T>(name: string, module: NodeModule): Story & T;
|
||||
declare function forceReRender(): void;
|
||||
|
||||
declare function getStorybook(): Array<StoryBucket>;
|
||||
}
|
249
flow-typed/npm/storybook-host_vx.x.x.js
vendored
249
flow-typed/npm/storybook-host_vx.x.x.js
vendored
@ -1,249 +0,0 @@
|
||||
// flow-typed signature: 48ec61af419d1ece506839678031f356
|
||||
// flow-typed version: <<STUB>>/storybook-host_v5.1.0/flow_v0.112.0
|
||||
|
||||
/**
|
||||
* This is an autogenerated libdef stub for:
|
||||
*
|
||||
* 'storybook-host'
|
||||
*
|
||||
* Fill this stub out by replacing all the `any` types.
|
||||
*
|
||||
* Once filled out, we encourage you to share your work with the
|
||||
* community by sending a pull request to:
|
||||
* https://github.com/flowtype/flow-typed
|
||||
*/
|
||||
|
||||
declare module 'storybook-host' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* We include stubs for each file inside this npm package in case you need to
|
||||
* require those files directly. Feel free to delete any files that aren't
|
||||
* needed.
|
||||
*/
|
||||
declare module 'storybook-host/lib/common/alignment' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'storybook-host/lib/common/color' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'storybook-host/lib/common/css/css' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'storybook-host/lib/common/css/glamor' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'storybook-host/lib/common/css' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'storybook-host/lib/common/css/test/css-flex.test' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'storybook-host/lib/common/css/test/css-image.test' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'storybook-host/lib/common/css/test/css-positioning.test' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'storybook-host/lib/common/css/test/css-spacing.test' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'storybook-host/lib/common/css/test/css.test' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'storybook-host/lib/common/css/types' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'storybook-host/lib/common' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'storybook-host/lib/common/libs' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'storybook-host/lib/common/util' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'storybook-host/lib/components/AlignmentContainer/AlignmentContainer' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'storybook-host/lib/components/AlignmentContainer/ComponentHost.stories' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'storybook-host/lib/components/AlignmentContainer' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'storybook-host/lib/components/ComponentHost/ComponentHost' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'storybook-host/lib/components/ComponentHost/ComponentHost.stories' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'storybook-host/lib/components/ComponentHost' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'storybook-host/lib/components/CropMarks/CropMark' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'storybook-host/lib/components/CropMarks/CropMarks' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'storybook-host/lib/components/CropMarks' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'storybook-host/lib/decorators/host' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'storybook-host/lib' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'storybook-host/lib/index.test' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'storybook-host/lib/test/Foo' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'storybook-host/lib/test' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'storybook-host/lib/types' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
// Filename aliases
|
||||
declare module 'storybook-host/lib/common/alignment.js' {
|
||||
declare module.exports: $Exports<'storybook-host/lib/common/alignment'>;
|
||||
}
|
||||
declare module 'storybook-host/lib/common/color.js' {
|
||||
declare module.exports: $Exports<'storybook-host/lib/common/color'>;
|
||||
}
|
||||
declare module 'storybook-host/lib/common/css/css.js' {
|
||||
declare module.exports: $Exports<'storybook-host/lib/common/css/css'>;
|
||||
}
|
||||
declare module 'storybook-host/lib/common/css/glamor.js' {
|
||||
declare module.exports: $Exports<'storybook-host/lib/common/css/glamor'>;
|
||||
}
|
||||
declare module 'storybook-host/lib/common/css/index' {
|
||||
declare module.exports: $Exports<'storybook-host/lib/common/css'>;
|
||||
}
|
||||
declare module 'storybook-host/lib/common/css/index.js' {
|
||||
declare module.exports: $Exports<'storybook-host/lib/common/css'>;
|
||||
}
|
||||
declare module 'storybook-host/lib/common/css/test/css-flex.test.js' {
|
||||
declare module.exports: $Exports<'storybook-host/lib/common/css/test/css-flex.test'>;
|
||||
}
|
||||
declare module 'storybook-host/lib/common/css/test/css-image.test.js' {
|
||||
declare module.exports: $Exports<'storybook-host/lib/common/css/test/css-image.test'>;
|
||||
}
|
||||
declare module 'storybook-host/lib/common/css/test/css-positioning.test.js' {
|
||||
declare module.exports: $Exports<'storybook-host/lib/common/css/test/css-positioning.test'>;
|
||||
}
|
||||
declare module 'storybook-host/lib/common/css/test/css-spacing.test.js' {
|
||||
declare module.exports: $Exports<'storybook-host/lib/common/css/test/css-spacing.test'>;
|
||||
}
|
||||
declare module 'storybook-host/lib/common/css/test/css.test.js' {
|
||||
declare module.exports: $Exports<'storybook-host/lib/common/css/test/css.test'>;
|
||||
}
|
||||
declare module 'storybook-host/lib/common/css/types.js' {
|
||||
declare module.exports: $Exports<'storybook-host/lib/common/css/types'>;
|
||||
}
|
||||
declare module 'storybook-host/lib/common/index' {
|
||||
declare module.exports: $Exports<'storybook-host/lib/common'>;
|
||||
}
|
||||
declare module 'storybook-host/lib/common/index.js' {
|
||||
declare module.exports: $Exports<'storybook-host/lib/common'>;
|
||||
}
|
||||
declare module 'storybook-host/lib/common/libs.js' {
|
||||
declare module.exports: $Exports<'storybook-host/lib/common/libs'>;
|
||||
}
|
||||
declare module 'storybook-host/lib/common/util.js' {
|
||||
declare module.exports: $Exports<'storybook-host/lib/common/util'>;
|
||||
}
|
||||
declare module 'storybook-host/lib/components/AlignmentContainer/AlignmentContainer.js' {
|
||||
declare module.exports: $Exports<'storybook-host/lib/components/AlignmentContainer/AlignmentContainer'>;
|
||||
}
|
||||
declare module 'storybook-host/lib/components/AlignmentContainer/ComponentHost.stories.js' {
|
||||
declare module.exports: $Exports<'storybook-host/lib/components/AlignmentContainer/ComponentHost.stories'>;
|
||||
}
|
||||
declare module 'storybook-host/lib/components/AlignmentContainer/index' {
|
||||
declare module.exports: $Exports<'storybook-host/lib/components/AlignmentContainer'>;
|
||||
}
|
||||
declare module 'storybook-host/lib/components/AlignmentContainer/index.js' {
|
||||
declare module.exports: $Exports<'storybook-host/lib/components/AlignmentContainer'>;
|
||||
}
|
||||
declare module 'storybook-host/lib/components/ComponentHost/ComponentHost.js' {
|
||||
declare module.exports: $Exports<'storybook-host/lib/components/ComponentHost/ComponentHost'>;
|
||||
}
|
||||
declare module 'storybook-host/lib/components/ComponentHost/ComponentHost.stories.js' {
|
||||
declare module.exports: $Exports<'storybook-host/lib/components/ComponentHost/ComponentHost.stories'>;
|
||||
}
|
||||
declare module 'storybook-host/lib/components/ComponentHost/index' {
|
||||
declare module.exports: $Exports<'storybook-host/lib/components/ComponentHost'>;
|
||||
}
|
||||
declare module 'storybook-host/lib/components/ComponentHost/index.js' {
|
||||
declare module.exports: $Exports<'storybook-host/lib/components/ComponentHost'>;
|
||||
}
|
||||
declare module 'storybook-host/lib/components/CropMarks/CropMark.js' {
|
||||
declare module.exports: $Exports<'storybook-host/lib/components/CropMarks/CropMark'>;
|
||||
}
|
||||
declare module 'storybook-host/lib/components/CropMarks/CropMarks.js' {
|
||||
declare module.exports: $Exports<'storybook-host/lib/components/CropMarks/CropMarks'>;
|
||||
}
|
||||
declare module 'storybook-host/lib/components/CropMarks/index' {
|
||||
declare module.exports: $Exports<'storybook-host/lib/components/CropMarks'>;
|
||||
}
|
||||
declare module 'storybook-host/lib/components/CropMarks/index.js' {
|
||||
declare module.exports: $Exports<'storybook-host/lib/components/CropMarks'>;
|
||||
}
|
||||
declare module 'storybook-host/lib/decorators/host.js' {
|
||||
declare module.exports: $Exports<'storybook-host/lib/decorators/host'>;
|
||||
}
|
||||
declare module 'storybook-host/lib/index' {
|
||||
declare module.exports: $Exports<'storybook-host/lib'>;
|
||||
}
|
||||
declare module 'storybook-host/lib/index.js' {
|
||||
declare module.exports: $Exports<'storybook-host/lib'>;
|
||||
}
|
||||
declare module 'storybook-host/lib/index.test.js' {
|
||||
declare module.exports: $Exports<'storybook-host/lib/index.test'>;
|
||||
}
|
||||
declare module 'storybook-host/lib/test/Foo.js' {
|
||||
declare module.exports: $Exports<'storybook-host/lib/test/Foo'>;
|
||||
}
|
||||
declare module 'storybook-host/lib/test/index' {
|
||||
declare module.exports: $Exports<'storybook-host/lib/test'>;
|
||||
}
|
||||
declare module 'storybook-host/lib/test/index.js' {
|
||||
declare module.exports: $Exports<'storybook-host/lib/test'>;
|
||||
}
|
||||
declare module 'storybook-host/lib/types.js' {
|
||||
declare module.exports: $Exports<'storybook-host/lib/types'>;
|
||||
}
|
45
flow-typed/npm/storybook-router_v0.x.x.js
vendored
45
flow-typed/npm/storybook-router_v0.x.x.js
vendored
@ -1,45 +0,0 @@
|
||||
// flow-typed signature: c2d42e89f2eeb1cdff2d4d7dea9fd97b
|
||||
// flow-typed version: c6154227d1/storybook-router_v0.x.x/flow_>=v0.104.x
|
||||
|
||||
type LocationShape = {
|
||||
pathname?: string,
|
||||
search?: string,
|
||||
hash?: string,
|
||||
state?: any,
|
||||
...
|
||||
};
|
||||
|
||||
type GetUserConfirmation = (
|
||||
message: string,
|
||||
callback: (confirmed: boolean) => void
|
||||
) => void;
|
||||
|
||||
declare module "storybook-router" {
|
||||
declare type Context = {
|
||||
kind: string,
|
||||
story: string,
|
||||
...
|
||||
};
|
||||
declare type Renderable = React$Element<*>;
|
||||
declare type RenderFunction = () => Renderable | Array<Renderable>;
|
||||
|
||||
declare type StoryDecorator = (
|
||||
story: RenderFunction,
|
||||
context: Context
|
||||
) => Renderable | null;
|
||||
|
||||
declare type Links = { [key: string]: (kind: string, story: string) => Function, ... };
|
||||
|
||||
declare type RouterProps = {
|
||||
initialEntry?: Array<string>,
|
||||
autoRoute?: boolean,
|
||||
initialEntries?: Array<LocationShape | string>,
|
||||
initialIndex?: number,
|
||||
getUserConfirmation?: GetUserConfirmation,
|
||||
keyLength?: number,
|
||||
children?: React$Element<*>,
|
||||
...
|
||||
};
|
||||
|
||||
declare module.exports: { (links?: Links, routerProps?: RouterProps): StoryDecorator, ... };
|
||||
}
|
27
package.json
27
package.json
@ -18,12 +18,10 @@
|
||||
"scripts": {
|
||||
"build": "node scripts/build.js",
|
||||
"build-mainnet": "REACT_APP_NETWORK=mainnet yarn build",
|
||||
"build-storybook": "build-storybook -o build_storybook",
|
||||
"flow": "flow",
|
||||
"precommit": "./precommit.sh",
|
||||
"start": "node scripts/start.js",
|
||||
"start-mainnet": "REACT_APP_NETWORK=mainnet yarn start",
|
||||
"storybook": "start-storybook -p 6006",
|
||||
"test": "NODE_ENV=test && node scripts/test.js --env=jsdom",
|
||||
"format": "prettier-eslint \"src/**/*.js\" --write"
|
||||
},
|
||||
@ -44,8 +42,11 @@
|
||||
"bignumber.js": "9.0.0",
|
||||
"connected-react-router": "6.6.1",
|
||||
"date-fns": "2.8.1",
|
||||
"currency-flags": "^2.1.1",
|
||||
"dotenv": "^8.2.0",
|
||||
"ethereum-ens": "0.7.8",
|
||||
"final-form": "4.18.6",
|
||||
"fortmatic": "^1.0.1",
|
||||
"history": "4.10.1",
|
||||
"immortal-db": "^1.0.2",
|
||||
"immutable": "^4.0.0-rc.9",
|
||||
@ -55,7 +56,9 @@
|
||||
"optimize-css-assets-webpack-plugin": "5.0.3",
|
||||
"polished": "^3.4.2",
|
||||
"qrcode.react": "1.0.0",
|
||||
"query-string": "6.9.0",
|
||||
"react": "16.12.0",
|
||||
"react-dev-utils": "^10.0.0",
|
||||
"react-dom": "16.12.0",
|
||||
"react-final-form": "6.3.3",
|
||||
"react-final-form-listeners": "^1.0.2",
|
||||
@ -70,10 +73,9 @@
|
||||
"redux-actions": "^2.6.5",
|
||||
"redux-thunk": "^2.3.0",
|
||||
"reselect": "^4.0.0",
|
||||
"squarelink": "^1.1.3",
|
||||
"squarelink": "^1.1.4",
|
||||
"web3": "1.2.4",
|
||||
"web3connect": "^1.0.0-beta.23",
|
||||
"react-ga": "^2.7.0"
|
||||
"web3connect": "^1.0.0-beta.23"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "7.7.5",
|
||||
@ -100,12 +102,7 @@
|
||||
"@babel/preset-env": "7.7.6",
|
||||
"@babel/preset-flow": "7.7.4",
|
||||
"@babel/preset-react": "7.7.4",
|
||||
"@sambego/storybook-state": "^1.3.6",
|
||||
"@storybook/addon-actions": "5.2.8",
|
||||
"@storybook/addon-knobs": "5.2.8",
|
||||
"@storybook/addon-links": "5.2.8",
|
||||
"@storybook/react": "5.2.8",
|
||||
"@testing-library/react": "9.3.2",
|
||||
"@testing-library/react": "9.3.3",
|
||||
"autoprefixer": "9.7.3",
|
||||
"babel-core": "^7.0.0-bridge.0",
|
||||
"babel-eslint": "10.0.3",
|
||||
@ -116,9 +113,9 @@
|
||||
"babel-plugin-transform-es3-property-literals": "^6.22.0",
|
||||
"babel-polyfill": "^6.26.0",
|
||||
"classnames": "^2.2.6",
|
||||
"css-loader": "3.2.1",
|
||||
"css-loader": "3.3.0",
|
||||
"detect-port": "^1.3.0",
|
||||
"eslint": "5.16.0",
|
||||
"eslint": "6.7.2",
|
||||
"eslint-config-airbnb": "18.0.1",
|
||||
"eslint-plugin-flowtype": "4.5.2",
|
||||
"eslint-plugin-import": "2.19.1",
|
||||
@ -142,10 +139,8 @@
|
||||
"pre-commit": "^1.2.2",
|
||||
"prettier-eslint-cli": "5.0.0",
|
||||
"run-with-testrpc": "0.3.1",
|
||||
"storybook-host": "5.1.0",
|
||||
"storybook-router": "^0.3.4",
|
||||
"style-loader": "1.0.1",
|
||||
"terser-webpack-plugin": "^2.2.2",
|
||||
"terser-webpack-plugin": "2.2.3",
|
||||
"truffle": "5.1.3",
|
||||
"truffle-contract": "4.0.31",
|
||||
"truffle-solidity-loader": "0.1.32",
|
||||
|
@ -5,7 +5,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
|
||||
<title>Gnosis Safe For Teams</title>
|
||||
<title>Gnosis Safe Multisig</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
@ -57,6 +57,8 @@ git clone https://github.com/gnosis/safe-transaction-service.git
|
||||
cd safe-transaction-service
|
||||
git checkout develop
|
||||
docker-compose build
|
||||
# it comes enabled by default in docker-compose
|
||||
sudo service postgresql stop
|
||||
docker-compose up -d
|
||||
```
|
||||
Check that the service is running at https://localhost:8000
|
||||
|
@ -3,6 +3,7 @@ import React from 'react'
|
||||
import Web3Connect from 'web3connect'
|
||||
import Torus from '@toruslabs/torus-embed'
|
||||
import WalletConnectProvider from '@walletconnect/web3-provider'
|
||||
import Fortmatic from 'fortmatic'
|
||||
import Portis from '@portis/web3'
|
||||
import Squarelink from 'squarelink'
|
||||
import Button from '~/components/layout/Button'
|
||||
@ -10,8 +11,11 @@ import { fetchProvider } from '~/logic/wallets/store/actions'
|
||||
import { getNetwork } from '~/config'
|
||||
import { store } from '~/store'
|
||||
|
||||
const PORTIS_DAPP_ID = process.env.REACT_APP_NETWORK === 'mainnet' ? process.env.REACT_APP_PORTIS_ID : '852b763d-f28b-4463-80cb-846d7ec5806b'
|
||||
const SQUARELINK_CLIENT_ID = process.env.REACT_APP_NETWORK === 'mainnet' ? process.env.REACT_APP_SQUARELINK_ID : '46ce08fe50913cfa1b78'
|
||||
const isMainnet = process.env.REACT_APP_NETWORK === 'mainnet'
|
||||
|
||||
const PORTIS_DAPP_ID = isMainnet ? process.env.REACT_APP_PORTIS_ID : '852b763d-f28b-4463-80cb-846d7ec5806b'
|
||||
const SQUARELINK_CLIENT_ID = isMainnet ? process.env.REACT_APP_SQUARELINK_ID : '46ce08fe50913cfa1b78'
|
||||
const FORTMATIC_API_KEY = isMainnet ? process.env.REACT_APP_FORTMATIC_KEY : 'pk_test_CAD437AA29BE0A40'
|
||||
|
||||
export const web3Connect = new Web3Connect.Core({
|
||||
network: getNetwork().toLowerCase(),
|
||||
@ -34,6 +38,12 @@ export const web3Connect = new Web3Connect.Core({
|
||||
id: SQUARELINK_CLIENT_ID,
|
||||
},
|
||||
},
|
||||
fortmatic: {
|
||||
package: Fortmatic,
|
||||
options: {
|
||||
key: FORTMATIC_API_KEY,
|
||||
},
|
||||
},
|
||||
torus: {
|
||||
package: Torus,
|
||||
options: {
|
||||
|
@ -8,7 +8,7 @@ import { makeStyles } from '@material-ui/core/styles'
|
||||
import { useDispatch, useSelector } from 'react-redux'
|
||||
import Link from '~/components/layout/Link'
|
||||
import Button from '~/components/layout/Button'
|
||||
import { primary, mainFontFamily } from '~/theme/variables'
|
||||
import { primary, mainFontFamily, md } from '~/theme/variables'
|
||||
import type { CookiesProps } from '~/logic/cookies/model/cookie'
|
||||
import { COOKIES_KEY } from '~/logic/cookies/model/cookie'
|
||||
import { loadFromCookie, saveCookie } from '~/logic/cookies/utils'
|
||||
@ -38,7 +38,7 @@ const useStyles = makeStyles({
|
||||
text: {
|
||||
color: primary,
|
||||
fontFamily: mainFontFamily,
|
||||
fontSize: '16px',
|
||||
fontSize: md,
|
||||
fontWeight: 'normal',
|
||||
lineHeight: '1.38',
|
||||
margin: '0 0 25px',
|
||||
|
@ -13,14 +13,14 @@ const useStyles = makeStyles({
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
cursor: 'pointer',
|
||||
padding: xs,
|
||||
margin: `0 ${xs}`,
|
||||
borderRadius: '50%',
|
||||
transition: 'background-color .2s ease-in-out',
|
||||
'&:hover': {
|
||||
backgroundColor: '#F0EFEE',
|
||||
},
|
||||
},
|
||||
inreasedPopperZindex: {
|
||||
increasedPopperZindex: {
|
||||
zIndex: 2001,
|
||||
},
|
||||
})
|
||||
@ -33,7 +33,7 @@ type CopyBtnProps = {
|
||||
const CopyBtn = ({ content, increaseZindex = false }: CopyBtnProps) => {
|
||||
const [clicked, setClicked] = useState<boolean>(false)
|
||||
const classes = useStyles()
|
||||
const customClasses = increaseZindex ? { popper: classes.inreasedPopperZindex } : {}
|
||||
const customClasses = increaseZindex ? { popper: classes.increasedPopperZindex } : {}
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
|
6
src/components/EtherscanBtn/img/etherscan-open.svg
Normal file
6
src/components/EtherscanBtn/img/etherscan-open.svg
Normal file
@ -0,0 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<path fill="#B2B5B2" fill-rule="nonzero" d="M17 17v-2a1 1 0 0 1 2 0v2a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V7a2 2 0 0 1 2-2h2a1 1 0 1 1 0 2H7v10h10z"/>
|
||||
<path fill="#B2B5B2" d="M15.586 7H13a1 1 0 0 1 0-2h5a.997.997 0 0 1 1 1v5a1 1 0 0 1-2 0V8.414l-6.243 6.243a1 1 0 1 1-1.414-1.414L15.586 7z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 442 B |
@ -3,23 +3,24 @@ import React from 'react'
|
||||
import Tooltip from '@material-ui/core/Tooltip'
|
||||
import { makeStyles } from '@material-ui/core/styles'
|
||||
import Img from '~/components/layout/Img'
|
||||
import EtherscanOpenIcon from './img/etherscan-open.svg'
|
||||
import { getEtherScanLink } from '~/logic/wallets/getWeb3'
|
||||
import { xs } from '~/theme/variables'
|
||||
import SearchIcon from './search.svg'
|
||||
|
||||
const useStyles = makeStyles({
|
||||
container: {
|
||||
alignItems: 'center',
|
||||
borderRadius: '50%',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
padding: xs,
|
||||
borderRadius: '50%',
|
||||
margin: `0 ${xs}`,
|
||||
padding: '0',
|
||||
transition: 'background-color .2s ease-in-out',
|
||||
'&:hover': {
|
||||
backgroundColor: '#F0EFEE',
|
||||
},
|
||||
},
|
||||
inreasedPopperZindex: {
|
||||
increasedPopperZindex: {
|
||||
zIndex: 2001,
|
||||
},
|
||||
})
|
||||
@ -32,18 +33,18 @@ type EtherscanBtnProps = {
|
||||
|
||||
const EtherscanBtn = ({ type, value, increaseZindex = false }: EtherscanBtnProps) => {
|
||||
const classes = useStyles()
|
||||
const customClasses = increaseZindex ? { popper: classes.inreasedPopperZindex } : {}
|
||||
const customClasses = increaseZindex ? { popper: classes.increasedPopperZindex } : {}
|
||||
|
||||
return (
|
||||
<Tooltip title="Show details on Etherscan" placement="top" classes={customClasses}>
|
||||
<a
|
||||
aria-label="Show details on Etherscan"
|
||||
className={classes.container}
|
||||
href={getEtherScanLink(type, value)}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
aria-label="Show details on Etherscan"
|
||||
target="_blank"
|
||||
>
|
||||
<Img src={SearchIcon} height={20} alt="Etherscan" />
|
||||
<Img src={EtherscanOpenIcon} height={20} alt="Show on Etherscan" />
|
||||
</a>
|
||||
</Tooltip>
|
||||
)
|
||||
|
@ -1,5 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<path fill="#B2B5B2" fill-rule="nonzero" d="M18.671 17.085a1.119 1.119 0 0 1-.002 1.587 1.126 1.126 0 0 1-1.586.003l-2.68-2.68a6.6 6.6 0 1 1 .862-10.061 6.603 6.603 0 0 1 .727 8.471l2.68 2.68zm-4.923-3.335a4.455 4.455 0 0 0-6.298-6.3 4.456 4.456 0 0 0 0 6.3 4.452 4.452 0 0 0 6.298 0z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 436 B |
@ -1,25 +1,30 @@
|
||||
// @flow
|
||||
import React from 'react'
|
||||
import OpenInNew from '@material-ui/icons/OpenInNew'
|
||||
import { getEtherScanLink } from '~/logic/wallets/getWeb3'
|
||||
import { withStyles } from '@material-ui/core/styles'
|
||||
import Block from '~/components/layout/Block'
|
||||
import Paragraph from '~/components/layout/Paragraph'
|
||||
import CopyBtn from '~/components/CopyBtn'
|
||||
import EtherscanBtn from '~/components/EtherscanBtn'
|
||||
import { shortVersionOf } from '~/logic/wallets/ethAddresses'
|
||||
import { secondary } from '~/theme/variables'
|
||||
|
||||
const openIconStyle = {
|
||||
height: '13px',
|
||||
color: secondary,
|
||||
}
|
||||
import { styles } from './style.js'
|
||||
|
||||
type EtherscanLinkProps = {
|
||||
type: 'tx' | 'address',
|
||||
value: string,
|
||||
cut?: number,
|
||||
classes: Object,
|
||||
}
|
||||
|
||||
const EtherscanLink = ({ type, value }: EtherscanLinkProps) => (
|
||||
<a href={getEtherScanLink(type, value)} target="_blank" rel="noopener noreferrer">
|
||||
{shortVersionOf(value, 4)}
|
||||
<OpenInNew style={openIconStyle} />
|
||||
</a>
|
||||
const EtherscanLink = ({
|
||||
type, value, cut, classes,
|
||||
}: EtherscanLinkProps) => (
|
||||
<Block className={classes.etherscanLink}>
|
||||
<Paragraph size="md" noMargin>
|
||||
{cut ? shortVersionOf(value, cut) : value}
|
||||
</Paragraph>
|
||||
<CopyBtn content={value} />
|
||||
<EtherscanBtn type={type} value={value} />
|
||||
</Block>
|
||||
)
|
||||
|
||||
export default EtherscanLink
|
||||
export default withStyles(styles)(EtherscanLink)
|
||||
|
8
src/components/EtherscanLink/style.js
Normal file
8
src/components/EtherscanLink/style.js
Normal file
@ -0,0 +1,8 @@
|
||||
// @flow
|
||||
|
||||
export const styles = () => ({
|
||||
etherscanLink: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
},
|
||||
})
|
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 5.7 KiB |
@ -0,0 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 960 330"><title>gnosis_safe_teams_2019_logo_all_rgb</title><path d="M161,14.2A146.54,146.54,0,1,0,307.56,160.74,146.54,146.54,0,0,0,161,14.2ZM268.27,168.74h-68a41.41,41.41,0,1,1,.32-14.41h67.68a7.21,7.21,0,1,1,0,14.41Z"/><path d="M347.28,203.9h9.86l29.27,51.46h.22l29.26-51.46h9.76v79.6h-9.76V222.84h-.22l-25.9,44.62h-6.62l-25.89-44.62h-.12V283.5h-9.86Z"/><path d="M442.8,261.41V228.9h9.08v29.93c0,12.33,4.71,17,13.34,17s16.26-7.51,16.26-20.51V228.9h9.08v54.6h-9.08v-9.42h-.11a21.28,21.28,0,0,1-18.05,10.09C450.76,284.17,442.8,277,442.8,261.41Z"/><path d="M507.71,201h9.08V283.5h-9.08Z"/><path d="M535.74,267.24V236.75h-7.06V228.9h7.06V210.29l9.08-1V228.9h18v7.85h-18V265.9c0,6.61,1.46,9.75,6.62,9.75a20.58,20.58,0,0,0,9.3-2.8l2.36,8c-3,1.79-6.73,3.36-13.23,3.36C540.22,284.17,535.74,278.23,535.74,267.24Z"/><path d="M573.3,212.42a6.62,6.62,0,1,1,6.61,6.5A6.53,6.53,0,0,1,573.3,212.42Zm2,16.48h9.08v54.6h-9.08Z"/><path d="M597.29,276.43l4.6-6.95c4.26,4.15,9.08,6.62,16.7,6.62,6.62,0,10.43-3.25,10.43-7.4,0-4.82-5-6.17-13-9.08-8.85-3.14-16.36-6.73-16.36-16.71,0-8.41,7.62-14.68,17.93-14.68A28.46,28.46,0,0,1,636.42,235l-4.71,7.18a20.61,20.61,0,0,0-14.46-5.83c-4.26,0-8.41,2.46-8.41,6.61s4.37,6.39,10.31,8.52c11.55,4.49,19.17,6.51,19.06,17.16,0,8.52-6.5,15.58-19.62,15.58A31.37,31.37,0,0,1,597.29,276.43Z"/><path d="M649.76,212.42a6.62,6.62,0,1,1,6.61,6.5A6.53,6.53,0,0,1,649.76,212.42Zm2,16.48h9.08v54.6h-9.08Z"/><path d="M680.48,300.43l2.24-8.08c6.28,3.59,11.77,5.72,19.62,5.72,12.33,0,18.27-7.17,18.27-16.37V273h-.22c-4,5.83-10.54,9.53-18.95,9.53-14.91,0-26.46-10.76-26.46-27,0-15.58,10.77-27.24,26.13-27.24a23.6,23.6,0,0,1,19.17,9.41h.22V228.9h9.08v50.56c0,15.7-7.85,26.91-26.9,26.91A42.46,42.46,0,0,1,680.48,300.43ZM720.84,255c0-11-8-18.39-18.16-18.39-11.1,0-18.5,8-18.5,18.61,0,11.55,8.07,18.84,18.38,18.84C713.55,274.08,720.84,265.9,720.84,255Z"/><path d="M341.67,132.53c0-23.1,14.91-41,40.36-41,11.55,0,24.11,4.82,32.29,14.24l-13.23,11.21A26.79,26.79,0,0,0,382,109.09c-11.32,0-20.74,8.64-20.74,23.44,0,12.89,8,23.43,21.53,23.43a27.69,27.69,0,0,0,13.79-3.48v-9.42H381.14V127.59h33.41v35.77c-7.29,5.6-19.4,9.75-31.73,9.75C359.84,173.11,341.67,158.42,341.67,132.53Z"/><path d="M426.09,117.39h17.49v6.39h.23a21.26,21.26,0,0,1,16.48-7.4c11.32,0,19.62,5.61,19.62,23v32.84H462.42V143.63c0-9.09-3-11.66-8.75-11.66-6.05,0-10.09,4.14-10.09,12.66v27.58H426.09Z"/><path d="M488.65,144.86c0-16.71,12-28.48,29.71-28.48,17.27,0,29.6,11.55,29.6,28.48s-12.33,28.36-29.6,28.36C500.65,173.22,488.65,161.45,488.65,144.86Zm41.6,0c0-7.63-5-12.89-11.89-12.89-7.06,0-12,5.38-12,12.89,0,7.29,5,12.89,12,12.89C525,157.75,530.25,152.37,530.25,144.86Z"/><path d="M553.12,165.15l8.18-11.32c4.6,4.15,9.31,6.16,14.35,6.16,3.48,0,5.27-1.23,5.27-3.25,0-1.79-1.68-2.91-8.52-5-9.2-2.81-17.27-7.29-17.27-17.83,0-11.1,9.09-17.49,20.52-17.49a32.3,32.3,0,0,1,20.74,6.84l-8.3,12.22c-3.81-3.81-8.52-5.72-12.22-5.72-2,0-4.37.9-4.37,3,0,1.68,2,2.92,7.51,4.82,12.11,4.15,18.73,7.29,18.73,18.05,0,10.2-7.29,17.6-22.31,17.6C566.79,173.22,559.17,170.53,553.12,165.15Z"/><path d="M605.58,100.46c0-5.38,4.38-9.86,10.43-9.86s10.54,4.37,10.54,9.86c0,5.72-4.49,10.09-10.54,10.09S605.58,106.18,605.58,100.46Zm1.69,16.93h17.48v54.82H607.27Z"/><path d="M633.16,165.15l8.19-11.32c4.59,4.15,9.3,6.16,14.35,6.16,3.47,0,5.27-1.23,5.27-3.25,0-1.79-1.69-2.91-8.52-5-9.2-2.81-17.27-7.29-17.27-17.83,0-11.1,9.08-17.49,20.52-17.49a32.31,32.31,0,0,1,20.74,6.84l-8.3,12.22c-3.81-3.81-8.52-5.72-12.22-5.72-2,0-4.37.9-4.37,3,0,1.68,2,2.92,7.51,4.82,12.11,4.15,18.72,7.29,18.72,18.05,0,10.2-7.28,17.6-22.31,17.6C646.84,173.22,639.22,170.53,633.16,165.15Z"/><path d="M710,160.55l11-13.34c6.06,6.62,13.35,9.42,18.84,9.42,6.28,0,9-3.14,9-6.73,0-4.37-2.8-6.27-11.77-9.3-12.11-4.15-24.22-9.87-24.22-25.56,0-13.23,11.32-23.21,26.12-23.44,10.43-.22,20,3.82,27.58,10.32L755.92,115.6c-6.84-5.38-11.77-7.51-16.25-7.51s-7.4,2.35-7.4,6.16,2.8,5.83,11.43,9.19c14,5.39,24.78,9,24.78,24.33,0,18.73-16,25.45-29.26,25.45A40.52,40.52,0,0,1,710,160.55Z"/><path d="M774.87,144.86c0-16.82,10.87-28.48,25-28.48A19.66,19.66,0,0,1,815,123.22l.22-.11v-5.72h17.6v54.82h-16.7V166.5l-.23-.12c-3.58,4.6-8.52,6.84-15.13,6.84C785.74,173.22,774.87,161.79,774.87,144.86Zm41.15,0c0-7.51-5-13-11.55-13-6.73,0-11.77,5.16-11.77,13s4.82,12.89,11.77,12.89C810.75,157.75,816,152.71,816,144.86Z"/><path d="M846.51,131.52h-5.27V117.39h5.27v-8.63c0-13.57,7.06-20.18,18-20.18a27.42,27.42,0,0,1,14.8,4.26l-3.25,12.67a17.51,17.51,0,0,0-6.84-2c-3.14,0-5.16,1.57-5.16,5.94v8h10.43v14.13H864.11v40.69h-17.6Z"/><path d="M932.84,149.45H895.5c1.12,6.28,6.39,9.53,13.12,9.53A17.29,17.29,0,0,0,921.4,153l10.09,10.32c-4.6,5.72-12.22,9.86-24.66,9.86-16.6,0-28.71-11.43-28.71-28.47,0-16.6,11.66-28.37,28.26-28.37,15.47,0,26.79,11.55,26.79,27.81C933.17,145.76,933,148.33,932.84,149.45ZM895.62,139h20.51c-1.12-5.38-4.71-8.75-10-8.75S896.74,133.54,895.62,139Z"/></svg>
|
After Width: | Height: | Size: 4.8 KiB |
@ -16,15 +16,15 @@ import {
|
||||
border, sm, md, headerHeight,
|
||||
} from '~/theme/variables'
|
||||
import Provider from './Provider'
|
||||
import EarlyAccessLabel from './EarlyAccessLabel'
|
||||
import NetworkLabel from './NetworkLabel'
|
||||
import SafeListHeader from './SafeListHeader'
|
||||
|
||||
const logo = require('../assets/gnosis-safe-logo.svg')
|
||||
const logo = require('../assets/gnosis-safe-multisig-logo.svg')
|
||||
|
||||
type Props = Open & {
|
||||
classes: Object,
|
||||
providerDetails: React.Node,
|
||||
providerInfo: React.Node,
|
||||
providerInfo: React.Node
|
||||
}
|
||||
|
||||
const styles = () => ({
|
||||
@ -33,7 +33,7 @@ const styles = () => ({
|
||||
padding: 0,
|
||||
boxShadow: '0 0 10px 0 rgba(33, 48, 77, 0.1)',
|
||||
minWidth: '280px',
|
||||
borderRadius: '8px',
|
||||
borderRadius: sm,
|
||||
marginTop: '11px',
|
||||
},
|
||||
summary: {
|
||||
@ -43,6 +43,8 @@ const styles = () => ({
|
||||
boxShadow: '0 2px 4px 0 rgba(212, 212, 211, 0.59)',
|
||||
backgroundColor: 'white',
|
||||
zIndex: 1301,
|
||||
position: 'fixed',
|
||||
width: '100%',
|
||||
},
|
||||
logo: {
|
||||
padding: `${sm} ${md}`,
|
||||
@ -54,10 +56,15 @@ const styles = () => ({
|
||||
},
|
||||
})
|
||||
|
||||
const Layout = openHoc(({
|
||||
open, toggle, clickAway, classes, providerInfo, providerDetails,
|
||||
}: Props) => (
|
||||
<>
|
||||
const Layout = openHoc(
|
||||
({
|
||||
open,
|
||||
toggle,
|
||||
clickAway,
|
||||
classes,
|
||||
providerInfo,
|
||||
providerDetails,
|
||||
}: Props) => (
|
||||
<Row className={classes.summary}>
|
||||
<Col start="xs" middle="xs" className={classes.logo}>
|
||||
<Link to="/">
|
||||
@ -67,15 +74,25 @@ const Layout = openHoc(({
|
||||
<Divider />
|
||||
<SafeListHeader />
|
||||
<Divider />
|
||||
<EarlyAccessLabel />
|
||||
<NetworkLabel />
|
||||
<Spacer />
|
||||
<Provider open={open} toggle={toggle} info={providerInfo}>
|
||||
{(providerRef) => (
|
||||
<Popper open={open} anchorEl={providerRef.current} placement="bottom" className={classes.popper}>
|
||||
<Popper
|
||||
open={open}
|
||||
anchorEl={providerRef.current}
|
||||
placement="bottom"
|
||||
className={classes.popper}
|
||||
popperOptions={{ positionFixed: true }}
|
||||
>
|
||||
{({ TransitionProps }) => (
|
||||
<Grow {...TransitionProps}>
|
||||
<>
|
||||
<ClickAwayListener onClickAway={clickAway} mouseEvent="onClick" touchEvent={false}>
|
||||
<ClickAwayListener
|
||||
onClickAway={clickAway}
|
||||
mouseEvent="onClick"
|
||||
touchEvent={false}
|
||||
>
|
||||
<List className={classes.root} component="div">
|
||||
{providerDetails}
|
||||
</List>
|
||||
@ -87,7 +104,7 @@ const Layout = openHoc(({
|
||||
)}
|
||||
</Provider>
|
||||
</Row>
|
||||
</>
|
||||
))
|
||||
),
|
||||
)
|
||||
|
||||
export default withStyles(styles)(Layout)
|
||||
|
@ -1,38 +0,0 @@
|
||||
// @flow
|
||||
import { storiesOf } from '@storybook/react'
|
||||
import * as React from 'react'
|
||||
import styles from '~/components/layout/PageFrame/index.scss'
|
||||
import Layout from './Layout'
|
||||
import ProviderAccesible from './ProviderInfo/ProviderAccesible'
|
||||
import UserDetails from './ProviderDetails/UserDetails'
|
||||
import ProviderDisconnected from './ProviderInfo/ProviderDisconnected'
|
||||
import ConnectDetails from './ProviderDetails/ConnectDetails'
|
||||
|
||||
const FrameDecorator = (story) => <div className={styles.frame}>{story()}</div>
|
||||
|
||||
storiesOf('Components /Header', module)
|
||||
.addDecorator(FrameDecorator)
|
||||
.add('Connected', () => {
|
||||
const provider = 'Metamask'
|
||||
const userAddress = '0x873faa4cddd5b157e8e5a57e7a5479afc5d30moe'
|
||||
const network = 'RINKEBY'
|
||||
const info = <ProviderAccesible provider={provider} network={network} userAddress={userAddress} connected />
|
||||
const details = <UserDetails provider={provider} network={network} userAddress={userAddress} connected />
|
||||
|
||||
return <Layout providerInfo={info} providerDetails={details} />
|
||||
})
|
||||
.add('Disconnected', () => {
|
||||
const info = <ProviderDisconnected />
|
||||
const details = <ConnectDetails />
|
||||
|
||||
return <Layout providerInfo={info} providerDetails={details} />
|
||||
})
|
||||
.add('Connection Error', () => {
|
||||
const provider = 'Metamask'
|
||||
const userAddress = '0x873faa4cddd5b157e8e5a57e7a5479afc5d30moe'
|
||||
const network = 'RINKEBY'
|
||||
const info = <ProviderAccesible provider={provider} network={network} userAddress={userAddress} connected={false} />
|
||||
const details = <UserDetails provider={provider} network={network} userAddress={userAddress} connected={false} />
|
||||
|
||||
return <Layout providerInfo={info} providerDetails={details} />
|
||||
})
|
@ -1,20 +1,22 @@
|
||||
// @flow
|
||||
import * as React from 'react'
|
||||
import { makeStyles } from '@material-ui/core/styles'
|
||||
import { getNetwork } from '~/config'
|
||||
import Paragraph from '~/components/layout/Paragraph'
|
||||
import Col from '~/components/layout/Col'
|
||||
import {
|
||||
xs, sm, md, border,
|
||||
} from '~/theme/variables'
|
||||
|
||||
export const TOGGLE_SIDEBAR_BTN_TESTID = 'TOGGLE_SIDEBAR_BTN'
|
||||
const network = getNetwork()
|
||||
const formattedNetwork = network[0].toUpperCase() + network.substring(1).toLowerCase()
|
||||
|
||||
const useStyles = makeStyles({
|
||||
container: {
|
||||
flexGrow: 0,
|
||||
padding: `0 ${md}`,
|
||||
},
|
||||
counter: {
|
||||
text: {
|
||||
background: border,
|
||||
padding: `${xs} ${sm}`,
|
||||
borderRadius: '3px',
|
||||
@ -28,8 +30,8 @@ const EarlyAccessLabel = () => {
|
||||
|
||||
return (
|
||||
<Col start="xs" middle="xs" className={classes.container}>
|
||||
<Paragraph size="xs" className={classes.counter}>
|
||||
Early access
|
||||
<Paragraph size="xs" className={classes.text}>
|
||||
{formattedNetwork}
|
||||
</Paragraph>
|
||||
</Col>
|
||||
)
|
@ -1,11 +0,0 @@
|
||||
// @flow
|
||||
import { storiesOf } from '@storybook/react'
|
||||
import * as React from 'react'
|
||||
import styles from '~/components/layout/PageFrame/index.scss'
|
||||
import Component from './index'
|
||||
|
||||
const FrameDecorator = (story) => <div className={styles.frame}>{story()}</div>
|
||||
|
||||
storiesOf('Components', module)
|
||||
.addDecorator(FrameDecorator)
|
||||
.add('Loader', () => <Component />)
|
@ -3,6 +3,7 @@ import * as React from 'react'
|
||||
import cn from 'classnames'
|
||||
import Modal from '@material-ui/core/Modal'
|
||||
import { withStyles } from '@material-ui/core/styles'
|
||||
import { sm } from '~/theme/variables'
|
||||
|
||||
type Props = {
|
||||
title: string,
|
||||
@ -27,7 +28,7 @@ const styles = () => ({
|
||||
top: '120px',
|
||||
width: '500px',
|
||||
height: '530px',
|
||||
borderRadius: '8px',
|
||||
borderRadius: sm,
|
||||
backgroundColor: '#ffffff',
|
||||
boxShadow: '0 0 5px 0 rgba(74, 85, 121, 0.5)',
|
||||
'&:focus': {
|
||||
|
@ -16,6 +16,7 @@ export type Column = {
|
||||
custom: boolean, // If content will be rendered by user manually
|
||||
width?: number,
|
||||
static?: boolean, // If content can't be sorted by values in the column
|
||||
style?: Object, // if you want to add some custom styling to the column
|
||||
}
|
||||
|
||||
export const cellWidth = (width: number | typeof undefined) => {
|
||||
@ -56,12 +57,15 @@ class GnoTableHead extends React.PureComponent<Props> {
|
||||
sortDirection={orderBy === column.id ? order : false}
|
||||
>
|
||||
{column.static ? (
|
||||
column.label
|
||||
<div style={column.style}>
|
||||
{column.label}
|
||||
</div>
|
||||
) : (
|
||||
<TableSortLabel
|
||||
active={orderBy === column.id}
|
||||
direction={order}
|
||||
onClick={this.changeSort(column.id, column.order)}
|
||||
style={column.style}
|
||||
>
|
||||
{column.label}
|
||||
</TableSortLabel>
|
||||
|
@ -1,6 +1,5 @@
|
||||
// @flow
|
||||
import * as React from 'react'
|
||||
import classNames from 'classnames'
|
||||
import { List } from 'immutable'
|
||||
import Table from '@material-ui/core/Table'
|
||||
import TableBody from '@material-ui/core/TableBody'
|
||||
@ -10,7 +9,7 @@ import TablePagination from '@material-ui/core/TablePagination'
|
||||
import Row from '~/components/layout/Row'
|
||||
import { type Order, stableSort, getSorting } from '~/components/Table/sorting'
|
||||
import TableHead, { type Column } from '~/components/Table/TableHead'
|
||||
import { xl } from '~/theme/variables'
|
||||
import { xxl, xl, sm } from '~/theme/variables'
|
||||
|
||||
type Props<K> = {
|
||||
label: string,
|
||||
@ -39,11 +38,12 @@ type State = {
|
||||
const styles = {
|
||||
root: {
|
||||
backgroundColor: 'white',
|
||||
borderRadius: '8px',
|
||||
borderTopRightRadius: sm,
|
||||
borderTopLeftRadius: sm,
|
||||
boxShadow: '1px 2px 10px 0 rgba(212, 212, 211, 0.59)',
|
||||
},
|
||||
selectRoot: {
|
||||
lineHeight: '40px',
|
||||
lineHeight: xxl,
|
||||
backgroundColor: 'white',
|
||||
},
|
||||
white: {
|
||||
@ -53,14 +53,11 @@ const styles = {
|
||||
backgroundColor: 'white',
|
||||
boxShadow: '1px 2px 10px 0 rgba(212, 212, 211, 0.59)',
|
||||
marginBottom: xl,
|
||||
borderRadius: '8px',
|
||||
borderTopLeftRadius: 0,
|
||||
borderTopRightRadius: 0,
|
||||
borderBottomRightRadius: sm,
|
||||
borderBottomLeftRadius: sm,
|
||||
},
|
||||
loader: {
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
backgroundColor: 'white',
|
||||
boxShadow: '1px 2px 10px 0 rgba(212, 212, 211, 0.59)',
|
||||
},
|
||||
}
|
||||
|
||||
@ -125,6 +122,13 @@ class GnoTable<K> extends React.Component<Props<K>, State> {
|
||||
|
||||
getEmptyStyle = (emptyRows: number) => ({
|
||||
height: FIXED_HEIGHT * emptyRows,
|
||||
borderTopRightRadius: sm,
|
||||
borderTopLeftRadius: sm,
|
||||
backgroundColor: 'white',
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
})
|
||||
|
||||
handleChangePage = (e: SyntheticInputEvent<HTMLInputElement>, page: number) => {
|
||||
@ -171,7 +175,7 @@ class GnoTable<K> extends React.Component<Props<K>, State> {
|
||||
sortedData = sortedData.slice(page * displayRows, page * displayRows + displayRows)
|
||||
}
|
||||
|
||||
const emptyRows = displayRows - Math.min(displayRows, data.length - page * displayRows)
|
||||
const emptyRows = displayRows - Math.min(displayRows, data.size - page * displayRows)
|
||||
const isEmpty = size === 0
|
||||
|
||||
return (
|
||||
@ -184,7 +188,7 @@ class GnoTable<K> extends React.Component<Props<K>, State> {
|
||||
)}
|
||||
{isEmpty && (
|
||||
<Row
|
||||
className={classNames(classes.loader, !noBorder && classes.root)}
|
||||
className={classes.loader}
|
||||
style={this.getEmptyStyle(emptyRows + 1)}
|
||||
>
|
||||
<CircularProgress size={60} />
|
||||
|
@ -19,6 +19,7 @@ type Props = {
|
||||
testId?: string,
|
||||
validators?: Function[],
|
||||
inputAdornment?: React.Element,
|
||||
defaultValue?: string,
|
||||
}
|
||||
|
||||
const isValidEnsName = (name) => /^([\w-]+\.)+(eth|test|xyz|luxe)$/.test(name)
|
||||
@ -35,6 +36,7 @@ const AddressInput = ({
|
||||
testId,
|
||||
inputAdornment,
|
||||
validators = [],
|
||||
defaultValue,
|
||||
}: Props): React.Element<*> => (
|
||||
<>
|
||||
<Field
|
||||
@ -51,6 +53,7 @@ const AddressInput = ({
|
||||
text={text}
|
||||
className={className}
|
||||
testId={testId}
|
||||
defaultValue={defaultValue}
|
||||
/>
|
||||
<OnChange name={name}>
|
||||
{async (value) => {
|
||||
|
@ -13,7 +13,7 @@ type Props = {
|
||||
margin?: Size,
|
||||
padding?: Size,
|
||||
justify?: 'center' | 'right' | 'left' | 'space-around',
|
||||
children: React.Node,
|
||||
children?: React.Node,
|
||||
className?: string,
|
||||
}
|
||||
|
||||
|
@ -1,16 +0,0 @@
|
||||
// @flow
|
||||
import { storiesOf } from '@storybook/react'
|
||||
import * as React from 'react'
|
||||
import { host } from 'storybook-host'
|
||||
import Component from './index'
|
||||
|
||||
storiesOf('Components', module)
|
||||
.addDecorator(
|
||||
host({
|
||||
title: 'Hairline',
|
||||
align: 'center',
|
||||
height: 5,
|
||||
width: '100%',
|
||||
}),
|
||||
)
|
||||
.add('Hairline', () => <Component />)
|
@ -2,12 +2,12 @@
|
||||
display: flex;
|
||||
flex: 1 0 auto;
|
||||
flex-direction: column;
|
||||
padding: 80px 200px 0px 200px;
|
||||
padding: 135px 200px 0px 200px;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: $(screenLg)px) {
|
||||
.page {
|
||||
padding: 80px $lg 0px $lg;
|
||||
padding: 135px $lg 0px $lg;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@ import ErrorIcon from './assets/error.svg'
|
||||
import InfoIcon from './assets/info.svg'
|
||||
import CookiesBanner from '~/components/CookiesBanner'
|
||||
import styles from './index.scss'
|
||||
import { fontColor } from '~/theme/variables'
|
||||
|
||||
const notificationStyles = {
|
||||
success: {
|
||||
@ -24,7 +25,7 @@ const notificationStyles = {
|
||||
fontFamily: 'Averta',
|
||||
fontSize: '14px',
|
||||
lineHeight: 1.43,
|
||||
color: '#001428',
|
||||
color: fontColor,
|
||||
minHeight: '58px',
|
||||
boxShadow: '0 0 10px 0 rgba(212, 212, 211, 0.59)',
|
||||
},
|
||||
@ -33,7 +34,7 @@ const notificationStyles = {
|
||||
fontFamily: 'Averta',
|
||||
fontSize: '14px',
|
||||
lineHeight: 1.43,
|
||||
color: '#001428',
|
||||
color: fontColor,
|
||||
minHeight: '58px',
|
||||
boxShadow: '0 0 10px 0 rgba(212, 212, 211, 0.59)',
|
||||
},
|
||||
@ -42,7 +43,7 @@ const notificationStyles = {
|
||||
fontFamily: 'Averta',
|
||||
fontSize: '14px',
|
||||
lineHeight: 1.43,
|
||||
color: '#001428',
|
||||
color: fontColor,
|
||||
minHeight: '58px',
|
||||
boxShadow: '0 0 10px 0 rgba(212, 212, 211, 0.59)',
|
||||
},
|
||||
@ -51,7 +52,7 @@ const notificationStyles = {
|
||||
fontFamily: 'Averta',
|
||||
fontSize: '14px',
|
||||
lineHeight: 1.43,
|
||||
color: '#001428',
|
||||
color: fontColor,
|
||||
minHeight: '58px',
|
||||
boxShadow: '0 0 10px 0 rgba(212, 212, 211, 0.59)',
|
||||
},
|
||||
|
@ -52,6 +52,9 @@ export const getTxServiceHost = () => {
|
||||
export const getTxServiceUriFrom = (safeAddress: string) =>
|
||||
`safes/${safeAddress}/transactions/`
|
||||
|
||||
export const getIncomingTxServiceUriTo = (safeAddress: string) =>
|
||||
`safes/${safeAddress}/incoming-transactions/`
|
||||
|
||||
export const getRelayUrl = () => getConfig()[RELAY_API_URL]
|
||||
|
||||
export const signaturesViaMetamask = () => {
|
||||
@ -69,3 +72,5 @@ export const getIntercomId = () =>
|
||||
process.env.REACT_APP_ENV === "production"
|
||||
? process.env.REACT_APP_INTERCOM_ID
|
||||
: "plssl1fl"
|
||||
|
||||
export const getExchangeRatesUrl = () => 'https://api.exchangeratesapi.io/latest'
|
||||
|
@ -8,6 +8,7 @@ import loadActiveTokens from '~/logic/tokens/store/actions/loadActiveTokens'
|
||||
import loadDefaultSafe from '~/routes/safe/store/actions/loadDefaultSafe'
|
||||
import loadSafesFromStorage from '~/routes/safe/store/actions/loadSafesFromStorage'
|
||||
import { store } from '~/store'
|
||||
import verifyRecurringUser from '~/utils/verifyRecurringUser'
|
||||
|
||||
BigNumber.set({ EXPONENTIAL_AT: [-7, 255] })
|
||||
|
||||
@ -21,6 +22,7 @@ if (process.env.NODE_ENV !== 'production') {
|
||||
store.dispatch(loadActiveTokens())
|
||||
store.dispatch(loadSafesFromStorage())
|
||||
store.dispatch(loadDefaultSafe())
|
||||
verifyRecurringUser()
|
||||
|
||||
const root = document.getElementById('root')
|
||||
|
||||
|
@ -55,7 +55,7 @@ export const decodeParamsFromSafeMethod = async (data: string) => {
|
||||
case '0xe318b52b':
|
||||
return {
|
||||
methodName: METHOD_TO_ID[methodId],
|
||||
args: web3.eth.abi.decodeParameters(['address', 'address', 'address'], params),
|
||||
args: web3.eth.abi.decodeParameters(['uint', 'address', 'address'], params),
|
||||
}
|
||||
|
||||
// addOwnerWithThreshold
|
||||
|
19
src/logic/currencyValues/api/fetchCurrenciesRates.js
Normal file
19
src/logic/currencyValues/api/fetchCurrenciesRates.js
Normal file
@ -0,0 +1,19 @@
|
||||
// @flow
|
||||
import axios from 'axios'
|
||||
import { getExchangeRatesUrl } from '~/config'
|
||||
import { AVAILABLE_CURRENCIES } from '~/logic/currencyValues/store/model/currencyValues'
|
||||
|
||||
const fetchCurrenciesRates = async (baseCurrency: AVAILABLE_CURRENCIES, targetCurrencyValue: AVAILABLE_CURRENCIES): Promise<number> => {
|
||||
let rate = 0
|
||||
const url = `${getExchangeRatesUrl()}?base=${baseCurrency}&symbols=${targetCurrencyValue}`
|
||||
|
||||
const result = await axios.get(url)
|
||||
if (result && result.data) {
|
||||
const { rates } = result.data
|
||||
rate = rates[targetCurrencyValue] ? rates[targetCurrencyValue] : 0
|
||||
}
|
||||
|
||||
return rate
|
||||
}
|
||||
|
||||
export default fetchCurrenciesRates
|
15
src/logic/currencyValues/api/fetchTokenCurrenciesBalances.js
Normal file
15
src/logic/currencyValues/api/fetchTokenCurrenciesBalances.js
Normal file
@ -0,0 +1,15 @@
|
||||
// @flow
|
||||
import axios from 'axios'
|
||||
import { getTxServiceHost } from '~/config'
|
||||
|
||||
const fetchTokenCurrenciesBalances = (safeAddress: string) => {
|
||||
if (!safeAddress) {
|
||||
return null
|
||||
}
|
||||
const apiUrl = getTxServiceHost()
|
||||
const url = `${apiUrl}safes/${safeAddress}/balances/usd`
|
||||
|
||||
return axios.get(url)
|
||||
}
|
||||
|
||||
export default fetchTokenCurrenciesBalances
|
@ -0,0 +1,35 @@
|
||||
// @flow
|
||||
import { Dispatch as ReduxDispatch } from 'redux'
|
||||
import { List } from 'immutable'
|
||||
import type { GlobalState } from '~/store'
|
||||
import { AVAILABLE_CURRENCIES } from '~/logic/currencyValues/store/model/currencyValues'
|
||||
import fetchCurrenciesRates from '~/logic/currencyValues/api/fetchCurrenciesRates'
|
||||
import { currencyValuesListSelector } from '~/logic/currencyValues/store/selectors'
|
||||
import { setCurrencyBalances } from '~/logic/currencyValues/store/actions/setCurrencyBalances'
|
||||
|
||||
|
||||
// eslint-disable-next-line max-len
|
||||
const fetchCurrencySelectedValue = (currencyValueSelected: AVAILABLE_CURRENCIES) => async (dispatch: ReduxDispatch<GlobalState>, getState: Function) => {
|
||||
const state = getState()
|
||||
const currencyBalancesList = currencyValuesListSelector(state)
|
||||
const selectedCurrencyRateInBaseCurrency = await fetchCurrenciesRates(AVAILABLE_CURRENCIES.USD, currencyValueSelected)
|
||||
|
||||
|
||||
const newList = []
|
||||
for (const currencyValue of currencyBalancesList) {
|
||||
const { balanceInBaseCurrency } = currencyValue
|
||||
|
||||
const balanceInSelectedCurrency = balanceInBaseCurrency * selectedCurrencyRateInBaseCurrency
|
||||
|
||||
const updatedValue = currencyValue.merge({
|
||||
currencyName: currencyValueSelected,
|
||||
balanceInSelectedCurrency,
|
||||
})
|
||||
|
||||
newList.push(updatedValue)
|
||||
}
|
||||
|
||||
dispatch(setCurrencyBalances(List(newList)))
|
||||
}
|
||||
|
||||
export default fetchCurrencySelectedValue
|
@ -0,0 +1,43 @@
|
||||
// @flow
|
||||
import type { Dispatch as ReduxDispatch } from 'redux'
|
||||
import { List } from 'immutable'
|
||||
import type { GlobalState } from '~/store'
|
||||
import { setCurrencyBalances } from '~/logic/currencyValues/store/actions/setCurrencyBalances'
|
||||
import { AVAILABLE_CURRENCIES, makeBalanceCurrency } from '~/logic/currencyValues/store/model/currencyValues'
|
||||
import { setCurrencySelected } from '~/logic/currencyValues/store/actions/setCurrencySelected'
|
||||
import fetchTokenCurrenciesBalances from '~/logic/currencyValues/api/fetchTokenCurrenciesBalances'
|
||||
import { loadFromStorage } from '~/utils/storage'
|
||||
import fetchCurrencySelectedValue from '~/logic/currencyValues/store/actions/fetchCurrencySelectedValue'
|
||||
import { CURRENCY_SELECTED_KEY } from '~/logic/currencyValues/store/actions/saveCurrencySelected'
|
||||
|
||||
|
||||
export const fetchCurrencyValues = (safeAddress: string) => async (dispatch: ReduxDispatch<GlobalState>) => {
|
||||
try {
|
||||
const tokensFetched = await fetchTokenCurrenciesBalances(safeAddress)
|
||||
|
||||
// eslint-disable-next-line max-len
|
||||
const currencyList = List(tokensFetched.data.filter((currencyBalance) => currencyBalance.balanceUsd).map((currencyBalance) => {
|
||||
const { balanceUsd, tokenAddress } = currencyBalance
|
||||
return makeBalanceCurrency({
|
||||
currencyName: balanceUsd ? AVAILABLE_CURRENCIES.USD : null,
|
||||
tokenAddress,
|
||||
balanceInBaseCurrency: balanceUsd,
|
||||
balanceInSelectedCurrency: balanceUsd,
|
||||
})
|
||||
}))
|
||||
|
||||
dispatch(setCurrencyBalances(currencyList))
|
||||
const currencyStored = await loadFromStorage(CURRENCY_SELECTED_KEY)
|
||||
if (!currencyStored) {
|
||||
return dispatch(setCurrencySelected(AVAILABLE_CURRENCIES.USD))
|
||||
}
|
||||
const { currencyValueSelected } = currencyStored
|
||||
dispatch(fetchCurrencySelectedValue(currencyValueSelected))
|
||||
dispatch(setCurrencySelected(currencyValueSelected))
|
||||
} catch (err) {
|
||||
console.error('Error fetching tokens price list', err)
|
||||
}
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
export default fetchCurrencyValues
|
@ -0,0 +1,18 @@
|
||||
// @flow
|
||||
|
||||
import { Dispatch as ReduxDispatch } from 'redux'
|
||||
import { AVAILABLE_CURRENCIES } from '~/logic/currencyValues/store/model/currencyValues'
|
||||
import type { GlobalState } from '~/store'
|
||||
|
||||
import { saveToStorage } from '~/utils/storage'
|
||||
import { setCurrencySelected } from '~/logic/currencyValues/store/actions/setCurrencySelected'
|
||||
|
||||
|
||||
export const CURRENCY_SELECTED_KEY = 'CURRENCY_SELECTED_KEY'
|
||||
|
||||
const saveCurrencySelected = (currencySelected: AVAILABLE_CURRENCIES) => async (dispatch: ReduxDispatch<GlobalState>) => {
|
||||
await saveToStorage(CURRENCY_SELECTED_KEY, { currencyValueSelected: currencySelected })
|
||||
dispatch(setCurrencySelected(currencySelected))
|
||||
}
|
||||
|
||||
export default saveCurrencySelected
|
@ -0,0 +1,10 @@
|
||||
// @flow
|
||||
import { Map } from 'immutable'
|
||||
import { createAction } from 'redux-actions'
|
||||
import type { CurrencyValues, CurrencyValuesProps } from '~/logic/currencyValues/store/model/currencyValues'
|
||||
|
||||
export const SET_CURRENCY_BALANCES = 'SET_CURRENCY_BALANCES'
|
||||
|
||||
|
||||
// eslint-disable-next-line max-len
|
||||
export const setCurrencyBalances = createAction<string, *>(SET_CURRENCY_BALANCES, (currencyBalances: Map<string, CurrencyValues>): CurrencyValuesProps => ({ currencyBalances }))
|
@ -0,0 +1,13 @@
|
||||
// @flow
|
||||
import { createAction } from 'redux-actions'
|
||||
import type {
|
||||
CurrencyValuesProps,
|
||||
} from '~/logic/currencyValues/store/model/currencyValues'
|
||||
import { AVAILABLE_CURRENCIES } from '~/logic/currencyValues/store/model/currencyValues'
|
||||
|
||||
|
||||
export const SET_CURRENT_CURRENCY = 'SET_CURRENT_CURRENCY'
|
||||
|
||||
|
||||
// eslint-disable-next-line max-len
|
||||
export const setCurrencySelected = createAction<string, *>(SET_CURRENT_CURRENCY, (currencyValueSelected: AVAILABLE_CURRENCIES): CurrencyValuesProps => ({ currencyValueSelected }))
|
61
src/logic/currencyValues/store/model/currencyValues.js
Normal file
61
src/logic/currencyValues/store/model/currencyValues.js
Normal file
@ -0,0 +1,61 @@
|
||||
// @flow
|
||||
import type { RecordOf } from 'immutable'
|
||||
import { Record } from 'immutable'
|
||||
|
||||
export const AVAILABLE_CURRENCIES = {
|
||||
USD: 'USD',
|
||||
EUR: 'EUR',
|
||||
CAD: 'CAD',
|
||||
HKD: 'HKD',
|
||||
ISK: 'ISK',
|
||||
PHP: 'PHP',
|
||||
DKK: 'DKK',
|
||||
HUF: 'HUF',
|
||||
CZK: 'CZK',
|
||||
AUD: 'AUD',
|
||||
RON: 'RON',
|
||||
SEK: 'SEK',
|
||||
IDR: 'IDR',
|
||||
INR: 'INR',
|
||||
BRL: 'BRL',
|
||||
RUB: 'RUB',
|
||||
HRK: 'HRK',
|
||||
JPY: 'JPY',
|
||||
THB: 'THB',
|
||||
CHF: 'CHF',
|
||||
SGD: 'SGD',
|
||||
PLN: 'PLN',
|
||||
BGN: 'BGN',
|
||||
TRY: 'TRY',
|
||||
CNY: 'CNY',
|
||||
NOK: 'NOK',
|
||||
NZD: 'NZD',
|
||||
ZAR: 'ZAR',
|
||||
MXN: 'MXN',
|
||||
ILS: 'ILS',
|
||||
GBP: 'GBP',
|
||||
KRW: 'KRW',
|
||||
MYR: 'MYR',
|
||||
}
|
||||
|
||||
|
||||
export type BalanceCurrencyType = {
|
||||
currencyName: AVAILABLE_CURRENCIES;
|
||||
tokenAddress: string,
|
||||
balanceInBaseCurrency: string,
|
||||
balanceInSelectedCurrency: string,
|
||||
}
|
||||
|
||||
export const makeBalanceCurrency = Record({
|
||||
currencyName: '',
|
||||
tokenAddress: '',
|
||||
balanceInBaseCurrency: '',
|
||||
balanceInSelectedCurrency: '',
|
||||
})
|
||||
|
||||
export type CurrencyValuesProps = {
|
||||
currencyValueSelected: AVAILABLE_CURRENCIES;
|
||||
currencyValuesList: BalanceCurrencyType[]
|
||||
}
|
||||
|
||||
export type CurrencyValues = RecordOf<CurrencyValuesProps>
|
28
src/logic/currencyValues/store/reducer/currencyValues.js
Normal file
28
src/logic/currencyValues/store/reducer/currencyValues.js
Normal file
@ -0,0 +1,28 @@
|
||||
// @flow
|
||||
import { Map } from 'immutable'
|
||||
import { handleActions, type ActionType } from 'redux-actions'
|
||||
import { SET_CURRENCY_BALANCES } from '../actions/setCurrencyBalances'
|
||||
import type { State } from '~/logic/tokens/store/reducer/tokens'
|
||||
import { SET_CURRENT_CURRENCY } from '~/logic/currencyValues/store/actions/setCurrencySelected'
|
||||
|
||||
export const CURRENCY_VALUES_KEY = 'currencyValues'
|
||||
|
||||
export default handleActions<State, *>(
|
||||
{
|
||||
[SET_CURRENCY_BALANCES]: (state: State, action: ActionType<Function>): State => {
|
||||
const { currencyBalances } = action.payload
|
||||
|
||||
const newState = state.set('currencyBalances', currencyBalances)
|
||||
|
||||
return newState
|
||||
},
|
||||
[SET_CURRENT_CURRENCY]: (state: State, action: ActionType<Function>): State => {
|
||||
const { currencyValueSelected } = action.payload
|
||||
|
||||
const newState = state.set('currencyValueSelected', currencyValueSelected)
|
||||
|
||||
return newState
|
||||
},
|
||||
},
|
||||
Map(),
|
||||
)
|
9
src/logic/currencyValues/store/selectors/index.js
Normal file
9
src/logic/currencyValues/store/selectors/index.js
Normal file
@ -0,0 +1,9 @@
|
||||
// @flow
|
||||
|
||||
import { List } from 'immutable'
|
||||
import { type GlobalState } from '~/store'
|
||||
import { CURRENCY_VALUES_KEY } from '~/logic/currencyValues/store/reducer/currencyValues'
|
||||
|
||||
|
||||
export const currencyValuesListSelector = (state: GlobalState) => (state[CURRENCY_VALUES_KEY].get('currencyBalances') ? state[CURRENCY_VALUES_KEY].get('currencyBalances') : List([]))
|
||||
export const currentCurrencySelector = (state: GlobalState) => state[CURRENCY_VALUES_KEY].get('currencyValueSelected')
|
@ -10,6 +10,7 @@ import { type Notification, NOTIFICATIONS } from './notificationTypes'
|
||||
export type NotificationsQueue = {
|
||||
beforeExecution: Notification | null,
|
||||
pendingExecution: Notification | null,
|
||||
waitingConfirmation: Notification | null,
|
||||
afterExecution: {
|
||||
noMoreConfirmationsNeeded: Notification | null,
|
||||
moreConfirmationsNeeded: Notification | null,
|
||||
@ -29,6 +30,15 @@ const standardTxNotificationsQueue: NotificationsQueue = {
|
||||
afterExecutionError: NOTIFICATIONS.TX_FAILED_MSG,
|
||||
}
|
||||
|
||||
const waitingTransactionNotificationsQueue: NotificationsQueue = {
|
||||
beforeExecution: null,
|
||||
pendingExecution: null,
|
||||
afterRejection: null,
|
||||
waitingConfirmation: NOTIFICATIONS.TX_WAITING_MSG,
|
||||
afterExecution: null,
|
||||
afterExecutionError: null,
|
||||
}
|
||||
|
||||
const confirmationTxNotificationsQueue: NotificationsQueue = {
|
||||
beforeExecution: NOTIFICATIONS.SIGN_TX_MSG,
|
||||
pendingExecution: NOTIFICATIONS.TX_CONFIRMATION_PENDING_MSG,
|
||||
@ -123,6 +133,10 @@ export const getNotificationsFromTxType = (txType: string) => {
|
||||
notificationsQueue = ownerNameChangeNotificationsQueue
|
||||
break
|
||||
}
|
||||
case TX_NOTIFICATION_TYPES.WAITING_TX: {
|
||||
notificationsQueue = waitingTransactionNotificationsQueue
|
||||
break
|
||||
}
|
||||
default: {
|
||||
notificationsQueue = defaultNotificationsQueue
|
||||
break
|
||||
@ -132,10 +146,12 @@ export const getNotificationsFromTxType = (txType: string) => {
|
||||
return notificationsQueue
|
||||
}
|
||||
|
||||
export const enhanceSnackbarForAction = (notification: Notification) => ({
|
||||
export const enhanceSnackbarForAction = (notification: Notification, key?: string, onClick?: Function) => ({
|
||||
...notification,
|
||||
key,
|
||||
options: {
|
||||
...notification.options,
|
||||
onClick,
|
||||
action: (key: number) => (
|
||||
<IconButton onClick={() => store.dispatch(closeSnackbarAction({ key }))}>
|
||||
<IconClose />
|
||||
|
@ -14,6 +14,7 @@ export type Variant = 'success' | 'error' | 'warning' | 'info'
|
||||
|
||||
export type Notification = {
|
||||
message: string,
|
||||
key?: string,
|
||||
options: {
|
||||
variant: Variant,
|
||||
persist: boolean,
|
||||
@ -38,6 +39,8 @@ export type Notifications = {
|
||||
TX_EXECUTED_MSG: Notification,
|
||||
TX_EXECUTED_MORE_CONFIRMATIONS_MSG: Notification,
|
||||
TX_FAILED_MSG: Notification,
|
||||
TX_WAITING_MSG: Notification,
|
||||
TX_INCOMING_MSG: Notification,
|
||||
|
||||
// Approval Transactions
|
||||
TX_CONFIRMATION_PENDING_MSG: Notification,
|
||||
@ -122,6 +125,20 @@ export const NOTIFICATIONS: Notifications = {
|
||||
message: 'Transaction failed',
|
||||
options: { variant: ERROR, persist: false, autoHideDuration: longDuration },
|
||||
},
|
||||
TX_WAITING_MSG: {
|
||||
message: 'A pending transaction requires your confirmation!',
|
||||
key: 'TX_WAITING_MSG',
|
||||
options: {
|
||||
variant: WARNING, persist: true, preventDuplicate: true,
|
||||
},
|
||||
},
|
||||
TX_INCOMING_MSG: {
|
||||
message: 'Incoming transfer: ',
|
||||
key: 'TX_INCOMING_MSG',
|
||||
options: {
|
||||
variant: SUCCESS, persist: false, autoHideDuration: longDuration, preventDuplicate: true,
|
||||
},
|
||||
},
|
||||
|
||||
// Approval Transactions
|
||||
TX_CONFIRMATION_PENDING_MSG: {
|
||||
|
@ -11,9 +11,8 @@ const addSnackbar = createAction<string, *>(ENQUEUE_SNACKBAR)
|
||||
const enqueueSnackbar = (notification: NotificationProps) => (dispatch: ReduxDispatch<GlobalState>) => {
|
||||
const newNotification = {
|
||||
...notification,
|
||||
key: new Date().getTime(),
|
||||
key: notification.key || new Date().getTime(),
|
||||
}
|
||||
|
||||
dispatch(addSnackbar(newNotification))
|
||||
}
|
||||
|
||||
|
43
src/logic/safe/transactions/awaitingTransactions.js
Normal file
43
src/logic/safe/transactions/awaitingTransactions.js
Normal file
@ -0,0 +1,43 @@
|
||||
// @flow
|
||||
import { Map, List } from 'immutable'
|
||||
import type { Transaction } from '~/routes/safe/store/models/transaction'
|
||||
|
||||
export const getAwaitingTransactions = (
|
||||
allTransactions: Map<string, List<Transaction>>,
|
||||
userAccount: string,
|
||||
): Map<string, List<Transaction>> => {
|
||||
if (!allTransactions) {
|
||||
return Map({})
|
||||
}
|
||||
|
||||
const allAwaitingTransactions = allTransactions.map((safeTransactions) => {
|
||||
const nonCancelledTransactions = safeTransactions.filter(
|
||||
(transaction: Transaction) => {
|
||||
// If transactions are not executed, but there's a transaction with the same nonce EXECUTED later
|
||||
// it means that the transaction was cancelled (Replaced) and shouldn't get executed
|
||||
if (!transaction.isExecuted) {
|
||||
const replacementTransaction = safeTransactions.findLast(
|
||||
(tx) => tx.isExecuted && tx.nonce === transaction.nonce,
|
||||
)
|
||||
if (replacementTransaction) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
transaction = transaction.set('cancelled', true)
|
||||
}
|
||||
}
|
||||
// The transaction is not executed and is not cancelled, so it's still waiting confirmations
|
||||
if (!transaction.executionTxHash && !transaction.cancelled) {
|
||||
// Then we check if the waiting confirmations are not from the current user, otherwise, filters this transaction
|
||||
const transactionWaitingUser = transaction.confirmations.filter(
|
||||
(confirmation) => confirmation.owner && confirmation.owner.address !== userAccount,
|
||||
)
|
||||
|
||||
return transactionWaitingUser.size > 0
|
||||
}
|
||||
return false
|
||||
},
|
||||
)
|
||||
return nonCancelledTransactions
|
||||
})
|
||||
|
||||
return allAwaitingTransactions
|
||||
}
|
11
src/logic/safe/transactions/incomingTxHistory.js
Normal file
11
src/logic/safe/transactions/incomingTxHistory.js
Normal file
@ -0,0 +1,11 @@
|
||||
// @flow
|
||||
import { getWeb3 } from '~/logic/wallets/getWeb3'
|
||||
import { getIncomingTxServiceUriTo, getTxServiceHost } from '~/config'
|
||||
|
||||
export const buildIncomingTxServiceUrl = (safeAddress: string) => {
|
||||
const host = getTxServiceHost()
|
||||
const address = getWeb3().utils.toChecksumAddress(safeAddress)
|
||||
const base = getIncomingTxServiceUriTo(address)
|
||||
|
||||
return `${host}${base}`
|
||||
}
|
@ -4,6 +4,7 @@ export type NotifiedTransaction = {
|
||||
STANDARD_TX: string,
|
||||
CONFIRMATION_TX: string,
|
||||
CANCELLATION_TX: string,
|
||||
WAITING_TX: string,
|
||||
SETTINGS_CHANGE_TX: string,
|
||||
SAFE_NAME_CHANGE_TX: string,
|
||||
OWNER_NAME_CHANGE_TX: string,
|
||||
@ -13,6 +14,7 @@ export const TX_NOTIFICATION_TYPES: NotifiedTransaction = {
|
||||
STANDARD_TX: 'STANDARD_TX',
|
||||
CONFIRMATION_TX: 'CONFIRMATION_TX',
|
||||
CANCELLATION_TX: 'CANCELLATION_TX',
|
||||
WAITING_TX: 'WAITING_TX',
|
||||
SETTINGS_CHANGE_TX: 'SETTINGS_CHANGE_TX',
|
||||
SAFE_NAME_CHANGE_TX: 'SAFE_NAME_CHANGE_TX',
|
||||
OWNER_NAME_CHANGE_TX: 'OWNER_NAME_CHANGE_TX',
|
||||
|
@ -2,7 +2,6 @@
|
||||
import GnosisSafeSol from '@gnosis.pm/safe-contracts/build/contracts/GnosisSafe.json'
|
||||
import { getWeb3 } from '~/logic/wallets/getWeb3'
|
||||
import { type Operation } from '~/logic/safe/transactions'
|
||||
import { ZERO_ADDRESS } from '~/logic/wallets/ethAddresses'
|
||||
|
||||
export const CALL = 0
|
||||
export const TX_TYPE_EXECUTION = 'execution'
|
||||
|
@ -1,4 +1,8 @@
|
||||
// @flow
|
||||
import { List } from 'immutable'
|
||||
import type { Safe } from '~/routes/safe/store/models/safe'
|
||||
import type { Owner } from '~/routes/safe/store/models/owner'
|
||||
|
||||
export const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'
|
||||
|
||||
export const sameAddress = (firstAddress: string, secondAddress: string): boolean => {
|
||||
@ -13,10 +17,32 @@ export const sameAddress = (firstAddress: string, secondAddress: string): boolea
|
||||
return firstAddress.toLowerCase() === secondAddress.toLowerCase()
|
||||
}
|
||||
|
||||
export const shortVersionOf = (address: string, cut: number) => {
|
||||
const final = 42 - cut
|
||||
export const shortVersionOf = (value: string, cut: number) => {
|
||||
if (!value) {
|
||||
return 'Unknown'
|
||||
}
|
||||
|
||||
if (!address) return 'Unknown address'
|
||||
if (address.length < final) return address
|
||||
return `${address.substring(0, cut)}...${address.substring(final)}`
|
||||
const final = value.length - cut
|
||||
if (value.length < final) {
|
||||
return value
|
||||
}
|
||||
|
||||
return `${value.substring(0, cut)}...${value.substring(final)}`
|
||||
}
|
||||
|
||||
export const isUserOwner = (safe: Safe, userAccount: string): boolean => {
|
||||
if (!safe) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (!userAccount) {
|
||||
return false
|
||||
}
|
||||
|
||||
const { owners }: List<Owner> = safe
|
||||
if (!owners) {
|
||||
return false
|
||||
}
|
||||
|
||||
return owners.find((owner: Owner) => sameAddress(owner.address, userAccount)) !== undefined
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ import ReviewInformation from '~/routes/load/components/ReviewInformation'
|
||||
import OwnerList from '~/routes/load/components/OwnerList'
|
||||
import DetailsForm, { safeFieldsValidation } from '~/routes/load/components/DetailsForm'
|
||||
import { history } from '~/store'
|
||||
import { secondary } from '~/theme/variables'
|
||||
import { secondary, sm } from '~/theme/variables'
|
||||
import { type SelectorProps } from '~/routes/load/container/selector'
|
||||
|
||||
const getSteps = () => ['Name and address', 'Owners', 'Review']
|
||||
@ -21,7 +21,7 @@ export type LayoutProps = SelectorProps & {
|
||||
|
||||
const iconStyle = {
|
||||
color: secondary,
|
||||
padding: '8px',
|
||||
padding: sm,
|
||||
marginRight: '5px',
|
||||
}
|
||||
|
||||
|
@ -9,28 +9,62 @@ import Row from '~/components/layout/Row'
|
||||
import Review from '~/routes/open/components/ReviewInformation'
|
||||
import SafeNameField from '~/routes/open/components/SafeNameForm'
|
||||
import SafeOwnersFields from '~/routes/open/components/SafeOwnersConfirmationsForm'
|
||||
import { getOwnerNameBy, getOwnerAddressBy, FIELD_CONFIRMATIONS } from '~/routes/open/components/fields'
|
||||
import {
|
||||
getOwnerNameBy,
|
||||
getOwnerAddressBy,
|
||||
FIELD_CONFIRMATIONS,
|
||||
FIELD_SAFE_NAME,
|
||||
} from '~/routes/open/components/fields'
|
||||
import { initContracts } from '~/logic/contracts/safeContracts'
|
||||
import { history } from '~/store'
|
||||
import { secondary } from '~/theme/variables'
|
||||
import { secondary, sm } from '~/theme/variables'
|
||||
import type { SafePropsType } from '~/routes/open/container/Open'
|
||||
import Welcome from '~/routes/welcome/components/Layout'
|
||||
|
||||
const { useEffect } = React
|
||||
|
||||
const getSteps = () => ['Name', 'Owners and confirmations', 'Review']
|
||||
|
||||
const initialValuesFrom = (userAccount: string) => ({
|
||||
[getOwnerNameBy(0)]: 'My Wallet',
|
||||
[getOwnerAddressBy(0)]: userAccount,
|
||||
[FIELD_CONFIRMATIONS]: '1',
|
||||
})
|
||||
|
||||
const initialValuesFrom = (userAccount: string, safeProps?: SafePropsType) => {
|
||||
if (!safeProps) {
|
||||
return ({
|
||||
[getOwnerNameBy(0)]: 'My Wallet',
|
||||
[getOwnerAddressBy(0)]: userAccount,
|
||||
[FIELD_CONFIRMATIONS]: '1',
|
||||
})
|
||||
}
|
||||
let obj = {}
|
||||
const {
|
||||
ownerAddresses, ownerNames, threshold, name,
|
||||
} = safeProps
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
for (const [index, value] of ownerAddresses.entries()) {
|
||||
const safeName = ownerNames[index] ? ownerNames[index] : 'My Wallet'
|
||||
obj = {
|
||||
...obj,
|
||||
[getOwnerAddressBy(index)]: value,
|
||||
[getOwnerNameBy(index)]: safeName,
|
||||
}
|
||||
}
|
||||
return ({
|
||||
...obj,
|
||||
[FIELD_CONFIRMATIONS]: threshold || '1',
|
||||
[FIELD_SAFE_NAME]: name,
|
||||
})
|
||||
}
|
||||
|
||||
type Props = {
|
||||
provider: string,
|
||||
userAccount: string,
|
||||
network: string,
|
||||
onCallSafeContractSubmit: (values: Object) => Promise<void>,
|
||||
safeProps?: SafePropsType,
|
||||
}
|
||||
|
||||
const iconStyle = {
|
||||
color: secondary,
|
||||
padding: '8px',
|
||||
padding: sm,
|
||||
marginRight: '5px',
|
||||
}
|
||||
|
||||
@ -44,11 +78,21 @@ const formMutators = {
|
||||
},
|
||||
}
|
||||
|
||||
const Layout = ({
|
||||
provider, userAccount, onCallSafeContractSubmit, network,
|
||||
}: Props) => {
|
||||
|
||||
const Layout = (props: Props) => {
|
||||
const {
|
||||
provider, userAccount, onCallSafeContractSubmit, network, safeProps,
|
||||
} = props
|
||||
|
||||
useEffect(() => {
|
||||
if (provider) {
|
||||
initContracts()
|
||||
}
|
||||
}, [provider])
|
||||
|
||||
const steps = getSteps()
|
||||
const initialValues = initialValuesFrom(userAccount)
|
||||
|
||||
const initialValues = initialValuesFrom(userAccount, safeProps)
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -75,7 +119,7 @@ const Layout = ({
|
||||
</Stepper>
|
||||
</Block>
|
||||
) : (
|
||||
<div>No web3 provider detected</div>
|
||||
<Welcome provider={provider} isOldMultisigMigration />
|
||||
)}
|
||||
</>
|
||||
)
|
||||
|
@ -1,68 +0,0 @@
|
||||
// @flow
|
||||
import { storiesOf } from '@storybook/react'
|
||||
import { State, Store } from '@sambego/storybook-state'
|
||||
import * as React from 'react'
|
||||
import styles from '~/components/layout/PageFrame/index.scss'
|
||||
import { getAccountsFrom, getThresholdFrom } from '~/routes/open/utils/safeDataExtractor'
|
||||
import { getProviderInfo } from '~/logic/wallets/getWeb3'
|
||||
import { sleep } from '~/utils/timer'
|
||||
import Component from './Layout'
|
||||
|
||||
const FrameDecorator = (story) => <div className={styles.frame}>{story()}</div>
|
||||
|
||||
const store = new Store({
|
||||
safeAddress: '',
|
||||
safeTx: '',
|
||||
})
|
||||
|
||||
storiesOf('Routes /open', module)
|
||||
.addDecorator(FrameDecorator)
|
||||
.add('Open Safe with all props set', () => {
|
||||
getProviderInfo()
|
||||
const provider = 'METAMASK'
|
||||
const userAccount = '0x03db1a8b26d08df23337e9276a36b474510f0023'
|
||||
const onCallSafeContractSubmit = async (values: Object): Promise<void> => {
|
||||
const accounts = getAccountsFrom(values)
|
||||
const numConfirmations = getThresholdFrom(values)
|
||||
const data = {
|
||||
userAccount,
|
||||
accounts,
|
||||
requiredConfirmations: numConfirmations,
|
||||
}
|
||||
// eslint-disable-next-line
|
||||
console.log(`Generating and sending a eth tx based on: ${JSON.stringify(data, null, 2)}`)
|
||||
|
||||
await sleep(3000)
|
||||
|
||||
store.set({
|
||||
safeAddress: '0x03db1a8b26d08df23337e9276a36b474510f0025',
|
||||
// eslint-disable-next-line
|
||||
safeTx: {
|
||||
transactionHash: '0x4603de1ab6a92b4ee1fd67189089f5c02f5df5d135bf85af84083c27808c0544',
|
||||
transactionIndex: 0,
|
||||
blockHash: '0x593ce7d85fef2a492e8f759f485c8b66ff803773e77182c68dd45c439b7a956d',
|
||||
blockNumber: 19,
|
||||
gasUsed: 3034193,
|
||||
cumulativeGasUsed: 3034193,
|
||||
contractAddress: '0xfddda33736fb95b587cbfecc1ff4a50f717adc00',
|
||||
logs: [],
|
||||
status: '0x01',
|
||||
logsBloom:
|
||||
'0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<State store={store}>
|
||||
<Component
|
||||
network="rinkeby"
|
||||
provider={provider}
|
||||
userAccount={userAccount}
|
||||
safeAddress={store.get('safeAddress')}
|
||||
safeTx={store.get('safeTx')}
|
||||
onCallSafeContractSubmit={onCallSafeContractSubmit}
|
||||
/>
|
||||
</State>
|
||||
)
|
||||
})
|
@ -12,6 +12,7 @@ import { sm, secondary } from '~/theme/variables'
|
||||
|
||||
type Props = {
|
||||
classes: Object,
|
||||
safeName?: string,
|
||||
}
|
||||
|
||||
const styles = () => ({
|
||||
@ -32,12 +33,13 @@ const styles = () => ({
|
||||
},
|
||||
})
|
||||
|
||||
const SafeName = ({ classes }: Props) => (
|
||||
const SafeName = ({ classes, safeName }: Props) => (
|
||||
<>
|
||||
<Block margin="lg">
|
||||
<Paragraph noMargin size="md" color="primary">
|
||||
You are about to create a new Gnosis Safe wallet with one or more owners. First, let's give your new wallet
|
||||
a name. This name is only stored locally and will never be shared with Gnosis or any third parties.
|
||||
You are about to create a new Gnosis Safe wallet with one or more owners. First, let's give your new
|
||||
wallet
|
||||
a name. This name is only stored locally and will never be shared with Gnosis or any third parties.
|
||||
</Paragraph>
|
||||
</Block>
|
||||
<Block margin="lg" className={classes.root}>
|
||||
@ -48,23 +50,24 @@ const SafeName = ({ classes }: Props) => (
|
||||
validate={required}
|
||||
placeholder="Name of the new Safe"
|
||||
text="Safe name"
|
||||
defaultValue={safeName}
|
||||
/>
|
||||
</Block>
|
||||
<Block margin="lg">
|
||||
<Paragraph noMargin size="md" color="primary" className={classes.links}>
|
||||
By continuing you consent with the
|
||||
By continuing you consent with the
|
||||
{' '}
|
||||
<a rel="noopener noreferrer" href="https://safe.gnosis.io/terms" target="_blank">
|
||||
terms of use
|
||||
terms of use
|
||||
</a>
|
||||
{' '}
|
||||
and
|
||||
and
|
||||
{' '}
|
||||
<a rel="noopener noreferrer" href="https://safe.gnosis.io/privacy" target="_blank">
|
||||
privacy policy
|
||||
privacy policy
|
||||
</a>
|
||||
. Most importantly, you confirm that your funds are held securely in the Gnosis Safe, a smart contract on the
|
||||
Ethereum blockchain. These funds cannot be accessed by Gnosis at any point.
|
||||
. Most importantly, you confirm that your funds are held securely in the Gnosis Safe, a smart contract on the
|
||||
Ethereum blockchain. These funds cannot be accessed by Gnosis at any point.
|
||||
</Paragraph>
|
||||
</Block>
|
||||
</>
|
||||
@ -72,10 +75,13 @@ const SafeName = ({ classes }: Props) => (
|
||||
|
||||
const SafeNameForm = withStyles(styles)(SafeName)
|
||||
|
||||
const SafeNamePage = () => (controls: React.Node) => (
|
||||
<OpenPaper controls={controls}>
|
||||
<SafeNameForm />
|
||||
</OpenPaper>
|
||||
)
|
||||
const SafeNamePage = () => (controls: React.Node, { values }) => {
|
||||
const { safeName } = values
|
||||
return (
|
||||
<OpenPaper controls={controls}>
|
||||
<SafeNameForm safeName={safeName} />
|
||||
</OpenPaper>
|
||||
)
|
||||
}
|
||||
|
||||
export default SafeNamePage
|
||||
|
@ -4,6 +4,7 @@ import { withStyles } from '@material-ui/core/styles'
|
||||
import InputAdornment from '@material-ui/core/InputAdornment'
|
||||
import CheckCircle from '@material-ui/icons/CheckCircle'
|
||||
import MenuItem from '@material-ui/core/MenuItem'
|
||||
import { withRouter } from 'react-router-dom'
|
||||
import Field from '~/components/forms/Field'
|
||||
import TextField from '~/components/forms/TextField'
|
||||
import SelectField from '~/components/forms/SelectField'
|
||||
@ -70,6 +71,7 @@ const SafeOwners = (props: Props) => {
|
||||
} = props
|
||||
|
||||
const validOwners = getNumOwnersFrom(values)
|
||||
|
||||
const [numOwners, setNumOwners] = useState<number>(validOwners)
|
||||
const [qrModalOpen, setQrModalOpen] = useState<boolean>(false)
|
||||
const [scanQrForOwnerName, setScanQrForOwnerName] = useState<string | null>(null)
|
||||
@ -222,7 +224,7 @@ owner(s)
|
||||
)
|
||||
}
|
||||
|
||||
const SafeOwnersForm = withStyles(styles)(SafeOwners)
|
||||
const SafeOwnersForm = withStyles(styles)(withRouter(SafeOwners))
|
||||
|
||||
const SafeOwnersPage = ({ updateInitialProps }: Object) => (controls: React.Node, { values, errors, form }: Object) => (
|
||||
<>
|
||||
|
@ -2,6 +2,7 @@
|
||||
export const FIELD_NAME: string = 'name'
|
||||
export const FIELD_CONFIRMATIONS: string = 'confirmations'
|
||||
export const FIELD_OWNERS: string = 'owners'
|
||||
export const FIELD_SAFE_NAME: string = 'safeName'
|
||||
|
||||
export const getOwnerNameBy = (index: number) => `owner${index}Name`
|
||||
export const getOwnerAddressBy = (index: number) => `owner${index}Address`
|
||||
|
@ -1,12 +1,14 @@
|
||||
// @flow
|
||||
import * as React from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import queryString from 'query-string'
|
||||
import { withRouter } from 'react-router-dom'
|
||||
import Page from '~/components/layout/Page'
|
||||
import {
|
||||
getAccountsFrom, getThresholdFrom, getNamesFrom, getSafeNameFrom, getOwnersFrom,
|
||||
} from '~/routes/open/utils/safeDataExtractor'
|
||||
import { buildSafe } from '~/routes/safe/store/actions/fetchSafe'
|
||||
import { getGnosisSafeInstanceAt, deploySafeContract, initContracts } from '~/logic/contracts/safeContracts'
|
||||
import { getGnosisSafeInstanceAt, deploySafeContract } from '~/logic/contracts/safeContracts'
|
||||
import { checkReceiptStatus } from '~/logic/wallets/ethTransactions'
|
||||
import { history } from '~/store'
|
||||
import { OPENING_ADDRESS, stillInOpeningView, SAFELIST_ADDRESS } from '~/routes/routes'
|
||||
@ -24,14 +26,36 @@ export type OpenState = {
|
||||
safeAddress: string,
|
||||
}
|
||||
|
||||
export type SafePropsType = {
|
||||
name: string,
|
||||
ownerAddresses: string[],
|
||||
ownerNames: string[],
|
||||
threshold: string,
|
||||
}
|
||||
|
||||
const validateQueryParams = (ownerAddresses?: string[], ownerNames?: string[], threshold?: string, safeName?: string) => {
|
||||
if (!ownerAddresses || !ownerNames || !threshold || !safeName) {
|
||||
return false
|
||||
}
|
||||
if (!ownerAddresses.length === 0 || ownerNames.length === 0) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (Number.isNaN(Number(threshold))) {
|
||||
return false
|
||||
}
|
||||
if (threshold > ownerAddresses.length) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
export const createSafe = async (values: Object, userAccount: string, addSafe: AddSafe): Promise<OpenState> => {
|
||||
const numConfirmations = getThresholdFrom(values)
|
||||
const name = getSafeNameFrom(values)
|
||||
const ownersNames = getNamesFrom(values)
|
||||
const ownerAddresses = getAccountsFrom(values)
|
||||
|
||||
await initContracts()
|
||||
|
||||
const safe = await deploySafeContract(ownerAddresses, numConfirmations, userAccount)
|
||||
await checkReceiptStatus(safe.tx)
|
||||
|
||||
@ -59,10 +83,6 @@ export const createSafe = async (values: Object, userAccount: string, addSafe: A
|
||||
}
|
||||
|
||||
class Open extends React.Component<Props> {
|
||||
async componentDidMount() {
|
||||
await initContracts()
|
||||
}
|
||||
|
||||
onCallSafeContractSubmit = async (values) => {
|
||||
try {
|
||||
const { userAccount, addSafe } = this.props
|
||||
@ -75,8 +95,23 @@ class Open extends React.Component<Props> {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { provider, userAccount, network } = this.props
|
||||
const {
|
||||
provider, userAccount, network, location,
|
||||
} = this.props
|
||||
const query: SafePropsType = queryString.parse(location.search, { arrayFormat: 'comma' })
|
||||
const {
|
||||
name, owneraddresses, ownernames, threshold,
|
||||
} = query
|
||||
|
||||
let safeProps = null
|
||||
if (validateQueryParams(owneraddresses, ownernames, threshold, name)) {
|
||||
safeProps = {
|
||||
name,
|
||||
ownerAddresses: owneraddresses,
|
||||
ownerNames: ownernames,
|
||||
threshold,
|
||||
}
|
||||
}
|
||||
return (
|
||||
<Page>
|
||||
<Layout
|
||||
@ -84,10 +119,11 @@ class Open extends React.Component<Props> {
|
||||
provider={provider}
|
||||
userAccount={userAccount}
|
||||
onCallSafeContractSubmit={this.onCallSafeContractSubmit}
|
||||
safeProps={safeProps}
|
||||
/>
|
||||
</Page>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(selector, actions)(Open)
|
||||
export default connect(selector, actions)(withRouter(Open))
|
||||
|
@ -1,19 +0,0 @@
|
||||
// @flow
|
||||
import { storiesOf } from '@storybook/react'
|
||||
import * as React from 'react'
|
||||
import styles from '~/components/layout/PageFrame/index.scss'
|
||||
import { ETHEREUM_NETWORK } from '~/logic/wallets/getWeb3'
|
||||
import Component from './component'
|
||||
|
||||
const FrameDecorator = (story) => <div className={styles.frame}>{story()}</div>
|
||||
|
||||
storiesOf('Routes /opening', module)
|
||||
.addDecorator(FrameDecorator)
|
||||
.add('View while Safe is being deployed', () => (
|
||||
<Component
|
||||
name="Super Vault 2000"
|
||||
tx="0xed163e50e2e85695f5edafeba51d6be1758549858d12611ed4dcc96feaa19fc9"
|
||||
network={ETHEREUM_NETWORK.RINKEBY}
|
||||
/>
|
||||
))
|
||||
.add('Load this view without a tx', () => <Component network={ETHEREUM_NETWORK.UNKNOWN} />)
|
@ -26,8 +26,8 @@ const styles = () => ({
|
||||
boxSizing: 'border-box',
|
||||
},
|
||||
close: {
|
||||
height: '24px',
|
||||
width: '24px',
|
||||
height: lg,
|
||||
width: lg,
|
||||
fill: secondaryText,
|
||||
},
|
||||
qrContainer: {
|
||||
@ -48,7 +48,7 @@ const styles = () => ({
|
||||
justifyContent: 'center',
|
||||
'& > button': {
|
||||
fontFamily: 'Averta',
|
||||
fontSize: '16px',
|
||||
fontSize: md,
|
||||
boxShadow: '1px 2px 10px 0 rgba(212, 212, 211, 0.59)',
|
||||
},
|
||||
},
|
||||
|
@ -22,7 +22,7 @@ const styles = () => ({
|
||||
maxHeight: '75px',
|
||||
},
|
||||
manage: {
|
||||
fontSize: '24px',
|
||||
fontSize: lg,
|
||||
},
|
||||
closeIcon: {
|
||||
height: '35px',
|
||||
@ -31,7 +31,7 @@ const styles = () => ({
|
||||
buttonColumn: {
|
||||
padding: '52px 0',
|
||||
'& > button': {
|
||||
fontSize: '16px',
|
||||
fontSize: md,
|
||||
fontFamily: 'Averta',
|
||||
},
|
||||
},
|
||||
|
@ -23,6 +23,7 @@ import { getEthAsToken } from '~/logic/tokens/utils/tokenHelpers'
|
||||
import { formatAmount } from '~/logic/tokens/utils/formatAmount'
|
||||
import ArrowDown from '../assets/arrow-down.svg'
|
||||
import { styles } from './style'
|
||||
import { sm } from '~/theme/variables'
|
||||
|
||||
type Props = {
|
||||
onClose: () => void,
|
||||
@ -78,15 +79,15 @@ const ReviewCustomTx = ({
|
||||
const txData = tx.data.trim()
|
||||
const txValue = tx.value ? web3.utils.toWei(tx.value, 'ether') : 0
|
||||
|
||||
createTransaction(
|
||||
createTransaction({
|
||||
safeAddress,
|
||||
txRecipient,
|
||||
txValue,
|
||||
to: txRecipient,
|
||||
valueInWei: txValue,
|
||||
txData,
|
||||
TX_NOTIFICATION_TYPES.STANDARD_TX,
|
||||
notifiedTransaction: TX_NOTIFICATION_TYPES.STANDARD_TX,
|
||||
enqueueSnackbar,
|
||||
closeSnackbar,
|
||||
)
|
||||
})
|
||||
onClose()
|
||||
}
|
||||
|
||||
@ -106,7 +107,7 @@ const ReviewCustomTx = ({
|
||||
<SafeInfo safeAddress={safeAddress} safeName={safeName} ethBalance={ethBalance} />
|
||||
<Row margin="md">
|
||||
<Col xs={1}>
|
||||
<img src={ArrowDown} alt="Arrow Down" style={{ marginLeft: '8px' }} />
|
||||
<img src={ArrowDown} alt="Arrow Down" style={{ marginLeft: sm }} />
|
||||
</Col>
|
||||
<Col xs={11} center="xs" layout="column">
|
||||
<Hairline />
|
||||
|
@ -17,7 +17,7 @@ export const styles = () => ({
|
||||
marginLeft: '20px',
|
||||
},
|
||||
headingText: {
|
||||
fontSize: '24px',
|
||||
fontSize: lg,
|
||||
},
|
||||
closeIcon: {
|
||||
height: '35px',
|
||||
@ -50,7 +50,7 @@ export const styles = () => ({
|
||||
justifyContent: 'center',
|
||||
'& > button': {
|
||||
fontFamily: 'Averta',
|
||||
fontSize: '16px',
|
||||
fontSize: md,
|
||||
},
|
||||
},
|
||||
submitButton: {
|
||||
|
@ -28,6 +28,7 @@ import { TX_NOTIFICATION_TYPES } from '~/logic/safe/transactions'
|
||||
import { ETH_ADDRESS } from '~/logic/tokens/utils/tokenHelpers'
|
||||
import ArrowDown from '../assets/arrow-down.svg'
|
||||
import { styles } from './style'
|
||||
import { sm } from '~/theme/variables'
|
||||
|
||||
type Props = {
|
||||
onClose: () => void,
|
||||
@ -108,15 +109,15 @@ const ReviewTx = ({
|
||||
txAmount = 0
|
||||
}
|
||||
|
||||
createTransaction(
|
||||
createTransaction({
|
||||
safeAddress,
|
||||
txRecipient,
|
||||
txAmount,
|
||||
to: txRecipient,
|
||||
valueInWei: txAmount,
|
||||
txData,
|
||||
TX_NOTIFICATION_TYPES.STANDARD_TX,
|
||||
notifiedTransaction: TX_NOTIFICATION_TYPES.STANDARD_TX,
|
||||
enqueueSnackbar,
|
||||
closeSnackbar,
|
||||
)
|
||||
})
|
||||
onClose()
|
||||
}
|
||||
|
||||
@ -136,7 +137,7 @@ const ReviewTx = ({
|
||||
<SafeInfo safeAddress={safeAddress} safeName={safeName} ethBalance={ethBalance} />
|
||||
<Row margin="md">
|
||||
<Col xs={1}>
|
||||
<img src={ArrowDown} alt="Arrow Down" style={{ marginLeft: '8px' }} />
|
||||
<img src={ArrowDown} alt="Arrow Down" style={{ marginLeft: sm }} />
|
||||
</Col>
|
||||
<Col xs={11} center="xs" layout="column">
|
||||
<Hairline />
|
||||
|
@ -17,7 +17,7 @@ export const styles = () => ({
|
||||
marginLeft: '20px',
|
||||
},
|
||||
headingText: {
|
||||
fontSize: '24px',
|
||||
fontSize: lg,
|
||||
},
|
||||
closeIcon: {
|
||||
height: '35px',
|
||||
@ -37,7 +37,7 @@ export const styles = () => ({
|
||||
justifyContent: 'center',
|
||||
'& > button': {
|
||||
fontFamily: 'Averta',
|
||||
fontSize: '16px',
|
||||
fontSize: md,
|
||||
},
|
||||
},
|
||||
submitButton: {
|
||||
|
@ -25,6 +25,7 @@ import SafeInfo from '~/routes/safe/components/Balances/SendModal/SafeInfo'
|
||||
import QRIcon from '~/assets/icons/qrcode.svg'
|
||||
import ArrowDown from '../assets/arrow-down.svg'
|
||||
import { styles } from './style'
|
||||
import { sm } from '~/theme/variables'
|
||||
|
||||
type Props = {
|
||||
onClose: () => void,
|
||||
@ -102,7 +103,7 @@ const SendCustomTx = ({
|
||||
<SafeInfo safeAddress={safeAddress} safeName={safeName} ethBalance={ethBalance} />
|
||||
<Row margin="md">
|
||||
<Col xs={1}>
|
||||
<img src={ArrowDown} alt="Arrow Down" style={{ marginLeft: '8px' }} />
|
||||
<img src={ArrowDown} alt="Arrow Down" style={{ marginLeft: sm }} />
|
||||
</Col>
|
||||
<Col xs={11} center="xs" layout="column">
|
||||
<Hairline />
|
||||
|
@ -15,7 +15,7 @@ export const styles = () => ({
|
||||
marginLeft: '20px',
|
||||
},
|
||||
manage: {
|
||||
fontSize: '24px',
|
||||
fontSize: lg,
|
||||
},
|
||||
closeIcon: {
|
||||
height: '35px',
|
||||
@ -32,7 +32,7 @@ export const styles = () => ({
|
||||
justifyContent: 'center',
|
||||
'& > button': {
|
||||
fontFamily: 'Averta',
|
||||
fontSize: '16px',
|
||||
fontSize: md,
|
||||
},
|
||||
},
|
||||
submitButton: {
|
||||
|
@ -28,6 +28,7 @@ import ScanQRModal from '~/components/ScanQRModal'
|
||||
import ArrowDown from '../assets/arrow-down.svg'
|
||||
import QRIcon from '~/assets/icons/qrcode.svg'
|
||||
import { styles } from './style'
|
||||
import { sm } from '~/theme/variables'
|
||||
|
||||
type Props = {
|
||||
onClose: () => void,
|
||||
@ -114,7 +115,7 @@ const SendFunds = ({
|
||||
<SafeInfo safeAddress={safeAddress} safeName={safeName} ethBalance={ethBalance} />
|
||||
<Row margin="md">
|
||||
<Col xs={1}>
|
||||
<img src={ArrowDown} alt="Arrow Down" style={{ marginLeft: '8px' }} />
|
||||
<img src={ArrowDown} alt="Arrow Down" style={{ marginLeft: sm }} />
|
||||
</Col>
|
||||
<Col xs={11} center="xs" layout="column">
|
||||
<Hairline />
|
||||
|
@ -15,7 +15,7 @@ export const styles = () => ({
|
||||
marginLeft: '20px',
|
||||
},
|
||||
manage: {
|
||||
fontSize: '24px',
|
||||
fontSize: lg,
|
||||
},
|
||||
closeIcon: {
|
||||
height: '35px',
|
||||
@ -32,7 +32,7 @@ export const styles = () => ({
|
||||
justifyContent: 'center',
|
||||
'& > button': {
|
||||
fontFamily: 'Averta',
|
||||
fontSize: '16px',
|
||||
fontSize: md,
|
||||
},
|
||||
},
|
||||
submitButton: {
|
||||
|
@ -1,10 +1,10 @@
|
||||
// @flow
|
||||
import { lg } from '~/theme/variables'
|
||||
import { lg, md } from '~/theme/variables'
|
||||
|
||||
export const styles = () => ({
|
||||
title: {
|
||||
padding: `${lg} 0 20px`,
|
||||
fontSize: '16px',
|
||||
fontSize: md,
|
||||
},
|
||||
formContainer: {
|
||||
padding: '0 20px',
|
||||
|
@ -4,6 +4,8 @@ import { type Token } from '~/logic/tokens/store/model/token'
|
||||
import { buildOrderFieldFrom, FIXED, type SortRow } from '~/components/Table/sorting'
|
||||
import { type Column } from '~/components/Table/TableHead'
|
||||
import { formatAmount } from '~/logic/tokens/utils/formatAmount'
|
||||
import type { BalanceCurrencyType } from '~/logic/currencyValues/store/model/currencyValues'
|
||||
import { AVAILABLE_CURRENCIES } from '~/logic/currencyValues/store/model/currencyValues'
|
||||
|
||||
export const BALANCE_TABLE_ASSET_ID = 'asset'
|
||||
export const BALANCE_TABLE_BALANCE_ID = 'balance'
|
||||
@ -16,13 +18,29 @@ type BalanceData = {
|
||||
|
||||
export type BalanceRow = SortRow<BalanceData>
|
||||
|
||||
export const getBalanceData = (activeTokens: List<Token>): List<BalanceRow> => {
|
||||
// eslint-disable-next-line max-len
|
||||
const getTokenPriceInCurrency = (token: Token, currencySelected: AVAILABLE_CURRENCIES, currencyValues: List<BalanceCurrencyType>): string => {
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
|
||||
for (const tokenPriceIterator of currencyValues) {
|
||||
const { tokenAddress, balanceInSelectedCurrency, currencyName } = tokenPriceIterator
|
||||
if (token.address === tokenAddress && currencySelected === currencyName) {
|
||||
const balance = balanceInSelectedCurrency ? parseFloat(balanceInSelectedCurrency, 10).toFixed(2) : balanceInSelectedCurrency
|
||||
return `${balance} ${currencySelected}`
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
// eslint-disable-next-line max-len
|
||||
export const getBalanceData = (activeTokens: List<Token>, currencySelected: string, currencyValues: List<BalanceCurrencyType>): List<BalanceRow> => {
|
||||
const rows = activeTokens.map((token: Token) => ({
|
||||
[BALANCE_TABLE_ASSET_ID]: { name: token.name, logoUri: token.logoUri, address: token.address },
|
||||
[buildOrderFieldFrom(BALANCE_TABLE_ASSET_ID)]: token.name,
|
||||
[BALANCE_TABLE_BALANCE_ID]: `${formatAmount(token.balance)} ${token.symbol}`,
|
||||
[buildOrderFieldFrom(BALANCE_TABLE_BALANCE_ID)]: Number(token.balance),
|
||||
[FIXED]: token.get('symbol') === 'ETH',
|
||||
[BALANCE_TABLE_VALUE_ID]: getTokenPriceInCurrency(token, currencySelected, currencyValues),
|
||||
}))
|
||||
|
||||
return rows
|
||||
@ -56,5 +74,26 @@ export const generateColumns = () => {
|
||||
static: true,
|
||||
}
|
||||
|
||||
return List([assetColumn, balanceColumn, actions])
|
||||
const value: Column = {
|
||||
id: BALANCE_TABLE_VALUE_ID,
|
||||
order: false,
|
||||
label: 'Value',
|
||||
custom: false,
|
||||
static: true,
|
||||
style: {
|
||||
fontSize: '11px',
|
||||
color: '#5d6d74',
|
||||
borderBottomWidth: '2px',
|
||||
width: '125px',
|
||||
fontFamily: 'Averta',
|
||||
fontWeight: 'normal',
|
||||
fontStyle: 'normal',
|
||||
textAlign: 'right',
|
||||
},
|
||||
}
|
||||
|
||||
return List([assetColumn, balanceColumn, value, actions])
|
||||
}
|
||||
|
||||
// eslint-disable-next-line max-len
|
||||
export const filterByZero = (data: List<BalanceRow>, hideZero: boolean): List<BalanceRow> => data.filter((row: BalanceRow) => (hideZero ? row[buildOrderFieldFrom(BALANCE_TABLE_BALANCE_ID)] !== 0 : true))
|
||||
|
@ -23,6 +23,9 @@ import Tokens from './Tokens'
|
||||
import SendModal from './SendModal'
|
||||
import Receive from './Receive'
|
||||
import { styles } from './style'
|
||||
import DropdownCurrency from '~/routes/safe/components/DropdownCurrency'
|
||||
import type { BalanceCurrencyType } from '~/logic/currencyValues/store/model/currencyValues'
|
||||
import { BALANCE_TABLE_BALANCE_ID, BALANCE_TABLE_VALUE_ID } from '~/routes/safe/components/Balances/dataFetcher'
|
||||
|
||||
export const MANAGE_TOKENS_BUTTON_TEST_ID = 'manage-tokens-btn'
|
||||
export const BALANCE_ROW_TEST_ID = 'balance-row'
|
||||
@ -45,6 +48,9 @@ type Props = {
|
||||
safeName: string,
|
||||
ethBalance: string,
|
||||
createTransaction: Function,
|
||||
currencySelected: string,
|
||||
fetchCurrencyValues: Function,
|
||||
currencyValues: BalanceCurrencyType[],
|
||||
}
|
||||
|
||||
type Action = 'Token' | 'Send' | 'Receive'
|
||||
@ -63,6 +69,12 @@ class Balances extends React.Component<Props, State> {
|
||||
props.fetchTokens()
|
||||
}
|
||||
|
||||
componentDidMount(): void {
|
||||
const { safeAddress, fetchCurrencyValues, activateTokensByBalance } = this.props
|
||||
fetchCurrencyValues(safeAddress)
|
||||
activateTokensByBalance(safeAddress)
|
||||
}
|
||||
|
||||
onShow = (action: Action) => () => {
|
||||
this.setState(() => ({ [`show${action}`]: true }))
|
||||
}
|
||||
@ -89,17 +101,6 @@ class Balances extends React.Component<Props, State> {
|
||||
})
|
||||
}
|
||||
|
||||
handleChange = (e: SyntheticInputEvent<HTMLInputElement>) => {
|
||||
const { checked } = e.target
|
||||
|
||||
this.setState(() => ({ hideZero: checked }))
|
||||
}
|
||||
|
||||
componentDidMount(): void {
|
||||
const { activateTokensByBalance, safeAddress } = this.props
|
||||
activateTokensByBalance(safeAddress)
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
showToken, showReceive, sendFunds,
|
||||
@ -114,17 +115,20 @@ class Balances extends React.Component<Props, State> {
|
||||
safeName,
|
||||
ethBalance,
|
||||
createTransaction,
|
||||
currencySelected,
|
||||
currencyValues,
|
||||
} = this.props
|
||||
|
||||
const columns = generateColumns()
|
||||
const autoColumns = columns.filter((c) => !c.custom)
|
||||
|
||||
const filteredData = getBalanceData(activeTokens)
|
||||
const filteredData = getBalanceData(activeTokens, currencySelected, currencyValues)
|
||||
|
||||
return (
|
||||
<>
|
||||
<Row align="center" className={classes.message}>
|
||||
<Col xs={12} end="sm">
|
||||
<DropdownCurrency />
|
||||
<ButtonLink size="lg" onClick={this.onShow('Token')} testId="manage-tokens-btn">
|
||||
Manage List
|
||||
</ButtonLink>
|
||||
@ -155,11 +159,42 @@ class Balances extends React.Component<Props, State> {
|
||||
>
|
||||
{(sortedData: Array<BalanceRow>) => sortedData.map((row: any, index: number) => (
|
||||
<TableRow tabIndex={-1} key={index} className={classes.hide} data-testid={BALANCE_ROW_TEST_ID}>
|
||||
{autoColumns.map((column: Column) => (
|
||||
<TableCell key={column.id} style={cellWidth(column.width)} align={column.align} component="td">
|
||||
{column.id === BALANCE_TABLE_ASSET_ID ? <AssetTableCell asset={row[column.id]} /> : row[column.id]}
|
||||
</TableCell>
|
||||
))}
|
||||
{autoColumns.map((column: Column) => {
|
||||
const { id, width, align } = column
|
||||
let cellItem
|
||||
switch (id) {
|
||||
case BALANCE_TABLE_ASSET_ID: {
|
||||
cellItem = <AssetTableCell asset={row[id]} />
|
||||
break
|
||||
}
|
||||
case BALANCE_TABLE_BALANCE_ID: {
|
||||
cellItem = (
|
||||
<div>
|
||||
{row[id]}
|
||||
</div>
|
||||
)
|
||||
break
|
||||
}
|
||||
case BALANCE_TABLE_VALUE_ID: {
|
||||
cellItem = <div className={classes.currencyValueRow}>{row[id]}</div>
|
||||
break
|
||||
}
|
||||
default: {
|
||||
cellItem = null
|
||||
break
|
||||
}
|
||||
}
|
||||
return (
|
||||
<TableCell
|
||||
key={id}
|
||||
style={cellWidth(width)}
|
||||
align={align}
|
||||
component="td"
|
||||
>
|
||||
{cellItem}
|
||||
</TableCell>
|
||||
)
|
||||
})}
|
||||
<TableCell component="td">
|
||||
<Row align="end" className={classes.actions}>
|
||||
{granted && (
|
||||
|
@ -1,5 +1,5 @@
|
||||
// @flow
|
||||
import { sm, md } from '~/theme/variables'
|
||||
import { xs, sm, md } from '~/theme/variables'
|
||||
|
||||
export const styles = (theme: Object) => ({
|
||||
root: {
|
||||
@ -41,7 +41,7 @@ export const styles = (theme: Object) => ({
|
||||
width: '95px',
|
||||
minWidth: '95px',
|
||||
marginLeft: sm,
|
||||
borderRadius: '4px',
|
||||
borderRadius: xs,
|
||||
'& > span': {
|
||||
fontSize: '14px',
|
||||
},
|
||||
@ -49,7 +49,7 @@ export const styles = (theme: Object) => ({
|
||||
send: {
|
||||
width: '75px',
|
||||
minWidth: '75px',
|
||||
borderRadius: '4px',
|
||||
borderRadius: xs,
|
||||
'& > span': {
|
||||
fontSize: '14px',
|
||||
},
|
||||
@ -63,4 +63,8 @@ export const styles = (theme: Object) => ({
|
||||
cursor: 'pointer',
|
||||
},
|
||||
},
|
||||
currencyValueRow: {
|
||||
maxWidth: '125px',
|
||||
textAlign: 'right',
|
||||
},
|
||||
})
|
||||
|
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="14" viewBox="0 0 18 14">
|
||||
<path fill="#008C73" fill-rule="evenodd" d="M5.6 10.6L1.4 6.4 0 7.8l5.6 5.6 12-12L16.2 0z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 188 B |
124
src/routes/safe/components/DropdownCurrency/index.jsx
Normal file
124
src/routes/safe/components/DropdownCurrency/index.jsx
Normal file
@ -0,0 +1,124 @@
|
||||
// @flow
|
||||
import ListItemIcon from '@material-ui/core/ListItemIcon'
|
||||
import ListItemText from '@material-ui/core/ListItemText'
|
||||
import Menu from '@material-ui/core/Menu'
|
||||
import MenuItem from '@material-ui/core/MenuItem'
|
||||
import React, { useState } from 'react'
|
||||
import style from 'currency-flags/dist/currency-flags.min.css'
|
||||
import { MuiThemeProvider } from '@material-ui/core/styles'
|
||||
import { useDispatch, useSelector } from 'react-redux'
|
||||
import SearchIcon from '@material-ui/icons/Search'
|
||||
import InputBase from '@material-ui/core/InputBase'
|
||||
import classNames from 'classnames'
|
||||
import { DropdownListTheme } from '~/theme/mui'
|
||||
import CheckIcon from './img/check.svg'
|
||||
import { AVAILABLE_CURRENCIES } from '~/logic/currencyValues/store/model/currencyValues'
|
||||
import fetchCurrencySelectedValue from '~/logic/currencyValues/store/actions/fetchCurrencySelectedValue'
|
||||
import { currentCurrencySelector } from '~/logic/currencyValues/store/selectors'
|
||||
import { useDropdownStyles } from '~/routes/safe/components/DropdownCurrency/style'
|
||||
import saveCurrencySelected from '~/logic/currencyValues/store/actions/saveCurrencySelected'
|
||||
|
||||
|
||||
const DropdownCurrency = () => {
|
||||
const currenciesList = Object.values(AVAILABLE_CURRENCIES)
|
||||
const dispatch = useDispatch()
|
||||
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null)
|
||||
const currencyValueSelected = useSelector(currentCurrencySelector)
|
||||
|
||||
const [searchParams, setSearchParams] = useState('')
|
||||
const classes = useDropdownStyles()
|
||||
const currenciesListFiltered = currenciesList.filter((currency) => currency.toLowerCase().includes(searchParams.toLowerCase()))
|
||||
|
||||
const handleClick = (event: React.MouseEvent<HTMLElement>) => {
|
||||
setAnchorEl(event.currentTarget)
|
||||
}
|
||||
|
||||
const handleClose = () => {
|
||||
setAnchorEl(null)
|
||||
}
|
||||
|
||||
const onCurrentCurrencyChangedHandler = (newCurrencySelectedName: AVAILABLE_CURRENCIES) => {
|
||||
dispatch(fetchCurrencySelectedValue(newCurrencySelectedName))
|
||||
dispatch(saveCurrencySelected(newCurrencySelectedName))
|
||||
handleClose()
|
||||
}
|
||||
|
||||
return (
|
||||
!currencyValueSelected ? null
|
||||
: (
|
||||
<MuiThemeProvider theme={DropdownListTheme}>
|
||||
<>
|
||||
<button
|
||||
className={classes.button}
|
||||
onClick={handleClick}
|
||||
type="button"
|
||||
>
|
||||
<span className={classNames(classes.buttonInner, anchorEl && classes.openMenuButton)}>
|
||||
{currencyValueSelected}
|
||||
</span>
|
||||
</button>
|
||||
<Menu
|
||||
anchorEl={anchorEl}
|
||||
elevation={0}
|
||||
getContentAnchorEl={null}
|
||||
id="customizedMenu"
|
||||
keepMounted
|
||||
onClose={handleClose}
|
||||
open={Boolean(anchorEl)}
|
||||
rounded={0}
|
||||
anchorOrigin={{
|
||||
horizontal: 'center',
|
||||
vertical: 'bottom',
|
||||
}}
|
||||
transformOrigin={{
|
||||
horizontal: 'center',
|
||||
vertical: 'top',
|
||||
}}
|
||||
>
|
||||
<MenuItem
|
||||
className={classes.listItemSearch}
|
||||
key="0"
|
||||
>
|
||||
<div className={classes.search}>
|
||||
<div className={classes.searchIcon}>
|
||||
<SearchIcon />
|
||||
</div>
|
||||
<InputBase
|
||||
placeholder="Search…"
|
||||
classes={{
|
||||
root: classes.inputRoot,
|
||||
input: classes.inputInput,
|
||||
}}
|
||||
inputProps={{ 'aria-label': 'search' }}
|
||||
onChange={(event) => setSearchParams(event.target.value)}
|
||||
value={searchParams}
|
||||
/>
|
||||
</div>
|
||||
</MenuItem>
|
||||
<div className={classes.dropdownItemsScrollWrapper}>
|
||||
{currenciesListFiltered.map((currencyName) => (
|
||||
<MenuItem
|
||||
className={classes.listItem}
|
||||
key={currencyName}
|
||||
value={currencyName}
|
||||
onClick={() => onCurrentCurrencyChangedHandler(currencyName)}
|
||||
>
|
||||
<ListItemIcon className={classes.iconLeft}>
|
||||
<div
|
||||
className={classNames(classes.localFlag, style['currency-flag'], style['currency-flag-lg'], style[`currency-flag-${currencyName.toLowerCase()}`])}
|
||||
/>
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={currencyName} />
|
||||
{currencyName === currencyValueSelected
|
||||
? <ListItemIcon className={classes.iconRight}><img src={CheckIcon} alt="checked" /></ListItemIcon> : null}
|
||||
</MenuItem>
|
||||
))}
|
||||
</div>
|
||||
</Menu>
|
||||
</>
|
||||
</MuiThemeProvider>
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
export default DropdownCurrency
|
119
src/routes/safe/components/DropdownCurrency/style.js
Normal file
119
src/routes/safe/components/DropdownCurrency/style.js
Normal file
@ -0,0 +1,119 @@
|
||||
// @flow
|
||||
import { makeStyles } from '@material-ui/core/styles'
|
||||
|
||||
const buttonWidth = '140px'
|
||||
export const useDropdownStyles = makeStyles({
|
||||
listItem: {
|
||||
maxWidth: buttonWidth,
|
||||
boxSizing: 'border-box',
|
||||
},
|
||||
listItemSearch: {
|
||||
maxWidth: buttonWidth,
|
||||
padding: '0',
|
||||
boxSizing: 'border-box',
|
||||
},
|
||||
localFlag: {
|
||||
backgroundPosition: '50% 50%',
|
||||
backgroundRepeat: 'no-repeat',
|
||||
backgroundSize: 'contain',
|
||||
height: '20px !important',
|
||||
width: '26px !important',
|
||||
},
|
||||
iconLeft: {
|
||||
marginRight: '10px',
|
||||
},
|
||||
iconRight: {
|
||||
marginLeft: '18px',
|
||||
},
|
||||
button: {
|
||||
backgroundColor: '#e8e7e6',
|
||||
border: 'none',
|
||||
borderRadius: '3px',
|
||||
boxSizing: 'border-box',
|
||||
color: '#5d6d74',
|
||||
cursor: 'pointer',
|
||||
fontSize: '12px',
|
||||
fontWeight: 'normal',
|
||||
height: '24px',
|
||||
lineHeight: '1.33',
|
||||
marginRight: '20px',
|
||||
minWidth: buttonWidth,
|
||||
outline: 'none',
|
||||
padding: '0',
|
||||
textAlign: 'left',
|
||||
'&:active': {
|
||||
opacity: '0.8',
|
||||
},
|
||||
},
|
||||
buttonInner: {
|
||||
boxSizing: 'border-box',
|
||||
display: 'block',
|
||||
height: '100%',
|
||||
lineHeight: '24px',
|
||||
padding: '0 22px 0 8px',
|
||||
position: 'relative',
|
||||
width: '100%',
|
||||
'&::after': {
|
||||
borderLeft: '5px solid transparent',
|
||||
borderRight: '5px solid transparent',
|
||||
borderTop: '5px solid #5d6d74',
|
||||
content: '""',
|
||||
height: '0',
|
||||
position: 'absolute',
|
||||
right: '8px',
|
||||
top: '9px',
|
||||
width: '0',
|
||||
},
|
||||
},
|
||||
openMenuButton: {
|
||||
'&::after': {
|
||||
borderBottom: '5px solid #5d6d74',
|
||||
borderLeft: '5px solid transparent',
|
||||
borderRight: '5px solid transparent',
|
||||
borderTop: 'none',
|
||||
},
|
||||
},
|
||||
dropdownItemsScrollWrapper: {
|
||||
maxHeight: '280px',
|
||||
overflow: 'auto',
|
||||
},
|
||||
search: {
|
||||
position: 'relative',
|
||||
borderRadius: '0',
|
||||
backgroundColor: '#fff',
|
||||
'&:hover': {
|
||||
backgroundColor: '#fff',
|
||||
},
|
||||
marginRight: 0,
|
||||
width: '100%',
|
||||
},
|
||||
searchIcon: {
|
||||
alignItems: 'center',
|
||||
display: 'flex',
|
||||
height: '100%',
|
||||
justifyContent: 'center',
|
||||
left: '12px',
|
||||
margin: '0',
|
||||
pointerEvents: 'none',
|
||||
position: 'absolute',
|
||||
top: '50%',
|
||||
transform: 'translateY(-50%)',
|
||||
width: '18px',
|
||||
'& path': {
|
||||
fill: '#b2b5b2',
|
||||
},
|
||||
},
|
||||
inputRoot: {
|
||||
color: '#5d6d74',
|
||||
fontSize: '14px',
|
||||
fontWeight: 'normal',
|
||||
lineHeight: '1.43',
|
||||
width: '100%',
|
||||
},
|
||||
inputInput: {
|
||||
boxSizing: 'border-box',
|
||||
height: '44px',
|
||||
padding: '12px 12px 12px 40px',
|
||||
width: '100%',
|
||||
},
|
||||
})
|
@ -49,6 +49,7 @@ type Props = SelectorProps &
|
||||
match: Object,
|
||||
location: Object,
|
||||
history: Object,
|
||||
fetchCurrencyValues: Function,
|
||||
}
|
||||
|
||||
const Layout = (props: Props) => {
|
||||
@ -63,7 +64,6 @@ const Layout = (props: Props) => {
|
||||
blacklistedTokens,
|
||||
createTransaction,
|
||||
processTransaction,
|
||||
fetchTransactions,
|
||||
activateTokensByBalance,
|
||||
fetchTokens,
|
||||
updateSafe,
|
||||
@ -77,6 +77,9 @@ const Layout = (props: Props) => {
|
||||
hideSendFunds,
|
||||
match,
|
||||
location,
|
||||
currencySelected,
|
||||
fetchCurrencyValues,
|
||||
currencyValues,
|
||||
} = props
|
||||
|
||||
const handleCallToRouter = (_, value) => {
|
||||
@ -166,6 +169,9 @@ const Layout = (props: Props) => {
|
||||
fetchTokens={fetchTokens}
|
||||
safeName={name}
|
||||
createTransaction={createTransaction}
|
||||
currencySelected={currencySelected}
|
||||
fetchCurrencyValues={fetchCurrencyValues}
|
||||
currencyValues={currencyValues}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
@ -176,8 +182,8 @@ const Layout = (props: Props) => {
|
||||
<Transactions
|
||||
threshold={safe.threshold}
|
||||
owners={safe.owners}
|
||||
nonce={safe.nonce}
|
||||
transactions={transactions}
|
||||
fetchTransactions={fetchTransactions}
|
||||
safeAddress={address}
|
||||
userAddress={userAddress}
|
||||
currentNetwork={network}
|
||||
|
@ -1,17 +0,0 @@
|
||||
// @flow
|
||||
import { storiesOf } from '@storybook/react'
|
||||
import * as React from 'react'
|
||||
import { List } from 'immutable'
|
||||
import styles from '~/components/layout/PageFrame/index.scss'
|
||||
import Component from './Layout'
|
||||
|
||||
const FrameDecorator = (story) => <div className={styles.frame}>{story()}</div>
|
||||
|
||||
storiesOf('Routes /safe:address', module)
|
||||
.addDecorator(FrameDecorator)
|
||||
.add('Safe undefined being connected', () => (
|
||||
<Component userAddress="foo" safe={undefined} provider="METAMASK" activeTokens={List([])} fetchBalance={() => {}} />
|
||||
))
|
||||
.add('Safe undefined NOT connected', () => (
|
||||
<Component userAddress="foo" safe={undefined} provider="" activeTokens={List([])} fetchBalance={() => {}} />
|
||||
))
|
@ -1,11 +0,0 @@
|
||||
// @flow
|
||||
import { storiesOf } from '@storybook/react'
|
||||
import * as React from 'react'
|
||||
import styles from '~/components/layout/PageFrame/index.scss'
|
||||
import Component from './index.jsx'
|
||||
|
||||
const FrameDecorator = (story) => <div className={styles.frame}>{story()}</div>
|
||||
|
||||
storiesOf('Components', module)
|
||||
.addDecorator(FrameDecorator)
|
||||
.add('NoRights', () => <Component />)
|
@ -47,15 +47,15 @@ export const sendAddOwner = async (
|
||||
const gnosisSafe = await getGnosisSafeInstanceAt(safeAddress)
|
||||
const txData = gnosisSafe.contract.methods.addOwnerWithThreshold(values.ownerAddress, values.threshold).encodeABI()
|
||||
|
||||
const txHash = await createTransaction(
|
||||
const txHash = await createTransaction({
|
||||
safeAddress,
|
||||
safeAddress,
|
||||
0,
|
||||
to: safeAddress,
|
||||
valueInWei: 0,
|
||||
txData,
|
||||
TX_NOTIFICATION_TYPES.SETTINGS_CHANGE_TX,
|
||||
notifiedTransaction: TX_NOTIFICATION_TYPES.SETTINGS_CHANGE_TX,
|
||||
enqueueSnackbar,
|
||||
closeSnackbar,
|
||||
)
|
||||
})
|
||||
|
||||
if (txHash) {
|
||||
addSafeOwner({ safeAddress, ownerName: values.ownerName, ownerAddress: values.ownerAddress })
|
||||
|
@ -17,7 +17,7 @@ export const styles = () => ({
|
||||
lineHeight: 'normal',
|
||||
},
|
||||
manage: {
|
||||
fontSize: '24px',
|
||||
fontSize: lg,
|
||||
},
|
||||
closeIcon: {
|
||||
height: '35px',
|
||||
|
@ -20,7 +20,7 @@ export const styles = () => ({
|
||||
lineHeight: 'normal',
|
||||
},
|
||||
manage: {
|
||||
fontSize: '24px',
|
||||
fontSize: lg,
|
||||
},
|
||||
closeIcon: {
|
||||
height: '35px',
|
||||
|
@ -17,14 +17,14 @@ export const styles = () => ({
|
||||
lineHeight: 'normal',
|
||||
},
|
||||
manage: {
|
||||
fontSize: '24px',
|
||||
fontSize: lg,
|
||||
},
|
||||
closeIcon: {
|
||||
height: '35px',
|
||||
width: '35px',
|
||||
},
|
||||
headingText: {
|
||||
fontSize: '16px',
|
||||
fontSize: md,
|
||||
},
|
||||
formContainer: {
|
||||
padding: `${md} ${lg}`,
|
||||
|
@ -10,7 +10,7 @@ export const styles = () => ({
|
||||
boxSizing: 'border-box',
|
||||
},
|
||||
manage: {
|
||||
fontSize: '24px',
|
||||
fontSize: lg,
|
||||
},
|
||||
container: {
|
||||
padding: `${md} ${lg}`,
|
||||
|
@ -62,15 +62,15 @@ export const sendRemoveOwner = async (
|
||||
.removeOwner(prevAddress, ownerAddressToRemove, values.threshold)
|
||||
.encodeABI()
|
||||
|
||||
const txHash = await createTransaction(
|
||||
const txHash = await createTransaction({
|
||||
safeAddress,
|
||||
safeAddress,
|
||||
0,
|
||||
to: safeAddress,
|
||||
valueInWei: 0,
|
||||
txData,
|
||||
TX_NOTIFICATION_TYPES.SETTINGS_CHANGE_TX,
|
||||
notifiedTransaction: TX_NOTIFICATION_TYPES.SETTINGS_CHANGE_TX,
|
||||
enqueueSnackbar,
|
||||
closeSnackbar,
|
||||
)
|
||||
})
|
||||
|
||||
if (txHash && safe.threshold === 1) {
|
||||
removeSafeOwner({ safeAddress, ownerAddress: ownerAddressToRemove })
|
||||
|
@ -17,7 +17,7 @@ export const styles = () => ({
|
||||
marginLeft: '20px',
|
||||
},
|
||||
manage: {
|
||||
fontSize: '24px',
|
||||
fontSize: lg,
|
||||
},
|
||||
address: {
|
||||
marginRight: sm,
|
||||
|
@ -20,7 +20,7 @@ export const styles = () => ({
|
||||
marginLeft: '20px',
|
||||
},
|
||||
manage: {
|
||||
fontSize: '24px',
|
||||
fontSize: lg,
|
||||
},
|
||||
closeIcon: {
|
||||
height: '35px',
|
||||
|
@ -17,14 +17,14 @@ export const styles = () => ({
|
||||
marginLeft: '20px',
|
||||
},
|
||||
manage: {
|
||||
fontSize: '24px',
|
||||
fontSize: lg,
|
||||
},
|
||||
closeIcon: {
|
||||
height: '35px',
|
||||
width: '35px',
|
||||
},
|
||||
headingText: {
|
||||
fontSize: '16px',
|
||||
fontSize: md,
|
||||
},
|
||||
formContainer: {
|
||||
padding: `${md} ${lg}`,
|
||||
|
@ -58,15 +58,15 @@ export const sendReplaceOwner = async (
|
||||
.swapOwner(prevAddress, ownerAddressToRemove, values.ownerAddress)
|
||||
.encodeABI()
|
||||
|
||||
const txHash = await createTransaction(
|
||||
const txHash = await createTransaction({
|
||||
safeAddress,
|
||||
safeAddress,
|
||||
0,
|
||||
to: safeAddress,
|
||||
valueInWei: 0,
|
||||
txData,
|
||||
TX_NOTIFICATION_TYPES.SETTINGS_CHANGE_TX,
|
||||
notifiedTransaction: TX_NOTIFICATION_TYPES.SETTINGS_CHANGE_TX,
|
||||
enqueueSnackbar,
|
||||
closeSnackbar,
|
||||
)
|
||||
})
|
||||
|
||||
if (txHash && safe.threshold === 1) {
|
||||
replaceSafeOwner({
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user