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,33 @@
|
||||
{
|
||||
"extends": [
|
||||
"../../../../.eslintrc.base.json"
|
||||
],
|
||||
"ignorePatterns": [
|
||||
"!**/*"
|
||||
],
|
||||
"overrides": [
|
||||
{
|
||||
"files": [
|
||||
"*.ts",
|
||||
"*.tsx",
|
||||
"*.js",
|
||||
"*.jsx"
|
||||
],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": [
|
||||
"*.ts",
|
||||
"*.tsx"
|
||||
],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": [
|
||||
"*.js",
|
||||
"*.jsx"
|
||||
],
|
||||
"rules": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
# pieces-bookedin
|
||||
|
||||
This library was generated with [Nx](https://nx.dev).
|
||||
|
||||
## Building
|
||||
|
||||
Run `nx build pieces-bookedin` to build the library.
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "@activepieces/piece-bookedin",
|
||||
"version": "0.0.1",
|
||||
"type": "commonjs",
|
||||
"main": "./src/index.js",
|
||||
"types": "./src/index.d.ts",
|
||||
"dependencies": {
|
||||
"tslib": "^2.3.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
{
|
||||
"name": "pieces-bookedin",
|
||||
"$schema": "../../../../node_modules/nx/schemas/project-schema.json",
|
||||
"sourceRoot": "packages/pieces/community/bookedin/src",
|
||||
"projectType": "library",
|
||||
"release": {
|
||||
"version": {
|
||||
"manifestRootsToUpdate": [
|
||||
"dist/{projectRoot}"
|
||||
],
|
||||
"currentVersionResolver": "git-tag",
|
||||
"fallbackCurrentVersionResolver": "disk"
|
||||
}
|
||||
},
|
||||
"tags": [],
|
||||
"targets": {
|
||||
"build": {
|
||||
"executor": "@nx/js:tsc",
|
||||
"outputs": [
|
||||
"{options.outputPath}"
|
||||
],
|
||||
"options": {
|
||||
"outputPath": "dist/packages/pieces/community/bookedin",
|
||||
"tsConfig": "packages/pieces/community/bookedin/tsconfig.lib.json",
|
||||
"packageJson": "packages/pieces/community/bookedin/package.json",
|
||||
"main": "packages/pieces/community/bookedin/src/index.ts",
|
||||
"assets": [
|
||||
"packages/pieces/community/bookedin/*.md",
|
||||
{
|
||||
"input": "packages/pieces/community/bookedin/src/i18n",
|
||||
"output": "./src/i18n",
|
||||
"glob": "**/!(i18n.json)"
|
||||
}
|
||||
],
|
||||
"buildableProjectDepsInPackageJsonType": "dependencies",
|
||||
"updateBuildableProjectDepsInPackageJson": true
|
||||
},
|
||||
"dependsOn": [
|
||||
"prebuild",
|
||||
"^build"
|
||||
]
|
||||
},
|
||||
"nx-release-publish": {
|
||||
"options": {
|
||||
"packageRoot": "dist/{projectRoot}"
|
||||
}
|
||||
},
|
||||
"prebuild": {
|
||||
"dependsOn": [
|
||||
"^build"
|
||||
],
|
||||
"executor": "nx:run-commands",
|
||||
"options": {
|
||||
"cwd": "packages/pieces/community/bookedin",
|
||||
"command": "bun install --no-save --silent"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"executor": "@nx/eslint:lint",
|
||||
"outputs": [
|
||||
"{options.outputFile}"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
import { createPiece, PieceAuth } from "@activepieces/pieces-framework";
|
||||
import { httpClient, HttpMethod, createCustomApiCallAction } from '@activepieces/pieces-common';
|
||||
import { BASE_URL, extractApiKey } from './lib/common/props';
|
||||
import { getLeads } from "./lib/actions/get-leads";
|
||||
import { createLead } from "./lib/actions/create-lead";
|
||||
import { getLead } from "./lib/actions/get-lead";
|
||||
import { deleteLead } from "./lib/actions/delete-lead";
|
||||
import { getLeadStats } from "./lib/actions/get-lead-stats";
|
||||
import { updateLead } from "./lib/actions/update-lead";
|
||||
import { PieceCategory } from "@activepieces/shared";
|
||||
|
||||
|
||||
// --- Authentication ---
|
||||
export const bookedinAuth = PieceAuth.SecretText({
|
||||
displayName: 'API Key',
|
||||
required: true,
|
||||
description: `To connect your Bookedin account, please follow these steps to retrieve your API Key:
|
||||
|
||||
1. Log in to your Bookedin Dashboard: dashboard.bookedin.ai
|
||||
2. From the left menu, go to **Business**
|
||||
3. Open **Settings**
|
||||
4. Click on **API Key**
|
||||
5. Copy your API Key (starts with **sk_…**)
|
||||
6. Paste the key below to authorize the integration
|
||||
|
||||
Your API Key allows Activepieces to securely access your Bookedin leads, agents, and booking data.
|
||||
`,
|
||||
validate: async ({ auth }) => {
|
||||
try {
|
||||
const apiKey = extractApiKey(auth);
|
||||
|
||||
if (!apiKey) {
|
||||
return { valid: false, error: 'API Key is empty' };
|
||||
}
|
||||
|
||||
await httpClient.sendRequest({
|
||||
method: HttpMethod.GET,
|
||||
url: `${BASE_URL}/agents/`,
|
||||
headers: {
|
||||
'X-API-Key': apiKey as string,
|
||||
'accept': 'application/json'
|
||||
},
|
||||
queryParams: {
|
||||
skip: '0',
|
||||
limit: '1'
|
||||
}
|
||||
});
|
||||
return { valid: true };
|
||||
} catch (e: any) {
|
||||
const errorMessage = e?.response?.body?.detail || e?.message || 'Connection failed';
|
||||
return {
|
||||
valid: false,
|
||||
error: errorMessage
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
// --- Piece Definition ---
|
||||
export const bookedin = createPiece({
|
||||
displayName: 'Bookedin',
|
||||
description: 'AI agents for lead conversion and appointment booking.',
|
||||
logoUrl: 'https://cdn.activepieces.com/pieces/bookedin.png',
|
||||
categories: [PieceCategory.SALES_AND_CRM],
|
||||
auth: bookedinAuth,
|
||||
minimumSupportedRelease: '0.36.1',
|
||||
authors: ["drona2938", "onyedikachi-david"],
|
||||
actions: [
|
||||
getLeads,
|
||||
createLead,
|
||||
getLead,
|
||||
deleteLead,
|
||||
getLeadStats,
|
||||
updateLead,
|
||||
createCustomApiCallAction({
|
||||
baseUrl: () => BASE_URL,
|
||||
auth: bookedinAuth,
|
||||
authMapping: async (auth) => {
|
||||
const apiKey = extractApiKey(auth);
|
||||
return {
|
||||
'X-API-Key': apiKey,
|
||||
};
|
||||
},
|
||||
}),
|
||||
],
|
||||
triggers: [],
|
||||
});
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
import { createAction } from '@activepieces/pieces-framework';
|
||||
import { httpClient, HttpMethod } from '@activepieces/pieces-common';
|
||||
import { bookedinAuth } from '../../index';
|
||||
import { BASE_URL, getBookedinHeaders, leadIdsMultiSelectDropdown, extractApiKey } from '../common/props';
|
||||
|
||||
export const bulkDeleteLeads = createAction({
|
||||
name: 'bulkDeleteLeads',
|
||||
displayName: 'Bulk Delete Leads',
|
||||
description: 'Delete multiple leads (max 500 per request)',
|
||||
auth: bookedinAuth,
|
||||
props: {
|
||||
lead_ids: leadIdsMultiSelectDropdown,
|
||||
},
|
||||
async run({ auth, propsValue }) {
|
||||
const apiKey = extractApiKey(auth);
|
||||
const leadIds = Array.isArray(propsValue.lead_ids) ? propsValue.lead_ids : [propsValue.lead_ids];
|
||||
|
||||
if (leadIds.length === 0) {
|
||||
throw new Error('At least one lead must be selected');
|
||||
}
|
||||
|
||||
if (leadIds.length > 500) {
|
||||
throw new Error('Maximum 500 leads can be deleted per request');
|
||||
}
|
||||
|
||||
const response = await httpClient.sendRequest({
|
||||
method: HttpMethod.POST,
|
||||
url: `${BASE_URL}/leads/bulk-delete`,
|
||||
headers: {
|
||||
...getBookedinHeaders(apiKey),
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: {
|
||||
lead_ids: leadIds,
|
||||
},
|
||||
});
|
||||
|
||||
return response.body;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,55 @@
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { httpClient, HttpMethod } from '@activepieces/pieces-common';
|
||||
import { bookedinAuth } from '../../index';
|
||||
import { BASE_URL, getBookedinHeaders, extractApiKey } from '../common/props';
|
||||
|
||||
export const createLead = createAction({
|
||||
name: 'createLead',
|
||||
displayName: 'Create Lead',
|
||||
description: 'Creates a new lead in Bookedin AI',
|
||||
auth: bookedinAuth,
|
||||
props: {
|
||||
firstName: Property.ShortText({
|
||||
displayName: 'First Name',
|
||||
required: true,
|
||||
}),
|
||||
lastName: Property.ShortText({
|
||||
displayName: 'Last Name',
|
||||
required: true,
|
||||
}),
|
||||
email: Property.ShortText({
|
||||
displayName: 'Email',
|
||||
required: true,
|
||||
}),
|
||||
phone: Property.ShortText({
|
||||
displayName: 'Phone Number',
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
async run({ auth, propsValue }) {
|
||||
const apiKey = extractApiKey(auth);
|
||||
|
||||
const payload = {
|
||||
contact: {
|
||||
name: {
|
||||
last: propsValue.lastName,
|
||||
first: propsValue.firstName,
|
||||
},
|
||||
email: propsValue.email,
|
||||
number: propsValue.phone,
|
||||
},
|
||||
};
|
||||
|
||||
const response = await httpClient.sendRequest({
|
||||
method: HttpMethod.POST,
|
||||
url: `${BASE_URL}/leads/`,
|
||||
headers: {
|
||||
...getBookedinHeaders(apiKey),
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: payload,
|
||||
});
|
||||
|
||||
return response.body;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,25 @@
|
||||
import { createAction } from '@activepieces/pieces-framework';
|
||||
import { httpClient, HttpMethod } from '@activepieces/pieces-common';
|
||||
import { bookedinAuth } from '../../index';
|
||||
import { BASE_URL, getBookedinHeaders, leadIdDropdown, extractApiKey } from '../common/props';
|
||||
|
||||
export const deleteLead = createAction({
|
||||
name: 'deleteLead',
|
||||
displayName: 'Delete Lead',
|
||||
description: 'Delete a lead.',
|
||||
auth: bookedinAuth,
|
||||
props: {
|
||||
lead_id: leadIdDropdown,
|
||||
},
|
||||
async run({ auth, propsValue }) {
|
||||
const apiKey = extractApiKey(auth);
|
||||
|
||||
const response = await httpClient.sendRequest({
|
||||
method: HttpMethod.DELETE,
|
||||
url: `${BASE_URL}/leads/${propsValue.lead_id}`,
|
||||
headers: getBookedinHeaders(apiKey),
|
||||
});
|
||||
|
||||
return response.body;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
import { createAction } from '@activepieces/pieces-framework';
|
||||
import { httpClient, HttpMethod } from '@activepieces/pieces-common';
|
||||
import { bookedinAuth } from '../../index';
|
||||
import { BASE_URL, getBookedinHeaders, extractApiKey } from '../common/props';
|
||||
|
||||
export const getLeadStats = createAction({
|
||||
name: 'getLeadStats',
|
||||
displayName: 'Get Lead Stats',
|
||||
description: 'Get lead statistics (Hot, Warm, Cold, Objectives Met, Total).',
|
||||
auth: bookedinAuth,
|
||||
props: {},
|
||||
async run({ auth }) {
|
||||
const apiKey = extractApiKey(auth);
|
||||
|
||||
const response = await httpClient.sendRequest({
|
||||
method: HttpMethod.GET,
|
||||
url: `${BASE_URL}/leads/stats`,
|
||||
headers: getBookedinHeaders(apiKey),
|
||||
});
|
||||
|
||||
return response.body;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,25 @@
|
||||
import { createAction } from '@activepieces/pieces-framework';
|
||||
import { httpClient, HttpMethod } from '@activepieces/pieces-common';
|
||||
import { bookedinAuth } from '../../index';
|
||||
import { BASE_URL, getBookedinHeaders, leadIdDropdown, extractApiKey } from '../common/props';
|
||||
|
||||
export const getLead = createAction({
|
||||
name: 'getLead',
|
||||
displayName: 'Get Lead',
|
||||
description: 'Get a specific lead by ID.',
|
||||
auth: bookedinAuth,
|
||||
props: {
|
||||
lead_id: leadIdDropdown,
|
||||
},
|
||||
async run({ auth, propsValue }) {
|
||||
const apiKey = extractApiKey(auth);
|
||||
|
||||
const response = await httpClient.sendRequest({
|
||||
method: HttpMethod.GET,
|
||||
url: `${BASE_URL}/leads/${propsValue.lead_id}`,
|
||||
headers: getBookedinHeaders(apiKey),
|
||||
});
|
||||
|
||||
return response.body;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,67 @@
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { httpClient, HttpMethod } from '@activepieces/pieces-common';
|
||||
import { bookedinAuth } from '../../index';
|
||||
import { BASE_URL, getBookedinHeaders, extractApiKey } from '../common/props';
|
||||
|
||||
export const getLeads = createAction({
|
||||
name: 'getLeads',
|
||||
displayName: 'Get Leads',
|
||||
description: 'Get all leads for the current business with pagination metadata.',
|
||||
auth: bookedinAuth,
|
||||
props: {
|
||||
search: Property.ShortText({
|
||||
displayName: 'Search',
|
||||
description: 'Search text in name, email, or phone number',
|
||||
required: false,
|
||||
}),
|
||||
source: Property.ShortText({
|
||||
displayName: 'Source',
|
||||
description: 'Filter by lead source (e.g., "API", "Import")',
|
||||
required: false,
|
||||
}),
|
||||
email: Property.ShortText({
|
||||
displayName: 'Email',
|
||||
description: 'Filter by exact email address',
|
||||
required: false,
|
||||
}),
|
||||
phone: Property.ShortText({
|
||||
displayName: 'Phone',
|
||||
description: 'Filter by phone number',
|
||||
required: false,
|
||||
}),
|
||||
limit: Property.Number({
|
||||
displayName: 'Limit',
|
||||
description: 'Number of leads to return',
|
||||
required: false,
|
||||
defaultValue: 100,
|
||||
}),
|
||||
skip: Property.Number({
|
||||
displayName: 'Skip',
|
||||
description: 'Number of leads to skip (pagination)',
|
||||
required: false,
|
||||
defaultValue: 0,
|
||||
}),
|
||||
},
|
||||
async run({ auth, propsValue }) {
|
||||
const apiKey = extractApiKey(auth);
|
||||
|
||||
const queryParams: Record<string, string> = {
|
||||
limit: (propsValue.limit ?? 100).toString(),
|
||||
skip: (propsValue.skip ?? 0).toString(),
|
||||
};
|
||||
|
||||
if (propsValue.search) queryParams['search'] = propsValue.search;
|
||||
if (propsValue.source) queryParams['source'] = propsValue.source;
|
||||
if (propsValue.email) queryParams['email'] = propsValue.email;
|
||||
if (propsValue.phone) queryParams['phone'] = propsValue.phone;
|
||||
|
||||
const response = await httpClient.sendRequest({
|
||||
method: HttpMethod.GET,
|
||||
url: `${BASE_URL}/leads/`,
|
||||
headers: getBookedinHeaders(apiKey),
|
||||
queryParams,
|
||||
});
|
||||
|
||||
return response.body;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,90 @@
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { httpClient, HttpMethod } from '@activepieces/pieces-common';
|
||||
import { bookedinAuth } from '../../index';
|
||||
import { BASE_URL, getBookedinHeaders, leadIdDropdown, extractApiKey } from '../common/props';
|
||||
import { isNil } from '@activepieces/shared';
|
||||
|
||||
export const updateLead = createAction({
|
||||
name: 'updateLead',
|
||||
displayName: 'Update Lead',
|
||||
description: 'Update a lead.',
|
||||
auth: bookedinAuth,
|
||||
props: {
|
||||
lead_id: leadIdDropdown,
|
||||
firstName: Property.ShortText({
|
||||
displayName: 'First Name',
|
||||
required: false,
|
||||
}),
|
||||
lastName: Property.ShortText({
|
||||
displayName: 'Last Name',
|
||||
required: false,
|
||||
}),
|
||||
email: Property.ShortText({
|
||||
displayName: 'Email',
|
||||
required: false,
|
||||
}),
|
||||
phone: Property.ShortText({
|
||||
displayName: 'Phone Number',
|
||||
required: false,
|
||||
}),
|
||||
handling_status: Property.ShortText({
|
||||
displayName: 'Handling Status',
|
||||
required: false,
|
||||
}),
|
||||
update_json: Property.Json({
|
||||
displayName: 'Update Payload (JSON)',
|
||||
description: 'Optional JSON body for complex updates. Merges with individual fields above.',
|
||||
required: false,
|
||||
defaultValue: {},
|
||||
}),
|
||||
},
|
||||
async run({ auth, propsValue }) {
|
||||
const apiKey = extractApiKey(auth);
|
||||
const basePayload: Record<string, unknown> = {};
|
||||
|
||||
if (!isNil(propsValue.firstName) || !isNil(propsValue.lastName) || !isNil(propsValue.email) || !isNil(propsValue.phone)) {
|
||||
const contact: Record<string, unknown> = {};
|
||||
|
||||
const nameParts: Record<string, string> = {};
|
||||
if (!isNil(propsValue.firstName) && propsValue.firstName !== '') {
|
||||
nameParts['first'] = propsValue.firstName;
|
||||
}
|
||||
if (!isNil(propsValue.lastName) && propsValue.lastName !== '') {
|
||||
nameParts['last'] = propsValue.lastName;
|
||||
}
|
||||
if (Object.keys(nameParts).length > 0) {
|
||||
contact['name'] = nameParts;
|
||||
}
|
||||
|
||||
if (!isNil(propsValue.email) && propsValue.email !== '') {
|
||||
contact['email'] = propsValue.email;
|
||||
}
|
||||
if (!isNil(propsValue.phone) && propsValue.phone !== '') {
|
||||
contact['number'] = propsValue.phone;
|
||||
}
|
||||
|
||||
basePayload['contact'] = contact;
|
||||
}
|
||||
|
||||
if (!isNil(propsValue.handling_status) && propsValue.handling_status !== '') {
|
||||
basePayload['handling_status'] = propsValue.handling_status;
|
||||
}
|
||||
|
||||
const finalPayload = {
|
||||
...basePayload,
|
||||
...(propsValue.update_json || {}),
|
||||
};
|
||||
|
||||
const response = await httpClient.sendRequest({
|
||||
method: HttpMethod.PUT,
|
||||
url: `${BASE_URL}/leads/${propsValue.lead_id}`,
|
||||
headers: {
|
||||
...getBookedinHeaders(apiKey),
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: finalPayload,
|
||||
});
|
||||
|
||||
return response.body;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,138 @@
|
||||
import { Property } from '@activepieces/pieces-framework';
|
||||
import { httpClient, HttpMethod } from '@activepieces/pieces-common';
|
||||
import { bookedinAuth } from '../../index';
|
||||
|
||||
export const BASE_URL = 'https://api.bookedin.ai/api/v1';
|
||||
|
||||
export const getBookedinHeaders = (apiKey: string) => {
|
||||
return {
|
||||
'X-API-Key': apiKey,
|
||||
'accept': 'application/json',
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
export const extractApiKey = (auth: unknown): string => {
|
||||
if (typeof auth === 'string') {
|
||||
return auth;
|
||||
}
|
||||
const authObj = auth as { secret_text?: string; auth?: string };
|
||||
return authObj?.secret_text || authObj?.auth || '';
|
||||
};
|
||||
|
||||
|
||||
const fetchLeadOptions = async (apiKey: string) => {
|
||||
const response = await httpClient.sendRequest<{
|
||||
items: Array<{
|
||||
id: string;
|
||||
contact: {
|
||||
name: {
|
||||
first: string;
|
||||
last: string;
|
||||
};
|
||||
email: string;
|
||||
};
|
||||
}>;
|
||||
}>({
|
||||
method: HttpMethod.GET,
|
||||
url: `${BASE_URL}/leads/`,
|
||||
headers: getBookedinHeaders(apiKey),
|
||||
queryParams: {
|
||||
limit: '100',
|
||||
skip: '0',
|
||||
},
|
||||
});
|
||||
|
||||
return response.body.items.map((lead) => {
|
||||
const firstName = lead.contact?.name?.first || '';
|
||||
const lastName = lead.contact?.name?.last || '';
|
||||
const email = lead.contact?.email || '';
|
||||
const name = [firstName, lastName].filter(Boolean).join(' ').trim();
|
||||
const label = name ? `${name} (${email})` : email || lead.id;
|
||||
|
||||
return {
|
||||
label,
|
||||
value: lead.id,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
export const leadIdDropdown = Property.Dropdown({
|
||||
auth: bookedinAuth,
|
||||
displayName: 'Lead',
|
||||
description: 'Select a lead',
|
||||
required: true,
|
||||
refreshers: [],
|
||||
options: async ({ auth }) => {
|
||||
if (!auth) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'Please connect your account first',
|
||||
options: [],
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const apiKey = extractApiKey(auth);
|
||||
if (!apiKey) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'API key is missing',
|
||||
options: [],
|
||||
};
|
||||
}
|
||||
|
||||
const options = await fetchLeadOptions(apiKey);
|
||||
return {
|
||||
disabled: false,
|
||||
options,
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'Failed to load leads. Please check your connection.',
|
||||
options: [],
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
export const leadIdsMultiSelectDropdown = Property.MultiSelectDropdown({
|
||||
auth: bookedinAuth,
|
||||
displayName: 'Leads',
|
||||
description: 'Select leads to delete (max 500)',
|
||||
required: true,
|
||||
refreshers: [],
|
||||
options: async ({ auth }) => {
|
||||
if (!auth) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'Please connect your account first',
|
||||
options: [],
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const apiKey = extractApiKey(auth);
|
||||
if (!apiKey) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'API key is missing',
|
||||
options: [],
|
||||
};
|
||||
}
|
||||
|
||||
const options = await fetchLeadOptions(apiKey);
|
||||
return {
|
||||
disabled: false,
|
||||
options,
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'Failed to load leads. Please check your connection.',
|
||||
options: [],
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"extends": "../../../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"importHelpers": true,
|
||||
"noImplicitOverride": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noPropertyAccessFromIndexSignature": true
|
||||
},
|
||||
"files": [],
|
||||
"include": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.lib.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../../dist/out-tsc",
|
||||
"declaration": true,
|
||||
"types": ["node"]
|
||||
},
|
||||
"include": ["src/**/*.ts"]
|
||||
}
|
||||
Reference in New Issue
Block a user