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,37 @@
import { Property, createAction } from '@activepieces/pieces-framework';
import { mondayAuth } from '../..';
import { makeClient, mondayCommon } from '../common';
import { COLUMN_TYPE_OPTIONS } from '../common/constants';
export const createColumnAction = createAction({
auth: mondayAuth,
name: 'monday_create_column',
displayName: 'Create Column',
description: 'Creates a new column in board.',
props: {
workspace_id: mondayCommon.workspace_id(true),
board_id: mondayCommon.board_id(true),
column_title: Property.ShortText({
displayName: 'Column Title',
required: true,
}),
column_type: Property.StaticDropdown({
displayName: 'Column Type',
required: true,
options: {
disabled: false,
options: COLUMN_TYPE_OPTIONS,
},
}),
},
async run(context) {
const { board_id, column_title, column_type } = context.propsValue;
const client = makeClient(context.auth);
return await client.createColumn({
boardId: board_id as string,
columnTitle: column_title as string,
columnType: column_type as string,
});
},
});

View File

@@ -0,0 +1,27 @@
import { Property, createAction } from '@activepieces/pieces-framework';
import { mondayAuth } from '../..';
import { makeClient, mondayCommon } from '../common';
export const createGroupAction = createAction({
auth: mondayAuth,
name: 'monday_create_group',
displayName: 'Create Group',
description: 'Creates a new group in board.',
props: {
workspace_id: mondayCommon.workspace_id(true),
board_id: mondayCommon.board_id(true),
group_name: Property.ShortText({
displayName: 'Group Name',
required: true,
}),
},
async run(context) {
const { board_id, group_name } = context.propsValue;
const client = makeClient(context.auth);
return await client.createGroup({
boardId: board_id as string,
groupName: group_name as string,
});
},
});

View File

@@ -0,0 +1,70 @@
import {
DynamicPropsValue,
Property,
createAction,
} from '@activepieces/pieces-framework';
import { mondayAuth } from '../..';
import { makeClient, mondayCommon } from '../common';
import {
convertPropValueToMondayColumnValue,
generateColumnIdTypeMap,
} from '../common/helper';
export const createItemAction = createAction({
auth: mondayAuth,
name: 'monday_create_item',
displayName: 'Create Item',
description: 'Creates a new item inside a board.',
props: {
workspace_id: mondayCommon.workspace_id(true),
board_id: mondayCommon.board_id(true),
group_id: mondayCommon.group_id(false),
item_name: Property.ShortText({
displayName: 'Item Name',
description: 'Item Name',
required: true,
}),
column_values: mondayCommon.columnValues,
create_labels_if_missing: Property.Checkbox({
displayName: 'Create Labels if Missing',
description:
'Creates status/dropdown labels if they are missing. This requires permission to change the board structure.',
defaultValue: false,
required: false,
}),
},
async run(context) {
const { board_id, item_name, create_labels_if_missing } =
context.propsValue;
const group_id = context.propsValue.group_id!;
const columnValuesInput = context.propsValue.column_values;
const mondayColumnValues: DynamicPropsValue = {};
const client = makeClient(context.auth);
const res = await client.listBoardColumns({
boardId: board_id as unknown as string,
});
const columns = res.data.boards[0]?.columns;
// map board column id with column type
const columnIdTypeMap = generateColumnIdTypeMap(columns);
Object.keys(columnValuesInput).forEach((key) => {
if (columnValuesInput[key] !== '') {
const columnType: string = columnIdTypeMap[key];
mondayColumnValues[key] = convertPropValueToMondayColumnValue(
columnType,
columnValuesInput[key]
);
}
});
return await client.createItem({
itemName: item_name,
boardId: board_id,
groupId: group_id,
columnValues: JSON.stringify(mondayColumnValues),
createLabels: create_labels_if_missing ?? false,
});
},
});

View File

@@ -0,0 +1,29 @@
import { Property, createAction } from '@activepieces/pieces-framework';
import { mondayAuth } from '../..';
import { makeClient } from '../common';
export const createUpdateAction = createAction({
auth: mondayAuth,
name: 'monday_create_update',
displayName: 'Create Update',
description: 'Creates a new update.',
props: {
item_id: Property.ShortText({
displayName: 'Item ID',
required: true,
}),
body: Property.LongText({
displayName: 'Body',
required: true,
}),
},
async run(context) {
const { item_id, body } = context.propsValue;
const client = makeClient(context.auth);
return await client.createUpdate({
itemId: item_id as string,
body: body as string,
});
},
});

View File

@@ -0,0 +1,40 @@
import { createAction } from '@activepieces/pieces-framework';
import { mondayAuth } from '../..';
import { makeClient, mondayCommon } from '../common';
import { parseMondayColumnValue } from '../common/helper';
export const getBoardItemValuesAction = createAction({
auth: mondayAuth,
name: 'monday_get_board_values',
displayName: 'Get Board Values',
description: "Gets a list of board's items.",
props: {
workspace_id: mondayCommon.workspace_id(true),
board_id: mondayCommon.board_id(true),
column_ids: mondayCommon.columnIds(false),
},
async run(context) {
const { board_id, column_ids } = context.propsValue;
const client = makeClient(context.auth);
const res = await client.getBoardItemValues({
boardId: board_id as string,
columnIds: column_ids as string[],
});
const items = res.data.boards[0].items_page.items;
const result = [];
for (const item of items) {
const transformedValues: Record<string, any> = {
id: item.id,
name: item.name,
};
for (const column of item.column_values) {
transformedValues[column.id] = parseMondayColumnValue(column);
}
result.push(transformedValues);
}
return result;
},
});

View File

