From 8696052e27f93d24ab1e2c2b64f479c95a8adc72 Mon Sep 17 00:00:00 2001 From: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com> Date: Tue, 8 Aug 2023 07:50:51 -0700 Subject: [PATCH] Desktop: Resolves #8380: Always show reencrypt button (#8555) --- .eslintignore | 1 + .gitignore | 1 + .../gui/ConfigScreen/ConfigScreen.tsx | 15 ++-- .../controls/ToggleAdvancedSettingsButton.tsx | 24 ++++++ .../EncryptionConfigScreen.tsx | 84 ++++++++++++------- 5 files changed, 84 insertions(+), 41 deletions(-) create mode 100644 packages/app-desktop/gui/ConfigScreen/controls/ToggleAdvancedSettingsButton.tsx diff --git a/.eslintignore b/.eslintignore index 35722f957..a5e7e5d9f 100644 --- a/.eslintignore +++ b/.eslintignore @@ -133,6 +133,7 @@ packages/app-desktop/gui/ClipperConfigScreen.js packages/app-desktop/gui/ConfigScreen/ButtonBar.js packages/app-desktop/gui/ConfigScreen/ConfigScreen.js packages/app-desktop/gui/ConfigScreen/Sidebar.js +packages/app-desktop/gui/ConfigScreen/controls/ToggleAdvancedSettingsButton.js packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginBox.js packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginsStates.js packages/app-desktop/gui/ConfigScreen/controls/plugins/SearchPlugins.js diff --git a/.gitignore b/.gitignore index 46e6583d4..d4aa75c28 100644 --- a/.gitignore +++ b/.gitignore @@ -119,6 +119,7 @@ packages/app-desktop/gui/ClipperConfigScreen.js packages/app-desktop/gui/ConfigScreen/ButtonBar.js packages/app-desktop/gui/ConfigScreen/ConfigScreen.js packages/app-desktop/gui/ConfigScreen/Sidebar.js +packages/app-desktop/gui/ConfigScreen/controls/ToggleAdvancedSettingsButton.js packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginBox.js packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginsStates.js packages/app-desktop/gui/ConfigScreen/controls/plugins/SearchPlugins.js diff --git a/packages/app-desktop/gui/ConfigScreen/ConfigScreen.tsx b/packages/app-desktop/gui/ConfigScreen/ConfigScreen.tsx index 8b8edea21..8d94a9890 100644 --- a/packages/app-desktop/gui/ConfigScreen/ConfigScreen.tsx +++ b/packages/app-desktop/gui/ConfigScreen/ConfigScreen.tsx @@ -19,6 +19,7 @@ import PluginService from '@joplin/lib/services/plugins/PluginService'; import { getDefaultPluginsInstallState, updateDefaultPluginsInstallState } from '@joplin/lib/services/plugins/defaultPlugins/defaultPluginsUtils'; import getDefaultPluginsInfo from '@joplin/lib/services/plugins/defaultPlugins/desktopDefaultPluginsInfo'; import JoplinCloudConfigScreen from '../JoplinCloudConfigScreen'; +import ToggleAdvancedSettingsButton from './controls/ToggleAdvancedSettingsButton'; const { KeymapConfigScreen } = require('../KeymapConfig/KeymapConfigScreen'); const settingKeyToControl: any = { @@ -208,17 +209,11 @@ class ConfigScreenComponent extends React.Component<any, any> { const advancedSettingsSectionStyle = { display: 'none' }; if (advancedSettingComps.length) { - const iconName = this.state.showAdvancedSettings ? 'fa fa-angle-down' : 'fa fa-angle-right'; - // const advancedSettingsButtonStyle = { ...theme.buttonStyle, marginBottom: 10 }; advancedSettingsButton = ( - <div style={{ marginBottom: 10 }}> - <Button - level={ButtonLevel.Secondary} - onClick={() => shared.advancedSettingsButton_click(this)} - iconName={iconName} - title={_('Show Advanced Settings')} - /> - </div> + <ToggleAdvancedSettingsButton + onClick={() => shared.advancedSettingsButton_click(this)} + advancedSettingsVisible={this.state.showAdvancedSettings} + /> ); advancedSettingsSectionStyle.display = this.state.showAdvancedSettings ? 'block' : 'none'; } diff --git a/packages/app-desktop/gui/ConfigScreen/controls/ToggleAdvancedSettingsButton.tsx b/packages/app-desktop/gui/ConfigScreen/controls/ToggleAdvancedSettingsButton.tsx new file mode 100644 index 000000000..26a19eb05 --- /dev/null +++ b/packages/app-desktop/gui/ConfigScreen/controls/ToggleAdvancedSettingsButton.tsx @@ -0,0 +1,24 @@ + +import * as React from 'react'; +import Button, { ButtonLevel } from '../../Button/Button'; +import { _ } from '@joplin/lib/locale'; + +interface Props { + onClick: ()=> void; + advancedSettingsVisible: boolean; +} + +const ToggleAdvancedSettingsButton: React.FunctionComponent<Props> = props => { + const iconName = props.advancedSettingsVisible ? 'fa fa-angle-down' : 'fa fa-angle-right'; + return ( + <div style={{ marginBottom: 10 }}> + <Button + level={ButtonLevel.Secondary} + onClick={props.onClick} + iconName={iconName} + title={_('Show Advanced Settings')} + /> + </div> + ); +}; +export default ToggleAdvancedSettingsButton; diff --git a/packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx b/packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx index a4a936e7a..4e83fd16b 100644 --- a/packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx +++ b/packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.tsx @@ -10,12 +10,13 @@ import { MasterKeyEntity } from '@joplin/lib/services/e2ee/types'; import { getEncryptionEnabled, masterKeyEnabled, SyncInfo } from '@joplin/lib/services/synchronizer/syncInfoUtils'; import { getDefaultMasterKey, getMasterPasswordStatusMessage, masterPasswordIsValid, toggleAndSetupEncryption } from '@joplin/lib/services/e2ee/utils'; import Button, { ButtonLevel } from '../Button/Button'; -import { useCallback, useMemo } from 'react'; +import { useCallback, useMemo, useState } from 'react'; import { connect } from 'react-redux'; import { AppState } from '../../app.reducer'; import Setting from '@joplin/lib/models/Setting'; import CommandService from '@joplin/lib/services/CommandService'; import { PublicPrivateKeyPair } from '@joplin/lib/services/e2ee/ppk'; +import ToggleAdvancedSettingsButton from '../ConfigScreen/controls/ToggleAdvancedSettingsButton'; interface Props { themeId: any; @@ -83,34 +84,6 @@ const EncryptionConfigScreen = (props: Props) => { ); }; - const renderReencryptData = () => { - if (!shim.isElectron()) return null; - if (!props.shouldReencrypt) return null; - - const theme = themeStyle(props.themeId); - const buttonLabel = _('Re-encrypt data'); - - const intro = props.shouldReencrypt ? _('The default encryption method has been changed to a more secure one and it is recommended that you apply it to your data.') : _('You may use the tool below to re-encrypt your data, for example if you know that some of your notes are encrypted with an obsolete encryption method.'); - - let t = `${intro}\n\n${_('In order to do so, your entire data set will have to be encrypted and synchronised, so it is best to run it overnight.\n\nTo start, please follow these instructions:\n\n1. Synchronise all your devices.\n2. Click "%s".\n3. Let it run to completion. While it runs, avoid changing any note on your other devices, to avoid conflicts.\n4. Once sync is done on this device, sync all your other devices and let it run to completion.\n\nImportant: you only need to run this ONCE on one device.', buttonLabel)}`; - - t = t.replace(/\n\n/g, '</p><p>'); - t = t.replace(/\n/g, '<br>'); - t = `<p>${t}</p>`; - - return ( - <div> - <h2>{_('Re-encryption')}</h2> - <p style={theme.textStyle} dangerouslySetInnerHTML={{ __html: t }}></p> - <span style={{ marginRight: 10 }}> - <button onClick={() => void reencryptData()} style={theme.buttonStyle}>{buttonLabel}</button> - </span> - - { !props.shouldReencrypt ? null : <button onClick={() => dontReencryptData()} style={theme.buttonStyle}>{_('Ignore')}</button> } - </div> - ); - }; - const renderMasterKey = (mk: MasterKeyEntity) => { const theme = themeStyle(props.themeId); @@ -239,7 +212,6 @@ const EncryptionConfigScreen = (props: Props) => { /> ); const needUpgradeSection = renderNeedUpgradeSection(); - const reencryptDataSection = renderReencryptData(); return ( <div className="section"> @@ -254,7 +226,6 @@ const EncryptionConfigScreen = (props: Props) => { {decryptedItemsInfo} {toggleButton} {needUpgradeSection} - {props.shouldReencrypt ? reencryptDataSection : null} </div> </div> ); @@ -338,6 +309,56 @@ const EncryptionConfigScreen = (props: Props) => { return nonExistingMasterKeySection; }; + const renderReencryptData = () => { + if (!shim.isElectron()) return null; + if (!props.encryptionEnabled) return null; + + const theme = themeStyle(props.themeId); + const buttonLabel = _('Re-encrypt data'); + + const intro = props.shouldReencrypt ? _('The default encryption method has been changed to a more secure one and it is recommended that you apply it to your data.') : _('You may use the tool below to re-encrypt your data, for example if you know that some of your notes are encrypted with an obsolete encryption method.'); + + let t = `${intro}\n\n${_('In order to do so, your entire data set will have to be encrypted and synchronised, so it is best to run it overnight.\n\nTo start, please follow these instructions:\n\n1. Synchronise all your devices.\n2. Click "%s".\n3. Let it run to completion. While it runs, avoid changing any note on your other devices, to avoid conflicts.\n4. Once sync is done on this device, sync all your other devices and let it run to completion.\n\nImportant: you only need to run this ONCE on one device.', buttonLabel)}`; + + t = t.replace(/\n\n/g, '</p><p>'); + t = t.replace(/\n/g, '<br>'); + t = `<p>${t}</p>`; + + return ( + <div> + <h2>{_('Re-encryption')}</h2> + <p style={theme.textStyle} dangerouslySetInnerHTML={{ __html: t }}></p> + <span style={{ marginRight: 10 }}> + <button onClick={() => void reencryptData()} style={theme.buttonStyle}>{buttonLabel}</button> + </span> + + { !props.shouldReencrypt ? null : <button onClick={() => dontReencryptData()} style={theme.buttonStyle}>{_('Ignore')}</button> } + </div> + ); + }; + + // If the user should re-encrypt, ensure that the section is visible initially. + const [showAdvanced, setShowAdvanced] = useState<boolean>(props.shouldReencrypt); + const toggleAdvanced = useCallback(() => { + setShowAdvanced(!showAdvanced); + }, [showAdvanced]); + + const renderAdvancedSection = () => { + const reEncryptSection = renderReencryptData(); + + if (!reEncryptSection) return null; + + + return ( + <div> + <ToggleAdvancedSettingsButton + onClick={toggleAdvanced} + advancedSettingsVisible={showAdvanced}/> + { showAdvanced ? reEncryptSection : null } + </div> + ); + }; + return ( <div className="config-screen-content"> {renderDebugSection()} @@ -346,6 +367,7 @@ const EncryptionConfigScreen = (props: Props) => { {renderMasterKeySection(props.masterKeys.filter(mk => masterKeyEnabled(mk)), true)} {renderMasterKeySection(props.masterKeys.filter(mk => !masterKeyEnabled(mk)), false)} {renderNonExistingMasterKeysSection()} + {renderAdvancedSection()} </div> ); };