Added Roles and Permissions. Some minor UI fixes
This commit is contained in:
@@ -18,6 +18,9 @@ import LogViewer from "./mqtt/LogViewer";
|
||||
import NoteList from "./equipment/NoteList";
|
||||
import NoteDetail from "./equipment/NoteDetail";
|
||||
import NoteForm from "./equipment/NoteForm";
|
||||
import StaffList from "./settings/StaffList";
|
||||
import StaffDetail from "./settings/StaffDetail";
|
||||
import StaffForm from "./settings/StaffForm";
|
||||
|
||||
function ProtectedRoute({ children }) {
|
||||
const { user, loading } = useAuth();
|
||||
@@ -37,6 +40,52 @@ function ProtectedRoute({ children }) {
|
||||
return children;
|
||||
}
|
||||
|
||||
function PermissionGate({ section, action = "view", children }) {
|
||||
const { hasPermission } = useAuth();
|
||||
|
||||
if (!hasPermission(section, action)) {
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center py-20">
|
||||
<div className="rounded-lg border p-8 text-center max-w-md" style={{ backgroundColor: "var(--bg-card)", borderColor: "var(--border-primary)" }}>
|
||||
<svg className="w-12 h-12 mx-auto mb-4" style={{ color: "var(--text-muted)" }} fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" />
|
||||
</svg>
|
||||
<h2 className="text-lg font-semibold mb-2" style={{ color: "var(--text-heading)" }}>Access Denied</h2>
|
||||
<p className="text-sm" style={{ color: "var(--text-muted)" }}>
|
||||
You don't have permission to access this feature.
|
||||
Please contact an administrator if you need access.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return children;
|
||||
}
|
||||
|
||||
function RoleGate({ roles, children }) {
|
||||
const { hasRole } = useAuth();
|
||||
|
||||
if (!hasRole(...roles)) {
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center py-20">
|
||||
<div className="rounded-lg border p-8 text-center max-w-md" style={{ backgroundColor: "var(--bg-card)", borderColor: "var(--border-primary)" }}>
|
||||
<svg className="w-12 h-12 mx-auto mb-4" style={{ color: "var(--text-muted)" }} fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" />
|
||||
</svg>
|
||||
<h2 className="text-lg font-semibold mb-2" style={{ color: "var(--text-heading)" }}>Access Denied</h2>
|
||||
<p className="text-sm" style={{ color: "var(--text-muted)" }}>
|
||||
You don't have permission to access this feature.
|
||||
Please contact an administrator if you need access.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return children;
|
||||
}
|
||||
|
||||
function DashboardPage() {
|
||||
const { user } = useAuth();
|
||||
return (
|
||||
@@ -62,26 +111,43 @@ export default function App() {
|
||||
}
|
||||
>
|
||||
<Route index element={<DashboardPage />} />
|
||||
<Route path="melodies" element={<MelodyList />} />
|
||||
<Route path="melodies/settings" element={<MelodySettings />} />
|
||||
<Route path="melodies/new" element={<MelodyForm />} />
|
||||
<Route path="melodies/:id" element={<MelodyDetail />} />
|
||||
<Route path="melodies/:id/edit" element={<MelodyForm />} />
|
||||
<Route path="devices" element={<DeviceList />} />
|
||||
<Route path="devices/new" element={<DeviceForm />} />
|
||||
<Route path="devices/:id" element={<DeviceDetail />} />
|
||||
<Route path="devices/:id/edit" element={<DeviceForm />} />
|
||||
<Route path="users" element={<UserList />} />
|
||||
<Route path="users/new" element={<UserForm />} />
|
||||
<Route path="users/:id" element={<UserDetail />} />
|
||||
<Route path="users/:id/edit" element={<UserForm />} />
|
||||
<Route path="mqtt" element={<MqttDashboard />} />
|
||||
<Route path="mqtt/commands" element={<CommandPanel />} />
|
||||
<Route path="mqtt/logs" element={<LogViewer />} />
|
||||
<Route path="equipment/notes" element={<NoteList />} />
|
||||
<Route path="equipment/notes/new" element={<NoteForm />} />
|
||||
<Route path="equipment/notes/:id" element={<NoteDetail />} />
|
||||
<Route path="equipment/notes/:id/edit" element={<NoteForm />} />
|
||||
|
||||
{/* Melodies */}
|
||||
<Route path="melodies" element={<PermissionGate section="melodies"><MelodyList /></PermissionGate>} />
|
||||
<Route path="melodies/settings" element={<PermissionGate section="melodies"><MelodySettings /></PermissionGate>} />
|
||||
<Route path="melodies/new" element={<PermissionGate section="melodies" action="add"><MelodyForm /></PermissionGate>} />
|
||||
<Route path="melodies/:id" element={<PermissionGate section="melodies"><MelodyDetail /></PermissionGate>} />
|
||||
<Route path="melodies/:id/edit" element={<PermissionGate section="melodies" action="edit"><MelodyForm /></PermissionGate>} />
|
||||
|
||||
{/* Devices */}
|
||||
<Route path="devices" element={<PermissionGate section="devices"><DeviceList /></PermissionGate>} />
|
||||
<Route path="devices/new" element={<PermissionGate section="devices" action="add"><DeviceForm /></PermissionGate>} />
|
||||
<Route path="devices/:id" element={<PermissionGate section="devices"><DeviceDetail /></PermissionGate>} />
|
||||
<Route path="devices/:id/edit" element={<PermissionGate section="devices" action="edit"><DeviceForm /></PermissionGate>} />
|
||||
|
||||
{/* App Users */}
|
||||
<Route path="users" element={<PermissionGate section="app_users"><UserList /></PermissionGate>} />
|
||||
<Route path="users/new" element={<PermissionGate section="app_users" action="add"><UserForm /></PermissionGate>} />
|
||||
<Route path="users/:id" element={<PermissionGate section="app_users"><UserDetail /></PermissionGate>} />
|
||||
<Route path="users/:id/edit" element={<PermissionGate section="app_users" action="edit"><UserForm /></PermissionGate>} />
|
||||
|
||||
{/* MQTT */}
|
||||
<Route path="mqtt" element={<PermissionGate section="mqtt"><MqttDashboard /></PermissionGate>} />
|
||||
<Route path="mqtt/commands" element={<PermissionGate section="mqtt"><CommandPanel /></PermissionGate>} />
|
||||
<Route path="mqtt/logs" element={<PermissionGate section="mqtt"><LogViewer /></PermissionGate>} />
|
||||
|
||||
{/* Equipment Notes */}
|
||||
<Route path="equipment/notes" element={<PermissionGate section="equipment"><NoteList /></PermissionGate>} />
|
||||
<Route path="equipment/notes/new" element={<PermissionGate section="equipment" action="add"><NoteForm /></PermissionGate>} />
|
||||
<Route path="equipment/notes/:id" element={<PermissionGate section="equipment"><NoteDetail /></PermissionGate>} />
|
||||
<Route path="equipment/notes/:id/edit" element={<PermissionGate section="equipment" action="edit"><NoteForm /></PermissionGate>} />
|
||||
|
||||
{/* Settings - Staff Management */}
|
||||
<Route path="settings/staff" element={<RoleGate roles={["sysadmin", "admin"]}><StaffList /></RoleGate>} />
|
||||
<Route path="settings/staff/new" element={<RoleGate roles={["sysadmin", "admin"]}><StaffForm /></RoleGate>} />
|
||||
<Route path="settings/staff/:id" element={<RoleGate roles={["sysadmin", "admin"]}><StaffDetail /></RoleGate>} />
|
||||
<Route path="settings/staff/:id/edit" element={<RoleGate roles={["sysadmin", "admin"]}><StaffForm /></RoleGate>} />
|
||||
|
||||
<Route path="*" element={<Navigate to="/" replace />} />
|
||||
</Route>
|
||||
</Routes>
|
||||
|
||||
Reference in New Issue
Block a user