Add UI improvements to edit release view in APPM UI

The following changes are with this commit.
- Add previews of selected images to upload
- Add supported OS versions field
feature/appm-store/pbac
Jayasanka Weerasinghe 5 years ago committed by Saad Sahibjan
parent ac0d01e1d5
commit f710c5489a

@ -28,6 +28,13 @@ import {withConfigContext} from "../../../context/ConfigContext";
const {Title, Text, Paragraph} = Typography; const {Title, Text, Paragraph} = Typography;
class ReleaseView extends React.Component { class ReleaseView extends React.Component {
constructor(props) {
super(props);
this.state = {
}
}
render() { render() {
const {app, release} = this.props; const {app, release} = this.props;
const config = this.props.context; const config = this.props.context;
@ -88,8 +95,10 @@ class ReleaseView extends React.Component {
<EditRelease <EditRelease
isAppUpdatable={isAppUpdatable} isAppUpdatable={isAppUpdatable}
type={app.type} type={app.type}
deviceType={app.deviceType}
release={release} release={release}
updateRelease={this.props.updateRelease} updateRelease={this.props.updateRelease}
supportedOsVersions={[...this.props.supportedOsVersions]}
/> />
</Col> </Col>

@ -17,12 +17,28 @@
*/ */
import React from "react"; import React from "react";
import {Modal, Button, Icon, notification, Spin, Tooltip, Upload, Input, Switch, Form, Divider, Row, Col} from 'antd'; import {
Modal,
Button,
Icon,
notification,
Spin,
Tooltip,
Upload,
Input,
Switch,
Form,
Divider,
Row,
Col,
Select
} from 'antd';
import axios from "axios"; import axios from "axios";
import {withConfigContext} from "../../../../context/ConfigContext"; import {withConfigContext} from "../../../../context/ConfigContext";
const {TextArea} = Input; const {TextArea} = Input;
const InputGroup = Input.Group; const InputGroup = Input.Group;
const {Option} = Select;
const formItemLayout = { const formItemLayout = {
labelCol: { labelCol: {
@ -33,6 +49,15 @@ const formItemLayout = {
}, },
}; };
function getBase64(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result);
reader.onerror = error => reject(error);
});
}
class EditReleaseModal extends React.Component { class EditReleaseModal extends React.Component {
constructor(props) { constructor(props) {
@ -51,6 +76,8 @@ class EditReleaseModal extends React.Component {
specificElements: {} specificElements: {}
} }
}; };
this.lowerOsVersion = null;
this.upperOsVersion = null;
} }
componentDidMount = () => { componentDidMount = () => {
@ -117,15 +144,16 @@ class EditReleaseModal extends React.Component {
showModal = () => { showModal = () => {
const config = this.props.context;
const {app, release} = this.props; const {app, release} = this.props;
const {formConfig} = this.state; const {formConfig} = this.state;
const {specificElements} = formConfig; const {specificElements} = formConfig;
let metaData = []; let metaData = [];
try{ try {
metaData =JSON.parse(release.metaData); metaData = JSON.parse(release.metaData);
}catch (e) { } catch (e) {
} }
this.props.form.setFields({ this.props.form.setFields({
@ -143,14 +171,19 @@ class EditReleaseModal extends React.Component {
} }
}); });
// if (specificElements.hasOwnProperty("packageName")) { if ((config.deviceTypes.mobileTypes.includes(this.props.deviceType))) {
// this.props.form.setFields({ const osVersions = release.supportedOsVersions.split("-");
// packageName: { this.lowerOsVersion = osVersions[0];
// value: app.packageName this.upperOsVersion = osVersions[1];
// } this.props.form.setFields({
// }); lowerOsVersion: {
// } value: osVersions[0]
},
upperOsVersion: {
value: osVersions[1]
}
});
}
if (specificElements.hasOwnProperty("version")) { if (specificElements.hasOwnProperty("version")) {
this.props.form.setFields({ this.props.form.setFields({
version: { version: {
@ -232,9 +265,12 @@ class EditReleaseModal extends React.Component {
isSharedWithAllTenants, isSharedWithAllTenants,
metaData: JSON.stringify(this.state.metaData), metaData: JSON.stringify(this.state.metaData),
releaseType: releaseType, releaseType: releaseType,
supportedOsVersions: "4-30"
}; };
if ((config.deviceTypes.mobileTypes.includes(this.props.deviceType))) {
release.supportedOsVersions = `${this.lowerOsVersion}-${this.upperOsVersion}`;
}
if (specificElements.hasOwnProperty("binaryFile") && binaryFiles.length === 1) { if (specificElements.hasOwnProperty("binaryFile") && binaryFiles.length === 1) {
data.append('binaryFile', binaryFiles[0].originFileObj); data.append('binaryFile', binaryFiles[0].originFileObj);
} }
@ -322,10 +358,50 @@ class EditReleaseModal extends React.Component {
}) })
}; };
handlePreviewCancel = () => this.setState({previewVisible: false});
handlePreview = async file => {
if (!file.url && !file.preview) {
file.preview = await getBase64(file.originFileObj);
}
this.setState({
previewImage: file.url || file.preview,
previewVisible: true,
});
};
handleLowerOsVersionChange = (lowerOsVersion) => {
this.lowerOsVersion = lowerOsVersion;
};
handleUpperOsVersionChange = (upperOsVersion) => {
this.upperOsVersion = upperOsVersion;
};
render() { render() {
const {formConfig, icons, screenshots, loading, binaryFiles, metaData} = this.state; const {
formConfig,
icons,
screenshots,
loading,
binaryFiles,
metaData,
previewImage,
previewVisible,
binaryFileHelperText,
iconHelperText,
screenshotHelperText
} = this.state;
const {getFieldDecorator} = this.props.form; const {getFieldDecorator} = this.props.form;
const {isAppUpdatable} = this.props; const {isAppUpdatable, supportedOsVersions, deviceType} = this.props;
const config = this.props.context;
const uploadButton = (
<div>
<Icon type="plus"/>
<div className="ant-upload-text">Select</div>
</div>
);
return ( return (
<div> <div>
@ -340,8 +416,8 @@ class EditReleaseModal extends React.Component {
title="Edit release" title="Edit release"
visible={this.state.visible} visible={this.state.visible}
footer={null} footer={null}
onCancel={this.handleCancel} width={580}
> onCancel={this.handleCancel}>
<div> <div>
<Spin tip="Uploading..." spinning={loading}> <Spin tip="Uploading..." spinning={loading}>
<Form labelAlign="left" layout="horizontal" <Form labelAlign="left" layout="horizontal"
@ -370,19 +446,6 @@ class EditReleaseModal extends React.Component {
</Form.Item> </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") && ( {formConfig.specificElements.hasOwnProperty("url") && (
<Form.Item {...formItemLayout} label="URL"> <Form.Item {...formItemLayout} label="URL">
{getFieldDecorator('url', { {getFieldDecorator('url', {
@ -418,19 +481,15 @@ class EditReleaseModal extends React.Component {
})( })(
<Upload <Upload
name="logo" name="logo"
listType="picture-card"
onChange={this.handleIconChange} onChange={this.handleIconChange}
beforeUpload={() => false} beforeUpload={() => false}
> onPreview={this.handlePreview}>
{icons.length !== 1 && ( {icons.length === 1 ? null : uploadButton}
<Button>
<Icon type="upload"/> Change
</Button>
)}
</Upload>, </Upload>,
)} )}
</Form.Item> </Form.Item>
<Form.Item {...formItemLayout} label="Screenshots"> <Form.Item {...formItemLayout} label="Screenshots">
{getFieldDecorator('screenshots', { {getFieldDecorator('screenshots', {
valuePropName: 'icon', valuePropName: 'icon',
@ -440,15 +499,11 @@ class EditReleaseModal extends React.Component {
})( })(
<Upload <Upload
name="screenshots" name="screenshots"
listType="picture-card"
onChange={this.handleScreenshotChange} onChange={this.handleScreenshotChange}
beforeUpload={() => false} beforeUpload={() => false}
multiple onPreview={this.handlePreview}>
> {screenshots.length >= 3 ? null : uploadButton}
{screenshots.length < 3 && (
<Button>
<Icon type="upload"/> Click to upload
</Button>
)}
</Upload>, </Upload>,
)} )}
</Form.Item> </Form.Item>
@ -475,7 +530,65 @@ class EditReleaseModal extends React.Component {
rows={5}/> rows={5}/>
)} )}
</Form.Item> </Form.Item>
{(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%"}}
onChange={this.handleLowerOsVersionChange}>
{supportedOsVersions.map(version => (
<Option key={version.versionName}
value={version.versionName}>
{version.versionName}
</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}>
{supportedOsVersions.map(version => (
<Option key={version.versionName}
value={version.versionName}>
{version.versionName}
</Option>
))}
</Select>
)}
</Form.Item>
</Col>
</Row>
</InputGroup>
</div>
)}
</Form.Item>
)}
<Form.Item {...formItemLayout} label="Price"> <Form.Item {...formItemLayout} label="Price">
{getFieldDecorator('price', { {getFieldDecorator('price', {
rules: [{ rules: [{
@ -575,6 +688,9 @@ class EditReleaseModal extends React.Component {
</Form> </Form>
</Spin> </Spin>
</div> </div>
<Modal visible={previewVisible} footer={null} onCancel={this.handlePreviewCancel}>
<img alt="Preview Image" style={{width: '100%'}} src={previewImage}/>
</Modal>
</Modal> </Modal>
</div> </div>
); );

@ -37,7 +37,6 @@ class LifeCycleDetailsModal extends React.Component {
}; };
handleCancel = e => { handleCancel = e => {
console.log(e);
this.setState({ this.setState({
visible: false, visible: false,
}); });

@ -39,7 +39,6 @@ class AddNewPage extends React.Component {
handleCancel = e => { handleCancel = e => {
console.log(e);
this.setState({ this.setState({
visible: false, visible: false,
}); });

@ -37,14 +37,12 @@ class GooglePlayIframe extends React.Component {
}; };
handleOk = e => { handleOk = e => {
console.log(e);
this.setState({ this.setState({
visible: false, visible: false,
}); });
}; };
handleCancel = e => { handleCancel = e => {
console.log(e);
this.setState({ this.setState({
visible: false, visible: false,
}); });

@ -43,14 +43,12 @@ class ManagedConfigurationsIframe extends React.Component {
}; };
handleOk = e => { handleOk = e => {
console.log(e);
this.setState({ this.setState({
visible: false, visible: false,
}); });
}; };
handleCancel = e => { handleCancel = e => {
console.log(e);
this.setState({ this.setState({
visible: false, visible: false,
}); });
@ -116,7 +114,6 @@ class ManagedConfigurationsIframe extends React.Component {
updateConfig = (method, event) => { updateConfig = (method, event) => {
const {packageName} = this.props; const {packageName} = this.props;
this.setState({loading: true}); this.setState({loading: true});
console.log(event);
const data = { const data = {
mcmId: event.mcmId, mcmId: event.mcmId,
@ -151,7 +148,6 @@ class ManagedConfigurationsIframe extends React.Component {
deleteConfig = (event) => { deleteConfig = (event) => {
const {packageName} = this.props; const {packageName} = this.props;
this.setState({loading: true}); this.setState({loading: true});
console.log(event);
//send request to the invoker //send request to the invoker
axios.delete( axios.delete(

@ -47,7 +47,6 @@ class Pages extends React.Component {
rowSelection = { rowSelection = {
onChange: (selectedRowKeys, selectedRows) => { onChange: (selectedRowKeys, selectedRows) => {
// console.lohhhg(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
this.setState({ this.setState({
selectedRows: selectedRows selectedRows: selectedRows
}) })

@ -84,9 +84,6 @@ class NewAppUploadForm extends React.Component {
this.setState({ this.setState({
loading: true loading: true
}); });
console.log(values);
const {price, isSharedWithAllTenants, binaryFile, icon, screenshots, releaseDescription, releaseType} = values; const {price, isSharedWithAllTenants, binaryFile, icon, screenshots, releaseDescription, releaseType} = values;
//add release data //add release data
@ -234,8 +231,7 @@ class NewAppUploadForm extends React.Component {
<Form <Form
labelAlign="right" labelAlign="right"
layout="horizontal" layout="horizontal"
onSubmit={this.handleSubmit} onSubmit={this.handleSubmit}>
>
{formConfig.specificElements.hasOwnProperty("binaryFile") && ( {formConfig.specificElements.hasOwnProperty("binaryFile") && (
<Form.Item {...formItemLayout} <Form.Item {...formItemLayout}
label="Application" label="Application"
@ -250,8 +246,7 @@ class NewAppUploadForm extends React.Component {
<Upload <Upload
name="binaryFile" name="binaryFile"
onChange={this.handleBinaryFileChange} onChange={this.handleBinaryFileChange}
beforeUpload={() => false} beforeUpload={() => false}>
>
{binaryFiles.length !== 1 && ( {binaryFiles.length !== 1 && (
<Button> <Button>
<Icon type="upload"/> Click to upload <Icon type="upload"/> Click to upload
@ -277,8 +272,7 @@ class NewAppUploadForm extends React.Component {
listType="picture-card" listType="picture-card"
onChange={this.handleIconChange} onChange={this.handleIconChange}
beforeUpload={() => false} beforeUpload={() => false}
onPreview={this.handlePreview} onPreview={this.handlePreview}>
>
{icons.length === 1 ? null : uploadButton} {icons.length === 1 ? null : uploadButton}
</Upload>, </Upload>,
)} )}
@ -418,7 +412,6 @@ class NewAppUploadForm extends React.Component {
</Select>, </Select>,
)} )}
</Form.Item> </Form.Item>
<Form.Item {...formItemLayout} label="Price"> <Form.Item {...formItemLayout} label="Price">
{getFieldDecorator('price', { {getFieldDecorator('price', {
rules: [{ rules: [{
@ -437,7 +430,6 @@ class NewAppUploadForm extends React.Component {
/> />
)} )}
</Form.Item> </Form.Item>
<Form.Item {...formItemLayout} label="Is Shared?"> <Form.Item {...formItemLayout} label="Is Shared?">
{getFieldDecorator('isSharedWithAllTenants', { {getFieldDecorator('isSharedWithAllTenants', {
rules: [{ rules: [{
@ -450,7 +442,6 @@ class NewAppUploadForm extends React.Component {
unCheckedChildren={<Icon type="close"/>} unCheckedChildren={<Icon type="close"/>}
/> />
)} )}
</Form.Item> </Form.Item>
<Form.Item {...formItemLayout} label="Meta Data"> <Form.Item {...formItemLayout} label="Meta Data">
{getFieldDecorator('meta', { {getFieldDecorator('meta', {
@ -510,7 +501,6 @@ class NewAppUploadForm extends React.Component {
</Button> </Button>
</div> </div>
)} )}
</Form.Item> </Form.Item>
<Form.Item style={{float: "right", marginLeft: 8}}> <Form.Item style={{float: "right", marginLeft: 8}}>
<Button type="primary" htmlType="submit"> <Button type="primary" htmlType="submit">
@ -531,7 +521,6 @@ class NewAppUploadForm extends React.Component {
</div> </div>
); );
} }
} }
export default (Form.create({name: 'app-upload-form'})(NewAppUploadForm)); export default (Form.create({name: 'app-upload-form'})(NewAppUploadForm));

@ -39,7 +39,8 @@ class Release extends React.Component {
uuid: null, uuid: null,
release: null, release: null,
currentLifecycleStatus: null, currentLifecycleStatus: null,
lifecycle: null lifecycle: null,
supportedOsVersions:[]
}; };
} }
@ -85,14 +86,17 @@ class Release extends React.Component {
loading: false, loading: false,
uuid: uuid uuid: uuid
}); });
if(config.deviceTypes.mobileTypes.includes(app.deviceType)){
this.getSupportedOsVersions(app.deviceType);
}else{
this.getLifecycle();
}
} }
}).catch((error) => { }).catch((error) => {
handleApiError(error, "Error occurred while trying to load the release."); handleApiError(error, "Error occurred while trying to load the release.");
this.setState({loading: false}); this.setState({loading: false});
}); });
this.getLifecycle();
}; };
getLifecycle = () => { getLifecycle = () => {
@ -112,6 +116,28 @@ class Release extends React.Component {
}); });
}; };
getSupportedOsVersions = (deviceType) => {
const config = this.props.context;
axios.get(
window.location.origin + config.serverConfig.invoker.uri + config.serverConfig.invoker.deviceMgt +
`/admin/device-types/${deviceType}/versions`
).then(res => {
if (res.status === 200) {
let supportedOsVersions = JSON.parse(res.data.data);
this.setState({
supportedOsVersions,
loading: false,
});
this.getLifecycle();
}
}).catch((error) => {
handleApiError(error, "Error occurred while trying to load supported OS versions.");
this.setState({
loading: false
});
});
};
render() { render() {
const {app, release, currentLifecycleStatus, lifecycle, loading} = this.state; const {app, release, currentLifecycleStatus, lifecycle, loading} = this.state;
@ -138,6 +164,7 @@ class Release extends React.Component {
currentLifecycleStatus={currentLifecycleStatus} currentLifecycleStatus={currentLifecycleStatus}
lifecycle={lifecycle} lifecycle={lifecycle}
updateRelease={this.updateRelease} updateRelease={this.updateRelease}
supportedOsVersions = {[...this.state.supportedOsVersions]}
/>) />)
} }
</Skeleton> </Skeleton>

@ -62,16 +62,16 @@ class ReleaseView extends React.Component {
headers: {'X-Platform': config.serverConfig.platform} headers: {'X-Platform': config.serverConfig.platform}
} }
).then(res => { ).then(res => {
if (res.status === 200) { if (res.status === 200 || res.status === 201) {
this.setState({ this.setState({
loading: false, loading: false,
appInstallModalVisible: false, appInstallModalVisible: false,
appUnInstallModalVisible: false, appUninstallModalVisible: false,
}); });
notification["success"]({ notification["success"]({
message: 'Done!', message: 'Done!',
description: description:
'App '+operation+'ed triggered.', 'Operation triggered.',
}); });
} else { } else {
this.setState({ this.setState({

@ -193,7 +193,7 @@ class DeviceUninstall extends React.Component {
type: device.type type: device.type
}); });
}); });
this.props.onUninstall("devices", payload, "uninstall", null); this.props.onUninstall("devices", payload, "uninstall", timestamp);
}; };
render() { render() {

@ -88,7 +88,7 @@ class GroupUninstall extends React.Component {
value.map(val=>{ value.map(val=>{
data.push(val.key); data.push(val.key);
}); });
this.props.onUninstall("group", data, "uninstall",null); this.props.onUninstall("group", data, "uninstall",timestamp);
}; };
render() { render() {

@ -87,7 +87,7 @@ class RoleUninstall extends React.Component {
value.map(val=>{ value.map(val=>{
data.push(val.key); data.push(val.key);
}); });
this.props.onUninstall("role", data, "uninstall",null); this.props.onUninstall("role", data, "uninstall",timestamp);
}; };
render() { render() {

@ -86,7 +86,7 @@ class UserUninstall extends React.Component {
value.map(val => { value.map(val => {
data.push(val.key); data.push(val.key);
}); });
this.props.onUninstall("user", data, "uninstall",null); this.props.onUninstall("user", data, "uninstall",timestamp);
}; };
render() { render() {

@ -46,6 +46,14 @@ class InstallModalFooter extends React.Component{
}) })
}; };
triggerInstallOperation = () =>{
this.props.operation();
};
triggerScheduledInstallOperation = () =>{
const {scheduledTime} =this.state;
this.props.operation(scheduledTime);
};
render() { render() {
const {scheduledTime,isScheduledInstallVisible} =this.state; const {scheduledTime,isScheduledInstallVisible} =this.state;
const {disabled, type} = this.props; const {disabled, type} = this.props;
@ -56,7 +64,7 @@ class InstallModalFooter extends React.Component{
display: (!isScheduledInstallVisible)?'block':'none' display: (!isScheduledInstallVisible)?'block':'none'
}}> }}>
<Button style={{margin: 5}} disabled={disabled} htmlType="button" type="primary" <Button style={{margin: 5}} disabled={disabled} htmlType="button" type="primary"
onClick={this.props.operation}> onClick={this.triggerInstallOperation}>
{type} {type}
</Button> </Button>
<Button style={{margin: 5}} disabled={disabled} htmlType="button" <Button style={{margin: 5}} disabled={disabled} htmlType="button"
@ -76,9 +84,7 @@ class InstallModalFooter extends React.Component{
style={{margin: 5}} style={{margin: 5}}
htmlType="button" htmlType="button"
type="primary" type="primary"
onClick={()=>{ onClick={this.triggerScheduledInstallOperation}>
this.props.operation(scheduledTime);
}}>
Schedule Schedule
</Button> </Button>
<Button style={{margin: 5}} htmlType="button" <Button style={{margin: 5}} htmlType="button"

@ -41,7 +41,6 @@ class EditReview extends React.Component {
componentDidMount() { componentDidMount() {
const {content,rating,id} = this.props.review; const {content,rating,id} = this.props.review;
console.log(this.props.review);
this.setState({ this.setState({
content, content,
rating rating

@ -19,7 +19,6 @@
import {notification} from "antd"; import {notification} from "antd";
export const handleApiError = (error, message) => { export const handleApiError = (error, message) => {
console.log(error);
if (error.hasOwnProperty("response") && error.response.status === 401) { if (error.hasOwnProperty("response") && error.response.status === 401) {
const redirectUrl = encodeURI(window.location.href); const redirectUrl = encodeURI(window.location.href);
window.location.href = window.location.origin + `/store/login?redirect=${redirectUrl}`; window.location.href = window.location.origin + `/store/login?redirect=${redirectUrl}`;

@ -80,7 +80,6 @@ class NormalLoginForm extends React.Component {
handleSubmit = (e) => { handleSubmit = (e) => {
const thisForm = this; const thisForm = this;
const config = this.props.context; const config = this.props.context;
console.log(config);
e.preventDefault(); e.preventDefault();
this.props.form.validateFields((err, values) => { this.props.form.validateFields((err, values) => {

Loading…
Cancel
Save