Skip to content

Commit

Permalink
Merge pull request #119 from polkadot-cloud/rb-input-key-fixes
Browse files Browse the repository at this point in the history
feat(fix): Correctly reset input args on active item changes
  • Loading branch information
rossbulat authored Jun 20, 2024
2 parents 1502b98 + 769ace1 commit ed91406
Show file tree
Hide file tree
Showing 21 changed files with 167 additions and 148 deletions.
7 changes: 4 additions & 3 deletions src/contexts/InputMeta/defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
import type { InputMetaContextInterface } from './types';

export const defaultInputMetaContext: InputMetaContextInterface = {
getInputMetaValue: () => undefined,
setInputMetaValue: () => {},
removeInputMeta: () => {},
getInputMetaValue: (tabId, inputId) => undefined,
setInputMetaValue: (tabId, inputId, value) => {},
removeInputMetaValue: (tabId, inputId) => {},
removeInputMeta: (tabId) => {},
};
13 changes: 13 additions & 0 deletions src/contexts/InputMeta/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,18 @@ export const InputMetaProvider = ({ children }: { children: ReactNode }) => {
}));
};

// Remove input meta for a tabId and inputId.
const removeInputMetaValue = (tabId: number, inputId: string) => {
setInputMeta((prev) => {
const updated = { ...prev };
if (!updated[tabId]) {
return updated;
}
delete updated[tabId][inputId];
return updated;
});
};