@@ -0,0 +1,36 @@
import { createAction } from '@activepieces/pieces-framework';
import { mondayAuth } from '../..';
import { makeClient, mondayCommon } from '../common';
import { parseMondayColumnValue } from '../common/helper';
export const getItemsColumnValuesAction = createAction({
auth: mondayAuth,
name: 'monday_get_item_column_values',
displayName: "Get an Item's Column Values",
description: 'Gets column values of an item.',
props: {
workspace_id: mondayCommon.workspace_id(true),
board_id: mondayCommon.board_id(true),
item_id: mondayCommon.item_id(true),
column_ids: mondayCommon.columnIds(false),
},
async run(context) {
const { board_id, item_id, column_ids } = context.propsValue;
const client = makeClient(context.auth);
const res = await client.getItemColumnValues({
boardId: board_id as string,
itemId: item_id as string,
columnIds: column_ids as string[],
});
const item = res.data.boards[0].items_page.items[0];
const transformedValues: Record<string, any> = {
id: item.id,
name: item.name,
};
for (const column of item.column_values) {
transformedValues[column.id] = parseMondayColumnValue(column);
}
return transformedValues;
},
});

View File

@@ -0,0 +1,53 @@
import {
DynamicPropsValue,
createAction,
} from '@activepieces/pieces-framework';
import { mondayAuth } from '../..';
import { makeClient, mondayCommon } from '../common';
import {
convertPropValueToMondayColumnValue,
generateColumnIdTypeMap,
} from '../common/helper';
export const updateColumnValuesOfItemAction = createAction({
auth: mondayAuth,
name: 'monday_update_column_values_of_item',
displayName: 'Update Column Values of Specific Item',
description: 'Updates multiple columns values of specific item.',
props: {
workspace_id: mondayCommon.workspace_id(true),
board_id: mondayCommon.board_id(true),
item_id: mondayCommon.item_id(true),
column_values: mondayCommon.columnValues,
},
async run(context) {
const { board_id, item_id } = context.propsValue;
const columnValuesInput = context.propsValue.column_values;
const mondayColumnValues: DynamicPropsValue = {};
const client = makeClient(context.auth);
const res = await client.listBoardColumns({
boardId: board_id as unknown as string,
});
const columns = res.data.boards[0]?.columns;
// map board column id with column type
const columnIdTypeMap = generateColumnIdTypeMap(columns);
Object.keys(columnValuesInput).forEach((key) => {
if (columnValuesInput[key] !== '') {
const columnType: string = columnIdTypeMap[key];
mondayColumnValues[key] = convertPropValueToMondayColumnValue(
columnType,
columnValuesInput[key]
);
}
});
return await client.updateItem({
boardId: board_id,
itemId: item_id,
columnValues: JSON.stringify(mondayColumnValues),
});
},
});

View File

@@ -0,0 +1,29 @@
import { Property, createAction } from '@activepieces/pieces-framework';
import { mondayAuth } from '../..';
import { makeClient, mondayCommon } from '../common';
export const updateItemNameAction = createAction({
auth: mondayAuth,
name: 'monday_update_item_name',
displayName: 'Update Item Name',
description: 'Updates an item name.',
props: {
workspace_id: mondayCommon.workspace_id(true),
board_id: mondayCommon.board_id(true),
item_id: mondayCommon.item_id(true),
name: Property.ShortText({
displayName: 'New Item name',
required: true,
}),
},
async run(context) {
const { board_id, item_id, name } = context.propsValue;
const client = makeClient(context.auth);
return await client.updateItem({
boardId: board_id,
itemId: item_id,
columnValues: JSON.stringify({ name: name }),
});
},
});

View File

@@ -0,0 +1,105 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { makeClient, mondayCommon } from '../common';
import { MondayColumnType } from '../common/constants';
import { httpClient, HttpMethod } from '@activepieces/pieces-common';
import FormData from 'form-data';
import { mondayAuth } from '../../';
export const uploadFileToColumnAction = createAction({
auth: mondayAuth,
name: 'monday_upload_file_to_column',
displayName: 'Upload File to Column',
description: 'Upload a file to a column in Monday.',
props: {
workspace_id: mondayCommon.workspace_id(true),
board_id: mondayCommon.board_id(true),
item_id: mondayCommon.item_id(true),
file_column_id: Property.Dropdown({
auth: mondayAuth,
displayName: 'File Column ID',
required: true,
refreshers: ['board_id'],
options: async ({ auth, board_id }) => {
if (!auth || !board_id) {
return {
disabled: true,
placeholder:
'connect your account first and select workspace board.',
options: [],
};
}
const client = makeClient(auth);
const res = await client.listBoardColumns({
boardId: board_id as string,
});
return {
disabled: false,
options: res.data.boards[0].columns
.filter((column) => column.type === MondayColumnType.FILE)
.map((column) => {
return {
label: column.title,
value: column.id,
};
}),
};
},
}),
file: Property.File({
displayName: 'File',
description: 'The file URL or base64 to upload.',
required: true,
}),
file_name: Property.ShortText({
displayName: 'File Name',
required: true,
}),
},
async run(context) {
const itemId = context.propsValue.item_id;
const fileColumnId = context.propsValue.file_column_id;
const fileName = context.propsValue.file_name;
const file = context.propsValue.file;
const formData = new FormData();
formData.append(
'query',
`mutation($item_id: ID!, $column_id: String!, $file: File!)
{
add_file_to_column(item_id: $item_id, column_id: $column_id, file: $file)
{
id
url
name
file_size
file_extension
created_at
}
}`
);
formData.append(
'variables',
JSON.stringify({ item_id: itemId, column_id: fileColumnId })
);
formData.append('map', JSON.stringify({ file: 'variables.file' }));
formData.append(
'file',
Buffer.from(file.base64, 'base64'),
fileName || file.filename
);
const response = await httpClient.sendRequest({
method: HttpMethod.POST,
url: 'https://api.monday.com/v2/file',
headers: {
'API-Version': '2024-01',
Authorization: context.auth.secret_text,
...formData.getHeaders(),
},
body: formData,
});
return response.body;
},
});

View File

