mirror of
https://repository.entgra.net/community/device-mgt-core.git
synced 2025-10-06 02:01:45 +00:00
Merge branch 'feature/appm-publisher/pbac' into 'master'
Add permission based access control to APPM Publisher Closes product-iots#483 See merge request entgra/carbon-device-mgt!507
This commit is contained in:
commit
831b2fa89f
@ -6,6 +6,7 @@
|
|||||||
},
|
},
|
||||||
"serverConfig": {
|
"serverConfig": {
|
||||||
"invoker": {
|
"invoker": {
|
||||||
|
"contextPath" : "/publisher-ui-request-handler",
|
||||||
"uri": "/publisher-ui-request-handler/invoke",
|
"uri": "/publisher-ui-request-handler/invoke",
|
||||||
"publisher": "/application-mgt-publisher/v1.0",
|
"publisher": "/application-mgt-publisher/v1.0",
|
||||||
"store": "/application-mgt-store/v1.0",
|
"store": "/application-mgt-store/v1.0",
|
||||||
|
|||||||
@ -106,37 +106,24 @@ class App extends React.Component {
|
|||||||
checkUserLoggedIn = config => {
|
checkUserLoggedIn = config => {
|
||||||
axios
|
axios
|
||||||
.post(
|
.post(
|
||||||
window.location.origin + '/publisher-ui-request-handler/user',
|
window.location.origin +
|
||||||
'platform=publisher',
|
config.serverConfig.invoker.contextPath +
|
||||||
|
'/user',
|
||||||
)
|
)
|
||||||
.then(res => {
|
.then(res => {
|
||||||
config.user = res.data.data;
|
config.user = {
|
||||||
|
username: res.data.data,
|
||||||
|
};
|
||||||
const pageURL = window.location.pathname;
|
const pageURL = window.location.pathname;
|
||||||
const lastURLSegment = pageURL.substr(pageURL.lastIndexOf('/') + 1);
|
const lastURLSegment = pageURL.substr(pageURL.lastIndexOf('/') + 1);
|
||||||
if (lastURLSegment === 'login') {
|
if (lastURLSegment === 'login') {
|
||||||
window.location.href = window.location.origin + '/publisher/';
|
window.location.href = window.location.origin + '/publisher/';
|
||||||
} else {
|
} else {
|
||||||
this.getAndroidEnterpriseToken(config);
|
this.getUserPermissions(config);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
this.handleApiError(error, config);
|
||||||
const redirectUrl = encodeURI(window.location.href);
|
|
||||||
const pageURL = window.location.pathname;
|
|
||||||
const lastURLSegment = pageURL.substr(pageURL.lastIndexOf('/') + 1);
|
|
||||||
if (lastURLSegment !== 'login') {
|
|
||||||
window.location.href =
|
|
||||||
window.location.origin +
|
|
||||||
`/publisher/login?redirect=${redirectUrl}`;
|
|
||||||
} else {
|
|
||||||
this.getAndroidEnterpriseToken(config);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.setState({
|
|
||||||
loading: false,
|
|
||||||
error: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -152,6 +139,42 @@ class App extends React.Component {
|
|||||||
document.getElementsByTagName('head')[0].appendChild(link);
|
document.getElementsByTagName('head')[0].appendChild(link);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
getUserPermissions = config => {
|
||||||
|
axios
|
||||||
|
.get(
|
||||||
|
window.location.origin +
|
||||||
|
config.serverConfig.invoker.uri +
|
||||||
|
config.serverConfig.invoker.deviceMgt +
|
||||||
|
'/users/current-user/permissions',
|
||||||
|
)
|
||||||
|
.then(res => {
|
||||||
|
config.user.permissions = res.data.data.permissions;
|
||||||
|
this.getAndroidEnterpriseToken(config);
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
this.handleApiError(error, config);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
handleApiError = (error, config) => {
|
||||||
|
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
||||||
|
const redirectUrl = encodeURI(window.location.href);
|
||||||
|
const pageURL = window.location.pathname;
|
||||||
|
const lastURLSegment = pageURL.substr(pageURL.lastIndexOf('/') + 1);
|
||||||
|
if (lastURLSegment !== 'login') {
|
||||||
|
window.location.href =
|
||||||
|
window.location.origin + `/publisher/login?redirect=${redirectUrl}`;
|
||||||
|
} else {
|
||||||
|
this.getAndroidEnterpriseToken(config);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
error: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { loading, error } = this.state;
|
const { loading, error } = this.state;
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* 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 { withConfigContext } from '../ConfigContext';
|
||||||
|
import { isAuthorized } from '../../services/utils/authorizationHandler';
|
||||||
|
|
||||||
|
class Authorized extends react.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return isAuthorized(this.props.context.user, this.props.permission)
|
||||||
|
? this.props.yes
|
||||||
|
: this.props.no;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Authorized.defaultProps = {
|
||||||
|
yes: null,
|
||||||
|
no: null,
|
||||||
|
};
|
||||||
|
export default withConfigContext(Authorized);
|
||||||
@ -24,6 +24,7 @@ import { Redirect } from 'react-router';
|
|||||||
import './styles.css';
|
import './styles.css';
|
||||||
import { withConfigContext } from '../../components/ConfigContext';
|
import { withConfigContext } from '../../components/ConfigContext';
|
||||||
import Logout from './components/Logout';
|
import Logout from './components/Logout';
|
||||||
|
import { isAuthorized } from '../../services/utils/authorizationHandler';
|
||||||
|
|
||||||
const { Header, Content, Footer } = Layout;
|
const { Header, Content, Footer } = Layout;
|
||||||
const { SubMenu } = Menu;
|
const { SubMenu } = Menu;
|
||||||
@ -84,33 +85,36 @@ class Dashboard extends React.Component {
|
|||||||
Apps
|
Apps
|
||||||
</Link>
|
</Link>
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
|
{isAuthorized(
|
||||||
<SubMenu
|
this.props.context.user,
|
||||||
title={
|
'/permission/admin/app-mgt/publisher/application/update',
|
||||||
<span className="submenu-title-wrapper">
|
) && (
|
||||||
<Icon type="plus" />
|
<SubMenu
|
||||||
Add New App
|
title={
|
||||||
</span>
|
<span className="submenu-title-wrapper">
|
||||||
}
|
<Icon type="plus" />
|
||||||
>
|
Add New App
|
||||||
<Menu.Item key="add-new-public-app">
|
</span>
|
||||||
<Link to="/publisher/add-new-app/public">Public App</Link>
|
}
|
||||||
</Menu.Item>
|
>
|
||||||
<Menu.Item key="add-new-enterprise-app">
|
<Menu.Item key="add-new-public-app">
|
||||||
<Link to="/publisher/add-new-app/enterprise">
|
<Link to="/publisher/add-new-app/public">Public App</Link>
|
||||||
Enterprise App
|
</Menu.Item>
|
||||||
</Link>
|
<Menu.Item key="add-new-enterprise-app">
|
||||||
</Menu.Item>
|
<Link to="/publisher/add-new-app/enterprise">
|
||||||
<Menu.Item key="add-new-web-clip">
|
Enterprise App
|
||||||
<Link to="/publisher/add-new-app/web-clip">Web Clip</Link>
|
</Link>
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
<Menu.Item key="add-new-custom-app">
|
<Menu.Item key="add-new-web-clip">
|
||||||
<Link to="/publisher/add-new-app/custom-app">
|
<Link to="/publisher/add-new-app/web-clip">Web Clip</Link>
|
||||||
Custom App
|
</Menu.Item>
|
||||||
</Link>
|
<Menu.Item key="add-new-custom-app">
|
||||||
</Menu.Item>
|
<Link to="/publisher/add-new-app/custom-app">
|
||||||
</SubMenu>
|
Custom App
|
||||||
|
</Link>
|
||||||
|
</Menu.Item>
|
||||||
|
</SubMenu>
|
||||||
|
)}
|
||||||
<SubMenu
|
<SubMenu
|
||||||
title={
|
title={
|
||||||
<span className="submenu-title-wrapper">
|
<span className="submenu-title-wrapper">
|
||||||
@ -139,7 +143,7 @@ class Dashboard extends React.Component {
|
|||||||
title={
|
title={
|
||||||
<span className="submenu-title-wrapper">
|
<span className="submenu-title-wrapper">
|
||||||
<Icon type="user" />
|
<Icon type="user" />
|
||||||
{this.config.user}
|
{this.config.username}
|
||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|||||||
@ -22,6 +22,7 @@ import axios from 'axios';
|
|||||||
import { withConfigContext } from '../../../../../../../../components/ConfigContext';
|
import { withConfigContext } from '../../../../../../../../components/ConfigContext';
|
||||||
import { handleApiError } from '../../../../../../../../services/utils/errorHandler';
|
import { handleApiError } from '../../../../../../../../services/utils/errorHandler';
|
||||||
import debounce from 'lodash.debounce';
|
import debounce from 'lodash.debounce';
|
||||||
|
import Authorized from '../../../../../../../../components/Authorized/Authorized';
|
||||||
|
|
||||||
const formItemLayout = {
|
const formItemLayout = {
|
||||||
labelCol: {
|
labelCol: {
|
||||||
@ -46,12 +47,6 @@ class NewAppDetailsForm extends React.Component {
|
|||||||
fetching: false,
|
fetching: false,
|
||||||
roleSearchValue: [],
|
roleSearchValue: [],
|
||||||
unrestrictedRoles: [],
|
unrestrictedRoles: [],
|
||||||
forbiddenErrors: {
|
|
||||||
categories: false,
|
|
||||||
tags: false,
|
|
||||||
deviceTypes: false,
|
|
||||||
roles: false,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
this.lastFetchId = 0;
|
this.lastFetchId = 0;
|
||||||
this.fetchRoles = debounce(this.fetchRoles, 800);
|
this.fetchRoles = debounce(this.fetchRoles, 800);
|
||||||
@ -127,18 +122,9 @@ class NewAppDetailsForm extends React.Component {
|
|||||||
'Error occurred while trying to load categories.',
|
'Error occurred while trying to load categories.',
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
if (error.hasOwnProperty('response') && error.response.status === 403) {
|
this.setState({
|
||||||
const { forbiddenErrors } = this.state;
|
loading: false,
|
||||||
forbiddenErrors.categories = true;
|
});
|
||||||
this.setState({
|
|
||||||
forbiddenErrors,
|
|
||||||
loading: false,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.setState({
|
|
||||||
loading: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -166,18 +152,9 @@ class NewAppDetailsForm extends React.Component {
|
|||||||
'Error occurred while trying to load tags.',
|
'Error occurred while trying to load tags.',
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
if (error.hasOwnProperty('response') && error.response.status === 403) {
|
this.setState({
|
||||||
const { forbiddenErrors } = this.state;
|
loading: false,
|
||||||
forbiddenErrors.tags = true;
|
});
|
||||||
this.setState({
|
|
||||||
forbiddenErrors,
|
|
||||||
loading: false,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.setState({
|
|
||||||
loading: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -279,18 +256,9 @@ class NewAppDetailsForm extends React.Component {
|
|||||||
'Error occurred while trying to load roles.',
|
'Error occurred while trying to load roles.',
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
if (error.hasOwnProperty('response') && error.response.status === 403) {
|
this.setState({
|
||||||
const { forbiddenErrors } = this.state;
|
fetching: false,
|
||||||
forbiddenErrors.roles = true;
|
});
|
||||||
this.setState({
|
|
||||||
forbiddenErrors,
|
|
||||||
fetching: false,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.setState({
|
|
||||||
fetching: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -310,7 +278,6 @@ class NewAppDetailsForm extends React.Component {
|
|||||||
deviceTypes,
|
deviceTypes,
|
||||||
fetching,
|
fetching,
|
||||||
unrestrictedRoles,
|
unrestrictedRoles,
|
||||||
forbiddenErrors,
|
|
||||||
} = this.state;
|
} = this.state;
|
||||||
const { getFieldDecorator } = this.props.form;
|
const { getFieldDecorator } = this.props.form;
|
||||||
|
|
||||||
@ -326,14 +293,17 @@ class NewAppDetailsForm extends React.Component {
|
|||||||
>
|
>
|
||||||
{formConfig.installationType !== 'WEB_CLIP' && (
|
{formConfig.installationType !== 'WEB_CLIP' && (
|
||||||
<div>
|
<div>
|
||||||
{forbiddenErrors.deviceTypes && (
|
<Authorized
|
||||||
<Alert
|
permission="/permission/admin/device-mgt/admin/device-type/view"
|
||||||
message="You don't have permission to view device types."
|
no={
|
||||||
type="warning"
|
<Alert
|
||||||
banner
|
message="You don't have permission to view device types."
|
||||||
closable
|
type="warning"
|
||||||
/>
|
banner
|
||||||
)}
|
closable
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
<Form.Item {...formItemLayout} label="Device Type">
|
<Form.Item {...formItemLayout} label="Device Type">
|
||||||
{getFieldDecorator('deviceType', {
|
{getFieldDecorator('deviceType', {
|
||||||
rules: [
|
rules: [
|
||||||
@ -387,14 +357,16 @@ class NewAppDetailsForm extends React.Component {
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
{/* Unrestricted Roles*/}
|
{/* Unrestricted Roles*/}
|
||||||
{forbiddenErrors.roles && (
|
<Authorized
|
||||||
<Alert
|
permission="/permission/admin/device-mgt/roles/view"
|
||||||
message="You don't have permission to view roles."
|
no={
|
||||||
type="warning"
|
<Alert
|
||||||
banner
|
message="You don't have permission to view roles."
|
||||||
closable
|
type="warning"
|
||||||
/>
|
banner
|
||||||
)}
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
<Form.Item {...formItemLayout} label="Visible Roles">
|
<Form.Item {...formItemLayout} label="Visible Roles">
|
||||||
{getFieldDecorator('unrestrictedRoles', {
|
{getFieldDecorator('unrestrictedRoles', {
|
||||||
rules: [],
|
rules: [],
|
||||||
@ -417,14 +389,6 @@ class NewAppDetailsForm extends React.Component {
|
|||||||
</Select>,
|
</Select>,
|
||||||
)}
|
)}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
{forbiddenErrors.categories && (
|
|
||||||
<Alert
|
|
||||||
message="You don't have permission to view categories."
|
|
||||||
type="warning"
|
|
||||||
banner
|
|
||||||
closable
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<Form.Item {...formItemLayout} label="Categories">
|
<Form.Item {...formItemLayout} label="Categories">
|
||||||
{getFieldDecorator('categories', {
|
{getFieldDecorator('categories', {
|
||||||
rules: [
|
rules: [
|
||||||
@ -450,14 +414,6 @@ class NewAppDetailsForm extends React.Component {
|
|||||||
</Select>,
|
</Select>,
|
||||||
)}
|
)}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
{forbiddenErrors.tags && (
|
|
||||||
<Alert
|
|
||||||
message="You don't have permission to view tags."
|
|
||||||
type="warning"
|
|
||||||
banner
|
|
||||||
closable
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<Form.Item {...formItemLayout} label="Tags">
|
<Form.Item {...formItemLayout} label="Tags">
|
||||||
{getFieldDecorator('tags', {
|
{getFieldDecorator('tags', {
|
||||||
rules: [
|
rules: [
|
||||||
|
|||||||
@ -31,6 +31,7 @@ import {
|
|||||||
Alert,
|
Alert,
|
||||||
} from 'antd';
|
} from 'antd';
|
||||||
import '@babel/polyfill';
|
import '@babel/polyfill';
|
||||||
|
import Authorized from '../../../../../../../../components/Authorized/Authorized';
|
||||||
|
|
||||||
const { Text } = Typography;
|
const { Text } = Typography;
|
||||||
|
|
||||||
@ -466,14 +467,16 @@ class NewAppUploadForm extends React.Component {
|
|||||||
{formConfig.installationType !== 'WEB_CLIP' &&
|
{formConfig.installationType !== 'WEB_CLIP' &&
|
||||||
formConfig.installationType !== 'CUSTOM' && (
|
formConfig.installationType !== 'CUSTOM' && (
|
||||||
<div>
|
<div>
|
||||||
{this.props.forbiddenErrors.supportedOsVersions && (
|
<Authorized
|
||||||
<Alert
|
permission="/permission/admin/device-mgt/admin/device-type"
|
||||||
message="You don't have permission to view supported OS versions."
|
no={
|
||||||
type="warning"
|
<Alert
|
||||||
banner
|
message="You don't have permission to view supported OS versions."
|
||||||
closable
|
type="warning"
|
||||||
/>
|
banner
|
||||||
)}
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
{...formItemLayout}
|
{...formItemLayout}
|
||||||
label="Supported OS Versions"
|
label="Supported OS Versions"
|
||||||
|
|||||||
@ -149,18 +149,9 @@ class AddNewAppFormComponent extends React.Component {
|
|||||||
'Error occurred while trying to load supported OS versions.',
|
'Error occurred while trying to load supported OS versions.',
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
if (error.hasOwnProperty('response') && error.response.status === 403) {
|
this.setState({
|
||||||
const { forbiddenErrors } = this.state;
|
loading: false,
|
||||||
forbiddenErrors.supportedOsVersions = true;
|
});
|
||||||
this.setState({
|
|
||||||
forbiddenErrors,
|
|
||||||
loading: false,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.setState({
|
|
||||||
loading: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -171,7 +162,6 @@ class AddNewAppFormComponent extends React.Component {
|
|||||||
isError,
|
isError,
|
||||||
supportedOsVersions,
|
supportedOsVersions,
|
||||||
errorText,
|
errorText,
|
||||||
forbiddenErrors,
|
|
||||||
} = this.state;
|
} = this.state;
|
||||||
const { formConfig } = this.props;
|
const { formConfig } = this.props;
|
||||||
return (
|
return (
|
||||||
@ -193,7 +183,6 @@ class AddNewAppFormComponent extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
<div style={{ display: current === 1 ? 'unset' : 'none' }}>
|
<div style={{ display: current === 1 ? 'unset' : 'none' }}>
|
||||||
<NewAppUploadForm
|
<NewAppUploadForm
|
||||||
forbiddenErrors={forbiddenErrors}
|
|
||||||
formConfig={formConfig}
|
formConfig={formConfig}
|
||||||
supportedOsVersions={supportedOsVersions}
|
supportedOsVersions={supportedOsVersions}
|
||||||
onSuccessReleaseData={this.onSuccessReleaseData}
|
onSuccessReleaseData={this.onSuccessReleaseData}
|
||||||
|
|||||||
@ -17,9 +17,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { PageHeader, Typography, Breadcrumb, Icon } from 'antd';
|
import { PageHeader, Typography, Breadcrumb, Icon, Result } from 'antd';
|
||||||
import AddNewAppForm from '../../components/AddNewAppForm';
|
import AddNewAppForm from '../../components/AddNewAppForm';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
import Authorized from '../../../../../../components/Authorized/Authorized';
|
||||||
|
|
||||||
const { Paragraph } = Typography;
|
const { Paragraph } = Typography;
|
||||||
|
|
||||||
@ -70,7 +71,17 @@ class AddNewCustomApp extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
<div style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}>
|
<div style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}>
|
||||||
<AddNewAppForm formConfig={formConfig} />
|
<Authorized
|
||||||
|
permission="/permission/admin/app-mgt/publisher/application/update"
|
||||||
|
yes={<AddNewAppForm formConfig={formConfig} />}
|
||||||
|
no={
|
||||||
|
<Result
|
||||||
|
status="403"
|
||||||
|
title="You don't have permission to add new apps."
|
||||||
|
subTitle="Please contact system administrator"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -17,9 +17,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { PageHeader, Typography, Breadcrumb, Icon } from 'antd';
|
import { PageHeader, Typography, Breadcrumb, Icon, Result } from 'antd';
|
||||||
import AddNewAppForm from '../../components/AddNewAppForm';
|
import AddNewAppForm from '../../components/AddNewAppForm';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
import Authorized from '../../../../../../components/Authorized/Authorized';
|
||||||
|
|
||||||
const { Paragraph } = Typography;
|
const { Paragraph } = Typography;
|
||||||
|
|
||||||
@ -64,7 +65,17 @@ class AddNewEnterpriseApp extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
<div style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}>
|
<div style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}>
|
||||||
<AddNewAppForm formConfig={formConfig} />
|
<Authorized
|
||||||
|
permission="/permission/admin/app-mgt/publisher/application/update"
|
||||||
|
yes={<AddNewAppForm formConfig={formConfig} />}
|
||||||
|
no={
|
||||||
|
<Result
|
||||||
|
status="403"
|
||||||
|
title="You don't have permission to add new apps."
|
||||||
|
subTitle="Please contact system administrator"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -17,9 +17,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Icon, PageHeader, Typography, Breadcrumb } from 'antd';
|
import { Icon, PageHeader, Typography, Breadcrumb, Result } from 'antd';
|
||||||
import AddNewAppForm from '../../components/AddNewAppForm';
|
import AddNewAppForm from '../../components/AddNewAppForm';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
import Authorized from '../../../../../../components/Authorized/Authorized';
|
||||||
|
|
||||||
const { Paragraph } = Typography;
|
const { Paragraph } = Typography;
|
||||||
|
|
||||||
@ -72,7 +73,17 @@ class AddNewPublicApp extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
<div style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}>
|
<div style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}>
|
||||||
<AddNewAppForm formConfig={formConfig} />
|
<Authorized
|
||||||
|
permission="/permission/admin/app-mgt/publisher/application/update"
|
||||||
|
yes={<AddNewAppForm formConfig={formConfig} />}
|
||||||
|
no={
|
||||||
|
<Result
|
||||||
|
status="403"
|
||||||
|
title="You don't have permission to add new apps."
|
||||||
|
subTitle="Please contact system administrator"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -17,9 +17,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Icon, PageHeader, Typography, Breadcrumb } from 'antd';
|
import { Icon, PageHeader, Typography, Breadcrumb, Result } from 'antd';
|
||||||
import AddNewAppForm from '../../components/AddNewAppForm';
|
import AddNewAppForm from '../../components/AddNewAppForm';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
import Authorized from '../../../../../../components/Authorized/Authorized';
|
||||||
|
|
||||||
const { Paragraph } = Typography;
|
const { Paragraph } = Typography;
|
||||||
|
|
||||||
@ -65,7 +66,17 @@ class AddNewEnterpriseApp extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
<div style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}>
|
<div style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}>
|
||||||
<AddNewAppForm formConfig={formConfig} />
|
<Authorized
|
||||||
|
permission="/permission/admin/app-mgt/publisher/application/update"
|
||||||
|
yes={<AddNewAppForm formConfig={formConfig} />}
|
||||||
|
no={
|
||||||
|
<Result
|
||||||
|
status="403"
|
||||||
|
title="You don't have permission to add new apps."
|
||||||
|
subTitle="Please contact system administrator"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -44,6 +44,8 @@ import pSBC from 'shade-blend-color';
|
|||||||
import { withConfigContext } from '../../../../../../../../../components/ConfigContext';
|
import { withConfigContext } from '../../../../../../../../../components/ConfigContext';
|
||||||
import ManagedConfigurationsIframe from './components/ManagedConfigurationsIframe';
|
import ManagedConfigurationsIframe from './components/ManagedConfigurationsIframe';
|
||||||
import { handleApiError } from '../../../../../../../../../services/utils/errorHandler';
|
import { handleApiError } from '../../../../../../../../../services/utils/errorHandler';
|
||||||
|
import Authorized from '../../../../../../../../../components/Authorized/Authorized';
|
||||||
|
import { isAuthorized } from '../../../../../../../../../services/utils/authorizationHandler';
|
||||||
|
|
||||||
const { Meta } = Card;
|
const { Meta } = Card;
|
||||||
const { Text, Title } = Typography;
|
const { Text, Title } = Typography;
|
||||||
@ -100,7 +102,15 @@ class AppDetailsDrawer extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.getCategories();
|
if (
|
||||||
|
isAuthorized(
|
||||||
|
this.props.context.user,
|
||||||
|
'/permission/admin/app-mgt/publisher/application/update',
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
this.getCategories();
|
||||||
|
this.getTags();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps, prevState, snapshot) {
|
componentDidUpdate(prevProps, prevState, snapshot) {
|
||||||
@ -130,7 +140,6 @@ class AppDetailsDrawer extends React.Component {
|
|||||||
.then(res => {
|
.then(res => {
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
const categories = JSON.parse(res.data.data);
|
const categories = JSON.parse(res.data.data);
|
||||||
this.getTags();
|
|
||||||
const globalCategories = categories.map(category => {
|
const globalCategories = categories.map(category => {
|
||||||
return (
|
return (
|
||||||
<Option key={category.categoryName}>
|
<Option key={category.categoryName}>
|
||||||
@ -520,36 +529,48 @@ class AppDetailsDrawer extends React.Component {
|
|||||||
<Spin spinning={loading} delay={500}>
|
<Spin spinning={loading} delay={500}>
|
||||||
<div style={{ textAlign: 'center' }}>
|
<div style={{ textAlign: 'center' }}>
|
||||||
{avatar}
|
{avatar}
|
||||||
<Title editable={{ onChange: this.handleNameSave }} level={2}>
|
<Authorized
|
||||||
{name}
|
permission="/permission/admin/app-mgt/publisher/application/update"
|
||||||
</Title>
|
yes={
|
||||||
|
<Title editable={{ onChange: this.handleNameSave }} level={2}>
|
||||||
|
{name}
|
||||||
|
</Title>
|
||||||
|
}
|
||||||
|
no={<Title level={2}>{name}</Title>}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Divider />
|
<Divider />
|
||||||
{/* display manage config button only if the app is public android app*/}
|
{/* display manage config button only if the app is public android app*/}
|
||||||
{app.isAndroidEnterpriseApp &&
|
{app.isAndroidEnterpriseApp &&
|
||||||
config.androidEnterpriseToken !== null && (
|
config.androidEnterpriseToken !== null && (
|
||||||
<div>
|
<Authorized
|
||||||
<div>
|
permission="/permission/admin/device-mgt/enterprise/user/modify"
|
||||||
<Text strong={true}>Set up managed configurations</Text>
|
yes={
|
||||||
</div>
|
<div>
|
||||||
<div style={{ paddingTop: 16 }}>
|
<div>
|
||||||
<Text>
|
<Text strong={true}>Set up managed configurations</Text>
|
||||||
If you are developing apps for the enterprise market, you
|
</div>
|
||||||
may need to satisfy particular requirements set by a
|
<div style={{ paddingTop: 16 }}>
|
||||||
organization's policies. Managed configurations,
|
<Text>
|
||||||
previously known as application restrictions, allow the
|
If you are developing apps for the enterprise market,
|
||||||
organization's IT admin to remotely specify settings
|
you may need to satisfy particular requirements set by
|
||||||
for apps. This capability is particularly useful for
|
a organization's policies. Managed
|
||||||
organization-approved apps deployed to a work profile.
|
configurations, previously known as application
|
||||||
</Text>
|
restrictions, allow the organization's IT admin
|
||||||
</div>
|
to remotely specify settings for apps. This capability
|
||||||
<br />
|
is particularly useful for organization-approved apps
|
||||||
<ManagedConfigurationsIframe
|
deployed to a work profile.
|
||||||
style={{ paddingTop: 16 }}
|
</Text>
|
||||||
packageName={app.packageName}
|
</div>
|
||||||
/>
|
<br />
|
||||||
<Divider dashed={true} />
|
<ManagedConfigurationsIframe
|
||||||
</div>
|
style={{ paddingTop: 16 }}
|
||||||
|
packageName={app.packageName}
|
||||||
|
/>
|
||||||
|
<Divider dashed={true} />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
<Text strong={true}>Releases </Text>
|
<Text strong={true}>Releases </Text>
|
||||||
<div className="releases-details">
|
<div className="releases-details">
|
||||||
@ -640,34 +661,44 @@ class AppDetailsDrawer extends React.Component {
|
|||||||
|
|
||||||
{/* display add new release only if app type is enterprise*/}
|
{/* display add new release only if app type is enterprise*/}
|
||||||
{app.type === 'ENTERPRISE' && (
|
{app.type === 'ENTERPRISE' && (
|
||||||
<div>
|
<Authorized
|
||||||
<Divider dashed={true} />
|
permission="/permission/admin/app-mgt/publisher/application/update"
|
||||||
<div style={{ paddingBottom: 16 }}>
|
yes={
|
||||||
<Text>Add new release for the application</Text>
|
<div>
|
||||||
</div>
|
<Divider dashed={true} />
|
||||||
<Link
|
<div style={{ paddingBottom: 16 }}>
|
||||||
to={`/publisher/apps/${app.deviceType}/${app.id}/add-release`}
|
<Text>Add new release for the application</Text>
|
||||||
>
|
</div>
|
||||||
<Button htmlType="button" type="primary" size="small">
|
<Link
|
||||||
Add
|
to={`/publisher/apps/${app.deviceType}/${app.id}/add-release`}
|
||||||
</Button>
|
>
|
||||||
</Link>
|
<Button htmlType="button" type="primary" size="small">
|
||||||
</div>
|
Add
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
<Divider dashed={true} />
|
<Divider dashed={true} />
|
||||||
|
|
||||||
<Text strong={true}>Description </Text>
|
<Text strong={true}>Description </Text>
|
||||||
{!isDescriptionEditEnabled && (
|
<Authorized
|
||||||
<Text
|
permission="/permission/admin/app-mgt/publisher/application/update"
|
||||||
style={{
|
yes={
|
||||||
color: config.theme.primaryColor,
|
!isDescriptionEditEnabled && (
|
||||||
cursor: 'pointer',
|
<Text
|
||||||
}}
|
style={{
|
||||||
onClick={this.enableDescriptionEdit}
|
color: config.theme.primaryColor,
|
||||||
>
|
cursor: 'pointer',
|
||||||
<Icon type="edit" />
|
}}
|
||||||
</Text>
|
onClick={this.enableDescriptionEdit}
|
||||||
)}
|
>
|
||||||
|
<Icon type="edit" />
|
||||||
|
</Text>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
{!isDescriptionEditEnabled && (
|
{!isDescriptionEditEnabled && (
|
||||||
<div>{ReactHtmlParser(description)}</div>
|
<div>{ReactHtmlParser(description)}</div>
|
||||||
@ -708,14 +739,22 @@ class AppDetailsDrawer extends React.Component {
|
|||||||
|
|
||||||
<Divider dashed={true} />
|
<Divider dashed={true} />
|
||||||
<Text strong={true}>Categories </Text>
|
<Text strong={true}>Categories </Text>
|
||||||
{!isCategoriesEditEnabled && (
|
<Authorized
|
||||||
<Text
|
permission="/permission/admin/app-mgt/publisher/application/update"
|
||||||
style={{ color: config.theme.primaryColor, cursor: 'pointer' }}
|
yes={
|
||||||
onClick={this.enableCategoriesEdit}
|
!isCategoriesEditEnabled && (
|
||||||
>
|
<Text
|
||||||
<Icon type="edit" />
|
style={{
|
||||||
</Text>
|
color: config.theme.primaryColor,
|
||||||
)}
|
cursor: 'pointer',
|
||||||
|
}}
|
||||||
|
onClick={this.enableCategoriesEdit}
|
||||||
|
>
|
||||||
|
<Icon type="edit" />
|
||||||
|
</Text>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
{isCategoriesEditEnabled && (
|
{isCategoriesEditEnabled && (
|
||||||
@ -767,14 +806,22 @@ class AppDetailsDrawer extends React.Component {
|
|||||||
|
|
||||||
<Divider dashed={true} />
|
<Divider dashed={true} />
|
||||||
<Text strong={true}>Tags </Text>
|
<Text strong={true}>Tags </Text>
|
||||||
{!isTagsEditEnabled && (
|
<Authorized
|
||||||
<Text
|
permission="/permission/admin/app-mgt/publisher/application/update"
|
||||||
style={{ color: config.theme.primaryColor, cursor: 'pointer' }}
|
yes={
|
||||||
onClick={this.enableTagsEdit}
|
!isTagsEditEnabled && (
|
||||||
>
|
<Text
|
||||||
<Icon type="edit" />
|
style={{
|
||||||
</Text>
|
color: config.theme.primaryColor,
|
||||||
)}
|
cursor: 'pointer',
|
||||||
|
}}
|
||||||
|
onClick={this.enableTagsEdit}
|
||||||
|
>
|
||||||
|
<Icon type="edit" />
|
||||||
|
</Text>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
{isTagsEditEnabled && (
|
{isTagsEditEnabled && (
|
||||||
@ -819,17 +866,22 @@ class AppDetailsDrawer extends React.Component {
|
|||||||
})}
|
})}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
|
<Authorized
|
||||||
<Divider dashed={true} />
|
permission="/permission/admin/app-mgt/publisher/review/view"
|
||||||
|
yes={
|
||||||
<div className="app-rate">
|
<div>
|
||||||
{app.applicationReleases.length > 0 && (
|
<Divider dashed={true} />
|
||||||
<DetailedRating
|
<div className="app-rate">
|
||||||
type="app"
|
{app.applicationReleases.length > 0 && (
|
||||||
uuid={app.applicationReleases[0].uuid}
|
<DetailedRating
|
||||||
/>
|
type="app"
|
||||||
)}
|
uuid={app.applicationReleases[0].uuid}
|
||||||
</div>
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
/>
|
||||||
</Spin>
|
</Spin>
|
||||||
</Drawer>
|
</Drawer>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -26,11 +26,11 @@ import {
|
|||||||
Select,
|
Select,
|
||||||
Button,
|
Button,
|
||||||
Form,
|
Form,
|
||||||
Alert,
|
|
||||||
} from 'antd';
|
} from 'antd';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { withConfigContext } from '../../../../../../../../components/ConfigContext';
|
import { withConfigContext } from '../../../../../../../../components/ConfigContext';
|
||||||
import { handleApiError } from '../../../../../../../../services/utils/errorHandler';
|
import { handleApiError } from '../../../../../../../../services/utils/errorHandler';
|
||||||
|
import Authorized from '../../../../../../../../components/Authorized/Authorized';
|
||||||
|
|
||||||
const { Option } = Select;
|
const { Option } = Select;
|
||||||
const { Title } = Typography;
|
const { Title } = Typography;
|
||||||
@ -42,11 +42,6 @@ class FiltersForm extends React.Component {
|
|||||||
categories: [],
|
categories: [],
|
||||||
tags: [],
|
tags: [],
|
||||||
deviceTypes: [],
|
deviceTypes: [],
|
||||||
forbiddenErrors: {
|
|
||||||
categories: false,
|
|
||||||
tags: false,
|
|
||||||
deviceTypes: false,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,18 +96,9 @@ class FiltersForm extends React.Component {
|
|||||||
'Error occurred while trying to load categories.',
|
'Error occurred while trying to load categories.',
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
if (error.hasOwnProperty('response') && error.response.status === 403) {
|
this.setState({
|
||||||
const { forbiddenErrors } = this.state;
|
loading: false,
|
||||||
forbiddenErrors.categories = true;
|
});
|
||||||
this.setState({
|
|
||||||
forbiddenErrors,
|
|
||||||
loading: false,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.setState({
|
|
||||||
loading: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -140,18 +126,9 @@ class FiltersForm extends React.Component {
|
|||||||
'Error occurred while trying to load tags.',
|
'Error occurred while trying to load tags.',
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
if (error.hasOwnProperty('response') && error.response.status === 403) {
|
this.setState({
|
||||||
const { forbiddenErrors } = this.state;
|
loading: false,
|
||||||
forbiddenErrors.tags = true;
|
});
|
||||||
this.setState({
|
|
||||||
forbiddenErrors,
|
|
||||||
loading: false,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.setState({
|
|
||||||
loading: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -179,23 +156,14 @@ class FiltersForm extends React.Component {
|
|||||||
'Error occurred while trying to load device types.',
|
'Error occurred while trying to load device types.',
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
if (error.hasOwnProperty('response') && error.response.status === 403) {
|
this.setState({
|
||||||
const { forbiddenErrors } = this.state;
|
loading: false,
|
||||||
forbiddenErrors.deviceTypes = true;
|
});
|
||||||
this.setState({
|
|
||||||
forbiddenErrors,
|
|
||||||
loading: false,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.setState({
|
|
||||||
loading: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { categories, tags, deviceTypes, forbiddenErrors } = this.state;
|
const { categories, tags, deviceTypes } = this.state;
|
||||||
const { getFieldDecorator } = this.props.form;
|
const { getFieldDecorator } = this.props.form;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -224,99 +192,85 @@ class FiltersForm extends React.Component {
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
{forbiddenErrors.categories && (
|
<Authorized
|
||||||
<Alert
|
permission="/permission/admin/app-mgt/publisher/application/update"
|
||||||
message="You don't have permission to view categories."
|
yes={
|
||||||
type="warning"
|
<div>
|
||||||
banner
|
<Form.Item label="Categories">
|
||||||
closable
|
{getFieldDecorator('categories', {
|
||||||
/>
|
rules: [
|
||||||
)}
|
{
|
||||||
<Form.Item label="Categories">
|
required: false,
|
||||||
{getFieldDecorator('categories', {
|
message: 'Please select categories',
|
||||||
rules: [
|
},
|
||||||
{
|
],
|
||||||
required: false,
|
})(
|
||||||
message: 'Please select categories',
|
<Select
|
||||||
},
|
mode="multiple"
|
||||||
],
|
style={{ width: '100%' }}
|
||||||
})(
|
placeholder="Select a Category"
|
||||||
<Select
|
onChange={this.handleCategoryChange}
|
||||||
mode="multiple"
|
>
|
||||||
style={{ width: '100%' }}
|
{categories.map(category => {
|
||||||
placeholder="Select a Category"
|
return (
|
||||||
onChange={this.handleCategoryChange}
|
<Option key={category.categoryName}>
|
||||||
>
|
{category.categoryName}
|
||||||
{categories.map(category => {
|
</Option>
|
||||||
return (
|
);
|
||||||
<Option key={category.categoryName}>
|
})}
|
||||||
{category.categoryName}
|
</Select>,
|
||||||
</Option>
|
)}
|
||||||
);
|
</Form.Item>
|
||||||
})}
|
<Form.Item label="Tags">
|
||||||
</Select>,
|
{getFieldDecorator('tags', {
|
||||||
)}
|
rules: [
|
||||||
</Form.Item>
|
{
|
||||||
|
required: false,
|
||||||
{forbiddenErrors.deviceTypes && (
|
message: 'Please select tags',
|
||||||
<Alert
|
},
|
||||||
message="You don't have permission to view device types."
|
],
|
||||||
type="warning"
|
})(
|
||||||
banner
|
<Select
|
||||||
closable
|
mode="multiple"
|
||||||
/>
|
style={{ width: '100%' }}
|
||||||
)}
|
placeholder="Select tags"
|
||||||
<Form.Item label="Device Type">
|
>
|
||||||
{getFieldDecorator('deviceType', {
|
{tags.map(tag => {
|
||||||
rules: [
|
return <Option key={tag.tagName}>{tag.tagName}</Option>;
|
||||||
{
|
})}
|
||||||
required: false,
|
</Select>,
|
||||||
message: 'Please select device types',
|
)}
|
||||||
},
|
</Form.Item>
|
||||||
],
|
</div>
|
||||||
})(
|
}
|
||||||
<Select
|
/>
|
||||||
style={{ width: '100%' }}
|
<Authorized
|
||||||
placeholder="Select device types"
|
permission="/permission/admin/device-mgt/admin/device-type/view"
|
||||||
>
|
yes={
|
||||||
{deviceTypes.map(deviceType => {
|
<Form.Item label="Device Type">
|
||||||
return (
|
{getFieldDecorator('deviceType', {
|
||||||
<Option key={deviceType.name}>{deviceType.name}</Option>
|
rules: [
|
||||||
);
|
{
|
||||||
})}
|
required: false,
|
||||||
<Option key="ALL">All</Option>
|
message: 'Please select device types',
|
||||||
</Select>,
|
},
|
||||||
)}
|
],
|
||||||
</Form.Item>
|
})(
|
||||||
{forbiddenErrors.tags && (
|
<Select
|
||||||
<Alert
|
style={{ width: '100%' }}
|
||||||
message="You don't have permission to view tags."
|
placeholder="Select device types"
|
||||||
type="warning"
|
>
|
||||||
banner
|
{deviceTypes.map(deviceType => {
|
||||||
closable
|
return (
|
||||||
/>
|
<Option key={deviceType.name}>{deviceType.name}</Option>
|
||||||
)}
|
);
|
||||||
<Form.Item label="Tags">
|
})}
|
||||||
{getFieldDecorator('tags', {
|
<Option key="ALL">All</Option>
|
||||||
rules: [
|
</Select>,
|
||||||
{
|
)}
|
||||||
required: false,
|
</Form.Item>
|
||||||
message: 'Please select tags',
|
}
|
||||||
},
|
/>
|
||||||
],
|
|
||||||
})(
|
|
||||||
<Select
|
|
||||||
mode="multiple"
|
|
||||||
style={{ width: '100%' }}
|
|
||||||
placeholder="Select tags"
|
|
||||||
>
|
|
||||||
{tags.map(tag => {
|
|
||||||
return <Option key={tag.tagName}>{tag.tagName}</Option>;
|
|
||||||
})}
|
|
||||||
</Select>,
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Form.Item label="App Type">
|
<Form.Item label="App Type">
|
||||||
{getFieldDecorator('appType', {})(
|
{getFieldDecorator('appType', {})(
|
||||||
<Select style={{ width: '100%' }} placeholder="Select app type">
|
<Select style={{ width: '100%' }} placeholder="Select app type">
|
||||||
|
|||||||
@ -18,6 +18,8 @@
|
|||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import AppList from './components/AppList';
|
import AppList from './components/AppList';
|
||||||
|
import Authorized from '../../../../components/Authorized/Authorized';
|
||||||
|
import { Result } from 'antd';
|
||||||
|
|
||||||
class Apps extends React.Component {
|
class Apps extends React.Component {
|
||||||
routes;
|
routes;
|
||||||
@ -30,7 +32,17 @@ class Apps extends React.Component {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div style={{ background: '#f0f2f5', padding: 24, minHeight: 780 }}>
|
<div style={{ background: '#f0f2f5', padding: 24, minHeight: 780 }}>
|
||||||
<AppList />
|
<Authorized
|
||||||
|
permission="/permission/admin/app-mgt/publisher/application/view"
|
||||||
|
yes={<AppList />}
|
||||||
|
no={
|
||||||
|
<Result
|
||||||
|
status="403"
|
||||||
|
title="You don't have permission to view apps."
|
||||||
|
subTitle="Please contact system administrator"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -36,6 +36,7 @@ import {
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import '@babel/polyfill';
|
import '@babel/polyfill';
|
||||||
import { withConfigContext } from '../../../../../../../../../../components/ConfigContext';
|
import { withConfigContext } from '../../../../../../../../../../components/ConfigContext';
|
||||||
|
import Authorized from '../../../../../../../../../../components/Authorized/Authorized';
|
||||||
|
|
||||||
const { TextArea } = Input;
|
const { TextArea } = Input;
|
||||||
const InputGroup = Input.Group;
|
const InputGroup = Input.Group;
|
||||||
@ -549,14 +550,16 @@ class EditReleaseModal extends React.Component {
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
{config.deviceTypes.mobileTypes.includes(deviceType) && (
|
{config.deviceTypes.mobileTypes.includes(deviceType) && (
|
||||||
<div>
|
<div>
|
||||||
{this.props.forbiddenErrors.supportedOsVersions && (
|
<Authorized
|
||||||
<Alert
|
permission="/permission/admin/device-mgt/admin/device-type"
|
||||||
message="You don't have permission to view supported OS versions."
|
no={
|
||||||
type="warning"
|
<Alert
|
||||||
banner
|
message="You don't have permission to view supported OS versions."
|
||||||
closable
|
type="warning"
|
||||||
/>
|
banner
|
||||||
)}
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
{...formItemLayout}
|
{...formItemLayout}
|
||||||
label="Supported OS Versions"
|
label="Supported OS Versions"
|
||||||
|
|||||||
@ -17,7 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { List, Spin, Button, Alert } from 'antd';
|
import { List, Spin, Button } from 'antd';
|
||||||
import './styles.css';
|
import './styles.css';
|
||||||
|
|
||||||
import InfiniteScroll from 'react-infinite-scroller';
|
import InfiniteScroll from 'react-infinite-scroller';
|
||||||
@ -130,14 +130,6 @@ class Reviews extends React.Component {
|
|||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{this.state.forbiddenErrors.reviews && (
|
|
||||||
<Alert
|
|
||||||
message="You don't have permission to view reviews."
|
|
||||||
type="warning"
|
|
||||||
banner
|
|
||||||
closable
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<div className="demo-infinite-container">
|
<div className="demo-infinite-container">
|
||||||
<InfiniteScroll
|
<InfiniteScroll
|
||||||
initialLoad={false}
|
initialLoad={false}
|
||||||
|
|||||||
@ -17,13 +17,23 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Divider, Row, Col, Typography, Button, Icon, Tooltip } from 'antd';
|
import {
|
||||||
|
Divider,
|
||||||
|
Row,
|
||||||
|
Col,
|
||||||
|
Typography,
|
||||||
|
Button,
|
||||||
|
Icon,
|
||||||
|
Tooltip,
|
||||||
|
Alert,
|
||||||
|
} from 'antd';
|
||||||
import StarRatings from 'react-star-ratings';
|
import StarRatings from 'react-star-ratings';
|
||||||
import Reviews from './components/Reviews';
|
import Reviews from './components/Reviews';
|
||||||
import '../../../../../../../../App.css';
|
import '../../../../../../../../App.css';
|
||||||
import DetailedRating from '../../../../components/DetailedRating';
|
import DetailedRating from '../../../../components/DetailedRating';
|
||||||
import EditRelease from './components/EditRelease';
|
import EditRelease from './components/EditRelease';
|
||||||
import { withConfigContext } from '../../../../../../../../components/ConfigContext';
|
import { withConfigContext } from '../../../../../../../../components/ConfigContext';
|
||||||
|
import Authorized from '../../../../../../../../components/Authorized/Authorized';
|
||||||
|
|
||||||
const { Title, Text, Paragraph } = Typography;
|
const { Title, Text, Paragraph } = Typography;
|
||||||
|
|
||||||
@ -33,22 +43,19 @@ class ReleaseView extends React.Component {
|
|||||||
this.state = {};
|
this.state = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
console.log('mounted: Release view');
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { app, release } = this.props;
|
const { app, release } = this.props;
|
||||||
const config = this.props.context;
|
const config = this.props.context;
|
||||||
const { lifecycle, currentLifecycleStatus } = this.props;
|
const { lifecycle, currentLifecycleStatus } = this.props;
|
||||||
|
if (release == null) {
|
||||||
if (release == null || lifecycle == null) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
let isAppUpdatable,
|
||||||
const { isAppUpdatable, isAppInstallable } = lifecycle[
|
isAppInstallable = false;
|
||||||
currentLifecycleStatus
|
if (lifecycle != null) {
|
||||||
];
|
isAppUpdatable = lifecycle[currentLifecycleStatus].isAppUpdatable;
|
||||||
|
isAppInstallable = lifecycle[currentLifecycleStatus].isAppInstallable;
|
||||||
|
}
|
||||||
|
|
||||||
const platform = app.deviceType;
|
const platform = app.deviceType;
|
||||||
const defaultPlatformIcons = config.defaultPlatformIcons;
|
const defaultPlatformIcons = config.defaultPlatformIcons;
|
||||||
@ -93,45 +100,53 @@ class ReleaseView extends React.Component {
|
|||||||
<Divider type="vertical" />
|
<Divider type="vertical" />
|
||||||
<Text>Version : {release.version}</Text>
|
<Text>Version : {release.version}</Text>
|
||||||
<br />
|
<br />
|
||||||
|
<Authorized
|
||||||
<EditRelease
|
permission="/permission/admin/app-mgt/publisher/application/update"
|
||||||
forbiddenErrors={this.props.forbiddenErrors}
|
yes={
|
||||||
isAppUpdatable={isAppUpdatable}
|
<EditRelease
|
||||||
type={app.type}
|
isAppUpdatable={isAppUpdatable}
|
||||||
deviceType={app.deviceType}
|
type={app.type}
|
||||||
release={release}
|
deviceType={app.deviceType}
|
||||||
updateRelease={this.props.updateRelease}
|
release={release}
|
||||||
supportedOsVersions={[...this.props.supportedOsVersions]}
|
updateRelease={this.props.updateRelease}
|
||||||
|
supportedOsVersions={[...this.props.supportedOsVersions]}
|
||||||
|
/>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
<Col xl={8} md={10} sm={24} xs={24} style={{ float: 'right' }}>
|
<Col xl={8} md={10} sm={24} xs={24} style={{ float: 'right' }}>
|
||||||
<div>
|
<div>
|
||||||
<Tooltip
|
<Authorized
|
||||||
title={
|
permission="/permission/admin/app-mgt/publisher/application/update"
|
||||||
isAppInstallable
|
yes={
|
||||||
? 'Open this app in store'
|
<Tooltip
|
||||||
: "This release isn't in an installable state"
|
title={
|
||||||
|
isAppInstallable
|
||||||
|
? 'Open this app in store'
|
||||||
|
: "This release isn't in an installable state"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
style={{ float: 'right' }}
|
||||||
|
htmlType="button"
|
||||||
|
type="primary"
|
||||||
|
icon="shop"
|
||||||
|
disabled={!isAppInstallable}
|
||||||
|
onClick={() => {
|
||||||
|
window.open(
|
||||||
|
window.location.origin +
|
||||||
|
'/store/' +
|
||||||
|
app.deviceType +
|
||||||
|
'/apps/' +
|
||||||
|
release.uuid,
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Open in store
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
}
|
}
|
||||||
>
|
/>
|
||||||
<Button
|
|
||||||
style={{ float: 'right' }}
|
|
||||||
htmlType="button"
|
|
||||||
type="primary"
|
|
||||||
icon="shop"
|
|
||||||
disabled={!isAppInstallable}
|
|
||||||
onClick={() => {
|
|
||||||
window.open(
|
|
||||||
window.location.origin +
|
|
||||||
'/store/' +
|
|
||||||
app.deviceType +
|
|
||||||
'/apps/' +
|
|
||||||
release.uuid,
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Open in store
|
|
||||||
</Button>
|
|
||||||
</Tooltip>
|
|
||||||
</div>
|
</div>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
@ -173,12 +188,27 @@ class ReleaseView extends React.Component {
|
|||||||
</Row>
|
</Row>
|
||||||
<Divider />
|
<Divider />
|
||||||
<Text>REVIEWS</Text>
|
<Text>REVIEWS</Text>
|
||||||
<Row>
|
<Authorized
|
||||||
<Col lg={18}>
|
permission="/permission/admin/app-mgt/publisher/admin/review/view"
|
||||||
<DetailedRating type="release" uuid={release.uuid} />
|
yes={
|
||||||
</Col>
|
<div>
|
||||||
</Row>
|
<Row>
|
||||||
<Reviews type="release" uuid={release.uuid} />
|
<Col lg={18}>
|
||||||
|
<DetailedRating type="release" uuid={release.uuid} />
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Reviews type="release" uuid={release.uuid} />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
no={
|
||||||
|
<Alert
|
||||||
|
message="You don't have permission to view reviews."
|
||||||
|
type="warning"
|
||||||
|
banner
|
||||||
|
closable
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -24,6 +24,8 @@ import ReleaseView from './components/ReleaseView';
|
|||||||
import LifeCycle from './components/LifeCycle';
|
import LifeCycle from './components/LifeCycle';
|
||||||
import { withConfigContext } from '../../../../../../components/ConfigContext';
|
import { withConfigContext } from '../../../../../../components/ConfigContext';
|
||||||
import { handleApiError } from '../../../../../../services/utils/errorHandler';
|
import { handleApiError } from '../../../../../../services/utils/errorHandler';
|
||||||
|
import Authorized from '../../../../../../components/Authorized/Authorized';
|
||||||
|
import { isAuthorized } from '../../../../../../services/utils/authorizationHandler';
|
||||||
|
|
||||||
const { Title } = Typography;
|
const { Title } = Typography;
|
||||||
|
|
||||||
@ -41,17 +43,20 @@ class Release extends React.Component {
|
|||||||
currentLifecycleStatus: null,
|
currentLifecycleStatus: null,
|
||||||
lifecycle: null,
|
lifecycle: null,
|
||||||
supportedOsVersions: [],
|
supportedOsVersions: [],
|
||||||
forbiddenErrors: {
|
|
||||||
supportedOsVersions: false,
|
|
||||||
lifeCycle: false,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const { uuid } = this.props.match.params;
|
const { uuid } = this.props.match.params;
|
||||||
this.fetchData(uuid);
|
this.fetchData(uuid);
|
||||||
this.getLifecycle();
|
if (
|
||||||
|
isAuthorized(
|
||||||
|
this.props.context.user,
|
||||||
|
'/permission/admin/app-mgt/publisher/application/update',
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
this.getLifecycle();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
changeCurrentLifecycleStatus = status => {
|
changeCurrentLifecycleStatus = status => {
|
||||||
@ -92,7 +97,16 @@ class Release extends React.Component {
|
|||||||
uuid: uuid,
|
uuid: uuid,
|
||||||
});
|
});
|
||||||
if (config.deviceTypes.mobileTypes.includes(app.deviceType)) {
|
if (config.deviceTypes.mobileTypes.includes(app.deviceType)) {
|
||||||
this.getSupportedOsVersions(app.deviceType);
|
if (
|
||||||
|
isAuthorized(
|
||||||
|
config.user,
|
||||||
|
'/permission/admin/device-mgt/admin/device-type',
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
this.getSupportedOsVersions(app.deviceType);
|
||||||
|
} else {
|
||||||
|
this.setState({ loading: false });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -128,13 +142,6 @@ class Release extends React.Component {
|
|||||||
'Error occurred while trying to load lifecycle configuration.',
|
'Error occurred while trying to load lifecycle configuration.',
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
if (error.hasOwnProperty('response') && error.response.status === 403) {
|
|
||||||
const { forbiddenErrors } = this.state;
|
|
||||||
forbiddenErrors.lifeCycle = true;
|
|
||||||
this.setState({
|
|
||||||
forbiddenErrors,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -161,18 +168,9 @@ class Release extends React.Component {
|
|||||||
'Error occurred while trying to load supported OS versions.',
|
'Error occurred while trying to load supported OS versions.',
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
if (error.hasOwnProperty('response') && error.response.status === 403) {
|
this.setState({
|
||||||
const { forbiddenErrors } = this.state;
|
loading: false,
|
||||||
forbiddenErrors.supportedOsVersions = true;
|
});
|
||||||
this.setState({
|
|
||||||
forbiddenErrors,
|
|
||||||
loading: false,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.setState({
|
|
||||||
loading: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -193,7 +191,6 @@ class Release extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo remove uppercase
|
// todo remove uppercase
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -221,22 +218,27 @@ class Release extends React.Component {
|
|||||||
</Skeleton>
|
</Skeleton>
|
||||||
</Card>
|
</Card>
|
||||||
</Col>
|
</Col>
|
||||||
<Col lg={8} md={24} style={{ padding: 3 }}>
|
<Authorized
|
||||||
<Card lg={8} md={24}>
|
permission="/permission/admin/app-mgt/publisher/application/update"
|
||||||
<Skeleton loading={loading} active paragraph={{ rows: 8 }}>
|
yes={
|
||||||
{release !== null && (
|
<Col lg={8} md={24} style={{ padding: 3 }}>
|
||||||
<LifeCycle
|
<Card lg={8} md={24}>
|
||||||
uuid={release.uuid}
|
<Skeleton loading={loading} active paragraph={{ rows: 8 }}>
|
||||||
currentStatus={release.currentStatus.toUpperCase()}
|
{release !== null && (
|
||||||
changeCurrentLifecycleStatus={
|
<LifeCycle
|
||||||
this.changeCurrentLifecycleStatus
|
uuid={release.uuid}
|
||||||
}
|
currentStatus={release.currentStatus.toUpperCase()}
|
||||||
lifecycle={lifecycle}
|
changeCurrentLifecycleStatus={
|
||||||
/>
|
this.changeCurrentLifecycleStatus
|
||||||
)}
|
}
|
||||||
</Skeleton>
|
lifecycle={lifecycle}
|
||||||
</Card>
|
/>
|
||||||
</Col>
|
)}
|
||||||
|
</Skeleton>
|
||||||
|
</Card>
|
||||||
|
</Col>
|
||||||
|
}
|
||||||
|
/>
|
||||||
</Row>
|
</Row>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -40,6 +40,7 @@ import { TweenOneGroup } from 'rc-tween-one';
|
|||||||
import pSBC from 'shade-blend-color';
|
import pSBC from 'shade-blend-color';
|
||||||
import { withConfigContext } from '../../../../../../components/ConfigContext';
|
import { withConfigContext } from '../../../../../../components/ConfigContext';
|
||||||
import { handleApiError } from '../../../../../../services/utils/errorHandler';
|
import { handleApiError } from '../../../../../../services/utils/errorHandler';
|
||||||
|
import { isAuthorized } from '../../../../../../services/utils/authorizationHandler';
|
||||||
|
|
||||||
const { Title } = Typography;
|
const { Title } = Typography;
|
||||||
|
|
||||||
@ -62,6 +63,10 @@ class ManageCategories extends React.Component {
|
|||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const config = this.props.context;
|
const config = this.props.context;
|
||||||
|
this.hasPermissionToManage = isAuthorized(
|
||||||
|
config.user,
|
||||||
|
'/permission/admin/app-mgt/publisher/admin/application/update',
|
||||||
|
);
|
||||||
axios
|
axios
|
||||||
.get(
|
.get(
|
||||||
window.location.origin +
|
window.location.origin +
|
||||||
@ -84,18 +89,9 @@ class ManageCategories extends React.Component {
|
|||||||
'Error occured while trying to load categories',
|
'Error occured while trying to load categories',
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
if (error.hasOwnProperty('response') && error.response.status === 403) {
|
this.setState({
|
||||||
const { forbiddenErrors } = this.state;
|
loading: false,
|
||||||
forbiddenErrors.categories = true;
|
});
|
||||||
this.setState({
|
|
||||||
forbiddenErrors,
|
|
||||||
loading: false,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.setState({
|
|
||||||
loading: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,36 +153,40 @@ class ManageCategories extends React.Component {
|
|||||||
style={{ marginTop: 8 }}
|
style={{ marginTop: 8 }}
|
||||||
>
|
>
|
||||||
{categoryName}
|
{categoryName}
|
||||||
<Divider type="vertical" />
|
{this.hasPermissionToManage && (
|
||||||
<Tooltip title="edit">
|
<>
|
||||||
<Icon
|
<Divider type="vertical" />
|
||||||
onClick={() => {
|
<Tooltip title="edit">
|
||||||
this.openEditModal(categoryName);
|
<Icon
|
||||||
}}
|
onClick={() => {
|
||||||
type="edit"
|
this.openEditModal(categoryName);
|
||||||
/>
|
}}
|
||||||
</Tooltip>
|
type="edit"
|
||||||
<Divider type="vertical" />
|
/>
|
||||||
<Tooltip title="delete">
|
</Tooltip>
|
||||||
<Popconfirm
|
<Divider type="vertical" />
|
||||||
title="Are you sure delete this category?"
|
<Tooltip title="delete">
|
||||||
onConfirm={() => {
|
<Popconfirm
|
||||||
if (category.isCategoryDeletable) {
|
title="Are you sure delete this category?"
|
||||||
this.deleteCategory(categoryName);
|
onConfirm={() => {
|
||||||
} else {
|
if (category.isCategoryDeletable) {
|
||||||
notification.error({
|
this.deleteCategory(categoryName);
|
||||||
message: 'Cannot delete "' + categoryName + '"',
|
} else {
|
||||||
description:
|
notification.error({
|
||||||
'This category is currently used. Please unassign the category from apps.',
|
message: 'Cannot delete "' + categoryName + '"',
|
||||||
});
|
description:
|
||||||
}
|
'This category is currently used. Please unassign the category from apps.',
|
||||||
}}
|
});
|
||||||
okText="Yes"
|
}
|
||||||
cancelText="No"
|
}}
|
||||||
>
|
okText="Yes"
|
||||||
<Icon type="delete" />
|
cancelText="No"
|
||||||
</Popconfirm>
|
>
|
||||||
</Tooltip>
|
<Icon type="delete" />
|
||||||
|
</Popconfirm>
|
||||||
|
</Tooltip>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</Tag>
|
</Tag>
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
@ -377,18 +377,16 @@ class ManageCategories extends React.Component {
|
|||||||
inputValue,
|
inputValue,
|
||||||
tempElements,
|
tempElements,
|
||||||
isAddNewVisible,
|
isAddNewVisible,
|
||||||
forbiddenErrors,
|
|
||||||
} = this.state;
|
} = this.state;
|
||||||
const categoriesElements = categories.map(this.renderElement);
|
const categoriesElements = categories.map(this.renderElement);
|
||||||
const temporaryElements = tempElements.map(this.renderTempElement);
|
const temporaryElements = tempElements.map(this.renderTempElement);
|
||||||
return (
|
return (
|
||||||
<div style={{ marginBottom: 16 }}>
|
<div style={{ marginBottom: 16 }}>
|
||||||
{forbiddenErrors.categories && (
|
{!this.hasPermissionToManage && (
|
||||||
<Alert
|
<Alert
|
||||||
message="You don't have permission to view categories."
|
message="You don't have permission to add / edit / delete categories."
|
||||||
type="warning"
|
type="warning"
|
||||||
banner
|
banner
|
||||||
closable
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<Card>
|
<Card>
|
||||||
@ -414,6 +412,7 @@ class ManageCategories extends React.Component {
|
|||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
htmlType="button"
|
htmlType="button"
|
||||||
|
disabled={!this.hasPermissionToManage}
|
||||||
>
|
>
|
||||||
Add
|
Add
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@ -39,6 +39,7 @@ import axios from 'axios';
|
|||||||
import { TweenOneGroup } from 'rc-tween-one';
|
import { TweenOneGroup } from 'rc-tween-one';
|
||||||
import { withConfigContext } from '../../../../../../components/ConfigContext';
|
import { withConfigContext } from '../../../../../../components/ConfigContext';
|
||||||
import { handleApiError } from '../../../../../../services/utils/errorHandler';
|
import { handleApiError } from '../../../../../../services/utils/errorHandler';
|
||||||
|
import { isAuthorized } from '../../../../../../services/utils/authorizationHandler';
|
||||||
|
|
||||||
const { Title } = Typography;
|
const { Title } = Typography;
|
||||||
|
|
||||||
@ -61,6 +62,10 @@ class ManageTags extends React.Component {
|
|||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const config = this.props.context;
|
const config = this.props.context;
|
||||||
|
this.hasPermissionToManage = isAuthorized(
|
||||||
|
config.user,
|
||||||
|
'/permission/admin/app-mgt/publisher/admin/application/update',
|
||||||
|
);
|
||||||
axios
|
axios
|
||||||
.get(
|
.get(
|
||||||
window.location.origin +
|
window.location.origin +
|
||||||
@ -83,18 +88,9 @@ class ManageTags extends React.Component {
|
|||||||
'Error occurred while trying to load tags.',
|
'Error occurred while trying to load tags.',
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
if (error.hasOwnProperty('response') && error.response.status === 403) {
|
this.setState({
|
||||||
const { forbiddenErrors } = this.state;
|
loading: false,
|
||||||
forbiddenErrors.tags = true;
|
});
|
||||||
this.setState({
|
|
||||||
forbiddenErrors,
|
|
||||||
loading: false,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.setState({
|
|
||||||
loading: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,36 +147,40 @@ class ManageTags extends React.Component {
|
|||||||
const tagElem = (
|
const tagElem = (
|
||||||
<Tag color="#34495e" style={{ marginTop: 8 }}>
|
<Tag color="#34495e" style={{ marginTop: 8 }}>
|
||||||
{tagName}
|
{tagName}
|
||||||
<Divider type="vertical" />
|
{this.hasPermissionToManage && (
|
||||||
<Tooltip title="edit">
|
<>
|
||||||
<Icon
|
<Divider type="vertical" />
|
||||||
onClick={() => {
|
<Tooltip title="edit">
|
||||||
this.openEditModal(tagName);
|
<Icon
|
||||||
}}
|
onClick={() => {
|
||||||
type="edit"
|
this.openEditModal(tagName);
|
||||||
/>
|
}}
|
||||||
</Tooltip>
|
type="edit"
|
||||||
<Divider type="vertical" />
|
/>
|
||||||
<Tooltip title="delete">
|
</Tooltip>
|
||||||
<Popconfirm
|
<Divider type="vertical" />
|
||||||
title="Are you sure delete this tag?"
|
<Tooltip title="delete">
|
||||||
onConfirm={() => {
|
<Popconfirm
|
||||||
if (tag.isTagDeletable) {
|
title="Are you sure delete this tag?"
|
||||||
this.deleteTag(tagName);
|
onConfirm={() => {
|
||||||
} else {
|
if (tag.isTagDeletable) {
|
||||||
notification.error({
|
this.deleteTag(tagName);
|
||||||
message: 'Cannot delete "' + tagName + '"',
|
} else {
|
||||||
description:
|
notification.error({
|
||||||
'This tag is currently used. Please unassign the tag from apps.',
|
message: 'Cannot delete "' + tagName + '"',
|
||||||
});
|
description:
|
||||||
}
|
'This tag is currently used. Please unassign the tag from apps.',
|
||||||
}}
|
});
|
||||||
okText="Yes"
|
}
|
||||||
cancelText="No"
|
}}
|
||||||
>
|
okText="Yes"
|
||||||
<Icon type="delete" />
|
cancelText="No"
|
||||||
</Popconfirm>
|
>
|
||||||
</Tooltip>
|
<Icon type="delete" />
|
||||||
|
</Popconfirm>
|
||||||
|
</Tooltip>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</Tag>
|
</Tag>
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
@ -368,18 +368,16 @@ class ManageTags extends React.Component {
|
|||||||
inputValue,
|
inputValue,
|
||||||
tempElements,
|
tempElements,
|
||||||
isAddNewVisible,
|
isAddNewVisible,
|
||||||
forbiddenErrors,
|
|
||||||
} = this.state;
|
} = this.state;
|
||||||
const tagsElements = tags.map(this.renderElement);
|
const tagsElements = tags.map(this.renderElement);
|
||||||
const temporaryElements = tempElements.map(this.renderTempElement);
|
const temporaryElements = tempElements.map(this.renderTempElement);
|
||||||
return (
|
return (
|
||||||
<div style={{ marginBottom: 16 }}>
|
<div style={{ marginBottom: 16 }}>
|
||||||
{forbiddenErrors.tags && (
|
{!this.hasPermissionToManage && (
|
||||||
<Alert
|
<Alert
|
||||||
message="You don't have permission to view tags."
|
message="You don't have permission to add / edit / delete tags."
|
||||||
type="warning"
|
type="warning"
|
||||||
banner
|
banner
|
||||||
closable
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<Card>
|
<Card>
|
||||||
@ -405,6 +403,7 @@ class ManageTags extends React.Component {
|
|||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
htmlType="button"
|
htmlType="button"
|
||||||
|
disabled={!this.hasPermissionToManage}
|
||||||
>
|
>
|
||||||
Add
|
Add
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@ -21,6 +21,7 @@ import { PageHeader, Typography, Breadcrumb, Row, Col, Icon } from 'antd';
|
|||||||
import ManageCategories from './components/Categories';
|
import ManageCategories from './components/Categories';
|
||||||
import ManageTags from './components/Tags';
|
import ManageTags from './components/Tags';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
import Authorized from '../../../../components/Authorized/Authorized';
|
||||||
|
|
||||||
const { Paragraph } = Typography;
|
const { Paragraph } = Typography;
|
||||||
|
|
||||||
@ -54,12 +55,19 @@ class Manage extends React.Component {
|
|||||||
</PageHeader>
|
</PageHeader>
|
||||||
<div style={{ background: '#f0f2f5', padding: 24, minHeight: 780 }}>
|
<div style={{ background: '#f0f2f5', padding: 24, minHeight: 780 }}>
|
||||||
<Row gutter={16}>
|
<Row gutter={16}>
|
||||||
<Col sm={24} md={12}>
|
<Authorized
|
||||||
<ManageCategories />
|
permission="/permission/admin/app-mgt/publisher/application/update"
|
||||||
</Col>
|
yes={
|
||||||
<Col sm={24} md={12}>
|
<>
|
||||||
<ManageTags />
|
<Col sm={24} md={12}>
|
||||||
</Col>
|
<ManageCategories />
|
||||||
|
</Col>
|
||||||
|
<Col sm={24} md={12}>
|
||||||
|
<ManageTags />
|
||||||
|
</Col>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
/>
|
||||||
</Row>
|
</Row>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -34,6 +34,7 @@ import './styles.css';
|
|||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import AddNewPage from './components/AddNewPage';
|
import AddNewPage from './components/AddNewPage';
|
||||||
import { handleApiError } from '../../../../../../../../services/utils/errorHandler';
|
import { handleApiError } from '../../../../../../../../services/utils/errorHandler';
|
||||||
|
import { isAuthorized } from '../../../../../../../../services/utils/authorizationHandler';
|
||||||
|
|
||||||
const { Text, Title } = Typography;
|
const { Text, Title } = Typography;
|
||||||
|
|
||||||
@ -47,6 +48,10 @@ class Pages extends React.Component {
|
|||||||
selectedRows: [],
|
selectedRows: [],
|
||||||
homePageId: null,
|
homePageId: null,
|
||||||
};
|
};
|
||||||
|
this.hasPermissionToManage = isAuthorized(
|
||||||
|
this.props.config.user,
|
||||||
|
'/device-mgt/enterprise/user/view',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
rowSelection = {
|
rowSelection = {
|
||||||
@ -226,34 +231,38 @@ class Pages extends React.Component {
|
|||||||
key: 'actions',
|
key: 'actions',
|
||||||
render: (name, page) => (
|
render: (name, page) => (
|
||||||
<div>
|
<div>
|
||||||
<span className="action">
|
{this.hasPermissionToManage && (
|
||||||
<Button
|
<>
|
||||||
disabled={page.id === this.state.homePageId}
|
<span className="action">
|
||||||
className="btn-warning"
|
<Button
|
||||||
icon="home"
|
disabled={page.id === this.state.homePageId}
|
||||||
type="link"
|
className="btn-warning"
|
||||||
onClick={() => {
|
icon="home"
|
||||||
this.updateHomePage(page.id);
|
type="link"
|
||||||
}}
|
onClick={() => {
|
||||||
>
|
this.updateHomePage(page.id);
|
||||||
set as homepage
|
}}
|
||||||
</Button>
|
>
|
||||||
</span>
|
set as homepage
|
||||||
<Divider type="vertical" />
|
</Button>
|
||||||
<Popconfirm
|
</span>
|
||||||
title="Are you sure?"
|
<Divider type="vertical" />
|
||||||
okText="Yes"
|
<Popconfirm
|
||||||
cancelText="No"
|
title="Are you sure?"
|
||||||
onConfirm={() => {
|
okText="Yes"
|
||||||
this.deletePage(page.id);
|
cancelText="No"
|
||||||
}}
|
onConfirm={() => {
|
||||||
>
|
this.deletePage(page.id);
|
||||||
<span className="action">
|
}}
|
||||||
<Text type="danger">
|
>
|
||||||
<Icon type="delete" /> delete
|
<span className="action">
|
||||||
</Text>
|
<Text type="danger">
|
||||||
</span>
|
<Icon type="delete" /> delete
|
||||||
</Popconfirm>
|
</Text>
|
||||||
|
</span>
|
||||||
|
</Popconfirm>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|||||||
@ -17,12 +17,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { PageHeader, Breadcrumb, Divider, Icon } from 'antd';
|
import { PageHeader, Breadcrumb, Divider, Icon, Result } from 'antd';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import SyncAndroidApps from './components/SyncAndroidApps';
|
import SyncAndroidApps from './components/SyncAndroidApps';
|
||||||
import { withConfigContext } from '../../../../../../components/ConfigContext';
|
import { withConfigContext } from '../../../../../../components/ConfigContext';
|
||||||
import GooglePlayIframe from './components/GooglePlayIframe';
|
import GooglePlayIframe from './components/GooglePlayIframe';
|
||||||
import Pages from './components/Pages';
|
import Pages from './components/Pages';
|
||||||
|
import Authorized from '../../../../../../components/Authorized/Authorized';
|
||||||
|
|
||||||
class ManageAndroidEnterprise extends React.Component {
|
class ManageAndroidEnterprise extends React.Component {
|
||||||
routes;
|
routes;
|
||||||
@ -52,10 +53,27 @@ class ManageAndroidEnterprise extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
<div style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}>
|
<div style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}>
|
||||||
<SyncAndroidApps />
|
<Authorized
|
||||||
<GooglePlayIframe />
|
permission="/permission/admin/device-mgt/enterprise/user/view"
|
||||||
<Divider />
|
yes={
|
||||||
<Pages />
|
<>
|
||||||
|
<SyncAndroidApps />
|
||||||
|
<Authorized
|
||||||
|
permission="/permission/admin/device-mgt/enterprise/user/modify"
|
||||||
|
yes={<GooglePlayIframe />}
|
||||||
|
/>
|
||||||
|
<Divider />
|
||||||
|
<Pages />
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
no={
|
||||||
|
<Result
|
||||||
|
status="403"
|
||||||
|
title="You don't have permission to view android enterprise configurations."
|
||||||
|
subTitle="Please contact system administrator"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -295,44 +295,50 @@ class Cluster extends React.Component {
|
|||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div className="product">
|
<div className="product">
|
||||||
<div className="arrow">
|
{this.props.hasPermissionToManage && (
|
||||||
<button
|
<div className="arrow">
|
||||||
disabled={index === 0}
|
<button
|
||||||
className="btn"
|
disabled={index === 0}
|
||||||
onClick={() => {
|
className="btn"
|
||||||
this.swapProduct(index, index - 1);
|
onClick={() => {
|
||||||
}}
|
this.swapProduct(index, index - 1);
|
||||||
>
|
}}
|
||||||
<Icon type="caret-left" theme="filled" />
|
>
|
||||||
</button>
|
<Icon type="caret-left" theme="filled" />
|
||||||
</div>
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<div className="product-icon">
|
<div className="product-icon">
|
||||||
<img src={imageSrc} />
|
<img src={imageSrc} />
|
||||||
<Tooltip title={packageId}>
|
<Tooltip title={packageId}>
|
||||||
<div className="title">{packageId}</div>
|
<div className="title">{packageId}</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
<div className="arrow">
|
{this.props.hasPermissionToManage && (
|
||||||
<button
|
<>
|
||||||
disabled={index === products.length - 1}
|
<div className="arrow">
|
||||||
onClick={() => {
|
<button
|
||||||
this.swapProduct(index, index + 1);
|
disabled={index === products.length - 1}
|
||||||
}}
|
onClick={() => {
|
||||||
className="btn btn-right"
|
this.swapProduct(index, index + 1);
|
||||||
>
|
}}
|
||||||
<Icon type="caret-right" theme="filled" />
|
className="btn btn-right"
|
||||||
</button>
|
>
|
||||||
</div>
|
<Icon type="caret-right" theme="filled" />
|
||||||
<div className="delete-btn">
|
</button>
|
||||||
<button
|
</div>
|
||||||
className="btn"
|
<div className="delete-btn">
|
||||||
onClick={() => {
|
<button
|
||||||
this.removeProduct(index);
|
className="btn"
|
||||||
}}
|
onClick={() => {
|
||||||
>
|
this.removeProduct(index);
|
||||||
<Icon type="close-circle" theme="filled" />
|
}}
|
||||||
</button>
|
>
|
||||||
</div>
|
<Icon type="close-circle" theme="filled" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -347,7 +353,7 @@ class Cluster extends React.Component {
|
|||||||
</Title>
|
</Title>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={8}>
|
<Col span={8}>
|
||||||
{!isTemporary && (
|
{!isTemporary && this.props.hasPermissionToManage && (
|
||||||
<div style={{ float: 'right' }}>
|
<div style={{ float: 'right' }}>
|
||||||
<Tooltip title="Move Up">
|
<Tooltip title="Move Up">
|
||||||
<Button
|
<Button
|
||||||
@ -391,10 +397,12 @@ class Cluster extends React.Component {
|
|||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
<div className="products-row">
|
<div className="products-row">
|
||||||
<AddAppsToClusterModal
|
{this.props.hasPermissionToManage && (
|
||||||
addSelectedProducts={this.addSelectedProducts}
|
<AddAppsToClusterModal
|
||||||
unselectedProducts={unselectedProducts}
|
addSelectedProducts={this.addSelectedProducts}
|
||||||
/>
|
unselectedProducts={unselectedProducts}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{products.map((product, index) => {
|
{products.map((product, index) => {
|
||||||
return (
|
return (
|
||||||
<Product
|
<Product
|
||||||
|
|||||||
@ -30,6 +30,7 @@ import {
|
|||||||
Spin,
|
Spin,
|
||||||
Tag,
|
Tag,
|
||||||
Divider,
|
Divider,
|
||||||
|
Result,
|
||||||
} from 'antd';
|
} from 'antd';
|
||||||
import { Link, withRouter } from 'react-router-dom';
|
import { Link, withRouter } from 'react-router-dom';
|
||||||
import { withConfigContext } from '../../../../../../../../components/ConfigContext';
|
import { withConfigContext } from '../../../../../../../../components/ConfigContext';
|
||||||
@ -37,6 +38,8 @@ import axios from 'axios';
|
|||||||
import Cluster from './components/Cluster';
|
import Cluster from './components/Cluster';
|
||||||
import EditLinks from './components/EditLinks';
|
import EditLinks from './components/EditLinks';
|
||||||
import { handleApiError } from '../../../../../../../../services/utils/errorHandler';
|
import { handleApiError } from '../../../../../../../../services/utils/errorHandler';
|
||||||
|
import Authorized from '../../../../../../../../components/Authorized/Authorized';
|
||||||
|
import { isAuthorized } from '../../../../../../../../services/utils/authorizationHandler';
|
||||||
|
|
||||||
const { Title } = Typography;
|
const { Title } = Typography;
|
||||||
|
|
||||||
@ -59,6 +62,10 @@ class Page extends React.Component {
|
|||||||
isAddNewClusterVisible: false,
|
isAddNewClusterVisible: false,
|
||||||
links: [],
|
links: [],
|
||||||
};
|
};
|
||||||
|
this.hasPermissionToManage = isAuthorized(
|
||||||
|
this.props.config.user,
|
||||||
|
'/device-mgt/enterprise/user/view',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
@ -328,94 +335,121 @@ class Page extends React.Component {
|
|||||||
{/* <Paragraph>Lorem ipsum</Paragraph>*/}
|
{/* <Paragraph>Lorem ipsum</Paragraph>*/}
|
||||||
</div>
|
</div>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
<Spin spinning={loading}>
|
<Authorized
|
||||||
<div style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}>
|
permission="/permission/admin/device-mgt/enterprise/user/view"
|
||||||
<Row>
|
yes={
|
||||||
<Col md={8} sm={18} xs={24}>
|
<Spin spinning={loading}>
|
||||||
<Title editable={{ onChange: this.updatePageName }} level={2}>
|
<div
|
||||||
{pageName}
|
style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}
|
||||||
</Title>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
<Row>
|
|
||||||
<Col>
|
|
||||||
<Title level={4}>Links</Title>
|
|
||||||
{links.map(link => {
|
|
||||||
if (this.pageNames.hasOwnProperty(link.toString())) {
|
|
||||||
return (
|
|
||||||
<Tag key={link} color="#87d068">
|
|
||||||
{this.pageNames[link.toString()]}
|
|
||||||
</Tag>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
})}
|
|
||||||
<EditLinks
|
|
||||||
updateLinks={this.updateLinks}
|
|
||||||
pageId={this.pageId}
|
|
||||||
selectedLinks={links}
|
|
||||||
pages={this.pages}
|
|
||||||
/>
|
|
||||||
</Col>
|
|
||||||
{/* <Col>*/}
|
|
||||||
|
|
||||||
{/* </Col>*/}
|
|
||||||
</Row>
|
|
||||||
|
|
||||||
<Divider dashed={true} />
|
|
||||||
<Title level={4}>Clusters</Title>
|
|
||||||
|
|
||||||
<div
|
|
||||||
hidden={isAddNewClusterVisible}
|
|
||||||
style={{ textAlign: 'center' }}
|
|
||||||
>
|
|
||||||
<Button
|
|
||||||
type="dashed"
|
|
||||||
shape="round"
|
|
||||||
icon="plus"
|
|
||||||
size="large"
|
|
||||||
onClick={() => {
|
|
||||||
this.toggleAddNewClusterVisibility(true);
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
Add new cluster
|
<Row>
|
||||||
</Button>
|
<Col md={8} sm={18} xs={24}>
|
||||||
</div>
|
<Title
|
||||||
<div hidden={!isAddNewClusterVisible}>
|
editable={{ onChange: this.updatePageName }}
|
||||||
<Cluster
|
level={2}
|
||||||
cluster={{
|
>
|
||||||
clusterId: 0,
|
{pageName}
|
||||||
name: 'New Cluster',
|
</Title>
|
||||||
products: [],
|
</Col>
|
||||||
}}
|
</Row>
|
||||||
orderInPage={clusters.length}
|
<Row>
|
||||||
isTemporary={true}
|
<Col>
|
||||||
pageId={this.pageId}
|
<Title level={4}>Links</Title>
|
||||||
applications={applications}
|
{links.map(link => {
|
||||||
addSavedClusterToThePage={this.addSavedClusterToThePage}
|
if (this.pageNames.hasOwnProperty(link.toString())) {
|
||||||
toggleAddNewClusterVisibility={
|
return (
|
||||||
this.toggleAddNewClusterVisibility
|
<Tag key={link} color="#87d068">
|
||||||
}
|
{this.pageNames[link.toString()]}
|
||||||
/>
|
</Tag>
|
||||||
</div>
|
);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
})}
|
||||||
|
<Authorized
|
||||||
|
permission="/permission/admin/device-mgt/enterprise/user/modify"
|
||||||
|
yes={
|
||||||
|
<EditLinks
|
||||||
|
updateLinks={this.updateLinks}
|
||||||
|
pageId={this.pageId}
|
||||||
|
selectedLinks={links}
|
||||||
|
pages={this.pages}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
{/* <Col>*/}
|
||||||
|
|
||||||
{clusters.map((cluster, index) => {
|
{/* </Col>*/}
|
||||||
return (
|
</Row>
|
||||||
<Cluster
|
|
||||||
key={cluster.clusterId}
|
<Divider dashed={true} />
|
||||||
index={index}
|
<Title level={4}>Clusters</Title>
|
||||||
orderInPage={cluster.orderInPage}
|
<Authorized
|
||||||
isTemporary={false}
|
permission="/permission/admin/device-mgt/enterprise/user/modify"
|
||||||
cluster={cluster}
|
yes={
|
||||||
pageId={this.pageId}
|
<div
|
||||||
applications={applications}
|
hidden={isAddNewClusterVisible}
|
||||||
swapClusters={this.swapClusters}
|
style={{ textAlign: 'center' }}
|
||||||
removeLoadedCluster={this.removeLoadedCluster}
|
>
|
||||||
|
<Button
|
||||||
|
type="dashed"
|
||||||
|
shape="round"
|
||||||
|
icon="plus"
|
||||||
|
size="large"
|
||||||
|
onClick={() => {
|
||||||
|
this.toggleAddNewClusterVisibility(true);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Add new cluster
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
);
|
<div hidden={!isAddNewClusterVisible}>
|
||||||
})}
|
<Cluster
|
||||||
</div>
|
cluster={{
|
||||||
</Spin>
|
clusterId: 0,
|
||||||
|
name: 'New Cluster',
|
||||||
|
products: [],
|
||||||
|
}}
|
||||||
|
orderInPage={clusters.length}
|
||||||
|
isTemporary={true}
|
||||||
|
pageId={this.pageId}
|
||||||
|
applications={applications}
|
||||||
|
addSavedClusterToThePage={this.addSavedClusterToThePage}
|
||||||
|
toggleAddNewClusterVisibility={
|
||||||
|
this.toggleAddNewClusterVisibility
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{clusters.map((cluster, index) => {
|
||||||
|
return (
|
||||||
|
<Cluster
|
||||||
|
hasPermissionToManage={this.hasPermissionToManage}
|
||||||
|
key={cluster.clusterId}
|
||||||
|
index={index}
|
||||||
|
orderInPage={cluster.orderInPage}
|
||||||
|
isTemporary={false}
|
||||||
|
cluster={cluster}
|
||||||
|
pageId={this.pageId}
|
||||||
|
applications={applications}
|
||||||
|
swapClusters={this.swapClusters}
|
||||||
|
removeLoadedCluster={this.removeLoadedCluster}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</Spin>
|
||||||
|
}
|
||||||
|
no={
|
||||||
|
<Result
|
||||||
|
status="403"
|
||||||
|
title="You don't have permission to view android enterprise configurations."
|
||||||
|
subTitle="Please contact system administrator"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const isAuthorized = (user, permission) => {
|
||||||
|
if (!user || !permission) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return user.permissions.includes(permission);
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue
Block a user