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,18 @@
|
||||
import { createPiece } from '@activepieces/pieces-framework';
|
||||
import { PieceCategory } from '@activepieces/shared';
|
||||
import { logrocketAuth } from './lib/common/auth';
|
||||
import { requestHighlights } from './lib/actions/request-highlights';
|
||||
import { identifyUser } from './lib/actions/identify-user';
|
||||
import { highlightsReady } from './lib/triggers/highlights-ready';
|
||||
|
||||
export const logrocket = createPiece({
|
||||
displayName: 'LogRocket',
|
||||
description: 'Get AI-generated summaries of user sessions to understand customer behavior and troubleshoot issues faster.',
|
||||
auth: logrocketAuth,
|
||||
minimumSupportedRelease: '0.36.1',
|
||||
logoUrl: 'https://cdn.activepieces.com/pieces/logrocket.png',
|
||||
categories: [PieceCategory.DEVELOPER_TOOLS],
|
||||
authors: ["onyedikachi-david"],
|
||||
actions: [requestHighlights, identifyUser],
|
||||
triggers: [highlightsReady],
|
||||
});
|
||||
@@ -0,0 +1,94 @@
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { logrocketAuth } from '../common/auth';
|
||||
import { httpClient, HttpMethod } from '@activepieces/pieces-common';
|
||||
|
||||
export const identifyUser = createAction({
|
||||
auth: logrocketAuth,
|
||||
name: 'identifyUser',
|
||||
displayName: 'Identify User',
|
||||
description: 'Create or update user information and traits in LogRocket to contextualize user behavior.',
|
||||
props: {
|
||||
orgId: Property.ShortText({
|
||||
displayName: 'Organization ID',
|
||||
description: 'Your LogRocket organization ID (found in Settings > General Settings, or in your App ID before the slash)',
|
||||
required: true,
|
||||
}),
|
||||
appId: Property.ShortText({
|
||||
displayName: 'App ID',
|
||||
description: 'Your LogRocket app/project ID (found in Settings > General Settings, or in your App ID after the slash)',
|
||||
required: true,
|
||||
}),
|
||||
userId: Property.ShortText({
|
||||
displayName: 'User ID',
|
||||
description: 'The unique identifier for the user',
|
||||
required: true,
|
||||
}),
|
||||
name: Property.ShortText({
|
||||
displayName: 'Name',
|
||||
description: 'The user\'s name (max 1024 characters)',
|
||||
required: false,
|
||||
}),
|
||||
email: Property.ShortText({
|
||||
displayName: 'Email',
|
||||
description: 'The user\'s email address (max 1024 characters)',
|
||||
required: false,
|
||||
}),
|
||||
timestamp: Property.DateTime({
|
||||
displayName: 'Timestamp',
|
||||
description: 'Unix timestamp in milliseconds indicating when this data was collected (optional)',
|
||||
required: false,
|
||||
}),
|
||||
traits: Property.Object({
|
||||
displayName: 'Traits',
|
||||
description: 'User traits as key-value pairs (e.g., {"plan": "free", "age": 43}). Values will be converted to strings.',
|
||||
required: false,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const { orgId, appId, userId, name, email, timestamp, traits } = context.propsValue;
|
||||
const apiKey = context.auth;
|
||||
|
||||
const body: Record<string, unknown> = {};
|
||||
|
||||
if (name) {
|
||||
body['name'] = name;
|
||||
}
|
||||
|
||||
if (email) {
|
||||
body['email'] = email;
|
||||
}
|
||||
|
||||
if (timestamp) {
|
||||
body['timestamp'] = new Date(timestamp).getTime();
|
||||
}
|
||||
|
||||
if (traits) {
|
||||
body['traits'] = traits;
|
||||
}
|
||||
|
||||
if (Object.keys(body).length === 0) {
|
||||
throw new Error('At least one of name, email, timestamp, or traits must be provided');
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await httpClient.sendRequest({
|
||||
method: HttpMethod.PUT,
|
||||
url: `https://api.logrocket.com/v1/orgs/${orgId}/apps/${appId}/users/${userId}`,
|
||||
headers: {
|
||||
Authorization: `token ${apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body,
|
||||
});
|
||||
|
||||
return response.body;
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
`Failed to identify user: ${
|
||||
error instanceof Error ? error.message : 'Unknown error'
|
||||
}`
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { logrocketAuth } from '../common/auth';
|
||||
import { httpClient, HttpMethod } from '@activepieces/pieces-common';
|
||||
|
||||
export const requestHighlights = createAction({
|
||||
auth: logrocketAuth,
|
||||
name: 'requestHighlights',
|
||||
displayName: 'Request Highlights',
|
||||
description: 'Request session highlights for a user. Results will be sent to the webhook URL when ready.',
|
||||
props: {
|
||||
orgId: Property.ShortText({
|
||||
displayName: 'Organization ID',
|
||||
description: 'Your LogRocket organization ID (found in Settings > General Settings, or in your App ID before the slash)',
|
||||
required: true,
|
||||
}),
|
||||
projectId: Property.ShortText({
|
||||
displayName: 'Project ID',
|
||||
description: 'Your LogRocket project ID (found in Settings > General Settings, or in your App ID after the slash)',
|
||||
required: true,
|
||||
}),
|
||||
userEmail: Property.ShortText({
|
||||
displayName: 'User Email',
|
||||
description: 'The email of the user to get highlights for',
|
||||
required: false,
|
||||
}),
|
||||
userId: Property.ShortText({
|
||||
displayName: 'User ID',
|
||||
description: 'The ID of the user from LogRocket.identify() calls',
|
||||
required: false,
|
||||
}),
|
||||
timeRangeStart: Property.DateTime({
|
||||
displayName: 'Start Time',
|
||||
description: 'Start of the time range for sessions (optional)',
|
||||
required: false,
|
||||
}),
|
||||
timeRangeEnd: Property.DateTime({
|
||||
displayName: 'End Time',
|
||||
description: 'End of the time range for sessions (optional)',
|
||||
required: false,
|
||||
}),
|
||||
webhookUrl: Property.ShortText({
|
||||
displayName: 'Webhook URL',
|
||||
description: 'URL where highlights results will be posted when ready. You can get this from the "Highlights Ready" trigger.',
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const { orgId, projectId, userEmail, userId, timeRangeStart, timeRangeEnd, webhookUrl } = context.propsValue;
|
||||
const apiKey = context.auth;
|
||||
|
||||
if (!userEmail && !userId) {
|
||||
throw new Error('Either userEmail or userId must be provided');
|
||||
}
|
||||
|
||||
const body: Record<string, unknown> = {
|
||||
webhookURL: webhookUrl,
|
||||
};
|
||||
|
||||
if (userEmail) {
|
||||
body['userEmail'] = userEmail;
|
||||
}
|
||||
|
||||
if (userId) {
|
||||
body['userID'] = userId;
|
||||
}
|
||||
|
||||
if (timeRangeStart && timeRangeEnd) {
|
||||
const startMs = new Date(timeRangeStart).getTime();
|
||||
const endMs = new Date(timeRangeEnd).getTime();
|
||||
|
||||
if (startMs >= endMs) {
|
||||
throw new Error('Start time must be before end time');
|
||||
}
|
||||
|
||||
body['timeRange'] = {
|
||||
startMs,
|
||||
endMs,
|
||||
};
|
||||
} else if (timeRangeStart || timeRangeEnd) {
|
||||
throw new Error('Both start time and end time must be provided if using time range');
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await httpClient.sendRequest({
|
||||
method: HttpMethod.POST,
|
||||
url: `https://api.logrocket.com/v1/orgs/${orgId}/apps/${projectId}/highlights/`,
|
||||
headers: {
|
||||
Authorization: `token ${apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body,
|
||||
});
|
||||
|
||||
return response.body;
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
`Failed to request highlights: ${
|
||||
error instanceof Error ? error.message : 'Unknown error'
|
||||
}`
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import { PieceAuth } from '@activepieces/pieces-framework';
|
||||
|
||||
export const logrocketAuth = PieceAuth.SecretText({
|
||||
displayName: 'API Key',
|
||||
description: `
|
||||
To get your LogRocket API key:
|
||||
|
||||
1. **Login to your LogRocket Dashboard**
|
||||
2. **Go to Settings > General Settings**
|
||||
3. **Copy your API key** from the API Key section
|
||||
4. **Paste it here**
|
||||
|
||||
Your API key is used to authenticate requests to the LogRocket API.
|
||||
`,
|
||||
required: true,
|
||||
});
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
import {
|
||||
createTrigger,
|
||||
Property,
|
||||
TriggerStrategy,
|
||||
} from '@activepieces/pieces-framework';
|
||||
import { logrocketAuth } from '../common/auth';
|
||||
|
||||
export const highlightsReady = createTrigger({
|
||||
auth: logrocketAuth,
|
||||
name: 'highlightsReady',
|
||||
displayName: 'Highlights Ready',
|
||||
description: 'Trigger when session highlights are ready. Use this webhook URL when requesting highlights.',
|
||||
props: {
|
||||
markdown: Property.MarkDown({
|
||||
value: `
|
||||
## Webhook Configuration
|
||||
|
||||
This trigger receives highlights results from LogRocket when they're ready.
|
||||
|
||||
**To use this trigger:**
|
||||
|
||||
1. Copy the webhook URL below
|
||||
2. Use it as the **Webhook URL** field when using the "Request Highlights" action
|
||||
3. When highlights are ready, this trigger will fire with the results
|
||||
|
||||
**Webhook URL:**
|
||||
\`\`\`text
|
||||
{{webhookUrl}}
|
||||
\`\`\`
|
||||
`,
|
||||
}),
|
||||
},
|
||||
sampleData: {
|
||||
result: {
|
||||
highlights: 'The user [checks out their cart](https://app.logrocket.com/orgID/appID/s/5-14de95d6-d5b8-1a62-0a3a-4858caf874b0/0?t=1715564734801) and [encounters an error loading settings](https://app.logrocket.com/orgID/appID/s/5-3cde95d6-a5b8-4a62-9b3a-6aa834f8747c/0?t=1715564554783).',
|
||||
sessions: [
|
||||
{
|
||||
recordingID: '5-3cde95d6-a5b8-4a62-9b3a-6aa834f8747c',
|
||||
sessionID: 0,
|
||||
highlights: 'The user [encounters an error loading settings](https://app.logrocket.com/orgID/appID/s/5-3cde95d6-a5b8-4a62-9b3a-6aa834f8747c/0?t=1715564554783) and [the issue persists](https://app.logrocket.com/orgID/appID/s/5-3cde95d6-a5b8-4a62-9b3a-6aa834f8747c/0?t=1715564734801).',
|
||||
},
|
||||
{
|
||||
recordingID: '5-14de95d6-d5b8-1a62-0a3a-4858caf874b0',
|
||||
sessionID: 0,
|
||||
highlights: 'The user [adds an item to their cart](https://app.logrocket.com/orgID/appID/s/5-14de95d6-d5b8-1a62-0a3a-4858caf874b0/0?t=1715564554783) and [proceeds to checkout](https://app.logrocket.com/orgID/appID/s/5-14de95d6-d5b8-1a62-0a3a-4858caf874b0/0?t=1715564734801)',
|
||||
},
|
||||
],
|
||||
},
|
||||
status: 'READY',
|
||||
appID: 'orgID/appID',
|
||||
requestID: '0cc12cad4b5b8b93760edf7fb5731ac66fbc8a766f9431df6c1e72b214ed6a65',
|
||||
},
|
||||
type: TriggerStrategy.WEBHOOK,
|
||||
async onEnable(context) {
|
||||
// No need to register webhook - LogRocket will POST to this URL when highlights are ready
|
||||
},
|
||||
async onDisable(context) {
|
||||
// No need to unregister webhook
|
||||
},
|
||||
async run(context) {
|
||||
return [context.payload.body];
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user