diff --git a/backend/files/misc/workflows/actions/misc/execute-action-if.hl b/backend/files/misc/workflows/actions/misc/execute-action-if.hl
new file mode 100644
index 0000000000..6c93143af0
--- /dev/null
+++ b/backend/files/misc/workflows/actions/misc/execute-action-if.hl
@@ -0,0 +1,68 @@
+
+/*
+ * Executes the specified [action] if the specified [condition] is true.
+ *
+ * Will pass in all arguments specified to the action. The [condition] can be two different
+ * values or expressions, and the [comparison] can be eq, neq, mt, mte, lt, lte, or some other
+ * comparison operator.
+ *
+ * The action will use the [comparison] to compare the [lhs] and [rhs] values/expressions.
+ */
+.arguments
+ lhs
+ type:string
+ mandatory:bool:true
+ comparison
+ type:enum
+ mandatory:bool:true
+ values
+ .:eq
+ .:neq
+ .:mt
+ .:mte
+ .:lt
+ .:lte
+ rhs
+ type:string
+ mandatory:bool:true
+ action
+ type:action
+ mandatory:bool:true
+ arguments
+ type:key-value
+ mandatory:bool:false
+.icon:settings
+
+// Sanity checking invocation.
+validators.mandatory:x:@.arguments/*/action
+validators.mandatory:x:@.arguments/*/lhs
+validators.mandatory:x:@.arguments/*/rhs
+validators.mandatory:x:@.arguments/*/comparison
+
+// Making sure we use correct comparison operator.
+set-name:x:./*/if/*/comparison
+ get-value:x:@.arguments/*/comparison
+
+// Checking if [comparison] yields true.
+if
+ comparison
+ get-value:x:@.arguments/*/lhs
+ get-value:x:@.arguments/*/rhs
+ .lambda
+
+ // Parametrising [execute].
+ add:x:./*/execute/*/arguments
+ get-nodes:x:@.arguments/*/arguments/*
+
+ // Executing file.
+ execute:magic.workflows.actions.execute
+ name:_
+ filename:x:@.arguments/*/action
+ arguments
+
+ // Parametrising [return] invocation.
+ add:x:./*/return
+ get-nodes:x:@execute/*
+
+ // Returning result of execution to caller.
+ return
diff --git a/backend/files/misc/workflows/snippets/create-action.hl b/backend/files/misc/workflows/snippets/create-action.hl
index 87c69eb316..3a5e690976 100644
--- a/backend/files/misc/workflows/snippets/create-action.hl
+++ b/backend/files/misc/workflows/snippets/create-action.hl
@@ -12,7 +12,7 @@
/*
* Type of argument, can be; key-value, array, int, decimal, float, double, long,
- * email, string, enum, textarea, workflow, sql, csharp, hyperlambda or bool.
+ * email, string, enum, textarea, workflow, action, sql, csharp, hyperlambda or bool.
*/
type:string
diff --git a/frontend/src/app/components/protected/create/hyper-ide/components/parametrise-action-dialog/components/formly-action/formly-action.component.ts b/frontend/src/app/components/protected/create/hyper-ide/components/parametrise-action-dialog/components/formly-action/formly-action.component.ts
new file mode 100644
index 0000000000..aec76e4ae4
--- /dev/null
+++ b/frontend/src/app/components/protected/create/hyper-ide/components/parametrise-action-dialog/components/formly-action/formly-action.component.ts
@@ -0,0 +1,129 @@
+
+/*
+ * Copyright (c) 2023 Thomas Hansen - For license inquiries you can contact thomas@ainiro.io.
+ */
+
+// Angular and system imports.
+import { FieldType, FieldTypeConfig } from '@ngx-formly/core';
+import { Component, OnInit } from '@angular/core';
+import { Observable, map, startWith } from 'rxjs';
+
+// Application specific imports
+import { GeneralService } from 'src/app/services/general.service';
+import { WorkflowService } from 'src/app/services/workflow.service';
+import { MatAutocompleteActivatedEvent } from '@angular/material/autocomplete';
+
+/**
+ * Formly workflow extension field.
+ */
+@Component({
+ selector: 'app-formly-action',
+ template: `
+
+ {{field.props.label}}
+
+
+ {{option.label}}
+
+
+`,
+ styleUrls: ['./formly-action.scss']
+})
+export class FormlyActionComponent extends FieldType implements OnInit {
+
+ filteredOptions: Observable;
+
+ constructor(
+ private generalService: GeneralService,
+ private workflowService: WorkflowService) {
+
+ super();
+ }
+
+ ngOnInit() {
+
+ // Retrieving all workflows from backend.
+ this.generalService.showLoading();
+ this.workflowService.getWorkflowActions().subscribe({
+
+ next: (result: any[]) => {
+
+ this.generalService.hideLoading();
+
+ result = (result || []).filter(x => x.filename.indexOf('execute-workflow') === -1 && x.filename.indexOf('execute-action') === -1);
+
+ for (const idx of result) {
+ (this.field.props.options).push({
+ value: idx.filename,
+ label: idx.filename,
+ complete: true,
+ });
+ }
+ },
+
+ error: (error: any) => {
+
+ this.generalService.showFeedback(error?.error?.message ?? error, 'errorMessage');
+ this.generalService.hideLoading();
+ }
+ });
+
+ this.filteredOptions = this.formControl.valueChanges.pipe(
+ startWith(this.model[this.field.key]),
+ map(value => this._filter(value || '')),
+ );
+ this.formControl.setValue(this.field.model[this.field.key]);
+ this.formControl.valueChanges.subscribe((val: string) => {
+ this.model[this.field.key] = val;
+ });
+ }
+
+ optionSelected(e: MatAutocompleteActivatedEvent) {
+
+ // Verifying this is a filename reference.
+ this.generalService.showLoading();
+ if (e.option.value.startsWith('/') && e.option.value.endsWith('.hl')) {
+
+ // Retrieving arguments workflow file can handle.
+ this.workflowService.getArgumentsForFile(e.option.value).subscribe({
+
+ next: (result: any) => {
+
+ this.generalService.hideLoading();
+ this.props.change.call(this, result);
+ },
+
+ error: (error: any) => {
+
+ this.generalService.showFeedback(error?.error?.message ?? error, 'errorMessage');
+ this.generalService.hideLoading();
+ }
+ });
+ }
+ }
+
+ /*
+ * Private helper methods.
+ */
+
+ private _filter(value: string): any[] {
+
+ if (!value) {
+ return this.field.props.options;
+ }
+
+ const filterValue = value.toLowerCase();
+ return (this.field.props.options).filter(option => option.label.toLowerCase().includes(filterValue));
+ }
+}
diff --git a/frontend/src/app/components/protected/create/hyper-ide/components/parametrise-action-dialog/components/formly-action/formly-action.scss b/frontend/src/app/components/protected/create/hyper-ide/components/parametrise-action-dialog/components/formly-action/formly-action.scss
new file mode 100644
index 0000000000..048ea33ba1
--- /dev/null
+++ b/frontend/src/app/components/protected/create/hyper-ide/components/parametrise-action-dialog/components/formly-action/formly-action.scss
@@ -0,0 +1,9 @@
+
+mat-option.warning {
+ background-color: #fff0f0;
+}
+
+mat-option.warning:hover,
+mat-option.warning:active {
+ background-color: #f0e0e0;
+}
diff --git a/frontend/src/app/components/protected/create/hyper-ide/components/parametrise-action-dialog/parametrise-action-dialog.component.ts b/frontend/src/app/components/protected/create/hyper-ide/components/parametrise-action-dialog/parametrise-action-dialog.component.ts
index 7a2045b760..859f9a8271 100644
--- a/frontend/src/app/components/protected/create/hyper-ide/components/parametrise-action-dialog/parametrise-action-dialog.component.ts
+++ b/frontend/src/app/components/protected/create/hyper-ide/components/parametrise-action-dialog/parametrise-action-dialog.component.ts
@@ -110,11 +110,29 @@ export class ParametriseActionDialog implements OnInit {
case 'string':
case 'enum':
case 'textarea':
+ case 'action':
case 'workflow':
+
add = true;
- field.type = this.data.input[idx].type === 'textarea'
- ? 'autocomplete-textarea'
- : (this.data.input[idx].type === 'workflow' ? 'workflow' : 'autocomplete');
+
+ switch (this.data.input[idx].type) {
+
+ case 'textarea':
+ field.type = 'autocomplete-textarea';
+ break;
+
+ case 'workflow':
+ field.type = 'workflow';
+ break;
+
+ case 'action':
+ field.type = 'action';
+ break;
+
+ default:
+ field.type = 'autocomplete';
+ }
+
field.props.options = [];
if (this.data.input[idx].type === 'enum') {
for (let idxNo = 0; idxNo < this.data.input[idx].values.length; idxNo++) {
@@ -147,6 +165,17 @@ export class ParametriseActionDialog implements OnInit {
}
};
}
+ if (field.type === 'action') {
+ field.props.change = (args: any) => {
+ if (argumentsField) {
+ this.model.arguments = {};
+ for (const idx in args) {
+ this.model.arguments[idx] = 'CHANGE-THIS';
+ }
+ argumentsField.options.detectChanges();
+ }
+ };
+ }
break;
case 'sql':
diff --git a/frontend/src/app/components/protected/create/hyper-ide/module/ide.module.ts b/frontend/src/app/components/protected/create/hyper-ide/module/ide.module.ts
index 0d0b323807..6235f1cd26 100644
--- a/frontend/src/app/components/protected/create/hyper-ide/module/ide.module.ts
+++ b/frontend/src/app/components/protected/create/hyper-ide/module/ide.module.ts
@@ -37,6 +37,7 @@ import { FormlyAutocompleteComponent } from '../components/parametrise-action-di
import { FormlyAutocompleteTextareaComponent } from '../components/parametrise-action-dialog/components/formly-autocomplete-textarea/formly-autocomplete-textarea.component';
import { ExecuteFeedbackDialog } from '../components/execute-feedback-dialog/execute-feedback-dialog.component';
import { FormlyWorkflowComponent } from '../components/parametrise-action-dialog/components/formly-workflow/formly-workflow.component';
+import { FormlyActionComponent } from '../components/parametrise-action-dialog/components/formly-action/formly-action.component';
@NgModule({
declarations: [
@@ -57,6 +58,7 @@ import { FormlyWorkflowComponent } from '../components/parametrise-action-dialog
FormlyArrayComponent,
FormlyAutocompleteComponent,
FormlyWorkflowComponent,
+ FormlyActionComponent,
FormlyAutocompleteTextareaComponent,
CreateKeyValueDialogComponent,
CreateArrayDialogComponent,
@@ -80,6 +82,7 @@ import { FormlyWorkflowComponent } from '../components/parametrise-action-dialog
{ name: 'autocomplete', component: FormlyAutocompleteComponent },
{ name: 'autocomplete-textarea', component: FormlyAutocompleteTextareaComponent },
{ name: 'workflow', component: FormlyWorkflowComponent },
+ { name: 'action', component: FormlyActionComponent },
],
}),
],