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:
poduck
2025-12-18 22:59:37 -05:00
parent 9848268d34
commit 3aa7199503
16292 changed files with 1284892 additions and 4708 deletions

View File

@@ -0,0 +1,41 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { linearAuth } from '../../..';
import { props } from '../../common/props';
import { makeClient } from '../../common/client';
import { LinearDocument } from '@linear/sdk';
export const linearCreateComment = createAction({
auth: linearAuth,
name: 'linear_create_comment',
displayName: 'Create Comment',
description: 'Create a new comment on an issue in Linear workspace',
props: {
team_id: props.team_id(),
user_id: props.assignee_id(),
issue_id: props.issue_id(),
body: Property.LongText({
displayName: 'Comment Body',
description: 'The content of the comment',
required: true,
}),
},
async run({ auth, propsValue }) {
const comment: LinearDocument.CommentCreateInput = {
issueId: propsValue.issue_id!,
body: propsValue.body,
};
const client = makeClient(auth);
const result = await client.createComment(comment);
if (result.success) {
const createdComment = await result.comment;
return {
success: result.success,
lastSyncId: result.lastSyncId,
comment: createdComment,
};
} else {
throw new Error(`Unexpected error: ${result}`)
}
},
});

View File

@@ -0,0 +1,52 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { linearAuth } from '../../..';
import { props } from '../../common/props';
import { makeClient } from '../../common/client';
import { LinearDocument } from '@linear/sdk';
export const linearCreateIssue = createAction({
auth: linearAuth,
name: 'linear_create_issue',
displayName: 'Create Issue',
description: 'Create a new issue in Linear workspace',
props: {
team_id: props.team_id(),
title: Property.ShortText({
displayName: 'Title',
required: true,
}),
description: Property.LongText({
displayName: 'Description',
required: false,
}),
state_id: props.status_id(),
labels: props.labels(),
assignee_id: props.assignee_id(),
priority_id: props.priority_id(),
template_id: props.template_id()
},
async run({ auth, propsValue }) {
const issue: LinearDocument.IssueCreateInput = {
teamId: propsValue.team_id!,
title: propsValue.title,
description: propsValue.description,
assigneeId: propsValue.assignee_id,
stateId: propsValue.state_id,
priority: propsValue.priority_id,
labelIds: propsValue.labels,
templateId: propsValue.template_id
};
const client = makeClient(auth);
const result = await client.createIssue(issue);
if (result.success) {
const createdIssue = await result.issue;
return {
success: result.success,
lastSyncId: result.lastSyncId,
issue: createdIssue,
};
} else {
throw new Error(`Unexpected error: ${result}`)
}
},
});

View File

@@ -0,0 +1,51 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { linearAuth } from '../../..';
import { props } from '../../common/props';
import { makeClient } from '../../common/client';
import { LinearDocument } from '@linear/sdk';
export const linearUpdateIssue = createAction({
auth: linearAuth,
name: 'linear_update_issue',
displayName: 'Update Issue',
description: 'Update a issue in Linear Workspace',
props: {
team_id: props.team_id(),
issue_id: props.issue_id(),
title: Property.ShortText({
displayName: 'Title',
required: false,
}),
description: Property.LongText({
displayName: 'Description',
required: false,
}),
state_id: props.status_id(),
labels: props.labels(),
assignee_id: props.assignee_id(),
priority_id: props.priority_id(),
},
async run({ auth, propsValue }) {
const issueId = propsValue.issue_id!;
const issue: LinearDocument.IssueUpdateInput = {
title: propsValue.title,
description: propsValue.description,
assigneeId: propsValue.assignee_id,
stateId: propsValue.state_id,
priority: propsValue.priority_id,
labelIds: propsValue.labels,
};
const client = makeClient(auth);
const result = await client.updateIssue(issueId, issue);
if (result.success) {
const updatedIssue = await result.issue;
return {
success: result.success,
lastSyncId: result.lastSyncId,
issue: updatedIssue,
};
} else {
throw new Error(`Unexpected error: ${result}`)
}
},
});

View File

