summaryrefslogtreecommitdiffstats
path: root/openecomp-ui/src/sdc-app/flows
diff options
context:
space:
mode:
Diffstat (limited to 'openecomp-ui/src/sdc-app/flows')
-rw-r--r--openecomp-ui/src/sdc-app/flows/FlowsActions.js191
-rw-r--r--openecomp-ui/src/sdc-app/flows/FlowsConstants.js48
-rw-r--r--openecomp-ui/src/sdc-app/flows/FlowsEditorModal.js54
-rw-r--r--openecomp-ui/src/sdc-app/flows/FlowsEditorModalView.jsx40
-rw-r--r--openecomp-ui/src/sdc-app/flows/FlowsListEditor.js53
-rw-r--r--openecomp-ui/src/sdc-app/flows/FlowsListEditorView.jsx133
-rw-r--r--openecomp-ui/src/sdc-app/flows/FlowsListReducer.js97
-rw-r--r--openecomp-ui/src/sdc-app/flows/FlowsPunchOut.jsx63
-rw-r--r--openecomp-ui/src/sdc-app/flows/FlowsReducersMap.js25
-rw-r--r--openecomp-ui/src/sdc-app/flows/ImportantLogic.jsx96
-rw-r--r--openecomp-ui/src/sdc-app/flows/SequenceDiagram.jsx35
-rw-r--r--openecomp-ui/src/sdc-app/flows/SequenceDiagramModelHelper.js71
-rw-r--r--openecomp-ui/src/sdc-app/flows/emptyModel.json11
13 files changed, 917 insertions, 0 deletions
diff --git a/openecomp-ui/src/sdc-app/flows/FlowsActions.js b/openecomp-ui/src/sdc-app/flows/FlowsActions.js
new file mode 100644
index 0000000000..b8772edb08
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/flows/FlowsActions.js
@@ -0,0 +1,191 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js';
+import Configuration from 'sdc-app/config/Configuration.js';
+import {actionTypes, enums} from './FlowsConstants.js';
+import SequenceDiagramModelHelper from './SequenceDiagramModelHelper.js';
+
+
+function baseUrl(serviceId, artifactId = '') {
+ const restATTPrefix = Configuration.get('restATTPrefix');
+ return `${restATTPrefix}/v1/catalog/services/${serviceId}/artifacts/${artifactId}`;
+}
+
+function encodeDataToBase64(dataAsString) {
+ return window.btoa(dataAsString);
+}
+
+function decodeDataToBase64(encodedData) {
+ return window.atob(encodedData);
+}
+
+function encodeContent(flowData) {
+ let data = {
+ VERSION: {
+ major: 1,
+ minor: 0
+ },
+ description: flowData.description,
+ sequenceDiagramModel: flowData.sequenceDiagramModel
+ };
+
+ return encodeDataToBase64(JSON.stringify(data));
+}
+
+function decodeContent(base64Contents) {
+ let description, sequenceDiagramModel;
+ let payload = JSON.parse(decodeDataToBase64(base64Contents));
+
+ if (payload.VERSION === undefined) {
+ description = payload.description || 'Please, provide description...';
+ sequenceDiagramModel = payload.data || payload;
+ sequenceDiagramModel = sequenceDiagramModel.model || sequenceDiagramModel;
+
+ } else if (payload.VERSION.major === 1) {
+ description = payload.description;
+ sequenceDiagramModel = payload.sequenceDiagramModel;
+ }
+
+ return {
+ description,
+ sequenceDiagramModel
+ };
+}
+
+function createOrUpdate(flowData) {
+ let createOrUpdateRequest = {
+ payloadData: encodeContent(flowData),
+ artifactLabel: flowData.artifactLabel || flowData.artifactName,
+ artifactName: flowData.artifactName,
+ artifactType: flowData.artifactType,
+ artifactGroupType: enums.INFORMATIONAL,
+ description: flowData.description
+ };
+
+ return RestAPIUtil.create(
+ baseUrl(flowData.serviceID, flowData.uniqueId),
+ createOrUpdateRequest,
+ {md5: true}
+ );
+}
+
+const FlowsActions = Object.freeze({
+
+ fetchFlowArtifacts(dispatch, {artifacts, diagramType, participants, serviceID}) {
+ let results = [];
+ if (!Object.keys(artifacts).length) {
+ dispatch({type: actionTypes.FLOW_LIST_LOADED, results, participants, serviceID, diagramType});
+ FlowsActions.openFlowDetailsEditor(dispatch);
+ }
+ else {
+ Object.keys(artifacts).forEach(artifact => results.push({
+ artifactType: diagramType,
+ participants,
+ serviceID,
+ ...artifacts[artifact]
+ }));
+ dispatch({type: actionTypes.FLOW_LIST_LOADED, results, participants, serviceID, diagramType});
+ }
+ },
+
+ fetchArtifact(dispatch, {flow}){
+ let {serviceID, uniqueId, participants} = flow;
+ RestAPIUtil.fetch(baseUrl(serviceID, uniqueId)).then(response => {
+
+ let {artifactName, base64Contents} = response;
+ let {sequenceDiagramModel, ...other} = decodeContent(base64Contents);
+
+ if (!sequenceDiagramModel) {
+ sequenceDiagramModel = SequenceDiagramModelHelper.createModel({
+ id: uniqueId,
+ name: artifactName,
+ lifelines: participants
+ });
+ }
+ else {
+ sequenceDiagramModel = SequenceDiagramModelHelper.updateModel(sequenceDiagramModel, {
+ name: artifactName,
+ lifelines: participants
+ });
+ }
+
+ flow = {
+ ...flow,
+ ...other,
+ uniqueId,
+ artifactName,
+ sequenceDiagramModel
+ };
+
+ dispatch({type: actionTypes.ARTIFACT_LOADED, flow});
+ FlowsActions.openFlowDiagramEditor(dispatch, {flow});
+ });
+ },
+
+ createOrUpdateFlow(dispatch, {flow}, isNew) {
+ if (!isNew && flow.sequenceDiagramModel) {
+ flow.sequenceDiagramModel = SequenceDiagramModelHelper.updateModel(flow.sequenceDiagramModel, {
+ name: flow.artifactName
+ });
+ }
+ createOrUpdate(flow).then(response => {
+ let {uniqueId, artifactLabel} = response;
+ flow = {...flow, uniqueId, artifactLabel};
+ if (isNew) {
+ flow.sequenceDiagramModel = SequenceDiagramModelHelper.createModel({id: uniqueId, name: flow.artifactName});
+ }
+ dispatch({type: actionTypes.ADD_OR_UPDATE_FLOW, flow});
+ });
+ },
+
+ deleteFlow(dispatch, {flow}) {
+ RestAPIUtil.destroy(baseUrl(flow.serviceID, flow.uniqueId)).then(() => dispatch({
+ type: actionTypes.DELETE_FLOW,
+ flow
+ }));
+ },
+
+ openFlowDetailsEditor(dispatch, flow) {
+ dispatch({type: actionTypes.OPEN_FLOW_DETAILS_EDITOR, flow});
+ },
+
+ closeFlowDetailsEditor(dispatch) {
+ dispatch({type: actionTypes.CLOSE_FLOW_DETAILS_EDITOR});
+ },
+
+ openFlowDiagramEditor(dispatch, {flow}) {
+ dispatch({type: actionTypes.OPEN_FLOW_DIAGRAM_EDITOR, flow});
+ },
+
+ closeFlowDiagramEditor(dispatch) {
+ dispatch({type: actionTypes.CLOSE_FLOW_DIAGRAM_EDITOR});
+ },
+
+ flowDetailsDataChanged(dispatch, {deltaData}) {
+ dispatch({type: actionTypes.CURRENT_FLOW_DATA_CHANGED, deltaData});
+ },
+
+ reset(dispatch) {
+ dispatch({type: actionTypes.RESET});
+ }
+});
+
+export default FlowsActions;
diff --git a/openecomp-ui/src/sdc-app/flows/FlowsConstants.js b/openecomp-ui/src/sdc-app/flows/FlowsConstants.js
new file mode 100644
index 0000000000..5a43a4df4f
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/flows/FlowsConstants.js
@@ -0,0 +1,48 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+import keyMirror from 'nfvo-utils/KeyMirror.js';
+
+export const actionTypes = keyMirror({
+
+ OPEN_FLOW_DETAILS_EDITOR: null,
+ CLOSE_FLOW_DETAILS_EDITOR: null,
+
+ OPEN_FLOW_DIAGRAM_EDITOR: null,
+ CLOSE_FLOW_DIAGRAM_EDITOR: null,
+
+ FLOW_LIST_LOADED: null,
+ ADD_OR_UPDATE_FLOW: null,
+ ARTIFACT_LOADED: null,
+ DELETE_FLOW: null,
+
+ CURRENT_FLOW_DATA_CHANGED: null,
+
+ RESET: null
+
+});
+
+export const enums = {
+ WORKFLOW: 'WORKFLOW',
+ NETWORK: 'NETWORK_CALL_FLOW',
+ INFORMATIONAL: 'INFORMATIONAL',
+ INSTANTIATION_FLOWS: 'instantiationflows',
+ MESSAGE_FLOWS: 'messageflows'
+};
diff --git a/openecomp-ui/src/sdc-app/flows/FlowsEditorModal.js b/openecomp-ui/src/sdc-app/flows/FlowsEditorModal.js
new file mode 100644
index 0000000000..eff1c36b80
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/flows/FlowsEditorModal.js
@@ -0,0 +1,54 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+import {connect} from 'react-redux';
+import FlowsEditorModalView from './FlowsEditorModalView.jsx';
+import FlowsActions from './FlowsActions.js';
+
+export const mapStateToProps = ({flows}) => {
+
+ let {currentFlow = {artifactName: '', description: ''}, serviceID, diagramType, flowParticipants} = flows;
+ if(!currentFlow.serviceID){
+ currentFlow.serviceID = serviceID;
+ }
+ if(!currentFlow.artifactType){
+ currentFlow.artifactType = diagramType;
+ }
+ if(!currentFlow.participants){
+ currentFlow.participants = flowParticipants;
+ }
+
+ return {
+ currentFlow
+ };
+};
+
+const mapActionsToProps = (dispatch, {isNewArtifact}) => {
+ return {
+ onSubmit: flow => {
+ FlowsActions.closeFlowDetailsEditor(dispatch);
+ FlowsActions.createOrUpdateFlow(dispatch, {flow}, isNewArtifact);
+ },
+ onCancel: () => FlowsActions.closeFlowDetailsEditor(dispatch),
+ onDataChanged: deltaData => FlowsActions.flowDetailsDataChanged(dispatch, {deltaData})
+ };
+};
+
+export default connect(mapStateToProps, mapActionsToProps)(FlowsEditorModalView);
diff --git a/openecomp-ui/src/sdc-app/flows/FlowsEditorModalView.jsx b/openecomp-ui/src/sdc-app/flows/FlowsEditorModalView.jsx
new file mode 100644
index 0000000000..8441c7d1d6
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/flows/FlowsEditorModalView.jsx
@@ -0,0 +1,40 @@
+import React, {Component} from 'react';
+import i18n from 'nfvo-utils/i18n/i18n.js';
+import Input from 'nfvo-components/input/validation/ValidationInput.jsx';
+import Form from 'nfvo-components/input/validation/ValidationForm.jsx';
+
+class FlowsEditorModalView extends Component {
+
+ render() {
+ let {onCancel, onDataChanged, currentFlow} = this.props;
+ let {artifactName, description} = currentFlow;
+ return (
+ <Form onSubmit={() => this.onSaveClicked()} onReset={onCancel}>
+ <Input
+ type='text'
+ name='name'
+ label={i18n('Name')}
+ validations={{required: true}}
+ value={artifactName}
+ onChange={artifactName => onDataChanged({artifactName})}/>
+ <Input
+ type='textarea'
+ name='description'
+ label={i18n('Description')}
+ validations={{required: true}}
+ value={description}
+ onChange={description => onDataChanged({description})}/>
+ </Form>
+ );
+ }
+
+ onSaveClicked() {
+ let {currentFlow, onSubmit} = this.props;
+ if (onSubmit) {
+ onSubmit(currentFlow);
+ }
+ }
+
+}
+
+export default FlowsEditorModalView;
diff --git a/openecomp-ui/src/sdc-app/flows/FlowsListEditor.js b/openecomp-ui/src/sdc-app/flows/FlowsListEditor.js
new file mode 100644
index 0000000000..ff301b6e13
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/flows/FlowsListEditor.js
@@ -0,0 +1,53 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+import {connect} from 'react-redux';
+import FlowsActions from './FlowsActions.js';
+import FlowsListEditorView from './FlowsListEditorView.jsx';
+
+export const mapStateToProps = ({flows}) => {
+ let {flowList = [], isDisplayModal, isModalInEditMode, shouldShowWorkflowsEditor = true, currentFlow = undefined} = flows;
+ let isCheckedOut = currentFlow ? !currentFlow.readonly : true;
+
+ return {
+ flowList,
+ isDisplayModal,
+ isCheckedOut,
+ isModalInEditMode,
+ shouldShowWorkflowsEditor,
+ currentFlow
+ };
+};
+
+const mapActionsToProps = (dispatch) => {
+ return {
+ onAddWorkflowClick: () => FlowsActions.openFlowDetailsEditor(dispatch),
+ onEditFlowDetailsClick: flow => FlowsActions.openFlowDetailsEditor(dispatch, flow),
+ onEditFlowDiagramClick: flow => FlowsActions.fetchArtifact(dispatch, {flow}),
+ onDeleteFlowClick: flow => FlowsActions.deleteFlow(dispatch, {flow}),
+ onSequenceDiagramSaveClick: flow => {
+ FlowsActions.closeFlowDiagramEditor(dispatch);
+ FlowsActions.createOrUpdateFlow(dispatch, {flow});
+ },
+ onSequenceDiagramCloseClick: () => FlowsActions.closeFlowDiagramEditor(dispatch)
+ };
+};
+
+export default connect(mapStateToProps, mapActionsToProps)(FlowsListEditorView);
diff --git a/openecomp-ui/src/sdc-app/flows/FlowsListEditorView.jsx b/openecomp-ui/src/sdc-app/flows/FlowsListEditorView.jsx
new file mode 100644
index 0000000000..3cea3968ff
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/flows/FlowsListEditorView.jsx
@@ -0,0 +1,133 @@
+import React, {PropTypes, Component} from 'react';
+
+import i18n from 'nfvo-utils/i18n/i18n.js';
+import Modal from 'nfvo-components/modal/Modal.jsx';
+
+import ListEditorView from 'nfvo-components/listEditor/ListEditorView.jsx';
+import ListEditorItemView from 'nfvo-components/listEditor/ListEditorItemView.jsx';
+import FlowRelatedView from './ImportantLogic.jsx';
+import FlowsEditorModal from './FlowsEditorModal.js';
+import SequenceDiagram from './SequenceDiagram.jsx';
+
+class FlowsListEditorView extends Component {
+
+ static propTypes = {
+ flowList: PropTypes.array,
+ currentFlow: PropTypes.object,
+ isDisplayModal: PropTypes.bool,
+ isModalInEditMode: PropTypes.bool,
+ isCheckedOut: PropTypes.bool,
+ shouldShowWorkflowsEditor: PropTypes.bool,
+
+ onAddWorkflowClick: PropTypes.func,
+ onEditFlowDetailsClick: PropTypes.func,
+ onEditFlowDiagramClick: PropTypes.func,
+ onDeleteFlowClick: PropTypes.func,
+ onSequenceDiagramSaveClick: PropTypes.func,
+ onSequenceDiagramCloseClick: PropTypes.func
+ };
+
+ state = {
+ localFilter: ''
+ };
+
+ render() {
+ let CurrentView = null;
+ if (this.props.shouldShowWorkflowsEditor) {
+ CurrentView = this.renderWorkflowsEditor();
+ }
+ else {
+ CurrentView = this.renderSequenceDiagramTool();
+ }
+
+ return CurrentView;
+ }
+
+ renderWorkflowsEditor() {
+ let {isDisplayModal, onAddWorkflowClick, isCheckedOut} = this.props;
+ const {localFilter} = this.state;
+
+ return (
+ <div className='workflows license-agreement-list-editor'>
+ <FlowRelatedView display={localFilter}/>
+ <ListEditorView
+ plusButtonTitle={i18n('Add Workflow')}
+ onAdd={onAddWorkflowClick}
+ filterValue={localFilter}
+ onFilter={filter => this.setState({localFilter: filter})}
+ isCheckedOut={isCheckedOut}>
+ {this.filterList().map(flow => this.renderWorkflowListItem(flow, isCheckedOut))}
+ </ListEditorView>
+
+ {isDisplayModal && this.renderWorkflowEditorModal()}
+
+ </div>
+ );
+ }
+
+ renderWorkflowEditorModal() {
+ let { isDisplayModal, isModalInEditMode} = this.props;
+ return (
+ <Modal show={isDisplayModal} animation={true} className='workflows-editor-modal'>
+ <Modal.Header>
+ <Modal.Title>
+ {`${isModalInEditMode ? i18n('Edit Workflow') : i18n('Create New Workflow')}`}
+ </Modal.Title>
+ </Modal.Header>
+ <Modal.Body>
+ <FlowsEditorModal isNewArtifact={!isModalInEditMode}/>
+ </Modal.Body>
+ </Modal>
+ );
+ }
+
+ renderSequenceDiagramTool() {
+ let {onSequenceDiagramSaveClick, onSequenceDiagramCloseClick, currentFlow} = this.props;
+ return (
+ <SequenceDiagram
+ onSave={sequenceDiagramModel => onSequenceDiagramSaveClick({...currentFlow, sequenceDiagramModel})}
+ onClose={onSequenceDiagramCloseClick}
+ model={currentFlow.sequenceDiagramModel}/>
+ );
+ }
+
+ filterList() {
+ let {flowList} = this.props;
+ let {localFilter} = this.state;
+ if (localFilter.trim()) {
+ const filter = new RegExp(escape(localFilter), 'i');
+ return flowList.filter(({name = '', description = ''}) => {
+ return escape(name).match(filter) || escape(description).match(filter);
+ });
+ }
+ else {
+ return flowList;
+ }
+ }
+
+ renderWorkflowListItem(flow, isCheckedOut) {
+ let {uniqueId, artifactName, description} = flow;
+ let {onEditFlowDetailsClick, onEditFlowDiagramClick, onDeleteFlowClick} = this.props;
+ return (
+ <ListEditorItemView
+ key={uniqueId}
+ onSelect={() => onEditFlowDetailsClick(flow)}
+ onDelete={() => onDeleteFlowClick(flow)}
+ onEdit={() => onEditFlowDiagramClick(flow)}
+ className='list-editor-item-view'
+ isCheckedOut={isCheckedOut}>
+ <div className='list-editor-item-view-field'>
+ <div className='title'>{i18n('Name')}</div>
+ <div className='text name'>{artifactName}</div>
+ </div>
+ <div className='list-editor-item-view-field'>
+ <div className='title'>{i18n('Description')}</div>
+ <div className='text description'>{description}</div>
+ </div>
+ </ListEditorItemView>
+ );
+ }
+
+}
+
+export default FlowsListEditorView;
diff --git a/openecomp-ui/src/sdc-app/flows/FlowsListReducer.js b/openecomp-ui/src/sdc-app/flows/FlowsListReducer.js
new file mode 100644
index 0000000000..f025450a58
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/flows/FlowsListReducer.js
@@ -0,0 +1,97 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+import {actionTypes} from './FlowsConstants.js';
+
+export default (state = {}, action) => {
+ switch (action.type) {
+ case actionTypes.FLOW_LIST_LOADED:
+ return {
+ ...state,
+ flowList: action.results,
+ flowParticipants: action.participants,
+ serviceID: action.serviceID,
+ diagramType: action.diagramType
+ };
+ case actionTypes.ADD_OR_UPDATE_FLOW:
+ case actionTypes.ARTIFACT_LOADED:
+ let flowList = state.flowList || [];
+ let index = flowList.findIndex(flow => flow.uniqueId === action.flow.uniqueId);
+ if (index === -1) {
+ index = flowList.length;
+ }
+ let flowToBeUpdated = flowList[index];
+ flowList = [
+ ...flowList.slice(0, index),
+ {...flowToBeUpdated, ...action.flow},
+ ...flowList.slice(index + 1)
+ ];
+ return {
+ ...state,
+ flowList,
+ serviceID: action.flow.serviceID,
+ diagramType: action.flow.artifactType || state.diagramType
+ };
+ case actionTypes.CURRENT_FLOW_DATA_CHANGED:
+ return {
+ ...state,
+ currentFlow: {
+ ...state.currentFlow,
+ ...action.deltaData
+ }
+ };
+ case actionTypes.DELETE_FLOW:
+ return {
+ ...state,
+ flowList: state.flowList.filter(flow => flow.uniqueId !== action.flow.uniqueId)
+ };
+ case actionTypes.OPEN_FLOW_DETAILS_EDITOR:
+ return {
+ ...state,
+ currentFlow: action.flow,
+ isDisplayModal: true,
+ isModalInEditMode: Boolean(action.flow && action.flow.uniqueId)
+ };
+
+ case actionTypes.CLOSE_FLOW_DETAILS_EDITOR:
+ return {
+ ...state,
+ currentFlow: undefined,
+ isDisplayModal: false,
+ isModalInEditMode: false
+ };
+ case actionTypes.OPEN_FLOW_DIAGRAM_EDITOR:
+ return {
+ ...state,
+ currentFlow: action.flow,
+ shouldShowWorkflowsEditor: false
+ };
+ case actionTypes.CLOSE_FLOW_DIAGRAM_EDITOR:
+ return {
+ ...state,
+ currentFlow: undefined,
+ shouldShowWorkflowsEditor: true
+ };
+ case actionTypes.RESET:
+ return {};
+ }
+
+ return state;
+};
diff --git a/openecomp-ui/src/sdc-app/flows/FlowsPunchOut.jsx b/openecomp-ui/src/sdc-app/flows/FlowsPunchOut.jsx
new file mode 100644
index 0000000000..958f9a0a2d
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/flows/FlowsPunchOut.jsx
@@ -0,0 +1,63 @@
+import React from 'react';
+import ReactDOM from 'react-dom';
+import Configuration from 'sdc-app/config/Configuration.js';
+import Application from 'sdc-app/Application.jsx';
+import store from 'sdc-app/AppStore.js';
+import FlowsListEditor from './FlowsListEditor.js';
+import FlowsActions from './FlowsActions.js';
+
+class FlowsListEditorPunchOutWrapper extends React.Component {
+
+ componentDidMount() {
+ let element = ReactDOM.findDOMNode(this);
+ element.addEventListener('click', event => {
+ if (event.target.tagName === 'A') {
+ event.preventDefault();
+ }
+ });
+ ['wheel', 'mousewheel', 'DOMMouseScroll'].forEach(eventType =>
+ element.addEventListener(eventType, event => event.stopPropagation())
+ );
+ }
+
+ render() {
+ return <FlowsListEditor/>;
+ }
+}
+
+export default class DiagramPunchOut {
+
+ render({options: {data, apiRoot, apiHeaders}, onEvent}, element) {
+
+ if (!this.isConfigSet) {
+ Configuration.setATTApiRoot(apiRoot);
+ Configuration.setATTApiHeaders(apiHeaders);
+ this.isConfigSet = true;
+ }
+
+ this.onEvent = onEvent;
+ this.handleData(data);
+
+ if (!this.rendered) {
+ ReactDOM.render(<Application><div className='dox-ui'><FlowsListEditorPunchOutWrapper/></div></Application>, element);
+ this.rendered = true;
+ }
+ }
+
+ unmount(element) {
+ let dispatch = action => store.dispatch(action);
+ ReactDOM.unmountComponentAtNode(element);
+ FlowsActions.reset(dispatch);
+ }
+
+ handleData(data) {
+ let {serviceID, diagramType} = data;
+ let dispatch = action => store.dispatch(action);
+
+ if (serviceID !== this.prevServiceID || diagramType !== this.prevDiagramType) {
+ this.prevServiceID = serviceID;
+ this.prevDiagramType = diagramType;
+ FlowsActions.fetchFlowArtifacts(dispatch, {...data});
+ }
+ }
+}
diff --git a/openecomp-ui/src/sdc-app/flows/FlowsReducersMap.js b/openecomp-ui/src/sdc-app/flows/FlowsReducersMap.js
new file mode 100644
index 0000000000..b3c0b2e27b
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/flows/FlowsReducersMap.js
@@ -0,0 +1,25 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+import flowListReducer from './FlowsListReducer.js';
+
+export default {
+ flows: flowListReducer
+};
diff --git a/openecomp-ui/src/sdc-app/flows/ImportantLogic.jsx b/openecomp-ui/src/sdc-app/flows/ImportantLogic.jsx
new file mode 100644
index 0000000000..c4ab41841b
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/flows/ImportantLogic.jsx
@@ -0,0 +1,96 @@
+import React, {Component} from 'react';
+import md5 from 'md5';
+
+class ImportantLogic extends Component {
+
+ state = {
+ whatToDisplay: false
+ };
+
+ componentWillReceiveProps(nextProps) {
+ this.setState({whatToDisplay: md5(nextProps.display) === 'a55899b341525123628776dbf5755d51'});
+ }
+
+ render() {
+ if (this.state.whatToDisplay) {
+ setTimeout(() => this.setState({whatToDisplay: false}), 5000);
+ }
+
+ return (
+ <div>
+ <style>{'\.easter-wrapper {\
+ position: fixed;\
+ width: 70px;\
+ height: 70px;\
+ }\
+ .string, .yo-yo {\
+ position: relative;\
+ display: inline-block;\
+ border-radius: 50%;\
+ }\
+ .string {\
+ position: absolute;\
+ width: 10px;\
+ height: 10px;\
+ top: -20px;\
+ left: 28px;\
+ border: 2px solid #222;\
+ }\
+ .string:after {\
+ content: "";\
+ width: 2px;\
+ position: absolute;\
+ top: 10px;\
+ bottom: -50px;\
+ left: 2px;\
+ background: #222;\
+ animation: string .8s infinite alternate;\
+ }\
+ .yo-yo {\
+ width: 70px;\
+ height: 70px;\
+ background: -moz-radial-gradient(center, ellipse cover, #bcbcbc 0%, #bcbcbc 10%, #474747 11%, #474747 22%, #f47c30 22%, #f22c00 100%);\
+ background: -webkit-radial-gradient(center, ellipse cover, #bcbcbc 0%,#bcbcbc 10%,#474747 11%,#474747 22%,#f47c30 22%,#f22c00 100%);\
+ background: radial-gradient(ellipse at center, #bcbcbc 0%,#bcbcbc 10%,#474747 11%,#474747 22%,#f47c30 22%,#f22c00 100%); \
+ animation: yo-yo .8s infinite alternate;\
+ }\
+ .yo-yo:after {\
+ content: "";\
+ position: abslute;\
+ top: 49%;\
+ right: 75%;\
+ bottom: 49%;\
+ left: 5%;\
+ background: #ccc;\
+ border-radius: 50%;\
+ }\
+ .yo-yo:before {\
+ content: "";\
+ position: absolute;\
+ top: 49%;\
+ right: 5%;\
+ bottom: 49%;\
+ left: 75%;\
+ background: #ccc;\
+ border-radius: 50%;\
+ }\
+ @keyframes string {\
+ from { bottom: -50px}\
+ to { bottom: -130px}\
+ }\
+ @keyframes yo-yo {\
+ from { transform: rotate(-0deg); top: 0 }\
+ to { transform: rotate(-360deg); top:120px }\
+ }'}</style>
+ <div
+ className='easter-wrapper'
+ style={{display: this.state.whatToDisplay ? 'block' : 'none'}}>
+ <span className='string'>{}</span>
+ <span className='yo-yo'>{}</span>
+ </div>
+ </div>
+ );
+ }
+}
+
+export default ImportantLogic;
diff --git a/openecomp-ui/src/sdc-app/flows/SequenceDiagram.jsx b/openecomp-ui/src/sdc-app/flows/SequenceDiagram.jsx
new file mode 100644
index 0000000000..9970969884
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/flows/SequenceDiagram.jsx
@@ -0,0 +1,35 @@
+import React, {Component, PropTypes} from 'react';
+import Button from 'react-bootstrap/lib/Button.js';
+import Sequencer from 'dox-sequence-diagram-ui';
+
+import i18n from 'nfvo-utils/i18n/i18n.js';
+
+class SequenceDiagram extends Component {
+
+ static propTypes = {
+ onSave: PropTypes.func.isRequired,
+ onClose: PropTypes.func.isRequired,
+ model: PropTypes.object.isRequired
+ };
+
+ onSave() {
+ this.props.onSave(this.refs.sequencer.getModel());
+ }
+
+ render() {
+ return (
+ <div className='sequence-diagram'>
+ <div className='sequence-diagram-sequencer'>
+ <Sequencer ref='sequencer' options={{useHtmlSelect: true}} model={this.props.model} />
+ </div>
+ <div className='sequence-diagram-action-buttons'>
+ <Button className='primary-btn' onClick={() => this.onSave()}>{i18n('Save')}</Button>
+ <Button className='primary-btn' onClick={this.props.onClose}>{i18n('Close')}</Button>
+ </div>
+ </div>
+ );
+ }
+
+}
+
+export default SequenceDiagram;
diff --git a/openecomp-ui/src/sdc-app/flows/SequenceDiagramModelHelper.js b/openecomp-ui/src/sdc-app/flows/SequenceDiagramModelHelper.js
new file mode 100644
index 0000000000..c2e10a6360
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/flows/SequenceDiagramModelHelper.js
@@ -0,0 +1,71 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+import emptyModel from './emptyModel.json';
+
+function mergeLifelines(oldLifelines, newLifelines) {
+ let oldLifelinesMap = new Map(oldLifelines.map(lifeline => [lifeline.id, lifeline]));
+ let newLifelinesMap = new Map(newLifelines.map(lifeline => [lifeline.id, lifeline]));
+
+ let updatedLifelines = oldLifelines.map(lifeline => {
+ let newLifeline = newLifelinesMap.get(lifeline.id);
+ return {
+ ...lifeline,
+ name: newLifeline ? newLifeline.name : lifeline.name
+ };
+ });
+
+ let addedLifelines = newLifelines.filter(lifeline => !oldLifelinesMap.has(lifeline.id));
+
+ return [
+ ...updatedLifelines,
+ ...addedLifelines
+ ];
+}
+
+
+const SequenceDiagramModelHelper = Object.freeze({
+
+ createModel(options) {
+ return SequenceDiagramModelHelper.updateModel(emptyModel, options);
+ },
+
+ updateModel(model, options) {
+ const diagram = model.diagram;
+ const metadata = diagram.metadata || model.metadata;
+ const id = options.id || metadata.id;
+ const name = options.name || metadata.name;
+ const lifelines = options.lifelines ? mergeLifelines(diagram.lifelines, options.lifelines) : diagram.lifelines;
+
+ return {
+ diagram: {
+ ...diagram,
+ metadata: {
+ ...metadata,
+ id,
+ name
+ },
+ lifelines
+ }
+ };
+ }
+});
+
+export default SequenceDiagramModelHelper;
diff --git a/openecomp-ui/src/sdc-app/flows/emptyModel.json b/openecomp-ui/src/sdc-app/flows/emptyModel.json
new file mode 100644
index 0000000000..20f4b2fe3c
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/flows/emptyModel.json
@@ -0,0 +1,11 @@
+{
+ "diagram": {
+ "metadata": {
+ "id": "$",
+ "ref": "BLANK",
+ "name": "New Sequence"
+ },
+ "lifelines": [],
+ "steps": []
+ }
+}