gateway/modules/workflows/methods/methodClickup/methodClickup.py

379 lines
17 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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()