@@ -0,0 +1,63 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { linearAuth } from '../../..';
import { props } from '../../common/props';
import { makeClient } from '../../common/client';
import { LinearDocument } from '@linear/sdk';
export const linearCreateProject = createAction({
auth: linearAuth,
name: 'linear_create_project',
displayName: 'Create Project',
description: 'Create a new project in Linear workspace',
props: {
team_id: props.team_id(),
name: Property.ShortText({
displayName: 'Project Name',
required: true,
}),
description: Property.LongText({
displayName: 'Description',
required: false,
}),
icon: Property.ShortText({
displayName: 'Icon',
required: false,
}),
color: Property.ShortText({
displayName: 'Color',
required: false,
}),
startDate: Property.DateTime({
displayName: 'Start Date',
required: false,
}),
targetDate: Property.DateTime({
displayName: 'Target Date',
required: false,
}),
},
async run({ auth, propsValue }) {
const project: LinearDocument.ProjectCreateInput = {
teamIds: [propsValue.team_id!],
name: propsValue.name,
description: propsValue.description,
icon: propsValue.icon,
color: propsValue.color,
startDate: propsValue.startDate,
targetDate: propsValue.targetDate,
};
const client = makeClient(auth);
const result = await client.createProject(project);
if (result.success) {
const createdProject = await result.project;
return {
success: result.success,
lastSyncId: result.lastSyncId,
project: createdProject,
};
} else {
throw new Error(`Unexpected error: ${result}`)
}
},
});

View File

@@ -0,0 +1,64 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { linearAuth } from '../../..';
import { props } from '../../common/props';
import { makeClient } from '../../common/client';
import { LinearDocument } from '@linear/sdk';
export const linearUpdateProject = createAction({
auth: linearAuth,
name: 'linear_update_project',
displayName: 'Update Project',
description: 'Update a existing project in Linear workspace',
props: {
team_id: props.team_id(),
project_id: props.project_id(),
name: Property.ShortText({
displayName: 'Project Name',
required: true,
}),
description: Property.LongText({
displayName: 'Description',
required: false,
}),
icon: Property.ShortText({
displayName: 'Icon',
required: false,
}),
color: Property.ShortText({
displayName: 'Color',
required: false,
}),
startDate: Property.DateTime({
displayName: 'Start Date',
required: false,
}),
targetDate: Property.DateTime({
displayName: 'Target Date',
required: false,
}),
},
async run({ auth, propsValue }) {
const project: LinearDocument.ProjectUpdateInput = {
teamIds: [propsValue.team_id!],
name: propsValue.name,
description: propsValue.description,
icon: propsValue.icon,
color: propsValue.color,
startDate: propsValue.startDate,
targetDate: propsValue.targetDate,
};
const client = makeClient(auth);
const result = await client.updateProject(propsValue.project_id!, project);
if (result.success) {
const updatedProject = await result.project;
return {
success: result.success,
lastSyncId: result.lastSyncId,
project: updatedProject,
};
} else {
throw new Error(`Unexpected error: ${result}`)
}
},
});

View File

@@ -0,0 +1,22 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { linearAuth } from '../..';
import { makeClient } from '../common/client';
export const linearRawGraphqlQuery = createAction({
name: 'rawGraphqlQuery',
displayName: 'Raw GraphQL query',
description: 'Perform a raw GraphQL query',
auth: linearAuth,
props: {
query: Property.LongText({ displayName: 'Query', required: true }),
variables: Property.Object({ displayName: 'Parameters', required: false }),
},
async run({ auth, propsValue }) {
const client = makeClient(auth);
const result = await client.rawRequest(
propsValue.query,
propsValue.variables
);
return result;
},
});

View File

