mirror of
https://repository.entgra.net/community/device-mgt-core.git
synced 2025-10-06 02:01:45 +00:00
Merge branch 'application-mgt-new' of gitlab.com:entgra/carbon-device-mgt into application-mgt-new
This commit is contained in:
commit
8feb157bb9
@ -30,7 +30,7 @@ import {
|
||||
Spin,
|
||||
message,
|
||||
Icon,
|
||||
Card
|
||||
Card, Badge
|
||||
} from 'antd';
|
||||
import DetailedRating from "../../detailed-rating/DetailedRating";
|
||||
import {Link} from "react-router-dom";
|
||||
@ -487,18 +487,14 @@ class AppDetailsDrawer extends React.Component {
|
||||
)}
|
||||
|
||||
<Text strong={true}>Releases </Text>
|
||||
{/*display add new release only if app type is enterprise*/}
|
||||
|
||||
<div className="releases-details">
|
||||
|
||||
{(app.type === "ENTERPRISE") && (
|
||||
<Link to={`/publisher/apps/${app.deviceType}/${app.id}/add-release`}><Button
|
||||
htmlType="button"
|
||||
size="small">Add
|
||||
new release</Button></Link>)}
|
||||
<List
|
||||
style={{paddingTop: 16}}
|
||||
grid={{gutter: 16, column: 2}}
|
||||
pagination={{
|
||||
pageSize: 4, // number of releases per page
|
||||
size: "small",
|
||||
}}
|
||||
dataSource={app.applicationReleases}
|
||||
renderItem={release => (
|
||||
<div className="app-release-cards">
|
||||
@ -507,7 +503,27 @@ class AppDetailsDrawer extends React.Component {
|
||||
<Card className="release-card">
|
||||
<Meta
|
||||
avatar={
|
||||
<Avatar size="large" shape="square" src={release.iconPath}/>
|
||||
<div>
|
||||
{(release.currentStatus === "PUBLISHED") ? (
|
||||
<Badge
|
||||
title="Published"
|
||||
style={{
|
||||
backgroundColor: '#52c41a',
|
||||
borderRadius:"50%",
|
||||
color:"white"
|
||||
}}
|
||||
count={
|
||||
<Icon
|
||||
type="check-circle"/>
|
||||
}>
|
||||
<Avatar size="large" shape="square"
|
||||
src={release.iconPath}/>
|
||||
</Badge>
|
||||
) : (
|
||||
<Avatar size="large" shape="square"
|
||||
src={release.iconPath}/>
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
title={release.version}
|
||||
description={
|
||||
@ -529,10 +545,27 @@ class AppDetailsDrawer extends React.Component {
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
|
||||
</div>
|
||||
|
||||
<Divider dashed={true}/>
|
||||
{/*display add new release only if app type is enterprise*/}
|
||||
{(app.type === "ENTERPRISE") && (
|
||||
<div>
|
||||
<div style={{paddingBottom: 16}}>
|
||||
<Text>
|
||||
Add new release for the application
|
||||
</Text>
|
||||
</div>
|
||||
<Link to={`/publisher/apps/${app.deviceType}/${app.id}/add-release`}>
|
||||
<Button
|
||||
htmlType="button"
|
||||
type="primary"
|
||||
size="small">
|
||||
Add
|
||||
</Button>
|
||||
</Link>
|
||||
</div>)}
|
||||
<Divider dashed={true}/>
|
||||
|
||||
<Text strong={true}>Description </Text>
|
||||
{!isDescriptionEditEnabled && (
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import {Avatar, Table, Tag, Icon, message, notification, Col} from "antd";
|
||||
import {Avatar, Table, Tag, Icon, message, notification, Col, Badge} from "antd";
|
||||
import axios from "axios";
|
||||
import pSBC from 'shade-blend-color';
|
||||
import "./AppsTable.css";
|
||||
@ -47,7 +47,31 @@ const columns = [
|
||||
</Avatar>
|
||||
);
|
||||
} else {
|
||||
avatar = (
|
||||
const {applicationReleases} = row;
|
||||
let hasPublishedRelease = false;
|
||||
for (let i = 0; i < applicationReleases.length; i++) {
|
||||
if (applicationReleases[i].currentStatus === "PUBLISHED") {
|
||||
hasPublishedRelease = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
avatar = (hasPublishedRelease) ? (
|
||||
<Badge
|
||||
title="Published"
|
||||
style={{ backgroundColor: '#52c41a', borderRadius:"50%", color:"white"}}
|
||||
count={
|
||||
<Icon
|
||||
type="check-circle"/>
|
||||
}>
|
||||
<Avatar shape="square" size="large"
|
||||
style={{
|
||||
borderRadius: "28%",
|
||||
border: "1px solid #ddd"
|
||||
}}
|
||||
src={row.applicationReleases[0].iconPath}
|
||||
/>
|
||||
</Badge>
|
||||
) : (
|
||||
<Avatar shape="square" size="large"
|
||||
style={{
|
||||
marginRight: 20,
|
||||
@ -56,13 +80,13 @@ const columns = [
|
||||
}}
|
||||
src={row.applicationReleases[0].iconPath}
|
||||
/>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
{avatar}
|
||||
{name}
|
||||
<span style={{marginLeft: 20}}>{name}</span>
|
||||
</div>);
|
||||
}
|
||||
},
|
||||
|
||||
@ -24,6 +24,7 @@ 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";
|
||||
import {handleApiError} from "../../../js/Utils";
|
||||
|
||||
const {Text} = Typography;
|
||||
|
||||
@ -180,19 +181,7 @@ class InstalledDevicesTable extends React.Component {
|
||||
}
|
||||
|
||||
}).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.",
|
||||
});
|
||||
}
|
||||
|
||||
handleApiError(error, "Something went wrong when trying to load subscription data.");
|
||||
this.setState({loading: false});
|
||||
});
|
||||
};
|
||||
@ -203,10 +192,7 @@ class InstalledDevicesTable extends React.Component {
|
||||
<div>
|
||||
<div style={{paddingBottom: 24}}>
|
||||
<Text>
|
||||
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.
|
||||
The following are the subscription details of the application in each respective device.
|
||||
</Text>
|
||||
</div>
|
||||
<Table
|
||||
|
||||
@ -21,12 +21,9 @@ import {Divider, Row, Col, Typography, Button, Dropdown, notification, Menu, Ico
|
||||
import "../../../App.css";
|
||||
import ImgViewer from "../../apps/release/images/ImgViewer";
|
||||
import StarRatings from "react-star-ratings";
|
||||
import DetailedRating from "./DetailedRating";
|
||||
import Reviews from "./review/Reviews";
|
||||
import axios from "axios";
|
||||
import AppInstallModal from "./install/AppInstallModal";
|
||||
import AppUninstallModal from "./install/AppUninstallModal";
|
||||
import CurrentUsersReview from "./review/CurrentUsersReview";
|
||||
import {withConfigContext} from "../../../context/ConfigContext";
|
||||
import {handleApiError} from "../../../js/Utils";
|
||||
import ReviewContainer from "./review/ReviewContainer";
|
||||
@ -207,7 +204,7 @@ class ReleaseView extends React.Component {
|
||||
<Divider/>
|
||||
<ReviewContainer uuid={release.uuid}/>
|
||||
</TabPane>
|
||||
<TabPane tab="Installed devices" key="2">
|
||||
<TabPane tab="Subscription Details" key="2">
|
||||
<InstalledDevicesTable uuid={release.uuid}/>
|
||||
</TabPane>
|
||||
</Tabs>
|
||||
|
||||
@ -17,12 +17,11 @@
|
||||
"moment": "latest",
|
||||
"prop-types": "latest",
|
||||
"rc-viewer": "0.0.9",
|
||||
"react-advanced-datetimerange-picker": "^1.0.8",
|
||||
"react-bootstrap": "^1.0.0-beta.12",
|
||||
"react-highlight-words": "^0.16.0",
|
||||
"react-image-viewer-zoom": "^1.0.36",
|
||||
"react-infinite-scroller": "^1.2.4",
|
||||
"react-leaflet": "^2.4.0",
|
||||
"react-bootstrap": "^1.0.0-beta.12",
|
||||
"react-moment": "^0.9.2",
|
||||
"react-router": "^5.0.1",
|
||||
"react-router-config": "^5.0.1",
|
||||
@ -31,6 +30,7 @@
|
||||
"react-star-ratings": "^2.3.0",
|
||||
"react-twemoji": "^0.2.3",
|
||||
"react-virtualized": "^9.21.1",
|
||||
"react-websocket": "^2.1.0",
|
||||
"reqwest": "^2.0.5",
|
||||
"storm-react-diagrams": "^5.2.1"
|
||||
},
|
||||
|
||||
@ -18,9 +18,8 @@
|
||||
|
||||
import React from "react";
|
||||
import axios from "axios";
|
||||
import {Tag, message, notification, Table, Typography, Tooltip, Icon, Divider, Card, Col, Row, Select} from "antd";
|
||||
import {Card, Col, Icon, message, notification, Row, Typography} 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";
|
||||
@ -113,16 +112,27 @@ class DeviceTypesTable extends React.Component {
|
||||
render() {
|
||||
|
||||
const {data, pagination, loading, selectedRows} = this.state;
|
||||
|
||||
const { Meta } = Card;
|
||||
const itemCard = data.map((data) =>
|
||||
<Col span={8} key={data.id}>
|
||||
<Card hoverable title="Device Type" bordered={true}>
|
||||
{data.name}
|
||||
<Col span={5} key={data.id}>
|
||||
<Card
|
||||
size="default"
|
||||
style={{ width: 200 }}
|
||||
bordered={true}
|
||||
actions={[
|
||||
<Icon type="setting" key="setting" />,
|
||||
<Icon type="edit" key="edit" />,]}
|
||||
>
|
||||
<Meta
|
||||
avatar={<Icon type="desktop" key="device-types"/>}
|
||||
title={data.name}
|
||||
/>
|
||||
|
||||
</Card>
|
||||
</Col>
|
||||
);
|
||||
return (
|
||||
<div style={{ background: '#ECECEC', padding: '30px' }}>
|
||||
<div style={{ background: '#ECECEC', padding: '20px' }}>
|
||||
<Row gutter={16}>
|
||||
{itemCard}
|
||||
</Row>
|
||||
|
||||
@ -18,9 +18,8 @@
|
||||
|
||||
import React from "react";
|
||||
import axios from "axios";
|
||||
import {Tag, message, notification, Table, Typography, Tooltip, Icon, Divider, Button, Modal, Select} from "antd";
|
||||
import {Icon, message, Modal, notification, Select, Table, Tag, Tooltip, Typography} 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";
|
||||
@ -133,18 +132,11 @@ class DeviceTable extends React.Component {
|
||||
selectedRows: [],
|
||||
deviceGroups: [],
|
||||
groupModalVisible: false,
|
||||
selectedGroupId: []
|
||||
selectedGroupId: [],
|
||||
selectedRowKeys:[]
|
||||
};
|
||||
}
|
||||
|
||||
rowSelection = {
|
||||
onChange: (selectedRowKeys, selectedRows) => {
|
||||
this.setState({
|
||||
selectedRows: selectedRows
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.fetch();
|
||||
}
|
||||
@ -249,6 +241,9 @@ class DeviceTable extends React.Component {
|
||||
).then(res => {
|
||||
if (res.status === 200) {
|
||||
this.fetch();
|
||||
this.setState({
|
||||
selectedRowKeys:[]
|
||||
})
|
||||
notification["success"]({
|
||||
message: "Done",
|
||||
duration: 4,
|
||||
@ -409,11 +404,30 @@ class DeviceTable extends React.Component {
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const {data, pagination, loading, selectedRows} = this.state;
|
||||
onSelectChange = (selectedRowKeys, selectedRows) => {
|
||||
this.setState({
|
||||
selectedRowKeys,
|
||||
selectedRows: selectedRows
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const {data, pagination, loading, selectedRows, selectedRowKeys} = this.state;
|
||||
const isSelectedSingle = this.state.selectedRows.length == 1;
|
||||
|
||||
let selectedText;
|
||||
if(isSelectedSingle){
|
||||
selectedText = "You have selected 1 device"
|
||||
}else{
|
||||
selectedText = "You have selected " + this.state.selectedRows.length + " devices"
|
||||
}
|
||||
|
||||
const rowSelection = {
|
||||
selectedRowKeys,
|
||||
selectedRows,
|
||||
onChange: this.onSelectChange,
|
||||
};
|
||||
|
||||
let item = this.state.deviceGroups.map((data) =>
|
||||
<Select.Option
|
||||
value={data.id}
|
||||
@ -441,8 +455,7 @@ class DeviceTable extends React.Component {
|
||||
}}
|
||||
loading={loading}
|
||||
onChange={this.handleTableChange}
|
||||
rowSelection={this.rowSelection}
|
||||
scroll={{x: 1000}}
|
||||
rowSelection={rowSelection}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -453,10 +466,11 @@ class DeviceTable extends React.Component {
|
||||
onOk={this.handleOk}
|
||||
onCancel={this.handleCancel}
|
||||
>
|
||||
<p>{selectedText}</p>
|
||||
<Select
|
||||
mode={isSelectedSingle ? "multiple" : "default"}
|
||||
showSearch
|
||||
style={{width: 200}}
|
||||
style={{display:"block"}}
|
||||
placeholder="Select Group"
|
||||
optionFilterProp="children"
|
||||
onChange={this.onGroupSelectChange}
|
||||
|
||||
@ -18,9 +18,8 @@
|
||||
|
||||
import React from "react";
|
||||
import axios from "axios";
|
||||
import {Tag, message, notification, Table, Typography, Tooltip, Icon, Divider} from "antd";
|
||||
import {Icon, message, notification, Table, Tag, Tooltip, Typography} 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";
|
||||
@ -239,7 +238,6 @@ class ReportDeviceTable extends React.Component {
|
||||
loading={loading}
|
||||
onChange={this.handleTableChange}
|
||||
rowSelection={this.rowSelection}
|
||||
scroll={{x: 1000}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -18,8 +18,7 @@
|
||||
|
||||
import React from "react";
|
||||
import moment from "moment";
|
||||
import DateTimeRangeContainer from "react-advanced-datetimerange-picker";
|
||||
import {Button, Select, message, notification, Tag, Tooltip, Empty} from "antd";
|
||||
import {Button, Select, message, notification, Tag, Tooltip, Empty, DatePicker} from "antd";
|
||||
import axios from "axios";
|
||||
import {withConfigContext} from "../../../context/ConfigContext";
|
||||
import GeoCustomMap from "../geo-custom-map/GeoCustomMap";
|
||||
@ -29,15 +28,16 @@ class GeoDashboard extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
let start = moment(new Date());
|
||||
let start = moment(
|
||||
new Date(new Date().getFullYear(), new Date().getMonth(), new Date().getDate(), 0, 0, 0, 0)
|
||||
);
|
||||
let end = moment(start)
|
||||
.add(5, "days")
|
||||
.subtract(1, "minute");
|
||||
.add(1, "days")
|
||||
.subtract(1, "seconds");
|
||||
this.state = {
|
||||
deviceData: [],
|
||||
selectedDevice: '',
|
||||
locationData: [],
|
||||
// currentLocation: [],
|
||||
loading: false,
|
||||
start: start,
|
||||
end: end,
|
||||
@ -55,11 +55,11 @@ class GeoDashboard extends React.Component {
|
||||
* @param startDate - start date
|
||||
* @param endDate - end date
|
||||
*/
|
||||
applyCallback = (startDate, endDate) => {
|
||||
applyCallback = (dates, dateStrings) => {
|
||||
console.log("Apply Callback");
|
||||
this.setState({
|
||||
start: startDate,
|
||||
end: endDate
|
||||
start: dateStrings[0],
|
||||
end: dateStrings[1]
|
||||
});
|
||||
};
|
||||
|
||||
@ -180,6 +180,7 @@ class GeoDashboard extends React.Component {
|
||||
*/
|
||||
controllerBar = () => {
|
||||
|
||||
const {RangePicker} = DatePicker;
|
||||
let now = new Date();
|
||||
let start = moment(
|
||||
new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0, 0)
|
||||
@ -199,32 +200,20 @@ class GeoDashboard extends React.Component {
|
||||
"2 Weeks": [moment(start).subtract(14, "days"), moment(end)],
|
||||
"1 Month": [moment(start).subtract(1, "months"), moment(end)],
|
||||
};
|
||||
let local = {
|
||||
format: "DD-MM-YYYY HH:mm",
|
||||
sundayFirst: false
|
||||
};
|
||||
let maxDate = moment(start).add(24, "hour");
|
||||
let value =
|
||||
`
|
||||
${this.state.start.format("DD-MM-YYYY HH:mm")} - ${this.state.end.format("DD-MM-YYYY HH:mm")}
|
||||
`;
|
||||
|
||||
let {deviceData} = this.state;
|
||||
|
||||
return (
|
||||
<div className="controllerDiv">
|
||||
<RangePicker
|
||||
ranges={ranges}
|
||||
style={{marginRight: 20}}
|
||||
showTime
|
||||
format="YYYY-MM-DD HH:mm:ss"
|
||||
defaultValue={[this.state.start, this.state.end]}
|
||||
onChange={this.applyCallback}
|
||||
|
||||
<Button style={{marginRight: 20}}>
|
||||
<DateTimeRangeContainer
|
||||
ranges={ranges}
|
||||
start={this.state.start}
|
||||
end={this.state.end}
|
||||
local={local}
|
||||
maxDate={maxDate}
|
||||
applyCallback={this.applyCallback}
|
||||
>
|
||||
{value}
|
||||
</DateTimeRangeContainer>
|
||||
</Button>
|
||||
/>
|
||||
|
||||
<Select
|
||||
showSearch
|
||||
|
||||
175
components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Groups/AddGroup.js
vendored
Normal file
175
components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Groups/AddGroup.js
vendored
Normal file
@ -0,0 +1,175 @@
|
||||
/*
|
||||
* 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 {Button, Form, Input, message, Modal, notification, Typography} from "antd";
|
||||
import axios from "axios";
|
||||
import {withConfigContext} from "../../context/ConfigContext";
|
||||
|
||||
const {Text} = Typography;
|
||||
let config = null;
|
||||
|
||||
class AddGroup extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
config = this.props.context;
|
||||
this.state = {
|
||||
addModalVisible: false,
|
||||
name:'',
|
||||
description:'',
|
||||
}
|
||||
}
|
||||
|
||||
onConfirmAdGroup = () => {
|
||||
const config = this.props.context;
|
||||
|
||||
const groupData = {
|
||||
name: this.state.name,
|
||||
description: this.state.description
|
||||
}
|
||||
|
||||
//send request to the invoker
|
||||
axios.post(
|
||||
window.location.origin + config.serverConfig.invoker.uri +
|
||||
config.serverConfig.invoker.deviceMgt +
|
||||
"/groups",
|
||||
groupData,
|
||||
{headers: {'Content-Type': 'application/json'}}
|
||||
).then(res => {
|
||||
if (res.status === 201) {
|
||||
this.props.fetchGroups();
|
||||
notification["success"]({
|
||||
message: "Done",
|
||||
duration: 4,
|
||||
description:
|
||||
"Successfully added the group.",
|
||||
});
|
||||
}
|
||||
}).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 add group.",
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
openAddModal = () => {
|
||||
this.setState({
|
||||
addModalVisible:true
|
||||
})
|
||||
};
|
||||
|
||||
handleAddOk = e => {
|
||||
this.props.form.validateFields(err => {
|
||||
if (!err) {
|
||||
this.onConfirmAdGroup();
|
||||
this.setState({
|
||||
addModalVisible: false,
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
handleAddCancel = e => {
|
||||
this.setState({
|
||||
addModalVisible: false,
|
||||
});
|
||||
};
|
||||
|
||||
onChangeName = (e) => {
|
||||
this.setState({
|
||||
name:e.currentTarget.value
|
||||
})
|
||||
};
|
||||
|
||||
onChangeDescription = (e) => {
|
||||
this.setState({
|
||||
description:e.currentTarget.value
|
||||
})
|
||||
};
|
||||
|
||||
render() {
|
||||
const { getFieldDecorator } = this.props.form;
|
||||
return(
|
||||
<div>
|
||||
<div>
|
||||
<Button type="primary" icon="plus" size={"default"} onClick={this.openAddModal}>
|
||||
Add Group
|
||||
</Button>
|
||||
</div>
|
||||
<div>
|
||||
<Modal
|
||||
title="ADD NEW GROUP"
|
||||
width="40%"
|
||||
visible={this.state.addModalVisible}
|
||||
onOk={this.handleAddOk}
|
||||
onCancel={this.handleAddCancel}
|
||||
footer={[
|
||||
<Button key="cancel" onClick={this.handleAddCancel}>
|
||||
Cancel
|
||||
</Button>,
|
||||
<Button key="submit" type="primary" onClick={this.handleAddOk}>
|
||||
Submit
|
||||
</Button>,
|
||||
]}
|
||||
>
|
||||
<div style={{alignItems:"center"}}>
|
||||
<p>Create new device group on IoT Server.</p>
|
||||
<Form
|
||||
labelCol={{ span: 5 }}
|
||||
wrapperCol={{ span: 18 }}
|
||||
>
|
||||
<Form.Item label="Name" style={{display:"block"}}>
|
||||
{getFieldDecorator('name', {
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: 'Please input group name',
|
||||
},
|
||||
],
|
||||
})(<Input onChange={this.onChangeName}/>)}
|
||||
</Form.Item>
|
||||
<Form.Item label="Description" style={{display:"block"}}>
|
||||
{getFieldDecorator('description', {
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: 'Please input group description',
|
||||
},
|
||||
],
|
||||
})(<Input onChange={this.onChangeDescription}/>)}
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default withConfigContext(Form.create({name: 'add-group'})(AddGroup));
|
||||
379
components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Groups/GroupActions.js
vendored
Normal file
379
components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Groups/GroupActions.js
vendored
Normal file
@ -0,0 +1,379 @@
|
||||
/*
|
||||
* 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 {
|
||||
Button,
|
||||
Divider,
|
||||
Form,
|
||||
Icon,
|
||||
Input,
|
||||
message,
|
||||
Modal,
|
||||
notification,
|
||||
Popconfirm,
|
||||
Select,
|
||||
Tooltip,
|
||||
Typography
|
||||
} from "antd";
|
||||
import axios from "axios";
|
||||
import {withConfigContext} from "../../context/ConfigContext";
|
||||
|
||||
const {Text} = Typography;
|
||||
let config = null;
|
||||
|
||||
class GroupActions extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
config = this.props.context;
|
||||
this.state = {
|
||||
editModalVisible: false,
|
||||
shareModalVisible: false,
|
||||
name:this.props.data.name,
|
||||
description:this.props.data.description,
|
||||
groupDataObject:{},
|
||||
rolesData:[],
|
||||
shareRolesData:[]
|
||||
}
|
||||
}
|
||||
|
||||
onConfirmDeleteGroup = () => {
|
||||
const config = this.props.context;
|
||||
|
||||
//send request to the invoker
|
||||
axios.delete(
|
||||
window.location.origin + config.serverConfig.invoker.uri +
|
||||
config.serverConfig.invoker.deviceMgt +
|
||||
"/groups/id/" + this.props.data.id,
|
||||
{headers: {'Content-Type': 'application/json'}}
|
||||
|
||||
).then(res => {
|
||||
if (res.status === 200) {
|
||||
this.props.fetchGroups();
|
||||
notification["success"]({
|
||||
message: "Done",
|
||||
duration: 4,
|
||||
description:
|
||||
"Successfully deleted the group.",
|
||||
});
|
||||
}
|
||||
}).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 delete group.",
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
onConfirmUpdateGroup = (data) => {
|
||||
const config = this.props.context;
|
||||
|
||||
//send request to the invoker
|
||||
axios.put(
|
||||
window.location.origin + config.serverConfig.invoker.uri +
|
||||
config.serverConfig.invoker.deviceMgt +
|
||||
"/groups/id/" + this.props.data.id,
|
||||
data
|
||||
).then(res => {
|
||||
if (res.status === 200) {
|
||||
this.props.fetchGroups();
|
||||
notification["success"]({
|
||||
message: "Done",
|
||||
duration: 4,
|
||||
description:
|
||||
"Successfully updated the group.",
|
||||
});
|
||||
}
|
||||
}).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 update group.",
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
fetchUserRoles = (params = {}) => {
|
||||
const config = this.props.context;
|
||||
|
||||
const apiUrl = window.location.origin + config.serverConfig.invoker.uri +
|
||||
config.serverConfig.invoker.deviceMgt +
|
||||
"/roles";
|
||||
|
||||
//send request to the invokerss
|
||||
axios.get(apiUrl).then(res => {
|
||||
if (res.status === 200) {
|
||||
this.setState({
|
||||
rolesData: res.data.data.roles,
|
||||
});
|
||||
}
|
||||
}).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 roles.",
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
onConfirmShareGroup = (data) => {
|
||||
const config = this.props.context;
|
||||
|
||||
//send request to the invoker
|
||||
axios.post(
|
||||
window.location.origin + config.serverConfig.invoker.uri +
|
||||
config.serverConfig.invoker.deviceMgt +
|
||||
"/groups/id/" + this.props.data.id + "/share",
|
||||
data
|
||||
).then(res => {
|
||||
if (res.status === 200) {
|
||||
this.props.fetchGroups();
|
||||
notification["success"]({
|
||||
message: "Done",
|
||||
duration: 4,
|
||||
description:
|
||||
"Successfully shared the group.",
|
||||
});
|
||||
}
|
||||
}).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 share group.",
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
openEditModal = () => {
|
||||
this.setState({
|
||||
editModalVisible:true
|
||||
})
|
||||
};
|
||||
|
||||
openShareModal = () => {
|
||||
this.fetchUserRoles();
|
||||
this.setState({
|
||||
shareModalVisible:true
|
||||
})
|
||||
}
|
||||
|
||||
handleEditOk = e => {
|
||||
this.state.groupDataObject = {
|
||||
name:this.state.name,
|
||||
description:this.state.description,
|
||||
id:this.props.data.id,
|
||||
owner:this.props.data.owner,
|
||||
groupProperties:this.props.data.groupProperties
|
||||
};
|
||||
this.props.form.validateFields(err => {
|
||||
if (!err) {
|
||||
this.onConfirmUpdateGroup(this.state.groupDataObject);
|
||||
this.setState({
|
||||
editModalVisible: false,
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
handleEditCancel = e => {
|
||||
this.setState({
|
||||
editModalVisible: false,
|
||||
});
|
||||
};
|
||||
|
||||
handleShareOk = e => {
|
||||
this.setState({
|
||||
shareModalVisible: false,
|
||||
});
|
||||
this.onConfirmShareGroup(this.state.shareRolesData);
|
||||
};
|
||||
|
||||
handleShareCancel = e => {
|
||||
this.setState({
|
||||
shareModalVisible: false,
|
||||
});
|
||||
};
|
||||
|
||||
onChangeName = (e) => {
|
||||
this.setState({
|
||||
name:e.currentTarget.value
|
||||
})
|
||||
};
|
||||
|
||||
onChangeDescription = (e) => {
|
||||
this.setState({
|
||||
description:e.currentTarget.value
|
||||
})
|
||||
};
|
||||
|
||||
handleRolesDropdownChange = (value) => {
|
||||
this.setState({
|
||||
shareRolesData:value
|
||||
})
|
||||
};
|
||||
|
||||
render() {
|
||||
const isAdminGroups = this.props.data.id==1 || this.props.data.id==2;
|
||||
const { Option } = Select;
|
||||
const { getFieldDecorator } = this.props.form;
|
||||
let item = this.state.rolesData.map((data) =>
|
||||
<Select.Option
|
||||
value={data}
|
||||
key={data}>
|
||||
{data}
|
||||
</Select.Option>);
|
||||
return(
|
||||
<div>
|
||||
<div style={{display:isAdminGroups ? "none" : "inline"}}>
|
||||
<Tooltip placement="top" title={"Share Group"}>
|
||||
<a><Icon type="share-alt" onClick={this.openShareModal}/></a>
|
||||
</Tooltip>
|
||||
<Divider type="vertical" />
|
||||
<Tooltip placement="top" title={"Edit Group"}>
|
||||
<a><Icon type="edit" onClick={this.openEditModal}/></a>
|
||||
</Tooltip>
|
||||
<Divider type="vertical" />
|
||||
<Tooltip placement="bottom" title={"Delete Group"}>
|
||||
<Popconfirm
|
||||
placement="top"
|
||||
title={"Are you sure?"}
|
||||
onConfirm={this.onConfirmDeleteGroup}
|
||||
okText="Ok"
|
||||
cancelText="Cancel">
|
||||
<a><Text type="danger"><Icon type="delete"/></Text></a>
|
||||
</Popconfirm>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div>
|
||||
<Modal
|
||||
title="Update Group"
|
||||
width="40%"
|
||||
visible={this.state.editModalVisible}
|
||||
onOk={this.handleEditOk}
|
||||
onCancel={this.handleEditCancel}
|
||||
footer={[
|
||||
<Button key="cancel" onClick={this.handleEditCancel}>
|
||||
Cancel
|
||||
</Button>,
|
||||
<Button key="submit" type="primary" onClick={this.handleEditOk}>
|
||||
Submit
|
||||
</Button>,
|
||||
]}
|
||||
>
|
||||
<div style={{alignItems:"center"}}>
|
||||
<p>Enter new name and description for the group</p>
|
||||
<Form
|
||||
labelCol={{ span: 5 }}
|
||||
wrapperCol={{ span: 18 }}
|
||||
>
|
||||
<Form.Item label="Name" style={{display:"block"}}>
|
||||
{getFieldDecorator(
|
||||
'name',
|
||||
{
|
||||
initialValue: this.props.data.name,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: 'Please input group name',
|
||||
},
|
||||
],
|
||||
})(<Input
|
||||
onChange={this.onChangeName}/>)}
|
||||
</Form.Item>
|
||||
<Form.Item label="Description" style={{display:"block"}}>
|
||||
{getFieldDecorator(
|
||||
'description',
|
||||
{
|
||||
initialValue: this.props.data.description,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: 'Please input group description',
|
||||
},
|
||||
],
|
||||
})(<Input
|
||||
onChange={this.onChangeDescription}/>)}
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
<div>
|
||||
<Modal
|
||||
title="Share Group"
|
||||
width="500px"
|
||||
visible={this.state.shareModalVisible}
|
||||
onOk={this.handleShareOk}
|
||||
onCancel={this.handleShareCancel}
|
||||
footer={[
|
||||
<Button key="new-role" onClick={this.handleShareCancel}>
|
||||
New Role
|
||||
</Button>,
|
||||
<Button key="new-role-selection" onClick={this.handleShareCancel}>
|
||||
New Role from Selection
|
||||
</Button>,
|
||||
<Button key="submit" type="primary" onClick={this.handleShareOk}>
|
||||
Share
|
||||
</Button>,
|
||||
]}
|
||||
>
|
||||
<p>Select user role(s)</p>
|
||||
<Select
|
||||
mode="multiple"
|
||||
defaultValue={"admin"}
|
||||
style={{ width: '100%' }}
|
||||
onChange={this.handleRolesDropdownChange}>
|
||||
{item}
|
||||
</Select>,
|
||||
</Modal>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default withConfigContext(Form.create({name: 'group-actions'})(GroupActions));
|
||||
@ -18,40 +18,19 @@
|
||||
|
||||
import React from "react";
|
||||
import axios from "axios";
|
||||
import {Tag, message, notification, Table, Typography, Tooltip, Icon, Divider} from "antd";
|
||||
import {message, notification, Table, Typography} 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";
|
||||
import GroupActions from "./GroupActions";
|
||||
import AddGroup from "./AddGroup";
|
||||
|
||||
const {Text} = Typography;
|
||||
|
||||
let config = null;
|
||||
let apiUrl;
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: 'Group Name',
|
||||
dataIndex: 'name',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: 'Owner',
|
||||
dataIndex: 'owner',
|
||||
key: 'owner',
|
||||
// render: enrolmentInfo => enrolmentInfo.owner
|
||||
// todo add filtering options
|
||||
},
|
||||
{
|
||||
title: 'Description',
|
||||
dataIndex: 'description',
|
||||
key: 'description',
|
||||
// render: enrolmentInfo => enrolmentInfo.ownership
|
||||
// todo add filtering options
|
||||
}
|
||||
];
|
||||
|
||||
const getTimeAgo = (time) => {
|
||||
const timeAgo = new TimeAgo('en-US');
|
||||
return timeAgo.format(time);
|
||||
@ -70,6 +49,38 @@ class GroupsTable extends React.Component {
|
||||
};
|
||||
}
|
||||
|
||||
columns = [
|
||||
{
|
||||
title: 'Group Name',
|
||||
dataIndex: 'name',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: 'Owner',
|
||||
dataIndex: 'owner',
|
||||
key: 'owner',
|
||||
// render: enrolmentInfo => enrolmentInfo.owner
|
||||
// todo add filtering options
|
||||
},
|
||||
{
|
||||
title: 'Description',
|
||||
dataIndex: 'description',
|
||||
key: 'description',
|
||||
// render: enrolmentInfo => enrolmentInfo.ownership
|
||||
// todo add filtering options
|
||||
},
|
||||
{
|
||||
title: 'Action',
|
||||
dataIndex: 'id',
|
||||
key: 'action',
|
||||
render: (id, row) => (
|
||||
<span>
|
||||
<GroupActions data={row} fetchGroups={this.fetchGroups}/>
|
||||
</span>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
rowSelection = {
|
||||
onChange: (selectedRowKeys, selectedRows) => {
|
||||
this.setState({
|
||||
@ -130,6 +141,8 @@ class GroupsTable extends React.Component {
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
handleTableChange = (pagination, filters, sorter) => {
|
||||
const pager = {...this.state.pagination};
|
||||
pager.current = pagination.current;
|
||||
@ -148,24 +161,29 @@ class GroupsTable extends React.Component {
|
||||
render() {
|
||||
|
||||
const {data, pagination, loading, selectedRows} = this.state;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Table
|
||||
columns={columns}
|
||||
rowKey={record => (record.id)}
|
||||
dataSource={data}
|
||||
pagination={{
|
||||
...pagination,
|
||||
size: "small",
|
||||
// position: "top",
|
||||
showTotal: (total, range) => `showing ${range[0]}-${range[1]} of ${total} groups`
|
||||
// showQuickJumper: true
|
||||
}}
|
||||
loading={loading}
|
||||
onChange={this.handleTableChange}
|
||||
rowSelection={this.rowSelection}
|
||||
scroll={{x: 1000}}
|
||||
/>
|
||||
<div style={{background: '#f0f2f5'}}>
|
||||
<AddGroup fetchGroups={this.fetchGroups} style={{marginBottom:"10px"}}/>
|
||||
</div>
|
||||
<div>
|
||||
<Table
|
||||
columns={this.columns}
|
||||
rowKey={record => (record.id)}
|
||||
dataSource={data}
|
||||
pagination={{
|
||||
...pagination,
|
||||
size: "small",
|
||||
// position: "top",
|
||||
showTotal: (total, range) => `showing ${range[0]}-${range[1]} of ${total} groups`
|
||||
// showQuickJumper: true
|
||||
}}
|
||||
loading={loading}
|
||||
onChange={this.handleTableChange}
|
||||
rowSelection={this.rowSelection}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -18,7 +18,7 @@
|
||||
|
||||
import React from "react";
|
||||
import axios from "axios";
|
||||
import {Tag, message, notification, Table, Typography, Tooltip, Icon, Divider} from "antd";
|
||||
import {message, notification, Table, Typography} from "antd";
|
||||
import TimeAgo from 'javascript-time-ago'
|
||||
|
||||
// Load locale-specific relative date/time formatting rules.
|
||||
@ -171,7 +171,6 @@ class PoliciesTable extends React.Component {
|
||||
loading={loading}
|
||||
onChange={this.handleTableChange}
|
||||
rowSelection={this.rowSelection}
|
||||
scroll={{x: 1000}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -18,9 +18,8 @@
|
||||
|
||||
import React from "react";
|
||||
import axios from "axios";
|
||||
import {Tag, message, notification, Table, Typography, Tooltip, Icon, Divider, Card, Col, Row, Select} from "antd";
|
||||
import {Card, Col, Icon, message, notification, Row, Typography} 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";
|
||||
@ -124,18 +123,27 @@ class RolesTable extends React.Component {
|
||||
};
|
||||
|
||||
render() {
|
||||
|
||||
const {data, pagination, loading, selectedRows} = this.state;
|
||||
|
||||
const { Meta } = Card;
|
||||
const itemCard = data.map((data) =>
|
||||
<Col span={8} key={data}>
|
||||
<Card hoverable title="Role" bordered={true}>
|
||||
{data}
|
||||
</Card>
|
||||
<Col span={5} key={data}>
|
||||
<Card
|
||||
size="default"
|
||||
style={{ width: 200 }}
|
||||
bordered={true}
|
||||
actions={[
|
||||
<Icon type="setting" key="setting" />,
|
||||
<Icon type="edit" key="edit" />,]}
|
||||
>
|
||||
<Meta
|
||||
avatar={<Icon type="book" key="roles"/>}
|
||||
title={data}
|
||||
/>
|
||||
</Card>
|
||||
</Col>
|
||||
);
|
||||
return (
|
||||
<div style={{ background: '#ECECEC', padding: '30px' }}>
|
||||
<div style={{ background: '#ECECEC', padding: '20px' }}>
|
||||
<Row gutter={16}>
|
||||
{itemCard}
|
||||
</Row>
|
||||
|
||||
@ -18,9 +18,8 @@
|
||||
|
||||
import React from "react";
|
||||
import axios from "axios";
|
||||
import {Tag, message, notification, Table, Typography, Tooltip, Icon, Divider} from "antd";
|
||||
import {Icon, message, notification, Table, Tag, Tooltip, Typography} 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";
|
||||
@ -240,7 +239,6 @@ class UsersDevices extends React.Component {
|
||||
loading={loading}
|
||||
onChange={this.handleTableChange}
|
||||
rowSelection={this.rowSelection}
|
||||
scroll={{x: 1000}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -18,13 +18,11 @@
|
||||
|
||||
import React from "react";
|
||||
import axios from "axios";
|
||||
import {message, notification, Table, Typography, Panel, Collapse, Button, List, Modal, Icon} from "antd";
|
||||
import {Button, Collapse, Icon, List, message, Modal, notification, Table, Tabs, Typography} 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";
|
||||
import DeviceTable from "../Devices/DevicesTable";
|
||||
import UsersDevices from "./UsersDevices";
|
||||
|
||||
const {Text} = Typography;
|
||||
@ -174,9 +172,9 @@ class UsersTable extends React.Component {
|
||||
};
|
||||
|
||||
render() {
|
||||
|
||||
const {data, pagination, loading, selectedRows} = this.state;
|
||||
const { Panel } = Collapse;
|
||||
const { TabPane } = Tabs;
|
||||
const columns = [
|
||||
{
|
||||
title: 'User Name',
|
||||
@ -231,30 +229,44 @@ class UsersTable extends React.Component {
|
||||
loading={loading}
|
||||
onChange={this.handleTableChange}
|
||||
rowSelection={this.rowSelection}
|
||||
scroll={{x: 1000}}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Modal
|
||||
width="900px"
|
||||
title="Info"
|
||||
visible={this.state.rolesModalVisible}
|
||||
onOk={this.handleOk}
|
||||
onCancel={this.handleCancel}
|
||||
>
|
||||
<Collapse>
|
||||
<Panel header="User Roles" key="1">
|
||||
<Tabs size="small" defaultActiveKey="1">
|
||||
<TabPane
|
||||
tab={
|
||||
<span>
|
||||
<Icon type="book"/>
|
||||
Roles
|
||||
</span>
|
||||
}
|
||||
key="1"
|
||||
>
|
||||
<List
|
||||
size="small"
|
||||
bordered
|
||||
dataSource={this.state.rolesData}
|
||||
renderItem={item => <List.Item>{item}</List.Item>}
|
||||
/>
|
||||
</Panel>
|
||||
<Panel header="Enrolled Devices" key="2">
|
||||
</TabPane>
|
||||
<TabPane
|
||||
tab={
|
||||
<span>
|
||||
<Icon type="appstore"/>
|
||||
Enrolled Devices
|
||||
</span>
|
||||
}
|
||||
key="2"
|
||||
>
|
||||
<UsersDevices user={this.state.user}/>
|
||||
</Panel>
|
||||
</Collapse>
|
||||
</TabPane>
|
||||
</Tabs>
|
||||
</Modal>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -74,12 +74,25 @@ class Dashboard extends React.Component {
|
||||
<span>Devices</span>
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
<Menu.Item key="geo">
|
||||
<Link to="/entgra/geo">
|
||||
<Icon type="environment"/>
|
||||
<span>Geo</span>
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
<SubMenu
|
||||
key="geo"
|
||||
title={
|
||||
<span>
|
||||
<Icon type="environment"/>
|
||||
<span>Geo</span>
|
||||
</span>}
|
||||
>
|
||||
<Menu.Item key="singleDevice">
|
||||
<Link to="/entgra/geo">
|
||||
<span>Single Device View</span>
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
<Menu.Item key="deviceGroup">
|
||||
<Link to="#">
|
||||
<span>Device Group View</span>
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
</SubMenu>
|
||||
<Menu.Item key="reports">
|
||||
<Link to="/entgra/reports">
|
||||
<Icon type="bar-chart"/>
|
||||
|
||||
@ -25,6 +25,7 @@ import {
|
||||
} from "antd";
|
||||
import {Link} from "react-router-dom";
|
||||
import GroupsTable from "../../../components/Groups/GroupsTable";
|
||||
import AddGroup from "../../../components/Groups/AddGroup";
|
||||
|
||||
const {Paragraph} = Typography;
|
||||
|
||||
|
||||
@ -55,7 +55,7 @@ class Policies extends React.Component {
|
||||
</div>
|
||||
</PageHeader>
|
||||
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -157,7 +157,7 @@ class NormalLoginForm extends React.Component {
|
||||
)}
|
||||
<br/>
|
||||
<a className="login-form-forgot" href="">Forgot password</a>
|
||||
<Button block type="primary" htmlType="submit" className="login-form-button">
|
||||
<Button loading={this.state.loading} block type="primary" htmlType="submit" className="login-form-button">
|
||||
Log in
|
||||
</Button>
|
||||
</Form.Item>
|
||||
|
||||
@ -1713,16 +1713,16 @@ public interface DeviceManagementService {
|
||||
@Valid OperationRequest operationRequest);
|
||||
|
||||
@GET
|
||||
@Path("/status/count/{tenantDomain}/{type}/{status}")
|
||||
@Path("/type/{type}/status/{status}/count")
|
||||
@ApiOperation(
|
||||
produces = MediaType.APPLICATION_JSON,
|
||||
httpMethod = "GET",
|
||||
value = "Get Device Count with status",
|
||||
notes = "Get specified device count with status.",
|
||||
notes = "Get specified device count with type and status.",
|
||||
tags = "Device Management",
|
||||
extensions = {
|
||||
@Extension(properties = {
|
||||
@ExtensionProperty(name = Constants.SCOPE, value = "perm:devices:details")
|
||||
@ExtensionProperty(name = Constants.SCOPE, value = "perm:devices:view")
|
||||
})
|
||||
}
|
||||
)
|
||||
@ -1730,7 +1730,7 @@ public interface DeviceManagementService {
|
||||
value = {
|
||||
@ApiResponse(
|
||||
code = 200,
|
||||
message = "OK. \n Successfully fetched the details of the device.",
|
||||
message = "OK. \n Successfully fetched the count of matching devices.",
|
||||
response = int.class,
|
||||
responseHeaders = {
|
||||
@ResponseHeader(
|
||||
@ -1764,13 +1764,6 @@ public interface DeviceManagementService {
|
||||
response = ErrorResponse.class)
|
||||
})
|
||||
Response getDeviceCountByStatus(
|
||||
@ApiParam(
|
||||
name = "tenantDomain",
|
||||
value = "The tenant doamin.",
|
||||
required = true)
|
||||
@PathParam("tenantDomain")
|
||||
@Size(max = 45)
|
||||
String tenantDomain,
|
||||
@ApiParam(
|
||||
name = "type",
|
||||
value = "The device type name, such as ios, android, windows or fire-alarm.",
|
||||
@ -1788,17 +1781,16 @@ public interface DeviceManagementService {
|
||||
|
||||
|
||||
@GET
|
||||
@Path("/status/ids/{tenantDomain}/{type}/{status}")
|
||||
@Path("/type/{type}/status/{status}/ids")
|
||||
@ApiOperation(
|
||||
produces = MediaType.APPLICATION_JSON,
|
||||
httpMethod = "GET",
|
||||
value = "Getting Details of a Device",
|
||||
notes = "Get the details of a device by specifying the device type and device identifier and optionally " +
|
||||
"the owner.",
|
||||
value = "Getting ids of devices with specified type and status",
|
||||
notes = "Get the ids of a device by specifying the device type and status.",
|
||||
tags = "Device Management",
|
||||
extensions = {
|
||||
@Extension(properties = {
|
||||
@ExtensionProperty(name = Constants.SCOPE, value = "perm:devices:details")
|
||||
@ExtensionProperty(name = Constants.SCOPE, value = "perm:devices:view")
|
||||
})
|
||||
}
|
||||
)
|
||||
@ -1840,13 +1832,6 @@ public interface DeviceManagementService {
|
||||
response = ErrorResponse.class)
|
||||
})
|
||||
Response getDeviceIdentifiersByStatus(
|
||||
@ApiParam(
|
||||
name = "tenantDomain",
|
||||
value = "The tenant domain.",
|
||||
required = true)
|
||||
@PathParam("tenantDomain")
|
||||
@Size(max = 45)
|
||||
String tenantDomain,
|
||||
@ApiParam(
|
||||
name = "type",
|
||||
value = "The device type name, such as ios, android, windows or fire-alarm.",
|
||||
@ -1863,7 +1848,7 @@ public interface DeviceManagementService {
|
||||
String status);
|
||||
|
||||
@PUT
|
||||
@Path("/status/update/{tenantDomain}/{type}/{status}")
|
||||
@Path("/type/{type}/status/{status}")
|
||||
@ApiOperation(
|
||||
produces = MediaType.APPLICATION_JSON,
|
||||
consumes = MediaType.APPLICATION_JSON,
|
||||
@ -1915,8 +1900,6 @@ public interface DeviceManagementService {
|
||||
response = ErrorResponse.class)
|
||||
})
|
||||
Response bulkUpdateDeviceStatus(
|
||||
@ApiParam(name = "tenantDomain", value = "The tenant domain.", required = true)
|
||||
@PathParam("tenantDomain") String tenantDomain,
|
||||
@ApiParam(name = "type", value = "The device type, such as ios, android or windows.", required = true)
|
||||
@PathParam("type") String type,
|
||||
@ApiParam(name = "status", value = "The device type, such as ios, android or windows.", required = true)
|
||||
|
||||
@ -458,8 +458,10 @@ public interface GroupManagementService {
|
||||
|
||||
@Path("/id/{groupId}")
|
||||
@DELETE
|
||||
@Consumes(MediaType.WILDCARD)
|
||||
@ApiOperation(
|
||||
produces = MediaType.APPLICATION_JSON,
|
||||
consumes = MediaType.WILDCARD,
|
||||
httpMethod = HTTPConstants.HEADER_DELETE,
|
||||
value = "Deleting a Group",
|
||||
notes = "If you wish to remove an existing group, that can be done by updating the group using this API.",
|
||||
|
||||
@ -45,9 +45,11 @@ import io.swagger.annotations.ApiParam;
|
||||
import io.swagger.annotations.ApiResponse;
|
||||
import io.swagger.annotations.ApiResponses;
|
||||
import io.swagger.annotations.ResponseHeader;
|
||||
import org.apache.axis2.transport.http.HTTPConstants;
|
||||
import org.wso2.carbon.apimgt.annotations.api.Scope;
|
||||
import org.wso2.carbon.apimgt.annotations.api.Scopes;
|
||||
import org.wso2.carbon.device.mgt.common.Device;
|
||||
import org.wso2.carbon.device.mgt.jaxrs.beans.DeviceGroupList;
|
||||
import org.wso2.carbon.device.mgt.jaxrs.beans.DeviceList;
|
||||
import org.wso2.carbon.device.mgt.jaxrs.beans.ErrorResponse;
|
||||
import org.wso2.carbon.device.mgt.jaxrs.util.Constants;
|
||||
@ -198,6 +200,59 @@ public interface DeviceManagementAdminService {
|
||||
defaultValue = "5")
|
||||
@QueryParam("limit") int limit);
|
||||
|
||||
@Path("/count")
|
||||
@GET
|
||||
@ApiOperation(
|
||||
produces = MediaType.APPLICATION_JSON,
|
||||
httpMethod = HTTPConstants.HEADER_GET,
|
||||
value = "Get the count of devices.",
|
||||
notes = "Returns count of all devices enrolled with the system.",
|
||||
tags = "Device Management Administrative Service",
|
||||
extensions = {
|
||||
@Extension(properties = {
|
||||
@ExtensionProperty(name = Constants.SCOPE, value = "perm:admin:devices:view")
|
||||
})
|
||||
}
|
||||
)
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(code = 200, message = "OK. \n Successfully fetched the device count.",
|
||||
response = Integer.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 has been modified the last time.\n" +
|
||||
"Used by caches, or in conditional requests."),
|
||||
}),
|
||||
@ApiResponse(
|
||||
code = 304,
|
||||
message = "Not Modified. \n Empty body because the client has already the latest version of " +
|
||||
"the requested resource."),
|
||||
@ApiResponse(
|
||||
code = 404,
|
||||
message = "No groups found.",
|
||||
response = ErrorResponse.class),
|
||||
@ApiResponse(
|
||||
code = 406,
|
||||
message = "Not Acceptable.\n The requested media type is not supported."),
|
||||
@ApiResponse(
|
||||
code = 500,
|
||||
message = "Internal Server Error. \n Server error occurred while fetching the device count.",
|
||||
response = ErrorResponse.class)
|
||||
})
|
||||
Response getDeviceCount(@ApiParam(
|
||||
name = "status",
|
||||
value = "status of group of which count should be retrieved")
|
||||
@QueryParam("status")
|
||||
String status);
|
||||
|
||||
|
||||
@PUT
|
||||
@Path("/device-owner")
|
||||
@ApiOperation(
|
||||
|
||||
@ -33,10 +33,12 @@ import io.swagger.annotations.ResponseHeader;
|
||||
import org.apache.axis2.transport.http.HTTPConstants;
|
||||
import org.wso2.carbon.apimgt.annotations.api.Scope;
|
||||
import org.wso2.carbon.apimgt.annotations.api.Scopes;
|
||||
import org.wso2.carbon.device.mgt.common.group.mgt.DeviceGroup;
|
||||
import org.wso2.carbon.device.mgt.jaxrs.beans.DeviceGroupList;
|
||||
import org.wso2.carbon.device.mgt.jaxrs.beans.ErrorResponse;
|
||||
import org.wso2.carbon.device.mgt.jaxrs.util.Constants;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.ws.rs.*;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
@ -75,6 +77,12 @@ import javax.ws.rs.core.Response;
|
||||
description = "",
|
||||
key = "perm:admin-groups:count",
|
||||
permissions = {"/device-mgt/admin/groups/view"}
|
||||
),
|
||||
@Scope(
|
||||
name = "Add groups",
|
||||
description = "",
|
||||
key = "perm:admin-groups:add",
|
||||
permissions = {"/device-mgt/admin/groups/add"}
|
||||
)
|
||||
}
|
||||
)
|
||||
@ -166,7 +174,7 @@ public interface GroupManagementAdminService {
|
||||
)
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(code = 200, message = "OK. \n Successfully fetched the device group count.",
|
||||
response = DeviceGroupList.class,
|
||||
response = Integer.class,
|
||||
responseHeaders = {
|
||||
@ResponseHeader(
|
||||
name = "Content-Type",
|
||||
@ -202,4 +210,71 @@ public interface GroupManagementAdminService {
|
||||
@QueryParam("status")
|
||||
String status);
|
||||
|
||||
@POST
|
||||
@ApiOperation(
|
||||
consumes = MediaType.APPLICATION_JSON,
|
||||
httpMethod = HTTPConstants.HEADER_POST,
|
||||
value = "Adding a New Device Group",
|
||||
notes = "Add device group with the current user as the owner.",
|
||||
tags = "Device Group Management",
|
||||
extensions = {
|
||||
@Extension(properties = {
|
||||
@ExtensionProperty(name = Constants.SCOPE, value = "perm:admin-groups:add")
|
||||
})
|
||||
}
|
||||
)
|
||||
@ApiResponses(
|
||||
value = {
|
||||
@ApiResponse(
|
||||
code = 201,
|
||||
message = "Created. \n Device group has successfully been created",
|
||||
responseHeaders = {
|
||||
@ResponseHeader(
|
||||
name = "Content-Location",
|
||||
description = "The URL of the added group."),
|
||||
@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 has been modified the last time" +
|
||||
".\n" + "Used by caches, or in conditional requests.")
|
||||
}
|
||||
),
|
||||
@ApiResponse(
|
||||
code = 303,
|
||||
message = "See Other. \n Source can be retrieved from the URL specified at the Location " +
|
||||
"header.",
|
||||
responseHeaders = {
|
||||
@ResponseHeader(
|
||||
name = "Content-Location",
|
||||
description = "The Source URL of the document.")}),
|
||||
@ApiResponse(
|
||||
code = 400,
|
||||
message = "Bad Request. \n Invalid request or validation error.",
|
||||
response = ErrorResponse.class),
|
||||
@ApiResponse(
|
||||
code = 401,
|
||||
message = "Unauthorized. \n Current logged in user is not authorized to add device groups.",
|
||||
response = ErrorResponse.class),
|
||||
@ApiResponse(
|
||||
code = 415,
|
||||
message = "Unsupported media type. \n The entity of the request was in a not supported " +
|
||||
"format."),
|
||||
@ApiResponse(
|
||||
code = 500,
|
||||
message = "Internal Server Error. \n " +
|
||||
"Server error occurred while adding a new device group.",
|
||||
response = ErrorResponse.class)
|
||||
})
|
||||
Response createGroup(@ApiParam(
|
||||
name = "group",
|
||||
value = "Define the group object with data.",
|
||||
required = true)
|
||||
@Valid DeviceGroup group);
|
||||
|
||||
}
|
||||
|
||||
@ -973,66 +973,48 @@ public class DeviceManagementServiceImpl implements DeviceManagementService {
|
||||
|
||||
@GET
|
||||
@Override
|
||||
@Path("/status/count/{tenantDomain}/{type}/{status}")
|
||||
public Response getDeviceCountByStatus(@PathParam("tenantDomain") String tenantDomain, @PathParam("type") String type, @PathParam("status") String status) {
|
||||
@Path("/type/{type}/status/{status}/count")
|
||||
public Response getDeviceCountByStatus(@PathParam("type") String type, @PathParam("status") String status) {
|
||||
int deviceCount;
|
||||
try {
|
||||
int tenantId = DeviceMgtAPIUtils.getRealmService().getTenantManager().getTenantId(tenantDomain);
|
||||
deviceCount = DeviceMgtAPIUtils.getDeviceManagementService().getDeviceCountOfTypeByStatus(tenantId, type, status);
|
||||
deviceCount = DeviceMgtAPIUtils.getDeviceManagementService().getDeviceCountOfTypeByStatus(type, status);
|
||||
return Response.status(Response.Status.OK).entity(deviceCount).build();
|
||||
} catch (DeviceManagementException 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();
|
||||
} catch (UserStoreException e) {
|
||||
String errorMessage = "Error resolving tenant Domain";
|
||||
log.error(errorMessage, e);
|
||||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(
|
||||
new ErrorResponse.ErrorResponseBuilder().setMessage(errorMessage).build()).build();
|
||||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
@Override
|
||||
@Path("/status/ids/{tenantDomain}/{type}/{status}")
|
||||
public Response getDeviceIdentifiersByStatus(@PathParam("tenantDomain") String tenantDomain, @PathParam("type") String type, @PathParam("status") String status) {
|
||||
@Path("/type/{type}/status/{status}/ids")
|
||||
public Response getDeviceIdentifiersByStatus(@PathParam("type") String type, @PathParam("status") String status) {
|
||||
List<String> deviceIds;
|
||||
try {
|
||||
int tenantId = DeviceMgtAPIUtils.getRealmService().getTenantManager().getTenantId(tenantDomain);
|
||||
deviceIds = DeviceMgtAPIUtils.getDeviceManagementService().getDeviceIdentifiersByStatus(tenantId, type, status);
|
||||
deviceIds = DeviceMgtAPIUtils.getDeviceManagementService().getDeviceIdentifiersByStatus(type, status);
|
||||
return Response.status(Response.Status.OK).entity(deviceIds.toArray(new String[0])).build();
|
||||
} catch (DeviceManagementException e) {
|
||||
String errorMessage = "Error while obtaining list of devices";
|
||||
log.error(errorMessage, e);
|
||||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(
|
||||
new ErrorResponse.ErrorResponseBuilder().setMessage(errorMessage).build()).build();
|
||||
} catch (UserStoreException e) {
|
||||
String errorMessage = "Error resolving tenant Domain";
|
||||
log.error(errorMessage, e);
|
||||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(
|
||||
new ErrorResponse.ErrorResponseBuilder().setMessage(errorMessage).build()).build();
|
||||
}
|
||||
}
|
||||
|
||||
@PUT
|
||||
@Override
|
||||
@Path("/status/update/{tenantDomain}/{type}/{status}")
|
||||
public Response bulkUpdateDeviceStatus(@PathParam("tenantDomain") String tenantDomain, @PathParam("type") String type,
|
||||
@PathParam("status") String status, @Valid List<String> deviceList) {
|
||||
@Path("/type/{type}/status/{status}")
|
||||
public Response bulkUpdateDeviceStatus(@PathParam("type") String type, @PathParam("status") String status,
|
||||
@Valid List<String> deviceList) {
|
||||
try {
|
||||
int tenantId = DeviceMgtAPIUtils.getRealmService().getTenantManager().getTenantId(tenantDomain);
|
||||
DeviceMgtAPIUtils.getDeviceManagementService().bulkUpdateDeviceStatus(tenantId, type, deviceList, status);
|
||||
DeviceMgtAPIUtils.getDeviceManagementService().bulkUpdateDeviceStatus(type, deviceList, status);
|
||||
} catch (DeviceManagementException e) {
|
||||
String errorMessage = "Error while updating device status in bulk.";
|
||||
log.error(errorMessage, e);
|
||||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(
|
||||
new ErrorResponse.ErrorResponseBuilder().setMessage(errorMessage).build()).build();
|
||||
} catch (UserStoreException e) {
|
||||
String errorMessage = "Error resolving tenant Domain";
|
||||
log.error(errorMessage, e);
|
||||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(
|
||||
new ErrorResponse.ErrorResponseBuilder().setMessage(errorMessage).build()).build();
|
||||
}
|
||||
return Response.status(Response.Status.OK).build();
|
||||
}
|
||||
|
||||
@ -40,10 +40,10 @@ import org.wso2.carbon.base.MultitenantConstants;
|
||||
import org.wso2.carbon.context.CarbonContext;
|
||||
import org.wso2.carbon.context.PrivilegedCarbonContext;
|
||||
import org.wso2.carbon.device.mgt.common.Device;
|
||||
import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
|
||||
import org.wso2.carbon.device.mgt.common.EnrolmentInfo;
|
||||
import org.wso2.carbon.device.mgt.common.PaginationRequest;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.InvalidDeviceException;
|
||||
import org.wso2.carbon.device.mgt.common.PaginationRequest;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.UserNotFoundException;
|
||||
import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService;
|
||||
import org.wso2.carbon.device.mgt.jaxrs.beans.DeviceList;
|
||||
@ -53,7 +53,13 @@ import org.wso2.carbon.device.mgt.jaxrs.service.impl.util.RequestValidationUtil;
|
||||
import org.wso2.carbon.device.mgt.jaxrs.util.DeviceMgtAPIUtils;
|
||||
|
||||
import javax.validation.constraints.Size;
|
||||
import javax.ws.rs.*;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.HeaderParam;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
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;
|
||||
@ -107,6 +113,26 @@ public class DeviceManagementAdminServiceImpl implements DeviceManagementAdminSe
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Path("/count")
|
||||
@GET
|
||||
public Response getDeviceCount(@QueryParam("status") String status) {
|
||||
int deviceCount;
|
||||
try {
|
||||
if (status == null) {
|
||||
deviceCount = DeviceMgtAPIUtils.getDeviceManagementService().getDeviceCount();
|
||||
} else {
|
||||
deviceCount = DeviceMgtAPIUtils.getDeviceManagementService().getDeviceCount(EnrolmentInfo.Status.valueOf(status));
|
||||
}
|
||||
} catch (DeviceManagementException e) {
|
||||
String msg = "Error occurred while fetching device count.";
|
||||
log.error(msg, e);
|
||||
return Response.serverError().entity(
|
||||
new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build();
|
||||
}
|
||||
return Response.status(Response.Status.OK).entity(deviceCount).build();
|
||||
}
|
||||
|
||||
@PUT
|
||||
@Override
|
||||
@Path("/device-owner")
|
||||
|
||||
@ -20,9 +20,11 @@ package org.wso2.carbon.device.mgt.jaxrs.service.impl.admin;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.solr.common.StringUtils;
|
||||
import org.wso2.carbon.device.mgt.common.GroupPaginationRequest;
|
||||
import org.wso2.carbon.device.mgt.common.PaginationResult;
|
||||
import org.wso2.carbon.device.mgt.common.group.mgt.DeviceGroup;
|
||||
import org.wso2.carbon.device.mgt.common.group.mgt.DeviceGroupConstants;
|
||||
import org.wso2.carbon.device.mgt.common.group.mgt.GroupAlreadyExistException;
|
||||
import org.wso2.carbon.device.mgt.common.group.mgt.GroupManagementException;
|
||||
import org.wso2.carbon.device.mgt.jaxrs.beans.DeviceGroupList;
|
||||
import org.wso2.carbon.device.mgt.jaxrs.service.api.admin.GroupManagementAdminService;
|
||||
@ -36,6 +38,10 @@ public class GroupManagementAdminServiceImpl implements GroupManagementAdminServ
|
||||
|
||||
private static final Log log = LogFactory.getLog(GroupManagementAdminServiceImpl.class);
|
||||
|
||||
private static final String DEFAULT_ADMIN_ROLE = "admin";
|
||||
private static final String[] DEFAULT_ADMIN_PERMISSIONS = {"/permission/device-mgt/admin/groups",
|
||||
"/permission/device-mgt/user/groups"};
|
||||
|
||||
@Override
|
||||
public Response getGroups(String name, String owner, int offset, int limit, String status) {
|
||||
try {
|
||||
@ -84,4 +90,24 @@ public class GroupManagementAdminServiceImpl implements GroupManagementAdminServ
|
||||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response createGroup(DeviceGroup group) {
|
||||
if (group == null) {
|
||||
return Response.status(Response.Status.BAD_REQUEST).build();
|
||||
}
|
||||
group.setStatus(DeviceGroupConstants.GroupStatus.ACTIVE);
|
||||
try {
|
||||
DeviceMgtAPIUtils.getGroupManagementProviderService().createGroup(group, DEFAULT_ADMIN_ROLE, DEFAULT_ADMIN_PERMISSIONS);
|
||||
return Response.status(Response.Status.CREATED).build();
|
||||
} catch (GroupManagementException e) {
|
||||
String msg = "Error occurred while adding new group.";
|
||||
log.error(msg, e);
|
||||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
|
||||
} catch (GroupAlreadyExistException e) {
|
||||
String msg = "Group already exists with name " + group.getName() + ".";
|
||||
log.warn(msg);
|
||||
return Response.status(Response.Status.CONFLICT).entity(msg).build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,45 +56,29 @@ public class DeviceLocation implements Serializable {
|
||||
@ApiModelProperty(name = "updatedTime", value = "Update time of the device.", required = true)
|
||||
private Date updatedTime;
|
||||
@ApiModelProperty(name = "altitude", value = "Device altitude.", required = true)
|
||||
private Double altitude;
|
||||
private double altitude;
|
||||
@ApiModelProperty(name = "speed", value = "Device speed.", required = true)
|
||||
private Float speed;
|
||||
private float speed;
|
||||
@ApiModelProperty(name = "bearing", value = "Device bearing.", required = true)
|
||||
private Float bearing;
|
||||
private float bearing;
|
||||
@ApiModelProperty(name = "distance", value = "Device distance.", required = true)
|
||||
private Double distance;
|
||||
private double distance;
|
||||
|
||||
public Double getDistance() {
|
||||
return distance;
|
||||
}
|
||||
public double getAltitude() { return altitude; }
|
||||
|
||||
public void setDistance(Double distance) {
|
||||
this.distance = distance;
|
||||
}
|
||||
public void setAltitude(double altitude) { this.altitude = altitude; }
|
||||
|
||||
public Double getAltitude() {
|
||||
return altitude;
|
||||
}
|
||||
public float getSpeed() { return speed; }
|
||||
|
||||
public Float getSpeed() {
|
||||
return speed;
|
||||
}
|
||||
public void setSpeed(float speed) { this.speed = speed; }
|
||||
|
||||
public void setSpeed(Float speed) {
|
||||
this.speed = speed;
|
||||
}
|
||||
public float getBearing() { return bearing; }
|
||||
|
||||
public Float getBearing() {
|
||||
return bearing;
|
||||
}
|
||||
public void setBearing(float bearing) { this.bearing = bearing; }
|
||||
|
||||
public void setBearing(Float bearing) {
|
||||
this.bearing = bearing;
|
||||
}
|
||||
public double getDistance() { return distance; }
|
||||
|
||||
public void setAltitude(Double altitude) {
|
||||
this.altitude = altitude;
|
||||
}
|
||||
public void setDistance(double distance) { this.distance = distance; }
|
||||
|
||||
public int getDeviceId() {
|
||||
return deviceId;
|
||||
|
||||
@ -752,11 +752,11 @@ public interface DeviceManagementProviderService {
|
||||
List<GeoCluster> findGeoClusters(String deviceType, GeoCoordinate southWest, GeoCoordinate northEast,
|
||||
int geohashLength) throws DeviceManagementException;
|
||||
|
||||
int getDeviceCountOfTypeByStatus(int tenantId, String deviceType, String deviceStatus) throws DeviceManagementException;
|
||||
int getDeviceCountOfTypeByStatus(String deviceType, String deviceStatus) throws DeviceManagementException;
|
||||
|
||||
List<String> getDeviceIdentifiersByStatus(int tenantId, String deviceType, String deviceStatus) throws DeviceManagementException;
|
||||
List<String> getDeviceIdentifiersByStatus(String deviceType, String deviceStatus) throws DeviceManagementException;
|
||||
|
||||
boolean bulkUpdateDeviceStatus(int tenantId, String deviceType, List<String> deviceList, String status) throws DeviceManagementException;
|
||||
boolean bulkUpdateDeviceStatus(String deviceType, List<String> deviceList, String status) throws DeviceManagementException;
|
||||
|
||||
boolean updateEnrollment(String owner, List<String> deviceIdentifiers)
|
||||
throws DeviceManagementException, UserNotFoundException, InvalidDeviceException;
|
||||
|
||||
@ -3125,10 +3125,10 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDeviceCountOfTypeByStatus(int tenantId, String deviceType, String deviceStatus) throws DeviceManagementException {
|
||||
public int getDeviceCountOfTypeByStatus(String deviceType, String deviceStatus) throws DeviceManagementException {
|
||||
try {
|
||||
DeviceManagementDAOFactory.openConnection();
|
||||
return deviceDAO.getDeviceCount(deviceType, deviceStatus, tenantId);
|
||||
return deviceDAO.getDeviceCount(deviceType, deviceStatus, getTenantId());
|
||||
} catch (DeviceManagementDAOException e) {
|
||||
String msg = "Error occurred in while retrieving device count by status for deviceType :" +deviceType + " status : " + deviceStatus;
|
||||
log.error(msg, e);
|
||||
@ -3143,11 +3143,11 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getDeviceIdentifiersByStatus(int tenantId, String deviceType, String deviceStatus) throws DeviceManagementException {
|
||||
public List<String> getDeviceIdentifiersByStatus(String deviceType, String deviceStatus) throws DeviceManagementException {
|
||||
List<String> deviceIds;
|
||||
try {
|
||||
DeviceManagementDAOFactory.openConnection();
|
||||
deviceIds = deviceDAO.getDeviceIdentifiers(deviceType, deviceStatus, tenantId);
|
||||
deviceIds = deviceDAO.getDeviceIdentifiers(deviceType, deviceStatus, getTenantId());
|
||||
} catch (DeviceManagementDAOException e) {
|
||||
String msg = "Error occurred in while retrieving devices by status for deviceType :" +deviceType + " status : " + deviceStatus;
|
||||
log.error(msg, e);
|
||||
@ -3163,20 +3163,19 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean bulkUpdateDeviceStatus(int tenantId, String deviceType,
|
||||
List<String> deviceList, String status)
|
||||
public boolean bulkUpdateDeviceStatus(String deviceType, List<String> deviceList, String status)
|
||||
throws DeviceManagementException {
|
||||
boolean success;
|
||||
try {
|
||||
DeviceManagementDAOFactory.openConnection();
|
||||
success = deviceDAO.setEnrolmentStatusInBulk(deviceType, status, tenantId, deviceList);
|
||||
DeviceManagementDAOFactory.beginTransaction();
|
||||
success = deviceDAO.setEnrolmentStatusInBulk(deviceType, status, getTenantId(), deviceList);
|
||||
DeviceManagementDAOFactory.commitTransaction();
|
||||
} catch (DeviceManagementDAOException e) {
|
||||
String msg = "Error occurred in while updating status of devices :" + deviceType + " status : " + deviceList
|
||||
.toString();
|
||||
DeviceManagementDAOFactory.rollbackTransaction();
|
||||
String msg = "Error occurred in while updating status of devices :" + deviceType + " status : " + status;
|
||||
log.error(msg, e);
|
||||
throw new DeviceManagementException(msg, e);
|
||||
} catch (SQLException e) {
|
||||
} catch (TransactionManagementException e) {
|
||||
String msg = "Error occurred while opening a connection to the data source";
|
||||
log.error(msg, e);
|
||||
throw new DeviceManagementException(msg, e);
|
||||
|
||||
@ -118,7 +118,7 @@
|
||||
{{/if}}
|
||||
{{#if iosPluginFlag}}
|
||||
<li>
|
||||
<a href="{{@app.context}}/dep/devices"><i class="fw fw-ios"></i>
|
||||
<a href="{{@app.context}}/dep/devices"><i class="fw fw-apple"></i>
|
||||
DEP Configurations
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@ -155,8 +155,8 @@ public class PolicyManagerUtil {
|
||||
PolicyAdministratorPoint pap = new PolicyAdministratorPointImpl();
|
||||
try {
|
||||
Policy correctivePolicy = pap.getPolicy(correctiveAction.getPolicyId());
|
||||
if (correctivePolicy == null || PolicyManagementConstants.CORRECTIVE_POLICY_TYPE
|
||||
.equalsIgnoreCase(correctivePolicy.getPolicyType())) {
|
||||
if (correctivePolicy == null || !PolicyManagementConstants.CORRECTIVE_POLICY_TYPE
|
||||
.equalsIgnoreCase(correctivePolicy.getPolicyType() )) {
|
||||
String msg = "No corrective policy was found for the policy " + policy.getPolicyName() +
|
||||
" and policy ID " + policy.getId();
|
||||
log.error(msg);
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
CREATE TABLE IF NOT EXISTS AP_APP(
|
||||
ID INTEGER NOT NULL AUTO_INCREMENT,
|
||||
NAME VARCHAR(45) NOT NULL,
|
||||
DESCRIPTION CLOB NULL,
|
||||
DESCRIPTION VARCHAR(200) NOT NULL,
|
||||
TYPE VARCHAR(200) NOT NULL,
|
||||
TENANT_ID INTEGER NOT NULL,
|
||||
STATUS VARCHAR(45) NOT NULL DEFAULT 'ACTIVE',
|
||||
@ -20,7 +20,7 @@ CREATE TABLE IF NOT EXISTS AP_APP(
|
||||
-- -----------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS AP_APP_RELEASE(
|
||||
ID INTEGER NOT NULL AUTO_INCREMENT,
|
||||
DESCRIPTION CLOB NOT NULL,
|
||||
DESCRIPTION VARCHAR(200) NOT NULL,
|
||||
VERSION VARCHAR(70) NOT NULL,
|
||||
TENANT_ID INTEGER NOT NULL,
|
||||
UUID VARCHAR(200) NOT NULL,
|
||||
@ -35,7 +35,7 @@ CREATE TABLE IF NOT EXISTS AP_APP_RELEASE(
|
||||
SC_3_LOCATION VARCHAR(100) NULL DEFAULT NULL,
|
||||
APP_HASH_VALUE VARCHAR(1000) NOT NULL,
|
||||
SHARED_WITH_ALL_TENANTS BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
APP_META_INFO CLOB NULL DEFAULT NULL,
|
||||
APP_META_INFO VARCHAR(150) NULL DEFAULT NULL,
|
||||
SUPPORTED_OS_VERSIONS VARCHAR(45) NOT NULL,
|
||||
RATING DOUBLE NULL DEFAULT NULL,
|
||||
CURRENT_STATE VARCHAR(45) NOT NULL,
|
||||
@ -57,8 +57,8 @@ CREATE TABLE IF NOT EXISTS AP_APP_REVIEW(
|
||||
COMMENT TEXT NOT NULL,
|
||||
ROOT_PARENT_ID INTEGER NOT NULL,
|
||||
IMMEDIATE_PARENT_ID INTEGER NOT NULL,
|
||||
CREATED_AT TIMESTAMP NOT NULL,
|
||||
MODIFIED_AT TIMESTAMP NOT NULL,
|
||||
CREATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
MODIFIED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
RATING INTEGER NULL,
|
||||
USERNAME VARCHAR(45) NOT NULL,
|
||||
ACTIVE_REVIEW BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
@ -267,14 +267,11 @@ CREATE TABLE IF NOT EXISTS AP_SCHEDULED_SUBSCRIPTION(
|
||||
ID INTEGER NOT NULL AUTO_INCREMENT,
|
||||
TASK_NAME VARCHAR(100) NOT NULL,
|
||||
APPLICATION_UUID VARCHAR(36) NOT NULL,
|
||||
SUBSCRIBER_LIST LONGVARCHAR NOT NULL,
|
||||
SUBSCRIBER_LIST TEXT NOT NULL,
|
||||
STATUS VARCHAR(15) NOT NULL,
|
||||
SCHEDULED_AT TIMESTAMP NOT NULL,
|
||||
SCHEDULED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
SCHEDULED_BY VARCHAR(100) NOT NULL,
|
||||
SCHEDULED_TIMESTAMP TIMESTAMP NOT NULL,
|
||||
SCHEDULED_TIMESTAMP TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
DELETED BOOLEAN,
|
||||
PRIMARY KEY (ID),
|
||||
CONSTRAINT fk_AP_SCHEDULED_SUBSCRIPTION_AP_APP_RELEASE
|
||||
FOREIGN KEY (APPLICATION_UUID)
|
||||
REFERENCES AP_APP_RELEASE (UUID) ON DELETE NO ACTION ON UPDATE NO ACTION
|
||||
);
|
||||
PRIMARY KEY (ID)
|
||||
);
|
||||
Loading…
Reference in New Issue
Block a user