enable/disable features in config.json

As per https://docs.google.com/document/d/1Kn-mz2dDce9Cqc4oUTl5yJXGvmTlky1_KezuwUg58x0/edit#

Replaces:
 * enableLabs setting
 * 'override' flag in labs
 * 'default' flag in labs

Un-feature-flags matrix apps since this was now overidden to be
enabled.
This commit is contained in:
David Baker 2017-10-12 17:03:38 +01:00
parent 757e42ddca
commit e50478aa1d
5 changed files with 76 additions and 84 deletions

View file

@ -1,5 +1,6 @@
/* /*
Copyright 2015, 2016 OpenMarket Ltd Copyright 2015, 2016 OpenMarket Ltd
Copyright 2017 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -17,33 +18,42 @@ limitations under the License.
import Promise from 'bluebird'; import Promise from 'bluebird';
import MatrixClientPeg from './MatrixClientPeg'; import MatrixClientPeg from './MatrixClientPeg';
import Notifier from './Notifier'; import Notifier from './Notifier';
import { _t } from './languageHandler'; import { _t, _td } from './languageHandler';
import SdkConfig from './SdkConfig';
/* /*
* TODO: Make things use this. This is all WIP - see UserSettings.js for usage. * TODO: Make things use this. This is all WIP - see UserSettings.js for usage.
*/ */
const FEATURES = [
{
id: 'feature_groups',
name: _td("Groups"),
},
];
export default { export default {
LABS_FEATURES: [ getLabsFeatures() {
{ const featuresConfig = SdkConfig.get()['features'] || {};
name: "-",
id: 'matrix_apps',
default: true,
// XXX: Always use default, ignore localStorage and remove from labs return FEATURES.filter((f) => {
override: true, const sdkConfigValue = featuresConfig[f.id];
}, if (!['enable', 'disable'].includes(sdkConfigValue)) {
{ return true;
name: "-", }
id: 'feature_groups', }).map((f) => {
default: false, return f.id;
}, });
], },
// horrible but it works. The locality makes this somewhat more palatable. translatedNameForFeature(featureId) {
doTranslations: function() { const feature = FEATURES.filter((f) => {
this.LABS_FEATURES[0].name = _t("Matrix Apps"); return f.id === featureId;
this.LABS_FEATURES[1].name = _t("Groups"); })[0];
if (feature === undefined) return null;
return _t(feature.name);
}, },
loadProfileInfo: function() { loadProfileInfo: function() {
@ -180,33 +190,30 @@ export default {
localStorage.setItem('mx_local_settings', JSON.stringify(settings)); localStorage.setItem('mx_local_settings', JSON.stringify(settings));
}, },
getFeatureById(feature: string) {
for (let i = 0; i < this.LABS_FEATURES.length; i++) {
const f = this.LABS_FEATURES[i];
if (f.id === feature) {
return f;
}
}
return null;
},
isFeatureEnabled: function(featureId: string): boolean { isFeatureEnabled: function(featureId: string): boolean {
// Disable labs for guests. const featuresConfig = SdkConfig.get()['features'];
if (MatrixClientPeg.get().isGuest()) return false;
const feature = this.getFeatureById(featureId); let sdkConfigValue = 'labs';
if (!feature) { if (featuresConfig && featuresConfig[featureId] !== undefined) {
console.warn(`Unknown feature "${featureId}"`); sdkConfigValue = featuresConfig[featureId];
}
if (sdkConfigValue === 'enable') {
return true;
} else if (sdkConfigValue === 'enable') {
return false;
} else if (sdkConfigValue === 'labs') {
if (!MatrixClientPeg.get().isGuest()) {
const userValue = localStorage.getItem(`mx_labs_feature_${featureId}`);
if (userValue !== null) {
return userValue === 'true';
}
}
return false;
} else {
console.warn(`Unknown features config for ${featureId}: ${sdkConfigValue}`);
return false; return false;
} }
// Return the default if this feature has an override to be the default value or
// if the feature has never been toggled and is therefore not in localStorage
if (Object.keys(feature).includes('override') ||
localStorage.getItem(`mx_labs_feature_${featureId}`) === null
) {
return feature.default;
}
return localStorage.getItem(`mx_labs_feature_${featureId}`) === 'true';
}, },
setFeatureEnabled: function(featureId: string, enabled: boolean) { setFeatureEnabled: function(featureId: string, enabled: boolean) {

View file

@ -1,6 +1,7 @@
/* /*
Copyright 2015, 2016 OpenMarket Ltd Copyright 2015, 2016 OpenMarket Ltd
Copyright 2017 Vector Creations Ltd Copyright 2017 Vector Creations Ltd
Copyright 2017 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -250,7 +251,6 @@ export default React.createClass({
page_element = <UserSettings page_element = <UserSettings
onClose={this.props.onUserSettingsClose} onClose={this.props.onUserSettingsClose}
brand={this.props.config.brand} brand={this.props.config.brand}
enableLabs={this.props.config.enableLabs}
referralBaseUrl={this.props.config.referralBaseUrl} referralBaseUrl={this.props.config.referralBaseUrl}
teamToken={this.props.teamToken} teamToken={this.props.teamToken}
/>; />;

View file

@ -1,6 +1,7 @@
/* /*
Copyright 2015, 2016 OpenMarket Ltd Copyright 2015, 2016 OpenMarket Ltd
Copyright 2017 Vector Creations Ltd Copyright 2017 Vector Creations Ltd
Copyright 2017 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -212,9 +213,6 @@ module.exports = React.createClass({
// The brand string given when creating email pushers // The brand string given when creating email pushers
brand: React.PropTypes.string, brand: React.PropTypes.string,
// True to show the 'labs' section of experimental features
enableLabs: React.PropTypes.bool,
// The base URL to use in the referral link. Defaults to window.location.origin. // The base URL to use in the referral link. Defaults to window.location.origin.
referralBaseUrl: React.PropTypes.string, referralBaseUrl: React.PropTypes.string,
@ -226,7 +224,6 @@ module.exports = React.createClass({
getDefaultProps: function() { getDefaultProps: function() {
return { return {
onClose: function() {}, onClose: function() {},
enableLabs: true,
}; };
}, },
@ -923,34 +920,25 @@ module.exports = React.createClass({
}, },
_renderLabs: function() { _renderLabs: function() {
// default to enabled if undefined
if (this.props.enableLabs === false) return null;
UserSettingsStore.doTranslations();
const features = []; const features = [];
UserSettingsStore.LABS_FEATURES.forEach((feature) => { UserSettingsStore.getLabsFeatures().forEach((featureId) => {
// This feature has an override and will be set to the default, so do not
// show it here.
if (feature.override) {
return;
}
// TODO: this ought to be a separate component so that we don't need // TODO: this ought to be a separate component so that we don't need
// to rebind the onChange each time we render // to rebind the onChange each time we render
const onChange = (e) => { const onChange = (e) => {
UserSettingsStore.setFeatureEnabled(feature.id, e.target.checked); UserSettingsStore.setFeatureEnabled(featureId, e.target.checked);
this.forceUpdate(); this.forceUpdate();
}; };
features.push( features.push(
<div key={feature.id} className="mx_UserSettings_toggle"> <div key={featureId} className="mx_UserSettings_toggle">
<input <input
type="checkbox" type="checkbox"
id={feature.id} id={featureId}
name={feature.id} name={featureId}
defaultChecked={UserSettingsStore.isFeatureEnabled(feature.id)} defaultChecked={UserSettingsStore.isFeatureEnabled(featureId)}
onChange={onChange} onChange={onChange}
/> />
<label htmlFor={feature.id}>{ feature.name }</label> <label htmlFor={featureId}>{ UserSettingsStore.translatedNameForFeature(featureId) }</label>
</div>); </div>);
}); });

View file

@ -1,5 +1,6 @@
/* /*
Copyright 2015, 2016 OpenMarket Ltd Copyright 2015, 2016 OpenMarket Ltd
Copyright 2017 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -128,15 +129,12 @@ module.exports = React.createClass({
/> />
); );
let appsDrawer = null; const appsDrawer = <AppsDrawer ref="appsDrawer"
if(UserSettingsStore.isFeatureEnabled('matrix_apps')) { room={this.props.room}
appsDrawer = <AppsDrawer ref="appsDrawer" userId={this.props.userId}
room={this.props.room} maxHeight={this.props.maxHeight}
userId={this.props.userId} showApps={this.props.showApps}
maxHeight={this.props.maxHeight} />;
showApps={this.props.showApps}
/>;
}
return ( return (
<div className="mx_RoomView_auxPanel" style={{maxHeight: this.props.maxHeight}} > <div className="mx_RoomView_auxPanel" style={{maxHeight: this.props.maxHeight}} >

View file

@ -1,5 +1,6 @@
/* /*
Copyright 2015, 2016 OpenMarket Ltd Copyright 2015, 2016 OpenMarket Ltd
Copyright 2017 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -285,18 +286,16 @@ export default class MessageComposer extends React.Component {
} }
// Apps // Apps
if (UserSettingsStore.isFeatureEnabled('matrix_apps')) { if (this.props.showApps) {
if (this.props.showApps) { hideAppsButton =
hideAppsButton = <div key="controls_hide_apps" className="mx_MessageComposer_apps" onClick={this.onHideAppsClick} title={_t("Hide Apps")}>
<div key="controls_hide_apps" className="mx_MessageComposer_apps" onClick={this.onHideAppsClick} title={_t("Hide Apps")}> <TintableSvg src="img/icons-hide-apps.svg" width="35" height="35" />
<TintableSvg src="img/icons-hide-apps.svg" width="35" height="35" /> </div>;
</div>; } else {
} else { showAppsButton =
showAppsButton = <div key="show_apps" className="mx_MessageComposer_apps" onClick={this.onShowAppsClick} title={_t("Show Apps")}>
<div key="show_apps" className="mx_MessageComposer_apps" onClick={this.onShowAppsClick} title={_t("Show Apps")}> <TintableSvg src="img/icons-show-apps.svg" width="35" height="35" />
<TintableSvg src="img/icons-show-apps.svg" width="35" height="35" /> </div>;
</div>;
}
} }
const canSendMessages = this.props.room.currentState.maySendMessage( const canSendMessages = this.props.room.currentState.maySendMessage(