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:
2026-01-07 13:05:27 +03:00
commit d21bfb1320
5867 changed files with 329019 additions and 0 deletions
@@ -0,0 +1,55 @@
// Copyright 2017-2025 @pezkuwi/app-scheduler authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { DeriveDispatch } from '@pezkuwi/api-derive/types';
import React from 'react';
import PreImageButton from '@pezkuwi/app-democracy/Overview/PreImageButton';
import ProposalCell from '@pezkuwi/app-democracy/Overview/ProposalCell';
import { LinkExternal, Table } from '@pezkuwi/react-components';
import { useBestNumber } from '@pezkuwi/react-hooks';
import { BlockToTime } from '@pezkuwi/react-query';
import { formatNumber } from '@pezkuwi/util';
interface Props {
value: DeriveDispatch;
}
function DispatchEntry ({ value: { at, image, imageHash, index } }: Props): React.ReactElement<Props> {
const bestNumber = useBestNumber();
return (
<tr>
<Table.Column.Id value={index} />
<ProposalCell
imageHash={imageHash}
proposal={image?.proposal}
/>
<td className='number together'>
{bestNumber && (
<>
<BlockToTime value={at.sub(bestNumber)} />
#{formatNumber(at)}
</>
)}
</td>
<td className='button'>
{!image?.proposal && (
<PreImageButton
imageHash={imageHash}
isImminent
/>
)}
</td>
<td className='links media--1000'>
<LinkExternal
data={index}
type='democracyReferendum'
/>
</td>
</tr>
);
}
export default React.memo(DispatchEntry);
@@ -0,0 +1,52 @@
// Copyright 2017-2025 @pezkuwi/app-scheduler authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { DeriveDispatch } from '@pezkuwi/api-derive/types';
import React, { useMemo, useRef } from 'react';
import { Table } from '@pezkuwi/react-components';
import { useApi, useBestNumber, useCall } from '@pezkuwi/react-hooks';
import DispatchEntry from './DispatchEntry.js';
import { useTranslation } from './translate.js';
interface Props {
className?: string;
}
function DispatchQueue ({ className }: Props): React.ReactElement<Props> | null {
const { t } = useTranslation();
const { api } = useApi();
const bestNumber = useBestNumber();
const queued = useCall<DeriveDispatch[]>(api.derive.democracy.dispatchQueue);
const filtered = useMemo(
() => bestNumber && queued?.filter(({ at }) => at.gte(bestNumber)).sort((a, b) => a.at.cmp(b.at)),
[bestNumber, queued]
);
const headerRef = useRef<([React.ReactNode?, string?, number?] | false)[]>([
[t('dispatch queue'), 'start', 2],
[t('enact')],
[],
[undefined, 'media--1000']
]);
return (
<Table
className={className}
empty={filtered && t('Nothing queued for execution')}
header={headerRef.current}
>
{filtered?.map((entry): React.ReactNode => (
<DispatchEntry
key={entry.index.toString()}
value={entry}
/>
))}
</Table>
);
}
export default React.memo(DispatchQueue);
+63
View File
@@ -0,0 +1,63 @@
// Copyright 2017-2025 @pezkuwi/app-scheduler authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { BlockNumber } from '@pezkuwi/types/interfaces';
import type { ScheduledExt } from './types.js';
import React from 'react';
import Hash from '@pezkuwi/app-preimages/Preimages/Hash';
import { usePreimage, useStakingAsyncApis } from '@pezkuwi/react-hooks';
import { CallExpander } from '@pezkuwi/react-params';
import { BlockToTime } from '@pezkuwi/react-query';
import { formatNumber } from '@pezkuwi/util';
interface Props {
bestNumber?: BlockNumber;
className?: string;
value: ScheduledExt;
}
function Scheduled ({ bestNumber, className = '', value: { blockNumber, call, maybeId, maybePeriodic, preimageHash } }: Props): React.ReactElement<Props> {
const { isStakingAsync, rcApi } = useStakingAsyncApis();
const preimage = usePreimage(preimageHash);
const period = maybePeriodic.unwrapOr(null);
const name = maybeId.unwrapOr(null);
return (
<tr className={className}>
<td className='all'>
<CallExpander value={call || preimage?.proposal} />
</td>
{name
? name.isAscii
? <td className='start'>{name.toUtf8()}</td>
: <Hash value={name.toHex()} />
: <td />
}
<td className='number together'>
{bestNumber && (
<>
<BlockToTime
api={isStakingAsync ? rcApi : undefined}
value={blockNumber.sub(bestNumber)}
/>
#{formatNumber(blockNumber)}
</>
)}
</td>
<td className='number together'>
{period && (
formatNumber(period[0])
)}
</td>
<td className='number together'>
{period && (
formatNumber(period[1])
)}
</td>
</tr>
);
}
export default React.memo(Scheduled);
+117
View File
@@ -0,0 +1,117 @@
// Copyright 2017-2025 @pezkuwi/app-scheduler authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { ApiPromise } from '@pezkuwi/api';
import type { Bytes, Option, u8, u32 } from '@pezkuwi/types';
import type { BlockNumber, Call, Hash, Scheduled } from '@pezkuwi/types/interfaces';
import type { FrameSupportPreimagesBounded, PalletSchedulerScheduled } from '@pezkuwi/types/lookup';
import type { Codec, ITuple } from '@pezkuwi/types/types';
import type { ScheduledExt } from './types.js';
import React, { useMemo, useRef } from 'react';
import { Table } from '@pezkuwi/react-components';
import { useApi, useBestNumberRelay, useCall } from '@pezkuwi/react-hooks';
import ScheduledView from './Scheduled.js';
import { useTranslation } from './translate.js';
interface Props {
className?: string;
}
// included here for backwards compat
interface PalletSchedulerScheduledV3 extends Codec {
maybeId: Option<Bytes>;
priority: u8;
call: FrameSupportScheduleMaybeHashed;
maybePeriodic: Option<ITuple<[u32, u32]>>;
origin: Codec;
}
// included here for backwards compat
interface FrameSupportScheduleMaybeHashed extends Codec {
// added here since we use it for detection
inner: Codec;
// enum features
isHash: boolean;
isValue: boolean;
asValue: Call;
asHash: Hash;
}
const OPT_SCHED = {
transform: (entries: [{ args: [BlockNumber] }, Option<Scheduled | PalletSchedulerScheduled | PalletSchedulerScheduledV3>[]][], api: ApiPromise): ScheduledExt[] => {
return entries
.filter(([, all]) => all.some((o) => o.isSome))
.reduce((items: ScheduledExt[], [key, all]): ScheduledExt[] => {
const blockNumber = key.args[0];
return all
.filter((o) => o.isSome)
.map((o) => o.unwrap())
.reduce((items: ScheduledExt[], { call: callOrEnum, maybeId, maybePeriodic, priority }, index) => {
let call: Call | null = null;
let preimageHash: FrameSupportPreimagesBounded | undefined;
if ((callOrEnum as unknown as FrameSupportScheduleMaybeHashed).inner) {
if ((callOrEnum as unknown as FrameSupportScheduleMaybeHashed).isValue) {
call = (callOrEnum as unknown as FrameSupportScheduleMaybeHashed).asValue;
} else if ((callOrEnum as unknown as FrameSupportPreimagesBounded).isInline) {
try {
call = api.registry.createType('Call', (callOrEnum as unknown as FrameSupportPreimagesBounded).asInline.toHex());
} catch (error) {
console.error(error);
}
} else if ((callOrEnum as unknown as FrameSupportPreimagesBounded).isLookup) {
preimageHash = (callOrEnum as unknown as FrameSupportPreimagesBounded);
}
} else {
call = callOrEnum as Call;
}
items.push({ blockNumber, call, key: `${blockNumber.toString()}-${index}`, maybeId, maybePeriodic, preimageHash, priority });
return items;
}, items);
}, []);
}
};
function Schedule ({ className = '' }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
const bestNumber = useBestNumberRelay();
const items = useCall<ScheduledExt[]>(api.query.scheduler.agenda.entries, undefined, OPT_SCHED);
const filtered = useMemo(
() => bestNumber && items?.filter(({ blockNumber }) => blockNumber.gte(bestNumber)).sort((a, b) => a.blockNumber.cmp(b.blockNumber)),
[bestNumber, items]
);
const headerRef = useRef<[React.ReactNode?, string?, number?][]>([
[t('scheduled'), 'start'],
[t('id'), 'start'],
[t('remaining')],
[t('period')],
[t('count')]
]);
return (
<Table
className={className}
empty={filtered && t('No active schedules')}
header={headerRef.current}
>
{filtered?.map((value): React.ReactNode => (
<ScheduledView
bestNumber={bestNumber}
key={value.key}
value={value}
/>
))}
</Table>
);
}
export default React.memo(Schedule);
+49
View File
@@ -0,0 +1,49 @@
// Copyright 2017-2025 @pezkuwi/app-scheduler authors & contributors
// SPDX-License-Identifier: Apache-2.0
import React, { useMemo } from 'react';
import { Tabs } from '@pezkuwi/react-components';
import { useApi } from '@pezkuwi/react-hooks';
import DispatchQueue from './DispatchQueue.js';
import Scheduler from './Scheduler.js';
import { useTranslation } from './translate.js';
interface Props {
basePath: string;
className?: string;
}
function App ({ basePath, className }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
const tabs = useMemo(
() => [
{
isRoot: true,
name: 'overview',
text: t('Overview')
}
],
[t]
);
return (
<main className={className}>
<Tabs
basePath={basePath}
items={tabs}
/>
{api.query.democracy && (
<DispatchQueue />
)}
{api.query.scheduler && (
<Scheduler />
)}
</main>
);
}
export default React.memo(App);
+8
View File
@@ -0,0 +1,8 @@
// Copyright 2017-2025 @pezkuwi/app-explorer authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { useTranslation as useTranslationBase } from 'react-i18next';
export function useTranslation (): { t: (key: string, options?: { replace: Record<string, unknown> }) => string } {
return useTranslationBase('app-scheduler');
}
+16
View File
@@ -0,0 +1,16 @@
// Copyright 2017-2025 @pezkuwi/app-scheduler authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Bytes, Option } from '@pezkuwi/types';
import type { BlockNumber, Call, SchedulePeriod, SchedulePriority } from '@pezkuwi/types/interfaces';
import type { FrameSupportPreimagesBounded } from '@pezkuwi/types/lookup';
export interface ScheduledExt {
blockNumber: BlockNumber;
call: Call | null;
key: string;
maybeId: Option<Bytes>;
maybePeriodic: Option<SchedulePeriod>;
priority: SchedulePriority;
preimageHash?: FrameSupportPreimagesBounded;
}