/ frontend / src / app / components / QuickActionFab.jsx
QuickActionFab.jsx
 1  import { useMemo } from "react";
 2  import { SpeedDial, SpeedDialAction, SpeedDialIcon, styled, useMediaQuery, useTheme } from "@mui/material";
 3  import {
 4    Assignment, Psychology, Hub, Person, Groups,
 5  } from "@mui/icons-material";
 6  import { useNavigate } from "react-router-dom";
 7  import useAuth from "app/hooks/useAuth";
 8  
 9  const StyledSpeedDial = styled(SpeedDial)(({ theme }) => ({
10    position: "fixed",
11    bottom: theme.spacing(3),
12    right: theme.spacing(3),
13    zIndex: theme.zIndex.speedDial,
14    "& .MuiFab-primary": {
15      width: 56,
16      height: 56,
17      boxShadow: "0 8px 24px -6px rgba(99,102,241,0.45)",
18    },
19    "& .MuiSpeedDialAction-staticTooltipLabel": {
20      width: 150,
21      maxWidth: "none",
22      textAlign: "center",
23      whiteSpace: "nowrap",
24      fontWeight: 500,
25    },
26  }));
27  
28  export default function QuickActionFab() {
29    const { user } = useAuth();
30    const navigate = useNavigate();
31    const theme = useTheme();
32    const isMobile = useMediaQuery(theme.breakpoints.down("sm"));
33  
34    const actions = useMemo(() => {
35      if (!user || user.is_restricted) return [];
36      const items = [
37        { icon: <Assignment />, name: "New Project", path: "/projects/new" },
38      ];
39      if (user.is_admin) {
40        items.push(
41          { icon: <Psychology />, name: "New LLM", path: "/llms/new" },
42          { icon: <Hub />, name: "New Embedding", path: "/embeddings/new" },
43          { icon: <Person />, name: "New User", path: "/users/new" },
44          { icon: <Groups />, name: "New Team", path: "/teams/new" },
45        );
46      }
47      return items;
48    }, [user]);
49  
50    if (actions.length === 0 || isMobile) return null;
51  
52    // If there's only one action, clicking the FAB goes directly to it
53    if (actions.length === 1) {
54      return (
55        <StyledSpeedDial
56          ariaLabel="Quick create"
57          icon={<SpeedDialIcon />}
58          onClick={() => navigate(actions[0].path)}
59          open={false}
60        />
61      );
62    }
63  
64    return (
65      <StyledSpeedDial
66        ariaLabel="Quick create"
67        icon={<SpeedDialIcon />}
68        FabProps={{ color: "primary" }}
69      >
70        {actions.map((action) => (
71          <SpeedDialAction
72            key={action.name}
73            icon={action.icon}
74            tooltipTitle={action.name}
75            tooltipOpen
76            onClick={() => navigate(action.path)}
77          />
78        ))}
79      </StyledSpeedDial>
80    );
81  }