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
This commit is contained in:
Mikhail Mikheev 2019-12-10 17:26:43 +04:00 committed by Germán Martínez
parent 1e0bf85b12
commit edf49ffc96
100 changed files with 955 additions and 4435 deletions

1
.gitignore vendored
View File

@ -1,6 +1,5 @@
node_modules/
build_webpack/
build_storybook/
.DS_Store
build/
yarn-error.log

View File

@ -1,3 +0,0 @@
import '@storybook/addon-actions/register'
import '@storybook/addon-links/register'
import '@storybook/addon-knobs/register'

View File

@ -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)

View File

@ -1 +0,0 @@
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">

View File

@ -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;
};

View File

@ -133,6 +133,7 @@ module.exports = {
{
loader: 'file-loader',
options: {
esModule: false,
name: 'img/[hash].[ext]',
esModule: false
},

View File

@ -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'>;
}

View File

@ -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'>;
}

View File

@ -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'>;
}

View File

@ -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'>;
}

View File

@ -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>;
}

View File

@ -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'>;
}

View File

@ -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, ... };
}

View File

@ -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,6 +42,7 @@
"bignumber.js": "9.0.0",
"connected-react-router": "6.6.1",
"date-fns": "2.8.1",
"dotenv": "^8.2.0",
"ethereum-ens": "0.7.8",
"final-form": "4.18.6",
"history": "4.10.1",
@ -56,6 +55,7 @@
"polished": "^3.4.2",
"qrcode.react": "1.0.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 +70,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,11 +99,6 @@
"@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",
"autoprefixer": "9.7.3",
"babel-core": "^7.0.0-bridge.0",
@ -118,7 +112,7 @@
"classnames": "^2.2.6",
"css-loader": "3.2.1",
"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,8 +136,6 @@
"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",
"truffle": "5.1.3",

View File

@ -57,6 +57,8 @@ git clone https://github.com/gnosis/safe-transaction-service.git
cd safe-transaction-history
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

View File

@ -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',

View File

@ -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

View File

@ -12,14 +12,14 @@ const useStyles = makeStyles({
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
padding: xs,
margin: `0 ${xs}`,
borderRadius: '50%',
transition: 'background-color .2s ease-in-out',
'&:hover': {
backgroundColor: '#F0EFEE',
},
},
inreasedPopperZindex: {
increasedPopperZindex: {
zIndex: 2001,
},
})
@ -32,7 +32,7 @@ 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}>

View File

@ -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)

View File

@ -0,0 +1,8 @@
// @flow
export const styles = () => ({
etherscanLink: {
display: 'flex',
alignItems: 'center',
},
})

View File

@ -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: {

View File

@ -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} />
})

View File

@ -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 />)

View File

@ -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': {

View File

@ -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} />

View File

@ -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 />)

View File

@ -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)',
},

View File

@ -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

View File

@ -13,10 +13,15 @@ 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)}`
}

View File

@ -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',
}

View File

@ -11,7 +11,7 @@ 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 { history } from '~/store'
import { secondary } from '~/theme/variables'
import { secondary, sm } from '~/theme/variables'
const getSteps = () => ['Name', 'Owners and confirmations', 'Review']
@ -30,7 +30,7 @@ type Props = {
const iconStyle = {
color: secondary,
padding: '8px',
padding: sm,
marginRight: '5px',
}

View File

@ -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>
)
})

View File

@ -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} />)

View File

@ -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)',
},
},

View File

@ -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',
},
},

View File

@ -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,
@ -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 />

View File

@ -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: {

View File

@ -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,
@ -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 />

View File

@ -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: {

View File

@ -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 />

View File

@ -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: {

View File

@ -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 />

View File

@ -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: {

View File

@ -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',

View File

@ -63,6 +63,11 @@ class Balances extends React.Component<Props, State> {
props.fetchTokens()
}
componentDidMount(): void {
const { activateTokensByBalance, safeAddress } = this.props
activateTokensByBalance(safeAddress)
}
onShow = (action: Action) => () => {
this.setState(() => ({ [`show${action}`]: true }))
}
@ -89,17 +94,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,

View File

@ -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',
},

View File

@ -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={() => {}} />
))

View File

@ -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 />)

View File

@ -17,7 +17,7 @@ export const styles = () => ({
lineHeight: 'normal',
},
manage: {
fontSize: '24px',
fontSize: lg,
},
closeIcon: {
height: '35px',

View File

@ -20,7 +20,7 @@ export const styles = () => ({
lineHeight: 'normal',
},
manage: {
fontSize: '24px',
fontSize: lg,
},
closeIcon: {
height: '35px',

View File

@ -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}`,

View File

