feat(dashboard): add Roles CRUD with permission-based menu filtering

- Roles CRUD: List/Create/Update/Delete actions, controller, requests
- Roles Vue pages: Index, Create, Edit (Options API, DashboardLayout)
- SidebarNav: filter menu items by user permissions via Inertia shared data
- HandleInertiaRequests: share permissions and roles arrays to frontend
- HttpKernel: register dashboard.permission middleware alias
- SidebarNavItem: add shield-check icon mapping
This commit is contained in:
F4ilji
2026-08-03 10:39:15 +05:00
parent d4ef7daeb1
commit 63e456088d
15 changed files with 725 additions and 3 deletions
@@ -2,7 +2,7 @@
<nav class="flex-1 overflow-y-auto px-3 py-4">
<div class="space-y-1">
<SidebarNavItem
v-for="item in menuItems"
v-for="item in visibleMenuItems"
:key="item.key"
:item="item"
:mobile="mobile"
@@ -44,6 +44,7 @@
<script setup>
import { computed } from 'vue';
import { usePage } from '@inertiajs/vue3';
import { menuItems } from './menuConfig';
import { quickActions } from './quickActionsConfig';
import SidebarNavItem from './SidebarNavItem.vue';
@@ -55,15 +56,24 @@ defineProps({
defineEmits(['child-click']);
const page = usePage();
const userPermissions = computed(() => page.props.auth?.permissions ?? []);
const visibleMenuItems = computed(() => {
return menuItems.filter(item => {
if (!item.permission) return true;
return userPermissions.value.includes(item.permission);
});
});
const iconMap = {
cog: DashboardIcon,
};
// Открываем только аккордеон активной страницы
const expandedKey = computed(() => {
const currentRoute = route().current();
for (const item of menuItems) {
for (const item of visibleMenuItems.value) {
if (item.activePrefixes && item.activePrefixes.some(prefix => currentRoute.startsWith(prefix))) {
return item.key;
}
@@ -76,6 +76,7 @@ const iconMap = {
'arrow-path': 'arrow-path',
'academic-cap': 'academic-cap',
'clipboard-document-check': 'clipboard-document-check',
'shield-check': 'shield-check',
key: 'key',
};