Configs for themes in Display Settings: hide themes options, hide custom themes, specific list of themes (#7173)

* Add configuration to enable or disable choosing themes in Display Settings. Only for Licensed servers.

* Add configuration to enable or disable choosing custom themes in Display Settings. Only for Licensed servers.

* Add configuration to enable or disable a specific list of themes to choose in Display Settings. Only for Licensed servers.

* Added config value and logic for "DefaultTheme"

* Fix problem with undefined values when the server is not licensed
Этот коммит содержится в:
David Meza
2017-09-05 19:28:46 -05:00
коммит произвёл Chris
родитель 7cee7b3342
Коммит 1605fa5102
9 изменённых файлов: 163 добавлений и 83 удалений

Просмотреть файл

@@ -26,6 +26,7 @@ const (
TRACK_CONFIG_RATE = "config_rate" TRACK_CONFIG_RATE = "config_rate"
TRACK_CONFIG_EMAIL = "config_email" TRACK_CONFIG_EMAIL = "config_email"
TRACK_CONFIG_PRIVACY = "config_privacy" TRACK_CONFIG_PRIVACY = "config_privacy"
TRACK_CONFIG_THEME = "config_theme"
TRACK_CONFIG_OAUTH = "config_oauth" TRACK_CONFIG_OAUTH = "config_oauth"
TRACK_CONFIG_LDAP = "config_ldap" TRACK_CONFIG_LDAP = "config_ldap"
TRACK_CONFIG_COMPLIANCE = "config_compliance" TRACK_CONFIG_COMPLIANCE = "config_compliance"
@@ -331,6 +332,13 @@ func trackConfig() {
"show_full_name": utils.Cfg.PrivacySettings.ShowFullName, "show_full_name": utils.Cfg.PrivacySettings.ShowFullName,
}) })
SendDiagnostic(TRACK_CONFIG_THEME, map[string]interface{}{
"enable_theme_selection": *utils.Cfg.ThemeSettings.EnableThemeSelection,
"isdefault_default_theme": isDefault(*utils.Cfg.ThemeSettings.DefaultTheme, model.TEAM_SETTINGS_DEFAULT_TEAM_TEXT),
"allow_custom_themes": *utils.Cfg.ThemeSettings.AllowCustomThemes,
"allowed_themes": len(utils.Cfg.ThemeSettings.AllowedThemes),
})
SendDiagnostic(TRACK_CONFIG_OAUTH, map[string]interface{}{ SendDiagnostic(TRACK_CONFIG_OAUTH, map[string]interface{}{
"enable_gitlab": utils.Cfg.GitLabSettings.Enable, "enable_gitlab": utils.Cfg.GitLabSettings.Enable,
"enable_google": utils.Cfg.GoogleSettings.Enable, "enable_google": utils.Cfg.GoogleSettings.Enable,

Просмотреть файл

@@ -186,6 +186,12 @@
"BannerTextColor": "#333333", "BannerTextColor": "#333333",
"AllowBannerDismissal": true "AllowBannerDismissal": true
}, },
"ThemeSettings": {
"EnableThemeSelection": true,
"DefaultTheme": "default",
"AllowCustomThemes": true,
"AllowedThemes": []
},
"GitLabSettings": { "GitLabSettings": {
"Enable": false, "Enable": false,
"Secret": "", "Secret": "",

Просмотреть файл

@@ -132,6 +132,8 @@ const (
ANNOUNCEMENT_SETTINGS_DEFAULT_BANNER_COLOR = "#f2a93b" ANNOUNCEMENT_SETTINGS_DEFAULT_BANNER_COLOR = "#f2a93b"
ANNOUNCEMENT_SETTINGS_DEFAULT_BANNER_TEXT_COLOR = "#333333" ANNOUNCEMENT_SETTINGS_DEFAULT_BANNER_TEXT_COLOR = "#333333"
TEAM_SETTINGS_DEFAULT_TEAM_TEXT = "default"
ELASTICSEARCH_SETTINGS_DEFAULT_CONNECTION_URL = "" ELASTICSEARCH_SETTINGS_DEFAULT_CONNECTION_URL = ""
ELASTICSEARCH_SETTINGS_DEFAULT_USERNAME = "" ELASTICSEARCH_SETTINGS_DEFAULT_USERNAME = ""
ELASTICSEARCH_SETTINGS_DEFAULT_PASSWORD = "" ELASTICSEARCH_SETTINGS_DEFAULT_PASSWORD = ""
@@ -335,6 +337,13 @@ type AnnouncementSettings struct {
AllowBannerDismissal *bool AllowBannerDismissal *bool
} }
type ThemeSettings struct {
EnableThemeSelection *bool
DefaultTheme *string
AllowCustomThemes *bool
AllowedThemes []string
}
type TeamSettings struct { type TeamSettings struct {
SiteName string SiteName string
MaxUsersPerTeam *int MaxUsersPerTeam *int
@@ -500,6 +509,7 @@ type Config struct {
PrivacySettings PrivacySettings PrivacySettings PrivacySettings
SupportSettings SupportSettings SupportSettings SupportSettings
AnnouncementSettings AnnouncementSettings AnnouncementSettings AnnouncementSettings
ThemeSettings ThemeSettings
GitLabSettings SSOSettings GitLabSettings SSOSettings
GoogleSettings SSOSettings GoogleSettings SSOSettings
Office365Settings SSOSettings Office365Settings SSOSettings
@@ -1003,6 +1013,25 @@ func (o *Config) SetDefaults() {
*o.AnnouncementSettings.AllowBannerDismissal = true *o.AnnouncementSettings.AllowBannerDismissal = true
} }
if o.ThemeSettings.EnableThemeSelection == nil {
o.ThemeSettings.EnableThemeSelection = new(bool)
*o.ThemeSettings.EnableThemeSelection = true
}
if o.ThemeSettings.DefaultTheme == nil {
o.ThemeSettings.DefaultTheme = new(string)
*o.ThemeSettings.DefaultTheme = TEAM_SETTINGS_DEFAULT_TEAM_TEXT
}
if o.ThemeSettings.AllowCustomThemes == nil {
o.ThemeSettings.AllowCustomThemes = new(bool)
*o.ThemeSettings.AllowCustomThemes = true
}
if o.ThemeSettings.AllowedThemes == nil {
o.ThemeSettings.AllowedThemes = []string{}
}
if o.LdapSettings.Enable == nil { if o.LdapSettings.Enable == nil {
o.LdapSettings.Enable = new(bool) o.LdapSettings.Enable = new(bool)
*o.LdapSettings.Enable = false *o.LdapSettings.Enable = false

Просмотреть файл

@@ -51,6 +51,7 @@ type Features struct {
PasswordRequirements *bool `json:"password_requirements"` PasswordRequirements *bool `json:"password_requirements"`
Elasticsearch *bool `json:"elastic_search"` Elasticsearch *bool `json:"elastic_search"`
Announcement *bool `json:"announcement"` Announcement *bool `json:"announcement"`
ThemeManagement *bool `json:"theme_management"`
EmailNotificationContents *bool `json:"email_notification_contents"` EmailNotificationContents *bool `json:"email_notification_contents"`
// after we enabled more features for webrtc we'll need to control them with this // after we enabled more features for webrtc we'll need to control them with this
@@ -152,6 +153,11 @@ func (f *Features) SetDefaults() {
*f.Announcement = true *f.Announcement = true
} }
if f.ThemeManagement == nil {
f.ThemeManagement = new(bool)
*f.ThemeManagement = true
}
if f.EmailNotificationContents == nil { if f.EmailNotificationContents == nil {
f.EmailNotificationContents = new(bool) f.EmailNotificationContents = new(bool)
*f.EmailNotificationContents = *f.FutureFeatures *f.EmailNotificationContents = *f.FutureFeatures

Просмотреть файл

@@ -539,7 +539,6 @@ func getClientConfig(c *model.Config) map[string]string {
props["PluginsEnabled"] = strconv.FormatBool(*c.PluginSettings.Enable) props["PluginsEnabled"] = strconv.FormatBool(*c.PluginSettings.Enable)
if IsLicensed() { if IsLicensed() {
License := License() License := License()
props["ExperimentalTownSquareIsReadOnly"] = strconv.FormatBool(*c.TeamSettings.ExperimentalTownSquareIsReadOnly) props["ExperimentalTownSquareIsReadOnly"] = strconv.FormatBool(*c.TeamSettings.ExperimentalTownSquareIsReadOnly)
@@ -605,6 +604,13 @@ func getClientConfig(c *model.Config) map[string]string {
props["BannerTextColor"] = *c.AnnouncementSettings.BannerTextColor props["BannerTextColor"] = *c.AnnouncementSettings.BannerTextColor
props["AllowBannerDismissal"] = strconv.FormatBool(*c.AnnouncementSettings.AllowBannerDismissal) props["AllowBannerDismissal"] = strconv.FormatBool(*c.AnnouncementSettings.AllowBannerDismissal)
} }
if *License.Features.ThemeManagement {
props["EnableThemeSelection"] = strconv.FormatBool(*c.ThemeSettings.EnableThemeSelection)
props["DefaultTheme"] = *c.ThemeSettings.DefaultTheme
props["AllowCustomThemes"] = strconv.FormatBool(*c.ThemeSettings.AllowCustomThemes)
props["AllowedThemes"] = strings.Join(c.ThemeSettings.AllowedThemes, ",")
}
} }
return props return props

Просмотреть файл

@@ -18,8 +18,15 @@ export default class PremadeThemeChooser extends React.Component {
const theme = this.props.theme; const theme = this.props.theme;
const premadeThemes = []; const premadeThemes = [];
const allowedThemes = global.mm_config.AllowedThemes ? global.mm_config.AllowedThemes.split(',') : [];
const hasAllowedThemes = allowedThemes.length > 1 || (allowedThemes[0] && allowedThemes[0].trim().length > 0);
for (const k in Constants.THEMES) { for (const k in Constants.THEMES) {
if (Constants.THEMES.hasOwnProperty(k)) { if (Constants.THEMES.hasOwnProperty(k)) {
if (hasAllowedThemes && allowedThemes.indexOf(k) < 0) {
continue;
}
const premadeTheme = $.extend(true, {}, Constants.THEMES[k]); const premadeTheme = $.extend(true, {}, Constants.THEMES[k]);
let activeClass = ''; let activeClass = '';

Просмотреть файл

@@ -595,6 +595,18 @@ export default class UserSettingsDisplay extends React.Component {
); );
} }
let themeSection;
if (global.mm_config.EnableThemeSelection !== 'false') {
themeSection = (
<ThemeSetting
selected={this.props.activeSection === 'theme'}
updateSection={this.updateSection}
setRequireConfirm={this.props.setRequireConfirm}
setEnforceFocus={this.props.setEnforceFocus}
/>
);
}
return ( return (
<div> <div>
<div className='modal-header'> <div className='modal-header'>
@@ -632,12 +644,7 @@ export default class UserSettingsDisplay extends React.Component {
/> />
</h3> </h3>
<div className='divider-dark first'/> <div className='divider-dark first'/>
<ThemeSetting {themeSection}
selected={this.props.activeSection === 'theme'}
updateSection={this.updateSection}
setRequireConfirm={this.props.setRequireConfirm}
setEnforceFocus={this.props.setEnforceFocus}
/>
<div className='divider-dark'/> <div className='divider-dark'/>
{clockSection} {clockSection}
<div className='divider-dark'/> <div className='divider-dark'/>

Просмотреть файл

@@ -180,10 +180,11 @@ export default class ThemeSetting extends React.Component {
} }
const displayCustom = this.state.type === 'custom'; const displayCustom = this.state.type === 'custom';
const allowCustomThemes = global.mm_config.AllowCustomThemes !== 'false';
let custom; let custom;
let premade; let premade;
if (displayCustom) { if (displayCustom && allowCustomThemes) {
custom = ( custom = (
<div key='customThemeChooser'> <div key='customThemeChooser'>
<CustomThemeChooser <CustomThemeChooser
@@ -208,87 +209,91 @@ export default class ThemeSetting extends React.Component {
if (this.props.selected) { if (this.props.selected) {
const inputs = []; const inputs = [];
inputs.push( if (allowCustomThemes) {
<div inputs.push(
className='radio' <div
key='premadeThemeColorLabel' className='radio'
> key='premadeThemeColorLabel'
<label> >
<input <label>
id='standardThemes' <input
type='radio' id='standardThemes'
name='theme' type='radio'
checked={!displayCustom} name='theme'
onChange={this.updateType.bind(this, 'premade')} checked={!displayCustom}
/> onChange={this.updateType.bind(this, 'premade')}
<FormattedMessage />
id='user.settings.display.theme.themeColors' <FormattedMessage
defaultMessage='Theme Colors' id='user.settings.display.theme.themeColors'
/> defaultMessage='Theme Colors'
</label> />
<br/> </label>
</div> <br/>
); </div>
);
}
inputs.push(premade); inputs.push(premade);
inputs.push( if (allowCustomThemes) {
<div inputs.push(
className='radio' <div
key='customThemeColorLabel' className='radio'
> key='customThemeColorLabel'
<label>
<input
id='customThemes'
type='radio'
name='theme'
checked={displayCustom}
onChange={this.updateType.bind(this, 'custom')}
/>
<FormattedMessage
id='user.settings.display.theme.customTheme'
defaultMessage='Custom Theme'
/>
</label>
</div>
);
inputs.push(custom);
inputs.push(
<div key='otherThemes'>
<br/>
<a
id='otherThemes'
href='http://docs.mattermost.com/help/settings/theme-colors.html#custom-theme-examples'
target='_blank'
rel='noopener noreferrer'
> >
<FormattedMessage <label>
id='user.settings.display.theme.otherThemes' <input
defaultMessage='See other themes' id='customThemes'
/> type='radio'
</a> name='theme'
</div> checked={displayCustom}
); onChange={this.updateType.bind(this, 'custom')}
/>
<FormattedMessage
id='user.settings.display.theme.customTheme'
defaultMessage='Custom Theme'
/>
</label>
</div>
);
inputs.push( inputs.push(custom);
<div
key='importSlackThemeButton' inputs.push(
className='padding-top' <div key='otherThemes'>
> <br/>
<a <a
id='slackImportTheme' id='otherThemes'
className='theme' href='http://docs.mattermost.com/help/settings/theme-colors.html#custom-theme-examples'
onClick={this.handleImportModal} target='_blank'
rel='noopener noreferrer'
>
<FormattedMessage
id='user.settings.display.theme.otherThemes'
defaultMessage='See other themes'
/>
</a>
</div>
);
inputs.push(
<div
key='importSlackThemeButton'
className='padding-top'
> >
<FormattedMessage <a
id='user.settings.display.theme.import' id='slackImportTheme'
defaultMessage='Import theme colors from Slack' className='theme'
/> onClick={this.handleImportModal}
</a> >
</div> <FormattedMessage
); id='user.settings.display.theme.import'
defaultMessage='Import theme colors from Slack'
/>
</a>
</div>
);
}
let allTeamsCheckbox = null; let allTeamsCheckbox = null;
if (this.state.showAllTeamsCheckbox) { if (this.state.showAllTeamsCheckbox) {

Просмотреть файл

@@ -141,6 +141,12 @@ class PreferenceStore extends EventEmitter {
return this.getObject(Constants.Preferences.CATEGORY_THEME, ''); return this.getObject(Constants.Preferences.CATEGORY_THEME, '');
} }
for (const k in Constants.THEMES) {
if (Constants.THEMES.hasOwnProperty(k) && k === global.mm_config.DefaultTheme) {
return Constants.THEMES[k];
}
}
return Constants.THEMES.default; return Constants.THEMES.default;
} }