2023-08-14 19:12:49 +02:00
|
|
|
const Setting = require('../../../models/Setting').default;
|
|
|
|
const SyncTargetRegistry = require('../../../SyncTargetRegistry').default;
|
|
|
|
const ObjectUtils = require('../../../ObjectUtils');
|
|
|
|
const { _ } = require('../../../locale');
|
2019-09-11 01:53:01 +02:00
|
|
|
const { createSelector } = require('reselect');
|
2023-07-27 17:05:56 +02:00
|
|
|
const Logger = require('@joplin/utils/Logger').default;
|
2022-04-13 13:38:09 +02:00
|
|
|
|
2023-01-02 20:36:39 +02:00
|
|
|
const logger = Logger.create('config-shared');
|
2018-02-06 20:59:36 +02:00
|
|
|
|
2019-07-29 15:43:53 +02:00
|
|
|
const shared = {};
|
2018-02-06 20:59:36 +02:00
|
|
|
|
2022-04-13 13:38:09 +02:00
|
|
|
shared.onSettingsSaved = () => {};
|
|
|
|
|
|
|
|
shared.init = function(comp, reg) {
|
2018-02-06 20:59:36 +02:00
|
|
|
if (!comp.state) comp.state = {};
|
|
|
|
comp.state.checkSyncConfigResult = null;
|
2018-02-13 20:26:33 +02:00
|
|
|
comp.state.settings = {};
|
|
|
|
comp.state.changedSettingKeys = [];
|
2019-12-13 03:16:34 +02:00
|
|
|
comp.state.showAdvancedSettings = false;
|
2022-04-13 13:38:09 +02:00
|
|
|
|
|
|
|
shared.onSettingsSaved = (event) => {
|
|
|
|
const savedSettingKeys = event.savedSettingKeys;
|
|
|
|
|
|
|
|
// After changing the sync settings we immediately trigger a sync
|
|
|
|
// operation. This will ensure that the client gets the sync info as
|
|
|
|
// early as possible, in particular the encryption state (encryption
|
|
|
|
// keys, whether it's enabled, etc.). This should prevent situations
|
|
|
|
// where the user tried to setup E2EE on the client even though it's
|
|
|
|
// already been done on another client.
|
|
|
|
if (savedSettingKeys.find(s => s.startsWith('sync.'))) {
|
|
|
|
logger.info('Sync settings have been changed - scheduling a sync');
|
|
|
|
void reg.scheduleSync();
|
|
|
|
}
|
|
|
|
};
|
2019-12-13 03:16:34 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
shared.advancedSettingsButton_click = (comp) => {
|
2020-05-21 10:14:33 +02:00
|
|
|
comp.setState(state => {
|
2019-12-13 03:16:34 +02:00
|
|
|
return { showAdvancedSettings: !state.showAdvancedSettings };
|
|
|
|
});
|
2019-07-29 15:43:53 +02:00
|
|
|
};
|
2018-02-06 20:59:36 +02:00
|
|
|
|
|
|
|
shared.checkSyncConfig = async function(comp, settings) {
|
2018-03-09 22:59:12 +02:00
|
|
|
const syncTargetId = settings['sync.target'];
|
2018-02-06 20:59:36 +02:00
|
|
|
const SyncTargetClass = SyncTargetRegistry.classById(syncTargetId);
|
2021-04-25 10:50:52 +02:00
|
|
|
|
2023-06-01 13:02:36 +02:00
|
|
|
const options = {
|
|
|
|
...Setting.subValues(`sync.${syncTargetId}`, settings),
|
|
|
|
...Setting.subValues('net', settings) };
|
2021-04-25 10:50:52 +02:00
|
|
|
|
2018-03-09 22:59:12 +02:00
|
|
|
comp.setState({ checkSyncConfigResult: 'checking' });
|
2018-03-15 19:57:11 +02:00
|
|
|
const result = await SyncTargetClass.checkConfig(ObjectUtils.convertValuesToFunctions(options));
|
2018-02-06 20:59:36 +02:00
|
|
|
comp.setState({ checkSyncConfigResult: result });
|
2019-12-13 03:16:34 +02:00
|
|
|
|
|
|
|
if (result.ok) {
|
|
|
|
// Users often expect config to be auto-saved at this point, if the config check was successful
|
|
|
|
shared.saveSettings(comp);
|
|
|
|
}
|
2021-04-25 10:50:52 +02:00
|
|
|
return result;
|
2019-07-29 15:43:53 +02:00
|
|
|
};
|
2018-02-06 20:59:36 +02:00
|
|
|
|
|
|
|
shared.checkSyncConfigMessages = function(comp) {
|
|
|
|
const result = comp.state.checkSyncConfigResult;
|
|
|
|
const output = [];
|
|
|
|
|
2018-03-09 22:59:12 +02:00
|
|
|
if (result === 'checking') {
|
|
|
|
output.push(_('Checking... Please wait.'));
|
2018-02-06 20:59:36 +02:00
|
|
|
} else if (result && result.ok) {
|
2018-03-09 22:59:12 +02:00
|
|
|
output.push(_('Success! Synchronisation configuration appears to be correct.'));
|
2018-02-06 20:59:36 +02:00
|
|
|
} else if (result && !result.ok) {
|
2018-03-09 22:59:12 +02:00
|
|
|
output.push(_('Error. Please check that URL, username, password, etc. are correct and that the sync target is accessible. The reported error was:'));
|
2018-02-06 20:59:36 +02:00
|
|
|
output.push(result.errorMessage);
|
|
|
|
}
|
|
|
|
|
|
|
|
return output;
|
2019-07-29 15:43:53 +02:00
|
|
|
};
|
2018-02-06 20:59:36 +02:00
|
|
|
|
2023-05-29 14:14:09 +02:00
|
|
|
shared.updateSettingValue = function(comp, key, value, callback = null) {
|
|
|
|
if (!callback) callback = () => {};
|
|
|
|
|
2020-05-21 10:14:33 +02:00
|
|
|
comp.setState(state => {
|
2023-01-02 20:36:39 +02:00
|
|
|
// @react-native-community/slider (4.4.0) will emit a valueChanged event
|
|
|
|
// when the component is mounted, even though the value hasn't changed.
|
|
|
|
// We should ignore this, otherwise it will mark the settings as
|
|
|
|
// unsaved.
|
|
|
|
//
|
|
|
|
// Upstream: https://github.com/callstack/react-native-slider/issues/395
|
|
|
|
//
|
|
|
|
// https://github.com/laurent22/joplin/issues/7503
|
|
|
|
if (state.settings[key] === value) {
|
|
|
|
logger.info('Trying to update a setting that has not changed - skipping it.', key, value);
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2023-06-01 13:02:36 +02:00
|
|
|
const settings = { ...state.settings };
|
2019-12-18 17:32:19 +02:00
|
|
|
const changedSettingKeys = state.changedSettingKeys.slice();
|
|
|
|
settings[key] = Setting.formatValue(key, value);
|
|
|
|
if (changedSettingKeys.indexOf(key) < 0) changedSettingKeys.push(key);
|
|
|
|
|
|
|
|
return {
|
|
|
|
settings: settings,
|
|
|
|
changedSettingKeys: changedSettingKeys,
|
|
|
|
};
|
2023-05-29 14:14:09 +02:00
|
|
|
}, callback);
|
2019-07-29 15:43:53 +02:00
|
|
|
};
|
2018-02-13 20:26:33 +02:00
|
|
|
|
2020-11-19 14:34:49 +02:00
|
|
|
shared.scheduleSaveSettings = function(comp) {
|
|
|
|
if (shared.scheduleSaveSettingsIID) clearTimeout(shared.scheduleSaveSettingsIID);
|
|
|
|
|
|
|
|
shared.scheduleSaveSettingsIID = setTimeout(() => {
|
|
|
|
shared.scheduleSaveSettingsIID = null;
|
|
|
|
shared.saveSettings(comp);
|
|
|
|
}, 100);
|
|
|
|
};
|
|
|
|
|
2018-02-13 20:26:33 +02:00
|
|
|
shared.saveSettings = function(comp) {
|
2022-04-13 13:38:09 +02:00
|
|
|
const savedSettingKeys = comp.state.changedSettingKeys.slice();
|
|
|
|
|
2020-03-14 01:46:14 +02:00
|
|
|
for (const key in comp.state.settings) {
|
2018-02-13 20:26:33 +02:00
|
|
|
if (!comp.state.settings.hasOwnProperty(key)) continue;
|
|
|
|
if (comp.state.changedSettingKeys.indexOf(key) < 0) continue;
|
|
|
|
Setting.setValue(key, comp.state.settings[key]);
|
|
|
|
}
|
|
|
|
|
|
|
|
comp.setState({ changedSettingKeys: [] });
|
2022-04-13 13:38:09 +02:00
|
|
|
|
|
|
|
shared.onSettingsSaved({ savedSettingKeys });
|
2019-07-29 15:43:53 +02:00
|
|
|
};
|
2018-02-13 20:26:33 +02:00
|
|
|
|
|
|
|
shared.settingsToComponents = function(comp, device, settings) {
|
|
|
|
const keys = Setting.keys(true, device);
|
|
|
|
const settingComps = [];
|
|
|
|
|
|
|
|
for (let i = 0; i < keys.length; i++) {
|
|
|
|
const key = keys[i];
|
|
|
|
if (!Setting.isPublic(key)) continue;
|
|
|
|
|
|
|
|
const md = Setting.settingMetadata(key);
|
|
|
|
if (md.show && !md.show(settings)) continue;
|
|
|
|
|
|
|
|
const settingComp = comp.settingToComponent(key, settings[key]);
|
|
|
|
if (!settingComp) continue;
|
|
|
|
settingComps.push(settingComp);
|
|
|
|
}
|
|
|
|
|
2019-07-29 15:43:53 +02:00
|
|
|
return settingComps;
|
|
|
|
};
|
2018-02-13 20:26:33 +02:00
|
|
|
|
2019-09-11 01:53:01 +02:00
|
|
|
const deviceSelector = (state) => state.device;
|
|
|
|
const settingsSelector = (state) => state.settings;
|
2019-01-28 01:15:56 +02:00
|
|
|
|
2019-09-11 01:53:01 +02:00
|
|
|
shared.settingsSections = createSelector(
|
|
|
|
deviceSelector,
|
|
|
|
settingsSelector,
|
|
|
|
(device, settings) => {
|
|
|
|
const keys = Setting.keys(true, device);
|
|
|
|
const metadatas = [];
|
2019-01-28 01:15:56 +02:00
|
|
|
|
2019-09-11 01:53:01 +02:00
|
|
|
for (let i = 0; i < keys.length; i++) {
|
|
|
|
const key = keys[i];
|
|
|
|
if (!Setting.isPublic(key)) continue;
|
2019-01-28 01:15:56 +02:00
|
|
|
|
2019-09-11 01:53:01 +02:00
|
|
|
const md = Setting.settingMetadata(key);
|
|
|
|
if (md.show && !md.show(settings)) continue;
|
|
|
|
|
|
|
|
metadatas.push(md);
|
|
|
|
}
|
|
|
|
|
|
|
|
const output = Setting.groupMetadatasBySections(metadatas);
|
|
|
|
|
|
|
|
output.push({
|
|
|
|
name: 'encryption',
|
|
|
|
metadatas: [],
|
|
|
|
isScreen: true,
|
|
|
|
});
|
|
|
|
|
|
|
|
output.push({
|
|
|
|
name: 'server',
|
|
|
|
metadatas: [],
|
|
|
|
isScreen: true,
|
|
|
|
});
|
|
|
|
|
2020-09-06 14:00:25 +02:00
|
|
|
output.push({
|
|
|
|
name: 'keymap',
|
|
|
|
metadatas: [],
|
|
|
|
isScreen: true,
|
|
|
|
});
|
|
|
|
|
2023-07-18 21:15:45 +02:00
|
|
|
// Ideallly we would also check if the user was able to synchronize
|
|
|
|
// but we don't have a way of doing that besides making a request to Joplin Cloud
|
|
|
|
const syncTargetIsJoplinCloud = settings['sync.target'] === SyncTargetRegistry.nameToId('joplinCloud');
|
|
|
|
if (syncTargetIsJoplinCloud) {
|
|
|
|
output.push({
|
|
|
|
name: 'joplinCloud',
|
|
|
|
metadatas: [],
|
|
|
|
isScreen: true,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-09-14 23:54:11 +02:00
|
|
|
const order = Setting.sectionOrder();
|
|
|
|
|
|
|
|
output.sort((a, b) => {
|
|
|
|
const o1 = order.indexOf(a.name);
|
|
|
|
const o2 = order.indexOf(b.name);
|
|
|
|
return o1 < o2 ? -1 : +1;
|
|
|
|
});
|
|
|
|
|
2019-09-11 01:53:01 +02:00
|
|
|
return output;
|
2023-08-22 12:58:53 +02:00
|
|
|
},
|
2019-09-11 01:53:01 +02:00
|
|
|
);
|
2019-01-28 01:15:56 +02:00
|
|
|
|
2019-09-11 01:53:01 +02:00
|
|
|
shared.settingsToComponents2 = function(comp, device, settings, selectedSectionName = '') {
|
|
|
|
const sectionComps = [];
|
|
|
|
const sections = shared.settingsSections({ device, settings });
|
2019-01-28 01:15:56 +02:00
|
|
|
|
|
|
|
for (let i = 0; i < sections.length; i++) {
|
|
|
|
const section = sections[i];
|
2019-09-11 01:53:01 +02:00
|
|
|
const sectionComp = comp.sectionToComponent(section.name, section, settings, selectedSectionName === section.name);
|
2019-01-28 01:15:56 +02:00
|
|
|
if (!sectionComp) continue;
|
|
|
|
sectionComps.push(sectionComp);
|
|
|
|
}
|
|
|
|
|
2019-07-29 15:43:53 +02:00
|
|
|
return sectionComps;
|
|
|
|
};
|
2019-01-28 01:15:56 +02:00
|
|
|
|
2019-07-29 15:43:53 +02:00
|
|
|
module.exports = shared;
|