mirror of
https://github.com/keepassxreboot/keepassxc-browser.git
synced 2026-03-11 08:54:43 +00:00
Add support for Creating a new credential manually
This commit is contained in:
parent
44e8b45cc6
commit
12563189fa
11 changed files with 280 additions and 79 deletions
|
|
@ -350,6 +350,14 @@
|
|||
"message": "Choose a Custom Login Field",
|
||||
"description": "Help text for Custom Login Field banner."
|
||||
},
|
||||
"url": {
|
||||
"message": "URL",
|
||||
"description": "General text for URL."
|
||||
},
|
||||
"group": {
|
||||
"message": "Group",
|
||||
"description": "General text for group."
|
||||
},
|
||||
"username": {
|
||||
"message": "Username",
|
||||
"description": "General text for username."
|
||||
|
|
@ -414,6 +422,22 @@
|
|||
"message": "Settings",
|
||||
"description": "Popup Settings button text."
|
||||
},
|
||||
"popupAddCredentialsText": {
|
||||
"message": "Add a new credential",
|
||||
"description": "Popup add a new credential text."
|
||||
},
|
||||
"popupAddCredentialsPasswordText": {
|
||||
"message": "If empty, KeePassXC generates the password automatically.",
|
||||
"description": "Popup add a new credential password help text."
|
||||
},
|
||||
"popupAddCredentialGroupText": {
|
||||
"message": "Separate the group with slashes. For example: Group/ChildGroup. If empty, the default group is used.",
|
||||
"description": "Popup add a new credential group help text."
|
||||
},
|
||||
"popupAddCredentialsTitlePlaceholder": {
|
||||
"message": "Title",
|
||||
"description": "Title placeholder."
|
||||
},
|
||||
"popupChooseCredentialsText": {
|
||||
"message": "Choose Custom Login Fields",
|
||||
"description": "Popup credential choosing button text."
|
||||
|
|
|
|||
|
|
@ -267,6 +267,7 @@ kpxcEvent.messageHandlers = {
|
|||
'load_keyring': kpxcEvent.onLoadKeyRing,
|
||||
'load_settings': kpxcEvent.onLoadSettings,
|
||||
'lock_database': kpxcEvent.lockDatabase,
|
||||
'page_add_new_credential': page.addNewCredential,
|
||||
'page_clear_logins': kpxcEvent.pageClearLogins,
|
||||
'page_clear_submitted': page.clearSubmittedCredentials,
|
||||
'page_get_autosubmit_performed': page.getAutoSubmitPerformed,
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ const defaultSettings = {
|
|||
};
|
||||
|
||||
const AUTO_SUBMIT_TIMEOUT = 5000;
|
||||
const DEFAULT_BROWSER_GROUP = 'KeePassXC-Browser Passwords';
|
||||
|
||||
const page = {};
|
||||
page.autoSubmitPerformed = false;
|
||||
|
|
@ -149,6 +150,79 @@ page.switchTab = async function(tab) {
|
|||
});
|
||||
};
|
||||
|
||||
// Adds a new credential and handles setting/creating the group
|
||||
page.addNewCredential = async function(tab, args) {
|
||||
if (!tab || !page.tabs[tab.id]) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Traverse the groups and ensure all paths are found
|
||||
const getDefaultGroup = function(groups, defaultGroup) {
|
||||
const getGroup = function(group, splitted, depth = -1) {
|
||||
++depth;
|
||||
for (const g of group) {
|
||||
if (g.name === splitted[depth]) {
|
||||
if (splitted.length === (depth + 1)) {
|
||||
return [ g.name, g.uuid ];
|
||||
}
|
||||
return getGroup(g.children, splitted, depth);
|
||||
}
|
||||
}
|
||||
return [ '', '' ];
|
||||
};
|
||||
|
||||
const splitted = defaultGroup.split('/');
|
||||
return getGroup(groups, splitted);
|
||||
};
|
||||
|
||||
const saveToDefaultGroup = async function(creds) {
|
||||
const args = [ creds.username, creds.password, creds.url, creds.group ];
|
||||
const res = await keepass.addCredentials(tab, args);
|
||||
return res;
|
||||
};
|
||||
|
||||
const result = await keepass.getDatabaseGroups(tab);
|
||||
if (!result || !result.groups) {
|
||||
const res = await saveToDefaultGroup(args);
|
||||
return res;
|
||||
}
|
||||
|
||||
// Group has not been set
|
||||
if (args?.group === ''
|
||||
|| (!args?.group && (result.defaultGroup === '' || result.defaultGroup === DEFAULT_BROWSER_GROUP))) {
|
||||
const res = await saveToDefaultGroup(args);
|
||||
return res;
|
||||
}
|
||||
|
||||
// A specified group is used
|
||||
const [ groupName, groupUUID ] = getDefaultGroup(result.groups[0].children, args.group || result.defaultGroup);
|
||||
if (groupName === '' && groupUUID === '') {
|
||||
// Create a new group
|
||||
const newGroup = await keepass.createNewGroup(tab, [ args.group || result.defaultGroup ]);
|
||||
if (newGroup.name && newGroup.uuid) {
|
||||
const res = await keepass.addCredentials(tab, [
|
||||
args.username,
|
||||
args.password,
|
||||
args.url,
|
||||
newGroup.name,
|
||||
newGroup.uuid,
|
||||
]);
|
||||
return res;
|
||||
}
|
||||
|
||||
return 'canceled';
|
||||
}
|
||||
|
||||
const res = await await keepass.addCredentials(tab, [
|
||||
args.username,
|
||||
args.password,
|
||||
args.url,
|
||||
groupName,
|
||||
groupUUID,
|
||||
]);
|
||||
return res;
|
||||
};
|
||||
|
||||
page.clearCredentials = async function(tabId, complete) {
|
||||
if (!page.tabs[tabId]) {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
'use strict';
|
||||
|
||||
const DEFAULT_BROWSER_GROUP = 'KeePassXC-Browser Passwords';
|
||||
|
||||
const kpxcBanner = {};
|
||||
kpxcBanner.banner = undefined;
|
||||
kpxcBanner.created = false;
|
||||
|
|
@ -170,64 +168,16 @@ kpxcBanner.create = async function(credentials = {}) {
|
|||
};
|
||||
|
||||
kpxcBanner.saveNewCredentials = async function(credentials = {}) {
|
||||
const saveToDefaultGroup = async function(creds) {
|
||||
const args = [ creds.username, creds.password, creds.url ];
|
||||
const res = await sendMessage('add_credentials', args);
|
||||
kpxcBanner.verifyResult(res);
|
||||
};
|
||||
|
||||
const result = await sendMessage('get_database_groups');
|
||||
if (!result || !result.groups) {
|
||||
logError('Empty result from get_database_groups');
|
||||
await saveToDefaultGroup(credentials);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!result.defaultGroupAlwaysAsk) {
|
||||
if (result.defaultGroup === '' || result.defaultGroup === DEFAULT_BROWSER_GROUP) {
|
||||
await saveToDefaultGroup(credentials);
|
||||
return;
|
||||
} else {
|
||||
// A specified group is used
|
||||
let gname = '';
|
||||
let guuid = '';
|
||||
|
||||
if (result.defaultGroup.toLowerCase() === 'root') {
|
||||
result.defaultGroup = '/';
|
||||
gname = result.groups[0].name;
|
||||
guuid = result.groups[0].uuid;
|
||||
} else {
|
||||
[ gname, guuid ] = kpxcBanner.getDefaultGroup(result.groups[0].children, result.defaultGroup);
|
||||
if (gname === '' && guuid === '') {
|
||||
// Create a new group
|
||||
const newGroup = await sendMessage('create_new_group', [ result.defaultGroup ]);
|
||||
if (newGroup.name && newGroup.uuid) {
|
||||
const res = await sendMessage('add_credentials', [
|
||||
credentials.username,
|
||||
credentials.password,
|
||||
credentials.url,
|
||||
newGroup.name,
|
||||
newGroup.uuid,
|
||||
]);
|
||||
kpxcBanner.verifyResult(res);
|
||||
} else {
|
||||
kpxcUI.createNotification('error', tr('rememberErrorCreatingNewGroup'));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const res = await sendMessage('add_credentials', [
|
||||
credentials.username,
|
||||
credentials.password,
|
||||
credentials.url,
|
||||
gname,
|
||||
guuid,
|
||||
]);
|
||||
kpxcBanner.verifyResult(res);
|
||||
return;
|
||||
}
|
||||
const res = await sendMessage('page_add_new_credential', credentials);
|
||||
kpxcBanner.verifyResult(res, credentials.username);
|
||||
return;
|
||||
}
|
||||
|
||||
const addChildren = function(group, parentElement, depth = 0) {
|
||||
|
|
@ -366,19 +316,23 @@ kpxcBanner.updateCredentials = async function(credentials = {}) {
|
|||
}
|
||||
};
|
||||
|
||||
kpxcBanner.verifyResult = async function(code) {
|
||||
kpxcBanner.verifyResult = async function(code, givenUsername) {
|
||||
const username = givenUsername || kpxcBanner.credentials.username;
|
||||
|
||||
if (code === 'error') {
|
||||
kpxcUI.createNotification('error', tr('rememberErrorCannotSaveCredentials'));
|
||||
} else if (code === 'error_new_group') {
|
||||
kpxcUI.createNotification('error', tr('rememberErrorCreatingNewGroup'));
|
||||
} else if (code === 'created') {
|
||||
kpxcUI.createNotification(
|
||||
'success',
|
||||
tr('rememberCredentialsSaved', kpxcBanner.credentials.username || tr('rememberEmptyUsername')),
|
||||
tr('rememberCredentialsSaved', username || tr('rememberEmptyUsername')),
|
||||
);
|
||||
await kpxc.retrieveCredentials(true); // Forced reload
|
||||
} else if (code === 'updated') {
|
||||
kpxcUI.createNotification(
|
||||
'success',
|
||||
tr('rememberCredentialsUpdated', kpxcBanner.credentials.username || tr('rememberEmptyUsername')),
|
||||
tr('rememberCredentialsUpdated', username || tr('rememberEmptyUsername')),
|
||||
);
|
||||
await kpxc.retrieveCredentials(true); // Forced reload
|
||||
} else if (code === 'canceled') {
|
||||
|
|
@ -386,28 +340,10 @@ kpxcBanner.verifyResult = async function(code) {
|
|||
} else {
|
||||
kpxcUI.createNotification('error', tr('rememberErrorDatabaseClosed'));
|
||||
}
|
||||
|
||||
kpxcBanner.destroy();
|
||||
};
|
||||
|
||||
// Traverse the groups and ensure all paths are found
|
||||
kpxcBanner.getDefaultGroup = function(groups, defaultGroup) {
|
||||
const getGroup = function(group, splitted, depth = -1) {
|
||||
++depth;
|
||||
for (const g of group) {
|
||||
if (g.name === splitted[depth]) {
|
||||
if (splitted.length === (depth + 1)) {
|
||||
return [ g.name, g.uuid ];
|
||||
}
|
||||
return getGroup(g.children, splitted, depth);
|
||||
}
|
||||
}
|
||||
return [ '', '' ];
|
||||
};
|
||||
|
||||
const splitted = defaultGroup.split('/');
|
||||
return getGroup(groups, splitted);
|
||||
};
|
||||
|
||||
kpxcBanner.createCredentialDialog = async function() {
|
||||
kpxcBanner.shadowSelector('#kpxc-banner-btn-new').hidden = true;
|
||||
kpxcBanner.shadowSelector('#kpxc-banner-btn-update').hidden = true;
|
||||
|
|
|
|||
|
|
@ -945,6 +945,9 @@ browser.runtime.onMessage.addListener(async function(req, sender) {
|
|||
kpxc.triggerActivatedTab();
|
||||
} else if (req.action === 'add_allow_iframes_option') {
|
||||
kpxc.addToSitePreferences('allowIframes');
|
||||
} else if (req.action === 'add_new_credential') {
|
||||
const res = await sendMessage('page_add_new_credential', req.args);
|
||||
kpxcBanner.verifyResult(res, req.args.username);
|
||||
} else if (req.action === 'add_username_only_option') {
|
||||
kpxc.addToSitePreferences('usernameOnly', true);
|
||||
} else if (req.action === 'check_database_hash' && 'hash' in req) {
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ code {
|
|||
display: none;
|
||||
}
|
||||
|
||||
#options-button {
|
||||
#options-button, #add-credentials-button {
|
||||
height: 31px;
|
||||
width: 2.5rem;
|
||||
}
|
||||
|
|
@ -205,3 +205,8 @@ code {
|
|||
color: var(--kpxc-text-color) !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add new credentials */
|
||||
.help-text {
|
||||
margin-inline-start: 1.725em;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,9 @@
|
|||
<i class="fa fa-cog" aria-hidden="true"></i>
|
||||
</button>
|
||||
<button id="choose-custom-login-fields-button" class="btn btn-sm btn-warning" data-i18n="[title]popupChooseCredentialsText"></button>
|
||||
<button id="add-credentials-button" class="btn btn-sm btn-warning" data-i18n="[title]popupAddCredentialsText" style="display: none">
|
||||
<i class="fa fa-user-plus" aria-hidden="true"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="lock-button-area">
|
||||
<button id="lock-database-button" class="btn btn-sm btn-danger" data-i18n="[title]lockDatabase">
|
||||
|
|
@ -142,6 +145,56 @@
|
|||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="add-credentials" style="display: none">
|
||||
<hr>
|
||||
<span data-i18n="popupAddCredentialsText"></span>
|
||||
<form>
|
||||
<div class="content pt-2 pb-2">
|
||||
<div class="pb-2">
|
||||
<input class="form-control form-control-sm" type="text" id="add-credentials-title" data-i18n="[placeholder]popupAddCredentialsTitlePlaceholder" required>
|
||||
</div>
|
||||
<div class="pb-2">
|
||||
<input type="text" class="form-control form-control-sm" id="add-credentials-username" data-i18n="[placeholder]username" required>
|
||||
</div>
|
||||
<div class="pb-2">
|
||||
<input type="password" class="form-control form-control-sm" id="add-credentials-password"data-i18n="[placeholder]password" required>
|
||||
<div class="form-text help-text" id="add-credentials-password-help-text">
|
||||
<span data-i18n="popupAddCredentialsPasswordText"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pb-2">
|
||||
<input type="url" class="form-control form-control-sm" id="add-credentials-url" data-i18n="[placeholder]url" required>
|
||||
</div>
|
||||
<div class="pb-2">
|
||||
<input type="text" class="form-control form-control-sm" id="add-credentials-group" data-i18n="[placeholder]group">
|
||||
<div class="form-text help-text" id="add-credentials-group-help-text">
|
||||
<span data-i18n="popupAddCredentialGroupText"></span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- TODO: Protocol V2
|
||||
<div class="input-group input-group-sm pb-2">
|
||||
<label class="input-group-text" for="add-credentials-database">Database</label>
|
||||
<select class="form-select form-select-sm" id="add-credentials-database">
|
||||
<option value="1">Database 1</option>
|
||||
<option value="2">...</option>
|
||||
</select>
|
||||
</div>
|
||||
-->
|
||||
</div>
|
||||
<div class="content right-align pt-2 pb-2">
|
||||
<button class="btn btn-sm btn-primary me-1" type="submit" id="add-credentials-save-button" data-i18n="[title]optionsButtonSave">
|
||||
<i class="fa fa-save" aria-hidden="true"></i>
|
||||
<span data-i18n="optionsButtonSave"></span>
|
||||
</button>
|
||||
<button class="btn btn-sm btn-danger" type="button" id="add-credentials-cancel-button" data-i18n="[title]optionsButtonCancel">
|
||||
<i class="fa fa-remove" aria-hidden="true"></i>
|
||||
<span data-i18n="optionsButtonCancel"></span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ HTMLElement.prototype.hide = function() {
|
|||
this.style.display = 'none';
|
||||
};
|
||||
|
||||
function statusResponse(r) {
|
||||
async function statusResponse(r) {
|
||||
$('#initial-state').hide();
|
||||
$('#error-encountered').hide();
|
||||
$('#need-reconfigure').hide();
|
||||
|
|
@ -20,6 +20,7 @@ function statusResponse(r) {
|
|||
$('#lock-database-button').hide();
|
||||
$('#getting-started-guide').hide();
|
||||
$('#database-not-opened').hide();
|
||||
$('#add-credentials-button').hide();
|
||||
|
||||
if (!r.keePassXCAvailable) {
|
||||
$('#error-message').textContent = r.error;
|
||||
|
|
@ -52,6 +53,7 @@ function statusResponse(r) {
|
|||
$('#configured-and-associated').show();
|
||||
$('#associated-identifier').textContent = r.identifier;
|
||||
$('#lock-database-button').show();
|
||||
$('#add-credentials-button').show();
|
||||
|
||||
if (r.usernameFieldDetected) {
|
||||
$('#username-field-detected').show();
|
||||
|
|
|
|||
|
|
@ -11,11 +11,13 @@ function updateAvailableResponse(available) {
|
|||
}
|
||||
|
||||
async function initSettings() {
|
||||
const tab = await getCurrentTab();
|
||||
|
||||
$('#settings #options-button').addEventListener('click', () => {
|
||||
browser.runtime.openOptionsPage().then(close());
|
||||
});
|
||||
|
||||
const customLoginFieldsButton = document.body.querySelector('#settings #choose-custom-login-fields-button');
|
||||
const customLoginFieldsButton = $('#settings #choose-custom-login-fields-button');
|
||||
if (isFirefox()) {
|
||||
customLoginFieldsButton.id = 'choose-custom-login-fields-button-moz';
|
||||
}
|
||||
|
|
@ -27,6 +29,36 @@ async function initSettings() {
|
|||
});
|
||||
close();
|
||||
});
|
||||
|
||||
$('#settings #add-credentials-button').addEventListener('click', () => {
|
||||
$('#add-credentials-title').value = tab?.title;
|
||||
$('#add-credentials-url').value = tab?.url;
|
||||
if ($('#add-credentials')?.style?.display === 'none') {
|
||||
$('#add-credentials').show();
|
||||
} else {
|
||||
$('#add-credentials').hide();
|
||||
}
|
||||
|
||||
if ($('#credentialsList')?.style?.display !== 'none') {
|
||||
$('#credentialsList')?.hide();
|
||||
} else {
|
||||
$('#credentialsList')?.show();
|
||||
}
|
||||
});
|
||||
|
||||
$('#add-credentials-save-button').addEventListener('click', async (e) => {
|
||||
if (e?.currentTarget?.form?.checkValidity()) {
|
||||
await addNewCredential();
|
||||
close();
|
||||
}
|
||||
});
|
||||
|
||||
$('#add-credentials-cancel-button').addEventListener('click', async () => {
|
||||
$('#add-credentials').hide();
|
||||
if ($('#credentialsList')?.style?.display === 'none') {
|
||||
$('#credentialsList').show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function initColorTheme() {
|
||||
|
|
@ -53,6 +85,23 @@ async function getLoginData() {
|
|||
return logins;
|
||||
}
|
||||
|
||||
async function addNewCredential() {
|
||||
const tab = await getCurrentTab();
|
||||
if (!tab) {
|
||||
return [];
|
||||
}
|
||||
|
||||
browser.tabs.sendMessage(tab?.id, {
|
||||
action: 'add_new_credential', args: {
|
||||
username: $('input#add-credentials-username')?.value,
|
||||
password: $('input#add-credentials-password')?.value,
|
||||
group: $('input#add-credentials-group')?.value,
|
||||
title: $('input#add-credentials-title')?.value,
|
||||
url: $('input#add-credentials-url')?.value,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
(async () => {
|
||||
if (document.readyState === 'complete' || (document.readyState !== 'loading' && !document.documentElement.doScroll)) {
|
||||
await initSettings();
|
||||
|
|
|
|||
|
|
@ -23,6 +23,9 @@
|
|||
<i class="fa fa-cog" aria-hidden="true"></i>
|
||||
</button>
|
||||
<button id="choose-custom-login-fields-button" class="btn btn-sm btn-warning" data-i18n="[title]popupChooseCredentialsText"></button>
|
||||
<button id="add-credentials-button" class="btn btn-sm btn-warning" data-i18n="[title]popupAddCredentialsText">
|
||||
<i class="fa fa-user-plus" aria-hidden="true"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="lock-button-area">
|
||||
<button id="lock-database-button" class="btn btn-sm btn-danger" data-i18n="[title]lockDatabase">
|
||||
|
|
@ -46,7 +49,7 @@
|
|||
<div id="login-list" class="list-group"></div>
|
||||
</div>
|
||||
|
||||
<div id="database-not-opened">
|
||||
<div id="database-not-opened">
|
||||
<p data-i18n="popupErrorEncountered"></p>
|
||||
<p style="margin-left: 1em">
|
||||
<code id="database-error-message"></code>
|
||||
|
|
@ -58,6 +61,55 @@
|
|||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="add-credentials" style="display: none">
|
||||
<span data-i18n="popupAddCredentialsText"></span>
|
||||
<form>
|
||||
<div class="content pt-2 pb-2">
|
||||
<div class="pb-2">
|
||||
<input class="form-control form-control-sm" type="text" id="add-credentials-title" data-i18n="[placeholder]popupAddCredentialsTitlePlaceholder" required>
|
||||
</div>
|
||||
<div class="pb-2">
|
||||
<input type="text" class="form-control form-control-sm" id="add-credentials-username" data-i18n="[placeholder]username" required>
|
||||
</div>
|
||||
<div class="pb-2">
|
||||
<input type="password" class="form-control form-control-sm" id="add-credentials-password"data-i18n="[placeholder]password" required>
|
||||
<div class="form-text help-text" id="add-credentials-password-help-text">
|
||||
<span data-i18n="popupAddCredentialsPasswordText"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pb-2">
|
||||
<input type="url" class="form-control form-control-sm" id="add-credentials-url" data-i18n="[placeholder]url" required>
|
||||
</div>
|
||||
<div class="pb-2">
|
||||
<input type="text" class="form-control form-control-sm" id="add-credentials-group" data-i18n="[placeholder]group">
|
||||
<div class="form-text help-text" id="add-credentials-group-help-text">
|
||||
<span data-i18n="popupAddCredentialGroupText"></span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- TODO: Protocol V2
|
||||
<div class="input-group input-group-sm pb-2">
|
||||
<label class="input-group-text" for="add-credentials-database">Database</label>
|
||||
<select class="form-select form-select-sm" id="add-credentials-database">
|
||||
<option value="1">Database 1</option>
|
||||
<option value="2">...</option>
|
||||
</select>
|
||||
</div>
|
||||
-->
|
||||
</div>
|
||||
<div class="content right-align pt-2 pb-2">
|
||||
<button class="btn btn-sm btn-primary me-1" type="submit" id="add-credentials-save-button" data-i18n="[title]optionsButtonSave">
|
||||
<i class="fa fa-save" aria-hidden="true"></i>
|
||||
<span data-i18n="optionsButtonSave"></span>
|
||||
</button>
|
||||
<button class="btn btn-sm btn-danger" type="button" id="add-credentials-cancel-button" data-i18n="[title]optionsButtonCancel">
|
||||
<i class="fa fa-remove" aria-hidden="true"></i>
|
||||
<span data-i18n="optionsButtonCancel"></span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -68,6 +68,8 @@
|
|||
$('#credentialsList').hide();
|
||||
$('#database-not-opened').show();
|
||||
$('#lock-database-button').hide();
|
||||
$('#add-credentials').hide();
|
||||
$('#add-credentials-button').hide();
|
||||
$('#database-error-message').textContent = tr('errorMessageDatabaseNotOpened');
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue