From a78d3e17d4b5bf40bf10246818a899a3983c1a91 Mon Sep 17 00:00:00 2001 From: Shamalka Navod Date: Fri, 25 Oct 2019 05:53:07 +0000 Subject: [PATCH] Group create/edit/delete/share functions --- .../DeviceTypes/DeviceTypesTable.js | 3 +- .../src/components/Devices/DevicesTable.js | 3 +- .../components/Devices/ReportDevicesTable.js | 3 +- .../src/components/Groups/AddGroup.js | 176 ++++++++ .../src/components/Groups/GroupActions.js | 377 ++++++++++++++++++ .../src/components/Groups/GroupsTable.js | 97 +++-- .../src/components/Roles/RolesTable.js | 4 +- .../src/components/Users/UsersDevices.js | 3 +- .../src/components/Users/UsersTable.js | 4 +- .../src/pages/Dashboard/Groups/Groups.js | 1 + .../src/pages/Dashboard/Policies/Policies.js | 2 +- .../service/api/GroupManagementService.java | 2 + 12 files changed, 621 insertions(+), 54 deletions(-) create mode 100644 components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Groups/AddGroup.js create mode 100644 components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Groups/GroupActions.js diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/DeviceTypes/DeviceTypesTable.js b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/DeviceTypes/DeviceTypesTable.js index 42af8271b76..19a7b3f1b65 100644 --- a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/DeviceTypes/DeviceTypesTable.js +++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/DeviceTypes/DeviceTypesTable.js @@ -18,9 +18,8 @@ import React from "react"; import axios from "axios"; -import {message, notification, Typography, Icon, Card, Col, Row} 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"; diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Devices/DevicesTable.js b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Devices/DevicesTable.js index 38e5444aebb..d129d6a6013 100644 --- a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Devices/DevicesTable.js +++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Devices/DevicesTable.js @@ -18,9 +18,8 @@ import React from "react"; import axios from "axios"; -import {Tag, message, notification, Table, Typography, Tooltip, Icon, 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"; diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Devices/ReportDevicesTable.js b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Devices/ReportDevicesTable.js index 604d540e001..61a8635564b 100644 --- a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Devices/ReportDevicesTable.js +++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Devices/ReportDevicesTable.js @@ -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"; diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Groups/AddGroup.js b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Groups/AddGroup.js new file mode 100644 index 00000000000..00db115bece --- /dev/null +++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Groups/AddGroup.js @@ -0,0 +1,176 @@ +/* + * 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( +
+
+ +
+
+ + Cancel + , + , + ]} + > +
+

Create new device group on IoT Server.

+
+ + {getFieldDecorator('name', { + rules: [ + { + required: true, + message: 'Please input group name', + }, + ], + })()} + + + {getFieldDecorator('description', { + rules: [ + { + required: true, + message: 'Please input group description', + }, + ], + })()} + +
+
+
+
+
+ ) + } +} + +export default withConfigContext(Form.create({name: 'add-group'})(AddGroup)); \ No newline at end of file diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Groups/GroupActions.js b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Groups/GroupActions.js new file mode 100644 index 00000000000..3a3e6e83b5d --- /dev/null +++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Groups/GroupActions.js @@ -0,0 +1,377 @@ +/* + * 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) => + + {data} + ); + return( +
+
+ + + + + + + + + + + + + +
+
+ + Cancel + , + , + ]} + > +
+

Enter new name and description for the group

+
+ + {getFieldDecorator( + 'name', + { + initialValue: this.props.data.name, + rules: [ + { + required: true, + message: 'Please input group name', + }, + ], + })()} + + + {getFieldDecorator( + 'description', + { + initialValue: this.props.data.description, + rules: [ + { + required: true, + message: 'Please input group description', + }, + ], + })()} + +
+
+
+
+
+ + Cancel + , + , + ]} + > + , + + +
+
+ ) + } +} + +export default withConfigContext(Form.create({name: 'group-actions'})(GroupActions)); \ No newline at end of file diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Groups/GroupsTable.js b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Groups/GroupsTable.js index 1fdaedec499..6bc8d6527a8 100644 --- a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Groups/GroupsTable.js +++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Groups/GroupsTable.js @@ -18,40 +18,19 @@ import React from "react"; import axios from "axios"; -import { message, notification, Table, Typography} 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) => ( + + + + ), + }, + ]; + 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,23 +161,29 @@ class GroupsTable extends React.Component { render() { const {data, pagination, loading, selectedRows} = this.state; + return (
- (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} - /> +
+ +
+
+
(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} + /> + ); } diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Roles/RolesTable.js b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Roles/RolesTable.js index 1080cddddbf..3d85bbe344c 100644 --- a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Roles/RolesTable.js +++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Roles/RolesTable.js @@ -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,7 +123,6 @@ class RolesTable extends React.Component { }; render() { - const {data, pagination, loading, selectedRows} = this.state; const { Meta } = Card; const itemCard = data.map((data) => diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Users/UsersDevices.js b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Users/UsersDevices.js index 75529becc12..eca727ac9a9 100644 --- a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Users/UsersDevices.js +++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Users/UsersDevices.js @@ -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"; diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Users/UsersTable.js b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Users/UsersTable.js index a1651111ffa..6684329e674 100644 --- a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Users/UsersTable.js +++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Users/UsersTable.js @@ -18,13 +18,11 @@ import React from "react"; import axios from "axios"; -import {message, notification, Table, Typography, Panel, Collapse, Button, List, Modal, Icon, Tabs} 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; diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/pages/Dashboard/Groups/Groups.js b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/pages/Dashboard/Groups/Groups.js index b96f869872b..b259c3256ac 100644 --- a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/pages/Dashboard/Groups/Groups.js +++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/pages/Dashboard/Groups/Groups.js @@ -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; diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/pages/Dashboard/Policies/Policies.js b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/pages/Dashboard/Policies/Policies.js index 7c32b7a0a23..09955efb4d4 100644 --- a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/pages/Dashboard/Policies/Policies.js +++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/pages/Dashboard/Policies/Policies.js @@ -55,7 +55,7 @@ class Policies extends React.Component {
- +

sghdfugjhskf

); diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/GroupManagementService.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/GroupManagementService.java index 0e5673dd299..9ea2e4b2bba 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/GroupManagementService.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/GroupManagementService.java @@ -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.",