// Copyright 2017-2019 @polkadot/app-storage 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 { StorageEntryPromise } from '@polkadot/api/types'; import { I18nProps } from '@polkadot/react-components/types'; import { QueryTypes, StorageModuleQuery } from './types'; import React from 'react'; import styled from 'styled-components'; import { Compact } from '@polkadot/types'; import { Button, Labelled } from '@polkadot/react-components'; import { withCallDiv } from '@polkadot/react-api'; import valueToText from '@polkadot/react-params/valueToText'; import { isU8a, u8aToHex, u8aToString } from '@polkadot/util'; import translate from './translate'; import { RenderFn, DefaultProps, ComponentRenderer } from '@polkadot/react-api/with/types'; import { ConstValue } from '@polkadot/react-components/InputConsts/types'; interface Props extends I18nProps { onRemove: (id: number) => void; value: QueryTypes; } interface State { inputs?: React.ReactNode[]; Component?: React.ComponentType<{}>; spread: Record; } interface CacheInstance { Component: React.ComponentType; render: RenderFn; refresh: (swallowErrors: boolean, contentShorten: boolean) => React.ComponentType; } const cache: CacheInstance[] = []; class Query extends React.PureComponent { public state: State = { spread: {} }; public static getCachedComponent (query: QueryTypes): CacheInstance { const { id, isConst, key, params = [] } = query as StorageModuleQuery; if (!cache[id]) { let renderHelper; let type: string; if (isConst) { const { meta, method, section } = key as unknown as ConstValue; renderHelper = withCallDiv(`consts.${section}.${method}`); type = meta.type.toString(); } else { const values: any[] = params.map(({ value }): any => value); // render function to create an element for the query results which is plugged to the api renderHelper = withCallDiv('subscribe', { paramName: 'params', paramValid: true, params: [key, ...values] }); type = key.creator.meta ? key.creator.meta.type.toString() : 'Data'; } const defaultProps = { className: 'ui--output' }; const Component = renderHelper( // By default we render a simple div node component with the query results in it (value: any): React.ReactNode => valueToText(type, value, true, true), defaultProps ); cache[query.id] = Query.createComponent(type, Component, defaultProps, renderHelper); } return cache[id]; } public static createComponent (type: string, Component: React.ComponentType, defaultProps: DefaultProps, renderHelper: ComponentRenderer): { Component: React.ComponentType; render: (createComponent: RenderFn) => React.ComponentType; refresh: (swallowErrors: boolean, contentShorten: boolean) => React.ComponentType } { return { Component, // In order to replace the default component during runtime we can provide a RenderFn to create a new 'plugged' component render: (createComponent: RenderFn): React.ComponentType => { return renderHelper(createComponent, defaultProps); }, // In order to modify the parameters which are used to render the default component, we can use this method refresh: (swallowErrors: boolean, contentShorten: boolean): React.ComponentType => { return renderHelper( (value: any): React.ReactNode => valueToText(type, value, swallowErrors, contentShorten), defaultProps ); } }; } public static getDerivedStateFromProps ({ value }: Props): Pick { const Component = Query.getCachedComponent(value).Component; const inputs: React.ReactNode[] = isU8a(value.key) ? [] // FIXME We need to render the actual key params // const { key, params } = value; // const inputs = key.params.map(({ name, type }, index) => ( // // {name}={valueToText(type, params[index].value)} // // )); : []; return { Component, inputs }; } public render (): React.ReactNode { const { className, value } = this.props; const { Component } = this.state; const { isConst, key } = value; const type = isConst ? (key as unknown as ConstValue).meta.type.toString() : isU8a(key) ? 'Data' : ( (key as StorageEntryPromise).creator.meta.modifier.isOptional ? `Option<${(key as StorageEntryPromise).creator.meta.type}>` : (key as StorageEntryPromise).creator.meta.type.toString() ); if (!Component) { return null; } return (
{this.keyToName(isConst, key)}: {type}
} >
{this.renderButtons()}
); } private renderButtons (): React.ReactNode { const { id, key } = this.props.value as StorageModuleQuery; const buttons = [