advanced settings

This commit is contained in:
antelle 2021-07-04 14:35:54 +02:00
parent f9a79bf2c4
commit 8df3899920
No known key found for this signature in database
GPG Key ID: 63C9777AAB7C563C
9 changed files with 215 additions and 187 deletions

View File

@ -3,68 +3,12 @@ import { View } from 'framework/views/view';
import { Storage } from 'storage';
import { Updater } from 'comp/app/updater';
import { Launcher } from 'comp/launcher';
import { Alerts } from 'comp/ui/alerts';
import { Links } from 'const/links';
import { AppSettingsModel } from 'models/app-settings-model';
import { Locale } from 'util/locale';
import { SettingsLogsView } from 'views/settings/settings-logs-view';
import { minmax } from 'util/fn';
import { NativeModules } from 'comp/launcher/native-modules';
import template from 'templates/settings/settings-general.hbs';
class SettingsGeneralView extends View {
template = template;
events = {
'click .settings__general-theme': 'changeTheme',
'click .settings__general-auto-switch-theme': 'changeAuthSwitchTheme',
'change .settings__general-locale': 'changeLocale',
'change .settings__general-font-size': 'changeFontSize',
'change .settings__general-expand': 'changeExpandGroups',
'change .settings__general-auto-update': 'changeAutoUpdate',
'change .settings__general-idle-minutes': 'changeIdleMinutes',
'change .settings__general-clipboard': 'changeClipboard',
'change .settings__general-auto-save': 'changeAutoSave',
'change .settings__general-auto-save-interval': 'changeAutoSaveInterval',
'change .settings__general-remember-key-files': 'changeRememberKeyFiles',
'change .settings__general-minimize': 'changeMinimize',
'change .settings__general-minimize-on-field-copy': 'changeMinimizeOnFieldCopy',
'change .settings__general-audit-passwords': 'changeAuditPasswords',
'change .settings__general-audit-password-entropy': 'changeAuditPasswordEntropy',
'change .settings__general-exclude-pins-from-audit': 'changeExcludePinsFromAudit',
'change .settings__general-check-passwords-on-hibp': 'changeCheckPasswordsOnHIBP',
'click .settings__general-toggle-help-hibp': 'clickToggleHelpHIBP',
'change .settings__general-audit-password-age': 'changeAuditPasswordAge',
'change .settings__general-lock-on-minimize': 'changeLockOnMinimize',
'change .settings__general-lock-on-copy': 'changeLockOnCopy',
'change .settings__general-lock-on-auto-type': 'changeLockOnAutoType',
'change .settings__general-lock-on-os-lock': 'changeLockOnOsLock',
'change .settings__general-table-view': 'changeTableView',
'change .settings__general-colorful-icons': 'changeColorfulIcons',
'change .settings__general-use-markdown': 'changeUseMarkdown',
'change .settings__general-use-group-icon-for-entries': 'changeUseGroupIconForEntries',
'change .settings__general-direct-autotype': 'changeDirectAutotype',
'change .settings__general-autotype-title-filter': 'changeAutoTypeTitleFilter',
'change .settings__general-field-label-dblclick-autotype':
'changeFieldLabelDblClickAutoType',
'change .settings__general-device-owner-auth': 'changeDeviceOwnerAuth',
'change .settings__general-device-owner-auth-timeout': 'changeDeviceOwnerAuthTimeout',
'change .settings__general-titlebar-style': 'changeTitlebarStyle',
'click .settings__general-update-btn': 'checkUpdate',
'click .settings__general-restart-btn': 'installUpdateAndRestart',
'click .settings__general-download-update-btn': 'downloadUpdate',
'click .settings__general-update-found-btn': 'installFoundUpdate',
'change .settings__general-disable-offline-storage': 'changeDisableOfflineStorage',
'change .settings__general-short-lived-storage-token': 'changeShortLivedStorageToken',
'change .settings__general-prv-check': 'changeStorageEnabled',
'click .settings__general-prv-logout': 'logoutFromStorage',
'click .settings__general-show-advanced': 'showAdvancedSettings',
'click .settings__general-dev-tools-link': 'openDevTools',
'click .settings__general-try-beta-link': 'tryBeta',
'click .settings__general-show-logs-link': 'showLogs',
'click .settings__general-reload-app-link': 'reloadApp'
};
changeClipboard(e) {
const clipboardSeconds = +e.target.value;
AppSettingsModel.clipboardSeconds = clipboardSeconds;
@ -270,47 +214,6 @@ class SettingsGeneralView extends View {
$(e.target).remove();
}
}
showAdvancedSettings() {
this.$el
.find('.settings__general-show-advanced, .settings__general-advanced')
.toggleClass('hide');
this.scrollToBottom();
}
openDevTools() {
if (Launcher) {
Launcher.openDevTools();
}
}
tryBeta() {
if (this.appModel.files.hasUnsavedFiles()) {
Alerts.info({
header: Locale.setGenTryBetaWarning,
body: Locale.setGenTryBetaWarningBody
});
} else {
location.href = Links.BetaWebApp;
}
}
showLogs() {
if (this.views.logView) {
this.views.logView.remove();
}
this.views.logView = new SettingsLogsView();
this.views.logView.render();
this.scrollToBottom();
}
reloadApp() {
location.reload();
}
scrollToBottom() {
this.$el.closest('.scroller').scrollTop(this.$el.height());
}
}
export { SettingsGeneralView };

