Merge pull request #27 from cadtoolbox/copilot/fix-edit-user-email-reset-password

Fix advanced authentication UI gaps: email field, password reset, templates
This commit is contained in:
Thomas Rambach
2026-02-09 19:27:31 -05:00
committed by GitHub
8 changed files with 190 additions and 127 deletions
@@ -43,6 +43,9 @@ EVENT_NAMES = {
"queue_job_skipped": "Queue Job Skipped",
"queue_job_failed": "Queue Job Failed",
"queue_completed": "Queue Completed",
# User management
"user_created": "Welcome Email",
"password_reset": "Password Reset",
}
@@ -146,4 +146,16 @@ DEFAULT_TEMPLATES = [
"title_template": "Queue Complete",
"body_template": "All {completed_count} queued jobs have finished",
},
{
"event_type": "user_created",
"name": "Welcome Email",
"title_template": "Welcome to {app_name}",
"body_template": "Welcome {username}!\n\nYour account has been created.\nUsername: {username}\nPassword: {password}\n\nLogin at: {login_url}",
},
{
"event_type": "password_reset",
"name": "Password Reset",
"title_template": "{app_name} - Password Reset",
"body_template": "Hello {username},\n\nYour password has been reset.\nNew Password: {password}\n\nLogin at: {login_url}",
},
]
@@ -53,6 +53,9 @@ EVENT_VARIABLES: dict[str, list[str]] = {
"queue_job_skipped": ["printer", "job_name", "reason", "timestamp", "app_name"],
"queue_job_failed": ["printer", "job_name", "reason", "timestamp", "app_name"],
"queue_completed": ["completed_count", "timestamp", "app_name"],
# User management notifications
"user_created": ["username", "password", "login_url", "app_name", "timestamp"],
"password_reset": ["username", "password", "login_url", "app_name", "timestamp"],
}
# Sample data for previewing templates
@@ -191,6 +194,21 @@ SAMPLE_DATA: dict[str, dict[str, str]] = {
"timestamp": "2024-01-15 18:30",
"app_name": "Bambuddy",
},
# User management notifications
"user_created": {
"username": "john_doe",
"password": "TempPass123!",
"login_url": "https://bambuddy.example.com/login",
"app_name": "Bambuddy",
"timestamp": "2024-01-15 14:30",
},
"password_reset": {
"username": "john_doe",
"password": "NewPass456!",
"login_url": "https://bambuddy.example.com/login",
"app_name": "Bambuddy",
"timestamp": "2024-01-15 14:30",
},
}
+32 -2
View File
@@ -380,6 +380,16 @@ export function SettingsPage() {
},
});
const resetPasswordMutation = useMutation({
mutationFn: (userId: number) => api.resetUserPassword({ user_id: userId }),
onSuccess: (response) => {
showToast(response.message, 'success');
},
onError: (error: Error) => {
showToast(error.message, 'error');
},
});
// Function to initiate user deletion with item count check
const handleDeleteUserClick = async (userId: number) => {
setDeleteUserId(userId);
@@ -501,6 +511,7 @@ export function SettingsPage() {
setUserFormData({
username: userToEdit.username,
password: '',
email: userToEdit.email || '',
confirmPassword: '',
role: userToEdit.role,
group_ids: userToEdit.groups?.map(g => g.id) || [],
@@ -946,7 +957,7 @@ export function SettingsPage() {
</div>
{/* Tab Navigation */}
<div className="flex flex-wrap gap-1 mb-6 border-b border-bambu-dark-tertiary overflow-y-auto max-h-32">
<div className="flex flex-wrap gap-1 mb-6 border-b border-bambu-dark-tertiary">
<button
onClick={() => handleTabChange('general')}
className={`px-4 py-2 text-sm font-medium transition-colors border-b-2 -mb-px ${
@@ -3952,10 +3963,29 @@ export function SettingsPage() {
{/* Info box about auto-generated password when Advanced Auth is enabled */}
{advancedAuthStatus?.advanced_auth_enabled && (
<div className="bg-bambu-dark-secondary/50 border border-bambu-green/20 rounded-lg p-3">
<div className="bg-bambu-dark-secondary/50 border border-bambu-green/20 rounded-lg p-3 space-y-3">
<p className="text-sm text-bambu-gray">
{t('users.form.passwordManagedByAdvancedAuth') || 'Password is managed by Advanced Authentication. Use "Reset Password" to send a new password to the user via email.'}
</p>
<Button
variant="secondary"
size="sm"
onClick={() => editingUserId && resetPasswordMutation.mutate(editingUserId)}
disabled={resetPasswordMutation.isPending || !userFormData.email}
className="w-full"
>
{resetPasswordMutation.isPending ? (
<>
<Loader2 className="w-4 h-4 animate-spin" />
{t('users.form.resettingPassword') || 'Resetting Password...'}
</>
) : (
<>
<RotateCcw className="w-4 h-4" />
{t('users.form.resetPassword') || 'Reset Password'}
</>
)}
</Button>
</div>
)}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -23,8 +23,8 @@
<!-- Splash screens for iOS -->
<link rel="apple-touch-startup-image" href="/img/android-chrome-512x512.png" />
<script type="module" crossorigin src="/assets/index-C4SeuzlU.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-RuMjImbZ.css">
<script type="module" crossorigin src="/assets/index-HOR_-s_H.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-BwfbnBQ9.css">
</head>
<body>
<div id="root"></div>