diff --git a/js/src/modals/EditMeta/editMeta.js b/js/src/modals/EditMeta/editMeta.js
index aea7a7060..8b5e14939 100644
--- a/js/src/modals/EditMeta/editMeta.js
+++ b/js/src/modals/EditMeta/editMeta.js
@@ -85,7 +85,7 @@ export default class EditMeta extends Component {
defaultMessage='(optional) tags' />
}
onTokensChange={ this.store.setTags }
- tokens={ tags } />
+ tokens={ tags.slice() } />
);
diff --git a/js/src/modals/EditMeta/editMeta.spec.js b/js/src/modals/EditMeta/editMeta.spec.js
index b490fcdaf..917f32076 100644
--- a/js/src/modals/EditMeta/editMeta.spec.js
+++ b/js/src/modals/EditMeta/editMeta.spec.js
@@ -20,7 +20,7 @@ import sinon from 'sinon';
import EditMeta from './';
-import { ACCOUNT } from './editMeta.test.js';
+import { ACCOUNT, createApi } from './editMeta.test.js';
let component;
let onClose;
@@ -35,12 +35,7 @@ function render (props) {
onClose={ onClose } />,
{
context: {
- api: {
- parity: {
- setAccountName: sinon.stub().resolves(),
- setAccountMeta: sinon.stub().resolves()
- }
- }
+ api: createApi()
}
}
);
diff --git a/js/src/modals/EditMeta/editMeta.test.js b/js/src/modals/EditMeta/editMeta.test.js
index 7f359a405..98bd61fea 100644
--- a/js/src/modals/EditMeta/editMeta.test.js
+++ b/js/src/modals/EditMeta/editMeta.test.js
@@ -14,6 +14,8 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see .
+import sinon from 'sinon';
+
const ACCOUNT = {
address: '0x123456789a123456789a123456789a123456789a',
meta: {
@@ -39,7 +41,17 @@ const ADDRESS = {
name: 'Random address'
};
+function createApi () {
+ return {
+ parity: {
+ setAccountName: sinon.stub().resolves(),
+ setAccountMeta: sinon.stub().resolves()
+ }
+ };
+}
+
export {
ACCOUNT,
- ADDRESS
+ ADDRESS,
+ createApi
};
diff --git a/js/src/modals/EditMeta/store.js b/js/src/modals/EditMeta/store.js
index 3f0355e84..b2d71c63a 100644
--- a/js/src/modals/EditMeta/store.js
+++ b/js/src/modals/EditMeta/store.js
@@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see .
-import { action, computed, observable, toJS, transaction } from 'mobx';
+import { action, computed, observable, transaction } from 'mobx';
import { newError } from '~/redux/actions';
import { validateName } from '~/util/validation';
@@ -23,25 +23,27 @@ export default class Store {
@observable address = null;
@observable isAccount = false;
@observable description = null;
- @observable meta = {};
+ @observable meta = null;
@observable name = null;
@observable nameError = null;
@observable passwordHint = null;
- @observable tags = [];
+ @observable tags = null;
constructor (api, account) {
const { address, name, meta, uuid } = account;
this._api = api;
- this.isAccount = !!uuid;
- this.address = address;
- this.meta = Object.assign({}, meta || {});
- this.name = name || '';
+ transaction(() => {
+ this.isAccount = !!uuid;
+ this.address = address;
+ this.meta = meta || {};
+ this.name = name || '';
- this.description = this.meta.description || '';
- this.passwordHint = this.meta.passwordHint || '';
- this.tags = [].concat((meta || {}).tags || []);
+ this.description = this.meta.description || '';
+ this.passwordHint = this.meta.passwordHint || '';
+ this.tags = this.meta.tags && this.meta.tags.peek() || [];
+ });
}
@computed get hasError () {
@@ -70,7 +72,7 @@ export default class Store {
}
@action setTags = (tags) => {
- this.tags = [].concat(tags);
+ this.tags = tags.slice();
}
save () {
@@ -86,7 +88,7 @@ export default class Store {
return Promise
.all([
this._api.parity.setAccountName(this.address, this.name),
- this._api.parity.setAccountMeta(this.address, Object.assign({}, toJS(this.meta), meta))
+ this._api.parity.setAccountMeta(this.address, Object.assign({}, this.meta, meta))
])
.catch((error) => {
console.error('onSave', error);
diff --git a/js/src/modals/EditMeta/store.spec.js b/js/src/modals/EditMeta/store.spec.js
index e69656e96..c707d1f6c 100644
--- a/js/src/modals/EditMeta/store.spec.js
+++ b/js/src/modals/EditMeta/store.spec.js
@@ -14,22 +14,14 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see .
-import { toJS } from 'mobx';
-import sinon from 'sinon';
-
import Store from './store';
-import { ACCOUNT, ADDRESS } from './editMeta.test.js';
+import { ACCOUNT, ADDRESS, createApi } from './editMeta.test.js';
let api;
let store;
function createStore (account) {
- api = {
- parity: {
- setAccountName: sinon.stub().resolves(),
- setAccountMeta: sinon.stub().resolves()
- }
- };
+ api = createApi();
store = new Store(api, account);
@@ -56,12 +48,12 @@ describe('modals/EditMeta/Store', () => {
});
it('extracts the tags', () => {
- expect(store.tags.peek()).to.deep.equal(ACCOUNT.meta.tags);
+ expect(store.tags).to.deep.equal(ACCOUNT.meta.tags);
});
describe('meta', () => {
it('extracts the full meta', () => {
- expect(toJS(store.meta)).to.deep.equal(ACCOUNT.meta);
+ expect(store.meta).to.deep.equal(ACCOUNT.meta);
});
it('extracts the description', () => {
diff --git a/js/src/modals/PasswordManager/passwordManager.js b/js/src/modals/PasswordManager/passwordManager.js
index 8121e14d2..0f7a08f27 100644
--- a/js/src/modals/PasswordManager/passwordManager.js
+++ b/js/src/modals/PasswordManager/passwordManager.js
@@ -14,54 +14,55 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see .
-import React, { Component, PropTypes } from 'react';
-import ContentClear from 'material-ui/svg-icons/content/clear';
-import CheckIcon from 'material-ui/svg-icons/navigation/check';
-import SendIcon from 'material-ui/svg-icons/content/send';
-
-import { Tabs, Tab } from 'material-ui/Tabs';
import Paper from 'material-ui/Paper';
+import { Tabs, Tab } from 'material-ui/Tabs';
+import { observer } from 'mobx-react';
+import React, { Component, PropTypes } from 'react';
+import { FormattedMessage } from 'react-intl';
-import { connect } from 'react-redux';
-import { bindActionCreators } from 'redux';
-import { showSnackbar } from '~/redux/providers/snackbarActions';
-
-import Form, { Input } from '~/ui/Form';
+import { newError, showSnackbar } from '~/redux/actions';
import { Button, Modal, IdentityName, IdentityIcon } from '~/ui';
+import Form, { Input } from '~/ui/Form';
+import { CancelIcon, CheckIcon, SendIcon } from '~/ui/Icons';
+import Store, { CHANGE_ACTION, TEST_ACTION } from './store';
import styles from './passwordManager.css';
-const TEST_ACTION = 'TEST_ACTION';
-const CHANGE_ACTION = 'CHANGE_ACTION';
+const MSG_SUCCESS_STYLE = {
+ backgroundColor: 'rgba(174, 213, 129, 0.75)'
+};
+const MSG_FAILURE_STYLE = {
+ backgroundColor: 'rgba(229, 115, 115, 0.75)'
+};
+const TABS_INKBAR_STYLE = {
+ backgroundColor: 'rgba(255, 255, 255, 0.55)'
+};
+const TABS_ITEM_STYLE = {
+ backgroundColor: 'rgba(255, 255, 255, 0.05)'
+};
-class PasswordManager extends Component {
+@observer
+export default class PasswordManager extends Component {
static contextTypes = {
api: PropTypes.object.isRequired
}
static propTypes = {
account: PropTypes.object.isRequired,
- showSnackbar: PropTypes.func.isRequired,
onClose: PropTypes.func
}
- state = {
- action: TEST_ACTION,
- waiting: false,
- showMessage: false,
- message: { value: '', success: true },
- currentPass: '',
- newPass: '',
- repeatNewPass: '',
- repeatValid: true,
- passwordHint: this.props.account.meta && this.props.account.meta.passwordHint || ''
- }
+ store = new Store(this.context.api, this.props.account);
render () {
return (
+ }
visible>
{ this.renderAccount() }
{ this.renderPage() }
@@ -71,150 +72,168 @@ class PasswordManager extends Component {
}
renderMessage () {
- const { message, showMessage } = this.state;
+ const { infoMessage } = this.store;
- const style = message.success
- ? {
- backgroundColor: 'rgba(174, 213, 129, 0.75)'
- }
- : {
- backgroundColor: 'rgba(229, 115, 115, 0.75)'
- };
-
- const classes = [ styles.message ];
-
- if (!showMessage) {
- classes.push(styles.hideMessage);
+ if (!infoMessage) {
+ return null;
}
return (
- { message.value }
+ className={ `${styles.message}` }
+ style={
+ infoMessage.success
+ ? MSG_SUCCESS_STYLE
+ : MSG_FAILURE_STYLE
+ }
+ zDepth={ 1 }>
+ { infoMessage.value }
);
}
renderAccount () {
- const { account } = this.props;
- const { address, meta } = account;
-
- const passwordHint = meta && meta.passwordHint
- ? (
-
- Hint
- { meta.passwordHint }
-
- )
- : null;
+ const { address, passwordHint } = this.store;
return (
-
+
+ className={ styles.accountName }
+ unknown />
{ address }
- { passwordHint }
+
+ Hint
+ { passwordHint || '-' }
+
);
}
renderPage () {
- const { account } = this.props;
- const { waiting, repeatValid } = this.state;
- const disabled = !!waiting;
-
- const repeatError = repeatValid
- ? null
- : 'the two passwords differ';
-
- const { meta } = account;
- const passwordHint = meta && meta.passwordHint || '';
+ const { busy, isRepeatValid, passwordHint } = this.store;
return (
+ inkBarStyle={ TABS_INKBAR_STYLE }
+ tabItemContainerStyle={ TABS_ITEM_STYLE }>
-
-