feat(auth): implement role-based access control (RBAC)
Add roles, permissions, and user_roles tables with default seed data Protect backend API endpoints with granular permission checks Add admin UI for managing users, roles, and permissions Update frontend views to conditionally render actions based on permissions
This commit is contained in:
@@ -35,20 +35,31 @@ function inDevBadge() {
|
||||
return { label: t('common.inDev'), tone: 'info' as const };
|
||||
}
|
||||
|
||||
const navItems = computed(() => [
|
||||
{ label: t('nav.pokemon'), to: '/pokemon', icon: iconPokemon },
|
||||
{ label: t('nav.habitats'), to: '/habitats', icon: iconHabitat },
|
||||
{ label: t('nav.items'), to: '/items', icon: iconItem },
|
||||
{ label: t('nav.recipes'), to: '/recipes', icon: iconRecipe },
|
||||
{ label: t('nav.dish'), to: '/dish', icon: iconDish, badge: inDevBadge() },
|
||||
{ label: t('nav.events'), to: '/events', icon: iconEvent, badge: inDevBadge() },
|
||||
{ label: t('nav.actions'), to: '/actions', icon: iconAction, badge: inDevBadge() },
|
||||
{ label: t('nav.dreamIsland'), to: '/dream-island', icon: iconDreamIsland, badge: inDevBadge() },
|
||||
{ label: t('nav.clothes'), to: '/clothes', icon: iconClothes, badge: inDevBadge() },
|
||||
{ label: t('nav.checklist'), to: '/checklist', icon: iconChecklist },
|
||||
{ label: t('nav.life'), to: '/life', icon: iconLife },
|
||||
{ label: t('nav.admin'), to: '/admin', icon: iconAdmin }
|
||||
]);
|
||||
function can(permissionKey: string) {
|
||||
return currentUser.value?.permissions.includes(permissionKey) === true;
|
||||
}
|
||||
|
||||
const navItems = computed(() => {
|
||||
const items = [
|
||||
{ label: t('nav.pokemon'), to: '/pokemon', icon: iconPokemon },
|
||||
{ label: t('nav.habitats'), to: '/habitats', icon: iconHabitat },
|
||||
{ label: t('nav.items'), to: '/items', icon: iconItem },
|
||||
{ label: t('nav.recipes'), to: '/recipes', icon: iconRecipe },
|
||||
{ label: t('nav.dish'), to: '/dish', icon: iconDish, badge: inDevBadge() },
|
||||
{ label: t('nav.events'), to: '/events', icon: iconEvent, badge: inDevBadge() },
|
||||
{ label: t('nav.actions'), to: '/actions', icon: iconAction, badge: inDevBadge() },
|
||||
{ label: t('nav.dreamIsland'), to: '/dream-island', icon: iconDreamIsland, badge: inDevBadge() },
|
||||
{ label: t('nav.clothes'), to: '/clothes', icon: iconClothes, badge: inDevBadge() },
|
||||
{ label: t('nav.checklist'), to: '/checklist', icon: iconChecklist },
|
||||
{ label: t('nav.life'), to: '/life', icon: iconLife }
|
||||
];
|
||||
|
||||
if (can('admin.access')) {
|
||||
items.push({ label: t('nav.admin'), to: '/admin', icon: iconAdmin });
|
||||
}
|
||||
|
||||
return items;
|
||||
});
|
||||
|
||||
async function loadCurrentUser() {
|
||||
if (!getAuthToken()) {
|
||||
|
||||
Reference in New Issue
Block a user