@@ -0,0 +1,101 @@
import mondaySdk from 'monday-sdk-js';
import { MondayClientSdk } from 'monday-sdk-js/types/client-sdk.interface';
import { Board, MondayColumn, User } from './models';
import { mondayGraphQLMutations } from './mutations';
import { mondayGraphQLQueries } from './queries';
export class mondayClient {
private client: MondayClientSdk;
constructor(apiKey: string) {
this.client = mondaySdk();
this.client.setToken(apiKey);
this.client.setApiVersion('2023-10');
}
async listWorkspcaes() {
return await this.client.api<{
workspaces: { id: string; name: string }[];
}>(mondayGraphQLQueries.listWorkspaces);
}
async listWorkspaceBoards(variables: object) {
return await this.client.api<{
boards: { id: string; name: string; type: string }[];
}>(mondayGraphQLQueries.listWorkspaceBoards, { variables: variables });
}
async listBoardGroups(variables: object) {
return await this.client.api<{ boards: Board[] }>(
mondayGraphQLQueries.listBoardGroups,
{ variables: variables }
);
}
async listBoardColumns(variables: object) {
return await this.client.api<{ boards: { columns: MondayColumn[] }[] }>(
mondayGraphQLQueries.listBoardColumns,
{ variables: variables }
);
}
async listBoardItems(variables: object) {
return await this.client.api<{ boards: Board[] }>(
mondayGraphQLQueries.listBoardItems,
{ variables: variables }
);
}
async createItem(variables: object) {
return await this.client.api(mondayGraphQLMutations.createItem, {
variables: variables,
});
}
async updateItem(variables: object) {
return await this.client.api(mondayGraphQLMutations.updateItem, {
variables: variables,
});
}
async createWebhook(variables: object) {
return await this.client.api<{ id: string; board_id: string }>(
mondayGraphQLMutations.createWebhook,
{
variables: variables,
}
);
}
async deleteWebhook(variables: object) {
return await this.client.api(mondayGraphQLMutations.deleteWebhook, {
variables: variables,
});
}
async listUsers() {
return await this.client.api<{ users: User[] }>(
mondayGraphQLQueries.listUsers
);
}
async getBoardItemValues(variables: object) {
return await this.client.api<{ boards: Board[] }>(
mondayGraphQLQueries.getBoardItemValues,
{ variables: variables }
);
}
async getItemColumnValues(variables: object) {
return await this.client.api<{ boards: Board[] }>(
mondayGraphQLQueries.getItemColumnValues,
{
variables: variables,
}
);
}
async createColumn(variables: object) {
return await this.client.api<{ id: string }>(
mondayGraphQLMutations.createColumn,
{ variables: variables }
);
}
async createGroup(variables: object) {
return await this.client.api<{ id: string }>(
mondayGraphQLMutations.createGroup,
{ variables: variables }
);
}
async createUpdate(variables: object) {
return await this.client.api<{ id: string }>(
mondayGraphQLMutations.createUpdate,
{ variables: variables }
);
}
}

View File

@@ -0,0 +1,199 @@
export const enum MondayColumnType {
AUTO_NUMBER = 'auto_number',
BOARD_RELATION = 'board_relation',
BUTTON = 'button',
CHECKBOX = 'checkbox',
COLOR_PICKER = 'color_picker',
COUNTRY = 'country',
CREATION_LOG = 'creation_log',
DATE = 'date',
DEPENDENCY = 'dependency',
DOC = 'doc',
DROPDOWN = 'dropdown',
EMAIL = 'email',
FILE = 'file',
FORMULA = 'formula',
HOUR = 'hour',
ITEM_ASSIGNEES = 'item_assignees',
ITEM_ID = 'item_id',
LAST_UPDATED = 'last_updated',
LINK = 'link',
LOCATION = 'location',
LONG_TEXT = 'long_text',
MIRROR = 'mirror',
NAME = 'name',
NUMBERS = 'numbers',
PHONE = 'phone',
PEOPLE = 'people',
PROGRESS = 'progress',
RATING = 'rating',
STATUS = 'status',
SUBTASKS = 'subtasks',
TAGS = 'tags',
TEAM = 'team',
TEXT = 'text',
TIMELINE = 'timeline',
TIME_TRACKING = 'time_tracking',
VOTE = 'vote',
WEEK = 'week',
WORLD_CLOCK = 'world_clock',
UNSUPPORTED = 'unsupported',
}
export const enum MondayWebhookEventType {
CHANGE_COLUMN_VALUE = 'change_column_value',
CHANGE_STATUS_COLUMN_VALUE = 'change_status_column_value',
CHANGE_SUBITEM_COLUMN_VALUE = 'change_subitem_column_value',
CHANGE_SPECIFIC_COLUMN_VALUE = 'change_specific_column_value',
CHANGE_NAME = 'change_name',
CREATE_ITEM = 'create_item',
ITEM_ARCHIVED = 'item_archived',
ITEM_DELETED = 'item_deleted',
ITEM_MOVED_TO_ANY_GROUP = 'item_moved_to_any_group',
ITEM_MOVED_TO_SPECIFIC_GROUP = 'item_moved_to_specific_group',
ITEM_RESTORED = 'item_restored',
CREATE_SUBITEM = 'create_subitem',
CHANGE_SUBITEM_NAME = 'change_subitem_name',
MOVE_SUBITEM = 'move_subitem',
SUBITEM_ARCHIVED = 'subitem_archived',
SUBITEM_DELETED = 'subitem_deleted',
CREATE_COLUMN = 'create_column',
CREATE_UPDATE = 'create_update',
EDIT_UPDATE = 'edit_update',
DELETE_UPDATE = 'delete_update',
CREATE_SUBITEM_UPDATE = 'create_subitem_update',
}
export const enum BoardType {
BOARD = 'board',
SUB_ITEMS_BOARD = 'sub_items_board',
}
export const MondayNotWritableColumnType = [
MondayColumnType.UNSUPPORTED,
MondayColumnType.AUTO_NUMBER,
MondayColumnType.NAME,
MondayColumnType.COLOR_PICKER,
MondayColumnType.BUTTON,
MondayColumnType.MIRROR,
MondayColumnType.SUBTASKS,
MondayColumnType.ITEM_ID,
MondayColumnType.CREATION_LOG,
MondayColumnType.FILE,
MondayColumnType.FORMULA,
MondayColumnType.DOC,
MondayColumnType.LAST_UPDATED,
MondayColumnType.PROGRESS,
MondayColumnType.TAGS,
MondayColumnType.TIME_TRACKING,
MondayColumnType.VOTE,
];
export const COLUMN_TYPE_OPTIONS = [
{
label: 'Auto Number',
value: MondayColumnType.AUTO_NUMBER,
},
{
label: 'Color Picker',
value: MondayColumnType.COLOR_PICKER,
},
{
label: 'Checkbox',
value: MondayColumnType.CHECKBOX,
},
{
label: 'Country',
value: MondayColumnType.COUNTRY,
},
{
label: 'Creation Log',
value: MondayColumnType.CREATION_LOG,
},
{
label: 'Date',
value: MondayColumnType.DATE,
},
{
label: 'Dropdown',
value: MondayColumnType.DROPDOWN,
},
{
label: 'Email',
value: MondayColumnType.EMAIL,
},
{
label: 'Hour',
value: MondayColumnType.HOUR,
},
{
label: 'Item ID',
value: MondayColumnType.ITEM_ID,
},
{
label: 'Last Updated',
value: MondayColumnType.LAST_UPDATED,
},
{
label: 'Link',
value: MondayColumnType.LINK,
},
{
label: 'Location',
value: MondayColumnType.LOCATION,
},
{
label: 'Long Text',
value: MondayColumnType.LONG_TEXT,
},
{
label: 'Numbers',
value: MondayColumnType.NUMBERS,
},
{
label: 'People',
value: MondayColumnType.PEOPLE,
},
{
label: 'Phone',
value: MondayColumnType.PHONE,
},
{
label: 'Progress Tracking',
value: MondayColumnType.PROGRESS,
},
{
label: 'Rating',
value: MondayColumnType.RATING,
},
{
label: 'Status',
value: MondayColumnType.STATUS,
},
{
label: 'Tags',
value: MondayColumnType.TAGS,
},
{
label: 'Text',
value: MondayColumnType.TEXT,
},
{
label: 'Timeline',
value: MondayColumnType.TIMELINE,
},
{
label: 'Time Tracking',
value: MondayColumnType.TIME_TRACKING,
},
{
label: 'Vote',
value: MondayColumnType.VOTE,
},
{
label: 'Week',
value: MondayColumnType.WEEK,
},
{
label: 'World Clock',
value: MondayColumnType.WORLD_CLOCK,
},
];

