Merge branch 'devicemgt-certificate-page' into 'master'

Create cetificates view in devicemgt react app

Closes product-iots#295

See merge request entgra/carbon-device-mgt!408
feature/appm-store/pbac
Dharmakeerthi Lasantha 5 years ago
commit 4362d21d75

@ -22,7 +22,7 @@
"react-image-viewer-zoom": "^1.0.36", "react-image-viewer-zoom": "^1.0.36",
"react-infinite-scroller": "^1.2.4", "react-infinite-scroller": "^1.2.4",
"react-leaflet": "^2.4.0", "react-leaflet": "^2.4.0",
"react-moment": "^0.9.2", "react-moment": "^0.9.7",
"react-router": "^5.0.1", "react-router": "^5.0.1",
"react-router-config": "^5.0.1", "react-router-config": "^5.0.1",
"react-router-dom": "^5.0.1", "react-router-dom": "^5.0.1",

@ -0,0 +1,233 @@
/*
* 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 {Icon, message, Modal, notification, Popconfirm, 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";
import Moment from "react-moment";
const {Paragraph, Text} = Typography;
let config = null;
class CertificateTable extends React.Component {
constructor(props) {
super(props);
config = this.props.context;
TimeAgo.addLocale(en);
this.state = {
data: [],
pagination: {},
loading: false,
};
}
componentDidMount() {
this.fetch();
}
//fetch data from api
fetch = (params = {}) => {
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,
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 +
'/certificate-mgt/v1.0/admin/certificates',
).then(res => {
if (res.status === 200) {
const pagination = {...this.state.pagination};
this.setState({
loading: false,
data: res.data.data.certificates,
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,
});
};
deleteCertificate = (serialNumber) =>{
axios.delete(
window.location.origin + config.serverConfig.invoker.uri +
'/certificate-mgt/v1.0/admin/certificates/'+ serialNumber,
{headers: {'Content-Type': 'application/json'}}
).then(res => {
if (res.status === 200) {
notification["success"]({
message: "Done",
duration: 4,
description:
"Successfully deleted the certificate.",
});
}
}).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 the certificate.",
});
}
});
};
columns = [
{
title: 'Serial Number',
dataIndex: 'serialNumber'
},
{
title: 'Username',
dataIndex: 'username'
},
{
title: 'Certificate Version',
dataIndex: 'certificateVersion'
},
{
title: 'Certificate Serial',
dataIndex: 'certificateserial'
},
{
title: 'Not Before',
dataIndex: 'notBefore',
render: notBefore => (
<Moment format="YYYY/MM/DD HH:mm" date={notBefore} />
)
},
{
title: 'Not After',
dataIndex: 'notAfter',
render: notAfter => (
<Moment format="YYYY/MM/DD HH:mm" date={notAfter} />
)
},
{
title: 'Subject',
dataIndex: 'subject',
render: subject => (
<Paragraph style={{marginBottom: 0}} ellipsis={{rows:1, expandable: true}}>{subject}</Paragraph>
)
},
{
title: 'Issuer',
dataIndex: 'issuer',
render: issuer => (
<Paragraph style={{marginBottom: 0}} ellipsis={{rows:1, expandable: true}}>{issuer}</Paragraph>
)
},
{
title: 'Actions',
key: 'actions',
dataIndex: 'serialNumber',
render: (serialNumber) => (
<Tooltip placement="bottom" title={"Remove User"}>
<Popconfirm
placement="top"
title={"Are you sure?"}
onConfirm={() => {this.deleteCertificate(serialNumber)}}
okText="Ok"
cancelText="Cancel">
<a><Text type="danger"><Icon type="delete"/></Text></a>
</Popconfirm>
</Tooltip>
)
}
];
render() {
const {data, pagination, loading} = this.state;
return (
<div>
<div>
<Table
columns={this.columns}
rowKey={record => record.serialNumber}
dataSource={data}
pagination={{
...pagination,
size: "small",
// position: "top",
showTotal: (total, range) => `showing ${range[0]}-${range[1]} of ${total} devices`
// showQuickJumper: true
}}
loading={loading}
onChange={this.handleTableChange}
/>
</div>
</div>
);
}
}
export default withConfigContext(CertificateTable);

@ -1077,7 +1077,7 @@ const jsonResponse = {
"Name": "COSU Profile Configurations", "Name": "COSU Profile Configurations",
"Panel": [{ "Panel": [{
"title": "COSU Profile Configurations", "title": "COSU Profile Configurations",
"description": "This policy can be used to configure the profile of COSU Devices.", "description": "This policy can be used to configure the profile of COSU Certificates.",
"PanelItem": [ "PanelItem": [
{ {
"Label": "Restrict Device Operation Time", "Label": "Restrict Device Operation Time",
@ -2081,4 +2081,4 @@ const jsonResponse = {
} }
}; };
export default jsonResponse; export default jsonResponse;

@ -33,6 +33,7 @@ import Roles from "./pages/Dashboard/Roles/Roles";
import DeviceTypes from "./pages/Dashboard/DeviceTypes/DeviceTypes"; import DeviceTypes from "./pages/Dashboard/DeviceTypes/DeviceTypes";
import DeviceEnroll from "./pages/Dashboard/Devices/DeviceEnroll"; import DeviceEnroll from "./pages/Dashboard/Devices/DeviceEnroll";
import AddNewPolicy from "./pages/Dashboard/Policies/AddNewPolicy"; import AddNewPolicy from "./pages/Dashboard/Policies/AddNewPolicy";
import Certificates from "./pages/Dashboard/Configurations/Certificates/Certificates";
const routes = [ const routes = [
{ {
@ -94,6 +95,11 @@ const routes = [
path: '/entgra/devicetypes', path: '/entgra/devicetypes',
component: DeviceTypes, component: DeviceTypes,
exact: true exact: true
},
{
path: '/entgra/certificates',
component: Certificates,
exact: true
} }
] ]
} }

@ -0,0 +1,67 @@
/*
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
*
* Entgra (pvt) Ltd. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import React from "react";
import {
PageHeader,
Typography,
Breadcrumb,
Icon,
} from "antd";
import {Link} from "react-router-dom";
import DeviceTable from "../../../../components/Devices/DevicesTable";
import CertificateTable from "../../../../components/Configurations/Certificates/CertificateTable";
const {Paragraph} = Typography;
class Certificates extends React.Component {
routes;
constructor(props) {
super(props);
this.routes = props.routes;
}
render() {
return (
<div>
<PageHeader style={{paddingTop: 0}}>
<Breadcrumb style={{paddingBottom: 16}}>
<Breadcrumb.Item>
<Link to="/entgra/devices"><Icon type="home"/> Home</Link>
</Breadcrumb.Item>
<Breadcrumb.Item>Configurations</Breadcrumb.Item>
<Breadcrumb.Item>Certificates</Breadcrumb.Item>
</Breadcrumb>
<div className="wrap">
<h3>Certificates</h3>
<Paragraph>Certificate configurations</Paragraph>
</div>
<div style={{backgroundColor: "#ffffff", borderRadius: 5}}>
<CertificateTable/>
</div>
</PageHeader>
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}>
</div>
</div>
);
}
}
export default Certificates;

@ -154,6 +154,20 @@ class Dashboard extends React.Component {
<span>Device Types</span> <span>Device Types</span>
</Link> </Link>
</Menu.Item> </Menu.Item>
<SubMenu
key="configurations"
title={
<span>
<Icon type="setting"/>
<span>Configurations</span>
</span>}
>
<Menu.Item key="certificates">
<Link to="/entgra/certificates">
<span>Certificates</span>
</Link>
</Menu.Item>
</SubMenu>
<Menu.Item key="trigger"> <Menu.Item key="trigger">
</Menu.Item> </Menu.Item>
<SubMenu className="profile" <SubMenu className="profile"

Loading…
Cancel
Save