mirror of https://github.com/keeweb/keeweb.git
settings
This commit is contained in:
parent
8df3899920
commit
48c4f28d5d
|
@ -668,6 +668,20 @@ class FileController {
|
|||
this.backupFile(file, data).catch(noop);
|
||||
}
|
||||
}
|
||||
|
||||
deleteAllCachedFiles(): void {
|
||||
for (const fileInfo of FileManager.fileInfos) {
|
||||
if (fileInfo.storage && !fileInfo.modified) {
|
||||
Storage.cache.remove(fileInfo.id).catch(noop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deleteAllStoredTokens(): void {
|
||||
for (const storage of Object.values(Storage.getAll())) {
|
||||
storage.deleteStoredToken();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const instance = new FileController();
|
||||
|
|
|
@ -64,7 +64,7 @@ class Updater extends Model {
|
|||
);
|
||||
}
|
||||
|
||||
private scheduleNextCheck() {
|
||||
scheduleNextCheck(): void {
|
||||
if (this._nextCheckTimeout) {
|
||||
clearTimeout(this._nextCheckTimeout);
|
||||
this._nextCheckTimeout = undefined;
|
||||
|
@ -89,7 +89,7 @@ class Updater extends Model {
|
|||
logger.info(`Next update check will happen in ${Math.round(timeDiff / 1000)}s`);
|
||||
}
|
||||
|
||||
private async check(startedByUser: boolean) {
|
||||
async check(startedByUser: boolean) {
|
||||
if (!this.enabled || this.updateInProgress) {
|
||||
return;
|
||||
}
|
||||
|
@ -176,6 +176,11 @@ class Updater extends Model {
|
|||
}
|
||||
}
|
||||
|
||||
async updateAndRestart() {
|
||||
await this.update();
|
||||
await this.installAndRestart();
|
||||
}
|
||||
|
||||
private async update() {
|
||||
if (!this.enabled) {
|
||||
logger.info('Updater is disabled');
|
||||
|
|
|
@ -181,25 +181,6 @@ class AppModel {
|
|||
);
|
||||
}
|
||||
|
||||
deleteAllCachedFiles() {
|
||||
for (const fileInfo of this.fileInfos) {
|
||||
if (fileInfo.storage && !fileInfo.modified) {
|
||||
Storage.cache.remove(fileInfo.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clearStoredKeyFiles() {
|
||||
for (const fileInfo of this.fileInfos) {
|
||||
fileInfo.set({
|
||||
keyFileName: null,
|
||||
keyFilePath: null,
|
||||
keyFileHash: null
|
||||
});
|
||||
}
|
||||
this.fileInfos.save();
|
||||
}
|
||||
|
||||
unsetKeyFile(fileId) {
|
||||
const fileInfo = this.fileInfos.get(fileId);
|
||||
fileInfo.set({
|
||||
|
|
|
@ -69,4 +69,12 @@ export class FileInfo extends Model {
|
|||
}
|
||||
return new FileInfo(rec as { id: string; name: string });
|
||||
}
|
||||
|
||||
clearKeyFile(): void {
|
||||
this.batchSet(() => {
|
||||
this.keyFileName = undefined;
|
||||
this.keyFilePath = undefined;
|
||||
this.keyFileHash = undefined;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -188,6 +188,13 @@ class FileManager extends Model<FileManagerEvents> {
|
|||
return this.files.some((f) => !f.readOnly);
|
||||
}
|
||||
|
||||
clearStoredKeyFiles(): void {
|
||||
for (const fileInfo of this.fileInfos) {
|
||||
fileInfo.clearKeyFile();
|
||||
}
|
||||
this.saveFileInfosDelayed();
|
||||
}
|
||||
|
||||
private fileClosed(file: File) {
|
||||
if (file.storage === 'file' && file.path) {
|
||||
Storage.file.unwatch(file.path);
|
||||
|
|
|
@ -130,7 +130,7 @@ abstract class StorageBase {
|
|||
}
|
||||
}
|
||||
|
||||
private deleteStoredToken(): void {
|
||||
deleteStoredToken(): void {
|
||||
RuntimeData.delete(`${this.name}OAuthToken`);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,219 +0,0 @@
|
|||
import { Events } from 'framework/events';
|
||||
import { View } from 'framework/views/view';
|
||||
import { Storage } from 'storage';
|
||||
import { Updater } from 'comp/app/updater';
|
||||
import { Launcher } from 'comp/launcher';
|
||||
import { Links } from 'const/links';
|
||||
import { AppSettingsModel } from 'models/app-settings-model';
|
||||
import { minmax } from 'util/fn';
|
||||
import { NativeModules } from 'comp/launcher/native-modules';
|
||||
|
||||
class SettingsGeneralView extends View {
|
||||
changeClipboard(e) {
|
||||
const clipboardSeconds = +e.target.value;
|
||||
AppSettingsModel.clipboardSeconds = clipboardSeconds;
|
||||
}
|
||||
|
||||
changeIdleMinutes(e) {
|
||||
const idleMinutes = +e.target.value;
|
||||
AppSettingsModel.idleMinutes = idleMinutes;
|
||||
}
|
||||
|
||||
changeAutoUpdate(e) {
|
||||
const autoUpdate = e.target.value || false;
|
||||
AppSettingsModel.autoUpdate = autoUpdate;
|
||||
if (autoUpdate) {
|
||||
Updater.scheduleNextCheck();
|
||||
}
|
||||
}
|
||||
|
||||
checkUpdate() {
|
||||
Updater.check(true);
|
||||
}
|
||||
|
||||
changeAutoSave(e) {
|
||||
const autoSave = e.target.checked || false;
|
||||
AppSettingsModel.autoSave = autoSave;
|
||||
}
|
||||
|
||||
changeAutoSaveInterval(e) {
|
||||
const autoSaveInterval = e.target.value | 0;
|
||||
AppSettingsModel.autoSaveInterval = autoSaveInterval;
|
||||
}
|
||||
|
||||
changeRememberKeyFiles(e) {
|
||||
const rememberKeyFiles = e.target.value || false;
|
||||
AppSettingsModel.rememberKeyFiles = rememberKeyFiles;
|
||||
this.appModel.clearStoredKeyFiles();
|
||||
}
|
||||
|
||||
changeMinimize(e) {
|
||||
const minimizeOnClose = e.target.checked || false;
|
||||
AppSettingsModel.minimizeOnClose = minimizeOnClose;
|
||||
}
|
||||
|
||||
changeMinimizeOnFieldCopy(e) {
|
||||
const minimizeOnFieldCopy = e.target.checked || false;
|
||||
AppSettingsModel.minimizeOnFieldCopy = minimizeOnFieldCopy;
|
||||
}
|
||||
|
||||
changeAuditPasswords(e) {
|
||||
const auditPasswords = e.target.checked || false;
|
||||
AppSettingsModel.auditPasswords = auditPasswords;
|
||||
}
|
||||
|
||||
changeAuditPasswordEntropy(e) {
|
||||
const auditPasswordEntropy = e.target.checked || false;
|
||||
AppSettingsModel.auditPasswordEntropy = auditPasswordEntropy;
|
||||
}
|
||||
|
||||
changeExcludePinsFromAudit(e) {
|
||||
const excludePinsFromAudit = e.target.checked || false;
|
||||
AppSettingsModel.excludePinsFromAudit = excludePinsFromAudit;
|
||||
}
|
||||
|
||||
changeCheckPasswordsOnHIBP(e) {
|
||||
if (e.target.closest('a')) {
|
||||
return;
|
||||
}
|
||||
const checkPasswordsOnHIBP = e.target.checked || false;
|
||||
AppSettingsModel.checkPasswordsOnHIBP = checkPasswordsOnHIBP;
|
||||
}
|
||||
|
||||
clickToggleHelpHIBP() {
|
||||
this.el.querySelector('.settings__general-help-hibp').classList.toggle('hide');
|
||||
}
|
||||
|
||||
changeAuditPasswordAge(e) {
|
||||
const auditPasswordAge = e.target.value | 0;
|
||||
AppSettingsModel.auditPasswordAge = auditPasswordAge;
|
||||
}
|
||||
|
||||
changeLockOnMinimize(e) {
|
||||
const lockOnMinimize = e.target.checked || false;
|
||||
AppSettingsModel.lockOnMinimize = lockOnMinimize;
|
||||
}
|
||||
|
||||
changeLockOnCopy(e) {
|
||||
const lockOnCopy = e.target.checked || false;
|
||||
AppSettingsModel.lockOnCopy = lockOnCopy;
|
||||
}
|
||||
|
||||
changeLockOnAutoType(e) {
|
||||
const lockOnAutoType = e.target.checked || false;
|
||||
AppSettingsModel.lockOnAutoType = lockOnAutoType;
|
||||
}
|
||||
|
||||
changeLockOnOsLock(e) {
|
||||
const lockOnOsLock = e.target.checked || false;
|
||||
AppSettingsModel.lockOnOsLock = lockOnOsLock;
|
||||
}
|
||||
|
||||
changeUseMarkdown(e) {
|
||||
const useMarkdown = e.target.checked || false;
|
||||
AppSettingsModel.useMarkdown = useMarkdown;
|
||||
Events.emit('refresh');
|
||||
}
|
||||
|
||||
changeUseGroupIconForEntries(e) {
|
||||
const useGroupIconForEntries = e.target.checked || false;
|
||||
AppSettingsModel.useGroupIconForEntries = useGroupIconForEntries;
|
||||
}
|
||||
|
||||
changeDirectAutotype(e) {
|
||||
const directAutotype = e.target.checked || false;
|
||||
AppSettingsModel.directAutotype = directAutotype;
|
||||
}
|
||||
|
||||
changeAutoTypeTitleFilter(e) {
|
||||
const autoTypeTitleFilterEnabled = e.target.checked || false;
|
||||
AppSettingsModel.autoTypeTitleFilterEnabled = autoTypeTitleFilterEnabled;
|
||||
}
|
||||
|
||||
changeFieldLabelDblClickAutoType(e) {
|
||||
const fieldLabelDblClickAutoType = e.target.checked || false;
|
||||
AppSettingsModel.fieldLabelDblClickAutoType = fieldLabelDblClickAutoType;
|
||||
Events.emit('refresh');
|
||||
}
|
||||
|
||||
changeDeviceOwnerAuth(e) {
|
||||
const deviceOwnerAuth = e.target.value || null;
|
||||
|
||||
let deviceOwnerAuthTimeoutMinutes = AppSettingsModel.deviceOwnerAuthTimeoutMinutes | 0;
|
||||
if (deviceOwnerAuth) {
|
||||
const timeouts = { memory: [30, 10080], file: [30, 525600] };
|
||||
const [tMin, tMax] = timeouts[deviceOwnerAuth] || [0, 0];
|
||||
deviceOwnerAuthTimeoutMinutes = minmax(deviceOwnerAuthTimeoutMinutes, tMin, tMax);
|
||||
}
|
||||
|
||||
AppSettingsModel.set({ deviceOwnerAuth, deviceOwnerAuthTimeoutMinutes });
|
||||
this.render();
|
||||
|
||||
this.appModel.checkEncryptedPasswordsStorage();
|
||||
if (!deviceOwnerAuth) {
|
||||
NativeModules.hardwareCryptoDeleteKey().catch(() => {});
|
||||
}
|
||||
}
|
||||
|
||||
changeDeviceOwnerAuthTimeout(e) {
|
||||
const deviceOwnerAuthTimeout = e.target.value | 0;
|
||||
AppSettingsModel.deviceOwnerAuthTimeoutMinutes = deviceOwnerAuthTimeout;
|
||||
}
|
||||
|
||||
installUpdateAndRestart() {
|
||||
if (Launcher) {
|
||||
Updater.installAndRestart();
|
||||
} else {
|
||||
window.location.reload();
|
||||
}
|
||||
}
|
||||
|
||||
downloadUpdate() {
|
||||
Launcher.openLink(Links.Desktop);
|
||||
}
|
||||
|
||||
installFoundUpdate() {
|
||||
Updater.update(true, () => {
|
||||
Updater.installAndRestart();
|
||||
});
|
||||
}
|
||||
|
||||
changeDisableOfflineStorage(e) {
|
||||
const disableOfflineStorage = e.target.checked;
|
||||
AppSettingsModel.disableOfflineStorage = disableOfflineStorage;
|
||||
if (disableOfflineStorage) {
|
||||
this.appModel.deleteAllCachedFiles();
|
||||
}
|
||||
}
|
||||
|
||||
changeShortLivedStorageToken(e) {
|
||||
const shortLivedStorageToken = e.target.checked;
|
||||
AppSettingsModel.shortLivedStorageToken = shortLivedStorageToken;
|
||||
if (shortLivedStorageToken) {
|
||||
for (const storage of Object.values(Storage)) {
|
||||
storage.deleteStoredToken();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
changeStorageEnabled(e) {
|
||||
const storage = Storage[$(e.target).data('storage')];
|
||||
if (storage) {
|
||||
storage.setEnabled(e.target.checked);
|
||||
AppSettingsModel[storage.name] = storage.enabled;
|
||||
this.$el
|
||||
.find('.settings__general-' + storage.name)
|
||||
.toggleClass('hide', !e.target.checked);
|
||||
}
|
||||
}
|
||||
|
||||
logoutFromStorage(e) {
|
||||
const storage = Storage[$(e.target).data('storage')];
|
||||
if (storage) {
|
||||
storage.logout();
|
||||
$(e.target).remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export { SettingsGeneralView };
|
|
@ -1,13 +1,48 @@
|
|||
import { FunctionComponent, h } from 'preact';
|
||||
import { SettingsGeneralAuditView } from 'views/settings/general/settings-general-audit-view';
|
||||
import { AppSettings } from 'models/app-settings';
|
||||
import { useState } from 'preact/hooks';
|
||||
|
||||
export const SettingsGeneralAudit: FunctionComponent = () => {
|
||||
const [showAboutHIBP, setShowAboutHIBP] = useState(false);
|
||||
|
||||
const auditPasswordsChanged = () => {
|
||||
AppSettings.auditPasswords = !AppSettings.auditPasswords;
|
||||
};
|
||||
|
||||
const auditPasswordEntropyChanged = () => {
|
||||
AppSettings.auditPasswordEntropy = !AppSettings.auditPasswordEntropy;
|
||||
};
|
||||
|
||||
const excludePinsFromAuditChanged = () => {
|
||||
AppSettings.excludePinsFromAudit = !AppSettings.excludePinsFromAudit;
|
||||
};
|
||||
|
||||
const checkPasswordsOnHIBPChanged = () => {
|
||||
AppSettings.checkPasswordsOnHIBP = !AppSettings.checkPasswordsOnHIBP;
|
||||
};
|
||||
|
||||
const showAboutHIBPChanged = () => {
|
||||
setShowAboutHIBP(!showAboutHIBP);
|
||||
};
|
||||
|
||||
const auditPasswordAgeChanged = (age: number) => {
|
||||
AppSettings.auditPasswordAge = age;
|
||||
};
|
||||
|
||||
return h(SettingsGeneralAuditView, {
|
||||
auditPasswords: AppSettings.auditPasswords,
|
||||
auditPasswordEntropy: AppSettings.auditPasswordEntropy,
|
||||
excludePinsFromAudit: AppSettings.excludePinsFromAudit,
|
||||
checkPasswordsOnHIBP: AppSettings.checkPasswordsOnHIBP,
|
||||
auditPasswordAge: AppSettings.auditPasswordAge
|
||||
showAboutHIBP,
|
||||
auditPasswordAge: AppSettings.auditPasswordAge,
|
||||
|
||||
auditPasswordsChanged,
|
||||
auditPasswordEntropyChanged,
|
||||
excludePinsFromAuditChanged,
|
||||
checkPasswordsOnHIBPChanged,
|
||||
showAboutHIBPChanged,
|
||||
auditPasswordAgeChanged
|
||||
});
|
||||
};
|
||||
|
|
|
@ -1,10 +1,83 @@
|
|||
import { FunctionComponent, h } from 'preact';
|
||||
import { SettingsGeneralFunctionView } from 'views/settings/general/settings-general-function-view';
|
||||
import { Launcher } from 'comp/launcher';
|
||||
import { AppSettings } from 'models/app-settings';
|
||||
import {
|
||||
AppSettings,
|
||||
AppSettingsDeviceOwnerAuth,
|
||||
AppSettingsRememberKeyFiles
|
||||
} from 'models/app-settings';
|
||||
import { Features } from 'util/features';
|
||||
import { FileManager } from 'models/file-manager';
|
||||
import { minmax } from 'util/fn';
|
||||
|
||||
export const SettingsGeneralFunction: FunctionComponent = () => {
|
||||
const autoSaveChanged = () => {
|
||||
AppSettings.autoSave = !AppSettings.autoSave;
|
||||
};
|
||||
|
||||
const autoSaveIntervalChanged = (interval: number) => {
|
||||
AppSettings.autoSaveInterval = interval;
|
||||
};
|
||||
|
||||
const rememberKeyFilesChanged = (rememberKeyFiles: AppSettingsRememberKeyFiles | null) => {
|
||||
AppSettings.rememberKeyFiles = rememberKeyFiles;
|
||||
FileManager.clearStoredKeyFiles();
|
||||
};
|
||||
|
||||
const clipboardSecondsChanged = (seconds: number) => {
|
||||
AppSettings.clipboardSeconds = seconds;
|
||||
};
|
||||
|
||||
const minimizeOnCloseChanged = () => {
|
||||
AppSettings.minimizeOnClose = !AppSettings.minimizeOnClose;
|
||||
};
|
||||
|
||||
const minimizeOnFieldCopyChanged = () => {
|
||||
AppSettings.minimizeOnFieldCopy = !AppSettings.minimizeOnFieldCopy;
|
||||
};
|
||||
|
||||
const directAutoTypeChanged = () => {
|
||||
AppSettings.directAutotype = !AppSettings.directAutotype;
|
||||
};
|
||||
|
||||
const autoTypeTitleFilterEnabledChanged = () => {
|
||||
AppSettings.autoTypeTitleFilterEnabled = !AppSettings.autoTypeTitleFilterEnabled;
|
||||
};
|
||||
|
||||
const fieldLabelDblClickAutoTypeChanged = () => {
|
||||
AppSettings.fieldLabelDblClickAutoType = !AppSettings.fieldLabelDblClickAutoType;
|
||||
};
|
||||
|
||||
const useMarkdownChanged = () => {
|
||||
AppSettings.useMarkdown = !AppSettings.useMarkdown;
|
||||
};
|
||||
|
||||
const useGroupIconForEntriesChanged = () => {
|
||||
AppSettings.useGroupIconForEntries = !AppSettings.useGroupIconForEntries;
|
||||
};
|
||||
|
||||
const deviceOwnerAuthChanged = (deviceOwnerAuth: AppSettingsDeviceOwnerAuth | null) => {
|
||||
let deviceOwnerAuthTimeoutMinutes = AppSettings.deviceOwnerAuthTimeoutMinutes | 0;
|
||||
if (deviceOwnerAuth) {
|
||||
const timeouts = { memory: [30, 10080], file: [30, 525600] };
|
||||
const [tMin, tMax] = timeouts[deviceOwnerAuth] || [0, 0];
|
||||
deviceOwnerAuthTimeoutMinutes = minmax(deviceOwnerAuthTimeoutMinutes, tMin, tMax);
|
||||
}
|
||||
|
||||
AppSettings.deviceOwnerAuth = deviceOwnerAuth;
|
||||
AppSettings.deviceOwnerAuthTimeoutMinutes = deviceOwnerAuthTimeoutMinutes;
|
||||
|
||||
// TODO: device owner auth
|
||||
// Workspace.checkEncryptedPasswordsStorage();
|
||||
// if (!deviceOwnerAuth) {
|
||||
// NativeModules.hardwareCryptoDeleteKey().catch(() => {});
|
||||
// }
|
||||
};
|
||||
|
||||
const deviceOwnerAuthTimeoutChanged = (timeout: number) => {
|
||||
AppSettings.deviceOwnerAuthTimeoutMinutes = timeout;
|
||||
};
|
||||
|
||||
return h(SettingsGeneralFunctionView, {
|
||||
canAutoSaveOnClose: !!Launcher,
|
||||
autoSave: AppSettings.autoSave,
|
||||
|
@ -24,6 +97,20 @@ export const SettingsGeneralFunction: FunctionComponent = () => {
|
|||
useGroupIconForEntries: AppSettings.useGroupIconForEntries,
|
||||
hasDeviceOwnerAuth: Features.isDesktop && Features.isMac,
|
||||
deviceOwnerAuth: AppSettings.deviceOwnerAuth,
|
||||
deviceOwnerAuthTimeout: AppSettings.deviceOwnerAuthTimeoutMinutes
|
||||
deviceOwnerAuthTimeout: AppSettings.deviceOwnerAuthTimeoutMinutes,
|
||||
|
||||
autoSaveChanged,
|
||||
autoSaveIntervalChanged,
|
||||
rememberKeyFilesChanged,
|
||||
clipboardSecondsChanged,
|
||||
minimizeOnCloseChanged,
|
||||
minimizeOnFieldCopyChanged,
|
||||
directAutoTypeChanged,
|
||||
autoTypeTitleFilterEnabledChanged,
|
||||
fieldLabelDblClickAutoTypeChanged,
|
||||
useMarkdownChanged,
|
||||
useGroupIconForEntriesChanged,
|
||||
deviceOwnerAuthChanged,
|
||||
deviceOwnerAuthTimeoutChanged
|
||||
});
|
||||
};
|
||||
|
|
|
@ -4,6 +4,26 @@ import { AppSettings } from 'models/app-settings';
|
|||
import { Launcher } from 'comp/launcher';
|
||||
|
||||
export const SettingsGeneralLock: FunctionComponent = () => {
|
||||
const idleMinutesChanged = (idleMinutes: number) => {
|
||||
AppSettings.idleMinutes = idleMinutes;
|
||||
};
|
||||
|
||||
const lockOnMinimizeChanged = () => {
|
||||
AppSettings.lockOnMinimize = !AppSettings.lockOnMinimize;
|
||||
};
|
||||
|
||||
const lockOnCopyChanged = () => {
|
||||
AppSettings.lockOnCopy = !AppSettings.lockOnCopy;
|
||||
};
|
||||
|
||||
const lockOnAutoTypeChanged = () => {
|
||||
AppSettings.lockOnAutoType = !AppSettings.lockOnAutoType;
|
||||
};
|
||||
|
||||
const lockOnOsLockChanged = () => {
|
||||
AppSettings.lockOnOsLock = !AppSettings.lockOnOsLock;
|
||||
};
|
||||
|
||||
return h(SettingsGeneralLockView, {
|
||||
idleMinutes: AppSettings.idleMinutes,
|
||||
canDetectMinimize: !!Launcher,
|
||||
|
@ -12,6 +32,12 @@ export const SettingsGeneralLock: FunctionComponent = () => {
|
|||
canAutoType: !!Launcher,
|
||||
lockOnAutoType: AppSettings.lockOnAutoType,
|
||||
canDetectOsSleep: !!Launcher,
|
||||
lockOnOsLock: AppSettings.lockOnOsLock
|
||||
lockOnOsLock: AppSettings.lockOnOsLock,
|
||||
|
||||
idleMinutesChanged,
|
||||
lockOnMinimizeChanged,
|
||||
lockOnCopyChanged,
|
||||
lockOnAutoTypeChanged,
|
||||
lockOnOsLockChanged
|
||||
});
|
||||
};
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
import { FunctionComponent, h } from 'preact';
|
||||
import { SettingsGeneralStorageView } from 'views/settings/general/settings-general-storage-view';
|
||||
import { AppSettings } from 'models/app-settings';
|
||||
import { AppSettings, AppSettingsFieldName } from 'models/app-settings';
|
||||
import { Storage } from 'storage';
|
||||
import { FileController } from 'comp/app/file-controller';
|
||||
import { useModelWatcher } from 'util/ui/hooks';
|
||||
import { RuntimeData } from 'models/runtime-data';
|
||||
|
||||
export const SettingsGeneralStorage: FunctionComponent = () => {
|
||||
useModelWatcher(RuntimeData);
|
||||
|
||||
const getStorageProviders = () => {
|
||||
const storageProviders = Object.values(Storage.getAll()).filter((prv) => !prv.system);
|
||||
storageProviders.sort((x, y) => (x.uipos || Infinity) - (y.uipos || Infinity));
|
||||
|
@ -16,9 +21,41 @@ export const SettingsGeneralStorage: FunctionComponent = () => {
|
|||
}));
|
||||
};
|
||||
|
||||
const disableOfflineStorageChanged = () => {
|
||||
AppSettings.disableOfflineStorage = !AppSettings.disableOfflineStorage;
|
||||
if (AppSettings.disableOfflineStorage) {
|
||||
FileController.deleteAllCachedFiles();
|
||||
}
|
||||
};
|
||||
|
||||
const shortLivedStorageTokenChanged = () => {
|
||||
AppSettings.shortLivedStorageToken = !AppSettings.shortLivedStorageToken;
|
||||
if (AppSettings.shortLivedStorageToken) {
|
||||
FileController.deleteAllStoredTokens();
|
||||
}
|
||||
};
|
||||
|
||||
const storageEnabledChanged = (storageName: string) => {
|
||||
const storage = Storage.get(storageName);
|
||||
if (!storage) {
|
||||
return;
|
||||
}
|
||||
|
||||
AppSettings.set(storage.name as AppSettingsFieldName, !storage.enabled);
|
||||
};
|
||||
|
||||
const logoutFromStorage = (storageName: string) => {
|
||||
Storage.get(storageName)?.logout();
|
||||
};
|
||||
|
||||
return h(SettingsGeneralStorageView, {
|
||||
disableOfflineStorage: AppSettings.disableOfflineStorage,
|
||||
shortLivedStorageToken: AppSettings.shortLivedStorageToken,
|
||||
storageProviders: getStorageProviders()
|
||||
storageProviders: getStorageProviders(),
|
||||
|
||||
disableOfflineStorageChanged,
|
||||
shortLivedStorageTokenChanged,
|
||||
storageEnabledChanged,
|
||||
logoutFromStorage
|
||||
});
|
||||
};
|
||||
|
|
|
@ -2,16 +2,18 @@ import { FunctionComponent, h } from 'preact';
|
|||
import { SettingsGeneralUpdateView } from 'views/settings/general/settings-general-update-view';
|
||||
import { Updater } from 'comp/app/updater';
|
||||
import { Launcher } from 'comp/launcher';
|
||||
import { AppSettings } from 'models/app-settings';
|
||||
import { AppSettings, AppSettingsAutoUpdate } from 'models/app-settings';
|
||||
import { useModelWatcher } from 'util/ui/hooks';
|
||||
import { Locale } from 'util/locale';
|
||||
import { SemVer } from 'util/data/semver';
|
||||
import { RuntimeInfo } from 'const/runtime-info';
|
||||
import { DateFormat } from 'util/formatting/date-format';
|
||||
import { RuntimeData } from 'models/runtime-data';
|
||||
import { noop } from 'util/fn';
|
||||
|
||||
export const SettingsGeneralUpdate: FunctionComponent = () => {
|
||||
useModelWatcher(Updater);
|
||||
useModelWatcher(RuntimeData);
|
||||
|
||||
const getUpdateInfo = () => {
|
||||
switch (Updater.status) {
|
||||
|
@ -73,6 +75,29 @@ export const SettingsGeneralUpdate: FunctionComponent = () => {
|
|||
}
|
||||
};
|
||||
|
||||
const installUpdateClicked = () => {
|
||||
if (Launcher) {
|
||||
Updater.installAndRestart().catch(noop);
|
||||
} else {
|
||||
window.location.reload();
|
||||
}
|
||||
};
|
||||
|
||||
const checkUpdateClicked = () => {
|
||||
Updater.check(true).catch(noop);
|
||||
};
|
||||
|
||||
const downloadAndInstallUpdateClicked = () => {
|
||||
Updater.updateAndRestart().catch(noop);
|
||||
};
|
||||
|
||||
const autoUpdateChanged = (autoUpdate: AppSettingsAutoUpdate | null) => {
|
||||
AppSettings.autoUpdate = autoUpdate;
|
||||
if (autoUpdate) {
|
||||
Updater.scheduleNextCheck();
|
||||
}
|
||||
};
|
||||
|
||||
return h(SettingsGeneralUpdateView, {
|
||||
updateWaitingReload: Updater.updateStatus === 'ready' && !Launcher,
|
||||
autoUpdate: AppSettings.autoUpdate,
|
||||
|
@ -80,6 +105,11 @@ export const SettingsGeneralUpdate: FunctionComponent = () => {
|
|||
updateInfo: getUpdateInfo(),
|
||||
updateInProgress: Updater.updateInProgress,
|
||||
updateReady: Updater.updateStatus === 'ready',
|
||||
updateFound: Updater.updateStatus === 'found'
|
||||
updateFound: Updater.updateStatus === 'found',
|
||||
|
||||
installUpdateClicked,
|
||||
checkUpdateClicked,
|
||||
downloadAndInstallUpdateClicked,
|
||||
autoUpdateChanged
|
||||
});
|
||||
};
|
||||
|
|
|
@ -9,13 +9,36 @@ export const SettingsGeneralAuditView: FunctionComponent<{
|
|||
excludePinsFromAudit: boolean;
|
||||
checkPasswordsOnHIBP: boolean;
|
||||
auditPasswordAge: number;
|
||||
showAboutHIBP: boolean;
|
||||
|
||||
auditPasswordsChanged: () => void;
|
||||
auditPasswordEntropyChanged: () => void;
|
||||
excludePinsFromAuditChanged: () => void;
|
||||
checkPasswordsOnHIBPChanged: () => void;
|
||||
showAboutHIBPChanged: () => void;
|
||||
auditPasswordAgeChanged: (age: number) => void;
|
||||
}> = ({
|
||||
auditPasswords,
|
||||
auditPasswordEntropy,
|
||||
excludePinsFromAudit,
|
||||
checkPasswordsOnHIBP,
|
||||
auditPasswordAge
|
||||
auditPasswordAge,
|
||||
showAboutHIBP,
|
||||
|
||||
auditPasswordsChanged,
|
||||
auditPasswordEntropyChanged,
|
||||
excludePinsFromAuditChanged,
|
||||
checkPasswordsOnHIBPChanged,
|
||||
showAboutHIBPChanged,
|
||||
auditPasswordAgeChanged
|
||||
}) => {
|
||||
const checkPasswordsOnHIBPClickedInternal = (e: Event) => {
|
||||
if ((e.target as HTMLElement).closest('a')) {
|
||||
return;
|
||||
}
|
||||
checkPasswordsOnHIBPChanged();
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<h2 id="audit">{Locale.setGenAudit}</h2>
|
||||
|
@ -25,6 +48,7 @@ export const SettingsGeneralAuditView: FunctionComponent<{
|
|||
class="settings__input input-base settings__general-audit-passwords"
|
||||
id="settings__general-audit-passwords"
|
||||
checked={auditPasswords}
|
||||
onClick={auditPasswordsChanged}
|
||||
/>
|
||||
<label for="settings__general-audit-passwords">{Locale.setGenAuditPasswords}</label>
|
||||
</div>
|
||||
|
@ -35,6 +59,7 @@ export const SettingsGeneralAuditView: FunctionComponent<{
|
|||
class="settings__input input-base settings__general-audit-password-entropy"
|
||||
id="settings__general-audit-password-entropy"
|
||||
checked={auditPasswordEntropy}
|
||||
onClick={auditPasswordEntropyChanged}
|
||||
/>
|
||||
<label for="settings__general-audit-password-entropy">
|
||||
{Locale.setGenAuditPasswordEntropy}
|
||||
|
@ -47,6 +72,7 @@ export const SettingsGeneralAuditView: FunctionComponent<{
|
|||
class="settings__input input-base settings__general-exclude-pins-from-audit"
|
||||
id="settings__general-exclude-pins-from-audit"
|
||||
checked={excludePinsFromAudit}
|
||||
onClick={excludePinsFromAuditChanged}
|
||||
/>
|
||||
<label for="settings__general-exclude-pins-from-audit">
|
||||
{Locale.setGenExcludePinsFromAudit}
|
||||
|
@ -59,6 +85,7 @@ export const SettingsGeneralAuditView: FunctionComponent<{
|
|||
class="settings__input input-base settings__general-check-passwords-on-hibp"
|
||||
id="settings__general-check-passwords-on-hibp"
|
||||
checked={checkPasswordsOnHIBP}
|
||||
onClick={checkPasswordsOnHIBPClickedInternal}
|
||||
/>
|
||||
<label for="settings__general-check-passwords-on-hibp">
|
||||
<LocalizedWith str={Locale.setGenCheckPasswordsOnHIBP}>
|
||||
|
@ -67,18 +94,23 @@ export const SettingsGeneralAuditView: FunctionComponent<{
|
|||
</a>
|
||||
</LocalizedWith>
|
||||
</label>
|
||||
<i class="fa fa-info-circle info-btn settings__general-toggle-help-hibp" />
|
||||
<div class="settings__general-help-hibp hide">
|
||||
<LocalizedWith str={Locale.setGenHelpHIBP}>
|
||||
<a
|
||||
href={Links.HaveIBeenPwnedPrivacy}
|
||||
rel="noreferrer noopener"
|
||||
target="_blank"
|
||||
>
|
||||
{Locale.setGenHelpHIBPLink}
|
||||
</a>
|
||||
</LocalizedWith>
|
||||
</div>
|
||||
<i
|
||||
class="fa fa-info-circle info-btn settings__general-toggle-help-hibp"
|
||||
onClick={showAboutHIBPChanged}
|
||||
/>
|
||||
{showAboutHIBP ? (
|
||||
<div class="settings__general-help-hibp">
|
||||
<LocalizedWith str={Locale.setGenHelpHIBP}>
|
||||
<a
|
||||
href={Links.HaveIBeenPwnedPrivacy}
|
||||
rel="noreferrer noopener"
|
||||
target="_blank"
|
||||
>
|
||||
{Locale.setGenHelpHIBPLink}
|
||||
</a>
|
||||
</LocalizedWith>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
@ -89,6 +121,9 @@ export const SettingsGeneralAuditView: FunctionComponent<{
|
|||
class="settings__select input-base settings__general-audit-password-age"
|
||||
id="settings__general-audit-password-age"
|
||||
value={auditPasswordAge}
|
||||
onChange={(e) =>
|
||||
auditPasswordAgeChanged(+(e.target as HTMLSelectElement).value)
|
||||
}
|
||||
>
|
||||
<option value="0">{Locale.setGenAuditPasswordAgeOff}</option>
|
||||
<option value="1">{Locale.setGenAuditPasswordAgeOneYear}</option>
|
||||
|
|
|
@ -24,6 +24,20 @@ export const SettingsGeneralFunctionView: FunctionComponent<{
|
|||
hasDeviceOwnerAuth: boolean;
|
||||
deviceOwnerAuth: AppSettingsDeviceOwnerAuth | null;
|
||||
deviceOwnerAuthTimeout: number;
|
||||
|
||||
autoSaveChanged: () => void;
|
||||
autoSaveIntervalChanged: (interval: number) => void;
|
||||
rememberKeyFilesChanged: (rememberKeyFiles: AppSettingsRememberKeyFiles | null) => void;
|
||||
clipboardSecondsChanged: (seconds: number) => void;
|
||||
minimizeOnCloseChanged: () => void;
|
||||
minimizeOnFieldCopyChanged: () => void;
|
||||
directAutoTypeChanged: () => void;
|
||||
autoTypeTitleFilterEnabledChanged: () => void;
|
||||
fieldLabelDblClickAutoTypeChanged: () => void;
|
||||
useMarkdownChanged: () => void;
|
||||
useGroupIconForEntriesChanged: () => void;
|
||||
deviceOwnerAuthChanged: (deviceOwnerAuth: AppSettingsDeviceOwnerAuth | null) => void;
|
||||
deviceOwnerAuthTimeoutChanged: (timeout: number) => void;
|
||||
}> = ({
|
||||
canAutoSaveOnClose,
|
||||
autoSave,
|
||||
|
@ -43,7 +57,21 @@ export const SettingsGeneralFunctionView: FunctionComponent<{
|
|||
useGroupIconForEntries,
|
||||
hasDeviceOwnerAuth,
|
||||
deviceOwnerAuth,
|
||||
deviceOwnerAuthTimeout
|
||||
deviceOwnerAuthTimeout,
|
||||
|
||||
autoSaveChanged,
|
||||
autoSaveIntervalChanged,
|
||||
rememberKeyFilesChanged,
|
||||
clipboardSecondsChanged,
|
||||
minimizeOnCloseChanged,
|
||||
minimizeOnFieldCopyChanged,
|
||||
directAutoTypeChanged,
|
||||
autoTypeTitleFilterEnabledChanged,
|
||||
fieldLabelDblClickAutoTypeChanged,
|
||||
useMarkdownChanged,
|
||||
useGroupIconForEntriesChanged,
|
||||
deviceOwnerAuthChanged,
|
||||
deviceOwnerAuthTimeoutChanged
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
|
@ -55,6 +83,7 @@ export const SettingsGeneralFunctionView: FunctionComponent<{
|
|||
class="settings__input input-base settings__general-auto-save"
|
||||
id="settings__general-auto-save"
|
||||
checked={autoSave}
|
||||
onClick={autoSaveChanged}
|
||||
/>
|
||||
<label for="settings__general-auto-save">{Locale.setGenAutoSyncOnClose}</label>
|
||||
</div>
|
||||
|
@ -67,6 +96,9 @@ export const SettingsGeneralFunctionView: FunctionComponent<{
|
|||
class="settings__select input-base settings__general-auto-save-interval"
|
||||
id="settings__general-auto-save-interval"
|
||||
value={autoSaveInterval}
|
||||
onChange={(e) =>
|
||||
autoSaveIntervalChanged(+(e.target as HTMLSelectElement).value)
|
||||
}
|
||||
>
|
||||
<option value="0">{Locale.setGenAutoSyncTimerOff}</option>
|
||||
<option value="-1">{Locale.setGenAutoSyncTimerOnChange}</option>
|
||||
|
@ -94,17 +126,16 @@ export const SettingsGeneralFunctionView: FunctionComponent<{
|
|||
<select
|
||||
class="settings__general-remember-key-files settings__select input-base"
|
||||
id="settings__general-remember-key-files"
|
||||
value={rememberKeyFiles || ''}
|
||||
onChange={(e) => {
|
||||
const val = (e.target as HTMLSelectElement).value || null;
|
||||
rememberKeyFilesChanged(val as AppSettingsRememberKeyFiles | null);
|
||||
}}
|
||||
>
|
||||
<option value="" selected={!rememberKeyFiles}>
|
||||
{Locale.setGenNoRememberKeyFiles}
|
||||
</option>
|
||||
<option value="data" selected={rememberKeyFiles === 'data'}>
|
||||
{Locale.setGenRememberKeyFilesData}
|
||||
</option>
|
||||
<option value="">{Locale.setGenNoRememberKeyFiles}</option>
|
||||
<option value="data">{Locale.setGenRememberKeyFilesData}</option>
|
||||
{supportFiles ? (
|
||||
<option value="path" selected={rememberKeyFiles === 'path'}>
|
||||
{Locale.setGenRememberKeyFilesPath}
|
||||
</option>
|
||||
<option value="path">{Locale.setGenRememberKeyFilesPath}</option>
|
||||
) : null}
|
||||
</select>
|
||||
</div>
|
||||
|
@ -115,6 +146,9 @@ export const SettingsGeneralFunctionView: FunctionComponent<{
|
|||
class="settings__general-clipboard settings__select input-base"
|
||||
id="settings__general-clipboard"
|
||||
value={clipboardSeconds}
|
||||
onChange={(e) =>
|
||||
clipboardSecondsChanged(+(e.target as HTMLSelectElement).value)
|
||||
}
|
||||
>
|
||||
<option value="0">{Locale.setGenNoClear}</option>
|
||||
<option value="5">
|
||||
|
@ -138,6 +172,7 @@ export const SettingsGeneralFunctionView: FunctionComponent<{
|
|||
class="settings__input input-base settings__general-minimize"
|
||||
id="settings__general-minimize"
|
||||
checked={minimizeOnClose}
|
||||
onClick={minimizeOnCloseChanged}
|
||||
/>
|
||||
<label for="settings__general-minimize">{Locale.setGenMinInstead}</label>
|
||||
</div>
|
||||
|
@ -147,6 +182,7 @@ export const SettingsGeneralFunctionView: FunctionComponent<{
|
|||
class="settings__input input-base settings__general-minimize-on-field-copy"
|
||||
id="settings__general-minimize-on-field-copy"
|
||||
checked={minimizeOnFieldCopy}
|
||||
onClick={minimizeOnFieldCopyChanged}
|
||||
/>
|
||||
<label for="settings__general-minimize-on-field-copy">
|
||||
{Locale.setGenMinOnFieldCopy}
|
||||
|
@ -162,6 +198,7 @@ export const SettingsGeneralFunctionView: FunctionComponent<{
|
|||
class="settings__input input-base settings__general-direct-autotype"
|
||||
id="settings__general-direct-autotype"
|
||||
checked={directAutotype}
|
||||
onClick={directAutoTypeChanged}
|
||||
/>
|
||||
<label for="settings__general-direct-autotype">
|
||||
{Locale.setGenDirectAutotype}
|
||||
|
@ -173,6 +210,7 @@ export const SettingsGeneralFunctionView: FunctionComponent<{
|
|||
class="settings__input input-base settings__general-autotype-title-filter"
|
||||
id="settings__general-autotype-title-filter"
|
||||
checked={autoTypeTitleFilterEnabled}
|
||||
onClick={autoTypeTitleFilterEnabledChanged}
|
||||
/>
|
||||
<label for="settings__general-autotype-title-filter">
|
||||
{Locale.setGenAutoTypeTitleFilterEnabled}
|
||||
|
@ -184,6 +222,7 @@ export const SettingsGeneralFunctionView: FunctionComponent<{
|
|||
class="settings__input input-base settings__general-field-label-dblclick-autotype"
|
||||
id="settings__general-field-label-dblclick-autotype"
|
||||
checked={fieldLabelDblClickAutoType}
|
||||
onClick={fieldLabelDblClickAutoTypeChanged}
|
||||
/>
|
||||
<label for="settings__general-field-label-dblclick-autotype">
|
||||
{Locale.setGenFieldLabelDblClickAutoType}
|
||||
|
@ -197,6 +236,7 @@ export const SettingsGeneralFunctionView: FunctionComponent<{
|
|||
class="settings__input input-base settings__general-use-markdown"
|
||||
id="settings__general-use-markdown"
|
||||
checked={useMarkdown}
|
||||
onClick={useMarkdownChanged}
|
||||
/>
|
||||
<label for="settings__general-use-markdown">{Locale.setGenUseMarkdown}</label>
|
||||
</div>
|
||||
|
@ -206,6 +246,7 @@ export const SettingsGeneralFunctionView: FunctionComponent<{
|
|||
class="settings__input input-base settings__general-use-group-icon-for-entries"
|
||||
id="settings__general-use-group-icon-for-entries"
|
||||
checked={useGroupIconForEntries}
|
||||
onClick={useGroupIconForEntriesChanged}
|
||||
/>
|
||||
<label for="settings__general-use-group-icon-for-entries">
|
||||
{Locale.setGenUseGroupIconForEntries}
|
||||
|
@ -220,16 +261,15 @@ export const SettingsGeneralFunctionView: FunctionComponent<{
|
|||
<select
|
||||
class="settings__general-device-owner-auth settings__select input-base"
|
||||
id="settings__general-device-owner-auth"
|
||||
value={deviceOwnerAuth || ''}
|
||||
onChange={(e) => {
|
||||
const val = (e.target as HTMLSelectElement).value || null;
|
||||
deviceOwnerAuthChanged(val as AppSettingsDeviceOwnerAuth | null);
|
||||
}}
|
||||
>
|
||||
<option value="" selected={!deviceOwnerAuth}>
|
||||
{Locale.setGenTouchIdDisabled}
|
||||
</option>
|
||||
<option value="memory" selected={deviceOwnerAuth === 'memory'}>
|
||||
{Locale.setGenTouchIdMemory}
|
||||
</option>
|
||||
<option value="file" selected={deviceOwnerAuth === 'file'}>
|
||||
{Locale.setGenTouchIdFile}
|
||||
</option>
|
||||
<option value="">{Locale.setGenTouchIdDisabled}</option>
|
||||
<option value="memory">{Locale.setGenTouchIdMemory}</option>
|
||||
<option value="file">{Locale.setGenTouchIdFile}</option>
|
||||
</select>
|
||||
</div>
|
||||
{deviceOwnerAuth ? (
|
||||
|
@ -241,6 +281,11 @@ export const SettingsGeneralFunctionView: FunctionComponent<{
|
|||
class="settings__general-device-owner-auth-timeout settings__select input-base"
|
||||
id="settings__general-device-owner-auth-timeout"
|
||||
value={deviceOwnerAuthTimeout}
|
||||
onChange={(e) =>
|
||||
deviceOwnerAuthTimeoutChanged(
|
||||
+(e.target as HTMLSelectElement).value
|
||||
)
|
||||
}
|
||||
>
|
||||
<option value="1">{StringFormat.capFirst(Locale.oneMinute)}</option>
|
||||
<option value="5">
|
||||
|
|
|
@ -11,6 +11,12 @@ export const SettingsGeneralLockView: FunctionComponent<{
|
|||
lockOnAutoType: boolean;
|
||||
canDetectOsSleep: boolean;
|
||||
lockOnOsLock: boolean;
|
||||
|
||||
idleMinutesChanged: (idleMinutes: number) => void;
|
||||
lockOnMinimizeChanged: () => void;
|
||||
lockOnCopyChanged: () => void;
|
||||
lockOnAutoTypeChanged: () => void;
|
||||
lockOnOsLockChanged: () => void;
|
||||
}> = ({
|
||||
idleMinutes,
|
||||
canDetectMinimize,
|
||||
|
@ -19,7 +25,13 @@ export const SettingsGeneralLockView: FunctionComponent<{
|
|||
canAutoType,
|
||||
lockOnAutoType,
|
||||
canDetectOsSleep,
|
||||
lockOnOsLock
|
||||
lockOnOsLock,
|
||||
|
||||
idleMinutesChanged,
|
||||
lockOnMinimizeChanged,
|
||||
lockOnCopyChanged,
|
||||
lockOnAutoTypeChanged,
|
||||
lockOnOsLockChanged
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
|
@ -30,6 +42,7 @@ export const SettingsGeneralLockView: FunctionComponent<{
|
|||
class="settings__general-idle-minutes settings__select input-base"
|
||||
id="settings__general-idle-minutes"
|
||||
value={idleMinutes}
|
||||
onChange={(e) => idleMinutesChanged(+(e.target as HTMLSelectElement).value)}
|
||||
>
|
||||
<option value="0">{Locale.setGenNoAutoLock}</option>
|
||||
<option value="5">
|
||||
|
@ -65,6 +78,7 @@ export const SettingsGeneralLockView: FunctionComponent<{
|
|||
class="settings__input input-base settings__general-lock-on-minimize"
|
||||
id="settings__general-lock-on-minimize"
|
||||
checked={lockOnMinimize}
|
||||
onClick={lockOnMinimizeChanged}
|
||||
/>
|
||||
<label for="settings__general-lock-on-minimize">
|
||||
{Locale.setGenLockMinimize}
|
||||
|
@ -78,6 +92,7 @@ export const SettingsGeneralLockView: FunctionComponent<{
|
|||
class="settings__input input-base settings__general-lock-on-copy"
|
||||
id="settings__general-lock-on-copy"
|
||||
checked={lockOnCopy}
|
||||
onClick={lockOnCopyChanged}
|
||||
/>
|
||||
<label for="settings__general-lock-on-copy">{Locale.setGenLockCopy}</label>
|
||||
</div>
|
||||
|
@ -89,6 +104,7 @@ export const SettingsGeneralLockView: FunctionComponent<{
|
|||
class="settings__input input-base settings__general-lock-on-auto-type"
|
||||
id="settings__general-lock-on-auto-type"
|
||||
checked={lockOnAutoType}
|
||||
onClick={lockOnAutoTypeChanged}
|
||||
/>
|
||||
<label for="settings__general-lock-on-auto-type">
|
||||
{Locale.setGenLockAutoType}
|
||||
|
@ -103,6 +119,7 @@ export const SettingsGeneralLockView: FunctionComponent<{
|
|||
class="settings__input input-base settings__general-lock-on-os-lock"
|
||||
id="settings__general-lock-on-os-lock"
|
||||
checked={lockOnOsLock}
|
||||
onClick={lockOnOsLockChanged}
|
||||
/>
|
||||
<label for="settings__general-lock-on-os-lock">
|
||||
{Locale.setGenLockOrSleep}
|
||||
|
|
|
@ -14,7 +14,21 @@ export const SettingsGeneralStorageView: FunctionComponent<{
|
|||
disableOfflineStorage: boolean;
|
||||
shortLivedStorageToken: boolean;
|
||||
storageProviders: SettingsGeneralStorageProviderItem[];
|
||||
}> = ({ disableOfflineStorage, shortLivedStorageToken, storageProviders }) => {
|
||||
|
||||
disableOfflineStorageChanged: () => void;
|
||||
shortLivedStorageTokenChanged: () => void;
|
||||
storageEnabledChanged: (storageName: string) => void;
|
||||
logoutFromStorage: (storageName: string) => void;
|
||||
}> = ({
|
||||
disableOfflineStorage,
|
||||
shortLivedStorageToken,
|
||||
storageProviders,
|
||||
|
||||
disableOfflineStorageChanged,
|
||||
shortLivedStorageTokenChanged,
|
||||
storageEnabledChanged,
|
||||
logoutFromStorage
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
<h2 id="storage">{Locale.setGenStorage}</h2>
|
||||
|
@ -24,6 +38,7 @@ export const SettingsGeneralStorageView: FunctionComponent<{
|
|||
class="settings__input input-base settings__general-disable-offline-storage"
|
||||
id="settings__general-disable-offline-storage"
|
||||
checked={disableOfflineStorage}
|
||||
onClick={disableOfflineStorageChanged}
|
||||
/>
|
||||
<label for="settings__general-disable-offline-storage">
|
||||
{Locale.setGenDisableOfflineStorage}
|
||||
|
@ -35,6 +50,7 @@ export const SettingsGeneralStorageView: FunctionComponent<{
|
|||
class="settings__input input-base settings__general-short-lived-storage-token"
|
||||
id="settings__general-short-lived-storage-token"
|
||||
checked={shortLivedStorageToken}
|
||||
onClick={shortLivedStorageTokenChanged}
|
||||
/>
|
||||
<label for="settings__general-short-lived-storage-token">
|
||||
{Locale.setGenShortLivedStorageToken}
|
||||
|
@ -48,8 +64,8 @@ export const SettingsGeneralStorageView: FunctionComponent<{
|
|||
type="checkbox"
|
||||
id={`settings__general-prv-check-${prv.name}`}
|
||||
class="settings__general-prv-check"
|
||||
data-storage={prv.name}
|
||||
checked={prv.enabled}
|
||||
onClick={() => storageEnabledChanged(prv.name)}
|
||||
/>
|
||||
<label for={`settings__general-prv-check-${prv.name}`}>{prv.locName}</label>
|
||||
</h4>
|
||||
|
@ -61,7 +77,7 @@ export const SettingsGeneralStorageView: FunctionComponent<{
|
|||
{prv.loggedIn ? (
|
||||
<button
|
||||
class="btn-silent settings__general-prv-logout"
|
||||
data-storage={prv.name}
|
||||
onClick={() => logoutFromStorage(prv.name)}
|
||||
>
|
||||
{Locale.setGenStorageLogout}
|
||||
</button>
|
||||
|
|
|
@ -11,6 +11,11 @@ export const SettingsGeneralUpdateView: FunctionComponent<{
|
|||
updateInProgress: boolean;
|
||||
updateReady: boolean;
|
||||
updateFound: boolean;
|
||||
|
||||
installUpdateClicked: () => void;
|
||||
checkUpdateClicked: () => void;
|
||||
downloadAndInstallUpdateClicked: () => void;
|
||||
autoUpdateChanged: (autoUpdate: AppSettingsAutoUpdate | null) => void;
|
||||
}> = ({
|
||||
updateWaitingReload,
|
||||
autoUpdate,
|
||||
|
@ -18,7 +23,12 @@ export const SettingsGeneralUpdateView: FunctionComponent<{
|
|||
updateInfo,
|
||||
updateInProgress,
|
||||
updateReady,
|
||||
updateFound
|
||||
updateFound,
|
||||
|
||||
installUpdateClicked,
|
||||
checkUpdateClicked,
|
||||
downloadAndInstallUpdateClicked,
|
||||
autoUpdateChanged
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
|
@ -32,7 +42,10 @@ export const SettingsGeneralUpdateView: FunctionComponent<{
|
|||
</a>
|
||||
</div>
|
||||
<div class="settings__general-update-buttons">
|
||||
<button class="settings__general-restart-btn">
|
||||
<button
|
||||
class="settings__general-restart-btn"
|
||||
onClick={installUpdateClicked}
|
||||
>
|
||||
{Locale.setGenReloadToUpdate}
|
||||
</button>
|
||||
</div>
|
||||
|
@ -42,16 +55,17 @@ export const SettingsGeneralUpdateView: FunctionComponent<{
|
|||
<>
|
||||
<h2>{Locale.setGenUpdate}</h2>
|
||||
<div>
|
||||
<select class="settings__general-auto-update settings__select input-base">
|
||||
<option value="install" selected={autoUpdate === 'install'}>
|
||||
{Locale.setGenUpdateAuto}
|
||||
</option>
|
||||
<option value="check" selected={autoUpdate === 'check'}>
|
||||
{Locale.setGenUpdateCheck}
|
||||
</option>
|
||||
<option value="" selected={!autoUpdate}>
|
||||
{Locale.setGenNoUpdate}
|
||||
</option>
|
||||
<select
|
||||
class="settings__general-auto-update settings__select input-base"
|
||||
value={autoUpdate || ''}
|
||||
onChange={(e) => {
|
||||
const val = (e.target as HTMLSelectElement).value || null;
|
||||
autoUpdateChanged(val as AppSettingsAutoUpdate | null);
|
||||
}}
|
||||
>
|
||||
<option value="install">{Locale.setGenUpdateAuto}</option>
|
||||
<option value="check">{Locale.setGenUpdateCheck}</option>
|
||||
<option value="">{Locale.setGenNoUpdate}</option>
|
||||
</select>
|
||||
<div>{updateInfo}</div>
|
||||
<a href={Links.ReleaseNotes} target="_blank" rel="noreferrer">
|
||||
|
@ -64,17 +78,26 @@ export const SettingsGeneralUpdateView: FunctionComponent<{
|
|||
{Locale.setGenUpdateChecking}
|
||||
</button>
|
||||
) : (
|
||||
<button class="settings__general-update-btn btn-silent">
|
||||
<button
|
||||
class="settings__general-update-btn btn-silent"
|
||||
onClick={checkUpdateClicked}
|
||||
>
|
||||
{Locale.setGenCheckUpdate}
|
||||
</button>
|
||||
)}
|
||||
{updateReady ? (
|
||||
<button class="settings__general-restart-btn">
|
||||
<button
|
||||
class="settings__general-restart-btn"
|
||||
onClick={installUpdateClicked}
|
||||
>
|
||||
{Locale.setGenRestartToUpdate}
|
||||
</button>
|
||||
) : null}
|
||||
{updateFound ? (
|
||||
<button class="settings__general-update-found-btn">
|
||||
<button
|
||||
class="settings__general-update-found-btn"
|
||||
onClick={downloadAndInstallUpdateClicked}
|
||||
>
|
||||
{Locale.setGenDownloadAndRestart}
|
||||
</button>
|
||||
) : null}
|
||||
|
|
|
@ -18,6 +18,11 @@ export const SettingsGeneralView: FunctionComponent<{
|
|||
if (selectedMenuAnchor) {
|
||||
const el = document.getElementById(selectedMenuAnchor);
|
||||
el?.scrollIntoView();
|
||||
} else {
|
||||
const scroller = contentRef.current.closest('.scroller');
|
||||
if (scroller) {
|
||||
scroller.scrollTop = 0;
|
||||
}
|
||||
}
|
||||
}, [selectedMenuAnchor]);
|
||||
|
||||
|
|
Loading…
Reference in New Issue