@@ -0,0 +1,74 @@
import { AppConnectionValueForAuthProperty } from '@activepieces/pieces-framework';
import { LinearClient, LinearDocument } from '@linear/sdk';
import { linearAuth } from '../..';
export class LinearClientWrapper {
private client: LinearClient;
constructor(apiKey: string) {
this.client = new LinearClient({ apiKey: apiKey });
}
async createIssue(input: LinearDocument.IssueCreateInput) {
return this.client.createIssue(input);
}
async listIssueStates(
variables: LinearDocument.WorkflowStatesQueryVariables
) {
return this.client.workflowStates(variables);
}
async listIssuePriorities() {
return this.client.issuePriorityValues;
}
async listUsers(variables: LinearDocument.UsersQueryVariables) {
return this.client.users(variables);
}
async listIssueLabels(variables: LinearDocument.IssueLabelsQueryVariables) {
return this.client.issueLabels(variables);
}
async listTeams(variables: LinearDocument.TeamsQueryVariables = {}) {
return this.client.teams(variables);
}
async listIssues(variables: LinearDocument.IssuesQueryVariables = {}) {
return this.client.issues(variables);
}
async updateIssue(issueId: string, input: LinearDocument.IssueUpdateInput) {
return this.client.updateIssue(issueId, input);
}
async createProject(input: LinearDocument.ProjectCreateInput) {
return this.client.createProject(input);
}
async listProjects(variables: LinearDocument.ProjectsQueryVariables = {}) {
return this.client.projects(variables);
}
async updateProject(
projectId: string,
input: LinearDocument.ProjectUpdateInput
) {
return this.client.updateProject(projectId, input);
}
async createComment(input: LinearDocument.CommentCreateInput) {
return this.client.createComment(input);
}
async createWebhook(input: LinearDocument.WebhookCreateInput) {
return this.client.createWebhook(input);
}
async listWebhooks(variables: LinearDocument.WebhooksQueryVariables = {}) {
return this.client.webhooks(variables);
}
async deleteWebhook(webhookId: string) {
return this.client.deleteWebhook(webhookId);
}
async listTeamsTemplates(
teamId: string,
variables: Omit<LinearDocument.Team_TemplatesQueryVariables, 'id'>
) {
const team = await this.client.team(teamId);
return team.templates(variables);
}
async rawRequest(query: string, variables?: Record<string, unknown>) {
return this.client.client.rawRequest(query, variables);
}
}
export function makeClient(auth: AppConnectionValueForAuthProperty<typeof linearAuth>): LinearClientWrapper {
return new LinearClientWrapper(auth.secret_text);
}

View File

