feat: global ui & functional update

This commit is contained in:
ivannoskov
2026-01-21 22:43:54 +03:00
parent 8958d89d12
commit 619fd5c1ef
32 changed files with 3803 additions and 1325 deletions

View File

@@ -55,6 +55,8 @@ interface WorkspaceContextType {
permissions: Permission[];
hasPermission: (key: PermissionKey, projectId?: string) => boolean;
isAdmin: boolean;
// Check if user is admin in a specific workspace
isWorkspaceAdmin: (workspaceId: string) => Promise<boolean>;
// Loading states
isLoading: boolean;
@@ -64,7 +66,7 @@ interface WorkspaceContextType {
// Actions
refreshWorkspaces: () => Promise<Workspace[]>;
refreshProjects: () => Promise<void>;
createWorkspace: (name: string) => Promise<Workspace>;
createWorkspace: (name: string, avatarFile?: File | null) => Promise<Workspace>;
}
const WorkspaceContext = createContext<WorkspaceContextType | undefined>(
@@ -406,12 +408,49 @@ export const WorkspaceProvider: React.FC<WorkspaceProviderProps> = ({
}
}, [projects, saveSelectedProjects]);
// ============================================================================
// Check if user is admin in a specific workspace
// ============================================================================
const isWorkspaceAdmin = useCallback(async (workspaceId: string): Promise<boolean> => {
// Demo mode - user is admin
if (isDemoMode || workspaceId === DEMO_WORKSPACE_ID) {
return true;
}
// Check if this is the current workspace
if (currentWorkspace?.id === workspaceId) {
return isAdmin;
}
// Load permissions for the target workspace
try {
const me = await authApi.me();
const membersResponse = await membersApi.list(workspaceId, { size: 100 });
const member = membersResponse.items.find((m) => m.user.id === me.id);
if (!member) {
// Check if user is creator (members list is empty or this is first member)
if (membersResponse.items.length === 0) {
return true;
}
return false;
}
// Check if has admin_full permission
return member.permissions.some((p) => p.key === "admin_full");
} catch (err) {
console.error("Failed to check workspace permissions:", err);
return false;
}
}, [currentWorkspace, isAdmin, isDemoMode]);
// ============================================================================
// Create Workspace
// ============================================================================
const createWorkspace = useCallback(async (name: string): Promise<Workspace> => {
const workspace = await workspacesApi.create({ name });
const createWorkspace = useCallback(async (name: string, avatarFile?: File | null): Promise<Workspace> => {
const workspace = await workspacesApi.create({ name, avatar_file: avatarFile });
setWorkspaces((prev) => [...prev, workspace]);
return workspace;
}, []);
@@ -462,6 +501,7 @@ export const WorkspaceProvider: React.FC<WorkspaceProviderProps> = ({
permissions,
hasPermission,
isAdmin,
isWorkspaceAdmin,
// Loading states
isLoading,