Add password validation with i18n support and GitHub button improvements

- Add password field to UserUpdate schema for password change on edit
- Implement password validation in update_user endpoint
- Add i18n translations for password validation errors (ru/en)
- Update SecurityService.validate_password to support language parameter
- Add GitHub icon and repository name 'pvemanager' to header button
- Fix internal server error when updating user password
- Clean up hardcoded translations in frontend
This commit is contained in:
2025-12-15 20:09:50 +05:00
parent 52ec402c03
commit 2b78d93710
15 changed files with 326 additions and 22 deletions

View File

@@ -610,6 +610,16 @@ body.update-in-progress .layout {
</button>
<h2>{{ page_title or title or t('nav_dashboard') }}</h2>
<div class="header-actions">
<!-- GitHub Stars Button -->
<a href="https://github.com/markmorado/pvemanager" target="_blank" rel="noopener noreferrer" class="github-btn" title="Star us on GitHub">
<i class="fa-brands fa-github"></i>
<span class="github-text">pvemanager</span>
<svg class="github-star-icon" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
<path d="M12 .587l3.668 7.568 8.332 1.151-6.064 5.828 1.48 8.279-7.416-3.967-7.417 3.967 1.481-8.279-6.064-5.828 8.332-1.151z"/>
</svg>
<span class="github-stars" id="githubStars">...</span>
</a>
<!-- Theme Toggle Button -->
<button id="themeToggle" class="theme-toggle" title="{{ t('theme') }}">
<svg class="icon-sun" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
@@ -851,6 +861,36 @@ body.update-in-progress .layout {
}
});
// Load GitHub stars count
async function loadGitHubStars() {
try {
const response = await fetch('https://api.github.com/repos/markmorado/pvemanager', {
headers: {
'Accept': 'application/vnd.github.v3+json'
}
});
if (response.ok) {
const data = await response.json();
const starsElement = document.getElementById('githubStars');
if (starsElement) {
// Format number with K for thousands
const stars = data.stargazers_count;
const formatted = stars >= 1000
? (stars / 1000).toFixed(1) + 'K'
: stars.toString();
starsElement.textContent = formatted;
}
}
} catch (error) {
console.error('Failed to load GitHub stars:', error);
const starsElement = document.getElementById('githubStars');
if (starsElement) {
starsElement.textContent = '★';
}
}
}
// Load unread notification count
async function loadNotificationCount() {
try {
@@ -1268,6 +1308,9 @@ body.update-in-progress .layout {
// Refresh count every 30 seconds
setInterval(loadNotificationCount, 30000);
// Load GitHub stars count
loadGitHubStars();
}
// Add click handlers for sidebar menu items to update page title

View File

@@ -715,6 +715,12 @@
color: var(--danger);
}
.update-status-box.warning {
background: rgba(245, 158, 11, 0.1);
border: 1px solid rgba(245, 158, 11, 0.3);
color: #f59e0b;
}
.update-changelog-box {
margin-bottom: var(--spacing-lg);
}
@@ -1797,9 +1803,16 @@ async function checkForUpdates() {
if (data.error) {
statusBox.style.display = 'block';
statusBox.className = 'update-status-box error';
statusBox.querySelector('#update-status-message').innerHTML =
'<i class="fas fa-exclamation-circle"></i> ' + data.error;
// Если проверка отключена, показываем warning вместо ошибки
if (data.disabled || data.error.includes('disabled')) {
statusBox.className = 'update-status-box warning';
statusBox.querySelector('#update-status-message').innerHTML =
'<i class="fas fa-info-circle"></i> ' + (t('update_check_disabled') || 'Проверка обновлений отключена');
} else {
statusBox.className = 'update-status-box error';
statusBox.querySelector('#update-status-message').innerHTML =
'<i class="fas fa-exclamation-circle"></i> ' + data.error;
}
updateBtn.style.display = 'none';
changelogBox.style.display = 'none';
} else if (data.update_available) {