Browse Source

Merge next into master (#529)

* Update API deps

* Duplicate new Api from api

* Explorer renders

* Cleanup trapping

* Allow Moment values

* Vector -> Array

* Add mapping FIXME

* Updates

* proposals -> publicProposals

* QueueTx

* nonce -> accountNonce

* Cleanup (some) naming

* FIXME

* Cleanups

* cmp & isZero on UInt

* WIP... storage dropdowns may work after latest API PR...

* Misplaced .public

* Update exposed methods

* Remove getBlock checks (available in poc-3)

* Align method/section

* Align with API (method)

* api-codec -> types

* Reanme API interfaces

* Type updates, still very much a WIP

* We have updating queries... without params

* Chainstate app is working

* Get rid of some params imports

* Cleanups

* Remove app-example... outdated, non-working

* Remove app-example link from README

* Additional cleanups

* InputRpc dropdowns working

* We can make transfers (Transfer app)

* Call doesn't encode toU8a

* Cleanup to use extrinsics from Api

* Remove references to @polkadot/params

* Update deps

* Submitting transactions hsould work in app-*

* Bump

* Extrinsics app renders

* Extrinsic app can transfer

* Adapt travis.yml

* Force things to pass checks...

* Update @polkadot/dev for gh-pages -> next

* Bump dev (hopefully now gh-pages deploy)

* Default theme

* Don't skip signer for sending

* Don't throw on unknown types

* Signer queue rework

* Render input params for rpc

* Explorer click-through working

* Update deps

* WIP#327 - app-accounts with ss58 address inputs

* transformtoss58 returns valid address or null

* syntax

* app-accounts

* app-democracy

* app-extrinsics

* app-rpc

* app-staking

* app-transfer

* Generate ui-identicon from ss58 as input

currently handling null address with null return - there should be a better way to do this but it "works".

* ui-app

adapt onChange Props params

* manage identities with ss58 addresses rather than u8a.

also currently handling null value input, should be a better way to handle this but currently "works".

* ui-signer use ss58 address in keyring

* ui-signer combine duplicate imports

* ui-signer signMessage with ss58 address

derive public key by decoding ss58 input

* use 'accountId' as variable name instead of 'ss58'

* Addressing some issues

* sanity check for accountId by decoding and checking public key

* allow u8a account id types for more flexibility around short address input types in the future

* throw error on generate identicon with empty seed

* fix: accountId over publicKey

Transactions work in extrinsics and transfers.

* fix linting errors in  rpc, addresses, transfer, identicon

* accountId in stakelist

* Allow file upload for Bytes

* Extrinsic change updates correctly, Params track codec instances

* Unused import

* Cleanup conflicts, linting

* [next] Display balance with μ, k & m (#350)

* Display balance with μ, k & m

* balanceFormat to handle UInt

* let -> const

* Format static Balance properly

* Take care of new extrinsics format

* m -> M (not mili, mega)

* [next] Proposals & democracy updates (#352)

* Update README.md

* Proposals actually submit (non-valid atm)

* New API package

* Promposal propose

* Poposal decoding

* Proposal & Referendums show up

* Formats

* Proposal & voting works as expected

* Staking works as expected

* Staking & Democracy fully operational

* Update package.json

* [next] Update API deps (#354)

* Update API deps

* Update type locations

* Update api deps

* [next] Add mnemonic support from keyring (#356)

* Add mnemonic support from keyring

* Bump @polkadot/api

* Bump dependencies (#358)

* [next] Add app-settings (#359)

* [next] Add app-settings

* Update deps, cleanups

* Re-encode address for adding

* Action for seedType selection

* Revert denominations (#360)

* [next] Dependency bumps (#362)

* Bump API decoding

* Bump deps

* [next] Chain configs (#361)

* Revert denominations

* Chain Id

* Distinct colours

* Cleanup options for settings

* Adjust tests aftrer colour change

* Gated on isConnected & isReady

* Allow selection/add of AccountIndex

* Remove examples (code removed already)

* Reverse Id <-> Index lookups

* Index reverse lookups

* Usable AccountIndex

* [next] Bump API (#363)

* [next] Merge master (#364)

* Update README.md

* Re-lock account only after save

* trying to get mapping of nominators correct (#346)

* trying to get mapping of nominators correct

* changed double quote to single

* Fix for disabled chain state button bug (#351)

* merge prev and next params on Selection key change

* build error

* [next] Balance formatting (#365)

* Update README.md

* Re-lock account only after save

* trying to get mapping of nominators correct (#346)

* trying to get mapping of nominators correct

* changed double quote to single

* Fix for disabled chain state button bug (#351)

* merge prev and next params on Selection key change

* build error

* Load order (we need chain)

* Dropdown for seed type selection

* Allow SI unit selection on number inputs

* Remove unused function

* Cleanup BalanceFormatter

* Fix tests

* [next] Bump API version (#366)

* Bump API version

* Proposal construction & chain units

* Update Extrinsic -> Call

* Pass correct call params

* Cleanup linting

* Re-encode address on loading

* Bump

* Lint fix.

* [next] Import from package indexes (#370)

* [next] Import form package indexes

* Update deps, fix Transfer balance checks

* Add error on unlock

* Save account with hex encoded (not address)

* Import InputAddress for swap

* Bump @polkadot/api (staking nominators show up)

* Align api & util deps

* Bump @polkadot/api

* [next] Bump API, adjust call/method (#372)

* Bump API, adjust call/method

* Add votes correctly to yay/nay

* [next] Local Testnet

* Don't link block 0

* [next] FF Warning message (#374)

* FF Warning message

* Bump deps, massage message a bit

* Bump deps

* i18next upgrade changes

* Bump yarn to 1.10.1 in engines, travis (#379)

* [next] submitAndWatchExtrinsic for transactions (#377)

* WIP: Replace submitExtrinsic with submitAndWatchExtrinsic

TODO:
* don't `complete` when calling send, rather update as update messages come in from API
* adjust queue statuses in UI with new Status codec type from API.

* update api wrapper for subscribeAndWatch

* Update index.tsx

* subscribe to updates

* remove unneeded subscribe

* display result type

* Wrap up submitAndWatch status display

* Status background colours

* Revert indent

* Queue status icons (#380)

* [next] Bump dependencies (#383)

* Bump dependencies

* Update mock creation

* Don't mangle classes via uglify (#384)

* [next] Update status overlay styling (#385)

* Update status overlay styling

* Adjust colours for status messages

* Slight padding adjustments

* [next] refactor: Create export index files in ui-react-rx/src/{with/util} for single line destructuring imports (#388)

* refactor: Create ui-react-rx/src/with index of exports. Import single line destructuring

* refactor: Create ui-react-rx/src/util index of exports. Import single line destructuring

* refactor: Use ui-react-rx/src/ index of exports. Import single line destructuring

* refactor: Refactor to use exported index

* refactor: Refactor to use another exported index

* fix: Add missing license headers. Avoid import from index in same location

* [next] Support latest substrate master (#390)

* Update deps (api, compact support)

* Bump deps

* Update deps

* Compact<BlockNumber> for Header

* Handle Compact<*> rendering

* Cleanup warnings

* Update deps

* Not perfect, but warn on (invalid) hashes for blocks

* [next] keyring classify (#393)

* refactor: reorder imports and props alphabetically

* fix: Make class methods private

* fix: Restrict user restoring account to select only .json. Add missing withLabel

* refactor: Replace onBack with onCreateAccount and onRestoreAccount

* fix: Show console.log of error in try/catch of Backup/Restore

* fix: accountAll is array of objects

* refactor: Move Backup keyring logic into ui-keyring

* refactor: Move restoreAccount logic into ui-keyring

* refactor: Move validatePass to ui-keyring as isPassValid with MAX_PASSWORD_LEN

* refactor: Issue #138 convert closure to separate function declare, call, export

* refactor: Issue #138 convert function to ES6 class object

* refactor: Move addPair, create, createMnemonic, restore, save into Keyring class

* refactor: Move backup/encrypt/forget account, get accounts, and save account meta functions into Keyring class

* refactor: Move get address/addresses, forget/save address, and save recent functions into Keyring class

* refactor: Move isPassValid, isAvailable functions into Keyring class

* refactor: Move loadAll into Keyring class

* refactor: Move much of ui-keyring/options into Keyring class

* refactor: Move private methods to top of class

* fix: fix: Prevent creating multiple instances of Keyring class

* Prevent creating multiple instances of Keyring class. i.e. the following does not create the second instance:

```
const keyringInstance = new Keyring();
const keyringInstance2 = new Keyring();
```

* References:
	* https://codepen.io/JoeCoulam/pen/mRqbzz
	* https://medium.com/@dmnsgn/singleton-pattern-in-es6-d2d021d150ae
	* https://stackoverflow.com/questions/26205565/converting-singleton-js-objects-to-use-es6-classes/26227662#26227662

* fix: Prevent calling initOptions of Keyring singleton multiple times

* the following calls to initOptions are prevented since initOptions called when instance created with by loadAll() function:

```
const keyringInstance = new Keyring();
keyringInstance.initOptions();
keyringInstance.initOptions();
```

* test: Add test for Keyring singeton instance check and so initOptions only callable once

* feat: Move Keyring options back. Remove singleton check. Move initOptions check. Only export Keyring instance

* Move keyring options back into options folder

* Remove checking if Keyring is singleton

* Move checking if initOptions called multiple times and associated tests out of Keyring and into options folder file

* Add type to pair to fix linting

* Remove exporting Keyring class, only Keyring instance is exported

* refactor: Class-ify the Keyring options directory into a class named

* fix: Store state outside of Keyring instance

* refactor: Move keyring state into Keyring class. Add getters and setters

* Move observable accounts and addresses into Keyring class.

* Rename KeyringInstance interface to KeyringStruct (similar to app-settings)

* Add getter for keyring, accounts, and addresses to Keyring

* Add setter for keyring

* Add AccountSubject type

* Fix State type to use AccountSubject instead of AddressSubject

* Small private member tweaks

* Rework (overzealous private members)

* Fix rename in test

* [next] Block explorer event display (#392)

* Update README.md

* Re-lock account only after save

* trying to get mapping of nominators correct (#346)

* trying to get mapping of nominators correct

* changed double quote to single

* Fix for disabled chain state button bug (#351)

* merge prev and next params on Selection key change

* build error

* Updated required Node version in README (#367)

The minimum Node version is 10.1.0 as specified in the package.json 'engines'. The installation fails if the node version is below that (eg. v10.0.0 ), that's why I changed it in the README

* Simple (unformatted) event display

* section, method + types

* Display events on explorer

* Styling & overflow fixes

* Fix linting issues

* Node 10.13.0 LTS

* Revert message on block, reduce flicker

* [next] Update nvmrc version. Add missing packages to Readme. Indicate LTS required (#395)

* docs: Fix typo in Readme

* fix: Update nvmrc to version in package.json

* docs: Add missing packages to Readme. Indicate that LTS is required

* Render logs in expanded block display (#396)

* [next] Cleanup staking list balance displays (#397)

* Cleanup staking list balance displays

* Don't naked map balances (params passed)

* Cleanup block display with cleaner formatting (#398)

* Only filter dev accounts when in dev (#401)

* [next] Move BIP generation to worker (UI responsiveness) (#400)

* Move BIP generation to worker (responsive)

* Test & cleanup via local prod build

* [next] Fix length encoding for uploaded Bytes (#405)

* Fix length encoding for uploaded Bytes

* Remove addressed FIXME

* Cleanup linting, adjust encoding via helpers

* [next] Handle null nonce in extrinsics (in addition to undefined) (#407)

* Handle null nonce (in addition to undefined)

* Adjust types for partials

* Helper for submit RPC

* [next] Highlight validators (#402)

* Add isHiglight to IdentityIcon

* Display validator highlight in Address{Row,Summary}

* Highlight validators in AddressMini

* Highlight validators in AddressInput

* Display zero balalnce as 0 instead of 0.000f (#408)

* Cleanup explorer header display (#410)

* [next] Align article headers (all h3, no extra classes) (#411)

* Align article headers (all h3, no extra classes)

* Adjust overflowing columns in explorer

* Adjust app contemnt to cover screen (#412)

* [next] Retrieve hash instead of calculating (slower) (#415)

* Retrieve hash instead of calculating (slower)

* Cleanups

* Allow raw-key queries via the storage app (#416)

[next] Allow raw-key queries via the storage app

* [next] Remove IdentityIcon bond dependencies (#419)

* Remove IdentityIcon bond dependencies

* Cleanup tests

* Update README

* Update header

* Update headers

* Catch & display observable status errors (#422)

* [next] refactor: Move backup/restore functionality to Keyring. See details (#386)

* refactor: reorder imports and props alphabetically

* fix: Make class methods private

* fix: Restrict user restoring account to select only .json. Add missing withLabel

* refactor: Replace onBack with onCreateAccount and onRestoreAccount

* fix: Show console.log of error in try/catch of Backup/Restore

* fix: accountAll is array of objects

* refactor: Move Backup keyring logic into ui-keyring

* refactor: Move restoreAccount logic into ui-keyring

* refactor: Move validatePass to ui-keyring as isPassValid with MAX_PASSWORD_LEN

* fix: Change allAccounts type to SubjectInfo

* refactor: Example with clearer usage of  for React Dropzone

* [next] refactor: Issue #138. Convert closure into ES6 class object. Move methods into class (#387)

* refactor: Issue #138 convert closure to separate function declare, call, export

* refactor: Issue #138 convert function to ES6 class object

* refactor: Move addPair, create, createMnemonic, restore, save into Keyring class

* refactor: Move backup/encrypt/forget account, get accounts, and save account meta functions into Keyring class

* refactor: Move get address/addresses, forget/save address, and save recent functions into Keyring class

* refactor: Move isPassValid, isAvailable functions into Keyring class

* refactor: Move loadAll into Keyring class

* refactor: Move much of ui-keyring/options into Keyring class

* refactor: Move private methods to top of class

* fix: fix: Prevent creating multiple instances of Keyring class

* Prevent creating multiple instances of Keyring class. i.e. the following does not create the second instance:

```
const keyringInstance = new Keyring();
const keyringInstance2 = new Keyring();
```

* References:
	* https://codepen.io/JoeCoulam/pen/mRqbzz
	* https://medium.com/@dmnsgn/singleton-pattern-in-es6-d2d021d150ae
	* https://stackoverflow.com/questions/26205565/converting-singleton-js-objects-to-use-es6-classes/26227662#26227662

* fix: Prevent calling initOptions of Keyring singleton multiple times

* the following calls to initOptions are prevented since initOptions called when instance created with by loadAll() function:

```
const keyringInstance = new Keyring();
keyringInstance.initOptions();
keyringInstance.initOptions();
```

* test: Add test for Keyring singeton instance check and so initOptions only callable once

* feat: Move Keyring options back. Remove singleton check. Move initOptions check. Only export Keyring instance

* Move keyring options back into options folder

* Remove checking if Keyring is singleton

* Move checking if initOptions called multiple times and associated tests out of Keyring and into options folder file

* Add type to pair to fix linting

* Remove exporting Keyring class, only Keyring instance is exported

* refactor: Class-ify the Keyring options directory into a class named

* fix: Store state outside of Keyring instance

* refactor: Move keyring state into Keyring class. Add getters and setters

* Move observable accounts and addresses into Keyring class.

* Rename KeyringInstance interface to KeyringStruct (similar to app-settings)

* Add getter for keyring, accounts, and addresses to Keyring

* Add setter for keyring

* Add AccountSubject type

* Fix State type to use AccountSubject instead of AddressSubject

* Small private member tweaks

* Rework (overzealous private members)

* Fix rename in test

* merge latest from next. fix merge conflicts

* fix linting error

* fix: Remove unncessary code

* Bump API version (bugfixes) (#424)

* [next] Apply fee color classes correctly (#426)

* Apply fee color classes correctly

* Class ordering

* Adjust menu & IdentityIcon styling (#427)

* Cleanup proposal & referendum display (#429)

* [next] Cleanup Referendums & voting process (with Vec<KV>) (#431)

* Cleanup Referendums & voting process (with Vec<KV>)

* Remove FIXME (addressed)

* [next] Cleanup styling (#428)

* Adjust backgrounds to be slightly darker

* Cleanup validator/intentions lists

* update readme reflect removal of ui-react (#434)

* moved shared function to parent (#404)

* moved shared function to parent

* lint

* remove balance array dance

* lint

* Bump deps, metadata parsing (#436)

* article styling updates (#437)

* [next] Merge master, param change update (#438)

* Marge master, param change update

* Tie params to section.method

* [next] autoFocus app fields (#439)

* autoFocus app fields

* Toolbox autoFocus

* Cleanup warnings in staking nominate

* Align borders

* Remove unused var

* [next] Revert menu border override (#440)

* Revert menu border override

* Revert article single border

* Menu background

* Align grays

* Lighten content background

* [next] Support dynamic Tuple & Array inputs (#441)

* Allow Tuple value entry

* Fire Param events

* Remove extra debug log

* Allow entry of Array<*>

* Bump deps

* Bump deps (API d.ts fixed)

* [next] Display intention/validator name in staking list #303 (#448)

* Added getAccount() method to ui-keyring package

* Added getDisplayName function for staking accounts/ addresses

* removed deprecated argument from earlier approach

* formatting (added empty line)

* Removed unnecessary typecheck & encoding from getAccount(),

* Added getAccount to types.d.ts

* removed space

* changed type of `address` to string (failing build fix)

* [next] Backup warning modal on account creation #394 (#447)

* Added address summary and auto-download of backup file to 'create'-modal

* Removed deprecated code after falsy merge

* Fixed typo Plesae -> Please

* Move check for whenCreated property from saveAccount to separate method

* removed unnecessary return statement

* grammar fix 'was' -> 'is'

* Added Highlight to Modal class, styling adjustments

* removed surrounding <p> in modal content

* Changed Modal.Highlight to built in MUI Modal.Description

* renamed translation key of Modal.Description

* Moved timestamp creation back to save Account

* [next] Explicit Identityicon prefix (#446)

* set IdentityIcon default prefix

* Update with import from keyring

* Rework encoding/decoding of addresses

* Update keyring deps

* [next] Bump deps (#449)

* Bumpo deps, work around i18next definitions being wonky (again)

* Cleanup yarn.lock

* [next] add user notifications in App-Accounts (#391)

* add toaster for app-accounts status changes

* status notifs

* linter

* lint

* refactor with addressmini

* remove debugger statement

* fixintl, status obj creation pattern

* lint

* Track events globally, alert use (notification pop-up)  (#413)

* move Status component to ui-app

* move status stuff up the component tree

some more generalizations with action types

* global status

currently works in app-accounts and ui-signer

* I18n and linting

* lintlint

* style

* add notifs to app-address

* status notifs with backup, changepass

* addresses unnecessary translates

* lint

* Fix merge

* Vector should not render add/remove in isDisabled mode (#452)

* [next] Bump API version (#455)

* Bump API version

* Bump deps

* Update README and LICENSE

* Bump dependencies

* [next] Track extrinsics, don't allow until accountIndex is updated (#406)

* dont allow queueing until accountindex increments

* WIP: deny txn submit before account nonce increments

* readding blocked extrinsics to the queue. Still need to properly set the accountNonce though

* queue unclog

* remove unnecessary _this=this scoping dance

* Moving the need for `?:` to a separate issue

* update types to match codec, account for different accountid with same nonce

* Fix toString for undefined (#456)

[next] Fix toString for undefined

* [next] Cleanup translate HOC definitions (#457)

* Cleanup translate HOC definitions

* Alignment

* [next] Bump API for Grandpa compat (#461)

* Bump API for Grandpa compat

* Update types for new API

* [next] Handle byte display consistently (#463)

* Handle byte display consistently

* Chack blocked status against completed status

* Bump

* Democracy countdown (lauch & voting) (#464)

* Bump API to handle StorageData -> Bytes with prefix (#466)

* Bump dependencies, align with stricter TS checks (#467)

* Only remove local files, not nested (#468)

* Bump api deps (#469)

* Display nonce via toString(), cleanup blocked checks (#470)

* [next] Bump deps, update with linting rules (#472)

* Bump deps, update with linting rules

* Update root package config

* Revert testing ruleset config

* Update tslint config pulling in dev-react

* Bump deps with UI packages, remove now unused eslint config (#474)

* Move types.d.ts -> types.ts (#475)

* [next] Bump dependencies (#481)

* Bump deps

* Bump deps

* Cleanup lintin issues with 3.2.1

* Bump @polkadot/api with Tuple map support

* Format JSON results from RPC app

* [next] Make settings accessible from non-running node (#484)

* Add onCopy to IdentityIcon

* Allow settings to be accessible when no node

* Proper license naming for identicon (#488)

* [next] Split ui-{identicon,keyring,settings} into ui repo (#491)

* Split ui-{identicon,keyring,settings} into ui repo

* Correct settings import from ui-app

* Use @polkadot/ui-* split from npm

* Update with latest @polkadot/ui

* Migrate to travis-ci.com, bump deps

* Change non-local imports to direct

* #459 Add spread and copy buttons for substrate.code query (#465)

* #459 Add spread and copy buttons for substrate.code query

* fix code style checks

* render spread&copy buttons for all queries which produce byte code

* Type and name refinement

* #459 A first revision where spread functionality for Byte queries is implemented

* remove state property

* Review fixes

* Review fixes

* break query output for overflowing content

* call valueToText with -1

* Fix linter issue

* [next] Global shared status queue and consumer (#490)

* Global shared status queue and consumer

* Bump deps

* Adjust styling

* Remove copy (unimplemented), spread & concat

* [next] Display received events (balalnces.Transfer atm) (#494)

* Display received events (balalnces.Transfer atm)

* Cleanup Status class

* Keys for values in Vector

* Extra information on address decode errors (#495)

* [next] Cleanup React & API errors (#498)

* Cleanup React & API errors

* Revert value override, breaks input

* InputNumber does not switch between controlled and uncontrolled

* Status has key for entries

* Adjust receive icon

* Bump dependencies, cleanup Unknown types (#499)

* Bump dependencies, cleanup Unknown types

* Cleanup status styling, icon stretch

* [next] fix: Fixes #493. Contain logs digest item within div (#497)

* fix: Fixes #493. Contain logs digest item within div

* refactor: Remove monospace and drop-down css. Add only wrapping and space between elements

* fix: Remove AuthoritiesChange, forgotten how that got there, but not required

* Allow onCopy Status for IdentityIcon (#501)

* Allow onCopy Status for IdentityIcon

* Clanup same-package imports

* [CI Skip] Update .codeclimate.yml (#502)

* [next] Bump dependencies (#503)

* Bump dependencies

* Bump dependencies

* Downgrade react-dropzone (8.x has new context API)

* Bump deps (API types fix)

* Cater for check where key has no meta (#504)

* Align number inputs to 0 defaults (#506)

* fix InputAddress display (#509)

* [next] Bump dependencies (#512)

* Bump dependencies

* Don't change status (flicker) when completed

* Expand status timeout

* Pull svg from ui-assets (#513)

* [next] Read chain properties, inject (#514)

* Read chain properties, inject

* Linting

* Bump deps (#520)

* Bump deps

* ... and include lockfile

* [next] Support latest Polkadot types (#523)

* Bump deps, latest Polkadot types

* Rendered for ParaId

* [next] Charred Cherry support (#522)

* Charred Cherry support

* Update deps to include CC

* Update injection & new method interfaces

* Naming, extrinsic vs method

* Update ExtrinsicStatus results

* Bump deps

* [next] launguage -> language (#524)

* [next] Bump deps, support latest metadata struct (#525)

* Bump deps, support latest metadata

* Bumpdeps

* Bump dev

* Bump local deps

* Display target period * 2 (#526)

* Alexanber support (#528)

* Bump API

* Bump deps

* Fix referendums, chain id for Alexander

* Bump deps
Jaco Greeff 6 years ago
parent
commit
4f96fc0d3f
100 changed files with 2647 additions and 2177 deletions
  1. 1 1
      .codeclimate.yml
  2. 0 2
      .eslintignore
  3. 0 5
      .eslintrc.json
  4. 1 1
      .nvmrc
  5. 0 3
      .stylelintrc.json
  6. 5 0
      .travis.yml
  7. 198 12
      LICENSE
  8. 11 25
      README.md
  9. 0 19
      examples/README.md
  10. BIN
      examples/final.png
  11. 0 52
      examples/tut-001.md
  12. 0 85
      examples/tut-002.md
  13. 0 56
      examples/tut-003.md
  14. 0 42
      examples/tut-004.md
  15. 0 57
      examples/tut-005.md
  16. BIN
      examples/tut-005.png
  17. 0 43
      examples/tut-006.md
  18. BIN
      examples/tut-006.png
  19. 0 65
      examples/tut-007.md
  20. BIN
      examples/tut-007.png
  21. 3 6
      jest.config.js
  22. 1 1
      lerna.json
  23. 18 28
      package.json
  24. 198 12
      packages/app-accounts/LICENSE
  25. 6 6
      packages/app-accounts/package.json
  26. 34 26
      packages/app-accounts/src/Backup.tsx
  27. 32 15
      packages/app-accounts/src/ChangePass.tsx
  28. 184 65
      packages/app-accounts/src/Creator.tsx
  29. 60 23
      packages/app-accounts/src/Editor.tsx
  30. 3 9
      packages/app-accounts/src/Forgetting.tsx
  31. 41 36
      packages/app-accounts/src/Restore.tsx
  32. 19 0
      packages/app-accounts/src/bipWorker.ts
  33. 6 3
      packages/app-accounts/src/index.css
  34. 17 10
      packages/app-accounts/src/index.tsx
  35. 3 3
      packages/app-accounts/src/translate.ts
  36. 8 0
      packages/app-accounts/src/worker-loader.d.ts
  37. 198 12
      packages/app-addresses/LICENSE
  38. 4 4
      packages/app-addresses/package.json
  39. 31 13
      packages/app-addresses/src/Creator.tsx
  40. 57 18
      packages/app-addresses/src/Editor.tsx
  41. 2 5
      packages/app-addresses/src/Forgetting.tsx
  42. 1 1
      packages/app-addresses/src/index.css
  43. 15 8
      packages/app-addresses/src/index.tsx
  44. 3 3
      packages/app-addresses/src/translate.ts
  45. 198 12
      packages/app-democracy/LICENSE
  46. 6 7
      packages/app-democracy/package.json
  47. 16 15
      packages/app-democracy/src/Item.tsx
  48. 23 28
      packages/app-democracy/src/Proposal.tsx
  49. 8 9
      packages/app-democracy/src/Proposals.tsx
  50. 42 34
      packages/app-democracy/src/Referendum.tsx
  51. 17 11
      packages/app-democracy/src/Referendums.tsx
  52. 47 35
      packages/app-democracy/src/Summary.tsx
  53. 10 10
      packages/app-democracy/src/Voting.tsx
  54. 21 19
      packages/app-democracy/src/VotingButtons.tsx
  55. 1 6
      packages/app-democracy/src/index.css
  56. 4 2
      packages/app-democracy/src/index.tsx
  57. 3 3
      packages/app-democracy/src/translate.ts
  58. 0 15
      packages/app-example/LICENSE
  59. 0 3
      packages/app-example/README.md
  60. 0 19
      packages/app-example/package.json
  61. 0 19
      packages/app-example/src/comp-002.tsx
  62. 0 66
      packages/app-example/src/comp-003.tsx
  63. 0 91
      packages/app-example/src/comp-004.tsx
  64. 0 118
      packages/app-example/src/comp-005.tsx
  65. 0 132
      packages/app-example/src/comp-006.tsx
  66. 0 180
      packages/app-example/src/comp-007.tsx
  67. 0 13
      packages/app-example/src/index-001.tsx
  68. 0 17
      packages/app-example/src/index-002.tsx
  69. 0 17
      packages/app-example/src/index-003.tsx
  70. 0 17
      packages/app-example/src/index-004.tsx
  71. 0 17
      packages/app-example/src/index-005.tsx
  72. 0 17
      packages/app-example/src/index-006.tsx
  73. 0 17
      packages/app-example/src/index-007.tsx
  74. 0 16
      packages/app-example/src/index.css
  75. 0 59
      packages/app-example/src/index.tsx
  76. 198 12
      packages/app-explorer/LICENSE
  77. 6 6
      packages/app-explorer/package.json
  78. 8 10
      packages/app-explorer/src/BestHash.tsx
  79. 92 70
      packages/app-explorer/src/BlockByHash/BlockByHash.tsx
  80. 89 0
      packages/app-explorer/src/BlockByHash/Logs.tsx
  81. 1 1
      packages/app-explorer/src/BlockByHash/index.tsx
  82. 41 0
      packages/app-explorer/src/BlockHeader/BlockHash.tsx
  83. 67 40
      packages/app-explorer/src/BlockHeader/BlockHeader.css
  84. 7 9
      packages/app-explorer/src/BlockHeader/Extrinsics.tsx
  85. 42 52
      packages/app-explorer/src/BlockHeader/index.tsx
  86. 10 9
      packages/app-explorer/src/BlockHeaders.tsx
  87. 112 0
      packages/app-explorer/src/Events.tsx
  88. 27 7
      packages/app-explorer/src/Main.tsx
  89. 6 14
      packages/app-explorer/src/Query.tsx
  90. 18 14
      packages/app-explorer/src/Summary.tsx
  91. 35 36
      packages/app-explorer/src/SummarySession.tsx
  92. 30 12
      packages/app-explorer/src/index.css
  93. 4 2
      packages/app-explorer/src/index.tsx
  94. 3 3
      packages/app-explorer/src/translate.ts
  95. 198 12
      packages/app-extrinsics/LICENSE
  96. 6 6
      packages/app-extrinsics/package.json
  97. 16 16
      packages/app-extrinsics/src/Account.tsx
  98. 56 38
      packages/app-extrinsics/src/Extrinsic.tsx
  99. 3 4
      packages/app-extrinsics/src/Nonce.tsx
  100. 16 5
      packages/app-extrinsics/src/Params/Account.tsx

+ 1 - 1
.codeclimate.yml

@@ -1,3 +1,3 @@
 exclude_patterns:
 - "**/*.spec.js"
-- "**/flow-typed/*"
+- "**/*.spec.ts"

+ 0 - 2
.eslintignore

@@ -1,2 +0,0 @@
-**/build/*
-**/node_modules/*

+ 0 - 5
.eslintrc.json

@@ -1,5 +0,0 @@
-{
-  "extends": [
-    "./node_modules/@polkadot/dev-react/config/eslint.js"
-  ]
-}

+ 1 - 1
.nvmrc

@@ -1 +1 @@
-10.1.0
+10.13.0

+ 0 - 3
.stylelintrc.json

@@ -1,3 +0,0 @@
-{
-  "extends": "@polkadot/dev-react/config/stylelint"
-}

+ 5 - 0
.travis.yml

@@ -1,6 +1,11 @@
 language: node_js
 node_js:
   - "10"
+env:
+  - GH_PAGES_SRC="packages/apps/build"
+before_install:
+  - curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 1.10.1
+  - export PATH=$HOME/.yarn/bin:$PATH
 cache:
   yarn: true
   directories:

+ 198 - 12
LICENSE

@@ -1,15 +1,201 @@
-ISC License (ISC)
+                              Apache License
+                        Version 2.0, January 2004
+                    http://www.apache.org/licenses/
 
-Copyright 2017-2018 Jaco Greeff <jacogr@gmail.com>
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
 
-Permission to use, copy, modify, and/or distribute this software for any
-purpose with or without fee is hereby granted, provided that the above
-copyright notice and this permission notice appear in all copies.
+1. Definitions.
 
-THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
-REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
-FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
-INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
-OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-PERFORMANCE OF THIS SOFTWARE.
+  "License" shall mean the terms and conditions for use, reproduction,
+  and distribution as defined by Sections 1 through 9 of this document.
+
+  "Licensor" shall mean the copyright owner or entity authorized by
+  the copyright owner that is granting the License.
+
+  "Legal Entity" shall mean the union of the acting entity and all
+  other entities that control, are controlled by, or are under common
+  control with that entity. For the purposes of this definition,
+  "control" means (i) the power, direct or indirect, to cause the
+  direction or management of such entity, whether by contract or
+  otherwise, or (ii) ownership of fifty percent (50%) or more of the
+  outstanding shares, or (iii) beneficial ownership of such entity.
+
+  "You" (or "Your") shall mean an individual or Legal Entity
+  exercising permissions granted by this License.
+
+  "Source" form shall mean the preferred form for making modifications,
+  including but not limited to software source code, documentation
+  source, and configuration files.
+
+  "Object" form shall mean any form resulting from mechanical
+  transformation or translation of a Source form, including but
+  not limited to compiled object code, generated documentation,
+  and conversions to other media types.
+
+  "Work" shall mean the work of authorship, whether in Source or
+  Object form, made available under the License, as indicated by a
+  copyright notice that is included in or attached to the work
+  (an example is provided in the Appendix below).
+
+  "Derivative Works" shall mean any work, whether in Source or Object
+  form, that is based on (or derived from) the Work and for which the
+  editorial revisions, annotations, elaborations, or other modifications
+  represent, as a whole, an original work of authorship. For the purposes
+  of this License, Derivative Works shall not include works that remain
+  separable from, or merely link (or bind by name) to the interfaces of,
+  the Work and Derivative Works thereof.
+
+  "Contribution" shall mean any work of authorship, including
+  the original version of the Work and any modifications or additions
+  to that Work or Derivative Works thereof, that is intentionally
+  submitted to Licensor for inclusion in the Work by the copyright owner
+  or by an individual or Legal Entity authorized to submit on behalf of
+  the copyright owner. For the purposes of this definition, "submitted"
+  means any form of electronic, verbal, or written communication sent
+  to the Licensor or its representatives, including but not limited to
+  communication on electronic mailing lists, source code control systems,
+  and issue tracking systems that are managed by, or on behalf of, the
+  Licensor for the purpose of discussing and improving the Work, but
+  excluding communication that is conspicuously marked or otherwise
+  designated in writing by the copyright owner as "Not a Contribution."
+
+  "Contributor" shall mean Licensor and any individual or Legal Entity
+  on behalf of whom a Contribution has been received by Licensor and
+  subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+  this License, each Contributor hereby grants to You a perpetual,
+  worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+  copyright license to reproduce, prepare Derivative Works of,
+  publicly display, publicly perform, sublicense, and distribute the
+  Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+  this License, each Contributor hereby grants to You a perpetual,
+  worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+  (except as stated in this section) patent license to make, have made,
+  use, offer to sell, sell, import, and otherwise transfer the Work,
+  where such license applies only to those patent claims licensable
+  by such Contributor that are necessarily infringed by their
+  Contribution(s) alone or by combination of their Contribution(s)
+  with the Work to which such Contribution(s) was submitted. If You
+  institute patent litigation against any entity (including a
+  cross-claim or counterclaim in a lawsuit) alleging that the Work
+  or a Contribution incorporated within the Work constitutes direct
+  or contributory patent infringement, then any patent licenses
+  granted to You under this License for that Work shall terminate
+  as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+  Work or Derivative Works thereof in any medium, with or without
+  modifications, and in Source or Object form, provided that You
+  meet the following conditions:
+
+  (a) You must give any other recipients of the Work or
+      Derivative Works a copy of this License; and
+
+  (b) You must cause any modified files to carry prominent notices
+      stating that You changed the files; and
+
+  (c) You must retain, in the Source form of any Derivative Works
+      that You distribute, all copyright, patent, trademark, and
+      attribution notices from the Source form of the Work,
+      excluding those notices that do not pertain to any part of
+      the Derivative Works; and
+
+  (d) If the Work includes a "NOTICE" text file as part of its
+      distribution, then any Derivative Works that You distribute must
+      include a readable copy of the attribution notices contained
+      within such NOTICE file, excluding those notices that do not
+      pertain to any part of the Derivative Works, in at least one
+      of the following places: within a NOTICE text file distributed
+      as part of the Derivative Works; within the Source form or
+      documentation, if provided along with the Derivative Works; or,
+      within a display generated by the Derivative Works, if and
+      wherever such third-party notices normally appear. The contents
+      of the NOTICE file are for informational purposes only and
+      do not modify the License. You may add Your own attribution
+      notices within Derivative Works that You distribute, alongside
+      or as an addendum to the NOTICE text from the Work, provided
+      that such additional attribution notices cannot be construed
+      as modifying the License.
+
+  You may add Your own copyright statement to Your modifications and
+  may provide additional or different license terms and conditions
+  for use, reproduction, or distribution of Your modifications, or
+  for any such Derivative Works as a whole, provided Your use,
+  reproduction, and distribution of the Work otherwise complies with
+  the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+  any Contribution intentionally submitted for inclusion in the Work
+  by You to the Licensor shall be under the terms and conditions of
+  this License, without any additional terms or conditions.
+  Notwithstanding the above, nothing herein shall supersede or modify
+  the terms of any separate license agreement you may have executed
+  with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+  names, trademarks, service marks, or product names of the Licensor,
+  except as required for reasonable and customary use in describing the
+  origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+  agreed to in writing, Licensor provides the Work (and each
+  Contributor provides its Contributions) on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+  implied, including, without limitation, any warranties or conditions
+  of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+  PARTICULAR PURPOSE. You are solely responsible for determining the
+  appropriateness of using or redistributing the Work and assume any
+  risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+  whether in tort (including negligence), contract, or otherwise,
+  unless required by applicable law (such as deliberate and grossly
+  negligent acts) or agreed to in writing, shall any Contributor be
+  liable to You for damages, including any direct, indirect, special,
+  incidental, or consequential damages of any character arising as a
+  result of this License or out of the use or inability to use the
+  Work (including but not limited to damages for loss of goodwill,
+  work stoppage, computer failure or malfunction, or any and all
+  other commercial damages or losses), even if such Contributor
+  has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+  the Work or Derivative Works thereof, You may choose to offer,
+  and charge a fee for, acceptance of support, warranty, indemnity,
+  or other liability obligations and/or rights consistent with this
+  License. However, in accepting such obligations, You may act only
+  on Your own behalf and on Your sole responsibility, not on behalf
+  of any other Contributor, and only if You agree to indemnify,
+  defend, and hold each Contributor harmless for any liability
+  incurred by, or claims asserted against, such Contributor by reason
+  of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+  To apply the Apache License to your work, attach the following
+  boilerplate notice, with the fields enclosed by brackets "[]"
+  replaced with your own identifying information. (Don't include
+  the brackets!)  The text should be enclosed in the appropriate
+  comment syntax for the file format. We also recommend that a
+  file or class name and description of purpose be included on the
+  same "printed page" as the copyright notice for easier
+  identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.

+ 11 - 25
README.md

@@ -1,19 +1,17 @@
 [![polkadotjs](https://img.shields.io/badge/polkadot-js-orange.svg?style=flat-square)](https://polkadot.js.org)
-![isc](https://img.shields.io/badge/license-ISC-lightgrey.svg?style=flat-square)
+![license](https://img.shields.io/badge/License-Apache%202.0-blue.svg?style=flat-square)
 [![style](https://img.shields.io/badge/code%20style-semistandard-lightgrey.svg?style=flat-square)](https://github.com/Flet/semistandard)
 [![npm](https://img.shields.io/npm/v/@polkadot/apps.svg?style=flat-square)](https://www.npmjs.com/package/@polkadot/apps)
-[![travis](https://img.shields.io/travis/polkadot-js/apps.svg?style=flat-square)](https://travis-ci.org/polkadot-js/apps)
+[![travis](https://img.shields.io/travis/polkadot-js/apps.svg?style=flat-square)](https://travis-ci.com/polkadot-js/apps)
 [![greenkeeper](https://img.shields.io/badge/greenkeeper-enabled-brightgreen.svg?style=flat-square)](https://greenkeeper.io/)
 [![dependency](https://img.shields.io/david/polkadot-js/apps.svg?style=flat-square)](https://david-dm.org/polkadot-js/apps)
 [![devDependency](https://img.shields.io/david/dev/polkadot-js/apps.svg?style=flat-square)](https://david-dm.org/polkadot-js/apps#info=devDependencies)
 
 # @polkadot/apps
 
-A Portal into the Polkadot network. Provides a view and interaction layer from a browser.
+A Portal into the Polkadot and Substrate networks. Provides a view and interaction layer from a browser.
 
-This can be accessed as a hosted application via [https://polkadot.js.org/apps/](https://polkadot.js.org/apps/) or via [https://poc-2.polkadot.io](https://poc-2.polkadot.io) with the latter not requiring a locally-hosted node.
-
-*Important* If you are running [Substrate master](https://github.com/paritytech/substrate), support is in the next version here. You can access it via [https://polkadot.js.org/apps/next/](https://polkadot.js.org/apps/next/). Once Substrate hits 1.0-beta, master will have the required support (next branch becomes master)
+This can be accessed as a hosted application via [https://polkadot.js.org/apps/](https://polkadot.js.org/apps/)
 
 ## overview
 
@@ -22,21 +20,21 @@ The repo is split into a number of packages, each representing an application. T
 - [apps](packages/apps/) This is the main entry point. It handles the selection sidebar and routing to the specific application being displayed.
 - [app-accounts](packages/app-accounts/) A basic account management app.
 - [app-addresses](packages/app-addresses/) A basic address management app.
+- [app-democracy](packages/app-democracy/) A basic voting app, allowing votes on activate proposals and referendums.
 - [app-explorer](packages/app-explorer/) A simple block explorer. It only shows the most recent blocks, updating as they become available.
 - [app-extrinsics](packages/app-extrinsics/) Submission of extrinsics to a node.
 - [app-rpc](packages/app-rpc/) Sumission of raw data to RPC endpoints.
+- [app-settings](packages/app-settings/) A basic settings management app, allowing choice of language, node to connect to, and theme
 - [app-staking](packages/app-staking/) A basic staking management app, allowing staking and nominations.
 - [app-storage](packages/app-storage/) A simple node storage query application. Multiple queries can be queued and updates as new values become available.
 - [app-toolbox](packages/app-toolbox/) Utilities to manage data.
+- [app-transfer](packages/app-transfer/) A basic account management app, allowing transfer of DOTs between accounts.
 - [app-vanitygen](packages/app-vanitygen/) A toy that allows you to generate vanity addresses. Running `yarn run vanitygen --match <string>` runs the generator as a Node CLI app. (Orders of a magnitude faster due to the use of libsoldium bindings)
 
 In addition the following libraries are also included in the repo. These are to be moved to the [@polkadot/ui](https://github.com/polkadot-js/ui/) repository once it reaches a base level of stability and usability. (At this point with the framework being tested on the apps above, it makes development easier having it close)
 
 - [ui-app](packages/ui-app/) A reactive (using RxJS) application framework with a number of useful shared components.
-- [ui-keyring](packages/ui-keyring/) A browser-specific wrapper around the base [@polkadot/util-keyring](https://github.com/polkadot-js/util/) library.
 - [ui-signer](packages/ui-signer/) Signer implementation for apps.
-- [ui-identicon](packages/ui-identicon/) Identity icon generator with raw publicKey as input
-- [ui-react](packages/ui-react) A collection of base React components
 - [ui-react-rx](packages/ui-react-rx) Base components that use the RxJS Observable APIs
 
 ## development
@@ -48,8 +46,8 @@ To start off, this repo (along with others in the [@polkadot](https://github.com
 To get started -
 
 1. Clone the repo locally, via `git clone https://github.com/polkadot-js/apps <optional local path>`
-2. Ensure that you have a recent version of Node.js, for development purposes [Node >=10.1.0](https://nodejs.org/en/) is required.
-3. Ensure that you have a recent version of Yarn, for development purposes [Yarn >=1.3.2](https://yarnpkg.com/docs/install) is required.
+2. Ensure that you have a recent LTS version of Node.js, for development purposes [Node >=10.13.0](https://nodejs.org/en/) is recommended.
+3. Ensure that you have a recent version of Yarn, for development purposes [Yarn >=1.10.1](https://yarnpkg.com/docs/install) is required.
 4. Install the dependencies by running `yarn`
 5. Ready! Now you can launch the UI (assuming you have a local Polkadot Node running), via `yarn run start`
 6. Access the UI via [http://localhost:3000](http://localhost:3000)
@@ -61,24 +59,12 @@ There are additional environment UI flags that change both the theme and mode -
 - Running with `UI_MODE=light|full` switches from a full (the default) to a light mode interface that only has specific applications highlighted.
 - Running with `UI_THEME=substrate|polkadot` switches from a Polkadot theme (the default) to a Substrate-branded UI
 
-## demos
-
-Demos for the different libraries can be viewed with `yarn run demo:<name>` and then browsing to [http://localhost:3000](http://localhost:3000). Available demo -
-
-- `yarn run demo:identicon`
-- `yarn run demo:ui`
-- `yarn run demo:rx`
-
-## tutorials
-
-Looking for tutorials to get started? Look at [examples](examples/README.md) for a step-by-step guide to using the API and Components to display some information.
-
 ## Docker
 
-### Run
+You can run a docker container via -
 
   docker run --rm -it --name polkadot-ui -p 80:80 chevdor/polkadot-ui:latest
 
-### Build
+To build a docker container containing local changes -
 
   docker build -t chevdor/polkadot-ui:latest .

+ 0 - 19
examples/README.md

@@ -1,19 +0,0 @@
-# examples
-
-This guide will take you through some basic examples in using the Components and API to build tools to extract information from a network client. Here you will setup basic infrastructure, perform storage queries (via provided components and API) and then string all these together into doing some more complex things.
-
-## tutorials
-
-- [Basic application scaffolding](tut-001.md) Setup a new app in using this framework. (Typically only needed when new top-level features are added)
-- [Storage and pulling from storage](tut-002.md) Use the built-in components to display something basic from storage
-- [Query storage via API](tut-003.md) Construct an API query to pull information from storage
-- [Query storage, replace HOC](tut-004.md) Queries storage, replacing the previous use of our HOC
-- [Combining proposal and intentions](tut-005.md) Using the information collected previously, combine the displays
-- [Showing selected validators](tut-006.md) Expand on intentions, filtering with current validators
-- [Sorting intentions by balance](tut-007.md) Cleanup our display, sorting the intentions by balance
-
-## ... and in the end ...
-
-You will know how to use UI components and the API to render a mapping of intentions, their balances to proposals
-
-![final](https://raw.githubusercontent.com/polkadot-js/apps/master/examples/final.png)

BIN
examples/final.png


+ 0 - 52
examples/tut-001.md

@@ -1,52 +0,0 @@
-# basic scaffolding
-
-To add a top-level application, some basic setup is required. This is only applicable for new top-level apps, i.e. like we currently have extrinsics, storage, accounts, etc. When just hacking away on a specific app, this section is not needed.
-
-# basic setup
-
-Initially we would need an new application folder to be added under [packages](../packages). For the sake of this tutorial, we have just created [app-example](../packages/app-example), a basic app that will be used in the rest of the tutorials.
-
-Once created, initialise the app with `package.json`, `README.md`, `LICENSE.md` and the basic folder setup under `src`
-
-# creating an app entry
-
-First off, let's create an app entry. Since we will just have a basic sample, let's keep it simple for now. Under [our example src](../packages/app-example/src) we just create an `index.tsx` with a simple entry point.
-
-```js
-import React from 'react';
-
-export default class App extends React.PureComponent<any> {
-  render () {
-    return (
-      <div>hello world</div>
-    );
-  }
-}
-```
-
-(We have kept the original, which has changed as the tutorial progresses as [index-001.tsx](../packages/app-example/src/index-001.tsx))
-
-# making it visible
-
-Once the app is created, it needs to be hooked up to the rest, allowing TypeScript, Jest & Webpack to find it and use it.
-
-- To enable Jest mappings, add the name of the app to [the Jest config](../jest.config.js)
-- To enable TypeScript mappings, add the app to [the TypeScript config](../tsconfig.json)
-- To allow the app to be included in the Webpack build, add it to [Webpack config](../packages/apps/webpack.config.js) (Note that this is not high-level, but rather at the entry point of the loader - this allows packages to have their own configs in the case of demos)
-
-At this point the application will be available and included, even though it does not have a [navigation entry](../packages/apps/routing) yet. Adding the navigation -
-
-- Add a reference to the application to the [apps package.json](../packages/apps/package.json)
-- Add a route file the defines the [app, name & icon](../packages/apps/src/routing/example.ts)
-- Finally include the route in the [route index](../packages/apps/src/routing/index.ts)
-
-# running!
-
-Basic app added, now let it run and see what it does.
-
-- Start the webpack server via `WS_URL=wss://poc-2.polkadot.io:9944 yarn run start`
-- Access the applcation on [localhost:3000/#/example](http://localhost:3000/#/example)
-
-# that is it
-
-We have something basic wired-up, now let's [build something](tut-002.md)

+ 0 - 85
examples/tut-002.md

@@ -1,85 +0,0 @@
-# storage via HOC
-
-In the [previous section](tut-001.md) we setup a basic application framework in [app-example](../packages/app-example). Here we will continute adding some useful queries using bare-bones UI components.
-
-In substrate chains, the storage (state) is exposed via API, allowing any app to perform queries against the current (and previous) states. Here we will use some built-in components to perform a query over the intentions, displaying the results.
-
-# creating a component
-
-Here we are creating a component that will attach to a specific storage entry, and display any changes as they happen on-chain. For this example, we are interested in the `intentions` storage area, i.e. those accounts that wish to participate in staking.
-
-Initially we will just create it, and then walk through what actually happens. In [comp-002.tsx](../packages/app-example/src/comp-002.tsx) we have -
-
-```js
-import React from 'react';
-
-import storage from '@polkadot/storage';
-import withStorageDiv from '@polkadot/ui-react-rx/with/storageDiv';
-import encodeAddress from '@polkadot/util-keyring/address/encode';
-
-const method = storage.staking.public.intentions;
-
-const Comp: React.ComponentType<any> = withStorageDiv(method)(
-  (value: Uint8Array[]): string => {
-    if (!value || !value.length) {
-      return 'No intentions found';
-    }
-
-    return value.map(encodeAddress).join(', ');
-  }
-);
-
-export default Comp;
-```
-
-Additionally, we change our entry-point to import this component.
-
-```js
-import React from 'react';
-
-import Comp from './comp-002';
-
-export default class App extends React.PureComponent<any> {
-  render () {
-    return (
-      <Comp />
-    );
-  }
-}
-```
-
-Now going to the app via [localhost:3000/#/example](http://localhost:3000/#/example) renders a list of accounts.
-
-# walk-through
-
-So what have we done. First off, we import all available storage entries and select the method we are interested in, i.e.
-
-```js
-import storage from '@polkadot/storage';
-
-const method = storage.staking.public.intentions;
-```
-
-Storage entries can be explored via the storage app and will always be (in code) `storage.<section>.public.<method>`. These are all defined in [@polkadot/storage](https://github.com/polkadot-js/common/tree/master/packages/type-storage/src)
-
-Next up we use an HOC helper `withStorageDiv` which basically takes a storage method and with the specified renderer wraps it in a Div.
-
-```js
-import withStorageDiv from '@polkadot/ui-react-rx/with/storageDiv';
-
-const Comp: React.ComponentType<any> = withStorageDiv(method)(
-  (value: Uint8Array[]): string => {
-    ...
-  }
-);
-```
-
-Here the storage query will return an `Uint8Array[]`, or rather an array of Accounts as used internally. These Accounts however are a list of the actual publicKeys, so for display we convert them with a formatter,
-
-```js
-return value.map(encodeAddress).join(', ');
-```
-
-# next steps
-
-At this point we have, with minimal effort, used some HOC helpers to display information from a storage area. [Next up](tut-003.md) we will actually pull this together and do the same query directly via the API.

+ 0 - 56
examples/tut-003.md

@@ -1,56 +0,0 @@
-# storage via API
-
-In the [previous section](tut-002.md) we have used an HOC to query a storage area. Here we will repeat the same, however this time we will actually use the Rx API to accomplish the same goal.
-
-# creating the component
-
-As in previous examples, we will first show the [actual component](../packages/app-example/src/comp-003.tsx) we are using and then delve into how it fits together. Focussing on the meat of the API subscription that happens in the `componentMount` cycle -
-
-```js
-class Comp extends React.PureComponent<ApiProps, State> {
-  ...
-  // TODO We should unsubscribe from subscriptions
-  componentDidMount () {
-    this.subscribeProposals();
-  }
-
-  subscribeProposals () {
-    const { api } = this.props;
-
-    api.state
-      .getStorage(storage.democracy.public.proposals)
-      .subscribe((value: Array<StorageProposal>) => {
-        this.setState({
-          proposals: value.reduce((proposals: StateProposals, [propIdx, proposal, accountId]) => {
-            const address = encodeAddress(accountId);
-
-            if (!proposals[address]) {
-              proposals[address] = [propIdx.toNumber()];
-            } else {
-              proposals[address].push(propIdx.toNumber());
-            }
-
-            return proposals;
-          }, {} as StateProposals)
-        });
-      });
-  }
-  ...
-}
-
-export default withApi(Comp);
-```
-
-# walk-through
-
-Since we are working on a slightly lower level now, a couple of things happen.
-
-We use a helper function to decode the values as it comes back - without this we would just have a raw stream of bytes as retrieved from storage. The decding take the raw stream and splits it into a mangeable Array stream (based on trhe number of items), each containing a tuple of data - in this case the `PropIndex`, `Proposal` and `AccountId`.
-
-Finally we loop through the proposals retrieved, indexing these by the actual account address - this information we finally use in the render to update the display.
-
-The API provided on the component props is injected via `withApi`, to make an API query - subscribing to any updates. As any updates happen to the storage, these will be automatically fed through the API subscriptions, updating the component display.
-
-# next up
-
-In the next round, we will extend our subscriptions to also pull the information we previously got via HOC and then map [these together](tut-004.md).

+ 0 - 42
examples/tut-004.md

@@ -1,42 +0,0 @@
-# storage via API (part II)
-
-[Previously](tut-002.md) we queried intentions via HOC, then [followed up](tut-003.md) with querying via API. Here we will replace our previous HOC component with the same storage queries.
-
-# the component
-
-Here we extend the component from the previous section, adding a subscription to intentions to create our [new component](../packages/app-example/src/comp-004.tsx) -
-
-```js
-class Comp extends React.PureComponent<ApiProps, State> {
-  ...
-  componentDidMount () {
-    this.setState({
-      subscriptions: [
-        this.subscribeIntentions(),
-        this.subscribeProposals()
-      ]
-    });
-  }
-
-  subscribeIntentions () {
-    const { api } = this.props;
-
-    return api.state
-      .getStorage(storage.staking.public.intentions)
-      .subscribe((intentions: StorageIntentions) => {
-        this.setState({
-          intentions: intentions.map(encodeAddress)
-        });
-      });
-  }
-  ...
-}
-```
-
-# walk-through
-
-This subscription is much simpler than what was found before, however it follows the same basic approach - query, transform the result.
-
-# next steps
-
-[Next up](tut-005.md), we will be using the actual data we have collected to render something useful on-screen.

+ 0 - 57
examples/tut-005.md

@@ -1,57 +0,0 @@
-# pulling it together
-
-Previously we have used the API to query the [actual storage](tut-004.md), here we will build on that base to show something usable on-screen.
-
-# component
-
-[This component](../packages/app-example/src/comp-005.tsx) will focus mostly on the `render()` method and display on-screen. As with other examples, we first show the actual code and then provide a short walk-through of the relevant parts -
-
-```js
-class Comp extends React.PureComponent<ApiProps, State> {
-  ...
-  render () {
-    const { intentions, proposals } = this.state;
-
-    return (
-      <table>
-        <thead>
-          <tr>
-            <th />
-            <th>Address</th>
-            <th>Balance</th>
-            <th>Proposals</th>
-          </tr>
-        </thead>
-        <tbody>
-          {intentions.map((address) => (
-            this.renderAccount(address, proposals[address])
-          ))}
-        </tbody>
-      </table>
-    );
-  }
-
-  renderAccount = (address: string, proposals: number[] = []) => {
-    return (
-      <tr key={address}>
-        <td><IdentityIcon size={24} value={address} /></td>
-        <td>{address}</td>
-        <td><Balance params={address} /></td>
-        <td>{proposals.length}</td>
-      </tr>
-    );
-  }
-}
-```
-
-# walk-through
-
-The render is straight-forward. For each of our intentions, render a row in a table showing the icon & address, the balance of the account and the number of proposals.
-
-# actual output
-
-![tut-005](https://raw.githubusercontent.com/polkadot-js/apps/master/examples/tut-005.png)
-
-# next steps
-
-[Next up](tut-006.md) we will expand our list, showing the actual activive validators.

BIN
examples/tut-005.png


+ 0 - 43
examples/tut-006.md

@@ -1,43 +0,0 @@
-# adding validators
-
-[Previously](tut-005.md), the list of accounts wishing to paritipate in staking has been shown. The next step would be to merge this with the list of validators (as selected from the intentions) and show these slightly differently.
-
-# component
-
-Building on the component created previously, we can expand [the selection](../packages/app-example/src/comp-006.tsx) (and rendering) to query the active validators.
-
-```js
-class Comp extends React.PureComponent<ApiProps, State> {
-  ...
-  subscribeValidators () {
-    const { api } = this.props;
-
-    return api.state
-      .getStorage(storage.session.public.validators)
-      .subscribe((validators: StorageValidators) => {
-        this.setState({
-          validators: validators.map(encodeAddress)
-        });
-      });
-  }
-  ...
-  renderAccount = (address: string, proposals: number[] = [], isValidator: boolean = false) => {
-    return (
-      <tr className={isValidator ? 'validator' : ''} key={address}>
-      ...
-    );
-  }
-}
-```
-
-# walk through
-
-Building on what we have done previously, we now also subscribe to the list of validators (`storage.session.public.validators`) and uses this to highlight the actual active validators that we have found. It is important to note that the validator list is a subset of intentions, i.e. validators will continue to be shows as active intentions while they are part of the network.
-
-# actual output
-
-![tut-006](https://raw.githubusercontent.com/polkadot-js/apps/master/examples/tut-006.png)
-
-# next steps
-
-For the [next round](tut-007.md), we will cleanup the display somewhat, allowing us to make sense of the actual unordered information displayed.

BIN
examples/tut-006.png


+ 0 - 65
examples/tut-007.md

@@ -1,65 +0,0 @@
-# sorting by balance
-
-After [the last section](tut-006.md), we are at a point we we have the intentions, actual validators and their balances. For users, we would like this display to be more usable, so here we are aiming on sorting by balance.
-
-# component
-
-Expanding on our previous component, we now change the previously used `<Balance />` component, into doing [actual `freeBalanceOf` queries](../packages/app-example/src/comp-007.tsx). There are 2 options here - we could also use the `onChange` event on the `Balance` component to return the display value. However here we opt for querying the raw value, transforming it and sorting with it.
-
-```js
-class Comp extends React.PureComponent<ApiProps, State> {
-  ...
-  subscribeBalances (accounts: string[]) {
-    const { api } = this.props;
-    const { balances, subscriptions } = this.state;
-    const newBalances = { ...balances };
-
-    accounts.forEach((account) => {
-      if (newBalances[account]) {
-        return;
-      } else {
-        newBalances[account] = ZERO;
-      }
-
-      subscriptions.push(
-        api.state
-          // Here we pass a parameter to the key generator, so it points to the correct storage entry
-          .getStorage(storage.staking.public.freeBalanceOf, account)
-          .subscribe((balance: BN) => {
-            this.setState(({ balances }: State) => {
-              const newBalances = { ...balances };
-
-              newBalances[account] = balance;
-
-              return {
-                balances: newBalances
-              };
-            });
-          })
-      );
-    });
-
-    this.setState({
-      balances: newBalances,
-      subscriptions
-    });
-  }
-  ...
-  render () {
-    const { balances, intentions, proposals, validators } = this.state;
-    const sortedIntentions = intentions.sort((a, b) =>
-      (balances[b] || ZERO).cmp(balances[a] || ZERO)
-    );
-    ...
-  }
-  ...
-}
-```
-
-# walk through
-
-By now the subscription approach is known. Where things do differ however is the passing of a parameter to the key encoder. Since each balance entry is denoted by the actual account, the hashing needs to take the actual account and append it to the prefix location before making a hash that the runtime understands.
-
-# actual output
-
-![tut-007](https://raw.githubusercontent.com/polkadot-js/apps/master/examples/tut-007.png)

BIN
examples/tut-007.png


+ 3 - 6
jest.config.js

@@ -2,12 +2,9 @@ const config = require('@polkadot/dev-react/config/jest');
 
 module.exports = Object.assign({}, config, {
   moduleNameMapper: {
-    '@polkadot/app-(accounts|addresses|democracy|example|explorer|extrinsics|rpc|staking|storage|toolbox|transfer|vanitygen)(.*)$': '<rootDir>/packages/ui-$1/src/$2',
-    '@polkadot/ui-(app|identicon|keyring|react-rx|react|signer)(.*)$': '<rootDir>/packages/ui-$1/src/$2',
+    '@polkadot/app-(accounts|addresses|democracy|explorer|extrinsics|rpc|settings|staking|storage|toolbox|transfer|vanitygen)(.*)$': '<rootDir>/packages/app-$1/src/$2',
+    '@polkadot/ui-(app|react-rx|signer)(.*)$': '<rootDir>/packages/ui-$1/src/$2',
     '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': 'empty/object',
     '\\.(css|less)$': 'empty/object'
-  },
-  transformIgnorePatterns: [
-    'node_modules/(?!polkadot-identicon)'
-  ]
+  }
 });

+ 1 - 1
lerna.json

@@ -10,5 +10,5 @@
   "packages": [
     "packages/*"
   ],
-  "version": "0.20.30"
+  "version": "0.21.0"
 }

+ 18 - 28
package.json

@@ -1,9 +1,9 @@
 {
-  "version": "0.20.30",
+  "version": "0.21.0",
   "private": true,
   "engines": {
-    "node": "^10.1.0",
-    "yarn": "^1.3.2"
+    "node": "^10.13.0",
+    "yarn": "^1.10.1"
   },
   "homepage": ".",
   "workspaces": [
@@ -12,45 +12,35 @@
   "resolutions": {
     "babel-core": "^7.0.0-bridge.0",
     "rxjs": "^6.3.2",
-    "typescript": "^3.0.1"
+    "typescript": "^3.2.2"
   },
   "scripts": {
     "analyze": "yarn run build && cd packages/apps && yarn run source-map-explorer build/main.*.js",
     "build": "polkadot-dev-build-ts",
-    "check": "tslint --project . && tsc --noEmit",
+    "check": "tslint --project . && tsc --noEmit --pretty",
     "clean": "polkadot-dev-clean-build",
     "postinstall": "polkadot-dev-yarn-only",
     "test": "jest --coverage",
-    "demo:identicon": "webpack-serve --config packages/ui-identicon/webpack.config.js --content packages/ui-identicon --port 3000",
-    "demo:rx": "webpack-serve --config packages/ui-react-rx/webpack.config.js --content packages/ui-react-rx --port 3000",
-    "demo:ui": "webpack-serve --config packages/ui-react/webpack.config.js --content packages/ui-react --port 3000",
-    "deploy:ghpages": "gh-pages -d packages/apps/build",
+    "deploy:ghpages": "gh-pages --dist packages/apps/build --remove locales,static,*.css,*.js,*.json,*.map,*.md",
     "vanitygen": "node packages/app-vanitygen/scripts/vanitygen.js",
     "start": "cd packages/apps && webpack-serve --config webpack.config.js --port 3000"
   },
   "devDependencies": {
-    "@polkadot/dev-react": "^0.20.21",
-    "@polkadot/ts": "^0.1.30",
-    "autoprefixer": "^9.1.5",
-    "babel-loader": "^8.0.2",
-    "css-loader": "^1.0.0",
-    "enzyme": "^3.6.0",
-    "enzyme-adapter-react-16": "^1.5.0",
-    "file-loader": "^2.0.0",
-    "gh-pages": "^1.1.0",
-    "html-webpack-plugin": "^3.2.0",
-    "mini-css-extract-plugin": "^0.4.2",
-    "postcss": "^7.0.2",
+    "@babel/core": "^7.2.2",
+    "@polkadot/dev-react": "^0.23.3",
+    "@polkadot/ts": "^0.1.44",
+    "autoprefixer": "^9.4.3",
+    "empty": "^0.10.1",
+    "gh-pages": "^2.0.1",
+    "postcss": "^7.0.7",
     "postcss-clean": "^1.1.0",
     "postcss-flexbugs-fixes": "^4.1.0",
     "postcss-import": "^12.0.0",
     "postcss-loader": "^3.0.0",
-    "postcss-nested": "^3.0.0",
-    "postcss-sass": "^0.3.3",
-    "postcss-simple-vars": "^4.1.0",
-    "precss": "^3.1.2",
-    "style-loader": "^0.23.0",
-    "thread-loader": "^1.2.0",
-    "url-loader": "^1.1.1"
+    "postcss-nested": "^4.1.1",
+    "postcss-sass": "^0.3.5",
+    "postcss-simple-vars": "^5.0.0",
+    "precss": "^4.0.0",
+    "source-map-explorer": "^1.6.0"
   }
 }

+ 198 - 12
packages/app-accounts/LICENSE

@@ -1,15 +1,201 @@
-ISC License (ISC)
+                              Apache License
+                        Version 2.0, January 2004
+                    http://www.apache.org/licenses/
 
-Copyright 2017-2018 @polkadot/app-accounts authors & contributors
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
 
-Permission to use, copy, modify, and/or distribute this software for any
-purpose with or without fee is hereby granted, provided that the above
-copyright notice and this permission notice appear in all copies.
+1. Definitions.
 
-THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
-REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
-FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
-INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
-OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-PERFORMANCE OF THIS SOFTWARE.
+  "License" shall mean the terms and conditions for use, reproduction,
+  and distribution as defined by Sections 1 through 9 of this document.
+
+  "Licensor" shall mean the copyright owner or entity authorized by
+  the copyright owner that is granting the License.
+
+  "Legal Entity" shall mean the union of the acting entity and all
+  other entities that control, are controlled by, or are under common
+  control with that entity. For the purposes of this definition,
+  "control" means (i) the power, direct or indirect, to cause the
+  direction or management of such entity, whether by contract or
+  otherwise, or (ii) ownership of fifty percent (50%) or more of the
+  outstanding shares, or (iii) beneficial ownership of such entity.
+
+  "You" (or "Your") shall mean an individual or Legal Entity
+  exercising permissions granted by this License.
+
+  "Source" form shall mean the preferred form for making modifications,
+  including but not limited to software source code, documentation
+  source, and configuration files.
+
+  "Object" form shall mean any form resulting from mechanical
+  transformation or translation of a Source form, including but
+  not limited to compiled object code, generated documentation,
+  and conversions to other media types.
+
+  "Work" shall mean the work of authorship, whether in Source or
+  Object form, made available under the License, as indicated by a
+  copyright notice that is included in or attached to the work
+  (an example is provided in the Appendix below).
+
+  "Derivative Works" shall mean any work, whether in Source or Object
+  form, that is based on (or derived from) the Work and for which the
+  editorial revisions, annotations, elaborations, or other modifications
+  represent, as a whole, an original work of authorship. For the purposes
+  of this License, Derivative Works shall not include works that remain
+  separable from, or merely link (or bind by name) to the interfaces of,
+  the Work and Derivative Works thereof.
+
+  "Contribution" shall mean any work of authorship, including
+  the original version of the Work and any modifications or additions
+  to that Work or Derivative Works thereof, that is intentionally
+  submitted to Licensor for inclusion in the Work by the copyright owner
+  or by an individual or Legal Entity authorized to submit on behalf of
+  the copyright owner. For the purposes of this definition, "submitted"
+  means any form of electronic, verbal, or written communication sent
+  to the Licensor or its representatives, including but not limited to
+  communication on electronic mailing lists, source code control systems,
+  and issue tracking systems that are managed by, or on behalf of, the
+  Licensor for the purpose of discussing and improving the Work, but
+  excluding communication that is conspicuously marked or otherwise
+  designated in writing by the copyright owner as "Not a Contribution."
+
+  "Contributor" shall mean Licensor and any individual or Legal Entity
+  on behalf of whom a Contribution has been received by Licensor and
+  subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+  this License, each Contributor hereby grants to You a perpetual,
+  worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+  copyright license to reproduce, prepare Derivative Works of,
+  publicly display, publicly perform, sublicense, and distribute the
+  Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+  this License, each Contributor hereby grants to You a perpetual,
+  worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+  (except as stated in this section) patent license to make, have made,
+  use, offer to sell, sell, import, and otherwise transfer the Work,
+  where such license applies only to those patent claims licensable
+  by such Contributor that are necessarily infringed by their
+  Contribution(s) alone or by combination of their Contribution(s)
+  with the Work to which such Contribution(s) was submitted. If You
+  institute patent litigation against any entity (including a
+  cross-claim or counterclaim in a lawsuit) alleging that the Work
+  or a Contribution incorporated within the Work constitutes direct
+  or contributory patent infringement, then any patent licenses
+  granted to You under this License for that Work shall terminate
+  as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+  Work or Derivative Works thereof in any medium, with or without
+  modifications, and in Source or Object form, provided that You
+  meet the following conditions:
+
+  (a) You must give any other recipients of the Work or
+      Derivative Works a copy of this License; and
+
+  (b) You must cause any modified files to carry prominent notices
+      stating that You changed the files; and
+
+  (c) You must retain, in the Source form of any Derivative Works
+      that You distribute, all copyright, patent, trademark, and
+      attribution notices from the Source form of the Work,
+      excluding those notices that do not pertain to any part of
+      the Derivative Works; and
+
+  (d) If the Work includes a "NOTICE" text file as part of its
+      distribution, then any Derivative Works that You distribute must
+      include a readable copy of the attribution notices contained
+      within such NOTICE file, excluding those notices that do not
+      pertain to any part of the Derivative Works, in at least one
+      of the following places: within a NOTICE text file distributed
+      as part of the Derivative Works; within the Source form or
+      documentation, if provided along with the Derivative Works; or,
+      within a display generated by the Derivative Works, if and
+      wherever such third-party notices normally appear. The contents
+      of the NOTICE file are for informational purposes only and
+      do not modify the License. You may add Your own attribution
+      notices within Derivative Works that You distribute, alongside
+      or as an addendum to the NOTICE text from the Work, provided
+      that such additional attribution notices cannot be construed
+      as modifying the License.
+
+  You may add Your own copyright statement to Your modifications and
+  may provide additional or different license terms and conditions
+  for use, reproduction, or distribution of Your modifications, or
+  for any such Derivative Works as a whole, provided Your use,
+  reproduction, and distribution of the Work otherwise complies with
+  the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+  any Contribution intentionally submitted for inclusion in the Work
+  by You to the Licensor shall be under the terms and conditions of
+  this License, without any additional terms or conditions.
+  Notwithstanding the above, nothing herein shall supersede or modify
+  the terms of any separate license agreement you may have executed
+  with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+  names, trademarks, service marks, or product names of the Licensor,
+  except as required for reasonable and customary use in describing the
+  origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+  agreed to in writing, Licensor provides the Work (and each
+  Contributor provides its Contributions) on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+  implied, including, without limitation, any warranties or conditions
+  of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+  PARTICULAR PURPOSE. You are solely responsible for determining the
+  appropriateness of using or redistributing the Work and assume any
+  risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+  whether in tort (including negligence), contract, or otherwise,
+  unless required by applicable law (such as deliberate and grossly
+  negligent acts) or agreed to in writing, shall any Contributor be
+  liable to You for damages, including any direct, indirect, special,
+  incidental, or consequential damages of any character arising as a
+  result of this License or out of the use or inability to use the
+  Work (including but not limited to damages for loss of goodwill,
+  work stoppage, computer failure or malfunction, or any and all
+  other commercial damages or losses), even if such Contributor
+  has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+  the Work or Derivative Works thereof, You may choose to offer,
+  and charge a fee for, acceptance of support, warranty, indemnity,
+  or other liability obligations and/or rights consistent with this
+  License. However, in accepting such obligations, You may act only
+  on Your own behalf and on Your sole responsibility, not on behalf
+  of any other Contributor, and only if You agree to indemnify,
+  defend, and hold each Contributor harmless for any liability
+  incurred by, or claims asserted against, such Contributor by reason
+  of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+  To apply the Apache License to your work, attach the following
+  boilerplate notice, with the fields enclosed by brackets "[]"
+  replaced with your own identifying information. (Don't include
+  the brackets!)  The text should be enclosed in the appropriate
+  comment syntax for the file format. We also recommend that a
+  file or class name and description of purpose be included on the
+  same "printed page" as the copyright notice for easier
+  identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.

+ 6 - 6
packages/app-accounts/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@polkadot/app-accounts",
-  "version": "0.20.30",
+  "version": "0.21.0",
   "main": "index.js",
   "repository": "https://github.com/polkadot-js/apps.git",
   "author": "Jaco Greeff <jacogr@gmail.com>",
@@ -8,11 +8,11 @@
     "Jaco Greeff <jacogr@gmail.com>"
   ],
   "contributors": [],
-  "license": "ISC",
+  "license": "Apache-2.0",
   "dependencies": {
-    "@babel/runtime": "^7.0.0",
-    "@polkadot/ui-app": "^0.20.30",
-    "@types/file-saver": "^1.3.0",
-    "file-saver": "^1.3.8"
+    "@babel/runtime": "^7.2.0",
+    "@polkadot/ui-app": "^0.21.0",
+    "@types/file-saver": "^2.0.0",
+    "file-saver": "^2.0.0"
   }
 }

+ 34 - 26
packages/app-accounts/src/Backup.tsx

@@ -1,20 +1,20 @@
 // Copyright 2017-2018 @polkadot/app-accounts authors & contributors
 // This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
+// of the Apache-2.0 license. See the LICENSE file for details.
 
-import { KeyringPair } from '@polkadot/util-keyring/types';
+import { KeyringPair } from '@polkadot/keyring/types';
 import { I18nProps } from '@polkadot/ui-app/types';
 
 import FileSaver from 'file-saver';
 import React from 'react';
-import Button from '@polkadot/ui-app/Button';
-import Modal from '@polkadot/ui-app/Modal';
-import Password from '@polkadot/ui-app/Password';
-import AddressSummary from '@polkadot/ui-app/AddressSummary';
+import { AddressSummary, Button, Modal, Password } from '@polkadot/ui-app/index';
+import { ActionStatus } from '@polkadot/ui-app/Status/types';
+import keyring from '@polkadot/ui-keyring';
 
 import translate from './translate';
 
 type Props = I18nProps & {
+  onStatusChange: (status: ActionStatus) => void,
   onClose: () => void,
   pair: KeyringPair
 };
@@ -39,9 +39,10 @@ class Backup extends React.PureComponent<Props, State> {
   render () {
     return (
       <Modal
-        size='tiny'
+        className='app--accounts-Modal'
         dimmer='inverted'
         open
+        size='tiny'
       >
         {this.renderContent()}
         {this.renderButtons()}
@@ -87,11 +88,11 @@ class Backup extends React.PureComponent<Props, State> {
           defaultValue: 'Backup account'
         })}
       </Modal.Header>,
-      <Modal.Content key='content'>
-        <AddressSummary
-          className='accounts--Modal-Address'
-          value={pair.address()}
-        />
+      <Modal.Content
+        className='app--account-Backup-content'
+        key='content'
+      >
+        <AddressSummary value={pair.address()} />
         <div className='ui--row'>
           <Password
             isError={!isPassValid}
@@ -108,40 +109,47 @@ class Backup extends React.PureComponent<Props, State> {
   }
 
   private doBackup = (): void => {
-    const { onClose, pair } = this.props;
+    const { onClose, onStatusChange, pair, t } = this.props;
     const { password } = this.state;
 
     if (!pair) {
       return;
     }
 
-    try {
-      if (!pair.isLocked()) {
-        pair.lock();
-      }
-
-      pair.decodePkcs8(password);
-    } catch (error) {
-      this.setState({ isPassValid: false });
-      return;
-    }
+    const status = {
+      action: 'backup'
+    } as ActionStatus;
 
     try {
-      const json = JSON.stringify(pair.toJson(password));
-      const blob = new Blob([json], { type: 'application/json; charset=utf-8' });
+      const json = keyring.backupAccount(pair, password);
+      const blob = new Blob([JSON.stringify(json)], { type: 'application/json; charset=utf-8' });
+
+      status.value = pair.address();
+      status.status = blob ? 'success' : 'error';
+      status.message = t('status.backup', {
+        defaultValue: 'account backed up'
+      });
 
       FileSaver.saveAs(blob, `${pair.address()}.json`);
     } catch (error) {
       this.setState({ isPassValid: false });
+      console.error(error);
+
+      status.status = 'error';
+      status.message = t('status.error', {
+        defaultValue: error.message
+      });
       return;
     }
 
+    onStatusChange(status);
+
     onClose();
   }
 
   private onChangePass = (password: string) => {
     this.setState({
-      isPassValid: password.length > 0 && password.length <= 32,
+      isPassValid: keyring.isPassValid(password),
       password
     });
   }

+ 32 - 15
packages/app-accounts/src/ChangePass.tsx

@@ -1,22 +1,21 @@
 // Copyright 2017-2018 @polkadot/app-accounts authors & contributors
 // This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
+// of the Apache-2.0 license. See the LICENSE file for details.
 
-import { KeyringPair } from '@polkadot/util-keyring/types';
+import { KeyringPair } from '@polkadot/keyring/types';
 import { I18nProps } from '@polkadot/ui-app/types';
 
 import React from 'react';
-import Button from '@polkadot/ui-app/Button';
-import Modal from '@polkadot/ui-app/Modal';
-import Password from '@polkadot/ui-app/Password';
-import AddressSummary from '@polkadot/ui-app/AddressSummary';
-import keyring from '@polkadot/ui-keyring/index';
+import { AddressSummary, Button, Modal, Password } from '@polkadot/ui-app/index';
+import { ActionStatus } from '@polkadot/ui-app/Status/types';
+import keyring from '@polkadot/ui-keyring';
 
 import translate from './translate';
 
 type Props = I18nProps & {
   account: KeyringPair,
-  onClose: () => void
+  onClose: () => void,
+  onStatusChange: (status: ActionStatus) => void
 };
 
 type State = {
@@ -43,7 +42,7 @@ class ChangePass extends React.PureComponent<Props, State> {
   render () {
     return (
       <Modal
-        className='accounts--ChangePass-Modal'
+        className='app--accounts-Modal'
         dimmer='inverted'
         open
         size='tiny'
@@ -93,10 +92,7 @@ class ChangePass extends React.PureComponent<Props, State> {
         })}
       </Modal.Header>,
       <Modal.Content key='content'>
-        <AddressSummary
-          className='accounts--Modal-Address'
-          value={account.address()}
-        />
+        <AddressSummary value={account.address()} />
         <div className='ui--row'>
           <Password
             autoFocus
@@ -119,9 +115,13 @@ class ChangePass extends React.PureComponent<Props, State> {
   }
 
   private doChange = (): void => {
-    const { account, onClose } = this.props;
+    const { account, onClose, onStatusChange, t } = this.props;
     const { newPass, oldPass } = this.state;
 
+    const status = {
+      action: 'changePassword'
+    } as ActionStatus;
+
     try {
       if (!account.isLocked()) {
         account.lock();
@@ -130,16 +130,33 @@ class ChangePass extends React.PureComponent<Props, State> {
       account.decodePkcs8(oldPass);
     } catch (error) {
       this.setState({ isOldValid: false });
+
+      status.message = t('status.error', {
+        defaultValue: error.message
+      });
+
       return;
     }
 
     try {
       keyring.encryptAccount(account, newPass);
+
+      status.value = account.address();
+      status.status = 'success';
+      status.message = t('status.change-password', {
+        defaultValue: 'password changed'
+      });
     } catch (error) {
       this.setState({ isNewValid: false });
+
+      status.status = 'error';
+      status.message = error.message;
+
       return;
     }
 
+    onStatusChange(status);
+
     onClose();
   }
 
@@ -158,7 +175,7 @@ class ChangePass extends React.PureComponent<Props, State> {
   }
 
   private validatePass (password: string): boolean {
-    return password.length > 0 && password.length <= 32;
+    return keyring.isPassValid(password);
   }
 }
 

+ 184 - 65
packages/app-accounts/src/Creator.tsx

@@ -1,34 +1,32 @@
 // Copyright 2017-2018 @polkadot/app-accounts authors & contributors
 // This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
+// of the Apache-2.0 license. See the LICENSE file for details.
 
 import { I18nProps } from '@polkadot/ui-app/types';
+import { ActionStatus } from '@polkadot/ui-app/Status/types';
 
 import React from 'react';
-
-import Button from '@polkadot/ui-app/Button';
-import Input from '@polkadot/ui-app/Input';
+import { AddressSummary, Button, Dropdown, Input, Modal, Password } from '@polkadot/ui-app/index';
 import { InputAddress } from '@polkadot/ui-app/InputAddress';
-import Password from '@polkadot/ui-app/Password';
-import keyring from '@polkadot/ui-keyring/index';
-import isHex from '@polkadot/util/is/hex';
-import hexToU8a from '@polkadot/util/hex/toU8a';
-import u8aFromString from '@polkadot/util/u8a/fromString';
-import u8aToHex from '@polkadot/util/u8a/toHex';
-import keypairFromSeed from '@polkadot/util-crypto/nacl/keypair/fromSeed';
-import randomBytes from '@polkadot/util-crypto/random/asU8a';
-import addressEncode from '@polkadot/util-keyring/address/encode';
-import Modal from '@polkadot/ui-app/Modal';
-
-import AddressSummary from '@polkadot/ui-app/AddressSummary';
+import { hexToU8a, isHex, stringToU8a, u8aToHex } from '@polkadot/util';
+import { mnemonicToSeed, mnemonicValidate, naclKeypairFromSeed, randomAsU8a } from '@polkadot/util-crypto';
+import keyring from '@polkadot/ui-keyring';
+
 import translate from './translate';
+import FileSaver from 'file-saver';
+
+const BipWorker = require('worker-loader?name=[name].[hash:8].js!./bipWorker');
 
 type Props = I18nProps & {
-  onBack: () => void
+  onStatusChange: (status: ActionStatus) => void,
+  onCreateAccount: () => void
 };
 
+type SeedType = 'bip' | 'raw';
+
 type State = {
   address: string,
+  isBipBusy: boolean,
   isNameValid: boolean,
   isSeedValid: boolean,
   isPassValid: boolean,
@@ -36,30 +34,55 @@ type State = {
   name: string,
   password: string,
   seed: string,
+  seedOptions: Array<{ value: SeedType, text: string }>,
+  seedType: SeedType,
   showWarning: boolean
 };
 
 function formatSeed (seed: string): Uint8Array {
   return isHex(seed)
     ? hexToU8a(seed)
-    : u8aFromString(seed.padEnd(32, ' '));
+    : stringToU8a((seed as string).padEnd(32, ' '));
 }
 
-function addressFromSeed (seed: string): string {
-  return addressEncode(
-    keypairFromSeed(
-      formatSeed(seed)
-    ).publicKey
+function addressFromSeed (seed: string, seedType: SeedType): string {
+  const keypair = naclKeypairFromSeed(
+    seedType === 'bip'
+      ? mnemonicToSeed(seed)
+      : formatSeed(seed)
+  );
+
+  return keyring.encodeAddress(
+    keypair.publicKey
   );
 }
 
 class Creator extends React.PureComponent<Props, State> {
-  state: State;
+  bipWorker: any;
+  state: State = { seedType: 'bip' } as State;
 
   constructor (props: Props) {
     super(props);
 
-    this.state = this.emptyState();
+    const { t } = this.props;
+
+    this.bipWorker = new BipWorker();
+    this.bipWorker.onmessage = (event: MessageEvent) => {
+      const { publicKey, seed } = event.data;
+
+      this.setState({
+        address: keyring.encodeAddress(publicKey),
+        isBipBusy: false,
+        seed
+      });
+    };
+    this.state = {
+      ...this.emptyState(),
+      seedOptions: [
+        { value: 'bip', text: t('seedType.bip', { defaultValue: 'Mnemonic' }) },
+        { value: 'raw', text: t('seedType.raw', { defaultValue: 'Raw seed' }) }
+      ]
+    };
   }
 
   render () {
@@ -110,23 +133,13 @@ class Creator extends React.PureComponent<Props, State> {
 
   renderInput () {
     const { t } = this.props;
-    const { isNameValid, isPassValid, isSeedValid, name, password, seed, showWarning } = this.state;
+    const { isBipBusy, isNameValid, isPassValid, isSeedValid, name, password, seed, seedOptions, seedType, showWarning } = this.state;
 
     return (
       <div className='grow'>
         <div className='ui--row'>
           <Input
-            className='full'
-            isError={!isSeedValid}
-            label={t('creator.seed', {
-              defaultValue: 'create from the following seed (hex or string)'
-            })}
-            onChange={this.onChangeSeed}
-            value={seed}
-          />
-        </div>
-        <div className='ui--row'>
-          <Input
+            autoFocus
             className='full'
             isError={!isNameValid}
             label={t('creator.name', {
@@ -136,6 +149,39 @@ class Creator extends React.PureComponent<Props, State> {
             value={name}
           />
         </div>
+        <div className='ui--row'>
+          <Input
+            className='full'
+            isAction
+            isDisabled={isBipBusy}
+            isError={!isSeedValid}
+            label={
+              seedType === 'bip'
+                ? t('creator.seed.bip', {
+                  defaultValue: 'create from the following mnemonic seed'
+                })
+                : t('creator.seed.raw', {
+                  defaultValue: 'create from the following seed (hex or string)'
+                })
+            }
+            onChange={this.onChangeSeed}
+            placeholder={
+              isBipBusy
+                ? t('creator.seed.bipBusy', {
+                  defaultValue: 'Generating Mnemeonic seed'
+                })
+                : null
+            }
+            value={isBipBusy ? '' : seed}
+          >
+            <Dropdown
+              isButton
+              defaultValue={seedType}
+              onChange={this.selectSeedType}
+              options={seedOptions}
+            />
+          </Input>
+        </div>
         <div className='ui--row'>
           <Password
             className='full'
@@ -148,8 +194,10 @@ class Creator extends React.PureComponent<Props, State> {
           />
         </div>
         <Modal
+          className='app--accounts-Modal'
           dimmer='inverted'
           open={showWarning}
+          size='small'
         >
           {this.renderModalContent()}
           {this.renderModalButtons()}
@@ -176,7 +224,7 @@ class Creator extends React.PureComponent<Props, State> {
             isPrimary
             onClick={this.onCommit}
             text={t('seedWarning.continue', {
-              defaultValue: 'Continue'
+              defaultValue: 'Create and backup account'
             })}
           />
         </Button.Group>
@@ -186,55 +234,89 @@ class Creator extends React.PureComponent<Props, State> {
 
   renderModalContent () {
     const { t } = this.props;
+    const { address } = this.state;
 
     return [
       <Modal.Header key='header'>
         {t('seedWarning.header', {
-          defaultValue: 'Warning'
+          defaultValue: 'Important notice!'
         })}
       </Modal.Header>,
       <Modal.Content key='content'>
         {t('seedWarning.content', {
-          defaultValue: 'Before you continue, make sure you have properly backed up your seed in a safe place as it is needed to restore your account.'
+          defaultValue: 'We will provide you with a generated backup file after your account is created. As long as you have access to your account you can always redownload this file later.'
         })}
+        <Modal.Description>
+          {t('seedWarning.description', {
+            defaultValue: 'Please make sure to save this file in a secure location as it is the only way to restore your account.'
+          })}
+        </Modal.Description>
+        <AddressSummary
+          className='accounts--Modal-Address'
+          value={address}
+        />
       </Modal.Content>
     ];
   }
 
-  emptyState (): State {
-    const seed = u8aToHex(randomBytes());
-    const address = addressFromSeed(seed);
+  private generateSeed (seedType: SeedType): State {
+    if (seedType === 'bip') {
+      this.bipWorker.postMessage('create');
+
+      return {
+        isBipBusy: true,
+        seed: ''
+      } as State;
+    }
+
+    const seed = u8aToHex(randomAsU8a());
+    const address = addressFromSeed(seed, seedType);
 
     return {
       address,
+      isBipBusy: false,
+      seed
+    } as State;
+  }
+
+  private emptyState (): State {
+    const { seedType } = this.state;
+
+    return {
+      ...this.generateSeed(seedType),
       isNameValid: true,
       isPassValid: false,
       isSeedValid: true,
       isValid: false,
       name: 'new keypair',
       password: '',
-      seed,
+      seedType,
       showWarning: false
     };
   }
 
-  nextState (newState: State): void {
+  private nextState (newState: State): void {
     this.setState(
       (prevState: State, props: Props): State => {
-        const { name = prevState.name, password = prevState.password, seed = prevState.seed, showWarning = prevState.showWarning } = newState;
+        const { isBipBusy = prevState.isBipBusy, name = prevState.name, password = prevState.password, seed = prevState.seed, seedOptions = prevState.seedOptions, seedType = prevState.seedType, showWarning = prevState.showWarning } = newState;
         let address = prevState.address;
         const isNameValid = !!name;
-        const isSeedValid = isHex(seed)
-          ? seed.length === 66
-          : seed.length <= 32;
-        const isPassValid = password.length > 0 && password.length <= 32;
+        const isSeedValid = seedType === 'bip'
+          ? mnemonicValidate(seed)
+          : (
+            isHex(seed)
+              ? seed.length === 66
+              : (seed as string).length <= 32
+          );
+        const isPassValid = keyring.isPassValid(password);
 
         if (isSeedValid && seed !== prevState.seed) {
-          address = addressFromSeed(seed);
+          address = addressFromSeed(seed, seedType);
         }
 
         return {
           address,
+          isBipBusy,
           isNameValid,
           isPassValid,
           isSeedValid,
@@ -242,48 +324,85 @@ class Creator extends React.PureComponent<Props, State> {
           name,
           password,
           seed,
+          seedOptions,
+          seedType,
           showWarning
         };
       }
     );
   }
 
-  onChangeSeed = (seed: string): void => {
+  private onChangeSeed = (seed: string): void => {
     this.nextState({ seed } as State);
   }
 
-  onChangeName = (name: string): void => {
+  private onChangeName = (name: string): void => {
     this.nextState({ name } as State);
   }
 
-  onChangePass = (password: string): void => {
+  private onChangePass = (password: string): void => {
     this.nextState({ password } as State);
   }
 
-  onShowWarning = (): void => {
+  private onShowWarning = (): void => {
     this.nextState({ showWarning: true } as State);
   }
 
-  onHideWarning = (): void => {
+  private onHideWarning = (): void => {
     this.nextState({ showWarning: false } as State);
   }
 
-  onCommit = (): void => {
-    const { onBack } = this.props;
-    const { name, password, seed } = this.state;
-    const pair = keyring.createAccount(
-      formatSeed(seed), password, { name }
-    );
+  private onCommit = (): void => {
+    const { onCreateAccount, onStatusChange, t } = this.props;
+    const { name, password, seed, seedType } = this.state;
+
+    const status = {
+      action: 'create'
+    } as ActionStatus;
+
+    try {
+      const pair = seedType === 'bip'
+        ? keyring.createAccountMnemonic(seed, password, { name })
+        : keyring.createAccount(formatSeed(seed), password, { name });
+
+      const json = pair.toJson(password);
+      const blob = new Blob([JSON.stringify(json)], { type: 'application/json; charset=utf-8' });
+
+      FileSaver.saveAs(blob, `${pair.address()}.json`);
+
+      status.value = pair.address();
+      status.status = pair ? 'success' : 'error';
+      status.message = t('status.created', {
+        defaultValue: `created account`
+      });
+
+      InputAddress.setLastValue('account', pair.address());
+    } catch (err) {
+      status.status = 'error';
+      status.message = err.message;
+    }
 
     this.onHideWarning();
-    InputAddress.setLastValue('account', pair.address());
 
-    onBack();
+    onCreateAccount();
+
+    onStatusChange(status);
   }
 
-  onDiscard = (): void => {
+  private onDiscard = (): void => {
     this.setState(this.emptyState());
   }
+
+  private selectSeedType = (seedType: SeedType): void => {
+    if (seedType === this.state.seedType) {
+      return;
+    }
+
+    this.setState({
+      ...this.generateSeed(seedType),
+      seedType
+    });
+  }
 }
 
 export default translate(Creator);

+ 60 - 23
packages/app-accounts/src/Editor.tsx

@@ -1,16 +1,15 @@
 // Copyright 2017-2018 @polkadot/app-accounts authors & contributors
 // This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
+// of the Apache-2.0 license. See the LICENSE file for details.
 
-import { KeyringPair } from '@polkadot/util-keyring/types';
+import { KeyringPair } from '@polkadot/keyring/types';
 import { I18nProps } from '@polkadot/ui-app/types';
+import { ActionStatus } from '@polkadot/ui-app/Status/types';
+import { SubjectInfo } from '@polkadot/ui-keyring/observable/types';
 
 import React from 'react';
-import AddressSummary from '@polkadot/ui-app/AddressSummary';
-import Button from '@polkadot/ui-app/Button';
-import Input from '@polkadot/ui-app/Input';
-import InputAddress from '@polkadot/ui-app/InputAddress';
-import keyring from '@polkadot/ui-keyring/index';
+import { AddressSummary, Button, Input, InputAddress } from '@polkadot/ui-app/index';
+import keyring from '@polkadot/ui-keyring';
 
 import Backup from './Backup';
 import ChangePass from './ChangePass';
@@ -18,8 +17,8 @@ import Forgetting from './Forgetting';
 import translate from './translate';
 
 type Props = I18nProps & {
-  allAccounts?: Array<any>,
-  onBack: () => void
+  allAccounts?: SubjectInfo,
+  onStatusChange: (status: ActionStatus) => void
 };
 
 type State = {
@@ -149,6 +148,7 @@ class Editor extends React.PureComponent<Props, State> {
   }
 
   renderModals () {
+    const { onStatusChange } = this.props;
     const { current, isBackupOpen, isForgetOpen, isPasswordOpen } = this.state;
 
     if (!current) {
@@ -162,8 +162,9 @@ class Editor extends React.PureComponent<Props, State> {
       modals.push(
         <Backup
           key='modal-backup-account'
-          pair={current}
           onClose={this.toggleBackup}
+          onStatusChange={onStatusChange}
+          pair={current}
         />
       );
     }
@@ -171,10 +172,10 @@ class Editor extends React.PureComponent<Props, State> {
     if (isForgetOpen) {
       modals.push(
         <Forgetting
-          key='modal-forget-account'
           address={address}
-          onClose={this.toggleForget}
           doForget={this.onForget}
+          key='modal-forget-account'
+          onClose={this.toggleForget}
         />
       );
     }
@@ -185,6 +186,7 @@ class Editor extends React.PureComponent<Props, State> {
           account={current}
           key='modal-change-pass'
           onClose={this.togglePass}
+          onStatusChange={onStatusChange}
         />
       );
     }
@@ -234,10 +236,10 @@ class Editor extends React.PureComponent<Props, State> {
     );
   }
 
-  onChangeAccount = (publicKey: Uint8Array): void => {
-    const current = publicKey && publicKey.length === 32
-      ? keyring.getPair(publicKey)
-      : null;
+  onChangeAccount = (accountId?: string): void => {
+    const current = accountId
+        ? keyring.getPair(accountId)
+        : null;
 
     this.nextState({
       current
@@ -249,16 +251,34 @@ class Editor extends React.PureComponent<Props, State> {
   }
 
   onCommit = (): void => {
+    const { onStatusChange, t } = this.props;
     const { current, editedName } = this.state;
 
     if (!current) {
       return;
     }
 
-    keyring.saveAccountMeta(current, {
-      name: editedName,
-      whenEdited: Date.now()
-    });
+    const status = {
+      action: 'edit',
+      value: current.address()
+    } as ActionStatus;
+
+    try {
+      keyring.saveAccountMeta(current, {
+        name: editedName,
+        whenEdited: Date.now()
+      });
+
+      status.status = current.getMeta().name === editedName ? 'success' : 'error';
+      status.message = t('status.editted', {
+        defaultValue: 'name edited'
+      });
+    } catch (error) {
+      status.status = 'error';
+      status.message = error.message;
+    }
+
+    onStatusChange(status);
 
     this.nextState({} as State);
   }
@@ -309,6 +329,7 @@ class Editor extends React.PureComponent<Props, State> {
   }
 
   onForget = (): void => {
+    const { onStatusChange, t } = this.props;
     const { current } = this.state;
 
     if (!current) {
@@ -318,9 +339,25 @@ class Editor extends React.PureComponent<Props, State> {
     this.setState(
       this.createState(null),
       () => {
-        keyring.forgetAccount(
-          current.address()
-        );
+        const status = {
+          action: 'forget',
+          value: current.address()
+        } as ActionStatus;
+
+        try {
+          keyring.forgetAccount(
+            current.address()
+          );
+          status.status = 'success';
+          status.message = t('status.forgotten', {
+            defaultValue: 'account forgotten'
+          });
+        } catch (err) {
+          status.status = 'error';
+          status.message = err.message;
+        }
+
+        onStatusChange(status);
       }
     );
   }

+ 3 - 9
packages/app-accounts/src/Forgetting.tsx

@@ -1,13 +1,11 @@
 // Copyright 2017-2018 @polkadot/app-accounts authors & contributors
 // This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
+// of the Apache-2.0 license. See the LICENSE file for details.
 
 import { I18nProps } from '@polkadot/ui-app/types';
 
 import React from 'react';
-import AddressSummary from '@polkadot/ui-app/AddressSummary';
-import Button from '@polkadot/ui-app/Button';
-import Modal from '@polkadot/ui-app/Modal';
+import { AddressSummary, Button, Modal } from '@polkadot/ui-app/index';
 
 import translate from './translate';
 
@@ -68,11 +66,7 @@ class Forgetting extends React.PureComponent<Props> {
         })}
       </Modal.Header>,
       <Modal.Content key='content'>
-        <AddressSummary
-          className='accounts--Modal-Address'
-          value={address}
-          withCopy={false}
-        />
+        <AddressSummary value={address} />
       </Modal.Content>
     ];
   }

+ 41 - 36
packages/app-accounts/src/Restore.tsx

@@ -1,28 +1,23 @@
 // Copyright 2017-2018 @polkadot/app-accounts authors & contributors
 // This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
+// of the Apache-2.0 license. See the LICENSE file for details.
 
-import { KeyringPair$Json } from '@polkadot/util-keyring/types';
+import { KeyringPair$Json } from '@polkadot/keyring/types';
 import { I18nProps } from '@polkadot/ui-app/types';
 
 import React from 'react';
-import AddressSummary from '@polkadot/ui-app/AddressSummary';
-import Button from '@polkadot/ui-app/Button';
-import InputFile from '@polkadot/ui-app/InputFile';
+import { AddressSummary, Button, InputFile, Password } from '@polkadot/ui-app/index';
 import { InputAddress } from '@polkadot/ui-app/InputAddress';
-import Password from '@polkadot/ui-app/Password';
-import createPair from '@polkadot/util-keyring/pair';
-import decodeAddress from '@polkadot/util-keyring/address/decode';
-import isHex from '@polkadot/util/is/hex';
-import isObject from '@polkadot/util/is/object';
-import hexToU8a from '@polkadot/util/hex/toU8a';
-import u8aToUtf8 from '@polkadot/util/u8a/toUtf8';
-import keyring from '@polkadot/ui-keyring/index';
+import { decodeAddress } from '@polkadot/keyring';
+import { isHex, isObject, u8aToString } from '@polkadot/util';
+import keyring from '@polkadot/ui-keyring';
 
 import translate from './translate';
+import { ActionStatus } from '@polkadot/ui-app/Status/types';
 
 type Props = I18nProps & {
-  onBack: () => void
+  onStatusChange: (status: ActionStatus) => void,
+  onRestoreAccount: () => void
 };
 
 type State = {
@@ -39,9 +34,9 @@ class Restore extends React.PureComponent<Props, State> {
     super(props);
 
     this.state = {
-      json: null,
       isFileValid: false,
       isPassValid: false,
+      json: null,
       password: ''
     };
   }
@@ -77,14 +72,17 @@ class Restore extends React.PureComponent<Props, State> {
     );
   }
 
-  renderInput () {
+  private renderInput () {
     const { t } = this.props;
     const { isFileValid, isPassValid, password } = this.state;
 
+    const acceptedFormats = ['application/json', 'text/plain'].join(', ');
+
     return (
       <div className='grow'>
         <div className='ui--row'>
           <Password
+            autoFocus
             className='full'
             isError={!isPassValid}
             label={t('restore.password', {
@@ -96,21 +94,23 @@ class Restore extends React.PureComponent<Props, State> {
         </div>
         <div className='ui--row'>
           <InputFile
+            accept={acceptedFormats}
             className='full'
             isError={!isFileValid}
             label={t('restore.json', {
               defaultValue: 'previously backed-up json keyfile'
             })}
             onChange={this.onChangeFile}
+            withLabel
           />
         </div>
       </div>
     );
   }
 
-  onChangeFile = (file: Uint8Array): void => {
+  private onChangeFile = (file: Uint8Array): void => {
     try {
-      const json = JSON.parse(u8aToUtf8(file));
+      const json = JSON.parse(u8aToString(file));
       const isFileValid = decodeAddress(json.address).length === 32 &&
         isHex(json.encoded) &&
         isObject(json.meta) &&
@@ -125,44 +125,49 @@ class Restore extends React.PureComponent<Props, State> {
         isFileValid: false,
         json: null
       });
+      console.error(error);
     }
   }
 
-  onChangePass = (password: string): void => {
+  private onChangePass = (password: string): void => {
     this.setState({
-      isPassValid: password.length > 0 && password.length <= 32,
+      isPassValid: keyring.isPassValid(password),
       password
     });
   }
 
-  onSave = (): void => {
-    const { onBack } = this.props;
+  private onSave = (): void => {
+    const { onRestoreAccount, onStatusChange, t } = this.props;
     const { json, password } = this.state;
 
     if (!json) {
       return;
     }
 
+    const status = {
+      action: 'restore'
+    } as ActionStatus;
+
     try {
-      const pair = createPair(
-        {
-          publicKey: decodeAddress(json.address),
-          secretKey: new Uint8Array()
-        },
-        json.meta,
-        hexToU8a(json.encoded)
-      );
-
-      // unlock, save account and then lock (locking cleans secretKey, so needs to be last)
-      pair.decodePkcs8(password);
-      keyring.addAccountPair(pair, password);
-      pair.lock();
+      const pair = keyring.restoreAccount(json, password);
+
+      status.status = pair ? 'success' : 'error';
+      status.value = pair.address();
+      status.message = t('status.restored', {
+        defaultValue: 'account restored'
+      });
 
       InputAddress.setLastValue('account', pair.address());
-      onBack();
+      onRestoreAccount();
     } catch (error) {
       this.setState({ isPassValid: false });
+
+      status.status = 'error';
+      status.message = error.message;
+      console.error(error);
     }
+
+    onStatusChange(status);
   }
 }
 

+ 19 - 0
packages/app-accounts/src/bipWorker.ts

@@ -0,0 +1,19 @@
+// Copyright 2017-2018 @polkadot/app-accounts authors & contributors
+// This software may be modified and distributed under the terms
+// of the Apache-2.0 license. See the LICENSE file for details.
+
+import { mnemonicGenerate, mnemonicToSeed, naclKeypairFromSeed } from '@polkadot/util-crypto';
+
+const ctx: Worker = self as any;
+
+ctx.onmessage = () => {
+  const seed = mnemonicGenerate();
+  const { publicKey } = naclKeypairFromSeed(
+    mnemonicToSeed(seed)
+  );
+
+  ctx.postMessage({
+    publicKey,
+    seed
+  });
+};

+ 6 - 3
packages/app-accounts/src/index.css

@@ -1,7 +1,10 @@
 /* Copyright 2017-2018 @polkadot/app-accounts authors & contributors
 /* This software may be modified and distributed under the terms
-/* of the ISC license. See the LICENSE file for details. */
+/* of the Apache-2.0 license. See the LICENSE file for details. */
 
-.accounts--Modal-Address {
-  text-align: center;
+@import '../../ui-app/src/styles/partials/_variables.css';
+
+.app--accounts-Modal .ui--AddressSummary {
+  display: inline-block;
+  margin-bottom: 1em;
 }

+ 17 - 10
packages/app-accounts/src/index.tsx

@@ -1,16 +1,18 @@
 // Copyright 2017-2018 @polkadot/app-accounts authors & contributors
 // This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
+// of the Apache-2.0 license. See the LICENSE file for details.
 
 import { I18nProps } from '@polkadot/ui-app/types';
+import { TabItem } from '@polkadot/ui-app/Tabs';
 import { SubjectInfo } from '@polkadot/ui-keyring/observable/types';
+import { Actions, ActionStatus } from '@polkadot/ui-app/Status/types';
 
 import './index.css';
 
 import React from 'react';
 import accountObservable from '@polkadot/ui-keyring/observable/accounts';
-import Tabs, { TabItem } from '@polkadot/ui-app/Tabs';
-import withObservableBase from '@polkadot/ui-react-rx/with/observableBase';
+import { Tabs } from '@polkadot/ui-app/index';
+import { withMulti, withObservableBase } from '@polkadot/ui-react-rx/with/index';
 
 import Creator from './Creator';
 import Editor from './Editor';
@@ -19,18 +21,16 @@ import translate from './translate';
 
 type Props = I18nProps & {
   allAccounts?: SubjectInfo,
+  onStatusChange: (status: ActionStatus) => void,
   basePath: string
 };
 
-type Actions = 'create' | 'edit' | 'restore';
-
 type State = {
   action: Actions,
   hidden: Array<string>,
   items: Array<TabItem>
 };
 
-// FIXME React-router would probably be the best route, not home-grown
 const Components: { [index: string]: React.ComponentType<any> } = {
   'create': Creator,
   'edit': Editor,
@@ -96,6 +96,7 @@ class AccountsApp extends React.PureComponent<Props, State> {
   }
 
   render () {
+    const { onStatusChange } = this.props;
     const { action, hidden, items } = this.state;
     const Component = Components[action];
 
@@ -109,7 +110,11 @@ class AccountsApp extends React.PureComponent<Props, State> {
             onChange={this.onMenuChange}
           />
         </header>
-        <Component onBack={this.selectEdit} />
+        <Component
+          onCreateAccount={this.selectEdit}
+          onRestoreAccount={this.selectEdit}
+          onStatusChange={onStatusChange}
+        />
       </main>
     );
   }
@@ -123,6 +128,8 @@ class AccountsApp extends React.PureComponent<Props, State> {
   }
 }
 
-export default withObservableBase(
-  accountObservable.subject, { propName: 'allAccounts' }
-)(translate(AccountsApp));
+export default withMulti(
+  AccountsApp,
+  translate,
+  withObservableBase(accountObservable.subject, { propName: 'allAccounts' })
+);

+ 3 - 3
packages/app-accounts/src/translate.ts

@@ -1,7 +1,7 @@
 // Copyright 2017-2018 @polkadot/app-accounts authors & contributors
 // This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
+// of the Apache-2.0 license. See the LICENSE file for details.
 
-import { translate } from 'react-i18next';
+import { withNamespaces } from 'react-i18next';
 
-export default translate(['accounts', 'ui']);
+export default withNamespaces(['accounts', 'ui']);

+ 8 - 0
packages/app-accounts/src/worker-loader.d.ts

@@ -0,0 +1,8 @@
+declare module 'worker-loader!*' {
+  class WebpackWorker extends Worker {
+    constructor();
+  }
+
+  // @ts-ignore valid according to integration instructions: https://github.com/webpack-contrib/worker-loader#integrating-with-typescript
+  export = WebpackWorker;
+}

+ 198 - 12
packages/app-addresses/LICENSE

@@ -1,15 +1,201 @@
-ISC License (ISC)
+                              Apache License
+                        Version 2.0, January 2004
+                    http://www.apache.org/licenses/
 
-Copyright 2017-2018 @polkadot/app-addresses authors & contributors
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
 
-Permission to use, copy, modify, and/or distribute this software for any
-purpose with or without fee is hereby granted, provided that the above
-copyright notice and this permission notice appear in all copies.
+1. Definitions.
 
-THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
-REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
-FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
-INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
-OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-PERFORMANCE OF THIS SOFTWARE.
+  "License" shall mean the terms and conditions for use, reproduction,
+  and distribution as defined by Sections 1 through 9 of this document.
+
+  "Licensor" shall mean the copyright owner or entity authorized by
+  the copyright owner that is granting the License.
+
+  "Legal Entity" shall mean the union of the acting entity and all
+  other entities that control, are controlled by, or are under common
+  control with that entity. For the purposes of this definition,
+  "control" means (i) the power, direct or indirect, to cause the
+  direction or management of such entity, whether by contract or
+  otherwise, or (ii) ownership of fifty percent (50%) or more of the
+  outstanding shares, or (iii) beneficial ownership of such entity.
+
+  "You" (or "Your") shall mean an individual or Legal Entity
+  exercising permissions granted by this License.
+
+  "Source" form shall mean the preferred form for making modifications,
+  including but not limited to software source code, documentation
+  source, and configuration files.
+
+  "Object" form shall mean any form resulting from mechanical
+  transformation or translation of a Source form, including but
+  not limited to compiled object code, generated documentation,
+  and conversions to other media types.
+
+  "Work" shall mean the work of authorship, whether in Source or
+  Object form, made available under the License, as indicated by a
+  copyright notice that is included in or attached to the work
+  (an example is provided in the Appendix below).
+
+  "Derivative Works" shall mean any work, whether in Source or Object
+  form, that is based on (or derived from) the Work and for which the
+  editorial revisions, annotations, elaborations, or other modifications
+  represent, as a whole, an original work of authorship. For the purposes
+  of this License, Derivative Works shall not include works that remain
+  separable from, or merely link (or bind by name) to the interfaces of,
+  the Work and Derivative Works thereof.
+
+  "Contribution" shall mean any work of authorship, including
+  the original version of the Work and any modifications or additions
+  to that Work or Derivative Works thereof, that is intentionally
+  submitted to Licensor for inclusion in the Work by the copyright owner
+  or by an individual or Legal Entity authorized to submit on behalf of
+  the copyright owner. For the purposes of this definition, "submitted"
+  means any form of electronic, verbal, or written communication sent
+  to the Licensor or its representatives, including but not limited to
+  communication on electronic mailing lists, source code control systems,
+  and issue tracking systems that are managed by, or on behalf of, the
+  Licensor for the purpose of discussing and improving the Work, but
+  excluding communication that is conspicuously marked or otherwise
+  designated in writing by the copyright owner as "Not a Contribution."
+
+  "Contributor" shall mean Licensor and any individual or Legal Entity
+  on behalf of whom a Contribution has been received by Licensor and
+  subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+  this License, each Contributor hereby grants to You a perpetual,
+  worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+  copyright license to reproduce, prepare Derivative Works of,
+  publicly display, publicly perform, sublicense, and distribute the
+  Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+  this License, each Contributor hereby grants to You a perpetual,
+  worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+  (except as stated in this section) patent license to make, have made,
+  use, offer to sell, sell, import, and otherwise transfer the Work,
+  where such license applies only to those patent claims licensable
+  by such Contributor that are necessarily infringed by their
+  Contribution(s) alone or by combination of their Contribution(s)
+  with the Work to which such Contribution(s) was submitted. If You
+  institute patent litigation against any entity (including a
+  cross-claim or counterclaim in a lawsuit) alleging that the Work
+  or a Contribution incorporated within the Work constitutes direct
+  or contributory patent infringement, then any patent licenses
+  granted to You under this License for that Work shall terminate
+  as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+  Work or Derivative Works thereof in any medium, with or without
+  modifications, and in Source or Object form, provided that You
+  meet the following conditions:
+
+  (a) You must give any other recipients of the Work or
+      Derivative Works a copy of this License; and
+
+  (b) You must cause any modified files to carry prominent notices
+      stating that You changed the files; and
+
+  (c) You must retain, in the Source form of any Derivative Works
+      that You distribute, all copyright, patent, trademark, and
+      attribution notices from the Source form of the Work,
+      excluding those notices that do not pertain to any part of
+      the Derivative Works; and
+
+  (d) If the Work includes a "NOTICE" text file as part of its
+      distribution, then any Derivative Works that You distribute must
+      include a readable copy of the attribution notices contained
+      within such NOTICE file, excluding those notices that do not
+      pertain to any part of the Derivative Works, in at least one
+      of the following places: within a NOTICE text file distributed
+      as part of the Derivative Works; within the Source form or
+      documentation, if provided along with the Derivative Works; or,
+      within a display generated by the Derivative Works, if and
+      wherever such third-party notices normally appear. The contents
+      of the NOTICE file are for informational purposes only and
+      do not modify the License. You may add Your own attribution
+      notices within Derivative Works that You distribute, alongside
+      or as an addendum to the NOTICE text from the Work, provided
+      that such additional attribution notices cannot be construed
+      as modifying the License.
+
+  You may add Your own copyright statement to Your modifications and
+  may provide additional or different license terms and conditions
+  for use, reproduction, or distribution of Your modifications, or
+  for any such Derivative Works as a whole, provided Your use,
+  reproduction, and distribution of the Work otherwise complies with
+  the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+  any Contribution intentionally submitted for inclusion in the Work
+  by You to the Licensor shall be under the terms and conditions of
+  this License, without any additional terms or conditions.
+  Notwithstanding the above, nothing herein shall supersede or modify
+  the terms of any separate license agreement you may have executed
+  with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+  names, trademarks, service marks, or product names of the Licensor,
+  except as required for reasonable and customary use in describing the
+  origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+  agreed to in writing, Licensor provides the Work (and each
+  Contributor provides its Contributions) on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+  implied, including, without limitation, any warranties or conditions
+  of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+  PARTICULAR PURPOSE. You are solely responsible for determining the
+  appropriateness of using or redistributing the Work and assume any
+  risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+  whether in tort (including negligence), contract, or otherwise,
+  unless required by applicable law (such as deliberate and grossly
+  negligent acts) or agreed to in writing, shall any Contributor be
+  liable to You for damages, including any direct, indirect, special,
+  incidental, or consequential damages of any character arising as a
+  result of this License or out of the use or inability to use the
+  Work (including but not limited to damages for loss of goodwill,
+  work stoppage, computer failure or malfunction, or any and all
+  other commercial damages or losses), even if such Contributor
+  has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+  the Work or Derivative Works thereof, You may choose to offer,
+  and charge a fee for, acceptance of support, warranty, indemnity,
+  or other liability obligations and/or rights consistent with this
+  License. However, in accepting such obligations, You may act only
+  on Your own behalf and on Your sole responsibility, not on behalf
+  of any other Contributor, and only if You agree to indemnify,
+  defend, and hold each Contributor harmless for any liability
+  incurred by, or claims asserted against, such Contributor by reason
+  of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+  To apply the Apache License to your work, attach the following
+  boilerplate notice, with the fields enclosed by brackets "[]"
+  replaced with your own identifying information. (Don't include
+  the brackets!)  The text should be enclosed in the appropriate
+  comment syntax for the file format. We also recommend that a
+  file or class name and description of purpose be included on the
+  same "printed page" as the copyright notice for easier
+  identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.

+ 4 - 4
packages/app-addresses/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@polkadot/app-addresses",
-  "version": "0.20.30",
+  "version": "0.21.0",
   "main": "index.js",
   "repository": "https://github.com/polkadot-js/apps.git",
   "author": "Jaco Greeff <jacogr@gmail.com>",
@@ -8,9 +8,9 @@
     "Jaco Greeff <jacogr@gmail.com>"
   ],
   "contributors": [],
-  "license": "ISC",
+  "license": "Apache-2.0",
   "dependencies": {
-    "@babel/runtime": "^7.0.0",
-    "@polkadot/ui-app": "^0.20.30"
+    "@babel/runtime": "^7.2.0",
+    "@polkadot/ui-app": "^0.21.0"
   }
 }

+ 31 - 13
packages/app-addresses/src/Creator.tsx

@@ -1,23 +1,21 @@
 // Copyright 2017-2018 @polkadot/app-addresses authors & contributors
 // This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
+// of the Apache-2.0 license. See the LICENSE file for details.
 
 import { I18nProps } from '@polkadot/ui-app/types';
 
 import React from 'react';
 
-import Button from '@polkadot/ui-app/Button';
-import Input from '@polkadot/ui-app/Input';
+import { AddressSummary, Button, Input } from '@polkadot/ui-app/index';
+import { ActionStatus } from '@polkadot/ui-app/Status/types';
 import { InputAddress } from '@polkadot/ui-app/InputAddress';
-import keyring from '@polkadot/ui-keyring/index';
-import addressDecode from '@polkadot/util-keyring/address/decode';
-import addressEncode from '@polkadot/util-keyring/address/encode';
+import keyring from '@polkadot/ui-keyring';
 
-import AddressSummary from '@polkadot/ui-app/AddressSummary';
 import translate from './translate';
 
 type Props = I18nProps & {
-  onCreateAddress: () => void
+  onCreateAddress: () => void,
+  onStatusChange: (status: ActionStatus) => void
 };
 
 type State = {
@@ -131,8 +129,8 @@ class Creator extends React.PureComponent<Props, State> {
         let newAddress = address;
 
         try {
-          newAddress = addressEncode(
-            addressDecode(address)
+          newAddress = keyring.encodeAddress(
+            keyring.decodeAddress(address)
           );
           isAddressValid = keyring.isAvailable(newAddress);
         } catch (error) {
@@ -161,13 +159,33 @@ class Creator extends React.PureComponent<Props, State> {
   }
 
   onCommit = (): void => {
-    const { onCreateAddress } = this.props;
+    const { onCreateAddress, onStatusChange, t } = this.props;
     const { address, name } = this.state;
 
-    keyring.saveAddress(address, { name });
-    InputAddress.setLastValue('address', address);
+    const status = {
+      action: 'create'
+    } as ActionStatus;
+
+    try {
+      keyring.saveAddress(address, { name });
+
+      status.value = address;
+      status.status = address ? 'success' : 'error';
+      status.message = t('status.created', {
+        defaultValue: 'address created'
+      });
+
+      InputAddress.setLastValue('address', address);
+    } catch (err) {
+      status.status = 'error';
+      status.message = t('status.error', {
+        defaultValue: err.message
+      });
+    }
 
     onCreateAddress();
+
+    onStatusChange(status);
   }
 
   onDiscard = (): void => {

+ 57 - 18
packages/app-addresses/src/Editor.tsx

@@ -1,22 +1,22 @@
 // Copyright 2017-2018 @polkadot/app-addresses authors & contributors
 // This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
+// of the Apache-2.0 license. See the LICENSE file for details.
 
 import { KeyringAddress } from '@polkadot/ui-keyring/types';
 import { I18nProps } from '@polkadot/ui-app/types';
 
 import React from 'react';
-
-import Button from '@polkadot/ui-app/Button';
-import Input from '@polkadot/ui-app/Input';
-import AddressSummary from '@polkadot/ui-app/AddressSummary';
-import InputAddress from '@polkadot/ui-app/InputAddress';
-import keyring from '@polkadot/ui-keyring/index';
+import { AddressSummary, Button, Input, InputAddress } from '@polkadot/ui-app/index';
+import { ActionStatus } from '@polkadot/ui-app/Status/types';
+import keyring from '@polkadot/ui-keyring';
+import { decodeAddress } from '@polkadot/keyring';
 
 import Forgetting from './Forgetting';
 import translate from './translate';
 
-type Props = I18nProps;
+type Props = I18nProps & {
+  onStatusChange: (status: ActionStatus) => void
+};
 
 type State = {
   current: KeyringAddress | null,
@@ -172,9 +172,9 @@ class Editor extends React.PureComponent<Props, State> {
     );
   }
 
-  onChangeAddress = (publicKey: Uint8Array): void => {
-    const current = publicKey && publicKey.length === 32
-      ? (keyring.getAddress(publicKey) || null)
+  onChangeAddress = (accountId: string): void => {
+    const current = accountId && decodeAddress(accountId)
+      ? (keyring.getAddress(accountId) || null)
       : null;
 
     this.nextState({ current } as State);
@@ -186,15 +186,35 @@ class Editor extends React.PureComponent<Props, State> {
 
   onCommit = (): void => {
     const { current, editedName } = this.state;
+    const { onStatusChange, t } = this.props;
 
     if (!current) {
       return;
     }
 
-    keyring.saveAddress(current.address(), {
-      name: editedName,
-      whenEdited: Date.now()
-    });
+    const status = {
+      action: 'edit',
+      value: current.address()
+    } as ActionStatus;
+
+    try {
+      keyring.saveAddress(current.address(), {
+        name: editedName,
+        whenEdited: Date.now()
+      });
+
+      status.status = current.getMeta().name === editedName ? 'success' : 'error';
+      status.message = t('status.editted', {
+        defaultValue: 'name edited'
+      });
+    } catch (e) {
+      status.status = 'error';
+      status.message = t('status.error', {
+        defaultValue: e.message
+      });
+    }
+
+    onStatusChange(status);
   }
 
   onDiscard = (): void => {
@@ -218,6 +238,7 @@ class Editor extends React.PureComponent<Props, State> {
   }
 
   onForget = (): void => {
+    const { onStatusChange, t } = this.props;
     const { current } = this.state;
 
     if (!current) {
@@ -227,9 +248,27 @@ class Editor extends React.PureComponent<Props, State> {
     this.setState(
       this.createState(null),
       () => {
-        keyring.forgetAddress(
-          current.address()
-        );
+        const status = {
+          action: 'forget',
+          value: current.address()
+        } as ActionStatus;
+
+        try {
+          keyring.forgetAddress(
+            current.address()
+          );
+          status.status = 'success';
+          status.message = t('status.forgotten', {
+            defaultValue: 'address forgotten'
+          });
+        } catch (err) {
+          status.status = 'error';
+          status.message = t('status.error', {
+            defaultValue: err.message
+          });
+        }
+
+        onStatusChange(status);
       }
     );
   }

+ 2 - 5
packages/app-addresses/src/Forgetting.tsx

@@ -1,15 +1,12 @@
 // Copyright 2017-2018 @polkadot/app-accounts authors & contributors
 // This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
+// of the Apache-2.0 license. See the LICENSE file for details.
 
 import { KeyringAddress } from '@polkadot/ui-keyring/types';
 import { I18nProps } from '@polkadot/ui-app/types';
 
 import React from 'react';
-
-import Button from '@polkadot/ui-app/Button';
-import Modal from '@polkadot/ui-app/Modal';
-import AddressSummary from '@polkadot/ui-app/AddressSummary';
+import { AddressSummary, Button, Modal } from '@polkadot/ui-app/index';
 
 import translate from './translate';
 

+ 1 - 1
packages/app-addresses/src/index.css

@@ -1,6 +1,6 @@
 /* Copyright 2017-2018 @polkadot/app-addresses authors & contributors
 /* This software may be modified and distributed under the terms
-/* of the ISC license. See the LICENSE file for details. */
+/* of the Apache-2.0 license. See the LICENSE file for details. */
 
 .forgetting-Address {
   text-align: center;

+ 15 - 8
packages/app-addresses/src/index.tsx

@@ -1,9 +1,10 @@
 // Copyright 2017-2018 @polkadot/app-addresses authors & contributors
 // This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
+// of the Apache-2.0 license. See the LICENSE file for details.
 
 import { I18nProps } from '@polkadot/ui-app/types';
 import { SubjectInfo } from '@polkadot/ui-keyring/observable/types';
+import { ActionStatus } from '@polkadot/ui-app/Status/types';
 
 import './index.css';
 
@@ -11,7 +12,7 @@ import React from 'react';
 
 import addressObservable from '@polkadot/ui-keyring/observable/addresses';
 import Tabs, { TabItem } from '@polkadot/ui-app/Tabs';
-import withObservableBase from '@polkadot/ui-react-rx/with/observableBase';
+import { withMulti, withObservableBase } from '@polkadot/ui-react-rx/with/index';
 
 import Creator from './Creator';
 import Editor from './Editor';
@@ -19,7 +20,8 @@ import translate from './translate';
 
 type Props = I18nProps & {
   allAddresses?: SubjectInfo,
-  basePath: string
+  basePath: string,
+  onStatusChange: (status: ActionStatus) => void
 };
 
 type Actions = 'create' | 'edit';
@@ -30,7 +32,6 @@ type State = {
   items: Array<TabItem>
 };
 
-// FIXME React-router would probably be the best route, not home-grown
 const Components: { [index: string]: React.ComponentType<any> } = {
   'create': Creator,
   'edit': Editor
@@ -91,6 +92,7 @@ class AddressesApp extends React.PureComponent<Props, State> {
   }
 
   render () {
+    const { onStatusChange } = this.props;
     const { action, hidden, items } = this.state;
     const Component = Components[action];
 
@@ -104,7 +106,10 @@ class AddressesApp extends React.PureComponent<Props, State> {
             onChange={this.onMenuChange}
           />
         </header>
-        <Component onCreateAddress={this.activateEdit} />
+        <Component
+          onCreateAddress={this.activateEdit}
+          onStatusChange={onStatusChange}
+        />
       </main>
     );
   }
@@ -120,6 +125,8 @@ class AddressesApp extends React.PureComponent<Props, State> {
   }
 }
 
-export default withObservableBase(
-  addressObservable.subject, { propName: 'allAddresses' }
-)(translate(AddressesApp));
+export default withMulti(
+  AddressesApp,
+  translate,
+  withObservableBase(addressObservable.subject, { propName: 'allAddresses' })
+);

+ 3 - 3
packages/app-addresses/src/translate.ts

@@ -1,7 +1,7 @@
 // Copyright 2017-2018 @polkadot/app-addresses authors & contributors
 // This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
+// of the Apache-2.0 license. See the LICENSE file for details.
 
-import { translate } from 'react-i18next';
+import { withNamespaces } from 'react-i18next';
 
-export default translate(['addresses', 'ui']);
+export default withNamespaces(['addresses', 'ui']);

+ 198 - 12
packages/app-democracy/LICENSE

@@ -1,15 +1,201 @@
-ISC License (ISC)
+                              Apache License
+                        Version 2.0, January 2004
+                    http://www.apache.org/licenses/
 
-Copyright 2017-2018 @polkadot/app-democracy authors & contributors
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
 
-Permission to use, copy, modify, and/or distribute this software for any
-purpose with or without fee is hereby granted, provided that the above
-copyright notice and this permission notice appear in all copies.
+1. Definitions.
 
-THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
-REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
-FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
-INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
-OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-PERFORMANCE OF THIS SOFTWARE.
+  "License" shall mean the terms and conditions for use, reproduction,
+  and distribution as defined by Sections 1 through 9 of this document.
+
+  "Licensor" shall mean the copyright owner or entity authorized by
+  the copyright owner that is granting the License.
+
+  "Legal Entity" shall mean the union of the acting entity and all
+  other entities that control, are controlled by, or are under common
+  control with that entity. For the purposes of this definition,
+  "control" means (i) the power, direct or indirect, to cause the
+  direction or management of such entity, whether by contract or
+  otherwise, or (ii) ownership of fifty percent (50%) or more of the
+  outstanding shares, or (iii) beneficial ownership of such entity.
+
+  "You" (or "Your") shall mean an individual or Legal Entity
+  exercising permissions granted by this License.
+
+  "Source" form shall mean the preferred form for making modifications,
+  including but not limited to software source code, documentation
+  source, and configuration files.
+
+  "Object" form shall mean any form resulting from mechanical
+  transformation or translation of a Source form, including but
+  not limited to compiled object code, generated documentation,
+  and conversions to other media types.
+
+  "Work" shall mean the work of authorship, whether in Source or
+  Object form, made available under the License, as indicated by a
+  copyright notice that is included in or attached to the work
+  (an example is provided in the Appendix below).
+
+  "Derivative Works" shall mean any work, whether in Source or Object
+  form, that is based on (or derived from) the Work and for which the
+  editorial revisions, annotations, elaborations, or other modifications
+  represent, as a whole, an original work of authorship. For the purposes
+  of this License, Derivative Works shall not include works that remain
+  separable from, or merely link (or bind by name) to the interfaces of,
+  the Work and Derivative Works thereof.
+
+  "Contribution" shall mean any work of authorship, including
+  the original version of the Work and any modifications or additions
+  to that Work or Derivative Works thereof, that is intentionally
+  submitted to Licensor for inclusion in the Work by the copyright owner
+  or by an individual or Legal Entity authorized to submit on behalf of
+  the copyright owner. For the purposes of this definition, "submitted"
+  means any form of electronic, verbal, or written communication sent
+  to the Licensor or its representatives, including but not limited to
+  communication on electronic mailing lists, source code control systems,
+  and issue tracking systems that are managed by, or on behalf of, the
+  Licensor for the purpose of discussing and improving the Work, but
+  excluding communication that is conspicuously marked or otherwise
+  designated in writing by the copyright owner as "Not a Contribution."
+
+  "Contributor" shall mean Licensor and any individual or Legal Entity
+  on behalf of whom a Contribution has been received by Licensor and
+  subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+  this License, each Contributor hereby grants to You a perpetual,
+  worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+  copyright license to reproduce, prepare Derivative Works of,
+  publicly display, publicly perform, sublicense, and distribute the
+  Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+  this License, each Contributor hereby grants to You a perpetual,
+  worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+  (except as stated in this section) patent license to make, have made,
+  use, offer to sell, sell, import, and otherwise transfer the Work,
+  where such license applies only to those patent claims licensable
+  by such Contributor that are necessarily infringed by their
+  Contribution(s) alone or by combination of their Contribution(s)
+  with the Work to which such Contribution(s) was submitted. If You
+  institute patent litigation against any entity (including a
+  cross-claim or counterclaim in a lawsuit) alleging that the Work
+  or a Contribution incorporated within the Work constitutes direct
+  or contributory patent infringement, then any patent licenses
+  granted to You under this License for that Work shall terminate
+  as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+  Work or Derivative Works thereof in any medium, with or without
+  modifications, and in Source or Object form, provided that You
+  meet the following conditions:
+
+  (a) You must give any other recipients of the Work or
+      Derivative Works a copy of this License; and
+
+  (b) You must cause any modified files to carry prominent notices
+      stating that You changed the files; and
+
+  (c) You must retain, in the Source form of any Derivative Works
+      that You distribute, all copyright, patent, trademark, and
+      attribution notices from the Source form of the Work,
+      excluding those notices that do not pertain to any part of
+      the Derivative Works; and
+
+  (d) If the Work includes a "NOTICE" text file as part of its
+      distribution, then any Derivative Works that You distribute must
+      include a readable copy of the attribution notices contained
+      within such NOTICE file, excluding those notices that do not
+      pertain to any part of the Derivative Works, in at least one
+      of the following places: within a NOTICE text file distributed
+      as part of the Derivative Works; within the Source form or
+      documentation, if provided along with the Derivative Works; or,
+      within a display generated by the Derivative Works, if and
+      wherever such third-party notices normally appear. The contents
+      of the NOTICE file are for informational purposes only and
+      do not modify the License. You may add Your own attribution
+      notices within Derivative Works that You distribute, alongside
+      or as an addendum to the NOTICE text from the Work, provided
+      that such additional attribution notices cannot be construed
+      as modifying the License.
+
+  You may add Your own copyright statement to Your modifications and
+  may provide additional or different license terms and conditions
+  for use, reproduction, or distribution of Your modifications, or
+  for any such Derivative Works as a whole, provided Your use,
+  reproduction, and distribution of the Work otherwise complies with
+  the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+  any Contribution intentionally submitted for inclusion in the Work
+  by You to the Licensor shall be under the terms and conditions of
+  this License, without any additional terms or conditions.
+  Notwithstanding the above, nothing herein shall supersede or modify
+  the terms of any separate license agreement you may have executed
+  with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+  names, trademarks, service marks, or product names of the Licensor,
+  except as required for reasonable and customary use in describing the
+  origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+  agreed to in writing, Licensor provides the Work (and each
+  Contributor provides its Contributions) on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+  implied, including, without limitation, any warranties or conditions
+  of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+  PARTICULAR PURPOSE. You are solely responsible for determining the
+  appropriateness of using or redistributing the Work and assume any
+  risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+  whether in tort (including negligence), contract, or otherwise,
+  unless required by applicable law (such as deliberate and grossly
+  negligent acts) or agreed to in writing, shall any Contributor be
+  liable to You for damages, including any direct, indirect, special,
+  incidental, or consequential damages of any character arising as a
+  result of this License or out of the use or inability to use the
+  Work (including but not limited to damages for loss of goodwill,
+  work stoppage, computer failure or malfunction, or any and all
+  other commercial damages or losses), even if such Contributor
+  has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+  the Work or Derivative Works thereof, You may choose to offer,
+  and charge a fee for, acceptance of support, warranty, indemnity,
+  or other liability obligations and/or rights consistent with this
+  License. However, in accepting such obligations, You may act only
+  on Your own behalf and on Your sole responsibility, not on behalf
+  of any other Contributor, and only if You agree to indemnify,
+  defend, and hold each Contributor harmless for any liability
+  incurred by, or claims asserted against, such Contributor by reason
+  of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+  To apply the Apache License to your work, attach the following
+  boilerplate notice, with the fields enclosed by brackets "[]"
+  replaced with your own identifying information. (Don't include
+  the brackets!)  The text should be enclosed in the appropriate
+  comment syntax for the file format. We also recommend that a
+  file or class name and description of purpose be included on the
+  same "printed page" as the copyright notice for easier
+  identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.

+ 6 - 7
packages/app-democracy/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@polkadot/app-democracy",
-  "version": "0.20.30",
+  "version": "0.21.0",
   "description": "A referendum & proposal app",
   "main": "index.js",
   "scripts": {},
@@ -8,12 +8,11 @@
   "maintainers": [
     "Jaco Greeff <jacogr@gmail.com>"
   ],
-  "license": "ISC",
+  "license": "Apache-2.0",
   "dependencies": {
-    "@babel/runtime": "^7.0.0",
-    "@polkadot/storage": "^0.29.7",
-    "@polkadot/ui-react": "^0.20.30",
-    "@polkadot/ui-react-rx": "^0.20.30",
-    "@polkadot/util-keyring": "^0.30.4"
+    "@babel/runtime": "^7.2.0",
+    "@polkadot/keyring": "^0.33.26",
+    "@polkadot/storage": "^0.35.9",
+    "@polkadot/ui-react-rx": "^0.21.0"
   }
 }

+ 16 - 15
packages/app-democracy/src/Item.tsx

@@ -1,53 +1,54 @@
 // Copyright 2017-2018 @polkadot/app-democracy authors & contributors
 // This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
+// of the Apache-2.0 license. See the LICENSE file for details.
 
-import { ExtrinsicDecoded } from '@polkadot/params/types';
 import { I18nProps } from '@polkadot/ui-app/types';
 
 import BN from 'bn.js';
 import React from 'react';
-import Extrinsic from '@polkadot/ui-app/Extrinsic';
+import { Method, Proposal } from '@polkadot/types';
+import { Call } from '@polkadot/ui-app/index';
 import numberFormat from '@polkadot/ui-react-rx/util/numberFormat';
 
-// TODO This would be nice as a shared component, move to ui-app as soon as
-// we have actual "more-than-one-use" apps
 import translate from './translate';
 
 type Props = I18nProps & {
   children?: React.ReactNode,
-  proposal: ExtrinsicDecoded,
+  proposal: Proposal,
   proposalExtra?: React.ReactNode,
   idNumber: BN
 };
 
-// FIXME Duplicated layout here and in explorer, clean up with extrinsics
 class Item extends React.PureComponent<Props> {
   render () {
     const { children, idNumber, proposal, proposalExtra } = this.props;
+    const { meta, method, section } = Method.findFunction(proposal.callIndex);
 
+    // FIXME This is _very_ similar to what we have in explorer/BlockByHash
     return (
       <article className='democracy--Item'>
         <div className='democracy--Item-header'>
           <div className='democracy--Item-header-info'>
-            <div className='democracy--Item-header-name'>
-              {proposal.extrinsic.section}.{proposal.extrinsic.name}
-            </div>
-            <div className='democracy--Item-header-description'>
-              {proposal.extrinsic.description}
-            </div>
+            <h3>
+              {section}.{method}
+            </h3>
+            <div className='democracy--Item-header-description'>{
+              meta && meta.documentation && meta.documentation.length
+                ? meta.documentation.map((doc) => doc.toString()).join(' ')
+                : ''
+            }</div>
           </div>
           <div className='democracy--Item-header-id'>
             #{numberFormat(idNumber)}
           </div>
         </div>
         <div className='democracy--Item-body'>
-          <Extrinsic
+          <Call
             className='democracy--Item-extrinsic'
             value={proposal}
           >
             {proposalExtra}
-          </Extrinsic>
+          </Call>
           <div className='democracy--Item-children'>
             {children}
           </div>

+ 23 - 28
packages/app-democracy/src/Proposal.tsx

@@ -1,24 +1,21 @@
 // Copyright 2017-2018 @polkadot/app-democracy authors & contributors
 // This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
+// of the Apache-2.0 license. See the LICENSE file for details.
 
 import { I18nProps } from '@polkadot/ui-app/types';
-import { RxProposal, RxProposalDeposits } from '@polkadot/ui-react-rx/ApiObservable/types';
+import { RxProposal, RxProposalDeposits } from '@polkadot/api-observable/classes';
 
 import BN from 'bn.js';
 import React from 'react';
-import AddressMini from '@polkadot/ui-app/AddressMini';
-import Labelled from '@polkadot/ui-app/Labelled';
-import Static from '@polkadot/ui-app/Static';
-import withObservable from '@polkadot/ui-react-rx/with/observable';
-import withMulti from '@polkadot/ui-react-rx/with/multi';
-import numberFormat from '@polkadot/ui-react-rx/util/numberFormat';
+import { AddressMini, Labelled, Static } from '@polkadot/ui-app/index';
+import { withMulti, withObservable } from '@polkadot/ui-react-rx/with/index';
+import { balanceFormat } from '@polkadot/ui-react-rx/util/index';
 
 import Item from './Item';
 import translate from './translate';
 
 type Props = I18nProps & {
-  democracyProposalDeposits?: RxProposalDeposits,
+  proposalDeposits?: RxProposalDeposits,
   idNumber: BN,
   value: RxProposal
 };
@@ -32,52 +29,50 @@ class Proposal extends React.PureComponent<Props> {
         idNumber={idNumber}
         proposal={value.proposal}
         proposalExtra={this.renderExtra()}
-      >
-        {this.renderVoting()}
-      </Item>
+      />
     );
   }
 
   private renderExtra () {
-    const { democracyProposalDeposits, t } = this.props;
+    const { proposalDeposits, t } = this.props;
 
-    if (!democracyProposalDeposits) {
+    if (!proposalDeposits) {
       return null;
     }
 
-    const { balance, addresses } = democracyProposalDeposits;
+    const { balance, addresses } = proposalDeposits;
 
     return (
       <div className='democracy--Proposal-info'>
-        <Labelled label={t('proposal.depositsAddresses', {
-          defaultValue: 'depositors'
-        })}>
+        <Labelled
+          label={t('proposal.depositsAddresses', {
+            defaultValue: 'depositors'
+          })}
+        >
           <div>
             {addresses.map((address) => (
               <AddressMini
                 isPadded={false}
-                key={address}
+                key={address.toString()}
                 value={address}
               />
             ))}
           </div>
         </Labelled>
-        <Static label={t('proposal.depositsBalanceLabel', {
-          defaultValue: 'balance'
-        })}>
-          {numberFormat(balance)}
+        <Static
+          label={t('proposal.depositsBalanceLabel', {
+            defaultValue: 'balance'
+          })}
+        >
+          {balanceFormat(balance)}
         </Static>
       </div>
     );
   }
-
-  private renderVoting () {
-    return null;
-  }
 }
 
 export default withMulti(
   Proposal,
   translate,
-  withObservable('democracyProposalDeposits', { paramProp: 'idNumber' })
+  withObservable('proposalDeposits', { paramProp: 'idNumber' })
 );

+ 8 - 9
packages/app-democracy/src/Proposals.tsx

@@ -1,19 +1,18 @@
 // Copyright 2017-2018 @polkadot/app-democracy authors & contributors
 // This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
+// of the Apache-2.0 license. See the LICENSE file for details.
 
 import { I18nProps } from '@polkadot/ui-app/types';
-import { RxProposal } from '@polkadot/ui-react-rx/ApiObservable/types';
+import { RxProposal } from '@polkadot/api-observable/classes';
 
 import React from 'react';
-import withObservable from '@polkadot/ui-react-rx/with/observable';
-import withMulti from '@polkadot/ui-react-rx/with/multi';
+import { withMulti, withObservable } from '@polkadot/ui-react-rx/with/index';
 
 import Proposal from './Proposal';
 import translate from './translate';
 
 type Props = I18nProps & {
-  democracyProposals?: Array<RxProposal>
+  publicProposals?: Array<RxProposal>
 };
 
 class Proposals extends React.PureComponent<Props> {
@@ -31,9 +30,9 @@ class Proposals extends React.PureComponent<Props> {
   }
 
   private renderProposals () {
-    const { democracyProposals, t } = this.props;
+    const { publicProposals, t } = this.props;
 
-    if (!democracyProposals || !democracyProposals.length) {
+    if (!publicProposals || !publicProposals.length) {
       return (
         <div className='ui disabled'>
           {t('proposals.none', {
@@ -43,7 +42,7 @@ class Proposals extends React.PureComponent<Props> {
       );
     }
 
-    return democracyProposals.map((proposal) => (
+    return publicProposals.map((proposal) => (
       <Proposal
         idNumber={proposal.id}
         key={proposal.id.toString()}
@@ -56,5 +55,5 @@ class Proposals extends React.PureComponent<Props> {
 export default withMulti(
   Proposals,
   translate,
-  withObservable('democracyProposals')
+  withObservable('publicProposals')
 );

+ 42 - 34
packages/app-democracy/src/Referendum.tsx

@@ -1,28 +1,28 @@
 // Copyright 2017-2018 @polkadot/app-democracy authors & contributors
 // This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
+// of the Apache-2.0 license. See the LICENSE file for details.
 
 import { I18nProps } from '@polkadot/ui-app/types';
 import { RawParam } from '@polkadot/ui-app/Params/types';
-import { RxReferendum, RxReferendumVote } from '@polkadot/ui-react-rx/ApiObservable/types';
+import { RxReferendumVote } from '@polkadot/api-observable/types';
 
 import BN from 'bn.js';
 import React from 'react';
-import Static from '@polkadot/ui-app/Static';
-import Doughnut from '@polkadot/ui-app/Chart/Doughnut';
+import { ReferendumInfo } from '@polkadot/types';
+import { Chart, Static } from '@polkadot/ui-app/index';
 import VoteThreshold from '@polkadot/ui-app/Params/Param/VoteThreshold';
-import numberFormat from '@polkadot/ui-react-rx/util/numberFormat';
-import withObservable from '@polkadot/ui-react-rx/with/observable';
-import withMulti from '@polkadot/ui-react-rx/with/multi';
+import { withMulti, withObservable } from '@polkadot/ui-react-rx/with/index';
+import { balanceFormat, numberFormat } from '@polkadot/ui-react-rx/util/index';
+import settings from '@polkadot/ui-settings';
 
 import Item from './Item';
 import Voting from './Voting';
 import translate from './translate';
 
-const COLORS_YAY = process.env.UI_THEME === 'substrate'
+const COLORS_YAY = settings.uiTheme === 'substrate'
   ? ['#4d4', '#4e4']
   : ['#64bebe', '#5badad'];
-const COLORS_NAY = process.env.UI_THEME === 'substrate'
+const COLORS_NAY = settings.uiTheme === 'substrate'
   ? ['#d44', '#e44']
   : ['#d75ea1', '#e189ba'];
 
@@ -30,7 +30,7 @@ type Props = I18nProps & {
   bestNumber?: BN,
   democracyReferendumVoters?: Array<RxReferendumVote>,
   idNumber: BN,
-  value: RxReferendum
+  value: ReferendumInfo
 };
 
 type State = {
@@ -64,7 +64,7 @@ class Referendum extends React.PureComponent<Props, State> {
     }
 
     const newState: State = democracyReferendumVoters.reduce((state, { balance, vote }) => {
-      if (vote) {
+      if (vote.valueOf() === true) {
         state.voteCountYay++;
         state.votedYay = state.votedYay.add(balance);
       } else {
@@ -93,7 +93,11 @@ class Referendum extends React.PureComponent<Props, State> {
   }
 
   render () {
-    const { idNumber, value } = this.props;
+    const { bestNumber, idNumber, value } = this.props;
+
+    if (!bestNumber || value.end.sub(bestNumber).lten(0)) {
+      return null;
+    }
 
     return (
       <Item
@@ -108,34 +112,35 @@ class Referendum extends React.PureComponent<Props, State> {
   }
 
   private renderExtra () {
-    const { bestNumber, t, value: { blockNumber, voteThreshold } } = this.props;
+    const { bestNumber, t, value: { end, threshold } } = this.props;
 
     if (!bestNumber) {
       return null;
     }
 
-    console.error('Referendum:: best:', numberFormat(bestNumber), 'target:', numberFormat(blockNumber), 'remaining:', numberFormat(blockNumber.sub(bestNumber)));
-
     return (
       <div className='democracy--Referendum-info'>
-        <Static label={t('referendum.endLabel', {
-          defaultValue: 'remaining time'
-        })}>
+        <Static
+          label={t('referendum.endLabel', {
+            defaultValue: 'remaining time'
+          })}
+        >
           {t('referendum.endInfo', {
             defaultValue: '{{remaining}} blocks remaining, ending at block #{{blockNumber}}',
             replace: {
-              blockNumber: numberFormat(blockNumber),
-              remaining: numberFormat(blockNumber.sub(bestNumber))
+              blockNumber: numberFormat(end),
+              remaining: numberFormat(end.sub(bestNumber).subn(1))
             }
           })}
         </Static>
         <VoteThreshold
           isDisabled
-          defaultValue={{ value: voteThreshold } as RawParam}
+          defaultValue={{ value: threshold } as RawParam}
           label={t('referendum.thresholdLabel', {
             defaultValue: 'vote threshold'
           })}
           name='voteThreshold'
+          type={{ info: 0, type: 'VoteThreshold' }}
         />
       </div>
     );
@@ -150,25 +155,28 @@ class Referendum extends React.PureComponent<Props, State> {
 
     return (
       <div className='democracy--Referendum-results chart'>
-        <Doughnut values={[
-          {
-            colors: COLORS_YAY,
-            label: `${numberFormat(votedYay)} (${numberFormat(voteCountYay)})`,
-            value: votedYay.muln(10000).div(votedTotal).toNumber() / 100
-          },
-          {
-            colors: COLORS_NAY,
-            label: `${numberFormat(votedNay)} (${numberFormat(voteCountNay)})`,
-            value: votedNay.muln(10000).div(votedTotal).toNumber() / 100
-          }
-        ]} />
+        <Chart.Doughnut
+          values={[
+            {
+              colors: COLORS_YAY,
+              label: `${balanceFormat(votedYay)} (${numberFormat(voteCountYay)})`,
+              value: votedYay.muln(10000).div(votedTotal).toNumber() / 100
+            },
+            {
+              colors: COLORS_NAY,
+              label: `${balanceFormat(votedNay)} (${numberFormat(voteCountNay)})`,
+              value: votedNay.muln(10000).div(votedTotal).toNumber() / 100
+            }
+          ]}
+        />
       </div>
     );
   }
 }
 
 export default withMulti(
-  translate(Referendum),
+  Referendum,
+  translate,
   withObservable('bestNumber'),
   withObservable('democracyReferendumVoters', { paramProp: 'idNumber' })
 );

+ 17 - 11
packages/app-democracy/src/Referendums.tsx

@@ -1,19 +1,21 @@
 // Copyright 2017-2018 @polkadot/app-democracy authors & contributors
 // This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
+// of the Apache-2.0 license. See the LICENSE file for details.
 
 import { I18nProps } from '@polkadot/ui-app/types';
-import { RxReferendum } from '@polkadot/ui-react-rx/ApiObservable/types';
 
+import BN from 'bn.js';
 import React from 'react';
-import withObservable from '@polkadot/ui-react-rx/with/observable';
-import withMulti from '@polkadot/ui-react-rx/with/multi';
+import { ReferendumInfo } from '@polkadot/types';
+import { withMulti, withObservable } from '@polkadot/ui-react-rx/with/index';
 
 import Referendum from './Referendum';
 import translate from './translate';
 
 type Props = I18nProps & {
-  democracyReferendums?: Array<RxReferendum>
+  democracyNextTally?: BN,
+  referendums?: Array<ReferendumInfo>,
+  referendumCount?: BN
 };
 
 class Referendums extends React.PureComponent<Props> {
@@ -31,9 +33,11 @@ class Referendums extends React.PureComponent<Props> {
   }
 
   private renderReferendums () {
-    const { democracyReferendums, t } = this.props;
+    const { democracyNextTally = new BN(0), referendums, referendumCount = new BN(0), t } = this.props;
 
-    if (!democracyReferendums || !democracyReferendums.length) {
+    console.error('democracyNextTally', democracyNextTally.toString(), referendums, referendumCount.toString());
+
+    if (!referendums || !referendums.length || referendumCount.toNumber() === democracyNextTally.toNumber()) {
       return (
         <div className='ui disabled'>
           {t('proposals.none', {
@@ -43,10 +47,10 @@ class Referendums extends React.PureComponent<Props> {
       );
     }
 
-    return democracyReferendums.map((referendum) => (
+    return referendums.map((referendum, index) => (
       <Referendum
-        idNumber={referendum.id}
-        key={referendum.id.toString()}
+        idNumber={index}
+        key={index}
         value={referendum}
       />
     ));
@@ -56,5 +60,7 @@ class Referendums extends React.PureComponent<Props> {
 export default withMulti(
   Referendums,
   translate,
-  withObservable('democracyReferendums')
+  withObservable('referendums'),
+  withObservable('referendumCount'),
+  withObservable('democracyNextTally')
 );

+ 47 - 35
packages/app-democracy/src/Summary.tsx

@@ -1,63 +1,74 @@
 // Copyright 2017-2018 @polkadot/app-democracy authors & contributors
 // This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
+// of the Apache-2.0 license. See the LICENSE file for details.
 
 import { I18nProps } from '@polkadot/ui-app/types';
 
 import BN from 'bn.js';
 import React from 'react';
-import CardSummary from '@polkadot/ui-app/CardSummary';
-import withObservable from '@polkadot/ui-react-rx/with/observable';
-import withMulti from '@polkadot/ui-react-rx/with/multi';
-import numberFormat from '@polkadot/ui-react-rx/util/numberFormat';
+import { CardSummary } from '@polkadot/ui-app/index';
+import { withMulti, withObservable } from '@polkadot/ui-react-rx/with/index';
+import { numberFormat } from '@polkadot/ui-react-rx/util/index';
 
 import translate from './translate';
 
 type Props = I18nProps & {
+  bestNumber?: BN,
   democracyLaunchPeriod?: BN,
   democracyNextTally?: BN,
-  democracyProposalCount?: BN,
-  democracyReferendumCount?: BN,
+  publicProposalCount?: BN,
+  referendumCount?: BN,
   democracyVotingPeriod?: BN
 };
 
 class Summary extends React.PureComponent<Props> {
   render () {
-    const { democracyLaunchPeriod, democracyNextTally = new BN(0), democracyProposalCount, democracyReferendumCount = new BN(0), democracyVotingPeriod, t } = this.props;
+    const { bestNumber = new BN(0), democracyLaunchPeriod = new BN(1), democracyNextTally = new BN(0), publicProposalCount, referendumCount = new BN(0), democracyVotingPeriod = new BN(1), t } = this.props;
 
     return (
       <summary>
         <section>
-          <CardSummary label={t('summary.proposalCount', {
-            defaultValue: 'proposals'
-          })}>
-            {numberFormat(democracyProposalCount)}
+          <CardSummary
+            label={t('summary.proposalCount', {
+              defaultValue: 'proposals'
+            })}
+          >
+            {numberFormat(publicProposalCount)}
           </CardSummary>
-          <CardSummary label={t('summary.referendumCount', {
-            defaultValue: 'referendums'
-          })}>
-            {numberFormat(democracyReferendumCount)}
+          <CardSummary
+            label={t('summary.referendumCount', {
+              defaultValue: 'referendums'
+            })}
+          >
+            {numberFormat(referendumCount)}
           </CardSummary>
-          <CardSummary label={t('summary.active', {
-            defaultValue: 'active num'
-          })}>
-            {democracyNextTally && democracyReferendumCount
-              ? numberFormat(democracyReferendumCount.sub(democracyNextTally))
-              : 0
-            }
+          <CardSummary
+            label={t('summary.active', {
+              defaultValue: 'active num'
+            })}
+          >
+            {numberFormat(referendumCount.sub(democracyNextTally))}
           </CardSummary>
         </section>
         <section>
-          <CardSummary label={t('summary.votingPeriod', {
-            defaultValue: 'voting period'
-          })}>
-            {numberFormat(democracyVotingPeriod)}
-          </CardSummary>
-          <CardSummary label={t('summary.launchPeriod', {
-            defaultValue: 'launch period'
-          })}>
-            {numberFormat(democracyLaunchPeriod)}
-          </CardSummary>
+          <CardSummary
+            label={t('summary.votingPeriod', {
+              defaultValue: 'voting period'
+            })}
+            progress={{
+              value: bestNumber.mod(democracyVotingPeriod).addn(1),
+              total: democracyVotingPeriod
+            }}
+          />
+          <CardSummary
+            label={t('summary.launchPeriod', {
+              defaultValue: 'launch period'
+            })}
+            progress={{
+              value: bestNumber.mod(democracyLaunchPeriod).addn(1),
+              total: democracyLaunchPeriod
+            }}
+          />
         </section>
       </summary>
     );
@@ -68,8 +79,9 @@ export default withMulti(
   Summary,
   translate,
   withObservable('democracyLaunchPeriod'),
-  withObservable('democracyReferendumCount'),
+  withObservable('bestNumber'),
+  withObservable('referendumCount'),
   withObservable('democracyNextTally'),
-  withObservable('democracyProposalCount'),
+  withObservable('publicProposalCount'),
   withObservable('democracyVotingPeriod')
 );

+ 10 - 10
packages/app-democracy/src/Voting.tsx

@@ -1,14 +1,14 @@
 // Copyright 2017-2018 @polkadot/app-democracy authors & contributors
 // This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
+// of the Apache-2.0 license. See the LICENSE file for details.
 
 import { I18nProps } from '@polkadot/ui-app/types';
-import { QueueProps } from '@polkadot/ui-signer/types';
+import { QueueProps } from '@polkadot/ui-app/Status/types';
 
 import BN from 'bn.js';
 import React from 'react';
-import InputAddress from '@polkadot/ui-app/InputAddress';
-import { QueueConsumer } from '@polkadot/ui-signer/Context';
+import { InputAddress } from '@polkadot/ui-app/index';
+import { QueueConsumer } from '@polkadot/ui-app/Status/Context';
 
 import VotingButtons from './VotingButtons';
 import translate from './translate';
@@ -18,7 +18,7 @@ type Props = I18nProps & {
 };
 
 type State = {
-  publicKey?: Uint8Array
+  accountId?: string
 };
 
 class Voting extends React.PureComponent<Props, State> {
@@ -45,9 +45,9 @@ class Voting extends React.PureComponent<Props, State> {
 
   private renderButtons () {
     const { referendumId } = this.props;
-    const { publicKey } = this.state;
+    const { accountId } = this.state;
 
-    if (!publicKey) {
+    if (!accountId) {
       return null;
     }
 
@@ -55,7 +55,7 @@ class Voting extends React.PureComponent<Props, State> {
       <QueueConsumer>
         {({ queueExtrinsic }: QueueProps) => (
           <VotingButtons
-            publicKey={publicKey}
+            accountId={accountId}
             queueExtrinsic={queueExtrinsic}
             referendumId={referendumId}
           />
@@ -64,8 +64,8 @@ class Voting extends React.PureComponent<Props, State> {
     );
   }
 
-  private onChangeAccount = (publicKey?: Uint8Array) => {
-    this.setState({ publicKey });
+  private onChangeAccount = (accountId?: string) => {
+    this.setState({ accountId });
   }
 }
 

+ 21 - 19
packages/app-democracy/src/VotingButtons.tsx

@@ -1,34 +1,34 @@
 // Copyright 2017-2018 @polkadot/app-democracy authors & contributors
 // This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
+// of the Apache-2.0 license. See the LICENSE file for details.
 
 import { I18nProps } from '@polkadot/ui-app/types';
-import { QueueTx$ExtrinsicAdd } from '@polkadot/ui-signer/types';
+import { QueueTx$ExtrinsicAdd } from '@polkadot/ui-app/Status/types';
 
 import BN from 'bn.js';
 import React from 'react';
-import extrinsics from '@polkadot/extrinsics';
-import Button from '@polkadot/ui-app/Button';
-import withMulti from '@polkadot/ui-react-rx/with/multi';
-import withObservable from '@polkadot/ui-react-rx/with/observable';
+import Api from '@polkadot/api-observable';
+import { Extrinsic } from '@polkadot/types';
+import { Button } from '@polkadot/ui-app/index';
+import { withMulti, withObservable } from '@polkadot/ui-react-rx/with/index';
 
 import translate from './translate';
 
 type Props = I18nProps & {
-  publicKey?: Uint8Array,
+  accountId?: string,
   queueExtrinsic: QueueTx$ExtrinsicAdd,
   referendumId: BN,
-  systemAccountIndexOf?: BN
+  accountNonce?: BN
 };
 
 class VotingButton extends React.PureComponent<Props> {
   render () {
-    const { publicKey, t } = this.props;
+    const { accountId, t } = this.props;
 
     return (
       <Button.Group>
         <Button
-          isDisabled={!publicKey}
+          isDisabled={!accountId}
           isNegative
           text={t('votebtn.nay', {
             defaultValue: 'Nay'
@@ -37,7 +37,7 @@ class VotingButton extends React.PureComponent<Props> {
         />
         <Button.Or />
         <Button
-          isDisabled={!publicKey}
+          isDisabled={!accountId}
           isPositive
           text={t('votebtn.aye', {
             defaultValue: 'Aye'
@@ -49,17 +49,18 @@ class VotingButton extends React.PureComponent<Props> {
   }
 
   private doVote (vote: boolean) {
-    const { publicKey, queueExtrinsic, referendumId, systemAccountIndexOf = new BN(0) } = this.props;
+    const { accountId, queueExtrinsic, referendumId, accountNonce = new BN(0) } = this.props;
 
-    if (!publicKey) {
+    if (!accountId) {
       return;
     }
 
     queueExtrinsic({
-      extrinsic: extrinsics.democracy.public.vote,
-      nonce: systemAccountIndexOf,
-      publicKey,
-      values: [referendumId, vote]
+      extrinsic: new Extrinsic({
+        method: Api.extrinsics.democracy.vote(referendumId, vote)
+      }),
+      accountNonce,
+      accountId
     });
   }
 
@@ -73,6 +74,7 @@ class VotingButton extends React.PureComponent<Props> {
 }
 
 export default withMulti(
-  translate(VotingButton),
-  withObservable('systemAccountIndexOf', { paramProp: 'publicKey' })
+  VotingButton,
+  translate,
+  withObservable('accountNonce', { paramProp: 'accountId' })
 );

+ 1 - 6
packages/app-democracy/src/index.css

@@ -1,6 +1,6 @@
 /* Copyright 2017-2018 @polkadot/app-democracy authors & contributors
 /* This software may be modified and distributed under the terms
-/* of the ISC license. See the LICENSE file for details. */
+/* of the Apache-2.0 license. See the LICENSE file for details. */
 
 .democracy--App {
   margin-bottom: 1em;
@@ -27,11 +27,6 @@
   color: rgba(0, 0, 0, 0.6);
 }
 
-.democracy--Item-header-name {
-  font-size: 1.2rem;
-  line-height: 1.2rem;
-}
-
 .democracy--Item-body {
   display: flex;
   flex-direction: row;

+ 4 - 2
packages/app-democracy/src/index.tsx

@@ -1,8 +1,9 @@
 // Copyright 2017-2018 @polkadot/app-democracy authors & contributors
 // This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
+// of the Apache-2.0 license. See the LICENSE file for details.
 
 import { BareProps } from '@polkadot/ui-app/types';
+import { ActionStatus } from '@polkadot/ui-app/Status/types';
 
 import './index.css';
 
@@ -13,7 +14,8 @@ import Referendums from './Referendums';
 import Summary from './Summary';
 
 type Props = BareProps & {
-  basePath: string
+  basePath: string,
+  onStatusChange: (status: ActionStatus) => void
 };
 
 export default class App extends React.PureComponent<Props> {

+ 3 - 3
packages/app-democracy/src/translate.ts

@@ -1,7 +1,7 @@
 // Copyright 2017-2018 @polkadot/app-explorer authors & contributors
 // This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
+// of the Apache-2.0 license. See the LICENSE file for details.
 
-import { translate } from 'react-i18next';
+import { withNamespaces } from 'react-i18next';
 
-export default translate(['democracy', 'ui']);
+export default withNamespaces(['democracy', 'ui']);

+ 0 - 15
packages/app-example/LICENSE

@@ -1,15 +0,0 @@
-ISC License (ISC)
-
-Copyright 2017-2018 @polkadot/app-example authors & contributors
-
-Permission to use, copy, modify, and/or distribute this software for any
-purpose with or without fee is hereby granted, provided that the above
-copyright notice and this permission notice appear in all copies.
-
-THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
-REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
-FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
-INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
-OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-PERFORMANCE OF THIS SOFTWARE.

+ 0 - 3
packages/app-example/README.md

@@ -1,3 +0,0 @@
-# @polkadot/app-example
-
-A set of examples, created [via tutorial](../../examples/index.md).

+ 0 - 19
packages/app-example/package.json

@@ -1,19 +0,0 @@
-{
-  "name": "@polkadot/app-example",
-  "version": "0.20.30",
-  "description": "A basic example app",
-  "main": "index.js",
-  "scripts": {},
-  "author": "Jaco Greeff <jacogr@gmail.com>",
-  "maintainers": [
-    "Jaco Greeff <jacogr@gmail.com>"
-  ],
-  "license": "ISC",
-  "dependencies": {
-    "@babel/runtime": "^7.0.0",
-    "@polkadot/storage": "^0.29.7",
-    "@polkadot/ui-react": "^0.20.30",
-    "@polkadot/ui-react-rx": "^0.20.30",
-    "@polkadot/util-keyring": "^0.30.4"
-  }
-}

+ 0 - 19
packages/app-example/src/comp-002.tsx

@@ -1,19 +0,0 @@
-// Copyright 2017-2018 @polkadot/app-example authors & contributors
-// This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
-
-import React from 'react';
-
-import withObservableDiv from '@polkadot/ui-react-rx/with/observableDiv';
-
-const Comp: React.ComponentType<any> = withObservableDiv('stakingIntentions')(
-  (value: Uint8Array[]): string => {
-    if (!value || !value.length) {
-      return 'No intentions found';
-    }
-
-    return value.join(', ');
-  }
-);
-
-export default Comp;

+ 0 - 66
packages/app-example/src/comp-003.tsx

@@ -1,66 +0,0 @@
-// Copyright 2017-2018 @polkadot/app-example authors & contributors
-// This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
-
-import { ApiProps } from '@polkadot/ui-react-rx/types';
-
-import BN from 'bn.js';
-import React from 'react';
-
-import storage from '@polkadot/storage';
-import withApi from '@polkadot/ui-react-rx/with/api';
-
-type StorageProposal = [BN, any, string];
-
-type StateProposals = {
-  [index: string]: number[]
-};
-
-type State = {
-  proposals: StateProposals
-};
-
-class Comp extends React.PureComponent<ApiProps, State> {
-  constructor (props: ApiProps) {
-    super(props);
-
-    this.state = {
-      proposals: {}
-    };
-  }
-
-  // TODO We should unsubscribe from subscriptions
-  componentDidMount () {
-    this.subscribeProposals();
-  }
-
-  subscribeProposals () {
-    const { api } = this.props;
-
-    api.state
-      .getStorage(storage.democracy.public.proposals)
-      .subscribe((value: Array<StorageProposal>) => {
-        this.setState({
-          proposals: value.reduce((proposals: StateProposals, [propIdx, proposal, accountId]) => {
-            if (!proposals[accountId]) {
-              proposals[accountId] = [propIdx.toNumber()];
-            } else {
-              proposals[accountId].push(propIdx.toNumber());
-            }
-
-            return proposals;
-          }, {} as StateProposals)
-        });
-      });
-  }
-
-  render () {
-    const { proposals } = this.state;
-
-    return (
-      <div>Found {Object.keys(proposals).length} accounts making proposals.</div>
-    );
-  }
-}
-
-export default withApi(Comp);

+ 0 - 91
packages/app-example/src/comp-004.tsx

@@ -1,91 +0,0 @@
-// Copyright 2017-2018 @polkadot/app-example authors & contributors
-// This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
-
-import { ApiProps } from '@polkadot/ui-react-rx/types';
-
-import BN from 'bn.js';
-import React from 'react';
-
-import storage from '@polkadot/storage';
-import withApi from '@polkadot/ui-react-rx/with/api';
-
-type StorageProposal = [BN, any, string];
-type StorageIntentions = Array<string>;
-
-type StateProposals = {
-  [index: string]: number[]
-};
-
-type State = {
-  intentions: StorageIntentions,
-  proposals: StateProposals,
-  subscriptions: Array<any>
-};
-
-class Comp extends React.PureComponent<ApiProps, State> {
-  constructor (props: ApiProps) {
-    super(props);
-
-    this.state = {
-      intentions: [],
-      proposals: {},
-      subscriptions: []
-    };
-  }
-
-  componentDidMount () {
-    this.setState({
-      subscriptions: [
-        this.subscribeIntentions(),
-        this.subscribeProposals()
-      ]
-    });
-  }
-
-  subscribeIntentions () {
-    const { api } = this.props;
-
-    return api.state
-      .getStorage(storage.staking.public.intentions)
-      .subscribe((intentions: StorageIntentions) => {
-        this.setState({ intentions });
-      });
-  }
-
-  subscribeProposals () {
-    const { api } = this.props;
-
-    return api.state
-      .getStorage(storage.democracy.public.proposals)
-      .subscribe((value: Array<StorageProposal>) => {
-        this.setState({
-          proposals: value.reduce((proposals: StateProposals, [propIdx, proposal, accountId]) => {
-            if (!proposals[accountId]) {
-              proposals[accountId] = [propIdx.toNumber()];
-            } else {
-              proposals[accountId].push(propIdx.toNumber());
-            }
-
-            return proposals;
-          }, {} as StateProposals)
-        });
-      });
-  }
-
-  componentWillUnmount () {
-    const { subscriptions } = this.state;
-
-    subscriptions.forEach((sub) => sub.unsubscribe());
-  }
-
-  render () {
-    const { intentions, proposals } = this.state;
-
-    return (
-      <div>Found {Object.keys(proposals).length} accounts making proposals and {intentions.length} accounts intending to stake.</div>
-    );
-  }
-}
-
-export default withApi(Comp);

+ 0 - 118
packages/app-example/src/comp-005.tsx

@@ -1,118 +0,0 @@
-// Copyright 2017-2018 @polkadot/app-example authors & contributors
-// This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
-
-import { ApiProps } from '@polkadot/ui-react-rx/types';
-
-import BN from 'bn.js';
-import React from 'react';
-
-import storage from '@polkadot/storage';
-import withApi from '@polkadot/ui-react-rx/with/api';
-import IdentityIcon from '@polkadot/ui-react/IdentityIcon';
-import Balance from '@polkadot/ui-react-rx/Balance';
-
-type StorageProposal = [BN, any, string];
-type StorageIntentions = Array<string>;
-
-type StateProposals = {
-  [index: string]: number[]
-};
-
-type State = {
-  intentions: Array<string>,
-  proposals: StateProposals,
-  subscriptions: Array<any>
-};
-
-class Comp extends React.PureComponent<ApiProps, State> {
-  constructor (props: ApiProps) {
-    super(props);
-
-    this.state = {
-      intentions: [],
-      proposals: {},
-      subscriptions: []
-    };
-  }
-
-  componentDidMount () {
-    this.setState({
-      subscriptions: [
-        this.subscribeIntentions(),
-        this.subscribeProposals()
-      ]
-    });
-  }
-
-  subscribeIntentions () {
-    const { api } = this.props;
-
-    return api.state
-      .getStorage(storage.staking.public.intentions)
-      .subscribe((intentions: StorageIntentions) => {
-        this.setState({ intentions });
-      });
-  }
-
-  subscribeProposals () {
-    const { api } = this.props;
-
-    return api.state
-      .getStorage(storage.democracy.public.proposals)
-      .subscribe((value: Array<StorageProposal>) => {
-        this.setState({
-          proposals: value.reduce((proposals: StateProposals, [propIdx, proposal, accountId]) => {
-            if (!proposals[accountId]) {
-              proposals[accountId] = [propIdx.toNumber()];
-            } else {
-              proposals[accountId].push(propIdx.toNumber());
-            }
-
-            return proposals;
-          }, {} as StateProposals)
-        });
-      });
-  }
-
-  componentWillUnmount () {
-    const { subscriptions } = this.state;
-
-    subscriptions.forEach((sub) => sub.unsubscribe());
-  }
-
-  render () {
-    const { intentions, proposals } = this.state;
-
-    return (
-      <table className='accounts'>
-        <thead>
-          <tr>
-            <th />
-            <th>Address</th>
-            <th>Balance</th>
-            <th>Proposals</th>
-          </tr>
-        </thead>
-        <tbody>
-          {intentions.map((address) => (
-            this.renderAccount(address, proposals[address])
-          ))}
-        </tbody>
-      </table>
-    );
-  }
-
-  renderAccount = (address: string, proposals: number[] = []) => {
-    return (
-      <tr key={address}>
-        <td><IdentityIcon size={24} value={address} /></td>
-        <td>{address}</td>
-        <td><Balance params={address} /></td>
-        <td>{proposals.length}</td>
-      </tr>
-    );
-  }
-}
-
-export default withApi(Comp);

+ 0 - 132
packages/app-example/src/comp-006.tsx

@@ -1,132 +0,0 @@
-// Copyright 2017-2018 @polkadot/app-example authors & contributors
-// This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
-
-import { ApiProps } from '@polkadot/ui-react-rx/types';
-
-import BN from 'bn.js';
-import React from 'react';
-
-import storage from '@polkadot/storage';
-import withApi from '@polkadot/ui-react-rx/with/api';
-import IdentityIcon from '@polkadot/ui-react/IdentityIcon';
-import Balance from '@polkadot/ui-react-rx/Balance';
-
-type StorageProposal = [BN, any, string];
-type StorageIntentions = Array<string>;
-type StorageValidators = Array<string>;
-
-type StateProposals = {
-  [index: string]: number[]
-};
-
-type State = {
-  intentions: Array<string>,
-  proposals: StateProposals,
-  subscriptions: Array<any>,
-  validators: Array<string>
-};
-
-class Comp extends React.PureComponent<ApiProps, State> {
-  constructor (props: ApiProps) {
-    super(props);
-
-    this.state = {
-      intentions: [],
-      proposals: {},
-      subscriptions: [],
-      validators: []
-    };
-  }
-
-  componentDidMount () {
-    this.setState({
-      subscriptions: [
-        this.subscribeIntentions(),
-        this.subscribeProposals(),
-        this.subscribeValidators()
-      ]
-    });
-  }
-
-  subscribeIntentions () {
-    const { api } = this.props;
-
-    return api.state
-      .getStorage(storage.staking.public.intentions)
-      .subscribe((intentions: StorageIntentions) => {
-        this.setState({ intentions });
-      });
-  }
-
-  subscribeProposals () {
-    const { api } = this.props;
-
-    return api.state
-      .getStorage(storage.democracy.public.proposals)
-      .subscribe((value: Array<StorageProposal>) => {
-        this.setState({
-          proposals: value.reduce((proposals: StateProposals, [propIdx, proposal, accountId]) => {
-            if (!proposals[accountId]) {
-              proposals[accountId] = [propIdx.toNumber()];
-            } else {
-              proposals[accountId].push(propIdx.toNumber());
-            }
-
-            return proposals;
-          }, {} as StateProposals)
-        });
-      });
-  }
-
-  subscribeValidators () {
-    const { api } = this.props;
-
-    return api.state
-      .getStorage(storage.session.public.validators)
-      .subscribe((validators: StorageValidators) => {
-        this.setState({ validators });
-      });
-  }
-
-  componentWillUnmount () {
-    const { subscriptions } = this.state;
-
-    subscriptions.forEach((sub) => sub.unsubscribe());
-  }
-
-  render () {
-    const { intentions, proposals, validators } = this.state;
-
-    return (
-      <table className='accounts'>
-        <thead>
-          <tr>
-            <th />
-            <th>Address</th>
-            <th>Balance</th>
-            <th>Proposals</th>
-          </tr>
-        </thead>
-        <tbody>
-          {intentions.map((address) => (
-            this.renderAccount(address, proposals[address], validators.includes(address))
-          ))}
-        </tbody>
-      </table>
-    );
-  }
-
-  renderAccount = (address: string, proposals: number[] = [], isValidator: boolean = false) => {
-    return (
-      <tr className={isValidator ? 'validator' : ''} key={address}>
-        <td><IdentityIcon size={24} value={address} /></td>
-        <td>{address}</td>
-        <td><Balance params={address} /></td>
-        <td>{proposals.length}</td>
-      </tr>
-    );
-  }
-}
-
-export default withApi(Comp);

+ 0 - 180
packages/app-example/src/comp-007.tsx

@@ -1,180 +0,0 @@
-// Copyright 2017-2018 @polkadot/app-example authors & contributors
-// This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
-
-import { ApiProps } from '@polkadot/ui-react-rx/types';
-
-import BN from 'bn.js';
-import React from 'react';
-
-import storage from '@polkadot/storage';
-import IdentityIcon from '@polkadot/ui-react/IdentityIcon';
-import withApi from '@polkadot/ui-react-rx/with/api';
-
-type StorageProposal = [BN, any, string];
-type StorageIntentions = Array<string>;
-type StorageValidators = Array<string>;
-
-type StateBalances = {
-  [index: string]: BN
-};
-
-type StateProposals = {
-  [index: string]: number[]
-};
-
-type State = {
-  balances: StateBalances,
-  intentions: Array<string>,
-  proposals: StateProposals,
-  subscriptions: Array<any>,
-  validators: Array<string>
-};
-
-const ZERO = new BN(0);
-
-class Comp extends React.PureComponent<ApiProps, State> {
-  constructor (props: ApiProps) {
-    super(props);
-
-    this.state = {
-      balances: {},
-      intentions: [],
-      proposals: {},
-      subscriptions: [],
-      validators: []
-    };
-  }
-
-  componentDidMount () {
-    this.setState({
-      subscriptions: [
-        this.subscribeIntentions(),
-        this.subscribeProposals(),
-        this.subscribeValidators()
-      ]
-    });
-  }
-
-  subscribeIntentions () {
-    const { api } = this.props;
-
-    return api.state
-      .getStorage(storage.staking.public.intentions)
-      .subscribe((intentions: StorageIntentions) => {
-        this.setState({ intentions }, () => {
-          this.subscribeBalances(intentions);
-        });
-      });
-  }
-
-  subscribeProposals () {
-    const { api } = this.props;
-
-    return api.state
-      .getStorage(storage.democracy.public.proposals)
-      .subscribe((value: Array<StorageProposal>) => {
-        this.setState({
-          proposals: value.reduce((proposals: StateProposals, [propIdx, proposal, accountId]) => {
-            if (!proposals[accountId]) {
-              proposals[accountId] = [propIdx.toNumber()];
-            } else {
-              proposals[accountId].push(propIdx.toNumber());
-            }
-
-            return proposals;
-          }, {} as StateProposals)
-        });
-      });
-  }
-
-  subscribeValidators () {
-    const { api } = this.props;
-
-    return api.state
-      .getStorage(storage.session.public.validators)
-      .subscribe((validators: StorageValidators) => {
-        this.setState({ validators });
-      });
-  }
-
-  subscribeBalances (accounts: string[]) {
-    const { api } = this.props;
-    const { balances, subscriptions } = this.state;
-    const newBalances = { ...balances };
-
-    accounts.forEach((account) => {
-      if (newBalances[account]) {
-        return;
-      } else {
-        newBalances[account] = ZERO;
-      }
-
-      subscriptions.push(
-        api.state
-          // Here we pass a parameter to the key generator, so it points to the correct storage entry
-          .getStorage(storage.staking.public.freeBalanceOf, account)
-          .subscribe((balance: BN) => {
-            this.setState(({ balances }: State) => {
-              const newBalances = { ...balances };
-
-              newBalances[account] = balance;
-
-              return {
-                balances: newBalances
-              };
-            });
-          })
-      );
-    });
-
-    this.setState({
-      balances: newBalances,
-      subscriptions
-    });
-  }
-
-  componentWillUnmount () {
-    const { subscriptions } = this.state;
-
-    subscriptions.forEach((sub) => sub.unsubscribe());
-  }
-
-  render () {
-    const { balances, intentions, proposals, validators } = this.state;
-    const sortedIntentions = intentions.sort((a, b) =>
-      (balances[b] || ZERO).cmp(balances[a] || ZERO)
-    );
-
-    return (
-      <table className='accounts'>
-        <thead>
-          <tr>
-            <th />
-            <th>Address</th>
-            <th>Balance</th>
-            <th>Proposals</th>
-          </tr>
-        </thead>
-        <tbody>
-          {sortedIntentions.map((address) => (
-            this.renderAccount(address, balances[address], proposals[address], validators.includes(address))
-          ))}
-        </tbody>
-      </table>
-    );
-  }
-
-  renderAccount = (address: string, balance: BN = ZERO, proposals: number[] = [], isValidator: boolean = false) => {
-    return (
-      <tr className={isValidator ? 'validator' : ''} key={address}>
-        <td><IdentityIcon size={24} value={address} /></td>
-        <td>{address}</td>
-        <td>{balance.toString(10)}</td>
-        <td>{proposals.length}</td>
-      </tr>
-    );
-  }
-}
-
-export default withApi(Comp);

+ 0 - 13
packages/app-example/src/index-001.tsx

@@ -1,13 +0,0 @@
-// Copyright 2017-2018 @polkadot/app-example authors & contributors
-// This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
-
-import React from 'react';
-
-export default class App extends React.PureComponent<any> {
-  render () {
-    return (
-      <div className='example--App'>hello world</div>
-    );
-  }
-}

+ 0 - 17
packages/app-example/src/index-002.tsx

@@ -1,17 +0,0 @@
-// Copyright 2017-2018 @polkadot/app-example authors & contributors
-// This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
-
-import React from 'react';
-
-import Comp from './comp-002';
-
-export default class App extends React.PureComponent<any> {
-  render () {
-    return (
-      <div className='example--App'>
-        <Comp />
-      </div>
-    );
-  }
-}

+ 0 - 17
packages/app-example/src/index-003.tsx

@@ -1,17 +0,0 @@
-// Copyright 2017-2018 @polkadot/app-example authors & contributors
-// This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
-
-import React from 'react';
-
-import Comp from './comp-003';
-
-export default class App extends React.PureComponent<any> {
-  render () {
-    return (
-      <div className='example--App'>
-        <Comp />
-      </div>
-    );
-  }
-}

+ 0 - 17
packages/app-example/src/index-004.tsx

@@ -1,17 +0,0 @@
-// Copyright 2017-2018 @polkadot/app-example authors & contributors
-// This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
-
-import React from 'react';
-
-import Comp from './comp-004';
-
-export default class App extends React.PureComponent<any> {
-  render () {
-    return (
-      <div className='example--App'>
-        <Comp />
-      </div>
-    );
-  }
-}

+ 0 - 17
packages/app-example/src/index-005.tsx

@@ -1,17 +0,0 @@
-// Copyright 2017-2018 @polkadot/app-example authors & contributors
-// This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
-
-import React from 'react';
-
-import Comp from './comp-005';
-
-export default class App extends React.PureComponent<any> {
-  render () {
-    return (
-      <div className='example--App'>
-        <Comp />
-      </div>
-    );
-  }
-}

+ 0 - 17
packages/app-example/src/index-006.tsx

@@ -1,17 +0,0 @@
-// Copyright 2017-2018 @polkadot/app-example authors & contributors
-// This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
-
-import React from 'react';
-
-import Comp from './comp-006';
-
-export default class App extends React.PureComponent<any> {
-  render () {
-    return (
-      <div className='example--App'>
-        <Comp />
-      </div>
-    );
-  }
-}

+ 0 - 17
packages/app-example/src/index-007.tsx

@@ -1,17 +0,0 @@
-// Copyright 2017-2018 @polkadot/app-example authors & contributors
-// This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
-
-import React from 'react';
-
-import Comp from './comp-007';
-
-export default class App extends React.PureComponent<any> {
-  render () {
-    return (
-      <div className='example--App'>
-        <Comp />
-      </div>
-    );
-  }
-}

+ 0 - 16
packages/app-example/src/index.css

@@ -1,16 +0,0 @@
-/* Copyright 2017-2018 @polkadot/app-example authors & contributors
-/* This software may be modified and distributed under the terms
-/* of the ISC license. See the LICENSE file for details. */
-
-.example--App a {
-  cursor: pointer;
-  margin-right: 0.5em;
-}
-
-.example--App table.accounts td {
-  padding: 0.125em 0.5em;
-}
-
-.example--App table.accounts tr.validator {
-  background: #f2f2f2;
-}

+ 0 - 59
packages/app-example/src/index.tsx

@@ -1,59 +0,0 @@
-// Copyright 2017-2018 @polkadot/app-example authors & contributors
-// This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
-
-import { BareProps } from '@polkadot/ui-app/types';
-
-import React from 'react';
-
-import './index.css';
-
-import Tut002 from './comp-002';
-import Tut003 from './comp-003';
-import Tut004 from './comp-004';
-import Tut005 from './comp-005';
-import Tut006 from './comp-006';
-import Tut007 from './comp-007';
-
-const Components: { [index: string]: React.ComponentType<any> } = {
-  Tut002, Tut003, Tut004, Tut005, Tut006, Tut007
-};
-
-type Props = BareProps & {
-  basePath: string
-};
-
-type State = {
-  Component: React.ComponentType<any>
-};
-
-export default class App extends React.PureComponent<Props, State> {
-  constructor (props: Props) {
-    super(props);
-
-    this.state = {
-      Component: Tut002
-    };
-  }
-
-  render () {
-    const { Component } = this.state;
-
-    return (
-      <main className='example--App'>
-        <header className='navigation'>{
-          Object.keys(Components).map((name) => (
-            <a key={name} onClick={() => this.onSelect(name)}>{name}</a>
-          ))
-        }</header>
-        <div><Component /></div>
-      </main>
-    );
-  }
-
-  onSelect (name: string) {
-    this.setState({
-      Component: Components[name]
-    });
-  }
-}

+ 198 - 12
packages/app-explorer/LICENSE

@@ -1,15 +1,201 @@
-ISC License (ISC)
+                              Apache License
+                        Version 2.0, January 2004
+                    http://www.apache.org/licenses/
 
-Copyright 2017-2018 @polkadot/app-explorer authors & contributors
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
 
-Permission to use, copy, modify, and/or distribute this software for any
-purpose with or without fee is hereby granted, provided that the above
-copyright notice and this permission notice appear in all copies.
+1. Definitions.
 
-THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
-REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
-FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
-INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
-OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-PERFORMANCE OF THIS SOFTWARE.
+  "License" shall mean the terms and conditions for use, reproduction,
+  and distribution as defined by Sections 1 through 9 of this document.
+
+  "Licensor" shall mean the copyright owner or entity authorized by
+  the copyright owner that is granting the License.
+
+  "Legal Entity" shall mean the union of the acting entity and all
+  other entities that control, are controlled by, or are under common
+  control with that entity. For the purposes of this definition,
+  "control" means (i) the power, direct or indirect, to cause the
+  direction or management of such entity, whether by contract or
+  otherwise, or (ii) ownership of fifty percent (50%) or more of the
+  outstanding shares, or (iii) beneficial ownership of such entity.
+
+  "You" (or "Your") shall mean an individual or Legal Entity
+  exercising permissions granted by this License.
+
+  "Source" form shall mean the preferred form for making modifications,
+  including but not limited to software source code, documentation
+  source, and configuration files.
+
+  "Object" form shall mean any form resulting from mechanical
+  transformation or translation of a Source form, including but
+  not limited to compiled object code, generated documentation,
+  and conversions to other media types.
+
+  "Work" shall mean the work of authorship, whether in Source or
+  Object form, made available under the License, as indicated by a
+  copyright notice that is included in or attached to the work
+  (an example is provided in the Appendix below).
+
+  "Derivative Works" shall mean any work, whether in Source or Object
+  form, that is based on (or derived from) the Work and for which the
+  editorial revisions, annotations, elaborations, or other modifications
+  represent, as a whole, an original work of authorship. For the purposes
+  of this License, Derivative Works shall not include works that remain
+  separable from, or merely link (or bind by name) to the interfaces of,
+  the Work and Derivative Works thereof.
+
+  "Contribution" shall mean any work of authorship, including
+  the original version of the Work and any modifications or additions
+  to that Work or Derivative Works thereof, that is intentionally
+  submitted to Licensor for inclusion in the Work by the copyright owner
+  or by an individual or Legal Entity authorized to submit on behalf of
+  the copyright owner. For the purposes of this definition, "submitted"
+  means any form of electronic, verbal, or written communication sent
+  to the Licensor or its representatives, including but not limited to
+  communication on electronic mailing lists, source code control systems,
+  and issue tracking systems that are managed by, or on behalf of, the
+  Licensor for the purpose of discussing and improving the Work, but
+  excluding communication that is conspicuously marked or otherwise
+  designated in writing by the copyright owner as "Not a Contribution."
+
+  "Contributor" shall mean Licensor and any individual or Legal Entity
+  on behalf of whom a Contribution has been received by Licensor and
+  subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+  this License, each Contributor hereby grants to You a perpetual,
+  worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+  copyright license to reproduce, prepare Derivative Works of,
+  publicly display, publicly perform, sublicense, and distribute the
+  Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+  this License, each Contributor hereby grants to You a perpetual,
+  worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+  (except as stated in this section) patent license to make, have made,
+  use, offer to sell, sell, import, and otherwise transfer the Work,
+  where such license applies only to those patent claims licensable
+  by such Contributor that are necessarily infringed by their
+  Contribution(s) alone or by combination of their Contribution(s)
+  with the Work to which such Contribution(s) was submitted. If You
+  institute patent litigation against any entity (including a
+  cross-claim or counterclaim in a lawsuit) alleging that the Work
+  or a Contribution incorporated within the Work constitutes direct
+  or contributory patent infringement, then any patent licenses
+  granted to You under this License for that Work shall terminate
+  as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+  Work or Derivative Works thereof in any medium, with or without
+  modifications, and in Source or Object form, provided that You
+  meet the following conditions:
+
+  (a) You must give any other recipients of the Work or
+      Derivative Works a copy of this License; and
+
+  (b) You must cause any modified files to carry prominent notices
+      stating that You changed the files; and
+
+  (c) You must retain, in the Source form of any Derivative Works
+      that You distribute, all copyright, patent, trademark, and
+      attribution notices from the Source form of the Work,
+      excluding those notices that do not pertain to any part of
+      the Derivative Works; and
+
+  (d) If the Work includes a "NOTICE" text file as part of its
+      distribution, then any Derivative Works that You distribute must
+      include a readable copy of the attribution notices contained
+      within such NOTICE file, excluding those notices that do not
+      pertain to any part of the Derivative Works, in at least one
+      of the following places: within a NOTICE text file distributed
+      as part of the Derivative Works; within the Source form or
+      documentation, if provided along with the Derivative Works; or,
+      within a display generated by the Derivative Works, if and
+      wherever such third-party notices normally appear. The contents
+      of the NOTICE file are for informational purposes only and
+      do not modify the License. You may add Your own attribution
+      notices within Derivative Works that You distribute, alongside
+      or as an addendum to the NOTICE text from the Work, provided
+      that such additional attribution notices cannot be construed
+      as modifying the License.
+
+  You may add Your own copyright statement to Your modifications and
+  may provide additional or different license terms and conditions
+  for use, reproduction, or distribution of Your modifications, or
+  for any such Derivative Works as a whole, provided Your use,
+  reproduction, and distribution of the Work otherwise complies with
+  the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+  any Contribution intentionally submitted for inclusion in the Work
+  by You to the Licensor shall be under the terms and conditions of
+  this License, without any additional terms or conditions.
+  Notwithstanding the above, nothing herein shall supersede or modify
+  the terms of any separate license agreement you may have executed
+  with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+  names, trademarks, service marks, or product names of the Licensor,
+  except as required for reasonable and customary use in describing the
+  origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+  agreed to in writing, Licensor provides the Work (and each
+  Contributor provides its Contributions) on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+  implied, including, without limitation, any warranties or conditions
+  of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+  PARTICULAR PURPOSE. You are solely responsible for determining the
+  appropriateness of using or redistributing the Work and assume any
+  risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+  whether in tort (including negligence), contract, or otherwise,
+  unless required by applicable law (such as deliberate and grossly
+  negligent acts) or agreed to in writing, shall any Contributor be
+  liable to You for damages, including any direct, indirect, special,
+  incidental, or consequential damages of any character arising as a
+  result of this License or out of the use or inability to use the
+  Work (including but not limited to damages for loss of goodwill,
+  work stoppage, computer failure or malfunction, or any and all
+  other commercial damages or losses), even if such Contributor
+  has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+  the Work or Derivative Works thereof, You may choose to offer,
+  and charge a fee for, acceptance of support, warranty, indemnity,
+  or other liability obligations and/or rights consistent with this
+  License. However, in accepting such obligations, You may act only
+  on Your own behalf and on Your sole responsibility, not on behalf
+  of any other Contributor, and only if You agree to indemnify,
+  defend, and hold each Contributor harmless for any liability
+  incurred by, or claims asserted against, such Contributor by reason
+  of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+  To apply the Apache License to your work, attach the following
+  boilerplate notice, with the fields enclosed by brackets "[]"
+  replaced with your own identifying information. (Don't include
+  the brackets!)  The text should be enclosed in the appropriate
+  comment syntax for the file format. We also recommend that a
+  file or class name and description of purpose be included on the
+  same "printed page" as the copyright notice for easier
+  identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.

+ 6 - 6
packages/app-explorer/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@polkadot/app-explorer",
-  "version": "0.20.30",
+  "version": "0.21.0",
   "main": "index.js",
   "repository": "https://github.com/polkadot-js/apps.git",
   "author": "Jaco Greeff <jacogr@gmail.com>",
@@ -8,11 +8,11 @@
     "Jaco Greeff <jacogr@gmail.com>"
   ],
   "contributors": [],
-  "license": "ISC",
+  "license": "Apache-2.0",
   "dependencies": {
-    "@babel/runtime": "^7.0.0",
-    "@polkadot/primitives": "^0.29.7",
-    "@polkadot/ui-app": "^0.20.30",
-    "@polkadot/util-crypto": "^0.30.4"
+    "@babel/runtime": "^7.2.0",
+    "@polkadot/types": "^0.35.9",
+    "@polkadot/ui-app": "^0.21.0",
+    "@polkadot/util-crypto": "^0.33.26"
   }
 }

+ 8 - 10
packages/app-explorer/src/BestHash.tsx

@@ -1,18 +1,16 @@
 // Copyright 2017-2018 @polkadot/app-explorer authors & contributors
 // This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
+// of the Apache-2.0 license. See the LICENSE file for details.
 
-import { Header } from '@polkadot/primitives/header';
+import { Header } from '@polkadot/types';
 
-import headerHash from '@polkadot/primitives/codec/header/hash';
-import withObservableDiv from '@polkadot/ui-react-rx/with/observableDiv';
-import u8aToHex from '@polkadot/util/u8a/toHex';
+import { withObservableDiv } from '@polkadot/ui-react-rx/with/index';
 
-const Component: React.ComponentType<any> = withObservableDiv('chainNewHead')(
-  (value?: Header): string | undefined =>
-    value
-      ? u8aToHex(headerHash(value), 64)
-      : value,
+const Component: React.ComponentType<any> = withObservableDiv('subscribeNewHead')(
+  (header?: Header): string | undefined =>
+    header
+      ? header.hash.toHex()
+      : undefined,
   { className: 'explorer--BestHash' }
 );
 

+ 92 - 70
packages/app-explorer/src/BlockByHash/BlockByHash.tsx

@@ -1,42 +1,34 @@
 // Copyright 2017-2018 @polkadot/app-explorer authors & contributors
 // This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
+// of the Apache-2.0 license. See the LICENSE file for details.
 
-import { BlockDecoded } from '@polkadot/params/types';
 import { I18nProps } from '@polkadot/ui-app/types';
 import { ApiProps } from '@polkadot/ui-react-rx/types';
 
 import React from 'react';
-import withMulti from '@polkadot/ui-react-rx/with/multi';
-import withObservable from '@polkadot/ui-react-rx/with/observable';
-import AddressMini from '@polkadot/ui-app/AddressMini';
-import Extrinsic from '@polkadot/ui-app/Extrinsic';
-import prettyJson from '@polkadot/ui-app/util/prettyJson';
-import numberFormat from '@polkadot/ui-react-rx/util/numberFormat';
-import isHex from '@polkadot/util/is/hex';
-import u8aToHex from '@polkadot/util/u8a/toHex';
+import { AddressMini, Call } from '@polkadot/ui-app/index';
+import { Extrinsic, Method, SignedBlock } from '@polkadot/types';
+import { withMulti, withObservable } from '@polkadot/ui-react-rx/with/index';
+import { numberFormat } from '@polkadot/ui-react-rx/util/index';
 
 import BlockHeader from '../BlockHeader';
 import translate from '../translate';
+import Logs from './Logs';
 
 type Props = ApiProps & I18nProps & {
-  chainGetBlock: BlockDecoded,
+  getBlock: SignedBlock,
   value: string
 };
 
-// FIXME Duplicated layout here and in democracy, clean up with extrinsics
 class BlockByHash extends React.PureComponent<Props> {
   render () {
-    const { chainGetBlock } = this.props;
+    const { getBlock } = this.props;
 
-    if (!chainGetBlock) {
+    if (!getBlock || !getBlock.block) {
       return null;
     }
 
-    const { header } = chainGetBlock;
-
-    // TODO Remove, debug info for reverse-engineering
-    console.log(prettyJson(chainGetBlock));
+    const { block: { header } } = getBlock;
 
     return [
       <header key='header'>
@@ -46,13 +38,17 @@ class BlockByHash extends React.PureComponent<Props> {
         />
       </header>,
       this.renderExtrinsics(),
-      this.renderJustification()
+      // this.renderJustification(),
+      <Logs
+        key='logs'
+        value={header.digest.logs}
+      />
     ];
   }
 
   private renderExtrinsics () {
-    const { chainGetBlock, t, value } = this.props;
-    const { extrinsics } = chainGetBlock;
+    const { getBlock, t } = this.props;
+    const { block: { extrinsics } } = getBlock;
 
     return (
       <section key='extrinsics'>
@@ -60,62 +56,88 @@ class BlockByHash extends React.PureComponent<Props> {
           defaultValue: 'extrinsics'
         })}</h1>
         <div className='explorer--BlockByHash-flexable'>
-          {extrinsics.map((extrinsic, index) => (
-            <div
-              className='explorer--BlockByHash-extrinsic'
-              key={`${value}:extrinsic:${index}`}
-            >
-              <article>
-                <div className='explorer--BlockByHash-extrinsic-header'>
-                  <div className='explorer--BlockByHash-extrinsic-header-name'>
-                    {extrinsic.extrinsic.section}.{extrinsic.extrinsic.name}
-                  </div>
-                  <div className='explorer--BlockByHash-extrinsic-header-description'>
-                    {extrinsic.extrinsic.description}
-                  </div>
-                  <div className='explorer--BlockByHash-header-right'>
-                    <div>{isHex(extrinsic.address)
-                      ? extrinsic.address
-                      : <AddressMini value={extrinsic.address} />
-                    }</div>
-                    <div className='explorer--BlockByHash-accountIndex'>{t('block.accountIndex', {
-                      defaultValue: 'index'
-                    })} {numberFormat(extrinsic.accountIndex)}</div>
-                  </div>
-                </div>
-                <Extrinsic value={extrinsic} />
-              </article>
-            </div>
-          ))}
+          {extrinsics.map(this.renderExtrinsic)}
         </div>
       </section>
     );
   }
 
-  private renderJustification () {
-    const { chainGetBlock, t, value } = this.props;
-    const { justification } = chainGetBlock;
+  // FIXME This is _very_ similar to what we have in democracy/Item
+  private renderExtrinsic = (extrinsic: Extrinsic, index?: number) => {
+    const { value } = this.props;
+    const { meta, method, section } = Method.findFunction(extrinsic.callIndex);
 
     return (
-      <section key='justification'>
-        <h1>{t('block.justifications', {
-          defaultValue: 'justifications'
-        })}</h1>
-        <div className='explorer--BlockByHash-flexable'>
-          {justification.signatures.map(({ address, signature }) => (
-            <div
-              className='explorer--BlockByHash-justification-signature'
-              key={`${value}:justification:${address}`}
-            >
-              <AddressMini value={address}>
-                <span>
-                  {u8aToHex(signature, 64)}
-                </span>
-              </AddressMini>
-            </div>
-          ))}
+      <div
+        className='explorer--BlockByHash-block'
+        key={`${value}:extrinsic:${index}`}
+      >
+        <article className='explorer--Container'>
+          <div className='header'>
+            <h3>
+              {section}.{method}
+            </h3>
+            <div className='description'>{
+              meta && meta.documentation && meta.documentation.length
+                ? meta.documentation.map((doc) => doc.toString()).join(' ')
+                : ''
+            }</div>
+            {this.renderSigner(extrinsic)}
+          </div>
+          <Call value={extrinsic} />
+        </article>
+      </div>
+    );
+  }
+
+  // Bft/Rhohenderon only
+  // private renderJustification () {
+  //   const { getBlock, t, value } = this.props;
+  //   const { justification: { signatures } } = getBlock;
+
+  //   if (!signatures || !signatures.length) {
+  //     return null;
+  //   }
+
+  //   return (
+  //     <section key='justification'>
+  //       <h1>{t('block.justifications', {
+  //         defaultValue: 'justifications'
+  //       })}</h1>
+  //       <div className='explorer--BlockByHash-flexable'>
+  //         {signatures.map(({ authorityId, signature }) => (
+  //           <div
+  //             className='explorer--BlockByHash-justification-signature'
+  //             key={`${value}:justification:${authorityId}`}
+  //           >
+  //             <AddressMini value={authorityId}>
+  //               <span>
+  //                 {u8aToHex(signature.toU8a(), 64)}
+  //               </span>
+  //             </AddressMini>
+  //           </div>
+  //         ))}
+  //       </div>
+  //     </section>
+  //   );
+  // }
+
+  private renderSigner (extrinsic: Extrinsic) {
+    const { t } = this.props;
+
+    if (!extrinsic.signature.isSigned) {
+      return null;
+    }
+
+    return (
+      <div className='explorer--BlockByHash-header-right'>
+        <div>
+          <AddressMini value={extrinsic.signature.signer} />
         </div>
-      </section>
+        <div className='explorer--BlockByHash-accountIndex'>{t('block.nonce', {
+          defaultValue: 'index'
+        })} {numberFormat(extrinsic.signature.nonce)}</div>
+      </div>
     );
   }
 }
@@ -123,5 +145,5 @@ class BlockByHash extends React.PureComponent<Props> {
 export default withMulti(
   BlockByHash,
   translate,
-  withObservable('chainGetBlock', { paramProp: 'value' })
+  withObservable('getBlock', { paramProp: 'value' })
 );

+ 89 - 0
packages/app-explorer/src/BlockByHash/Logs.tsx

@@ -0,0 +1,89 @@
+// Copyright 2017-2018 @polkadot/app-explorer authors & contributors
+// This software may be modified and distributed under the terms
+// of the Apache-2.0 license. See the LICENSE file for details.
+
+import { I18nProps } from '@polkadot/ui-app/types';
+
+import React from 'react';
+import { Struct, Vector, getTypeDef } from '@polkadot/types/codec';
+import { DigestItem } from '@polkadot/types/Digest';
+import { Params } from '@polkadot/ui-app/index';
+
+import translate from '../translate';
+
+type Props = I18nProps & {
+  value?: Array<DigestItem>
+};
+
+class Logs extends React.PureComponent<Props> {
+  render () {
+    const { t, value } = this.props;
+
+    if (!value || !value.length) {
+      return null;
+    }
+
+    return (
+      <section>
+        <h1>{t('block.logs', {
+          defaultValue: 'logs'
+        })}</h1>
+        <div className='explorer--BlockByHash-flexable'>
+          {value.map(this.renderItem)}
+        </div>
+      </section>
+    );
+  }
+
+  private renderItem = (item: DigestItem, index: number) => {
+    let content: React.ReactNode;
+
+    if (item.value instanceof Struct) {
+      const types: { [index: string]: string } = item.value.Type;
+
+      const params = Object.keys(types).map((name) => ({
+        name,
+        type: getTypeDef(types[name])
+      }));
+      const values = item.value.toArray().map((value) => ({
+        isValid: true,
+        value
+      }));
+
+      content = (
+        <Params
+          isDisabled
+          params={params}
+          values={values}
+        />
+      );
+    } else if (item.value instanceof Vector) {
+      content = item.value.map((entry, index) => (
+        <span key={index}>{entry.toString()}</span>
+      ));
+    } else {
+      content = item.value.toString().split(',').join(', ');
+    }
+
+    return (
+      <div
+        className='explorer--BlockByHash-block'
+        key={index}
+      >
+        <article className='explorer--Container'>
+          <div className='header'>
+            <h3>
+              {item.type.toString()}
+            </h3>
+            <div className='description' />
+          </div>
+          <div className='value'>
+            {content}
+          </div>
+        </article>
+      </div>
+    );
+  }
+}
+
+export default translate(Logs);

+ 1 - 1
packages/app-explorer/src/BlockByHash/index.tsx

@@ -1,6 +1,6 @@
 // Copyright 2017-2018 @polkadot/app-explorer authors & contributors
 // This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
+// of the Apache-2.0 license. See the LICENSE file for details.
 
 import { BareProps } from '@polkadot/ui-app/types';
 

+ 41 - 0
packages/app-explorer/src/BlockHeader/BlockHash.tsx

@@ -0,0 +1,41 @@
+// Copyright 2017-2018 @polkadot/app-explorer authors & contributors
+// This software may be modified and distributed under the terms
+// of the Apache-2.0 license. See the LICENSE file for details.
+
+import { I18nProps } from '@polkadot/ui-app/types';
+
+import React from 'react';
+import { Link } from 'react-router-dom';
+import jsonrpc from '@polkadot/jsonrpc';
+import { withObservable } from '@polkadot/ui-react-rx/with/index';
+import { BlockNumber, Hash } from '@polkadot/types';
+
+type Props = I18nProps & {
+  blockNumber: BlockNumber,
+  getBlockHash?: Hash,
+  withLink?: boolean
+};
+
+class BlockHash extends React.PureComponent<Props> {
+  render () {
+    const { getBlockHash, withLink } = this.props;
+
+    if (!getBlockHash) {
+      return null;
+    }
+
+    const hashHex = getBlockHash.toHex();
+
+    return (
+      withLink
+        ? <Link to={`/explorer/hash/${hashHex}`}>{hashHex}</Link>
+        : hashHex
+    );
+  }
+}
+
+export default withObservable('rawCall', {
+  params: [jsonrpc.chain.methods.getBlockHash],
+  paramProp: 'blockNumber',
+  propName: 'getBlockHash'
+})(BlockHash);

+ 67 - 40
packages/app-explorer/src/BlockHeader/BlockHeader.css

@@ -1,56 +1,83 @@
 /* Copyright 2017-2018 @polkadot/app-explorer authors & contributors
 /* This software may be modified and distributed under the terms
-/* of the ISC license. See the LICENSE file for details. */
-
-.explorer--BlockHeader {
-  animation: fadein 1.5s;
-  display: flex;
-}
+/* of the Apache-2.0 license. See the LICENSE file for details. */
 
 @keyframes fadein {
   from { opacity: 0; }
   to { opacity: 1; }
 }
 
-.explorer--BlockHeader:nth-child(even) {
-  background: #fcfcfc;
-}
+.explorer--BlockHeader {
+  animation: fadein 1.5s;
 
-.explorer--BlockHeader > div {
-  padding: 0.5em;
-}
+  > div {
+    padding: 0.5em;
+    overflow: hidden;
+  }
 
-.explorer--BlockHeader > .number {
-  align-items: center;
-  box-sizing: border-box;
-  display: flex;
-  flex: 1 33%;
-  font-size: 3rem;
-  font-weight: 100;
-}
+  .header {
+    color: rgba(0, 0, 0, 0.6);
+    overflow: hidden;
+    text-align: left;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+    vertical-align: middle;
 
-.explorer--BlockHeader > .number div {
-  flex: 1;
-  text-align: right;
-}
+    > div {
+      display: inline-block;
+      font-size: 3rem;
+      font-weight: 100;
+      line-height: 1;
+      margin-bottom: 0.25rem;
+      vertical-align: middle;
+      white-space: nowrap;
+    }
 
-.explorer--BlockHeader > .details {
-  box-sizing: border-box;
-  flex: 1 67%;
-  text-align: left;
-}
+    .hash {
+      font-size: 1.5em;
+    }
+  }
 
-.explorer--BlockHeader > .details > .contains {
-  border: 0;
-  font-size: 0.75em;
-  opacity: 0.75;
-}
+  .hash {
+    font-family: monospace;
+    overflow: hidden;
+    text-overflow: ellipsis;
+  }
 
-.explorer--BlockHeader > .details > .contains td {
-  padding: 0 0.25em;
-}
+  .number {
+    align-items: center;
+    box-sizing: border-box;
+  }
+
+  .details {
+    box-sizing: border-box;
+    flex: 1;
+    min-width: 0;
+    text-align: center;
+    overflow: hidden;
+
+    .contains {
+      border: 0;
+      opacity: 0.75;
+
+      div {
+        margin-bottom: 0.125em;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        white-space: nowrap;
+
+        div {
+          display: inline-block;
+          padding: 0 0.25em;
+          vertical-align: middle;
 
-.explorer--BlockHeader > .details > .contains td.type {
-  opacity: 0.75;
-  text-align: right;
+          &.type {
+            opacity: 0.75;
+            text-align: right;
+            width: 10em;
+          }
+        }
+      }
+    }
+  }
 }

+ 7 - 9
packages/app-explorer/src/BlockHeader/Extrinsics.tsx

@@ -1,26 +1,24 @@
 // Copyright 2017-2018 @polkadot/app-explorer authors & contributors
 // This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
+// of the Apache-2.0 license. See the LICENSE file for details.
 
 import { I18nProps } from '@polkadot/ui-app/types';
 
 import React from 'react';
-
-import withMulti from '@polkadot/ui-react-rx/with/multi';
-import withObservable from '@polkadot/ui-react-rx/with/observable';
+import { withMulti, withObservable } from '@polkadot/ui-react-rx/with/index';
 
 import translate from '../translate';
 
 type Props = I18nProps & {
   hash: Uint8Array,
-  chainGetBlock: any
+  getBlock: any
 };
 
 class Extrinsics extends React.PureComponent<Props> {
   render () {
-    const { chainGetBlock, t } = this.props;
+    const { getBlock, t } = this.props;
 
-    if (!chainGetBlock || !chainGetBlock.extrinsics) {
+    if (!getBlock || !getBlock.extrinsics) {
       return null;
     }
 
@@ -31,7 +29,7 @@ class Extrinsics extends React.PureComponent<Props> {
           {t('extrinsics.count', {
             defaultValue: '{{count}} in block',
             replace: {
-              count: chainGetBlock.extrinsics.length
+              count: getBlock.extrinsics.length
             }
           })}
         </td>
@@ -44,5 +42,5 @@ class Extrinsics extends React.PureComponent<Props> {
 export default withMulti(
   Extrinsics,
   translate,
-  withObservable('chainGetBlock', { paramProp: 'hash' })
+  withObservable('getBlock', { paramProp: 'hash' })
 );

+ 42 - 52
packages/app-explorer/src/BlockHeader/index.tsx

@@ -1,84 +1,74 @@
 // Copyright 2017-2018 @polkadot/app-explorer authors & contributors
 // This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
+// of the Apache-2.0 license. See the LICENSE file for details.
 
-import { Header } from '@polkadot/primitives/header';
+import { Header } from '@polkadot/types';
 import { BareProps } from '@polkadot/ui-app/types';
-import { ApiProps } from '@polkadot/ui-react-rx/types';
 
 import './BlockHeader.css';
 
 import React from 'react';
 import { Link } from 'react-router-dom';
-import headerHash from '@polkadot/primitives/codec/header/hash';
 import numberFormat from '@polkadot/ui-react-rx/util/numberFormat';
-import withApi from '@polkadot/ui-react-rx/with/api';
-import u8aToHex from '@polkadot/util/u8a/toHex';
 
-import CopyButton from '@polkadot/ui-app/CopyButton';
+// FIXME 7 Nov 2018 Due to mismatches with block hashes between Substrate and BBQ,
+// the hashes are retrieved and not calculated (go back to calculated once resolved)
+import BlockHash from './BlockHash';
 import Extrinsics from './Extrinsics';
 
-type Props = ApiProps & BareProps & {
+type Props = BareProps & {
   value?: Header,
   withExtrinsics?: boolean,
   withLink?: boolean
 };
 
-class BlockHeader extends React.PureComponent<Props> {
+export default class BlockHeader extends React.PureComponent<Props> {
   render () {
-    const { apiMethods, value, withExtrinsics = false, withLink = false } = this.props;
+    const { value, withExtrinsics = false, withLink = false } = this.props;
 
     if (!value) {
       return null;
     }
 
-    const isLinkable = !!apiMethods.chain_getBlock;
-    const hash = headerHash(value);
-    // tslint:disable-next-line:variable-name
-    const { extrinsicsRoot, number, parentHash, stateRoot } = value;
-    const hashHex = u8aToHex(hash);
-    const parentHex = u8aToHex(parentHash);
+    const { blockNumber, extrinsicsRoot, parentHash, stateRoot } = value;
+    const parentHex = parentHash.toHex();
 
     return (
-      <div className='explorer--BlockHeader'>
-        <div className='number'>
-          <div>{numberFormat(number)}</div>
-        </div>
+      <article className='explorer--BlockHeader'>
         <div className='details'>
-          <div className='hash'>
-            {isLinkable && withLink
-              ? <Link to={`/explorer/hash/${hashHex}`}>{hashHex}</Link>
-              : hashHex}
-            <CopyButton value={hashHex} />
+          <div className='header'>
+            <div className='number'>{numberFormat(blockNumber)}&nbsp;</div>
+            <div className='hash'>
+              <BlockHash
+                blockNumber={blockNumber}
+                withLink={withLink}
+              />
+            </div>
+          </div>
+          <div className='contains'>
+            <div>
+              <div className='type'>parentHash</div>
+              <div className='hash'>{
+                value.blockNumber.gtn(1)
+                  ? <Link to={`/explorer/hash/${parentHex}`}>{parentHex}</Link>
+                  : parentHex
+              }</div>
+            </div>
+            <div>
+              <div className='type'>extrinsicsRoot</div>
+              <div className='hash'>{extrinsicsRoot.toHex()}</div>
+            </div>
+            <div>
+              <div className='type'>stateRoot</div>
+              <div className='hash'>{stateRoot.toHex()}</div>
+            </div>
+            {withExtrinsics
+              ? <Extrinsics hash={value.hash} />
+              : undefined
+            }
           </div>
-          <table className='contains'>
-            <tbody>
-              <tr>
-                <td className='type'>parentHash</td>
-                <td className='hash'>{
-                  isLinkable && number.gtn(1)
-                    ? <Link to={`/explorer/hash/${parentHex}`}>{parentHex}</Link>
-                    : parentHex
-                }</td>
-              </tr>
-              <tr>
-                <td className='type'>extrinsicsRoot</td>
-                <td className='hash'>{u8aToHex(extrinsicsRoot)}</td>
-              </tr>
-              <tr>
-                <td className='type'>stateRoot</td>
-                <td className='hash'>{u8aToHex(stateRoot)}</td>
-              </tr>
-              {withExtrinsics
-                ? <Extrinsics hash={hash} />
-                : undefined
-              }
-            </tbody>
-          </table>
         </div>
-      </div>
+      </article>
     );
   }
 }
-
-export default withApi(BlockHeader);

+ 10 - 9
packages/app-explorer/src/BlockHeaders.tsx

@@ -1,15 +1,16 @@
 // Copyright 2017-2018 @polkadot/app-explorer authors & contributors
 // This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
+// of the Apache-2.0 license. See the LICENSE file for details.
 
-import { Header } from '@polkadot/primitives/header';
+import { Header } from '@polkadot/types';
 
 import React from 'react';
-
-import withObservableDiv from '@polkadot/ui-react-rx/with/observableDiv';
+import { withObservableDiv } from '@polkadot/ui-react-rx/with/index';
 
 import BlockHeader from './BlockHeader';
 
+export const MAX_ITEMS = 15;
+
 let blockHeaders: Array<Header> = [];
 
 const apiOptions = {
@@ -20,7 +21,7 @@ const apiOptions = {
 
     blockHeaders = blockHeaders
       .filter((old, index) =>
-        index < 9 && old.number.lt(header.number)
+        index < MAX_ITEMS && old.blockNumber.lt(header.blockNumber)
       )
       .reduce((next, header) => {
         next.push(header);
@@ -28,20 +29,20 @@ const apiOptions = {
         return next;
       }, [header])
       .sort((a, b) =>
-        b.number.cmp(a.number)
+        b.blockNumber.cmp(a.blockNumber)
       );
 
     return blockHeaders;
   }
 };
 
-export default withObservableDiv('chainNewHead', apiOptions)(
+export default withObservableDiv('subscribeNewHead', apiOptions)(
   (value: Array<Header> = []) =>
     value.map((value) => (
       <BlockHeader
-        key={value.number.toString()}
+        key={value.blockNumber.toString()}
         value={value}
-        withLink
+        withLink={!value.blockNumber.isZero()}
       />
     )),
   { className: 'explorer--BlockHeaders' }

+ 112 - 0
packages/app-explorer/src/Events.tsx

@@ -0,0 +1,112 @@
+// Copyright 2017-2018 @polkadot/app-explorer authors & contributors
+// This software may be modified and distributed under the terms
+// of the Apache-2.0 license. See the LICENSE file for details.
+
+// Copyright 2017-2018 @polkadot/app-explorer authors & contributors
+// This software may be modified and distributed under the terms
+// of the Apache-2.0 license. See the LICENSE file for details.
+
+import { I18nProps } from '@polkadot/ui-app/types';
+
+import React from 'react';
+import { Event, EventRecord } from '@polkadot/types';
+import { Event as EventDisplay } from '@polkadot/ui-app/index';
+import { withMulti, withObservable } from '@polkadot/ui-react-rx/with';
+import { stringToU8a } from '@polkadot/util';
+import { xxhashAsHex } from '@polkadot/util-crypto';
+
+import { MAX_ITEMS } from './BlockHeaders';
+import translate from './translate';
+
+type Props = I18nProps & {
+  systemEvents?: Array<EventRecord>
+};
+
+type State = {
+  prevEventHash: string;
+  recentEvents: Array<Event>;
+};
+
+class EventsDisplay extends React.PureComponent<Props, State> {
+  constructor (props: Props) {
+    super(props);
+
+    this.state = {
+      prevEventHash: '',
+      recentEvents: []
+    };
+  }
+
+  static getDerivedStateFromProps ({ systemEvents = [] }: Props, prevState: State): State | null {
+    const prevEventHash = xxhashAsHex(stringToU8a(JSON.stringify(systemEvents)));
+
+    if (prevEventHash === prevState.prevEventHash) {
+      return null;
+    }
+
+    const recentEvents = systemEvents
+      .filter(({ event }) =>
+        event.section !== 'system'
+      )
+      .map(({ event }) =>
+        event
+      )
+      .concat(prevState.recentEvents)
+      .filter((_, index) =>
+        index < MAX_ITEMS
+      );
+
+    return {
+      prevEventHash,
+      recentEvents
+    };
+  }
+
+  render () {
+    const { t } = this.props;
+    const { recentEvents } = this.state;
+
+    if (recentEvents.length === 0) {
+      return (
+        <div>{t('events.none', {
+          defaultValue: 'no non-internal events available'
+        })}</div>
+      );
+    }
+
+    return (
+      <div>
+        {recentEvents.map(this.renderEvent)}
+      </div>
+    );
+  }
+
+  private renderEvent = (event: Event, index: number) => {
+    return (
+      <article
+        className='explorer--Container'
+        key={index}
+      >
+        <div className='header'>
+          <h3>
+            {event.section}.{event.method}
+          </h3>
+          <div className='description'>
+            {
+              event.meta.documentation && event.meta.documentation.length
+                ? event.meta.documentation.map((doc) => doc.toString()).join(' ')
+                : ''
+            }
+          </div>
+        </div>
+        <EventDisplay value={event} />
+      </article>
+    );
+  }
+}
+
+export default withMulti(
+  EventsDisplay,
+  translate,
+  withObservable('systemEvents')
+);

+ 27 - 7
packages/app-explorer/src/Main.tsx

@@ -1,25 +1,45 @@
 // Copyright 2017-2018 @polkadot/app-explorer authors & contributors
 // This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
+// of the Apache-2.0 license. See the LICENSE file for details.
 
-import { BareProps } from '@polkadot/ui-app/types';
+import { I18nProps } from '@polkadot/ui-app/types';
 
 import React from 'react';
 
 import BlockHeaders from './BlockHeaders';
+import Events from './Events';
 import Query from './Query';
 import Summary from './Summary';
+import translate from './translate';
 
-type Props = BareProps & {
-  basePath: string
-};
+type Props = I18nProps & {};
 
-export default class Main extends React.PureComponent<Props> {
+class Main extends React.PureComponent<Props> {
   render () {
+    const { t } = this.props;
+
     return [
       <Summary key='summary' />,
       <Query key='query' />,
-      <BlockHeaders key='headers' />
+      <div
+        className='explorer--Overview'
+        key='overview'
+      >
+        <div className='column'>
+          <h1>{t('main.recentBlocks', {
+            defaultValue: 'recent blocks'
+          })}</h1>
+          <BlockHeaders />
+        </div>
+        <div className='column'>
+          <h1>{t('main.recentEvents', {
+            defaultValue: 'recent events'
+          })}</h1>
+          <Events />
+        </div>
+      </div>
     ];
   }
 }
+
+export default translate(Main);

+ 6 - 14
packages/app-explorer/src/Query.tsx

@@ -1,20 +1,16 @@
 // Copyright 2017-2018 @polkadot/app-explorer authors & contributors
 // This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
+// of the Apache-2.0 license. See the LICENSE file for details.
 
 import { I18nProps } from '@polkadot/ui-app/types';
-import { ApiProps } from '@polkadot/ui-react-rx/types';
 
 import React from 'react';
-import Button from '@polkadot/ui-app/Button';
-import Input from '@polkadot/ui-app/Input';
-import Labelled from '@polkadot/ui-app/Labelled';
-import withApi from '@polkadot/ui-react-rx/with/api';
-import isHex from '@polkadot/util/is/hex';
+import { Button, Input, Labelled } from '@polkadot/ui-app/index';
+import { isHex } from '@polkadot/util';
 
 import translate from './translate';
 
-type Props = ApiProps & I18nProps & {};
+type Props = I18nProps & {};
 
 type State = {
   hash: string
@@ -28,13 +24,9 @@ class Query extends React.PureComponent<Props, State> {
   };
 
   render () {
-    const { apiMethods, t } = this.props;
+    const { t } = this.props;
     const { hash, isValid } = this.state;
 
-    if (!apiMethods.chain_getBlock) {
-      return null;
-    }
-
     return (
       <header>
         <div className='ui--row'>
@@ -76,4 +68,4 @@ class Query extends React.PureComponent<Props, State> {
   }
 }
 
-export default translate(withApi(Query));
+export default translate(Query);

+ 18 - 14
packages/app-explorer/src/Summary.tsx

@@ -1,14 +1,12 @@
 // Copyright 2017-2018 @polkadot/app-explorer authors & contributors
 // This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
+// of the Apache-2.0 license. See the LICENSE file for details.
 
 import { I18nProps } from '@polkadot/ui-app/types';
 
 import React from 'react';
-import CardSummary from '@polkadot/ui-app/CardSummary';
-import BestNumber from '@polkadot/ui-react-rx/BestNumber';
-import TimePeriod from '@polkadot/ui-react-rx/TimePeriod';
-import TimeNow from '@polkadot/ui-react-rx/TimeNow';
+import { CardSummary } from '@polkadot/ui-app/index';
+import { BestNumber, TimeNow, TimePeriod } from '@polkadot/ui-react-rx/index';
 
 import SummarySession from './SummarySession';
 import translate from './translate';
@@ -25,14 +23,18 @@ class Summary extends React.PureComponent<Props> {
         style={style}
       >
         <section>
-          <CardSummary label={t('summary.period', {
-            defaultValue: 'target time'
-          })}>
+          <CardSummary
+            label={t('summary.period', {
+              defaultValue: 'target time'
+            })}
+          >
             <TimePeriod />
           </CardSummary>
-          <CardSummary label={t('summary.now', {
-            defaultValue: 'last block'
-          })}>
+          <CardSummary
+            label={t('summary.now', {
+              defaultValue: 'last block'
+            })}
+          >
             <TimeNow />
           </CardSummary>
         </section>
@@ -40,9 +42,11 @@ class Summary extends React.PureComponent<Props> {
           <SummarySession />
         </section>
         <section>
-          <CardSummary label={t('summary.best', {
-            defaultValue: 'best'
-          })}>
+          <CardSummary
+            label={t('summary.best', {
+              defaultValue: 'best'
+            })}
+          >
             <BestNumber />
           </CardSummary>
         </section>

+ 35 - 36
packages/app-explorer/src/SummarySession.tsx

@@ -1,24 +1,24 @@
 // Copyright 2017-2018 @polkadot/app-explorer authors & contributors
 // This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
+// of the Apache-2.0 license. See the LICENSE file for details.
 
 import { I18nProps } from '@polkadot/ui-app/types';
 
-import BN from 'bn.js';
 import React from 'react';
-import CardSummary from '@polkadot/ui-app/CardSummary';
-import withObservable from '@polkadot/ui-react-rx/with/observable';
-import withMulti from '@polkadot/ui-react-rx/with/multi';
+import { BlockNumber } from '@polkadot/types';
+import { CardSummary } from '@polkadot/ui-app/index';
+import { withMulti, withObservable } from '@polkadot/ui-react-rx/with/index';
 
 import translate from './translate';
 
 type Props = I18nProps & {
-  eraBlockLength?: BN,
-  eraBlockProgress?: BN,
-  sessionBlockProgress?: BN,
-  sessionBrokenValue?: BN,
-  sessionBrokenPercentLate?: BN,
-  sessionLength?: BN,
+  eraBlockLength?: BlockNumber,
+  eraBlockProgress?: BlockNumber,
+  sessionBlockProgress?: BlockNumber,
+  // FIXME Replaced in poc-3
+  // sessionBrokenValue?: BN,
+  // sessionBrokenPercentLate?: BN,
+  sessionLength?: BlockNumber,
   withBroken?: boolean,
   withEra?: boolean,
   withSession?: boolean
@@ -28,33 +28,34 @@ class SummarySession extends React.PureComponent<Props> {
   render () {
     return [
       this.renderSession(),
-      this.renderEra(),
-      this.renderBroken()
+      this.renderEra()
+      // FIXME Replace with "reward"
+      // this.renderBroken()
     ];
   }
 
-  private renderBroken () {
-    const { sessionBrokenValue, sessionBrokenPercentLate, t, withBroken = true } = this.props;
+  // private renderBroken () {
+  //   const { sessionBrokenValue, sessionBrokenPercentLate, t, withBroken = true } = this.props;
 
-    if (!withBroken) {
-      return null;
-    }
+  //   if (!withBroken) {
+  //     return null;
+  //   }
 
-    return (
-      <CardSummary
-        key='brokenCount'
-        label={t('summary.brokenCount', {
-          defaultValue: 'lateness'
-        })}
-        progress={{
-          color: 'autoReverse',
-          isPercent: true,
-          total: sessionBrokenPercentLate,
-          value: sessionBrokenValue
-        }}
-      />
-    );
-  }
+  //   return (
+  //     <CardSummary
+  //       key='brokenCount'
+  //       label={t('summary.brokenCount', {
+  //         defaultValue: 'lateness'
+  //       })}
+  //       progress={{
+  //         color: 'autoReverse',
+  //         isPercent: true,
+  //         total: sessionBrokenPercentLate,
+  //         value: sessionBrokenValue
+  //       }}
+  //     />
+  //   );
+  // }
 
   private renderEra () {
     const { eraBlockLength, eraBlockProgress, t, withEra = true } = this.props;
@@ -105,7 +106,5 @@ export default withMulti(
   withObservable('eraBlockLength'),
   withObservable('eraBlockProgress'),
   withObservable('sessionBlockProgress'),
-  withObservable('sessionBrokenValue'),
-  withObservable('sessionLength'),
-  withObservable('sessionBrokenPercentLate')
+  withObservable('sessionLength')
 );

+ 30 - 12
packages/app-explorer/src/index.css

@@ -1,6 +1,6 @@
 /* Copyright 2017-2018 @polkadot/app-explorer authors & contributors
 /* This software may be modified and distributed under the terms
-/* of the ISC license. See the LICENSE file for details. */
+/* of the Apache-2.0 license. See the LICENSE file for details. */
 
 .explorer--App .rx--updated {
   background: transparent !important;
@@ -35,23 +35,30 @@
   flex-wrap: wrap;
 }
 
-.explorer--BlockByHash-extrinsic {
+.explorer--BlockByHash-block {
   flex: 0 0 50%;
   min-width: 0;
+  max-width: 50%;
 }
 
-.explorer--BlockByHash-extrinsic-header {
-  position: relative;
-  margin-bottom: 1rem;
-}
+.explorer--Container {
+  color: inherit;
 
-.explorer--BlockByHash-extrinsic-header-description {
-  color: rgba(0, 0, 0, 0.6);
-}
+  .header {
+    position: relative;
+
+    .description {
+      color: rgba(0, 0, 0, 0.6);
+      margin-bottom: 0.5rem;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      white-space: nowrap;
+    }
+  }
 
-.explorer--BlockByHash-extrinsic-header-name {
-  font-size: 1.2rem;
-  line-height: 1.2rem;
+  .value {
+    word-break: break-all;
+  }
 }
 
 .explorer--BlockByHash-accountIndex {
@@ -74,6 +81,17 @@
   right: 0rem;
 }
 
+.explorer--Overview {
+  display: flex;
+
+  .column {
+    flex: 0 0 50%;
+    min-width: 0;
+    max-width: 50%;
+    padding: 0 1em 1em;
+  }
+}
+
 .storage--Query-actionrow {
   display: flex;
 }

+ 4 - 2
packages/app-explorer/src/index.tsx

@@ -1,8 +1,9 @@
 // Copyright 2017-2018 @polkadot/app-explorer authors & contributors
 // This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
+// of the Apache-2.0 license. See the LICENSE file for details.
 
 import { BareProps } from '@polkadot/ui-app/types';
+import { ActionStatus } from '@polkadot/ui-app/Status/types';
 
 import './index.css';
 
@@ -13,7 +14,8 @@ import BlockByHash from './BlockByHash';
 import Main from './Main';
 
 type Props = BareProps & {
-  basePath: string
+  basePath: string,
+  onStatusChange: (status: ActionStatus) => void
 };
 
 export default class ExplorerApp extends React.Component<Props> {

+ 3 - 3
packages/app-explorer/src/translate.ts

@@ -1,7 +1,7 @@
 // Copyright 2017-2018 @polkadot/app-explorer authors & contributors
 // This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
+// of the Apache-2.0 license. See the LICENSE file for details.
 
-import { translate } from 'react-i18next';
+import { withNamespaces } from 'react-i18next';
 
-export default translate(['explorer', 'ui']);
+export default withNamespaces(['explorer', 'ui']);

+ 198 - 12
packages/app-extrinsics/LICENSE

@@ -1,15 +1,201 @@
-ISC License (ISC)
+                              Apache License
+                        Version 2.0, January 2004
+                    http://www.apache.org/licenses/
 
-Copyright 2017-2018 @polkadot/app-extrinsics authors & contributors
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
 
-Permission to use, copy, modify, and/or distribute this software for any
-purpose with or without fee is hereby granted, provided that the above
-copyright notice and this permission notice appear in all copies.
+1. Definitions.
 
-THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
-REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
-FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
-INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
-OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-PERFORMANCE OF THIS SOFTWARE.
+  "License" shall mean the terms and conditions for use, reproduction,
+  and distribution as defined by Sections 1 through 9 of this document.
+
+  "Licensor" shall mean the copyright owner or entity authorized by
+  the copyright owner that is granting the License.
+
+  "Legal Entity" shall mean the union of the acting entity and all
+  other entities that control, are controlled by, or are under common
+  control with that entity. For the purposes of this definition,
+  "control" means (i) the power, direct or indirect, to cause the
+  direction or management of such entity, whether by contract or
+  otherwise, or (ii) ownership of fifty percent (50%) or more of the
+  outstanding shares, or (iii) beneficial ownership of such entity.
+
+  "You" (or "Your") shall mean an individual or Legal Entity
+  exercising permissions granted by this License.
+
+  "Source" form shall mean the preferred form for making modifications,
+  including but not limited to software source code, documentation
+  source, and configuration files.
+
+  "Object" form shall mean any form resulting from mechanical
+  transformation or translation of a Source form, including but
+  not limited to compiled object code, generated documentation,
+  and conversions to other media types.
+
+  "Work" shall mean the work of authorship, whether in Source or
+  Object form, made available under the License, as indicated by a
+  copyright notice that is included in or attached to the work
+  (an example is provided in the Appendix below).
+
+  "Derivative Works" shall mean any work, whether in Source or Object
+  form, that is based on (or derived from) the Work and for which the
+  editorial revisions, annotations, elaborations, or other modifications
+  represent, as a whole, an original work of authorship. For the purposes
+  of this License, Derivative Works shall not include works that remain
+  separable from, or merely link (or bind by name) to the interfaces of,
+  the Work and Derivative Works thereof.
+
+  "Contribution" shall mean any work of authorship, including
+  the original version of the Work and any modifications or additions
+  to that Work or Derivative Works thereof, that is intentionally
+  submitted to Licensor for inclusion in the Work by the copyright owner
+  or by an individual or Legal Entity authorized to submit on behalf of
+  the copyright owner. For the purposes of this definition, "submitted"
+  means any form of electronic, verbal, or written communication sent
+  to the Licensor or its representatives, including but not limited to
+  communication on electronic mailing lists, source code control systems,
+  and issue tracking systems that are managed by, or on behalf of, the
+  Licensor for the purpose of discussing and improving the Work, but
+  excluding communication that is conspicuously marked or otherwise
+  designated in writing by the copyright owner as "Not a Contribution."
+
+  "Contributor" shall mean Licensor and any individual or Legal Entity
+  on behalf of whom a Contribution has been received by Licensor and
+  subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+  this License, each Contributor hereby grants to You a perpetual,
+  worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+  copyright license to reproduce, prepare Derivative Works of,
+  publicly display, publicly perform, sublicense, and distribute the
+  Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+  this License, each Contributor hereby grants to You a perpetual,
+  worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+  (except as stated in this section) patent license to make, have made,
+  use, offer to sell, sell, import, and otherwise transfer the Work,
+  where such license applies only to those patent claims licensable
+  by such Contributor that are necessarily infringed by their
+  Contribution(s) alone or by combination of their Contribution(s)
+  with the Work to which such Contribution(s) was submitted. If You
+  institute patent litigation against any entity (including a
+  cross-claim or counterclaim in a lawsuit) alleging that the Work
+  or a Contribution incorporated within the Work constitutes direct
+  or contributory patent infringement, then any patent licenses
+  granted to You under this License for that Work shall terminate
+  as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+  Work or Derivative Works thereof in any medium, with or without
+  modifications, and in Source or Object form, provided that You
+  meet the following conditions:
+
+  (a) You must give any other recipients of the Work or
+      Derivative Works a copy of this License; and
+
+  (b) You must cause any modified files to carry prominent notices
+      stating that You changed the files; and
+
+  (c) You must retain, in the Source form of any Derivative Works
+      that You distribute, all copyright, patent, trademark, and
+      attribution notices from the Source form of the Work,
+      excluding those notices that do not pertain to any part of
+      the Derivative Works; and
+
+  (d) If the Work includes a "NOTICE" text file as part of its
+      distribution, then any Derivative Works that You distribute must
+      include a readable copy of the attribution notices contained
+      within such NOTICE file, excluding those notices that do not
+      pertain to any part of the Derivative Works, in at least one
+      of the following places: within a NOTICE text file distributed
+      as part of the Derivative Works; within the Source form or
+      documentation, if provided along with the Derivative Works; or,
+      within a display generated by the Derivative Works, if and
+      wherever such third-party notices normally appear. The contents
+      of the NOTICE file are for informational purposes only and
+      do not modify the License. You may add Your own attribution
+      notices within Derivative Works that You distribute, alongside
+      or as an addendum to the NOTICE text from the Work, provided
+      that such additional attribution notices cannot be construed
+      as modifying the License.
+
+  You may add Your own copyright statement to Your modifications and
+  may provide additional or different license terms and conditions
+  for use, reproduction, or distribution of Your modifications, or
+  for any such Derivative Works as a whole, provided Your use,
+  reproduction, and distribution of the Work otherwise complies with
+  the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+  any Contribution intentionally submitted for inclusion in the Work
+  by You to the Licensor shall be under the terms and conditions of
+  this License, without any additional terms or conditions.
+  Notwithstanding the above, nothing herein shall supersede or modify
+  the terms of any separate license agreement you may have executed
+  with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+  names, trademarks, service marks, or product names of the Licensor,
+  except as required for reasonable and customary use in describing the
+  origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+  agreed to in writing, Licensor provides the Work (and each
+  Contributor provides its Contributions) on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+  implied, including, without limitation, any warranties or conditions
+  of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+  PARTICULAR PURPOSE. You are solely responsible for determining the
+  appropriateness of using or redistributing the Work and assume any
+  risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+  whether in tort (including negligence), contract, or otherwise,
+  unless required by applicable law (such as deliberate and grossly
+  negligent acts) or agreed to in writing, shall any Contributor be
+  liable to You for damages, including any direct, indirect, special,
+  incidental, or consequential damages of any character arising as a
+  result of this License or out of the use or inability to use the
+  Work (including but not limited to damages for loss of goodwill,
+  work stoppage, computer failure or malfunction, or any and all
+  other commercial damages or losses), even if such Contributor
+  has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+  the Work or Derivative Works thereof, You may choose to offer,
+  and charge a fee for, acceptance of support, warranty, indemnity,
+  or other liability obligations and/or rights consistent with this
+  License. However, in accepting such obligations, You may act only
+  on Your own behalf and on Your sole responsibility, not on behalf
+  of any other Contributor, and only if You agree to indemnify,
+  defend, and hold each Contributor harmless for any liability
+  incurred by, or claims asserted against, such Contributor by reason
+  of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+  To apply the Apache License to your work, attach the following
+  boilerplate notice, with the fields enclosed by brackets "[]"
+  replaced with your own identifying information. (Don't include
+  the brackets!)  The text should be enclosed in the appropriate
+  comment syntax for the file format. We also recommend that a
+  file or class name and description of purpose be included on the
+  same "printed page" as the copyright notice for easier
+  identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.

+ 6 - 6
packages/app-extrinsics/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@polkadot/app-extrinsics",
-  "version": "0.20.30",
+  "version": "0.21.0",
   "main": "index.js",
   "repository": "https://github.com/polkadot-js/apps.git",
   "author": "Jaco Greeff <jacogr@gmail.com>",
@@ -8,11 +8,11 @@
     "Jaco Greeff <jacogr@gmail.com>"
   ],
   "contributors": [],
-  "license": "ISC",
+  "license": "Apache-2.0",
   "dependencies": {
-    "@babel/runtime": "^7.0.0",
-    "@polkadot/extrinsics": "^0.29.7",
-    "@polkadot/ui-app": "^0.20.30",
-    "@polkadot/ui-signer": "^0.20.30"
+    "@babel/runtime": "^7.2.0",
+    "@polkadot/types": "^0.35.9",
+    "@polkadot/ui-app": "^0.21.0",
+    "@polkadot/ui-signer": "^0.21.0"
   }
 }

+ 16 - 16
packages/app-extrinsics/src/Account.tsx

@@ -1,31 +1,29 @@
 // Copyright 2017-2018 @polkadot/app-extrinsics authors & contributors
 // This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
+// of the Apache-2.0 license. See the LICENSE file for details.
 
 import { KeyringOption$Type } from '@polkadot/ui-keyring/options/types';
 import { I18nProps } from '@polkadot/ui-app/types';
 
 import React from 'react';
-
-import InputAddress from '@polkadot/ui-app/InputAddress';
-import Labelled from '@polkadot/ui-app/Labelled';
-import Balance from '@polkadot/ui-react-rx/Balance';
+import { InputAddress, Labelled } from '@polkadot/ui-app/index';
+import { Balance } from '@polkadot/ui-react-rx/index';
 
 import translate from './translate';
 
 type Props = I18nProps & {
-  defaultValue?: Uint8Array,
+  defaultValue?: string,
   isDisabled?: boolean,
   isError?: boolean,
   isInput?: boolean,
   label: string,
-  onChange?: (publicKey: Uint8Array) => void,
+  onChange?: (accountId: string) => void,
   type?: KeyringOption$Type,
   withLabel?: boolean
 };
 
 type State = {
-  publicKey?: Uint8Array
+  accountId?: string
 };
 
 class Account extends React.PureComponent<Props, State> {
@@ -35,7 +33,7 @@ class Account extends React.PureComponent<Props, State> {
     super(props);
 
     this.state = {
-      publicKey: props.defaultValue
+      accountId: props.defaultValue
     };
   }
 
@@ -64,9 +62,9 @@ class Account extends React.PureComponent<Props, State> {
 
   private renderBalance (): React.ReactNode {
     const { t, withLabel } = this.props;
-    const { publicKey } = this.state;
+    const { accountId } = this.state;
 
-    if (!publicKey) {
+    if (!accountId) {
       return null;
     }
 
@@ -80,18 +78,20 @@ class Account extends React.PureComponent<Props, State> {
       >
         <Balance
           className='ui disabled dropdown selection'
-          params={publicKey}
+          params={accountId}
         />
       </Labelled>
     );
   }
 
-  private onChange = (publicKey: Uint8Array): void => {
+  private onChange = (accountId: string): void => {
     const { onChange } = this.props;
 
-    this.setState({ publicKey }, () =>
-      onChange && onChange(publicKey)
-    );
+    if (accountId) {
+      this.setState({ accountId }, () => {
+        onChange && onChange(accountId);
+      });
+    }
   }
 }
 

+ 56 - 38
packages/app-extrinsics/src/Extrinsic.tsx

@@ -1,55 +1,55 @@
 // Copyright 2017-2018 @polkadot/app-extrinsics authors & contributors
 // This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
+// of the Apache-2.0 license. See the LICENSE file for details.
 
-import { SectionItem } from '@polkadot/params/types';
-import { Extrinsics } from '@polkadot/extrinsics/types';
+import { MethodFunction } from '@polkadot/types/Method';
 import { BareProps } from '@polkadot/ui-app/types';
 import { ApiProps } from '@polkadot/ui-react-rx/types';
 import { RawParam } from '@polkadot/ui-app/Params/types';
-import { EncodedMessage } from '@polkadot/ui-signer/types';
 
 import React from 'react';
+import { TypeDef, getTypeDef } from '@polkadot/types/codec';
+import { Method } from '@polkadot/types';
 
-import encode from '@polkadot/extrinsics/codec/encode/extrinsic';
-import InputExtrinsic from '@polkadot/ui-app/InputExtrinsic';
-import Params from '@polkadot/ui-app/Params';
-import isUndefined from '@polkadot/util/is/undefined';
-import withApi from '@polkadot/ui-react-rx/with/api';
+import { InputExtrinsic, Params } from '@polkadot/ui-app/index';
+import { isUndefined } from '@polkadot/util';
+import { withApi } from '@polkadot/ui-react-rx/with/index';
 
 import paramComponents from './Params';
 
 type Props = BareProps & ApiProps & {
-  defaultValue: SectionItem<Extrinsics>,
+  defaultValue: MethodFunction,
   isDisabled?: boolean,
   isError?: boolean,
   isPrivate?: boolean,
   labelMethod?: string,
   labelSection?: string,
-  onChange: (encoded: EncodedMessage) => void,
+  onChange: (method?: Method) => void,
   withLabel?: boolean
 };
 
 type State = {
-  extrinsic: SectionItem<Extrinsics>,
+  methodfn: MethodFunction,
+  params: Array<{ name: string, type: TypeDef }>,
   values: Array<RawParam>
 };
 
-class Extrinsic extends React.PureComponent<Props, State> {
+class ExtrinsicDisplay extends React.PureComponent<Props, State> {
   state: State;
 
   constructor (props: Props) {
     super(props);
 
     this.state = {
-      extrinsic: props.defaultValue,
+      methodfn: props.defaultValue,
+      params: this.getParams(props.defaultValue),
       values: []
     };
   }
 
   render () {
     const { defaultValue, isDisabled, isError, isPrivate, labelMethod, labelSection, withLabel } = this.props;
-    const { extrinsic } = this.state;
+    const { params } = this.state;
 
     return (
       <div className='extrinsics--Extrinsic'>
@@ -60,47 +60,65 @@ class Extrinsic extends React.PureComponent<Props, State> {
           isPrivate={isPrivate}
           labelMethod={labelMethod}
           labelSection={labelSection}
-          onChange={this.onChangeExtrinsic}
+          onChange={this.onChangeMethod}
           withLabel={withLabel}
         />
         <Params
-          item={extrinsic}
           onChange={this.onChangeValues}
           overrides={paramComponents}
+          params={params}
         />
       </div>
     );
   }
 
-  nextState (newState: State): void {
+  private nextState (newState: State): void {
     this.setState(newState, () => {
-      const { apiSupport, onChange } = this.props;
-      const { extrinsic, values } = this.state;
-      const params = Object.values(extrinsic.params);
-      const isValid = values.length === params.length &&
-        params.reduce((isValid, param, index) =>
+      const { onChange } = this.props;
+      const { methodfn, params, values } = this.state;
+
+      const isValid = values.reduce((isValid, value) =>
           isValid &&
-          !isUndefined(values[index]) &&
-          !isUndefined(values[index].value) &&
-          values[index].isValid, true);
-      const value = isValid && extrinsic.params
-        ? encode(extrinsic, values.map((p) => p.value), apiSupport)
-        : new Uint8Array([]);
-
-      onChange({
-        isValid,
-        values: [value]
-      });
+          !isUndefined(value) &&
+          !isUndefined(value.value) &&
+          value.isValid, params.length === values.length);
+
+      let method;
+
+      if (isValid) {
+        try {
+          method = methodfn(
+            ...values.map(({ value }) =>
+              value
+            )
+          );
+        } catch (error) {
+          // swallow
+        }
+      }
+
+      onChange(method);
     });
   }
 
-  onChangeExtrinsic = (extrinsic: SectionItem<Extrinsics>): void => {
-    this.nextState({ extrinsic, values: [] } as State);
+  private onChangeMethod = (methodfn: MethodFunction): void => {
+    this.nextState({
+      methodfn,
+      params: this.getParams(methodfn),
+      values: []
+    });
   }
 
-  onChangeValues = (values: Array<RawParam>): void => {
+  private onChangeValues = (values: Array<RawParam>): void => {
     this.nextState({ values } as State);
   }
+
+  private getParams (methodfn: MethodFunction): Array<{ name: string, type: TypeDef }> {
+    return Method.filterOrigin(methodfn.meta).map((arg) => ({
+      name: arg.name.toString(),
+      type: getTypeDef(arg.type)
+    }));
+  }
 }
 
-export default withApi(Extrinsic);
+export default withApi(ExtrinsicDisplay);

+ 3 - 4
packages/app-extrinsics/src/Nonce.tsx

@@ -1,19 +1,18 @@
 // Copyright 2017-2018 @polkadot/app-extrinsics authors & contributors
 // This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
+// of the Apache-2.0 license. See the LICENSE file for details.
 
 import BN from 'bn.js';
 import { BareProps } from '@polkadot/ui-app/types';
 
 import React from 'react';
-
-import Labelled from '@polkadot/ui-app/Labelled';
+import { Labelled } from '@polkadot/ui-app/index';
 import RxNonce from '@polkadot/ui-react-rx/Nonce';
 
 type Props = BareProps & {
   label: string,
   rxChange: (value: BN) => void,
-  value?: Uint8Array
+  value?: string
 };
 
 export default class Nonce extends React.PureComponent<Props> {

+ 16 - 5
packages/app-extrinsics/src/Params/Account.tsx

@@ -1,17 +1,18 @@
 // Copyright 2017-2018 @polkadot/app-extrinsics authors & contributors
 // This software may be modified and distributed under the terms
-// of the ISC license. See the LICENSE file for details.
+// of the Apache-2.0 license. See the LICENSE file for details.
 
 import { Props } from '@polkadot/ui-app/Params/types';
 
 import React from 'react';
+import { decodeAddress } from '@polkadot/keyring';
 
 import BaseAccount from '../Account';
 
 export default class Account extends React.PureComponent<Props> {
   render () {
     const { className, defaultValue: { value }, isDisabled, isError, label, style, withLabel } = this.props;
-    const defaultValue = (value as Uint8Array);
+    const defaultValue = (value as string);
 
     return (
       <BaseAccount
@@ -28,12 +29,22 @@ export default class Account extends React.PureComponent<Props> {
     );
   }
 
-  onChange = (publicKey?: Uint8Array): void => {
+  onChange = (value: string): void => {
     const { onChange } = this.props;
 
+    let isValid = false;
+
+    try {
+      decodeAddress(value);
+
+      isValid = true;
+    } catch (err) {
+      console.error(err);
+    }
+
     onChange && onChange({
-      isValid: !!publicKey && publicKey.length === 32,
-      value: publicKey
+      isValid,
+      value
     });
   }
 }

Some files were not shown because too many files changed in this diff