Skip to content

Commit 25650b2

Browse files
mroz22marekrjpolak
authored andcommitted
feat(suite): add password manager as an experimental feature
1 parent cf42a0a commit 25650b2

File tree

16 files changed

+176
-142
lines changed

16 files changed

+176
-142
lines changed

packages/suite-desktop-ui/src/support/Router.tsx

+3
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import { SettingsGeneral } from 'src/views/settings/SettingsGeneral/SettingsGene
3737
import { SettingsCoins } from 'src/views/settings/SettingsCoins/SettingsCoins';
3838
import { SettingsDebug } from 'src/views/settings/SettingsDebug/SettingsDebug';
3939
import { SettingsDevice } from 'src/views/settings/SettingsDevice/SettingsDevice';
40+
import PasswordManager from 'src/views/password-manager';
4041

4142
const components: { [key: string]: ComponentType<any> } = {
4243
'suite-index': Dashboard,
@@ -71,6 +72,8 @@ const components: { [key: string]: ComponentType<any> } = {
7172
'wallet-coinmarket-savings-overview': WalletCoinmarketSavingsOverview,
7273
'wallet-coinmarket-redirect': WalletCoinmarketRedirect,
7374

75+
'password-manager-index': PasswordManager,
76+
7477
'settings-index': SettingsGeneral,
7578
'settings-coins': SettingsCoins,
7679
'settings-debug': SettingsDebug,

packages/suite-web/src/support/Router.tsx

+5
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,11 @@ const components: Record<PageName, LazyExoticComponent<ComponentType<any>>> = {
127127
() => import(/* webpackChunkName: "coinmarket" */ 'src/views/wallet/coinmarket/redirect'),
128128
),
129129

130+
// password-manager
131+
'password-manager-index': lazy(
132+
() => import(/* webpackChunkName: "password-manager" */ 'src/views/password-manager'),
133+
),
134+
130135
// settings
131136
'settings-index': lazy(() =>
132137
import(

packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/Navigation.tsx

+19
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ import styled from 'styled-components';
33
import { spacingsPx } from '@trezor/theme';
44
import { NavigationItem, NavigationItemProps } from './NavigationItem';
55
import { NotificationDropdown } from './NotificationDropdown';
6+
import { useSelector } from 'src/hooks/suite';
7+
import { selectHasExperimentalFeature } from 'src/reducers/suite/suiteReducer';
8+
import { ExperimentalFeature } from 'src/constants/suite/experimental';
69

710
const Nav = styled.nav`
811
display: flex;
@@ -11,6 +14,14 @@ const Nav = styled.nav`
1114
margin: ${spacingsPx.xs};
1215
`;
1316

17+
const PasswordManagerNavItem = (props: NavigationItemProps) => {
18+
const passwordManagerExperimentalFeature = useSelector(
19+
selectHasExperimentalFeature(ExperimentalFeature.PasswordManager),
20+
);
21+
22+
return passwordManagerExperimentalFeature ? <NavigationItem {...props} /> : null;
23+
};
24+
1425
const navItems: Array<NavigationItemProps & { CustomComponent?: FC<NavigationItemProps> }> = [
1526
{
1627
nameId: 'TR_DASHBOARD',
@@ -30,6 +41,14 @@ const navItems: Array<NavigationItemProps & { CustomComponent?: FC<NavigationIte
3041
routes: ['settings-index', 'settings-device', 'settings-coins', 'settings-debug'],
3142
dataTest: '@suite/menu/settings',
3243
},
44+
{
45+
nameId: 'TR_PASSWORD_MANAGER',
46+
icon: 'ghost',
47+
goToRoute: 'password-manager-index',
48+
routes: ['password-manager-index'],
49+
dataTest: '@suite/menu/password-manager',
50+
CustomComponent: PasswordManagerNavItem,
51+
},
3352
];
3453

3554
export const Navigation = () => (

packages/suite/src/components/suite/layouts/SuiteLayout/Sidebar/NavigationItem.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ export const NavigationItem = ({
108108
<Container
109109
$isActive={isActive || isActiveRoute}
110110
onClick={handleClick}
111-
data-test={dataTest! !== undefined ? dataTest : `@suite/menu/${goToRoute}`}
111+
data-test={dataTest || `@suite/menu/${goToRoute}`}
112112
className={className}
113113
tabIndex={0}
114114
$elevation={elevation}

packages/suite/src/support/messages.ts

+4
Original file line numberDiff line numberDiff line change
@@ -3574,6 +3574,10 @@ export default defineMessages({
35743574
defaultMessage: 'Entered wrong PIN',
35753575
id: 'TR_WRONG_PIN_ENTERED',
35763576
},
3577+
TR_PASSWORD_MANAGER: {
3578+
defaultMessage: 'Password manager',
3579+
id: 'TR_PASSWORD_MANAGER',
3580+
},
35773581
TR_SETTINGS: {
35783582
defaultMessage: 'Settings',
35793583
id: 'TR_SETTINGS',

packages/suite/src/views/settings/SettingsDebug/PasswordManager/PasswordEntry.tsx packages/suite/src/views/password-manager/PasswordManager/PasswordEntry.tsx

+1-2
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,8 @@ export const PasswordEntry = ({
106106
<>
107107
{confirmRemove != null && (
108108
<DialogModal
109-
icon="check"
110109
bodyHeading="Remove password entry"
111-
text="Really remove?"
110+
text={`Really remove ${note || title}?`}
112111
bottomBarComponents={
113112
<>
114113
<Button
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
import React, { useState } from 'react';
2+
import styled from 'styled-components';
3+
import { Button } from '@trezor/components';
4+
5+
import { TextColumn, ActionColumn } from 'src/components/suite';
6+
import { useDevice, usePasswords } from 'src/hooks/suite';
7+
import { getNextId } from 'src/utils/suite/passwords';
8+
9+
import { EntryForm } from './EntryForm';
10+
import { PasswordsList } from './PasswordsList';
11+
import { TagsList } from './TagsList';
12+
13+
const PasswordManagerBody = styled.div`
14+
display: flex;
15+
flex: 1;
16+
flex-direction: column;
17+
`;
18+
19+
const Section = styled.div`
20+
display: flex;
21+
`;
22+
23+
export const PasswordManager = () => {
24+
const {
25+
entries,
26+
tags,
27+
entriesByTag,
28+
isSomeTagSelected,
29+
config,
30+
fileName,
31+
selectedTags,
32+
setSelectedTags,
33+
connect,
34+
disconnect,
35+
selectedProvider,
36+
providerConnecting,
37+
savePasswords,
38+
device,
39+
} = usePasswords();
40+
41+
const { isLocked } = useDevice();
42+
const isDeviceLocked = isLocked();
43+
44+
const [formActive, setFormActive] = useState<null | number>(null);
45+
46+
if (!device?.state) {
47+
return <Section>Connect and authorize device</Section>;
48+
}
49+
if (providerConnecting) {
50+
return <Section>Connecting...</Section>;
51+
}
52+
53+
if (!selectedProvider || !fileName) {
54+
return (
55+
<Section>
56+
<TextColumn
57+
title="Trezor password manager"
58+
description="Re-implementation of former Trezor Password Manager webextension"
59+
/>
60+
<ActionColumn>
61+
<Button onClick={connect} isDisabled={isDeviceLocked}>
62+
Connect to Dropbox
63+
</Button>
64+
{/* TODO: connect to drive */}
65+
</ActionColumn>
66+
</Section>
67+
);
68+
}
69+
70+
return (
71+
<>
72+
<Section>
73+
<TextColumn
74+
title="Provider details"
75+
description={`type: ${selectedProvider.type}, clientId: ${selectedProvider.clientId}, connected user: ${selectedProvider.user}`}
76+
/>
77+
<ActionColumn>
78+
<Button onClick={disconnect}>Disconnect</Button>
79+
</ActionColumn>
80+
</Section>
81+
<Section>
82+
{config ? (
83+
<PasswordManagerBody>
84+
<TagsList
85+
tags={tags}
86+
selectedTags={selectedTags}
87+
setSelectedTags={setSelectedTags}
88+
/>
89+
90+
<PasswordsList
91+
isSomeTagSelected={isSomeTagSelected}
92+
formActive={formActive}
93+
entriesByTag={entriesByTag}
94+
entries={entries}
95+
savePasswords={savePasswords}
96+
setFormActive={setFormActive}
97+
fileName={fileName}
98+
nextId={getNextId(entries)}
99+
/>
100+
</PasswordManagerBody>
101+
) : (
102+
<div style={{ display: 'flex', justifyContent: 'center', flex: 1 }}>
103+
{formActive !== 0 && (
104+
<>
105+
<div>There are no passwords yet </div>
106+
<Button
107+
size="tiny"
108+
onClick={() => setFormActive(0)}
109+
type="button"
110+
variant="tertiary"
111+
icon="PENCIL"
112+
>
113+
Add the first one!
114+
</Button>
115+
</>
116+
)}
117+
{formActive === 0 && (
118+
<EntryForm
119+
cancel={() => setFormActive(null)}
120+
onEncrypted={entry => {
121+
savePasswords(getNextId(entries), entry);
122+
setFormActive(null);
123+
}}
124+
/>
125+
)}
126+
</div>
127+
)}
128+
</Section>
129+
</>
130+
);
131+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { useLayout } from 'src/hooks/suite';
2+
import { PasswordManager } from './PasswordManager/PasswordManager';
3+
4+
export default () => {
5+
useLayout('Password manager');
6+
return <PasswordManager />;
7+
};

packages/suite/src/views/settings/SettingsDebug/PasswordManager/PasswordManager.tsx

-135
This file was deleted.

packages/suite/src/views/settings/SettingsDebug/SettingsDebug.tsx

-4
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import { DeviceAuthenticity } from './DeviceAuthenticity';
1414
import { Devkit } from './Devkit';
1515
import { Transport } from './Transport';
1616
import { TransportBackends } from './TransportBackends';
17-
import { PasswordManager } from './PasswordManager/PasswordManager';
1817
import { ViewOnlySettings } from './ViewOnlySettings';
1918
import { TriggerHighlight } from './TriggerHighlight';
2019
import { Backends } from './Backends';
@@ -65,9 +64,6 @@ export const SettingsDebug = () => {
6564
<SettingsSection title="Backends">
6665
<Backends />
6766
</SettingsSection>
68-
<SettingsSection title="Password manager">
69-
<PasswordManager />
70-
</SettingsSection>
7167
<SettingsSection title="View only">
7268
<ViewOnlySettings />
7369
</SettingsSection>

0 commit comments

Comments
 (0)