Feat[DropdownButtonComponent]: Create Dropdown Button component
This commit is contained in:
parent
02cc23d6b1
commit
d6f9124405
8 changed files with 310 additions and 251 deletions
|
|
@ -43,7 +43,9 @@ def add_user(
|
||||||
db.refresh(new_user)
|
db.refresh(new_user)
|
||||||
except IntegrityError as e:
|
except IntegrityError as e:
|
||||||
db.rollback()
|
db.rollback()
|
||||||
raise HTTPException(status_code=400, detail="This username is unavailable.") from e
|
raise HTTPException(
|
||||||
|
status_code=400, detail="This username is unavailable."
|
||||||
|
) from e
|
||||||
|
|
||||||
return new_user
|
return new_user
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
import { useState } from "react";
|
||||||
|
import IconComponent from "../genericIconComponent";
|
||||||
|
import { Button } from "../ui/button";
|
||||||
|
|
||||||
|
export default function DropdownButton({
|
||||||
|
firstButtonName,
|
||||||
|
onFirstBtnClick,
|
||||||
|
options,
|
||||||
|
}): JSX.Element {
|
||||||
|
const [showOptions, setShowOptions] = useState(false);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="align-center relative flex">
|
||||||
|
<div>
|
||||||
|
<Button
|
||||||
|
variant="primary"
|
||||||
|
className="mr-4 w-full"
|
||||||
|
onClick={onFirstBtnClick}
|
||||||
|
>
|
||||||
|
{firstButtonName}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
className="absolute inset-y-0 right-0 items-center text-muted-foreground"
|
||||||
|
onClick={(event) => {
|
||||||
|
event.stopPropagation();
|
||||||
|
setShowOptions(!showOptions);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{!showOptions ? (
|
||||||
|
<IconComponent name="ChevronDown" className="" aria-hidden="true" />
|
||||||
|
) : (
|
||||||
|
<IconComponent name="ChevronUp" />
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{showOptions && (
|
||||||
|
<div className="absolute top-10 w-full">
|
||||||
|
{options.map((optionName) => (
|
||||||
|
<Button className="w-full" variant="primary">
|
||||||
|
{optionName}
|
||||||
|
</Button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -37,7 +37,7 @@ export default function Header(): JSX.Element {
|
||||||
logout();
|
logout();
|
||||||
navigate("/login");
|
navigate("/login");
|
||||||
}}
|
}}
|
||||||
className="text-sm font-medium text-muted-foreground transition-colors hover:text-primary cursor-pointer mx-5"
|
className="mx-5 cursor-pointer text-sm font-medium text-muted-foreground transition-colors hover:text-primary"
|
||||||
>
|
>
|
||||||
Sign out
|
Sign out
|
||||||
</a>
|
</a>
|
||||||
|
|
@ -48,7 +48,7 @@ export default function Header(): JSX.Element {
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
navigate("/");
|
navigate("/");
|
||||||
}}
|
}}
|
||||||
className="text-sm font-medium text-muted-foreground transition-colors hover:text-primary cursor-pointer"
|
className="cursor-pointer text-sm font-medium text-muted-foreground transition-colors hover:text-primary"
|
||||||
>
|
>
|
||||||
Home
|
Home
|
||||||
</a>
|
</a>
|
||||||
|
|
@ -59,7 +59,7 @@ export default function Header(): JSX.Element {
|
||||||
location.pathname !== "/admin" &&
|
location.pathname !== "/admin" &&
|
||||||
location.pathname !== `/flow/${tabId}` && (
|
location.pathname !== `/flow/${tabId}` && (
|
||||||
<a
|
<a
|
||||||
className="text-sm font-medium text-muted-foreground transition-colors hover:text-primary cursor-pointer"
|
className="cursor-pointer text-sm font-medium text-muted-foreground transition-colors hover:text-primary"
|
||||||
onClick={() => navigate("/admin")}
|
onClick={() => navigate("/admin")}
|
||||||
>
|
>
|
||||||
Admin page
|
Admin page
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import { useContext, useEffect, useRef, useState } from "react";
|
||||||
import PaginatorComponent from "../../components/PaginatorComponent";
|
import PaginatorComponent from "../../components/PaginatorComponent";
|
||||||
import ShadTooltip from "../../components/ShadTooltipComponent";
|
import ShadTooltip from "../../components/ShadTooltipComponent";
|
||||||
import IconComponent from "../../components/genericIconComponent";
|
import IconComponent from "../../components/genericIconComponent";
|
||||||
|
import Header from "../../components/headerComponent";
|
||||||
import { Button } from "../../components/ui/button";
|
import { Button } from "../../components/ui/button";
|
||||||
import { Checkbox } from "../../components/ui/checkbox";
|
import { Checkbox } from "../../components/ui/checkbox";
|
||||||
import { Input } from "../../components/ui/input";
|
import { Input } from "../../components/ui/input";
|
||||||
|
|
@ -25,9 +26,8 @@ import {
|
||||||
} from "../../controllers/API";
|
} from "../../controllers/API";
|
||||||
import ConfirmationModal from "../../modals/ConfirmationModal";
|
import ConfirmationModal from "../../modals/ConfirmationModal";
|
||||||
import UserManagementModal from "../../modals/UserManagementModal";
|
import UserManagementModal from "../../modals/UserManagementModal";
|
||||||
import { UserInputType } from "../../types/components";
|
|
||||||
import Header from "../../components/headerComponent";
|
|
||||||
import { Users } from "../../types/api";
|
import { Users } from "../../types/api";
|
||||||
|
import { UserInputType } from "../../types/components";
|
||||||
|
|
||||||
export default function AdminPage() {
|
export default function AdminPage() {
|
||||||
const [inputValue, setInputValue] = useState("");
|
const [inputValue, setInputValue] = useState("");
|
||||||
|
|
@ -89,7 +89,7 @@ export default function AdminPage() {
|
||||||
if (input === "") {
|
if (input === "") {
|
||||||
setFilterUserList(userList.current);
|
setFilterUserList(userList.current);
|
||||||
} else {
|
} else {
|
||||||
const filteredList = userList.current.filter((user:Users) =>
|
const filteredList = userList.current.filter((user: Users) =>
|
||||||
user.username.toLowerCase().includes(input.toLowerCase())
|
user.username.toLowerCase().includes(input.toLowerCase())
|
||||||
);
|
);
|
||||||
setFilterUserList(filteredList);
|
setFilterUserList(filteredList);
|
||||||
|
|
@ -280,7 +280,8 @@ export default function AdminPage() {
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
{!loadingUsers && (
|
{!loadingUsers && (
|
||||||
<TableBody>
|
<TableBody>
|
||||||
{filterUserList.map((user:UserInputType, index) => (
|
{filterUserList.map(
|
||||||
|
(user: UserInputType, index) => (
|
||||||
<TableRow key={index}>
|
<TableRow key={index}>
|
||||||
<TableCell className="truncate py-2 font-medium">
|
<TableCell className="truncate py-2 font-medium">
|
||||||
<ShadTooltip content={user.id}>
|
<ShadTooltip content={user.id}>
|
||||||
|
|
@ -396,7 +397,10 @@ export default function AdminPage() {
|
||||||
handleDeleteUser(user);
|
handleDeleteUser(user);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ShadTooltip content="Delete" side="top">
|
<ShadTooltip
|
||||||
|
content="Delete"
|
||||||
|
side="top"
|
||||||
|
>
|
||||||
<IconComponent
|
<IconComponent
|
||||||
name="Trash2"
|
name="Trash2"
|
||||||
className="ml-2 h-4 w-4 cursor-pointer"
|
className="ml-2 h-4 w-4 cursor-pointer"
|
||||||
|
|
@ -406,7 +410,8 @@ export default function AdminPage() {
|
||||||
</div>
|
</div>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
))}
|
)
|
||||||
|
)}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
)}
|
)}
|
||||||
</Table>
|
</Table>
|
||||||
|
|
|
||||||
|
|
@ -421,7 +421,7 @@ export default function Page({
|
||||||
zoomOnScroll={!view}
|
zoomOnScroll={!view}
|
||||||
zoomOnPinch={!view}
|
zoomOnPinch={!view}
|
||||||
panOnDrag={!view}
|
panOnDrag={!view}
|
||||||
proOptions={{hideAttribution: true}}
|
proOptions={{ hideAttribution: true }}
|
||||||
>
|
>
|
||||||
<Background className="" />
|
<Background className="" />
|
||||||
{!view && (
|
{!view && (
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,8 @@ export default function LoginPage(): JSX.Element {
|
||||||
useState<loginInputStateType>(CONTROL_LOGIN_STATE);
|
useState<loginInputStateType>(CONTROL_LOGIN_STATE);
|
||||||
|
|
||||||
const { password, username } = inputState;
|
const { password, username } = inputState;
|
||||||
const { login, getAuthentication, setUserData, setIsAdmin } = useContext(AuthContext);
|
const { login, getAuthentication, setUserData, setIsAdmin } =
|
||||||
|
useContext(AuthContext);
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { setErrorData } = useContext(alertContext);
|
const { setErrorData } = useContext(alertContext);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -268,7 +268,7 @@ export type UserInputType = {
|
||||||
is_superuser?: boolean;
|
is_superuser?: boolean;
|
||||||
id?: string;
|
id?: string;
|
||||||
create_at?: string;
|
create_at?: string;
|
||||||
updated_at?:string;
|
updated_at?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ApiKeyType = {
|
export type ApiKeyType = {
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import {
|
||||||
ChevronDown,
|
ChevronDown,
|
||||||
ChevronLeft,
|
ChevronLeft,
|
||||||
ChevronRight,
|
ChevronRight,
|
||||||
|
ChevronUp,
|
||||||
ChevronsLeft,
|
ChevronsLeft,
|
||||||
ChevronsRight,
|
ChevronsRight,
|
||||||
ChevronsUpDown,
|
ChevronsUpDown,
|
||||||
|
|
@ -300,4 +301,5 @@ export const nodeIconsLucide: iconsType = {
|
||||||
UserCog2,
|
UserCog2,
|
||||||
Key,
|
Key,
|
||||||
Unplug,
|
Unplug,
|
||||||
|
ChevronUp,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue