diff --git a/.codeclimate.yml b/.codeclimate.yml index 9d3a27c156..534a13e57f 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -1,3 +1,3 @@ exclude_patterns: - "**/*.spec.js" -- "**/flow-typed/*" +- "**/*.spec.ts" diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 8fcb34f2be..0000000000 --- a/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -**/build/* -**/node_modules/* diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index fbdde8630f..0000000000 --- a/.eslintrc.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "extends": [ - "./node_modules/@polkadot/dev-react/config/eslint.js" - ] -} diff --git a/.nvmrc b/.nvmrc index 4149c39eec..db24ab967f 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -10.1.0 +10.13.0 diff --git a/.stylelintrc.json b/.stylelintrc.json deleted file mode 100644 index 8477594ade..0000000000 --- a/.stylelintrc.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "@polkadot/dev-react/config/stylelint" -} diff --git a/.travis.yml b/.travis.yml index 3fca86022f..4f34e1741d 100644 --- a/.travis.yml +++ b/.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: diff --git a/LICENSE b/LICENSE index 3d150a620a..0d381b2e97 100644 --- a/LICENSE +++ b/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 +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. diff --git a/README.md b/README.md index 57aa48dc29..5724089bdc 100644 --- a/README.md +++ b/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 ` 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 ` -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:` 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 . diff --git a/examples/README.md b/examples/README.md deleted file mode 100644 index e2e794c764..0000000000 --- a/examples/README.md +++ /dev/null @@ -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) diff --git a/examples/final.png b/examples/final.png deleted file mode 100644 index bada7df514..0000000000 Binary files a/examples/final.png and /dev/null differ diff --git a/examples/tut-001.md b/examples/tut-001.md deleted file mode 100644 index 5e0786d77c..0000000000 --- a/examples/tut-001.md +++ /dev/null @@ -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 { - render () { - return ( -
hello world
- ); - } -} -``` - -(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) diff --git a/examples/tut-002.md b/examples/tut-002.md deleted file mode 100644 index 2f5730b6f9..0000000000 --- a/examples/tut-002.md +++ /dev/null @@ -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 = 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 { - render () { - return ( - - ); - } -} -``` - -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.
.public.`. 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 = 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. diff --git a/examples/tut-003.md b/examples/tut-003.md deleted file mode 100644 index 24d10a1c64..0000000000 --- a/examples/tut-003.md +++ /dev/null @@ -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 { - ... - // TODO We should unsubscribe from subscriptions - componentDidMount () { - this.subscribeProposals(); - } - - subscribeProposals () { - const { api } = this.props; - - api.state - .getStorage(storage.democracy.public.proposals) - .subscribe((value: Array) => { - 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). diff --git a/examples/tut-004.md b/examples/tut-004.md deleted file mode 100644 index 8d3cab09bb..0000000000 --- a/examples/tut-004.md +++ /dev/null @@ -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 { - ... - 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. diff --git a/examples/tut-005.md b/examples/tut-005.md deleted file mode 100644 index c74c11c492..0000000000 --- a/examples/tut-005.md +++ /dev/null @@ -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 { - ... - render () { - const { intentions, proposals } = this.state; - - return ( - - - - - - - - - - {intentions.map((address) => ( - this.renderAccount(address, proposals[address]) - ))} - -
- AddressBalanceProposals
- ); - } - - renderAccount = (address: string, proposals: number[] = []) => { - return ( - - - {address} - - {proposals.length} - - ); - } -} -``` - -# 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. diff --git a/examples/tut-005.png b/examples/tut-005.png deleted file mode 100644 index 6c9f606483..0000000000 Binary files a/examples/tut-005.png and /dev/null differ diff --git a/examples/tut-006.md b/examples/tut-006.md deleted file mode 100644 index e87d1ad946..0000000000 --- a/examples/tut-006.md +++ /dev/null @@ -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 { - ... - 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 ( - - ... - ); - } -} -``` - -# 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. diff --git a/examples/tut-006.png b/examples/tut-006.png deleted file mode 100644 index fa51651ddb..0000000000 Binary files a/examples/tut-006.png and /dev/null differ diff --git a/examples/tut-007.md b/examples/tut-007.md deleted file mode 100644 index ccca67e357..0000000000 --- a/examples/tut-007.md +++ /dev/null @@ -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 `` 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 { - ... - 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) diff --git a/examples/tut-007.png b/examples/tut-007.png deleted file mode 100644 index bada7df514..0000000000 Binary files a/examples/tut-007.png and /dev/null differ diff --git a/jest.config.js b/jest.config.js index 0cafb2c034..9fc3bdb403 100644 --- a/jest.config.js +++ b/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)(.*)$': '/packages/ui-$1/src/$2', - '@polkadot/ui-(app|identicon|keyring|react-rx|react|signer)(.*)$': '/packages/ui-$1/src/$2', + '@polkadot/app-(accounts|addresses|democracy|explorer|extrinsics|rpc|settings|staking|storage|toolbox|transfer|vanitygen)(.*)$': '/packages/app-$1/src/$2', + '@polkadot/ui-(app|react-rx|signer)(.*)$': '/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)' - ] + } }); diff --git a/lerna.json b/lerna.json index fd7f929ef3..7fc530bb6d 100644 --- a/lerna.json +++ b/lerna.json @@ -10,5 +10,5 @@ "packages": [ "packages/*" ], - "version": "0.20.30" + "version": "0.21.0" } diff --git a/package.json b/package.json index ef27e2506a..58272963a0 100644 --- a/package.json +++ b/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" } } diff --git a/packages/app-accounts/LICENSE b/packages/app-accounts/LICENSE index a3778e3bf6..0d381b2e97 100644 --- a/packages/app-accounts/LICENSE +++ b/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. diff --git a/packages/app-accounts/package.json b/packages/app-accounts/package.json index 5dc6da27de..d225ccd680 100644 --- a/packages/app-accounts/package.json +++ b/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 ", @@ -8,11 +8,11 @@ "Jaco Greeff " ], "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" } } diff --git a/packages/app-accounts/src/Backup.tsx b/packages/app-accounts/src/Backup.tsx index e9ed3bc281..15a5553a8f 100644 --- a/packages/app-accounts/src/Backup.tsx +++ b/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 { render () { return ( {this.renderContent()} {this.renderButtons()} @@ -87,11 +88,11 @@ class Backup extends React.PureComponent { defaultValue: 'Backup account' })} , - - + +
{ } 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 }); } diff --git a/packages/app-accounts/src/ChangePass.tsx b/packages/app-accounts/src/ChangePass.tsx index e8cad23892..8adedddac3 100644 --- a/packages/app-accounts/src/ChangePass.tsx +++ b/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 { render () { return ( { })} , - +
{ } 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 { 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 { } private validatePass (password: string): boolean { - return password.length > 0 && password.length <= 32; + return keyring.isPassValid(password); } } diff --git a/packages/app-accounts/src/Creator.tsx b/packages/app-accounts/src/Creator.tsx index c92e3f715d..6cf726acec 100644 --- a/packages/app-accounts/src/Creator.tsx +++ b/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 { hexToU8a, isHex, stringToU8a, u8aToHex } from '@polkadot/util'; +import { mnemonicToSeed, mnemonicValidate, naclKeypairFromSeed, randomAsU8a } from '@polkadot/util-crypto'; +import keyring from '@polkadot/ui-keyring'; -import AddressSummary from '@polkadot/ui-app/AddressSummary'; 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 { - 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 { 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 (
-
-
- { value={name} />
+
+ + + +
{ />
{this.renderModalContent()} {this.renderModalButtons()} @@ -176,7 +224,7 @@ class Creator extends React.PureComponent { isPrimary onClick={this.onCommit} text={t('seedWarning.continue', { - defaultValue: 'Continue' + defaultValue: 'Create and backup account' })} /> @@ -186,55 +234,89 @@ class Creator extends React.PureComponent { renderModalContent () { const { t } = this.props; + const { address } = this.state; return [ {t('seedWarning.header', { - defaultValue: 'Warning' + defaultValue: 'Important notice!' })} , {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.' })} + + {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.' + })} + + ]; } - 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 { 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); diff --git a/packages/app-accounts/src/Editor.tsx b/packages/app-accounts/src/Editor.tsx index 2c76956224..ed9bdc01a4 100644 --- a/packages/app-accounts/src/Editor.tsx +++ b/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, - onBack: () => void + allAccounts?: SubjectInfo, + onStatusChange: (status: ActionStatus) => void }; type State = { @@ -149,6 +148,7 @@ class Editor extends React.PureComponent { } renderModals () { + const { onStatusChange } = this.props; const { current, isBackupOpen, isForgetOpen, isPasswordOpen } = this.state; if (!current) { @@ -162,8 +162,9 @@ class Editor extends React.PureComponent { modals.push( ); } @@ -171,10 +172,10 @@ class Editor extends React.PureComponent { if (isForgetOpen) { modals.push( ); } @@ -185,6 +186,7 @@ class Editor extends React.PureComponent { account={current} key='modal-change-pass' onClose={this.togglePass} + onStatusChange={onStatusChange} /> ); } @@ -234,10 +236,10 @@ class Editor extends React.PureComponent { ); } - 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 { } 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 { } onForget = (): void => { + const { onStatusChange, t } = this.props; const { current } = this.state; if (!current) { @@ -318,9 +339,25 @@ class Editor extends React.PureComponent { 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); } ); } diff --git a/packages/app-accounts/src/Forgetting.tsx b/packages/app-accounts/src/Forgetting.tsx index fac011ca87..7519cbe95d 100644 --- a/packages/app-accounts/src/Forgetting.tsx +++ b/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 { })} , - + ]; } diff --git a/packages/app-accounts/src/Restore.tsx b/packages/app-accounts/src/Restore.tsx index 1b6496556d..cefcb5e45f 100644 --- a/packages/app-accounts/src/Restore.tsx +++ b/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 { super(props); this.state = { - json: null, isFileValid: false, isPassValid: false, + json: null, password: '' }; } @@ -77,14 +72,17 @@ class Restore extends React.PureComponent { ); } - renderInput () { + private renderInput () { const { t } = this.props; const { isFileValid, isPassValid, password } = this.state; + const acceptedFormats = ['application/json', 'text/plain'].join(', '); + return (
{
); } - 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 { 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; } - try { - const pair = createPair( - { - publicKey: decodeAddress(json.address), - secretKey: new Uint8Array() - }, - json.meta, - hexToU8a(json.encoded) - ); + const status = { + action: 'restore' + } as ActionStatus; - // unlock, save account and then lock (locking cleans secretKey, so needs to be last) - pair.decodePkcs8(password); - keyring.addAccountPair(pair, password); - pair.lock(); + try { + 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); } } diff --git a/packages/app-accounts/src/bipWorker.ts b/packages/app-accounts/src/bipWorker.ts new file mode 100644 index 0000000000..4aaaa98b33 --- /dev/null +++ b/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 + }); +}; diff --git a/packages/app-accounts/src/index.css b/packages/app-accounts/src/index.css index 11dcb164bb..fb89fa0d18 100644 --- a/packages/app-accounts/src/index.css +++ b/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; } diff --git a/packages/app-accounts/src/index.tsx b/packages/app-accounts/src/index.tsx index 3aef70fba9..6f3d30a0cf 100644 --- a/packages/app-accounts/src/index.tsx +++ b/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, items: Array }; -// FIXME React-router would probably be the best route, not home-grown const Components: { [index: string]: React.ComponentType } = { 'create': Creator, 'edit': Editor, @@ -96,6 +96,7 @@ class AccountsApp extends React.PureComponent { } render () { + const { onStatusChange } = this.props; const { action, hidden, items } = this.state; const Component = Components[action]; @@ -109,7 +110,11 @@ class AccountsApp extends React.PureComponent { onChange={this.onMenuChange} /> - + ); } @@ -123,6 +128,8 @@ class AccountsApp extends React.PureComponent { } } -export default withObservableBase( - accountObservable.subject, { propName: 'allAccounts' } -)(translate(AccountsApp)); +export default withMulti( + AccountsApp, + translate, + withObservableBase(accountObservable.subject, { propName: 'allAccounts' }) +); diff --git a/packages/app-accounts/src/translate.ts b/packages/app-accounts/src/translate.ts index 1a7bdfa204..bedf459ed3 100644 --- a/packages/app-accounts/src/translate.ts +++ b/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']); diff --git a/packages/app-accounts/src/worker-loader.d.ts b/packages/app-accounts/src/worker-loader.d.ts new file mode 100644 index 0000000000..cd9ad52616 --- /dev/null +++ b/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; +} diff --git a/packages/app-addresses/LICENSE b/packages/app-addresses/LICENSE index 1b71edeea4..0d381b2e97 100644 --- a/packages/app-addresses/LICENSE +++ b/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. diff --git a/packages/app-addresses/package.json b/packages/app-addresses/package.json index cbde6f0b93..386163c642 100644 --- a/packages/app-addresses/package.json +++ b/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 ", @@ -8,9 +8,9 @@ "Jaco Greeff " ], "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" } } diff --git a/packages/app-addresses/src/Creator.tsx b/packages/app-addresses/src/Creator.tsx index b515837d52..55955c3785 100644 --- a/packages/app-addresses/src/Creator.tsx +++ b/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 { 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 { } 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 => { diff --git a/packages/app-addresses/src/Editor.tsx b/packages/app-addresses/src/Editor.tsx index aad37f4bd8..1333498cbf 100644 --- a/packages/app-addresses/src/Editor.tsx +++ b/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 { ); } - 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 { 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 { } onForget = (): void => { + const { onStatusChange, t } = this.props; const { current } = this.state; if (!current) { @@ -227,9 +248,27 @@ class Editor extends React.PureComponent { 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); } ); } diff --git a/packages/app-addresses/src/Forgetting.tsx b/packages/app-addresses/src/Forgetting.tsx index 4e8457c851..4e82c55231 100644 --- a/packages/app-addresses/src/Forgetting.tsx +++ b/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'; diff --git a/packages/app-addresses/src/index.css b/packages/app-addresses/src/index.css index 9724257e32..d262c23656 100644 --- a/packages/app-addresses/src/index.css +++ b/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; diff --git a/packages/app-addresses/src/index.tsx b/packages/app-addresses/src/index.tsx index 1f9e97b3a3..c721221fb4 100644 --- a/packages/app-addresses/src/index.tsx +++ b/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 }; -// FIXME React-router would probably be the best route, not home-grown const Components: { [index: string]: React.ComponentType } = { 'create': Creator, 'edit': Editor @@ -91,6 +92,7 @@ class AddressesApp extends React.PureComponent { } render () { + const { onStatusChange } = this.props; const { action, hidden, items } = this.state; const Component = Components[action]; @@ -104,7 +106,10 @@ class AddressesApp extends React.PureComponent { onChange={this.onMenuChange} /> - + ); } @@ -120,6 +125,8 @@ class AddressesApp extends React.PureComponent { } } -export default withObservableBase( - addressObservable.subject, { propName: 'allAddresses' } -)(translate(AddressesApp)); +export default withMulti( + AddressesApp, + translate, + withObservableBase(addressObservable.subject, { propName: 'allAddresses' }) +); diff --git a/packages/app-addresses/src/translate.ts b/packages/app-addresses/src/translate.ts index a2f6a8db2b..3f1f311455 100644 --- a/packages/app-addresses/src/translate.ts +++ b/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']); diff --git a/packages/app-democracy/LICENSE b/packages/app-democracy/LICENSE index 3f30c1da65..0d381b2e97 100644 --- a/packages/app-democracy/LICENSE +++ b/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. diff --git a/packages/app-democracy/package.json b/packages/app-democracy/package.json index 1aa8c7fcf7..a9556f9924 100644 --- a/packages/app-democracy/package.json +++ b/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 " ], - "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" } } diff --git a/packages/app-democracy/src/Item.tsx b/packages/app-democracy/src/Item.tsx index 053b1d57a1..82ad770cc8 100644 --- a/packages/app-democracy/src/Item.tsx +++ b/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 { 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 (
-
- {proposal.extrinsic.section}.{proposal.extrinsic.name} -
-
- {proposal.extrinsic.description} -
+

+ {section}.{method} +

+
{ + meta && meta.documentation && meta.documentation.length + ? meta.documentation.map((doc) => doc.toString()).join(' ') + : '' + }
#{numberFormat(idNumber)}
- {proposalExtra} - +
{children}
diff --git a/packages/app-democracy/src/Proposal.tsx b/packages/app-democracy/src/Proposal.tsx index 61616d45d1..392899c04d 100644 --- a/packages/app-democracy/src/Proposal.tsx +++ b/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 { idNumber={idNumber} proposal={value.proposal} proposalExtra={this.renderExtra()} - > - {this.renderVoting()} - + /> ); } 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 (
- +
{addresses.map((address) => ( ))}
- - {numberFormat(balance)} + + {balanceFormat(balance)}
); } - - private renderVoting () { - return null; - } } export default withMulti( Proposal, translate, - withObservable('democracyProposalDeposits', { paramProp: 'idNumber' }) + withObservable('proposalDeposits', { paramProp: 'idNumber' }) ); diff --git a/packages/app-democracy/src/Proposals.tsx b/packages/app-democracy/src/Proposals.tsx index 77e6579b8f..44f9ff766a 100644 --- a/packages/app-democracy/src/Proposals.tsx +++ b/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 + publicProposals?: Array }; class Proposals extends React.PureComponent { @@ -31,9 +30,9 @@ class Proposals extends React.PureComponent { } private renderProposals () { - const { democracyProposals, t } = this.props; + const { publicProposals, t } = this.props; - if (!democracyProposals || !democracyProposals.length) { + if (!publicProposals || !publicProposals.length) { return (
{t('proposals.none', { @@ -43,7 +42,7 @@ class Proposals extends React.PureComponent { ); } - return democracyProposals.map((proposal) => ( + return publicProposals.map((proposal) => ( { export default withMulti( Proposals, translate, - withObservable('democracyProposals') + withObservable('publicProposals') ); diff --git a/packages/app-democracy/src/Referendum.tsx b/packages/app-democracy/src/Referendum.tsx index 67aa957042..a2c0b98037 100644 --- a/packages/app-democracy/src/Referendum.tsx +++ b/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, idNumber: BN, - value: RxReferendum + value: ReferendumInfo }; type State = { @@ -64,7 +64,7 @@ class Referendum extends React.PureComponent { } 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 { } render () { - const { idNumber, value } = this.props; + const { bestNumber, idNumber, value } = this.props; + + if (!bestNumber || value.end.sub(bestNumber).lten(0)) { + return null; + } return ( { } 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 (
- + {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)) } })}
); @@ -150,25 +155,28 @@ class Referendum extends React.PureComponent { return (
- +
); } } export default withMulti( - translate(Referendum), + Referendum, + translate, withObservable('bestNumber'), withObservable('democracyReferendumVoters', { paramProp: 'idNumber' }) ); diff --git a/packages/app-democracy/src/Referendums.tsx b/packages/app-democracy/src/Referendums.tsx index cbc4a16763..b0f339f4a2 100644 --- a/packages/app-democracy/src/Referendums.tsx +++ b/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 + democracyNextTally?: BN, + referendums?: Array, + referendumCount?: BN }; class Referendums extends React.PureComponent { @@ -31,9 +33,11 @@ class Referendums extends React.PureComponent { } 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 (
{t('proposals.none', { @@ -43,10 +47,10 @@ class Referendums extends React.PureComponent { ); } - return democracyReferendums.map((referendum) => ( + return referendums.map((referendum, index) => ( )); @@ -56,5 +60,7 @@ class Referendums extends React.PureComponent { export default withMulti( Referendums, translate, - withObservable('democracyReferendums') + withObservable('referendums'), + withObservable('referendumCount'), + withObservable('democracyNextTally') ); diff --git a/packages/app-democracy/src/Summary.tsx b/packages/app-democracy/src/Summary.tsx index cc2b9abcd2..704ab72f06 100644 --- a/packages/app-democracy/src/Summary.tsx +++ b/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 { 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 (
- - {numberFormat(democracyProposalCount)} + + {numberFormat(publicProposalCount)} - - {numberFormat(democracyReferendumCount)} + + {numberFormat(referendumCount)} - - {democracyNextTally && democracyReferendumCount - ? numberFormat(democracyReferendumCount.sub(democracyNextTally)) - : 0 - } + + {numberFormat(referendumCount.sub(democracyNextTally))}
- - {numberFormat(democracyVotingPeriod)} - - - {numberFormat(democracyLaunchPeriod)} - + +
); @@ -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') ); diff --git a/packages/app-democracy/src/Voting.tsx b/packages/app-democracy/src/Voting.tsx index 2cd77511ec..5b5a7b395d 100644 --- a/packages/app-democracy/src/Voting.tsx +++ b/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 { @@ -45,9 +45,9 @@ class Voting extends React.PureComponent { 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 { {({ queueExtrinsic }: QueueProps) => ( @@ -64,8 +64,8 @@ class Voting extends React.PureComponent { ); } - private onChangeAccount = (publicKey?: Uint8Array) => { - this.setState({ publicKey }); + private onChangeAccount = (accountId?: string) => { + this.setState({ accountId }); } } diff --git a/packages/app-democracy/src/VotingButtons.tsx b/packages/app-democracy/src/VotingButtons.tsx index 8b1a43e4fb..69c20cd3db 100644 --- a/packages/app-democracy/src/VotingButtons.tsx +++ b/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 { render () { - const { publicKey, t } = this.props; + const { accountId, t } = this.props; return (
); } } @@ -123,5 +145,5 @@ class BlockByHash extends React.PureComponent { export default withMulti( BlockByHash, translate, - withObservable('chainGetBlock', { paramProp: 'value' }) + withObservable('getBlock', { paramProp: 'value' }) ); diff --git a/packages/app-explorer/src/BlockByHash/Logs.tsx b/packages/app-explorer/src/BlockByHash/Logs.tsx new file mode 100644 index 0000000000..103084d96d --- /dev/null +++ b/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 +}; + +class Logs extends React.PureComponent { + render () { + const { t, value } = this.props; + + if (!value || !value.length) { + return null; + } + + return ( +
+

{t('block.logs', { + defaultValue: 'logs' + })}

+
+ {value.map(this.renderItem)} +
+
+ ); + } + + 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 = ( + + ); + } else if (item.value instanceof Vector) { + content = item.value.map((entry, index) => ( + {entry.toString()} + )); + } else { + content = item.value.toString().split(',').join(', '); + } + + return ( +
+
+
+

+ {item.type.toString()} +

+
+
+
+ {content} +
+
+
+ ); + } +} + +export default translate(Logs); diff --git a/packages/app-explorer/src/BlockByHash/index.tsx b/packages/app-explorer/src/BlockByHash/index.tsx index b4e2cd0977..3e541aaef9 100644 --- a/packages/app-explorer/src/BlockByHash/index.tsx +++ b/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'; diff --git a/packages/app-explorer/src/BlockHeader/BlockHash.tsx b/packages/app-explorer/src/BlockHeader/BlockHash.tsx new file mode 100644 index 0000000000..5138c8e89b --- /dev/null +++ b/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 { + render () { + const { getBlockHash, withLink } = this.props; + + if (!getBlockHash) { + return null; + } + + const hashHex = getBlockHash.toHex(); + + return ( + withLink + ? {hashHex} + : hashHex + ); + } +} + +export default withObservable('rawCall', { + params: [jsonrpc.chain.methods.getBlockHash], + paramProp: 'blockNumber', + propName: 'getBlockHash' +})(BlockHash); diff --git a/packages/app-explorer/src/BlockHeader/BlockHeader.css b/packages/app-explorer/src/BlockHeader/BlockHeader.css index 8792bf7d0a..7f4198a291 100644 --- a/packages/app-explorer/src/BlockHeader/BlockHeader.css +++ b/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; + } -.explorer--BlockHeader > .details > .contains td.type { - opacity: 0.75; - text-align: right; + .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; + + &.type { + opacity: 0.75; + text-align: right; + width: 10em; + } + } + } + } + } } diff --git a/packages/app-explorer/src/BlockHeader/Extrinsics.tsx b/packages/app-explorer/src/BlockHeader/Extrinsics.tsx index 220b57a1a8..518013546f 100644 --- a/packages/app-explorer/src/BlockHeader/Extrinsics.tsx +++ b/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 { 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 { {t('extrinsics.count', { defaultValue: '{{count}} in block', replace: { - count: chainGetBlock.extrinsics.length + count: getBlock.extrinsics.length } })} @@ -44,5 +42,5 @@ class Extrinsics extends React.PureComponent { export default withMulti( Extrinsics, translate, - withObservable('chainGetBlock', { paramProp: 'hash' }) + withObservable('getBlock', { paramProp: 'hash' }) ); diff --git a/packages/app-explorer/src/BlockHeader/index.tsx b/packages/app-explorer/src/BlockHeader/index.tsx index 91b7dc50f1..15df70622d 100644 --- a/packages/app-explorer/src/BlockHeader/index.tsx +++ b/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 { +export default class BlockHeader extends React.PureComponent { 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 ( -
-
-
{numberFormat(number)}
-
+
-
- {isLinkable && withLink - ? {hashHex} - : hashHex} - +
+
{numberFormat(blockNumber)} 
+
+ +
+
+
+
+
parentHash
+
{ + value.blockNumber.gtn(1) + ? {parentHex} + : parentHex + }
+
+
+
extrinsicsRoot
+
{extrinsicsRoot.toHex()}
+
+
+
stateRoot
+
{stateRoot.toHex()}
+
+ {withExtrinsics + ? + : undefined + }
- - - - - - - - - - - - - - - {withExtrinsics - ? - : undefined - } - -
parentHash{ - isLinkable && number.gtn(1) - ? {parentHex} - : parentHex - }
extrinsicsRoot{u8aToHex(extrinsicsRoot)}
stateRoot{u8aToHex(stateRoot)}
-
+
); } } - -export default withApi(BlockHeader); diff --git a/packages/app-explorer/src/BlockHeaders.tsx b/packages/app-explorer/src/BlockHeaders.tsx index 78e8e8c8bc..1b9baf913f 100644 --- a/packages/app-explorer/src/BlockHeaders.tsx +++ b/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
= []; 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
= []) => value.map((value) => ( )), { className: 'explorer--BlockHeaders' } diff --git a/packages/app-explorer/src/Events.tsx b/packages/app-explorer/src/Events.tsx new file mode 100644 index 0000000000..586a8d9631 --- /dev/null +++ b/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 +}; + +type State = { + prevEventHash: string; + recentEvents: Array; +}; + +class EventsDisplay extends React.PureComponent { + 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 ( +
{t('events.none', { + defaultValue: 'no non-internal events available' + })}
+ ); + } + + return ( +
+ {recentEvents.map(this.renderEvent)} +
+ ); + } + + private renderEvent = (event: Event, index: number) => { + return ( +
+
+

+ {event.section}.{event.method} +

+
+ { + event.meta.documentation && event.meta.documentation.length + ? event.meta.documentation.map((doc) => doc.toString()).join(' ') + : '' + } +
+
+ +
+ ); + } +} + +export default withMulti( + EventsDisplay, + translate, + withObservable('systemEvents') +); diff --git a/packages/app-explorer/src/Main.tsx b/packages/app-explorer/src/Main.tsx index 147b1f8d48..44889ced42 100644 --- a/packages/app-explorer/src/Main.tsx +++ b/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 { +class Main extends React.PureComponent { render () { + const { t } = this.props; + return [ , , - +
+
+

{t('main.recentBlocks', { + defaultValue: 'recent blocks' + })}

+ +
+
+

{t('main.recentEvents', { + defaultValue: 'recent events' + })}

+ +
+
]; } } + +export default translate(Main); diff --git a/packages/app-explorer/src/Query.tsx b/packages/app-explorer/src/Query.tsx index fc7d57bfa3..9486b4494b 100644 --- a/packages/app-explorer/src/Query.tsx +++ b/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 { }; render () { - const { apiMethods, t } = this.props; + const { t } = this.props; const { hash, isValid } = this.state; - if (!apiMethods.chain_getBlock) { - return null; - } - return (
@@ -76,4 +68,4 @@ class Query extends React.PureComponent { } } -export default translate(withApi(Query)); +export default translate(Query); diff --git a/packages/app-explorer/src/Summary.tsx b/packages/app-explorer/src/Summary.tsx index 5b9eae5988..1c9bc06a14 100644 --- a/packages/app-explorer/src/Summary.tsx +++ b/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 { style={style} >
- + - +
@@ -40,9 +42,11 @@ class Summary extends React.PureComponent {
- +
diff --git a/packages/app-explorer/src/SummarySession.tsx b/packages/app-explorer/src/SummarySession.tsx index 2565192da9..f5e71b8043 100644 --- a/packages/app-explorer/src/SummarySession.tsx +++ b/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 { 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 ( - - ); - } + // return ( + // + // ); + // } 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') ); diff --git a/packages/app-explorer/src/index.css b/packages/app-explorer/src/index.css index b026d35766..e3d9359bc0 100644 --- a/packages/app-explorer/src/index.css +++ b/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; -.explorer--BlockByHash-extrinsic-header-name { - font-size: 1.2rem; - line-height: 1.2rem; + .description { + color: rgba(0, 0, 0, 0.6); + margin-bottom: 0.5rem; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + } + + .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; } diff --git a/packages/app-explorer/src/index.tsx b/packages/app-explorer/src/index.tsx index 6938723d24..e56d607211 100644 --- a/packages/app-explorer/src/index.tsx +++ b/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 { diff --git a/packages/app-explorer/src/translate.ts b/packages/app-explorer/src/translate.ts index 09184a9971..7385cbaece 100644 --- a/packages/app-explorer/src/translate.ts +++ b/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']); diff --git a/packages/app-extrinsics/LICENSE b/packages/app-extrinsics/LICENSE index 208112d972..0d381b2e97 100644 --- a/packages/app-extrinsics/LICENSE +++ b/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. diff --git a/packages/app-extrinsics/package.json b/packages/app-extrinsics/package.json index c5cd42f52e..2509935aed 100644 --- a/packages/app-extrinsics/package.json +++ b/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 ", @@ -8,11 +8,11 @@ "Jaco Greeff " ], "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" } } diff --git a/packages/app-extrinsics/src/Account.tsx b/packages/app-extrinsics/src/Account.tsx index d4a71e4cc6..435f76066e 100644 --- a/packages/app-extrinsics/src/Account.tsx +++ b/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 { @@ -35,7 +33,7 @@ class Account extends React.PureComponent { super(props); this.state = { - publicKey: props.defaultValue + accountId: props.defaultValue }; } @@ -64,9 +62,9 @@ class Account extends React.PureComponent { 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 { > ); } - 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); + }); + } } } diff --git a/packages/app-extrinsics/src/Extrinsic.tsx b/packages/app-extrinsics/src/Extrinsic.tsx index 086f4e1ab4..07c6ccc627 100644 --- a/packages/app-extrinsics/src/Extrinsic.tsx +++ b/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, + 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, + methodfn: MethodFunction, + params: Array<{ name: string, type: TypeDef }>, values: Array }; -class Extrinsic extends React.PureComponent { +class ExtrinsicDisplay extends React.PureComponent { 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 (
@@ -60,47 +60,65 @@ class Extrinsic extends React.PureComponent { isPrivate={isPrivate} labelMethod={labelMethod} labelSection={labelSection} - onChange={this.onChangeExtrinsic} + onChange={this.onChangeMethod} withLabel={withLabel} />
); } - 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) => - 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([]); + const { onChange } = this.props; + const { methodfn, params, values } = this.state; - onChange({ - isValid, - values: [value] - }); + const isValid = values.reduce((isValid, value) => + isValid && + !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): void => { - this.nextState({ extrinsic, values: [] } as State); + private onChangeMethod = (methodfn: MethodFunction): void => { + this.nextState({ + methodfn, + params: this.getParams(methodfn), + values: [] + }); } - onChangeValues = (values: Array): void => { + private onChangeValues = (values: Array): 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); diff --git a/packages/app-extrinsics/src/Nonce.tsx b/packages/app-extrinsics/src/Nonce.tsx index ebf4c2aa2c..89e9fdb3c0 100644 --- a/packages/app-extrinsics/src/Nonce.tsx +++ b/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 { diff --git a/packages/app-extrinsics/src/Params/Account.tsx b/packages/app-extrinsics/src/Params/Account.tsx index 4f28faca12..5325860e43 100644 --- a/packages/app-extrinsics/src/Params/Account.tsx +++ b/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 { render () { const { className, defaultValue: { value }, isDisabled, isError, label, style, withLabel } = this.props; - const defaultValue = (value as Uint8Array); + const defaultValue = (value as string); return ( { ); } - 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 }); } } diff --git a/packages/app-extrinsics/src/Params/Call.tsx b/packages/app-extrinsics/src/Params/Call.tsx index b5092d635c..f3f8ed54ac 100644 --- a/packages/app-extrinsics/src/Params/Call.tsx +++ b/packages/app-extrinsics/src/Params/Call.tsx @@ -1,22 +1,19 @@ // 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 extrinsics from '@polkadot/extrinsics'; +import Api from '@polkadot/api-observable'; import Extrinsic from './Extrinsic'; -const defaultValue = extrinsics.staking.public.transfer; - export default function Call ({ className, isDisabled, isError, label, onChange, style, withLabel }: Props) { return ( , + defaultValue: MethodFunction, isDisabled?: boolean, isError?: boolean, isPrivate: boolean, @@ -23,7 +22,7 @@ type Props = I18nProps & { withLabel?: boolean }; -class Extrinsic extends React.PureComponent { +class ExtrinsicDisplay extends React.PureComponent { render () { const { className, defaultValue, isDisabled, isError, isPrivate, label, style, t, withLabel } = this.props; @@ -53,14 +52,14 @@ class Extrinsic extends React.PureComponent { ); } - onChange = ({ isValid, values }: EncodedMessage): void => { + onChange = (method: Method): void => { const { onChange } = this.props; onChange && onChange({ - isValid, - value: (values[0] as Uint8Array) + isValid: !!method, + value: method }); } } -export default translate(Extrinsic); +export default translate(ExtrinsicDisplay); diff --git a/packages/app-extrinsics/src/Params/Proposal.tsx b/packages/app-extrinsics/src/Params/Proposal.tsx index 6135eec6a9..023bc3ab75 100644 --- a/packages/app-extrinsics/src/Params/Proposal.tsx +++ b/packages/app-extrinsics/src/Params/Proposal.tsx @@ -1,29 +1,45 @@ // 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 { Props, RawParam } from '@polkadot/ui-app/Params/types'; import React from 'react'; +import Api from '@polkadot/api-observable'; +import { Proposal } from '@polkadot/types'; -import extrinsics from '@polkadot/extrinsics'; +import ExtrinsicDisplay from './Extrinsic'; -import Extrinsic from './Extrinsic'; +export default class ProposalDisplay extends React.PureComponent { + render () { + const { className, isDisabled, isError, label, style, withLabel } = this.props; -const defaultValue = extrinsics.consensus.private.setCode; + return ( + + ); + } -export default function Proposal ({ className, isDisabled, isError, label, onChange, style, withLabel }: Props) { - return ( - - ); + private onChange = ({ isValid, value }: RawParam) => { + const { onChange } = this.props; + let proposal = null; + + if (isValid && value) { + proposal = new Proposal(value); + } + + onChange && onChange({ + isValid, + value: proposal + }); + } } diff --git a/packages/app-extrinsics/src/Params/index.ts b/packages/app-extrinsics/src/Params/index.ts index 8bebb537a3..eb5da44e63 100644 --- a/packages/app-extrinsics/src/Params/index.ts +++ b/packages/app-extrinsics/src/Params/index.ts @@ -1,6 +1,6 @@ // 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 { ComponentMap } from '@polkadot/ui-app/Params/types'; diff --git a/packages/app-extrinsics/src/Selection.tsx b/packages/app-extrinsics/src/Selection.tsx index 2772fedf4c..fb56057b40 100644 --- a/packages/app-extrinsics/src/Selection.tsx +++ b/packages/app-extrinsics/src/Selection.tsx @@ -1,36 +1,33 @@ // 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 { I18nProps } from '@polkadot/ui-app/types'; -import { EncodedMessage, QueueTx$MessageAdd } from '@polkadot/ui-signer/types'; +import { QueueTx$ExtrinsicAdd, QueueTx$Unclog } from '@polkadot/ui-app/Status/types'; import React from 'react'; - -import extrinsics from '@polkadot/extrinsics'; -import rpc from '@polkadot/jsonrpc'; -import Button from '@polkadot/ui-app/Button'; +import Api from '@polkadot/api-observable'; +import { Extrinsic, Method } from '@polkadot/types'; +import { Button } from '@polkadot/ui-app/index'; import Account from './Account'; -import Extrinsic from './Extrinsic'; +import ExtrinsicDisplay from './Extrinsic'; import Nonce from './Nonce'; import translate from './translate'; type Props = I18nProps & { - queueAdd: QueueTx$MessageAdd + queueExtrinsic: QueueTx$ExtrinsicAdd, + queueUnclog: QueueTx$Unclog }; type State = { isValid: boolean, - encoded: EncodedMessage, - nonce: BN, - publicKey: Uint8Array + method: Method | null, + accountNonce: BN, + accountId: string }; -const defaultExtrinsic = extrinsics.staking.public.transfer; -const defaultRpc = rpc.author.public.submitExtrinsic; - class Selection extends React.PureComponent { state: State = { isValid: false @@ -38,7 +35,7 @@ class Selection extends React.PureComponent { render () { const { t } = this.props; - const { publicKey, isValid } = this.state; + const { isValid, accountId } = this.state; return (
@@ -50,19 +47,19 @@ class Selection extends React.PureComponent { onChange={this.onChangeSender} type='account' /> -
); } - - private balanceArray (address: string): Array | undefined { - const { balances } = this.props; - - return balances[address] - ? [balances[address].stakingBalance, balances[address].nominatedBalance] - : undefined; - } } export default translate(CurrentList); diff --git a/packages/app-staking/src/Overview/Summary.tsx b/packages/app-staking/src/Overview/Summary.tsx index adfaa5a38a..b67c758b57 100644 --- a/packages/app-staking/src/Overview/Summary.tsx +++ b/packages/app-staking/src/Overview/Summary.tsx @@ -1,17 +1,16 @@ // Copyright 2017-2018 @polkadot/app-staking 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 { RxBalance, RxBalanceMap } from '@polkadot/ui-react-rx/ApiObservable/types'; +import { RxBalance, RxBalanceMap } from '@polkadot/api-observable/types'; import BN from 'bn.js'; import React from 'react'; -import CardSummary from '@polkadot/ui-app/CardSummary'; -import numberFormat from '@polkadot/ui-react-rx/util/numberFormat'; +import { CardSummary } from '@polkadot/ui-app/index'; import SummarySession from '@polkadot/app-explorer/SummarySession'; -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 } from '@polkadot/ui-react-rx/util/index'; import translate from '../translate'; @@ -33,14 +32,18 @@ class Summary extends React.PureComponent { style={style} >
- + {validators.length}/{validatorCount ? validatorCount.toString() : '-'} - + {intentions.length}
@@ -48,9 +51,11 @@ class Summary extends React.PureComponent {
- + {this.renderBalances()}
@@ -62,6 +67,12 @@ class Summary extends React.PureComponent { const { t } = this.props; const intentionHigh = this.calcIntentionsHigh(); const validatorLow = this.calcValidatorLow(); + const nominatedLow = validatorLow && validatorLow.nominatedBalance.gtn(0) + ? `(+${balanceFormat(validatorLow.nominatedBalance)})` + : ''; + const nominatedHigh = intentionHigh && intentionHigh.nominatedBalance.gtn(0) + ? `(+${balanceFormat(intentionHigh.nominatedBalance)})` + : ''; return (
@@ -69,16 +80,16 @@ class Summary extends React.PureComponent { defaultValue: 'lowest validator {{validatorLow}}', replace: { validatorLow: validatorLow && validatorLow.stakingBalance - ? `${numberFormat(validatorLow.stakingBalance)} (+${numberFormat(validatorLow.nominatedBalance)})` - : 'unknown' + ? `${balanceFormat(validatorLow.stakingBalance)} ${nominatedLow}` + : '-' } })}
{t('summary.balance.stake', { defaultValue: 'highest intention {{intentionHigh}}', replace: { intentionHigh: intentionHigh - ? `${numberFormat(intentionHigh.stakingBalance)} (+${numberFormat(intentionHigh.nominatedBalance)})` - : 'unknown' + ? `${balanceFormat(intentionHigh.stakingBalance)} ${nominatedHigh}` + : '-' } })}
@@ -117,6 +128,7 @@ class Summary extends React.PureComponent { } export default withMulti( - translate(Summary), + Summary, + translate, withObservable('validatorCount') ); diff --git a/packages/app-staking/src/Overview/index.css b/packages/app-staking/src/Overview/index.css index e49f7d97cd..f300e1a3e8 100644 --- a/packages/app-staking/src/Overview/index.css +++ b/packages/app-staking/src/Overview/index.css @@ -1,6 +1,6 @@ /* Copyright 2017-2018 @polkadot/app-staking 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. */ .validator--Account-info-address { flex: 3; diff --git a/packages/app-staking/src/Overview/index.tsx b/packages/app-staking/src/Overview/index.tsx index d85c5d09c1..c6df7387a7 100644 --- a/packages/app-staking/src/Overview/index.tsx +++ b/packages/app-staking/src/Overview/index.tsx @@ -1,29 +1,30 @@ // Copyright 2017-2018 @polkadot/app-staking 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 { RxBalanceMap } from '@polkadot/ui-react-rx/ApiObservable/types'; +import { RxBalanceMap } from '@polkadot/api-observable/types'; import { I18nProps } from '@polkadot/ui-app/types'; import './index.css'; -import BN from 'bn.js'; import React from 'react'; +import { AccountId, Balance } from '@polkadot/types'; import CurrentList from './CurrentList'; import Summary from './Summary'; type Props = I18nProps & { balances: RxBalanceMap, + balanceArray: (_address: AccountId | string) => Array | undefined, intentions: Array, validators: Array }; -const ZERO = new BN(0); +const ZERO = new Balance(0); export default class Overview extends React.PureComponent { render () { - const { balances, intentions, validators } = this.props; + const { balances, balanceArray, intentions, validators } = this.props; const intentionsSorted = this.sortByBalance( intentions.filter((address) => !validators.includes(address) @@ -40,6 +41,7 @@ export default class Overview extends React.PureComponent { /> diff --git a/packages/app-staking/src/StakeList/Account.tsx b/packages/app-staking/src/StakeList/Account.tsx index 197ffd656e..93b1a81b5d 100644 --- a/packages/app-staking/src/StakeList/Account.tsx +++ b/packages/app-staking/src/StakeList/Account.tsx @@ -1,36 +1,29 @@ // Copyright 2017-2018 @polkadot/app-staking 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 { Extrinsics } from '@polkadot/extrinsics/types'; -import { SectionItem } from '@polkadot/params/types'; -import { RawParam$Value } from '@polkadot/ui-app/Params/types'; -import { QueueTx$ExtrinsicAdd } from '@polkadot/ui-signer/types'; -import { RxBalanceMap } from '@polkadot/ui-react-rx/ApiObservable/types'; +import { QueueTx$ExtrinsicAdd } from '@polkadot/ui-app/Status/types'; +import { RxBalanceMap } from '@polkadot/api-observable/types'; import BN from 'bn.js'; import React from 'react'; -import extrinsics from '@polkadot/extrinsics'; -import AddressMini from '@polkadot/ui-app/AddressMini'; -import AddressSummary from '@polkadot/ui-app/AddressSummary'; -import Button from '@polkadot/ui-app/Button'; -import Icon from '@polkadot/ui-app/Icon'; -import classes from '@polkadot/ui-app/util/classes'; -import withMulti from '@polkadot/ui-react-rx/with/multi'; -import withObservable from '@polkadot/ui-react-rx/with/observable'; -import decodeAddress from '@polkadot/util-keyring/address/decode'; +import Api from '@polkadot/api-observable'; +import { AccountId, Balance, Extrinsic, Method } from '@polkadot/types'; +import { AddressMini, AddressSummary, Button } from '@polkadot/ui-app/index'; +import { withMulti, withObservable } from '@polkadot/ui-react-rx/with/index'; import Nominating from './Nominating'; import UnnominateButton from './UnnominateButton'; import translate from '../translate'; type Props = I18nProps & { - systemAccountIndexOf?: BN, - address: string, + accountNonce?: BN, + accountId: string, balances: RxBalanceMap, + balanceArray: (_address: AccountId | string) => Array | undefined, name: string, - stakingNominating?: string, + stakingNominating?: AccountId, stakingNominatorsFor?: Array, intentions: Array, isValidator: boolean, @@ -52,16 +45,11 @@ class Account extends React.PureComponent { } render () { - const { address, intentions, isValidator, name } = this.props; + const { accountId, balanceArray, intentions, name } = this.props; const { isNominateOpen } = this.state; return (
- { intentions={intentions} />
@@ -84,16 +72,8 @@ class Account extends React.PureComponent { ); } - private balanceArray (address: string): Array | undefined { - const { balances } = this.props; - - return balances[address] - ? [balances[address].stakingBalance, balances[address].nominatedBalance] - : undefined; - } - private renderNominee () { - const { stakingNominating } = this.props; + const { stakingNominating, balanceArray } = this.props; if (!stakingNominating) { return null; @@ -101,7 +81,7 @@ class Account extends React.PureComponent { return ( @@ -130,8 +110,8 @@ class Account extends React.PureComponent { } private renderButtons () { - const { address, intentions, stakingNominating, t } = this.props; - const isIntending = intentions.includes(address); + const { accountId, intentions, stakingNominating, t } = this.props; + const isIntending = intentions.includes(accountId); const isNominating = !!stakingNominating; const canStake = !isIntending && !isNominating; @@ -161,7 +141,7 @@ class Account extends React.PureComponent { return ( @@ -182,15 +162,13 @@ class Account extends React.PureComponent { ); } - private send (extrinsic: SectionItem, values: Array) { - const { systemAccountIndexOf, address, queueExtrinsic } = this.props; - const publicKey = decodeAddress(address); + private send (method: Method) { + const { accountNonce, accountId, queueExtrinsic } = this.props; queueExtrinsic({ - extrinsic, - nonce: systemAccountIndexOf || new BN(0), - publicKey, - values + extrinsic: new Extrinsic({ method }), + accountNonce: accountNonce || new BN(0), + accountId }); } @@ -203,30 +181,30 @@ class Account extends React.PureComponent { } private nominate = (nominee: string) => { - this.send(extrinsics.staking.public.nominate, [nominee]); + this.send(Api.extrinsics.staking.nominate(nominee)); this.toggleNominate(); } private unnominate = (index: number) => { - this.send(extrinsics.staking.public.unnominate, [index]); + this.send(Api.extrinsics.staking.unnominate(index)); } private stake = () => { - this.send(extrinsics.staking.public.stake, []); + this.send(Api.extrinsics.staking.stake()); } private unstake = () => { - const { address, intentions } = this.props; + const { accountId, intentions } = this.props; - this.send(extrinsics.staking.public.unstake, [intentions.indexOf(address)]); + this.send(Api.extrinsics.staking.unstake(intentions.indexOf(accountId))); } } export default withMulti( Account, translate, - withObservable('stakingNominatorsFor', { paramProp: 'address' }), - withObservable('stakingNominating', { paramProp: 'address' }), - withObservable('systemAccountIndexOf', { paramProp: 'address' }) + withObservable('stakingNominatorsFor', { paramProp: 'accountId' }), + withObservable('stakingNominating', { paramProp: 'accountId' }), + withObservable('accountNonce', { paramProp: 'accountId' }) ); diff --git a/packages/app-staking/src/StakeList/Nominating.tsx b/packages/app-staking/src/StakeList/Nominating.tsx index 8cbad6ec89..6a54dec5ce 100644 --- a/packages/app-staking/src/StakeList/Nominating.tsx +++ b/packages/app-staking/src/StakeList/Nominating.tsx @@ -1,20 +1,15 @@ -// Copyright 2017-2018 @polkadot/ui-signer authors & contributors +// Copyright 2017-2018 @polkadot/ui-staking 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 Modal from '@polkadot/ui-app/Modal'; -import InputError from '@polkadot/ui-app/InputError'; +import { decodeAddress } from '@polkadot/keyring'; +import { Button, Input, Modal } from '@polkadot/ui-app/index'; import translate from '../translate'; -import addressDecode from '@polkadot/util-keyring/address/decode'; - type Props = I18nProps & { isOpen: boolean, onClose: () => void, @@ -91,7 +86,7 @@ class Nominating extends React.PureComponent { renderContent () { const { t } = this.props; - const { isNomineeValid, isAddressFormatValid, nominee } = this.state; + const { isNomineeValid, nominee } = this.state; return [ @@ -109,44 +104,56 @@ class Nominating extends React.PureComponent { onChange={this.onChangeNominee} value={nominee} /> - { - !isNomineeValid - ? - : null - } - { - !isAddressFormatValid - ? - : null - } + {this.renderErrors()} ]; } + private renderErrors () { + const { t } = this.props; + const { isNomineeValid, isAddressFormatValid } = this.state; + const hasError = !isNomineeValid || !isAddressFormatValid; + + if (!hasError) { + return null; + } + + return ( +
+ { + !isNomineeValid && isAddressFormatValid + ? t('nominator.error', { + defaultValue: 'The address you input is not intending to stake, and is therefore invalid. Please try again with a validator address.' + }) + : null + } + { + !isAddressFormatValid + ? t('nominator.error', { + defaultValue: 'The address does not conform to a recognized address format. Please make sure you enter a valid address.' + }) + : null + } +
+ ); + } + private onChangeNominee = (nominee: string) => { const { intentions } = this.props; - let publicKey; + + let isAddressFormatValid = false; try { - publicKey = addressDecode(nominee); + decodeAddress(nominee); + + isAddressFormatValid = true; } catch (err) { console.error(err); - this.setState({ - isAddressFormatValid: false - }); } this.setState({ isNomineeValid: intentions.includes(nominee), - isAddressFormatValid: publicKey && publicKey.length === 32, + isAddressFormatValid, nominee }); } diff --git a/packages/app-staking/src/StakeList/UnnominateButton.tsx b/packages/app-staking/src/StakeList/UnnominateButton.tsx index 9e55cf1a9d..eff2acac22 100644 --- a/packages/app-staking/src/StakeList/UnnominateButton.tsx +++ b/packages/app-staking/src/StakeList/UnnominateButton.tsx @@ -1,18 +1,17 @@ // Copyright 2017-2018 @polkadot/app-staking 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 withMulti from '@polkadot/ui-react-rx/with/multi'; -import withObservable from '@polkadot/ui-react-rx/with/observable'; +import { Button } from '@polkadot/ui-app/index'; +import { withMulti, withObservable } from '@polkadot/ui-react-rx/with/index'; import translate from '../translate'; type Props = I18nProps & { - address: string, + accountId: string, nominating: string, stakingNominatorsFor: Array, onClick: (index: number) => void @@ -22,7 +21,7 @@ class UnnominateButton extends React.Component { render () { const { nominating, stakingNominatorsFor, style, t } = this.props; - if (!nominating || !stakingNominatorsFor || stakingNominatorsFor.length === 0) { + if (!nominating || !stakingNominatorsFor) { return null; } @@ -40,9 +39,14 @@ class UnnominateButton extends React.Component { } onClick = () => { - const { address, stakingNominatorsFor, onClick } = this.props; + const { accountId, stakingNominatorsFor, onClick } = this.props; - onClick(stakingNominatorsFor.indexOf(address)); + onClick( + stakingNominatorsFor + .map((accountId) => + accountId.toString() + ) + .indexOf(accountId)); } } diff --git a/packages/app-staking/src/StakeList/index.css b/packages/app-staking/src/StakeList/index.css index 2a369d7715..5c136d0f92 100644 --- a/packages/app-staking/src/StakeList/index.css +++ b/packages/app-staking/src/StakeList/index.css @@ -1,6 +1,6 @@ /* Copyright 2017-2018 @polkadot/app-staking 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. */ .staking--Summary { margin-bottom: 2rem; diff --git a/packages/app-staking/src/StakeList/index.tsx b/packages/app-staking/src/StakeList/index.tsx index e802832f9f..99175e7b0e 100644 --- a/packages/app-staking/src/StakeList/index.tsx +++ b/packages/app-staking/src/StakeList/index.tsx @@ -1,27 +1,29 @@ // Copyright 2017-2018 @polkadot/app-staking 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 { RxBalanceMap } from '@polkadot/ui-react-rx/ApiObservable/types'; +import { QueueProps } from '@polkadot/ui-app/Status/types'; +import { RxBalanceMap } from '@polkadot/api-observable/types'; +import { AccountId, Balance } from '@polkadot/types'; import React from 'react'; -import keyring from '@polkadot/ui-keyring/index'; -import { QueueConsumer } from '@polkadot/ui-signer/Context'; +import keyring from '@polkadot/ui-keyring'; +import { QueueConsumer } from '@polkadot/ui-app/Status/Context'; import Account from './Account'; import translate from '../translate'; type Props = I18nProps & { balances: RxBalanceMap, + balanceArray: (_address: AccountId | string) => Array | undefined, intentions: Array, validators: Array }; class StakeList extends React.PureComponent { render () { - const { balances, intentions, validators } = this.props; + const { balances, balanceArray, intentions, validators } = this.props; return ( @@ -33,8 +35,9 @@ class StakeList extends React.PureComponent { return ( , - sessionValidators?: Array + onStatusChange: (status: ActionStatus) => void, + stakingIntentions?: Array, + sessionValidators?: Array, + validatingBalances?: RxBalanceMap }; type State = { - action: Actions + action: Actions, + intentions: Array, + validators: Array }; -// FIXME React-router would probably be the best route, not home-grown const Components: { [index: string]: React.ComponentType } = { 'overview': Overview, 'actions': StakeList @@ -42,13 +45,26 @@ class App extends React.PureComponent { super(props); this.state = { - action: 'overview' + action: 'overview', + intentions: [], + validators: [] }; } + static getDerivedStateFromProps ({ sessionValidators = [], stakingIntentions = [] }: Props): State { + return { + intentions: stakingIntentions.map((accountId) => + accountId.toString() + ), + validators: sessionValidators.map((authorityId) => + authorityId.toString() + ) + } as State; + } + render () { - const { action } = this.state; - const { sessionValidators = [], stakingIntentions = [], t, validatingBalances = {} } = this.props; + const { action, intentions, validators } = this.state; + const { t, validatingBalances = {} } = this.props; const Component = Components[action]; const items = [ { @@ -72,16 +88,31 @@ class App extends React.PureComponent { ); } - onMenuChange = (action: Actions) => { + private onMenuChange = (action: Actions) => { this.setState({ action }); } + + private balanceArray = (_address: AccountId | string): Array | undefined => { + const { validatingBalances = {} } = this.props; + + if (!_address) { + return undefined; + } + + const address = _address.toString(); + + return validatingBalances[address] + ? [validatingBalances[address].stakingBalance, validatingBalances[address].nominatedBalance] + : undefined; + } } export default withMulti( diff --git a/packages/app-staking/src/translate.ts b/packages/app-staking/src/translate.ts index 00ee500943..07e4a2d12d 100644 --- a/packages/app-staking/src/translate.ts +++ b/packages/app-staking/src/translate.ts @@ -1,7 +1,7 @@ // Copyright 2017-2018 @polkadot/app-staking 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(['staking', 'ui']); +export default withNamespaces(['staking', 'ui']); diff --git a/packages/app-storage/LICENSE b/packages/app-storage/LICENSE index b2d5cab6e5..0d381b2e97 100644 --- a/packages/app-storage/LICENSE +++ b/packages/app-storage/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-storage 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. diff --git a/packages/app-storage/package.json b/packages/app-storage/package.json index 177c692b12..5347f01629 100644 --- a/packages/app-storage/package.json +++ b/packages/app-storage/package.json @@ -1,6 +1,6 @@ { "name": "@polkadot/app-storage", - "version": "0.20.30", + "version": "0.21.0", "main": "index.js", "repository": "https://github.com/polkadot-js/apps.git", "author": "Jaco Greeff ", @@ -8,9 +8,9 @@ "Jaco Greeff " ], "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" } } diff --git a/packages/app-storage/src/Queries.tsx b/packages/app-storage/src/Queries.tsx index 19be82ae49..c7b240243b 100644 --- a/packages/app-storage/src/Queries.tsx +++ b/packages/app-storage/src/Queries.tsx @@ -1,9 +1,9 @@ // Copyright 2017-2018 @polkadot/app-storage 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 { StorageQuery } from './types'; +import { QueryTypes } from './types'; import React from 'react'; @@ -11,7 +11,7 @@ import Query from './Query'; type Props = BareProps & { onRemove: (id: number) => void, - value?: Array + value?: Array }; export default class Queries extends React.PureComponent { diff --git a/packages/app-storage/src/Query.tsx b/packages/app-storage/src/Query.tsx index 4f07332771..113f53d30f 100644 --- a/packages/app-storage/src/Query.tsx +++ b/packages/app-storage/src/Query.tsx @@ -1,73 +1,111 @@ // Copyright 2017-2018 @polkadot/app-storage 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 { Storage$Key$Value } from '@polkadot/storage/types'; +import { StorageFunction } from '@polkadot/types/StorageKey'; import { I18nProps } from '@polkadot/ui-app/types'; -import { StorageQuery } from './types'; +import { QueryTypes, StorageModuleQuery } from './types'; import React from 'react'; - -import typeToString from '@polkadot/params/typeToString'; -import Button from '@polkadot/ui-app/Button'; -import Labelled from '@polkadot/ui-app/Labelled'; +import { Compact } from '@polkadot/types/codec'; +import { Button, Labelled } from '@polkadot/ui-app/index'; import valueToText from '@polkadot/ui-app/Params/valueToText'; -import withObservableDiv from '@polkadot/ui-react-rx/with/observableDiv'; +import { withObservableDiv } from '@polkadot/ui-react-rx/with/index'; +import { isU8a, u8aToHex, u8aToString } from '@polkadot/util'; import translate from './translate'; +import { RenderFn, DefaultProps, ComponentRenderer } from '@polkadot/ui-react-rx/with/types'; type Props = I18nProps & { onRemove: (id: number) => void, - value: StorageQuery + value: QueryTypes }; type ComponentProps = {}; type State = { - inputs: Array, // node? - Component: React.ComponentType; + inputs: Array, + Component: React.ComponentType, + spread: { [index: number]: boolean } }; -const cache: Array> = []; +type CacheInstance = { + Component: React.ComponentType, + render: RenderFn, + refresh: (swallowErrors: boolean, contentShorten: boolean) => React.ComponentType +}; + +const cache: Array = []; class Query extends React.PureComponent { - state: State = {} as State; + state: State = { spread: {} } as State; + + static getCachedComponent (query: QueryTypes): CacheInstance { + const { id, key, params = [] } = query as StorageModuleQuery; - static getCachedComponent ({ id, key, params }: StorageQuery): React.ComponentType { if (!cache[id]) { - const values: Array = params.map(({ value }) => - // FIXME not 100% convinced, arrays could be an issue? (Plus, if we have to cast, something just _seems_ off) - value as Storage$Key$Value - ); + const values: Array = params.map(({ value }) => value); + const type = key.meta + ? key.meta.type.toString() + : 'Data'; + const defaultProps = { className: 'ui--output' }; - cache[id] = withObservableDiv('rawStorage', { params: [key, ...values] })( - (value: any) => - valueToText(key.type, value), - { className: 'ui--output' } + // render function to create an element for the query results which is plugged to the api + const fetchAndRenderHelper = withObservableDiv('rawStorage', { params: [key, ...values] }); + const pluggedComponent = fetchAndRenderHelper( + // By default we render a simple div node component with the query results in it + (value: any) => valueToText(type, value, true, true), + defaultProps ); + cache[query.id] = Query.createComponentCacheInstance(type, pluggedComponent, defaultProps, fetchAndRenderHelper); } return cache[id]; } + static createComponentCacheInstance (type: string, pluggedComponent: React.ComponentType, defaultProps: DefaultProps, fetchAndRenderHelper: ComponentRenderer) { + return { + Component: pluggedComponent, + // In order to replace the default component during runtime we can provide a RenderFn to create a new 'plugged' component + render: (createComponent: RenderFn) => { + return fetchAndRenderHelper( + createComponent, + defaultProps + ); + }, + // In order to modify the parameters which are used to render the default component, we can use this method + refresh: (swallowErrors: boolean, contentShorten: boolean) => { + return fetchAndRenderHelper( + (value: any) => valueToText(type, value, swallowErrors, contentShorten), + defaultProps + ); + } + }; + } + static getDerivedStateFromProps ({ value }: Props, prevState: State): State | null { - const Component = Query.getCachedComponent(value); - const { key, params } = value; - const inputs = key.params.map(({ name, type }, index) => ( - - {name}={valueToText(type, params[index].value)} - - )); + const Component = Query.getCachedComponent(value).Component; + const inputs: Array = isU8a(value.key) + ? [] + // FIXME We need to render the actual key params + // const { key, params } = value; + // const inputs = key.params.map(({ name, type }, index) => ( + // + // {name}={valueToText(type, params[index].value)} + // + // )); + : []; return { Component, inputs - }; + } as State; } render () { - const { value: { key } } = this.props; - const { Component, inputs } = this.state; + const { value } = this.props; + const { Component } = this.state; + const { key } = value; return (
@@ -75,27 +113,104 @@ class Query extends React.PureComponent { className='storage--actionrow-value' label={
-
{key.section}.{key.name}(
- {inputs} -
):
-
{typeToString(key.type)}
+
{this.keyToName(key)}
+ {this.renderInputs()} +
{ + isU8a(key) + ? 'Data' + : key.meta.type.toString() + }
} > - -
); } - onRemove = (): void => { + private renderButtons () { + const { id, key } = this.props.value as StorageModuleQuery; + + const buttons = [ +
- {this.renderAddress(from)} + {this.renderAddress(accountId)}
{({ queueExtrinsic }: QueueProps) => ( )}
- {this.renderAddress(to)} + {this.renderAddress(recipientId)}
); } - private renderAddress (publicKey: Uint8Array | null) { - if (!publicKey) { + private renderAddress (accountId: string | null) { + if (!accountId) { + return null; + } + + try { + decodeAddress(accountId); + } catch (err) { return null; } return (
); } - private onChangeAmount = (amount: BN) => { - this.setState({ amount }); + private nextState (newState: Partial): void { + this.setState((prevState: State): State => { + const { accountId = prevState.accountId, amount = prevState.amount, recipientId = prevState.recipientId, txfees = prevState.txfees } = newState; + const extrinsic = accountId && recipientId + ? new Extrinsic({ method: Api.extrinsics.balances.transfer(recipientId, amount) }) + : null; + + return { + accountId, + amount, + extrinsic, + recipientId, + txfees + }; + }); } - private onChangeFrom = (from: Uint8Array) => { - this.setState({ from }); + private onChangeFrom = (accountId: string) => { + this.nextState({ accountId }); } - private onChangeTo = (to: Uint8Array) => { - this.setState({ to }); + private onChangeAmount = (amount: BN = new BN(0)) => { + this.nextState({ amount }); + } + + private onChangeTo = (recipientId: string) => { + this.nextState({ recipientId }); } private onChangeFees = (txfees: Fees) => { @@ -149,6 +175,7 @@ class Transfer extends React.PureComponent { } export default withMulti( - translate(Transfer), + Transfer, + translate, withObservable('fees', { propName: 'fees' }) ); diff --git a/packages/app-transfer/src/index.css b/packages/app-transfer/src/index.css index 7b55ba387c..f03608c1fe 100644 --- a/packages/app-transfer/src/index.css +++ b/packages/app-transfer/src/index.css @@ -1,35 +1,25 @@ /* Copyright 2017-2018 @polkadot/app-transfer authors & contributors /* This software may be modified and distributed under the terms -/* of the ISC license. See the LICENSE file for details. */ - -.transfer--Transfer-info { - display: flex; - flex-direction: row; -} - -.transfer--Transfer-data { - flex: 1 1; -} +/* of the Apache-2.0 license. See the LICENSE file for details. */ .transfer--Transfer-address { flex: 0 1; padding: 2em 0; -} -.transfer--Transfer-address .ui--AddressSummary { - text-align: center; + .ui--AddressSummary { + text-align: center; + } } .transfer--Transfer-amounts { padding: 0 26%; } -.error { - background-color: #fff6f6; - border-color: #e0b4b4; - color: #9f3a38; +.transfer--Transfer-data { + flex: 1 1; } -.warning { - background: #ffffe0; +.transfer--Transfer-info { + display: flex; + flex-direction: row; } diff --git a/packages/app-transfer/src/index.tsx b/packages/app-transfer/src/index.tsx index 43bff257b6..2b73194858 100644 --- a/packages/app-transfer/src/index.tsx +++ b/packages/app-transfer/src/index.tsx @@ -1,13 +1,14 @@ // Copyright 2017-2018 @polkadot/app-transfer 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 React from 'react'; import { Trans } from 'react-i18next'; import accountObservable from '@polkadot/ui-keyring/observable/accounts'; -import withObservableBase from '@polkadot/ui-react-rx/with/observableBase'; +import { withMulti, withObservableBase } from '@polkadot/ui-react-rx/with/index'; import './index.css'; @@ -15,7 +16,7 @@ import Transfer from './Transfer'; import translate from './translate'; type Props = I18nProps & { - allAccounts?: Array + allAccounts?: SubjectInfo }; type State = { @@ -49,6 +50,8 @@ class App extends React.PureComponent { } } -export default withObservableBase( - accountObservable.subject, { propName: 'allAccounts' } -)(translate(App)); +export default withMulti( + App, + translate, + withObservableBase(accountObservable.subject, { propName: 'allAccounts' }) +); diff --git a/packages/app-transfer/src/translate.ts b/packages/app-transfer/src/translate.ts index 1aee83529c..5a78cad433 100644 --- a/packages/app-transfer/src/translate.ts +++ b/packages/app-transfer/src/translate.ts @@ -1,7 +1,7 @@ -// Copyright 2017-2018 @polkadot/app-toolbox authors & contributors +// Copyright 2017-2018 @polkadot/app-transfer 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(['transfer', 'ui']); +export default withNamespaces(['transfer', 'ui']); diff --git a/packages/app-transfer/src/types.d.ts b/packages/app-transfer/src/types.ts similarity index 83% rename from packages/app-transfer/src/types.d.ts rename to packages/app-transfer/src/types.ts index f1a0c7ad85..ebcfb84f24 100644 --- a/packages/app-transfer/src/types.d.ts +++ b/packages/app-transfer/src/types.ts @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/app-toolbox 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'; diff --git a/packages/app-vanitygen/LICENSE b/packages/app-vanitygen/LICENSE index 5e71624eaf..0d381b2e97 100644 --- a/packages/app-vanitygen/LICENSE +++ b/packages/app-vanitygen/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-vanitygen 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. diff --git a/packages/app-vanitygen/package.json b/packages/app-vanitygen/package.json index 4256eba783..2af7e648c6 100644 --- a/packages/app-vanitygen/package.json +++ b/packages/app-vanitygen/package.json @@ -1,6 +1,6 @@ { "name": "@polkadot/app-vanitygen", - "version": "0.20.30", + "version": "0.21.0", "main": "index.js", "repository": "https://github.com/polkadot-js/apps.git", "author": "Jaco Greeff ", @@ -8,16 +8,16 @@ "Jaco Greeff " ], "contributors": [], - "license": "ISC", + "license": "Apache-2.0", "dependencies": { - "@babel/runtime": "^7.0.0", - "@polkadot/ui-app": "^0.20.30", - "@types/yargs": "^11.1.1", + "@babel/runtime": "^7.2.0", + "@polkadot/ui-app": "^0.21.0", + "@types/yargs": "^12.0.2", "babel-plugin-module-resolver": "^3.1.1", "libsodium-wrappers": "^0.7.3", - "yargs": "12.0.1" + "yargs": "^12.0.5" }, "optionalDependencies": { - "sodium": "^2.0.1" + "sodium": "^3.0.2" } } diff --git a/packages/app-vanitygen/scripts/vanitygen.js b/packages/app-vanitygen/scripts/vanitygen.js index 4b0409ca29..9c069f9887 100755 --- a/packages/app-vanitygen/scripts/vanitygen.js +++ b/packages/app-vanitygen/scripts/vanitygen.js @@ -1,7 +1,7 @@ #!/usr/bin/env node // Copyright 2017-2018 @polkadot/client 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. const fs = require('fs'); const path = require('path'); diff --git a/packages/app-vanitygen/src/Match.tsx b/packages/app-vanitygen/src/Match.tsx index bac6d26dbf..4c688dfc80 100644 --- a/packages/app-vanitygen/src/Match.tsx +++ b/packages/app-vanitygen/src/Match.tsx @@ -1,15 +1,13 @@ // Copyright 2017-2018 @polkadot/app-vanitygen 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 React from 'react'; -import CopyButton from '@polkadot/ui-app/CopyButton'; -import Button from '@polkadot/ui-app/Button'; -import IdentityIcon from '@polkadot/ui-react/IdentityIcon'; -import u8aToHex from '@polkadot/util/u8a/toHex'; +import { Button, CopyButton, IdentityIcon } from '@polkadot/ui-app/index'; +import { u8aToHex } from '@polkadot/util'; type Props = BareProps & { address: string; diff --git a/packages/app-vanitygen/src/generator/calculate.ts b/packages/app-vanitygen/src/generator/calculate.ts index 40eba3092d..fe33f9a0a2 100644 --- a/packages/app-vanitygen/src/generator/calculate.ts +++ b/packages/app-vanitygen/src/generator/calculate.ts @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/app-vanitygen 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 { Generator$Calculation, Generator$Options } from './types'; diff --git a/packages/app-vanitygen/src/generator/cli.ts b/packages/app-vanitygen/src/generator/cli.ts index d1811e9406..bc3ab01e87 100644 --- a/packages/app-vanitygen/src/generator/cli.ts +++ b/packages/app-vanitygen/src/generator/cli.ts @@ -1,11 +1,11 @@ #!/usr/bin/env node // Copyright 2017-2018 @polkadot/app-vanitygen 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 yargs from 'yargs'; import chalk from 'chalk'; -import u8aToHex from '@polkadot/util/u8a/toHex'; +import { u8aToHex } from '@polkadot/util'; import generator from './index'; import matchRegex from './regex'; diff --git a/packages/app-vanitygen/src/generator/generate.ts b/packages/app-vanitygen/src/generator/generate.ts index 3faecd2257..3e81145d3a 100644 --- a/packages/app-vanitygen/src/generator/generate.ts +++ b/packages/app-vanitygen/src/generator/generate.ts @@ -1,19 +1,18 @@ // Copyright 2017-2018 @polkadot/app-vanitygen 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 { Generator$PkFromSeed, Generator$Match, Generator$Options } from './types'; import sodiumWasm from 'libsodium-wrappers'; -import randomBytes from '@polkadot/util-crypto/random/asU8a'; -import addressEncode from '@polkadot/util-keyring/address/encode'; -import pairFromSeed from '@polkadot/util-crypto/nacl/keypair/fromSeed'; +import { encodeAddress } from '@polkadot/keyring'; +import { naclKeypairFromSeed, randomAsU8a } from '@polkadot/util-crypto'; import calculate from './calculate'; import sodiumKeygen from './sodiumKeygen'; const tweetPkFromSeed = (seed: Uint8Array): Uint8Array => - pairFromSeed(seed).publicKey; + naclKeypairFromSeed(seed).publicKey; let defaultPkFromSeed: Generator$PkFromSeed = tweetPkFromSeed; @@ -29,8 +28,8 @@ let defaultPkFromSeed: Generator$PkFromSeed = tweetPkFromSeed; })(); export default function generator (test: Array, options: Generator$Options, pkFromSeed: Generator$PkFromSeed = defaultPkFromSeed): Generator$Match { - const seed = randomBytes(); - const address = addressEncode(pkFromSeed(seed)); + const seed = randomAsU8a(); + const address = encodeAddress(pkFromSeed(seed)); const { count, offset } = calculate(test, address, options); return { diff --git a/packages/app-vanitygen/src/generator/index.ts b/packages/app-vanitygen/src/generator/index.ts index 4137cb67b4..532670a2cf 100644 --- a/packages/app-vanitygen/src/generator/index.ts +++ b/packages/app-vanitygen/src/generator/index.ts @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/app-vanitygen 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 { Generator$PkFromSeed, Generator$Matches, Generator$Result, Generator$Options } from './types'; diff --git a/packages/app-vanitygen/src/generator/regex.ts b/packages/app-vanitygen/src/generator/regex.ts index 467a6f4e6f..17f1a8a01b 100644 --- a/packages/app-vanitygen/src/generator/regex.ts +++ b/packages/app-vanitygen/src/generator/regex.ts @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/app-vanitygen 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. const regex = new RegExp('^[1-9A-HJ-NP-Za-km-z]*$', ''); diff --git a/packages/app-vanitygen/src/generator/sodium.ts b/packages/app-vanitygen/src/generator/sodium.ts index a339fe8c86..23e385d92b 100644 --- a/packages/app-vanitygen/src/generator/sodium.ts +++ b/packages/app-vanitygen/src/generator/sodium.ts @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/app-vanitygen 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 { Generator$PkFromSeed } from './types'; diff --git a/packages/app-vanitygen/src/generator/sodiumKeygen.ts b/packages/app-vanitygen/src/generator/sodiumKeygen.ts index 84e5711a4b..4b99a4f1ec 100644 --- a/packages/app-vanitygen/src/generator/sodiumKeygen.ts +++ b/packages/app-vanitygen/src/generator/sodiumKeygen.ts @@ -1,11 +1,10 @@ // Copyright 2017-2018 @polkadot/app-vanitygen 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 { Generator$PkFromSeed } from './types'; -import bufferToU8a from '@polkadot/util/buffer/toU8a'; -import u8aToBuffer from '@polkadot/util/u8a/toBuffer'; +import { bufferToU8a, u8aToBuffer } from '@polkadot/util'; export default function setupFn (sodium: any): Generator$PkFromSeed { return (seed: Uint8Array): Uint8Array => diff --git a/packages/app-vanitygen/src/generator/sort.ts b/packages/app-vanitygen/src/generator/sort.ts index 256e5a35d4..21081c1388 100644 --- a/packages/app-vanitygen/src/generator/sort.ts +++ b/packages/app-vanitygen/src/generator/sort.ts @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/app-vanitygen 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 { Generator$Match } from './types'; diff --git a/packages/app-vanitygen/src/generator/types.d.ts b/packages/app-vanitygen/src/generator/types.d.ts index 8144113a7a..fbcf1a1d48 100644 --- a/packages/app-vanitygen/src/generator/types.d.ts +++ b/packages/app-vanitygen/src/generator/types.d.ts @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/app-vanitygen 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. export type Generator$Calculation = { count: number, diff --git a/packages/app-vanitygen/src/index.css b/packages/app-vanitygen/src/index.css index 953afa5ec8..00bc0a3a4e 100644 --- a/packages/app-vanitygen/src/index.css +++ b/packages/app-vanitygen/src/index.css @@ -1,6 +1,6 @@ /* Copyright 2017-2018 @polkadot/app-vanitygen 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. */ .vanity--App-matches { padding: 1em 0; diff --git a/packages/app-vanitygen/src/index.tsx b/packages/app-vanitygen/src/index.tsx index da672a2d7e..619950a213 100644 --- a/packages/app-vanitygen/src/index.tsx +++ b/packages/app-vanitygen/src/index.tsx @@ -1,17 +1,15 @@ // Copyright 2017-2018 @polkadot/app-vanitygen 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 { Generator$Matches, Generator$Result } from './generator/types'; import './index.css'; import React from 'react'; -import Button from '@polkadot/ui-app/Button'; -import Dropdown from '@polkadot/ui-app/Dropdown'; -import Input from '@polkadot/ui-app/Input'; -import Static from '@polkadot/ui-app/Static'; +import { Button, Dropdown, Input, Static } from '@polkadot/ui-app/index'; import Match from './Match'; import generator from './generator'; @@ -20,7 +18,8 @@ import generatorSort from './generator/sort'; import translate from './translate'; type Props = I18nProps & { - basePath: string + basePath: string, + onStatusChange: (status: ActionStatus) => void }; type State = { @@ -109,6 +108,7 @@ class VanityApp extends React.PureComponent { return (
" ], "contributors": [], - "license": "ISC", + "license": "Apache-2.0", "dependencies": { - "@babel/runtime": "^7.0.0", - "@polkadot/app-accounts": "^0.20.30", - "@polkadot/app-addresses": "^0.20.30", - "@polkadot/app-democracy": "^0.20.30", - "@polkadot/app-example": "^0.20.30", - "@polkadot/app-explorer": "^0.20.30", - "@polkadot/app-extrinsics": "^0.20.30", - "@polkadot/app-rpc": "^0.20.30", - "@polkadot/app-staking": "^0.20.30", - "@polkadot/app-storage": "^0.20.30", - "@polkadot/app-toolbox": "^0.20.30", - "@polkadot/app-transfer": "^0.20.30", - "@polkadot/app-vanitygen": "^0.20.30", - "@polkadot/ui-app": "^0.20.30", - "@polkadot/ui-signer": "^0.20.30" - }, - "devDependencies": { - "copy-webpack-plugin": "^4.5.1", - "empty": "^0.10.1", - "source-map-explorer": "^1.6.0" + "@babel/runtime": "^7.2.0", + "@polkadot/app-accounts": "^0.21.0", + "@polkadot/app-addresses": "^0.21.0", + "@polkadot/app-democracy": "^0.21.0", + "@polkadot/app-explorer": "^0.21.0", + "@polkadot/app-extrinsics": "^0.21.0", + "@polkadot/app-rpc": "^0.21.0", + "@polkadot/app-settings": "^0.21.0", + "@polkadot/app-staking": "^0.21.0", + "@polkadot/app-storage": "^0.21.0", + "@polkadot/app-toolbox": "^0.21.0", + "@polkadot/app-transfer": "^0.21.0", + "@polkadot/app-vanitygen": "^0.21.0", + "@polkadot/ui-app": "^0.21.0", + "@polkadot/ui-assets": "^0.24.9", + "@polkadot/ui-signer": "^0.21.0" } } diff --git a/packages/apps/src/Connecting/Connecting.css b/packages/apps/src/Connecting/Connecting.css index 210908979a..0a936eb11e 100644 --- a/packages/apps/src/Connecting/Connecting.css +++ b/packages/apps/src/Connecting/Connecting.css @@ -1,6 +1,6 @@ /* Copyright 2017-2018 @polkadot/apps 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. */ .apps--Connecting { bottom: 0; diff --git a/packages/apps/src/Connecting/index.tsx b/packages/apps/src/Connecting/index.tsx index d7881c4ee4..5cac1ab1bc 100644 --- a/packages/apps/src/Connecting/index.tsx +++ b/packages/apps/src/Connecting/index.tsx @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/apps 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'; @@ -8,17 +8,21 @@ import { ApiProps } from '@polkadot/ui-react-rx/types'; import './Connecting.css'; import React from 'react'; -import withApi from '@polkadot/ui-react-rx/with/api'; +import { withApi, withMulti } from '@polkadot/ui-react-rx/with/index'; +import settings from '@polkadot/ui-settings'; import translate from '../translate'; type Props = I18nProps & ApiProps; +// @ts-ignore +const isFirefox = typeof InstallTrigger !== 'undefined'; + class Connecting extends React.PureComponent { render () { - const { apiConnected, t } = this.props; + const { isApiConnected, t } = this.props; - if (apiConnected) { + if (isApiConnected) { return null; } @@ -27,13 +31,25 @@ class Connecting extends React.PureComponent {
{t('connecting.disconnected', { defaultValue: 'You are not connected to a node. Ensure that your node is running and that the Websocket endpoint is reachable.' - })} + })}  + { + isFirefox && settings.apiUrl.indexOf('ws://') === 0 + ? t('connecting.ff', { + defaultValue: 'With the Firefox browser connecting to insecure WebSockets (in this case {{url}}) will fail due to the browser not allowing localhost access from a secure site.', + replace: { + url: settings.apiUrl + } + }) + : '' + }
); } } -export default translate( - withApi(Connecting) +export default withMulti( + Connecting, + translate, + withApi ); diff --git a/packages/apps/src/Content/Content.css b/packages/apps/src/Content/Content.css index 08d7d49ea2..6b90934831 100644 --- a/packages/apps/src/Content/Content.css +++ b/packages/apps/src/Content/Content.css @@ -1,6 +1,6 @@ /* Copyright 2017-2018 @polkadot/apps 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. */ .apps--Content { background: white; diff --git a/packages/apps/src/Content/NotFound.tsx b/packages/apps/src/Content/NotFound.tsx index d1409605cd..46c2ef4775 100644 --- a/packages/apps/src/Content/NotFound.tsx +++ b/packages/apps/src/Content/NotFound.tsx @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/apps 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 React from 'react'; import { Redirect } from 'react-router'; diff --git a/packages/apps/src/Content/index.tsx b/packages/apps/src/Content/index.tsx index 621c956f32..26a94a7e8d 100644 --- a/packages/apps/src/Content/index.tsx +++ b/packages/apps/src/Content/index.tsx @@ -1,42 +1,77 @@ // Copyright 2017-2018 @polkadot/apps 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 { QueueProps } from '@polkadot/ui-app/Status/types'; import './Content.css'; import React from 'react'; import { withRouter } from 'react-router'; +import { withApi, withMulti } from '@polkadot/ui-react-rx/with/index'; +import { QueueConsumer } from '@polkadot/ui-app/Status/Context'; +import Status from '../Status'; import routing from '../routing'; +import translate from '../translate'; import NotFound from './NotFound'; -type Props = I18nProps & { +type Props = I18nProps & ApiProps & { location: Location }; const unknown = { + isApiGated: false, Component: NotFound, name: '' }; -class Content extends React.PureComponent { +class Content extends React.Component { render () { - const { location } = this.props; - + const { isApiConnected, isApiReady, location, t } = this.props; const app = location.pathname.slice(1) || ''; - const { Component, name } = routing.routes.find((route) => + const { Component, isApiGated, name } = routing.routes.find((route) => !!(route && app.indexOf(route.name) === 0) ) || unknown; + if (isApiGated && (!isApiReady || !isApiConnected)) { + return ( +
+
{t('content.gated', { + defaultValue: 'Waiting for API to be connected and ready.' + })}
+
+ ); + } + return (
- + + {({ queueAction, stqueue, txqueue }: QueueProps) => [ + , + + ]} +
); } } -// @ts-ignore Ok, here the definition doesn't like this one... at all :( -export default withRouter(Content); +export default withMulti( + Content, + // React-router needs to be first, otherwise we have blocked updates + withRouter, + translate, + withApi +); diff --git a/packages/apps/src/NodeInfo.tsx b/packages/apps/src/NodeInfo.tsx index b0d22c19c4..7bc1db1543 100644 --- a/packages/apps/src/NodeInfo.tsx +++ b/packages/apps/src/NodeInfo.tsx @@ -1,32 +1,27 @@ // Copyright 2017-2018 @polkadot/apps 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 React from 'react'; -import isTestChain from '@polkadot/ui-react-rx/util/isTestChain'; -import keyring from '@polkadot/ui-keyring/index'; -import BestNumber from '@polkadot/ui-react-rx/BestNumber'; -import Chain from '@polkadot/ui-react-rx/Chain'; -import NodeName from '@polkadot/ui-react-rx/NodeName'; -import NodeVersion from '@polkadot/ui-react-rx/NodeVersion'; +import { AccountId } from '@polkadot/types'; +import { BestNumber, Chain, NodeName, NodeVersion } from '@polkadot/ui-react-rx/index'; +import { withMulti, withObservable } from '@polkadot/ui-react-rx/with/index'; -type Props = BareProps & {}; +type Props = BareProps & { + sessionValidators?: Array +}; const pkgJson = require('../package.json'); -function updateTestInfo (chain?: string) { - keyring.setDevMode(isTestChain(chain)); -} - -export default class NodeInfo extends React.PureComponent { +class NodeInfo extends React.PureComponent { render () { return (
-   +  
@@ -38,3 +33,11 @@ export default class NodeInfo extends React.PureComponent { ); } } + +// NOTE While these are not used internally to this specific component, we are loading them +// to have them warmed-up globally. This means when accessing in other components, the values +// are already there +export default withMulti( + NodeInfo, + withObservable('sessionValidators') +); diff --git a/packages/apps/src/SideBar/Item.tsx b/packages/apps/src/SideBar/Item.tsx index 382e2a01f8..146b4ecf98 100644 --- a/packages/apps/src/SideBar/Item.tsx +++ b/packages/apps/src/SideBar/Item.tsx @@ -1,24 +1,28 @@ // Copyright 2017-2018 @polkadot/apps 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 { Route } from '../types'; import React from 'react'; import { withRouter } from 'react-router'; import { NavLink } from 'react-router-dom'; +import { Icon, Menu } from '@polkadot/ui-app/index'; +import { withApi, withMulti } from '@polkadot/ui-react-rx/with/index'; -import Icon from '@polkadot/ui-app/Icon'; -import Menu from '@polkadot/ui-app/Menu'; - -type Props = I18nProps & { +type Props = I18nProps & ApiProps & { route: Route }; class Item extends React.PureComponent { render () { - const { route: { i18n, icon, name }, t } = this.props; + const { isApiConnected, isApiReady, route: { isApiGated, i18n, icon, name }, t } = this.props; + + if (isApiGated && (!isApiReady || !isApiConnected)) { + return null; + } return ( @@ -34,5 +38,8 @@ class Item extends React.PureComponent { } } -// @ts-ignore the definitions complain here, however the use is valid -export default withRouter(Item); +export default withMulti( + Item, + withRouter, + withApi +); diff --git a/packages/apps/src/SideBar/SideBar.css b/packages/apps/src/SideBar/SideBar.css index 10527932c5..5d9a4398cd 100644 --- a/packages/apps/src/SideBar/SideBar.css +++ b/packages/apps/src/SideBar/SideBar.css @@ -1,15 +1,11 @@ /* Copyright 2017-2018 @polkadot/apps 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 '../../../ui-app/src/styles/theme/_colors-polkadot.css'; @import '../../../ui-app/src/styles/theme/_colors-substrate.css'; .apps--SideBar { - /* - background: #fcfcfc; - border-right: 1px solid rgba(34, 36, 38, 0.15); - */ background: #4e4e4e; flex-shrink: 0; min-width: 10em; @@ -31,7 +27,7 @@ .apps--SideBar-logo { width: 100%; - margin: 0 1.5rem 0.75rem 0.75rem; + margin: .5rem 1.5rem 1.5rem .75rem; width: 10rem; } @@ -49,7 +45,7 @@ a.apps--SideBar-Item-NavLink { } a.apps--SideBar-Item-NavLink-active { - background: white; + background: #fafafa; border-radius: 0.28571429rem 0 0 0.28571429rem; /* border: 1px solid rgba(34, 36, 38, 0.15); diff --git a/packages/apps/src/SideBar/index.tsx b/packages/apps/src/SideBar/index.tsx index 44f06befc5..8c50ab8883 100644 --- a/packages/apps/src/SideBar/index.tsx +++ b/packages/apps/src/SideBar/index.tsx @@ -1,17 +1,17 @@ // Copyright 2017-2018 @polkadot/apps 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 './SideBar.css'; import React from 'react'; -import Icon from '@polkadot/ui-app/Icon'; -import Menu from '@polkadot/ui-app/Menu'; +import { Icon, Menu } from '@polkadot/ui-app/index'; +import polkadotLogo from '@polkadot/ui-assets/polkadot-white.svg'; +import substrateLogo from '@polkadot/ui-assets/parity-substrate-white.svg'; +import settings from '@polkadot/ui-settings'; -import polkadotLogo from '../static/polkadot-white.svg'; -import substrateLogo from '../static/parity-substrate-white.svg'; import routing from '../routing'; import translate from '../translate'; import Item from './Item'; @@ -25,7 +25,7 @@ const LOGOS: Map = new Map([ ['substrate', substrateLogo] ]); -const LOGO = LOGOS.get(process.env.UI_THEME) || polkadotLogo; +const LOGO = LOGOS.get(settings.uiTheme) || polkadotLogo; class SideBar extends React.PureComponent { render () { @@ -68,7 +68,8 @@ class SideBar extends React.PureComponent { + href='https://github.com/polkadot-js/apps' + > GitHub diff --git a/packages/apps/src/static/types.d.ts b/packages/apps/src/SideBar/svg.d.ts similarity index 75% rename from packages/apps/src/static/types.d.ts rename to packages/apps/src/SideBar/svg.d.ts index f2d6943e37..5e2fbe2e26 100644 --- a/packages/apps/src/static/types.d.ts +++ b/packages/apps/src/SideBar/svg.d.ts @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/apps 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. declare module '*.svg' { const content: any; diff --git a/packages/apps/src/Status.tsx b/packages/apps/src/Status.tsx new file mode 100644 index 0000000000..9e1c084238 --- /dev/null +++ b/packages/apps/src/Status.tsx @@ -0,0 +1,76 @@ +// Copyright 2017-2018 @polkadot/apps 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 { KeyringOptions } from '@polkadot/ui-keyring/options/types'; +import { QueueStatus, QueueTx, QueueAction$Add } from '@polkadot/ui-app/Status/types'; +import { I18nProps } from '@polkadot/ui-app/types'; + +import React from 'react'; +import keyringOption from '@polkadot/ui-keyring/options'; +import { EventRecord } from '@polkadot/types'; +import { Status as StatusDisplay } from '@polkadot/ui-app/index'; +import { withMulti, withObservable, withObservableBase } from '@polkadot/ui-react-rx/with'; +import { stringToU8a } from '@polkadot/util'; +import { xxhashAsHex } from '@polkadot/util-crypto'; + +import translate from './translate'; + +type Props = I18nProps & { + optionsAll?: KeyringOptions, + queueAction: QueueAction$Add, + stqueue: Array, + systemEvents?: Array, + txqueue: Array +}; + +let prevEventHash: string; + +class Status extends React.PureComponent { + componentDidUpdate ({ optionsAll = { account: [] as any } as KeyringOptions, queueAction, systemEvents = [], t }: Props) { + const eventHash = xxhashAsHex(stringToU8a(JSON.stringify(systemEvents))); + + if (eventHash === prevEventHash) { + return; + } + + prevEventHash = eventHash; + + const addresses = optionsAll.account.map((account) => account.value); + + systemEvents.forEach(({ event: { data, method, section } }) => { + if (section === 'balances' && method === 'Transfer') { + const recipient = data[1].toString(); + + if (addresses.includes(recipient)) { + queueAction({ + action: method, + status: 'received', + value: recipient, + message: t('transfer.received', { + defaultValue: 'transfer received' + }) + }); + } + } + }); + } + + render () { + const { stqueue, txqueue } = this.props; + + return ( + + ); + } +} + +export default withMulti( + Status, + translate, + withObservable('systemEvents'), + withObservableBase(keyringOption.optionsSubject, { propName: 'optionsAll' }) +); diff --git a/packages/apps/src/index.css b/packages/apps/src/index.css index 095982d77c..421cb755c7 100644 --- a/packages/apps/src/index.css +++ b/packages/apps/src/index.css @@ -1,39 +1,45 @@ /* Copyright 2017-2018 @polkadot/apps 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. */ .apps--App { align-items: stretch; box-sizing: border-box; display: flex; min-height: 100vh; -} -.apps--App .apps--Content, -.apps--App .apps--SideBar, { - display: flex; - flex-direction: column; - flex-grow: 1; - overflow-y: auto; + .apps--Content, + .apps--SideBar { + display: flex; + flex-direction: column; + min-height: 100vh; + } + + .apps--Content { + background: #fafafa; + flex-grow: 1; + overflow-x: hidden; + overflow-y: auto; + } } .apps--NodeInfo { background: transparent; color: white; font-size: 0.75rem; - padding: 0 1.5rem 0 0; opacity: 0.5; + padding: 0 1.5rem 0 0; text-align: right; -} -.apps--NodeInfo > div { - margin-bottom: -0.125em; + > div { + margin-bottom: -0.125em; + } + + div.rx--updated { + background: inherit !important; + } } .apps--NodeInfo-inline > div { display: inline-block; } - -.apps--NodeInfo div.rx--updated { - background: inherit !important; -} diff --git a/packages/apps/src/index.tsx b/packages/apps/src/index.tsx index 22517450c7..a192e5b300 100644 --- a/packages/apps/src/index.tsx +++ b/packages/apps/src/index.tsx @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/apps 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'; @@ -10,6 +10,7 @@ import React from 'react'; import createApp from '@polkadot/ui-app/index'; import Signer from '@polkadot/ui-signer/index'; import classes from '@polkadot/ui-app/util/classes'; +import settings from '@polkadot/ui-settings'; import Connecting from './Connecting'; import Content from './Content'; @@ -20,7 +21,7 @@ type Props = BareProps & {}; function App (props: Props) { return ( -
+
@@ -32,12 +33,10 @@ function App (props: Props) { ); } -// tslint:disable-next-line -var url = (process.env.WS_URL === null) || (process.env.WS_URL === '') - ? undefined - : process.env.WS_URL; +const url = !settings.apiUrl + ? undefined + : settings.apiUrl; -console.log('process.env.WS_URL=', process.env.WS_URL); console.log('Web socket url=', url); createApp(App, { diff --git a/packages/apps/src/routing/accounts.ts b/packages/apps/src/routing/accounts.ts index 7c6f892841..acb43b0935 100644 --- a/packages/apps/src/routing/accounts.ts +++ b/packages/apps/src/routing/accounts.ts @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/apps 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 { Routes } from '../types'; @@ -13,6 +13,7 @@ export default ([ defaultValue: 'Accounts' }, icon: 'users', + isApiGated: true, isHidden: false, name: 'accounts' } diff --git a/packages/apps/src/routing/addresses.ts b/packages/apps/src/routing/addresses.ts index 8bf314e5a0..788eabcd3b 100644 --- a/packages/apps/src/routing/addresses.ts +++ b/packages/apps/src/routing/addresses.ts @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/apps 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 { Routes } from '../types'; @@ -13,6 +13,7 @@ export default ([ defaultValue: 'Addresses' }, icon: 'address book', + isApiGated: true, isHidden: false, name: 'addresses' } diff --git a/packages/apps/src/routing/democracy.ts b/packages/apps/src/routing/democracy.ts index a212e81196..5b70eb4a18 100644 --- a/packages/apps/src/routing/democracy.ts +++ b/packages/apps/src/routing/democracy.ts @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/apps 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 { Routes } from '../types'; @@ -13,6 +13,7 @@ export default ([ defaultValue: 'Democracy' }, icon: 'calendar check', + isApiGated: true, isHidden: false, name: 'democracy' } diff --git a/packages/apps/src/routing/example.ts b/packages/apps/src/routing/example.ts deleted file mode 100644 index de7ee58653..0000000000 --- a/packages/apps/src/routing/example.ts +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2017-2018 @polkadot/apps authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import { Routes } from '../types'; - -import Example from '@polkadot/app-example/index'; - -export default ([ - { - Component: Example, - i18n: { - defaultValue: 'Example' - }, - icon: 'hand spock', - isHidden: true, - name: 'example' - } -] as Routes); diff --git a/packages/apps/src/routing/explorer.ts b/packages/apps/src/routing/explorer.ts index 93d75ffa0f..6ffc6e5b2f 100644 --- a/packages/apps/src/routing/explorer.ts +++ b/packages/apps/src/routing/explorer.ts @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/apps 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 { Routes } from '../types'; @@ -13,6 +13,7 @@ export default ([ defaultValue: 'Explorer' }, icon: 'braille', + isApiGated: true, isHidden: false, name: 'explorer' } diff --git a/packages/apps/src/routing/extrinsics.ts b/packages/apps/src/routing/extrinsics.ts index b7e4694b6a..95c1755c5b 100644 --- a/packages/apps/src/routing/extrinsics.ts +++ b/packages/apps/src/routing/extrinsics.ts @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/apps 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 { Routes } from '../types'; @@ -13,6 +13,7 @@ export default ([ defaultValue: 'Extrinsics' }, icon: 'send', + isApiGated: true, isHidden: false, name: 'extrinsics' } diff --git a/packages/apps/src/routing/index.ts b/packages/apps/src/routing/index.ts index 3a9b6dcd76..ab2f53215b 100644 --- a/packages/apps/src/routing/index.ts +++ b/packages/apps/src/routing/index.ts @@ -1,34 +1,36 @@ // Copyright 2017-2018 @polkadot/apps 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 { Routing, - Routes } from '../types'; +import { Routing, Routes } from '../types'; + +import appSettings from '@polkadot/ui-settings'; import accounts from './accounts'; import addresses from './addresses'; import democracy from './democracy'; -import example from './example'; import explorer from './explorer'; import extrinsics from './extrinsics'; import rpc from './rpc'; +import settings from './settings'; import staking from './staking'; import storage from './storage'; import toolbox from './toolbox'; import transfer from './transfer'; import vanitygen from './vanitygen'; -const routes: Routes = process.env.UI_MODE === 'light' +const routes: Routes = appSettings.uiMode === 'light' ? ([] as Routes).concat( transfer, staking, democracy, null, accounts, - addresses + addresses, + null, + settings ) : ([] as Routes).concat( - example, explorer, transfer, staking, @@ -40,13 +42,14 @@ const routes: Routes = process.env.UI_MODE === 'light' storage, extrinsics, null, + settings, vanitygen, rpc, toolbox ); export default ({ - default: process.env.UI_MODE === 'light' + default: appSettings.uiMode === 'light' ? 'transfer' : 'explorer', routes diff --git a/packages/apps/src/routing/rpc.ts b/packages/apps/src/routing/rpc.ts index f5214420ef..7222f8d4ad 100644 --- a/packages/apps/src/routing/rpc.ts +++ b/packages/apps/src/routing/rpc.ts @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/apps 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 { Routes } from '../types'; @@ -13,6 +13,7 @@ export default ([ defaultValue: 'Raw RPC' }, icon: 'code', + isApiGated: true, isHidden: false, name: 'rpc' } diff --git a/packages/apps/src/routing/settings.ts b/packages/apps/src/routing/settings.ts new file mode 100644 index 0000000000..1d50cdaf38 --- /dev/null +++ b/packages/apps/src/routing/settings.ts @@ -0,0 +1,20 @@ +// Copyright 2017-2018 @polkadot/apps 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 { Routes } from '../types'; + +import Settings from '@polkadot/app-settings/index'; + +export default ([ + { + Component: Settings, + i18n: { + defaultValue: 'Settings' + }, + icon: 'settings', + isApiGated: false, + isHidden: false, + name: 'settings' + } +] as Routes); diff --git a/packages/apps/src/routing/staking.ts b/packages/apps/src/routing/staking.ts index 415f0de9f2..145a8ce824 100644 --- a/packages/apps/src/routing/staking.ts +++ b/packages/apps/src/routing/staking.ts @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/apps 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 { Routes } from '../types'; @@ -13,6 +13,7 @@ export default ([ defaultValue: 'Staking' }, icon: 'certificate', + isApiGated: true, isHidden: false, name: 'staking' } diff --git a/packages/apps/src/routing/storage.ts b/packages/apps/src/routing/storage.ts index 85de14cbda..3586925677 100644 --- a/packages/apps/src/routing/storage.ts +++ b/packages/apps/src/routing/storage.ts @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/apps 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 { Routes } from '../types'; @@ -13,6 +13,7 @@ export default ([ defaultValue: 'Chain state' }, icon: 'database', + isApiGated: true, isHidden: false, name: 'chainstate' } diff --git a/packages/apps/src/routing/toolbox.ts b/packages/apps/src/routing/toolbox.ts index 6dc184d2ae..4af9585382 100644 --- a/packages/apps/src/routing/toolbox.ts +++ b/packages/apps/src/routing/toolbox.ts @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/apps 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 { Routes } from '../types'; @@ -13,6 +13,7 @@ export default ([ defaultValue: 'Toolbox' }, icon: 'configure', + isApiGated: true, isHidden: false, name: 'toolbox' } diff --git a/packages/apps/src/routing/transfer.ts b/packages/apps/src/routing/transfer.ts index de7980d309..66f678a48b 100644 --- a/packages/apps/src/routing/transfer.ts +++ b/packages/apps/src/routing/transfer.ts @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/apps 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 { Routes } from '../types'; @@ -13,6 +13,7 @@ export default ([ defaultValue: 'Transfer' }, icon: 'angle double right', + isApiGated: true, isHidden: false, name: 'transfer' } diff --git a/packages/apps/src/routing/vanitygen.ts b/packages/apps/src/routing/vanitygen.ts index 50e3436059..c285a1c329 100644 --- a/packages/apps/src/routing/vanitygen.ts +++ b/packages/apps/src/routing/vanitygen.ts @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/apps 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 { Routes } from '../types'; @@ -13,6 +13,7 @@ export default ([ defaultValue: 'Vanity' }, icon: 'hand lizard', + isApiGated: true, isHidden: false, name: 'vanitygen' } diff --git a/packages/apps/src/static/parity-substrate-white.svg b/packages/apps/src/static/parity-substrate-white.svg deleted file mode 100644 index 0eb6ad15dd..0000000000 --- a/packages/apps/src/static/parity-substrate-white.svg +++ /dev/null @@ -1 +0,0 @@ -parity-substrate-3 diff --git a/packages/apps/src/static/parity-substrate.svg b/packages/apps/src/static/parity-substrate.svg deleted file mode 100644 index b894a59985..0000000000 --- a/packages/apps/src/static/parity-substrate.svg +++ /dev/null @@ -1 +0,0 @@ -parity-substrate-3 \ No newline at end of file diff --git a/packages/apps/src/static/polkadot-white.svg b/packages/apps/src/static/polkadot-white.svg deleted file mode 100644 index 4023c9daa1..0000000000 --- a/packages/apps/src/static/polkadot-white.svg +++ /dev/null @@ -1,104 +0,0 @@ - diff --git a/packages/apps/src/static/polkadot.svg b/packages/apps/src/static/polkadot.svg deleted file mode 100644 index 5cb9729be5..0000000000 --- a/packages/apps/src/static/polkadot.svg +++ /dev/null @@ -1,104 +0,0 @@ - diff --git a/packages/apps/src/translate.ts b/packages/apps/src/translate.ts index df5a100d9a..32a5b64524 100644 --- a/packages/apps/src/translate.ts +++ b/packages/apps/src/translate.ts @@ -1,7 +1,7 @@ // Copyright 2017-2018 @polkadot/apps 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(['apps', 'ui']); +export default withNamespaces(['apps', 'ui']); diff --git a/packages/apps/src/types.d.ts b/packages/apps/src/types.ts similarity index 71% rename from packages/apps/src/types.d.ts rename to packages/apps/src/types.ts index ec0f186bf0..3335e937a8 100644 --- a/packages/apps/src/types.d.ts +++ b/packages/apps/src/types.ts @@ -1,18 +1,21 @@ // Copyright 2017-2018 @polkadot/apps 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 { SemanticICONS } from 'semantic-ui-react/dist/commonjs'; import { BareProps } from '@polkadot/ui-app/types'; +import { ActionStatus } from '@polkadot/ui-app/Status/types'; export type RouteProps = BareProps & { - basePath: string -} + basePath: string, + onStatusChange: (status: ActionStatus) => void +}; export type Route = { Component: React.ComponentType, i18n: any, // I18Next$Translate$Config, icon: SemanticICONS, + isApiGated: boolean, isHidden: boolean, name: string }; @@ -22,4 +25,4 @@ export type Routes = Array; export type Routing = { default: string, routes: Routes -} +}; diff --git a/packages/apps/webpack.config.js b/packages/apps/webpack.config.js index 142b83ab52..af490a4c68 100644 --- a/packages/apps/webpack.config.js +++ b/packages/apps/webpack.config.js @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/apps 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. const fs = require('fs'); const path = require('path'); @@ -14,23 +14,24 @@ const packages = [ 'app-accounts', 'app-addresses', 'app-democracy', - 'app-example', 'app-explorer', 'app-extrinsics', 'app-rpc', + 'app-settings', 'app-staking', 'app-storage', 'app-toolbox', 'app-transfer', 'app-vanitygen', 'ui-app', - 'ui-identicon', - 'ui-keyring', 'ui-react-rx', - 'ui-react', 'ui-signer' ]; +const DEFAULT_THEME = process.env.TRAVIS_BRANCH === 'next' + ? 'substrate' + : 'polkadot'; + function createWebpack ({ alias = {}, context, name = 'index' }) { const pkgJson = require(path.join(context, 'package.json')); const ENV = process.env.NODE_ENV || 'development'; @@ -46,9 +47,10 @@ function createWebpack ({ alias = {}, context, name = 'index' }) { entry: `./src/${name}.tsx`, mode: ENV, output: { - path: path.join(context, 'build'), + chunkFilename: `[name].[chunkhash:8].js`, filename: `[name].[hash:8].js`, - chunkFilename: `[name].[chunkhash:8].js` + globalObject: `(typeof self !== 'undefined' ? self : this)`, + path: path.join(context, 'build') }, resolve: { alias, @@ -174,7 +176,7 @@ function createWebpack ({ alias = {}, context, name = 'index' }) { NODE_ENV: JSON.stringify(ENV), VERSION: JSON.stringify(pkgJson.version), UI_MODE: JSON.stringify(process.env.UI_MODE || 'full'), - UI_THEME: JSON.stringify(process.env.UI_THEME || 'polkadot'), + UI_THEME: JSON.stringify(process.env.UI_THEME || DEFAULT_THEME), WS_URL: JSON.stringify(process.env.WS_URL) } }), diff --git a/packages/ui-app/LICENSE b/packages/ui-app/LICENSE index c401843d44..0d381b2e97 100644 --- a/packages/ui-app/LICENSE +++ b/packages/ui-app/LICENSE @@ -1,15 +1,201 @@ -ISC License (ISC) + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ -Copyright 2017-2018 @polkadot/ui-app 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. diff --git a/packages/ui-app/package.json b/packages/ui-app/package.json index cae60be498..dec5fee5ee 100644 --- a/packages/ui-app/package.json +++ b/packages/ui-app/package.json @@ -1,6 +1,6 @@ { "name": "@polkadot/ui-app", - "version": "0.20.30", + "version": "0.21.0", "main": "index.js", "repository": "https://github.com/polkadot-js/apps.git", "author": "Jaco Greeff ", @@ -8,35 +8,35 @@ "Jaco Greeff " ], "contributors": [], - "license": "ISC", + "license": "Apache-2.0", "dependencies": { - "@babel/runtime": "^7.0.0", - "@polkadot/extrinsics": "^0.29.7", - "@polkadot/storage": "^0.29.7", - "@polkadot/ui-keyring": "^0.20.30", - "@polkadot/ui-react": "^0.20.30", - "@polkadot/ui-react-rx": "^0.20.30", - "@types/chart.js": "^2.7.32", + "@babel/runtime": "^7.2.0", + "@polkadot/types": "^0.35.9", + "@polkadot/ui-identicon": "^0.24.9", + "@polkadot/ui-keyring": "^0.24.9", + "@polkadot/ui-react-rx": "^0.21.0", + "@polkadot/ui-settings": "^0.24.9", + "@types/chart.js": "^2.7.42", + "@types/i18next": "^12.1.0", "@types/i18next-browser-languagedetector": "^2.0.1", "@types/i18next-xhr-backend": "^1.4.1", "@types/react-copy-to-clipboard": "^4.2.6", "@types/react-dropzone": "^4.2.2", - "@types/react-i18next": "^7.8.2", "@types/react-router-dom": "^4.3.0q", "chart.js": "^2.7.2", - "i18next": "^11.7.0", - "i18next-browser-languagedetector": "^2.2.3", + "i18next": "^12.1.0", + "i18next-browser-languagedetector": "^2.2.4", "i18next-xhr-backend": "^1.5.1", - "react": "^16.5.0", + "react": "^16.7.0", "react-chartjs-2": "^2.7.4", "react-copy-to-clipboard": "^5.0.1", - "react-dom": "^16.5.0", - "react-dropzone": "^5.0.1", - "react-i18next": "^7.11.1", + "react-dom": "^16.7.0", + "react-dropzone": "^7.0.1", + "react-i18next": "^8.3.8", "react-router": "^4.3.1", "react-router-dom": "^4.3.1", "semantic-ui-css": "^2.3.1", - "semantic-ui-react": "^0.82.3", + "semantic-ui-react": "^0.84.0", "store": "^2.0.12" } } diff --git a/packages/ui-app/src/AddressMini.tsx b/packages/ui-app/src/AddressMini.tsx index 39e83f3b4d..1db28e3b99 100644 --- a/packages/ui-app/src/AddressMini.tsx +++ b/packages/ui-app/src/AddressMini.tsx @@ -1,34 +1,42 @@ // Copyright 2017-2018 @polkadot/app-staking 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 { BareProps } from './types'; import BN from 'bn.js'; import React from 'react'; -import IdentityIcon from '@polkadot/ui-react/IdentityIcon'; +import { AccountId, AccountIndex, Address, Balance } from '@polkadot/types'; +import { withMulti, withObservable } from '@polkadot/ui-react-rx/with/index'; import classes from './util/classes'; import toShortAddress from './util/toShortAddress'; -import Balance from './Balance'; +import BalanceDisplay from './Balance'; +import IdentityIcon from './IdentityIcon'; type Props = BareProps & { - balance?: BN | Array, + balance?: Balance | Array | BN, children?: React.ReactNode, isPadded?: boolean, isShort?: boolean, - value?: string, + sessionValidators?: Array, + value?: AccountId | AccountIndex | Address | string, withBalance?: boolean }; -export default class AddressMini extends React.PureComponent { +class AddressMini extends React.PureComponent { render () { - const { children, className, isPadded = true, isShort = true, style, value } = this.props; + const { children, className, isPadded = true, isShort = true, sessionValidators = [], style, value } = this.props; if (!value) { return null; } + const address = value.toString(); + const isValidator = sessionValidators.find((validator) => + validator.toString() === address + ); + return (
{ >
-
{isShort ? toShortAddress(value) : value}
+
{isShort ? toShortAddress(address) : address}
{children}
{this.renderBalance()} @@ -55,7 +64,7 @@ export default class AddressMini extends React.PureComponent { } return ( - { ); } } + +export default withMulti( + AddressMini, + withObservable('sessionValidators') +); diff --git a/packages/ui-app/src/AddressRow.tsx b/packages/ui-app/src/AddressRow.tsx index b15236d887..6ccbfd2249 100644 --- a/packages/ui-app/src/AddressRow.tsx +++ b/packages/ui-app/src/AddressRow.tsx @@ -1,10 +1,9 @@ // Copyright 2017-2018 @polkadot/ui-app 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 React from 'react'; - -import IdentityIcon from '@polkadot/ui-react/IdentityIcon'; +import { withMulti, withObservable } from '@polkadot/ui-react-rx/with/index'; import classes from './util/classes'; import { AddressSummary } from './AddressSummary'; @@ -12,20 +11,15 @@ import translate from './translate'; class AddressRow extends AddressSummary { render () { - const { className, style, identIconSize } = this.props; - const { address, isValid } = this.state; + const { className, style, identIconSize = 64, value } = this.props; return (
- + {this.renderIcon('ui--AddressRow-icon', identIconSize)}
{this.renderAddress()} {this.renderBalance()} @@ -38,4 +32,9 @@ class AddressRow extends AddressSummary { } } -export default translate(AddressRow); +export default withMulti( + AddressRow, + translate, + withObservable('accountIdAndIndex', { paramProp: 'value' }), + withObservable('sessionValidators') +); diff --git a/packages/ui-app/src/AddressSummary.tsx b/packages/ui-app/src/AddressSummary.tsx index a7fd0e421c..16a1c27183 100644 --- a/packages/ui-app/src/AddressSummary.tsx +++ b/packages/ui-app/src/AddressSummary.tsx @@ -1,70 +1,43 @@ // Copyright 2017-2018 @polkadot/ui-app 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 { I18nProps } from './types'; -import BN from 'bn.js'; import React from 'react'; -import IdentityIcon from '@polkadot/ui-react/IdentityIcon'; -import Nonce from '@polkadot/ui-react-rx/Nonce'; -import addressDecode from '@polkadot/util-keyring/address/decode'; -import addressEncode from '@polkadot/util-keyring/address/encode'; +import { AccountId, AccountIndex, Address, Balance } from '@polkadot/types'; +import { Nonce } from '@polkadot/ui-react-rx/index'; +import { withMulti, withObservable } from '@polkadot/ui-react-rx/with/index'; import classes from './util/classes'; import toShortAddress from './util/toShortAddress'; -import Balance from './Balance'; -import CopyButton from './CopyButton'; +import BalanceDisplay from './Balance'; +import IdentityIcon from './IdentityIcon'; import translate from './translate'; export type Props = I18nProps & { - balance?: BN | Array, + accountIdAndIndex?: [AccountId | undefined, AccountIndex | undefined], + balance?: Balance | Array, children?: React.ReactNode, name?: string, - value: string | Uint8Array | null, + value: AccountId | AccountIndex | Address | string | null, withBalance?: boolean, + withIndex?: boolean, identIconSize?: number, - isShort?: boolean + isShort?: boolean, + sessionValidators?: Array, withCopy?: boolean, withIcon?: boolean, withNonce?: boolean }; -export type State = { - address: string, - isValid: boolean, - publicKey: Uint8Array | null, - shortValue: string -}; - const DEFAULT_ADDR = '5'.padEnd(16, 'x'); -const DEFAULT_SHORT = toShortAddress(DEFAULT_ADDR); - -class AddressSummary extends React.PureComponent { - state: State = {} as State; - - static getDerivedStateFromProps ({ value }: Props, { address, publicKey, shortValue }: State): State { - try { - publicKey = addressDecode(value as string); - address = addressEncode(publicKey); - shortValue = toShortAddress(address); - } catch (error) { - publicKey = null; - } - - const isValid = !!publicKey && publicKey.length === 32; - - return { - address: isValid ? address : DEFAULT_ADDR, - isValid, - publicKey, - shortValue: isValid ? shortValue : DEFAULT_SHORT - }; - } +class AddressSummary extends React.PureComponent { render () { - const { className, style } = this.props; - const { isValid } = this.state; + const { accountIdAndIndex = [], className, style } = this.props; + const [accountId, accountIndex] = accountIdAndIndex; + const isValid = accountId || accountIndex; return (
{ >
{this.renderIcon()} - {this.renderAddress()} + {this.renderAccountId()} + {this.renderAccountIndex()} {this.renderBalance()} {this.renderNonce()}
@@ -83,84 +57,148 @@ class AddressSummary extends React.PureComponent { } protected renderAddress () { - const { name, value, isShort = true } = this.props; - const { shortValue } = this.state; + const { name, isShort = true, value } = this.props; + + if (!value) { + return null; + } + + const address = value.toString(); return (
{name}
-
- {isShort ? shortValue : value} +
+ { + isShort + ? toShortAddress(address) + : value + } +
+ {this.renderCopy(address)} +
+ ); + } + + protected renderAccountId () { + const { accountIdAndIndex = [], name, isShort = true } = this.props; + const [accountId, accountIndex] = accountIdAndIndex; + + if (!accountId && accountIndex) { + return null; + } + + const address = accountId + ? accountId.toString() + : DEFAULT_ADDR; + + return ( +
+
+ {name} +
+
+ { + isShort + ? toShortAddress(address) + : address + } +
+ {this.renderCopy(address)} +
+ ); + } + + protected renderAccountIndex () { + const { accountIdAndIndex = [] } = this.props; + const [, accountIndex] = accountIdAndIndex; + + if (!accountIndex) { + return null; + } + + const address = accountIndex.toString(); + + return ( +
+
+
+ {address}
- {this.renderCopy()}
); } protected renderBalance () { - const { isValid, publicKey } = this.state; - const { balance, t, withBalance = true } = this.props; + const { balance, t, withBalance = true, value } = this.props; - if (!withBalance || !isValid || !publicKey) { + if (!withBalance) { return null; } return ( - ); } - protected renderCopy () { - const { withCopy = true } = this.props; - const { address, publicKey } = this.state; + protected renderCopy (address: string) { + return null; - if (!withCopy || !publicKey) { - return null; - } + // const { withCopy = true } = this.props; - return ( - - ); + // if (!withCopy || !address) { + // return null; + // } + + // return ( + // + // ); } - protected renderIcon () { - const { identIconSize = 96, withIcon = true } = this.props; - const { address } = this.state; + protected renderIcon (className: string = 'ui--AddressSummary-icon', size?: number) { + const { accountIdAndIndex = [], identIconSize = 96, sessionValidators = [], value, withIcon = true } = this.props; if (!withIcon) { return null; } + const [_accountId] = accountIdAndIndex; + const accountId = (_accountId || '').toString(); + const isValidator = sessionValidators.find((validator) => + validator.toString() === accountId + ); + return ( ); } protected renderNonce () { - const { isValid, publicKey } = this.state; - const { t, withNonce = true } = this.props; + const { accountIdAndIndex = [], t, withNonce = true } = this.props; + const [accountId] = accountIdAndIndex; - if (!withNonce || !isValid) { + if (!withNonce || !accountId) { return null; } return ( {t('addressSummary.transactions', { defaultValue: ' transactions' @@ -186,8 +224,12 @@ class AddressSummary extends React.PureComponent { export { DEFAULT_ADDR, - DEFAULT_SHORT, AddressSummary }; -export default translate(AddressSummary); +export default withMulti( + AddressSummary, + translate, + withObservable('accountIdAndIndex', { paramProp: 'value' }), + withObservable('sessionValidators') +); diff --git a/packages/ui-app/src/Balance.tsx b/packages/ui-app/src/Balance.tsx index 8e464f5240..bd29cdcff3 100644 --- a/packages/ui-app/src/Balance.tsx +++ b/packages/ui-app/src/Balance.tsx @@ -1,27 +1,32 @@ // Copyright 2017-2018 @polkadot/ui-app 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 { BareProps } from './types'; import BN from 'bn.js'; import React from 'react'; +import { AccountId, AccountIndex, Address, Balance } from '@polkadot/types'; import RxBalance from '@polkadot/ui-react-rx/Balance'; -import numberFormat from '@polkadot/ui-react-rx/util/numberFormat'; +import { balanceFormat } from '@polkadot/ui-react-rx/util/index'; import classes from './util/classes'; export type Props = BareProps & { - balance?: BN | Array, + balance?: Balance | Array | BN, label?: string, - value: string | Uint8Array, + value?: AccountId | AccountIndex | Address | string | Uint8Array | null, withLabel?: boolean }; -export default class Balance extends React.PureComponent { +export default class BalanceDisplay extends React.PureComponent { render () { const { balance, className, label, value, style } = this.props; + if (!value) { + return null; + } + return balance ? this.renderProvided() : ( @@ -41,16 +46,15 @@ export default class Balance extends React.PureComponent { return null; } - let value = `${numberFormat(Array.isArray(balance) ? balance[0] : balance)}`; + let value = `${balanceFormat(Array.isArray(balance) ? balance[0] : balance)}`; if (Array.isArray(balance)) { - const totals = balance - .filter((value, index) => - index !== 0 - ) - .map(numberFormat); + const totals = balance.filter((value, index) => index !== 0); + const total = totals.reduce((total, value) => total.add(value), new BN(0)).gtn(0) + ? `(+${totals.map((balance) => balanceFormat(balance)).join(', ')})` + : ''; - value = `${value} (${totals.length === 1 ? '+' : ''}${totals.join(', ')})`; + value = `${value} ${total}`; } return ( diff --git a/packages/ui-app/src/Button/Button.css b/packages/ui-app/src/Button/Button.css index a388db53c1..7d811f9187 100644 --- a/packages/ui-app/src/Button/Button.css +++ b/packages/ui-app/src/Button/Button.css @@ -1,6 +1,6 @@ /* Copyright 2017-2018 @polkadot/ui-app 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. */ .ui--Button-Group { text-align: right; diff --git a/packages/ui-app/src/Button/Button.tsx b/packages/ui-app/src/Button/Button.tsx new file mode 100644 index 0000000000..6900c23f42 --- /dev/null +++ b/packages/ui-app/src/Button/Button.tsx @@ -0,0 +1,43 @@ +// Copyright 2017-2018 @polkadot/ui-app 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 { ButtonProps } from './types'; + +import React from 'react'; +import SUIButton from 'semantic-ui-react/dist/commonjs/elements/Button/Button'; + +import { isUndefined } from '@polkadot/util'; + +export default class Button extends React.PureComponent { + render () { + const { children, className, floated, icon, isBasic = false, isCircular = false, isDisabled = false, isNegative = false, isPositive = false, isPrimary = false, onClick, size, style, tabIndex, text } = this.props; + + const props = { + basic: isBasic || false, + circular: isCircular, + className, + disabled: isDisabled, + floated, + icon, + negative: isNegative, + onClick, + positive: isPositive, + primary: isPrimary, + size, + secondary: isBasic && !(isPositive || isPrimary || isNegative || false), + style, + tabIndex + }; + + return isUndefined(text) && isUndefined(children) + ? ( + + ) + : ( + + {text}{children} + + ); + } +} diff --git a/packages/ui-app/src/Button/Divider.tsx b/packages/ui-app/src/Button/Divider.tsx index bede6904ca..7427e59bce 100644 --- a/packages/ui-app/src/Button/Divider.tsx +++ b/packages/ui-app/src/Button/Divider.tsx @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/ui-app 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 { DividerProps } from './types'; diff --git a/packages/ui-app/src/Button/Group.tsx b/packages/ui-app/src/Button/Group.tsx index 9a00902d87..d358ce0144 100644 --- a/packages/ui-app/src/Button/Group.tsx +++ b/packages/ui-app/src/Button/Group.tsx @@ -1,17 +1,15 @@ // Copyright 2017-2018 @polkadot/ui-app 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 { GroupProps, GroupType } from './types'; import React from 'react'; import SUIButton from 'semantic-ui-react/dist/commonjs/elements/Button/Button'; -import Button from '@polkadot/ui-app/Button'; import classes from '../util/classes'; import Divider from './Divider'; -// ({ children, className, style }: GroupProps) class ButtonGroup extends React.PureComponent { render () { const { children, className, style } = this.props; @@ -22,7 +20,7 @@ class ButtonGroup extends React.PureComponent { style={style} > - + {children}
diff --git a/packages/ui-app/src/Button/Or.tsx b/packages/ui-app/src/Button/Or.tsx index e6b709a7ce..e85b9cf557 100644 --- a/packages/ui-app/src/Button/Or.tsx +++ b/packages/ui-app/src/Button/Or.tsx @@ -1,13 +1,12 @@ // Copyright 2017-2018 @polkadot/ui-app 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 '../types'; import React from 'react'; import SUIButton from 'semantic-ui-react/dist/commonjs/elements/Button/Button'; - -import isUndefined from '@polkadot/util/is/undefined'; +import { isUndefined } from '@polkadot/util'; import translate from '../translate'; diff --git a/packages/ui-app/src/Button/index.tsx b/packages/ui-app/src/Button/index.tsx index 4c9c0f254d..c2456e43dd 100644 --- a/packages/ui-app/src/Button/index.tsx +++ b/packages/ui-app/src/Button/index.tsx @@ -1,53 +1,16 @@ // Copyright 2017-2018 @polkadot/ui-app 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 { ButtonProps, ButtonType } from './types'; +import { ButtonType } from './types'; import './Button.css'; -import React from 'react'; -import SUIButton from 'semantic-ui-react/dist/commonjs/elements/Button/Button'; - -import isUndefined from '@polkadot/util/is/undefined'; - +import Button from './Button'; import Divider from './Divider'; import Group from './Group'; import Or from './Or'; -class Button extends React.PureComponent { - render () { - const { children, className, floated, icon, isBasic = false, isCircular = false, isDisabled = false, isNegative = false, isPositive = false, isPrimary = false, onClick, size, style, tabIndex, text } = this.props; - - const props = { - basic: isBasic || false, - circular: isCircular, - className, - disabled: isDisabled, - floated, - icon, - negative: isNegative, - onClick, - positive: isPositive, - primary: isPrimary, - size, - secondary: isBasic && !(isPositive || isPrimary || isNegative || false), - style, - tabIndex - }; - - return isUndefined(text) && isUndefined(children) - ? ( - - ) - : ( - - {text}{children} - - ); - } -} - (Button as ButtonType).Divider = Divider; (Button as ButtonType).Group = Group; (Button as ButtonType).Or = Or; diff --git a/packages/ui-app/src/Button/types.d.ts b/packages/ui-app/src/Button/types.ts similarity index 93% rename from packages/ui-app/src/Button/types.d.ts rename to packages/ui-app/src/Button/types.ts index 3f6d32676d..1dfde1391d 100644 --- a/packages/ui-app/src/Button/types.d.ts +++ b/packages/ui-app/src/Button/types.ts @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/ui-app 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 '../types'; @@ -30,10 +30,10 @@ export type GroupProps = BareProps & { export type GroupType = React.ComponentType & { Divider: React.ComponentType -} +}; export type ButtonType = React.ComponentType & { Divider: React.ComponentType, Group: GroupType, Or: React.ComponentType -} +}; diff --git a/packages/ui-app/src/Call.tsx b/packages/ui-app/src/Call.tsx new file mode 100644 index 0000000000..754cb9250f --- /dev/null +++ b/packages/ui-app/src/Call.tsx @@ -0,0 +1,45 @@ +// Copyright 2017-2018 @polkadot/ui-app 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 { getTypeDef } from '@polkadot/types/codec'; +import { BareProps } from './types'; + +import React from 'react'; +import { Extrinsic, Method, Proposal } from '@polkadot/types'; + +import classes from './util/classes'; +import Params from './Params'; + +export type Props = BareProps & { + children?: React.ReactNode, + value: Extrinsic | Method | Proposal +}; + +export default class Call extends React.PureComponent { + render () { + const { children, className, style, value } = this.props; + const params = Method.filterOrigin(value.meta).map(({ name, type }) => ({ + name: name.toString(), + type: getTypeDef(type) + })); + const values = value.args.map((value) => ({ + isValid: true, + value + })); + + return ( +
+ {children} + +
+ ); + } +} diff --git a/packages/ui-app/src/CardSummary.tsx b/packages/ui-app/src/CardSummary.tsx index f23ce9522c..d2ddd41a9d 100644 --- a/packages/ui-app/src/CardSummary.tsx +++ b/packages/ui-app/src/CardSummary.tsx @@ -1,12 +1,13 @@ // Copyright 2017-2018 @polkadot/ui-app 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 './types'; import BN from 'bn.js'; import React from 'react'; -import isUndefined from '@polkadot/util/is/undefined'; +import { UInt } from '@polkadot/types/codec'; +import { isUndefined } from '@polkadot/util'; import Progress, { Colors as ProgressColors } from './Progress'; import Labelled from './Labelled'; @@ -14,9 +15,10 @@ import classes from './util/classes'; type ProgressProps = { color?: ProgressColors, + hideValue?: boolean, isPercent?: boolean, - total?: BN, - value?: BN + total?: BN | UInt, + value?: BN | UInt }; type Props = BareProps & { @@ -28,18 +30,20 @@ type Props = BareProps & { export default class CardSummary extends React.PureComponent { render () { const { children, className, progress, label, style } = this.props; - const left = progress && !isUndefined(progress.value) && !isUndefined(progress.total) && progress.value.gten(0) && progress.total.gtn(0) + const value = progress && progress.value; + const total = progress && progress.total; + const left = progress && !isUndefined(value) && !isUndefined(total) && value.gten(0) && total.gtn(0) ? ( - progress.value.gt(progress.total) + value.gt(total) ? `>${ progress.isPercent ? '100' - : progress.total.toString() + : total.toString() }` : ( progress.isPercent - ? progress.value.muln(100).div(progress.total).toString() - : progress.value.toString() + ? value.muln(100).div(total).toString() + : value.toString() ) ) : undefined; @@ -52,7 +56,7 @@ export default class CardSummary extends React.PureComponent {
{children}{ - progress && ( + progress && !progress.hideValue && ( !left || isUndefined(progress.total) ? '-' : `${left}${progress.isPercent ? '' : '/'}${ diff --git a/packages/ui-app/src/Chart/Doughnut.tsx b/packages/ui-app/src/Chart/Doughnut.tsx index 3b164c313c..a118308444 100644 --- a/packages/ui-app/src/Chart/Doughnut.tsx +++ b/packages/ui-app/src/Chart/Doughnut.tsx @@ -1,13 +1,13 @@ // Copyright 2017-2018 @polkadot/ui-app 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 '../types'; import BN from 'bn.js'; import React from 'react'; import { Doughnut } from 'react-chartjs-2'; -import bnToBn from '@polkadot/util/bn/toBn'; +import { bnToBn } from '@polkadot/util'; import classes from '../util/classes'; @@ -62,7 +62,8 @@ export default class ChartDoughnut extends React.PureComponent { }] }} height={size} - width={size} /> + width={size} + />
); } diff --git a/packages/ui-app/src/Chart/index.ts b/packages/ui-app/src/Chart/index.ts new file mode 100644 index 0000000000..a14e118d1a --- /dev/null +++ b/packages/ui-app/src/Chart/index.ts @@ -0,0 +1,9 @@ +// Copyright 2017-2018 @polkadot/ui-app 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 Doughnut from './Doughnut'; + +export default { + Doughnut +}; diff --git a/packages/ui-app/src/CopyButton.tsx b/packages/ui-app/src/CopyButton.tsx index d2c5b0a112..530c154838 100644 --- a/packages/ui-app/src/CopyButton.tsx +++ b/packages/ui-app/src/CopyButton.tsx @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/ui-app 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 { Button$Sizes } from './Button/types'; import { BareProps } from './types'; diff --git a/packages/ui-app/src/Dropdown.tsx b/packages/ui-app/src/Dropdown.tsx index f956575f2b..746d90a52b 100644 --- a/packages/ui-app/src/Dropdown.tsx +++ b/packages/ui-app/src/Dropdown.tsx @@ -1,23 +1,25 @@ // Copyright 2017-2018 @polkadot/ui-app 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 './types'; import React from 'react'; -import SUIDropdown from 'semantic-ui-react/dist/commonjs/modules/Dropdown/Dropdown'; -import isUndefined from '@polkadot/util/is/undefined'; +import SUIButton from 'semantic-ui-react/dist/commonjs/elements/Button/Button'; +import SUIDropdown, { DropdownProps } from 'semantic-ui-react/dist/commonjs/modules/Dropdown/Dropdown'; +import { isUndefined } from '@polkadot/util'; import classes from './util/classes'; import Labelled from './Labelled'; type Props
); } + private renderSiDropdown () { + const { isSi } = this.props; + const { siOptions, siUnit } = this.state; + + if (!isSi) { + return undefined; + } + + return ( + + ); + } + private maxValue = (bitLength?: number): BN => new BN(2).pow(new BN(bitLength || DEFAULT_BITLENGTH)).subn(1) - // check if string value is non-integer even if above MAX_SAFE_INTEGER. isNaN(Number(value)) is faster for values of length 1 - private isNonInteger = (value: string): boolean => - value && value.length && value.split('').find(value => '0123456789'.indexOf(value) === -1) ? true : false - private isValidBitLength = (value: BN, bitLength?: number): boolean => value.bitLength() <= (bitLength || DEFAULT_BITLENGTH) @@ -115,26 +154,10 @@ class InputNumber extends React.PureComponent { return true; } - private isValidNumber = (input: string, bitLength?: number): boolean => { - const { t } = this.props; - bitLength = bitLength || DEFAULT_BITLENGTH; - - // failsafe as expects only positive integers as permitted by onKeyDown from input of type text - if (!isString(input)) { - throw Error(t('inputnumber.error.string.required', { - defaultValue: 'Number input value must be valid type' - })); - } - - if (this.isNonInteger(input)) { - return false; - } - - // max is (2 ** 128 - 1) for bitLength of 128 bit + private isValidNumber = (input: BN, bitLength: number = DEFAULT_BITLENGTH): boolean => { const maxBN = this.maxValue(bitLength); - const inputBN = new BN(input); - if (!inputBN.lt(maxBN) || !this.isValidBitLength(inputBN, bitLength)) { + if (!input.lt(maxBN) || !this.isValidBitLength(input, bitLength)) { return false; } @@ -143,18 +166,19 @@ class InputNumber extends React.PureComponent { private onChange = (value: string): void => { const { bitLength, onChange } = this.props; + const { siUnit } = this.state; try { - const valueBN = new BN(value || 0); - const isValid = this.isValidNumber(value, bitLength); + const valueBN = this.applySi(siUnit, new BN(value || 0)); + const isValid = this.isValidNumber(valueBN, bitLength); - this.setState({ isValid }); + this.setState({ isValid, valueBN }); - if (!onChange || !isValid) { - return; - } - - onChange(valueBN); + onChange( + isValid + ? valueBN + : undefined + ); } catch (error) { console.error(error); } @@ -162,10 +186,6 @@ class InputNumber extends React.PureComponent { private onKeyDown = (event: React.KeyboardEvent): void => { const { isPreKeyDown } = this.state; - const { value: previousValue } = event.target as HTMLInputElement; - - // store previous input field in state incase user pastes invalid value and we need to revert the input value - this.setState({ previousValue }); if (KEYS_PRE.includes(event.key)) { this.setState({ isPreKeyDown: true }); @@ -202,6 +222,40 @@ class InputNumber extends React.PureComponent { (event.target as HTMLInputElement).value = newValue.replace(/^0+/, ''); } } + + private applySi (siUnit: string, value: BN): BN { + const si = balanceFormat.findSi(siUnit); + const power = new BN(balanceFormat.getDefaultDecimals() + si.power); + + return value.mul(new BN(10).pow(power)); + } + + private applyNewSi (oldSi: string, newSi: string, value: BN): BN { + const si = balanceFormat.findSi(oldSi); + const power = new BN(balanceFormat.getDefaultDecimals() + si.power); + + return this.applySi(newSi, value.div(new BN(10).pow(power))); + } + + private selectSiUnit = (siUnit: string): void => { + this.setState((prevState: State) => { + const { bitLength, onChange } = this.props; + const valueBN = this.applyNewSi(prevState.siUnit, siUnit, prevState.valueBN); + const isValid = this.isValidNumber(valueBN, bitLength); + + onChange( + isValid + ? valueBN + : undefined + ); + + return { + isValid, + siUnit, + valueBN + }; + }); + } } export { diff --git a/packages/ui-app/src/InputRpc/SelectMethod.tsx b/packages/ui-app/src/InputRpc/SelectMethod.tsx index 6a45b435e3..e4ddd3eb10 100644 --- a/packages/ui-app/src/InputRpc/SelectMethod.tsx +++ b/packages/ui-app/src/InputRpc/SelectMethod.tsx @@ -1,9 +1,8 @@ // Copyright 2017-2018 @polkadot/ui-app 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 { Interfaces, Interface$Sections } from '@polkadot/jsonrpc/types'; +import { RpcMethod } from '@polkadot/jsonrpc/types'; import { DropdownOptions } from '../util/types'; import { I18nProps } from '../types'; @@ -18,22 +17,22 @@ import translate from '../translate'; type Props = I18nProps & { isError?: boolean, label?: string, - onChange: (value: SectionItem) => void, + onChange: (value: RpcMethod) => void, options: DropdownOptions, - value: SectionItem, + value: RpcMethod, withLabel?: boolean }; class SelectMethod extends React.PureComponent { render () { - const { className, isError, label = '', onChange, options, style, t, value: { name, section }, withLabel } = this.props; + const { className, isError, label = '', onChange, options, style, t, value, withLabel } = this.props; if (!options.length) { return null; } - const transform = (name: Interface$Sections): SectionItem => - map[section].public[name]; + const transform = (method: string): RpcMethod => + map[value.section].methods[method]; return ( { options={options} style={style} transform={transform} - value={name} + value={value.method} withLabel={withLabel} /> ); diff --git a/packages/ui-app/src/InputRpc/SelectSection.tsx b/packages/ui-app/src/InputRpc/SelectSection.tsx index 01524d501d..17b1b51829 100644 --- a/packages/ui-app/src/InputRpc/SelectSection.tsx +++ b/packages/ui-app/src/InputRpc/SelectSection.tsx @@ -1,9 +1,8 @@ // Copyright 2017-2018 @polkadot/ui-app 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 { Interfaces, Interface$Sections } from '@polkadot/jsonrpc/types'; +import { RpcMethod } from '@polkadot/jsonrpc/types'; import { DropdownOptions } from '../util/types'; import { I18nProps } from '../types'; @@ -14,18 +13,18 @@ import classes from '../util/classes'; import translate from '../translate'; type Props = I18nProps & { - defaultValue?: Interface$Sections, + defaultValue?: string, isError?: boolean, label?: string, - onChange: (value: Interface$Sections) => void, + onChange: (value: string) => void, options: DropdownOptions, - value: SectionItem, + value: RpcMethod, withLabel?: boolean }; class SelectSection extends React.PureComponent { render () { - const { className, defaultValue, isError, label, onChange, options, style, t, value: { section }, withLabel } = this.props; + const { className, defaultValue, isError, label, onChange, options, style, t, value, withLabel } = this.props; return ( { onChange={onChange} options={options} style={style} - value={section} + value={value.section} withLabel={withLabel} /> ); diff --git a/packages/ui-app/src/InputRpc/index.tsx b/packages/ui-app/src/InputRpc/index.tsx index 0436ec686e..94e3408f5b 100644 --- a/packages/ui-app/src/InputRpc/index.tsx +++ b/packages/ui-app/src/InputRpc/index.tsx @@ -1,18 +1,16 @@ // Copyright 2017-2018 @polkadot/ui-app 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. // TODO: We have a lot shared between this and InputExtrinsic & InputStorage -import { SectionItem } from '@polkadot/params/types'; -import { Interfaces, Interface$Sections } from '@polkadot/jsonrpc/types'; +import { RpcMethod } from '@polkadot/jsonrpc/types'; import { DropdownOptions } from '../util/types'; import { I18nProps } from '../types'; import '../InputExtrinsic/InputExtrinsic.css'; import React from 'react'; - import map from '@polkadot/jsonrpc'; import classes from '../util/classes'; @@ -23,18 +21,18 @@ import methodOptions from './options/method'; import sectionOptions from './options/section'; type Props = I18nProps & { - defaultValue: SectionItem, + defaultValue: RpcMethod, isError?: boolean, labelMethod?: string, labelSection?: string, - onChange: (value: SectionItem) => void, + onChange: (value: RpcMethod) => void, withLabel?: boolean }; type State = { optionsMethod: DropdownOptions, optionsSection: DropdownOptions, - value: SectionItem + value: RpcMethod }; class InputRpc extends React.PureComponent { @@ -81,31 +79,31 @@ class InputRpc extends React.PureComponent { ); } - onMethodChange = (value: SectionItem): void => { + private onMethodChange = (newValue: RpcMethod): void => { const { onChange } = this.props; - const { value: { name, section } } = this.state; + const { value } = this.state; - if (value.section === section && value.name === name) { + if (value.section === newValue.section && value.method === newValue.method) { return; } - this.setState({ value }, () => - onChange(value) + this.setState({ value: newValue }, () => + onChange(newValue) ); } - onSectionChange = (newSection: Interface$Sections): void => { - const { value: { section } } = this.state; + private onSectionChange = (newSection: string): void => { + const { value } = this.state; - if (newSection === section) { + if (newSection === value.section) { return; } const optionsMethod = methodOptions(newSection); - const value = map[newSection].public[optionsMethod[0].value]; + const newValue = map[newSection].methods[optionsMethod[0].value]; this.setState({ optionsMethod }, () => - this.onMethodChange(value) + this.onMethodChange(newValue) ); } } diff --git a/packages/ui-app/src/InputRpc/options/method.tsx b/packages/ui-app/src/InputRpc/options/method.tsx index 7ff492ca7b..a1a050cff4 100644 --- a/packages/ui-app/src/InputRpc/options/method.tsx +++ b/packages/ui-app/src/InputRpc/options/method.tsx @@ -1,51 +1,50 @@ // Copyright 2017-2018 @polkadot/ui-app 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 { Interface$Sections } from '@polkadot/jsonrpc/types'; import { DropdownOptions } from '../../util/types'; import React from 'react'; import map from '@polkadot/jsonrpc'; -export default function createOptions (sectionName: Interface$Sections): DropdownOptions { - const section = map[sectionName]; +export default function createOptions (sectionName: string): DropdownOptions { + const section = map[sectionName as keyof typeof map]; if (!section) { return []; } return Object - .keys(section.public) + .keys(section.methods) .sort() - .filter((name) => { - const { isDeprecated, isHidden, isSubscription } = section.public[name]; + .filter((value) => { + const { isDeprecated, isHidden, isSubscription } = section.methods[value]; return !isDeprecated && !isHidden && !isSubscription; }) - .map((name) => { - const { description, params } = section.public[name]; + .map((value) => { + const { description, params } = section.methods[value]; const inputs = params.map(({ name }) => name).join(', '); return { className: 'ui--DropdownLinked-Item', - key: `${sectionName}_${name}`, + key: `${sectionName}_${value}`, text: [
- {name}({inputs}) + {value}({inputs})
,
- {description || name} + {description || value}
], - value: name + value }; }); } diff --git a/packages/ui-app/src/InputRpc/options/section.ts b/packages/ui-app/src/InputRpc/options/section.ts index 4a4d4e90a0..d085a8aabf 100644 --- a/packages/ui-app/src/InputRpc/options/section.ts +++ b/packages/ui-app/src/InputRpc/options/section.ts @@ -1,10 +1,8 @@ // Copyright 2017-2018 @polkadot/ui-app 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 { Interface$Sections } from '@polkadot/jsonrpc/types'; import { DropdownOptions } from '../../util/types'; -import { shouldDisplaySection } from '../../util/shouldDisplaySection'; import map from '@polkadot/jsonrpc'; @@ -12,11 +10,6 @@ export default function createOptions (): DropdownOptions { return Object .keys(map) .sort() - .filter((name) => { - const section = map[name as Interface$Sections]; - - return shouldDisplaySection(section, 'public'); - }) .map((name) => ({ text: name, value: name diff --git a/packages/ui-app/src/InputStorage/SelectKey.tsx b/packages/ui-app/src/InputStorage/SelectKey.tsx index 7815b82e43..b5bf8258a7 100644 --- a/packages/ui-app/src/InputStorage/SelectKey.tsx +++ b/packages/ui-app/src/InputStorage/SelectKey.tsx @@ -1,15 +1,13 @@ // Copyright 2017-2018 @polkadot/ui-app 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 { Storages } from '@polkadot/storage/types'; import { DropdownOptions } from '../util/types'; import { I18nProps } from '../types'; import React from 'react'; - -import map from '@polkadot/storage'; +import Api from '@polkadot/api-observable'; +import { StorageFunction } from '@polkadot/types/StorageKey'; import Dropdown from '../Dropdown'; import classes from '../util/classes'; @@ -18,22 +16,22 @@ import translate from '../translate'; type Props = I18nProps & { isError?: boolean, label?: string, - onChange: (value: SectionItem) => void, + onChange: (value: StorageFunction) => void, options: DropdownOptions, - value: SectionItem, + value: StorageFunction, withLabel?: boolean }; class SelectKey extends React.PureComponent { render () { - const { className, isError, label = '', onChange, options, style, t, value: { name, section }, withLabel } = this.props; + const { className, isError, label = '', onChange, options, style, t, value, withLabel } = this.props; if (!options.length) { return null; } - const transform = (name: string): SectionItem => - map[section].public[name]; + const transform = (method: string): StorageFunction => + Api.storage[value.section][method]; return ( { options={options} style={style} transform={transform} - value={name} + value={value.method} withLabel={withLabel} /> ); diff --git a/packages/ui-app/src/InputStorage/SelectSection.tsx b/packages/ui-app/src/InputStorage/SelectSection.tsx index 2b9c31989c..3891738285 100644 --- a/packages/ui-app/src/InputStorage/SelectSection.tsx +++ b/packages/ui-app/src/InputStorage/SelectSection.tsx @@ -1,9 +1,8 @@ // Copyright 2017-2018 @polkadot/ui-app 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 { Storages, Storage$Sections } from '@polkadot/storage/types'; +import { StorageFunction } from '@polkadot/types/StorageKey'; import { DropdownOptions } from '../util/types'; import { I18nProps } from '../types'; @@ -14,12 +13,12 @@ import classes from '../util/classes'; import translate from '../translate'; type Props = I18nProps & { - defaultValue?: Storage$Sections, + defaultValue?: StorageFunction, isError?: boolean, label?: string, - onChange: (value: Storage$Sections) => void, + onChange: (value: string) => void, options: DropdownOptions, - value: SectionItem, + value: StorageFunction, withLabel?: boolean }; diff --git a/packages/ui-app/src/InputStorage/index.tsx b/packages/ui-app/src/InputStorage/index.tsx index 48d92668c1..0130259b3d 100644 --- a/packages/ui-app/src/InputStorage/index.tsx +++ b/packages/ui-app/src/InputStorage/index.tsx @@ -1,19 +1,17 @@ // Copyright 2017-2018 @polkadot/ui-app 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. // TODO: We have a lot shared between this and InputExtrinsic -import { SectionItem } from '@polkadot/params/types'; -import { Storages, Storage$Sections } from '@polkadot/storage/types'; +import { StorageFunction } from '@polkadot/types/StorageKey'; import { DropdownOptions } from '../util/types'; import { I18nProps } from '../types'; import '../InputExtrinsic/InputExtrinsic.css'; import React from 'react'; - -import map from '@polkadot/storage'; +import Api from '@polkadot/api-observable'; import classes from '../util/classes'; import translate from '../translate'; @@ -23,18 +21,18 @@ import keyOptions from './options/key'; import sectionOptions from './options/section'; type Props = I18nProps & { - defaultValue: SectionItem, + defaultValue: StorageFunction, isError?: boolean, labelMethod?: string, labelSection?: string, - onChange: (value: SectionItem) => void, + onChange: (value: StorageFunction) => void, withLabel?: boolean }; type State = { optionsMethod: DropdownOptions, optionsSection: DropdownOptions, - value: SectionItem + value: StorageFunction }; class InputStorage extends React.PureComponent { @@ -43,10 +41,10 @@ class InputStorage extends React.PureComponent { constructor (props: Props) { super(props); - const { section } = this.props.defaultValue; + const method = this.props.defaultValue; this.state = { - optionsMethod: keyOptions(section), + optionsMethod: keyOptions(method.section), optionsSection: sectionOptions(), value: this.props.defaultValue }; @@ -81,31 +79,31 @@ class InputStorage extends React.PureComponent { ); } - onKeyChange = (value: SectionItem): void => { + private onKeyChange = (newValue: StorageFunction): void => { const { onChange } = this.props; - const { value: { name, section } } = this.state; + const { value } = this.state; - if (value.section === section && value.name === name) { + if (value.section === newValue.section && value.method === newValue.method) { return; } - this.setState({ value }, () => - onChange(value) + this.setState({ value: newValue }, () => + onChange(newValue) ); } - onSectionChange = (newSection: Storage$Sections): void => { - const { value: { section } } = this.state; + private onSectionChange = (newSection: string): void => { + const { value } = this.state; - if (newSection === section) { + if (newSection === value.section) { return; } const optionsMethod = keyOptions(newSection); - const value = map[newSection].public[optionsMethod[0].value]; + const newValue = Api.storage[newSection][optionsMethod[0].value]; this.setState({ optionsMethod }, () => - this.onKeyChange(value) + this.onKeyChange(newValue) ); } } diff --git a/packages/ui-app/src/InputStorage/options/key.tsx b/packages/ui-app/src/InputStorage/options/key.tsx index c0e8cf339b..1db243fd7a 100644 --- a/packages/ui-app/src/InputStorage/options/key.tsx +++ b/packages/ui-app/src/InputStorage/options/key.tsx @@ -1,51 +1,47 @@ // Copyright 2017-2018 @polkadot/ui-app 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 { Storage$Sections } from '@polkadot/storage/types'; import { DropdownOptions } from '../../util/types'; import React from 'react'; +import Api from '@polkadot/api-observable'; -import map from '@polkadot/storage'; - -export default function createOptions (sectionName: Storage$Sections): DropdownOptions { - const section = map[sectionName]; +export default function createOptions (sectionName: keyof typeof Api.storage): DropdownOptions { + const section = Api.storage[sectionName]; if (!section) { return []; } return Object - .keys(section.public) + .keys(section) .sort() - .filter((name) => { - const { isDeprecated, isHidden } = section.public[name]; - - return !isDeprecated && !isHidden; - }) - .map((name) => { - const { description, params } = section.public[name]; - const inputs = params.map(({ name }) => name).join(', '); + .map((value) => { + const method = section[value]; + const type = method.meta.type; + let input = type.isMap + ? type.asMap.key.toString() + : ''; return { className: 'ui--DropdownLinked-Item', - key: `${sectionName}_${name}`, + key: `${sectionName}_${value}`, text: [
- {name}({inputs}) + {value}({input}): {type.toString()}
,
- {description || name} + {(method.meta.documentation[0] || method.meta.name).toString()}
], - value: name + value }; }); } diff --git a/packages/ui-app/src/InputStorage/options/section.ts b/packages/ui-app/src/InputStorage/options/section.ts index 042afbe195..cbccb2f00e 100644 --- a/packages/ui-app/src/InputStorage/options/section.ts +++ b/packages/ui-app/src/InputStorage/options/section.ts @@ -1,23 +1,15 @@ // Copyright 2017-2018 @polkadot/ui-app 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 { Storage$Sections } from '@polkadot/storage/types'; import { DropdownOptions } from '../../util/types'; -import { shouldDisplaySection } from '../../util/shouldDisplaySection'; - -import map from '@polkadot/storage'; +import Api from '@polkadot/api-observable'; export default function createOptions (): DropdownOptions { return Object - .keys(map) + .keys(Api.storage) .sort() - .filter((name) => { - const section = map[name as Storage$Sections]; - - return shouldDisplaySection(section, 'public'); - }) .map((name) => ({ text: name, value: name diff --git a/packages/ui-app/src/Labelled.tsx b/packages/ui-app/src/Labelled.tsx index 37b052b212..18724e8dd8 100644 --- a/packages/ui-app/src/Labelled.tsx +++ b/packages/ui-app/src/Labelled.tsx @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/ui-app 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 './types'; diff --git a/packages/ui-app/src/Menu.tsx b/packages/ui-app/src/Menu.tsx index 77c8e809f5..713bd6a8e0 100644 --- a/packages/ui-app/src/Menu.tsx +++ b/packages/ui-app/src/Menu.tsx @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/ui-app 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 SUIDivider from 'semantic-ui-react/dist/commonjs/elements/Divider/Divider'; import SUIMenu from 'semantic-ui-react/dist/commonjs/collections/Menu/Menu'; diff --git a/packages/ui-app/src/Modal.tsx b/packages/ui-app/src/Modal.tsx index da99502619..244c36a966 100644 --- a/packages/ui-app/src/Modal.tsx +++ b/packages/ui-app/src/Modal.tsx @@ -1,12 +1,14 @@ // Copyright 2017-2018 @polkadot/ui-app 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 './types'; import React from 'react'; import SUIModal from 'semantic-ui-react/dist/commonjs/modules/Modal/Modal'; -import classes from '@polkadot/ui-app/util/classes'; +import settings from '@polkadot/ui-settings'; + +import classes from './util/classes'; type Props = BareProps & { children: React.ReactNode, @@ -17,6 +19,7 @@ export default class Modal extends React.PureComponent { static Actions = SUIModal.Actions; static Content = SUIModal.Content; static Header = SUIModal.Header; + static Description = SUIModal.Description; render () { const { className } = this.props; @@ -24,7 +27,7 @@ export default class Modal extends React.PureComponent { return ( ); } diff --git a/packages/ui-app/src/Output.tsx b/packages/ui-app/src/Output.tsx index 3311a60901..cf51a724e2 100644 --- a/packages/ui-app/src/Output.tsx +++ b/packages/ui-app/src/Output.tsx @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/ui-app 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 './types'; diff --git a/packages/ui-app/src/Params/Param/Account.tsx b/packages/ui-app/src/Params/Param/Account.tsx index f743d57e60..5dbc2b4cb2 100644 --- a/packages/ui-app/src/Params/Param/Account.tsx +++ b/packages/ui-app/src/Params/Param/Account.tsx @@ -1,10 +1,11 @@ // Copyright 2017-2018 @polkadot/ui-app 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 '../types'; import React from 'react'; +import { decodeAddress } from '@polkadot/keyring'; import InputAddress from '../../InputAddress'; import Bare from './Bare'; @@ -12,7 +13,7 @@ import Bare from './Bare'; export default class Account extends React.PureComponent { render () { const { className, defaultValue: { value }, isDisabled, isError, label, style, withLabel } = this.props; - const defaultValue = value as Uint8Array; + const defaultValue = value && value.toString(); return ( { ); } - onChange = (value?: Uint8Array): void => { + private onChange = (value?: string): void => { const { onChange } = this.props; + let isValid = false; + + if (value) { + try { + decodeAddress(value); + + isValid = true; + } catch (err) { + console.error(err); + } + } + onChange && onChange({ - isValid: !!value && value.length === 32, + isValid, value }); } diff --git a/packages/ui-app/src/Params/Param/Amount.tsx b/packages/ui-app/src/Params/Param/Amount.tsx index 375306ad01..1c4afbc1db 100644 --- a/packages/ui-app/src/Params/Param/Amount.tsx +++ b/packages/ui-app/src/Params/Param/Amount.tsx @@ -1,11 +1,12 @@ // Copyright 2017-2018 @polkadot/ui-app 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 '../types'; import BN from 'bn.js'; import React from 'react'; +import numberFormat from '@polkadot/ui-react-rx/util/numberFormat'; import Input from '../../Input'; import Bare from './Bare'; @@ -13,7 +14,13 @@ import Bare from './Bare'; export default class Amount extends React.PureComponent { render () { const { className, defaultValue: { value }, isDisabled, isError, label, style, withLabel } = this.props; - const defaultValue = new BN((value as number) || 0).toNumber(); + const defaultValue = isDisabled + ? numberFormat(value) + : ( + value instanceof BN + ? value.toNumber() + : new BN((value as number) || 0).toNumber() + ); return ( { label={label} min={0} onChange={this.onChange} - type='number' + type={ + isDisabled + ? 'text' + : 'number' + } withLabel={withLabel} /> ); } - onChange = (value: string): void => { + private onChange = (value: string): void => { const { onChange } = this.props; onChange && onChange({ diff --git a/packages/ui-app/src/Params/Param/Balance.spec.js b/packages/ui-app/src/Params/Param/Balance.spec.js index 7d98bd6c88..b0608b31a1 100644 --- a/packages/ui-app/src/Params/Param/Balance.spec.js +++ b/packages/ui-app/src/Params/Param/Balance.spec.js @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/ui-app 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 React from 'react'; diff --git a/packages/ui-app/src/Params/Param/Balance.tsx b/packages/ui-app/src/Params/Param/Balance.tsx index 4360bf3238..cb436c8e02 100644 --- a/packages/ui-app/src/Params/Param/Balance.tsx +++ b/packages/ui-app/src/Params/Param/Balance.tsx @@ -1,12 +1,13 @@ // Copyright 2017-2018 @polkadot/ui-app 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 { BitLength } from '../../types'; import { Props as BareProps } from '../types'; import BN from 'bn.js'; import React from 'react'; +import { balanceFormat } from '@polkadot/ui-react-rx/util/index'; import { BitLengthOption } from '../../constants'; import InputNumber from '../../InputNumber'; @@ -18,8 +19,10 @@ const DEFAULT_BITLENGTH = BitLengthOption.CHAIN_SPEC as BitLength; class Balance extends React.PureComponent { render () { - const { className, defaultValue: { value }, isError, label, style, withLabel } = this.props; - const defaultValue = new BN(value as BN || '0').toString(10); + const { className, defaultValue: { value }, isDisabled, isError, label, style, withLabel } = this.props; + const defaultValue = isDisabled + ? balanceFormat(value) + : new BN(value as BN || '0').toString(10); return ( { bitLength={DEFAULT_BITLENGTH} className='large' defaultValue={defaultValue || '0'} + isDisabled={isDisabled} isError={isError} + isSi label={label} onChange={this.onChange} withLabel={withLabel} @@ -39,7 +44,7 @@ class Balance extends React.PureComponent { ); } - onChange = (value: BN): void => { + private onChange = (value?: BN): void => { const { isError, onChange } = this.props; if (!onChange) { @@ -47,7 +52,7 @@ class Balance extends React.PureComponent { } onChange({ - isValid: !isError, + isValid: !isError && !!value, value }); } diff --git a/packages/ui-app/src/Params/Param/Bare.tsx b/packages/ui-app/src/Params/Param/Bare.tsx index e25f67de0d..8c9595b578 100644 --- a/packages/ui-app/src/Params/Param/Bare.tsx +++ b/packages/ui-app/src/Params/Param/Bare.tsx @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/ui-app 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 '../../types'; diff --git a/packages/ui-app/src/Params/Param/Base.tsx b/packages/ui-app/src/Params/Param/Base.tsx index 4655483150..fae358327d 100644 --- a/packages/ui-app/src/Params/Param/Base.tsx +++ b/packages/ui-app/src/Params/Param/Base.tsx @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/ui-app 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 '../../types'; import { Size } from '../types'; diff --git a/packages/ui-app/src/Params/Param/BaseBytes.tsx b/packages/ui-app/src/Params/Param/BaseBytes.tsx index 3b78c39d41..874fa7ffe4 100644 --- a/packages/ui-app/src/Params/Param/BaseBytes.tsx +++ b/packages/ui-app/src/Params/Param/BaseBytes.tsx @@ -1,19 +1,18 @@ // Copyright 2017-2018 @polkadot/ui-app 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 as BaseProps, Size } from '../types'; import React from 'react'; -import hexToU8a from '@polkadot/util/hex/toU8a'; -import bnToU8a from '@polkadot/util/bn/toU8a'; -import u8aConcat from '@polkadot/util/u8a/concat'; -import u8aToHex from '@polkadot/util/u8a/toHex'; +import { Compact } from '@polkadot/types/codec'; +import { hexToU8a, u8aToHex } from '@polkadot/util'; import Input from '../../Input'; import Bare from './Bare'; type Props = BaseProps & { + children?: React.ReactNode, length?: number, size?: Size, validate?: (u8a: Uint8Array) => boolean, @@ -25,7 +24,7 @@ const defaultValidate = (u8a: Uint8Array): boolean => export default class BaseBytes extends React.PureComponent { render () { - const { className, defaultValue: { value }, isDisabled, isError, label, size = 'full', style, withLabel } = this.props; + const { children, className, defaultValue: { value }, isDisabled, isError, label, size = 'full', style, withLabel } = this.props; const defaultValue = value ? u8aToHex(value as Uint8Array, isDisabled ? 256 : -1) : undefined; @@ -38,6 +37,7 @@ export default class BaseBytes extends React.PureComponent { { placeholder='0x...' type='text' withLabel={withLabel} - /> + > + {children} + ); } - onChange = (hex: string): void => { - const { length = -1, onChange, validate = defaultValidate, withLength = false } = this.props; + private onChange = (hex: string): void => { + const { length = -1, onChange, validate = defaultValidate, withLength } = this.props; - let u8a: Uint8Array; + let value: Uint8Array; try { - u8a = hexToU8a(hex); + value = hexToU8a(hex); } catch (error) { - u8a = new Uint8Array([]); + value = new Uint8Array([]); } - const isValidLength = length !== -1 - ? u8a.length === length - : u8a.length !== 0; - const isValid = isValidLength && validate(u8a); + let isValid = validate(value) && length !== -1 + ? value.length === length + : value.length !== 0; + + if (withLength && isValid) { + value = Compact.addLengthPrefix(value); + } onChange && onChange({ isValid, - value: u8aConcat( - withLength - ? bnToU8a(u8a.length, 32, true) - : new Uint8Array([]), - u8a - ) + value }); } } diff --git a/packages/ui-app/src/Params/Param/Bool.tsx b/packages/ui-app/src/Params/Param/Bool.tsx index aeb389fc68..c8c406946f 100644 --- a/packages/ui-app/src/Params/Param/Bool.tsx +++ b/packages/ui-app/src/Params/Param/Bool.tsx @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/ui-app 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 '../types'; @@ -14,10 +14,12 @@ const options = [ { text: 'Yes', value: true } ]; -export default class Bool extends React.PureComponent { +export default class BoolParam extends React.PureComponent { render () { const { className, defaultValue: { value }, isDisabled, isError, label, style, withLabel } = this.props; - const defaultValue = value as boolean; + const defaultValue = value instanceof Boolean + ? value.valueOf() + : value as boolean; return ( { ); } - onChange = (value: boolean): void => { + private onChange = (value: boolean): void => { const { onChange } = this.props; onChange && onChange({ diff --git a/packages/ui-app/src/Params/Param/Bytes.tsx b/packages/ui-app/src/Params/Param/Bytes.tsx index 273d103ac7..9d7c97582e 100644 --- a/packages/ui-app/src/Params/Param/Bytes.tsx +++ b/packages/ui-app/src/Params/Param/Bytes.tsx @@ -1,16 +1,40 @@ // Copyright 2017-2018 @polkadot/ui-app 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 '../types'; import React from 'react'; +import { Compact } from '@polkadot/types/codec'; +import Button from '../../Button'; import BaseBytes from './BaseBytes'; +import File from './File'; + +type State = { + isFileDrop: boolean +}; + +export default class Bytes extends React.PureComponent { + constructor (props: Props) { + super(props); + + this.state = { + isFileDrop: false + }; + } -export default class Bytes extends React.PureComponent { render () { - const { className, defaultValue, isDisabled, isError, label, name, onChange, style, withLabel } = this.props; + const { isDisabled } = this.props; + const { isFileDrop } = this.state; + + return !isDisabled && isFileDrop + ? this.renderFile() + : this.renderInput(); + } + + private renderInput () { + const { className, defaultValue, isDisabled, isError, label, name, onChange, style, type, withLabel } = this.props; return ( { onChange={onChange} size='full' style={style} + type={type} withLabel={withLabel} withLength + > + {this.renderFileButton()} + + ); + } + + private renderFileButton () { + const { isDisabled } = this.props; + + if (isDisabled) { + return null; + } + + return ( +
diff --git a/packages/ui-app/src/Params/Param/Vector.tsx b/packages/ui-app/src/Params/Param/Vector.tsx new file mode 100644 index 0000000000..3a22fab8de --- /dev/null +++ b/packages/ui-app/src/Params/Param/Vector.tsx @@ -0,0 +1,154 @@ +// Copyright 2017-2018 @polkadot/ui-app 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 { WithNamespaces } from 'react-i18next'; +import { TypeDef } from '@polkadot/types/codec'; +import { Props as BareProps, RawParam } from '../types'; + +import React from 'react'; + +import Button from '../../Button'; +import translate from '../../translate'; +import getInitValue from '../initValue'; +import Bare from './Bare'; +import findComponent from './findComponent'; + +type Props = BareProps & WithNamespaces; + +type State = { + Component: React.ComponentType | null, + type?: string, + values: Array +}; + +class Vector extends React.PureComponent { + constructor (props: Props) { + super(props); + + this.state = { + Component: null, + values: [] + }; + } + + static getDerivedStateFromProps ({ defaultValue: { value = [] }, isDisabled, type: { sub, type } }: Props, prevState: State): Partial | null { + if (type === prevState.type) { + return null; + } + + return { + Component: findComponent(sub as TypeDef), + type, + values: isDisabled || prevState.values.length === 0 + ? value + : prevState.values + }; + } + + render () { + const { className, defaultValue, isDisabled, style, type, withLabel } = this.props; + const { Component } = this.state; + + if (!Component) { + return null; + } + + const subType = type.sub as TypeDef; + const values: Array = isDisabled + ? defaultValue.value || [] + : this.state.values; + + return ( + + {values.map((value, index) => ( + + ))} + {this.renderButtons()} + + ); + } + + private renderButtons () { + const { isDisabled, t } = this.props; + const { values } = this.state; + + if (isDisabled) { + return null; + } + + return ( +
+
+ ); + } + + private onChange = (index: number) => { + const { onChange } = this.props; + + return (value: RawParam): void => { + let isValid = value.isValid; + const values = this.state.values.map((svalue, sindex) => { + if (sindex === index) { + return value; + } + + isValid = isValid && svalue.isValid; + + return svalue; + }); + + this.setState({ values }, () => { + onChange && onChange({ + isValid, + value: values.map(({ value }) => value) + }); + }); + }; + } + + private rowAdd = (): void => { + const { type } = this.props; + const { values } = this.state; + + this.setState({ + values: values.concat(getInitValue(type)) + }); + } + + private rowRemove = (): void => { + const { values } = this.state; + + this.setState({ + values: values.slice(0, values.length - 1) + }); + } +} + +export default translate(Vector); diff --git a/packages/ui-app/src/Params/Param/VoteThreshold.tsx b/packages/ui-app/src/Params/Param/VoteThreshold.tsx index c942e06161..45e6a205a0 100644 --- a/packages/ui-app/src/Params/Param/VoteThreshold.tsx +++ b/packages/ui-app/src/Params/Param/VoteThreshold.tsx @@ -1,11 +1,12 @@ // Copyright 2017-2018 @polkadot/ui-app 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 '../types'; import React from 'react'; -import bnToBn from '@polkadot/util/bn/toBn'; +import { VoteThreshold } from '@polkadot/types'; +import { bnToBn } from '@polkadot/util'; import Dropdown from '../../Dropdown'; import Bare from './Bare'; @@ -24,10 +25,12 @@ export const textMap = options.reduce((textMap, { text, value }) => { return textMap; }, {} as TextMap); -export default class VoteThreshold extends React.PureComponent { +export default class VoteThresholdParam extends React.PureComponent { render () { const { className, defaultValue: { value }, isDisabled, isError, label, style, withLabel } = this.props; - const defaultValue = bnToBn(value as number).toNumber(); + const defaultValue = value instanceof VoteThreshold + ? value.toNumber() + : bnToBn(value as number).toNumber(); return ( { ); } - onChange = (value: number): void => { + private onChange = (value: number): void => { const { onChange } = this.props; onChange && onChange({ diff --git a/packages/ui-app/src/Params/Param/findComponent.ts b/packages/ui-app/src/Params/Param/findComponent.ts index 7a87557ab0..f5efbf92a8 100644 --- a/packages/ui-app/src/Params/Param/findComponent.ts +++ b/packages/ui-app/src/Params/Param/findComponent.ts @@ -1,8 +1,8 @@ // Copyright 2017-2018 @polkadot/ui-app 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 { Param$Types } from '@polkadot/params/types'; +import { TypeDef, TypeDefInfo } from '@polkadot/types/codec'; import { Props, ComponentMap } from '../types'; import Account from './Account'; @@ -13,16 +13,19 @@ import Bytes from './Bytes'; import Code from './Code'; import Hash from './Hash'; import Proposal from './Proposal'; -import StorageKeyValue from './StorageKeyValue'; -import StorageKeyValueArray from './StorageKeyValueArray'; +import KeyValue from './KeyValue'; +import KeyValueArray from './KeyValueArray'; import StringParam from './String'; import Timestamp from './Timestamp'; +import Tuple from './Tuple'; import Unknown from './Unknown'; +import Vector from './Vector'; import VoteThreshold from './VoteThreshold'; const components: ComponentMap = { 'AccountId': Account, - 'AccountIndex': Amount, + 'AccountIndex': Account, + 'Address': Account, 'Balance': Balance, 'BlockNumber': Amount, 'bool': Bool, @@ -30,13 +33,13 @@ const components: ComponentMap = { 'Code': Code, 'Call': Unknown, 'Digest': Unknown, + 'Gas': Amount, 'Hash': Hash, 'Index': Amount, - 'KeyValue': StorageKeyValue, - 'StorageKeyValue': StorageKeyValue, - 'StorageKeyValue[]': StorageKeyValueArray, + 'KeyValue': KeyValue, + 'Vec': KeyValueArray, 'MisbehaviorReport': Unknown, - 'ParachainId': Amount, + 'ParaId': Amount, 'PropIndex': Amount, 'Proposal': Proposal, 'ReferendumIndex': Amount, @@ -44,31 +47,32 @@ const components: ComponentMap = { 'Signature': Hash, 'String': StringParam, 'Timestamp': Timestamp, + 'Tuple': Tuple, 'u32': Amount, 'u64': Amount, + 'Vector': Vector, 'VoteIndex': Amount, 'VoteThreshold': VoteThreshold }; -function getFromMap (type: Param$Types, overrides: ComponentMap): React.ComponentType | [React.ComponentType, React.ComponentType] { - if (Array.isArray(type)) { - // Special case for components where we have a specific override formatter - if (type.length === 1) { - const arrayType = `${type}[]`; +export default function findComponent (def: TypeDef, overrides: ComponentMap = {}): React.ComponentType { + const type = (({ info, sub, type }: TypeDef) => { + switch (info) { + case TypeDefInfo.Compact: + return (sub as TypeDef).type; - return overrides[arrayType] || components[arrayType] || Unknown; + case TypeDefInfo.Tuple: + return 'Tuple'; + + case TypeDefInfo.Vector: + return ['Vec'].includes(type) + ? 'Vec' + : 'Vector'; + + default: + return type; } - - return Unknown; - } + })(def); return overrides[type] || components[type] || Unknown; } - -export default function findComponent (type: Param$Types, overrides: ComponentMap = {}, isDisabled: boolean = false): React.ComponentType { - const component = getFromMap(type, overrides); - - return Array.isArray(component) - ? component[0] - : component; -} diff --git a/packages/ui-app/src/Params/Param/index.tsx b/packages/ui-app/src/Params/Param/index.tsx index 390bd10365..16e45d3997 100644 --- a/packages/ui-app/src/Params/Param/index.tsx +++ b/packages/ui-app/src/Params/Param/index.tsx @@ -1,13 +1,12 @@ // Copyright 2017-2018 @polkadot/ui-app 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 '../../types'; import { BaseProps, Props as ComponentProps, ComponentMap } from '../types'; import React from 'react'; - -import typeToString from '@polkadot/params/typeToString'; +import { isUndefined } from '@polkadot/util'; import classes from '../../util/classes'; import translate from '../../translate'; @@ -27,11 +26,11 @@ class ParamComponent extends React.PureComponent { Component: null }; - static getDerivedStateFromProps ({ defaultValue: { type }, isDisabled, overrides }: Props): State { + static getDerivedStateFromProps ({ overrides, type }: Props): State { return { Component: !type ? null - : findComponent(type, overrides, isDisabled) + : findComponent(type, overrides) } as State; } @@ -42,8 +41,7 @@ class ParamComponent extends React.PureComponent { return null; } - const { className, defaultValue, isDisabled, name, onChange, style } = this.props; - const type = typeToString(defaultValue.type); + const { className, defaultValue, isDisabled, name, onChange, style, type } = this.props; return ( { defaultValue={defaultValue} key={`${name}:${type}`} isDisabled={isDisabled} - label={`${name}: ${type}`} + label={ + isUndefined(name) + ? type.type + : `${name}: ${type.type}` + } name={name} onChange={onChange} style={style} + type={type} /> ); } diff --git a/packages/ui-app/src/Params/Params.css b/packages/ui-app/src/Params/Params.css index 0ff390e4ba..76ae326086 100644 --- a/packages/ui-app/src/Params/Params.css +++ b/packages/ui-app/src/Params/Params.css @@ -1,6 +1,6 @@ /* Copyright 2017-2018 @polkadot/ui-app 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. */ .ui--Param-Address { font-family: monospace; @@ -37,3 +37,7 @@ .ui--Param-text + .ui--Param-text { margin-left: 0.5rem; } + +.ui--Param-Vector-buttons { + text-align: right; +} diff --git a/packages/ui-app/src/Params/index.tsx b/packages/ui-app/src/Params/index.tsx index 69fd818a97..90449685e8 100644 --- a/packages/ui-app/src/Params/index.tsx +++ b/packages/ui-app/src/Params/index.tsx @@ -1,8 +1,8 @@ // Copyright 2017-2018 @polkadot/ui-app 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 { TypeDef } from '@polkadot/types/codec'; import { I18nProps } from '../types'; import { ComponentMap, RawParams, RawParam$OnChange, RawParam$OnChange$Value } from './types'; @@ -15,41 +15,45 @@ import translate from '../translate'; import Param from './Param'; import createValues from './values'; -type Props = I18nProps & { +type Param = { + name?: string, + type: TypeDef +}; + +type Props = I18nProps & { isDisabled?: boolean, - item: S, onChange?: (value: RawParams) => void, overrides?: ComponentMap, + params: Array, values?: RawParams }; -type State = { - item: S, +type State = { handlers: Array, onChangeParam: (at: number, next: RawParam$OnChange$Value) => void, + params: Array, values: RawParams }; -class Params> extends React.PureComponent, State> { - state: State; +class Params extends React.PureComponent { + state: State; - constructor (props: Props) { + constructor (props: Props) { super(props); this.state = ({ onChangeParam: this.onChangeParam - } as State); + } as State); } - static getDerivedStateFromProps (props: Props, { item, onChangeParam }: State): State | null { - const isSame = item && item.name === props.item.name && item.section === props.item.section; + static getDerivedStateFromProps (props: Props, { params, onChangeParam }: State): State | null { + const isSame = JSON.stringify(params) === JSON.stringify(props.params); if (props.isDisabled || isSame) { return null; } - const { params } = props.item; - const values = createValues(params); + const values = createValues(props.params); const handlers = values.map( (value, index): RawParam$OnChange => (value: RawParam$OnChange$Value): void => @@ -57,14 +61,20 @@ class Params> extends React.PureComponent, ); return { - item: props.item, handlers, + params: props.params, values - } as State; + } as State; } - // NOTE This is needed in the case where the item changes, i.e. the values get initialised and we need to alert the parent that we have new values - componentDidUpdate (prevProps: Props, prevState: State) { + // Fire the intial onChange (we did update) when the component is loaded + componentDidMount () { + this.componentDidUpdate({} as Props, {} as State); + } + + // This is needed in the case where the item changes, i.e. the values get + // initialised and we need to alert the parent that we have new values + componentDidUpdate (prevProps: Props, prevState: State) { const { onChange, isDisabled } = this.props; const { values } = this.state; @@ -74,10 +84,10 @@ class Params> extends React.PureComponent, } render () { - const { className, isDisabled, item: { params }, overrides, style } = this.props; + const { className, isDisabled, overrides, params, style } = this.props; const { handlers = [], values = this.props.values } = this.state; - if (!values || values.length === 0 || params.length === 0) { + if (!params || params.length === 0 || !values || values.length === 0) { return null; } @@ -87,7 +97,7 @@ class Params> extends React.PureComponent, style={style} >
- {params.map(({ name }, index) => ( + {params.map(({ name, type }, index) => ( > extends React.PureComponent, name={name} onChange={handlers[index]} overrides={overrides} + type={type} /> ))}
@@ -102,30 +113,31 @@ class Params> extends React.PureComponent, ); } - private onChangeParam = (at: number, { isValid = false, value }: RawParam$OnChange$Value): void => { + private onChangeParam = (at: number, newValue: RawParam$OnChange$Value): void => { const { isDisabled } = this.props; if (isDisabled) { return; } + const { isValid = false, value } = newValue; + this.setState( - (prevState: State): State => ({ + (prevState: State): State => ({ values: prevState.values.map((prev, index) => index !== at ? prev : { isValid, - type: prev.type, value } ) - } as State), + } as State), this.triggerUpdate ); } - triggerUpdate = (): void => { + private triggerUpdate = (): void => { const { values } = this.state; const { onChange, isDisabled } = this.props; @@ -137,5 +149,4 @@ class Params> extends React.PureComponent, } } -// @ts-ignore something is wrong with generics and these imports export default translate(Params); diff --git a/packages/ui-app/src/Params/initValue.ts b/packages/ui-app/src/Params/initValue.ts index 6feb0c8e2d..8bce71c811 100644 --- a/packages/ui-app/src/Params/initValue.ts +++ b/packages/ui-app/src/Params/initValue.ts @@ -1,25 +1,35 @@ // Copyright 2017-2018 @polkadot/ui-app 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 { Param$Type, Param$Types } from '@polkadot/params/types'; +import { TypeDef, TypeDefInfo } from '@polkadot/types/codec'; import { RawParam$Value } from './types'; import BN from 'bn.js'; -import typeToString from '@polkadot/params/typeToString'; +export default function getInitValue (def: TypeDef): RawParam$Value | Array { + if (def.info === TypeDefInfo.Vector) { + return [getInitValue(def.sub as TypeDef)]; + } else if (def.info === TypeDefInfo.Tuple) { + return Array.isArray(def.sub) + ? def.sub.map((def) => getInitValue(def)) + : []; + } else if (def.info === TypeDefInfo.Struct) { + console.error(`Unable to determine default type from Struct ${JSON.stringify(def)}`); + return void 0; + } -import getInitValueArray from './initValueArray'; + const type = def.info === TypeDefInfo.Compact + ? (def.sub as TypeDef).type + : def.type; -export default function getInitValue (type: Param$Types): RawParam$Value | Array { switch (type) { case 'Balance': - return new BN(1); - case 'BlockNumber': - case 'AccountIndex': + case 'Compact': + case 'Gas': case 'Index': - case 'ParachainId': + case 'ParaId': case 'PropIndex': case 'ReferendumIndex': case 'SessionKey': @@ -42,27 +52,22 @@ export default function getInitValue (type: Param$Types): RawParam$Value | Array return 0; case 'AccountId': + case 'AccountIndex': + case 'Address': case 'Bytes': case 'Call': case 'CandidateReceipt': - case 'Code': case 'Digest': case 'Hash': case 'Header': case 'KeyValue': - case 'StorageKeyValue': case 'MisbehaviorReport': case 'Proposal': case 'Signature': return void 0; default: - if (Array.isArray(type)) { - return getInitValueArray(type as Array); - } - - // tslint:disable-next-line - (type as never); - throw new Error(`Unable to determine default type for ${typeToString(type)}`); + console.error(`Unable to determine default type for ${JSON.stringify(def)}`); + return void 0; } } diff --git a/packages/ui-app/src/Params/initValueArray.ts b/packages/ui-app/src/Params/initValueArray.ts deleted file mode 100644 index 9dc7cc0d72..0000000000 --- a/packages/ui-app/src/Params/initValueArray.ts +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-app authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import { Param$Type } from '@polkadot/params/types'; -import { RawParam$Value } from './types'; - -import getInitValue from './initValue'; - -export default function getInitValueArray (type: Param$Type[]): RawParam$Value | Array { - // NOTE special cases for where we have a known override formatter. The only horrible thing with - // this atm is that we need to add the same override in ./values.ts - which is actually horrible, - // need a single place for both the actual raw values and wrapped values - if (type.length === 1 && type[0] === 'StorageKeyValue') { - return []; - } - - return type.map((value) => - // NOTE since TS is not quite good at recursives, cast to a single - getInitValue(value) as RawParam$Value - ); -} diff --git a/packages/ui-app/src/Params/types.d.ts b/packages/ui-app/src/Params/types.ts similarity index 65% rename from packages/ui-app/src/Params/types.d.ts rename to packages/ui-app/src/Params/types.ts index 5e8533c3b1..841e106afe 100644 --- a/packages/ui-app/src/Params/types.d.ts +++ b/packages/ui-app/src/Params/types.ts @@ -1,11 +1,13 @@ // Copyright 2017-2018 @polkadot/ui-app 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 { Param$Type, Param$Types, Param$Value } from '@polkadot/params/types'; +import { TypeDef } from '@polkadot/types/codec'; import { BareProps } from '../types'; -export type RawParam$Value = Param$Value | undefined; +// FIXME Ideally, we want these as Base from api-codec - as a stop-gap, any this until we have +// params returning types extending Base (i.e. anything from api-codec) +export type RawParam$Value = any | undefined; export type RawParam$ValueArray = Array>; @@ -13,9 +15,8 @@ export type RawParam$Values = RawParam$Value | RawParam$ValueArray; export type RawParam = { isValid: boolean, - type: Param$Types, - value: RawParam$Values, -} + value: RawParam$Values +}; export type RawParam$OnChange$Value = { isValid: boolean, value: RawParam$Values }; export type RawParam$OnChange = (value: RawParam$OnChange$Value) => void; @@ -24,8 +25,9 @@ export type RawParams = Array; export type BaseProps = BareProps & { defaultValue: RawParam, - name: string, - onChange?: RawParam$OnChange + name?: string, + onChange?: RawParam$OnChange, + type: TypeDef }; export type Props = BaseProps & { @@ -39,5 +41,5 @@ export type Props = BaseProps & { export type Size = 'full' | 'large' | 'medium' | 'small'; export type ComponentMap = { - [index: string]: React.ComponentType | [React.ComponentType, React.ComponentType] // Param$Type + [index: string]: React.ComponentType }; diff --git a/packages/ui-app/src/Params/valueToText.tsx b/packages/ui-app/src/Params/valueToText.tsx index f83fd5aa63..4c33d578bf 100644 --- a/packages/ui-app/src/Params/valueToText.tsx +++ b/packages/ui-app/src/Params/valueToText.tsx @@ -1,25 +1,22 @@ // Copyright 2017-2018 @polkadot/ui-app authors & contributors // This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import { Param$Types, Param$Type$Array, ExtrinsicDecoded } from '@polkadot/params/types'; +// of the Apache-2.0 license. See the LICENSE file for details. import './Params.css'; import React from 'react'; -import IdentityIcon from '@polkadot/ui-react/IdentityIcon'; -import numberFormat from '@polkadot/ui-react-rx/util/numberFormat'; -import u8aToHex from '@polkadot/util/u8a/toHex'; -import isBn from '@polkadot/util/is/bn'; -import isNull from '@polkadot/util/is/null'; -import isU8a from '@polkadot/util/is/u8a'; -import isUndefined from '@polkadot/util/is/undefined'; -import encodeAddress from '@polkadot/util-keyring/address/encode'; +import { isNull, isUndefined, u8aToHex } from '@polkadot/util'; +// import { decodeAddress } from '@polkadot/keyring'; +// import IdentityIcon from '@polkadot/ui-react/IdentityIcon'; +// import numberFormat from '@polkadot/ui-react-rx/util/numberFormat'; +// import u8aToHex from '@polkadot/util/u8a/toHex'; +// import isBn from '@polkadot/util/is/bn'; +// import isU8a from '@polkadot/util/is/u8a'; import classes from '../util/classes'; -import { textMap as thresholdTextMap } from './Param/VoteThreshold'; +// import { textMap as thresholdTextMap } from './Param/VoteThreshold'; -const empty = div({}, ''); +// const empty = div({}, ''); const unknown = div({}, ''); type DivProps = { @@ -38,123 +35,128 @@ function div ({ key, className }: DivProps, ...values: Array): ); } -function accountToText (_address: string | Uint8Array): React.ReactNode { - const address = isU8a(_address) - ? encodeAddress(_address) - : _address; +// function accountToText (_address: string | Uint8Array): React.ReactNode { +// const address = isU8a(_address) +// ? encodeAddress(_address) +// : _address; - return div( - { className: 'nowrap', key: `account_${address}` }, - , - div({ key: 'address', className: 'ui--Param-Address' }, address), - // Empty div so double clicking on the address only selects the address -
- ); -} +// return div( +// { className: 'nowrap', key: `account_${address}` }, +// , +// div({ key: 'address', className: 'ui--Param-Address' }, address), +// // Empty div so double clicking on the address only selects the address +//
+// ); +// } -function proposalToText ({ extrinsic, params }: ExtrinsicDecoded): React.ReactNode { - if (!extrinsic) { - return unknown; - } +// function proposalToText ({ extrinsic, params }: ExtrinsicDecoded): React.ReactNode { +// if (!extrinsic) { +// return unknown; +// } - const inputs = extrinsic.params.map(({ name, type }, index) => - div( - { key: `param_${index}` }, - div({ className: 'name', key: 'param_name' }, `${name}=`), - valueToText(type, params[index]) - ) - ); +// const inputs = extrinsic.params.map(({ name, type }, index) => +// div( +// { key: `param_${index}` }, +// div({ className: 'name', key: 'param_name' }, `${name}=`), +// valueToText(type, params[index]) +// ) +// ); - return div( - {}, - div({ className: 'name' }, `${extrinsic.section}.${extrinsic.name}(`), - inputs, - div({ className: 'name' }, ')') - ); -} +// return div( +// {}, +// div({ className: 'name' }, `${extrinsic.section}.${extrinsic.name}(`), +// inputs, +// div({ className: 'name' }, ')') +// ); +// } -function arrayToText (type: Param$Type$Array, value: Array, withBound: boolean = true): React.ReactNode { - if (value.length === 0) { - return empty; - } +// function arrayToText (type: Param$Type$Array, value: Array, withBound: boolean = true): React.ReactNode { +// if (value.length === 0) { +// return empty; +// } - if (type.length === 1) { - if (type[0] === 'KeyValueStorage') { - return div({}, value.length); - } +// if (type.length === 1) { +// if (type[0] === 'KeyValueStorage') { +// return div({}, value.length); +// } - return value.map((value, index) => - div( - { key: `value_${index}` }, - div({ className: 'name', key: 'name' }, `${index}:`), - valueToText(type[0], value, false) - ) - ); - } +// return value.map((value, index) => +// div( +// { key: `value_${index}` }, +// div({ className: 'name', key: 'name' }, `${index}:`), +// valueToText(type[0], value, false) +// ) +// ); +// } - const values = type.map((_type, index) => - valueToText(_type, value[index], false) - ); +// const values = type.map((_type, index) => +// valueToText(_type, value[index], false) +// ); - return div( - {}, - div({ className: 'name' }, '('), - values, - div({ className: 'name' }, ')') - ); -} +// return div( +// {}, +// div({ className: 'name' }, '('), +// values, +// div({ className: 'name' }, ')') +// ); +// } -function valueToText (type: Param$Types, value: any, swallowError: boolean = true): React.ReactNode { - try { - if (type === 'bool') { - return div({}, value ? 'Yes' : 'No'); - } +function valueToText (type: string, value: any, swallowError: boolean = true, contentShorten: boolean = true): React.ReactNode { + // try { + // if (type === 'bool') { + // return div({}, value ? 'Yes' : 'No'); + // } - if (isUndefined(value)) { - return unknown; - } + // if (isUndefined(value)) { + // return unknown; + // } - if (Array.isArray(type)) { - return arrayToText(type, value); - } + // if (Array.isArray(type)) { + // return arrayToText(type, value); + // } - if (type === 'AccountId') { - return value && value.length - ? accountToText(value as string) - : unknown; - } + // if (type === 'AccountId') { + // return value && value.length + // ? accountToText(value as string) + // : unknown; + // } - if (type === 'Proposal') { - return proposalToText(value as ExtrinsicDecoded); - } + // if (type === 'Proposal') { + // return proposalToText(value as ExtrinsicDecoded); + // } - if (type === 'VoteThreshold') { - return div({}, thresholdTextMap[value]); - } + // if (type === 'VoteThreshold') { + // return div({}, thresholdTextMap[value]); + // } - if (isU8a(value)) { - return div({}, u8aToHex(value, 256)); - } + // if (isU8a(value)) { + // return div({}, u8aToHex(value, 256)); + // } - if (isBn(value)) { - return div({}, numberFormat(value)); - } - } catch (error) { - if (!swallowError) { - throw error; - } else { - console.log('valueToText', type, value, error); - } - } + // if (isBn(value)) { + // return div({}, numberFormat(value)); + // } + // } catch (error) { + // if (!swallowError) { + // throw error; + // } else { + // console.log('valueToText', type, value, error); + // } + // } return isNull(value) || isUndefined(value) ? unknown - : div({}, value.toString()); + : div( + {}, + ['Bytes', 'Data'].includes(type) + ? u8aToHex(value.toU8a(true), contentShorten ? 512 : -1) + : value.toString() + ); } export default valueToText; diff --git a/packages/ui-app/src/Params/values.ts b/packages/ui-app/src/Params/values.ts index 8ba125d298..c94da82057 100644 --- a/packages/ui-app/src/Params/values.ts +++ b/packages/ui-app/src/Params/values.ts @@ -1,60 +1,20 @@ // Copyright 2017-2018 @polkadot/ui-app 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 { Params } from '@polkadot/params/types'; -import { RawParam, RawParam$ValueArray } from './types'; +import { TypeDef } from '@polkadot/types/codec'; +import { RawParam } from './types'; -import isUndefined from '@polkadot/util/is/undefined'; +import { isUndefined } from '@polkadot/util'; import getInitValue from './initValue'; -export default function values (params: Params): Array { - const types = params.map(({ type }) => type); - - return types.map((type): RawParam => { - if (Array.isArray(type)) { - if (type.length !== 1) { - console.error('Unable to determine default values for tuple type', type); - - return { - isValid: false, - type, - value: void 0 - }; - } - - // NOTE special cases for where we have a known override formatter. See comments - // in ./inintValueArray.ts - if (type[0] === 'KeyValueStorage') { - return { - isValid: false, // invalid to start with, empty array - type, - value: [] - }; - } - - const value: RawParam$ValueArray = []; - - return type.reduce(({ isValid, type }, subtype) => { - const avalue = getInitValue(subtype); - - value.push(avalue); - - return { - isValid: isValid && !isUndefined(avalue), - type, - value - }; - // FIXME Arrays are currently not valid as inputs, no rendered - }, { isValid: false, type, value }); - } - +export default function values (params: Array<{ type: TypeDef }>): Array { + return params.map(({ type }): RawParam => { const value = getInitValue(type); return { isValid: !isUndefined(value), - type, value }; }); diff --git a/packages/ui-app/src/Password.tsx b/packages/ui-app/src/Password.tsx index ffa41a6c00..6d79d4c8ff 100644 --- a/packages/ui-app/src/Password.tsx +++ b/packages/ui-app/src/Password.tsx @@ -1,10 +1,11 @@ // Copyright 2017-2018 @polkadot/ui-app 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 './types'; import React from 'react'; +import { MAX_PASS_LEN } from '@polkadot/ui-keyring/defaults'; import classes from './util/classes'; import Button from './Button'; @@ -12,8 +13,8 @@ import Input from './Input'; type Props = BareProps & { autoFocus?: boolean, - defaultValue?: any, children?: React.ReactNode, + defaultValue?: any, isDisabled?: boolean, isError?: boolean, label?: string, @@ -47,7 +48,7 @@ export default class Password extends React.PureComponent { isDisabled={isDisabled} isError={isError} label={label} - maxLength={32} + maxLength={MAX_PASS_LEN} name={name} onChange={onChange} onKeyDown={onKeyDown} diff --git a/packages/ui-app/src/Progress.tsx b/packages/ui-app/src/Progress.tsx index 4b3cd2c4f3..2fd1fee08d 100644 --- a/packages/ui-app/src/Progress.tsx +++ b/packages/ui-app/src/Progress.tsx @@ -1,14 +1,14 @@ // Copyright 2017-2018 @polkadot/ui-app 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 './types'; import BN from 'bn.js'; import React from 'react'; import SUIProgress from 'semantic-ui-react/dist/commonjs/modules/Progress/Progress'; -import isBn from '@polkadot/util/is/bn'; -import isUndefined from '@polkadot/util/is/undefined'; +import { UInt } from '@polkadot/types/codec'; +import { bnToBn, isBn, isUndefined } from '@polkadot/util'; import classes from './util/classes'; @@ -18,17 +18,19 @@ export type Colors = 'auto' | 'autoReverse' | BaseColors; type Props = BareProps & { color?: Colors, percent?: BN | number, - total?: BN | number, - value?: BN | number + total?: UInt | BN | number, + value?: UInt | BN | number }; export default class Progress extends React.PureComponent { render () { const { className, color = 'blue', percent, total, style, value } = this.props; let calculated: number | undefined; + const _total = bnToBn(total); + const _value = bnToBn(value); - if (!isUndefined(value) && !isUndefined(total) && (isBn(total) ? total.gtn(0) : total > 0)) { - calculated = 100.0 * (isBn(value) ? value.toNumber() : value) / (isBn(total) ? total.toNumber() : total); + if (_total.gtn(0)) { + calculated = 100.0 * _value.toNumber() / _total.toNumber(); } else { calculated = isBn(percent) ? percent.toNumber() : percent; } diff --git a/packages/ui-app/src/Static.tsx b/packages/ui-app/src/Static.tsx index 50bdb6cca7..c94f2652b8 100644 --- a/packages/ui-app/src/Static.tsx +++ b/packages/ui-app/src/Static.tsx @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/ui-app 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 './types'; @@ -11,9 +11,11 @@ import Labelled from './Labelled'; type Props = BareProps & { children?: React.ReactNode, defaultValue?: any, + isDisabled?: boolean, + isError?: boolean, isHidden?: boolean, - label?: any, // node? - value?: any, // node? + label?: React.ReactNode, + value?: React.ReactNode, withLabel?: boolean }; diff --git a/packages/ui-signer/src/Context.ts b/packages/ui-app/src/Status/Context.ts similarity index 62% rename from packages/ui-signer/src/Context.ts rename to packages/ui-app/src/Status/Context.ts index a860831ae9..03d8378dea 100644 --- a/packages/ui-signer/src/Context.ts +++ b/packages/ui-app/src/Status/Context.ts @@ -1,13 +1,14 @@ -// Copyright 2017-2018 @polkadot/ui-react-rx authors & contributors +// Copyright 2017-2018 @polkadot/ui-app 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 { QueueProps, QueueTx } from './types'; +import { QueueProps, QueueStatus, QueueTx } from './types'; import React from 'react'; const defaultState = { - queue: [] as Array + stqueue: [] as Array, + txqueue: [] as Array } as QueueProps; const Context: React.Context = React.createContext(defaultState); diff --git a/packages/ui-app/src/Status/Queue.tsx b/packages/ui-app/src/Status/Queue.tsx new file mode 100644 index 0000000000..bdb22b3d1b --- /dev/null +++ b/packages/ui-app/src/Status/Queue.tsx @@ -0,0 +1,180 @@ +// Copyright 2017-2018 @polkadot/ui-app 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 { RpcMethod } from '@polkadot/jsonrpc/types'; +import { BareProps } from '../types'; +import { ActionStatus, PartialQueueTx$Extrinsic, PartialQueueTx$Rpc, QueueProps, QueueStatus, QueueTx, QueueTx$Extrinsic, QueueTx$Rpc, QueueTx$Status } from './types'; + +import BN from 'bn.js'; +import React from 'react'; +import jsonrpc from '@polkadot/jsonrpc'; + +import { QueueProvider } from './Context'; + +export type Props = BareProps & { + children: React.ReactNode +}; + +type State = QueueProps; + +const defaultState = { + stqueue: [] as Array, + txqueue: [] as Array +} as QueueProps; + +let nextId = 0; + +const REMOVE_TIMEOUT = 7500; +const SUBMIT_RPC = jsonrpc.author.methods.submitAndWatchExtrinsic; +const STATUS_COMPLETE: Array = [ + // status from subscription + 'finalised', 'usurped', 'dropped', 'invalid', + // normal completion + 'cancelled', 'error', 'sent' +]; + +export default class Queue extends React.Component { + state: State = defaultState; + + constructor (props: Props) { + super(props); + + this.state = { + stqueue: [], + txqueue: [], + queueAction: this.queueAction, + queueRpc: this.queueRpc, + queueExtrinsic: this.queueExtrinsic, + queueSetTxStatus: this.queueSetTxStatus, + queueUnclog: this.queueUnclog + }; + } + + render () { + return ( + + {this.props.children} + + ); + } + + private isDuplicateNonce = (value: QueueTx$Extrinsic | QueueTx$Rpc | QueueTx): boolean => { + const { txqueue } = this.state; + + return txqueue.filter((item) => + !STATUS_COMPLETE.includes(item.status) && + item.status !== 'completed' && + item.accountNonce.eq(value.accountNonce) && + item.accountId === value.accountId + ).length > 0; + } + + queueAction = (status: ActionStatus): number => { + const id = ++nextId; + + this.setState( + (prevState: State): State => ({ + stqueue: prevState.stqueue.concat({ + ...status, + id, + isCompleted: false + }) + } as State) + ); + + setTimeout(() => { + this.setState( + (prevState: State): State => ({ + stqueue: prevState.stqueue.map((item) => ({ + ...item, + isCompleted: item.isCompleted || item.id === id + })) + } as State) + ); + }, REMOVE_TIMEOUT); + + return id; + } + + queueSetTxStatus = (id: number, status: QueueTx$Status, result?: any, error?: Error): void => { + this.setState( + (prevState: State): State => ({ + txqueue: prevState.txqueue.map((item) => + item.id === id + ? { + ...item, + error: error === undefined + ? item.error + : error, + result: result === undefined + ? item.result + : result, + status: item.status === 'completed' + ? item.status + : status + } + : item + ) + } as State) + ); + + if (STATUS_COMPLETE.includes(status)) { + setTimeout(() => { + this.queueSetTxStatus(id, 'completed'); + }, REMOVE_TIMEOUT); + } + } + + private queueAdd = (value: QueueTx$Extrinsic | QueueTx$Rpc | QueueTx): number => { + const id = ++nextId; + const rpc: RpcMethod = (value as QueueTx$Rpc).rpc || SUBMIT_RPC; + + this.setState( + (prevState: State): State => ({ + txqueue: prevState.txqueue.concat([{ + ...value, + id, + rpc, + status: this.isDuplicateNonce(value) ? 'blocked' : 'queued' + }]) + } as State) + ); + + return id; + } + + queueExtrinsic = ({ accountId, accountNonce, extrinsic }: PartialQueueTx$Extrinsic): number => { + return this.queueAdd({ + accountId, + accountNonce: accountNonce || new BN(0), + extrinsic + }); + } + + queueRpc = ({ accountId, accountNonce, rpc, values }: PartialQueueTx$Rpc): number => { + return this.queueAdd({ + accountId, + accountNonce: accountNonce || new BN(0), + rpc, + values + }); + } + + queueUnclog = (accountNonce: BN): void => { + const { txqueue } = this.state; + + // FIXME It works, but it's gross. It cancels all queued extrinsic with the nonincremenated + // nonce marked with a 'blocked' status and then requeues them all with the updated nonce. + // Unless users spam submit extrinsics, i can't see this being an issue, but it is still ugly. + txqueue.forEach((item) => { + if (item.status === 'blocked') { + let updatedItem = item; + this.queueSetTxStatus(item.id, 'cancelled'); + + updatedItem.accountNonce = accountNonce; + this.queueAdd(updatedItem); + } + }); + } +} diff --git a/packages/ui-app/src/Status/index.tsx b/packages/ui-app/src/Status/index.tsx new file mode 100644 index 0000000000..ceb4679003 --- /dev/null +++ b/packages/ui-app/src/Status/index.tsx @@ -0,0 +1,147 @@ +// Copyright 2017-2018 @polkadot/ui-app 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 '../types'; +import { QueueStatus, QueueTx, QueueTx$Status } from './types'; + +import React from 'react'; +import { Method } from '@polkadot/types'; + +import AddressMini from '../AddressMini'; +import Icon from '../Icon'; +import classes from '../util/classes'; +import translate from '../translate'; + +type Props = I18nProps & { + stqueue?: Array, + txqueue?: Array +}; + +class Status extends React.PureComponent { + render () { + const { stqueue = [], txqueue = [] } = this.props; + const allst: Array = stqueue.filter(({ isCompleted }) => !isCompleted); + const alltx: Array = txqueue.filter(({ status }) => + !['completed', 'incomplete'].includes(status) + ); + + if (!allst.length && !alltx.length) { + return null; + } + + return ( +
+ {alltx.map(this.renderItem)} + {allst.map(this.renderStatus)} +
+ ); + } + + private renderStatus = ({ action, id, message, status, value }: QueueStatus) => { + return ( +
+
+
+
+
+ {action} +
+ +
+ {message} +
+
+
+ +
+
+
+
+ ); + } + + private renderItem = ({ id, extrinsic, rpc, status }: QueueTx) => { + let { method, section } = rpc; + + if (extrinsic) { + const found = Method.findFunction(extrinsic.callIndex); + + if (found.section !== 'unknown') { + method = found.method; + section = found.section; + } + } + + const icon = this.signerIconName(status); + + return ( +
+
+
+
+
+ {section}.{method} +
+
+ {status} +
+
+
+ +
+
+
+
+ ); + } + + private iconName = (status: string) => { + switch (status) { + case 'error': + return 'ban'; + + case 'received': + return 'telegram plane'; + + default: + return 'check'; + } + } + + private signerIconName = (status: QueueTx$Status) => { + switch (status) { + case 'cancelled': + return 'ban'; + + case 'completed': + case 'finalised': + return 'check'; + + case 'dropped': + case 'invalid': + case 'usurped': + return 'arrow down'; + + case 'error': + return 'warning sign'; + + case 'queued': + return 'random'; + + default: + return 'spinner'; + } + } +} + +export default translate(Status); diff --git a/packages/ui-app/src/Status/types.ts b/packages/ui-app/src/Status/types.ts new file mode 100644 index 0000000000..913882effe --- /dev/null +++ b/packages/ui-app/src/Status/types.ts @@ -0,0 +1,87 @@ +// Copyright 2017-2018 @polkadot/ui-app 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 BN from 'bn.js'; +import { RpcMethod } from '@polkadot/jsonrpc/types'; +import { AccountId, Address, Extrinsic } from '@polkadot/types'; + +export type Actions = 'create' | 'edit' | 'restore' | 'forget' | 'backup' | 'changePassword' | 'transfer'; + +export type ActionStatus = { + action: Actions | string, + message?: string, + status: 'error' | 'queued' | 'received' | 'success', + value?: AccountId | Address | string +}; + +export type AccountInfo = { + accountId?: string | null, + accountNonce: BN +}; + +export type QueueTx$Status = 'future' | 'ready' | 'finalised' | 'usurped' | 'dropped' | 'invalid' | 'broadcast' | 'cancelled' | 'completed' | 'error' | 'incomplete' | 'queued' | 'sending' | 'sent' | 'blocked'; + +export type QueueTx = AccountInfo & { + error?: Error, + extrinsic?: Extrinsic, + id: number, + result?: any, + rpc: RpcMethod, + values?: Array, + status: QueueTx$Status +}; + +export type QueueStatus = ActionStatus & { + id: number, + isCompleted: boolean +}; + +export type QueueTx$Result = { + error?: Error, + result?: any, + status: QueueTx$Status +}; + +export type QueueTx$Extrinsic = AccountInfo & { + extrinsic: Extrinsic +}; + +export type QueueTx$Rpc = AccountInfo & { + rpc: RpcMethod, + values: Array +}; + +export type PartialAccountInfo = { + accountId?: string | null, + accountNonce?: BN | null +}; + +export type PartialQueueTx$Extrinsic = PartialAccountInfo & { + extrinsic: Extrinsic +}; + +export type PartialQueueTx$Rpc = PartialAccountInfo & { + rpc: RpcMethod, + values: Array +}; + +export type QueueTx$RpcAdd = (value: PartialQueueTx$Rpc) => number; + +export type QueueTx$ExtrinsicAdd = (value: PartialQueueTx$Extrinsic) => number; + +export type QueueTx$MessageSetStatus = (id: number, status: QueueTx$Status, result?: any, error?: Error) => void; + +export type QueueTx$Unclog = (accountNonce: BN) => void; + +export type QueueAction$Add = (status: ActionStatus) => number; + +export type QueueProps = { + stqueue: Array, + txqueue: Array, + queueAction: QueueAction$Add, + queueUnclog: QueueTx$Unclog, + queueExtrinsic: QueueTx$ExtrinsicAdd, + queueRpc: QueueTx$RpcAdd, + queueSetTxStatus: QueueTx$MessageSetStatus +}; diff --git a/packages/ui-app/src/Tabs.tsx b/packages/ui-app/src/Tabs.tsx index cf4cf9626f..bba68d9695 100644 --- a/packages/ui-app/src/Tabs.tsx +++ b/packages/ui-app/src/Tabs.tsx @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/ui-app 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 './types'; diff --git a/packages/ui-app/src/constants.ts b/packages/ui-app/src/constants.ts index e3b7f140c3..112f1de69f 100644 --- a/packages/ui-app/src/constants.ts +++ b/packages/ui-app/src/constants.ts @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/ui-app 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. export enum BitLengthOption { CHAIN_SPEC = 128, diff --git a/packages/ui-app/src/i18n.ts b/packages/ui-app/src/i18n.ts index 91e806b72c..e0e5dc3a7d 100644 --- a/packages/ui-app/src/i18n.ts +++ b/packages/ui-app/src/i18n.ts @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/ui-app 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 i18n from 'i18next'; import LanguageDetector from 'i18next-browser-languagedetector'; diff --git a/packages/ui-app/src/index.tsx b/packages/ui-app/src/index.tsx index 7e13385030..135859112c 100644 --- a/packages/ui-app/src/index.tsx +++ b/packages/ui-app/src/index.tsx @@ -1,26 +1,92 @@ // Copyright 2017-2018 @polkadot/ui-app authors & contributors // This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import { ProviderInterface } from '@polkadot/api-provider/types'; -import { RxApiInterface } from '@polkadot/api-rx/types'; -import { BareProps } from './types'; +// of the Apache-2.0 license. See the LICENSE file for details. +import '@polkadot/ui-settings'; import './i18n'; import './styles'; +import { ProviderInterface } from '@polkadot/rpc-provider/types'; +import { RpcRxInterface } from '@polkadot/rpc-rx/types'; +import { BareProps } from './types'; + import React from 'react'; import ReactDOM from 'react-dom'; import { HashRouter } from 'react-router-dom'; +import { Api } from '@polkadot/ui-react-rx/index'; -import Api from '@polkadot/ui-react-rx/Api'; +import AddressMini from './AddressMini'; +import AddressRow from './AddressRow'; +import AddressSummary from './AddressSummary'; +import Balance from './Balance'; +import Button from './Button'; +import Call from './Call'; +import CardSummary from './CardSummary'; +import Chart from './Chart'; +import CopyButton from './CopyButton'; +import Dropdown from './Dropdown'; +import Event from './Event'; +import Icon from './Icon'; +import IdentityIcon from './IdentityIcon'; +import Input from './Input'; +import InputAddress from './InputAddress'; +import InputError from './InputError'; +import InputExtrinsic from './InputExtrinsic'; +import InputFile from './InputFile'; +import InputNumber from './InputNumber'; +import InputRpc from './InputRpc'; +import InputStorage from './InputStorage'; +import Labelled from './Labelled'; +import Menu from './Menu'; +import Modal from './Modal'; +import Output from './Output'; +import Params from './Params'; +import Password from './Password'; +import Progress from './Progress'; +import Static from './Static'; +import Status from './Status'; +import Tabs from './Tabs'; type Props = BareProps & { - api?: RxApiInterface, + api?: RpcRxInterface, provider?: ProviderInterface, url?: string }; +export { + AddressMini, + AddressRow, + AddressSummary, + Balance, + Button, + Call, + CardSummary, + Chart, + CopyButton, + Dropdown, + Event, + Icon, + IdentityIcon, + Input, + InputAddress, + InputError, + InputExtrinsic, + InputFile, + InputNumber, + InputRpc, + InputStorage, + Labelled, + Menu, + Modal, + Output, + Params, + Password, + Progress, + Static, + Status, + Tabs +}; + export default function createApp (App: React.ComponentType, { api, className, provider, style, url }: Props = {}, rootId: string = 'root'): void { const rootElement = document.getElementById(rootId); diff --git a/packages/ui-app/src/styles.ts b/packages/ui-app/src/styles.ts index 74279ce63b..04d2f8c9d6 100644 --- a/packages/ui-app/src/styles.ts +++ b/packages/ui-app/src/styles.ts @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/ui-app 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 'semantic-ui-css/semantic.min.css'; diff --git a/packages/ui-app/src/styles/app.css b/packages/ui-app/src/styles/app.css index c234e56517..991c3dc241 100644 --- a/packages/ui-app/src/styles/app.css +++ b/packages/ui-app/src/styles/app.css @@ -1,6 +1,6 @@ /* Copyright 2017-2018 @polkadot/ui-app 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. */ html { height: 100%; @@ -17,12 +17,19 @@ body { height: 100%; } -h1 { +h1, h2, h3, h4, h5 { color: rgba(0, 0, 0, .6); font-weight: 100; +} + +h1 { text-transform: lowercase; } +h3, h4, h5 { + margin-bottom: 0.25rem; +} + /* a:hover { color: #D75EA1; @@ -31,6 +38,7 @@ a:hover { main { padding: 1em 2em; + min-height: 100vh; } main > section { @@ -38,11 +46,24 @@ main > section { } article { - background: #fefefe; - border: 1px solid #fafafa; + background: white; + border: 1px solid #f2f2f2; + border-left-width: 0.25rem; border-radius: 0.25rem; + /* border-top-width: 1px; */ margin: 0.5rem; - padding: 1.5rem; + padding: 1rem 1.5rem; + + &.error { + background: #fff6f6; + border-color: #e0b4b4; + color: #9f3a38; + } + + &.warning { + background: #ffffe0; + border-color: #eeeeae; + } } header, @@ -51,6 +72,12 @@ summary { text-align: center; } +/* header { + background: #f5f5f5; + margin: -1em -2em 2em; + padding: 1em 2em 0; +} */ + header+header, header+summary, summary+header { @@ -65,6 +92,7 @@ summary { } summary article { + color: rgba(0, 0, 0, 0.6); flex: 0 1 auto; text-align: left; } diff --git a/packages/ui-app/src/styles/components.css b/packages/ui-app/src/styles/components.css index a693e9dc61..e17626ad2d 100644 --- a/packages/ui-app/src/styles/components.css +++ b/packages/ui-app/src/styles/components.css @@ -1,6 +1,6 @@ /* Copyright 2017-2018 @polkadot/ui-app 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 './partials/_variables.css'; @@ -35,6 +35,10 @@ header .ui--Button-Group { text-align: center; } +.ui.input .ui--Button-Group { + margin: 0; +} + .ui--AddressMini { display: inline-block; padding: 0 0.25rem 0 0; @@ -80,7 +84,7 @@ header .ui--Button-Group { .ui--AddressSummary { padding: 0 1em; - text-align: left; + /* text-align: left; */ white-space: nowrap } @@ -118,13 +122,17 @@ header .ui--Button-Group { opacity: 0.45; } +.ui--AddressSummary-balance { + padding-top: 0.5em; +} + .ui--AddressSummary-balance.rx--updated, .ui--AddressSummary-nonce.rx--updated { opacity: 1; } .ui--AddressSummary-data { - padding: 0.5em 0; + padding: 0; white-space: nowrap; } @@ -133,13 +141,19 @@ header .ui--Button-Group { vertical-align: middle; } -.ui--AddressSummary-address { +.ui--AddressSummary-accountId, +.ui--AddressSummary-accountIndex { display: inline-block; font-family: monospace; font-size: 1.5em; padding: 0; } +.ui--AddressSummary-accountIndex { + font-size: 1.25em; + font-style: italic; +} + .ui--CardSummary .ui.label { padding-left: 0; padding-right: 0; @@ -167,6 +181,7 @@ header .ui--Button-Group { .ui--CopyButton { cursor: copy !important; + margin-left: 0.25rem !important; } .ui--InputFile { @@ -174,9 +189,9 @@ header .ui--Button-Group { border: 1px dashed rgba(34, 36, 38, 0.15); border-radius: $small-corner; display: flex; - justify-content: center; font-size: 1.2em; height: 5em; + justify-content: center; margin-bottom: 0.5rem; width: 100% !important; @@ -194,3 +209,70 @@ header .ui--Button-Group { color: rgba(0, 0, 0, .6); } } + +.ui--Status { + display: inline-block; + position: fixed; + right: 0.25rem; + top: 0.25rem; + z-index: 1001; + + .ui--IdentityIcon { + margin-left: 0 !important; + } + + .item { + display: block; + text-align: right; + + > .wrapper { + display: inline-block; + + > .container { + align-items: center; + background: #00688b; + border-radius: $small-corner; + color: white; + display: flex; + margin-bottom: 0.25rem; + padding: 0 0.5rem; + text-align: center; + opacity: 0.9; + vertical-align: middle; + + .desc { + padding: 0.5rem 1rem; + + .status { + font-weight: 700; + } + } + + .short { + font-size: 2.5rem; + padding: 0.5rem; + + i.icon { + line-height: 1; + } + } + } + } + + &.cancelled > .wrapper > .container { + background: #cd9b1d + } + + &.completed > .wrapper > .container, + &.finalised > .wrapper > .container, + &.success > .wrapper > .container { + background: green; + } + + &.dropped > .wrapper > .container , + &.error > .wrapper > .container , + &.usurped > .wrapper > .container { + background: red; + } + } +} diff --git a/packages/ui-app/src/styles/form.css b/packages/ui-app/src/styles/form.css index 4d145572b1..ea7bf202dc 100644 --- a/packages/ui-app/src/styles/form.css +++ b/packages/ui-app/src/styles/form.css @@ -1,6 +1,6 @@ /* Copyright 2017-2018 @polkadot/ui-app 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. */ .ui--grid, .ui--row { @@ -9,11 +9,12 @@ .ui--grid, .ui--row { + align-items: stretch; display: flex; flex-wrap: wrap; flex-direction: row; justify-content: flex-start; - align-items: stretch; + text-align: left; } .ui--grid > div, diff --git a/packages/ui-app/src/styles/partials/_variables.css b/packages/ui-app/src/styles/partials/_variables.css index 8494a11faf..a0da933277 100644 --- a/packages/ui-app/src/styles/partials/_variables.css +++ b/packages/ui-app/src/styles/partials/_variables.css @@ -1,5 +1,5 @@ /* Copyright 2017-2018 @polkadot/ui-app 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. */ $small-corner: .28571429rem; diff --git a/packages/ui-app/src/styles/rx.css b/packages/ui-app/src/styles/rx.css index 5698c791a6..14692df1eb 100644 --- a/packages/ui-app/src/styles/rx.css +++ b/packages/ui-app/src/styles/rx.css @@ -1,6 +1,6 @@ /* Copyright 2017-2018 @polkadot/ui-app 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. */ .rx--updated { background: #ffffe0 !important; diff --git a/packages/ui-app/src/styles/semantic.css b/packages/ui-app/src/styles/semantic.css index 80aed15731..d52e9c145b 100644 --- a/packages/ui-app/src/styles/semantic.css +++ b/packages/ui-app/src/styles/semantic.css @@ -1,6 +1,6 @@ /* Copyright 2017-2018 @polkadot/ui-app 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 'partials/_variables.css'; @@ -56,15 +56,33 @@ z-index: 1; } -.ui.modal > .actions { - background: transparent; - border-top: none; - text-align: right; -} +.ui.modal { + background: #fdfdfd; -.ui.modal > .header { - border-bottom: none; - padding-bottom: 0; + > .actions, + > .content, + > .header { + background: transparent; + } + + > .actions { + border-top: none; + text-align: right; + } + + > .content { + text-align: center; + } + + > .header { + border-bottom: none; + padding-bottom: 0; + } + + .description { + margin: 1.5em 0; + font-weight: 700; + } } .ui.page.modals.transition.visible { @@ -95,3 +113,21 @@ .ui.disabled.button:hover { opacity: 0.1 !important; } + +/* modals aligned to top, not center */ +.ui.dimmer { + justify-content: flex-start; +} + +.ui.menu.tabular { + background: #f2f2f2; + /* border-color: white; */ + /* break out of the wrapping main padding */ + margin: -1em -2em 0; + padding: 1em 2em 0; + + .item.active { + background: #fafafa; + /* border-color: white; */ + } +} diff --git a/packages/ui-app/src/styles/theme/_colors-polkadot.css b/packages/ui-app/src/styles/theme/_colors-polkadot.css index e08ba015a0..c9bf244c48 100644 --- a/packages/ui-app/src/styles/theme/_colors-polkadot.css +++ b/packages/ui-app/src/styles/theme/_colors-polkadot.css @@ -1,6 +1,6 @@ /* Copyright 2017-2018 @polkadot/ui-app 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. */ $green: #77c689; $orange: #f6a46e; diff --git a/packages/ui-app/src/styles/theme/_colors-substrate.css b/packages/ui-app/src/styles/theme/_colors-substrate.css index baf1b9b284..31f1c2a4b3 100644 --- a/packages/ui-app/src/styles/theme/_colors-substrate.css +++ b/packages/ui-app/src/styles/theme/_colors-substrate.css @@ -1,3 +1,3 @@ /* Copyright 2017-2018 @polkadot/ui-app 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. */ diff --git a/packages/ui-app/src/styles/theme/polkadot.css b/packages/ui-app/src/styles/theme/polkadot.css index a6152bb0c5..567eedca41 100644 --- a/packages/ui-app/src/styles/theme/polkadot.css +++ b/packages/ui-app/src/styles/theme/polkadot.css @@ -1,6 +1,6 @@ /* Copyright 2017-2018 @polkadot/ui-app 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 './_colors-polkadot.css'; diff --git a/packages/ui-app/src/styles/theme/substrate.css b/packages/ui-app/src/styles/theme/substrate.css index 1633f3925d..b89c560a5f 100644 --- a/packages/ui-app/src/styles/theme/substrate.css +++ b/packages/ui-app/src/styles/theme/substrate.css @@ -1,6 +1,6 @@ /* Copyright 2017-2018 @polkadot/ui-app 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 './_colors-substrate.css'; diff --git a/packages/ui-app/src/translate.ts b/packages/ui-app/src/translate.ts index a4e019538e..7aa681d704 100644 --- a/packages/ui-app/src/translate.ts +++ b/packages/ui-app/src/translate.ts @@ -1,7 +1,7 @@ // Copyright 2017-2018 @polkadot/ui-app 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(['ui']); +export default withNamespaces(['ui']); diff --git a/packages/ui-app/src/types.d.ts b/packages/ui-app/src/types.ts similarity index 61% rename from packages/ui-app/src/types.d.ts rename to packages/ui-app/src/types.ts index 6fd7bef95e..98979b4029 100644 --- a/packages/ui-app/src/types.d.ts +++ b/packages/ui-app/src/types.ts @@ -1,9 +1,9 @@ // Copyright 2017-2018 @polkadot/ui-app 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 { TranslationFunction } from 'i18next'; -import { RxApiInterface } from '@polkadot/api-rx/types'; +import { WithNamespaces } from 'react-i18next'; +import { RpcRxInterface } from '@polkadot/rpc-rx/types'; export type BareProps = { className?: string, @@ -12,12 +12,10 @@ export type BareProps = { } }; -export type I18nProps = BareProps & { - t: TranslationFunction -}; +export type I18nProps = BareProps & WithNamespaces; export type BaseContext = { - api: RxApiInterface, + api: RpcRxInterface, // TODO: Set the correct type router: { route: { diff --git a/packages/ui-app/src/util/classes.ts b/packages/ui-app/src/util/classes.ts index d3fd2afb96..9bf25b2d15 100644 --- a/packages/ui-app/src/util/classes.ts +++ b/packages/ui-app/src/util/classes.ts @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/ui-app 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. export default function classes (...classNames: Array): string { return classNames diff --git a/packages/ui-app/src/util/prettyJson.ts b/packages/ui-app/src/util/prettyJson.ts deleted file mode 100644 index 1b84441d4f..0000000000 --- a/packages/ui-app/src/util/prettyJson.ts +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-app authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import bnToHex from '@polkadot/util/bn/toHex'; -import u8aToHex from '@polkadot/util/u8a/toHex'; -import isBn from '@polkadot/util/is/bn'; -import isFunction from '@polkadot/util/is/function'; -import isObject from '@polkadot/util/is/object'; -import isU8a from '@polkadot/util/is/u8a'; - -function format (key: string | number, value: any): any { - if (isU8a(value)) { - return u8aToHex(value); - } - - if (isBn(value)) { - return bnToHex(value); - } - - if (Array.isArray(value)) { - return value.map((entry, index) => - format(index, entry) - ); - } - - if (isObject(value) && !isFunction(value.toString)) { - const obj = value as { [index: string]: any }; - - return Object.keys(obj).reduce((map, key) => { - map[key] = format(key, obj[key]); - - return map; - }, {} as { [index: string]: any }); - } - - return value; -} - -export default function prettyJson (value: any): string { - return JSON.stringify(value, format); -} diff --git a/packages/ui-app/src/util/shouldDisplaySection.spec.js b/packages/ui-app/src/util/shouldDisplaySection.spec.js deleted file mode 100644 index f719f5adb8..0000000000 --- a/packages/ui-app/src/util/shouldDisplaySection.spec.js +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-app authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import { shouldDisplaySection } from './shouldDisplaySection'; - -describe('input extrinsic section', () => { - let type, dummySection; - - beforeEach(() => { - type = 'public'; - - dummySection = { - name: 'dummy', - description: 'an dummy extrinsic section', - isDeprecated: false, - isHidden: false, - private: {}, - public: { - didUpdate: { - isDeprecated: false, - isHidden: false - } - } - } - }); - - it('will be shown if section and its associated methods are not deprecated or hidden', () => { - const expectedOutput = true; - const actualOutput = shouldDisplaySection(dummySection, type); - - expect(actualOutput).toEqual(expectedOutput); - }); - - it('will not be shown if section is hidden', () => { - dummySection['isHidden'] = true; - const expectedOutput = false; - const actualOutput = shouldDisplaySection(dummySection, type); - - expect(actualOutput).toEqual(expectedOutput); - }); - - it('will not be shown if section is deprecated', () => { - dummySection['isDeprecated'] = true; - const expectedOutput = false; - const actualOutput = shouldDisplaySection(dummySection, type); - - expect(actualOutput).toEqual(expectedOutput); - }); - - it('will not be shown if section is not deprecated or hidden and no associated methods exist', () => { - type = 'private'; - const expectedOutput = false; - const actualOutput = shouldDisplaySection(dummySection, type); - - expect(actualOutput).toEqual(expectedOutput); - }); - - it('will not be shown if section is not deprecated or hidden but an associated method is deprecated or hidden', () => { - dummySection['public']['didUpdate']['isHidden'] = true; - const expectedOutput = false; - const actualOutput = shouldDisplaySection(dummySection, type); - - expect(actualOutput).toEqual(expectedOutput); - }); - - it('will not be shown if section methods are undefined or not an object', () => { - type = 'non-existant-type'; - const expectedOutput = false; - const actualOutput = shouldDisplaySection(dummySection, type); - - expect(actualOutput).toEqual(expectedOutput); - }); - -}); diff --git a/packages/ui-app/src/util/shouldDisplaySection.ts b/packages/ui-app/src/util/shouldDisplaySection.ts deleted file mode 100644 index e46e4f10c4..0000000000 --- a/packages/ui-app/src/util/shouldDisplaySection.ts +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-app authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import { Section, SectionItems } from '@polkadot/params/types'; -import { SectionVisibilityAll } from '../util/types'; - -import isUndefined from '@polkadot/util/is/undefined'; -import isNull from '@polkadot/util/is/null'; - -function anyMethodToDisplay (methods: SectionItems) { - if (isUndefined(methods) || isNull(methods)) { - return false; - } - - return Object - .keys(methods) - .filter((name) => { - const { isDeprecated, isHidden } = methods[name]; - - return !isDeprecated && !isHidden; - }) - .length !== 0; -} - -export function shouldDisplaySection (section: Section, type: SectionVisibilityAll) { - if (isUndefined(section)) { - return false; - } - - const methods = section[type]; - - return !section.isDeprecated && !section.isHidden && anyMethodToDisplay(methods); -} diff --git a/packages/ui-app/src/util/toAddress.ts b/packages/ui-app/src/util/toAddress.ts index d61df9d6d1..e075c252be 100644 --- a/packages/ui-app/src/util/toAddress.ts +++ b/packages/ui-app/src/util/toAddress.ts @@ -1,11 +1,9 @@ // Copyright 2017-2018 @polkadot/ui-app 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 addressDecode from '@polkadot/util-keyring/address/decode'; -import addressEncode from '@polkadot/util-keyring/address/encode'; -import isHex from '@polkadot/util/is/hex'; -import hexToU8a from '@polkadot/util/hex/toU8a'; +import keyring from '@polkadot/ui-keyring'; +import { hexToU8a, isHex } from '@polkadot/util'; export default function toAddress (value?: string | Uint8Array): string | undefined { if (!value) { @@ -13,12 +11,13 @@ export default function toAddress (value?: string | Uint8Array): string | undefi } try { - return addressEncode( + return keyring.encodeAddress( isHex(value) - ? hexToU8a(value as string) - : addressDecode(value) + ? hexToU8a(value) + : keyring.decodeAddress(value) ); } catch (error) { console.error('Unable to encode address', value); + return; } } diff --git a/packages/ui-app/src/util/toShortAddress.ts b/packages/ui-app/src/util/toShortAddress.ts index f572c535b8..5cb5579aa2 100644 --- a/packages/ui-app/src/util/toShortAddress.ts +++ b/packages/ui-app/src/util/toShortAddress.ts @@ -1,7 +1,13 @@ // Copyright 2017-2018 @polkadot/ui-app 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. -export default function toShortAddress (address: string): string { - return `${address.slice(0, 7)}…${address.slice(-7)}`; +import { AccountId, AccountIndex, Address } from '@polkadot/types'; + +export default function toShortAddress (_address?: AccountId | AccountIndex | Address | string | null): string { + const address = (_address || '').toString(); + + return (address.length > 15) + ? `${address.slice(0, 7)}…${address.slice(-7)}` + : address; } diff --git a/packages/ui-app/src/util/types.d.ts b/packages/ui-app/src/util/types.ts similarity index 64% rename from packages/ui-app/src/util/types.d.ts rename to packages/ui-app/src/util/types.ts index 1fa35af2fc..05a9a000b6 100644 --- a/packages/ui-app/src/util/types.d.ts +++ b/packages/ui-app/src/util/types.ts @@ -1,14 +1,12 @@ // Copyright 2017-2018 @polkadot/ui-app 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. export type DropdownOption = { className?: string, key?: string, - text: any, // string | React$Node, + text: React.ReactNode, value: string }; export type DropdownOptions = Array; - -export type SectionVisibilityAll = 'private' | 'public'; diff --git a/packages/ui-identicon/LICENSE b/packages/ui-identicon/LICENSE deleted file mode 100644 index 5652064fe5..0000000000 --- a/packages/ui-identicon/LICENSE +++ /dev/null @@ -1,16 +0,0 @@ -ISC License (ISC) - -Copyright 2016 Dan Finlay -Copyright 2017-2018 @polkadot/ui-identicon 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. diff --git a/packages/ui-identicon/README.md b/packages/ui-identicon/README.md deleted file mode 100644 index 7c388156bc..0000000000 --- a/packages/ui-identicon/README.md +++ /dev/null @@ -1,39 +0,0 @@ -[![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) -[![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/ui-identicon.svg?style=flat-square)](https://www.npmjs.com/package/@polkadot/ui-identicon) -[![travis](https://img.shields.io/travis/polkadot-js/apps.svg?style=flat-square)](https://travis-ci.org/polkadot-js/ui) -[![maintainability](https://img.shields.io/codeclimate/maintainability/polkadot-js/apps.svg?style=flat-square)](https://codeclimate.com/github/polkadot-js/apps/maintainability) -[![coverage](https://img.shields.io/coveralls/polkadot-js/apps.svg?style=flat-square)](https://coveralls.io/github/polkadot-js/apps?branch=master) -[![dependency](https://david-dm.org/polkadot-js/apps.svg?style=flat-square&path=packages/ui-identicon)](https://david-dm.org/polkadot-js/apps?path=packages/ui-identicon) -[![devDependency](https://david-dm.org/polkadot-js/apps/dev-status.svg?style=flat-square&path=packages/ui-identicon)](https://david-dm.org/polkadot-js/apps?path=packages/ui-identicon#info=devDependencies) - -# @polkadot/ui-identicon - -Adapted from [Jazzicon](https://github.com/danfinlay/jazzicon) by Dan Finlay with the following changes - - -- Random values now is read from the Uint8Array supplied (as opposed to having the seed as a number). This allows us to give an publicKey/address as an input and use those values in the pattern generation. -- Upgrade to the underlying [color](https://github.com/Qix-/color) library -- Generate circles as shapes (instead of rectangles) -- Interface updated to take in optional className & style -- Update everywhere to use ES6 -- Split source into self-contained functions (TODO: future testing) -- Everything has been updated to use flow -- Test the library functions -- Copyright headers added (original also under ISC) - -## Usage - -```js -import identicon from '@polkadot/ui-identicon'; - -const publicKey = new Uint8Array([...]); // 32 bytes -const body = document.querySelector('body'); -const identity = identicon(publicKey, 100 /* diameter, optional */, 'my-class' /* className, optional */ /* style. optional */ /* colors, optional */); - -body.append(identity); -``` - -Also see [src/demo.js](src/demo.js) for a randomly generated example. - -![demo](https://raw.githubusercontent.com/polkadot-js/ui/master/packages/ui-identicon/demo.png) diff --git a/packages/ui-identicon/demo.png b/packages/ui-identicon/demo.png deleted file mode 100644 index 5698431db5..0000000000 Binary files a/packages/ui-identicon/demo.png and /dev/null differ diff --git a/packages/ui-identicon/index.html b/packages/ui-identicon/index.html deleted file mode 100644 index 58667b9ffa..0000000000 --- a/packages/ui-identicon/index.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - -
- - - diff --git a/packages/ui-identicon/package.json b/packages/ui-identicon/package.json deleted file mode 100644 index 3b9ed7ea00..0000000000 --- a/packages/ui-identicon/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "@polkadot/ui-identicon", - "version": "0.20.30", - "description": "Renders an SVG picture representing an address", - "main": "index.js", - "scripts": { - "build": "polkadot-dev-build-babel", - "check": "eslint src && flow check", - "test": "echo \"Tests only available from root wrapper\"" - }, - "author": "Jaco Greeff ", - "maintainers": [ - "Jaco Greeff " - ], - "contributors": [ - "Dan Finlay" - ], - "license": "ISC", - "dependencies": { - "@babel/runtime": "^7.0.0", - "@types/color": "^3.0.0", - "color": "^3.0.0" - }, - "devDependencies": { - "@polkadot/util-crypto": "^0.30.4", - "xmlserializer": "^0.6.1" - } -} diff --git a/packages/ui-identicon/src/colors.spec.js b/packages/ui-identicon/src/colors.spec.js deleted file mode 100644 index d3b3bf10d8..0000000000 --- a/packages/ui-identicon/src/colors.spec.js +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-identicon authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import newSeeder from './seeder'; -import newColors from './colors'; - -describe('colors', () => { - let colors; - - beforeEach(() => { - colors = newColors(newSeeder()); - }); - - it('generates using default alpha', () => { - expect( - colors() - ).toEqual('hsla(166.70000000000005, 98.6%, 27.6%, 0.9)'); - }); - - it('applies specified alpha', () => { - expect( - colors(0.5) - ).toEqual('hsla(166.70000000000005, 98.6%, 27.6%, 0.5)'); - }); - - it('rolates colors', () => { - colors(); - - expect( - colors() - ).not.toEqual('hsla(166.70000000000005, 98.6%, 27.6%, 0.9)'); - }); - - it('works in edge conditions (0xff)', () => { - const u8a = new Uint8Array(32); - - u8a.fill(255); - - expect( - colors = newColors(newSeeder(u8a)) - ).not.toThrow(); - - expect( - colors() - ).toEqual('hsla(234.39999999999998, 75.9%, 51.2%, 0.9)'); - }); -}); diff --git a/packages/ui-identicon/src/colors.ts b/packages/ui-identicon/src/colors.ts deleted file mode 100644 index 49315e6e4a..0000000000 --- a/packages/ui-identicon/src/colors.ts +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2016 Dan Finlay -// Copyright 2017-2018 @polkadot/ui-identicon authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import { Seeder } from './types'; - -import Color from 'color'; - -import { COLORS } from './defaults'; - -type ColorGen = { - (alpha?: number): string -}; - -const WOBBLE = 30; - -export default function colors (seeder: Seeder): ColorGen { - const amount = (seeder() * WOBBLE) - (WOBBLE / 2); - const all = COLORS.map((hex) => Color(hex).rotate(amount)); - - return (alpha: number = 0.9): string => { - const index = Math.floor(all.length * seeder()); - - return all.splice(index, 1)[0] - .alpha(alpha) - .string(); - }; -} diff --git a/packages/ui-identicon/src/container.spec.js b/packages/ui-identicon/src/container.spec.js deleted file mode 100644 index dc9998cf81..0000000000 --- a/packages/ui-identicon/src/container.spec.js +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-identicon authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import container from './container'; - -describe('container', () => { - it('applies default styles', () => { - expect( - container(100).style._values - ).toMatchObject({ - 'background': 'white', - 'border-radius': '50px', - 'display': 'inline-block', - 'height': '100px', - 'margin': '0px', - 'overflow': 'hidden', - 'padding': '0px', - 'width': '100px' - }); - }); - - it('overrides with supplied styles', () => { - expect( - container(50, 'black', '', { display: 'block' }).style._values - ).toMatchObject({ - 'background': 'black', - 'border-radius': '25px', - 'display': 'block', - 'height': '50px', - 'margin': '0px', - 'overflow': 'hidden', - 'padding': '0px', - 'width': '50px' - }); - }); - - it('applies the specified className', () => { - expect( - container(100, 'blue', 'testClass').className - ).toEqual('testClass'); - }); -}); diff --git a/packages/ui-identicon/src/container.ts b/packages/ui-identicon/src/container.ts deleted file mode 100644 index b844e018d6..0000000000 --- a/packages/ui-identicon/src/container.ts +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2016 Dan Finlay -// Copyright 2017-2018 @polkadot/ui-identicon authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -export default function container (diameter: number, background: string = 'white', className: string = '', _style: { [index: string]: string } = {}): HTMLElement { - const element = document.createElement('div'); - const style = Object.assign({ - background, - borderRadius: `${diameter / 2}px`, - display: 'inline-block', - height: `${diameter}px`, - margin: '0px', - overflow: 'hidden', - padding: '0px', - width: `${diameter}px` - }, _style); - - element.className = className; - element.style.background = background; - - // FIXME Flow seems to believe element.style[key] has number keys - Object.keys(style).forEach((key: any) => { - element.style[key] = style[key]; - }); - - return element; -} diff --git a/packages/ui-identicon/src/defaults.ts b/packages/ui-identicon/src/defaults.ts deleted file mode 100644 index c76d162ae1..0000000000 --- a/packages/ui-identicon/src/defaults.ts +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2016 Dan Finlay -// Copyright 2017-2018 @polkadot/ui-identicon authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -const COLORS: Array = [ - '#01888C', // teal - '#FC7500', // bright orange - '#034F5D', // dark teal - '#F73F01', // orangered - '#FC1960', // magenta - '#C7144C', // raspberry - '#F3C100', // goldenrod - '#1598F2', // lightning blue - '#2465E1', // sail blue - '#F19E02' // gold -]; - -const SHAPE_COUNT = 5; - -export { - COLORS, - SHAPE_COUNT -}; diff --git a/packages/ui-identicon/src/demo.ts b/packages/ui-identicon/src/demo.ts deleted file mode 100644 index 4cd8077a31..0000000000 --- a/packages/ui-identicon/src/demo.ts +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2016 Dan Finlay -// Copyright 2017-2018 @polkadot/ui-identicon authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import isNull from '@polkadot/util/is/null'; -import randomAsU8a from '@polkadot/util-crypto/random/asU8a'; - -import identicon from './index'; - -const element = document.getElementById('demo'); - -function generateIcon (seed: Uint8Array = randomAsU8a(32)): void { - const start = Date.now(); - - if (isNull(element)) { - throw new Error('Unable to find #demo element'); - } - - element.appendChild( - identicon(seed, 100, 'padded') - ); - - console.log(`Icon generated in ${(Date.now() - start)}ms`); -} - -function generateIcons (count: number = 512): void { - generateIcon(new Uint8Array(32)); - - for (let index = 1; index < count; index++) { - generateIcon(); - } -} - -generateIcons(); diff --git a/packages/ui-identicon/src/index.spec.js b/packages/ui-identicon/src/index.spec.js deleted file mode 100644 index 065f0f72e7..0000000000 --- a/packages/ui-identicon/src/index.spec.js +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-identicon authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import xmlserializer from 'xmlserializer'; - -import identicon from './index'; - -describe('identicon', () => { - it('generates a basic [0,..,0] identicon', () => { - expect( - xmlserializer.serializeToString( - identicon(new Uint8Array(32)) - ) - ).toEqual('
'); - }); - - it('allows overrides', () => { - expect( - xmlserializer.serializeToString( - identicon(new Uint8Array(32), 100, 'testClass', { display: 'block' }) - ) - ).toEqual('
'); - }); -}); diff --git a/packages/ui-identicon/src/index.ts b/packages/ui-identicon/src/index.ts deleted file mode 100644 index 3f5d4af119..0000000000 --- a/packages/ui-identicon/src/index.ts +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2016 Dan Finlay -// Copyright 2017-2018 @polkadot/ui-identicon authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import colors from './colors'; -import newContainer from './container'; -import newSeeder from './seeder'; -import newShape from './shape/circle'; -import newElement from './svg/element'; -import { SHAPE_COUNT } from './defaults'; - -export default function identicon (seed: string | Uint8Array, diameter: number = 256, className: string = '', style?: { [index: string]: string }): HTMLElement { - const seeder = newSeeder(seed); - const colorGen = colors(seeder); - const outer = newContainer(diameter, 'white', className, style); - const container = newContainer(diameter, colorGen()); - const svg = newElement(diameter); - - outer.appendChild(container); - container.appendChild(svg); - - for (let count = 0; count < SHAPE_COUNT; count++) { - const fill = colorGen(); - const shape = newShape(seeder, fill, diameter, count); - - svg.appendChild(shape); - } - - return outer; -} diff --git a/packages/ui-identicon/src/seeder.spec.js b/packages/ui-identicon/src/seeder.spec.js deleted file mode 100644 index 845c940970..0000000000 --- a/packages/ui-identicon/src/seeder.spec.js +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-identicon authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import newSeeder from './seeder'; - -describe('seeder', () => { - let seeder; - - beforeEach(() => { - seeder = newSeeder(new Uint8Array([1, 2, 3, 4])); - }); - - it('generates numbers using 2 spaces', () => { - expect( - seeder() - ).toEqual(0.0156402587890625); - }); - - it('generates numbers using 2 spaces (incremented)', () => { - seeder(); - - expect( - seeder() - ).toEqual(0.0078582763671875); - }); -}); diff --git a/packages/ui-identicon/src/seeder.ts b/packages/ui-identicon/src/seeder.ts deleted file mode 100644 index 88473e096a..0000000000 --- a/packages/ui-identicon/src/seeder.ts +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-identicon authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import { Seeder } from './types'; - -import isU8a from '@polkadot/util/is/u8a'; -import u8aFromString from '@polkadot/util/u8a/fromString'; - -const DIVISOR = 256 * 256; - -export default function seeder (_seed: string | Uint8Array = new Uint8Array(32)): Seeder { - const seed: Uint8Array = isU8a(_seed) - ? _seed - : u8aFromString(_seed); - - let index = (seed[Math.floor(seed.length / 2)] % seed.length) - 1; - - const next = () => { - index += 1; - - if (index === seed.length) { - index = 0; - } - - return seed[index]; - }; - - return (): number => { - return ((next() * 256) + next()) / DIVISOR; - }; -} diff --git a/packages/ui-identicon/src/shape/circle.spec.js b/packages/ui-identicon/src/shape/circle.spec.js deleted file mode 100644 index db68c64c4e..0000000000 --- a/packages/ui-identicon/src/shape/circle.spec.js +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-identicon authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import xmlserializer from 'xmlserializer'; - -import seeder from '../seeder'; -import circle from './circle'; - -describe('circle', () => { - it('creates a circle shape', () => { - expect( - xmlserializer.serializeToString( - circle(seeder(), 'blue', 50, 2) - ) - ).toEqual(''); - }); -}); diff --git a/packages/ui-identicon/src/shape/circle.ts b/packages/ui-identicon/src/shape/circle.ts deleted file mode 100644 index 8253dc6274..0000000000 --- a/packages/ui-identicon/src/shape/circle.ts +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2016 Dan Finlay -// Copyright 2017-2018 @polkadot/ui-identicon authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import { Seeder } from '../types'; - -import newCircle from '../svg/circle'; -import { SHAPE_COUNT } from '../defaults'; - -export default function circle (seeder: Seeder, fill: string, diameter: number, count: number): Element { - const center = diameter / 2; - const angle = seeder() * 360; - const radius = (((SHAPE_COUNT - count) / SHAPE_COUNT) * (diameter / 2)) + ((diameter / 8) * seeder()); - const offset = (diameter / 4) * (seeder() + ((count + 1) / SHAPE_COUNT)); - const cx = (offset * Math.sin(angle)) + center; - const cy = (offset * Math.cos(angle)) + center; - const svg = newCircle(radius, cx, cy); - - svg.setAttributeNS('', 'fill', fill); - - return svg; -} diff --git a/packages/ui-identicon/src/shape/square.ts b/packages/ui-identicon/src/shape/square.ts deleted file mode 100644 index 93e1c5dde4..0000000000 --- a/packages/ui-identicon/src/shape/square.ts +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2016 Dan Finlay -// Copyright 2017-2018 @polkadot/ui-identicon authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import { Seeder } from '../types'; - -import newRect from '../svg/rect'; -import { SHAPE_COUNT } from '../defaults'; - -export default function square (seeder: Seeder, fill: string, diameter: number, count: number): Element { - const center = diameter / 2; - const svg = newRect(diameter); - const firstRot = seeder(); - const angle = Math.PI * 2 * firstRot; - const scale = count / SHAPE_COUNT; - const velocity = ((diameter / SHAPE_COUNT) * seeder()) + (scale * diameter); - const tx = (Math.cos(angle) * velocity).toFixed(3); - const ty = (Math.sin(angle) * velocity).toFixed(3); - const rot = ((firstRot * 360) + (seeder() * 180)).toFixed(1); - - svg.setAttributeNS('', 'transform', `translate(${tx} ${ty}) rotate(${rot} ${center} ${center})`); - svg.setAttributeNS('', 'fill', fill); - - return svg; -} diff --git a/packages/ui-identicon/src/svg/circle.spec.js b/packages/ui-identicon/src/svg/circle.spec.js deleted file mode 100644 index 4eab3b5800..0000000000 --- a/packages/ui-identicon/src/svg/circle.spec.js +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-identicon authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import xmlserializer from 'xmlserializer'; - -import circle from './circle'; - -describe('circle', () => { - it('creates a basic SVG circle element', () => { - expect( - xmlserializer.serializeToString( - circle(123, 12, 34) - ) - ).toEqual(''); - }); -}); diff --git a/packages/ui-identicon/src/svg/circle.ts b/packages/ui-identicon/src/svg/circle.ts deleted file mode 100644 index 0003e2d568..0000000000 --- a/packages/ui-identicon/src/svg/circle.ts +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-identicon authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import createSvg from './svg'; - -export default function circle (r: number, cx: number, cy: number): Element { - const elem = createSvg('circle'); - - elem.setAttributeNS('', 'cx', `${cx}`); - elem.setAttributeNS('', 'cy', `${cy}`); - elem.setAttributeNS('', 'r', `${r}`); - - return elem; -} diff --git a/packages/ui-identicon/src/svg/element.spec.js b/packages/ui-identicon/src/svg/element.spec.js deleted file mode 100644 index e17d1fe0ff..0000000000 --- a/packages/ui-identicon/src/svg/element.spec.js +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-identicon authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import xmlserializer from 'xmlserializer'; - -import element from './element'; - -describe('element', () => { - it('creates a basic SVG element', () => { - expect( - xmlserializer.serializeToString( - element(123) - ) - ).toEqual(''); - }); -}); diff --git a/packages/ui-identicon/src/svg/element.ts b/packages/ui-identicon/src/svg/element.ts deleted file mode 100644 index 14d03f2eec..0000000000 --- a/packages/ui-identicon/src/svg/element.ts +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2016 Dan Finlay -// Copyright 2017-2018 @polkadot/ui-identicon authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import createSvg from './svg'; - -export default function element (size: number, type: string = 'svg', x: number = 0, y: number = 0): Element { - const elem = createSvg(type); - - elem.setAttributeNS('', 'x', `${x}`); - elem.setAttributeNS('', 'y', `${y}`); - elem.setAttributeNS('', 'width', `${size}`); - elem.setAttributeNS('', 'height', `${size}`); - - return elem; -} diff --git a/packages/ui-identicon/src/svg/rect.spec.js b/packages/ui-identicon/src/svg/rect.spec.js deleted file mode 100644 index 45c66c12e0..0000000000 --- a/packages/ui-identicon/src/svg/rect.spec.js +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-identicon authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import xmlserializer from 'xmlserializer'; - -import rect from './rect'; - -describe('rect', () => { - it('creates a basic SVG rect element', () => { - expect( - xmlserializer.serializeToString( - rect(123) - ) - ).toEqual(''); - }); -}); diff --git a/packages/ui-identicon/src/svg/rect.ts b/packages/ui-identicon/src/svg/rect.ts deleted file mode 100644 index 7d80a0324f..0000000000 --- a/packages/ui-identicon/src/svg/rect.ts +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-identicon authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import createElement from './element'; - -export default function rect (size: number): Element { - const elem = createElement(size, 'rect'); - - elem.setAttributeNS('', 'rx', `${size / 16}`); - elem.setAttributeNS('', 'ry', `${size / 16}`); - - return elem; -} diff --git a/packages/ui-identicon/src/svg/svg.spec.js b/packages/ui-identicon/src/svg/svg.spec.js deleted file mode 100644 index a29ac7ca5d..0000000000 --- a/packages/ui-identicon/src/svg/svg.spec.js +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-identicon authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import xmlserializer from 'xmlserializer'; - -import svg from './svg'; - -describe('svg', () => { - it('creates a basic SVG element', () => { - expect( - xmlserializer.serializeToString( - svg('rect') - ) - ).toEqual(''); - }); -}); diff --git a/packages/ui-identicon/src/svg/svg.ts b/packages/ui-identicon/src/svg/svg.ts deleted file mode 100644 index 197de2424f..0000000000 --- a/packages/ui-identicon/src/svg/svg.ts +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2016 Dan Finlay -// Copyright 2017-2018 @polkadot/ui-identicon authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -const SVG_NS = 'http://www.w3.org/2000/svg'; - -export default function svg (type: string): Element { - return document.createElementNS(SVG_NS, type); -} diff --git a/packages/ui-identicon/src/types.d.ts b/packages/ui-identicon/src/types.d.ts deleted file mode 100644 index 9b1e3fe489..0000000000 --- a/packages/ui-identicon/src/types.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-identicon authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -export type Seeder = () => number; diff --git a/packages/ui-identicon/webpack.config.js b/packages/ui-identicon/webpack.config.js deleted file mode 100644 index 9b3bf017f3..0000000000 --- a/packages/ui-identicon/webpack.config.js +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-identicon authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -const ENV = process.env.NODE_ENV || 'development'; -const isProd = ENV === 'production'; - -module.exports = { - context: __dirname, - devtool: isProd ? 'source-map' : 'cheap-eval-source-map', - entry: './src/demo.ts', - mode: ENV, - output: { - path: __dirname, - filename: './demo.js' - }, - resolve: { - extensions: ['.js', '.jsx', '.ts', '.tsx'] - }, - module: { - rules: [ - { - test: /\.(js|ts|tsx)$/, - exclude: /(node_modules)/, - use: [ - 'babel-loader' - ] - } - ] - }, - plugins: [] -}; diff --git a/packages/ui-keyring/LICENSE b/packages/ui-keyring/LICENSE deleted file mode 100644 index 9e3a5705b1..0000000000 --- a/packages/ui-keyring/LICENSE +++ /dev/null @@ -1,15 +0,0 @@ -ISC License (ISC) - -Copyright 2017-2018 @polkadot/ui-keyring 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. diff --git a/packages/ui-keyring/README.md b/packages/ui-keyring/README.md deleted file mode 100644 index d8e65a8238..0000000000 --- a/packages/ui-keyring/README.md +++ /dev/null @@ -1 +0,0 @@ -# @polkadot/ui-keyring diff --git a/packages/ui-keyring/package.json b/packages/ui-keyring/package.json deleted file mode 100644 index fbb55dcd89..0000000000 --- a/packages/ui-keyring/package.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "@polkadot/ui-keyring", - "version": "0.20.30", - "main": "index.js", - "repository": "https://github.com/polkadot-js/apps.git", - "author": "Jaco Greeff ", - "maintainers": [ - "Jaco Greeff " - ], - "contributors": [], - "license": "ISC", - "dependencies": { - "@babel/runtime": "^7.0.0", - "@polkadot/ui-react": "^0.20.30", - "@polkadot/util-keyring": "^0.30.4", - "store": "^2.0.12" - }, - "peerDependencies": { - "react": "^16.5.0", - "semantic-ui-react": "^0.80.0" - } -} diff --git a/packages/ui-keyring/src/account/addPair.ts b/packages/ui-keyring/src/account/addPair.ts deleted file mode 100644 index f704b84794..0000000000 --- a/packages/ui-keyring/src/account/addPair.ts +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-keyring authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import { KeyringPair } from '@polkadot/util-keyring/types'; -import { State } from '../types'; - -import saveAccount from './save'; - -export default function addAccountPair (state: State, pair: KeyringPair, password: string): KeyringPair { - state.keyring.addPair(pair); - - saveAccount(state, pair, password); - - return pair; -} diff --git a/packages/ui-keyring/src/account/all.ts b/packages/ui-keyring/src/account/all.ts deleted file mode 100644 index 49a82a7aa9..0000000000 --- a/packages/ui-keyring/src/account/all.ts +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-keyring authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import { KeyringAddress, State } from '../types'; - -import get from '../address/get'; - -export default function all (state: State): Array { - const available = state.accounts.subject.getValue(); - - return Object - .keys(available) - .map((address) => - get(state, address, 'account') - ) - .filter((account) => - !account.getMeta().isTesting - ); -} diff --git a/packages/ui-keyring/src/account/create.ts b/packages/ui-keyring/src/account/create.ts deleted file mode 100644 index fd341376ad..0000000000 --- a/packages/ui-keyring/src/account/create.ts +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-keyring authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import { KeyringPair, KeyringPair$Meta } from '@polkadot/util-keyring/types'; -import { State } from '../types'; - -import saveAccount from './save'; - -export default function accountCreate (state: State, seed: Uint8Array, password?: string, meta: KeyringPair$Meta = {}): KeyringPair { - const pair = state.keyring.addFromSeed(seed, meta); - - saveAccount(state, pair, password); - - return pair; -} diff --git a/packages/ui-keyring/src/account/encrypt.ts b/packages/ui-keyring/src/account/encrypt.ts deleted file mode 100644 index 1e8c4df30e..0000000000 --- a/packages/ui-keyring/src/account/encrypt.ts +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-keyring authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import { KeyringPair } from '@polkadot/util-keyring/types'; -import { State } from '../types'; - -export default function encryptAccount (state: State, pair: KeyringPair, password: string): void { - const { accounts, keyring } = state; - const json = pair.toJson(password); - - json.meta.whenEdited = Date.now(); - - keyring.addFromJson(json); - accounts.add(json.address, json); -} diff --git a/packages/ui-keyring/src/account/forget.ts b/packages/ui-keyring/src/account/forget.ts deleted file mode 100644 index 89c1a7d86b..0000000000 --- a/packages/ui-keyring/src/account/forget.ts +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-keyring authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import { State } from '../types'; - -export default function forgetAccount (state: State, address: string): void { - state.keyring.removePair(address); - state.accounts.remove(address); -} diff --git a/packages/ui-keyring/src/account/meta.ts b/packages/ui-keyring/src/account/meta.ts deleted file mode 100644 index dfca183bab..0000000000 --- a/packages/ui-keyring/src/account/meta.ts +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-keyring authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import { KeyringPair, KeyringPair$Meta } from '@polkadot/util-keyring/types'; -import { State } from '../types'; - -import store from 'store'; - -import { accountKey } from '../defaults'; - -export default function saveAccountMeta (state: State, pair: KeyringPair, meta: KeyringPair$Meta): void { - const address = pair.address(); - const json = store.get(accountKey(address)); - - pair.setMeta(meta); - json.meta = pair.getMeta(); - - state.accounts.add(json.address, json); -} diff --git a/packages/ui-keyring/src/account/save.ts b/packages/ui-keyring/src/account/save.ts deleted file mode 100644 index 76b5afaa1e..0000000000 --- a/packages/ui-keyring/src/account/save.ts +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-keyring authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import { KeyringPair } from '@polkadot/util-keyring/types'; -import { State } from '../types'; - -export default function saveAccount (state: State, pair: KeyringPair, password?: string): void { - const json = pair.toJson(password); - - if (!json.meta.whenCreated) { - json.meta.whenCreated = Date.now(); - } - - state.keyring.addFromJson(json); - state.accounts.add(json.address, json); -} diff --git a/packages/ui-keyring/src/address/all.ts b/packages/ui-keyring/src/address/all.ts deleted file mode 100644 index ba881b6a1c..0000000000 --- a/packages/ui-keyring/src/address/all.ts +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-keyring authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import { KeyringAddress, State } from '../types'; - -import get from './get'; - -export default function all (state: State): Array { - const available = state.addresses.subject.getValue(); - - return Object - .keys(available) - .map((address) => - get(state, address) - ); -} diff --git a/packages/ui-keyring/src/address/forget.ts b/packages/ui-keyring/src/address/forget.ts deleted file mode 100644 index 3b61128aa5..0000000000 --- a/packages/ui-keyring/src/address/forget.ts +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-keyring authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import { State } from '../types'; - -export default function forgetAddress (state: State, address: string): void { - state.addresses.remove(address); -} diff --git a/packages/ui-keyring/src/address/get.ts b/packages/ui-keyring/src/address/get.ts deleted file mode 100644 index 5f9c915768..0000000000 --- a/packages/ui-keyring/src/address/get.ts +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-keyring authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import { KeyringAddress, KeyringJson$Meta, State } from '../types'; - -import isString from '@polkadot/util/is/string'; -import addressDecode from '@polkadot/util-keyring/address/decode'; -import addressEncode from '@polkadot/util-keyring/address/encode'; - -export default function get (state: State, _address: string | Uint8Array, type: 'account' | 'address' = 'address'): KeyringAddress { - const address = isString(_address) - ? _address - : addressEncode(_address); - const publicKey = addressDecode(address); - const subject = type === 'account' - ? state.accounts.subject - : state.addresses.subject; - - return { - address: (): string => - address, - isValid: (): boolean => - !!subject.getValue()[address], - publicKey: (): Uint8Array => - publicKey, - getMeta: (): KeyringJson$Meta => - subject.getValue()[address].json.meta - }; -} diff --git a/packages/ui-keyring/src/address/meta.ts b/packages/ui-keyring/src/address/meta.ts deleted file mode 100644 index 7c48a0986f..0000000000 --- a/packages/ui-keyring/src/address/meta.ts +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-keyring authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import { KeyringPair$Meta } from '@polkadot/util-keyring/types'; -import { State } from '../types'; - -export default function saveMeta (state: State, address: string, meta: KeyringPair$Meta): void { - const available = state.addresses.subject.getValue(); - - const json = (available[address] && available[address].json) || { - address, - meta: { - isRecent: void 0, - whenCreated: Date.now() - } - }; - - Object.keys(meta).forEach((key) => { - json.meta[key] = meta[key]; - }); - - delete json.meta.isRecent; - - state.addresses.add(address, json); -} diff --git a/packages/ui-keyring/src/address/metaRecent.ts b/packages/ui-keyring/src/address/metaRecent.ts deleted file mode 100644 index 6bfba47842..0000000000 --- a/packages/ui-keyring/src/address/metaRecent.ts +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-keyring authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import { SingleAddress } from '../observable/types'; -import { KeyringJson, State } from '../types'; - -export default function saveRecent (state: State, address: string): SingleAddress { - const available = state.addresses.subject.getValue(); - - if (!available[address]) { - const json = { - address, - meta: { - isRecent: true, - whenCreated: Date.now() - } - }; - - state.addresses.add(address, (json as KeyringJson)); - } - - return state.addresses.subject.getValue()[address]; -} diff --git a/packages/ui-keyring/src/defaults.ts b/packages/ui-keyring/src/defaults.ts deleted file mode 100644 index 301a41588d..0000000000 --- a/packages/ui-keyring/src/defaults.ts +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-keyring authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -const ACCOUNT_PREFIX = 'account:'; -const ADDRESS_PREFIX = 'address:'; - -export const accountKey = (address: string): string => - `${ACCOUNT_PREFIX}${address}`; - -export const addressKey = (address: string): string => - `${ADDRESS_PREFIX}${address}`; - -export const accountRegex = new RegExp(`^${ACCOUNT_PREFIX}`, ''); - -export const addressRegex = new RegExp(`^${ADDRESS_PREFIX}`, ''); diff --git a/packages/ui-keyring/src/index.ts b/packages/ui-keyring/src/index.ts deleted file mode 100644 index 5e37c990d3..0000000000 --- a/packages/ui-keyring/src/index.ts +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-keyring authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import { KeyringPair, KeyringPair$Meta } from '@polkadot/util-keyring/types'; -import { SingleAddress } from './observable/types'; -import { KeyringAddress, KeyringInstance, State } from './types'; - -import testKeyring from '@polkadot/util-keyring/testing'; - -import accounts from './observable/accounts'; -import addresses from './observable/addresses'; -import development from './observable/development'; -import loadAll from './loadAll'; -import addAccountPair from './account/addPair'; -import createAccount from './account/create'; -import forgetAccount from './account/forget'; -import isAvailable from './isAvailable'; -import encryptAccount from './account/encrypt'; -import saveAccount from './account/save'; -import saveAccountMeta from './account/meta'; -import forgetAddress from './address/forget'; -import getAccounts from './account/all'; -import getAddress from './address/get'; -import getAddresses from './address/all'; -import saveAddress from './address/meta'; -import saveRecent from './address/metaRecent'; - -const state: State = { - accounts, - addresses, - keyring: testKeyring() -}; - -loadAll(state); - -// FIXME The quicker we get in https://github.com/polkadot-js/apps/issues/138 -// the better, this is now completely out of control -export default ({ - addAccountPair: (pair: KeyringPair, password: string): KeyringPair => - addAccountPair(state, pair, password), - createAccount: (seed: Uint8Array, password?: string, meta?: KeyringPair$Meta): KeyringPair => - createAccount(state, seed, password, meta), - encryptAccount: (pair: KeyringPair, password: string): void => - encryptAccount(state, pair, password), - forgetAccount: (address: string): void => - forgetAccount(state, address), - forgetAddress: (address: string): void => - forgetAddress(state, address), - isAvailable: (address: string | Uint8Array): boolean => - isAvailable(state, address), - getAccounts: (): Array => - getAccounts(state), - getAddress: (address: string | Uint8Array): KeyringAddress => - getAddress(state, address), - getAddresses: (): Array => - getAddresses(state), - getPair: (address: string | Uint8Array): KeyringPair => - state.keyring.getPair(address), - getPairs: (): Array => - state.keyring.getPairs().filter((pair) => - development.isDevelopment() || pair.getMeta().isTesting !== true - ), - loadAll: (): void => - loadAll(state), - saveAccount: (pair: KeyringPair, password?: string): void => - saveAccount(state, pair, password), - saveAccountMeta: (pair: KeyringPair, meta: KeyringPair$Meta): void => - saveAccountMeta(state, pair, meta), - saveAddress: (address: string, meta: KeyringPair$Meta): void => - saveAddress(state, address, meta), - saveRecent: (address: string): SingleAddress => - saveRecent(state, address), - setDevMode: (isDevelopment: boolean): void => - development.set(isDevelopment) -} as KeyringInstance); diff --git a/packages/ui-keyring/src/isAvailable.ts b/packages/ui-keyring/src/isAvailable.ts deleted file mode 100644 index c43cb3c16d..0000000000 --- a/packages/ui-keyring/src/isAvailable.ts +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-keyring authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import { State } from './types'; - -import isString from '@polkadot/util/is/string'; -import addressEncode from '@polkadot/util-keyring/address/encode'; - -export default function isAvailable (state: State, _address: Uint8Array | string): boolean { - const accounts = state.accounts.subject.getValue(); - const addresses = state.addresses.subject.getValue(); - - const address = isString(_address) - ? _address - : addressEncode(_address); - - return !accounts[address] && !addresses[address]; -} diff --git a/packages/ui-keyring/src/loadAll.ts b/packages/ui-keyring/src/loadAll.ts deleted file mode 100644 index 8e03b18dc9..0000000000 --- a/packages/ui-keyring/src/loadAll.ts +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-keyring authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import { KeyringPair$Json } from '@polkadot/util-keyring/types'; -import { State, KeyringJson } from './types'; - -import store from 'store'; -import addressEncode from '@polkadot/util-keyring/address/encode'; -import isHex from '@polkadot/util/is/hex'; -import hexToU8a from '@polkadot/util/hex/toU8a'; - -import saveAddress from './address/meta'; -import initOptions from './options'; -import { accountRegex, addressRegex } from './defaults'; - -function addPairs ({ accounts, keyring }: State): void { - keyring - .getPairs() - .forEach((pair) => { - const address = pair.address(); - - accounts.add(address, { - address, - meta: pair.getMeta() - }); - }); -} - -export default function loadAll (state: State): void { - const { accounts, addresses, keyring } = state; - - addPairs(state); - - store.each((json: KeyringJson, key: string) => { - if (accountRegex.test(key)) { - if (!json.meta || !json.meta.isTesting) { - keyring.addFromJson(json as KeyringPair$Json); - accounts.add(json.address, json); - } - } else if (addressRegex.test(key)) { - const address = isHex(json.address) - ? addressEncode(hexToU8a(json.address)) - : json.address; - - // NOTE This is a fix for an older version where publicKeys instead of addresses - // were saved. Here we clean the old and replace with a new address-specific key - if (address !== json.address) { - json.address = address; - - store.remove(key); - saveAddress(state, address, json.meta); - } - - addresses.add(json.address, json); - } - }); - - initOptions(state); -} diff --git a/packages/ui-keyring/src/observable/accounts.ts b/packages/ui-keyring/src/observable/accounts.ts deleted file mode 100644 index a62af1337b..0000000000 --- a/packages/ui-keyring/src/observable/accounts.ts +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-keyring authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import { accountKey } from '../defaults'; - -import genericSubject from './genericSubject'; - -export default genericSubject(accountKey, true); diff --git a/packages/ui-keyring/src/observable/addresses.ts b/packages/ui-keyring/src/observable/addresses.ts deleted file mode 100644 index e47911308c..0000000000 --- a/packages/ui-keyring/src/observable/addresses.ts +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-keyring authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import { addressKey } from '../defaults'; - -import genericSubject from './genericSubject'; - -export default genericSubject(addressKey); diff --git a/packages/ui-keyring/src/observable/development.ts b/packages/ui-keyring/src/observable/development.ts deleted file mode 100644 index 34281dcb21..0000000000 --- a/packages/ui-keyring/src/observable/development.ts +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-keyring authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import { BehaviorSubject } from 'rxjs'; - -const subject = new BehaviorSubject(false); - -export default { - isDevelopment: (): boolean => - subject.getValue(), - set: (isDevelopment: boolean): void => { - subject.next(isDevelopment); - }, - subject -}; diff --git a/packages/ui-keyring/src/observable/genericSubject.ts b/packages/ui-keyring/src/observable/genericSubject.ts deleted file mode 100644 index 292d8265db..0000000000 --- a/packages/ui-keyring/src/observable/genericSubject.ts +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-keyring authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import { BehaviorSubject } from 'rxjs'; -import { SubjectInfo, AddressSubject, SingleAddress } from './types'; -import { KeyringJson } from '../types'; - -import store from 'store'; - -import createOptionItem from '../options/item'; -import development from './development'; - -export default function genericSubject (keyCreator: (address: string) => string, withTest: boolean = false): AddressSubject { - let current: SubjectInfo = {}; - const subject = new BehaviorSubject({}); - const next = (): void => { - const isDevMode = development.isDevelopment(); - - subject.next( - Object - .keys(current) - .reduce((filtered, key) => { - const { json: { meta: { isTesting = false } = {} } = {} } = current[key]; - - if (!withTest || isDevMode || isTesting !== true) { - filtered[key] = current[key]; - } - - return filtered; - }, {} as SubjectInfo) - ); - }; - - development.subject.subscribe(next); - - return { - add: (address: string, json: KeyringJson): SingleAddress => { - current = { ...current }; - - current[address] = { - json, - option: createOptionItem(address, json.meta.name) - }; - - store.set(keyCreator(address), json); - next(); - - return current[address]; - }, - remove: (address: string) => { - current = { ...current }; - - delete current[address]; - - store.remove(keyCreator(address)); - next(); - }, - subject - }; -} diff --git a/packages/ui-keyring/src/observable/index.ts b/packages/ui-keyring/src/observable/index.ts deleted file mode 100644 index d950e3e407..0000000000 --- a/packages/ui-keyring/src/observable/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-keyring authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import { combineLatest } from 'rxjs'; -import { map } from 'rxjs/operators'; - -import accounts from './accounts'; -import addresses from './addresses'; - -export default combineLatest( - accounts.subject, - addresses.subject -).pipe( - map(([accounts, addresses]) => ({ - accounts, - addresses - })) -); diff --git a/packages/ui-keyring/src/observable/types.d.ts b/packages/ui-keyring/src/observable/types.d.ts deleted file mode 100644 index d572a6e3c8..0000000000 --- a/packages/ui-keyring/src/observable/types.d.ts +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-keyring authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import { BehaviorSubject } from 'rxjs'; -import { KeyringSectionOption } from '../options/types'; -import { KeyringJson } from '../types'; - -export type SingleAddress = { - json: KeyringJson, - option: KeyringSectionOption -} - -export type SubjectInfo = { - [index: string]: SingleAddress -}; - -export type AddressSubject = { - add: (address: string, json: KeyringJson) => SingleAddress, - remove: (address: string) => void, - subject: BehaviorSubject -}; diff --git a/packages/ui-keyring/src/options/KeyPair.css b/packages/ui-keyring/src/options/KeyPair.css deleted file mode 100644 index 0b8eb3b98a..0000000000 --- a/packages/ui-keyring/src/options/KeyPair.css +++ /dev/null @@ -1,47 +0,0 @@ -/* Copyright 2017-2018 @polkadot/ui-keyring authors & contributors -/* This software may be modified and distributed under the terms -/* of the ISC license. See the LICENSE file for details. */ - -.ui--KeyPair { - display: flex; - flex-wrap: nowrap; - justify-content: space-between; - position: relative; - white-space: nowrap; -} - -.ui--KeyPair-icon { - position: absolute; - top: -9px; - left: 0; -} - -.ui--KeyPair-address, -.ui--KeyPair-name { - display: inline-block; -} - -.ui--KeyPair-address { - flex: 1; - font-family: monospace; - margin-left: 1rem; - opacity: 0.5; - overflow: hidden; - text-align: right; - text-overflow: ellipsis; -} - -.ui--KeyPair-name { - flex: 1 0; - margin-left: 3rem; - overflow: hidden; - text-transform: uppercase; - text-overflow: ellipsis; -} - -.ui.dropdown .menu > .disabled.item.ui--KeyPair-header { - font-size: .75em; - font-weight: 700; - opacity: 1; - text-transform: uppercase; -} diff --git a/packages/ui-keyring/src/options/KeyPair.tsx b/packages/ui-keyring/src/options/KeyPair.tsx deleted file mode 100644 index 043a4c0750..0000000000 --- a/packages/ui-keyring/src/options/KeyPair.tsx +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-keyring authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import './KeyPair.css'; - -import React from 'react'; - -import IdentityIcon from '@polkadot/ui-react/IdentityIcon'; - -type Props = { - address: string, - className?: string, - name: string, - style?: { - [index: string]: string - } -}; - -export default function KeyPair ({ address, className, name, style }: Props) { - return ( -
- -
- {name} -
-
- {address} -
-
- ); -} diff --git a/packages/ui-keyring/src/options/header.ts b/packages/ui-keyring/src/options/header.ts deleted file mode 100644 index 823b45ae41..0000000000 --- a/packages/ui-keyring/src/options/header.ts +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-keyring authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import { KeyringSectionOption } from './types'; - -export default function createHeader (name: string): KeyringSectionOption { - return { - className: 'header disabled', - name, - key: `header-${name.toLowerCase()}`, - text: name, - value: null - }; -} diff --git a/packages/ui-keyring/src/options/index.ts b/packages/ui-keyring/src/options/index.ts deleted file mode 100644 index cc825dab24..0000000000 --- a/packages/ui-keyring/src/options/index.ts +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-keyring authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import { State } from '../types'; -import { SingleAddress } from '../observable/types'; -import { KeyringOptions, KeyringSectionOptions } from './types'; - -import { BehaviorSubject } from 'rxjs'; - -import observableAll from '../observable'; -import createHeader from './header'; - -function addAccounts ({ accounts }: State, options: KeyringOptions): void { - const available = accounts.subject.getValue(); - - Object - .keys(available) - .map((address) => - available[address] - ) - .forEach(({ json: { meta: { isTesting = false } }, option }: SingleAddress) => { - if (!isTesting) { - options.account.push(option); - } else { - options.testing.push(option); - } - }); -} - -function addAddresses ({ addresses }: State, options: KeyringOptions): void { - const available = addresses.subject.getValue(); - - Object - .keys(available) - .map((address) => - available[address] - ) - .forEach(({ json: { meta: { isRecent = false } }, option }: SingleAddress) => { - if (isRecent) { - options.recent.push(option); - } else { - options.address.push(option); - } - }); -} - -function emptyOptions (): KeyringOptions { - return { - account: [], - address: [], - all: [], - recent: [], - testing: [] - }; -} - -const optionsSubject: BehaviorSubject = new BehaviorSubject(emptyOptions()); - -// NOTE To be called _only_ once (should be addressed with https://github.com/polkadot-js/apps/issues/138) -export default function initOptions (state: State): void { - observableAll.subscribe((value) => { - const options = emptyOptions(); - - addAccounts(state, options); - addAddresses(state, options); - - options.address = ([] as KeyringSectionOptions).concat( - options.address.length ? [ createHeader('Addresses') ] : [], - options.address, - options.recent.length ? [ createHeader('Recent') ] : [], - options.recent - ); - options.account = ([] as KeyringSectionOptions).concat( - options.account.length ? [ createHeader('Accounts') ] : [], - options.account, - options.testing.length ? [ createHeader('Development') ] : [], - options.testing - ); - - options.all = ([] as KeyringSectionOptions).concat( - options.account, - options.address - ); - - optionsSubject.next(options); - }); -} - -export { - optionsSubject -}; diff --git a/packages/ui-keyring/src/options/item.tsx b/packages/ui-keyring/src/options/item.tsx deleted file mode 100644 index bdf2a8b4bf..0000000000 --- a/packages/ui-keyring/src/options/item.tsx +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-keyring authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import { KeyringSectionOption } from './types'; - -import React from 'react'; - -import KeyPair from './KeyPair'; - -export default function createItem (address: string, _name?: string): KeyringSectionOption { - const name = _name === undefined - ? `${address.slice(0, 7)}…${address.slice(-7)}` - : _name; - - return { - key: address, - name, - text: ( - - ), - value: address - }; -} diff --git a/packages/ui-keyring/src/options/types.d.ts b/packages/ui-keyring/src/options/types.d.ts deleted file mode 100644 index 3ec22078a7..0000000000 --- a/packages/ui-keyring/src/options/types.d.ts +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-keyring authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -export type KeyringSectionOption = { - className?: string, - disabled?: boolean, - content?: any | string, // node? - key: string | null, - name: string, - text: any | string, // node? - value: string | null -}; - -export type KeyringSectionOptions = Array; - -export type KeyringOptions = { - account: KeyringSectionOptions, - address: KeyringSectionOptions, - all: KeyringSectionOptions, - recent: KeyringSectionOptions, - testing: KeyringSectionOptions -} - -export type KeyringOption$Type = keyof KeyringOptions; diff --git a/packages/ui-keyring/src/types.d.ts b/packages/ui-keyring/src/types.d.ts deleted file mode 100644 index 70cc35d2c9..0000000000 --- a/packages/ui-keyring/src/types.d.ts +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-keyring authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import { KeyringInstance as BaseKeyringInstance, KeyringPair, KeyringPair$Meta } from '@polkadot/util-keyring/types'; -import { AddressSubject, SingleAddress } from './observable/types'; -import { KeyringSectionOption } from './options/types'; - -export type KeyringJson$Meta = { - isRecent?: boolean, - isTesting?: boolean, - name?: string, - whenCreated?: number, - whenEdited?: number, - whenUsed?: number, - [index: string]: any -}; - -export type KeyringJson = { - address: string, - meta: KeyringJson$Meta -}; - -export type KeyringAddress = { - address: () => string, - isValid: () => boolean, - publicKey: () => Uint8Array, - getMeta: () => KeyringJson$Meta -} - -export type State = { - accounts: AddressSubject, - addresses: AddressSubject, - keyring: BaseKeyringInstance -}; - -export type KeyringInstance = { - addAccountPair: (pair: KeyringPair, password: string) => KeyringPair, - createAccount: (seed: Uint8Array, password?: string, meta?: KeyringPair$Meta) => KeyringPair, - encryptAccount: (pair: KeyringPair, password: string) => void, - forgetAccount: (address: string) => void, - forgetAddress: (address: string) => void, - getAccounts: () => Array, - getAddress: (address: string | Uint8Array) => KeyringAddress, - getAddresses: () => Array, - getPair: (address: string | Uint8Array) => KeyringPair, - getPairs: () => Array, - isAvailable: (address: string | Uint8Array) => boolean, - loadAll: () => void, - saveAccount: (pair: KeyringPair, password?: string) => void, - saveAccountMeta: (pair: KeyringPair, meta: KeyringPair$Meta) => void, - saveAddress: (address: string, meta: KeyringPair$Meta) => void, - saveRecent: (address: string) => SingleAddress, - setDevMode: (isDevelopment: boolean) => void -}; diff --git a/packages/ui-react-rx/LICENSE b/packages/ui-react-rx/LICENSE index 18f0cbfaca..0d381b2e97 100644 --- a/packages/ui-react-rx/LICENSE +++ b/packages/ui-react-rx/LICENSE @@ -1,15 +1,201 @@ -ISC License (ISC) + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ -Copyright 2017-2018 @polkadot/ui-react-rx 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. diff --git a/packages/ui-react-rx/README.md b/packages/ui-react-rx/README.md index 1e89c99705..16b92bea4a 100644 --- a/packages/ui-react-rx/README.md +++ b/packages/ui-react-rx/README.md @@ -1,13 +1,3 @@ -[![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) -[![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/ui-react-rx.svg?style=flat-square)](https://www.npmjs.com/package/@polkadot/ui-react-rx) -[![travis](https://img.shields.io/travis/polkadot-js/apps.svg?style=flat-square)](https://travis-ci.org/polkadot-js/ui) -[![maintainability](https://img.shields.io/codeclimate/maintainability/polkadot-js/apps.svg?style=flat-square)](https://codeclimate.com/github/polkadot-js/apps/maintainability) -[![coverage](https://img.shields.io/coveralls/polkadot-js/apps.svg?style=flat-square)](https://coveralls.io/github/polkadot-js/apps?branch=master) -[![dependency](https://david-dm.org/polkadot-js/apps.svg?style=flat-square&path=packages/ui-react-rx)](https://david-dm.org/polkadot-js/apps?path=packages/ui-react-rx) -[![devDependency](https://david-dm.org/polkadot-js/apps/dev-status.svg?style=flat-square&path=packages/ui-react-rx)](https://david-dm.org/polkadot-js/apps?path=packages/ui-react-rx#info=devDependencies) - # @polkadot/ui-react-rx A collection of RxJS enabled React components that operate with the [@polkadot/api-rx](https://github.com/polkadot-js/api) library. It automatically manages subscriptions on behalf of the developer, providing a number of unstyled components that can be used to construct UIs. diff --git a/packages/ui-react-rx/package.json b/packages/ui-react-rx/package.json index 7fa0710a44..e6146c225d 100644 --- a/packages/ui-react-rx/package.json +++ b/packages/ui-react-rx/package.json @@ -1,6 +1,6 @@ { "name": "@polkadot/ui-react-rx", - "version": "0.20.30", + "version": "0.21.0", "description": "A collection of RxJs React components the Polkadot JS API", "main": "index.js", "keywords": [ @@ -13,7 +13,7 @@ "Jaco Greeff " ], "contributors": [], - "license": "ISC", + "license": "Apache-2.0", "engines": { "node": ">=8.0" }, @@ -30,14 +30,10 @@ }, "homepage": "https://github.com/polkadot-js/ui/tree/master/packages/ui-react-rx#readme", "dependencies": { - "@babel/runtime": "^7.0.0", - "@polkadot/api-rx": "^0.29.7", - "@polkadot/extrinsics": "^0.29.7", - "@polkadot/storage": "^0.29.7", + "@babel/runtime": "^7.2.0", + "@polkadot/api-observable": "^0.35.9", + "@polkadot/rpc-rx": "^0.35.9", + "@polkadot/types": "^0.35.9", "rxjs-compat": "^6.3.2" - }, - "devDependencies": { - "react": "^16.5.0", - "react-dom": "^16.5.0" } } diff --git a/packages/ui-react-rx/src/Api/Context.ts b/packages/ui-react-rx/src/Api/Context.ts index 8f349a7dd1..d7720ffdf7 100644 --- a/packages/ui-react-rx/src/Api/Context.ts +++ b/packages/ui-react-rx/src/Api/Context.ts @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/ui-react-rx 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 { ApiProps } from '../types'; diff --git a/packages/ui-react-rx/src/Api/index.tsx b/packages/ui-react-rx/src/Api/index.tsx index 8b8e7f6944..9dc0fe47bb 100644 --- a/packages/ui-react-rx/src/Api/index.tsx +++ b/packages/ui-react-rx/src/Api/index.tsx @@ -1,34 +1,43 @@ // Copyright 2017-2018 @polkadot/ui-react-rx 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 { ProviderInterface } from '@polkadot/api-provider/types'; -import { RxApiInterface } from '@polkadot/api-rx/types'; -import { Header } from '@polkadot/primitives/header'; +import { ProviderInterface } from '@polkadot/rpc-provider/types'; +import { RpcRxInterface } from '@polkadot/rpc-rx/types'; import { ApiProps } from '../types'; import React from 'react'; +import { combineLatest, of } from 'rxjs'; +import { catchError } from 'rxjs/operators'; +import Api from '@polkadot/api-observable'; +import defaults from '@polkadot/rpc-provider/defaults'; +import WsProvider from '@polkadot/rpc-provider/ws'; +import RxApi from '@polkadot/rpc-rx'; +import keyring from '@polkadot/ui-keyring'; +import { isTestChain } from '@polkadot/ui-react-rx/util/index'; +import settings from '@polkadot/ui-settings'; +import { Header, Method, ChainProperties } from '@polkadot/types'; -import WsProvider from '@polkadot/api-provider/ws'; -import RxApi from '@polkadot/api-rx'; -import defaults from '@polkadot/api-rx/defaults'; -import isUndefined from '@polkadot/util/is/undefined'; - -import ApiObservable from '../ApiObservable'; +import { balanceFormat } from '../util/index'; import ApiContext from './Context'; +import { InputNumber } from '@polkadot/ui-app/InputNumber'; type Props = { - api?: RxApiInterface, - children: any, // node? + api?: RpcRxInterface, + children: React.ReactNode, provider?: ProviderInterface, url?: string }; type State = ApiProps & { + chain?: string, subscriptions: Array // rxjs$ISubscription | null>; }; -export default class Api extends React.PureComponent { +// HACK Initialise with static data +Method.injectMethods(Api.extrinsics); + +export default class ApiWrapper extends React.PureComponent { state: State = {} as State; constructor (props: Props) { @@ -40,8 +49,8 @@ export default class Api extends React.PureComponent { ? new WsProvider(url) : provider ); - const setApi = (api: RxApiInterface): void => { - const apiObservable = new ApiObservable(api); + const setApi = (api: RpcRxInterface): void => { + const apiObservable = new Api(api); this.setState({ api, apiObservable }, () => { this.updateSubscriptions(); @@ -53,10 +62,11 @@ export default class Api extends React.PureComponent { setApiProvider(new WsProvider(url)); this.state = { + isApiConnected: false, + isApiReady: false, api, - apiConnected: false, apiMethods: {}, - apiObservable: new ApiObservable(api), + apiObservable: new Api(api), apiSupport: 'latest', setApi, setApiProvider, @@ -74,17 +84,19 @@ export default class Api extends React.PureComponent { } private updateSubscriptions () { - const { api } = this.state; + const { api, apiObservable } = this.state; this.unsubscribe(); this.setState({ subscriptions: [ this.subscribeIsConnected, + this.subscribeIsReady, + this.subscribeChain, this.subscribeMethodCheck ].map((fn: Function) => { try { - return fn(api); + return fn(api, apiObservable); } catch (error) { console.error(error); return null; @@ -93,53 +105,58 @@ export default class Api extends React.PureComponent { }); } - private subscribeIsConnected = (api: RxApiInterface): void => { - api - .isConnected() - .subscribe((isConnected?: boolean) => { - this.setState({ apiConnected: !!isConnected }); - }); + private subscribeChain = (rpc: RpcRxInterface, api: Api): void => { + combineLatest( + rpc.system.properties().pipe(catchError(() => of())), + api.chain() + ).subscribe(([properties = new ChainProperties(), value]: [ChainProperties, any]) => { + const chain = value + ? value.toString() + : null; + const found = settings.availableChains.find(({ name }) => name === chain) || { + networkId: 0, + tokenDecimals: 0, + tokenSymbol: undefined + }; + + console.log('found chain', chain, [...properties.entries()]); + + balanceFormat.setDefaultDecimals(properties.get('tokenDecimals') || found.tokenDecimals); + InputNumber.setUnit(properties.get('tokenSymbol') || found.tokenSymbol); + + // setup keyringonly after prefix has been set + keyring.setAddressPrefix(properties.get('networkId') || found.networkId as any); + keyring.setDevMode(isTestChain(chain || '')); + keyring.loadAll(); + + this.setState({ chain }); + }); } - private subscribeMethodCheck = (api: RxApiInterface): void => { - api.chain - .newHead() + private subscribeIsConnected = (rpc: RpcRxInterface, api: Api): void => { + rpc.isConnected().subscribe((isConnected?: boolean) => { + this.setState({ isApiConnected: !!isConnected }); + }); + } + + private subscribeIsReady = (rpc: RpcRxInterface, api: Api): void => { + api.whenReady.subscribe((isReady?: boolean) => { + this.setState({ isApiReady: !!isReady }); + }); + } + + private subscribeMethodCheck = (rpc: RpcRxInterface, api: Api): void => { + rpc.chain + .subscribeNewHead() .subscribe(async (header?: Header) => { if (!header || !header.parentHash) { return; } - try { - await this.hasChainGetBlock(header.parentHash); - } catch (error) { - // swallow - } + // NOTE no checks atm, add when new method checks are required }); } - private async hasChainGetBlock (hash: Uint8Array) { - const { api, apiMethods: { chain_getBlock } } = this.state; - - if (!isUndefined(chain_getBlock)) { - return; - } - - let available = false; - - try { - available = !!(await api.chain.getBlock(hash).toPromise()); - } catch (error) { - // swallow - } - - this.setState(({ apiMethods }) => ({ - apiMethods: { - ...apiMethods, - chain_getBlock: available - } - })); - } - private unsubscribe (): void { const { subscriptions } = this.state; @@ -155,19 +172,22 @@ export default class Api extends React.PureComponent { } render () { - const { api, apiConnected, apiMethods, apiObservable, apiSupport, setApi, setApiProvider, setApiWsUrl } = this.state; + const { isApiConnected, isApiReady, api, apiMethods, apiObservable, apiSupport, chain, setApi, setApiProvider, setApiWsUrl } = this.state; return ( - + {this.props.children} ); diff --git a/packages/ui-react-rx/src/ApiObservable/index.ts b/packages/ui-react-rx/src/ApiObservable/index.ts deleted file mode 100644 index b6df0eaffe..0000000000 --- a/packages/ui-react-rx/src/ApiObservable/index.ts +++ /dev/null @@ -1,588 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-react-rx authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import { Header } from '@polkadot/primitives/header'; -import { RxApiInterface, RxApiInterface$Method } from '@polkadot/api-rx/types'; -import { Interfaces } from '@polkadot/jsonrpc/types'; -import { BlockDecoded, ExtrinsicDecoded, SectionItem } from '@polkadot/params/types'; -import { Storages } from '@polkadot/storage/types'; -import { RxBalance, RxBalanceMap, RxFees, RxProposal, RxProposalDeposits, RxReferendum, ObservableApiInterface, KeyWithParams, KeyWithoutParams, RxReferendumVote } from './types'; - -import BN from 'bn.js'; -import { EMPTY, Observable, combineLatest } from 'rxjs'; -import { switchMap, defaultIfEmpty, map } from 'rxjs/operators'; -import storage from '@polkadot/storage'; -import assert from '@polkadot/util/assert'; -import isUndefined from '@polkadot/util/is/undefined'; - -type OptBN = BN | undefined; -type OptDate = Date | undefined; -type MapFn = (combined: R) => T; - -type ResultReferendum = [BN, ExtrinsicDecoded, number]; -type ResultProposal = [BN, ExtrinsicDecoded, string]; -type ResultProposalDeposits = [BN, Array]; - -const defaultMapFn = (result: any): any => - result; - -export default class ObservableApi implements ObservableApiInterface { - private api: RxApiInterface; - - constructor (api: RxApiInterface) { - this.api = api; - } - - private combine = (observables: Array>, mapfn: MapFn = defaultMapFn): Observable => { - return combineLatest(...observables).pipe( - // FIXME There are a couple of places now where this casting happens after rxjs 6.3.2 - defaultIfEmpty([] as any), - map(mapfn) - ); - } - - rawCall = ({ name, section }: SectionItem, ...params: Array): Observable => { - assert(section && this.api[section], `Unable to find 'api.${section}'`); - - const fn: RxApiInterface$Method = section - ? this.api[section][name] - // @ts-ignore This one is done for 'isConnected' - : this.api[name]; - - assert(fn, `Unable to find 'api${section ? '.' : ''}${section || ''}.${name}'`); - - return fn.apply(null, params); - } - - rawStorage = (key: SectionItem, ...params: Array): Observable => { - return this - .rawStorageMulti([key, ...params] as KeyWithParams) - .pipe( - // @ts-ignore After upgrade to 6.3.2 - map(([result]: Array): T => - result - ) - ); - } - - rawStorageMulti = (...keys: Array): Observable => { - return this.api.state - .storage(keys) - .pipe( - map((result?: any) => - isUndefined(result) - ? [] - : result - ) - ); - } - - bestNumber = (): Observable => { - return this - .chainNewHead() - .pipe( - map((header?: Header): OptBN => - header && header.number - ? header.number - : undefined - ) - ); - } - - chainGetBlock = (hash: Uint8Array): Observable => { - return this.api.chain.getBlock(hash); - } - - chainNewHead = (): Observable
=> { - return this.api.chain.newHead().pipe( - defaultIfEmpty() - ); - } - - democracyLaunchPeriod = (): Observable => { - return this.rawStorage(storage.democracy.public.launchPeriod); - } - - democracyNextTally = (): Observable => { - return this.rawStorage(storage.democracy.public.nextTally); - } - - democracyProposals = (): Observable> => { - return this - .rawStorage(storage.democracy.public.proposals) - .pipe( - // @ts-ignore After upgrade to 6.3.2 - map((proposals: Array = []) => - proposals - .map((result: ResultProposal): RxProposal | undefined => - result && result[1] - ? { - address: result[2], - id: result[0], - proposal: result[1] - } - : undefined - ) - .filter((proposal) => - proposal - ) - ) - ); - } - - democracyProposalCount = (): Observable => { - return this - .democracyProposals() - .pipe( - map((proposals: Array) => - proposals.length - ) - ); - } - - democracyProposalDeposits = (proposalId: BN): Observable => { - return this - .rawStorage(storage.democracy.public.depositOf, proposalId) - .pipe( - // @ts-ignore After upgrade to 6.3.2 - map((result: ResultProposalDeposits): RxProposalDeposits | undefined => - result && result[0] - ? { - addresses: result[1] || [], - balance: result[0] - } - : undefined - ) - ); - } - - democracyReferendumCount = (): Observable => { - return this.rawStorage(storage.democracy.public.referendumCount); - } - - democracyReferendumInfoOf = (referendumId: BN | number): Observable => { - return this - .rawStorage(storage.democracy.public.referendumInfoOf, referendumId) - .pipe( - // @ts-ignore After upgrade to 6.3.2 - map((result: ResultReferendum) => - result && result[1] - ? { - blockNumber: result[0], - id: new BN(referendumId), - proposal: result[1], - voteThreshold: result[2] - } - : undefined - ) - ); - } - - democracyReferendumInfos = (referendumIds: Array): Observable> => { - return this.combine( - referendumIds.map((referendumId) => - this.democracyReferendumInfoOf(referendumId) - ), - (referendums: Array = []): Array => - referendums.filter((referendum) => - referendum - ) - ); - } - - democracyReferendumVoters = (referendumId: BN): Observable> => { - return this.combine( - [ - this.democracyVotersFor(referendumId), - this.democracyVotersBalancesOf(referendumId), - this.democracyVotersVotesOf(referendumId) - ], - ([voters, balances, votes]: [Array, Array, Array]): Array => - voters.map((address, index): RxReferendumVote => ({ - address, - balance: balances[index] || new BN(0), - vote: votes[index] || false - })) - ); - } - - democracyReferendums = (): Observable> => { - return this.combine( - [ - this.democracyReferendumCount(), - this.democracyNextTally() - ] - ).pipe( - // @ts-ignore After upgrade to 6.3.2 - switchMap(([referendumCount, nextTally]: [OptBN, OptBN]): Observable> => - referendumCount && nextTally && referendumCount.gt(nextTally) && referendumCount.gtn(0) - ? this.democracyReferendumInfos( - [...Array(referendumCount.sub(nextTally).toNumber())].map((_, i) => - nextTally.addn(i).toNumber() - ) - ) - : EMPTY - ), - defaultIfEmpty([]) - ); - } - - democacyVoteOf = (index: BN, address: string): Observable => { - return this.rawStorage(storage.democracy.public.voteOf, index, address); - } - - democracyVotesOf = (index: BN, addresses: Array): Observable => { - return this.combine( - addresses.map((address) => - this.democacyVoteOf(index, address) - ) - ); - } - - democracyVotersFor = (index: BN): Observable> => { - return this - .rawStorage(storage.democracy.public.votersFor, index) - .pipe( - // @ts-ignore After upgrade to 6.3.2 - map((voters: Array = []) => - voters - ) - ); - } - - democracyVotersBalancesOf = (referendumId: BN): Observable> => { - return this - .democracyVotersFor(referendumId) - .pipe( - switchMap((voters: Array = []) => - this.votingBalances(...voters) - ), - defaultIfEmpty([] as any), - map((balances: Array) => - balances.map(({ votingBalance }) => - votingBalance - ) - ) - ); - } - - democracyVotersVotesOf = (referendumId: BN): Observable> => { - return this - .democracyVotersFor(referendumId) - .pipe( - switchMap((voters: Array = []) => - this.democracyVotesOf(referendumId, voters) - ), - defaultIfEmpty([] as any) - ); - } - - democracyVotingPeriod = (): Observable => { - return this.rawStorage(storage.democracy.public.votingPeriod); - } - - eraBlockLength = (): Observable => { - return this.combine( - [ - this.sessionLength(), - this.sessionsPerEra() - ], - ([sessionLength, sessionsPerEra]: [OptBN, OptBN]): OptBN => - sessionLength && sessionsPerEra - ? sessionLength.mul(sessionsPerEra) - : undefined - ); - } - - eraBlockProgress = (): Observable => { - return this.combine( - [ - this.sessionBlockProgress(), - this.sessionLength(), - this.sessionCurrentIndex(), - this.sessionsPerEra(), - this.eraLastLengthChange() - ], - ([sessionBlockProgress, sessionLength, sessionCurrentIndex, sessionsPerEra, eraLastLengthChange = new BN(0)]: [OptBN, OptBN, OptBN, OptBN, OptBN]): OptBN => - sessionsPerEra && sessionCurrentIndex && sessionLength && sessionBlockProgress && eraLastLengthChange - ? sessionCurrentIndex - .sub(eraLastLengthChange) - .mod(sessionsPerEra) - .mul(sessionLength) - .add(sessionBlockProgress) - : undefined - ); - } - - eraBlockRemaining = (): Observable => { - return this.combine( - [ - this.eraBlockLength(), - this.eraBlockProgress() - ], - ([eraBlockLength, eraBlockProgress]: [OptBN, OptBN]): OptBN => - eraBlockLength && eraBlockProgress - ? eraBlockLength.sub(eraBlockProgress) - : undefined - ); - } - - fees = (): Observable => { - return this - .rawStorageMulti( - [storage.staking.public.transactionBaseFee], - [storage.staking.public.transactionByteFee], - [storage.staking.public.creationFee], - [storage.staking.public.existentialDeposit ], - [storage.staking.public.transferFee ] - ) - .pipe( - // @ts-ignore After upgrade to 6.3.2 - map(([baseFee = new BN(0), byteFee = new BN(0), creationFee = new BN(0), existentialDeposit = new BN(0), transferFee = new BN(0)]: [OptBN, OptBN, OptBN, OptBN, OptBN]) => ({ - baseFee, - byteFee, - creationFee, - existentialDeposit, - transferFee - })) - ); - } - - eraLastLengthChange = (): Observable => { - return this.rawStorage(storage.staking.public.lastEraLengthChange); - } - - sessionBlockProgress = (): Observable => { - return this.combine( - [ - this.bestNumber(), - this.sessionLength(), - this.sessionLastLengthChange() - ], - ([bestNumber, sessionLength, lastSessionLengthChange]: [OptBN, OptBN, OptBN]): OptBN => - bestNumber && sessionLength && lastSessionLengthChange - ? bestNumber - .sub(lastSessionLengthChange) - .add(sessionLength) - .mod(sessionLength) - : undefined - ); - } - - sessionBlockRemaining = (): Observable => { - return this.combine( - [ - this.sessionBlockProgress(), - this.sessionLength() - ], - ([sessionBlockProgress, sessionLength]: [OptBN, OptBN]): OptBN => - sessionBlockProgress && sessionLength - ? sessionLength.sub(sessionBlockProgress) - : undefined - ); - } - - sessionBrokenPercentLate = (): Observable => { - return this.rawStorage(storage.session.public.brokenPercentLate); - } - - sessionBrokenValue = (): Observable => { - return this.combine( - [ - this.timestampNow(), - this.sessionTimeExpected(), - this.sessionTimeRemaining(), - this.sessionCurrentStart() - ], - ([now, sessionTimeExpected, sessionTimeRemaining, sessionCurrentStart]: [OptDate, OptBN, OptBN, OptDate]): OptBN => - sessionTimeExpected && sessionTimeRemaining && sessionCurrentStart && now - ? new BN( - Math.round( - 100 * (now.getTime() + sessionTimeRemaining.toNumber() - sessionCurrentStart.getTime()) / sessionTimeExpected.toNumber() - 100 - ) - ) - : undefined - ); - } - - sessionCurrentIndex = (): Observable => { - return this.rawStorage(storage.session.public.currentIndex); - } - - sessionCurrentStart = (): Observable => { - return this.rawStorage(storage.session.public.currentStart); - } - - sessionLastLengthChange = (): Observable => { - return this.rawStorage(storage.session.public.lastLengthChange); - } - - sessionLength = (): Observable => { - return this.rawStorage(storage.session.public.length); - } - - sessionsPerEra = (): Observable => { - return this.rawStorage(storage.staking.public.sessionsPerEra); - } - - sessionTimeExpected = (): Observable => { - return this.combine( - [ - this.sessionLength(), - this.timestampBlockPeriod() - ], - ([sessionLength, blockPeriod]: [OptBN, OptBN]): OptBN => - sessionLength && blockPeriod - ? blockPeriod.mul(sessionLength).muln(1000) - : undefined - ); - } - - sessionTimeRemaining = (): Observable => { - return this.combine( - [ - this.sessionBlockRemaining(), - this.timestampBlockPeriod() - ], - ([sessionBlockRemaining, blockPeriod]: [OptBN, OptBN]): OptBN => - blockPeriod && sessionBlockRemaining - ? blockPeriod.mul(sessionBlockRemaining).muln(1000) - : undefined - ); - } - - sessionValidators = (): Observable> => { - return this - .rawStorage(storage.session.public.validators) - .pipe( - // @ts-ignore After upgrade to 6.3.2 - map((validators: Array = []) => - validators - ) - ); - } - - stakingIntentions = (): Observable> => { - return this - .rawStorage(storage.staking.public.intentions) - .pipe( - // @ts-ignore After upgrade to 6.3.2 - map((intentions: Array = []) => - intentions - ) - ); - } - - stakingFreeBalanceOf = (address: string): Observable => { - return this.rawStorage(storage.staking.public.freeBalanceOf, address); - } - - stakingNominatorsFor = (address: string): Observable> => { - return this - .rawStorage(storage.staking.public.nominatorsFor, address) - .pipe( - // @ts-ignore After upgrade to 6.3.2 - map((nominators: Array = []) => - nominators - ) - ); - } - - stakingNominating = (address: string): Observable => { - return this.rawStorage(storage.staking.public.nominating, address); - } - - stakingReservedBalanceOf = (address: string): Observable => { - return this.rawStorage(storage.staking.public.reservedBalanceOf, address); - } - - timestampBlockPeriod = (): Observable => { - return this.rawStorage(storage.timestamp.public.blockPeriod); - } - - timestampNow = (): Observable => { - return this.rawStorage(storage.timestamp.public.now); - } - - systemAccountIndexOf = (address: string): Observable => { - return this.rawStorage(storage.system.public.accountIndexOf, address); - } - - validatorCount = (): Observable => { - return this.rawStorage(storage.staking.public.validatorCount); - } - - validatingBalance = (address: string): Observable => { - return this.combine( - [ - this.votingBalance(address), - this.votingBalancesNominatorsFor(address) - ], - ([balance, nominators = []]: [RxBalance, Array]): RxBalance => { - const nominatedBalance = nominators.reduce((total, nominator: RxBalance) => { - return total.add(nominator.votingBalance); - }, new BN(0)); - - const result = { - ...balance, - nominators, - nominatedBalance, - stakingBalance: nominatedBalance.add(balance.votingBalance) - }; - - return result; - } - ); - } - - validatingBalances = (...addresses: Array): Observable => { - return this.combine( - addresses.map((address) => - this.validatingBalance(address) - ), - (result: Array): RxBalanceMap => - result.reduce((balances, balance) => { - balances[balance.address] = balance; - - return balances; - }, {} as RxBalanceMap) - ); - } - - votingBalance = (address: string): Observable => { - return this.combine( - [ - this.stakingFreeBalanceOf(address), - this.stakingReservedBalanceOf(address) - ], - ([freeBalance = new BN(0), reservedBalance = new BN(0)]: [OptBN, OptBN]): RxBalance => ({ - address, - freeBalance, - nominatedBalance: new BN(0), - reservedBalance, - stakingBalance: new BN(0), - votingBalance: freeBalance.add(reservedBalance) - }) - ); - } - - votingBalancesNominatorsFor = (address: string) => { - return this - .stakingNominatorsFor(address) - .pipe( - switchMap((nominators: Array) => - this.votingBalances(...nominators) - ), - defaultIfEmpty([] as any) - ); - } - - votingBalances = (...addresses: Array): Observable => { - return this.combine( - addresses.map((address) => - this.votingBalance(address) - ) - ); - } -} diff --git a/packages/ui-react-rx/src/ApiObservable/types.d.ts b/packages/ui-react-rx/src/ApiObservable/types.d.ts deleted file mode 100644 index 2db4395b55..0000000000 --- a/packages/ui-react-rx/src/ApiObservable/types.d.ts +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-react-rx authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import BN from 'bn.js'; -import { Observable } from 'rxjs'; -import { Interfaces } from '@polkadot/jsonrpc/types'; -import { BlockDecoded, ExtrinsicDecoded, SectionItem } from '@polkadot/params/types'; -import { Header } from '@polkadot/primitives/header'; -import { Storages } from '@polkadot/storage/types'; - -export type RxBalance = { - address: string, - freeBalance: BN, - nominatedBalance: BN, - reservedBalance: BN, - votingBalance: BN, - stakingBalance: BN, - nominators?: Array -} - -export type RxFees = { - baseFee: BN, - byteFee: BN, - creationFee: BN, - existentialDeposit: BN, - transferFee: BN, -}; - -export type RxProposal = { - address: string, - id: BN, - proposal: ExtrinsicDecoded -}; - -export type RxProposalDeposits = { - balance: BN, - addresses: Array -} - -export type RxReferendum = { - blockNumber: BN, - id: BN, - proposal: ExtrinsicDecoded, - voteThreshold: number -} - -export type RxReferendumVote = { - address: string, - balance: BN, - vote: boolean -}; - -export type RxBalanceMap = { - [index: string]: RxBalance -} - -export type KeyWithoutParams = [SectionItem]; -export type KeyWithParams = [SectionItem, any]; - -export interface ObservableApiInterface { - rawCall: ({ name, section }: SectionItem, ...params: Array) => Observable, - rawStorage: (key: SectionItem, ...params: Array) => Observable, - rawStorageMulti: (...keys: Array) => Observable, - bestNumber: () => Observable, - chainGetBlock: (hash: Uint8Array) => Observable, - chainNewHead: () => Observable
, - democracyLaunchPeriod: () => Observable, - democracyNextTally: () => Observable, - democracyProposalCount: () => Observable, - democracyProposalDeposits: (index: BN) => Observable, - democracyProposals: () => Observable>, - democracyReferendumCount: () => Observable, - democracyReferendums: () => Observable>, - democracyReferendumVoters:(index: BN) => Observable>, - democracyVotingPeriod: () => Observable, - eraBlockLength: () => Observable, - eraBlockProgress: () => Observable, - eraBlockRemaining: () => Observable, - fees: () => Observable, - sessionBlockProgress: () => Observable, - sessionBlockRemaining: () => Observable, - sessionBrokenPercentLate: () => Observable, - sessionBrokenValue: () => Observable, - sessionLength: () => Observable, - sessionTimeExpected: () => Observable, - sessionTimeRemaining: () => Observable, - sessionValidators: () => Observable>, - stakingFreeBalanceOf: (address: string) => Observable, - stakingIntentions: () => Observable>, - stakingNominatorsFor: (address: string) => Observable>, - stakingNominating: (address: string) => Observable, - stakingReservedBalanceOf: (address: string) => Observable, - systemAccountIndexOf: (address: string) => Observable, - timestampBlockPeriod: () => Observable, - timestampNow: () => Observable, - validatorCount: () => Observable, - validatingBalance: (address: string) => Observable, - validatingBalances: (...addresses: Array) => Observable, - votingBalance: (address: string) => Observable, - votingBalances: (...addresses: Array) => Observable -} - -export type ObservableApiNames = keyof ObservableApiInterface; diff --git a/packages/ui-react-rx/src/Balance.ts b/packages/ui-react-rx/src/Balance.ts index 580c3db42a..1ee7819cff 100644 --- a/packages/ui-react-rx/src/Balance.ts +++ b/packages/ui-react-rx/src/Balance.ts @@ -1,12 +1,20 @@ // Copyright 2017-2018 @polkadot/ui-react-rx 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 numberFormat from './util/numberFormat'; -import withObservableDiv from './with/observableDiv'; +import { RxBalance } from '@polkadot/api-observable/types'; -const Component: React.ComponentType = withObservableDiv('stakingFreeBalanceOf')( - numberFormat, +import { withObservableDiv } from './with/index'; +import { balanceFormat } from './util/index'; + +const Component: React.ComponentType = withObservableDiv('votingBalance')( + (balance?: RxBalance): string => { + if (!balance) { + return '0'; + } + + return balanceFormat(balance.freeBalance); + }, { className: 'rx--Balance' } ); diff --git a/packages/ui-react-rx/src/BestNumber.ts b/packages/ui-react-rx/src/BestNumber.ts index 5c3812bad9..14ed65c0a3 100644 --- a/packages/ui-react-rx/src/BestNumber.ts +++ b/packages/ui-react-rx/src/BestNumber.ts @@ -1,14 +1,14 @@ // Copyright 2017-2018 @polkadot/ui-react-rx 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 { BlockNumber } from '@polkadot/types'; -import numberFormat from './util/numberFormat'; -import withObservableDiv from './with/observableDiv'; +import { numberFormat } from './util/index'; +import { withObservableDiv } from './with/index'; const Component: React.ComponentType = withObservableDiv('bestNumber')( - (value?: BN): string => { + (value?: BlockNumber): string => { return value ? numberFormat(value) : 'unknown'; diff --git a/packages/ui-react-rx/src/Chain.ts b/packages/ui-react-rx/src/Chain.ts index bb04e658e5..91024f44de 100644 --- a/packages/ui-react-rx/src/Chain.ts +++ b/packages/ui-react-rx/src/Chain.ts @@ -1,16 +1,14 @@ // Copyright 2017-2018 @polkadot/ui-react-rx 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 rpcs from '@polkadot/jsonrpc'; +import { Text } from '@polkadot/types'; -import withApiDiv from './with/apiDiv'; +import { withObservableDiv } from './with/index'; -const method = rpcs.system.public.chain; - -const Component: React.ComponentType = withApiDiv(method)( - (value: string = 'unknown'): string => - value, +const Component: React.ComponentType = withObservableDiv('chain')( + (value: Text | string = 'unknown'): string => + value.toString(), { className: 'rx--Chain' } ); diff --git a/packages/ui-react-rx/src/Connected.ts b/packages/ui-react-rx/src/Connected.ts index 26f7bdaee1..a1125b15e8 100644 --- a/packages/ui-react-rx/src/Connected.ts +++ b/packages/ui-react-rx/src/Connected.ts @@ -1,10 +1,10 @@ // Copyright 2017-2018 @polkadot/ui-react-rx 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 withApiDiv from './with/apiDiv'; +import { withObservableDiv } from './with/index'; -const Component: React.ComponentType = withApiDiv({ name: 'isConnected' })( +const Component: React.ComponentType = withObservableDiv('isConnected')( (value: boolean = false): string => { return value ? 'connected' diff --git a/packages/ui-react-rx/src/Div.tsx b/packages/ui-react-rx/src/Div.tsx index 06d8969d64..44d479bd54 100644 --- a/packages/ui-react-rx/src/Div.tsx +++ b/packages/ui-react-rx/src/Div.tsx @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/ui-react-rx 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 { BaseProps, BareProps } from './types'; @@ -8,9 +8,10 @@ import React from 'react'; type Props = BaseProps; -// FIXME Not 100% on how to push through the generic type when used -const echoFormatter = (value?: any): any => - value; +const echoFormatter = (value?: any): string | undefined => + value + ? value.toString() + : undefined; export default function Div ({ children, className = 'rx--Div', render = echoFormatter, rxUpdated = false, label = '', style, value }: Props) { const props: BareProps = { diff --git a/packages/ui-react/src/Elapsed.tsx b/packages/ui-react-rx/src/Elapsed.tsx similarity index 81% rename from packages/ui-react/src/Elapsed.tsx rename to packages/ui-react-rx/src/Elapsed.tsx index 2c45133a12..3558b51073 100644 --- a/packages/ui-react/src/Elapsed.tsx +++ b/packages/ui-react-rx/src/Elapsed.tsx @@ -1,13 +1,14 @@ -// Copyright 2017-2018 @polkadot/ui-react authors & contributors +// Copyright 2017-2018 @polkadot/ui-react-rx 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 { BaseProps } from './types'; +import { BareProps } from './types'; import React from 'react'; +import { Moment } from '@polkadot/types'; -type Props = BaseProps & { - value?: Date +type Props = BareProps & { + value?: Moment | Date }; type State = { @@ -58,7 +59,7 @@ export default class Elapsed extends React.PureComponent { ); } - private getDisplayValue (now?: Date, value?: Date): string { + private getDisplayValue (now?: Date, value?: Moment | Date): string { const tsNow = (now && now.getTime()) || 0; const tsValue = (value && value.getTime()) || 0; let display = '-'; diff --git a/packages/ui-react-rx/src/NodeName.ts b/packages/ui-react-rx/src/NodeName.ts index 54dcb07cde..f9173769f3 100644 --- a/packages/ui-react-rx/src/NodeName.ts +++ b/packages/ui-react-rx/src/NodeName.ts @@ -1,16 +1,14 @@ // Copyright 2017-2018 @polkadot/ui-react-rx 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 rpcs from '@polkadot/jsonrpc'; +import { Text } from '@polkadot/types'; -import withApiDiv from './with/apiDiv'; +import { withObservableDiv } from './with/index'; -const method = rpcs.system.public.name; - -const Component: React.ComponentType = withApiDiv(method)( - (value: string = 'unknown'): string => - value, +const Component: React.ComponentType = withObservableDiv('systemName')( + (value: Text | string = 'unknown'): string => + value.toString(), { className: 'rx--NodeName' } ); diff --git a/packages/ui-react-rx/src/NodeVersion.ts b/packages/ui-react-rx/src/NodeVersion.ts index afa6496451..7a03523e33 100644 --- a/packages/ui-react-rx/src/NodeVersion.ts +++ b/packages/ui-react-rx/src/NodeVersion.ts @@ -1,16 +1,14 @@ // Copyright 2017-2018 @polkadot/ui-react-rx 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 rpcs from '@polkadot/jsonrpc'; +import { Text } from '@polkadot/types'; -import withApiDiv from './with/apiDiv'; +import { withObservableDiv } from './with/index'; -const method = rpcs.system.public.version; - -const Component: React.ComponentType = withApiDiv(method)( - (value: string = 'unknown'): string => - value, +const Component: React.ComponentType = withObservableDiv('systemVersion')( + (value: Text | string = 'unknown'): string => + value.toString(), { className: 'rx--NodeVersion' } ); diff --git a/packages/ui-react-rx/src/Nonce.ts b/packages/ui-react-rx/src/Nonce.ts index 2e1abc824e..6a74affc62 100644 --- a/packages/ui-react-rx/src/Nonce.ts +++ b/packages/ui-react-rx/src/Nonce.ts @@ -1,11 +1,11 @@ // Copyright 2017-2018 @polkadot/ui-react-rx 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 numberFormat from './util/numberFormat'; -import withObservableDiv from './with/observableDiv'; +import { withObservableDiv } from './with/index'; -const Component: React.ComponentType = withObservableDiv('systemAccountIndexOf')( +const Component: React.ComponentType = withObservableDiv('accountNonce')( numberFormat, { className: 'rx--Nonce' } ); diff --git a/packages/ui-react-rx/src/TimeNow.ts b/packages/ui-react-rx/src/TimeNow.ts index d81bb084db..3d3b7c1c5e 100644 --- a/packages/ui-react-rx/src/TimeNow.ts +++ b/packages/ui-react-rx/src/TimeNow.ts @@ -1,11 +1,11 @@ // Copyright 2017-2018 @polkadot/ui-react-rx 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 Elapsed from '@polkadot/ui-react/Elapsed'; -import withApiObservble from './with/observable'; +import { withObservable } from './with/index'; +import Elapsed from './Elapsed'; -const Component: React.ComponentType = withApiObservble('timestampNow', { propName: 'value' })( +const Component: React.ComponentType = withObservable('blockNow', { propName: 'value' })( Elapsed, { className: 'rx--TimeNow' } ); diff --git a/packages/ui-react-rx/src/TimePeriod.ts b/packages/ui-react-rx/src/TimePeriod.ts index 45b3d8a420..ed01380a01 100644 --- a/packages/ui-react-rx/src/TimePeriod.ts +++ b/packages/ui-react-rx/src/TimePeriod.ts @@ -1,15 +1,15 @@ // Copyright 2017-2018 @polkadot/ui-react-rx 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 { Moment } from '@polkadot/types'; import numberFormat from './util/numberFormat'; -import withObservableDiv from './with/observableDiv'; +import { withObservableDiv } from './with/index'; -const Component: React.ComponentType = withObservableDiv('timestampBlockPeriod')( - (value?: BN): string => - `${numberFormat(value)}.0s`, +const Component: React.ComponentType = withObservableDiv('blockPeriod')( + (value?: Moment): string => + `${numberFormat(value ? (2 * value.toNumber()) : 0)}.0s`, { className: 'rx--TimePeriod' } ); diff --git a/packages/ui-react-rx/src/demo.tsx b/packages/ui-react-rx/src/demo.tsx index 8e9f27a069..17405fb3d4 100644 --- a/packages/ui-react-rx/src/demo.tsx +++ b/packages/ui-react-rx/src/demo.tsx @@ -1,10 +1,10 @@ // Copyright 2017-2018 @polkadot/ui-react-rx 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 React from 'react'; import ReactDOM from 'react-dom'; -import mockProvider from '@polkadot/api-provider/mock'; +import Mock from '@polkadot/rpc-provider/mock'; import Api from './Api'; import Balance from './Balance'; @@ -14,9 +14,9 @@ import Connected from './Connected'; import NodeName from './NodeName'; import NodeVersion from './NodeVersion'; import Nonce from './Nonce'; -import withApi from './with/api'; +import { withApi } from './with/index'; -const provider = mockProvider(); +const provider = new Mock(); const ALICE_ADDR = '5GoKvZWG5ZPYL1WUovuHW3zJBWBP5eT8CbqjdRY4Q6iMaDtZ'; const ALICE_PUBLIC = '0xd172a74cda4c865912c32ba0a80a57ae69abae410e5ccb59dee84e2f4432db4f'; diff --git a/packages/ui-react-rx/src/index.ts b/packages/ui-react-rx/src/index.ts index 281facdc08..cbf5e946ed 100644 --- a/packages/ui-react-rx/src/index.ts +++ b/packages/ui-react-rx/src/index.ts @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/ui-react-rx 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 Api from './Api'; import Balance from './Balance'; @@ -11,6 +11,8 @@ import Div from './Div'; import NodeName from './NodeName'; import NodeVersion from './NodeVersion'; import Nonce from './Nonce'; +import TimeNow from './TimeNow'; +import TimePeriod from './TimePeriod'; export { Api, @@ -21,5 +23,7 @@ export { Div, NodeName, NodeVersion, - Nonce + Nonce, + TimeNow, + TimePeriod }; diff --git a/packages/ui-react-rx/src/types.d.ts b/packages/ui-react-rx/src/types.ts similarity index 50% rename from packages/ui-react-rx/src/types.d.ts rename to packages/ui-react-rx/src/types.ts index f06cf5a667..eb85e9900b 100644 --- a/packages/ui-react-rx/src/types.d.ts +++ b/packages/ui-react-rx/src/types.ts @@ -1,16 +1,11 @@ // Copyright 2017-2018 @polkadot/ui-react-rx 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 { Observable } from 'rxjs'; -import { ProviderInterface } from '@polkadot/api-provider/types'; -import { RxApiInterface, RxApiInterface$Method } from '@polkadot/api-rx/types'; -import { Interfaces } from '@polkadot/jsonrpc/types'; -import { EncodingVersions, SectionItem } from '@polkadot/params/types'; -import { Header } from '@polkadot/primitives/header'; -import { Storages, Storage$Key$Value } from '@polkadot/storage/types'; -import { ObservableApiInterface } from './ApiObservable/types'; +import { ProviderInterface } from '@polkadot/rpc-provider/types'; +import { RpcRxInterface } from '@polkadot/rpc-rx/types'; + +import ApiObservable from '@polkadot/api-observable'; export type BareProps = { className?: string, @@ -18,20 +13,21 @@ export type BareProps = { }; export type ApiProps = { - api: RxApiInterface, - apiConnected: boolean, + isApiConnected: boolean, + isApiReady: boolean, + api: RpcRxInterface, apiMethods: { [index: string]: boolean }, - apiObservable: ObservableApiInterface, - apiSupport: EncodingVersions, - setApi: (api: RxApiInterface) => void, + apiObservable: ApiObservable, + apiSupport: 'latest', + setApi: (api: RpcRxInterface) => void, setApiProvider: (provider?: ProviderInterface) => void, setApiWsUrl: (url?: string) => void }; -type OnChangeCb$Obs = { next: (value?: T) => any }; -type OnChangeCb$Fn = (value?: T) => void; +export type OnChangeCb$Obs = { next: (value?: T) => any }; +export type OnChangeCb$Fn = (value?: T) => void; export type OnChangeCb = OnChangeCb$Obs | OnChangeCb$Fn | undefined; @@ -40,14 +36,14 @@ export type ChangeProps = { }; export type ParamProps = { - params?: Array + params?: Array }; export type RxProps = { rxUpdated?: boolean; rxUpdatedAt?: number; value?: T; -} +}; export type BaseProps = BareProps & ApiProps & ChangeProps & ParamProps & RxProps & { children?: React.ReactNode, diff --git a/packages/ui-react-rx/src/util/balanceFormat.spec.js b/packages/ui-react-rx/src/util/balanceFormat.spec.js new file mode 100644 index 0000000000..03d49f554d --- /dev/null +++ b/packages/ui-react-rx/src/util/balanceFormat.spec.js @@ -0,0 +1,77 @@ +// Copyright 2017-2018 @polkadot/ui-app 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 BN from 'bn.js'; + +import { balanceFormat } from './'; + +describe('balanceFormat', () => { + const TESTVAL = new BN('123456789000'); + + it('formats 123,456,789,000 (decimals=15)', () => { + expect( + balanceFormat(TESTVAL, 15) + ).toEqual('123.456µ'); + }); + + it('formats 123,456,789,000 (decimals=12)', () => { + expect( + balanceFormat(TESTVAL, 12) + ).toEqual('123.456m'); + }); + + it('formats 123,456,789,000 (decimals=9)', () => { + expect( + balanceFormat(TESTVAL, 9) + ).toEqual('123.456'); + }); + + it('formats 123,456,789,000 (decimals=6)', () => { + expect( + balanceFormat(TESTVAL, 6) + ).toEqual('123.456k'); + }); + + it('formats 123,456,789,000 * 10 (decimals=12)', () => { + expect( + balanceFormat(TESTVAL.muln(10), 12) + ).toEqual('1.234'); + }); + + it('formats 123,456,789,000 * 100 (decimals=12)', () => { + expect( + balanceFormat(TESTVAL.muln(100), 12) + ).toEqual('12.345'); + }); + + it('formats 123,456,789,000 * 1000 (decimals=12)', () => { + expect( + balanceFormat(TESTVAL.muln(1000), 12) + ).toEqual('123.456'); + }); + + describe('findSi', () => { + it('finds the SI value', () => { + expect( + balanceFormat.findSi('k') + ).toEqual({ power: 3, value: 'k', text: 'Kilo' }); + }); + + it('returns default on not found', () => { + expect( + balanceFormat.findSi('blah') + ).toEqual({ power: 0, value: '-', text: '----' }); + }); + }); + + describe('setDefaultDecimals', () => { + it('formats 123,456,789,000 (defaultDecimals=15)', () => { + balanceFormat.setDefaultDecimals(15); + + expect( + balanceFormat(TESTVAL) + ).toEqual('123.456µ'); + }); + }); +}); diff --git a/packages/ui-react-rx/src/util/balanceFormat.ts b/packages/ui-react-rx/src/util/balanceFormat.ts new file mode 100644 index 0000000000..4fcc5d7620 --- /dev/null +++ b/packages/ui-react-rx/src/util/balanceFormat.ts @@ -0,0 +1,92 @@ +// Copyright 2017-2018 @polkadot/ui-react-rx 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 BN from 'bn.js'; +import { UInt } from '@polkadot/types/codec'; + +import decimalFormat from './decimalFormat'; + +type SiDef = { + power: number, + text: string, + value: string +}; + +interface BalanceFormatter { + (input: string | BN | UInt, decimals?: number): string; + findSi (type: string): SiDef; + getDefaultDecimals (): number; + getOptions (decimals?: number): Array; + setDefaultDecimals (decimals: number): void; +} + +const SI: Array = [ + { power: -24, value: 'y', text: 'yocto' }, + { power: -21, value: 'z', text: 'zepto' }, + { power: -18, value: 'a', text: 'atto' }, + { power: -15, value: 'f', text: 'femto' }, + { power: -12, value: 'p', text: 'pico' }, + { power: -9, value: 'n', text: 'nano' }, + { power: -6, value: 'µ', text: 'micro' }, + { power: -3, value: 'm', text: 'milli' }, + { power: 0, value: '-', text: '----' }, // position 8 + { power: 3, value: 'k', text: 'Kilo' }, + { power: 6, value: 'M', text: 'Mega' }, + { power: 9, value: 'G', text: 'Giga' }, + { power: 12, value: 'T', text: 'Tera' }, + { power: 15, value: 'P', text: 'Peta' }, + { power: 18, value: 'E', text: 'Exa' }, + { power: 21, value: 'Z', text: 'Zeta' }, + { power: 24, value: 'Y', text: 'Yotta' } +]; + +const SI_MID = 8; + +let defaultDecimals = 0; + +// Formats a string/number with . notation +function _balanceFormat (input: string | BN | UInt, decimals: number = defaultDecimals): string { + const text = (input || '').toString(); + + if (text.length === 0 || text === '0') { + return text; + } + + // NOTE We start at midpoint (8) minus 1 - this means that values display as + // 123.456 instead of 0.123k (so always 6 relevant). Additionally we us ceil + // so there are at most 3 decimal before the decimal seperator + const si = SI[(SI_MID - 1) + Math.ceil((text.length - decimals) / 3)]; + const mid = text.length - (decimals + si.power); + const prefix = text.substr(0, mid); + const postfix = `${text.substr(mid)}000`.substr(0, 3); + + return `${decimalFormat(prefix || '0')}.${postfix}${si.value === '-' ? '' : si.value}`; +} + +const balanceFormat = _balanceFormat as BalanceFormatter; + +// Given a SI type (e.g. k, m, Y) find the SI definition +balanceFormat.findSi = (type: string): SiDef => { + return SI.find(({ value }) => value === type) || SI[SI_MID]; +}; + +balanceFormat.getDefaultDecimals = (): number => { + return defaultDecimals; +}; + +// get allowable options to display in a dropdown +balanceFormat.getOptions = (decimals: number = defaultDecimals): Array => { + return SI.filter(({ power }) => + power < 0 + ? (decimals + power) >= 0 + : true + ); +}; + +// Sets the default decimals to use for formatting (chain-wide) +balanceFormat.setDefaultDecimals = (decimals: number = 0): void => { + defaultDecimals = decimals; +}; + +export default balanceFormat; diff --git a/packages/ui-react-rx/src/util/decimalFormat.ts b/packages/ui-react-rx/src/util/decimalFormat.ts new file mode 100644 index 0000000000..dc35911473 --- /dev/null +++ b/packages/ui-react-rx/src/util/decimalFormat.ts @@ -0,0 +1,9 @@ +// Copyright 2017-2018 @polkadot/ui-react-rx authors & contributors +// This software may be modified and distributed under the terms +// of the Apache-2.0 license. See the LICENSE file for details. + +const NUMBER_REGEX = new RegExp('(\\d+?)(?=(\\d{3})+(?!\\d)|$)', 'g'); + +export default function decimalFormat (value: string): string { + return (value.match(NUMBER_REGEX) || []).join(','); +} diff --git a/packages/ui-react-rx/src/util/index.ts b/packages/ui-react-rx/src/util/index.ts new file mode 100644 index 0000000000..0db6c94428 --- /dev/null +++ b/packages/ui-react-rx/src/util/index.ts @@ -0,0 +1,21 @@ +// Copyright 2017-2018 @polkadot/ui-react-rx 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 balanceFormat from './balanceFormat'; +import decimalFormat from './decimalFormat'; +import intervalSubscribe from './intervalSubscribe'; +import isEqual from './isEqual'; +import isTestChain from './isTestChain'; +import numberFormat from './numberFormat'; +import triggerChange from './triggerChange'; + +export { + balanceFormat, + decimalFormat, + intervalSubscribe, + isEqual, + isTestChain, + numberFormat, + triggerChange +}; diff --git a/packages/ui-react-rx/src/util/intervalSubscribe.ts b/packages/ui-react-rx/src/util/intervalSubscribe.ts index aa385b2eb2..79ad823f2f 100644 --- a/packages/ui-react-rx/src/util/intervalSubscribe.ts +++ b/packages/ui-react-rx/src/util/intervalSubscribe.ts @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/ui-react-rx 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 { RxProps } from '../types'; @@ -8,12 +8,9 @@ import { interval } from 'rxjs/observable/interval'; const interval$ = interval(500); -// FIXME Return type here is NOT any, horribly defined (leave until rx-lite decicion is made) - export default function intervalSubscribe> (that: React.Component) { return interval$.subscribe(() => { - // @ts-ignore right-hand side? Not sure wtf here - const elapsed = Date.now() - (that.state.rxUpdatedAt || 0); + const elapsed = Date.now() - ((that.state.rxUpdatedAt as number) || 0); const rxUpdated = elapsed <= 1500; if (rxUpdated !== that.state.rxUpdated) { diff --git a/packages/ui-react-rx/src/util/isEqual.ts b/packages/ui-react-rx/src/util/isEqual.ts index 3216ee2d7e..736eb2b12d 100644 --- a/packages/ui-react-rx/src/util/isEqual.ts +++ b/packages/ui-react-rx/src/util/isEqual.ts @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/ui-react-rx 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. function flatten (key: string | null, value: any): any { if (!value) { diff --git a/packages/ui-react-rx/src/util/isTestChain.spec.js b/packages/ui-react-rx/src/util/isTestChain.spec.js index 4f19e43154..e123d12f50 100644 --- a/packages/ui-react-rx/src/util/isTestChain.spec.js +++ b/packages/ui-react-rx/src/util/isTestChain.spec.js @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/ui-react-rx 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 isTestChain from './isTestChain'; diff --git a/packages/ui-react-rx/src/util/isTestChain.ts b/packages/ui-react-rx/src/util/isTestChain.ts index 2dd0f879ce..b0ed15714d 100644 --- a/packages/ui-react-rx/src/util/isTestChain.ts +++ b/packages/ui-react-rx/src/util/isTestChain.ts @@ -1,8 +1,8 @@ // Copyright 2017-2018 @polkadot/ui-react-rx 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 isUndefined from '@polkadot/util/is/undefined'; +import { isUndefined } from '@polkadot/util'; const re = new RegExp('(dev|loc)', 'i'); diff --git a/packages/ui-react-rx/src/util/numberFormat.ts b/packages/ui-react-rx/src/util/numberFormat.ts index e761828df8..8f76783de5 100644 --- a/packages/ui-react-rx/src/util/numberFormat.ts +++ b/packages/ui-react-rx/src/util/numberFormat.ts @@ -1,15 +1,16 @@ // Copyright 2017-2018 @polkadot/ui-react-rx 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 { UInt } from '@polkadot/types/codec'; -const NUMBER_REGEX = new RegExp('(\\d+?)(?=(\\d{3})+(?!\\d)|$)', 'g'); +import decimalFormat from './decimalFormat'; -export default function numberFormat (value?: BN | number | null): string { +export default function numberFormat (value?: UInt | BN | number | null): string { if (value === undefined || value === null) { return '0'; } - return ((value as number).toString().match(NUMBER_REGEX) || []).join(','); + return decimalFormat((value as number).toString()); } diff --git a/packages/ui-react-rx/src/util/triggerChange.ts b/packages/ui-react-rx/src/util/triggerChange.ts index e1d9a970e0..1c3e9786ff 100644 --- a/packages/ui-react-rx/src/util/triggerChange.ts +++ b/packages/ui-react-rx/src/util/triggerChange.ts @@ -1,11 +1,10 @@ // Copyright 2017-2018 @polkadot/ui-react-rx 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 { OnChangeCb, OnChangeCb$Obs } from '../types'; -import isFunction from '@polkadot/util/is/function'; -import isObservable from '@polkadot/util/is/observable'; +import { isFunction, isObservable } from '@polkadot/util'; export default function triggerChange (value?: T, ...rxChange: Array>): void { if (!rxChange || !rxChange.length) { diff --git a/packages/ui-react-rx/src/with/api.tsx b/packages/ui-react-rx/src/with/api.tsx index f04f828e9a..2ec634ae7b 100644 --- a/packages/ui-react-rx/src/with/api.tsx +++ b/packages/ui-react-rx/src/with/api.tsx @@ -1,12 +1,12 @@ // Copyright 2017-2018 @polkadot/ui-react-rx 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 { ApiProps } from '../types'; import { DefaultProps } from './types'; import React from 'react'; -import assert from '@polkadot/util/assert'; +import { assert } from '@polkadot/util'; import { ApiConsumer } from '../Api/Context'; @@ -25,6 +25,7 @@ export default function withApi (Inner: React.ComponentT assert(apiProps && apiProps.api, `Application root must be wrapped inside 'rx-react/Api' to provide API context`); return ( + // @ts-ignore Something here with the props are going wonky ) => React.ComponentType; -export default function withMulti (Component: React.ComponentType, ...hocs: Array): React.ComponentType { +export default function withMulti (Component: React.ComponentType, ...hocs: Array): React.ComponentType { // NOTE: Order is reversed so it makes sense in the props, i.e. component // after something can use the value of the preceding version return hocs diff --git a/packages/ui-react-rx/src/with/observable.tsx b/packages/ui-react-rx/src/with/observable.tsx index 7b1d23b102..1f7216871a 100644 --- a/packages/ui-react-rx/src/with/observable.tsx +++ b/packages/ui-react-rx/src/with/observable.tsx @@ -1,17 +1,17 @@ // Copyright 2017-2018 @polkadot/ui-react-rx 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. // TODO: Lots of duplicated code between this and withObservable, surely there ois a better way of doing this? -import { ObservableApiNames } from '../ApiObservable/types'; +import { ApiFunctions } from '@polkadot/api-observable/types'; import { RxProps } from '../types'; import { HOC, Options, DefaultProps, RenderFn } from './types'; import React from 'react'; -import isUndefined from '@polkadot/util/is/undefined'; +import { isUndefined } from '@polkadot/util'; -import isEqual from '../util/isEqual'; +import { isEqual } from '../util/index'; import echoTransform from './transform/echo'; import withApi from './api'; import withObservableBase from './observableBase'; @@ -22,7 +22,7 @@ type State = RxProps & { // FIXME proper types for attributes -export default function withObservable (subscription: ObservableApiNames, { rxChange, params = [], paramProp = 'params', propName = subscription, transform = echoTransform }: Options = {}): HOC { +export default function withObservable (subscription: ApiFunctions, { rxChange, params = [], paramProp = 'params', propName = subscription, transform = echoTransform }: Options = {}): HOC { return (Inner: React.ComponentType, defaultProps: DefaultProps = {}, render?: RenderFn): React.ComponentType => { class WithObservable extends React.Component> { state: State; @@ -64,16 +64,22 @@ export default function withObservable (subscription: ObservableApiNames, { r } private subscribe (newParams: Array) { - const { apiObservable } = this.props; - const observable = apiObservable[subscription](...newParams); + try { + const { apiObservable } = this.props; + const observable = apiObservable[subscription](...newParams); - this.setState({ - Component: withObservableBase(observable, { - rxChange, - propName, - transform - })(Inner, defaultProps, render) - }); + this.setState({ + Component: withObservableBase(observable, { + rxChange, + propName, + transform + })(Inner, defaultProps, render) + }); + } catch (error) { + console.error('withObservable:subscribe', subscription, error); + + throw error; + } } render () { diff --git a/packages/ui-react-rx/src/with/observableBase.tsx b/packages/ui-react-rx/src/with/observableBase.tsx index 2eb391ee20..bfd78153a8 100644 --- a/packages/ui-react-rx/src/with/observableBase.tsx +++ b/packages/ui-react-rx/src/with/observableBase.tsx @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/ui-react-rx 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. // TODO: Lots of duplicated code between this and withObservable, surely there ois a better way of doing this? @@ -8,12 +8,10 @@ import { RxProps } from '../types'; import { HOC, Options, DefaultProps, RenderFn } from './types'; import React from 'react'; -import { Observable } from 'rxjs'; -import { map } from 'rxjs/operators'; +import { Observable, of } from 'rxjs'; +import { catchError, map } from 'rxjs/operators'; -import intervalSubscribe from '../util/intervalSubscribe'; -import isEqual from '../util/isEqual'; -import triggerChange from '../util/triggerChange'; +import { intervalSubscribe, isEqual, triggerChange } from '../util/index'; import echoTransform from './transform/echo'; type State = RxProps & { @@ -22,7 +20,7 @@ type State = RxProps & { // FIXME proper types for attributes -export default function withObservableBase (observable: Observable, { rxChange, propName = 'value', transform = echoTransform }: Options = {}): HOC { +export default function withObservableBase (observable: Observable

, { rxChange, propName = 'value', transform = echoTransform }: Options = {}): HOC { return (Inner: React.ComponentType, defaultProps: DefaultProps = {}, render?: RenderFn): React.ComponentType => { return class WithObservable extends React.Component> { state: State; @@ -42,7 +40,12 @@ export default function withObservableBase (observable: Observable, { rx this.setState({ subscriptions: [ observable - .pipe(map(transform)) + .pipe( + map(transform), + catchError(() => + of(undefined) + ) + ) .subscribe((value: any) => this.triggerUpdate(this.props, value) ), @@ -58,17 +61,21 @@ export default function withObservableBase (observable: Observable, { rx } triggerUpdate = (props: any, value?: T): void => { - if (isEqual(value, this.state.value)) { - return; + try { + if (isEqual(value, this.state.value)) { + return; + } + + triggerChange(value, rxChange, props.rxChange || defaultProps.rxChange); + + this.setState({ + rxUpdated: true, + rxUpdatedAt: Date.now(), + value + }); + } catch (error) { + console.error(this.props, error); } - - triggerChange(value, rxChange, props.rxChange || defaultProps.rxChange); - - this.setState({ - rxUpdated: true, - rxUpdatedAt: Date.now(), - value - }); } render () { diff --git a/packages/ui-react-rx/src/with/observableDiv.ts b/packages/ui-react-rx/src/with/observableDiv.ts index 04b173167a..18ed98e4f2 100644 --- a/packages/ui-react-rx/src/with/observableDiv.ts +++ b/packages/ui-react-rx/src/with/observableDiv.ts @@ -1,15 +1,15 @@ // Copyright 2017-2018 @polkadot/ui-react-rx 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 { ObservableApiNames } from '../ApiObservable/types'; +import { ApiFunctions } from '@polkadot/api-observable/types'; import { BaseProps } from '../types'; import { ComponentRenderer, DefaultProps, RenderFn, Options } from './types'; import Div from '../Div'; import withObservable from './observable'; -export default function withObservableDiv> (call: ObservableApiNames, options?: Options): ComponentRenderer { +export default function withObservableDiv> (call: ApiFunctions, options?: Options): ComponentRenderer { return (render: RenderFn, defaultProps: DefaultProps = {}): React.ComponentType => withObservable(call, options)(Div, defaultProps, render); } diff --git a/packages/ui-react-rx/src/with/transform/echo.ts b/packages/ui-react-rx/src/with/transform/echo.ts index ac46a449c4..e5dfcc7391 100644 --- a/packages/ui-react-rx/src/with/transform/echo.ts +++ b/packages/ui-react-rx/src/with/transform/echo.ts @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/ui-react-rx 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. export default function echoTransform (x: T, index: number): T { return x; diff --git a/packages/ui-react-rx/src/with/transform/storage.ts b/packages/ui-react-rx/src/with/transform/storage.ts deleted file mode 100644 index 5a0a7f9655..0000000000 --- a/packages/ui-react-rx/src/with/transform/storage.ts +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-react-rx authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import { Param$Values, SectionItem } from '@polkadot/params/types'; -import { Storages } from '@polkadot/storage/types'; -import { StorageTransform } from '../types'; - -import decodeParams from '@polkadot/params/decode'; - -export default function storageTransform ({ type }: SectionItem): StorageTransform { - return (input: Uint8Array = new Uint8Array(0), index: number): Param$Values | null => { - try { - return decodeParams(type, input, 'latest', true).value; - } catch (error) { - console.error('Decoding', type, '::', error); - return null; - } - }; -} diff --git a/packages/ui-react-rx/src/with/types.d.ts b/packages/ui-react-rx/src/with/types.ts similarity index 77% rename from packages/ui-react-rx/src/with/types.d.ts rename to packages/ui-react-rx/src/with/types.ts index 9021c40ea8..dd044fe574 100644 --- a/packages/ui-react-rx/src/with/types.d.ts +++ b/packages/ui-react-rx/src/with/types.ts @@ -1,9 +1,7 @@ // Copyright 2017-2018 @polkadot/ui-react-rx 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 { Param$Values } from '@polkadot/params/types'; -import { Storage$Key$Value } from '@polkadot/storage/types'; import { OnChangeCb } from '../types'; import React from 'react'; @@ -25,7 +23,7 @@ export type Options = { export type RenderFn = (value?: any) => React.ReactNode; -export type StorageTransform = (input: any, index: number) => Param$Values | null; +export type StorageTransform = (input: any, index: number) => any | null; export type HOC = (Component: React.ComponentType, defaultProps?: DefaultProps, render?: RenderFn) => React.ComponentType; @@ -35,3 +33,6 @@ export type ApiMethod = { }; export type ComponentRenderer = (render: RenderFn, defaultProps?: DefaultProps) => React.ComponentType; + +export type OmitProps = Pick>; +export type SubtractProps = OmitProps; diff --git a/packages/ui-react-rx/test/enzyme.js b/packages/ui-react-rx/test/enzyme.js index 6cbeb7c1e4..a8b03751ea 100644 --- a/packages/ui-react-rx/test/enzyme.js +++ b/packages/ui-react-rx/test/enzyme.js @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/ui-react-rx 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. const Adapter = require('enzyme-adapter-react-16'); const Enzyme = require('enzyme'); diff --git a/packages/ui-react-rx/test/observable.js b/packages/ui-react-rx/test/observable.js index 246fdcdca2..8ea3abcce9 100644 --- a/packages/ui-react-rx/test/observable.js +++ b/packages/ui-react-rx/test/observable.js @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/ui-react-rx 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. const createObservable = require('@polkadot/api-rx/observable'); diff --git a/packages/ui-react-rx/webpack.config.js b/packages/ui-react-rx/webpack.config.js index 7fde27e022..c9aef54f98 100644 --- a/packages/ui-react-rx/webpack.config.js +++ b/packages/ui-react-rx/webpack.config.js @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/ui-react-rx 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. const ENV = process.env.NODE_ENV || 'development'; const isProd = ENV === 'production'; diff --git a/packages/ui-react/LICENSE b/packages/ui-react/LICENSE deleted file mode 100644 index 10e8fd8d5f..0000000000 --- a/packages/ui-react/LICENSE +++ /dev/null @@ -1,15 +0,0 @@ -ISC License (ISC) - -Copyright 2017-2018 @polkadot/ui-react 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. diff --git a/packages/ui-react/README.md b/packages/ui-react/README.md deleted file mode 100644 index 3cc45dd65d..0000000000 --- a/packages/ui-react/README.md +++ /dev/null @@ -1,13 +0,0 @@ -[![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) -[![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/ui-react.svg?style=flat-square)](https://www.npmjs.com/package/@polkadot/ui-react) -[![travis](https://img.shields.io/travis/polkadot-js/apps.svg?style=flat-square)](https://travis-ci.org/polkadot-js/ui) -[![maintainability](https://img.shields.io/codeclimate/maintainability/polkadot-js/apps.svg?style=flat-square)](https://codeclimate.com/github/polkadot-js/apps/maintainability) -[![coverage](https://img.shields.io/coveralls/polkadot-js/apps.svg?style=flat-square)](https://coveralls.io/github/polkadot-js/apps?branch=master) -[![dependency](https://david-dm.org/polkadot-js/apps.svg?style=flat-square&path=packages/ui-react)](https://david-dm.org/polkadot-js/apps?path=packages/ui-react) -[![devDependency](https://david-dm.org/polkadot-js/apps/dev-status.svg?style=flat-square&path=packages/ui-react)](https://david-dm.org/polkadot-js/apps?path=packages/ui-react#info=devDependencies) - -# @polkadot/ui-react - -A lightweight collection of React components used for construction of applications. See [src/demo.js](src/demo.js) for a sample utilising all components. diff --git a/packages/ui-react/index.html b/packages/ui-react/index.html deleted file mode 100644 index fb30a73837..0000000000 --- a/packages/ui-react/index.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - - -

- - - diff --git a/packages/ui-react/package.json b/packages/ui-react/package.json deleted file mode 100644 index bc5996c410..0000000000 --- a/packages/ui-react/package.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "@polkadot/ui-react", - "version": "0.20.30", - "description": "A collection of base React components", - "main": "index.js", - "author": "Jaco Greeff ", - "maintainers": [ - "Jaco Greeff " - ], - "contributors": [], - "license": "ISC", - "dependencies": { - "@babel/runtime": "^7.0.0", - "@polkadot/ui-identicon": "^0.20.30", - "polkadot-identicon": "^1.0.2" - }, - "devDependencies": { - "@polkadot/util-keyring": "^0.30.4", - "empty": "^0.10.1", - "react": "^16.5.0", - "react-dom": "^16.5.0" - } -} diff --git a/packages/ui-react/postcss.config.ts b/packages/ui-react/postcss.config.ts deleted file mode 100644 index f053ebf797..0000000000 --- a/packages/ui-react/postcss.config.ts +++ /dev/null @@ -1 +0,0 @@ -module.exports = {}; diff --git a/packages/ui-react/src/Container/Container.css b/packages/ui-react/src/Container/Container.css deleted file mode 100644 index 44bfa4ad6e..0000000000 --- a/packages/ui-react/src/Container/Container.css +++ /dev/null @@ -1,18 +0,0 @@ -/* Copyright 2017-2018 @polkadot/ui-react authors & contributors -/* This software may be modified and distributed under the terms -/* of the ISC license. See the LICENSE file for details. */ - -.ui--Container { - padding: 0.5em; -} - -.ui--DemoContainer { - padding: 0.5em 0.5em 1.5em 5em; -} - -.ui--DemoHeader { - background: #f5f5f5; - font-size: 0.75em; - margin: 0 0 1em -6em; - padding: 0.5em; -} diff --git a/packages/ui-react/src/Container/Demo.tsx b/packages/ui-react/src/Container/Demo.tsx deleted file mode 100644 index bf04f0258a..0000000000 --- a/packages/ui-react/src/Container/Demo.tsx +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-react 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 Container from './index'; - -type DemoProps = { - attrs: { [index: string]: any }, - attrsReq: Array, - children: any, // node? - component: string -}; - -export default class Demo extends React.PureComponent { - render () { - const { attrs, attrsReq, children, component } = this.props; - const allAttrs = Object.assign({ className: '"..."', style: '{...}' }, attrs); - const attrsText = Object - .keys(allAttrs) - .map((attr) => { - const value = allAttrs[attr]; - const bool = value === 'bool'; - const opt = bool || !attrsReq.includes(attr); - - return `${opt ? '[' : ''}${attr}${bool ? '' : '='}${bool ? '' : value}${opt ? ']' : ''}`; - }) - .sort() - .join('\n '); - - return ( - -
-          {`<${component}\n  ${attrsText}\n/>`}
-        
- {children} -
- ); - } -} diff --git a/packages/ui-react/src/Container/index.tsx b/packages/ui-react/src/Container/index.tsx deleted file mode 100644 index 263e5e4b23..0000000000 --- a/packages/ui-react/src/Container/index.tsx +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-react authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import { BaseProps } from '../types'; - -import './Container.css'; - -import React from 'react'; - -type Props = BaseProps & { - children: any // React$Node -}; - -export default class Container extends React.PureComponent { - render () { - return ( -
- {this.props.children} -
- ); - } -} diff --git a/packages/ui-react/src/IdentityIcon/Demo.tsx b/packages/ui-react/src/IdentityIcon/Demo.tsx deleted file mode 100644 index e253e9c37a..0000000000 --- a/packages/ui-react/src/IdentityIcon/Demo.tsx +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-react 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 randomAsU8a from '@polkadot/util-crypto/random/asU8a'; -import addressEncode from '@polkadot/util-keyring/address/encode'; - -import Container from '../Container/Demo'; -import IdentityIcon from './index'; - -export default class Demo extends React.PureComponent { - render () { - const identities: Array = [new Uint8Array(32)]; - - while (identities.length !== 10) { - identities.push( - addressEncode(randomAsU8a(32)) - ); - } - - return ( - ', - value: '{...}' - }} - attrsReq={[ - 'value' - ]} - > - { - identities.map((value) => ( - - )) - } - - ); - } - -} diff --git a/packages/ui-react/src/IdentityIcon/IdentityIcon.css b/packages/ui-react/src/IdentityIcon/IdentityIcon.css deleted file mode 100644 index c7b85f492f..0000000000 --- a/packages/ui-react/src/IdentityIcon/IdentityIcon.css +++ /dev/null @@ -1,8 +0,0 @@ -/* Copyright 2017-2018 @polkadot/ui-react authors & contributors -/* This software may be modified and distributed under the terms -/* of the ISC license. See the LICENSE file for details. */ - -.ui--IdentityIcon { - cursor: copy; - display: inline-block; -} diff --git a/packages/ui-react/src/IdentityIcon/Polkadot.tsx b/packages/ui-react/src/IdentityIcon/Polkadot.tsx deleted file mode 100644 index 5561f065fa..0000000000 --- a/packages/ui-react/src/IdentityIcon/Polkadot.tsx +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-react authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import { BaseProps } from '../types'; - -import React from 'react'; -import Identicon from 'polkadot-identicon'; - -type Props = BaseProps & { - size: number, - value: string | Uint8Array -}; - -export default class Polkadot extends React.PureComponent { - render () { - const { size, value } = this.props; - - return ( - - ); - } -} diff --git a/packages/ui-react/src/IdentityIcon/Substrate.tsx b/packages/ui-react/src/IdentityIcon/Substrate.tsx deleted file mode 100644 index e828afb6e4..0000000000 --- a/packages/ui-react/src/IdentityIcon/Substrate.tsx +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-react authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import { BaseProps } from '../types'; - -import React from 'react'; -import identicon from '@polkadot/ui-identicon/index'; -import encodeAddress from '@polkadot/util-keyring/address/encode'; -import isHex from '@polkadot/util/is/hex'; -import isU8a from '@polkadot/util/is/u8a'; - -type Props = BaseProps & { - size: number, - value: string | Uint8Array -}; - -type State = { - address: string -}; - -export default class Substrate extends React.PureComponent { - state: State = {} as State; - - static getDerivedStateFromProps ({ value }: Props, prevState: State): State | null { - const address = isU8a(value) || isHex(value) - ? encodeAddress(value) - : value; - - return address === prevState.address - ? null - : { address }; - } - - render () { - return ( -
- ); - } - - private appendIcon = (node: Element | null): void => { - const { size } = this.props; - const { address } = this.state; - - if (node) { - node.appendChild( - identicon(address, size) - ); - } - } -} diff --git a/packages/ui-react/src/IdentityIcon/index.tsx b/packages/ui-react/src/IdentityIcon/index.tsx deleted file mode 100644 index 30b0e0a135..0000000000 --- a/packages/ui-react/src/IdentityIcon/index.tsx +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-react authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import { BaseProps } from '../types'; - -import './IdentityIcon.css'; - -import React from 'react'; - -import Polkadot from './Polkadot'; -import Substrate from './Substrate'; - -type Props = BaseProps & { - size?: number, - value: string | Uint8Array -}; - -const DEFAULT_SIZE = 64; -const Component = process.env.UI_THEME === 'substrate' - ? Substrate - : Polkadot; - -export default class IdentityIcon extends React.PureComponent { - render () { - const { className, size = DEFAULT_SIZE, style, value } = this.props; - - return ( -
- -
- ); - } -} diff --git a/packages/ui-react/src/demo.css b/packages/ui-react/src/demo.css deleted file mode 100644 index db04bb1e4c..0000000000 --- a/packages/ui-react/src/demo.css +++ /dev/null @@ -1,8 +0,0 @@ -/* Copyright 2017-2018 @polkadot/ui-react authors & contributors -/* This software may be modified and distributed under the terms -/* of the ISC license. See the LICENSE file for details. */ - -.ui--Demo { - margin: 0; - padding: 0.5em; -} diff --git a/packages/ui-react/src/demo.tsx b/packages/ui-react/src/demo.tsx deleted file mode 100644 index 80783c1398..0000000000 --- a/packages/ui-react/src/demo.tsx +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-react authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import './demo.css'; - -import React from 'react'; -import ReactDOM from 'react-dom'; - -import IdentityIcon from './IdentityIcon/Demo'; - -const element = document.getElementById('demo'); - -if (!element) { - throw new Error('Unable to find #demo element'); -} - -ReactDOM.render( -
- -
, - element -); diff --git a/packages/ui-react/src/index.ts b/packages/ui-react/src/index.ts deleted file mode 100644 index 0b6c31f02d..0000000000 --- a/packages/ui-react/src/index.ts +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-react authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -import Container from './Container'; -import IdentityIcon from './IdentityIcon'; - -export { - Container, - IdentityIcon -}; diff --git a/packages/ui-react/src/types.d.ts b/packages/ui-react/src/types.d.ts deleted file mode 100644 index 4279553154..0000000000 --- a/packages/ui-react/src/types.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-react authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -export type BaseProps = { - className?: string, - style?: { - [index: string]: any - } -}; diff --git a/packages/ui-react/test/enzyme.js b/packages/ui-react/test/enzyme.js deleted file mode 100644 index 0198201d9a..0000000000 --- a/packages/ui-react/test/enzyme.js +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-react authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -const Adapter = require('enzyme-adapter-react-16'); -const Enzyme = require('enzyme'); - -Enzyme.configure({ - adapter: new Adapter() -}); - -module.exports = Enzyme; diff --git a/packages/ui-react/webpack.config.js b/packages/ui-react/webpack.config.js deleted file mode 100644 index fcd53b99be..0000000000 --- a/packages/ui-react/webpack.config.js +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2017-2018 @polkadot/ui-react authors & contributors -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -const path = require('path'); -const ENV = process.env.NODE_ENV || 'development'; -const isProd = ENV === 'production'; - -module.exports = { - context: __dirname, - devtool: isProd ? 'source-map' : 'cheap-eval-source-map', - entry: './src/demo.tsx', - mode: ENV, - output: { - path: __dirname, - filename: './demo.js' - }, - resolve: { - alias: { - '@polkadot/ui-identicon/index': path.resolve(__dirname, '../ui-identicon/src/index.ts') - }, - extensions: ['.js', '.jsx', '.ts', '.tsx'] - }, - module: { - rules: [ - { - test: /\.css$/, - exclude: /(node_modules)/, - use: [ - 'style-loader', - { - loader: 'css-loader', - options: { - importLoaders: 1 - } - }, - 'postcss-loader' - ] - }, - { - test: /\.(js|ts|tsx)$/, - exclude: /(node_modules)/, - use: { - loader: 'babel-loader' - } - } - ] - }, - plugins: [] -}; diff --git a/packages/ui-signer/LICENSE b/packages/ui-signer/LICENSE index f9134f38ea..0d381b2e97 100644 --- a/packages/ui-signer/LICENSE +++ b/packages/ui-signer/LICENSE @@ -1,15 +1,201 @@ -ISC License (ISC) + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ -Copyright 2017-2018 @polkadot/ui-signer 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. diff --git a/packages/ui-signer/package.json b/packages/ui-signer/package.json index 0b7b5a6842..bc6a5657c9 100644 --- a/packages/ui-signer/package.json +++ b/packages/ui-signer/package.json @@ -1,6 +1,6 @@ { "name": "@polkadot/ui-signer", - "version": "0.20.30", + "version": "0.21.0", "main": "index.js", "repository": "https://github.com/polkadot-js/apps.git", "author": "Jaco Greeff ", @@ -8,15 +8,10 @@ "Jaco Greeff " ], "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-keyring": "^0.20.30" - }, - "peerDependencies": { - "react": "^16.5.0", - "semantic-ui-react": "^0.80.0" + "@babel/runtime": "^7.2.0", + "@polkadot/ui-app": "^0.21.0", + "@polkadot/ui-keyring": "^0.24.9" } } diff --git a/packages/ui-signer/src/Extrinsic.tsx b/packages/ui-signer/src/Extrinsic.tsx index 3a5f642a96..d6f1f2c7ad 100644 --- a/packages/ui-signer/src/Extrinsic.tsx +++ b/packages/ui-signer/src/Extrinsic.tsx @@ -1,19 +1,15 @@ // Copyright 2017-2018 @polkadot/ui-signer 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 } from './types'; +import { QueueTx } from '@polkadot/ui-app/Status/types'; import BN from 'bn.js'; import React from 'react'; import { Trans } from 'react-i18next'; - -import extrinsics from '@polkadot/extrinsics'; -import Modal from '@polkadot/ui-app/Modal'; -import IdentityIcon from '@polkadot/ui-react/IdentityIcon'; -import u8aToHex from '@polkadot/util/u8a/toHex'; -import addressEncode from '@polkadot/util-keyring/address/encode'; +import { Method } from '@polkadot/types'; +import { Call, IdentityIcon, Modal } from '@polkadot/ui-app/index'; import translate from './translate'; @@ -22,35 +18,15 @@ type Props = I18nProps & { value: QueueTx }; -function findExtrinsic (sectionId: number, methodId: number): { method: string | undefined, section: string | undefined } { - const section = Object.values(extrinsics).find(({ index }) => - index[0] === sectionId - ); - const methods = section - ? section.public - : {}; - const method = Object.keys(methods).find((method) => - methods[method].index[1] === methodId - ); - - return { - method, - section: section - ? section.name - : undefined - }; -} - -class Extrinsic extends React.PureComponent { +class Transaction extends React.PureComponent { render () { - const { children, t, value: { nonce = new BN(0), publicKey, values: [_value] } } = this.props; + const { children, t, value: { accountId, accountNonce = new BN(0), extrinsic } } = this.props; - const unknown = t('decoded.unknown', { - defaultValue: 'unknown' - }); - const value = _value as Uint8Array; - const { method = unknown, section = unknown } = findExtrinsic(value[0], value[1]); - const from = addressEncode(publicKey as Uint8Array); + if (!extrinsic) { + return null; + } + + const { method, section } = Method.findFunction(extrinsic.callIndex); return [ @@ -63,21 +39,14 @@ class Extrinsic extends React.PureComponent {

- You are about to sign a message from {from} calling {section}.{method} with an index of {nonce.toString()} + You are about to sign a message from {accountId} calling {section}.{method} with an index of {accountNonce.toString()}

-

- {t('decoded.data', { - defaultValue: 'The encoded parameters contains the data' - })} -

-

- {u8aToHex(value, 512)} -

+
{children} @@ -86,4 +55,4 @@ class Extrinsic extends React.PureComponent { } } -export default translate(Extrinsic); +export default translate(Transaction); diff --git a/packages/ui-signer/src/Modal.spec.js b/packages/ui-signer/src/Modal.spec.js index 1aaf3003d3..acff7c6214 100644 --- a/packages/ui-signer/src/Modal.spec.js +++ b/packages/ui-signer/src/Modal.spec.js @@ -1,6 +1,6 @@ // Copyright 2017-2018 @polkadot/ui-app 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 React from 'react'; diff --git a/packages/ui-signer/src/Modal.tsx b/packages/ui-signer/src/Modal.tsx index 14f2aa9a5a..e66fcddab8 100644 --- a/packages/ui-signer/src/Modal.tsx +++ b/packages/ui-signer/src/Modal.tsx @@ -1,26 +1,27 @@ // Copyright 2017-2018 @polkadot/ui-signer 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 { ApiProps } from '@polkadot/ui-react-rx/types'; import { I18nProps, BareProps } from '@polkadot/ui-app/types'; -import { QueueTx, QueueTx$MessageSetStatus } from './types'; +import { RpcMethod } from '@polkadot/jsonrpc/types'; +import { QueueTx, QueueTx$MessageSetStatus, QueueTx$Result, QueueTx$Status } from '@polkadot/ui-app/Status/types'; import React from 'react'; -import Button from '@polkadot/ui-app/Button'; -import Modal from '@polkadot/ui-app/Modal'; -import keyring from '@polkadot/ui-keyring/index'; -import withApi from '@polkadot/ui-react-rx/with/api'; +import { decodeAddress } from '@polkadot/keyring'; +import { Button, Modal } from '@polkadot/ui-app/index'; +import keyring from '@polkadot/ui-keyring'; +import { withApi, withMulti } from '@polkadot/ui-react-rx/with/index'; +import { format } from '@polkadot/util/logger'; +import { Extrinsic } from '@polkadot/types'; -import Extrinsic from './Extrinsic'; +import ExtrinsicDisplay from './Extrinsic'; import Unlock from './Unlock'; -import signMessage from './sign'; -import submitMessage from './submit'; import translate from './translate'; type BaseProps = BareProps & { queue: Array, - queueSetStatus: QueueTx$MessageSetStatus + queueSetTxStatus: QueueTx$MessageSetStatus }; type Props = I18nProps & ApiProps & BaseProps; @@ -56,9 +57,9 @@ class Signer extends React.PureComponent { !!nextItem && !!currentItem && ( - (!nextItem.publicKey && !currentItem.publicKey) || + (!nextItem.accountId && !currentItem.accountId) || ( - (nextItem.publicKey && nextItem.publicKey.toString()) === (currentItem.publicKey && currentItem.publicKey.toString()) + (nextItem.accountId && nextItem.accountId.toString()) === (currentItem.accountId && currentItem.accountId.toString()) ) ); @@ -72,15 +73,15 @@ class Signer extends React.PureComponent { async componentDidUpdate (prevProps: Props, prevState: State) { const { currentItem } = this.state; - if (currentItem && currentItem.status === 'queued' && currentItem.rpc.isSigned !== true) { - return this.sendItem(currentItem); + if (currentItem && currentItem.status === 'queued' && !currentItem.extrinsic) { + return this.sendRpc(currentItem); } } render () { const { currentItem } = this.state; - if (!currentItem || currentItem.rpc.isSigned !== true) { + if (!currentItem) { return null; } @@ -96,9 +97,8 @@ class Signer extends React.PureComponent { ); } - renderButtons () { + private renderButtons () { const { t } = this.props; - const { currentItem: { rpc: { isSigned = false } = {} } = {} } = this.state; return ( @@ -112,29 +112,23 @@ class Signer extends React.PureComponent { })} /> -
-
+