Update release notes and deploy workspace
CI - Build & Verify / Build, Typecheck & Hygiene (push) Successful in 59s
CI - Build & Verify / Deploy to award.noveria.net (push) Failing after 53s

This commit is contained in:
AzuTear
2026-06-29 17:49:54 +02:00
parent c466348d18
commit 441ef2b850
196 changed files with 9279 additions and 39292 deletions
+17 -91
View File
@@ -1,8 +1,9 @@
<script setup lang="ts">
import { Check, KeyRound, LockKeyhole, Minus, Pencil, RefreshCw, RotateCcw, Save, ShieldCheck, Trash2, UserPlus, Users } from '@lucide/vue'
import { Check, KeyRound, LockKeyhole, Pencil, RefreshCw, RotateCcw, Save, ShieldCheck, Trash2, UserPlus, Users } from '@lucide/vue'
import { computed, reactive, ref } from 'vue'
import AdminPageHeader from '../../components/admin/AdminPageHeader.vue'
import AdminTeamRolePermissionsModal from '../../components/admin/AdminTeamRolePermissionsModal.vue'
import { useAdminTeamManager } from '../../components/admin/useAdminTeamManager'
import { useBodyScrollLock } from '../../composables/useBodyScrollLock'
import { watchAdminToast } from '../../composables/useAdminToast'
@@ -43,6 +44,7 @@ const {
members,
roles,
permissions,
permissionGroups,
memberForm,
selectedMember,
pendingPasswordChanges,
@@ -72,7 +74,6 @@ const anyTeamModalOpen = computed(() =>
passwordModalOpen.value
|| createMemberModalOpen.value
|| editMemberModalOpen.value
|| rolePermissionsModalOpen.value
|| Boolean(memberPendingDeletion.value),
)
@@ -81,6 +82,7 @@ useBodyScrollLock(() => anyTeamModalOpen.value)
const summaryItems = computed(() => [
{ label: 'Mitglieder', value: members.value.length, note: `${onlineMembers.value} online` },
{ label: 'Rollen', value: roles.value.length, note: 'Owner, Creator und Team' },
{ label: 'Berechtigungen', value: permissions.value.length, note: `${permissionGroups.value.length} Bereiche` },
{ label: 'PW-Wechsel', value: pendingPasswordChanges.value, note: 'temporäre Passwörter offen' },
])
@@ -112,14 +114,6 @@ function memberOnlineStatus(member: AdminTeamMember) {
return member.isOnline ? 'Online' : 'Offline'
}
function rolePermissionLocked(roleKey: string) {
return roleKey === 'owner' || roleKey === 'creator'
}
function rolePermissionCount(roleKey: string) {
return permissions.value.filter((permission) => roleHasPermission(roleKey, permission.key)).length
}
function isOwnTeamAccount(member: AdminTeamMember) {
const teamLogin = authStore.session?.teamLogin?.toLowerCase()
const boundTwitchUserId = authStore.session?.boundTwitchUserId?.toLowerCase()
@@ -219,7 +213,7 @@ async function changeOwnPassword() {
:icon="Users"
/>
<div class="grid gap-3 md:grid-cols-3">
<div class="grid gap-3 md:grid-cols-2 xl:grid-cols-4">
<Card
v-for="item in summaryItems"
:key="item.label"
@@ -383,86 +377,18 @@ async function changeOwnPassword() {
</div>
</Card>
<Teleport to="body">
<div
v-if="rolePermissionsModalOpen"
class="fixed inset-0 z-[305] flex items-center justify-center bg-slate-950/50 p-3 backdrop-blur-sm md:p-6"
@click.self="rolePermissionsModalOpen = false"
>
<Card class="flex max-h-[88vh] w-full max-w-6xl flex-col overflow-hidden rounded-[30px] bg-white p-0 shadow-[0_34px_100px_rgba(39,28,72,0.28)]">
<div class="flex flex-wrap items-center justify-between gap-4 border-b border-violet-100 bg-white px-5 py-4 md:px-6">
<div class="flex min-w-0 items-center gap-3">
<span class="grid h-11 w-11 shrink-0 place-items-center rounded-2xl bg-violet-50 text-violet-600 ring-1 ring-violet-100">
<ShieldCheck class="h-5 w-5" />
</span>
<div class="min-w-0">
<p class="text-[10px] font-bold uppercase tracking-[0.18em] text-violet-500">Rollenrechte</p>
<h2 class="mt-1 text-xl font-bold leading-tight text-slate-950">Berechtigungen einstellen</h2>
</div>
</div>
<div class="flex flex-wrap items-center justify-end gap-2">
<Button type="button" variant="ghost" @click="rolePermissionsModalOpen = false">Schließen</Button>
<Button type="button" :disabled="saving || !hasRoleChanges" @click="saveRolePermissions">
<Save class="mr-2 h-4 w-4" />
Speichern
</Button>
</div>
</div>
<div class="min-h-0 flex-1 overflow-auto bg-slate-50/70 p-3 md:p-5">
<table class="w-full min-w-[1040px] overflow-hidden rounded-2xl border border-violet-100 bg-white text-sm shadow-sm">
<thead class="sticky top-0 z-20 bg-violet-50 text-left text-[10px] font-bold uppercase tracking-[0.16em] text-violet-500 shadow-[0_1px_0_rgba(221,214,254,0.85)]">
<tr>
<th class="sticky left-0 z-30 w-[340px] bg-violet-50 px-5 py-4">Bereich</th>
<th v-for="role in roles" :key="role.key" class="min-w-[112px] px-3 py-4 text-center">
<span class="block text-[11px] leading-4 text-violet-600">{{ role.label }}</span>
<span class="mt-1 block text-[10px] font-extrabold tracking-normal text-slate-400">
{{ rolePermissionCount(role.key) }}/{{ permissions.length }}
</span>
</th>
</tr>
</thead>
<tbody class="divide-y divide-violet-100 bg-white">
<tr v-for="permission in permissions" :key="permission.key" class="transition hover:bg-violet-50/35">
<td class="sticky left-0 z-10 w-[340px] bg-white px-5 py-4 shadow-[1px_0_0_rgba(237,233,254,0.95)]">
<span class="block text-base font-bold leading-5 text-slate-950">{{ permission.label }}</span>
<span class="mt-1 block max-w-[300px] text-xs font-semibold leading-5 text-slate-500">{{ permission.description }}</span>
</td>
<td v-for="role in roles" :key="`${role.key}-${permission.key}`" class="px-3 py-4 text-center">
<button
type="button"
class="relative mx-auto grid h-9 w-9 place-items-center rounded-xl ring-1 transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-violet-400 focus-visible:ring-offset-2 disabled:cursor-not-allowed"
:class="[
roleHasPermission(role.key, permission.key)
? rolePermissionLocked(role.key)
? 'bg-slate-100 text-slate-400 ring-slate-200'
: 'bg-violet-600 text-white shadow-lg shadow-violet-500/20 ring-violet-500 hover:bg-violet-500'
: rolePermissionLocked(role.key)
? 'bg-slate-50 text-slate-300 ring-slate-200'
: 'bg-white text-slate-300 ring-slate-300 hover:text-violet-500 hover:ring-violet-300',
]"
:disabled="rolePermissionLocked(role.key)"
:aria-label="`${role.label}: ${permission.label}`"
:aria-pressed="roleHasPermission(role.key, permission.key)"
@click="setRolePermission(role.key, permission.key, !roleHasPermission(role.key, permission.key))"
>
<Check v-if="roleHasPermission(role.key, permission.key)" class="h-5 w-5" :stroke-width="3" />
<Minus v-else class="h-4 w-4" :stroke-width="3" />
<span
v-if="rolePermissionLocked(role.key) && roleHasPermission(role.key, permission.key)"
class="absolute -right-1 -top-1 grid h-4 w-4 place-items-center rounded-full bg-white text-slate-400 ring-1 ring-slate-200"
>
<LockKeyhole class="h-2.5 w-2.5" />
</span>
</button>
</td>
</tr>
</tbody>
</table>
</div>
</Card>
</div>
</Teleport>
<AdminTeamRolePermissionsModal
:open="rolePermissionsModalOpen"
:saving="saving"
:has-role-changes="hasRoleChanges"
:roles="roles"
:permissions="permissions"
:permission-groups="permissionGroups"
:role-has-permission="roleHasPermission"
:set-role-permission="setRolePermission"
:save-role-permissions="saveRolePermissions"
@close="rolePermissionsModalOpen = false"
/>
<Teleport to="body">
<div