PR change requests

This commit is contained in:
axeleron007 2021-09-30 12:00:44 +03:00
parent 80ce9995a8
commit f203e0cdef
10 changed files with 144 additions and 90 deletions

View file

@ -75,10 +75,12 @@ namespace Elsa.Activities.Http.Middleware
return;
}
var isTest = pendingWorkflowInstance.GetMetadata("isTest");
var workflowBlueprint = (isTest != null && Convert.ToBoolean(isTest)) ?
await workflowRegistry.FindAsync(x => x.Id == pendingWorkflowInstance.DefinitionId, cancellationToken) :
await workflowRegistry.FindAsync(x => x.IsPublished && x.Id == pendingWorkflowInstance.DefinitionId && !x.IsDisabled, cancellationToken);
//var isTest = pendingWorkflowInstance.GetMetadata("isTest");
//var workflowBlueprint = (isTest != null && Convert.ToBoolean(isTest)) ?
// await workflowRegistry.FindAsync(x => x.Id == pendingWorkflowInstance.DefinitionId, cancellationToken) :
// await workflowRegistry.FindAsync(x => x.IsPublished && x.Id == pendingWorkflowInstance.DefinitionId && !x.IsDisabled, cancellationToken);
var workflowBlueprint = await workflowRegistry.FindActiveAsync(x => x.Id == pendingWorkflowInstance.DefinitionId && !x.IsDisabled, cancellationToken);
if (workflowBlueprint is null)
{

View file

@ -36,5 +36,10 @@ namespace Elsa.Services
/// Returns a single workflow blueprint that fits the specified predicate.
/// </summary>
Task<IWorkflowBlueprint?> FindAsync(Func<IWorkflowBlueprint, bool> predicate, CancellationToken cancellationToken = default);
/// <summary>
/// Returns a single workflow blueprint that fits the specified predicate.
/// </summary>
Task<IWorkflowBlueprint?> FindActiveAsync(Func<IWorkflowBlueprint, bool> predicate, CancellationToken cancellationToken = default);
}
}

