Skip to content

Commit

Permalink
feat(deploy-toolbar): add modal for deployment
Browse files Browse the repository at this point in the history
* add ModalConductor and modal related methods to App component
* add DeployDiagramModal to handle diagram deployment
* connect BPMN and DMN editors to deployment feature
  • Loading branch information
barmac committed Dec 3, 2018
1 parent dbc16a6 commit 5e84b82
Show file tree
Hide file tree
Showing 24 changed files with 594 additions and 13 deletions.
31 changes: 30 additions & 1 deletion client/src/app/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import Log from './Log';

import debug from 'debug';

import { ModalConductor } from './modals';

import {
Button,
DropdownButton,
Expand Down Expand Up @@ -57,7 +59,8 @@ const INITIAL_STATE = {
layout: {},
tabs: [],
tabState: {},
logEntries: []
logEntries: [],
currentModal: null
};


Expand Down Expand Up @@ -1095,10 +1098,19 @@ export class App extends Component {
return this.showDialog(options);
}

if (action === 'open-modal') {
return this.setModal(options);
}

if (action === 'close-modal') {
return this.setModal(null);
}

if (action === 'open-external-url') {
this.openExternalUrl(options);
}


const tab = this.tabRef.current;

return tab.triggerAction(action, options);
Expand All @@ -1108,6 +1120,16 @@ export class App extends Component {
this.props.globals.backend.send('external:open-url', options);
}

openModal = modal => this.triggerAction('open-modal', modal);

closeModal = () => this.triggerAction('close-modal');

setModal = currentModal => this.setState({ currentModal });

handleDeploy = options => {
return this.props.globals.backend.send('deploy', { ...options, file: this.state.activeTab.file });
};

quit() {
return true;
}
Expand Down Expand Up @@ -1244,6 +1266,7 @@ export class App extends Component {
onLayoutChanged={ this.handleLayoutChanged }
onContextMenu={ this.openTabMenu }
onAction={ this.triggerAction }
onModal={ this.openModal }
ref={ this.tabRef }
/>
}
Expand All @@ -1257,6 +1280,12 @@ export class App extends Component {
onClear={ this.clearLog }
/>
</SlotFillRoot>

<ModalConductor
currentModal={ this.state.currentModal }
onClose={ this.composeAction('close-modal') }
onDeploy={ this.handleDeploy }
/>
</div>
);
}
Expand Down
54 changes: 54 additions & 0 deletions client/src/app/__tests__/DeployDiagramModalSpec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/* global sinon */

import React from 'react';

import {
shallow
} from 'enzyme';

import { DeployDiagramModal } from '../deploy-diagram-modal';


describe('<DeployDiagramModal>', function() {

it('should render', function() {
shallow(<DeployDiagramModal />);
});


it('should set state.error to error message when onDeploy throws error', async function() {
// given
const errorMessage = 'error';

const onDeployStub = sinon.stub().throws({ message: errorMessage });

const wrapper = shallow(<DeployDiagramModal onDeploy={ onDeployStub } />);
const instance = wrapper.instance();

// when
await instance.handleDeploy(new Event('click'));

// expect
expect(instance.state.error).to.be.equal(errorMessage);
});


it('should set state.success to success message when onDeploy resolves', async function() {
// given
const endpointUrl = 'http://example.com';
const successMessage = `Successfully deployed diagram to ${endpointUrl}`;

const onDeployStub = sinon.stub().resolves();

const wrapper = shallow(<DeployDiagramModal onDeploy={ onDeployStub } />);
const instance = wrapper.instance();
instance.state.endpointUrl = endpointUrl;

// when
await instance.handleDeploy(new Event('click'));

// expect
expect(instance.state.success).to.be.equal(successMessage);
});

});
84 changes: 84 additions & 0 deletions client/src/app/deploy-diagram-modal/DeployDiagramModal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import React from 'react';

import View from './View';


const defaultState = {
isLoading: false,
success: '',
error: '',
endpointUrl: '',
tenantId: '',
deploymentName: ''
};

class DeployDiagramModal extends React.Component {
constructor() {
super();

this.state = defaultState;
}

handleDeploy = async (event) => {
event.preventDefault();

this.setState({
success: '',
error: '',
isLoading: true
});

const payload = this.getPayloadFromState();

try {
await this.props.onDeploy(payload);

this.setState({
isLoading: false,
success: `Successfully deployed diagram to ${payload.endpointUrl}`,
error: ''
});
} catch (error) {
this.setState({
isLoading: false,
success: '',
error: error.message
});
}
}

handleEndpointUrlChange = event => this.setState({ endpointUrl: event.target.value });

handleTenantIdChange = event => this.setState({ tenantId: event.target.value });

handleDeploymentNameChange = event => this.setState({ deploymentName: event.target.value });

render() {
return <View
onClose={ this.props.onClose }
onDeploy={ this.handleDeploy }
onEndpointUrlChange={ this.handleEndpointUrlChange }
onTenantIdChange={ this.handleTenantIdChange }
onDeploymentNameChange={ this.handleDeploymentNameChange }

isLoading={ this.state.isLoading }
success={ this.state.success }
error={ this.state.error }
endpointUrl={ this.state.endpointUrl }
tenantId={ this.state.tenantId }
deploymentName={ this.state.deploymentName }
/>;
}

getPayloadFromState() {
const payload = {
endpointUrl: this.state.endpointUrl,
deploymentName: this.state.deploymentName,
tenantId: this.state.tenantId
};

return payload;
}
}

export default DeployDiagramModal;
12 changes: 12 additions & 0 deletions client/src/app/deploy-diagram-modal/ErrorMessage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from 'react';

import css from './ErrorMessage.less';


const ErrorMessage = ({ message }) => (
<div className={ css.ErrorMessage }>
<strong>Error: </strong><span className={ css.ErrorContent }>{ message }</span>
</div>
);

export default ErrorMessage;
13 changes: 13 additions & 0 deletions client/src/app/deploy-diagram-modal/ErrorMessage.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
:local(.ErrorMessage) {
border: solid 1px;
border-radius: 4px;
padding: 8px 10px;

color: #721c24;
background-color: #f8d7da;
border-color: #f5c6cb;
}

:local(.ErrorContent) {
user-select: text;
}
7 changes: 7 additions & 0 deletions client/src/app/deploy-diagram-modal/Loading.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import React from 'react';

import { Loading as style } from './Loading.less';

import { Icon } from '../primitives';

export default () => <Icon name={ 'loading' } className={ style } />;
14 changes: 14 additions & 0 deletions client/src/app/deploy-diagram-modal/Loading.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
:local(.Loading) {
animation: spin 2s infinite linear;
display: inline-block;

@keyframes spin {
0% {
transform: rotate(0deg);
}

100% {
transform: rotate(359deg);
}
}
}
12 changes: 12 additions & 0 deletions client/src/app/deploy-diagram-modal/Success.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from 'react';

import css from './Success.less';


const Success = ({ message }) => (
<div className={ css.Success }>
<strong>Success: </strong><span className={ css.SuccessContent }>{ message }</span>
</div>
);

export default Success;
13 changes: 13 additions & 0 deletions client/src/app/deploy-diagram-modal/Success.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
:local(.Success) {
border: solid 1px;
border-radius: 4px;
padding: 8px 10px;

color: #155724;
background-color: #d4edda;
border-color: #c3e6cb;
}

:local(.SuccessContent) {
user-select: text;
}
Loading

0 comments on commit 5e84b82

Please sign in to comment.