import { Head, usePage } from '@inertiajs/react'; import { Cell, ColumnDef, ColumnFiltersState, flexRender, getCoreRowModel, getFilteredRowModel, getSortedRowModel, Row, SortingState, useReactTable, VisibilityState, } from '@tanstack/react-table'; import * as Icons from 'lucide-react'; import { MoreHorizontal } from 'lucide-react'; import { useMemo, useState } from 'react'; import { index as automationRulesIndex } from '@/actions/App/Http/Controllers/Settings/AutomationRuleController'; import { CreateAutomationRuleDialog } from '@/components/automation-rules/create-automation-rule-dialog'; import { DeleteAutomationRuleDialog } from '@/components/automation-rules/delete-automation-rule-dialog'; import { EditAutomationRuleDialog } from '@/components/automation-rules/edit-automation-rule-dialog'; import HeadingSmall from '@/components/heading-small'; import { LabelBadges } from '@/components/shared/label-combobox'; import { Badge } from '@/components/ui/badge'; import { Button } from '@/components/ui/button'; import { ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuLabel, ContextMenuTrigger, } from '@/components/ui/context-menu'; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuTrigger, } from '@/components/ui/dropdown-menu'; import { Input } from '@/components/ui/input'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/components/ui/table'; import { useEncryptionKey } from '@/contexts/encryption-key-context'; import AppLayout from '@/layouts/app-layout'; import SettingsLayout from '@/layouts/settings/layout'; import { type BreadcrumbItem } from '@/types'; import { type AutomationRule, getRuleActions } from '@/types/automation-rule'; import { type Category, getCategoryColorClasses } from '@/types/category'; import { type Label } from '@/types/label'; const breadcrumbs: BreadcrumbItem[] = [ { title: 'Automation rules settings', href: automationRulesIndex().url, }, ]; function AutomationRuleActions({ rule, categories, labels, }: { rule: AutomationRule; categories: Category[]; labels: Label[]; }) { const [editOpen, setEditOpen] = useState(false); const [deleteOpen, setDeleteOpen] = useState(false); return ( <> Actions setEditOpen(true)}> Edit setDeleteOpen(true)} variant="destructive" > Delete ); } function AutomationRuleRow({ row, categories, labels, }: { row: Row; categories: Category[]; labels: Label[]; }) { const rule = row.original; const [editOpen, setEditOpen] = useState(false); const [deleteOpen, setDeleteOpen] = useState(false); const [contextMenuOpen, setContextMenuOpen] = useState(false); return ( <> {row .getVisibleCells() .map((cell: Cell) => ( {flexRender( cell.column.columnDef.cell, cell.getContext(), )} ))} Actions setEditOpen(true)}> Edit setDeleteOpen(true)} variant="destructive" > Delete ); } export default function AutomationRules() { const { isKeySet } = useEncryptionKey(); const { automationRules: rawRules } = usePage<{ automationRules: AutomationRule[]; }>().props; // Get categories and labels from globally shared Inertia data const categories = usePage().props.categories as Category[]; const labels = usePage().props.labels as Label[]; const rules = useMemo( () => rawRules.map((rule) => ({ ...rule, rules_json: typeof rule.rules_json === 'string' ? JSON.parse(rule.rules_json) : rule.rules_json, })), [rawRules], ); const [sorting, setSorting] = useState([ { id: 'priority', desc: false, }, ]); const [columnFilters, setColumnFilters] = useState([]); const [columnVisibility, setColumnVisibility] = useState( {}, ); const columns: ColumnDef[] = [ { accessorKey: 'priority', header: 'Priority', cell: ({ row }) => { return (
{row.getValue('priority')}
); }, }, { accessorKey: 'title', header: 'Title', cell: ({ row }) => { return (
{row.getValue('title')}
); }, }, { id: 'actions_display', header: 'Actions', cell: ({ row }) => { const rule = row.original; const actions = getRuleActions(rule); if (actions.type === 'multiple') { return (
{actions.category && ( {(() => { const IconComponent = Icons[ actions.category .icon as keyof typeof Icons ] as Icons.LucideIcon; return IconComponent ? ( ) : null; })()} {actions.category.name} )} {actions.hasLabels && actions.labels && ( )} {actions.hasNote && ( + note )}
); } if (actions.type === 'category' && actions.category) { const colorClasses = getCategoryColorClasses( actions.category.color, ); const IconComponent = Icons[ actions.category.icon as keyof typeof Icons ] as Icons.LucideIcon; return ( {actions.category.name} ); } if (actions.type === 'labels' && actions.labels) { return ; } return ( Add note ); }, }, { id: 'actions', enableHiding: false, cell: ({ row }) => ( ), }, ]; const table = useReactTable({ data: rules, columns, onSortingChange: setSorting, onColumnFiltersChange: setColumnFilters, getCoreRowModel: getCoreRowModel(), getSortedRowModel: getSortedRowModel(), getFilteredRowModel: getFilteredRowModel(), onColumnVisibilityChange: setColumnVisibility, state: { sorting, columnFilters, columnVisibility, }, }); return (
table .getColumn('title') ?.setFilterValue(event.target.value) } className="max-w-sm" />
{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) => ( )) ) : ( No automation rules found. )}
{table.getFilteredRowModel().rows.length}{' '} rule(s) total.
); }