@@ -0,0 +1,394 @@
import { DropdownOption, Property } from '@activepieces/pieces-framework';
import { makeClient } from './client';
import { LinearDocument } from '@linear/sdk';
import { linearAuth } from '../..';
export const props = {
team_id: (required = true) =>
Property.Dropdown({
auth: linearAuth,
description:
'The team for which the issue, project or comment will be created',
displayName: 'Team',
required,
refreshers: ['auth'],
options: async ({ auth }) => {
if (!auth) {
return {
disabled: true,
placeholder: 'connect your account first',
options: [],
};
}
const client = makeClient(auth);
const options: DropdownOption<string>[] = [];
let hasNextPage = false;
let cursor;
do {
const teams = await client.listTeams({
orderBy: LinearDocument.PaginationOrderBy.UpdatedAt,
first: 100,
after: cursor,
});
for (const team of teams.nodes) {
options.push({ label: team.name, value: team.id });
}
hasNextPage = teams.pageInfo.hasNextPage;
cursor = teams.pageInfo.endCursor;
} while (hasNextPage);
return {
disabled: false,
options,
};
},
}),
status_id: (required = false) =>
Property.Dropdown({
auth: linearAuth,
description: 'Status of the Issue',
displayName: 'Status',
required,
refreshers: ['auth', 'team_id'],
options: async ({ auth, team_id }) => {
if (!auth || !team_id) {
return {
disabled: true,
placeholder: 'connect your account first and select team',
options: [],
};
}
const client = makeClient(auth);
const options: DropdownOption<string>[] = [];
let hasNextPage = false;
let cursor;
do {
const filter: LinearDocument.WorkflowStatesQueryVariables = {
filter: {
team: {
id: {
eq: team_id as string,
},
},
},
first: 100,
after: cursor,
};
const statusList = await client.listIssueStates(filter);
for (const status of statusList.nodes) {
options.push({ label: status.name, value: status.id });
}
hasNextPage = statusList.pageInfo.hasNextPage;
cursor = statusList.pageInfo.endCursor;
} while (hasNextPage);
return {
disabled: false,
options,
};
},
}),
labels: (required = false) =>
Property.MultiSelectDropdown({
auth: linearAuth,
description: 'Labels for the Issue',
displayName: 'Labels',
required,
refreshers: ['auth', 'team_id'],
options: async ({ auth, team_id }) => {
if (!auth) {
return {
disabled: true,
placeholder: 'connect your account first',
options: [],
};
}
if (!team_id) {
return {
disabled: true,
placeholder: 'select a team to load labels',
options: [],
};
}
const client = makeClient(auth);
const teamLabels: DropdownOption<string>[] = [];
const workspaceLabels: DropdownOption<string>[] = [];
// Fetch team specific labels
let hasNextPage = false;
let cursor;
do {
const labels = await client.listIssueLabels({
filter: {
team: {
id: {
eq: team_id as string,
},
},
},
orderBy: LinearDocument.PaginationOrderBy.UpdatedAt,
first: 100,
after: cursor,
});
for (const label of labels.nodes) {
teamLabels.push({ label: label.name, value: label.id });
}
hasNextPage = labels.pageInfo.hasNextPage;
cursor = labels.pageInfo.endCursor;
} while (hasNextPage);
// Fetch all workspace labels that are common to all teams
hasNextPage = false;
cursor = undefined;
do {
const labels = await client.listIssueLabels({
filter: {
team: {
null: true,
},
},
orderBy: LinearDocument.PaginationOrderBy.UpdatedAt,
first: 100,
after: cursor,
});
for (const label of labels.nodes) {
// Prefix workspace labels with [Workspace]
workspaceLabels.push({ label: `[Workspace] ${label.name}`, value: label.id });
}
hasNextPage = labels.pageInfo.hasNextPage;
cursor = labels.pageInfo.endCursor;
} while (hasNextPage);
// team labels are displayed first in alphabetical order
teamLabels.sort((a, b) => a.label.localeCompare(b.label));
// followed by workspace labels in alphabetical order
workspaceLabels.sort((a, b) => a.label.localeCompare(b.label));
const options = [...teamLabels, ...workspaceLabels];
return {
disabled: false,
options,
};
},
}),
assignee_id: (required = false) =>
Property.Dropdown({
auth: linearAuth,
description: 'Assignee of the Issue / Comment',
displayName: 'Assignee',
required,
refreshers: ['auth'],
options: async ({ auth }) => {
if (!auth) {
return {
disabled: true,
placeholder: 'connect your account first',
options: [],
};
}
const client = makeClient(auth);
const options: DropdownOption<string>[] = [];
let hasNextPage = false;
let cursor;
do {
const users = await client.listUsers({
orderBy: LinearDocument.PaginationOrderBy.UpdatedAt,
first: 100,
after: cursor,
});
for (const user of users.nodes) {
options.push({ label: user.name, value: user.id });
}
hasNextPage = users.pageInfo.hasNextPage;
cursor = users.pageInfo.endCursor;
} while (hasNextPage);
return {
disabled: false,
options,
};
},
}),
priority_id: (required = false) =>
Property.Dropdown({
auth: linearAuth,
description: 'Priority of the Issue',
displayName: 'Priority',
required,
refreshers: ['auth'],
options: async ({ auth }) => {
if (!auth) {
return {
disabled: true,
placeholder: 'connect your account first',
options: [],
};
}
const client = makeClient(auth);
const priorities = await client.listIssuePriorities();
return {
disabled: false,
options: priorities.map((priority: { label: any; priority: any }) => {
return {
label: priority.label,
value: priority.priority,
};
}),
};
},
}),
issue_id: (required = true) =>
Property.Dropdown({
auth: linearAuth,
displayName: 'Issue',
required,
description: 'ID of Linear Issue',
refreshers: ['team_id'],
options: async ({ auth, team_id }) => {
if (!auth || !team_id) {
return {
disabled: true,
placeholder: 'connect your account first and select team',
options: [],
};
}
const client = makeClient(auth);
const filter: LinearDocument.IssuesQueryVariables = {
first: 50,
filter: {
team: {
id: {
eq: team_id as string,
},
},
},
orderBy: LinearDocument.PaginationOrderBy.UpdatedAt,
};
const issues = await client.listIssues(filter);
return {
disabled: false,
options: issues.nodes.map((issue: { title: any; id: any }) => {
return {
label: issue.title,
value: issue.id,
};
}),
};
},
}),
project_id: (required = true) =>
Property.Dropdown({
auth: linearAuth,
displayName: 'Project',
required,
description: 'ID of Linear Project',
refreshers: ['team_id'],
options: async ({ auth, team_id }) => {
if (!auth || !team_id) {
return {
disabled: true,
placeholder: 'connect your account first and select team',
options: [],
};
}
const client = makeClient(auth);
const options: DropdownOption<string>[] = [];
let hasNextPage = false;
let cursor;
do {
const projects = await client.listProjects({
orderBy: LinearDocument.PaginationOrderBy.UpdatedAt,
first: 100,
after: cursor,
});
for (const project of projects.nodes) {
options.push({ label: project.name, value: project.id });
}
hasNextPage = projects.pageInfo.hasNextPage;
cursor = projects.pageInfo.endCursor;
} while (hasNextPage);
return {
disabled: false,
options,
};
},
}),
template_id: (required = false) =>
Property.Dropdown({
auth: linearAuth,
displayName: 'Template',
required,
description: 'ID of Template',
refreshers: ['auth', 'team_id'],
options: async ({ auth, team_id }) => {
if (!auth || !team_id) {
return {
disabled: true,
placeholder: 'connect your account first and select team',
options: [],
};
}
const client = makeClient(auth);
const options: DropdownOption<string>[] = [];
let hasNextPage = false;
let cursor;
do {
const filter: Omit<
LinearDocument.Team_TemplatesQueryVariables,
'id'
> = {
first: 100,
after: cursor,
orderBy: LinearDocument.PaginationOrderBy.UpdatedAt,
};
const templatesConnection = await client.listTeamsTemplates(
team_id as string,
filter
);
const templates = await templatesConnection.nodes;
for (const template of templates) {
options.push({ label: template.name, value: template.id });
}
hasNextPage = templatesConnection.pageInfo.hasNextPage;
cursor = templatesConnection.pageInfo.endCursor;
} while (hasNextPage);
return {
disabled: false,
options,
};
},
}),
};

