mirror of
https://github.com/dani-garcia/vaultwarden.git
synced 2025-09-14 20:45:57 +03:00
Multiple Admin Interface fixes and some others.
Misc: - Fixed hadolint workflow, new git cli needs some extra arguments. - Add ignore paths to all specific on triggers. - Updated hadolint version. - Made SMTP_DEBUG read-only, since it can't be changed at runtime. Admin: - Migrated from Bootstrap v4 to v5 - Updated jquery to v3.6.0 - Updated Datatables - Made Javascript strict - Added a way to show which ENV Vars are overridden. - Changed the way to provide data for handlebars. - Fixed date/time check. - Made support string use details and summary feature of markdown/github.
This commit is contained in:
@@ -15,14 +15,16 @@
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
}
|
||||
.navbar .vaultwarden-icon {
|
||||
.vaultwarden-icon {
|
||||
height: 32px;
|
||||
width: auto;
|
||||
margin: -5px -3px 0 0;
|
||||
margin: -5px 0 0 0;
|
||||
}
|
||||
</style>
|
||||
<script src="{{urlpath}}/bwrs_static/identicon.js"></script>
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
function reload() { window.location.reload(); }
|
||||
function msg(text, reload_page = true) {
|
||||
text && alert(text);
|
||||
@@ -78,19 +80,18 @@
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body class="bg-light">
|
||||
<nav class="navbar navbar-expand-md navbar-dark bg-dark mb-4 shadow fixed-top">
|
||||
<div class="container-xl">
|
||||
<a class="navbar-brand" href="{{urlpath}}/admin"><img class="pr-1 vaultwarden-icon" src="{{urlpath}}/bwrs_static/vaultwarden-icon.png" alt="V">aultwarden Admin</a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarCollapse"
|
||||
<a class="navbar-brand" href="{{urlpath}}/admin"><img class="vaultwarden-icon" src="{{urlpath}}/bwrs_static/vaultwarden-icon.png" alt="V">aultwarden Admin</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse"
|
||||
aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarCollapse">
|
||||
<ul class="navbar-nav mr-auto">
|
||||
<ul class="navbar-nav me-auto">
|
||||
{{#if logged_in}}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{{urlpath}}/admin">Settings</a>
|
||||
@@ -121,17 +122,19 @@
|
||||
|
||||
<!-- This script needs to be at the bottom, else it will fail! -->
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
// get current URL path and assign 'active' class to the correct nav-item
|
||||
(function () {
|
||||
(() => {
|
||||
var pathname = window.location.pathname;
|
||||
if (pathname === "") return;
|
||||
var navItem = document.querySelectorAll('.navbar-nav .nav-item a[href="'+pathname+'"]');
|
||||
if (navItem.length === 1) {
|
||||
navItem[0].parentElement.className = navItem[0].parentElement.className + ' active';
|
||||
navItem[0].className = navItem[0].className + ' active';
|
||||
navItem[0].setAttribute('aria-current', 'page');
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
<!-- This script needs to be at the bottom, else it will fail! -->
|
||||
<script src="{{urlpath}}/bwrs_static/bootstrap-native.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
@@ -7,37 +7,37 @@
|
||||
<div class="col-md">
|
||||
<dl class="row">
|
||||
<dt class="col-sm-5">Server Installed
|
||||
<span class="badge badge-success d-none" id="server-success" title="Latest version is installed.">Ok</span>
|
||||
<span class="badge badge-warning d-none" id="server-warning" title="There seems to be an update available.">Update</span>
|
||||
<span class="badge badge-info d-none" id="server-branch" title="This is a branched version.">Branched</span>
|
||||
<span class="badge bg-success d-none" id="server-success" title="Latest version is installed.">Ok</span>
|
||||
<span class="badge bg-warning d-none" id="server-warning" title="There seems to be an update available.">Update</span>
|
||||
<span class="badge bg-info d-none" id="server-branch" title="This is a branched version.">Branched</span>
|
||||
</dt>
|
||||
<dd class="col-sm-7">
|
||||
<span id="server-installed">{{version}}</span>
|
||||
</dd>
|
||||
<dt class="col-sm-5">Server Latest
|
||||
<span class="badge badge-secondary d-none" id="server-failed" title="Unable to determine latest version.">Unknown</span>
|
||||
<span class="badge bg-secondary d-none" id="server-failed" title="Unable to determine latest version.">Unknown</span>
|
||||
</dt>
|
||||
<dd class="col-sm-7">
|
||||
<span id="server-latest">{{diagnostics.latest_release}}<span id="server-latest-commit" class="d-none">-{{diagnostics.latest_commit}}</span></span>
|
||||
<span id="server-latest">{{page_data.latest_release}}<span id="server-latest-commit" class="d-none">-{{page_data.latest_commit}}</span></span>
|
||||
</dd>
|
||||
{{#if diagnostics.web_vault_enabled}}
|
||||
{{#if page_data.web_vault_enabled}}
|
||||
<dt class="col-sm-5">Web Installed
|
||||
<span class="badge badge-success d-none" id="web-success" title="Latest version is installed.">Ok</span>
|
||||
<span class="badge badge-warning d-none" id="web-warning" title="There seems to be an update available.">Update</span>
|
||||
<span class="badge bg-success d-none" id="web-success" title="Latest version is installed.">Ok</span>
|
||||
<span class="badge bg-warning d-none" id="web-warning" title="There seems to be an update available.">Update</span>
|
||||
</dt>
|
||||
<dd class="col-sm-7">
|
||||
<span id="web-installed">{{diagnostics.web_vault_version}}</span>
|
||||
<span id="web-installed">{{page_data.web_vault_version}}</span>
|
||||
</dd>
|
||||
{{#unless diagnostics.running_within_docker}}
|
||||
{{#unless page_data.running_within_docker}}
|
||||
<dt class="col-sm-5">Web Latest
|
||||
<span class="badge badge-secondary d-none" id="web-failed" title="Unable to determine latest version.">Unknown</span>
|
||||
<span class="badge bg-secondary d-none" id="web-failed" title="Unable to determine latest version.">Unknown</span>
|
||||
</dt>
|
||||
<dd class="col-sm-7">
|
||||
<span id="web-latest">{{diagnostics.latest_web_build}}</span>
|
||||
<span id="web-latest">{{page_data.latest_web_build}}</span>
|
||||
</dd>
|
||||
{{/unless}}
|
||||
{{/if}}
|
||||
{{#unless diagnostics.web_vault_enabled}}
|
||||
{{#unless page_data.web_vault_enabled}}
|
||||
<dt class="col-sm-5">Web Installed</dt>
|
||||
<dd class="col-sm-7">
|
||||
<span id="web-installed">Web Vault is disabled</span>
|
||||
@@ -45,7 +45,7 @@
|
||||
{{/unless}}
|
||||
<dt class="col-sm-5">Database</dt>
|
||||
<dd class="col-sm-7">
|
||||
<span><b>{{diagnostics.db_type}}:</b> {{diagnostics.db_version}}</span>
|
||||
<span><b>{{page_data.db_type}}:</b> {{page_data.db_version}}</span>
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
@@ -57,96 +57,105 @@
|
||||
<dl class="row">
|
||||
<dt class="col-sm-5">Running within Docker</dt>
|
||||
<dd class="col-sm-7">
|
||||
{{#if diagnostics.running_within_docker}}
|
||||
{{#if page_data.running_within_docker}}
|
||||
<span class="d-block"><b>Yes</b></span>
|
||||
{{/if}}
|
||||
{{#unless diagnostics.running_within_docker}}
|
||||
{{#unless page_data.running_within_docker}}
|
||||
<span class="d-block"><b>No</b></span>
|
||||
{{/unless}}
|
||||
</dd>
|
||||
<dt class="col-sm-5">Environment settings overridden</dt>
|
||||
<dd class="col-sm-7">
|
||||
{{#if page_data.overrides}}
|
||||
<span class="d-block" title="The following settings are overridden: {{page_data.overrides}}"><b>Yes</b></span>
|
||||
{{/if}}
|
||||
{{#unless page_data.overrides}}
|
||||
<span class="d-block"><b>No</b></span>
|
||||
{{/unless}}
|
||||
</dd>
|
||||
<dt class="col-sm-5">Uses a reverse proxy</dt>
|
||||
<dd class="col-sm-7">
|
||||
{{#if diagnostics.ip_header_exists}}
|
||||
{{#if page_data.ip_header_exists}}
|
||||
<span class="d-block" title="IP Header found."><b>Yes</b></span>
|
||||
{{/if}}
|
||||
{{#unless diagnostics.ip_header_exists}}
|
||||
{{#unless page_data.ip_header_exists}}
|
||||
<span class="d-block" title="No IP Header found."><b>No</b></span>
|
||||
{{/unless}}
|
||||
</dd>
|
||||
{{!-- Only show this if the IP Header Exists --}}
|
||||
{{#if diagnostics.ip_header_exists}}
|
||||
{{#if page_data.ip_header_exists}}
|
||||
<dt class="col-sm-5">IP header
|
||||
{{#if diagnostics.ip_header_match}}
|
||||
<span class="badge badge-success" title="IP_HEADER config seems to be valid.">Match</span>
|
||||
{{#if page_data.ip_header_match}}
|
||||
<span class="badge bg-success" title="IP_HEADER config seems to be valid.">Match</span>
|
||||
{{/if}}
|
||||
{{#unless diagnostics.ip_header_match}}
|
||||
<span class="badge badge-danger" title="IP_HEADER config seems to be invalid. IP's in the log could be invalid. Please fix.">No Match</span>
|
||||
{{#unless page_data.ip_header_match}}
|
||||
<span class="badge bg-danger" title="IP_HEADER config seems to be invalid. IP's in the log could be invalid. Please fix.">No Match</span>
|
||||
{{/unless}}
|
||||
</dt>
|
||||
<dd class="col-sm-7">
|
||||
{{#if diagnostics.ip_header_match}}
|
||||
<span class="d-block"><b>Config/Server:</b> {{ diagnostics.ip_header_name }}</span>
|
||||
{{#if page_data.ip_header_match}}
|
||||
<span class="d-block"><b>Config/Server:</b> {{ page_data.ip_header_name }}</span>
|
||||
{{/if}}
|
||||
{{#unless diagnostics.ip_header_match}}
|
||||
<span class="d-block"><b>Config:</b> {{ diagnostics.ip_header_config }}</span>
|
||||
<span class="d-block"><b>Server:</b> {{ diagnostics.ip_header_name }}</span>
|
||||
{{#unless page_data.ip_header_match}}
|
||||
<span class="d-block"><b>Config:</b> {{ page_data.ip_header_config }}</span>
|
||||
<span class="d-block"><b>Server:</b> {{ page_data.ip_header_name }}</span>
|
||||
{{/unless}}
|
||||
</dd>
|
||||
{{/if}}
|
||||
{{!-- End if IP Header Exists --}}
|
||||
<dt class="col-sm-5">Internet access
|
||||
{{#if diagnostics.has_http_access}}
|
||||
<span class="badge badge-success" title="We have internet access!">Ok</span>
|
||||
{{#if page_data.has_http_access}}
|
||||
<span class="badge bg-success" title="We have internet access!">Ok</span>
|
||||
{{/if}}
|
||||
{{#unless diagnostics.has_http_access}}
|
||||
<span class="badge badge-danger" title="There seems to be no internet access. Please fix.">Error</span>
|
||||
{{#unless page_data.has_http_access}}
|
||||
<span class="badge bg-danger" title="There seems to be no internet access. Please fix.">Error</span>
|
||||
{{/unless}}
|
||||
</dt>
|
||||
<dd class="col-sm-7">
|
||||
{{#if diagnostics.has_http_access}}
|
||||
{{#if page_data.has_http_access}}
|
||||
<span class="d-block"><b>Yes</b></span>
|
||||
{{/if}}
|
||||
{{#unless diagnostics.has_http_access}}
|
||||
{{#unless page_data.has_http_access}}
|
||||
<span class="d-block"><b>No</b></span>
|
||||
{{/unless}}
|
||||
</dd>
|
||||
<dt class="col-sm-5">Internet access via a proxy</dt>
|
||||
<dd class="col-sm-7">
|
||||
{{#if diagnostics.uses_proxy}}
|
||||
{{#if page_data.uses_proxy}}
|
||||
<span class="d-block" title="Internet access goes via a proxy (HTTPS_PROXY or HTTP_PROXY is configured)."><b>Yes</b></span>
|
||||
{{/if}}
|
||||
{{#unless diagnostics.uses_proxy}}
|
||||
{{#unless page_data.uses_proxy}}
|
||||
<span class="d-block" title="We have direct internet access, no outgoing proxy configured."><b>No</b></span>
|
||||
{{/unless}}
|
||||
</dd>
|
||||
<dt class="col-sm-5">DNS (github.com)
|
||||
<span class="badge badge-success d-none" id="dns-success" title="DNS Resolving works!">Ok</span>
|
||||
<span class="badge badge-danger d-none" id="dns-warning" title="DNS Resolving failed. Please fix.">Error</span>
|
||||
<span class="badge bg-success d-none" id="dns-success" title="DNS Resolving works!">Ok</span>
|
||||
<span class="badge bg-danger d-none" id="dns-warning" title="DNS Resolving failed. Please fix.">Error</span>
|
||||
</dt>
|
||||
<dd class="col-sm-7">
|
||||
<span id="dns-resolved">{{diagnostics.dns_resolved}}</span>
|
||||
<span id="dns-resolved">{{page_data.dns_resolved}}</span>
|
||||
</dd>
|
||||
<dt class="col-sm-5">Date & Time (Local)</dt>
|
||||
<dd class="col-sm-7">
|
||||
<span><b>Server:</b> {{diagnostics.server_time_local}}</span>
|
||||
<span><b>Server:</b> {{page_data.server_time_local}}</span>
|
||||
</dd>
|
||||
<dt class="col-sm-5">Date & Time (UTC)
|
||||
<span class="badge badge-success d-none" id="time-success" title="Time offsets seem to be correct.">Ok</span>
|
||||
<span class="badge badge-danger d-none" id="time-warning" title="Time offsets are too mouch at drift.">Error</span>
|
||||
<span class="badge bg-success d-none" id="time-success" title="Time offsets seem to be correct.">Ok</span>
|
||||
<span class="badge bg-danger d-none" id="time-warning" title="Time offsets are too mouch at drift.">Error</span>
|
||||
</dt>
|
||||
<dd class="col-sm-7">
|
||||
<span id="time-server" class="d-block"><b>Server:</b> <span id="time-server-string">{{diagnostics.server_time}}</span></span>
|
||||
<span id="time-server" class="d-block"><b>Server:</b> <span id="time-server-string">{{page_data.server_time}}</span></span>
|
||||
<span id="time-browser" class="d-block"><b>Browser:</b> <span id="time-browser-string"></span></span>
|
||||
</dd>
|
||||
|
||||
<dt class="col-sm-5">Domain configuration
|
||||
<span class="badge badge-success d-none" id="domain-success" title="The domain variable matches the browser location and seems to be configured correctly.">Match</span>
|
||||
<span class="badge badge-danger d-none" id="domain-warning" title="The domain variable does not matches the browsers location.
The domain variable does not seem to be configured correctly.
Some features may not work as expected!">No Match</span>
|
||||
<span class="badge badge-success d-none" id="https-success" title="Configurued to use HTTPS">HTTPS</span>
|
||||
<span class="badge badge-danger d-none" id="https-warning" title="Not configured to use HTTPS.
Some features may not work as expected!">No HTTPS</span>
|
||||
<span class="badge bg-success d-none" id="domain-success" title="The domain variable matches the browser location and seems to be configured correctly.">Match</span>
|
||||
<span class="badge bg-danger d-none" id="domain-warning" title="The domain variable does not matches the browsers location.
The domain variable does not seem to be configured correctly.
Some features may not work as expected!">No Match</span>
|
||||
<span class="badge bg-success d-none" id="https-success" title="Configurued to use HTTPS">HTTPS</span>
|
||||
<span class="badge bg-danger d-none" id="https-warning" title="Not configured to use HTTPS.
Some features may not work as expected!">No HTTPS</span>
|
||||
</dt>
|
||||
<dd class="col-sm-7">
|
||||
<span id="domain-server" class="d-block"><b>Server:</b> <span id="domain-server-string">{{diagnostics.admin_url}}</span></span>
|
||||
<span id="domain-server" class="d-block"><b>Server:</b> <span id="domain-server-string">{{page_data.admin_url}}</span></span>
|
||||
<span id="domain-browser" class="d-block"><b>Browser:</b> <span id="domain-browser-string"></span></span>
|
||||
</dd>
|
||||
</dl>
|
||||
@@ -173,10 +182,17 @@
|
||||
<dt class="col-sm-3">
|
||||
<button type="button" id="gen-support" class="btn btn-primary" onclick="generateSupportString(); return false;">Generate Support String</button>
|
||||
<br><br>
|
||||
<button type="button" id="copy-support" class="btn btn-info d-none" onclick="copyToClipboard(); return false;">Copy To Clipboard</button>
|
||||
<button type="button" id="copy-support" class="btn btn-info mb-3 d-none" onclick="copyToClipboard(); return false;">Copy To Clipboard</button>
|
||||
<div class="toast-container position-absolute float-start" style="width: 15rem;">
|
||||
<div id="toastClipboardCopy" class="toast fade hide" role="status" aria-live="polite" aria-atomic="true" data-bs-autohide="true" data-bs-delay="1500">
|
||||
<div class="toast-body">
|
||||
Copied to clipboard!
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</dt>
|
||||
<dd class="col-sm-9">
|
||||
<pre id="support-string" class="pre-scrollable d-none" style="width: 100%; height: 16em; size: 0.6em; border: 1px solid; padding: 4px;"></pre>
|
||||
<pre id="support-string" class="pre-scrollable d-none w-100 border p-2" style="height: 16rem;"></pre>
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
@@ -185,10 +201,13 @@
|
||||
</main>
|
||||
|
||||
<script>
|
||||
dnsCheck = false;
|
||||
timeCheck = false;
|
||||
domainCheck = false;
|
||||
httpsCheck = false;
|
||||
'use strict';
|
||||
|
||||
var dnsCheck = false;
|
||||
var timeCheck = false;
|
||||
var domainCheck = false;
|
||||
var httpsCheck = false;
|
||||
|
||||
(() => {
|
||||
// ================================
|
||||
// Date & Time Check
|
||||
@@ -203,7 +222,10 @@
|
||||
document.getElementById("time-browser-string").innerText = browserUTC;
|
||||
|
||||
const serverUTC = document.getElementById("time-server-string").innerText;
|
||||
const timeDrift = (Date.parse(serverUTC) - Date.parse(browserUTC)) / 1000;
|
||||
const timeDrift = (
|
||||
Date.parse(serverUTC.replace(' ', 'T').replace(' UTC', '')) -
|
||||
Date.parse(browserUTC.replace(' ', 'T').replace(' UTC', ''))
|
||||
) / 1000;
|
||||
if (timeDrift > 30 || timeDrift < -30) {
|
||||
document.getElementById('time-warning').classList.remove('d-none');
|
||||
} else {
|
||||
@@ -233,7 +255,7 @@
|
||||
const webInstalled = document.getElementById('web-installed').innerText;
|
||||
checkVersions('server', serverInstalled, serverLatest, serverLatestCommit);
|
||||
|
||||
{{#unless diagnostics.running_within_docker}}
|
||||
{{#unless page_data.running_within_docker}}
|
||||
const webLatest = document.getElementById('web-latest').innerText;
|
||||
checkVersions('web', webInstalled, webLatest);
|
||||
{{/unless}}
|
||||
@@ -303,30 +325,38 @@
|
||||
// ================================
|
||||
// Generate support string to be pasted on github or the forum
|
||||
async function generateSupportString() {
|
||||
supportString = "### Your environment (Generated via diagnostics page)\n";
|
||||
let supportString = "### Your environment (Generated via diagnostics page)\n";
|
||||
|
||||
supportString += "* Vaultwarden version: v{{ version }}\n";
|
||||
supportString += "* Web-vault version: v{{ diagnostics.web_vault_version }}\n";
|
||||
supportString += "* Running within Docker: {{ diagnostics.running_within_docker }}\n";
|
||||
supportString += "* Uses a reverse proxy: {{ diagnostics.ip_header_exists }}\n";
|
||||
{{#if diagnostics.ip_header_exists}}
|
||||
supportString += "* IP Header check: {{ diagnostics.ip_header_match }} ({{ diagnostics.ip_header_name }})\n";
|
||||
supportString += "* Web-vault version: v{{ page_data.web_vault_version }}\n";
|
||||
supportString += "* Running within Docker: {{ page_data.running_within_docker }}\n";
|
||||
supportString += "* Environment settings overridden: ";
|
||||
{{#if page_data.overrides}}
|
||||
supportString += "true\n"
|
||||
{{else}}
|
||||
supportString += "false\n"
|
||||
{{/if}}
|
||||
supportString += "* Internet access: {{ diagnostics.has_http_access }}\n";
|
||||
supportString += "* Internet access via a proxy: {{ diagnostics.uses_proxy }}\n";
|
||||
supportString += "* Uses a reverse proxy: {{ page_data.ip_header_exists }}\n";
|
||||
{{#if page_data.ip_header_exists}}
|
||||
supportString += "* IP Header check: {{ page_data.ip_header_match }} ({{ page_data.ip_header_name }})\n";
|
||||
{{/if}}
|
||||
supportString += "* Internet access: {{ page_data.has_http_access }}\n";
|
||||
supportString += "* Internet access via a proxy: {{ page_data.uses_proxy }}\n";
|
||||
supportString += "* DNS Check: " + dnsCheck + "\n";
|
||||
supportString += "* Time Check: " + timeCheck + "\n";
|
||||
supportString += "* Domain Configuration Check: " + domainCheck + "\n";
|
||||
supportString += "* HTTPS Check: " + httpsCheck + "\n";
|
||||
supportString += "* Database type: {{ diagnostics.db_type }}\n";
|
||||
supportString += "* Database version: {{ diagnostics.db_version }}\n";
|
||||
supportString += "* Database type: {{ page_data.db_type }}\n";
|
||||
supportString += "* Database version: {{ page_data.db_version }}\n";
|
||||
supportString += "* Clients used: \n";
|
||||
supportString += "* Reverse proxy and version: \n";
|
||||
supportString += "* Other relevant information: \n";
|
||||
|
||||
jsonResponse = await fetch('{{urlpath}}/admin/diagnostics/config');
|
||||
configJson = await jsonResponse.json();
|
||||
supportString += "\n### Config (Generated via diagnostics page)\n```json\n" + JSON.stringify(configJson, undefined, 2) + "\n```\n";
|
||||
let jsonResponse = await fetch('{{urlpath}}/admin/diagnostics/config');
|
||||
const configJson = await jsonResponse.json();
|
||||
supportString += "\n### Config (Generated via diagnostics page)\n<details><summary>Show Running Config</summary>\n"
|
||||
supportString += "\n**Environment settings which are overridden:** {{page_data.overrides}}\n"
|
||||
supportString += "\n\n```json\n" + JSON.stringify(configJson, undefined, 2) + "\n```\n</details>\n";
|
||||
|
||||
document.getElementById('support-string').innerText = supportString;
|
||||
document.getElementById('support-string').classList.remove('d-none');
|
||||
@@ -334,16 +364,19 @@
|
||||
}
|
||||
|
||||
function copyToClipboard() {
|
||||
const str = document.getElementById('support-string').innerText;
|
||||
const el = document.createElement('textarea');
|
||||
el.value = str;
|
||||
el.setAttribute('readonly', '');
|
||||
el.style.position = 'absolute';
|
||||
el.style.left = '-9999px';
|
||||
document.body.appendChild(el);
|
||||
el.select();
|
||||
document.execCommand('copy');
|
||||
document.body.removeChild(el);
|
||||
}
|
||||
const supportStr = document.getElementById('support-string').innerText;
|
||||
const tmpCopyEl = document.createElement('textarea');
|
||||
|
||||
tmpCopyEl.setAttribute('id', 'copy-support-string');
|
||||
tmpCopyEl.setAttribute('readonly', '');
|
||||
tmpCopyEl.value = supportStr;
|
||||
tmpCopyEl.style.position = 'absolute';
|
||||
tmpCopyEl.style.left = '-9999px';
|
||||
document.body.appendChild(tmpCopyEl);
|
||||
tmpCopyEl.select();
|
||||
document.execCommand('copy');
|
||||
tmpCopyEl.remove();
|
||||
|
||||
new BSN.Toast('#toastClipboardCopy').show();
|
||||
}
|
||||
</script>
|
||||
|
@@ -1,7 +1,6 @@
|
||||
<main class="container-xl">
|
||||
<div id="organizations-block" class="my-3 p-3 bg-white rounded shadow">
|
||||
<h6 class="border-bottom pb-2 mb-3">Organizations</h6>
|
||||
|
||||
<div class="table-responsive-xl small">
|
||||
<table id="orgs-table" class="table table-sm table-striped table-hover">
|
||||
<thead>
|
||||
@@ -10,19 +9,19 @@
|
||||
<th>Users</th>
|
||||
<th>Items</th>
|
||||
<th>Attachments</th>
|
||||
<th style="width: 120px; min-width: 120px;">Actions</th>
|
||||
<th style="width: 130px; min-width: 130px;">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#each organizations}}
|
||||
{{#each page_data}}
|
||||
<tr>
|
||||
<td>
|
||||
<img class="mr-2 float-left rounded identicon" data-src="{{Id}}">
|
||||
<div class="float-left">
|
||||
<img class="float-start me-2 rounded identicon" data-src="{{Id}}">
|
||||
<div class="float-start">
|
||||
<strong>{{Name}}</strong>
|
||||
<span class="mr-2">({{BillingEmail}})</span>
|
||||
<span class="me-2">({{BillingEmail}})</span>
|
||||
<span class="d-block">
|
||||
<span class="badge badge-success">{{Id}}</span>
|
||||
<span class="badge bg-success">{{Id}}</span>
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
@@ -38,7 +37,7 @@
|
||||
<span class="d-block"><strong>Size:</strong> {{attachment_size}}</span>
|
||||
{{/if}}
|
||||
</td>
|
||||
<td style="font-size: 90%; text-align: right; padding-right: 15px">
|
||||
<td class="text-end pe-2 small">
|
||||
<a class="d-block" href="#" onclick='deleteOrganization({{jsesc Id}}, {{jsesc Name}}, {{jsesc BillingEmail}})'>Delete Organization</a>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -46,14 +45,15 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<link rel="stylesheet" href="{{urlpath}}/bwrs_static/datatables.css" />
|
||||
<script src="{{urlpath}}/bwrs_static/jquery-3.5.1.slim.js"></script>
|
||||
<script src="{{urlpath}}/bwrs_static/jquery-3.6.0.slim.js"></script>
|
||||
<script src="{{urlpath}}/bwrs_static/datatables.js"></script>
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
function deleteOrganization(id, name, billing_email) {
|
||||
// First make sure the user wants to delete this organization
|
||||
var continueDelete = confirm("WARNING: All data of this organization ("+ name +") will be lost!\nMake sure you have a backup, this cannot be undone!");
|
||||
@@ -79,7 +79,7 @@
|
||||
}
|
||||
})();
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function(event) {
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
$('#orgs-table').DataTable({
|
||||
"responsive": true,
|
||||
"lengthMenu": [ [-1, 5, 10, 25, 50], ["All", 5, 10, 25, 50] ],
|
||||
|
@@ -3,34 +3,32 @@
|
||||
<div>
|
||||
<h6 class="text-white mb-3">Configuration</h6>
|
||||
<div class="small text-white mb-3">
|
||||
NOTE: The settings here override the environment variables. Once saved, it's recommended to stop setting
|
||||
them to avoid confusion. This does not apply to the read-only section, which can only be set through the
|
||||
environment.
|
||||
<span class="font-weight-bolder">NOTE:</span> The settings here override the environment variables. Once saved, it's recommended to stop setting them to avoid confusion.<br>
|
||||
This does not apply to the read-only section, which can only be set via environment variables.<br>
|
||||
Settings which are overridden are shown with <span class="is-overridden-true">double underscores</span>.
|
||||
</div>
|
||||
|
||||
<form class="form accordion" id="config-form" onsubmit="saveConfig(); return false;">
|
||||
<form class="form needs-validation" id="config-form" onsubmit="saveConfig(); return false;" novalidate>
|
||||
{{#each config}}
|
||||
{{#if groupdoc}}
|
||||
<div class="card bg-light mb-3">
|
||||
<div class="card-header"><button type="button" class="btn btn-link collapsed" data-toggle="collapse"
|
||||
data-target="#g_{{group}}">{{groupdoc}}</button></div>
|
||||
<div id="g_{{group}}" class="card-body collapse" data-parent="#config-form">
|
||||
<div class="card-header" role="button" data-bs-toggle="collapse" data-bs-target="#g_{{group}}">
|
||||
<button type="button" class="btn btn-link text-decoration-none collapsed" data-bs-toggle="collapse" data-bs-target="#g_{{group}}">{{groupdoc}}</button>
|
||||
</div>
|
||||
<div id="g_{{group}}" class="card-body collapse">
|
||||
{{#each elements}}
|
||||
{{#if editable}}
|
||||
<div class="form-group row align-items-center" title="[{{name}}] {{doc.description}}">
|
||||
<div class="row my-2 align-items-center is-overridden-{{overridden}}" title="[{{name}}] {{doc.description}}">
|
||||
{{#case type "text" "number" "password"}}
|
||||
<label for="input_{{name}}" class="col-sm-3 col-form-label">{{doc.name}}</label>
|
||||
<div class="col-sm-8 input-group">
|
||||
<div class="col-sm-8">
|
||||
<div class="input-group">
|
||||
<input class="form-control conf-{{type}}" id="input_{{name}}" type="{{type}}"
|
||||
name="{{name}}" value="{{value}}" {{#if default}} placeholder="Default: {{default}}"
|
||||
{{/if}}>
|
||||
|
||||
name="{{name}}" value="{{value}}" {{#if default}} placeholder="Default: {{default}}"{{/if}}>
|
||||
{{#case type "password"}}
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-outline-secondary" type="button"
|
||||
onclick="toggleVis('input_{{name}}');">Show/hide</button>
|
||||
</div>
|
||||
<button class="btn btn-outline-secondary input-group-text" type="button" onclick="toggleVis('input_{{name}}');">Show/hide</button>
|
||||
{{/case}}
|
||||
</div>
|
||||
</div>
|
||||
{{/case}}
|
||||
{{#case type "checkbox"}}
|
||||
@@ -48,13 +46,12 @@
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
{{#case group "smtp"}}
|
||||
<div class="form-group row align-items-center pt-3 border-top" title="Send a test email to given email address">
|
||||
<div class="row my-2 align-items-center pt-3 border-top" title="Send a test email to given email address">
|
||||
<label for="smtp-test-email" class="col-sm-3 col-form-label">Test SMTP</label>
|
||||
<div class="col-sm-8 input-group">
|
||||
<input class="form-control" id="smtp-test-email" type="email" placeholder="Enter test email">
|
||||
<div class="input-group-append">
|
||||
<button type="button" class="btn btn-outline-primary" onclick="smtpTest(); return false;">Send test email</button>
|
||||
</div>
|
||||
<input class="form-control" id="smtp-test-email" type="email" placeholder="Enter test email" required>
|
||||
<button type="button" class="btn btn-outline-primary input-group-text" onclick="smtpTest(); return false;">Send test email</button>
|
||||
<div class="invalid-tooltip">Please provide a valid email address</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/case}}
|
||||
@@ -64,9 +61,11 @@
|
||||
{{/each}}
|
||||
|
||||
<div class="card bg-light mb-3">
|
||||
<div class="card-header"><button type="button" class="btn btn-link collapsed" data-toggle="collapse"
|
||||
data-target="#g_readonly">Read-Only Config</button></div>
|
||||
<div id="g_readonly" class="card-body collapse" data-parent="#config-form">
|
||||
<div class="card-header" role="button" data-bs-toggle="collapse" data-bs-target="#g_readonly">
|
||||
<button type="button" class="btn btn-link text-decoration-none collapsed" data-bs-toggle="collapse" data-bs-target="#g_readonly">Read-Only Config</button>
|
||||
</div>
|
||||
|
||||
<div id="g_readonly" class="card-body collapse">
|
||||
<div class="small mb-3">
|
||||
NOTE: These options can't be modified in the editor because they would require the server
|
||||
to be restarted. To modify them, you need to set the correct environment variables when
|
||||
@@ -76,19 +75,17 @@
|
||||
{{#each config}}
|
||||
{{#each elements}}
|
||||
{{#unless editable}}
|
||||
<div class="form-group row align-items-center" title="[{{name}}] {{doc.description}}">
|
||||
<div class="row my-2 align-items-center" title="[{{name}}] {{doc.description}}">
|
||||
{{#case type "text" "number" "password"}}
|
||||
<label for="input_{{name}}" class="col-sm-3 col-form-label">{{doc.name}}</label>
|
||||
<div class="col-sm-8 input-group">
|
||||
<div class="col-sm-8">
|
||||
<div class="input-group">
|
||||
<input readonly class="form-control" id="input_{{name}}" type="{{type}}"
|
||||
value="{{value}}" {{#if default}} placeholder="Default: {{default}}" {{/if}}>
|
||||
|
||||
{{#case type "password"}}
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-outline-secondary" type="button"
|
||||
onclick="toggleVis('input_{{name}}');">Show/hide</button>
|
||||
</div>
|
||||
<button class="btn btn-outline-secondary" type="button" onclick="toggleVis('input_{{name}}');">Show/hide</button>
|
||||
{{/case}}
|
||||
</div>
|
||||
</div>
|
||||
{{/case}}
|
||||
{{#case type "checkbox"}}
|
||||
@@ -112,9 +109,10 @@
|
||||
|
||||
{{#if can_backup}}
|
||||
<div class="card bg-light mb-3">
|
||||
<div class="card-header"><button type="button" class="btn btn-link collapsed" data-toggle="collapse"
|
||||
data-target="#g_database">Backup Database</button></div>
|
||||
<div id="g_database" class="card-body collapse" data-parent="#config-form">
|
||||
<div class="card-header" role="button" data-bs-toggle="collapse" data-bs-target="#g_database">
|
||||
<button type="button" class="btn btn-link text-decoration-none collapsed" data-bs-toggle="collapse" data-bs-target="#g_database">Backup Database</button>
|
||||
</div>
|
||||
<div id="g_database" class="card-body collapse">
|
||||
<div class="small mb-3">
|
||||
WARNING: This function only creates a backup copy of the SQLite database.
|
||||
This does not include any configuration or file attachment data that may
|
||||
@@ -128,7 +126,7 @@
|
||||
{{/if}}
|
||||
|
||||
<button type="submit" class="btn btn-primary">Save</button>
|
||||
<button type="button" class="btn btn-danger float-right" onclick="deleteConf();">Reset defaults</button>
|
||||
<button type="button" class="btn btn-danger float-end" onclick="deleteConf();">Reset defaults</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -139,16 +137,34 @@
|
||||
/* Most modern browsers support this now. */
|
||||
color: orangered;
|
||||
}
|
||||
|
||||
.is-overridden-true {
|
||||
text-decoration: underline double;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
function smtpTest() {
|
||||
if (formHasChanges(config_form)) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
alert("Config has been changed but not yet saved.\nPlease save the changes first before sending a test email.");
|
||||
return false;
|
||||
}
|
||||
test_email = document.getElementById("smtp-test-email");
|
||||
data = JSON.stringify({ "email": test_email.value });
|
||||
|
||||
let test_email = document.getElementById("smtp-test-email");
|
||||
|
||||
// Do a very very basic email address check.
|
||||
if (test_email.value.match(/\S+@\S+/i) === null) {
|
||||
test_email.parentElement.classList.add('was-validated');
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
return false;
|
||||
}
|
||||
|
||||
const data = JSON.stringify({ "email": test_email.value });
|
||||
_post("{{urlpath}}/admin/test/smtp/",
|
||||
"SMTP Test email sent correctly",
|
||||
"Error sending SMTP test email", data, false);
|
||||
@@ -157,21 +173,21 @@
|
||||
function getFormData() {
|
||||
let data = {};
|
||||
|
||||
document.querySelectorAll(".conf-checkbox").forEach(function (e, i) {
|
||||
document.querySelectorAll(".conf-checkbox").forEach(function (e) {
|
||||
data[e.name] = e.checked;
|
||||
});
|
||||
|
||||
document.querySelectorAll(".conf-number").forEach(function (e, i) {
|
||||
document.querySelectorAll(".conf-number").forEach(function (e) {
|
||||
data[e.name] = e.value ? +e.value : null;
|
||||
});
|
||||
|
||||
document.querySelectorAll(".conf-text, .conf-password").forEach(function (e, i) {
|
||||
document.querySelectorAll(".conf-text, .conf-password").forEach(function (e) {
|
||||
data[e.name] = e.value || null;
|
||||
});
|
||||
return data;
|
||||
}
|
||||
function saveConfig() {
|
||||
data = JSON.stringify(getFormData());
|
||||
const data = JSON.stringify(getFormData());
|
||||
_post("{{urlpath}}/admin/config/", "Config saved correctly",
|
||||
"Error saving config", data);
|
||||
return false;
|
||||
@@ -198,10 +214,10 @@
|
||||
function masterCheck(check_id, inputs_query) {
|
||||
function onChanged(checkbox, inputs_query) {
|
||||
return function _fn() {
|
||||
document.querySelectorAll(inputs_query).forEach(function (e, i) { e.disabled = !checkbox.checked; });
|
||||
document.querySelectorAll(inputs_query).forEach(function (e) { e.disabled = !checkbox.checked; });
|
||||
checkbox.disabled = false;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
const checkbox = document.getElementById(check_id);
|
||||
const onChange = onChanged(checkbox, inputs_query);
|
||||
@@ -238,7 +254,6 @@
|
||||
Array.from(risk_el).forEach((el) => {
|
||||
if (el.innerText.toLowerCase().includes('risks') ) {
|
||||
el.parentElement.className += ' alert-danger'
|
||||
console.log(el)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@@ -7,34 +7,34 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th>User</th>
|
||||
<th style="width:65px; min-width: 65px;">Created at</th>
|
||||
<th style="width:70px; min-width: 65px;">Last Active</th>
|
||||
<th style="width:35px; min-width: 35px;">Items</th>
|
||||
<th style="width: 85px; min-width: 70px;">Created at</th>
|
||||
<th style="width: 85px; min-width: 70px;">Last Active</th>
|
||||
<th style="width: 35px; min-width: 35px;">Items</th>
|
||||
<th>Attachments</th>
|
||||
<th style="min-width: 120px;">Organizations</th>
|
||||
<th style="width: 120px; min-width: 120px;">Actions</th>
|
||||
<th style="width: 130px; min-width: 130px;">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#each users}}
|
||||
{{#each page_data}}
|
||||
<tr>
|
||||
<td>
|
||||
<img class="float-left mr-2 rounded identicon" data-src="{{Email}}">
|
||||
<div class="float-left">
|
||||
<img class="float-start me-2 rounded identicon" data-src="{{Email}}">
|
||||
<div class="float-start">
|
||||
<strong>{{Name}}</strong>
|
||||
<span class="d-block">{{Email}}</span>
|
||||
<span class="d-block">
|
||||
{{#unless user_enabled}}
|
||||
<span class="badge badge-danger mr-2" title="User is disabled">Disabled</span>
|
||||
<span class="badge bg-danger me-2" title="User is disabled">Disabled</span>
|
||||
{{/unless}}
|
||||
{{#if TwoFactorEnabled}}
|
||||
<span class="badge badge-success mr-2" title="2FA is enabled">2FA</span>
|
||||
<span class="badge bg-success me-2" title="2FA is enabled">2FA</span>
|
||||
{{/if}}
|
||||
{{#case _Status 1}}
|
||||
<span class="badge badge-warning mr-2" title="User is invited">Invited</span>
|
||||
<span class="badge bg-warning me-2" title="User is invited">Invited</span>
|
||||
{{/case}}
|
||||
{{#if EmailVerified}}
|
||||
<span class="badge badge-success mr-2" title="Email has been verified">Verified</span>
|
||||
<span class="badge bg-success me-2" title="Email has been verified">Verified</span>
|
||||
{{/if}}
|
||||
</span>
|
||||
</div>
|
||||
@@ -57,11 +57,11 @@
|
||||
<td>
|
||||
<div class="overflow-auto" style="max-height: 120px;">
|
||||
{{#each Organizations}}
|
||||
<button class="badge badge-primary" data-toggle="modal" data-target="#userOrgTypeDialog" data-orgtype="{{Type}}" data-orguuid="{{jsesc Id no_quote}}" data-orgname="{{jsesc Name no_quote}}" data-useremail="{{jsesc ../Email no_quote}}" data-useruuid="{{jsesc ../Id no_quote}}">{{Name}}</button>
|
||||
<button class="badge" data-bs-toggle="modal" data-bs-target="#userOrgTypeDialog" data-orgtype="{{Type}}" data-orguuid="{{jsesc Id no_quote}}" data-orgname="{{jsesc Name no_quote}}" data-useremail="{{jsesc ../Email no_quote}}" data-useruuid="{{jsesc ../Id no_quote}}">{{Name}}</button>
|
||||
{{/each}}
|
||||
</div>
|
||||
</td>
|
||||
<td style="font-size: 90%; text-align: right; padding-right: 15px">
|
||||
<td class="text-end pe-2 small">
|
||||
{{#if TwoFactorEnabled}}
|
||||
<a class="d-block" href="#" onclick='remove2fa({{jsesc Id}})'>Remove all 2FA</a>
|
||||
{{/if}}
|
||||
@@ -85,7 +85,7 @@
|
||||
Force clients to resync
|
||||
</button>
|
||||
|
||||
<button type="button" class="btn btn-sm btn-primary float-right" onclick="reload();">Reload users</button>
|
||||
<button type="button" class="btn btn-sm btn-primary float-end" onclick="reload();">Reload users</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -94,8 +94,8 @@
|
||||
<h6 class="mb-0 text-white">Invite User</h6>
|
||||
<small>Email:</small>
|
||||
|
||||
<form class="form-inline" id="invite-form" onsubmit="inviteUser(); return false;">
|
||||
<input type="email" class="form-control w-50 mr-2" id="email-invite" placeholder="Enter email">
|
||||
<form class="form-inline input-group w-50" id="invite-form" onsubmit="inviteUser(); return false;">
|
||||
<input type="email" class="form-control me-2" id="email-invite" placeholder="Enter email" required>
|
||||
<button type="submit" class="btn btn-primary">Invite</button>
|
||||
</form>
|
||||
</div>
|
||||
@@ -106,9 +106,7 @@
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h6 class="modal-title" id="userOrgTypeDialogTitle"></h6>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<form class="form" id="userOrgTypeForm" onsubmit="updateUserOrgType(); return false;">
|
||||
<input type="hidden" name="user_uuid" id="userOrgTypeUserUuid" value="">
|
||||
@@ -128,7 +126,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-sm btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="submit" class="btn btn-sm btn-primary">Change Role</button>
|
||||
</div>
|
||||
</form>
|
||||
@@ -138,9 +136,11 @@
|
||||
</main>
|
||||
|
||||
<link rel="stylesheet" href="{{urlpath}}/bwrs_static/datatables.css" />
|
||||
<script src="{{urlpath}}/bwrs_static/jquery-3.5.1.slim.js"></script>
|
||||
<script src="{{urlpath}}/bwrs_static/jquery-3.6.0.slim.js"></script>
|
||||
<script src="{{urlpath}}/bwrs_static/datatables.js"></script>
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
function deleteUser(id, mail) {
|
||||
var input_mail = prompt("To delete user '" + mail + "', please type the email below")
|
||||
if (input_mail != null) {
|
||||
@@ -191,8 +191,8 @@
|
||||
return false;
|
||||
}
|
||||
function inviteUser() {
|
||||
inv = document.getElementById("email-invite");
|
||||
data = JSON.stringify({ "email": inv.value });
|
||||
const inv = document.getElementById("email-invite");
|
||||
const data = JSON.stringify({ "email": inv.value });
|
||||
inv.value = "";
|
||||
_post("{{urlpath}}/admin/invite/", "User invited correctly",
|
||||
"Error inviting user", data);
|
||||
@@ -212,7 +212,7 @@
|
||||
}
|
||||
})();
|
||||
|
||||
document.querySelectorAll("[data-orgtype]").forEach(function (e, i) {
|
||||
document.querySelectorAll("[data-orgtype]").forEach(function (e) {
|
||||
let orgtype = OrgTypes[e.dataset.orgtype];
|
||||
e.style.backgroundColor = orgtype.color;
|
||||
e.title = orgtype.name;
|
||||
@@ -225,7 +225,7 @@
|
||||
let sortDate = a.replace(/(<([^>]+)>)/gi, "").trim();
|
||||
if ( sortDate !== '' ) {
|
||||
let dtParts = sortDate.split(' ');
|
||||
var timeParts = (undefined != dtParts[1]) ? dtParts[1].split(':') : [00,00,00];
|
||||
var timeParts = (undefined != dtParts[1]) ? dtParts[1].split(':') : ['00','00','00'];
|
||||
var dateParts = dtParts[0].split('-');
|
||||
x = (dateParts[0] + dateParts[1] + dateParts[2] + timeParts[0] + timeParts[1] + ((undefined != timeParts[2]) ? timeParts[2] : 0)) * 1;
|
||||
if ( isNaN(x) ) {
|
||||
@@ -246,7 +246,7 @@
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function(event) {
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
$('#users-table').DataTable({
|
||||
"responsive": true,
|
||||
"lengthMenu": [ [-1, 5, 10, 25, 50], ["All", 5, 10, 25, 50] ],
|
||||
@@ -275,7 +275,7 @@
|
||||
}, false);
|
||||
|
||||
// Prevent accidental submission of the form with valid elements after the modal has been hidden.
|
||||
userOrgTypeDialog.addEventListener('hide.bs.modal', function(event){
|
||||
userOrgTypeDialog.addEventListener('hide.bs.modal', function(){
|
||||
document.getElementById("userOrgTypeDialogTitle").innerHTML = '';
|
||||
document.getElementById("userOrgTypeUserUuid").value = '';
|
||||
document.getElementById("userOrgTypeOrgUuid").value = '';
|
||||
|
Reference in New Issue
Block a user