Commit 1368bca1 authored by Hanwen Cheng's avatar Hanwen Cheng Committed by Thibaut Sardan
Browse files

feat: enable path derivation from existed path card (#516)

* feat: enable derive path from existed path

* add test for getNetworkKey function

* update UI with input path

* fix naming and account related text
parent cda2c04e
Pipeline #74836 passed with stages
in 15 minutes and 43 seconds
......@@ -19,6 +19,7 @@
import {
deserializeIdentities,
getExistedNetworkKeys,
getNetworkKeyByPath,
getPathName,
groupPaths,
serializeIdentities
......@@ -231,4 +232,18 @@ describe('IdentitiesUtils', () => {
UnknownNetworkKeys.UNKNOWN
]);
});
it('get networkKey correctly by path', () => {
expect(getNetworkKeyByPath('')).toEqual(UnknownNetworkKeys.UNKNOWN);
expect(getNetworkKeyByPath('//kusama')).toEqual(
SubstrateNetworkKeys.KUSAMA
);
expect(getNetworkKeyByPath('//kusama//derived//anything')).toEqual(
SubstrateNetworkKeys.KUSAMA
);
expect(getNetworkKeyByPath('1')).toEqual(EthereumNetworkKeys.FRONTIER);
expect(getNetworkKeyByPath('//anything/could/be')).toEqual(
UnknownNetworkKeys.UNKNOWN
);
});
});
......@@ -24,7 +24,7 @@ import AccountCard from '../components/AccountCard';
import QrView from '../components/QrView';
import PopupMenu from '../components/PopupMenu';
import { NETWORK_LIST, NetworkProtocols } from '../constants';
import { alertDeleteAccount } from '../util/alertUtils';
import { alertDeleteLegacyAccount } from '../util/alertUtils';
import {
navigateToLandingPage,
navigateToLegacyAccountList
......@@ -49,7 +49,7 @@ function AccountDetails({ accounts, navigation }) {
NetworkProtocols.UNKNOWN;
const onDelete = () => {
alertDeleteAccount(
alertDeleteLegacyAccount(
account.name || account.address || 'this account',
async () => {
await accounts.deleteAccount(selectedKey);
......
......@@ -175,7 +175,9 @@ function AccountNetworkChooser({ navigation, accounts }) {
<>
<NetworkCard
isAdd={true}
onPress={() => navigation.navigate('PathDerivation')}
onPress={() =>
navigation.navigate('PathDerivation', { parentPath: '' })
}
testID={testIDs.AccountNetworkChooser.addCustomNetworkButton}
title="Create Custom Path"
networkColor={colors.bg}
......
......@@ -30,7 +30,6 @@ import {
navigateToPathsList,
unlockSeedPhrase
} from '../util/navigationHelpers';
import { NETWORK_LIST } from '../constants';
import { alertPathDerivationError } from '../util/alertUtils';
import testIDs from '../../e2e/testIDs';
import Separator from '../components/Separator';
......@@ -44,13 +43,9 @@ function PathDerivation({ accounts, navigation }) {
const [keyPairsName, setKeyPairsName] = useState('');
const [isPathValid, setIsPathValid] = useState(true);
const pathNameInput = useRef(null);
const inheritNetworkKey = navigation.getParam('networkKey');
const isCustomPath = inheritNetworkKey === undefined;
const networkKey = inheritNetworkKey || getNetworkKeyByPath(derivationPath);
const currentNetworkPath = `//${NETWORK_LIST[networkKey].pathId}`;
const completePath = isCustomPath
? derivationPath
: `${currentNetworkPath}${derivationPath}`;
const parentPath = navigation.getParam('parentPath');
const completePath = `${parentPath}${derivationPath}`;
const networkKey = getNetworkKeyByPath(completePath);
const onPathDerivation = async () => {
if (!validateDerivedPath(derivationPath)) {
......@@ -75,7 +70,7 @@ function PathDerivation({ accounts, navigation }) {
<View style={styles.container}>
<ScreenHeading
title="Derive Account"
subtitle={currentNetworkPath}
subtitle={parentPath}
hasSubtitleIcon={true}
/>
<KeyboardScrollView extraHeight={Platform.OS === 'ios' ? 250 : 180}>
......@@ -112,7 +107,7 @@ function PathDerivation({ accounts, navigation }) {
disabled={!validateDerivedPath(derivationPath)}
bottom={false}
style={{ marginTop: 8 }}
title="Derive Address"
title="Next"
testID={testIDs.PathDerivation.deriveButton}
onPress={onPathDerivation}
/>
......
......@@ -58,23 +58,29 @@ export function PathDetailsView({ accounts, navigation, path, networkKey }) {
const formattedNetworkKey = isUnknownNetwork ? defaultNetworkKey : networkKey;
const onOptionSelect = value => {
if (value === 'PathDelete') {
alertDeleteAccount('this key pairs', async () => {
await unlockSeedPhrase(navigation);
const deleteSucceed = await accounts.deletePath(path);
const paths = Array.from(accounts.state.currentIdentity.meta.keys());
const listedPaths = getPathsWithSubstrateNetwork(paths, networkKey);
const hasOtherPaths = listedPaths.length > 0;
if (deleteSucceed) {
isSubstratePath(path) && !isRootPath && hasOtherPaths
? navigateToPathsList(navigation, networkKey)
: navigation.navigate('AccountNetworkChooser');
} else {
alertPathDeletionError();
}
});
} else {
navigation.navigate('PathManagement', { path });
switch (value) {
case 'PathDelete':
alertDeleteAccount('this account', async () => {
await unlockSeedPhrase(navigation);
const deleteSucceed = await accounts.deletePath(path);
const paths = Array.from(accounts.state.currentIdentity.meta.keys());
const listedPaths = getPathsWithSubstrateNetwork(paths, networkKey);
const hasOtherPaths = listedPaths.length > 0;
if (deleteSucceed) {
isSubstratePath(path) && !isRootPath && hasOtherPaths
? navigateToPathsList(navigation, networkKey)
: navigation.navigate('AccountNetworkChooser');
} else {
alertPathDeletionError();
}
});
break;
case 'PathDerivation':
navigation.navigate('PathDerivation', { parentPath: path });
break;
case 'PathManagement':
navigation.navigate('PathManagement', { path });
break;
}
};
......@@ -91,6 +97,7 @@ export function PathDetailsView({ accounts, navigation, path, networkKey }) {
menuTriggerIconName={'more-vert'}
menuItems={[
{ hide: isUnknownNetwork, text: 'Edit', value: 'PathManagement' },
{ text: 'Derive Account', value: 'PathDerivation' },
{
testID: testIDs.PathDetail.deleteButton,
text: 'Delete',
......
......@@ -36,7 +36,7 @@ function PathManagement({ accounts, navigation }) {
label="Display Name"
onChangeText={name => accounts.updatePathName(path, name)}
value={pathName}
placeholder="Enter a new identity name"
placeholder="Enter a new account name"
focus={true}
/>
</ScrollView>
......
......@@ -81,10 +81,10 @@ function PathsList({ accounts, navigation }) {
}
const { navigate } = navigation;
const rootPath = `//${networkParams.pathId}`;
const onClickRootPath = () => {
if (isUnknownNetworkPath) return;
const rootPath = `//${networkParams.pathId}`;
const rootPathMeta = getRootPathMeta(currentIdentity, networkKey);
if (rootPathMeta) {
navigate('PathDetails', { path: rootPath });
......@@ -154,15 +154,6 @@ function PathsList({ accounts, navigation }) {
{pathsGroup.title}
</Text>
</View>
{/*<ButtonIcon*/}
{/* iconName="plus"*/}
{/* iconType="antdesign"*/}
{/* style={{ opacity: 0.5 }}*/}
{/* onPress={() =>*/}
{/* navigation.navigate('PathDerivation', { networkKey })*/}
{/* }*/}
{/*/>*/}
</View>
</View>
{pathsGroup.paths.map(path => (
......@@ -204,7 +195,7 @@ function PathsList({ accounts, navigation }) {
testID={testIDs.PathsList.deriveButton}
title="Create New Derivation"
onPress={() =>
navigation.navigate('PathDerivation', { networkKey })
navigation.navigate('PathDerivation', { parentPath: rootPath })
}
/>
)}
......
......@@ -56,10 +56,18 @@ const buildAlertDeleteButtons = onDelete =>
buildAlertButtons(onDelete, 'Delete');
export const alertDeleteAccount = (accountName, onDelete) => {
Alert.alert(
'Delete Key Pairs',
`Do you really want to delete ${accountName}?`,
buildAlertDeleteButtons(onDelete)
);
};
export const alertDeleteLegacyAccount = (accountName, onDelete) => {
Alert.alert(
'Delete Key Pairs',
`Do you really want to delete ${accountName}?
This account can only be recovered with its associated recovery phrase.`,
The account can only be recovered with its associated recovery phrase.`,
buildAlertDeleteButtons(onDelete)
);
};
......@@ -67,7 +75,7 @@ This account can only be recovered with its associated recovery phrase.`,
export const alertDeleteIdentity = onDelete => {
Alert.alert(
'Delete Identity',
`Do you really want to delete this Identity and all the related key pairs?
`Do you really want to delete this Identity and all the related accounts?
This identity can only be recovered with its associated recovery phrase.`,
buildAlertDeleteButtons(onDelete)
);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment