mirror of
https://repository.entgra.net/community/device-mgt-core.git
synced 2025-10-06 02:01:45 +00:00
Merge branch 'application-mgt-new' into 'application-mgt-new'
Add lifecycle Graph See merge request entgra/carbon-device-mgt!89
This commit is contained in:
commit
3cb9fd3a43
@ -13,6 +13,7 @@
|
|||||||
"acorn": "^6.1.1",
|
"acorn": "^6.1.1",
|
||||||
"antd": "^3.15.0",
|
"antd": "^3.15.0",
|
||||||
"axios": "^0.18.0",
|
"axios": "^0.18.0",
|
||||||
|
"dagre": "^0.8.4",
|
||||||
"keymirror": "^0.1.1",
|
"keymirror": "^0.1.1",
|
||||||
"react": "^16.8.4",
|
"react": "^16.8.4",
|
||||||
"react-dom": "^16.8.4",
|
"react-dom": "^16.8.4",
|
||||||
@ -21,7 +22,8 @@
|
|||||||
"react-router-config": "^5.0.0",
|
"react-router-config": "^5.0.0",
|
||||||
"react-router-dom": "latest",
|
"react-router-dom": "latest",
|
||||||
"react-scripts": "2.1.8",
|
"react-scripts": "2.1.8",
|
||||||
"redux-thunk": "^2.3.0"
|
"redux-thunk": "^2.3.0",
|
||||||
|
"storm-react-diagrams": "^5.2.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.0.0",
|
"@babel/core": "^7.0.0",
|
||||||
|
|||||||
@ -0,0 +1,7 @@
|
|||||||
|
.srd-diagram{
|
||||||
|
height: 100%;
|
||||||
|
min-height: 300px;
|
||||||
|
background-color: #3c3c3c !important;
|
||||||
|
background-image: linear-gradient(0deg, transparent 24%, rgba(255, 255, 255, 0.05) 25%, rgba(255, 255, 255, 0.05) 26%, transparent 27%, transparent 74%, rgba(255, 255, 255, 0.05) 75%, rgba(255, 255, 255, 0.05) 76%, transparent 77%, transparent), linear-gradient(90deg, transparent 24%, rgba(255, 255, 255, 0.05) 25%, rgba(255, 255, 255, 0.05) 26%, transparent 27%, transparent 74%, rgba(255, 255, 255, 0.05) 75%, rgba(255, 255, 255, 0.05) 76%, transparent 77%, transparent);
|
||||||
|
background-size: 50px 50px;
|
||||||
|
}
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
import React from "react";
|
||||||
|
import LifeCycleGraph from "./LifeCycleGraph";
|
||||||
|
import {connect} from "react-redux";
|
||||||
|
import {getLifecycle, openReleasesModal} from "../../../js/actions";
|
||||||
|
|
||||||
|
const mapDispatchToProps = dispatch => ({
|
||||||
|
getLifecycle: () => dispatch(getLifecycle())
|
||||||
|
});
|
||||||
|
|
||||||
|
const mapStateToProps = state => {
|
||||||
|
return {
|
||||||
|
lifecycle: state.lifecycle
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConnectedLifeCycle extends React.Component {
|
||||||
|
componentDidMount() {
|
||||||
|
this.props.getLifecycle();
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
console.log();
|
||||||
|
const lifecycle = this.props.lifecycle;
|
||||||
|
if(lifecycle != null){
|
||||||
|
return (
|
||||||
|
<LifeCycleGraph currentStatus={this.props.currentStatus} lifecycle={this.props.lifecycle}/>
|
||||||
|
);
|
||||||
|
|
||||||
|
}else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const LifeCycle = connect(mapStateToProps, mapDispatchToProps)(ConnectedLifeCycle);
|
||||||
|
|
||||||
|
export default LifeCycle;
|
||||||
@ -0,0 +1,90 @@
|
|||||||
|
import React from "react";
|
||||||
|
import * as SRD from "storm-react-diagrams";
|
||||||
|
import "storm-react-diagrams/dist/style.min.css";
|
||||||
|
import "./LifeCycle.css";
|
||||||
|
import {distributeElements} from "../../../js/utils/dagre-utils.ts";
|
||||||
|
|
||||||
|
const inPortName = "IN";
|
||||||
|
const outPortName = "OUT";
|
||||||
|
|
||||||
|
class LifeCycleGraph extends React.Component {
|
||||||
|
render() {
|
||||||
|
|
||||||
|
const lifecycle = this.props.lifecycle;
|
||||||
|
const nodes = [];
|
||||||
|
const links = [];
|
||||||
|
|
||||||
|
const engine = new SRD.DiagramEngine();
|
||||||
|
engine.installDefaultFactories();
|
||||||
|
|
||||||
|
const model = new SRD.DiagramModel();
|
||||||
|
const nextStates = lifecycle[this.props.currentStatus].proceedingStates;
|
||||||
|
|
||||||
|
|
||||||
|
Object.keys(lifecycle).forEach((stateName) => {
|
||||||
|
let color = "rgb(83, 92, 104)";
|
||||||
|
if (stateName === this.props.currentStatus) {
|
||||||
|
color = "rgb(192,255,0)";
|
||||||
|
}else if(nextStates.includes(stateName)){
|
||||||
|
color = "rgb(0,192,255)";
|
||||||
|
}
|
||||||
|
const node = createNode(stateName, color);
|
||||||
|
// node.addPort()
|
||||||
|
nodes.push(node);
|
||||||
|
lifecycle[stateName].node = node;
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.keys(lifecycle).forEach((stateName) => {
|
||||||
|
const state = lifecycle[stateName];
|
||||||
|
//todo: remove checking property
|
||||||
|
if (state.hasOwnProperty("proceedingStates")) {
|
||||||
|
|
||||||
|
state.proceedingStates.forEach((proceedingState) => {
|
||||||
|
links.push(connectNodes(state.node, lifecycle[proceedingState].node));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
nodes.forEach((node) => {
|
||||||
|
model.addNode(node);
|
||||||
|
});
|
||||||
|
links.forEach((link) => {
|
||||||
|
model.addLink(link);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
let distributedModel = getDistributedModel(engine, model);
|
||||||
|
engine.setDiagramModel(distributedModel);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{height: 900}}>
|
||||||
|
<SRD.DiagramWidget diagramEngine={engine} maxNumberPointsPerLink={10} smartRouting={true}/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDistributedModel(engine, model) {
|
||||||
|
const serialized = model.serializeDiagram();
|
||||||
|
const distributedSerializedDiagram = distributeElements(serialized);
|
||||||
|
|
||||||
|
//deserialize the model
|
||||||
|
let deSerializedModel = new SRD.DiagramModel();
|
||||||
|
deSerializedModel.deSerializeDiagram(distributedSerializedDiagram, engine);
|
||||||
|
return deSerializedModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createNode(name, color) {
|
||||||
|
const node = new SRD.DefaultNodeModel(name, color);
|
||||||
|
node.addPort(new SRD.DefaultPortModel(true, inPortName, " "));
|
||||||
|
node.addPort(new SRD.DefaultPortModel(false, outPortName, " "));
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
let count = 0;
|
||||||
|
|
||||||
|
function connectNodes(nodeFrom, nodeTo) {
|
||||||
|
return nodeFrom.getPort(outPortName).link(nodeTo.getPort(inPortName));
|
||||||
|
}
|
||||||
|
|
||||||
|
export default LifeCycleGraph;
|
||||||
@ -14,7 +14,6 @@ export const getApps = () => dispatch => {
|
|||||||
if (res.data.data.hasOwnProperty("applications")) {
|
if (res.data.data.hasOwnProperty("applications")) {
|
||||||
apps = res.data.data.applications;
|
apps = res.data.data.applications;
|
||||||
}
|
}
|
||||||
console.log(res.data);
|
|
||||||
dispatch({type: ActionTypes.GET_APPS, payload: apps});
|
dispatch({type: ActionTypes.GET_APPS, payload: apps});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,8 +34,6 @@ export const getRelease = (uuid) => dispatch => {
|
|||||||
).then(res => {
|
).then(res => {
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
let release = res.data.data;
|
let release = res.data.data;
|
||||||
|
|
||||||
console.log(res.data);
|
|
||||||
dispatch({type: ActionTypes.GET_RELEASE, payload: release});
|
dispatch({type: ActionTypes.GET_RELEASE, payload: release});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,7 +47,6 @@ export const getRelease = (uuid) => dispatch => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const openReleasesModal = (app) => dispatch => {
|
export const openReleasesModal = (app) => dispatch => {
|
||||||
console.log(app);
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ActionTypes.OPEN_RELEASES_MODAL,
|
type: ActionTypes.OPEN_RELEASES_MODAL,
|
||||||
payload: {
|
payload: {
|
||||||
@ -59,3 +55,19 @@ export const openReleasesModal = (app) => dispatch => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getLifecycle = ()=> dispatch =>{
|
||||||
|
const request = "method=get&content-type=application/json&payload={}&api-endpoint=/application-mgt-publisher/v1.0/applications/lifecycle-config";
|
||||||
|
|
||||||
|
return axios.post('https://' + config.serverConfig.hostname + ':' + config.serverConfig.httpsPort + config.serverConfig.invokerUri, request
|
||||||
|
).then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
let lifecycle = res.data.data;
|
||||||
|
dispatch({type: ActionTypes.GET_LIFECYCLE, payload: lifecycle});
|
||||||
|
}
|
||||||
|
|
||||||
|
}).catch(function (error) {
|
||||||
|
if (error.response.status === 401) {
|
||||||
|
window.location.href = 'https://localhost:9443/publisher/login';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|||||||
@ -1,16 +1,12 @@
|
|||||||
import keyMirror from 'keymirror';
|
import keyMirror from 'keymirror';
|
||||||
|
|
||||||
// export const LOGIN = "LOGIN";
|
|
||||||
// export const GET_APPS = "GET_APPS";
|
|
||||||
// export const OPEN_RELEASES_MODAL = "OPEN_RELEASES_MODAL";
|
|
||||||
// export const CLOSE_RELEASES_MODAL = "CLOSE_RELEASES_MODAL";
|
|
||||||
|
|
||||||
const ActionTypes = keyMirror({
|
const ActionTypes = keyMirror({
|
||||||
LOGIN: null,
|
LOGIN: null,
|
||||||
GET_APPS: null,
|
GET_APPS: null,
|
||||||
OPEN_RELEASES_MODAL: null,
|
OPEN_RELEASES_MODAL: null,
|
||||||
CLOSE_RELEASES_MODAL: null,
|
CLOSE_RELEASES_MODAL: null,
|
||||||
GET_RELEASE: null
|
GET_RELEASE: null,
|
||||||
|
GET_LIFECYCLE: null
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,8 @@ const initialState = {
|
|||||||
visible: false,
|
visible: false,
|
||||||
app: null
|
app: null
|
||||||
},
|
},
|
||||||
release: null
|
release: null,
|
||||||
|
lifecycle: null
|
||||||
};
|
};
|
||||||
|
|
||||||
function rootReducer(state = initialState, action) {
|
function rootReducer(state = initialState, action) {
|
||||||
@ -25,7 +26,10 @@ function rootReducer(state = initialState, action) {
|
|||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
release: action.payload
|
release: action.payload
|
||||||
});
|
});
|
||||||
|
} else if (action.type === ActionTypes.GET_LIFECYCLE) {
|
||||||
|
return Object.assign({}, state, {
|
||||||
|
lifecycle: action.payload
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,56 @@
|
|||||||
|
import * as dagre from "dagre";
|
||||||
|
import * as _ from "lodash";
|
||||||
|
|
||||||
|
const size = {
|
||||||
|
width: 60,
|
||||||
|
height: 60
|
||||||
|
};
|
||||||
|
|
||||||
|
export function distributeElements(model) {
|
||||||
|
let clonedModel = _.cloneDeep(model);
|
||||||
|
let nodes = distributeGraph(clonedModel);
|
||||||
|
nodes.forEach(node => {
|
||||||
|
let modelNode = clonedModel.nodes.find(item => item.id === node.id);
|
||||||
|
modelNode.x = node.x - node.width / 2;
|
||||||
|
modelNode.y = node.y - node.height / 2;
|
||||||
|
});
|
||||||
|
return clonedModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
function distributeGraph(model) {
|
||||||
|
let nodes = mapElements(model);
|
||||||
|
let edges = mapEdges(model);
|
||||||
|
let graph = new dagre.graphlib.Graph();
|
||||||
|
graph.setGraph({});
|
||||||
|
graph.setDefaultEdgeLabel(() => ({}));
|
||||||
|
//add elements to dagre graph
|
||||||
|
nodes.forEach(node => {
|
||||||
|
graph.setNode(node.id, node.metadata);
|
||||||
|
});
|
||||||
|
edges.forEach(edge => {
|
||||||
|
if (edge.from && edge.to) {
|
||||||
|
graph.setEdge(edge.from, edge.to);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
//auto-distribute
|
||||||
|
dagre.layout(graph);
|
||||||
|
return graph.nodes().map(node => graph.node(node));
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapElements(model) {
|
||||||
|
// dagre compatible format
|
||||||
|
return model.nodes.map(node => ({ id: node.id, metadata: { ...size, id: node.id } }));
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapEdges(model) {
|
||||||
|
// returns links which connects nodes
|
||||||
|
// we check are there both from and to nodes in the model. Sometimes links can be detached
|
||||||
|
return model.links
|
||||||
|
.map(link => ({
|
||||||
|
from: link.source,
|
||||||
|
to: link.target
|
||||||
|
}))
|
||||||
|
.filter(
|
||||||
|
item => model.nodes.find(node => node.id === item.from) && model.nodes.find(node => node.id === item.to)
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -38,7 +38,7 @@ class Dashboard extends React.Component {
|
|||||||
</Header>
|
</Header>
|
||||||
<Content style={{padding: '0 0'}}>
|
<Content style={{padding: '0 0'}}>
|
||||||
<Switch>
|
<Switch>
|
||||||
<Redirect exact from="/publisher/dashboard" to="/publisher/dashboard/apps"/>
|
<Redirect exact from="/publisher" to="/publisher/apps"/>
|
||||||
{this.state.routes.map((route) => (
|
{this.state.routes.map((route) => (
|
||||||
<RouteWithSubRoutes key={route.path} {...route} />
|
<RouteWithSubRoutes key={route.path} {...route} />
|
||||||
))}
|
))}
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import {PageHeader, Typography, Input, Button, Row, Col, Avatar, Card} from "ant
|
|||||||
import {connect} from "react-redux";
|
import {connect} from "react-redux";
|
||||||
import ReleaseView from "../../../../components/apps/release/ReleaseView";
|
import ReleaseView from "../../../../components/apps/release/ReleaseView";
|
||||||
import {getRelease} from "../../../../js/actions";
|
import {getRelease} from "../../../../js/actions";
|
||||||
|
import LifeCycle from "../../../../components/apps/release/LifeCycle";
|
||||||
|
|
||||||
const Search = Input.Search;
|
const Search = Input.Search;
|
||||||
const {Title} = Typography;
|
const {Title} = Typography;
|
||||||
@ -54,6 +55,8 @@ class ConnectedRelease extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//todo remove uppercase
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<PageHeader
|
<PageHeader
|
||||||
@ -61,11 +64,16 @@ class ConnectedRelease extends React.Component {
|
|||||||
/>
|
/>
|
||||||
<div style={{background: '#f0f2f5', padding: 24, minHeight: 780}}>
|
<div style={{background: '#f0f2f5', padding: 24, minHeight: 780}}>
|
||||||
<Row style={{padding: 10}}>
|
<Row style={{padding: 10}}>
|
||||||
<Col span={18}>
|
<Col span={16}>
|
||||||
<Card>
|
<Card>
|
||||||
<ReleaseView release={release}/>
|
<ReleaseView release={release}/>
|
||||||
</Card>
|
</Card>
|
||||||
</Col>
|
</Col>
|
||||||
|
<Col span={8}>
|
||||||
|
<Card>
|
||||||
|
<LifeCycle currentStatus={release.currentStatus.toUpperCase()}/>
|
||||||
|
</Card>
|
||||||
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user