View File

@ -1,57 +0,0 @@
import { View } from 'framework/views/view';
import { StringFormat } from 'util/formatting/string-format';
import { Logger } from 'util/logger';
import template from 'templates/settings/settings-logs-view.hbs';
class SettingsLogsView extends View {
parent = '.settings__general-advanced';
template = template;
levelToColor = { debug: 'muted', warn: 'yellow', error: 'red' };
render() {
const logs = Logger.getLast().map((item) => ({
level: item.level,
color: this.levelToColor[item.level],
msg:
'[' +
StringFormat.padStr(item.level.toUpperCase(), 5) +
'] ' +
item.args.map((arg) => this.mapArg(arg)).join(' ')
}));
super.render({ logs });
}
mapArg(arg) {
if (arg === null) {
return 'null';
}
if (arg === undefined) {
return 'undefined';
}
if (arg === '') {
return '""';
}
if (!arg || !arg.toString() || typeof arg !== 'object') {
return arg ? arg.toString() : arg;
}
if (arg instanceof Array) {
return '[' + arg.map((item) => this.mapArg(item)).join(', ') + ']';
}
let str = arg.toString();
if (str === '[object Object]') {
const cache = [];
str = JSON.stringify(arg, (key, value) => {
if (typeof value === 'object' && value !== null) {
if (cache.indexOf(value) !== -1) {
return;
}
cache.push(value);
}
return value;
});
}
return str;
}
}
export { SettingsLogsView };

View File

@ -2,10 +2,53 @@ import { FunctionComponent, h } from 'preact';
import { SettingsGeneralAdvancedView } from 'views/settings/general/settings-general-advanced-view';
import { Launcher } from 'comp/launcher';
import { Features } from 'util/features';
import { useState } from 'preact/hooks';
import { Alerts } from 'comp/ui/alerts';
import { Locale } from 'util/locale';
import { Links } from 'const/links';
import { FileManager } from 'models/file-manager';
export const SettingsGeneralAdvanced: FunctionComponent = () => {
const [showAdvanced, setShowAdvanced] = useState(false);
const [showAppLogs, setShowAppLogs] = useState(false);
const showAdvancedChanged = () => {
setShowAdvanced(!showAdvanced);
};
const reloadAppClicked = () => {
location.reload();
};
const showDevToolsClicked = () => {
Launcher?.ipcRenderer.invoke('show-devtools');
};
const tryBetaClicked = () => {
if (FileManager.hasUnsavedFiles) {
Alerts.info({
header: Locale.setGenTryBetaWarning,
body: Locale.setGenTryBetaWarningBody
});
} else {
location.href = Links.BetaWebApp;
}
};
const showAppLogsClicked = () => {
setShowAppLogs(!showAppLogs);
};
return h(SettingsGeneralAdvancedView, {
showAdvanced,
showAppLogs,
devTools: !!Launcher,
showReloadApp: Features.isStandalone
showReloadApp: Features.isStandalone,
showAdvancedChanged,
reloadAppClicked,
showDevToolsClicked,
tryBetaClicked,
showAppLogsClicked
});
};

