mirror of
https://repository.entgra.net/community/device-mgt-core.git
synced 2025-10-06 02:01:45 +00:00
UI for device enrollment reports
This commit is contained in:
parent
8fcb753568
commit
40bf2ca1e9
@ -8,6 +8,7 @@
|
||||
"acorn": "^6.2.0",
|
||||
"antd": "^3.23.5",
|
||||
"axios": "^0.18.1",
|
||||
"bizcharts": "^3.5.6",
|
||||
"bootstrap": "^4.3.1",
|
||||
"javascript-time-ago": "^2.0.1",
|
||||
"keymirror": "^0.1.1",
|
||||
@ -35,6 +36,7 @@
|
||||
"storm-react-diagrams": "^5.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@antv/data-set": "^0.10.2",
|
||||
"@babel/core": "^7.5.4",
|
||||
"@babel/plugin-proposal-class-properties": "^7.5.0",
|
||||
"@babel/preset-env": "^7.5.4",
|
||||
|
||||
@ -24,7 +24,7 @@ import {
|
||||
Redirect, Switch,
|
||||
} from 'react-router-dom';
|
||||
import axios from "axios";
|
||||
import {Layout, Spin, Result} from "antd";
|
||||
import {Layout, Spin, Result, message, notification} from "antd";
|
||||
import ConfigContext from "./context/ConfigContext";
|
||||
|
||||
const {Content} = Layout;
|
||||
@ -93,6 +93,7 @@ class App extends React.Component {
|
||||
config: config
|
||||
});
|
||||
}
|
||||
this.getDeviceTypes(config);
|
||||
}).catch((error) => {
|
||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
||||
const redirectUrl = encodeURI(window.location.href);
|
||||
@ -115,9 +116,30 @@ class App extends React.Component {
|
||||
});
|
||||
};
|
||||
|
||||
getDeviceTypes = (config) => {
|
||||
axios.get(
|
||||
window.location.origin + "/entgra-ui-request-handler/invoke/device-mgt/v1.0/device-types",
|
||||
).then(res => {
|
||||
config.deviceTypes = JSON.parse(res.data.data);
|
||||
this.setState({
|
||||
config: config,
|
||||
loading: false
|
||||
});
|
||||
}).catch((error) => {
|
||||
|
||||
notification["error"]({
|
||||
message: "There was a problem",
|
||||
duration: 0,
|
||||
description:"Error occurred while trying to load device types.",
|
||||
});
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const {loading, error} = this.state;
|
||||
|
||||
const abc = this.state.deviceTypes;
|
||||
const applicationView = (
|
||||
<Router>
|
||||
<ConfigContext.Provider value={this.state.config}>
|
||||
|
||||
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* 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 {
|
||||
PageHeader,
|
||||
Typography,
|
||||
Breadcrumb,
|
||||
Icon,
|
||||
Tag,
|
||||
Radio, Select, Button, Card,
|
||||
Row, Col, message, notification
|
||||
} from "antd";
|
||||
|
||||
import {Link} from "react-router-dom";
|
||||
import PoliciesTable from "../../../components/Policies/PoliciesTable";
|
||||
import DevicesTable from "../../../components/Devices/DevicesTable";
|
||||
import DateRangePicker from "../../../components/Reports/DateRangePicker";
|
||||
import ReportDeviceTable from "../../../components/Devices/ReportDevicesTable";
|
||||
import PieChart from "../../../components/Reports/Widgets/PieChart";
|
||||
import axios from "axios";
|
||||
import CountWidget from "../../../components/Reports/Widgets/CountWidget";
|
||||
import {withConfigContext} from "../../../context/ConfigContext";
|
||||
const {Paragraph} = Typography;
|
||||
const { CheckableTag } = Tag;
|
||||
|
||||
const { Option } = Select;
|
||||
let config = null;
|
||||
|
||||
|
||||
class DeviceStatusReport extends React.Component {
|
||||
routes;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.routes = props.routes;
|
||||
config = this.props.context;
|
||||
const { reportData } = this.props.location;
|
||||
this.state = {
|
||||
selectedTags: ['Enrolled'],
|
||||
paramsObject:{
|
||||
from:reportData.duration[0],
|
||||
to:reportData.duration[1]
|
||||
},
|
||||
statsObject:{},
|
||||
statArray:[{item:"ACTIVE",count:0},{item:"INACTIVE",count:0},{item:"REMOVED",count:0}]
|
||||
};
|
||||
}
|
||||
|
||||
onClickPieChart = (value) => {
|
||||
console.log(value.data.point.item);
|
||||
const chartValue = value.data.point.item;
|
||||
let tempParamObj = this.state.paramsObject;
|
||||
|
||||
tempParamObj.status = chartValue;
|
||||
|
||||
|
||||
this.setState({paramsObject:tempParamObj});
|
||||
console.log(this.state.paramsObject)
|
||||
};
|
||||
|
||||
render() {
|
||||
const { statArray } = this.state;
|
||||
const { reportData } = this.props.location;
|
||||
|
||||
const params = {...this.state.paramsObject};
|
||||
return (
|
||||
<div>
|
||||
<PageHeader style={{paddingTop: 0}}>
|
||||
<Breadcrumb style={{paddingBottom: 16}}>
|
||||
<Breadcrumb.Item>
|
||||
<Link to="/entgra"><Icon type="home"/> Home</Link>
|
||||
</Breadcrumb.Item>
|
||||
<Breadcrumb.Item>Report</Breadcrumb.Item>
|
||||
</Breadcrumb>
|
||||
<div className="wrap" style={{marginBottom: '10px'}}>
|
||||
<h3>Summary of enrollments</h3>
|
||||
<div style={{marginBottom: '10px'}}>
|
||||
<Select defaultValue="android" style={{ width: 120 , marginRight:10}}>
|
||||
<Option value="android">Android</Option>
|
||||
<Option value="ios">IOS</Option>
|
||||
<Option value="windows">Windows</Option>
|
||||
</Select>
|
||||
<Button onClick={this.onSubmitReport} style={{marginLeft:10}} type="primary">Generate Report</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Card
|
||||
bordered={true}
|
||||
hoverable={true}
|
||||
style={{borderRadius: 5, marginBottom: 10, height:window.innerHeight*0.5}}>
|
||||
|
||||
<PieChart onClickPieChart={this.onClickPieChart} reportData={reportData}/>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<div style={{backgroundColor:"#ffffff", borderRadius: 5}}>
|
||||
<ReportDeviceTable paramsObject={params}/>
|
||||
</div>
|
||||
</PageHeader>
|
||||
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withConfigContext(DeviceStatusReport);
|
||||
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* 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 {
|
||||
PageHeader,
|
||||
Typography,
|
||||
Breadcrumb,
|
||||
Icon,
|
||||
Tag,
|
||||
Radio, Select, Button, Card,
|
||||
Row, Col, message, notification
|
||||
} from "antd";
|
||||
|
||||
import {Link} from "react-router-dom";
|
||||
import PoliciesTable from "../../../components/Policies/PoliciesTable";
|
||||
import DevicesTable from "../../../components/Devices/DevicesTable";
|
||||
import DateRangePicker from "../../../components/Reports/DateRangePicker";
|
||||
import ReportDeviceTable from "../../../components/Devices/ReportDevicesTable";
|
||||
import PieChart from "../../../components/Reports/Widgets/PieChart";
|
||||
import axios from "axios";
|
||||
import CountWidget from "../../../components/Reports/Widgets/CountWidget";
|
||||
import {withConfigContext} from "../../../context/ConfigContext";
|
||||
const {Paragraph} = Typography;
|
||||
const { CheckableTag } = Tag;
|
||||
|
||||
const { Option } = Select;
|
||||
let config = null;
|
||||
|
||||
|
||||
class EnrollmentTypeReport extends React.Component {
|
||||
routes;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.routes = props.routes;
|
||||
config = this.props.context;
|
||||
const { reportData } = this.props.location;
|
||||
this.state = {
|
||||
paramsObject:{
|
||||
from:reportData.duration[0],
|
||||
to:reportData.duration[1]
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
console.log(reportData.duration);
|
||||
}
|
||||
|
||||
setParam = (tempParamObj, type, value) => {
|
||||
if(type==="status"){
|
||||
tempParamObj.status = value;
|
||||
if(tempParamObj.status) {
|
||||
delete tempParamObj.status;
|
||||
}
|
||||
} else if(type=="ownership"){
|
||||
tempParamObj.ownership = value;
|
||||
if(value=="ALL" && tempParamObj.ownership) {
|
||||
delete tempParamObj.ownership;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
onClickPieChart = (value) => {
|
||||
const chartValue = value.data.point.item;
|
||||
let tempParamObj = this.state.paramsObject;
|
||||
|
||||
console.log(chartValue)
|
||||
|
||||
tempParamObj.ownership = chartValue;
|
||||
|
||||
this.setState({paramsObject:tempParamObj});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { reportData } = this.props.location;
|
||||
|
||||
const params = {...this.state.paramsObject};
|
||||
return (
|
||||
<div>
|
||||
<PageHeader style={{paddingTop: 0}}>
|
||||
<Breadcrumb style={{paddingBottom: 16}}>
|
||||
<Breadcrumb.Item>
|
||||
<Link to="/entgra"><Icon type="home"/> Home</Link>
|
||||
</Breadcrumb.Item>
|
||||
<Breadcrumb.Item>Report</Breadcrumb.Item>
|
||||
</Breadcrumb>
|
||||
<div className="wrap" style={{marginBottom: '10px'}}>
|
||||
<h3>Summary of enrollments</h3>
|
||||
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Card
|
||||
bordered={true}
|
||||
hoverable={true}
|
||||
style={{borderRadius: 5, marginBottom: 10, height:window.innerHeight*0.5}}>
|
||||
|
||||
|
||||
<PieChart onClickPieChart={this.onClickPieChart} reportData={reportData}/>
|
||||
|
||||
</Card>
|
||||
|
||||
</div>
|
||||
|
||||
<div style={{backgroundColor:"#ffffff", borderRadius: 5}}>
|
||||
<ReportDeviceTable paramsObject={params}/>
|
||||
</div>
|
||||
</PageHeader>
|
||||
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withConfigContext(EnrollmentTypeReport);
|
||||
@ -0,0 +1,172 @@
|
||||
/*
|
||||
* 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 {
|
||||
PageHeader,
|
||||
Typography,
|
||||
Breadcrumb,
|
||||
Icon,
|
||||
Tag,
|
||||
Radio, Select, Button, Card,
|
||||
Row, Col, message, notification
|
||||
} from "antd";
|
||||
|
||||
import {Link, Redirect} from "react-router-dom";
|
||||
import PoliciesTable from "../../../components/Policies/PoliciesTable";
|
||||
import DevicesTable from "../../../components/Devices/DevicesTable";
|
||||
import DateRangePicker from "../../../components/Reports/DateRangePicker";
|
||||
import ReportDeviceTable from "../../../components/Devices/ReportDevicesTable";
|
||||
import PieChart from "../../../components/Reports/Widgets/PieChart";
|
||||
import axios from "axios";
|
||||
import CountWidget from "../../../components/Reports/Widgets/CountWidget";
|
||||
import {withConfigContext} from "../../../context/ConfigContext";
|
||||
const {Paragraph} = Typography;
|
||||
const { CheckableTag } = Tag;
|
||||
|
||||
const { Option } = Select;
|
||||
let config = null;
|
||||
|
||||
|
||||
class EnrollmentsVsUnenrollmentsReport extends React.Component {
|
||||
routes;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.routes = props.routes;
|
||||
config = this.props.context;
|
||||
const { reportData } = this.props.location;
|
||||
|
||||
this.state = {
|
||||
paramsObject:{
|
||||
from:reportData? reportData.duration[0]: "2019-01-01",
|
||||
to:reportData? reportData.duration[1]: "2019-01-01"
|
||||
},
|
||||
redirect: false
|
||||
};
|
||||
|
||||
this.redirectToHome();
|
||||
console.log(this.state.paramsObject);
|
||||
}
|
||||
|
||||
setParam = (tempParamObj, type, value) => {
|
||||
if(type==="status"){
|
||||
tempParamObj.status = value;
|
||||
if(tempParamObj.status) {
|
||||
delete tempParamObj.status;
|
||||
}
|
||||
} else if(type=="ownership"){
|
||||
tempParamObj.ownership = value;
|
||||
if(value=="ALL" && tempParamObj.ownership) {
|
||||
delete tempParamObj.ownership;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
redirectToHome = () => {
|
||||
return <Redirect to="/entgra" />
|
||||
};
|
||||
|
||||
setRedirect = (reportData) => {
|
||||
if(!reportData){
|
||||
this.setState({
|
||||
redirect: true
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
renderRedirect = () => {
|
||||
if (this.state.redirect) {
|
||||
return <Redirect to='/entgra' />
|
||||
}
|
||||
}
|
||||
|
||||
onClickPieChart = (value) => {
|
||||
const chartValue = value.data.point.item;
|
||||
let tempParamObj = this.state.paramsObject;
|
||||
|
||||
console.log(chartValue)
|
||||
|
||||
// tempParamObj.status = chartValue;
|
||||
|
||||
if(chartValue==="Enrollments"){
|
||||
tempParamObj.status = "ACTIVE&status=INACTIVE"
|
||||
}else{
|
||||
tempParamObj.status = "REMOVED"
|
||||
}
|
||||
|
||||
|
||||
this.setState({paramsObject:tempParamObj});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { reportData } = this.props.location;
|
||||
|
||||
console.log("======")
|
||||
console.log(reportData)
|
||||
console.log("======")
|
||||
|
||||
let reportDataClone = {
|
||||
params: ["ACTIVE"],
|
||||
duration: ["2020-01-01","2020-01-01"]
|
||||
};
|
||||
|
||||
const params = {...this.state.paramsObject};
|
||||
return (
|
||||
<div>
|
||||
|
||||
<div>{!reportData ? (
|
||||
<Redirect to='/entgra/reports' />
|
||||
) : (
|
||||
<PageHeader style={{paddingTop: 0}}>
|
||||
<Breadcrumb style={{paddingBottom: 16}}>
|
||||
<Breadcrumb.Item>
|
||||
<Link to="/entgra"><Icon type="home"/> Home</Link>
|
||||
</Breadcrumb.Item>
|
||||
<Breadcrumb.Item>Report</Breadcrumb.Item>
|
||||
</Breadcrumb>
|
||||
<div className="wrap" style={{marginBottom: '10px'}}>
|
||||
<h3>Summary of enrollments</h3>
|
||||
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Card
|
||||
bordered={true}
|
||||
hoverable={true}
|
||||
style={{borderRadius: 5, marginBottom: 10, height:window.innerHeight*0.5}}>
|
||||
|
||||
|
||||
<PieChart onClickPieChart={this.onClickPieChart} reportData={reportData? reportData : reportDataClone}/>
|
||||
|
||||
</Card>
|
||||
|
||||
</div>
|
||||
|
||||
<div style={{backgroundColor:"#ffffff", borderRadius: 5}}>
|
||||
<ReportDeviceTable paramsObject={params}/>
|
||||
</div>
|
||||
</PageHeader>
|
||||
|
||||
)}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withConfigContext(EnrollmentsVsUnenrollmentsReport);
|
||||
@ -0,0 +1,63 @@
|
||||
import React from "react";
|
||||
|
||||
import {Card, Col, Icon} from "antd";
|
||||
import {Link} from "react-router-dom";
|
||||
|
||||
class CountWidget extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.routes = props.routes;
|
||||
this.state = {
|
||||
statArray:[]
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.setState({statArray:this.props.statArray})
|
||||
console.log("$$$$")
|
||||
console.log(this.props.statArray)
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
const countObj = [
|
||||
{item:"All",count:100},
|
||||
{item:"Enrolled",count:80},
|
||||
{item:"Unenrolled",count:20}];
|
||||
|
||||
const { statArray } = this.state;
|
||||
|
||||
let card = statArray.map((data) =>
|
||||
// <Card
|
||||
// bordered={true}
|
||||
// hoverable={true}
|
||||
// key={data.item}
|
||||
// style={{borderRadius: 5, marginBottom: 5, width:"100%"}}>
|
||||
//
|
||||
// <h3>{data.item} Devices: {data.count}</h3>
|
||||
//
|
||||
// </Card>
|
||||
<Col key={data.item} span={6}>
|
||||
<Card key={data.item} bordered={true} hoverable={true} style={{borderRadius: 10, marginBottom: 16}}>
|
||||
|
||||
<div align='center'>
|
||||
<h2><b>{data.item}</b></h2>
|
||||
<h1>{data.count}</h1>
|
||||
{/*<p>{data.duration}</p>*/}
|
||||
{/*<ReportFilterModal/>*/}
|
||||
</div>
|
||||
</Card>
|
||||
</Col>
|
||||
)
|
||||
|
||||
return(
|
||||
<div>
|
||||
{card}
|
||||
</div>
|
||||
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default CountWidget;
|
||||
322
components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Reports/Widgets/PieChart.js
vendored
Normal file
322
components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Reports/Widgets/PieChart.js
vendored
Normal file
@ -0,0 +1,322 @@
|
||||
import React from "react";
|
||||
import {
|
||||
G2,
|
||||
Chart,
|
||||
Geom,
|
||||
Axis,
|
||||
Tooltip,
|
||||
Coord,
|
||||
Label,
|
||||
Legend,
|
||||
View,
|
||||
Guide,
|
||||
Shape,
|
||||
Facet,
|
||||
Util
|
||||
} from "bizcharts";
|
||||
import DataSet from "@antv/data-set";
|
||||
import axios from "axios";
|
||||
import {message, notification} from "antd";
|
||||
import {withConfigContext} from "../../../context/ConfigContext";
|
||||
|
||||
let config = null;
|
||||
|
||||
class PieChart extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
config = this.props.context;
|
||||
this.state = {
|
||||
loading:true,
|
||||
statArray:[]
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
let { statArray } = this.state;
|
||||
const { reportData } = this.props;
|
||||
let params = {
|
||||
status: reportData.params[0],
|
||||
from: reportData.duration[0],
|
||||
to: reportData.duration[1]
|
||||
};
|
||||
|
||||
const urlSet = {
|
||||
paramsList:reportData.params,
|
||||
duration:reportData.duration
|
||||
};
|
||||
|
||||
console.log(urlSet)
|
||||
|
||||
if(reportData.params[0]==="Enrollments"){
|
||||
this.getEnrollmentsVsUnenrollmentsCount(params, urlSet)
|
||||
}else if(reportData.params[0]==="BYOD"){
|
||||
this.getEnrollmentTypeCount(params, urlSet);
|
||||
}else{
|
||||
this.getCount(params, urlSet);
|
||||
}
|
||||
}
|
||||
|
||||
clicked = () => {
|
||||
console.log("Clicked...!!")
|
||||
};
|
||||
|
||||
onChartChange = (data) => {
|
||||
this.props.onClickPieChart(data);
|
||||
};
|
||||
|
||||
statArray = [];
|
||||
|
||||
//Call count APIs and get count for given parameters, then create data object to build pie chart
|
||||
getCount = (params, urlSet) => {
|
||||
|
||||
this.setState({loading: true});
|
||||
|
||||
let { statArray } = this.state;
|
||||
|
||||
console.log(urlSet);
|
||||
|
||||
const urlArray = [];
|
||||
|
||||
urlSet.paramsList.map((data) => {
|
||||
const paramsObj = {
|
||||
status:data,
|
||||
from:urlSet.duration[0],
|
||||
to:urlSet.duration[1]
|
||||
}
|
||||
// console.log(paramsObj)
|
||||
const encodedExtraParams = Object.keys(paramsObj)
|
||||
.map(key => key + '=' + paramsObj[key]).join('&');
|
||||
const apiUrl = window.location.origin + config.serverConfig.invoker.uri +
|
||||
config.serverConfig.invoker.deviceMgt +
|
||||
"/reports/devices/count?" + encodedExtraParams;
|
||||
|
||||
urlArray.push(axios.get(apiUrl, data));
|
||||
});
|
||||
|
||||
console.log(urlArray)
|
||||
|
||||
|
||||
axios.all(urlArray).then(res => {
|
||||
|
||||
res.map((response) => {
|
||||
if(response.status === 200){
|
||||
let countData = {item:response.config[0], count:parseInt(response.data.data)}
|
||||
statArray.push(countData);
|
||||
}
|
||||
})
|
||||
this.setState({statArray})
|
||||
}).catch((error) => {
|
||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
||||
//todo display a popup 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 get device count.",
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
//Call count APIs and get count for given parameters, then create data object to build pie chart
|
||||
getEnrollmentsVsUnenrollmentsCount = (params, urlSet) => {
|
||||
|
||||
this.setState({loading: true});
|
||||
|
||||
let { statArray } = this.state;
|
||||
|
||||
console.log(urlSet);
|
||||
|
||||
const urlArray = [];
|
||||
|
||||
urlSet.paramsList.map((data) => {
|
||||
const paramsObj = {
|
||||
from:urlSet.duration[0],
|
||||
to:urlSet.duration[1]
|
||||
}
|
||||
const encodedExtraParams = Object.keys(paramsObj)
|
||||
.map(key => key + '=' + paramsObj[key]).join('&');
|
||||
|
||||
let apiUrl;
|
||||
if(data==="Enrollments"){
|
||||
apiUrl = window.location.origin + config.serverConfig.invoker.uri +
|
||||
config.serverConfig.invoker.deviceMgt +
|
||||
"/reports/devices/count?status=ACTIVE&status=INACTIVE&" + encodedExtraParams;
|
||||
}else{
|
||||
apiUrl = window.location.origin + config.serverConfig.invoker.uri +
|
||||
config.serverConfig.invoker.deviceMgt +
|
||||
"/reports/devices/count?status=REMOVED&" + encodedExtraParams;
|
||||
}
|
||||
|
||||
urlArray.push(axios.get(apiUrl, data));
|
||||
});
|
||||
|
||||
console.log(urlArray)
|
||||
|
||||
|
||||
axios.all(urlArray).then(res => {
|
||||
res.map((response) => {
|
||||
if(response.status === 200){
|
||||
let countData = {item:response.config[0], count:parseInt(response.data.data)}
|
||||
statArray.push(countData);
|
||||
}
|
||||
})
|
||||
this.setState({statArray})
|
||||
}).catch((error) => {
|
||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
||||
//todo display a popup 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 get device count.",
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
//Call count APIs and get count for given parameters, then create data object to build pie chart
|
||||
getEnrollmentTypeCount = (params, urlSet) => {
|
||||
|
||||
this.setState({loading: true});
|
||||
|
||||
let { statArray } = this.state;
|
||||
|
||||
console.log(urlSet);
|
||||
|
||||
const urlArray = [];
|
||||
|
||||
urlSet.paramsList.map((data) => {
|
||||
const paramsObj = {
|
||||
ownership:data,
|
||||
from:urlSet.duration[0],
|
||||
to:urlSet.duration[1]
|
||||
}
|
||||
const encodedExtraParams = Object.keys(paramsObj)
|
||||
.map(key => key + '=' + paramsObj[key]).join('&');
|
||||
const apiUrl = window.location.origin + config.serverConfig.invoker.uri +
|
||||
config.serverConfig.invoker.deviceMgt +
|
||||
"/reports/devices/count?" + encodedExtraParams;
|
||||
|
||||
urlArray.push(axios.get(apiUrl, data));
|
||||
});
|
||||
|
||||
console.log(urlArray)
|
||||
|
||||
|
||||
axios.all(urlArray).then(res => {
|
||||
res.map((response) => {
|
||||
if(response.status === 200){
|
||||
let countData = {item:response.config[0], count:parseInt(response.data.data)}
|
||||
statArray.push(countData);
|
||||
}
|
||||
})
|
||||
this.setState({statArray})
|
||||
}).catch((error) => {
|
||||
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
||||
//todo display a popup 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 get device count.",
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { DataView } = DataSet;
|
||||
const { Html } = Guide;
|
||||
const { statArray , loading} = this.state;
|
||||
|
||||
const dv = new DataView();
|
||||
dv.source(statArray).transform({
|
||||
type: "percent",
|
||||
field: "count",
|
||||
dimension: "item",
|
||||
as: "percent"
|
||||
});
|
||||
const cols = {
|
||||
percent: {
|
||||
formatter: val => {
|
||||
val = val * 100 + "%";
|
||||
return val;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Chart
|
||||
height={window.innerHeight/2}
|
||||
data={dv}
|
||||
scale={cols}
|
||||
padding={[20, 25, 20, 20]}
|
||||
forceFit
|
||||
onPlotClick={this.onChartChange}
|
||||
animate={true}
|
||||
>
|
||||
<Coord type={"theta"} radius={0.75} innerRadius={0.6} />
|
||||
<Axis name="percent" />
|
||||
<Legend
|
||||
position="right"
|
||||
offsetY={-window.innerHeight / 2 + 120}
|
||||
offsetX={-100}
|
||||
/>
|
||||
<Tooltip
|
||||
showTitle={false}
|
||||
itemTpl="<li><span style="background-color:{color};" class="g2-tooltip-marker"></span>{name}: {value}</li>"
|
||||
/>
|
||||
<Guide>
|
||||
<Html
|
||||
position={["50%", "50%"]}
|
||||
html="<div style="color:#8c8c8c;font-size:1.16em;text-align: center;width: 10em;">Total<br><span style="color:#262626;font-size:2.5em">200</span>台</div>"
|
||||
alignX="middle"
|
||||
alignY="middle"
|
||||
/>
|
||||
</Guide>
|
||||
<div onClick={this.clicked}>
|
||||
<Geom
|
||||
type="intervalStack"
|
||||
position="percent"
|
||||
color="item"
|
||||
|
||||
tooltip={[
|
||||
"item*percent",
|
||||
(item, percent) => {
|
||||
percent = percent * 100 + "%";
|
||||
return {
|
||||
name: item,
|
||||
value: percent
|
||||
};
|
||||
}
|
||||
]}
|
||||
style={{
|
||||
lineWidth: 1,
|
||||
stroke: "#fff"
|
||||
}}
|
||||
>
|
||||
<Label
|
||||
content="percent"
|
||||
formatter={(val, item) => {
|
||||
return item.point.item + ": " + val;
|
||||
}}/>
|
||||
</Geom>
|
||||
</div>
|
||||
|
||||
</Chart>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withConfigContext(PieChart);
|
||||
@ -34,6 +34,9 @@ import DeviceTypes from "./pages/Dashboard/DeviceTypes/DeviceTypes";
|
||||
import DeviceEnroll from "./pages/Dashboard/Devices/DeviceEnroll";
|
||||
import AddNewPolicy from "./pages/Dashboard/Policies/AddNewPolicy";
|
||||
import Certificates from "./pages/Dashboard/Configurations/Certificates/Certificates";
|
||||
import ReportDurationItemList from "./pages/Dashboard/Reports/ReportDurationItemList";
|
||||
import EnrollmentsVsUnenrollmentsReport from "./components/Reports/Templates/EnrollmentsVsUnenrollmentsReport";
|
||||
import EnrollmentTypeReport from "./components/Reports/Templates/EnrollmentTypeReport";
|
||||
|
||||
const routes = [
|
||||
{
|
||||
@ -100,6 +103,26 @@ const routes = [
|
||||
path: '/entgra/certificates',
|
||||
component: Certificates,
|
||||
exact: true
|
||||
},
|
||||
{
|
||||
path: '/entgra/reportList',
|
||||
component: ReportDurationItemList,
|
||||
exact: true
|
||||
},
|
||||
{
|
||||
path: '/entgra/enrollmentsvsunenrollments',
|
||||
component: EnrollmentsVsUnenrollmentsReport,
|
||||
exact: true
|
||||
},
|
||||
{
|
||||
path: '/entgra/enrollmenttype',
|
||||
component: EnrollmentTypeReport,
|
||||
exact: true
|
||||
},
|
||||
{
|
||||
path: '/entgra/devicestatus',
|
||||
component: DeviceStatusReport,
|
||||
exact: true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@ -0,0 +1,152 @@
|
||||
/*
|
||||
* 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 {
|
||||
Icon,
|
||||
Col,
|
||||
Row, Select,
|
||||
Radio, Card,
|
||||
Button
|
||||
} from "antd";
|
||||
|
||||
import {Link} from "react-router-dom";
|
||||
import moment from "moment";
|
||||
|
||||
|
||||
const { Option } = Select;
|
||||
|
||||
class ReportDurationItemList extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
reportParams:["ACTIVE","INACTIVE","REMOVED"],
|
||||
enrollmentsVsUnenrollmentsParams:["Enrollments", "Unenrollments"],
|
||||
enrollmentTypeParams:["BYOD", "COPE"]
|
||||
}
|
||||
}
|
||||
|
||||
durationItemArray = [
|
||||
{name:"Daily Report", description:"Enrollments of today", duration:[moment().format('YYYY-MM-DD'), moment().add(1, 'days').format('YYYY-MM-DD')]},
|
||||
{name:"Weekly Report", description:"Enrollments of last 7 days", duration:[moment().subtract(6, 'days').format('YYYY-MM-DD'), moment().add(1, 'days').format('YYYY-MM-DD')]},
|
||||
{name:"Monthly Report", description:"Enrollments of last month", duration:[moment().subtract(29, 'days').format('YYYY-MM-DD'), moment().add(1, 'days').format('YYYY-MM-DD')]}]
|
||||
|
||||
|
||||
render(){
|
||||
|
||||
let itemStatus = this.durationItemArray.map((data) =>
|
||||
<Col key={data.name} span={6}>
|
||||
<Link
|
||||
to={{
|
||||
//Path to respective report page
|
||||
pathname: "/entgra/devicestatus",
|
||||
reportData: {
|
||||
duration: data.duration,
|
||||
reportType: data.reportType,
|
||||
params: this.state.reportParams,
|
||||
paramsType: data.paramsType
|
||||
}
|
||||
}}>
|
||||
<Card key={data.name} bordered={true} hoverable={true} style={{borderRadius: 10, marginBottom: 16}}>
|
||||
|
||||
<div align='center'>
|
||||
<Icon type="desktop" style={{ fontSize: '25px', color: '#08c' }}/>
|
||||
<h2><b>{data.name}</b></h2>
|
||||
<p>{data.description}</p>
|
||||
{/*<p>{data.duration}</p>*/}
|
||||
</div>
|
||||
</Card>
|
||||
</Link>
|
||||
</Col>
|
||||
);
|
||||
|
||||
let itemEnrollmentsVsUnenrollments = this.durationItemArray.map((data) =>
|
||||
<Col key={data.name} span={6}>
|
||||
<Link
|
||||
to={{
|
||||
//Path to respective report page
|
||||
pathname: "/entgra/enrollmentsvsunenrollments",
|
||||
reportData: {
|
||||
duration: data.duration,
|
||||
reportType: data.reportType,
|
||||
params: this.state.enrollmentsVsUnenrollmentsParams,
|
||||
paramsType: data.paramsType
|
||||
}
|
||||
}}>
|
||||
<Card key={data.name} bordered={true} hoverable={true} style={{borderRadius: 10, marginBottom: 16}}>
|
||||
|
||||
<div align='center'>
|
||||
<Icon type="desktop" style={{ fontSize: '25px', color: '#08c' }}/>
|
||||
<h2><b>{data.name}</b></h2>
|
||||
<p>{data.description}</p>
|
||||
</div>
|
||||
</Card>
|
||||
</Link>
|
||||
</Col>
|
||||
);
|
||||
|
||||
let itemEnrollmentType = this.durationItemArray.map((data) =>
|
||||
<Col key={data.name} span={6}>
|
||||
<Link
|
||||
to={{
|
||||
//Path to respective report page
|
||||
pathname: "/entgra/enrollmenttype",
|
||||
reportData: {
|
||||
duration: data.duration,
|
||||
reportType: data.reportType,
|
||||
params: this.state.enrollmentTypeParams,
|
||||
paramsType: data.paramsType
|
||||
}
|
||||
}}>
|
||||
<Card key={data.name} bordered={true} hoverable={true} style={{borderRadius: 10, marginBottom: 16}}>
|
||||
|
||||
<div align='center'>
|
||||
<Icon type="desktop" style={{ fontSize: '25px', color: '#08c' }}/>
|
||||
<h2><b>{data.name}</b></h2>
|
||||
<p>{data.description}</p>
|
||||
</div>
|
||||
</Card>
|
||||
</Link>
|
||||
</Col>
|
||||
);
|
||||
return(
|
||||
<div>
|
||||
<div style={{borderRadius: 5}}>
|
||||
<Row gutter={16} >
|
||||
{itemStatus}
|
||||
</Row>
|
||||
</div>
|
||||
|
||||
<div style={{borderRadius: 5}}>
|
||||
<Row gutter={16} >
|
||||
{itemEnrollmentsVsUnenrollments}
|
||||
</Row>
|
||||
</div>
|
||||
|
||||
<div style={{borderRadius: 5}}>
|
||||
<Row gutter={16} >
|
||||
{itemEnrollmentType}
|
||||
</Row>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default ReportDurationItemList;
|
||||
@ -24,9 +24,7 @@ import {
|
||||
Icon
|
||||
} from "antd";
|
||||
import {Link} from "react-router-dom";
|
||||
import ReportDeviceTable from "../../../components/Devices/ReportDevicesTable";
|
||||
import Filter from "../../../components/Reports/Filter";
|
||||
import DateRangePicker from "../../../components/Reports/DateRangePicker";
|
||||
import ReportDurationItemList from "./ReportDurationItemList";
|
||||
|
||||
const {Paragraph} = Typography;
|
||||
|
||||
@ -37,17 +35,16 @@ class Reports extends React.Component {
|
||||
super(props);
|
||||
this.routes = props.routes;
|
||||
this.state = {
|
||||
paramsObject:{}
|
||||
paramsObject:{},
|
||||
}
|
||||
}
|
||||
|
||||
//Get modified value from datepicker and set it to 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) => {
|
||||
@ -64,7 +61,7 @@ class Reports extends React.Component {
|
||||
}
|
||||
}
|
||||
this.setState({paramsObject:tempParamObj});
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
//Arrays for filters
|
||||
@ -84,41 +81,7 @@ class Reports extends React.Component {
|
||||
</Breadcrumb>
|
||||
<div className="wrap">
|
||||
<h3>Reports</h3>
|
||||
<Paragraph>
|
||||
To generate a report, select a duration and apply filters
|
||||
</Paragraph>
|
||||
<div style={{paddingBottom:'5px'}}>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr style={{fontSize:'12px'}}>
|
||||
<td>Select Duration</td>
|
||||
<td>Device Status</td>
|
||||
<td>Device Ownership</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<DateRangePicker
|
||||
updateDurationValue={this.updateDurationValue}/>
|
||||
</td>
|
||||
<td>
|
||||
<Filter
|
||||
updateFiltersValue={this.updateFiltersValue}
|
||||
dropDownItems={statusObj}
|
||||
dropDownName={"Device Status"}/>
|
||||
</td>
|
||||
<td>
|
||||
<Filter
|
||||
updateFiltersValue={this.updateFiltersValue}
|
||||
dropDownItems={ownershipObj}
|
||||
dropDownName={"Device Ownership"}/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div style={{backgroundColor:"#ffffff", borderRadius: 5}}>
|
||||
<ReportDeviceTable paramsObject={params}/>
|
||||
</div>
|
||||
<ReportDurationItemList/>
|
||||
</div>
|
||||
</PageHeader>
|
||||
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}>
|
||||
|
||||
@ -42,6 +42,7 @@ import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.util.List;
|
||||
|
||||
@SwaggerDefinition(
|
||||
info = @Info(
|
||||
@ -127,7 +128,7 @@ public interface ReportManagementService {
|
||||
@ApiParam(
|
||||
name = "status",
|
||||
value = "Provide the device status details, such as active or inactive.")
|
||||
@QueryParam("status") String status,
|
||||
@QueryParam("status") List<String> status,
|
||||
@ApiParam(
|
||||
name = "ownership",
|
||||
allowableValues = "BYOD, COPE",
|
||||
@ -157,4 +158,76 @@ public interface ReportManagementService {
|
||||
defaultValue = "5")
|
||||
@QueryParam("limit")
|
||||
int limit) throws ReportManagementException;
|
||||
|
||||
|
||||
@GET
|
||||
@Path("/devices/count")
|
||||
@ApiOperation(
|
||||
produces = MediaType.APPLICATION_JSON,
|
||||
httpMethod = "GET",
|
||||
value = "Getting Details of Registered Devices",
|
||||
notes = "Provides details of all the devices enrolled with WSO2 IoT Server.",
|
||||
tags = "Device Management",
|
||||
extensions = {
|
||||
@Extension(properties = {
|
||||
@ExtensionProperty(name = Constants.SCOPE, value = "perm:devices:view")
|
||||
})
|
||||
}
|
||||
)
|
||||
@ApiResponses(
|
||||
value = {
|
||||
@ApiResponse(
|
||||
code = 200,
|
||||
message = "OK. \n Successfully fetched the list of devices.",
|
||||
response = DeviceList.class,
|
||||
responseHeaders = {
|
||||
@ResponseHeader(
|
||||
name = "Content-Type",
|
||||
description = "The content type of the body"),
|
||||
@ResponseHeader(
|
||||
name = "ETag",
|
||||
description = "Entity Tag of the response resource.\n" +
|
||||
"Used by caches, or in conditional requests."),
|
||||
@ResponseHeader(
|
||||
name = "Last-Modified",
|
||||
description = "Date and time the resource was last modified.\n" +
|
||||
"Used by caches, or in conditional requests."),
|
||||
}),
|
||||
@ApiResponse(
|
||||
code = 400,
|
||||
message = "Bad Request. \n Invalid device status type received. \n" +
|
||||
"Valid status types are NEW | CHECKED",
|
||||
response = ErrorResponse.class),
|
||||
@ApiResponse(
|
||||
code = 404,
|
||||
message = "Not Found. \n There are no devices.",
|
||||
response = ErrorResponse.class),
|
||||
@ApiResponse(
|
||||
code = 500,
|
||||
message = "Internal Server Error. " +
|
||||
"\n Server error occurred while fetching the device list.",
|
||||
response = ErrorResponse.class)
|
||||
})
|
||||
Response getDevicesByDurationCount(
|
||||
@ApiParam(
|
||||
name = "status",
|
||||
value = "Provide the device status details, such as active or inactive.")
|
||||
@QueryParam("status") List<String> status,
|
||||
@ApiParam(
|
||||
name = "ownership",
|
||||
allowableValues = "BYOD, COPE",
|
||||
value = "Provide the ownership status of the device. The following values can be assigned:\n" +
|
||||
"- BYOD: Bring Your Own Device\n" +
|
||||
"- COPE: Corporate-Owned, Personally-Enabled")
|
||||
@QueryParam("ownership") String ownership,
|
||||
@ApiParam(
|
||||
name = "fromDate",
|
||||
value = "Start date of the duration",
|
||||
required = true)
|
||||
@QueryParam("from") String fromDate,
|
||||
@ApiParam(
|
||||
name = "toDate",
|
||||
value = "end date of the duration",
|
||||
required = true)
|
||||
@QueryParam("to") String toDate) throws ReportManagementException;
|
||||
}
|
||||
@ -23,6 +23,7 @@ import org.apache.commons.logging.LogFactory;
|
||||
import org.wso2.carbon.device.mgt.common.Device;
|
||||
import org.wso2.carbon.device.mgt.common.PaginationRequest;
|
||||
import org.wso2.carbon.device.mgt.common.PaginationResult;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.ReportManagementException;
|
||||
import org.wso2.carbon.device.mgt.jaxrs.beans.DeviceList;
|
||||
import org.wso2.carbon.device.mgt.jaxrs.beans.ErrorResponse;
|
||||
@ -54,13 +55,13 @@ public class ReportManagementServiceImpl implements ReportManagementService {
|
||||
@Path("/devices")
|
||||
@Override
|
||||
public Response getDevicesByDuration(
|
||||
@QueryParam("status") String status,
|
||||
@QueryParam("status") List<String> status,
|
||||
@QueryParam("ownership") String ownership,
|
||||
@QueryParam("from") String fromDate,
|
||||
@QueryParam("to") String toDate,
|
||||
@DefaultValue("0")
|
||||
@QueryParam("offset") int offset,
|
||||
@DefaultValue("5")
|
||||
@DefaultValue("10")
|
||||
@QueryParam("limit") int limit) {
|
||||
try {
|
||||
RequestValidationUtil.validatePaginationParameters(offset, limit);
|
||||
@ -68,15 +69,12 @@ public class ReportManagementServiceImpl implements ReportManagementService {
|
||||
PaginationResult result;
|
||||
DeviceList devices = new DeviceList();
|
||||
|
||||
if (!StringUtils.isBlank(status)) {
|
||||
request.setStatus(status);
|
||||
}
|
||||
if (!StringUtils.isBlank(ownership)) {
|
||||
request.setOwnership(ownership);
|
||||
}
|
||||
|
||||
result = DeviceMgtAPIUtils.getReportManagementService()
|
||||
.getDevicesByDuration(request, fromDate, toDate);
|
||||
.getDevicesByDuration(request, status, fromDate, toDate);
|
||||
if (result.getData().isEmpty()) {
|
||||
String msg = "No devices have enrolled between " + fromDate + " to " + toDate +
|
||||
" or doesn't match with" +
|
||||
@ -94,4 +92,24 @@ public class ReportManagementServiceImpl implements ReportManagementService {
|
||||
new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build();
|
||||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/devices/count")
|
||||
@Override
|
||||
public Response getDevicesByDurationCount(
|
||||
@QueryParam("status") List<String> status,
|
||||
@QueryParam("ownership") String ownership,
|
||||
@QueryParam("from") String fromDate,
|
||||
@QueryParam("to") String toDate) {
|
||||
int deviceCount;
|
||||
try {
|
||||
deviceCount = DeviceMgtAPIUtils.getReportManagementService().getDevicesByDurationCount(status, ownership, fromDate, toDate);
|
||||
return Response.status(Response.Status.OK).entity(deviceCount).build();
|
||||
} catch (ReportManagementException e) {
|
||||
String errorMessage = "Error while retrieving device count.";
|
||||
log.error(errorMessage, e);
|
||||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(
|
||||
new ErrorResponse.ErrorResponseBuilder().setMessage(errorMessage).build()).build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,6 +21,8 @@ import org.wso2.carbon.device.mgt.common.PaginationRequest;
|
||||
import org.wso2.carbon.device.mgt.common.PaginationResult;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.ReportManagementException;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This is the service class for reports which connects with DAO layer
|
||||
*/
|
||||
@ -36,6 +38,9 @@ public interface ReportManagementService {
|
||||
* @throws {@Link DeviceManagementException} When error occurred while validating device list page size
|
||||
* @throws {@Link ReportManagementException} When failed to retrieve devices.
|
||||
*/
|
||||
PaginationResult getDevicesByDuration(PaginationRequest request, String fromDate, String toDate)
|
||||
PaginationResult getDevicesByDuration(PaginationRequest request, List<String> statusList, String fromDate, String toDate)
|
||||
throws ReportManagementException;
|
||||
|
||||
int getDevicesByDurationCount(List<String> statusList, String ownership, String fromDate, String toDate)
|
||||
throws ReportManagementException;
|
||||
}
|
||||
|
||||
@ -552,10 +552,15 @@ public interface DeviceDAO {
|
||||
*
|
||||
*/
|
||||
List<Device> getDevicesByDuration(PaginationRequest request,
|
||||
List<String> statusList,
|
||||
int tenantId,
|
||||
String fromDate,
|
||||
String toDate) throws DeviceManagementDAOException;
|
||||
|
||||
int getDevicesByDurationCount(
|
||||
List<String> statusList, String ownership, String fromDate, String toDate, int tenantId)
|
||||
throws DeviceManagementDAOException;
|
||||
|
||||
/**
|
||||
* Retrieve device location information
|
||||
* @param deviceIdentifier Device Identifier object
|
||||
|
||||
@ -455,12 +455,12 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Device> getDevicesByDuration(PaginationRequest request, int tenantId,
|
||||
public List<Device> getDevicesByDuration(PaginationRequest request, List<String> statusList, int tenantId,
|
||||
String fromDate, String toDate)
|
||||
throws DeviceManagementDAOException {
|
||||
List<Device> devices;
|
||||
String deviceStatus = request.getStatus();
|
||||
String ownership = request.getOwnership();
|
||||
boolean isStatusProvided = false;
|
||||
|
||||
String sql = "SELECT " +
|
||||
"d.ID AS DEVICE_ID, " +
|
||||
@ -479,9 +479,15 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl {
|
||||
"e.TENANT_ID = ? AND " +
|
||||
"e.DATE_OF_ENROLMENT BETWEEN ? AND ?";
|
||||
|
||||
if (deviceStatus != null) {
|
||||
sql = sql + " AND e.STATUS = ?";
|
||||
//Add the query for status
|
||||
StringBuilder sqlBuilder = new StringBuilder(sql);
|
||||
isStatusProvided = buildStatusQuery(statusList, sqlBuilder);
|
||||
sql = sqlBuilder.toString();
|
||||
|
||||
if(statusList != null && !statusList.isEmpty()){
|
||||
isStatusProvided = true;
|
||||
}
|
||||
|
||||
if (ownership != null) {
|
||||
sql = sql + " AND e.OWNERSHIP = ?";
|
||||
}
|
||||
@ -494,8 +500,10 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl {
|
||||
stmt.setInt(paramIdx++, tenantId);
|
||||
stmt.setString(paramIdx++, fromDate);
|
||||
stmt.setString(paramIdx++, toDate);
|
||||
if (deviceStatus != null) {
|
||||
stmt.setString(paramIdx++, deviceStatus);
|
||||
if (isStatusProvided) {
|
||||
for (String status : statusList) {
|
||||
stmt.setString(paramIdx++, status);
|
||||
}
|
||||
}
|
||||
if (ownership != null) {
|
||||
stmt.setString(paramIdx++, ownership);
|
||||
@ -518,6 +526,73 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl {
|
||||
return devices;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDevicesByDurationCount(List<String> statusList, String ownership, String fromDate, String toDate, int tenantId) throws DeviceManagementDAOException {
|
||||
int deviceCount = 0;
|
||||
boolean isStatusProvided = false;
|
||||
|
||||
String sql = "SELECT " +
|
||||
"COUNT(d.ID) AS DEVICE_COUNT " +
|
||||
"FROM DM_DEVICE AS d , DM_ENROLMENT AS e , DM_DEVICE_TYPE AS t " +
|
||||
"WHERE d.ID = e.DEVICE_ID AND " +
|
||||
"d.DEVICE_TYPE_ID = t.ID AND " +
|
||||
"e.TENANT_ID = ? AND " +
|
||||
"e.DATE_OF_ENROLMENT BETWEEN ? AND ?";
|
||||
|
||||
//Add the query for status
|
||||
StringBuilder sqlBuilder = new StringBuilder(sql);
|
||||
isStatusProvided = buildStatusQuery(statusList, sqlBuilder);
|
||||
sql = sqlBuilder.toString();
|
||||
|
||||
if (ownership != null) {
|
||||
sql = sql + " AND e.OWNERSHIP = ?";
|
||||
}
|
||||
|
||||
try (Connection conn = this.getConnection();
|
||||
PreparedStatement stmt = conn.prepareStatement(sql)) {
|
||||
int paramIdx = 1;
|
||||
stmt.setInt(paramIdx++, tenantId);
|
||||
stmt.setString(paramIdx++, fromDate);
|
||||
stmt.setString(paramIdx++, toDate);
|
||||
if (isStatusProvided) {
|
||||
for (String status : statusList) {
|
||||
stmt.setString(paramIdx++, status);
|
||||
}
|
||||
}
|
||||
if (ownership != null) {
|
||||
stmt.setString(paramIdx++, ownership);
|
||||
}
|
||||
try (ResultSet rs = stmt.executeQuery()) {
|
||||
if (rs.next()) {
|
||||
deviceCount = rs.getInt("DEVICE_COUNT");
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
String msg = "Error occurred while retrieving information of all " +
|
||||
"registered devices under tenant id " + tenantId;
|
||||
log.error(msg, e);
|
||||
throw new DeviceManagementDAOException(msg, e);
|
||||
}
|
||||
return deviceCount;
|
||||
}
|
||||
|
||||
protected boolean buildStatusQuery(List<String> statusList, StringBuilder sqlBuilder) {
|
||||
if (statusList != null && !statusList.isEmpty() && !statusList.get(0).isEmpty()) {
|
||||
sqlBuilder.append(" AND e.STATUS IN(");
|
||||
for (int i = 0; i < statusList.size(); i++) {
|
||||
sqlBuilder.append("?");
|
||||
if (i != statusList.size() - 1) {
|
||||
sqlBuilder.append(",");
|
||||
}
|
||||
}
|
||||
sqlBuilder.append(")");
|
||||
return true;
|
||||
}else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the list of devices that matches with the given device name and (or) device type.
|
||||
*
|
||||
|
||||
@ -459,7 +459,7 @@ public class OracleDeviceDAOImpl extends AbstractDeviceDAOImpl {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Device> getDevicesByDuration(PaginationRequest request, int tenantId,
|
||||
public List<Device> getDevicesByDuration(PaginationRequest request, List<String> statusList, int tenantId,
|
||||
String fromDate, String toDate)
|
||||
throws DeviceManagementDAOException {
|
||||
List<Device> devices;
|
||||
@ -522,6 +522,11 @@ public class OracleDeviceDAOImpl extends AbstractDeviceDAOImpl {
|
||||
return devices;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDevicesByDurationCount(List<String> statusList, String ownership, String fromDate, String toDate, int tenantId) throws DeviceManagementDAOException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of devices that matches with the given device name and (or) device type.
|
||||
*
|
||||
|
||||
@ -438,7 +438,7 @@ public class PostgreSQLDeviceDAOImpl extends AbstractDeviceDAOImpl {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Device> getDevicesByDuration(PaginationRequest request, int tenantId,
|
||||
public List<Device> getDevicesByDuration(PaginationRequest request, List<String> statusList, int tenantId,
|
||||
String fromDate, String toDate)
|
||||
throws DeviceManagementDAOException {
|
||||
List<Device> devices;
|
||||
@ -501,6 +501,11 @@ public class PostgreSQLDeviceDAOImpl extends AbstractDeviceDAOImpl {
|
||||
return devices;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDevicesByDurationCount(List<String> statusList, String ownership, String fromDate, String toDate, int tenantId) throws DeviceManagementDAOException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of devices that matches with the given device name and (or) device type.
|
||||
*
|
||||
|
||||
@ -601,7 +601,7 @@ public class SQLServerDeviceDAOImpl extends AbstractDeviceDAOImpl {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Device> getDevicesByDuration(PaginationRequest request, int tenantId,
|
||||
public List<Device> getDevicesByDuration(PaginationRequest request, List<String> statusList, int tenantId,
|
||||
String fromDate, String toDate)
|
||||
throws DeviceManagementDAOException {
|
||||
List<Device> devices;
|
||||
@ -664,6 +664,11 @@ public class SQLServerDeviceDAOImpl extends AbstractDeviceDAOImpl {
|
||||
return devices;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDevicesByDurationCount(List<String> statusList, String ownership, String fromDate, String toDate, int tenantId) throws DeviceManagementDAOException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSubscribedDeviceCount(List<Integer> deviceIds, int tenantId, String status)
|
||||
throws DeviceManagementDAOException {
|
||||
|
||||
@ -49,7 +49,7 @@ public class ReportManagementServiceImpl implements ReportManagementService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public PaginationResult getDevicesByDuration(PaginationRequest request, String fromDate,
|
||||
public PaginationResult getDevicesByDuration(PaginationRequest request, List<String> statusList, String fromDate,
|
||||
String toDate)
|
||||
throws ReportManagementException {
|
||||
PaginationResult paginationResult = new PaginationResult();
|
||||
@ -64,6 +64,7 @@ public class ReportManagementServiceImpl implements ReportManagementService {
|
||||
DeviceManagementDAOFactory.openConnection();
|
||||
List<Device> devices = deviceDAO.getDevicesByDuration(
|
||||
request,
|
||||
statusList,
|
||||
DeviceManagementDAOUtil.getTenantId(),
|
||||
fromDate,
|
||||
toDate
|
||||
@ -85,4 +86,23 @@ public class ReportManagementServiceImpl implements ReportManagementService {
|
||||
DeviceManagementDAOFactory.closeConnection();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDevicesByDurationCount(List<String> statusList, String ownership, String fromDate, String toDate)
|
||||
throws ReportManagementException {
|
||||
try {
|
||||
DeviceManagementDAOFactory.openConnection();
|
||||
return deviceDAO.getDevicesByDurationCount(statusList, ownership, fromDate, toDate, DeviceManagementDAOUtil.getTenantId());
|
||||
} catch (DeviceManagementDAOException e) {
|
||||
String msg = "Error occurred in while retrieving device count by status for " + statusList + "devices.";
|
||||
log.error(msg, e);
|
||||
throw new ReportManagementException(msg, e);
|
||||
} catch (SQLException e) {
|
||||
String msg = "Error occurred while opening a connection to the data source";
|
||||
log.error(msg, e);
|
||||
throw new ReportManagementException(msg, e);
|
||||
} finally {
|
||||
DeviceManagementDAOFactory.closeConnection();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user