record.deviceIdentifier}
+ rowKey={record => (record.deviceIdentifier + record.enrolmentInfo.owner + record.enrolmentInfo.ownership)}
dataSource={data}
pagination={{
...pagination,
diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Devices/ReportDevicesTable.js b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Devices/ReportDevicesTable.js
new file mode 100644
index 0000000000..d71f141e96
--- /dev/null
+++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Devices/ReportDevicesTable.js
@@ -0,0 +1,260 @@
+/*
+ * 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} 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;
+let apiUrl;
+
+const columns = [
+ {
+ title: 'Device',
+ dataIndex: 'name',
+ width: 100,
+ },
+ {
+ title: 'Type',
+ dataIndex: 'type',
+ key: 'type',
+ render: type => {
+ const defaultPlatformIcons = config.defaultPlatformIcons;
+ let icon = defaultPlatformIcons.default.icon;
+ let color = defaultPlatformIcons.default.color;
+ let theme = defaultPlatformIcons.default.theme;
+
+ if (defaultPlatformIcons.hasOwnProperty(type)) {
+ icon = defaultPlatformIcons[type].icon;
+ color = defaultPlatformIcons[type].color;
+ theme = defaultPlatformIcons[type].theme;
+ }
+
+ return (
+
+
+
+ );
+ }
+ // todo add filtering options
+ },
+ {
+ title: 'Owner',
+ dataIndex: 'enrolmentInfo',
+ key: 'owner',
+ render: enrolmentInfo => enrolmentInfo.owner
+ // todo add filtering options
+ },
+ {
+ title: 'Ownership',
+ dataIndex: 'enrolmentInfo',
+ key: 'ownership',
+ render: enrolmentInfo => enrolmentInfo.ownership
+ // todo add filtering options
+ },
+ {
+ title: 'Status',
+ dataIndex: 'enrolmentInfo',
+ key: 'status',
+ render: (enrolmentInfo) => {
+ const status = 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};
+ }
+ // todo add filtering options
+ },
+ {
+ title: 'Last Updated',
+ dataIndex: 'enrolmentInfo',
+ key: 'dateOfLastUpdate',
+ render: (data) => {
+ const {dateOfLastUpdate} = data;
+ const timeAgoString = getTimeAgo(dateOfLastUpdate);
+ return {timeAgoString};
+ }
+ // todo add filtering options
+ },
+ {
+ title: 'Action',
+ key: 'action',
+ render: () => (
+
+
+
+
+
+ ),
+ },
+];
+
+const getTimeAgo = (time) => {
+ const timeAgo = new TimeAgo('en-US');
+ return timeAgo.format(time);
+};
+
+class ReportDeviceTable extends React.Component {
+ constructor(props) {
+ super(props);
+ config = this.props.context;
+ TimeAgo.addLocale(en);
+ this.state = {
+ data: [],
+ pagination: {},
+ loading: false,
+ selectedRows: [],
+ paramsObj:{}
+ };
+ }
+
+ rowSelection = {
+ onChange: (selectedRowKeys, selectedRows) => {
+ this.setState({
+ selectedRows: selectedRows
+ })
+ }
+ };
+
+ componentDidMount() {
+ this.fetch();
+ }
+
+ //Rerender component when parameters change
+ componentDidUpdate(prevProps, prevState, snapshot) {
+ if(prevProps.paramsObject !== this.props.paramsObject){
+ 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;
+
+ this.props.paramsObject.offset = 10 * (currentPage -1); //calculate the offset
+ this.props.paramsObject.limit = 10;
+
+ const encodedExtraParams = Object.keys(this.props.paramsObject)
+ .map(key => key + '=' + this.props.paramsObject[key]).join('&');
+
+ if(this.props.paramsObject.from==null && this.props.paramsObject.to==null){
+ apiUrl = window.location.origin + config.serverConfig.invoker.uri +
+ config.serverConfig.invoker.deviceMgt +
+ "/devices?" + encodedExtraParams;
+
+ }else{
+ apiUrl = window.location.origin + config.serverConfig.invoker.uri +
+ config.serverConfig.invoker.deviceMgt +
+ "/reports/devices?" + encodedExtraParams;
+ }
+
+ //send request to the invokerss
+ axios.get(apiUrl).then(res => {
+ if (res.status === 200) {
+ const pagination = {...this.state.pagination};
+ this.setState({
+ loading: false,
+ data: res.data.data.devices,
+ 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});
+ });
+ };
+
+ handleTableChange = (pagination, filters, sorter) => {
+ const pager = {...this.state.pagination};
+ pager.current = pagination.current;
+ this.setState({
+ pagination: pager,
+ });
+ this.fetch({
+ results: pagination.pageSize,
+ page: pagination.current,
+ sortField: sorter.field,
+ sortOrder: sorter.order,
+ ...filters,
+ });
+ };
+
+ render() {
+
+ const {data, pagination, loading, selectedRows} = this.state;
+ return (
+
+
(record.deviceIdentifier + record.enrolmentInfo.owner + record.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}
+ onChange={this.handleTableChange}
+ rowSelection={this.rowSelection}
+ scroll={{x: 1000}}
+ />
+
+ );
+ }
+}
+
+export default withConfigContext(ReportDeviceTable);
\ No newline at end of file
diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Reports/DateRangePicker.js b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Reports/DateRangePicker.js
new file mode 100644
index 0000000000..c41c0c86e5
--- /dev/null
+++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Reports/DateRangePicker.js
@@ -0,0 +1,60 @@
+/*
+ * 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 { DatePicker } from 'antd';
+import moment from 'moment';
+
+class DateRangePicker extends React.Component {
+
+ constructor(props){
+ super(props);
+ }
+
+ //Send updated date range to Reports.js when duration change
+ onChange = (dates, dateStrings) => {
+ this.props.updateDurationValue(dateStrings[0],dateStrings[1]);
+ }
+
+ render(){
+ const { RangePicker } = DatePicker;
+ return(
+
+ )
+ }
+}
+
+export default DateRangePicker;
\ No newline at end of file
diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Reports/Filter.js b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Reports/Filter.js
new file mode 100644
index 0000000000..606f5d6a3d
--- /dev/null
+++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Reports/Filter.js
@@ -0,0 +1,67 @@
+/*
+ * 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 { Select } from 'antd';
+
+class Filter extends React.Component {
+
+ constructor(props){
+ super(props);
+ const { Option } = Select;
+ this.state = {
+ selectedItem:null
+ }
+ }
+
+ //Send updated filter value to Reports.js
+ onChange = value => {
+ this.setState({selectedItem:value},() => {
+ if(this.props.dropDownName=="Device Status"){
+ this.props.updateFiltersValue(this.state.selectedItem,"Device Status");
+ }else{
+ this.props.updateFiltersValue(this.state.selectedItem, "Device Ownership");
+ }
+ });
+ }
+
+ render(){
+ //Dynamically generate dropdown items from dropDownItems array
+ let item = this.props.dropDownItems.map((data) =>
+
+ {data}
+ );
+ return(
+
+ )
+ }
+}
+
+export default Filter;
\ No newline at end of file
diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/pages/Dashboard/Reports/Reports.js b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/pages/Dashboard/Reports/Reports.js
index 5449bf726b..0f271fa05a 100644
--- a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/pages/Dashboard/Reports/Reports.js
+++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/pages/Dashboard/Reports/Reports.js
@@ -21,11 +21,12 @@ import {
PageHeader,
Typography,
Breadcrumb,
- Icon,
- Card
+ Icon
} from "antd";
import {Link} from "react-router-dom";
-import DeviceTable from "../../../components/Devices/DevicesTable";
+import ReportDeviceTable from "../../../components/Devices/ReportDevicesTable";
+import Filter from "../../../components/Reports/Filter";
+import DateRangePicker from "../../../components/Reports/DateRangePicker";
const {Paragraph} = Typography;
@@ -35,10 +36,43 @@ class Reports extends React.Component {
constructor(props) {
super(props);
this.routes = props.routes;
+ this.state = {
+ paramsObject:{}
+ }
+ }
+
+ //Get modified value from datepicker and set it to paramsObject
+ updateDurationValue = (modifiedFromDate,modifiedToDate) => {
+ let tempParamObj = this.state.paramsObject;
+ tempParamObj.from = modifiedFromDate;
+ tempParamObj.to = modifiedToDate;
+ this.setState({paramsObject:tempParamObj});
+ }
+ //Get modified value from filters and set it to paramsObject
+ updateFiltersValue = (modifiedValue,filterType) => {
+ let tempParamObj = this.state.paramsObject;
+ if(filterType=="Device Status"){
+ tempParamObj.status = modifiedValue;
+ if(modifiedValue=="ALL" && tempParamObj.status){
+ delete tempParamObj.status;
+ }
+ }else{
+ tempParamObj.ownership = modifiedValue;
+ if(modifiedValue=="ALL" && tempParamObj.ownership){
+ delete tempParamObj.ownership;
+ }
+ }
+ this.setState({paramsObject:tempParamObj});
}
render() {
+ //Arrays for filters
+ const statusObj = ['ALL','ACTIVE','INACTIVE','REMOVED'];
+ const ownershipObj = ['ALL','BYOD','COPE'];
+
+ const params = {...this.state.paramsObject};
+
return (
@@ -50,8 +84,41 @@ class Reports extends React.Component {
Reports
- Lorem ipsum dolor sit amet, est similique constituto at, quot inermis id mel, an
- illud incorrupte nam.
+
+ To generate a report, select a duration and apply filters
+
+