import { QueryContext, ModelOptions } from 'objection'; import Base from './base'; import App from './app'; import Flow from './flow'; import Connection from './connection'; import ExecutionStep from './execution-step'; import type { IJSONObject, IStep } from '@automatisch/types'; import Telemetry from '../helpers/telemetry'; import appConfig from '../config/app'; class Step extends Base { id!: string; flowId!: string; key?: string; appKey?: string; type!: IStep['type']; connectionId?: string; status = 'incomplete'; position!: number; parameters: IJSONObject; connection?: Connection; flow: Flow; executionSteps: ExecutionStep[]; static tableName = 'steps'; static jsonSchema = { type: 'object', required: ['type'], properties: { id: { type: 'string', format: 'uuid' }, flowId: { type: 'string', format: 'uuid' }, key: { type: ['string', 'null'] }, appKey: { type: ['string', 'null'], minLength: 1, maxLength: 255 }, type: { type: 'string', enum: ['action', 'trigger'] }, connectionId: { type: ['string', 'null'], format: 'uuid' }, status: { type: 'string', enum: ['incomplete', 'completed'] }, position: { type: 'integer' }, parameters: { type: 'object' }, }, }; static get virtualAttributes() { return ['iconUrl']; } static relationMappings = () => ({ flow: { relation: Base.BelongsToOneRelation, modelClass: Flow, join: { from: 'steps.flow_id', to: 'flows.id', }, }, connection: { relation: Base.HasOneRelation, modelClass: Connection, join: { from: 'steps.connection_id', to: 'connections.id', }, }, executionSteps: { relation: Base.HasManyRelation, modelClass: ExecutionStep, join: { from: 'steps.id', to: 'execution_steps.step_id', }, }, }); get iconUrl() { if (!this.appKey) return null; return `${appConfig.baseUrl}/apps/${this.appKey}/assets/favicon.svg`; } async $afterInsert(queryContext: QueryContext) { await super.$afterInsert(queryContext); Telemetry.stepCreated(this); } async $afterUpdate(opt: ModelOptions, queryContext: QueryContext) { await super.$afterUpdate(opt, queryContext); Telemetry.stepUpdated(this); } get isTrigger(): boolean { return this.type === 'trigger'; } get isAction(): boolean { return this.type === 'action'; } async getApp() { if (!this.appKey) return null; return await App.findOneByKey(this.appKey); } async getNextStep() { const flow = await this.$relatedQuery('flow'); return await flow .$relatedQuery('steps') .findOne({ position: this.position + 1 }); } async getTriggerCommand() { const { appKey, key, isTrigger } = this; if (!isTrigger || !appKey || !key) return null; const app = await App.findOneByKey(appKey); const command = app.triggers.find((trigger) => trigger.key === key); return command; } async getActionCommand() { const { appKey, key, isAction } = this; if (!isAction || !appKey || !key) return null; const app = await App.findOneByKey(appKey); const command = app.actions.find((action) => action.key === key); return command; } } export default Step;