Clean up some permissions
This commit is contained in:
@@ -7,12 +7,13 @@ This document outlines the permission system implemented in the Inventory Manage
|
|||||||
Permissions follow this naming convention:
|
Permissions follow this naming convention:
|
||||||
|
|
||||||
- Page access: `access:{page_name}`
|
- Page access: `access:{page_name}`
|
||||||
- Actions: `{action}:{resource}`
|
- Settings sections: `settings:{section_name}`
|
||||||
|
- Admin features: `admin:{feature}`
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
- `access:products` - Can access the Products page
|
- `access:products` - Can access the Products page
|
||||||
- `create:products` - Can create new products
|
- `settings:user_management` - Can access User Management settings
|
||||||
- `edit:users` - Can edit user accounts
|
- `admin:debug` - Can see debug information
|
||||||
|
|
||||||
## Permission Components
|
## Permission Components
|
||||||
|
|
||||||
@@ -22,10 +23,10 @@ The core component that conditionally renders content based on permissions.
|
|||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
<PermissionGuard
|
<PermissionGuard
|
||||||
permission="create:products"
|
permission="settings:user_management"
|
||||||
fallback={<p>No permission</p>}
|
fallback={<p>No permission</p>}
|
||||||
>
|
>
|
||||||
<button>Create Product</button>
|
<button>Manage Users</button>
|
||||||
</PermissionGuard>
|
</PermissionGuard>
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -81,7 +82,7 @@ Specific component for settings with built-in permission checks.
|
|||||||
<SettingsSection
|
<SettingsSection
|
||||||
title="System Settings"
|
title="System Settings"
|
||||||
description="Configure global settings"
|
description="Configure global settings"
|
||||||
permission="edit:system_settings"
|
permission="settings:global"
|
||||||
>
|
>
|
||||||
{/* Settings content */}
|
{/* Settings content */}
|
||||||
</SettingsSection>
|
</SettingsSection>
|
||||||
@@ -95,8 +96,8 @@ Core hook for checking any permission.
|
|||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
const { hasPermission, hasPageAccess, isAdmin } = usePermissions();
|
const { hasPermission, hasPageAccess, isAdmin } = usePermissions();
|
||||||
if (hasPermission('delete:products')) {
|
if (hasPermission('settings:user_management')) {
|
||||||
// Can delete products
|
// Can access user management
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -106,8 +107,8 @@ Specialized hook for page-level permissions.
|
|||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
const { canView, canCreate, canEdit, canDelete } = usePagePermission('products');
|
const { canView, canCreate, canEdit, canDelete } = usePagePermission('products');
|
||||||
if (canEdit()) {
|
if (canView()) {
|
||||||
// Can edit products
|
// Can view products
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -119,18 +120,43 @@ Permissions are stored in the database:
|
|||||||
|
|
||||||
Admin users automatically have all permissions.
|
Admin users automatically have all permissions.
|
||||||
|
|
||||||
## Common Permission Codes
|
## Implemented Permission Codes
|
||||||
|
|
||||||
|
### Page Access Permissions
|
||||||
| Code | Description |
|
| Code | Description |
|
||||||
|------|-------------|
|
|------|-------------|
|
||||||
| `access:dashboard` | Access to Dashboard page |
|
| `access:dashboard` | Access to Dashboard page |
|
||||||
|
| `access:overview` | Access to Overview page |
|
||||||
| `access:products` | Access to Products page |
|
| `access:products` | Access to Products page |
|
||||||
| `create:products` | Create new products |
|
| `access:categories` | Access to Categories page |
|
||||||
| `edit:products` | Edit existing products |
|
| `access:brands` | Access to Brands page |
|
||||||
| `delete:products` | Delete products |
|
| `access:vendors` | Access to Vendors page |
|
||||||
| `view:users` | View user accounts |
|
| `access:purchase_orders` | Access to Purchase Orders page |
|
||||||
| `edit:users` | Edit user accounts |
|
| `access:analytics` | Access to Analytics page |
|
||||||
| `manage:permissions` | Assign permissions to users |
|
| `access:forecasting` | Access to Forecasting page |
|
||||||
|
| `access:import` | Access to Import page |
|
||||||
|
| `access:settings` | Access to Settings page |
|
||||||
|
| `access:chat` | Access to Chat Archive page |
|
||||||
|
|
||||||
|
### Settings Permissions
|
||||||
|
| Code | Description |
|
||||||
|
|------|-------------|
|
||||||
|
| `settings:global` | Access to Global Settings section |
|
||||||
|
| `settings:products` | Access to Product Settings section |
|
||||||
|
| `settings:vendors` | Access to Vendor Settings section |
|
||||||
|
| `settings:data_management` | Access to Data Management settings |
|
||||||
|
| `settings:calculation_settings` | Access to Calculation Settings |
|
||||||
|
| `settings:library_management` | Access to Image Library Management |
|
||||||
|
| `settings:performance_metrics` | Access to Performance Metrics |
|
||||||
|
| `settings:prompt_management` | Access to AI Prompt Management |
|
||||||
|
| `settings:stock_management` | Access to Stock Management |
|
||||||
|
| `settings:templates` | Access to Template Management |
|
||||||
|
| `settings:user_management` | Access to User Management |
|
||||||
|
|
||||||
|
### Admin Permissions
|
||||||
|
| Code | Description |
|
||||||
|
|------|-------------|
|
||||||
|
| `admin:debug` | Can see debug information and features |
|
||||||
|
|
||||||
## Implementation Examples
|
## Implementation Examples
|
||||||
|
|
||||||
@@ -148,25 +174,31 @@ In `App.tsx`:
|
|||||||
### Component Level Protection
|
### Component Level Protection
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
const { canEdit } = usePagePermission('products');
|
const { hasPermission } = usePermissions();
|
||||||
|
|
||||||
function handleEdit() {
|
function handleAction() {
|
||||||
if (!canEdit()) {
|
if (!hasPermission('settings:user_management')) {
|
||||||
toast.error("You don't have permission");
|
toast.error("You don't have permission");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Edit logic
|
// Action logic
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### UI Element Protection
|
### UI Element Protection
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
<PermissionButton
|
<PermissionGuard permission="settings:user_management">
|
||||||
page="products"
|
<button onClick={handleManageUsers}>
|
||||||
action="delete"
|
Manage Users
|
||||||
onClick={handleDelete}
|
</button>
|
||||||
>
|
</PermissionGuard>
|
||||||
Delete
|
|
||||||
</PermissionButton>
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- **Page Access**: These permissions control which pages a user can navigate to
|
||||||
|
- **Settings Access**: These permissions control access to different sections within the Settings page
|
||||||
|
- **Admin Features**: Special permissions for administrative functions
|
||||||
|
- **CRUD Operations**: The application currently focuses on viewing and managing data rather than creating/editing/deleting individual records
|
||||||
|
- **User Management**: User CRUD operations are handled through the settings interface rather than dedicated user management pages
|
||||||
@@ -103,14 +103,7 @@ function App() {
|
|||||||
}>
|
}>
|
||||||
{/* Core inventory app routes - will be lazy loaded */}
|
{/* Core inventory app routes - will be lazy loaded */}
|
||||||
<Route index element={
|
<Route index element={
|
||||||
<Protected page="dashboard" fallback={<FirstAccessiblePage />}>
|
<Protected page="overview" fallback={<FirstAccessiblePage />}>
|
||||||
<Suspense fallback={<PageLoading />}>
|
|
||||||
<Overview />
|
|
||||||
</Suspense>
|
|
||||||
</Protected>
|
|
||||||
} />
|
|
||||||
<Route path="/" element={
|
|
||||||
<Protected page="dashboard">
|
|
||||||
<Suspense fallback={<PageLoading />}>
|
<Suspense fallback={<PageLoading />}>
|
||||||
<Overview />
|
<Overview />
|
||||||
</Suspense>
|
</Suspense>
|
||||||
|
|||||||
@@ -1,67 +1,162 @@
|
|||||||
# Permission System Documentation
|
# Permission System Documentation
|
||||||
|
|
||||||
This document outlines the simplified permission system implemented in the Inventory Manager application.
|
This document outlines the permission system implemented in the Inventory Manager application.
|
||||||
|
|
||||||
## Permission Structure
|
## Permission Structure
|
||||||
|
|
||||||
Permissions follow this naming convention:
|
Permissions follow this naming convention:
|
||||||
|
|
||||||
- Page access: `access:{page_name}`
|
- Page access: `access:{page_name}`
|
||||||
- Actions: `{action}:{resource}`
|
- Settings sections: `settings:{section_name}`
|
||||||
|
- Admin features: `admin:{feature}`
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
- `access:products` - Can access the Products page
|
- `access:products` - Can access the Products page
|
||||||
- `create:products` - Can create new products
|
- `settings:user_management` - Can access User Management settings
|
||||||
- `edit:users` - Can edit user accounts
|
- `admin:debug` - Can see debug information
|
||||||
|
|
||||||
## Permission Component
|
## Permission Components
|
||||||
|
|
||||||
### Protected
|
### PermissionGuard
|
||||||
|
|
||||||
The core component that conditionally renders content based on permissions.
|
The core component that conditionally renders content based on permissions.
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
<Protected
|
<PermissionGuard
|
||||||
permission="create:products"
|
permission="settings:user_management"
|
||||||
fallback={<p>No permission</p>}
|
fallback={<p>No permission</p>}
|
||||||
>
|
>
|
||||||
<button>Create Product</button>
|
<button>Manage Users</button>
|
||||||
</Protected>
|
</PermissionGuard>
|
||||||
```
|
```
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
- `permission`: Single permission code (e.g., "create:products")
|
- `permission`: Single permission code
|
||||||
- `page`: Page name (checks `access:{page}` permission)
|
- `anyPermissions`: Array of permissions (ANY match grants access)
|
||||||
- `resource` + `action`: Resource and action (checks `{action}:{resource}` permission)
|
- `allPermissions`: Array of permissions (ALL required)
|
||||||
- `adminOnly`: For admin-only sections
|
- `adminOnly`: For admin-only sections
|
||||||
|
- `page`: Page name (checks `access:{page}` permission)
|
||||||
- `fallback`: Content to show if permission check fails
|
- `fallback`: Content to show if permission check fails
|
||||||
|
|
||||||
### RequireAuth
|
### PermissionProtectedRoute
|
||||||
|
|
||||||
Used for basic authentication checks (is user logged in?).
|
Protects entire pages based on page access permissions.
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
<Route element={
|
<Route path="/products" element={
|
||||||
<RequireAuth>
|
<PermissionProtectedRoute page="products">
|
||||||
<MainLayout />
|
<Products />
|
||||||
</RequireAuth>
|
</PermissionProtectedRoute>
|
||||||
}>
|
} />
|
||||||
{/* Protected routes */}
|
|
||||||
</Route>
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Common Permission Codes
|
### ProtectedSection
|
||||||
|
|
||||||
|
Protects sections within a page based on action permissions.
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
<ProtectedSection page="products" action="create">
|
||||||
|
<button>Add Product</button>
|
||||||
|
</ProtectedSection>
|
||||||
|
```
|
||||||
|
|
||||||
|
### PermissionButton
|
||||||
|
|
||||||
|
Button that automatically handles permissions.
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
<PermissionButton
|
||||||
|
page="products"
|
||||||
|
action="create"
|
||||||
|
onClick={handleCreateProduct}
|
||||||
|
>
|
||||||
|
Add Product
|
||||||
|
</PermissionButton>
|
||||||
|
```
|
||||||
|
|
||||||
|
### SettingsSection
|
||||||
|
|
||||||
|
Specific component for settings with built-in permission checks.
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
<SettingsSection
|
||||||
|
title="System Settings"
|
||||||
|
description="Configure global settings"
|
||||||
|
permission="settings:global"
|
||||||
|
>
|
||||||
|
{/* Settings content */}
|
||||||
|
</SettingsSection>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Permission Hooks
|
||||||
|
|
||||||
|
### usePermissions
|
||||||
|
|
||||||
|
Core hook for checking any permission.
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
const { hasPermission, hasPageAccess, isAdmin } = usePermissions();
|
||||||
|
if (hasPermission('settings:user_management')) {
|
||||||
|
// Can access user management
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### usePagePermission
|
||||||
|
|
||||||
|
Specialized hook for page-level permissions.
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
const { canView, canCreate, canEdit, canDelete } = usePagePermission('products');
|
||||||
|
if (canView()) {
|
||||||
|
// Can view products
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Database Schema
|
||||||
|
|
||||||
|
Permissions are stored in the database:
|
||||||
|
- `permissions` table: Stores all available permissions
|
||||||
|
- `user_permissions` junction table: Maps permissions to users
|
||||||
|
|
||||||
|
Admin users automatically have all permissions.
|
||||||
|
|
||||||
|
## Implemented Permission Codes
|
||||||
|
|
||||||
|
### Page Access Permissions
|
||||||
| Code | Description |
|
| Code | Description |
|
||||||
|------|-------------|
|
|------|-------------|
|
||||||
| `access:dashboard` | Access to Dashboard page |
|
| `access:dashboard` | Access to Dashboard page |
|
||||||
|
| `access:overview` | Access to Overview page |
|
||||||
| `access:products` | Access to Products page |
|
| `access:products` | Access to Products page |
|
||||||
| `create:products` | Create new products |
|
| `access:categories` | Access to Categories page |
|
||||||
| `edit:products` | Edit existing products |
|
| `access:brands` | Access to Brands page |
|
||||||
| `delete:products` | Delete products |
|
| `access:vendors` | Access to Vendors page |
|
||||||
| `view:users` | View user accounts |
|
| `access:purchase_orders` | Access to Purchase Orders page |
|
||||||
| `edit:users` | Edit user accounts |
|
| `access:analytics` | Access to Analytics page |
|
||||||
| `manage:permissions` | Assign permissions to users |
|
| `access:forecasting` | Access to Forecasting page |
|
||||||
|
| `access:import` | Access to Import page |
|
||||||
|
| `access:settings` | Access to Settings page |
|
||||||
|
| `access:chat` | Access to Chat Archive page |
|
||||||
|
|
||||||
|
### Settings Permissions
|
||||||
|
| Code | Description |
|
||||||
|
|------|-------------|
|
||||||
|
| `settings:global` | Access to Global Settings section |
|
||||||
|
| `settings:products` | Access to Product Settings section |
|
||||||
|
| `settings:vendors` | Access to Vendor Settings section |
|
||||||
|
| `settings:data_management` | Access to Data Management settings |
|
||||||
|
| `settings:calculation_settings` | Access to Calculation Settings |
|
||||||
|
| `settings:library_management` | Access to Image Library Management |
|
||||||
|
| `settings:performance_metrics` | Access to Performance Metrics |
|
||||||
|
| `settings:prompt_management` | Access to AI Prompt Management |
|
||||||
|
| `settings:stock_management` | Access to Stock Management |
|
||||||
|
| `settings:templates` | Access to Template Management |
|
||||||
|
| `settings:user_management` | Access to User Management |
|
||||||
|
|
||||||
|
### Admin Permissions
|
||||||
|
| Code | Description |
|
||||||
|
|------|-------------|
|
||||||
|
| `admin:debug` | Can see debug information and features |
|
||||||
|
|
||||||
## Implementation Examples
|
## Implementation Examples
|
||||||
|
|
||||||
@@ -70,35 +165,40 @@ Used for basic authentication checks (is user logged in?).
|
|||||||
In `App.tsx`:
|
In `App.tsx`:
|
||||||
```tsx
|
```tsx
|
||||||
<Route path="/products" element={
|
<Route path="/products" element={
|
||||||
<Protected page="products" fallback={<Navigate to="/" />}>
|
<PermissionProtectedRoute page="products">
|
||||||
<Products />
|
<Products />
|
||||||
</Protected>
|
</PermissionProtectedRoute>
|
||||||
} />
|
} />
|
||||||
```
|
```
|
||||||
|
|
||||||
### Component Level Protection
|
### Component Level Protection
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
<Protected permission="edit:products">
|
const { hasPermission } = usePermissions();
|
||||||
<form>
|
|
||||||
{/* Form fields */}
|
function handleAction() {
|
||||||
<button type="submit">Save Changes</button>
|
if (!hasPermission('settings:user_management')) {
|
||||||
</form>
|
toast.error("You don't have permission");
|
||||||
</Protected>
|
return;
|
||||||
|
}
|
||||||
|
// Action logic
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Button Protection
|
### UI Element Protection
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
<Button
|
<PermissionGuard permission="settings:user_management">
|
||||||
onClick={handleDelete}
|
<button onClick={handleManageUsers}>
|
||||||
disabled={!hasPermission('delete:products')}
|
Manage Users
|
||||||
>
|
</button>
|
||||||
Delete
|
</PermissionGuard>
|
||||||
</Button>
|
|
||||||
|
|
||||||
// With Protected component
|
|
||||||
<Protected permission="delete:products" fallback={null}>
|
|
||||||
<Button onClick={handleDelete}>Delete</Button>
|
|
||||||
</Protected>
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- **Page Access**: These permissions control which pages a user can navigate to
|
||||||
|
- **Settings Access**: These permissions control access to different sections within the Settings page
|
||||||
|
- **Admin Features**: Special permissions for administrative functions
|
||||||
|
- **CRUD Operations**: The application currently focuses on viewing and managing data rather than creating/editing/deleting individual records
|
||||||
|
- **User Management**: User CRUD operations are handled through the settings interface rather than dedicated user management pages
|
||||||
@@ -29,6 +29,8 @@ import {
|
|||||||
} from "@/components/ui/sidebar";
|
} from "@/components/ui/sidebar";
|
||||||
import { useLocation, useNavigate, Link } from "react-router-dom";
|
import { useLocation, useNavigate, Link } from "react-router-dom";
|
||||||
import { Protected } from "@/components/auth/Protected";
|
import { Protected } from "@/components/auth/Protected";
|
||||||
|
import { useContext } from "react";
|
||||||
|
import { AuthContext } from "@/contexts/AuthContext";
|
||||||
|
|
||||||
const dashboardItems = [
|
const dashboardItems = [
|
||||||
{
|
{
|
||||||
@@ -112,6 +114,7 @@ export function AppSidebar() {
|
|||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
useSidebar();
|
useSidebar();
|
||||||
|
const { user } = useContext(AuthContext);
|
||||||
|
|
||||||
const handleLogout = () => {
|
const handleLogout = () => {
|
||||||
localStorage.removeItem('token');
|
localStorage.removeItem('token');
|
||||||
@@ -119,6 +122,12 @@ export function AppSidebar() {
|
|||||||
navigate('/login');
|
navigate('/login');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Check if user has access to any items in a section
|
||||||
|
const hasAccessToSection = (items: typeof inventoryItems): boolean => {
|
||||||
|
if (user?.is_admin) return true;
|
||||||
|
return items.some(item => user?.permissions?.includes(item.permission));
|
||||||
|
};
|
||||||
|
|
||||||
const renderMenuItems = (items: typeof inventoryItems) => {
|
const renderMenuItems = (items: typeof inventoryItems) => {
|
||||||
return items.map((item) => {
|
return items.map((item) => {
|
||||||
const isActive =
|
const isActive =
|
||||||
@@ -180,58 +189,58 @@ export function AppSidebar() {
|
|||||||
<SidebarSeparator />
|
<SidebarSeparator />
|
||||||
<SidebarContent>
|
<SidebarContent>
|
||||||
{/* Dashboard Section */}
|
{/* Dashboard Section */}
|
||||||
<SidebarGroup>
|
{hasAccessToSection(dashboardItems) && (
|
||||||
<SidebarGroupLabel>Dashboard</SidebarGroupLabel>
|
<SidebarGroup>
|
||||||
<SidebarGroupContent>
|
<SidebarGroupLabel>Dashboard</SidebarGroupLabel>
|
||||||
<SidebarMenu>
|
<SidebarGroupContent>
|
||||||
{renderMenuItems(dashboardItems)}
|
<SidebarMenu>
|
||||||
</SidebarMenu>
|
{renderMenuItems(dashboardItems)}
|
||||||
</SidebarGroupContent>
|
</SidebarMenu>
|
||||||
</SidebarGroup>
|
</SidebarGroupContent>
|
||||||
|
</SidebarGroup>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Inventory Section */}
|
{/* Inventory Section */}
|
||||||
<SidebarGroup>
|
{hasAccessToSection(inventoryItems) && (
|
||||||
<SidebarGroupLabel>Inventory</SidebarGroupLabel>
|
<SidebarGroup>
|
||||||
<SidebarGroupContent>
|
<SidebarGroupLabel>Inventory</SidebarGroupLabel>
|
||||||
<SidebarMenu>
|
<SidebarGroupContent>
|
||||||
{renderMenuItems(inventoryItems)}
|
<SidebarMenu>
|
||||||
</SidebarMenu>
|
{renderMenuItems(inventoryItems)}
|
||||||
</SidebarGroupContent>
|
</SidebarMenu>
|
||||||
</SidebarGroup>
|
</SidebarGroupContent>
|
||||||
|
</SidebarGroup>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Product Setup Section */}
|
{/* Product Setup Section */}
|
||||||
<SidebarGroup>
|
{hasAccessToSection(productSetupItems) && (
|
||||||
<SidebarGroupLabel>Product Setup</SidebarGroupLabel>
|
<SidebarGroup>
|
||||||
<SidebarGroupContent>
|
<SidebarGroupLabel>Product Setup</SidebarGroupLabel>
|
||||||
<SidebarMenu>
|
<SidebarGroupContent>
|
||||||
{renderMenuItems(productSetupItems)}
|
<SidebarMenu>
|
||||||
</SidebarMenu>
|
{renderMenuItems(productSetupItems)}
|
||||||
</SidebarGroupContent>
|
</SidebarMenu>
|
||||||
</SidebarGroup>
|
</SidebarGroupContent>
|
||||||
|
</SidebarGroup>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Chat Section */}
|
{/* Chat Section */}
|
||||||
<SidebarGroup>
|
{hasAccessToSection(chatItems) && (
|
||||||
<SidebarGroupLabel>Chat</SidebarGroupLabel>
|
<SidebarGroup>
|
||||||
<SidebarGroupContent>
|
<SidebarGroupLabel>Chat</SidebarGroupLabel>
|
||||||
<SidebarMenu>
|
<SidebarGroupContent>
|
||||||
{renderMenuItems(chatItems)}
|
<SidebarMenu>
|
||||||
</SidebarMenu>
|
{renderMenuItems(chatItems)}
|
||||||
</SidebarGroupContent>
|
</SidebarMenu>
|
||||||
</SidebarGroup>
|
</SidebarGroupContent>
|
||||||
<SidebarSeparator />
|
</SidebarGroup>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Settings Section */}
|
{/* Settings Section */}
|
||||||
<SidebarGroup>
|
<Protected permission="access:settings" fallback={null}>
|
||||||
|
<SidebarGroup>
|
||||||
<SidebarGroupContent>
|
<SidebarGroupContent>
|
||||||
<SidebarMenu>
|
<SidebarMenu>
|
||||||
<Protected
|
|
||||||
permission="access:settings"
|
|
||||||
fallback={null}
|
|
||||||
>
|
|
||||||
<SidebarMenuItem>
|
<SidebarMenuItem>
|
||||||
<SidebarMenuButton
|
<SidebarMenuButton
|
||||||
asChild
|
asChild
|
||||||
@@ -246,10 +255,10 @@ export function AppSidebar() {
|
|||||||
</Link>
|
</Link>
|
||||||
</SidebarMenuButton>
|
</SidebarMenuButton>
|
||||||
</SidebarMenuItem>
|
</SidebarMenuItem>
|
||||||
</Protected>
|
</SidebarMenu>
|
||||||
</SidebarMenu>
|
</SidebarGroupContent>
|
||||||
</SidebarGroupContent>
|
</SidebarGroup>
|
||||||
</SidebarGroup>
|
</Protected>
|
||||||
</SidebarContent>
|
</SidebarContent>
|
||||||
<SidebarSeparator />
|
<SidebarSeparator />
|
||||||
<SidebarFooter>
|
<SidebarFooter>
|
||||||
|
|||||||
@@ -291,8 +291,7 @@ export function UserForm({ user, permissions, onSave, onCancel }: UserFormProps)
|
|||||||
<>
|
<>
|
||||||
{form.watch("is_admin") ? (
|
{form.watch("is_admin") ? (
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<h3 className="text-lg font-medium">Permissions</h3>
|
<Alert variant="destructive">
|
||||||
<Alert>
|
|
||||||
<AlertDescription>
|
<AlertDescription>
|
||||||
Administrators have access to all permissions by default. Individual permissions cannot be edited for admin users.
|
Administrators have access to all permissions by default. Individual permissions cannot be edited for admin users.
|
||||||
</AlertDescription>
|
</AlertDescription>
|
||||||
|
|||||||
Reference in New Issue
Block a user