From 08860acfbad50b5920a5b465fe137e6bd9597d47 Mon Sep 17 00:00:00 2001 From: Jayasanka Weerasinghe Date: Tue, 22 Oct 2019 17:32:56 +0000 Subject: [PATCH] Add ui improvements to APPM Publisher UI The following changes are with this commit - View subscription status of devices in release view - Display server error response in add new app form --- .../src/components/apps/list-apps/Filters.js | 14 -- .../apps/list-apps/appsTable/AppsTable.js | 8 +- .../apps/release/lifeCycle/LifeCycle.js | 12 +- .../src/components/new-app/AddNewAppForm.js | 12 +- .../apps/release/InstalledDevicesTable.js | 231 ++++++++++++++++++ .../components/apps/release/ReleaseView.js | 67 +++-- 6 files changed, 288 insertions(+), 56 deletions(-) create mode 100644 components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/InstalledDevicesTable.js diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/components/apps/list-apps/Filters.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/components/apps/list-apps/Filters.js index de8bbf83578..e042def20da 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/components/apps/list-apps/Filters.js +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/components/apps/list-apps/Filters.js @@ -63,9 +63,6 @@ class FiltersForm extends React.Component { delete values["deviceType"]; } - if(values.hasOwnProperty("subscriptionType") && values.subscriptionType==="ALL"){ - delete values["subscriptionType"]; - } if(values.hasOwnProperty("appType") && values.appType==="ALL"){ delete values["appType"]; } @@ -271,17 +268,6 @@ class FiltersForm extends React.Component { )} - - - {getFieldDecorator('subscriptionType', {})( - - Free - Paid - All - , - )} - - ); diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/components/apps/list-apps/appsTable/AppsTable.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/components/apps/list-apps/appsTable/AppsTable.js index aae593fb2af..24e43a89c61 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/components/apps/list-apps/appsTable/AppsTable.js +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/components/apps/list-apps/appsTable/AppsTable.js @@ -123,7 +123,8 @@ class AppsTable extends React.Component { filters: {}, isDrawerVisible: false, selectedApp: null, - selectedAppIndex: -1 + selectedAppIndex: -1, + loading: false }; config = this.props.context; } @@ -222,14 +223,14 @@ class AppsTable extends React.Component { onUpdateApp = (key, value) => { const apps = [...this.state.apps]; - apps[this.state.selectedAppIndex][key]= value; + apps[this.state.selectedAppIndex][key] = value; this.setState({ apps }); }; render() { - const {isDrawerVisible} = this.state; + const {isDrawerVisible, loading} = this.state; return (
{ return { onClick: event => { diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/components/apps/release/lifeCycle/LifeCycle.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/components/apps/release/lifeCycle/LifeCycle.js index 3230939c727..34384f7f24c 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/components/apps/release/lifeCycle/LifeCycle.js +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/components/apps/release/lifeCycle/LifeCycle.js @@ -132,7 +132,7 @@ class LifeCycle extends React.Component { render() { - const {currentStatus, selectedStatus} = this.state; + const {currentStatus, selectedStatus, isConfirmButtonLoading} = this.state; const {lifecycle} = this.props; const selectedValue = selectedStatus == null ? [] : selectedStatus; let proceedingStates = []; @@ -180,21 +180,17 @@ class LifeCycle extends React.Component { type="primary" htmlType="button" onClick={this.showReasonModal} - disabled={selectedStatus == null} - > + loading={isConfirmButtonLoading} + disabled={selectedStatus == null}> Change - - - + okText="Confirm"> You are going to change the lifecycle state from,
{currentStatus}to { - handleApiError(error, "Sorry, we were unable to complete your request.") + handleApiError(error, error.response.data.data); this.setState({ loading: false, isError: true, - current: 2 + current: 2, + errorText: error.response.data.data }); }); @@ -149,7 +151,7 @@ class AddNewAppFormComponent extends React.Component { }; render() { - const {loading, current, isError, supportedOsVersions} = this.state; + const {loading, current, isError, supportedOsVersions, errorText} = this.state; const {formConfig} = this.props; return (
@@ -190,7 +192,7 @@ class AddNewAppFormComponent extends React.Component { {isError && (Back} />)} diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/InstalledDevicesTable.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/InstalledDevicesTable.js new file mode 100644 index 00000000000..1b6642f3d41 --- /dev/null +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/InstalledDevicesTable.js @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved. + * + * Entgra (pvt) Ltd. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React from "react"; +import axios from "axios"; +import {Tag, message, notification, Table, Typography, Tooltip, Icon, Divider, Button, Modal, Select} from "antd"; +import TimeAgo from 'javascript-time-ago' + +// Load locale-specific relative date/time formatting rules. +import en from 'javascript-time-ago/locale/en' +import {withConfigContext} from "../../../context/ConfigContext"; + +const {Text} = Typography; + +let config = null; + +const columns = [ + { + title: 'Device', + dataIndex: 'device', + width: 100, + render: device => device.name + }, + { + title: 'Owner', + dataIndex: 'device', + key: 'owner', + render: device => device.enrolmentInfo.owner + }, + { + title: 'Action Type', + dataIndex: 'actionType', + key: 'actionType', + render: actionType => actionType.toLowerCase() + }, + { + title: 'Action', + dataIndex: 'action', + key: 'action', + render: action => action.toLowerCase() + }, + { + title: 'Triggered By', + dataIndex: 'actionTriggeredBy', + key: 'actionTriggeredBy' + }, + { + title: 'Action Triggered At', + dataIndex: 'actionTriggeredTimestamp', + key: 'actionTriggeredTimestamp' + }, + { + title: 'Action Status', + dataIndex: 'status', + key: 'actionStatus', + render: (status) => { + let color = "#f9ca24"; + switch (status) { + case "COMPLETED": + color = "#badc58"; + break; + case "REPEATED": + color = "#6ab04c"; + break; + case "ERROR": + case "INVALID": + case "UNAUTHORIZED": + color = "#ff7979"; + break; + case "IN_PROGRESS": + color = "#f9ca24"; + break; + case "PENDING": + color = "#636e72"; + break; + } + return {status.toLowerCase()}; + } + }, + { + title: 'Device Status', + dataIndex: 'device', + key: 'deviceStatus', + render: (device) => { + const status = device.enrolmentInfo.status.toLowerCase(); + let color = "#f9ca24"; + switch (status) { + case "active": + color = "#badc58"; + break; + case "created": + color = "#6ab04c"; + break; + case "removed": + color = "#ff7979"; + break; + case "inactive": + color = "#f9ca24"; + break; + case "blocked": + color = "#636e72"; + break; + } + return {status}; + } + } +]; + +const getTimeAgo = (time) => { + const timeAgo = new TimeAgo('en-US'); + return timeAgo.format(time); +}; + + +class InstalledDevicesTable extends React.Component { + constructor(props) { + super(props); + config = this.props.context; + TimeAgo.addLocale(en); + this.state = { + data: [], + pagination: {}, + loading: false, + selectedRows: [], + deviceGroups: [], + groupModalVisible: false, + selectedGroupId: [] + }; + } + + componentDidMount() { + this.fetch(); + } + + //fetch data from api + fetch = (params = {}) => { + const config = this.props.context; + this.setState({loading: true}); + // get current page + const currentPage = (params.hasOwnProperty("page")) ? params.page : 1; + + const extraParams = { + offset: 10 * (currentPage - 1), //calculate the offset + limit: 10, + requireDeviceInfo: true, + }; + + const encodedExtraParams = Object.keys(extraParams) + .map(key => key + '=' + extraParams[key]).join('&'); + + //send request to the invoker + axios.get( + window.location.origin + config.serverConfig.invoker.uri + + config.serverConfig.invoker.store + + `/admin/subscription/${this.props.uuid}?` + encodedExtraParams, + ).then(res => { + if (res.status === 200) { + const pagination = {...this.state.pagination}; + console.log(res.data.data.data); + this.setState({ + loading: false, + data: res.data.data.data, + pagination, + }); + } + + }).catch((error) => { + if (error.hasOwnProperty("response") && error.response.status === 401) { + //todo display a popop with error + message.error('You are not logged in'); + window.location.href = window.location.origin + '/entgra/login'; + } else { + notification["error"]({ + message: "There was a problem", + duration: 0, + description: + "Error occurred while trying to load devices.", + }); + } + + this.setState({loading: false}); + }); + }; + + render() { + const {data, pagination, loading, selectedRows} = this.state; + return ( +
+
+ + Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque + laudantium, + totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae + dicta sunt explicabo. + +
+
(record.device.deviceIdentifier + record.device.enrolmentInfo.owner + record.device.enrolmentInfo.ownership)} + dataSource={data} + pagination={{ + ...pagination, + size: "small", + // position: "top", + showTotal: (total, range) => `showing ${range[0]}-${range[1]} of ${total} devices` + // showQuickJumper: true + }} + loading={loading} + scroll={{x: 1000}} + /> + + ); + } +} + +export default withConfigContext(InstalledDevicesTable); \ No newline at end of file diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/ReleaseView.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/ReleaseView.js index 6994f16e476..51ab619df26 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/ReleaseView.js +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/ReleaseView.js @@ -17,7 +17,7 @@ */ import React from "react"; -import {Divider, Row, Col, Typography, Button, Dropdown, notification, Menu, Icon, Spin} from "antd"; +import {Divider, Row, Col, Typography, Button, Dropdown, notification, Menu, Icon, Spin, Tabs} from "antd"; import "../../../App.css"; import ImgViewer from "../../apps/release/images/ImgViewer"; import StarRatings from "react-star-ratings"; @@ -30,8 +30,10 @@ import CurrentUsersReview from "./review/CurrentUsersReview"; import {withConfigContext} from "../../../context/ConfigContext"; import {handleApiError} from "../../../js/Utils"; import ReviewContainer from "./review/ReviewContainer"; +import InstalledDevicesTable from "./InstalledDevicesTable"; const {Title, Text, Paragraph} = Typography; +const {TabPane} = Tabs; class ReleaseView extends React.Component { constructor(props) { @@ -118,6 +120,12 @@ class ReleaseView extends React.Component { metaData = JSON.parse(release.metaData); } catch (e) { + } + if (app.hasOwnProperty("packageName")) { + metaData.push({ + key: "Package Name", + value: app.packageName + }); } const menu = ( @@ -171,31 +179,38 @@ class ReleaseView extends React.Component { - - - - - - - {release.description} - - - META DATA - - { - metaData.map((data, index) => { - return ( - - {data.key}
- {data.value} - - ) - }) - } - {(metaData.length === 0) && (No meta data available.)} - - - + + + + + + + + + {release.description} + + + META DATA + + { + metaData.map((data, index) => { + return ( + + {data.key}
+ {data.value} + + ) + }) + } + {(metaData.length === 0) && (No meta data available.)} + + + + + + + + );