mirror of
https://github.com/cssgunc/compass.git
synced 2025-04-28 05:49:49 -04:00
Delete Button and Update QoL changes (#60)
* Edit visibility for options depending on administrator status * Connect delete frontend route to delete backend * small readme.md changes * Fix table lines and update bug * Add clicking outside of drawer to close
This commit is contained in:
parent
bdc6600a3f
commit
469236cb04
|
@ -60,12 +60,12 @@ def update(
|
|||
return resource_svc.update(subject, resource)
|
||||
|
||||
|
||||
@api.delete("", response_model=None, tags=["Resource"])
|
||||
@api.delete("", response_model=dict, tags=["Resource"])
|
||||
def delete(
|
||||
uuid: str,
|
||||
resource: Resource,
|
||||
id: int,
|
||||
user_svc: UserService = Depends(),
|
||||
resource_svc: ResourceService = Depends(),
|
||||
):
|
||||
subject = user_svc.get_user_by_uuid(uuid)
|
||||
resource_svc.delete(subject, resource)
|
||||
return resource_svc.delete(subject, id)
|
||||
|
|
|
@ -19,7 +19,10 @@ openapi_tags = {
|
|||
# TODO: Create custom exceptions
|
||||
@api.post("", response_model=Service, tags=["Service"])
|
||||
def create(
|
||||
uuid: str, service: Service, user_svc: UserService = Depends(), service_svc: ServiceService = Depends()
|
||||
uuid: str,
|
||||
service: Service,
|
||||
user_svc: UserService = Depends(),
|
||||
service_svc: ServiceService = Depends(),
|
||||
):
|
||||
subject = user_svc.get_user_by_uuid(uuid)
|
||||
return service_svc.create(subject, service)
|
||||
|
@ -27,28 +30,42 @@ def create(
|
|||
|
||||
@api.get("", response_model=List[Service], tags=["Service"])
|
||||
def get_all(
|
||||
uuid: str, user_svc: UserService = Depends(), service_svc: ServiceService = Depends()
|
||||
uuid: str,
|
||||
user_svc: UserService = Depends(),
|
||||
service_svc: ServiceService = Depends(),
|
||||
):
|
||||
subject = user_svc.get_user_by_uuid(uuid)
|
||||
return service_svc.get_service_by_user(subject)
|
||||
|
||||
|
||||
@api.get("/{name}", response_model=Service, tags=["Service"])
|
||||
def get_by_name(
|
||||
name: str, uuid: str, user_svc: UserService = Depends(), service_svc: ServiceService = Depends()
|
||||
name: str,
|
||||
uuid: str,
|
||||
user_svc: UserService = Depends(),
|
||||
service_svc: ServiceService = Depends(),
|
||||
):
|
||||
subject = user_svc.get_user_by_uuid(uuid)
|
||||
return service_svc.get_service_by_name(name, subject)
|
||||
|
||||
|
||||
@api.put("", response_model=Service, tags=["Service"])
|
||||
def update(
|
||||
uuid: str, service: Service, user_svc: UserService = Depends(), service_svc: ServiceService = Depends()
|
||||
uuid: str,
|
||||
service: Service,
|
||||
user_svc: UserService = Depends(),
|
||||
service_svc: ServiceService = Depends(),
|
||||
):
|
||||
subject = user_svc.get_user_by_uuid(uuid)
|
||||
return service_svc.update(subject, service)
|
||||
|
||||
@api.delete("", response_model=None, tags=["Service"])
|
||||
|
||||
@api.delete("", response_model=dict, tags=["Service"])
|
||||
def delete(
|
||||
uuid: str, service: Service, user_svc: UserService = Depends(), service_svc: ServiceService = Depends()
|
||||
uuid: str,
|
||||
id: int,
|
||||
user_svc: UserService = Depends(),
|
||||
service_svc: ServiceService = Depends(),
|
||||
):
|
||||
subject = user_svc.get_user_by_uuid(uuid)
|
||||
service_svc.delete(subject, service)
|
||||
return service_svc.delete(subject, id)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from fastapi import APIRouter, Depends
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from ..services import UserService
|
||||
from ..models.user_model import User, UserTypeEnum
|
||||
|
||||
|
@ -46,3 +46,14 @@ def update_user(uuid: str, user: User, user_svc: UserService = Depends()):
|
|||
raise Exception(f"Insufficient permissions for user {subject.uuid}")
|
||||
|
||||
return user_svc.update(user)
|
||||
|
||||
|
||||
@api.delete("/", response_model=dict, tags=["Users"])
|
||||
def delete_user(uuid: str, id: int, user_svc: UserService = Depends()):
|
||||
subject = user_svc.get_user_by_uuid(uuid)
|
||||
|
||||
try:
|
||||
user_svc.delete_by_id(id, subject)
|
||||
return {"message": "User deleted successfully"}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
|
|
|
@ -93,7 +93,7 @@ class ResourceService:
|
|||
self._session.commit()
|
||||
return entity.to_model()
|
||||
|
||||
def delete(self, subject: User, resource: Resource) -> None:
|
||||
def delete(self, subject: User, id: int) -> None:
|
||||
"""
|
||||
Delete resource based on id that the user has access to
|
||||
Parameters:
|
||||
|
@ -106,15 +106,16 @@ class ResourceService:
|
|||
raise ProgramNotAssignedException(
|
||||
f"User is not {UserTypeEnum.ADMIN}, cannot update service"
|
||||
)
|
||||
query = select(ResourceEntity).where(ResourceEntity.id == resource.id)
|
||||
|
||||
query = select(ResourceEntity).where(ResourceEntity.id == id)
|
||||
entity = self._session.scalars(query).one_or_none()
|
||||
if entity is None:
|
||||
raise ResourceNotFoundException(
|
||||
f"No resource found with matching id: {resource.id}"
|
||||
)
|
||||
raise ResourceNotFoundException(f"No resource found with matching id: {id}")
|
||||
self._session.delete(entity)
|
||||
self._session.commit()
|
||||
|
||||
return {"message": "Resource deleted successfully"}
|
||||
|
||||
def get_by_slug(self, user: User, search_string: str) -> list[Resource]:
|
||||
"""
|
||||
Get a list of resources given a search string that the user has access to
|
||||
|
|
|
@ -90,12 +90,12 @@ class ServiceService:
|
|||
|
||||
return entity.to_model()
|
||||
|
||||
def delete(self, subject: User, service: Service) -> None:
|
||||
def delete(self, subject: User, id: int) -> None:
|
||||
"""Deletes a service from the table."""
|
||||
if subject.role != UserTypeEnum.ADMIN:
|
||||
raise ProgramNotAssignedException(f"User is not {UserTypeEnum.ADMIN}")
|
||||
|
||||
query = select(ServiceEntity).where(ServiceEntity.id == service.id)
|
||||
query = select(ServiceEntity).where(ServiceEntity.id == id)
|
||||
entity = self._session.scalars(query).one_or_none()
|
||||
|
||||
if entity is None:
|
||||
|
@ -105,3 +105,5 @@ class ServiceService:
|
|||
|
||||
self._session.delete(entity)
|
||||
self._session.commit()
|
||||
|
||||
return {"message": "Service deleted successfully"}
|
||||
|
|
|
@ -4,6 +4,7 @@ from sqlalchemy.orm import Session
|
|||
from ..entities.user_entity import UserEntity
|
||||
from ..models.user_model import User
|
||||
from sqlalchemy import select
|
||||
from ..models.enum_for_models import UserTypeEnum
|
||||
|
||||
|
||||
class UserService:
|
||||
|
@ -89,6 +90,22 @@ class UserService:
|
|||
self._session.delete(obj)
|
||||
self._session.commit()
|
||||
|
||||
def delete_by_id(self, id: int, user: User) -> None:
|
||||
"""
|
||||
Delete a user by id
|
||||
|
||||
Args: the id of the user to delete
|
||||
|
||||
Returns: none
|
||||
"""
|
||||
|
||||
if user.role != UserTypeEnum.ADMIN:
|
||||
raise Exception(f"Insufficient permissions for user {user.uuid}")
|
||||
|
||||
obj = self._session.get(UserEntity, id)
|
||||
self._session.delete(obj)
|
||||
self._session.commit()
|
||||
|
||||
def update(self, user: User) -> User:
|
||||
"""
|
||||
Updates a user
|
||||
|
|
39
compass/app/api/resource/delete/route.ts
Normal file
39
compass/app/api/resource/delete/route.ts
Normal file
|
@ -0,0 +1,39 @@
|
|||
import { NextResponse } from "next/server";
|
||||
|
||||
export async function DELETE(request: Request) {
|
||||
const apiEndpoint = `${process.env.NEXT_PUBLIC_API_HOST}/api/resource`;
|
||||
|
||||
try {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const uuid = searchParams.get("uuid");
|
||||
const resource_id = searchParams.get("id");
|
||||
|
||||
console.log("Resource to be deleted", resource_id);
|
||||
|
||||
// Send the POST request to the backend
|
||||
const response = await fetch(
|
||||
`${apiEndpoint}?uuid=${uuid}&id=${resource_id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
return NextResponse.json(
|
||||
{ message: "Resource deleted successfully" },
|
||||
{ status: response.status }
|
||||
);
|
||||
} catch (error) {
|
||||
console.error("Error deleting resource:", error);
|
||||
return NextResponse.json(
|
||||
{ error: "Failed to delete resource" },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
39
compass/app/api/service/delete/route.ts
Normal file
39
compass/app/api/service/delete/route.ts
Normal file
|
@ -0,0 +1,39 @@
|
|||
import { NextResponse } from "next/server";
|
||||
|
||||
export async function DELETE(request: Request) {
|
||||
const apiEndpoint = `${process.env.NEXT_PUBLIC_API_HOST}/api/service`;
|
||||
|
||||
try {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const uuid = searchParams.get("uuid");
|
||||
const service_id = searchParams.get("id");
|
||||
|
||||
console.log("Service to be deleted", service_id);
|
||||
|
||||
// Send the POST request to the backend
|
||||
const response = await fetch(
|
||||
`${apiEndpoint}?uuid=${uuid}&id=${service_id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
return NextResponse.json(
|
||||
{ message: "Service deleted successfully" },
|
||||
{ status: response.status }
|
||||
);
|
||||
} catch (error) {
|
||||
console.error("Error deleting service:", error);
|
||||
return NextResponse.json(
|
||||
{ error: "Failed to delete service" },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
39
compass/app/api/user/delete/route.ts
Normal file
39
compass/app/api/user/delete/route.ts
Normal file
|
@ -0,0 +1,39 @@
|
|||
import { NextResponse } from "next/server";
|
||||
|
||||
export async function DELETE(request: Request) {
|
||||
const apiEndpoint = `${process.env.NEXT_PUBLIC_API_HOST}/api/user`;
|
||||
|
||||
try {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const uuid = searchParams.get("uuid");
|
||||
const user_id = searchParams.get("id");
|
||||
|
||||
console.log("User to be deleted", user_id);
|
||||
|
||||
// Send the POST request to the backend
|
||||
const response = await fetch(
|
||||
`${apiEndpoint}?uuid=${uuid}&id=${user_id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
return NextResponse.json(
|
||||
{ message: "User deleted successfully" },
|
||||
{ status: response.status }
|
||||
);
|
||||
} catch (error) {
|
||||
console.error("Error deleting user:", error);
|
||||
return NextResponse.json(
|
||||
{ error: "Failed to delete user" },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
import { Dispatch, FunctionComponent, ReactNode, SetStateAction } from "react";
|
||||
import { Dispatch, FunctionComponent, ReactNode, SetStateAction, useEffect, useRef } from "react";
|
||||
import React, { useState } from "react";
|
||||
import { ChevronDoubleLeftIcon } from "@heroicons/react/24/solid";
|
||||
import { StarIcon as SolidStarIcon, UserIcon } from "@heroicons/react/24/solid";
|
||||
|
@ -47,6 +47,47 @@ const Drawer: FunctionComponent<DrawerProps> = ({
|
|||
const [isFull, setIsFull] = useState(false);
|
||||
const [isFavorite, setIsFavorite] = useState(false);
|
||||
const [tempRowContent, setTempRowContent] = useState(rowContent);
|
||||
const drawerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
if (drawerRef.current && !drawerRef.current.contains(event.target as Node)) {
|
||||
if (setRowContent && isOpen) {
|
||||
// Check if any values have changed
|
||||
const hasChanges = Object.keys(tempRowContent).some(
|
||||
(key) => tempRowContent[key] !== rowContent[key]
|
||||
);
|
||||
|
||||
if (hasChanges) {
|
||||
handleUpdate().then((response) => {
|
||||
if (response.ok) {
|
||||
setRowContent((prev: any) => {
|
||||
return prev.map((row: any) => {
|
||||
if (row.id === tempRowContent.id) {
|
||||
return tempRowContent;
|
||||
}
|
||||
return row;
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
setIsOpen(false);
|
||||
if (isFull) {
|
||||
setIsFull(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (isOpen) {
|
||||
document.addEventListener('mousedown', handleClickOutside);
|
||||
}
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('mousedown', handleClickOutside);
|
||||
};
|
||||
}, [isOpen, tempRowContent, rowContent]);
|
||||
|
||||
const handleTempRowContentChangeHTML = (
|
||||
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
|
||||
|
@ -114,8 +155,7 @@ const Drawer: FunctionComponent<DrawerProps> = ({
|
|||
|
||||
const toggleFavorite = () => setIsFavorite(!isFavorite);
|
||||
|
||||
const drawerClassName = `fixed top-0 right-0 w-1/2 h-full bg-white transform ease-in-out duration-300 z-20 ${
|
||||
isOpen ? "translate-x-0 shadow-xl" : "translate-x-full"
|
||||
const drawerClassName = `fixed top-0 right-0 w-1/2 h-full bg-white transform ease-in-out duration-300 z-20 ${isOpen ? "translate-x-0 shadow-xl" : "translate-x-full"
|
||||
} ${isFull ? "w-full" : "w-1/2"}`;
|
||||
|
||||
const iconComponent = isFull ? (
|
||||
|
@ -140,7 +180,7 @@ const Drawer: FunctionComponent<DrawerProps> = ({
|
|||
>
|
||||
Open
|
||||
</button>
|
||||
<div className={drawerClassName}>
|
||||
<div ref={drawerRef} className={drawerClassName}>
|
||||
<div className="flex items-center justify-between p-4">
|
||||
<div className="flex flex-row items-center justify-between space-x-2">
|
||||
<span className="h-5 text-purple-200 w-5">
|
||||
|
|
|
@ -143,6 +143,7 @@ export default function ResourceTable({
|
|||
columns={columns}
|
||||
details={resourceDetails}
|
||||
createEndpoint={`/api/resource/create?uuid=${user?.uuid}`}
|
||||
deleteEndpoint={`/api/resource/delete?uuid=${user?.uuid}`}
|
||||
isAdmin={user?.role === "ADMIN"}
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -27,7 +27,7 @@ export function RowOpenAction<T extends DataPoint>({
|
|||
updateRoute,
|
||||
}: RowOpenActionProps<T>) {
|
||||
return (
|
||||
<div className="font-semibold group flex flex-row items-center justify-between pr-2">
|
||||
<div className="font-semibold group flex flex-row items-center justify-between px-2">
|
||||
{title}
|
||||
<span>
|
||||
<Drawer
|
||||
|
|
|
@ -5,41 +5,78 @@ import {
|
|||
ArrowUpRightIcon,
|
||||
EllipsisVerticalIcon,
|
||||
EyeSlashIcon,
|
||||
EyeIcon,
|
||||
} from "@heroicons/react/24/solid";
|
||||
import Button from "../Button";
|
||||
import { useState, useEffect, useRef } from "react";
|
||||
import { RowOption } from "./RowOption";
|
||||
|
||||
export const RowOptionMenu = ({ onDelete, onHide }) => {
|
||||
const [menuOpen, setMenuOpen] = useState(false);
|
||||
const openMenu = () => setMenuOpen(true);
|
||||
const closeMenu = () => setMenuOpen(false);
|
||||
interface RowOptionMenuProps {
|
||||
onDelete: () => void;
|
||||
onHide: () => void;
|
||||
visible: boolean;
|
||||
}
|
||||
|
||||
// TODO: Hide menu if clicked elsewhere
|
||||
export const RowOptionMenu = ({
|
||||
onDelete,
|
||||
onHide,
|
||||
visible,
|
||||
}: RowOptionMenuProps) => {
|
||||
const [menuOpen, setMenuOpen] = useState(false);
|
||||
const menuRef = useRef<HTMLDivElement>(null);
|
||||
const buttonRef = useRef<HTMLButtonElement>(null);
|
||||
|
||||
const handleDelete = () => {
|
||||
if (window.confirm("Are you sure you want to delete this item?")) {
|
||||
onDelete();
|
||||
setMenuOpen(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
if (
|
||||
menuRef.current &&
|
||||
buttonRef.current &&
|
||||
!menuRef.current.contains(event.target as Node) &&
|
||||
!buttonRef.current.contains(event.target as Node)
|
||||
) {
|
||||
setMenuOpen(false);
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener("mousedown", handleClickOutside);
|
||||
return () => {
|
||||
document.removeEventListener("mousedown", handleClickOutside);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
ref={buttonRef}
|
||||
className="items-end"
|
||||
onClick={() => setMenuOpen(!menuOpen)}
|
||||
>
|
||||
<EllipsisVerticalIcon className="h-4" />
|
||||
</button>
|
||||
<div
|
||||
ref={menuRef}
|
||||
className={
|
||||
"justify-start border border-gray-200 shadow-lg flex flex-col absolute bg-white w-auto p-2 rounded [&>*]:rounded z-10" +
|
||||
(!menuOpen ? " invisible" : "")
|
||||
}
|
||||
>
|
||||
<RowOption icon={TrashIcon} label="Delete" onClick={onDelete} />
|
||||
<RowOption
|
||||
icon={ArrowUpRightIcon}
|
||||
label="Open"
|
||||
onClick={() => {
|
||||
/* handle open */
|
||||
}}
|
||||
icon={TrashIcon}
|
||||
label="Delete"
|
||||
onClick={handleDelete}
|
||||
/>
|
||||
<RowOption
|
||||
icon={visible ? EyeSlashIcon : EyeIcon}
|
||||
label={visible ? "Hide" : "Show"}
|
||||
onClick={onHide}
|
||||
/>
|
||||
<RowOption icon={EyeSlashIcon} label="Hide" onClick={onHide} />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -195,6 +195,7 @@ export default function ServiceTable({
|
|||
columns={columns}
|
||||
details={serviceDetails}
|
||||
createEndpoint={`/api/service/create?uuid=${user?.uuid}`}
|
||||
deleteEndpoint={`/api/service/delete?uuid=${user?.uuid}`}
|
||||
isAdmin={user?.role === "ADMIN"}
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -28,6 +28,7 @@ type TableProps<T extends DataPoint> = {
|
|||
columns: ColumnDef<T, any>[];
|
||||
details: Details[];
|
||||
createEndpoint: string;
|
||||
deleteEndpoint: string;
|
||||
isAdmin?: boolean;
|
||||
};
|
||||
|
||||
|
@ -79,12 +80,24 @@ export default function Table<T extends DataPoint>({
|
|||
columns,
|
||||
details,
|
||||
createEndpoint,
|
||||
deleteEndpoint,
|
||||
isAdmin = false,
|
||||
}: TableProps<T>) {
|
||||
console.log(data);
|
||||
const offset = isAdmin ? 1 : 0;
|
||||
|
||||
const columnHelper = createColumnHelper<T>();
|
||||
|
||||
const deleteRow = async (id: number) => {
|
||||
const response = await fetch(`${deleteEndpoint}&id=${id}`, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
return response.ok;
|
||||
};
|
||||
|
||||
const createRow = async (newItem: any) => {
|
||||
const response = await fetch(createEndpoint, {
|
||||
method: "POST",
|
||||
|
@ -97,9 +110,9 @@ export default function Table<T extends DataPoint>({
|
|||
return response;
|
||||
};
|
||||
|
||||
// /** Sorting function based on visibility */
|
||||
// const visibilitySort = (a: T, b: T) =>
|
||||
// a.visible === b.visible ? 0 : a.visible ? -1 : 1;
|
||||
/** Sorting function based on visibility */
|
||||
const visibilitySort = (a: T, b: T) =>
|
||||
a.visible === b.visible ? 0 : a.visible ? -1 : 1;
|
||||
|
||||
// // Sort data on load
|
||||
// useEffect(() => {
|
||||
|
@ -115,36 +128,59 @@ export default function Table<T extends DataPoint>({
|
|||
// );
|
||||
// };
|
||||
|
||||
// const hideData = (dataId: number) => {
|
||||
// console.log(`Toggling visibility for data with ID: ${dataId}`);
|
||||
// setData((currentData) => {
|
||||
// const newData = currentData
|
||||
// .map((data) =>
|
||||
// data.id === dataId
|
||||
// ? { ...data, visible: !data.visible }
|
||||
// : data
|
||||
// )
|
||||
// .sort(visibilitySort);
|
||||
const hideData = (dataId: number) => {
|
||||
console.log(`Toggling visibility for data with ID: ${dataId}`);
|
||||
setData((currentData) => {
|
||||
const newData = currentData
|
||||
.map((data) =>
|
||||
data.id === dataId
|
||||
? { ...data, visible: !data.visible }
|
||||
: data
|
||||
)
|
||||
.sort((a, b) => {
|
||||
// First sort by visibility
|
||||
const visibilityResult = visibilitySort(a, b);
|
||||
if (visibilityResult !== 0) return visibilityResult;
|
||||
// Then sort by id
|
||||
return a.id - b.id;
|
||||
});
|
||||
|
||||
// console.log(newData);
|
||||
// return newData;
|
||||
// });
|
||||
// };
|
||||
console.log(newData);
|
||||
return newData;
|
||||
});
|
||||
};
|
||||
|
||||
// Add data manipulation options to the first column
|
||||
if (isAdmin) {
|
||||
columns.unshift(
|
||||
columnHelper.display({
|
||||
id: "options",
|
||||
cell: (props) => (
|
||||
<RowOptionMenu
|
||||
onDelete={() => {}}
|
||||
onHide={() => {}}
|
||||
// onDelete={() => deleteData(props.row.original.id)}
|
||||
// onHide={() => hideData(props.row.original.id)}
|
||||
onDelete={() => {
|
||||
deleteRow(props.row.original.id).then(
|
||||
(response) => {
|
||||
if (response) {
|
||||
setData((prev) =>
|
||||
prev.filter(
|
||||
(data) =>
|
||||
data.id !==
|
||||
props.row.original.id
|
||||
)
|
||||
);
|
||||
} else {
|
||||
alert("Failed to delete row!");
|
||||
}
|
||||
}
|
||||
);
|
||||
}}
|
||||
onHide={() => hideData(props.row.original.id)}
|
||||
visible={props.row.original.visible}
|
||||
/>
|
||||
),
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// Searching
|
||||
const [query, setQuery] = useState("");
|
||||
|
@ -186,7 +222,7 @@ export default function Table<T extends DataPoint>({
|
|||
scope="col"
|
||||
className={
|
||||
"p-2 border-gray-200 border-y font-medium " +
|
||||
(1 < i && i < columns.length - 1
|
||||
(0 + offset < i && i < columns.length - 1
|
||||
? "border-x"
|
||||
: "")
|
||||
}
|
||||
|
@ -207,8 +243,7 @@ export default function Table<T extends DataPoint>({
|
|||
{table.getRowModel().rows.map((row) => {
|
||||
// Individual row
|
||||
const isDataVisible = row.original.visible;
|
||||
const rowClassNames = `text-gray-800 border-y lowercase hover:bg-gray-50 ${
|
||||
!isDataVisible ? "bg-gray-200 text-gray-500" : ""
|
||||
const rowClassNames = `text-gray-800 border-y lowercase hover:bg-gray-50 ${!isDataVisible ? "bg-gray-200 text-gray-500" : ""
|
||||
}`;
|
||||
return (
|
||||
<tr className={rowClassNames} key={row.id}>
|
||||
|
@ -216,7 +251,7 @@ export default function Table<T extends DataPoint>({
|
|||
<td
|
||||
key={cell.id}
|
||||
className={
|
||||
"[&:nth-child(n+3)]:border-x relative first:text-left first:px-0 last:border-none"
|
||||
`[&:nth-child(n+${2 + offset})]:border-x relative first:text-left first:px-0 last:border-none`
|
||||
}
|
||||
>
|
||||
{flexRender(
|
||||
|
@ -248,10 +283,13 @@ export default function Table<T extends DataPoint>({
|
|||
createRow(newItem).then((response) => {
|
||||
if (response.ok) {
|
||||
newItem.visible = true;
|
||||
response.json().then((data) => {
|
||||
newItem.id = data.id;
|
||||
setData((prev) => [
|
||||
...prev,
|
||||
newItem,
|
||||
]);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -143,6 +143,7 @@ export default function UserTable({ data, setData, user }: UserTableProps) {
|
|||
columns={columns}
|
||||
details={userDetails}
|
||||
createEndpoint={`/api/user/create?uuid=${user?.uuid}`}
|
||||
deleteEndpoint={`/api/user/delete?uuid=${user?.uuid}`}
|
||||
isAdmin={user?.role === "ADMIN"}
|
||||
/>
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue
Block a user