@alanse/clickup-multi-mcp-server 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Dockerfile +38 -0
- package/LICENSE +21 -0
- package/README.md +470 -0
- package/build/config.js +237 -0
- package/build/index.js +87 -0
- package/build/logger.js +163 -0
- package/build/middleware/security.js +231 -0
- package/build/server.js +288 -0
- package/build/services/clickup/base.js +432 -0
- package/build/services/clickup/bulk.js +180 -0
- package/build/services/clickup/document.js +159 -0
- package/build/services/clickup/folder.js +136 -0
- package/build/services/clickup/index.js +76 -0
- package/build/services/clickup/list.js +191 -0
- package/build/services/clickup/tag.js +239 -0
- package/build/services/clickup/task/index.js +32 -0
- package/build/services/clickup/task/task-attachments.js +105 -0
- package/build/services/clickup/task/task-comments.js +114 -0
- package/build/services/clickup/task/task-core.js +604 -0
- package/build/services/clickup/task/task-custom-fields.js +107 -0
- package/build/services/clickup/task/task-search.js +986 -0
- package/build/services/clickup/task/task-service.js +104 -0
- package/build/services/clickup/task/task-tags.js +113 -0
- package/build/services/clickup/time.js +244 -0
- package/build/services/clickup/types.js +33 -0
- package/build/services/clickup/workspace.js +397 -0
- package/build/services/shared.js +61 -0
- package/build/sse_server.js +277 -0
- package/build/tools/documents.js +489 -0
- package/build/tools/folder.js +331 -0
- package/build/tools/index.js +16 -0
- package/build/tools/list.js +428 -0
- package/build/tools/member.js +106 -0
- package/build/tools/tag.js +833 -0
- package/build/tools/task/attachments.js +357 -0
- package/build/tools/task/attachments.types.js +9 -0
- package/build/tools/task/bulk-operations.js +338 -0
- package/build/tools/task/handlers.js +919 -0
- package/build/tools/task/index.js +30 -0
- package/build/tools/task/main.js +233 -0
- package/build/tools/task/single-operations.js +469 -0
- package/build/tools/task/time-tracking.js +575 -0
- package/build/tools/task/utilities.js +310 -0
- package/build/tools/task/workspace-operations.js +258 -0
- package/build/tools/tool-enhancer.js +37 -0
- package/build/tools/utils.js +12 -0
- package/build/tools/workspace-helper.js +44 -0
- package/build/tools/workspace.js +73 -0
- package/build/utils/color-processor.js +183 -0
- package/build/utils/concurrency-utils.js +248 -0
- package/build/utils/date-utils.js +542 -0
- package/build/utils/resolver-utils.js +135 -0
- package/build/utils/sponsor-service.js +93 -0
- package/build/utils/token-utils.js +49 -0
- package/package.json +77 -0
- package/smithery.yaml +23 -0
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SPDX-FileCopyrightText: © 2025 João Santana <joaosantana@gmail.com>
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*
|
|
5
|
+
* Document service for ClickUp
|
|
6
|
+
*
|
|
7
|
+
* This service provides methods to manage ClickUp documents:
|
|
8
|
+
* - Create documents
|
|
9
|
+
* - Get document details
|
|
10
|
+
* - List documents in a container
|
|
11
|
+
* - List document pages
|
|
12
|
+
* - Get document pages content
|
|
13
|
+
* - Update document pages
|
|
14
|
+
*/
|
|
15
|
+
import { BaseClickUpService, ClickUpServiceError, ErrorCode } from './base.js';
|
|
16
|
+
export class DocumentService extends BaseClickUpService {
|
|
17
|
+
constructor(apiKey, teamId, baseUrl) {
|
|
18
|
+
// Override baseUrl to use v3 API, since Docs are only available in v3
|
|
19
|
+
super(apiKey, teamId, baseUrl || 'https://api.clickup.com/api/v3');
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Helper method to handle errors consistently
|
|
23
|
+
* @param error The error that occurred
|
|
24
|
+
* @param message Optional custom error message
|
|
25
|
+
* @returns A ClickUpServiceError
|
|
26
|
+
*/
|
|
27
|
+
handleError(error, message) {
|
|
28
|
+
if (error instanceof ClickUpServiceError) {
|
|
29
|
+
return error;
|
|
30
|
+
}
|
|
31
|
+
return new ClickUpServiceError(message || `Document service error: ${error.message}`, ErrorCode.UNKNOWN, error);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Creates a new document in a space, folder, or list
|
|
35
|
+
* @param data - Document data with parent object structured as {id: string, type: number}
|
|
36
|
+
* @returns Created document
|
|
37
|
+
*/
|
|
38
|
+
async createDocument(data) {
|
|
39
|
+
try {
|
|
40
|
+
// Log the request data for debugging
|
|
41
|
+
this.logOperation('Creating document with data:', { data });
|
|
42
|
+
const response = await this.client.post(`/workspaces/${this.teamId}/docs`, {
|
|
43
|
+
name: data.name,
|
|
44
|
+
parent: data.parent,
|
|
45
|
+
visibility: data.visibility || 'PRIVATE',
|
|
46
|
+
create_page: data.create_page !== undefined ? data.create_page : true
|
|
47
|
+
});
|
|
48
|
+
return response.data;
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
throw this.handleError(error, 'Failed to create document');
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Creates a new page in a document
|
|
56
|
+
* @param documentId - ID of the document to create the page in
|
|
57
|
+
* @param data - Page data
|
|
58
|
+
* @returns Created page
|
|
59
|
+
*/
|
|
60
|
+
async createPage(documentId, data) {
|
|
61
|
+
try {
|
|
62
|
+
this.logOperation('Creating page in document with data:', { documentId, data });
|
|
63
|
+
const response = await this.client.post(`/workspaces/${this.teamId}/docs/${documentId}/pages`, data);
|
|
64
|
+
return response.data;
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
throw this.handleError(error, `Failed to create page in document ${documentId}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Gets a document by ID
|
|
72
|
+
* @param documentId - ID of the document to retrieve
|
|
73
|
+
* @returns Document details
|
|
74
|
+
*/
|
|
75
|
+
async getDocument(documentId) {
|
|
76
|
+
try {
|
|
77
|
+
this.logOperation('Getting document with ID:', { documentId });
|
|
78
|
+
const response = await this.client.get(`/workspaces/${this.teamId}/docs/${documentId}`);
|
|
79
|
+
return response.data;
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
throw this.handleError(error, `Failed to get document ${documentId}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Lists documents in the workspace with optional filters
|
|
87
|
+
* @param options - Search and filter options
|
|
88
|
+
* @returns List of documents
|
|
89
|
+
*/
|
|
90
|
+
async listDocuments(options = {}) {
|
|
91
|
+
try {
|
|
92
|
+
this.logOperation('Listing documents with options:', { options });
|
|
93
|
+
const response = await this.client.get(`/workspaces/${this.teamId}/docs`, {
|
|
94
|
+
params: options
|
|
95
|
+
});
|
|
96
|
+
return response.data;
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
throw this.handleError(error, 'Failed to list documents');
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Lists all pages in a document with optional depth control
|
|
104
|
+
* @param documentId - ID of the document
|
|
105
|
+
* @param options - Options for page listing
|
|
106
|
+
* @returns List of document pages
|
|
107
|
+
*/
|
|
108
|
+
async listDocumentPages(documentId, options = {}) {
|
|
109
|
+
try {
|
|
110
|
+
this.logOperation('Listing pages for document with ID:', { documentId, options });
|
|
111
|
+
const response = await this.client.get(`/workspaces/${this.teamId}/docs/${documentId}/pageListing`, { params: options });
|
|
112
|
+
return response.data;
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
throw this.handleError(error, `Failed to list pages for document ${documentId}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Gets the content of specific pages in a document
|
|
120
|
+
* @param documentId - ID of the document
|
|
121
|
+
* @param pageIds - Array of page IDs to retrieve
|
|
122
|
+
* @param options - Options for retrieving pages content
|
|
123
|
+
* @returns Document pages with content
|
|
124
|
+
*/
|
|
125
|
+
async getDocumentPages(documentId, pageIds, options = {}) {
|
|
126
|
+
try {
|
|
127
|
+
// Get pages in parallel
|
|
128
|
+
this.logOperation('Getting pages for document with ID:', { documentId, pageIds, options });
|
|
129
|
+
const pagePromises = pageIds.map(pageId => this.client.get(`/workspaces/${this.teamId}/docs/${documentId}/pages/${pageId}`, { params: { ...options, pageIds } }));
|
|
130
|
+
const responses = await Promise.all(pagePromises);
|
|
131
|
+
const pages = responses.map(response => response.data);
|
|
132
|
+
return { pages };
|
|
133
|
+
}
|
|
134
|
+
catch (error) {
|
|
135
|
+
throw this.handleError(error, `Failed to get pages for document ${documentId}`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Updates an existing page in a document
|
|
140
|
+
* @param documentId - ID of the document containing the page
|
|
141
|
+
* @param pageId - ID of the page to update
|
|
142
|
+
* @param data - Updated page data
|
|
143
|
+
* @returns Updated page
|
|
144
|
+
*/
|
|
145
|
+
async updatePage(documentId, pageId, data) {
|
|
146
|
+
try {
|
|
147
|
+
this.logOperation('Updating page in document with ID:', { documentId, pageId, data });
|
|
148
|
+
const response = await this.client.put(`/workspaces/${this.teamId}/docs/${documentId}/pages/${pageId}`, {
|
|
149
|
+
...data,
|
|
150
|
+
content_format: data.content_format || 'text/md',
|
|
151
|
+
content_edit_mode: data.content_edit_mode || 'append'
|
|
152
|
+
});
|
|
153
|
+
return response.data;
|
|
154
|
+
}
|
|
155
|
+
catch (error) {
|
|
156
|
+
throw this.handleError(error, `Failed to update page ${pageId} in document ${documentId}`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SPDX-FileCopyrightText: © 2025 Talib Kareem <taazkareem@icloud.com>
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*
|
|
5
|
+
* ClickUp Folder Service
|
|
6
|
+
*
|
|
7
|
+
* Handles all operations related to folders in ClickUp, including:
|
|
8
|
+
* - Creating folders
|
|
9
|
+
* - Retrieving folders
|
|
10
|
+
* - Updating folders
|
|
11
|
+
* - Deleting folders
|
|
12
|
+
* - Finding folders by name
|
|
13
|
+
*/
|
|
14
|
+
import { BaseClickUpService, ErrorCode, ClickUpServiceError } from './base.js';
|
|
15
|
+
export class FolderService extends BaseClickUpService {
|
|
16
|
+
/**
|
|
17
|
+
* Creates an instance of FolderService
|
|
18
|
+
* @param apiKey - ClickUp API key
|
|
19
|
+
* @param teamId - ClickUp team ID
|
|
20
|
+
* @param baseUrl - Optional custom API URL
|
|
21
|
+
* @param workspaceService - Optional workspace service for lookups
|
|
22
|
+
*/
|
|
23
|
+
constructor(apiKey, teamId, baseUrl, workspaceService) {
|
|
24
|
+
super(apiKey, teamId, baseUrl);
|
|
25
|
+
this.workspaceService = null;
|
|
26
|
+
this.workspaceService = workspaceService || null;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Helper method to handle errors consistently
|
|
30
|
+
* @param error The error that occurred
|
|
31
|
+
* @param message Optional custom error message
|
|
32
|
+
* @returns A ClickUpServiceError
|
|
33
|
+
*/
|
|
34
|
+
handleError(error, message) {
|
|
35
|
+
if (error instanceof ClickUpServiceError) {
|
|
36
|
+
return error;
|
|
37
|
+
}
|
|
38
|
+
return new ClickUpServiceError(message || `Folder service error: ${error.message}`, ErrorCode.UNKNOWN, error);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Create a new folder in a space
|
|
42
|
+
* @param spaceId The ID of the space to create the folder in
|
|
43
|
+
* @param folderData The data for the new folder
|
|
44
|
+
* @returns The created folder
|
|
45
|
+
*/
|
|
46
|
+
async createFolder(spaceId, folderData) {
|
|
47
|
+
try {
|
|
48
|
+
this.logOperation('createFolder', { spaceId, ...folderData });
|
|
49
|
+
const response = await this.client.post(`/space/${spaceId}/folder`, folderData);
|
|
50
|
+
return response.data;
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
throw this.handleError(error, `Failed to create folder in space ${spaceId}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Get a folder by its ID
|
|
58
|
+
* @param folderId The ID of the folder to retrieve
|
|
59
|
+
* @returns The folder details
|
|
60
|
+
*/
|
|
61
|
+
async getFolder(folderId) {
|
|
62
|
+
try {
|
|
63
|
+
this.logOperation('getFolder', { folderId });
|
|
64
|
+
const response = await this.client.get(`/folder/${folderId}`);
|
|
65
|
+
return response.data;
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
throw this.handleError(error, `Failed to get folder ${folderId}`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Update an existing folder
|
|
73
|
+
* @param folderId The ID of the folder to update
|
|
74
|
+
* @param updateData The data to update on the folder
|
|
75
|
+
* @returns The updated folder
|
|
76
|
+
*/
|
|
77
|
+
async updateFolder(folderId, updateData) {
|
|
78
|
+
try {
|
|
79
|
+
this.logOperation('updateFolder', { folderId, ...updateData });
|
|
80
|
+
const response = await this.client.put(`/folder/${folderId}`, updateData);
|
|
81
|
+
return response.data;
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
throw this.handleError(error, `Failed to update folder ${folderId}`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Delete a folder
|
|
89
|
+
* @param folderId The ID of the folder to delete
|
|
90
|
+
* @returns Success indicator
|
|
91
|
+
*/
|
|
92
|
+
async deleteFolder(folderId) {
|
|
93
|
+
try {
|
|
94
|
+
this.logOperation('deleteFolder', { folderId });
|
|
95
|
+
await this.client.delete(`/folder/${folderId}`);
|
|
96
|
+
return {
|
|
97
|
+
success: true
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
throw this.handleError(error, `Failed to delete folder ${folderId}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Get all folders in a space
|
|
106
|
+
* @param spaceId The ID of the space to get folders from
|
|
107
|
+
* @returns Array of folders in the space
|
|
108
|
+
*/
|
|
109
|
+
async getFoldersInSpace(spaceId) {
|
|
110
|
+
this.logOperation('getFoldersInSpace', { spaceId });
|
|
111
|
+
try {
|
|
112
|
+
const response = await this.client.get(`/space/${spaceId}/folder`);
|
|
113
|
+
return response.data.folders;
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
throw this.handleError(error, `Failed to get folders in space ${spaceId}`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Find a folder by its name in a space
|
|
121
|
+
* @param spaceId The ID of the space to search in
|
|
122
|
+
* @param folderName The name of the folder to find
|
|
123
|
+
* @returns The folder if found, otherwise null
|
|
124
|
+
*/
|
|
125
|
+
async findFolderByName(spaceId, folderName) {
|
|
126
|
+
this.logOperation('findFolderByName', { spaceId, folderName });
|
|
127
|
+
try {
|
|
128
|
+
const folders = await this.getFoldersInSpace(spaceId);
|
|
129
|
+
const matchingFolder = folders.find(folder => folder.name.toLowerCase() === folderName.toLowerCase());
|
|
130
|
+
return matchingFolder || null;
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
throw this.handleError(error, `Failed to find folder by name in space ${spaceId}`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SPDX-FileCopyrightText: © 2025 Talib Kareem <taazkareem@icloud.com>
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*
|
|
5
|
+
* ClickUp Service Entry Point
|
|
6
|
+
*
|
|
7
|
+
* This file re-exports all service modules for the ClickUp API integration.
|
|
8
|
+
* It also provides a convenient factory method to create instances of all services.
|
|
9
|
+
*/
|
|
10
|
+
// Export base service components
|
|
11
|
+
export { BaseClickUpService, ClickUpServiceError, ErrorCode } from './base.js';
|
|
12
|
+
// Export type definitions
|
|
13
|
+
export * from './types.js';
|
|
14
|
+
// Export service modules
|
|
15
|
+
export { WorkspaceService } from './workspace.js';
|
|
16
|
+
export { TaskService } from './task/index.js';
|
|
17
|
+
export { ListService } from './list.js';
|
|
18
|
+
export { FolderService } from './folder.js';
|
|
19
|
+
export { ClickUpTagService } from './tag.js';
|
|
20
|
+
export { TimeTrackingService } from './time.js';
|
|
21
|
+
export { DocumentService } from './document.js';
|
|
22
|
+
// Import service classes for the factory function
|
|
23
|
+
import { WorkspaceService } from './workspace.js';
|
|
24
|
+
import { TaskService } from './task/index.js';
|
|
25
|
+
import { ListService } from './list.js';
|
|
26
|
+
import { FolderService } from './folder.js';
|
|
27
|
+
import { ClickUpTagService } from './tag.js';
|
|
28
|
+
import { TimeTrackingService } from './time.js';
|
|
29
|
+
import { Logger } from '../../logger.js';
|
|
30
|
+
import { DocumentService } from './document.js';
|
|
31
|
+
// Singleton logger for ClickUp services
|
|
32
|
+
const logger = new Logger('ClickUpServices');
|
|
33
|
+
/**
|
|
34
|
+
* Factory function to create instances of all ClickUp services
|
|
35
|
+
* @param config Configuration for the services
|
|
36
|
+
* @returns Object containing all service instances
|
|
37
|
+
*/
|
|
38
|
+
export function createClickUpServices(config) {
|
|
39
|
+
const { apiKey, teamId, baseUrl } = config;
|
|
40
|
+
// Log start of overall initialization
|
|
41
|
+
logger.info('Starting ClickUp services initialization', {
|
|
42
|
+
teamId,
|
|
43
|
+
baseUrl: baseUrl || 'https://api.clickup.com/api/v2'
|
|
44
|
+
});
|
|
45
|
+
// Create workspace service first since others depend on it
|
|
46
|
+
logger.info('Initializing ClickUp Workspace service');
|
|
47
|
+
const workspaceService = new WorkspaceService(apiKey, teamId, baseUrl);
|
|
48
|
+
// Initialize remaining services with workspace dependency
|
|
49
|
+
logger.info('Initializing ClickUp Task service');
|
|
50
|
+
const taskService = new TaskService(apiKey, teamId, baseUrl, workspaceService);
|
|
51
|
+
logger.info('Initializing ClickUp List service');
|
|
52
|
+
const listService = new ListService(apiKey, teamId, baseUrl, workspaceService);
|
|
53
|
+
logger.info('Initializing ClickUp Folder service');
|
|
54
|
+
const folderService = new FolderService(apiKey, teamId, baseUrl, workspaceService);
|
|
55
|
+
logger.info('Initializing ClickUp Tag service');
|
|
56
|
+
const tagService = new ClickUpTagService(apiKey, teamId, baseUrl);
|
|
57
|
+
logger.info('Initializing ClickUp Time Tracking service');
|
|
58
|
+
const timeTrackingService = new TimeTrackingService(apiKey, teamId, baseUrl);
|
|
59
|
+
logger.info('Initializing ClickUp Document service');
|
|
60
|
+
const documentService = new DocumentService(apiKey, teamId, baseUrl);
|
|
61
|
+
const services = {
|
|
62
|
+
workspace: workspaceService,
|
|
63
|
+
task: taskService,
|
|
64
|
+
list: listService,
|
|
65
|
+
folder: folderService,
|
|
66
|
+
tag: tagService,
|
|
67
|
+
timeTracking: timeTrackingService,
|
|
68
|
+
document: documentService
|
|
69
|
+
};
|
|
70
|
+
// Log successful completion
|
|
71
|
+
logger.info('All ClickUp services initialized successfully', {
|
|
72
|
+
services: Object.keys(services),
|
|
73
|
+
baseUrl: baseUrl || 'https://api.clickup.com/api/v2'
|
|
74
|
+
});
|
|
75
|
+
return services;
|
|
76
|
+
}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SPDX-FileCopyrightText: © 2025 Talib Kareem <taazkareem@icloud.com>
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*
|
|
5
|
+
* ClickUp List Service
|
|
6
|
+
*
|
|
7
|
+
* Handles all operations related to lists in ClickUp, including:
|
|
8
|
+
* - Creating lists
|
|
9
|
+
* - Retrieving lists
|
|
10
|
+
* - Updating lists
|
|
11
|
+
* - Deleting lists
|
|
12
|
+
* - Finding lists by name
|
|
13
|
+
*/
|
|
14
|
+
import { BaseClickUpService, ErrorCode, ClickUpServiceError } from './base.js';
|
|
15
|
+
export class ListService extends BaseClickUpService {
|
|
16
|
+
constructor(apiKey, teamId, baseUrl, workspaceService) {
|
|
17
|
+
super(apiKey, teamId, baseUrl);
|
|
18
|
+
this.workspaceService = null;
|
|
19
|
+
this.workspaceService = workspaceService || null;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Helper method to handle errors consistently
|
|
23
|
+
* @param error The error that occurred
|
|
24
|
+
* @param message Optional custom error message
|
|
25
|
+
* @returns A ClickUpServiceError
|
|
26
|
+
*/
|
|
27
|
+
handleError(error, message) {
|
|
28
|
+
if (error instanceof ClickUpServiceError) {
|
|
29
|
+
return error;
|
|
30
|
+
}
|
|
31
|
+
return new ClickUpServiceError(message || `List service error: ${error.message}`, ErrorCode.UNKNOWN, error);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Create a new list in a space
|
|
35
|
+
* @param spaceId The ID of the space to create the list in
|
|
36
|
+
* @param listData The data for the new list
|
|
37
|
+
* @returns The created list
|
|
38
|
+
*/
|
|
39
|
+
async createList(spaceId, listData) {
|
|
40
|
+
this.logOperation('createList', { spaceId, ...listData });
|
|
41
|
+
try {
|
|
42
|
+
return await this.makeRequest(async () => {
|
|
43
|
+
const response = await this.client.post(`/space/${spaceId}/list`, listData);
|
|
44
|
+
return response.data;
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
throw this.handleError(error, `Failed to create list in space ${spaceId}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Create a new list in a folder
|
|
53
|
+
* @param folderId The ID of the folder to create the list in
|
|
54
|
+
* @param listData The data for the new list
|
|
55
|
+
* @returns The created list
|
|
56
|
+
*/
|
|
57
|
+
async createListInFolder(folderId, listData) {
|
|
58
|
+
this.logOperation('createListInFolder', { folderId, ...listData });
|
|
59
|
+
try {
|
|
60
|
+
return await this.makeRequest(async () => {
|
|
61
|
+
const response = await this.client.post(`/folder/${folderId}/list`, listData);
|
|
62
|
+
return response.data;
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
throw this.handleError(error, `Failed to create list in folder ${folderId}`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Get a list by ID
|
|
71
|
+
* @param listId The ID of the list to retrieve
|
|
72
|
+
* @returns The requested list
|
|
73
|
+
*/
|
|
74
|
+
async getList(listId) {
|
|
75
|
+
this.logOperation('getList', { listId });
|
|
76
|
+
try {
|
|
77
|
+
return await this.makeRequest(async () => {
|
|
78
|
+
const response = await this.client.get(`/list/${listId}`);
|
|
79
|
+
return response.data;
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
throw this.handleError(error, `Failed to get list ${listId}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Update an existing list
|
|
88
|
+
* @param listId The ID of the list to update
|
|
89
|
+
* @param updateData The data to update on the list
|
|
90
|
+
* @returns The updated list
|
|
91
|
+
*/
|
|
92
|
+
async updateList(listId, updateData) {
|
|
93
|
+
this.logOperation('updateList', { listId, ...updateData });
|
|
94
|
+
try {
|
|
95
|
+
return await this.makeRequest(async () => {
|
|
96
|
+
const response = await this.client.put(`/list/${listId}`, updateData);
|
|
97
|
+
return response.data;
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
throw this.handleError(error, `Failed to update list ${listId}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Delete a list
|
|
106
|
+
* @param listId The ID of the list to delete
|
|
107
|
+
* @returns Success indicator
|
|
108
|
+
*/
|
|
109
|
+
async deleteList(listId) {
|
|
110
|
+
this.logOperation('deleteList', { listId });
|
|
111
|
+
try {
|
|
112
|
+
await this.makeRequest(async () => {
|
|
113
|
+
await this.client.delete(`/list/${listId}`);
|
|
114
|
+
});
|
|
115
|
+
return {
|
|
116
|
+
success: true
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
throw this.handleError(error, `Failed to delete list ${listId}`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Get all lists in a space
|
|
125
|
+
* @param spaceId The ID of the space to get lists from
|
|
126
|
+
* @returns Array of lists in the space
|
|
127
|
+
*/
|
|
128
|
+
async getListsInSpace(spaceId) {
|
|
129
|
+
this.logOperation('getListsInSpace', { spaceId });
|
|
130
|
+
try {
|
|
131
|
+
return await this.makeRequest(async () => {
|
|
132
|
+
const response = await this.client.get(`/space/${spaceId}/list`);
|
|
133
|
+
return response.data.lists;
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
catch (error) {
|
|
137
|
+
throw this.handleError(error, `Failed to get lists in space ${spaceId}`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Get all lists in a folder
|
|
142
|
+
* @param folderId The ID of the folder to get lists from
|
|
143
|
+
* @returns Array of lists in the folder
|
|
144
|
+
*/
|
|
145
|
+
async getListsInFolder(folderId) {
|
|
146
|
+
this.logOperation('getListsInFolder', { folderId });
|
|
147
|
+
try {
|
|
148
|
+
return await this.makeRequest(async () => {
|
|
149
|
+
const response = await this.client.get(`/folder/${folderId}/list`);
|
|
150
|
+
return response.data.lists;
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
catch (error) {
|
|
154
|
+
throw this.handleError(error, `Failed to get lists in folder ${folderId}`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Find a list by its name in a space
|
|
159
|
+
* @param spaceId The ID of the space to search in
|
|
160
|
+
* @param listName The name of the list to find
|
|
161
|
+
* @returns The list if found, otherwise null
|
|
162
|
+
*/
|
|
163
|
+
async findListByNameInSpace(spaceId, listName) {
|
|
164
|
+
this.logOperation('findListByNameInSpace', { spaceId, listName });
|
|
165
|
+
try {
|
|
166
|
+
const lists = await this.getListsInSpace(spaceId);
|
|
167
|
+
const matchingList = lists.find(list => list.name.toLowerCase() === listName.toLowerCase());
|
|
168
|
+
return matchingList || null;
|
|
169
|
+
}
|
|
170
|
+
catch (error) {
|
|
171
|
+
throw this.handleError(error, `Failed to find list by name in space ${spaceId}`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Find a list by its name in a folder
|
|
176
|
+
* @param folderId The ID of the folder to search in
|
|
177
|
+
* @param listName The name of the list to find
|
|
178
|
+
* @returns The list if found, otherwise null
|
|
179
|
+
*/
|
|
180
|
+
async findListByNameInFolder(folderId, listName) {
|
|
181
|
+
this.logOperation('findListByNameInFolder', { folderId, listName });
|
|
182
|
+
try {
|
|
183
|
+
const lists = await this.getListsInFolder(folderId);
|
|
184
|
+
const matchingList = lists.find(list => list.name.toLowerCase() === listName.toLowerCase());
|
|
185
|
+
return matchingList || null;
|
|
186
|
+
}
|
|
187
|
+
catch (error) {
|
|
188
|
+
throw this.handleError(error, `Failed to find list by name in folder ${folderId}`);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|