feat: api communication table
This commit is contained in:
parent
cba7c522c3
commit
dbcf6cab66
|
@ -0,0 +1,20 @@
|
||||||
|
import ToolsTable from "@/components/api-communication-table/tools-table";
|
||||||
|
import Breadcrumb from "@/components/breadcrumb";
|
||||||
|
import { dummyApiCommunications } from "@/constants/data";
|
||||||
|
import { ApiCommunication } from "@/types/api-communication";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
const breadcrumbItems = [
|
||||||
|
{ title: "Dashboard", link: "#" },
|
||||||
|
{ title: "Api Communication" },
|
||||||
|
];
|
||||||
|
const Page = () => {
|
||||||
|
return (
|
||||||
|
<div className="flex-1 space-y-4 p-4 md:p-8 pt-6">
|
||||||
|
<Breadcrumb items={breadcrumbItems} />
|
||||||
|
<ToolsTable apiCommunications={dummyApiCommunications as ApiCommunication[]} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Page;
|
|
@ -1,8 +1,7 @@
|
||||||
import Breadcrumb from "@/components/breadcrumb";
|
import Breadcrumb from "@/components/breadcrumb";
|
||||||
import ToolsTable from "@/components/organizations-table/tools-table";
|
import ToolsTable from "@/components/organizations-table/tools-table";
|
||||||
import { dummyOrganizations, dummyUsers } from "@/constants/data";
|
import { dummyOrganizations } from "@/constants/data";
|
||||||
import { Organization } from "@/types/organization";
|
import { Organization } from "@/types/organization";
|
||||||
import { User } from "@/types/user";
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
const breadcrumbItems = [
|
const breadcrumbItems = [
|
||||||
|
|
|
@ -3,38 +3,37 @@ import {
|
||||||
ChevronRightIcon,
|
ChevronRightIcon,
|
||||||
DoubleArrowLeftIcon,
|
DoubleArrowLeftIcon,
|
||||||
DoubleArrowRightIcon,
|
DoubleArrowRightIcon,
|
||||||
} from "@radix-ui/react-icons"
|
} from "@radix-ui/react-icons";
|
||||||
import { Table } from "@tanstack/react-table"
|
import { Table } from "@tanstack/react-table";
|
||||||
|
|
||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button";
|
||||||
import {
|
import {
|
||||||
Select,
|
Select,
|
||||||
SelectContent,
|
SelectContent,
|
||||||
SelectItem,
|
SelectItem,
|
||||||
SelectTrigger,
|
SelectTrigger,
|
||||||
SelectValue,
|
SelectValue,
|
||||||
} from "@/components/ui/select"
|
} from "@/components/ui/select";
|
||||||
|
|
||||||
interface DataTablePaginationProps<TData> {
|
interface DataTablePaginationProps<TData> {
|
||||||
table: Table<TData>
|
table: Table<TData>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function DataTablePagination<TData>({
|
export function DataTablePagination<TData>({
|
||||||
table,
|
table,
|
||||||
}: DataTablePaginationProps<TData>) {
|
}: DataTablePaginationProps<TData>) {
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center justify-between px-2">
|
<div className="grid grid-cols-2 md:grid-cols-[1fr_auto_auto] gap-x-6 gap-y-2">
|
||||||
<div className="flex-1 text-sm text-muted-foreground">
|
<div className="text-sm text-muted-foreground">
|
||||||
{table.getFilteredSelectedRowModel().rows.length} of{" "}
|
{table.getFilteredSelectedRowModel().rows.length} of{" "}
|
||||||
{table.getFilteredRowModel().rows.length} row(s) selected.
|
{table.getFilteredRowModel().rows.length} row(s) selected.
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center space-x-6 lg:space-x-8">
|
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<p className="text-sm font-medium hidden md:block">Rows per page</p>
|
<p className="text-sm font-medium">Rows per page</p>
|
||||||
<Select
|
<Select
|
||||||
value={`${table.getState().pagination.pageSize}`}
|
value={`${table.getState().pagination.pageSize}`}
|
||||||
onValueChange={(value) => {
|
onValueChange={(value) => {
|
||||||
table.setPageSize(Number(value))
|
table.setPageSize(Number(value));
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<SelectTrigger className="h-8 w-[70px]">
|
<SelectTrigger className="h-8 w-[70px]">
|
||||||
|
@ -49,14 +48,15 @@ import {
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex w-[100px] items-center justify-center text-sm font-medium">
|
<div className="flex items-center gap-2">
|
||||||
|
<div className="text-sm font-medium">
|
||||||
Page {table.getState().pagination.pageIndex + 1} of{" "}
|
Page {table.getState().pagination.pageIndex + 1} of{" "}
|
||||||
{table.getPageCount()}
|
{table.getPageCount()}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
className="hidden h-8 w-8 p-0 lg:flex"
|
className="h-8 w-8 p-0 flex"
|
||||||
onClick={() => table.setPageIndex(0)}
|
onClick={() => table.setPageIndex(0)}
|
||||||
disabled={!table.getCanPreviousPage()}
|
disabled={!table.getCanPreviousPage()}
|
||||||
>
|
>
|
||||||
|
@ -83,7 +83,7 @@ import {
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
className="hidden h-8 w-8 p-0 lg:flex"
|
className="h-8 w-8 p-0 flex"
|
||||||
onClick={() => table.setPageIndex(table.getPageCount() - 1)}
|
onClick={() => table.setPageIndex(table.getPageCount() - 1)}
|
||||||
disabled={!table.getCanNextPage()}
|
disabled={!table.getCanNextPage()}
|
||||||
>
|
>
|
||||||
|
@ -93,5 +93,5 @@ import {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
"use client";
|
||||||
|
import { AlertModal } from "@/components/alert-modal";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import {
|
||||||
|
DropdownMenu,
|
||||||
|
DropdownMenuContent,
|
||||||
|
DropdownMenuItem,
|
||||||
|
DropdownMenuLabel,
|
||||||
|
DropdownMenuTrigger,
|
||||||
|
} from "@/components/ui/dropdown-menu";
|
||||||
|
import { useToast } from "@/components/ui/use-toast";
|
||||||
|
import { ApiCommunication } from "@/types/api-communication";
|
||||||
|
|
||||||
|
import { Edit, MoreHorizontal, Trash } from "lucide-react";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
interface CellActionProps {
|
||||||
|
data: ApiCommunication;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CellAction: React.FC<CellActionProps> = ({ data }) => {
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
|
||||||
|
const router = useRouter();
|
||||||
|
const { toast } = useToast();
|
||||||
|
|
||||||
|
const onDeleteConfirm = async () => {};
|
||||||
|
|
||||||
|
const handleUpdateStatus = async () => {};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<AlertModal
|
||||||
|
isOpen={isDeleteModalOpen}
|
||||||
|
onClose={() => setIsDeleteModalOpen(false)}
|
||||||
|
onConfirm={onDeleteConfirm}
|
||||||
|
loading={loading}
|
||||||
|
/>
|
||||||
|
<DropdownMenu modal={false}>
|
||||||
|
<DropdownMenuTrigger asChild>
|
||||||
|
<Button variant="ghost" className="h-8 w-8 p-0">
|
||||||
|
<span className="sr-only">Open menu</span>
|
||||||
|
<MoreHorizontal className="h-4 w-4" />
|
||||||
|
</Button>
|
||||||
|
</DropdownMenuTrigger>
|
||||||
|
<DropdownMenuContent align="end">
|
||||||
|
<DropdownMenuLabel>Actions</DropdownMenuLabel>
|
||||||
|
|
||||||
|
<DropdownMenuItem
|
||||||
|
className="cursor-pointer"
|
||||||
|
// onClick={() =>
|
||||||
|
// router.push(`#`)
|
||||||
|
// }
|
||||||
|
>
|
||||||
|
<Edit className="mr-2 h-4 w-4" /> Update
|
||||||
|
</DropdownMenuItem>
|
||||||
|
<DropdownMenuItem
|
||||||
|
className="cursor-pointer"
|
||||||
|
onClick={() => setIsDeleteModalOpen(true)}
|
||||||
|
>
|
||||||
|
<Trash className="mr-2 h-4 w-4" /> Delete
|
||||||
|
</DropdownMenuItem>
|
||||||
|
</DropdownMenuContent>
|
||||||
|
</DropdownMenu>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,269 @@
|
||||||
|
"use client";
|
||||||
|
import { DataTableColumnHeader } from "./data-table-column-header";
|
||||||
|
import { CellAction } from "./cell-action";
|
||||||
|
|
||||||
|
import { ColumnDef } from "@tanstack/react-table";
|
||||||
|
import {
|
||||||
|
HoverCard,
|
||||||
|
HoverCardContent,
|
||||||
|
HoverCardTrigger,
|
||||||
|
} from "@/components/ui/hover-card";
|
||||||
|
import { Checkbox } from "@/components/ui/checkbox";
|
||||||
|
import { Organization } from "@/types/organization";
|
||||||
|
import { formatDate } from "@/lib/format-date";
|
||||||
|
import { ApiCommunication } from "@/types/api-communication";
|
||||||
|
import { ScrollArea, ScrollBar } from "../ui/scroll-area";
|
||||||
|
|
||||||
|
export const columns: ColumnDef<ApiCommunication>[] = [
|
||||||
|
{
|
||||||
|
id: "select",
|
||||||
|
header: ({ table }) => (
|
||||||
|
<Checkbox
|
||||||
|
checked={
|
||||||
|
table.getIsAllPageRowsSelected() ||
|
||||||
|
(table.getIsSomePageRowsSelected() && "indeterminate")
|
||||||
|
}
|
||||||
|
onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}
|
||||||
|
aria-label="Select all"
|
||||||
|
className="translate-y-[2px]"
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
cell: ({ row }) => (
|
||||||
|
<Checkbox
|
||||||
|
checked={row.getIsSelected()}
|
||||||
|
onCheckedChange={(value) => row.toggleSelected(!!value)}
|
||||||
|
aria-label="Select row"
|
||||||
|
className="translate-y-[2px]"
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
enableSorting: false,
|
||||||
|
enableHiding: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
accessorKey: "id",
|
||||||
|
header: ({ column }) => (
|
||||||
|
<DataTableColumnHeader column={column} title="PT" />
|
||||||
|
),
|
||||||
|
cell: ({ row }) => {
|
||||||
|
return (
|
||||||
|
<div className="w-fit">
|
||||||
|
<HoverCard>
|
||||||
|
<HoverCardTrigger>
|
||||||
|
<p>{row.getValue("id")}</p>
|
||||||
|
</HoverCardTrigger>
|
||||||
|
<HoverCardContent>{row.getValue("id")}</HoverCardContent>
|
||||||
|
</HoverCard>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: "messages",
|
||||||
|
header: ({ column }) => (
|
||||||
|
<DataTableColumnHeader column={column} title="MESSAGES" />
|
||||||
|
),
|
||||||
|
cell: ({ row }) => {
|
||||||
|
return (
|
||||||
|
<div className="w-fit">
|
||||||
|
<HoverCard>
|
||||||
|
<HoverCardTrigger>
|
||||||
|
<p className="max-w-[200px] truncate font-medium">
|
||||||
|
{row.getValue("messages")}
|
||||||
|
</p>
|
||||||
|
</HoverCardTrigger>
|
||||||
|
<HoverCardContent className="p-0 h-72 w-72 lg:h-96 lg:w-96">
|
||||||
|
<ScrollArea className="h-72 w-72 p-4 lg:h-96 lg:w-96">
|
||||||
|
{JSON.stringify(row.getValue("messages"), null, 2)}
|
||||||
|
<ScrollBar orientation="horizontal" />
|
||||||
|
</ScrollArea>
|
||||||
|
</HoverCardContent>
|
||||||
|
</HoverCard>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: "completion",
|
||||||
|
header: ({ column }) => (
|
||||||
|
<DataTableColumnHeader column={column} title="COMPLETION" />
|
||||||
|
),
|
||||||
|
cell: ({ row }) => {
|
||||||
|
return (
|
||||||
|
<div className="w-fit">
|
||||||
|
<HoverCard>
|
||||||
|
<HoverCardTrigger>
|
||||||
|
<p className="max-w-[200px] truncate font-medium">
|
||||||
|
{row.getValue("completion")}
|
||||||
|
</p>
|
||||||
|
</HoverCardTrigger>
|
||||||
|
<HoverCardContent className="p-0 h-72 w-72 lg:h-96 lg:w-96">
|
||||||
|
<ScrollArea className="h-72 w-72 p-4 lg:h-96 lg:w-96">
|
||||||
|
{row.getValue("completion")}
|
||||||
|
<ScrollBar orientation="horizontal" />
|
||||||
|
</ScrollArea>
|
||||||
|
</HoverCardContent>
|
||||||
|
</HoverCard>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: "pt",
|
||||||
|
header: ({ column }) => (
|
||||||
|
<DataTableColumnHeader column={column} title="PT" />
|
||||||
|
),
|
||||||
|
cell: ({ row }) => {
|
||||||
|
return (
|
||||||
|
<div className="w-fit">
|
||||||
|
<HoverCard>
|
||||||
|
<HoverCardTrigger>
|
||||||
|
<p>{row.getValue("pt")}</p>
|
||||||
|
{/* <p className="max-w-[100px] truncate font-medium">
|
||||||
|
{row.getValue("pt")}
|
||||||
|
</p> */}
|
||||||
|
</HoverCardTrigger>
|
||||||
|
<HoverCardContent
|
||||||
|
// className="p-0"
|
||||||
|
>
|
||||||
|
{/* <ScrollArea className="w-64 p-4"> */}
|
||||||
|
{row.getValue("pt")}
|
||||||
|
{/* <ScrollBar orientation="horizontal" /> */}
|
||||||
|
{/* </ScrollArea> */}
|
||||||
|
</HoverCardContent>
|
||||||
|
</HoverCard>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: "ct",
|
||||||
|
header: ({ column }) => (
|
||||||
|
<DataTableColumnHeader column={column} title="CT" />
|
||||||
|
),
|
||||||
|
cell: ({ row }) => {
|
||||||
|
return (
|
||||||
|
<div className="w-fit">
|
||||||
|
<HoverCard>
|
||||||
|
<HoverCardTrigger>
|
||||||
|
<p>{row.getValue("ct")}</p>
|
||||||
|
{/* <p className="max-w-[100px] truncate font-medium">
|
||||||
|
{row.getValue("ct")}
|
||||||
|
</p> */}
|
||||||
|
</HoverCardTrigger>
|
||||||
|
<HoverCardContent
|
||||||
|
// className="p-0"
|
||||||
|
>
|
||||||
|
{/* <ScrollArea className="w-64 p-4"> */}
|
||||||
|
{row.getValue("ct")}
|
||||||
|
{/* <ScrollBar orientation="horizontal" /> */}
|
||||||
|
{/* </ScrollArea> */}
|
||||||
|
</HoverCardContent>
|
||||||
|
</HoverCard>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
filterFn: (row, id, value) => {
|
||||||
|
return value.includes(row.getValue(id));
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: "tt",
|
||||||
|
header: ({ column }) => (
|
||||||
|
<DataTableColumnHeader column={column} title="TT" />
|
||||||
|
),
|
||||||
|
cell: ({ row }) => {
|
||||||
|
return (
|
||||||
|
<div className="w-fit">
|
||||||
|
<HoverCard>
|
||||||
|
<HoverCardTrigger>
|
||||||
|
<p>{row.getValue("tt")}</p>
|
||||||
|
{/* <p className="max-w-[100px] truncate font-medium">
|
||||||
|
{row.getValue("tt")}
|
||||||
|
</p> */}
|
||||||
|
</HoverCardTrigger>
|
||||||
|
<HoverCardContent
|
||||||
|
// className="p-0"
|
||||||
|
>
|
||||||
|
{/* <ScrollArea className="w-64 p-4"> */}
|
||||||
|
{row.getValue("tt")}
|
||||||
|
{/* <ScrollBar orientation="horizontal" /> */}
|
||||||
|
{/* </ScrollArea> */}
|
||||||
|
</HoverCardContent>
|
||||||
|
</HoverCard>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
filterFn: (row, id, value) => {
|
||||||
|
return value.includes(row.getValue(id));
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: "status",
|
||||||
|
header: ({ column }) => (
|
||||||
|
<DataTableColumnHeader column={column} title="STATUS" />
|
||||||
|
),
|
||||||
|
cell: ({ row }) => {
|
||||||
|
return (
|
||||||
|
<div className="w-fit">
|
||||||
|
<HoverCard>
|
||||||
|
<HoverCardTrigger>
|
||||||
|
<p>{row.getValue("status")}</p>
|
||||||
|
</HoverCardTrigger>
|
||||||
|
<HoverCardContent>{row.getValue("status")}</HoverCardContent>
|
||||||
|
</HoverCard>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
filterFn: (row, id, value) => {
|
||||||
|
return value.includes(row.getValue(id));
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: "evaluation",
|
||||||
|
header: ({ column }) => (
|
||||||
|
<DataTableColumnHeader column={column} title="EVALUATION" />
|
||||||
|
),
|
||||||
|
cell: ({ row }) => {
|
||||||
|
return (
|
||||||
|
<div className="w-fit">
|
||||||
|
<HoverCard>
|
||||||
|
<HoverCardTrigger>
|
||||||
|
{/* <p>{row.getValue("evaluation")}</p> */}
|
||||||
|
<p className="max-w-[200px] truncate font-medium">
|
||||||
|
{row.getValue("evaluation")}
|
||||||
|
</p>
|
||||||
|
</HoverCardTrigger>
|
||||||
|
<HoverCardContent className="p-0 h-52">
|
||||||
|
<ScrollArea className="h-52 p-4">
|
||||||
|
{row.getValue("evaluation")}
|
||||||
|
<ScrollBar orientation="horizontal" />
|
||||||
|
</ScrollArea>
|
||||||
|
</HoverCardContent>
|
||||||
|
</HoverCard>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
accessorKey: "created_at",
|
||||||
|
header: ({ column }) => (
|
||||||
|
<DataTableColumnHeader column={column} title="CREATED AT" />
|
||||||
|
),
|
||||||
|
cell: ({ row }) => {
|
||||||
|
return <p className="w-fit">{formatDate(row.getValue("created_at"))}</p>;
|
||||||
|
},
|
||||||
|
filterFn: (row, id, value) => {
|
||||||
|
return value.includes(row.getValue(id));
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
id: "actions",
|
||||||
|
header: ({ column }) => (
|
||||||
|
<DataTableColumnHeader column={column} title="ACTIONS" />
|
||||||
|
),
|
||||||
|
cell: ({ row }) => <CellAction data={row.original} />,
|
||||||
|
},
|
||||||
|
];
|
|
@ -0,0 +1,72 @@
|
||||||
|
import {
|
||||||
|
ArrowDownIcon,
|
||||||
|
ArrowUpIcon,
|
||||||
|
CaretSortIcon,
|
||||||
|
EyeNoneIcon,
|
||||||
|
} from "@radix-ui/react-icons"
|
||||||
|
import { Column } from "@tanstack/react-table"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
import { Button } from "@/components/ui/button"
|
||||||
|
import {
|
||||||
|
DropdownMenu,
|
||||||
|
DropdownMenuContent,
|
||||||
|
DropdownMenuItem,
|
||||||
|
DropdownMenuSeparator,
|
||||||
|
DropdownMenuTrigger,
|
||||||
|
} from "@/components/ui/dropdown-menu"
|
||||||
|
|
||||||
|
interface DataTableColumnHeaderProps<TData, TValue>
|
||||||
|
extends React.HTMLAttributes<HTMLDivElement> {
|
||||||
|
column: Column<TData, TValue>
|
||||||
|
title: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export function DataTableColumnHeader<TData, TValue>({
|
||||||
|
column,
|
||||||
|
title,
|
||||||
|
className,
|
||||||
|
}: DataTableColumnHeaderProps<TData, TValue>) {
|
||||||
|
if (!column.getCanSort()) {
|
||||||
|
return <div className={cn(className)}>{title}</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={cn("flex items-center space-x-2", className)}>
|
||||||
|
<DropdownMenu>
|
||||||
|
<DropdownMenuTrigger asChild>
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
|
className="-ml-3 h-8 data-[state=open]:bg-accent"
|
||||||
|
>
|
||||||
|
<span>{title}</span>
|
||||||
|
{column.getIsSorted() === "desc" ? (
|
||||||
|
<ArrowDownIcon className="ml-2 h-4 w-4" />
|
||||||
|
) : column.getIsSorted() === "asc" ? (
|
||||||
|
<ArrowUpIcon className="ml-2 h-4 w-4" />
|
||||||
|
) : (
|
||||||
|
<CaretSortIcon className="ml-2 h-4 w-4" />
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
</DropdownMenuTrigger>
|
||||||
|
<DropdownMenuContent align="start">
|
||||||
|
<DropdownMenuItem onClick={() => column.toggleSorting(false)}>
|
||||||
|
<ArrowUpIcon className="mr-2 h-3.5 w-3.5 text-muted-foreground/70" />
|
||||||
|
Asc
|
||||||
|
</DropdownMenuItem>
|
||||||
|
<DropdownMenuItem onClick={() => column.toggleSorting(true)}>
|
||||||
|
<ArrowDownIcon className="mr-2 h-3.5 w-3.5 text-muted-foreground/70" />
|
||||||
|
Desc
|
||||||
|
</DropdownMenuItem>
|
||||||
|
<DropdownMenuSeparator />
|
||||||
|
<DropdownMenuItem onClick={() => column.toggleVisibility(false)}>
|
||||||
|
<EyeNoneIcon className="mr-2 h-3.5 w-3.5 text-muted-foreground/70" />
|
||||||
|
Hide
|
||||||
|
</DropdownMenuItem>
|
||||||
|
</DropdownMenuContent>
|
||||||
|
</DropdownMenu>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1,152 @@
|
||||||
|
import * as React from "react";
|
||||||
|
import { CheckIcon, PlusCircledIcon } from "@radix-ui/react-icons";
|
||||||
|
import { Column } from "@tanstack/react-table";
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
import { Badge } from "@/components/ui/badge";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import {
|
||||||
|
Command,
|
||||||
|
CommandEmpty,
|
||||||
|
CommandGroup,
|
||||||
|
CommandInput,
|
||||||
|
CommandItem,
|
||||||
|
CommandList,
|
||||||
|
CommandSeparator,
|
||||||
|
} from "@/components/ui/command";
|
||||||
|
import {
|
||||||
|
Popover,
|
||||||
|
PopoverContent,
|
||||||
|
PopoverTrigger,
|
||||||
|
} from "@/components/ui/popover";
|
||||||
|
import { Separator } from "@/components/ui/separator";
|
||||||
|
|
||||||
|
interface DataTableFacetedFilterProps<TData, TValue> {
|
||||||
|
column?: Column<TData, TValue>;
|
||||||
|
title?: string;
|
||||||
|
options: {
|
||||||
|
label: string;
|
||||||
|
value: string;
|
||||||
|
icon?: React.ComponentType<{ className?: string }>;
|
||||||
|
}[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function DataTableFacetedFilter<TData, TValue>({
|
||||||
|
column,
|
||||||
|
title,
|
||||||
|
options,
|
||||||
|
}: DataTableFacetedFilterProps<TData, TValue>) {
|
||||||
|
const facets = column?.getFacetedUniqueValues();
|
||||||
|
const selectedValues = new Set(column?.getFilterValue() as string[]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Popover>
|
||||||
|
<PopoverTrigger asChild>
|
||||||
|
<Button variant="outline" size="sm" className="h-8 border-dashed">
|
||||||
|
<PlusCircledIcon className="mr-2 h-4 w-4" />
|
||||||
|
{title}
|
||||||
|
{selectedValues?.size > 0 && (
|
||||||
|
<>
|
||||||
|
<Separator orientation="vertical" className="mx-2 h-4" />
|
||||||
|
<Badge
|
||||||
|
variant="secondary"
|
||||||
|
className="rounded-sm px-1 font-normal lg:hidden"
|
||||||
|
>
|
||||||
|
{selectedValues.size}
|
||||||
|
</Badge>
|
||||||
|
<div className="hidden space-x-1 lg:flex">
|
||||||
|
{selectedValues.size > 2 ? (
|
||||||
|
<Badge
|
||||||
|
variant="secondary"
|
||||||
|
className="rounded-sm px-1 font-normal"
|
||||||
|
>
|
||||||
|
{selectedValues.size} selected
|
||||||
|
</Badge>
|
||||||
|
) : (
|
||||||
|
options
|
||||||
|
.filter((option) => selectedValues.has(option.value))
|
||||||
|
.map((option) => (
|
||||||
|
<Badge
|
||||||
|
variant="secondary"
|
||||||
|
key={option.value}
|
||||||
|
className="rounded-sm px-1 font-normal"
|
||||||
|
>
|
||||||
|
{option.label}
|
||||||
|
</Badge>
|
||||||
|
))
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
</PopoverTrigger>
|
||||||
|
<PopoverContent className="w-[200px] p-0" align="start">
|
||||||
|
<Command>
|
||||||
|
<CommandInput placeholder={title} />
|
||||||
|
<CommandList>
|
||||||
|
<CommandEmpty>No results found.</CommandEmpty>
|
||||||
|
<CommandGroup>
|
||||||
|
{options.map((option) => {
|
||||||
|
const isSelected = selectedValues.has(option.value);
|
||||||
|
return (
|
||||||
|
<CommandItem
|
||||||
|
key={option.value}
|
||||||
|
onSelect={() => {
|
||||||
|
if (isSelected) {
|
||||||
|
selectedValues.delete(option.value);
|
||||||
|
} else {
|
||||||
|
selectedValues.add(option.value);
|
||||||
|
}
|
||||||
|
const filterValues = Array.from(selectedValues);
|
||||||
|
column?.setFilterValue(
|
||||||
|
filterValues.length ? filterValues : undefined
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
"mr-2 flex h-4 w-4 items-center justify-center rounded-sm border border-primary",
|
||||||
|
isSelected
|
||||||
|
? "bg-primary text-primary-foreground"
|
||||||
|
: "opacity-50 [&_svg]:invisible"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<CheckIcon className={cn("h-4 w-4")} />
|
||||||
|
</div>
|
||||||
|
{option.icon && (
|
||||||
|
<option.icon className="mr-2 h-4 w-4 text-muted-foreground" />
|
||||||
|
)}
|
||||||
|
<span
|
||||||
|
title={option.label}
|
||||||
|
className="w-[80%] inline-block truncate"
|
||||||
|
>
|
||||||
|
{option.label}
|
||||||
|
</span>
|
||||||
|
{facets?.get(option.value) && (
|
||||||
|
<span className="ml-auto flex h-4 w-4 items-center justify-center font-mono text-xs">
|
||||||
|
{facets.get(option.value)}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</CommandItem>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</CommandGroup>
|
||||||
|
{selectedValues.size > 0 && (
|
||||||
|
<>
|
||||||
|
<CommandSeparator />
|
||||||
|
<CommandGroup>
|
||||||
|
<CommandItem
|
||||||
|
onSelect={() => column?.setFilterValue(undefined)}
|
||||||
|
className="justify-center text-center"
|
||||||
|
>
|
||||||
|
Clear filters
|
||||||
|
</CommandItem>
|
||||||
|
</CommandGroup>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</CommandList>
|
||||||
|
</Command>
|
||||||
|
</PopoverContent>
|
||||||
|
</Popover>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,97 @@
|
||||||
|
import {
|
||||||
|
ChevronLeftIcon,
|
||||||
|
ChevronRightIcon,
|
||||||
|
DoubleArrowLeftIcon,
|
||||||
|
DoubleArrowRightIcon,
|
||||||
|
} from "@radix-ui/react-icons";
|
||||||
|
import { Table } from "@tanstack/react-table";
|
||||||
|
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import {
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectItem,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue,
|
||||||
|
} from "@/components/ui/select";
|
||||||
|
|
||||||
|
interface DataTablePaginationProps<TData> {
|
||||||
|
table: Table<TData>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function DataTablePagination<TData>({
|
||||||
|
table,
|
||||||
|
}: DataTablePaginationProps<TData>) {
|
||||||
|
return (
|
||||||
|
<div className="grid grid-cols-2 md:grid-cols-[1fr_auto_auto] gap-x-6 gap-y-2">
|
||||||
|
<div className="text-sm text-muted-foreground">
|
||||||
|
{table.getFilteredSelectedRowModel().rows.length} of{" "}
|
||||||
|
{table.getFilteredRowModel().rows.length} row(s) selected.
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center space-x-2">
|
||||||
|
<p className="text-sm font-medium">Rows per page</p>
|
||||||
|
<Select
|
||||||
|
value={`${table.getState().pagination.pageSize}`}
|
||||||
|
onValueChange={(value) => {
|
||||||
|
table.setPageSize(Number(value));
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<SelectTrigger className="h-8 w-[70px]">
|
||||||
|
<SelectValue placeholder={table.getState().pagination.pageSize} />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent side="top">
|
||||||
|
{[10, 20, 30, 40, 50].map((pageSize) => (
|
||||||
|
<SelectItem key={pageSize} value={`${pageSize}`}>
|
||||||
|
{pageSize}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<div className="text-sm font-medium">
|
||||||
|
Page {table.getState().pagination.pageIndex + 1} of{" "}
|
||||||
|
{table.getPageCount()}
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center space-x-2">
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
className="h-8 w-8 p-0 flex"
|
||||||
|
onClick={() => table.setPageIndex(0)}
|
||||||
|
disabled={!table.getCanPreviousPage()}
|
||||||
|
>
|
||||||
|
<span className="sr-only">Go to first page</span>
|
||||||
|
<DoubleArrowLeftIcon className="h-4 w-4" />
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
className="h-8 w-8 p-0"
|
||||||
|
onClick={() => table.previousPage()}
|
||||||
|
disabled={!table.getCanPreviousPage()}
|
||||||
|
>
|
||||||
|
<span className="sr-only">Go to previous page</span>
|
||||||
|
<ChevronLeftIcon className="h-4 w-4" />
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
className="h-8 w-8 p-0"
|
||||||
|
onClick={() => table.nextPage()}
|
||||||
|
disabled={!table.getCanNextPage()}
|
||||||
|
>
|
||||||
|
<span className="sr-only">Go to next page</span>
|
||||||
|
<ChevronRightIcon className="h-4 w-4" />
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
className="h-8 w-8 p-0 flex"
|
||||||
|
onClick={() => table.setPageIndex(table.getPageCount() - 1)}
|
||||||
|
disabled={!table.getCanNextPage()}
|
||||||
|
>
|
||||||
|
<span className="sr-only">Go to last page</span>
|
||||||
|
<DoubleArrowRightIcon className="h-4 w-4" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,96 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import { Cross2Icon } from "@radix-ui/react-icons";
|
||||||
|
import { Table } from "@tanstack/react-table";
|
||||||
|
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { Input } from "@/components/ui/input";
|
||||||
|
// import { DataTableViewOptions } from "./components/data-table-view-options"
|
||||||
|
|
||||||
|
import { DataTableFacetedFilter } from "./data-table-faceted-filter";
|
||||||
|
import { DataTableViewOptions } from "./data-table-view-options";
|
||||||
|
import { ApiCommunication } from "@/types/api-communication";
|
||||||
|
|
||||||
|
interface DataTableToolbarProps<TData> {
|
||||||
|
table: Table<TData>;
|
||||||
|
data: ApiCommunication[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function DataTableToolbar<TData>({
|
||||||
|
table,
|
||||||
|
data,
|
||||||
|
}: DataTableToolbarProps<TData>) {
|
||||||
|
const isFiltered = table.getState().columnFilters.length > 0;
|
||||||
|
|
||||||
|
const statusFilterOptions = Array.from(
|
||||||
|
new Set(data.map((d) => d.status.toLocaleLowerCase()))
|
||||||
|
).map((v) => ({
|
||||||
|
label: v,
|
||||||
|
value: v,
|
||||||
|
}));
|
||||||
|
// const statusFilterOptions = Array.from(
|
||||||
|
// new Set(data.map((d) => d.status.toLocaleLowerCase()))
|
||||||
|
// ).map((v) => ({
|
||||||
|
// label: v.slice(0, 1).toLocaleUpperCase() + v.slice(1),
|
||||||
|
// value: v.slice(0, 1).toLocaleUpperCase() + v.slice(1),
|
||||||
|
// }));
|
||||||
|
|
||||||
|
console.log(statusFilterOptions);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div className="flex flex-1 items-center gap-2 flex-wrap">
|
||||||
|
<Input
|
||||||
|
placeholder="Search messages..."
|
||||||
|
value={
|
||||||
|
(table.getColumn("messages")?.getFilterValue() as string) ?? ""
|
||||||
|
}
|
||||||
|
onChange={(event: any) =>
|
||||||
|
table.getColumn("messages")?.setFilterValue(event.target.value)
|
||||||
|
}
|
||||||
|
className="h-8 w-[150px] lg:w-[250px]"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
placeholder="Search completion..."
|
||||||
|
value={
|
||||||
|
(table.getColumn("completion")?.getFilterValue() as string) ?? ""
|
||||||
|
}
|
||||||
|
onChange={(event: any) =>
|
||||||
|
table.getColumn("completion")?.setFilterValue(event.target.value)
|
||||||
|
}
|
||||||
|
className="h-8 w-[150px] lg:w-[250px]"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
placeholder="Search evaluation..."
|
||||||
|
value={
|
||||||
|
(table.getColumn("evaluation")?.getFilterValue() as string) ?? ""
|
||||||
|
}
|
||||||
|
onChange={(event: any) =>
|
||||||
|
table.getColumn("evaluation")?.setFilterValue(event.target.value)
|
||||||
|
}
|
||||||
|
className="h-8 w-[150px] lg:w-[250px]"
|
||||||
|
/>
|
||||||
|
|
||||||
|
{table.getColumn("status") && (
|
||||||
|
<DataTableFacetedFilter
|
||||||
|
column={table.getColumn("status")}
|
||||||
|
title="Status"
|
||||||
|
options={statusFilterOptions}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{isFiltered && (
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
onClick={() => table.resetColumnFilters()}
|
||||||
|
className="h-8 px-2 lg:px-3"
|
||||||
|
>
|
||||||
|
Reset
|
||||||
|
<Cross2Icon className="ml-2 h-4 w-4" />
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<DataTableViewOptions table={table} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
"use client"
|
||||||
|
|
||||||
|
import { DropdownMenuTrigger } from "@radix-ui/react-dropdown-menu"
|
||||||
|
import { MixerHorizontalIcon } from "@radix-ui/react-icons"
|
||||||
|
import { Table } from "@tanstack/react-table"
|
||||||
|
|
||||||
|
import { Button } from "@/components/ui/button"
|
||||||
|
import {
|
||||||
|
DropdownMenu,
|
||||||
|
DropdownMenuCheckboxItem,
|
||||||
|
DropdownMenuContent,
|
||||||
|
DropdownMenuLabel,
|
||||||
|
DropdownMenuSeparator,
|
||||||
|
} from "@/components/ui/dropdown-menu"
|
||||||
|
|
||||||
|
interface DataTableViewOptionsProps<TData> {
|
||||||
|
table: Table<TData>
|
||||||
|
}
|
||||||
|
|
||||||
|
export function DataTableViewOptions<TData>({
|
||||||
|
table,
|
||||||
|
}: DataTableViewOptionsProps<TData>) {
|
||||||
|
return (
|
||||||
|
<DropdownMenu>
|
||||||
|
<DropdownMenuTrigger asChild>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
className="ml-auto hidden h-8 lg:flex"
|
||||||
|
>
|
||||||
|
<MixerHorizontalIcon className="mr-2 h-4 w-4" />
|
||||||
|
View
|
||||||
|
</Button>
|
||||||
|
</DropdownMenuTrigger>
|
||||||
|
<DropdownMenuContent align="end" className="w-[150px]">
|
||||||
|
<DropdownMenuLabel>Toggle columns</DropdownMenuLabel>
|
||||||
|
<DropdownMenuSeparator />
|
||||||
|
{table
|
||||||
|
.getAllColumns()
|
||||||
|
.filter(
|
||||||
|
(column) =>
|
||||||
|
typeof column.accessorFn !== "undefined" && column.getCanHide()
|
||||||
|
)
|
||||||
|
.map((column) => {
|
||||||
|
return (
|
||||||
|
<DropdownMenuCheckboxItem
|
||||||
|
key={column.id}
|
||||||
|
className="capitalize"
|
||||||
|
checked={column.getIsVisible()}
|
||||||
|
onCheckedChange={(value) => column.toggleVisibility(!!value)}
|
||||||
|
>
|
||||||
|
{column.id}
|
||||||
|
</DropdownMenuCheckboxItem>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</DropdownMenuContent>
|
||||||
|
</DropdownMenu>
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1,131 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import * as React from "react";
|
||||||
|
import {
|
||||||
|
ColumnDef,
|
||||||
|
ColumnFiltersState,
|
||||||
|
SortingState,
|
||||||
|
VisibilityState,
|
||||||
|
flexRender,
|
||||||
|
getCoreRowModel,
|
||||||
|
getFacetedRowModel,
|
||||||
|
getFacetedUniqueValues,
|
||||||
|
getFilteredRowModel,
|
||||||
|
getPaginationRowModel,
|
||||||
|
getSortedRowModel,
|
||||||
|
useReactTable,
|
||||||
|
} from "@tanstack/react-table";
|
||||||
|
|
||||||
|
import {
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCell,
|
||||||
|
TableHead,
|
||||||
|
TableHeader,
|
||||||
|
TableRow,
|
||||||
|
} from "@/components/ui/table";
|
||||||
|
|
||||||
|
import { DataTablePagination } from "./data-table-pagination";
|
||||||
|
import { DataTableToolbar } from "./data-table-toolbar";
|
||||||
|
import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area";
|
||||||
|
import { Organization } from "@/types/organization";
|
||||||
|
|
||||||
|
interface DataTableProps<TData, TValue> {
|
||||||
|
columns: ColumnDef<TData, TValue>[];
|
||||||
|
data: TData[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function DataTable<TData, TValue>({
|
||||||
|
columns,
|
||||||
|
data,
|
||||||
|
}: DataTableProps<TData, TValue>) {
|
||||||
|
const [rowSelection, setRowSelection] = React.useState({});
|
||||||
|
const [columnVisibility, setColumnVisibility] =
|
||||||
|
React.useState<VisibilityState>({});
|
||||||
|
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
const [sorting, setSorting] = React.useState<SortingState>([]);
|
||||||
|
|
||||||
|
const table = useReactTable({
|
||||||
|
data,
|
||||||
|
columns,
|
||||||
|
state: {
|
||||||
|
sorting,
|
||||||
|
columnVisibility,
|
||||||
|
rowSelection,
|
||||||
|
columnFilters,
|
||||||
|
},
|
||||||
|
enableRowSelection: true,
|
||||||
|
onRowSelectionChange: setRowSelection,
|
||||||
|
onSortingChange: setSorting,
|
||||||
|
onColumnFiltersChange: setColumnFilters,
|
||||||
|
onColumnVisibilityChange: setColumnVisibility,
|
||||||
|
getCoreRowModel: getCoreRowModel(),
|
||||||
|
getFilteredRowModel: getFilteredRowModel(),
|
||||||
|
getPaginationRowModel: getPaginationRowModel(),
|
||||||
|
getSortedRowModel: getSortedRowModel(),
|
||||||
|
getFacetedRowModel: getFacetedRowModel(),
|
||||||
|
getFacetedUniqueValues: getFacetedUniqueValues(),
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-4">
|
||||||
|
<DataTableToolbar table={table} data={data as Organization[]} />
|
||||||
|
{/* <div className="rounded-md border"> */}
|
||||||
|
<ScrollArea className="rounded-md border h-[66vh]">
|
||||||
|
<Table>
|
||||||
|
<TableHeader>
|
||||||
|
{table.getHeaderGroups().map((headerGroup) => (
|
||||||
|
<TableRow key={headerGroup.id}>
|
||||||
|
{headerGroup.headers.map((header) => {
|
||||||
|
return (
|
||||||
|
<TableHead key={header.id} colSpan={header.colSpan}>
|
||||||
|
{header.isPlaceholder
|
||||||
|
? null
|
||||||
|
: flexRender(
|
||||||
|
header.column.columnDef.header,
|
||||||
|
header.getContext()
|
||||||
|
)}
|
||||||
|
</TableHead>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableHeader>
|
||||||
|
<TableBody>
|
||||||
|
{table.getRowModel().rows?.length ? (
|
||||||
|
table.getRowModel().rows.map((row) => (
|
||||||
|
<TableRow
|
||||||
|
key={row.id}
|
||||||
|
data-state={row.getIsSelected() && "selected"}
|
||||||
|
>
|
||||||
|
{row.getVisibleCells().map((cell) => (
|
||||||
|
<TableCell key={cell.id}>
|
||||||
|
{flexRender(
|
||||||
|
cell.column.columnDef.cell,
|
||||||
|
cell.getContext()
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
))}
|
||||||
|
</TableRow>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<TableRow>
|
||||||
|
<TableCell
|
||||||
|
colSpan={columns.length}
|
||||||
|
className="h-24 text-center"
|
||||||
|
>
|
||||||
|
No results.
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
)}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
<ScrollBar orientation="horizontal" />
|
||||||
|
</ScrollArea>
|
||||||
|
{/* </div> */}
|
||||||
|
<DataTablePagination table={table} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import { Heading } from "@/components/ui/heading";
|
||||||
|
import { Separator } from "@/components/ui/separator";
|
||||||
|
import React from "react";
|
||||||
|
import { DataTable } from "./data-table";
|
||||||
|
import { columns } from "./columns";
|
||||||
|
import Link from "next/link";
|
||||||
|
import { Plus } from "lucide-react";
|
||||||
|
import { buttonVariants } from "@/components/ui/button";
|
||||||
|
import { Organization } from "@/types/organization";
|
||||||
|
import { ApiCommunication } from "@/types/api-communication";
|
||||||
|
|
||||||
|
const ToolsTable = ({
|
||||||
|
apiCommunications,
|
||||||
|
}: {
|
||||||
|
apiCommunications: ApiCommunication[];
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<Heading
|
||||||
|
title={`Api Communications (${apiCommunications.length})`}
|
||||||
|
description="Manage Api Communications"
|
||||||
|
/>
|
||||||
|
<Link
|
||||||
|
href="#"
|
||||||
|
className={buttonVariants({
|
||||||
|
variant: "default",
|
||||||
|
// size: "sm",
|
||||||
|
})}
|
||||||
|
// className="text-xs md:text-sm"
|
||||||
|
// onClick={() => router.push(`/admin-dashboard/tools/add`)}
|
||||||
|
>
|
||||||
|
<Plus className="mr-2 h-4 w-4" />{" "}
|
||||||
|
<span className="md:hidden">Add</span>{" "}
|
||||||
|
<span className="hidden md:block">Add ApiCommunication</span>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
<Separator />
|
||||||
|
<DataTable data={apiCommunications} columns={columns} />
|
||||||
|
{/* <DataTable data={tasks} columns={columns} /> */}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ToolsTable;
|
|
@ -3,38 +3,37 @@ import {
|
||||||
ChevronRightIcon,
|
ChevronRightIcon,
|
||||||
DoubleArrowLeftIcon,
|
DoubleArrowLeftIcon,
|
||||||
DoubleArrowRightIcon,
|
DoubleArrowRightIcon,
|
||||||
} from "@radix-ui/react-icons"
|
} from "@radix-ui/react-icons";
|
||||||
import { Table } from "@tanstack/react-table"
|
import { Table } from "@tanstack/react-table";
|
||||||
|
|
||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button";
|
||||||
import {
|
import {
|
||||||
Select,
|
Select,
|
||||||
SelectContent,
|
SelectContent,
|
||||||
SelectItem,
|
SelectItem,
|
||||||
SelectTrigger,
|
SelectTrigger,
|
||||||
SelectValue,
|
SelectValue,
|
||||||
} from "@/components/ui/select"
|
} from "@/components/ui/select";
|
||||||
|
|
||||||
interface DataTablePaginationProps<TData> {
|
interface DataTablePaginationProps<TData> {
|
||||||
table: Table<TData>
|
table: Table<TData>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function DataTablePagination<TData>({
|
export function DataTablePagination<TData>({
|
||||||
table,
|
table,
|
||||||
}: DataTablePaginationProps<TData>) {
|
}: DataTablePaginationProps<TData>) {
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center justify-between px-2">
|
<div className="grid grid-cols-2 md:grid-cols-[1fr_auto_auto] gap-x-6 gap-y-2">
|
||||||
<div className="flex-1 text-sm text-muted-foreground">
|
<div className="text-sm text-muted-foreground">
|
||||||
{table.getFilteredSelectedRowModel().rows.length} of{" "}
|
{table.getFilteredSelectedRowModel().rows.length} of{" "}
|
||||||
{table.getFilteredRowModel().rows.length} row(s) selected.
|
{table.getFilteredRowModel().rows.length} row(s) selected.
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center space-x-6 lg:space-x-8">
|
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<p className="text-sm font-medium hidden md:block">Rows per page</p>
|
<p className="text-sm font-medium">Rows per page</p>
|
||||||
<Select
|
<Select
|
||||||
value={`${table.getState().pagination.pageSize}`}
|
value={`${table.getState().pagination.pageSize}`}
|
||||||
onValueChange={(value) => {
|
onValueChange={(value) => {
|
||||||
table.setPageSize(Number(value))
|
table.setPageSize(Number(value));
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<SelectTrigger className="h-8 w-[70px]">
|
<SelectTrigger className="h-8 w-[70px]">
|
||||||
|
@ -49,14 +48,15 @@ import {
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex w-[100px] items-center justify-center text-sm font-medium">
|
<div className="flex items-center gap-2">
|
||||||
|
<div className="text-sm font-medium">
|
||||||
Page {table.getState().pagination.pageIndex + 1} of{" "}
|
Page {table.getState().pagination.pageIndex + 1} of{" "}
|
||||||
{table.getPageCount()}
|
{table.getPageCount()}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
className="hidden h-8 w-8 p-0 lg:flex"
|
className="h-8 w-8 p-0 flex"
|
||||||
onClick={() => table.setPageIndex(0)}
|
onClick={() => table.setPageIndex(0)}
|
||||||
disabled={!table.getCanPreviousPage()}
|
disabled={!table.getCanPreviousPage()}
|
||||||
>
|
>
|
||||||
|
@ -83,7 +83,7 @@ import {
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
className="hidden h-8 w-8 p-0 lg:flex"
|
className="h-8 w-8 p-0 flex"
|
||||||
onClick={() => table.setPageIndex(table.getPageCount() - 1)}
|
onClick={() => table.setPageIndex(table.getPageCount() - 1)}
|
||||||
disabled={!table.getCanNextPage()}
|
disabled={!table.getCanNextPage()}
|
||||||
>
|
>
|
||||||
|
@ -93,5 +93,5 @@ import {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
}
|
|
@ -13,13 +13,14 @@ import { useParams, usePathname } from "next/navigation";
|
||||||
import { Separator } from "@/components/ui/separator";
|
import { Separator } from "@/components/ui/separator";
|
||||||
import { Icons } from "./icons";
|
import { Icons } from "./icons";
|
||||||
import { ExpandedItem } from "./sidebar-nav";
|
import { ExpandedItem } from "./sidebar-nav";
|
||||||
import { Fragment } from "react";
|
import { Fragment, useState } from "react";
|
||||||
import { sideNavItems } from "@/config/nav";
|
import { sideNavItems } from "@/config/nav";
|
||||||
import { siteConfig } from "@/config/site";
|
import { siteConfig } from "@/config/site";
|
||||||
import { buttonVariants } from "./ui/button";
|
import { buttonVariants } from "./ui/button";
|
||||||
import { ScrollArea, ScrollBar } from "./ui/scroll-area";
|
import { ScrollArea, ScrollBar } from "./ui/scroll-area";
|
||||||
|
|
||||||
export default function MobileSidebarNav() {
|
export default function MobileSidebarNav() {
|
||||||
|
const [isSheetOpen, setIsSheetOpen] = useState(false)
|
||||||
const params = useParams<{ workspaceId: string }>();
|
const params = useParams<{ workspaceId: string }>();
|
||||||
const path = usePathname();
|
const path = usePathname();
|
||||||
|
|
||||||
|
@ -28,7 +29,7 @@ export default function MobileSidebarNav() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex lg:hidden">
|
<div className="flex lg:hidden">
|
||||||
<Sheet>
|
<Sheet open={isSheetOpen} onOpenChange={(v) => setIsSheetOpen(v)}>
|
||||||
<SheetTrigger
|
<SheetTrigger
|
||||||
className={buttonVariants({ variant: "outline", size: "icon" })}
|
className={buttonVariants({ variant: "outline", size: "icon" })}
|
||||||
>
|
>
|
||||||
|
@ -60,6 +61,7 @@ export default function MobileSidebarNav() {
|
||||||
key={link.href + idx}
|
key={link.href + idx}
|
||||||
item={link}
|
item={link}
|
||||||
currentPath={"/" + currentPath}
|
currentPath={"/" + currentPath}
|
||||||
|
onLinkClick={() => setIsSheetOpen(!isSheetOpen)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|
|
@ -3,38 +3,37 @@ import {
|
||||||
ChevronRightIcon,
|
ChevronRightIcon,
|
||||||
DoubleArrowLeftIcon,
|
DoubleArrowLeftIcon,
|
||||||
DoubleArrowRightIcon,
|
DoubleArrowRightIcon,
|
||||||
} from "@radix-ui/react-icons"
|
} from "@radix-ui/react-icons";
|
||||||
import { Table } from "@tanstack/react-table"
|
import { Table } from "@tanstack/react-table";
|
||||||
|
|
||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button";
|
||||||
import {
|
import {
|
||||||
Select,
|
Select,
|
||||||
SelectContent,
|
SelectContent,
|
||||||
SelectItem,
|
SelectItem,
|
||||||
SelectTrigger,
|
SelectTrigger,
|
||||||
SelectValue,
|
SelectValue,
|
||||||
} from "@/components/ui/select"
|
} from "@/components/ui/select";
|
||||||
|
|
||||||
interface DataTablePaginationProps<TData> {
|
interface DataTablePaginationProps<TData> {
|
||||||
table: Table<TData>
|
table: Table<TData>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function DataTablePagination<TData>({
|
export function DataTablePagination<TData>({
|
||||||
table,
|
table,
|
||||||
}: DataTablePaginationProps<TData>) {
|
}: DataTablePaginationProps<TData>) {
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center justify-between px-2">
|
<div className="grid grid-cols-2 md:grid-cols-[1fr_auto_auto] gap-x-6 gap-y-2">
|
||||||
<div className="flex-1 text-sm text-muted-foreground">
|
<div className="text-sm text-muted-foreground">
|
||||||
{table.getFilteredSelectedRowModel().rows.length} of{" "}
|
{table.getFilteredSelectedRowModel().rows.length} of{" "}
|
||||||
{table.getFilteredRowModel().rows.length} row(s) selected.
|
{table.getFilteredRowModel().rows.length} row(s) selected.
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center space-x-6 lg:space-x-8">
|
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<p className="text-sm font-medium hidden md:block">Rows per page</p>
|
<p className="text-sm font-medium">Rows per page</p>
|
||||||
<Select
|
<Select
|
||||||
value={`${table.getState().pagination.pageSize}`}
|
value={`${table.getState().pagination.pageSize}`}
|
||||||
onValueChange={(value) => {
|
onValueChange={(value) => {
|
||||||
table.setPageSize(Number(value))
|
table.setPageSize(Number(value));
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<SelectTrigger className="h-8 w-[70px]">
|
<SelectTrigger className="h-8 w-[70px]">
|
||||||
|
@ -49,14 +48,15 @@ import {
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex w-[100px] items-center justify-center text-sm font-medium">
|
<div className="flex items-center gap-2">
|
||||||
|
<div className="text-sm font-medium">
|
||||||
Page {table.getState().pagination.pageIndex + 1} of{" "}
|
Page {table.getState().pagination.pageIndex + 1} of{" "}
|
||||||
{table.getPageCount()}
|
{table.getPageCount()}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
className="hidden h-8 w-8 p-0 lg:flex"
|
className="h-8 w-8 p-0 flex"
|
||||||
onClick={() => table.setPageIndex(0)}
|
onClick={() => table.setPageIndex(0)}
|
||||||
disabled={!table.getCanPreviousPage()}
|
disabled={!table.getCanPreviousPage()}
|
||||||
>
|
>
|
||||||
|
@ -83,7 +83,7 @@ import {
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
className="hidden h-8 w-8 p-0 lg:flex"
|
className="h-8 w-8 p-0 flex"
|
||||||
onClick={() => table.setPageIndex(table.getPageCount() - 1)}
|
onClick={() => table.setPageIndex(table.getPageCount() - 1)}
|
||||||
disabled={!table.getCanNextPage()}
|
disabled={!table.getCanNextPage()}
|
||||||
>
|
>
|
||||||
|
@ -93,5 +93,5 @@ import {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
}
|
|
@ -52,19 +52,22 @@ const CollapsedItem = ({
|
||||||
const ExpandedItem = ({
|
const ExpandedItem = ({
|
||||||
item,
|
item,
|
||||||
currentPath,
|
currentPath,
|
||||||
|
onLinkClick,
|
||||||
}: {
|
}: {
|
||||||
item: NavItem;
|
item: NavItem;
|
||||||
currentPath: string;
|
currentPath: string;
|
||||||
|
onLinkClick?: Function;
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<Link
|
<Link
|
||||||
|
onClick={() => onLinkClick && onLinkClick()}
|
||||||
href={item.href}
|
href={item.href}
|
||||||
className={cn(
|
className={cn(
|
||||||
buttonVariants({ variant: "ghost" }),
|
buttonVariants({ variant: "ghost" }),
|
||||||
"justify-start text-muted-foreground",
|
"justify-start text-muted-foreground",
|
||||||
currentPath === item.href
|
currentPath === item.href
|
||||||
? "bg-primary text-primary-foreground hover:bg-primary/90 hover:text-primary-foreground"
|
? "bg-primary text-primary-foreground hover:bg-primary/90 hover:text-primary-foreground"
|
||||||
: "transparent",
|
: "transparent"
|
||||||
// "soon" === item.badge && "cursor-not-allowed opacity-80"
|
// "soon" === item.badge && "cursor-not-allowed opacity-80"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|
|
@ -3,38 +3,37 @@ import {
|
||||||
ChevronRightIcon,
|
ChevronRightIcon,
|
||||||
DoubleArrowLeftIcon,
|
DoubleArrowLeftIcon,
|
||||||
DoubleArrowRightIcon,
|
DoubleArrowRightIcon,
|
||||||
} from "@radix-ui/react-icons"
|
} from "@radix-ui/react-icons";
|
||||||
import { Table } from "@tanstack/react-table"
|
import { Table } from "@tanstack/react-table";
|
||||||
|
|
||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button";
|
||||||
import {
|
import {
|
||||||
Select,
|
Select,
|
||||||
SelectContent,
|
SelectContent,
|
||||||
SelectItem,
|
SelectItem,
|
||||||
SelectTrigger,
|
SelectTrigger,
|
||||||
SelectValue,
|
SelectValue,
|
||||||
} from "@/components/ui/select"
|
} from "@/components/ui/select";
|
||||||
|
|
||||||
interface DataTablePaginationProps<TData> {
|
interface DataTablePaginationProps<TData> {
|
||||||
table: Table<TData>
|
table: Table<TData>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function DataTablePagination<TData>({
|
export function DataTablePagination<TData>({
|
||||||
table,
|
table,
|
||||||
}: DataTablePaginationProps<TData>) {
|
}: DataTablePaginationProps<TData>) {
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center justify-between px-2">
|
<div className="grid grid-cols-2 md:grid-cols-[1fr_auto_auto] gap-x-6 gap-y-2">
|
||||||
<div className="flex-1 text-sm text-muted-foreground">
|
<div className="text-sm text-muted-foreground">
|
||||||
{table.getFilteredSelectedRowModel().rows.length} of{" "}
|
{table.getFilteredSelectedRowModel().rows.length} of{" "}
|
||||||
{table.getFilteredRowModel().rows.length} row(s) selected.
|
{table.getFilteredRowModel().rows.length} row(s) selected.
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center space-x-6 lg:space-x-8">
|
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<p className="text-sm font-medium hidden md:block">Rows per page</p>
|
<p className="text-sm font-medium">Rows per page</p>
|
||||||
<Select
|
<Select
|
||||||
value={`${table.getState().pagination.pageSize}`}
|
value={`${table.getState().pagination.pageSize}`}
|
||||||
onValueChange={(value) => {
|
onValueChange={(value) => {
|
||||||
table.setPageSize(Number(value))
|
table.setPageSize(Number(value));
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<SelectTrigger className="h-8 w-[70px]">
|
<SelectTrigger className="h-8 w-[70px]">
|
||||||
|
@ -49,14 +48,15 @@ import {
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex w-[100px] items-center justify-center text-sm font-medium">
|
<div className="flex items-center gap-2">
|
||||||
|
<div className="text-sm font-medium">
|
||||||
Page {table.getState().pagination.pageIndex + 1} of{" "}
|
Page {table.getState().pagination.pageIndex + 1} of{" "}
|
||||||
{table.getPageCount()}
|
{table.getPageCount()}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
className="hidden h-8 w-8 p-0 lg:flex"
|
className="h-8 w-8 p-0 flex"
|
||||||
onClick={() => table.setPageIndex(0)}
|
onClick={() => table.setPageIndex(0)}
|
||||||
disabled={!table.getCanPreviousPage()}
|
disabled={!table.getCanPreviousPage()}
|
||||||
>
|
>
|
||||||
|
@ -83,7 +83,7 @@ import {
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
className="hidden h-8 w-8 p-0 lg:flex"
|
className="h-8 w-8 p-0 flex"
|
||||||
onClick={() => table.setPageIndex(table.getPageCount() - 1)}
|
onClick={() => table.setPageIndex(table.getPageCount() - 1)}
|
||||||
disabled={!table.getCanNextPage()}
|
disabled={!table.getCanNextPage()}
|
||||||
>
|
>
|
||||||
|
@ -93,5 +93,5 @@ import {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
}
|
|
@ -85,7 +85,7 @@ export const sideNavItems: GroupedNavItems[] = [
|
||||||
icon: Wrench,
|
icon: Wrench,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
href: "/dashboard/api-communication",
|
href: "/dashboard/api-communications",
|
||||||
title: "Api Communication",
|
title: "Api Communication",
|
||||||
icon: Cloudy,
|
icon: Cloudy,
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { Account } from "@/types/account";
|
import { Account } from "@/types/account";
|
||||||
|
import { ApiCommunication } from "@/types/api-communication";
|
||||||
import { Configuration } from "@/types/configuration";
|
import { Configuration } from "@/types/configuration";
|
||||||
import { Organization } from "@/types/organization";
|
import { Organization } from "@/types/organization";
|
||||||
import { User } from "@/types/user";
|
import { User } from "@/types/user";
|
||||||
|
@ -130,3 +131,35 @@ export const dummyConfigurations: Configuration[] = [
|
||||||
created_at: new Date().toISOString(),
|
created_at: new Date().toISOString(),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export const dummyApiCommunications: ApiCommunication[] = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
messages:
|
||||||
|
"{"messages":[{"role":"system","content":"\n \n You are a professional language detection service.\n You are given a commit message or a commit diff.\n You have to answer with the programming languages and libraries the user input's code is written in.\n You have to ignore comments and strings in variables. \n You can detect up to 3 but you need to be 100% sure.\n \n Always answer in the following json format where "n" is the name of the detected language or library:\n \n [{"n":"PHP", {"n":"Symfony"}] or []\n \n ----------------------------------------\n \n ONLY JSON IS ALLOWED as an answer. No explanation or other text is allowed.\n \n \n"},{"role":"user","content":"Allow PHP 8\n\ndiff --git a/composer.json b/composer.json\nindex 7889d20..4c6382c 100644\n--- a/composer.json\n+++ b/composer.json\n@@ -13,7 +13,7 @@\n ],\n "minimum-stability": "dev",\n "require": {\n- "php": "^7.1.3",\n+ "php": ">=7.1.3",\n "doctrine/inflector": "^1.2",\n "nikic/php-parser": "^4.0",\n "symfony/config": "^3.4|^4.0|^5.0",\n"}]}",
|
||||||
|
completion: '"[{"n":"PHP"}]"',
|
||||||
|
pt: 287,
|
||||||
|
ct: 7,
|
||||||
|
tt: 294,
|
||||||
|
status: "skill_extraction_success",
|
||||||
|
type: "skill_extraction",
|
||||||
|
evaluation:
|
||||||
|
"Uploaded at: 2023-09-20 00:00:00 - Uploader: jschultz@php.net - Developer: fabien@potencier.org - Status: finished",
|
||||||
|
created_at: new Date().toISOString(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
messages:
|
||||||
|
"{"messages":[{"role":"system","content":"\nThis is a training task for a developer who has the following skillMatrix:\n\nskill: PHP - score:7\nskill: Symfony - score: 7\nskill: EasyAdmin - score: 3\n\n===========================================================================\n\n--- task\ntaskTitle: Create a tabbed user administration page in symfony 6 using easy admin\ntaskDescription: \n\n -- index page\n\n - "List" all users that have a Role that matches or is below your own Role\n - "Create" a new user with a Role that matches or is below your own Role \n tab 1\n firstname, lastname, email\n tab 2\n roles with checkboxes\n tab 3\n change password\n - "Edit" a user with a Role that matches or is below your own Role \n tab 1\n form with firstname, lastname, email \n tab 2\n form with roles with checkboxes\n - "Change Password of exiting User"\n form with password and password confirmation \n\n You got 2 hours to finish this task starting from now.\n Document your findings and the challenges you faced. Adhere to the project's coding standards.\n \n===========================================================================\n\nThe user will give you another skill matrix and you need to create a task with a task title for training purposes. \n\nAlways answer in the following json format:\n\n{ "taskTitle": "", "taskDescription": "[15-20 sentences formatted in markdown]" }\n\ntaskDescription should be written in markdown with proper headlines and formatting.\n\nYou may use newlines in the json response values for formatting reasons.\n\nONLY JSON IS ALLOWED as an answer. No explanation or other text is allowed.\n"},{"role":"user","content":"PHP: 7\nSymfony: 7\n"}]}",
|
||||||
|
completion:
|
||||||
|
""{ "taskTitle": "Develop a Blogging Platform using Symfony 6", "taskDescription": "\n\nYour task is to create a basic blogging platform using Symfony 6. The platform should have the following features:\n\n- `User Registration and Login`: Implement a user registration and login system using Symfony's security component. Users should be able to register with an email and password.\n\n- `Create Blog Post`: Authenticated users should be able to create a new blog post. A blog post should have a title, content, and the date of creation.\n\n- `List Blog Posts`: Create a page to list all blog posts. Each blog post listing should include the title, an excerpt of the content, and the date of creation. The list should be paginated.\n\n- `View Blog Post`: Users should be able to click on a blog post title in the list to view the full blog post. The full blog post view should include the title, full content, and the date of creation.\n\n- `Edit and Delete Blog Post`: Authenticated users should be able to edit and delete their own blog posts.\n\n- `Comments`: Authenticated users should be able to post comments on a blog post.\n\nYou are given 4 hours to complete this task. Document your findings and the challenges you faced. Adhere to the project's coding standards.\n\n" }"",
|
||||||
|
pt: 364,
|
||||||
|
ct: 271,
|
||||||
|
tt: 635,
|
||||||
|
status: "course_creation_success",
|
||||||
|
type: "course_creation",
|
||||||
|
evaluation:
|
||||||
|
" Uploaded at: 2023-09-20 00:00:00 - Uploader: jschultz@php.net - Developer: fabien@potencier.org - Status: finished",
|
||||||
|
created_at: new Date().toISOString(),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
export interface ApiCommunication {
|
||||||
|
id: number;
|
||||||
|
messages: string;
|
||||||
|
completion: string;
|
||||||
|
pt: number;
|
||||||
|
ct: number;
|
||||||
|
tt: number;
|
||||||
|
status: string;
|
||||||
|
type: string;
|
||||||
|
evaluation: string;
|
||||||
|
created_at: string;
|
||||||
|
}
|
Loading…
Reference in New Issue