fix: impersonation UX — banner contrast, route blocking, nav filtering
- Banner: white elevated button for contrast, fixed 48px height, layout top padding offset so content isn't obscured - Middleware: allow GET me/profile (viewing), block mutations only; add auth/refresh to blocked routes - Navigation: hide Platform section during impersonation; hide org-dependent items when impersonated user has no organisation - Test: add read-only routes allowed test, auth/refresh blocked test Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -65,54 +65,43 @@ onUnmounted(() => {
|
||||
<VSystemBar
|
||||
v-if="impersonationStore.isImpersonating"
|
||||
color="warning"
|
||||
class="impersonation-banner"
|
||||
height="48"
|
||||
style="z-index: 9999; position: fixed; top: 0; left: 0; right: 0;"
|
||||
class="px-4"
|
||||
>
|
||||
<VIcon
|
||||
icon="tabler-user-exclamation"
|
||||
icon="tabler-user-search"
|
||||
size="20"
|
||||
class="me-2"
|
||||
/>
|
||||
<span>
|
||||
<span class="text-body-2 font-weight-medium">
|
||||
Je bekijkt het platform als
|
||||
<strong>{{ impersonationStore.impersonatedUser?.full_name }}</strong>
|
||||
({{ impersonationStore.impersonatedUser?.email }})
|
||||
</span>
|
||||
|
||||
<VSpacer />
|
||||
|
||||
<VChip
|
||||
size="small"
|
||||
variant="tonal"
|
||||
color="warning"
|
||||
class="me-3"
|
||||
<span
|
||||
v-if="remainingFormatted"
|
||||
class="text-caption me-4"
|
||||
>
|
||||
<VIcon
|
||||
icon="tabler-clock"
|
||||
size="14"
|
||||
class="me-1"
|
||||
/>
|
||||
{{ remainingFormatted }}
|
||||
</VChip>
|
||||
</span>
|
||||
|
||||
<VBtn
|
||||
variant="tonal"
|
||||
color="warning"
|
||||
size="small"
|
||||
variant="elevated"
|
||||
color="white"
|
||||
class="text-warning"
|
||||
:loading="isStopping"
|
||||
prepend-icon="tabler-arrow-back"
|
||||
@click="handleStop"
|
||||
>
|
||||
<VIcon
|
||||
icon="tabler-arrow-back"
|
||||
size="16"
|
||||
class="me-1"
|
||||
/>
|
||||
Terug naar admin
|
||||
</VBtn>
|
||||
</VSystemBar>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* VSystemBar uses a fixed height by default; override to accommodate the button */
|
||||
.impersonation-banner {
|
||||
z-index: 9999;
|
||||
block-size: auto;
|
||||
min-block-size: 36px;
|
||||
padding-block: 4px;
|
||||
padding-inline: 16px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,22 +1,36 @@
|
||||
<script lang="ts" setup>
|
||||
import { orgNavItems, platformNavItems } from '@/navigation/vertical'
|
||||
import { useAuthStore } from '@/stores/useAuthStore'
|
||||
import { useImpersonationStore } from '@/stores/useImpersonationStore'
|
||||
|
||||
const authStore = useAuthStore()
|
||||
const impersonationStore = useImpersonationStore()
|
||||
|
||||
const hasOrganisation = computed(() => !!authStore.organisations.length)
|
||||
|
||||
const navItems = computed(() => {
|
||||
const orgName = authStore.currentOrganisation?.name ?? 'Beheer'
|
||||
|
||||
const orgItems = orgNavItems.map(item => {
|
||||
let orgItems = orgNavItems.map(item => {
|
||||
if ('heading' in item && item.heading === 'Beheer') {
|
||||
return { ...item, heading: orgName }
|
||||
}
|
||||
return item
|
||||
})
|
||||
|
||||
if (authStore.isSuperAdmin) {
|
||||
// During impersonation: hide org-dependent items if user has no organisation
|
||||
if (impersonationStore.isImpersonating && !hasOrganisation.value) {
|
||||
orgItems = orgItems.filter(item => {
|
||||
if ('heading' in item) return false
|
||||
return 'to' in item && item.to?.name === 'dashboard'
|
||||
})
|
||||
}
|
||||
|
||||
// Platform items: only for super_admin AND only when NOT impersonating
|
||||
if (authStore.isSuperAdmin && !impersonationStore.isImpersonating) {
|
||||
return [...orgItems, ...platformNavItems]
|
||||
}
|
||||
|
||||
return orgItems
|
||||
})
|
||||
|
||||
@@ -35,6 +49,7 @@ import { VerticalNavLayout } from '@layouts'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :style="{ paddingTop: impersonationStore.isImpersonating ? '48px' : '0' }">
|
||||
<VerticalNavLayout :nav-items="navItems">
|
||||
<!-- 👉 Organisation switcher -->
|
||||
<template #before-vertical-nav-items>
|
||||
@@ -82,4 +97,5 @@ import { VerticalNavLayout } from '@layouts'
|
||||
<!-- 👉 Customizer -->
|
||||
<!-- <TheCustomizer /> -->
|
||||
</VerticalNavLayout>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user