Skip to content

Commit

Permalink
Desktop, Mobile: Resolves #9263: Do not allow switching the sync targ…
Browse files Browse the repository at this point in the history
…et if not all resources are downloaded
  • Loading branch information
laurent22 committed Jan 27, 2024
1 parent 8abd9b4 commit 07b4117
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 11 deletions.
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -738,6 +738,7 @@ packages/lib/models/Tag.test.js
packages/lib/models/Tag.js
packages/lib/models/dateTimeFormats.test.js
packages/lib/models/settings/FileHandler.js
packages/lib/models/settings/settingValidations.js
packages/lib/models/utils/isItemId.js
packages/lib/models/utils/itemCanBeEncrypted.js
packages/lib/models/utils/paginatedFeed.js
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -718,6 +718,7 @@ packages/lib/models/Tag.test.js
packages/lib/models/Tag.js
packages/lib/models/dateTimeFormats.test.js
packages/lib/models/settings/FileHandler.js
packages/lib/models/settings/settingValidations.js
packages/lib/models/utils/isItemId.js
packages/lib/models/utils/itemCanBeEncrypted.js
packages/lib/models/utils/paginatedFeed.js
Expand Down
17 changes: 11 additions & 6 deletions packages/app-desktop/gui/ConfigScreen/ConfigScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ class ConfigScreenComponent extends React.Component<any, any> {
public componentDidMount() {
if (this.props.defaultSection) {
this.setState({ selectedSectionName: this.props.defaultSection }, () => {
this.switchSection(this.props.defaultSection);
void this.switchSection(this.props.defaultSection);
});
}
}
Expand Down Expand Up @@ -112,23 +112,25 @@ class ConfigScreenComponent extends React.Component<any, any> {
throw new Error(`Invalid screen name: ${screenName}`);
}

public switchSection(name: string) {
public async switchSection(name: string) {
const section = this.sectionByName(name);
let screenName = '';
if (section.isScreen) {
screenName = section.name;

if (this.hasChanges()) {
const ok = confirm(_('This will open a new screen. Save your current changes?'));
if (ok) shared.saveSettings(this);
if (ok) {
await shared.saveSettings(this);
}
}
}

this.setState({ selectedSectionName: section.name, screenName: screenName });
}

private sidebar_selectionChange(event: any) {
this.switchSection(event.section.name);
void this.switchSection(event.section.name);
}

public renderSectionDescription(section: any) {
Expand Down Expand Up @@ -655,12 +657,15 @@ class ConfigScreenComponent extends React.Component<any, any> {
}

public async onApplyClick() {
shared.saveSettings(this);
const done = await shared.saveSettings(this);
if (!done) return;

await this.checkNeedRestart();
}

public async onSaveClick() {
shared.saveSettings(this);
const done = await shared.saveSettings(this);
if (!done) return;
await this.checkNeedRestart();
this.props.dispatch({ type: 'NAV_BACK' });
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,8 @@ class ConfigScreenComponent extends BaseScreenComponent<ConfigScreenProps, Confi
// changedSettingKeys is cleared in shared.saveSettings so reading it now
const shouldSetIgnoreTlsErrors = this.state.changedSettingKeys.includes('net.ignoreTlsErrors');

await shared.saveSettings(this);
const done = await shared.saveSettings(this);
if (!done) return;

if (shouldSetIgnoreTlsErrors) {
await setIgnoreTlsErrors(Setting.value('net.ignoreTlsErrors'));
Expand Down
17 changes: 13 additions & 4 deletions packages/lib/components/shared/config/config-shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Logger from '@joplin/utils/Logger';

import { type ReactNode } from 'react';
import { type Registry } from '../../../registry';
import settingValidations from '../../../models/settings/settingValidations';

const logger = Logger.create('config-shared');

Expand Down Expand Up @@ -78,7 +79,7 @@ export const checkSyncConfig = async (comp: ConfigScreenComponent, settings: any

if (result.ok) {
// Users often expect config to be auto-saved at this point, if the config check was successful
saveSettings(comp);
await saveSettings(comp);
}
return result;
};
Expand Down Expand Up @@ -132,15 +133,21 @@ let scheduleSaveSettingsIID: ReturnType<typeof setTimeout>|null = null;
export const scheduleSaveSettings = (comp: ConfigScreenComponent) => {
if (scheduleSaveSettingsIID) clearTimeout(scheduleSaveSettingsIID);

scheduleSaveSettingsIID = setTimeout(() => {
scheduleSaveSettingsIID = setTimeout(async () => {
scheduleSaveSettingsIID = null;
saveSettings(comp);
await saveSettings(comp);
}, 100);
};

export const saveSettings = (comp: ConfigScreenComponent) => {
export const saveSettings = async (comp: ConfigScreenComponent) => {
const savedSettingKeys = comp.state.changedSettingKeys.slice();

const validationMessage = await settingValidations(savedSettingKeys, comp.state.settings);
if (validationMessage) {
alert(validationMessage);
return false;
}

for (const key in comp.state.settings) {
if (!comp.state.settings.hasOwnProperty(key)) continue;
if (comp.state.changedSettingKeys.indexOf(key) < 0) continue;
Expand All @@ -150,6 +157,8 @@ export const saveSettings = (comp: ConfigScreenComponent) => {
comp.setState({ changedSettingKeys: [] });

onSettingsSaved({ savedSettingKeys });

return true;
};

export const settingsToComponents = (comp: ConfigScreenComponent, device: AppType, settings: any) => {
Expand Down
57 changes: 57 additions & 0 deletions packages/lib/models/settings/settingValidations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { _ } from '../../locale';
import shim from '../../shim';
import BaseItem from '../BaseItem';
import Resource from '../Resource';
import Setting from '../Setting';

// Should return an error message if there's a problem, and an empty string if not.
type ValidationHandler = (oldValue: any, newValue: any)=> Promise<string>;

const validations: Record<string, ValidationHandler> = {

'sync.target': async (oldValue: number, newValue: number) => {
if (oldValue === 0 || newValue === 0) return '';

const preventChangeMessage = async () => {
const needToBeFetched = await Resource.needToBeFetched('always', 1);
if (needToBeFetched.length) return _('Some attachments need to be downloaded. Set the attachment download mode to "always" and try again.');

const downloadErrorCount = await Resource.downloadStatusCounts(Resource.FETCH_STATUS_ERROR);
if (downloadErrorCount > 0) return _('Some attachments could not be downloaded. Please try to download them again.');

const disabledCount = await BaseItem.syncDisabledItemsCount(Setting.value('sync.target'));
if (disabledCount > 0) return _('Some items could not be synchronised. Please try to synchronise them first.');

return '';
};

const message = await preventChangeMessage();
if (message) {
const resolutionMessage = shim.isReactNative() ?
_('Uninstall and reinstall the application. Make sure you create a backup first by exporting all your notes as JEX from the desktop application.') :
_('Close the application, then delete your profile in "%s", and start the application again. Make sure you create a backup first by exporting all your notes as JEX.', Setting.value('profileDir'));

return _('The sync target cannot be changed for the following reason: %s\n\nIf the issue cannot be resolved, you may need to clear your data first by following these instructions:\n\n%s', message, resolutionMessage);
}

return '';
},

};

const validateSetting = async (settingName: string, oldValue: any, newValue: any) => {
if (oldValue === newValue) return '';
if (!validations[settingName]) return '';

return await validations[settingName](oldValue, newValue);
};

export default async (settingKeys: string[], newValues: Record<string, any>) => {
for (const key of settingKeys) {
const oldValue = Setting.value(key);
const newValue = newValues[key];
const message = await validateSetting(key, oldValue, newValue);
return message;
}
return '';
};

0 comments on commit 07b4117

Please sign in to comment.