App for realtime storage queries (#11)

* Create app-storage structure

* Split shared components into ui-react-app

* Cleanup @flow issues

* Rename apps classes

* Split with ui-react-app operational

* Import es semantic-ui

* Selection section/key split into 2

* Basic storage queries (no-params) in-place

* Upgrades

* No-param queries operational

* Default values operational (dropdown)

* Additional cleanups, constrolled value

* @flow updates

* @flow fixes

* Move Params to ui-react-app (future-use in app-storage)

* Fix final @flow issues

* Query removal

* Cleanups

* Update README

* Upgrades

* Fixup cached components

* Bump @polkadot/rx-react

* Simple explorer animations

* Additional (final) cleanups
This commit is contained in:
Jaco Greeff 2018-05-04 15:07:44 +02:00 committed by GitHub
parent 3d17f951ab
commit a5607ac90e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
148 changed files with 2250 additions and 1708 deletions

View File

@ -14,5 +14,4 @@ all=warn
include_warnings=true
module.name_mapper='^@polkadot/app-\(accounts\|explorer\|extrinsics\|home\|rpc\|settings\|storage\)\(.*\)$' -> '<PROJECT_ROOT>/packages/app-\1/src\2'
module.name_mapper='^@polkadot/apps\(.*\)$' -> '<PROJECT_ROOT>/packages/apps/src\1'
module.name_mapper='^@polkadot/extrinsics-\(codec\|polkadot\|substrate\)\(.*\)$' -> '<PROJECT_ROOT>/packages/extrinsics-\1/src\2'
module.name_mapper='^@polkadot/extrinsics\(.*\)$' -> '<PROJECT_ROOT>/packages/extrinsics/src\1'
module.name_mapper='^@polkadot/ui-react-app\(.*\)$' -> '<PROJECT_ROOT>/packages/ui-react-app/src\1'

View File

@ -12,3 +12,16 @@
A Portal into the Polkadot network. 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/).
## overview
The repo is split into a number of packages, each representing an application. These are -
- [apps](packages/apps/) This is the main entry point. It handles the selection sidebar and routing to the specific application being displayed.
- [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-storage](packages/app-storage/) A simple node storage query application. Multiple queries can be queued and updates as new values become available.
In addition the following libraries are also included in the repo -
- [ui-react-app](packages/ui-react-app/) A reactive (using RxJS) application framework with a number of useful shared components. This will 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)

View File

@ -1,5 +1,6 @@
// @flow
declare module 'react-dropzone' {
declare module.exports: React$StatelessFunctionalComponent<*>
declare type Dropzone = React$StatelessFunctionalComponent<*>;
declare module.exports: Dropzone;
}

View File

@ -3,23 +3,23 @@
declare module 'semantic-ui-react/dist/es/collections/Menu' {
declare module.exports: React$StatelessFunctionalComponent<*> & {
Item: React$StatelessFunctionalComponent<*>
}
};
}
declare module 'semantic-ui-react/dist/es/elements/Button' {
declare module.exports: React$StatelessFunctionalComponent<*>
declare module.exports: React$StatelessFunctionalComponent<*>;
}
declare module 'semantic-ui-react/dist/es/elements/Icon' {
declare module.exports: React$StatelessFunctionalComponent<*>
declare module.exports: React$StatelessFunctionalComponent<*>;
}
declare module 'semantic-ui-react/dist/es/elements/Input' {
declare module.exports: React$StatelessFunctionalComponent<*>
declare module.exports: React$StatelessFunctionalComponent<*>;
}
declare module 'semantic-ui-react/dist/es/elements/Label' {
declare module.exports: React$StatelessFunctionalComponent<*>
declare module.exports: React$StatelessFunctionalComponent<*>;
}
declare module 'semantic-ui-react/dist/es/modules/Dropdown' {
@ -27,7 +27,7 @@ declare module 'semantic-ui-react/dist/es/modules/Dropdown' {
Divider: React$StatelessFunctionalComponent<*>,
Header: React$StatelessFunctionalComponent<*>,
Item: React$StatelessFunctionalComponent<*>
}
};
}
declare module 'semantic-ui-react/dist/es/modules/Modal' {
@ -35,5 +35,5 @@ declare module 'semantic-ui-react/dist/es/modules/Modal' {
Actions: React$StatelessFunctionalComponent<*>,
Content: React$StatelessFunctionalComponent<*>,
Header: React$StatelessFunctionalComponent<*>
}
};
}

View File

@ -14,7 +14,7 @@
"test": "echo 'no tests executed'"
},
"devDependencies": {
"@polkadot/dev": "^0.17.12",
"@polkadot/dev": "^0.17.13",
"babel-preset-react": "^6.24.1",
"gh-pages": "^1.1.0",
"lerna": "^2.5.1",

View File

@ -2,7 +2,7 @@
"name": "@polkadot/app-explorer",
"version": "0.1.6",
"main": "index.js",
"repository": "https://github.com/polkadot-js/portal.git",
"repository": "https://github.com/polkadot-js/apps.git",
"author": "Jaco Greeff <jacogr@gmail.com>",
"license": "ISC",
"scripts": {
@ -11,16 +11,10 @@
"test": "jest --coverage"
},
"devDependencies": {
"@polkadot/primitives": "^0.10.4",
"@polkadot/primitives-codec": "^0.10.4",
"@polkadot/primitives-json": "^0.10.4",
"@polkadot/rx-react": "^0.4.7",
"@polkadot/util": "^0.19.4",
"@polkadot/util-crypto": "^0.19.4",
"react": "^16.3.1",
"react-dom": "^16.3.1",
"react-i18next": "^7.5.1",
"semantic-ui-css": "^2.3.1",
"semantic-ui-react": "^0.79.1"
"@polkadot/primitives": "^0.12.4",
"@polkadot/primitives-codec": "^0.12.4",
"@polkadot/primitives-json": "^0.12.4",
"@polkadot/ui-react-app": "^0.1.6",
"@polkadot/util-crypto": "^0.19.4"
}
}

View File