@ -10,7 +10,7 @@ export const styles = () => ({
boxSizing: 'border-box',
},
manage: {
fontSize: '24px',
fontSize: lg,
},
container: {
padding: `${md} ${lg}`,

View File

@ -17,7 +17,7 @@ export const styles = () => ({
marginLeft: '20px',
},
manage: {
fontSize: '24px',
fontSize: lg,
},
address: {
marginRight: sm,

View File

@ -20,7 +20,7 @@ export const styles = () => ({
marginLeft: '20px',
},
manage: {
fontSize: '24px',
fontSize: lg,
},
closeIcon: {
height: '35px',

View File

@ -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}`,

View File

@ -20,7 +20,7 @@ export const styles = () => ({
marginRight: sm,
},
manage: {
fontSize: '24px',
fontSize: lg,
},
closeIcon: {
height: '35px',

View File

@ -20,7 +20,7 @@ export const styles = () => ({
lineHeight: 'normal',
},
manage: {
fontSize: '24px',
fontSize: lg,
},
address: {
marginRight: sm,

View File

@ -1,5 +1,5 @@
// @flow
import { lg } from '~/theme/variables'
import { lg, sm } from '~/theme/variables'
export const styles = () => ({
formContainer: {
@ -40,7 +40,7 @@ export const styles = () => ({
controlsRow: {
backgroundColor: 'white',
padding: lg,
borderRadius: '8px',
borderRadius: sm,
},
removeOwnerIcon: {
marginLeft: lg,

View File

@ -18,11 +18,11 @@ import Link from '~/components/layout/Link'
import Paragraph from '~/components/layout/Paragraph'
import Hairline from '~/components/layout/Hairline'
import actions, { type Actions } from './actions'
import { secondary } from '~/theme/variables'
import { secondary, md } from '~/theme/variables'
import { styles } from './style'
const openIconStyle = {
height: '16px',
height: md,
color: secondary,
}

View File

@ -14,7 +14,7 @@ export const styles = () => ({
minHeight: '369px',
},
manage: {
fontSize: '24px',
fontSize: lg,
},
close: {
height: '35px',

View File

@ -1,6 +1,6 @@
// @flow
import {
fontColor, lg, smallFontSize, border, secondaryText,
fontColor, xl, lg, smallFontSize, border, secondaryText,
} from '~/theme/variables'
export const styles = () => ({
@ -24,7 +24,7 @@ export const styles = () => ({
borderTop: `2px solid ${border}`,
},
modifyBtn: {
height: '32px',
height: xl,
fontSize: smallFontSize,
},
})

View File

@ -10,7 +10,7 @@ export const styles = () => ({
minHeight: '505px',
marginBottom: '54px',
display: 'flex',
borderRadius: '8px',
borderRadius: sm,
},
settings: {
letterSpacing: '-0.5px',
@ -25,7 +25,7 @@ export const styles = () => ({
alignItems: 'center',
cursor: 'pointer',
'&:first-child': {
borderTopLeftRadius: '8px',
borderTopLeftRadius: sm,
},
},
active: {
@ -57,7 +57,7 @@ export const styles = () => ({
},
removeSafeIcon: {
marginLeft: sm,
height: '16px',
height: md,
cursor: 'pointer',
},
})

View File

@ -1,20 +0,0 @@
// @flow
import * as React from 'react'
import Bold from '~/components/layout/Bold'
import Col from '~/components/layout/Col'
import Row from '~/components/layout/Row'
import Paragraph from '~/components/layout/Paragraph/index'
export const NO_TRANSACTION_ROW_TEST_ID = 'no-transaction-row'
const NoTransactions = () => (
<Row data-testid={NO_TRANSACTION_ROW_TEST_ID}>
<Col xs={12} center="xs" sm={10} smOffset={2} start="sm" margin="md">
<Paragraph size="lg">
<Bold>No transactions found for this Safe</Bold>
</Paragraph>
</Col>
</Row>
)
export default NoTransactions

View File

@ -11,7 +11,7 @@ export const styles = () => ({
maxHeight: '75px',
},
headingText: {
fontSize: '24px',
fontSize: lg,
},
closeIcon: {
height: '35px',

View File

@ -11,7 +11,7 @@ export const styles = () => ({
maxHeight: '75px',
},
headingText: {
fontSize: '24px',
fontSize: lg,
},
closeIcon: {
height: '35px',

View File

@ -1,36 +1,25 @@
// @flow
import React from 'react'
import { withStyles } from '@material-ui/core/styles'
import EditIcon from '@material-ui/icons/Edit'
import BlockIcon from '@material-ui/icons/Block'
import Row from '~/components/layout/Row'
import Button from '~/components/layout/Button'
import { sm, lg, background } from '~/theme/variables'
export const CONFIRM_TX_BTN_TEST_ID = 'confirm-btn'
export const EXECUTE_TX_BTN_TEST_ID = 'execute-btn'
import { xl, sm, border } from '~/theme/variables'
type Props = {
onTxConfirm: Function,
onTxCancel: Function,
onTxExecute: Function,
classes: Object,
showConfirmBtn: boolean,
onTxCancel: Function,
showCancelBtn: boolean,
showExecuteBtn: boolean,
}
const styles = () => ({
buttonRow: {
height: '56px',
justifyContent: 'center',
backgroundColor: background,
borderTop: `2px solid ${border}`,
display: 'flex',
justifyContent: 'flex-end',
padding: '10px 20px',
},
button: {
height: '32px',
'&:last-child': {
marginLeft: lg,
},
height: xl,
},
icon: {
width: '14px',
@ -42,46 +31,12 @@ const styles = () => ({
const ButtonRow = ({
classes,
onTxCancel,
onTxConfirm,
showConfirmBtn,
showCancelBtn,
showExecuteBtn,
onTxExecute,
}: Props) => (
<Row align="center" className={classes.buttonRow}>
<Row align="right" className={classes.buttonRow}>
{showCancelBtn && (
<Button className={classes.button} variant="contained" minWidth={140} color="secondary" onClick={onTxCancel}>
<BlockIcon className={classes.icon} />
{' '}
Cancel TX
</Button>
)}
{showConfirmBtn && (
<Button
className={classes.button}
variant="contained"
minWidth={140}
color="primary"
onClick={onTxConfirm}
testId={CONFIRM_TX_BTN_TEST_ID}
>
<EditIcon className={classes.icon} />
{' '}
Confirm TX
</Button>
)}
{showExecuteBtn && (
<Button
className={classes.button}
variant="contained"
minWidth={140}
color="primary"
onClick={onTxExecute}
testId={EXECUTE_TX_BTN_TEST_ID}
>
<EditIcon className={classes.icon} />
{' '}
Execute TX
Cancel tx
</Button>
)}
</Row>

View File

@ -1,67 +0,0 @@
// @flow
import React from 'react'
import { List } from 'immutable'
import { withStyles } from '@material-ui/core/styles'
import OpenInNew from '@material-ui/icons/OpenInNew'
import MuiList from '@material-ui/core/List'
import ListItem from '@material-ui/core/ListItem'
import ListItemIcon from '@material-ui/core/ListItemIcon'
import ListItemText from '@material-ui/core/ListItemText'
import Chip from '@material-ui/core/Chip'
import Identicon from '~/components/Identicon'
import Hairline from '~/components/layout/Hairline'
import { type Owner } from '~/routes/safe/store/models/owner'
import { getEtherScanLink } from '~/logic/wallets/getWeb3'
import { secondary } from '~/theme/variables'
import { shortVersionOf } from '~/logic/wallets/ethAddresses'
import { styles } from './style'
type ListProps = {
owners: List<Owner>,
classes: Object,
executionConfirmation?: Owner,
}
type OwnerProps = {
owner: Owner,
classes: Object,
isExecutor?: boolean,
}
const openIconStyle = {
height: '13px',
color: secondary,
}
const OwnerComponent = withStyles(styles)(({ owner, classes, isExecutor }: OwnerProps) => (
<ListItem key={owner.address} className={classes.owner}>
<ListItemIcon>
<Identicon address={owner.address} diameter={32} className={classes.icon} />
</ListItemIcon>
<ListItemText
primary={owner.name}
secondary={(
<a href={getEtherScanLink('address', owner.address)} target="_blank" rel="noopener noreferrer">
{shortVersionOf(owner.address, 4)}
{' '}
<OpenInNew style={openIconStyle} />
</a>
)}
/>
{isExecutor && <Chip label="EXECUTOR" color="secondary" />}
</ListItem>
))
const OwnersList = ({ owners, classes, executionConfirmation }: ListProps) => (
<>
<MuiList className={classes.ownersList}>
{executionConfirmation && <OwnerComponent owner={executionConfirmation} isExecutor />}
{owners.map((owner) => (
<OwnerComponent key={owner.address} owner={owner} />
))}
</MuiList>
<Hairline color="#d4d53d" />
</>
)
export default withStyles(styles)(OwnersList)

View File

@ -0,0 +1,92 @@
// @flow
import React from 'react'
import { withStyles } from '@material-ui/core/styles'
import Button from '~/components/layout/Button'
import Img from '~/components/layout/Img'
import EtherscanLink from '~/components/EtherscanLink'
import Identicon from '~/components/Identicon'
import Block from '~/components/layout/Block'
import Paragraph from '~/components/layout/Paragraph'
import { type Owner } from '~/routes/safe/store/models/owner'
import { styles } from './style'
import ConfirmSmallGreyIcon from './assets/confirm-small-grey.svg'
import ConfirmSmallGreenIcon from './assets/confirm-small-green.svg'
import ConfirmSmallFilledIcon from './assets/confirm-small-filled.svg'
export const CONFIRM_TX_BTN_TEST_ID = 'confirm-btn'
export const EXECUTE_TX_BTN_TEST_ID = 'execute-btn'
type OwnerProps = {
owner: Owner,
classes: Object,
userAddress: string,
confirmed?: boolean,
executor?: string,
thresholdReached: boolean,
showConfirmBtn: boolean,
showExecuteBtn: boolean,
onTxConfirm: Function,
onTxExecute: Function,
}
const OwnerComponent = ({
owner,
userAddress,
classes,
onTxConfirm,
showConfirmBtn,
showExecuteBtn,
onTxExecute,
executor,
confirmed,
thresholdReached,
}: OwnerProps) => (
<Block className={classes.container}>
<div className={confirmed || thresholdReached || executor
? classes.verticalLineProgressDone
: classes.verticalLineProgressPending}
/>
<div className={classes.iconState}>
{confirmed
? <Img src={ConfirmSmallFilledIcon} />
: thresholdReached || executor ? <Img src={ConfirmSmallGreenIcon} /> : <Img src={ConfirmSmallGreyIcon} />}
</div>
<Identicon address={owner.address} diameter={32} className={classes.icon} />
<Block>
<Paragraph className={classes.name} noMargin>
{owner.name}
</Paragraph>
<EtherscanLink className={classes.address} type="address" value={owner.address} cut={4} />
</Block>
<Block className={classes.spacer} />
{showConfirmBtn && owner.address === userAddress && (
<Button
className={classes.button}
variant="contained"
minWidth={140}
color="primary"
onClick={onTxConfirm}
testId={CONFIRM_TX_BTN_TEST_ID}
>
Confirm tx
</Button>
)}
{showExecuteBtn && owner.address === userAddress && (
<Button
className={classes.button}
variant="contained"
minWidth={140}
color="primary"
onClick={onTxExecute}
testId={EXECUTE_TX_BTN_TEST_ID}
>
Execute tx
</Button>
)}
{owner.address === executor && (
<Block className={classes.executor}>Executor</Block>
)}
</Block>
)
export default withStyles(styles)(OwnerComponent)

View File

@ -0,0 +1,65 @@
// @flow
import React from 'react'
import { List } from 'immutable'
import { withStyles } from '@material-ui/core/styles'
import OwnerComponent from './OwnerComponent'
import { type Owner } from '~/routes/safe/store/models/owner'
import { styles } from './style'
type ListProps = {
ownersWhoConfirmed: List<Owner>,
ownersUnconfirmed: List<Owner>,
classes: Object,
userAddress: string,
executor: string,
thresholdReached: boolean,
showConfirmBtn: boolean,
showExecuteBtn: boolean,
onTxConfirm: Function,
onTxExecute: Function,
}
const OwnersList = ({
userAddress,
ownersWhoConfirmed,
ownersUnconfirmed,
classes,
executor,
thresholdReached,
showConfirmBtn,
showExecuteBtn,
onTxConfirm,
onTxExecute,
}: ListProps) => (
<>
{ownersWhoConfirmed.map((owner) => (
<OwnerComponent
key={owner.address}
owner={owner}
classes={classes}
userAddress={userAddress}
executor={executor}
thresholdReached={thresholdReached}
confirmed
showExecuteBtn={showExecuteBtn}
onTxExecute={onTxExecute}
/>
))}
{ownersUnconfirmed.map((owner) => (
<OwnerComponent
key={owner.address}
owner={owner}
classes={classes}
userAddress={userAddress}
executor={executor}
thresholdReached={thresholdReached}
onTxConfirm={onTxConfirm}
showConfirmBtn={showConfirmBtn}
showExecuteBtn={showExecuteBtn}
onTxExecute={onTxExecute}
/>
))}
</>
)
export default withStyles(styles)(OwnersList)

View File

@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20">
<g fill="none" fill-rule="evenodd">
<path fill="#008C73" d="M10 0C4.489 0 0 4.489 0 10s4.489 10 10 10 10-4.489 10-10S15.511 0 10 0z"/>
<path fill="#FFF" d="M9.124 13.75L5 9.406l1.245-1.312 2.88 3.034 4.63-4.878L15 7.561z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 344 B

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20">
<circle cx="10" cy="10" r="9" fill="#FFFAF4" fill-rule="evenodd" stroke="#008C73" stroke-width="2"/>
</svg>

After

Width:  |  Height:  |  Size: 196 B

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20">
<circle cx="10" cy="10" r="9" fill="#FFFAF4" fill-rule="evenodd" stroke="#B2B5B2" stroke-width="2"/>
</svg>

After

Width:  |  Height:  |  Size: 196 B

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10" viewBox="0 0 10 10">
<circle cx="5" cy="5" r="5" fill="#008C73" fill-rule="evenodd"/>
</svg>

After

Width:  |  Height:  |  Size: 160 B

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10" viewBox="0 0 10 10">
<circle cx="5" cy="5" r="4" fill="#FFFAF4" fill-rule="evenodd" stroke="#008C73" stroke-width="2"/>
</svg>

After

Width:  |  Height:  |  Size: 194 B

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10" viewBox="0 0 10 10">
<circle cx="5" cy="5" r="4" fill="#FFFAF4" fill-rule="evenodd" stroke="#B2B5B2" stroke-width="2"/>
</svg>

After

Width:  |  Height:  |  Size: 194 B

View File

@ -1,18 +1,20 @@
// @flow
import React, { useState } from 'react'
import React from 'react'
import cn from 'classnames'
import { List } from 'immutable'
import { withStyles } from '@material-ui/core/styles'
import Tabs from '@material-ui/core/Tabs'
import Tab from '@material-ui/core/Tab'
import Block from '~/components/layout/Block'
import Col from '~/components/layout/Col'
import Row from '~/components/layout/Row'
import Hairline from '~/components/layout/Hairline'
import Img from '~/components/layout/Img'
import { type Owner } from '~/routes/safe/store/models/owner'
import { type Transaction } from '~/routes/safe/store/models/transaction'
import { TX_TYPE_CONFIRMATION } from '~/logic/safe/transactions/send'
import { EMPTY_DATA } from '~/logic/wallets/ethTransactions'
import OwnersList from './List'
import OwnersList from './OwnersList'
import ButtonRow from './ButtonRow'
import CheckLargeFilledGreenIcon from './assets/check-large-filled-green.svg'
import ConfirmLargeGreenIcon from './assets/confirm-large-green.svg'
import ConfirmLargeGreyIcon from './assets/confirm-large-grey.svg'
import { styles } from './style'
type Props = {
@ -29,7 +31,10 @@ type Props = {
onTxExecute: Function,
}
const isCancellationTransaction = (tx: Transaction, safeAddress: string) => !tx.value && tx.data === EMPTY_DATA && tx.recipient === safeAddress
const isCancellationTransaction = (
tx: Transaction,
safeAddress: string,
) => !tx.value && tx.data === EMPTY_DATA && tx.recipient === safeAddress
const OwnersColumn = ({
tx,
@ -44,31 +49,26 @@ const OwnersColumn = ({
onTxCancel,
onTxExecute,
}: Props) => {
const [tabIndex, setTabIndex] = useState(0)
const handleTabChange = (event, tabClicked) => {
setTabIndex(tabClicked)
}
const cancellationTx = isCancellationTransaction(tx, safeAddress)
const ownersWhoConfirmed = []
let currentUserAlreadyConfirmed = false
let executionConfirmation
tx.confirmations.forEach((conf) => {
if (conf.owner.address === userAddress) {
currentUserAlreadyConfirmed = true
}
if (conf.type === TX_TYPE_CONFIRMATION) {
ownersWhoConfirmed.push(conf.owner)
} else {
executionConfirmation = conf.owner
}
})
const ownersUnconfirmed = owners.filter(
(owner) => tx.confirmations.findIndex((conf) => conf.owner.address === owner.address) === -1,
)
let userIsUnconfirmedOwner
ownersUnconfirmed.some((owner) => {
userIsUnconfirmedOwner = owner.address === userAddress
return userIsUnconfirmedOwner
})
let displayButtonRow = true
if (tx.executionTxHash) {
@ -83,33 +83,51 @@ const OwnersColumn = ({
displayButtonRow = false
}
let confirmedLabel = `Confirmed [${tx.confirmations.size}/${threshold}]`
if (tx.executionTxHash) {
confirmedLabel = `Confirmed [${tx.confirmations.size}]`
}
const unconfirmedLabel = `Unconfirmed [${ownersUnconfirmed.size}]`
const showConfirmBtn = !tx.isExecuted
&& !tx.cancelled
&& userIsUnconfirmedOwner
&& !currentUserAlreadyConfirmed
&& !thresholdReached
return (
<Col xs={6} className={classes.rightCol} layout="block">
<Row>
<Tabs value={tabIndex} onChange={handleTabChange} indicatorColor="secondary" textColor="secondary">
<Tab label={confirmedLabel} />
<Tab label={unconfirmedLabel} />
</Tabs>
<Hairline color="#d4d53d" />
</Row>
<Row>
{tabIndex === 0 && <OwnersList owners={ownersWhoConfirmed} executionConfirmation={executionConfirmation} />}
</Row>
<Row>{tabIndex === 1 && <OwnersList owners={ownersUnconfirmed} />}</Row>
<Block className={cn(classes.ownerListTitle, (thresholdReached || tx.isExecuted) && classes.ownerListTitleDone)}>
<div className={classes.iconState}>
{thresholdReached || tx.isExecuted
? <Img src={CheckLargeFilledGreenIcon} />
: <Img src={ConfirmLargeGreenIcon} />}
</div>
{tx.isExecuted
? `Confirmed [${tx.confirmations.size}/${tx.confirmations.size}]`
: `Confirmed [${tx.confirmations.size}/${threshold}]`}
</Block>
<OwnersList
userAddress={userAddress}
ownersWhoConfirmed={ownersWhoConfirmed}
ownersUnconfirmed={ownersUnconfirmed}
executor={tx.executor}
thresholdReached={thresholdReached}
onTxConfirm={onTxConfirm}
onTxExecute={onTxExecute}
showConfirmBtn={showConfirmBtn}
showExecuteBtn={!tx.isExecuted && thresholdReached}
/>
<Block className={cn(classes.ownerListTitle, tx.isExecuted && classes.ownerListTitleDone)}>
<div className={thresholdReached || tx.isExecuted
? classes.verticalLineProgressDone
: classes.verticalLineProgressPending}
/>
<div className={classes.iconState}>
{!thresholdReached && !tx.isExecuted && <Img src={ConfirmLargeGreyIcon} />}
{thresholdReached && !tx.isExecuted && <Img src={ConfirmLargeGreenIcon} />}
{tx.isExecuted && <Img src={CheckLargeFilledGreenIcon} />}
</div>
Executed
</Block>
{granted && displayButtonRow && (
<ButtonRow
onTxConfirm={onTxConfirm}
onTxCancel={onTxCancel}
showConfirmBtn={!currentUserAlreadyConfirmed && !thresholdReached}
showCancelBtn={!cancellationTx}
showExecuteBtn={thresholdReached}
onTxExecute={onTxExecute}
/>
)}
</Col>

View File

@ -1,5 +1,7 @@
// @flow
import { border, sm } from '~/theme/variables'
import {
border, sm, boldFont, primary, secondary, secondaryText,
} from '~/theme/variables'
export const styles = () => ({
ownersList: {
@ -10,7 +12,23 @@ export const styles = () => ({
},
rightCol: {
boxSizing: 'border-box',
borderLeft: 'solid 1px #d4d53d',
borderLeft: `2px solid ${border}`,
},
verticalLineProgressPending: {
position: 'absolute',
borderLeft: `2px solid ${secondaryText}`,
height: '52px',
top: '-26px',
left: '29px',
zIndex: '10',
},
verticalLineProgressDone: {
position: 'absolute',
borderLeft: `2px solid ${secondary}`,
height: '52px',
top: '-26px',
left: '29px',
zIndex: '10',
},
icon: {
marginRight: sm,
@ -18,4 +36,57 @@ export const styles = () => ({
owner: {
borderBottom: `1px solid ${border}`,
},
container: {
position: 'relative',
display: 'flex',
padding: '5px 20px',
},
ownerListTitle: {
position: 'relative',
display: 'flex',
alignItems: 'center',
padding: '15px',
paddingLeft: '20px',
fontSize: '11px',
fontWeight: boldFont,
lineHeight: 1.27,
textTransform: 'uppercase',
letterSpacing: '1px',
},
ownerListTitleDone: {
color: secondary,
},
name: {
textOverflow: 'ellipsis',
overflow: 'hidden',
height: '15px',
},
address: {
height: '20px',
},
spacer: {
flex: 'auto',
},
iconState: {
width: '20px',
display: 'flex',
justifyContent: 'center',
marginRight: '10px',
zIndex: '100',
'& > img': {
display: 'block',
},
},
button: {
justifyContent: 'center',
alignSelf: 'center',
},
executor: {
borderRadius: '3px',
padding: '3px 5px',
background: border,
color: primary,
alignSelf: 'center',
fontSize: '11px',
},
})

View File

@ -50,7 +50,7 @@ type CustomDescProps = {
}
const TransferDescription = ({ value = '', symbol, recipient }: TransferDescProps) => (
<Paragraph noMargin data-testid={TRANSACTIONS_DESC_SEND_TEST_ID}>
<Block data-testid={TRANSACTIONS_DESC_SEND_TEST_ID}>
<Bold>
Send
{' '}
@ -60,33 +60,31 @@ const TransferDescription = ({ value = '', symbol, recipient }: TransferDescProp
{' '}
to:
</Bold>
<br />
<EtherscanLink type="address" value={recipient} />
</Paragraph>
</Block>
)
const SettingsDescription = ({ removedOwner, addedOwner, newThreshold }: DescriptionDescProps) => (
<>
{removedOwner && (
<Paragraph data-testid={TRANSACTIONS_DESC_REMOVE_OWNER_TEST_ID}>
<Block data-testid={TRANSACTIONS_DESC_REMOVE_OWNER_TEST_ID}>
<Bold>Remove owner:</Bold>
<br />
<EtherscanLink type="address" value={removedOwner} />
</Paragraph>
</Block>
)}
{addedOwner && (
<Paragraph data-testid={TRANSACTIONS_DESC_ADD_OWNER_TEST_ID}>
<Block data-testid={TRANSACTIONS_DESC_ADD_OWNER_TEST_ID}>
<Bold>Add owner:</Bold>
<br />
<EtherscanLink type="address" value={addedOwner} />
</Paragraph>
</Block>
)}
{newThreshold && (
<Paragraph data-testid={TRANSACTIONS_DESC_CHANGE_THRESHOLD_TEST_ID}>
<Block data-testid={TRANSACTIONS_DESC_CHANGE_THRESHOLD_TEST_ID}>
<Bold>Change required confirmations:</Bold>
<br />
{newThreshold}
</Paragraph>
<Paragraph size="md" noMargin>
{newThreshold}
</Paragraph>
</Block>
)}
</>
)
@ -95,7 +93,7 @@ const CustomDescription = ({
data, value = 0, recipient, classes,
}: CustomDescProps) => (
<>
<Paragraph noMargin data-testid={TRANSACTIONS_DESC_CUSTOM_VALUE_TEST_ID}>
<Block data-testid={TRANSACTIONS_DESC_CUSTOM_VALUE_TEST_ID}>
<Bold>
Send
{' '}
@ -105,22 +103,21 @@ const CustomDescription = ({
{' '}
to:
</Bold>
<br />
<EtherscanLink type="address" value={recipient} />
</Paragraph>
<Paragraph className={classes.txData} data-testid={TRANSACTIONS_DESC_CUSTOM_DATA_TEST_ID}>
</Block>
<Block className={classes.txData} data-testid={TRANSACTIONS_DESC_CUSTOM_DATA_TEST_ID}>
<Bold>Data (hex encoded):</Bold>
<br />
{data}
</Paragraph>
<Paragraph size="md" noMargin>
{data}
</Paragraph>
</Block>
</>
)
const TxDescription = ({ tx, classes }: Props) => {
const {
recipient, value, modifySettingsTx, removedOwner, addedOwner, newThreshold, cancellationTx, customTx, data,
recipient, value, modifySettingsTx, removedOwner, addedOwner, newThreshold, cancellationTx, customTx, creationTx, data,
} = getTxData(tx)
return (
<Block className={classes.txDataContainer}>
{modifySettingsTx && (
@ -129,7 +126,7 @@ const TxDescription = ({ tx, classes }: Props) => {
{customTx && (
<CustomDescription data={data} value={value} recipient={recipient} classes={classes} />
)}
{!cancellationTx && !modifySettingsTx && !customTx && (
{!cancellationTx && !modifySettingsTx && !customTx && !creationTx && (
<TransferDescription value={value} symbol={tx.symbol} recipient={recipient} />
)}
</Block>

View File

@ -11,6 +11,7 @@ type DecodedTxData = {
addedOwner?: string,
cancellationTx?: boolean,
customTx?: boolean,
creationTx?: boolean,
data: string,
}
@ -54,6 +55,8 @@ export const getTxData = (tx: Transaction): DecodedTxData => {
}
} else if (tx.cancellationTx) {
txData.cancellationTx = true
} else if (tx.creationTx) {
txData.creationTx = true
} else {
txData.recipient = tx.recipient
txData.value = 0

View File

@ -2,7 +2,6 @@
import React, { useState } from 'react'
import { List } from 'immutable'
import { withStyles } from '@material-ui/core/styles'
import OpenInNew from '@material-ui/icons/OpenInNew'
import Row from '~/components/layout/Row'
import Block from '~/components/layout/Block'
import Col from '~/components/layout/Col'
@ -10,11 +9,9 @@ import Bold from '~/components/layout/Bold'
import Span from '~/components/layout/Span'
import Paragraph from '~/components/layout/Paragraph'
import Hairline from '~/components/layout/Hairline'
import EtherScanLink from '~/components/EtherscanLink'
import { type Transaction } from '~/routes/safe/store/models/transaction'
import { type Owner } from '~/routes/safe/store/models/owner'
import { getEtherScanLink } from '~/logic/wallets/getWeb3'
import { shortVersionOf } from '~/logic/wallets/ethAddresses'
import { secondary } from '~/theme/variables'
import TxDescription from './TxDescription'
import OwnersColumn from './OwnersColumn'
import CancelTxModal from './CancelTxModal'
@ -36,16 +33,13 @@ type Props = {
type OpenModal = 'cancelTx' | 'approveTx' | null
const openIconStyle = {
height: '13px',
color: secondary,
}
const txStatusToLabel = {
success: 'Success',
awaiting_your_confirmation: 'Awaiting your confirmation',
awaiting_confirmations: 'Awaiting confirmations',
cancelled: 'Cancelled',
awaiting_execution: 'Awaiting execution',
pending: 'Pending',
}
const ExpandedTx = ({
@ -67,24 +61,21 @@ const ExpandedTx = ({
return (
<>
<Block>
<Block className={classes.expandedTxBlock}>
<Row>
<Col xs={6} layout="column">
<Block className={classes.txDataContainer}>
<Paragraph noMargin>
<Bold>TX hash: </Bold>
<Block align="left" className={classes.txData}>
<Bold className={classes.txHash}>TX hash:</Bold>
{tx.executionTxHash ? (
<a href={getEtherScanLink('tx', tx.executionTxHash)} target="_blank" rel="noopener noreferrer">
{shortVersionOf(tx.executionTxHash, 4)}
<OpenInNew style={openIconStyle} />
</a>
<EtherScanLink type="tx" value={tx.executionTxHash} cut={8} />
) : (
'n/a'
)}
</Paragraph>
</Block>
<Paragraph noMargin>
<Bold>TX status: </Bold>
<Span className={classes[tx.status]} style={{ fontWeight: 'bold' }}>
<Span>
{txStatusToLabel[tx.status]}
</Span>
</Paragraph>

View File

@ -1,12 +1,22 @@
// @flow
import {
md, lg, connected, error, disabled,
md, lg, connected, error, disabled, border,
} from '~/theme/variables'
export const styles = () => ({
expandedTxBlock: {
borderBottom: `2px solid ${border}`,
},
txDataContainer: {
padding: `${lg} ${md}`,
},
txData: {
display: 'flex',
alignItems: 'center',
},
awaiting_your_confirmation: {
color: disabled,
},
awaiting_confirmations: {
color: disabled,
},
@ -19,4 +29,7 @@ export const styles = () => ({
cancelled: {
color: error,
},
txHash: {
paddingRight: '3px',
},
})

View File

@ -19,6 +19,7 @@ type Props = {
const statusToIcon = {
success: OkIcon,
cancelled: ErrorIcon,
awaiting_your_confirmation: AwaitingIcon,
awaiting_confirmations: AwaitingIcon,
awaiting_execution: AwaitingIcon,
pending: <CircularProgress size={14} />,
@ -26,9 +27,10 @@ const statusToIcon = {
const statusToLabel = {
success: 'Success',
cancelled: 'Cancelled',
awaiting_confirmations: 'Awaiting',
awaiting_execution: 'Awaiting',
cancelled: 'Failed',
awaiting_your_confirmation: 'Awaiting your confirmation',
awaiting_confirmations: 'Awaiting confirmations',
awaiting_execution: 'Awaiting execution',
pending: 'Pending',
}
@ -45,7 +47,7 @@ const Status = ({ classes, status }: Props) => {
{typeof Icon === 'object' ? (
Icon
) : (
<Img src={Icon} alt="OK Icon" style={statusIconStyle} />
<Img src={Icon} alt={statusToLabel[status]} style={statusIconStyle} />
)}
<Paragraph noMargin className={classes.statusText}>
{statusToLabel[status]}

View File

@ -1,32 +1,40 @@
// @flow
import {
smallFontSize, boldFont, sm, error, disabled, primary,
boldFont, sm, lg, error, disabled, extraSmallFontSize, secondary,
} from '~/theme/variables'
export const styles = () => ({
container: {
display: 'flex',
fontSize: smallFontSize,
fontSize: extraSmallFontSize,
fontWeight: boldFont,
width: '100px',
padding: sm,
alignItems: 'center',
boxSizing: 'border-box',
height: lg,
marginTop: sm,
marginBottom: sm,
borderRadius: '3px',
},
success: {
backgroundColor: '#A1D2CA',
color: primary,
color: secondary,
},
cancelled: {
backgroundColor: 'transparent',
color: error,
border: `1px solid ${error}`,
},
awaiting_your_confirmation: {
backgroundColor: '#d4d5d3',
color: disabled,
},
awaiting_confirmations: {
backgroundColor: '#dfebff',
backgroundColor: '#d4d5d3',
color: disabled,
},
awaiting_execution: {
backgroundColor: '#dfebff',
backgroundColor: '#d4d5d3',
color: disabled,
},
pending: {
@ -34,7 +42,6 @@ export const styles = () => ({
color: '#e8673c',
},
statusText: {
marginLeft: 'auto',
textTransform: 'uppercase',
padding: '0 7px',
},
})

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="10" viewBox="0 0 14 10">
<path fill="#5D6D74" fill-rule="nonzero" d="M2.849 5L6.41 8.571 4.986 10 0 5l4.986-5L6.41 1.429 2.849 5zm8.302 0L7.59 1.429 9.014 0 14 5l-4.986 5L7.59 8.571 11.151 5z"/>
</svg>

After

Width:  |  Height:  |  Size: 265 B

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10" viewBox="0 0 10 10">
<path fill="#008C73" fill-rule="nonzero" d="M10 1.007L8.993 0 1.429 7.564V2.857H0V10h7.143V8.571H2.436z"/>
</svg>

After

Width:  |  Height:  |  Size: 202 B

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10" viewBox="0 0 10 10">
<path fill="#F02525" fill-rule="nonzero" d="M0 8.993L1.007 10l7.564-7.564v4.707H10V0H2.857v1.429h4.707z"/>
</svg>

After

Width:  |  Height:  |  Size: 202 B

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
<path fill="#5D6D74" fill-rule="nonzero" d="M6.001 8.1C4.81 8.1 3.842 7.16 3.842 6c0-1.16.967-2.1 2.16-2.1 1.192 0 2.158.94 2.158 2.1 0 1.16-.966 2.1-2.159 2.1zm4.583-1.518c.025-.192.044-.384.044-.582 0-.198-.019-.396-.044-.6l1.302-.978a.297.297 0 0 0 .074-.384l-1.234-2.076a.307.307 0 0 0-.376-.132l-1.536.6a4.503 4.503 0 0 0-1.042-.588L7.543.252A.31.31 0 0 0 7.235 0H4.768a.31.31 0 0 0-.309.252l-.228 1.59c-.389.15-.722.354-1.042.588l-1.536-.6a.307.307 0 0 0-.377.132L.043 4.038a.29.29 0 0 0 .074.384l1.301.978a4.993 4.993 0 0 0-.043.6c0 .198.019.39.043.582l-1.301.996a.29.29 0 0 0-.074.384l1.233 2.076c.074.132.241.18.377.132l1.536-.606c.32.24.653.444 1.042.594l.228 1.59a.31.31 0 0 0 .309.252h2.467a.31.31 0 0 0 .308-.252l.229-1.59a4.522 4.522 0 0 0 1.042-.594l1.536.606c.136.048.302 0 .376-.132l1.234-2.076a.297.297 0 0 0-.074-.384l-1.302-.996z"/>
</svg>

After

Width:  |  Height:  |  Size: 948 B

View File

@ -0,0 +1,44 @@
// @flow
import * as React from 'react'
import { withStyles } from '@material-ui/core/styles'
import Block from '~/components/layout/Block'
import Paragraph from '~/components/layout/Paragraph/'
import Img from '~/components/layout/Img'
import { type TransactionType } from '~/routes/safe/store/models/transaction'
import OutgoingTxIcon from './assets/outgoing.svg'
import IncomingTxIcon from './assets/incoming.svg'
import CustomTxIcon from './assets/custom.svg'
import SettingsTxIcon from './assets/settings.svg'
import { styles } from './style'
type Props = {
classes: Object,
txType: TransactionType,
}
const typeToIcon = {
outgoing: OutgoingTxIcon,
incoming: IncomingTxIcon,
custom: CustomTxIcon,
settings: SettingsTxIcon,
creation: SettingsTxIcon,
cancellation: SettingsTxIcon,
}
const typeToLabel = {
outgoing: 'Outgoing transfer',
incoming: 'Incoming transfer',
custom: 'Custom transaction',
settings: 'Modify settings',
creation: 'Safe created',
cancellation: 'Cancellation transaction',
}
const TxType = ({ classes, txType }: Props) => (
<Block className={classes.container}>
<Img src={typeToIcon[txType]} alt={typeToLabel[txType]} className={classes.img} />
<Paragraph className={classes.type} noMargin>{typeToLabel[txType]}</Paragraph>
</Block>
)
export default withStyles(styles)(TxType)

View File

@ -0,0 +1,12 @@
// @flow
export const styles = () => ({
container: {
display: 'flex',
},
img: {
marginRight: '5px',
},
type: {
height: '17px',
},
})

View File

@ -1,7 +1,9 @@
// @flow
import React from 'react'
import { format, getTime, parseISO } from 'date-fns'
import { BigNumber } from 'bignumber.js'
import { List } from 'immutable'
import TxType from './TxType'
import { type Transaction } from '~/routes/safe/store/models/transaction'
import { type SortRow, buildOrderFieldFrom } from '~/components/Table/sorting'
import { type Column } from '~/components/Table/TableHead'
@ -17,7 +19,7 @@ export const TX_TABLE_EXPAND_ICON = 'expand'
type TxData = {
nonce: number,
type: string,
type: React.ReactNode,
date: string,
amount: number | string,
tx: Transaction,
@ -47,20 +49,31 @@ export type TransactionRow = SortRow<TxData>
export const getTxTableData = (transactions: List<Transaction>): List<TransactionRow> => {
const rows = transactions.map((tx: Transaction) => {
const txDate = tx.isExecuted ? tx.executionDate : tx.submissionDate
let txType = 'Outgoing transfer'
let txType = 'outgoing'
if (tx.modifySettingsTx) {
txType = 'Modify Safe Settings'
txType = 'settings'
} else if (tx.cancellationTx) {
txType = 'Cancellation transaction'
txType = 'cancellation'
} else if (tx.customTx) {
txType = 'Custom transaction'
txType = 'custom'
} else if (tx.creationTx) {
txType = 'creation'
}
let txIndex = 1
if (tx.nonce) {
txIndex = tx.nonce + 2
} else if (tx.nonce === 0) {
txIndex = 2
}
return {
[TX_TABLE_NONCE_ID]: tx.nonce,
[TX_TABLE_TYPE_ID]: txType,
[TX_TABLE_DATE_ID]: formatDate(tx.isExecuted ? tx.executionDate : tx.submissionDate),
[buildOrderFieldFrom(TX_TABLE_DATE_ID)]: getTime(parseISO(txDate)),
[TX_TABLE_NONCE_ID]: txIndex,
[TX_TABLE_TYPE_ID]: <TxType txType={txType} />,
[TX_TABLE_DATE_ID]: tx.isExecuted
? tx.executionDate && formatDate(tx.executionDate)
: tx.submissionDate && formatDate(tx.submissionDate),
[buildOrderFieldFrom(TX_TABLE_DATE_ID)]: txDate ? getTime(parseISO(txDate)) : null,
[TX_TABLE_AMOUNT_ID]: getTxAmount(tx),
[TX_TABLE_STATUS_ID]: tx.status,
[TX_TABLE_RAW_TX_ID]: tx,
@ -74,7 +87,7 @@ export const generateColumns = () => {
const nonceColumn: Column = {
id: TX_TABLE_NONCE_ID,
disablePadding: false,
label: 'Nonce',
label: 'Id',
custom: false,
order: false,
width: 50,
@ -95,7 +108,7 @@ export const generateColumns = () => {
disablePadding: false,
label: 'Amount',
custom: false,
width: 100,
width: 120,
}
const dateColumn: Column = {
@ -112,6 +125,7 @@ export const generateColumns = () => {
disablePadding: false,
label: 'Status',
custom: true,
align: 'right',
}
const expandIconColumn: Column = {

View File

@ -26,7 +26,7 @@ export const TRANSACTION_ROW_TEST_ID = 'transaction-row'
const expandCellStyle = {
paddingLeft: 0,
paddingRight: 0,
paddingRight: 15,
}
type Props = {
@ -68,6 +68,7 @@ const TxsTable = ({
label="Transactions"
defaultOrderBy={TX_TABLE_DATE_ID}
defaultOrder="desc"
defaultRowsPerPage={25}
columns={columns}
data={filteredData}
size={filteredData.size}
@ -84,7 +85,7 @@ const TxsTable = ({
{autoColumns.map((column: Column) => (
<TableCell
key={column.id}
className={classes.cell}
className={cn(classes.cell, row.status === 'cancelled' && classes.cancelledRow)}
style={cellWidth(column.width)}
align={column.align}
component="td"
@ -98,31 +99,37 @@ const TxsTable = ({
</Row>
</TableCell>
<TableCell style={expandCellStyle}>
<IconButton disableRipple>{expandedTx === row.safeTxHash ? <ExpandLess /> : <ExpandMore />}</IconButton>
</TableCell>
</TableRow>
<TableRow>
<TableCell
style={{ paddingBottom: 0, paddingTop: 0 }}
colSpan={6}
className={classes.extendedTxContainer}
>
<Collapse
in={expandedTx === row.tx.safeTxHash}
timeout="auto"
component={ExpandedTxComponent}
unmountOnExit
tx={row[TX_TABLE_RAW_TX_ID]}
threshold={threshold}
owners={owners}
granted={granted}
userAddress={userAddress}
createTransaction={createTransaction}
processTransaction={processTransaction}
safeAddress={safeAddress}
/>
{!row.tx.creationTx && (
<IconButton disableRipple>
{expandedTx === row.safeTxHash ? <ExpandLess /> : <ExpandMore />}
</IconButton>
)}
</TableCell>
</TableRow>
{!row.tx.creationTx && (
<TableRow>
<TableCell
style={{ paddingBottom: 0, paddingTop: 0 }}
colSpan={6}
className={classes.extendedTxContainer}
>
<Collapse
in={expandedTx === row.tx.safeTxHash}
timeout="auto"
component={ExpandedTxComponent}
unmountOnExit
tx={row[TX_TABLE_RAW_TX_ID]}
threshold={threshold}
owners={owners}
granted={granted}
userAddress={userAddress}
createTransaction={createTransaction}
processTransaction={processTransaction}
safeAddress={safeAddress}
/>
</TableCell>
</TableRow>
)}
</React.Fragment>
))}
</Table>

View File

@ -1,9 +1,7 @@
// @flow
import { lg } from '~/theme/variables'
export const styles = () => ({
container: {
marginTop: lg,
marginTop: '70px',
},
row: {
cursor: 'pointer',
@ -14,11 +12,19 @@ export const styles = () => ({
expandedRow: {
backgroundColor: '#fff3e2',
},
cancelledRow: {
opacity: 0.4,
},
extendedTxContainer: {
padding: 0,
border: 0,
'&:last-child': {
padding: 0,
},
backgroundColor: '#fffaf4',
},
actions: {
display: 'flex',
justifyContent: 'flex-end',
},
})

View File

@ -1,7 +1,6 @@
// @flow
import React, { useEffect } from 'react'
import { List } from 'immutable'
import NoTransactions from '~/routes/safe/components/Transactions/NoTransactions'
import TxsTable from '~/routes/safe/components/Transactions/TxsTable'
import { type Transaction } from '~/routes/safe/store/models/transaction'
import { type Owner } from '~/routes/safe/store/models/owner'
@ -19,6 +18,8 @@ type Props = {
currentNetwork: string,
}
const TIMEOUT = process.env.NODE_ENV === 'test' ? 1500 : 5000
const Transactions = ({
transactions = List(),
owners,
@ -31,30 +32,30 @@ const Transactions = ({
fetchTransactions,
currentNetwork,
}: Props) => {
let intervalId: IntervalID
useEffect(() => {
fetchTransactions(safeAddress)
intervalId = setInterval(() => {
fetchTransactions(safeAddress)
}, TIMEOUT)
return () => clearInterval(intervalId)
}, [safeAddress])
const hasTransactions = transactions.size > 0
return (
<>
{hasTransactions ? (
<TxsTable
transactions={transactions}
threshold={threshold}
owners={owners}
userAddress={userAddress}
currentNetwork={currentNetwork}
granted={granted}
safeAddress={safeAddress}
createTransaction={createTransaction}
processTransaction={processTransaction}
/>
) : (
<NoTransactions />
)}
</>
<TxsTable
transactions={transactions}
threshold={threshold}
owners={owners}
userAddress={userAddress}
currentNetwork={currentNetwork}
granted={granted}
safeAddress={safeAddress}
createTransaction={createTransaction}
processTransaction={processTransaction}
/>
)
}

View File

@ -33,17 +33,22 @@ export type SelectorProps = {
transactions: List<Transaction>,
}
const getTxStatus = (tx: Transaction, safe: Safe): TransactionStatus => {
let txStatus = 'awaiting_confirmations'
const getTxStatus = (tx: Transaction, userAddress: string, safe: Safe): TransactionStatus => {
let txStatus
if (tx.executionTxHash) {
txStatus = 'success'
} else if (tx.cancelled) {
txStatus = 'cancelled'
} else if (tx.confirmations.size === safe.threshold) {
txStatus = 'awaiting_execution'
} else if (tx.creationTx) {
txStatus = 'success'
} else if (!tx.confirmations.size) {
txStatus = 'pending'
} else {
const userConfirmed = tx.confirmations.filter((conf) => conf.owner.address === userAddress).size === 1
const userIsSafeOwner = safe.owners.filter((owner) => owner.address === userAddress).size === 1
txStatus = !userConfirmed && userIsSafeOwner ? 'awaiting_your_confirmation' : 'awaiting_confirmations'
}
return txStatus
@ -108,8 +113,9 @@ const extendedSafeTokensSelector: Selector<GlobalState, RouterProps, List<Token>
const extendedTransactionsSelector: Selector<GlobalState, RouterProps, List<Transaction>> = createSelector(
safeSelector,
userAccountSelector,
safeTransactionsSelector,
(safe, transactions) => {
(safe, userAddress, transactions) => {
const extendedTransactions = transactions.map((tx: Transaction) => {
let extendedTx = tx
@ -117,15 +123,17 @@ const extendedTransactionsSelector: Selector<GlobalState, RouterProps, List<Tran
// it means that the transaction was cancelled (Replaced) and shouldn't get executed
let replacementTransaction
if (!tx.isExecuted) {
replacementTransaction = transactions.findLast(
(transaction) => transaction.isExecuted && transaction.nonce >= tx.nonce,
replacementTransaction = transactions.size > 1 && transactions.findLast(
(transaction) => (
transaction.isExecuted && transaction.nonce && transaction.nonce >= tx.nonce
),
)
if (replacementTransaction) {
extendedTx = tx.set('cancelled', true)
}
}
return extendedTx.set('status', getTxStatus(extendedTx, safe))
return extendedTx.set('status', getTxStatus(extendedTx, userAddress, safe))
})
return extendedTransactions

View File

@ -40,6 +40,7 @@ type TxServiceModel = {
refundReceiver: string,
safeTxHash: string,
submissionDate: string,
executor: string,
executionDate: string,
confirmations: ConfirmationServiceModel[],
isExecuted: boolean,
@ -139,6 +140,7 @@ export const buildTransactionFrom = async (
refundParams,
isExecuted: tx.isExecuted,
submissionDate: tx.submissionDate,
executor: tx.executor,
executionDate: tx.executionDate,
executionTxHash: tx.transactionHash,
safeTxHash: tx.safeTxHash,
@ -147,29 +149,54 @@ export const buildTransactionFrom = async (
modifySettingsTx,
customTx,
cancellationTx,
creationTx: tx.creationTx,
})
}
const addMockSafeCreationTx = (safeAddress) => [{
baseGas: 0,
confirmations: [],
data: null,
executionDate: null,
gasPrice: 0,
gasToken: '0x0000000000000000000000000000000000000000',
isExecuted: true,
nonce: null,
operation: 0,
refundReceiver: '0x0000000000000000000000000000000000000000',
safe: safeAddress,
safeTxGas: 0,
safeTxHash: '',
signatures: null,
submissionDate: null,
executor: '',
to: '',
transactionHash: null,
value: 0,
creationTx: true,
}]
export const loadSafeTransactions = async (safeAddress: string) => {
web3 = await getWeb3()
const url = buildTxServiceUrl(safeAddress)
const response = await axios.get(url)
const transactions: TxServiceModel[] = response.data.results
let transactions: TxServiceModel[] = addMockSafeCreationTx(safeAddress)
try {
const url = buildTxServiceUrl(safeAddress)
const response = await axios.get(url)
if (response.data.count > 0) {
transactions = transactions.concat(response.data.results)
}
} catch (err) {
console.error(`Requests for transactions for ${safeAddress} failed with 404`, err)
}
const safeSubjects = loadSafeSubjects(safeAddress)
const txsRecord = await Promise.all(
transactions.map((tx: TxServiceModel) => buildTransactionFrom(safeAddress, tx, safeSubjects)),
)
return Map().set(safeAddress, List(txsRecord))
}
export default (safeAddress: string) => async (dispatch: ReduxDispatch<GlobalState>) => {
try {
const transactions: Map<string, List<Transaction>> = await loadSafeTransactions(safeAddress)
return dispatch(addTransactions(transactions))
} catch (err) {
console.error(`Requests for transactions for ${safeAddress} failed with 404`)
}
const transactions: Map<string, List<Transaction>> = await loadSafeTransactions(safeAddress)
return dispatch(addTransactions(transactions))
}

View File

@ -124,8 +124,8 @@ const safeStorageMware = (store: Store<GlobalState>) => (next: Function) => asyn
case SET_DEFAULT_SAFE: {
if (action.payload) {
saveDefaultSafe(action.payload)
break
}
break
}
default:
break

View File

@ -4,7 +4,15 @@ import type { RecordFactory, RecordOf } from 'immutable'
import { type Confirmation } from '~/routes/safe/store/models/confirmation'
import { ZERO_ADDRESS } from '~/logic/wallets/ethAddresses'
export type TransactionStatus = 'awaiting_confirmations' | 'success' | 'cancelled' | 'awaiting_execution' | 'pending'
export type TransactionType = 'incoming' | 'outgoing' | 'settings' | 'custom' | 'creation' | 'cancellation'
export type TransactionStatus =
| 'awaiting_your_confirmation'
| 'awaiting_confirmations'
| 'success'
| 'cancelled'
| 'awaiting_execution'
| 'pending'
export type TransactionProps = {
nonce: number,
@ -25,7 +33,9 @@ export type TransactionProps = {
modifySettingsTx: boolean,
cancellationTx: boolean,
customTx: boolean,
creationTx: boolean,
safeTxHash: string,
executor: string,
executionTxHash?: string,
decimals?: number,
cancelled?: boolean,
@ -49,6 +59,7 @@ export const makeTransaction: RecordFactory<TransactionProps> = Record({
refundReceiver: ZERO_ADDRESS,
isExecuted: false,
submissionDate: '',
executor: '',
executionDate: '',
symbol: '',
executionTxHash: undefined,
@ -57,6 +68,7 @@ export const makeTransaction: RecordFactory<TransactionProps> = Record({
modifySettingsTx: false,
cancellationTx: false,
customTx: false,
creationTx: false,
status: 'awaiting',
decimals: 18,
isTokenTransfer: false,

View File

@ -1,27 +0,0 @@
// @flow
import { select } from '@storybook/addon-knobs'
import { storiesOf } from '@storybook/react'
import * as React from 'react'
import styles from '~/components/layout/PageFrame/index.scss'
import Component from './Layout'
const FrameDecorator = (story) => <div className={styles.frame}>{story()}</div>
storiesOf('Routes /welcome', module)
.addDecorator(FrameDecorator)
.add('Welcome with Gnosis Safe connected', () => {
const provider = select('Status by Provider', ['', 'UNKNOWN', 'SAFE', 'METAMASK', 'PARITY'], 'SAFE')
return <Component provider={provider} fetchProvider={() => {}} />
})
.add('Welcome with Metamask connected', () => {
const provider = select('Status by Provider', ['', 'UNKNOWN', 'SAFE', 'METAMASK', 'PARITY'], 'METAMASK')
return <Component provider={provider} fetchProvider={() => {}} />
})
.add('Welcome with unknown wallet', () => {
const provider = select('Status by Provider', ['', 'UNKNOWN', 'SAFE', 'METAMASK', 'PARITY'], 'UNKNOWN')
return <Component provider={provider} fetchProvider={() => {}} />
})
.add('Welcome without wallet connected', () => {
const provider = select('Status by Provider', ['', 'UNKNOWN', 'SAFE', 'METAMASK', 'PARITY'], '')
return <Component provider={provider} fetchProvider={() => {}} />
})

View File

@ -63,7 +63,7 @@ export default createMuiTheme({
},
color: disabled,
textTransform: 'none',
borderRadius: '8px',
borderRadius: sm,
},
contained: {
boxShadow: '1px 2px 10px 0 rgba(212, 212, 211, 0.59)',
@ -102,7 +102,7 @@ export default createMuiTheme({
},
MuiStepper: {
root: {
padding: '24px 0 0 15px',
padding: `${lg} 0 0 15px`,
},
},
MuiIconButton: {
@ -238,6 +238,7 @@ export default createMuiTheme({
},
MuiTablePagination: {
toolbar: {
paddingRight: '15px',
'& > span:nth-child(2)': {
order: 1,
},
@ -255,11 +256,11 @@ export default createMuiTheme({
input: {
order: 2,
width: '60px',
padding: `0 ${md} 0 0`,
color: disabled,
},
select: {
paddingRight: 30,
minWidth: '20px',
minWidth: lg,
},
actions: {
order: 4,
@ -270,6 +271,9 @@ export default createMuiTheme({
root: {
fontSize: extraSmallFontSize,
},
active: {
fontWeight: boldFont,
},
},
MuiTableCell: {
root: {
@ -280,7 +284,6 @@ export default createMuiTheme({
head: {
letterSpacing: '1px',
textTransform: 'uppercase',
fontWeight: boldFont,
},
body: {
color: primary,

2897
yarn.lock

File diff suppressed because it is too large Load Diff