diff --git a/app/tasks/components/columns.tsx b/app/tasks/components/columns.tsx new file mode 100644 index 0000000..5c00b6c --- /dev/null +++ b/app/tasks/components/columns.tsx @@ -0,0 +1,121 @@ +"use client"; + +import { Badge } from "@/components/ui/badge"; +import { Checkbox } from "@/components/ui/checkbox"; +import { ColumnDef } from "@tanstack/react-table"; +import { labels, priorities, statuses } from "../data/data"; +import { Task } from "../data/schema"; +import { DataTableColumnHeader } from "./data-table-column-header"; +import { DataTableRowActions } from "./data-table-row-actions"; + +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: "id", + header: ({ column }) => ( + + ), + cell: ({ row }) =>
{row.getValue("id")}
, + enableSorting: false, + enableHiding: false, + }, + { + accessorKey: "title", + header: ({ column }) => ( + + ), + cell: ({ row }) => { + const label = labels.find((label) => label.value === row.original.label); + + return ( +
+ {label && {label.label}} + + {row.getValue("title")} + +
+ ); + }, + }, + { + accessorKey: "status", + header: ({ column }) => ( + + ), + cell: ({ row }) => { + const status = statuses.find( + (status) => status.value === row.getValue("status"), + ); + + if (!status) { + return null; + } + + return ( +
+ {status.icon && ( + + )} + {status.label} +
+ ); + }, + filterFn: (row, id, value) => { + return value.includes(row.getValue(id)); + }, + }, + { + accessorKey: "priority", + header: ({ column }) => ( + + ), + cell: ({ row }) => { + const priority = priorities.find( + (priority) => priority.value === row.getValue("priority"), + ); + + if (!priority) { + return null; + } + + return ( +
+ {priority.icon && ( + + )} + {priority.label} +
+ ); + }, + filterFn: (row, id, value) => { + return value.includes(row.getValue(id)); + }, + }, + { + id: "actions", + cell: ({ row }) => , + }, +]; diff --git a/app/tasks/components/data-table-column-header.tsx b/app/tasks/components/data-table-column-header.tsx new file mode 100644 index 0000000..54881d8 --- /dev/null +++ b/app/tasks/components/data-table-column-header.tsx @@ -0,0 +1,70 @@ +import { Button } from "@/components/ui/button"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; +import { cn } from "@/lib/utils"; +import { + ArrowDownIcon, + ArrowUpIcon, + CaretSortIcon, + EyeNoneIcon, +} from "@radix-ui/react-icons"; +import { Column } from "@tanstack/react-table"; + +interface DataTableColumnHeaderProps + extends React.HTMLAttributes { + column: Column; + title: string; +} + +export function DataTableColumnHeader({ + column, + title, + className, +}: DataTableColumnHeaderProps) { + if (!column.getCanSort()) { + return
{title}
; + } + + return ( +
+ + + + + + column.toggleSorting(false)}> + + Asc + + column.toggleSorting(true)}> + + Desc + + + column.toggleVisibility(false)}> + + Hide + + + +
+ ); +} diff --git a/app/tasks/components/data-table-faceted-filter.tsx b/app/tasks/components/data-table-faceted-filter.tsx new file mode 100644 index 0000000..ca7726a --- /dev/null +++ b/app/tasks/components/data-table-faceted-filter.tsx @@ -0,0 +1,146 @@ +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"; +import { cn } from "@/lib/utils"; +import { CheckIcon, PlusCircledIcon } from "@radix-ui/react-icons"; +import { Column } from "@tanstack/react-table"; +import * as React from "react"; + +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 ( + + + + + + + + + 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 + + + + )} +
+
+
+
+ ); +} diff --git a/app/tasks/components/data-table-pagination.tsx b/app/tasks/components/data-table-pagination.tsx new file mode 100644 index 0000000..ac05079 --- /dev/null +++ b/app/tasks/components/data-table-pagination.tsx @@ -0,0 +1,96 @@ +import { Button } from "@/components/ui/button"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { + ChevronLeftIcon, + ChevronRightIcon, + DoubleArrowLeftIcon, + DoubleArrowRightIcon, +} from "@radix-ui/react-icons"; +import { Table } from "@tanstack/react-table"; + +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

