Move activity properties to bottom panel

This commit is contained in:
Sipke Schoorstra 2022-06-27 15:12:37 +02:00
parent 5d82cca4d3
commit aff6446a28
8 changed files with 68 additions and 86 deletions

View file

@ -788,7 +788,6 @@ declare namespace LocalJSX {
"expand"?: boolean;
"headerText"?: string;
"onCollapsed"?: (event: CustomEvent<any>) => void;
"onSubmitted"?: (event: CustomEvent<FormData>) => void;
"selectedTab"?: TabDefinition;
"tabs"?: Array<TabDefinition>;
}

View file

@ -55,13 +55,13 @@ export class FormPanel {
</div>
</div>
<div class="border-b border-gray-200">
<nav class="-mb-px flex" aria-label="Tabs">
<div class="border-b border-gray-200 pl-4">
<nav class="-mb-px flex justify-start space-x-5" aria-label="Tabs">
{tabs.map((tab, tabIndex) => {
const cssClass = tabIndex == selectedTabIndex ? 'border-blue-500 text-blue-600' : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300';
return <a href="#"
onClick={e => this.onTabClick(e, tab)}
class={`${cssClass} py-4 px-1 text-center border-b-2 font-medium text-sm flex-1`}>
class={`${cssClass} py-4 px-1 text-center border-b-2 font-medium text-sm`}>
{tab.displayText}
</a>
})}
@ -81,34 +81,35 @@ export class FormPanel {
</div>
</div>
<div class="flex-shrink-0 px-4 border-t border-gray-200 py-5 sm:px-6">
<div class="space-x-3 flex justify-end">
{actions.map(action => {
{actions.length > 0 ? (
<div class="flex-shrink-0 px-4 border-t border-gray-200 py-5 sm:px-6">
<div class="space-x-3 flex justify-end">
{actions.map(action => {
if (action.display)
return action.display(action);
if (action.display)
return action.display(action);
const cssClass = action.isPrimary
? 'text-white bg-blue-600 hover:bg-blue-700 border-transparent focus:ring-blue-500'
: action.isDangerous ? 'text-white bg-red-600 hover:bg-red-700 border-transparent focus:ring-red-500'
: 'bg-white border-gray-300 text-gray-700 hover:bg-gray-50 focus:ring-blue-500';
const cssClass = action.isPrimary
? 'text-white bg-blue-600 hover:bg-blue-700 border-transparent focus:ring-blue-500'
: action.isDangerous ? 'text-white bg-red-600 hover:bg-red-700 border-transparent focus:ring-red-500'
: 'bg-white border-gray-300 text-gray-700 hover:bg-gray-50 focus:ring-blue-500';
const buttonType = action.type == ActionType.Submit ? 'submit' : 'button';
const buttonType = action.type == ActionType.Submit ? 'submit' : 'button';
const cancelHandler = () => {
};
const cancelHandler = () => {
};
const defaultHandler = (e: any, action: ActionDefinition) => this.actionInvoked.emit({action: action});
const clickHandler = !!action.onClick ? action.onClick : action.type == ActionType.Cancel ? cancelHandler : defaultHandler;
const defaultHandler = (e: any, action: ActionDefinition) => this.actionInvoked.emit({action: action});
const clickHandler = !!action.onClick ? action.onClick : action.type == ActionType.Cancel ? cancelHandler : defaultHandler;
return <button type={buttonType}
onClick={e => clickHandler(e, action)}
class={`${cssClass} py-2 px-4 border rounded-md shadow-sm text-sm font-medium focus:outline-none focus:ring-2 focus:ring-offset-2`}>
{action.text}
</button>
})}
</div>
</div>
return <button type={buttonType}
onClick={e => clickHandler(e, action)}
class={`${cssClass} py-2 px-4 border rounded-md shadow-sm text-sm font-medium focus:outline-none focus:ring-2 focus:ring-offset-2`}>
{action.text}
</button>
})}
</div>
</div>) : undefined}
</form>
</div>
);

View file

@ -35,7 +35,7 @@ export class InputControlSwitch {
@Prop() defaultSyntax: string = SyntaxNames.Literal;
@Prop() supportedSyntaxes: Array<string> = ['JavaScript', 'Liquid']; // TODO: Get available syntaxes from some more centralized settings.
@Prop() isReadOnly?: boolean;
@Prop() codeEditorHeight: string = '10em';
@Prop() codeEditorHeight: string = '16em';
@Prop() codeEditorSingleLineMode: boolean = false;
@Prop() context?: IntellisenseContext;

View file

@ -13,10 +13,7 @@ export class SlideOverPanel {
@Prop({mutable: true}) public selectedTab?: TabDefinition;
@Prop() public actions: Array<ActionDefinition> = [];
@Prop() public expand: boolean;
@Event() public collapsed: EventEmitter;
@Event() public submitted: EventEmitter<FormData>;
@Method()
public async show(): Promise<void> {
@ -58,11 +55,6 @@ export class SlideOverPanel {
// Hide panel.
await this.hide();
// Raise Form Submitted event to apply changes.
const formData = new FormData(this.formElement);
this.submitted.emit(formData);
};
private onTransitionEnd = (e: TransitionEvent) => {
@ -78,12 +70,6 @@ export class SlideOverPanel {
this.selectedTab = tab;
}
private onSubmit(e: Event) {
e.preventDefault();
const formData = new FormData(e.target as HTMLFormElement);
this.submitted.emit(formData);
}
private renderPanel() {
const isVisible = this.isVisible;
const isHiding = this.isHiding;
@ -108,7 +94,7 @@ export class SlideOverPanel {
<div class="fixed inset-y-0 right-0 pl-10 max-w-full flex sm:pl-16">
<div class={`w-screen ease-in-out duration-200 ${panelClass}`}>
<form class="h-full flex flex-col bg-white shadow-xl" onSubmit={e => this.onSubmit(e)}
<form class="h-full flex flex-col bg-white shadow-xl"
ref={el => this.formElement = el} method="post">
<div class="flex flex-col flex-1">

View file

@ -130,7 +130,7 @@ export class ActivityPropertiesEditor {
if (selectedTabIndex < 0)
selectedTabIndex = 0;
const actions = [DefaultActions.Delete(this.onDeleteActivity)];
const actions = []; // [DefaultActions.Delete(this.onDeleteActivity)];
const mainTitle = activity.id;
const subTitle = activityDescriptor.displayName;

View file

@ -1,22 +1,10 @@
import {Component, h, Listen, Prop, State, Event, EventEmitter, Method, Watch, Element} from '@stencil/core';
import {debounce, camelCase} from 'lodash';
import {Component, Element, Event, EventEmitter, h, Listen, Method, Prop, State, Watch} from '@stencil/core';
import {camelCase, debounce} from 'lodash';
import {Container} from "typedi";
import {PanelPosition, PanelStateChangedArgs} from '../panel/models';
import {
Activity,
ActivityDescriptor,
ActivitySelectedArgs, ChildActivitySelectedArgs,
ContainerSelectedArgs,
EditChildActivityArgs,
GraphUpdatedArgs,
WorkflowDefinition
} from '../../../models';
import {
ActivityIdUpdatedArgs,
ActivityUpdatedArgs,
DeleteActivityRequestedArgs
} from './activity-properties-editor';
import {PluginRegistry, ActivityNameFormatter, ActivityDriverRegistry, EventBus, findActivity, walkActivities, flattenList, flatten, ActivityNode, createActivityMap} from '../../../services';
import {Activity, ActivityDescriptor, ActivitySelectedArgs, ChildActivitySelectedArgs, ContainerSelectedArgs, EditChildActivityArgs, GraphUpdatedArgs, WorkflowDefinition} from '../../../models';
import {ActivityIdUpdatedArgs, ActivityUpdatedArgs, DeleteActivityRequestedArgs} from './activity-properties-editor';
import {ActivityDriverRegistry, ActivityNameFormatter, createActivityMap, EventBus, flatten, flattenList, PluginRegistry, walkActivities} from '../../../services';
import {MonacoEditorSettings} from "../../../services/monaco-editor-settings";
import {Flowchart} from "../../activities/flowchart/models";
import {ActivityPropertyChangedEventArgs, WorkflowDefinitionPropsUpdatedArgs, WorkflowDefinitionUpdatedArgs, WorkflowEditorEventTypes} from "./models";
@ -76,13 +64,13 @@ export class WorkflowDefinitionEditor {
}
@Listen('collapsed')
private async handlePanelCollapsed() {
this.selectedActivity = null;
private async handlePanelCollapsed(e: CustomEvent) {
//this.selectedActivity = null;
}
@Listen('containerSelected')
private async handleContainerSelected(e: CustomEvent<ContainerSelectedArgs>) {
this.selectedActivity = null;
this.selectedActivity = this.getCurrentContainer();
}
@Listen('activitySelected')
@ -134,7 +122,7 @@ export class WorkflowDefinitionEditor {
await this.canvas.importGraph(childActivity);
}
this.selectedActivity = null;
this.selectedActivity = this.getCurrentContainer();
}
@Method()
@ -166,8 +154,10 @@ export class WorkflowDefinitionEditor {
this.workflowDefinitionState = workflowDefinition;
this.nodeMap = createActivityMap(flatten(walkActivities(workflowDefinition.root)));
if (this.currentWorkflowPath.length == 0)
if (this.currentWorkflowPath.length == 0) {
this.currentWorkflowPath = [{activityId: workflowDefinition.root.id, portName: null}];
this.selectedActivity = this.getCurrentContainer();
}
}
@Method()
@ -242,18 +232,22 @@ export class WorkflowDefinitionEditor {
<elsa-panel
class="elsa-workflow-editor-container"
position={PanelPosition.Right}
onExpandedStateChanged={e => this.onActivityEditorPanelStateChanged(e.detail)}>
onExpandedStateChanged={e => this.onWorkflowEditorPanelStateChanged(e.detail)}>
<div class="object-editor-container">
{this.renderSelectedObject()}
<elsa-workflow-definition-properties-editor
workflowDefinition={this.workflowDefinitionState}
onWorkflowPropsUpdated={e => this.onWorkflowPropsUpdated(e)}
/>
</div>
</elsa-panel>
<elsa-panel
class="elsa-activity-editor-container"
position={PanelPosition.Bottom}
onExpandedStateChanged={e => this.onActivityEditorPanelStateChanged(e.detail)}>
<div class="activity-editor-container">
</div>
</elsa-panel>
class="elsa-activity-editor-container"
position={PanelPosition.Bottom}
onExpandedStateChanged={e => this.onActivityEditorPanelStateChanged(e.detail)}>
<div class="activity-editor-container">
{this.renderSelectedObject()}
</div>
</elsa-panel>
</div>
</WorkflowEditorTunnel.Provider>
);
@ -266,12 +260,7 @@ export class WorkflowDefinitionEditor {
variables={this.workflowDefinitionState.variables}
onActivityUpdated={e => this.onActivityUpdated(e)}
onActivityIdUpdated={e => this.onActivityIdUpdated(e)}
onDeleteActivityRequested={e => this.onDeleteActivityRequested(e)}/>
return <elsa-workflow-definition-properties-editor
workflowDefinition={this.workflowDefinitionState}
onWorkflowPropsUpdated={e => this.onWorkflowPropsUpdated(e)}
/>;
onDeleteActivityRequested={e => this.onDeleteActivityRequested(e)}/>;
}
private getWorkflowDefinitionInternal = async (): Promise<WorkflowDefinition> => {
@ -338,6 +327,15 @@ export class WorkflowDefinitionEditor {
return newName;
};
private getCurrentContainer = (): Activity => {
const currentItem = this.currentWorkflowPath.length > 0 ? this.currentWorkflowPath[this.currentWorkflowPath.length - 1] : null;
if (!currentItem)
return this.workflowDefinitionState.root;
return this.nodeMap[currentItem.activityId];
};
private onActivityPickerPanelStateChanged = async (e: PanelStateChangedArgs) => await this.updateContainerLayout('activity-picker-closed', e.expanded)
private onWorkflowEditorPanelStateChanged = async (e: PanelStateChangedArgs) => await this.updateContainerLayout('object-editor-closed', e.expanded)
private onActivityEditorPanelStateChanged = async (e: PanelStateChangedArgs) => await this.updateContainerLayout('activity-editor-closed', e.expanded)
@ -351,15 +349,14 @@ export class WorkflowDefinitionEditor {
const activityDescriptor: ActivityDescriptor = JSON.parse(json);
const newName = await this.generateUniqueActivityName(activityDescriptor);
const newActivity: Activity = {
// Make sure the node hash is up to date so that it can be found by the activity template.
this.nodeMap[newName] = {
id: newName,
typeName: activityDescriptor.activityType,
metadata: {},
applicationProperties: {}
};
this.nodeMap[newName] = newActivity;
await this.canvas.addActivity({
descriptor: activityDescriptor,
id: newName,
@ -391,12 +388,11 @@ export class WorkflowDefinitionEditor {
this.currentWorkflowPath = [...workflowPath];
}
private onWorkflowPropsUpdated = (e: CustomEvent<WorkflowDefinitionPropsUpdatedArgs>) => this.saveChangesDebounced()
private onDeleteActivityRequested = (e: CustomEvent<DeleteActivityRequestedArgs>) => {
this.deleteActivity(e.detail.activity);
this.selectedActivity = null;
this.selectedActivity = this.getCurrentContainer();
};
private onNavigateHierarchy = async (e: CustomEvent<WorkflowNavigationItem>) => {

View file

@ -1,7 +1,7 @@
.monaco-editor-host {
display: block;
position: relative;
min-height: 6em;
min-height: 12em;
}
.monaco-editor-container {

View file

@ -23,7 +23,7 @@ export class MonacoEditor {
private editor: any;
@Prop() public monacoLibPath?: string;
@Prop() public editorHeight: string = '5em';
@Prop() public editorHeight: string = '10em';
@Prop() public value: string;
@Prop() public language: string;
@Prop() public singleLineMode: boolean = false;