Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/marius-wieschollek/passwords-webextension.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMarius David Wieschollek <passwords.public@mdns.eu>2020-12-20 15:39:28 +0300
committerMarius David Wieschollek <passwords.public@mdns.eu>2020-12-20 15:39:28 +0300
commit345f7f0d2528cff8a706b6cec6e7ea841a650570 (patch)
tree87fe764173dab704b1102829acef076f9899536f /src
parent71243ba36fe4ac09e4ba628dc8c60c8e3bc628b7 (diff)
Add debug tab in options with internal data
Signed-off-by: Marius David Wieschollek <passwords.public@mdns.eu>
Diffstat (limited to 'src')
-rw-r--r--src/js/App/Options.js8
-rw-r--r--src/js/Controller/Options/DebugData.js31
-rw-r--r--src/js/Helper/HiddenFolderHelper.js5
-rw-r--r--src/js/Manager/ControllerManager.js7
-rw-r--r--src/js/Manager/ErrorManager.js10
-rw-r--r--src/platform/generic/_locales/de/messages.json46
-rw-r--r--src/platform/generic/_locales/en/messages.json492
-rw-r--r--src/vue/App/Options.vue87
-rw-r--r--src/vue/Components/Options/Debug.vue192
-rw-r--r--src/vue/Components/Tabs.vue2
10 files changed, 609 insertions, 271 deletions
diff --git a/src/js/App/Options.js b/src/js/App/Options.js
index d107243..eb4f8ee 100644
--- a/src/js/App/Options.js
+++ b/src/js/App/Options.js
@@ -49,7 +49,13 @@ class Options {
async _initVue() {
let reply = await MessageService.send('options.status'),
status = reply.getPayload();
- document.body.classList.add(status.device);
+ document.body.classList.add(status.device)
+
+ Vue.filter('capitalize', function (value) {
+ if (!value) return ''
+ value = value.toString()
+ return value.charAt(0).toUpperCase() + value.slice(1)
+ })
this._app = new Vue({propsData: status, ...App});
}
diff --git a/src/js/Controller/Options/DebugData.js b/src/js/Controller/Options/DebugData.js
new file mode 100644
index 0000000..fb2c84a
--- /dev/null
+++ b/src/js/Controller/Options/DebugData.js
@@ -0,0 +1,31 @@
+import AbstractController from '@js/Controller/AbstractController';
+import HiddenFolderHelper from "@js/Helper/HiddenFolderHelper";
+import ErrorManager from "@js/Manager/ErrorManager";
+import ServerManager from "@js/Manager/ServerManager";
+
+export default class DebugData extends AbstractController {
+
+ /**
+ *
+ * @param {Message} message
+ * @param {Message} reply
+ */
+ async execute(message, reply) {
+ let data = {
+ hidden: {id: null},
+ errors: ErrorManager.errors
+ };
+
+ try {
+ let api = await ServerManager.getDefaultApi(),
+ helper = new HiddenFolderHelper();
+ data.hidden.id = await helper.getHiddenFolderId(api);
+ } catch(e) {
+ ErrorManager.logError(e)
+ }
+
+ reply
+ .setType('debug.data')
+ .setPayload(data);
+ }
+} \ No newline at end of file
diff --git a/src/js/Helper/HiddenFolderHelper.js b/src/js/Helper/HiddenFolderHelper.js
index 9a63043..5cc3fc6 100644
--- a/src/js/Helper/HiddenFolderHelper.js
+++ b/src/js/Helper/HiddenFolderHelper.js
@@ -1,6 +1,5 @@
import ServerRepository from "@js/Repositories/ServerRepository";
import ErrorManager from "@js/Manager/ErrorManager";
-import Setting from "passwords-client/src/Model/Setting/Setting";
import NotFoundError from "passwords-client/src/Exception/Http/NotFoundError";
import SettingsService from "@js/Services/SettingsService";
@@ -63,8 +62,8 @@ export default class HiddenFolderHelper {
* @private
*/
async _createHiddenFolder(api) {
- let server = api.getServer(),
- folder = api
+ let server = api.getServer(),
+ folder = api
.getClass('model.folder')
.setLabel('BrowserExtensionPrivateFolder')
.setHidden(true);
diff --git a/src/js/Manager/ControllerManager.js b/src/js/Manager/ControllerManager.js
index fb4e7d3..20ecddd 100644
--- a/src/js/Manager/ControllerManager.js
+++ b/src/js/Manager/ControllerManager.js
@@ -166,6 +166,13 @@ class ControllerManager {
}
);
MessageService.listen(
+ 'options.debug.data',
+ async (message, reply) => {
+ let module = await import(/* webpackChunkName: "DebugData" */ '@js/Controller/Options/DebugData');
+ await this._executeController(module, message, reply);
+ }
+ );
+ MessageService.listen(
'setting.set',
async (message, reply) => {
let module = await import(/* webpackChunkName: "SettingSet" */ '@js/Controller/Setting/Set');
diff --git a/src/js/Manager/ErrorManager.js b/src/js/Manager/ErrorManager.js
index dd27a91..f7dc53a 100644
--- a/src/js/Manager/ErrorManager.js
+++ b/src/js/Manager/ErrorManager.js
@@ -4,6 +4,10 @@ import QueueService from '@js/Services/QueueService';
class ErrorManager {
+ get errors() {
+ return this._errors;
+ }
+
get catchEvt() {
return this.catch();
}
@@ -118,7 +122,8 @@ class ErrorManager {
let error = new Error();
return {
data,
- stack: error.stack ? error.stack:''
+ stack: error.stack ? error.stack:'',
+ time: Date.now()
};
}
@@ -136,7 +141,8 @@ class ErrorManager {
message: error.message,
file : error.fileName,
line : error.lineNumber,
- stack : error.stack ? error.stack:''
+ stack : error.stack ? error.stack:'',
+ time : Date.now()
};
}
diff --git a/src/platform/generic/_locales/de/messages.json b/src/platform/generic/_locales/de/messages.json
index e52c680..8f5f083 100644
--- a/src/platform/generic/_locales/de/messages.json
+++ b/src/platform/generic/_locales/de/messages.json
@@ -45,6 +45,10 @@
"message" : "Weitere Einstellungen",
"description": ""
},
+ "SettingsTabDebug" : {
+ "message" : "Debug",
+ "description": ""
+ },
"SettingsAccountsMain" : {
"message" : "Standardkonto für neue Passwörter",
"description": ""
@@ -999,8 +1003,48 @@
"message" : "Felder von Anmeldeformularen zeigen",
"description": ""
},
- "AutofillBadPasswordWarning" : {
+ "AutofillBadPasswordWarning" : {
"message" : "Dieses Passwort ist kompromittiert und sollte sofort geändert werden",
"description": ""
+ },
+ "DebugInternalStats" : {
+ "message" : "Interner Status",
+ "description": ""
+ },
+ "DebugInfoExtensionVersion" : {
+ "message" : "Extension Version",
+ "description": ""
+ },
+ "DebugInfoExtensionPlatform" : {
+ "message" : "Extension Plattform",
+ "description": ""
+ },
+ "DebugInfoExtensionEnvironment" : {
+ "message" : "Extension Modus",
+ "description": ""
+ },
+ "DebugInfoHiddenFolderId" : {
+ "message" : "ID des Ordners für private Passwörter",
+ "description": ""
+ },
+ "DebugErrorLog" : {
+ "message" : "Fehlerberichte",
+ "description": ""
+ },
+ "DebugErrorNoMessage" : {
+ "message" : "Keine Fehlerbeschreibung",
+ "description": ""
+ },
+ "DebugErrorNoDetails" : {
+ "message" : "Keine Fehlerdetails",
+ "description": ""
+ },
+ "DebugErrorDataCopied" : {
+ "message" : "Fehlerbericht in die Zwischenablage kopiert",
+ "description": ""
+ },
+ "DebugNoErrors" : {
+ "message" : "Keine Fehlerberichte vorhanden",
+ "description": ""
}
} \ No newline at end of file
diff --git a/src/platform/generic/_locales/en/messages.json b/src/platform/generic/_locales/en/messages.json
index 1ac9030..706f0a8 100644
--- a/src/platform/generic/_locales/en/messages.json
+++ b/src/platform/generic/_locales/en/messages.json
@@ -1,25 +1,25 @@
{
- "extensionName" : {
+ "extensionName" : {
"message" : "Passwords for Nextcloud Client",
"description": "Name of the extension."
},
- "extensionDescription" : {
+ "extensionDescription" : {
"message" : "The official browser extension for Passwords for Nextcloud",
"description": "Description of the extension."
},
- "browserActionTitle" : {
+ "browserActionTitle" : {
"message" : "Passwords",
"description": "Title of the button in the browser bar"
},
- "contextMenuTitle" : {
+ "contextMenuTitle" : {
"message" : "Passwords",
"description": "Title of the context menu item"
},
- "protocolHandler" : {
+ "protocolHandler" : {
"message" : "PassLink Client",
"description": "Title of the custom protocol handler"
},
- "BrowserActionTitleCounter" : {
+ "BrowserActionTitleCounter" : {
"message" : "Passwords ($COUNTER$)",
"description" : "Title of the button in the browser bar with suggestion counter",
"placeholders": {
@@ -29,7 +29,7 @@
}
}
},
- "UserAgent" : {
+ "UserAgent" : {
"message" : "Official Passwords Client for $BROWSER$ on $OS$",
"description" : "The user agent used for api requests. Only ASCII characters allowed",
"placeholders": {
@@ -43,143 +43,147 @@
}
}
},
- "MigrationAccountName" : {
+ "MigrationAccountName" : {
"message" : "Nextcloud Account",
"description": "Label assigned to the account used by the v1.x migration"
},
- "SettingsTabAccounts" : {
+ "SettingsTabAccounts" : {
"message" : "Accounts",
"description": ""
},
- "SettingsTabTheming" : {
+ "SettingsTabTheming" : {
"message" : "Theming",
"description": ""
},
- "SettingsTabOther" : {
+ "SettingsTabOther" : {
"message" : "Other Settings",
"description": ""
},
- "SettingsAccountsMain" : {
+ "SettingsTabDebug" : {
+ "message" : "Debug",
+ "description": ""
+ },
+ "SettingsAccountsMain" : {
"message" : "Default account for new passwords",
"description": ""
},
- "AutofillSettings" : {
+ "AutofillSettings" : {
"message" : "Password autofill",
"description": ""
},
- "SettingsPopupAutoclose" : {
+ "SettingsPopupAutoclose" : {
"message" : "Close popup after autofill",
"description": ""
},
- "SettingsPasswordAutosubmit" : {
+ "SettingsPasswordAutosubmit" : {
"message" : "Automatically submit login forms",
"description": ""
},
- "NotificationSettings" : {
+ "NotificationSettings" : {
"message" : "Notifications",
"description": ""
},
- "SettingsNotifyPasswordNew" : {
+ "SettingsNotifyPasswordNew" : {
"message" : "Notification for new passwords",
"description": ""
},
- "SettingsNotifyPasswordUpdate": {
+ "SettingsNotifyPasswordUpdate" : {
"message" : "Notification for updated passwords",
"description": ""
},
- "SearchSettings" : {
+ "SearchSettings" : {
"message" : "Search",
"description": ""
},
- "SettingsPopupRelatedSearch" : {
+ "SettingsPopupRelatedSearch" : {
"message" : "Search on type from \"Related\" tab",
"description": ""
},
- "AccountList" : {
+ "AccountList" : {
"message" : "User accounts",
"description": ""
},
- "NoAccounts" : {
+ "NoAccounts" : {
"message" : "There are no accounts yet. Click here to create one.",
"description": ""
},
- "NewServer" : {
+ "NewServer" : {
"message" : "Create account",
"description": ""
},
- "ServerSaveTitle" : {
+ "ServerSaveTitle" : {
"message" : "Account saved",
"description": ""
},
- "ServerSaveMessage" : {
+ "ServerSaveMessage" : {
"message" : "All changes were applied successfully",
"description": ""
},
- "ServerSaveErrorTitle" : {
+ "ServerSaveErrorTitle" : {
"message" : "Saving failed",
"description": ""
},
- "ServerCreatedMessage" : {
+ "ServerCreatedMessage" : {
"message" : "The account has been created and is ready to be used",
"description": ""
},
- "ServerDisabledWarning" : {
+ "ServerDisabledWarning" : {
"message" : "This account is deactivated. It will be activated after it was saved successfully.",
"description": ""
},
- "ServerLabel" : {
+ "ServerLabel" : {
"message" : "Name",
"description": ""
},
- "ServerBaseUrl" : {
+ "ServerBaseUrl" : {
"message" : "Url",
"description": ""
},
- "ServerUser" : {
+ "ServerUser" : {
"message" : "User",
"description": ""
},
- "ServerToken" : {
+ "ServerToken" : {
"message" : "Token",
"description": ""
},
- "TabRelated" : {
+ "TabRelated" : {
"message" : "Suggestions",
"description": ""
},
- "TabSearch" : {
+ "TabSearch" : {
"message" : "Search",
"description": ""
},
- "TabBrowse" : {
+ "TabBrowse" : {
"message" : "Browse",
"description": ""
},
- "TabCollected" : {
+ "TabCollected" : {
"message" : "Collected",
"description": ""
},
- "TabTools" : {
+ "TabTools" : {
"message" : "Tools",
"description": ""
},
- "ValidationLabel" : {
+ "ValidationLabel" : {
"message" : "label",
"description": ""
},
- "ValidationUser" : {
+ "ValidationUser" : {
"message" : "user",
"description": ""
},
- "ValidationToken" : {
+ "ValidationToken" : {
"message" : "token",
"description": ""
},
- "ValidationBaseUrl" : {
+ "ValidationBaseUrl" : {
"message" : "base url",
"description": ""
},
- "ValidationNotEmpty" : {
+ "ValidationNotEmpty" : {
"message" : "The $FIELD$ can not be empty",
"description" : "",
"placeholders": {
@@ -189,7 +193,7 @@
}
}
},
- "ValidationMinLength" : {
+ "ValidationMinLength" : {
"message" : "The $FIELD$ must be at least $MIN$ characters long",
"description" : "",
"placeholders": {
@@ -203,7 +207,7 @@
}
}
},
- "ValidationMaxLength" : {
+ "ValidationMaxLength" : {
"message" : "The $FIELD$ must be shorter than $MAX$ characters",
"description" : "",
"placeholders": {
@@ -217,23 +221,23 @@
}
}
},
- "ValidationFailed" : {
+ "ValidationFailed" : {
"message" : "Validation failed",
"description": ""
},
- "ValidationNotAnUrl" : {
+ "ValidationNotAnUrl" : {
"message" : "The base url must be a valid url",
"description": ""
},
- "ValidationNotAToken" : {
+ "ValidationNotAToken" : {
"message" : "The token must be a valid Nextcloud token",
"description": ""
},
- "ValidationDuplicate" : {
+ "ValidationDuplicate" : {
"message" : "There is already an account for this user on this Nextcloud.",
"description": ""
},
- "ValidationNoConnection" : {
+ "ValidationNoConnection" : {
"message" : "Unable to connect to $URL$",
"description" : "",
"placeholders": {
@@ -243,7 +247,7 @@
}
}
},
- "ValidationUnauthorizedError" : {
+ "ValidationUnauthorizedError" : {
"message" : "The server at $URL$ did not accept the login data",
"description" : "",
"placeholders": {
@@ -253,7 +257,7 @@
}
}
},
- "ValidationHttpError" : {
+ "ValidationHttpError" : {
"message" : "Trying to connect to $URL$ resulted in $ERROR$",
"description" : "",
"placeholders": {
@@ -267,7 +271,7 @@
}
}
},
- "ValidationConnectionError" : {
+ "ValidationConnectionError" : {
"message" : "Trying to connect to $URL$ resulted in $ERROR$",
"description" : "",
"placeholders": {
@@ -281,43 +285,43 @@
}
}
},
- "ValidationServerVersion" : {
+ "ValidationServerVersion" : {
"message" : "The app version installed on the server is outdated",
"description": ""
},
- "NoRelatedPasswords" : {
+ "NoRelatedPasswords" : {
"message" : "Did not find any related passwords",
"description": "Used in the related tab when no entries match the current website"
},
- "NoSearchResults" : {
+ "NoSearchResults" : {
"message" : "Did not find any passwords matching your query",
"description": "Used in the search tab when no entries match the search query"
},
- "NoSearchQuery" : {
+ "NoSearchQuery" : {
"message" : "Write into the search box to find passwords",
"description": "Used in the search tab when there is no search query"
},
- "NoCollectedPasswords" : {
+ "NoCollectedPasswords" : {
"message" : "No new passwords found",
"description": "Used in the collected tab when no new passwords have been found"
},
- "AddPasswordForCurrentTab" : {
+ "AddPasswordForCurrentTab" : {
"message" : "Add account for current tab",
"description": "Used in the collected tab for the option to add a blank entry with just the url of the current tab"
},
- "NoServerItems" : {
+ "NoServerItems" : {
"message" : "No elements found",
"description": "Used in the browse tab when a server has no entries to list"
},
- "SearchPlaceholder" : {
+ "SearchPlaceholder" : {
"message" : "Find passwords",
"description": "Placeholder text of the search box"
},
- "MiningItemIsNew" : {
+ "MiningItemIsNew" : {
"message" : "This is a new password",
"description": ""
},
- "MiningItemIsUpdate" : {
+ "MiningItemIsUpdate" : {
"message" : "This seems to be an update of \"$PASSWORD$\"",
"description" : "",
"placeholders": {
@@ -327,79 +331,79 @@
}
}
},
- "TitleClickToEdit" : {
+ "TitleClickToEdit" : {
"message" : "Double click to edit",
"description": ""
},
- "TitleEnterToExit" : {
+ "TitleEnterToExit" : {
"message" : "Press enter to save",
"description": ""
},
- "LabelLabel" : {
+ "LabelLabel" : {
"message" : "Name",
"description": ""
},
- "LabelPassword" : {
+ "LabelPassword" : {
"message" : "Password",
"description": ""
},
- "LabelUsername" : {
+ "LabelUsername" : {
"message" : "User",
"description": ""
},
- "LabelUrl" : {
+ "LabelUrl" : {
"message" : "Url",
"description": ""
},
- "LabelUser" : {
+ "LabelUser" : {
"message" : "User",
"description": ""
},
- "LabelPasswords" : {
+ "LabelPasswords" : {
"message" : "Passwords",
"description": ""
},
- "LabelFolders" : {
+ "LabelFolders" : {
"message" : "Folders",
"description": ""
},
- "LabelTags" : {
+ "LabelTags" : {
"message" : "Tags",
"description": ""
},
- "LabelHidden" : {
+ "LabelHidden" : {
"message" : "Incognito Password",
"description": ""
},
- "PlaceholderPassword" : {
+ "PlaceholderPassword" : {
"message" : "Password",
"description": ""
},
- "PlaceholderToken" : {
+ "PlaceholderToken" : {
"message" : "Two-Factor Token",
"description": ""
},
- "ButtonLogin" : {
+ "ButtonLogin" : {
"message" : "Login",
"description": ""
},
- "AuthorizationFailedTitle" : {
+ "AuthorizationFailedTitle" : {
"message" : "Authorization failed",
"description": ""
},
- "AuthorizationFailedText" : {
+ "AuthorizationFailedText" : {
"message" : "Access to the password database with the provided login was denied",
"description": ""
},
- "TokenRequestFailed" : {
+ "TokenRequestFailed" : {
"message" : "Token request failed",
"description": ""
},
- "NotifyNewPasswordTitle" : {
+ "NotifyNewPasswordTitle" : {
"message" : "New password detected",
"description": ""
},
- "NotifyNewPasswordText" : {
+ "NotifyNewPasswordText" : {
"message" : "A new password for \"$LABEL$\" was detected.",
"description" : "",
"placeholders": {
@@ -409,7 +413,7 @@
}
}
},
- "NotifyNewPasswordTextFF" : {
+ "NotifyNewPasswordTextFF" : {
"message" : "A new password for \"$LABEL$\" was detected. Click the passwords icon to view and save it.",
"description" : "",
"placeholders": {
@@ -419,11 +423,11 @@
}
}
},
- "NotifyUpdatePasswordTitle" : {
+ "NotifyUpdatePasswordTitle" : {
"message" : "Updated password detected",
"description": ""
},
- "NotifyUpdatePasswordText" : {
+ "NotifyUpdatePasswordText" : {
"message" : "An update for \"$LABEL$\" was detected.",
"description" : "",
"placeholders": {
@@ -433,7 +437,7 @@
}
}
},
- "NotifyUpdatePasswordTextFF" : {
+ "NotifyUpdatePasswordTextFF" : {
"message" : "An update for \"$LABEL$\" was detected. Click the passwords icon to view and save it.",
"description" : "",
"placeholders": {
@@ -443,15 +447,15 @@
}
}
},
- "ButtonSave" : {
+ "ButtonSave" : {
"message" : "Save",
"description": "The save button of a password notification"
},
- "ButtonMore" : {
+ "ButtonMore" : {
"message" : "More Options",
"description": "The more options button of a password notification which opens the popup"
},
- "ToastServerCheckTitle" : {
+ "ToastServerCheckTitle" : {
"message" : "$SERVER$ needs to be upgraded",
"description" : "",
"placeholders": {
@@ -461,7 +465,7 @@
}
}
},
- "ToastServerCheckMessage" : {
+ "ToastServerCheckMessage" : {
"message" : "The account \"$SERVER$\" uses a server running an outdated version of passwords. The server must be updated before the account can be reactivated in the settings.",
"description" : "",
"placeholders": {
@@ -471,7 +475,7 @@
}
}
},
- "PasswordPastedSuccess" : {
+ "PasswordPastedSuccess" : {
"message" : "$LABEL$ pasted successfully",
"description" : "",
"placeholders": {
@@ -481,7 +485,7 @@
}
}
},
- "PasswordPastedError" : {
+ "PasswordPastedError" : {
"message" : "Could not paste $LABEL$",
"description" : "",
"placeholders": {
@@ -491,7 +495,7 @@
}
}
},
- "PasswordPropertyCopied" : {
+ "PasswordPropertyCopied" : {
"message" : "Copied $PROPERTY$",
"description" : "",
"placeholders": {
@@ -501,19 +505,19 @@
}
}
},
- "PropertyPassword" : {
+ "PropertyPassword" : {
"message" : "Password",
"description": ""
},
- "PropertyUsername" : {
+ "PropertyUsername" : {
"message" : "Username",
"description": ""
},
- "PropertyUrl" : {
+ "PropertyUrl" : {
"message" : "Url",
"description": ""
},
- "ServerConnectionErrorTitle" : {
+ "ServerConnectionErrorTitle" : {
"message" : "Unable to connect to $SERVER$",
"description" : "",
"placeholders": {
@@ -523,11 +527,11 @@
}
}
},
- "ServerCredentialsRejected" : {
+ "ServerCredentialsRejected" : {
"message" : "Server credentials rejected. Please update the login data in the settings.",
"description": ""
},
- "ServerHttpError" : {
+ "ServerHttpError" : {
"message" : "HTTP connection error: $ERROR$",
"description" : "",
"placeholders": {
@@ -537,15 +541,15 @@
}
}
},
- "ServerNetworkError" : {
+ "ServerNetworkError" : {
"message" : "A network error occurred. Please check if you're online and the server is reachable.",
"description": ""
},
- "ServerUnknownError" : {
+ "ServerUnknownError" : {
"message" : "Unknown error.",
"description": ""
},
- "ServerGenericError" : {
+ "ServerGenericError" : {
"message" : "Error: $ERROR$",
"description" : "",
"placeholders": {
@@ -555,287 +559,287 @@
}
}
},
- "DemoInfoNotification" : {
+ "DemoInfoNotification" : {
"message" : "Info notification",
"description": ""
},
- "DemoSuccessNotification" : {
+ "DemoSuccessNotification" : {
"message" : "Success notification",
"description": ""
},
- "DemoWarningNotification" : {
+ "DemoWarningNotification" : {
"message" : "Warning notification",
"description": ""
},
- "DemoErrorNotification" : {
+ "DemoErrorNotification" : {
"message" : "Error notification",
"description": ""
},
- "DemoText" : {
+ "DemoText" : {
"message" : "Demo",
"description": ""
},
- "SettingsThemeId" : {
+ "SettingsThemeId" : {
"message" : "Active theme",
"description": ""
},
- "ThemeDark" : {
+ "ThemeDark" : {
"message" : "Dark theme",
"description": ""
},
- "ThemeOledDark" : {
+ "ThemeOledDark" : {
"message" : "Dark OLED",
"description": ""
},
- "ThemeLight" : {
+ "ThemeLight" : {
"message" : "Default",
"description": ""
},
- "ThemeAdaptaLight" : {
+ "ThemeAdaptaLight" : {
"message" : "Adapta",
"description": ""
},
- "ThemeAdaptaTeal" : {
+ "ThemeAdaptaTeal" : {
"message" : "Adapta teal",
"description": ""
},
- "ThemeArcDark" : {
+ "ThemeArcDark" : {
"message" : "Arc dark",
"description": ""
},
- "ThemeArcLight" : {
+ "ThemeArcLight" : {
"message" : "Arc",
"description": ""
},
- "ThemeHacker" : {
+ "ThemeHacker" : {
"message" : "Hacker",
"description": ""
},
- "ThemeRGB" : {
+ "ThemeRGB" : {
"message" : "Gaming RGB",
"description": ""
},
- "ThemeCustom" : {
+ "ThemeCustom" : {
"message" : "Custom theme",
"description": ""
},
- "CustomFont" : {
+ "CustomFont" : {
"message" : "Font",
"description": ""
},
- "CustomDefaultElement" : {
+ "CustomDefaultElement" : {
"message" : "Default element",
"description": ""
},
- "CustomActiveElement" : {
+ "CustomActiveElement" : {
"message" : "Active element",
"description": ""
},
- "CustomButtons" : {
+ "CustomButtons" : {
"message" : "Buttons",
"description": ""
},
- "CustomToasts" : {
+ "CustomToasts" : {
"message" : "Toast notifications",
"description": ""
},
- "CustomBadge" : {
+ "CustomBadge" : {
"message" : "Browser icon",
"description": ""
},
- "BackgroundColorLabel" : {
+ "BackgroundColorLabel" : {
"message" : "Background color",
"description": ""
},
- "ForegroundColorLabel" : {
+ "ForegroundColorLabel" : {
"message" : "Foreground color",
"description": ""
},
- "BackgroundInheritLabel" : {
+ "BackgroundInheritLabel" : {
"message" : "Inherit background",
"description": ""
},
- "ForegroundInheritLabel" : {
+ "ForegroundInheritLabel" : {
"message" : "Inherit foreground",
"description": ""
},
- "BackgroundColorBaseTitle" : {
+ "BackgroundColorBaseTitle" : {
"message" : "This color is usually used for the background",
"description": ""
},
- "BackgroundColorHoverTitle" : {
+ "BackgroundColorHoverTitle" : {
"message" : "This color is used for the background if the element is active. It can also be used for the border of an inactive element",
"description": ""
},
- "ForegroundColorBaseTitle" : {
+ "ForegroundColorBaseTitle" : {
"message" : "This color is usually used for texts and borders",
"description": ""
},
- "ForegroundColorHoverTitle" : {
+ "ForegroundColorHoverTitle" : {
"message" : "This color is used for texts and borders if the element is active",
"description": ""
},
- "BackgroundInheritTitle" : {
+ "BackgroundInheritTitle" : {
"message" : "If activated, the value will be inherited from the parent element",
"description": ""
},
- "ForegroundInheritTitle" : {
+ "ForegroundInheritTitle" : {
"message" : "If activated, the value will be inherited from the parent element",
"description": ""
},
- "SettingsCustomFont" : {
+ "SettingsCustomFont" : {
"message" : "Font family",
"description": ""
},
- "FontDefault" : {
+ "FontDefault" : {
"message" : "Default",
"description": ""
},
- "FontMono" : {
+ "FontMono" : {
"message" : "Monospace",
"description": ""
},
- "FontSerif" : {
+ "FontSerif" : {
"message" : "Serif",
"description": ""
},
- "FontSans" : {
+ "FontSans" : {
"message" : "Sans serif",
"description": ""
},
- "FontLight" : {
+ "FontLight" : {
"message" : "Light",
"description": ""
},
- "FontNextcloud" : {
+ "FontNextcloud" : {
"message" : "Nextcloud",
"description": ""
},
- "FontOpenDyslexic" : {
+ "FontOpenDyslexic" : {
"message" : "Open Dyslexic",
"description": ""
},
- "FontCustom" : {
+ "FontCustom" : {
"message" : "Custom",
"description": ""
},
- "SettingsCustomFontSize" : {
+ "SettingsCustomFontSize" : {
"message" : "Font size",
"description": ""
},
- "FontSizeVerySmall" : {
+ "FontSizeVerySmall" : {
"message" : "Very small",
"description": ""
},
- "FontSizeSmall" : {
+ "FontSizeSmall" : {
"message" : "Small",
"description": ""
},
- "FontSizeDefault" : {
+ "FontSizeDefault" : {
"message" : "Default",
"description": ""
},
- "FontSizeMedium" : {
+ "FontSizeMedium" : {
"message" : "Medium",
"description": ""
},
- "FontSizeLarge" : {
+ "FontSizeLarge" : {
"message" : "Large",
"description": ""
},
- "FontSizeVeryLarge" : {
+ "FontSizeVeryLarge" : {
"message" : "Very large",
"description": ""
},
- "ToastInfoColors" : {
+ "ToastInfoColors" : {
"message" : "Info toast",
"description": ""
},
- "ToastSuccessColors" : {
+ "ToastSuccessColors" : {
"message" : "Success toast",
"description": ""
},
- "ToastWarningColors" : {
+ "ToastWarningColors" : {
"message" : "Warning toast",
"description": ""
},
- "ToastErrorColors" : {
+ "ToastErrorColors" : {
"message" : "Error toast",
"description": ""
},
- "ToastBackgroundTitle" : {
+ "ToastBackgroundTitle" : {
"message" : "Background color for popup messages",
"description": ""
},
- "ToastForegroundTitle" : {
+ "ToastForegroundTitle" : {
"message" : "Color for text and button backgrounds",
"description": ""
},
- "SettingsBadgeIcon" : {
+ "SettingsBadgeIcon" : {
"message" : "Toolbar icon",
"description": ""
},
- "BadgeIconAuto" : {
+ "BadgeIconAuto" : {
"message" : "Automatic",
"description": ""
},
- "BadgeIconLight" : {
+ "BadgeIconLight" : {
"message" : "Light icon",
"description": ""
},
- "BadgeIconMedium" : {
+ "BadgeIconMedium" : {
"message" : "Grey icon",
"description": ""
},
- "BadgeIconDark" : {
+ "BadgeIconDark" : {
"message" : "Dark icon",
"description": ""
},
- "BadgeIconNewLight" : {
+ "BadgeIconNewLight" : {
"message" : "Light modern icon",
"description": ""
},
- "BadgeIconNewMedium" : {
+ "BadgeIconNewMedium" : {
"message" : "Grey modern icon",
"description": ""
},
- "BadgeIconNewDark" : {
+ "BadgeIconNewDark" : {
"message" : "Dark modern icon",
"description": ""
},
- "CustomBadgeColors" : {
+ "CustomBadgeColors" : {
"message" : "Badge colors",
"description": ""
},
- "BadgeBackgroundTitle" : {
+ "BadgeBackgroundTitle" : {
"message" : "Background color of the badge",
"description": ""
},
- "BadgeForegroundTitle" : {
+ "BadgeForegroundTitle" : {
"message" : "Text color of the badge",
"description": ""
},
- "PasslinkErrorNoMessage" : {
+ "PasslinkErrorNoMessage" : {
"message" : "There has been an error but no error message was provided",
"description": ""
},
- "PasslinkNoLinkProvided" : {
+ "PasslinkNoLinkProvided" : {
"message" : "No link or action is missing",
"description": ""
},
- "PasslinkErrorClose" : {
+ "PasslinkErrorClose" : {
"message" : "Close",
"description": ""
},
- "PasslinkNoActiveAction" : {
+ "PasslinkNoActiveAction" : {
"message" : "There is no active passlink action of this type",
"description": ""
},
- "PasslinkConnectCheckCodes" : {
+ "PasslinkConnectCheckCodes" : {
"message" : "Check if the codes below match with the ones you see in the app. If they do, confirm the connection in the app and you're done.",
"description": ""
},
- "PasslinkConnectServer" : {
+ "PasslinkConnectServer" : {
"message" : "The new connection was saved as \"$LABEL$\"",
"description" : "",
"placeholders": {
@@ -845,121 +849,121 @@
}
}
},
- "PasslinkConnectNotFound" : {
+ "PasslinkConnectNotFound" : {
"message" : "This link is invalid. It may have been used already or is expired.",
"description": ""
},
- "PasslinkConnectRejected" : {
+ "PasslinkConnectRejected" : {
"message" : "The login request was rejected by the server.",
"description": ""
},
- "PasslinkConnectNetworkError" : {
+ "PasslinkConnectNetworkError" : {
"message" : "The connection to the server failed. Please check your network.",
"description": ""
},
- "PasslinkConnectSuccess" : {
+ "PasslinkConnectSuccess" : {
"message" : "Connection successful",
"description": ""
},
- "PasslinkConnectFailed" : {
+ "PasslinkConnectFailed" : {
"message" : "Connection failed",
"description": ""
},
- "PasslinkConnectSettings" : {
+ "PasslinkConnectSettings" : {
"message" : "Open settings",
"description": ""
},
- "PasslinkConnectClose" : {
+ "PasslinkConnectClose" : {
"message" : "Close the window",
"description": ""
},
- "PasslinkScanInstructions" : {
+ "PasslinkScanInstructions" : {
"message" : "Point your camera to the QR code and wait for it to be recognized and scanned.",
"description": "Instructions shown above the PassLink QR scanner telling the use to point his camera at the qr code he wants to scan"
},
- "PasslinkScanScanning" : {
+ "PasslinkScanScanning" : {
"message" : "Looking for a QR Code",
"description": "Message used by the PassLink QR scanner while the camera feed is scanned for a qr code"
},
- "PasslinkScanProcessingLink" : {
+ "PasslinkScanProcessingLink" : {
"message" : "Processing QR Code",
"description": "Message used by the PassLink QR scanner when a valid code was found and is now being analyzed"
},
- "PasslinkScanInvalidQrCode" : {
+ "PasslinkScanInvalidQrCode" : {
"message" : "This QR Code is not supported",
"description": "Message used by the PassLink QR scanner when the user scans a code that does not contain a valid and supported uri of Passlink"
},
- "QrNotAllowedError" : {
+ "QrNotAllowedError" : {
"message" : "Access to the camera was not granted",
"description": "Message used by the PassLink QR scanner when the user did not allow camera access"
},
- "QrNotFoundError" : {
+ "QrNotFoundError" : {
"message" : "No cameras were found on this device",
"description": "Message used by the PassLink QR scanner when the device has no cameras"
},
- "QrNotSupportedError" : {
+ "QrNotSupportedError" : {
"message" : "Insecure Context",
"description": "Message used by the PassLink QR scanner when the page was opened in an insecure context (http://). This should never happen"
},
- "QrNotReadableError" : {
+ "QrNotReadableError" : {
"message" : "Camera not accessible. Maybe it is already in use?",
"description": "Message used by the PassLink QR scanner when the camera stream can not be read"
},
- "QrOverconstrainedError" : {
+ "QrOverconstrainedError" : {
"message" : "Camera not suitable to be used",
"description": "Message used by the PassLink QR scanner when the camera is faulty"
},
- "QrStreamApiNotSupportedError": {
+ "QrStreamApiNotSupportedError" : {
"message" : "The Stream API is not supported by this browser",
"description": "Message used by the PassLink QR scanner when the browser does not support the required streaming api. This should never happen"
},
- "FirstRunConnectTitle" : {
+ "FirstRunConnectTitle" : {
"message" : "Connect to Nextcloud",
"description": ""
},
- "FirstRunConnectText" : {
+ "FirstRunConnectText" : {
"message" : "Open the passwords app, click on \"More\", open \"Apps & Extensions\" and open the PassLink Connect dialog.",
"description": ""
},
- "FirstRunConnectLink" : {
+ "FirstRunConnectLink" : {
"message" : "If the PassLink dialog is open on the same device, use the connect via link option",
"description": ""
},
- "FirstRunConnectScan" : {
+ "FirstRunConnectScan" : {
"message" : "If this is a different device, scan the PassLink Connect Code with the button below",
"description": ""
},
- "FirstRunConnectScanChrome" : {
+ "FirstRunConnectScanChrome" : {
"message" : "Click the button below and scan the PassLink Connect code",
"description": ""
},
- "FirstRunConnectManual" : {
+ "FirstRunConnectManual" : {
"message" : "You can also create the account manually in the extension settings",
"description": ""
},
- "FirstRunConnectScanButton" : {
+ "FirstRunConnectScanButton" : {
"message" : "Scan PassLink Code",
"description": ""
},
- "OpenSettings" : {
+ "OpenSettings" : {
"message" : "Open Extension Settings",
"description": ""
},
- "ToolsTabGeneratePassword" : {
+ "ToolsTabGeneratePassword" : {
"message" : "Generate Password",
"description": ""
},
- "ToolsTabDebugTools" : {
+ "ToolsTabDebugTools" : {
"message" : "Debug Tools",
"description": ""
},
- "GeneratedPasswordPlaceholder" : {
+ "GeneratedPasswordPlaceholder" : {
"message" : "Generated Password",
"description": ""
},
- "GeneratedPasswordTitle" : {
- "message" : "Password words: $WORDS$",
- "description": "",
+ "GeneratedPasswordTitle" : {
+ "message" : "Password words: $WORDS$",
+ "description" : "",
"placeholders": {
"words": {
"content": "$1",
@@ -967,41 +971,41 @@
}
}
},
- "LabelGenerateAddNumbers" : {
+ "LabelGenerateAddNumbers" : {
"message" : "Numbers",
- "description": ""
+ "description": "Label of the option to include numbers in the password generator in the tools tab"
},
- "LabelGenerateAddSpecial" : {
+ "LabelGenerateAddSpecial" : {
"message" : "Symbols",
- "description": ""
+ "description": "Label of the option to include special characters in the password generator in the tools tab"
},
- "LabelGenerateStrength" : {
+ "LabelGenerateStrength" : {
"message" : "Strength",
- "description": ""
+ "description": "Label of the option to set the strength in the password generator in the tools tab"
},
- "LabelGeneratorStrengthLow" : {
+ "LabelGeneratorStrengthLow" : {
"message" : "Low",
- "description": ""
+ "description": "Label of the low (0) strength option for the password generator in the tools tab"
},
- "LabelGeneratorStrengthStandard" : {
+ "LabelGeneratorStrengthStandard": {
"message" : "Standard",
- "description": ""
+ "description": "Label of the default (1) strength option for the password generator in the tools tab"
},
- "LabelGeneratorStrengthMedium" : {
+ "LabelGeneratorStrengthMedium" : {
"message" : "Medium",
- "description": ""
+ "description": "Label of the medium (2) strength option for the password generator in the tools tab"
},
"LabelGeneratorStrengthHigh" : {
"message" : "High",
- "description": ""
+ "description": "Label of the high (3) strength option for the password generator in the tools tab"
},
- "LabelGeneratorStrengthUltra" : {
+ "LabelGeneratorStrengthUltra" : {
"message" : "Ultra",
- "description": ""
+ "description": "Label of the very high (4) strength option for the password generator in the tools tab"
},
- "PasswordGenerateError" : {
- "message" : "Failed to generate a password: $ERROR$",
- "description": "",
+ "PasswordGenerateError" : {
+ "message" : "Failed to generate a password: $ERROR$",
+ "description" : "Notification shown when the generation of a password fails",
"placeholders": {
"error": {
"content": "$1",
@@ -1009,12 +1013,52 @@
}
}
},
- "DebugHighlightLoginForms" : {
+ "DebugHighlightLoginForms" : {
"message" : "Highlight Login Form Fields",
"description": ""
},
- "AutofillBadPasswordWarning" : {
+ "AutofillBadPasswordWarning" : {
"message" : "This password is compromised and should be changed immediately",
- "description": ""
+ "description": "Notification shown after the user used autofill for a password with the security status breached/compromised"
+ },
+ "DebugInternalStats" : {
+ "message" : "Internal Status",
+ "description": "Headline above the internal status section in the extension settings in the debug tab"
+ },
+ "DebugInfoExtensionVersion" : {
+ "message" : "Extension Version",
+ "description": "Description of the extension version in the internal status section in the debug tab in the extension settings"
+ },
+ "DebugInfoExtensionPlatform" : {
+ "message" : "Extension Platform",
+ "description": "Description of the extension platform (firefox or chrome) in the internal status section in the debug tab in the extension settings"
+ },
+ "DebugInfoExtensionEnvironment" : {
+ "message" : "Extension Mode",
+ "description": "Description of the extension mode (production or development) in the internal status section in the debug tab in the extension settings"
+ },
+ "DebugInfoHiddenFolderId" : {
+ "message" : "Hidden Passwords Folder ID",
+ "description": "Description of the id of the folder used to store hidden/private passwords in the internal status section in the debug tab in the extension settings"
+ },
+ "DebugErrorLog" : {
+ "message" : "Error Log",
+ "description": "Headline above the error logs section in the extension settings in the debug tab"
+ },
+ "DebugErrorNoMessage" : {
+ "message" : "No error message",
+ "description": "Used as error message for errors with no error message (but have a timestamp) in the error logs section in the extension settings in the debug tab"
+ },
+ "DebugErrorNoDetails" : {
+ "message" : "No error details",
+ "description": "Used as error message for errors with no details at all in the error logs section in the extension settings in the debug tab"
+ },
+ "DebugErrorDataCopied" : {
+ "message" : "Error details copied to clipboard",
+ "description": "Success notification when you copy an error report to the clipboard in the error logs section in the extension settings in the debug tab"
+ },
+ "DebugNoErrors" : {
+ "message" : "No errors in log",
+ "description": "Message shown when no error reports exist instead of the error logs in the error logs section in the extension settings in the debug tab"
}
}
diff --git a/src/vue/App/Options.vue b/src/vue/App/Options.vue
index fb69700..7251e8b 100644
--- a/src/vue/App/Options.vue
+++ b/src/vue/App/Options.vue
@@ -2,8 +2,9 @@
<div id="options">
<tabs :tabs="tabs">
<accounts slot="accounts"/>
- <theming slot="theming" />
+ <theming slot="theming"/>
<settings slot="other"/>
+ <debug slot="debug"/>
</tabs>
<div id="toasts"></div>
</div>
@@ -14,22 +15,30 @@
import Theming from '@vue/Components/Options/Theming';
import Accounts from '@vue/Components/Options/Accounts';
import Settings from '@vue/Components/Options/Settings';
+ import Debug from "@vue/Components/Options/Debug";
export default {
el : '#app',
- components: {Theming, Tabs, Accounts, Settings},
+ components: {Debug, Theming, Tabs, Accounts, Settings},
computed: {
tabs() {
return {
accounts: {
+ icon : 'user',
label: 'SettingsTabAccounts'
},
- theming : {
+ theming : {
+ icon : 'palette',
label: 'SettingsTabTheming'
},
other : {
+ icon : 'sliders-h',
label: 'SettingsTabOther'
+ },
+ debug : {
+ icon : 'bug',
+ label: 'SettingsTabDebug'
}
};
}
@@ -38,49 +47,49 @@
</script>
<style lang="scss">
- @import "@scss/includes";
- @import "@scssP/browser.scss";
+@import "@scss/includes";
+@import "@scssP/browser.scss";
- body {
- min-height : 600px;
+body {
+ min-height : 600px;
- select,
- input[type=text] {
- background-color : var(--element-bg-color);
- color : var(--element-fg-color);
- border : 1px solid var(--element-hover-bg-color);
- border-radius : 3px;
- font-weight : normal;
- cursor : text;
- padding : 3px;
- }
+ select,
+ input[type=text] {
+ background-color : var(--element-bg-color);
+ color : var(--element-fg-color);
+ border : 1px solid var(--element-hover-bg-color);
+ border-radius : 3px;
+ font-weight : normal;
+ cursor : text;
+ padding : 3px;
+ }
- select {
- cursor : pointer;
- }
+ select {
+ cursor : pointer;
+ }
- input[type=button] {
- background-color : var(--element-hover-bg-color);
- color : var(--element-hover-fg-color);
- border : 1px solid var(--element-hover-bg-color);
- border-radius : 3px;
- font-weight : normal;
- cursor : pointer;
+ input[type=button] {
+ background-color : var(--element-hover-bg-color);
+ color : var(--element-hover-fg-color);
+ border : 1px solid var(--element-hover-bg-color);
+ border-radius : 3px;
+ font-weight : normal;
+ cursor : pointer;
- &:hover {
- background-color : var(--button-hover-bg-color);
- color : var(--button-hover-fg-color);
- border : 1px solid var(--button-hover-bg-color);
- }
+ &:hover {
+ background-color : var(--button-hover-bg-color);
+ color : var(--button-hover-fg-color);
+ border : 1px solid var(--button-hover-bg-color);
}
+ }
- &.mobile {
- input,
- select,
- button {
- line-height : 3rem;
- padding : 0 1rem;
- }
+ &.mobile {
+ input,
+ select,
+ button {
+ line-height : 3rem;
+ padding : 0 1rem;
}
}
+}
</style> \ No newline at end of file
diff --git a/src/vue/Components/Options/Debug.vue b/src/vue/Components/Options/Debug.vue
new file mode 100644
index 0000000..3dccd6a
--- /dev/null
+++ b/src/vue/Components/Options/Debug.vue
@@ -0,0 +1,192 @@
+<template>
+ <div class="debug-settings">
+ <translate tag="h3" say="DebugInternalStats"/>
+ <div class="debug-info">
+ <translate class="label" say="DebugInfoExtensionVersion"/>
+ <span class="value">{{ app.version }}</span>
+ </div>
+ <div class="debug-info">
+ <translate class="label" say="DebugInfoExtensionPlatform"/>
+ <span class="value">{{ app.platform | capitalize }}</span>
+ </div>
+ <div class="debug-info">
+ <translate class="label" say="DebugInfoExtensionEnvironment"/>
+ <span class="value">{{ app.environment | capitalize }}</span>
+ </div>
+ <div class="debug-info">
+ <translate class="label" say="DebugInfoHiddenFolderId"/>
+ <span class="value">{{ hidden.id }}</span>
+ </div>
+
+ <translate tag="h3" say="DebugErrorLog"/>
+ <div class="debug-error-item" v-for="error in errors">
+ <div class="error-message" v-if="error.details && error.details.message" @click="showData">
+ {{ getTitle(error) }}
+ <icon font="regular" icon="clipboard" @click.stop="copy(error)"/>
+ </div>
+ <pre class="error-data">{{ error }}</pre>
+ </div>
+ <translate class="debug-no-errors" say="DebugNoErrors" v-if="errors.length === 0"/>
+ </div>
+</template>
+
+<script>
+ import MessageService from "@js/Services/MessageService";
+ import Translate from "@vue/Components/Translate";
+ import Icon from "@vue/Components/Icon";
+ import ToastService from "@js/Services/ToastService";
+ import ErrorManager from "@js/Manager/ErrorManager";
+ import LocalisationService from "@js/Services/LocalisationService";
+
+ export default {
+ components: {Icon, Translate},
+ data() {
+ return {
+ hidden: {
+ id: ''
+ },
+ errors: [],
+ app: {
+ version: process.env.APP_VERSION,
+ platform: process.env.APP_PLATFORM,
+ environment: process.env.NODE_ENV
+ }
+ };
+ },
+
+ mounted() {
+ MessageService.send('options.debug.data').then((reply) => {
+ let data = reply.getPayload();
+
+ if(data.hasOwnProperty('hidden')) {
+ this.hidden = data.hidden;
+ }
+
+ if(data.hasOwnProperty('errors')) {
+ this.errors = data.errors;
+ }
+ });
+ },
+
+ methods: {
+ getTitle(error) {
+ if(error.details) {
+ let label = '';
+ if(error.details.time) {
+ let date = new Date(error.details.time),
+ month = (date.getMonth() + 1).toString().padStart(2, '0'),
+ day = date.getDate().toString().padStart(2, '0'),
+ hours = (date.getHours() + 1).toString().padStart(2, '0'),
+ minutes = date.getMinutes().toString().padStart(2, '0'),
+ seconds = date.getSeconds().toString().padStart(2, '0');
+
+ label = `[${date.getFullYear()}-${month}-${day} ${hours}:${minutes}:${seconds}] `;
+ }
+
+ if(error.details.message) {
+ label += error.details.message;
+ } else {
+ label += LocalisationService.translate('DebugErrorNoMessage');
+ }
+ return label;
+ }
+
+ return LocalisationService.translate('DebugErrorNoDetails');
+ },
+ showData($event) {
+ $event.target.parentNode.classList.toggle('open');
+ },
+ copy(error) {
+ navigator.clipboard.writeText(JSON.stringify(error));
+
+ ToastService
+ .success('DebugErrorDataCopied')
+ .catch(ErrorManager.catchEvt);
+ }
+ }
+ };
+</script>
+
+<style lang="scss">
+.tab-container .tab.tab-label-debug {
+ flex-grow : 0;
+}
+
+.debug-settings {
+
+ h3 {
+ margin : 1.5rem 1rem .5rem 1rem;
+ }
+
+ .debug-info {
+ padding : .25rem 1rem;
+ display : flex;
+
+ .label {
+ flex-grow : 1;
+ }
+
+ .value {
+ user-select : text;
+ cursor : text;
+ }
+ }
+
+ .debug-error-item {
+ .error-message {
+ overflow : hidden;
+ background-color : var(--element-bg-color);
+ color : var(--element-fg-color);
+ box-shadow : var(--tab-border);
+ transition : var(--element-transition);
+ padding : 1rem;
+ white-space : nowrap;
+ text-overflow : ellipsis;
+ cursor : pointer;
+
+ &:hover {
+ background-color : var(--element-hover-bg-color);
+ color : var(--element-hover-fg-color);
+ box-shadow : var(--tab-border);
+ }
+
+ .icon {
+ float : right;
+ width : 3rem;
+ line-height : 3rem;
+ text-align : center;
+ margin : -1rem;
+ background-color : var(--button-bg-color);
+ color : var(--button-fg-color);
+ transition : var(--button-transition);
+
+ &:hover {
+ background-color : var(--button-hover-bg-color);
+ color : var(--button-hover-fg-color);
+ box-shadow : var(--tab-button-active-border);
+ }
+ }
+ }
+
+ .error-data {
+ width : 100vw;
+ overflow : auto;
+ padding : .25rem 1rem;
+ margin : 0;
+ display : none;
+ user-select : text;
+ cursor : text;
+ }
+
+ &.open .error-data {
+ display : block;
+ }
+ }
+
+ .debug-no-errors {
+ text-align : center;
+ padding : 1rem;
+ display : block;
+ }
+}
+</style> \ No newline at end of file
diff --git a/src/vue/Components/Tabs.vue b/src/vue/Components/Tabs.vue
index d07ce0f..94c703b 100644
--- a/src/vue/Components/Tabs.vue
+++ b/src/vue/Components/Tabs.vue
@@ -4,7 +4,7 @@
<div :key="name"
v-for="(tab, name) in tabs"
@click="setActive(name)"
- :class="{ active: isActive(name) }"
+ :class="`tab-label-${name} ${isActive(name) ? 'active':''}`"
class="tab">
<div>
<icon :icon="tab.icon" class="icon" v-if="tab.icon" font="solid"/>