+ +
+
+ Page {table.getState().pagination.pageIndex + 1} of{" "} + {table.getPageCount()} +
+
+ + + + +
+
+
+ ); +} diff --git a/app/tasks/components/data-table-row-actions.tsx b/app/tasks/components/data-table-row-actions.tsx new file mode 100644 index 0000000..37ef0f6 --- /dev/null +++ b/app/tasks/components/data-table-row-actions.tsx @@ -0,0 +1,67 @@ +"use client"; + +import { Button } from "@/components/ui/button"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuRadioGroup, + DropdownMenuRadioItem, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuSub, + DropdownMenuSubContent, + DropdownMenuSubTrigger, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; +import { DotsHorizontalIcon } from "@radix-ui/react-icons"; +import { Row } from "@tanstack/react-table"; +import { labels } from "../data/data"; +import { taskSchema } from "../data/schema"; + +interface DataTableRowActionsProps { + row: Row; +} + +export function DataTableRowActions({ + row, +}: DataTableRowActionsProps) { + const task = taskSchema.parse(row.original); + + return ( + + + + + + Edit + Make a copy + Favorite + + + Labels + + + {labels.map((label) => ( + + {label.label} + + ))} + + + + + + Delete + ⌘⌫ + + + + ); +} diff --git a/app/tasks/components/data-table-toolbar.tsx b/app/tasks/components/data-table-toolbar.tsx new file mode 100644 index 0000000..b57903b --- /dev/null +++ b/app/tasks/components/data-table-toolbar.tsx @@ -0,0 +1,59 @@ +"use client"; + +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Cross2Icon } from "@radix-ui/react-icons"; +import { Table } from "@tanstack/react-table"; +import { priorities, statuses } from "../data/data"; +import { DataTableFacetedFilter } from "./data-table-faceted-filter"; +import { DataTableViewOptions } from "./data-table-view-options"; + +interface DataTableToolbarProps { + table: Table; +} + +export function DataTableToolbar({ + table, +}: DataTableToolbarProps) { + const isFiltered = table.getState().columnFilters.length > 0; + + return ( +
+
+ + table.getColumn("title")?.setFilterValue(event.target.value) + } + className="h-8 w-[150px] lg:w-[250px]" + /> + {table.getColumn("status") && ( + + )} + {table.getColumn("priority") && ( + + )} + {isFiltered && ( + + )} +
+ +
+ ); +} diff --git a/app/tasks/components/data-table-view-options.tsx b/app/tasks/components/data-table-view-options.tsx new file mode 100644 index 0000000..2b053a2 --- /dev/null +++ b/app/tasks/components/data-table-view-options.tsx @@ -0,0 +1,58 @@ +"use client"; + +import { Button } from "@/components/ui/button"; +import { + DropdownMenu, + DropdownMenuCheckboxItem, + DropdownMenuContent, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; +import { MixerHorizontalIcon } from "@radix-ui/react-icons"; +import { Table } from "@tanstack/react-table"; + +interface DataTableViewOptionsProps { + table: Table; +} + +export function DataTableViewOptions({ + table, +}: DataTableViewOptionsProps) { + return ( + + + + + + Toggle columns + + {table + .getAllColumns() + .filter( + (column) => + typeof column.accessorFn !== "undefined" && column.getCanHide(), + ) + .map((column) => { + return ( + column.toggleVisibility(!!value)} + > + {column.id} + + ); + })} + + + ); +} diff --git a/app/tasks/components/data-table.tsx b/app/tasks/components/data-table.tsx new file mode 100644 index 0000000..5943590 --- /dev/null +++ b/app/tasks/components/data-table.tsx @@ -0,0 +1,124 @@ +"use client"; + +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; +import { + ColumnDef, + ColumnFiltersState, + SortingState, + VisibilityState, + flexRender, + getCoreRowModel, + getFacetedRowModel, + getFacetedUniqueValues, + getFilteredRowModel, + getPaginationRowModel, + getSortedRowModel, + useReactTable, +} from "@tanstack/react-table"; +import * as React from "react"; +import { DataTablePagination } from "./data-table-pagination"; +import { DataTableToolbar } from "./data-table-toolbar"; + +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/app/tasks/data/data.tsx b/app/tasks/data/data.tsx new file mode 100644 index 0000000..d46890a --- /dev/null +++ b/app/tasks/data/data.tsx @@ -0,0 +1,71 @@ +import { + ArrowDownIcon, + ArrowRightIcon, + ArrowUpIcon, + CheckCircledIcon, + CircleIcon, + CrossCircledIcon, + QuestionMarkCircledIcon, + StopwatchIcon, +} from "@radix-ui/react-icons"; + +export const labels = [ + { + value: "bug", + label: "Bug", + }, + { + value: "feature", + label: "Feature", + }, + { + value: "documentation", + label: "Documentation", + }, +]; + +export const statuses = [ + { + value: "backlog", + label: "Backlog", + icon: QuestionMarkCircledIcon, + }, + { + value: "todo", + label: "Todo", + icon: CircleIcon, + }, + { + value: "in progress", + label: "In Progress", + icon: StopwatchIcon, + }, + { + value: "done", + label: "Done", + icon: CheckCircledIcon, + }, + { + value: "canceled", + label: "Canceled", + icon: CrossCircledIcon, + }, +]; + +export const priorities = [ + { + label: "Low", + value: "low", + icon: ArrowDownIcon, + }, + { + label: "Medium", + value: "medium", + icon: ArrowRightIcon, + }, + { + label: "High", + value: "high", + icon: ArrowUpIcon, + }, +]; diff --git a/app/tasks/data/schema.ts b/app/tasks/data/schema.ts new file mode 100644 index 0000000..8cd11b0 --- /dev/null +++ b/app/tasks/data/schema.ts @@ -0,0 +1,13 @@ +import { z } from "zod"; + +// We're keeping a simple non-relational schema here. +// IRL, you will have a schema for your data models. +export const taskSchema = z.object({ + id: z.string(), + title: z.string(), + status: z.string(), + label: z.string(), + priority: z.string(), +}); + +export type Task = z.infer; diff --git a/app/tasks/data/tasks.json b/app/tasks/data/tasks.json new file mode 100644 index 0000000..2d10a4a --- /dev/null +++ b/app/tasks/data/tasks.json @@ -0,0 +1,702 @@ +[ + { + "id": "TASK-8782", + "title": "You can't compress the program without quantifying the open-source SSD pixel!", + "status": "in progress", + "label": "documentation", + "priority": "medium" + }, + { + "id": "TASK-7878", + "title": "Try to calculate the EXE feed, maybe it will index the multi-byte pixel!", + "status": "backlog", + "label": "documentation", + "priority": "medium" + }, + { + "id": "TASK-7839", + "title": "We need to bypass the neural TCP card!", + "status": "todo", + "label": "bug", + "priority": "high" + }, + { + "id": "TASK-5562", + "title": "The SAS interface is down, bypass the open-source pixel so we can back up the PNG bandwidth!", + "status": "backlog", + "label": "feature", + "priority": "medium" + }, + { + "id": "TASK-8686", + "title": "I'll parse the wireless SSL protocol, that should driver the API panel!", + "status": "canceled", + "label": "feature", + "priority": "medium" + }, + { + "id": "TASK-1280", + "title": "Use the digital TLS panel, then you can transmit the haptic system!", + "status": "done", + "label": "bug", + "priority": "high" + }, + { + "id": "TASK-7262", + "title": "The UTF8 application is down, parse the neural bandwidth so we can back up the PNG firewall!", + "status": "done", + "label": "feature", + "priority": "high" + }, + { + "id": "TASK-1138", + "title": "Generating the driver won't do anything, we need to quantify the 1080p SMTP bandwidth!", + "status": "in progress", + "label": "feature", + "priority": "medium" + }, + { + "id": "TASK-7184", + "title": "We need to program the back-end THX pixel!", + "status": "todo", + "label": "feature", + "priority": "low" + }, + { + "id": "TASK-5160", + "title": "Calculating the bus won't do anything, we need to navigate the back-end JSON protocol!", + "status": "in progress", + "label": "documentation", + "priority": "high" + }, + { + "id": "TASK-5618", + "title": "Generating the driver won't do anything, we need to index the online SSL application!", + "status": "done", + "label": "documentation", + "priority": "medium" + }, + { + "id": "TASK-6699", + "title": "I'll transmit the wireless JBOD capacitor, that should hard drive the SSD feed!", + "status": "backlog", + "label": "documentation", + "priority": "medium" + }, + { + "id": "TASK-2858", + "title": "We need to override the online UDP bus!", + "status": "backlog", + "label": "bug", + "priority": "medium" + }, + { + "id": "TASK-9864", + "title": "I'll reboot the 1080p FTP panel, that should matrix the HEX hard drive!", + "status": "done", + "label": "bug", + "priority": "high" + }, + { + "id": "TASK-8404", + "title": "We need to generate the virtual HEX alarm!", + "status": "in progress", + "label": "bug", + "priority": "low" + }, + { + "id": "TASK-5365", + "title": "Backing up the pixel won't do anything, we need to transmit the primary IB array!", + "status": "in progress", + "label": "documentation", + "priority": "low" + }, + { + "id": "TASK-1780", + "title": "The CSS feed is down, index the bluetooth transmitter so we can compress the CLI protocol!", + "status": "todo", + "label": "documentation", + "priority": "high" + }, + { + "id": "TASK-6938", + "title": "Use the redundant SCSI application, then you can hack the optical alarm!", + "status": "todo", + "label": "documentation", + "priority": "high" + }, + { + "id": "TASK-9885", + "title": "We need to compress the auxiliary VGA driver!", + "status": "backlog", + "label": "bug", + "priority": "high" + }, + { + "id": "TASK-3216", + "title": "Transmitting the transmitter won't do anything, we need to compress the virtual HDD sensor!", + "status": "backlog", + "label": "documentation", + "priority": "medium" + }, + { + "id": "TASK-9285", + "title": "The IP monitor is down, copy the haptic alarm so we can generate the HTTP transmitter!", + "status": "todo", + "label": "bug", + "priority": "high" + }, + { + "id": "TASK-1024", + "title": "Overriding the microchip won't do anything, we need to transmit the digital OCR transmitter!", + "status": "in progress", + "label": "documentation", + "priority": "low" + }, + { + "id": "TASK-7068", + "title": "You can't generate the capacitor without indexing the wireless HEX pixel!", + "status": "canceled", + "label": "bug", + "priority": "low" + }, + { + "id": "TASK-6502", + "title": "Navigating the microchip won't do anything, we need to bypass the back-end SQL bus!", + "status": "todo", + "label": "bug", + "priority": "high" + }, + { + "id": "TASK-5326", + "title": "We need to hack the redundant UTF8 transmitter!", + "status": "todo", + "label": "bug", + "priority": "low" + }, + { + "id": "TASK-6274", + "title": "Use the virtual PCI circuit, then you can parse the bluetooth alarm!", + "status": "canceled", + "label": "documentation", + "priority": "low" + }, + { + "id": "TASK-1571", + "title": "I'll input the neural DRAM circuit, that should protocol the SMTP interface!", + "status": "in progress", + "label": "feature", + "priority": "medium" + }, + { + "id": "TASK-9518", + "title": "Compressing the interface won't do anything, we need to compress the online SDD matrix!", + "status": "canceled", + "label": "documentation", + "priority": "medium" + }, + { + "id": "TASK-5581", + "title": "I'll synthesize the digital COM pixel, that should transmitter the UTF8 protocol!", + "status": "backlog", + "label": "documentation", + "priority": "high" + }, + { + "id": "TASK-2197", + "title": "Parsing the feed won't do anything, we need to copy the bluetooth DRAM bus!", + "status": "todo", + "label": "documentation", + "priority": "low" + }, + { + "id": "TASK-8484", + "title": "We need to parse the solid state UDP firewall!", + "status": "in progress", + "label": "bug", + "priority": "low" + }, + { + "id": "TASK-9892", + "title": "If we back up the application, we can get to the UDP application through the multi-byte THX capacitor!", + "status": "done", + "label": "documentation", + "priority": "high" + }, + { + "id": "TASK-9616", + "title": "We need to synthesize the cross-platform ASCII pixel!", + "status": "in progress", + "label": "feature", + "priority": "medium" + }, + { + "id": "TASK-9744", + "title": "Use the back-end IP card, then you can input the solid state hard drive!", + "status": "done", + "label": "documentation", + "priority": "low" + }, + { + "id": "TASK-1376", + "title": "Generating the alarm won't do anything, we need to generate the mobile IP capacitor!", + "status": "backlog", + "label": "documentation", + "priority": "low" + }, + { + "id": "TASK-7382", + "title": "If we back up the firewall, we can get to the RAM alarm through the primary UTF8 pixel!", + "status": "todo", + "label": "feature", + "priority": "low" + }, + { + "id": "TASK-2290", + "title": "I'll compress the virtual JSON panel, that should application the UTF8 bus!", + "status": "canceled", + "label": "documentation", + "priority": "high" + }, + { + "id": "TASK-1533", + "title": "You can't input the firewall without overriding the wireless TCP firewall!", + "status": "done", + "label": "bug", + "priority": "high" + }, + { + "id": "TASK-4920", + "title": "Bypassing the hard drive won't do anything, we need to input the bluetooth JSON program!", + "status": "in progress", + "label": "bug", + "priority": "high" + }, + { + "id": "TASK-5168", + "title": "If we synthesize the bus, we can get to the IP panel through the virtual TLS array!", + "status": "in progress", + "label": "feature", + "priority": "low" + }, + { + "id": "TASK-7103", + "title": "We need to parse the multi-byte EXE bandwidth!", + "status": "canceled", + "label": "feature", + "priority": "low" + }, + { + "id": "TASK-4314", + "title": "If we compress the program, we can get to the XML alarm through the multi-byte COM matrix!", + "status": "in progress", + "label": "bug", + "priority": "high" + }, + { + "id": "TASK-3415", + "title": "Use the cross-platform XML application, then you can quantify the solid state feed!", + "status": "todo", + "label": "feature", + "priority": "high" + }, + { + "id": "TASK-8339", + "title": "Try to calculate the DNS interface, maybe it will input the bluetooth capacitor!", + "status": "in progress", + "label": "feature", + "priority": "low" + }, + { + "id": "TASK-6995", + "title": "Try to hack the XSS bandwidth, maybe it will override the bluetooth matrix!", + "status": "todo", + "label": "feature", + "priority": "high" + }, + { + "id": "TASK-8053", + "title": "If we connect the program, we can get to the UTF8 matrix through the digital UDP protocol!", + "status": "todo", + "label": "feature", + "priority": "medium" + }, + { + "id": "TASK-4336", + "title": "If we synthesize the microchip, we can get to the SAS sensor through the optical UDP program!", + "status": "todo", + "label": "documentation", + "priority": "low" + }, + { + "id": "TASK-8790", + "title": "I'll back up the optical COM alarm, that should alarm the RSS capacitor!", + "status": "done", + "label": "bug", + "priority": "medium" + }, + { + "id": "TASK-8980", + "title": "Try to navigate the SQL transmitter, maybe it will back up the virtual firewall!", + "status": "canceled", + "label": "bug", + "priority": "low" + }, + { + "id": "TASK-7342", + "title": "Use the neural CLI card, then you can parse the online port!", + "status": "backlog", + "label": "documentation", + "priority": "low" + }, + { + "id": "TASK-5608", + "title": "I'll hack the haptic SSL program, that should bus the UDP transmitter!", + "status": "canceled", + "label": "documentation", + "priority": "low" + }, + { + "id": "TASK-1606", + "title": "I'll generate the bluetooth PNG firewall, that should pixel the SSL driver!", + "status": "done", + "label": "feature", + "priority": "medium" + }, + { + "id": "TASK-7872", + "title": "Transmitting the circuit won't do anything, we need to reboot the 1080p RSS monitor!", + "status": "canceled", + "label": "feature", + "priority": "medium" + }, + { + "id": "TASK-4167", + "title": "Use the cross-platform SMS circuit, then you can synthesize the optical feed!", + "status": "canceled", + "label": "bug", + "priority": "medium" + }, + { + "id": "TASK-9581", + "title": "You can't index the port without hacking the cross-platform XSS monitor!", + "status": "backlog", + "label": "documentation", + "priority": "low" + }, + { + "id": "TASK-8806", + "title": "We need to bypass the back-end SSL panel!", + "status": "done", + "label": "bug", + "priority": "medium" + }, + { + "id": "TASK-6542", + "title": "Try to quantify the RSS firewall, maybe it will quantify the open-source system!", + "status": "done", + "label": "feature", + "priority": "low" + }, + { + "id": "TASK-6806", + "title": "The VGA protocol is down, reboot the back-end matrix so we can parse the CSS panel!", + "status": "canceled", + "label": "documentation", + "priority": "low" + }, + { + "id": "TASK-9549", + "title": "You can't bypass the bus without connecting the neural JBOD bus!", + "status": "todo", + "label": "feature", + "priority": "high" + }, + { + "id": "TASK-1075", + "title": "Backing up the driver won't do anything, we need to parse the redundant RAM pixel!", + "status": "done", + "label": "feature", + "priority": "medium" + }, + { + "id": "TASK-1427", + "title": "Use the auxiliary PCI circuit, then you can calculate the cross-platform interface!", + "status": "done", + "label": "documentation", + "priority": "high" + }, + { + "id": "TASK-1907", + "title": "Hacking the circuit won't do anything, we need to back up the online DRAM system!", + "status": "todo", + "label": "documentation", + "priority": "high" + }, + { + "id": "TASK-4309", + "title": "If we generate the system, we can get to the TCP sensor through the optical GB pixel!", + "status": "backlog", + "label": "bug", + "priority": "medium" + }, + { + "id": "TASK-3973", + "title": "I'll parse the back-end ADP array, that should bandwidth the RSS bandwidth!", + "status": "todo", + "label": "feature", + "priority": "medium" + }, + { + "id": "TASK-7962", + "title": "Use the wireless RAM program, then you can hack the cross-platform feed!", + "status": "canceled", + "label": "bug", + "priority": "low" + }, + { + "id": "TASK-3360", + "title": "You can't quantify the program without synthesizing the neural OCR interface!", + "status": "done", + "label": "feature", + "priority": "medium" + }, + { + "id": "TASK-9887", + "title": "Use the auxiliary ASCII sensor, then you can connect the solid state port!", + "status": "backlog", + "label": "bug", + "priority": "medium" + }, + { + "id": "TASK-3649", + "title": "I'll input the virtual USB system, that should circuit the DNS monitor!", + "status": "in progress", + "label": "feature", + "priority": "medium" + }, + { + "id": "TASK-3586", + "title": "If we quantify the circuit, we can get to the CLI feed through the mobile SMS hard drive!", + "status": "in progress", + "label": "bug", + "priority": "low" + }, + { + "id": "TASK-5150", + "title": "I'll hack the wireless XSS port, that should transmitter the IP interface!", + "status": "canceled", + "label": "feature", + "priority": "medium" + }, + { + "id": "TASK-3652", + "title": "The SQL interface is down, override the optical bus so we can program the ASCII interface!", + "status": "backlog", + "label": "feature", + "priority": "low" + }, + { + "id": "TASK-6884", + "title": "Use the digital PCI circuit, then you can synthesize the multi-byte microchip!", + "status": "canceled", + "label": "feature", + "priority": "high" + }, + { + "id": "TASK-1591", + "title": "We need to connect the mobile XSS driver!", + "status": "in progress", + "label": "feature", + "priority": "high" + }, + { + "id": "TASK-3802", + "title": "Try to override the ASCII protocol, maybe it will parse the virtual matrix!", + "status": "in progress", + "label": "feature", + "priority": "low" + }, + { + "id": "TASK-7253", + "title": "Programming the capacitor won't do anything, we need to bypass the neural IB hard drive!", + "status": "backlog", + "label": "bug", + "priority": "high" + }, + { + "id": "TASK-9739", + "title": "We need to hack the multi-byte HDD bus!", + "status": "done", + "label": "documentation", + "priority": "medium" + }, + { + "id": "TASK-4424", + "title": "Try to hack the HEX alarm, maybe it will connect the optical pixel!", + "status": "in progress", + "label": "documentation", + "priority": "medium" + }, + { + "id": "TASK-3922", + "title": "You can't back up the capacitor without generating the wireless PCI program!", + "status": "backlog", + "label": "bug", + "priority": "low" + }, + { + "id": "TASK-4921", + "title": "I'll index the open-source IP feed, that should system the GB application!", + "status": "canceled", + "label": "bug", + "priority": "low" + }, + { + "id": "TASK-5814", + "title": "We need to calculate the 1080p AGP feed!", + "status": "backlog", + "label": "bug", + "priority": "high" + }, + { + "id": "TASK-2645", + "title": "Synthesizing the system won't do anything, we need to navigate the multi-byte HDD firewall!", + "status": "todo", + "label": "documentation", + "priority": "medium" + }, + { + "id": "TASK-4535", + "title": "Try to copy the JSON circuit, maybe it will connect the wireless feed!", + "status": "in progress", + "label": "feature", + "priority": "low" + }, + { + "id": "TASK-4463", + "title": "We need to copy the solid state AGP monitor!", + "status": "done", + "label": "documentation", + "priority": "low" + }, + { + "id": "TASK-9745", + "title": "If we connect the protocol, we can get to the GB system through the bluetooth PCI microchip!", + "status": "canceled", + "label": "feature", + "priority": "high" + }, + { + "id": "TASK-2080", + "title": "If we input the bus, we can get to the RAM matrix through the auxiliary RAM card!", + "status": "todo", + "label": "bug", + "priority": "medium" + }, + { + "id": "TASK-3838", + "title": "I'll bypass the online TCP application, that should panel the AGP system!", + "status": "backlog", + "label": "bug", + "priority": "high" + }, + { + "id": "TASK-1340", + "title": "We need to navigate the virtual PNG circuit!", + "status": "todo", + "label": "bug", + "priority": "medium" + }, + { + "id": "TASK-6665", + "title": "If we parse the monitor, we can get to the SSD hard drive through the cross-platform AGP alarm!", + "status": "canceled", + "label": "feature", + "priority": "low" + }, + { + "id": "TASK-7585", + "title": "If we calculate the hard drive, we can get to the SSL program through the multi-byte CSS microchip!", + "status": "backlog", + "label": "feature", + "priority": "low" + }, + { + "id": "TASK-6319", + "title": "We need to copy the multi-byte SCSI program!", + "status": "backlog", + "label": "bug", + "priority": "high" + }, + { + "id": "TASK-4369", + "title": "Try to input the SCSI bus, maybe it will generate the 1080p pixel!", + "status": "backlog", + "label": "bug", + "priority": "high" + }, + { + "id": "TASK-9035", + "title": "We need to override the solid state PNG array!", + "status": "canceled", + "label": "documentation", + "priority": "low" + }, + { + "id": "TASK-3970", + "title": "You can't index the transmitter without quantifying the haptic ASCII card!", + "status": "todo", + "label": "documentation", + "priority": "medium" + }, + { + "id": "TASK-4473", + "title": "You can't bypass the protocol without overriding the neural RSS program!", + "status": "todo", + "label": "documentation", + "priority": "low" + }, + { + "id": "TASK-4136", + "title": "You can't hack the hard drive without hacking the primary JSON program!", + "status": "canceled", + "label": "bug", + "priority": "medium" + }, + { + "id": "TASK-3939", + "title": "Use the back-end SQL firewall, then you can connect the neural hard drive!", + "status": "done", + "label": "feature", + "priority": "low" + }, + { + "id": "TASK-2007", + "title": "I'll input the back-end USB protocol, that should bandwidth the PCI system!", + "status": "backlog", + "label": "bug", + "priority": "high" + }, + { + "id": "TASK-7516", + "title": "Use the primary SQL program, then you can generate the auxiliary transmitter!", + "status": "done", + "label": "documentation", + "priority": "medium" + }, + { + "id": "TASK-6906", + "title": "Try to back up the DRAM system, maybe it will reboot the online transmitter!", + "status": "done", + "label": "feature", + "priority": "high" + }, + { + "id": "TASK-5207", + "title": "The SMS interface is down, copy the bluetooth bus so we can quantify the VGA card!", + "status": "in progress", + "label": "bug", + "priority": "low" + } +] diff --git a/app/tasks/page.tsx b/app/tasks/page.tsx new file mode 100644 index 0000000..7ba2bf2 --- /dev/null +++ b/app/tasks/page.tsx @@ -0,0 +1,27 @@ +import { promises as fs } from "fs"; +import path from "path"; +import { z } from "zod"; +import { columns } from "./components/columns"; +import { DataTable } from "./components/data-table"; +import { taskSchema } from "./data/schema"; + +async function getTasks() { + const data = await fs.readFile( + path.join(process.cwd(), "app/tasks/data/tasks.json"), + ); + + const tasks = JSON.parse(data.toString()); + + return z.array(taskSchema).parse(tasks); +} + +export default async function TaskPage() { + const tasks = await getTasks(); + + return ( +
+

CosmWasm Tracing UI

+ +
+ ); +}