UI updates

This commit is contained in:
= 2025-01-12 17:19:11 -05:00
parent 09342c9743
commit 65c9ad9caf
5 changed files with 73 additions and 13 deletions

View File

@ -7899,7 +7899,7 @@ a.badge-dark.focus {
display: block;
padding: 0.75rem 1.25rem;
margin-bottom: -1px;
background-color: var(--select-bg);
background-color: var(--outline);
border: 1px solid rgba(0, 0, 0, 0.125);
}

View File

@ -0,0 +1,30 @@
.bootbox-custom-layout {
display: flex;
justify-content: space-between;
gap: 20px;
}
.bootbox-custom-layout .left-panel {
flex: 1;
text-align: center;
}
.bootbox-custom-layout .right-panel {
flex: 1;
}
.bootbox-custom-layout .qr-code {
width: 100%;
max-width: 200px;
/* Adjust as needed */
margin: auto;
}
.bootbox-custom-layout .list-group {
margin-top: 10px;
}
.bootbox .modal-dialog {
max-width: 900px;
/* Wider modal */
}

View File

@ -6,6 +6,7 @@
{% block title %}Crafty Controller - {{ translate('userConfig', 'editTOTP', data['lang']) }}{% end %}
{% block content %}
<link href="/static/assets/css/mfa.css" rel="stylesheet">
<div class="content-wrapper">
<!-- Page Title Header Starts-->
@ -54,7 +55,9 @@
<h4 class="card-title"><i class="fas fa-key"></i>&nbsp;{{ translate('otp',
'otpTitle',
data['lang']) }}</h4>
<div><button class="btn btn-primary" id="createButton"><i
<div><button class="btn btn-primary" id="createButton" data-backup-codes="{{
translate('otp', 'backupCodes', data['lang']) }}" data-backup-codes-max="{{
translate('otp', 'backupCodesMax', data['lang']) }}"><i
class="fas fa-plus-circle"></i>
&nbsp; {{
translate('otp', 'newOTP', data['lang']) }}</button></div>
@ -129,17 +132,37 @@
// Function to create the modal response content
function createResponseDiv(data) {
let backupcodes = ``;
let backupcodes = `<ul class="list-group">`;
data["backup_codes"].forEach(element => {
backupcodes += `<li>${element}</li>`;
backupcodes += `<li class="list-group-item">${element}</li>`;
});
backupcodes += `</ul>`
if (data["backup_codes"].length == 0) {
backupcodes = `<div style="text-align: center; color: grey;">
${$("#createButton").data("backup-codes-max")}
</div>`
}
const contentHTML = `
<div class="col-sm-12 col-md-6">
<div id="qrcode"></div>
<span id="secret">${data["otp"]["totp_secret"]}</span>
</div>
<div class="col-sm-12 col-md-6">
<ul id="backupcodes">${backupcodes}</ul>
<div class="bootbox-custom-layout row">
<div class="left-panel col-md-6 col-12 d-flex flex-column align-items-center justify-content-center">
<div id="qrcode" class="mb-3"></div>
<ul class="list-group">
<li class="list-group-item" id="secret">${data["otp"]["totp_secret"]}</li>
<ul>
<!-- Input and Verify button inline -->
<div class="d-flex align-items-center mt-3">
<input type="text" class="form-control me-2" placeholder="Enter code">
<button class="btn btn-primary">Verify</button>
</div>
</div>
<div class="right-panel col-md-6 col-12">
<h4>${$("#createButton").data("backup-codes")}</h4>
<ul class="list-group">
${backupcodes}
</ul>
</div>
</div>
`;
let responseDIV = document.createElement("div");
@ -173,17 +196,20 @@
let resdiv = createResponseDiv(responseData.data);
bootbox.dialog({
title: 'Your TOTP QR Code',
size: "large",
closeButton: false,
message: resdiv, // Display the generated QR code
buttons: {
close: {
label: 'Close',
className: 'btn-secondary',
className: 'bb-close-button',
callback: function () {
// Optional: Any cleanup logic
}
}
}
});
$(`.bb-close-button`).prop("disabled", true);
// Generate the QR Code with the TOTP secret, user name, and issuer
generateTotpQrCode(responseData.data["otp"]["totp_secret"], responseData.data["otp"]["user"]["username"], "CraftyController");

View File

@ -112,7 +112,7 @@
</div>
<select required class="form-control form-control-lg select-css" id="2fa-type" name="type">
<option value="totp">{{ translate('login', 'totpSelect', data['lang']) }}</option>
<option value="backupCode">{{ translate('login', 'backupCodeTitle', data['lang']) }}</option>
<option value="backup_code">{{ translate('login', 'backupCodeTitle', data['lang']) }}</option>
</select>
</div>
</div>
@ -206,10 +206,11 @@
"password": formDataObject.password,
}
if (formDataObject.totp != "") {
let key = $("#2fa-type").val();
body = {
"username": formDataObject.username,
"password": formDataObject.password,
"totp": formDataObject.totp,
[key]: formDataObject.totp,
}
}
let res = await fetch(`/api/v2/auth/login/`, {

View File

@ -263,6 +263,8 @@
"no": "No",
"2faCreate": "Add New 2FA Method",
"backupCodes": "New 2FA method created. Please copy your backup codes.",
"backupCodesMax": "A maximum of 6 back codes has already been reached.",
"saveWarn": "Make sure to save these backup codes or you could lose access",
"confirm2FA": "Please Confirm Authenticator Code",
"otpTitle": "2FA Methods",
"newOTP": "Add New 2 Factor Auth"
@ -698,6 +700,7 @@
"otpReq": "TOTP is required for super users. You cannot remove your only TOTP method."
},
"validators": {
"2FAerror": "2 Factor code must be 6 digits (i.e. 000000) or a backup code of 16 characters separated every 4 by - (i.e. ABCD-EFGH-IJKL-MNOP)",
"backupName": "Backup name must be a string and a minimum length of 3.",
"enumErr": "failed validating. Acceptable data includes: ",
"filesPageLen": "length must be greater than 1 for property",