phase5: workspace frontend — API hooks, useWorkspace hook, WorkspaceSwitcher, Sidebar workspace filter

This commit is contained in:
Agent Zero
2026-07-29 22:12:23 +02:00
parent bd50a85483
commit fca7191269
5 changed files with 276 additions and 2 deletions
+11 -2
View File
@@ -8,6 +8,7 @@ import { usePluginStore } from '@/store/pluginStore';
import * as LucideIcons from 'lucide-react';
import { useMenuOrder } from '@/api/users';
import { usePermission } from '@/hooks/usePermission';
import { useWorkspace } from '@/hooks/useWorkspace';
import { useAuthStore } from '@/store/authStore';
interface NavSingleItem {
@@ -44,6 +45,7 @@ export function Sidebar() {
const { data: menuOrderData } = useMenuOrder();
const { hasPermission } = usePermission();
const user = useAuthStore((state) => state.user);
const { isModuleVisible } = useWorkspace();
// Use hasPermission directly — permissions are loaded via useUserPermissions hook
const canAccess = (perm?: string): boolean => {
@@ -78,12 +80,19 @@ export function Sidebar() {
}));
const allItems = [...staticItems, ...pluginItems];
// Filter by workspace visibility (in addition to permissions)
// If no workspace is active, isModuleVisible returns true (backward compatible)
const workspaceFiltered = allItems.filter(item => {
const moduleKey = item.path.replace(/^\//, '').split('/')[0];
return isModuleVisible(moduleKey);
});
// Apply saved menu order if available
const savedOrder = menuOrderData?.menu_order;
if (savedOrder && savedOrder.length > 0) {
const orderMap = new Map(savedOrder.map((id, idx) => [id, idx]));
return allItems.sort((a, b) => {
return workspaceFiltered.sort((a, b) => {
// Map path to menu ID: static items use their path without leading /
const aId = a.path.startsWith('/') ? a.path.slice(1) : a.path;
const bId = b.path.startsWith('/') ? b.path.slice(1) : b.path;
@@ -98,7 +107,7 @@ export function Sidebar() {
});
}
return allItems.sort((a, b) => {
return workspaceFiltered.sort((a, b) => {
if (a.order !== b.order) return a.order - b.order;
return a.label.localeCompare(b.label);
});