summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGeorge Goldberg <george@gberg.me>2017-07-13 21:00:59 +0100
committerChristopher Speller <crspeller@gmail.com>2017-07-13 13:00:59 -0700
commita1f17c1f8482f3c38e17cabe2365c76a1a2f32d4 (patch)
tree8681a3840d9881dad385628f74310e1576a188c4
parent4eed88e0c2eebbaf04489526dfaeab7cfb77ee98 (diff)
downloadchat-a1f17c1f8482f3c38e17cabe2365c76a1a2f32d4.tar.gz
chat-a1f17c1f8482f3c38e17cabe2365c76a1a2f32d4.tar.bz2
chat-a1f17c1f8482f3c38e17cabe2365c76a1a2f32d4.zip
PLT-6474 Basic Elasticsearch System Console Page (#6825)
* PLT-6474: Basic System Console Elasticsearch Config. * Fix review comments. * More review fixes. * Review comments.
-rw-r--r--model/config.go2
-rw-r--r--utils/config.go11
-rw-r--r--webapp/actions/admin_actions.jsx13
-rw-r--r--webapp/components/admin_console/admin_sidebar.jsx16
-rw-r--r--webapp/components/admin_console/elasticsearch_settings.jsx280
-rwxr-xr-xwebapp/i18n/en.json21
-rw-r--r--webapp/routes/route_admin_console.jsx5
-rw-r--r--webapp/yarn.lock2
8 files changed, 336 insertions, 14 deletions
diff --git a/model/config.go b/model/config.go
index 3e98aa8f6..7bf891462 100644
--- a/model/config.go
+++ b/model/config.go
@@ -1662,8 +1662,6 @@ func (o *Config) Sanitize() {
o.SqlSettings.DataSourceSearchReplicas[i] = FAKE_SETTING
}
- *o.ElasticSearchSettings.ConnectionUrl = FAKE_SETTING
- *o.ElasticSearchSettings.Username = FAKE_SETTING
*o.ElasticSearchSettings.Password = FAKE_SETTING
}
diff --git a/utils/config.go b/utils/config.go
index f8ceccc2c..478e3ba99 100644
--- a/utils/config.go
+++ b/utils/config.go
@@ -536,11 +536,6 @@ func getClientConfig(c *model.Config) map[string]string {
props["PasswordRequireSymbol"] = strconv.FormatBool(*c.PasswordSettings.Symbol)
}
- if *License.Features.Elasticsearch {
- props["ElasticSearchEnableIndexing"] = strconv.FormatBool(*c.ElasticSearchSettings.EnableIndexing)
- props["ElasticSearchEnableSearching"] = strconv.FormatBool(*c.ElasticSearchSettings.EnableSearching)
- }
-
if *License.Features.Announcement {
props["EnableBanner"] = strconv.FormatBool(*c.AnnouncementSettings.EnableBanner)
props["BannerText"] = *c.AnnouncementSettings.BannerText
@@ -616,12 +611,6 @@ func Desanitize(cfg *model.Config) {
cfg.SqlSettings.AtRestEncryptKey = Cfg.SqlSettings.AtRestEncryptKey
}
- if *cfg.ElasticSearchSettings.ConnectionUrl == model.FAKE_SETTING {
- *cfg.ElasticSearchSettings.ConnectionUrl = *Cfg.ElasticSearchSettings.ConnectionUrl
- }
- if *cfg.ElasticSearchSettings.Username == model.FAKE_SETTING {
- *cfg.ElasticSearchSettings.Username = *Cfg.ElasticSearchSettings.Username
- }
if *cfg.ElasticSearchSettings.Password == model.FAKE_SETTING {
*cfg.ElasticSearchSettings.Password = *Cfg.ElasticSearchSettings.Password
}
diff --git a/webapp/actions/admin_actions.jsx b/webapp/actions/admin_actions.jsx
index fdaeb8732..ac02ac058 100644
--- a/webapp/actions/admin_actions.jsx
+++ b/webapp/actions/admin_actions.jsx
@@ -383,3 +383,16 @@ export function getPostsPerDayAnalytics(teamId) {
export function getUsersPerDayAnalytics(teamId) {
AdminActions.getUsersPerDayAnalytics(teamId)(dispatch, getState);
}
+
+export function elasticsearchTest(config, success, error) {
+ AdminActions.testElasticsearch(config)(dispatch, getState).then(
+ (data) => {
+ if (data && success) {
+ success(data);
+ } else if (data == null && error) {
+ const serverError = getState().requests.admin.testElasticsearch.error;
+ error({id: serverError.server_error_id, ...serverError});
+ }
+ }
+ );
+}
diff --git a/webapp/components/admin_console/admin_sidebar.jsx b/webapp/components/admin_console/admin_sidebar.jsx
index 1dbbff2f2..9b27ab81e 100644
--- a/webapp/components/admin_console/admin_sidebar.jsx
+++ b/webapp/components/admin_console/admin_sidebar.jsx
@@ -258,6 +258,21 @@ export default class AdminSidebar extends React.Component {
/>
);
+ let elasticSearchSettings = null;
+ if (window.mm_license.IsLicensed === 'true') {
+ elasticSearchSettings = (
+ <AdminSidebarSection
+ name='elasticsearch'
+ title={
+ <FormattedMessage
+ id='admin.sidebar.elasticsearch'
+ defaultMessage='Elasticsearch'
+ />
+ }
+ />
+ );
+ }
+
return (
<div className='admin-sidebar'>
<AdminSidebarHeader/>
@@ -618,6 +633,7 @@ export default class AdminSidebar extends React.Component {
/>
}
/>
+ {elasticSearchSettings}
<AdminSidebarSection
name='developer'
title={
diff --git a/webapp/components/admin_console/elasticsearch_settings.jsx b/webapp/components/admin_console/elasticsearch_settings.jsx
new file mode 100644
index 000000000..23ba14b25
--- /dev/null
+++ b/webapp/components/admin_console/elasticsearch_settings.jsx
@@ -0,0 +1,280 @@
+// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import React from 'react';
+
+import * as Utils from 'utils/utils.jsx';
+
+import AdminSettings from './admin_settings.jsx';
+import {elasticsearchTest} from 'actions/admin_actions.jsx';
+import BooleanSetting from './boolean_setting.jsx';
+import {FormattedMessage} from 'react-intl';
+import SettingsGroup from './settings_group.jsx';
+import TextSetting from './text_setting.jsx';
+import RequestButton from './request_button/request_button.jsx';
+
+export default class ElasticsearchSettings extends AdminSettings {
+ constructor(props) {
+ super(props);
+
+ this.getConfigFromState = this.getConfigFromState.bind(this);
+
+ this.doTestConfig = this.doTestConfig.bind(this);
+ this.handleChange = this.handleChange.bind(this);
+
+ this.renderSettings = this.renderSettings.bind(this);
+ }
+
+ getConfigFromState(config) {
+ config.ElasticSearchSettings.ConnectionUrl = this.state.connectionUrl;
+ config.ElasticSearchSettings.Username = this.state.username;
+ config.ElasticSearchSettings.Password = this.state.password;
+ config.ElasticSearchSettings.Sniff = this.state.sniff;
+ config.ElasticSearchSettings.EnableIndexing = this.state.enableIndexing;
+ config.ElasticSearchSettings.EnableSearching = this.state.enableSearching;
+
+ return config;
+ }
+
+ getStateFromConfig(config) {
+ return {
+ connectionUrl: config.ElasticSearchSettings.ConnectionUrl,
+ username: config.ElasticSearchSettings.Username,
+ password: config.ElasticSearchSettings.Password,
+ sniff: config.ElasticSearchSettings.Sniff,
+ enableIndexing: config.ElasticSearchSettings.EnableIndexing,
+ enableSearching: config.ElasticSearchSettings.EnableSearching,
+ configTested: true,
+ canSave: true
+ };
+ }
+
+ handleChange(id, value) {
+ if (id === 'enableIndexing') {
+ if (value === false) {
+ this.setState({
+ enableSearching: false
+ });
+ } else {
+ this.setState({
+ canSave: false,
+ configTested: false
+ });
+ }
+ }
+
+ if (id === 'connectionUrl' || id === 'username' || id === 'password' || id === 'sniff') {
+ this.setState({
+ configTested: false,
+ canSave: false
+ });
+ }
+
+ super.handleChange(id, value);
+ }
+
+ canSave() {
+ return this.state.canSave;
+ }
+
+ doTestConfig(success, error) {
+ const config = JSON.parse(JSON.stringify(this.props.config));
+ this.getConfigFromState(config);
+
+ elasticsearchTest(
+ config,
+ () => {
+ this.setState({
+ configTested: true,
+ canSave: true
+ });
+ success();
+ },
+ (err) => {
+ this.setState({
+ configTested: false,
+ canSave: false
+ });
+ error(err);
+ }
+ );
+ }
+
+ renderTitle() {
+ return (
+ <FormattedMessage
+ id='admin.elasticsearch.title'
+ defaultMessage='Elasticsearch Settings'
+ />
+ );
+ }
+
+ renderSettings() {
+ return (
+ <SettingsGroup>
+ <div className='banner'>
+ <div className='banner__content'>
+ <FormattedMessage
+ id='admin.elasticsearch.noteDescription'
+ defaultMessage='Changing properties in this section will require a server restart before taking effect.'
+ />
+ </div>
+ </div>
+ <BooleanSetting
+ id='enableIndexing'
+ label={
+ <FormattedMessage
+ id='admin.elasticsearch.enableIndexingTitle'
+ defaultMessage='Enable Elasticsearch Indexing:'
+ />
+ }
+ helpText={
+ <FormattedMessage
+ id='admin.elasticsearch.enableIndexingDescription'
+ defaultMessage='When true, indexing of new posts occurs automatically. Search queries will use database search until "Enable Elasticsearch for search queries" is enabled. {documentationLink}'
+ values={{
+ documentationLink: (
+ <a
+ href='http://www.mattermost.com'
+ rel='noopener noreferrer'
+ target='_blank'
+ >
+ <FormattedMessage
+ id='admin.elasticsearch.enableIndexingDescription.documentationLinkText'
+ defaultMessage='Learn more about Elasticsearch in our documentation.'
+ />
+ </a>
+ )
+ }}
+ />
+ }
+ value={this.state.enableIndexing}
+ onChange={this.handleChange}
+ />
+ <TextSetting
+ id='connectionUrl'
+ label={
+ <FormattedMessage
+ id='admin.elasticsearch.connectionUrlTitle'
+ defaultMessage='Server Connection Address:'
+ />
+ }
+ placeholder={Utils.localizeMessage('admin.elasticsearch.connectionUrlExample', 'E.g.: "https://elasticsearch.example.org:9200"')}
+ helpText={
+ <FormattedMessage
+ id='admin.elasticsearch.connectionUrlDescription'
+ defaultMessage='The address of the Elasticsearch server. {documentationLink}'
+ values={{
+ documentationLink: (
+ <a
+ href='http://www.mattermost.com'
+ rel='noopener noreferrer'
+ target='_blank'
+ >
+ <FormattedMessage
+ id='admin.elasticsearch.connectionUrlExample.documentationLinkText'
+ defaultMessage='Please see documentation with server setup instructions.'
+ />
+ </a>
+ )
+ }}
+ />
+ }
+ value={this.state.connectionUrl}
+ disabled={!this.state.enableIndexing}
+ onChange={this.handleChange}
+ />
+ <TextSetting
+ id='username'
+ label={
+ <FormattedMessage
+ id='admin.elasticsearch.usernameTitle'
+ defaultMessage='Server Username:'
+ />
+ }
+ placeholder={Utils.localizeMessage('admin.elasticsearch.usernameExample', 'E.g.: "elastic"')}
+ helpText={
+ <FormattedMessage
+ id='admin.elasticsearch.usernameDescription'
+ defaultMessage='(Optional) The username to authenticate to the Elasticsearch server.'
+ />
+ }
+ value={this.state.username}
+ disabled={!this.state.enableIndexing}
+ onChange={this.handleChange}
+ />
+ <TextSetting
+ id='password'
+ label={
+ <FormattedMessage
+ id='admin.elasticsearch.passwordTitle'
+ defaultMessage='Server Password:'
+ />
+ }
+ placeholder={Utils.localizeMessage('admin.elasticsearch.password', 'E.g.: "yourpassword"')}
+ helpText={
+ <FormattedMessage
+ id='admin.elasticsearch.passwordDescription'
+ defaultMessage='(Optional) The password to authenticate to the Elasticsearch server.'
+ />
+ }
+ value={this.state.password}
+ disabled={!this.state.enableIndexing}
+ onChange={this.handleChange}
+ />
+ <BooleanSetting
+ id='sniff'
+ label={
+ <FormattedMessage
+ id='admin.elasticsearch.sniffTitle'
+ defaultMessage='Enable Cluster Sniffing:'
+ />
+ }
+ helpText={
+ <FormattedMessage
+ id='admin.elasticsearch.sniffDescription'
+ defaultMessage='When true, sniffing finds and connects to all data nodes in your cluster automatically.'
+ />
+ }
+ value={this.state.sniff}
+ disabled={!this.state.enableIndexing}
+ onChange={this.handleChange}
+ />
+ <RequestButton
+ requestAction={this.doTestConfig}
+ helpText={
+ <FormattedMessage
+ id='admin.elasticsearch.testHelpText'
+ defaultMessage='Tests if the Mattermost server can connect to the Elasticsearch server specified. Testing the connection does not save the configuration. See log file for more detailed error messages.'
+ />
+ }
+ buttonText={
+ <FormattedMessage
+ id='admin.elasticsearch.elasticsearch_test_button'
+ defaultMessage='Test Connection'
+ />
+ }
+ disabled={!this.state.enableIndexing}
+ />
+ <BooleanSetting
+ id='enableSearching'
+ label={
+ <FormattedMessage
+ id='admin.elasticsearch.enableSearchingTitle'
+ defaultMessage='Enable Elasticsearch for search queries:'
+ />
+ }
+ helpText={
+ <FormattedMessage
+ id='admin.elasticsearch.enableSearchingDescription'
+ defaultMessage='Requires a successful connection to the Elasticsearch server. When true, Elasticsearch will be used for all search queries using the latest index. Search results may be incomplete until a bulk index of the existing post database is finished. When false, database search is used.'
+ />
+ }
+ value={this.state.enableSearching}
+ disabled={!this.state.enableIndexing || !this.state.configTested}
+ onChange={this.handleChange}
+ />
+ </SettingsGroup>
+ );
+ }
+}
diff --git a/webapp/i18n/en.json b/webapp/i18n/en.json
index c4c0951f4..684fe7329 100755
--- a/webapp/i18n/en.json
+++ b/webapp/i18n/en.json
@@ -235,6 +235,27 @@
"admin.customization.support": "Legal and Support",
"admin.database.title": "Database Settings",
"admin.developer.title": "Developer Settings",
+ "admin.elasticsearch.title": "Elasticsearch Settings",
+ "admin.elasticsearch.noteDescription": "Changing properties in this section will require a server restart before taking effect.",
+ "admin.elasticsearch.enableIndexingTitle": "Enable Elasticsearch Indexing:",
+ "admin.elasticsearch.enableIndexingDescription": "When true, indexing of new posts occurs automatically. Search queries will use database search until \"Enable Elasticsearch for search queries\" is enabled. {documentationLink}",
+ "admin.elasticsearch.enableIndexingDescription.documentationLinkText": "Learn more about Elasticsearch in our documentation.",
+ "admin.elasticsearch.connectionUrlTitle": "Server Connection Address:",
+ "admin.elasticsearch.connectionUrlDescription": "The address of the Elasticsearch server. {documentationLink}",
+ "admin.elasticsearch.connectionUrlExample.documentationLinkText": "Please see documentation with server setup instructions.",
+ "admin.elasticsearch.usernameTitle": "Server Username:",
+ "admin.elasticsearch.usernameDescription": "(Optional) The username to authenticate to the Elasticsearch server.",
+ "admin.elasticsearch.passwordTitle": "Server Password:",
+ "admin.elasticsearch.passwordDescription": "(Optional) The password to authenticate to the Elasticsearch server.",
+ "admin.elasticsearch.sniffTitle": "Enable Cluster Sniffing:",
+ "admin.elasticsearch.sniffDescription": "When true, sniffing finds and connects to all data nodes in your cluster automatically.",
+ "admin.elasticsearch.enableSearchingTitle": "Enable Elasticsearch for search queries:",
+ "admin.elasticsearch.enableSearchingDescription": "Requires a successful connection to the Elasticsearch server. When true, Elasticsearch will be used for all search queries using the latest index. Search results may be incomplete until a bulk index of the existing post database is finished. When false, database search is used.",
+ "admin.elasticsearch.connectionUrlExample": "E.g.: \"https://elasticsearch.example.org:9200\"",
+ "admin.elasticsearch.usernameExample": "E.g.: \"elastic\"",
+ "admin.elasticsearch.password": "E.g.: \"yourpassword\"",
+ "admin.elasticsearch.testHelpText": "Tests if the Mattermost server can connect to the Elasticsearch server specified. Testing the connection does not save the configuration. See log file for more detailed error messages.",
+ "admin.elasticsearch.elasticsearch_test_button": "Test Connection",
"admin.email.agreeHPNS": " I understand and accept the Mattermost Hosted Push Notification Service <a href=\"https://about.mattermost.com/hpns-terms/\" target='_blank'>Terms of Service</a> and <a href=\"https://about.mattermost.com/hpns-privacy/\" target='_blank'>Privacy Policy</a>.",
"admin.email.allowEmailSignInDescription": "When true, Mattermost allows users to sign in using their email and password.",
"admin.email.allowEmailSignInTitle": "Enable sign-in with email: ",
diff --git a/webapp/routes/route_admin_console.jsx b/webapp/routes/route_admin_console.jsx
index b0b6ebf62..17e0290c2 100644
--- a/webapp/routes/route_admin_console.jsx
+++ b/webapp/routes/route_admin_console.jsx
@@ -45,6 +45,7 @@ import TeamAnalytics from 'components/analytics/team_analytics';
import LicenseSettings from 'components/admin_console/license_settings.jsx';
import Audits from 'components/admin_console/audits';
import Logs from 'components/admin_console/server_logs';
+import ElasticsearchSettings from 'components/admin_console/elasticsearch_settings.jsx';
export default (
<Route>
@@ -200,6 +201,10 @@ export default (
component={DatabaseSettings}
/>
<Route
+ path='elasticsearch'
+ component={ElasticsearchSettings}
+ />
+ <Route
path='developer'
component={DeveloperSettings}
/>
diff --git a/webapp/yarn.lock b/webapp/yarn.lock
index ed9c41742..21ac7dbef 100644
--- a/webapp/yarn.lock
+++ b/webapp/yarn.lock
@@ -5047,7 +5047,7 @@ math-expression-evaluator@^1.2.14:
mattermost-redux@mattermost/mattermost-redux#webapp-master:
version "0.0.1"
- resolved "https://codeload.github.com/mattermost/mattermost-redux/tar.gz/dd48556075c8be41aa5ac4a0165bbe830d496875"
+ resolved "https://codeload.github.com/mattermost/mattermost-redux/tar.gz/a850fc2696c7083a068f7852c1d4b8bce0ec72ba"
dependencies:
deep-equal "1.0.1"
harmony-reflect "1.5.1"