View File

@@ -0,0 +1,374 @@
import {
DynamicPropsValue,
Property,
} from '@activepieces/pieces-framework';
import { isEmpty } from '@activepieces/shared';
import dayjs from 'dayjs';
import { MondayColumnType } from './constants';
import { ColumnValue, MondayColumn } from './models';
type ColumnIdTypeMap = {
[key: string]: string;
};
export function generateColumnIdTypeMap(
columns: MondayColumn[]
): ColumnIdTypeMap {
const result: ColumnIdTypeMap = {};
for (const column of columns) {
result[column.id] = column.type;
}
return result;
}
// creates activepiece prop type for monday column
export const convertMondayColumnToActivepiecesProp = (column: MondayColumn) => {
switch (column.type) {
case MondayColumnType.CHECKBOX:
return Property.Checkbox({
displayName: column.title,
required: false,
});
case MondayColumnType.BOARD_RELATION:
return Property.ShortText({
displayName: column.title,
description:
'A list of item IDs to connect with. The items must be on boards that are connected to the column. Example: [125345, 5846475]',
required: false,
});
case MondayColumnType.COUNTRY:
return Property.ShortText({
displayName: column.title,
required: false,
description: `The ISO 2-letter code and the country's name are separated by a dash. Example: US-United States`,
});
case MondayColumnType.DATE:
return Property.DateTime({
displayName: column.title,
required: false,
description: 'Use YYYY-MM-DD HH:mm:ss format.',
});
case MondayColumnType.DEPENDENCY:
return Property.ShortText({
displayName: column.title,
description:
'A list of item IDs from the same board. Example: [188392, 20339]',
required: false,
});
case MondayColumnType.DROPDOWN: {
const labels: { id: string; name: string }[] = JSON.parse(
column.settings_str
).labels;
return Property.StaticMultiSelectDropdown({
displayName: column.title,
required: false,
options: {
disabled: false,
options:
labels.length > 0
? labels.map((label) => {
return {
label: label.name,
value: label.name,
};
})
: [],
},
});
}
case MondayColumnType.EMAIL:
case MondayColumnType.LINK:
case MondayColumnType.TEXT:
return Property.ShortText({
displayName: column.title,
required: false,
});
case MondayColumnType.HOUR:
return Property.ShortText({
displayName: column.title,
required: false,
description: `Represent time in 24-hour format, like '16:30' or '2:00', ensuring removal of leading zeroes from data (e.g., send '9' instead of '09').`,
});
case MondayColumnType.LOCATION:
return Property.ShortText({
displayName: column.title,
required: false,
description: `Enter location details in the following format: **latitude|longitude|address(optional)**. For example: "37.7749|-122.4194|San Francisco, CA, USA."`,
});
case MondayColumnType.LONG_TEXT:
return Property.LongText({
displayName: column.title,
required: false,
});
case MondayColumnType.NUMBERS:
return Property.Number({
displayName: column.title,
required: false,
});
case MondayColumnType.PHONE:
return Property.ShortText({
displayName: column.title,
required: false,
description: `Enter your phone number along with the country's ISO 2-letter code, separated by a dash. For ezample, 1234567890-US.`,
});
case MondayColumnType.RATING:
return Property.Number({
displayName: column.title,
required: false,
description: `A number between 1 and 5.For example, 3.`,
});
case MondayColumnType.STATUS: {
const labels = JSON.parse(column.settings_str).labels;
const options: { label: string; value: string }[] = [];
Object.keys(labels).forEach((key) => {
if (labels[key] !== '') {
options.push({ value: labels[key], label: labels[key] });
}
});
return Property.StaticDropdown({
displayName: column.title,
required: false,
options: {
disabled: false,
options: options,
},
});
}
case MondayColumnType.TIMELINE:
return Property.ShortText({
displayName: column.title,
required: false,
description: `Enter the start and end dates in the YYYY-MM-DD format, separated by a symbol of semicolon(;) symbol. For example: '2022-01-01;2022-12-31`,
});
case MondayColumnType.WEEK:
return Property.ShortText({
displayName: column.title,
required: false,
description: `Enter the start and end dates in the YYYY-MM-DD format, separated by a symbol of semicolon(;) symbol. The dates must be 7 days apart (inclusive of the first and last date).\n For example: '2019-06-10;2019-06-16`,
});
case MondayColumnType.WORLD_CLOCK:
return Property.ShortText({
displayName: column.title,
required: false,
description: `Enter the timezone in the 'Continent/City' format, for example, Europe/London.`,
});
default:
return null;
}
};
export const convertPropValueToMondayColumnValue = (
columnType: string,
propValue: DynamicPropsValue
) => {
switch (columnType) {
case MondayColumnType.CHECKBOX:
return {
checked: propValue ? 'true' : 'false',
};
case MondayColumnType.BOARD_RELATION:
case MondayColumnType.DEPENDENCY:
return {
item_ids: JSON.parse(propValue as unknown as string),
};
case MondayColumnType.COUNTRY:
return {
countryCode: propValue.split('-')[0],
countryName: propValue.split('-')[1],
};
case MondayColumnType.DATE: {
let datevalue = dayjs(propValue as unknown as string);
if (!datevalue.isValid()) {
datevalue = dayjs();
}
return {
date: datevalue.format('YYYY-MM-DD'),
time: datevalue.format('HH:mm:ss'),
};
}
case MondayColumnType.DROPDOWN:
return {
labels: propValue,
};
case MondayColumnType.EMAIL:
return {
email: propValue,
text: propValue,
};
case MondayColumnType.HOUR: {
const [hour, minute] = propValue.split(':');
return {
hour: Number(hour) ?? 0,
minute: Number(minute) ?? 0,
};
}
case MondayColumnType.LINK:
return {
url: propValue,
text: propValue,
};
case MondayColumnType.LOCATION: {
const [lat, lng, address] = propValue.split('|');
return {
lat: lat ?? '',
lng: lng ?? '',
address: address ?? '',
};
}
case MondayColumnType.LONG_TEXT:
return {
text: propValue,
};
case MondayColumnType.NUMBERS:
return String(propValue);
case MondayColumnType.PEOPLE: {
const res: { id: string; kind: string }[] = [];
if (Array.isArray(propValue)) {
propValue.forEach((person) => {
res.push({ id: person, kind: 'person' });
});
}
return {
personsAndTeams: res,
};
}
case MondayColumnType.PHONE: {
const [phone, countryCode] = propValue.split('-');
return {
phone: `+${phone}`,
countryShortName: countryCode,
};
}
case MondayColumnType.RATING:
return {
rating: Number(propValue),
};
case MondayColumnType.STATUS:
return {
label: propValue,
};
case MondayColumnType.TEXT:
return propValue;
case MondayColumnType.TIMELINE:
return {
from: propValue.split(';')[0],
to: propValue.split(';')[1],
};
case MondayColumnType.WEEK:
return {
startDate: propValue.split(';')[0],
endDate: propValue.split(';')[1],
};
case MondayColumnType.WORLD_CLOCK:
return {
timezone: propValue,
};
default:
return null;
}
};
export const parseMondayColumnValue = (columnValue: ColumnValue) => {
switch (columnValue.type) {
case MondayColumnType.BUTTON:
return columnValue.label;
case MondayColumnType.CHECKBOX:
return JSON.parse(columnValue.value)?.checked ?? false;
case MondayColumnType.BOARD_RELATION:
return columnValue.linked_item_ids ?? [];
case MondayColumnType.DEPENDENCY:
return JSON.parse(columnValue.linked_item_ids ?? '[]');
case MondayColumnType.SUBTASKS: {
const res: number[] = [];
if (!isEmpty(JSON.parse(columnValue.value))) {
JSON.parse(columnValue.value).linkedPulseIds.map(
(item: { linkedPulseId: number }) => {
res.push(item.linkedPulseId);
}
);
}
return res;
}
case MondayColumnType.COLOR_PICKER:
return JSON.parse(columnValue.value)?.color.hex ?? null;
case MondayColumnType.COUNTRY:
return JSON.parse(columnValue.value)?.countryName ?? null;
case MondayColumnType.CREATION_LOG:
return JSON.parse(columnValue.value)?.created_at ?? null;
case MondayColumnType.DATE: {
if (isEmpty(columnValue.value)) {
return null;
}
const dateTime = JSON.parse(columnValue.value);
return `${dateTime.date} ${dateTime.time}`;
}
case MondayColumnType.DOC:
return JSON.parse(columnValue.value)?.files[0].linkToFile ?? null;
case MondayColumnType.DROPDOWN:
return JSON.parse(columnValue.value)?.ids ?? [];
case MondayColumnType.EMAIL:
return JSON.parse(columnValue.value)?.email ?? null;
case MondayColumnType.FILE:
return columnValue.text;
case MondayColumnType.HOUR: {
if (isEmpty(columnValue.value)) {
return null;
}
const hourTime = JSON.parse(columnValue.value);
return `${hourTime.hour}:${hourTime.minute}`;
}
case MondayColumnType.ITEM_ID:
return JSON.parse(columnValue.value)?.item_id ?? null;
case MondayColumnType.LAST_UPDATED:
return JSON.parse(columnValue.value).updated_at;
case MondayColumnType.LINK:
return JSON.parse(columnValue.value)?.url ?? null;
case MondayColumnType.LOCATION:
return JSON.parse(columnValue.value)?.address ?? null;
case MondayColumnType.LONG_TEXT:
return JSON.parse(columnValue.value)?.text ?? null;
case MondayColumnType.MIRROR:
return null;
case MondayColumnType.NUMBERS:
return Number(JSON.parse(columnValue.value));
case MondayColumnType.PEOPLE: {
const people: number[] = [];
if (!isEmpty(columnValue.value)) {
JSON.parse(columnValue.value).personsAndTeams.map(
(item: { id: number; kind: string }) => {
people.push(item.id);
}
);
}
return people;
}
case MondayColumnType.PHONE:
return JSON.parse(columnValue.value)?.phone ?? null;
case MondayColumnType.RATING:
return JSON.parse(columnValue.value)?.rating ?? null;
case MondayColumnType.STATUS:
return columnValue.label;
case MondayColumnType.TAGS:
return columnValue.tags.map((item: { name: string }) => item.name);
case MondayColumnType.TEXT:
return JSON.parse(columnValue.value);
case MondayColumnType.TIMELINE: {
if (isEmpty(columnValue.value)) {
return null;
}
const timeline = JSON.parse(columnValue.value);
return { from: timeline.from, to: timeline.to };
}
case MondayColumnType.TIME_TRACKING:
return JSON.parse(columnValue.value)?.duration ?? null;
case MondayColumnType.VOTE:
return columnValue?.vote_count ?? 0;
case MondayColumnType.WEEK: {
return {
startDate: columnValue.start_date,
endDate: columnValue.end_date,
};
}
case MondayColumnType.WORLD_CLOCK:
return JSON.parse(columnValue.value)?.timezone ?? null;
}
};