View File

@ -0,0 +1,67 @@
import { FunctionComponent, h } from 'preact';
import { SettingsGeneralAppLogsView } from 'views/settings/general/settings-general-app-logs-view';
import { Logger, LoggerLevel } from 'util/logger';
import { StringFormat } from 'util/formatting/string-format';
const LevelToColor: Partial<Record<LoggerLevel, string>> = {
[LoggerLevel.Debug]: 'muted',
[LoggerLevel.Warn]: 'yellow',
[LoggerLevel.Error]: 'red'
};
const LevelToString: Record<LoggerLevel, string> = {
[LoggerLevel.Off]: 'OFF',
[LoggerLevel.All]: 'ALL',
[LoggerLevel.Debug]: 'DEBUG',
[LoggerLevel.Warn]: 'WARN',
[LoggerLevel.Info]: 'INFO',
[LoggerLevel.Error]: 'ERROR'
};
function mapArg(arg: unknown): string {
if (arg === null) {
return 'null';
}
if (arg === undefined) {
return 'undefined';
}
if (arg === '') {
return '""';
}
if (!arg || !String(arg) || typeof arg !== 'object') {
return arg ? String(arg) : '';
}
if (arg instanceof Array) {
return '[' + arg.map((item) => mapArg(item)).join(', ') + ']';
}
let str = String(arg);
if (str === '[object Object]') {
const cache = new Set<unknown>();
str = JSON.stringify(arg, (key, value) => {
if (typeof value === 'object' && value !== null) {
if (cache.has(value)) {
return;
}
cache.add(value);
}
return value as unknown;
});
}
return str;
}
export const SettingsGeneralAppLogs: FunctionComponent = () => {
const logs = Logger.getLast().map((item) => ({
level: LevelToString[item.level],
color: LevelToColor[item.level],
msg:
'[' +
StringFormat.padStr(LevelToString[item.level], 5) +
'] ' +
item.args.map((arg) => mapArg(arg)).join(' ')
}));
return h(SettingsGeneralAppLogsView, {
logs
});
};

View File

