From 0a45a1f5fb60854f3ef6d7aa5e098cc03f16674b Mon Sep 17 00:00:00 2001 From: Peter Krzyzek Date: Tue, 25 Feb 2025 15:03:17 -0600 Subject: [PATCH] first commit --- f/app_custom/folder.meta.yaml | 5 + f/app_groups/folder.meta.yaml | 5 + f/app_themes/folder.meta.yaml | 5 + f/clickup/create_task.deno.ts | 155 +++++++++++ f/clickup/create_task.script.yaml | 21 ++ f/clickup/folder.meta.yaml | 7 + f/clickup/get_task.deno.ts | 205 +++++++++++++++ f/clickup/get_task.script.yaml | 35 +++ f/clickup/rotate_tokens.deno.ts | 132 ++++++++++ f/clickup/rotate_tokens.script.lock | 11 + f/clickup/rotate_tokens.script.yaml | 46 ++++ f/clickup/utils/filter-task-fields.deno.ts | 64 +++++ .../utils/filter-task-fields.script.yaml | 10 + f/clickup_utils/folder.meta.yaml | 6 + f/types/clickup.deno.ts | 241 ++++++++++++++++++ f/types/clickup.script.yaml | 16 ++ f/types/folder.meta.yaml | 6 + f/utils/folder.meta.yaml | 6 + wmill-lock.yaml | 6 + wmill.yaml | 10 + 20 files changed, 992 insertions(+) create mode 100644 f/app_custom/folder.meta.yaml create mode 100644 f/app_groups/folder.meta.yaml create mode 100644 f/app_themes/folder.meta.yaml create mode 100644 f/clickup/create_task.deno.ts create mode 100644 f/clickup/create_task.script.yaml create mode 100644 f/clickup/folder.meta.yaml create mode 100644 f/clickup/get_task.deno.ts create mode 100644 f/clickup/get_task.script.yaml create mode 100644 f/clickup/rotate_tokens.deno.ts create mode 100644 f/clickup/rotate_tokens.script.lock create mode 100644 f/clickup/rotate_tokens.script.yaml create mode 100644 f/clickup/utils/filter-task-fields.deno.ts create mode 100644 f/clickup/utils/filter-task-fields.script.yaml create mode 100644 f/clickup_utils/folder.meta.yaml create mode 100644 f/types/clickup.deno.ts create mode 100644 f/types/clickup.script.yaml create mode 100644 f/types/folder.meta.yaml create mode 100644 f/utils/folder.meta.yaml create mode 100644 wmill-lock.yaml create mode 100644 wmill.yaml diff --git a/f/app_custom/folder.meta.yaml b/f/app_custom/folder.meta.yaml new file mode 100644 index 0000000..573f64a --- /dev/null +++ b/f/app_custom/folder.meta.yaml @@ -0,0 +1,5 @@ +summary: null +display_name: App Custom Components +extra_perms: + g/all: false +owners: [] diff --git a/f/app_groups/folder.meta.yaml b/f/app_groups/folder.meta.yaml new file mode 100644 index 0000000..d224ebe --- /dev/null +++ b/f/app_groups/folder.meta.yaml @@ -0,0 +1,5 @@ +summary: null +display_name: App Groups +extra_perms: + g/all: false +owners: [] diff --git a/f/app_themes/folder.meta.yaml b/f/app_themes/folder.meta.yaml new file mode 100644 index 0000000..7c672ae --- /dev/null +++ b/f/app_themes/folder.meta.yaml @@ -0,0 +1,5 @@ +summary: null +display_name: App Themes +extra_perms: + g/all: false +owners: [] diff --git a/f/clickup/create_task.deno.ts b/f/clickup/create_task.deno.ts new file mode 100644 index 0000000..eda7a8c --- /dev/null +++ b/f/clickup/create_task.deno.ts @@ -0,0 +1,155 @@ +// clickup/create_task.ts +type TaskInput = { + // REQUIRED FIELDS + /** The ID of the list to put this task into */ + list_id: string; + /** Name of the task (max 99840 chars) */ + name: string; + + // OPTIONAL CORE FIELDS + /** Detailed task description (supports markdown) */ + description?: string; + /** Task status must match existing status in List */ + status?: string; + /** Unix timestamp in milliseconds */ + due_date?: number; + /** Unix timestamp in milliseconds */ + start_date?: number; + /** Time estimate in milliseconds */ + time_estimate?: number; + /** Markdown-formatted description */ + markdown_description?: string; + /** Priority level (1-4) */ + priority?: 1 | 2 | 3 | 4; + /** Parent task ID for subtasks */ + parent?: string; + /** Custom task type ID */ + custom_item_id?: number; + + // PEOPLE MANAGEMENT + /** Array of user IDs */ + assignees?: number[]; + /** Notify all task members */ + notify_all?: boolean; + + // TAGS & RELATIONSHIPS + /** Array of tag names */ + tags?: string[]; + /** Task dependencies */ + depends_on?: string[]; + /** Linked task IDs */ + links_to?: string; + + // CUSTOMIZATION + /** Array of custom field objects */ + custom_fields?: { + /** Custom field ID */ + id: string; + /** Field value (type-specific) */ + value: string | number | boolean | string[]; + }[]; + + // VALIDATION FLAGS + /** Enforce required custom fields */ + check_required_custom_fields?: boolean; + + // ADVANCED OPTIONS + /** Team ID for custom task IDs */ + team_id?: number; + /** Custom task ID (requires team_id) */ + custom_task_id?: string; + /** Task creation source (max 6 chars) */ + source?: string; +}; + +// All we need here is the access token. +type ClickupCredentials = { + access_token: string; +}; + +export async function main( + params: TaskInput, + credentials: ClickupCredentials +) { + // 1. Input Validation + if (!params.list_id?.trim()) { + throw new Error("Missing required field: list_id"); + } + + if (!params.name?.trim()) { + throw new Error("Missing required field: name"); + } + + // 2. API Request Configuration + const response = await fetch(`https://api.clickup.com/api/v2/list/${params.list_id}/task`, { + method: "POST", + headers: { + "Content-Type": "application/json", + "accept": 'application/json', + "Authorization": "Bearer " + credentials.access_token + }, + body: JSON.stringify({ + // Required + name: params.name, + + // Core optional parameters + description: params.description, + status: params.status, + due_date: params.due_date, + start_date: params.start_date, + time_estimate: params.time_estimate, + markdown_description: params.markdown_description, + priority: params.priority, + parent: params.parent, + custom_item_id: params.custom_item_id, + + // People management + assignees: params.assignees, + notify_all: params.notify_all, + + // Tags & relationships + tags: params.tags, + depends_on: params.depends_on, + links_to: params.links_to, + + // Customization + custom_fields: params.custom_fields?.map(field => ({ + id: field.id, + value: field.value + })), + + // Validation flags + check_required_custom_fields: params.check_required_custom_fields, + + // Advanced configurations + team_id: params.team_id, + custom_task_id: params.custom_task_id, + source: params.source + }) + + }); + + // 3. Error Handling + if (!response.ok) { + const errorBody = await response.text(); + throw new Error(`ClickUp API Error (${response.status}): ${errorBody}`); + } + + // 4. Response Processing + const result = await response.json(); + + // Validate successful task creation + if (!result?.id) { + throw new Error("Failed to create task: No ID returned"); + } + + return { + task_id: result.id, + url: result.url, + status: result.status?.status || "created", + _metadata: { + clickup_space: result.space?.id, + created_at: new Date().toISOString() + } + }; +} diff --git a/f/clickup/create_task.script.yaml b/f/clickup/create_task.script.yaml new file mode 100644 index 0000000..40e6a7b --- /dev/null +++ b/f/clickup/create_task.script.yaml @@ -0,0 +1,21 @@ +summary: Create Task +description: '' +lock: '' +kind: script +schema: + $schema: 'https://json-schema.org/draft/2020-12/schema' + type: object + properties: + credentials: + type: object + description: '' + default: null + format: resource-clickup_credentials + params: + type: object + description: '' + default: null + format: resource-task_input + required: + - params + - credentials diff --git a/f/clickup/folder.meta.yaml b/f/clickup/folder.meta.yaml new file mode 100644 index 0000000..39427db --- /dev/null +++ b/f/clickup/folder.meta.yaml @@ -0,0 +1,7 @@ +summary: '' +display_name: clickup +extra_perms: + g/all: true + u/peter: true +owners: + - u/peter diff --git a/f/clickup/get_task.deno.ts b/f/clickup/get_task.deno.ts new file mode 100644 index 0000000..24aae88 --- /dev/null +++ b/f/clickup/get_task.deno.ts @@ -0,0 +1,205 @@ +// clickup/get_task.ts +interface TaskResponse { + id: string; + name: string; + description?: string; + text_content?: string; + status?: { + status: string; + color: string; + orderindex: number; + type: "open" | "closed" | "custom"; + }; + orderindex?: string; + date_created?: string; + date_updated?: string; + date_closed?: string | null; + date_done?: string | null; + archived?: boolean; + creator?: { + id: number; + username: string; + email: string; + color: string; + profilePicture?: string; + }; + assignees?: Array<{ + id: number; + username: string; + email: string; + color: string; + initials: string; + profilePicture?: string; + }>; + watchers?: Array<{ + id: number; + username: string; + email: string; + color: string; + initials: string; + profilePicture?: string; + }>; + checklists?: Array<{ + id: string; + name: string; + orderindex: number; + resolved: number; + unresolved: number; + items: Array<{ + id: string; + name: string; + orderindex: number; + assignee?: number; + resolved: boolean; + parent?: string; + date_created: string; + children?: string[]; + }>; + }>; + tags?: Array<{ + name: string; + tag_fg: string; + tag_bg: string; + creator?: number; + }>; + parent?: string | null; + priority?: { + id: string; + priority: "urgent" | "high" | "normal" | "low"; + color: string; + }; + due_date?: string | null; + start_date?: string | null; + time_estimate?: number | null; + time_spent?: number | null; + custom_fields?: Array<{ + id: string; + name: string; + type: string; + type_config: Record; + value: any; + }>; + list?: { + id: string; + name: string; + access: boolean; + }; + project?: { + id: string; + name: string; + hidden: boolean; + access: boolean; + }; + folder?: { + id: string; + name: string; + hidden: boolean; + access: boolean; + }; + space?: { + id: string; + name: string; + }; + url?: string; + permission_level?: string; + custom_item_id?: number | null; + custom_task_ids?: Array<{ + custom_task_id: string; + team_id: string; + }>; + dependencies?: Array<{ + task_id: string; + depends_on: string; + type: number; + date_created: string; + userid: string; + }>; + linked_tasks?: Array<{ + task_id: string; + link_id: string; + date_created: string; + userid: string; + }>; + team_id?: string; + custom_id?: string | null; + attachments?: Array<{ + id: string; + version: string; + date: string; + title: string; + extension: string; + thumbnail_small: string; + thumbnail_large: string; + size: number; + }>; + shared?: Array<{ + id: string; + name: string; + type: string; + access_level: string; + team_id: string; + }>; + followers?: Array<{ + id: number; + username: string; + email: string; + color: string; + initials: string; + profilePicture?: string; + }>; + [key: string]: any; // For future API additions +} + +type FieldSelector = Array; + +// All we need here is the access token. +type ClickupCredentials = { + access_token: string; +}; + +export async function main( + task_id: string, + fields: FieldSelector = ["id", "name", "status", "date_created"], + credentials: ClickupCredentials, +) { + // Input validation + if (!task_id?.trim()) throw new Error("Task ID is required"); + + // API call + const response = await fetch( + `https://api.clickup.com/api/v2/task/${task_id}`, + { + headers: { + "Authorization": credentials.access_token, + }, + }, + ); + + if (!response.ok) { + const error = await response.text(); + throw new Error(`ClickUp Error ${response.status}: ${error}`); + } + + // Full response parsing + const fullTask = await response.json(); + + // Field filtering + return fields.length > 0 ? filterFields(fullTask, fields) : fullTask; +} + +// Recursive field filtering function +function filterFields(obj: any, fields: FieldSelector): any { + return fields.reduce((acc, field) => { + const [root, ...nested] = (field as string).split("."); + + if (obj[root] !== undefined) { + if (nested.length > 0 && typeof obj[root] === "object") { + acc[root] = filterFields(obj[root], [nested.join(".")]); + } else { + acc[root] = obj[root]; + } + } + + return acc; + }, {} as Record); +} diff --git a/f/clickup/get_task.script.yaml b/f/clickup/get_task.script.yaml new file mode 100644 index 0000000..6e81a29 --- /dev/null +++ b/f/clickup/get_task.script.yaml @@ -0,0 +1,35 @@ +summary: Get Task +description: '' +lock: '' +kind: script +schema: + $schema: 'https://json-schema.org/draft/2020-12/schema' + type: object + properties: + credentials: + type: object + description: '' + default: null + format: resource-clickup_credentials + properties: + access_token: + type: string + description: '' + originalType: string + fields: + type: object + description: '' + default: + - id + - name + - status + - date_created + format: resource-field_selector + task_id: + type: string + description: '' + default: null + originalType: string + required: + - task_id + - credentials diff --git a/f/clickup/rotate_tokens.deno.ts b/f/clickup/rotate_tokens.deno.ts new file mode 100644 index 0000000..2f8156e --- /dev/null +++ b/f/clickup/rotate_tokens.deno.ts @@ -0,0 +1,132 @@ +import * as wmill from "jsr:@windmill/windmill"; + +type ClickupCredentials = { + client_id: string; + expires_at: number; + access_token: string; + client_secret: string; +}; + +// Function to initiate OAuth flow and get initial tokens +export async function get_initial_token( + client_id: string, + client_secret: string, + redirect_uri: string, +) { + const state = crypto.randomUUID(); + + const authUrl = `https://app.clickup.com/api?client_id=${encodeURIComponent(client_id) + }&redirect_uri=${encodeURIComponent(redirect_uri)}&state=${encodeURIComponent(state) + }&response_type=code&scope=*`; + + console.log("Please visit this URL to authorize the application:", authUrl); + + return { + auth_url: authUrl, + state: state, + next_step: + "After authorization, you will receive a code in the redirect URI. Use this code with exchange_code_for_token function and verify the state parameter matches.", + }; +} + +// Function to exchange authorization code for tokens +export async function exchange_code_for_token( + code: string, + client_id: string, + client_secret: string, + expected_state?: string, + received_state?: string, +) { + if (expected_state && received_state) { + if (expected_state !== received_state) { + throw new Error("State parameter mismatch - possible CSRF attack"); + } + } + + const formData = new URLSearchParams({ + client_id: client_id, + client_secret: client_secret, + code: code, + grant_type: "authorization_code" + }); + + try { + const response = await fetch("https://api.clickup.com/api/v2/oauth/token", { + method: "POST", + headers: { + "Content-Type": "application/x-www-form-urlencoded", + }, + body: formData.toString(), + }); + + if (!response.ok) { + const errorText = await response.text(); + console.error("Token exchange error details:", { + status: response.status, + statusText: response.statusText, + error: errorText, + requestBody: formData.toString(), + }); + throw new Error( + `Token exchange failed: ${response.status} ${errorText}`, + ); + } + + const tokens = await response.json(); + + const credentials: ClickupCredentials = { + client_id, + client_secret, + access_token: tokens.access_token, + expires_at: Date.now() + (tokens.expires_in * 1000), + }; + + // Using setResource with string path instead of object + await wmill.setResource("f/clickup/clickup_prod_creds", JSON.stringify(credentials)); + + return { + status: "initialized", + expires_at: new Date(credentials.expires_at).toISOString(), + }; + } catch (error) { + console.error("Detailed error:", error); + throw error; + } +} + +export async function main( + clickupResource: ClickupCredentials, + mode: "check" | "refresh" | "initialize" = "check", + code?: string, + redirect_uri?: string, + state?: string, + expected_state?: string, +) { + if (mode === "initialize") { + if (!clickupResource.client_id || !clickupResource.client_secret) { + throw new Error( + "Client ID and Client Secret are required for initialization", + ); + } + if (!redirect_uri) { + throw new Error("Redirect URI is required for initialization"); + } + return await get_initial_token( + clickupResource.client_id, + clickupResource.client_secret, + redirect_uri, + ); + } + + if (!code) { + throw new Error("Clickup oAuth CODE required to get token. Use Initialize step first."); + } + + return await exchange_code_for_token( + code, + clickupResource.client_id, + clickupResource.client_secret, + expected_state, + state, + ); +} \ No newline at end of file diff --git a/f/clickup/rotate_tokens.script.lock b/f/clickup/rotate_tokens.script.lock new file mode 100644 index 0000000..65bcba6 --- /dev/null +++ b/f/clickup/rotate_tokens.script.lock @@ -0,0 +1,11 @@ +{ + "version": "4", + "specifiers": { + "jsr:@windmill/windmill@*": "1.458.2" + }, + "jsr": { + "@windmill/windmill@1.458.2": { + "integrity": "c3188c099b9553cd92c5f3aa2b9a4f500feef31d8222237b527b7751de49558c" + } + } +} diff --git a/f/clickup/rotate_tokens.script.yaml b/f/clickup/rotate_tokens.script.yaml new file mode 100644 index 0000000..2f48709 --- /dev/null +++ b/f/clickup/rotate_tokens.script.yaml @@ -0,0 +1,46 @@ +summary: Rotate Tokens +description: '' +lock: '!inline f/clickup/rotate_tokens.script.lock' +concurrency_time_window_s: 0 +kind: script +schema: + $schema: 'https://json-schema.org/draft/2020-12/schema' + type: object + order: [] + properties: + clickupResource: + type: object + description: '' + default: null + format: resource-clickup_credentials + code: + type: string + description: '' + default: null + originalType: string + expected_state: + type: string + description: '' + default: null + originalType: string + mode: + type: string + description: '' + default: check + enum: + - check + - refresh + - initialize + originalType: enum + redirect_uri: + type: string + description: '' + default: null + originalType: string + state: + type: string + description: '' + default: null + originalType: string + required: + - clickupResource diff --git a/f/clickup/utils/filter-task-fields.deno.ts b/f/clickup/utils/filter-task-fields.deno.ts new file mode 100644 index 0000000..32e8dca --- /dev/null +++ b/f/clickup/utils/filter-task-fields.deno.ts @@ -0,0 +1,64 @@ +// utils/filter-task-fields.ts +import type { TaskResponse } from '../types/clickup'; + +type FieldSelector = Array; +type NestedField = { + field: string; + subfields?: FieldSelector; +}; + +export function filterTaskFields( + task: TaskResponse, + fields: FieldSelector +): Partial { + return fields.reduce((acc, selector) => { + if (typeof selector === 'string') { + handleStringSelector(acc, task, selector); + } else if (selector.subfields) { + handleNestedSelector(acc, task, selector); + } + return acc; + }, {} as Partial); +} + +function handleStringSelector( + acc: Partial, + task: TaskResponse, + selector: string +) { + const [root, ...nested] = selector.split('.'); + + if (task[root as keyof TaskResponse] !== undefined) { + if (nested.length > 0) { + acc[root as keyof TaskResponse] = processNestedField( + task[root as keyof TaskResponse], + nested.join('.') + ); + } else { + acc[root as keyof TaskResponse] = task[root as keyof TaskResponse]; + } + } +} + +function handleNestedSelector( + acc: Partial, + task: TaskResponse, + selector: NestedField +) { + const value = task[selector.field as keyof TaskResponse]; + if (value && typeof value === 'object') { + acc[selector.field as keyof TaskResponse] = Array.isArray(value) + ? value.map(item => filterTaskFields(item as TaskResponse, selector.subfields!)) + : filterTaskFields(value as TaskResponse, selector.subfields!); + } +} + +function processNestedField(value: any, nestedPath: string): any { + const [current, ...remaining] = nestedPath.split('.'); + + if (value[current] === undefined) return undefined; + + return remaining.length > 0 + ? processNestedField(value[current], remaining.join('.')) + : value[current]; +} \ No newline at end of file diff --git a/f/clickup/utils/filter-task-fields.script.yaml b/f/clickup/utils/filter-task-fields.script.yaml new file mode 100644 index 0000000..4d5bc0b --- /dev/null +++ b/f/clickup/utils/filter-task-fields.script.yaml @@ -0,0 +1,10 @@ +summary: Filter Task Fields +description: '' +lock: '' +kind: script +no_main_func: true +schema: + $schema: 'https://json-schema.org/draft/2020-12/schema' + type: object + properties: {} + required: [] diff --git a/f/clickup_utils/folder.meta.yaml b/f/clickup_utils/folder.meta.yaml new file mode 100644 index 0000000..8cf74bd --- /dev/null +++ b/f/clickup_utils/folder.meta.yaml @@ -0,0 +1,6 @@ +summary: null +display_name: clickup_utils +extra_perms: + u/peter: true +owners: + - u/peter diff --git a/f/types/clickup.deno.ts b/f/types/clickup.deno.ts new file mode 100644 index 0000000..523ee08 --- /dev/null +++ b/f/types/clickup.deno.ts @@ -0,0 +1,241 @@ +// types/clickup.d.ts + +/** + * Base Task Interface - Shared mutable fields across operations + * Contains all fields that can be SENT in create/update requests + * and RECEIVED in responses (excluding read-only metadata) + */ +interface TaskBase { + // Core Content + name: string; + description?: string; + text_content?: string; + + // Status & Priority + status?: string; + priority?: 1 | 2 | 3 | 4; + + // Time Management + due_date?: number | null; + start_date?: number | null; + time_estimate?: number | null; + time_spent?: number | null; + + // People & Assignments + assignees?: number[]; + tags?: string[]; + custom_fields?: Array<{ + id: string; + value: any; + }>; + + // Task Relationships + parent?: string | null; + links_to?: string; + + // Advanced Features + markdown_description?: string; + notify_all?: boolean; + check_required_custom_fields?: boolean; + custom_item_id?: number | null; + source?: string; +} + +/** + * Task Creation Parameters + * @see https://developer.clickup.com/reference/createtask + */ +interface TaskCreate extends TaskBase { + /** Required Fields */ + list_id: string; + name: string; + + /** Creation-Specific Fields */ + custom_task_id?: string; + team_id?: number; +} + +/** + * Task Update Parameters + * @see https://developer.clickup.com/reference/updatetask + */ +interface TaskUpdate extends Partial { + /** Required Identifier */ + id: string; + + /** Update-Specific Fields */ + task_revision?: number; + task_template_id?: string; + idempotency_key?: string; +} + +/** + * Full Task Response + * @see https://developer.clickup.com/reference/gettask + */ +interface TaskResponse extends TaskBase { + /** Read-Only Metadata */ + id: string; + url: string; + orderindex: string; + date_created: string; + date_updated: string; + date_closed?: string | null; + date_done?: string | null; + archived: boolean; + + /** System Relationships */ + list: { + id: string; + name: string; + access: boolean; + }; + space: { + id: string; + name: string; + }; + folder: { + id: string; + name: string; + hidden: boolean; + access: boolean; + }; + + /** People & Permissions */ + creator: User; + watchers: User[]; + followers: User[]; + permission_level: string; + shared: SharedAccess[]; + + /** Complex Structures */ + checklists: Checklist[]; + dependencies: Dependency[]; + linked_tasks: LinkedTask[]; + subtasks: TaskResponse[]; + attachments: Attachment[]; + + /** Status Details */ + status: { + status: string; + color: string; + orderindex: number; + type: 'open' | 'closed' | 'custom'; + }; + + /** Priority Details */ + priority: { + id: string; + priority: 'urgent' | 'high' | 'normal' | 'low'; + color: string; + } | null; +} + +// Supporting Interfaces +interface User { + id: number; + username: string; + email: string; + color: string; + initials: string; + profilePicture?: string; +} + +interface Checklist { + id: string; + name: string; + orderindex: number; + resolved: number; + unresolved: number; + items: ChecklistItem[]; +} + +interface ChecklistItem { + id: string; + name: string; + orderindex: number; + assignee?: number; + resolved: boolean; + parent?: string; + date_created: string; + children?: string[]; +} + +interface Tag { + name: string; + tag_fg: string; + tag_bg: string; + creator?: number; +} + +interface Dependency { + task_id: string; + depends_on: string; + type: number; + date_created: string; + userid: string; +} + +interface LinkedTask { + task_id: string; + link_id: string; + date_created: string; + userid: string; +} + +interface CustomField { + id: string; + name: string; + type: string; + type_config: { + [key: string]: any; + options?: Array<{ + id: string; + name: string; + color?: string; + orderindex?: number; + }>; + }; + value: any; +} + +interface Attachment { + id: string; + version: string; + date: string; + title: string; + extension: string; + thumbnail_small: string; + thumbnail_large: string; + size: number; +} + +interface SharedAccess { + id: string; + name: string; + type: string; + access_level: string; + team_id: string; +} + +/** + * Full task hierarchy types + * Ref: https://developer.clickup.com/docs + */ +interface ClickUpHierarchy { + workspace_id: string; + space_id: string; + folder_id?: string; + list_id: string; + task_id: string; +} + +/** + * API error response format + * Ref: https://developer.clickup.com/docs/errors + */ +interface ClickUpError { + err: string; + code: number; + message?: string; +} diff --git a/f/types/clickup.script.yaml b/f/types/clickup.script.yaml new file mode 100644 index 0000000..f20f790 --- /dev/null +++ b/f/types/clickup.script.yaml @@ -0,0 +1,16 @@ +summary: clickup +description: '' +lock: '' +concurrency_time_window_s: 0 +kind: script +no_main_func: true +schema: + $schema: 'https://json-schema.org/draft/2020-12/schema' + type: object + order: + - a + - b + - d + - e + properties: {} + required: [] diff --git a/f/types/folder.meta.yaml b/f/types/folder.meta.yaml new file mode 100644 index 0000000..3f4c6d1 --- /dev/null +++ b/f/types/folder.meta.yaml @@ -0,0 +1,6 @@ +summary: null +display_name: types +extra_perms: + u/peter: true +owners: + - u/peter diff --git a/f/utils/folder.meta.yaml b/f/utils/folder.meta.yaml new file mode 100644 index 0000000..26c6e13 --- /dev/null +++ b/f/utils/folder.meta.yaml @@ -0,0 +1,6 @@ +summary: null +display_name: utils +extra_perms: + u/peter: true +owners: + - u/peter diff --git a/wmill-lock.yaml b/wmill-lock.yaml new file mode 100644 index 0000000..f97633f --- /dev/null +++ b/wmill-lock.yaml @@ -0,0 +1,6 @@ +locks: + f/clickup/create_task: 43a306643623f8d42f2e9432175d2061cb05bd4ac0825972c93559163b773ad0 + f/clickup/get_task: e1ac7c952de428bd53df01621c05ecb3995e38cf5f78de1ab03c6baeda9da760 + f/clickup/rotate_tokens: d0a53e8f1855ab682ebf0cc89d093e8e98db761d9225831c7c9c2d0014f4f6bb + f/clickup/utils/filter-task-fields: a160d19c2fa752fa3828f2c87b498be1e79f383ac271678a7dc51c63a4237b4a + f/types/clickup: eb03485311a666b6410b7a621f063dcc84aee0e3a198a721165abdccdf690fa4 diff --git a/wmill.yaml b/wmill.yaml new file mode 100644 index 0000000..d38463d --- /dev/null +++ b/wmill.yaml @@ -0,0 +1,10 @@ +defaultTs: bun +includes: + - f/** +excludes: [] +codebases: [] +skipVariables: true +skipResources: true +skipSecrets: true +includeSchedules: false +includeTriggers: false