diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/package.json b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/package.json
index ac80be19a0..784a4bc702 100644
--- a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/package.json
+++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/package.json
@@ -15,6 +15,7 @@
"axios": "^0.18.0",
"d3": "^5.9.2",
"dagre": "^0.8.4",
+ "javascript-time-ago": "^2.0.1",
"keymirror": "^0.1.1",
"lodash.debounce": "^4.0.8",
"rc-viewer": "0.0.9",
diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/AppInstallModal.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/AppInstallModal.js
index 0cced3824f..990eea393e 100644
--- a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/AppInstallModal.js
+++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/AppInstallModal.js
@@ -3,10 +3,14 @@ import {Button, Modal, Tabs} from "antd";
import UserInstall from "./UserInstall";
import GroupInstall from "./GroupInstall";
import RoleInstall from "./RoleInstall";
+import DeviceInstall from "./DeviceInstall";
const { TabPane } = Tabs;
class AppInstallModal extends React.Component{
+ state={
+ data:[]
+ };
render() {
return (
@@ -17,12 +21,12 @@ class AppInstallModal extends React.Component{
onCancel={this.props.onClose}
footer={null}
>
-
+ {console.log("changed");}}>
- Device install
+
diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/DeviceInstall.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/DeviceInstall.js
new file mode 100644
index 0000000000..0a19afcf04
--- /dev/null
+++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/DeviceInstall.js
@@ -0,0 +1,226 @@
+import React from "react";
+import axios from "axios";
+import config from "../../../../../public/conf/config.json";
+import {Button, message, Table} from "antd";
+import TimeAgo from 'javascript-time-ago'
+
+// Load locale-specific relative date/time formatting rules.
+import en from 'javascript-time-ago/locale/en'
+
+const columns = [
+ {
+ title: 'Device',
+ dataIndex: 'name',
+ fixed: 'left',
+ width: 100,
+ },
+ {
+ title: 'Modal',
+ dataIndex: 'deviceInfo',
+ key:'modal',
+ render: deviceInfo => `${deviceInfo.vendor} ${deviceInfo.deviceModel}`
+ // todo add filtering options
+ },
+ {
+ title: 'Owner',
+ dataIndex: 'enrolmentInfo',
+ key: 'owner',
+ render: enrolmentInfo => enrolmentInfo.owner
+ // todo add filtering options
+ },
+ {
+ title: 'Last Updated',
+ dataIndex: 'enrolmentInfo',
+ key: 'dateOfLastUpdate',
+ render: (data) => {
+ return (getTimeAgo(data.dateOfLastUpdate));
+ }
+ // todo add filtering options
+ },
+ {
+ title: 'Status',
+ dataIndex: 'enrolmentInfo',
+ key: 'status',
+ render: enrolmentInfo => enrolmentInfo.status
+ // todo add filtering options
+ },
+ {
+ title: 'Ownership',
+ dataIndex: 'enrolmentInfo',
+ key: 'ownership',
+ render: enrolmentInfo => enrolmentInfo.ownership
+ // todo add filtering options
+ },
+ {
+ title: 'OS Version',
+ dataIndex: 'deviceInfo',
+ key:'osVersion',
+ render: deviceInfo => deviceInfo.osVersion
+ // todo add filtering options
+ },
+ {
+ title: 'IMEI',
+ dataIndex: 'properties',
+ key:'imei',
+ render: properties => {
+ let imei = "not-found";
+ for (let i = 0; i < properties.length; i++) {
+ if(properties[i].name==="IMEI"){
+ imei = properties[i].value;
+ }
+ }
+ return imei;
+ }
+ // todo add filtering options
+ },
+];
+
+const getTimeAgo = (time) => {
+ const timeAgo = new TimeAgo('en-US');
+ return timeAgo.format(time);
+};
+
+
+class DeviceInstall extends React.Component {
+ constructor(props) {
+ super(props);
+ TimeAgo.addLocale(en);
+ this.state = {
+ data: [],
+ pagination: {},
+ loading: false,
+ selectedRows:[]
+ };
+ }
+
+ rowSelection = {
+ onChange: (selectedRowKeys, selectedRows) => {
+ console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
+ this.setState({
+ selectedRows: selectedRows
+ })
+ },
+ getCheckboxProps: record => ({
+ disabled: record.name === 'Disabled User', // Column configuration not to be checked
+ name: record.name,
+ }),
+ };
+
+
+
+
+ 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,
+ status: "INACTIVE",
+ requireDeviceInfo: true
+ };
+
+ // note: encode with '%26' not '&'
+ const encodedExtraParams = Object.keys(extraParams).map(key => key + '=' + extraParams[key]).join('%26');
+
+ const parameters = {
+ method: "get",
+ 'content-type': "application/json",
+ payload: "{}",
+ 'api-endpoint': "/device-mgt/v1.0/devices?" + encodedExtraParams
+ };
+
+ //url-encode parameters
+ const request = Object.keys(parameters).map(key => key + '=' + parameters[key]).join('&');
+
+ //send request to the invoker
+ axios.post(config.serverConfig.protocol + "://" + config.serverConfig.hostname + ':' + config.serverConfig.httpsPort + config.serverConfig.invokerUri, request
+ ).then(res => {
+ if (res.status === 200) {
+ const pagination = {...this.state.pagination};
+ console.log(res.data.data.devices);
+ this.setState({
+ loading: false,
+ data: res.data.data.devices,
+ pagination,
+ });
+
+ }
+
+ }).catch((error) => {
+ if (error.hasOwnProperty("status") && error.response.status === 401) {
+ //todo display a popop with error
+ message.error('You are not logged in');
+ window.location.href = config.serverConfig.protocol + "://" + config.serverConfig.hostname + ':' + config.serverConfig.httpsPort + '/store/login';
+ } else {
+ message.error('Something went wrong... :(');
+ }
+
+ 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,
+ });
+ };
+
+ install = () => {
+ const {selectedRows} = this.state;
+ const payload = [];
+ selectedRows.map(device => {
+ payload.push({
+ deviceIdentifier: device.deviceIdentifier,
+ type: device.type
+ });
+ });
+ this.props.onInstall("device", payload);
+ };
+
+
+ render() {
+ const {data,pagination,loading,selectedRows} = this.state;
+ return (
+
+
record.deviceIdentifier}
+ 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}
+ rowSelection={this.rowSelection}
+ scroll={{x: 1000}}
+ />
+
+
+
+
+ );
+ }
+}
+
+export default DeviceInstall;
\ No newline at end of file