Skip to content

Commit

Permalink
Merge pull request #2244 from kids-first/dev
Browse files Browse the repository at this point in the history
Release 2.13.2
  • Loading branch information
Jeremy Costanza authored Jan 14, 2020
2 parents a1b1b4a + a5bb0f5 commit 0196561
Show file tree
Hide file tree
Showing 12 changed files with 178 additions and 112 deletions.
13 changes: 13 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,19 @@
-->

## 2020-01-14 kf-portal-ui 2.13.2

### Features

This feature includes :

#### kf-portal-ui
- [#2233](https://github.com/kids-first/kf-portal-ui/issues/2233) Change label when disconnecting
- [#2236](https://github.com/kids-first/kf-portal-ui/issues/2236) Enable feature toggles with url parameters

#### kf-api-portal-reports
- [#14](https://github.com/kids-first/kf-api-portal-reports/issues/14) Add `Method of Sample Procurement` to biospecimen report download

## 2020-01-13 kf-portal-ui 2.13.1

### Features
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "kf-portal-ui",
"version": "2.13.1",
"version": "2.13.2",
"private": true,
"dependencies": {
"@kfarranger/components": "^1.4.4",
Expand Down
14 changes: 8 additions & 6 deletions src/common/featuresToggles.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,32 @@ import camelCase from 'lodash/camelCase';
import { getApplicationEnvVar } from 'common/injectGlobals';

const featureTogglePrefix = 'REACT_APP_FT';
const togglePrefix = 'REACT_APP_';

const isEnabled = (featureName, defaultValue = true) => {
const isEnabled = (featureName, enabledFeatures = {}, defaultValue = true) => {
const flag = getApplicationEnvVar(featureName);

// missing feature flags defaults to their default
if (typeof flag === 'undefined') return defaultValue;

// any casing for 'false', false, 0 and '0' are all disabled
// eslint-disable-next-line eqeqeq
if (flag === false || flag.toString().toLowerCase() === 'false' || flag == 0) {
return false;
if (flag === false || flag.toString().toLowerCase() === 'false' || flag === 0) {
return enabledFeatures[featureName] === true;
}

// the rest is enabled (but could contain a value like 'canary' or 'ADMIN')
return true;
};

const toggles = Array.from(Object.entries(process.env))
const toggles = (queryStrings) => Array.from(Object.entries(process.env))
.filter(env => {
return typeof env[1] === 'string';
})
.filter(env => env[0].startsWith(featureTogglePrefix))
.reduce(
(allToggles, toggle) => {
allToggles[camelCase(toggle[0].slice(featureTogglePrefix.length))] = isEnabled(toggle[0], toggle[1]);
allToggles[camelCase(toggle[0].slice(featureTogglePrefix.length))] = isEnabled(toggle[0].slice(togglePrefix.length), queryStrings);
return allToggles;
},
{
Expand All @@ -39,6 +40,7 @@ const toggles = Array.from(Object.entries(process.env))
/**
* Checks if a feature is enabled or not.
* @param {String} featureName - The name of the feature, as defined in the feature toggles configuration.
* @param features
* @returns {Boolean} `true` if the name feature exists and is enabled; `false` otherwise.
*/
export const isFeatureEnabled = featureName => toggles[featureName] === true;
export const isFeatureEnabled = (featureName, features = {}) => toggles(features)[featureName] === true;
4 changes: 2 additions & 2 deletions src/components/CohortBuilder/Categories/Category.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,9 @@ export default class Category extends React.Component {
overlayClassName="cb-category-overlay-container"
getPopupContainer={() => document.getElementById(anchorId)}
>
<Column id={anchorId} className="cb-category-button" style={{ borderTopColor: color }}>
<Column id={anchorId} className="cb-category-button" style={{ borderTopColor: color, position:'relative' }}>
{children}
<h3 style={{position:'relative'}}>{title}</h3>
<h3 >{title}</h3>
</Column>
</Dropdown>
);
Expand Down
27 changes: 19 additions & 8 deletions src/components/Header/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,19 @@ import { Alert, Badge } from 'antd';
import { KEY_PUBLIC_PROFILE_INVITE_IS_SEEN } from 'common/constants';
import ROUTES from 'common/routes';
import { loggedInUserShape } from 'shapes/index';
import queryString from 'query-string'

import UserMenu from './UserMenu';

import './Header.css';

import { dismissError } from 'store/actionCreators/errors';
import { enableFeature } from 'store/actionCreators/enableFeatures';

const isSearchMemberFeatEnabled = isFeatureEnabled('searchMembers'); //TODO : remove me one day :)
const isSearchMemberFeatEnabled = features => isFeatureEnabled('searchMembers', features); //TODO : remove me one day :)

const showPublicProfileInvite = (user = {}) => {
if (!isSearchMemberFeatEnabled) {
const showPublicProfileInvite = (user = {}, features = {}) => {
if (!isSearchMemberFeatEnabled(features)) {
return false;
}
return (
Expand All @@ -44,7 +46,7 @@ const onClosePublicProfileInviteAlert = () =>

const getUrlForUser = (user, hash = '') => `${ROUTES.user}/${user._id}${hash}`;

const renderAlertIfAny = (loggedInUser, currentError, dismissError) => {
const renderAlertIfAny = (loggedInUser, currentError, dismissError, features) => {
if (currentError) {
return (
<Alert
Expand All @@ -62,7 +64,7 @@ const renderAlertIfAny = (loggedInUser, currentError, dismissError) => {
);
}

if (showPublicProfileInvite(loggedInUser)) {
if (showPublicProfileInvite(loggedInUser, features)) {
return (
<Alert
message={
Expand Down Expand Up @@ -100,19 +102,26 @@ class Header extends React.Component {
match: PropTypes.shape({
path: PropTypes.string.isRequired,
}).isRequired,
enabledFeatures: PropTypes.object,
};

constructor(props) {
super(props);
autobind(this);
}

componentDidMount() {
const queries = queryString.parse(this.props.location.search);
this.props.enableFeature(queries)
}

render() {
const {
currentError,
dismissError,
loggedInUser,
history,
features,
match: { path },
} = this.props;

Expand All @@ -127,7 +136,7 @@ class Header extends React.Component {

return (
<div className="headerContainer">
{renderAlertIfAny(loggedInUser, currentError, dismissError)}
{renderAlertIfAny(loggedInUser, currentError, dismissError, features)}
<div className="gradientAccent" />
<Row className="headerContent">
<Row>
Expand Down Expand Up @@ -158,7 +167,7 @@ class Header extends React.Component {
<DatabaseIcon /> File Repository
</NavLink>
</li>
{isSearchMemberFeatEnabled && (
{isSearchMemberFeatEnabled(this.props.features) && (
<li>
<NavLink currentPathName={currentPathName} to={ROUTES.searchMember}>
<Badge
Expand Down Expand Up @@ -197,10 +206,12 @@ class Header extends React.Component {
const mapStateToProps = state => ({
loggedInUser: state.user.loggedInUser,
currentError: state.errors.currentError,
features: state.enableFeatures.enableFeatures,
});

const mapDispatchToProps = {
dismissError,
enableFeature,
};

export default compose(withRouter, withApi, connect(mapStateToProps, mapDispatchToProps))(Header);
export default compose(withRouter, withApi, connect(mapStateToProps, mapDispatchToProps))(Header);
12 changes: 9 additions & 3 deletions src/components/UserProfile/HeaderBanner.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ import { computeGravatarSrcFromEmail } from 'utils';
import ProfilePill from 'uikit/ProfilePill';
import { isFeatureEnabled } from 'common/featuresToggles';
import './style.css';
import { connect } from 'react-redux';
import { compose } from 'redux';

const { Title, Text } = Typography;

const HeaderBanner = ({ profile, onChangePrivacyStatusCb, isLoading, error, canEdit }) => {
const HeaderBanner = ({ profile, onChangePrivacyStatusCb, isLoading, error, canEdit, features }) => {
return (
<Row
align={'middle'}
Expand Down Expand Up @@ -44,7 +46,7 @@ const HeaderBanner = ({ profile, onChangePrivacyStatusCb, isLoading, error, canE
</div>
</div>
{canEdit &&
isFeatureEnabled('searchMembers') && ( //remove me one day :)
isFeatureEnabled('searchMembers', features) && ( //remove me one day :)
<div className={'hd-switch-wrapper'}>
<Row
type={'flex'}
Expand Down Expand Up @@ -99,4 +101,8 @@ HeaderBanner.propTypes = {
canEdit: PropTypes.bool.isRequired,
};

export default HeaderBanner;
const mapStateToProps = state => ({
features: state.enableFeatures.enableFeatures,
});

export default compose(connect(mapStateToProps))(HeaderBanner);
Loading

0 comments on commit 0196561

Please sign in to comment.