mirror of
https://repository.entgra.net/community/device-mgt-core.git
synced 2025-10-06 02:01:45 +00:00
Add app delete and retire functionality to APPM UI
This commit is contained in:
parent
c953c41872
commit
2d0277de3a
@ -11,6 +11,7 @@
|
||||
"license": "Apache License 2.0",
|
||||
"dependencies": {
|
||||
"@ant-design/dark-theme": "^0.2.2",
|
||||
"@ant-design/icons": "^4.0.6",
|
||||
"@babel/polyfill": "^7.6.0",
|
||||
"acorn": "^6.2.0",
|
||||
"antd": "^3.23.6",
|
||||
@ -25,6 +26,7 @@
|
||||
"fetch": "^1.1.0",
|
||||
"imagemin": "^6.1.0",
|
||||
"keymirror": "^0.1.1",
|
||||
"lodash.debounce": "latest",
|
||||
"rc-tween-one": "^2.4.1",
|
||||
"react-d3-graph": "^2.1.0",
|
||||
"react-highlight-words": "^0.16.0",
|
||||
@ -39,8 +41,7 @@
|
||||
"redux-thunk": "^2.3.0",
|
||||
"shade-blend-color": "^1.0.0",
|
||||
"storm-react-diagrams": "^5.2.1",
|
||||
"typescript": "^3.6.4",
|
||||
"lodash.debounce": "latest"
|
||||
"typescript": "^3.6.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.5.0",
|
||||
|
||||
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 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 { DeleteOutlined, ExclamationCircleOutlined } from '@ant-design/icons';
|
||||
import { Button, Modal, notification, Tooltip } from 'antd';
|
||||
import axios from 'axios';
|
||||
import { handleApiError } from '../../../../../../../../../../../services/utils/errorHandler';
|
||||
import { withConfigContext } from '../../../../../../../../../../../components/ConfigContext';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
import '../../styles.css';
|
||||
|
||||
const { confirm } = Modal;
|
||||
|
||||
class DeleteApp extends React.Component {
|
||||
showModal = () => {
|
||||
confirm({
|
||||
title: 'Are you sure you want to delete this app?',
|
||||
icon: <ExclamationCircleOutlined style={{ color: 'red' }} />,
|
||||
content:
|
||||
'You are trying to delete the entire application, by performing this operation all ' +
|
||||
'app data, app release data, and all release artifacts will be deleted ' +
|
||||
'permanently. Further, please note, this process cannot be undone.',
|
||||
okText: 'Yes',
|
||||
okType: 'danger',
|
||||
cancelText: 'No',
|
||||
onOk: this.deleteRelease,
|
||||
});
|
||||
};
|
||||
|
||||
deleteRelease = () => {
|
||||
const config = this.props.context;
|
||||
const apiUrl =
|
||||
window.location.origin +
|
||||
config.serverConfig.invoker.uri +
|
||||
config.serverConfig.invoker.publisher +
|
||||
'/admin/applications/' +
|
||||
this.props.id;
|
||||
axios
|
||||
.delete(apiUrl)
|
||||
.then(res => {
|
||||
if (res.status === 200) {
|
||||
notification.success({
|
||||
message: 'Successfully deleted the app',
|
||||
});
|
||||
this.props.history.push('/publisher');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
handleApiError(
|
||||
error,
|
||||
'Something Went wrong when trying to delete the app, Please contact the administrator',
|
||||
);
|
||||
this.setState({
|
||||
loading: false,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="delete-app">
|
||||
{this.props.isDeletableApp && (
|
||||
<Button
|
||||
type="link"
|
||||
className="btn-view-more"
|
||||
onClick={this.showModal}
|
||||
>
|
||||
<DeleteOutlined /> Delete
|
||||
</Button>
|
||||
)}
|
||||
{!this.props.isDeletableApp && (
|
||||
<Tooltip
|
||||
placement="leftTop"
|
||||
title="All application releases should be in a deletable state."
|
||||
>
|
||||
<Button type="link" disabled={true} className="btn-view-more">
|
||||
<DeleteOutlined /> Delete
|
||||
</Button>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withConfigContext(withRouter(DeleteApp));
|
||||
@ -17,10 +17,12 @@
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Button, Modal, notification, Spin } from 'antd';
|
||||
import { Button, Modal, notification, Popover, Spin, Tooltip } from 'antd';
|
||||
import axios from 'axios';
|
||||
import { withConfigContext } from '../../../../../../../../../../../components/ConfigContext';
|
||||
import { handleApiError } from '../../../../../../../../../../../services/utils/errorHandler';
|
||||
import { SettingOutlined, QuestionCircleOutlined } from '@ant-design/icons';
|
||||
import '../../styles.css';
|
||||
|
||||
class ManagedConfigurationsIframe extends React.Component {
|
||||
constructor(props) {
|
||||
@ -29,6 +31,7 @@ class ManagedConfigurationsIframe extends React.Component {
|
||||
this.state = {
|
||||
visible: false,
|
||||
loading: false,
|
||||
isHintVisible: false,
|
||||
};
|
||||
}
|
||||
|
||||
@ -201,26 +204,69 @@ class ManagedConfigurationsIframe extends React.Component {
|
||||
});
|
||||
};
|
||||
|
||||
handleHintVisibleChange = visible => {
|
||||
this.setState({ isHintVisible: visible });
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<Button
|
||||
size="small"
|
||||
type="primary"
|
||||
icon="setting"
|
||||
onClick={this.showModal}
|
||||
>
|
||||
Manage
|
||||
</Button>
|
||||
{this.props.isEnabled && (
|
||||
<Button
|
||||
type="link"
|
||||
className="btn-view-more"
|
||||
onClick={this.showModal}
|
||||
>
|
||||
<SettingOutlined /> Managed Configurations
|
||||
</Button>
|
||||
)}
|
||||
{!this.props.isEnabled && (
|
||||
<Tooltip
|
||||
placement="leftTop"
|
||||
title="Managed configurations are available only with android enterprise apps."
|
||||
>
|
||||
<Button type="link" className="btn-view-more" disabled={true}>
|
||||
<SettingOutlined /> Managed Configurations
|
||||
</Button>
|
||||
</Tooltip>
|
||||
)}
|
||||
<Modal
|
||||
visible={this.state.visible}
|
||||
onOk={this.handleOk}
|
||||
onCancel={this.handleCancel}
|
||||
footer={null}
|
||||
>
|
||||
<Spin spinning={this.state.loading}>
|
||||
<div id="manage-config-iframe-container"></div>
|
||||
</Spin>
|
||||
<div>
|
||||
<Popover
|
||||
title={null}
|
||||
trigger="click"
|
||||
visible={this.state.isHintVisible}
|
||||
content={
|
||||
<p>
|
||||
If you are developing apps for the enterprise market, you may
|
||||
need to satisfy particular requirements set by a
|
||||
organization"s policies. Managed configurations,
|
||||
previously previously known as application restrictions, allow
|
||||
the organization"s IT admin to remotely specify settings
|
||||
for apps. This capability is particularly useful for
|
||||
organization-approved apps deployed to a work profile.
|
||||
</p>
|
||||
}
|
||||
onVisibleChange={this.handleHintVisibleChange}
|
||||
overlayStyle={{ width: 300 }}
|
||||
>
|
||||
<Button
|
||||
size="large"
|
||||
type="link"
|
||||
style={{ marginTop: -56, fontSize: '1.2em' }}
|
||||
>
|
||||
<QuestionCircleOutlined />
|
||||
</Button>
|
||||
</Popover>
|
||||
<Spin spinning={this.state.loading}>
|
||||
<div id="manage-config-iframe-container"></div>
|
||||
</Spin>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 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 {
|
||||
EyeInvisibleOutlined,
|
||||
ExclamationCircleOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import { Button, Modal, notification, Tooltip } from 'antd';
|
||||
import axios from 'axios';
|
||||
import { handleApiError } from '../../../../../../../../../../../services/utils/errorHandler';
|
||||
import { withConfigContext } from '../../../../../../../../../../../components/ConfigContext';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
import '../../styles.css';
|
||||
|
||||
const { confirm } = Modal;
|
||||
|
||||
class RetireApp extends React.Component {
|
||||
showModal = () => {
|
||||
confirm({
|
||||
title: 'Are you sure you want to retire this app?',
|
||||
icon: <ExclamationCircleOutlined style={{ color: 'red' }} />,
|
||||
content:
|
||||
'You are trying to retire the entire application, by performing this operation, ' +
|
||||
'you will not see the app data or app release data on either publisher or store. ' +
|
||||
'Further, please note, this process cannot be undone.',
|
||||
okText: 'Yes',
|
||||
okType: 'danger',
|
||||
cancelText: 'No',
|
||||
onOk: this.hideApp,
|
||||
});
|
||||
};
|
||||
|
||||
hideApp = () => {
|
||||
const config = this.props.context;
|
||||
const apiUrl =
|
||||
window.location.origin +
|
||||
config.serverConfig.invoker.uri +
|
||||
config.serverConfig.invoker.publisher +
|
||||
'/admin/applications/retire/' +
|
||||
this.props.id;
|
||||
axios
|
||||
.put(apiUrl)
|
||||
.then(res => {
|
||||
if (res.status === 200) {
|
||||
notification.success({
|
||||
message: 'Successfully hided the app',
|
||||
});
|
||||
this.props.history.push('/publisher');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.log(error);
|
||||
handleApiError(
|
||||
error,
|
||||
'Something Went wrong when trying to reitre the app, Please contact the administrator',
|
||||
);
|
||||
this.setState({
|
||||
loading: false,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
{this.props.isHideableApp && (
|
||||
<Button
|
||||
type="link"
|
||||
onClick={this.showModal}
|
||||
className="btn-view-more"
|
||||
>
|
||||
<EyeInvisibleOutlined /> Retire
|
||||
</Button>
|
||||
)}
|
||||
{!this.props.isHideableApp && (
|
||||
<Tooltip
|
||||
placement="leftTop"
|
||||
title="All releases should be in retired state"
|
||||
>
|
||||
<Button type="link" disabled={true} className="btn-view-more">
|
||||
<EyeInvisibleOutlined /> Retire
|
||||
</Button>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withConfigContext(withRouter(RetireApp));
|
||||
@ -33,6 +33,8 @@ import {
|
||||
Card,
|
||||
Badge,
|
||||
Tooltip,
|
||||
Dropdown,
|
||||
Menu,
|
||||
} from 'antd';
|
||||
import DetailedRating from '../../../../DetailedRating';
|
||||
import { Link } from 'react-router-dom';
|
||||
@ -46,6 +48,9 @@ import ManagedConfigurationsIframe from './components/ManagedConfigurationsIfram
|
||||
import { handleApiError } from '../../../../../../../../../services/utils/errorHandler';
|
||||
import Authorized from '../../../../../../../../../components/Authorized/Authorized';
|
||||
import { isAuthorized } from '../../../../../../../../../services/utils/authorizationHandler';
|
||||
import { MoreOutlined } from '@ant-design/icons';
|
||||
import DeleteApp from './components/DeleteApp';
|
||||
import RetireApp from './components/RetireApp';
|
||||
|
||||
const { Meta } = Card;
|
||||
const { Text, Title } = Typography;
|
||||
@ -485,6 +490,7 @@ class AppDetailsDrawer extends React.Component {
|
||||
if (app == null) {
|
||||
return null;
|
||||
}
|
||||
const { id } = this.props.app;
|
||||
|
||||
let avatar = null;
|
||||
|
||||
@ -527,6 +533,36 @@ class AppDetailsDrawer extends React.Component {
|
||||
visible={visible}
|
||||
>
|
||||
<Spin spinning={loading} delay={500}>
|
||||
<div className="app-details-drawer">
|
||||
<Dropdown
|
||||
trigger={['click']}
|
||||
overlay={
|
||||
<Menu>
|
||||
<Menu.Item key="0">
|
||||
<DeleteApp id={id} isDeletableApp={app.isDeletableApp} />
|
||||
</Menu.Item>
|
||||
<Menu.Item key="1">
|
||||
<RetireApp id={id} isHideableApp={app.isHideableApp} />
|
||||
</Menu.Item>
|
||||
{config.androidEnterpriseToken !== null &&
|
||||
isAuthorized(
|
||||
config.user,
|
||||
'/permission/admin/device-mgt/enterprise/user/modify',
|
||||
) && (
|
||||
<Menu.Item key="2">
|
||||
<ManagedConfigurationsIframe
|
||||
isEnabled={app.isAndroidEnterpriseApp}
|
||||
style={{ paddingTop: 16 }}
|
||||
packageName={app.packageName}
|
||||
/>
|
||||
</Menu.Item>
|
||||
)}
|
||||
</Menu>
|
||||
}
|
||||
>
|
||||
<MoreOutlined style={{ fontSize: 34 }} />
|
||||
</Dropdown>
|
||||
</div>
|
||||
<div style={{ textAlign: 'center' }}>
|
||||
{avatar}
|
||||
<Authorized
|
||||
@ -540,38 +576,6 @@ class AppDetailsDrawer extends React.Component {
|
||||
/>
|
||||
</div>
|
||||
<Divider />
|
||||
{/* display manage config button only if the app is public android app*/}
|
||||
{app.isAndroidEnterpriseApp &&
|
||||
config.androidEnterpriseToken !== null && (
|
||||
<Authorized
|
||||
permission="/permission/admin/device-mgt/enterprise/user/modify"
|
||||
yes={
|
||||
<div>
|
||||
<div>
|
||||
<Text strong={true}>Set up managed configurations</Text>
|
||||
</div>
|
||||
<div style={{ paddingTop: 16 }}>
|
||||
<Text>
|
||||
If you are developing apps for the enterprise market,
|
||||
you may need to satisfy particular requirements set by
|
||||
a organization's policies. Managed
|
||||
configurations, previously known as application
|
||||
restrictions, allow the organization's IT admin
|
||||
to remotely specify settings for apps. This capability
|
||||
is particularly useful for organization-approved apps
|
||||
deployed to a work profile.
|
||||
</Text>
|
||||
</div>
|
||||
<br />
|
||||
<ManagedConfigurationsIframe
|
||||
style={{ paddingTop: 16 }}
|
||||
packageName={app.packageName}
|
||||
/>
|
||||
<Divider dashed={true} />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<Text strong={true}>Releases </Text>
|
||||
<div className="releases-details">
|
||||
<List
|
||||
|
||||
@ -35,3 +35,11 @@
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.app-details-drawer {
|
||||
text-align: right
|
||||
}
|
||||
|
||||
.btn-view-more {
|
||||
color: rgba(0, 0, 0, 0.65) !important;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user