Skip to content

Commit

Permalink
chore: update data table
Browse files Browse the repository at this point in the history
  • Loading branch information
shczhen committed Jan 7, 2025
1 parent 10c1e30 commit bd99a67
Show file tree
Hide file tree
Showing 4 changed files with 224 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { Badge } from "@/components/ui/Badge";
import { FileMenu } from "@/components/AppBar/FileMenu";
import { EditMenu } from "@/components/AppBar/EditMenu";
import { HelpMenu } from "@/components/AppBar/HelpMenu";
import { AppStatus } from "@/components/AppBar/AppStatus";
import { cn } from "@/lib/utils";

interface AppBarProps {
Expand Down Expand Up @@ -67,8 +68,16 @@ const AppBar: React.FC<AppBarProps> = ({
</NavigationMenuList>
</NavigationMenu>

{/* Middle part is the status bar. */}
<AppStatus
className={cn(
"flex-1 flex justify-center items-center",
"text-xs text-muted-foreground"
)}
/>

{/* Right part is the logo. */}
<div className="ml-auto flex items-center gap-1.5">
<div className="flex items-center gap-1.5">
<LanguageToggle />
<ModeToggle />
<div
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { SaveIcon, FilePenLineIcon, SaveOffIcon } from "lucide-react";

import { Button } from "@/components/ui/Button";
import { cn } from "@/lib/utils";

// eslint-disable-next-line react-refresh/only-export-components
export enum EAppStatus {
SAVED = "Saved",
UNSAVED = "Unsaved",
EDITING = "Editing",
}

export function AppStatus(props: { className?: string; status?: EAppStatus }) {
const { className, status } = props;
if (!status) {
return null;
}
return (
<div className={cn("flex items-center gap-2", "w-fit", className)}>
<div className="flex items-center">
{status === EAppStatus.SAVED && <SaveIcon className="w-4 h-4 me-2" />}
{status === EAppStatus.UNSAVED && (
<SaveOffIcon className="w-4 h-4 me-2" />
)}
{status === EAppStatus.EDITING && (
<FilePenLineIcon className="w-4 h-4 me-2" />
)}
{status}
</div>
{status === EAppStatus.EDITING && (
<div className="flex items-center text-primary">
<Button variant="outline" size="sm" className="">
<SaveIcon className="w-3 h-3" />
<span className="text-xs">Save</span>
</Button>
</div>
)}
</div>
);
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,24 @@
import * as React from "react";

import {
ColumnDef,
ColumnFiltersState,
SortingState,
flexRender,
getCoreRowModel,
getFilteredRowModel,
getSortedRowModel,
useReactTable,
} from "@tanstack/react-table";
import { BlocksIcon, ArrowBigRightDashIcon } from "lucide-react";
import {
BlocksIcon,
ArrowBigRightDashIcon,
MoreHorizontal,
ArrowUpDown,
ArrowUpIcon,
ArrowDownIcon,
} from "lucide-react";
import { toast } from "sonner";

import {
Table,
Expand All @@ -16,6 +30,14 @@ import {
} from "@/components/ui/table";
import { Badge } from "@/components/ui/Badge";
import { Button } from "@/components/ui/Button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/components/ui/DropdownMenu";
import { cn } from "@/lib/utils";
import { dispatchCustomNodeActionPopup } from "@/utils/popup";

Expand All @@ -40,7 +62,23 @@ export const commonConnectionColumns: ColumnDef<TConnection>[] = [
},
{
accessorKey: "type",
header: "Type",
header: ({ column }) => {
return (
<Button
variant="ghost"
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
>
Type
{column.getIsSorted() === "asc" && (
<ArrowUpIcon className="ml-2 h-4 w-4" />
)}
{column.getIsSorted() === "desc" && (
<ArrowDownIcon className="ml-2 h-4 w-4" />
)}
{!column.getIsSorted() && <ArrowUpDown className="ml-2 h-4 w-4" />}
</Button>
);
},
cell: ({ row }) => {
const type = row.getValue("type") as EConnectionType;
if (!type) return null;
Expand All @@ -60,6 +98,53 @@ export const connectionColumns: ColumnDef<TConnection>[] = [
accessorKey: "target",
header: "Target",
},
{
id: "actions",
header: "Actions",
cell: ({ row }) => {
const connection = row.original;
const { id, source, target, type } = connection;

return (
<DropdownMenu>
<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" className="z-[2000]">
<DropdownMenuLabel>Actions</DropdownMenuLabel>
<DropdownMenuItem
onClick={() => {
toast.info("View Details", {
description:
"Source: " +
source +
", Target: " +
target +
", Type: " +
type,
});
}}
>
View Details
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem
onClick={() => {
toast.info("Delete", {
description: "Delete connection: " + id,
});
}}
>
Delete
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
);
},
},
];

// eslint-disable-next-line react-refresh/only-export-components
Expand Down Expand Up @@ -130,57 +215,78 @@ export function DataTable<TData, TValue>({
data,
className,
}: DataTableProps<TData, TValue> & { className?: string }) {
const [sorting, setSorting] = React.useState<SortingState>([]);
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[]
);

const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
onSortingChange: setSorting,
getSortedRowModel: getSortedRowModel(),
onColumnFiltersChange: setColumnFilters,
getFilteredRowModel: getFilteredRowModel(),
state: {
sorting,
columnFilters,
},
});

return (
<div className={cn("rounded-md border", className)}>
<Table>
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id}>
{headerGroup.headers.map((header) => {
return (
<TableHead key={header.id}>
{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>
))}
<>
<div className={cn("rounded-md border", className)}>
<Table>
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id}>
{headerGroup.headers.map((header) => {
return (
<TableHead key={header.id}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</TableHead>
);
})}
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center">
No results.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
</div>
))}
</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>
</div>
</>
);
}

Expand Down
23 changes: 23 additions & 0 deletions core/src/ten_manager/designer_frontend/src/components/ui/input.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/* eslint-disable max-len */
import * as React from "react";

import { cn } from "@/lib/utils";

const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<"input">>(
({ className, type, ...props }, ref) => {
return (
<input
type={type}
className={cn(
"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
className
)}
ref={ref}
{...props}
/>
);
}
);
Input.displayName = "Input";

export { Input };

0 comments on commit bd99a67

Please sign in to comment.