View File

@@ -0,0 +1,219 @@
import { AppConnectionValueForAuthProperty, DynamicPropsValue, Property } from '@activepieces/pieces-framework';
import { mondayClient } from './client';
import { MondayColumnType, MondayNotWritableColumnType } from './constants';
import { convertMondayColumnToActivepiecesProp } from './helper';
import { mondayAuth } from '../..';
export function makeClient(auth: AppConnectionValueForAuthProperty<typeof mondayAuth>): mondayClient {
return new mondayClient(auth.secret_text);
}
export const mondayCommon = {
workspace_id: (required = true) =>
Property.Dropdown({
auth: mondayAuth,
displayName: 'Workspace ID',
required: required,
refreshers: [],
options: async ({ auth }) => {
if (!auth) {
return {
disabled: true,
placeholder: 'connect your account first',
options: [],
};
}
const client = makeClient(auth);
const res = await client.listWorkspcaes();
return {
disabled: false,
options: res.data.workspaces.map((workspace) => {
return {
label: workspace.name,
value: workspace.id,
};
}),
};
},
}),
board_id: (required = true) =>
Property.Dropdown({
auth: mondayAuth,
displayName: 'Board ID',
required: required,
refreshers: ['workspace_id'],
options: async ({ auth, workspace_id }) => {
if (!auth || !workspace_id) {
return {
disabled: true,
placeholder:
'connect your account first and select your workspace.',
options: [],
};
}
const client = makeClient(auth);
const res = await client.listWorkspaceBoards({
workspaceId: workspace_id as string,
});
return {
disabled: false,
options: res.data.boards
.filter((board) => board.type === 'board')
.map((board) => {
return {
label: board.name,
value: board.id,
};
}),
};
},
}),
group_id: (required = false) =>
Property.Dropdown({
auth: mondayAuth,
displayName: 'Board Group ID',
required: required,
refreshers: ['board_id'],
options: async ({ auth, board_id }) => {
if (!auth || !board_id) {
return {
disabled: true,
placeholder:
'connect your account first and select workspace board.',
options: [],
};
}
const client = makeClient(auth);
const res = await client.listBoardGroups({
boardId: board_id as string,
});
return {
disabled: false,
options:
res.data.boards.length > 0
? res.data.boards[0]?.groups.map((group) => ({
label: group.title,
value: group.id,
}))
: [],
};
},
}),
item_id: (required = true) =>
Property.Dropdown({
auth: mondayAuth,
displayName: 'Item ID',
required: required,
refreshers: ['board_id'],
options: async ({ auth, board_id }) => {
if (!auth || !board_id) {
return {
disabled: true,
placeholder:
'connect your account first and select workspace board.',
options: [],
};
}
const client = makeClient(auth);
const res = await client.listBoardItems({
boardId: board_id as string,
});
const items = res.data.boards[0]?.items_page.items;
return {
disabled: false,
options: items.map((item) => {
return {
label: item.name,
value: item.id,
};
}),
};
},
}),
columnIds: (required = true) =>
Property.MultiSelectDropdown({
auth: mondayAuth,
displayName: 'Column IDs',
description:
'Limit data output by specifying column IDs; leave empty to display all columns.',
required,
refreshers: ['board_id'],
options: async ({ auth, board_id }) => {
if (!auth || !board_id) {
return {
disabled: true,
placeholder:
'connect your account first and select workspace board.',
options: [],
};
}
const client = makeClient(auth);
const res = await client.listBoardColumns({
boardId: board_id as string,
});
return {
disabled: false,
options: res.data.boards[0].columns.map((column) => {
return {
label: column.title,
value: column.id,
};
}),
};
},
}),
columnValues: Property.DynamicProperties({
auth: mondayAuth,
displayName: 'Columns',
required: true,
refreshers: ['board_id'],
props: async ({ auth, board_id }) => {
if (!auth || !board_id) {
return {
disabled: true,
placeholder: 'connect your account first and select workspace board.',
options: [],
};
}
const fields: DynamicPropsValue = {};
try {
const client = makeClient(auth);
const res = await client.listBoardColumns({
boardId: board_id as unknown as string,
});
const columns = res.data.boards[0]?.columns;
for (const column of columns) {
if (!MondayNotWritableColumnType.includes(column.type)) {
if (column.type === MondayColumnType.PEOPLE) {
const userData = await client.listUsers();
fields[column.id] = Property.StaticMultiSelectDropdown({
displayName: column.title,
required: false,
options: {
disabled: false,
options: userData.data.users.map((user) => {
return {
label: `${user.name} (${user.email})`,
value: user.id,
};
}),
},
});
} else {
const prop = convertMondayColumnToActivepiecesProp(column);
if (prop != null) fields[column.id] = prop;
}
}
}
} catch (e) {
console.debug(e);
}
return fields;
},
}),
};