View File

@@ -0,0 +1,101 @@
import { createTrigger, TriggerStrategy } from '@activepieces/pieces-framework';
import { linearAuth } from '../..';
import { makeClient } from '../common/client';
import { props } from '../common/props';
export const linearNewIssue = createTrigger({
auth: linearAuth,
name: 'new_issue',
displayName: 'New Issue',
description: 'Triggers when Linear receives a new issue',
props: {
team_id: props.team_id(),
},
sampleData: {
// Sample data structure based on Linear's webhook payload for issues
action: 'create',
data: {
id: 'issue_1',
identifier: '1',
title: 'Test issue',
description: 'This is a test issue',
priority: 'priority_1',
priorityLabel: 'High',
state: 'state_1',
stateLabel: 'In Progress',
team: {
id: 'team_1',
name: 'Test team',
key: 'test-team',
description: 'This is a test team',
archived: false,
createdAt: '2023-09-05T12:00:00.000Z',
updatedAt: '2023-09-05T12:00:00.000Z',
},
creator: {
id: 'user_1',
name: 'Test user',
email: 'test@gmail.com',
avatarUrl: 'https://avatars.githubusercontent.com/u/1?v=4',
createdAt: '2023-09-05T12:00:00.000Z',
updatedAt: '2023-09-05T12:00:00.000Z',
},
assignee: {
id: 'user_1',
name: 'Test user',
email: 'test@gmail.com',
avatarUrl: 'https://avatars.githubusercontent.com/u/1?v=4',
createdAt: '2023-09-05T12:00:00.000Z',
updatedAt: '2023-09-05T12:00:00.000Z',
},
labels: [
{
id: 'label_1',
name: 'Test label',
color: '#000000',
createdAt: '2023-09-05T12:00:00.000Z',
updatedAt: '2023-09-05T12:00:00.000Z',
},
],
createdAt: '2023-09-05T12:00:00.000Z',
updatedAt: '2023-09-05T12:00:00.000Z',
},
},
type: TriggerStrategy.WEBHOOK,
async onEnable(context) {
const client = makeClient(context.auth);
const webhook = await client.createWebhook({
label: 'ActivePieces New Issue',
url: context.webhookUrl,
teamId: context.propsValue['team_id'],
resourceTypes: ['Issue'],
});
if (webhook.success && webhook.webhook) {
await context.store?.put<WebhookInformation>('_new_issue_trigger', {
webhookId: (await webhook.webhook).id,
});
} else {
console.error('Failed to create the webhook');
}
},
async onDisable(context) {
const client = makeClient(context.auth);
const response = await context.store?.get<WebhookInformation>(
'_new_issue_trigger'
);
if (response && response.webhookId) {
await client.deleteWebhook(response.webhookId);
}
},
async run(context) {
const body = context.payload.body as { action: string; data: unknown };
if (body.action === 'create') {
return [body.data];
}
return [];
},
});
interface WebhookInformation {
webhookId: string;
}

