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,7 @@
|
||||
import { PieceAuth } from "@activepieces/pieces-framework";
|
||||
|
||||
export const circleAuth = PieceAuth.SecretText({
|
||||
displayName: 'API Token',
|
||||
description: `You can obtain your API token by navigating to **Settings->Developers->Tokens**.`,
|
||||
required: true,
|
||||
});
|
||||
@@ -0,0 +1,121 @@
|
||||
import { Property } from '@activepieces/pieces-framework';
|
||||
import { httpClient, HttpMethod } from '@activepieces/pieces-common';
|
||||
import { ListBasicPostsResponse, ListCommunityMembersResponse, ListSpacesResponse } from './types';
|
||||
import { circleAuth } from './auth';
|
||||
|
||||
export const BASE_URL = 'https://app.circle.so/api/admin/v2';
|
||||
|
||||
export const spaceIdDropdown = Property.Dropdown({
|
||||
displayName: 'Space',
|
||||
required: true,
|
||||
refreshers: [],
|
||||
auth: circleAuth,
|
||||
options: async ({ auth }) => {
|
||||
if (!auth) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'Please connect your account first',
|
||||
options: [],
|
||||
};
|
||||
}
|
||||
const response = await httpClient.sendRequest<ListSpacesResponse>({
|
||||
method: HttpMethod.GET,
|
||||
url: `${BASE_URL}/spaces`,
|
||||
headers: {
|
||||
Authorization: `Bearer ${auth.secret_text}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
if (response.status === 200) {
|
||||
return {
|
||||
disabled: false,
|
||||
options: response.body.records.map((space) => ({
|
||||
label: space.name,
|
||||
value: space.id,
|
||||
})),
|
||||
};
|
||||
}
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'Error fetching spaces',
|
||||
options: [],
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export const postIdDropdown = Property.Dropdown({
|
||||
displayName: 'Post',
|
||||
required: true,
|
||||
refreshers: ['space_id'],
|
||||
auth: circleAuth,
|
||||
options: async ({ auth, space_id }) => {
|
||||
if (!auth || !space_id) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: !auth ? 'Please connect your account first' : 'Select a space first',
|
||||
options: [],
|
||||
};
|
||||
}
|
||||
const response = await httpClient.sendRequest<ListBasicPostsResponse>({
|
||||
method: HttpMethod.GET,
|
||||
url: `${BASE_URL}/posts`,
|
||||
headers: {
|
||||
Authorization: `Bearer ${auth.secret_text}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
queryParams: {
|
||||
space_id: (space_id as number).toString(),
|
||||
status: 'all', // Fetch all posts for selection
|
||||
},
|
||||
});
|
||||
if (response.status === 200) {
|
||||
return {
|
||||
disabled: false,
|
||||
options: response.body.records.map((post) => ({
|
||||
label: post.name,
|
||||
value: post.id,
|
||||
})),
|
||||
};
|
||||
}
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'Error fetching posts or no posts found in space.',
|
||||
options: [],
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export const communityMemberIdDropdown = Property.Dropdown({
|
||||
displayName: 'Community Member',
|
||||
required: true,
|
||||
refreshers: [],
|
||||
auth: circleAuth,
|
||||
options: async ({ auth }) => {
|
||||
if (!auth) {
|
||||
return { disabled: true, placeholder: 'Please authenticate first', options: [] };
|
||||
}
|
||||
const response = await httpClient.sendRequest<ListCommunityMembersResponse>({
|
||||
method: HttpMethod.GET,
|
||||
url: `${BASE_URL}/community_members`,
|
||||
headers: {
|
||||
Authorization: `Bearer ${auth.secret_text}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
queryParams: { status: 'all' },
|
||||
});
|
||||
if (response.status === 200 && response.body.records) {
|
||||
return {
|
||||
disabled: false,
|
||||
options: response.body.records.map((member) => ({
|
||||
label: `${member.name} (${member.email})`,
|
||||
value: member.id,
|
||||
})),
|
||||
};
|
||||
}
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'Error fetching community members or no members found',
|
||||
options: [],
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,269 @@
|
||||
export interface Space {
|
||||
id: number;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface ListSpacesResponse {
|
||||
records: Space[];
|
||||
page?: number;
|
||||
per_page?: number;
|
||||
has_next_page?: boolean;
|
||||
count?: number;
|
||||
page_count?: number;
|
||||
}
|
||||
|
||||
// Interface for individual post item based on 'List Basic Posts' records
|
||||
export interface BasicPostFromList {
|
||||
id: number;
|
||||
status: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
comments_count: number;
|
||||
hide_meta_info: boolean;
|
||||
published_at: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
is_comments_enabled: boolean;
|
||||
is_liking_enabled: boolean;
|
||||
flagged_for_approval_at: string | null;
|
||||
body: {
|
||||
id: number;
|
||||
name: string; // e.g., "body"
|
||||
body: string; // HTML content snippet
|
||||
record_type: string; // "Post"
|
||||
record_id: number;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
};
|
||||
url: string;
|
||||
space_name: string;
|
||||
space_slug: string;
|
||||
space_id: number;
|
||||
user_id: number;
|
||||
user_email: string;
|
||||
user_name: string;
|
||||
community_id: number;
|
||||
user_avatar_url: string | null;
|
||||
cover_image_url: string | null;
|
||||
cover_image: string | null;
|
||||
cardview_thumbnail_url: string | null;
|
||||
cardview_thumbnail: string | null;
|
||||
is_comments_closed: boolean;
|
||||
custom_html: string | null;
|
||||
likes_count: number;
|
||||
member_posts_count: number;
|
||||
member_comments_count: number;
|
||||
member_likes_count: number;
|
||||
topics: number[];
|
||||
}
|
||||
|
||||
// Interface based on the 'List Basic Posts' API response
|
||||
export interface ListBasicPostsResponse {
|
||||
page: number;
|
||||
per_page: number;
|
||||
has_next_page: boolean;
|
||||
count: number;
|
||||
page_count: number;
|
||||
records: BasicPostFromList[];
|
||||
}
|
||||
|
||||
// --- Shared Member Profile Sub-Interfaces ---
|
||||
export interface ProfileFieldChoice {
|
||||
id: number;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface CommunityMemberProfileFieldChoice {
|
||||
id: number;
|
||||
profile_field_choice: ProfileFieldChoice;
|
||||
}
|
||||
|
||||
export interface CommunityMemberProfileFieldDetails {
|
||||
id: number;
|
||||
text: string | null;
|
||||
textarea: string | null;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
display_value: string[] | null;
|
||||
community_member_choices: CommunityMemberProfileFieldChoice[];
|
||||
}
|
||||
|
||||
export interface ProfileFieldPage {
|
||||
id: number;
|
||||
name: string;
|
||||
position: number;
|
||||
visible: boolean;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
export interface ProfileField {
|
||||
id: number;
|
||||
label: string;
|
||||
field_type: string;
|
||||
key: string;
|
||||
placeholder: string | null;
|
||||
description: string | null;
|
||||
required: boolean;
|
||||
platform_field: boolean;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
community_member_profile_field: CommunityMemberProfileFieldDetails | null;
|
||||
number_options: any | null;
|
||||
choices: ProfileFieldChoice[];
|
||||
pages: ProfileFieldPage[];
|
||||
}
|
||||
|
||||
export interface MemberTag {
|
||||
name: string;
|
||||
id: number;
|
||||
}
|
||||
|
||||
export interface GamificationStats {
|
||||
community_member_id: number;
|
||||
total_points: number;
|
||||
current_level: number;
|
||||
current_level_name: string;
|
||||
points_to_next_level: number;
|
||||
level_progress: number;
|
||||
}
|
||||
|
||||
export interface CommunityMemberListItem {
|
||||
id: number;
|
||||
name: string; // Full name
|
||||
email: string;
|
||||
first_name: string | null;
|
||||
last_name: string | null;
|
||||
headline: string | null;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
community_id: number;
|
||||
last_seen_at: string | null;
|
||||
profile_confirmed_at: string | null;
|
||||
profile_url: string;
|
||||
public_uid: string;
|
||||
avatar_url: string | null;
|
||||
user_id: number; // This is the user_id associated with the community_member, not the community_member.id
|
||||
active: boolean;
|
||||
sso_provider_user_id: string | null;
|
||||
accepted_invitation: string | null;
|
||||
profile_fields: ProfileField[];
|
||||
flattened_profile_fields: Record<string, string[] | null>;
|
||||
member_tags: MemberTag[];
|
||||
posts_count: number;
|
||||
comments_count: number;
|
||||
gamification_stats: GamificationStats;
|
||||
}
|
||||
export interface ListCommunityMembersResponse {
|
||||
page: number;
|
||||
per_page: number;
|
||||
has_next_page: boolean;
|
||||
count: number;
|
||||
page_count: number;
|
||||
records: CommunityMemberListItem[];
|
||||
}
|
||||
|
||||
export interface CommunityMemberDetails {
|
||||
id: number;
|
||||
first_name: string | null;
|
||||
last_name: string | null;
|
||||
headline: string | null;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
community_id: number;
|
||||
last_seen_at: string | null;
|
||||
profile_confirmed_at: string | null;
|
||||
profile_url: string;
|
||||
public_uid: string;
|
||||
profile_fields: ProfileField[];
|
||||
flattened_profile_fields: Record<string, string[] | null>;
|
||||
avatar_url: string | null;
|
||||
user_id: number;
|
||||
name: string;
|
||||
email: string;
|
||||
accepted_invitation: string | null;
|
||||
active: boolean;
|
||||
sso_provider_user_id: string | null;
|
||||
member_tags: MemberTag[];
|
||||
posts_count: number;
|
||||
comments_count: number;
|
||||
gamification_stats: GamificationStats;
|
||||
}
|
||||
|
||||
|
||||
interface PostBody {
|
||||
id: number;
|
||||
name: string; // "body"
|
||||
body: string; // HTML content
|
||||
record_type: string; // "Post"
|
||||
record_id: number;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
interface TipTapMark {
|
||||
type: string;
|
||||
attrs?: Record<string, unknown>; // Example: { href: 'url' } for a link mark
|
||||
}
|
||||
|
||||
interface TipTapContentItem {
|
||||
type: string;
|
||||
text?: string;
|
||||
marks?: TipTapMark[];
|
||||
attrs?: Record<string, unknown>;
|
||||
content?: TipTapContentItem[];
|
||||
circle_ios_fallback_text?: string;
|
||||
}
|
||||
|
||||
interface TipTapBody {
|
||||
body: {
|
||||
type: string; // "doc"
|
||||
content: TipTapContentItem[];
|
||||
};
|
||||
circle_ios_fallback_text?: string;
|
||||
attachments?: unknown[];
|
||||
inline_attachments?: unknown[];
|
||||
sgids_to_object_map?: Record<string, unknown>;
|
||||
format?: string; // "post"
|
||||
community_members?: unknown[];
|
||||
entities?: unknown[];
|
||||
group_mentions?: unknown[];
|
||||
polls?: unknown[];
|
||||
}
|
||||
|
||||
export interface PostDetails {
|
||||
id: number;
|
||||
status: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
comments_count: number;
|
||||
hide_meta_info: boolean;
|
||||
published_at: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
is_comments_enabled: boolean;
|
||||
is_liking_enabled: boolean;
|
||||
flagged_for_approval_at: string | null;
|
||||
body: PostBody;
|
||||
tiptap_body: TipTapBody;
|
||||
url: string;
|
||||
space_name: string;
|
||||
space_slug: string;
|
||||
space_id: number;
|
||||
user_id: number;
|
||||
user_email: string;
|
||||
user_name: string;
|
||||
community_id: number;
|
||||
user_avatar_url: string | null;
|
||||
cover_image_url: string | null;
|
||||
cover_image: string | null; // This seems to be an identifier string
|
||||
cardview_thumbnail_url: string | null;
|
||||
cardview_thumbnail: string | null; // Also an identifier
|
||||
is_comments_closed: boolean;
|
||||
custom_html: string | null;
|
||||
likes_count: number;
|
||||
member_posts_count: number;
|
||||
member_comments_count: number;
|
||||
member_likes_count: number;
|
||||
topics: number[];
|
||||
}
|
||||
Reference in New Issue
Block a user