diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/ReleaseView.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/ReleaseView.js
index 33d6afaca8c..690a71f01df 100644
--- a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/ReleaseView.js
+++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/ReleaseView.js
@@ -42,7 +42,7 @@ class ReleaseView extends React.Component {
}
}
- appOperation = (type, payload, operation) => {
+ appOperation = (type, payload, operation, timestamp=null) => {
const config = this.props.context;
const release = this.props.app.applicationReleases[0];
const {uuid} = release;
@@ -50,7 +50,11 @@ class ReleaseView extends React.Component {
this.setState({
loading: true,
});
- const url = window.location.origin+ config.serverConfig.invoker.uri + config.serverConfig.invoker.store + "/subscription/" + uuid + "/" + type + "/" + operation;
+ let url = window.location.origin+ config.serverConfig.invoker.uri +
+ config.serverConfig.invoker.store + "/subscription/" + uuid + "/" + type + "/" + operation;
+ if(timestamp!= null){
+ url += `?timestamp=${timestamp}`;
+ }
axios.post(
url,
payload,
@@ -61,7 +65,8 @@ class ReleaseView extends React.Component {
if (res.status === 200) {
this.setState({
loading: false,
- appInstallModalVisible: false
+ appInstallModalVisible: false,
+ appUnInstallModalVisible: false,
});
notification["success"]({
message: 'Done!',
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
index 14fbb0ce670..3e67c54c033 100644
--- 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
@@ -18,13 +18,14 @@
import React from "react";
import axios from "axios";
-import {Button, message, notification, Table, Typography} from "antd";
+import {Button, message, DatePicker, 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 {handleApiError} from "../../../../js/Utils";
+import InstallModalFooter from "./installModalFooter/InstallModalFooter";
const {Text} = Typography;
const columns = [
@@ -109,7 +110,9 @@ class DeviceInstall extends React.Component {
data: [],
pagination: {},
loading: false,
- selectedRows: []
+ selectedRows: [],
+ scheduledTime: null,
+ isScheduledInstallVisible: false
};
}
@@ -147,7 +150,7 @@ class DeviceInstall extends React.Component {
if (deviceType !== 'ANY') {
extraParams.type = deviceType;
}
-
+
// note: encode with '%26' not '&'
const encodedExtraParams = Object.keys(extraParams).map(key => key + '=' + extraParams[key]).join('&');
@@ -163,11 +166,10 @@ class DeviceInstall extends React.Component {
data: res.data.data.devices,
pagination,
});
-
}
}).catch((error) => {
- handleApiError(error,"Error occurred while trying to load devices.");
+ handleApiError(error, "Error occurred while trying to load devices.");
this.setState({loading: false});
});
};
@@ -187,7 +189,7 @@ class DeviceInstall extends React.Component {
});
};
- install = () => {
+ install = (timestamp=null) => {
const {selectedRows} = this.state;
const payload = [];
selectedRows.map(device => {
@@ -196,11 +198,11 @@ class DeviceInstall extends React.Component {
type: device.type
});
});
- this.props.onInstall("devices", payload, "install");
+ this.props.onInstall("devices", payload, "install",timestamp);
};
render() {
- const {data, pagination, loading, selectedRows} = this.state;
+ const {data, pagination, loading, selectedRows, scheduledTime,isScheduledInstallVisible} = this.state;
return (
@@ -224,12 +226,7 @@ class DeviceInstall extends React.Component {
rowSelection={this.rowSelection}
scroll={{x: 1000}}
/>
-
-
- Install
-
-
+
);
}
diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/DeviceUninstall.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/DeviceUninstall.js
index f9d30db39fc..c590608fb87 100644
--- a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/DeviceUninstall.js
+++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/DeviceUninstall.js
@@ -18,13 +18,14 @@
import React from "react";
import axios from "axios";
-import {Button,Table, Typography} from "antd";
+import {Button, Select, 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 {handleApiError} from "../../../../js/Utils";
+import InstallModalFooter from "./installModalFooter/InstallModalFooter";
const {Text} = Typography;
const columns = [
@@ -115,8 +116,8 @@ class DeviceUninstall extends React.Component {
rowSelection = {
onChange: (selectedRowKeys, selectedRows) => {
this.setState({
- selectedRows: selectedRows
- })
+ selectedRows: selectedRows
+ })
},
getCheckboxProps: record => ({
disabled: record.name === 'Disabled User', // Column configuration not to be checked
@@ -151,7 +152,7 @@ class DeviceUninstall extends React.Component {
const uuid = this.props.uuid;
axios.get(
- window.location.origin + config.serverConfig.invoker.uri + config.serverConfig.invoker.store + "/subscription/" + uuid + "/"+
+ window.location.origin + config.serverConfig.invoker.uri + config.serverConfig.invoker.store + "/subscription/" + uuid + "/" +
"/devices?" + encodedExtraParams,
).then(res => {
if (res.status === 200) {
@@ -163,7 +164,7 @@ class DeviceUninstall extends React.Component {
});
}
}).catch((error) => {
- handleApiError(error,"Error occurred while trying to load devices.");
+ handleApiError(error, "Error occurred while trying to load devices.");
this.setState({loading: false});
});
};
@@ -172,59 +173,54 @@ class DeviceUninstall extends React.Component {
const pager = {...this.state.pagination};
pager.current = pagination.current;
this.setState({
- pagination: pager,
- });
+ pagination: pager,
+ });
this.fetch({
- results: pagination.pageSize,
- page: pagination.current,
- sortField: sorter.field,
- sortOrder: sorter.order,
- ...filters,
- });
+ results: pagination.pageSize,
+ page: pagination.current,
+ sortField: sorter.field,
+ sortOrder: sorter.order,
+ ...filters,
+ });
};
- uninstall = () => {
+ uninstall = (timestamp = null) => {
const {selectedRows} = this.state;
const payload = [];
selectedRows.map(device => {
payload.push({
- id: device.deviceIdentifier,
- type: device.type
- });
+ id: device.deviceIdentifier,
+ type: device.type
+ });
});
- this.props.onUninstall("devices", payload, "uninstall");
+ this.props.onUninstall("devices", payload, "uninstall", null);
};
render() {
const {data, pagination, loading, selectedRows} = this.state;
return (
-
-
- Start uninstalling the application for devices by selecting the corresponding devices.
- Select uninstall to automatically start uninstalling the application for the respective devices.
-
-
record.deviceIdentifier}
- dataSource={data}
- pagination={{
- ...pagination,
- size: "small",
- showTotal: (total, range) => `showing ${range[0]}-${range[1]} of ${total} devices`
- }}
- loading={loading}
- onChange={this.handleTableChange}
- rowSelection={this.rowSelection}
- scroll={{x: 1000}}
- />
-
-
- Uninstall
-
-
-
+
+
+ Start uninstalling the application for devices by selecting the corresponding devices.
+ Select uninstall to automatically start uninstalling the application for the respective devices.
+
+
record.deviceIdentifier}
+ dataSource={data}
+ pagination={{
+ ...pagination,
+ size: "small",
+ showTotal: (total, range) => `showing ${range[0]}-${range[1]} of ${total} devices`
+ }}
+ loading={loading}
+ onChange={this.handleTableChange}
+ rowSelection={this.rowSelection}
+ scroll={{x: 1000}}
+ />
+
+
);
}
}
diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/GroupInstall.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/GroupInstall.js
index 47d3b628c46..be8c598a234 100644
--- a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/GroupInstall.js
+++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/GroupInstall.js
@@ -22,6 +22,7 @@ import debounce from 'lodash.debounce';
import axios from "axios";
import {withConfigContext} from "../../../../context/ConfigContext";
import {handleApiError} from "../../../../js/Utils";
+import InstallModalFooter from "./installModalFooter/InstallModalFooter";
const {Text} = Typography;
const {Option} = Select;
@@ -112,9 +113,7 @@ class GroupInstall extends React.Component {
{d.text}
))}
-
- Install
-
+
);
}
diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/GroupUninstall.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/GroupUninstall.js
index f3aeebc9748..014d37105dc 100644
--- a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/GroupUninstall.js
+++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/GroupUninstall.js
@@ -22,6 +22,7 @@ import debounce from 'lodash.debounce';
import axios from "axios";
import {withConfigContext} from "../../../../context/ConfigContext";
import {handleApiError} from "../../../../js/Utils";
+import InstallModalFooter from "./installModalFooter/InstallModalFooter";
const {Text} = Typography;
const {Option} = Select;
@@ -75,19 +76,19 @@ class GroupUninstall extends React.Component {
handleChange = value => {
this.setState({
- value,
- data: [],
- fetching: false,
- });
+ value,
+ data: [],
+ fetching: false,
+ });
};
- install = () =>{
+ uninstall = (timestamp=null) =>{
const {value} = this.state;
const data = [];
value.map(val=>{
data.push(val.key);
});
- this.props.onInstall("group", data, "uninstall");
+ this.props.onUninstall("group", data, "uninstall",null);
};
render() {
@@ -108,15 +109,12 @@ class GroupUninstall extends React.Component {
filterOption={false}
onSearch={this.fetchUser}
onChange={this.handleChange}
- style={{width: '100%'}}
- >
+ style={{width: '100%'}}>
{data.map(d => (
{d.text}
))}
-
- Install
-
+
);
}
diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/RoleInstall.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/RoleInstall.js
index b9edba286e0..276ba34ab37 100644
--- a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/RoleInstall.js
+++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/RoleInstall.js
@@ -22,6 +22,7 @@ import debounce from 'lodash.debounce';
import axios from "axios";
import {withConfigContext} from "../../../../context/ConfigContext";
import {handleApiError} from "../../../../js/Utils";
+import InstallModalFooter from "./installModalFooter/InstallModalFooter";
const {Text} = Typography;
const {Option} = Select;
@@ -79,13 +80,13 @@ class RoleInstall extends React.Component {
});
};
- install = () =>{
+ install = (timestamp=null) =>{
const {value} = this.state;
const data = [];
value.map(val=>{
data.push(val.key);
});
- this.props.onInstall("role", data, "install");
+ this.props.onInstall("role", data, "install", timestamp);
};
render() {
@@ -112,9 +113,7 @@ class RoleInstall extends React.Component {
{d.text}
))}
-
- Install
-
+
);
}
diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/RoleUninstall.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/RoleUninstall.js
index 53c3a6c5574..83e27f920c1 100644
--- a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/RoleUninstall.js
+++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/RoleUninstall.js
@@ -22,6 +22,7 @@ import debounce from 'lodash.debounce';
import axios from "axios";
import {withConfigContext} from "../../../../context/ConfigContext";
import {handleApiError} from "../../../../js/Utils";
+import InstallModalFooter from "./installModalFooter/InstallModalFooter";
const {Text} = Typography;
const {Option} = Select;
@@ -80,17 +81,16 @@ class RoleUninstall extends React.Component {
});
};
- install = () =>{
+ uninstall = (timestamp=null) =>{
const {value} = this.state;
const data = [];
value.map(val=>{
data.push(val.key);
});
- this.props.onInstall("role", data, "uninstall");
+ this.props.onUninstall("role", data, "uninstall",null);
};
render() {
-
const {fetching, data, value} = this.state;
return (
@@ -113,9 +113,7 @@ class RoleUninstall extends React.Component {
{d.text}
))}
-
- Install
-
+
);
}
diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/UserInstall.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/UserInstall.js
index 7be794f9ae2..82f91bddff4 100644
--- a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/UserInstall.js
+++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/UserInstall.js
@@ -22,6 +22,7 @@ import debounce from 'lodash.debounce';
import axios from "axios";
import {withConfigContext} from "../../../../context/ConfigContext";
import {handleApiError} from "../../../../js/Utils";
+import InstallModalFooter from "./installModalFooter/InstallModalFooter";
const {Text} = Typography;
const {Option} = Select;
@@ -81,13 +82,13 @@ class UserInstall extends React.Component {
});
};
- install = () => {
+ install = (timestamp=null) => {
const {value} = this.state;
const data = [];
value.map(val => {
data.push(val.key);
});
- this.props.onInstall("user", data, "install");
+ this.props.onInstall("user", data, "install",timestamp);
};
render() {
@@ -112,9 +113,7 @@ class UserInstall extends React.Component {
{d.text}
))}
-
- Install
-
+
);
}
diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/UserUninstall.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/UserUninstall.js
index 5c68455abdc..73786afca25 100644
--- a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/UserUninstall.js
+++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/UserUninstall.js
@@ -22,6 +22,7 @@ import debounce from 'lodash.debounce';
import axios from "axios";
import {withConfigContext} from "../../../../context/ConfigContext";
import {handleApiError} from "../../../../js/Utils";
+import InstallModalFooter from "./installModalFooter/InstallModalFooter";
const {Text} = Typography;
const {Option} = Select;
@@ -49,9 +50,8 @@ class UserUninstall extends React.Component {
const uuid = this.props.uuid;
axios.get(
- window.location.origin+ config.serverConfig.invoker.uri + config.serverConfig.invoker.store+ "/subscription/" + uuid + "/"+
- "/USER?",
-
+ window.location.origin + config.serverConfig.invoker.uri + config.serverConfig.invoker.store + "/subscription/" + uuid + "/" +
+ "/USER?",
).then(res => {
if (res.status === 200) {
if (fetchId !== this.lastFetchId) {
@@ -67,54 +67,53 @@ class UserUninstall extends React.Component {
}
}).catch((error) => {
- handleApiError(error,"Error occurred while trying to load users.");
+ handleApiError(error, "Error occurred while trying to load users.");
this.setState({fetching: false});
});
};
handleChange = value => {
this.setState({
- value,
- data: [],
- fetching: false,
- });
+ value,
+ data: [],
+ fetching: false,
+ });
};
- uninstall = () => {
+ uninstall = (timestamp=null) => {
const {value} = this.state;
const data = [];
value.map(val => {
data.push(val.key);
});
- this.props.onUninstall("user", data, "uninstall");
+ this.props.onUninstall("user", data, "uninstall",null);
};
render() {
const {fetching, data, value} = this.state;
return (
-
-
Start uninstalling the application for one or more users by entering the corresponding user name. Select uninstall to automatically start uninstalling the application for the respective user/users.
-
Select users
-
: null}
- filterOption={false}
- onSearch={this.fetchUser}
- onChange={this.handleChange}
- style={{width: '100%'}}
- >
- {data.map(d => (
-
{d.text}
- ))}
-
-
- Uninstall
-
-
+
+
Start uninstalling the application for one or more users by entering the corresponding user name.
+ Select uninstall to automatically start uninstalling the application for the respective
+ user/users.
+
Select users
+
: null}
+ filterOption={false}
+ onSearch={this.fetchUser}
+ onChange={this.handleChange}
+ style={{width: '100%'}}>
+ {data.map(d => (
+
{d.text}
+ ))}
+
+
+
);
}
}
diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/installModalFooter/InstallModalFooter.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/installModalFooter/InstallModalFooter.js
new file mode 100644
index 00000000000..72552dfc7a5
--- /dev/null
+++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/components/apps/release/install/installModalFooter/InstallModalFooter.js
@@ -0,0 +1,94 @@
+/*
+ * 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, DatePicker} from "antd";
+
+class InstallModalFooter extends React.Component{
+ constructor(props) {
+ super(props);
+ this.state={
+ scheduledTime: null,
+ isScheduledInstallVisible: false
+ }
+ }
+
+ onDateTimeChange = (value, dateString) => {
+ this.setState({
+ scheduledTime: dateString
+ });
+ };
+
+ showScheduledInstall = ()=>{
+ this.setState({
+ isScheduledInstallVisible: true
+ })
+ };
+
+ hideScheduledInstall = ()=>{
+ this.setState({
+ isScheduledInstallVisible: false
+ })
+ };
+
+ render() {
+ const {scheduledTime,isScheduledInstallVisible} =this.state;
+ const {disabled, type} = this.props;
+ return (
+
+
+
+ {type}
+
+
+ Scheduled {type}
+
+
+
+
+ {
+ this.props.operation(scheduledTime);
+ }}>
+ Schedule
+
+
+ Cancel
+
+
+
+ );
+ }
+}
+
+export default InstallModalFooter;
\ No newline at end of file
diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/js/Utils.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/js/Utils.js
index 1850d221327..9bb8c4a521e 100644
--- a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/js/Utils.js
+++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.ui/react-app/src/js/Utils.js
@@ -25,7 +25,7 @@ export const handleApiError = (error, message) => {
} else {
notification["error"]({
message: "There was a problem",
- duration: 10,
+ duration: 2,
description: message,
});
}