View File

@@ -0,0 +1,101 @@
import { createTrigger, TriggerStrategy } from '@activepieces/pieces-framework';
import { linearAuth } from '../..';
import { makeClient } from '../common/client';
import { props } from '../common/props';
export const linearRemovedIssue = createTrigger({
auth: linearAuth,
name: 'removed_issue',
displayName: 'Removed Issue',
description: 'Triggers when an existing Linear issue is removed',
props: {
team_id: props.team_id()
},
sampleData: {
// Sample data structure based on Linear's webhook payload for issues
action: 'remove',
data: {
id: 'issue_1',
identifier: '1',
title: 'Test issue',
description: 'This is a test issue',
priority: 'priority_1',
priorityLabel: 'High',
state: 'state_1',
stateLabel: 'In Progress',
team: {
id: 'team_1',
name: 'Test team',
key: 'test-team',
description: 'This is a test team',
archived: false,
createdAt: '2023-09-05T12:00:00.000Z',
updatedAt: '2023-09-05T12:00:00.000Z',
},
creator: {
id: 'user_1',
name: 'Test user',
email: 'test@gmail.com',
avatarUrl: 'https://avatars.githubusercontent.com/u/1?v=4',
createdAt: '2023-09-05T12:00:00.000Z',
updatedAt: '2023-09-05T12:00:00.000Z',
},
assignee: {
id: 'user_1',
name: 'Test user',
email: 'test@gmail.com',
avatarUrl: 'https://avatars.githubusercontent.com/u/1?v=4',
createdAt: '2023-09-05T12:00:00.000Z',
updatedAt: '2023-09-05T12:00:00.000Z',
},
labels: [
{
id: 'label_1',
name: 'Test label',
color: '#000000',
createdAt: '2023-09-05T12:00:00.000Z',
updatedAt: '2023-09-05T12:00:00.000Z',
},
],
createdAt: '2023-09-05T12:00:00.000Z',
updatedAt: '2023-09-05T12:00:00.000Z',
},
},
type: TriggerStrategy.WEBHOOK,
async onEnable(context) {
const client = makeClient(context.auth);
const webhook = await client.createWebhook({
label: 'ActivePieces Updated Issue',
url: context.webhookUrl,
teamId: context.propsValue['team_id'],
resourceTypes: ['Issue']
});
if (webhook.success && webhook.webhook) {
await context.store?.put<WebhookInformation>('_removed_issue_trigger', {
webhookId: (await webhook.webhook).id
});
} else {
console.error('Failed to create the webhook');
}
},
async onDisable(context) {
const client = makeClient(context.auth);
const response = await context.store?.get<WebhookInformation>(
'_removed_issue_trigger'
);
if (response && response.webhookId) {
await client.deleteWebhook(response.webhookId);
}
},
async run(context) {
const body = context.payload.body as { action: string; data: unknown};
if (body.action === 'remove') {
return [body.data];
}
return [];
}
});
interface WebhookInformation {
webhookId: string;
}

