mirror of
https://github.com/OneUptime/oneuptime.git
synced 2026-04-06 00:32:12 +02:00
add select clause to trigger
This commit is contained in:
@@ -18,6 +18,7 @@ export enum ComponentInputType {
|
||||
Email = 'Email',
|
||||
CronTab = 'CronTab',
|
||||
Query = 'Database Query',
|
||||
Select = 'Database Select',
|
||||
BaseModel = 'Database Record',
|
||||
BaseModelArray = 'Database Records',
|
||||
JSONArray = 'List of JSON',
|
||||
|
||||
@@ -33,7 +33,7 @@ export default class BaseModelComponent {
|
||||
placeholder: 'Example: {"columnName": "value", ...}',
|
||||
},
|
||||
{
|
||||
type: ComponentInputType.Query,
|
||||
type: ComponentInputType.Select,
|
||||
name: 'Select Fields',
|
||||
description: `Select on ${model.singularName}`,
|
||||
required: true,
|
||||
@@ -92,7 +92,7 @@ export default class BaseModelComponent {
|
||||
placeholder: 'Example: {"columnName": "value", ...}',
|
||||
},
|
||||
{
|
||||
type: ComponentInputType.Query,
|
||||
type: ComponentInputType.Select,
|
||||
name: 'Select Fields',
|
||||
description: `Select on ${model.singularName}`,
|
||||
required: true,
|
||||
@@ -288,7 +288,16 @@ export default class BaseModelComponent {
|
||||
iconProp: IconProp.Bolt,
|
||||
tableName: model.tableName!,
|
||||
componentType: ComponentType.Trigger,
|
||||
arguments: [],
|
||||
arguments: [
|
||||
{
|
||||
type: ComponentInputType.Select,
|
||||
name: 'Select Fields',
|
||||
description: `Select on ${model.singularName}`,
|
||||
required: true,
|
||||
id: 'select',
|
||||
placeholder: 'Example: {"columnName": true, ...}',
|
||||
},
|
||||
],
|
||||
returnValues: [
|
||||
{
|
||||
id: 'data',
|
||||
@@ -422,7 +431,16 @@ export default class BaseModelComponent {
|
||||
iconProp: IconProp.Bolt,
|
||||
tableName: model.tableName!,
|
||||
componentType: ComponentType.Trigger,
|
||||
arguments: [],
|
||||
arguments: [
|
||||
{
|
||||
type: ComponentInputType.Select,
|
||||
name: 'Select Fields',
|
||||
description: `Select on ${model.singularName}`,
|
||||
required: true,
|
||||
id: 'select',
|
||||
placeholder: 'Example: {"columnName": true, ...}',
|
||||
},
|
||||
],
|
||||
returnValues: [
|
||||
{
|
||||
id: 'data',
|
||||
|
||||
@@ -47,7 +47,6 @@ import API from 'Common/Utils/API';
|
||||
import Protocol from 'Common/Types/API/Protocol';
|
||||
import Route from 'Common/Types/API/Route';
|
||||
import URL from 'Common/Types/API/URL';
|
||||
import JSONFunctions from 'Common/Types/JSONFunctions';
|
||||
import ClusterKeyAuthorization from '../Middleware/ClusterKeyAuthorization';
|
||||
import Text from 'Common/Types/Text';
|
||||
|
||||
@@ -502,7 +501,7 @@ class DatabaseService<TBaseModel extends BaseModel> {
|
||||
}
|
||||
|
||||
public async onTrigger(
|
||||
model: TBaseModel,
|
||||
id: ObjectID,
|
||||
projectId: ObjectID,
|
||||
triggerType: DatabaseTriggerType
|
||||
): Promise<void> {
|
||||
@@ -517,7 +516,9 @@ class DatabaseService<TBaseModel extends BaseModel> {
|
||||
)
|
||||
),
|
||||
{
|
||||
data: JSONFunctions.toJSON(model, this.entityType),
|
||||
data: {
|
||||
_id: id.toString(),
|
||||
},
|
||||
},
|
||||
{
|
||||
...ClusterKeyAuthorization.getClusterKeyHeaders(),
|
||||
@@ -601,7 +602,7 @@ class DatabaseService<TBaseModel extends BaseModel> {
|
||||
)))
|
||||
) {
|
||||
await this.onTrigger(
|
||||
createBy.data,
|
||||
createBy.data.id!,
|
||||
createBy.props.tenantId ||
|
||||
createBy.data.getValue<ObjectID>(
|
||||
this.getModel().getTenantColumn()!
|
||||
@@ -937,7 +938,7 @@ class DatabaseService<TBaseModel extends BaseModel> {
|
||||
deleteBy.props.tenantId
|
||||
) {
|
||||
await this.onTrigger(
|
||||
item,
|
||||
item.id!,
|
||||
deleteBy.props.tenantId ||
|
||||
item.getValue<ObjectID>(
|
||||
this.getModel().getTenantColumn()!
|
||||
@@ -1213,7 +1214,7 @@ class DatabaseService<TBaseModel extends BaseModel> {
|
||||
))
|
||||
) {
|
||||
await this.onTrigger(
|
||||
item,
|
||||
item.id!,
|
||||
updateBy.props.tenantId ||
|
||||
item.getValue<ObjectID>(
|
||||
this.getModel().getTenantColumn()!
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import BaseModel from 'Common/Models/BaseModel';
|
||||
import BadDataException from 'Common/Types/Exception/BadDataException';
|
||||
import ObjectID from 'Common/Types/ObjectID';
|
||||
import ComponentMetadata from 'Common/Types/Workflow/Component';
|
||||
import ComponentMetadata, { Port } from 'Common/Types/Workflow/Component';
|
||||
import DatabaseService from '../../../../Services/DatabaseService';
|
||||
import { ExpressRequest, ExpressResponse } from '../../../../Utils/Express';
|
||||
import Response from '../../../../Utils/Response';
|
||||
@@ -12,6 +12,10 @@ import WorkflowService from '../../../../Services/WorkflowService';
|
||||
import LIMIT_MAX from 'Common/Types/Database/LimitMax';
|
||||
import Workflow from 'Model/Models/Workflow';
|
||||
import ClusterKeyAuthorization from '../../../../Middleware/ClusterKeyAuthorization';
|
||||
import { JSONObject } from 'Common/Types/JSON';
|
||||
import { RunOptions, RunReturnType } from '../../ComponentCode';
|
||||
import JSONFunctions from 'Common/Types/JSONFunctions';
|
||||
import Select from '../../../Database/Select';
|
||||
|
||||
export default class OnTriggerBaseModel<
|
||||
TBaseModel extends BaseModel
|
||||
@@ -19,12 +23,14 @@ export default class OnTriggerBaseModel<
|
||||
public modelId: string = '';
|
||||
public type: string = '';
|
||||
|
||||
public service: DatabaseService<TBaseModel> | null = null;
|
||||
|
||||
public constructor(
|
||||
modelService: DatabaseService<TBaseModel>,
|
||||
type: string
|
||||
) {
|
||||
super();
|
||||
|
||||
this.service = modelService;
|
||||
this.modelId = `${Text.pascalCaseToDashes(
|
||||
modelService.getModel().tableName!
|
||||
)}`;
|
||||
@@ -66,6 +72,80 @@ export default class OnTriggerBaseModel<
|
||||
);
|
||||
}
|
||||
|
||||
public override async run(
|
||||
args: JSONObject,
|
||||
options: RunOptions
|
||||
): Promise<RunReturnType> {
|
||||
const data: JSONObject = args['data'] as JSONObject;
|
||||
|
||||
const successPort: Port | undefined = this.getMetadata().outPorts.find(
|
||||
(p: Port) => {
|
||||
return p.id === 'success';
|
||||
}
|
||||
);
|
||||
|
||||
if (!successPort) {
|
||||
throw options.onError(
|
||||
new BadDataException('Success port not found')
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
!data['_id'] ||
|
||||
!args['select'] ||
|
||||
Object.keys(args['select']).length === 0
|
||||
) {
|
||||
return {
|
||||
returnValues: {
|
||||
model: data
|
||||
? JSONFunctions.toJSON(
|
||||
data as any,
|
||||
this.service!.entityType
|
||||
)
|
||||
: null,
|
||||
},
|
||||
executePort: successPort,
|
||||
};
|
||||
}
|
||||
|
||||
let select: Select<TBaseModel> = args['select'] as Select<TBaseModel>;
|
||||
|
||||
if (select) {
|
||||
select = JSONFunctions.deserialize(
|
||||
args['select'] as JSONObject
|
||||
) as Select<TBaseModel>;
|
||||
}
|
||||
|
||||
const model: TBaseModel | null = await this.service!.findOneById({
|
||||
id: new ObjectID(args['_id'] as string),
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
select: {
|
||||
_id: true,
|
||||
...select,
|
||||
},
|
||||
});
|
||||
|
||||
if (!model) {
|
||||
throw new BadDataException(
|
||||
('Model not found with id ' + args['_id']) as string
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
returnValues: {
|
||||
model: data
|
||||
? JSONFunctions.toJSON(
|
||||
model as any,
|
||||
this.service!.entityType
|
||||
)
|
||||
: null,
|
||||
},
|
||||
executePort: successPort,
|
||||
};
|
||||
}
|
||||
|
||||
public async initTrigger(
|
||||
req: ExpressRequest,
|
||||
res: ExpressResponse,
|
||||
@@ -95,6 +175,8 @@ export default class OnTriggerBaseModel<
|
||||
for (const workflow of workflows) {
|
||||
/// Run Graph.
|
||||
|
||||
/// Find the object and send data.
|
||||
|
||||
const executeWorkflow: ExecuteWorkflowType = {
|
||||
workflowId: workflow.id!,
|
||||
returnValues: {
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
import { JSONObject } from 'Common/Types/JSON';
|
||||
import ObjectID from 'Common/Types/ObjectID';
|
||||
import { ExpressRouter } from '../../Utils/Express';
|
||||
import ComponentCode from './ComponentCode';
|
||||
import ComponentCode, { RunOptions, RunReturnType } from './ComponentCode';
|
||||
import { Port } from 'Common/Types/Workflow/Component';
|
||||
import BadDataException from 'Common/Types/Exception/BadDataException';
|
||||
|
||||
export interface ExecuteWorkflowType {
|
||||
workflowId: ObjectID;
|
||||
@@ -44,6 +46,30 @@ export default class TrigegrCode extends ComponentCode {
|
||||
super();
|
||||
}
|
||||
|
||||
public override async run(
|
||||
args: JSONObject,
|
||||
options: RunOptions
|
||||
): Promise<RunReturnType> {
|
||||
const successPort: Port | undefined = this.getMetadata().outPorts.find(
|
||||
(p: Port) => {
|
||||
return p.id === 'success';
|
||||
}
|
||||
);
|
||||
|
||||
if (!successPort) {
|
||||
throw options.onError(
|
||||
new BadDataException('Success port not found')
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
returnValues: {
|
||||
...args,
|
||||
},
|
||||
executePort: successPort,
|
||||
};
|
||||
}
|
||||
|
||||
public async setupComponent(props: InitProps): Promise<void> {
|
||||
this.executeWorkflow = props.executeWorkflow;
|
||||
this.scheduleWorkflow = props.scheduleWorkflow;
|
||||
|
||||
@@ -74,6 +74,8 @@ const RunModal: FunctionComponent<ComponentProps> = (
|
||||
ComponentInputType.BaseModelArray ||
|
||||
args.type ===
|
||||
ComponentInputType.Query ||
|
||||
args.type ===
|
||||
ComponentInputType.Select ||
|
||||
args.type ===
|
||||
ComponentInputType.StringDictionary) &&
|
||||
component.returnValues[args.id] &&
|
||||
|
||||
@@ -80,6 +80,12 @@ export const componentInputTypeToFormFieldType: Function = (
|
||||
};
|
||||
}
|
||||
|
||||
if (componentInputType === ComponentInputType.Select) {
|
||||
return {
|
||||
fieldType: FormFieldSchemaType.JSON,
|
||||
};
|
||||
}
|
||||
|
||||
if (componentInputType === ComponentInputType.StringDictionary) {
|
||||
return {
|
||||
fieldType: FormFieldSchemaType.JSON,
|
||||
|
||||
@@ -196,99 +196,70 @@ export default class RunWorkflow {
|
||||
);
|
||||
}
|
||||
|
||||
// execute this stack.
|
||||
// now actually run this component.
|
||||
|
||||
let args: JSONObject = this.getComponentArguments(
|
||||
storageMap,
|
||||
stackItem.node
|
||||
);
|
||||
|
||||
if (stackItem.node.componentType === ComponentType.Trigger) {
|
||||
// this is already executed. So, place its arguments inside of storage map.
|
||||
storageMap.local.components[stackItem.node.id] = {
|
||||
returnValues: runProps.arguments,
|
||||
// If this is the trigger. Then pass workflow argument to this component as args to execute.
|
||||
args = {
|
||||
...args,
|
||||
...runProps.arguments,
|
||||
};
|
||||
}
|
||||
|
||||
this.log('Trigger args:');
|
||||
this.log(runProps.arguments);
|
||||
this.log('Component Args:');
|
||||
this.log(args);
|
||||
this.log('Component Logs: ' + executeComponentId);
|
||||
|
||||
// need port to be executed.
|
||||
const nodesToBeExecuted: Array<string> | undefined =
|
||||
Object.keys(stackItem.outPorts)
|
||||
.map((outport: string) => {
|
||||
return stackItem.outPorts[outport] || [];
|
||||
})
|
||||
.flat();
|
||||
const result: RunReturnType = await this.runComponent(
|
||||
args,
|
||||
stackItem.node,
|
||||
setDidErrorOut
|
||||
);
|
||||
|
||||
if (nodesToBeExecuted && nodesToBeExecuted.length > 0) {
|
||||
nodesToBeExecuted.forEach((item: string) => {
|
||||
// if its not in the stack, then add it to execution stack.
|
||||
if (
|
||||
!fifoStackOfComponentsPendingExecution.includes(
|
||||
item
|
||||
)
|
||||
) {
|
||||
fifoStackOfComponentsPendingExecution.push(
|
||||
item
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// now actually run this component.
|
||||
|
||||
const args: JSONObject = this.getComponentArguments(
|
||||
storageMap,
|
||||
stackItem.node
|
||||
if (didWorkflowErrorOut) {
|
||||
throw new BadDataException(
|
||||
'Workflow stopped because of an error'
|
||||
);
|
||||
}
|
||||
|
||||
this.log('Component Args:');
|
||||
this.log(args);
|
||||
this.log('Component Logs: ' + executeComponentId);
|
||||
const result: RunReturnType = await this.runComponent(
|
||||
args,
|
||||
stackItem.node,
|
||||
setDidErrorOut
|
||||
);
|
||||
this.log(
|
||||
'Completed Execution Component: ' + executeComponentId
|
||||
);
|
||||
this.log('Data Returned');
|
||||
this.log(result.returnValues);
|
||||
this.log(
|
||||
'Executing Port: ' + result.executePort?.title || '<None>'
|
||||
);
|
||||
|
||||
if (didWorkflowErrorOut) {
|
||||
throw new BadDataException(
|
||||
'Workflow stopped because of an error'
|
||||
);
|
||||
}
|
||||
storageMap.local.components[stackItem.node.id] = {
|
||||
returnValues: result.returnValues,
|
||||
};
|
||||
|
||||
this.log(
|
||||
'Completed Execution Component: ' + executeComponentId
|
||||
);
|
||||
this.log('Data Returned');
|
||||
this.log(result.returnValues);
|
||||
this.log(
|
||||
'Executing Port: ' + result.executePort?.title ||
|
||||
'<None>'
|
||||
);
|
||||
const portToBeExecuted: Port | undefined = result.executePort;
|
||||
|
||||
storageMap.local.components[stackItem.node.id] = {
|
||||
returnValues: result.returnValues,
|
||||
};
|
||||
if (!portToBeExecuted) {
|
||||
break; // stop the workflow, the process has ended.
|
||||
}
|
||||
|
||||
const portToBeExecuted: Port | undefined =
|
||||
result.executePort;
|
||||
const nodesToBeExecuted: Array<string> | undefined =
|
||||
stackItem.outPorts[portToBeExecuted.id];
|
||||
|
||||
if (!portToBeExecuted) {
|
||||
break; // stop the workflow, the process has ended.
|
||||
}
|
||||
|
||||
const nodesToBeExecuted: Array<string> | undefined =
|
||||
stackItem.outPorts[portToBeExecuted.id];
|
||||
|
||||
if (nodesToBeExecuted && nodesToBeExecuted.length > 0) {
|
||||
nodesToBeExecuted.forEach((item: string) => {
|
||||
// if its not in the stack, then add it to execution stack.
|
||||
if (
|
||||
!fifoStackOfComponentsPendingExecution.includes(
|
||||
item
|
||||
)
|
||||
) {
|
||||
fifoStackOfComponentsPendingExecution.push(
|
||||
item
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (nodesToBeExecuted && nodesToBeExecuted.length > 0) {
|
||||
nodesToBeExecuted.forEach((item: string) => {
|
||||
// if its not in the stack, then add it to execution stack.
|
||||
if (
|
||||
!fifoStackOfComponentsPendingExecution.includes(
|
||||
item
|
||||
)
|
||||
) {
|
||||
fifoStackOfComponentsPendingExecution.push(item);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,7 +279,7 @@ export default class RunWorkflow {
|
||||
});
|
||||
} catch (err: any) {
|
||||
logger.error(err);
|
||||
this.log(err.toString());
|
||||
this.log(err.message || err.toString());
|
||||
|
||||
if (!runProps.workflowLogId) {
|
||||
return;
|
||||
@@ -473,6 +444,26 @@ export default class RunWorkflow {
|
||||
argumentContent = argumentContentCopy;
|
||||
}
|
||||
|
||||
if (
|
||||
typeof argumentContent === 'string' &&
|
||||
(argument.type === ComponentInputType.JSON ||
|
||||
argument.type === ComponentInputType.Query ||
|
||||
argument.type === ComponentInputType.Select)
|
||||
) {
|
||||
try {
|
||||
argumentContent = JSON.parse(argumentContent);
|
||||
} catch (err: any) {
|
||||
throw new BadDataException(
|
||||
'Invalid JSON provided for argument ' +
|
||||
argument.id +
|
||||
'. JSON parse error: ' +
|
||||
err.message +
|
||||
'. JSON: ' +
|
||||
argumentContent
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
argumentObj[argument.id] = argumentContent;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user