# Copyright (c) 2025 Patrick Motsch # All rights reserved. """ClickUp workflow method — list/search/get/create/update tasks and upload attachments.""" import logging from modules.datamodels.datamodelWorkflowActions import WorkflowActionDefinition, WorkflowActionParameter from modules.shared.frontendTypes import FrontendType from modules.workflows.methods.methodBase import MethodBase from .helpers.connection import ClickupConnectionHelper from .actions.list_tasks import list_tasks from .actions.list_fields import list_fields from .actions.search_tasks import search_tasks from .actions.get_task import get_task from .actions.create_task import create_task from .actions.update_task import update_task from .actions.upload_attachment import upload_attachment logger = logging.getLogger(__name__) class MethodClickup(MethodBase): """ClickUp API actions for automation2 (lists as tables).""" def __init__(self, services): super().__init__(services) self.name = "clickup" self.description = "ClickUp task and list operations" self.connection = ClickupConnectionHelper(self) self._actions = { "listTasks": WorkflowActionDefinition( actionId="clickup.listTasks", description="List tasks in a ClickUp list (virtual path /team/{id}/list/{id})", dynamicMode=True, parameters={ "connectionReference": WorkflowActionParameter( name="connectionReference", type="str", frontendType=FrontendType.USER_CONNECTION, required=True, description="ClickUp connection", ), "pathQuery": WorkflowActionParameter( name="pathQuery", type="str", frontendType=FrontendType.TEXT, required=True, description="Virtual path to list: /team/{teamId}/list/{listId}", ), "page": WorkflowActionParameter( name="page", type="int", frontendType=FrontendType.NUMBER, required=False, default=0, description="Page index", ), "includeClosed": WorkflowActionParameter( name="includeClosed", type="bool", frontendType=FrontendType.CHECKBOX, required=False, default=False, description="Include closed tasks", ), }, execute=list_tasks.__get__(self, self.__class__), ), "listFields": WorkflowActionDefinition( actionId="clickup.listFields", description="List custom and built-in field definitions for a ClickUp list (names, types, ids)", dynamicMode=True, parameters={ "connectionReference": WorkflowActionParameter( name="connectionReference", type="str", frontendType=FrontendType.USER_CONNECTION, required=True, description="ClickUp connection", ), "listId": WorkflowActionParameter( name="listId", type="str", frontendType=FrontendType.TEXT, required=False, description="ClickUp list ID (if set, pathQuery is optional)", ), "pathQuery": WorkflowActionParameter( name="pathQuery", type="str", frontendType=FrontendType.TEXT, required=False, description="Virtual path /team/{teamId}/list/{listId} (same as data source path)", ), }, execute=list_fields.__get__(self, self.__class__), ), "searchTasks": WorkflowActionDefinition( actionId="clickup.searchTasks", description="Search tasks in a ClickUp workspace (team)", dynamicMode=True, parameters={ "connectionReference": WorkflowActionParameter( name="connectionReference", type="str", frontendType=FrontendType.USER_CONNECTION, required=True, description="ClickUp connection", ), "teamId": WorkflowActionParameter( name="teamId", type="str", frontendType=FrontendType.TEXT, required=True, description="Workspace (team) ID", ), "query": WorkflowActionParameter( name="query", type="str", frontendType=FrontendType.TEXT, required=True, description="Search query", ), "page": WorkflowActionParameter( name="page", type="int", frontendType=FrontendType.NUMBER, required=False, default=0, description="Page index", ), "listId": WorkflowActionParameter( name="listId", type="str", frontendType=FrontendType.TEXT, required=False, description=( "If set, tasks are loaded from this list via the list API (not team search). " "Use this to search the selected table." ), ), "includeClosed": WorkflowActionParameter( name="includeClosed", type="bool", frontendType=FrontendType.CHECKBOX, required=False, default=False, description="When listId is set, include closed tasks in list pages.", ), "fullTaskData": WorkflowActionParameter( name="fullTaskData", type="bool", frontendType=FrontendType.CHECKBOX, required=False, default=False, description="If true, return raw ClickUp API task objects (large). Default is a slim payload.", ), "matchNameOnly": WorkflowActionParameter( name="matchNameOnly", type="bool", frontendType=FrontendType.CHECKBOX, required=False, default=True, description="If true, keep only tasks whose title contains the search query (default: true).", ), }, execute=search_tasks.__get__(self, self.__class__), ), "getTask": WorkflowActionDefinition( actionId="clickup.getTask", description="Get a single task by ID", dynamicMode=True, parameters={ "connectionReference": WorkflowActionParameter( name="connectionReference", type="str", frontendType=FrontendType.USER_CONNECTION, required=True, description="ClickUp connection", ), "taskId": WorkflowActionParameter( name="taskId", type="str", frontendType=FrontendType.TEXT, required=False, description="Task ID", ), "pathQuery": WorkflowActionParameter( name="pathQuery", type="str", frontendType=FrontendType.TEXT, required=False, description="Optional virtual path ending in /task/{taskId}", ), }, execute=get_task.__get__(self, self.__class__), ), "createTask": WorkflowActionDefinition( actionId="clickup.createTask", description="Create a task in a list", dynamicMode=True, parameters={ "connectionReference": WorkflowActionParameter( name="connectionReference", type="str", frontendType=FrontendType.USER_CONNECTION, required=True, description="ClickUp connection", ), "listId": WorkflowActionParameter( name="listId", type="str", frontendType=FrontendType.TEXT, required=False, description="List ID (if not using path)", ), "pathQuery": WorkflowActionParameter( name="pathQuery", type="str", frontendType=FrontendType.TEXT, required=False, description="Virtual path to list /team/{teamId}/list/{listId}", ), "name": WorkflowActionParameter( name="name", type="str", frontendType=FrontendType.TEXT, required=True, description="Task name", ), "description": WorkflowActionParameter( name="description", type="str", frontendType=FrontendType.TEXTAREA, required=False, description="Task description", ), "customFieldValues": WorkflowActionParameter( name="customFieldValues", type="str", frontendType=FrontendType.TEXTAREA, required=False, description="Map of ClickUp custom field id to value (merged into custom_fields).", ), "taskFields": WorkflowActionParameter( name="taskFields", type="str", frontendType=FrontendType.TEXTAREA, required=False, description="Optional extra JSON object merged into create payload (overrides standard fields)", ), "taskStatus": WorkflowActionParameter( name="taskStatus", type="str", frontendType=FrontendType.TEXT, required=False, description="ClickUp status name for this list", ), "taskPriority": WorkflowActionParameter( name="taskPriority", type="str", frontendType=FrontendType.TEXT, required=False, description="Priority 1 (urgent)–4 (low), empty to omit", ), "taskDueDateMs": WorkflowActionParameter( name="taskDueDateMs", type="str", frontendType=FrontendType.TEXT, required=False, description="Due date as Unix ms timestamp", ), "taskAssigneeIds": WorkflowActionParameter( name="taskAssigneeIds", type="str", frontendType=FrontendType.TEXTAREA, required=False, description="JSON array of ClickUp user ids, e.g. [123,456]", ), "taskTimeEstimateMs": WorkflowActionParameter( name="taskTimeEstimateMs", type="str", frontendType=FrontendType.TEXT, required=False, description="Time estimate in milliseconds", ), "taskTimeEstimateHours": WorkflowActionParameter( name="taskTimeEstimateHours", type="str", frontendType=FrontendType.TEXT, required=False, description="Time estimate in hours (converted to ms; preferred over taskTimeEstimateMs)", ), }, execute=create_task.__get__(self, self.__class__), ), "updateTask": WorkflowActionDefinition( actionId="clickup.updateTask", description="Update a task (JSON body per ClickUp API)", dynamicMode=True, parameters={ "connectionReference": WorkflowActionParameter( name="connectionReference", type="str", frontendType=FrontendType.USER_CONNECTION, required=True, description="ClickUp connection", ), "taskId": WorkflowActionParameter( name="taskId", type="str", frontendType=FrontendType.TEXT, required=False, description="Task ID", ), "path": WorkflowActionParameter( name="path", type="str", frontendType=FrontendType.TEXT, required=False, description="Optional path ending in /task/{taskId}", ), "taskUpdate": WorkflowActionParameter( name="taskUpdate", type="str", frontendType=FrontendType.TEXTAREA, required=False, description="JSON object for PUT /task/{id} (e.g. {\"name\":\"...\",\"status\":\"...\"}); built from editor rows if empty", ), }, execute=update_task.__get__(self, self.__class__), ), "uploadAttachment": WorkflowActionDefinition( actionId="clickup.uploadAttachment", description="Upload a file attachment to a task", dynamicMode=True, parameters={ "connectionReference": WorkflowActionParameter( name="connectionReference", type="str", frontendType=FrontendType.USER_CONNECTION, required=True, description="ClickUp connection", ), "taskId": WorkflowActionParameter( name="taskId", type="str", frontendType=FrontendType.TEXT, required=False, description="Task ID", ), "path": WorkflowActionParameter( name="path", type="str", frontendType=FrontendType.TEXT, required=False, description="Optional path ending in /task/{taskId}", ), "fileName": WorkflowActionParameter( name="fileName", type="str", frontendType=FrontendType.TEXT, required=False, description="Attachment file name", ), "content": WorkflowActionParameter( name="content", type="Any", frontendType=FrontendType.DOCUMENT_REFERENCE, required=True, description="File from upstream node", ), }, execute=upload_attachment.__get__(self, self.__class__), ), } self._validateActions()