@ -3,18 +3,16 @@
// of the ISC license. See the LICENSE file for details.
// @flow
import type { BaseProps } from '../types';
import './App.css';
import type { I18nProps } from '@polkadot/ui-react-app/types';
import React from 'react';
import BestNumber from '@polkadot/rx-react/BestNumber';
import translate from '../translate';
import BestHash from '../BestHash';
import BlockHeaders from '../BlockHeaders';
import BestHash from './BestHash';
import BlockHeaders from './BlockHeaders';
import translate from './translate';
type Props = BaseProps & {};
type Props = I18nProps & {};
function App ({ className, style, t }: Props): React$Node {
return (
@ -23,12 +21,12 @@ function App ({ className, style, t }: Props): React$Node {
style={style}
>
<BestNumber
className='explorer--App-BestNumber'
className='explorer--BestNumber'
label={t('app.bestNumber', {
defaultValue: 'best #'
})}
/>
<BestHash className='explorer--App-BestHash' />
<BestHash />
<BlockHeaders />
</div>
);

View File

@ -1,27 +0,0 @@
/* Copyright 2017-2018 Jaco Greeff
/* This software may be modified and distributed under the terms
/* of the ISC license. See the LICENSE file for details. */
.explorer--App {
padding: 1em;
}
.explorer--App-BestNumber {
font-size: 3rem;
font-weight: 100;
line-height: 3rem;
opacity: 0.5;
text-align: right;
}
.explorer--App-BestHash {
font-size: 1.5em;
font-weight: 100;
line-height: 1.5em;
margin-bottom: 1em;
opacity: 0.5;
text-align: right;
}
.explorer--App-BlockHeaders {
}

View File

@ -4,37 +4,18 @@
// @flow
import type { Header } from '@polkadot/primitives/header';
import type { BaseProps } from './types';
import React from 'react';
import headerHash from '@polkadot/primitives-codec/header/hash';
import Div from '@polkadot/rx-react/Div';
import withApiCall from '@polkadot/rx-react/with/apiCall';
import u8aToHexShort from '@polkadot/util/u8a/toHexShort';
import translate from './translate';
type Props = BaseProps & {
value?: Header
};
function BestHash ({ className, style, value }: Props): React$Node {
if (!value) {
return null;
export default withApiCall({ method: 'newHead', section: 'chain' })(
Div, {
className: 'explorer--BestHash',
format: (value?: Header): ?string =>
value
? u8aToHexShort(headerHash(value))
: value
}
return (
<div
className={['explorer--BestHash', className].join(' ')}
style={style}
>
{u8aToHexShort(headerHash(value))}
</div>
);
}
export default translate(
withApiCall({
method: 'newHead',
section: 'chain'
})(BestHash)
);

View File

@ -3,9 +3,15 @@
/* of the ISC license. See the LICENSE file for details. */
.explorer--BlockHeader {
animation: fadein 1.5s;
display: flex;
}
@keyframes fadein {
from { opacity: 0; }
to { opacity: 1; }
}
.explorer--BlockHeader:nth-child(even) {
background: #f9f9f9;
}

View File

@ -4,7 +4,7 @@
// @flow
import type { Header } from '@polkadot/primitives/header';
import type { BaseProps } from '../types';
import type { I18nProps } from '@polkadot/ui-react-app/types';
import './BlockHeader.css';
@ -14,7 +14,7 @@ import u8aToHex from '@polkadot/util/u8a/toHex';
import translate from '../translate';
type Props = BaseProps & {
type Props = I18nProps & {
label?: string,
value?: Header
};

View File

@ -4,47 +4,32 @@
// @flow
import type { Header } from '@polkadot/primitives/header';
import type { BaseProps } from '../types';
import React from 'react';
import Div from '@polkadot/rx-react/Div';
import withApiCall from '@polkadot/rx-react/with/apiCall';
import translate from '../translate';
import BlockHeader from '../BlockHeader';
import { blockHeaders } from '../subjects';
import { blockHeaders as subject } from '../subjects';
import transform from './transform';
type Props = BaseProps & {
value: Array<Header>
const apiMethod = {
method: 'newHead',
section: 'chain'
};
function BlockHeaders ({ className, style, value }: Props): React$Node {
return (
<div
className={['explorer--BlockHeaders', className].join(' ')}
style={style}
>
{
(value || []).map((header) => (
<BlockHeader
value={header}
key={header.number.toString()}
/>
))
}
</div>
);
}
const apiOptions = {
subject,
transform
};
export default translate(
withApiCall(
{
method: 'newHead',
section: 'chain'
},
{
subject: blockHeaders,
transform
}
)(BlockHeaders)
);
export default withApiCall(apiMethod, apiOptions)(Div, {
className: 'explorer--BlockHeaders',
format: (value?: Array<Header> = []): React$Node =>
value.map((value) => (
<BlockHeader
key={value.number.toString()}
value={value}
/>
))
});

View File

@ -14,11 +14,11 @@ export default function transform (header: Header): Array<Header> {
return prev;
}
return prev.reduce((next, value, index) => {
if (index < 9) {
return prev
.filter((value, index) => index < 9)
.reduce((next, value, index) => {
next.push(value);
}
return next;
}, [header]);
return next;
}, [header]);
}

View File

@ -1,3 +1,36 @@
/* Copyright 2017-2018 Jaco Greeff
/* This software may be modified and distributed under the terms
/* of the ISC license. See the LICENSE file for details. */
.explorer--App {
padding: 1em;
}
.explorer--App .rx--updated {
background: transparent !important;
}
.explorer--BestHash,
.explorer--BestNumber {
font-weight: 100;
text-align: right;
opacity: 0.5;
}
.explorer--BestHash.rx--updated,
.explorer--BestNumber.rx--updated {
opacity: 1;
}
.explorer--BestHash {
font-size: 1.5em;
line-height: 1.5em;
margin-bottom: 1em;
}
.explorer--BestNumber {
font-size: 3rem;
line-height: 3rem;
}
.explorer--BlockHeaders {}

View File

@ -5,4 +5,4 @@
import { translate } from 'react-i18next';
export default translate(['explorer']);
export default translate(['explorer', 'ui']);

View File

@ -2,7 +2,7 @@
"name": "@polkadot/app-extrinsics",
"version": "0.1.6",
"main": "index.js",
"repository": "https://github.com/polkadot-js/portal.git",
"repository": "https://github.com/polkadot-js/apps.git",
"author": "Jaco Greeff <jacogr@gmail.com>",
"license": "ISC",
"scripts": {
@ -11,18 +11,9 @@
"test": "jest --coverage"
},
"devDependencies": {
"@polkadot/extrinsics": "^0.1.6",
"@polkadot/extrinsics-codec": "^0.1.6",
"@polkadot/extrinsics-polkadot": "^0.1.6",
"@polkadot/rx-react": "^0.4.7",
"@polkadot/ui-react": "^0.9.12",
"@polkadot/util": "^0.19.4",
"@polkadot/util-keyring": "^0.19.4",
"react": "^16.3.1",
"react-dom": "^16.3.1",
"react-dropzone": "^4.2.9",
"react-i18next": "^7.5.1",
"semantic-ui-css": "^2.3.1",
"semantic-ui-react": "^0.79.1"
"@polkadot/extrinsics": "^0.12.4",
"@polkadot/extrinsics-codec": "^0.12.4",
"@polkadot/ui-react-app": "^0.1.6",
"react-dropzone": "^4.2.9"
}
}

View File

@ -3,50 +3,60 @@
// of the ISC license. See the LICENSE file for details.
// @flow
import type { BaseProps } from './types';
import type { I18nProps } from '@polkadot/ui-react-app/types';
import React from 'react';
import Label from 'semantic-ui-react/dist/es/elements/Label';
import Balance from '@polkadot/rx-react/Balance';
import withObservableParams from '@polkadot/rx-react/with/observableParams';
import InputAddress from '@polkadot/ui-react-app/src/InputAddress';
import translate from './translate';
import InputAddress from './InputAddress';
type Props = BaseProps & {
type Props = I18nProps & {
isError?: boolean,
label: string,
subject: rxjs$BehaviorSubject<Uint8Array>
};
function Account ({ className, isError, label, subject, style, t }: Props): React$Node {
const AccountBalance = withObservableParams(subject)(Balance);
class Account extends React.PureComponent<Props> {
Balance: React$ComponentType<*>;
return (
<div
className={['extrinsics--Account', 'extrinsics--split', className].join(' ')}
style={style}
>
<div className='large'>
<Label>{label}</Label>
<InputAddress
placeholder='0x...'
subject={subject}
/>
constructor (props: Props) {
super(props);
this.Balance = withObservableParams(props.subject)(Balance, {
className: 'ui disabled dropdown selection'
});
}
render (): React$Node {
const { className, label, subject, style, t } = this.props;
const Balance = this.Balance;
return (
<div
className={['extrinsics--Account', 'ui--form', className].join(' ')}
style={style}
>
<div className='large'>
<InputAddress
label={label}
placeholder='0x...'
subject={subject}
/>
</div>
<div className='small'>
<Label>
{t('account.balance', {
defaultValue: 'with an available balance of'
})}
</Label>
<Balance />
</div>
</div>
<div className='small'>
<Label>
{t('account.balance', {
defaultValue: 'with an available balance of'
})}
</Label>
<AccountBalance
className='ui disabled dropdown selection'
classNameUpdated='hasUpdated'
/>
</div>
</div>
);
);
}
}
export default translate(Account);

View File

@ -3,7 +3,8 @@
// of the ISC license. See the LICENSE file for details.
// @flow
import type { BaseProps, QueueTx } from './types';
import type { I18nProps } from '@polkadot/ui-react-app/types';
import type { QueueTx } from './types';
import React from 'react';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
@ -13,7 +14,7 @@ import Submission from './Submission';
import Signer from './Signer';
import translate from './translate';
type Props = BaseProps & {};
type Props = I18nProps & {};
const queue: rxjs$BehaviorSubject<QueueTx> = new BehaviorSubject(({
isValid: false,

View File

@ -3,43 +3,99 @@
// of the ISC license. See the LICENSE file for details.
// @flow
import type { BareProps, EncodedParams } from '../types';
import type { BareProps } from '@polkadot/ui-react-app/types';
import type { EncodedParams } from '../types';
import type { Subjects } from './types';
import React from 'react';
import Label from 'semantic-ui-react/dist/es/elements/Label';
import encodeExtrinsic from '@polkadot/extrinsics-codec/encode/extrinsic';
import withObservable from '@polkadot/rx-react/with/observable';
import InputExtrinsic from '@polkadot/ui-react-app/src/InputExtrinsic';
import Params from '@polkadot/ui-react-app/src/Params';
import isUndefined from '@polkadot/util/is/undefined';
import InputExtrinsic from '../InputExtrinsic';
import Params from '../Params';
import paramComponents from '../Params';
import createSubjects from './subjects';
type Props = BareProps & {
isError?: boolean,
isPrivate?: boolean,
label: string,
labelMethod?: string,
labelSection?: string,
subject: rxjs$BehaviorSubject<EncodedParams>
};
export default function Extrinsic ({ className, isError, isPrivate, label, style, subject }: Props): React$Node {
const subjects = createSubjects(subject);
const MethodParams = withObservable(subjects.method)(Params);
export default class Extrinsic extends React.PureComponent<Props> {
subjects: Subjects;
subscriptions: Array<rxjs$ISubscription>;
Params: React$ComponentType<*>;
return (
<div
className={['extrinsics--Extrinsic', 'extrinsics--split', className].join(' ')}
style={style}
>
<div className='full'>
<Label>{label}</Label>
<InputExtrinsic
isError={isError}
isPrivate={isPrivate}
subject={subjects.method}
constructor (props: Props) {
super(props);
this.subjects = createSubjects(props.subject);
this.Params = withObservable(this.subjects.method)(Params);
this.subscriptions = [];
}
componentWillMount () {
this.subscriptions = [
this.subjects.params.subscribe(this.onChange),
this.subjects.method.subscribe(this.onChange)
];
}
componentWillUnmount () {
this.subscriptions.forEach((s) =>
s.unsubscribe()
);
}
onChange = (): void => {
const extrinsic = this.subjects.method.getValue();
const values = this.subjects.params.getValue();
const isValid = !!extrinsic.params &&
Object
.values(extrinsic.params)
.reduce((isValid, param, index) => {
return isValid &&
!isUndefined(values[index]) &&
!isUndefined(values[index].value) &&
values[index].isValid;
}, !!values);
const raw = values.map((param) => param && param.value);
const data = extrinsic.params && encodeExtrinsic(extrinsic, raw);
this.props.subject.next({
data,
extrinsic,
isValid
});
};
render (): React$Node {
const { className, isError, isPrivate, labelMethod, labelSection, style } = this.props;
const { Params, subjects } = this;
return (
<div
className={['extrinsics--Extrinsic', 'ui--form', className].join(' ')}
style={style}
>
<div className='full'>
<InputExtrinsic
isError={isError}
isPrivate={isPrivate}
labelMethod={labelMethod}
labelSection={labelSection}
subject={subjects.method}
/>
</div>
<Params
overrides={paramComponents}
subject={subjects.params}
/>
</div>
<MethodParams
subject={subjects.params}
/>
</div>
);
);
}
}

View File

@ -4,40 +4,16 @@
// @flow
import type { Extrinsic } from '@polkadot/extrinsics/types';
import type { EncodedParams, RawParam } from '../types';
import type { EncodedParams } from '../types';
import type { Subjects } from './types';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import encodeExtrinsic from '@polkadot/extrinsics-codec/src/encode/extrinsic';
import isUndefined from '@polkadot/util/is/undefined';
type Subjects = {
method: rxjs$BehaviorSubject<Extrinsic>,
params: rxjs$BehaviorSubject<Array<RawParam>>
};
export default function subjects (subject: rxjs$BehaviorSubject<EncodedParams>): Subjects {
const subjects = {
method: new BehaviorSubject(({}: $Shape<Extrinsic>)),
const extrinsic = subject.getValue().extrinsic || ({}: $Shape<Extrinsic>);
return {
method: new BehaviorSubject(extrinsic),
params: new BehaviorSubject([])
};
const onChange = (): void => {
const extrinsic = subjects.method.getValue();
const values = subjects.params.getValue();
const isValid = !!extrinsic.params && extrinsic.params.reduce((isValid, param, index) => {
return isValid && !isUndefined(values[index]) && !isUndefined(values[index].value) && values[index].isValid;
}, !!values);
const raw = values.map((param) => param && param.value);
const data = extrinsic.params && encodeExtrinsic(extrinsic, raw);
subject.next({
data,
extrinsic,
isValid
});
};
subjects.params.subscribe(onChange);
return subjects;
}

View File

@ -0,0 +1,12 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
import type { Extrinsic } from '@polkadot/extrinsics/types';
import type { RawParam } from '@polkadot/ui-react-app/Params/types';
export type Subjects = {
method: rxjs$BehaviorSubject<Extrinsic>,
params: rxjs$BehaviorSubject<Array<RawParam>>
};

View File

@ -1,63 +0,0 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
// TODO: This is a useful, shared component, move out
import type { Extrinsic } from '@polkadot/extrinsics/types';
import './InputExtrinsic.css';
import React from 'react';
import Dropdown from 'semantic-ui-react/dist/es/modules/Dropdown';
import extrinsics from '@polkadot/extrinsics-polkadot/src';
import options from './options';
type Props = {
className?: string,
isError?: boolean,
isPrivate?: boolean,
onChange?: (event: SyntheticEvent<*>, value: Extrinsic) => void,
style?: {
[string]: string
},
subject?: rxjs$Subject<Extrinsic>
};
export default function InputExtrinsic (props: Props): React$Node {
// eslint-disable-next-line no-unused-vars
const onChange = (event: SyntheticEvent<*>, { value }): void => {
const extrinsic = extrinsics.get(value);
if (props.subject) {
props.subject.next(extrinsic);
}
if (props.onChange) {
props.onChange(event, extrinsic);
}
};
const _props = Object.assign({}, props);
delete _props.isError;
delete _props.isPrivate;
return (
<Dropdown
selection
{..._props}
className={['ui--InputExtrinsic', props.className].join(' ')}
error={props.isError}
onChange={onChange}
options={
// flowlint-next-line sketchy-null-bool:off
props.isPrivate
? options.private
: options.public
}
/>
);
}

View File

@ -1,60 +0,0 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
import React from 'react';
import Dropdown from 'semantic-ui-react/dist/es/modules/Dropdown';
import extrinsics from '@polkadot/extrinsics-polkadot/src';
const options = {
private: [],
public: []
};
const sortByName = (a, b) =>
a.name.localeCompare(b.name);
const addHeader = (shouldAdd, to, name, description) => {
if (shouldAdd) {
if (to.length) {
to.push(<Dropdown.Divider key={`${name}:divider`} />);
}
to.push(
<Dropdown.Header key={`${name}:header`}>
{description}
</Dropdown.Header>
);
}
};
extrinsics.sections.sort(sortByName).forEach(({ description, hasPrivate, hasPublic, methods, name }) => {
addHeader(hasPublic, options.public, name, description);
addHeader(hasPrivate, options.private, name, description);
methods.sort(sortByName).forEach(({ description, name, params, isPrivate }) => {
const inputs = params.map(({ name }) => name).join(', ');
options[isPrivate ? 'private' : 'public'].push({
className: 'ui--InputExtrinsic-Item',
text: [
<div
className='ui--InputExtrinsic-Item-text'
key={`${name}:name`}
>
{description || name}
</div>,
<div
className='ui--InputExtrinsic-Item-call'
key={`${name}:call`}
>
{name}({inputs})
</div>
],
value: name
});
});
});
export default options;

View File

@ -0,0 +1,51 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
import type { Props } from '@polkadot/ui-react-app/Params/types';
import React from 'react';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import BaseAccount from '../Account';
export default class Account extends React.PureComponent<Props> {
account: rxjs$BehaviorSubject<Uint8Array>;
subscriptions: Array<rxjs$ISubscription>
constructor (props: Props) {
super(props);
this.account = new BehaviorSubject(new Uint8Array([]));
}
componentWillMount () {
this.subscriptions = [
this.account.subscribe((value: Uint8Array) =>
this.props.subject.next({
isValid: !!value && value.length === 32,
value
})
)
];
}
componentWillUnmount () {
this.subscriptions.forEach((s) =>
s.unsubscribe()
);
}
render (): React$Node {
const { isError, label } = this.props;
return (
<BaseAccount
isError={isError}
label={label}
subject={this.account}
/>
);
}
}

View File

@ -1,30 +0,0 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
import type { Props } from '../types';
import React from 'react';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import BaseAccount from '../../Account';
export default function Account ({ isError, label, subject }: Props): React$Node {
const account: rxjs$BehaviorSubject<Uint8Array> = new BehaviorSubject(new Uint8Array([]));
account.subscribe((value: Uint8Array) =>
subject.next({
isValid: !!(value && value.length),
value
})
);
return (
<BaseAccount
isError={isError}
label={label}
subject={account}
/>
);
}

View File

@ -1,32 +0,0 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
import type { EncodedParams } from '../../types';
import type { Props } from '../types';
import React from 'react';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import Extrinsic from '../../Extrinsic';
export default function Proposal ({ isError, label, subject }: Props): React$Node {
const extrinsic: rxjs$BehaviorSubject<EncodedParams> = new BehaviorSubject(({ isValid: false }: $Shape<EncodedParams>));
extrinsic.subscribe(({ data, isValid }: EncodedParams) =>
subject.next({
isValid,
value: data
})
);
return (
<Extrinsic
isError={isError}
isPrivate
label={label}
subject={extrinsic}
/>
);
}

View File

@ -0,0 +1,70 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
import type { Props as BaseProps } from '@polkadot/ui-react-app/Params/types';
import type { I18nProps } from '@polkadot/ui-react-app/types';
import type { EncodedParams } from '../types';
import React from 'react';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import Extrinsic from '../Extrinsic';
import translate from '../translate';
type Props = BaseProps & I18nProps;
class Proposal extends React.PureComponent<Props> {
extrinsic: rxjs$BehaviorSubject<EncodedParams>;
subscriptions: Array<rxjs$ISubscription>
constructor (props: Props) {
super(props);
this.extrinsic = new BehaviorSubject(({ isValid: false }: $Shape<EncodedParams>));
}
componentWillMount () {
this.subscriptions = [
this.extrinsic.subscribe(({ data, isValid }: EncodedParams) =>
this.props.subject.next({
isValid,
value: data
})
)
];
}
componentWillUnmount () {
this.subscriptions.forEach((s) =>
s.unsubscribe()
);
}
render (): React$Node {
const { isError, label, t } = this.props;
return (
<Extrinsic
isError={isError}
isPrivate
labelMethod={t('proposal.method', {
defaultValue: '{{label}} (extrinsic)',
replace: {
label
}
})}
labelSection={t('proposal.method', {
defaultValue: '{{label}} (section)',
replace: {
label
}
})}
subject={this.extrinsic}
/>
);
}
}
export default translate(Proposal);

View File

@ -1,43 +0,0 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
import type { Extrinsic$Type } from '@polkadot/extrinsics/types';
import Account from './Param/Account';
import Amount from './Param/Amount';
import Bool from './Param/Bool';
import Bytes from './Param/Bytes';
import Hash from './Param/Hash';
import Proposal from './Param/Proposal';
import Unknown from './Param/Unknown';
import VoteThreshold from './Param/VoteThreshold';
import Wasm from './Param/Wasm';
const Components = {
'AccountId': Account,
'Balance': Amount,
'BlockNumber': Amount,
'bool': Bool,
'Bytes': Bytes,
'Hash': Hash,
'MisbehaviorReport': Unknown,
'Proposal': Proposal,
'SessionKey': Unknown,
'u32': Amount,
'u64': Amount,
'VoteThreshold': VoteThreshold,
'Wasm': Wasm
};
export default function findComponent (type: Extrinsic$Type): React$ComponentType<*> {
if (Array.isArray(type)) {
// eslint-disable-next-line no-unused-vars
const [outer, inner] = type;
return findComponent(inner);
}
return Components[type];
}

View File

@ -3,52 +3,14 @@
// of the ISC license. See the LICENSE file for details.
// @flow
import type { Extrinsic } from '@polkadot/extrinsics/types';
import type { BaseProps, RawParam } from '../types';
import type { ComponentMap } from '@polkadot/ui-react-app/Params/types';
import './Params.css';
import Account from './Account';
import Proposal from './Proposal';
import React from 'react';
import translate from '../translate';
import findComponent from './findComponent';
import createSubjects from './subjects';
import typeToText from './typeToText';
type Props = BaseProps & {
subject: rxjs$BehaviorSubject<Array<RawParam>>,
value: Extrinsic;
const components: ComponentMap = {
'AccountId': Account,
'Proposal': Proposal
};
function Params ({ className, style, subject, value: { name, params } }: Props): React$Node {
if (!params || !params.length) {
return null;
}
const subjects = createSubjects(params, subject);
return (
<div
className={['extrinsics--Params', 'extrinsics--split', className].join(' ')}
style={style}
>
<div className='extrinsics--Params-Content'>
{params.map((value, index) => {
const Component = findComponent(value.type);
return (
<Component
className='extrinsics--Param'
key={`${name}:${value.name}:${index}`}
label={`${value.name}: ${typeToText(value.type)}`}
subject={subjects[index]}
value={value}
/>
);
})}
</div>
</div>
);
}
export default translate(Params);
export default components;

View File

@ -3,7 +3,8 @@
// of the ISC license. See the LICENSE file for details.
// @flow
import type { BaseProps, QueueTx } from '../types';
import type { I18nProps } from '@polkadot/ui-react-app/types';
import type { QueueTx } from '../types';
import React from 'react';
import { Trans } from 'react-i18next';
@ -13,7 +14,7 @@ import u8aToHexShort from '@polkadot/util/u8a/toHexShort';
import translate from '../translate';
type Props = BaseProps & {
type Props = I18nProps & {
value: QueueTx
};
@ -33,7 +34,7 @@ function Decoded ({ className, style, t, value: { data, extrinsic, index, public
<div className='expanded'>
<p>
<Trans i18nkey='decoded.short'>
You are about to sign a message from <span className='code'>{from}</span> calling <span className='code'>{extrinsic.name}</span> with an index of <span className='code'>{index.toString()}</span>
You are about to sign a message from <span className='code'>{from}</span> calling <span className='code'>{extrinsic.section}_{extrinsic.name}</span> with an index of <span className='code'>{index.toString()}</span>
</Trans>
</p>
<p>

View File

@ -4,7 +4,8 @@
// @flow
import type { ApiProps } from '@polkadot/rx-react/types';
import type { BaseProps, QueueTx } from '../types';
import type { I18nProps } from '@polkadot/ui-react-app/types';
import type { QueueTx } from '../types';
import './Signer.css';
@ -17,7 +18,7 @@ import translate from '../translate';
import Decoded from './Decoded';
import submitExtrinsic from './submit';
type Props = BaseProps & ApiProps & {
type Props = I18nProps & ApiProps & {
subject: rxjs$BehaviorSubject<QueueTx>,
value: QueueTx
};

View File

@ -6,12 +6,11 @@
import type { RxApiInterface } from '@polkadot/rx-api/types';
import type { QueueTx } from '../types';
import encodeCall from '@polkadot/extrinsics-codec/src/encode/call';
import encodeCall from '@polkadot/extrinsics-codec/encode/call';
import keyring from '@polkadot/ui-react-app/src/keyring';
import u8aConcat from '@polkadot/util/u8a/concat';
import u8aToHex from '@polkadot/util/u8a/toHex';
import keyring from '../keyring';
export default function submit (api: RxApiInterface, tx: QueueTx, subject: rxjs$BehaviorSubject<QueueTx>): Promise<void> {
const message = encodeCall(tx.publicKey, tx.index, tx.data);
const signature = keyring.getPair(tx.publicKey).sign(message);

View File

@ -4,7 +4,7 @@
// @flow
import type BN from 'bn.js';
import type { BareProps } from '../types';
import type { BareProps } from '@polkadot/ui-react-app/types';
import React from 'react';
import Label from 'semantic-ui-react/dist/es/elements/Label';
@ -17,22 +17,33 @@ type Props = BareProps & {
value: rxjs$BehaviorSubject<Uint8Array>
};
export default function Nonce ({ className, label, style, subject, t, value }: Props): React$Node {
const SenderNonce = withObservableParams(value)(RxNonce);
export default class Nonce extends React.PureComponent<Props> {
Nonce: React$ComponentType<*>;
return (
<div
className={['extrinsics--split', className].join(' ')}
style={style}
>
<div className='small'>
<Label>{label}</Label>
<SenderNonce
className='ui disabled dropdown selection'
classNameUpdated='hasUpdated'
subject={subject}
/>
constructor (props: Props) {
super(props);
// NOTE we basically get away with not checking updates since the parent is only created once
this.Nonce = withObservableParams(props.value)(RxNonce);
}
render (): React$Node {
const { className, label, style, subject } = this.props;
const Nonce = this.Nonce;
return (
<div
className={['ui--form', className].join(' ')}
style={style}
>
<div className='small'>
<Label>{label}</Label>
<Nonce
className='ui disabled dropdown selection'
subject={subject}
/>
</div>
</div>
</div>
);
);
}
}

View File

@ -10,6 +10,6 @@
}
.extrinsics--Submission-ButtonRow .button {
margin-right: 0.5rem;
margin-left: 0.5rem;
text-align: left;
}

View File

@ -3,14 +3,15 @@
// of the ISC license. See the LICENSE file for details.
// @flow
import type { BaseProps, QueueTx } from '../types';
import type { I18nProps } from '@polkadot/ui-react-app/types';
import type { QueueTx } from '../types';
import React from 'react';
import Button from 'semantic-ui-react/dist/es/elements/Button';
import translate from '../translate';
type Props = BaseProps & {
type Props = I18nProps & {
subject: rxjs$BehaviorSubject<QueueTx>,
value: QueueTx;
};

View File

@ -3,7 +3,9 @@
// of the ISC license. See the LICENSE file for details.
// @flow
import type { BaseProps, QueueTx } from '../types';
import type { I18nProps } from '@polkadot/ui-react-app/types';
import type { QueueTx } from '../types';
import type { Subjects } from './types';
import './Submission.css';
@ -17,43 +19,76 @@ import Nonce from './Nonce';
import Submit from './Submit';
import createSubjects from './subjects';
type Props = BaseProps & {
type Props = I18nProps & {
subject: rxjs$BehaviorSubject<QueueTx>
};
function Submission ({ className, subject, style, t }: Props): React$Node {
const subjects = createSubjects();
const Button = withObservable(subjects.call)(Submit);
class Submission extends React.PureComponent<Props> {
Submit: React$ComponentType<*>;
subjects: Subjects;
return (
<div
className={['extrinsics--Submission', className].join(' ')}
style={style}
>
<Account
label={t('display.sender', {
defaultValue: 'using the selected account'
})}
subject={subjects.sender}
/>
<Extrinsic
label={t('display.method', {
defaultValue: 'submit the following extrinsic'
})}
subject={subjects.method}
/>
<Nonce
label={t('display.nonce', {
defaultValue: 'with an index'
})}
subject={subjects.index}
value={subjects.sender}
/>
<div className='extrinsics--Submission-ButtonRow'>
<Button subject={subject} />
constructor (props: Props) {
super(props);
this.subjects = createSubjects();
this.Submit = withObservable(this.subjects.call)(Submit);
}
componentWillMount () {
this.subjects.method.subscribe(this.onChange);
this.subjects.sender.subscribe(this.onChange);
}
onChange = (): void => {
const publicKey = this.subjects.sender.getValue();
const message = this.subjects.method.getValue();
const index = this.subjects.index.getValue();
const isValid = !!(publicKey && publicKey.length && message && message.isValid);
this.subjects.call.next({
data: message.data,
extrinsic: message.extrinsic,
isValid,
index,
publicKey,
status: 'incomplete'
});
};
render (): React$Node {
const { className, subject, style, t } = this.props;
const { Submit, subjects } = this;
return (
<div
className={['extrinsics--Submission', className].join(' ')}
style={style}
>
<Account
label={t('display.sender', {
defaultValue: 'using the selected account'
})}
subject={subjects.sender}
/>
<Extrinsic
labelMethod={t('display.method', {
defaultValue: 'submit the following extrinsic'
})}
subject={subjects.method}
/>
<Nonce
label={t('display.nonce', {
defaultValue: 'with an index'
})}
subject={subjects.index}
value={subjects.sender}
/>
<div className='extrinsics--Submission-ButtonRow'>
<Submit subject={subject} />
</div>
</div>
</div>
);
);
}
}
export default translate(Submission);

View File

@ -4,47 +4,22 @@
// @flow
import type { EncodedParams, QueueTx } from '../types';
import type { Subjects } from './types';
import BN from 'bn.js';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
type Subjects = {
call: rxjs$BehaviorSubject<QueueTx>,
index: rxjs$BehaviorSubject<BN>,
method: rxjs$BehaviorSubject<EncodedParams>,
sender: rxjs$BehaviorSubject<Uint8Array>
};
import map from '@polkadot/extrinsics-substrate';
export default function createSubjects (): Subjects {
const subjects = {
return {
index: new BehaviorSubject(new BN(0)),
call: new BehaviorSubject(({
isValid: false
}: $Shape<QueueTx>)),
method: new BehaviorSubject(({
extrinsic: map.staking.methods.public.transfer,
isValid: false
}: $Shape<EncodedParams>)),
sender: new BehaviorSubject(new Uint8Array([]))
};
const onChange = (): void => {
const publicKey = subjects.sender.getValue();
const message = subjects.method.getValue();
const index = subjects.index.getValue();
const isValid = !!(publicKey && publicKey.length && message && message.isValid);
subjects.call.next({
data: message.data,
extrinsic: message.extrinsic,
isValid,
index,
publicKey,
status: 'incomplete'
});
};
subjects.method.subscribe(onChange);
subjects.sender.subscribe(onChange);
return subjects;
}

View File

@ -0,0 +1,14 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
import type BN from 'bn.js';
import type { EncodedParams, QueueTx } from '../types';
export type Subjects = {
call: rxjs$BehaviorSubject<QueueTx>,
index: rxjs$BehaviorSubject<BN>,
method: rxjs$BehaviorSubject<EncodedParams>,
sender: rxjs$BehaviorSubject<Uint8Array>
};

View File

@ -5,50 +5,3 @@
.extrinsics--App {
padding: 1em;
}
.extrinsics--full,
.extrinsics--split {
width: 100%;
}
.extrinsics--split {
display: flex;
flex-wrap: wrap;
flex-direction: row;
justify-content: flex-start;
align-items: stretch;
}
.extrinsics--split > div {
box-sizing: border-box;
min-width: 0;
width: 100%;
}
.extrinsics--split > div.full,
.extrinsics--split > div.large,
.extrinsics--split > div.medium,
.extrinsics--split > div.small {
padding-right: 0.5rem;
}
.extrinsics--split > div.full {
flex: 0 100%;
}
.extrinsics--split > div.large {
flex: 0 75%;
}
.extrinsics--split > div.medium {
flex: 0 50%;
}
.extrinsics--split > div.small {
flex: 0 25%;
}
.hasUpdated {
background: #ffffe0 !important;
transition: all 0.7s ease-in-out;
}

View File

@ -5,4 +5,4 @@
import { translate } from 'react-i18next';
export default translate(['extrinsics']);
export default translate(['extrinsics', 'ui']);

View File

@ -6,24 +6,6 @@
import type BN from 'bn.js';
import type { Extrinsic } from '@polkadot/extrinsics/types';
export type BareProps = {
className?: string,
style?: {
[string]: string
}
};
export type BaseProps = BareProps & {
t: I18Next$Translate
};
export type RawParam = {
// flowlint-next-line unclear-type:off
data?: any,
isValid: boolean,
value: mixed,
}
export type EncodedParams = {
data: Uint8Array,
extrinsic: Extrinsic,

View File

@ -0,0 +1 @@
# @polkadot/app-storage

View File

@ -1,8 +1,8 @@
{
"name": "@polkadot/extrinsics",
"name": "@polkadot/app-storage",
"version": "0.1.6",
"main": "index.js",
"repository": "https://github.com/polkadot-js/portal.git",
"repository": "https://github.com/polkadot-js/apps.git",
"author": "Jaco Greeff <jacogr@gmail.com>",
"license": "ISC",
"scripts": {
@ -10,8 +10,7 @@
"check": "stylelint 'src/**/*.css' && eslint src && flow check",
"test": "jest --coverage"
},
"dependencies": {
"@polkadot/util": "^0.19.4",
"babel-runtime": "^6.26.0"
"devDependencies": {
"@polkadot/ui-react-app": "^0.1.6"
}
}

View File

@ -0,0 +1,28 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
import type { I18nProps } from '@polkadot/ui-react-app/types';
import React from 'react';
import Queries from './Queries';
import Selection from './Selection';
import translate from './translate';
type Props = I18nProps & {};
function App ({ className, style, t }: Props): React$Node {
return (
<div
className={['storage--App', className].join(' ')}
style={style}
>
<Selection />
<Queries />
</div>
);
}
export default translate(App);

View File

@ -0,0 +1,61 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
import type { I18nProps } from '@polkadot/ui-react-app/types';
import type { StorageQuery } from '../types';
import React from 'react';
import Label from 'semantic-ui-react/dist/es/elements/Label';
import Div from '@polkadot/rx-react/Div';
import withStorage from '@polkadot/rx-react/with/storage';
import translate from '../translate';
import Remove from './Remove';
import cache from './cache';
import createTransform from './transform';
type Props = I18nProps & {
value: StorageQuery
};
function Query ({ className, style, value: { id, key, params } }: Props): React$Node {
const CachedQuery = (() => {
if (!cache[id]) {
const transform = createTransform(key);
cache[id] = withStorage(key, { params, transform })(
Div, { className: 'ui disabled dropdown selection' }
);
}
return cache[id];
})();
const inputs = Object
.keys(key.params || {})
// $FlowFixMe key.params exists
.map((name) => `${name}: ${key.params[name].type}`)
.join(', ');
return (
<div
className={['storage--Queries-Query', 'storage--actionrow', className].join(' ')}
style={style}
>
<div className='storage--actionrow-value'>
<Label>
{key.section}_{key.name}({inputs}): {key.type}
</Label>
<CachedQuery />
</div>
<div className='storage--actionrow-button'>
<Label>&nbsp;</Label>
<Remove value={id} />
</div>
</div>
);
}
export default translate(Query);

View File

@ -0,0 +1,46 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
import type { I18nProps } from '@polkadot/ui-react-app/types';
import React from 'react';
import Button from 'semantic-ui-react/dist/es/elements/Button';
import subjects from '../subjects';
import translate from '../translate';
import cache from './cache';
type Props = I18nProps & {
value: number;
};
function Remove ({ className, style, value }: Props): React$Node {
const onRemove = (): void => {
const current = subjects.queries.getValue();
delete cache[value];
subjects.queries.next(
current
.filter(({ id }) => id !== value)
.reduce((next, item) => {
next.push(item);
return next;
}, [])
);
};
return (
<Button
disabled={!value}
icon='close'
negative
onClick={onRemove}
/>
);
}
export default translate(Remove);

View File

@ -3,10 +3,6 @@
// of the ISC license. See the LICENSE file for details.
// @flow
export type BaseProps = {
className?: string,
style?: {
[string]: string
},
t: I18Next$Translate
};
const cache = {};
export default cache;

View File

@ -0,0 +1,42 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
import type { I18nProps } from '@polkadot/ui-react-app/types';
import type { StorageQuery } from '../types';
import React from 'react';
import withObservable from '@polkadot/rx-react/with/observable';
import subjects from '../subjects';
import translate from '../translate';
import Query from './Query';
type Props = I18nProps & {
value?: Array<StorageQuery>
};
function Queries ({ className, style, value }: Props): React$Node {
if (!value || !value.length) {
return null;
}
return (
<div
className={['storage--Queries', className].join(' ')}
style={style}
>
{value.map((query) => (
<Query
key={query.id}
value={query}
/>
))}
</div>
);
}
export default translate(
withObservable(subjects.queries)(Queries)
);

View File

@ -0,0 +1,33 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
import type BN from 'bn.js';
import type { StorageDef$Key } from '@polkadot/storage/types';
import u8aToHexShort from '@polkadot/util/u8a/toHexShort';
import isU8a from '@polkadot/util/is/u8a';
type Formatter = (value: boolean | BN | Date | Uint8Array) => string;
export default function transform ({ type }: StorageDef$Key): Formatter {
return (value: boolean | BN | Date | Uint8Array): string => {
if (typeof value === typeof true) {
return value
? 'Yes'
: 'No';
}
if (!value) {
return 'unknown';
}
if (isU8a(value)) {
// $FlowFixMe type has been determined
return u8aToHexShort(value, 256);
}
return value.toString();
};
}

View File

@ -0,0 +1,56 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
import type { StorageDef$Key } from '@polkadot/storage/types';
import type { I18nProps } from '@polkadot/ui-react-app/types';
import React from 'react';
import Button from 'semantic-ui-react/dist/es/elements/Button';
import withObservable from '@polkadot/rx-react/with/observable';
import subjects from '../subjects';
import translate from '../translate';
type Props = I18nProps & {
value: StorageDef$Key;
};
let id = 0;
function Add ({ className, style, value }: Props): React$Node {
const onAdd = (): void => {
if (!value) {
return;
}
const current = subjects.queries.getValue();
const next = [{
id: ++id,
key: value,
params: subjects.params.getValue().map((s) => s.getValue())
}];
subjects.queries.next(
current.reduce((next, item) => {
next.push(item);
return next;
}, next)
);
};
return (
<Button
disabled={!value}
icon='plus'
onClick={onAdd}
primary
/>
);
}
export default translate(
withObservable(subjects.next)(Add)
);

View File

@ -0,0 +1,44 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
import type { I18nProps } from '@polkadot/ui-react-app/types';
import React from 'react';
import Label from 'semantic-ui-react/dist/es/elements/Label';
import InputStorage from '@polkadot/ui-react-app/src/InputStorage';
import subjects from '../subjects';
import translate from '../translate';
import Add from './Add';
type Props = I18nProps & {};
function Selection ({ className, style, t }: Props): React$Node {
return (
<div
className={['storage--Selection', 'storage--actionrow', className].join(' ')}
style={style}
>
<div className='storage--actionrow-value'>
<div className='ui--form'>
<div className='full'>
<InputStorage
labelSection={t('selection.section', {
defaultValue: 'query storage area'
})}
subject={subjects.next}
/>
</div>
</div>
</div>
<div className='storage--actionrow-button'>
<Label>&nbsp;</Label>
<Add />
</div>
</div>
);
}
export default translate(Selection);

View File

@ -0,0 +1,25 @@
/* Copyright 2017-2018 Jaco Greeff
/* This software may be modified and distributed under the terms
/* of the ISC license. See the LICENSE file for details. */
.storage--App {
padding: 1em;
}
.storage--Queries {
margin-top: 1em;
}
.storage--actionrow {
display: flex;
}
.storage--actionrow-value {
flex: 1;
min-width: 0;
}
.storage--actionrow-button {
flex: 0;
padding-left: 0.5rem;
}

View File

@ -3,6 +3,8 @@
// of the ISC license. See the LICENSE file for details.
// @flow
// HACK: Only here because of CRA's lack of proper workspace + src/* support
import './index.css';
module.exports = require('./src');
import App from './App';
export default App;

View File

@ -0,0 +1,29 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
import type { StorageDef$Key } from '@polkadot/storage/types';
import type { StorageQuery } from './types';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import storage from '@polkadot/storage-substrate/keys';
type ValueSubject = rxjs$BehaviorSubject<*>;
type ValueSubjects = Array<ValueSubject>;
type Subjects = {
next: rxjs$BehaviorSubject<StorageDef$Key>,
params: rxjs$BehaviorSubject<ValueSubjects>,
queries: rxjs$BehaviorSubject<Array<StorageQuery>>
};
function createSubjects (): Subjects {
return {
next: new BehaviorSubject(storage.timestamp.keys.current),
params: new BehaviorSubject([]),
queries: new BehaviorSubject([])
};
}
export default createSubjects();

View File

@ -0,0 +1,8 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
import { translate } from 'react-i18next';
export default translate(['storage', 'ui']);

View File

@ -0,0 +1,12 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
import type { StorageDef$Key } from '@polkadot/storage/types';
export type StorageQuery = {
id: number,
key: StorageDef$Key,
params: Array<*>
}

View File

@ -4,7 +4,7 @@
"description": "An Apps portal into the Polkadot network",
"main": "index.js",
"homepage": ".",
"repository": "https://github.com/polkadot-js/portal.git",
"repository": "https://github.com/polkadot-js/apps.git",
"author": "Jaco Greeff <jacogr@gmail.com>",
"license": "ISC",
"scripts": {
@ -16,17 +16,8 @@
"devDependencies": {
"@polkadot/app-explorer": "^0.1.6",
"@polkadot/app-extrinsics": "^0.1.6",
"@polkadot/rx-react": "^0.4.7",
"@polkadot/ui-react": "^0.9.12",
"i18next": "^11.1.1",
"i18next-browser-languagedetector": "^2.2.0",
"i18next-xhr-backend": "^1.5.1",
"react": "^16.3.1",
"react-dom": "^16.3.1",
"react-i18next": "^7.5.1",
"react-remarkable": "^1.1.3",
"react-router-dom": "^4.2.2",
"semantic-ui-css": "^2.3.1",
"semantic-ui-react": "^0.79.1"
"@polkadot/app-storage": "^0.1.6",
"@polkadot/ui-react-app": "^0.1.6",
"react-remarkable": "^1.1.3"
}
}

View File

@ -2,13 +2,13 @@
/* This software may be modified and distributed under the terms
/* of the ISC license. See the LICENSE file for details. */
.portal--App {
.apps--App {
box-sizing: border-box;
display: flex;
height: 100%;
}
.portal--App-column {
.apps--App-column {
display: flex;
flex-direction: column;
height: 100%;

View File

@ -3,27 +3,27 @@
// of the ISC license. See the LICENSE file for details.
// @flow
import type { BaseProps } from '../types';
import type { I18nProps } from '@polkadot/ui-react-app/types';
import './App.css';
import React from 'react';
import translate from '../translate';
import Connecting from '../Connecting';
import Content from '../Content';
import SideBar from '../SideBar';
import translate from '../translate';
type Props = BaseProps & {};
type Props = I18nProps & {};
function App ({ className, style }: Props): React$Node {
return (
<div
className={['portal--App', className].join(' ')}
className={['apps--App', className].join(' ')}
style={style}
>
<SideBar className='portal--App-column' />
<Content className='portal--App-column' />
<SideBar className='apps--App-column' />
<Content className='apps--App-column' />
<Connecting />
</div>
);

View File

@ -2,15 +2,18 @@
/* This software may be modified and distributed under the terms
/* of the ISC license. See the LICENSE file for details. */
.portal--Connecting {
.apps--Connecting {
bottom: 0;
left: 0;
position: fixed;
right: 0;
text-align: center;
}
.portal--Connecting-text {
.apps--Connecting-text {
background: red;
bottom: 0;
color: white;
display: inline-block;
line-height: 1.5em;
padding: 1em 2em;
position: absolute;
}

View File

@ -3,7 +3,7 @@
// of the ISC license. See the LICENSE file for details.
// @flow
import type { BaseProps } from '../types';
import type { I18nProps } from '@polkadot/ui-react-app/types';
import './Connecting.css';
@ -12,7 +12,7 @@ import withApiCall from '@polkadot/rx-react/with/apiCall';
import translate from '../translate';
type Props = BaseProps & {
type Props = I18nProps & {
value: boolean
};
@ -21,12 +21,13 @@ function Connecting ({ className, style, value, t }: Props): React$Node {
return null;
}
// 'ui inverted page modals dimmer transition visible active'
return (
<div
className={['portal--Connecting', 'ui inverted page modals dimmer transition visible active', className].join(' ')}
className={['apps--Connecting', className].join(' ')}
style={style}
>
<div className='portal--Connecting-text'>
<div className='apps--Connecting-text'>
{t('connecting.disconnected', {
defaultValue: 'You are disconnected from the node. Check that your node is running and that the Websocket endpoint is reachable.'
})}
@ -36,7 +37,7 @@ function Connecting ({ className, style, value, t }: Props): React$Node {
}
export default translate(
withApiCall({
method: 'isConnected'
})(Connecting)
withApiCall({ method: 'isConnected' })(
Connecting
)
);

View File

@ -2,12 +2,12 @@
/* This software may be modified and distributed under the terms
/* of the ISC license. See the LICENSE file for details. */
.portal--Content {
.apps--Content {
height: 100%;
width: 100%;
}
.portal--Content-Frame {
.apps--Content-Frame {
border: none;
box-sizing: border-box;
height: 100%;

View File

@ -4,7 +4,7 @@
// @flow
import type { Location } from 'react-router-dom';
import type { BaseProps } from '../types';
import type { I18nProps } from '@polkadot/ui-react-app/types';
import './Content.css';
@ -14,7 +14,7 @@ import { withRouter } from 'react-router';
import routing from '../routing';
import translate from '../translate';
type Props = BaseProps & {
type Props = I18nProps & {
location: Location
};
@ -23,11 +23,11 @@ function Content ({ className, location, style }: Props): React$Node {
return (
<div
className={['portal--Content', className].join(' ')}
className={['apps--Content', className].join(' ')}
style={style}
>
<iframe
className='portal--Content-Frame'
className='apps--Content-Frame'
src={`index.html?app=${app}`}
title={app}
/>

View File

@ -2,6 +2,6 @@
/* This software may be modified and distributed under the terms
/* of the ISC license. See the LICENSE file for details. */
.portal--NotFound {
.apps--NotFound {
color: red;
}

View File

@ -3,7 +3,7 @@
// of the ISC license. See the LICENSE file for details.
// @flow
import type { BaseProps } from '../types';
import type { I18nProps } from '@polkadot/ui-react-app/types';
import './NotFound.css';
@ -11,10 +11,12 @@ import React from 'react';
import translate from '../translate';
function NotFound ({ className, style, t }: BaseProps): React$Node {
type Props = I18nProps & {};
function NotFound ({ className, style, t }: Props): React$Node {
return (
<div
className={['portal--NotFound', className].join(' ')}
className={['apps--NotFound', className].join(' ')}
style={style}
>
{t('notfound.error', {

View File

@ -2,12 +2,12 @@
/* This software may be modified and distributed under the terms
/* of the ISC license. See the LICENSE file for details. */
.portal--SideBar-Item {}
.apps--SideBar-Item {}
.portal--SideBar-Item-NavLink {
.apps--SideBar-Item-NavLink {
white-space: nowrap;
}
.portal--SideBar-Item-NavLink-active {
.apps--SideBar-Item-NavLink-active {
color: inherit;
}

View File

@ -3,7 +3,8 @@
// of the ISC license. See the LICENSE file for details.
// @flow
import type { BaseProps, Route } from '../types';
import type { I18nProps } from '@polkadot/ui-react-app/types';
import type { Route } from '../types';
import './Item.css';
@ -12,23 +13,20 @@ import { NavLink } from 'react-router-dom';
import Icon from 'semantic-ui-react/dist/es/elements/Icon';
import Menu from 'semantic-ui-react/dist/es/collections/Menu';
type Props = BaseProps & Route & {};
export default function Item ({ className, i18n, icon, isExact, name, path, style, t }: Props): React$Node {
// flowlint-next-line sketchy-null-string:off
const to = path || `/${name}`;
type Props = I18nProps & Route & {};
export default function Item ({ className, i18n, icon, isExact, name, path = '', style, t }: Props): React$Node {
return (
<Menu.Item
className={['portal--SideBar-Item', className].join(' ')}
className={['apps--SideBar-Item', className].join(' ')}
name={name}
style={style}
>
<NavLink
activeClassName='portal--SideBar-Item-NavLink-active'
className='portal--SideBar-Item-NavLink'
activeClassName='apps--SideBar-Item-NavLink-active'
className='apps--SideBar-Item-NavLink'
exact={isExact}
to={to}
to={path || `/${name}`}
>
<Icon name={icon} /> {t(`sidebar.${name}`, i18n)}
</NavLink>

View File

@ -2,7 +2,7 @@
/* This software may be modified and distributed under the terms
/* of the ISC license. See the LICENSE file for details. */
.portal--SideBar {
.apps--SideBar {
flex-shrink: 0;
min-width: 12em;
padding: 0.75em;

View File

@ -3,7 +3,7 @@
// of the ISC license. See the LICENSE file for details.
// @flow
import type { BaseProps } from '../types';
import type { I18nProps } from '@polkadot/ui-react-app/types';
import './SideBar.css';
@ -14,12 +14,12 @@ import routing from '../routing';
import translate from '../translate';
import Item from './Item';
type Props = BaseProps & {};
type Props = I18nProps & {};
function SideBar ({ className, style, t }: Props): React$Node {
return (
<div
className={['portal--SideBar', className].join(' ')}
className={['apps--SideBar', className].join(' ')}
style={style}
>
<Menu
@ -27,11 +27,12 @@ function SideBar ({ className, style, t }: Props): React$Node {
vertical
>
{
routing.routes.map((props) => (
routing.routes.map((route) => (
<Item
key={props.name}
key={route.name}
t={t}
{...props}
// flowlint-next-line inexact-spread:off
{...route}
/>
))
}

View File

@ -3,24 +3,14 @@
// of the ISC license. See the LICENSE file for details.
// @flow
import 'semantic-ui-css/semantic.min.css';
import './semantic.css';
import './index.css';
import createApp from '@polkadot/ui-react-app/src';
import React from 'react';
import ReactDOM from 'react-dom';
import { I18nextProvider } from 'react-i18next';
import { HashRouter } from 'react-router-dom';
import Api from '@polkadot/rx-react/Api';
import i18n from './i18n';
import Portal from './App';
import App from './App';
import NotFound from './NotFound';
import routing from './routing';
import urlParams from './urlParams';
const Component = (() => {
createApp((() => {
const { app } = urlParams();
if (app) {
@ -31,17 +21,5 @@ const Component = (() => {
: NotFound;
}
return Portal;
})();
ReactDOM.render(
<Api>
<I18nextProvider i18n={i18n}>
<HashRouter>
<Component />
</HashRouter>
</I18nextProvider>
</Api>,
// flowlint-next-line unclear-type:off
((document.getElementById('root'): any): Element)
);
return App;
})());

View File

@ -10,10 +10,11 @@ import explorer from './explorer';
import extrinsics from './extrinsics';
// import home from './home';
// import settings from './settings';
import storage from './storage';
export default ({
default: 'explorer',
routes: [].concat(
explorer, extrinsics
explorer, extrinsics, storage
)
}: Routing);

View File

@ -0,0 +1,21 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
import type { Routes } from '../types';
import Storage from '@polkadot/app-storage/src';
export default ([
{
component: Storage,
i18n: {
defaultValue: 'Storage'
},
icon: 'database',
isExact: false,
isHidden: false,
name: 'storage'
}
]: Routes);

View File

@ -5,4 +5,4 @@
import { translate } from 'react-i18next';
export default translate(['portal']);
export default translate(['apps', 'ui']);

View File

@ -3,26 +3,6 @@
// of the ISC license. See the LICENSE file for details.
// @flow
import type { RxApiInterface } from '@polkadot/rx-api/types';
export type BaseProps = {
className?: string,
style?: {
[string]: string
},
t: I18Next$Translate
};
export type BaseContext = {
api: RxApiInterface,
// TODO: Set the correct/full type
router: {
route: {
location: Location
}
}
};
export type Route = {
component: React$StatelessFunctionalComponent<*>,
i18n: I18Next$Translate$Config,

View File

@ -1 +0,0 @@
# @polkadot/extrinsics-codec

View File

@ -1,21 +0,0 @@
{
"name": "@polkadot/extrinsics-codec",
"version": "0.1.6",
"main": "index.js",
"repository": "https://github.com/polkadot-js/portal.git",
"author": "Jaco Greeff <jacogr@gmail.com>",
"license": "ISC",
"scripts": {
"build": "polkadot-dev-build-babel",
"check": "stylelint 'src/**/*.css' && eslint src && flow check",
"test": "jest --coverage"
},
"devDependencies": {
"@polkadot/extrinsics": "^0.1.6"
},
"dependencies": {
"@polkadot/util": "^0.19.4",
"babel-runtime": "^6.26.0",
"bn.js": "^4.11.8"
}
}

View File

@ -1,17 +0,0 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
import type BN from 'bn.js';
const bnToU8a = require('@polkadot/util/bn/toU8a');
const u8aConcat = require('@polkadot/util/u8a/concat');
module.exports = function encodeCall (publicKey: Uint8Array, nonce: number | BN, data: Uint8Array): Uint8Array {
return u8aConcat(
publicKey,
bnToU8a(nonce, 64, true),
data
);
};

View File

@ -1,21 +0,0 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
import type { Extrinsic } from '@polkadot/extrinsics/types';
const u8aConcat = require('@polkadot/util/u8a/concat');
const encodeParams = require('./params');
module.exports = function encodeExtrinsic (extrinsic: Extrinsic, values?: Array<mixed>): Uint8Array {
if (!extrinsic) {
return new Uint8Array([]);
}
return u8aConcat(
extrinsic.index,
encodeParams(extrinsic.params, values)
);
};

View File

@ -1,18 +0,0 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
import type BN from 'bn.js';
import type { Extrinsic } from '@polkadot/extrinsics/types';
const encodeCall = require('./call');
const encodeExtrinsic = require('./extrinsic');
module.exports = function encode (extrinsic: Extrinsic, publicKey: Uint8Array, nonce: number | BN, values?: Array<mixed>): Uint8Array {
return encodeCall(
publicKey,
nonce,
encodeExtrinsic(extrinsic, values)
);
};

View File

@ -1,32 +0,0 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
import type { Extrinsic$Param } from '@polkadot/extrinsics/types';
const u8aConcat = require('@polkadot/util/u8a/concat');
const bnToU8a = require('@polkadot/util/bn/toU8a');
const encodeType = require('./type');
// flowlint-next-line unclear-type:off
module.exports = function encodeParam (param: Extrinsic$Param, value: any): Uint8Array {
if (Array.isArray(param.type)) {
const [outer, inner] = param.type;
switch (outer) {
case 'Array':
return u8aConcat(
bnToU8a((value: Array<*>).length, 32, true),
u8aConcat.apply(null, (value: Array<*>).map((v) =>
encodeType(inner, v)
))
);
default:
return encodeType(inner, value);
}
}
return encodeType(param.type, value);
};

View File

@ -1,16 +0,0 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
import type { Extrinsic$Params } from '@polkadot/extrinsics/types';
const u8aConcat = require('@polkadot/util/u8a/concat');
const encodeParam = require('./param');
module.exports = function encodeParams (params: Extrinsic$Params, values?: Array<mixed> = []): Uint8Array {
return u8aConcat.apply(null, params.map((param, index) => {
return encodeParam(param, values[index]);
}));
};

View File

@ -1,47 +0,0 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
import type { Extrinsic$TypeName } from '@polkadot/extrinsics/types';
const bnToU8a = require('@polkadot/util/bn/toU8a');
const u8aToU8a = require('@polkadot/util/u8a/toU8a');
// flowlint-next-line unclear-type:off
module.exports = function encodeType (type: Extrinsic$TypeName, value: any): Uint8Array {
try {
switch (type) {
case 'AccountId':
return value;
case 'Balance':
case 'BlockNumber':
case 'u64':
return bnToU8a(value, 64, true);
case 'Bytes':
case 'Hash':
return u8aToU8a(value);
case 'bool':
return bnToU8a(value ? 1 : 0, 8, true);
case 'Proposal':
return u8aToU8a(value);
case 'u32':
return bnToU8a(value, 32, true);
case 'VoteThreshold':
return bnToU8a(value || 0, 8, true);
default:
return value;
}
} catch (error) {
console.error(error, 'with', value, 'encoded with', type);
throw error;
}
};

View File

@ -1 +0,0 @@
# @polkadot/extrinsics

View File

@ -1,17 +0,0 @@
{
"name": "@polkadot/extrinsics-polkadot",
"version": "0.1.6",
"main": "index.js",
"repository": "https://github.com/polkadot-js/portal.git",
"author": "Jaco Greeff <jacogr@gmail.com>",
"license": "ISC",
"scripts": {
"build": "polkadot-dev-build-babel",
"check": "stylelint 'src/**/*.css' && eslint src && flow check",
"test": "jest --coverage"
},
"dependencies": {
"@polkadot/extrinsics": "^0.1.6",
"babel-runtime": "^6.26.0"
}
}

View File

@ -1,30 +0,0 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
import type { ExtrinsicsBaseSection } from '@polkadot/extrinsics/types';
module.exports = ({
description: 'Consensus',
methods: {
public: {
reportMisbehavior: {
description: 'Report misbehavior',
index: 0,
params: {
report: { type: 'MisbehaviorReport' }
}
}
},
private: {
setCode: {
description: 'Set new code',
index: 0,
params: {
code: { type: 'Wasm' }
}
}
}
}
}: ExtrinsicsBaseSection);

View File

@ -1,85 +0,0 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
import type { ExtrinsicsBaseSection } from '@polkadot/extrinsics/types';
module.exports = ({
description: 'Council',
methods: {
public: {
setApprovals: {
description: 'Set approvals',
index: 0,
params: {
votes: { type: ['Array', 'bool'] },
index: { type: 'u32' }
}
},
reapInactiveVoter: {
description: 'Remove insactive voter',
index: 1,
params: {
signedIndex: { type: 'u32' },
who: { type: 'AccountId' },
whoIndex: { type: 'u32' },
assumedVoteIndex: { type: 'u32' }
}
},
retractVoter: {
description: 'Retract voter',
index: 2,
params: {
index: { type: 'u32' }
}
},
submitCandidacy: {
description: 'Submit candidacy',
index: 3,
params: {
slot: { type: 'u32' }
}
},
presentWinner: {
description: 'Present winner',
index: 4,
params: {
candidate: { type: 'AccountId' },
total: { type: 'Balance' },
index: { type: 'u32' }
}
}
},
private: {
setDesiredSeats: {
description: 'Set desired seats',
index: 0,
params: {
count: { type: 'u32' }
}
},
removeMember: {
description: 'Remove member',
index: 1,
params: {
member: { type: 'AccountId' }
}
},
setPresentationDuration: {
description: 'Set presentation duration',
index: 2,
params: {
duration: { type: 'u64' }
}
},
setTermDuration: {
description: 'Set term duration',
index: 3,
params: {
duration: { type: 'u64' }
}
}
}
}
}: ExtrinsicsBaseSection);

View File

@ -1,52 +0,0 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
import type { ExtrinsicsBaseSection } from '@polkadot/extrinsics/types';
module.exports = ({
description: 'Council Voting',
methods: {
public: {
propose: {
description: 'Propose',
index: 0,
params: {
proposal: { type: 'Proposal' }
}
},
vote: {
description: 'Vote',
index: 1,
params: {
proposal: { type: 'Hash' },
approve: { type: 'bool' }
}
},
veto: {
description: 'Veto',
index: 2,
params: {
proposal: { type: 'Hash' }
}
}
},
private: {
setCooloffPeriod: {
description: 'Set cooloff period',
index: 0,
params: {
blocks: { type: 'BlockNumber' }
}
},
setVotingPeriod: {
description: 'Set voting period',
index: 1,
params: {
blocks: { type: 'BlockNumber' }
}
}
}
}
}: ExtrinsicsBaseSection);

View File

@ -1,54 +0,0 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
import type { ExtrinsicsBaseSection } from '@polkadot/extrinsics/types';
module.exports = ({
description: 'Democracy',
methods: {
public: {
propose: {
description: 'Propose',
index: 0,
params: {
proposal: { type: 'Proposal' },
value: { type: 'Balance' }
}
},
second: {
description: 'Second',
index: 1,
params: {
proposal: { type: 'u32' }
}
},
vote: {
description: 'Vote',
index: 2,
params: {
referendumIndex: { type: 'u32' },
vote: { type: 'bool' }
}
}
},
private: {
startReferendum: {
description: 'Start referendum',
index: 0,
params: {
proposal: { type: 'Proposal' },
voteThreshold: { type: 'VoteThreshold' }
}
},
cancelReferendum: {
description: 'Cancel referendum',
index: 1,
params: {
referendumIndex: { type: 'u32' }
}
}
}
}
}: ExtrinsicsBaseSection);

View File

@ -1,26 +0,0 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
import type { ExtrinsicsBaseMap } from '@polkadot/extrinsics/types';
const init = require('@polkadot/extrinsics');
const consensus = require('./consensus');
const council = require('./council');
const councilVoting = require('./councilVoting');
const democracy = require('./democracy');
const session = require('./session');
const staking = require('./staking');
const map: ExtrinsicsBaseMap = {
consensus,
council,
councilVoting,
democracy,
session,
staking
};
module.exports = init(map);

View File

@ -1,35 +0,0 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
import type { ExtrinsicsBaseSection } from '@polkadot/extrinsics/types';
module.exports = ({
description: 'Session',
methods: {
public: {
setKey: {
description: 'Set session key',
index: 0,
params: {
key: { type: 'SessionKey' }
}
}
},
private: {
setLength: {
description: 'Set session length',
index: 0,
params: {
length: { type: 'u64' }
}
},
forceNewSession: {
description: 'Force new session',
index: 1,
params: {}
}
}
}
}: ExtrinsicsBaseSection);

View File

@ -1,60 +0,0 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
import type { ExtrinsicsBaseSection } from '@polkadot/extrinsics/types';
module.exports = ({
description: 'Staking',
methods: {
public: {
transfer: {
description: 'Transfer',
index: 0,
params: {
recipient: { type: 'AccountId' },
value: { type: 'Balance', options: { minValue: 1 } }
}
},
stake: {
description: 'Stake',
index: 1,
params: {}
},
unstake: {
description: 'Unstake',
index: 2,
params: {}
}
},
private: {
setSessionsPerEra: {
description: 'Set sessions per era',
index: 0,
params: {
sessions: { type: 'u64' }
}
},
setBondingDuration: {
description: 'Set bonding duration',
index: 1,
params: {
duration: { type: 'u64' }
}
},
setValidatorCount: {
description: 'Set validator count',
index: 2,
params: {
count: { type: 'u32' }
}
},
forceNewEra: {
description: 'Force new era',
index: 3,
params: {}
}
}
}
}: ExtrinsicsBaseSection);

View File

@ -1,15 +0,0 @@
ISC License (ISC)
Copyright 2017-2018 Jaco Greeff <jacogr@gmail.com>
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.

View File

@ -1 +0,0 @@
# @polkadot/extrinsics

View File

@ -1,46 +0,0 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
import type { Extrinsic, Extrinsics, ExtrinsicsBaseMap, ExtrinsicSectionName, ExtrinsicsMap, ExtrinsicSection } from './types';
const assert = require('@polkadot/util/assert');
const expandSection = require('./section');
// NOTE: Order here is important, counts as an index
const BASIC_KEYS: Array<ExtrinsicSectionName> = ['consensus', 'session', 'staking', 'democracy', 'council', 'councilVoting'];
module.exports = function init (baseMap: ExtrinsicsBaseMap): Extrinsics {
const map: ExtrinsicsMap = {};
const get = (method: string): Extrinsic => {
const extrinsic = map[method];
assert(extrinsic, `Unable to retrieve extrinsic with name '${method}'`);
return extrinsic;
};
const sections: Array<ExtrinsicSection> = BASIC_KEYS.reduce((sections: Array<ExtrinsicSection>, sectionName: ExtrinsicSectionName, sectionIndex: number) => {
const sectionSource = baseMap[sectionName];
if (sectionSource) {
const section = expandSection(sectionSource, sectionName, sectionIndex);
section.methods.forEach((method) => {
map[method.name] = method;
});
sections.push(section);
}
return sections;
}, []);
return {
get,
sections
};
};

View File

@ -1,35 +0,0 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
import type { Extrinsic, ExtrinsicsBaseSection, ExtrinsicSectionName } from './types';
const bnToU8a = require('@polkadot/util/bn/toU8a');
const u8aConcat = require('@polkadot/util/u8a/concat');
const expandParams = require('./params');
const TYPES = ['private', 'public'];
module.exports = function expandMethods (sectionSource: ExtrinsicsBaseSection, sectionName: ExtrinsicSectionName, sectionIndex: Uint8Array): Array<Extrinsic> {
const [priMethods, pubMethods] = TYPES.map((type) => {
const isPrivate = type === 'private';
const methods = sectionSource.methods[type];
const methodNames = Object.keys(methods);
return methodNames.map((name: string): Extrinsic => {
const { description, index, params } = methods[name];
return {
description,
index: u8aConcat(sectionIndex, bnToU8a(index, 8)),
isPrivate,
name: `${sectionName}_${name}`,
params: expandParams(params)
};
});
});
return [].concat(priMethods, pubMethods);
};

View File

@ -1,19 +0,0 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
import type { ExtrinsicBase$Params, Extrinsic$Param, Extrinsic$Params } from './types';
module.exports = function expandParams (base: ExtrinsicBase$Params): Extrinsic$Params {
const paramNames = Object.keys(base);
return paramNames.map((name: string): Extrinsic$Param => {
const source = base[name];
return {
...source,
name
};
});
};

View File

@ -1,23 +0,0 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
import type { ExtrinsicSectionName, ExtrinsicsBaseSection, ExtrinsicSection } from './types';
const bnToU8a = require('@polkadot/util/bn/toU8a');
const expandMethods = require('./methods');
module.exports = function expandSection (sectionSource: ExtrinsicsBaseSection, name: ExtrinsicSectionName, sectionIndex: number): ExtrinsicSection {
const index = bnToU8a(sectionIndex, 8);
return {
description: sectionSource.description || name,
hasPrivate: !!Object.keys(sectionSource.methods.private).length,
hasPublic: !!Object.keys(sectionSource.methods.public).length,
index,
methods: expandMethods(sectionSource, name, index),
name
};
};

View File

@ -1,84 +0,0 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
export type Extrinsic$TypeName = 'AccountId' | 'Balance' | 'BlockNumber' | 'bool' | 'Bytes' | 'Hash' | 'MisbehaviorReport' | 'Proposal' | 'SessionKey' | 'u32' | 'u64' | 'VoteThreshold' | 'Wasm';
export type Extrinsic$Type =
Extrinsic$TypeName |
['Array', Extrinsic$TypeName];
export type ExtrinsicBase$Param = {
options?: {
initValue?: mixed,
minValue?: mixed,
maxValue?: mixed
},
type: Extrinsic$Type
};
export type ExtrinsicBase$Params = {
[string]: ExtrinsicBase$Param
};
export type ExtrinsicBase = {
description: string,
index: number,
params: ExtrinsicBase$Params
}
export type ExtrinsicSectionName = 'consensus' | 'council' | 'councilVoting' | 'democracy' | 'session' | 'staking';
export type ExtrinsicsBaseSection = {
description: string,
methods: {
private: {
[string]: ExtrinsicBase
},
public: {
[string]: ExtrinsicBase
}
}
}
export type ExtrinsicsBaseMap = {
[ExtrinsicSectionName]: ExtrinsicsBaseSection
};
export type Extrinsic$Param = {
name: string,
options?: {
initValue?: mixed,
minValue?: mixed,
maxValue?: mixed
},
type: Extrinsic$Type
};
export type Extrinsic$Params = Array<Extrinsic$Param>;
export type Extrinsic = {
description: string,
index: Uint8Array,
isPrivate: boolean,
name: string,
params: Extrinsic$Params
};
export type ExtrinsicSection = {
description: string,
hasPrivate: boolean,
hasPublic: boolean,
index: Uint8Array,
methods: Array<Extrinsic>,
name: ExtrinsicSectionName
};
export type Extrinsics = {
sections: Array<ExtrinsicSection>,
get: (sectionMethod: string) => Extrinsic
}
export type ExtrinsicsMap = {
[string]: Extrinsic
};

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