View File

@@ -0,0 +1,80 @@
import { BoardType, MondayColumnType } from './constants';
export interface MondayColumn {
id: string;
title: string;
type: MondayColumnType;
description?: string;
settings_str: string;
}
export interface ColumnValue {
id: string;
value: string;
text: string;
type: MondayColumnType;
[key: string]: any;
}
export type WorkspaceResponse = {
data: { workspaces: Workspace[] };
account_id: number;
};
export interface Workspace {
id: string;
name: string;
}
export interface Group {
id: string;
title: string;
}
export interface SubItem {
id: string;
board: Board;
group: Group;
subscribers: User[];
name: string;
email: string;
created_at: string;
}
export interface Item {
id: string;
board: Board;
group: Group;
name: string;
email: string;
created_at: string;
column_values: ColumnValue[];
subitems: SubItem[];
}
export interface Board {
id: string;
name: string;
groups: Group[];
type: BoardType;
items_page: { items: Item[] };
}
export interface Update {
body: string;
id: string;
created_at: string;
creator: {
name: string;
id: string;
};
}
export interface User {
id: string;
name: string;
email: string;
created_at: string;
}
export type BoardResponse = { data: { boards: Board[] }; account_id: number };
export interface WebhookInformation {
id: string;
board_id: string;
}

