mirror of
https://github.com/Unleash/unleash.git
synced 2025-04-29 01:15:48 +02:00
feature: Add support for permission system in unleash frontend
refactored PermissionComponent to pure component fixed feature-list-item-component
This commit is contained in:
parent
1eb8fc0464
commit
aad612d3d6
@ -1,47 +1,21 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { ADMIN } from '../../permissions';
|
||||
|
||||
class PermissionComponent extends Component {
|
||||
static propTypes = {
|
||||
user: PropTypes.object,
|
||||
component: PropTypes.oneOfType([PropTypes.node, PropTypes.func]),
|
||||
others: PropTypes.object,
|
||||
denied: PropTypes.object,
|
||||
granted: PropTypes.object,
|
||||
otherwise: PropTypes.node,
|
||||
permission: PropTypes.string,
|
||||
children: PropTypes.node,
|
||||
};
|
||||
|
||||
render() {
|
||||
const { user, otherwise, component: Component, permission, granted, denied, children, ...others } = this.props;
|
||||
let grantedComponent = Component;
|
||||
let deniedCompoinent = otherwise || '';
|
||||
|
||||
if (granted || denied) {
|
||||
grantedComponent = (
|
||||
<Component {...others} {...granted || {}}>
|
||||
{children}
|
||||
</Component>
|
||||
);
|
||||
deniedCompoinent = (
|
||||
<Component {...others} {...denied || {}}>
|
||||
{children}
|
||||
</Component>
|
||||
);
|
||||
}
|
||||
|
||||
if (!user) return deniedCompoinent;
|
||||
if (
|
||||
!user.permissions ||
|
||||
user.permissions.indexOf(ADMIN) !== -1 ||
|
||||
user.permissions.indexOf(permission) !== -1
|
||||
) {
|
||||
return grantedComponent;
|
||||
}
|
||||
return deniedCompoinent;
|
||||
const PermissionComponent = ({ user, permission, component, otherwise }) => {
|
||||
if (
|
||||
user &&
|
||||
(!user.permissions || user.permissions.indexOf(ADMIN) !== -1 || user.permissions.indexOf(permission) !== -1)
|
||||
) {
|
||||
return component;
|
||||
}
|
||||
}
|
||||
return otherwise || '';
|
||||
};
|
||||
|
||||
PermissionComponent.propTypes = {
|
||||
user: PropTypes.object,
|
||||
component: PropTypes.node,
|
||||
otherwise: PropTypes.node,
|
||||
permission: PropTypes.string,
|
||||
};
|
||||
|
||||
export default PermissionComponent;
|
||||
|
@ -22,7 +22,7 @@ exports[`renders correctly with one feature 1`] = `
|
||||
>
|
||||
<react-mdl-Switch
|
||||
checked={false}
|
||||
disabled={true}
|
||||
disabled={false}
|
||||
onChange={[Function]}
|
||||
title="Toggle Another"
|
||||
/>
|
||||
|
@ -1,8 +1,12 @@
|
||||
import React from 'react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { createStore } from 'redux';
|
||||
import { Provider } from 'react-redux';
|
||||
import { Map as $Map } from 'immutable';
|
||||
|
||||
import Feature from './../feature-list-item-component';
|
||||
import renderer from 'react-test-renderer';
|
||||
import { UPDATE_FEATURE } from '../../../permissions';
|
||||
|
||||
jest.mock('react-mdl');
|
||||
|
||||
@ -21,19 +25,22 @@ test('renders correctly with one feature', () => {
|
||||
],
|
||||
createdAt: '2018-02-04T20:27:52.127Z',
|
||||
};
|
||||
const store = { user: new $Map({ profile: { permissions: [UPDATE_FEATURE] } }) };
|
||||
const featureMetrics = { lastHour: {}, lastMinute: {}, seenApps: {} };
|
||||
const settings = { sort: 'name' };
|
||||
const tree = renderer.create(
|
||||
<MemoryRouter>
|
||||
<Feature
|
||||
key={0}
|
||||
settings={settings}
|
||||
metricsLastHour={featureMetrics.lastHour[feature.name]}
|
||||
metricsLastMinute={featureMetrics.lastMinute[feature.name]}
|
||||
feature={feature}
|
||||
toggleFeature={jest.fn()}
|
||||
/>
|
||||
</MemoryRouter>
|
||||
<Provider store={createStore(state => state, store)}>
|
||||
<MemoryRouter>
|
||||
<Feature
|
||||
key={0}
|
||||
settings={settings}
|
||||
metricsLastHour={featureMetrics.lastHour[feature.name]}
|
||||
metricsLastMinute={featureMetrics.lastMinute[feature.name]}
|
||||
feature={feature}
|
||||
toggleFeature={jest.fn()}
|
||||
/>
|
||||
</MemoryRouter>
|
||||
</Provider>
|
||||
);
|
||||
|
||||
expect(tree).toMatchSnapshot();
|
||||
|
@ -3,6 +3,8 @@ import PropTypes from 'prop-types';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Switch, Chip, ListItem, ListItemAction, Icon } from 'react-mdl';
|
||||
import Progress from './progress';
|
||||
import PermissionComponent from '../common/permission-container';
|
||||
import { UPDATE_FEATURE } from '../../permissions';
|
||||
import { calc, styles as commonStyles } from '../common';
|
||||
|
||||
import styles from './feature.scss';
|
||||
@ -14,7 +16,6 @@ const Feature = ({
|
||||
metricsLastHour = { yes: 0, no: 0, isFallback: true },
|
||||
metricsLastMinute = { yes: 0, no: 0, isFallback: true },
|
||||
revive,
|
||||
updateable,
|
||||
}) => {
|
||||
const { name, description, enabled, strategies } = feature;
|
||||
const { showLastHour = false } = settings;
|
||||
@ -42,12 +43,26 @@ const Feature = ({
|
||||
<Progress strokeWidth={15} percentage={percent} isFallback={isStale} />
|
||||
</span>
|
||||
<span className={styles.listItemToggle}>
|
||||
<Switch
|
||||
disabled={!updateable || toggleFeature === undefined}
|
||||
title={`Toggle ${name}`}
|
||||
key="left-actions"
|
||||
onChange={() => toggleFeature(name)}
|
||||
checked={enabled}
|
||||
<PermissionComponent
|
||||
permission={UPDATE_FEATURE}
|
||||
component={
|
||||
<Switch
|
||||
disabled={toggleFeature === undefined}
|
||||
title={`Toggle ${name}`}
|
||||
key="left-actions"
|
||||
onChange={() => toggleFeature(name)}
|
||||
checked={enabled}
|
||||
/>
|
||||
}
|
||||
otherwise={
|
||||
<Switch
|
||||
disabled
|
||||
title={`Toggle ${name}`}
|
||||
key="left-actions"
|
||||
onChange={() => toggleFeature(name)}
|
||||
checked={enabled}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</span>
|
||||
<span className={['mdl-list__item-primary-content', styles.listItemLink].join(' ')}>
|
||||
@ -60,10 +75,16 @@ const Feature = ({
|
||||
{strategyChips}
|
||||
{summaryChip}
|
||||
</span>
|
||||
{updateable && revive ? (
|
||||
<ListItemAction onClick={() => revive(feature.name)}>
|
||||
<Icon name="undo" />
|
||||
</ListItemAction>
|
||||
{revive ? (
|
||||
<PermissionComponent
|
||||
permission={UPDATE_FEATURE}
|
||||
component={
|
||||
<ListItemAction onClick={() => revive(feature.name)}>
|
||||
<Icon name="undo" />
|
||||
</ListItemAction>
|
||||
}
|
||||
otherwise={<span />}
|
||||
/>
|
||||
) : (
|
||||
<span />
|
||||
)}
|
||||
|
@ -8,10 +8,10 @@ import { HeaderTitle } from '../../common';
|
||||
class StrategiesSectionComponent extends React.Component {
|
||||
static propTypes = {
|
||||
strategies: PropTypes.array.isRequired,
|
||||
addStrategy: PropTypes.func.isRequired,
|
||||
removeStrategy: PropTypes.func.isRequired,
|
||||
updateStrategy: PropTypes.func.isRequired,
|
||||
fetchStrategies: PropTypes.func.isRequired,
|
||||
addStrategy: PropTypes.func,
|
||||
removeStrategy: PropTypes.func,
|
||||
updateStrategy: PropTypes.func,
|
||||
fetchStrategies: PropTypes.func,
|
||||
};
|
||||
|
||||
componentWillMount() {
|
||||
|
@ -155,20 +155,29 @@ export default class ViewFeatureToggleComponent extends React.Component {
|
||||
{this.isFeatureView ? (
|
||||
<PermissionComponent
|
||||
permission={UPDATE_FEATURE}
|
||||
component={Textfield}
|
||||
granted={{
|
||||
onChange: v => setValue('description', v),
|
||||
onBlur: updateFeatureToggle,
|
||||
}}
|
||||
denied={{
|
||||
disabled: true,
|
||||
}}
|
||||
floatingLabel
|
||||
style={{ width: '100%' }}
|
||||
rows={1}
|
||||
label="Description"
|
||||
required
|
||||
value={featureToggle.description}
|
||||
component={
|
||||
<Textfield
|
||||
floatingLabel
|
||||
style={{ width: '100%' }}
|
||||
rows={1}
|
||||
label="Description"
|
||||
required
|
||||
value={featureToggle.description}
|
||||
onChange={v => setValue('description', v)}
|
||||
onBlur={updateFeatureToggle}
|
||||
/>
|
||||
}
|
||||
otherwise={
|
||||
<Textfield
|
||||
disabled
|
||||
floatingLabel
|
||||
style={{ width: '100%' }}
|
||||
rows={1}
|
||||
label="Description"
|
||||
required
|
||||
value={featureToggle.description}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<Textfield
|
||||
@ -194,19 +203,27 @@ export default class ViewFeatureToggleComponent extends React.Component {
|
||||
<span style={{ paddingRight: '24px' }}>
|
||||
<PermissionComponent
|
||||
permission={UPDATE_FEATURE}
|
||||
component={Switch}
|
||||
granted={{
|
||||
disabled: !this.isFeatureView,
|
||||
}}
|
||||
denied={{
|
||||
disabled: true,
|
||||
}}
|
||||
ripple
|
||||
checked={featureToggle.enabled}
|
||||
onChange={() => toggleFeature(featureToggle.name)}
|
||||
>
|
||||
{featureToggle.enabled ? 'Enabled' : 'Disabled'}
|
||||
</PermissionComponent>
|
||||
component={
|
||||
<Switch
|
||||
disabled={!this.isFeatureView}
|
||||
ripple
|
||||
checked={featureToggle.enabled}
|
||||
onChange={() => toggleFeature(featureToggle.name)}
|
||||
>
|
||||
{featureToggle.enabled ? 'Enabled' : 'Disabled'}
|
||||
</Switch>
|
||||
}
|
||||
otherwise={
|
||||
<Switch
|
||||
disabled
|
||||
ripple
|
||||
checked={featureToggle.enabled}
|
||||
onChange={() => toggleFeature(featureToggle.name)}
|
||||
>
|
||||
{featureToggle.enabled ? 'Enabled' : 'Disabled'}
|
||||
</Switch>
|
||||
}
|
||||
/>
|
||||
</span>
|
||||
|
||||
{this.isFeatureView ? (
|
||||
|
Loading…
Reference in New Issue
Block a user