mirror of
https://github.com/Unleash/unleash.git
synced 2025-08-04 13:48:56 +02:00
fix: some ux cleanup for toggle types
This commit is contained in:
parent
3ecdab8583
commit
7e50ebbad9
@ -60,11 +60,7 @@ exports[`renders correctly with one feature 1`] = `
|
|||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
className="listItemStrategies hideLt920"
|
className="listItemStrategies hideLt920"
|
||||||
>
|
/>
|
||||||
<react-mdl-Chip
|
|
||||||
className="typeChip"
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
<span />
|
<span />
|
||||||
</react-mdl-ListItem>
|
</react-mdl-ListItem>
|
||||||
`;
|
`;
|
||||||
@ -128,11 +124,7 @@ exports[`renders correctly with one feature without permission 1`] = `
|
|||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
className="listItemStrategies hideLt920"
|
className="listItemStrategies hideLt920"
|
||||||
>
|
/>
|
||||||
<react-mdl-Chip
|
|
||||||
className="typeChip"
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
<span />
|
<span />
|
||||||
</react-mdl-ListItem>
|
</react-mdl-ListItem>
|
||||||
`;
|
`;
|
||||||
|
@ -172,6 +172,7 @@ exports[`renders correctly with one feature 1`] = `
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
hasPermission={[Function]}
|
hasPermission={[Function]}
|
||||||
|
setFilter={[Function]}
|
||||||
settings={
|
settings={
|
||||||
Object {
|
Object {
|
||||||
"sort": "name",
|
"sort": "name",
|
||||||
@ -343,6 +344,7 @@ exports[`renders correctly with one feature without permissions 1`] = `
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
hasPermission={[Function]}
|
hasPermission={[Function]}
|
||||||
|
setFilter={[Function]}
|
||||||
settings={
|
settings={
|
||||||
Object {
|
Object {
|
||||||
"sort": "name",
|
"sort": "name",
|
||||||
|
@ -6,6 +6,7 @@ import renderer from 'react-test-renderer';
|
|||||||
import { UPDATE_FEATURE } from '../../../permissions';
|
import { UPDATE_FEATURE } from '../../../permissions';
|
||||||
|
|
||||||
jest.mock('react-mdl');
|
jest.mock('react-mdl');
|
||||||
|
jest.mock('../feature-type-container');
|
||||||
|
|
||||||
test('renders correctly with one feature', () => {
|
test('renders correctly with one feature', () => {
|
||||||
const feature = {
|
const feature = {
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { Switch, Chip, ListItem, ListItemAction, Icon } from 'react-mdl';
|
import { Switch, ListItem, ListItemAction, Icon } from 'react-mdl';
|
||||||
import TimeAgo from 'react-timeago';
|
import TimeAgo from 'react-timeago';
|
||||||
import Progress from './progress';
|
import Progress from './progress';
|
||||||
import { UPDATE_FEATURE } from '../../permissions';
|
import { UPDATE_FEATURE } from '../../permissions';
|
||||||
import { calc, styles as commonStyles } from '../common';
|
import { calc, styles as commonStyles } from '../common';
|
||||||
import StatusComponent from './status-component';
|
import Status from './status-component';
|
||||||
|
import FeatureType from './feature-type-container';
|
||||||
|
|
||||||
import styles from './feature.scss';
|
import styles from './feature.scss';
|
||||||
|
|
||||||
@ -56,8 +57,8 @@ const Feature = ({
|
|||||||
</Link>
|
</Link>
|
||||||
</span>
|
</span>
|
||||||
<span className={[styles.listItemStrategies, commonStyles.hideLt920].join(' ')}>
|
<span className={[styles.listItemStrategies, commonStyles.hideLt920].join(' ')}>
|
||||||
<StatusComponent stale={stale} showActive={false} />
|
<Status stale={stale} showActive={false} />
|
||||||
<Chip className={styles.typeChip}>{type}</Chip>
|
<FeatureType type={type} />
|
||||||
</span>
|
</span>
|
||||||
{revive && hasPermission(UPDATE_FEATURE) ? (
|
{revive && hasPermission(UPDATE_FEATURE) ? (
|
||||||
<ListItemAction onClick={() => revive(feature.name)}>
|
<ListItemAction onClick={() => revive(feature.name)}>
|
||||||
|
20
frontend/src/component/feature/feature-type-component.jsx
Normal file
20
frontend/src/component/feature/feature-type-component.jsx
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Chip } from 'react-mdl';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import styles from './feature.scss';
|
||||||
|
|
||||||
|
export default function StatusComponent({ type, types, onClick }) {
|
||||||
|
const typeObject = types.find(o => o.id === type) || { id: type, name: type };
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Chip className={styles.typeChip} title={typeObject.description} onClick={onClick}>
|
||||||
|
{typeObject.name}
|
||||||
|
</Chip>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusComponent.propTypes = {
|
||||||
|
type: PropTypes.string.isRequired,
|
||||||
|
types: PropTypes.array,
|
||||||
|
onClick: PropTypes.func,
|
||||||
|
};
|
10
frontend/src/component/feature/feature-type-container.jsx
Normal file
10
frontend/src/component/feature/feature-type-container.jsx
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import { connect } from 'react-redux';
|
||||||
|
import Component from './feature-type-component';
|
||||||
|
|
||||||
|
const mapStateToProps = state => ({
|
||||||
|
types: state.featureTypes.toJS(),
|
||||||
|
});
|
||||||
|
|
||||||
|
const FeatureType = connect(mapStateToProps)(Component);
|
||||||
|
|
||||||
|
export default FeatureType;
|
@ -26,7 +26,7 @@ export default class FeatureListComponent extends React.Component {
|
|||||||
super();
|
super();
|
||||||
this.state = {
|
this.state = {
|
||||||
filter: props.settings.filter,
|
filter: props.settings.filter,
|
||||||
updateFilter: debounce(props.updateSetting.bind(this, 'filter'), 250),
|
updateFilter: debounce(props.updateSetting.bind(this, 'filter'), 150),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,11 +42,11 @@ export default class FeatureListComponent extends React.Component {
|
|||||||
this.props.updateSetting('showLastHour', !this.props.settings.showLastHour);
|
this.props.updateSetting('showLastHour', !this.props.settings.showLastHour);
|
||||||
}
|
}
|
||||||
|
|
||||||
setFilter(v) {
|
setFilter = v => {
|
||||||
const value = typeof v === 'string' ? v : '';
|
const value = typeof v === 'string' ? v : '';
|
||||||
this.setState({ filter: value });
|
this.setState({ filter: value });
|
||||||
this.state.updateFilter(value);
|
this.state.updateFilter(value);
|
||||||
}
|
};
|
||||||
|
|
||||||
setSort(v) {
|
setSort(v) {
|
||||||
this.props.updateSetting('sort', typeof v === 'string' ? v.trim() : '');
|
this.props.updateSetting('sort', typeof v === 'string' ? v.trim() : '');
|
||||||
@ -138,6 +138,7 @@ export default class FeatureListComponent extends React.Component {
|
|||||||
toggleFeature={toggleFeature}
|
toggleFeature={toggleFeature}
|
||||||
revive={revive}
|
revive={revive}
|
||||||
hasPermission={hasPermission}
|
hasPermission={hasPermission}
|
||||||
|
setFilter={this.setFilter}
|
||||||
/>
|
/>
|
||||||
))
|
))
|
||||||
) : (
|
) : (
|
||||||
|
@ -17,7 +17,7 @@ export const mapStateToPropsConfigurable = isFeature => state => {
|
|||||||
regex.test(feature.name) ||
|
regex.test(feature.name) ||
|
||||||
regex.test(feature.description) ||
|
regex.test(feature.description) ||
|
||||||
feature.strategies.some(s => s && s.name && regex.test(s.name)) ||
|
feature.strategies.some(s => s && s.name && regex.test(s.name)) ||
|
||||||
regex.test(JSON.stringify(feature))
|
(settings.filter.length > 1 && regex.test(JSON.stringify(feature)))
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Invalid filter regex
|
// Invalid filter regex
|
||||||
|
@ -6,20 +6,17 @@ import { Route } from 'react-router-dom';
|
|||||||
import { DrawerMenu } from './drawer';
|
import { DrawerMenu } from './drawer';
|
||||||
import Breadcrum from './breadcrumb';
|
import Breadcrum from './breadcrumb';
|
||||||
import ShowUserContainer from '../user/show-user-container';
|
import ShowUserContainer from '../user/show-user-container';
|
||||||
import { fetchUIConfig } from './../../store/ui-config/actions';
|
import { loadInitalData } from './../../store/loader';
|
||||||
import { fetchContext } from './../../store/context/actions';
|
|
||||||
|
|
||||||
class HeaderComponent extends PureComponent {
|
class HeaderComponent extends PureComponent {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
uiConfig: PropTypes.object.isRequired,
|
uiConfig: PropTypes.object.isRequired,
|
||||||
fetchUIConfig: PropTypes.func.isRequired,
|
loadInitalData: PropTypes.func.isRequired,
|
||||||
fetchContext: PropTypes.func.isRequired,
|
|
||||||
location: PropTypes.object.isRequired,
|
location: PropTypes.object.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.props.fetchUIConfig();
|
this.props.loadInitalData();
|
||||||
this.props.fetchContext();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line camelcase
|
// eslint-disable-next-line camelcase
|
||||||
@ -53,6 +50,4 @@ class HeaderComponent extends PureComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(state => ({ uiConfig: state.uiConfig.toJS() }), { fetchUIConfig, fetchContext })(
|
export default connect(state => ({ uiConfig: state.uiConfig.toJS() }), { loadInitalData })(HeaderComponent);
|
||||||
HeaderComponent
|
|
||||||
);
|
|
||||||
|
@ -37,8 +37,7 @@ class AuthComponent extends React.Component {
|
|||||||
user: PropTypes.object.isRequired,
|
user: PropTypes.object.isRequired,
|
||||||
unsecureLogin: PropTypes.func.isRequired,
|
unsecureLogin: PropTypes.func.isRequired,
|
||||||
passwordLogin: PropTypes.func.isRequired,
|
passwordLogin: PropTypes.func.isRequired,
|
||||||
fetchFeatureToggles: PropTypes.func.isRequired,
|
loadInitalData: PropTypes.func.isRequired,
|
||||||
fetchUIConfig: PropTypes.func.isRequired,
|
|
||||||
history: PropTypes.object.isRequired,
|
history: PropTypes.object.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -52,8 +51,7 @@ class AuthComponent extends React.Component {
|
|||||||
<AuthenticationPasswordComponent
|
<AuthenticationPasswordComponent
|
||||||
passwordLogin={this.props.passwordLogin}
|
passwordLogin={this.props.passwordLogin}
|
||||||
authDetails={authDetails}
|
authDetails={authDetails}
|
||||||
fetchFeatureToggles={this.props.fetchFeatureToggles}
|
loadInitalData={this.props.loadInitalData}
|
||||||
fetchUIConfig={this.props.fetchUIConfig}
|
|
||||||
history={this.props.history}
|
history={this.props.history}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@ -62,8 +60,7 @@ class AuthComponent extends React.Component {
|
|||||||
<AuthenticationSimpleComponent
|
<AuthenticationSimpleComponent
|
||||||
unsecureLogin={this.props.unsecureLogin}
|
unsecureLogin={this.props.unsecureLogin}
|
||||||
authDetails={authDetails}
|
authDetails={authDetails}
|
||||||
fetchFeatureToggles={this.props.fetchFeatureToggles}
|
loadInitalData={this.props.loadInitalData}
|
||||||
fetchUIConfig={this.props.fetchUIConfig}
|
|
||||||
history={this.props.history}
|
history={this.props.history}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import AuthenticationComponent from './authentication-component';
|
import AuthenticationComponent from './authentication-component';
|
||||||
import { unsecureLogin, passwordLogin } from '../../store/user/actions';
|
import { unsecureLogin, passwordLogin } from '../../store/user/actions';
|
||||||
import { fetchFeatureToggles } from '../../store/feature-actions';
|
import { loadInitalData } from './../../store/loader';
|
||||||
import { fetchUIConfig } from '../../store/ui-config/actions';
|
|
||||||
|
|
||||||
const mapDispatchToProps = {
|
const mapDispatchToProps = {
|
||||||
unsecureLogin,
|
unsecureLogin,
|
||||||
passwordLogin,
|
passwordLogin,
|
||||||
fetchFeatureToggles,
|
loadInitalData,
|
||||||
fetchUIConfig,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
|
@ -6,8 +6,7 @@ class EnterpriseAuthenticationComponent extends React.Component {
|
|||||||
static propTypes = {
|
static propTypes = {
|
||||||
authDetails: PropTypes.object.isRequired,
|
authDetails: PropTypes.object.isRequired,
|
||||||
passwordLogin: PropTypes.func.isRequired,
|
passwordLogin: PropTypes.func.isRequired,
|
||||||
fetchFeatureToggles: PropTypes.func.isRequired,
|
loadInitalData: PropTypes.func.isRequired,
|
||||||
fetchUIConfig: PropTypes.func.isRequired,
|
|
||||||
history: PropTypes.object.isRequired,
|
history: PropTypes.object.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -38,8 +37,7 @@ class EnterpriseAuthenticationComponent extends React.Component {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await this.props.passwordLogin(path, user);
|
await this.props.passwordLogin(path, user);
|
||||||
await this.props.fetchFeatureToggles();
|
await this.props.loadInitalData();
|
||||||
await this.props.fetchUIConfig();
|
|
||||||
this.props.history.push(`/`);
|
this.props.history.push(`/`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.statusCode === 404) {
|
if (error.statusCode === 404) {
|
||||||
|
@ -6,8 +6,7 @@ class SimpleAuthenticationComponent extends React.Component {
|
|||||||
static propTypes = {
|
static propTypes = {
|
||||||
authDetails: PropTypes.object.isRequired,
|
authDetails: PropTypes.object.isRequired,
|
||||||
unsecureLogin: PropTypes.func.isRequired,
|
unsecureLogin: PropTypes.func.isRequired,
|
||||||
fetchFeatureToggles: PropTypes.func.isRequired,
|
loadInitalData: PropTypes.func.isRequired,
|
||||||
fetchUIConfig: PropTypes.func.isRequired,
|
|
||||||
history: PropTypes.object.isRequired,
|
history: PropTypes.object.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -19,8 +18,7 @@ class SimpleAuthenticationComponent extends React.Component {
|
|||||||
|
|
||||||
this.props
|
this.props
|
||||||
.unsecureLogin(path, user)
|
.unsecureLogin(path, user)
|
||||||
.then(this.props.fetchFeatureToggles)
|
.then(this.props.loadInitalData)
|
||||||
.then(this.props.fetchUIConfig)
|
|
||||||
.then(() => this.props.history.push(`/`));
|
.then(() => this.props.history.push(`/`));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
11
frontend/src/store/loader.js
Normal file
11
frontend/src/store/loader.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { fetchUIConfig } from './ui-config/actions';
|
||||||
|
import { fetchContext } from './context/actions';
|
||||||
|
import { fetchFeatureTypes } from './feature-type/actions';
|
||||||
|
|
||||||
|
export function loadInitalData() {
|
||||||
|
return dispatch => {
|
||||||
|
fetchUIConfig()(dispatch);
|
||||||
|
fetchContext()(dispatch);
|
||||||
|
fetchFeatureTypes()(dispatch);
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user