Sd 668 app console (#684)
* [app-js] fixed copyright * [app-js] css fixes * [app-js] Add api to window object * Make CSS columns resizable (FF & Chrome) * Window Interface export * formatting * Make columns responsive, added Dropdown * Added code snippets * Strip down output to functional component * removed component state, removed onEdit, update on select * Editor styling * Added snippets and local storage * output formatting * Example dummies * Cleanup & examples * Added util & keyring @polkadot modules to window object * Moved intro to component to make it translatable * Added more RPC examples * small fix * WIP exaples * Styles for resizer, fixed flex overflow misbehaviour * remove code from snippets for options, * Added labels to dropdown * Examples * More examples and removed deprecated examples * Added labels to dropdown -> missing type decl. * correst link to ui-keyring package * Make tslint happy * Pull api clone/disconnect into sd-668 (#686) * JS playground & console (start something...) * It runs... * WIP * Use codeflask * Highlights * Small updates, console v0.1 is ok to play with * Bump * Only shadow, no border (article) * Allow API to be disposed of between runs * Clone and disconnect API * Move id generation (no need for constructor) * Small updates * Small type adjustments * smaller fixes after code review * updated yarn.lock * move options calculation out of return * Remove exposure of api to window object * Expand JS console logging (#691) * Expand JS console logging * Log extrinsics directly * switch to getDerivedStateFromProps() * roll back ts versions * react-i18next rollback to 9.0.2 * Lock react-i18next to 9.0.2
This commit is contained in:
parent
e3ac5dbc3d
commit
061f346fd6
@ -1,4 +1,4 @@
|
||||
// Copyright 2017-2019 @polkadot/app-123code authors & contributors
|
||||
// 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.
|
||||
|
||||
@ -7,74 +7,79 @@ import { BareProps } from '@polkadot/ui-app/types';
|
||||
import React from 'react';
|
||||
import CodeFlask from 'codeflask';
|
||||
|
||||
import DEFAULT_CODE from './snippets/newHead';
|
||||
import WRAPPING from './snippets/wrapping';
|
||||
|
||||
type Props = BareProps & {
|
||||
children?: React.ReactNode,
|
||||
onEdit: (code: string) => void
|
||||
};
|
||||
type State = {
|
||||
code: string
|
||||
code: string,
|
||||
onEdit: (code: string) => void,
|
||||
snippet: string
|
||||
};
|
||||
|
||||
export default class Editor extends React.PureComponent<Props, State> {
|
||||
private id: string;
|
||||
type State = {
|
||||
snippet: string
|
||||
};
|
||||
|
||||
export default class Editor extends React.PureComponent<Props> {
|
||||
private id: string = `flask-${Date.now()}`;
|
||||
private editor: any;
|
||||
|
||||
state: State = {
|
||||
snippet: ''
|
||||
};
|
||||
|
||||
constructor (props: Props) {
|
||||
super(props);
|
||||
|
||||
this.id = `flask-${Date.now()}`;
|
||||
this.state = {
|
||||
code: `${WRAPPING}${DEFAULT_CODE}`
|
||||
};
|
||||
}
|
||||
|
||||
static getDerivedStateFromProps (nextProps: Props, prevState: State) {
|
||||
if (nextProps.snippet !== prevState.snippet) {
|
||||
return {
|
||||
snippet: nextProps.snippet
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
const { onEdit } = this.props;
|
||||
const { code } = this.state;
|
||||
|
||||
const editor = new CodeFlask(`#${this.id}`, {
|
||||
this.editor = new CodeFlask(`#${this.id}`, {
|
||||
language: 'js',
|
||||
lineNumbers: true
|
||||
});
|
||||
const { editor, props: { code, onEdit } } = this;
|
||||
|
||||
editor.updateCode(code);
|
||||
editor.updateCode(`${WRAPPING}${code}`);
|
||||
|
||||
editor.onUpdate((code: string) => {
|
||||
this.onEdit(code);
|
||||
onEdit(code);
|
||||
});
|
||||
|
||||
editor.editorRoot.addEventListener('focusin', () => {
|
||||
editor.onUpdate(this.onEdit);
|
||||
});
|
||||
|
||||
editor.editorRoot.addEventListener('focusout', () => {
|
||||
editor.onUpdate(() => {
|
||||
// empty
|
||||
});
|
||||
this.editor.onUpdate(onEdit);
|
||||
});
|
||||
|
||||
onEdit(code);
|
||||
}
|
||||
|
||||
render () {
|
||||
const { children } = this.props;
|
||||
componentDidUpdate () {
|
||||
const { code, onEdit, snippet } = this.props;
|
||||
|
||||
if (snippet !== this.state.snippet) {
|
||||
onEdit(code);
|
||||
this.editor.updateCode(`${WRAPPING}${code}`);
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
return (
|
||||
<article className='js--Editor'>
|
||||
<article className='container js--Editor'>
|
||||
<div
|
||||
className='container'
|
||||
className=''
|
||||
id={this.id}
|
||||
/>
|
||||
{children}
|
||||
{this.props.children}
|
||||
</article>
|
||||
);
|
||||
}
|
||||
|
||||
private onEdit = (code: string): void => {
|
||||
const { onEdit } = this.props;
|
||||
|
||||
this.setState({ code }, () => onEdit(code));
|
||||
}
|
||||
}
|
||||
|
||||
27
packages/app-js/src/Intro.tsx
Normal file
27
packages/app-js/src/Intro.tsx
Normal file
@ -0,0 +1,27 @@
|
||||
// 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);
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright 2017-2019 @polkadot/app-123code authors & contributors
|
||||
// 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.
|
||||
|
||||
@ -6,33 +6,46 @@ import { BareProps } from '@polkadot/ui-app/types';
|
||||
import { Log } from './types';
|
||||
|
||||
import React from 'react';
|
||||
import { format } from '@polkadot/util/logger';
|
||||
import { isError, isNull, isUndefined } from '@polkadot/util';
|
||||
|
||||
type Props = BareProps & {
|
||||
children?: React.ReactNode,
|
||||
logs: Array<Log>
|
||||
};
|
||||
|
||||
export default class Output extends React.PureComponent<Props> {
|
||||
render () {
|
||||
const { children, logs } = this.props;
|
||||
|
||||
return (
|
||||
<div className='js--Output'>
|
||||
{logs.map(this.renderEntry)}
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
const format = (value: any): string => {
|
||||
if (isError(value)) {
|
||||
return value.stack ? value.stack : value.toString();
|
||||
} else if (isUndefined(value)) {
|
||||
return 'undefined';
|
||||
} else if (isNull(value)) {
|
||||
return 'null';
|
||||
} else if (Array.isArray(value)) {
|
||||
return `[${value.map((value) => format(value)).join(', ')}]`;
|
||||
} else if (value instanceof Map) {
|
||||
return `{${[...value.entries()].map(([key, value]) => key + ': ' + format(value)).join(', ')}}`;
|
||||
}
|
||||
|
||||
private renderEntry = ({ args, type }: Log, index: number) => {
|
||||
return (
|
||||
<div
|
||||
className={`js--Log ${type}`}
|
||||
key={index}
|
||||
>
|
||||
{args.map((arg) => format(arg)).join(' ')}
|
||||
return value.toString();
|
||||
};
|
||||
|
||||
const renderEntry = ({ args, type }: Log, index: number): React.ReactNode => (
|
||||
<div className={`js--Log ${type}`} key={index}>
|
||||
{args.map((arg) => format(arg)).join(' ')}
|
||||
</div>
|
||||
);
|
||||
|
||||
export default (props: Props) => {
|
||||
return (
|
||||
<article className='container js--Output'>
|
||||
<div className='logs-wrapper'>
|
||||
<div className='logs-container'>
|
||||
<div className='logs-content'>
|
||||
{props.logs.map(renderEntry)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
{props.children}
|
||||
</article>
|
||||
);
|
||||
};
|
||||
|
||||
2
packages/app-js/src/codeflask.d.ts
vendored
2
packages/app-js/src/codeflask.d.ts
vendored
@ -1,4 +1,4 @@
|
||||
// Copyright 2017-2019 @polkadot/app-123code authors & contributors
|
||||
// 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.
|
||||
|
||||
|
||||
@ -3,15 +3,35 @@
|
||||
/* of the Apache-2.0 license. See the LICENSE file for details. */
|
||||
|
||||
.js--App {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
padding: 1rem 1.5rem;
|
||||
}
|
||||
|
||||
/* .container {
|
||||
padding: 0.25rem;
|
||||
} */
|
||||
.js--Content {
|
||||
align-items: stretch;
|
||||
display: flex;
|
||||
flex-grow: 2;
|
||||
justify-content: space-between;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.js--Dropdown {
|
||||
margin-right: 100px;
|
||||
position: relative;
|
||||
z-index: 200;
|
||||
.dropdown .menu > .item {
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
|
||||
.js--Editor,
|
||||
.js--Output {
|
||||
min-width: 200px;
|
||||
|
||||
.action-button {
|
||||
position: absolute;
|
||||
right: 0.25rem;
|
||||
@ -21,12 +41,46 @@
|
||||
}
|
||||
|
||||
.js--Output {
|
||||
margin-top: 1rem;
|
||||
padding: 10px;
|
||||
background-color: #4e4e4e;
|
||||
color: #ffffff;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
font-family: monospace;
|
||||
font-size: 14px;
|
||||
font-size: 13px;
|
||||
font-variant-ligatures: common-ligatures;
|
||||
overflow: auto;
|
||||
padding: 10px;
|
||||
position: relative;
|
||||
resize: horizontal;
|
||||
width: 50%;
|
||||
|
||||
&::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;
|
||||
min-height: 0px;
|
||||
}
|
||||
|
||||
.logs-container {
|
||||
flex: 1;
|
||||
overflow: auto;;
|
||||
}
|
||||
|
||||
.logs-content {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.js--Log {
|
||||
animation: fadein 0.2s;
|
||||
@ -34,26 +88,25 @@
|
||||
word-break: break-all;
|
||||
|
||||
&.error {
|
||||
color: red;
|
||||
color: #f88;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.js--Editor {
|
||||
flex-grow: 2;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
|
||||
> div.container {
|
||||
width: 100%;
|
||||
height: 60vh;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.codeflask {
|
||||
/* background: #f4f7fb; */
|
||||
}
|
||||
|
||||
textarea {
|
||||
outline: 0;
|
||||
}
|
||||
.codeflask--has-line-numbers .codeflask__flatten {
|
||||
min-width: calc(100% - 40px);
|
||||
width: auto;
|
||||
}
|
||||
.codeflask__lines {
|
||||
background: #eee;
|
||||
z-index: 100;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,58 +2,108 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { ApiPromise } from '@polkadot/api';
|
||||
import { KeyringInstance } from '@polkadot/keyring/types';
|
||||
import { ApiProps } from '@polkadot/ui-api/types';
|
||||
import { AppProps, I18nProps } from '@polkadot/ui-app/types';
|
||||
import { Log, LogType } from './types';
|
||||
|
||||
import React from 'react';
|
||||
import { withApi, withMulti } from '@polkadot/ui-api/index';
|
||||
import { Button } from '@polkadot/ui-app/index';
|
||||
import { Button, Dropdown } from '@polkadot/ui-app/index';
|
||||
import uiKeyring from '@polkadot/ui-keyring';
|
||||
import * as util from '@polkadot/util';
|
||||
import * as hashing from '@polkadot/util-crypto';
|
||||
|
||||
import './index.css';
|
||||
|
||||
import Editor from './Editor';
|
||||
import Output from './Output';
|
||||
import snippets from './snippets';
|
||||
import translate from './translate';
|
||||
|
||||
import Intro from './Intro';
|
||||
import Editor from './Editor';
|
||||
import Output from './Output';
|
||||
|
||||
type Injected = {
|
||||
api: ApiPromise,
|
||||
console: {
|
||||
error: (...args: Array<any>) => void,
|
||||
log: (...args: Array<any>) => void
|
||||
},
|
||||
global: null,
|
||||
hashing: typeof hashing,
|
||||
keyring: KeyringInstance,
|
||||
util: typeof util,
|
||||
window: null
|
||||
};
|
||||
type Props = ApiProps & AppProps & I18nProps;
|
||||
type State = {
|
||||
code: string,
|
||||
logs: Array<Log>
|
||||
isRunning: boolean,
|
||||
logs: Array<Log>,
|
||||
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: '',
|
||||
logs: []
|
||||
code: local ? local.code : snippets[0].code,
|
||||
isRunning: false,
|
||||
logs: [],
|
||||
snippet: local ? local.value : snippets[0].value
|
||||
};
|
||||
|
||||
render () {
|
||||
const { logs } = this.state;
|
||||
const { code, isRunning, logs, snippet } = this.state;
|
||||
const { t } = this.props;
|
||||
const options = snippets.map(({ code, ...options }) => ({ ...options }));
|
||||
|
||||
return (
|
||||
<main className='js--App'>
|
||||
<Editor onEdit={this.onEdit}>
|
||||
<Button
|
||||
className='action-button'
|
||||
isCircular
|
||||
isPrimary
|
||||
icon='play'
|
||||
onClick={this.runJs}
|
||||
<header className='container'>
|
||||
<Intro />
|
||||
<Dropdown
|
||||
className='js--Dropdown'
|
||||
onChange={this.selectExample}
|
||||
options={options}
|
||||
label={t('Select example')}
|
||||
defaultValue={snippet}
|
||||
withLabel
|
||||
/>
|
||||
</Editor>
|
||||
<Output logs={logs}>
|
||||
<Button
|
||||
className='action-button'
|
||||
isCircular
|
||||
isNegative
|
||||
icon='erase'
|
||||
onClick={this.clearConsole}
|
||||
/>
|
||||
</Output>
|
||||
</header>
|
||||
<section className='js--Content'>
|
||||
<Editor
|
||||
code={code}
|
||||
snippet={snippet}
|
||||
onEdit={this.onEdit}
|
||||
>
|
||||
<div className='action-button'>
|
||||
<Button
|
||||
isCircular
|
||||
isPrimary
|
||||
icon='play'
|
||||
onClick={this.runJs}
|
||||
/>
|
||||
<Button
|
||||
isCircular
|
||||
isDisabled={!isRunning}
|
||||
isNegative
|
||||
icon='close'
|
||||
onClick={this.stopJs}
|
||||
/>
|
||||
</div>
|
||||
</Editor>
|
||||
<Output logs={logs}>
|
||||
<Button
|
||||
className='action-button'
|
||||
isCircular
|
||||
isNegative
|
||||
icon='erase'
|
||||
onClick={this.clearConsole}
|
||||
/>
|
||||
</Output>
|
||||
</section>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
@ -62,8 +112,12 @@ class App extends React.PureComponent<Props, State> {
|
||||
const { api } = this.props;
|
||||
const { code } = this.state;
|
||||
const { keyring } = uiKeyring;
|
||||
const injected = {
|
||||
api,
|
||||
|
||||
this.stopJs();
|
||||
this.clearConsole();
|
||||
|
||||
this.injected = {
|
||||
api: api.clone(),
|
||||
console: {
|
||||
error: this.hookConsole('error'),
|
||||
log: this.hookConsole('log')
|
||||
@ -75,9 +129,31 @@ class App extends React.PureComponent<Props, State> {
|
||||
window: null
|
||||
};
|
||||
|
||||
const exec = `(async ({${Object.keys(injected).join(',')}}) => { try { ${code} } catch (error) { console.error(error); } })(injected);`;
|
||||
// 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);`;
|
||||
|
||||
new Function('injected', exec)(injected);
|
||||
new Function('injected', exec)(this.injected);
|
||||
|
||||
this.setState({ isRunning: true });
|
||||
}
|
||||
|
||||
private stopJs = (): void => {
|
||||
if (!this.injected) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.injected.api.disconnect();
|
||||
this.injected = null;
|
||||
|
||||
this.setState({ isRunning: false });
|
||||
}
|
||||
|
||||
private selectExample = (value: string) => {
|
||||
const snippet = snippets.find(obj => obj.value === value);
|
||||
|
||||
localStorage.setItem('app-js-snippet', value);
|
||||
this.setState({ code: (snippet ? snippet.code : ''), snippet: value });
|
||||
}
|
||||
|
||||
private onEdit = (code: string): void => {
|
||||
|
||||
38
packages/app-js/src/snippets/extrinsics-examples.ts
Normal file
38
packages/app-js/src/snippets/extrinsics-examples.ts
Normal file
@ -0,0 +1,38 @@
|
||||
// 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 { Snippet } from '@polkadot/app-js/types';
|
||||
|
||||
export const extrinsicMakeTransfer: Snippet = {
|
||||
value: 'extrinsicMakeTransfer',
|
||||
text: 'Extrinsics - 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 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 }) => {
|
||||
if (type === 'Finalised') {
|
||||
console.log('Successful transfer of ' + randomAmount + ' with hash ' + status.asFinalised.toHex());
|
||||
} else {
|
||||
console.log('Status of transfer: ' + type);
|
||||
}
|
||||
events.forEach(({ phase, event: { data, method, section } }) => {
|
||||
console.log(phase.toString() + ' : ' + section + '.' + method + ' ' + data.toString());
|
||||
});
|
||||
});`
|
||||
};
|
||||
35
packages/app-js/src/snippets/index.ts
Normal file
35
packages/app-js/src/snippets/index.ts
Normal file
@ -0,0 +1,35 @@
|
||||
// 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.
|
||||
|
||||
import { Snippet } from './../types';
|
||||
|
||||
import {
|
||||
rpcNetworkAuthoring,
|
||||
rpcNewHead,
|
||||
rpcQueryState,
|
||||
rpcSysthemInfo
|
||||
} from './rpc-examples';
|
||||
|
||||
import {
|
||||
storageGetInfo,
|
||||
storageGetBalanceInformation,
|
||||
storageSystemEvents,
|
||||
storageListenToBalanceChange
|
||||
} from './storage-examples';
|
||||
|
||||
import { extrinsicMakeTransfer } from './extrinsics-examples';
|
||||
|
||||
const snippets: Array<Snippet> = [
|
||||
rpcNetworkAuthoring,
|
||||
rpcNewHead,
|
||||
rpcQueryState,
|
||||
rpcSysthemInfo,
|
||||
storageGetInfo,
|
||||
storageGetBalanceInformation,
|
||||
storageSystemEvents,
|
||||
storageListenToBalanceChange,
|
||||
extrinsicMakeTransfer
|
||||
];
|
||||
|
||||
export default snippets;
|
||||
@ -1,14 +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 `// subscribe to new headers, printing the full info for 5
|
||||
let count = 0;
|
||||
const unsub = await api.rpc.chain.subscribeNewHead((header) => {
|
||||
console.log(\`#\${header.blockNumber}:\`, header);
|
||||
|
||||
if (++count === 5) {
|
||||
console.log('5 headers retrieved, unsubscribing');
|
||||
unsub();
|
||||
}
|
||||
});`;
|
||||
29
packages/app-js/src/snippets/queries.ts
Normal file
29
packages/app-js/src/snippets/queries.ts
Normal file
@ -0,0 +1,29 @@
|
||||
// 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);`;
|
||||
70
packages/app-js/src/snippets/rpc-examples.ts
Normal file
70
packages/app-js/src/snippets/rpc-examples.ts
Normal file
@ -0,0 +1,70 @@
|
||||
// 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 { Snippet } from '@polkadot/app-js/types';
|
||||
|
||||
export const rpcNetworkAuthoring: Snippet = {
|
||||
value: 'rpcNetworkAuthoring',
|
||||
text: 'Get authoring information',
|
||||
label: { color: 'pink', children: 'RPC', size: 'tiny' },
|
||||
code: `// Returns all pending extrinsics, potentially grouped by sender
|
||||
const unsub = await api.rpc.author.pendingExtrinsics((extrinsics) => {
|
||||
if(extrinsics.length === 0){
|
||||
console.log('No pending extrinsics');
|
||||
return;
|
||||
}
|
||||
console.log(extrinsics);
|
||||
});`
|
||||
};
|
||||
|
||||
export const rpcNewHead: Snippet = {
|
||||
value: 'rpcListenToHead',
|
||||
text: 'Listen to new Head',
|
||||
label: { color: 'pink', children: 'RPC', size: 'tiny' },
|
||||
code: `// subscribe to new headers, printing the full info for 5 Blocks
|
||||
let count = 0;
|
||||
const unsub = await api.rpc.chain.subscribeNewHead((header) => {
|
||||
console.log(\`#\${header.blockNumber}:\`, header);
|
||||
|
||||
if (++count === 5) {
|
||||
console.log('5 headers retrieved, unsubscribing');
|
||||
unsub();
|
||||
}
|
||||
});`
|
||||
};
|
||||
|
||||
export const rpcQueryState: Snippet = {
|
||||
value: 'rpcQueryState',
|
||||
text: 'Get authoring iformation',
|
||||
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 }) => {
|
||||
console.log( 'Magic number: ' + magicNumber );
|
||||
console.log( 'Metadata: ' + metadata.raw );
|
||||
});`
|
||||
};
|
||||
|
||||
export const rpcSysthemInfo: Snippet = {
|
||||
value: 'rpcSysthemInfo',
|
||||
text: 'Get system information',
|
||||
label: { color: 'pink', children: 'RPC', size: 'tiny' },
|
||||
code: `// Retrieve the chain & node information information via rpc calls
|
||||
const [chain, nodeName, nodeVersion, properties] = await Promise.all([
|
||||
api.rpc.system.chain(),
|
||||
api.rpc.system.name(),
|
||||
api.rpc.system.version(),
|
||||
api.rpc.system.properties()
|
||||
]);
|
||||
console.log('You are connected to chain ' + chain)
|
||||
console.log('You are using: ' + nodeName + ' v' + nodeVersion);
|
||||
|
||||
if (properties.size > 0) {
|
||||
console.log('Node specific properties:');
|
||||
properties.forEach((value, key) => {
|
||||
console.log(key, value);
|
||||
});
|
||||
} else {
|
||||
console.log('No specific chain properties found.');
|
||||
}`
|
||||
};
|
||||
98
packages/app-js/src/snippets/storage-examples.ts
Normal file
98
packages/app-js/src/snippets/storage-examples.ts
Normal file
@ -0,0 +1,98 @@
|
||||
// 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 { Snippet } from '@polkadot/app-js/types';
|
||||
|
||||
export const storageGetInfo: Snippet = {
|
||||
value: 'storageGetInfo',
|
||||
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),
|
||||
api.query.timestamp.blockPeriod(),
|
||||
api.query.session.validators()
|
||||
]);
|
||||
console.log('Account: ' + ALICE + ' -- AccountNonce: ' + accountNonce);
|
||||
console.log('blockPeriod in seconds: ' + blockPeriod.toNumber());
|
||||
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))
|
||||
);
|
||||
|
||||
validators.forEach((authorityId, index) => {
|
||||
console.log('Validator: ' + authorityId.toString() )
|
||||
console.log('Balance: ' + validatorBalances[index].toString() );
|
||||
});
|
||||
}
|
||||
`
|
||||
};
|
||||
|
||||
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',
|
||||
label: { color: 'blue', children: 'Storage', size: 'tiny' },
|
||||
code: `// Subscribe to system events via storage
|
||||
api.query.system.events((events) => {
|
||||
console.log('----- Received ' + events.length + ' event(s): -----');
|
||||
// loop through the Vec<EventRecord>
|
||||
events.forEach((record) => {
|
||||
// extract the phase, event and the event types
|
||||
const { event, phase } = record;
|
||||
const types = event.typeDef;
|
||||
// show what we are busy with
|
||||
console.log(event.section + ':' + event.method + '::' + 'phase=' + phase.toString());
|
||||
console.log(event.meta.documentation.toString());
|
||||
// loop through each of the parameters, displaying the type and data
|
||||
event.data.forEach((data, index) => {
|
||||
console.log(types[index].type + ';' + data.toString());
|
||||
});
|
||||
});
|
||||
});`
|
||||
};
|
||||
|
||||
export const storageListenToBalanceChange: Snippet = {
|
||||
value: 'storageListenToBalanceChange',
|
||||
text: 'Listen to balance changes',
|
||||
label: { color: 'blue', children: 'Storage', size: 'tiny' },
|
||||
code: `// You may leave this example running and make a transfer
|
||||
// of any value from or to Alice address in the 'Transfer' App
|
||||
const ALICE = '5GoKvZWG5ZPYL1WUovuHW3zJBWBP5eT8CbqjdRY4Q6iMaDtZ';
|
||||
|
||||
// Retrieve the initial balance.
|
||||
let previous = await api.query.balances.freeBalance(ALICE);
|
||||
console.log('ALICE has a balance of' + previous);
|
||||
|
||||
// Subscribe and listen to balance changes
|
||||
api.query.balances.freeBalance(ALICE, (balance) => {
|
||||
// Calculate the delta
|
||||
const change = balance.sub(previous);
|
||||
// Only display positive value changes (Since we are pulling 'previous' above already,
|
||||
// the initial balance change will also be zero)
|
||||
if (!change.isZero()) {
|
||||
previous = balance;
|
||||
console.log('New transaction of: '+ change);
|
||||
}
|
||||
});`
|
||||
};
|
||||
@ -1,12 +1,9 @@
|
||||
// Copyright 2017-2019 @polkadot/app-123code authors & contributors
|
||||
// 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.
|
||||
|
||||
export default `// all code is wrapped within an async closure, allowing access to:
|
||||
// api (@polkadot/api), hashing (@polkadot/util-crypto),
|
||||
// keyring (@polkadot/keyring) and util (@polkadot/util)
|
||||
// (async ({ api, hashing, keyring, util }) => {
|
||||
export default `// (async ({ api, hashing, keyring, util }) => {
|
||||
// ... any user code is executed here ...
|
||||
// })(injected);
|
||||
// })();
|
||||
|
||||
`;
|
||||
|
||||
@ -1,10 +1,20 @@
|
||||
// Copyright 2017-2019 @polkadot/app-123code authors & contributors
|
||||
// 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 { SemanticShorthandItem } from 'semantic-ui-react/dist/commonjs/generic';
|
||||
import { LabelProps } from 'semantic-ui-react/dist/commonjs/elements/Label';
|
||||
|
||||
export type LogType = 'error' | 'log';
|
||||
|
||||
export type Log = {
|
||||
args: Array<any>,
|
||||
type: LogType
|
||||
};
|
||||
|
||||
export type Snippet = {
|
||||
text: string;
|
||||
value: string;
|
||||
code: string;
|
||||
label?: SemanticShorthandItem<LabelProps>
|
||||
};
|
||||
|
||||
@ -31,8 +31,7 @@
|
||||
"homepage": "https://github.com/polkadot-js/ui/tree/master/packages/ui-reactive#readme",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.2.0",
|
||||
"@polkadot/api": "^0.42.2",
|
||||
"@polkadot/types": "^0.42.2",
|
||||
"@polkadot/api": "^0.42.4",
|
||||
"rxjs-compat": "^6.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,10 +11,10 @@
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.2.0",
|
||||
"@polkadot/extrinsics": "^0.42.2",
|
||||
"@polkadot/extrinsics": "^0.42.4",
|
||||
"@polkadot/keyring": "^0.33.36",
|
||||
"@polkadot/storage": "^0.42.2",
|
||||
"@polkadot/types": "^0.42.2",
|
||||
"@polkadot/storage": "^0.42.4",
|
||||
"@polkadot/types": "^0.42.4",
|
||||
"@polkadot/ui-api": "^0.23.7",
|
||||
"@polkadot/ui-identicon": "^0.25.8",
|
||||
"@polkadot/ui-keyring": "^0.25.8",
|
||||
@ -38,7 +38,7 @@
|
||||
"react-copy-to-clipboard": "^5.0.1",
|
||||
"react-dom": "^16.7.0",
|
||||
"react-dropzone": "^7.0.1",
|
||||
"react-i18next": "^9.0.2",
|
||||
"react-i18next": "9.0.2",
|
||||
"react-router": "^4.3.1",
|
||||
"react-router-dom": "^4.3.1",
|
||||
"semantic-ui-css": "^2.3.1",
|
||||
|
||||
@ -31,8 +31,7 @@
|
||||
"homepage": "https://github.com/polkadot-js/ui/tree/master/packages/ui-reactive#readme",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.2.0",
|
||||
"@polkadot/api": "^0.42.2",
|
||||
"@polkadot/types": "^0.42.2",
|
||||
"@polkadot/api": "^0.42.4",
|
||||
"rxjs-compat": "^6.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user