View File

@@ -0,0 +1,81 @@
export const mondayGraphQLMutations = {
createItem: `
mutation createItem(
$itemName: String!
$boardId: ID!
$groupId: String
$columnValues: JSON
$createLabels: Boolean
) {
create_item(
item_name: $itemName
board_id: $boardId
group_id: $groupId
column_values: $columnValues
create_labels_if_missing: $createLabels
) {
id
}
}`,
updateItem: `
mutation updateItem($itemId: ID!, $boardId: ID!, $columnValues: JSON!) {
change_multiple_column_values(
item_id: $itemId
board_id: $boardId
column_values: $columnValues
) {
id
name
}
}`,
createWebhook: `
mutation createWebhook(
$boardId: ID!
$url: String!
$event: WebhookEventType!
$config: JSON
) {
create_webhook(
board_id: $boardId
url: $url
event: $event
config: $config
) {
id
board_id
}
}`,
deleteWebhook: `
mutation deleteWebhook($webhookId: ID!) {
delete_webhook(id: $webhookId) {
id
board_id
}
}`,
createColumn: `
mutation createColumn(
$boardId: ID!
$columnTitle: String!
$columnType: ColumnType!
) {
create_column(
board_id: $boardId
title: $columnTitle
column_type: $columnType
) {
id
}
}`,
createGroup: `
mutation createGroup($boardId: ID!, $groupName: String!) {
create_group(board_id: $boardId, group_name: $groupName) {
id
}
}`,
createUpdate: `
mutation createUpdate($itemId: ID!, $body: String!) {
create_update(item_id: $itemId, body: $body) {
id
}
}`,
};

View File

@@ -0,0 +1,158 @@
export const mondayGraphQLQueries = {
listWorkspaces: `
query listWorkspaces($limit: Int)
{
workspaces(limit: $limit)
{
id
name
}
}`,
listWorkspaceBoards: `
query listWorkspaceBoards($workspaceId: ID)
{
boards(workspace_ids: [$workspaceId], order_by: created_at)
{
id
name
type
}
}`,
listBoardGroups: `
query listGroups($boardId: ID!)
{
boards(ids: [$boardId])
{
groups{
id
title
}
}
}`,
listBoardColumns: `
query listBoardColumns($boardId: ID!)
{
boards(ids: [$boardId])
{
columns{
id
title
type
settings_str
description
}
}
}`,
listBoardItems: `
query listBoardItems($boardId: ID!)
{
boards(ids: [$boardId])
{
items_page
{
items{
id
name
}
}
}
}`,
listUsers: `
query listUsers
{
users(newest_first: true)
{
id
name
email
}
}`,
getItemColumnValues: `
query getItemColumnValues($boardId: ID!,$itemId: ID!,$columnIds: [String!])
{
boards(ids: [$boardId])
{
items_page(query_params: {ids: [$itemId]})
{
items{
id
name
column_values(ids: $columnIds){
id
type
value
text
... on ButtonValue{
label
}
... on StatusValue{
label
}
... on VoteValue{
vote_count
}
... on TagsValue{
tags{
name
}
}
... on BoardRelationValue {
linked_item_ids
}
... on DependencyValue {
linked_item_ids
}
... on WeekValue {
start_date
end_date
}
}
}
}
}
}`,
getBoardItemValues: `
query getItemColumnValues($boardId: ID!,$columnIds: [String!])
{
boards(ids: [$boardId])
{
items_page(query_params: {order_by: {column_id: "__last_updated__",direction: desc}})
{
items{
id
name
column_values(ids: $columnIds){
id
type
value
text
... on ButtonValue{
label
}
... on StatusValue{
label
}
... on VoteValue{
vote_count
}
... on TagsValue{
tags{
name
}
}
... on BoardRelationValue {
linked_item_ids
}
... on DependencyValue {
linked_item_ids
}
... on WeekValue {
start_date
end_date
}
}
}
}
}
}`,
};

View File

