Add Activepieces integration for workflow automation
- Add Activepieces fork with SmoothSchedule custom piece - Create integrations app with Activepieces service layer - Add embed token endpoint for iframe integration - Create Automations page with embedded workflow builder - Add sidebar visibility fix for embed mode - Add list inactive customers endpoint to Public API - Include SmoothSchedule triggers: event created/updated/cancelled - Include SmoothSchedule actions: create/update/cancel events, list resources/services/customers 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
import { taskadeAuth } from '../../';
|
||||
import { createAction } from '@activepieces/pieces-framework';
|
||||
import { taskadeProps } from '../common/props';
|
||||
import { TaskadeAPIClient } from '../common/client';
|
||||
|
||||
export const completeTaskAction = createAction({
|
||||
auth: taskadeAuth,
|
||||
name: 'taskade-complete-task',
|
||||
displayName: 'Complete Task',
|
||||
description: 'Complete a task in a project.',
|
||||
props: {
|
||||
workspace_id: taskadeProps.workspace_id,
|
||||
folder_id: taskadeProps.folder_id,
|
||||
project_id: taskadeProps.project_id,
|
||||
task_id: taskadeProps.task_id,
|
||||
},
|
||||
async run(context) {
|
||||
const { project_id, task_id } = context.propsValue;
|
||||
|
||||
const client = new TaskadeAPIClient(context.auth.secret_text);
|
||||
|
||||
return await client.completeTask(project_id, task_id);
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,68 @@
|
||||
import { taskadeAuth } from '../../';
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { taskadeProps } from '../common/props';
|
||||
import { TaskadeAPIClient } from '../common/client';
|
||||
|
||||
export const createTaskAction = createAction({
|
||||
auth: taskadeAuth,
|
||||
name: 'taskade-create-task',
|
||||
displayName: 'Create Task',
|
||||
description: 'Creates a new task.',
|
||||
props: {
|
||||
workspace_id: taskadeProps.workspace_id,
|
||||
folder_id: taskadeProps.folder_id,
|
||||
project_id: taskadeProps.project_id,
|
||||
content_type: Property.StaticDropdown({
|
||||
displayName: 'Content Type',
|
||||
required: true,
|
||||
defaultValue: 'text/markdown',
|
||||
options: {
|
||||
disabled: false,
|
||||
options: [
|
||||
{
|
||||
label: 'text/markdown',
|
||||
value: 'text/markdown',
|
||||
},
|
||||
{
|
||||
label: 'text/plain',
|
||||
value: 'text/plain',
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
content: Property.LongText({
|
||||
displayName: 'Task Content',
|
||||
required: true,
|
||||
}),
|
||||
placement: Property.StaticDropdown({
|
||||
displayName: 'Placement',
|
||||
description: 'Placement of task in block',
|
||||
required: true,
|
||||
defaultValue: 'afterbegin',
|
||||
options: {
|
||||
disabled: false,
|
||||
options: [
|
||||
{
|
||||
label: 'afterbegin',
|
||||
value: 'afterbegin',
|
||||
},
|
||||
{
|
||||
label: 'beforeend',
|
||||
value: 'beforeend',
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const { project_id, content_type, content, placement } = context.propsValue;
|
||||
|
||||
const client = new TaskadeAPIClient(context.auth.secret_text);
|
||||
|
||||
return await client.createTask(project_id, {
|
||||
content,
|
||||
contentType: content_type,
|
||||
placement,
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,24 @@
|
||||
import { taskadeAuth } from '../../';
|
||||
import { createAction } from '@activepieces/pieces-framework';
|
||||
import { taskadeProps } from '../common/props';
|
||||
import { TaskadeAPIClient } from '../common/client';
|
||||
|
||||
export const deleteTaskAction = createAction({
|
||||
auth: taskadeAuth,
|
||||
name: 'taskade-delete-task',
|
||||
displayName: 'Delete Task',
|
||||
description: 'Delete an existing task in a project.',
|
||||
props: {
|
||||
workspace_id: taskadeProps.workspace_id,
|
||||
folder_id: taskadeProps.folder_id,
|
||||
project_id: taskadeProps.project_id,
|
||||
task_id: taskadeProps.task_id,
|
||||
},
|
||||
async run(context) {
|
||||
const { project_id, task_id } = context.propsValue;
|
||||
|
||||
const client = new TaskadeAPIClient(context.auth.secret_text);
|
||||
|
||||
return await client.deleteTask(project_id, task_id);
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,105 @@
|
||||
import {
|
||||
HttpMessageBody,
|
||||
HttpMethod,
|
||||
QueryParams,
|
||||
httpClient,
|
||||
HttpRequest,
|
||||
AuthenticationType,
|
||||
} from '@activepieces/pieces-common';
|
||||
import {
|
||||
CreateTaskDateParams,
|
||||
CreateTaskParams,
|
||||
ListAPIResponse,
|
||||
ProjectResponse,
|
||||
CreateTaskResponse,
|
||||
WorkspaceFolderResponse,
|
||||
WorkspaceResponse,
|
||||
TaskResponse,
|
||||
} from './types';
|
||||
|
||||
type RequestParams = Record<string, string | number | string[] | undefined>;
|
||||
|
||||
export class TaskadeAPIClient {
|
||||
constructor(private personalToken: string) {}
|
||||
|
||||
async makeRequest<T extends HttpMessageBody>(
|
||||
method: HttpMethod,
|
||||
resourceUri: string,
|
||||
query?: RequestParams,
|
||||
body: any | undefined = undefined,
|
||||
): Promise<T> {
|
||||
const baseUrl = 'https://www.taskade.com/api/v1';
|
||||
const qs: QueryParams = {};
|
||||
|
||||
if (query) {
|
||||
for (const [key, value] of Object.entries(query)) {
|
||||
if (value !== null && value !== undefined) {
|
||||
qs[key] = String(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const request: HttpRequest = {
|
||||
method,
|
||||
url: baseUrl + resourceUri,
|
||||
authentication: {
|
||||
type: AuthenticationType.BEARER_TOKEN,
|
||||
token: this.personalToken,
|
||||
},
|
||||
queryParams: qs,
|
||||
body,
|
||||
};
|
||||
|
||||
const response = await httpClient.sendRequest<T>(request);
|
||||
return response.body;
|
||||
}
|
||||
|
||||
async listWorkspaces(): Promise<ListAPIResponse<WorkspaceResponse>> {
|
||||
return await this.makeRequest(HttpMethod.GET, '/workspaces');
|
||||
}
|
||||
|
||||
async listWorkspaceFolders(
|
||||
workspace_id: string,
|
||||
): Promise<ListAPIResponse<WorkspaceFolderResponse>> {
|
||||
return await this.makeRequest(HttpMethod.GET, `/workspaces/${workspace_id}/folders`);
|
||||
}
|
||||
|
||||
async listProjects(folder_id: string): Promise<ListAPIResponse<ProjectResponse>> {
|
||||
return await this.makeRequest(HttpMethod.GET, `/folders/${folder_id}/projects`);
|
||||
}
|
||||
|
||||
async createTask(projectId: string, params: CreateTaskParams): Promise<CreateTaskResponse> {
|
||||
return await this.makeRequest(HttpMethod.POST, `/projects/${projectId}/tasks`, undefined, {
|
||||
tasks: [params],
|
||||
});
|
||||
}
|
||||
|
||||
async createTaskDate(projectId: string, taskId: string, params: CreateTaskDateParams) {
|
||||
return await this.makeRequest(
|
||||
HttpMethod.PUT,
|
||||
`/projects/${projectId}/tasks/${taskId}/date`,
|
||||
undefined,
|
||||
params,
|
||||
);
|
||||
}
|
||||
|
||||
async listTasks(
|
||||
projectId: string,
|
||||
params: RequestParams,
|
||||
): Promise<ListAPIResponse<TaskResponse>> {
|
||||
return await this.makeRequest(HttpMethod.GET, `/projects/${projectId}/tasks`, params);
|
||||
}
|
||||
|
||||
async completeTask(projectId: string, taskId: string) {
|
||||
return await this.makeRequest(
|
||||
HttpMethod.POST,
|
||||
`/projects/${projectId}/tasks/${taskId}/complete`,
|
||||
undefined,
|
||||
{},
|
||||
);
|
||||
}
|
||||
|
||||
async deleteTask(projectId: string, taskId: string) {
|
||||
return await this.makeRequest(HttpMethod.DELETE, `/projects/${projectId}/tasks/${taskId}`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
import { DropdownOption, Property } from '@activepieces/pieces-framework';
|
||||
import { TaskadeAPIClient } from './client';
|
||||
import { taskadeAuth } from '../..';
|
||||
|
||||
const createEmptyOptions = (placeholder: string) => {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder,
|
||||
};
|
||||
};
|
||||
|
||||
export const taskadeProps = {
|
||||
workspace_id: Property.Dropdown({
|
||||
auth: taskadeAuth,
|
||||
displayName: 'Workspace',
|
||||
refreshers: [],
|
||||
required: true,
|
||||
options: async ({ auth }) => {
|
||||
if (!auth) {
|
||||
return createEmptyOptions('Please connect account first.');
|
||||
}
|
||||
|
||||
const client = new TaskadeAPIClient(auth.secret_text);
|
||||
const response = await client.listWorkspaces();
|
||||
|
||||
const options: DropdownOption<string>[] = [];
|
||||
|
||||
for (const workspace of response.items) {
|
||||
options.push({ label: workspace.name, value: workspace.id });
|
||||
}
|
||||
|
||||
return {
|
||||
disabled: false,
|
||||
options,
|
||||
};
|
||||
},
|
||||
}),
|
||||
folder_id: Property.Dropdown({
|
||||
auth: taskadeAuth,
|
||||
displayName: 'Folder',
|
||||
refreshers: ['workspace_id'],
|
||||
required: false,
|
||||
options: async ({ auth, workspace_id }) => {
|
||||
if (!auth) {
|
||||
return createEmptyOptions('Please connect account first.');
|
||||
}
|
||||
if (!workspace_id) {
|
||||
return createEmptyOptions('Please select workspace.');
|
||||
}
|
||||
|
||||
const client = new TaskadeAPIClient(auth.secret_text);
|
||||
const response = await client.listWorkspaceFolders(workspace_id as string);
|
||||
|
||||
const options: DropdownOption<string>[] = [];
|
||||
|
||||
for (const folder of response.items) {
|
||||
options.push({ label: folder.name, value: folder.id });
|
||||
}
|
||||
|
||||
return {
|
||||
disabled: false,
|
||||
options,
|
||||
};
|
||||
},
|
||||
}),
|
||||
project_id: Property.Dropdown({
|
||||
auth: taskadeAuth,
|
||||
displayName: 'Project',
|
||||
refreshers: ['workspace_id', 'folder_id'],
|
||||
required: true,
|
||||
options: async ({ auth, workspace_id, folder_id }) => {
|
||||
if (!auth) {
|
||||
return createEmptyOptions('Please connect account first.');
|
||||
}
|
||||
if (!workspace_id) {
|
||||
return createEmptyOptions('Please select workspace.');
|
||||
}
|
||||
|
||||
const workspaceId = workspace_id as string;
|
||||
const folderId = (folder_id as string) ?? workspaceId;
|
||||
|
||||
const client = new TaskadeAPIClient(auth.secret_text);
|
||||
const response = await client.listProjects(folderId as string);
|
||||
|
||||
const options: DropdownOption<string>[] = [];
|
||||
|
||||
for (const project of response.items) {
|
||||
options.push({ label: project.name, value: project.id });
|
||||
}
|
||||
|
||||
return {
|
||||
disabled: false,
|
||||
options,
|
||||
};
|
||||
},
|
||||
}),
|
||||
task_id: Property.Dropdown({
|
||||
auth: taskadeAuth,
|
||||
displayName: 'Task',
|
||||
refreshers: ['project_id'],
|
||||
required: true,
|
||||
options: async ({ auth, project_id }) => {
|
||||
if (!auth) {
|
||||
return createEmptyOptions('Please connect account first.');
|
||||
}
|
||||
if (!project_id) {
|
||||
return createEmptyOptions('Please select project.');
|
||||
}
|
||||
|
||||
const client = new TaskadeAPIClient(auth.secret_text);
|
||||
const options: DropdownOption<string>[] = [];
|
||||
|
||||
let after;
|
||||
let moreTasks = true;
|
||||
while (moreTasks) {
|
||||
const response = await client.listTasks(project_id as string, { limit: 100, after });
|
||||
if (response.items.length === 0) {
|
||||
moreTasks = false;
|
||||
} else {
|
||||
after = response.items[response.items.length - 1].id;
|
||||
for (const task of response.items) {
|
||||
options.push({ label: task.text, value: task.id });
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
disabled: false,
|
||||
options,
|
||||
};
|
||||
},
|
||||
}),
|
||||
};
|
||||
@@ -0,0 +1,42 @@
|
||||
export interface ListAPIResponse<T> {
|
||||
ok: boolean;
|
||||
items: Array<T>;
|
||||
}
|
||||
|
||||
export interface BaseResponse {
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export type WorkspaceResponse = BaseResponse;
|
||||
export type WorkspaceFolderResponse = BaseResponse;
|
||||
export type ProjectResponse = BaseResponse;
|
||||
|
||||
export interface CreateTaskParams {
|
||||
contentType: string;
|
||||
content: string;
|
||||
placement: string;
|
||||
}
|
||||
|
||||
export interface TaskResponse {
|
||||
id: string;
|
||||
parentId: string;
|
||||
text: string;
|
||||
completed: boolean;
|
||||
}
|
||||
|
||||
export interface CreateTaskResponse {
|
||||
ok: boolean;
|
||||
item: TaskResponse[];
|
||||
}
|
||||
|
||||
export interface CreateTaskDateParams {
|
||||
start: {
|
||||
date: string;
|
||||
time: string;
|
||||
};
|
||||
end?: {
|
||||
date: string;
|
||||
time: string;
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user