diff --git a/packages/backend/src/app/flows/trigger-events/trigger-event.module.ts b/packages/backend/src/app/flows/trigger-events/trigger-event.module.ts index c97cacde63..27a1c74bbe 100755 --- a/packages/backend/src/app/flows/trigger-events/trigger-event.module.ts +++ b/packages/backend/src/app/flows/trigger-events/trigger-event.module.ts @@ -1,5 +1,5 @@ import { FastifyInstance, FastifyRequest } from "fastify"; -import { ListTriggerEventsRequest } from "@activepieces/shared"; +import { ListTriggerEventsRequest, TestTriggerRequest } from "@activepieces/shared"; import { triggerEventService } from "./trigger-event.service"; import { flowService } from "../flow.service"; @@ -12,6 +12,27 @@ export const triggerEventModule = async (app: FastifyInstance) => { const triggerEventController = async (fastify: FastifyInstance) => { + + fastify.get( + "/poll", + { + schema: { + querystring: TestTriggerRequest + }, + }, + async ( + request: FastifyRequest<{ + Querystring: TestTriggerRequest; + }> + ) => { + const flow = await flowService.getOneOrThrow({ projectId: request.principal.projectId, id: request.query.flowId }); + return await triggerEventService.test({ + projectId: request.principal.projectId, + flow: flow + }); + } + ); + fastify.get( "/", { @@ -24,10 +45,10 @@ const triggerEventController = async (fastify: FastifyInstance) => { Querystring: ListTriggerEventsRequest; }> ) => { - const flow = await flowService.getOneOrThrow({projectId: request.principal.projectId, id: request.query.flowId}); + const flow = await flowService.getOneOrThrow({ projectId: request.principal.projectId, id: request.query.flowId }); return await triggerEventService.list({ projectId: request.principal.projectId, - flowVersion: flow.version, + flow: flow, cursor: request.query.cursor ?? null, limit: request.query.limit ?? DEFUALT_PAGE_SIZE }); diff --git a/packages/backend/src/app/flows/trigger-events/trigger-event.service.ts b/packages/backend/src/app/flows/trigger-events/trigger-event.service.ts index bb7f327dd1..26957591ea 100644 --- a/packages/backend/src/app/flows/trigger-events/trigger-event.service.ts +++ b/packages/backend/src/app/flows/trigger-events/trigger-event.service.ts @@ -1,26 +1,16 @@ -import { apId, Cursor, FlowId, FlowVersion, ListenForTriggerEventsRequest, PieceTrigger, ProjectId, SeekPage, Trigger, TriggerEvent , TriggerType} from "@activepieces/shared"; +import { apId, Cursor, Flow, FlowId, FlowVersion, PieceTrigger, ProjectId, SeekPage, Trigger, TriggerEvent , TriggerHookType, TriggerType} from "@activepieces/shared"; import { databaseConnection } from "../../database/database-connection"; +import { engineHelper } from "../../helper/engine-helper"; import { buildPaginator } from "../../helper/pagination/build-paginator"; import { paginationHelper } from "../../helper/pagination/pagination-utils"; import { Order } from "../../helper/pagination/paginator"; +import { webhookService } from "../../webhooks/webhook-service"; import { flowService } from "../flow.service"; import { TriggerEventEntity } from "./trigger-event.entity"; const triggerEventrepo = databaseConnection.getRepository(TriggerEventEntity); export const triggerEventService = { - async test(flowVersion: FlowVersion, request: ListenForTriggerEventsRequest): Promise { - const trigger = flowVersion.trigger; - // TODO: Implement this - switch (trigger.type) { - case TriggerType.WEBHOOK: - break; - case TriggerType.PIECE: - throw new Error("Not implemented"); - case TriggerType.EMPTY: - break; - } - }, async saveEvent({projectId, flowId, payload}:{projectId: ProjectId, flowId: FlowId, payload: unknown}): Promise { const flow = await flowService.getOne({projectId: projectId, id: flowId, versionId: undefined, includeArtifacts: false}); const sourceName = getSourceName(flow.version.trigger); @@ -32,10 +22,46 @@ export const triggerEventService = { payload, }); }, - async list({projectId, flowVersion, cursor, limit}: {projectId: ProjectId, flowVersion: FlowVersion, cursor: Cursor | null, limit: number}): Promise> { + async test({projectId, flow}: {projectId: ProjectId, flow: Flow}): Promise> { + const trigger = flow.version.trigger; + const emptyPage = paginationHelper.createPage([], null); + switch (trigger.type) { + case TriggerType.WEBHOOK: + throw new Error("Cannot be tested"); + case TriggerType.PIECE: { + const testResult =( await engineHelper.executeTrigger({ + hookType: TriggerHookType.TEST, + flowVersion: flow.version, + collectionId: flow.collectionId, + webhookUrl: await webhookService.getWebhookUrl(projectId), + projectId: projectId + }) )as unknown[]; + await triggerEventrepo.delete({ + projectId, + flowId: flow.id, + }); + for(let i = 0; i < testResult.length; i++) { + await triggerEventService.saveEvent({ + projectId, + flowId: flow.id, + payload: testResult[i] + }); + } + return triggerEventService.list({ + projectId, + flow, + cursor: null, + limit: testResult.length + }); + } + case TriggerType.EMPTY: + return emptyPage; + } + }, + async list({projectId, flow, cursor, limit}: ListParams): Promise> { const decodedCursor = paginationHelper.decodeCursor(cursor); - const sourceName = getSourceName(flowVersion.trigger); - const flowId = flowVersion.flowId; + const sourceName = getSourceName(flow.version.trigger); + const flowId = flow.id; const paginator = buildPaginator({ entity: TriggerEventEntity, query: { @@ -66,4 +92,11 @@ function getSourceName(trigger: Trigger): string { case TriggerType.EMPTY: return TriggerType.EMPTY; } +} + +interface ListParams { + projectId: ProjectId; + flow: Flow; + cursor: Cursor | null; + limit: number; } \ No newline at end of file diff --git a/packages/backend/src/app/helper/engine-helper.ts b/packages/backend/src/app/helper/engine-helper.ts index 8a043eb494..5154f671dd 100644 --- a/packages/backend/src/app/helper/engine-helper.ts +++ b/packages/backend/src/app/helper/engine-helper.ts @@ -9,6 +9,7 @@ import { ExecuteFlowOperation, ExecutePropsOptions, ExecuteTriggerOperation, + ExecuteTriggerResponse, ExecutionOutput, getPackageAliasForPiece, getPackageVersionForPiece, @@ -78,12 +79,11 @@ export const engineHelper = { return result as ParseEventResponse; }, - async executeTrigger(operation: ExecuteTriggerOperation): Promise { + async executeTrigger(operation: ExecuteTriggerOperation): Promise { const sandbox = sandboxManager.obtainSandbox(); let result; try { await sandbox.cleanAndInit(); - const buildPath = sandbox.getSandboxFolderPath(); const { pieceName, pieceVersion } = (operation.flowVersion.trigger as PieceTrigger).settings; await installPieceDependency(buildPath, pieceName, pieceVersion); @@ -102,13 +102,9 @@ export const engineHelper = { finally { sandboxManager.returnSandbox(sandbox.boxId); } - - if (operation.hookType === TriggerHookType.RUN) { + if (operation.hookType === TriggerHookType.RUN || operation.hookType === TriggerHookType.TEST) { return result as unknown[]; } - if (operation.hookType === TriggerHookType.TEST) { - return result as unknown; - } return result as void; }, diff --git a/packages/backend/src/app/helper/pagination/pagination-utils.ts b/packages/backend/src/app/helper/pagination/pagination-utils.ts index 146a3a763b..56df1afa77 100755 --- a/packages/backend/src/app/helper/pagination/pagination-utils.ts +++ b/packages/backend/src/app/helper/pagination/pagination-utils.ts @@ -93,8 +93,8 @@ function encodePreviousCursor(cursor: string) { export const paginationHelper = { createPage(data: T[], cursor: CursorResult): SeekPage { return { - next: encodeNextCursor(cursor.afterCursor), - previous: encodePreviousCursor(cursor.beforeCursor), + next: encodeNextCursor(cursor?.afterCursor), + previous: encodePreviousCursor(cursor?.beforeCursor), data, }; }, diff --git a/packages/frontend/src/app/modules/common/common-layout.module.ts b/packages/frontend/src/app/modules/common/common-layout.module.ts index 6f653de287..c952b74871 100755 --- a/packages/frontend/src/app/modules/common/common-layout.module.ts +++ b/packages/frontend/src/app/modules/common/common-layout.module.ts @@ -82,6 +82,8 @@ import { MatButtonToggleModule } from '@angular/material/button-toggle'; import { HotspotComponent } from './components/hotspot/hotspot.component'; import { LoopStepMentionItemComponent } from './components/form-controls/interpolating-text-form-control/mentions-list/loop-step-mention-item/loop-step-mention-item.component'; import { CustomPathMentionDialogComponent } from './components/form-controls/interpolating-text-form-control/mentions-list/custom-path-mention-dialog/custom-path-mention-dialog.component'; +import { WarningBoxComponent } from './components/warning-box/warning-box.component'; +import { PieceTriggerMentionItemComponent } from './components/form-controls/interpolating-text-form-control/mentions-list/piece-trigger-mention-item/piece-trigger-mention-item.component'; export const materialTooltipDefaults: MatTooltipDefaultOptions = { showDelay: 0, hideDelay: 0, @@ -132,6 +134,8 @@ export const materialTooltipDefaults: MatTooltipDefaultOptions = { HotspotComponent, LoopStepMentionItemComponent, CustomPathMentionDialogComponent, + WarningBoxComponent, + PieceTriggerMentionItemComponent, ], imports: [ FontAwesomeModule, @@ -211,6 +215,8 @@ export const materialTooltipDefaults: MatTooltipDefaultOptions = { MatDividerModule, MatButtonToggleModule, HotspotComponent, + WarningBoxComponent, + PieceTriggerMentionItemComponent, ], providers: [ HighlightService, diff --git a/packages/frontend/src/app/modules/common/components/editable-text/editable-text.component.html b/packages/frontend/src/app/modules/common/components/editable-text/editable-text.component.html index c365ec40f8..430fbc2261 100755 --- a/packages/frontend/src/app/modules/common/components/editable-text/editable-text.component.html +++ b/packages/frontend/src/app/modules/common/components/editable-text/editable-text.component.html @@ -1,7 +1,7 @@
+ [matTooltip]="viewedText.scrollWidth > viewedText.clientWidth && value && !hideOverflownTextTooltip? value:'' "> {{ value }}
diff --git a/packages/frontend/src/app/modules/common/components/editable-text/editable-text.component.ts b/packages/frontend/src/app/modules/common/components/editable-text/editable-text.component.ts index 1a5e1729b9..29407002e1 100755 --- a/packages/frontend/src/app/modules/common/components/editable-text/editable-text.component.ts +++ b/packages/frontend/src/app/modules/common/components/editable-text/editable-text.component.ts @@ -23,8 +23,10 @@ export class EditableTextComponent { @Output() editingChanges: EventEmitter = new EventEmitter(); @ViewChild('editableText') editableText: ElementRef; @Input() hideOverflowWhileEditing = true; + @Input() hideOverflownTextTooltip = false; valueOnEditingStarted = ''; _editing = false; + get editing(): boolean { return this._editing; } diff --git a/packages/frontend/src/app/modules/common/components/form-controls/interpolating-text-form-control/mentions-list/mentions-list.component.html b/packages/frontend/src/app/modules/common/components/form-controls/interpolating-text-form-control/mentions-list/mentions-list.component.html index 4e20edcc09..c1ec9dfd88 100644 --- a/packages/frontend/src/app/modules/common/components/form-controls/interpolating-text-form-control/mentions-list/mentions-list.component.html +++ b/packages/frontend/src/app/modules/common/components/form-controls/interpolating-text-form-control/mentions-list/mentions-list.component.html @@ -25,20 +25,15 @@ - + - - - + diff --git a/packages/frontend/src/app/modules/common/components/form-controls/interpolating-text-form-control/mentions-list/piece-step-mention-item/piece-step-mention-item.component.ts b/packages/frontend/src/app/modules/common/components/form-controls/interpolating-text-form-control/mentions-list/piece-step-mention-item/piece-step-mention-item.component.ts index 8a81c73bfe..3c1439520b 100644 --- a/packages/frontend/src/app/modules/common/components/form-controls/interpolating-text-form-control/mentions-list/piece-step-mention-item/piece-step-mention-item.component.ts +++ b/packages/frontend/src/app/modules/common/components/form-controls/interpolating-text-form-control/mentions-list/piece-step-mention-item/piece-step-mention-item.component.ts @@ -72,12 +72,10 @@ export class PieceStepMentionItemComponent implements OnInit { private mentionsTreeCache: MentionsTreeCacheService ) {} ngOnInit(): void { - const cacheResult = this.mentionsTreeCache.getStepMentionsTree( - this._stepMention.step.name - ); - if (cacheResult) { + const cachedResult: undefined | MentionTreeNode[] = this.getChachedData(); + if (cachedResult) { this.sampleData$ = combineLatest({ - stepTree: of({ children: cacheResult.children, error: '' }), + stepTree: of({ children: cachedResult, error: '' }), search: this.mentionsTreeCache.listSearchBarObs$, }).pipe( map((res) => { @@ -100,15 +98,31 @@ export class PieceStepMentionItemComponent implements OnInit { BuilderSelectors.selectFlowItemDetails(this._stepMention.step) ); } + getChachedData() { + const step = this._stepMention.step; + let cachedResult: undefined | MentionTreeNode[] = undefined; + if ( + step.type === TriggerType.PIECE && + step.settings.inputUiInfo.currentSelectedData + ) { + cachedResult = traverseStepOutputAndReturnMentionTree( + step.settings.inputUiInfo.currentSelectedData, + step.name, + step.displayName + )?.children; + } else { + cachedResult = this.mentionsTreeCache.getStepMentionsTree( + step.name + )?.children; + } + return cachedResult; + } fetchSampleData() { const step = this._stepMention.step; - if (step.type !== TriggerType.PIECE && step.type !== ActionType.PIECE) { throw new Error("Activepieces- step isn't of a piece type"); } - const { pieceName, pieceVersion } = step.settings; - this.sampleData$ = this.actionMetaDataService .getPieceMetadata(pieceName, pieceVersion) .pipe( diff --git a/packages/frontend/src/app/modules/common/components/form-controls/interpolating-text-form-control/mentions-list/piece-trigger-mention-item/piece-trigger-mention-item.component.html b/packages/frontend/src/app/modules/common/components/form-controls/interpolating-text-form-control/mentions-list/piece-trigger-mention-item/piece-trigger-mention-item.component.html new file mode 100644 index 0000000000..ad46a39594 --- /dev/null +++ b/packages/frontend/src/app/modules/common/components/form-controls/interpolating-text-form-control/mentions-list/piece-trigger-mention-item/piece-trigger-mention-item.component.html @@ -0,0 +1,46 @@ + + + + + +
+ {{result.error}} +
+
+ +
+
+ Load sample data first +
+
+ This trigger needs to have data loaded from your account, to use as sample data +
+
+ Go to trigger + +
+
+
+
+
\ No newline at end of file diff --git a/packages/frontend/src/app/modules/common/components/form-controls/interpolating-text-form-control/mentions-list/piece-trigger-mention-item/piece-trigger-mention-item.component.ts b/packages/frontend/src/app/modules/common/components/form-controls/interpolating-text-form-control/mentions-list/piece-trigger-mention-item/piece-trigger-mention-item.component.ts new file mode 100644 index 0000000000..1290635bae --- /dev/null +++ b/packages/frontend/src/app/modules/common/components/form-controls/interpolating-text-form-control/mentions-list/piece-trigger-mention-item/piece-trigger-mention-item.component.ts @@ -0,0 +1,215 @@ +import { + ChangeDetectionStrategy, + Component, + EventEmitter, + Input, + OnInit, + Output, +} from '@angular/core'; +import { Store } from '@ngrx/store'; +import { + combineLatest, + map, + Observable, + of, + shareReplay, + Subject, + switchMap, + tap, +} from 'rxjs'; +import { + PieceTrigger, + TriggerStrategy, + TriggerType, +} from '@activepieces/shared'; +import { + MentionListItem, + MentionTreeNode, + traverseStepOutputAndReturnMentionTree, +} from '../../utils'; +import { MentionsTreeCacheService } from '../mentions-tree-cache.service'; +import { ActionMetaService } from '../../../../../../flow-builder/service/action-meta.service'; +import { FlowItemDetails } from '../../../../../../flow-builder/page/flow-builder/flow-right-sidebar/step-type-sidebar/step-type-item/flow-item-details'; +import { BuilderSelectors } from '../../../../../../flow-builder/store/builder/builder.selector'; +import { FlowItem } from '../../../../../model/flow-builder/flow-item'; +import { FlowsActions } from '../../../../../../flow-builder/store/flow/flows.action'; + +@Component({ + selector: 'app-piece-trigger-mention-item', + templateUrl: './piece-trigger-mention-item.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class PieceTriggerMentionItemComponent implements OnInit { + TriggerType = TriggerType; + expandSample = false; + @Input() + set stepMention(val: MentionListItem & { step: FlowItem }) { + if (val.step.type !== TriggerType.PIECE) { + throw new Error('Step is not a piece trigger'); + } + this._stepMention = val as MentionListItem & { + step: PieceTrigger; + }; + } + _stepMention: MentionListItem & { step: PieceTrigger }; + @Output() mentionClicked: EventEmitter = new EventEmitter(); + @Input() stepIndex: number; + flowItemDetails$: Observable; + sampleData$: Observable<{ + children: MentionTreeNode[] | undefined; + error: string; + markedNodesToShow: Map; + }>; + fetching$: Subject = new Subject(); + isPollingTrigger$: Observable; + constructor( + private store: Store, + private actionMetaDataService: ActionMetaService, + private mentionsTreeCache: MentionsTreeCacheService + ) {} + ngOnInit(): void { + const cachedResult: undefined | MentionTreeNode[] = this.getChachedData(); + this.isPollingTrigger$ = this.checkIfItIsPollingTrigger(); + if (cachedResult) { + this.sampleData$ = combineLatest({ + stepTree: of({ children: cachedResult, error: '' }), + search: this.mentionsTreeCache.listSearchBarObs$, + }).pipe( + map((res) => { + const markedNodesToShow = this.mentionsTreeCache.markNodesToShow( + this._stepMention.step.name, + res.search + ); + return { + children: res.stepTree.children, + error: '', + markedNodesToShow: markedNodesToShow, + }; + }) + ); + } else { + this.fetchSampleData(); + } + + this.flowItemDetails$ = this.store.select( + BuilderSelectors.selectFlowItemDetails(this._stepMention.step) + ); + } + getChachedData() { + const step = this._stepMention.step; + let cachedResult: undefined | MentionTreeNode[] = undefined; + if ( + step.type === TriggerType.PIECE && + step.settings.inputUiInfo.currentSelectedData + ) { + cachedResult = traverseStepOutputAndReturnMentionTree( + step.settings.inputUiInfo.currentSelectedData, + step.name, + step.displayName + )?.children; + } else { + cachedResult = this.mentionsTreeCache.getStepMentionsTree( + step.name + )?.children; + } + return cachedResult; + } + fetchSampleData() { + const step = this._stepMention.step; + if (step.type !== TriggerType.PIECE) { + throw new Error("Activepieces- step isn't of a piece type"); + } + const { pieceName, pieceVersion } = step.settings; + this.sampleData$ = this.actionMetaDataService + .getPieceMetadata(pieceName, pieceVersion) + .pipe( + tap(() => { + this.fetching$.next(true); + }), + map((pieceMetadata) => { + return step.settings.triggerName + ? pieceMetadata.triggers[step.settings.triggerName].sampleData ?? {} + : {}; + }), + map((sampleData) => { + const childrenNodes = traverseStepOutputAndReturnMentionTree( + sampleData, + step.name, + step.displayName + ).children; + return childrenNodes; + }), + map((res) => { + if (!res || res.length === 0) { + const error = this.getErrorMessage(); + return { error: error, children: [] }; + } + return { children: res, error: '' }; + }), + tap((res) => { + if (!res.error) { + this.mentionsTreeCache.setStepMentionsTree(step.name, { + children: res.children, + }); + } + this.fetching$.next(false); + }), + switchMap((res) => { + if (res.error) { + return combineLatest({ + stepTree: of({ children: [], error: res.error }), + search: this.mentionsTreeCache.listSearchBarObs$, + }); + } + return combineLatest({ + stepTree: of({ children: res.children, error: res.error }), + search: this.mentionsTreeCache.listSearchBarObs$, + }); + }), + map((res) => { + const markedNodesToShow = this.mentionsTreeCache.markNodesToShow( + step.name, + res.search + ); + return { + children: res.stepTree.children, + error: '', + markedNodesToShow: markedNodesToShow, + }; + }), + shareReplay(1) + ); + } + + private getErrorMessage() { + const noSampleData = `No sample available`; + const error = !this._stepMention.step.settings.triggerName + ? `Please select a trigger` + : noSampleData; + return error; + } + checkIfItIsPollingTrigger() { + return this.actionMetaDataService + .getPieceMetadata( + this._stepMention.step.settings.pieceName, + this._stepMention.step.settings.pieceVersion + ) + .pipe( + map((res) => { + if (res) { + return ( + res.triggers[this._stepMention.step.settings.triggerName].type === + TriggerStrategy.POLLING && + this._stepMention.step.settings.pieceName !== 'schedule' + ); + } + return false; + }) + ); + } + selectStep() { + this.store.dispatch( + FlowsActions.selectStepByName({ stepName: this._stepMention.step.name }) + ); + } +} diff --git a/packages/frontend/src/app/modules/common/components/form-controls/interpolating-text-form-control/mentions-list/webhook-trigger-mention-item/webhook-trigger-mention-item.component.html b/packages/frontend/src/app/modules/common/components/form-controls/interpolating-text-form-control/mentions-list/webhook-trigger-mention-item/webhook-trigger-mention-item.component.html index 7c84dc2cf8..644598c51d 100644 --- a/packages/frontend/src/app/modules/common/components/form-controls/interpolating-text-form-control/mentions-list/webhook-trigger-mention-item/webhook-trigger-mention-item.component.html +++ b/packages/frontend/src/app/modules/common/components/form-controls/interpolating-text-form-control/mentions-list/webhook-trigger-mention-item/webhook-trigger-mention-item.component.html @@ -20,14 +20,14 @@
- Test Trigger First + Send sample data first
- This trigger needs to be tested in order to view its data. + This trigger needs to have data sent to it, to use as sample data
Go to step + (click)="$event.stopPropagation(); selectStep()">Go to trigger
diff --git a/packages/frontend/src/app/modules/common/components/warning-box/warning-box.component.ts b/packages/frontend/src/app/modules/common/components/warning-box/warning-box.component.ts new file mode 100644 index 0000000000..9582d9a65d --- /dev/null +++ b/packages/frontend/src/app/modules/common/components/warning-box/warning-box.component.ts @@ -0,0 +1,14 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core'; + +@Component({ + selector: 'app-warning-box', + template: ` +
+ +
+ `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class WarningBoxComponent {} diff --git a/packages/frontend/src/app/modules/flow-builder/components/sidebar-header/sidebar-header.component.html b/packages/frontend/src/app/modules/flow-builder/components/sidebar-header/sidebar-header.component.html index 76f3a9fdea..1489e4a9da 100755 --- a/packages/frontend/src/app/modules/flow-builder/components/sidebar-header/sidebar-header.component.html +++ b/packages/frontend/src/app/modules/flow-builder/components/sidebar-header/sidebar-header.component.html @@ -3,7 +3,7 @@
-
{{ title }}
diff --git a/packages/frontend/src/app/modules/flow-builder/flow-builder.module.ts b/packages/frontend/src/app/modules/flow-builder/flow-builder.module.ts index f68374f6c6..49953f6999 100644 --- a/packages/frontend/src/app/modules/flow-builder/flow-builder.module.ts +++ b/packages/frontend/src/app/modules/flow-builder/flow-builder.module.ts @@ -70,7 +70,7 @@ import { BranchStepInputFormComponent } from './page/flow-builder/flow-right-sid import { CanvasUtilsComponent } from './page/flow-builder/canvas-utils/canvas-utils.component'; import { MagicWandDialogComponent } from './page/flow-builder/flow-builder-header/magic-wand-dialog/magic-flow-dialog.component'; import { HorizontalSidebarSeparatorComponent } from './page/flow-builder/canvas-utils/horizontal-sidebar-separator/horizontal-sidebar-separator.component'; -import { TestStepComponent } from './page/flow-builder/flow-right-sidebar/edit-step-sidebar/test-step/test-step.component'; +import { TestingStepsAndTriggersModule } from '../testing-steps-and-triggers/testing-steps-and-triggers.module'; import { StepNameEditorComponent } from './page/flow-builder/flow-right-sidebar/edit-step-sidebar/step-name-editor/step-name-editor.component'; import { CustomAuthConnectionDialogComponent } from './page/flow-builder/flow-right-sidebar/edit-step-sidebar/edit-step-accordion/input-forms/piece-input-forms/custom-auth-connection-dialog/custom-auth-connection-dialog.component'; @@ -101,6 +101,7 @@ import { CustomAuthConnectionDialogComponent } from './page/flow-builder/flow-ri MatExpansionModule, MonacoEditorModule, MatTabsModule, + TestingStepsAndTriggersModule, ], providers: [ { @@ -156,7 +157,6 @@ import { CustomAuthConnectionDialogComponent } from './page/flow-builder/flow-ri CanvasUtilsComponent, MagicWandDialogComponent, HorizontalSidebarSeparatorComponent, - TestStepComponent, StepNameEditorComponent, CustomAuthConnectionDialogComponent, ], diff --git a/packages/frontend/src/app/modules/flow-builder/page/flow-builder/collection-builder.component.html b/packages/frontend/src/app/modules/flow-builder/page/flow-builder/collection-builder.component.html index 6646b95969..8b10371413 100755 --- a/packages/frontend/src/app/modules/flow-builder/page/flow-builder/collection-builder.component.html +++ b/packages/frontend/src/app/modules/flow-builder/page/flow-builder/collection-builder.component.html @@ -16,7 +16,7 @@
diff --git a/packages/frontend/src/app/modules/flow-builder/page/flow-builder/collection-builder.component.ts b/packages/frontend/src/app/modules/flow-builder/page/flow-builder/collection-builder.component.ts index e7c1990697..c157e2f145 100755 --- a/packages/frontend/src/app/modules/flow-builder/page/flow-builder/collection-builder.component.ts +++ b/packages/frontend/src/app/modules/flow-builder/page/flow-builder/collection-builder.component.ts @@ -30,7 +30,7 @@ import { import { Title } from '@angular/platform-browser'; import { LeftSideBarType } from '../../../common/model/enum/left-side-bar-type.enum'; import { PannerService } from './canvas-utils/panning/panner.service'; -import { FlowItem } from '../../../common/model/flow-builder/flow-item'; +import { TestStepService } from '../../service/test-step.service'; @Component({ selector: 'app-collection-builder', @@ -51,8 +51,8 @@ export class CollectionBuilderComponent implements OnInit, OnDestroy { leftSidebarDragging = false; loadInitialData$: Observable = new Observable(); cursorStyle$: Observable; - currentStep$: Observable; TriggerType = TriggerType; + testingStepSectionIsRendered$: Observable; constructor( private store: Store, public pieceBuilderService: CollectionBuilderService, @@ -61,9 +61,11 @@ export class CollectionBuilderComponent implements OnInit, OnDestroy { private snackbar: MatSnackBar, private runDetailsService: RunDetailsService, private titleService: Title, - private pannerService: PannerService + private pannerService: PannerService, + private testStepService: TestStepService ) { - this.currentStep$ = this.store.select(BuilderSelectors.selectCurrentStep); + this.testingStepSectionIsRendered$ = + this.testStepService.testingStepSectionIsRendered$.asObservable(); this.cursorStyle$ = this.pannerService.isGrabbing$.asObservable().pipe( map((val) => { if (val) { diff --git a/packages/frontend/src/app/modules/flow-builder/page/flow-builder/flow-right-sidebar/edit-step-sidebar/edit-step-accordion/edit-step-accodion.component.html b/packages/frontend/src/app/modules/flow-builder/page/flow-builder/flow-right-sidebar/edit-step-sidebar/edit-step-accordion/edit-step-accodion.component.html index 878d08607a..37fb59681c 100755 --- a/packages/frontend/src/app/modules/flow-builder/page/flow-builder/flow-right-sidebar/edit-step-sidebar/edit-step-accordion/edit-step-accodion.component.html +++ b/packages/frontend/src/app/modules/flow-builder/page/flow-builder/flow-right-sidebar/edit-step-sidebar/edit-step-accordion/edit-step-accodion.component.html @@ -14,9 +14,7 @@ - - diff --git a/packages/frontend/src/app/modules/flow-builder/page/flow-builder/flow-right-sidebar/edit-step-sidebar/step-name-editor/step-name-editor.component.html b/packages/frontend/src/app/modules/flow-builder/page/flow-builder/flow-right-sidebar/edit-step-sidebar/step-name-editor/step-name-editor.component.html index 1199634119..2f0f64ad1f 100644 --- a/packages/frontend/src/app/modules/flow-builder/page/flow-builder/flow-right-sidebar/edit-step-sidebar/step-name-editor/step-name-editor.component.html +++ b/packages/frontend/src/app/modules/flow-builder/page/flow-builder/flow-right-sidebar/edit-step-sidebar/step-name-editor/step-name-editor.component.html @@ -1,7 +1,8 @@
- - -
-
- - Test - Trigger -
-
- - -
-
- Tested Successfully -
-
- -
- Retest -
- - - - Data - - - -
(Result {{currentResults.length-idx}})
-
{{res.created | date:"short"}}
-
-
-
-
- This sample data can be used in the next steps -
- - - -
- -
-
-
Testing trigger -
- Cancel -
- -
- - Action Required -
-

- Please send data to the webhook endpoint to - test the step. -

-
- -
-
- -
- -
-
- - - - - \ No newline at end of file diff --git a/packages/frontend/src/app/modules/flow-builder/page/flow-builder/flow-right-sidebar/edit-step-sidebar/test-step/test-step.component.scss b/packages/frontend/src/app/modules/flow-builder/page/flow-builder/flow-right-sidebar/edit-step-sidebar/test-step/test-step.component.scss deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/frontend/src/app/modules/flow-builder/page/flow-builder/flow-right-sidebar/flow-right-sidebar.component.html b/packages/frontend/src/app/modules/flow-builder/page/flow-builder/flow-right-sidebar/flow-right-sidebar.component.html index 52e4316571..163cf2ee77 100755 --- a/packages/frontend/src/app/modules/flow-builder/page/flow-builder/flow-right-sidebar/flow-right-sidebar.component.html +++ b/packages/frontend/src/app/modules/flow-builder/page/flow-builder/flow-right-sidebar/flow-right-sidebar.component.html @@ -8,11 +8,12 @@
+
@@ -22,10 +23,21 @@
- +
+
+ +
+ + +
+
+ +
diff --git a/packages/frontend/src/app/modules/flow-builder/page/flow-builder/flow-right-sidebar/flow-right-sidebar.component.scss b/packages/frontend/src/app/modules/flow-builder/page/flow-builder/flow-right-sidebar/flow-right-sidebar.component.scss index 50d4bb6717..9659a0f2cf 100644 --- a/packages/frontend/src/app/modules/flow-builder/page/flow-builder/flow-right-sidebar/flow-right-sidebar.component.scss +++ b/packages/frontend/src/app/modules/flow-builder/page/flow-builder/flow-right-sidebar/flow-right-sidebar.component.scss @@ -2,16 +2,16 @@ .top-resizer-section { - height:calc(100% - 160px); - max-height: calc(100% - 160px); + height:calc(100% - 200px); + max-height: calc(100% - 200px); } .bottom-resizer-section { - max-height: 160px; - min-height: 160px; + max-height: 200px; + min-height: 200px; } .resizer-area{ - height: calc(100% - 205px); + height: calc(100% - 245px); } \ No newline at end of file diff --git a/packages/frontend/src/app/modules/flow-builder/page/flow-builder/flow-right-sidebar/flow-right-sidebar.component.ts b/packages/frontend/src/app/modules/flow-builder/page/flow-builder/flow-right-sidebar/flow-right-sidebar.component.ts index bd1ff5e947..b2bb1e2316 100755 --- a/packages/frontend/src/app/modules/flow-builder/page/flow-builder/flow-right-sidebar/flow-right-sidebar.component.ts +++ b/packages/frontend/src/app/modules/flow-builder/page/flow-builder/flow-right-sidebar/flow-right-sidebar.component.ts @@ -7,15 +7,16 @@ import { ViewChild, } from '@angular/core'; import { RightSideBarType } from '../../../../common/model/enum/right-side-bar-type.enum'; -import { map, Observable, tap } from 'rxjs'; +import { map, Observable, of, switchMap, tap } from 'rxjs'; import { Store } from '@ngrx/store'; import { FormControl } from '@angular/forms'; import { BuilderSelectors } from '../../../store/builder/builder.selector'; import { CdkDragMove } from '@angular/cdk/drag-drop'; import { FlowItem } from '../../../../common/model/flow-builder/flow-item'; -import { ActionType, TriggerType } from '@activepieces/shared'; +import { ActionType, TriggerStrategy, TriggerType } from '@activepieces/shared'; import { TestStepService } from '../../../service/test-step.service'; +import { ActionMetaService } from '../../../service/action-meta.service'; @Component({ selector: 'app-flow-right-sidebar', @@ -37,11 +38,13 @@ export class FlowRightSidebarComponent implements OnInit { selectedStepResultContainer: ElementRef; elevateResizer$: Observable; animateSectionsHeightChange = false; + isCurrentStepPollingTrigger$: Observable; constructor( private store: Store, private ngZone: NgZone, private testStepService: TestStepService, - private renderer2: Renderer2 + private renderer2: Renderer2, + private actionMetaDataService: ActionMetaService ) {} ngOnInit(): void { @@ -62,6 +65,31 @@ export class FlowRightSidebarComponent implements OnInit { ); }) ); + this.isCurrentStepPollingTrigger$ = this.currentStep$.pipe( + switchMap((step) => { + if ( + step && + step.type === TriggerType.PIECE && + step.settings.pieceName !== 'schedule' + ) { + return this.actionMetaDataService + .getPieceMetadata( + step.settings.pieceName, + step.settings.pieceVersion + ) + .pipe( + map((res) => { + return ( + res.triggers[step.settings.triggerName] && + res.triggers[step.settings.triggerName].type === + TriggerStrategy.POLLING + ); + }) + ); + } + return of(false); + }) + ); } get sidebarType() { diff --git a/packages/frontend/src/app/modules/flow-builder/page/flow-builder/flow-right-sidebar/step-type-sidebar/step-type-sidebar.component.ts b/packages/frontend/src/app/modules/flow-builder/page/flow-builder/flow-right-sidebar/step-type-sidebar/step-type-sidebar.component.ts index 53d3bd0aed..35120dc74e 100755 --- a/packages/frontend/src/app/modules/flow-builder/page/flow-builder/flow-right-sidebar/step-type-sidebar/step-type-sidebar.component.ts +++ b/packages/frontend/src/app/modules/flow-builder/page/flow-builder/flow-right-sidebar/step-type-sidebar/step-type-sidebar.component.ts @@ -193,6 +193,9 @@ export class StepTypeSidebarComponent implements OnInit { pieceVersion: triggerDetails.extra!.appVersion, triggerName: '', input: {}, + inputUiInfo: { + currentSelectedData: '', + }, }, }; break; diff --git a/packages/frontend/src/app/modules/flow-builder/service/test-step.service.ts b/packages/frontend/src/app/modules/flow-builder/service/test-step.service.ts index 0d808cea3e..acb08bbbae 100644 --- a/packages/frontend/src/app/modules/flow-builder/service/test-step.service.ts +++ b/packages/frontend/src/app/modules/flow-builder/service/test-step.service.ts @@ -1,6 +1,6 @@ import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; -import { Subject } from 'rxjs'; +import { BehaviorSubject, Subject } from 'rxjs'; import { SeekPage, TriggerEvent } from '@activepieces/shared'; import { environment } from '../../../../environments/environment'; @@ -9,8 +9,11 @@ import { environment } from '../../../../environments/environment'; }) export class TestStepService { elevateResizer$: Subject = new Subject(); + testingStepSectionIsRendered$: BehaviorSubject = new BehaviorSubject( + false + ); constructor(private http: HttpClient) {} - getWebhookResults(flowId: string) { + getTriggerEventsResults(flowId: string) { return this.http.get>( environment.apiUrl + '/trigger-events', { @@ -21,10 +24,13 @@ export class TestStepService { ); } getPollingResults(flowId: string) { - return this.http.get>(environment.apiUrl + '/poll', { - params: { - flowId: flowId, - }, - }); + return this.http.get>( + environment.apiUrl + '/trigger-events/poll', + { + params: { + flowId: flowId, + }, + } + ); } } diff --git a/packages/frontend/src/app/modules/flow-builder/store/builder/builder.selector.ts b/packages/frontend/src/app/modules/flow-builder/store/builder/builder.selector.ts index d981a64416..4e02bedcad 100755 --- a/packages/frontend/src/app/modules/flow-builder/store/builder/builder.selector.ts +++ b/packages/frontend/src/app/modules/flow-builder/store/builder/builder.selector.ts @@ -454,6 +454,9 @@ const selectAllStepsForMentionsDropdown = createSelector( }); } ); +const selectStepValidity = createSelector(selectCurrentStep, (step) => { + return step?.valid || false; +}); function findStepLogoUrlForMentions( step: FlowItem, flowItemsDetailsState: FlowItemsDetailsState @@ -547,4 +550,5 @@ export const BuilderSelectors = { selectStepLogoUrl, selectCurrentStepSettings, selectStepSelectedSampleData, + selectStepValidity, }; diff --git a/packages/frontend/src/app/modules/testing-steps-and-triggers/test-polling-trigger/test-polling-trigger.component.html b/packages/frontend/src/app/modules/testing-steps-and-triggers/test-polling-trigger/test-polling-trigger.component.html new file mode 100644 index 0000000000..74fa2a9086 --- /dev/null +++ b/packages/frontend/src/app/modules/testing-steps-and-triggers/test-polling-trigger/test-polling-trigger.component.html @@ -0,0 +1,88 @@ +
+
+ Generate Sample Data +
+ + + + +
+ +
+ + Load Data +
+
+ + +
+
+ + Loaded + Successfully +
+
+ +
+ Load Data +
+ + + + Data + + + +
(Result {{currentResults.length-idx}})
+
{{res.created | date:"short"}}
+
+
+
+
+ This sample data can be used in the next steps +
+ + + +
+ +
+
+ No results found +
+
+ +
+ Load Data +
+ +

Please add some data then press "Load Data"

+
+
+ + +
+
+ + +
+ +
+
+ + + + + \ No newline at end of file diff --git a/packages/frontend/src/app/modules/testing-steps-and-triggers/test-polling-trigger/test-polling-trigger.component.ts b/packages/frontend/src/app/modules/testing-steps-and-triggers/test-polling-trigger/test-polling-trigger.component.ts new file mode 100644 index 0000000000..a62b8ca94e --- /dev/null +++ b/packages/frontend/src/app/modules/testing-steps-and-triggers/test-polling-trigger/test-polling-trigger.component.ts @@ -0,0 +1,135 @@ +import { Component } from '@angular/core'; +import { FormControl } from '@angular/forms'; +import { Store } from '@ngrx/store'; +import deepEqual from 'deep-equal'; +import { + BehaviorSubject, + map, + Observable, + of, + switchMap, + take, + tap, +} from 'rxjs'; +import { TriggerType } from '@activepieces/shared'; +import { TestStepService } from '../../flow-builder/service/test-step.service'; +import { BuilderSelectors } from '../../flow-builder/store/builder/builder.selector'; +import { FlowsActions } from '../../flow-builder/store/flow/flows.action'; +import { TestStepCoreComponent } from '../test-steps-core'; +export interface PollingHistoricalData { + payload: unknown; + created: string; +} +@Component({ + selector: 'app-test-polling-trigger', + templateUrl: './test-polling-trigger.component.html', +}) +export class TestPollingTriggerComponent extends TestStepCoreComponent { + currentResults$: BehaviorSubject; + saveAfterNewDataIsLoaded$: Observable; + saveNewSelectedData$: Observable; + selectedDataControl: FormControl = new FormControl(); + initialHistoricalData$: Observable; + initaillySelectedSampleData$: Observable; + testStep$: Observable; + loading = false; + hasBeenTested = false; + isValid$: Observable; + constructor(testStepService: TestStepService, private store: Store) { + super(testStepService); + this.isValid$ = this.store.select(BuilderSelectors.selectStepValidity); + this.initialObservables(); + } + private initialObservables() { + this.saveNewSelectedData$ = this.selectedDataControl.valueChanges.pipe( + tap(() => { + this.saveNewResultToStep(); + }), + map(() => void 0) + ); + this.initialHistoricalData$ = this.store + .select(BuilderSelectors.selectCurrentFlowId) + .pipe( + take(1), + switchMap((res) => { + return this.testStepService.getTriggerEventsResults(res!.toString()); + }), + map((res) => { + return res.data; + }), + tap((res) => { + this.currentResults$ = new BehaviorSubject( + res + ); + }) + ); + this.initaillySelectedSampleData$ = this.store + .select(BuilderSelectors.selectStepSelectedSampleData) + .pipe( + take(1), + tap((res) => { + this.selectedDataControl.setValue(res); + this.setSelectedDataControlListener(); + }) + ); + } + private setSelectedDataControlListener() { + this.saveNewSelectedData$ = this.selectedDataControl.valueChanges.pipe( + tap(() => { + this.saveNewResultToStep(); + }), + map(() => void 0) + ); + } + testStep() { + this.loading = true; + this.hasBeenTested = true; + this.testStep$ = this.store + .select(BuilderSelectors.selectCurrentFlowId) + .pipe( + take(1), + switchMap((id) => { + if (id) { + return this.testStepService.getPollingResults(id.toString()).pipe( + tap((res) => { + this.loading = false; + this.currentResults$.next(res.data); + if (res.data.length > 0) + this.selectedDataControl.setValue(res.data[0].payload); + this.testStepService.elevateResizer$.next(true); + }), + map((res) => res.data) + ); + } + return of([]); + }) + ); + } + saveNewResultToStep() { + this.saveAfterNewDataIsLoaded$ = this.store + .select(BuilderSelectors.selectCurrentStep) + .pipe( + take(1), + tap((step) => { + if (step && step.type === TriggerType.PIECE) { + const clone = { ...step }; + clone.settings = { + ...clone.settings, + inputUiInfo: { + currentSelectedData: this.selectedDataControl.value, + }, + }; + this.store.dispatch( + FlowsActions.updateTrigger({ + operation: clone, + }) + ); + } + }), + map(() => void 0) + ); + } + dropdownCompareWithFunction = (opt: unknown, formControlValue: unknown) => { + return formControlValue !== undefined && deepEqual(opt, formControlValue); + }; +} diff --git a/packages/frontend/src/app/modules/testing-steps-and-triggers/test-steps-core.ts b/packages/frontend/src/app/modules/testing-steps-and-triggers/test-steps-core.ts new file mode 100644 index 0000000000..89ab2ac28b --- /dev/null +++ b/packages/frontend/src/app/modules/testing-steps-and-triggers/test-steps-core.ts @@ -0,0 +1,15 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { TestStepService } from '../flow-builder/service/test-step.service'; +@Component({ + template: ``, +}) +export class TestStepCoreComponent implements OnDestroy, OnInit { + constructor(protected testStepService: TestStepService) {} + ngOnInit(): void { + this.testStepService.testingStepSectionIsRendered$.next(true); + } + + ngOnDestroy(): void { + this.testStepService.testingStepSectionIsRendered$.next(false); + } +} diff --git a/packages/frontend/src/app/modules/testing-steps-and-triggers/test-webhook-trigger/test-webhook-trigger.component.html b/packages/frontend/src/app/modules/testing-steps-and-triggers/test-webhook-trigger/test-webhook-trigger.component.html new file mode 100644 index 0000000000..db702530b0 --- /dev/null +++ b/packages/frontend/src/app/modules/testing-steps-and-triggers/test-webhook-trigger/test-webhook-trigger.component.html @@ -0,0 +1,86 @@ +
+
+ Generate Sample Data +
+ +
+
+ + Send + Data +
+
+ + +
+
+ Tested + Successfully +
+
+ +
+ Retest +
+ + + + Data + + + +
(Result {{currentResults.length-idx}})
+
{{res.created | date:"short"}}
+
+
+
+
+ This sample data can be used in the next steps +
+ + + +
+ +
+
+
Testing trigger +
+ Cancel +
+ + +
+ + Action Required +
+

+ Please send data to the webhook endpoint to + test the step. +

+ +
+ + +
+
+
+ +
+ +
+ +
+
+ + + + + \ No newline at end of file diff --git a/packages/frontend/src/app/modules/flow-builder/page/flow-builder/flow-right-sidebar/edit-step-sidebar/test-step/test-step.component.ts b/packages/frontend/src/app/modules/testing-steps-and-triggers/test-webhook-trigger/test-webhook-trigger.component.ts similarity index 86% rename from packages/frontend/src/app/modules/flow-builder/page/flow-builder/flow-right-sidebar/edit-step-sidebar/test-step/test-step.component.ts rename to packages/frontend/src/app/modules/testing-steps-and-triggers/test-webhook-trigger/test-webhook-trigger.component.ts index 50a80b1da5..d350186da3 100644 --- a/packages/frontend/src/app/modules/flow-builder/page/flow-builder/flow-right-sidebar/edit-step-sidebar/test-step/test-step.component.ts +++ b/packages/frontend/src/app/modules/testing-steps-and-triggers/test-webhook-trigger/test-webhook-trigger.component.ts @@ -16,43 +16,46 @@ import { tap, } from 'rxjs'; import { TriggerType } from '@activepieces/shared'; -import { TestStepService } from '../../../../../service/test-step.service'; -import { BuilderSelectors } from '../../../../../store/builder/builder.selector'; import { FormControl } from '@angular/forms'; -import { FlowsActions } from '../../../../../store/flow/flows.action'; import deepEqual from 'deep-equal'; +import { TestStepService } from '../../flow-builder/service/test-step.service'; +import { BuilderSelectors } from '../../flow-builder/store/builder/builder.selector'; +import { FlowsActions } from '../../flow-builder/store/flow/flows.action'; +import { TestStepCoreComponent } from '../test-steps-core'; export interface WebhookHistoricalData { payload: unknown; created: string; } @Component({ - selector: 'app-test-step', - templateUrl: './test-step.component.html', - styleUrls: ['./test-step.component.scss'], + selector: 'app-test-webhook-trigger', + templateUrl: './test-webhook-trigger.component.html', }) -export class TestStepComponent { +export class TestWebhookTriggerComponent extends TestStepCoreComponent { currentResults$: BehaviorSubject; testStep$: Observable; foundNewResult$: Subject = new Subject(); loading = false; selectedDataControl: FormControl = new FormControl(); - saveAfterNewDataIsLoaded$: Observable; + saveNewSelectedData$: Observable; initialHistoricalData$: Observable; initaillySelectedSampleData$: Observable; stopSelectedDataControlListener$ = new Subject(); cancelTesting$ = new Subject(); - constructor(private testStepService: TestStepService, private store: Store) { + saveAfterNewDataIsLoaded$: Observable; + constructor(testStepService: TestStepService, private store: Store) { + super(testStepService); this.initialObservables(); } + private initialObservables() { this.setSelectedDataControlListener(); this.initialHistoricalData$ = this.store .select(BuilderSelectors.selectCurrentFlowId) .pipe( switchMap((res) => { - return this.testStepService.getWebhookResults(res!.toString()); + return this.testStepService.getTriggerEventsResults(res!.toString()); }), map((res) => { return res.data; @@ -111,7 +114,7 @@ export class TestStepComponent { createResultsChecker(flowId: string) { const observables = { currentResults: of(this.currentResults$.value), - resultsChecked: this.testStepService.getWebhookResults(flowId), + resultsChecked: this.testStepService.getTriggerEventsResults(flowId), }; return forkJoin(observables).pipe( map((res) => { diff --git a/packages/frontend/src/app/modules/testing-steps-and-triggers/testing-steps-and-triggers.module.ts b/packages/frontend/src/app/modules/testing-steps-and-triggers/testing-steps-and-triggers.module.ts new file mode 100644 index 0000000000..7759d8b249 --- /dev/null +++ b/packages/frontend/src/app/modules/testing-steps-and-triggers/testing-steps-and-triggers.module.ts @@ -0,0 +1,13 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { TestWebhookTriggerComponent } from './test-webhook-trigger/test-webhook-trigger.component'; +import { CommonLayoutModule } from '../common/common-layout.module'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { TestPollingTriggerComponent } from './test-polling-trigger/test-polling-trigger.component'; + +@NgModule({ + declarations: [TestWebhookTriggerComponent, TestPollingTriggerComponent], + exports: [TestWebhookTriggerComponent, TestPollingTriggerComponent], + imports: [CommonModule, CommonLayoutModule, FormsModule, ReactiveFormsModule], +}) +export class TestingStepsAndTriggersModule {} diff --git a/packages/pieces/framework/package.json b/packages/pieces/framework/package.json index 86d838478b..0e0aaa2d49 100644 --- a/packages/pieces/framework/package.json +++ b/packages/pieces/framework/package.json @@ -1,5 +1,5 @@ { "name": "@activepieces/framework", - "version": "0.3.5", + "version": "0.3.6", "type": "commonjs" } diff --git a/packages/pieces/framework/src/lib/common/polling/index.ts b/packages/pieces/framework/src/lib/common/polling/index.ts index 2804d6cf68..0f871e1137 100644 --- a/packages/pieces/framework/src/lib/common/polling/index.ts +++ b/packages/pieces/framework/src/lib/common/polling/index.ts @@ -34,7 +34,7 @@ export const pollingHelper = { switch (polling.strategy) { case DedupeStrategy.TIMEBASED: { const lastEpochMillSeconds = (await store.get("lastPoll")) ?? 0; - const items = await polling.items({ propsValue, lastFetchEpochMS: lastEpochMillSeconds}); + const items = await polling.items({ propsValue, lastFetchEpochMS: lastEpochMillSeconds }); const newLastEpochMillSeconds = items.reduce((acc, item) => Math.max(acc, item.epochMillSeconds), lastEpochMillSeconds); await store.put("lastPoll", newLastEpochMillSeconds); return items.filter(f => f.epochMillSeconds > lastEpochMillSeconds).map((item) => item.data); @@ -75,10 +75,20 @@ export const pollingHelper = { }, async test(polling: Polling, { propsValue }: { store: Store, propsValue: INPUT }): Promise { switch (polling.strategy) { - case DedupeStrategy.TIMEBASED: - return (await polling.items({ propsValue , lastFetchEpochMS: 0 })); + case DedupeStrategy.TIMEBASED: { + const items = await polling.items({ propsValue, lastFetchEpochMS: 0 }); + return getFirstFiveOrAll(items); + } case DedupeStrategy.LAST_ITEM: - return (await polling.items({ propsValue })); + return getFirstFiveOrAll(await polling.items({ propsValue })); } } -} \ No newline at end of file +} + +function getFirstFiveOrAll(array: unknown[]) { + if (array.length <= 5) { + return array; + } else { + return array.slice(0, 5); + } +} diff --git a/packages/pieces/framework/src/lib/framework/trigger/trigger.ts b/packages/pieces/framework/src/lib/framework/trigger/trigger.ts index c0895fdc39..cefa578aa6 100644 --- a/packages/pieces/framework/src/lib/framework/trigger/trigger.ts +++ b/packages/pieces/framework/src/lib/framework/trigger/trigger.ts @@ -20,7 +20,7 @@ class ITrigger implements Tr ) => Promise, public readonly test: ( ctx: TriggerContext> - ) => Promise, + ) => Promise, public sampleData: unknown ) { } } @@ -36,7 +36,7 @@ export function createTrigger, S>) => Promise; onDisable: (context: TriggerHookContext, S>) => Promise; run: (context: TriggerContext>) => Promise; - test?: (context: TriggerContext>) => Promise; + test?: (context: TriggerContext>) => Promise; sampleData: unknown | ((context: TriggerContext>) => Promise); }): Trigger { return new ITrigger( @@ -48,7 +48,7 @@ export function createTrigger Promise.resolve()), + request.test ?? (() => Promise.resolve([request.sampleData])), request.sampleData ); } diff --git a/packages/pieces/google-sheets/package.json b/packages/pieces/google-sheets/package.json index a03c9d2b81..f52b29365a 100644 --- a/packages/pieces/google-sheets/package.json +++ b/packages/pieces/google-sheets/package.json @@ -1,4 +1,4 @@ { "name": "@activepieces/piece-google-sheets", - "version": "0.2.1" + "version": "0.2.2" } diff --git a/packages/pieces/google-sheets/src/lib/triggers/new-row-added.ts b/packages/pieces/google-sheets/src/lib/triggers/new-row-added.ts index a393905fba..a7113766ab 100644 --- a/packages/pieces/google-sheets/src/lib/triggers/new-row-added.ts +++ b/packages/pieces/google-sheets/src/lib/triggers/new-row-added.ts @@ -18,6 +18,17 @@ export const newRowAdded = createTrigger({ "value": sampleData }, type: TriggerStrategy.POLLING, + async test(context) { + const sheetId = context.propsValue['sheet_id']; + const accessToken = context.propsValue['authentication']['access_token']; + const spreadSheetId = context.propsValue['spreadsheet_id']; + const allValues = await googleSheetsCommon.getValues(spreadSheetId, accessToken, sheetId); + if(!allValues) + { + return []; + } + return allValues.slice(Math.max(allValues.length-5,0)); + }, async onEnable(context) { const sheetId = context.propsValue['sheet_id']; const accessToken = context.propsValue['authentication']['access_token']; @@ -35,7 +46,7 @@ export const newRowAdded = createTrigger({ const spreadSheetId = context.propsValue['spreadsheet_id']; const rowCount = (await context.store?.get("rowCount")) ?? 0; const currentValues = await googleSheetsCommon.getValues(spreadSheetId, accessToken, sheetId) - let payloads: any[] = []; + let payloads: unknown[] = []; console.log(`The spreadsheet ${spreadSheetId} has now ${currentValues.length} rows, previous # of rows ${rowCount}`); if (currentValues.length > rowCount) { payloads = currentValues.slice(rowCount).map(value => { diff --git a/packages/shared/package.json b/packages/shared/package.json index 529c2d17e6..863ff76e00 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -1,5 +1,5 @@ { "name": "@activepieces/shared", - "version": "0.3.3", + "version": "0.3.4", "type": "commonjs" } diff --git a/packages/shared/src/lib/flows/trigger-events/trigger-events-dto.ts b/packages/shared/src/lib/flows/trigger-events/trigger-events-dto.ts index 7edc4ac16a..85c4b9586f 100755 --- a/packages/shared/src/lib/flows/trigger-events/trigger-events-dto.ts +++ b/packages/shared/src/lib/flows/trigger-events/trigger-events-dto.ts @@ -2,12 +2,6 @@ import { Static, Type } from "@sinclair/typebox"; import { Cursor } from "../../common/seek-page"; import { FlowId } from "../flow"; -export const ListenForTriggerEventsRequest = Type.Object({ - flowId: Type.String(), -}); - -export type ListenForTriggerEventsRequest = Static; - export const ListTriggerEventsRequest = Type.Object({ flowId: Type.String({}), limit: Type.Optional(Type.Number({})), @@ -15,3 +9,10 @@ export const ListTriggerEventsRequest = Type.Object({ }); export type ListTriggerEventsRequest = Omit, "flowId">, "cursor"> & { flowId: FlowId, cursor: Cursor | undefined }; + +export const TestTriggerRequest = Type.Object({ + flowId: Type.String({}), +}); + +export type TestTriggerRequest = Omit, "flowId"> & { flowId: FlowId }; + diff --git a/packages/shared/src/lib/flows/triggers/trigger.ts b/packages/shared/src/lib/flows/triggers/trigger.ts index ad27643b44..6dd4502a10 100755 --- a/packages/shared/src/lib/flows/triggers/trigger.ts +++ b/packages/shared/src/lib/flows/triggers/trigger.ts @@ -44,7 +44,9 @@ export const PieceTriggerSettings = Type.Object({ pieceName: Type.String({}), pieceVersion: SemVerType, triggerName: Type.String({}), - input: Type.Record(Type.String({}), Type.Any()) + input: Type.Record(Type.String({}), Type.Any()), + inputUiInfo:SampleDataSettingsObject + }); export type PieceTriggerSettings = Static;