diff --git a/config/deploy/deploy.sh b/config/deploy/deploy.sh
index c375961f..851809aa 100644
--- a/config/deploy/deploy.sh
+++ b/config/deploy/deploy.sh
@@ -3,6 +3,11 @@
echo "Deployment script for gnosis-safe-team"
+RANGE=500
+
+number=$RANDOM
+let "number %= $RANGE"
+
# Split on "/", ref: http://stackoverflow.com/a/5257398/689223
REPO_SLUG_ARRAY=(${TRAVIS_REPO_SLUG//\// })
REPO_OWNER=${REPO_SLUG_ARRAY[0]}
@@ -17,9 +22,9 @@ if [ "$TRAVIS_PULL_REQUEST" != "false" ]
then
if [ "$NODE_ENV" == "production" ]
then
- DEPLOY_SUBDOMAIN_UNFORMATTED_LIST+=(release-${TRAVIS_PULL_REQUEST}-pr)
+ DEPLOY_SUBDOMAIN_UNFORMATTED_LIST+=(release-${TRAVIS_PULL_REQUEST}-pr-${number})
else
- DEPLOY_SUBDOMAIN_UNFORMATTED_LIST+=(staging-${TRAVIS_PULL_REQUEST}-pr)
+ DEPLOY_SUBDOMAIN_UNFORMATTED_LIST+=(staging-${TRAVIS_PULL_REQUEST}-pr-${number})
fi
elif [ -n "${TRAVIS_TAG// }" ] #TAG is not empty
then
diff --git a/src/components/forms/TextField/index.jsx b/src/components/forms/TextField/index.jsx
index b1ca1bd6..cbc88c88 100644
--- a/src/components/forms/TextField/index.jsx
+++ b/src/components/forms/TextField/index.jsx
@@ -2,30 +2,39 @@
import React from 'react'
import MuiTextField, { TextFieldProps } from 'material-ui/TextField'
-const TextField = ({
- input: {
- name, onChange, value, ...restInput
- },
- meta,
- render,
- text,
- ...rest
-}: TextFieldProps) => {
- const helperText = value ? text : undefined
- const showError = meta.touched && !meta.valid
+// Neded for solving a fix in Windows browsers
+const overflowStyle = {
+ overflow: 'hidden',
+}
- return (
-
- )
+class TextField extends React.PureComponent {
+ render() {
+ const {
+ input: {
+ name, onChange, value, ...restInput
+ },
+ meta,
+ render,
+ text,
+ ...rest
+ } = this.props
+ const helperText = value ? text : undefined
+ const showError = (meta.touched || !meta.pristine) && !meta.valid
+
+ return (
+
+ )
+ }
}
export default TextField
diff --git a/src/components/layout/Block/index.scss b/src/components/layout/Block/index.scss
index 5ce04657..b8e523a0 100644
--- a/src/components/layout/Block/index.scss
+++ b/src/components/layout/Block/index.scss
@@ -1,7 +1,7 @@
.block {
display: inline-block;
width: 100%;
- overflow-x: hidden;
+ overflow: hidden;
}
.sm {
diff --git a/src/components/layout/Table/index.jsx b/src/components/layout/Table/index.jsx
index 77c7089b..817b7c2d 100644
--- a/src/components/layout/Table/index.jsx
+++ b/src/components/layout/Table/index.jsx
@@ -13,14 +13,20 @@ const buildWidthFrom = (size: number) => ({
minWidth: `${size}px`,
})
+const overflowStyle = {
+ overflowX: 'scroll',
+}
+
// see: https://css-tricks.com/responsive-data-tables/
const GnoTable = ({ size, children }: Props) => {
const style = size ? buildWidthFrom(size) : undefined
return (
-
+
)
}
diff --git a/src/routes/open/components/Layout.test.js b/src/routes/open/components/Layout.test.js
index 38467270..b41ed29f 100644
--- a/src/routes/open/components/Layout.test.js
+++ b/src/routes/open/components/Layout.test.js
@@ -66,16 +66,13 @@ describe('React DOM TESTS > Create Safe form', () => {
await sleep(1500)
// THEN
- const Deployed = TestUtils.findRenderedDOMComponentWithClass(open, DEPLOYED_COMPONENT_ID)
+ const deployed = TestUtils.findRenderedDOMComponentWithClass(open, DEPLOYED_COMPONENT_ID)
- const addressHtml = Deployed.getElementsByTagName('p')[0].innerHTML
- const contractAddress = addressHtml.slice(addressHtml.lastIndexOf('>') + 1)
- const transactionHash = JSON.parse(Deployed.getElementsByTagName('pre')[0].innerHTML)
- delete transactionHash.logsBloom
- // eslint-disable-next-line
- console.log('Deployed safe address is: ' + contractAddress)
-
- // eslint-disable-next-line
- console.log(transactionHash)
+ if (deployed) {
+ const transactionHash = JSON.parse(deployed.getElementsByTagName('pre')[0].innerHTML)
+ delete transactionHash.logsBloom
+ // eslint-disable-next-line
+ console.log(transactionHash)
+ }
})
})
diff --git a/src/routes/open/components/SafeForm/Confirmations/index.test.js b/src/routes/open/components/SafeForm/Confirmations/index.test.js
new file mode 100644
index 00000000..38fb0e01
--- /dev/null
+++ b/src/routes/open/components/SafeForm/Confirmations/index.test.js
@@ -0,0 +1,51 @@
+// @flow
+import TextField from '~/components/forms/TextField'
+import * as React from 'react'
+import * as TestUtils from 'react-dom/test-utils'
+import Layout from '~/routes/open/components/Layout'
+import { FIELD_CONFIRMATIONS, FIELD_OWNERS } from '~/routes/open/components/fields'
+import { getProviderInfo } from '~/wallets/getWeb3'
+import Wrapper from '~/test/Wrapper'
+import { CONFIRMATIONS_ERROR } from '~/routes/open/components/SafeForm'
+
+describe('React DOM TESTS > Create Safe form', () => {
+ beforeEach(async () => {
+ // init app web3 instance
+ await getProviderInfo()
+ })
+
+ it('should not allow to continue if confirmations are higher than owners', async () => {
+ // GIVEN
+ const open = TestUtils.renderIntoDocument((
+
+ { }}
+ />
+
+ ))
+
+ const inputs = TestUtils.scryRenderedDOMComponentsWithTag(open, 'input')
+
+ const fieldOwners = inputs[1]
+ expect(fieldOwners.name).toEqual(FIELD_OWNERS)
+ TestUtils.Simulate.change(fieldOwners, { target: { value: '1' } })
+
+ const fieldConfirmations = inputs[2]
+ expect(fieldConfirmations.name).toEqual(FIELD_CONFIRMATIONS)
+
+ // WHEN
+ TestUtils.Simulate.change(fieldConfirmations, { target: { value: '2' } })
+
+ // THEN
+ const muiFields = TestUtils.scryRenderedComponentsWithType(open, TextField)
+ expect(5).toEqual(muiFields.length)
+ const confirmationsField = muiFields[4]
+
+ expect(confirmationsField.props.meta.valid).toBe(false)
+ expect(confirmationsField.props.meta.error).toBe(CONFIRMATIONS_ERROR)
+ })
+})
diff --git a/src/routes/open/components/SafeForm/Owners/index.jsx b/src/routes/open/components/SafeForm/Owners/index.jsx
index 7158e0a3..c6423275 100644
--- a/src/routes/open/components/SafeForm/Owners/index.jsx
+++ b/src/routes/open/components/SafeForm/Owners/index.jsx
@@ -2,7 +2,7 @@
import * as React from 'react'
import Field from '~/components/forms/Field'
import TextField from '~/components/forms/TextField'
-import { composeValidators, minValue, mustBeNumber, mustBeEthereumAddress, required } from '~/components/forms/validator'
+import { composeValidators, minValue, maxValue, mustBeNumber, mustBeEthereumAddress, required } from '~/components/forms/validator'
import Block from '~/components/layout/Block'
import Col from '~/components/layout/Col'
import Heading from '~/components/layout/Heading'
@@ -14,49 +14,57 @@ type Props = {
numOwners: number,
}
-const Owners = ({ numOwners }: Props) => (
-
- Owners
-
-
+const MAX_NUMBER_OWNERS = 50
+
+const Owners = (props: Props) => {
+ const { numOwners } = props
+ const validNumber = numOwners && Number.isInteger(Number(numOwners))
+ const renderOwners = validNumber && Number(numOwners) <= MAX_NUMBER_OWNERS
+
+ return (
+
+ Owners
+
+
+
+ { renderOwners && [...Array(Number(numOwners))].map((x, index) => (
+
+
+
+ Owner Nº {index + 1}
+
+
+
+
+
+
+
+
+
+ )) }
- { numOwners && Number.isInteger(Number(numOwners)) && [...Array(Number(numOwners))].map((x, index) => (
-
-
-
- Owner Nº {index + 1}
-
-
-
-
-
-
-
-
-
- )) }
-
-)
+ )
+}
export default Owners
diff --git a/src/routes/open/components/SafeForm/index.jsx b/src/routes/open/components/SafeForm/index.jsx
index 425480a7..bf3c56e1 100644
--- a/src/routes/open/components/SafeForm/index.jsx
+++ b/src/routes/open/components/SafeForm/index.jsx
@@ -6,11 +6,13 @@ import Name from './Name'
import Owners from './Owners'
import Confirmations from './Confirmations'
+export const CONFIRMATIONS_ERROR = 'Number of confirmations can not be higher than the number of owners'
+
export const safeFieldsValidation = (values: Object) => {
const errors = {}
if (values.owners < values.confirmations) {
- errors.confirmations = 'Number of confirmations can not be higher than the number of owners'
+ errors.confirmations = CONFIRMATIONS_ERROR
}
return errors
diff --git a/src/routes/open/container/Open.jsx b/src/routes/open/container/Open.jsx
index c2cddd6b..c80aadf4 100644
--- a/src/routes/open/container/Open.jsx
+++ b/src/routes/open/container/Open.jsx
@@ -21,6 +21,20 @@ type State = {
safeTx: string,
}
+const createSafe = async (safeContract, values, userAccount, addSafe) => {
+ const accounts = getAccountsFrom(values)
+ const numConfirmations = getThresholdFrom(values)
+ const name = getSafeNameFrom(values)
+ const owners = getNamesFrom(values)
+
+ const web3 = getWeb3()
+ safeContract.setProvider(web3.currentProvider)
+
+ const safe = await safeContract.new(accounts, numConfirmations, 0, 0, { from: userAccount, gas: '5000000' })
+ addSafe(name, safe.address, numConfirmations, owners, accounts)
+ return safe
+}
+
class Open extends React.Component {
constructor() {
super()
@@ -36,19 +50,13 @@ class Open extends React.Component {
onCallSafeContractSubmit = async (values) => {
try {
const { userAccount, addSafe } = this.props
- const accounts = getAccountsFrom(values)
- const numConfirmations = getThresholdFrom(values)
- const name = getSafeNameFrom(values)
- const owners = getNamesFrom(values)
-
const web3 = getWeb3()
- this.safe.setProvider(web3.currentProvider)
- const safeInstance = await this.safe.new(accounts, numConfirmations, 0, 0, { from: userAccount, gas: '5000000' })
+ const safeInstance = await createSafe(this.safe, values, userAccount, addSafe)
const { address, transactionHash } = safeInstance
+
const transactionReceipt = await promisify(cb => web3.eth.getTransactionReceipt(transactionHash, cb))
- addSafe(name, address, numConfirmations, owners, accounts)
this.setState({ safeAddress: address, safeTx: transactionReceipt })
} catch (error) {
// eslint-disable-next-line
diff --git a/src/routes/safe/component/Safe.jsx b/src/routes/safe/component/Safe.jsx
index a69e9145..7c7b4dd9 100644
--- a/src/routes/safe/component/Safe.jsx
+++ b/src/routes/safe/component/Safe.jsx
@@ -49,7 +49,7 @@ const GnoSafe = ({ safe }: SafeProps) => (
-
+
Name
diff --git a/src/routes/safeList/container/index.jsx b/src/routes/safeList/container/index.jsx
index 0a504ccc..b878dea9 100644
--- a/src/routes/safeList/container/index.jsx
+++ b/src/routes/safeList/container/index.jsx
@@ -12,7 +12,7 @@ type Props = {
}
const SafeList = ({ safes }: Props) => (
-
+
)
diff --git a/src/test/Wrapper.jsx b/src/test/Wrapper.jsx
new file mode 100644
index 00000000..3351c228
--- /dev/null
+++ b/src/test/Wrapper.jsx
@@ -0,0 +1,18 @@
+// @flow
+import * as React from 'react'
+
+type WrapperProps = {
+ children: React$Node
+}
+
+class Wrapper extends React.PureComponent {
+ render() {
+ return (
+
+ { this.props.children }
+
+ )
+ }
+}
+
+export default Wrapper
diff --git a/test/TestSimpleStorage.sol b/test/TestSimpleStorage.sol
deleted file mode 100644
index c8ee668c..00000000
--- a/test/TestSimpleStorage.sol
+++ /dev/null
@@ -1,19 +0,0 @@
-pragma solidity ^0.4.2;
-
-import "truffle/Assert.sol";
-import "truffle/DeployedAddresses.sol";
-import "../contracts/SimpleStorage.sol";
-
-contract TestSimpleStorage {
-
- function testItStoresAValue() public {
- SimpleStorage simpleStorage = SimpleStorage(DeployedAddresses.SimpleStorage());
-
- simpleStorage.set(89);
-
- uint expected = 89;
-
- Assert.equal(simpleStorage.get(), expected, "It should store the value 89.");
- }
-
-}
diff --git a/test/simplestorage.js b/test/simplestorage.js
deleted file mode 100644
index 36ebf824..00000000
--- a/test/simplestorage.js
+++ /dev/null
@@ -1,17 +0,0 @@
-var SimpleStorage = artifacts.require("./SimpleStorage.sol");
-
-contract('SimpleStorage', function(accounts) {
-
- it("...should store the value 89.", function() {
- return SimpleStorage.deployed().then(function(instance) {
- simpleStorageInstance = instance;
-
- return simpleStorageInstance.set(89, {from: accounts[0]});
- }).then(function() {
- return simpleStorageInstance.get.call();
- }).then(function(storedData) {
- assert.equal(storedData, 89, "The value 89 was not stored.");
- });
- });
-
-});