openethereum/js/packages/dapp-vaults/store.js

432 lines
10 KiB
JavaScript
Raw Normal View History

// Copyright 2015-2017 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import { action, computed, observable, transaction } from 'mobx';
// TODO: We need to move this to a generic location, it should most probably be
// merged with the other valitation errors. Import here better than duplication.
import ERRORS from '@parity/dapp-accounts/CreateAccount/errors';
let instance;
export default class Store {
@observable isBusyAccounts = false;
@observable isBusyCreate = false;
@observable isBusyLoad = false;
@observable isBusyLock = false;
@observable isBusyMeta = false;
@observable isBusyUnlock = false;
@observable isModalAccountsOpen = false;
@observable isModalCreateOpen = false;
@observable isModalLockOpen = false;
@observable isModalMetaOpen = false;
@observable isModalUnlockOpen = false;
@observable selectedAccounts = {};
@observable vault = null;
@observable vaults = [];
Vault Management UI (round 3) (#4652) * Render Dapps via SectionList * Initial rendering of accounts via SectionList * Width vars * Allow classNames in certifications & tags * Overlay of info on hover * Adjust hover balances * Large owner icons (align with vaults) * Consistent block mined at message * Attach ParityBackground to html * Adjust page padding to align * Lint fixes * Link to different types of addresses * Make content parts clickable only (a within a) * Force Chrome hardware acceleration * Trust the vendors... don't go crazy with transform :) * Use faster & default transitions * Add VaultMeta edit dialog * Updated (WIP) * Meta & password edit completed * Added SelectionList component for selections * Use SelectionList in DappPermisions * AddDapps uses SelectionList * Fix AccountCard to consistent height * Display type icons in creation dialog * Complimentary colours * Convert Signer defaults to SelectionList * Fix Geth import - actually pass addresses through * Work from addresses returned via RPC * Display actual addresses imported (not selected) * Update tests to cover bug fixed * Prettyfy Geth import * Description on selection actions * SelectionList as entry point * Update failing tests * Subtle selection border * Styling updates for account details * Add ModalBox summary * AddAddress updated * Display account vault information * Allow invalid addresses to display icons (e.g. vaults) * Display vault on edit meta * Convert VaultAccounts to SelectionList * Allow editing of Vault in meta * Add tests for SectionList component * Add tests for ModalBox component * Add tests for VaultSelector component * Add vaultsOpened in store * Add ~/ui/Form/VaultSelect * WIP * Fix failing tests * Move account to vault when selected * Fix circular build deps * EditMeta uses Form/VaultSelect * Vault move into meta store (alignment) * Re-apply stretch fix * Display vault in account summary * Add busy indicators to relevant modals * Auto-focus description field (aligns with #4657) * Remove extra container (double scrolling) * Remove unused container style * Apply scroll fixes from lates commit in #4621 * Remove unneeded logs * Remove extra div, fixing ParityBar overflow * Make dapp iframe background white * Stop event propgation on tag click * ChangeVault component (re-usable) * Use ChangeVault component * Pass vaultStores in * Icon highlight colour * Tag-ify vault name display * ChangeVault location * Bothced merge, selector rendering twice * Value can be undefined (no vault) * Close selector on Select bug * Fix toggle botched merge * Update tests * Add Vault Tags to Account Header
2017-03-03 19:50:54 +01:00
@observable vaultsOpened = [];
@observable vaultNames = [];
@observable vaultName = '';
@observable vaultNameError = ERRORS.noName;
@observable vaultDescription = '';
@observable vaultPassword = '';
@observable vaultPasswordHint = '';
@observable vaultPasswordOld = '';
@observable vaultPasswordRepeat = '';
@observable vaultTags = [];
constructor (api) {
this._api = api;
}
@computed get vaultPasswordRepeatError () {
return this.vaultPassword === this.vaultPasswordRepeat
? null
: ERRORS.noMatchPassword;
}
@action clearVaultFields = () => {
transaction(() => {
this.setVaultName('');
this.setVaultDescription('');
this.setVaultPassword('');
this.setVaultPasswordHint('');
this.setVaultPasswordOld('');
this.setVaultPasswordRepeat('');
this.setVaultTags([]);
});
}
@action setBusyAccounts = (isBusy) => {
this.isBusyAccounts = isBusy;
}
@action setBusyCreate = (isBusy) => {
this.isBusyCreate = isBusy;
}
@action setBusyLoad = (isBusy) => {
this.isBusyLoad = isBusy;
}
@action setBusyLock = (isBusy) => {
this.isBusyLock = isBusy;
}
@action setBusyMeta = (isBusy) => {
this.isBusyMeta = isBusy;
}
@action setBusyUnlock = (isBusy) => {
this.isBusyUnlock = isBusy;
}
@action setModalAccountsOpen = (isOpen) => {
transaction(() => {
this.setBusyAccounts(false);
this.isModalAccountsOpen = isOpen;
});
}
@action setModalCreateOpen = (isOpen) => {
transaction(() => {
this.setBusyCreate(false);
this.isModalCreateOpen = isOpen;
});
}
@action setModalLockOpen = (isOpen) => {
transaction(() => {
this.setBusyLock(false);
this.isModalLockOpen = isOpen;
});
}
@action setModalMetaOpen = (isOpen) => {
transaction(() => {
this.setBusyMeta(false);
this.isModalMetaOpen = isOpen;
});
}
@action setModalUnlockOpen = (isOpen) => {
transaction(() => {
this.setBusyUnlock(false);
this.setVaultPassword('');
this.isModalUnlockOpen = isOpen;
});
}
@action setSelectedAccounts = (selectedAccounts) => {
this.selectedAccounts = selectedAccounts;
}
@action setVaults = (allVaults, openedVaults, metaData) => {
transaction(() => {
this.vaultNames = allVaults.map((name) => name.toLowerCase());
this.vaults = allVaults.map((name, index) => {
return {
meta: metaData[index] || {},
name,
isOpen: openedVaults.includes(name)
};
});
Vault Management UI (round 3) (#4652) * Render Dapps via SectionList * Initial rendering of accounts via SectionList * Width vars * Allow classNames in certifications & tags * Overlay of info on hover * Adjust hover balances * Large owner icons (align with vaults) * Consistent block mined at message * Attach ParityBackground to html * Adjust page padding to align * Lint fixes * Link to different types of addresses * Make content parts clickable only (a within a) * Force Chrome hardware acceleration * Trust the vendors... don't go crazy with transform :) * Use faster & default transitions * Add VaultMeta edit dialog * Updated (WIP) * Meta & password edit completed * Added SelectionList component for selections * Use SelectionList in DappPermisions * AddDapps uses SelectionList * Fix AccountCard to consistent height * Display type icons in creation dialog * Complimentary colours * Convert Signer defaults to SelectionList * Fix Geth import - actually pass addresses through * Work from addresses returned via RPC * Display actual addresses imported (not selected) * Update tests to cover bug fixed * Prettyfy Geth import * Description on selection actions * SelectionList as entry point * Update failing tests * Subtle selection border * Styling updates for account details * Add ModalBox summary * AddAddress updated * Display account vault information * Allow invalid addresses to display icons (e.g. vaults) * Display vault on edit meta * Convert VaultAccounts to SelectionList * Allow editing of Vault in meta * Add tests for SectionList component * Add tests for ModalBox component * Add tests for VaultSelector component * Add vaultsOpened in store * Add ~/ui/Form/VaultSelect * WIP * Fix failing tests * Move account to vault when selected * Fix circular build deps * EditMeta uses Form/VaultSelect * Vault move into meta store (alignment) * Re-apply stretch fix * Display vault in account summary * Add busy indicators to relevant modals * Auto-focus description field (aligns with #4657) * Remove extra container (double scrolling) * Remove unused container style * Apply scroll fixes from lates commit in #4621 * Remove unneeded logs * Remove extra div, fixing ParityBar overflow * Make dapp iframe background white * Stop event propgation on tag click * ChangeVault component (re-usable) * Use ChangeVault component * Pass vaultStores in * Icon highlight colour * Tag-ify vault name display * ChangeVault location * Bothced merge, selector rendering twice * Value can be undefined (no vault) * Close selector on Select bug * Fix toggle botched merge * Update tests * Add Vault Tags to Account Header
2017-03-03 19:50:54 +01:00
this.vaultsOpened = this.vaults.filter((vault) => vault.isOpen);
});
}
@action setVaultDescription = (description) => {
this.vaultDescription = description;
}
@action setVaultName = (name) => {
let nameError = null;
if (!name || !name.trim().length) {
nameError = ERRORS.noName;
} else {
const lowerName = name.toLowerCase();
if (this.vaultNames.includes(lowerName)) {
nameError = ERRORS.duplicateName;
}
}
transaction(() => {
this.vault = this.vaults.find((vault) => vault.name === name);
this.vaultName = name;
this.vaultNameError = nameError;
});
}
@action setVaultPassword = (password) => {
this.vaultPassword = password;
}
@action setVaultPasswordHint = (hint) => {
this.vaultPasswordHint = hint;
}
@action setVaultPasswordOld = (password) => {
this.vaultPasswordOld = password;
}
@action setVaultPasswordRepeat = (password) => {
this.vaultPasswordRepeat = password;
}
@action setVaultTags = (tags) => {
this.vaultTags = tags;
}
@action toggleSelectedAccount = (address) => {
this.setSelectedAccounts(Object.assign({}, this.selectedAccounts, {
[address]: !this.selectedAccounts[address] })
);
}
closeAccountsModal () {
this.setModalAccountsOpen(false);
}
closeCreateModal () {
this.setModalCreateOpen(false);
}
closeLockModal () {
this.setModalLockOpen(false);
}
closeMetaModal () {
this.setModalMetaOpen(false);
}
closeUnlockModal () {
this.setModalUnlockOpen(false);
}
openAccountsModal (name) {
transaction(() => {
this.setVaultName(name);
this.setSelectedAccounts({});
this.setModalAccountsOpen(true);
});
}
openCreateModal () {
transaction(() => {
this.clearVaultFields();
this.setModalCreateOpen(true);
});
}
openLockModal (name) {
transaction(() => {
this.setVaultName(name);
this.setModalLockOpen(true);
});
}
openMetaModal (name) {
transaction(() => {
this.clearVaultFields();
this.setVaultName(name);
if (this.vault && this.vault.meta) {
this.setVaultDescription(this.vault.meta.description);
this.setVaultPasswordHint(this.vault.meta.passwordHint);
}
this.setModalMetaOpen(true);
});
}
openUnlockModal (name) {
transaction(() => {
this.setVaultName(name);
this.setModalUnlockOpen(true);
});
}
loadVaults = () => {
this.setBusyLoad(true);
return Promise
.all([
this._api.parity.listVaults(),
this._api.parity.listOpenedVaults()
])
.then(([allVaults, openedVaults]) => {
return Promise
.all(allVaults.map((name) => this._api.parity.getVaultMeta(name)))
.then((metaData) => {
transaction(() => {
this.setBusyLoad(false);
this.setVaults(allVaults, openedVaults, metaData);
});
});
})
.catch((error) => {
console.warn('loadVaults', error);
this.setBusyLoad(false);
});
}
closeVault () {
this.setBusyLock(true);
return this._api.parity
.closeVault(this.vaultName)
.then(this.loadVaults)
.then(() => {
this.setBusyLock(false);
})
.catch((error) => {
console.error('closeVault', error);
this.setBusyLock(false);
throw error;
});
}
createVault () {
if (this.vaultNameError || this.vaultPasswordRepeatError) {
return Promise.reject();
}
this.setBusyCreate(true);
return this._api.parity
.newVault(this.vaultName, this.vaultPassword)
.then(() => {
return this._api.parity.setVaultMeta(this.vaultName, {
description: this.vaultDescription,
passwordHint: this.vaultPasswordHint,
tags: this.vaultTags
});
})
.then(this.loadVaults)
.then(() => {
this.setBusyCreate(false);
})
.catch((error) => {
console.error('createVault', error);
this.setBusyCreate(false);
throw error;
});
}
editVaultMeta () {
this.setBusyMeta(true);
return this._api.parity
.setVaultMeta(this.vaultName, {
description: this.vaultDescription,
passwordHint: this.vaultPasswordHint,
tags: this.vaultTags
})
.then(this.loadVaults)
.then(() => {
this.setBusyMeta(false);
})
.catch((error) => {
console.error('editVaultMeta', error);
this.setBusyMeta(false);
throw error;
});
}
editVaultPassword () {
this.setBusyMeta(true);
return this._api.parity
.closeVault(this.vaultName)
.then(() => {
return this._api.parity.openVault(this.vaultName, this.vaultPasswordOld);
})
.then(() => {
return this._api.parity.changeVaultPassword(this.vaultName, this.vaultPassword);
})
.then(() => {
this.setBusyMeta(false);
})
.catch((error) => {
console.error('editVaultPassword', error);
this.loadVaults();
this.setBusyMeta(false);
throw new Error('Unable to change the vault password');
});
}
openVault () {
this.setBusyUnlock(true);
return this._api.parity
.openVault(this.vaultName, this.vaultPassword)
.then(this.loadVaults)
.then(() => {
this.setBusyUnlock(false);
})
.catch((error) => {
console.error('openVault', error);
this.setBusyUnlock(false);
throw error;
});
}
moveAccounts (vaultName, inAccounts, outAccounts) {
this.setBusyAccounts(true);
return Promise
.all([
inAccounts.map((address) => this._api.parity.changeVault(address, vaultName)),
outAccounts.map((address) => this._api.parity.changeVault(address, ''))
])
.then(this.loadVaults)
.then(() => {
this.setBusyAccounts(false);
})
.catch((error) => {
console.error('moveAccounts', error);
this.setBusyAccounts(false);
throw error;
});
}
moveAccount (vaultName, address) {
this.setBusyAccounts(true);
return this._api.parity
.changeVault(address, vaultName)
.then(this.loadVaults)
.then(() => {
this.setBusyAccounts(false);
})
.catch((error) => {
console.error('moveAccount', error);
this.setBusyAccounts(false);
throw error;
});
}
static get (api) {
if (!instance) {
instance = new Store(api);
}
return instance;
}
}