mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-11-22 09:57:02 +01:00
enable disconnecting single or all accounts
This commit is contained in:
parent
d45956b2b7
commit
15958683e5
@ -16,10 +16,13 @@
|
||||
"disconnect": {
|
||||
"message": "Disconnect"
|
||||
},
|
||||
"disconnectSite": {
|
||||
"message": "Disconnect $1?"
|
||||
"disconnectAllAccounts": {
|
||||
"message": "Disconnect all accounts"
|
||||
},
|
||||
"disconnectSiteConfirmationDescription": {
|
||||
"disconnectPrompt": {
|
||||
"message": "Disconnect $1"
|
||||
},
|
||||
"disconnectAllAccountsConfirmationDescription": {
|
||||
"message": "Are you sure you want to disconnect? You may lose site functionality."
|
||||
},
|
||||
"dismiss": {
|
||||
|
@ -40,7 +40,7 @@
|
||||
"ganache:start": "./development/run-ganache",
|
||||
"sentry:publish": "node ./development/sentry-publish.js",
|
||||
"lint": "eslint . --ext js,json",
|
||||
"lint:fix": "eslint --ext js,json --fix",
|
||||
"lint:fix": "eslint . --ext js,json --fix",
|
||||
"lint:changed": "{ git ls-files --others --exclude-standard ; git diff-index --name-only --diff-filter=d HEAD ; } | grep --regexp='[.]js$' --regexp='[.]json$' | tr '\\n' '\\0' | xargs -0 eslint",
|
||||
"lint:changed:fix": "{ git ls-files --others --exclude-standard ; git diff-index --name-only --diff-filter=d HEAD ; } | grep --regexp='[.]js$' --regexp='[.]json$' | tr '\\n' '\\0' | xargs -0 eslint --fix",
|
||||
"lint:shellcheck": "./development/shellcheck.sh",
|
||||
|
@ -13,20 +13,20 @@ export default class ConnectedSitesList extends Component {
|
||||
icon: PropTypes.string,
|
||||
key: PropTypes.string,
|
||||
})).isRequired,
|
||||
onDisconnectSite: PropTypes.func.isRequired,
|
||||
onDisconnect: PropTypes.func.isRequired,
|
||||
}
|
||||
|
||||
render () {
|
||||
const { connectedDomains, onDisconnectSite } = this.props
|
||||
const { connectedDomains, onDisconnect } = this.props
|
||||
const { t } = this.context
|
||||
|
||||
return (
|
||||
<main className="connected-sites__content-rows">
|
||||
<main className="connected-sites-list__content-rows">
|
||||
{ connectedDomains.map((domain) => (
|
||||
<div key={domain.key} className="connected-sites__content-row">
|
||||
<div className="connected-sites__domain-info">
|
||||
<div key={domain.key} className="connected-sites-list__content-row">
|
||||
<div className="connected-sites-list__domain-info">
|
||||
<IconWithFallBack icon={domain.icon} name={domain.name} />
|
||||
<span className="connected-sites__domain-name" title={domain.extensionId || domain.key}>
|
||||
<span className="connected-sites-list__domain-name" title={domain.extensionId || domain.key}>
|
||||
{
|
||||
domain.extensionId
|
||||
? t('externalExtension')
|
||||
@ -35,9 +35,9 @@ export default class ConnectedSitesList extends Component {
|
||||
</span>
|
||||
</div>
|
||||
<i
|
||||
className="fas fa-trash-alt connected-sites__trash"
|
||||
className="fas fa-trash-alt connected-sites-list__trash"
|
||||
title={t('disconnect')}
|
||||
onClick={() => onDisconnectSite(domain.key, domain.name)}
|
||||
onClick={() => onDisconnect(domain.key, domain.name)}
|
||||
/>
|
||||
</div>
|
||||
)) }
|
||||
|
@ -1,4 +1,4 @@
|
||||
.connected-sites {
|
||||
.connected-sites-list {
|
||||
&__content-rows {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
@ -61,7 +61,7 @@
|
||||
&__button {
|
||||
background: none;
|
||||
font-size: inherit;
|
||||
padding: 0;
|
||||
padding: 0 0 0 10px;
|
||||
}
|
||||
|
||||
i {
|
||||
|
@ -4,7 +4,7 @@ import ConnectedSitesList from '../../components/app/connected-sites-list'
|
||||
import Popover from '../../components/ui/popover/popover.component'
|
||||
import Button from '../../components/ui/button'
|
||||
|
||||
export default class ConnectSites extends Component {
|
||||
export default class ConnectedSites extends Component {
|
||||
static contextTypes = {
|
||||
t: PropTypes.func,
|
||||
}
|
||||
@ -17,22 +17,26 @@ export default class ConnectSites extends Component {
|
||||
accountLabel: PropTypes.string.isRequired,
|
||||
closePopover: PropTypes.func.isRequired,
|
||||
connectedDomains: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
disconnectSite: PropTypes.func.isRequired,
|
||||
tabToConnect: PropTypes.object,
|
||||
legacyExposeAccount: PropTypes.func.isRequired,
|
||||
disconnectAllAccounts: PropTypes.func.isRequired,
|
||||
disconnectAccount: PropTypes.func.isRequired,
|
||||
getOpenMetamaskTabsIds: PropTypes.func.isRequired,
|
||||
legacyExposeAccount: PropTypes.func.isRequired,
|
||||
permittedAccountsByOrigin: PropTypes.objectOf(
|
||||
PropTypes.arrayOf(PropTypes.string),
|
||||
).isRequired,
|
||||
tabToConnect: PropTypes.object,
|
||||
}
|
||||
|
||||
state = {
|
||||
sitePendingDisconnect: null,
|
||||
}
|
||||
|
||||
UNSAFE_componentWillMount () {
|
||||
componentDidMount () {
|
||||
const { getOpenMetamaskTabsIds } = this.props
|
||||
getOpenMetamaskTabsIds()
|
||||
}
|
||||
|
||||
setSitePendingDisconnect = (domainKey, domainName) => {
|
||||
setPendingDisconnect = (domainKey, domainName) => {
|
||||
this.setState({
|
||||
sitePendingDisconnect: {
|
||||
domainKey,
|
||||
@ -41,25 +45,33 @@ export default class ConnectSites extends Component {
|
||||
})
|
||||
}
|
||||
|
||||
clearSitePendingDisconnect = () => {
|
||||
clearPendingDisconnect = () => {
|
||||
this.setState({
|
||||
sitePendingDisconnect: null,
|
||||
})
|
||||
}
|
||||
|
||||
disconnect = () => {
|
||||
const { disconnectSite } = this.props
|
||||
disconnectAccount = () => {
|
||||
const { disconnectAccount } = this.props
|
||||
const { sitePendingDisconnect } = this.state
|
||||
|
||||
disconnectSite(sitePendingDisconnect.domainKey)
|
||||
this.clearSitePendingDisconnect()
|
||||
disconnectAccount(sitePendingDisconnect.domainKey)
|
||||
this.clearPendingDisconnect()
|
||||
}
|
||||
|
||||
disconnectAllAccounts = () => {
|
||||
const { disconnectAllAccounts } = this.props
|
||||
const { sitePendingDisconnect } = this.state
|
||||
|
||||
disconnectAllAccounts(sitePendingDisconnect.domainKey)
|
||||
this.clearPendingDisconnect()
|
||||
}
|
||||
|
||||
renderConnectedSitesList () {
|
||||
return (
|
||||
<ConnectedSitesList
|
||||
connectedDomains={this.props.connectedDomains}
|
||||
onDisconnectSite={this.setSitePendingDisconnect}
|
||||
onDisconnect={this.setPendingDisconnect}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@ -86,7 +98,12 @@ export default class ConnectSites extends Component {
|
||||
footer={
|
||||
tabToConnect
|
||||
? (
|
||||
<a onClick={legacyExposeAccount}>{ t('connectManually') }</a>
|
||||
<div
|
||||
className="connected-sites__text-button"
|
||||
onClick={legacyExposeAccount}
|
||||
>
|
||||
{t('connectManually')}
|
||||
</div>
|
||||
)
|
||||
: null
|
||||
}
|
||||
@ -97,25 +114,47 @@ export default class ConnectSites extends Component {
|
||||
)
|
||||
}
|
||||
|
||||
renderDisconnectSitePopover () {
|
||||
renderDisconnectPopover () {
|
||||
|
||||
const { closePopover } = this.props
|
||||
const { closePopover, permittedAccountsByOrigin } = this.props
|
||||
const { t } = this.context
|
||||
const { sitePendingDisconnect } = this.state
|
||||
const { sitePendingDisconnect: { domainKey, domainName } } = this.state
|
||||
|
||||
const numPermittedAccounts = permittedAccountsByOrigin[domainKey].length
|
||||
|
||||
return (
|
||||
<Popover
|
||||
title={t('disconnectSite', [sitePendingDisconnect.domainName])}
|
||||
subtitle={t('disconnectSiteConfirmationDescription')}
|
||||
className="connected-sites"
|
||||
title={t('disconnectPrompt', [domainName])}
|
||||
subtitle={t('disconnectAllAccountsConfirmationDescription')}
|
||||
onClose={closePopover}
|
||||
footer={(
|
||||
<>
|
||||
<Button type="secondary" onClick={this.clearSitePendingDisconnect}>
|
||||
{ t('cancel') }
|
||||
</Button>
|
||||
<Button type="primary" onClick={this.disconnect}>
|
||||
{ t('disconnect') }
|
||||
</Button>
|
||||
<div className="connected-sites__footer-row">
|
||||
<Button type="secondary" onClick={this.clearPendingDisconnect}>
|
||||
{ t('cancel') }
|
||||
</Button>
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={this.disconnectAccount}
|
||||
>
|
||||
{ t('disconnect') }
|
||||
</Button>
|
||||
</div>
|
||||
<div className="connected-sites__footer-row">
|
||||
{
|
||||
numPermittedAccounts > 1
|
||||
? (
|
||||
<div
|
||||
className="connected-sites__text-button"
|
||||
onClick={this.disconnectAllAccounts}
|
||||
>
|
||||
{t('disconnectAllAccounts')}
|
||||
</div>
|
||||
)
|
||||
: null
|
||||
}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
footerClassName="connected-sites__confirmation"
|
||||
@ -127,7 +166,7 @@ export default class ConnectSites extends Component {
|
||||
const { sitePendingDisconnect } = this.state
|
||||
return (
|
||||
sitePendingDisconnect
|
||||
? this.renderDisconnectSitePopover()
|
||||
? this.renderDisconnectPopover()
|
||||
: this.renderConnectedSitesPopover()
|
||||
)
|
||||
}
|
||||
|
@ -4,12 +4,14 @@ import {
|
||||
getOpenMetamaskTabsIds,
|
||||
legacyExposeAccounts,
|
||||
removePermissionsFor,
|
||||
removePermittedAccount,
|
||||
} from '../../store/actions'
|
||||
import {
|
||||
getConnectedDomainsForSelectedAddress,
|
||||
getCurrentAccountWithSendEtherInfo,
|
||||
getOriginOfCurrentTab,
|
||||
getPermissionsDomains,
|
||||
getPermittedAccountsForCurrentTab,
|
||||
getPermittedAccountsByOrigin,
|
||||
getSelectedAddress,
|
||||
} from '../../selectors/selectors'
|
||||
import { DEFAULT_ROUTE } from '../../helpers/constants/routes'
|
||||
@ -18,11 +20,17 @@ import { getOriginFromUrl } from '../../helpers/utils/util'
|
||||
const mapStateToProps = (state) => {
|
||||
const { openMetaMaskTabs } = state.appState
|
||||
const { title, url, id } = state.activeTab
|
||||
const permittedAccounts = getPermittedAccountsForCurrentTab(state)
|
||||
const connectedDomains = getConnectedDomainsForSelectedAddress(state)
|
||||
const originOfCurrentTab = getOriginOfCurrentTab(state)
|
||||
const permittedAccountsByOrigin = getPermittedAccountsByOrigin(state)
|
||||
const selectedAddress = getSelectedAddress(state)
|
||||
|
||||
const currentTabHasAccounts = permittedAccountsByOrigin[
|
||||
originOfCurrentTab
|
||||
]?.length
|
||||
|
||||
let tabToConnect
|
||||
if (url && permittedAccounts.length === 0 && !openMetaMaskTabs[id]) {
|
||||
if (url && !currentTabHasAccounts && !openMetaMaskTabs[id]) {
|
||||
tabToConnect = {
|
||||
title,
|
||||
origin: getOriginFromUrl(url),
|
||||
@ -33,7 +41,8 @@ const mapStateToProps = (state) => {
|
||||
accountLabel: getCurrentAccountWithSendEtherInfo(state).name,
|
||||
connectedDomains,
|
||||
domains: getPermissionsDomains(state),
|
||||
selectedAddress: getSelectedAddress(state),
|
||||
permittedAccountsByOrigin,
|
||||
selectedAddress,
|
||||
tabToConnect,
|
||||
}
|
||||
}
|
||||
@ -41,7 +50,10 @@ const mapStateToProps = (state) => {
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
getOpenMetamaskTabsIds: () => dispatch(getOpenMetamaskTabsIds()),
|
||||
disconnectSite: (domainKey, domain) => {
|
||||
disconnectAccount: (domainKey, address) => {
|
||||
dispatch(removePermittedAccount(domainKey, address))
|
||||
},
|
||||
disconnectAllAccounts: (domainKey, domain) => {
|
||||
const permissionMethodNames = domain.permissions.map(({ parentCapability }) => parentCapability)
|
||||
dispatch(removePermissionsFor({
|
||||
[domainKey]: permissionMethodNames,
|
||||
@ -53,13 +65,14 @@ const mapDispatchToProps = (dispatch) => {
|
||||
|
||||
const mergeProps = (stateProps, dispatchProps, ownProps) => {
|
||||
const {
|
||||
connectedDomains,
|
||||
domains,
|
||||
selectedAddress,
|
||||
tabToConnect,
|
||||
connectedDomains,
|
||||
} = stateProps
|
||||
const {
|
||||
disconnectSite,
|
||||
disconnectAccount,
|
||||
disconnectAllAccounts,
|
||||
legacyExposeAccounts: dispatchLegacyExposeAccounts,
|
||||
} = dispatchProps
|
||||
const { history } = ownProps
|
||||
@ -71,8 +84,14 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => {
|
||||
...stateProps,
|
||||
...dispatchProps,
|
||||
closePopover,
|
||||
disconnectSite: (domainKey) => {
|
||||
disconnectSite(domainKey, domains[domainKey])
|
||||
disconnectAccount: (domainKey) => {
|
||||
disconnectAccount(domainKey, selectedAddress)
|
||||
if (connectedDomains.length === 1) {
|
||||
closePopover()
|
||||
}
|
||||
},
|
||||
disconnectAllAccounts: (domainKey) => {
|
||||
disconnectAllAccounts(domainKey, domains[domainKey])
|
||||
if (connectedDomains.length === 1) {
|
||||
closePopover()
|
||||
}
|
||||
|
@ -1,22 +1,34 @@
|
||||
.connected-sites {
|
||||
h2 {
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
&__confirmation {
|
||||
flex-direction: column;
|
||||
button:first-child {
|
||||
margin-right: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
&__add-site-manually {
|
||||
margin-top: -1px;
|
||||
&__footer-row {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&__footer-row + &__footer-row {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
&__text-button {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
|
||||
& :only-child {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
a, a:hover {
|
||||
cursor: pointer;
|
||||
color: #037DD6;
|
||||
}
|
||||
color: #2f9ae0;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,10 @@ import {
|
||||
|
||||
import { getPermittedAccountsByOrigin } from './permissions'
|
||||
|
||||
export { getPermittedAccounts } from './permissions'
|
||||
export {
|
||||
getPermittedAccounts,
|
||||
getPermittedAccountsByOrigin,
|
||||
} from './permissions'
|
||||
|
||||
export function getNetworkIdentifier (state) {
|
||||
const { metamask: { provider: { type, nickname, rpcTarget } } } = state
|
||||
|
Loading…
Reference in New Issue
Block a user