diff --git a/src/app/(dashboard)/dashboard/criteria/page.tsx b/src/app/(dashboard)/dashboard/criteria/page.tsx
new file mode 100644
index 0000000..e900c23
--- /dev/null
+++ b/src/app/(dashboard)/dashboard/criteria/page.tsx
@@ -0,0 +1,20 @@
+import Breadcrumb from "@/components/breadcrumb";
+import ToolsTable from "@/components/criteria-table/tools-table";
+import { dummyCriteria } from "@/constants/data";
+import { Criteria } from "@/types/criteria";
+import React from "react";
+
+const breadcrumbItems = [
+ { title: "Dashboard", link: "#" },
+ { title: "Criteria" },
+];
+const Page = () => {
+ return (
+
+
+
+
+ );
+};
+
+export default Page;
diff --git a/src/app/(dashboard)/dashboard/page.tsx b/src/app/(dashboard)/dashboard/page.tsx
index 9dcc0fa..4883458 100644
--- a/src/app/(dashboard)/dashboard/page.tsx
+++ b/src/app/(dashboard)/dashboard/page.tsx
@@ -2,7 +2,7 @@ import Breadcrumb from "@/components/breadcrumb";
import ToolsTable from "@/components/evaluation-start-table/tools-table";
import { dummyCourseAdmin, dummyEvaluation } from "@/constants/data";
import { CourseAdmin } from "@/types/course-admin";
-import { Evaluation } from "@/types/evaluation-start";
+import { EvaluationStart } from "@/types/evaluation-start";
import React from "react";
const breadcrumbItems = [
@@ -13,7 +13,7 @@ const Page = () => {
return (
-
+
);
};
diff --git a/src/components/criteria-table/cell-action.tsx b/src/components/criteria-table/cell-action.tsx
new file mode 100644
index 0000000..0e2cc79
--- /dev/null
+++ b/src/components/criteria-table/cell-action.tsx
@@ -0,0 +1,69 @@
+"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 { Criteria } from "@/types/criteria";
+import { EvaluationStart } from "@/types/evaluation-start";
+
+import { Edit, GitCommit, MoreHorizontal, Trash } from "lucide-react";
+import { useRouter } from "next/navigation";
+import { useState } from "react";
+
+interface CellActionProps {
+ data: Criteria;
+}
+
+export const CellAction: React.FC = ({ data }) => {
+ const [loading, setLoading] = useState(false);
+ const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
+ const router = useRouter();
+ const { toast } = useToast();
+
+ const onDeleteConfirm = async () => {};
+
+ const handleUpdateStatus = async () => {};
+
+ return (
+ <>
+ setIsDeleteModalOpen(false)}
+ onConfirm={onDeleteConfirm}
+ loading={loading}
+ />
+
+
+
+ Open menu
+
+
+
+
+ Actions
+
+
+ // router.push(`#`)
+ // }
+ >
+ Edit
+
+ setIsDeleteModalOpen(true)}
+ >
+ Delete
+
+
+
+ >
+ );
+};
diff --git a/src/components/criteria-table/columns.tsx b/src/components/criteria-table/columns.tsx
new file mode 100644
index 0000000..8b29be5
--- /dev/null
+++ b/src/components/criteria-table/columns.tsx
@@ -0,0 +1,122 @@
+"use client";
+import { DataTableColumnHeader } from "./data-table-column-header";
+import { CellAction } from "./cell-action";
+import { ColumnDef } from "@tanstack/react-table";
+import { Checkbox } from "@/components/ui/checkbox";
+import { Criteria } from "@/types/criteria";
+import { formatDate } from "@/lib/format-date";
+import {
+ HoverCard,
+ HoverCardContent,
+ HoverCardTrigger,
+} from "../ui/hover-card";
+import { ScrollArea, ScrollBar } from "../ui/scroll-area";
+
+export const columns: ColumnDef[] = [
+ {
+ id: "select",
+ header: ({ table }) => (
+ table.toggleAllPageRowsSelected(!!value)}
+ aria-label="Select all"
+ className="translate-y-[2px]"
+ />
+ ),
+ cell: ({ row }) => (
+ row.toggleSelected(!!value)}
+ aria-label="Select row"
+ className="translate-y-[2px]"
+ />
+ ),
+ enableSorting: false,
+ enableHiding: false,
+ },
+
+ {
+ accessorKey: "name",
+ header: ({ column }) => (
+
+ ),
+ cell: ({ row }) => {
+ return {row.getValue("name")}
;
+ },
+ },
+
+ {
+ accessorKey: "description",
+ header: ({ column }) => (
+
+ ),
+ cell: ({ row }) => {
+ return (
+
+
+
+
+ {row.getValue("description")}
+
+
+
+
+ {row.getValue("description")}
+
+
+
+
+ );
+ },
+ },
+
+ {
+ accessorKey: "prompt",
+ header: ({ column }) => (
+
+ ),
+ cell: ({ row }) => {
+ return (
+
+
+
+
+ {row.getValue("prompt")}
+
+
+
+
+ {row.getValue("prompt")}
+
+
+
+
+
+ );
+ },
+ },
+
+ {
+ accessorKey: "created_at",
+ header: ({ column }) => (
+
+ ),
+ cell: ({ row }) => {
+ return {formatDate(row.getValue("created_at"))}
;
+ },
+ filterFn: (row, id, value) => {
+ return value.includes(row.getValue(id));
+ },
+ },
+
+ {
+ id: "actions",
+ header: ({ column }) => (
+
+ ),
+ cell: ({ row }) => ,
+ },
+];
diff --git a/src/components/criteria-table/data-table-column-header.tsx b/src/components/criteria-table/data-table-column-header.tsx
new file mode 100644
index 0000000..85df45e
--- /dev/null
+++ b/src/components/criteria-table/data-table-column-header.tsx
@@ -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
+ extends React.HTMLAttributes {
+ column: Column
+ title: string
+ }
+
+ export function DataTableColumnHeader({
+ column,
+ title,
+ className,
+ }: DataTableColumnHeaderProps) {
+ if (!column.getCanSort()) {
+ return {title}
+ }
+
+
+ return (
+
+
+
+
+ {title}
+ {column.getIsSorted() === "desc" ? (
+
+ ) : column.getIsSorted() === "asc" ? (
+
+ ) : (
+
+ )}
+
+
+
+ column.toggleSorting(false)}>
+
+ Asc
+
+ column.toggleSorting(true)}>
+
+ Desc
+
+
+ column.toggleVisibility(false)}>
+
+ Hide
+
+
+
+
+ )
+ }
\ No newline at end of file
diff --git a/src/components/criteria-table/data-table-faceted-filter.tsx b/src/components/criteria-table/data-table-faceted-filter.tsx
new file mode 100644
index 0000000..a5efee2
--- /dev/null
+++ b/src/components/criteria-table/data-table-faceted-filter.tsx
@@ -0,0 +1,147 @@
+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 {
+ column?: Column
+ title?: string
+ options: {
+ label: string
+ value: string
+ icon?: React.ComponentType<{ className?: string }>
+ }[]
+}
+
+export function DataTableFacetedFilter({
+ column,
+ title,
+ options,
+}: DataTableFacetedFilterProps) {
+ const facets = column?.getFacetedUniqueValues()
+ const selectedValues = new Set(column?.getFilterValue() as string[])
+
+ return (
+
+
+
+
+ {title}
+ {selectedValues?.size > 0 && (
+ <>
+
+
+ {selectedValues.size}
+
+
+ {selectedValues.size > 2 ? (
+
+ {selectedValues.size} selected
+
+ ) : (
+ options
+ .filter((option) => selectedValues.has(option.value))
+ .map((option) => (
+
+ {option.label}
+
+ ))
+ )}
+
+ >
+ )}
+
+
+
+
+
+
+ No results found.
+
+ {options.map((option) => {
+ const isSelected = selectedValues.has(option.value)
+ return (
+ {
+ if (isSelected) {
+ selectedValues.delete(option.value)
+ } else {
+ selectedValues.add(option.value)
+ }
+ const filterValues = Array.from(selectedValues)
+ column?.setFilterValue(
+ filterValues.length ? filterValues : undefined
+ )
+ }}
+ >
+
+
+
+ {option.icon && (
+
+ )}
+ {option.label}
+ {facets?.get(option.value) && (
+
+ {facets.get(option.value)}
+
+ )}
+
+ )
+ })}
+
+ {selectedValues.size > 0 && (
+ <>
+
+
+ column?.setFilterValue(undefined)}
+ className="justify-center text-center"
+ >
+ Clear filters
+
+
+ >
+ )}
+
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/src/components/criteria-table/data-table-pagination.tsx b/src/components/criteria-table/data-table-pagination.tsx
new file mode 100644
index 0000000..3c5a1d9
--- /dev/null
+++ b/src/components/criteria-table/data-table-pagination.tsx
@@ -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 {
+ table: Table;
+}
+
+export function DataTablePagination({
+ table,
+}: DataTablePaginationProps) {
+ return (
+
+
+ {table.getFilteredSelectedRowModel().rows.length} of{" "}
+ {table.getFilteredRowModel().rows.length} row(s) selected.
+
+
+
Rows per page
+
{
+ table.setPageSize(Number(value));
+ }}
+ >
+
+
+
+
+ {[10, 20, 30, 40, 50].map((pageSize) => (
+
+ {pageSize}
+
+ ))}
+
+
+
+
+
+ Page {table.getState().pagination.pageIndex + 1} of{" "}
+ {table.getPageCount()}
+
+
+ table.setPageIndex(0)}
+ disabled={!table.getCanPreviousPage()}
+ >
+ Go to first page
+
+
+ table.previousPage()}
+ disabled={!table.getCanPreviousPage()}
+ >
+ Go to previous page
+
+
+ table.nextPage()}
+ disabled={!table.getCanNextPage()}
+ >
+ Go to next page
+
+
+ table.setPageIndex(table.getPageCount() - 1)}
+ disabled={!table.getCanNextPage()}
+ >
+ Go to last page
+
+
+
+
+
+ );
+}
diff --git a/src/components/criteria-table/data-table-toolbar.tsx b/src/components/criteria-table/data-table-toolbar.tsx
new file mode 100644
index 0000000..1538fa5
--- /dev/null
+++ b/src/components/criteria-table/data-table-toolbar.tsx
@@ -0,0 +1,84 @@
+"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 { DataTableFacetedFilter } from "./data-table-faceted-filter";
+import { DataTableViewOptions } from "./data-table-view-options";
+import { userFilterLabels } from "@/constants/data";
+import { Criteria } from "@/types/criteria";
+
+interface DataTableToolbarProps {
+ table: Table;
+ data: Criteria[];
+}
+
+export function DataTableToolbar({
+ table,
+ data,
+}: DataTableToolbarProps) {
+ const isFiltered = table.getState().columnFilters.length > 0;
+
+ // const statusFilterOptions = Array.from(
+ // new Set(data.map((d) => d.status))
+ // ).map((v) => ({
+ // label: v,
+ // value: v,
+ // }));
+
+ return (
+
+ );
+}
diff --git a/src/components/criteria-table/data-table-view-options.tsx b/src/components/criteria-table/data-table-view-options.tsx
new file mode 100644
index 0000000..6d56347
--- /dev/null
+++ b/src/components/criteria-table/data-table-view-options.tsx
@@ -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 {
+ table: Table
+}
+
+export function DataTableViewOptions({
+ table,
+}: DataTableViewOptionsProps) {
+ return (
+
+
+
+
+ View
+
+
+
+ Toggle columns
+
+ {table
+ .getAllColumns()
+ .filter(
+ (column) =>
+ typeof column.accessorFn !== "undefined" && column.getCanHide()
+ )
+ .map((column) => {
+ return (
+ column.toggleVisibility(!!value)}
+ >
+ {column.id}
+
+ )
+ })}
+
+
+ )
+}
\ No newline at end of file
diff --git a/src/components/criteria-table/data-table.tsx b/src/components/criteria-table/data-table.tsx
new file mode 100644
index 0000000..93f525c
--- /dev/null
+++ b/src/components/criteria-table/data-table.tsx
@@ -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 { Criteria } from "@/types/criteria";
+
+interface DataTableProps {
+ columns: ColumnDef[];
+ data: TData[];
+}
+
+export function DataTable({
+ columns,
+ data,
+}: DataTableProps) {
+ const [rowSelection, setRowSelection] = React.useState({});
+ const [columnVisibility, setColumnVisibility] =
+ React.useState({});
+ const [columnFilters, setColumnFilters] = React.useState(
+ []
+ );
+ const [sorting, setSorting] = React.useState([]);
+
+ 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 (
+
+
+ {/*
*/}
+
+
+
+ {table.getHeaderGroups().map((headerGroup) => (
+
+ {headerGroup.headers.map((header) => {
+ return (
+
+ {header.isPlaceholder
+ ? null
+ : flexRender(
+ header.column.columnDef.header,
+ header.getContext()
+ )}
+
+ );
+ })}
+
+ ))}
+
+
+ {table.getRowModel().rows?.length ? (
+ table.getRowModel().rows.map((row) => (
+
+ {row.getVisibleCells().map((cell) => (
+
+ {flexRender(
+ cell.column.columnDef.cell,
+ cell.getContext()
+ )}
+
+ ))}
+
+ ))
+ ) : (
+
+
+ No results.
+
+
+ )}
+
+
+
+
+ {/*
*/}
+
+
+ );
+}
diff --git a/src/components/criteria-table/tools-table.tsx b/src/components/criteria-table/tools-table.tsx
new file mode 100644
index 0000000..7a135aa
--- /dev/null
+++ b/src/components/criteria-table/tools-table.tsx
@@ -0,0 +1,39 @@
+"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 { Criteria } from "@/types/criteria";
+
+const ToolsTable = ({ criteriaData }: { criteriaData: Criteria[] }) => {
+ return (
+ <>
+
+
+
router.push(`/admin-dashboard/tools/add`)}
+ >
+
Add Criteria
+
+
+
+
+ >
+ );
+};
+
+export default ToolsTable;
diff --git a/src/components/users-table/columns.tsx b/src/components/users-table/columns.tsx
index 6a89029..114c3dd 100644
--- a/src/components/users-table/columns.tsx
+++ b/src/components/users-table/columns.tsx
@@ -1,13 +1,7 @@
"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 { User } from "@/types/user";
import { Checkbox } from "@/components/ui/checkbox";
import { formatDate } from "@/lib/format-date";
@@ -44,28 +38,8 @@ export const columns: ColumnDef[] = [
),
cell: ({ row }) => {
- return (
-
-
-
- {/*
- {row.getValue("email")}
-
*/}
- {row.getValue("email")}
-
-
- {/* */}
- {row.getValue("email")}
- {/* */}
- {/* */}
-
-
-
- );
+ return {row.getValue("email")}
;
},
- // filterFn: (row, id, value) => {
- // return value.includes(row.getValue(id));
- // },
},
{
accessorKey: "fullName",
@@ -73,29 +47,8 @@ export const columns: ColumnDef[] = [
),
cell: ({ row }) => {
- return (
-
-
-
-
- {row.getValue("fullName")}
-
-
-
- {/* */}
- {row.getValue("fullName")}
- {/* */}
- {/* */}
-
-
-
- );
+ return {row.getValue("fullName")}
;
},
- // filterFn: (row, id, value) => {
- // return value.includes(row.getValue(id));
- // },
},
{
accessorKey: "role",
@@ -103,25 +56,7 @@ export const columns: ColumnDef[] = [
),
cell: ({ row }) => {
- return (
-
-
-
-
- {row.getValue("role")}
-
-
-
- {/* */}
- {row.getValue("role")}
- {/* */}
- {/* */}
-
-
-
- );
+ return {row.getValue("role")}
;
},
filterFn: (row, id, value) => {
return value.includes(row.getValue(id));
diff --git a/src/constants/data.ts b/src/constants/data.ts
index fcca85f..0b1c16f 100644
--- a/src/constants/data.ts
+++ b/src/constants/data.ts
@@ -1,7 +1,8 @@
import { Account } from "@/types/account";
import { ApiCommunication } from "@/types/api-communication";
import { Configuration } from "@/types/configuration";
-import { Evaluation } from "@/types/evaluation-start";
+import { Criteria } from "@/types/criteria";
+import { EvaluationStart } from "@/types/evaluation-start";
import { Organization } from "@/types/organization";
import { User } from "@/types/user";
import { UserRound, UserRoundCheck } from "lucide-react";
@@ -180,7 +181,7 @@ export const dummyCourseAdmin = [
},
];
-export const dummyEvaluation: Evaluation[] = [
+export const dummyEvaluation: EvaluationStart[] = [
{
id: 1,
fullName: "John Doe",
@@ -194,3 +195,78 @@ export const dummyEvaluation: Evaluation[] = [
status: "unfinished",
},
];
+
+export const dummyCriteria: Criteria[] = [
+ {
+ id: 1,
+ name: "readability",
+ description: "assesses the clarity and understandability of the code",
+ prompt: `You are a professional git reviewing assistant with focus on --name--.
+You are given a commit message or a commit diff.
+
+You know sometimes developers do simple stuff like fixing a typo.
+In that case you can evaluate the criterias with a score of 0 which means it is not applicable.
+
+If there is no code at all, you can evaluate the criterias with a score of 0 which means it is not applicable.
+
+Otherwise if you think the code is good enough to make a review,
+
+You have to rate the code from 1-10, where 1 is poor and 10 is excellent based on the following criterias:
+
+--subcriteria--
+
+If you always rate the coe above 5, you are too nice.
+
+You have to ignore comments and strings in variables.
+
+Always answer in the following json format where "cn" is the name of criterion and "s" is the score:
+
+ {[
+ {"cn": criterion_name_1, "s": score_1},
+ {"cn": criterion_name_2, "s": score_2},
+ ...
+ ]}
+
+----------------------------------------
+
+ONLY JSON IS ALLOWED as an answer. No explanation or other text is allowed.
+`,
+ created_at: new Date().toISOString(),
+ },
+ {
+ id: 2,
+ name: "refinement",
+ description: "assesses the process and stages of code development",
+ prompt: `You are a professional git reviewing assistant with focus on --name--.
+ You are given a commit message or a commit diff.
+
+ You know sometimes developers do simple stuff like fixing a typo.
+ In that case you can evaluate the criterias with a score of 0 which means it is not applicable.
+
+ If there is no code at all, you can evaluate the criterias with a score of 0 which means it is not applicable.
+
+ Otherwise if you think the code is good enough to make a review,
+
+ You have to rate the code from 1-10, where 1 is poor and 10 is excellent based on the following criterias:
+
+ --subcriteria--
+
+ If you always rate the coe above 5, you are too nice.
+
+ You have to ignore comments and strings in variables.
+
+ Always answer in the following json format where "cn" is the name of criterion and "s" is the score:
+
+ {[
+ {"cn": criterion_name_1, "s": score_1},
+ {"cn": criterion_name_2, "s": score_2},
+ ...
+ ]}
+
+ ----------------------------------------
+
+ ONLY JSON IS ALLOWED as an answer. No explanation or other text is allowed.
+`,
+ created_at: new Date().toISOString(),
+ },
+];
diff --git a/src/types/criteria.ts b/src/types/criteria.ts
new file mode 100644
index 0000000..019ed39
--- /dev/null
+++ b/src/types/criteria.ts
@@ -0,0 +1,7 @@
+export interface Criteria {
+ id: number;
+ name: string;
+ description: string;
+ prompt: string;
+ created_at: string;
+}