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 ee5bed4129..5e1a5494ca 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 @@ -77,7 +77,6 @@ class DeviceTypesTable extends React.Component { pagination, }); } - console.log(JSON.parse(res.data.data)) }).catch((error) => { if (error.hasOwnProperty("response") && error.response.status === 401) { 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 5d24e85986..80f577bcb8 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 @@ -151,7 +151,7 @@ class ReportDeviceTable extends React.Component { if(prevProps.paramsObject !== this.props.paramsObject){ this.fetch(); } - } + } //fetch data from api fetch = (params = {}) => { diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Policies/PoliciesTable.js b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Policies/PoliciesTable.js new file mode 100644 index 0000000000..29394b9cde --- /dev/null +++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Policies/PoliciesTable.js @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved. + * + * Entgra (pvt) Ltd. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React from "react"; +import axios from "axios"; +import {Tag, message, notification, Table, Typography, Tooltip, Icon, Divider} from "antd"; +import TimeAgo from 'javascript-time-ago' + +// Load locale-specific relative date/time formatting rules. +import en from 'javascript-time-ago/locale/en' +import {withConfigContext} from "../../context/ConfigContext"; + +const {Text} = Typography; + +let config = null; +let apiUrl; + +const columns = [ + { + title: 'Policy Name', + dataIndex: 'policyName', + width: 100, + }, + { + title: 'Description', + dataIndex: 'description', + key: 'description', + // render: enrolmentInfo => enrolmentInfo.owner + // todo add filtering options + }, + { + title: 'Compilance', + dataIndex: 'compliance', + key: 'compliance', + // render: enrolmentInfo => enrolmentInfo.ownership + // todo add filtering options + }, + { + title: 'Policy Type', + dataIndex: 'policyType', + key: 'policyType', + // render: enrolmentInfo => enrolmentInfo.ownership + // todo add filtering options + } +]; + +const getTimeAgo = (time) => { + const timeAgo = new TimeAgo('en-US'); + return timeAgo.format(time); +}; + +class PoliciesTable extends React.Component { + constructor(props) { + super(props); + config = this.props.context; + TimeAgo.addLocale(en); + this.state = { + data: [], + pagination: {}, + loading: false, + selectedRows: [] + }; + } + + rowSelection = { + onChange: (selectedRowKeys, selectedRows) => { + this.setState({ + selectedRows: selectedRows + }) + } + }; + + componentDidMount() { + this.fetchGroups(); + } + + //fetch data from api + fetchGroups = (params = {}) => { + const config = this.props.context; + this.setState({loading: true}); + + // get current page + const currentPage = (params.hasOwnProperty("page")) ? params.page : 1; + + const extraParams = { + offset: 10 * (currentPage - 1), //calculate the offset + limit: 10, + }; + + const encodedExtraParams = Object.keys(extraParams) + .map(key => key + '=' + extraParams[key]).join('&'); + + apiUrl = window.location.origin + config.serverConfig.invoker.uri + + config.serverConfig.invoker.deviceMgt + + "/policies?" + encodedExtraParams; + + //send request to the invokerss + axios.get(apiUrl).then(res => { + if (res.status === 200) { + const pagination = {...this.state.pagination}; + this.setState({ + loading: false, + data: res.data.data.policies, + pagination, + }); + } + + }).catch((error) => { + if (error.hasOwnProperty("response") && error.response.status === 401) { + //todo display a popop with error + message.error('You are not logged in'); + window.location.href = window.location.origin + '/entgra/login'; + } else { + notification["error"]({ + message: "There was a problem", + duration: 0, + description:"Error occurred while trying to load policies.", + }); + } + + this.setState({loading: false}); + }); + }; + + handleTableChange = (pagination, filters, sorter) => { + const pager = {...this.state.pagination}; + pager.current = pagination.current; + this.setState({ + pagination: pager, + }); + this.fetch({ + results: pagination.pageSize, + page: pagination.current, + sortField: sorter.field, + sortOrder: sorter.order, + ...filters, + }); + }; + + render() { + + const {data, pagination, loading, selectedRows} = this.state; + return ( +
+ (record.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}} + /> + + ); + } +} + +export default withConfigContext(PoliciesTable); \ No newline at end of file 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 new file mode 100644 index 0000000000..13ce62e98e --- /dev/null +++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Users/UsersDevices.js @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved. + * + * Entgra (pvt) Ltd. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React from "react"; +import axios from "axios"; +import {Tag, message, notification, Table, Typography, Tooltip, Icon, Divider} from "antd"; +import TimeAgo from 'javascript-time-ago' + +// Load locale-specific relative date/time formatting rules. +import en from 'javascript-time-ago/locale/en' +import {withConfigContext} from "../../context/ConfigContext"; + +const {Text} = Typography; + +let config = null; +let apiUrl; + +const columns = [ + { + title: 'Device', + dataIndex: 'name', + width: 100, + }, + { + title: 'Type', + dataIndex: 'type', + key: 'type', + render: type => { + const defaultPlatformIcons = config.defaultPlatformIcons; + let icon = defaultPlatformIcons.default.icon; + let color = defaultPlatformIcons.default.color; + let theme = defaultPlatformIcons.default.theme; + + if (defaultPlatformIcons.hasOwnProperty(type)) { + icon = defaultPlatformIcons[type].icon; + color = defaultPlatformIcons[type].color; + theme = defaultPlatformIcons[type].theme; + } + + return ( + + + + ); + } + // todo add filtering options + }, + { + title: 'Owner', + dataIndex: 'enrolmentInfo', + key: 'owner', + render: enrolmentInfo => enrolmentInfo.owner + // todo add filtering options + }, + { + title: 'Ownership', + dataIndex: 'enrolmentInfo', + key: 'ownership', + width: 100, + render: enrolmentInfo => enrolmentInfo.ownership + // todo add filtering options + }, + { + title: 'Status', + dataIndex: 'enrolmentInfo', + width: 100, + key: 'status', + render: (enrolmentInfo) => { + const status = enrolmentInfo.status.toLowerCase(); + let color = "#f9ca24"; + switch (status) { + case "active": + color = "#badc58"; + break; + case "created": + color = "#6ab04c"; + break; + case "removed": + color = "#ff7979"; + break; + case "inactive": + color = "#f9ca24"; + break; + case "blocked": + color = "#636e72"; + break; + } + return {status}; + } + // todo add filtering options + }, + { + title: 'Last Updated', + dataIndex: 'enrolmentInfo', + key: 'dateOfLastUpdate', + render: (data) => { + const {dateOfLastUpdate} = data; + const timeAgoString = getTimeAgo(dateOfLastUpdate); + return {timeAgoString}; + } + // todo add filtering options + } +]; + +const getTimeAgo = (time) => { + const timeAgo = new TimeAgo('en-US'); + return timeAgo.format(time); +}; + +class UsersDevices extends React.Component { + constructor(props) { + super(props); + config = this.props.context; + TimeAgo.addLocale(en); + this.state = { + data: [], + pagination: {}, + loading: false, + selectedRows: [] + }; + } + + rowSelection = { + onChange: (selectedRowKeys, selectedRows) => { + this.setState({ + selectedRows: selectedRows + }) + } + }; + + componentDidMount() { + this.fetch(); + } + + //Rerender component when parameters change + componentDidUpdate(prevProps, prevState, snapshot) { + if(prevProps.user !== this.props.user){ + this.fetch(); + } + } + + //fetch data from api + fetch = (params = {}) => { + const config = this.props.context; + this.setState({loading: true}); + // get current page + const currentPage = (params.hasOwnProperty("page")) ? params.page : 1; + + const extraParams = { + offset: 10 * (currentPage - 1), //calculate the offset + limit: 10, + user: this.props.user, + requireDeviceInfo: true, + }; + + const encodedExtraParams = Object.keys(extraParams) + .map(key => key + '=' + extraParams[key]).join('&'); + + //send request to the invoker + axios.get( + window.location.origin + config.serverConfig.invoker.uri + + config.serverConfig.invoker.deviceMgt + + "/devices?" + encodedExtraParams, + ).then(res => { + if (res.status === 200) { + const pagination = {...this.state.pagination}; + this.setState({ + loading: false, + data: res.data.data.devices, + pagination + }); + } + + }).catch((error) => { + if (error.hasOwnProperty("response") && error.response.status === 401) { + //todo display a popop with error + message.error('You are not logged in'); + window.location.href = window.location.origin + '/entgra/login'; + } else { + notification["error"]({ + message: "There was a problem", + duration: 0, + description: + "Error occurred while trying to load devices.", + }); + } + + this.setState({loading: false}); + }); + }; + + handleTableChange = (pagination, filters, sorter) => { + const pager = {...this.state.pagination}; + pager.current = pagination.current; + this.setState({ + pagination: pager, + }); + this.fetch({ + results: pagination.pageSize, + page: pagination.current, + sortField: sorter.field, + sortOrder: sorter.order, + ...filters, + }); + }; + + render() { + + const {data, pagination, loading, selectedRows} = this.state; + return ( +
+
(record.deviceIdentifier + record.enrolmentInfo.owner + record.enrolmentInfo.ownership)} + dataSource={data} + showHeader={false} + size="small" + pagination={{ + ...pagination, + size: "small", + // position: "top", + showTotal: (total, range) => `showing ${range[0]}-${range[1]} of ${total} devices` + // showQuickJumper: true + }} + loading={loading} + onChange={this.handleTableChange} + rowSelection={this.rowSelection} + scroll={{x: 1000}} + /> + + ); + } +} + +export default withConfigContext(UsersDevices); \ No newline at end of file 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 beb34a94d6..ac7fc9c66a 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,12 +18,14 @@ import React from "react"; import axios from "axios"; -import {Tag, message, notification, Table, Typography, Tooltip, Icon, Divider, Card, Col, Row, Select} from "antd"; +import {message, notification, Table, Typography, Panel, Collapse, Button, List, Modal, Icon} 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; @@ -39,10 +41,21 @@ class UsersTable extends React.Component { data: [], pagination: {}, loading: false, - selectedRows: [] + selectedRows: [], + rolesModalVisible: false, + rolesData: [], + user:'' }; } + rowSelection = { + onChange: (selectedRowKeys, selectedRows) => { + this.setState({ + selectedRows: selectedRows + }) + } + }; + componentDidMount() { this.fetchUsers(); } @@ -65,7 +78,7 @@ class UsersTable extends React.Component { apiUrl = window.location.origin + config.serverConfig.invoker.uri + config.serverConfig.invoker.deviceMgt + - "/users"; + "/users?" + encodedExtraParams; //send request to the invokerss axios.get(apiUrl).then(res => { @@ -95,6 +108,44 @@ class UsersTable extends React.Component { }); }; + //fetch data from api + fetchRoles = (username) => { + const config = this.props.context; + + this.setState({ + rolesModalVisible: true, + user: username + }); + + apiUrl = window.location.origin + config.serverConfig.invoker.uri + + config.serverConfig.invoker.deviceMgt + + "/users/" + username + "/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.", + }); + } + + this.setState({loading: false}); + }); + }; + handleTableChange = (pagination, filters, sorter) => { const pager = {...this.state.pagination}; pager.current = pagination.current; @@ -110,22 +161,102 @@ class UsersTable extends React.Component { }); }; + handleOk = e => { + this.setState({ + rolesModalVisible: false, + }); + }; + + handleCancel = e => { + this.setState({ + rolesModalVisible: false, + }); + }; + render() { const {data, pagination, loading, selectedRows} = this.state; - - const itemCard = data.map((data) => - - - {data.username} - - - ); + const { Panel } = Collapse; + const columns = [ + { + title: 'User Name', + dataIndex: 'username', + width: 150, + key: "username", + }, + { + title: 'First Name', + width: 150, + dataIndex: 'firstname', + key: 'firstname', + }, + { + title: 'Last Name', + width: 150, + dataIndex: 'lastname', + key: 'lastname', + }, + { + title: 'Email', + width: 100, + dataIndex: 'emailAddress', + key: 'emailAddress', + }, + { + title: '', + dataIndex: 'username', + key: 'roles', + render: (username) => + + } + ]; return ( -
- - {itemCard} - +
+
+
(record.username)} + 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}} + /> + +
+ + + + {item}} + /> + + + + + + +
); } 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 e17cac8665..b96f869872 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 @@ -54,6 +54,9 @@ class Groups extends React.Component { +
+ +
); } 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 bedaff0b57..7c32b7a0a2 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 @@ -24,6 +24,7 @@ import { Icon } from "antd"; import {Link} from "react-router-dom"; +import PoliciesTable from "../../../components/Policies/PoliciesTable"; const {Paragraph} = Typography; @@ -50,9 +51,12 @@ class Policies extends React.Component { All policies for device management
- +
+
+ +
); }