Add admin user creation & must-change flag

Add server and UI support for creating admin users and forcing password change. API: introduce CreateUserRequest contract and add CreateNewAppUser endpoint in AppUserController; extend ChangeUserRequest with MustChangePassword and handle role assignment and detailed error responses (409/422/400). Frontend: new CreateUserDialog component, integrate it into AdminUsers list, and add createAdminUser service with CreateAdminUserError and payload handling; include mustChangePassword in update payloads and EditUserDialog. UI polish: enhanced app banner enter/leave animations in Layout.vue and add auto-dismiss timers/cleanup to appBanners store to limit and auto-remove banners.
This commit is contained in:
Jonas
2026-05-03 15:56:28 +02:00
parent 1d00fb3a4b
commit 178bc8731e
9 changed files with 720 additions and 8 deletions
+21
View File
@@ -7,6 +7,7 @@ import { useAppBannersStore } from '@/stores/appBanners'
import StatusPill from '@/components/ui/StatusPill.vue'
import UserAvatar from '@/components/ui/UserAvatar.vue'
import EmptyState from '@/components/ui/EmptyState.vue'
import CreateUserDialog from '@/components/admin/CreateUserDialog.vue'
const router = useRouter()
const appBannersStore = useAppBannersStore()
@@ -15,6 +16,7 @@ const isLoading = ref(true)
const errorMessage = ref('')
const users = ref<AdminUser[]>([])
const searchQuery = ref('')
const isCreateDialogOpen = ref(false)
const hasUsers = computed(() => users.value.length > 0)
const activeUserCount = computed(() => users.value.filter((user) => user.isActive).length)
@@ -108,6 +110,14 @@ async function openUserDetail(userId: string) {
await router.push({ name: 'AdminUserDetail', params: { userId } })
}
function openCreateDialog() {
isCreateDialogOpen.value = true
}
function handleUserCreated(user: AdminUser) {
users.value = [...users.value, user]
}
onMounted(() => {
void loadUsers()
})
@@ -135,6 +145,15 @@ onMounted(() => {
/>
<v-btn
variant="elevated"
color="primary"
prepend-icon="mdi-account-plus-outline"
:disabled="isLoading"
@click="openCreateDialog"
>
Benutzer anlegen
</v-btn>
<v-btn
variant="outlined"
prepend-icon="mdi-refresh"
:loading="isLoading"
:disabled="isLoading"
@@ -303,6 +322,8 @@ onMounted(() => {
</article>
</div>
</section>
<CreateUserDialog v-model="isCreateDialogOpen" @created="handleUserCreated" />
</v-container>
</template>