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,77 @@
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { assertNotNullOrUndefined } from '@activepieces/shared';
|
||||
import { todoistRestClient } from '../common/client/rest-client';
|
||||
import {
|
||||
todoistProjectIdDropdown,
|
||||
todoistSectionIdDropdown,
|
||||
} from '../common/props';
|
||||
import { TodoistCreateTaskRequest } from '../common/models';
|
||||
import { todoistAuth } from '../..';
|
||||
|
||||
export const todoistCreateTaskAction = createAction({
|
||||
auth: todoistAuth,
|
||||
name: 'create_task',
|
||||
displayName: 'Create Task',
|
||||
description: 'Create task',
|
||||
props: {
|
||||
project_id: todoistProjectIdDropdown(
|
||||
"Task project ID. If not set, task is put to user's Inbox."
|
||||
),
|
||||
content: Property.LongText({
|
||||
displayName: 'content',
|
||||
description:
|
||||
"The task's content. It may contain some markdown-formatted text and hyperlinks",
|
||||
required: true,
|
||||
}),
|
||||
description: Property.LongText({
|
||||
displayName: 'Description',
|
||||
description:
|
||||
'A description for the task. This value may contain some markdown-formatted text and hyperlinks.',
|
||||
required: false,
|
||||
}),
|
||||
labels: Property.Array({
|
||||
displayName: 'Labels',
|
||||
required: false,
|
||||
description:
|
||||
"The task's labels (a list of names that may represent either personal or shared labels)",
|
||||
}),
|
||||
priority: Property.Number({
|
||||
displayName: 'Priority',
|
||||
description: 'Task priority from 1 (normal) to 4 (urgent)',
|
||||
required: false,
|
||||
}),
|
||||
due_date: Property.ShortText({
|
||||
displayName: 'Due date',
|
||||
description:
|
||||
"Can be either a specific date in YYYY-MM-DD format relative to user's timezone, a specific date and time in RFC3339 format, or a human defined date (e.g. 'next Monday') using local time",
|
||||
required: false,
|
||||
}),
|
||||
section_id: todoistSectionIdDropdown,
|
||||
},
|
||||
|
||||
async run({ auth, propsValue }) {
|
||||
const token = auth.access_token;
|
||||
const {
|
||||
project_id,
|
||||
content,
|
||||
description,
|
||||
labels,
|
||||
priority,
|
||||
due_date,
|
||||
section_id,
|
||||
} = propsValue as TodoistCreateTaskRequest;
|
||||
|
||||
assertNotNullOrUndefined(token, 'token');
|
||||
assertNotNullOrUndefined(content, 'content');
|
||||
return await todoistRestClient.tasks.create({
|
||||
token,
|
||||
project_id,
|
||||
content,
|
||||
description,
|
||||
labels,
|
||||
priority,
|
||||
due_date,
|
||||
section_id,
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,36 @@
|
||||
import { todoistAuth } from '../..';
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { todoistProjectIdDropdown } from '../common/props';
|
||||
import { todoistRestClient } from '../common/client/rest-client';
|
||||
import { assertNotNullOrUndefined } from '@activepieces/shared';
|
||||
|
||||
export const todoistFindTaskAction = createAction({
|
||||
auth: todoistAuth,
|
||||
name: 'find_task',
|
||||
displayName: 'Find Task',
|
||||
description: 'Finds a task by name.',
|
||||
props: {
|
||||
name: Property.ShortText({
|
||||
displayName: 'Name',
|
||||
description: 'The name of the task to search for.',
|
||||
required: true,
|
||||
}),
|
||||
project_id: todoistProjectIdDropdown(
|
||||
'Search for tasks within the selected project. If left blank, then all projects are searched.',
|
||||
),
|
||||
},
|
||||
async run(context) {
|
||||
const token = context.auth.access_token;
|
||||
const { name, project_id } = context.propsValue;
|
||||
|
||||
assertNotNullOrUndefined(token, 'token');
|
||||
const tasks = await todoistRestClient.tasks.list({ token, project_id });
|
||||
|
||||
const matchedTask = tasks.find((task) => task.content == name);
|
||||
if (!matchedTask) {
|
||||
throw new Error('Task not found');
|
||||
} else {
|
||||
return matchedTask;
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,25 @@
|
||||
import { assertNotNullOrUndefined } from '@activepieces/shared';
|
||||
import { todoistAuth } from '../..';
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { todoistRestClient } from '../common/client/rest-client';
|
||||
|
||||
export const todoistMarkTaskCompletedAction = createAction({
|
||||
auth: todoistAuth,
|
||||
name: 'mark_task_completed',
|
||||
displayName: 'Mark Task as Completed',
|
||||
description: 'Marks a task as being completed.',
|
||||
props: {
|
||||
task_id: Property.ShortText({
|
||||
displayName: 'Task ID',
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const token = context.auth.access_token;
|
||||
const { task_id } = context.propsValue;
|
||||
|
||||
assertNotNullOrUndefined(token, 'token');
|
||||
|
||||
return await todoistRestClient.tasks.close({ token, task_id });
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,63 @@
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { assertNotNullOrUndefined } from '@activepieces/shared';
|
||||
import { todoistRestClient } from '../common/client/rest-client';
|
||||
import { todoistAuth } from '../..';
|
||||
|
||||
export const todoistUpdateTaskAction = createAction({
|
||||
auth: todoistAuth,
|
||||
name: 'update_task',
|
||||
displayName: 'Update Task',
|
||||
description: 'Updates an existing task.',
|
||||
props: {
|
||||
task_id: Property.ShortText({
|
||||
displayName: 'Task ID',
|
||||
required: true,
|
||||
}),
|
||||
content: Property.LongText({
|
||||
displayName: 'content',
|
||||
description:
|
||||
"The task's content. It may contain some markdown-formatted text and hyperlinks",
|
||||
required: false,
|
||||
}),
|
||||
description: Property.LongText({
|
||||
displayName: 'Description',
|
||||
description:
|
||||
'A description for the task. This value may contain some markdown-formatted text and hyperlinks.',
|
||||
required: false,
|
||||
}),
|
||||
labels: Property.Array({
|
||||
displayName: 'Labels',
|
||||
required: false,
|
||||
description:
|
||||
"The task's labels (a list of names that may represent either personal or shared labels)",
|
||||
}),
|
||||
priority: Property.Number({
|
||||
displayName: 'Priority',
|
||||
description: 'Task priority from 1 (normal) to 4 (urgent)',
|
||||
required: false,
|
||||
}),
|
||||
due_date: Property.ShortText({
|
||||
displayName: 'Due date',
|
||||
description:
|
||||
"Can be either a specific date in YYYY-MM-DD format relative to user's timezone, a specific date and time in RFC3339 format, or a human defined date (e.g. 'next Monday') using local time",
|
||||
required: false,
|
||||
}),
|
||||
},
|
||||
|
||||
async run({ auth, propsValue }) {
|
||||
const token = auth.access_token;
|
||||
const { task_id, content, description, priority, due_date } = propsValue;
|
||||
const labels = propsValue.labels as string[];
|
||||
|
||||
assertNotNullOrUndefined(token, 'token');
|
||||
return await todoistRestClient.tasks.update({
|
||||
token,
|
||||
task_id,
|
||||
content,
|
||||
description,
|
||||
labels,
|
||||
priority,
|
||||
due_date,
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,189 @@
|
||||
import {
|
||||
HttpRequest,
|
||||
HttpMethod,
|
||||
AuthenticationType,
|
||||
httpClient,
|
||||
} from '@activepieces/pieces-common';
|
||||
import { isNotUndefined, pickBy } from '@activepieces/shared';
|
||||
import {
|
||||
TodoistCreateTaskRequest,
|
||||
TodoistProject,
|
||||
TodoistSection,
|
||||
TodoistTask,
|
||||
TodoistUpdateTaskRequest,
|
||||
} from '../models';
|
||||
|
||||
const API = 'https://api.todoist.com/rest/v2';
|
||||
|
||||
export const todoistRestClient = {
|
||||
projects: {
|
||||
async list({ token }: ProjectsListParams): Promise<TodoistProject[]> {
|
||||
const request: HttpRequest = {
|
||||
method: HttpMethod.GET,
|
||||
url: `${API}/projects`,
|
||||
authentication: {
|
||||
type: AuthenticationType.BEARER_TOKEN,
|
||||
token,
|
||||
},
|
||||
};
|
||||
|
||||
const response = await httpClient.sendRequest<TodoistProject[]>(request);
|
||||
return response.body;
|
||||
},
|
||||
},
|
||||
|
||||
sections: {
|
||||
async list(params: SectionsListPrams): Promise<TodoistSection[]> {
|
||||
const qs: Record<string, any> = {};
|
||||
if (params.project_id) qs['project_id'] = params.project_id;
|
||||
|
||||
const request: HttpRequest = {
|
||||
method: HttpMethod.GET,
|
||||
url: `${API}/sections`,
|
||||
authentication: {
|
||||
type: AuthenticationType.BEARER_TOKEN,
|
||||
token: params.token,
|
||||
},
|
||||
queryParams: qs,
|
||||
};
|
||||
|
||||
const response = await httpClient.sendRequest<TodoistSection[]>(request);
|
||||
return response.body;
|
||||
},
|
||||
},
|
||||
|
||||
tasks: {
|
||||
async create({
|
||||
token,
|
||||
project_id,
|
||||
content,
|
||||
description,
|
||||
labels,
|
||||
priority,
|
||||
due_date,
|
||||
section_id,
|
||||
}: TasksCreateParams): Promise<TodoistTask> {
|
||||
const body: TodoistCreateTaskRequest = {
|
||||
content,
|
||||
project_id,
|
||||
description,
|
||||
labels,
|
||||
priority,
|
||||
section_id,
|
||||
...dueDateParams(due_date),
|
||||
};
|
||||
|
||||
const request: HttpRequest<TodoistCreateTaskRequest> = {
|
||||
method: HttpMethod.POST,
|
||||
url: `${API}/tasks`,
|
||||
authentication: {
|
||||
type: AuthenticationType.BEARER_TOKEN,
|
||||
token,
|
||||
},
|
||||
body,
|
||||
};
|
||||
|
||||
const response = await httpClient.sendRequest<TodoistTask>(request);
|
||||
return response.body;
|
||||
},
|
||||
|
||||
async update(params: TasksUpdateParams): Promise<TodoistTask> {
|
||||
const body: TodoistUpdateTaskRequest = {
|
||||
content: params.content,
|
||||
description: params.description,
|
||||
labels: params.labels?.length === 0 ? undefined : params.labels,
|
||||
priority: params.priority,
|
||||
...dueDateParams(params.due_date),
|
||||
};
|
||||
|
||||
const request: HttpRequest<TodoistUpdateTaskRequest> = {
|
||||
method: HttpMethod.POST,
|
||||
url: `${API}/tasks/${params.task_id}`,
|
||||
authentication: {
|
||||
type: AuthenticationType.BEARER_TOKEN,
|
||||
token: params.token,
|
||||
},
|
||||
body,
|
||||
};
|
||||
|
||||
const response = await httpClient.sendRequest<TodoistTask>(request);
|
||||
return response.body;
|
||||
},
|
||||
|
||||
async list({
|
||||
token,
|
||||
project_id,
|
||||
filter,
|
||||
}: TasksListParams): Promise<TodoistTask[]> {
|
||||
const queryParams = {
|
||||
filter,
|
||||
project_id,
|
||||
};
|
||||
|
||||
const request: HttpRequest = {
|
||||
method: HttpMethod.GET,
|
||||
url: `${API}/tasks`,
|
||||
authentication: {
|
||||
type: AuthenticationType.BEARER_TOKEN,
|
||||
token,
|
||||
},
|
||||
queryParams: pickBy(queryParams, isNotUndefined),
|
||||
};
|
||||
|
||||
const response = await httpClient.sendRequest<TodoistTask[]>(request);
|
||||
return response.body;
|
||||
},
|
||||
|
||||
async close({ token, task_id }: { token: string; task_id: string }) {
|
||||
const request: HttpRequest = {
|
||||
method: HttpMethod.POST,
|
||||
url: `${API}/tasks/${task_id}/close`,
|
||||
authentication: {
|
||||
type: AuthenticationType.BEARER_TOKEN,
|
||||
token,
|
||||
},
|
||||
};
|
||||
|
||||
const response = await httpClient.sendRequest(request);
|
||||
return response.body;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
type ProjectsListParams = {
|
||||
token: string;
|
||||
};
|
||||
|
||||
type SectionsListPrams = {
|
||||
token: string;
|
||||
project_id?: string;
|
||||
};
|
||||
|
||||
type TasksCreateParams = {
|
||||
token: string;
|
||||
} & TodoistCreateTaskRequest;
|
||||
|
||||
type TasksUpdateParams = {
|
||||
token: string;
|
||||
task_id: string;
|
||||
} & TodoistUpdateTaskRequest;
|
||||
|
||||
type TasksListParams = {
|
||||
token: string;
|
||||
project_id?: string | undefined;
|
||||
filter?: string | undefined;
|
||||
};
|
||||
|
||||
const dueDateParams = (dueDate?: string) => {
|
||||
if (dueDate) {
|
||||
const parsedDate = Date.parse(dueDate);
|
||||
if (isNaN(parsedDate)) {
|
||||
return { due_string: dueDate };
|
||||
} else if (/\d{4}-\d{2}-\d{2}/.test(dueDate)) {
|
||||
return { due_date: dueDate };
|
||||
} else {
|
||||
return { due_datetime: new Date(parsedDate).toISOString() };
|
||||
}
|
||||
}
|
||||
return {};
|
||||
};
|
||||
@@ -0,0 +1,49 @@
|
||||
import {
|
||||
AuthenticationType,
|
||||
httpClient,
|
||||
HttpMethod,
|
||||
HttpRequest,
|
||||
} from '@activepieces/pieces-common';
|
||||
import { isNotUndefined, pickBy } from '@activepieces/shared';
|
||||
import { TodoistCompletedListResponse } from '../models';
|
||||
|
||||
const API = 'https://api.todoist.com/sync/v9';
|
||||
|
||||
export const todoistSyncClient = {
|
||||
completed: {
|
||||
async list({
|
||||
token,
|
||||
since,
|
||||
project_id,
|
||||
until,
|
||||
}: CompletedListParams): Promise<TodoistCompletedListResponse> {
|
||||
const queryParams = {
|
||||
limit: '200',
|
||||
since,
|
||||
until,
|
||||
project_id,
|
||||
};
|
||||
|
||||
const request: HttpRequest = {
|
||||
method: HttpMethod.GET,
|
||||
url: `${API}/completed/get_all`,
|
||||
queryParams: pickBy(queryParams, isNotUndefined),
|
||||
authentication: {
|
||||
type: AuthenticationType.BEARER_TOKEN,
|
||||
token,
|
||||
},
|
||||
};
|
||||
|
||||
const response =
|
||||
await httpClient.sendRequest<TodoistCompletedListResponse>(request);
|
||||
return response.body;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
type CompletedListParams = {
|
||||
token: string;
|
||||
since: string;
|
||||
until: string;
|
||||
project_id: string | undefined;
|
||||
};
|
||||
@@ -0,0 +1,76 @@
|
||||
export type TodoistProject = {
|
||||
id: string;
|
||||
name: string;
|
||||
};
|
||||
|
||||
export type TodoistSection = {
|
||||
id: string;
|
||||
name: string;
|
||||
project_id: string;
|
||||
order: number;
|
||||
};
|
||||
|
||||
export type TodoistCreateTaskRequest = {
|
||||
content: string;
|
||||
project_id?: string | undefined;
|
||||
description?: string | undefined;
|
||||
labels?: Array<string> | undefined;
|
||||
priority?: number | undefined;
|
||||
due_date?: string | undefined;
|
||||
due_string?: string | undefined;
|
||||
due_datetime?: string | undefined;
|
||||
section_id?: string | undefined;
|
||||
};
|
||||
|
||||
export type TodoistUpdateTaskRequest = {
|
||||
content?: string;
|
||||
description?: string;
|
||||
labels?: Array<string>;
|
||||
priority?: number;
|
||||
due_date?: string | undefined;
|
||||
due_string?: string | undefined;
|
||||
due_datetime?: string | undefined;
|
||||
};
|
||||
|
||||
type TodoistTaskDue = {
|
||||
string: string;
|
||||
date: string;
|
||||
is_recurring: boolean;
|
||||
datetime?: string | undefined;
|
||||
timezone?: string | undefined;
|
||||
};
|
||||
|
||||
export type TodoistTask = {
|
||||
id: string;
|
||||
projectId: string | null;
|
||||
sectionId: string | null;
|
||||
content: string;
|
||||
description?: string | undefined;
|
||||
is_completed: boolean;
|
||||
labels: string[];
|
||||
parent_id: string | null;
|
||||
order: number;
|
||||
priority: number;
|
||||
due: TodoistTaskDue | null;
|
||||
url: string;
|
||||
comment_count: number;
|
||||
created_at: string;
|
||||
creator_id: string;
|
||||
assignee_id: string | null;
|
||||
assigner_id: string | null;
|
||||
};
|
||||
|
||||
export type TodoistCompletedTask = {
|
||||
id: string;
|
||||
task_id: string;
|
||||
user_id: string;
|
||||
project_id: string;
|
||||
section_id: string;
|
||||
content: string;
|
||||
completed_at: string;
|
||||
note_count: number;
|
||||
};
|
||||
|
||||
export type TodoistCompletedListResponse = {
|
||||
items: TodoistCompletedTask[];
|
||||
};
|
||||
@@ -0,0 +1,80 @@
|
||||
import { OAuth2PropertyValue, Property } from '@activepieces/pieces-framework';
|
||||
import { todoistRestClient } from './client/rest-client';
|
||||
import { todoistAuth } from '../..';
|
||||
|
||||
const buildEmptyList = ({ placeholder }: { placeholder: string }) => {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder,
|
||||
};
|
||||
};
|
||||
|
||||
export const todoistProjectIdDropdown = (description: string) =>
|
||||
Property.Dropdown<string,false,typeof todoistAuth>({
|
||||
auth: todoistAuth,
|
||||
displayName: 'Project',
|
||||
refreshers: [],
|
||||
description,
|
||||
required: false,
|
||||
options: async ({ auth }) => {
|
||||
if (!auth) {
|
||||
return buildEmptyList({
|
||||
placeholder: 'Please select an authentication',
|
||||
});
|
||||
}
|
||||
|
||||
const token = (auth as OAuth2PropertyValue).access_token;
|
||||
const projects = await todoistRestClient.projects.list({ token });
|
||||
|
||||
if (projects.length === 0) {
|
||||
return buildEmptyList({
|
||||
placeholder: 'No projects found! Please create a project.',
|
||||
});
|
||||
}
|
||||
|
||||
const options = projects.map((p) => ({
|
||||
label: p.name,
|
||||
value: p.id,
|
||||
}));
|
||||
|
||||
return {
|
||||
disabled: false,
|
||||
options,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export const todoistSectionIdDropdown = Property.Dropdown({
|
||||
auth: todoistAuth,
|
||||
displayName: 'Section',
|
||||
refreshers: ['project_id'],
|
||||
required: false,
|
||||
options: async ({ auth, project_id }) => {
|
||||
if (!auth) {
|
||||
return buildEmptyList({
|
||||
placeholder: 'Please select an authentication',
|
||||
});
|
||||
}
|
||||
|
||||
const token = (auth as OAuth2PropertyValue).access_token;
|
||||
const projectId = project_id as string | undefined;
|
||||
const sections = await todoistRestClient.sections.list({ token, project_id: projectId });
|
||||
|
||||
if (sections.length === 0) {
|
||||
return buildEmptyList({
|
||||
placeholder: 'No sections found! Please create a section.',
|
||||
});
|
||||
}
|
||||
|
||||
const options = sections.map((p) => ({
|
||||
label: p.name,
|
||||
value: p.id,
|
||||
}));
|
||||
|
||||
return {
|
||||
disabled: false,
|
||||
options,
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,119 @@
|
||||
import {
|
||||
AppConnectionValueForAuthProperty,
|
||||
createTrigger,
|
||||
PiecePropValueSchema,
|
||||
TriggerStrategy,
|
||||
} from '@activepieces/pieces-framework';
|
||||
import dayjs from 'dayjs';
|
||||
import { TodoistCompletedListResponse, TodoistCompletedTask } from '../common/models';
|
||||
import { todoistProjectIdDropdown } from '../common/props';
|
||||
import { todoistAuth } from '../..';
|
||||
import {
|
||||
AuthenticationType,
|
||||
DedupeStrategy,
|
||||
httpClient,
|
||||
HttpMethod,
|
||||
Polling,
|
||||
pollingHelper,
|
||||
QueryParams,
|
||||
} from '@activepieces/pieces-common';
|
||||
|
||||
const ISO_FORMAT = 'YYYY-MM-DDTHH:mm:ss';
|
||||
|
||||
const polling: Polling<AppConnectionValueForAuthProperty<typeof todoistAuth>, { project_id?: string }> = {
|
||||
strategy: DedupeStrategy.TIMEBASED,
|
||||
async items({ auth, propsValue, lastFetchEpochMS }) {
|
||||
const lastUpdatedTime =
|
||||
lastFetchEpochMS === 0
|
||||
? dayjs().subtract(5, 'minutes').format(ISO_FORMAT)
|
||||
: dayjs(lastFetchEpochMS).format(ISO_FORMAT);
|
||||
|
||||
const tasks: TodoistCompletedTask[] = [];
|
||||
|
||||
let hasMore = true;
|
||||
let offset = 0;
|
||||
const limit = 200;
|
||||
|
||||
do {
|
||||
const qs: QueryParams = {
|
||||
limit: limit.toString(),
|
||||
offset: offset.toString(),
|
||||
since: lastUpdatedTime,
|
||||
};
|
||||
|
||||
if (propsValue.project_id) {
|
||||
qs.project_id = propsValue.project_id;
|
||||
}
|
||||
|
||||
const response = await httpClient.sendRequest<TodoistCompletedListResponse>({
|
||||
method: HttpMethod.GET,
|
||||
url: 'https://api.todoist.com/sync/v9/completed/get_all',
|
||||
queryParams: qs,
|
||||
authentication: {
|
||||
type: AuthenticationType.BEARER_TOKEN,
|
||||
token: auth.access_token,
|
||||
},
|
||||
});
|
||||
if (response.body.items.length > 0) {
|
||||
tasks.push(...response.body.items);
|
||||
offset += limit;
|
||||
} else {
|
||||
hasMore = false;
|
||||
}
|
||||
} while (hasMore);
|
||||
|
||||
return tasks.map((task) => {
|
||||
return {
|
||||
epochMilliSeconds: dayjs(task.completed_at).valueOf(),
|
||||
data: task,
|
||||
};
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
export const todoistTaskCompletedTrigger = createTrigger({
|
||||
auth: todoistAuth,
|
||||
name: 'task_completed',
|
||||
displayName: 'Task Completed',
|
||||
description: 'Triggers when a new task is completed',
|
||||
type: TriggerStrategy.POLLING,
|
||||
|
||||
props: {
|
||||
project_id: todoistProjectIdDropdown(
|
||||
'Leave it blank if you want to get completed tasks from all your projects.',
|
||||
),
|
||||
},
|
||||
|
||||
async onEnable(context) {
|
||||
await pollingHelper.onEnable(polling, {
|
||||
auth: context.auth,
|
||||
store: context.store,
|
||||
propsValue: context.propsValue,
|
||||
});
|
||||
},
|
||||
|
||||
async onDisable(context) {
|
||||
await pollingHelper.onDisable(polling, {
|
||||
auth: context.auth,
|
||||
store: context.store,
|
||||
propsValue: context.propsValue,
|
||||
});
|
||||
},
|
||||
async test(context) {
|
||||
return await pollingHelper.test(polling, context);
|
||||
},
|
||||
async run(context) {
|
||||
return await pollingHelper.poll(polling, context);
|
||||
},
|
||||
sampleData: {
|
||||
content: 'Buy Milk',
|
||||
meta_data: null,
|
||||
user_id: '2671355',
|
||||
task_id: '2995104339',
|
||||
note_count: 0,
|
||||
project_id: '2203306141',
|
||||
section_id: '7025',
|
||||
completed_at: '2015-02-17T15:40:41.000000Z',
|
||||
id: '1899066186',
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user