From c8ca70870f1e202eb5784839520199fdf0beaeec Mon Sep 17 00:00:00 2001 From: Elias Nahum Date: Wed, 27 Jan 2016 15:49:26 -0300 Subject: PLT-7: Refactoring frontend (chunk 2) - System Console complete --- web/react/components/admin_console/analytics.jsx | 119 ++++++-- .../components/admin_console/gitlab_settings.jsx | 150 ++++++++-- .../components/admin_console/image_settings.jsx | 295 +++++++++++++++---- .../components/admin_console/ldap_settings.jsx | 266 +++++++++++++---- .../admin_console/legal_and_support_settings.jsx | 100 ++++++- .../components/admin_console/license_settings.jsx | 153 ++++++---- .../components/admin_console/log_settings.jsx | 173 +++++++++-- web/react/components/admin_console/logs.jsx | 14 +- .../components/admin_console/privacy_settings.jsx | 72 ++++- .../components/admin_console/rate_settings.jsx | 141 +++++++-- .../admin_console/reset_password_modal.jsx | 38 ++- .../components/admin_console/service_settings.jsx | 322 +++++++++++++++++---- .../components/admin_console/sql_settings.jsx | 145 ++++++++-- .../components/admin_console/system_analytics.jsx | 29 +- .../components/admin_console/team_analytics.jsx | 23 +- .../components/admin_console/team_settings.jsx | 171 +++++++++-- web/react/components/admin_console/team_users.jsx | 23 +- web/react/components/admin_console/user_item.jsx | 60 +++- 18 files changed, 1857 insertions(+), 437 deletions(-) (limited to 'web/react/components/admin_console') diff --git a/web/react/components/admin_console/analytics.jsx b/web/react/components/admin_console/analytics.jsx index 70ef1ecab..ff5903c62 100644 --- a/web/react/components/admin_console/analytics.jsx +++ b/web/react/components/admin_console/analytics.jsx @@ -8,6 +8,8 @@ import LineChart from './line_chart.jsx'; var Tooltip = ReactBootstrap.Tooltip; var OverlayTrigger = ReactBootstrap.OverlayTrigger; +import {FormattedMessage} from 'mm-intl'; + export default class Analytics extends React.Component { constructor(props) { super(props); @@ -21,11 +23,23 @@ export default class Analytics extends React.Component { serverError =
; } + let loading = ( + + ); + var totalCount = (
-
{'Total Users'}
-
{this.props.uniqueUserCount == null ? 'Loading...' : this.props.uniqueUserCount}
+
+ +
+
{this.props.uniqueUserCount == null ? loading : this.props.uniqueUserCount}
); @@ -33,8 +47,13 @@ export default class Analytics extends React.Component { var openChannelCount = (
-
{'Public Channels'}
-
{this.props.channelOpenCount == null ? 'Loading...' : this.props.channelOpenCount}
+
+ +
+
{this.props.channelOpenCount == null ? loading : this.props.channelOpenCount}
); @@ -42,8 +61,13 @@ export default class Analytics extends React.Component { var openPrivateCount = (
-
{'Private Groups'}
-
{this.props.channelPrivateCount == null ? 'Loading...' : this.props.channelPrivateCount}
+
+ +
+
{this.props.channelPrivateCount == null ? loading : this.props.channelPrivateCount}
); @@ -51,8 +75,13 @@ export default class Analytics extends React.Component { var postCount = (
-
{'Total Posts'}
-
{this.props.postCount == null ? 'Loading...' : this.props.postCount}
+
+ +
+
{this.props.postCount == null ? loading : this.props.postCount}
); @@ -60,8 +89,13 @@ export default class Analytics extends React.Component { var postCountsByDay = (
-
{'Total Posts'}
-
{'Loading...'}
+
+ +
+
{loading}
); @@ -69,7 +103,12 @@ export default class Analytics extends React.Component { if (this.props.postCountsDay != null) { let content; if (this.props.postCountsDay.labels.length === 0) { - content = 'Not enough data for a meaningful representation.'; + content = ( + + ); } else { content = (
-
{'Total Posts'}
+
+ +
{content}
@@ -94,8 +138,13 @@ export default class Analytics extends React.Component { var usersWithPostsByDay = (
-
{'Active Users With Posts'}
-
{'Loading...'}
+
+ +
+
{loading}
); @@ -103,7 +152,12 @@ export default class Analytics extends React.Component { if (this.props.userCountsWithPostsDay != null) { let content; if (this.props.userCountsWithPostsDay.labels.length === 0) { - content = 'Not enough data for a meaningful representation.'; + content = ( + + ); } else { content = (
-
{'Active Users With Posts'}
+
+ +
{content}
@@ -129,7 +188,7 @@ export default class Analytics extends React.Component { if (this.props.recentActiveUsers != null) { let content; if (this.props.recentActiveUsers.length === 0) { - content = 'Loading...'; + content = loading; } else { content = ( @@ -167,7 +226,12 @@ export default class Analytics extends React.Component { recentActiveUser = (
-
{'Recent Active Users'}
+
+ +
{content}
@@ -180,7 +244,7 @@ export default class Analytics extends React.Component { if (this.props.newlyCreatedUsers != null) { let content; if (this.props.newlyCreatedUsers.length === 0) { - content = 'Loading...'; + content = loading; } else { content = (
@@ -218,7 +282,12 @@ export default class Analytics extends React.Component { newUsers = (
-
{'Newly Created Users'}
+
+ +
{content}
@@ -229,7 +298,15 @@ export default class Analytics extends React.Component { return (
-

{'Statistics for ' + this.props.title}

+

+ +

{serverError}
{totalCount} diff --git a/web/react/components/admin_console/gitlab_settings.jsx b/web/react/components/admin_console/gitlab_settings.jsx index 8c689a2d8..744fa3b19 100644 --- a/web/react/components/admin_console/gitlab_settings.jsx +++ b/web/react/components/admin_console/gitlab_settings.jsx @@ -4,7 +4,36 @@ import * as Client from '../../utils/client.jsx'; import * as AsyncClient from '../../utils/async_client.jsx'; -export default class GitLabSettings extends React.Component { +import {injectIntl, intlShape, defineMessages, FormattedMessage, FormattedHTMLMessage} from 'mm-intl'; + +const holders = defineMessages({ + clientIdExample: { + id: 'admin.gitlab.clientIdExample', + defaultMessage: 'Ex "jcuS8PuvcpGhpgHhlcpT1Mx42pnqMxQY"' + }, + clientSecretExample: { + id: 'admin.gitlab.clientSecretExample', + defaultMessage: 'Ex "jcuS8PuvcpGhpgHhlcpT1Mx42pnqMxQY"' + }, + authExample: { + id: 'admin.gitlab.authExample', + defaultMessage: 'Ex ""' + }, + tokenExample: { + id: 'admin.gitlab.tokenExample', + defaultMessage: 'Ex ""' + }, + userExample: { + id: 'admin.gitlab.userExample', + defaultMessage: 'Ex ""' + }, + saving: { + id: 'admin.gitlab.saving', + defaultMessage: 'Saving Config...' + } +}); + +class GitLabSettings extends React.Component { constructor(props) { super(props); @@ -65,6 +94,7 @@ export default class GitLabSettings extends React.Component { } render() { + const {formatMessage} = this.props.intl; var serverError = ''; if (this.state.serverError) { serverError =
; @@ -78,7 +108,12 @@ export default class GitLabSettings extends React.Component { return (
-

{'GitLab Settings'}

+

+ +

- {'Enable Sign Up With GitLab: '} +

- {'When true, Mattermost allows team creation and account signup using GitLab OAuth.'}
+ +

-
    -
  1. {'Log in to your GitLab account and go to Applications -> Profile Settings.'}
  2. -
  3. {'Enter Redirect URIs "/login/gitlab/complete" (example: http://localhost:8065/login/gitlab/complete) and "/signup/gitlab/complete". '}
  4. -
  5. {'Then use "Secret" and "Id" fields from GitLab to complete the options below.'}
  6. -
  7. {'Complete the Endpoint URLs below. '}
  8. -
+
@@ -132,7 +178,10 @@ export default class GitLabSettings extends React.Component { className='control-label col-sm-4' htmlFor='Id' > - {'Id:'} +
-

{'Obtain this value via the instructions above for logging into GitLab'}

+

+ +

@@ -154,7 +208,10 @@ export default class GitLabSettings extends React.Component { className='control-label col-sm-4' htmlFor='Secret' > - {'Secret:'} +
-

{'Obtain this value via the instructions above for logging into GitLab.'}

+

+ +

@@ -176,7 +238,10 @@ export default class GitLabSettings extends React.Component { className='control-label col-sm-4' htmlFor='AuthEndpoint' > - {'Auth Endpoint:'} +
-

{'Enter https:///oauth/authorize (example https://example.com:3000/oauth/authorize). Make sure you use HTTP or HTTPS in your URL depending on your server configuration.'}

+

+ +

@@ -198,7 +268,10 @@ export default class GitLabSettings extends React.Component { className='control-label col-sm-4' htmlFor='TokenEndpoint' > - {'Token Endpoint:'} +
-

{'Enter https:///oauth/token. Make sure you use HTTP or HTTPS in your URL depending on your server configuration.'}

+

+ +

@@ -220,7 +298,10 @@ export default class GitLabSettings extends React.Component { className='control-label col-sm-4' htmlFor='UserApiEndpoint' > - {'User API Endpoint:'} +
-

{'Enter https:///api/v3/user. Make sure you use HTTP or HTTPS in your URL depending on your server configuration.'}

+

+ +

@@ -246,9 +332,12 @@ export default class GitLabSettings extends React.Component { className={saveClass} onClick={this.handleSubmit} id='save-button' - data-loading-text={' Saving Config...'} + data-loading-text={' ' + formatMessage(holders.saving)} > - {'Save'} + @@ -283,5 +372,8 @@ export default class GitLabSettings extends React.Component { // GitLabSettings.propTypes = { + intl: intlShape.isRequired, config: React.PropTypes.object }; + +export default injectIntl(GitLabSettings); \ No newline at end of file diff --git a/web/react/components/admin_console/image_settings.jsx b/web/react/components/admin_console/image_settings.jsx index e1ffad7d3..12bf554ea 100644 --- a/web/react/components/admin_console/image_settings.jsx +++ b/web/react/components/admin_console/image_settings.jsx @@ -5,7 +5,76 @@ import * as Client from '../../utils/client.jsx'; import * as AsyncClient from '../../utils/async_client.jsx'; import crypto from 'crypto'; -export default class FileSettings extends React.Component { +import {injectIntl, intlShape, defineMessages, FormattedMessage} from 'mm-intl'; + +const holders = defineMessages({ + storeDisabled: { + id: 'admin.image.storeDisabled', + defaultMessage: 'Disable File Storage' + }, + storeLocal: { + id: 'admin.image.storeLocal', + defaultMessage: 'Local File System' + }, + storeAmazonS3: { + id: 'admin.image.storeAmazonS3', + defaultMessage: 'Amazon S3' + }, + localExample: { + id: 'admin.image.localExample', + defaultMessage: 'Ex "./data/"' + }, + amazonS3IdExample: { + id: 'admin.image.amazonS3IdExample', + defaultMessage: 'Ex "AKIADTOVBGERKLCBV"' + }, + amazonS3SecretExample: { + id: 'admin.image.amazonS3SecretExample', + defaultMessage: 'Ex "jcuS8PuvcpGhpgHhlcpT1Mx42pnqMxQY"' + }, + amazonS3BucketExample: { + id: 'admin.image.amazonS3BucketExample', + defaultMessage: 'Ex "mattermost-media"' + }, + amazonS3RegionExample: { + id: 'admin.image.amazonS3RegionExample', + defaultMessage: 'Ex "us-east-1"' + }, + thumbWidthExample: { + id: 'admin.image.thumbWidthExample', + defaultMessage: 'Ex "120"' + }, + thumbHeightExample: { + id: 'admin.image.thumbHeightExample', + defaultMessage: 'Ex "100"' + }, + previewWidthExample: { + id: 'admin.image.previewWidthExample', + defaultMessage: 'Ex "1024"' + }, + previewHeightExample: { + id: 'admin.image.previewHeightExample', + defaultMessage: 'Ex "0"' + }, + profileWidthExample: { + id: 'admin.image.profileWidthExample', + defaultMessage: 'Ex "1024"' + }, + profileHeightExample: { + id: 'admin.image.profileHeightExample', + defaultMessage: 'Ex "0"' + }, + publicLinkExample: { + id: 'admin.image.publicLinkExample', + defaultMessage: 'Ex "gxHVDcKUyP2y1eiyW8S8na1UYQAfq6J6"' + }, + saving: { + id: 'admin.image.saving', + defaultMessage: 'Saving Config...' + } +}); + +class FileSettings extends React.Component { constructor(props) { super(props); @@ -120,6 +189,7 @@ export default class FileSettings extends React.Component { } render() { + const {formatMessage} = this.props.intl; var serverError = ''; if (this.state.serverError) { serverError =
; @@ -143,7 +213,12 @@ export default class FileSettings extends React.Component { return (
-

{'File Settings'}

+

+ +

- {'Store Files In:'} +
@@ -176,7 +254,10 @@ export default class FileSettings extends React.Component { className='control-label col-sm-4' htmlFor='Directory' > - {'Local Directory Location:'} +
-

{'Directory to which image files are written. If blank, will be set to ./data/.'}

+

+ +

@@ -198,7 +284,10 @@ export default class FileSettings extends React.Component { className='control-label col-sm-4' htmlFor='AmazonS3AccessKeyId' > - {'Amazon S3 Access Key Id:'} +
-

{'Obtain this credential from your Amazon EC2 administrator.'}

+

+ +

@@ -220,7 +314,10 @@ export default class FileSettings extends React.Component { className='control-label col-sm-4' htmlFor='AmazonS3SecretAccessKey' > - {'Amazon S3 Secret Access Key:'} +
-

{'Obtain this credential from your Amazon EC2 administrator.'}

+

+ +

@@ -242,7 +344,10 @@ export default class FileSettings extends React.Component { className='control-label col-sm-4' htmlFor='AmazonS3Bucket' > - {'Amazon S3 Bucket:'} +
-

{'Name you selected for your S3 bucket in AWS.'}

+

+ +

@@ -264,7 +374,10 @@ export default class FileSettings extends React.Component { className='control-label col-sm-4' htmlFor='AmazonS3Region' > - {'Amazon S3 Region:'} +
-

{'AWS region you selected for creating your S3 bucket.'}

+

+ +

@@ -286,7 +404,10 @@ export default class FileSettings extends React.Component { className='control-label col-sm-4' htmlFor='ThumbnailWidth' > - {'Thumbnail Width:'} +
-

{'Width of thumbnails generated from uploaded images. Updating this value changes how thumbnail images render in future, but does not change images created in the past.'}

+

+ +

@@ -307,7 +433,10 @@ export default class FileSettings extends React.Component { className='control-label col-sm-4' htmlFor='ThumbnailHeight' > - {'Thumbnail Height:'} +
-

{'Height of thumbnails generated from uploaded images. Updating this value changes how thumbnail images render in future, but does not change images created in the past.'}

+

+ +

@@ -328,7 +462,10 @@ export default class FileSettings extends React.Component { className='control-label col-sm-4' htmlFor='PreviewWidth' > - {'Preview Width:'} +
-

{'Maximum width of preview image. Updating this value changes how preview images render in future, but does not change images created in the past.'}

+

+ +

@@ -349,7 +491,10 @@ export default class FileSettings extends React.Component { className='control-label col-sm-4' htmlFor='PreviewHeight' > - {'Preview Height:'} +
-

{'Maximum height of preview image ("0": Sets to auto-size). Updating this value changes how preview images render in future, but does not change images created in the past.'}

+

+ +

@@ -370,7 +520,10 @@ export default class FileSettings extends React.Component { className='control-label col-sm-4' htmlFor='ProfileWidth' > - {'Profile Width:'} +
-

{'Width of profile picture.'}

+

+ +

@@ -391,7 +549,10 @@ export default class FileSettings extends React.Component { className='control-label col-sm-4' htmlFor='ProfileHeight' > - {'Profile Height:'} +
-

{'Height of profile picture.'}

+

+ +

@@ -412,7 +578,10 @@ export default class FileSettings extends React.Component { className='control-label col-sm-4' htmlFor='EnablePublicLink' > - {'Share Public File Link: '} +
-

{'Allow users to share public links to files and images.'}

+

+ +

@@ -445,7 +625,10 @@ export default class FileSettings extends React.Component { className='control-label col-sm-4' htmlFor='PublicLinkSalt' > - {'Public Link Salt:'} +
-

{'32-character salt added to signing of public image links. Randomly generated on install. Click "Re-Generate" to create new salt.'}

+

+ +

@@ -478,9 +669,12 @@ export default class FileSettings extends React.Component { className={saveClass} onClick={this.handleSubmit} id='save-button' - data-loading-text={' Saving Config...'} + data-loading-text={' ' + formatMessage(holders.saving)} > - {'Save'} + @@ -492,5 +686,8 @@ export default class FileSettings extends React.Component { } FileSettings.propTypes = { + intl: intlShape.isRequired, config: React.PropTypes.object }; + +export default injectIntl(FileSettings); \ No newline at end of file diff --git a/web/react/components/admin_console/ldap_settings.jsx b/web/react/components/admin_console/ldap_settings.jsx index 1447f3bd7..bc13b3bcd 100644 --- a/web/react/components/admin_console/ldap_settings.jsx +++ b/web/react/components/admin_console/ldap_settings.jsx @@ -4,10 +4,55 @@ import * as Client from '../../utils/client.jsx'; import * as AsyncClient from '../../utils/async_client.jsx'; +import {injectIntl, intlShape, defineMessages, FormattedMessage, FormattedHTMLMessage} from 'mm-intl'; + const DEFAULT_LDAP_PORT = 389; const DEFAULT_QUERY_TIMEOUT = 60; -export default class LdapSettings extends React.Component { +var holders = defineMessages({ + serverEx: { + id: 'admin.ldap.serverEx', + defaultMessage: 'Ex "10.0.0.23"' + }, + portEx: { + id: 'admin.ldap.portEx', + defaultMessage: 'Ex "389"' + }, + baseEx: { + id: 'admin.ldap.baseEx', + defaultMessage: 'Ex "dc=mydomain,dc=com"' + }, + firstnameAttrEx: { + id: 'admin.ldap.firstnameAttrEx', + defaultMessage: 'Ex "givenName"' + }, + lastnameAttrEx: { + id: 'admin.ldap.lastnameAttrEx', + defaultMessage: 'Ex "sn"' + }, + emailAttrEx: { + id: 'admin.ldap.emailAttrEx', + defaultMessage: 'Ex "mail"' + }, + usernameAttrEx: { + id: 'admin.ldap.usernameAttrEx', + defaultMessage: 'Ex "sAMAccountName"' + }, + idAttrEx: { + id: 'admin.ldap.idAttrEx', + defaultMessage: 'Ex "sAMAccountName"' + }, + queryEx: { + id: 'admin.ldap.queryEx', + defaultMessage: 'Ex "60"' + }, + saving: { + id: 'admin.ldap.saving', + defaultMessage: 'Saving Config...' + } +}); + +class LdapSettings extends React.Component { constructor(props) { super(props); @@ -80,6 +125,7 @@ export default class LdapSettings extends React.Component { ); } render() { + const {formatMessage} = this.props.intl; let serverError = ''; if (this.state.serverError) { serverError =
; @@ -97,8 +143,18 @@ export default class LdapSettings extends React.Component { bannerContent = (
-

{'Note:'}

-

{'If a user attribute changes on the LDAP server it will be updated the next time the user enters their credentials to log in to Mattermost. This includes if a user is made inactive or removed from an LDAP server. Synchronization with LDAP servers is planned in a future release.'}

+

+ +

+

+ +

); @@ -106,17 +162,10 @@ export default class LdapSettings extends React.Component { bannerContent = (
-

{'Note:'}

-

- {'LDAP is an enterprise feature. Your current license does not support LDAP. Click '} - - {'here'} - - {' for information and pricing on enterprise licenses.'} -

+
); @@ -125,7 +174,12 @@ export default class LdapSettings extends React.Component { return (
{bannerContent} -

{'LDAP Settings'}

+

+ +

- {'Enable Login With LDAP:'} +
-

{'When true, Mattermost allows login using LDAP'}

+

+ +

@@ -168,7 +236,10 @@ export default class LdapSettings extends React.Component { className='control-label col-sm-4' htmlFor='LdapServer' > - {'LDAP Server:'} +
-

{'The domain or IP address of LDAP server.'}

+

+ +

@@ -189,7 +265,10 @@ export default class LdapSettings extends React.Component { className='control-label col-sm-4' htmlFor='LdapPort' > - {'LDAP Port:'} +
-

{'The port Mattermost will use to connect to the LDAP server. Default is 389.'}

+

+ +

@@ -210,7 +294,10 @@ export default class LdapSettings extends React.Component { className='control-label col-sm-4' htmlFor='BaseDN' > - {'BaseDN:'} +
-

{'The Base DN is the Distinguished Name of the location where Mattermost should start its search for users in the LDAP tree.'}

+

+ +

@@ -231,7 +323,10 @@ export default class LdapSettings extends React.Component { className='control-label col-sm-4' htmlFor='BindUsername' > - {'Bind Username:'} +
-

{'The username used to perform the LDAP search. This should typically be an account created specifically for use with Mattermost. It should have access limited to read the portion of the LDAP tree specified in the BaseDN field.'}

+

+ +

@@ -252,7 +352,10 @@ export default class LdapSettings extends React.Component { className='control-label col-sm-4' htmlFor='BindPassword' > - {'Bind Password:'} +
-

{'Password of the user given in "Bind Username".'}

+

+ +

@@ -273,7 +381,10 @@ export default class LdapSettings extends React.Component { className='control-label col-sm-4' htmlFor='FirstNameAttribute' > - {'First Name Attrubute'} +
-

{'The attribute in the LDAP server that will be used to populate the first name of users in Mattermost.'}

+

+ +

@@ -294,7 +410,10 @@ export default class LdapSettings extends React.Component { className='control-label col-sm-4' htmlFor='LastNameAttribute' > - {'Last Name Attribute:'} +
-

{'The attribute in the LDAP server that will be used to populate the last name of users in Mattermost.'}

+

+ +

@@ -315,7 +439,10 @@ export default class LdapSettings extends React.Component { className='control-label col-sm-4' htmlFor='EmailAttribute' > - {'Email Attribute:'} +
-

{'The attribute in the LDAP server that will be used to populate the email addresses of users in Mattermost.'}

+

+ +

@@ -336,7 +468,10 @@ export default class LdapSettings extends React.Component { className='control-label col-sm-4' htmlFor='UsernameAttribute' > - {'Username Attribute:'} +
-

{'The attribute in the LDAP server that will be used to populate the username field in Mattermost. This may be the same as the ID Attribute.'}

+

+ +

@@ -357,7 +497,10 @@ export default class LdapSettings extends React.Component { className='control-label col-sm-4' htmlFor='IdAttribute' > - {'Id Attribute: '} +
-

{'The attribute in the LDAP server that will be used as a unique identifier in Mattermost. It should be an LDAP attribute with a value that does not change, such as username or uid. If a user’s Id Attribute changes, it will create a new Mattermost account unassociated with their old one. This is the value used to log in to Mattermost in the "LDAP Username" field on the sign in page. Normally this attribute is the same as the “Username Attribute” field above. If your team typically uses domain\\username to sign in to other services with LDAP, you may choose to put domain\\username in this field to maintain consistency between sites.'}

+

+ +

@@ -378,7 +526,10 @@ export default class LdapSettings extends React.Component { className='control-label col-sm-4' htmlFor='QueryTimeout' > - {'Query Timeout (seconds):'} +
-

{'The timeout value for queries to the LDAP server. Increase if you are getting timeout errors caused by a slow LDAP server.'}

+

+ +

@@ -403,9 +559,12 @@ export default class LdapSettings extends React.Component { className={saveClass} onClick={this.handleSubmit} id='save-button' - data-loading-text={' Saving Config...'} + data-loading-text={' ' + formatMessage(holders.saving)} > - {'Save'} +
@@ -418,5 +577,8 @@ LdapSettings.defaultProps = { }; LdapSettings.propTypes = { + intl: intlShape.isRequired, config: React.PropTypes.object }; + +export default injectIntl(LdapSettings); \ No newline at end of file diff --git a/web/react/components/admin_console/legal_and_support_settings.jsx b/web/react/components/admin_console/legal_and_support_settings.jsx index b00e4b6bd..a6c6a0626 100644 --- a/web/react/components/admin_console/legal_and_support_settings.jsx +++ b/web/react/components/admin_console/legal_and_support_settings.jsx @@ -4,7 +4,16 @@ import * as Client from '../../utils/client.jsx'; import * as AsyncClient from '../../utils/async_client.jsx'; -export default class LegalAndSupportSettings extends React.Component { +import {injectIntl, intlShape, defineMessages, FormattedMessage} from 'mm-intl'; + +var holders = defineMessages({ + saving: { + id: 'admin.support.saving', + defaultMessage: 'Saving Config...' + } +}); + +class LegalAndSupportSettings extends React.Component { constructor(props) { super(props); @@ -69,7 +78,12 @@ export default class LegalAndSupportSettings extends React.Component { return (
-

{'Legal and Support Settings'}

+

+ +

- {'Terms of Service link:'} +
-

{'Link to Terms of Service available to users on desktop and on mobile. Leaving this blank will hide the option to display a notice.'}

+

+ +

@@ -100,7 +122,10 @@ export default class LegalAndSupportSettings extends React.Component { className='control-label col-sm-4' htmlFor='PrivacyPolicyLink' > - {'Privacy Policy link:'} +
-

{'Link to Privacy Policy available to users on desktop and on mobile. Leaving this blank will hide the option to display a notice.'}

+

+ +

@@ -120,7 +150,10 @@ export default class LegalAndSupportSettings extends React.Component { className='control-label col-sm-4' htmlFor='AboutLink' > - {'About link:'} +
-

{'Link to About page for more information on your Mattermost deployment, for example its purpose and audience within your organization. Defaults to Mattermost information page.'}

+

+ +

@@ -140,7 +178,10 @@ export default class LegalAndSupportSettings extends React.Component { className='control-label col-sm-4' htmlFor='HelpLink' > - {'Help link:'} +
-

{'Link to help documentation from team site main menu. Typically not changed unless your organization chooses to create custom documentation.'}

+

+ +

@@ -160,7 +206,10 @@ export default class LegalAndSupportSettings extends React.Component { className='control-label col-sm-4' htmlFor='ReportAProblemLink' > - {'Report a Problem link:'} +
-

{'Link to help documentation from team site main menu. By default this points to the peer-to-peer troubleshooting forum where users can search for, find and request help with technical issues.'}

+

+ +

@@ -180,7 +234,10 @@ export default class LegalAndSupportSettings extends React.Component { className='control-label col-sm-4' htmlFor='SupportEmail' > - {'Support email:'} +
-

{'Email shown during tutorial for end users to ask support questions.'}

+

+ +

@@ -204,9 +266,12 @@ export default class LegalAndSupportSettings extends React.Component { className={saveClass} onClick={this.handleSubmit} id='save-button' - data-loading-text={' Saving Config...'} + data-loading-text={' ' + this.props.intl.formatMessage(holders.saving)} > - {'Save'} + @@ -218,5 +283,8 @@ export default class LegalAndSupportSettings extends React.Component { } LegalAndSupportSettings.propTypes = { + intl: intlShape.isRequired, config: React.PropTypes.object }; + +export default injectIntl(LegalAndSupportSettings); \ No newline at end of file diff --git a/web/react/components/admin_console/license_settings.jsx b/web/react/components/admin_console/license_settings.jsx index ba953f3bd..539acd869 100644 --- a/web/react/components/admin_console/license_settings.jsx +++ b/web/react/components/admin_console/license_settings.jsx @@ -4,7 +4,20 @@ import * as Utils from '../../utils/utils.jsx'; import * as Client from '../../utils/client.jsx'; -export default class LicenseSettings extends React.Component { +import {injectIntl, intlShape, defineMessages, FormattedMessage, FormattedHTMLMessage} from 'mm-intl'; + +const holders = defineMessages({ + removing: { + id: 'admin.license.removing', + defaultMessage: 'Removing License...' + }, + uploading: { + id: 'admin.license.uploading', + defaultMessage: 'Uploading License...' + } +}); + +class LicenseSettings extends React.Component { constructor(props) { super(props); @@ -88,41 +101,26 @@ export default class LicenseSettings extends React.Component { let licenseKey; if (global.window.mm_license.IsLicensed === 'true') { - edition = 'Mattermost Enterprise Edition. Designed for enterprise-scale communication.'; + edition = ( + + ); licenseType = ( -
-

- {'This compiled release of Mattermost platform is provided under a '} - - {'commercial license'} - - {' from Mattermost, Inc. based on your subscription level and is subject to the '} - - {'Terms of Service.'} - -

-

{'Your subscription details are as follows:'}

- {'Name: ' + global.window.mm_license.Name} -
- {'Company or organization name: ' + global.window.mm_license.Company} -
- {'Number of users: ' + global.window.mm_license.Users} -
- {`License issued: ${Utils.displayDate(parseInt(global.window.mm_license.IssuedAt, 10))} ${Utils.displayTime(parseInt(global.window.mm_license.IssuedAt, 10), true)}`} -
- {'Start date of license: ' + Utils.displayDate(parseInt(global.window.mm_license.StartsAt, 10))} -
- {'Expiry date of license: ' + Utils.displayDate(parseInt(global.window.mm_license.ExpiresAt, 10))} -
- {'LDAP: ' + global.window.mm_license.LDAP} -
-
+ ); licenseKey = ( @@ -131,32 +129,39 @@ export default class LicenseSettings extends React.Component { className='btn btn-danger' onClick={this.handleRemove} id='remove-button' - data-loading-text={' Removing License...'} + data-loading-text={' ' + this.props.intl.formatMessage(holders.removing)} > - {'Remove Enterprise License and Downgrade Server'} +

- {'If you’re migrating servers you may need to remove your license key from this server in order to install it on a new server. To start, '} - - {'disable all Enterprise Edition features on this server'} - - {'. This will enable the ability to remove the license key and downgrade this server from Enterprise Edition to Team Edition.'} +

); } else { - edition = 'Mattermost Team Edition. Designed for teams from 5 to 50 users.'; + edition = ( + + ); licenseType = ( - -

{'This compiled release of Mattermost platform is offered under an MIT license.'}

-

{'See MIT-COMPILED-LICENSE.txt in your root install directory for details. See NOTICES.txt for information about open source software used in this system.'}

-
+ ); licenseKey = ( @@ -173,23 +178,23 @@ export default class LicenseSettings extends React.Component { disabled={!this.state.fileSelected} onClick={this.handleSubmit} id='upload-button' - data-loading-text={' Uploading License...'} + data-loading-text={' ' + this.props.intl.formatMessage(holders.uploading)} > - {'Upload'} +


{serverError}

- {'Upload a license key for Mattermost Enterprise Edition to upgrade this server. '} - - {'Visit us online'} - - {' to learn more about the benefits of Enterprise Edition or to purchase a key.'} +

); @@ -197,7 +202,12 @@ export default class LicenseSettings extends React.Component { return (
-

{'Edition and License'}

+

+ +

- {'Edition: '} +
{edition} @@ -216,7 +229,10 @@ export default class LicenseSettings extends React.Component {
{licenseType} @@ -226,7 +242,10 @@ export default class LicenseSettings extends React.Component { {licenseKey}
@@ -235,3 +254,9 @@ export default class LicenseSettings extends React.Component { ); } } + +LicenseSettings.propTypes = { + intl: intlShape.isRequired +}; + +export default injectIntl(LicenseSettings); \ No newline at end of file diff --git a/web/react/components/admin_console/log_settings.jsx b/web/react/components/admin_console/log_settings.jsx index a91cc57ab..cefe6afba 100644 --- a/web/react/components/admin_console/log_settings.jsx +++ b/web/react/components/admin_console/log_settings.jsx @@ -4,7 +4,24 @@ import * as Client from '../../utils/client.jsx'; import * as AsyncClient from '../../utils/async_client.jsx'; -export default class LogSettings extends React.Component { +import {injectIntl, intlShape, defineMessages, FormattedMessage} from 'mm-intl'; + +const holders = defineMessages({ + locationPlaceholder: { + id: 'admin.log.locationPlaceholder', + defaultMessage: 'Enter your file location' + }, + formatPlaceholder: { + id: 'admin.log.formatPlaceholder', + defaultMessage: 'Enter your file format' + }, + saving: { + id: 'admin.log.saving', + defaultMessage: 'Saving Config...' + } +}); + +class LogSettings extends React.Component { constructor(props) { super(props); @@ -78,6 +95,7 @@ export default class LogSettings extends React.Component { } render() { + const {formatMessage} = this.props.intl; var serverError = ''; if (this.state.serverError) { serverError =
; @@ -90,7 +108,12 @@ export default class LogSettings extends React.Component { return (
-

{'Log Settings'}

+

+ +

- {'Log To The Console: '} +
-

{'Typically set to false in production. Developers may set this field to true to output log messages to console based on the console level option. If true, server writes messages to the standard output stream (stdout).'}

+

+ +

@@ -134,7 +171,10 @@ export default class LogSettings extends React.Component { className='control-label col-sm-4' htmlFor='consoleLevel' > - {'Console Log Level:'} +
-

{'This setting determines the level of detail at which log events are written to the console. ERROR: Outputs only error messages. INFO: Outputs error messages and information around startup and initialization. DEBUG: Prints high detail for developers working on debugging issues.'}

+

+ +

@@ -157,7 +202,10 @@ export default class LogSettings extends React.Component {
-

{'Typically set to true in production. When true, log files are written to the log file specified in file location field below.'}

+

+ +

@@ -190,7 +249,10 @@ export default class LogSettings extends React.Component { className='control-label col-sm-4' htmlFor='fileLevel' > - {'File Log Level:'} +
-

{'This setting determines the level of detail at which log events are written to the log file. ERROR: Outputs only error messages. INFO: Outputs error messages and information around startup and initialization. DEBUG: Prints high detail for developers working on debugging issues.'}

+

+ +

@@ -214,7 +281,10 @@ export default class LogSettings extends React.Component { className='control-label col-sm-4' htmlFor='fileLocation' > - {'File Location:'} +
-

{'File to which log files are written. If blank, will be set to ./logs/mattermost, which writes logs to mattermost.log. Log rotation is enabled and every 10,000 lines of log information is written to new files stored in the same directory, for example mattermost.2015-09-23.001, mattermost.2015-09-23.002, and so forth.'}

+

+ +

@@ -236,7 +311,10 @@ export default class LogSettings extends React.Component { className='control-label col-sm-4' htmlFor='fileFormat' > - {'File Format:'} +
- {'Format of log message output. If blank will be set to "[%D %T] [%L] %M", where:'} +
- - - - - - + + + + + +
{'%T'}{'Time (15:04:05 MST)'}
{'%D'}{'Date (2006/01/02)'}
{'%d'}{'Date (01/02/06)'}
{'%L'}{'Level (DEBG, INFO, EROR)'}
{'%S'}{'Source'}
{'%M'}{'Message'}
{'%T'} + +
{'%D'} + +
{'%d'} + +
{'%L'} + +
{'%S'} + +
{'%M'} + +
@@ -279,9 +390,12 @@ export default class LogSettings extends React.Component { className={saveClass} onClick={this.handleSubmit} id='save-button' - data-loading-text={' Saving Config...'} + data-loading-text={' ' + formatMessage(holders.saving)} > - {'Save'} +
@@ -293,5 +407,8 @@ export default class LogSettings extends React.Component { } LogSettings.propTypes = { + intl: intlShape.isRequired, config: React.PropTypes.object }; + +export default injectIntl(LogSettings); \ No newline at end of file diff --git a/web/react/components/admin_console/logs.jsx b/web/react/components/admin_console/logs.jsx index 01135f1b8..71a4a5d8c 100644 --- a/web/react/components/admin_console/logs.jsx +++ b/web/react/components/admin_console/logs.jsx @@ -5,6 +5,8 @@ import AdminStore from '../../stores/admin_store.jsx'; import LoadingScreen from '../loading_screen.jsx'; import * as AsyncClient from '../../utils/async_client.jsx'; +import {FormattedMessage} from 'mm-intl'; + export default class Logs extends React.Component { constructor(props) { super(props); @@ -73,13 +75,21 @@ export default class Logs extends React.Component { return (
-

{'Server Logs'}

+

+ +

{content} diff --git a/web/react/components/admin_console/privacy_settings.jsx b/web/react/components/admin_console/privacy_settings.jsx index 78747d9f2..1ab625049 100644 --- a/web/react/components/admin_console/privacy_settings.jsx +++ b/web/react/components/admin_console/privacy_settings.jsx @@ -4,7 +4,16 @@ import * as Client from '../../utils/client.jsx'; import * as AsyncClient from '../../utils/async_client.jsx'; -export default class PrivacySettings extends React.Component { +import {injectIntl, intlShape, defineMessages, FormattedMessage} from 'mm-intl'; + +const holders = defineMessages({ + saving: { + id: 'admin.privacy.saving', + defaultMessage: 'Saving Config...' + } +}); + +class PrivacySettings extends React.Component { constructor(props) { super(props); @@ -64,7 +73,12 @@ export default class PrivacySettings extends React.Component { return (
-

{'Privacy Settings'}

+

+ +

- {'Show Email Address: '} +
-

{'When false, hides email address of users from other users in the user interface, including team owners and team administrators. Used when system is set up for managing teams where some users choose to keep their contact information private.'}

+

+ +

@@ -108,7 +136,10 @@ export default class PrivacySettings extends React.Component { className='control-label col-sm-4' htmlFor='ShowFullName' > - {'Show Full Name: '} +
-

{'When false, hides full name of users from other users, including team owners and team administrators. Username is shown in place of full name.'}

+

+ +

@@ -145,9 +187,12 @@ export default class PrivacySettings extends React.Component { className={saveClass} onClick={this.handleSubmit} id='save-button' - data-loading-text={' Saving Config...'} + data-loading-text={' ' + this.props.intl.formatMessage(holders.saving)} > - {'Save'} +
@@ -159,5 +204,8 @@ export default class PrivacySettings extends React.Component { } PrivacySettings.propTypes = { + intl: intlShape.isRequired, config: React.PropTypes.object }; + +export default injectIntl(PrivacySettings); \ No newline at end of file diff --git a/web/react/components/admin_console/rate_settings.jsx b/web/react/components/admin_console/rate_settings.jsx index aabb24326..d3c1bffa2 100644 --- a/web/react/components/admin_console/rate_settings.jsx +++ b/web/react/components/admin_console/rate_settings.jsx @@ -4,7 +4,28 @@ import * as Client from '../../utils/client.jsx'; import * as AsyncClient from '../../utils/async_client.jsx'; -export default class RateSettings extends React.Component { +import {injectIntl, intlShape, defineMessages, FormattedMessage} from 'mm-intl'; + +const holders = defineMessages({ + queriesExample: { + id: 'admin.rate.queriesExample', + defaultMessage: 'Ex "10"' + }, + memoryExample: { + id: 'admin.rate.memoryExample', + defaultMessage: 'Ex "10000"' + }, + httpHeaderExample: { + id: 'admin.rate.httpHeaderExample', + defaultMessage: 'Ex "X-Real-IP", "X-Forwarded-For"' + }, + saving: { + id: 'admin.rate.saving', + defaultMessage: 'Saving Config...' + } +}); + +class RateSettings extends React.Component { constructor(props) { super(props); @@ -85,6 +106,7 @@ export default class RateSettings extends React.Component { } render() { + const {formatMessage} = this.props.intl; var serverError = ''; if (this.state.serverError) { serverError =
; @@ -100,12 +122,27 @@ export default class RateSettings extends React.Component {
-

{'Note:'}

-

{'Changing properties in this section will require a server restart before taking effect.'}

+

+ +

+

+ +

-

{'Rate Limit Settings'}

+

+ +

- {'Enable Rate Limiter: '} +
-

{'When true, APIs are throttled at rates specified below.'}

+

+ +

@@ -149,7 +200,10 @@ export default class RateSettings extends React.Component { className='control-label col-sm-4' htmlFor='PerSec' > - {'Number Of Queries Per Second:'} +
-

{'Throttles API at this number of requests per second.'}

+

+ +

@@ -171,7 +230,10 @@ export default class RateSettings extends React.Component { className='control-label col-sm-4' htmlFor='MemoryStoreSize' > - {'Memory Store Size:'} +
-

{'Maximum number of users sessions connected to the system as determined by "Vary By Remote Address" and "Vary By Header" settings below.'}

+

+ +

@@ -193,7 +260,10 @@ export default class RateSettings extends React.Component { className='control-label col-sm-4' htmlFor='VaryByRemoteAddr' > - {'Vary By Remote Address: '} +
-

{'When true, rate limit API access by IP address.'}

+

+ +

@@ -228,7 +309,10 @@ export default class RateSettings extends React.Component { className='control-label col-sm-4' htmlFor='VaryByHeader' > - {'Vary By HTTP Header:'} +
-

{'When filled in, vary rate limiting by HTTP header field specified (e.g. when configuring NGINX set to "X-Real-IP", when configuring AmazonELB set to "X-Forwarded-For").'}

+

+ +

@@ -254,9 +343,12 @@ export default class RateSettings extends React.Component { className={saveClass} onClick={this.handleSubmit} id='save-button' - data-loading-text={' Saving Config...'} + data-loading-text={' ' + formatMessage(holders.saving)} > - {'Save'} + @@ -268,5 +360,8 @@ export default class RateSettings extends React.Component { } RateSettings.propTypes = { + intl: intlShape.isRequired, config: React.PropTypes.object }; + +export default injectIntl(RateSettings); \ No newline at end of file diff --git a/web/react/components/admin_console/reset_password_modal.jsx b/web/react/components/admin_console/reset_password_modal.jsx index bf7d5f7e5..8ed519ffb 100644 --- a/web/react/components/admin_console/reset_password_modal.jsx +++ b/web/react/components/admin_console/reset_password_modal.jsx @@ -5,7 +5,16 @@ import * as Client from '../../utils/client.jsx'; import Constants from '../../utils/constants.jsx'; var Modal = ReactBootstrap.Modal; -export default class ResetPasswordModal extends React.Component { +import {injectIntl, intlShape, defineMessages, FormattedMessage} from 'mm-intl'; + +var holders = defineMessages({ + submit: { + id: 'admin.reset_password.submit', + defaultMessage: 'Please enter at least {chars} characters.' + } +}); + +class ResetPasswordModal extends React.Component { constructor(props) { super(props); @@ -22,7 +31,7 @@ export default class ResetPasswordModal extends React.Component { var password = ReactDOM.findDOMNode(this.refs.password).value; if (!password || password.length < Constants.MIN_PASSWORD_LENGTH) { - this.setState({serverError: 'Please enter at least ' + Constants.MIN_PASSWORD_LENGTH + ' characters.'}); + this.setState({serverError: this.props.intl.formatMessage(holders.submit, {chars: Constants.MIN_PASSWORD_LENGTH})}); return; } @@ -67,7 +76,12 @@ export default class ResetPasswordModal extends React.Component { onHide={this.doCancel} > - {'Reset Password'} + + + - {'New Password'} + - {'Close'} + @@ -125,9 +148,12 @@ ResetPasswordModal.defaultProps = { }; ResetPasswordModal.propTypes = { + intl: intlShape.isRequired, user: React.PropTypes.object, team: React.PropTypes.object, show: React.PropTypes.bool.isRequired, onModalSubmit: React.PropTypes.func, onModalDismissed: React.PropTypes.func }; + +export default injectIntl(ResetPasswordModal); \ No newline at end of file diff --git a/web/react/components/admin_console/service_settings.jsx b/web/react/components/admin_console/service_settings.jsx index f10721ffa..7021900eb 100644 --- a/web/react/components/admin_console/service_settings.jsx +++ b/web/react/components/admin_console/service_settings.jsx @@ -4,11 +4,40 @@ import * as Client from '../../utils/client.jsx'; import * as AsyncClient from '../../utils/async_client.jsx'; +import {injectIntl, intlShape, defineMessages, FormattedMessage, FormattedHTMLMessage} from 'mm-intl'; + const DefaultSessionLength = 30; const DefaultMaximumLoginAttempts = 10; const DefaultSessionCacheInMinutes = 10; -export default class ServiceSettings extends React.Component { +var holders = defineMessages({ + listenExample: { + id: 'admin.service.listenExample', + defaultMessage: 'Ex ":8065"' + }, + attemptExample: { + id: 'admin.service.attemptExample', + defaultMessage: 'Ex "10"' + }, + segmentExample: { + id: 'admin.service.segmentExample', + defaultMessage: 'Ex "g3fgGOXJAQ43QV7rAh6iwQCkV4cA1Gs"' + }, + googleExample: { + id: 'admin.service.googleExample', + defaultMessage: 'Ex "7rAh6iwQCkV4cA1Gsg3fgGOXJAQ43QV"' + }, + sessionDaysEx: { + id: 'admin.service.sessionDaysEx', + defaultMessage: 'Ex "30"' + }, + saving: { + id: 'admin.service.saving', + defaultMessage: 'Saving Config...' + } +}); + +class ServiceSettings extends React.Component { constructor(props) { super(props); @@ -120,6 +149,7 @@ export default class ServiceSettings extends React.Component { } render() { + const {formatMessage} = this.props.intl; var serverError = ''; if (this.state.serverError) { serverError =
; @@ -133,7 +163,12 @@ export default class ServiceSettings extends React.Component { return (
-

{'Service Settings'}

+

+ +

- {'Listen Address:'} +
-

{'The address to which to bind and listen. Entering ":8065" will bind to all interfaces or you can choose one like "127.0.0.1:8065". Changing this will require a server restart before taking effect.'}

+

+ +

@@ -165,7 +208,10 @@ export default class ServiceSettings extends React.Component { className='control-label col-sm-4' htmlFor='MaximumLoginAttempts' > - {'Maximum Login Attempts:'} +
-

{'Login attempts allowed before user is locked out and required to reset password via email.'}

+

+ +

@@ -186,7 +237,10 @@ export default class ServiceSettings extends React.Component { className='control-label col-sm-4' htmlFor='SegmentDeveloperKey' > - {'Segment Developer Key:'} +
-

{'For users running a SaaS services, sign up for a key at Segment.com to track metrics.'}

+

+ +

@@ -207,7 +266,10 @@ export default class ServiceSettings extends React.Component { className='control-label col-sm-4' htmlFor='GoogleDeveloperKey' > - {'Google Developer Key:'} +

- {'Set this key to enable embedding of YouTube video previews based on hyperlinks appearing in messages or comments. Instructions to obtain a key available at '} - - {'https://www.youtube.com/watch?v=Im69kzhpR3I'} - - {'. Leaving the field blank disables the automatic generation of YouTube video previews from links.'} +

@@ -237,7 +297,10 @@ export default class ServiceSettings extends React.Component { className='control-label col-sm-4' htmlFor='EnableIncomingWebhooks' > - {'Enable Incoming Webhooks: '} +
-

{'When true, incoming webhooks will be allowed. To help combat phishing attacks, all posts from webhooks will be labelled by a BOT tag.'}

+

+ +

@@ -270,7 +344,10 @@ export default class ServiceSettings extends React.Component { className='control-label col-sm-4' htmlFor='EnableOutgoingWebhooks' > - {'Enable Outgoing Webhooks: '} +
-

{'When true, outgoing webhooks will be allowed.'}

+

+ +

@@ -303,7 +391,10 @@ export default class ServiceSettings extends React.Component { className='control-label col-sm-4' htmlFor='EnablePostUsernameOverride' > - {'Enable Overriding Usernames from Webhooks: '} +
-

{'When true, webhooks will be allowed to change the username they are posting as. Note, combined with allowing icon overriding, this could open users up to phishing attacks.'}

+

+ +

@@ -336,7 +438,10 @@ export default class ServiceSettings extends React.Component { className='control-label col-sm-4' htmlFor='EnablePostIconOverride' > - {'Enable Overriding Icon from Webhooks: '} +
-

{'When true, webhooks will be allowed to change the icon they post with. Note, combined with allowing username overriding, this could open users up to phishing attacks.'}

+

+ +

@@ -369,7 +485,10 @@ export default class ServiceSettings extends React.Component { className='control-label col-sm-4' htmlFor='EnableTesting' > - {'Enable Testing: '} +
-

{'(Developer Option) When true, /loadtest slash command is enabled to load test accounts and test data. Changing this will require a server restart before taking effect.'}

+

+ +

@@ -402,7 +532,10 @@ export default class ServiceSettings extends React.Component { className='control-label col-sm-4' htmlFor='EnableDeveloper' > - {'Enable Developer Mode: '} +
-

{'(Developer Option) When true, extra information around errors will be displayed in the UI.'}

+

+ +

@@ -435,7 +579,10 @@ export default class ServiceSettings extends React.Component { className='control-label col-sm-4' htmlFor='EnableSecurityFixAlert' > - {'Enable Security Alerts: '} +
-

{'When true, System Administrators are notified by email if a relevant security fix alert has been announced in the last 12 hours. Requires email to be enabled.'}

+

+ +

@@ -468,7 +626,10 @@ export default class ServiceSettings extends React.Component { className='control-label col-sm-4' htmlFor='SessionLengthWebInDays' > - {'Session Length for Web in Days:'} +
-

{'The web session will expire after the number of days specified and will require a user to login again.'}

+

+ +

@@ -489,7 +655,10 @@ export default class ServiceSettings extends React.Component { className='control-label col-sm-4' htmlFor='SessionLengthMobileInDays' > - {'Session Length for Mobile Device in Days:'} +
-

{'The native mobile session will expire after the number of days specified and will require a user to login again.'}

+

+ +

@@ -510,7 +684,10 @@ export default class ServiceSettings extends React.Component { className='control-label col-sm-4' htmlFor='SessionLengthSSOInDays' > - {'Session Length for SSO in Days:'} +
-

{'The SSO session will expire after the number of days specified and will require a user to login again.'}

+

+ +

@@ -531,7 +713,10 @@ export default class ServiceSettings extends React.Component { className='control-label col-sm-4' htmlFor='SessionCacheInMinutes' > - {'Session Cache in Minutes:'} +
-

{'The number of minutes to cache a session in memory.'}

+

+ +

@@ -556,9 +746,12 @@ export default class ServiceSettings extends React.Component { className={saveClass} onClick={this.handleSubmit} id='save-button' - data-loading-text={' Saving Config...'} + data-loading-text={' ' + formatMessage(holders.saving)} > - {'Save'} + @@ -603,5 +796,8 @@ export default class ServiceSettings extends React.Component { // ServiceSettings.propTypes = { + intl: intlShape.isRequired, config: React.PropTypes.object }; + +export default injectIntl(ServiceSettings); \ No newline at end of file diff --git a/web/react/components/admin_console/sql_settings.jsx b/web/react/components/admin_console/sql_settings.jsx index 2a55f7324..69ae808f6 100644 --- a/web/react/components/admin_console/sql_settings.jsx +++ b/web/react/components/admin_console/sql_settings.jsx @@ -5,7 +5,32 @@ import * as Client from '../../utils/client.jsx'; import * as AsyncClient from '../../utils/async_client.jsx'; import crypto from 'crypto'; -export default class SqlSettings extends React.Component { +import {injectIntl, intlShape, defineMessages, FormattedMessage} from 'mm-intl'; + +const holders = defineMessages({ + warning: { + id: 'admin.sql.warning', + defaultMessage: 'Warning: re-generating this salt may cause some columns in the database to return empty results.' + }, + maxConnectionsExample: { + id: 'admin.sql.maxConnectionsExample', + defaultMessage: 'Ex "10"' + }, + maxOpenExample: { + id: 'admin.sql.maxOpenExample', + defaultMessage: 'Ex "10"' + }, + keyExample: { + id: 'admin.sql.keyExample', + defaultMessage: 'Ex "gxHVDcKUyP2y1eiyW8S8na1UYQAfq6J6"' + }, + saving: { + id: 'admin.sql.saving', + defaultMessage: 'Saving Config...' + } +}); + +class SqlSettings extends React.Component { constructor(props) { super(props); @@ -74,7 +99,7 @@ export default class SqlSettings extends React.Component { handleGenerate(e) { e.preventDefault(); - var cfm = global.window.confirm('Warning: re-generating this salt may cause some columns in the database to return empty results.'); + var cfm = global.window.confirm(this.props.intl.formatMessage(holders.warning)); if (cfm === false) { return; } @@ -85,6 +110,7 @@ export default class SqlSettings extends React.Component { } render() { + const {formatMessage} = this.props.intl; var serverError = ''; if (this.state.serverError) { serverError =
; @@ -111,12 +137,27 @@ export default class SqlSettings extends React.Component {
-

{'Note:'}

-

{'Changing properties in this section will require a server restart before taking effect.'}

+

+ +

+

+ +

-

{'SQL Settings'}

+

+ +

- {'Driver Name:'} +

{this.props.config.SqlSettings.DriverName}

@@ -139,7 +183,10 @@ export default class SqlSettings extends React.Component { className='control-label col-sm-4' htmlFor='DataSource' > - {'Data Source:'} +

{dataSource}

@@ -151,7 +198,10 @@ export default class SqlSettings extends React.Component { className='control-label col-sm-4' htmlFor='DataSourceReplicas' > - {'Data Source Replicas:'} +

{dataSourceReplicas}

@@ -163,7 +213,10 @@ export default class SqlSettings extends React.Component { className='control-label col-sm-4' htmlFor='MaxIdleConns' > - {'Maximum Idle Connections:'} +
-

{'Maximum number of idle connections held open to the database.'}

+

+ +

@@ -184,7 +242,10 @@ export default class SqlSettings extends React.Component { className='control-label col-sm-4' htmlFor='MaxOpenConns' > - {'Maximum Open Connections:'} +
-

{'Maximum number of open connections held open to the database.'}

+

+ +

@@ -205,7 +271,10 @@ export default class SqlSettings extends React.Component { className='control-label col-sm-4' htmlFor='AtRestEncryptKey' > - {'At Rest Encrypt Key:'} +
-

{'32-character salt available to encrypt and decrypt sensitive fields in database.'}

+

+ +

@@ -234,7 +311,10 @@ export default class SqlSettings extends React.Component { className='control-label col-sm-4' htmlFor='Trace' > - {'Trace: '} +
-

{'(Development Mode) When true, executing SQL statements are written to the log.'}

+

+ +

@@ -271,9 +362,12 @@ export default class SqlSettings extends React.Component { className={saveClass} onClick={this.handleSubmit} id='save-button' - data-loading-text={' Saving Config...'} + data-loading-text={' ' + formatMessage(holders.saving)} > - {'Save'} + @@ -285,5 +379,8 @@ export default class SqlSettings extends React.Component { } SqlSettings.propTypes = { + intl: intlShape.isRequired, config: React.PropTypes.object }; + +export default injectIntl(SqlSettings); \ No newline at end of file diff --git a/web/react/components/admin_console/system_analytics.jsx b/web/react/components/admin_console/system_analytics.jsx index f54813a94..2dd833fb2 100644 --- a/web/react/components/admin_console/system_analytics.jsx +++ b/web/react/components/admin_console/system_analytics.jsx @@ -4,7 +4,24 @@ import Analytics from './analytics.jsx'; import * as Client from '../../utils/client.jsx'; -export default class SystemAnalytics extends React.Component { +import {injectIntl, intlShape, defineMessages} from 'mm-intl'; + +const labels = defineMessages({ + totalPosts: { + id: 'admin.system_analytics.totalPosts', + defaultMessage: 'Total Posts' + }, + activeUsers: { + id: 'admin.system_analytics.activeUsers', + defaultMessage: 'Active Users With Posts' + }, + title: { + id: 'admin.system_analytics.title', + defaultMessage: 'the System' + } +}); + +class SystemAnalytics extends React.Component { constructor(props) { super(props); @@ -29,6 +46,7 @@ export default class SystemAnalytics extends React.Component { } getData() { // should be moved to an action creator eventually + const {formatMessage} = this.props.intl; Client.getSystemAnalytics( 'standard', (data) => { @@ -63,7 +81,7 @@ export default class SystemAnalytics extends React.Component { var chartData = { labels: [], datasets: [{ - label: 'Total Posts', + label: formatMessage(labels.totalPosts), fillColor: 'rgba(151,187,205,0.2)', strokeColor: 'rgba(151,187,205,1)', pointColor: 'rgba(151,187,205,1)', @@ -97,7 +115,7 @@ export default class SystemAnalytics extends React.Component { var chartData = { labels: [], datasets: [{ - label: 'Active Users With Posts', + label: formatMessage(labels.activeUsers), fillColor: 'rgba(151,187,205,0.2)', strokeColor: 'rgba(151,187,205,1)', pointColor: 'rgba(151,187,205,1)', @@ -142,7 +160,7 @@ export default class SystemAnalytics extends React.Component { return (
; @@ -75,7 +97,12 @@ export default class TeamSettings extends React.Component { return (
-

{'Team Settings'}

+

+ +

- {'Site Name:'} +
-

{'Name of service shown in login screens and UI.'}

+

+ +

@@ -107,7 +142,10 @@ export default class TeamSettings extends React.Component { className='control-label col-sm-4' htmlFor='MaxUsersPerTeam' > - {'Max Users Per Team:'} +
-

{'Maximum total number of users per team, including both active and inactive users.'}

+

+ +

@@ -128,7 +171,10 @@ export default class TeamSettings extends React.Component { className='control-label col-sm-4' htmlFor='EnableTeamCreation' > - {'Enable Team Creation: '} +
-

{'When false, the ability to create teams is disabled. The create team button displays error when pressed.'}

+

+ +

@@ -161,7 +218,10 @@ export default class TeamSettings extends React.Component { className='control-label col-sm-4' htmlFor='EnableUserCreation' > - {'Enable User Creation: '} +
-

{'When false, the ability to create accounts is disabled. The create account button displays error when pressed.'}

+

+ +

@@ -194,7 +265,10 @@ export default class TeamSettings extends React.Component { className='control-label col-sm-4' htmlFor='RestrictCreationToDomains' > - {'Restrict Creation To Domains:'} +
-

{'Teams and user accounts can only be created from a specific domain (e.g. "mattermost.org") or list of comma-separated domains (e.g. "corp.mattermost.com, mattermost.org").'}

+

+ +

@@ -215,7 +294,10 @@ export default class TeamSettings extends React.Component { className='control-label col-sm-4' htmlFor='RestrictTeamNames' > - {'Restrict Team Names: '} +
-

{'When true, You cannot create a team name with reserved words like www, admin, support, test, channel, etc'}

+

+ +

@@ -248,7 +341,10 @@ export default class TeamSettings extends React.Component { className='control-label col-sm-4' htmlFor='EnableTeamListing' > - {'Enable Team Directory: '} +
-

{'When true, teams that are configured to show in team directory will show on main page inplace of creating a new team.'}

+

+ +

@@ -285,9 +392,12 @@ export default class TeamSettings extends React.Component { className={saveClass} onClick={this.handleSubmit} id='save-button' - data-loading-text={' Saving Config...'} + data-loading-text={' ' + formatMessage(holders.saving)} > - {'Save'} + @@ -299,5 +409,8 @@ export default class TeamSettings extends React.Component { } TeamSettings.propTypes = { + intl: intlShape.isRequired, config: React.PropTypes.object }; + +export default injectIntl(TeamSettings); \ No newline at end of file diff --git a/web/react/components/admin_console/team_users.jsx b/web/react/components/admin_console/team_users.jsx index 2d9657956..1177c9c56 100644 --- a/web/react/components/admin_console/team_users.jsx +++ b/web/react/components/admin_console/team_users.jsx @@ -6,6 +6,8 @@ import LoadingScreen from '../loading_screen.jsx'; import UserItem from './user_item.jsx'; import ResetPasswordModal from './reset_password_modal.jsx'; +import {FormattedMessage} from 'mm-intl'; + export default class UserList extends React.Component { constructor(props) { super(props); @@ -122,7 +124,15 @@ export default class UserList extends React.Component { if (this.state.users == null) { return (
-

{'Users for ' + this.props.team.name}

+

+ +

{serverError}
@@ -141,7 +151,16 @@ export default class UserList extends React.Component { return (
-

{'Users for ' + this.props.team.name + ' (' + this.state.users.length + ')'}

+

+ +

{serverError} + ); if (user.roles.length > 0) { if (Utils.isSystemAdmin(user.roles)) { - currentRoles = 'System Admin'; + currentRoles = ( + + ); } else if (Utils.isAdmin(user.roles)) { - currentRoles = 'Team Admin'; + currentRoles = ( + + ); } else { currentRoles = user.roles.charAt(0).toUpperCase() + user.roles.slice(1); } @@ -128,7 +145,12 @@ export default class UserItem extends React.Component { let showMakeNotActive = user.roles !== 'system_admin'; if (user.delete_at > 0) { - currentRoles = 'Inactive'; + currentRoles = ( + + ); showMakeMember = false; showMakeAdmin = false; showMakeSystemAdmin = false; @@ -145,7 +167,10 @@ export default class UserItem extends React.Component { href='#' onClick={this.handleMakeSystemAdmin} > - {'Make System Admin'} + ); @@ -160,7 +185,10 @@ export default class UserItem extends React.Component { href='#' onClick={this.handleMakeAdmin} > - {'Make Team Admin'} + ); @@ -175,7 +203,10 @@ export default class UserItem extends React.Component { href='#' onClick={this.handleMakeMember} > - {'Make Member'} + ); @@ -190,7 +221,10 @@ export default class UserItem extends React.Component { href='#' onClick={this.handleMakeActive} > - {'Make Active'} + ); @@ -205,7 +239,10 @@ export default class UserItem extends React.Component { href='#' onClick={this.handleMakeNotActive} > - {'Make Inactive'} + ); @@ -248,7 +285,10 @@ export default class UserItem extends React.Component { href='#' onClick={this.handleResetPassword} > - {'Reset Password'} + -- cgit v1.2.3-1-g7c22