Alec Rust 2 лет назад
Родитель
Сommit
d3875f8096

+ 1 - 0
.eslintrc.cjs

@@ -40,6 +40,7 @@ module.exports = {
 			},
 		],
 		'no-console': 'error',
+		'prefer-const': 'error',
 		'import/no-unresolved': 'off',
 	},
 };

+ 30 - 14
web/css/src/themes/default.css

@@ -1055,6 +1055,16 @@
 	padding-top: 12px;
 	vertical-align: top;
 	padding-bottom: 10px;
+
+	@media (--viewport-large) {
+		& .actions-panel {
+			visibility: hidden;
+		}
+
+		&:hover .actions-panel {
+			visibility: visible;
+		}
+	}
 }
 
 .l-unit__col--right.total {
@@ -1222,24 +1232,17 @@
 
 .actions-panel__col {
 	display: inline-block;
-	margin-left: 3px;
-	text-transform: uppercase;
+	margin-left: 6px;
 
 	& a {
 		color: #777;
-		font-weight: 600;
 		font-size: 0.9rem;
 		display: inline-block;
-		cursor: pointer;
 	}
-}
-
-.l-unit__col .actions-panel .fas {
-	display: none;
-}
 
-.l-unit__col:hover .actions-panel .fas {
-	display: inline-block;
+	@media (--viewport-large) {
+		margin-left: 3px;
+	}
 }
 
 /* Statistics
@@ -1395,23 +1398,36 @@
 }
 
 @media (--viewport-medium) {
-	.sidebar-right-container {
+	.sidebar-right-grid {
 		display: grid;
 		gap: 50px;
 		grid-template-columns: 2fr 1.3fr;
 	}
+
+	.sidebar-right-grid-content {
+	}
+
+	.sidebar-right-grid-sidebar {
+		max-width: 385px;
+	}
 }
 
 @media (--viewport-medium) {
-	.sidebar-left-container {
+	.sidebar-left-grid {
 		display: grid;
 		gap: 20px;
 		grid-template-columns: 1fr 3fr;
 	}
+
+	.sidebar-left-grid-sidebar {
+	}
+
+	.sidebar-left-grid-content {
+	}
 }
 
 @media (--viewport-large) {
-	.sidebar-left-container {
+	.sidebar-left-grid {
 		gap: 50px;
 	}
 }

+ 4 - 0
web/css/src/utilities.css

@@ -49,6 +49,10 @@
 	white-space: nowrap !important;
 }
 
+.u-overflow {
+	overflow: auto !important;
+}
+
 .u-mt15 {
 	margin-top: 15px !important;
 }

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
web/css/themes/default.min.css


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
web/js/dist/main.min.js


Разница между файлами не показана из-за своего большого размера
+ 0 - 1
web/js/dist/main.min.js.map


+ 10 - 14
web/js/pages/add_db.js

@@ -28,14 +28,12 @@ App.Listeners.DB.keypress_db_username = () => {
 		App.Actions.DB.update_db_username_hint(input);
 	}
 
-	const updateTimeout = (evt) => {
-		clearTimeout(window.frp_usr_tmt);
-		window.frp_usr_tmt = setTimeout(() => {
+	input.addEventListener(
+		'input',
+		Hestia.helpers.debounce((evt) => {
 			App.Actions.DB.update_db_username_hint(evt.target);
-		}, 100);
-	};
-
-	input.addEventListener('input', updateTimeout);
+		}, 100)
+	);
 };
 
 // Listener that triggers database user hint updating
@@ -46,14 +44,12 @@ App.Listeners.DB.keypress_db_databasename = () => {
 		App.Actions.DB.update_db_databasename_hint(input);
 	}
 
-	const updateTimeout = (evt) => {
-		clearTimeout(window.frp_dbn_tmt);
-		window.frp_dbn_tmt = setTimeout(() => {
+	input.addEventListener(
+		'input',
+		Hestia.helpers.debounce((evt) => {
 			App.Actions.DB.update_db_databasename_hint(evt.target);
-		}, 100);
-	};
-
-	input.addEventListener('input', updateTimeout);
+		}, 100)
+	);
 };
 
 //

+ 0 - 52
web/js/pages/add_dns_rec.js

@@ -1,52 +0,0 @@
-// Updates database DNS record dynamically, showing its full domain path
-App.Actions.DB.update_dns_record_hint = (input) => {
-	const domainInput = document.querySelector('input[name="v_domain"]');
-	const hintElement = input.parentElement.querySelector('.hint');
-
-	// Clean hint
-	let hint = input.value.trim();
-
-	if (hint === '') {
-		hintElement.textContent = '';
-	}
-
-	// Set domain name without rec in case of @ entries
-	if (hint === '@') {
-		hint = '';
-	}
-
-	// Don't show prefix if domain name equals rec value
-	if (hint === domainInput.value) {
-		hint = '';
-	}
-
-	// Add dot at the end if needed
-	if (hint !== '' && hint.slice(-1) !== '.') {
-		hint += '.';
-	}
-
-	hintElement.textContent = hint + domainInput.value;
-};
-
-// Listener that triggers dns record name hint updating
-App.Listeners.DB.keypress_dns_rec_entry = () => {
-	const input = document.querySelector('input[name="v_rec"]');
-
-	if (input.value.trim() != '') {
-		App.Actions.DB.update_dns_record_hint(input);
-	}
-
-	const updateTimeout = (evt) => {
-		clearTimeout(window.frp_usr_tmt);
-		window.frp_usr_tmt = setTimeout(() => {
-			App.Actions.DB.update_dns_record_hint(evt.target);
-		}, 100);
-	};
-
-	input.addEventListener('input', updateTimeout);
-};
-
-//
-// Page entry point
-// Trigger listeners
-App.Listeners.DB.keypress_dns_rec_entry();

+ 2 - 67
web/js/pages/add_web.js

@@ -1,45 +1,7 @@
-// Page entry point
-// Trigger listeners
-App.Listeners.DB.keypress_custom_folder();
-App.Listeners.DB.change_custom_doc();
-
-App.Actions.WEB.update_ftp_username_hint = function (elm, hint) {
-	if (hint.trim() == '') {
-		$(elm).parent().find('.hint').text('');
-	}
-
-	hint = hint.replace(/[^\w\d]/gi, '');
-
-	$(elm).parent().find('.js-ftp-user').val(hint);
-	$(elm)
-		.parent()
-		.find('.hint')
-		.text(Alpine.store('globals').FTP_USER_PREFIX + hint);
-};
-
-App.Listeners.WEB.keypress_ftp_username = function () {
-	var ftp_user_inputs = $('.js-ftp-user');
-	$.each(ftp_user_inputs, function (i, ref) {
-		var $ref = $(ref);
-		var current_val = $ref.val();
-		if (current_val.trim() != '') {
-			App.Actions.WEB.update_ftp_username_hint($ref, current_val);
-		}
-
-		$ref.bind('keypress input', function (evt) {
-			clearTimeout(window.frp_usr_tmt);
-			window.frp_usr_tmt = setTimeout(function () {
-				var elm = $(evt.target);
-				App.Actions.WEB.update_ftp_username_hint(elm, $(elm).val());
-			}, 100);
-		});
-	});
-};
-
 App.Listeners.WEB.keypress_domain_name = function () {
 	$('#v_domain').bind('keypress input', function () {
-		clearTimeout(window.frp_usr_tmt);
-		window.frp_usr_tmt = setTimeout(function () {
+		clearTimeout(window.frpUserTimeout);
+		window.frpUserTimeout = setTimeout(function () {
 			$('#v-custom-doc-domain-main').text($('#v_domain').val());
 			$('#v-custom-doc-domain-main').val($('#v_domain').val());
 			App.Actions.WEB.update_custom_doc_root(13, 12);
@@ -47,24 +9,8 @@ App.Listeners.WEB.keypress_domain_name = function () {
 	});
 };
 
-App.Actions.WEB.toggle_letsencrypt = function (elm) {
-	if ($(elm).prop('checked')) {
-		$(
-			'#ssltable textarea[name=v_ssl_crt],#ssltable textarea[name=v_ssl_key], #ssltable textarea[name=v_ssl_ca]'
-		).attr('disabled', 'disabled');
-		$('#generate-csr').hide();
-	} else {
-		$(
-			'#ssltable textarea[name=v_ssl_crt],#ssltable textarea[name=v_ssl_key], #ssltable textarea[name=v_ssl_ca]'
-		).removeAttr('disabled');
-		$('#generate-csr').show();
-	}
-};
-
 //
 // Page entry point
-App.Listeners.WEB.keypress_ftp_username();
-App.Listeners.WEB.keypress_ftp_path();
 App.Listeners.WEB.keypress_domain_name();
 
 $(function () {
@@ -77,15 +23,4 @@ $(function () {
 				prefix + document.getElementById('v_domain').value;
 		}
 	});
-	App.Actions.WEB.toggle_letsencrypt($('input[name=v_letsencrypt]'));
-
-	$('select[name="v_stats"]').change(function (evt) {
-		var select = $(evt.target);
-
-		if (select.val() == 'none') {
-			$('.stats-auth').hide();
-		} else {
-			$('.stats-auth').show();
-		}
-	});
 });

+ 10 - 14
web/js/pages/edit_db.js

@@ -28,14 +28,12 @@ App.Listeners.DB.keypress_db_username = () => {
 		App.Actions.DB.update_db_username_hint(input);
 	}
 
-	const updateTimeout = (evt) => {
-		clearTimeout(window.frp_usr_tmt);
-		window.frp_usr_tmt = setTimeout(() => {
+	input.addEventListener(
+		'input',
+		Hestia.helpers.debounce((evt) => {
 			App.Actions.DB.update_db_username_hint(evt.target);
-		}, 100);
-	};
-
-	input.addEventListener('input', updateTimeout);
+		}, 100)
+	);
 };
 
 // Listener that triggers database user hint updating
@@ -51,14 +49,12 @@ App.Listeners.DB.keypress_db_databasename = () => {
 		App.Actions.DB.update_db_databasename_hint(input);
 	}
 
-	const updateTimeout = (evt) => {
-		clearTimeout(window.frp_dbn_tmt);
-		window.frp_dbn_tmt = setTimeout(() => {
+	input.addEventListener(
+		'input',
+		Hestia.helpers.debounce((evt) => {
 			App.Actions.DB.update_db_databasename_hint(evt.target);
-		}, 100);
-	};
-
-	input.addEventListener('input', updateTimeout);
+		}, 100)
+	);
 };
 
 //

+ 0 - 52
web/js/pages/edit_dns_rec.js

@@ -1,52 +0,0 @@
-// Updates database DNS record dynamically, showing its full domain path
-App.Actions.DB.update_dns_record_hint = (input) => {
-	const domainInput = document.querySelector('input[name="v_domain"]');
-	const hintElement = input.parentElement.querySelector('.hint');
-
-	// Clean hint
-	let hint = input.value.trim();
-
-	if (hint === '') {
-		hintElement.textContent = '';
-	}
-
-	// Set domain name without rec in case of @ entries
-	if (hint === '@') {
-		hint = '';
-	}
-
-	// Don't show prefix if domain name equals rec value
-	if (hint === domainInput.value) {
-		hint = '';
-	}
-
-	// Add dot at the end if needed
-	if (hint !== '' && hint.slice(-1) !== '.') {
-		hint += '.';
-	}
-
-	hintElement.textContent = hint + domainInput.value;
-};
-
-// Listener that triggers dns record name hint updating
-App.Listeners.DB.keypress_dns_rec_entry = () => {
-	const input = document.querySelector('input[name="v_rec"]');
-
-	if (input.value.trim() != '') {
-		App.Actions.DB.update_dns_record_hint(input);
-	}
-
-	const updateTimeout = (evt) => {
-		clearTimeout(window.frp_usr_tmt);
-		window.frp_usr_tmt = setTimeout(() => {
-			App.Actions.DB.update_dns_record_hint(evt.target);
-		}, 100);
-	};
-
-	input.addEventListener('input', updateTimeout);
-};
-
-//
-// Page entry point
-// Trigger listeners
-App.Listeners.DB.keypress_dns_rec_entry();

+ 8 - 8
web/js/pages/edit_web.js

@@ -11,8 +11,8 @@ App.Listeners.DB.keypress_custom_folder = function () {
 	App.Actions.WEB.update_custom_doc_root(ref, current_rec);
 
 	ref.bind('keypress input', function (evt) {
-		clearTimeout(window.frp_usr_tmt);
-		window.frp_usr_tmt = setTimeout(function () {
+		clearTimeout(window.frpUserTimeout);
+		window.frpUserTimeout = setTimeout(function () {
 			var elm = $(evt.target);
 			App.Actions.WEB.update_custom_doc_root(elm, $(elm).val());
 		});
@@ -24,8 +24,8 @@ App.Listeners.DB.change_custom_doc = function () {
 	// var current_rec = ref.val();
 
 	ref.bind('change select', function (evt) {
-		clearTimeout(window.frp_usr_tmt);
-		window.frp_usr_tmt = setTimeout(function () {
+		clearTimeout(window.frpUserTimeout);
+		window.frpUserTimeout = setTimeout(function () {
 			var elm = $(evt.target);
 			App.Actions.WEB.update_custom_doc_root(elm, $(elm).val());
 		});
@@ -61,8 +61,8 @@ App.Listeners.WEB.keypress_ftp_username = function () {
 		}
 
 		$ref.bind('keypress input', function (evt) {
-			clearTimeout(window.frp_usr_tmt);
-			window.frp_usr_tmt = setTimeout(function () {
+			clearTimeout(window.frpUserTimeout);
+			window.frpUserTimeout = setTimeout(function () {
 				var elm = $(evt.target);
 				App.Actions.WEB.update_ftp_username_hint(elm, $(elm).val());
 			}, 100);
@@ -97,8 +97,8 @@ App.Listeners.WEB.keypress_ftp_path = function () {
 		}
 
 		$ref.bind('keypress input', function (evt) {
-			clearTimeout(window.frp_usr_tmt);
-			window.frp_usr_tmt = setTimeout(function () {
+			clearTimeout(window.frpUserTimeout);
+			window.frpUserTimeout = setTimeout(function () {
 				var elm = $(evt.target);
 				App.Actions.WEB.update_ftp_path_hint(elm, $(elm).val());
 			}, 100);

+ 11 - 4
web/js/src/copyCreds.js

@@ -1,3 +1,5 @@
+import { debounce } from './helpers';
+
 // Monitor "Account" and "Password" inputs on "Add/Edit Mail Account"
 // page and update the sidebar "Account" and "Password" output
 export default function handleCopyCreds() {
@@ -18,9 +20,12 @@ function monitorAndUpdate(inputSelector, outputSelector) {
 		generateMailCredentials();
 	}
 
-	inputElement.addEventListener('input', (event) => {
-		updateOutput(event.target.value);
-	});
+	inputElement.addEventListener(
+		'input',
+		debounce((evt) => {
+			updateOutput(evt.target.value);
+		}, 100)
+	);
 	updateOutput(inputElement.value);
 }
 
@@ -28,7 +33,9 @@ function monitorAndUpdate(inputSelector, outputSelector) {
 function generateMailCredentials() {
 	const mailInfoPanel = document.querySelector('.js-mail-info');
 
-	if (!mailInfoPanel) return;
+	if (!mailInfoPanel) {
+		return;
+	}
 
 	const formattedCredentials = emailCredentialsAsPlainText(mailInfoPanel.cloneNode(true));
 	document.querySelector('.js-hidden-credentials').value = formattedCredentials;

+ 3 - 1
web/js/src/discardAllMail.js

@@ -2,7 +2,9 @@
 export default function handleDiscardAllMail() {
 	const discardAllMailCheckbox = document.querySelector('.js-discard-all-mail');
 
-	if (!discardAllMailCheckbox) return;
+	if (!discardAllMailCheckbox) {
+		return;
+	}
 
 	discardAllMailCheckbox.addEventListener('click', () => {
 		const forwardToTextarea = document.getElementById('v_fwd');

+ 51 - 0
web/js/src/dnsRecordHint.js

@@ -0,0 +1,51 @@
+import { debounce } from './helpers';
+
+// Attach listener to DNS "Record" field to update its hint
+export default function handleDnsRecordHint() {
+	const recordInput = document.querySelector('.js-dns-record-input');
+
+	if (!recordInput) {
+		return;
+	}
+
+	if (recordInput.value.trim() != '') {
+		updateHint(recordInput);
+	}
+
+	recordInput.addEventListener(
+		'input',
+		debounce((evt) => {
+			updateHint(evt.target);
+		}, 100)
+	);
+}
+
+// Update DNS "Record" field hint
+function updateHint(input) {
+	const domainInput = document.querySelector('input[name="v_domain"]');
+	const hintElement = input.parentElement.querySelector('.hint');
+	let hint = input.value.trim();
+
+	// Clear the hint if input is empty
+	if (hint === '') {
+		hintElement.textContent = '';
+		return;
+	}
+
+	// Set domain name without rec in case of @ entries
+	if (hint === '@') {
+		hint = '';
+	}
+
+	// Don't show prefix if domain name equals rec value
+	if (hint === domainInput.value) {
+		hint = '';
+	}
+
+	// Add dot at the end if needed
+	if (hint !== '' && hint.slice(-1) !== '.') {
+		hint += '.';
+	}
+
+	hintElement.textContent = hint + domainInput.value;
+}

+ 9 - 0
web/js/src/helpers.js

@@ -18,6 +18,15 @@ export function randomPassword(length = 16) {
 	return password;
 }
 
+// Debounces a function to avoid excessive calls
+export function debounce(func, wait) {
+	let timeout;
+	return function (...args) {
+		clearTimeout(timeout);
+		timeout = setTimeout(() => func.apply(this, args), wait);
+	};
+}
+
 // Returns the value of a CSS variable
 export function getCssVariable(variableName) {
 	return getComputedStyle(document.documentElement).getPropertyValue(variableName).trim();

+ 6 - 2
web/js/src/ipListDataSource.js

@@ -2,7 +2,9 @@
 export default function handleIpListDataSource() {
 	const dataSourceSelect = document.querySelector('.js-datasource-select');
 
-	if (!dataSourceSelect) return;
+	if (!dataSourceSelect) {
+		return;
+	}
 
 	// Parse IP lists from HTML and sort them alphabetically
 	const countryIplists = parseAndSortIplists(dataSourceSelect.dataset.countryIplists);
@@ -32,6 +34,8 @@ function addOption(element, text, value, disabled) {
 	const option = document.createElement('option');
 	option.text = text;
 	option.value = value;
-	if (disabled) option.disabled = true;
+	if (disabled) {
+		option.disabled = true;
+	}
 	element.appendChild(option);
 }

+ 7 - 3
web/js/src/listSorting.js

@@ -1,6 +1,6 @@
 // List view sorting dropdown
 export default function handleListSorting() {
-	let state = {
+	const state = {
 		sort_par: 'sort-name',
 		sort_direction: -1,
 		sort_as_int: false,
@@ -19,7 +19,9 @@ export default function handleListSorting() {
 		const toggleButton = document.querySelector('.toolbar-sorting-toggle');
 		const dropdown = document.querySelector('.toolbar-sorting-menu');
 
-		if (!dropdown || !toggleButton) return;
+		if (!dropdown || !toggleButton) {
+			return;
+		}
 
 		if (
 			!dropdown.contains(event.target) &&
@@ -36,7 +38,9 @@ export default function handleListSorting() {
 			const menu = document.querySelector('.toolbar-sorting-menu');
 			menu.classList.toggle('u-hidden');
 
-			if (this.classList.contains('active')) return;
+			if (this.classList.contains('active')) {
+				return;
+			}
 
 			document
 				.querySelectorAll('.toolbar-sorting-menu span')

+ 2 - 0
web/js/src/main.js

@@ -4,6 +4,7 @@ import handleConfirmationDialogs from './confirmationDialog';
 import handleCopyCreds from './copyCreds';
 import handleCronGenerator from './cronGenerator';
 import handleDiscardAllMail from './discardAllMail';
+import handleDnsRecordHint from './dnsRecordHint';
 import handleErrorMessage from './errorHandler';
 import handleFormSubmit from './formSubmit';
 import handleIpListDataSource from './ipListDataSource';
@@ -29,6 +30,7 @@ function initListeners() {
 	handleCopyCreds();
 	handleCronGenerator();
 	handleDiscardAllMail();
+	handleDnsRecordHint();
 	handleFormSubmit();
 	handleListSelectAll();
 	handleListSorting();

+ 7 - 3
web/js/src/navigation.js

@@ -1,5 +1,5 @@
 // Page navigation methods called by shortcuts
-let state = {
+const state = {
 	active_menu: 1,
 	menu_selector: '.main-menu-item',
 	menu_active_selector: '.active',
@@ -82,7 +82,9 @@ function moveFocusUpDown(direction) {
 	const currentFocused = document.querySelector('.units .l-unit.focus');
 	let index = units.indexOf(currentFocused);
 
-	if (index === -1) index = 0;
+	if (index === -1) {
+		index = 0;
+	}
 
 	if (direction === 'up' && index > 0) {
 		index--;
@@ -92,7 +94,9 @@ function moveFocusUpDown(direction) {
 		return;
 	}
 
-	if (currentFocused) currentFocused.classList.remove('focus');
+	if (currentFocused) {
+		currentFocused.classList.remove('focus');
+	}
 	units[index].classList.add('focus');
 
 	window.scrollTo({

+ 6 - 8
web/js/src/passwordInput.js

@@ -1,18 +1,16 @@
 import { passwordStrength } from 'check-password-strength';
-import { randomPassword } from './helpers';
+import { randomPassword, debounce } from './helpers';
 
 // Adds listeners to password inputs (to monitor strength) and generate password buttons
 export default function handlePasswordInput() {
 	// Listen for changes to password inputs and update the password strength
 	document.querySelectorAll('.js-password-input').forEach((passwordInput) => {
-		const updateTimeout = (evt) => {
-			clearTimeout(window.frp_usr_tmt);
-			window.frp_usr_tmt = setTimeout(() => {
+		passwordInput.addEventListener(
+			'input',
+			debounce((evt) => {
 				recalculatePasswordStrength(evt.target);
-			}, 100);
-		};
-
-		passwordInput.addEventListener('input', updateTimeout);
+			}, 100)
+		);
 	});
 
 	// Listen for clicks on generate password buttons and set a new random password

+ 3 - 1
web/js/src/shortcuts.js

@@ -99,7 +99,9 @@ export default function handleShortcuts() {
 			const shortcut = this.registeredShortcuts.find(
 				(shortcut) => JSON.stringify(shortcut.combination) == JSON.stringify(combination)
 			);
-			if (!shortcut) return;
+			if (!shortcut) {
+				return;
+			}
 
 			this.registeredShortcuts = this.registeredShortcuts.filter(
 				(shortcut) => JSON.stringify(shortcut.combination) != JSON.stringify(combination)

+ 8 - 1
web/js/src/syncEmailValues.js

@@ -1,3 +1,5 @@
+import { debounce } from './helpers';
+
 // Synchronizes the "Email" input value with "Email login credentials to" input value
 // based on the "Send welcome email" checkbox state on Add User page
 export default function handleSyncEmailValues() {
@@ -17,6 +19,11 @@ export default function handleSyncEmailValues() {
 		}
 	}
 
-	emailInput.addEventListener('input', syncEmailValues);
+	emailInput.addEventListener(
+		'input',
+		debounce(() => {
+			syncEmailValues();
+		}, 100)
+	);
 	sendWelcomeEmailCheckbox.addEventListener('change', syncEmailValues);
 }

+ 3 - 1
web/js/src/tabPanels.js

@@ -2,7 +2,9 @@
 export default function handleTabPanels() {
 	const tabs = document.querySelector('.js-tabs');
 
-	if (!tabs) return;
+	if (!tabs) {
+		return;
+	}
 
 	const tabItems = tabs.querySelectorAll('.tabs-item');
 	const panels = tabs.querySelectorAll('.tabs-panel');

+ 3 - 3
web/templates/pages/add_cron.php

@@ -28,8 +28,8 @@
 				<label for="v_cmd" class="form-label"><?= _("Command") ?></label>
 				<input type="text" class="form-control" name="v_cmd" id="v_cmd" value="<?= htmlentities(trim($v_cmd, "'")) ?>">
 			</div>
-			<div class="sidebar-left-container">
-				<div>
+			<div class="sidebar-left-grid">
+				<div class="sidebar-left-grid-sidebar">
 					<div class="u-mb10">
 						<label for="v_min" class="form-label"><?= _("Minute") ?></label>
 						<input type="text" class="form-control" name="v_min" id="v_min" value="<?= htmlentities(trim($v_min, "'")) ?>">
@@ -51,7 +51,7 @@
 						<input type="text" class="form-control" name="v_wday" id="v_wday" value="<?= htmlentities(trim($v_wday, "'")) ?>">
 					</div>
 				</div>
-				<div>
+				<div class="sidebar-left-grid-content">
 					<div class="tabs cron-tabs js-tabs">
 						<div class="tabs-items" role="tablist">
 							<button type="button" class="tabs-item" id="tab-one" role="tab" tabindex="0" aria-selected="true"><?= _("Minutes") ?></button>

+ 2 - 2
web/templates/pages/add_dns_rec.php

@@ -31,7 +31,7 @@
 			</div>
 			<div class="u-mb10">
 				<label for="v_rec" class="form-label"><?= _("Record") ?></label>
-				<input type="text" class="form-control" name="v_rec" id="v_rec" value="<?= htmlentities(trim($v_rec, "'")) ?>">
+				<input type="text" class="form-control js-dns-record-input" name="v_rec" id="v_rec" value="<?= htmlentities(trim($v_rec, "'")) ?>">
 				<small class="hint"></small>
 			</div>
 			<div class="u-mb10">
@@ -66,7 +66,7 @@
 							}
 						?>
 					</select>
-					<input type="text" class="form-control list-editor" name="v_val" id="v_val" value="<?= htmlentities(trim($v_val, "'")) ?>">
+					<input type="text" class="form-control list-editor" name="v_val" id="v_val" value="<?= htmlentities(trim($v_val, "'")) ?>" required>
 				</div>
 			</div>
 			<div class="u-mb10">

+ 1 - 1
web/templates/pages/add_firewall_banlist.php

@@ -28,7 +28,7 @@
 				<label for="v_ip" class="form-label">
 					<?= _("IP address") ?> <span class="optional">(<?= _("CIDR format is supported") ?>)</span>
 				</label>
-				<input type="text" class="form-control" name="v_ip" id="v_ip" value="<?= htmlentities(trim($v_ip, "'")) ?>">
+				<input type="text" class="form-control" name="v_ip" id="v_ip" value="<?= htmlentities(trim($v_ip, "'")) ?>" required>
 			</div>
 			<div class="u-mb10">
 				<label for="v_chain" class="form-label"><?= _("Banlist") ?></label>

+ 1 - 1
web/templates/pages/add_key.php

@@ -32,7 +32,7 @@
 			<?php show_alert_message($_SESSION); ?>
 			<div>
 				<label for="v_key" class="form-label"><?= _("SSH KEY") ?></label>
-				<textarea class="form-control u-min-height300" name="v_key" id="v_key"><?= htmlentities(trim($v_key, "'")) ?></textarea>
+				<textarea class="form-control u-min-height300" name="v_key" id="v_key" required><?= htmlentities(trim($v_key, "'")) ?></textarea>
 			</div>
 		</div>
 

+ 7 - 7
web/templates/pages/add_mail_acc.php

@@ -31,8 +31,8 @@
 		<div class="form-container form-container-wide">
 			<h1 class="form-title"><?= _("Adding Mail Account") ?></h1>
 			<?php show_alert_message($_SESSION); ?>
-			<div class="sidebar-right-container">
-				<div>
+			<div class="sidebar-right-grid">
+				<div class="sidebar-right-grid-content">
 					<div class="u-mb10">
 						<label for="v_domain" class="form-label"><?= _("Domain") ?></label>
 						<input type="text" class="form-control" name="v_domain" id="v_domain" value="<?= htmlentities(trim($v_domain, "'")) ?>" disabled>
@@ -40,7 +40,7 @@
 					</div>
 					<div class="u-mb10">
 						<label for="v_account" class="form-label"><?= _("Account") ?></label>
-						<input type="text" class="form-control js-account-input" name="v_account" id="v_account" value="<?= htmlentities(trim($v_account, "'")) ?>">
+						<input type="text" class="form-control js-account-input" name="v_account" id="v_account" value="<?= htmlentities(trim($v_account, "'")) ?>" required>
 					</div>
 					<div class="u-mb10">
 						<label for="v_password" class="form-label">
@@ -50,7 +50,7 @@
 							</button>
 						</label>
 						<div class="u-pos-relative u-mb10">
-							<input type="text" class="form-control js-password-input" name="v_password" id="v_password">
+							<input type="text" class="form-control js-password-input" name="v_password" id="v_password" required>
 							<div class="password-meter">
 								<meter max="4" class="password-meter-input js-password-meter"></meter>
 							</div>
@@ -118,17 +118,17 @@
 						<input type="hidden" name="v_credentials" class="js-hidden-credentials">
 					</div>
 				</div>
-				<div>
+				<div class="sidebar-right-grid-sidebar">
 					<div class="panel js-mail-info">
 						<h2 class="u-text-H3 u-mb10"><?= _("Common account settings") ?></h2>
 						<ul class="values-list u-mb20">
 							<li class="values-list-item">
 								<span class="values-list-label"><?= _("Username") ?></span>
-								<span class="values-list-value"><span class="js-account-output"></span>@<?= htmlentities(trim($v_domain, "'")) ?></span>
+								<span class="values-list-value u-overflow"><span class="js-account-output"></span>@<?= htmlentities(trim($v_domain, "'")) ?></span>
 							</li>
 							<li class="values-list-item">
 								<span class="values-list-label"><?= _("Password") ?></span>
-								<span class="values-list-value"><span class="js-password-output"></span></span>
+								<span class="values-list-value u-overflow"><span class="js-password-output"></span></span>
 							</li>
 							<?php if ($_SESSION["WEBMAIL_SYSTEM"]) { ?>
 								<li class="values-list-item">

+ 3 - 3
web/templates/pages/edit_cron.php

@@ -28,8 +28,8 @@
 				<label for="v_cmd" class="form-label"><?= _("Command") ?></label>
 				<input type="text" class="form-control" name="v_cmd" id="v_cmd" value="<?= htmlentities(trim($v_cmd, "'")) ?>">
 			</div>
-			<div class="sidebar-left-container">
-				<div>
+			<div class="sidebar-left-grid">
+				<div class="sidebar-left-grid-sidebar">
 					<div class="u-mb10">
 						<label for="v_min" class="form-label"><?= _("Minute") ?></label>
 						<input type="text" class="form-control" name="v_min" id="v_min" value="<?= htmlentities(trim($v_min, "'")) ?>">
@@ -51,7 +51,7 @@
 						<input type="text" class="form-control" name="v_wday" id="v_wday" value="<?= htmlentities(trim($v_wday, "'")) ?>">
 					</div>
 				</div>
-				<div>
+				<div class="sidebar-left-grid-content">
 					<div class="tabs cron-tabs js-tabs">
 						<div class="tabs-items" role="tablist">
 							<button type="button" class="tabs-item" id="tab-one" role="tab" tabindex="0" aria-selected="true"><?= _("Minutes") ?></button>

+ 1 - 1
web/templates/pages/edit_dns_rec.php

@@ -31,7 +31,7 @@
 			</div>
 			<div class="u-mb10">
 				<label for="v_rec" class="form-label"><?= _("Record") ?></label>
-				<input type="text" class="form-control" name="v_rec" id="v_rec" value="<?= htmlentities(trim($v_rec, "'")) ?>">
+				<input type="text" class="form-control js-dns-record-input" name="v_rec" id="v_rec" value="<?= htmlentities(trim($v_rec, "'")) ?>">
 				<input type="hidden" name="v_record_id" value="<?= htmlentities(trim($v_record_id, "'")) ?>">
 				<small class="hint"></small>
 			</div>

+ 5 - 5
web/templates/pages/edit_mail_acc.php

@@ -32,8 +32,8 @@
 		<div class="form-container form-container-wide">
 			<h1 class="form-title"><?= _("Editing Mail Account") ?></h1>
 			<?php show_alert_message($_SESSION); ?>
-			<div class="sidebar-right-container">
-				<div>
+			<div class="sidebar-right-grid">
+				<div class="sidebar-right-grid-content">
 					<div class="u-mb10">
 						<label for="v_email" class="form-label"><?= _("Account") ?></label>
 						<input type="text" class="form-control" name="v_email" id="v_email" value="<?= htmlentities($_GET["account"]) . "@" . htmlentities($_GET["domain"]) ?>" disabled>
@@ -121,17 +121,17 @@
 						<input type="text" class="form-control" name="v_rate" id="v_rate" value="<?=htmlentities(trim($v_rate, "'"))?>" <?php if($_SESSION['userContext'] != "admin"){ echo "disabled";}?>>
 					</div>
 				</div>
-				<div>
+				<div class="sidebar-right-grid-sidebar">
 					<div class="panel js-mail-info">
 						<h2 class="u-text-H3 u-mb10"><?= _("Common account settings") ?></h2>
 						<ul class="values-list u-mb20">
 							<li class="values-list-item">
 								<span class="values-list-label"><?= _("Username") ?></span>
-								<span class="values-list-value"><span class="js-account-output"></span>@<?= htmlentities(trim($v_domain, "'")) ?></span>
+								<span class="values-list-value u-overflow"><span class="js-account-output"></span>@<?= htmlentities(trim($v_domain, "'")) ?></span>
 							</li>
 							<li class="values-list-item">
 								<span class="values-list-label"><?= _("Password") ?></span>
-								<span class="values-list-value"><span class="js-password-output"></span></span>
+								<span class="values-list-value u-overflow"><span class="js-password-output"></span></span>
 							</li>
 							<?php if ($_SESSION["WEBMAIL_SYSTEM"]) { ?>
 								<li class="values-list-item">

+ 1 - 1
web/templates/pages/list_user.php

@@ -100,7 +100,7 @@
 		<div class="l-unit <?php if ($status == 'suspended') echo 'l-unit--suspended';?> animate__animated animate__fadeIn" v_section="user"
 			v_unit_id="<?=$key?>" sort-date="<?=strtotime($data[$key]['DATE'].' '.$data[$key]['TIME'])?>" sort-name="<?=strtolower($key)?>"
 			sort-bandwidth="<?=$data[$key]['U_BANDWIDTH']?>" sort-disk="<?=$data[$key]['U_DISK']?>">
-			<div class="l-unit__col l-unit__col--right" style="<?php if (($_SESSION['POLICY_SYSTEM_HIDE_ADMIN'] === 'yes') && ($_SESSION['user'] !== 'admin') && ($key === 'admin')) { echo 'display: none';} else {echo 'display: table-cell';}?>">
+			<div class="l-unit__col l-unit__col--right" style="<?php if (($_SESSION['POLICY_SYSTEM_HIDE_ADMIN'] === 'yes') && ($_SESSION['user'] !== 'admin') && ($key === 'admin')) { echo 'display: none';} ?>">
 				<div class="clearfix l-unit__stat-col--left super-compact">
 					<input id="check<?= $i ?>" class="ch-toggle" type="checkbox" title="<?= _("Select") ?>" name="user[]" value="<?= $key ?>">
 				</div>

Некоторые файлы не были показаны из-за большого количества измененных файлов