mirror of
https://github.com/pezkuwichain/pezkuwi-apps.git
synced 2026-04-26 19:57:57 +00:00
feat: initial Pezkuwi Apps rebrand from polkadot-apps
Rebranded terminology: - Polkadot → Pezkuwi - Kusama → Dicle - Westend → Zagros - Rococo → PezkuwiChain - Substrate → Bizinikiwi - parachain → teyrchain Custom logos with Kurdistan brand colors (#e6007a → #86e62a): - bizinikiwi-hexagon.svg - sora-bizinikiwi.svg - hezscanner.svg - heztreasury.svg - pezkuwiscan.svg - pezkuwistats.svg - pezkuwiassembly.svg - pezkuwiholic.svg
This commit is contained in:
@@ -0,0 +1,227 @@
|
||||
// Copyright 2017-2025 @pezkuwi/app-storage authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { QueryableStorageEntry } from '@pezkuwi/api/types';
|
||||
import type { ComponentRenderer, DefaultProps, RenderFn } from '@pezkuwi/react-api/hoc/types';
|
||||
import type { ConstValue } from '@pezkuwi/react-components/InputConsts/types';
|
||||
import type { Option, Raw } from '@pezkuwi/types';
|
||||
import type { Registry } from '@pezkuwi/types/types';
|
||||
import type { QueryTypes, StorageModuleQuery } from './types.js';
|
||||
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
|
||||
import { withCallDiv } from '@pezkuwi/react-api/hoc';
|
||||
import { Button, Labelled, styled } from '@pezkuwi/react-components';
|
||||
import { useApi } from '@pezkuwi/react-hooks';
|
||||
import valueToText from '@pezkuwi/react-params/valueToText';
|
||||
import { getSiName } from '@pezkuwi/types/metadata/util';
|
||||
import { unwrapStorageType } from '@pezkuwi/types/util';
|
||||
import { compactStripLength, isU8a, u8aToHex, u8aToString } from '@pezkuwi/util';
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
onRemove: (id: number) => void;
|
||||
value: QueryTypes;
|
||||
}
|
||||
|
||||
interface CacheInstance {
|
||||
Component: React.ComponentType<any>;
|
||||
render: RenderFn;
|
||||
refresh: (swallowErrors: boolean) => React.ComponentType<any>;
|
||||
}
|
||||
|
||||
const cache: CacheInstance[] = [];
|
||||
|
||||
function keyToName (isConst: boolean, _key: Uint8Array | QueryableStorageEntry<'promise'> | ConstValue): string {
|
||||
if (isConst) {
|
||||
const key = _key as ConstValue;
|
||||
|
||||
return `const ${key.section}.${key.method}`;
|
||||
}
|
||||
|
||||
const key = _key as Uint8Array | QueryableStorageEntry<'promise'>;
|
||||
|
||||
if (isU8a(key)) {
|
||||
const [, u8a] = compactStripLength(key);
|
||||
|
||||
// If the string starts with `:`, handle it as a pure string
|
||||
return u8a[0] === 0x3a
|
||||
? u8aToString(u8a)
|
||||
: u8aToHex(u8a);
|
||||
}
|
||||
|
||||
return `${key.creator.section}.${key.creator.method}`;
|
||||
}
|
||||
|
||||
function constTypeToString (registry: Registry, { meta }: ConstValue): string {
|
||||
return getSiName(registry.lookup, meta.type);
|
||||
}
|
||||
|
||||
function queryTypeToString (registry: Registry, { creator: { meta: { modifier, type } } }: QueryableStorageEntry<'promise'>): string {
|
||||
const _type = unwrapStorageType(registry, type);
|
||||
|
||||
return modifier.isOptional
|
||||
? `Option<${_type}>`
|
||||
: _type;
|
||||
}
|
||||
|
||||
function createComponent (type: string, Component: React.ComponentType<any>, defaultProps: DefaultProps, renderHelper: ComponentRenderer): { Component: React.ComponentType<any>; render: (createComponent: RenderFn) => React.ComponentType<any>; refresh: (swallowErrors: boolean) => React.ComponentType<any> } {
|
||||
return {
|
||||
Component,
|
||||
// In order to modify the parameters which are used to render the default component, we can use this method
|
||||
refresh: (): React.ComponentType<any> =>
|
||||
renderHelper(
|
||||
(value: unknown) => <pre>{valueToText(type, value as null)}</pre>,
|
||||
defaultProps
|
||||
),
|
||||
// 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<any> =>
|
||||
renderHelper(createComponent, defaultProps)
|
||||
};
|
||||
}
|
||||
|
||||
function getCachedComponent (registry: Registry, query: QueryTypes): CacheInstance {
|
||||
const { blockHash, id, isConst, key, params = [] } = query as StorageModuleQuery;
|
||||
|
||||
if (!cache[id]) {
|
||||
let renderHelper;
|
||||
let type: string;
|
||||
|
||||
if (isConst) {
|
||||
const { method, section } = key as unknown as ConstValue;
|
||||
|
||||
renderHelper = withCallDiv(`consts.${section}.${method}`, { withIndicator: true });
|
||||
type = constTypeToString(registry, key as unknown as ConstValue);
|
||||
} else {
|
||||
if (isU8a(key)) {
|
||||
// subscribe to the raw key here
|
||||
renderHelper = withCallDiv('rpc.state.subscribeStorage', {
|
||||
paramName: 'params',
|
||||
paramValid: true,
|
||||
params: [[key]],
|
||||
transform: ([data]: Option<Raw>[]): Option<Raw> => data,
|
||||
withIndicator: true
|
||||
});
|
||||
} else {
|
||||
const values: unknown[] = params.map(({ value }) => value);
|
||||
const { creator: { meta: { type } } } = key;
|
||||
const allCount = type.isPlain
|
||||
? 0
|
||||
: type.asMap.hashers.length;
|
||||
const isEntries = values.length !== allCount;
|
||||
|
||||
renderHelper = withCallDiv('subscribe', {
|
||||
paramName: 'params',
|
||||
paramValid: true,
|
||||
params: isEntries
|
||||
? [key.entries, ...values]
|
||||
: blockHash
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
? [key.at, blockHash, ...values]
|
||||
: [key, ...values],
|
||||
withIndicator: true
|
||||
});
|
||||
}
|
||||
|
||||
type = key.creator?.meta
|
||||
? queryTypeToString(registry, key)
|
||||
: 'Raw';
|
||||
}
|
||||
|
||||
const defaultProps = { className: 'ui--output' };
|
||||
const Component = renderHelper(
|
||||
// By default we render a simple div node component with the query results in it
|
||||
(value: unknown) => <pre>{valueToText(type, value as null)}</pre>,
|
||||
defaultProps
|
||||
);
|
||||
|
||||
cache[query.id] = createComponent(type, Component, defaultProps, renderHelper);
|
||||
}
|
||||
|
||||
return cache[id];
|
||||
}
|
||||
|
||||
function Query ({ className = '', onRemove, value }: Props): React.ReactElement<Props> | null {
|
||||
const { api } = useApi();
|
||||
const [{ Component }, callName, callType] = useMemo(
|
||||
() => [
|
||||
getCachedComponent(api.registry, value),
|
||||
keyToName(value.isConst, value.key),
|
||||
value.isConst
|
||||
? constTypeToString(api.registry, value.key as unknown as ConstValue)
|
||||
: isU8a(value.key)
|
||||
? 'Raw'
|
||||
: queryTypeToString(api.registry, value.key as QueryableStorageEntry<'promise'>)
|
||||
],
|
||||
[api, value]
|
||||
);
|
||||
|
||||
const _onRemove = useCallback(
|
||||
(): void => {
|
||||
delete cache[value.id];
|
||||
|
||||
onRemove(value.id);
|
||||
},
|
||||
[onRemove, value]
|
||||
);
|
||||
|
||||
if (!Component) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<StyledDiv className={`${className} storage--Query storage--actionrow`}>
|
||||
<div className='storage--actionrow-value'>
|
||||
<Labelled
|
||||
label={
|
||||
<div className='storage--actionrow-label'>
|
||||
{callName}: {callType}
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<Component />
|
||||
</Labelled>
|
||||
</div>
|
||||
<div className='storage--actionrow-buttons'>
|
||||
<Button
|
||||
icon='times'
|
||||
key='close'
|
||||
onClick={_onRemove}
|
||||
/>
|
||||
</div>
|
||||
</StyledDiv>
|
||||
);
|
||||
}
|
||||
|
||||
const StyledDiv = styled.div`
|
||||
margin-bottom: 0.25em;
|
||||
|
||||
label {
|
||||
text-transform: none !important;
|
||||
}
|
||||
|
||||
.ui.disabled.dropdown.selection {
|
||||
color: #aaa;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.ui--IdentityIcon {
|
||||
margin: -10px 0;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
pre {
|
||||
margin: 0.5;
|
||||
|
||||
.ui--Param-text {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
|
||||
.storage--actionrow-buttons {
|
||||
margin-top: -0.25rem; /* offset parent spacing for buttons */
|
||||
}
|
||||
`;
|
||||
|
||||
export default React.memo(Query);
|
||||
Reference in New Issue
Block a user