@@ -0,0 +1,118 @@
import {
TriggerStrategy,
createTrigger,
} from '@activepieces/pieces-framework';
import { mondayAuth } from '../..';
import { makeClient, mondayCommon } from '../common';
import { MondayWebhookEventType } from '../common/constants';
import { parseMondayColumnValue } from '../common/helper';
import { WebhookInformation } from '../common/models';
import { WebhookHandshakeStrategy } from '@activepieces/shared';
export const newItemInBoardTrigger = createTrigger({
auth: mondayAuth,
name: 'monday_new_item_in_board',
displayName: 'New Item in Board',
description: 'Triggers when a new item is created in board.',
props: {
workspace_id: mondayCommon.workspace_id(true),
board_id: mondayCommon.board_id(true),
},
type: TriggerStrategy.WEBHOOK,
sampleData: {
event: {
userId: 9603417,
originalTriggerUuid: null,
boardId: 1771812698,
pulseId: 1772099344,
pulseName: 'Create_item webhook',
groupId: 'topics',
groupName: 'Group Title',
groupColor: '#579bfc',
isTopGroup: true,
columnValues: {},
app: 'monday',
type: 'create_pulse',
triggerTime: '2021-10-11T09:07:28.210Z',
subscriptionId: 73759690,
triggerUuid: 'b5ed2e17c530f43668de130142445cba',
},
},
async onEnable(context) {
const { board_id } = context.propsValue;
const client = makeClient(context.auth);
const res = await client.createWebhook({
boardId: board_id,
url: context.webhookUrl,
event: MondayWebhookEventType.CREATE_ITEM,
});
await context.store.put<WebhookInformation>(
'monday_new_item_trigger',
res.data
);
},
async onDisable(context) {
const webhook = await context.store.get<WebhookInformation>(
'monday_new_item_trigger'
);
if (webhook != null) {
const client = makeClient(context.auth);
await client.deleteWebhook({ webhookId: webhook.id });
}
},
async run(context) {
const payload = context.payload.body as MondayWebhookPayload;
const transformedValues: Record<string, any> = {};
try {
const client = makeClient(context.auth);
const res = await client.getItemColumnValues({
boardId: payload.event.boardId,
itemId: payload.event.pulseId,
});
const item = res.data.boards[0].items_page.items[0];
for (const column of item.column_values) {
transformedValues[column.id] = parseMondayColumnValue(column);
}
} catch (e) {
console.error(e);
}
const enriched = [
{
...payload,
columnValues: transformedValues,
},
];
return enriched;
},
handshakeConfiguration: {
strategy: WebhookHandshakeStrategy.BODY_PARAM_PRESENT,
paramName: 'challenge',
},
async onHandshake(context) {
return {
status: 200,
body: { challenge: (context.payload.body as any)['challenge'] },
};
},
});
interface MondayWebhookPayload {
event: {
userId: number;
originalTriggerUuid: null;
boardId: number;
pulseId: number;
pulseName: string;
groupId: string;
groupName: string;
groupColor: string;
isTopGroup: boolean;
columnValues: Record<string, unknown>;
app: string;
type: 'create_pulse';
triggerTime: string;
subscriptionId: number;
triggerUuid: string;
};
}

View File

@@ -0,0 +1,124 @@
import {
Property,
TriggerStrategy,
createTrigger,
} from '@activepieces/pieces-framework';
import { mondayAuth } from '../..';
import { makeClient, mondayCommon } from '../common';
import {
MondayNotWritableColumnType,
MondayWebhookEventType,
} from '../common/constants';
import { WebhookInformation } from '../common/models';
import { WebhookHandshakeStrategy } from '@activepieces/shared';
export const specificColumnValueUpdatedTrigger = createTrigger({
auth: mondayAuth,
name: 'monday_specific_column_updated',
displayName: 'Specific Column Value Updated in Board',
description: 'Triggers when a specific column value is updated in board.',
props: {
workspace_id: mondayCommon.workspace_id(true),
board_id: mondayCommon.board_id(true),
column_id: Property.Dropdown({
auth: mondayAuth,
displayName: 'Column ID',
required: true,
refreshers: ['board_id'],
options: async ({ auth, board_id }) => {
if (!auth || !board_id) {
return {
disabled: true,
placeholder:
'connect your account first and select workspace board.',
options: [],
};
}
const client = makeClient(auth);
const res = await client.listBoardColumns({
boardId: board_id as string,
});
return {
disabled: false,
options: res.data.boards[0].columns
.filter(
(column) => !MondayNotWritableColumnType.includes(column.type)
)
.map((column) => {
return {
label: column.title,
value: column.id,
};
}),
};
},
}),
},
type: TriggerStrategy.WEBHOOK,
sampleData: {
event: {
app: 'monday',
type: 'update_column_value',
triggerTime: '2024-01-08T04:41:55.245Z',
subscriptionId: 3209024,
userId: 53812737,
originalTriggerUuid: null,
boardId: 1835745535,
groupId: 'topics',
pulseId: 1835700420,
pulseName: 'Sample Item',
columnId: 'country',
columnType: 'country',
columnTitle: 'Country',
value: {
countryCode: 'AW',
countryName: 'Aruba',
changed_at: '2024-01-08T04:42:00.109Z',
},
previousValue: {
changed_at: '2024-01-08T04:41:39.461Z',
countryCode: 'IO',
countryName: 'British Indian Ocean Territory',
},
changedAt: 1704688953.239433,
isTopGroup: true,
triggerUuid: '72a1ec82ea678e03b55b050711b71e9d',
},
},
async onEnable(context) {
const { board_id, column_id } = context.propsValue;
const client = makeClient(context.auth);
const res = await client.createWebhook({
boardId: board_id,
url: context.webhookUrl,
event: MondayWebhookEventType.CHANGE_SPECIFIC_COLUMN_VALUE,
config: JSON.stringify({ columnId: column_id }),
});
await context.store.put<WebhookInformation>(
'monday_specific_column_updated',
res.data
);
},
async onDisable(context) {
const webhook = await context.store.get<WebhookInformation>(
'monday_specific_column_updated'
);
if (webhook != null) {
const client = makeClient(context.auth);
await client.deleteWebhook({ webhookId: webhook.id });
}
},
async run(context) {
return [context.payload.body];
},
handshakeConfiguration: {
strategy: WebhookHandshakeStrategy.BODY_PARAM_PRESENT,
paramName: 'challenge',
},
async onHandshake(context) {
return {
status: 200,
body: { challenge: (context.payload.body as any)['challenge'] },
};
},
});