Skip to content
This repository has been archived by the owner on Dec 11, 2019. It is now read-only.

Commit

Permalink
allow sync devices to be removed
Browse files Browse the repository at this point in the history
fix #9254
fix #12356
  • Loading branch information
cezaraugusto committed Apr 3, 2018
1 parent aa76fe1 commit 9e37bf5
Show file tree
Hide file tree
Showing 7 changed files with 135 additions and 2 deletions.
6 changes: 6 additions & 0 deletions app/extensions/brave/locales/en-US/preferences.properties
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,12 @@ syncNewDeviceButton=Sync a new device…
syncPhoneOrTablet=Phone/Tablet
syncQRCode=QR Code
syncQRImg.title=Brave sync QR code
syncRemove=Remove
syncRemoveDeviceModal=Remove "{{device}}" from this sync chain?
syncRemoveDevice.title=Remove this device
syncRemoveActiveDeviceWarning1=Local device data will remain intact on all devices. Other devices in this sync chain will remain sync'd.
syncRemoveActiveDeviceWarning2=To join a sync chain again, choose "Enter a sync chain code".
syncRemoveOtherDeviceWarning= Note: Removing this device from this sync chain does not clear previously sync'd data from the device.
syncReset=Reset Sync
syncResetDataDisabled=This feature is only available when Sync is enabled.
syncResetMessageOtherDevices=If you've synced other devices, they will continue to sync their future browsing data. If you don't want that, you should reset Sync on those devices as well.
Expand Down
106 changes: 105 additions & 1 deletion app/renderer/components/preferences/syncTab.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ const syncComputerImage = require('../../../extensions/brave/img/sync/device_typ
const syncPlusImage = require('../../../extensions/brave/img/sync/add_device_titleicon.svg')
const syncCodeImage = require('../../../extensions/brave/img/sync/synccode_titleicon.svg')
const syncHandImage = require('../../../extensions/brave/img/sync/hand_image.png')
const syncRemoveImage = require('../../../extensions/brave/img/sync/remove_device_titleicon.svg')
const removeIcon = require('../../../extensions/brave/img/ledger/icon_remove.svg')
const syncPassphraseInputSize = 16

class SyncTab extends ImmutableComponent {
Expand All @@ -53,8 +55,12 @@ class SyncTab extends ImmutableComponent {
this.onCopy = this.copyPassphraseToClipboard.bind(this)
this.state = {
wordCount: 0,
deviceIdToRemove: '',
deviceNameToRemove: '',
isRemovingMainDevice: '',
currentDeviceOption: ''
}
this.onRemove = this.removeSyncDevice.bind(this)
}

get setupError () {
Expand Down Expand Up @@ -204,6 +210,15 @@ class SyncTab extends ImmutableComponent {
)
}

onClickSyncRemoveButton (e) {
// create a temporary state to host the device to be removed
this.setState({deviceIdToRemove: e.target.id})
this.setState({deviceNameToRemove: e.target.dataset.deviceName})
this.setState({isRemovingMainDevice: e.target.dataset.mainDevice})
// hide the current modal
this.props.showOverlay('syncRemove')
}

get devicesTableRows () {
const devices = this.props.syncData.get('devices')
if (!devices) { return [] }
Expand All @@ -215,6 +230,17 @@ class SyncTab extends ImmutableComponent {
{
html: new Date(device.get('lastRecordTimestamp')).toLocaleString(),
value: device.get('lastRecordTimestamp')
},
{
html: <span
id={id}
data-main-device={device.get('mainDevice')}
data-device-name={device.get('name')}
data-l10n-id='syncRemoveDevice'
className={css(styles.actionIcons__icon, styles.actionIcons__icon_remove)}
onClick={this.onClickSyncRemoveButton.bind(this)}
/>,
value: ''
}
])
}
Expand All @@ -225,7 +251,7 @@ class SyncTab extends ImmutableComponent {
<Grid gap={0} columns={2}>
<Column size={1}>
<SortableTable
headings={['syncDeviceName', 'syncDeviceLastActive']}
headings={['syncDeviceName', 'syncDeviceLastActive', 'remove']}
defaultHeading='syncDeviceLastActive'
defaultHeadingSortOrder='desc'
rows={this.devicesTableRows}
Expand Down Expand Up @@ -716,6 +742,42 @@ class SyncTab extends ImmutableComponent {
</section>
}

get removeOverlayContent () {
return (
<Grid gap={0} columns={1} padding='0 77px'>
<Column>
{
this.state.isRemovingMainDevice
? (
<div>
<p
className={css(styles.settingsListContainerMargin__bottom)} data-l10n-id='syncRemoveActiveDeviceWarning1'
/>
<p data-l10n-id='syncRemoveActiveDeviceWarning2' />
</div>
)
: <p data-l10n-id='syncRemoveOtherDeviceWarning' />
}
</Column>
</Grid>
)
}

get removeOverlayFooter () {
return <section>
<BrowserButton groupedItem secondaryColor
l10nId='cancel'
testId='cancelButton'
onClick={this.props.hideOverlay.bind(this, 'syncRemove')}
/>
<BrowserButton groupedItem primaryColor
l10nId='syncRemove'
testId='syncRemoveButton'
onClick={this.onRemove}
/>
</section>
}

enableRestore (e) {
if (e.target.value.length > 0) {
const wordCount = e.target.value
Expand Down Expand Up @@ -764,6 +826,21 @@ class SyncTab extends ImmutableComponent {
}
}

removeSyncDevice (e) {
const targetDeviceId = this.state.deviceIdToRemove
const isMainDevice = this.state.isRemovingMainDevice

// if it's the main device, reset sync completely
if (isMainDevice) {
aboutActions.resetSync()
appActions.syncSetupCompleted(false)
} else {
appActions.removeSyncDevice(targetDeviceId)
}
// hide the current overlay
this.props.hideOverlay('syncRemove')
}

restoreSyncProfile () {
if (this.passphraseInput.value) {
let text = this.passphraseInput.value.toLowerCase().replace(/,/g, ' ').replace(/\s+/g, ' ').trim()
Expand Down Expand Up @@ -858,6 +935,18 @@ class SyncTab extends ImmutableComponent {
onHide={this.props.hideOverlay.bind(this, 'syncReset')} />
: null
}
{
this.props.syncRemoveOverlayVisible
? <ModalOverlay
whiteOverlay
title={'syncRemoveDeviceModal'}
titleImage={syncRemoveImage}
titleArgs={{device: this.state.deviceNameToRemove}}
content={this.removeOverlayContent}
footer={this.removeOverlayFooter}
onHide={this.props.hideOverlay.bind(this, 'syncRemove')} />
: null
}
<section className={css(styles.settingsListContainerMargin__bottom)}>
{
this.setupError
Expand Down Expand Up @@ -1070,6 +1159,21 @@ const styles = StyleSheet.create({
alignItems: 'center'
},

actionIcons__icon: {
backgroundColor: '#c4c5c5',
width: '1rem',
height: '1rem',
display: 'inline-block',

':hover': {
backgroundColor: globalStyles.color.buttonColor
}
},

actionIcons__icon_remove: {
'-webkit-mask-image': `url(${removeIcon})`
},

sync__button_block: {
display: 'block',
margin: '0 15px 15px',
Expand Down
2 changes: 2 additions & 0 deletions js/about/preferences.js
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,7 @@ class AboutPreferences extends React.Component {
syncChainCodeOverlayVisible: false,
syncQRPassphraseOverlayVisible: false,
syncResetOverlayVisible: false,
syncRemoveOverlayVisible: false,
syncRestoreEnabled: false,
preferenceTab: this.tabFromCurrentHash,
hintNumber: this.getNextHintNumber(),
Expand Down Expand Up @@ -672,6 +673,7 @@ class AboutPreferences extends React.Component {
syncChainCodeOverlayVisible={this.state.syncChainCodeOverlayVisible}
syncQRPassphraseOverlayVisible={this.state.syncQRPassphraseOverlayVisible}
syncResetOverlayVisible={this.state.syncResetOverlayVisible}
syncRemoveOverlayVisible={this.state.syncRemoveOverlayVisible}
/>
break
case preferenceTabs.SHIELDS:
Expand Down
10 changes: 10 additions & 0 deletions js/actions/appActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -1074,6 +1074,16 @@ const appActions = {
})
},

/**
* Dispatches a message to stop syncing the requested device.
*/
removeSyncDevice: function (deviceId) {
dispatch({
actionType: appConstants.APP_REMOVE_SYNC_DEVICE,
deviceId
})
},

/**
* Tells the store that user has finish setting up Sync
*/
Expand Down
1 change: 1 addition & 0 deletions js/constants/appConstants.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ const appConstants = {
APP_SAVE_SYNC_INIT_DATA: _,
APP_RESET_SYNC_DATA: _,
APP_SET_SYNC_SETUP_ERROR: _,
APP_REMOVE_SYNC_DEVICE: _,
APP_SETUP_SYNC_COMPLETED: _,
APP_ADD_NOSCRIPT_EXCEPTIONS: _,
APP_TAB_MESSAGE_BOX_SHOWN: _,
Expand Down
8 changes: 8 additions & 0 deletions js/stores/appStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const {HrtimeLogger} = require('../../app/common/lib/logUtil')
const platformUtil = require('../../app/common/lib/platformUtil')
const urlUtil = require('../lib/urlutil')
const buildConfig = require('../constants/buildConfig')
const {getSetting} = require('../../js/settings')

// state helpers
const {makeImmutable, findNullKeyPaths} = require('../../app/common/state/immutableUtil')
Expand Down Expand Up @@ -560,6 +561,7 @@ const handleAppAction = (action) => {
}
break
case appConstants.APP_SAVE_SYNC_DEVICES:
const hasMainDevice = appState.getIn(['sync', 'devices']).some(device => device.get('mainDevice'))
for (let deviceId of Object.keys(action.devices)) {
const device = action.devices[deviceId]
if (device.lastRecordTimestamp) {
Expand All @@ -568,6 +570,9 @@ const handleAppAction = (action) => {
if (device.name) {
appState = appState.setIn(['sync', 'devices', deviceId, 'name'], device.name)
}
if (!hasMainDevice && getSetting(settings.SYNC_DEVICE_NAME) === device.name) {
appState = appState.setIn(['sync', 'devices', deviceId, 'mainDevice'], true)
}
}
break
case appConstants.APP_SAVE_SYNC_INIT_DATA:
Expand Down Expand Up @@ -614,6 +619,9 @@ const handleAppAction = (action) => {
appState = appState.setIn(['sync', 'devices'], {})
appState = appState.setIn(['sync', 'objectsById'], {})
break
case appConstants.APP_REMOVE_SYNC_DEVICE:
appState = appState.deleteIn(['sync', 'devices', action.deviceId])
break
case appConstants.APP_SETUP_SYNC_COMPLETED:
appState = appState.setIn(['sync', 'setupCompleted'], action.isCompleted)
break
Expand Down
4 changes: 3 additions & 1 deletion test/unit/about/preferencesTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,15 @@ describe('Preferences component unittest', function () {
mockery.registerMock('../../../../../../extensions/brave/img/ledger/cryptoIcons/LTC_icon.svg')
mockery.registerMock('../../../../../../extensions/brave/img/ledger/cryptoIcons/BAT_icon.svg')
// Mock image from addFundsDialogFooter
mockery.registerMock('../../../../../extensions/brave/img/ledger/uphold_logo_medium.png')
mockery.registerMock('../../../../../extension s/brave/img/ledger/uphold_logo_medium.png')
mockery.registerMock('../../../extensions/brave/img/sync/circle_of_sync_landing_graphic.svg')
mockery.registerMock('../../../extensions/brave/img/sync/device_type_phone-tablet.svg')
mockery.registerMock('../../../extensions/brave/img/sync/device_type_computer.svg')
mockery.registerMock('../../../extensions/brave/img/sync/add_device_titleicon.svg')
mockery.registerMock('../../../extensions/brave/img/sync/synccode_titleicon.svg')
mockery.registerMock('../../../extensions/brave/img/sync/hand_image.png')
mockery.registerMock('../../../extensions/brave/img/ledger/icon_remove.svg')
mockery.registerMock('../../../extensions/brave/img/sync/remove_device_titleicon.svg')

mockery.registerMock('electron', fakeElectron)

Expand Down

0 comments on commit 9e37bf5

Please sign in to comment.