import { IconPin, IconPinFilled, IconPalette, IconFlag, IconEdit, IconPencil, IconCopy, IconSubtask, IconLink, IconUnlink, IconArrowRight, IconLogicBuffer, IconTrash, } from "@tabler/icons-react"; import { taskRowActionAvailability } from "./task/task-row-action-availability"; import type { CommandItem } from "@/lib/commands/types"; import type { TaskSwitcherItem } from "./task/task-switcher-types"; import type { TFunction } from "i18next"; export type TaskCommandContext = { task: TaskSwitcherItem; t: TFunction; isPinned: boolean; disabled?: boolean; colors: CommandItem[]; priorities: CommandItem[]; links: CommandItem[]; nesting: CommandItem[]; steps: CommandItem[]; workflows: CommandItem[]; plugins: CommandItem[]; onPin: () => void; onEdit: () => void; onRename: () => void; onDetach: () => void; onDelete: () => void; }; export function buildSidebarTaskCommands(ctx: TaskCommandContext): CommandItem[] { const { task, t } = ctx; const available = taskRowActionAvailability(task); const group = t("common:commandGroupTasks"); const command = ( id: string, label: string, Icon: typeof IconPin, action?: () => void, ): CommandItem => ({ id, label, group, icon: , action, disabled: ctx.disabled, }); const items = [ command( "task-pin", t(ctx.isPinned ? "task:unpin" : "task:annotationPin"), ctx.isPinned ? IconPinFilled : IconPin, ctx.onPin, ), ]; const choices = (id: string, label: string, Icon: typeof IconPin, children: CommandItem[]) => { if (children.length) items.push({ ...command(id, label, Icon), children }); }; if (available.mark) { choices("task-color", t("task:color"), IconPalette, ctx.colors); choices("task-priority", t("kanban:priority"), IconFlag, ctx.priorities); } if (available.edit) items.push(command("task-edit", t("common:edit"), IconEdit, ctx.onEdit)); items.push(command("task-rename", t("task:rename"), IconPencil, ctx.onRename)); if (available.mark) items.push({ ...command("task-duplicate", t("settings:duplicate"), IconCopy), disabled: true }); if (available.nest) choices("task-nest", t("task:nestUnder"), IconSubtask, ctx.nesting); choices("task-link", t("task:link"), IconLink, ctx.links); if (available.detach) items.push(command("task-detach", t("task:detachFromParent"), IconUnlink, ctx.onDetach)); if (available.move) { choices("task-move", t("task:moveTo"), IconArrowRight, ctx.steps); if (ctx.workflows.length) { items.push( command( "task-change-workflow", t("task:changeWorkflow"), IconLogicBuffer, ctx.workflows[0]?.action, ), ); } } items.push(...ctx.plugins); items.push({ ...command("task-delete", t("task:delete"), IconTrash, ctx.onDelete), destructive: true, }); return items.map((item) => ({ ...item, priority: 0, disabled: item.disabled || ctx.disabled, // An item that names its own context keeps it (a plugin submenu child // carries the trigger it came from); the task title is only the default // second line for everything else. context: item.context ?? task.title, })); }