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 <Intro /> import
This commit is contained in:
Stefanie Doll 2019-02-13 12:30:41 +01:00 committed by GitHub
parent c57fee1494
commit a69548866b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 118 additions and 156 deletions

View File

@ -33,23 +33,13 @@ export default class Editor extends React.PureComponent<Props> {
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<Props> {
if (snippet !== this.state.snippet) {
onEdit(code);
this.editor.updateCode(`${WRAPPING}${code}`);
this.setState({ snippet });
}
}

View File

@ -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 (
<Trans i18nKey='appJsIntro'>
<p>All code is wrapped within an async closure, allowing access to
<a href='https://www.npmjs.com/package/@polkadot/api' title={t('Go to module page on npmjs.com')} target='_blank'>@polkadot/api</a>,
<a href='https://www.npmjs.com/package/@polkadot/util-crypto' title={t('Go to module page on npmjs.com')} target='_blank'>@polkadot/util-crypto</a>,
<a href='https://www.npmjs.com/package/@polkadot/ui-keyring' title={t('Go to module page on npmjs.com')} target='_blank'>@polkadot/ui-keyring</a> and
<a href='https://www.npmjs.com/package/@polkadot/util' title={t('Go to module page on npmjs.com')} target='_blank'>@polkadot/util</a>.
</p>
</Trans>
);
};
export default translate(Intro);

View File

@ -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;
}
}

View File

@ -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<Props, State> {
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<Props, State> {
return (
<main className='js--App'>
<header className='container'>
<Intro />
<Dropdown
className='js--Dropdown'
onChange={this.selectExample}
@ -133,7 +137,7 @@ class App extends React.PureComponent<Props, State> {
// 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);

View File

@ -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 {

View File

@ -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<Snippet> = [
rpcQueryState,
rpcSysthemInfo,
storageGetInfo,
storageGetBalanceInformation,
storageSystemEvents,
storageListenToBalanceChange,
storageRetrieveInfoOnQueryKeys,
extrinsicMakeTransfer
];

View File

@ -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);`;

View File

@ -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 }) => {

View File

@ -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);`
};

View File

@ -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 }) => {

View File

@ -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 ...
// })();

View File

@ -10,7 +10,6 @@ export default ([
{
Component: Js,
display: {
isHidden: true,
needsApi: []
},
i18n: {