View file

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
@ -55,6 +55,12 @@ namespace Elsa.Decorators
return workflows.FirstOrDefault(predicate);
}
public async Task<IWorkflowBlueprint?> FindActiveAsync(Func<IWorkflowBlueprint, bool> predicate, CancellationToken cancellationToken)
{
var workflows = await ListActiveAsync(cancellationToken);
return workflows.FirstOrDefault(predicate);
}
private async Task<ICollection<IWorkflowBlueprint>> ListInternalAsync(CancellationToken cancellationToken)
{
return await _memoryCache.GetOrCreateAsync(CacheKey, async entry =>

View file

@ -44,6 +44,9 @@ namespace Elsa.Services.Workflows
public async Task<IWorkflowBlueprint?> FindAsync(Func<IWorkflowBlueprint, bool> predicate, CancellationToken cancellationToken) =>
(await ListAsync(cancellationToken).Where(predicate).OrderByDescending(x => x.Version)).FirstOrDefault();
public async Task<IWorkflowBlueprint?> FindActiveAsync(Func<IWorkflowBlueprint, bool> predicate, CancellationToken cancellationToken) =>
(await ListActiveAsync(cancellationToken).Where(predicate).OrderByDescending(x => x.Version)).FirstOrDefault();
private async IAsyncEnumerable<IWorkflowBlueprint> ListActiveInternalAsync([EnumeratorCancellation] CancellationToken cancellationToken)
{
var workflows = await ListAsync(cancellationToken);

View file

@ -1,9 +1,8 @@
import {Component, h, Prop, State} from '@stencil/core';
import {ActivityDefinitionProperty, ActivityPropertyDescriptor} from "../../../../models";
import {createElsaClient} from "../../../../services";
import {ActivityDefinitionProperty, ActivityPropertyDescriptor, ActivityValidatingContext, EventTypes} from "../../../../models";
import {createElsaClient, eventBus} from "../../../../services";
import Tunnel from '../../../../data/workflow-editor';
import {MonacoValueChangedArgs} from "../../../controls/elsa-monaco/elsa-monaco";
import Ajv from "ajv"
@Component({
tag: 'elsa-script-property',
@ -19,9 +18,10 @@ export class ElsaScriptProperty {
@Prop() syntax?: string;
@Prop({mutable: true}) serverUrl: string;
@Prop({mutable: true}) workflowDefinitionId: string;
@State() currentValue?: string
@State() isJsonSchemaValid?: boolean;
@State() currentValue?: string;
monacoEditor: HTMLElsaMonacoElement;
private activityValidatingContext: ActivityValidatingContext = null;
async componentWillLoad() {
this.currentValue = this.propertyModel.expressions['Literal'];
@ -49,47 +49,24 @@ export class ElsaScriptProperty {
onConvertToJsonSchemaClick(e: Event) {
e.preventDefault();
window.open('https://extendsclass.com/json-schema-validator.html');
window.open('https://www.convertsimple.com/convert-json-to-json-schema/');
}
onMonacoValueChanged(e: MonacoValueChangedArgs) {
this.currentValue = e.value;
this.validate(e.value);
this.validate(this.currentValue);
}
validate(value: string) {
const propertyDescriptor = this.propertyDescriptor;
const propertyName = propertyDescriptor.name;
const fieldName = propertyName;
if (fieldName === "Schema")
{
this.isJsonSchemaValid = true;
if (value == '') return;
const ajv = new Ajv();
let json: object;
try{
json = JSON.parse(value)
}
catch (e){
this.isJsonSchemaValid = false;
}
if (json != undefined)
{
try {
const validate = ajv.compile(json);
const errors = validate.errors;
if (errors != null)
this.isJsonSchemaValid = false;
}
catch (e){
const err = e;
this.isJsonSchemaValid = false;
}
}
}
this.activityValidatingContext = {
activityType: this.context,
prop: this.propertyDescriptor.name,
value: value,
data: null,
isValidated: false,
isPositiveResult: false
};
eventBus.emit(EventTypes.ActivityPluginValidating, this, this.activityValidatingContext);
}
render() {
@ -104,6 +81,22 @@ export class ElsaScriptProperty {
const value = this.currentValue;
const isSchema = fieldName === "Schema";
const renderValidationResult = () => {
if (this.activityValidatingContext == null || !this.activityValidatingContext.isValidated)
return;
const isPositiveResult = this.activityValidatingContext.isPositiveResult;
const color = isPositiveResult ? 'green' : 'red';
return (
<div class="elsa-mt-3">
<p class={`elsa-mt-1 elsa-text-sm elsa-text-${color}-500`}>
{this.activityValidatingContext.data}
</p>
</div>
)
}
return <div>
<div class="elsa-flex">
@ -133,18 +126,10 @@ export class ElsaScriptProperty {
ref={el => this.monacoEditor = el}/>
</div>
{fieldHint ? <p class="elsa-mt-2 elsa-text-sm elsa-text-gray-500">{fieldHint}</p> : undefined}
{this.isJsonSchemaValid == undefined ? undefined : this.isJsonSchemaValid ?
<p class="elsa-mt-1 elsa-text-sm elsa-text-green-500">
Json is valid
</p>
:
<p class="elsa-mt-1 elsa-text-sm elsa-text-red-500">
Json is invalid
</p>
}
<input type="hidden" name={fieldName} value={value}/>
{renderValidationResult()}
{isSchema ?
<div class="elsa-mt-1">
<div class="elsa-mt-3">
<a href="#"
onClick={e => this.onConvertToJsonSchemaClick(e)}
class="elsa-relative elsa-inline-flex elsa-items-center elsa-px-4 elsa-py-2 elsa-border elsa-border-gray-300 elsa-text-sm elsa-leading-5 elsa-font-medium elsa-rounded-md elsa-text-gray-700 elsa-bg-white hover:elsa-text-gray-500 focus:elsa-outline-none focus:elsa-shadow-outline-blue focus:elsa-border-blue-300 active:elsa-bg-gray-100 active:elsa-text-gray-700 elsa-transition elsa-ease-in-out elsa-duration-150">

View file

@ -4,16 +4,15 @@ import {
ActivityDefinition,
ActivityDescriptor,
ActivityModel,
ActivityUpdatedContext,
ConnectionDefinition,
ConnectionModel,
EventTypes,
SyntaxNames,
VersionOptions,
WorkflowDefinition,
WorkflowModel,
WorkflowPersistenceBehavior,
WorkflowTestActivityMessage,
WorkflowTestUpdateHttpEndpoint
WorkflowTestActivityMessage
} from "../../../../models";
import {createElsaClient, eventBus, SaveWorkflowDefinitionRequest} from "../../../../services";
import state from '../../../../utils/store';
@ -447,18 +446,7 @@ export class ElsaWorkflowDefinitionEditorScreen {
this.workflowTestActivityMessages = [];
this.render();
};
async updateHttpEndpointJsonSchema(request: WorkflowTestUpdateHttpEndpoint) {
let workflowModel = {...this.workflowModel};
const activity = workflowModel.activities.find(x => x.activityId == request.activityId);
if (activity)
{
const activityModel = activity.properties.find(x => x.name == 'Schema');
activityModel.expressions[SyntaxNames.Literal] = request.jsonSchema;
eventBus.emit(EventTypes.UpdateActivity, this, activityModel);
}
};
};
private onUpdateWorkflowSettings = async (workflowDefinition: WorkflowDefinition) => {
this.updateWorkflowDefinition(workflowDefinition);
@ -588,12 +576,14 @@ export class ElsaWorkflowDefinitionEditorScreen {
async onUseAsSchemaClick(message: WorkflowTestActivityMessage) {
const value = message.data["Body"];
const request: WorkflowTestUpdateHttpEndpoint = {
activityId: message.activityId,
jsonSchema: JSON.stringify(convert(value), null, 1)
};
let workflowModel = {...this.workflowModel};
const activityModel = workflowModel.activities.find(x => x.activityId == message.activityId);
await this.updateHttpEndpointJsonSchema(request);
const context: ActivityUpdatedContext = {
activityModel: activityModel,
data: JSON.stringify(convert(value), null, 1)
};
eventBus.emit(EventTypes.ActivityPluginUpdated, this, context);
}
renderTestActivityMenu = () => {

View file

@ -334,11 +334,6 @@ export interface WorkflowTestActivityMessage {
error?: string;
}
export interface WorkflowTestUpdateHttpEndpoint {
activityId?: string,
jsonSchema?: string
}
export const getVersionOptionsString = (versionOptions?: VersionOptions) => {
if (!versionOptions)

View file

@ -15,6 +15,8 @@ export const EventTypes = {
WorkflowModelChanged: 'workflow-model-changed',
ActivityDesignDisplaying: 'activity-design-displaying',
ActivityDescriptorDisplaying: 'activity-descriptor-displaying',
ActivityPluginUpdated: 'activity-plugin-updated',
ActivityPluginValidating: 'activity-plugin-validating',
WorkflowPublished: 'workflow-published',
WorkflowRetracted: 'workflow-retracted',
WorkflowImported: 'workflow-imported',
@ -57,6 +59,20 @@ export interface ActivityDesignDisplayContext {
outcomes: Array<string>;
}
export interface ActivityUpdatedContext {
activityModel: ActivityModel,
data?: string
}
export interface ActivityValidatingContext {
activityType: string
prop: string,
value?: string,
isValidated: boolean,
data: any,
isPositiveResult: boolean
}
export interface ActivityDescriptorDisplayContext {
activityDescriptor: ActivityDescriptor;
activityIcon: any;

View file

@ -1,11 +1,13 @@
import {eventBus, ElsaPlugin} from "../services";
import {ActivityDesignDisplayContext, EventTypes, SyntaxNames} from "../models";
import {h} from "@stencil/core";
import {ActivityDesignDisplayContext, ActivityUpdatedContext, ActivityValidatingContext, EventTypes, SyntaxNames} from "../models";
import {htmlEncode} from "../utils/utils";
import Ajv from "ajv"
export class HttpEndpointPlugin implements ElsaPlugin {
constructor() {
eventBus.on(EventTypes.ActivityDesignDisplaying, this.onActivityDisplaying);
eventBus.on(EventTypes.ActivityPluginUpdated, this.onActivityUpdated);
eventBus.on(EventTypes.ActivityPluginValidating, this.onActivityValidating);
}
onActivityDisplaying(context: ActivityDesignDisplayContext) {
@ -20,4 +22,53 @@ export class HttpEndpointPlugin implements ElsaPlugin {
const bodyDisplay = htmlEncode(path.expressions[syntax]);
context.bodyDisplay = `<p>${bodyDisplay}</p>`;
}
onActivityUpdated(context: ActivityUpdatedContext) {
const activityModel = context.activityModel;
if (activityModel.type !== 'HttpEndpoint')
return;
const props = activityModel.properties || [];
const prop = props.find(x => x.name == 'Schema') || { name: 'Schema', expressions: { 'Literal': '', syntax: SyntaxNames.Literal } };
prop.expressions[SyntaxNames.Literal] = context.data;
eventBus.emit(EventTypes.UpdateActivity, this, prop);
}
onActivityValidating(context: ActivityValidatingContext) {
if (context.activityType !== 'HttpEndpoint' || context.prop !== 'Schema')
return;
const jsonSchema = context.value;
let isValid = true;
if (jsonSchema == '') return;
const ajv = new Ajv();
let json: object;
try{
json = JSON.parse(jsonSchema)
}
catch (e){
isValid = false;
}
if (json != undefined)
{
try {
const validate = ajv.compile(json);
const errors = validate.errors;
if (errors != null)
isValid = false;
}
catch (e){
const err = e;
isValid = false;
}
}
context.isValidated = true;
context.isPositiveResult = isValid;
context.data = isValid ? 'Json is valid' : 'Json is invalid';
}
}

View file

@ -1,5 +1,4 @@
using System;
using System.Linq;
using Elsa;
using Elsa.Models;
using Elsa.Server.Api;
@ -7,6 +6,7 @@ using Elsa.Server.Api.Handlers;
using Elsa.Server.Api.Mapping;
using Elsa.Server.Api.Services;
using Elsa.Server.Api.Swagger.Examples;
using Elsa.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
@ -48,14 +48,15 @@ namespace Microsoft.Extensions.DependencyInjection
options.AssumeDefaultVersionWhenUnspecified = true;
});
services.AddSingleton<ConnectionConverter>();
services.AddSingleton<ActivityBlueprintConverter>();
services.AddScoped<IWorkflowBlueprintMapper, WorkflowBlueprintMapper>();
services.AddScoped<IWorkflowTestService, WorkflowTestService>();
services.AddSingleton<IEndpointContentSerializerSettingsProvider, EndpointContentSerializerSettingsProvider>();
services.AddAutoMapperProfile<AutoMapperProfile>();
services.AddNotificationHandlersFrom<ActivityExecutionResultExecutedHandler>();
services.AddSignalR();
services
.AddSingleton<ConnectionConverter>()
.AddSingleton<ActivityBlueprintConverter>()
.AddScoped<IWorkflowBlueprintMapper, WorkflowBlueprintMapper>()
.AddScoped<IWorkflowTestService, WorkflowTestService>()
.AddSingleton<IEndpointContentSerializerSettingsProvider, EndpointContentSerializerSettingsProvider>()
.AddAutoMapperProfile<AutoMapperProfile>()
.AddNotificationHandlersFrom<ActivityExecutionResultExecutedHandler>()
.AddSignalR();
return services;
}