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,82 @@
|
||||
import { confluenceAuth } from "../../index";
|
||||
import { createAction, Property } from "@activepieces/pieces-framework";
|
||||
import { folderIdProp, spaceIdProp, templateIdProp, templateVariablesProp } from "../common/props";
|
||||
import { confluenceApiCall } from "../common";
|
||||
import { HttpMethod } from "@activepieces/pieces-common";
|
||||
|
||||
export const createPageFromTemplateAction = createAction({
|
||||
auth:confluenceAuth,
|
||||
name:'create-page-from-template',
|
||||
displayName:'Create Page from Template',
|
||||
description:'Creates a new page from a template with the given title and variables.',
|
||||
props:{
|
||||
spaceId:spaceIdProp,
|
||||
templateId:templateIdProp,
|
||||
folderId:folderIdProp,
|
||||
title:Property.ShortText({
|
||||
displayName:'Title',
|
||||
required:true,
|
||||
}),
|
||||
status:Property.StaticDropdown({
|
||||
displayName:'Status',
|
||||
required:true,
|
||||
defaultValue:'draft',
|
||||
options:{
|
||||
disabled:false,
|
||||
options:[
|
||||
{
|
||||
label:'Published ',
|
||||
value:'current'
|
||||
},
|
||||
{
|
||||
label:'Draft',
|
||||
value:'draft'
|
||||
}
|
||||
]
|
||||
}
|
||||
}),
|
||||
templateVariables:templateVariablesProp,
|
||||
},
|
||||
async run(context){
|
||||
const {spaceId,templateId,title,status,folderId} = context.propsValue;
|
||||
const variables = context.propsValue.templateVariables ??{};
|
||||
|
||||
const template = await confluenceApiCall<{ body: { storage: { value: string } } }>({
|
||||
domain: context.auth.props.confluenceDomain,
|
||||
username: context.auth.props.username,
|
||||
password: context.auth.props.password,
|
||||
method: HttpMethod.GET,
|
||||
version: 'v1',
|
||||
resourceUri: `/template/${templateId}`,
|
||||
});
|
||||
|
||||
const body = template.body.storage.value;
|
||||
|
||||
let content = body.replace(/<at:declarations>[\s\S]*?<\/at:declarations>/, "").trim();
|
||||
Object.entries(variables).forEach(([key, value]) => {
|
||||
const varRegex = new RegExp(`<at:var at:name=(['"])${key}\\1\\s*\\/?>`, "g");
|
||||
content = content.replace(varRegex, value);
|
||||
});
|
||||
|
||||
const response = await confluenceApiCall({
|
||||
domain: context.auth.props.confluenceDomain,
|
||||
username: context.auth.props.username,
|
||||
password: context.auth.props.password,
|
||||
method: HttpMethod.POST,
|
||||
version: 'v2',
|
||||
resourceUri: '/pages',
|
||||
body: {
|
||||
spaceId:spaceId,
|
||||
title,
|
||||
parentId:folderId,
|
||||
status,
|
||||
body:{
|
||||
representation:'storage',
|
||||
value:content,
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return response;
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,149 @@
|
||||
import {
|
||||
createAction,
|
||||
Property,
|
||||
DynamicPropsValue,
|
||||
PiecePropValueSchema,
|
||||
AppConnectionValueForAuthProperty,
|
||||
} from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { confluenceAuth } from '../..';
|
||||
import { confluenceApiCall } from '../common';
|
||||
|
||||
interface ConfluencePage {
|
||||
id: string;
|
||||
title: string;
|
||||
body: any;
|
||||
children?: ConfluencePage[];
|
||||
}
|
||||
|
||||
async function getPageWithContent(
|
||||
auth: AppConnectionValueForAuthProperty<typeof confluenceAuth>,
|
||||
pageId: string,
|
||||
): Promise<ConfluencePage> {
|
||||
try {
|
||||
const response = await confluenceApiCall<ConfluencePage>({
|
||||
domain: auth.props.confluenceDomain,
|
||||
username: auth.props.username,
|
||||
password: auth.props.password,
|
||||
method: HttpMethod.GET,
|
||||
version: 'v2',
|
||||
resourceUri: `/pages/${pageId}`,
|
||||
query: {
|
||||
'body-format': 'storage',
|
||||
},
|
||||
});
|
||||
return response;
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
`Failed to fetch page ${pageId}: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async function getChildPages(
|
||||
auth: AppConnectionValueForAuthProperty<typeof confluenceAuth>,
|
||||
parentId: string,
|
||||
currentDepth: number,
|
||||
maxDepth: number,
|
||||
): Promise<ConfluencePage[]> {
|
||||
if (currentDepth >= maxDepth) {
|
||||
return [];
|
||||
}
|
||||
|
||||
try {
|
||||
const childrenResponse = await confluenceApiCall<{ results: ConfluencePage[] }>({
|
||||
domain: auth.props.confluenceDomain,
|
||||
username: auth.props.username,
|
||||
password: auth.props.password,
|
||||
method: HttpMethod.GET,
|
||||
version: 'v2',
|
||||
resourceUri: `/pages/${parentId}/children`,
|
||||
});
|
||||
|
||||
const childPages = await Promise.all(
|
||||
childrenResponse.results.map(async (childPage) => {
|
||||
const pageWithContent = await getPageWithContent(auth, childPage.id);
|
||||
const children = await getChildPages(auth, childPage.id, currentDepth + 1, maxDepth);
|
||||
return {
|
||||
...pageWithContent,
|
||||
children,
|
||||
};
|
||||
}),
|
||||
);
|
||||
|
||||
return childPages;
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
`Failed to fetch children for page ${parentId}: ${
|
||||
error instanceof Error ? error.message : 'Unknown error'
|
||||
}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export const getPageContent = createAction({
|
||||
name: 'getPageContent',
|
||||
displayName: 'Get Page Content',
|
||||
description: 'Get page content and optionally all its descendants',
|
||||
auth: confluenceAuth,
|
||||
props: {
|
||||
pageId: Property.ShortText({
|
||||
displayName: 'Page ID',
|
||||
description: 'Get this from the page URL of your Confluence Cloud',
|
||||
required: true,
|
||||
}),
|
||||
includeDescendants: Property.Checkbox({
|
||||
displayName: 'Include Descendants ?',
|
||||
description: 'If checked, will fetch all child pages recursively.',
|
||||
required: false,
|
||||
defaultValue: false,
|
||||
}),
|
||||
dynamic: Property.DynamicProperties({
|
||||
auth: confluenceAuth,
|
||||
displayName: 'Dynamic Properties',
|
||||
refreshers: ['includeDescendants'],
|
||||
required: true,
|
||||
props: async ({ includeDescendants }) => {
|
||||
if (!includeDescendants) {
|
||||
return {};
|
||||
}
|
||||
const fields: DynamicPropsValue = {
|
||||
maxDepth: Property.Number({
|
||||
displayName: 'Maximum Depth',
|
||||
description: 'Maximum depth of child pages to fetch.',
|
||||
required: true,
|
||||
defaultValue: 5,
|
||||
}),
|
||||
};
|
||||
return fields;
|
||||
},
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
try {
|
||||
const page = await getPageWithContent(context.auth, context.propsValue.pageId);
|
||||
|
||||
if (!context.propsValue.includeDescendants) {
|
||||
return page;
|
||||
}
|
||||
|
||||
const children = await getChildPages(
|
||||
context.auth,
|
||||
context.propsValue.pageId,
|
||||
1,
|
||||
context.propsValue.dynamic['maxDepth'],
|
||||
);
|
||||
|
||||
return {
|
||||
...page,
|
||||
children,
|
||||
};
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
`Failed to fetch page ${context.propsValue.pageId}: ${
|
||||
error instanceof Error ? error.message : 'Unknown error'
|
||||
}`,
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,118 @@
|
||||
import {
|
||||
AuthenticationType,
|
||||
httpClient,
|
||||
HttpMessageBody,
|
||||
HttpMethod,
|
||||
HttpRequest,
|
||||
QueryParams,
|
||||
} from '@activepieces/pieces-common';
|
||||
import { isNil } from '@activepieces/shared';
|
||||
|
||||
export type ConfluenceApiCallParams = {
|
||||
domain: string;
|
||||
username: string;
|
||||
password: string;
|
||||
version: 'v1' | 'v2';
|
||||
method: HttpMethod;
|
||||
resourceUri: string;
|
||||
query?: QueryParams;
|
||||
body?: any;
|
||||
};
|
||||
|
||||
export type PaginatedResponse<T> = {
|
||||
results: T[];
|
||||
_links?: {
|
||||
next?: string;
|
||||
};
|
||||
};
|
||||
|
||||
export async function confluenceApiCall<T extends HttpMessageBody>({
|
||||
domain,
|
||||
username,
|
||||
password,
|
||||
method,
|
||||
version,
|
||||
resourceUri,
|
||||
query,
|
||||
body,
|
||||
}: ConfluenceApiCallParams): Promise<T> {
|
||||
const baseUrl = version === 'v2' ? `${domain}/wiki/api/v2` : `${domain}/wiki/rest/api`;
|
||||
|
||||
const request: HttpRequest = {
|
||||
method,
|
||||
url: baseUrl + resourceUri,
|
||||
authentication: {
|
||||
type: AuthenticationType.BASIC,
|
||||
username,
|
||||
password,
|
||||
},
|
||||
queryParams: query,
|
||||
body: body,
|
||||
};
|
||||
|
||||
const response = await httpClient.sendRequest<T>(request);
|
||||
return response.body;
|
||||
}
|
||||
|
||||
export async function confluencePaginatedApiCall<T extends HttpMessageBody>({
|
||||
domain,
|
||||
username,
|
||||
password,
|
||||
method,
|
||||
version,
|
||||
resourceUri,
|
||||
query,
|
||||
body,
|
||||
}: ConfluenceApiCallParams): Promise<T[]> {
|
||||
const qs = query ? query : {};
|
||||
const resultData: T[] = [];
|
||||
|
||||
if (version === 'v2') {
|
||||
let nextUrl = `${domain}/wiki/api/v2${resourceUri}?limit=200`;
|
||||
|
||||
do {
|
||||
const response = await httpClient.sendRequest<PaginatedResponse<T>>({
|
||||
method,
|
||||
url: nextUrl,
|
||||
authentication: {
|
||||
type: AuthenticationType.BASIC,
|
||||
username,
|
||||
password,
|
||||
},
|
||||
queryParams: qs,
|
||||
body,
|
||||
});
|
||||
|
||||
if (isNil(response.body.results)) {
|
||||
break;
|
||||
}
|
||||
resultData.push(...response.body.results);
|
||||
nextUrl = response.body?._links?.next ? `${domain}${response.body._links.next}` : '';
|
||||
} while (nextUrl);
|
||||
} else {
|
||||
let start = 0;
|
||||
let hasMoreData = true;
|
||||
|
||||
do {
|
||||
const response = await httpClient.sendRequest<{ results: T[] }>({
|
||||
method,
|
||||
url: `${domain}/wiki/rest/api${resourceUri}?start=${start}&limit=100`,
|
||||
authentication: {
|
||||
type: AuthenticationType.BASIC,
|
||||
username,
|
||||
password,
|
||||
},
|
||||
queryParams: qs,
|
||||
body,
|
||||
});
|
||||
if (isNil(response.body.results) || response.body.results.length === 0) {
|
||||
hasMoreData = false;
|
||||
} else {
|
||||
resultData.push(...response.body.results);
|
||||
start += 100;
|
||||
}
|
||||
} while (hasMoreData);
|
||||
}
|
||||
|
||||
return resultData;
|
||||
}
|
||||
@@ -0,0 +1,251 @@
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { confluenceApiCall, confluencePaginatedApiCall } from '.';
|
||||
import { confluenceAuth } from '../../index';
|
||||
import {
|
||||
DropdownOption,
|
||||
DynamicPropsValue,
|
||||
PiecePropValueSchema,
|
||||
Property,
|
||||
} from '@activepieces/pieces-framework';
|
||||
import { parseStringPromise } from 'xml2js';
|
||||
|
||||
export const spaceIdProp = Property.Dropdown({
|
||||
auth: confluenceAuth,
|
||||
displayName: 'Space',
|
||||
refreshers: [],
|
||||
required: true,
|
||||
options: async ({ auth }) => {
|
||||
if (!auth) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder: 'Please connect your account first.',
|
||||
};
|
||||
}
|
||||
|
||||
const spaces = await confluencePaginatedApiCall<{ id: string; name: string }>({
|
||||
domain: auth.props.confluenceDomain,
|
||||
username: auth.props.username,
|
||||
password: auth.props.password,
|
||||
version: 'v2',
|
||||
method: HttpMethod.GET,
|
||||
resourceUri: '/spaces',
|
||||
});
|
||||
|
||||
const options: DropdownOption<string>[] = [];
|
||||
for (const space of spaces) {
|
||||
options.push({
|
||||
label: space.name,
|
||||
value: space.id,
|
||||
});
|
||||
}
|
||||
return {
|
||||
disabled: false,
|
||||
options,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export const templateIdProp = Property.Dropdown({
|
||||
displayName: 'Template',
|
||||
auth: confluenceAuth,
|
||||
refreshers: ['spaceId'],
|
||||
required: true,
|
||||
options: async ({ auth, spaceId }) => {
|
||||
if (!auth || !spaceId) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder: 'Please connect your account first and select a space.',
|
||||
};
|
||||
}
|
||||
|
||||
const space = await confluenceApiCall<{ id: string; name: string; key: string }>({
|
||||
domain: auth.props.confluenceDomain,
|
||||
username: auth.props.username,
|
||||
password: auth.props.password,
|
||||
method: HttpMethod.GET,
|
||||
version: 'v2',
|
||||
resourceUri: `/spaces/${spaceId}`,
|
||||
});
|
||||
|
||||
const templates = await confluencePaginatedApiCall<{ templateId: string; name: string }>({
|
||||
domain: auth.props.confluenceDomain,
|
||||
username: auth.props.username,
|
||||
password: auth.props.password,
|
||||
version: 'v1',
|
||||
method: HttpMethod.GET,
|
||||
resourceUri: `/template/page`,
|
||||
query: { spaceKey: space.key },
|
||||
});
|
||||
|
||||
const options: DropdownOption<string>[] = [];
|
||||
for (const template of templates) {
|
||||
options.push({
|
||||
label: template.name,
|
||||
value: template.templateId,
|
||||
});
|
||||
}
|
||||
return {
|
||||
disabled: false,
|
||||
options,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export const folderIdProp = Property.Dropdown({
|
||||
displayName:'Parent Folder',
|
||||
auth: confluenceAuth,
|
||||
refreshers:['spaceId'],
|
||||
required:false,
|
||||
options:async ({auth,spaceId})=>{
|
||||
if (!auth || !spaceId) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder: 'Please connect your account first and select a space.',
|
||||
};
|
||||
}
|
||||
|
||||
const space = await confluenceApiCall<{ id: string; name: string; key: string,homepageId:string }>({
|
||||
domain: auth.props.confluenceDomain,
|
||||
username: auth.props.username,
|
||||
password: auth.props.password,
|
||||
method: HttpMethod.GET,
|
||||
version: 'v2',
|
||||
resourceUri: `/spaces/${spaceId}`,
|
||||
});
|
||||
|
||||
const folders = await confluencePaginatedApiCall<{id:string,title:string}>({
|
||||
domain:auth.props.confluenceDomain,
|
||||
username:auth.props.username,
|
||||
password:auth.props.password,
|
||||
version:'v1',
|
||||
method:HttpMethod.GET,
|
||||
resourceUri:`/content/${space.homepageId}/descendant/folder`,
|
||||
})
|
||||
|
||||
const options:DropdownOption<string>[] = [];
|
||||
for(const folder of folders){
|
||||
options.push({
|
||||
label:folder.title,
|
||||
value:folder.id
|
||||
})
|
||||
}
|
||||
return{
|
||||
disabled:false,
|
||||
options
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
export const templateVariablesProp = Property.DynamicProperties({
|
||||
displayName: 'Template Variables',
|
||||
auth: confluenceAuth,
|
||||
refreshers: ['templateId'],
|
||||
required: true,
|
||||
props: async ({ auth, templateId }) => {
|
||||
if (!auth) return {};
|
||||
if (!templateId) return {};
|
||||
|
||||
const props: DynamicPropsValue = {};
|
||||
|
||||
const response = await confluenceApiCall<{ body: { storage: { value: string } } }>({
|
||||
domain: auth.props.confluenceDomain,
|
||||
username: auth.props.username,
|
||||
password: auth.props.password,
|
||||
method: HttpMethod.GET,
|
||||
version: 'v1',
|
||||
resourceUri: `/template/${templateId}`,
|
||||
});
|
||||
|
||||
const parsedXml = await parseStringPromise(response.body.storage.value, {
|
||||
explicitArray: false,
|
||||
});
|
||||
const declarations = parsedXml['at:declarations'];
|
||||
|
||||
if (!declarations) return {};
|
||||
|
||||
const variables: Array<{ name: string; type: string; options?: string[] }> = [];
|
||||
|
||||
Object.entries(declarations).forEach(([key, value]: [string, any]) => {
|
||||
const type = key.replace('at:', '');
|
||||
if (Array.isArray(value)) {
|
||||
value.forEach((item) => {
|
||||
if (item['$']) {
|
||||
const varName = item['$']['at:name'];
|
||||
let options: string[] | undefined;
|
||||
|
||||
if (type === 'list' && item['at:option']) {
|
||||
options = item['at:option'].map((opt: any) => opt['$']['at:value']);
|
||||
}
|
||||
|
||||
if (varName && type) {
|
||||
variables.push({
|
||||
name: varName,
|
||||
type: type,
|
||||
options: options,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
} else if (value['$']) {
|
||||
const varName = value['$']['at:name'];
|
||||
let options: string[] | undefined;
|
||||
|
||||
if (type === 'list' && value['at:option']) {
|
||||
options = value['at:option'].map((opt: any) => opt['$']['at:value']);
|
||||
}
|
||||
|
||||
if (varName && type) {
|
||||
variables.push({
|
||||
name: varName,
|
||||
type: type,
|
||||
options: options,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for (const variable of variables) {
|
||||
switch (variable.type) {
|
||||
case 'list':
|
||||
props[variable.name] = Property.StaticDropdown({
|
||||
displayName: variable.name,
|
||||
required: false,
|
||||
defaultValue: '',
|
||||
options: {
|
||||
disabled: false,
|
||||
options: variable.options
|
||||
? variable.options.map((option) => {
|
||||
return {
|
||||
label: option,
|
||||
value: option,
|
||||
};
|
||||
})
|
||||
: [],
|
||||
},
|
||||
});
|
||||
break;
|
||||
case 'string':
|
||||
props[variable.name] = Property.ShortText({
|
||||
displayName: variable.name,
|
||||
required: false,
|
||||
defaultValue: '',
|
||||
});
|
||||
break;
|
||||
case 'textarea':
|
||||
props[variable.name] = Property.LongText({
|
||||
displayName: variable.name,
|
||||
required: false,
|
||||
defaultValue: '',
|
||||
});
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return props;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,126 @@
|
||||
import {
|
||||
createTrigger,
|
||||
TriggerStrategy,
|
||||
PiecePropValueSchema,
|
||||
AppConnectionValueForAuthProperty,
|
||||
} from '@activepieces/pieces-framework';
|
||||
import { DedupeStrategy, Polling, pollingHelper, HttpMethod } from '@activepieces/pieces-common';
|
||||
import { confluenceAuth } from '../../index';
|
||||
import { confluenceApiCall, confluencePaginatedApiCall, PaginatedResponse } from '../common';
|
||||
import { isNil } from '@activepieces/shared';
|
||||
import { spaceIdProp } from '../common/props';
|
||||
|
||||
interface ConfluencePage {
|
||||
id: string;
|
||||
status: string;
|
||||
title: string;
|
||||
spaceId: string;
|
||||
createdAt: string;
|
||||
version: {
|
||||
number: number;
|
||||
createdAt: string;
|
||||
};
|
||||
}
|
||||
|
||||
type Props = {
|
||||
spaceId: string;
|
||||
};
|
||||
|
||||
const polling: Polling<AppConnectionValueForAuthProperty<typeof confluenceAuth>, Props> = {
|
||||
strategy: DedupeStrategy.TIMEBASED,
|
||||
async items({ auth, propsValue, lastFetchEpochMS }) {
|
||||
const pages = [];
|
||||
if (lastFetchEpochMS === 0) {
|
||||
const response = await confluenceApiCall<PaginatedResponse<ConfluencePage>>({
|
||||
domain: auth.props.confluenceDomain,
|
||||
username: auth.props.username,
|
||||
password: auth.props.password,
|
||||
version: 'v2',
|
||||
method: HttpMethod.GET,
|
||||
resourceUri: `/spaces/${propsValue.spaceId}/pages`,
|
||||
query: {
|
||||
limit: '10',
|
||||
sort: '-created-date',
|
||||
},
|
||||
});
|
||||
if (isNil(response.results)) {
|
||||
return [];
|
||||
}
|
||||
pages.push(...response.results);
|
||||
} else {
|
||||
const response = await confluencePaginatedApiCall<ConfluencePage>({
|
||||
domain: auth.props.confluenceDomain,
|
||||
username: auth.props.username,
|
||||
password: auth.props.password,
|
||||
method: HttpMethod.GET,
|
||||
version: 'v2',
|
||||
resourceUri: `/spaces/${propsValue.spaceId}/pages`,
|
||||
query: {
|
||||
sort: '-created-date',
|
||||
},
|
||||
});
|
||||
if (isNil(response)) {
|
||||
return [];
|
||||
}
|
||||
pages.push(...response);
|
||||
}
|
||||
|
||||
return pages.map((page) => {
|
||||
return {
|
||||
epochMilliSeconds: new Date(page.createdAt).getTime(),
|
||||
data: page,
|
||||
};
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
export const newPageTrigger = createTrigger({
|
||||
name: 'new-page',
|
||||
displayName: 'New Page',
|
||||
description: 'Triggers when a new page is created.',
|
||||
auth: confluenceAuth,
|
||||
type: TriggerStrategy.POLLING,
|
||||
props: {
|
||||
spaceId: spaceIdProp,
|
||||
},
|
||||
|
||||
async onEnable(context) {
|
||||
await pollingHelper.onEnable(polling, context);
|
||||
},
|
||||
async onDisable(context) {
|
||||
await pollingHelper.onDisable(polling, context);
|
||||
},
|
||||
async run(context) {
|
||||
return await pollingHelper.poll(polling, context);
|
||||
},
|
||||
async test(context) {
|
||||
return await pollingHelper.test(polling, context);
|
||||
},
|
||||
sampleData: {
|
||||
parentType: 'page',
|
||||
parentId: '123456',
|
||||
spaceId: 'SAMPLE123',
|
||||
ownerId: '12345678abcd',
|
||||
lastOwnerId: null,
|
||||
createdAt: '2024-01-01T12:00:00.000Z',
|
||||
authorId: '12345678abcd',
|
||||
position: 1000,
|
||||
version: {
|
||||
number: 1,
|
||||
message: 'Initial version',
|
||||
minorEdit: false,
|
||||
authorId: '12345678abcd',
|
||||
createdAt: '2024-01-01T12:00:00.000Z',
|
||||
},
|
||||
body: {},
|
||||
status: 'current',
|
||||
title: 'Sample Confluence Page',
|
||||
id: '987654321',
|
||||
_links: {
|
||||
editui: '/pages/resumedraft.action?draftId=987654321',
|
||||
webui: '/spaces/SAMPLE/pages/987654321/Sample+Confluence+Page',
|
||||
edituiv2: '/spaces/SAMPLE/pages/edit-v2/987654321',
|
||||
tinyui: '/x/abcd123',
|
||||
},
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user