From 0b4cae5243acca74919d1db037e6b8cc1172938d Mon Sep 17 00:00:00 2001 From: Arjun Porwal Date: Fri, 28 Feb 2025 12:16:56 +0530 Subject: [PATCH 1/5] enhance: Add user preimages component and update preimage handling --- .../page-preimages/src/Preimages/Preimage.tsx | 10 ++++- .../page-preimages/src/Preimages/index.tsx | 27 +++++++++++- .../src/Preimages/userPreimages/index.tsx | 43 +++++++++++++++++++ 3 files changed, 77 insertions(+), 3 deletions(-) create mode 100644 packages/page-preimages/src/Preimages/userPreimages/index.tsx diff --git a/packages/page-preimages/src/Preimages/Preimage.tsx b/packages/page-preimages/src/Preimages/Preimage.tsx index 4144228adc8e..fb9d0bea61dd 100644 --- a/packages/page-preimages/src/Preimages/Preimage.tsx +++ b/packages/page-preimages/src/Preimages/Preimage.tsx @@ -1,9 +1,10 @@ // Copyright 2017-2025 @polkadot/app-preimages authors & contributors // SPDX-License-Identifier: Apache-2.0 +import type { Preimage as TPreimage } from '@polkadot/react-hooks/types'; import type { HexString } from '@polkadot/util/types'; -import React from 'react'; +import React, { useEffect } from 'react'; import { usePreimage } from '@polkadot/react-hooks'; import { formatNumber } from '@polkadot/util'; @@ -15,11 +16,16 @@ import Hash from './Hash.js'; interface Props { className?: string; value: HexString; + cb?: (info: TPreimage) => void; } -function Preimage ({ className, value }: Props): React.ReactElement { +function Preimage ({ cb, className, value }: Props): React.ReactElement { const info = usePreimage(value); + useEffect(() => { + info && cb?.(info); + }, [cb, info]); + return ( diff --git a/packages/page-preimages/src/Preimages/index.tsx b/packages/page-preimages/src/Preimages/index.tsx index 2eacaba67da0..6eebfa65cb38 100644 --- a/packages/page-preimages/src/Preimages/index.tsx +++ b/packages/page-preimages/src/Preimages/index.tsx @@ -2,14 +2,16 @@ // SPDX-License-Identifier: Apache-2.0 import type { SubmittableExtrinsicFunction } from '@polkadot/api/types'; +import type { Preimage as TPreimage } from '@polkadot/react-hooks/types'; -import React, { useRef } from 'react'; +import React, { useCallback, useMemo, useRef, useState } from 'react'; import { Button, styled, Table } from '@polkadot/react-components'; import { useTranslation } from '../translate.js'; import usePreimages from '../usePreimages.js'; import Add from './Add/index.js'; +import { UserPreimages } from './userPreimages/index.js'; import Preimage from './Preimage.js'; import Summary from './Summary.js'; @@ -21,8 +23,29 @@ interface Props { function Hashes ({ className }: Props): React.ReactElement { const { t } = useTranslation(); + const [allPreImagesInfo, setAllPreImagesInfo] = useState([]); const hashes = usePreimages(); + // HACK to concat all preimages info without creating a new hook, just for multiple hashes + const onSetAllPreImagesInfo = useCallback((info: TPreimage) => { + setAllPreImagesInfo((preimages) => ([ + ...preimages.filter((e) => e.proposalHash !== info.proposalHash), + info + ])); + }, []); + + const groupedByDepositor = useMemo(() => { + return allPreImagesInfo.reduce((result: Record, current) => { + if (current.deposit?.who) { + const newItems = [...(result[current.deposit?.who] || []), current]; + + result[current.deposit?.who] = newItems; + } + + return result; + }, {} as Record); + }, [allPreImagesInfo]); + const headerRef = useRef<([React.ReactNode?, string?, number?] | false)[]>([ [t('preimages'), 'start', 2], [undefined, 'media--1300'], @@ -36,6 +59,7 @@ function Hashes ({ className }: Props): React.ReactElement { + { > {hashes?.map((h) => ( diff --git a/packages/page-preimages/src/Preimages/userPreimages/index.tsx b/packages/page-preimages/src/Preimages/userPreimages/index.tsx new file mode 100644 index 000000000000..1d969404632c --- /dev/null +++ b/packages/page-preimages/src/Preimages/userPreimages/index.tsx @@ -0,0 +1,43 @@ +// Copyright 2017-2025 @polkadot/app-preimages authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import type { Preimage as TPreimage } from '@polkadot/react-hooks/types'; + +import React, { useRef } from 'react'; + +import { Table } from '@polkadot/react-components'; + +import { useTranslation } from '../../translate.js'; + +interface Props { + className?: string; + userPreimages: Record +} + +export const UserPreimages = ({ className, userPreimages }: Props) => { + const { t } = useTranslation(); + + const headerRef = useRef<([React.ReactNode?, string?, number?] | false)[]>([ + [t('my preimages'), 'start', 2], + [t('hash'), 'media--1000'], + [undefined, 'media--1000'], + [t('length'), 'media--1000'], + [t('status'), 'start media--1200'] + ]); + + return ( +
+ {/* {hashes?.map((h) => ( + + ))} */} +
+ ); +}; From 9f731f496fe836fb8c1a7de06d4e771064cd0d4f Mon Sep 17 00:00:00 2001 From: Arjun Porwal Date: Fri, 28 Feb 2025 13:44:18 +0530 Subject: [PATCH 2/5] refactor: user preimages handling and improve UI components --- .../page-preimages/src/Preimages/index.tsx | 12 ++-- .../src/Preimages/userPreimages/Preimage.tsx | 58 +++++++++++++++++++ .../src/Preimages/userPreimages/index.tsx | 21 ++++--- 3 files changed, 77 insertions(+), 14 deletions(-) create mode 100644 packages/page-preimages/src/Preimages/userPreimages/Preimage.tsx diff --git a/packages/page-preimages/src/Preimages/index.tsx b/packages/page-preimages/src/Preimages/index.tsx index 6eebfa65cb38..c9ed6def42a0 100644 --- a/packages/page-preimages/src/Preimages/index.tsx +++ b/packages/page-preimages/src/Preimages/index.tsx @@ -7,11 +7,12 @@ import type { Preimage as TPreimage } from '@polkadot/react-hooks/types'; import React, { useCallback, useMemo, useRef, useState } from 'react'; import { Button, styled, Table } from '@polkadot/react-components'; +import { useAccounts } from '@polkadot/react-hooks'; import { useTranslation } from '../translate.js'; import usePreimages from '../usePreimages.js'; import Add from './Add/index.js'; -import { UserPreimages } from './userPreimages/index.js'; +import UserPreimages from './userPreimages/index.js'; import Preimage from './Preimage.js'; import Summary from './Summary.js'; @@ -23,6 +24,7 @@ interface Props { function Hashes ({ className }: Props): React.ReactElement { const { t } = useTranslation(); + const { allAccounts } = useAccounts(); const [allPreImagesInfo, setAllPreImagesInfo] = useState([]); const hashes = usePreimages(); @@ -34,9 +36,9 @@ function Hashes ({ className }: Props): React.ReactElement { ])); }, []); - const groupedByDepositor = useMemo(() => { + const groupedUserPreimages = useMemo(() => { return allPreImagesInfo.reduce((result: Record, current) => { - if (current.deposit?.who) { + if (current.deposit?.who && allAccounts.includes(current.deposit?.who)) { const newItems = [...(result[current.deposit?.who] || []), current]; result[current.deposit?.who] = newItems; @@ -44,7 +46,7 @@ function Hashes ({ className }: Props): React.ReactElement { return result; }, {} as Record); - }, [allPreImagesInfo]); + }, [allAccounts, allPreImagesInfo]); const headerRef = useRef<([React.ReactNode?, string?, number?] | false)[]>([ [t('preimages'), 'start', 2], @@ -59,7 +61,7 @@ function Hashes ({ className }: Props): React.ReactElement { - + { + return ( + <> + {preimageInfos.map((info, index) => { + return ( + + + + + + + + ); + })} + + ); +}; + +export default React.memo(Preimage); diff --git a/packages/page-preimages/src/Preimages/userPreimages/index.tsx b/packages/page-preimages/src/Preimages/userPreimages/index.tsx index 1d969404632c..34709872634e 100644 --- a/packages/page-preimages/src/Preimages/userPreimages/index.tsx +++ b/packages/page-preimages/src/Preimages/userPreimages/index.tsx @@ -8,21 +8,22 @@ import React, { useRef } from 'react'; import { Table } from '@polkadot/react-components'; import { useTranslation } from '../../translate.js'; +import Preimage from './Preimage.js'; interface Props { className?: string; userPreimages: Record } -export const UserPreimages = ({ className, userPreimages }: Props) => { +const UserPreimages = ({ className, userPreimages }: Props) => { const { t } = useTranslation(); const headerRef = useRef<([React.ReactNode?, string?, number?] | false)[]>([ [t('my preimages'), 'start', 2], - [t('hash'), 'media--1000'], - [undefined, 'media--1000'], + [undefined, 'media--1300'], + [t('hash'), 'start'], [t('length'), 'media--1000'], - [t('status'), 'start media--1200'] + [t('status'), 'start media--1100'] ]); return ( @@ -31,13 +32,15 @@ export const UserPreimages = ({ className, userPreimages }: Props) => { empty={Object.values(userPreimages) && t('No hashes found')} header={headerRef.current} > - {/* {hashes?.map((h) => ( + {Object.keys(userPreimages)?.map((depositor) => ( - ))} */} + ))}
+ {index === 0 && } + + {info?.proposalLength + ? formatNumber(info.proposalLength) + : 999,999} + + {info + ? ( + <> + {info.status && (
{info.status?.type}{info.count !== 0 && <> / {formatNumber(info.count)}}
)} + + ) + : Unrequested} +
); }; + +export default React.memo(UserPreimages); From 7a92f2abc41491673ee769a53acd410f0247f458 Mon Sep 17 00:00:00 2001 From: Arjun Porwal Date: Fri, 28 Feb 2025 13:52:48 +0530 Subject: [PATCH 3/5] style: enhance table row styling in Preimage component --- .../src/Preimages/userPreimages/Preimage.tsx | 32 ++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/packages/page-preimages/src/Preimages/userPreimages/Preimage.tsx b/packages/page-preimages/src/Preimages/userPreimages/Preimage.tsx index 008375ce624b..84141ebf3e8a 100644 --- a/packages/page-preimages/src/Preimages/userPreimages/Preimage.tsx +++ b/packages/page-preimages/src/Preimages/userPreimages/Preimage.tsx @@ -5,7 +5,7 @@ import type { Preimage as TPreimage } from '@polkadot/react-hooks/types'; import React from 'react'; -import { AddressMini } from '@polkadot/react-components'; +import { AddressMini, styled } from '@polkadot/react-components'; import { formatNumber } from '@polkadot/util'; import Call from '../Call.js'; @@ -22,8 +22,10 @@ const Preimage = ({ className, depositor, preimageInfos }: Props) => { <> {preimageInfos.map((info, index) => { return ( - { ) : Unrequested} - + ); })} ); }; +const BASE_BORDER = 0.125; +const BORDER_TOP = `${BASE_BORDER * 3}rem solid var(--bg-page)`; +const BORDER_RADIUS = `${BASE_BORDER * 4}rem`; + +const StyledTr = styled.tr<{isFirstItem: boolean; isLastItem: boolean}>` + td { + border-top: ${(props) => props.isFirstItem && BORDER_TOP}; + border-radius: 0rem !important; + + &:first-child { + padding-block: 1rem !important; + border-top-left-radius: ${(props) => props.isFirstItem ? BORDER_RADIUS : '0rem'}!important; + border-bottom-left-radius: ${(props) => props.isLastItem ? BORDER_RADIUS : '0rem'}!important; + } + + &:last-child { + border-top-right-radius: ${(props) => props.isFirstItem ? BORDER_RADIUS : '0rem'}!important; + border-bottom-right-radius: ${(props) => props.isLastItem ? BORDER_RADIUS : '0rem'}!important; + } + } +`; + export default React.memo(Preimage); From 26015e74efa18f04ac70c3ba8653fa0519cdb0a1 Mon Sep 17 00:00:00 2001 From: Arjun Porwal Date: Fri, 28 Feb 2025 16:21:11 +0530 Subject: [PATCH 4/5] feat: unnote multiple preimages at once --- .../src/Preimages/userPreimages/Preimage.tsx | 95 ++++++++++++++++--- 1 file changed, 81 insertions(+), 14 deletions(-) diff --git a/packages/page-preimages/src/Preimages/userPreimages/Preimage.tsx b/packages/page-preimages/src/Preimages/userPreimages/Preimage.tsx index 84141ebf3e8a..ada4f964921e 100644 --- a/packages/page-preimages/src/Preimages/userPreimages/Preimage.tsx +++ b/packages/page-preimages/src/Preimages/userPreimages/Preimage.tsx @@ -3,11 +3,13 @@ import type { Preimage as TPreimage } from '@polkadot/react-hooks/types'; -import React from 'react'; +import React, { useState } from 'react'; -import { AddressMini, styled } from '@polkadot/react-components'; +import { AddressMini, Checkbox, styled, TxButton } from '@polkadot/react-components'; +import { useApi } from '@polkadot/react-hooks'; import { formatNumber } from '@polkadot/util'; +import { useTranslation } from '../../translate.js'; import Call from '../Call.js'; import Hash from '../Hash.js'; @@ -17,7 +19,36 @@ interface Props { preimageInfos: TPreimage[]; } +interface SelectPreimageProps { + proposalHash: TPreimage['proposalHash'], + onSelectPreimage: React.Dispatch> +} + +const SelectPreimage = ({ onSelectPreimage, proposalHash }: SelectPreimageProps) => { + const [checked, setChecked] = useState(false); + + const onChange = React.useCallback((value: boolean) => { + setChecked(value); + onSelectPreimage((prevHashes) => + // Add preimage hash if checked else filter it out + value ? [...prevHashes, proposalHash] : prevHashes.filter((i) => i !== proposalHash) + ); + }, [onSelectPreimage, proposalHash]); + + return ( + + ); +}; + const Preimage = ({ className, depositor, preimageInfos }: Props) => { + const { t } = useTranslation(); + const { api } = useApi(); + + const [selectedPreimages, onSelectPreimage] = useState([]); + return ( <> {preimageInfos.map((info, index) => { @@ -25,7 +56,7 @@ const Preimage = ({ className, depositor, preimageInfos }: Props) => { { {index === 0 && } - + + + + {info?.proposalLength ? formatNumber(info.proposalLength) @@ -53,6 +90,28 @@ const Preimage = ({ className, depositor, preimageInfos }: Props) => { ); })} + + + + + + api.tx.preimage.unnotePreimage(i))]} + tx={api.tx.utility.batchAll} + /> + + + + ); }; @@ -62,20 +121,28 @@ const BORDER_TOP = `${BASE_BORDER * 3}rem solid var(--bg-page)`; const BORDER_RADIUS = `${BASE_BORDER * 4}rem`; const StyledTr = styled.tr<{isFirstItem: boolean; isLastItem: boolean}>` + .ui--Icon { + border-width: 2px; + } + td { border-top: ${(props) => props.isFirstItem && BORDER_TOP}; border-radius: 0rem !important; - &:first-child { - padding-block: 1rem !important; - border-top-left-radius: ${(props) => props.isFirstItem ? BORDER_RADIUS : '0rem'}!important; - border-bottom-left-radius: ${(props) => props.isLastItem ? BORDER_RADIUS : '0rem'}!important; - } - - &:last-child { - border-top-right-radius: ${(props) => props.isFirstItem ? BORDER_RADIUS : '0rem'}!important; - border-bottom-right-radius: ${(props) => props.isLastItem ? BORDER_RADIUS : '0rem'}!important; - } + &:first-child { + padding-block: 1rem !important; + border-top-left-radius: ${(props) => props.isFirstItem ? BORDER_RADIUS : '0rem'}!important; + border-bottom-left-radius: ${(props) => props.isLastItem ? BORDER_RADIUS : '0rem'}!important; + } + + &:last-child { + border-top-right-radius: ${(props) => props.isFirstItem ? BORDER_RADIUS : '0rem'}!important; + border-bottom-right-radius: ${(props) => props.isLastItem ? BORDER_RADIUS : '0rem'}!important; + } + + td { + border: none !important; + } } `; From fa35ddd8d0b66eb099562c5f794710c57195853f Mon Sep 17 00:00:00 2001 From: Arjun Porwal Date: Fri, 28 Feb 2025 18:30:17 +0530 Subject: [PATCH 5/5] chore: check if id is not undefined --- packages/react-hooks/src/useAssetIds.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-hooks/src/useAssetIds.ts b/packages/react-hooks/src/useAssetIds.ts index 312a9d0f7acc..45f5dc1908e0 100644 --- a/packages/react-hooks/src/useAssetIds.ts +++ b/packages/react-hooks/src/useAssetIds.ts @@ -11,7 +11,7 @@ const EMPTY_PARAMS: unknown[] = []; const OPT_KEY = { transform: (keys: StorageKey<[u32]>[]): u32[] => - keys.map(({ args: [id] }) => id) + keys.map(({ args: [id] }) => id).filter((id) => id !== undefined) }; function filter (records: EventRecord[]): Changes {