@ -12,7 +12,7 @@ enum Level {
const MaxLogsToSave = 100;
interface LogItem {
level: string;
level: Level;
args: unknown[];
}
@ -50,7 +50,7 @@ class Logger {
debug(...args: unknown[]): void {
args[0] = `${this.getPrefix()}${String(args[0])}`;
if (this.level >= Level.Debug) {
Logger.saveLast('debug', args);
Logger.saveLast(Level.Debug, args);
console.log(...args);
}
}
@ -58,7 +58,7 @@ class Logger {
info(...args: unknown[]): void {
args[0] = `${this.getPrefix()}${String(args[0])}`;
if (this.level >= Level.Info) {
Logger.saveLast('info', args);
Logger.saveLast(Level.Info, args);
console.info(...args);
}
}
@ -66,7 +66,7 @@ class Logger {
warn(...args: unknown[]): void {
args[0] = `${this.getPrefix()}${String(args[0])}`;
if (this.level >= Level.Warn) {
Logger.saveLast('warn', args);
Logger.saveLast(Level.Warn, args);
console.warn(...args);
}
}
@ -74,12 +74,12 @@ class Logger {
error(...args: unknown[]): void {
args[0] = `${this.getPrefix()}${String(args[0])}`;
if (this.level >= Level.Error) {
Logger.saveLast('error', args);
Logger.saveLast(Level.Error, args);
console.error(...args);
}
}
static saveLast(level: string, args: unknown[]): void {
static saveLast(level: Level, args: unknown[]): void {
lastLogs.push({ level, args: Array.prototype.slice.call(args) });
if (lastLogs.length > MaxLogsToSave) {
lastLogs.shift();
@ -91,4 +91,4 @@ class Logger {
}
}
export { Logger };
export { Logger, Level as LoggerLevel };

View File

@ -1,34 +1,73 @@
import { FunctionComponent } from 'preact';
import { Locale } from 'util/locale';
import { SettingsGeneralAppLogs } from 'ui/settings/general/settings-general-app-logs';
export const SettingsGeneralAdvancedView: FunctionComponent<{
showAdvanced: boolean;
devTools: boolean;
showReloadApp: boolean;
}> = ({ devTools, showReloadApp }) => {
showAppLogs: boolean;
showAdvancedChanged: () => void;
reloadAppClicked: () => void;
showDevToolsClicked: () => void;
tryBetaClicked: () => void;
showAppLogsClicked: () => void;
}> = ({
showAdvanced,
devTools,
showReloadApp,
showAppLogs,
showAdvancedChanged,
reloadAppClicked,
showDevToolsClicked,
tryBetaClicked,
showAppLogsClicked
}) => {
return (
<>
<h2 id="advanced">{Locale.advanced}</h2>
<a class="settings__general-show-advanced">{Locale.setGenShowAdvanced}</a>
<div class="settings__general-advanced hide">
{devTools ? (
<>
<button class="btn-silent settings__general-dev-tools-link">
{Locale.setGenDevTools}
<p>
<a class="settings__general-show-advanced" onClick={showAdvancedChanged}>
{Locale.setGenShowAdvanced}
</a>
</p>
{showAdvanced ? (
<div class="settings__general-advanced">
{devTools ? (
<>
<button
class="btn-silent settings__general-dev-tools-link"
onClick={showDevToolsClicked}
>
{Locale.setGenDevTools}
</button>
<button
class="btn-silent settings__general-try-beta-link"
onClick={tryBetaClicked}
>
{Locale.setGenTryBeta}
</button>
</>
) : null}
{showReloadApp ? (
<button
class="btn-silent settings__general-reload-app-link"
onClick={reloadAppClicked}
>
{Locale.setGenReloadApp}
</button>
<button class="btn-silent settings__general-try-beta-link">
{Locale.setGenTryBeta}
</button>
</>
) : null}
{showReloadApp ? (
<button class="btn-silent settings__general-reload-app-link">
{Locale.setGenReloadApp}
) : null}
<button
class="btn-silent settings__general-show-logs-link"
onClick={showAppLogsClicked}
>
{Locale.setGenShowAppLogs}
</button>
) : null}
<button class="btn-silent settings__general-show-logs-link">
{Locale.setGenShowAppLogs}
</button>
</div>
{showAppLogs ? <SettingsGeneralAppLogs /> : null}
</div>
) : null}
</>
);
};

View File

@ -0,0 +1,37 @@
import { FunctionComponent } from 'preact';
import { classes } from 'util/ui/classes';
import { useLayoutEffect, useRef } from 'preact/hooks';
interface LogItem {
level: string;
msg: string;
color?: string;
}
export const SettingsGeneralAppLogsView: FunctionComponent<{
logs: LogItem[];
}> = ({ logs }) => {
const lastLine = useRef<HTMLDivElement>();
useLayoutEffect(() => {
lastLine.current.scrollIntoView();
}, []);
return (
<div class="settings__logs">
{logs.map((log, ix) => (
<pre
key={ix}
class={classes({
'settings__logs-log': true,
[`settings__logs-log--${log.level}`]: true,
[`${log.color || ''}-color`]: !!log.color
})}
>
{log.msg}
</pre>
))}
<div class="settings__logs-last" ref={lastLine} />
</div>
);
};

View File

@ -1,5 +0,0 @@
<div class="settings__logs">
{{#each logs as |log|}}
<pre class="settings__logs-log settings__logs-log--{{level}} {{#if color}}{{color}}-color{{/if}}">{{msg}}</pre>
{{/each}}
</div>

View File

@ -119,4 +119,5 @@ export interface DesktopIpcMainCalls {
'minimize-main-window': () => void;
'maximize-main-window': () => void;
'restore-main-window': () => void;
'show-devtools': () => void;
}