1
0
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:
Ivar Conradi Østhus 2020-08-10 21:58:14 +02:00
parent 3ecdab8583
commit 7e50ebbad9
14 changed files with 69 additions and 45 deletions

View File

@ -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>
`; `;

View File

@ -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",

View File

@ -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 = {

View File

@ -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)}>

View 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,
};

View 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;

View File

@ -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}
/> />
)) ))
) : ( ) : (

View File

@ -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

View File

@ -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
);

View File

@ -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}
/> />
); );

View File

@ -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 => ({

View File

@ -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) {

View File

@ -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(`/`));
}; };

View 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);
};
}