forked from community/device-mgt-core
The following imrovements are with this commit - Fix issues and change ui in manage page - Change error messages to closable notifications - Create a view to inform user when no apps available - Change error messages - Change install mode order in store - Change the lifecycle UI - Fix typo in error messages in APPM UIfeature/appm-store/pbac
parent
a5f75df99a
commit
4d59b8d900
@ -0,0 +1,96 @@
|
|||||||
|
import React from "react";
|
||||||
|
import {Modal, Button, Tag, Collapse, List,Typography} from 'antd';
|
||||||
|
import pSBC from "shade-blend-color";
|
||||||
|
import config from "../../../../../../public/conf/config.json";
|
||||||
|
|
||||||
|
const {Text} = Typography;
|
||||||
|
const lifeCycleConfig = config.lifecycle;
|
||||||
|
|
||||||
|
class LifeCycleDetailsModal extends React.Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {visible: false};
|
||||||
|
}
|
||||||
|
|
||||||
|
showModal = () => {
|
||||||
|
this.setState({
|
||||||
|
visible: true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
handleCancel = e => {
|
||||||
|
console.log(e);
|
||||||
|
this.setState({
|
||||||
|
visible: false,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {lifecycle} = this.props;
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
icon="question-circle"
|
||||||
|
onClick={this.showModal}
|
||||||
|
>
|
||||||
|
Learn more
|
||||||
|
</Button>
|
||||||
|
<Modal
|
||||||
|
title="Lifecycle"
|
||||||
|
visible={this.state.visible}
|
||||||
|
footer = {null}
|
||||||
|
onCancel={this.handleCancel}
|
||||||
|
>
|
||||||
|
|
||||||
|
<List
|
||||||
|
itemLayout="horizontal"
|
||||||
|
dataSource={Object.keys(lifecycle)}
|
||||||
|
renderItem={lifecycleState => {
|
||||||
|
let text = "";
|
||||||
|
let footerText = "";
|
||||||
|
let nextProceedingStates = [];
|
||||||
|
|
||||||
|
if (lifeCycleConfig.hasOwnProperty(lifecycleState)) {
|
||||||
|
text = lifeCycleConfig[lifecycleState].text;
|
||||||
|
}
|
||||||
|
if (lifecycle[lifecycleState].hasOwnProperty("proceedingStates")) {
|
||||||
|
nextProceedingStates = lifecycle[lifecycleState].proceedingStates;
|
||||||
|
footerText = "You can only proceed to one of the following states:"
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<List.Item>
|
||||||
|
<List.Item.Meta
|
||||||
|
title={lifecycleState}
|
||||||
|
/>
|
||||||
|
{text}
|
||||||
|
<br/>
|
||||||
|
<Text type="secondary">{footerText}</Text>
|
||||||
|
<div>
|
||||||
|
{
|
||||||
|
nextProceedingStates.map(lifecycleState => {
|
||||||
|
return (
|
||||||
|
<Tag
|
||||||
|
key={lifecycleState}
|
||||||
|
style={{margin: 5}}
|
||||||
|
color={pSBC(0.30, config.theme.primaryColor)}
|
||||||
|
>
|
||||||
|
{lifecycleState}
|
||||||
|
</Tag>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</List.Item>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Modal>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default LifeCycleDetailsModal;
|
@ -1,136 +0,0 @@
|
|||||||
import axios from "axios";
|
|
||||||
import ActionTypes from "../constants/ActionTypes";
|
|
||||||
import config from "../../../public/conf/config.json";
|
|
||||||
import {message} from "antd";
|
|
||||||
|
|
||||||
export const getApps = () => dispatch => {
|
|
||||||
|
|
||||||
const request = "method=post&content-type=application/json&payload={}&api-endpoint=/application-mgt-publisher/v1.0/applications";
|
|
||||||
|
|
||||||
return axios.post(
|
|
||||||
config.serverConfig.protocol + "://"+config.serverConfig.hostname + ':' + config.serverConfig.httpsPort + config.serverConfig.invoker.uri +config.serverConfig.invoker.publisher,
|
|
||||||
request
|
|
||||||
).then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
let apps = [];
|
|
||||||
|
|
||||||
if (res.data.data.hasOwnProperty("applications")) {
|
|
||||||
apps = res.data.data.applications;
|
|
||||||
}
|
|
||||||
dispatch({type: ActionTypes.GET_APPS, payload: apps});
|
|
||||||
}
|
|
||||||
|
|
||||||
}).catch(function (error) {
|
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
|
||||||
window.location.href = config.serverConfig.protocol + "://" + config.serverConfig.hostname + ':' + config.serverConfig.httpsPort+'/publisher/login';
|
|
||||||
} else {
|
|
||||||
message.error('Something went wrong when trying to load applications... :(');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getRelease = (uuid) => dispatch => {
|
|
||||||
|
|
||||||
const request = "method=get&content-type=application/json&payload={}&api-endpoint=/application-mgt-publisher/v1.0/applications/release/" + uuid;
|
|
||||||
|
|
||||||
return axios.post(
|
|
||||||
config.serverConfig.protocol + "://"+config.serverConfig.hostname + ':' + config.serverConfig.httpsPort + config.serverConfig.invoker.uri +config.serverConfig.invoker.publisher, request
|
|
||||||
).then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
let release = res.data.data;
|
|
||||||
dispatch({type: ActionTypes.GET_RELEASE, payload: release});
|
|
||||||
}
|
|
||||||
|
|
||||||
}).catch(function (error) {
|
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
|
||||||
window.location.href = config.serverConfig.protocol + "://" + config.serverConfig.hostname + ':' + config.serverConfig.httpsPort+'/publisher/login';
|
|
||||||
} else {
|
|
||||||
message.error('Something went wrong... :(');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
export const openReleasesModal = (app) => dispatch => {
|
|
||||||
dispatch({
|
|
||||||
type: ActionTypes.OPEN_RELEASES_MODAL,
|
|
||||||
payload: {
|
|
||||||
app: app
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
export const openLifecycleModal = (nextState) => dispatch => {
|
|
||||||
dispatch({
|
|
||||||
type: ActionTypes.OPEN_LIFECYCLE_MODAL,
|
|
||||||
payload: {
|
|
||||||
nextState: nextState
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const closeLifecycleModal = () => dispatch => {
|
|
||||||
dispatch({
|
|
||||||
type: ActionTypes.CLOSE_LIFECYCLE_MODAL
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
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(
|
|
||||||
config.serverConfig.protocol + "://"+config.serverConfig.hostname + ':' + config.serverConfig.httpsPort + config.serverConfig.invoker.uri +config.serverConfig.invoker.publisher, request
|
|
||||||
).then(res => {
|
|
||||||
if (res.status === 200) {
|
|
||||||
let lifecycle = res.data.data;
|
|
||||||
dispatch({type: ActionTypes.GET_LIFECYCLE, payload: lifecycle});
|
|
||||||
}
|
|
||||||
|
|
||||||
}).catch(function (error) {
|
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
|
||||||
window.location.href = config.serverConfig.protocol + "://" + config.serverConfig.hostname + ':' + config.serverConfig.httpsPort+'/publisher/login';
|
|
||||||
} else {
|
|
||||||
message.error('Something went wrong... :(');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const updateLifecycleState = (uuid, nextState, reason) => dispatch => {
|
|
||||||
|
|
||||||
const payload = {
|
|
||||||
action: nextState,
|
|
||||||
reason: reason
|
|
||||||
};
|
|
||||||
|
|
||||||
const request = "method=post&content-type=application/json&payload=" + JSON.stringify(payload) + "&api-endpoint=/application-mgt-publisher/v1.0/applications/life-cycle/" + uuid;
|
|
||||||
|
|
||||||
|
|
||||||
return axios.post(
|
|
||||||
config.serverConfig.protocol + "://"+config.serverConfig.hostname + ':' + config.serverConfig.httpsPort + config.serverConfig.invoker.uri +config.serverConfig.invoker.publisher, request
|
|
||||||
).then(res => {
|
|
||||||
if (res.status === 201) {
|
|
||||||
let release = res.data.data;
|
|
||||||
dispatch({type: ActionTypes.UPDATE_LIFECYCLE_STATE, payload: release});
|
|
||||||
}else {
|
|
||||||
alert("error");
|
|
||||||
dispatch({
|
|
||||||
type: ActionTypes.CLOSE_LIFECYCLE_MODAL
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}).catch(function (error) {
|
|
||||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
|
||||||
window.location.href = config.serverConfig.protocol + "://" + config.serverConfig.hostname + ':' + config.serverConfig.httpsPort+'/publisher/login';
|
|
||||||
} else if (error.response.status === 500) {
|
|
||||||
alert("error");
|
|
||||||
dispatch({
|
|
||||||
type: ActionTypes.CLOSE_LIFECYCLE_MODAL
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
};
|
|
@ -1,15 +0,0 @@
|
|||||||
import keyMirror from 'keymirror';
|
|
||||||
|
|
||||||
const ActionTypes = keyMirror({
|
|
||||||
LOGIN: null,
|
|
||||||
GET_APPS: null,
|
|
||||||
OPEN_RELEASES_MODAL: null,
|
|
||||||
CLOSE_RELEASES_MODAL: null,
|
|
||||||
GET_RELEASE: null,
|
|
||||||
GET_LIFECYCLE: null,
|
|
||||||
OPEN_LIFECYCLE_MODAL: null,
|
|
||||||
CLOSE_LIFECYCLE_MODAL: null,
|
|
||||||
UPDATE_LIFECYCLE_STATE: null,
|
|
||||||
});
|
|
||||||
|
|
||||||
export default ActionTypes;
|
|
@ -1,64 +0,0 @@
|
|||||||
import ActionTypes from "../constants/ActionTypes";
|
|
||||||
|
|
||||||
const initialState = {
|
|
||||||
apps: [],
|
|
||||||
releaseView: {
|
|
||||||
visible: false,
|
|
||||||
app: null
|
|
||||||
},
|
|
||||||
release: null,
|
|
||||||
lifecycle: null,
|
|
||||||
lifecycleModal:{
|
|
||||||
visible: false,
|
|
||||||
nextState: null
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function rootReducer(state = initialState, action) {
|
|
||||||
if (action.type === ActionTypes.GET_APPS) {
|
|
||||||
return Object.assign({}, state, {
|
|
||||||
apps: action.payload
|
|
||||||
});
|
|
||||||
} else if (action.type === ActionTypes.OPEN_RELEASES_MODAL) {
|
|
||||||
return Object.assign({}, state, {
|
|
||||||
releaseView: {
|
|
||||||
visible: true,
|
|
||||||
app: action.payload.app
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else if (action.type === ActionTypes.GET_RELEASE) {
|
|
||||||
return Object.assign({}, state, {
|
|
||||||
release: action.payload
|
|
||||||
});
|
|
||||||
} else if (action.type === ActionTypes.GET_LIFECYCLE) {
|
|
||||||
return Object.assign({}, state, {
|
|
||||||
lifecycle: action.payload
|
|
||||||
});
|
|
||||||
}else if (action.type === ActionTypes.OPEN_LIFECYCLE_MODAL) {
|
|
||||||
return Object.assign({}, state, {
|
|
||||||
lifecycleModal: {
|
|
||||||
visible: true,
|
|
||||||
nextState: action.payload.nextState
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}else if (action.type === ActionTypes.CLOSE_LIFECYCLE_MODAL) {
|
|
||||||
return Object.assign({}, state, {
|
|
||||||
lifecycleModal: {
|
|
||||||
visible: false,
|
|
||||||
nextState: null
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}else if (action.type === ActionTypes.UPDATE_LIFECYCLE_STATE) {
|
|
||||||
return Object.assign({}, state, {
|
|
||||||
lifecycleModal: {
|
|
||||||
visible: false,
|
|
||||||
nextState: null,
|
|
||||||
},
|
|
||||||
release: action.payload
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export default rootReducer;
|
|
@ -1,5 +0,0 @@
|
|||||||
import { createStore, applyMiddleware } from "redux";
|
|
||||||
import rootReducer from "../reducers/index";
|
|
||||||
import thunk from "redux-thunk";
|
|
||||||
const store = createStore(rootReducer, applyMiddleware(thunk));
|
|
||||||
export default store;
|
|
@ -1,56 +0,0 @@
|
|||||||
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)
|
|
||||||
);
|
|
||||||
}
|
|
Loading…
Reference in new issue