Improve lifecycle changing UX

revert-70ac1926
shamalka 5 years ago
parent f6da863e3a
commit 4e3a45fa93

@ -40,28 +40,52 @@
}, },
"lifecycle": { "lifecycle": {
"CREATED": { "CREATED": {
"text": "The initial most state of an application." "title": "Created",
"text": "The initial most state of an application.\n You can only proceed to one of the following states:",
"icon": "file-text",
"step": 0
}, },
"IN-REVIEW": { "IN-REVIEW": {
"text": "This state can be applied when the application is being reviewed by approvers." "title": "In-Review",
"text": "This state can be applied when the application is being reviewed by approvers.\n You can only proceed to one of the following states:",
"icon": "audit",
"step": 1
}, },
"APPROVED": { "APPROVED": {
"text": "The approved state is a compulsory state prior to publishing the application." "title": "Approved",
}, "text": "The approved state is a compulsory state prior to publishing the application.\n You can only proceed to one of the following states:",
"REJECTED": { "icon": "file-done",
"text": "The Approvers can reject an application due to a faulty of the app or not being in compliance with company policies." "step": 2
}, },
"PUBLISHED": { "PUBLISHED": {
"text": "The state which is applied for applications which are qualified for your Corporate App Store. Only the applications of Published state can be installed to your corporate devices." "title": "Published",
"text": "The state which is applied for applications which are qualified for your Corporate App Store. Only the applications of Published state can be installed to your corporate devices.\n You can only proceed to one of the following states:",
"icon": "global",
"step": 3
}, },
"BLOCKED": { "BLOCKED": {
"text": "This state allows you to block your application either to publish or deprecate at a future date." "title": "Blocked",
"text": "This state allows you to block your application either to publish or deprecate at a future date.\n You can only proceed to one of the following states:",
"icon": "exception",
"step": 4
}, },
"DEPRECATED": { "DEPRECATED": {
"text": "The applications which are outdated and no longer suit your app store." "title": "Deprecated",
"text": "The applications which are outdated and no longer suit your app store.\n You can only proceed to one of the following states:",
"icon": "file-excel",
"step": 5
},
"REJECTED": {
"title": "Rejected",
"text": "The Approvers can reject an application due to a faulty of the app or not being in compliance with company policies.\n You can only proceed to one of the following states:",
"icon": "frown",
"step": 6
}, },
"RETIRED": { "RETIRED": {
"text": "The final state of an application, where no transition of states will be allowed after this." "title": "Retired",
"text": "The final state of an application, where no transition of states will be allowed after this.\n You can only proceed to one of the following states:",
"icon": "rest",
"step": 7
} }
}, },
"deviceTypes": { "deviceTypes": {

@ -21,21 +21,21 @@ import {
Typography, Typography,
Tag, Tag,
Divider, Divider,
Select,
Button, Button,
Modal, Modal,
notification, notification,
Steps,
Icon,
Alert,
} from 'antd'; } from 'antd';
import axios from 'axios'; import axios from 'axios';
import ReactQuill from 'react-quill'; import ReactQuill from 'react-quill';
import 'react-quill/dist/quill.snow.css'; import 'react-quill/dist/quill.snow.css';
import './styles.css'; import './styles.css';
import LifeCycleDetailsModal from './components/lifeCycleDetailsModal';
import { withConfigContext } from '../../../../../../../../components/ConfigContext'; import { withConfigContext } from '../../../../../../../../components/ConfigContext';
import { handleApiError } from '../../../../../../../../services/utils/errorHandler'; import { handleApiError } from '../../../../../../../../services/utils/errorHandler';
const { Text, Title, Paragraph } = Typography; const { Text, Title, Paragraph } = Typography;
const { Option } = Select;
const modules = { const modules = {
toolbar: [ toolbar: [
@ -60,6 +60,8 @@ const formats = [
'image', 'image',
]; ];
const { Step } = Steps;
class LifeCycle extends React.Component { class LifeCycle extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
@ -69,9 +71,23 @@ class LifeCycle extends React.Component {
reasonText: '', reasonText: '',
isReasonModalVisible: false, isReasonModalVisible: false,
isConfirmButtonLoading: false, isConfirmButtonLoading: false,
current: 0,
lifecycleSteps: [],
}; };
} }
componentDidMount() {
const config = this.props.context;
const lifeCycleConfig = config.lifecycle;
const lifecycleSteps = Object.keys(lifeCycleConfig).map(config => {
return lifeCycleConfig[config];
});
this.setState({
current: lifeCycleConfig[this.props.currentStatus].step,
lifecycleSteps,
});
}
componentDidUpdate(prevProps, prevState, snapshot) { componentDidUpdate(prevProps, prevState, snapshot) {
if ( if (
prevProps.currentStatus !== this.props.currentStatus || prevProps.currentStatus !== this.props.currentStatus ||
@ -87,12 +103,9 @@ class LifeCycle extends React.Component {
this.setState({ reasonText: value }); this.setState({ reasonText: value });
}; };
handleSelectChange = value => { showReasonModal = lifecycleState => {
this.setState({ selectedStatus: value });
};
showReasonModal = () => {
this.setState({ this.setState({
selectedStatus: lifecycleState,
isReasonModalVisible: true, isReasonModalVisible: true,
}); });
}; };
@ -105,6 +118,7 @@ class LifeCycle extends React.Component {
addLifeCycle = () => { addLifeCycle = () => {
const config = this.props.context; const config = this.props.context;
const lifeCycleConfig = config.lifecycle;
const { selectedStatus, reasonText } = this.state; const { selectedStatus, reasonText } = this.state;
const { uuid } = this.props; const { uuid } = this.props;
const data = { const data = {
@ -128,6 +142,7 @@ class LifeCycle extends React.Component {
.then(res => { .then(res => {
if (res.status === 201) { if (res.status === 201) {
this.setState({ this.setState({
current: lifeCycleConfig[selectedStatus].step,
isReasonModalVisible: false, isReasonModalVisible: false,
isConfirmButtonLoading: false, isConfirmButtonLoading: false,
currentStatus: selectedStatus, currentStatus: selectedStatus,
@ -149,14 +164,18 @@ class LifeCycle extends React.Component {
}); });
}; };
onChange = current => {
this.setState({ current });
};
render() { render() {
const { const {
currentStatus, currentStatus,
selectedStatus, selectedStatus,
isConfirmButtonLoading, current,
lifecycleSteps,
} = this.state; } = this.state;
const { lifecycle } = this.props; const { lifecycle } = this.props;
const selectedValue = selectedStatus == null ? [] : selectedStatus;
let proceedingStates = []; let proceedingStates = [];
if ( if (
@ -176,43 +195,47 @@ class LifeCycle extends React.Component {
application. Have a thorough review and approval process before application. Have a thorough review and approval process before
directly publishing it to your app store. You can easily transition directly publishing it to your app store. You can easily transition
from one state to another. <br /> from one state to another. <br />
Note: Change State To displays only the next states allowed from the
current state
</Paragraph> </Paragraph>
{lifecycle !== null && <LifeCycleDetailsModal lifecycle={lifecycle} />} <Divider />
<Divider dashed={true} /> <div>
<Text strong={true}>Current State: </Text>{' '} <Steps
<Tag color="blue">{currentStatus}</Tag> direction={'vertical'}
<br /> current={current}
<br /> onChange={this.onChange}
<Text>Change State to: </Text> size="small"
<Select >
placeholder="Select state" {lifecycleSteps.map((step, index) => (
style={{ width: 120 }} <Step
size="small" key={index}
onChange={this.handleSelectChange} icon={<Icon type={step.icon} />}
value={selectedValue} title={step.title}
showSearch={true} disabled={current !== step.step}
> description={
{proceedingStates.map(lifecycleState => { current === step.step ? (
return ( <div style={{ width: 400 }}>
<Option key={lifecycleState} value={lifecycleState}> <p>{step.text}</p>
{lifecycleState} {proceedingStates.map(lifecycleState => {
</Option> return (
); <Button
})} size={'small'}
</Select> style={{ marginRight: 3 }}
<Button onClick={() => this.showReasonModal(lifecycleState)}
style={{ marginLeft: 10 }} key={lifecycleState}
size="small" type={'primary'}
type="primary" >
htmlType="button" {lifecycleState}
onClick={this.showReasonModal} </Button>
loading={isConfirmButtonLoading} );
disabled={selectedStatus == null} })}
> </div>
Change ) : (
</Button> ''
)
}
/>
))}
</Steps>
</div>
<Divider /> <Divider />
<Modal <Modal
title="Confirm changing lifecycle state" title="Confirm changing lifecycle state"
@ -228,7 +251,19 @@ class LifeCycle extends React.Component {
<Tag color="blue">{selectedStatus}</Tag> <Tag color="blue">{selectedStatus}</Tag>
</Text> </Text>
<br /> <br />
<br /> {lifecycle &&
selectedStatus &&
lifecycle[selectedStatus].isEndState ? (
<Alert
message="In this state application becomes completely obsolete. Be careful,
this process cannot be undone."
banner
style={{ marginTop: 5 }}
/>
) : (
<div />
)}
<Divider orientation="left">Reason</Divider>
<ReactQuill <ReactQuill
theme="snow" theme="snow"
value={this.state.reasonText} value={this.state.reasonText}

Loading…
Cancel
Save