mirror of
https://github.com/pezkuwichain/pezkuwi-apps.git
synced 2026-06-17 20:41:05 +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,184 @@
|
||||
// Copyright 2017-2025 @pezkuwi/react-components authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { ExtrinsicSignature } from '@pezkuwi/types/interfaces';
|
||||
import type { Codec, IExtrinsic, IMethod, TypeDef } from '@pezkuwi/types/types';
|
||||
import type { BN } from '@pezkuwi/util';
|
||||
import type { ComponentMap } from '../types.js';
|
||||
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
import { Static, styled } from '@pezkuwi/react-components';
|
||||
import Params from '@pezkuwi/react-params';
|
||||
import { FormatBalance } from '@pezkuwi/react-query';
|
||||
import { Enum, getTypeDef } from '@pezkuwi/types';
|
||||
|
||||
import { balanceCalls, balanceCallsOverrides } from '../overrides.js';
|
||||
import { useTranslation } from '../translate.js';
|
||||
|
||||
export interface Props {
|
||||
callName?: string;
|
||||
children?: React.ReactNode;
|
||||
className?: string;
|
||||
labelHash?: React.ReactNode;
|
||||
labelSignature?: React.ReactNode;
|
||||
mortality?: string;
|
||||
onError?: () => void;
|
||||
value?: IExtrinsic | IMethod | null;
|
||||
withBorder?: boolean;
|
||||
withExpander?: boolean;
|
||||
withHash?: boolean;
|
||||
withSignature?: boolean;
|
||||
tip?: BN;
|
||||
}
|
||||
|
||||
interface Param {
|
||||
name: string;
|
||||
type: TypeDef;
|
||||
}
|
||||
|
||||
interface Value {
|
||||
isValid: boolean;
|
||||
value: Codec;
|
||||
}
|
||||
|
||||
interface Extracted {
|
||||
hash?: string | null;
|
||||
overrides?: ComponentMap;
|
||||
params?: Param[];
|
||||
signature: string | null;
|
||||
signatureType: string | null;
|
||||
values?: Value[];
|
||||
}
|
||||
|
||||
function isExtrinsic (value: unknown): value is IExtrinsic {
|
||||
return !!(value as IExtrinsic).signature;
|
||||
}
|
||||
|
||||
// This is no doubt NOT the way to do things - however there is no other option
|
||||
function getRawSignature (value: IExtrinsic): ExtrinsicSignature | undefined {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any
|
||||
return (value as any)._raw?.signature?.multiSignature as ExtrinsicSignature;
|
||||
}
|
||||
|
||||
function extractState (value?: IExtrinsic | IMethod | null, withHash?: boolean, withSignature?: boolean, callName?: string): Extracted {
|
||||
const overrides = callName && balanceCalls.includes(callName)
|
||||
? balanceCallsOverrides
|
||||
: undefined;
|
||||
const params = value?.meta.args.map(({ name, type }): Param => ({
|
||||
name: name.toString(),
|
||||
type: getTypeDef(type.toString())
|
||||
}));
|
||||
const values = value?.args.map((value): Value => ({
|
||||
isValid: true,
|
||||
value
|
||||
}));
|
||||
const hash = withHash
|
||||
? value?.hash.toHex()
|
||||
: null;
|
||||
let signature: string | null = null;
|
||||
let signatureType: string | null = null;
|
||||
|
||||
if (withSignature && isExtrinsic(value) && value.isSigned) {
|
||||
const raw = getRawSignature(value);
|
||||
|
||||
signature = value.signature.toHex();
|
||||
signatureType = raw instanceof Enum
|
||||
? raw.type
|
||||
: null;
|
||||
}
|
||||
|
||||
return { hash, overrides, params, signature, signatureType, values };
|
||||
}
|
||||
|
||||
function Call ({ callName, children, className = '', labelHash, labelSignature, mortality, onError, tip, value, withBorder, withExpander, withHash, withSignature }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
const [{ hash, overrides, params, signature, signatureType, values }, setExtracted] = useState<Extracted>({ hash: null, params: [], signature: null, signatureType: null, values: [] });
|
||||
|
||||
useEffect((): void => {
|
||||
setExtracted(extractState(value, withHash, withSignature, callName));
|
||||
}, [callName, value, withHash, withSignature]);
|
||||
|
||||
return (
|
||||
<StyledDiv className={`${className} ui--Call`}>
|
||||
<Params
|
||||
isDisabled
|
||||
onError={onError}
|
||||
overrides={overrides}
|
||||
params={params}
|
||||
registry={value?.registry}
|
||||
values={values}
|
||||
withBorder={withBorder}
|
||||
withExpander={withExpander}
|
||||
>
|
||||
{children}
|
||||
<div className='ui--Call--toplevel'>
|
||||
{hash && (
|
||||
<Static
|
||||
className='hash'
|
||||
label={labelHash || t('extrinsic hash')}
|
||||
value={hash}
|
||||
withCopy
|
||||
/>
|
||||
)}
|
||||
{signature && (
|
||||
<Static
|
||||
className='hash'
|
||||
label={labelSignature || t('signature {{type}}', { replace: { type: signatureType ? `(${signatureType})` : '' } })}
|
||||
value={signature}
|
||||
withCopy
|
||||
/>
|
||||
)}
|
||||
{mortality && (
|
||||
<Static
|
||||
className='mortality'
|
||||
label={t('lifetime')}
|
||||
value={mortality}
|
||||
/>
|
||||
)}
|
||||
{tip?.gtn(0) && (
|
||||
<Static
|
||||
className='tip'
|
||||
label={t('tip')}
|
||||
value={<FormatBalance value={tip} />}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</Params>
|
||||
</StyledDiv>
|
||||
);
|
||||
}
|
||||
|
||||
const StyledDiv = styled.div`
|
||||
.ui--Labelled.hash .ui--Static {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
word-break: unset;
|
||||
word-wrap: unset;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.ui--Call--toplevel {
|
||||
margin-top: 0;
|
||||
|
||||
.ui--Labelled {
|
||||
&:last-child > .ui--Labelled-content > .ui--Static {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
> .ui--Labelled-content > .ui--Static {
|
||||
background: var(--bg-static-extra);
|
||||
}
|
||||
|
||||
+ .ui--Labelled > .ui--Labelled-content > .ui--Static {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> .ui--Params {
|
||||
margin-top: -0.25rem;
|
||||
}
|
||||
`;
|
||||
|
||||
export default React.memo(Call);
|
||||
@@ -0,0 +1,76 @@
|
||||
// Copyright 2017-2025 @pezkuwi/react-params authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { Call, Extrinsic } from '@pezkuwi/types/interfaces';
|
||||
import type { BN } from '@pezkuwi/util';
|
||||
|
||||
import React, { useMemo } from 'react';
|
||||
|
||||
import { Expander } from '@pezkuwi/react-components';
|
||||
|
||||
import CallDisplay from './Call.js';
|
||||
|
||||
interface Props {
|
||||
children?: React.ReactNode;
|
||||
className?: string;
|
||||
idString?: string;
|
||||
isHeader?: boolean;
|
||||
labelHash?: React.ReactNode;
|
||||
labelSignature?: React.ReactNode;
|
||||
mortality?: string;
|
||||
onError?: () => void;
|
||||
stringId?: string;
|
||||
tip?: BN;
|
||||
value?: Call | Extrinsic | null;
|
||||
withBorder?: boolean;
|
||||
withHash?: boolean;
|
||||
withSignature?: boolean;
|
||||
isExpanded?: boolean
|
||||
}
|
||||
|
||||
function CallExpander ({ children, className = '', isExpanded, isHeader, labelHash, labelSignature, mortality, onError, stringId, tip, value, withBorder, withHash, withSignature }: Props): React.ReactElement<Props> | null {
|
||||
const call = useMemo(
|
||||
() => value?.callIndex
|
||||
? value.registry.findMetaCall(value.callIndex)
|
||||
: null,
|
||||
[value]
|
||||
);
|
||||
|
||||
if (!call || !value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { meta, method, section } = call;
|
||||
const callName = `${section}.${method}`;
|
||||
|
||||
return (
|
||||
<div className={`${className} ui--CallExpander`}>
|
||||
<Expander
|
||||
isHeader={isHeader}
|
||||
isLeft
|
||||
isOpen={isExpanded}
|
||||
summaryHead={
|
||||
<>{stringId && `#${stringId}: `}{callName}</>
|
||||
}
|
||||
summaryMeta={meta}
|
||||
>
|
||||
<CallDisplay
|
||||
callName={callName}
|
||||
labelHash={labelHash}
|
||||
labelSignature={labelSignature}
|
||||
mortality={mortality}
|
||||
onError={onError}
|
||||
tip={tip}
|
||||
value={value}
|
||||
withBorder={withBorder}
|
||||
withExpander
|
||||
withHash={withHash}
|
||||
withSignature={withSignature}
|
||||
/>
|
||||
{children}
|
||||
</Expander>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default React.memo(CallExpander);
|
||||
@@ -0,0 +1,110 @@
|
||||
// Copyright 2017-2025 @pezkuwi/react-components authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { DecodedEvent } from '@pezkuwi/api-contract/types';
|
||||
import type { Event, EventRecord } from '@pezkuwi/types/interfaces';
|
||||
import type { Codec } from '@pezkuwi/types/types';
|
||||
|
||||
import React, { useMemo } from 'react';
|
||||
|
||||
import { Input } from '@pezkuwi/react-components';
|
||||
import { getContractAbi } from '@pezkuwi/react-components/util';
|
||||
import Params from '@pezkuwi/react-params';
|
||||
|
||||
import { balanceEvents, balanceEventsOverrides } from '../overrides.js';
|
||||
import { useTranslation } from '../translate.js';
|
||||
|
||||
export interface Props {
|
||||
children?: React.ReactNode;
|
||||
className?: string;
|
||||
eventName?: string;
|
||||
value: Event;
|
||||
withExpander?: boolean;
|
||||
}
|
||||
|
||||
interface Value {
|
||||
isValid: boolean;
|
||||
value: Codec;
|
||||
}
|
||||
|
||||
interface AbiEvent extends DecodedEvent {
|
||||
values: Value[];
|
||||
}
|
||||
|
||||
function EventDisplay ({ children, className = '', eventName, value, withExpander }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
const names = value.data.names;
|
||||
const params = value.typeDef.map((type, i) => ({
|
||||
name: names?.[i] || undefined,
|
||||
type
|
||||
}));
|
||||
const values = value.data.map((value) => ({ isValid: true, value }));
|
||||
|
||||
const overrides = useMemo(
|
||||
() => eventName && balanceEvents.includes(eventName)
|
||||
? balanceEventsOverrides
|
||||
: undefined,
|
||||
[eventName]
|
||||
);
|
||||
|
||||
const abiEvent = useMemo(
|
||||
(): AbiEvent | null => {
|
||||
// for contracts, we decode the actual event
|
||||
if (value.section === 'contracts' && value.method === 'ContractExecution' && value.data.length === 2) {
|
||||
// see if we have info for this contract
|
||||
const [accountId, encoded] = value.data;
|
||||
|
||||
try {
|
||||
const abi = getContractAbi(accountId.toString());
|
||||
|
||||
if (abi) {
|
||||
const decoded = abi.decodeEvent(encoded as EventRecord);
|
||||
|
||||
return {
|
||||
...decoded,
|
||||
values: decoded.args.map((value) => ({ isValid: true, value }))
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
// ABI mismatch?
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
[value]
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={`${className} ui--Event`}>
|
||||
{children}
|
||||
<Params
|
||||
isDisabled
|
||||
overrides={overrides}
|
||||
params={params}
|
||||
registry={value.registry}
|
||||
values={values}
|
||||
withExpander={withExpander}
|
||||
>
|
||||
{abiEvent && (
|
||||
<>
|
||||
<Input
|
||||
isDisabled
|
||||
label={t('contract event')}
|
||||
value={abiEvent.event.identifier}
|
||||
/>
|
||||
<Params
|
||||
isDisabled
|
||||
params={abiEvent.event.args}
|
||||
registry={value.registry}
|
||||
values={abiEvent.values}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</Params>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default React.memo(EventDisplay);
|
||||
@@ -0,0 +1,151 @@
|
||||
// Copyright 2017-2025 @pezkuwi/react-params authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { SubmittableExtrinsic, SubmittableExtrinsicFunction } from '@pezkuwi/api/types';
|
||||
import type { TypeDef } from '@pezkuwi/types/types';
|
||||
import type { ComponentMap, RawParam } from '../types.js';
|
||||
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
|
||||
import { InputExtrinsic } from '@pezkuwi/react-components';
|
||||
import Params from '@pezkuwi/react-params';
|
||||
import { getTypeDef } from '@pezkuwi/types/create';
|
||||
import { isUndefined, objectSpread } from '@pezkuwi/util';
|
||||
|
||||
import paramComponents from '../Extra/index.js';
|
||||
import { balanceCalls, balanceCallsOverrides } from '../overrides.js';
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
defaultArgs?: RawParam[];
|
||||
defaultValue: SubmittableExtrinsicFunction<'promise'>;
|
||||
filter?: (section: string, method?: string) => boolean;
|
||||
isDisabled?: boolean;
|
||||
isError?: boolean;
|
||||
isPrivate?: boolean;
|
||||
label?: React.ReactNode;
|
||||
onChange: (method?: SubmittableExtrinsic<'promise'>) => void;
|
||||
onEnter?: () => void;
|
||||
onError?: (error?: Error | null) => void;
|
||||
onEscape?: () => void;
|
||||
withLabel?: boolean;
|
||||
}
|
||||
|
||||
interface ParamDef {
|
||||
name: string;
|
||||
type: TypeDef;
|
||||
}
|
||||
|
||||
interface CallState {
|
||||
extrinsic: {
|
||||
fn: SubmittableExtrinsicFunction<'promise'>;
|
||||
params: ParamDef[];
|
||||
},
|
||||
values: RawParam[];
|
||||
}
|
||||
|
||||
const allComponents = objectSpread<ComponentMap>({}, paramComponents, balanceCallsOverrides);
|
||||
|
||||
function isValuesValid (params: ParamDef[], values: RawParam[]): boolean {
|
||||
return values.reduce((isValid, value): boolean =>
|
||||
isValid &&
|
||||
!isUndefined(value) &&
|
||||
!isUndefined(value.value) &&
|
||||
value.isValid, params.length === values.length
|
||||
);
|
||||
}
|
||||
|
||||
function getParams ({ meta }: SubmittableExtrinsicFunction<'promise'>): ParamDef[] {
|
||||
return meta.args.map(({ name, type, typeName }): { name: string; type: TypeDef } => ({
|
||||
name: name.toString(),
|
||||
type: {
|
||||
...getTypeDef(type.toString()),
|
||||
...(typeName.isSome
|
||||
? { typeName: typeName.unwrap().toString() }
|
||||
: {}
|
||||
)
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
function getCallState (fn: SubmittableExtrinsicFunction<'promise'>, values: RawParam[] = []): CallState {
|
||||
return {
|
||||
extrinsic: {
|
||||
fn,
|
||||
params: getParams(fn)
|
||||
},
|
||||
values
|
||||
};
|
||||
}
|
||||
|
||||
function ExtrinsicDisplay ({ defaultArgs, defaultValue, filter, isDisabled, isError, isPrivate, label, onChange, onEnter, onError, onEscape, withLabel }: Props): React.ReactElement<Props> {
|
||||
const [{ extrinsic, values }, setDisplay] = useState<CallState>(() => getCallState(defaultValue, defaultArgs));
|
||||
|
||||
useEffect((): void => {
|
||||
const isValid = isValuesValid(extrinsic.params, values);
|
||||
let method;
|
||||
|
||||
if (isValid) {
|
||||
try {
|
||||
method = extrinsic.fn(...values.map(({ value }) => value));
|
||||
} catch (error) {
|
||||
onError && onError(error as Error);
|
||||
}
|
||||
} else {
|
||||
onError && onError(null);
|
||||
}
|
||||
|
||||
onChange(method);
|
||||
}, [extrinsic, onChange, onError, values]);
|
||||
|
||||
const overrides = useMemo(
|
||||
() => balanceCalls.includes(`${extrinsic.fn.section}.${extrinsic.fn.method}`)
|
||||
? allComponents
|
||||
: paramComponents,
|
||||
[extrinsic]
|
||||
);
|
||||
|
||||
const _onChangeMethod = useCallback(
|
||||
(fn: SubmittableExtrinsicFunction<'promise'>) =>
|
||||
setDisplay((prev): CallState =>
|
||||
fn.section === prev.extrinsic.fn.section && fn.method === prev.extrinsic.fn.method
|
||||
? prev
|
||||
: getCallState(fn)
|
||||
),
|
||||
[]
|
||||
);
|
||||
|
||||
const _setValues = useCallback(
|
||||
(values: RawParam[]) =>
|
||||
setDisplay(({ extrinsic }) => ({ extrinsic, values })),
|
||||
[]
|
||||
);
|
||||
|
||||
const { fn: { method, section }, params } = extrinsic;
|
||||
|
||||
return (
|
||||
<div className='extrinsics--Extrinsic'>
|
||||
<InputExtrinsic
|
||||
defaultValue={defaultValue}
|
||||
filter={filter}
|
||||
isDisabled={isDisabled}
|
||||
isError={isError}
|
||||
isPrivate={isPrivate}
|
||||
label={label}
|
||||
onChange={_onChangeMethod}
|
||||
withLabel={withLabel}
|
||||
/>
|
||||
<Params
|
||||
key={`${section}.${method}:params` /* force re-render on change */}
|
||||
onChange={_setValues}
|
||||
onEnter={onEnter}
|
||||
onEscape={onEscape}
|
||||
overrides={overrides}
|
||||
params={params}
|
||||
values={values}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default React.memo(ExtrinsicDisplay);
|
||||
@@ -0,0 +1,49 @@
|
||||
// Copyright 2017-2025 @pezkuwi/react-params authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { Call } from '@pezkuwi/types/interfaces';
|
||||
import type { BN } from '@pezkuwi/util';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { formatNumber, isString, isUndefined } from '@pezkuwi/util';
|
||||
|
||||
import { useTranslation } from '../translate.js';
|
||||
import CallExpander from './CallExpander.js';
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
proposal?: Call | null;
|
||||
idNumber?: BN | number | string;
|
||||
withLinks?: boolean;
|
||||
expandNested?: boolean;
|
||||
}
|
||||
|
||||
function ProposedAction ({ className = '', idNumber, proposal }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
const stringId = isString(idNumber) || isUndefined(idNumber)
|
||||
? idNumber
|
||||
: formatNumber(idNumber);
|
||||
|
||||
if (!proposal) {
|
||||
return (
|
||||
<div className={`${className} ui--ProposedAction`}>
|
||||
<div>{stringId ? `#${stringId}: ` : ''}{t('No execution details available for this proposal')}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`${className} ui--ProposedAction`}>
|
||||
<CallExpander
|
||||
isHeader
|
||||
labelHash={t('preimage')}
|
||||
stringId={stringId}
|
||||
value={proposal}
|
||||
withHash
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default React.memo(ProposedAction);
|
||||
@@ -0,0 +1,8 @@
|
||||
// Copyright 2017-2025 @pezkuwi/react-params authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
export { default as Call } from './Call.js';
|
||||
export { default as CallExpander } from './CallExpander.js';
|
||||
export { default as Event } from './Event.js';
|
||||
export { default as Extrinsic } from './Extrinsic.js';
|
||||
export { default as ProposedAction } from './ProposedAction.js';
|
||||
Reference in New Issue
Block a user