Add improvements to add & edit application forms in APPM UI

- Remove price field and tenancy sharing switch
- Make supported OS versions a required field
feature/appm-store/pbac
Jayasanka 5 years ago
parent d43bfecda9
commit dfc4ce98cb

@ -57,10 +57,10 @@ class ListApps extends React.Component {
return (
<Card>
<Row gutter={28}>
<Col md={7}>
<Col md={6}>
<Filters setFilters={this.setFilters}/>
</Col>
<Col md={17}>
<Col md={18}>
<Row>
<Col span={6}>
<Title level={4}>Apps</Title>

@ -59,7 +59,7 @@ function getBase64(file) {
}
class EditReleaseModal extends React.Component {
// To add subscription type & tenancy sharing, refer https://gitlab.com/entgra/carbon-device-mgt/merge_requests/331
constructor(props) {
super(props);
this.state = {
@ -162,12 +162,6 @@ class EditReleaseModal extends React.Component {
},
releaseDescription: {
value: release.description
},
price: {
value: release.price
},
isSharedWithAllTenants: {
value: release.isSharedWithAllTenants
}
});
@ -252,7 +246,7 @@ class EditReleaseModal extends React.Component {
this.setState({
loading: true
});
const {price, isSharedWithAllTenants, releaseDescription, releaseType} = values;
const {releaseDescription, releaseType} = values;
const {icons, screenshots, binaryFiles} = this.state;
@ -261,8 +255,8 @@ class EditReleaseModal extends React.Component {
//add release data
const release = {
description: releaseDescription,
price: (price === undefined) ? 0 : parseInt(price),
isSharedWithAllTenants,
price: 0,
isSharedWithAllTenants: false,
metaData: JSON.stringify(this.state.metaData),
releaseType: releaseType,
};
@ -282,10 +276,6 @@ class EditReleaseModal extends React.Component {
if (specificElements.hasOwnProperty("url")) {
release.url = values.url;
}
//
// if (specificElements.hasOwnProperty("packageName")) {
// release.packageName = values.packageName;
// }
if (icons.length === 1) {
data.append('icon', icons[0].originFileObj);
@ -589,30 +579,6 @@ class EditReleaseModal extends React.Component {
)}
</Form.Item>
)}
<Form.Item {...formItemLayout} label="Price">
{getFieldDecorator('price', {
rules: [{
required: false
}],
})(
<Input prefix="$" placeholder="00.00"/>
)}
</Form.Item>
<Form.Item {...formItemLayout} label="Is Shared?">
{getFieldDecorator('isSharedWithAllTenants', {
rules: [{
required: true,
message: 'Please select'
}],
initialValue: false
})(
<Switch checkedChildren={<Icon type="check"/>}
unCheckedChildren={<Icon type="close"/>}
/>
)}
</Form.Item>
<Form.Item {...formItemLayout} label="Meta Data">
{getFieldDecorator('meta', {
rules: [{

@ -17,24 +17,37 @@
*/
import React from "react";
import {Button, Col, Form, Icon, Input, Row, Select, Switch, Upload, InputNumber, Modal} from "antd";
import "@babel/polyfill";
import {
Modal,
Button,
Icon,
notification,
Spin,
Tooltip,
Upload,
Input,
Switch,
Form,
Divider,
Row,
Col,
Select
} from 'antd';
import axios from "axios";
import {handleApiError} from "../../../js/Utils";
import {withConfigContext} from "../../../../context/ConfigContext";
const {TextArea} = Input;
const InputGroup = Input.Group;
const {Option} = Select;
const formItemLayout = {
labelCol: {
xs: {span: 24},
sm: {span: 8},
span: 8,
},
wrapperCol: {
xs: {span: 24},
sm: {span: 16},
span: 16,
},
};
const {Option} = Select;
const {TextArea} = Input;
const InputGroup = Input.Group;
function getBase64(file) {
return new Promise((resolve, reject) => {
@ -45,30 +58,168 @@ function getBase64(file) {
});
}
class NewAppUploadForm extends React.Component {
class EditReleaseModal extends React.Component {
// To add subscription type & tenancy sharing, refer https://gitlab.com/entgra/carbon-device-mgt/merge_requests/331
constructor(props) {
super(props);
this.state = {
visible: false,
current: 0,
categories: [],
tags: [],
icons: [],
screenshots: [],
loading: false,
binaryFiles: [],
application: null,
isFree: true,
previewVisible: false,
previewImage: '',
binaryFileHelperText: '',
iconHelperText: '',
screenshotHelperText: '',
osVersionsHelperText: '',
osVersionsValidateStatus: 'validating',
metaData: []
metaData: [],
formConfig: {
specificElements: {}
}
};
this.lowerOsVersion = null;
this.upperOsVersion = null;
}
componentDidMount = () => {
this.generateConfig();
};
generateConfig = () => {
const {type} = this.props;
const formConfig = {
type
};
switch (type) {
case "ENTERPRISE":
formConfig.endpoint = "/ent-app-release";
formConfig.specificElements = {
binaryFile: {
required: true
}
};
break;
case "PUBLIC":
formConfig.endpoint = "/public-app-release";
formConfig.specificElements = {
packageName: {
required: true
},
version: {
required: true
}
};
break;
case "WEB_CLIP":
formConfig.endpoint = "/web-app-release";
formConfig.specificElements = {
version: {
required: true
},
url: {
required: true
}
};
break;
case "CUSTOM":
formConfig.endpoint = "/custom-app-release";
formConfig.specificElements = {
binaryFile: {
required: true
},
packageName: {
required: true
},
version: {
required: true
}
};
break;
}
this.setState({
formConfig
});
};
showModal = () => {
const config = this.props.context;
const {app, release} = this.props;
const {formConfig} = this.state;
const {specificElements} = formConfig;
let metaData = [];
try {
metaData = JSON.parse(release.metaData);
} catch (e) {
}
this.props.form.setFields({
releaseType: {
value: release.releaseType
},
releaseDescription: {
value: release.description
}
});
if ((config.deviceTypes.mobileTypes.includes(this.props.deviceType))) {
const osVersions = release.supportedOsVersions.split("-");
this.lowerOsVersion = osVersions[0];
this.upperOsVersion = osVersions[1];
this.props.form.setFields({
lowerOsVersion: {
value: osVersions[0]
},
upperOsVersion: {
value: osVersions[1]
}
});
}
if (specificElements.hasOwnProperty("version")) {
this.props.form.setFields({
version: {
value: release.version
}
});
}
if (specificElements.hasOwnProperty("url")) {
this.props.form.setFields({
url: {
value: release.url
}
});
}
if (specificElements.hasOwnProperty("packageName")) {
this.props.form.setFields({
packageName: {
value: release.packageName
}
});
}
this.setState({
visible: true,
metaData
});
};
handleOk = e => {
this.setState({
visible: false,
});
};
handleCancel = e => {
this.setState({
visible: false,
});
};
normFile = e => {
if (Array.isArray(e)) {
return e;
@ -76,9 +227,18 @@ class NewAppUploadForm extends React.Component {
return e && e.fileList;
};
handleIconChange = ({fileList}) => this.setState({icons: fileList});
handleBinaryFileChange = ({fileList}) => this.setState({binaryFiles: fileList});
handleScreenshotChange = ({fileList}) => this.setState({screenshots: fileList});
handleSubmit = e => {
e.preventDefault();
const {formConfig} = this.props;
const {uuid} = this.props.release;
const config = this.props.context;
const {formConfig} = this.state;
const {specificElements} = formConfig;
this.props.form.validateFields((err, values) => {
@ -86,123 +246,110 @@ class NewAppUploadForm extends React.Component {
this.setState({
loading: true
});
const {price, isSharedWithAllTenants, binaryFile, icon, screenshots, releaseDescription, releaseType} = values;
const {releaseDescription, releaseType} = values;
const {icons, screenshots, binaryFiles} = this.state;
const data = new FormData();
//add release data
const release = {
description: releaseDescription,
price: (price === undefined) ? 0 : parseInt(price),
isSharedWithAllTenants,
price: 0,
isSharedWithAllTenants: false,
metaData: JSON.stringify(this.state.metaData),
releaseType: releaseType
releaseType: releaseType,
};
if ((config.deviceTypes.mobileTypes.includes(this.props.deviceType))) {
release.supportedOsVersions = `${this.lowerOsVersion}-${this.upperOsVersion}`;
}
if (specificElements.hasOwnProperty("binaryFile") && binaryFiles.length === 1) {
data.append('binaryFile', binaryFiles[0].originFileObj);
}
if (specificElements.hasOwnProperty("version")) {
release.version = values.version;
}
if (specificElements.hasOwnProperty("url")) {
release.url = values.url;
}
if (specificElements.hasOwnProperty("packageName")) {
release.packageName = values.packageName;
}
const data = new FormData();
let isFormValid = true; // flag to check if this form is valid
if (icons.length === 1) {
data.append('icon', icons[0].originFileObj);
}
if (formConfig.installationType !== "WEB_CLIP" && formConfig.installationType !== "CUSTOM") {
if(this.lowerOsVersion==null || this.upperOsVersion==null){
isFormValid = false;
this.setState({
osVersionsHelperText: 'Please select supported OS versions',
osVersionsValidateStatus: 'error',
});
}else if(this.lowerOsVersion>=this.upperOsVersion){
isFormValid = false;
this.setState({
osVersionsHelperText: 'Please select valid range',
osVersionsValidateStatus: 'error',
});
}else{
release.supportedOsVersions = `${this.lowerOsVersion}-${this.upperOsVersion}`;
if (screenshots.length > 0) {
data.append('screenshot1', screenshots[0].originFileObj);
}
if (screenshots.length > 1) {
data.append('screenshot2', screenshots[1].originFileObj);
}
if (specificElements.hasOwnProperty("binaryFile") && this.state.binaryFiles.length !== 1) {
isFormValid = false;
this.setState({
binaryFileHelperText: 'Please select the application'
});
if (screenshots.length > 2) {
data.append('screenshot3', screenshots[2].originFileObj);
}
if (this.state.icons.length !== 1) {
isFormValid = false;
this.setState({
iconHelperText: 'Please select an icon'
const json = JSON.stringify(release);
const blob = new Blob([json], {
type: 'application/json'
});
}
if (this.state.screenshots.length !== 3) {
isFormValid = false;
data.append("applicationRelease", blob);
const url = window.location.origin + config.serverConfig.invoker.uri + config.serverConfig.invoker.publisher + "/applications" + formConfig.endpoint + "/" + uuid;
axios.put(
url,
data
).then(res => {
if (res.status === 200) {
const updatedRelease = res.data.data;
this.setState({
screenshotHelperText: 'Please select 3 screenshots'
loading: false,
visible: false,
});
}
if (this.state.screenshots.length !== 3) {
isFormValid = false;
this.setState({
screenshotHelperText: 'Please select 3 screenshots'
notification["success"]({
message: "Done!",
description:
"Saved!",
});
// console.log(updatedRelease);
this.props.updateRelease(updatedRelease);
}
if(isFormValid) {
data.append('icon', icon[0].originFileObj);
data.append('screenshot1', screenshots[0].originFileObj);
data.append('screenshot2', screenshots[1].originFileObj);
data.append('screenshot3', screenshots[2].originFileObj);
if (specificElements.hasOwnProperty("binaryFile")) {
data.append('binaryFile', binaryFile[0].originFileObj);
}
this.props.onSuccessReleaseData({data, release});
}
}
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
window.location.href = window.location.origin + '/publisher/login';
} else {
notification["error"]({
message: "Something went wrong!",
description:
"Sorry, we were unable to complete your request.",
});
};
handleIconChange = ({fileList}) => {
if (fileList.length === 1) {
this.setState({
iconHelperText: ''
});
}
this.setState({
icons: fileList
loading: false
});
};
handleBinaryFileChange = ({fileList}) => {
if (fileList.length === 1) {
this.setState({
binaryFileHelperText: ''
});
}
this.setState({binaryFiles: fileList});
};
handleScreenshotChange = ({fileList}) => {
if (fileList.length === 3) {
this.setState({
screenshotHelperText: ''
});
}
this.setState({
screenshots: fileList
});
};
handlePriceTypeChange = (value) => {
addNewMetaData = () => {
this.setState({
isFree: (value === 'free')
});
metaData: this.state.metaData.concat({'key': '', 'value': ''})
})
};
handlePreviewCancel = () => this.setState({previewVisible: false});
handlePreview = async file => {
if (!file.url && !file.preview) {
file.preview = await getBase64(file.originFileObj);
@ -214,45 +361,31 @@ class NewAppUploadForm extends React.Component {
});
};
addNewMetaData = () => {
this.setState({
metaData: this.state.metaData.concat({'key': '', 'value': ''})
})
};
handleLowerOsVersionChange = (lowerOsVersion) => {
this.lowerOsVersion = parseFloat(lowerOsVersion);
this.setState({
osVersionsValidateStatus: 'validating',
osVersionsHelperText: ''
});
this.lowerOsVersion = lowerOsVersion;
};
handleUpperOsVersionChange = (upperOsVersion) => {
this.upperOsVersion = parseFloat(upperOsVersion);
this.setState({
osVersionsValidateStatus: 'validating',
osVersionsHelperText: ''
});
this.upperOsVersion = upperOsVersion;
};
render() {
const {formConfig, supportedOsVersions} = this.props;
const {getFieldDecorator} = this.props.form;
const {
formConfig,
icons,
screenshots,
loading,
binaryFiles,
isFree,
metaData,
previewImage,
previewVisible,
binaryFileHelperText,
iconHelperText,
screenshotHelperText,
metaData,
osVersionsHelperText,
osVersionsValidateStatus
screenshotHelperText
} = this.state;
const {getFieldDecorator} = this.props.form;
const {isAppUpdatable, supportedOsVersions, deviceType} = this.props;
const config = this.props.context;
const uploadButton = (
<div>
<Icon type="plus"/>
@ -262,20 +395,26 @@ class NewAppUploadForm extends React.Component {
return (
<div>
<Row>
<Col md={5}>
</Col>
<Col md={14}>
<Form
labelAlign="right"
layout="horizontal"
<Tooltip title={isAppUpdatable ? "Edit this release" : "This release isn't in an editable state"}>
<Button
disabled={!isAppUpdatable}
size="small" type="primary" onClick={this.showModal}>
<Icon type="edit"/> Edit
</Button>
</Tooltip>
<Modal
title="Edit release"
visible={this.state.visible}
footer={null}
width={580}
onCancel={this.handleCancel}>
<div>
<Spin tip="Uploading..." spinning={loading}>
<Form labelAlign="left" layout="horizontal"
hideRequiredMark
onSubmit={this.handleSubmit}>
{formConfig.specificElements.hasOwnProperty("binaryFile") && (
<Form.Item {...formItemLayout}
label="Application"
validateStatus="error"
help={binaryFileHelperText}>
<Form.Item {...formItemLayout} label="Application">
{getFieldDecorator('binaryFile', {
valuePropName: 'binaryFile',
getValueFromEvent: this.normFile,
@ -285,10 +424,11 @@ class NewAppUploadForm extends React.Component {
<Upload
name="binaryFile"
onChange={this.handleBinaryFileChange}
beforeUpload={() => false}>
beforeUpload={() => false}
>
{binaryFiles.length !== 1 && (
<Button>
<Icon type="upload"/> Click to upload
<Icon type="upload"/> Change
</Button>
)}
</Upload>,
@ -296,10 +436,33 @@ class NewAppUploadForm extends React.Component {
</Form.Item>
)}
<Form.Item {...formItemLayout}
label="Icon"
validateStatus="error"
help={iconHelperText}>
{formConfig.specificElements.hasOwnProperty("url") && (
<Form.Item {...formItemLayout} label="URL">
{getFieldDecorator('url', {
rules: [{
required: true,
message: 'Please input the url'
}],
})(
<Input placeholder="url"/>
)}
</Form.Item>
)}
{formConfig.specificElements.hasOwnProperty("version") && (
<Form.Item {...formItemLayout} label="Version">
{getFieldDecorator('version', {
rules: [{
required: true,
message: 'Please input the version'
}],
})(
<Input placeholder="Version"/>
)}
</Form.Item>
)}
<Form.Item {...formItemLayout} label="Icon">
{getFieldDecorator('icon', {
valuePropName: 'icon',
getValueFromEvent: this.normFile,
@ -317,10 +480,7 @@ class NewAppUploadForm extends React.Component {
)}
</Form.Item>
<Form.Item {...formItemLayout}
label="Screenshots"
validateStatus="error"
help={screenshotHelperText}>
<Form.Item {...formItemLayout} label="Screenshots">
{getFieldDecorator('screenshots', {
valuePropName: 'icon',
getValueFromEvent: this.normFile,
@ -338,45 +498,6 @@ class NewAppUploadForm extends React.Component {
)}
</Form.Item>
{formConfig.specificElements.hasOwnProperty("packageName") && (
<Form.Item {...formItemLayout} label="Package Name">
{getFieldDecorator('packageName', {
rules: [{
required: true,
message: 'Please input the package name'
}],
})(
<Input placeholder="Package Name"/>
)}
</Form.Item>
)}
{formConfig.specificElements.hasOwnProperty("url") && (
<Form.Item {...formItemLayout} label="URL">
{getFieldDecorator('url', {
rules: [{
required: true,
message: 'Please input the url'
}],
})(
<Input placeholder="url"/>
)}
</Form.Item>
)}
{formConfig.specificElements.hasOwnProperty("version") && (
<Form.Item {...formItemLayout} label="Version">
{getFieldDecorator('version', {
rules: [{
required: true,
message: 'Please input the version'
}],
})(
<Input placeholder="Version"/>
)}
</Form.Item>
)}
<Form.Item {...formItemLayout} label="Release Type">
{getFieldDecorator('releaseType', {
rules: [{
@ -395,21 +516,24 @@ class NewAppUploadForm extends React.Component {
message: 'Please enter a description for release'
}],
})(
<TextArea placeholder="Enter a description for release" rows={5}/>
<TextArea placeholder="Enter a description for release"
rows={5}/>
)}
</Form.Item>
{(formConfig.installationType !== "WEB_CLIP" && formConfig.installationType !== "CUSTOM") && (
<Form.Item
{...formItemLayout}
label="Supported OS Versions"
validateStatus={osVersionsValidateStatus}
help={osVersionsHelperText}>
{(config.deviceTypes.mobileTypes.includes(deviceType)) && (
<Form.Item {...formItemLayout} label="Supported OS Versions">
{getFieldDecorator('supportedOS')(
<div>
<InputGroup>
<Row gutter={8}>
<Col span={11}>
<Form.Item>
{getFieldDecorator('lowerOsVersion', {
rules: [{
required: true,
message: 'Please select Value'
}],
})(
<Select
placeholder="Lower version"
style={{width: "100%"}}
@ -421,11 +545,20 @@ class NewAppUploadForm extends React.Component {
</Option>
))}
</Select>
)}
</Form.Item>
</Col>
<Col span={2}>
<p> - </p>
</Col>
<Col span={11}>
<Form.Item>
{getFieldDecorator('upperOsVersion', {
rules: [{
required: true,
message: 'Please select Value'
}],
})(
<Select style={{width: "100%"}}
placeholder="Upper version"
onChange={this.handleUpperOsVersionChange}>
@ -436,6 +569,9 @@ class NewAppUploadForm extends React.Component {
</Option>
))}
</Select>
)}
</Form.Item>
</Col>
</Row>
</InputGroup>
@ -443,58 +579,21 @@ class NewAppUploadForm extends React.Component {
)}
</Form.Item>
)}
<Form.Item {...formItemLayout} label="Price Type">
{getFieldDecorator('select', {
rules: [{required: true, message: 'Please select price Type'}],
})(
<Select
placeholder="Please select a price type"
onChange={this.handlePriceTypeChange}>
<Option value="free">Free</Option>
<Option value="paid">Paid</Option>
</Select>,
)}
</Form.Item>
<Form.Item {...formItemLayout} label="Price">
{getFieldDecorator('price', {
rules: [{
required: !isFree
}],
})(
<InputNumber
disabled={isFree}
options={{
initialValue: 1
}}
min={0}
max={10000}
formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
parser={value => value.replace(/\$\s?|(,*)/g, '')}
/>
)}
</Form.Item>
<Form.Item {...formItemLayout} label="Is Shared?">
{getFieldDecorator('isSharedWithAllTenants', {
<Form.Item {...formItemLayout} label="Meta Data">
{getFieldDecorator('meta', {
rules: [{
required: true,
message: 'Please select'
message: 'Please fill empty fields'
}],
initialValue: false
})(
<Switch checkedChildren={<Icon type="check"/>}
unCheckedChildren={<Icon type="close"/>}
/>
)}
</Form.Item>
<Form.Item {...formItemLayout} label="Meta Data">
{getFieldDecorator('meta', {})(
<div>
{
metaData.map((data, index) => {
return (
<InputGroup key={index}>
<Row gutter={8}>
<Col span={5}>
<Col span={10}>
<Input
placeholder="key"
value={data.key}
@ -505,7 +604,7 @@ class NewAppUploadForm extends React.Component {
})
}}/>
</Col>
<Col span={8}>
<Col span={10}>
<Input
placeholder="value"
value={data.value}
@ -538,26 +637,32 @@ class NewAppUploadForm extends React.Component {
</Button>
</div>
)}
</Form.Item>
<Divider/>
<Form.Item style={{float: "right", marginLeft: 8}}>
<Button type="primary" htmlType="submit">
Submit
Update
</Button>
</Form.Item>
<Form.Item style={{float: "right"}}>
<Button htmlType="button" onClick={this.props.onClickBackButton}>
<Button htmlType="button" onClick={this.handleCancel}>
Back
</Button>
</Form.Item>
<br/>
</Form>
</Col>
</Row>
</Spin>
</div>
<Modal visible={previewVisible} footer={null} onCancel={this.handlePreviewCancel}>
<img alt="Preview Image" style={{width: '100%'}} src={previewImage}/>
</Modal>
</Modal>
</div>
);
}
}
export default (Form.create({name: 'app-upload-form'})(NewAppUploadForm));
const EditRelease = withConfigContext(Form.create({name: 'add-new-release'})(EditReleaseModal));
export default EditRelease;

Loading…
Cancel
Save