Skip to main content
Glama
views-enhanced.ts9.01 kB
import { ClickUpClient } from './index.js'; import type { CreateViewRequest, UpdateViewRequest, GetViewsFilter, SetViewFiltersRequest, SetViewGroupingRequest, SetViewSortingRequest, UpdateViewSettingsRequest, ViewSharingRequest, ViewFilter, ViewGrouping, ViewSorting // ViewSettings } from '../schemas/views-schemas.js'; export interface ViewResponse { id: string; name: string; type: string; parent: { id: string; type: string; }; grouping: { field: string; dir: number; collapsed: boolean; }; divide: { field: string; dir: number; collapsed: boolean; }; sorting: { fields: Array<{ field: string; dir: number; }>; }; filters: { op: string; fields: Array<{ field: string; operator: string; value: any; }>; search: string; show_closed: boolean; }; columns: Array<{ id: string; name: string; type: string; type_config: any; date_created: string; hide_from_guests: boolean; }>; team_sidebar: { assignees: any[]; assigned_comments: boolean; unassigned_tasks: boolean; }; settings: { show_task_locations: boolean; show_subtasks: number; show_subtask_parent_names: boolean; show_closed_subtasks: boolean; show_assignees: boolean; show_images: boolean; collapse_empty_columns: boolean; show_task_description: boolean; show_task_checklists: boolean; show_task_attachments: boolean; }; creator: number; date_created: string; date_protected: string; orderindex: string; protected: boolean; override_statuses: boolean; required_custom_fields: any[]; visibility: { access: string; password_protected: boolean; password: string; expires: string; }; } export interface ViewListResponse { views: ViewResponse[]; } export class ViewsEnhancedClient extends ClickUpClient { constructor(apiToken: string) { super({ apiToken }); } /** * Create a new view */ async createView(request: CreateViewRequest): Promise<ViewResponse> { const endpoint = this.getParentEndpoint(request.parent_type, request.parent_id); const payload = { name: request.name, type: request.type, parent: { id: request.parent_id, type: request.parent_type }, grouping: request.grouping ? this.formatGrouping(request.grouping) : undefined, sorting: request.sorting ? this.formatSorting(request.sorting) : undefined, filters: request.filters ? this.formatFilters(request.filters) : undefined, settings: request.settings || {}, visibility: { access: request.access || 'private' }, description: request.description }; const response = await this.post<{ view: ViewResponse }>(`${endpoint}/view`, payload); return response.view; } /** * Get views for a parent (space, folder, or list) */ async getViews(filter: GetViewsFilter): Promise<ViewListResponse> { const endpoint = this.getParentEndpoint(filter.parent_type, filter.parent_id); const params = new URLSearchParams(); if (filter.type) params.append('type', filter.type); if (filter.access) params.append('access', filter.access); const queryString = params.toString(); const fullEndpoint = `${endpoint}/view${queryString ? `?${queryString}` : ''}`; const response = await this.get<ViewListResponse>(fullEndpoint); return response; } /** * Get a specific view by ID */ async getView(viewId: string): Promise<ViewResponse> { const response = await this.get<{ view: ViewResponse }>(`/view/${viewId}`); return response.view; } /** * Update an existing view */ async updateView(request: UpdateViewRequest): Promise<ViewResponse> { const updateData: Record<string, any> = {}; if (request.name) updateData.name = request.name; if (request.access) updateData.visibility = { access: request.access }; if (request.grouping) updateData.grouping = this.formatGrouping(request.grouping); if (request.sorting) updateData.sorting = this.formatSorting(request.sorting); if (request.filters) updateData.filters = this.formatFilters(request.filters); if (request.settings) updateData.settings = request.settings; if (request.description) updateData.description = request.description; const response = await this.put<{ view: ViewResponse }>(`/view/${request.view_id}`, updateData); return response.view; } /** * Delete a view */ async deleteView(viewId: string): Promise<{ success: boolean }> { await this.delete(`/view/${viewId}`); return { success: true }; } /** * Set view filters */ async setViewFilters(request: SetViewFiltersRequest): Promise<ViewResponse> { const payload = { filters: this.formatFilters(request.filters) }; const response = await this.put<{ view: ViewResponse }>(`/view/${request.view_id}`, payload); return response.view; } /** * Set view grouping */ async setViewGrouping(request: SetViewGroupingRequest): Promise<ViewResponse> { const payload = { grouping: this.formatGrouping(request.grouping) }; const response = await this.put<{ view: ViewResponse }>(`/view/${request.view_id}`, payload); return response.view; } /** * Set view sorting */ async setViewSorting(request: SetViewSortingRequest): Promise<ViewResponse> { const payload = { sorting: this.formatSorting(request.sorting) }; const response = await this.put<{ view: ViewResponse }>(`/view/${request.view_id}`, payload); return response.view; } /** * Update view settings */ async updateViewSettings(request: UpdateViewSettingsRequest): Promise<ViewResponse> { const payload = { settings: request.settings }; const response = await this.put<{ view: ViewResponse }>(`/view/${request.view_id}`, payload); return response.view; } /** * Update view sharing settings */ async updateViewSharing(request: ViewSharingRequest): Promise<ViewResponse> { const payload = { visibility: { access: request.access, password_protected: !!request.password, password: request.password, expires: request.expires_at ? new Date(request.expires_at * 1000).toISOString() : undefined } }; const response = await this.put<{ view: ViewResponse }>(`/view/${request.view_id}`, payload); return response.view; } /** * Get view tasks (tasks visible in the view) */ async getViewTasks(viewId: string, page?: number): Promise<{ tasks: any[]; last_page: boolean; }> { const params = new URLSearchParams(); if (page) params.append('page', page.toString()); const queryString = params.toString(); const endpoint = `/view/${viewId}/task${queryString ? `?${queryString}` : ''}`; const response = await this.get<{ tasks: any[]; last_page: boolean; }>(endpoint); return response; } /** * Duplicate a view */ async duplicateView(viewId: string, name: string): Promise<ViewResponse> { const payload = { name }; const response = await this.post<{ view: ViewResponse }>(`/view/${viewId}/duplicate`, payload); return response.view; } // Helper methods private getParentEndpoint(parentType: string, parentId: string): string { switch (parentType) { case 'space': return `/space/${parentId}`; case 'folder': return `/folder/${parentId}`; case 'list': return `/list/${parentId}`; default: throw new Error(`Invalid parent type: ${parentType}`); } } private formatGrouping(grouping: ViewGrouping[]): any { if (grouping.length === 0) return {}; const primary = grouping[0]; return { field: primary.field, dir: primary.order === 'asc' ? 1 : -1, collapsed: primary.collapsed }; } private formatSorting(sorting: ViewSorting[]): any { return { fields: sorting.map(sort => ({ field: sort.field, dir: sort.order === 'asc' ? 1 : -1 })) }; } private formatFilters(filters: ViewFilter[]): any { return { op: 'AND', fields: filters.map(filter => ({ field: filter.field, operator: filter.operator, value: filter.value || filter.values })), search: '', show_closed: false }; } /** * Get available view fields for a parent */ async getViewFields(parentType: string, parentId: string): Promise<{ fields: Array<{ id: string; name: string; type: string; type_config: any; }>; }> { const endpoint = this.getParentEndpoint(parentType, parentId); const response = await this.get<{ fields: Array<{ id: string; name: string; type: string; type_config: any; }>; }>(`${endpoint}/field`); return response; } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Chykalophia/ClickUp-MCP-Server---Enhanced'

If you have feedback or need assistance with the MCP directory API, please join our Discord server