View File

@@ -0,0 +1,124 @@
import { createTrigger, TriggerStrategy } from '@activepieces/pieces-framework';
import { linearAuth } from '../..';
import { makeClient } from '../common/client';
import { props } from '../common/props';
export const linearUpdatedIssue = createTrigger({
auth: linearAuth,
name: 'updated_issue',
displayName: 'Updated Issue',
description: 'Triggers when an existing Linear issue is updated',
props: {
team_id: props.team_id(false)
},
sampleData: {
// Sample data structure based on Linear's webhook payload for issues
action: 'update',
data: {
id: 'issue_1',
identifier: '1',
title: 'Test issue updated',
description: 'This is a test issue (updated)',
priority: 'priority_1',
priorityLabel: 'High',
state: 'state_2',
stateLabel: 'In Review',
team: {
id: 'team_2',
name: 'Test team',
key: 'test-team',
description: 'This is another test team',
archived: false,
createdAt: '2023-09-05T12:00:00.000Z',
updatedAt: '2023-09-06T12:00:00.000Z'
},
creator: {
id: 'user_1',
name: 'Test user',
email: 'test@gmail.com',
avatarUrl: 'https://avatars.githubusercontent.com/u/1?v=4',
createdAt: '2023-09-05T12:00:00.000Z',
updatedAt: '2023-09-06T12:00:00.000Z'
},
assignee: {
id: 'user_1',
name: 'Test user',
email: 'test@gmail.com',
avatarUrl: 'https://avatars.githubusercontent.com/u/1?v=4',
createdAt: '2023-09-05T12:00:00.000Z',
updatedAt: '2023-09-05T12:00:00.000Z'
},
labels: [
{
id: 'label_1',
name: 'Test label',
color: '#000000',
createdAt: '2023-09-05T12:00:00.000Z',
updatedAt: '2023-09-05T12:00:00.000Z'
},
{
id: 'label_1',
name: 'Test label 2',
color: '#000000',
createdAt: '2023-09-05T12:00:00.000Z',
updatedAt: '2023-09-06T12:00:00.000Z'
}
],
createdAt: '2023-09-05T12:00:00.000Z',
updatedAt: '2023-09-06T12:00:00.000Z'
},
updatedFrom: {
'updatedAt': '2023-09-06T12:00:00.000Z',
'sortOrder': -14.61,
'startedAt': null,
'stateId': 'state_1'
}
},
type: TriggerStrategy.WEBHOOK,
async onEnable(context) {
const client = makeClient(context.auth);
// Create webhook configuration
const webhookConfig: any = {
label: 'ActivePieces Updated Issue',
url: context.webhookUrl,
allPublicTeams: true,
resourceTypes: ['Issue']
};
// Only add teamId if it's provided
if (context.propsValue['team_id']) {
webhookConfig.teamId = context.propsValue['team_id'];
}
const webhook = await client.createWebhook(webhookConfig);
if (webhook.success && webhook.webhook) {
await context.store?.put<WebhookInformation>('_updated_issue_trigger', {
webhookId: (await webhook.webhook).id
});
} else {
console.error('Failed to create the webhook');
}
},
async onDisable(context) {
const client = makeClient(context.auth);
const response = await context.store?.get<WebhookInformation>(
'_updated_issue_trigger'
);
if (response && response.webhookId) {
await client.deleteWebhook(response.webhookId);
}
},
async run(context) {
const body = context.payload.body as { action: string; data: unknown};
if (body.action === 'update') {
return [body.data];
}
return [];
}
});
interface WebhookInformation {
webhookId: string;
}