// Remove input meta for a tab.
const removeInputMeta = (tabId: number) => {
const updated = { ...inputMeta };
Expand All @@ -45,6 +57,7 @@ export const InputMetaProvider = ({ children }: { children: ReactNode }) => {
value={{
getInputMetaValue,
setInputMetaValue,
removeInputMetaValue,
removeInputMeta,
}}
>
Expand Down
1 change: 1 addition & 0 deletions src/contexts/InputMeta/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
export interface InputMetaContextInterface {
getInputMetaValue: (tabId: number, inputId: string) => string | undefined;
setInputMetaValue: (tabId: number, inputId: string, value: string) => void;
removeInputMetaValue: (tabId: number, inputId: string) => void;
removeInputMeta: (tabId: number) => void;
}
12 changes: 6 additions & 6 deletions src/library/Inputs/AccountId32/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { useInputMeta } from 'contexts/InputMeta';
import { useActiveTab } from 'contexts/ActiveTab';

export const AccountId32 = ({
uid,
inputId,
accounts,
defaultAddress,
heightRef,
Expand All @@ -41,7 +41,7 @@ export const AccountId32 = ({
}

// Get input value from input meta.
const inputMetaValue = getInputMetaValue(tabId, uid);
const inputMetaValue = getInputMetaValue(tabId, inputId);

// The current selected address. If input meta value is not present, use the the first imported
// account, if any.
Expand All @@ -60,7 +60,7 @@ export const AccountId32 = ({

// Handle input value change.
const handleInputChange = (val: string) => {
setInputMetaValue(tabId, uid, val);
setInputMetaValue(tabId, inputId, val);
setSearchValue(val);

if (onChange !== undefined) {
Expand All @@ -73,7 +73,7 @@ export const AccountId32 = ({
const handleInputBlur = () => {
const isImportedAddress = accounts.find(({ address }) => address === value);
if (isImportedAddress) {
setInputMetaValue(tabId, uid, isImportedAddress.name);
setInputMetaValue(tabId, inputId, isImportedAddress.name);
}
};

Expand Down Expand Up @@ -103,7 +103,7 @@ export const AccountId32 = ({
useEffect(() => {
setInputMetaValue(
tabId,
uid,
inputId,
accounts?.find(({ address }) => address === selectedAddress)?.name ||
selectedAddress
);
Expand Down Expand Up @@ -175,7 +175,7 @@ export const AccountId32 = ({
className={`option${value === name ? ` selected` : ``}`}
onClick={() => {
setDropdownOpen(false);
setInputMetaValue(tabId, uid, name);
setInputMetaValue(tabId, inputId, name);

if (onChange !== undefined) {
onChange(address);
Expand Down
2 changes: 1 addition & 1 deletion src/library/Inputs/AccountId32/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import type { InputCallbackProps } from '../types';
import type { RefObject } from 'react';

export type AccountId32Props = InputCallbackProps & {
uid: string;
inputId: string;
accounts: ImportedAccount[];
defaultAddress: string | undefined;
heightRef?: RefObject<HTMLDivElement>;
Expand Down
4 changes: 2 additions & 2 deletions src/modals/Transfer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ export const Transfer = () => {
<div>
<Label value="From" />
<AccountId32
uid={`${metaKey}_transferFromAddress`}
inputId={`${metaKey}_transferFromAddress`}
defaultAddress={fromAddress}
accounts={accounts}
onChange={(val) => setFromAddress(val)}
Expand All @@ -126,7 +126,7 @@ export const Transfer = () => {

<Label value="Recipient" marginTop />
<AccountId32
uid={`${metaKey}_transferRecipientAddress`}
inputId={`${metaKey}_transferRecipientAddress`}
defaultAddress={toAddress}
accounts={accounts}
onChange={(val) => setToAddress(val)}
Expand Down
45 changes: 20 additions & 25 deletions src/routes/Chain/ChainState/ChainStateList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import { SearchInput } from 'library/ContextMenu/SearchInput';
import { useBrowseListWithKeys } from 'hooks/useBrowseListWithKeys';
import { SelectDropdown } from 'library/SelectDropdown';
import { SelectItemWrapper, SelectTextWrapper } from 'library/Inputs/Wrappers';
import { useInputForm } from '../InputForm/provider';
import { useSelectFirst } from 'hooks/useSelectFirst';

export const ChainStateList = ({
Expand All @@ -24,9 +23,9 @@ export const ChainStateList = ({
activeItem,
subject,
scraper,
inputNamespace,
}: ChainStateListProps) => {
const { tabId } = useActiveTab();
const { namespace } = useInputForm();
const { getChainUi, setChainUiNamespace, resetInputArgSection } =
useChainUi();

Expand All @@ -46,6 +45,22 @@ export const ChainStateList = ({
setChainUiNamespace(tabId, chainUiSection, 'search', value);
};

// Handle item change.
const handleItemChange = (value: string, closeDropdown: boolean) => {
// Updated the selected item in chain ui state.
setChainUiNamespace(tabId, chainUiSection, 'selected', value);

// If an input namespace is provided, reset input arg values.
if (inputNamespace) {
resetInputArgSection(tabId, inputNamespace);
}

// Close item the dropdown if requested.
if (closeDropdown) {
setDropdownOpen(false);
}
};

// Gets a filtered list by applying a search term on list items, if not empty.
const getFilteredItems = (search: string) =>
search !== ''
Expand Down Expand Up @@ -84,9 +99,7 @@ export const ChainStateList = ({
listItems: filteredList.map(({ name }) => name),
listOpenRef: dropdownOpenRef,
activeValue: activeItem,
onUpdate: (newItem: string) => {
setChainUiNamespace(tabId, chainUiSection, 'selected', newItem);
},
onUpdate: (value: string) => handleItemChange(value, false),
});

// Dropdown search input ref.
Expand All @@ -95,9 +108,7 @@ export const ChainStateList = ({
// If the currently selected pallet is not in the filtered list, select the first item.
useSelectFirst({
isActive: chainUi['selectOnSearch'] === true,
onSelect: (value) => {
setChainUiNamespace(tabId, chainUiSection, 'selected', value);
},
onSelect: (value) => handleItemChange(value, false),
activeItem,
searchTerm: chainUi.search,
getFiltered: (searchTerm: string) =>
Expand All @@ -111,19 +122,6 @@ export const ChainStateList = ({
}
}, [dropdownOpen]);

// Manage `activeItem` changes.
useEffect(() => {
// Reset input args when active item changes.
if (namespace) {
resetInputArgSection(tabId, namespace);
}

// On initial render, set the selected item to the first list item, if any.
if (activeItem) {
setChainUiNamespace(tabId, chainUiSection, 'selected', activeItem);
}
}, [activeItem]);

return (
<section>
<div className="inner">
Expand Down Expand Up @@ -168,10 +166,7 @@ export const ChainStateList = ({
<SelectItemWrapper
key={`${chainUiSection}_select_${name}`}
className={`option${filteredSelectedItem.name === name ? ` selected` : ``}`}
onClick={() => {
setChainUiNamespace(tabId, chainUiSection, 'selected', name);
setDropdownOpen(false);
}}
onClick={() => handleItemChange(name, true)}
>
<span>
<SelectTextWrapper>
Expand Down
10 changes: 9 additions & 1 deletion src/routes/Chain/ChainState/Constants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// SPDX-License-Identifier: GPL-3.0-only

import { InputFormWrapper } from '../Wrappers';
import { useMemo } from 'react';
import { useEffect, useMemo } from 'react';
import { PalletList } from '../PalletList';
import { PalletScraper } from 'model/Scraper/Pallet';
import { useChainUi } from 'contexts/ChainUi';
Expand Down Expand Up @@ -72,6 +72,14 @@ export const Constants = () => {
}
};

// Manage `activeItem` changes.
useEffect(() => {
// On initial render, set the selected item to the first list item, if any.
if (activeItem) {
setChainUiNamespace(tabId, chainUiSection, 'selected', activeItem);
}
}, [activeItem]);

return (
<>
<SelectFormWrapper className="withHeader">
Expand Down
28 changes: 20 additions & 8 deletions src/routes/Chain/ChainState/StorageItems.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2024 @polkadot-cloud/polkadot-developer-console authors & contributors
// SPDX-License-Identifier: GPL-3.0-only

import { useMemo } from 'react';
import { useEffect, useMemo } from 'react';
import { PalletList } from '../PalletList';
import { PalletScraper } from 'model/Scraper/Pallet';
import { useChainUi } from 'contexts/ChainUi';
Expand All @@ -17,21 +17,24 @@ import { camelize } from '@w3ux/utils';
import { Results } from './Results';
import { InputFormProvider } from '../InputForm/provider';
import { InputForm } from '../InputForm';
import type { InputNamespace } from 'contexts/ChainUi/types';

export const StorageItems = () => {
const { tabId } = useActiveTab();
const { chainSpec, instanceId } = useChain();
const { getChainUi, setChainUiNamespace } = useChainUi();
const { getChainUi, setChainUiNamespace, resetInputArgSection } =
useChainUi();

const chainUiSection = 'storage';
const inputNamespace: InputNamespace = 'storage';
const chainUi = getChainUi(tabId, chainUiSection);
const Metadata = chainSpec.metadata;

// Fetch storage items when metadata or the selected pallet changes.
const scrapedStorageList = useMemo(() => {
// Get pallet list from scraper.
const scraper = new PalletScraper(Metadata, { maxDepth: 7 });
const pallets = scraper.getPalletList(['storage']);
const pallets = scraper.getPalletList([chainUiSection]);

// If no pallet selected, get first one from scraper or fall back to null.
const activePallet = chainUi.pallet || pallets?.[0].name || null;
Expand Down Expand Up @@ -94,19 +97,27 @@ export const StorageItems = () => {
});
};

// Manage `activeItem` changes.
useEffect(() => {
// On initial render, set the selected item to the first list item, if any.
if (activeItem) {
setChainUiNamespace(tabId, chainUiSection, 'selected', activeItem);
}
}, [activeItem]);

return (
<InputFormProvider
namespace="storage"
activeItem={activeItem}
scraper={itemScraper}
>
<InputFormProvider namespace={inputNamespace} scraper={itemScraper}>
<SelectFormWrapper className="withHeader">
<PalletList
pallets={pallets}
activePallet={activePallet}
chainUiSection={chainUiSection}
onSelect={(value) => {
// Update selected pallet in chain ui state.
setChainUiNamespace(tabId, chainUiSection, 'pallet', value);

// Reset input args when selected pallet changes.
resetInputArgSection(tabId, inputNamespace);
}}
/>
<ChainStateList
Expand All @@ -115,6 +126,7 @@ export const StorageItems = () => {
items={items}
activeItem={activeItem}
chainUiSection={chainUiSection}
inputNamespace={inputNamespace}
/>
</SelectFormWrapper>
<InputForm
Expand Down
1 change: 1 addition & 0 deletions src/routes/Chain/ChainState/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export interface ChainStateListProps {
activeItem: string | null;
chainUiSection: ChainStateSection;
scraper: PalletScraper | null;
inputNamespace?: InputNamespace;
}

export interface EncodedDetailsProps {
Expand Down
25 changes: 11 additions & 14 deletions src/routes/Chain/Extrinsics/CallList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@ import { SearchInput } from 'library/ContextMenu/SearchInput';
import { SelectDropdown } from 'library/SelectDropdown';
import type { CallListItem, CallListProps } from './types';
import { SelectItemWrapper, SelectTextWrapper } from 'library/Inputs/Wrappers';
import { useInputForm } from '../InputForm/provider';
import type { InputNamespace } from 'contexts/ChainUi/types';

export const CallList = ({ items, activeItem }: CallListProps) => {
export const CallList = ({ items }: CallListProps) => {
const { tabId } = useActiveTab();
const { namespace } = useInputForm();
const { getChainUi, setChainUiNamespace, resetInputArgSection } =
useChainUi();

const chainUiSection = 'calls';
const inputNamespace: InputNamespace = 'call';
const chainUi = getChainUi(tabId, chainUiSection);

// Call selection open.
Expand All @@ -36,6 +36,13 @@ export const CallList = ({ items, activeItem }: CallListProps) => {
setChainUiNamespace(tabId, chainUiSection, 'search', value);
};

// Handle call change.
const handleCallChange = (name: string) => {
setChainUiNamespace(tabId, chainUiSection, 'selected', name);
resetInputArgSection(tabId, inputNamespace);
setCallsOpen(false);
};

// Filter calls based on search term, if selection is present.
const filteredCalls =
items.length > 0
Expand All @@ -60,13 +67,6 @@ export const CallList = ({ items, activeItem }: CallListProps) => {
}
}, [callsOpen]);

// Reset input args when active item changes.
useEffect(() => {
if (namespace) {
resetInputArgSection(tabId, namespace);
}
}, [activeItem]);

return (
<section>
<div className="inner">
Expand Down Expand Up @@ -113,10 +113,7 @@ export const CallList = ({ items, activeItem }: CallListProps) => {
<SelectItemWrapper
key={`call_select_${name}`}
className="option"
onClick={() => {
setChainUiNamespace(tabId, chainUiSection, 'selected', name);
setCallsOpen(false);
}}
onClick={() => handleCallChange(name)}
>
<span>
<SelectTextWrapper>
Expand Down
Loading

0 comments on commit ed91406

Please sign in to comment.