From a69548866be641b1bb97f18f051327d1f7fdfa62 Mon Sep 17 00:00:00 2001 From: Stefanie Doll Date: Wed, 13 Feb 2019 12:30:41 +0100 Subject: [PATCH] App-js follow up tasks (#703) * Bump up yarn.lock * Clean up examples, added jacos example to storage examples * Fixed Dropdown * Update package.json * resize wip * css resize fix * Add line-break after code in exec to prevent catch from being commented out * Fixed typo in example * Formatting * More formatting * Added missing semicolon * Update to use UI signer * Make visible on sidebar * Combine some info from samples * blockPeriod.toNumber() (oops, dropped that, reinstate) * lifecycle bugfix for duplicate comments * Kicked Intro, moved info to WRAPPER * removed leftover import --- packages/app-js/src/Editor.tsx | 13 +-- packages/app-js/src/Intro.tsx | 27 ----- packages/app-js/src/index.css | 101 ++++++++++-------- packages/app-js/src/index.tsx | 18 ++-- .../src/snippets/extrinsics-examples.ts | 11 +- packages/app-js/src/snippets/index.ts | 6 +- packages/app-js/src/snippets/queries.ts | 29 ----- packages/app-js/src/snippets/rpc-examples.ts | 2 +- .../app-js/src/snippets/storage-examples.ts | 59 ++++++---- packages/app-js/src/snippets/transfer.ts | 4 + packages/app-js/src/snippets/wrapping.ts | 3 +- packages/apps/src/routing/js.ts | 1 - 12 files changed, 118 insertions(+), 156 deletions(-) delete mode 100644 packages/app-js/src/Intro.tsx delete mode 100644 packages/app-js/src/snippets/queries.ts diff --git a/packages/app-js/src/Editor.tsx b/packages/app-js/src/Editor.tsx index fd04b7f72b..59759bd21c 100644 --- a/packages/app-js/src/Editor.tsx +++ b/packages/app-js/src/Editor.tsx @@ -33,23 +33,13 @@ export default class Editor extends React.PureComponent { this.id = `flask-${Date.now()}`; } - static getDerivedStateFromProps (nextProps: Props, prevState: State) { - if (nextProps.snippet !== prevState.snippet) { - return { - snippet: nextProps.snippet - }; - } - return null; - } - componentDidMount () { this.editor = new CodeFlask(`#${this.id}`, { language: 'js', lineNumbers: true }); - const { editor, props: { code, onEdit } } = this; - editor.updateCode(`${WRAPPING}${code}`); + const { editor, props: { code, onEdit } } = this; editor.onUpdate((code: string) => { onEdit(code); @@ -68,6 +58,7 @@ export default class Editor extends React.PureComponent { if (snippet !== this.state.snippet) { onEdit(code); this.editor.updateCode(`${WRAPPING}${code}`); + this.setState({ snippet }); } } diff --git a/packages/app-js/src/Intro.tsx b/packages/app-js/src/Intro.tsx deleted file mode 100644 index 43aef7afba..0000000000 --- a/packages/app-js/src/Intro.tsx +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2017-2019 @polkadot/app-js 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 { Trans } from 'react-i18next'; -import React from 'react'; - -import translate from './translate'; - -type Props = I18nProps; - -const Intro = (props: Props) => { - const { t } = props; - return ( - -

All code is wrapped within an async closure, allowing access to - @polkadot/api, - @polkadot/util-crypto, - @polkadot/ui-keyring and - @polkadot/util. -

-
- ); -}; -export default translate(Intro); diff --git a/packages/app-js/src/index.css b/packages/app-js/src/index.css index fff1e07bda..161e31ef60 100644 --- a/packages/app-js/src/index.css +++ b/packages/app-js/src/index.css @@ -9,15 +9,6 @@ padding: 1rem 0 0; } -.js--Content { - align-items: stretch; - display: flex; - flex-grow: 2; - height: 100%; - justify-content: space-between; - margin-bottom: 0; -} - .js--Dropdown { margin-right: 100px; position: relative; @@ -30,6 +21,15 @@ } } +.js--Content { + align-content: stretch; + align-items: stretch; + display: flex; + height: 100%; + justify-content: space-between; + margin-bottom: 0; +} + .js--Editor, .js--Output { min-width: 200px; @@ -42,34 +42,64 @@ } } +.js--Editor { + flex-grow: 1; + overflow: auto; + padding: 0; + position: relative; + resize: horizontal; + width: 60%; + + textarea { + outline: 0; + } + + .codeflask--has-line-numbers { + z-index: 0; + } + + .codeflask--has-line-numbers .codeflask__flatten { + font-size: 12px; + height: 99.99%; + line-height: 18px; + min-width: calc(100% - 40px); + width: auto; + } + + .codeflask__lines { + background: #fafafa; + line-height: 18px; + z-index: 100; + } + + &::after { + bottom: 0; + content: '↔'; + cursor: col-resize; + font-size: 20px; + height: 20px; + line-height: 18px; + position: absolute; + right: 0; + width: 22px; + z-index: 1; + } +} + .js--Output { background-color: #4e4e4e; color: #ffffff; display: flex; flex-direction: column; + flex-grow: 1; font-family: monospace; font-size: 12px; font-variant-ligatures: common-ligatures; line-height: 18px; - overflow: auto; padding: 10px; position: relative; - resize: horizontal; width: 40%; - &::after { - font-size: 24px; - line-height: 24px; - content: '↔'; - cursor: col-resize; - z-index: 1; - width: 22px; - height: 30px; - position: absolute; - bottom: 0; - right: 0; - } - .logs-wrapper { display: flex; flex: 1; @@ -95,26 +125,3 @@ } } } - -.js--Editor { - flex-grow: 2; - padding: 0; - position: relative; - - textarea { - outline: 0; - } - - .codeflask--has-line-numbers .codeflask__flatten { - font-size: 12px; - line-height: 18px; - min-width: calc(100% - 40px); - width: auto; - } - - .codeflask__lines { - background: #fafafa; - line-height: 18px; - z-index: 100; - } -} diff --git a/packages/app-js/src/index.tsx b/packages/app-js/src/index.tsx index f425bff289..91d5127b91 100644 --- a/packages/app-js/src/index.tsx +++ b/packages/app-js/src/index.tsx @@ -19,7 +19,6 @@ import './index.css'; import snippets from './snippets'; import translate from './translate'; -import Intro from './Intro'; import Editor from './Editor'; import Output from './Output'; @@ -43,17 +42,23 @@ type State = { snippet: string }; -const local = snippets.find(obj => obj.value === localStorage.getItem('app-js-snippet')); - class App extends React.PureComponent { injected: Injected | null = null; state: State = { - code: local ? local.code : snippets[0].code, + code: '', isRunning: false, logs: [], - snippet: local ? local.value : snippets[0].value + snippet: '' }; + componentDidMount () { + const local = snippets.find(obj => obj.value === localStorage.getItem('app-js-snippet')); + this.setState({ + code: local ? local.code : snippets[0].code, + snippet: local ? local.value : snippets[0].value + }); + } + render () { const { code, isRunning, logs, snippet } = this.state; const { t } = this.props; @@ -62,7 +67,6 @@ class App extends React.PureComponent { return (
- { // squash into a single line so exceptions (with linenumbers) maps to the same line/origin // as we have in the editor view (TODO: Make the console.error here actually return the full stack) - const exec = `(async ({${Object.keys(this.injected).join(',')}}) => { try { ${code} } catch (error) { console.error(error); } })(injected);`; + const exec = `(async ({${Object.keys(this.injected).join(',')}}) => { try { ${code} \n } catch (error) { console.error(error); } })(injected);`; new Function('injected', exec)(this.injected); diff --git a/packages/app-js/src/snippets/extrinsics-examples.ts b/packages/app-js/src/snippets/extrinsics-examples.ts index 91a962112f..f95960678c 100644 --- a/packages/app-js/src/snippets/extrinsics-examples.ts +++ b/packages/app-js/src/snippets/extrinsics-examples.ts @@ -6,26 +6,21 @@ import { Snippet } from '@polkadot/app-js/types'; export const extrinsicMakeTransfer: Snippet = { value: 'extrinsicMakeTransfer', - text: 'Extrinsics - Make transfer and listen to events', + text: 'Make transfer and listen to events', label: { color: 'grey', children: 'Extrinsics', size: 'tiny' }, code: `// Make a transfer from Alice to Bob and listen to system events. // You need to be connected to a development chain for this example to work. +const ALICE = '5GoKvZWG5ZPYL1WUovuHW3zJBWBP5eT8CbqjdRY4Q6iMaDtZ'; const BOB = '5Gw3s7q4QLkSWwknsiPtjujPv3XM4Trxi5d4PgKMMk3gfGTE'; // Get a random number between 1 and 100000 const randomAmount = Math.floor((Math.random() * 100000) + 1); -// Get Alice seed -const ALICE_SEED = 'Alice'.padEnd(32, ' '); - -// Add Alice to our keyring (with the known seed for the account) -const alice = keyring.addFromSeed(util.stringToU8a(ALICE_SEED)); - // Create a extrinsic, transferring randomAmount units to Bob. const transfer = api.tx.balances.transfer(BOB, randomAmount); // Sign and Send the transaction -transfer.signAndSend(alice, ({ events = [], status, type }) => { +transfer.signAndSend(ALICE, ({ events = [], status, type }) => { if (type === 'Finalised') { console.log('Successful transfer of ' + randomAmount + ' with hash ' + status.asFinalised.toHex()); } else { diff --git a/packages/app-js/src/snippets/index.ts b/packages/app-js/src/snippets/index.ts index 080d50e8af..0b75c49e09 100644 --- a/packages/app-js/src/snippets/index.ts +++ b/packages/app-js/src/snippets/index.ts @@ -13,9 +13,9 @@ import { import { storageGetInfo, - storageGetBalanceInformation, storageSystemEvents, - storageListenToBalanceChange + storageListenToBalanceChange, + storageRetrieveInfoOnQueryKeys } from './storage-examples'; import { extrinsicMakeTransfer } from './extrinsics-examples'; @@ -26,9 +26,9 @@ const snippets: Array = [ rpcQueryState, rpcSysthemInfo, storageGetInfo, - storageGetBalanceInformation, storageSystemEvents, storageListenToBalanceChange, + storageRetrieveInfoOnQueryKeys, extrinsicMakeTransfer ]; diff --git a/packages/app-js/src/snippets/queries.ts b/packages/app-js/src/snippets/queries.ts deleted file mode 100644 index 8e17492a72..0000000000 --- a/packages/app-js/src/snippets/queries.ts +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2017-2019 @polkadot/app-123code authors & contributors -// This software may be modified and distributed under the terms -// of the Apache-2.0 license. See the LICENSE file for details. - -export default `// This example set shows how to make queries and retrieve info on query keys -const ALICE = '5GoKvZWG5ZPYL1WUovuHW3zJBWBP5eT8CbqjdRY4Q6iMaDtZ'; - -// retrieve the balance, once-off at the latest block -const currBalance = await api.query.balances.freeBalance(ALICE); - -console.log('Alice has a current balance of', currBalance); - -// retrieve balance updates with an optional value callback -const balanceUnsub = await api.query.balances.freeBalance(ALICE, (balance) => { - console.log('Alice has an updated balance of', balance); -}); - -// retrieve the balance at a block hash in the past -const header = await api.rpc.chain.getHeader(); -const prevHash = await api.rpc.chain.getBlockHash(header.blockNumber.subn(42)); -const prevBalance = await api.query.balances.freeBalance.at(prevHash, ALICE); - -console.log('Alice had a balance of', prevBalance, '(42 blocks ago)'); - -// useful in some situations - the value hash and storage entry size -const currHash = await api.query.balanace.freeBalance.hash(ALICE); -const currSize = await api.query.balanace.freeBalance.size(ALICE); - -console.log('Alice balance entry has a value hash of', currHash, 'with a size of', currSize);`; diff --git a/packages/app-js/src/snippets/rpc-examples.ts b/packages/app-js/src/snippets/rpc-examples.ts index 9a27b75ea6..d5f0cbe893 100644 --- a/packages/app-js/src/snippets/rpc-examples.ts +++ b/packages/app-js/src/snippets/rpc-examples.ts @@ -36,7 +36,7 @@ const unsub = await api.rpc.chain.subscribeNewHead((header) => { export const rpcQueryState: Snippet = { value: 'rpcQueryState', - text: 'Get authoring iformation', + text: 'Get state metadata', label: { color: 'pink', children: 'RPC', size: 'tiny' }, code: `// subscribe to new headers, printing the full info for 5 Blocks const unsub = await api.rpc.state.getMetadata(({ magicNumber, metadata }) => { diff --git a/packages/app-js/src/snippets/storage-examples.ts b/packages/app-js/src/snippets/storage-examples.ts index 16e9dfc2ae..be809fe130 100644 --- a/packages/app-js/src/snippets/storage-examples.ts +++ b/packages/app-js/src/snippets/storage-examples.ts @@ -9,18 +9,20 @@ export const storageGetInfo: Snippet = { text: 'Get chain state information', label: { color: 'blue', children: 'Storage', size: 'tiny' }, code: `// Get chain state information -const ALICE = '5GoKvZWG5ZPYL1WUovuHW3zJBWBP5eT8CbqjdRY4Q6iMaDtZ'; // Make our basic chain state/storage queries, all in one go -const [accountNonce, blockPeriod, validators] = await Promise.all([ - api.query.system.accountNonce(ALICE), +const [blockPeriod, validators, transferFee] = await Promise.all([ api.query.timestamp.blockPeriod(), - api.query.session.validators() + api.query.session.validators(), + api.query.balances.transferFee() ]); -console.log('Account: ' + ALICE + ' -- AccountNonce: ' + accountNonce); + console.log('blockPeriod in seconds: ' + blockPeriod.toNumber()); +console.log('transferFee: ', transferFee); + if (validators && validators.length > 0) { // Retrieve the balances for all validators console.log('Validators'); + const validatorBalances = await Promise.all( validators.map(authorityId => api.query.balances.freeBalance(authorityId)) ); @@ -33,22 +35,6 @@ if (validators && validators.length > 0) { ` }; -export const storageGetBalanceInformation: Snippet = { - value: 'storageGetBalanceInformation', - text: 'Get current transfer fee', - label: { color: 'blue', children: 'Storage', size: 'tiny' }, - code: `// Listen to the total transfer fee for 5 Blocks -let count = 0; -const unsub = await api.query.balances.transferFee((sum) => { - console.log('Transfer fee: '+ sum); - - if (++count === 5) { - console.log('listened to 5 blocks, unsubscribing'); - unsub(); - } -});` -}; - export const storageSystemEvents: Snippet = { value: 'storageSystemEvents', text: 'Listen to system events', @@ -96,3 +82,34 @@ api.query.balances.freeBalance(ALICE, (balance) => { } });` }; + +export const storageRetrieveInfoOnQueryKeys: Snippet = { + value: 'storageRetrieveInfoOnQueryKeys', + text: 'Retrieve Info on query keys', + label: { color: 'blue', children: 'Storage', size: 'tiny' }, + code: `// This example set shows how to make queries and retrieve info on query keys +const ALICE = '5GoKvZWG5ZPYL1WUovuHW3zJBWBP5eT8CbqjdRY4Q6iMaDtZ'; + +// retrieve the balance, once-off at the latest block +const currBalance = await api.query.balances.freeBalance(ALICE); + +console.log('Alice has a current balance of', currBalance); + +// retrieve balance updates with an optional value callback +const balanceUnsub = await api.query.balances.freeBalance(ALICE, (balance) => { + console.log('Alice has an updated balance of', balance); +}); + +// retrieve the balance at a block hash in the past +const header = await api.rpc.chain.getHeader(); +const prevHash = await api.rpc.chain.getBlockHash(header.blockNumber.subn(42)); +const prevBalance = await api.query.balances.freeBalance.at(prevHash, ALICE); + +console.log('Alice had a balance of', prevBalance, '(42 blocks ago)'); + +// useful in some situations - the value hash and storage entry size +const currHash = await api.query.balances.freeBalance.hash(ALICE); +const currSize = await api.query.balances.freeBalance.size(ALICE); + +console.log('Alice balance entry has a value hash of', currHash, 'with a size of', currSize);` +}; diff --git a/packages/app-js/src/snippets/transfer.ts b/packages/app-js/src/snippets/transfer.ts index bfd3c2cdb4..8510d424d8 100644 --- a/packages/app-js/src/snippets/transfer.ts +++ b/packages/app-js/src/snippets/transfer.ts @@ -6,6 +6,10 @@ export default `// transfer const sender = '5GoKvZWG5ZPYL1WUovuHW3zJBWBP5eT8CbqjdRY4Q6iMaDtZ'; const recipient = '5GTZEKgRKX2a5hepNjwTBzR5nR6UqtEsMZ4TnL1Yuah1N2Tu'; +const nonce = await api.query.system.accountNonce(ALICE), + +console.log('Current nonce', nonce); + const unsub = await api.tx.balances .transfer(recipient,12345) .signAndSend(sender, ({ events = [], status, type }) => { diff --git a/packages/app-js/src/snippets/wrapping.ts b/packages/app-js/src/snippets/wrapping.ts index 580e7d1601..85f8fc3a4f 100644 --- a/packages/app-js/src/snippets/wrapping.ts +++ b/packages/app-js/src/snippets/wrapping.ts @@ -2,7 +2,8 @@ // This software may be modified and distributed under the terms // of the Apache-2.0 license. See the LICENSE file for details. -export default `// (async ({ api, hashing, keyring, util }) => { +export default `// All code is wrapped within an async closure, allowing access to api, hashing, keyring, util. +// (async ({ api, hashing, keyring, util }) => { // ... any user code is executed here ... // })(); diff --git a/packages/apps/src/routing/js.ts b/packages/apps/src/routing/js.ts index 6f4523eb75..660e368545 100644 --- a/packages/apps/src/routing/js.ts +++ b/packages/apps/src/routing/js.ts @@ -10,7 +10,6 @@ export default ([ { Component: Js, display: { - isHidden: true, needsApi: [] }, i18n: {