Remove t function from admin_definition.tsx (and more) (#25406)

* Remove t function from schema_admin_settings

* i18n

* Fix import

* Use always string or descriptor and more improvements

* i18n-extract

* Remove t function for roles

* Remove more t functions

* Address feedback

* i18n-extract fix

* Fix tests

* Fix tests

* Remove translation of team edition notice

* Remove unexpected file in the commit

* Address feedback

* Fix search in admin console

* Fix test
This commit is contained in:
Daniel Espino García 2024-01-16 10:10:24 +01:00 committed by GitHub
parent 6f1bbcd8ec
commit 8818141dae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
159 changed files with 7096 additions and 6350 deletions

View File

@ -26,19 +26,11 @@ exports[`components/BleveSettings should match snapshot, disabled 1`] = `
}
helpText={
<Memo(MemoizedFormattedMessage)
defaultMessage="When true, indexing of new posts occurs automatically. Search queries will use database search until \\"Enable Bleve for search queries\\" is enabled. {documentationLink}"
defaultMessage="When true, indexing of new posts occurs automatically. Search queries will use database search until \\"Enable Bleve for search queries\\" is enabled. <link>Learn more about Bleve in our documentation.</link>"
id="admin.bleve.enableIndexingDescription"
values={
Object {
"documentationLink": <ExternalLink
href="https://docs.mattermost.com/deploy/bleve-search.html"
location="bleve_settings"
>
<Memo(MemoizedFormattedMessage)
defaultMessage="Learn more about Bleve in our documentation."
id="admin.bleve.enableIndexingDescription.documentationLinkText"
/>
</ExternalLink>,
"link": [Function],
}
}
/>
@ -285,19 +277,11 @@ exports[`components/BleveSettings should match snapshot, enabled 1`] = `
}
helpText={
<Memo(MemoizedFormattedMessage)
defaultMessage="When true, indexing of new posts occurs automatically. Search queries will use database search until \\"Enable Bleve for search queries\\" is enabled. {documentationLink}"
defaultMessage="When true, indexing of new posts occurs automatically. Search queries will use database search until \\"Enable Bleve for search queries\\" is enabled. <link>Learn more about Bleve in our documentation.</link>"
id="admin.bleve.enableIndexingDescription"
values={
Object {
"documentationLink": <ExternalLink
href="https://docs.mattermost.com/deploy/bleve-search.html"
location="bleve_settings"
>
<Memo(MemoizedFormattedMessage)
defaultMessage="Learn more about Bleve in our documentation."
id="admin.bleve.enableIndexingDescription.documentationLinkText"
/>
</ExternalLink>,
"link": [Function],
}
}
/>

View File

@ -16,7 +16,7 @@ exports[`components/ClusterSettings should match snapshot, compression disabled
/>
</AdminHeader>
<SettingsGroup>
<ClusterTableContainer />
<Memo(ClusterTableContainer) />
<div
className="banner"
>
@ -76,7 +76,12 @@ exports[`components/ClusterSettings should match snapshot, compression disabled
/>
}
onChange={[Function]}
placeholder="E.g.: \\"Production\\" or \\"Staging\\""
placeholder={
Object {
"defaultMessage": "E.g.: \\"Production\\" or \\"Staging\\"",
"id": "admin.cluster.ClusterNameEx",
}
}
setByEnv={false}
value="test"
/>
@ -95,7 +100,12 @@ exports[`components/ClusterSettings should match snapshot, compression disabled
/>
}
onChange={[Function]}
placeholder="E.g.: \\"app-server-01\\""
placeholder={
Object {
"defaultMessage": "E.g.: \\"app-server-01\\"",
"id": "admin.cluster.OverrideHostnameEx",
}
}
setByEnv={false}
value=""
/>
@ -207,7 +217,12 @@ exports[`components/ClusterSettings should match snapshot, compression disabled
/>
}
onChange={[Function]}
placeholder="E.g.: \\"8074\\""
placeholder={
Object {
"defaultMessage": "E.g.: \\"8074\\"",
"id": "admin.cluster.GossipPortEx",
}
}
setByEnv={false}
value={8074}
/>
@ -226,7 +241,12 @@ exports[`components/ClusterSettings should match snapshot, compression disabled
/>
}
onChange={[Function]}
placeholder="E.g.: \\"8075\\""
placeholder={
Object {
"defaultMessage": "E.g.: \\"8075\\"",
"id": "admin.cluster.StreamingPortEx",
}
}
setByEnv={false}
/>
</SettingsGroup>
@ -289,7 +309,7 @@ exports[`components/ClusterSettings should match snapshot, compression enabled 1
/>
</AdminHeader>
<SettingsGroup>
<ClusterTableContainer />
<Memo(ClusterTableContainer) />
<div
className="banner"
>
@ -349,7 +369,12 @@ exports[`components/ClusterSettings should match snapshot, compression enabled 1
/>
}
onChange={[Function]}
placeholder="E.g.: \\"Production\\" or \\"Staging\\""
placeholder={
Object {
"defaultMessage": "E.g.: \\"Production\\" or \\"Staging\\"",
"id": "admin.cluster.ClusterNameEx",
}
}
setByEnv={false}
value="test"
/>
@ -368,7 +393,12 @@ exports[`components/ClusterSettings should match snapshot, compression enabled 1
/>
}
onChange={[Function]}
placeholder="E.g.: \\"app-server-01\\""
placeholder={
Object {
"defaultMessage": "E.g.: \\"app-server-01\\"",
"id": "admin.cluster.OverrideHostnameEx",
}
}
setByEnv={false}
value=""
/>
@ -480,7 +510,12 @@ exports[`components/ClusterSettings should match snapshot, compression enabled 1
/>
}
onChange={[Function]}
placeholder="E.g.: \\"8074\\""
placeholder={
Object {
"defaultMessage": "E.g.: \\"8074\\"",
"id": "admin.cluster.GossipPortEx",
}
}
setByEnv={false}
value={8074}
/>
@ -499,7 +534,12 @@ exports[`components/ClusterSettings should match snapshot, compression enabled 1
/>
}
onChange={[Function]}
placeholder="E.g.: \\"8075\\""
placeholder={
Object {
"defaultMessage": "E.g.: \\"8075\\"",
"id": "admin.cluster.StreamingPortEx",
}
}
setByEnv={false}
/>
</SettingsGroup>
@ -562,7 +602,7 @@ exports[`components/ClusterSettings should match snapshot, encryption disabled 1
/>
</AdminHeader>
<SettingsGroup>
<ClusterTableContainer />
<Memo(ClusterTableContainer) />
<div
className="banner"
>
@ -622,7 +662,12 @@ exports[`components/ClusterSettings should match snapshot, encryption disabled 1
/>
}
onChange={[Function]}
placeholder="E.g.: \\"Production\\" or \\"Staging\\""
placeholder={
Object {
"defaultMessage": "E.g.: \\"Production\\" or \\"Staging\\"",
"id": "admin.cluster.ClusterNameEx",
}
}
setByEnv={false}
value="test"
/>
@ -641,7 +686,12 @@ exports[`components/ClusterSettings should match snapshot, encryption disabled 1
/>
}
onChange={[Function]}
placeholder="E.g.: \\"app-server-01\\""
placeholder={
Object {
"defaultMessage": "E.g.: \\"app-server-01\\"",
"id": "admin.cluster.OverrideHostnameEx",
}
}
setByEnv={false}
value=""
/>
@ -753,7 +803,12 @@ exports[`components/ClusterSettings should match snapshot, encryption disabled 1
/>
}
onChange={[Function]}
placeholder="E.g.: \\"8074\\""
placeholder={
Object {
"defaultMessage": "E.g.: \\"8074\\"",
"id": "admin.cluster.GossipPortEx",
}
}
setByEnv={false}
value={8074}
/>
@ -772,7 +827,12 @@ exports[`components/ClusterSettings should match snapshot, encryption disabled 1
/>
}
onChange={[Function]}
placeholder="E.g.: \\"8075\\""
placeholder={
Object {
"defaultMessage": "E.g.: \\"8075\\"",
"id": "admin.cluster.StreamingPortEx",
}
}
setByEnv={false}
/>
</SettingsGroup>
@ -835,7 +895,7 @@ exports[`components/ClusterSettings should match snapshot, encryption enabled 1`
/>
</AdminHeader>
<SettingsGroup>
<ClusterTableContainer />
<Memo(ClusterTableContainer) />
<div
className="banner"
>
@ -895,7 +955,12 @@ exports[`components/ClusterSettings should match snapshot, encryption enabled 1`
/>
}
onChange={[Function]}
placeholder="E.g.: \\"Production\\" or \\"Staging\\""
placeholder={
Object {
"defaultMessage": "E.g.: \\"Production\\" or \\"Staging\\"",
"id": "admin.cluster.ClusterNameEx",
}
}
setByEnv={false}
value="test"
/>
@ -914,7 +979,12 @@ exports[`components/ClusterSettings should match snapshot, encryption enabled 1`
/>
}
onChange={[Function]}
placeholder="E.g.: \\"app-server-01\\""
placeholder={
Object {
"defaultMessage": "E.g.: \\"app-server-01\\"",
"id": "admin.cluster.OverrideHostnameEx",
}
}
setByEnv={false}
value=""
/>
@ -1026,7 +1096,12 @@ exports[`components/ClusterSettings should match snapshot, encryption enabled 1`
/>
}
onChange={[Function]}
placeholder="E.g.: \\"8074\\""
placeholder={
Object {
"defaultMessage": "E.g.: \\"8074\\"",
"id": "admin.cluster.GossipPortEx",
}
}
setByEnv={false}
value={8074}
/>
@ -1045,7 +1120,12 @@ exports[`components/ClusterSettings should match snapshot, encryption enabled 1`
/>
}
onChange={[Function]}
placeholder="E.g.: \\"8075\\""
placeholder={
Object {
"defaultMessage": "E.g.: \\"8075\\"",
"id": "admin.cluster.StreamingPortEx",
}
}
setByEnv={false}
/>
</SettingsGroup>

View File

@ -101,7 +101,12 @@ exports[`components/DatabaseSettings should match snapshot 1`] = `
/>
}
onChange={[Function]}
placeholder="E.g.: \\"10\\""
placeholder={
Object {
"defaultMessage": "E.g.: \\"10\\"",
"id": "admin.sql.maxConnectionsExample",
}
}
setByEnv={false}
type="text"
value={10}
@ -122,7 +127,12 @@ exports[`components/DatabaseSettings should match snapshot 1`] = `
/>
}
onChange={[Function]}
placeholder="E.g.: \\"10\\""
placeholder={
Object {
"defaultMessage": "E.g.: \\"10\\"",
"id": "admin.sql.maxOpenExample",
}
}
setByEnv={false}
type="text"
value={100}
@ -143,7 +153,12 @@ exports[`components/DatabaseSettings should match snapshot 1`] = `
/>
}
onChange={[Function]}
placeholder="E.g.: \\"30\\""
placeholder={
Object {
"defaultMessage": "E.g.: \\"30\\"",
"id": "admin.sql.queryTimeoutExample",
}
}
setByEnv={false}
type="text"
value={10}
@ -164,7 +179,12 @@ exports[`components/DatabaseSettings should match snapshot 1`] = `
/>
}
onChange={[Function]}
placeholder="E.g.: \\"3600000\\""
placeholder={
Object {
"defaultMessage": "E.g.: \\"3600000\\"",
"id": "admin.sql.connMaxLifetimeExample",
}
}
setByEnv={false}
type="text"
value={10}
@ -185,7 +205,12 @@ exports[`components/DatabaseSettings should match snapshot 1`] = `
/>
}
onChange={[Function]}
placeholder="E.g.: \\"300000\\""
placeholder={
Object {
"defaultMessage": "E.g.: \\"300000\\"",
"id": "admin.sql.connMaxIdleTimeExample",
}
}
setByEnv={false}
type="text"
value={20}
@ -211,7 +236,12 @@ exports[`components/DatabaseSettings should match snapshot 1`] = `
/>
}
onChange={[Function]}
placeholder="E.g.: \\"3\\""
placeholder={
Object {
"defaultMessage": "E.g.: \\"3\\"",
"id": "admin.service.minimumHashtagLengthExample",
}
}
setByEnv={false}
type="text"
value={10}

View File

@ -26,19 +26,11 @@ exports[`components/ElasticSearchSettings should match snapshot, disabled 1`] =
}
helpText={
<Memo(MemoizedFormattedMessage)
defaultMessage="When true, indexing of new posts occurs automatically. Search queries will use database search until \\"Enable Elasticsearch for search queries\\" is enabled. {documentationLink}"
defaultMessage="When true, indexing of new posts occurs automatically. Search queries will use database search until \\"Enable Elasticsearch for search queries\\" is enabled. <link>Learn more about Elasticsearch in our documentation.</link>"
id="admin.elasticsearch.enableIndexingDescription"
values={
Object {
"documentationLink": <ExternalLink
href="https://mattermost.com/pl/setup-elasticsearch"
location="elasticsearch_settings"
>
<Memo(MemoizedFormattedMessage)
defaultMessage="Learn more about Elasticsearch in our documentation."
id="admin.elasticsearch.enableIndexingDescription.documentationLinkText"
/>
</ExternalLink>,
"link": [Function],
}
}
/>
@ -64,19 +56,11 @@ exports[`components/ElasticSearchSettings should match snapshot, disabled 1`] =
disabled={true}
helpText={
<Memo(MemoizedFormattedMessage)
defaultMessage="The address of the Elasticsearch server. {documentationLink}"
defaultMessage="The address of the Elasticsearch server. <link>Please see documentation with server setup instructions.</link>"
id="admin.elasticsearch.connectionUrlDescription"
values={
Object {
"documentationLink": <ExternalLink
href="https://mattermost.com/pl/setup-elasticsearch"
location="elasticsearch_settings"
>
<Memo(MemoizedFormattedMessage)
defaultMessage="Please see documentation with server setup instructions."
id="admin.elasticsearch.connectionUrlExample.documentationLinkText"
/>
</ExternalLink>,
"link": [Function],
}
}
/>
@ -89,7 +73,12 @@ exports[`components/ElasticSearchSettings should match snapshot, disabled 1`] =
/>
}
onChange={[Function]}
placeholder="E.g.: \\"https://elasticsearch.example.org:9200\\""
placeholder={
Object {
"defaultMessage": "E.g.: \\"https://elasticsearch.example.org:9200\\"",
"id": "admin.elasticsearch.connectionUrlExample",
}
}
setByEnv={false}
value="test"
/>
@ -109,7 +98,12 @@ exports[`components/ElasticSearchSettings should match snapshot, disabled 1`] =
/>
}
onChange={[Function]}
placeholder="E.g.: \\"./elasticsearch/ca.pem\\""
placeholder={
Object {
"defaultMessage": "E.g.: \\"./elasticsearch/ca.pem\\"",
"id": "admin.elasticsearch.caExample",
}
}
setByEnv={false}
value="test.ca"
/>
@ -129,7 +123,12 @@ exports[`components/ElasticSearchSettings should match snapshot, disabled 1`] =
/>
}
onChange={[Function]}
placeholder="E.g.: \\"./elasticsearch/client-cert.pem\\""
placeholder={
Object {
"defaultMessage": "E.g.: \\"./elasticsearch/client-cert.pem\\"",
"id": "admin.elasticsearch.clientCertExample",
}
}
setByEnv={false}
value="test.crt"
/>
@ -149,7 +148,12 @@ exports[`components/ElasticSearchSettings should match snapshot, disabled 1`] =
/>
}
onChange={[Function]}
placeholder="E.g.: \\"./elasticsearch/client-key.pem\\""
placeholder={
Object {
"defaultMessage": "E.g.: \\"./elasticsearch/client-key.pem\\"",
"id": "admin.elasticsearch.clientKeyExample",
}
}
setByEnv={false}
value="test.key"
/>
@ -200,7 +204,12 @@ exports[`components/ElasticSearchSettings should match snapshot, disabled 1`] =
/>
}
onChange={[Function]}
placeholder="E.g.: \\"elastic\\""
placeholder={
Object {
"defaultMessage": "E.g.: \\"elastic\\"",
"id": "admin.elasticsearch.usernameExample",
}
}
setByEnv={false}
value="test"
/>
@ -220,7 +229,12 @@ exports[`components/ElasticSearchSettings should match snapshot, disabled 1`] =
/>
}
onChange={[Function]}
placeholder="E.g.: \\"yourpassword\\""
placeholder={
Object {
"defaultMessage": "E.g.: \\"yourpassword\\"",
"id": "admin.elasticsearch.password",
}
}
setByEnv={false}
value="test"
/>
@ -378,7 +392,12 @@ exports[`components/ElasticSearchSettings should match snapshot, disabled 1`] =
/>
}
onChange={[Function]}
placeholder="E.g.: .opendistro*,.security*"
placeholder={
Object {
"defaultMessage": "E.g.: .opendistro*,.security*",
"id": "admin.elasticsearch.ignoredPurgeIndexesDescription.example",
}
}
setByEnv={false}
/>
<BooleanSetting
@ -513,19 +532,11 @@ exports[`components/ElasticSearchSettings should match snapshot, enabled 1`] = `
}
helpText={
<Memo(MemoizedFormattedMessage)
defaultMessage="When true, indexing of new posts occurs automatically. Search queries will use database search until \\"Enable Elasticsearch for search queries\\" is enabled. {documentationLink}"
defaultMessage="When true, indexing of new posts occurs automatically. Search queries will use database search until \\"Enable Elasticsearch for search queries\\" is enabled. <link>Learn more about Elasticsearch in our documentation.</link>"
id="admin.elasticsearch.enableIndexingDescription"
values={
Object {
"documentationLink": <ExternalLink
href="https://mattermost.com/pl/setup-elasticsearch"
location="elasticsearch_settings"
>
<Memo(MemoizedFormattedMessage)
defaultMessage="Learn more about Elasticsearch in our documentation."
id="admin.elasticsearch.enableIndexingDescription.documentationLinkText"
/>
</ExternalLink>,
"link": [Function],
}
}
/>
@ -551,19 +562,11 @@ exports[`components/ElasticSearchSettings should match snapshot, enabled 1`] = `
disabled={false}
helpText={
<Memo(MemoizedFormattedMessage)
defaultMessage="The address of the Elasticsearch server. {documentationLink}"
defaultMessage="The address of the Elasticsearch server. <link>Please see documentation with server setup instructions.</link>"
id="admin.elasticsearch.connectionUrlDescription"
values={
Object {
"documentationLink": <ExternalLink
href="https://mattermost.com/pl/setup-elasticsearch"
location="elasticsearch_settings"
>
<Memo(MemoizedFormattedMessage)
defaultMessage="Please see documentation with server setup instructions."
id="admin.elasticsearch.connectionUrlExample.documentationLinkText"
/>
</ExternalLink>,
"link": [Function],
}
}
/>
@ -576,7 +579,12 @@ exports[`components/ElasticSearchSettings should match snapshot, enabled 1`] = `
/>
}
onChange={[Function]}
placeholder="E.g.: \\"https://elasticsearch.example.org:9200\\""
placeholder={
Object {
"defaultMessage": "E.g.: \\"https://elasticsearch.example.org:9200\\"",
"id": "admin.elasticsearch.connectionUrlExample",
}
}
setByEnv={false}
value="test"
/>
@ -596,7 +604,12 @@ exports[`components/ElasticSearchSettings should match snapshot, enabled 1`] = `
/>
}
onChange={[Function]}
placeholder="E.g.: \\"./elasticsearch/ca.pem\\""
placeholder={
Object {
"defaultMessage": "E.g.: \\"./elasticsearch/ca.pem\\"",
"id": "admin.elasticsearch.caExample",
}
}
setByEnv={false}
value="test.ca"
/>
@ -616,7 +629,12 @@ exports[`components/ElasticSearchSettings should match snapshot, enabled 1`] = `
/>
}
onChange={[Function]}
placeholder="E.g.: \\"./elasticsearch/client-cert.pem\\""
placeholder={
Object {
"defaultMessage": "E.g.: \\"./elasticsearch/client-cert.pem\\"",
"id": "admin.elasticsearch.clientCertExample",
}
}
setByEnv={false}
value="test.crt"
/>
@ -636,7 +654,12 @@ exports[`components/ElasticSearchSettings should match snapshot, enabled 1`] = `
/>
}
onChange={[Function]}
placeholder="E.g.: \\"./elasticsearch/client-key.pem\\""
placeholder={
Object {
"defaultMessage": "E.g.: \\"./elasticsearch/client-key.pem\\"",
"id": "admin.elasticsearch.clientKeyExample",
}
}
setByEnv={false}
value="test.key"
/>
@ -687,7 +710,12 @@ exports[`components/ElasticSearchSettings should match snapshot, enabled 1`] = `
/>
}
onChange={[Function]}
placeholder="E.g.: \\"elastic\\""
placeholder={
Object {
"defaultMessage": "E.g.: \\"elastic\\"",
"id": "admin.elasticsearch.usernameExample",
}
}
setByEnv={false}
value="test"
/>
@ -707,7 +735,12 @@ exports[`components/ElasticSearchSettings should match snapshot, enabled 1`] = `
/>
}
onChange={[Function]}
placeholder="E.g.: \\"yourpassword\\""
placeholder={
Object {
"defaultMessage": "E.g.: \\"yourpassword\\"",
"id": "admin.elasticsearch.password",
}
}
setByEnv={false}
value="test"
/>
@ -864,7 +897,12 @@ exports[`components/ElasticSearchSettings should match snapshot, enabled 1`] = `
/>
}
onChange={[Function]}
placeholder="E.g.: .opendistro*,.security*"
placeholder={
Object {
"defaultMessage": "E.g.: .opendistro*,.security*",
"id": "admin.elasticsearch.ignoredPurgeIndexesDescription.example",
}
}
setByEnv={false}
/>
<BooleanSetting

View File

@ -68,7 +68,12 @@ exports[`components/MessageExportSettings should match snapshot, disabled, actia
/>
}
onChange={[Function]}
placeholder="E.g.: \\"02:00\\""
placeholder={
Object {
"defaultMessage": "E.g.: \\"02:00\\"",
"id": "admin.complianceExport.exportJobStartTime.example",
}
}
setByEnv={false}
value="01:00"
/>
@ -76,11 +81,13 @@ exports[`components/MessageExportSettings should match snapshot, disabled, actia
disabled={true}
helpText={
<FormattedMarkdownMessage
defaultMessage="Format of the compliance export. Corresponds to the system that you want to import the data into.\\\\n \\\\nFor Actiance XML, compliance export files are written to the \\\\\\"exports\\\\\\" subdirectory of the configured [Local Storage Directory]({siteURL}/admin_console/environment/file_storage). For Global Relay EML, they are emailed to the configured email address."
defaultMessage="Format of the compliance export. Corresponds to the system that you want to import the data into.{lineBreak} {lineBreak}For Actiance XML, compliance export files are written to the exports subdirectory of the configured [Local Storage Directory]({url}). For Global Relay EML, they are emailed to the configured email address."
id="admin.complianceExport.exportFormat.description"
values={
Object {
"siteURL": "http://localhost:8065",
"lineBreak": "
",
"url": "http://localhost:8065/admin_console/environment/file_storage",
}
}
/>
@ -241,7 +248,12 @@ exports[`components/MessageExportSettings should match snapshot, disabled, globa
/>
}
onChange={[Function]}
placeholder="E.g.: \\"02:00\\""
placeholder={
Object {
"defaultMessage": "E.g.: \\"02:00\\"",
"id": "admin.complianceExport.exportJobStartTime.example",
}
}
setByEnv={false}
value="01:00"
/>
@ -249,11 +261,13 @@ exports[`components/MessageExportSettings should match snapshot, disabled, globa
disabled={true}
helpText={
<FormattedMarkdownMessage
defaultMessage="Format of the compliance export. Corresponds to the system that you want to import the data into.\\\\n \\\\nFor Actiance XML, compliance export files are written to the \\\\\\"exports\\\\\\" subdirectory of the configured [Local Storage Directory]({siteURL}/admin_console/environment/file_storage). For Global Relay EML, they are emailed to the configured email address."
defaultMessage="Format of the compliance export. Corresponds to the system that you want to import the data into.{lineBreak} {lineBreak}For Actiance XML, compliance export files are written to the exports subdirectory of the configured [Local Storage Directory]({url}). For Global Relay EML, they are emailed to the configured email address."
id="admin.complianceExport.exportFormat.description"
values={
Object {
"siteURL": "http://localhost:8065",
"lineBreak": "
",
"url": "http://localhost:8065/admin_console/environment/file_storage",
}
}
/>
@ -339,7 +353,12 @@ exports[`components/MessageExportSettings should match snapshot, disabled, globa
/>
}
onChange={[Function]}
placeholder="E.g.: \\"globalRelayUser\\""
placeholder={
Object {
"defaultMessage": "E.g.: \\"globalRelayUser\\"",
"id": "admin.complianceExport.globalRelaySMTPUsername.example",
}
}
setByEnv={false}
value="globalRelayUser"
/>
@ -359,7 +378,12 @@ exports[`components/MessageExportSettings should match snapshot, disabled, globa
/>
}
onChange={[Function]}
placeholder="E.g.: \\"globalRelayPassword\\""
placeholder={
Object {
"defaultMessage": "E.g.: \\"globalRelayPassword\\"",
"id": "admin.complianceExport.globalRelaySMTPPassword.example",
}
}
setByEnv={false}
value="globalRelayPassword"
/>
@ -379,7 +403,12 @@ exports[`components/MessageExportSettings should match snapshot, disabled, globa
/>
}
onChange={[Function]}
placeholder="E.g.: \\"globalrelay@mattermost.com\\""
placeholder={
Object {
"defaultMessage": "E.g.: \\"globalrelay@mattermost.com\\"",
"id": "admin.complianceExport.globalRelayEmailAddress.example",
}
}
setByEnv={false}
value="globalRelay@mattermost.com"
/>
@ -513,7 +542,12 @@ exports[`components/MessageExportSettings should match snapshot, enabled, actian
/>
}
onChange={[Function]}
placeholder="E.g.: \\"02:00\\""
placeholder={
Object {
"defaultMessage": "E.g.: \\"02:00\\"",
"id": "admin.complianceExport.exportJobStartTime.example",
}
}
setByEnv={false}
value="01:00"
/>
@ -521,11 +555,13 @@ exports[`components/MessageExportSettings should match snapshot, enabled, actian
disabled={false}
helpText={
<FormattedMarkdownMessage
defaultMessage="Format of the compliance export. Corresponds to the system that you want to import the data into.\\\\n \\\\nFor Actiance XML, compliance export files are written to the \\\\\\"exports\\\\\\" subdirectory of the configured [Local Storage Directory]({siteURL}/admin_console/environment/file_storage). For Global Relay EML, they are emailed to the configured email address."
defaultMessage="Format of the compliance export. Corresponds to the system that you want to import the data into.{lineBreak} {lineBreak}For Actiance XML, compliance export files are written to the exports subdirectory of the configured [Local Storage Directory]({url}). For Global Relay EML, they are emailed to the configured email address."
id="admin.complianceExport.exportFormat.description"
values={
Object {
"siteURL": "http://localhost:8065",
"lineBreak": "
",
"url": "http://localhost:8065/admin_console/environment/file_storage",
}
}
/>
@ -686,7 +722,12 @@ exports[`components/MessageExportSettings should match snapshot, enabled, global
/>
}
onChange={[Function]}
placeholder="E.g.: \\"02:00\\""
placeholder={
Object {
"defaultMessage": "E.g.: \\"02:00\\"",
"id": "admin.complianceExport.exportJobStartTime.example",
}
}
setByEnv={false}
value="01:00"
/>
@ -694,11 +735,13 @@ exports[`components/MessageExportSettings should match snapshot, enabled, global
disabled={false}
helpText={
<FormattedMarkdownMessage
defaultMessage="Format of the compliance export. Corresponds to the system that you want to import the data into.\\\\n \\\\nFor Actiance XML, compliance export files are written to the \\\\\\"exports\\\\\\" subdirectory of the configured [Local Storage Directory]({siteURL}/admin_console/environment/file_storage). For Global Relay EML, they are emailed to the configured email address."
defaultMessage="Format of the compliance export. Corresponds to the system that you want to import the data into.{lineBreak} {lineBreak}For Actiance XML, compliance export files are written to the exports subdirectory of the configured [Local Storage Directory]({url}). For Global Relay EML, they are emailed to the configured email address."
id="admin.complianceExport.exportFormat.description"
values={
Object {
"siteURL": "http://localhost:8065",
"lineBreak": "
",
"url": "http://localhost:8065/admin_console/environment/file_storage",
}
}
/>
@ -784,7 +827,12 @@ exports[`components/MessageExportSettings should match snapshot, enabled, global
/>
}
onChange={[Function]}
placeholder="E.g.: \\"globalRelayUser\\""
placeholder={
Object {
"defaultMessage": "E.g.: \\"globalRelayUser\\"",
"id": "admin.complianceExport.globalRelaySMTPUsername.example",
}
}
setByEnv={false}
value="globalRelayUser"
/>
@ -804,7 +852,12 @@ exports[`components/MessageExportSettings should match snapshot, enabled, global
/>
}
onChange={[Function]}
placeholder="E.g.: \\"globalRelayPassword\\""
placeholder={
Object {
"defaultMessage": "E.g.: \\"globalRelayPassword\\"",
"id": "admin.complianceExport.globalRelaySMTPPassword.example",
}
}
setByEnv={false}
value="globalRelayPassword"
/>
@ -824,7 +877,12 @@ exports[`components/MessageExportSettings should match snapshot, enabled, global
/>
}
onChange={[Function]}
placeholder="E.g.: \\"globalrelay@mattermost.com\\""
placeholder={
Object {
"defaultMessage": "E.g.: \\"globalrelay@mattermost.com\\"",
"id": "admin.complianceExport.globalRelayEmailAddress.example",
}
}
setByEnv={false}
value="globalRelay@mattermost.com"
/>

View File

@ -122,7 +122,12 @@ exports[`components/PushSettings should match snapshot, licensed 1`] = `
/>
}
onChange={[Function]}
placeholder="E.g.: \\"https://push-test.mattermost.com\\""
placeholder={
Object {
"defaultMessage": "E.g.: \\"https://push-test.mattermost.com\\"",
"id": "admin.email.pushServerEx",
}
}
setByEnv={false}
value="https://push.mattermost.com"
/>
@ -141,7 +146,12 @@ exports[`components/PushSettings should match snapshot, licensed 1`] = `
/>
}
onChange={[Function]}
placeholder="E.g.: \\"1000\\""
placeholder={
Object {
"defaultMessage": "E.g.: \\"1000\\"",
"id": "admin.team.maxNotificationsPerChannelExample",
}
}
setByEnv={false}
type="number"
value={1000}
@ -256,7 +266,12 @@ exports[`components/PushSettings should match snapshot, unlicensed 1`] = `
/>
}
onChange={[Function]}
placeholder="E.g.: \\"https://push-test.mattermost.com\\""
placeholder={
Object {
"defaultMessage": "E.g.: \\"https://push-test.mattermost.com\\"",
"id": "admin.email.pushServerEx",
}
}
setByEnv={false}
value="https://push.mattermost.com"
/>
@ -275,7 +290,12 @@ exports[`components/PushSettings should match snapshot, unlicensed 1`] = `
/>
}
onChange={[Function]}
placeholder="E.g.: \\"1000\\""
placeholder={
Object {
"defaultMessage": "E.g.: \\"1000\\"",
"id": "admin.team.maxNotificationsPerChannelExample",
}
}
setByEnv={false}
type="number"
value={1000}

View File

@ -2,6 +2,7 @@
exports[`components/admin_console/SchemaAdminSettings should match snapshot with custom component 1`] = `
<component
cloud={Object {}}
config={
Object {
"EscapedSettings": Object {
@ -24,6 +25,10 @@ exports[`components/admin_console/SchemaAdminSettings should match snapshot with
},
}
}
consoleAccess={Object {}}
disabled={false}
editRole={[MockFunction]}
enterpriseReady={false}
environmentConfig={
Object {
"FirstSettings": Object {
@ -31,11 +36,54 @@ exports[`components/admin_console/SchemaAdminSettings should match snapshot with
},
}
}
intl={
Object {
"$t": [Function],
"defaultFormats": Object {},
"defaultLocale": "en",
"defaultRichTextElements": undefined,
"fallbackOnEmptyString": true,
"formatDate": [Function],
"formatDateTimeRange": [Function],
"formatDateToParts": [Function],
"formatDisplayName": [Function],
"formatList": [Function],
"formatListToParts": [Function],
"formatMessage": [Function],
"formatNumber": [Function],
"formatNumberToParts": [Function],
"formatPlural": [Function],
"formatRelativeTime": [Function],
"formatTime": [Function],
"formatTimeToParts": [Function],
"formats": Object {},
"formatters": Object {
"getDateTimeFormat": [Function],
"getDisplayNames": [Function],
"getListFormat": [Function],
"getMessageFormat": [Function],
"getNumberFormat": [Function],
"getPluralRules": [Function],
"getRelativeTimeFormat": [Function],
},
"locale": "en",
"messages": Object {},
"onError": [Function],
"onWarn": [Function],
"textComponent": "span",
"timeZone": "Etc/UTC",
}
}
isCurrentUserSystemAdmin={false}
isDisabled={false}
license={Object {}}
roles={Object {}}
schema={
Object {
"component": [Function],
}
}
setNavigationBlocked={[MockFunction]}
updateConfig={[MockFunction]}
/>
`;
@ -44,12 +92,7 @@ exports[`components/admin_console/SchemaAdminSettings should match snapshot with
<div
className="wrapper--fixed "
>
<AdminHeader>
<MemoizedFormattedMessage
defaultMessage="Configuration"
id="config"
/>
</AdminHeader>
config
<div
className="admin-console__wrapper"
>
@ -69,16 +112,14 @@ exports[`components/admin_console/SchemaAdminSettings should match snapshot with
footer={null}
helpText={
<SchemaText
isTranslated={true}
text="help-text-a"
textDefault="This is some help text for the text field."
/>
}
id="FirstSettings.settinga"
key="Config_text_FirstSettings.settinga"
label="Setting One"
label="label-a"
onChange={[Function]}
placeholder="e.g. some setting"
placeholder="placeholder-a"
setByEnv={false}
type="text"
value="fsdsdg"
@ -93,14 +134,12 @@ exports[`components/admin_console/SchemaAdminSettings should match snapshot with
}
helpText={
<SchemaText
isTranslated={true}
text="help-text-b"
textDefault="This is some help text for the bool field."
/>
}
id="FirstSettings.settingb"
key="Config_bool_FirstSettings.settingb"
label="Setting Two"
label="label-b"
onChange={[Function]}
setByEnv={false}
trueText={
@ -109,20 +148,18 @@ exports[`components/admin_console/SchemaAdminSettings should match snapshot with
id="admin.true"
/>
}
value={false}
value={true}
/>
<Memo(DropdownSetting)
disabled={false}
helpText={
<SchemaText
isTranslated={true}
text="help-text-c"
textDefault="This is some help text for the dropdown field."
/>
}
id="FirstSettings.settingc"
key="Config_dropdown_FirstSettings.settingc"
label="Setting Three"
label="label-c"
onChange={[Function]}
setByEnv={false}
value="option3"
@ -147,14 +184,12 @@ exports[`components/admin_console/SchemaAdminSettings should match snapshot with
disabled={false}
helpText={
<SchemaText
isTranslated={true}
text="help-text-d"
textDefault="This is some help text for the radio field."
/>
}
id="SecondSettings.settingd"
key="Config_radio_SecondSettings.settingd"
label="Setting Four"
label="label-d"
onChange={[Function]}
setByEnv={false}
value="option1"
@ -179,16 +214,14 @@ exports[`components/admin_console/SchemaAdminSettings should match snapshot with
disabled={false}
helpText={
<SchemaText
isTranslated={true}
text="help-text-e"
textDefault="This is some help text for the generated field."
/>
}
id="SecondSettings.settinge"
key="Config_generated_SecondSettings.settinge"
label="Setting Five"
label="label-e"
onChange={[Function]}
placeholder="e.g. 47KyfOxtk5+ovi1MDHFyzMDHIA6esMWb"
placeholder="placeholder-e"
regenerateHelpText="This is help text for the regenerate button."
regenerateText={
<Memo(MemoizedFormattedMessage)
@ -203,16 +236,14 @@ exports[`components/admin_console/SchemaAdminSettings should match snapshot with
disabled={false}
helpText={
<SchemaText
isTranslated={true}
text="help-text-f"
textDefault="This is some help text for the user autocomplete field."
/>
}
id="SecondSettings.settingf"
key="Config_userautocomplete_SecondSettings.settingf"
label="Setting Six"
label="label-f"
onChange={[Function]}
placeholder="Type a username here"
placeholder="placeholder-f"
value="3xz3r6n7dtbbmgref3yw4zg7sr"
/>
<AdminTextSetting
@ -220,16 +251,14 @@ exports[`components/admin_console/SchemaAdminSettings should match snapshot with
footer={null}
helpText={
<SchemaText
isTranslated={true}
text="help-text-g"
textDefault="This is some help text for the number field."
/>
}
id="SecondSettings.settingg"
key="Config_text_SecondSettings.settingg"
label="Setting Seven"
label="label-g"
onChange={[Function]}
placeholder="e.g. some setting"
placeholder="placeholder-g"
setByEnv={false}
type="number"
value={7}
@ -239,16 +268,14 @@ exports[`components/admin_console/SchemaAdminSettings should match snapshot with
footer={null}
helpText={
<SchemaText
isTranslated={true}
text="help-text-h"
textDefault="This is some help text for the number field."
/>
}
id="SecondSettings.settingh"
key="Config_text_SecondSettings.settingh"
label="Setting Eight"
label="label-h"
onChange={[Function]}
placeholder="e.g. some setting"
placeholder="placeholder-h"
setByEnv={false}
type="number"
value={10}
@ -261,10 +288,9 @@ exports[`components/admin_console/SchemaAdminSettings should match snapshot with
className="banner__content"
>
<span>
<MemoizedFormattedMessage
defaultMessage="Setting Eight"
id="label-h"
/>
<span>
label-h
</span>
</span>
</div>
</div>
@ -272,14 +298,12 @@ exports[`components/admin_console/SchemaAdminSettings should match snapshot with
disabled={false}
helpText={
<SchemaText
isTranslated={true}
text="help-text-i"
textDefault="This is some help text for the language field."
/>
}
id="SecondSettings.settingi"
key="Config_language_SecondSettings.settingi"
label="Setting Nine"
label="label-i"
onChange={[Function]}
setByEnv={false}
value="de"
@ -402,20 +426,13 @@ exports[`components/admin_console/SchemaAdminSettings should match snapshot with
disabled={false}
helpText={
<SchemaText
isTranslated={true}
text="help-text-j"
textDefault="This is some help text for the multiple-language field."
/>
}
id="SecondSettings.settingj"
key="Config_language_SecondSettings.settingj"
label="Setting Nine"
noResultText={
<Memo(MemoizedFormattedMessage)
defaultMessage="No result"
id="no-result-j"
/>
}
label="label-j"
noResultText="no-result-j"
onChange={[Function]}
selected={Array []}
setByEnv={false}
@ -537,21 +554,14 @@ exports[`components/admin_console/SchemaAdminSettings should match snapshot with
<RequestButton
buttonText={
<span>
Setting Eleven
label-k
</span>
}
disabled={false}
errorMessage={
Object {
"defaultMessage": "Reload unsuccessful: {error}",
"id": "admin.reload.reloadFail",
}
}
errorMessage="admin.reload.reloadFail"
helpText={
<SchemaText
isTranslated={true}
text="help-text-k"
textDefault="This is some help text for the button field."
/>
}
id="SecondSettings.settingk"
@ -577,14 +587,12 @@ exports[`components/admin_console/SchemaAdminSettings should match snapshot with
}
helpText={
<SchemaText
isTranslated={true}
text="help-text-l"
textDefault="This is some help text for the second bool field."
/>
}
id="FirstSettings.settingl"
key="Config_bool_FirstSettings.settingl"
label="Setting Twelve"
label="label-l"
onChange={[Function]}
setByEnv={true}
trueText={
@ -599,14 +607,12 @@ exports[`components/admin_console/SchemaAdminSettings should match snapshot with
disabled={false}
helpText={
<SchemaText
isTranslated={true}
text="help-text-m"
textDefault="This is some help text for the color field."
/>
}
id="FirstSettings.settingm"
key="Config_text_FirstSettings.settingm"
label="Setting Thirteen"
label="label-m"
onChange={[Function]}
value=""
/>
@ -635,9 +641,15 @@ exports[`components/admin_console/SchemaAdminSettings should match snapshot with
}
}
disabled={false}
helpText={null}
helpText={
<span>
</span>
}
id="custom"
key="Config_custom_custom"
label=""
license={Object {}}
onChange={[Function]}
registerSaveAction={[Function]}
setByEnv={false}
@ -646,16 +658,10 @@ exports[`components/admin_console/SchemaAdminSettings should match snapshot with
unRegisterSaveAction={[Function]}
/>
<Connect(JobTable)
createJobButtonText={
<Memo(MemoizedFormattedMessage)
defaultMessage="Setting Twelve"
id="label-l"
/>
}
createJobButtonText="label-l"
createJobHelpText={
<FormattedMarkdownMessage
defaultMessage="This is some help text for the jobs table field."
id="help-text-l"
<SchemaText
text="help-text-l"
/>
}
disabled={false}
@ -673,14 +679,12 @@ exports[`components/admin_console/SchemaAdminSettings should match snapshot with
}
helpText={
<SchemaText
isTranslated={true}
text="escaped-help-text-a"
textDefault="This is some help text for the first escaped field."
/>
}
id="EscapedSettings.com+example+setting.a"
key="Config_bool_EscapedSettings.com+example+setting.a"
label="Escaped Setting A"
label="escaped-label-a"
onChange={[Function]}
setByEnv={false}
trueText={
@ -731,7 +735,6 @@ exports[`components/admin_console/SchemaAdminSettings should match snapshot with
</div>
<Overlay
animation={[Function]}
delayShow={400}
placement="top"
rootClose={false}
show={false}

View File

@ -6,9 +6,8 @@ import {Route, Switch, Redirect} from 'react-router-dom';
import type {RouteComponentProps} from 'react-router-dom';
import type {CloudState} from '@mattermost/types/cloud';
import type {AdminConfig, EnvironmentConfig} from '@mattermost/types/config';
import type {AdminConfig, ClientLicense, EnvironmentConfig} from '@mattermost/types/config';
import type {Role} from '@mattermost/types/roles';
import type {DeepPartial} from '@mattermost/types/utilities';
import type {ActionResult} from 'mattermost-redux/types/actions';
@ -38,13 +37,13 @@ type State = {
// not every page in the system console will need the license and config, but the vast majority will
type ExtraProps = {
enterpriseReady: boolean;
license?: Record<string, any>;
config?: DeepPartial<AdminConfig>;
environmentConfig?: Partial<EnvironmentConfig>;
setNavigationBlocked?: () => void;
roles?: Record<string, Role>;
editRole?: (role: Role) => void;
updateConfig?: (config: AdminConfig) => Promise<ActionResult>;
license: ClientLicense;
config: Partial<AdminConfig>;
environmentConfig: Partial<EnvironmentConfig>;
setNavigationBlocked: (blocked: boolean) => void;
roles: Record<string, Role>;
editRole: (role: Role) => void;
updateConfig: (config: AdminConfig) => Promise<ActionResult>;
cloud: CloudState;
isCurrentUserSystemAdmin: boolean;
}

View File

@ -2,7 +2,7 @@
// See LICENSE.txt for license information.
import React from 'react';
import {FormattedMessage} from 'react-intl';
import {FormattedMessage, defineMessage} from 'react-intl';
const SECTION_NONE = (
<tr>
@ -156,17 +156,14 @@ export const WEBSERVER_MODE_HELP_TEXT = (
export const LOG_LEVEL_OPTIONS = [
{
value: 'DEBUG',
display_name: 'DEBUG',
display_name_default: 'DEBUG',
display_name: defineMessage({id: 'admin.log.levelOptions.DEBUG', defaultMessage: 'DEBUG'}),
},
{
value: 'INFO',
display_name: 'INFO',
display_name_default: 'INFO',
display_name: defineMessage({id: 'admin.log.levelOptions.INFO', defaultMessage: 'INFO'}),
},
{
value: 'ERROR',
display_name: 'ERROR',
display_name_default: 'ERROR',
display_name: defineMessage({id: 'admin.log.levelOptions.ERROR', defaultMessage: 'ERROR'}),
},
];

View File

@ -1157,7 +1157,7 @@ exports[`components/AdminSidebar should match snapshot 1`] = `
name="experimental/feature_flags"
title={
<Memo(MemoizedFormattedMessage)
defaultMessage="Feature Flags"
defaultMessage="Features Flags"
id="admin.feature_flags.title"
/>
}
@ -1851,7 +1851,7 @@ exports[`components/AdminSidebar should match snapshot with workspace optimizati
name="experimental/feature_flags"
title={
<Memo(MemoizedFormattedMessage)
defaultMessage="Feature Flags"
defaultMessage="Features Flags"
id="admin.feature_flags.title"
/>
}
@ -2600,7 +2600,7 @@ exports[`components/AdminSidebar should match snapshot, not prevent the console
name="experimental/feature_flags"
title={
<Memo(MemoizedFormattedMessage)
defaultMessage="Feature Flags"
defaultMessage="Features Flags"
id="admin.feature_flags.title"
/>
}
@ -3294,7 +3294,7 @@ exports[`components/AdminSidebar should match snapshot, render plugins without a
name="experimental/feature_flags"
title={
<Memo(MemoizedFormattedMessage)
defaultMessage="Feature Flags"
defaultMessage="Features Flags"
id="admin.feature_flags.title"
/>
}
@ -4150,7 +4150,7 @@ exports[`components/AdminSidebar should match snapshot, with license (with all f
name="experimental/feature_flags"
title={
<Memo(MemoizedFormattedMessage)
defaultMessage="Feature Flags"
defaultMessage="Features Flags"
id="admin.feature_flags.title"
/>
}
@ -5103,7 +5103,7 @@ exports[`components/AdminSidebar should match snapshot, with license (without an
name="experimental/feature_flags"
title={
<Memo(MemoizedFormattedMessage)
defaultMessage="Feature Flags"
defaultMessage="Features Flags"
id="admin.feature_flags.title"
/>
}

View File

@ -2,7 +2,6 @@
// See LICENSE.txt for license information.
import React from 'react';
import type {IntlShape} from 'react-intl';
import {SelfHostedSignupProgress} from '@mattermost/types/cloud';
import type {ExperimentalSettings, PluginSettings, SSOSettings, Office365Settings} from '@mattermost/types/config';
@ -11,7 +10,7 @@ import {RESOURCE_KEYS} from 'mattermost-redux/constants/permissions_sysconsole';
import AdminDefinition from 'components/admin_console/admin_definition';
import AdminSidebar from 'components/admin_console/admin_sidebar/admin_sidebar';
import type {Props} from 'components/admin_console/admin_sidebar/admin_sidebar';
import type {Props as OriginalProps} from 'components/admin_console/admin_sidebar/admin_sidebar';
import {samplePlugin1} from 'tests/helpers/admin_console_plugin_index_sample_pluings';
import {shallowWithIntl} from 'tests/helpers/intl-test-helper';
@ -27,8 +26,10 @@ jest.mock('utils/utils', () => {
jest.mock('utils/admin_console_index');
type Props = Omit<OriginalProps, 'intl'>;
describe('components/AdminSidebar', () => {
const defaultProps: Props = {
const defaultProps: Omit<Props, 'intl'> = {
license: {},
config: {
ExperimentalSettings: {
@ -40,7 +41,6 @@ describe('components/AdminSidebar', () => {
} as PluginSettings,
FeatureFlags: {},
},
intl: {} as IntlShape,
adminDefinition: AdminDefinition,
buildEnterpriseReady: false,
navigationBlocked: false,
@ -155,7 +155,6 @@ describe('components/AdminSidebar', () => {
EnableUploads: true,
} as PluginSettings,
},
intl: {} as IntlShape,
adminDefinition: AdminDefinition,
buildEnterpriseReady: false,
siteName: 'test snap',
@ -202,7 +201,6 @@ describe('components/AdminSidebar', () => {
EnableUploads: true,
} as PluginSettings,
},
intl: {} as IntlShape,
adminDefinition: AdminDefinition,
buildEnterpriseReady: false,
siteName: 'test snap',
@ -251,7 +249,6 @@ describe('components/AdminSidebar', () => {
EnableUploads: true,
} as PluginSettings,
},
intl: {} as IntlShape,
adminDefinition: AdminDefinition,
buildEnterpriseReady: true,
navigationBlocked: false,
@ -328,7 +325,6 @@ describe('components/AdminSidebar', () => {
Scope: 'scope',
} as Office365Settings,
},
intl: {} as IntlShape,
adminDefinition: AdminDefinition,
buildEnterpriseReady: true,
navigationBlocked: false,
@ -375,7 +371,6 @@ describe('components/AdminSidebar', () => {
EnableUploads: true,
} as PluginSettings,
},
intl: {} as IntlShape,
adminDefinition: AdminDefinition,
buildEnterpriseReady: true,
navigationBlocked: false,
@ -464,7 +459,6 @@ describe('components/AdminSidebar', () => {
EnableUploads: true,
} as PluginSettings,
},
intl: {} as IntlShape,
adminDefinition: AdminDefinition,
buildEnterpriseReady: true,
navigationBlocked: false,

View File

@ -20,7 +20,6 @@ import SearchIcon from 'components/widgets/icons/search_icon';
import {generateIndex} from 'utils/admin_console_index';
import type {Index} from 'utils/admin_console_index';
import {getHistory} from 'utils/browser_history';
import {localizeMessage} from 'utils/utils';
import type AdminDefinition from '../admin_definition';
@ -140,7 +139,7 @@ class AdminSidebar extends React.PureComponent<Props, State> {
currentSiteName = ' - ' + this.props.siteName;
}
document.title = localizeMessage('sidebar_right_menu.console', 'System Console') + currentSiteName;
document.title = this.props.intl.formatMessage({id: 'sidebar_right_menu.console', defaultMessage: 'System Console'}) + currentSiteName;
};
visibleSections = () => {
@ -210,10 +209,11 @@ class AdminSidebar extends React.PureComponent<Props, State> {
name={item.url}
restrictedIndicator={item.restrictedIndicator?.shouldDisplay(license, subscriptionProduct) ? item.restrictedIndicator.value(cloud) : undefined}
title={
<FormattedMessage
id={item.title}
defaultMessage={item.title_default}
/>
typeof item.title === 'string' ?
item.title :
<FormattedMessage
{...item.title}
/>
}
/>
));
@ -238,10 +238,11 @@ class AdminSidebar extends React.PureComponent<Props, State> {
icon={section.icon}
sectionClass=''
title={
<FormattedMessage
id={section.sectionTitle}
defaultMessage={section.sectionTitleDefault}
/>
typeof section.sectionTitle === 'string' ?
section.sectionTitle :
<FormattedMessage
{...section.sectionTitle}
/>
}
>
{sidebarItems}
@ -303,7 +304,7 @@ class AdminSidebar extends React.PureComponent<Props, State> {
type='text'
onChange={this.onFilterChange}
value={this.state.filter}
placeholder={localizeMessage('admin.sidebar.filter', 'Find settings')}
placeholder={this.props.intl.formatMessage({id: 'admin.sidebar.filter', defaultMessage: 'Find settings'})}
ref={this.searchRef}
id='adminSidebarFilter'
clearable={true}

View File

@ -7,7 +7,7 @@ import {NavLink, Route} from 'react-router-dom';
type Props = {
icon: JSX.Element;
title: JSX.Element;
title: string | JSX.Element;
action?: JSX.Element;
children?: JSX.Element[];
definitionKey?: string;

View File

@ -3,7 +3,7 @@
import React from 'react';
import type {CSSProperties} from 'react';
import {FormattedMessage} from 'react-intl';
import {FormattedMessage, defineMessages} from 'react-intl';
import type {Audit} from '@mattermost/types/audits';
@ -27,6 +27,14 @@ type State = {
loadingAudits: boolean;
};
const messages = defineMessages({
reload: {id: 'admin.audits.reload', defaultMessage: 'Reload User Activity Logs'},
});
export const searchableStrings = [
messages.reload,
];
export default class Audits extends React.PureComponent<Props, State> {
public constructor(props: Props) {
super(props);
@ -71,10 +79,7 @@ export default class Audits extends React.PureComponent<Props, State> {
onClick={this.reload}
>
<ReloadIcon/>
<FormattedMessage
id='admin.audits.reload'
defaultMessage='Reload User Activity Logs'
/>
<FormattedMessage {...messages.reload}/>
</button>
</div>
);

View File

@ -2,7 +2,7 @@
// See LICENSE.txt for license information.
import React, {useEffect} from 'react';
import {FormattedMessage} from 'react-intl';
import {FormattedMessage, defineMessages} from 'react-intl';
import {useDispatch, useSelector} from 'react-redux';
import {getInvoices} from 'mattermost-redux/actions/cloud';
@ -24,6 +24,14 @@ import BillingHistoryTable from './billing_history_table';
import './billing_history.scss';
const messages = defineMessages({
title: {id: 'admin.billing.history.title', defaultMessage: 'Billing History'},
});
export const searchableStrings = [
messages.title,
];
interface NoBillingHistorySectionProps {
selfHosted: boolean;
}
@ -73,8 +81,7 @@ const BillingHistory = () => {
<div className='wrapper--fixed BillingHistory'>
<AdminHeader>
<FormattedMessage
id='admin.billing.history.title'
defaultMessage='Billing History'
{...messages.title}
/>
</AdminHeader>
<div className='admin-console__wrapper'>

View File

@ -2,7 +2,7 @@
// See LICENSE.txt for license information.
import React, {useEffect, useState} from 'react';
import {FormattedMessage} from 'react-intl';
import {FormattedMessage, defineMessages} from 'react-intl';
import {useDispatch, useSelector} from 'react-redux';
import type {GlobalState} from '@mattermost/types/store';
@ -49,6 +49,14 @@ import PlanDetails from '../plan_details';
import './billing_subscriptions.scss';
const messages = defineMessages({
title: {id: 'admin.billing.subscription.title', defaultMessage: 'Subscription'},
});
export const searchableStrings = [
messages.title,
];
const BillingSubscriptions = () => {
const dispatch = useDispatch<DispatchFunc>();
const subscription = useSelector(selectCloudSubscription);
@ -121,10 +129,7 @@ const BillingSubscriptions = () => {
return (
<div className='wrapper--fixed BillingSubscriptions'>
<AdminHeader>
<FormattedMessage
id='admin.billing.subscription.title'
defaultMessage='Subscription'
/>
<FormattedMessage {...messages.title}/>
</AdminHeader>
<div className='admin-console__wrapper'>
<div className='admin-console__content'>

View File

@ -2,7 +2,7 @@
// See LICENSE.txt for license information.
import React, {useEffect} from 'react';
import {FormattedMessage} from 'react-intl';
import {FormattedMessage, defineMessages} from 'react-intl';
import {useDispatch, useSelector} from 'react-redux';
import {getCloudCustomer} from 'mattermost-redux/actions/cloud';
@ -18,6 +18,14 @@ import CompanyInfoDisplay from './company_info_display';
type Props = Record<string, never>;
const messages = defineMessages({
title: {id: 'admin.billing.company_info.title', defaultMessage: 'Company Information'},
});
export const searchableStrings = [
messages.title,
];
const CompanyInfo: React.FC<Props> = () => {
const dispatch = useDispatch<DispatchFunc>();
const {customer: customerError} = useSelector(getCloudErrors);
@ -31,10 +39,7 @@ const CompanyInfo: React.FC<Props> = () => {
return (
<div className='wrapper--fixed CompanyInfo'>
<AdminHeader>
<FormattedMessage
id='admin.billing.company_info.title'
defaultMessage='Company Information'
/>
<FormattedMessage {...messages.title}/>
</AdminHeader>
<div className='admin-console__wrapper'>
<div className='admin-console__content'>

View File

@ -2,7 +2,7 @@
// See LICENSE.txt for license information.
import React from 'react';
import {FormattedMessage} from 'react-intl';
import {FormattedMessage, defineMessages} from 'react-intl';
import {useDispatch, useSelector} from 'react-redux';
import {getCloudSubscription, getSubscriptionProduct} from 'mattermost-redux/selectors/entities/cloud';
@ -16,6 +16,9 @@ import {isCloudLicense} from 'utils/license_utils';
import DeleteWorkspaceModal from './delete_workspace_modal';
export const messages = defineMessages({
title: {id: 'admin.billing.subscription.deleteWorkspaceSection.title', defaultMessage: 'Delete your workspace'},
});
export default function DeleteWorkspaceCTA() {
const dispatch = useDispatch();
@ -61,10 +64,7 @@ export default function DeleteWorkspaceCTA() {
<div className='cancelSubscriptionSection'>
<div className='cancelSubscriptionSection__text'>
<div className='cancelSubscriptionSection__text-title'>
<FormattedMessage
id='admin.billing.subscription.deleteWorkspaceSection.title'
defaultMessage='Delete your workspace'
/>
<FormattedMessage {...messages.title}/>
</div>
<div className='cancelSubscriptionSection__text-description'>
<FormattedMessage

View File

@ -2,7 +2,7 @@
// See LICENSE.txt for license information.
import React from 'react';
import {FormattedMessage} from 'react-intl';
import {FormattedMessage, defineMessages} from 'react-intl';
import {useDispatch, useSelector} from 'react-redux';
import {GenericModal} from '@mattermost/components';
@ -40,6 +40,10 @@ type Props = {
callerCTA: string;
}
export const messages = defineMessages({
deleteButton: {id: 'admin.billing.subscription.deleteWorkspaceModal.deleteButton', defaultMessage: 'Delete Workspace'},
});
export default function DeleteWorkspaceModal(props: Props) {
const dispatch = useDispatch<DispatchFunc>();
const openDowngradeModal = useOpenDowngradeModal();
@ -226,10 +230,7 @@ export default function DeleteWorkspaceModal(props: Props) {
className='btn DeleteWorkspaceModal__Buttons-Delete'
onClick={handleClickDeleteWorkspace}
>
<FormattedMessage
id='admin.billing.subscription.deleteWorkspaceModal.deleteButton'
defaultMessage='Delete Workspace'
/>
<FormattedMessage {...messages.deleteButton}/>
</button>
{!isStarter && !isEnterprise &&
<button

View File

@ -2,7 +2,7 @@
// See LICENSE.txt for license information.
import React, {useEffect, useState} from 'react';
import {FormattedMessage} from 'react-intl';
import {FormattedMessage, defineMessages} from 'react-intl';
import {useDispatch, useSelector} from 'react-redux';
import type {GlobalState} from '@mattermost/types/store';
@ -23,6 +23,14 @@ import './payment_info.scss';
type Props = Record<string, never>;
const messages = defineMessages({
title: {id: 'admin.billing.payment_info.title', defaultMessage: 'Payment Information'},
});
export const searchableStrings = [
messages.title,
];
const PaymentInfo: React.FC<Props> = () => {
const dispatch = useDispatch<DispatchFunc>();
const {customer: customerError} = useSelector(getCloudErrors);
@ -59,10 +67,7 @@ const PaymentInfo: React.FC<Props> = () => {
return (
<div className='wrapper--fixed PaymentInfo'>
<AdminHeader>
<FormattedMessage
id='admin.billing.payment_info.title'
defaultMessage='Payment Information'
/>
<FormattedMessage {...messages.title}/>
</AdminHeader>
<div className='admin-console__wrapper'>
<div className='admin-console__content'>

View File

@ -2,7 +2,7 @@
// See LICENSE.txt for license information.
import React from 'react';
import {FormattedMessage} from 'react-intl';
import {FormattedMessage, defineMessage, defineMessages} from 'react-intl';
import type {AdminConfig} from '@mattermost/types/config';
import type {Job} from '@mattermost/types/jobs';
@ -12,7 +12,6 @@ import {blevePurgeIndexes} from 'actions/admin_actions.jsx';
import ExternalLink from 'components/external_link';
import {JobStatuses, JobTypes} from 'utils/constants';
import {t} from 'utils/i18n';
import AdminSettings from './admin_settings';
import type {BaseProps, BaseState} from './admin_settings';
@ -35,6 +34,32 @@ type State = BaseState & {
canPurgeAndIndex: boolean;
};
const messages = defineMessages({
title: {id: 'admin.bleve.title', defaultMessage: 'Bleve'},
enableIndexingTitle: {id: 'admin.bleve.enableIndexingTitle', defaultMessage: 'Enable Bleve Indexing:'},
enableIndexingDescription: {id: 'admin.bleve.enableIndexingDescription', defaultMessage: 'When true, indexing of new posts occurs automatically. Search queries will use database search until "Enable Bleve for search queries" is enabled. <link>Learn more about Bleve in our documentation.</link>'},
bulkIndexingTitle: {id: 'admin.bleve.bulkIndexingTitle', defaultMessage: 'Bulk Indexing:'},
createJob_help: {id: 'admin.bleve.createJob.help', defaultMessage: 'All users, channels and posts in the database will be indexed from oldest to newest. Bleve is available during indexing but search results may be incomplete until the indexing job is complete.'},
purgeIndexesHelpText: {id: 'admin.bleve.purgeIndexesHelpText', defaultMessage: 'Purging will entirely remove the content of the Bleve index directory. Search results may be incomplete until a bulk index of the existing database is rebuilt.'},
purgeIndexesButton: {id: 'admin.bleve.purgeIndexesButton', defaultMessage: 'Purge Index'},
purgeIndexesButton_label: {id: 'admin.bleve.purgeIndexesButton.label', defaultMessage: 'Purge Indexes:'},
enableSearchingTitle: {id: 'admin.bleve.enableSearchingTitle', defaultMessage: 'Enable Bleve for search queries:'},
enableSearchingDescription: {id: 'admin.bleve.enableSearchingDescription', defaultMessage: 'When true, Bleve 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.'},
});
export const searchableStrings = [
messages.title,
messages.enableIndexingTitle,
messages.enableIndexingDescription,
messages.bulkIndexingTitle,
messages.createJob_help,
messages.purgeIndexesHelpText,
messages.purgeIndexesButton,
messages.purgeIndexesButton_label,
messages.enableSearchingTitle,
messages.enableSearchingDescription,
];
export default class BleveSettings extends AdminSettings<Props, State> {
getConfigFromState = (config: Props['config']) => {
if (config && config.BleveSettings) {
@ -101,12 +126,7 @@ export default class BleveSettings extends AdminSettings<Props, State> {
}
renderTitle() {
return (
<FormattedMessage
id='admin.bleve.title'
defaultMessage='Bleve'
/>
);
return (<FormattedMessage {...messages.title}/>);
}
renderSettings = () => {
@ -114,26 +134,17 @@ export default class BleveSettings extends AdminSettings<Props, State> {
<SettingsGroup>
<BooleanSetting
id='enableIndexing'
label={
<FormattedMessage
id='admin.bleve.enableIndexingTitle'
defaultMessage='Enable Bleve Indexing:'
/>
}
label={<FormattedMessage {...messages.enableIndexingTitle}/>}
helpText={
<FormattedMessage
id='admin.bleve.enableIndexingDescription'
defaultMessage='When true, indexing of new posts occurs automatically. Search queries will use database search until "Enable Bleve for search queries" is enabled. {documentationLink}'
{...messages.enableIndexingDescription}
values={{
documentationLink: (
link: (chunks) => (
<ExternalLink
href='https://docs.mattermost.com/deploy/bleve-search.html'
location='bleve_settings'
>
<FormattedMessage
id='admin.bleve.enableIndexingDescription.documentationLinkText'
defaultMessage='Learn more about Bleve in our documentation.'
/>
{chunks}
</ExternalLink>
),
}}
@ -164,13 +175,8 @@ export default class BleveSettings extends AdminSettings<Props, State> {
disabled={this.props.isDisabled}
/>
<div className='form-group'>
<label
className='control-label col-sm-4'
>
<FormattedMessage
id='admin.bleve.bulkIndexingTitle'
defaultMessage='Bulk Indexing:'
/>
<label className='control-label col-sm-4'>
<FormattedMessage {...messages.bulkIndexingTitle}/>
</label>
<div className='col-sm-8'>
<div className='job-table-setting'>
@ -183,12 +189,7 @@ export default class BleveSettings extends AdminSettings<Props, State> {
defaultMessage='Index Now'
/>
}
createJobHelpText={
<FormattedMessage
id='admin.bleve.createJob.help'
defaultMessage='All users, channels and posts in the database will be indexed from oldest to newest. Bleve is available during indexing but search results may be incomplete until the indexing job is complete.'
/>
}
createJobHelpText={<FormattedMessage {...messages.createJob_help}/>}
getExtraInfoText={this.getExtraInfo}
/>
</div>
@ -197,48 +198,23 @@ export default class BleveSettings extends AdminSettings<Props, State> {
<RequestButton
id='purgeIndexesSection'
requestAction={blevePurgeIndexes}
helpText={
<FormattedMessage
id='admin.bleve.purgeIndexesHelpText'
defaultMessage='Purging will entirely remove the content of the Bleve index directory. Search results may be incomplete until a bulk index of the existing database is rebuilt.'
/>
}
buttonText={
<FormattedMessage
id='admin.bleve.purgeIndexesButton'
defaultMessage='Purge Index'
/>
}
successMessage={{
id: t('admin.bleve.purgeIndexesButton.success'),
helpText={<FormattedMessage {...messages.purgeIndexesHelpText}/>}
buttonText={<FormattedMessage {...messages.purgeIndexesButton}/>}
successMessage={defineMessage({
id: 'admin.bleve.purgeIndexesButton.success',
defaultMessage: 'Indexes purged successfully.',
}}
errorMessage={{
id: t('admin.bleve.purgeIndexesButton.error'),
})}
errorMessage={defineMessage({
id: 'admin.bleve.purgeIndexesButton.error',
defaultMessage: 'Failed to purge indexes: {error}',
}}
})}
disabled={!this.state.canPurgeAndIndex || this.props.isDisabled}
label={(
<FormattedMessage
id='admin.bleve.purgeIndexesButton.label'
defaultMessage='Purge Indexes:'
/>
)}
label={<FormattedMessage {...messages.purgeIndexesButton_label}/>}
/>
<BooleanSetting
id='enableSearching'
label={
<FormattedMessage
id='admin.bleve.enableSearchingTitle'
defaultMessage='Enable Bleve for search queries:'
/>
}
helpText={
<FormattedMessage
id='admin.bleve.enableSearchingDescription'
defaultMessage='When true, Bleve 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.'
/>
}
label={<FormattedMessage {...messages.enableSearchingTitle}/>}
helpText={<FormattedMessage {...messages.enableSearchingDescription}/>}
value={this.state.enableSearching}
disabled={!this.state.enableIndexing || this.props.isDisabled}
onChange={this.handleSettingChanged}

View File

@ -12,7 +12,7 @@ type Props = {
id: string;
label: React.ReactNode;
value: boolean;
onChange: (id: string, foo: boolean) => void;
onChange: (id: string, value: boolean) => void;
trueText?: React.ReactNode;
falseText?: React.ReactNode;
disabled: boolean;

View File

@ -4,7 +4,7 @@
import {shallow} from 'enzyme';
import React from 'react';
import ClusterSettings from 'components/admin_console/cluster_settings.jsx';
import ClusterSettings from 'components/admin_console/cluster_settings';
describe('components/ClusterSettings', () => {
const baseProps = {

View File

@ -2,24 +2,84 @@
// See LICENSE.txt for license information.
import React from 'react';
import {FormattedMessage} from 'react-intl';
import {FormattedMessage, defineMessage, defineMessages} from 'react-intl';
import type {AdminConfig, ClientLicense} from '@mattermost/types/config';
import {Client4} from 'mattermost-redux/client';
import ExternalLink from 'components/external_link';
import WarningIcon from 'components/widgets/icons/fa_warning_icon';
import DocLinks from 'utils/constants';
import * as Utils from 'utils/utils';
import {DocLinks} from 'utils/constants';
import type {BaseProps, BaseState} from './admin_settings';
import AdminSettings from './admin_settings';
import BooleanSetting from './boolean_setting';
import ClusterTableContainer from './cluster_table_container';
import SettingsGroup from './settings_group';
import TextSetting from './text_setting';
export default class ClusterSettings extends AdminSettings {
getConfigFromState = (config) => {
type Props = {
license: ClientLicense;
} & BaseProps;
type State = {
Enable: boolean;
ClusterName: string;
OverrideHostname: string;
UseIPAddress: boolean;
EnableExperimentalGossipEncryption: boolean;
EnableGossipCompression: boolean;
GossipPort: number;
StreamingPort: number;
showWarning: boolean;
} & BaseState;
const messages = defineMessages({
cluster: {id: 'admin.advance.cluster', defaultMessage: 'High Availability'},
noteDescription: {id: 'admin.cluster.noteDescription', defaultMessage: 'Changing properties in this section will require a server restart before taking effect.'},
enableTitle: {id: 'admin.cluster.enableTitle', defaultMessage: 'Enable High Availability Mode:'},
enableDescription: {id: 'admin.cluster.enableDescription', defaultMessage: 'When true, Mattermost will run in High Availability mode. Please see <link>documentation</link> to learn more about configuring High Availability for Mattermost.'},
clusterName: {id: 'admin.cluster.ClusterName', defaultMessage: 'Cluster Name:'},
clusterNameDesc: {id: 'admin.cluster.ClusterNameDesc', defaultMessage: 'The cluster to join by name. Only nodes with the same cluster name will join together. This is to support Blue-Green deployments or staging pointing to the same database.'},
overrideHostname: {id: 'admin.cluster.OverrideHostname', defaultMessage: 'Override Hostname:'},
overrideHostnameDesc: {id: 'admin.cluster.OverrideHostnameDesc', defaultMessage: "The default value of '<blank>' will attempt to get the Hostname from the OS or use the IP Address. You can override the hostname of this server with this property. It is not recommended to override the Hostname unless needed. This property can also be set to a specific IP Address if needed."},
useIPAddress: {id: 'admin.cluster.UseIPAddress', defaultMessage: 'Use IP Address:'},
useIPAddressDesc: {id: 'admin.cluster.UseIPAddressDesc', defaultMessage: 'When true, the cluster will attempt to communicate via IP Address vs using the hostname.'},
enableExperimentalGossipEncryption: {id: 'admin.cluster.EnableExperimentalGossipEncryption', defaultMessage: 'Enable Experimental Gossip encryption:'},
enableExperimentalGossipEncryptionDesc: {id: 'admin.cluster.EnableExperimentalGossipEncryptionDesc', defaultMessage: 'When true, all communication through the gossip protocol will be encrypted.'},
enableGossipCompression: {id: 'admin.cluster.EnableGossipCompression', defaultMessage: 'Enable Gossip compression:'},
enableGossipCompressionDesc: {id: 'admin.cluster.EnableGossipCompressionDesc', defaultMessage: 'When true, all communication through the gossip protocol will be compressed. It is recommended to keep this flag disabled.'},
gossipPort: {id: 'admin.cluster.GossipPort', defaultMessage: 'Gossip Port:'},
gossipPortDesc: {id: 'admin.cluster.GossipPortDesc', defaultMessage: 'The port used for the gossip protocol. Both UDP and TCP should be allowed on this port.'},
streamingPort: {id: 'admin.cluster.StreamingPort', defaultMessage: 'Streaming Port:'},
streamingPortDesc: {id: 'admin.cluster.StreamingPortDesc', defaultMessage: 'The port used for streaming data between servers.'},
});
export const searchableStrings = [
messages.cluster,
messages.noteDescription,
messages.enableTitle,
messages.enableDescription,
messages.clusterName,
messages.clusterNameDesc,
messages.overrideHostname,
messages.overrideHostnameDesc,
messages.useIPAddress,
messages.useIPAddressDesc,
messages.enableExperimentalGossipEncryption,
messages.enableExperimentalGossipEncryptionDesc,
messages.enableGossipCompression,
messages.enableGossipCompressionDesc,
messages.gossipPort,
messages.gossipPortDesc,
messages.streamingPort,
messages.streamingPortDesc,
];
export default class ClusterSettings extends AdminSettings<Props, State> {
getConfigFromState = (config: AdminConfig) => {
config.ClusterSettings.Enable = this.state.Enable;
config.ClusterSettings.ClusterName = this.state.ClusterName;
config.ClusterSettings.OverrideHostname = this.state.OverrideHostname;
@ -31,7 +91,7 @@ export default class ClusterSettings extends AdminSettings {
return config;
};
getStateFromConfig(config) {
getStateFromConfig(config: AdminConfig) {
const settings = config.ClusterSettings;
return {
@ -48,15 +108,10 @@ export default class ClusterSettings extends AdminSettings {
}
renderTitle() {
return (
<FormattedMessage
id='admin.advance.cluster'
defaultMessage='High Availability'
/>
);
return (<FormattedMessage {...messages.cluster}/>);
}
overrideHandleChange = (id, value) => {
overrideHandleChange = (id: string, value: unknown) => {
this.setState({
showWarning: true,
});
@ -67,10 +122,10 @@ export default class ClusterSettings extends AdminSettings {
renderSettings = () => {
const licenseEnabled = this.props.license.IsLicensed === 'true' && this.props.license.Cluster === 'true';
if (!licenseEnabled) {
return null;
return (<></>);
}
var configLoadedFromCluster = null;
let configLoadedFromCluster = null;
if (Client4.clusterId) {
configLoadedFromCluster = (
@ -98,7 +153,7 @@ export default class ClusterSettings extends AdminSettings {
);
}
var warning = null;
let warning = null;
if (this.state.showWarning) {
warning = (
@ -125,7 +180,7 @@ export default class ClusterSettings extends AdminSettings {
);
}
var clusterTableContainer = null;
let clusterTableContainer: React.ReactNode = null;
if (this.state.Enable) {
clusterTableContainer = (<ClusterTableContainer/>);
}
@ -135,24 +190,17 @@ export default class ClusterSettings extends AdminSettings {
{configLoadedFromCluster}
{clusterTableContainer}
<div className='banner'>
<FormattedMessage
id='admin.cluster.noteDescription'
defaultMessage='Changing properties in this section will require a server restart before taking effect.'
/>
<FormattedMessage {...messages.noteDescription}/>
</div>
{warning}
<BooleanSetting
id='Enable'
label={
<FormattedMessage
id='admin.cluster.enableTitle'
defaultMessage='Enable High Availability Mode:'
/>
<FormattedMessage {...messages.enableTitle}/>
}
helpText={
<FormattedMessage
id='admin.cluster.enableDescription'
defaultMessage='When true, Mattermost will run in High Availability mode. Please see <link>documentation</link> to learn more about configuring High Availability for Mattermost.'
{...messages.enableDescription}
values={{
link: (msg) => (
<ExternalLink
@ -172,19 +220,9 @@ export default class ClusterSettings extends AdminSettings {
/>
<TextSetting
id='ClusterName'
label={
<FormattedMessage
id='admin.cluster.ClusterName'
defaultMessage='Cluster Name:'
/>
}
placeholder={Utils.localizeMessage('admin.cluster.ClusterNameEx', 'E.g.: "Production" or "Staging"')}
helpText={
<FormattedMessage
id='admin.cluster.ClusterNameDesc'
defaultMessage='The cluster to join by name. Only nodes with the same cluster name will join together. This is to support Blue-Green deployments or staging pointing to the same database.'
/>
}
label={<FormattedMessage {...messages.clusterName}/>}
placeholder={defineMessage({id: 'admin.cluster.ClusterNameEx', defaultMessage: 'E.g.: "Production" or "Staging"'})}
helpText={<FormattedMessage {...messages.clusterNameDesc}/>}
value={this.state.ClusterName}
onChange={this.overrideHandleChange}
setByEnv={this.isSetByEnv('ClusterSettings.ClusterName')}
@ -192,19 +230,9 @@ export default class ClusterSettings extends AdminSettings {
/>
<TextSetting
id='OverrideHostname'
label={
<FormattedMessage
id='admin.cluster.OverrideHostname'
defaultMessage='Override Hostname:'
/>
}
placeholder={Utils.localizeMessage('admin.cluster.OverrideHostnameEx', 'E.g.: "app-server-01"')}
helpText={
<FormattedMessage
id='admin.cluster.OverrideHostnameDesc'
defaultMessage="The default value of '<blank>' will attempt to get the Hostname from the OS or use the IP Address. You can override the hostname of this server with this property. It is not recommended to override the Hostname unless needed. This property can also be set to a specific IP Address if needed."
/>
}
label={<FormattedMessage {...messages.overrideHostname}/>}
placeholder={defineMessage({id: 'admin.cluster.OverrideHostnameEx', defaultMessage: 'E.g.: "app-server-01"'})}
helpText={<FormattedMessage {...messages.overrideHostnameDesc}/>}
value={this.state.OverrideHostname}
onChange={this.overrideHandleChange}
setByEnv={this.isSetByEnv('ClusterSettings.OverrideHostname')}
@ -212,18 +240,8 @@ export default class ClusterSettings extends AdminSettings {
/>
<BooleanSetting
id='UseIPAddress'
label={
<FormattedMessage
id='admin.cluster.UseIPAddress'
defaultMessage='Use IP Address:'
/>
}
helpText={
<FormattedMessage
id='admin.cluster.UseIPAddressDesc'
defaultMessage='When true, the cluster will attempt to communicate via IP Address vs using the hostname.'
/>
}
label={<FormattedMessage {...messages.useIPAddress}/>}
helpText={<FormattedMessage {...messages.useIPAddressDesc}/>}
value={this.state.UseIPAddress}
onChange={this.overrideHandleChange}
setByEnv={this.isSetByEnv('ClusterSettings.UseIPAddress')}
@ -231,18 +249,8 @@ export default class ClusterSettings extends AdminSettings {
/>
<BooleanSetting
id='EnableExperimentalGossipEncryption'
label={
<FormattedMessage
id='admin.cluster.EnableExperimentalGossipEncryption'
defaultMessage='Enable Experimental Gossip encryption:'
/>
}
helpText={
<FormattedMessage
id='admin.cluster.EnableExperimentalGossipEncryptionDesc'
defaultMessage='When true, all communication through the gossip protocol will be encrypted.'
/>
}
label={<FormattedMessage {...messages.enableExperimentalGossipEncryption}/>}
helpText={<FormattedMessage {...messages.enableExperimentalGossipEncryptionDesc}/>}
value={this.state.EnableExperimentalGossipEncryption}
onChange={this.overrideHandleChange}
setByEnv={this.isSetByEnv('ClusterSettings.EnableExperimentalGossipEncryption')}
@ -250,18 +258,8 @@ export default class ClusterSettings extends AdminSettings {
/>
<BooleanSetting
id='EnableGossipCompression'
label={
<FormattedMessage
id='admin.cluster.EnableGossipCompression'
defaultMessage='Enable Gossip compression:'
/>
}
helpText={
<FormattedMessage
id='admin.cluster.EnableGossipCompressionDesc'
defaultMessage='When true, all communication through the gossip protocol will be compressed. It is recommended to keep this flag disabled.'
/>
}
label={<FormattedMessage {...messages.enableGossipCompression}/>}
helpText={<FormattedMessage {...messages.enableGossipCompressionDesc}/>}
value={this.state.EnableGossipCompression}
onChange={this.overrideHandleChange}
setByEnv={this.isSetByEnv('ClusterSettings.EnableGossipCompression')}
@ -269,19 +267,9 @@ export default class ClusterSettings extends AdminSettings {
/>
<TextSetting
id='GossipPort'
label={
<FormattedMessage
id='admin.cluster.GossipPort'
defaultMessage='Gossip Port:'
/>
}
placeholder={Utils.localizeMessage('admin.cluster.GossipPortEx', 'E.g.: "8074"')}
helpText={
<FormattedMessage
id='admin.cluster.GossipPortDesc'
defaultMessage='The port used for the gossip protocol. Both UDP and TCP should be allowed on this port.'
/>
}
label={<FormattedMessage {...messages.gossipPort}/>}
placeholder={defineMessage({id: 'admin.cluster.GossipPortEx', defaultMessage: 'E.g.: "8074"'})}
helpText={<FormattedMessage {...messages.gossipPortDesc}/>}
value={this.state.GossipPort}
onChange={this.overrideHandleChange}
setByEnv={this.isSetByEnv('ClusterSettings.GossipPort')}
@ -289,19 +277,9 @@ export default class ClusterSettings extends AdminSettings {
/>
<TextSetting
id='StreamingPort'
label={
<FormattedMessage
id='admin.cluster.StreamingPort'
defaultMessage='Streaming Port:'
/>
}
placeholder={Utils.localizeMessage('admin.cluster.StreamingPortEx', 'E.g.: "8075"')}
helpText={
<FormattedMessage
id='admin.cluster.StreamingPortDesc'
defaultMessage='The port used for streaming data between servers.'
/>
}
label={<FormattedMessage {...messages.streamingPort}/>}
placeholder={defineMessage({id: 'admin.cluster.StreamingPortEx', defaultMessage: 'E.g.: "8075"'})}
helpText={<FormattedMessage {...messages.streamingPortDesc}/>}
value={this.state.StreamingPort}
onChange={this.overrideHandleChange}
setByEnv={this.isSetByEnv('ClusterSettings.StreamingPort')}

View File

@ -1,7 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {PureComponent} from 'react';
import React, {useCallback, useEffect, useRef, useState} from 'react';
import type {MouseEvent} from 'react';
import type {ClusterInfo} from '@mattermost/types/admin';
@ -12,69 +12,44 @@ import ClusterTable from './cluster_table';
import LoadingScreen from '../loading_screen';
interface State {
clusterInfos: ClusterInfo[] | null;
}
const ClusterTableContainer = () => {
const interval = useRef<NodeJS.Timeout>();
const [clusterInfos, setClusterInfos] = useState<ClusterInfo[] | null>(null);
export default class ClusterTableContainer extends PureComponent<null, State> {
interval: NodeJS.Timeout | null;
const load = useCallback(() => {
getClusterStatus(setClusterInfos, null);
}, []);
constructor(props: null) {
super(props);
this.interval = null;
this.state = {
clusterInfos: null,
useEffect(() => {
load();
interval.current = setInterval(load, 15000);
return () => {
if (interval.current) {
clearInterval(interval.current);
}
};
}
}, []);
load = () => {
getClusterStatus(
(data: ClusterInfo[]) => {
this.setState({
clusterInfos: data,
});
},
null,
);
};
componentDidMount() {
this.load();
// reload the cluster status every 15 seconds
this.interval = setInterval(this.load, 15000);
}
componentWillUnmount() {
if (this.interval) {
clearInterval(this.interval);
}
}
reload = (e: MouseEvent<HTMLButtonElement>) => {
const reload = useCallback((e: MouseEvent<HTMLButtonElement>) => {
if (e) {
e.preventDefault();
}
this.setState({
clusterInfos: null,
});
setClusterInfos(null);
this.load();
};
load();
}, [load]);
render() {
if (this.state.clusterInfos == null) {
return (<LoadingScreen/>);
}
return (
<ClusterTable
clusterInfos={this.state.clusterInfos}
reload={this.reload}
/>
);
if (clusterInfos == null) {
return (<LoadingScreen/>);
}
}
return (
<ClusterTable
clusterInfos={clusterInfos}
reload={reload}
/>
);
};
export default React.memo(ClusterTableContainer);

View File

@ -4,9 +4,7 @@ exports[`components/admin_console/CustomPluginSettings should match snapshot wit
<div
className="wrapper--fixed "
>
<AdminHeader>
testplugin
</AdminHeader>
testplugin
<div
className="admin-console__wrapper"
>
@ -26,7 +24,6 @@ exports[`components/admin_console/CustomPluginSettings should match snapshot wit
>
<SchemaText
isMarkdown={true}
isTranslated={false}
text="# Header
*This* is the **header**"
/>
@ -36,7 +33,6 @@ exports[`components/admin_console/CustomPluginSettings should match snapshot wit
footer={null}
helpText={
<SchemaText
isTranslated={true}
text="This is some help text for the text field."
/>
}
@ -59,7 +55,6 @@ exports[`components/admin_console/CustomPluginSettings should match snapshot wit
}
helpText={
<SchemaText
isTranslated={true}
text="This is some help text for the bool field."
/>
}
@ -80,7 +75,6 @@ exports[`components/admin_console/CustomPluginSettings should match snapshot wit
disabled={false}
helpText={
<SchemaText
isTranslated={true}
text="This is some help text for the dropdown field."
/>
}
@ -111,7 +105,6 @@ exports[`components/admin_console/CustomPluginSettings should match snapshot wit
disabled={false}
helpText={
<SchemaText
isTranslated={true}
text="This is some help text for the radio field."
/>
}
@ -142,7 +135,6 @@ exports[`components/admin_console/CustomPluginSettings should match snapshot wit
disabled={false}
helpText={
<SchemaText
isTranslated={true}
text="This is some help text for the generated field."
/>
}
@ -165,7 +157,6 @@ exports[`components/admin_console/CustomPluginSettings should match snapshot wit
disabled={false}
helpText={
<SchemaText
isTranslated={true}
text="This is some help text for the user autocomplete field."
/>
}
@ -181,7 +172,6 @@ exports[`components/admin_console/CustomPluginSettings should match snapshot wit
>
<SchemaText
isMarkdown={true}
isTranslated={false}
text="# Footer
*This* is the **footer**"
/>
@ -226,7 +216,6 @@ exports[`components/admin_console/CustomPluginSettings should match snapshot wit
</div>
<Overlay
animation={[Function]}
delayShow={400}
placement="top"
rootClose={false}
show={false}
@ -244,9 +233,7 @@ exports[`components/admin_console/CustomPluginSettings should match snapshot wit
<div
className="wrapper--fixed "
>
<AdminHeader>
testplugin
</AdminHeader>
testplugin
<div
className="admin-console__wrapper"
>
@ -296,7 +283,6 @@ exports[`components/admin_console/CustomPluginSettings should match snapshot wit
</div>
<Overlay
animation={[Function]}
delayShow={400}
placement="top"
rootClose={false}
show={false}
@ -314,9 +300,7 @@ exports[`components/admin_console/CustomPluginSettings should match snapshot wit
<div
className="wrapper--fixed "
>
<AdminHeader>
testplugin
</AdminHeader>
testplugin
<div
className="admin-console__wrapper"
>
@ -336,7 +320,6 @@ exports[`components/admin_console/CustomPluginSettings should match snapshot wit
>
<SchemaText
isMarkdown={true}
isTranslated={false}
text="# Header
*This* is the **header**"
/>
@ -346,7 +329,6 @@ exports[`components/admin_console/CustomPluginSettings should match snapshot wit
footer={null}
helpText={
<SchemaText
isTranslated={true}
text="This is some help text for the text field."
/>
}
@ -369,7 +351,6 @@ exports[`components/admin_console/CustomPluginSettings should match snapshot wit
}
helpText={
<SchemaText
isTranslated={true}
text="This is some help text for the bool field."
/>
}
@ -384,13 +365,12 @@ exports[`components/admin_console/CustomPluginSettings should match snapshot wit
id="admin.true"
/>
}
value={false}
value={true}
/>
<Memo(DropdownSetting)
disabled={false}
helpText={
<SchemaText
isTranslated={true}
text="This is some help text for the dropdown field."
/>
}
@ -421,7 +401,6 @@ exports[`components/admin_console/CustomPluginSettings should match snapshot wit
disabled={false}
helpText={
<SchemaText
isTranslated={true}
text="This is some help text for the radio field."
/>
}
@ -452,7 +431,6 @@ exports[`components/admin_console/CustomPluginSettings should match snapshot wit
disabled={false}
helpText={
<SchemaText
isTranslated={true}
text="This is some help text for the generated field."
/>
}
@ -475,7 +453,6 @@ exports[`components/admin_console/CustomPluginSettings should match snapshot wit
disabled={false}
helpText={
<SchemaText
isTranslated={true}
text="This is some help text for the user autocomplete field."
/>
}
@ -491,7 +468,6 @@ exports[`components/admin_console/CustomPluginSettings should match snapshot wit
>
<SchemaText
isMarkdown={true}
isTranslated={false}
text="# Footer
*This* is the **footer**"
/>
@ -536,7 +512,6 @@ exports[`components/admin_console/CustomPluginSettings should match snapshot wit
</div>
<Overlay
animation={[Function]}
delayShow={400}
placement="top"
rootClose={false}
show={false}

View File

@ -1,19 +1,35 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {shallow} from 'enzyme';
import React from 'react';
import type {CloudState} from '@mattermost/types/cloud';
import type {PluginSettings} from '@mattermost/types/config';
import type {PluginRedux} from '@mattermost/types/plugins';
import CustomPluginSettings from 'components/admin_console/custom_plugin_settings/custom_plugin_settings';
import SchemaAdminSettings from 'components/admin_console/schema_admin_settings';
import {escapePathPart} from 'components/admin_console/schema_admin_settings';
import {shallowWithIntl} from 'tests/helpers/intl-test-helper';
import type {AdminDefinitionSetting} from '../types';
describe('components/admin_console/CustomPluginSettings', () => {
let plugin: PluginRedux = {} as PluginRedux;
let config: {PluginSettings: Partial<PluginSettings>} = {PluginSettings: {}};
let plugin: PluginRedux;
let config: {PluginSettings: PluginSettings};
const baseProps = {
isDisabled: false,
environmentConfig: {},
setNavigationBlocked: jest.fn(),
roles: {},
cloud: {} as CloudState,
license: {},
editRole: jest.fn(),
consoleAccess: {read: {}, write: {}},
isCurrentUserSystemAdmin: false,
enterpriseReady: false,
};
beforeEach(() => {
plugin = {
id: 'testplugin',
@ -103,23 +119,24 @@ describe('components/admin_console/CustomPluginSettings', () => {
settingf: '3xz3r6n7dtbbmgref3yw4zg7sr',
},
},
},
} as unknown as PluginSettings,
};
});
test('should match snapshot with settings and plugin', () => {
const settings = plugin && plugin.settings_schema && plugin.settings_schema.settings && plugin.settings_schema.settings.map((setting) => {
const escapedPluginId = SchemaAdminSettings.escapePathPart(plugin.id);
const settings = plugin.settings_schema!.settings.map((setting) => {
const escapedPluginId = escapePathPart(plugin.id);
return {
...setting,
key: 'PluginSettings.Plugins.' + escapedPluginId + '.' + setting.key.toLowerCase(),
label: setting.display_name,
};
} as AdminDefinitionSetting;
});
const wrapper = shallow(
const wrapper = shallowWithIntl(
<CustomPluginSettings
{...baseProps}
config={config}
schema={{...plugin.settings_schema, id: plugin.id, name: plugin.name, translate: false, settings}}
schema={{...plugin.settings_schema, id: plugin.id, name: plugin.name, settings}}
updateConfig={jest.fn()}
/>,
);
@ -127,13 +144,13 @@ describe('components/admin_console/CustomPluginSettings', () => {
});
test('should match snapshot with settings and no plugin', () => {
const wrapper = shallow(
const wrapper = shallowWithIntl(
<CustomPluginSettings
{...baseProps}
config={config}
schema={{
id: 'testplugin',
name: 'testplugin',
translate: false,
}}
updateConfig={jest.fn()}
/>,
@ -143,16 +160,17 @@ describe('components/admin_console/CustomPluginSettings', () => {
test('should match snapshot with no settings and plugin', () => {
const settings = plugin && plugin.settings_schema && plugin.settings_schema.settings && plugin.settings_schema.settings.map((setting) => {
return {...setting, label: setting.display_name};
return {...setting, label: setting.display_name} as AdminDefinitionSetting;
});
const wrapper = shallow(
const wrapper = shallowWithIntl(
<CustomPluginSettings
{...baseProps}
config={{
PluginSettings: {
Plugins: {},
},
} as PluginSettings,
}}
schema={{...plugin.settings_schema, id: plugin.id, name: plugin.name, translate: false, settings}}
schema={{...plugin.settings_schema, id: plugin.id, name: plugin.name, settings}}
updateConfig={jest.fn()}
/>,
);

View File

@ -1,7 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import SchemaAdminSettings from 'components/admin_console/schema_admin_settings.jsx';
import SchemaAdminSettings from 'components/admin_console/schema_admin_settings';
// No changes required to the base SchemaAdminSettings, except to inject custom props.
const CustomPluginSettings = SchemaAdminSettings;

View File

@ -1,23 +1,21 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {defineMessage} from 'react-intl';
import type {PluginRedux, PluginSetting} from '@mattermost/types/plugins';
import {t} from 'utils/i18n';
import SchemaAdminSettings from '../schema_admin_settings';
import {escapePathPart} from '../schema_admin_settings';
import type {AdminDefinitionSetting} from '../types';
export default function getEnablePluginSetting(plugin: PluginRedux): Partial<AdminDefinitionSetting & PluginSetting> {
const escapedPluginId = SchemaAdminSettings.escapePathPart(plugin.id);
const escapedPluginId = escapePathPart(plugin.id);
const pluginEnabledConfigKey = 'PluginSettings.PluginStates.' + escapedPluginId + '.Enable';
return {
type: 'bool',
key: pluginEnabledConfigKey,
label: t('admin.plugin.enable_plugin'),
label_default: 'Enable Plugin: ',
help_text: t('admin.plugin.enable_plugin.help'),
help_text_default: 'When true, this plugin is enabled.',
label: defineMessage({id: 'admin.plugin.enable_plugin', defaultMessage: 'Enable Plugin: '}),
help_text: defineMessage({id: 'admin.plugin.enable_plugin.help', defaultMessage: 'When true, this plugin is enabled.'}),
};
}

View File

@ -1,9 +1,11 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import type {MessageDescriptor} from 'react-intl';
import {defineMessage} from 'react-intl';
import {connect} from 'react-redux';
import type {PluginRedux, PluginSetting} from '@mattermost/types/plugins';
import type {PluginRedux} from '@mattermost/types/plugins';
import type {GlobalState} from '@mattermost/types/store';
import {createSelector} from 'mattermost-redux/selectors/create_selector';
@ -15,7 +17,6 @@ import {getAdminConsoleCustomComponents} from 'selectors/admin_console';
import {appsPluginID} from 'utils/apps';
import {Constants} from 'utils/constants';
import {localizeMessage} from 'utils/utils';
import type {AdminConsolePluginComponent} from 'types/store/plugins';
@ -23,8 +24,8 @@ import CustomPluginSettings from './custom_plugin_settings';
import getEnablePluginSetting from './enable_plugin_setting';
import {it} from '../admin_definition';
import SchemaAdminSettings from '../schema_admin_settings';
import type {AdminDefinitionSetting} from '../types';
import {escapePathPart} from '../schema_admin_settings';
import type {AdminDefinitionSetting, AdminDefinitionSubSectionSchema} from '../types';
type OwnProps = { match: { params: { plugin_id: string } } }
@ -40,17 +41,17 @@ function makeGetPluginSchema() {
return null;
}
const escapedPluginId = SchemaAdminSettings.escapePathPart(plugin.id);
const escapedPluginId = escapePathPart(plugin.id);
const pluginEnabledConfigKey = 'PluginSettings.PluginStates.' + escapedPluginId + '.Enable';
let settings: Array<Partial<AdminDefinitionSetting & PluginSetting>> = [];
let settings: Array<Partial<AdminDefinitionSetting>> = [];
if (plugin.settings_schema && plugin.settings_schema.settings) {
settings = plugin.settings_schema.settings.map((setting) => {
const key = setting.key.toLowerCase();
let component = null;
let bannerType = '';
let type = setting.type;
let displayName = setting.display_name;
let displayName: string | MessageDescriptor = setting.display_name;
let isDisabled = it.any(it.stateIsFalse(pluginEnabledConfigKey), it.not(it.userHasWritePermissionOnResource('plugins')));
if (customComponents[key]) {
@ -59,7 +60,7 @@ function makeGetPluginSchema() {
} else if (setting.type === Constants.SettingsTypes.TYPE_CUSTOM) {
// Show a warning banner to enable the plugin in order to display the custom component.
type = Constants.SettingsTypes.TYPE_BANNER;
displayName = localizeMessage('admin.plugin.customSetting.pluginDisabledWarning', 'In order to view this setting, enable the plugin and click Save.');
displayName = defineMessage({id: 'admin.plugin.customSetting.pluginDisabledWarning', defaultMessage: 'In order to view this setting, enable the plugin and click Save.'});
bannerType = 'warning';
isDisabled = it.any(it.stateIsTrue(pluginEnabledConfigKey), it.not(it.userHasWritePermissionOnResource('plugins')));
}
@ -82,7 +83,7 @@ function makeGetPluginSchema() {
component,
showTitle: customComponents[key] ? customComponents[key].options.showTitle : false,
};
}) as Array<Partial<AdminDefinitionSetting & PluginSetting>>;
}) as Array<Partial<AdminDefinitionSetting>>;
}
if (plugin.id !== appsPluginID || appsFeatureFlagIsEnabled) {
@ -109,7 +110,7 @@ function makeGetPluginSchema() {
name: plugin.name,
settings,
translate: Boolean(plugin.translate),
};
} as AdminDefinitionSubSectionSchema;
},
);
}

View File

@ -2,7 +2,7 @@
// See LICENSE.txt for license information.
import React from 'react';
import {FormattedMessage} from 'react-intl';
import {FormattedMessage, defineMessages} from 'react-intl';
import type {AdminConfig, ClientLicense} from '@mattermost/types/config';
import type {TermsOfService} from '@mattermost/types/terms_of_service';
@ -46,6 +46,26 @@ type State = BaseState & {
errorTooltip: boolean;
}
export const messages = defineMessages({
termsOfServiceTitle: {id: 'admin.support.termsOfServiceTitle', defaultMessage: 'Custom Terms of Service'},
enableTermsOfServiceTitle: {id: 'admin.support.enableTermsOfServiceTitle', defaultMessage: 'Enable Custom Terms of Service'},
termsOfServiceTextTitle: {id: 'admin.support.termsOfServiceTextTitle', defaultMessage: 'Custom Terms of Service Text'},
termsOfServiceTextHelp: {id: 'admin.support.termsOfServiceTextHelp', defaultMessage: 'Text that will appear in your custom Terms of Service. Supports Markdown-formatted text.'},
termsOfServiceReAcceptanceTitle: {id: 'admin.support.termsOfServiceReAcceptanceTitle', defaultMessage: 'Re-Acceptance Period:'},
termsOfServiceReAcceptanceHelp: {id: 'admin.support.termsOfServiceReAcceptanceHelp', defaultMessage: 'The number of days before Terms of Service acceptance expires, and the terms must be re-accepted.'},
enableTermsOfServiceHelp: {id: 'admin.support.enableTermsOfServiceHelp', defaultMessage: 'When true, new users must accept the terms of service before accessing any Mattermost teams on desktop, web or mobile. Existing users must accept them after login or a page refresh. To update terms of service link displayed in account creation and login pages, go to [Site Configuration > Customization](../site_config/customization).'},
});
export const searchableStrings = [
messages.termsOfServiceTitle,
messages.enableTermsOfServiceTitle,
messages.enableTermsOfServiceHelp,
messages.termsOfServiceTextTitle,
messages.termsOfServiceTextHelp,
messages.termsOfServiceReAcceptanceTitle,
messages.termsOfServiceReAcceptanceHelp,
];
export default class CustomTermsOfServiceSettings extends AdminSettings<Props, State> {
constructor(props: Props) {
super(props);
@ -167,12 +187,7 @@ export default class CustomTermsOfServiceSettings extends AdminSettings<Props, S
};
renderTitle() {
return (
<FormattedMessage
id='admin.support.termsOfServiceTitle'
defaultMessage='Custom Terms of Service'
/>
);
return (<FormattedMessage {...messages.termsOfServiceTitle}/>);
}
renderSettings = () => {
@ -185,18 +200,8 @@ export default class CustomTermsOfServiceSettings extends AdminSettings<Props, S
<BooleanSetting
key={'customTermsOfServiceEnabled'}
id={'SupportSettings.CustomTermsOfServiceEnabled'}
label={
<FormattedMessage
id='admin.support.enableTermsOfServiceTitle'
defaultMessage='Enable Custom Terms of Service'
/>
}
helpText={
<FormattedMarkdownMessage
id='admin.support.enableTermsOfServiceHelp'
defaultMessage='When true, new users must accept the terms of service before accessing any Mattermost teams on desktop, web or mobile. Existing users must accept them after login or a page refresh.\n \nTo update terms of service link displayed in account creation and login pages, go to [Site Configuration > Customization](../site_config/customization).'
/>
}
label={<FormattedMessage {...messages.enableTermsOfServiceTitle}/>}
helpText={<FormattedMarkdownMessage {...messages.enableTermsOfServiceHelp}/>}
value={Boolean(this.state.termsEnabled)}
onChange={this.handleTermsEnabledChange}
setByEnv={this.isSetByEnv('SupportSettings.CustomTermsOfServiceEnabled')}
@ -206,18 +211,8 @@ export default class CustomTermsOfServiceSettings extends AdminSettings<Props, S
key={'customTermsOfServiceText'}
id={'SupportSettings.CustomTermsOfServiceText'}
type={'textarea'}
label={
<FormattedMessage
id='admin.support.termsOfServiceTextTitle'
defaultMessage='Custom Terms of Service Text'
/>
}
helpText={
<FormattedMessage
id='admin.support.termsOfServiceTextHelp'
defaultMessage='Text that will appear in your custom Terms of Service. Supports Markdown-formatted text.'
/>
}
label={<FormattedMessage {...messages.termsOfServiceTextTitle}/>}
helpText={<FormattedMessage {...messages.termsOfServiceTextHelp}/>}
onChange={this.handleTermsTextChange}
setByEnv={this.isSetByEnv('SupportSettings.CustomTermsOfServiceText')}
value={this.state.termsText}
@ -228,18 +223,8 @@ export default class CustomTermsOfServiceSettings extends AdminSettings<Props, S
key={'customTermsOfServiceReAcceptancePeriod'}
id={'SupportSettings.CustomTermsOfServiceReAcceptancePeriod'}
type={'number'}
label={
<FormattedMessage
id='admin.support.termsOfServiceReAcceptanceTitle'
defaultMessage='Re-Acceptance Period:'
/>
}
helpText={
<FormattedMessage
id='admin.support.termsOfServiceReAcceptanceHelp'
defaultMessage='The number of days before Terms of Service acceptance expires, and the terms must be re-accepted.'
/>
}
label={<FormattedMessage {...messages.termsOfServiceReAcceptanceTitle}/>}
helpText={<FormattedMessage {...messages.termsOfServiceReAcceptanceHelp}/>}
value={this.state.reAcceptancePeriod || ''}
onChange={this.handleReAcceptancePeriodChange}
setByEnv={this.isSetByEnv('SupportSettings.CustomTermsOfServiceReAcceptancePeriod')}

View File

@ -1,9 +1,10 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {shallow} from 'enzyme';
import React from 'react';
import {shallowWithIntl} from 'tests/helpers/intl-test-helper';
import DataRetentionSettings from './data_retention_settings';
describe('components/admin_console/data_retention_settings/data_retention_settings', () => {
@ -33,7 +34,7 @@ describe('components/admin_console/data_retention_settings/data_retention_settin
};
test('should match snapshot with no custom policies', () => {
const wrapper = shallow(
const wrapper = shallowWithIntl(
<DataRetentionSettings
{...baseProps}
/>,
@ -53,7 +54,7 @@ describe('components/admin_console/data_retention_settings/data_retention_settin
},
};
props.customPoliciesCount = 1;
const wrapper = shallow(
const wrapper = shallowWithIntl(
<DataRetentionSettings
{...props}
/>,
@ -73,7 +74,7 @@ describe('components/admin_console/data_retention_settings/data_retention_settin
},
};
props.customPoliciesCount = 1;
const wrapper = shallow(
const wrapper = shallowWithIntl(
<DataRetentionSettings
{...props}
/>,
@ -85,7 +86,7 @@ describe('components/admin_console/data_retention_settings/data_retention_settin
const props = baseProps;
props.config.DataRetentionSettings.EnableMessageDeletion = false;
props.config.DataRetentionSettings.EnableFileDeletion = false;
const wrapper = shallow(
const wrapper = shallowWithIntl(
<DataRetentionSettings
{...props}
/>,

View File

@ -3,7 +3,8 @@
import React, {createRef} from 'react';
import type {RefObject} from 'react';
import {FormattedMessage} from 'react-intl';
import type {WrappedComponentProps} from 'react-intl';
import {FormattedMessage, defineMessages, injectIntl} from 'react-intl';
import ReactSelect from 'react-select';
import type {AdminConfig} from '@mattermost/types/config';
@ -24,7 +25,6 @@ import MenuWrapper from 'components/widgets/menu/menu_wrapper';
import {getHistory} from 'utils/browser_history';
import {JobTypes} from 'utils/constants';
import * as Utils from 'utils/utils';
import './data_retention_settings.scss';
@ -46,7 +46,7 @@ type Props = {
deleteDataRetentionCustomPolicy: (id: string) => Promise<ActionResult>;
updateConfig: (config: Record<string, any>) => Promise<ActionResult>;
};
};
} & WrappedComponentProps;
type State = {
customPoliciesLoading: boolean;
@ -56,7 +56,31 @@ type State = {
}
const PAGE_SIZE = 10;
export default class DataRetentionSettings extends React.PureComponent<Props, State> {
const messages = defineMessages({
createJob_title: {id: 'admin.data_retention.createJob.title', defaultMessage: 'Run Deletion Job Now'},
settings_title: {id: 'admin.data_retention.settings.title', defaultMessage: 'Data Retention Policies'},
globalPolicy_title: {id: 'admin.data_retention.globalPolicy.title', defaultMessage: 'Global retention policy'},
globalPolicy_subTitle: {id: 'admin.data_retention.globalPolicy.subTitle', defaultMessage: 'Keep messages and files for a set amount of time.'},
customPolicies_title: {id: 'admin.data_retention.customPolicies.title', defaultMessage: 'Custom retention policies'},
customPolicies_subTitle: {id: 'admin.data_retention.customPolicies.subTitle', defaultMessage: 'Customize how long specific teams and channels will keep messages.'},
jobCreation_title: {id: 'admin.data_retention.jobCreation.title', defaultMessage: 'Policy log'},
jobCreation_subTitle: {id: 'admin.data_retention.jobCreation.subTitle', defaultMessage: 'Daily log of messages and files removed based on the policies defined above.'},
createJob_instructions: {id: 'admin.data_retention.createJob.instructions', defaultMessage: 'Daily time to check policies and run delete job:'},
});
export const searchableStrings = [
messages.createJob_title,
messages.settings_title,
messages.globalPolicy_title,
messages.globalPolicy_subTitle,
messages.customPolicies_title,
messages.customPolicies_subTitle,
messages.jobCreation_title,
messages.jobCreation_subTitle,
messages.createJob_instructions,
];
class DataRetentionSettings extends React.PureComponent<Props, State> {
inputRef: RefObject<ReactSelect<OptionType>>;
constructor(props: Props) {
super(props);
@ -230,7 +254,7 @@ export default class DataRetentionSettings extends React.PureComponent<Props, St
const {DataRetentionSettings} = this.props.config;
return [{
cells: {
description: Utils.localizeMessage('admin.data_retention.form.text', 'Applies to all teams and channels, but does not apply to custom retention policies.'),
description: this.props.intl.formatMessage({id: 'admin.data_retention.form.text', defaultMessage: 'Applies to all teams and channels, but does not apply to custom retention policies.'}),
channel_messages: (
<div data-testid='global_message_retention_cell'>
{this.getGlobalRetentionSetting(DataRetentionSettings?.EnableMessageDeletion, this.props.globalMessageRetentionHours)}
@ -254,14 +278,14 @@ export default class DataRetentionSettings extends React.PureComponent<Props, St
<Menu
openLeft={false}
openUp={false}
ariaLabel={Utils.localizeMessage('admin.user_item.menuAriaLabel', 'User Actions Menu')}
ariaLabel={this.props.intl.formatMessage({id: 'admin.user_item.menuAriaLabel', defaultMessage: 'User Actions Menu'})}
>
<Menu.ItemAction
show={true}
onClick={() => {
getHistory().push('/admin_console/compliance/data_retention_settings/global_policy');
}}
text={Utils.localizeMessage('admin.data_retention.globalPoliciesTable.edit', 'Edit')}
text={this.props.intl.formatMessage({id: 'admin.data_retention.globalPoliciesTable.edit', defaultMessage: 'Edit'})}
disabled={false}
buttonClass={'edit_global_policy'}
/>
@ -334,14 +358,14 @@ export default class DataRetentionSettings extends React.PureComponent<Props, St
<Menu
openLeft={false}
openUp={false}
ariaLabel={Utils.localizeMessage('admin.user_item.menuAriaLabel', 'User Actions Menu')}
ariaLabel={this.props.intl.formatMessage({id: 'admin.user_item.menuAriaLabel', defaultMessage: 'User Actions Menu'})}
>
<Menu.ItemAction
show={true}
onClick={() => {
getHistory().push(`/admin_console/compliance/data_retention_settings/custom_policy/${policy.id}`);
}}
text={Utils.localizeMessage('admin.data_retention.globalPoliciesTable.edit', 'Edit')}
text={this.props.intl.formatMessage({id: 'admin.data_retention.globalPoliciesTable.edit', defaultMessage: 'Edit'})}
disabled={false}
/>
<Menu.ItemAction
@ -349,7 +373,7 @@ export default class DataRetentionSettings extends React.PureComponent<Props, St
onClick={() => {
this.deleteCustomPolicy(policy.id);
}}
text={Utils.localizeMessage('admin.data_retention.globalPoliciesTable.delete', 'Delete')}
text={this.props.intl.formatMessage({id: 'admin.data_retention.globalPoliciesTable.delete', defaultMessage: 'Delete'})}
disabled={false}
/>
</Menu>
@ -488,10 +512,7 @@ export default class DataRetentionSettings extends React.PureComponent<Props, St
return (
<div className='wrapper--fixed DataRetentionSettings'>
<AdminHeader>
<FormattedMessage
id='admin.data_retention.settings.title'
defaultMessage='Data Retention Policies'
/>
<FormattedMessage {...messages.settings_title}/>
</AdminHeader>
<div className='admin-console__wrapper'>
<div className='admin-console__content'>
@ -501,18 +522,8 @@ export default class DataRetentionSettings extends React.PureComponent<Props, St
>
<Card.Header>
<TitleAndButtonCardHeader
title={
<FormattedMessage
id='admin.data_retention.globalPolicy.title'
defaultMessage='Global retention policy'
/>
}
subtitle={
<FormattedMessage
id='admin.data_retention.globalPolicy.subTitle'
defaultMessage='Keep messages and files for a set amount of time.'
/>
}
title={<FormattedMessage {...messages.globalPolicy_title}/>}
subtitle={<FormattedMessage {...messages.globalPolicy_subTitle}/>}
/>
</Card.Header>
<Card.Body
@ -540,18 +551,8 @@ export default class DataRetentionSettings extends React.PureComponent<Props, St
>
<Card.Header>
<TitleAndButtonCardHeader
title={
<FormattedMessage
id='admin.data_retention.customPolicies.title'
defaultMessage='Custom retention policies'
/>
}
subtitle={
<FormattedMessage
id='admin.data_retention.customPolicies.subTitle'
defaultMessage='Customize how long specific teams and channels will keep messages.'
/>
}
title={<FormattedMessage {...messages.customPolicies_title}/>}
subtitle={<FormattedMessage {...messages.customPolicies_subTitle}/>}
buttonText={
<FormattedMessage
id='admin.data_retention.customPolicies.addPolicy'
@ -588,24 +589,9 @@ export default class DataRetentionSettings extends React.PureComponent<Props, St
>
<Card.Header>
<TitleAndButtonCardHeader
title={
<FormattedMessage
id='admin.data_retention.jobCreation.title'
defaultMessage='Policy log'
/>
}
subtitle={
<FormattedMessage
id='admin.data_retention.jobCreation.subTitle'
defaultMessage='Daily log of messages and files removed based on the policies defined above.'
/>
}
buttonText={
<FormattedMessage
id='admin.data_retention.createJob.title'
defaultMessage='Run Deletion Job Now'
/>
}
title={<FormattedMessage {...messages.jobCreation_title}/>}
subtitle={<FormattedMessage {...messages.jobCreation_subTitle}/>}
buttonText={<FormattedMessage {...messages.createJob_title}/>}
isDisabled={String(DataRetentionSettings?.EnableMessageDeletion) !== 'true' && String(DataRetentionSettings?.EnableFileDeletion) !== 'true' && (this.props.customPoliciesCount === 0)}
onClick={this.handleCreateJob}
/>
@ -618,18 +604,10 @@ export default class DataRetentionSettings extends React.PureComponent<Props, St
hideJobCreateButton={true}
className={'job-table__data-retention'}
disabled={String(DataRetentionSettings?.EnableMessageDeletion) !== 'true' && String(DataRetentionSettings?.EnableFileDeletion) !== 'true'}
createJobButtonText={
<FormattedMessage
id='admin.data_retention.createJob.title'
defaultMessage='Run Deletion Job Now'
/>
}
createJobButtonText={<FormattedMessage {...messages.createJob_title}/>}
createJobHelpText={
<div>
<FormattedMessage
id='admin.data_retention.createJob.instructions'
defaultMessage='Daily time to check policies and run delete job:'
/>
<FormattedMessage {...messages.createJob_instructions}/>
{this.state.showEditJobTime ? (
<ReactSelect
id={'JobSelectTime'}
@ -676,7 +654,7 @@ export default class DataRetentionSettings extends React.PureComponent<Props, St
className='EditJobTime'
onClick={() => this.showEditJobTime(true)}
>
{Utils.localizeMessage('admin.data_retention.globalPoliciesTable.edit', 'Edit')}
{this.props.intl.formatMessage({id: 'admin.data_retention.globalPoliciesTable.edit', defaultMessage: 'Edit'})}
</a>
</div>
}
@ -689,3 +667,5 @@ export default class DataRetentionSettings extends React.PureComponent<Props, St
);
};
}
export default injectIntl(DataRetentionSettings);

View File

@ -2,7 +2,8 @@
// See LICENSE.txt for license information.
import React from 'react';
import {FormattedMessage} from 'react-intl';
import type {MessageDescriptor} from 'react-intl';
import {FormattedMessage, defineMessage, defineMessages} from 'react-intl';
import type {AdminConfig} from '@mattermost/types/config';
@ -11,8 +12,6 @@ import {recycleDatabaseConnection, ping} from 'actions/admin_actions';
import ExternalLink from 'components/external_link';
import {DocLinks} from 'utils/constants';
import {t} from 'utils/i18n';
import * as Utils from 'utils/utils';
import type {BaseState} from './admin_settings';
import AdminSettings from './admin_settings';
@ -22,12 +21,12 @@ import RequestButton from './request_button/request_button';
import SettingsGroup from './settings_group';
import TextSetting from './text_setting';
interface Props {
type Props = {
license: {
IsLicensed: string;
};
isDisabled: boolean;
}
};
interface State extends BaseState {
searchBackend: string;
@ -43,6 +42,62 @@ interface State extends BaseState {
driverName: string;
}
const messages = defineMessages({
title: {id: 'admin.database.title', defaultMessage: 'Database Settings'},
recycleDescription: {id: 'admin.recycle.recycleDescription', defaultMessage: 'Deployments using multiple databases can switch from one master database to another without restarting the Mattermost server by updating "config.json" to the new desired configuration and using the {reloadConfiguration} feature to load the new settings while the server is running. The administrator should then use {featureName} feature to recycle the database connections based on the new settings.'},
featureName: {id: 'admin.recycle.recycleDescription.featureName', defaultMessage: 'Recycle Database Connections'},
reloadConfiguration: {id: 'admin.recycle.recycleDescription.reloadConfiguration', defaultMessage: 'Environment > Web Server > Reload Configuration from Disk'},
button: {id: 'admin.recycle.button', defaultMessage: 'Recycle Database Connections'},
noteDescription: {id: 'admin.sql.noteDescription', defaultMessage: 'Changing properties in this section will require a server restart before taking effect.'},
disableDatabaseSearchTitle: {id: 'admin.sql.disableDatabaseSearchTitle', defaultMessage: 'Disable database search: '},
disableDatabaseSearchDescription: {id: 'admin.sql.disableDatabaseSearchDescription', defaultMessage: 'Disables the use of the database to perform searches. Should only be used when other <link>search engines</link> are configured.'},
driverName: {id: 'admin.sql.driverName', defaultMessage: 'Driver Name:'},
driverNameDescription: {id: 'admin.sql.driverNameDescription', defaultMessage: 'Set the database driver in the config.json file.'},
dataSource: {id: 'admin.sql.dataSource', defaultMessage: 'Data Source:'},
dataSourceDescription: {id: 'admin.sql.dataSourceDescription', defaultMessage: 'Set the database source in the config.json file.'},
maxConnectionsTitle: {id: 'admin.sql.maxConnectionsTitle', defaultMessage: 'Maximum Idle Connections:'},
maxConnectionsDescription: {id: 'admin.sql.maxConnectionsDescription', defaultMessage: 'Maximum number of idle connections held open to the database.'},
maxOpenTitle: {id: 'admin.sql.maxOpenTitle', defaultMessage: 'Maximum Open Connections:'},
maxOpenDescription: {id: 'admin.sql.maxOpenDescription', defaultMessage: 'Maximum number of open connections held open to the database.'},
queryTimeoutTitle: {id: 'admin.sql.queryTimeoutTitle', defaultMessage: 'Query Timeout:'},
queryTimeoutDescription: {id: 'admin.sql.queryTimeoutDescription', defaultMessage: 'The number of seconds to wait for a response from the database after opening a connection and sending the query. Errors that you see in the UI or in the logs as a result of a query timeout can vary depending on the type of query.'},
connMaxLifetimeTitle: {id: 'admin.sql.connMaxLifetimeTitle', defaultMessage: 'Maximum Connection Lifetime:'},
connMaxLifetimeDescription: {id: 'admin.sql.connMaxLifetimeDescription', defaultMessage: 'Maximum lifetime for a connection to the database in milliseconds.'},
connMaxIdleTimeTitle: {id: 'admin.sql.connMaxIdleTimeTitle', defaultMessage: 'Maximum Connection Idle Time:'},
connMaxIdleTimeDescription: {id: 'admin.sql.connMaxIdleTimeDescription', defaultMessage: 'Maximum idle time for a connection to the database in milliseconds.'},
minimumHashtagLengthTitle: {id: 'admin.service.minimumHashtagLengthTitle', defaultMessage: 'Minimum Hashtag Length:'},
minimumHashtagLengthDescription: {id: 'admin.service.minimumHashtagLengthDescription', defaultMessage: 'Minimum number of characters in a hashtag. This must be greater than or equal to 2. MySQL databases must be configured to support searching strings shorter than three characters, <link>see documentation</link>.'},
traceTitle: {id: 'admin.sql.traceTitle', defaultMessage: 'SQL Statement Logging: '},
traceDescription: {id: 'admin.sql.traceDescription', defaultMessage: '(Development Mode) When true, executing SQL statements are written to the log.'},
});
export const searchableStrings: Array<string|MessageDescriptor|[MessageDescriptor, {[key: string]: any}]> = [
messages.title,
[messages.recycleDescription, {featureName: '', reloadConfiguration: ''}],
messages.featureName,
messages.reloadConfiguration,
messages.button,
messages.noteDescription,
messages.disableDatabaseSearchTitle,
messages.disableDatabaseSearchDescription,
messages.driverName,
messages.driverNameDescription,
messages.dataSource,
messages.dataSourceDescription,
messages.maxConnectionsTitle,
messages.maxConnectionsDescription,
messages.maxOpenTitle,
messages.maxOpenDescription,
messages.queryTimeoutTitle,
messages.queryTimeoutDescription,
messages.connMaxLifetimeTitle,
messages.connMaxLifetimeDescription,
messages.connMaxIdleTimeTitle,
messages.connMaxIdleTimeDescription,
messages.traceTitle,
messages.traceDescription,
];
export default class DatabaseSettings extends AdminSettings<Props, State> {
constructor(props: Props) {
super(props);
@ -95,12 +150,7 @@ export default class DatabaseSettings extends AdminSettings<Props, State> {
}
renderTitle() {
return (
<FormattedMessage
id='admin.database.title'
defaultMessage='Database Settings'
/>
);
return (<FormattedMessage {...messages.title}/>);
}
renderSettings = () => {
@ -113,24 +163,17 @@ export default class DatabaseSettings extends AdminSettings<Props, State> {
requestAction={recycleDatabaseConnection}
helpText={
<FormattedMessage
id='admin.recycle.recycleDescription'
defaultMessage='Deployments using multiple databases can switch from one master database to another without restarting the Mattermost server by updating "config.json" to the new desired configuration and using the {reloadConfiguration} feature to load the new settings while the server is running. The administrator should then use {featureName} feature to recycle the database connections based on the new settings.'
{...messages.recycleDescription}
values={{
featureName: (
<b>
<FormattedMessage
id='admin.recycle.recycleDescription.featureName'
defaultMessage='Recycle Database Connections'
/>
<FormattedMessage {...messages.featureName}/>
</b>
),
reloadConfiguration: (
<a href='../environment/web_server'>
<b>
<FormattedMessage
id='admin.recycle.recycleDescription.reloadConfiguration'
defaultMessage='Environment > Web Server > Reload Configuration from Disk'
/>
<FormattedMessage {...messages.reloadConfiguration}/>
</b>
</a>
),
@ -138,16 +181,13 @@ export default class DatabaseSettings extends AdminSettings<Props, State> {
/>
}
buttonText={
<FormattedMessage
id='admin.recycle.button'
defaultMessage='Recycle Database Connections'
/>
<FormattedMessage {...messages.button}/>
}
showSuccessMessage={false}
errorMessage={{
id: t('admin.recycle.reloadFail'),
errorMessage={defineMessage({
id: 'admin.recycle.reloadFail',
defaultMessage: 'Recycling unsuccessful: {error}',
}}
})}
includeDetailedError={true}
disabled={this.props.isDisabled}
/>
@ -157,20 +197,14 @@ export default class DatabaseSettings extends AdminSettings<Props, State> {
return (
<SettingsGroup>
<div className='banner'>
<FormattedMessage
id='admin.sql.noteDescription'
defaultMessage='Changing properties in this section will require a server restart before taking effect.'
/>
<FormattedMessage {...messages.noteDescription}/>
</div>
<div className='form-group'>
<label
className='control-label col-sm-4'
htmlFor='DriverName'
>
<FormattedMessage
id='admin.sql.driverName'
defaultMessage='Driver Name:'
/>
<FormattedMessage {...messages.driverName}/>
</label>
<div className='col-sm-8'>
<input
@ -180,10 +214,7 @@ export default class DatabaseSettings extends AdminSettings<Props, State> {
disabled={true}
/>
<div className='help-text'>
<FormattedMessage
id='admin.sql.driverNameDescription'
defaultMessage='Set the database driver in the config.json file.'
/>
<FormattedMessage {...messages.driverNameDescription}/>
</div>
</div>
</div>
@ -192,10 +223,7 @@ export default class DatabaseSettings extends AdminSettings<Props, State> {
className='control-label col-sm-4'
htmlFor='DataSource'
>
<FormattedMessage
id='admin.sql.dataSource'
defaultMessage='Data Source:'
/>
<FormattedMessage {...messages.dataSource}/>
</label>
<div className='col-sm-8'>
<input
@ -205,27 +233,18 @@ export default class DatabaseSettings extends AdminSettings<Props, State> {
disabled={true}
/>
<div className='help-text'>
<FormattedMessage
id='admin.sql.dataSourceDescription'
defaultMessage='Set the database source in the config.json file.'
/>
<FormattedMessage {...messages.dataSourceDescription}/>
</div>
</div>
</div>
<TextSetting
id='maxIdleConns'
label={
<FormattedMessage
id='admin.sql.maxConnectionsTitle'
defaultMessage='Maximum Idle Connections:'
/>
<FormattedMessage {...messages.maxConnectionsTitle}/>
}
placeholder={Utils.localizeMessage('admin.sql.maxConnectionsExample', 'E.g.: "10"')}
placeholder={defineMessage({id: 'admin.sql.maxConnectionsExample', defaultMessage: 'E.g.: "10"'})}
helpText={
<FormattedMessage
id='admin.sql.maxConnectionsDescription'
defaultMessage='Maximum number of idle connections held open to the database.'
/>
<FormattedMessage {...messages.maxConnectionsDescription}/>
}
value={this.state.maxIdleConns}
onChange={this.handleChange}
@ -236,17 +255,11 @@ export default class DatabaseSettings extends AdminSettings<Props, State> {
<TextSetting
id='maxOpenConns'
label={
<FormattedMessage
id='admin.sql.maxOpenTitle'
defaultMessage='Maximum Open Connections:'
/>
<FormattedMessage {...messages.maxOpenTitle}/>
}
placeholder={Utils.localizeMessage('admin.sql.maxOpenExample', 'E.g.: "10"')}
placeholder={defineMessage({id: 'admin.sql.maxOpenExample', defaultMessage: 'E.g.: "10"'})}
helpText={
<FormattedMessage
id='admin.sql.maxOpenDescription'
defaultMessage='Maximum number of open connections held open to the database.'
/>
<FormattedMessage {...messages.maxOpenDescription}/>
}
value={this.state.maxOpenConns}
onChange={this.handleChange}
@ -257,17 +270,11 @@ export default class DatabaseSettings extends AdminSettings<Props, State> {
<TextSetting
id='queryTimeout'
label={
<FormattedMessage
id='admin.sql.queryTimeoutTitle'
defaultMessage='Query Timeout:'
/>
<FormattedMessage {...messages.queryTimeoutTitle}/>
}
placeholder={Utils.localizeMessage('admin.sql.queryTimeoutExample', 'E.g.: "30"')}
placeholder={defineMessage({id: 'admin.sql.queryTimeoutExample', defaultMessage: 'E.g.: "30"'})}
helpText={
<FormattedMessage
id='admin.sql.queryTimeoutDescription'
defaultMessage='The number of seconds to wait for a response from the database after opening a connection and sending the query. Errors that you see in the UI or in the logs as a result of a query timeout can vary depending on the type of query.'
/>
<FormattedMessage {...messages.queryTimeoutDescription}/>
}
value={this.state.queryTimeout}
onChange={this.handleChange}
@ -278,17 +285,11 @@ export default class DatabaseSettings extends AdminSettings<Props, State> {
<TextSetting
id='connMaxLifetimeMilliseconds'
label={
<FormattedMessage
id='admin.sql.connMaxLifetimeTitle'
defaultMessage='Maximum Connection Lifetime:'
/>
<FormattedMessage {...messages.connMaxLifetimeTitle}/>
}
placeholder={Utils.localizeMessage('admin.sql.connMaxLifetimeExample', 'E.g.: "3600000"')}
placeholder={defineMessage({id: 'admin.sql.connMaxLifetimeExample', defaultMessage: 'E.g.: "3600000"'})}
helpText={
<FormattedMessage
id='admin.sql.connMaxLifetimeDescription'
defaultMessage='Maximum lifetime for a connection to the database in milliseconds.'
/>
<FormattedMessage {...messages.connMaxLifetimeDescription}/>
}
value={this.state.connMaxLifetimeMilliseconds}
onChange={this.handleChange}
@ -299,17 +300,11 @@ export default class DatabaseSettings extends AdminSettings<Props, State> {
<TextSetting
id='connMaxIdleTimeMilliseconds'
label={
<FormattedMessage
id='admin.sql.connMaxIdleTimeTitle'
defaultMessage='Maximum Connection Idle Time:'
/>
<FormattedMessage {...messages.connMaxIdleTimeTitle}/>
}
placeholder={Utils.localizeMessage('admin.sql.connMaxIdleTimeExample', 'E.g.: "300000"')}
placeholder={defineMessage({id: 'admin.sql.connMaxIdleTimeExample', defaultMessage: 'E.g.: "300000"'})}
helpText={
<FormattedMessage
id='admin.sql.connMaxIdleTimeDescription'
defaultMessage='Maximum idle time for a connection to the database in milliseconds.'
/>
<FormattedMessage {...messages.connMaxIdleTimeDescription}/>
}
value={this.state.connMaxIdleTimeMilliseconds}
onChange={this.handleChange}
@ -320,16 +315,12 @@ export default class DatabaseSettings extends AdminSettings<Props, State> {
<TextSetting
id='minimumHashtagLength'
label={
<FormattedMessage
id='admin.service.minimumHashtagLengthTitle'
defaultMessage='Minimum Hashtag Length:'
/>
<FormattedMessage {...messages.minimumHashtagLengthTitle}/>
}
placeholder={Utils.localizeMessage('admin.service.minimumHashtagLengthExample', 'E.g.: "3"')}
placeholder={defineMessage({id: 'admin.service.minimumHashtagLengthExample', defaultMessage: 'E.g.: "3"'})}
helpText={
<FormattedMessage
id='admin.service.minimumHashtagLengthDescription'
defaultMessage='Minimum number of characters in a hashtag. This must be greater than or equal to 2. MySQL databases must be configured to support searching strings shorter than three characters, <link>see documentation</link>.'
{...messages.minimumHashtagLengthDescription}
values={{
link: (msg) => (
<ExternalLink
@ -351,16 +342,10 @@ export default class DatabaseSettings extends AdminSettings<Props, State> {
<BooleanSetting
id='trace'
label={
<FormattedMessage
id='admin.sql.traceTitle'
defaultMessage='SQL Statement Logging: '
/>
<FormattedMessage {...messages.traceTitle}/>
}
helpText={
<FormattedMessage
id='admin.sql.traceDescription'
defaultMessage='(Development Mode) When true, executing SQL statements are written to the log.'
/>
<FormattedMessage {...messages.traceDescription}/>
}
value={this.state.trace}
onChange={this.handleChange}
@ -371,15 +356,11 @@ export default class DatabaseSettings extends AdminSettings<Props, State> {
<BooleanSetting
id='disableDatabaseSearch'
label={
<FormattedMessage
id='admin.sql.disableDatabaseSearchTitle'
defaultMessage='Disable database search: '
/>
<FormattedMessage {...messages.disableDatabaseSearchTitle}/>
}
helpText={
<FormattedMessage
id='admin.sql.disableDatabaseSearchDescription'
defaultMessage='Disables the use of the database to perform searches. Should only be used when other <link>search engines</link> are configured.'
{...messages.disableDatabaseSearchDescription}
values={{
link: (msg) => (
<ExternalLink

View File

@ -78,15 +78,15 @@ describe('components/ElasticSearchSettings', () => {
EnableAutocomplete: false,
},
};
const wrapper = shallow<ElasticSearchSettings>(
const wrapper = shallow(
<ElasticSearchSettings
config={config as AdminConfig}
/>,
);
const instance = wrapper.instance() as any;
expect(wrapper.find(SaveButton).prop('disabled')).toBe(true);
wrapper.instance().handleSettingChanged('enableIndexing', true);
instance.handleSettingChanged('enableIndexing', true);
expect(wrapper.find(SaveButton).prop('disabled')).toBe(true);
const instance = wrapper.instance();
const success = jest.fn();
const error = jest.fn();
instance.doTestConfig(success, error);

View File

@ -2,7 +2,8 @@
// See LICENSE.txt for license information.
import React from 'react';
import {FormattedMessage} from 'react-intl';
import type {MessageDescriptor} from 'react-intl';
import {FormattedMessage, defineMessage, defineMessages} from 'react-intl';
import type {AdminConfig} from '@mattermost/types/config';
import type {Job, JobType} from '@mattermost/types/jobs';
@ -12,8 +13,6 @@ import {elasticsearchPurgeIndexes, elasticsearchTest} from 'actions/admin_action
import ExternalLink from 'components/external_link';
import {DocLinks, JobStatuses, JobTypes} from 'utils/constants';
import {t} from 'utils/i18n';
import * as Utils from 'utils/utils';
import AdminSettings from './admin_settings';
import type {BaseProps, BaseState} from './admin_settings';
@ -45,6 +44,56 @@ type Props = BaseProps & {
config: AdminConfig;
};
export const messages = defineMessages({
title: {id: 'admin.elasticsearch.title', defaultMessage: 'Elasticsearch'},
enableIndexingTitle: {id: 'admin.elasticsearch.enableIndexingTitle', defaultMessage: 'Enable Elasticsearch Indexing:'},
enableIndexingDescription: {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. <link>Learn more about Elasticsearch in our documentation.</link>'},
connectionUrlTitle: {id: 'admin.elasticsearch.connectionUrlTitle', defaultMessage: 'Server Connection Address:'},
connectionUrlDescription: {id: 'admin.elasticsearch.connectionUrlDescription', defaultMessage: 'The address of the Elasticsearch server. <link>Please see documentation with server setup instructions.</link>'},
skipTLSVerificationTitle: {id: 'admin.elasticsearch.skipTLSVerificationTitle', defaultMessage: 'Skip TLS Verification:'},
skipTLSVerificationDescription: {id: 'admin.elasticsearch.skipTLSVerificationDescription', defaultMessage: 'When true, Mattermost will not require the Elasticsearch certificate to be signed by a trusted Certificate Authority.'},
usernameTitle: {id: 'admin.elasticsearch.usernameTitle', defaultMessage: 'Server Username:'},
usernameDescription: {id: 'admin.elasticsearch.usernameDescription', defaultMessage: '(Optional) The username to authenticate to the Elasticsearch server.'},
passwordTitle: {id: 'admin.elasticsearch.passwordTitle', defaultMessage: 'Server Password:'},
passwordDescription: {id: 'admin.elasticsearch.passwordDescription', defaultMessage: '(Optional) The password to authenticate to the Elasticsearch server.'},
sniffTitle: {id: 'admin.elasticsearch.sniffTitle', defaultMessage: 'Enable Cluster Sniffing:'},
sniffDescription: {id: 'admin.elasticsearch.sniffDescription', defaultMessage: 'When true, sniffing finds and connects to all data nodes in your cluster automatically.'},
testHelpText: {id: 'admin.elasticsearch.testHelpText', defaultMessage: 'Tests if the Mattermost server can connect to the Elasticsearch server specified. Testing the connection only saves the configuration if the test is successful. A successful test will also re-initialize the client if you have started Elasticsearch after starting Mattermost. But this will not restart the workers. To do that, please toggle "Enable Elasticsearch Indexing".'},
elasticsearch_test_button: {id: 'admin.elasticsearch.elasticsearch_test_button', defaultMessage: 'Test Connection'},
bulkIndexingTitle: {id: 'admin.elasticsearch.bulkIndexingTitle', defaultMessage: 'Bulk Indexing:'},
help: {id: 'admin.elasticsearch.createJob.help', defaultMessage: 'All users, channels and posts in the database will be indexed from oldest to newest. Elasticsearch is available during indexing but search results may be incomplete until the indexing job is complete.'},
purgeIndexesHelpText: {id: 'admin.elasticsearch.purgeIndexesHelpText', defaultMessage: 'Purging will entirely remove the indexes on the Elasticsearch server. Search results may be incomplete until a bulk index of the existing database is rebuilt.'},
purgeIndexesButton: {id: 'admin.elasticsearch.purgeIndexesButton', defaultMessage: 'Purge Index'},
label: {id: 'admin.elasticsearch.purgeIndexesButton.label', defaultMessage: 'Purge Indexes:'},
enableSearchingTitle: {id: 'admin.elasticsearch.enableSearchingTitle', defaultMessage: 'Enable Elasticsearch for search queries:'},
enableSearchingDescription: {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.'},
});
export const searchableStrings: Array<string|MessageDescriptor|[MessageDescriptor, {[key: string]: any}]> = [
[messages.connectionUrlDescription, {documentationLink: ''}],
[messages.enableIndexingDescription, {documentationLink: ''}],
messages.title,
messages.enableIndexingTitle,
messages.connectionUrlTitle,
messages.skipTLSVerificationTitle,
messages.skipTLSVerificationDescription,
messages.usernameTitle,
messages.usernameDescription,
messages.passwordTitle,
messages.passwordDescription,
messages.sniffTitle,
messages.sniffDescription,
messages.testHelpText,
messages.elasticsearch_test_button,
messages.bulkIndexingTitle,
messages.help,
messages.purgeIndexesHelpText,
messages.purgeIndexesButton,
messages.label,
messages.enableSearchingTitle,
messages.enableSearchingDescription,
];
export default class ElasticsearchSettings extends AdminSettings<Props, State> {
getConfigFromState = (config: AdminConfig) => {
config.ElasticsearchSettings.ConnectionURL = this.state.connectionUrl;
@ -124,7 +173,7 @@ export default class ElasticsearchSettings extends AdminSettings<Props, State> {
return this.state.canSave;
};
doTestConfig = (success: () => void, error: (error: string) => void): void => {
doTestConfig = (success: () => void, error: (error: {message: string; detailed_message?: string}) => void): void => {
const config = JSON.parse(JSON.stringify(this.props.config));
this.getConfigFromState(config);
@ -137,7 +186,7 @@ export default class ElasticsearchSettings extends AdminSettings<Props, State> {
});
success();
},
(err: string) => {
(err: {message: string; detailed_message?: string}) => {
this.setState({
configTested: false,
canSave: false,
@ -163,10 +212,7 @@ export default class ElasticsearchSettings extends AdminSettings<Props, State> {
renderTitle() {
return (
<FormattedMessage
id='admin.elasticsearch.title'
defaultMessage='Elasticsearch'
/>
<FormattedMessage {...messages.title}/>
);
}
@ -176,25 +222,18 @@ export default class ElasticsearchSettings extends AdminSettings<Props, State> {
<BooleanSetting
id='enableIndexing'
label={
<FormattedMessage
id='admin.elasticsearch.enableIndexingTitle'
defaultMessage='Enable Elasticsearch Indexing:'
/>
<FormattedMessage {...messages.enableIndexingTitle}/>
}
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}'
{...messages.enableIndexingDescription}
values={{
documentationLink: (
link: (chunks) => (
<ExternalLink
location='elasticsearch_settings'
href={DocLinks.ELASTICSEARCH}
>
<FormattedMessage
id='admin.elasticsearch.enableIndexingDescription.documentationLinkText'
defaultMessage='Learn more about Elasticsearch in our documentation.'
/>
{chunks}
</ExternalLink>
),
}}
@ -208,26 +247,19 @@ export default class ElasticsearchSettings extends AdminSettings<Props, State> {
<TextSetting
id='connectionUrl'
label={
<FormattedMessage
id='admin.elasticsearch.connectionUrlTitle'
defaultMessage='Server Connection Address:'
/>
<FormattedMessage {...messages.connectionUrlTitle}/>
}
placeholder={Utils.localizeMessage('admin.elasticsearch.connectionUrlExample', 'E.g.: "https://elasticsearch.example.org:9200"')}
placeholder={defineMessage({id: 'admin.elasticsearch.connectionUrlExample', defaultMessage: 'E.g.: "https://elasticsearch.example.org:9200"'})}
helpText={
<FormattedMessage
id='admin.elasticsearch.connectionUrlDescription'
defaultMessage='The address of the Elasticsearch server. {documentationLink}'
{...messages.connectionUrlDescription}
values={{
documentationLink: (
link: (chunks) => (
<ExternalLink
location='elasticsearch_settings'
href={DocLinks.ELASTICSEARCH}
>
<FormattedMessage
id='admin.elasticsearch.connectionUrlExample.documentationLinkText'
defaultMessage='Please see documentation with server setup instructions.'
/>
{chunks}
</ExternalLink>
),
}}
@ -246,7 +278,7 @@ export default class ElasticsearchSettings extends AdminSettings<Props, State> {
defaultMessage='CA path:'
/>
}
placeholder={Utils.localizeMessage('admin.elasticsearch.caExample', 'E.g.: "./elasticsearch/ca.pem"')}
placeholder={defineMessage({id: 'admin.elasticsearch.caExample', defaultMessage: 'E.g.: "./elasticsearch/ca.pem"'})}
helpText={
<FormattedMessage
id='admin.elasticsearch.caDescription'
@ -266,7 +298,7 @@ export default class ElasticsearchSettings extends AdminSettings<Props, State> {
defaultMessage='Client Certificate path:'
/>
}
placeholder={Utils.localizeMessage('admin.elasticsearch.clientCertExample', 'E.g.: "./elasticsearch/client-cert.pem"')}
placeholder={defineMessage({id: 'admin.elasticsearch.clientCertExample', defaultMessage: 'E.g.: "./elasticsearch/client-cert.pem"'})}
helpText={
<FormattedMessage
id='admin.elasticsearch.clientCertDescription'
@ -286,7 +318,7 @@ export default class ElasticsearchSettings extends AdminSettings<Props, State> {
defaultMessage='Client Certificate Key path:'
/>
}
placeholder={Utils.localizeMessage('admin.elasticsearch.clientKeyExample', 'E.g.: "./elasticsearch/client-key.pem"')}
placeholder={defineMessage({id: 'admin.elasticsearch.clientKeyExample', defaultMessage: 'E.g.: "./elasticsearch/client-key.pem"'})}
helpText={
<FormattedMessage
id='admin.elasticsearch.clientKeyDescription'
@ -300,18 +332,8 @@ export default class ElasticsearchSettings extends AdminSettings<Props, State> {
/>
<BooleanSetting
id='skipTLSVerification'
label={
<FormattedMessage
id='admin.elasticsearch.skipTLSVerificationTitle'
defaultMessage='Skip TLS Verification:'
/>
}
helpText={
<FormattedMessage
id='admin.elasticsearch.skipTLSVerificationDescription'
defaultMessage='When true, Mattermost will not require the Elasticsearch certificate to be signed by a trusted Certificate Authority.'
/>
}
label={<FormattedMessage {...messages.skipTLSVerificationTitle}/>}
helpText={<FormattedMessage {...messages.skipTLSVerificationDescription}/>}
value={this.state.skipTLSVerification}
disabled={this.props.isDisabled || !this.state.enableIndexing}
onChange={this.handleSettingChanged}
@ -319,19 +341,9 @@ export default class ElasticsearchSettings extends AdminSettings<Props, State> {
/>
<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.'
/>
}
label={<FormattedMessage {...messages.usernameTitle}/>}
placeholder={defineMessage({id: 'admin.elasticsearch.usernameExample', defaultMessage: 'E.g.: "elastic"'})}
helpText={<FormattedMessage {...messages.usernameDescription}/>}
value={this.state.username}
disabled={this.props.isDisabled || !this.state.enableIndexing}
onChange={this.handleSettingChanged}
@ -339,19 +351,9 @@ export default class ElasticsearchSettings extends AdminSettings<Props, State> {
/>
<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.'
/>
}
label={<FormattedMessage {...messages.passwordTitle}/>}
placeholder={defineMessage({id: 'admin.elasticsearch.password', defaultMessage: 'E.g.: "yourpassword"'})}
helpText={<FormattedMessage {...messages.passwordDescription}/>}
value={this.state.password}
disabled={this.props.isDisabled || !this.state.enableIndexing}
onChange={this.handleSettingChanged}
@ -359,18 +361,8 @@ export default class ElasticsearchSettings extends AdminSettings<Props, State> {
/>
<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.'
/>
}
label={<FormattedMessage {...messages.sniffTitle}/>}
helpText={<FormattedMessage {...messages.sniffDescription}/>}
value={this.state.sniff}
disabled={this.props.isDisabled || !this.state.enableIndexing}
onChange={this.handleSettingChanged}
@ -379,32 +371,17 @@ export default class ElasticsearchSettings extends AdminSettings<Props, State> {
<RequestButton
id='testConfig'
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 only saves the configuration if the test is successful. A successful test will also re-initialize the client if you have started Elasticsearch after starting Mattermost. But this will not restart the workers. To do that, please toggle "Enable Elasticsearch Indexing".'
/>
}
buttonText={
<FormattedMessage
id='admin.elasticsearch.elasticsearch_test_button'
defaultMessage='Test Connection'
/>
}
successMessage={{
id: t('admin.elasticsearch.testConfigSuccess'),
helpText={<FormattedMessage {...messages.testHelpText}/>}
buttonText={<FormattedMessage {...messages.elasticsearch_test_button}/>}
successMessage={defineMessage({
id: 'admin.elasticsearch.testConfigSuccess',
defaultMessage: 'Test successful. Configuration saved.',
}}
})}
disabled={!this.state.enableIndexing}
/>
<div className='form-group'>
<label
className='control-label col-sm-4'
>
<FormattedMessage
id='admin.elasticsearch.bulkIndexingTitle'
defaultMessage='Bulk Indexing:'
/>
<label className='control-label col-sm-4'>
<FormattedMessage {...messages.bulkIndexingTitle}/>
</label>
<div className='col-sm-8'>
<div className='job-table-setting'>
@ -417,12 +394,7 @@ export default class ElasticsearchSettings extends AdminSettings<Props, State> {
defaultMessage='Index Now'
/>
}
createJobHelpText={
<FormattedMessage
id='admin.elasticsearch.createJob.help'
defaultMessage='All users, channels and posts in the database will be indexed from oldest to newest. Elasticsearch is available during indexing but search results may be incomplete until the indexing job is complete.'
/>
}
createJobHelpText={<FormattedMessage {...messages.help}/>}
getExtraInfoText={this.getExtraInfo}
/>
</div>
@ -431,33 +403,18 @@ export default class ElasticsearchSettings extends AdminSettings<Props, State> {
<RequestButton
id='purgeIndexesSection'
requestAction={elasticsearchPurgeIndexes}
helpText={
<FormattedMessage
id='admin.elasticsearch.purgeIndexesHelpText'
defaultMessage='Purging will entirely remove the indexes on the Elasticsearch server. Search results may be incomplete until a bulk index of the existing database is rebuilt.'
/>
}
buttonText={
<FormattedMessage
id='admin.elasticsearch.purgeIndexesButton'
defaultMessage='Purge Index'
/>
}
successMessage={{
id: t('admin.elasticsearch.purgeIndexesButton.success'),
helpText={<FormattedMessage {...messages.purgeIndexesHelpText}/>}
buttonText={<FormattedMessage {...messages.purgeIndexesButton}/>}
successMessage={defineMessage({
id: 'admin.elasticsearch.purgeIndexesButton.success',
defaultMessage: 'Indexes purged successfully.',
}}
errorMessage={{
id: t('admin.elasticsearch.purgeIndexesButton.error'),
})}
errorMessage={defineMessage({
id: 'admin.elasticsearch.purgeIndexesButton.error',
defaultMessage: 'Failed to purge indexes: {error}',
}}
})}
disabled={this.props.isDisabled || !this.state.canPurgeAndIndex}
label={(
<FormattedMessage
id='admin.elasticsearch.purgeIndexesButton.label'
defaultMessage='Purge Indexes:'
/>
)}
label={<FormattedMessage {...messages.label}/>}
/>
<TextSetting
id='ignoredPurgeIndexes'
@ -467,7 +424,7 @@ export default class ElasticsearchSettings extends AdminSettings<Props, State> {
defaultMessage='Indexes to skip while purging:'
/>
}
placeholder={'E.g.: .opendistro*,.security*'}
placeholder={defineMessage({id: 'admin.elasticsearch.ignoredPurgeIndexesDescription.example', defaultMessage: 'E.g.: .opendistro*,.security*'})}
helpText={
<FormattedMessage
id='admin.elasticsearch.ignoredPurgeIndexesDescription'
@ -481,18 +438,8 @@ export default class ElasticsearchSettings extends AdminSettings<Props, State> {
/>
<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.'
/>
}
label={<FormattedMessage {...messages.enableSearchingTitle}/>}
helpText={<FormattedMessage {...messages.enableSearchingDescription}/>}
value={this.state.enableSearching}
disabled={this.props.isDisabled || !this.state.enableIndexing || !this.state.configTested}
onChange={this.handleSettingChanged}

View File

@ -2,7 +2,7 @@
// See LICENSE.txt for license information.
import React from 'react';
import {FormattedMessage} from 'react-intl';
import {FormattedMessage, defineMessages} from 'react-intl';
import type {AdminConfig} from '@mattermost/types/config';
@ -12,6 +12,10 @@ type Props = {
config: AdminConfig;
};
export const messages = defineMessages({
title: {id: 'admin.feature_flags.title', defaultMessage: 'Features Flags'},
});
const FeatureFlags: React.FC<Props> = (props: Props) => {
const flags = props.config.FeatureFlags;
let settings = null;
@ -28,10 +32,7 @@ const FeatureFlags: React.FC<Props> = (props: Props) => {
return (
<div className='wrapper--admin'>
<AdminHeader>
<FormattedMessage
id='admin.feature_flags.title'
defaultMessage='Features Flags'
/>
<FormattedMessage {...messages.title}/>
</AdminHeader>
<div className='admin-console__wrapper'>
<div className='admin-logs-content admin-console__content'>

View File

@ -13,7 +13,7 @@ type Props = {
label: React.ReactNode;
helpText?: React.ReactNode;
uploadingText?: React.ReactNode;
onSubmit: (id: string, file: File, errorCallback: (error: string) => void) => void;
onSubmit: (id: string, file: File, errorCallback: (error?: string) => void) => void;
disabled: boolean;
fileType: string;
error?: string;

View File

@ -35,17 +35,24 @@ For more information on Groups, please see <link>documentation</link>."
</div>
</div>
<AdminPanel
className=""
id="ldap_groups"
subtitleDefault="Connect AD/LDAP and create groups in Mattermost. To get started, configure group attributes on the <link>AD/LDAP</link> configuration page."
subtitleId="admin.group_settings.ldapGroupsDescription"
subtitle={
Object {
"defaultMessage": "Connect AD/LDAP and create groups in Mattermost. To get started, configure group attributes on the <link>AD/LDAP</link> configuration page.",
"id": "admin.group_settings.ldapGroupsDescription",
}
}
subtitleValues={
Object {
"link": [Function],
}
}
titleDefault="AD/LDAP Groups"
titleId="admin.group_settings.ldapGroupsTitle"
title={
Object {
"defaultMessage": "AD/LDAP Groups",
"id": "admin.group_settings.ldapGroupsTitle",
}
}
>
<Connect(GroupsList) />
</AdminPanel>

View File

@ -84,12 +84,19 @@ exports[`components/admin_console/group_settings/group_details/GroupDetails shou
</MenuWrapper>
</div>
}
className=""
id="group_teams_and_channels"
subtitleDefault="Set default teams and channels for group members. Teams added will include default channels, town-square, and off-topic. Adding a channel without setting the team will add the implied team to the listing below."
subtitleId="admin.group_settings.group_detail.groupTeamsAndChannelsDescription"
titleDefault="Team and Channel Membership"
titleId="admin.group_settings.group_detail.groupTeamsAndChannelsTitle"
subtitle={
Object {
"defaultMessage": "Set default teams and channels for group members. Teams added will include default channels, town-square, and off-topic. Adding a channel without setting the team will add the implied team to the listing below.",
"id": "admin.group_settings.group_detail.groupTeamsAndChannelsDescription",
}
}
title={
Object {
"defaultMessage": "Team and Channel Membership",
"id": "admin.group_settings.group_detail.groupTeamsAndChannelsTitle",
}
}
>
<GroupTeamsAndChannels
channels={Array []}
@ -113,12 +120,19 @@ exports[`components/admin_console/group_settings/group_details/GroupDetails shou
onModalDismissed={[Function]}
/>
<AdminPanel
className=""
id="group_users"
subtitleDefault="Listing of users in Mattermost associated with this group."
subtitleId="admin.group_settings.group_detail.groupUsersDescription"
titleDefault="Users"
titleId="admin.group_settings.group_detail.groupUsersTitle"
subtitle={
Object {
"defaultMessage": "Listing of users in Mattermost associated with this group.",
"id": "admin.group_settings.group_detail.groupUsersDescription",
}
}
title={
Object {
"defaultMessage": "Users",
"id": "admin.group_settings.group_detail.groupUsersTitle",
}
}
>
<GroupUsers
getMembers={[MockFunction]}
@ -234,12 +248,19 @@ exports[`components/admin_console/group_settings/group_details/GroupDetails shou
</MenuWrapper>
</div>
}
className=""
id="group_teams_and_channels"
subtitleDefault="Set default teams and channels for group members. Teams added will include default channels, town-square, and off-topic. Adding a channel without setting the team will add the implied team to the listing below."
subtitleId="admin.group_settings.group_detail.groupTeamsAndChannelsDescription"
titleDefault="Team and Channel Membership"
titleId="admin.group_settings.group_detail.groupTeamsAndChannelsTitle"
subtitle={
Object {
"defaultMessage": "Set default teams and channels for group members. Teams added will include default channels, town-square, and off-topic. Adding a channel without setting the team will add the implied team to the listing below.",
"id": "admin.group_settings.group_detail.groupTeamsAndChannelsDescription",
}
}
title={
Object {
"defaultMessage": "Team and Channel Membership",
"id": "admin.group_settings.group_detail.groupTeamsAndChannelsTitle",
}
}
>
<GroupTeamsAndChannels
channels={Array []}
@ -262,12 +283,19 @@ exports[`components/admin_console/group_settings/group_details/GroupDetails shou
onTeamsSelected={[Function]}
/>
<AdminPanel
className=""
id="group_users"
subtitleDefault="Listing of users in Mattermost associated with this group."
subtitleId="admin.group_settings.group_detail.groupUsersDescription"
titleDefault="Users"
titleId="admin.group_settings.group_detail.groupUsersTitle"
subtitle={
Object {
"defaultMessage": "Listing of users in Mattermost associated with this group.",
"id": "admin.group_settings.group_detail.groupUsersDescription",
}
}
title={
Object {
"defaultMessage": "Users",
"id": "admin.group_settings.group_detail.groupUsersTitle",
}
}
>
<GroupUsers
getMembers={[MockFunction]}
@ -383,12 +411,19 @@ exports[`components/admin_console/group_settings/group_details/GroupDetails shou
</MenuWrapper>
</div>
}
className=""
id="group_teams_and_channels"
subtitleDefault="Set default teams and channels for group members. Teams added will include default channels, town-square, and off-topic. Adding a channel without setting the team will add the implied team to the listing below."
subtitleId="admin.group_settings.group_detail.groupTeamsAndChannelsDescription"
titleDefault="Team and Channel Membership"
titleId="admin.group_settings.group_detail.groupTeamsAndChannelsTitle"
subtitle={
Object {
"defaultMessage": "Set default teams and channels for group members. Teams added will include default channels, town-square, and off-topic. Adding a channel without setting the team will add the implied team to the listing below.",
"id": "admin.group_settings.group_detail.groupTeamsAndChannelsDescription",
}
}
title={
Object {
"defaultMessage": "Team and Channel Membership",
"id": "admin.group_settings.group_detail.groupTeamsAndChannelsTitle",
}
}
>
<GroupTeamsAndChannels
channels={Array []}
@ -400,12 +435,19 @@ exports[`components/admin_console/group_settings/group_details/GroupDetails shou
/>
</AdminPanel>
<AdminPanel
className=""
id="group_users"
subtitleDefault="Listing of users in Mattermost associated with this group."
subtitleId="admin.group_settings.group_detail.groupUsersDescription"
titleDefault="Users"
titleId="admin.group_settings.group_detail.groupUsersTitle"
subtitle={
Object {
"defaultMessage": "Listing of users in Mattermost associated with this group.",
"id": "admin.group_settings.group_detail.groupUsersDescription",
}
}
title={
Object {
"defaultMessage": "Users",
"id": "admin.group_settings.group_detail.groupUsersTitle",
}
}
>
<GroupUsers
getMembers={[MockFunction]}
@ -521,12 +563,19 @@ exports[`components/admin_console/group_settings/group_details/GroupDetails shou
</MenuWrapper>
</div>
}
className=""
id="group_teams_and_channels"
subtitleDefault="Set default teams and channels for group members. Teams added will include default channels, town-square, and off-topic. Adding a channel without setting the team will add the implied team to the listing below."
subtitleId="admin.group_settings.group_detail.groupTeamsAndChannelsDescription"
titleDefault="Team and Channel Membership"
titleId="admin.group_settings.group_detail.groupTeamsAndChannelsTitle"
subtitle={
Object {
"defaultMessage": "Set default teams and channels for group members. Teams added will include default channels, town-square, and off-topic. Adding a channel without setting the team will add the implied team to the listing below.",
"id": "admin.group_settings.group_detail.groupTeamsAndChannelsDescription",
}
}
title={
Object {
"defaultMessage": "Team and Channel Membership",
"id": "admin.group_settings.group_detail.groupTeamsAndChannelsTitle",
}
}
>
<GroupTeamsAndChannels
channels={Array []}
@ -538,12 +587,19 @@ exports[`components/admin_console/group_settings/group_details/GroupDetails shou
/>
</AdminPanel>
<AdminPanel
className=""
id="group_users"
subtitleDefault="Listing of users in Mattermost associated with this group."
subtitleId="admin.group_settings.group_detail.groupUsersDescription"
titleDefault="Users"
titleId="admin.group_settings.group_detail.groupUsersTitle"
subtitle={
Object {
"defaultMessage": "Listing of users in Mattermost associated with this group.",
"id": "admin.group_settings.group_detail.groupUsersDescription",
}
}
title={
Object {
"defaultMessage": "Users",
"id": "admin.group_settings.group_detail.groupUsersTitle",
}
}
>
<GroupUsers
getMembers={[MockFunction]}

View File

@ -2,20 +2,31 @@
exports[`components/admin_console/group_settings/group_details/GroupProfileAndSettings should match snapshot, with toggle off 1`] = `
<AdminPanel
className=""
id="group_profile"
subtitleDefault="The name for this group."
subtitleId="admin.group_settings.group_detail.groupProfileDescription"
titleDefault="Group Profile"
titleId="admin.group_settings.group_detail.groupProfileTitle"
subtitle={
Object {
"defaultMessage": "The name for this group.",
"id": "admin.group_settings.group_detail.groupProfileDescription",
}
}
title={
Object {
"defaultMessage": "Group Profile",
"id": "admin.group_settings.group_detail.groupProfileTitle",
}
}
>
<Memo(GroupProfile)
customID="groupDisplayName"
isDisabled={true}
name="GroupProfileAndSettings"
showAtMention={false}
title="admin.group_settings.group_details.group_profile.name"
titleDefault="Name:"
title={
Object {
"defaultMessage": "Name:",
"id": "admin.group_settings.group_details.group_profile.name",
}
}
/>
<div
className="group-settings"
@ -42,20 +53,31 @@ exports[`components/admin_console/group_settings/group_details/GroupProfileAndSe
exports[`components/admin_console/group_settings/group_details/GroupProfileAndSettings should match snapshot, with toggle on 1`] = `
<AdminPanel
className=""
id="group_profile"
subtitleDefault="The name for this group."
subtitleId="admin.group_settings.group_detail.groupProfileDescription"
titleDefault="Group Profile"
titleId="admin.group_settings.group_detail.groupProfileTitle"
subtitle={
Object {
"defaultMessage": "The name for this group.",
"id": "admin.group_settings.group_detail.groupProfileDescription",
}
}
title={
Object {
"defaultMessage": "Group Profile",
"id": "admin.group_settings.group_detail.groupProfileTitle",
}
}
>
<Memo(GroupProfile)
customID="groupDisplayName"
isDisabled={true}
name="GroupProfileAndSettings"
showAtMention={false}
title="admin.group_settings.group_details.group_profile.name"
titleDefault="Name:"
title={
Object {
"defaultMessage": "Name:",
"id": "admin.group_settings.group_details.group_profile.name",
}
}
/>
<div
className="group-settings"
@ -82,8 +104,12 @@ exports[`components/admin_console/group_settings/group_details/GroupProfileAndSe
name="GroupProfileAndSettings"
onChange={[MockFunction]}
showAtMention={true}
title="admin.group_settings.group_details.group_mention.name"
titleDefault="Group Mention:"
title={
Object {
"defaultMessage": "Group Mention:",
"id": "admin.group_settings.group_details.group_mention.name",
}
}
/>
</AdminPanel>
`;

View File

@ -1,7 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {shallow} from 'enzyme';
import React from 'react';
import type {ChannelWithTeamData} from '@mattermost/types/channels';
@ -11,6 +10,16 @@ import type {UserProfile} from '@mattermost/types/users';
import GroupDetails from 'components/admin_console/group_settings/group_details/group_details';
import {shallowWithIntl} from 'tests/helpers/intl-test-helper';
function getAnyInstance(wrapper: any) {
return wrapper.instance() as any;
}
function getAnyState(wrapper: any) {
return wrapper.state() as any;
}
describe('components/admin_console/group_settings/group_details/GroupDetails', () => {
const defaultProps = {
groupID: 'xxxxxxxxxxxxxxxxxxxxxxxxxx',
@ -48,27 +57,27 @@ describe('components/admin_console/group_settings/group_details/GroupDetails', (
};
test('should match snapshot, with everything closed', () => {
const wrapper = shallow(<GroupDetails {...defaultProps}/>);
const wrapper = shallowWithIntl(<GroupDetails {...defaultProps}/>);
defaultProps.actions.getGroupSyncables.mockClear();
expect(wrapper).toMatchSnapshot();
});
test('should match snapshot, with add team selector open', () => {
const wrapper = shallow(<GroupDetails {...defaultProps}/>);
const wrapper = shallowWithIntl(<GroupDetails {...defaultProps}/>);
wrapper.setState({addTeamOpen: true});
defaultProps.actions.getGroupSyncables.mockClear();
expect(wrapper).toMatchSnapshot();
});
test('should match snapshot, with add channel selector open', () => {
const wrapper = shallow(<GroupDetails {...defaultProps}/>);
const wrapper = shallowWithIntl(<GroupDetails {...defaultProps}/>);
wrapper.setState({addChannelOpen: true});
defaultProps.actions.getGroupSyncables.mockClear();
expect(wrapper).toMatchSnapshot();
});
test('should match snapshot, with loaded state', () => {
const wrapper = shallow(<GroupDetails {...defaultProps}/>);
const wrapper = shallowWithIntl(<GroupDetails {...defaultProps}/>);
wrapper.setState({loading: false, loadingTeamsAndChannels: false});
defaultProps.actions.getGroupSyncables.mockClear();
expect(wrapper).toMatchSnapshot();
@ -86,7 +95,7 @@ describe('components/admin_console/group_settings/group_details/GroupDetails', (
patchGroupSyncable: jest.fn(),
setNavigationBlocked: jest.fn(),
};
shallow(
shallowWithIntl(
<GroupDetails
{...defaultProps}
actions={actions}
@ -110,13 +119,13 @@ describe('components/admin_console/group_settings/group_details/GroupDetails', (
patchGroupSyncable: jest.fn(),
setNavigationBlocked: jest.fn(),
};
const wrapper = shallow<GroupDetails>(
const wrapper = shallowWithIntl(
<GroupDetails
{...defaultProps}
actions={actions}
/>,
);
const instance = wrapper.instance();
const instance = getAnyInstance(wrapper);
await instance.addChannels([
{id: '11111111111111111111111111'} as ChannelWithTeamData,
{id: '22222222222222222222222222'} as ChannelWithTeamData,
@ -142,13 +151,13 @@ describe('components/admin_console/group_settings/group_details/GroupDetails', (
patchGroupSyncable: jest.fn(),
setNavigationBlocked: jest.fn(),
};
const wrapper = shallow<GroupDetails>(
const wrapper = shallowWithIntl(
<GroupDetails
{...defaultProps}
actions={actions}
/>,
);
const instance = wrapper.instance();
const instance = getAnyInstance(wrapper);
expect(instance.state.groupTeams?.length === 0);
instance.addTeams([
{id: '11111111111111111111111111'} as Team,
@ -164,7 +173,7 @@ describe('components/admin_console/group_settings/group_details/GroupDetails', (
});
test('update name for null slug', async () => {
const wrapper = shallow<GroupDetails>(
const wrapper = shallowWithIntl(
<GroupDetails
{...defaultProps}
group={{
@ -174,12 +183,12 @@ describe('components/admin_console/group_settings/group_details/GroupDetails', (
/>,
);
wrapper.instance().onMentionToggle(true);
expect(wrapper.state().groupMentionName).toBe('test-group');
getAnyInstance(wrapper).onMentionToggle(true);
expect(getAnyState(wrapper).groupMentionName).toBe('test-group');
});
test('update name for empty slug', async () => {
const wrapper = shallow<GroupDetails>(
const wrapper = shallowWithIntl(
<GroupDetails
{...defaultProps}
group={{
@ -190,12 +199,12 @@ describe('components/admin_console/group_settings/group_details/GroupDetails', (
/>,
);
wrapper.instance().onMentionToggle(true);
expect(wrapper.state().groupMentionName).toBe('test-group');
getAnyInstance(wrapper).onMentionToggle(true);
expect(getAnyState(wrapper).groupMentionName).toBe('test-group');
});
test('Should not update name for slug', async () => {
const wrapper = shallow<GroupDetails>(
const wrapper = shallowWithIntl(
<GroupDetails
{...defaultProps}
group={{
@ -205,7 +214,7 @@ describe('components/admin_console/group_settings/group_details/GroupDetails', (
} as Group}
/>,
);
wrapper.instance().onMentionToggle(true);
expect(wrapper.state().groupMentionName).toBe('any_name_at_all');
getAnyInstance(wrapper).onMentionToggle(true);
expect(getAnyState(wrapper).groupMentionName).toBe('any_name_at_all');
});
});

View File

@ -2,7 +2,8 @@
// See LICENSE.txt for license information.
import React from 'react';
import {FormattedMessage} from 'react-intl';
import type {WrappedComponentProps} from 'react-intl';
import {FormattedMessage, defineMessage, injectIntl} from 'react-intl';
import type {ChannelWithTeamData} from '@mattermost/types/channels';
import {
@ -32,9 +33,6 @@ import AdminPanel from 'components/widgets/admin_console/admin_panel';
import Menu from 'components/widgets/menu/menu';
import MenuWrapper from 'components/widgets/menu/menu_wrapper';
import {t} from 'utils/i18n';
import {localizeMessage} from 'utils/utils';
export type Props = {
groupID: string;
group: Group;
@ -78,7 +76,7 @@ export type Props = {
blocked: boolean;
};
};
};
} & WrappedComponentProps;
export type State = {
loadingTeamsAndChannels: boolean;
@ -99,7 +97,7 @@ export type State = {
groupChannels: GroupChannel[];
};
export default class GroupDetails extends React.PureComponent<Props, State> {
class GroupDetails extends React.PureComponent<Props, State> {
static defaultProps: Partial<Props> = {
groupID: '',
members: [],
@ -680,14 +678,8 @@ export default class GroupDetails extends React.PureComponent<Props, State> {
<AdminPanel
id='group_teams_and_channels'
titleId={t(
'admin.group_settings.group_detail.groupTeamsAndChannelsTitle',
)}
titleDefault='Team and Channel Membership'
subtitleId={t(
'admin.group_settings.group_detail.groupTeamsAndChannelsDescription',
)}
subtitleDefault='Set default teams and channels for group members. Teams added will include default channels, town-square, and off-topic. Adding a channel without setting the team will add the implied team to the listing below.'
title={defineMessage({id: 'admin.group_settings.group_detail.groupTeamsAndChannelsTitle', defaultMessage: 'Team and Channel Membership'})}
subtitle={defineMessage({id: 'admin.group_settings.group_detail.groupTeamsAndChannelsDescription', defaultMessage: 'Set default teams and channels for group members. Teams added will include default channels, town-square, and off-topic. Adding a channel without setting the team will add the implied team to the listing below.'})}
button={
<div className='group-profile-add-menu'>
<MenuWrapper isDisabled={isDisabled}>
@ -703,26 +695,26 @@ export default class GroupDetails extends React.PureComponent<Props, State> {
<i className={'fa fa-caret-down'}/>
</button>
<Menu
ariaLabel={localizeMessage(
'admin.group_settings.group_details.menuAriaLabel',
'Add Team or Channel Menu',
)}
ariaLabel={this.props.intl.formatMessage({
id: 'admin.group_settings.group_details.menuAriaLabel',
defaultMessage: 'Add Team or Channel Menu',
})}
>
<Menu.ItemAction
id='add_team'
onClick={this.openAddTeam}
text={localizeMessage(
'admin.group_settings.group_details.add_team',
'Add Team',
)}
text={this.props.intl.formatMessage({
id: 'admin.group_settings.group_details.add_team',
defaultMessage: 'Add Team',
})}
/>
<Menu.ItemAction
id='add_channel'
onClick={this.openAddChannel}
text={localizeMessage(
'admin.group_settings.group_details.add_channel',
'Add Channel',
)}
text={this.props.intl.formatMessage({
id: 'admin.group_settings.group_details.add_channel',
defaultMessage: 'Add Channel',
})}
/>
</Menu>
</MenuWrapper>
@ -761,14 +753,8 @@ export default class GroupDetails extends React.PureComponent<Props, State> {
<AdminPanel
id='group_users'
titleId={t(
'admin.group_settings.group_detail.groupUsersTitle',
)}
titleDefault='Users'
subtitleId={t(
'admin.group_settings.group_detail.groupUsersDescription',
)}
subtitleDefault='Listing of users in Mattermost associated with this group.'
title={defineMessage({id: 'admin.group_settings.group_detail.groupUsersTitle', defaultMessage: 'Users'})}
subtitle={defineMessage({id: 'admin.group_settings.group_detail.groupUsersDescription', defaultMessage: 'Listing of users in Mattermost associated with this group.'})}
>
<GroupUsers
members={members}
@ -799,3 +785,5 @@ export default class GroupDetails extends React.PureComponent<Props, State> {
);
};
}
export default injectIntl(GroupDetails);

View File

@ -13,8 +13,7 @@ describe('components/admin_console/group_settings/group_details/GroupProfile', (
isDisabled={false}
name='Test'
showAtMention={true}
title='admin.group_settings.group_details.group_profile.name'
titleDefault='Name:'
title={{id: 'admin.group_settings.group_details.group_profile.name', defaultMessage: 'Name:'}}
/>,
);
expect(wrapper).toMatchSnapshot();

View File

@ -2,14 +2,14 @@
// See LICENSE.txt for license information.
import React, {memo} from 'react';
import type {MessageDescriptor} from 'react-intl';
import {FormattedMessage} from 'react-intl';
import MentionsIcon from 'components/widgets/icons/mentions_icon';
type Props = {
name?: string;
title: string;
titleDefault: string;
title: MessageDescriptor;
customID?: string;
isDisabled?: boolean;
showAtMention: boolean;
@ -19,7 +19,6 @@ type Props = {
const GroupProfile = ({
name,
title,
titleDefault,
customID,
isDisabled,
showAtMention,
@ -31,10 +30,7 @@ const GroupProfile = ({
>
<div className='group-profile-field form-group mb-0'>
<label className='control-label col-sm-4'>
<FormattedMessage
id={title}
defaultMessage={titleDefault}
/>
<FormattedMessage {...title}/>
</label>
<div className='col-sm-8'>
<div className='icon-over-input'>

View File

@ -2,15 +2,13 @@
// See LICENSE.txt for license information.
import React from 'react';
import {FormattedMessage} from 'react-intl';
import {FormattedMessage, defineMessage} from 'react-intl';
import GroupProfile from 'components/admin_console/group_settings/group_details/group_profile';
import LineSwitch from 'components/admin_console/team_channel_settings/line_switch';
import FormattedMarkdownMessage from 'components/formatted_markdown_message';
import AdminPanel from 'components/widgets/admin_console/admin_panel';
import {t} from 'utils/i18n';
type GroupSettingsToggleProps = {
isDefault: boolean;
allowReference: boolean;
@ -70,17 +68,12 @@ export const GroupProfileAndSettings = ({
}: GroupProfileAndSettingsProps) => (
<AdminPanel
id='group_profile'
titleId={t('admin.group_settings.group_detail.groupProfileTitle')}
titleDefault='Group Profile'
subtitleId={t(
'admin.group_settings.group_detail.groupProfileDescription',
)}
subtitleDefault='The name for this group.'
title={defineMessage({id: 'admin.group_settings.group_detail.groupProfileTitle', defaultMessage: 'Group Profile'})}
subtitle={defineMessage({id: 'admin.group_settings.group_detail.groupProfileDescription', defaultMessage: 'The name for this group.'})}
>
<GroupProfile
name={displayname}
title={t('admin.group_settings.group_details.group_profile.name')}
titleDefault={'Name:'}
title={defineMessage({id: 'admin.group_settings.group_details.group_profile.name', defaultMessage: 'Name:'})}
customID={'groupDisplayName'}
isDisabled={true}
showAtMention={false}
@ -101,10 +94,7 @@ export const GroupProfileAndSettings = ({
{allowReference && (
<GroupProfile
name={mentionname}
title={t(
'admin.group_settings.group_details.group_mention.name',
)}
titleDefault={'Group Mention:'}
title={defineMessage({id: 'admin.group_settings.group_details.group_mention.name', defaultMessage: 'Group Mention:'})}
customID={'groupMention'}
isDisabled={readOnly}
showAtMention={true}

View File

@ -2,7 +2,7 @@
// See LICENSE.txt for license information.
import React from 'react';
import {FormattedMessage} from 'react-intl';
import {FormattedMessage, defineMessage} from 'react-intl';
import GroupsList from 'components/admin_console/group_settings/groups_list';
import ExternalLink from 'components/external_link';
@ -10,7 +10,6 @@ import AdminHeader from 'components/widgets/admin_console/admin_header';
import AdminPanel from 'components/widgets/admin_console/admin_panel';
import {DocLinks} from 'utils/constants';
import {t} from 'utils/i18n';
import {getSiteURL} from 'utils/url';
type Props = {
@ -50,10 +49,8 @@ const GroupSettings = ({isDisabled}: Props) => {
<AdminPanel
id='ldap_groups'
titleId={t('admin.group_settings.ldapGroupsTitle')}
titleDefault='AD/LDAP Groups'
subtitleId={t('admin.group_settings.ldapGroupsDescription')}
subtitleDefault={'Connect AD/LDAP and create groups in Mattermost. To get started, configure group attributes on the <link>AD/LDAP</link> configuration page.'}
title={defineMessage({id: 'admin.group_settings.ldapGroupsTitle', defaultMessage: 'AD/LDAP Groups'})}
subtitle={defineMessage({id: 'admin.group_settings.ldapGroupsDescription', defaultMessage: 'Connect AD/LDAP and create groups in Mattermost. To get started, configure group attributes on the <link>AD/LDAP</link> configuration page.'})}
subtitleValues={{
link: (msg: React.ReactNode) => (
<ExternalLink

View File

@ -28,7 +28,7 @@ export type Props = {
downloadExportResults?: boolean;
className?: string;
hideJobCreateButton?: boolean;
createJobButtonText: React.ReactElement;
createJobButtonText: React.ReactNode;
actions: {
getJobsByType: (jobType: JobType) => void;
cancelJob: (jobId: string) => Promise<ActionResult>;

View File

@ -4,7 +4,7 @@
import classNames from 'classnames';
import React, {useEffect, useState} from 'react';
import type {RefObject} from 'react';
import {FormattedDate, FormattedMessage, FormattedNumber, FormattedTime, useIntl} from 'react-intl';
import {FormattedDate, FormattedMessage, FormattedNumber, FormattedTime, defineMessages, useIntl} from 'react-intl';
import {useSelector} from 'react-redux';
import type {ClientLicense} from '@mattermost/types/config';
@ -44,6 +44,10 @@ export interface EnterpriseEditionProps {
statsActiveUsers: number;
}
export const messages = defineMessages({
keyRemove: {id: 'admin.license.keyRemove', defaultMessage: 'Remove license and downgrade to Mattermost Free'},
});
const EnterpriseEditionLeftPanel = ({
openEELicenseModal,
upgradedFromTE,
@ -179,6 +183,7 @@ const EnterpriseEditionLeftPanel = ({
}
</div>
<div className='license-notices'>
{/* This notice should not be translated */}
{upgradedFromTE ? <>
<p>
{'When using Mattermost Enterprise Edition, the software is offered under a commercial license. See '}
@ -347,12 +352,7 @@ const renderRemoveButton = (
isDisabled: boolean,
removing: boolean,
) => {
let removeButtonText = (
<FormattedMessage
id='admin.license.keyRemove'
defaultMessage='Remove license and downgrade to Mattermost Free'
/>
);
let removeButtonText = (<FormattedMessage {...messages.keyRemove}/>);
if (removing) {
removeButtonText = (
<FormattedMessage

View File

@ -2,7 +2,7 @@
// See LICENSE.txt for license information.
import React from 'react';
import {FormattedMessage} from 'react-intl';
import {FormattedMessage, defineMessages} from 'react-intl';
import type {StatusOK} from '@mattermost/types/client4';
import type {ClientLicense} from '@mattermost/types/config';
@ -22,13 +22,13 @@ import {isLicenseExpired, isLicenseExpiring, isTrialLicense, isEnterpriseOrE20Li
import type {ModalData} from 'types/actions';
import EnterpriseEditionLeftPanel from './enterprise_edition/enterprise_edition_left_panel';
import EnterpriseEditionLeftPanel, {messages as enterpriseEditionLeftPanelMessages} from './enterprise_edition/enterprise_edition_left_panel';
import EnterpriseEditionRightPanel from './enterprise_edition/enterprise_edition_right_panel';
import ConfirmLicenseRemovalModal from './modals/confirm_license_removal_modal';
import EELicenseModal from './modals/ee_license_modal';
import UploadLicenseModal from './modals/upload_license_modal';
import RenewLinkCard from './renew_license_card/renew_license_card';
import StarterLeftPanel from './starter_edition/starter_left_panel';
import StarterLeftPanel, {messages as licenseSettingsStarterEditionMessages} from './starter_edition/starter_left_panel';
import StarterRightPanel from './starter_edition/starter_right_panel';
import TeamEditionLeftPanel from './team_edition/team_edition_left_panel';
import TeamEditionRightPanel from './team_edition/team_edition_right_panel';
@ -63,6 +63,16 @@ type Props = {
};
}
const messages = defineMessages({
title: {id: 'admin.license.title', defaultMessage: 'Edition and License'},
});
export const searchableStrings = [
licenseSettingsStarterEditionMessages.key,
enterpriseEditionLeftPanelMessages.keyRemove,
messages.title,
];
type State = {
fileSelected: boolean;
file: File | null;
@ -339,10 +349,7 @@ export default class LicenseSettings extends React.PureComponent<Props, State> {
return (
<div className='wrapper--fixed'>
<AdminHeader>
<FormattedMessage
id='admin.license.title'
defaultMessage='Edition and License'
/>
<FormattedMessage {...messages.title}/>
</AdminHeader>
<div className='admin-console__wrapper'>
<div className='admin-console__content'>

View File

@ -3,7 +3,7 @@
import React from 'react';
import type {RefObject} from 'react';
import {FormattedMessage, useIntl} from 'react-intl';
import {FormattedMessage, defineMessages, useIntl} from 'react-intl';
import useOpenPricingModal from 'components/common/hooks/useOpenPricingModal';
@ -18,6 +18,10 @@ export interface StarterEditionProps {
handleChange: () => void;
}
export const messages = defineMessages({
key: {id: 'admin.license.key', defaultMessage: 'License Key: '},
});
const StarterLeftPanel: React.FC<StarterEditionProps> = ({
openEELicenseModal,
currentPlan,
@ -86,13 +90,8 @@ const StarterLeftPanel: React.FC<StarterEditionProps> = ({
}
</div>
<div className='licenseInformation'>
<div
className='licenseKeyTitle'
>
<FormattedMessage
id='admin.license.key'
defaultMessage='License Key: '
/>
<div className='licenseKeyTitle'>
<FormattedMessage {...messages.key}/>
</div>
<div className='uploadButtons'>
<button

View File

@ -1,11 +1,12 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {shallow} from 'enzyme';
import React from 'react';
import MessageExportSettings from 'components/admin_console/message_export_settings';
import {shallowWithIntl} from 'tests/helpers/intl-test-helper';
describe('components/MessageExportSettings', () => {
test('should match snapshot, disabled, actiance', () => {
const config = {
@ -18,7 +19,7 @@ describe('components/MessageExportSettings', () => {
},
};
const wrapper = shallow(
const wrapper = shallowWithIntl(
<MessageExportSettings
config={config}
/>,
@ -49,7 +50,7 @@ describe('components/MessageExportSettings', () => {
},
};
const wrapper = shallow(
const wrapper = shallowWithIntl(
<MessageExportSettings
config={config}
/>,
@ -88,7 +89,7 @@ describe('components/MessageExportSettings', () => {
},
};
const wrapper = shallow(
const wrapper = shallowWithIntl(
<MessageExportSettings
config={config}
/>,
@ -134,7 +135,7 @@ describe('components/MessageExportSettings', () => {
},
};
const wrapper = shallow(
const wrapper = shallowWithIntl(
<MessageExportSettings
config={config}
/>,
@ -175,7 +176,7 @@ describe('components/MessageExportSettings/getJobDetails', () => {
},
};
const wrapper = shallow(<MessageExportSettings {...baseProps}/>);
const wrapper = shallowWithIntl(<MessageExportSettings {...baseProps}/>);
function runTest(testJob, expectNull, expectedCount) {
const jobDetails = wrapper.instance().getJobDetails(testJob);

View File

@ -3,7 +3,8 @@
import React from 'react';
import type {ReactNode} from 'react';
import {FormattedMessage} from 'react-intl';
import type {MessageDescriptor, WrappedComponentProps} from 'react-intl';
import {FormattedMessage, defineMessage, defineMessages, injectIntl} from 'react-intl';
import type {AdminConfig} from '@mattermost/types/config';
import type {Job} from '@mattermost/types/jobs';
@ -13,7 +14,6 @@ import FormattedMarkdownMessage from 'components/formatted_markdown_message';
import {DocLinks, JobTypes, exportFormats} from 'utils/constants';
import {getSiteURL} from 'utils/url';
import * as Utils from 'utils/utils';
import type {BaseProps, BaseState} from './admin_settings';
import AdminSettings from './admin_settings';
@ -37,7 +37,45 @@ interface State extends BaseState {
globalRelaySMTPServerTimeout: AdminConfig['MessageExportSettings']['GlobalRelaySettings']['SMTPServerTimeout'];
}
export default class MessageExportSettings extends AdminSettings<BaseProps, State> {
const messages = defineMessages({
globalRelayCustomerType_title: {id: 'admin.complianceExport.globalRelayCustomerType.title', defaultMessage: 'Customer Type:'},
globalRelayCustomerType_description: {id: 'admin.complianceExport.globalRelayCustomerType.description', defaultMessage: 'The type of GlobalRelay customer account that your organization has.'},
globalRelaySMTPUsername_title: {id: 'admin.complianceExport.globalRelaySMTPUsername.title', defaultMessage: 'SMTP Username:'},
globalRelaySMTPUsername_description: {id: 'admin.complianceExport.globalRelaySMTPUsername.description', defaultMessage: 'The username that is used to authenticate against the GlobalRelay SMTP server.'},
globalRelaySMTPPassword_title: {id: 'admin.complianceExport.globalRelaySMTPPassword.title', defaultMessage: 'SMTP Password:'},
globalRelaySMTPPassword_description: {id: 'admin.complianceExport.globalRelaySMTPPassword.description', defaultMessage: 'The password that is used to authenticate against the GlobalRelay SMTP server.'},
globalRelayEmailAddress_title: {id: 'admin.complianceExport.globalRelayEmailAddress.title', defaultMessage: 'Email Address:'},
globalRelayEmailAddress_description: {id: 'admin.complianceExport.globalRelayEmailAddress.description', defaultMessage: 'The email address that your GlobalRelay server monitors for incoming Compliance Exports.'},
complianceExportTitle: {id: 'admin.service.complianceExportTitle', defaultMessage: 'Enable Compliance Export:'},
complianceExportDesc: {id: 'admin.service.complianceExportDesc', defaultMessage: 'When true, Mattermost will export all messages that were posted in the last 24 hours. The export task is scheduled to run once per day. See <link>the documentation</link> to learn more.'},
exportJobStartTime_title: {id: 'admin.complianceExport.exportJobStartTime.title', defaultMessage: 'Compliance Export Time:'},
exportJobStartTime_description: {id: 'admin.complianceExport.exportJobStartTime.description', defaultMessage: 'Set the start time of the daily scheduled compliance export job. Choose a time when fewer people are using your system. Must be a 24-hour time stamp in the form HH:MM.'},
exportFormat_title: {id: 'admin.complianceExport.exportFormat.title', defaultMessage: 'Export Format:'},
exportFormat_description: {id: 'admin.complianceExport.exportFormat.description', defaultMessage: 'Format of the compliance export. Corresponds to the system that you want to import the data into.{lineBreak} {lineBreak}For Actiance XML, compliance export files are written to the exports subdirectory of the configured [Local Storage Directory]({url}). For Global Relay EML, they are emailed to the configured email address.'},
createJob_title: {id: 'admin.complianceExport.createJob.title', defaultMessage: 'Run Compliance Export Job Now'},
createJob_help: {id: 'admin.complianceExport.createJob.help', defaultMessage: 'Initiates a Compliance Export job immediately.'},
});
export const searchableStrings: Array<string|MessageDescriptor|[MessageDescriptor, {[key: string]: any}]> = [
[messages.exportFormat_description, {siteURL: ''}],
messages.complianceExportTitle,
messages.complianceExportDesc,
messages.exportJobStartTime_title,
messages.exportJobStartTime_description,
messages.exportFormat_title,
messages.createJob_title,
messages.createJob_help,
messages.globalRelayCustomerType_title,
messages.globalRelayCustomerType_description,
messages.globalRelaySMTPUsername_title,
messages.globalRelaySMTPUsername_description,
messages.globalRelaySMTPPassword_title,
messages.globalRelaySMTPPassword_description,
messages.globalRelayEmailAddress_title,
messages.globalRelayEmailAddress_description,
];
class MessageExportSettings extends AdminSettings<BaseProps & WrappedComponentProps, State> {
getConfigFromState = (config: AdminConfig) => {
config.MessageExportSettings.EnableExport = this.state.enableComplianceExport;
config.MessageExportSettings.ExportFormat = this.state.exportFormat;
@ -142,9 +180,9 @@ export default class MessageExportSettings extends AdminSettings<BaseProps, Stat
renderSettings = () => {
const exportFormatOptions = [
{value: exportFormats.EXPORT_FORMAT_ACTIANCE, text: Utils.localizeMessage('admin.complianceExport.exportFormat.actiance', 'Actiance XML')},
{value: exportFormats.EXPORT_FORMAT_CSV, text: Utils.localizeMessage('admin.complianceExport.exportFormat.csv', 'CSV')},
{value: exportFormats.EXPORT_FORMAT_GLOBALRELAY, text: Utils.localizeMessage('admin.complianceExport.exportFormat.globalrelay', 'GlobalRelay EML')},
{value: exportFormats.EXPORT_FORMAT_ACTIANCE, text: this.props.intl.formatMessage({id: 'admin.complianceExport.exportFormat.actiance', defaultMessage: 'Actiance XML'})},
{value: exportFormats.EXPORT_FORMAT_CSV, text: this.props.intl.formatMessage({id: 'admin.complianceExport.exportFormat.csv', defaultMessage: 'CSV'})},
{value: exportFormats.EXPORT_FORMAT_GLOBALRELAY, text: this.props.intl.formatMessage({id: 'admin.complianceExport.exportFormat.globalrelay', defaultMessage: 'GlobalRelay EML'})},
];
// if the export format is globalrelay, the user needs to set some additional parameters
@ -154,22 +192,12 @@ export default class MessageExportSettings extends AdminSettings<BaseProps, Stat
<RadioSetting
id='globalRelayCustomerType'
values={[
{value: 'A9', text: Utils.localizeMessage('admin.complianceExport.globalRelayCustomerType.a9.description', 'A9/Type 9')},
{value: 'A10', text: Utils.localizeMessage('admin.complianceExport.globalRelayCustomerType.a10.description', 'A10/Type 10')},
{value: 'CUSTOM', text: Utils.localizeMessage('admin.complianceExport.globalRelayCustomerType.custom.description', 'Custom')},
{value: 'A9', text: this.props.intl.formatMessage({id: 'admin.complianceExport.globalRelayCustomerType.a9.description', defaultMessage: 'A9/Type 9'})},
{value: 'A10', text: this.props.intl.formatMessage({id: 'admin.complianceExport.globalRelayCustomerType.a10.description', defaultMessage: 'A10/Type 10'})},
{value: 'CUSTOM', text: this.props.intl.formatMessage({id: 'admin.complianceExport.globalRelayCustomerType.custom.description', defaultMessage: 'Custom'})},
]}
label={
<FormattedMessage
id='admin.complianceExport.globalRelayCustomerType.title'
defaultMessage='Customer Type:'
/>
}
helpText={
<FormattedMessage
id='admin.complianceExport.globalRelayCustomerType.description'
defaultMessage='The type of GlobalRelay customer account that your organization has.'
/>
}
label={<FormattedMessage {...messages.globalRelayCustomerType_title}/>}
helpText={<FormattedMessage {...messages.globalRelayCustomerType_description}/>}
value={this.state.globalRelayCustomerType ? this.state.globalRelayCustomerType : ''}
onChange={this.handleChange}
setByEnv={this.isSetByEnv('DataRetentionSettings.GlobalRelaySettings.CustomerType')}
@ -180,19 +208,9 @@ export default class MessageExportSettings extends AdminSettings<BaseProps, Stat
const globalRelaySMTPUsername = (
<TextSetting
id='globalRelaySMTPUsername'
label={
<FormattedMessage
id='admin.complianceExport.globalRelaySMTPUsername.title'
defaultMessage='SMTP Username:'
/>
}
placeholder={Utils.localizeMessage('admin.complianceExport.globalRelaySMTPUsername.example', 'E.g.: "globalRelayUser"')}
helpText={
<FormattedMessage
id='admin.complianceExport.globalRelaySMTPUsername.description'
defaultMessage='The username that is used to authenticate against the GlobalRelay SMTP server.'
/>
}
label={<FormattedMessage {...messages.globalRelaySMTPUsername_title}/>}
placeholder={defineMessage({id: 'admin.complianceExport.globalRelaySMTPUsername.example', defaultMessage: 'E.g.: "globalRelayUser"'})}
helpText={<FormattedMessage {...messages.globalRelaySMTPUsername_description}/>}
value={this.state.globalRelaySMTPUsername ? this.state.globalRelaySMTPUsername : ''}
onChange={this.handleChange}
setByEnv={this.isSetByEnv('DataRetentionSettings.GlobalRelaySettings.SMTPUsername')}
@ -203,19 +221,9 @@ export default class MessageExportSettings extends AdminSettings<BaseProps, Stat
const globalRelaySMTPPassword = (
<TextSetting
id='globalRelaySMTPPassword'
label={
<FormattedMessage
id='admin.complianceExport.globalRelaySMTPPassword.title'
defaultMessage='SMTP Password:'
/>
}
placeholder={Utils.localizeMessage('admin.complianceExport.globalRelaySMTPPassword.example', 'E.g.: "globalRelayPassword"')}
helpText={
<FormattedMessage
id='admin.complianceExport.globalRelaySMTPPassword.description'
defaultMessage='The password that is used to authenticate against the GlobalRelay SMTP server.'
/>
}
label={<FormattedMessage {...messages.globalRelaySMTPPassword_title}/>}
placeholder={defineMessage({id: 'admin.complianceExport.globalRelaySMTPPassword.example', defaultMessage: 'E.g.: "globalRelayPassword"'})}
helpText={<FormattedMessage {...messages.globalRelaySMTPPassword_description}/>}
value={this.state.globalRelaySMTPPassword ? this.state.globalRelaySMTPPassword : ''}
onChange={this.handleChange}
setByEnv={this.isSetByEnv('DataRetentionSettings.GlobalRelaySettings.SMTPPassword')}
@ -226,19 +234,9 @@ export default class MessageExportSettings extends AdminSettings<BaseProps, Stat
const globalRelayEmail = (
<TextSetting
id='globalRelayEmailAddress'
label={
<FormattedMessage
id='admin.complianceExport.globalRelayEmailAddress.title'
defaultMessage='Email Address:'
/>
}
placeholder={Utils.localizeMessage('admin.complianceExport.globalRelayEmailAddress.example', 'E.g.: "globalrelay@mattermost.com"')}
helpText={
<FormattedMessage
id='admin.complianceExport.globalRelayEmailAddress.description'
defaultMessage='The email address that your GlobalRelay server monitors for incoming Compliance Exports.'
/>
}
label={<FormattedMessage {...messages.globalRelayEmailAddress_title}/>}
placeholder={defineMessage({id: 'admin.complianceExport.globalRelayEmailAddress.example', defaultMessage: 'E.g.: "globalrelay@mattermost.com"'})}
helpText={<FormattedMessage {...messages.globalRelayEmailAddress_description}/>}
value={this.state.globalRelayEmailAddress ? this.state.globalRelayEmailAddress : ''}
onChange={this.handleChange}
setByEnv={this.isSetByEnv('DataRetentionSettings.GlobalRelaySettings.EmailAddress')}
@ -255,7 +253,7 @@ export default class MessageExportSettings extends AdminSettings<BaseProps, Stat
defaultMessage='SMTP Server Name:'
/>
}
placeholder={Utils.localizeMessage('admin.complianceExport.globalRelayCustomSMTPServerName.example', 'E.g.: "feeds.globalrelay.com"')}
placeholder={defineMessage({id: 'admin.complianceExport.globalRelayCustomSMTPServerName.example', defaultMessage: 'E.g.: "feeds.globalrelay.com"'})}
helpText={
<FormattedMessage
id='admin.complianceExport.globalRelayCustomSMTPServerName.description'
@ -278,7 +276,7 @@ export default class MessageExportSettings extends AdminSettings<BaseProps, Stat
defaultMessage='SMTP Server Port:'
/>
}
placeholder={Utils.localizeMessage('admin.complianceExport.globalRelayCustomSMTPPort.example', 'E.g.: "25"')}
placeholder={defineMessage({id: 'admin.complianceExport.globalRelayCustomSMTPPort.example', defaultMessage: 'E.g.: "25"'})}
helpText={
<FormattedMessage
id='admin.complianceExport.globalRelayCustomSMTPPort.description'
@ -312,9 +310,11 @@ export default class MessageExportSettings extends AdminSettings<BaseProps, Stat
const dropdownHelpText = (
<FormattedMarkdownMessage
id='admin.complianceExport.exportFormat.description'
defaultMessage='Format of the compliance export. Corresponds to the system that you want to import the data into.\n \nFor Actiance XML, compliance export files are written to the \"exports\" subdirectory of the configured [Local Storage Directory]({siteURL}/admin_console/environment/file_storage). For Global Relay EML, they are emailed to the configured email address.'
values={{siteURL: getSiteURL()}}
{...messages.exportFormat_description}
values={{
url: `${getSiteURL()}/admin_console/environment/file_storage`,
lineBreak: '\n',
}}
/>
);
@ -322,16 +322,10 @@ export default class MessageExportSettings extends AdminSettings<BaseProps, Stat
<SettingsGroup>
<BooleanSetting
id='enableComplianceExport'
label={
<FormattedMessage
id='admin.service.complianceExportTitle'
defaultMessage='Enable Compliance Export:'
/>
}
label={<FormattedMessage {...messages.complianceExportTitle}/>}
helpText={
<FormattedMessage
id='admin.service.complianceExportDesc'
defaultMessage='When true, Mattermost will export all messages that were posted in the last 24 hours. The export task is scheduled to run once per day. See <link>the documentation</link> to learn more.'
{...messages.complianceExportDesc}
values={{
link: (msg: ReactNode) => (
<ExternalLink
@ -352,19 +346,9 @@ export default class MessageExportSettings extends AdminSettings<BaseProps, Stat
<TextSetting
id='exportJobStartTime'
label={
<FormattedMessage
id='admin.complianceExport.exportJobStartTime.title'
defaultMessage='Compliance Export Time:'
/>
}
placeholder={Utils.localizeMessage('admin.complianceExport.exportJobStartTime.example', 'E.g.: "02:00"')}
helpText={
<FormattedMessage
id='admin.complianceExport.exportJobStartTime.description'
defaultMessage='Set the start time of the daily scheduled compliance export job. Choose a time when fewer people are using your system. Must be a 24-hour time stamp in the form HH:MM.'
/>
}
label={<FormattedMessage {...messages.exportJobStartTime_title}/>}
placeholder={defineMessage({id: 'admin.complianceExport.exportJobStartTime.example', defaultMessage: 'E.g.: "02:00"'})}
helpText={<FormattedMessage {...messages.exportJobStartTime_description}/>}
value={this.state.exportJobStartTime}
onChange={this.handleChange}
setByEnv={this.isSetByEnv('DataRetentionSettings.DailyRunTime')}
@ -374,12 +358,7 @@ export default class MessageExportSettings extends AdminSettings<BaseProps, Stat
<DropdownSetting
id='exportFormat'
values={exportFormatOptions}
label={
<FormattedMessage
id='admin.complianceExport.exportFormat.title'
defaultMessage='Export Format:'
/>
}
label={<FormattedMessage {...messages.exportFormat_title}/>}
helpText={dropdownHelpText}
value={this.state.exportFormat}
onChange={this.handleChange}
@ -391,18 +370,8 @@ export default class MessageExportSettings extends AdminSettings<BaseProps, Stat
<JobsTable
jobType={JobTypes.MESSAGE_EXPORT}
createJobButtonText={
<FormattedMessage
id='admin.complianceExport.createJob.title'
defaultMessage='Run Compliance Export Job Now'
/>
}
createJobHelpText={
<FormattedMessage
id='admin.complianceExport.createJob.help'
defaultMessage='Initiates a Compliance Export job immediately.'
/>
}
createJobButtonText={<FormattedMessage {...messages.createJob_title}/>}
createJobHelpText={<FormattedMessage {...messages.createJob_help}/>}
getExtraInfoText={this.getJobDetails}
disabled={this.props.isDisabled || !this.state.enableComplianceExport}
/>
@ -410,3 +379,5 @@ export default class MessageExportSettings extends AdminSettings<BaseProps, Stat
);
};
}
export default injectIntl(MessageExportSettings);

View File

@ -2,14 +2,13 @@
// See LICENSE.txt for license information.
import React from 'react';
import {FormattedMessage} from 'react-intl';
import type {MessageDescriptor} from 'react-intl';
import {FormattedMessage, defineMessage, defineMessages} from 'react-intl';
import type {AdminConfig} from '@mattermost/types/config';
import type {DeepPartial} from '@mattermost/types/utilities';
import Constants from 'utils/constants';
import {t} from 'utils/i18n';
import * as Utils from 'utils/utils';
import AdminSettings from './admin_settings';
import type {BaseProps, BaseState} from './admin_settings';
@ -33,6 +32,75 @@ type State = BaseState & {
maximumLoginAttempts?: string;
};
const messages = defineMessages({
passwordMinLength: {id: 'user.settings.security.passwordMinLength', defaultMessage: 'Invalid minimum length, cannot show preview.'},
password: {id: 'admin.security.password', defaultMessage: 'Password'},
minimumLength: {id: 'admin.password.minimumLength', defaultMessage: 'Minimum Password Length:'},
minimumLengthDescription: {id: 'admin.password.minimumLengthDescription', defaultMessage: 'Minimum number of characters required for a valid password. Must be a whole number greater than or equal to {min} and less than or equal to {max}.'},
lowercase: {id: 'admin.password.lowercase', defaultMessage: 'At least one lowercase letter'},
uppercase: {id: 'admin.password.uppercase', defaultMessage: 'At least one uppercase letter'},
number: {id: 'admin.password.number', defaultMessage: 'At least one number'},
symbol: {id: 'admin.password.symbol', defaultMessage: 'At least one symbol (e.g. "~!@#$%^&*()")'},
preview: {id: 'admin.password.preview', defaultMessage: 'Error message preview:'},
attemptTitle: {id: 'admin.service.attemptTitle', defaultMessage: 'Maximum Login Attempts:'},
attemptDescription: {id: 'admin.service.attemptDescription', defaultMessage: 'Login attempts allowed before user is locked out and required to reset password via email.'},
passwordRequirements: {id: 'passwordRequirements', defaultMessage: 'Password Requirements:'},
});
export const searchableStrings: Array<string|MessageDescriptor|[MessageDescriptor, {[key: string]: any}]> = [
[messages.minimumLength, {max: '', min: ''}],
[messages.minimumLengthDescription, {max: '', min: ''}],
messages.passwordMinLength,
messages.password,
messages.passwordRequirements,
messages.lowercase,
messages.uppercase,
messages.number,
messages.symbol,
messages.preview,
messages.attemptTitle,
messages.attemptDescription,
];
const passwordErrors = defineMessages({
passwordError: {id: 'user.settings.security.passwordError', defaultMessage: 'Must be {min}-{max} characters long.'},
passwordErrorLowercase: {id: 'user.settings.security.passwordErrorLowercase', defaultMessage: 'Must be {min}-{max} characters long and include lowercase letters.'},
passwordErrorLowercaseNumber: {id: 'user.settings.security.passwordErrorLowercaseNumber', defaultMessage: 'Must be {min}-{max} characters long and include lowercase letters and numbers.'},
passwordErrorLowercaseNumberSymbol: {id: 'user.settings.security.passwordErrorLowercaseNumberSymbol', defaultMessage: 'Must be {min}-{max} characters long and include lowercase letters, numbers, and special characters.'},
passwordErrorLowercaseSymbol: {id: 'user.settings.security.passwordErrorLowercaseSymbol', defaultMessage: 'Must be {min}-{max} characters long and include lowercase letters and special characters.'},
passwordErrorLowercaseUppercase: {id: 'user.settings.security.passwordErrorLowercaseUppercase', defaultMessage: 'Must be {min}-{max} characters long and include both lowercase and uppercase letters.'},
passwordErrorLowercaseUppercaseNumber: {id: 'user.settings.security.passwordErrorLowercaseUppercaseNumber', defaultMessage: 'Must be {min}-{max} characters long and include both lowercase and uppercase letters, and numbers.'},
passwordErrorLowercaseUppercaseNumberSymbol: {id: 'user.settings.security.passwordErrorLowercaseUppercaseNumberSymbol', defaultMessage: 'Must be {min}-{max} characters long and include both lowercase and uppercase letters, numbers, and special characters.'},
passwordErrorLowercaseUppercaseSymbol: {id: 'user.settings.security.passwordErrorLowercaseUppercaseSymbol', defaultMessage: 'Must be {min}-{max} characters long and include both lowercase and uppercase letters, and special characters.'},
passwordErrorNumber: {id: 'user.settings.security.passwordErrorNumber', defaultMessage: 'Must be {min}-{max} characters long and include numbers.'},
passwordErrorNumberSymbol: {id: 'user.settings.security.passwordErrorNumberSymbol', defaultMessage: 'Must be {min}-{max} characters long and include numbers and special characters.'},
passwordErrorSymbol: {id: 'user.settings.security.passwordErrorSymbol', defaultMessage: 'Must be {min}-{max} characters long and include special characters.'},
passwordErrorUppercase: {id: 'user.settings.security.passwordErrorUppercase', defaultMessage: 'Must be {min}-{max} characters long and include uppercase letters.'},
passwordErrorUppercaseNumber: {id: 'user.settings.security.passwordErrorUppercaseNumber', defaultMessage: 'Must be {min}-{max} characters long and include uppercase letters, and numbers.'},
passwordErrorUppercaseNumberSymbol: {id: 'user.settings.security.passwordErrorUppercaseNumberSymbol', defaultMessage: 'Must be {min}-{max} characters long and include uppercase letters, numbers, and special characters.'},
passwordErrorUppercaseSymbol: {id: 'user.settings.security.passwordErrorUppercaseSymbol', defaultMessage: 'Must be {min}-{max} characters long and include uppercase letters, and special characters.'},
});
function getPasswordErrorsMessage(lowercase?: boolean, uppercase?: boolean, number?: boolean, symbol?: boolean) {
type KeyType = keyof typeof passwordErrors;
let key: KeyType = 'passwordError';
if (lowercase) {
key += 'Lowercase';
}
if (uppercase) {
key += 'Uppercase';
}
if (number) {
key += 'Number';
}
if (symbol) {
key += 'Symbol';
}
return passwordErrors[key as KeyType];
}
export default class PasswordSettings extends AdminSettings<Props, State> {
sampleErrorMsg: React.ReactNode;
@ -49,40 +117,14 @@ export default class PasswordSettings extends AdminSettings<Props, State> {
maximumLoginAttempts: props.config.ServiceSettings.MaximumLoginAttempts,
});
// Update sample message from config settings
t('user.settings.security.passwordErrorLowercase');
t('user.settings.security.passwordErrorLowercaseUppercase');
t('user.settings.security.passwordErrorLowercaseUppercaseNumber');
t('user.settings.security.passwordErrorLowercaseUppercaseNumberSymbol');
t('user.settings.security.passwordErrorLowercaseUppercaseSymbol');
t('user.settings.security.passwordErrorLowercaseNumber');
t('user.settings.security.passwordErrorLowercaseNumberSymbol');
t('user.settings.security.passwordErrorLowercaseSymbol');
t('user.settings.security.passwordErrorUppercase');
t('user.settings.security.passwordErrorUppercaseNumber');
t('user.settings.security.passwordErrorUppercaseNumberSymbol');
t('user.settings.security.passwordErrorUppercaseSymbol');
t('user.settings.security.passwordErrorNumber');
t('user.settings.security.passwordErrorNumberSymbol');
t('user.settings.security.passwordErrorSymbol');
let sampleErrorMsgId = 'user.settings.security.passwordError';
if (props.config.PasswordSettings.Lowercase) {
sampleErrorMsgId += 'Lowercase';
}
if (props.config.PasswordSettings.Uppercase) {
sampleErrorMsgId += 'Uppercase';
}
if (props.config.PasswordSettings.Number) {
sampleErrorMsgId += 'Number';
}
if (props.config.PasswordSettings.Symbol) {
sampleErrorMsgId += 'Symbol';
}
this.sampleErrorMsg = (
<FormattedMessage
id={sampleErrorMsgId}
defaultMessage='Your password must contain between {min} and {max} characters.'
{...getPasswordErrorsMessage(
props.config.PasswordSettings.Lowercase,
props.config.PasswordSettings.Uppercase,
props.config.PasswordSettings.Number,
props.config.PasswordSettings.Symbol,
)}
values={{
min: (this.state.passwordMinimumLength || Constants.MIN_PASSWORD_LENGTH),
max: Constants.MAX_PASSWORD_LENGTH,
@ -122,30 +164,16 @@ export default class PasswordSettings extends AdminSettings<Props, State> {
getSampleErrorMsg = () => {
if (this.props.config.PasswordSettings.MinimumLength > Constants.MAX_PASSWORD_LENGTH || this.props.config.PasswordSettings.MinimumLength < Constants.MIN_PASSWORD_LENGTH) {
return (
<FormattedMessage
id='user.settings.security.passwordMinLength'
defaultMessage='Invalid minimum length, cannot show preview.'
/>
);
}
let sampleErrorMsgId = 'user.settings.security.passwordError';
if (this.state.passwordLowercase) {
sampleErrorMsgId += 'Lowercase';
}
if (this.state.passwordUppercase) {
sampleErrorMsgId += 'Uppercase';
}
if (this.state.passwordNumber) {
sampleErrorMsgId += 'Number';
}
if (this.state.passwordSymbol) {
sampleErrorMsgId += 'Symbol';
return (<FormattedMessage {...messages.passwordMinLength}/>);
}
return (
<FormattedMessage
id={sampleErrorMsgId}
defaultMessage='Your password must contain between {min} and {max} characters.'
{...getPasswordErrorsMessage(
this.state.passwordLowercase,
this.state.passwordUppercase,
this.state.passwordNumber,
this.state.passwordSymbol,
)}
values={{
min: (this.state.passwordMinimumLength || Constants.MIN_PASSWORD_LENGTH),
max: Constants.MAX_PASSWORD_LENGTH,
@ -162,10 +190,7 @@ export default class PasswordSettings extends AdminSettings<Props, State> {
renderTitle() {
return (
<FormattedMessage
id='admin.security.password'
defaultMessage='Password'
/>
<FormattedMessage {...messages.password}/>
);
}
@ -175,17 +200,11 @@ export default class PasswordSettings extends AdminSettings<Props, State> {
<div>
<TextSetting
id='passwordMinimumLength'
label={
<FormattedMessage
id='admin.password.minimumLength'
defaultMessage='Minimum Password Length:'
/>
}
placeholder={Utils.localizeMessage('admin.password.minimumLengthExample', 'E.g.: "5"')}
label={<FormattedMessage {...messages.minimumLength}/>}
placeholder={defineMessage({id: 'admin.password.minimumLengthExample', defaultMessage: 'E.g.: "5"'})}
helpText={
<FormattedMessage
id='admin.password.minimumLengthDescription'
defaultMessage='Minimum number of characters required for a valid password. Must be a whole number greater than or equal to {min} and less than or equal to {max}.'
{...messages.minimumLengthDescription}
values={{
min: Constants.MIN_PASSWORD_LENGTH,
max: Constants.MAX_PASSWORD_LENGTH,
@ -198,12 +217,7 @@ export default class PasswordSettings extends AdminSettings<Props, State> {
disabled={this.props.isDisabled}
/>
<Setting
label={
<FormattedMessage
id='passwordRequirements'
defaultMessage='Password Requirements:'
/>
}
label={<FormattedMessage {...messages.passwordRequirements}/>}
>
<div>
<label className='checkbox-inline'>
@ -214,10 +228,7 @@ export default class PasswordSettings extends AdminSettings<Props, State> {
disabled={this.props.isDisabled}
onChange={this.handleCheckboxChange('passwordLowercase')}
/>
<FormattedMessage
id='admin.password.lowercase'
defaultMessage='At least one lowercase letter'
/>
<FormattedMessage {...messages.lowercase}/>
</label>
</div>
<div>
@ -229,10 +240,7 @@ export default class PasswordSettings extends AdminSettings<Props, State> {
disabled={this.props.isDisabled}
onChange={this.handleCheckboxChange('passwordUppercase')}
/>
<FormattedMessage
id='admin.password.uppercase'
defaultMessage='At least one uppercase letter'
/>
<FormattedMessage {...messages.uppercase}/>
</label>
</div>
<div>
@ -244,10 +252,7 @@ export default class PasswordSettings extends AdminSettings<Props, State> {
disabled={this.props.isDisabled}
onChange={this.handleCheckboxChange('passwordNumber')}
/>
<FormattedMessage
id='admin.password.number'
defaultMessage='At least one number'
/>
<FormattedMessage {...messages.number}/>
</label>
</div>
<div>
@ -259,19 +264,13 @@ export default class PasswordSettings extends AdminSettings<Props, State> {
disabled={this.props.isDisabled}
onChange={this.handleCheckboxChange('passwordSymbol')}
/>
<FormattedMessage
id='admin.password.symbol'
defaultMessage='At least one symbol (e.g. "~!@#$%^&*()")'
/>
<FormattedMessage {...messages.symbol}/>
</label>
</div>
<div>
<br/>
<label>
<FormattedMessage
id='admin.password.preview'
defaultMessage='Error message preview:'
/>
<FormattedMessage {...messages.preview}/>
</label>
<br/>
{this.getSampleErrorMsg()}
@ -283,17 +282,11 @@ export default class PasswordSettings extends AdminSettings<Props, State> {
<TextSetting
id='maximumLoginAttempts'
label={
<FormattedMessage
id='admin.service.attemptTitle'
defaultMessage='Maximum Login Attempts:'
/>
<FormattedMessage {...messages.attemptTitle}/>
}
placeholder={Utils.localizeMessage('admin.service.attemptExample', 'E.g.: "10"')}
placeholder={defineMessage({id: 'admin.service.attemptExample', defaultMessage: 'E.g.: "10"'})}
helpText={
<FormattedMessage
id='admin.service.attemptDescription'
defaultMessage='Login attempts allowed before user is locked out and required to reset password via email.'
/>
<FormattedMessage {...messages.attemptDescription}/>
}
value={this.state.maximumLoginAttempts ?? ''}
onChange={this.handleChange}

View File

@ -20,13 +20,11 @@ exports[`components/admin_console/permission_schemes_settings/permission_group s
<span
className="permission-name"
>
<MemoizedFormattedMessage
id="admin.permissions.group.name.name"
/>
name
</span>
<PermissionDescription
description=""
id="name"
rowType="group"
selectRow={[MockFunction]}
/>
</div>
@ -75,13 +73,11 @@ exports[`components/admin_console/permission_schemes_settings/permission_group s
<span
className="permission-name"
>
<MemoizedFormattedMessage
id="admin.permissions.group.name.name"
/>
name
</span>
<PermissionDescription
description=""
id="name"
rowType="group"
selectRow={[MockFunction]}
/>
</div>
@ -130,13 +126,11 @@ exports[`components/admin_console/permission_schemes_settings/permission_group s
<span
className="permission-name"
>
<MemoizedFormattedMessage
id="admin.permissions.group.name.name"
/>
name
</span>
<PermissionDescription
description=""
id="name"
rowType="group"
selectRow={[MockFunction]}
/>
</div>
@ -185,13 +179,11 @@ exports[`components/admin_console/permission_schemes_settings/permission_group s
<span
className="permission-name"
>
<MemoizedFormattedMessage
id="admin.permissions.group.name.name"
/>
name
</span>
<PermissionDescription
description=""
id="name"
rowType="group"
selectRow={[MockFunction]}
/>
</div>
@ -240,13 +232,11 @@ exports[`components/admin_console/permission_schemes_settings/permission_group s
<span
className="permission-name"
>
<MemoizedFormattedMessage
id="admin.permissions.group.name.name"
/>
name
</span>
<PermissionDescription
description=""
id="name"
rowType="group"
selectRow={[MockFunction]}
/>
</div>
@ -297,13 +287,11 @@ exports[`components/admin_console/permission_schemes_settings/permission_group s
<span
className="permission-name"
>
<MemoizedFormattedMessage
id="admin.permissions.group.name.name"
/>
name
</span>
<PermissionDescription
description=""
id="name"
rowType="group"
selectRow={[MockFunction]}
/>
</div>
@ -370,13 +358,11 @@ exports[`components/admin_console/permission_schemes_settings/permission_group s
<span
className="permission-name"
>
<MemoizedFormattedMessage
id="admin.permissions.group.name.name"
/>
name
</span>
<PermissionDescription
description=""
id="name"
rowType="group"
selectRow={[MockFunction]}
/>
</div>
@ -425,13 +411,11 @@ exports[`components/admin_console/permission_schemes_settings/permission_group s
<span
className="permission-name"
>
<MemoizedFormattedMessage
id="admin.permissions.group.name.name"
/>
name
</span>
<PermissionDescription
description=""
id="name"
rowType="group"
selectRow={[MockFunction]}
/>
</div>
@ -482,13 +466,11 @@ exports[`components/admin_console/permission_schemes_settings/permission_group s
<span
className="permission-name"
>
<MemoizedFormattedMessage
id="admin.permissions.group.name.name"
/>
name
</span>
<PermissionDescription
description=""
id="name"
rowType="group"
selectRow={[MockFunction]}
/>
</div>
@ -546,13 +528,11 @@ exports[`components/admin_console/permission_schemes_settings/permission_group s
<span
className="permission-name"
>
<MemoizedFormattedMessage
id="admin.permissions.group.name.name"
/>
name
</span>
<PermissionDescription
description=""
id="name"
rowType="group"
selectRow={[MockFunction]}
/>
</div>
@ -601,13 +581,11 @@ exports[`components/admin_console/permission_schemes_settings/permission_group s
<span
className="permission-name"
>
<MemoizedFormattedMessage
id="admin.permissions.group.name.name"
/>
name
</span>
<PermissionDescription
description=""
id="name"
rowType="group"
selectRow={[MockFunction]}
/>
</div>
@ -656,13 +634,11 @@ exports[`components/admin_console/permission_schemes_settings/permission_group s
<span
className="permission-name"
>
<MemoizedFormattedMessage
id="admin.permissions.group.name.name"
/>
name
</span>
<PermissionDescription
description=""
id="name"
rowType="group"
selectRow={[MockFunction]}
/>
</div>

View File

@ -13,19 +13,17 @@ exports[`components/admin_console/permission_schemes_settings/permission_row sho
<span
className="permission-name"
>
<MemoizedFormattedMessage
id="admin.permissions.permission.id.name"
/>
id
</span>
<PermissionDescription
additionalValues={Object {}}
description=""
id="id"
inherited={
Object {
"name": "test",
}
}
rowType="permission"
selectRow={[MockFunction]}
/>
</div>
@ -44,14 +42,12 @@ exports[`components/admin_console/permission_schemes_settings/permission_row sho
<span
className="permission-name"
>
<MemoizedFormattedMessage
id="admin.permissions.permission.id.name"
/>
id
</span>
<PermissionDescription
additionalValues={Object {}}
description=""
id="id"
rowType="permission"
selectRow={[MockFunction]}
/>
</div>
@ -70,14 +66,12 @@ exports[`components/admin_console/permission_schemes_settings/permission_row sho
<span
className="permission-name"
>
<MemoizedFormattedMessage
id="admin.permissions.permission.id.name"
/>
id
</span>
<PermissionDescription
additionalValues={Object {}}
description=""
id="id"
rowType="permission"
selectRow={[MockFunction]}
/>
</div>
@ -96,14 +90,12 @@ exports[`components/admin_console/permission_schemes_settings/permission_row sho
<span
className="permission-name"
>
<MemoizedFormattedMessage
id="admin.permissions.permission.id.name"
/>
id
</span>
<PermissionDescription
additionalValues={Object {}}
description=""
id="id"
rowType="permission"
selectRow={[MockFunction]}
/>
</div>

View File

@ -38,36 +38,59 @@ exports[`components/admin_console/permission_schemes_settings/permission_schemes
</div>
</div>
<AdminPanelWithLink
className=""
disabled={false}
id="systemScheme"
linkTextDefault="Edit Scheme"
linkTextId="admin.permissions.systemSchemeBannerButton"
subtitleDefault="Set the default permissions inherited by all teams unless a <link>Team Override Scheme</link> is applied."
subtitleId="admin.permissions.systemSchemeBannerText"
linkText={
Object {
"defaultMessage": "Edit Scheme",
"id": "admin.permissions.systemSchemeBannerButton",
}
}
subtitle={
Object {
"defaultMessage": "Set the default permissions inherited by all teams unless a <link>Team Override Scheme</link> is applied.",
"id": "admin.permissions.systemSchemeBannerText",
}
}
subtitleValues={
Object {
"link": [Function],
}
}
titleDefault="System Scheme"
titleId="admin.permissions.systemSchemeBannerTitle"
title={
Object {
"defaultMessage": "System Scheme",
"id": "admin.permissions.systemSchemeBannerTitle",
}
}
url="/admin_console/user_management/permissions/system_scheme"
/>
<AdminPanelWithLink
className="permissions-block"
id="team-override-schemes"
linkTextDefault="New Team Override Scheme"
linkTextId="admin.permissions.teamOverrideSchemesNewButton"
subtitleDefault="Use when specific teams need permission exceptions to the <link>System Scheme</link>"
subtitleId="admin.permissions.teamOverrideSchemesBannerText"
linkText={
Object {
"defaultMessage": "New Team Override Scheme",
"id": "admin.permissions.teamOverrideSchemesNewButton",
}
}
subtitle={
Object {
"defaultMessage": "Use when specific teams need permission exceptions to the <link>System Scheme</link>",
"id": "admin.permissions.teamOverrideSchemesBannerText",
}
}
subtitleValues={
Object {
"link": [Function],
}
}
titleDefault="Team Override Schemes"
titleId="admin.permissions.teamOverrideSchemesTitle"
title={
Object {
"defaultMessage": "Team Override Schemes",
"id": "admin.permissions.teamOverrideSchemesTitle",
}
}
url="/admin_console/user_management/permissions/team_override_scheme"
>
<Connect(PermissionsSchemeSummary)
@ -142,36 +165,59 @@ exports[`components/admin_console/permission_schemes_settings/permission_schemes
</div>
</div>
<AdminPanelWithLink
className=""
disabled={false}
id="systemScheme"
linkTextDefault="Edit Scheme"
linkTextId="admin.permissions.systemSchemeBannerButton"
subtitleDefault="Set the default permissions inherited by all teams unless a <link>Team Override Scheme</link> is applied."
subtitleId="admin.permissions.systemSchemeBannerText"
linkText={
Object {
"defaultMessage": "Edit Scheme",
"id": "admin.permissions.systemSchemeBannerButton",
}
}
subtitle={
Object {
"defaultMessage": "Set the default permissions inherited by all teams unless a <link>Team Override Scheme</link> is applied.",
"id": "admin.permissions.systemSchemeBannerText",
}
}
subtitleValues={
Object {
"link": [Function],
}
}
titleDefault="System Scheme"
titleId="admin.permissions.systemSchemeBannerTitle"
title={
Object {
"defaultMessage": "System Scheme",
"id": "admin.permissions.systemSchemeBannerTitle",
}
}
url="/admin_console/user_management/permissions/system_scheme"
/>
<AdminPanelWithLink
className="permissions-block"
id="team-override-schemes"
linkTextDefault="New Team Override Scheme"
linkTextId="admin.permissions.teamOverrideSchemesNewButton"
subtitleDefault="Use when specific teams need permission exceptions to the <link>System Scheme</link>"
subtitleId="admin.permissions.teamOverrideSchemesBannerText"
linkText={
Object {
"defaultMessage": "New Team Override Scheme",
"id": "admin.permissions.teamOverrideSchemesNewButton",
}
}
subtitle={
Object {
"defaultMessage": "Use when specific teams need permission exceptions to the <link>System Scheme</link>",
"id": "admin.permissions.teamOverrideSchemesBannerText",
}
}
subtitleValues={
Object {
"link": [Function],
}
}
titleDefault="Team Override Schemes"
titleId="admin.permissions.teamOverrideSchemesTitle"
title={
Object {
"defaultMessage": "Team Override Schemes",
"id": "admin.permissions.teamOverrideSchemesTitle",
}
}
url="/admin_console/user_management/permissions/team_override_scheme"
>
<div
@ -224,37 +270,60 @@ exports[`components/admin_console/permission_schemes_settings/permission_schemes
</div>
</div>
<AdminPanelWithLink
className=""
disabled={true}
id="systemScheme"
linkTextDefault="Edit Scheme"
linkTextId="admin.permissions.systemSchemeBannerButton"
subtitleDefault="Set the default permissions inherited by all teams unless a <link>Team Override Scheme</link> is applied."
subtitleId="admin.permissions.systemSchemeBannerText"
linkText={
Object {
"defaultMessage": "Edit Scheme",
"id": "admin.permissions.systemSchemeBannerButton",
}
}
subtitle={
Object {
"defaultMessage": "Set the default permissions inherited by all teams unless a <link>Team Override Scheme</link> is applied.",
"id": "admin.permissions.systemSchemeBannerText",
}
}
subtitleValues={
Object {
"link": [Function],
}
}
titleDefault="System Scheme"
titleId="admin.permissions.systemSchemeBannerTitle"
title={
Object {
"defaultMessage": "System Scheme",
"id": "admin.permissions.systemSchemeBannerTitle",
}
}
url="/admin_console/user_management/permissions/system_scheme"
/>
<AdminPanelWithLink
className="permissions-block"
disabled={true}
id="team-override-schemes"
linkTextDefault="New Team Override Scheme"
linkTextId="admin.permissions.teamOverrideSchemesNewButton"
subtitleDefault="Use when specific teams need permission exceptions to the <link>System Scheme</link>"
subtitleId="admin.permissions.teamOverrideSchemesBannerText"
linkText={
Object {
"defaultMessage": "New Team Override Scheme",
"id": "admin.permissions.teamOverrideSchemesNewButton",
}
}
subtitle={
Object {
"defaultMessage": "Use when specific teams need permission exceptions to the <link>System Scheme</link>",
"id": "admin.permissions.teamOverrideSchemesBannerText",
}
}
subtitleValues={
Object {
"link": [Function],
}
}
titleDefault="Team Override Schemes"
titleId="admin.permissions.teamOverrideSchemesTitle"
title={
Object {
"defaultMessage": "Team Override Schemes",
"id": "admin.permissions.teamOverrideSchemesTitle",
}
}
url="/admin_console/user_management/permissions/team_override_scheme"
>
<div
@ -264,19 +333,11 @@ exports[`components/admin_console/permission_schemes_settings/permission_schemes
className="team-override-unavailable__inner"
>
<MemoizedFormattedMessage
defaultMessage="Migration job in progress: Team Override Schemes are not available until the job server completes the permissions migration. Learn more in the {documentationLink}."
defaultMessage="Migration job in progress: Team Override Schemes are not available until the job server completes the permissions migration. Learn more in the <link>documentation</link>."
id="admin.permissions.teamOverrideSchemesInProgress"
values={
Object {
"documentationLink": <ExternalLink
href="https://docs.mattermost.com/administration/config-settings.html#jobs"
location="permission_scheme_settings"
>
<Memo(MemoizedFormattedMessage)
defaultMessage="documentation"
id="admin.permissions.documentationLinkText"
/>
</ExternalLink>,
"link": [Function],
}
}
/>
@ -354,37 +415,60 @@ exports[`components/admin_console/permission_schemes_settings/permission_schemes
</div>
</div>
<AdminPanelWithLink
className=""
disabled={true}
id="systemScheme"
linkTextDefault="Edit Scheme"
linkTextId="admin.permissions.systemSchemeBannerButton"
subtitleDefault="Set the default permissions inherited by all teams unless a <link>Team Override Scheme</link> is applied."
subtitleId="admin.permissions.systemSchemeBannerText"
linkText={
Object {
"defaultMessage": "Edit Scheme",
"id": "admin.permissions.systemSchemeBannerButton",
}
}
subtitle={
Object {
"defaultMessage": "Set the default permissions inherited by all teams unless a <link>Team Override Scheme</link> is applied.",
"id": "admin.permissions.systemSchemeBannerText",
}
}
subtitleValues={
Object {
"link": [Function],
}
}
titleDefault="System Scheme"
titleId="admin.permissions.systemSchemeBannerTitle"
title={
Object {
"defaultMessage": "System Scheme",
"id": "admin.permissions.systemSchemeBannerTitle",
}
}
url="/admin_console/user_management/permissions/system_scheme"
/>
<AdminPanelWithLink
className="permissions-block"
disabled={true}
id="team-override-schemes"
linkTextDefault="New Team Override Scheme"
linkTextId="admin.permissions.teamOverrideSchemesNewButton"
subtitleDefault="Use when specific teams need permission exceptions to the <link>System Scheme</link>"
subtitleId="admin.permissions.teamOverrideSchemesBannerText"
linkText={
Object {
"defaultMessage": "New Team Override Scheme",
"id": "admin.permissions.teamOverrideSchemesNewButton",
}
}
subtitle={
Object {
"defaultMessage": "Use when specific teams need permission exceptions to the <link>System Scheme</link>",
"id": "admin.permissions.teamOverrideSchemesBannerText",
}
}
subtitleValues={
Object {
"link": [Function],
}
}
titleDefault="Team Override Schemes"
titleId="admin.permissions.teamOverrideSchemesTitle"
title={
Object {
"defaultMessage": "Team Override Schemes",
"id": "admin.permissions.teamOverrideSchemesTitle",
}
}
url="/admin_console/user_management/permissions/team_override_scheme"
>
<div
@ -394,19 +478,11 @@ exports[`components/admin_console/permission_schemes_settings/permission_schemes
className="team-override-unavailable__inner"
>
<MemoizedFormattedMessage
defaultMessage="Migration job on hold: Team Override Schemes are not available until the job server can execute the permissions migration. The job will be automatically started when the job server is enabled. Learn more in the {documentationLink}."
defaultMessage="Migration job on hold: Team Override Schemes are not available until the job server can execute the permissions migration. The job will be automatically started when the job server is enabled. Learn more in the <link>documentation</link>."
id="admin.permissions.teamOverrideSchemesNoJobsEnabled"
values={
Object {
"documentationLink": <ExternalLink
href="https://docs.mattermost.com/administration/config-settings.html#jobs"
location="permission_scheme_settings"
>
<Memo(MemoizedFormattedMessage)
defaultMessage="documentation"
id="admin.permissions.documentationLinkText"
/>
</ExternalLink>,
"link": [Function],
}
}
/>
@ -484,36 +560,59 @@ exports[`components/admin_console/permission_schemes_settings/permission_schemes
</div>
</div>
<AdminPanelWithLink
className=""
disabled={false}
id="systemScheme"
linkTextDefault="Edit Scheme"
linkTextId="admin.permissions.systemSchemeBannerButton"
subtitleDefault="Set the default permissions inherited by all teams unless a <link>Team Override Scheme</link> is applied."
subtitleId="admin.permissions.systemSchemeBannerText"
linkText={
Object {
"defaultMessage": "Edit Scheme",
"id": "admin.permissions.systemSchemeBannerButton",
}
}
subtitle={
Object {
"defaultMessage": "Set the default permissions inherited by all teams unless a <link>Team Override Scheme</link> is applied.",
"id": "admin.permissions.systemSchemeBannerText",
}
}
subtitleValues={
Object {
"link": [Function],
}
}
titleDefault="System Scheme"
titleId="admin.permissions.systemSchemeBannerTitle"
title={
Object {
"defaultMessage": "System Scheme",
"id": "admin.permissions.systemSchemeBannerTitle",
}
}
url="/admin_console/user_management/permissions/system_scheme"
/>
<AdminPanelWithLink
className="permissions-block"
id="team-override-schemes"
linkTextDefault="New Team Override Scheme"
linkTextId="admin.permissions.teamOverrideSchemesNewButton"
subtitleDefault="Use when specific teams need permission exceptions to the <link>System Scheme</link>"
subtitleId="admin.permissions.teamOverrideSchemesBannerText"
linkText={
Object {
"defaultMessage": "New Team Override Scheme",
"id": "admin.permissions.teamOverrideSchemesNewButton",
}
}
subtitle={
Object {
"defaultMessage": "Use when specific teams need permission exceptions to the <link>System Scheme</link>",
"id": "admin.permissions.teamOverrideSchemesBannerText",
}
}
subtitleValues={
Object {
"link": [Function],
}
}
titleDefault="Team Override Schemes"
titleId="admin.permissions.teamOverrideSchemesTitle"
title={
Object {
"defaultMessage": "Team Override Schemes",
"id": "admin.permissions.teamOverrideSchemesTitle",
}
}
url="/admin_console/user_management/permissions/team_override_scheme"
>
<Connect(PermissionsSchemeSummary)

View File

@ -4,7 +4,7 @@
import React, {useState, useRef} from 'react';
import type {MouseEvent} from 'react';
import {Overlay} from 'react-bootstrap';
import {FormattedMessage, useIntl} from 'react-intl';
import {useIntl} from 'react-intl';
import type {Role} from '@mattermost/types/roles';
@ -14,16 +14,23 @@ import Tooltip from 'components/tooltip';
import {generateId} from 'utils/utils';
import type {AdditionalValues} from './permissions_tree/types';
import {rolesRolesStrings} from './strings/roles';
type Props = {
id: string;
rowType: string;
inherited?: Partial<Role>;
selectRow: (id: string) => void;
additionalValues?: AdditionalValues | AdditionalValues['edit_post'];
description: string | JSX.Element;
}
const PermissionDescription = (props: Props): JSX.Element => {
const PermissionDescription = ({
id,
selectRow,
description,
additionalValues,
inherited,
}: Props): JSX.Element => {
const [open, setOpen] = useState(false);
const randomId = generateId();
const contentRef = useRef<HTMLSpanElement>(null);
@ -43,35 +50,24 @@ const PermissionDescription = (props: Props): JSX.Element => {
if (parent?.className !== 'permission-description' && !isInheritLink) {
e.stopPropagation();
} else if (isInheritLink) {
props.selectRow(props.id);
selectRow(id);
e.stopPropagation();
}
};
const {inherited, id, rowType} = props;
let content: string | JSX.Element = '';
if (inherited) {
if (inherited && inherited.name) {
content = (
<span className='inherit-link-wrapper'>
<FormattedMarkdownMessage
id='admin.permissions.inherited_from'
values={{
name: intl.formatMessage({
id: 'admin.permissions.roles.' + inherited.name + '.name',
defaultMessage: inherited.display_name,
}),
}}
defaultMessage='Inherited from [{name}]().'
values={{name: intl.formatMessage(rolesRolesStrings[inherited.name])}}
/>
</span>
);
} else {
content = (
<FormattedMessage
id={'admin.permissions.' + rowType + '.' + id + '.description'}
values={props.additionalValues}
/>
);
content = description;
}
let tooltip: JSX.Element | null = (
<Overlay
@ -84,7 +80,7 @@ const PermissionDescription = (props: Props): JSX.Element => {
</Tooltip>
</Overlay>
);
if (content.props.values && Object.keys(content.props.values).length > 0) {
if (!inherited && additionalValues) {
tooltip = null;
}
content = (

View File

@ -13,6 +13,7 @@ import PermissionCheckbox from './permission_checkbox';
import PermissionDescription from './permission_description';
import PermissionRow from './permission_row';
import type {AdditionalValues, Permission, Permissions} from './permissions_tree/types';
import {groupRolesStrings} from './strings/groups';
type Props = {
id: string;
@ -280,6 +281,9 @@ export default class PermissionGroup extends React.PureComponent<Props, State> {
}
const additionalValuesProp = additionalValues?.[id] ? additionalValues[id] : undefined;
const name = groupRolesStrings[id] ? <FormattedMessage {...groupRolesStrings[id].name}/> : id;
const description = groupRolesStrings[id] ? <FormattedMessage {...groupRolesStrings[id].description}/> : '';
return (
<div className='permission-group'>
{!root &&
@ -298,14 +302,14 @@ export default class PermissionGroup extends React.PureComponent<Props, State> {
id={`${uniqId}-checkbox`}
/>
<span className='permission-name'>
<FormattedMessage id={'admin.permissions.group.' + id + '.name'}/>
{name}
</span>
<PermissionDescription
additionalValues={additionalValuesProp}
inherited={inherited}
id={id}
selectRow={this.props.selectRow}
rowType='group'
description={description}
/>
</div>}
{!combined &&

View File

@ -1,7 +1,8 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import classNames from 'classnames';
import React, {useCallback} from 'react';
import {FormattedMessage} from 'react-intl';
import type {Role} from '@mattermost/types/roles';
@ -9,6 +10,7 @@ import type {Role} from '@mattermost/types/roles';
import PermissionCheckbox from './permission_checkbox';
import PermissionDescription from './permission_description';
import type {AdditionalValues} from './permissions_tree/types';
import {permissionRolesStrings} from './strings/permissions';
type Props = {
id: string;
@ -22,27 +24,30 @@ type Props = {
additionalValues: AdditionalValues;
}
const PermissionRow = (props: Props): JSX.Element => {
const toggleSelect = (): void => {
if (props.readOnly) {
const PermissionRow = ({
additionalValues,
id,
onChange,
selectRow,
uniqId,
value,
inherited,
readOnly,
selected,
}: Props) => {
const toggleSelect = useCallback(() => {
if (readOnly) {
return;
}
props.onChange(props.id);
};
onChange(id);
}, [readOnly, onChange, id]);
const {id, uniqId, inherited, value, readOnly, selected, additionalValues} = props;
let classes = 'permission-row';
if (readOnly) {
classes += ' read-only';
}
if (selected === id) {
classes += ' selected';
}
const name = permissionRolesStrings[id] ? <FormattedMessage {...permissionRolesStrings[id].name}/> : id;
const description = permissionRolesStrings[id] ? <FormattedMessage {...permissionRolesStrings[id].description}/> : '';
return (
<div
className={classes}
className={classNames('permission-row', {'read-only': readOnly, selected: selected === id})}
onClick={toggleSelect}
id={uniqId}
>
@ -51,15 +56,13 @@ const PermissionRow = (props: Props): JSX.Element => {
id={`${uniqId}-checkbox`}
/>
<span className='permission-name'>
<FormattedMessage
id={'admin.permissions.permission.' + id + '.name'}
/>
{name}
</span>
<PermissionDescription
inherited={inherited}
id={id}
selectRow={props.selectRow}
rowType='permission'
selectRow={selectRow}
description={description}
additionalValues={additionalValues}
/>
</div>

View File

@ -1,7 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {shallow} from 'enzyme';
import React from 'react';
import type {ComponentProps} from 'react';
import type {RouteComponentProps} from 'react-router-dom';
@ -10,6 +9,8 @@ import type {Scheme} from '@mattermost/types/schemes';
import PermissionSchemesSettings from 'components/admin_console/permission_schemes_settings/permission_schemes_settings';
import {shallowWithIntl} from 'tests/helpers/intl-test-helper';
describe('components/admin_console/permission_schemes_settings/permission_schemes_settings', () => {
const defaultProps: ComponentProps<typeof PermissionSchemesSettings> = {
schemes: {
@ -31,14 +32,14 @@ describe('components/admin_console/permission_schemes_settings/permission_scheme
};
test('should match snapshot loading', () => {
const wrapper = shallow(
const wrapper = shallowWithIntl(
<PermissionSchemesSettings {...defaultProps}/>,
);
expect(wrapper).toMatchSnapshot();
});
test('should match snapshot without schemes', () => {
const wrapper = shallow(
const wrapper = shallowWithIntl(
<PermissionSchemesSettings
{...defaultProps}
schemes={{}}
@ -49,7 +50,7 @@ describe('components/admin_console/permission_schemes_settings/permission_scheme
});
test('should match snapshot with schemes', () => {
const wrapper = shallow(
const wrapper = shallowWithIntl(
<PermissionSchemesSettings {...defaultProps}/>,
);
wrapper.setState({loading: false, phase2MigrationIsComplete: true});
@ -57,7 +58,7 @@ describe('components/admin_console/permission_schemes_settings/permission_scheme
});
test('should show migration in-progress view', () => {
const wrapper = shallow(
const wrapper = shallowWithIntl(
<PermissionSchemesSettings {...defaultProps}/>,
);
wrapper.setState({loading: false, phase2MigrationIsComplete: false});
@ -67,7 +68,7 @@ describe('components/admin_console/permission_schemes_settings/permission_scheme
test('should show migration on hold view', () => {
const testProps = {...defaultProps};
testProps.jobsAreEnabled = false;
const wrapper = shallow(
const wrapper = shallowWithIntl(
<PermissionSchemesSettings {...testProps}/>,
);
wrapper.setState({loading: false, phase2MigrationIsComplete: false});
@ -77,7 +78,7 @@ describe('components/admin_console/permission_schemes_settings/permission_scheme
test('should show normal view (jobs disabled after migration)', () => {
const testProps = {...defaultProps};
testProps.jobsAreEnabled = false;
const wrapper = shallow(
const wrapper = shallowWithIntl(
<PermissionSchemesSettings {...testProps}/>,
);
wrapper.setState({loading: false, phase2MigrationIsComplete: true});

View File

@ -2,7 +2,8 @@
// See LICENSE.txt for license information.
import React from 'react';
import {FormattedMessage} from 'react-intl';
import {injectIntl, type MessageDescriptor, type WrappedComponentProps} from 'react-intl';
import {FormattedMessage, defineMessage, defineMessages} from 'react-intl';
import type {RouteComponentProps} from 'react-router-dom';
import type {Scheme, SchemeScope, SchemesState} from '@mattermost/types/schemes';
@ -16,8 +17,6 @@ import AdminPanelWithLink from 'components/widgets/admin_console/admin_panel_wit
import LoadingWrapper from 'components/widgets/loading/loading_wrapper';
import {DocLinks, LicenseSkus} from 'utils/constants';
import {t} from 'utils/i18n';
import * as Utils from 'utils/utils';
import PermissionsSchemeSummary from './permissions_scheme_summary';
@ -37,7 +36,7 @@ export type Props = {
loadSchemeTeams: (id: string) => Promise<ActionResult>;
};
isDisabled?: boolean;
};
} & WrappedComponentProps;
type State = {
loading: boolean;
@ -45,7 +44,32 @@ type State = {
page: number;
phase2MigrationIsComplete: boolean;
};
export default class PermissionSchemesSettings extends React.PureComponent<Props & RouteComponentProps, State> {
const messages = defineMessages({
teamOverrideSchemesNoSchemes: {id: 'admin.permissions.teamOverrideSchemesNoSchemes', defaultMessage: 'No team override schemes created.'},
loadMoreSchemes: {id: 'admin.permissions.loadMoreSchemes', defaultMessage: 'Load more schemes'},
introBanner: {id: 'admin.permissions.introBanner', defaultMessage: 'Permission Schemes set the default permissions for Team Admins, Channel Admins and everyone else. Learn more about permission schemes in our <link>documentation</link>.'},
systemSchemeBannerTitle: {id: 'admin.permissions.systemSchemeBannerTitle', defaultMessage: 'System Scheme'},
systemSchemeBannerText: {id: 'admin.permissions.systemSchemeBannerText', defaultMessage: 'Set the default permissions inherited by all teams unless a <link>Team Override Scheme</link> is applied.'},
systemSchemeBannerButton: {id: 'admin.permissions.systemSchemeBannerButton', defaultMessage: 'Edit Scheme'},
teamOverrideSchemesTitle: {id: 'admin.permissions.teamOverrideSchemesTitle', defaultMessage: 'Team Override Schemes'},
teamOverrideSchemesBannerText: {id: 'admin.permissions.teamOverrideSchemesBannerText', defaultMessage: 'Use when specific teams need permission exceptions to the <link>System Scheme</link>'},
teamOverrideSchemesNewButton: {id: 'admin.permissions.teamOverrideSchemesNewButton', defaultMessage: 'New Team Override Scheme'},
});
export const searchableStrings = [
messages.teamOverrideSchemesNoSchemes,
messages.loadMoreSchemes,
messages.introBanner,
messages.systemSchemeBannerTitle,
messages.systemSchemeBannerText,
messages.systemSchemeBannerButton,
messages.teamOverrideSchemesTitle,
messages.teamOverrideSchemesBannerText,
messages.teamOverrideSchemesNewButton,
];
class PermissionSchemesSettings extends React.PureComponent<Props & RouteComponentProps, State> {
constructor(props: Props & RouteComponentProps) {
super(props);
this.state = {
@ -98,41 +122,39 @@ export default class PermissionSchemesSettings extends React.PureComponent<Props
return null;
}
const docLink = (
<ExternalLink
href='https://docs.mattermost.com/administration/config-settings.html#jobs'
location='permission_scheme_settings'
>
<FormattedMessage
id='admin.permissions.documentationLinkText'
defaultMessage='documentation'
/>
</ExternalLink>
);
if (this.props.jobsAreEnabled && !this.props.clusterIsEnabled) {
return this.teamOverrideUnavalableView(
t('admin.permissions.teamOverrideSchemesInProgress'),
'Migration job in progress: Team Override Schemes are not available until the job server completes the permissions migration. Learn more in the {documentationLink}.',
docLink,
defineMessage({
id: 'admin.permissions.teamOverrideSchemesInProgress',
defaultMessage: 'Migration job in progress: Team Override Schemes are not available until the job server completes the permissions migration. Learn more in the <link>documentation</link>.',
}),
);
}
return this.teamOverrideUnavalableView(
t('admin.permissions.teamOverrideSchemesNoJobsEnabled'),
'Migration job on hold: Team Override Schemes are not available until the job server can execute the permissions migration. The job will be automatically started when the job server is enabled. Learn more in the {documentationLink}.',
docLink,
defineMessage({
id: 'admin.permissions.teamOverrideSchemesNoJobsEnabled',
defaultMessage: 'Migration job on hold: Team Override Schemes are not available until the job server can execute the permissions migration. The job will be automatically started when the job server is enabled. Learn more in the <link>documentation</link>.',
}),
);
};
teamOverrideUnavalableView = (id: string, defaultMsg: string, documentationLink: React.ReactNode) => {
teamOverrideUnavalableView = (message: MessageDescriptor) => {
return (
<div className='team-override-unavailable'>
<div className='team-override-unavailable__inner'>
<FormattedMessage
id={id}
defaultMessage={defaultMsg}
values={{documentationLink}}
{...message}
values={{
link: (chunks) => (
<ExternalLink
href='https://docs.mattermost.com/administration/config-settings.html#jobs'
location='permission_scheme_settings'
>
{chunks}
</ExternalLink>
),
}}
/>
</div>
</div>
@ -158,10 +180,8 @@ export default class PermissionSchemesSettings extends React.PureComponent<Props
<AdminPanelWithLink
id='team-override-schemes'
className='permissions-block'
titleId={t('admin.permissions.teamOverrideSchemesTitle')}
titleDefault='Team Override Schemes'
subtitleId={t('admin.permissions.teamOverrideSchemesBannerText')}
subtitleDefault='Use when specific teams need permission exceptions to the <link>System Scheme</link>'
title={messages.teamOverrideSchemesTitle}
subtitle={messages.teamOverrideSchemesBannerText}
subtitleValues={{
link: (msg: React.ReactNode) => (
<ExternalLink
@ -174,14 +194,12 @@ export default class PermissionSchemesSettings extends React.PureComponent<Props
}}
url='/admin_console/user_management/permissions/team_override_scheme'
disabled={(teamOverrideView !== null) || this.props.isDisabled}
linkTextId={t('admin.permissions.teamOverrideSchemesNewButton')}
linkTextDefault='New Team Override Scheme'
linkText={messages.teamOverrideSchemesNewButton}
>
{schemes.length === 0 && teamOverrideView === null &&
<div className='no-team-schemes'>
<FormattedMessage
id='admin.permissions.teamOverrideSchemesNoSchemes'
defaultMessage='No team override schemes created.'
{...messages.teamOverrideSchemesNoSchemes}
/>
</div>}
{teamOverrideView}
@ -195,12 +213,9 @@ export default class PermissionSchemesSettings extends React.PureComponent<Props
>
<LoadingWrapper
loading={this.state.loadingMore}
text={Utils.localizeMessage('admin.permissions.loadingMoreSchemes', 'Loading...')}
text={this.props.intl.formatMessage({id: 'admin.permissions.loadingMoreSchemes', defaultMessage: 'Loading...'})}
>
<FormattedMessage
id='admin.permissions.loadMoreSchemes'
defaultMessage='Load more schemes'
/>
<FormattedMessage {...messages.loadMoreSchemes}/>
</LoadingWrapper>
</button>}
</AdminPanelWithLink>
@ -230,8 +245,7 @@ export default class PermissionSchemesSettings extends React.PureComponent<Props
<div className='banner__content'>
<span>
<FormattedMessage
id='admin.permissions.introBanner'
defaultMessage='Permission Schemes set the default permissions for Team Admins, Channel Admins and everyone else. Learn more about permission schemes in our <link>documentation</link>.'
{...messages.introBanner}
values={{
link: (msg: React.ReactNode) => (
<ExternalLink
@ -249,10 +263,8 @@ export default class PermissionSchemesSettings extends React.PureComponent<Props
<AdminPanelWithLink
id='systemScheme'
titleId={t('admin.permissions.systemSchemeBannerTitle')}
titleDefault='System Scheme'
subtitleId={t('admin.permissions.systemSchemeBannerText')}
subtitleDefault='Set the default permissions inherited by all teams unless a <link>Team Override Scheme</link> is applied.'
title={messages.systemSchemeBannerTitle}
subtitle={messages.systemSchemeBannerText}
subtitleValues={{
link: (msg: React.ReactNode) => (
<ExternalLink
@ -265,8 +277,7 @@ export default class PermissionSchemesSettings extends React.PureComponent<Props
}}
url='/admin_console/user_management/permissions/system_scheme'
disabled={teamOverrideView !== null}
linkTextId={t('admin.permissions.systemSchemeBannerButton')}
linkTextDefault='Edit Scheme'
linkText={messages.systemSchemeBannerButton}
/>
{this.renderTeamOverrideSchemes()}
@ -277,182 +288,4 @@ export default class PermissionSchemesSettings extends React.PureComponent<Props
};
}
t('admin.permissions.group.delete_posts.description');
t('admin.permissions.group.delete_posts.name');
t('admin.permissions.group.integrations.description');
t('admin.permissions.group.integrations.name');
t('admin.permissions.group.posts.description');
t('admin.permissions.group.posts.name');
t('admin.permissions.group.private_channel.description');
t('admin.permissions.group.private_channel.name');
t('admin.permissions.group.public_channel.description');
t('admin.permissions.group.public_channel.name');
t('admin.permissions.group.reactions.description');
t('admin.permissions.group.reactions.name');
t('admin.permissions.group.send_invites.description');
t('admin.permissions.group.send_invites.name');
t('admin.permissions.group.teams.description');
t('admin.permissions.group.teams.name');
t('admin.permissions.group.edit_posts.description');
t('admin.permissions.group.edit_posts.name');
t('admin.permissions.group.teams_team_scope.description');
t('admin.permissions.group.teams_team_scope.name');
t('admin.permissions.permission.assign_system_admin_role.description');
t('admin.permissions.permission.assign_system_admin_role.name');
t('admin.permissions.permission.convert_public_channel_to_private.description');
t('admin.permissions.permission.convert_public_channel_to_private.name');
t('admin.permissions.permission.convert_private_channel_to_public.description');
t('admin.permissions.permission.convert_private_channel_to_public.name');
t('admin.permissions.permission.create_direct_channel.description');
t('admin.permissions.permission.create_direct_channel.name');
t('admin.permissions.permission.create_group_channel.description');
t('admin.permissions.permission.create_group_channel.name');
t('admin.permissions.permission.create_post.description');
t('admin.permissions.permission.create_post.name');
t('admin.permissions.permission.create_private_channel.description');
t('admin.permissions.permission.create_private_channel.name');
t('admin.permissions.permission.create_public_channel.description');
t('admin.permissions.permission.create_public_channel.name');
t('admin.permissions.permission.create_team.description');
t('admin.permissions.permission.create_team.name');
t('admin.permissions.permission.create_user_access_token.description');
t('admin.permissions.permission.create_user_access_token.name');
t('admin.permissions.permission.delete_others_posts.description');
t('admin.permissions.permission.delete_others_posts.name');
t('admin.permissions.permission.delete_post.description');
t('admin.permissions.permission.delete_post.name');
t('admin.permissions.permission.delete_private_channel.description');
t('admin.permissions.permission.delete_private_channel.name');
t('admin.permissions.permission.delete_public_channel.description');
t('admin.permissions.permission.delete_public_channel.name');
t('admin.permissions.permission.edit_other_users.description');
t('admin.permissions.permission.edit_other_users.name');
t('admin.permissions.permission.edit_post.description');
t('admin.permissions.group.guest_reactions.description');
t('admin.permissions.group.guest_reactions.name');
t('admin.permissions.group.guest_create_post.description');
t('admin.permissions.group.guest_create_post.name');
t('admin.permissions.group.guest_create_private_channel.description');
t('admin.permissions.group.guest_create_private_channel.name');
t('admin.permissions.group.guest_delete_post.description');
t('admin.permissions.group.guest_delete_post.name');
t('admin.permissions.group.guest_edit_post.description');
t('admin.permissions.group.guest_edit_post.name');
t('admin.permissions.group.guest_use_channel_mentions.description');
t('admin.permissions.group.guest_use_channel_mentions.name');
t('admin.permissions.group.guest_use_group_mentions.description');
t('admin.permissions.group.guest_use_group_mentions.name');
t('admin.permissions.permission.edit_post.name');
t('admin.permissions.permission.import_team.description');
t('admin.permissions.permission.import_team.name');
t('admin.permissions.permission.list_team_channels.description');
t('admin.permissions.permission.list_team_channels.name');
t('admin.permissions.permission.list_users_without_team.description');
t('admin.permissions.permission.list_users_without_team.name');
t('admin.permissions.permission.manage_channel_roles.description');
t('admin.permissions.permission.manage_channel_roles.name');
t('admin.permissions.permission.create_emojis.description');
t('admin.permissions.permission.create_emojis.name');
t('admin.permissions.permission.delete_emojis.description');
t('admin.permissions.permission.delete_emojis.name');
t('admin.permissions.permission.delete_others_emojis.description');
t('admin.permissions.permission.delete_others_emojis.name');
t('admin.permissions.permission.manage_jobs.description');
t('admin.permissions.permission.manage_jobs.name');
t('admin.permissions.permission.manage_oauth.description');
t('admin.permissions.permission.manage_oauth.name');
t('admin.permissions.group.manage_private_channel_members_and_read_groups.description');
t('admin.permissions.group.manage_private_channel_members_and_read_groups.name');
t('admin.permissions.permission.manage_private_channel_properties.description');
t('admin.permissions.permission.manage_private_channel_properties.name');
t('admin.permissions.group.manage_public_channel_members_and_read_groups.description');
t('admin.permissions.group.manage_public_channel_members_and_read_groups.name');
t('admin.permissions.group.convert_public_channel_to_private.description');
t('admin.permissions.group.convert_public_channel_to_private.name');
t('admin.permissions.permission.manage_public_channel_properties.description');
t('admin.permissions.permission.manage_public_channel_properties.name');
t('admin.permissions.permission.manage_roles.description');
t('admin.permissions.permission.manage_roles.name');
t('admin.permissions.permission.manage_slash_commands.description');
t('admin.permissions.permission.manage_slash_commands.name');
t('admin.permissions.permission.manage_system.description');
t('admin.permissions.permission.manage_system.name');
t('admin.permissions.permission.manage_team.description');
t('admin.permissions.permission.manage_team.name');
t('admin.permissions.permission.manage_team_roles.description');
t('admin.permissions.permission.manage_team_roles.name');
t('admin.permissions.permission.manage_incoming_webhooks.description');
t('admin.permissions.permission.manage_incoming_webhooks.name');
t('admin.permissions.permission.manage_outgoing_webhooks.description');
t('admin.permissions.permission.manage_outgoing_webhooks.name');
t('admin.permissions.permission.permanent_delete_user.description');
t('admin.permissions.permission.permanent_delete_user.name');
t('admin.permissions.permission.read_channel.description');
t('admin.permissions.permission.read_channel.name');
t('admin.permissions.permission.read_user_access_token.description');
t('admin.permissions.permission.read_user_access_token.name');
t('admin.permissions.permission.remove_user_from_team.description');
t('admin.permissions.permission.remove_user_from_team.name');
t('admin.permissions.permission.revoke_user_access_token.description');
t('admin.permissions.permission.revoke_user_access_token.name');
t('admin.permissions.permission.upload_file.description');
t('admin.permissions.permission.upload_file.name');
t('admin.permissions.permission.use_channel_mentions.description');
t('admin.permissions.permission.use_channel_mentions.name');
t('admin.permissions.permission.use_group_mentions.description');
t('admin.permissions.permission.use_group_mentions.name');
t('admin.permissions.permission.view_team.description');
t('admin.permissions.permission.view_team.name');
t('admin.permissions.permission.edit_others_posts.description');
t('admin.permissions.permission.edit_others_posts.name');
t('admin.permissions.permission.invite_guest.name');
t('admin.permissions.permission.invite_guest.description');
t('admin.permissions.roles.all_users.name');
t('admin.permissions.roles.channel_admin.name');
t('admin.permissions.roles.channel_user.name');
t('admin.permissions.roles.system_admin.name');
t('admin.permissions.roles.system_user.name');
t('admin.permissions.roles.team_admin.name');
t('admin.permissions.roles.team_user.name');
t('admin.permissions.group.manage_shared_channels.name');
t('admin.permissions.group.manage_shared_channels.description');
t('admin.permissions.permission.manage_shared_channels.name');
t('admin.permissions.permission.manage_shared_channels.description');
t('admin.permissions.permission.manage_secure_connections.name');
t('admin.permissions.permission.manage_secure_connections.description');
t('admin.permissions.group.playbook_public.name');
t('admin.permissions.group.playbook_public.description');
t('admin.permissions.permission.playbook_public_create.name');
t('admin.permissions.permission.playbook_public_create.description');
t('admin.permissions.permission.playbook_public_manage_properties.name');
t('admin.permissions.permission.playbook_public_manage_properties.description');
t('admin.permissions.permission.playbook_public_manage_members.name');
t('admin.permissions.permission.playbook_public_manage_members.description');
t('admin.permissions.permission.playbook_public_make_private.name');
t('admin.permissions.permission.playbook_public_make_private.description');
t('admin.permissions.group.playbook_private.name');
t('admin.permissions.group.playbook_private.description');
t('admin.permissions.permission.playbook_private_create.name');
t('admin.permissions.permission.playbook_private_create.description');
t('admin.permissions.permission.playbook_private_manage_properties.name');
t('admin.permissions.permission.playbook_private_manage_properties.description');
t('admin.permissions.permission.playbook_private_manage_members.name');
t('admin.permissions.permission.playbook_private_manage_members.description');
t('admin.permissions.permission.playbook_private_make_public.name');
t('admin.permissions.permission.playbook_private_make_public.description');
t('admin.permissions.group.runs.name');
t('admin.permissions.group.runs.description');
t('admin.permissions.permission.run_create.name');
t('admin.permissions.permission.run_create.description');
t('admin.permissions.group.custom_groups.name');
t('admin.permissions.group.custom_groups.description');
t('admin.permissions.permission.create_custom_group.name');
t('admin.permissions.permission.create_custom_group.description');
t('admin.permissions.permission.manage_custom_group_members.name');
t('admin.permissions.permission.manage_custom_group_members.description');
t('admin.permissions.permission.delete_custom_group.name');
t('admin.permissions.permission.delete_custom_group.description');
t('admin.permissions.permission.restore_custom_group.name');
t('admin.permissions.permission.restore_custom_group.description');
t('admin.permissions.permission.edit_custom_group.name');
t('admin.permissions.permission.edit_custom_group.description');
export default injectIntl(PermissionSchemesSettings);

View File

@ -191,10 +191,18 @@ exports[`components/admin_console/permission_schemes_settings/permission_system_
id="all_users"
onToggle={[Function]}
open={true}
subtitleDefault="Permissions granted to guest users."
subtitleId="admin.permissions.systemScheme.GuestsDescription"
titleDefault="Guests"
titleId="admin.permissions.systemScheme.GuestsTitle"
subtitle={
Object {
"defaultMessage": "Permissions granted to guest users.",
"id": "admin.permissions.systemScheme.GuestsDescription",
}
}
title={
Object {
"defaultMessage": "Guests",
"id": "admin.permissions.systemScheme.GuestsTitle",
}
}
>
<Connect(GuestPermissionsTree)
onToggle={[Function]}
@ -215,10 +223,18 @@ exports[`components/admin_console/permission_schemes_settings/permission_system_
id="all_users"
onToggle={[Function]}
open={true}
subtitleDefault="Permissions granted to all members, including administrators and newly created users."
subtitleId="admin.permissions.systemScheme.allMembersDescription"
titleDefault="All Members"
titleId="admin.permissions.systemScheme.allMembersTitle"
subtitle={
Object {
"defaultMessage": "Permissions granted to all members, including administrators and newly created users.",
"id": "admin.permissions.systemScheme.allMembersDescription",
}
}
title={
Object {
"defaultMessage": "All Members",
"id": "admin.permissions.systemScheme.allMembersTitle",
}
}
>
<Connect(PermissionsTree)
onToggle={[Function]}
@ -237,10 +253,18 @@ exports[`components/admin_console/permission_schemes_settings/permission_system_
className="permissions-block"
onToggle={[Function]}
open={true}
subtitleDefault="Permissions granted to channel creators and any users promoted to Channel Administrator."
subtitleId="admin.permissions.systemScheme.channelAdminsDescription"
titleDefault="Channel Administrators"
titleId="admin.permissions.systemScheme.channelAdminsTitle"
subtitle={
Object {
"defaultMessage": "Permissions granted to channel creators and any users promoted to Channel Administrator.",
"id": "admin.permissions.systemScheme.channelAdminsDescription",
}
}
title={
Object {
"defaultMessage": "Channel Administrators",
"id": "admin.permissions.systemScheme.channelAdminsTitle",
}
}
>
<Connect(PermissionsTree)
onToggle={[Function]}
@ -273,10 +297,18 @@ exports[`components/admin_console/permission_schemes_settings/permission_system_
className="permissions-block"
onToggle={[Function]}
open={true}
subtitleDefault="Permissions granted to administrators of a playbook."
subtitleId="admin.permissions.systemScheme.playbookAdminSubtitle"
titleDefault="Playbook Administrator"
titleId="admin.permissions.systemScheme.playbookAdmin"
subtitle={
Object {
"defaultMessage": "Permissions granted to administrators of a playbook.",
"id": "admin.permissions.systemScheme.playbookAdminSubtitle",
}
}
title={
Object {
"defaultMessage": "Playbook Administrator",
"id": "admin.permissions.systemScheme.playbookAdmin",
}
}
>
<PermissionsTreePlaybooks
license={
@ -316,10 +348,18 @@ exports[`components/admin_console/permission_schemes_settings/permission_system_
className="permissions-block"
onToggle={[Function]}
open={true}
subtitleDefault="Permissions granted to team creators and any users promoted to Team Administrator."
subtitleId="admin.permissions.systemScheme.teamAdminsDescription"
titleDefault="Team Administrators"
titleId="admin.permissions.systemScheme.teamAdminsTitle"
subtitle={
Object {
"defaultMessage": "Permissions granted to team creators and any users promoted to Team Administrator.",
"id": "admin.permissions.systemScheme.teamAdminsDescription",
}
}
title={
Object {
"defaultMessage": "Team Administrators",
"id": "admin.permissions.systemScheme.teamAdminsTitle",
}
}
>
<Connect(PermissionsTree)
onToggle={[Function]}
@ -352,10 +392,18 @@ exports[`components/admin_console/permission_schemes_settings/permission_system_
className="permissions-block"
onToggle={[Function]}
open={true}
subtitleDefault="Full permissions granted to System Administrators."
subtitleId="admin.permissions.systemScheme.systemAdminsDescription"
titleDefault="System Administrators"
titleId="admin.permissions.systemScheme.systemAdminsTitle"
subtitle={
Object {
"defaultMessage": "Full permissions granted to System Administrators.",
"id": "admin.permissions.systemScheme.systemAdminsDescription",
}
}
title={
Object {
"defaultMessage": "System Administrators",
"id": "admin.permissions.systemScheme.systemAdminsTitle",
}
}
>
<Connect(PermissionsTree)
onToggle={[Function]}
@ -501,10 +549,18 @@ exports[`components/admin_console/permission_schemes_settings/permission_system_
id="all_users"
onToggle={[Function]}
open={true}
subtitleDefault="Permissions granted to guest users."
subtitleId="admin.permissions.systemScheme.GuestsDescription"
titleDefault="Guests"
titleId="admin.permissions.systemScheme.GuestsTitle"
subtitle={
Object {
"defaultMessage": "Permissions granted to guest users.",
"id": "admin.permissions.systemScheme.GuestsDescription",
}
}
title={
Object {
"defaultMessage": "Guests",
"id": "admin.permissions.systemScheme.GuestsTitle",
}
}
>
<Connect(GuestPermissionsTree)
onToggle={[Function]}
@ -525,10 +581,18 @@ exports[`components/admin_console/permission_schemes_settings/permission_system_
id="all_users"
onToggle={[Function]}
open={true}
subtitleDefault="Permissions granted to all members, including administrators and newly created users."
subtitleId="admin.permissions.systemScheme.allMembersDescription"
titleDefault="All Members"
titleId="admin.permissions.systemScheme.allMembersTitle"
subtitle={
Object {
"defaultMessage": "Permissions granted to all members, including administrators and newly created users.",
"id": "admin.permissions.systemScheme.allMembersDescription",
}
}
title={
Object {
"defaultMessage": "All Members",
"id": "admin.permissions.systemScheme.allMembersTitle",
}
}
>
<Connect(PermissionsTree)
onToggle={[Function]}
@ -547,10 +611,18 @@ exports[`components/admin_console/permission_schemes_settings/permission_system_
className="permissions-block"
onToggle={[Function]}
open={true}
subtitleDefault="Permissions granted to channel creators and any users promoted to Channel Administrator."
subtitleId="admin.permissions.systemScheme.channelAdminsDescription"
titleDefault="Channel Administrators"
titleId="admin.permissions.systemScheme.channelAdminsTitle"
subtitle={
Object {
"defaultMessage": "Permissions granted to channel creators and any users promoted to Channel Administrator.",
"id": "admin.permissions.systemScheme.channelAdminsDescription",
}
}
title={
Object {
"defaultMessage": "Channel Administrators",
"id": "admin.permissions.systemScheme.channelAdminsTitle",
}
}
>
<Connect(PermissionsTree)
onToggle={[Function]}
@ -583,10 +655,18 @@ exports[`components/admin_console/permission_schemes_settings/permission_system_
className="permissions-block"
onToggle={[Function]}
open={true}
subtitleDefault="Permissions granted to administrators of a playbook."
subtitleId="admin.permissions.systemScheme.playbookAdminSubtitle"
titleDefault="Playbook Administrator"
titleId="admin.permissions.systemScheme.playbookAdmin"
subtitle={
Object {
"defaultMessage": "Permissions granted to administrators of a playbook.",
"id": "admin.permissions.systemScheme.playbookAdminSubtitle",
}
}
title={
Object {
"defaultMessage": "Playbook Administrator",
"id": "admin.permissions.systemScheme.playbookAdmin",
}
}
>
<PermissionsTreePlaybooks
license={
@ -627,10 +707,18 @@ exports[`components/admin_console/permission_schemes_settings/permission_system_
className="permissions-block"
onToggle={[Function]}
open={true}
subtitleDefault="Permissions granted to team creators and any users promoted to Team Administrator."
subtitleId="admin.permissions.systemScheme.teamAdminsDescription"
titleDefault="Team Administrators"
titleId="admin.permissions.systemScheme.teamAdminsTitle"
subtitle={
Object {
"defaultMessage": "Permissions granted to team creators and any users promoted to Team Administrator.",
"id": "admin.permissions.systemScheme.teamAdminsDescription",
}
}
title={
Object {
"defaultMessage": "Team Administrators",
"id": "admin.permissions.systemScheme.teamAdminsTitle",
}
}
>
<Connect(PermissionsTree)
onToggle={[Function]}
@ -663,10 +751,18 @@ exports[`components/admin_console/permission_schemes_settings/permission_system_
className="permissions-block"
onToggle={[Function]}
open={true}
subtitleDefault="Full permissions granted to System Administrators."
subtitleId="admin.permissions.systemScheme.systemAdminsDescription"
titleDefault="System Administrators"
titleId="admin.permissions.systemScheme.systemAdminsTitle"
subtitle={
Object {
"defaultMessage": "Full permissions granted to System Administrators.",
"id": "admin.permissions.systemScheme.systemAdminsDescription",
}
}
title={
Object {
"defaultMessage": "System Administrators",
"id": "admin.permissions.systemScheme.systemAdminsTitle",
}
}
>
<Connect(PermissionsTree)
onToggle={[Function]}
@ -812,10 +908,18 @@ exports[`components/admin_console/permission_schemes_settings/permission_system_
id="all_users"
onToggle={[Function]}
open={true}
subtitleDefault="Permissions granted to guest users."
subtitleId="admin.permissions.systemScheme.GuestsDescription"
titleDefault="Guests"
titleId="admin.permissions.systemScheme.GuestsTitle"
subtitle={
Object {
"defaultMessage": "Permissions granted to guest users.",
"id": "admin.permissions.systemScheme.GuestsDescription",
}
}
title={
Object {
"defaultMessage": "Guests",
"id": "admin.permissions.systemScheme.GuestsTitle",
}
}
>
<Connect(GuestPermissionsTree)
onToggle={[Function]}
@ -836,10 +940,18 @@ exports[`components/admin_console/permission_schemes_settings/permission_system_
id="all_users"
onToggle={[Function]}
open={true}
subtitleDefault="Permissions granted to all members, including administrators and newly created users."
subtitleId="admin.permissions.systemScheme.allMembersDescription"
titleDefault="All Members"
titleId="admin.permissions.systemScheme.allMembersTitle"
subtitle={
Object {
"defaultMessage": "Permissions granted to all members, including administrators and newly created users.",
"id": "admin.permissions.systemScheme.allMembersDescription",
}
}
title={
Object {
"defaultMessage": "All Members",
"id": "admin.permissions.systemScheme.allMembersTitle",
}
}
>
<Connect(PermissionsTree)
onToggle={[Function]}
@ -858,10 +970,18 @@ exports[`components/admin_console/permission_schemes_settings/permission_system_
className="permissions-block"
onToggle={[Function]}
open={true}
subtitleDefault="Permissions granted to channel creators and any users promoted to Channel Administrator."
subtitleId="admin.permissions.systemScheme.channelAdminsDescription"
titleDefault="Channel Administrators"
titleId="admin.permissions.systemScheme.channelAdminsTitle"
subtitle={
Object {
"defaultMessage": "Permissions granted to channel creators and any users promoted to Channel Administrator.",
"id": "admin.permissions.systemScheme.channelAdminsDescription",
}
}
title={
Object {
"defaultMessage": "Channel Administrators",
"id": "admin.permissions.systemScheme.channelAdminsTitle",
}
}
>
<Connect(PermissionsTree)
onToggle={[Function]}
@ -894,10 +1014,18 @@ exports[`components/admin_console/permission_schemes_settings/permission_system_
className="permissions-block"
onToggle={[Function]}
open={true}
subtitleDefault="Permissions granted to administrators of a playbook."
subtitleId="admin.permissions.systemScheme.playbookAdminSubtitle"
titleDefault="Playbook Administrator"
titleId="admin.permissions.systemScheme.playbookAdmin"
subtitle={
Object {
"defaultMessage": "Permissions granted to administrators of a playbook.",
"id": "admin.permissions.systemScheme.playbookAdminSubtitle",
}
}
title={
Object {
"defaultMessage": "Playbook Administrator",
"id": "admin.permissions.systemScheme.playbookAdmin",
}
}
>
<PermissionsTreePlaybooks
license={
@ -938,10 +1066,18 @@ exports[`components/admin_console/permission_schemes_settings/permission_system_
className="permissions-block"
onToggle={[Function]}
open={true}
subtitleDefault="Permissions granted to team creators and any users promoted to Team Administrator."
subtitleId="admin.permissions.systemScheme.teamAdminsDescription"
titleDefault="Team Administrators"
titleId="admin.permissions.systemScheme.teamAdminsTitle"
subtitle={
Object {
"defaultMessage": "Permissions granted to team creators and any users promoted to Team Administrator.",
"id": "admin.permissions.systemScheme.teamAdminsDescription",
}
}
title={
Object {
"defaultMessage": "Team Administrators",
"id": "admin.permissions.systemScheme.teamAdminsTitle",
}
}
>
<Connect(PermissionsTree)
onToggle={[Function]}
@ -974,10 +1110,18 @@ exports[`components/admin_console/permission_schemes_settings/permission_system_
className="permissions-block"
onToggle={[Function]}
open={true}
subtitleDefault="Full permissions granted to System Administrators."
subtitleId="admin.permissions.systemScheme.systemAdminsDescription"
titleDefault="System Administrators"
titleId="admin.permissions.systemScheme.systemAdminsTitle"
subtitle={
Object {
"defaultMessage": "Full permissions granted to System Administrators.",
"id": "admin.permissions.systemScheme.systemAdminsDescription",
}
}
title={
Object {
"defaultMessage": "System Administrators",
"id": "admin.permissions.systemScheme.systemAdminsTitle",
}
}
>
<Connect(PermissionsTree)
onToggle={[Function]}
@ -1123,10 +1267,18 @@ exports[`components/admin_console/permission_schemes_settings/permission_system_
id="all_users"
onToggle={[Function]}
open={true}
subtitleDefault="Permissions granted to guest users."
subtitleId="admin.permissions.systemScheme.GuestsDescription"
titleDefault="Guests"
titleId="admin.permissions.systemScheme.GuestsTitle"
subtitle={
Object {
"defaultMessage": "Permissions granted to guest users.",
"id": "admin.permissions.systemScheme.GuestsDescription",
}
}
title={
Object {
"defaultMessage": "Guests",
"id": "admin.permissions.systemScheme.GuestsTitle",
}
}
>
<Connect(GuestPermissionsTree)
onToggle={[Function]}
@ -1147,10 +1299,18 @@ exports[`components/admin_console/permission_schemes_settings/permission_system_
id="all_users"
onToggle={[Function]}
open={true}
subtitleDefault="Permissions granted to all members, including administrators and newly created users."
subtitleId="admin.permissions.systemScheme.allMembersDescription"
titleDefault="All Members"
titleId="admin.permissions.systemScheme.allMembersTitle"
subtitle={
Object {
"defaultMessage": "Permissions granted to all members, including administrators and newly created users.",
"id": "admin.permissions.systemScheme.allMembersDescription",
}
}
title={
Object {
"defaultMessage": "All Members",
"id": "admin.permissions.systemScheme.allMembersTitle",
}
}
>
<Connect(PermissionsTree)
onToggle={[Function]}
@ -1169,10 +1329,18 @@ exports[`components/admin_console/permission_schemes_settings/permission_system_
className="permissions-block"
onToggle={[Function]}
open={true}
subtitleDefault="Permissions granted to channel creators and any users promoted to Channel Administrator."
subtitleId="admin.permissions.systemScheme.channelAdminsDescription"
titleDefault="Channel Administrators"
titleId="admin.permissions.systemScheme.channelAdminsTitle"
subtitle={
Object {
"defaultMessage": "Permissions granted to channel creators and any users promoted to Channel Administrator.",
"id": "admin.permissions.systemScheme.channelAdminsDescription",
}
}
title={
Object {
"defaultMessage": "Channel Administrators",
"id": "admin.permissions.systemScheme.channelAdminsTitle",
}
}
>
<Connect(PermissionsTree)
onToggle={[Function]}
@ -1205,10 +1373,18 @@ exports[`components/admin_console/permission_schemes_settings/permission_system_
className="permissions-block"
onToggle={[Function]}
open={true}
subtitleDefault="Permissions granted to administrators of a playbook."
subtitleId="admin.permissions.systemScheme.playbookAdminSubtitle"
titleDefault="Playbook Administrator"
titleId="admin.permissions.systemScheme.playbookAdmin"
subtitle={
Object {
"defaultMessage": "Permissions granted to administrators of a playbook.",
"id": "admin.permissions.systemScheme.playbookAdminSubtitle",
}
}
title={
Object {
"defaultMessage": "Playbook Administrator",
"id": "admin.permissions.systemScheme.playbookAdmin",
}
}
>
<PermissionsTreePlaybooks
license={
@ -1249,10 +1425,18 @@ exports[`components/admin_console/permission_schemes_settings/permission_system_
className="permissions-block"
onToggle={[Function]}
open={true}
subtitleDefault="Permissions granted to team creators and any users promoted to Team Administrator."
subtitleId="admin.permissions.systemScheme.teamAdminsDescription"
titleDefault="Team Administrators"
titleId="admin.permissions.systemScheme.teamAdminsTitle"
subtitle={
Object {
"defaultMessage": "Permissions granted to team creators and any users promoted to Team Administrator.",
"id": "admin.permissions.systemScheme.teamAdminsDescription",
}
}
title={
Object {
"defaultMessage": "Team Administrators",
"id": "admin.permissions.systemScheme.teamAdminsTitle",
}
}
>
<Connect(PermissionsTree)
onToggle={[Function]}
@ -1285,10 +1469,18 @@ exports[`components/admin_console/permission_schemes_settings/permission_system_
className="permissions-block"
onToggle={[Function]}
open={true}
subtitleDefault="Full permissions granted to System Administrators."
subtitleId="admin.permissions.systemScheme.systemAdminsDescription"
titleDefault="System Administrators"
titleId="admin.permissions.systemScheme.systemAdminsTitle"
subtitle={
Object {
"defaultMessage": "Full permissions granted to System Administrators.",
"id": "admin.permissions.systemScheme.systemAdminsDescription",
}
}
title={
Object {
"defaultMessage": "System Administrators",
"id": "admin.permissions.systemScheme.systemAdminsTitle",
}
}
>
<Connect(PermissionsTree)
onToggle={[Function]}

View File

@ -1,15 +1,23 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {shallow} from 'enzyme';
import React from 'react';
import type {Role} from '@mattermost/types/roles';
import PermissionSystemSchemeSettings from 'components/admin_console/permission_schemes_settings/permission_system_scheme_settings/permission_system_scheme_settings';
import {shallowWithIntl} from 'tests/helpers/intl-test-helper';
import {DefaultRolePermissions} from 'utils/constants';
function getAnyInstance(wrapper: any) {
return wrapper.instance() as any;
}
function getAnyState(wrapper: any) {
return wrapper.state() as any;
}
describe('components/admin_console/permission_schemes_settings/permission_system_scheme_settings/permission_system_scheme_settings', () => {
const defaultRole: Role = {
id: '',
@ -56,11 +64,11 @@ describe('components/admin_console/permission_schemes_settings/permission_system
};
test('should match snapshot on roles without permissions', (done) => {
const wrapper = shallow(
const wrapper = shallowWithIntl(
<PermissionSystemSchemeSettings {...defaultProps}/>,
);
defaultProps.actions.loadRolesIfNeeded().then(() => {
expect(wrapper.state()).toMatchSnapshot();
expect(getAnyState(wrapper)).toMatchSnapshot();
done();
});
});
@ -70,7 +78,7 @@ describe('components/admin_console/permission_schemes_settings/permission_system
IsLicensed: 'true',
CustomPermissionsSchemes: 'false',
};
const wrapper = shallow(
const wrapper = shallowWithIntl(
<PermissionSystemSchemeSettings
{...defaultProps}
license={license}
@ -121,7 +129,7 @@ describe('components/admin_console/permission_schemes_settings/permission_system
permissions: ['delete_post'],
},
};
const wrapper = shallow(
const wrapper = shallowWithIntl(
<PermissionSystemSchemeSettings
{...defaultProps}
roles={roles}
@ -130,14 +138,14 @@ describe('components/admin_console/permission_schemes_settings/permission_system
expect(wrapper).toMatchSnapshot();
defaultProps.actions.loadRolesIfNeeded().then(() => {
expect(wrapper.state()).toMatchSnapshot();
expect(getAnyState(wrapper)).toMatchSnapshot();
done();
});
});
test('should save each role on handleSubmit except system_admin role', async () => {
const editRole = jest.fn().mockImplementation(() => Promise.resolve({data: {}}));
const wrapper = shallow<PermissionSystemSchemeSettings>(
const wrapper = shallowWithIntl(
<PermissionSystemSchemeSettings
{...defaultProps}
actions={{...defaultProps.actions, editRole}}
@ -146,7 +154,7 @@ describe('components/admin_console/permission_schemes_settings/permission_system
expect(wrapper).toMatchSnapshot();
await wrapper.instance().handleSubmit();
await getAnyInstance(wrapper).handleSubmit();
expect(editRole).toHaveBeenCalledTimes(11);
});
@ -157,7 +165,7 @@ describe('components/admin_console/permission_schemes_settings/permission_system
GuestAccountsPermissions: 'false',
};
let editRole = jest.fn().mockImplementation(() => Promise.resolve({data: {}}));
const wrapper = shallow<PermissionSystemSchemeSettings>(
const wrapper = shallowWithIntl(
<PermissionSystemSchemeSettings
{...defaultProps}
license={license}
@ -167,11 +175,11 @@ describe('components/admin_console/permission_schemes_settings/permission_system
expect(wrapper).toMatchSnapshot();
await wrapper.instance().handleSubmit();
await getAnyInstance(wrapper).handleSubmit();
expect(editRole).toHaveBeenCalledTimes(8);
license.GuestAccountsPermissions = 'true';
editRole = jest.fn().mockImplementation(() => Promise.resolve({data: {}}));
const wrapper2 = shallow<PermissionSystemSchemeSettings>(
const wrapper2 = shallowWithIntl(
<PermissionSystemSchemeSettings
{...defaultProps}
license={license}
@ -181,73 +189,73 @@ describe('components/admin_console/permission_schemes_settings/permission_system
expect(wrapper2).toMatchSnapshot();
await wrapper2.instance().handleSubmit();
await getAnyInstance(wrapper2).handleSubmit();
expect(editRole).toHaveBeenCalledTimes(11);
});
test('should show error if editRole fails', async () => {
const editRole = jest.fn().mockImplementation(() => Promise.resolve({error: {message: 'test error'}}));
const wrapper = shallow<PermissionSystemSchemeSettings>(
const wrapper = shallowWithIntl(
<PermissionSystemSchemeSettings
{...defaultProps}
actions={{...defaultProps.actions, editRole}}
/>,
);
await wrapper.instance().handleSubmit();
await expect(wrapper.state().serverError).toBe('test error');
await getAnyInstance(wrapper).handleSubmit();
await expect(getAnyState(wrapper).serverError).toBe('test error');
});
test('should open and close correctly roles blocks', () => {
const wrapper = shallow<PermissionSystemSchemeSettings>(
const wrapper = shallowWithIntl(
<PermissionSystemSchemeSettings {...defaultProps}/>,
);
const instance = wrapper.instance();
expect(wrapper.state().openRoles.all_users).toBe(true);
const instance = getAnyInstance(wrapper);
expect(getAnyState(wrapper).openRoles.all_users).toBe(true);
instance.toggleRole('all_users');
expect(wrapper.state().openRoles.all_users).toBe(false);
expect(getAnyState(wrapper).openRoles.all_users).toBe(false);
instance.toggleRole('all_users');
expect(wrapper.state().openRoles.all_users).toBe(true);
expect(getAnyState(wrapper).openRoles.all_users).toBe(true);
expect(wrapper.state().openRoles.channel_admin).toBe(true);
expect(getAnyState(wrapper).openRoles.channel_admin).toBe(true);
instance.toggleRole('channel_admin');
expect(wrapper.state().openRoles.channel_admin).toBe(false);
expect(getAnyState(wrapper).openRoles.channel_admin).toBe(false);
instance.toggleRole('channel_admin');
expect(wrapper.state().openRoles.channel_admin).toBe(true);
expect(getAnyState(wrapper).openRoles.channel_admin).toBe(true);
expect(wrapper.state().openRoles.team_admin).toBe(true);
expect(getAnyState(wrapper).openRoles.team_admin).toBe(true);
instance.toggleRole('team_admin');
expect(wrapper.state().openRoles.team_admin).toBe(false);
expect(getAnyState(wrapper).openRoles.team_admin).toBe(false);
instance.toggleRole('team_admin');
expect(wrapper.state().openRoles.team_admin).toBe(true);
expect(getAnyState(wrapper).openRoles.team_admin).toBe(true);
expect(wrapper.state().openRoles.system_admin).toBe(true);
expect(getAnyState(wrapper).openRoles.system_admin).toBe(true);
instance.toggleRole('system_admin');
expect(wrapper.state().openRoles.system_admin).toBe(false);
expect(getAnyState(wrapper).openRoles.system_admin).toBe(false);
instance.toggleRole('system_admin');
expect(wrapper.state().openRoles.system_admin).toBe(true);
expect(getAnyState(wrapper).openRoles.system_admin).toBe(true);
});
test('should open modal on click reset defaults', () => {
const wrapper = shallow<PermissionSystemSchemeSettings>(
const wrapper = shallowWithIntl(
<PermissionSystemSchemeSettings {...defaultProps}/>,
);
expect(wrapper.state().showResetDefaultModal).toBe(false);
expect(getAnyState(wrapper).showResetDefaultModal).toBe(false);
wrapper.find('.btn-quaternary').first().simulate('click');
expect(wrapper.state().showResetDefaultModal).toBe(true);
expect(getAnyState(wrapper).showResetDefaultModal).toBe(true);
});
test('should have default permissions that match the defaults constant', () => {
const wrapper = shallow<PermissionSystemSchemeSettings>(
const wrapper = shallowWithIntl(
<PermissionSystemSchemeSettings {...defaultProps}/>,
);
expect(wrapper.state().roles.all_users.permissions?.length).toBe(0);
expect(wrapper.state().roles.channel_admin.permissions?.length).toBe(0);
expect(wrapper.state().roles.team_admin.permissions?.length).toBe(0);
wrapper.instance().resetDefaults();
expect(wrapper.state().roles.all_users.permissions).toBe(DefaultRolePermissions.all_users);
expect(wrapper.state().roles.channel_admin.permissions).toBe(DefaultRolePermissions.channel_admin);
expect(wrapper.state().roles.team_admin.permissions).toBe(DefaultRolePermissions.team_admin);
expect(wrapper.state().roles.system_admin.permissions?.length).toBe(defaultProps.roles.system_admin.permissions.length);
expect(getAnyState(wrapper).roles.all_users.permissions?.length).toBe(0);
expect(getAnyState(wrapper).roles.channel_admin.permissions?.length).toBe(0);
expect(getAnyState(wrapper).roles.team_admin.permissions?.length).toBe(0);
getAnyInstance(wrapper).resetDefaults();
expect(getAnyState(wrapper).roles.all_users.permissions).toBe(DefaultRolePermissions.all_users);
expect(getAnyState(wrapper).roles.channel_admin.permissions).toBe(DefaultRolePermissions.channel_admin);
expect(getAnyState(wrapper).roles.team_admin.permissions).toBe(DefaultRolePermissions.team_admin);
expect(getAnyState(wrapper).roles.system_admin.permissions?.length).toBe(defaultProps.roles.system_admin.permissions.length);
});
});

View File

@ -2,7 +2,8 @@
// See LICENSE.txt for license information.
import React from 'react';
import {FormattedMessage} from 'react-intl';
import type {WrappedComponentProps} from 'react-intl';
import {FormattedMessage, defineMessage, injectIntl} from 'react-intl';
import type {ClientConfig, ClientLicense} from '@mattermost/types/config';
import type {Role} from '@mattermost/types/roles';
@ -20,8 +21,6 @@ import AdminHeader from 'components/widgets/admin_console/admin_header';
import AdminPanelTogglable from 'components/widgets/admin_console/admin_panel_togglable';
import {PermissionsScope, DefaultRolePermissions, DocLinks} from 'utils/constants';
import {t} from 'utils/i18n';
import {localizeMessage} from 'utils/utils';
import GuestPermissionsTree, {GUEST_INCLUDED_PERMISSIONS} from '../guest_permissions_tree';
import PermissionsTree, {EXCLUDED_PERMISSIONS} from '../permissions_tree';
@ -38,7 +37,7 @@ type Props = {
setNavigationBlocked: (blocked: boolean) => void;
};
location: Location;
}
} & WrappedComponentProps;
type State = {
showResetDefaultModal: boolean;
@ -52,7 +51,7 @@ type State = {
urlParams: URLSearchParams;
}
export default class PermissionSystemSchemeSettings extends React.PureComponent<Props, State> {
class PermissionSystemSchemeSettings extends React.PureComponent<Props, State> {
private rolesNeeded: string[];
constructor(props: Props) {
@ -395,10 +394,8 @@ export default class PermissionSystemSchemeSettings extends React.PureComponent<
open={this.state.openRoles.guests}
id='all_users'
onToggle={() => this.toggleRole('guests')}
titleId={t('admin.permissions.systemScheme.GuestsTitle')}
titleDefault='Guests'
subtitleId={t('admin.permissions.systemScheme.GuestsDescription')}
subtitleDefault='Permissions granted to guest users.'
title={defineMessage({id: 'admin.permissions.systemScheme.GuestsTitle', defaultMessage: 'Guests'})}
subtitle={defineMessage({id: 'admin.permissions.systemScheme.GuestsDescription', defaultMessage: 'Permissions granted to guest users.'})}
>
<GuestPermissionsTree
selected={this.state.selectedPermission}
@ -415,10 +412,8 @@ export default class PermissionSystemSchemeSettings extends React.PureComponent<
open={this.state.openRoles.all_users}
id='all_users'
onToggle={() => this.toggleRole('all_users')}
titleId={t('admin.permissions.systemScheme.allMembersTitle')}
titleDefault='All Members'
subtitleId={t('admin.permissions.systemScheme.allMembersDescription')}
subtitleDefault='Permissions granted to all members, including administrators and newly created users.'
title={defineMessage({id: 'admin.permissions.systemScheme.allMembersTitle', defaultMessage: 'All Members'})}
subtitle={defineMessage({id: 'admin.permissions.systemScheme.allMembersDescription', defaultMessage: 'Permissions granted to all members, including administrators and newly created users.'})}
>
<PermissionsTree
selected={this.state.selectedPermission}
@ -434,10 +429,8 @@ export default class PermissionSystemSchemeSettings extends React.PureComponent<
className='permissions-block'
open={this.state.openRoles.channel_admin}
onToggle={() => this.toggleRole('channel_admin')}
titleId={t('admin.permissions.systemScheme.channelAdminsTitle')}
titleDefault='Channel Administrators'
subtitleId={t('admin.permissions.systemScheme.channelAdminsDescription')}
subtitleDefault='Permissions granted to channel creators and any users promoted to Channel Administrator.'
title={defineMessage({id: 'admin.permissions.systemScheme.channelAdminsTitle', defaultMessage: 'Channel Administrators'})}
subtitle={defineMessage({id: 'admin.permissions.systemScheme.channelAdminsDescription', defaultMessage: 'Permissions granted to channel creators and any users promoted to Channel Administrator.'})}
>
<PermissionsTree
parentRole={this.state.roles.all_users}
@ -453,10 +446,8 @@ export default class PermissionSystemSchemeSettings extends React.PureComponent<
className='permissions-block'
open={this.state.openRoles.playbook_admin}
onToggle={() => this.toggleRole('playbook_admin')}
titleId={t('admin.permissions.systemScheme.playbookAdmin')}
titleDefault='Playbook Administrator'
subtitleId={t('admin.permissions.systemScheme.playbookAdminSubtitle')}
subtitleDefault='Permissions granted to administrators of a playbook.'
title={defineMessage({id: 'admin.permissions.systemScheme.playbookAdmin', defaultMessage: 'Playbook Administrator'})}
subtitle={defineMessage({id: 'admin.permissions.systemScheme.playbookAdminSubtitle', defaultMessage: 'Permissions granted to administrators of a playbook.'})}
>
<PermissionsTreePlaybooks
role={this.state.roles.playbook_admin}
@ -473,10 +464,8 @@ export default class PermissionSystemSchemeSettings extends React.PureComponent<
className='permissions-block'
open={this.state.openRoles.team_admin}
onToggle={() => this.toggleRole('team_admin')}
titleId={t('admin.permissions.systemScheme.teamAdminsTitle')}
titleDefault='Team Administrators'
subtitleId={t('admin.permissions.systemScheme.teamAdminsDescription')}
subtitleDefault='Permissions granted to team creators and any users promoted to Team Administrator.'
title={defineMessage({id: 'admin.permissions.systemScheme.teamAdminsTitle', defaultMessage: 'Team Administrators'})}
subtitle={defineMessage({id: 'admin.permissions.systemScheme.teamAdminsDescription', defaultMessage: 'Permissions granted to team creators and any users promoted to Team Administrator.'})}
>
<PermissionsTree
parentRole={this.state.roles.all_users}
@ -492,10 +481,8 @@ export default class PermissionSystemSchemeSettings extends React.PureComponent<
className='permissions-block'
open={this.state.openRoles.system_admin}
onToggle={() => this.toggleRole('system_admin')}
titleId={t('admin.permissions.systemScheme.systemAdminsTitle')}
titleDefault='System Administrators'
subtitleId={t('admin.permissions.systemScheme.systemAdminsDescription')}
subtitleDefault='Full permissions granted to System Administrators.'
title={defineMessage({id: 'admin.permissions.systemScheme.systemAdminsTitle', defaultMessage: 'System Administrators'})}
subtitle={defineMessage({id: 'admin.permissions.systemScheme.systemAdminsDescription', defaultMessage: 'Full permissions granted to System Administrators.'})}
>
<PermissionsTree
readOnly={true}
@ -513,7 +500,7 @@ export default class PermissionSystemSchemeSettings extends React.PureComponent<
saving={this.state.saving}
disabled={this.props.isDisabled || !this.state.saveNeeded}
onClick={this.handleSubmit}
savingMessage={localizeMessage('admin.saving', 'Saving Config...')}
savingMessage={this.props.intl.formatMessage({id: 'admin.saving', defaultMessage: 'Saving Config...'})}
/>
<BlockableLink
className='btn btn-tertiary'
@ -569,3 +556,5 @@ export default class PermissionSystemSchemeSettings extends React.PureComponent<
);
};
}
export default injectIntl(PermissionSystemSchemeSettings);

View File

@ -71,11 +71,18 @@ exports[`components/admin_console/permission_schemes_settings/permission_team_sc
</div>
</div>
<AdminPanel
className=""
subtitleDefault="Set the name and description for this scheme."
subtitleId="admin.permissions.teamScheme.schemeDetailsDescription"
titleDefault="Scheme Details"
titleId="admin.permissions.teamScheme.schemeDetailsTitle"
subtitle={
Object {
"defaultMessage": "Set the name and description for this scheme.",
"id": "admin.permissions.teamScheme.schemeDetailsDescription",
}
}
title={
Object {
"defaultMessage": "Scheme Details",
"id": "admin.permissions.teamScheme.schemeDetailsTitle",
}
}
>
<div
className="team-scheme-details"
@ -118,7 +125,6 @@ exports[`components/admin_console/permission_schemes_settings/permission_team_sc
disabled={false}
id="scheme-description"
onChange={[Function]}
placeholder="Scheme Description"
rows={5}
value="Test scheme description"
/>
@ -126,15 +132,27 @@ exports[`components/admin_console/permission_schemes_settings/permission_team_sc
</div>
</AdminPanel>
<AdminPanelWithButton
buttonTextDefault="Add Teams"
buttonTextId="admin.permissions.teamScheme.addTeams"
buttonText={
Object {
"defaultMessage": "Add Teams",
"id": "admin.permissions.teamScheme.addTeams",
}
}
className="permissions-block"
disabled={false}
onButtonClick={[Function]}
subtitleDefault="Select teams where permission exceptions are required."
subtitleId="admin.permissions.teamScheme.selectTeamsDescription"
titleDefault="Select teams to override permissions"
titleId="admin.permissions.teamScheme.selectTeamsTitle"
subtitle={
Object {
"defaultMessage": "Select teams where permission exceptions are required.",
"id": "admin.permissions.teamScheme.selectTeamsDescription",
}
}
title={
Object {
"defaultMessage": "Select teams to override permissions",
"id": "admin.permissions.teamScheme.selectTeamsTitle",
}
}
>
<div
className="teams-list"
@ -152,13 +170,20 @@ exports[`components/admin_console/permission_schemes_settings/permission_team_sc
<AdminPanelTogglable
className="permissions-block all_users"
id="all_users"
isDisabled={false}
onToggle={[Function]}
open={true}
subtitleDefault="Permissions granted to all members, including administrators and newly created users."
subtitleId="admin.permissions.systemScheme.allMembersDescription"
titleDefault="All Members"
titleId="admin.permissions.systemScheme.allMembersTitle"
subtitle={
Object {
"defaultMessage": "Permissions granted to all members, including administrators and newly created users.",
"id": "admin.permissions.systemScheme.allMembersDescription",
}
}
title={
Object {
"defaultMessage": "All Members",
"id": "admin.permissions.systemScheme.allMembersTitle",
}
}
>
<Connect(PermissionsTree)
onToggle={[Function]}
@ -176,13 +201,20 @@ exports[`components/admin_console/permission_schemes_settings/permission_team_sc
</AdminPanelTogglable>
<AdminPanelTogglable
className="permissions-block channel_admin"
isDisabled={false}
onToggle={[Function]}
open={true}
subtitleDefault="Permissions granted to channel creators and any users promoted to Channel Administrator."
subtitleId="admin.permissions.systemScheme.channelAdminsDescription"
titleDefault="Channel Administrators"
titleId="admin.permissions.systemScheme.channelAdminsTitle"
subtitle={
Object {
"defaultMessage": "Permissions granted to channel creators and any users promoted to Channel Administrator.",
"id": "admin.permissions.systemScheme.channelAdminsDescription",
}
}
title={
Object {
"defaultMessage": "Channel Administrators",
"id": "admin.permissions.systemScheme.channelAdminsTitle",
}
}
>
<Connect(PermissionsTree)
onToggle={[Function]}
@ -205,13 +237,20 @@ exports[`components/admin_console/permission_schemes_settings/permission_team_sc
</AdminPanelTogglable>
<AdminPanelTogglable
className="permissions-block"
isDisabled={false}
onToggle={[Function]}
open={true}
subtitleDefault="Permissions granted to administrators of a playbook."
subtitleId="admin.permissions.systemScheme.playbookAdminSubtitle"
titleDefault="Playbook Administrator"
titleId="admin.permissions.systemScheme.playbookAdmin"
subtitle={
Object {
"defaultMessage": "Permissions granted to administrators of a playbook.",
"id": "admin.permissions.systemScheme.playbookAdminSubtitle",
}
}
title={
Object {
"defaultMessage": "Playbook Administrator",
"id": "admin.permissions.systemScheme.playbookAdmin",
}
}
>
<PermissionsTreePlaybooks
license={
@ -241,13 +280,20 @@ exports[`components/admin_console/permission_schemes_settings/permission_team_sc
</AdminPanelTogglable>
<AdminPanelTogglable
className="permissions-block team_admin"
isDisabled={false}
onToggle={[Function]}
open={true}
subtitleDefault="Permissions granted to team creators and any users promoted to Team Administrator."
subtitleId="admin.permissions.systemScheme.teamAdminsDescription"
titleDefault="Team Administrators"
titleId="admin.permissions.systemScheme.teamAdminsTitle"
subtitle={
Object {
"defaultMessage": "Permissions granted to team creators and any users promoted to Team Administrator.",
"id": "admin.permissions.systemScheme.teamAdminsDescription",
}
}
title={
Object {
"defaultMessage": "Team Administrators",
"id": "admin.permissions.systemScheme.teamAdminsTitle",
}
}
>
<Connect(PermissionsTree)
onToggle={[Function]}
@ -285,7 +331,12 @@ exports[`components/admin_console/permission_schemes_settings/permission_team_sc
extraClasses=""
onClick={[Function]}
saving={false}
savingMessage="Saving Config..."
savingMessage={
<Memo(MemoizedFormattedMessage)
defaultMessage="Saving"
id="save_button.saving"
/>
}
/>
<Connect(Component)
className="cancel-button"
@ -395,11 +446,18 @@ exports[`components/admin_console/permission_schemes_settings/permission_team_sc
</div>
</div>
<AdminPanel
className=""
subtitleDefault="Set the name and description for this scheme."
subtitleId="admin.permissions.teamScheme.schemeDetailsDescription"
titleDefault="Scheme Details"
titleId="admin.permissions.teamScheme.schemeDetailsTitle"
subtitle={
Object {
"defaultMessage": "Set the name and description for this scheme.",
"id": "admin.permissions.teamScheme.schemeDetailsDescription",
}
}
title={
Object {
"defaultMessage": "Scheme Details",
"id": "admin.permissions.teamScheme.schemeDetailsTitle",
}
}
>
<div
className="team-scheme-details"
@ -442,7 +500,6 @@ exports[`components/admin_console/permission_schemes_settings/permission_team_sc
disabled={false}
id="scheme-description"
onChange={[Function]}
placeholder="Scheme Description"
rows={5}
value="Test scheme description"
/>
@ -450,15 +507,27 @@ exports[`components/admin_console/permission_schemes_settings/permission_team_sc
</div>
</AdminPanel>
<AdminPanelWithButton
buttonTextDefault="Add Teams"
buttonTextId="admin.permissions.teamScheme.addTeams"
buttonText={
Object {
"defaultMessage": "Add Teams",
"id": "admin.permissions.teamScheme.addTeams",
}
}
className="permissions-block"
disabled={false}
onButtonClick={[Function]}
subtitleDefault="Select teams where permission exceptions are required."
subtitleId="admin.permissions.teamScheme.selectTeamsDescription"
titleDefault="Select teams to override permissions"
titleId="admin.permissions.teamScheme.selectTeamsTitle"
subtitle={
Object {
"defaultMessage": "Select teams where permission exceptions are required.",
"id": "admin.permissions.teamScheme.selectTeamsDescription",
}
}
title={
Object {
"defaultMessage": "Select teams to override permissions",
"id": "admin.permissions.teamScheme.selectTeamsTitle",
}
}
>
<div
className="teams-list"
@ -476,13 +545,20 @@ exports[`components/admin_console/permission_schemes_settings/permission_team_sc
<AdminPanelTogglable
className="permissions-block"
id="guests"
isDisabled={false}
onToggle={[Function]}
open={true}
subtitleDefault="Permissions granted to guest users."
subtitleId="admin.permissions.systemScheme.GuestsDescription"
titleDefault="Guests"
titleId="admin.permissions.systemScheme.GuestsTitle"
subtitle={
Object {
"defaultMessage": "Permissions granted to guest users.",
"id": "admin.permissions.systemScheme.GuestsDescription",
}
}
title={
Object {
"defaultMessage": "Guests",
"id": "admin.permissions.systemScheme.GuestsTitle",
}
}
>
<Connect(GuestPermissionsTree)
onToggle={[Function]}
@ -501,13 +577,20 @@ exports[`components/admin_console/permission_schemes_settings/permission_team_sc
<AdminPanelTogglable
className="permissions-block all_users"
id="all_users"
isDisabled={false}
onToggle={[Function]}
open={true}
subtitleDefault="Permissions granted to all members, including administrators and newly created users."
subtitleId="admin.permissions.systemScheme.allMembersDescription"
titleDefault="All Members"
titleId="admin.permissions.systemScheme.allMembersTitle"
subtitle={
Object {
"defaultMessage": "Permissions granted to all members, including administrators and newly created users.",
"id": "admin.permissions.systemScheme.allMembersDescription",
}
}
title={
Object {
"defaultMessage": "All Members",
"id": "admin.permissions.systemScheme.allMembersTitle",
}
}
>
<Connect(PermissionsTree)
onToggle={[Function]}
@ -525,13 +608,20 @@ exports[`components/admin_console/permission_schemes_settings/permission_team_sc
</AdminPanelTogglable>
<AdminPanelTogglable
className="permissions-block channel_admin"
isDisabled={false}
onToggle={[Function]}
open={true}
subtitleDefault="Permissions granted to channel creators and any users promoted to Channel Administrator."
subtitleId="admin.permissions.systemScheme.channelAdminsDescription"
titleDefault="Channel Administrators"
titleId="admin.permissions.systemScheme.channelAdminsTitle"
subtitle={
Object {
"defaultMessage": "Permissions granted to channel creators and any users promoted to Channel Administrator.",
"id": "admin.permissions.systemScheme.channelAdminsDescription",
}
}
title={
Object {
"defaultMessage": "Channel Administrators",
"id": "admin.permissions.systemScheme.channelAdminsTitle",
}
}
>
<Connect(PermissionsTree)
onToggle={[Function]}
@ -554,13 +644,20 @@ exports[`components/admin_console/permission_schemes_settings/permission_team_sc
</AdminPanelTogglable>
<AdminPanelTogglable
className="permissions-block"
isDisabled={false}
onToggle={[Function]}
open={true}
subtitleDefault="Permissions granted to administrators of a playbook."
subtitleId="admin.permissions.systemScheme.playbookAdminSubtitle"
titleDefault="Playbook Administrator"
titleId="admin.permissions.systemScheme.playbookAdmin"
subtitle={
Object {
"defaultMessage": "Permissions granted to administrators of a playbook.",
"id": "admin.permissions.systemScheme.playbookAdminSubtitle",
}
}
title={
Object {
"defaultMessage": "Playbook Administrator",
"id": "admin.permissions.systemScheme.playbookAdmin",
}
}
>
<PermissionsTreePlaybooks
license={
@ -588,13 +685,20 @@ exports[`components/admin_console/permission_schemes_settings/permission_team_sc
</AdminPanelTogglable>
<AdminPanelTogglable
className="permissions-block team_admin"
isDisabled={false}
onToggle={[Function]}
open={true}
subtitleDefault="Permissions granted to team creators and any users promoted to Team Administrator."
subtitleId="admin.permissions.systemScheme.teamAdminsDescription"
titleDefault="Team Administrators"
titleId="admin.permissions.systemScheme.teamAdminsTitle"
subtitle={
Object {
"defaultMessage": "Permissions granted to team creators and any users promoted to Team Administrator.",
"id": "admin.permissions.systemScheme.teamAdminsDescription",
}
}
title={
Object {
"defaultMessage": "Team Administrators",
"id": "admin.permissions.systemScheme.teamAdminsTitle",
}
}
>
<Connect(PermissionsTree)
onToggle={[Function]}
@ -632,7 +736,12 @@ exports[`components/admin_console/permission_schemes_settings/permission_team_sc
extraClasses=""
onClick={[Function]}
saving={false}
savingMessage="Saving Config..."
savingMessage={
<Memo(MemoizedFormattedMessage)
defaultMessage="Saving"
id="save_button.saving"
/>
}
/>
<Connect(Component)
className="cancel-button"
@ -742,11 +851,18 @@ exports[`components/admin_console/permission_schemes_settings/permission_team_sc
</div>
</div>
<AdminPanel
className=""
subtitleDefault="Set the name and description for this scheme."
subtitleId="admin.permissions.teamScheme.schemeDetailsDescription"
titleDefault="Scheme Details"
titleId="admin.permissions.teamScheme.schemeDetailsTitle"
subtitle={
Object {
"defaultMessage": "Set the name and description for this scheme.",
"id": "admin.permissions.teamScheme.schemeDetailsDescription",
}
}
title={
Object {
"defaultMessage": "Scheme Details",
"id": "admin.permissions.teamScheme.schemeDetailsTitle",
}
}
>
<div
className="team-scheme-details"
@ -789,7 +905,6 @@ exports[`components/admin_console/permission_schemes_settings/permission_team_sc
disabled={false}
id="scheme-description"
onChange={[Function]}
placeholder="Scheme Description"
rows={5}
value="Test scheme description"
/>
@ -797,15 +912,27 @@ exports[`components/admin_console/permission_schemes_settings/permission_team_sc
</div>
</AdminPanel>
<AdminPanelWithButton
buttonTextDefault="Add Teams"
buttonTextId="admin.permissions.teamScheme.addTeams"
buttonText={
Object {
"defaultMessage": "Add Teams",
"id": "admin.permissions.teamScheme.addTeams",
}
}
className="permissions-block"
disabled={false}
onButtonClick={[Function]}
subtitleDefault="Select teams where permission exceptions are required."
subtitleId="admin.permissions.teamScheme.selectTeamsDescription"
titleDefault="Select teams to override permissions"
titleId="admin.permissions.teamScheme.selectTeamsTitle"
subtitle={
Object {
"defaultMessage": "Select teams where permission exceptions are required.",
"id": "admin.permissions.teamScheme.selectTeamsDescription",
}
}
title={
Object {
"defaultMessage": "Select teams to override permissions",
"id": "admin.permissions.teamScheme.selectTeamsTitle",
}
}
>
<div
className="teams-list"
@ -823,13 +950,20 @@ exports[`components/admin_console/permission_schemes_settings/permission_team_sc
<AdminPanelTogglable
className="permissions-block"
id="guests"
isDisabled={false}
onToggle={[Function]}
open={true}
subtitleDefault="Permissions granted to guest users."
subtitleId="admin.permissions.systemScheme.GuestsDescription"
titleDefault="Guests"
titleId="admin.permissions.systemScheme.GuestsTitle"
subtitle={
Object {
"defaultMessage": "Permissions granted to guest users.",
"id": "admin.permissions.systemScheme.GuestsDescription",
}
}
title={
Object {
"defaultMessage": "Guests",
"id": "admin.permissions.systemScheme.GuestsTitle",
}
}
>
<Connect(GuestPermissionsTree)
onToggle={[Function]}
@ -848,13 +982,20 @@ exports[`components/admin_console/permission_schemes_settings/permission_team_sc
<AdminPanelTogglable
className="permissions-block all_users"
id="all_users"
isDisabled={false}
onToggle={[Function]}
open={true}
subtitleDefault="Permissions granted to all members, including administrators and newly created users."
subtitleId="admin.permissions.systemScheme.allMembersDescription"
titleDefault="All Members"
titleId="admin.permissions.systemScheme.allMembersTitle"
subtitle={
Object {
"defaultMessage": "Permissions granted to all members, including administrators and newly created users.",
"id": "admin.permissions.systemScheme.allMembersDescription",
}
}
title={
Object {
"defaultMessage": "All Members",
"id": "admin.permissions.systemScheme.allMembersTitle",
}
}
>
<Connect(PermissionsTree)
onToggle={[Function]}
@ -872,13 +1013,20 @@ exports[`components/admin_console/permission_schemes_settings/permission_team_sc
</AdminPanelTogglable>
<AdminPanelTogglable
className="permissions-block channel_admin"
isDisabled={false}
onToggle={[Function]}
open={true}
subtitleDefault="Permissions granted to channel creators and any users promoted to Channel Administrator."
subtitleId="admin.permissions.systemScheme.channelAdminsDescription"
titleDefault="Channel Administrators"
titleId="admin.permissions.systemScheme.channelAdminsTitle"
subtitle={
Object {
"defaultMessage": "Permissions granted to channel creators and any users promoted to Channel Administrator.",
"id": "admin.permissions.systemScheme.channelAdminsDescription",
}
}
title={
Object {
"defaultMessage": "Channel Administrators",
"id": "admin.permissions.systemScheme.channelAdminsTitle",
}
}
>
<Connect(PermissionsTree)
onToggle={[Function]}
@ -901,13 +1049,20 @@ exports[`components/admin_console/permission_schemes_settings/permission_team_sc
</AdminPanelTogglable>
<AdminPanelTogglable
className="permissions-block"
isDisabled={false}
onToggle={[Function]}
open={true}
subtitleDefault="Permissions granted to administrators of a playbook."
subtitleId="admin.permissions.systemScheme.playbookAdminSubtitle"
titleDefault="Playbook Administrator"
titleId="admin.permissions.systemScheme.playbookAdmin"
subtitle={
Object {
"defaultMessage": "Permissions granted to administrators of a playbook.",
"id": "admin.permissions.systemScheme.playbookAdminSubtitle",
}
}
title={
Object {
"defaultMessage": "Playbook Administrator",
"id": "admin.permissions.systemScheme.playbookAdmin",
}
}
>
<PermissionsTreePlaybooks
license={
@ -937,13 +1092,20 @@ exports[`components/admin_console/permission_schemes_settings/permission_team_sc
</AdminPanelTogglable>
<AdminPanelTogglable
className="permissions-block team_admin"
isDisabled={false}
onToggle={[Function]}
open={true}
subtitleDefault="Permissions granted to team creators and any users promoted to Team Administrator."
subtitleId="admin.permissions.systemScheme.teamAdminsDescription"
titleDefault="Team Administrators"
titleId="admin.permissions.systemScheme.teamAdminsTitle"
subtitle={
Object {
"defaultMessage": "Permissions granted to team creators and any users promoted to Team Administrator.",
"id": "admin.permissions.systemScheme.teamAdminsDescription",
}
}
title={
Object {
"defaultMessage": "Team Administrators",
"id": "admin.permissions.systemScheme.teamAdminsTitle",
}
}
>
<Connect(PermissionsTree)
onToggle={[Function]}
@ -981,7 +1143,12 @@ exports[`components/admin_console/permission_schemes_settings/permission_team_sc
extraClasses=""
onClick={[Function]}
saving={false}
savingMessage="Saving Config..."
savingMessage={
<Memo(MemoizedFormattedMessage)
defaultMessage="Saving"
id="save_button.saving"
/>
}
/>
<Connect(Component)
className="cancel-button"
@ -1157,11 +1324,18 @@ exports[`components/admin_console/permission_schemes_settings/permission_team_sc
</div>
</div>
<AdminPanel
className=""
subtitleDefault="Set the name and description for this scheme."
subtitleId="admin.permissions.teamScheme.schemeDetailsDescription"
titleDefault="Scheme Details"
titleId="admin.permissions.teamScheme.schemeDetailsTitle"
subtitle={
Object {
"defaultMessage": "Set the name and description for this scheme.",
"id": "admin.permissions.teamScheme.schemeDetailsDescription",
}
}
title={
Object {
"defaultMessage": "Scheme Details",
"id": "admin.permissions.teamScheme.schemeDetailsTitle",
}
}
>
<div
className="team-scheme-details"
@ -1204,7 +1378,6 @@ exports[`components/admin_console/permission_schemes_settings/permission_team_sc
disabled={false}
id="scheme-description"
onChange={[Function]}
placeholder="Scheme Description"
rows={5}
value=""
/>
@ -1212,15 +1385,27 @@ exports[`components/admin_console/permission_schemes_settings/permission_team_sc
</div>
</AdminPanel>
<AdminPanelWithButton
buttonTextDefault="Add Teams"
buttonTextId="admin.permissions.teamScheme.addTeams"
buttonText={
Object {
"defaultMessage": "Add Teams",
"id": "admin.permissions.teamScheme.addTeams",
}
}
className="permissions-block"
disabled={false}
onButtonClick={[Function]}
subtitleDefault="Select teams where permission exceptions are required."
subtitleId="admin.permissions.teamScheme.selectTeamsDescription"
titleDefault="Select teams to override permissions"
titleId="admin.permissions.teamScheme.selectTeamsTitle"
subtitle={
Object {
"defaultMessage": "Select teams where permission exceptions are required.",
"id": "admin.permissions.teamScheme.selectTeamsDescription",
}
}
title={
Object {
"defaultMessage": "Select teams to override permissions",
"id": "admin.permissions.teamScheme.selectTeamsTitle",
}
}
>
<div
className="teams-list"
@ -1238,13 +1423,20 @@ exports[`components/admin_console/permission_schemes_settings/permission_team_sc
<AdminPanelTogglable
className="permissions-block"
id="guests"
isDisabled={false}
onToggle={[Function]}
open={true}
subtitleDefault="Permissions granted to guest users."
subtitleId="admin.permissions.systemScheme.GuestsDescription"
titleDefault="Guests"
titleId="admin.permissions.systemScheme.GuestsTitle"
subtitle={
Object {
"defaultMessage": "Permissions granted to guest users.",
"id": "admin.permissions.systemScheme.GuestsDescription",
}
}
title={
Object {
"defaultMessage": "Guests",
"id": "admin.permissions.systemScheme.GuestsTitle",
}
}
>
<Connect(GuestPermissionsTree)
onToggle={[Function]}
@ -1263,13 +1455,20 @@ exports[`components/admin_console/permission_schemes_settings/permission_team_sc
<AdminPanelTogglable
className="permissions-block all_users"
id="all_users"
isDisabled={false}
onToggle={[Function]}
open={true}
subtitleDefault="Permissions granted to all members, including administrators and newly created users."
subtitleId="admin.permissions.systemScheme.allMembersDescription"
titleDefault="All Members"
titleId="admin.permissions.systemScheme.allMembersTitle"
subtitle={
Object {
"defaultMessage": "Permissions granted to all members, including administrators and newly created users.",
"id": "admin.permissions.systemScheme.allMembersDescription",
}
}
title={
Object {
"defaultMessage": "All Members",
"id": "admin.permissions.systemScheme.allMembersTitle",
}
}
>
<Connect(PermissionsTree)
onToggle={[Function]}
@ -1287,13 +1486,20 @@ exports[`components/admin_console/permission_schemes_settings/permission_team_sc
</AdminPanelTogglable>
<AdminPanelTogglable
className="permissions-block channel_admin"
isDisabled={false}
onToggle={[Function]}
open={true}
subtitleDefault="Permissions granted to channel creators and any users promoted to Channel Administrator."
subtitleId="admin.permissions.systemScheme.channelAdminsDescription"
titleDefault="Channel Administrators"
titleId="admin.permissions.systemScheme.channelAdminsTitle"
subtitle={
Object {
"defaultMessage": "Permissions granted to channel creators and any users promoted to Channel Administrator.",
"id": "admin.permissions.systemScheme.channelAdminsDescription",
}
}
title={
Object {
"defaultMessage": "Channel Administrators",
"id": "admin.permissions.systemScheme.channelAdminsTitle",
}
}
>
<Connect(PermissionsTree)
onToggle={[Function]}
@ -1316,13 +1522,20 @@ exports[`components/admin_console/permission_schemes_settings/permission_team_sc
</AdminPanelTogglable>
<AdminPanelTogglable
className="permissions-block"
isDisabled={false}
onToggle={[Function]}
open={true}
subtitleDefault="Permissions granted to administrators of a playbook."
subtitleId="admin.permissions.systemScheme.playbookAdminSubtitle"
titleDefault="Playbook Administrator"
titleId="admin.permissions.systemScheme.playbookAdmin"
subtitle={
Object {
"defaultMessage": "Permissions granted to administrators of a playbook.",
"id": "admin.permissions.systemScheme.playbookAdminSubtitle",
}
}
title={
Object {
"defaultMessage": "Playbook Administrator",
"id": "admin.permissions.systemScheme.playbookAdmin",
}
}
>
<PermissionsTreePlaybooks
license={
@ -1352,13 +1565,20 @@ exports[`components/admin_console/permission_schemes_settings/permission_team_sc
</AdminPanelTogglable>
<AdminPanelTogglable
className="permissions-block team_admin"
isDisabled={false}
onToggle={[Function]}
open={true}
subtitleDefault="Permissions granted to team creators and any users promoted to Team Administrator."
subtitleId="admin.permissions.systemScheme.teamAdminsDescription"
titleDefault="Team Administrators"
titleId="admin.permissions.systemScheme.teamAdminsTitle"
subtitle={
Object {
"defaultMessage": "Permissions granted to team creators and any users promoted to Team Administrator.",
"id": "admin.permissions.systemScheme.teamAdminsDescription",
}
}
title={
Object {
"defaultMessage": "Team Administrators",
"id": "admin.permissions.systemScheme.teamAdminsTitle",
}
}
>
<Connect(PermissionsTree)
onToggle={[Function]}
@ -1396,7 +1616,12 @@ exports[`components/admin_console/permission_schemes_settings/permission_team_sc
extraClasses=""
onClick={[Function]}
saving={false}
savingMessage="Saving Config..."
savingMessage={
<Memo(MemoizedFormattedMessage)
defaultMessage="Saving"
id="save_button.saving"
/>
}
/>
<Connect(Component)
className="cancel-button"

View File

@ -1,11 +1,19 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {shallow} from 'enzyme';
import React from 'react';
import {PermissionTeamSchemeSettings} from 'components/admin_console/permission_schemes_settings/permission_team_scheme_settings/permission_team_scheme_settings';
import PermissionTeamSchemeSettings from 'components/admin_console/permission_schemes_settings/permission_team_scheme_settings/permission_team_scheme_settings';
import {shallowWithIntl} from 'tests/helpers/intl-test-helper';
function getAnyInstance(wrapper: any) {
return wrapper.instance() as any;
}
function getAnyState(wrapper: any) {
return wrapper.state() as any;
}
describe('components/admin_console/permission_schemes_settings/permission_team_scheme_settings/permission_team_scheme_settings', () => {
const defaultProps = {
config: {
@ -110,11 +118,11 @@ describe('components/admin_console/permission_schemes_settings/permission_team_s
} as any;
test('should match snapshot on new with default roles without permissions', (done) => {
const wrapper = shallow<PermissionTeamSchemeSettings>(
const wrapper = shallowWithIntl(
<PermissionTeamSchemeSettings {...defaultProps}/>,
);
defaultProps.actions.loadRolesIfNeeded().then(() => {
expect(wrapper.instance().getStateRoles()).toMatchSnapshot();
expect(getAnyInstance(wrapper).getStateRoles()).toMatchSnapshot();
done();
});
});
@ -149,7 +157,7 @@ describe('components/admin_console/permission_schemes_settings/permission_team_s
permissions: ['delete_post'],
},
};
const wrapper = shallow(
const wrapper = shallowWithIntl(
<PermissionTeamSchemeSettings
{...defaultProps}
roles={roles}
@ -158,7 +166,7 @@ describe('components/admin_console/permission_schemes_settings/permission_team_s
expect(wrapper).toMatchSnapshot();
defaultProps.actions.loadRolesIfNeeded().then(() => {
expect(wrapper.state()).toMatchSnapshot();
expect(getAnyState(wrapper)).toMatchSnapshot();
done();
});
});
@ -181,7 +189,7 @@ describe('components/admin_console/permission_schemes_settings/permission_team_s
},
}));
const updateTeamScheme = jest.fn().mockImplementation(() => Promise.resolve({}));
const wrapper = shallow<PermissionTeamSchemeSettings>(
const wrapper = shallowWithIntl(
<PermissionTeamSchemeSettings
{...defaultProps}
actions={{...defaultProps.actions, editRole, createScheme, updateTeamScheme}}
@ -189,7 +197,7 @@ describe('components/admin_console/permission_schemes_settings/permission_team_s
);
expect(wrapper).toMatchSnapshot();
await wrapper.instance().handleSubmit();
await getAnyInstance(wrapper).handleSubmit();
expect(editRole).toHaveBeenCalledTimes(9);
});
@ -197,15 +205,15 @@ describe('components/admin_console/permission_schemes_settings/permission_team_s
const editRole = jest.fn().mockImplementation(() => Promise.resolve({}));
const createScheme = jest.fn().mockImplementation(() => Promise.resolve({error: {message: 'test error'}}));
const updateTeamScheme = jest.fn().mockImplementation(() => Promise.resolve({}));
const wrapper = shallow<PermissionTeamSchemeSettings>(
const wrapper = shallowWithIntl(
<PermissionTeamSchemeSettings
{...defaultProps}
actions={{...defaultProps.actions, editRole, createScheme, updateTeamScheme}}
/>,
);
await wrapper.instance().handleSubmit();
expect(wrapper.state().serverError).toBe('test error');
await getAnyInstance(wrapper).handleSubmit();
expect(getAnyState(wrapper).serverError).toBe('test error');
});
test('should show error if editRole fails', async () => {
@ -226,45 +234,45 @@ describe('components/admin_console/permission_schemes_settings/permission_team_s
},
}));
const updateTeamScheme = jest.fn().mockImplementation(() => Promise.resolve({}));
const wrapper = shallow<PermissionTeamSchemeSettings>(
const wrapper = shallowWithIntl(
<PermissionTeamSchemeSettings
{...defaultProps}
actions={{...defaultProps.actions, editRole, createScheme, updateTeamScheme}}
/>,
);
await wrapper.instance().handleSubmit();
expect(wrapper.state().serverError).toBe('test error');
await getAnyInstance(wrapper).handleSubmit();
expect(getAnyState(wrapper).serverError).toBe('test error');
});
test('should open and close correctly roles blocks', () => {
const wrapper = shallow<PermissionTeamSchemeSettings>(
const wrapper = shallowWithIntl(
<PermissionTeamSchemeSettings {...defaultProps}/>,
);
const instance = wrapper.instance();
expect(wrapper.state().openRoles.guests).toBe(true);
const instance = getAnyInstance(wrapper);
expect(getAnyState(wrapper).openRoles.guests).toBe(true);
instance.toggleRole('guests');
expect(wrapper.state().openRoles.guests).toBe(false);
expect(getAnyState(wrapper).openRoles.guests).toBe(false);
instance.toggleRole('guests');
expect(wrapper.state().openRoles.guests).toBe(true);
expect(getAnyState(wrapper).openRoles.guests).toBe(true);
expect(wrapper.state().openRoles.all_users).toBe(true);
expect(getAnyState(wrapper).openRoles.all_users).toBe(true);
instance.toggleRole('all_users');
expect(wrapper.state().openRoles.all_users).toBe(false);
expect(getAnyState(wrapper).openRoles.all_users).toBe(false);
instance.toggleRole('all_users');
expect(wrapper.state().openRoles.all_users).toBe(true);
expect(getAnyState(wrapper).openRoles.all_users).toBe(true);
expect(wrapper.state().openRoles.channel_admin).toBe(true);
expect(getAnyState(wrapper).openRoles.channel_admin).toBe(true);
instance.toggleRole('channel_admin');
expect(wrapper.state().openRoles.channel_admin).toBe(false);
expect(getAnyState(wrapper).openRoles.channel_admin).toBe(false);
instance.toggleRole('channel_admin');
expect(wrapper.state().openRoles.channel_admin).toBe(true);
expect(getAnyState(wrapper).openRoles.channel_admin).toBe(true);
expect(wrapper.state().openRoles.team_admin).toBe(true);
expect(getAnyState(wrapper).openRoles.team_admin).toBe(true);
instance.toggleRole('team_admin');
expect(wrapper.state().openRoles.team_admin).toBe(false);
expect(getAnyState(wrapper).openRoles.team_admin).toBe(false);
instance.toggleRole('team_admin');
expect(wrapper.state().openRoles.team_admin).toBe(true);
expect(getAnyState(wrapper).openRoles.team_admin).toBe(true);
});
test('should match snapshot on edit without permissions', (done) => {
@ -289,12 +297,12 @@ describe('components/admin_console/permission_schemes_settings/permission_team_s
},
};
const wrapper = shallow<PermissionTeamSchemeSettings>(
const wrapper = shallowWithIntl(
<PermissionTeamSchemeSettings {...props}/>,
);
expect(wrapper).toMatchSnapshot();
defaultProps.actions.loadRolesIfNeeded().then(() => {
expect(wrapper.instance().getStateRoles()).toMatchSnapshot();
expect(getAnyInstance(wrapper).getStateRoles()).toMatchSnapshot();
done();
});
});
@ -344,12 +352,12 @@ describe('components/admin_console/permission_schemes_settings/permission_team_s
},
};
const wrapper = shallow<PermissionTeamSchemeSettings>(
const wrapper = shallowWithIntl(
<PermissionTeamSchemeSettings {...props}/>,
);
expect(wrapper).toMatchSnapshot();
defaultProps.actions.loadRolesIfNeeded().then(() => {
expect(wrapper.instance().getStateRoles()).toMatchSnapshot();
expect(getAnyInstance(wrapper).getStateRoles()).toMatchSnapshot();
done();
});
});
@ -379,12 +387,12 @@ describe('components/admin_console/permission_schemes_settings/permission_team_s
},
};
const wrapper = shallow<PermissionTeamSchemeSettings>(
const wrapper = shallowWithIntl(
<PermissionTeamSchemeSettings {...props}/>,
);
expect(wrapper).toMatchSnapshot();
defaultProps.actions.loadRolesIfNeeded().then(() => {
expect(wrapper.instance().getStateRoles()).toMatchSnapshot();
expect(getAnyInstance(wrapper).getStateRoles()).toMatchSnapshot();
done();
});
});
@ -414,12 +422,12 @@ describe('components/admin_console/permission_schemes_settings/permission_team_s
},
};
const wrapper = shallow<PermissionTeamSchemeSettings>(
const wrapper = shallowWithIntl(
<PermissionTeamSchemeSettings {...props}/>,
);
expect(wrapper).toMatchSnapshot();
defaultProps.actions.loadRolesIfNeeded().then(() => {
expect(wrapper.instance().getStateRoles()).toMatchSnapshot();
expect(getAnyInstance(wrapper).getStateRoles()).toMatchSnapshot();
done();
});
});

View File

@ -2,7 +2,8 @@
// See LICENSE.txt for license information.
import React from 'react';
import {FormattedMessage, injectIntl, type IntlShape} from 'react-intl';
import {defineMessage, FormattedMessage, injectIntl} from 'react-intl';
import type {WrappedComponentProps} from 'react-intl';
import type {RouteComponentProps} from 'react-router-dom';
import type {ClientConfig, ClientLicense} from '@mattermost/types/config';
@ -25,8 +26,6 @@ import AdminPanelTogglable from 'components/widgets/admin_console/admin_panel_to
import AdminPanelWithButton from 'components/widgets/admin_console/admin_panel_with_button';
import {PermissionsScope, ModalIdentifiers, DocLinks} from 'utils/constants';
import {t} from 'utils/i18n';
import {localizeMessage} from 'utils/utils';
import TeamInList from './team_in_list';
@ -46,7 +45,6 @@ export type Props = {
teams: Team[] | null;
isDisabled: boolean;
config: Partial<ClientConfig>;
intl: IntlShape;
actions: {
loadRolesIfNeeded: (roles: Iterable<string>) => Promise<ActionResult>;
loadScheme: (schemeId: string) => Promise<ActionResult>;
@ -57,7 +55,7 @@ export type Props = {
createScheme: (scheme: Scheme) => Promise<ActionResult>;
setNavigationBlocked: (blocked: boolean) => void;
};
}
} & WrappedComponentProps;
type State = {
saving: boolean;
@ -81,7 +79,7 @@ type State = {
schemeDescription: string | undefined;
};
export class PermissionTeamSchemeSettings extends React.PureComponent<Props & RouteComponentProps, State> {
class PermissionTeamSchemeSettings extends React.PureComponent<Props & RouteComponentProps, State> {
constructor(props: Props & RouteComponentProps) {
super(props);
this.state = {
@ -633,10 +631,8 @@ export class PermissionTeamSchemeSettings extends React.PureComponent<Props & Ro
</div>
<AdminPanel
titleId={t('admin.permissions.teamScheme.schemeDetailsTitle')}
titleDefault='Scheme Details'
subtitleId={t('admin.permissions.teamScheme.schemeDetailsDescription')}
subtitleDefault='Set the name and description for this scheme.'
title={defineMessage({id: 'admin.permissions.teamScheme.schemeDetailsTitle', defaultMessage: 'Scheme Details'})}
subtitle={defineMessage({id: 'admin.permissions.teamScheme.schemeDetailsDescription', defaultMessage: 'Set the name and description for this scheme.'})}
>
<div className='team-scheme-details'>
<div className='form-group'>
@ -674,7 +670,7 @@ export class PermissionTeamSchemeSettings extends React.PureComponent<Props & Ro
className='form-control'
rows={5}
value={schemeDescription}
placeholder={localizeMessage('admin.permissions.teamScheme.schemeDescriptionPlaceholder', 'Scheme Description')}
placeholder={this.props.intl.formatMessage({id: 'admin.permissions.teamScheme.schemeDescriptionPlaceholder', defaultMessage: 'Scheme Description'})}
onChange={this.handleDescriptionChange}
disabled={this.props.isDisabled}
/>
@ -684,13 +680,10 @@ export class PermissionTeamSchemeSettings extends React.PureComponent<Props & Ro
<AdminPanelWithButton
className='permissions-block'
titleId={t('admin.permissions.teamScheme.selectTeamsTitle')}
titleDefault='Select teams to override permissions'
subtitleId={t('admin.permissions.teamScheme.selectTeamsDescription')}
subtitleDefault='Select teams where permission exceptions are required.'
title={defineMessage({id: 'admin.permissions.teamScheme.selectTeamsTitle', defaultMessage: 'Select teams to override permissions'})}
subtitle={defineMessage({id: 'admin.permissions.teamScheme.selectTeamsDescription', defaultMessage: 'Select teams where permission exceptions are required.'})}
onButtonClick={this.openAddTeam}
buttonTextId={t('admin.permissions.teamScheme.addTeams')}
buttonTextDefault='Add Teams'
buttonText={defineMessage({id: 'admin.permissions.teamScheme.addTeams', defaultMessage: 'Add Teams'})}
disabled={this.props.isDisabled}
>
<div className='teams-list'>
@ -718,11 +711,8 @@ export class PermissionTeamSchemeSettings extends React.PureComponent<Props & Ro
open={this.state.openRoles.guests}
id='guests'
onToggle={() => this.toggleRole('guests')}
titleId={t('admin.permissions.systemScheme.GuestsTitle')}
titleDefault='Guests'
subtitleId={t('admin.permissions.systemScheme.GuestsDescription')}
subtitleDefault='Permissions granted to guest users.'
isDisabled={this.props.isDisabled}
title={defineMessage({id: 'admin.permissions.systemScheme.GuestsTitle', defaultMessage: 'Guests'})}
subtitle={defineMessage({id: 'admin.permissions.systemScheme.GuestsDescription', defaultMessage: 'Permissions granted to guest users.'})}
>
<GuestPermissionsTree
selected={this.state.selectedPermission}
@ -740,11 +730,8 @@ export class PermissionTeamSchemeSettings extends React.PureComponent<Props & Ro
open={this.state.openRoles.all_users}
id='all_users'
onToggle={() => this.toggleRole('all_users')}
titleId={t('admin.permissions.systemScheme.allMembersTitle')}
titleDefault='All Members'
subtitleId={t('admin.permissions.systemScheme.allMembersDescription')}
subtitleDefault='Permissions granted to all members, including administrators and newly created users.'
isDisabled={this.props.isDisabled}
title={defineMessage({id: 'admin.permissions.systemScheme.allMembersTitle', defaultMessage: 'All Members'})}
subtitle={defineMessage({id: 'admin.permissions.systemScheme.allMembersDescription', defaultMessage: 'Permissions granted to all members, including administrators and newly created users.'})}
>
<PermissionsTree
selected={this.state.selectedPermission}
@ -760,11 +747,8 @@ export class PermissionTeamSchemeSettings extends React.PureComponent<Props & Ro
className='permissions-block channel_admin'
open={this.state.openRoles.channel_admin}
onToggle={() => this.toggleRole('channel_admin')}
titleId={t('admin.permissions.systemScheme.channelAdminsTitle')}
titleDefault='Channel Administrators'
subtitleId={t('admin.permissions.systemScheme.channelAdminsDescription')}
subtitleDefault='Permissions granted to channel creators and any users promoted to Channel Administrator.'
isDisabled={this.props.isDisabled}
title={defineMessage({id: 'admin.permissions.systemScheme.channelAdminsTitle', defaultMessage: 'Channel Administrators'})}
subtitle={defineMessage({id: 'admin.permissions.systemScheme.channelAdminsDescription', defaultMessage: 'Permissions granted to channel creators and any users promoted to Channel Administrator.'})}
>
<PermissionsTree
parentRole={roles?.all_users}
@ -780,11 +764,8 @@ export class PermissionTeamSchemeSettings extends React.PureComponent<Props & Ro
className='permissions-block'
open={this.state.openRoles.playbook_admin}
onToggle={() => this.toggleRole('playbook_admin')}
titleId={t('admin.permissions.systemScheme.playbookAdmin')}
titleDefault='Playbook Administrator'
subtitleId={t('admin.permissions.systemScheme.playbookAdminSubtitle')}
subtitleDefault='Permissions granted to administrators of a playbook.'
isDisabled={this.props.isDisabled}
title={defineMessage({id: 'admin.permissions.systemScheme.playbookAdmin', defaultMessage: 'Playbook Administrator'})}
subtitle={defineMessage({id: 'admin.permissions.systemScheme.playbookAdminSubtitle', defaultMessage: 'Permissions granted to administrators of a playbook.'})}
>
<PermissionsTreePlaybooks
parentRole={roles?.all_users}
@ -801,11 +782,8 @@ export class PermissionTeamSchemeSettings extends React.PureComponent<Props & Ro
className='permissions-block team_admin'
open={this.state.openRoles.team_admin}
onToggle={() => this.toggleRole('team_admin')}
titleId={t('admin.permissions.systemScheme.teamAdminsTitle')}
titleDefault='Team Administrators'
subtitleId={t('admin.permissions.systemScheme.teamAdminsDescription')}
subtitleDefault='Permissions granted to team creators and any users promoted to Team Administrator.'
isDisabled={this.props.isDisabled}
title={defineMessage({id: 'admin.permissions.systemScheme.teamAdminsTitle', defaultMessage: 'Team Administrators'})}
subtitle={defineMessage({id: 'admin.permissions.systemScheme.teamAdminsDescription', defaultMessage: 'Permissions granted to team creators and any users promoted to Team Administrator.'})}
>
<PermissionsTree
parentRole={roles?.all_users}
@ -824,7 +802,7 @@ export class PermissionTeamSchemeSettings extends React.PureComponent<Props & Ro
saving={this.state.saving}
disabled={this.props.isDisabled || !this.state.saveNeeded}
onClick={this.handleSubmit}
savingMessage={localizeMessage('admin.saving', 'Saving Config...')}
savingMessage={this.props.intl.formatMessage({id: 'admin.saving', defaultMessage: 'Saving Config...'})}
/>
<BlockableLink
className='cancel-button'

View File

@ -0,0 +1,258 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import type {MessageDescriptor} from 'react-intl';
import {defineMessages} from 'react-intl';
export const groupRolesStrings: Record<string, Record<string, MessageDescriptor>> = {
delete_posts: defineMessages({
name: {
id: 'admin.permissions.group.delete_posts.name',
defaultMessage: 'Delete Posts',
},
description: {
id: 'admin.permissions.group.delete_posts.description',
defaultMessage: 'Delete own and others\' posts.',
},
}),
integrations: defineMessages({
name: {
id: 'admin.permissions.group.integrations.name',
defaultMessage: 'Integrations & Customizations',
},
description: {
id: 'admin.permissions.group.integrations.description',
defaultMessage: 'Manage OAuth 2.0, slash commands, webhooks and emoji.',
},
}),
posts: defineMessages({
name: {
id: 'admin.permissions.group.posts.name',
defaultMessage: 'Manage Posts',
},
description: {
id: 'admin.permissions.group.posts.description',
defaultMessage: 'Write, edit and delete posts.',
},
}),
private_channel: defineMessages({
name: {
id: 'admin.permissions.group.private_channel.name',
defaultMessage: 'Manage Private Channels',
},
description: {
id: 'admin.permissions.group.private_channel.description',
defaultMessage: 'Create and archive channels, manage settings and members.',
},
}),
public_channel: defineMessages({
name: {
id: 'admin.permissions.group.public_channel.name',
defaultMessage: 'Manage Public Channels',
},
description: {
id: 'admin.permissions.group.public_channel.description',
defaultMessage: 'Join, create and archive channels, manage settings and members.',
},
}),
reactions: defineMessages({
name: {
id: 'admin.permissions.group.reactions.name',
defaultMessage: 'Post Reactions',
},
description: {
id: 'admin.permissions.group.reactions.description',
defaultMessage: 'Add and delete reactions on posts.',
},
}),
send_invites: defineMessages({
name: {
id: 'admin.permissions.group.send_invites.name',
defaultMessage: 'Add Team Members',
},
description: {
id: 'admin.permissions.group.send_invites.description',
defaultMessage: 'Add team members, send email invites and share team invite link.',
},
}),
teams: defineMessages({
name: {
id: 'admin.permissions.group.teams.name',
defaultMessage: 'Teams',
},
description: {
id: 'admin.permissions.group.teams.description',
defaultMessage: 'Create teams and manage members.',
},
}),
edit_posts: defineMessages({
name: {
id: 'admin.permissions.group.edit_posts.name',
defaultMessage: 'Edit Posts',
},
description: {
id: 'admin.permissions.group.edit_posts.description',
defaultMessage: 'Edit own and others\' posts.',
},
}),
teams_team_scope: defineMessages({
name: {
id: 'admin.permissions.group.teams_team_scope.name',
defaultMessage: 'Teams',
},
description: {
id: 'admin.permissions.group.teams_team_scope.description',
defaultMessage: 'Manage team members.',
},
}),
guest_reactions: defineMessages({
name: {
id: 'admin.permissions.group.guest_reactions.name',
defaultMessage: 'Post Reactions',
},
description: {
id: 'admin.permissions.group.guest_reactions.description',
defaultMessage: 'Add and delete reactions on posts.',
},
}),
guest_create_post: defineMessages({
name: {
id: 'admin.permissions.group.guest_create_post.name',
defaultMessage: 'Create Posts',
},
description: {
id: 'admin.permissions.group.guest_create_post.description',
defaultMessage: 'Allow users to create posts.',
},
}),
guest_create_private_channel: defineMessages({
name: {
id: 'admin.permissions.group.guest_create_private_channel.name',
defaultMessage: 'Create Channels',
},
description: {
id: 'admin.permissions.group.guest_create_private_channel.description',
defaultMessage: 'Create new private channels.',
},
}),
guest_delete_post: defineMessages({
name: {
id: 'admin.permissions.group.guest_delete_post.name',
defaultMessage: 'Delete Own Posts',
},
description: {
id: 'admin.permissions.group.guest_delete_post.description',
defaultMessage: 'Author\'s own posts can be deleted.',
},
}),
guest_edit_post: defineMessages({
name: {
id: 'admin.permissions.group.guest_edit_post.name',
defaultMessage: 'Edit Own Posts',
},
description: {
id: 'admin.permissions.group.guest_edit_post.description',
defaultMessage: '{editTimeLimitButton} after posting, allow users to edit their own posts.',
},
}),
guest_use_channel_mentions: defineMessages({
name: {
id: 'admin.permissions.group.guest_use_channel_mentions.name',
defaultMessage: 'Channel Mentions',
},
description: {
id: 'admin.permissions.group.guest_use_channel_mentions.description',
defaultMessage: 'Notify channel members with @all, @channel and @here',
},
}),
guest_use_group_mentions: defineMessages({
name: {
id: 'admin.permissions.group.guest_use_group_mentions.name',
defaultMessage: 'Group Mentions',
},
description: {
id: 'admin.permissions.group.guest_use_group_mentions.description',
defaultMessage: 'Notify group members with a group mention',
},
}),
manage_private_channel_members_and_read_groups: defineMessages({
name: {
id: 'admin.permissions.group.manage_private_channel_members_and_read_groups.name',
defaultMessage: 'Manage Channel Members',
},
description: {
id: 'admin.permissions.group.manage_private_channel_members_and_read_groups.description',
defaultMessage: 'Add and remove private channel members.',
},
}),
manage_public_channel_members_and_read_groups: defineMessages({
name: {
id: 'admin.permissions.group.manage_public_channel_members_and_read_groups.name',
defaultMessage: 'Manage Channel Members',
},
description: {
id: 'admin.permissions.group.manage_public_channel_members_and_read_groups.description',
defaultMessage: 'Add and remove public channel members.',
},
}),
convert_public_channel_to_private: defineMessages({
name: {
id: 'admin.permissions.group.convert_public_channel_to_private.name',
defaultMessage: 'Convert Channels',
},
description: {
id: 'admin.permissions.group.convert_public_channel_to_private.description',
defaultMessage: 'Convert public channels to private',
},
}),
manage_shared_channels: defineMessages({
name: {
id: 'admin.permissions.group.manage_shared_channels.name',
defaultMessage: 'Shared Channels',
},
description: {
id: 'admin.permissions.group.manage_shared_channels.description',
defaultMessage: 'Manage Shared Channels',
},
}),
playbook_public: defineMessages({
name: {
id: 'admin.permissions.group.playbook_public.name',
defaultMessage: 'Manage Public Playbooks',
},
description: {
id: 'admin.permissions.group.playbook_public.description',
defaultMessage: 'Manage public playbooks.',
},
}),
playbook_private: defineMessages({
name: {
id: 'admin.permissions.group.playbook_private.name',
defaultMessage: 'Manage Private Playbooks',
},
description: {
id: 'admin.permissions.group.playbook_private.description',
defaultMessage: 'Manage private playbooks.',
},
}),
runs: defineMessages({
name: {
id: 'admin.permissions.group.runs.name',
defaultMessage: 'Manage Runs',
},
description: {
id: 'admin.permissions.group.runs.description',
defaultMessage: 'Manage runs.',
},
}),
custom_groups: defineMessages({
name: {
id: 'admin.permissions.group.custom_groups.name',
defaultMessage: 'Custom Groups',
},
description: {
id: 'admin.permissions.group.custom_groups.description',
defaultMessage: 'Create, edit, delete and manage the members of custom groups.',
},
}),
};

View File

@ -0,0 +1,618 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import type {MessageDescriptor} from 'react-intl';
import {defineMessages} from 'react-intl';
export const permissionRolesStrings: Record<string, Record<string, MessageDescriptor>> = {
assign_system_admin_role: defineMessages({
name: {
id: 'admin.permissions.permission.assign_system_admin_role.name',
defaultMessage: 'Assign system admin role',
},
description: {
id: 'admin.permissions.permission.assign_system_admin_role.description',
defaultMessage: 'Assign system admin role',
},
}),
convert_public_channel_to_private: defineMessages({
name: {
id: 'admin.permissions.permission.convert_public_channel_to_private.name',
defaultMessage: 'Convert Channels',
},
description: {
id: 'admin.permissions.permission.convert_public_channel_to_private.description',
defaultMessage: 'Convert public channels to private',
},
}),
convert_private_channel_to_public: defineMessages({
name: {
id: 'admin.permissions.permission.convert_private_channel_to_public.name',
defaultMessage: 'Convert Channels',
},
description: {
id: 'admin.permissions.permission.convert_private_channel_to_public.description',
defaultMessage: 'Convert private channels to public',
},
}),
create_direct_channel: defineMessages({
name: {
id: 'admin.permissions.permission.create_direct_channel.name',
defaultMessage: 'Create direct channel',
},
description: {
id: 'admin.permissions.permission.create_direct_channel.description',
defaultMessage: 'Create direct channel',
},
}),
create_group_channel: defineMessages({
name: {
id: 'admin.permissions.permission.create_group_channel.name',
defaultMessage: 'Create group channel',
},
description: {
id: 'admin.permissions.permission.create_group_channel.description',
defaultMessage: 'Create group channel',
},
}),
create_post: defineMessages({
name: {
id: 'admin.permissions.permission.create_post.name',
defaultMessage: 'Create Posts',
},
description: {
id: 'admin.permissions.permission.create_post.description',
defaultMessage: 'Allow users to create posts.',
},
}),
create_private_channel: defineMessages({
name: {
id: 'admin.permissions.permission.create_private_channel.name',
defaultMessage: 'Create Channels',
},
description: {
id: 'admin.permissions.permission.create_private_channel.description',
defaultMessage: 'Create new private channels.',
},
}),
create_public_channel: defineMessages({
name: {
id: 'admin.permissions.permission.create_public_channel.name',
defaultMessage: 'Create Channels',
},
description: {
id: 'admin.permissions.permission.create_public_channel.description',
defaultMessage: 'Create new public channels.',
},
}),
create_team: defineMessages({
name: {
id: 'admin.permissions.permission.create_team.name',
defaultMessage: 'Create Teams',
},
description: {
id: 'admin.permissions.permission.create_team.description',
defaultMessage: 'Create new teams.',
},
}),
create_user_access_token: defineMessages({
name: {
id: 'admin.permissions.permission.create_user_access_token.name',
defaultMessage: 'Create user access token',
},
description: {
id: 'admin.permissions.permission.create_user_access_token.description',
defaultMessage: 'Create user access token',
},
}),
delete_others_posts: defineMessages({
name: {
id: 'admin.permissions.permission.delete_others_posts.name',
defaultMessage: 'Delete Others\' Posts',
},
description: {
id: 'admin.permissions.permission.delete_others_posts.description',
defaultMessage: 'Posts made by other users can be deleted.',
},
}),
delete_post: defineMessages({
name: {
id: 'admin.permissions.permission.delete_post.name',
defaultMessage: 'Delete Own Posts',
},
description: {
id: 'admin.permissions.permission.delete_post.description',
defaultMessage: 'Author\'s own posts can be deleted.',
},
}),
delete_private_channel: defineMessages({
name: {
id: 'admin.permissions.permission.delete_private_channel.name',
defaultMessage: 'Archive Channels',
},
description: {
id: 'admin.permissions.permission.delete_private_channel.description',
defaultMessage: 'Archive private channels.',
},
}),
delete_public_channel: defineMessages({
name: {
id: 'admin.permissions.permission.delete_public_channel.name',
defaultMessage: 'Archive Channels',
},
description: {
id: 'admin.permissions.permission.delete_public_channel.description',
defaultMessage: 'Archive public channels.',
},
}),
edit_other_users: defineMessages({
name: {
id: 'admin.permissions.permission.edit_other_users.name',
defaultMessage: 'Edit other users',
},
description: {
id: 'admin.permissions.permission.edit_other_users.description',
defaultMessage: 'Edit other users',
},
}),
edit_post: defineMessages({
name: {
id: 'admin.permissions.permission.edit_post.name',
defaultMessage: 'Edit Own Posts',
},
description: {
id: 'admin.permissions.permission.edit_post.description',
defaultMessage: '{editTimeLimitButton} after posting, allow users to edit their own posts.',
},
}),
import_team: defineMessages({
name: {
id: 'admin.permissions.permission.import_team.name',
defaultMessage: 'Import team',
},
description: {
id: 'admin.permissions.permission.import_team.description',
defaultMessage: 'Import team',
},
}),
list_team_channels: defineMessages({
name: {
id: 'admin.permissions.permission.list_team_channels.name',
defaultMessage: 'List team channels',
},
description: {
id: 'admin.permissions.permission.list_team_channels.description',
defaultMessage: 'List team channels',
},
}),
list_users_without_team: defineMessages({
name: {
id: 'admin.permissions.permission.list_users_without_team.name',
defaultMessage: 'List users without team',
},
description: {
id: 'admin.permissions.permission.list_users_without_team.description',
defaultMessage: 'List users without team',
},
}),
manage_channel_roles: defineMessages({
name: {
id: 'admin.permissions.permission.manage_channel_roles.name',
defaultMessage: 'Manage channel roles',
},
description: {
id: 'admin.permissions.permission.manage_channel_roles.description',
defaultMessage: 'Manage channel roles',
},
}),
create_emojis: defineMessages({
name: {
id: 'admin.permissions.permission.create_emojis.name',
defaultMessage: 'Create Custom Emoji',
},
description: {
id: 'admin.permissions.permission.create_emojis.description',
defaultMessage: 'Allow users to create custom emoji.',
},
}),
delete_emojis: defineMessages({
name: {
id: 'admin.permissions.permission.delete_emojis.name',
defaultMessage: 'Delete Own Custom Emoji',
},
description: {
id: 'admin.permissions.permission.delete_emojis.description',
defaultMessage: 'Allow users to delete custom emoji that they created.',
},
}),
delete_others_emojis: defineMessages({
name: {
id: 'admin.permissions.permission.delete_others_emojis.name',
defaultMessage: 'Delete Others\' Custom Emoji',
},
description: {
id: 'admin.permissions.permission.delete_others_emojis.description',
defaultMessage: 'Allow users to delete custom emoji that were created by other users.',
},
}),
manage_jobs: defineMessages({
name: {
id: 'admin.permissions.permission.manage_jobs.name',
defaultMessage: 'Manage jobs',
},
description: {
id: 'admin.permissions.permission.manage_jobs.description',
defaultMessage: 'Manage jobs',
},
}),
manage_oauth: defineMessages({
name: {
id: 'admin.permissions.permission.manage_oauth.name',
defaultMessage: 'Manage OAuth Applications',
},
description: {
id: 'admin.permissions.permission.manage_oauth.description',
defaultMessage: 'Create, edit and delete OAuth 2.0 application tokens.',
},
}),
manage_private_channel_properties: defineMessages({
name: {
id: 'admin.permissions.permission.manage_private_channel_properties.name',
defaultMessage: 'Manage Channel Settings',
},
description: {
id: 'admin.permissions.permission.manage_private_channel_properties.description',
defaultMessage: 'Update private channel names, headers and purposes.',
},
}),
manage_public_channel_properties: defineMessages({
name: {
id: 'admin.permissions.permission.manage_public_channel_properties.name',
defaultMessage: 'Manage Channel Settings',
},
description: {
id: 'admin.permissions.permission.manage_public_channel_properties.description',
defaultMessage: 'Update public channel names, headers and purposes.',
},
}),
manage_roles: defineMessages({
name: {
id: 'admin.permissions.permission.manage_roles.name',
defaultMessage: 'Manage roles',
},
description: {
id: 'admin.permissions.permission.manage_roles.description',
defaultMessage: 'Manage roles',
},
}),
manage_slash_commands: defineMessages({
name: {
id: 'admin.permissions.permission.manage_slash_commands.name',
defaultMessage: 'Manage Slash Commands',
},
description: {
id: 'admin.permissions.permission.manage_slash_commands.description',
defaultMessage: 'Create, edit and delete custom slash commands.',
},
}),
manage_system: defineMessages({
name: {
id: 'admin.permissions.permission.manage_system.name',
defaultMessage: 'Manage system',
},
description: {
id: 'admin.permissions.permission.manage_system.description',
defaultMessage: 'Manage system',
},
}),
manage_team: defineMessages({
name: {
id: 'admin.permissions.permission.manage_team.name',
defaultMessage: 'Manage team',
},
description: {
id: 'admin.permissions.permission.manage_team.description',
defaultMessage: 'Manage team',
},
}),
manage_team_roles: defineMessages({
name: {
id: 'admin.permissions.permission.manage_team_roles.name',
defaultMessage: 'Manage team roles',
},
description: {
id: 'admin.permissions.permission.manage_team_roles.description',
defaultMessage: 'Manage team roles',
},
}),
manage_incoming_webhooks: defineMessages({
name: {
id: 'admin.permissions.permission.manage_incoming_webhooks.name',
defaultMessage: 'Manage Incoming Webhooks',
},
description: {
id: 'admin.permissions.permission.manage_incoming_webhooks.description',
defaultMessage: 'Create, edit, and delete incoming webhooks.',
},
}),
manage_outgoing_webhooks: defineMessages({
name: {
id: 'admin.permissions.permission.manage_outgoing_webhooks.name',
defaultMessage: 'Manage Outgoing Webhooks',
},
description: {
id: 'admin.permissions.permission.manage_outgoing_webhooks.description',
defaultMessage: 'Create, edit, and delete outgoing webhooks.',
},
}),
permanent_delete_user: defineMessages({
name: {
id: 'admin.permissions.permission.permanent_delete_user.name',
defaultMessage: 'Permanent delete user',
},
description: {
id: 'admin.permissions.permission.permanent_delete_user.description',
defaultMessage: 'Permanent delete user',
},
}),
read_channel: defineMessages({
name: {
id: 'admin.permissions.permission.read_channel.name',
defaultMessage: 'Read channel',
},
description: {
id: 'admin.permissions.permission.read_channel.description',
defaultMessage: 'Read channel',
},
}),
read_user_access_token: defineMessages({
name: {
id: 'admin.permissions.permission.read_user_access_token.name',
defaultMessage: 'Read user access token',
},
description: {
id: 'admin.permissions.permission.read_user_access_token.description',
defaultMessage: 'Read user access token',
},
}),
remove_user_from_team: defineMessages({
name: {
id: 'admin.permissions.permission.remove_user_from_team.name',
defaultMessage: 'Remove user from team',
},
description: {
id: 'admin.permissions.permission.remove_user_from_team.description',
defaultMessage: 'Remove user from team',
},
}),
revoke_user_access_token: defineMessages({
name: {
id: 'admin.permissions.permission.revoke_user_access_token.name',
defaultMessage: 'Revoke user access token',
},
description: {
id: 'admin.permissions.permission.revoke_user_access_token.description',
defaultMessage: 'Revoke user access token',
},
}),
upload_file: defineMessages({
name: {
id: 'admin.permissions.permission.upload_file.name',
defaultMessage: 'Upload file',
},
description: {
id: 'admin.permissions.permission.upload_file.description',
defaultMessage: 'Upload file',
},
}),
use_channel_mentions: defineMessages({
name: {
id: 'admin.permissions.permission.use_channel_mentions.name',
defaultMessage: 'Channel Mentions',
},
description: {
id: 'admin.permissions.permission.use_channel_mentions.description',
defaultMessage: 'Notify channel members with @all, @channel and @here',
},
}),
use_group_mentions: defineMessages({
name: {
id: 'admin.permissions.permission.use_group_mentions.name',
defaultMessage: 'Group Mentions',
},
description: {
id: 'admin.permissions.permission.use_group_mentions.description',
defaultMessage: 'Notify group members with a group mention',
},
}),
view_team: defineMessages({
name: {
id: 'admin.permissions.permission.view_team.name',
defaultMessage: 'View team',
},
description: {
id: 'admin.permissions.permission.view_team.description',
defaultMessage: 'View team',
},
}),
edit_others_posts: defineMessages({
name: {
id: 'admin.permissions.permission.edit_others_posts.name',
defaultMessage: 'Edit Others\' Posts',
},
description: {
id: 'admin.permissions.permission.edit_others_posts.description',
defaultMessage: 'Allow users to edit others\' posts.',
},
}),
invite_guest: defineMessages({
name: {
id: 'admin.permissions.permission.invite_guest.name',
defaultMessage: 'Invite guests',
},
description: {
id: 'admin.permissions.permission.invite_guest.description',
defaultMessage: 'Invite guests to channels and send guest email invites.',
},
}),
manage_shared_channels: defineMessages({
name: {
id: 'admin.permissions.permission.manage_shared_channels.name',
defaultMessage: 'Manage Shared Channels',
},
description: {
id: 'admin.permissions.permission.manage_shared_channels.description',
defaultMessage: 'Share, unshare and invite another instance to sync with a shared channel',
},
}),
manage_secure_connections: defineMessages({
name: {
id: 'admin.permissions.permission.manage_secure_connections.name',
defaultMessage: 'Manage Secure Connections',
},
description: {
id: 'admin.permissions.permission.manage_secure_connections.description',
defaultMessage: 'Create, remove and view secure connections for shared channels',
},
}),
playbook_public_create: defineMessages({
name: {
id: 'admin.permissions.permission.playbook_public_create.name',
defaultMessage: 'Create Public Playbook',
},
description: {
id: 'admin.permissions.permission.playbook_public_create.description',
defaultMessage: 'Create new public playbooks.',
},
}),
playbook_public_manage_properties: defineMessages({
name: {
id: 'admin.permissions.permission.playbook_public_manage_properties.name',
defaultMessage: 'Manage Playbook Configurations',
},
description: {
id: 'admin.permissions.permission.playbook_public_manage_properties.description',
defaultMessage: 'Prescribe checklists, actions, and templates.',
},
}),
playbook_public_manage_members: defineMessages({
name: {
id: 'admin.permissions.permission.playbook_public_manage_members.name',
defaultMessage: 'Manage Playbook Members',
},
description: {
id: 'admin.permissions.permission.playbook_public_manage_members.description',
defaultMessage: 'Add and remove public playbook members.',
},
}),
playbook_public_make_private: defineMessages({
name: {
id: 'admin.permissions.permission.playbook_public_make_private.name',
defaultMessage: 'Convert Playbooks',
},
description: {
id: 'admin.permissions.permission.playbook_public_make_private.description',
defaultMessage: 'Convert public playbooks to private.',
},
}),
playbook_private_create: defineMessages({
name: {
id: 'admin.permissions.permission.playbook_private_create.name',
defaultMessage: 'Create Private Playbook',
},
description: {
id: 'admin.permissions.permission.playbook_private_create.description',
defaultMessage: 'Create new private playbooks.',
},
}),
playbook_private_manage_properties: defineMessages({
name: {
id: 'admin.permissions.permission.playbook_private_manage_properties.name',
defaultMessage: 'Manage Playbook Configurations',
},
description: {
id: 'admin.permissions.permission.playbook_private_manage_properties.description',
defaultMessage: 'Prescribe checklists, actions, and templates.',
},
}),
playbook_private_manage_members: defineMessages({
name: {
id: 'admin.permissions.permission.playbook_private_manage_members.name',
defaultMessage: 'Manage Playbook Members',
},
description: {
id: 'admin.permissions.permission.playbook_private_manage_members.description',
defaultMessage: 'Add and remove private playbook members.',
},
}),
playbook_private_make_public: defineMessages({
name: {
id: 'admin.permissions.permission.playbook_private_make_public.name',
defaultMessage: 'Convert Playbooks',
},
description: {
id: 'admin.permissions.permission.playbook_private_make_public.description',
defaultMessage: 'Convert private playbooks to public.',
},
}),
run_create: defineMessages({
name: {
id: 'admin.permissions.permission.run_create.name',
defaultMessage: 'Create Runs',
},
description: {
id: 'admin.permissions.permission.run_create.description',
defaultMessage: 'Run playbooks.',
},
}),
create_custom_group: defineMessages({
name: {
id: 'admin.permissions.permission.create_custom_group.name',
defaultMessage: 'Create',
},
description: {
id: 'admin.permissions.permission.create_custom_group.description',
defaultMessage: 'Create custom groups.',
},
}),
manage_custom_group_members: defineMessages({
name: {
id: 'admin.permissions.permission.manage_custom_group_members.name',
defaultMessage: 'Manage members',
},
description: {
id: 'admin.permissions.permission.manage_custom_group_members.description',
defaultMessage: 'Add and remove custom group members.',
},
}),
delete_custom_group: defineMessages({
name: {
id: 'admin.permissions.permission.delete_custom_group.name',
defaultMessage: 'Delete',
},
description: {
id: 'admin.permissions.permission.delete_custom_group.description',
defaultMessage: 'Delete custom groups.',
},
}),
restore_custom_group: defineMessages({
name: {
id: 'admin.permissions.permission.restore_custom_group.name',
defaultMessage: 'Restore',
},
description: {
id: 'admin.permissions.permission.restore_custom_group.description',
defaultMessage: 'Restore archived user groups.',
},
}),
edit_custom_group: defineMessages({
name: {
id: 'admin.permissions.permission.edit_custom_group.name',
defaultMessage: 'Edit',
},
description: {
id: 'admin.permissions.permission.edit_custom_group.description',
defaultMessage: 'Rename custom groups.',
},
}),
};

View File

@ -0,0 +1,36 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import type {MessageDescriptor} from 'react-intl';
import {defineMessages} from 'react-intl';
export const rolesRolesStrings: Record<string, MessageDescriptor> = defineMessages({
all_users: {
id: 'admin.permissions.roles.all_users.name',
defaultMessage: 'All Members',
},
channel_admin: {
id: 'admin.permissions.roles.channel_admin.name',
defaultMessage: 'Channel Admin',
},
channel_user: {
id: 'admin.permissions.roles.channel_user.name',
defaultMessage: 'Channel User',
},
system_admin: {
id: 'admin.permissions.roles.system_admin.name',
defaultMessage: 'System Admin',
},
system_user: {
id: 'admin.permissions.roles.system_user.name',
defaultMessage: 'System User',
},
team_admin: {
id: 'admin.permissions.roles.team_admin.name',
defaultMessage: 'Team Admin',
},
team_user: {
id: 'admin.permissions.roles.team_user.name',
defaultMessage: 'Team User',
},
});

View File

@ -106,7 +106,7 @@ exports[`components/PluginManagement should match snapshot 1`] = `
/>
}
helpText={
<FormattedMarkdownMessage
<Memo(MemoizedFormattedMessage)
defaultMessage="When true, automatically installs any prepackaged plugin found to be enabled in the server configuration."
id="admin.plugins.settings.automaticPrepackagedPluginsDesc"
/>
@ -260,7 +260,7 @@ exports[`components/PluginManagement should match snapshot 1`] = `
disabled={false}
helpText={
<div>
<FormattedMarkdownMessage
<Memo(MemoizedFormattedMessage)
defaultMessage="URL of the marketplace server."
id="admin.plugins.settings.marketplaceUrlDesc"
/>
@ -454,7 +454,7 @@ exports[`components/PluginManagement should match snapshot when \`Enable Marketp
/>
}
helpText={
<FormattedMarkdownMessage
<Memo(MemoizedFormattedMessage)
defaultMessage="When true, automatically installs any prepackaged plugin found to be enabled in the server configuration."
id="admin.plugins.settings.automaticPrepackagedPluginsDesc"
/>
@ -608,7 +608,7 @@ exports[`components/PluginManagement should match snapshot when \`Enable Marketp
disabled={true}
helpText={
<div>
<FormattedMarkdownMessage
<Memo(MemoizedFormattedMessage)
defaultMessage="URL of the marketplace server."
id="admin.plugins.settings.marketplaceUrlDesc"
/>
@ -898,7 +898,7 @@ exports[`components/PluginManagement should match snapshot when \`Enable Remote
/>
}
helpText={
<FormattedMarkdownMessage
<Memo(MemoizedFormattedMessage)
defaultMessage="When true, automatically installs any prepackaged plugin found to be enabled in the server configuration."
id="admin.plugins.settings.automaticPrepackagedPluginsDesc"
/>
@ -1052,7 +1052,7 @@ exports[`components/PluginManagement should match snapshot when \`Enable Remote
disabled={true}
helpText={
<div>
<FormattedMarkdownMessage
<Memo(MemoizedFormattedMessage)
defaultMessage="URL of the marketplace server."
id="admin.plugins.settings.marketplaceUrlDesc"
/>
@ -1246,7 +1246,7 @@ exports[`components/PluginManagement should match snapshot when \`Require Signat
/>
}
helpText={
<FormattedMarkdownMessage
<Memo(MemoizedFormattedMessage)
defaultMessage="When true, automatically installs any prepackaged plugin found to be enabled in the server configuration."
id="admin.plugins.settings.automaticPrepackagedPluginsDesc"
/>
@ -1402,7 +1402,7 @@ exports[`components/PluginManagement should match snapshot when \`Require Signat
disabled={false}
helpText={
<div>
<FormattedMarkdownMessage
<Memo(MemoizedFormattedMessage)
defaultMessage="URL of the marketplace server."
id="admin.plugins.settings.marketplaceUrlDesc"
/>
@ -1596,7 +1596,7 @@ exports[`components/PluginManagement should match snapshot, No installed plugins
/>
}
helpText={
<FormattedMarkdownMessage
<Memo(MemoizedFormattedMessage)
defaultMessage="When true, automatically installs any prepackaged plugin found to be enabled in the server configuration."
id="admin.plugins.settings.automaticPrepackagedPluginsDesc"
/>
@ -1750,7 +1750,7 @@ exports[`components/PluginManagement should match snapshot, No installed plugins
disabled={false}
helpText={
<div>
<FormattedMarkdownMessage
<Memo(MemoizedFormattedMessage)
defaultMessage="URL of the marketplace server."
id="admin.plugins.settings.marketplaceUrlDesc"
/>
@ -1948,7 +1948,7 @@ exports[`components/PluginManagement should match snapshot, allow insecure URL e
/>
}
helpText={
<FormattedMarkdownMessage
<Memo(MemoizedFormattedMessage)
defaultMessage="When true, automatically installs any prepackaged plugin found to be enabled in the server configuration."
id="admin.plugins.settings.automaticPrepackagedPluginsDesc"
/>
@ -2102,7 +2102,7 @@ exports[`components/PluginManagement should match snapshot, allow insecure URL e
disabled={false}
helpText={
<div>
<FormattedMarkdownMessage
<Memo(MemoizedFormattedMessage)
defaultMessage="URL of the marketplace server."
id="admin.plugins.settings.marketplaceUrlDesc"
/>
@ -2296,7 +2296,7 @@ exports[`components/PluginManagement should match snapshot, disabled 1`] = `
/>
}
helpText={
<FormattedMarkdownMessage
<Memo(MemoizedFormattedMessage)
defaultMessage="When true, automatically installs any prepackaged plugin found to be enabled in the server configuration."
id="admin.plugins.settings.automaticPrepackagedPluginsDesc"
/>
@ -2452,7 +2452,7 @@ exports[`components/PluginManagement should match snapshot, disabled 1`] = `
disabled={true}
helpText={
<div>
<FormattedMarkdownMessage
<Memo(MemoizedFormattedMessage)
defaultMessage="URL of the marketplace server."
id="admin.plugins.settings.marketplaceUrlDesc"
/>
@ -2621,7 +2621,7 @@ exports[`components/PluginManagement should match snapshot, text entered into th
/>
}
helpText={
<FormattedMarkdownMessage
<Memo(MemoizedFormattedMessage)
defaultMessage="When true, automatically installs any prepackaged plugin found to be enabled in the server configuration."
id="admin.plugins.settings.automaticPrepackagedPluginsDesc"
/>
@ -2775,7 +2775,7 @@ exports[`components/PluginManagement should match snapshot, text entered into th
disabled={false}
helpText={
<div>
<FormattedMarkdownMessage
<Memo(MemoizedFormattedMessage)
defaultMessage="URL of the marketplace server."
id="admin.plugins.settings.marketplaceUrlDesc"
/>
@ -2969,7 +2969,7 @@ exports[`components/PluginManagement should match snapshot, upload disabled 1`]
/>
}
helpText={
<FormattedMarkdownMessage
<Memo(MemoizedFormattedMessage)
defaultMessage="When true, automatically installs any prepackaged plugin found to be enabled in the server configuration."
id="admin.plugins.settings.automaticPrepackagedPluginsDesc"
/>
@ -3324,7 +3324,7 @@ exports[`components/PluginManagement should match snapshot, with installed plugi
/>
}
helpText={
<FormattedMarkdownMessage
<Memo(MemoizedFormattedMessage)
defaultMessage="When true, automatically installs any prepackaged plugin found to be enabled in the server configuration."
id="admin.plugins.settings.automaticPrepackagedPluginsDesc"
/>
@ -3478,7 +3478,7 @@ exports[`components/PluginManagement should match snapshot, with installed plugi
disabled={false}
helpText={
<div>
<FormattedMarkdownMessage
<Memo(MemoizedFormattedMessage)
defaultMessage="URL of the marketplace server."
id="admin.plugins.settings.marketplaceUrlDesc"
/>
@ -3735,7 +3735,7 @@ exports[`components/PluginManagement should match snapshot, with installed plugi
/>
}
helpText={
<FormattedMarkdownMessage
<Memo(MemoizedFormattedMessage)
defaultMessage="When true, automatically installs any prepackaged plugin found to be enabled in the server configuration."
id="admin.plugins.settings.automaticPrepackagedPluginsDesc"
/>
@ -3889,7 +3889,7 @@ exports[`components/PluginManagement should match snapshot, with installed plugi
disabled={false}
helpText={
<div>
<FormattedMarkdownMessage
<Memo(MemoizedFormattedMessage)
defaultMessage="URL of the marketplace server."
id="admin.plugins.settings.marketplaceUrlDesc"
/>
@ -4114,7 +4114,7 @@ exports[`components/PluginManagement should match snapshot, with installed plugi
/>
}
helpText={
<FormattedMarkdownMessage
<Memo(MemoizedFormattedMessage)
defaultMessage="When true, automatically installs any prepackaged plugin found to be enabled in the server configuration."
id="admin.plugins.settings.automaticPrepackagedPluginsDesc"
/>
@ -4268,7 +4268,7 @@ exports[`components/PluginManagement should match snapshot, with installed plugi
disabled={false}
helpText={
<div>
<FormattedMarkdownMessage
<Memo(MemoizedFormattedMessage)
defaultMessage="URL of the marketplace server."
id="admin.plugins.settings.marketplaceUrlDesc"
/>
@ -4493,7 +4493,7 @@ exports[`components/PluginManagement should match snapshot, with installed plugi
/>
}
helpText={
<FormattedMarkdownMessage
<Memo(MemoizedFormattedMessage)
defaultMessage="When true, automatically installs any prepackaged plugin found to be enabled in the server configuration."
id="admin.plugins.settings.automaticPrepackagedPluginsDesc"
/>
@ -4647,7 +4647,7 @@ exports[`components/PluginManagement should match snapshot, with installed plugi
disabled={false}
helpText={
<div>
<FormattedMarkdownMessage
<Memo(MemoizedFormattedMessage)
defaultMessage="URL of the marketplace server."
id="admin.plugins.settings.marketplaceUrlDesc"
/>
@ -4872,7 +4872,7 @@ exports[`components/PluginManagement should match snapshot, with installed plugi
/>
}
helpText={
<FormattedMarkdownMessage
<Memo(MemoizedFormattedMessage)
defaultMessage="When true, automatically installs any prepackaged plugin found to be enabled in the server configuration."
id="admin.plugins.settings.automaticPrepackagedPluginsDesc"
/>
@ -5026,7 +5026,7 @@ exports[`components/PluginManagement should match snapshot, with installed plugi
disabled={false}
helpText={
<div>
<FormattedMarkdownMessage
<Memo(MemoizedFormattedMessage)
defaultMessage="URL of the marketplace server."
id="admin.plugins.settings.marketplaceUrlDesc"
/>

View File

@ -1,13 +1,14 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {shallow} from 'enzyme';
import React from 'react';
import PluginState from 'mattermost-redux/constants/plugins';
import PluginManagement from 'components/admin_console/plugin_management/plugin_management';
import {shallowWithIntl} from 'tests/helpers/intl-test-helper';
describe('components/PluginManagement', () => {
const defaultProps = {
config: {
@ -104,7 +105,7 @@ describe('components/PluginManagement', () => {
test('should match snapshot', () => {
const props = {...defaultProps};
const wrapper = shallow(<PluginManagement {...props}/>);
const wrapper = shallowWithIntl(<PluginManagement {...props}/>);
expect(wrapper).toMatchSnapshot();
});
@ -119,7 +120,7 @@ describe('components/PluginManagement', () => {
},
},
};
const wrapper = shallow(<PluginManagement {...props}/>);
const wrapper = shallowWithIntl(<PluginManagement {...props}/>);
expect(wrapper).toMatchSnapshot();
});
@ -133,7 +134,7 @@ describe('components/PluginManagement', () => {
},
},
};
const wrapper = shallow(<PluginManagement {...props}/>);
const wrapper = shallowWithIntl(<PluginManagement {...props}/>);
expect(wrapper).toMatchSnapshot();
});
@ -148,7 +149,7 @@ describe('components/PluginManagement', () => {
},
},
};
const wrapper = shallow(<PluginManagement {...props}/>);
const wrapper = shallowWithIntl(<PluginManagement {...props}/>);
expect(wrapper).toMatchSnapshot();
});
@ -163,7 +164,7 @@ describe('components/PluginManagement', () => {
},
},
};
const wrapper = shallow(<PluginManagement {...props}/>);
const wrapper = shallowWithIntl(<PluginManagement {...props}/>);
expect(wrapper).toMatchSnapshot();
});
@ -178,7 +179,7 @@ describe('components/PluginManagement', () => {
},
},
};
const wrapper = shallow(<PluginManagement {...props}/>);
const wrapper = shallowWithIntl(<PluginManagement {...props}/>);
expect(wrapper).toMatchSnapshot();
});
@ -193,7 +194,7 @@ describe('components/PluginManagement', () => {
},
},
};
const wrapper = shallow(<PluginManagement {...props}/>);
const wrapper = shallowWithIntl(<PluginManagement {...props}/>);
expect(wrapper).toMatchSnapshot();
});
@ -208,14 +209,14 @@ describe('components/PluginManagement', () => {
},
},
};
const wrapper = shallow(<PluginManagement {...props}/>);
const wrapper = shallowWithIntl(<PluginManagement {...props}/>);
expect(wrapper).toMatchSnapshot();
});
test('should match snapshot, text entered into the URL install text box', () => {
const props = defaultProps;
const wrapper = shallow(<PluginManagement {...props}/>);
const wrapper = shallowWithIntl(<PluginManagement {...props}/>);
wrapper.setState({pluginDownloadUrl: 'https://pluginsite.com/plugin.tar.gz'});
expect(wrapper).toMatchSnapshot();
});
@ -244,13 +245,13 @@ describe('components/PluginManagement', () => {
disablePlugin: jest.fn(),
},
};
const wrapper = shallow(<PluginManagement {...props}/>);
const wrapper = shallowWithIntl(<PluginManagement {...props}/>);
wrapper.setState({loading: false});
expect(wrapper).toMatchSnapshot();
});
test('should match snapshot, with installed plugins', () => {
const wrapper = shallow(<PluginManagement {...defaultProps}/>);
const wrapper = shallowWithIntl(<PluginManagement {...defaultProps}/>);
wrapper.setState({loading: false});
expect(wrapper).toMatchSnapshot();
});
@ -334,7 +335,7 @@ describe('components/PluginManagement', () => {
disablePlugin: jest.fn(),
},
};
const wrapper = shallow(<PluginManagement {...props}/>);
const wrapper = shallowWithIntl(<PluginManagement {...props}/>);
wrapper.setState({loading: false});
expect(wrapper).toMatchSnapshot();
});
@ -391,7 +392,7 @@ describe('components/PluginManagement', () => {
disablePlugin: jest.fn(),
},
};
const wrapper = shallow(<PluginManagement {...props}/>);
const wrapper = shallowWithIntl(<PluginManagement {...props}/>);
wrapper.setState({loading: false});
expect(wrapper).toMatchSnapshot();
});
@ -449,7 +450,7 @@ describe('components/PluginManagement', () => {
disablePlugin: jest.fn(),
},
};
const wrapper = shallow(<PluginManagement {...props}/>);
const wrapper = shallowWithIntl(<PluginManagement {...props}/>);
wrapper.setState({loading: false});
expect(wrapper).toMatchSnapshot();
});
@ -508,7 +509,7 @@ describe('components/PluginManagement', () => {
disablePlugin: jest.fn(),
},
};
const wrapper = shallow(<PluginManagement {...props}/>);
const wrapper = shallowWithIntl(<PluginManagement {...props}/>);
wrapper.setState({loading: false});
expect(wrapper).toMatchSnapshot();
});

View File

@ -3,7 +3,8 @@
import classNames from 'classnames';
import React from 'react';
import {FormattedMessage} from 'react-intl';
import type {WrappedComponentProps} from 'react-intl';
import {FormattedMessage, defineMessages, injectIntl} from 'react-intl';
import {Link} from 'react-router-dom';
import type {AdminConfig} from '@mattermost/types/config';
@ -186,6 +187,44 @@ type PluginItemProps = {
isDisabled?: boolean;
};
const messages = defineMessages({
title: {id: 'admin.plugin.management.title', defaultMessage: 'Management'},
enable: {id: 'admin.plugins.settings.enable', defaultMessage: 'Enable Plugins: '},
enableDesc: {id: 'admin.plugins.settings.enableDesc', defaultMessage: 'When true, enables plugins on your Mattermost server. Use plugins to integrate with third-party systems, extend functionality, or customize the user interface of your Mattermost server. See <link>documentation</link> to learn more.'},
uploadTitle: {id: 'admin.plugin.uploadTitle', defaultMessage: 'Upload Plugin: '},
installedTitle: {id: 'admin.plugin.installedTitle', defaultMessage: 'Installed Plugins: '},
installedDesc: {id: 'admin.plugin.installedDesc', defaultMessage: 'Installed plugins on your Mattermost server.'},
uploadDesc: {id: 'admin.plugin.uploadDesc', defaultMessage: 'Upload a plugin for your Mattermost server. See <link>documentation</link> to learn more.'},
uploadDisabledDesc: {id: 'admin.plugin.uploadDisabledDesc', defaultMessage: 'Enable plugin uploads in config.json. See <link>documentation</link> to learn more.'},
enableMarketplace: {id: 'admin.plugins.settings.enableMarketplace', defaultMessage: 'Enable Marketplace:'},
enableMarketplaceDesc: {id: 'admin.plugins.settings.enableMarketplaceDesc', defaultMessage: 'When true, enables System Administrators to install plugins from the <link>marketplace</link>.'},
enableRemoteMarketplace: {id: 'admin.plugins.settings.enableRemoteMarketplace', defaultMessage: 'Enable Remote Marketplace:'},
enableRemoteMarketplaceDesc: {id: 'admin.plugins.settings.enableRemoteMarketplaceDesc', defaultMessage: 'When true, marketplace fetches latest plugins from the configured Marketplace URL.'},
automaticPrepackagedPlugins: {id: 'admin.plugins.settings.automaticPrepackagedPlugins', defaultMessage: 'Enable Automatic Prepackaged Plugins:'},
automaticPrepackagedPluginsDesc: {id: 'admin.plugins.settings.automaticPrepackagedPluginsDesc', defaultMessage: 'When true, automatically installs any prepackaged plugin found to be enabled in the server configuration.'},
marketplaceUrl: {id: 'admin.plugins.settings.marketplaceUrl', defaultMessage: 'Marketplace URL:'},
marketplaceUrlDesc: {id: 'admin.plugins.settings.marketplaceUrlDesc', defaultMessage: 'URL of the marketplace server.'},
});
export const searchableStrings = [
messages.title,
messages.enable,
messages.enableDesc,
messages.uploadTitle,
messages.installedTitle,
messages.installedDesc,
messages.uploadDesc,
messages.uploadDisabledDesc,
messages.enableMarketplace,
messages.enableMarketplaceDesc,
messages.enableRemoteMarketplace,
messages.enableRemoteMarketplaceDesc,
messages.automaticPrepackagedPlugins,
messages.automaticPrepackagedPluginsDesc,
messages.marketplaceUrl,
messages.marketplaceUrlDesc,
];
const PluginItem = ({
pluginStatus,
removing,
@ -429,7 +468,7 @@ type Props = BaseProps & {
disablePlugin: (pluginId: string) => any;
installPluginFromUrl: (url: string, force: boolean) => any;
};
};
} & WrappedComponentProps;
type State = BaseState & {
loading: boolean;
@ -456,7 +495,7 @@ type State = BaseState & {
requirePluginSignature: boolean;
removing: string | null;
}
export default class PluginManagement extends AdminSettings<Props, State> {
class PluginManagement extends AdminSettings<Props, State> {
private fileInput: React.RefObject<HTMLInputElement>;
constructor(props: Props) {
super(props);
@ -540,9 +579,9 @@ export default class PluginManagement extends AdminSettings<Props, State> {
uploading: false,
});
if (error.server_error_id === 'app.plugin.activate.app_error') {
this.setState({serverError: Utils.localizeMessage('admin.plugin.error.activate', 'Unable to upload the plugin. It may conflict with another plugin on your server.')});
this.setState({serverError: this.props.intl.formatMessage({id: 'admin.plugin.error.activate', defaultMessage: 'Unable to upload the plugin. It may conflict with another plugin on your server.'})});
} else if (error.server_error_id === 'app.plugin.extract.app_error') {
this.setState({serverError: Utils.localizeMessage('admin.plugin.error.extract', 'Encountered an error when extracting the plugin. Review your plugin file content and try again.')});
this.setState({serverError: this.props.intl.formatMessage({id: 'admin.plugin.error.extract', defaultMessage: 'Encountered an error when extracting the plugin. Review your plugin file content and try again.'})});
} else {
this.setState({serverError: error.message});
}
@ -628,7 +667,7 @@ export default class PluginManagement extends AdminSettings<Props, State> {
});
if (error.server_error_id === 'app.plugin.extract.app_error') {
this.setState({serverError: Utils.localizeMessage('admin.plugin.error.extract', 'Encountered an error when extracting the plugin. Review your plugin file content and try again.')});
this.setState({serverError: this.props.intl.formatMessage({id: 'admin.plugin.error.extract', defaultMessage: 'Encountered an error when extracting the plugin. Review your plugin file content and try again.'})});
} else {
this.setState({serverError: error.message});
}
@ -659,7 +698,7 @@ export default class PluginManagement extends AdminSettings<Props, State> {
url === '' && enableUploads &&
<div className='alert-warning'>
<i className='fa fa-warning'/>
<FormattedMarkdownMessage
<FormattedMessage
id='admin.plugins.settings.marketplaceUrlDesc.empty'
defaultMessage=' Marketplace URL is a required field.'
/>
@ -667,16 +706,12 @@ export default class PluginManagement extends AdminSettings<Props, State> {
}
{
url !== '' && enableUploads &&
<FormattedMarkdownMessage
id='admin.plugins.settings.marketplaceUrlDesc'
defaultMessage='URL of the marketplace server.'
/>
<FormattedMessage {...messages.marketplaceUrlDesc}/>
}
{
!enableUploads &&
<FormattedMessage
id='admin.plugin.uploadDisabledDesc'
defaultMessage='Enable plugin uploads in config.json. See <link>documentation</link> to learn more.'
{...messages.uploadDisabledDesc}
values={{
link: (msg: React.ReactNode) => (
<ExternalLink
@ -781,12 +816,7 @@ export default class PluginManagement extends AdminSettings<Props, State> {
};
renderTitle() {
return (
<FormattedMessage
id='admin.plugin.management.title'
defaultMessage='Management'
/>
);
return (<FormattedMessage {...messages.title}/>);
}
renderOverwritePluginModal = (
@ -868,16 +898,10 @@ export default class PluginManagement extends AdminSettings<Props, State> {
return (
<BooleanSetting
id='enable'
label={
<FormattedMessage
id='admin.plugins.settings.enable'
defaultMessage='Enable Plugins: '
/>
}
label={<FormattedMessage {...messages.enable}/>}
helpText={
<FormattedMessage
id='admin.plugins.settings.enableDesc'
defaultMessage='When true, enables plugins on your Mattermost server. Use plugins to integrate with third-party systems, extend functionality, or customize the user interface of your Mattermost server. See <link>documentation</link> to learn more.'
{...messages.enableDesc}
values={{
link: (msg: React.ReactNode) => (
<ExternalLink
@ -995,20 +1019,12 @@ export default class PluginManagement extends AdminSettings<Props, State> {
if (enable) {
pluginsContainer = (
<div className='form-group'>
<label
className='control-label col-sm-4'
>
<FormattedMessage
id='admin.plugin.installedTitle'
defaultMessage='Installed Plugins: '
/>
<label className='control-label col-sm-4'>
<FormattedMessage {...messages.installedTitle}/>
</label>
<div className='col-sm-8'>
<p className='help-text'>
<FormattedMessage
id='admin.plugin.installedDesc'
defaultMessage='Installed plugins on your Mattermost server.'
/>
<FormattedMessage {...messages.installedDesc}/>
</p>
<br/>
{pluginsListContainer}
@ -1022,8 +1038,7 @@ export default class PluginManagement extends AdminSettings<Props, State> {
if (enableUploads && enable) {
uploadHelpText = (
<FormattedMessage
id='admin.plugin.uploadDesc'
defaultMessage='Upload a plugin for your Mattermost server. See <link>documentation</link> to learn more.'
{...messages.uploadDesc}
values={{
link: (msg: React.ReactNode) => (
<ExternalLink
@ -1039,8 +1054,7 @@ export default class PluginManagement extends AdminSettings<Props, State> {
} else if (enable && !enableUploads) {
uploadHelpText = (
<FormattedMessage
id='admin.plugin.uploadDisabledDesc'
defaultMessage='Enable plugin uploads in config.json. See <link>documentation</link> to learn more.'
{...messages.uploadDisabledDesc}
values={{
link: (msg: React.ReactNode) => (
<ExternalLink
@ -1126,31 +1140,16 @@ export default class PluginManagement extends AdminSettings<Props, State> {
/>
<BooleanSetting
id='automaticPrepackagedPlugins'
label={
<FormattedMessage
id='admin.plugins.settings.automaticPrepackagedPlugins'
defaultMessage='Enable Automatic Prepackaged Plugins:'
/>
}
helpText={
<FormattedMarkdownMessage
id='admin.plugins.settings.automaticPrepackagedPluginsDesc'
defaultMessage='When true, automatically installs any prepackaged plugin found to be enabled in the server configuration.'
/>
}
label={<FormattedMessage {...messages.automaticPrepackagedPlugins}/>}
helpText={<FormattedMessage {...messages.automaticPrepackagedPluginsDesc}/>}
value={this.state.automaticPrepackagedPlugins}
disabled={this.props.isDisabled || !this.state.enable}
onChange={this.handleChange}
setByEnv={this.isSetByEnv('PluginSettings.AutomaticPrepackagedPlugins')}
/>
<div className='form-group'>
<label
className='control-label col-sm-4'
>
<FormattedMessage
id='admin.plugin.uploadTitle'
defaultMessage='Upload Plugin: '
/>
<label className='control-label col-sm-4'>
<FormattedMessage {...messages.uploadTitle}/>
</label>
<div className='col-sm-8'>
<div className='file__upload'>
@ -1192,16 +1191,10 @@ export default class PluginManagement extends AdminSettings<Props, State> {
</div>
<BooleanSetting
id='enableMarketplace'
label={
<FormattedMessage
id='admin.plugins.settings.enableMarketplace'
defaultMessage='Enable Marketplace:'
/>
}
label={<FormattedMessage {...messages.enableMarketplace}/>}
helpText={
<FormattedMessage
id='admin.plugins.settings.enableMarketplaceDesc'
defaultMessage='When true, enables System Administrators to install plugins from the <link>marketplace</link>.'
{...messages.enableMarketplaceDesc}
values={{
link: (msg: React.ReactNode) => (
<ExternalLink
@ -1221,18 +1214,8 @@ export default class PluginManagement extends AdminSettings<Props, State> {
/>
<BooleanSetting
id='enableRemoteMarketplace'
label={
<FormattedMessage
id='admin.plugins.settings.enableRemoteMarketplace'
defaultMessage='Enable Remote Marketplace:'
/>
}
helpText={
<FormattedMarkdownMessage
id='admin.plugins.settings.enableRemoteMarketplaceDesc'
defaultMessage='When true, marketplace fetches latest plugins from the configured Marketplace URL.'
/>
}
label={<FormattedMessage {...messages.enableRemoteMarketplace}/>}
helpText={<FormattedMarkdownMessage {...messages.enableRemoteMarketplaceDesc}/>}
value={this.state.enableRemoteMarketplace}
disabled={this.props.isDisabled || !this.state.enable || !this.state.enableUploads || !this.state.enableMarketplace}
onChange={this.handleChange}
@ -1240,12 +1223,7 @@ export default class PluginManagement extends AdminSettings<Props, State> {
/>
<TextSetting
id={'marketplaceUrl'}
label={
<FormattedMessage
id='admin.plugins.settings.marketplaceUrl'
defaultMessage='Marketplace URL:'
/>
}
label={<FormattedMessage {...messages.marketplaceUrl}/>}
helpText={this.getMarketplaceURLHelpText(this.state.marketplaceUrl, this.state.enableUploads)}
value={this.state.marketplaceUrl}
disabled={this.props.isDisabled || !this.state.enable || !this.state.enableUploads || !this.state.enableMarketplace || !this.state.enableRemoteMarketplace}
@ -1263,3 +1241,5 @@ export default class PluginManagement extends AdminSettings<Props, State> {
);
};
}
export default injectIntl(PluginManagement);

View File

@ -1,13 +1,14 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {shallow} from 'enzyme';
import React from 'react';
import type {AdminConfig} from '@mattermost/types/config';
import PushSettings from 'components/admin_console/push_settings';
import {shallowWithIntl} from 'tests/helpers/intl-test-helper';
describe('components/PushSettings', () => {
test('should match snapshot, licensed', () => {
const config = {
@ -29,7 +30,7 @@ describe('components/PushSettings', () => {
},
};
const wrapper = shallow(
const wrapper = shallowWithIntl(
<PushSettings {...props}/>,
);
@ -54,7 +55,7 @@ describe('components/PushSettings', () => {
license: {},
};
const wrapper = shallow(
const wrapper = shallowWithIntl(
<PushSettings {...props}/>,
);
expect(wrapper).toMatchSnapshot();

View File

@ -2,14 +2,14 @@
// See LICENSE.txt for license information.
import React from 'react';
import {FormattedMessage} from 'react-intl';
import type {WrappedComponentProps} from 'react-intl';
import {FormattedMessage, defineMessage, defineMessages, injectIntl} from 'react-intl';
import type {AdminConfig, ClientLicense, EmailSettings} from '@mattermost/types/config';
import ExternalLink from 'components/external_link';
import {Constants, DocLinks} from 'utils/constants';
import * as Utils from 'utils/utils';
import AdminSettings from './admin_settings';
import type {BaseProps, BaseState} from './admin_settings';
@ -20,7 +20,7 @@ import TextSetting from './text_setting';
type Props = BaseProps & {
config: AdminConfig;
license: ClientLicense;
};
} & WrappedComponentProps;
type State = BaseState & {
pushNotificationServer: string;
@ -45,7 +45,19 @@ const PUSH_NOTIFICATIONS_SERVER_DIC = {
const DROPDOWN_ID_SERVER_TYPE = 'pushNotificationServerType';
const DROPDOWN_ID_SERVER_LOCATION = 'pushNotificationServerLocation';
export default class PushSettings extends AdminSettings<Props, State> {
const messages = defineMessages({
pushNotificationServer: {id: 'admin.environment.pushNotificationServer', defaultMessage: 'Push Notification Server'},
pushTitle: {id: 'admin.email.pushTitle', defaultMessage: 'Enable Push Notifications: '},
pushServerTitle: {id: 'admin.email.pushServerTitle', defaultMessage: 'Push Notification Server:'},
});
export const searchableStrings = [
messages.pushNotificationServer,
messages.pushTitle,
messages.pushServerTitle,
];
class PushSettings extends AdminSettings<Props, State> {
canSave = () => {
return this.state.pushNotificationServerType !== PUSH_NOTIFICATIONS_MHPNS || this.state.agree;
};
@ -143,22 +155,17 @@ export default class PushSettings extends AdminSettings<Props, State> {
};
renderTitle() {
return (
<FormattedMessage
id='admin.environment.pushNotificationServer'
defaultMessage='Push Notification Server'
/>
);
return (<FormattedMessage {...messages.pushNotificationServer}/>);
}
renderSettings = () => {
const pushNotificationServerTypes = [];
pushNotificationServerTypes.push({value: PUSH_NOTIFICATIONS_OFF, text: Utils.localizeMessage('admin.email.pushOff', 'Do not send push notifications')});
pushNotificationServerTypes.push({value: PUSH_NOTIFICATIONS_OFF, text: this.props.intl.formatMessage({id: 'admin.email.pushOff', defaultMessage: 'Do not send push notifications'})});
if (this.props.license.IsLicensed === 'true' && this.props.license.MHPNS === 'true') {
pushNotificationServerTypes.push({value: PUSH_NOTIFICATIONS_MHPNS, text: Utils.localizeMessage('admin.email.mhpns', 'Use HPNS connection with uptime SLA to send notifications to iOS and Android apps')});
pushNotificationServerTypes.push({value: PUSH_NOTIFICATIONS_MHPNS, text: this.props.intl.formatMessage({id: 'admin.email.mhpns', defaultMessage: 'Use HPNS connection with uptime SLA to send notifications to iOS and Android apps'})});
}
pushNotificationServerTypes.push({value: PUSH_NOTIFICATIONS_MTPNS, text: Utils.localizeMessage('admin.email.mtpns', 'Use TPNS connection to send notifications to iOS and Android apps')});
pushNotificationServerTypes.push({value: PUSH_NOTIFICATIONS_CUSTOM, text: Utils.localizeMessage('admin.email.selfPush', 'Manually enter Push Notification Service location')});
pushNotificationServerTypes.push({value: PUSH_NOTIFICATIONS_MTPNS, text: this.props.intl.formatMessage({id: 'admin.email.mtpns', defaultMessage: 'Use TPNS connection to send notifications to iOS and Android apps'})});
pushNotificationServerTypes.push({value: PUSH_NOTIFICATIONS_CUSTOM, text: this.props.intl.formatMessage({id: 'admin.email.selfPush', defaultMessage: 'Manually enter Push Notification Service location'})});
let sendHelpText = null;
let pushServerHelpText = null;
@ -306,8 +313,8 @@ export default class PushSettings extends AdminSettings<Props, State> {
let locationDropdown;
if (this.state.pushNotificationServerType === PUSH_NOTIFICATIONS_MHPNS) {
const pushNotificationServerLocations = [
{value: PUSH_NOTIFICATIONS_LOCATION_US, text: Utils.localizeMessage('admin.email.pushServerLocationUS', 'US')},
{value: PUSH_NOTIFICATIONS_LOCATION_DE, text: Utils.localizeMessage('admin.email.pushServerLocationDE', 'Germany')},
{value: PUSH_NOTIFICATIONS_LOCATION_US, text: this.props.intl.formatMessage({id: 'admin.email.pushServerLocationUS', defaultMessage: 'US'})},
{value: PUSH_NOTIFICATIONS_LOCATION_DE, text: this.props.intl.formatMessage({id: 'admin.email.pushServerLocationDE', defaultMessage: 'Germany'})},
];
locationDropdown = (
@ -333,12 +340,7 @@ export default class PushSettings extends AdminSettings<Props, State> {
<DropdownSetting
id={DROPDOWN_ID_SERVER_TYPE}
values={pushNotificationServerTypes}
label={
<FormattedMessage
id='admin.email.pushTitle'
defaultMessage='Enable Push Notifications: '
/>
}
label={<FormattedMessage {...messages.pushTitle}/>}
value={this.state.pushNotificationServerType}
onChange={this.handleDropdownChange}
helpText={sendHelpText}
@ -349,13 +351,8 @@ export default class PushSettings extends AdminSettings<Props, State> {
{tosCheckbox}
<TextSetting
id='pushNotificationServer'
label={
<FormattedMessage
id='admin.email.pushServerTitle'
defaultMessage='Push Notification Server:'
/>
}
placeholder={Utils.localizeMessage('admin.email.pushServerEx', 'E.g.: "https://push-test.mattermost.com"')}
label={<FormattedMessage {...messages.pushServerTitle}/>}
placeholder={defineMessage({id: 'admin.email.pushServerEx', defaultMessage: 'E.g.: "https://push-test.mattermost.com"'})}
helpText={pushServerHelpText}
value={this.state.pushNotificationServer}
onChange={this.handleChange}
@ -371,7 +368,7 @@ export default class PushSettings extends AdminSettings<Props, State> {
defaultMessage='Max Notifications Per Channel:'
/>
}
placeholder={Utils.localizeMessage('admin.team.maxNotificationsPerChannelExample', 'E.g.: "1000"')}
placeholder={defineMessage({id: 'admin.team.maxNotificationsPerChannelExample', defaultMessage: 'E.g.: "1000"'})}
helpText={
<FormattedMessage
id='admin.team.maxNotificationsPerChannelDescription'
@ -387,3 +384,5 @@ export default class PushSettings extends AdminSettings<Props, State> {
);
};
}
export default injectIntl(PushSettings);

View File

@ -16,7 +16,12 @@ exports[`components/admin_console/request_button/request_button.jsx should match
>
<Memo(LoadingWrapper)
loading={false}
text="Loading..."
text={
<Memo(MemoizedFormattedMessage)
defaultMessage="Loading..."
id="admin.requestButton.loading"
/>
}
>
<MemoizedFormattedMessage
defaultMessage="Button Text"
@ -99,7 +104,12 @@ exports[`components/admin_console/request_button/request_button.jsx should match
>
<Memo(LoadingWrapper)
loading={false}
text="Loading..."
text={
<Memo(MemoizedFormattedMessage)
defaultMessage="Loading..."
id="admin.requestButton.loading"
/>
}
>
<FormattedMessage
defaultMessage="Button Text"
@ -224,7 +234,12 @@ exports[`components/admin_console/request_button/request_button.jsx should match
>
<Memo(LoadingWrapper)
loading={false}
text="Loading..."
text={
<Memo(MemoizedFormattedMessage)
defaultMessage="Loading..."
id="admin.requestButton.loading"
/>
}
>
<FormattedMessage
defaultMessage="Button Text"
@ -341,7 +356,12 @@ exports[`components/admin_console/request_button/request_button.jsx should match
>
<Memo(LoadingWrapper)
loading={false}
text="Loading..."
text={
<Memo(MemoizedFormattedMessage)
defaultMessage="Loading..."
id="admin.requestButton.loading"
/>
}
>
<FormattedMessage
defaultMessage="Button Text"
@ -461,7 +481,12 @@ exports[`components/admin_console/request_button/request_button.jsx should match
>
<Memo(LoadingWrapper)
loading={false}
text="Loading..."
text={
<Memo(MemoizedFormattedMessage)
defaultMessage="Loading..."
id="admin.requestButton.loading"
/>
}
>
<FormattedMessage
defaultMessage="Button Text"

View File

@ -2,15 +2,13 @@
// See LICENSE.txt for license information.
import React from 'react';
import {FormattedMessage} from 'react-intl';
import type {MessageDescriptor} from 'react-intl';
import {FormattedMessage, defineMessage} from 'react-intl';
import SuccessIcon from 'components/widgets/icons/fa_success_icon';
import WarningIcon from 'components/widgets/icons/fa_warning_icon';
import LoadingWrapper from 'components/widgets/loading/loading_wrapper';
import {t} from 'utils/i18n';
import * as Utils from 'utils/utils';
/**
* A button which, when clicked, performs an action and displays
* its outcome as either success, or failure accompanied by the
@ -27,8 +25,8 @@ type Props = {
* The action to be called to carry out the request.
*/
requestAction: (
success: (data?: any) => void,
error: (error: any) => void
success: () => void,
error: (error: {message: string; detailed_error?: string}) => void
) => void;
/**
@ -87,37 +85,12 @@ type Props = {
/**
* The message to show when the request completes successfully.
*/
successMessage: {
/**
* The i18n string ID for the success message.
*/
id: string;
/**
* The i18n default value for the success message.
*/
defaultMessage: string;
};
successMessage: string | MessageDescriptor;
/**
* The message to show when the request returns an error.
*/
errorMessage: {
/**
* The i18n string ID for the error message.
*/
id: string;
/**
* The i18n default value for the error message.
*
* The placeholder {error} may be used to include the error message returned
* by the server in response to the failed request.
*/
defaultMessage: string;
};
errorMessage: string | MessageDescriptor;
/**
* True if the {error} placeholder for the `errorMessage` property should include both
@ -144,14 +117,14 @@ export default class RequestButton extends React.PureComponent<Props, State> {
saveNeeded: false,
showSuccessMessage: true,
includeDetailedError: false,
successMessage: {
id: t('admin.requestButton.requestSuccess'),
successMessage: defineMessage({
id: 'admin.requestButton.requestSuccess',
defaultMessage: 'Test Successful',
},
errorMessage: {
id: t('admin.requestButton.requestFailure'),
}),
errorMessage: defineMessage({
id: 'admin.requestButton.requestFailure',
defaultMessage: 'Test Failure: {error}',
},
}),
};
constructor(props: Props) {
@ -203,33 +176,33 @@ export default class RequestButton extends React.PureComponent<Props, State> {
render() {
let message = null;
if (this.state.fail) {
const text = typeof this.props.errorMessage === 'string' ?
this.props.errorMessage :
(
<FormattedMessage
{...this.props.errorMessage}
values={{
error: this.state.fail,
}}
/>
);
message = (
<div>
<div className='alert alert-warning'>
<WarningIcon/>
<FormattedMessage
id={this.props.errorMessage.id}
defaultMessage={
this.props.errorMessage.defaultMessage
}
values={{
error: this.state.fail,
}}
/>
{text}
</div>
</div>
);
} else if (this.state.success && this.props.showSuccessMessage) {
const text = typeof this.props.successMessage === 'string' ?
this.props.successMessage :
(<FormattedMessage {...this.props.successMessage}/>);
message = (
<div>
<div className='alert alert-success'>
<SuccessIcon/>
<FormattedMessage
id={this.props.successMessage.id}
defaultMessage={
this.props.successMessage.defaultMessage
}
/>
{text}
</div>
</div>
);
@ -265,9 +238,11 @@ export default class RequestButton extends React.PureComponent<Props, State> {
loading={this.state.busy}
text={
this.props.loadingText ||
Utils.localizeMessage(
'admin.requestButton.loading',
'Loading...',
(
<FormattedMessage
id={'admin.requestButton.loading'}
defaultMessage={'Loading...'}
/>
)
}
>

View File

@ -1,15 +1,30 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {shallow} from 'enzyme';
import React from 'react';
import {FormattedMessage} from 'react-intl';
import SchemaText from 'components/admin_console/schema_text';
import {shallowWithIntl} from 'tests/helpers/intl-test-helper';
import SchemaAdminSettings from './schema_admin_settings';
import ValidationResult from './validation';
const getBaseProps = () => {
return {
cloud: {},
consoleAccess: {},
editRole: jest.fn(),
enterpriseReady: false,
isCurrentUserSystemAdmin: false,
isDisabled: false,
license: {},
roles: {},
setNavigationBlocked: jest.fn(),
};
};
describe('components/admin_console/SchemaAdminSettings', () => {
let schema = null;
let config = null;
@ -234,8 +249,9 @@ describe('components/admin_console/SchemaAdminSettings', () => {
});
test('should match snapshot with settings and plugin', () => {
const wrapper = shallow(
const wrapper = shallowWithIntl(
<SchemaAdminSettings
{...getBaseProps()}
config={config}
environmentConfig={environmentConfig}
schema={{...schema}}
@ -246,8 +262,9 @@ describe('components/admin_console/SchemaAdminSettings', () => {
});
test('should match snapshot with custom component', () => {
const wrapper = shallow(
const wrapper = shallowWithIntl(
<SchemaAdminSettings
{...getBaseProps()}
config={config}
environmentConfig={environmentConfig}
schema={{component: () => <p>{'Test'}</p>}}
@ -260,6 +277,7 @@ describe('components/admin_console/SchemaAdminSettings', () => {
test('should render header using a SchemaText', () => {
const headerText = 'This is [a link](!https://example.com) in the header';
const props = {
...getBaseProps(),
config,
environmentConfig,
schema: {
@ -269,7 +287,7 @@ describe('components/admin_console/SchemaAdminSettings', () => {
updateConfig: jest.fn(),
};
const wrapper = shallow(<SchemaAdminSettings {...props}/>);
const wrapper = shallowWithIntl(<SchemaAdminSettings {...props}/>);
const header = wrapper.find(SchemaText);
expect(header.exists()).toBe(true);
@ -282,6 +300,7 @@ describe('components/admin_console/SchemaAdminSettings', () => {
test('should render footer using a SchemaText', () => {
const footerText = 'This is [a link](https://example.com) in the footer';
const props = {
...getBaseProps(),
config,
environmentConfig,
schema: {
@ -291,7 +310,7 @@ describe('components/admin_console/SchemaAdminSettings', () => {
updateConfig: jest.fn(),
};
const wrapper = shallow(<SchemaAdminSettings {...props}/>);
const wrapper = shallowWithIntl(<SchemaAdminSettings {...props}/>);
const footer = wrapper.find(SchemaText);
expect(footer.exists()).toBe(true);
@ -303,13 +322,14 @@ describe('components/admin_console/SchemaAdminSettings', () => {
test('should render page not found', () => {
const props = {
...getBaseProps(),
config,
environmentConfig,
schema: null,
updateConfig: jest.fn(),
};
const wrapper = shallow(<SchemaAdminSettings {...props}/>);
const wrapper = shallowWithIntl(<SchemaAdminSettings {...props}/>);
expect(wrapper.contains(
<FormattedMessage
@ -335,13 +355,14 @@ describe('components/admin_console/SchemaAdminSettings', () => {
},
];
const props = {
...getBaseProps(),
config,
environmentConfig,
schema: localSchema,
updateConfig: jest.fn(),
};
const wrapper = shallow(<SchemaAdminSettings {...props}/>);
const wrapper = shallowWithIntl(<SchemaAdminSettings {...props}/>);
expect(wrapper.instance().canSave()).toBe(true);
expect(mockValidate).not.toHaveBeenCalled();
@ -364,13 +385,14 @@ describe('components/admin_console/SchemaAdminSettings', () => {
},
];
const props = {
...getBaseProps(),
config,
environmentConfig,
schema: localSchema,
updateConfig: jest.fn(),
};
const wrapper = shallow(<SchemaAdminSettings {...props}/>);
const wrapper = shallowWithIntl(<SchemaAdminSettings {...props}/>);
expect(wrapper.instance().canSave()).toBe(true);
expect(mockValidate).toHaveBeenCalled();

View File

@ -35,8 +35,7 @@ describe('SchemaText', () => {
const props = {
...baseProps,
isTranslated: true,
text: 'help.text',
textDefault: 'This is {object}',
text: {id: 'help.text', defaultMessage: 'This is {object}'},
textValues: {
object: 'help text',
},
@ -52,8 +51,7 @@ describe('SchemaText', () => {
...baseProps,
isMarkdown: true,
isTranslated: true,
text: 'help.text.markdown',
textDefault: 'This is [{object}](https://example.com)',
text: {id: 'help.text.markdown', defaultMessage: 'This is [{object}](https://example.com)'},
textValues: {
object: 'a help link',
},

View File

@ -3,60 +3,24 @@
import marked from 'marked';
import React from 'react';
import type {MessageDescriptor} from 'react-intl';
import {FormattedMessage} from 'react-intl';
import FormattedMarkdownMessage, {CustomRenderer} from 'components/formatted_markdown_message';
type Props = {
isMarkdown?: boolean;
isTranslated?: boolean;
text: string | object;
textDefault?: string;
text: string | MessageDescriptor | JSX.Element;
textValues?: Record<string, React.ReactNode>;
}
export default class SchemaText extends React.PureComponent<Props> {
static defaultProps = {
isTranslated: true,
};
renderTranslated = () => {
const {
isMarkdown,
text,
textDefault,
textValues,
} = this.props;
if (typeof text === 'object') {
return text;
}
const SchemaText = ({
isMarkdown,
text,
textValues,
}: Props) => {
if (typeof text === 'string') {
if (isMarkdown) {
return (
<FormattedMarkdownMessage
id={text}
defaultMessage={textDefault}
values={textValues}
/>
);
}
return (
<FormattedMessage
id={text}
values={textValues}
defaultMessage={textDefault}
/>
);
};
renderUntranslated = () => {
const {isMarkdown, text} = this.props;
if (isMarkdown) {
if (typeof text === 'object') {
return text;
}
const html = marked(text, {
breaks: true,
sanitize: true,
@ -67,9 +31,27 @@ export default class SchemaText extends React.PureComponent<Props> {
}
return <span>{text}</span>;
};
render() {
return this.props.isTranslated ? this.renderTranslated() : this.renderUntranslated();
}
}
if ('id' in text) {
if (isMarkdown) {
return (
<FormattedMarkdownMessage
{...text}
values={textValues}
/>
);
}
return (
<FormattedMessage
{...text}
values={textValues}
/>
);
}
return text as JSX.Element;
};
export default SchemaText;

View File

@ -3,7 +3,7 @@
import {debounce} from 'lodash';
import React from 'react';
import {FormattedMessage} from 'react-intl';
import {FormattedMessage, defineMessages} from 'react-intl';
import type {
LogFilter,
@ -43,6 +43,16 @@ type State = {
loadingPlain: boolean;
};
const messages = defineMessages({
title: {id: 'admin.logs.title', defaultMessage: 'Server Logs'},
bannerDesc: {id: 'admin.logs.bannerDesc', defaultMessage: 'To look up users by User ID or Token ID, go to User Management > Users and paste the ID into the search filter.'},
});
export const searchableStrings = [
messages.title,
messages.bannerDesc,
];
export default class Logs extends React.PureComponent<Props, State> {
constructor(props: Props) {
super(props);
@ -131,10 +141,7 @@ export default class Logs extends React.PureComponent<Props, State> {
<>
<div className='banner'>
<div className='banner__content'>
<FormattedMessage
id='admin.logs.bannerDesc'
defaultMessage='To look up users by User ID or Token ID, go to User Management > Users and paste the ID into the search filter.'
/>
<FormattedMessage {...messages.bannerDesc}/>
</div>
</div>
<button
@ -160,10 +167,7 @@ export default class Logs extends React.PureComponent<Props, State> {
<div className='logs-banner'>
<div className='banner'>
<div className='banner__content'>
<FormattedMessage
id='admin.logs.bannerDesc'
defaultMessage='To look up users by User ID or Token ID, go to User Management > Users and paste the ID into the search filter.'
/>
<FormattedMessage {...messages.bannerDesc}/>
</div>
</div>
<button
@ -195,10 +199,7 @@ export default class Logs extends React.PureComponent<Props, State> {
return (
<div className='wrapper--admin'>
<AdminHeader>
<FormattedMessage
id='admin.logs.title'
defaultMessage='Server Logs'
/>
<FormattedMessage {...messages.title}/>
</AdminHeader>
<div className='admin-console__wrapper'>
<div className='admin-logs-content admin-console__content'>

View File

@ -2,14 +2,12 @@
// See LICENSE.txt for license information.
import React from 'react';
import {FormattedMessage} from 'react-intl';
import {FormattedMessage, defineMessage, defineMessages} from 'react-intl';
import type {AdminConfig, ClientLicense, ServiceSettings} from '@mattermost/types/config';
import FormattedMarkdownMessage from 'components/formatted_markdown_message';
import * as Utils from 'utils/utils';
import AdminSettings from './admin_settings';
import type {BaseState, BaseProps} from './admin_settings';
import BooleanSetting from './boolean_setting';
@ -26,9 +24,49 @@ interface State extends BaseState {
sessionIdleTimeoutMobileInMinutes: ClientLicense['SessionIdleTimeoutMobileInMinutes'];
}
interface Props extends BaseProps {
type Props = BaseProps & {
license: ClientLicense;
}
};
const messages = defineMessages({
title: {id: 'admin.sessionLengths.title', defaultMessage: 'Session Lengths'},
webSessionHoursDesc_extendLength: {id: 'admin.service.webSessionHoursDesc.extendLength', defaultMessage: "Set the number of hours from the last activity in Mattermost to the expiry of the user's session when using email and AD/LDAP authentication. After changing this setting, the new session length will take effect after the next time the user enters their credentials."},
mobileSessionHoursDesc_extendLength: {id: 'admin.service.mobileSessionHoursDesc.extendLength', defaultMessage: "Set the number of hours from the last activity in Mattermost to the expiry of the user's session on mobile. After changing this setting, the new session length will take effect after the next time the user enters their credentials."},
ssoSessionHoursDesc_extendLength: {id: 'admin.service.ssoSessionHoursDesc.extendLength', defaultMessage: "Set the number of hours from the last activity in Mattermost to the expiry of the user's session for SSO authentication, such as SAML, GitLab and OAuth 2.0. If the authentication method is SAML or GitLab, the user may automatically be logged back in to Mattermost if they are already logged in to SAML or GitLab. After changing this setting, the setting will take effect after the next time the user enters their credentials."},
webSessionHoursDesc: {id: 'admin.service.webSessionHoursDesc', defaultMessage: "The number of hours from the last time a user entered their credentials to the expiry of the user's session. After changing this setting, the new session length will take effect after the next time the user enters their credentials."},
mobileSessionHoursDesc: {id: 'admin.service.mobileSessionHoursDesc', defaultMessage: "The number of hours from the last time a user entered their credentials to the expiry of the user's session. After changing this setting, the new session length will take effect after the next time the user enters their credentials."},
ssoSessionHoursDesc: {id: 'admin.service.ssoSessionHoursDesc', defaultMessage: "The number of hours from the last time a user entered their credentials to the expiry of the user's session. If the authentication method is SAML or GitLab, the user may automatically be logged back in to Mattermost if they are already logged in to SAML or GitLab. After changing this setting, the setting will take effect after the next time the user enters their credentials."},
sessionIdleTimeout: {id: 'admin.service.sessionIdleTimeout', defaultMessage: 'Session Idle Timeout (minutes):'},
extendSessionLengthActivity_label: {id: 'admin.service.extendSessionLengthActivity.label', defaultMessage: 'Extend session length with activity: '},
extendSessionLengthActivity_helpText: {id: 'admin.service.extendSessionLengthActivity.helpText', defaultMessage: 'When true, sessions will be automatically extended when the user is active in their Mattermost client. Users sessions will only expire if they are not active in their Mattermost client for the entire duration of the session lengths defined in the fields below. When false, sessions will not extend with activity in Mattermost. User sessions will immediately expire at the end of the session length or idle timeouts defined below. '},
webSessionHours: {id: 'admin.service.webSessionHours', defaultMessage: 'Session Length AD/LDAP and Email (hours):'},
mobileSessionHours: {id: 'admin.service.mobileSessionHours', defaultMessage: 'Session Length Mobile (hours):'},
ssoSessionHours: {id: 'admin.service.ssoSessionHours', defaultMessage: 'Session Length SSO (hours):'},
sessionCache: {id: 'admin.service.sessionCache', defaultMessage: 'Session Cache (minutes):'},
sessionCacheDesc: {id: 'admin.service.sessionCacheDesc', defaultMessage: 'The number of minutes to cache a session in memory:'},
sessionHoursEx: {id: 'admin.service.sessionHoursEx', defaultMessage: 'E.g.: "720"'},
sessionIdleTimeoutDesc: {id: 'admin.service.sessionIdleTimeoutDesc', defaultMessage: "The number of minutes from the last time a user was active on the system to the expiry of the user's session. Once expired, the user will need to log in to continue. Minimum is 5 minutes, and 0 is unlimited. Applies to the desktop app and browsers. For mobile apps, use an EMM provider to lock the app when not in use. In High Availability mode, enable IP hash load balancing for reliable timeout measurement."},
});
export const searchableStrings = [
messages.title,
messages.webSessionHoursDesc_extendLength,
messages.mobileSessionHoursDesc_extendLength,
messages.ssoSessionHoursDesc_extendLength,
messages.webSessionHoursDesc,
messages.mobileSessionHoursDesc,
messages.ssoSessionHoursDesc,
messages.sessionIdleTimeout,
messages.extendSessionLengthActivity_label,
messages.extendSessionLengthActivity_helpText,
messages.webSessionHours,
messages.mobileSessionHours,
messages.ssoSessionHours,
messages.sessionCache,
messages.sessionCacheDesc,
messages.sessionHoursEx,
messages.sessionIdleTimeoutDesc,
];
export default class SessionLengthSettings extends AdminSettings<Props, State> {
getConfigFromState = (config: AdminConfig) => {
@ -57,10 +95,7 @@ export default class SessionLengthSettings extends AdminSettings<Props, State> {
renderTitle() {
return (
<FormattedMessage
id='admin.sessionLengths.title'
defaultMessage='Session Lengths'
/>
<FormattedMessage {...messages.title}/>
);
}
@ -70,62 +105,22 @@ export default class SessionLengthSettings extends AdminSettings<Props, State> {
let sessionLengthSSOHelpText;
let sessionTimeoutSetting;
if (this.state.extendSessionLengthWithActivity) {
sessionLengthWebHelpText = (
<FormattedMessage
id='admin.service.webSessionHoursDesc.extendLength'
defaultMessage="Set the number of hours from the last activity in Mattermost to the expiry of the user's session when using email and AD/LDAP authentication. After changing this setting, the new session length will take effect after the next time the user enters their credentials."
/>
);
sessionLengthMobileHelpText = (
<FormattedMessage
id='admin.service.mobileSessionHoursDesc.extendLength'
defaultMessage="Set the number of hours from the last activity in Mattermost to the expiry of the user's session on mobile. After changing this setting, the new session length will take effect after the next time the user enters their credentials."
/>
);
sessionLengthSSOHelpText = (
<FormattedMessage
id='admin.service.ssoSessionHoursDesc.extendLength'
defaultMessage="Set the number of hours from the last activity in Mattermost to the expiry of the user's session for SSO authentication, such as SAML, GitLab and OAuth 2.0. If the authentication method is SAML or GitLab, the user may automatically be logged back in to Mattermost if they are already logged in to SAML or GitLab. After changing this setting, the setting will take effect after the next time the user enters their credentials."
/>
);
sessionLengthWebHelpText = (<FormattedMessage {...messages.webSessionHoursDesc_extendLength}/>);
sessionLengthMobileHelpText = (<FormattedMessage {...messages.mobileSessionHoursDesc_extendLength}/>);
sessionLengthSSOHelpText = (<FormattedMessage {...messages.ssoSessionHoursDesc_extendLength}/>);
} else {
sessionLengthWebHelpText = (
<FormattedMessage
id='admin.service.webSessionHoursDesc'
defaultMessage="The number of hours from the last time a user entered their credentials to the expiry of the user's session. After changing this setting, the new session length will take effect after the next time the user enters their credentials."
/>
);
sessionLengthMobileHelpText = (
<FormattedMessage
id='admin.service.mobileSessionHoursDesc'
defaultMessage="The number of hours from the last time a user entered their credentials to the expiry of the user's session. After changing this setting, the new session length will take effect after the next time the user enters their credentials."
/>
);
sessionLengthSSOHelpText = (
<FormattedMessage
id='admin.service.ssoSessionHoursDesc'
defaultMessage="The number of hours from the last time a user entered their credentials to the expiry of the user's session. If the authentication method is SAML or GitLab, the user may automatically be logged back in to Mattermost if they are already logged in to SAML or GitLab. After changing this setting, the setting will take effect after the next time the user enters their credentials."
/>
);
sessionLengthWebHelpText = (<FormattedMessage {...messages.webSessionHoursDesc}/>);
sessionLengthMobileHelpText = (<FormattedMessage {...messages.mobileSessionHoursDesc}/>);
sessionLengthSSOHelpText = (<FormattedMessage {...messages.ssoSessionHoursDesc}/>);
}
if (this.props.license.Compliance && !this.state.extendSessionLengthWithActivity) {
sessionTimeoutSetting = (
<TextSetting
id='sessionIdleTimeoutInMinutes'
type='number'
label={
<FormattedMessage
id='admin.service.sessionIdleTimeout'
defaultMessage='Session Idle Timeout (minutes):'
/>
}
placeholder={Utils.localizeMessage('admin.service.sessionIdleTimeoutEx', 'E.g.: "60"')}
helpText={
<FormattedMarkdownMessage
id='admin.service.sessionIdleTimeoutDesc'
defaultMessage="The number of minutes from the last time a user was active on the system to the expiry of the user\'s session. Once expired, the user will need to log in to continue. Minimum is 5 minutes, and 0 is unlimited.\n \nApplies to the desktop app and browsers. For mobile apps, use an EMM provider to lock the app when not in use. In High Availability mode, enable IP hash load balancing for reliable timeout measurement."
/>
}
label={<FormattedMessage {...messages.sessionIdleTimeout}/>}
placeholder={defineMessage({id: 'admin.service.sessionIdleTimeoutEx', defaultMessage: 'E.g.: "60"'})}
helpText={<FormattedMarkdownMessage {...messages.sessionIdleTimeoutDesc}/>}
value={this.state.sessionIdleTimeoutInMinutes}
onChange={this.handleChange}
setByEnv={this.isSetByEnv('ServiceSettings.SessionIdleTimeoutInMinutes')}
@ -138,18 +133,8 @@ export default class SessionLengthSettings extends AdminSettings<Props, State> {
<SettingsGroup>
<BooleanSetting
id='extendSessionLengthWithActivity'
label={
<FormattedMessage
id='admin.service.extendSessionLengthActivity.label'
defaultMessage='Extend session length with activity: '
/>
}
helpText={
<FormattedMessage
id='admin.service.extendSessionLengthActivity.helpText'
defaultMessage='When true, sessions will be automatically extended when the user is active in their Mattermost client. Users sessions will only expire if they are not active in their Mattermost client for the entire duration of the session lengths defined in the fields below. When false, sessions will not extend with activity in Mattermost. User sessions will immediately expire at the end of the session length or idle timeouts defined below. '
/>
}
label={<FormattedMessage {...messages.extendSessionLengthActivity_label}/>}
helpText={<FormattedMessage {...messages.extendSessionLengthActivity_helpText}/>}
value={this.state.extendSessionLengthWithActivity}
onChange={this.handleChange}
setByEnv={this.isSetByEnv('ServiceSettings.ExtendSessionLengthWithActivity')}
@ -157,13 +142,8 @@ export default class SessionLengthSettings extends AdminSettings<Props, State> {
/>
<TextSetting
id='sessionLengthWebInHours'
label={
<FormattedMessage
id='admin.service.webSessionHours'
defaultMessage='Session Length AD/LDAP and Email (hours):'
/>
}
placeholder={Utils.localizeMessage('admin.service.sessionHoursEx', 'E.g.: "720"')}
label={<FormattedMessage {...messages.webSessionHours}/>}
placeholder={defineMessage(messages.sessionHoursEx)}
helpText={sessionLengthWebHelpText}
value={this.state.sessionLengthWebInHours}
onChange={this.handleChange}
@ -173,12 +153,8 @@ export default class SessionLengthSettings extends AdminSettings<Props, State> {
/>
<TextSetting
id='sessionLengthMobileInHours'
label={
<FormattedMessage
id='admin.service.mobileSessionHours'
defaultMessage='Session Length Mobile (hours):'
/>}
placeholder={Utils.localizeMessage('admin.service.sessionHoursEx', 'E.g.: "720"')}
label={<FormattedMessage {...messages.mobileSessionHours}/>}
placeholder={defineMessage(messages.sessionHoursEx)}
helpText={sessionLengthMobileHelpText}
value={this.state.sessionLengthMobileInHours}
onChange={this.handleChange}
@ -188,12 +164,8 @@ export default class SessionLengthSettings extends AdminSettings<Props, State> {
/>
<TextSetting
id='sessionLengthSSOInHours'
label={
<FormattedMessage
id='admin.service.ssoSessionHours'
defaultMessage='Session Length SSO (hours):'
/>}
placeholder={Utils.localizeMessage('admin.service.sessionHoursEx', 'E.g.: "720"')}
label={<FormattedMessage {...messages.ssoSessionHours}/>}
placeholder={defineMessage(messages.sessionHoursEx)}
helpText={sessionLengthSSOHelpText}
value={this.state.sessionLengthSSOInHours}
onChange={this.handleChange}
@ -203,17 +175,9 @@ export default class SessionLengthSettings extends AdminSettings<Props, State> {
/>
<TextSetting
id='sessionCacheInMinutes'
label={
<FormattedMessage
id='admin.service.sessionCache'
defaultMessage='Session Cache (minutes):'
/>}
placeholder={Utils.localizeMessage('admin.service.sessionMinutesEx', 'E.g.: "10"')}
helpText={
<FormattedMessage
id='admin.service.sessionCacheDesc'
defaultMessage='The number of minutes to cache a session in memory:'
/>}
label={<FormattedMessage {...messages.sessionCache}/>}
placeholder={defineMessage({id: 'admin.service.sessionMinutesEx', defaultMessage: 'E.g.: "10"'})}
helpText={<FormattedMessage {...messages.sessionCacheDesc}/>}
value={this.state.sessionCacheInMinutes}
onChange={this.handleChange}
setByEnv={this.isSetByEnv('ServiceSettings.SessionCacheInMinutes')}

View File

@ -8,7 +8,7 @@ import SetByEnv from './set_by_env';
export type Props = {
inputId?: string;
label: React.ReactNode;
children: React.ReactNode;
children?: React.ReactNode;
helpText?: React.ReactNode;
setByEnv?: boolean;
}

View File

@ -17,12 +17,19 @@ exports[`admin_console/system_roles should match snapshot 1`] = `
className="admin-console__content"
>
<AdminPanel
className=""
id="SystemRoles"
subtitleDefault="Manage different levels of access to the system console."
subtitleId="admin.permissions.systemRolesBannerText"
titleDefault="Admin Roles"
titleId="admin.permissions.systemRolesBannerTitle"
subtitle={
Object {
"defaultMessage": "Manage different levels of access to the system console.",
"id": "admin.permissions.systemRolesBannerText",
}
}
title={
Object {
"defaultMessage": "Admin Roles",
"id": "admin.permissions.systemRolesBannerTitle",
}
}
>
<div
className="SystemRoles"
@ -63,6 +70,7 @@ exports[`admin_console/system_roles should match snapshot 1`] = `
Object {
"cells": Object {
"description": <Memo(MemoizedFormattedMessage)
defaultMessage="Access to modifying everything."
id="admin.permissions.roles.system_admin.description"
/>,
"edit": <span
@ -79,9 +87,11 @@ exports[`admin_console/system_roles should match snapshot 1`] = `
</Link>
</span>,
"role": <Memo(MemoizedFormattedMessage)
defaultMessage="System Admin"
id="admin.permissions.roles.system_admin.name"
/>,
"type": <Memo(MemoizedFormattedMessage)
defaultMessage="System Role"
id="admin.permissions.roles.system_admin.type"
/>,
},

View File

@ -0,0 +1,77 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {defineMessages, type MessageDescriptor} from 'react-intl';
export const rolesStrings: Record<string, Record<string, MessageDescriptor>> = {
system_admin: defineMessages({
name: {
id: 'admin.permissions.roles.system_admin.name',
defaultMessage: 'System Admin',
},
description: {
id: 'admin.permissions.roles.system_admin.description',
defaultMessage: 'Access to modifying everything.',
},
type: {
id: 'admin.permissions.roles.system_admin.type',
defaultMessage: 'System Role',
},
}),
system_user_manager: defineMessages({
name: {
id: 'admin.permissions.roles.system_user_manager.name',
defaultMessage: 'User Manager',
},
description: {
id: 'admin.permissions.roles.system_user_manager.description',
defaultMessage: 'Enough access to help with user management.',
},
type: {
id: 'admin.permissions.roles.system_user_manager.type',
defaultMessage: 'System Role',
},
}),
system_manager: defineMessages({
name: {
id: 'admin.permissions.roles.system_manager.name',
defaultMessage: 'System Manager',
},
description: {
id: 'admin.permissions.roles.system_manager.description',
defaultMessage: 'Slightly less access than system admin.',
},
type: {
id: 'admin.permissions.roles.system_manager.type',
defaultMessage: 'System Role',
},
}),
system_read_only_admin: defineMessages({
name: {
id: 'admin.permissions.roles.system_read_only_admin.name',
defaultMessage: 'Viewer',
},
description: {
id: 'admin.permissions.roles.system_read_only_admin.description',
defaultMessage: 'Read only access for oversight.',
},
type: {
id: 'admin.permissions.roles.system_read_only_admin.type',
defaultMessage: 'System Role',
},
}),
system_custom_group_admin: defineMessages({
name: {
id: 'admin.permissions.roles.system_custom_group_admin.name',
defaultMessage: 'Custom Group Manager',
},
description: {
id: 'admin.permissions.roles.system_custom_group_admin.description',
defaultMessage: 'Administers all Custom Groups across the system.',
},
type: {
id: 'admin.permissions.roles.system_custom_group_admin.type',
defaultMessage: 'System Role',
},
}),
};

View File

@ -12,10 +12,7 @@ exports[`admin_console/system_role should match snapshot 1`] = `
className="fa fa-angle-left back"
to="/admin_console/user_management/system_roles"
/>
<MemoizedFormattedMessage
defaultMessage="R O L E _ N A M E"
id="admin.permissions.roles.role_name.name"
/>
role_name
</div>
</AdminHeader>
<div
@ -77,10 +74,7 @@ exports[`admin_console/system_role should match snapshot with isLicensedForCloud
className="fa fa-angle-left back"
to="/admin_console/user_management/system_roles"
/>
<MemoizedFormattedMessage
defaultMessage="R O L E _ N A M E"
id="admin.permissions.roles.role_name.name"
/>
role_name
</div>
</AdminHeader>
<div

View File

@ -6,7 +6,7 @@ exports[`admin_console/system_role_permission should match snapshot 1`] = `
>
<div
className="PermissionSection"
key="environemnt"
key="environment"
>
<div
className="PermissionSectionText"
@ -15,16 +15,16 @@ exports[`admin_console/system_role_permission should match snapshot 1`] = `
className="PermissionSectionText_title"
>
<MemoizedFormattedMessage
defaultMessage="environemnt"
id="admin.permissions.sysconsole_section_environemnt.name"
defaultMessage="Environment"
id="admin.permissions.sysconsole_section_environment.name"
/>
</div>
<div
className="PermissionSection_description"
>
<MemoizedFormattedMessage
defaultMessage=""
id="admin.permissions.sysconsole_section_environemnt.description"
defaultMessage="Review server environment configuration such as URLs, database and performance."
id="admin.permissions.sysconsole_section_environment.description"
/>
</div>
</div>
@ -32,12 +32,12 @@ exports[`admin_console/system_role_permission should match snapshot 1`] = `
className="PermissionSectionDropdown"
>
<SystemRolePermissionDropdown
access={false}
access="read"
isDisabled={true}
section={
Object {
"hasDescription": true,
"name": "environemnt",
"name": "environment",
"subsections": Array [],
}
}

View File

@ -2,12 +2,19 @@
exports[`admin_console/system_role_permissions should match snapshot 1`] = `
<AdminPanel
className=""
id="SystemRolePermissions"
subtitleDefault="Level of access to the system console."
subtitleId="admin.permissions.system_role_permissions.description"
titleDefault="Privileges"
titleId="admin.permissions.system_role_permissions.title"
subtitle={
Object {
"defaultMessage": "Level of access to the system console.",
"id": "admin.permissions.system_role_permissions.description",
}
}
title={
Object {
"defaultMessage": "Privileges",
"id": "admin.permissions.system_role_permissions.title",
}
}
>
<div
className="SystemRolePermissions"
@ -395,12 +402,19 @@ exports[`admin_console/system_role_permissions should match snapshot 1`] = `
exports[`admin_console/system_role_permissions should match snapshot with isLicensedForCloud = true 1`] = `
<AdminPanel
className=""
id="SystemRolePermissions"
subtitleDefault="Level of access to the system console."
subtitleId="admin.permissions.system_role_permissions.description"
titleDefault="Privileges"
titleId="admin.permissions.system_role_permissions.title"
subtitle={
Object {
"defaultMessage": "Level of access to the system console.",
"id": "admin.permissions.system_role_permissions.description",
}
}
title={
Object {
"defaultMessage": "Privileges",
"id": "admin.permissions.system_role_permissions.title",
}
}
>
<div
className="SystemRolePermissions"

View File

@ -44,10 +44,7 @@ exports[`admin_console/add_users_to_role_modal search should not include bot use
values={
Object {
"roleName": <strong>
<Memo(MemoizedFormattedMessage)
defaultMessage="role_name"
id="admin.permissions.roles.role_name.name"
/>
role_name
</strong>,
}
}
@ -227,10 +224,7 @@ exports[`admin_console/add_users_to_role_modal should exclude user 1`] = `
values={
Object {
"roleName": <strong>
<Memo(MemoizedFormattedMessage)
defaultMessage="role_name"
id="admin.permissions.roles.role_name.name"
/>
role_name
</strong>,
}
}
@ -366,10 +360,7 @@ exports[`admin_console/add_users_to_role_modal should have single passed value 1
values={
Object {
"roleName": <strong>
<Memo(MemoizedFormattedMessage)
defaultMessage="role_name"
id="admin.permissions.roles.role_name.name"
/>
role_name
</strong>,
}
}
@ -549,10 +540,7 @@ exports[`admin_console/add_users_to_role_modal should include additional user 1`
values={
Object {
"roleName": <strong>
<Memo(MemoizedFormattedMessage)
defaultMessage="role_name"
id="admin.permissions.roles.role_name.name"
/>
role_name
</strong>,
}
}
@ -773,10 +761,7 @@ exports[`admin_console/add_users_to_role_modal should include additional user 2`
values={
Object {
"roleName": <strong>
<Memo(MemoizedFormattedMessage)
defaultMessage="role_name"
id="admin.permissions.roles.role_name.name"
/>
role_name
</strong>,
}
}
@ -997,10 +982,7 @@ exports[`admin_console/add_users_to_role_modal should not include bot user 1`] =
values={
Object {
"roleName": <strong>
<Memo(MemoizedFormattedMessage)
defaultMessage="role_name"
id="admin.permissions.roles.role_name.name"
/>
role_name
</strong>,
}
}

View File

@ -22,6 +22,8 @@ import GuestTag from 'components/widgets/tag/guest_tag';
import {displayEntireNameForUser, localizeMessage} from 'utils/utils';
import {rolesStrings} from '../../strings';
const USERS_PER_PAGE = 50;
const MAX_SELECTABLE_VALUES = 20;
@ -219,6 +221,8 @@ export class AddUsersToRoleModal extends React.PureComponent<Props, State> {
return {label: user.username, value: user.id, ...user};
});
const name = rolesStrings[this.props.role.name] ? <FormattedMessage {...rolesStrings[this.props.role.name].name}/> : this.props.role.name;
return (
<Modal
id='addUsersToRoleModal'
@ -235,10 +239,7 @@ export class AddUsersToRoleModal extends React.PureComponent<Props, State> {
values={{
roleName: (
<strong>
<FormattedMessage
id={`admin.permissions.roles.${this.props.role.name}.name`}
defaultMessage={this.props.role.name}
/>
{name}
</strong>
),
}}

View File

@ -0,0 +1,433 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {defineMessages, type MessageDescriptor} from 'react-intl';
export const sectionStrings: Record<string, Record<string, MessageDescriptor>> = {
about: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_about.name',
defaultMessage: 'About',
},
description: {
id: 'admin.permissions.sysconsole_section_about.description',
defaultMessage: 'The ability to install or upgrade your servers enterprise licensing.',
},
}),
about_edition_and_license: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_about_edition_and_license.name',
defaultMessage: 'Edition and License',
},
}),
billing: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_billing.name',
defaultMessage: 'Billing',
},
description: {
id: 'admin.permissions.sysconsole_section_billing.description',
defaultMessage: 'Access subscription details, billing history, company information and payment information.',
},
}),
reporting: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_reporting.name',
defaultMessage: 'Reporting',
},
description: {
id: 'admin.permissions.sysconsole_section_reporting.description',
defaultMessage: 'Review site statistics, team statistics and server logs.',
},
}),
reporting_site_statistics: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_reporting_site_statistics.name',
defaultMessage: 'Site Statistics',
},
}),
reporting_team_statistics: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_reporting_team_statistics.name',
defaultMessage: 'Team Statistics',
},
}),
reporting_server_logs: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_reporting_server_logs.name',
defaultMessage: 'Server Logs',
},
}),
user_management: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_user_management.name',
defaultMessage: 'User Management',
},
description: {
id: 'admin.permissions.sysconsole_section_user_management.description',
defaultMessage: 'Review users, groups, teams, channels, permissions and system roles.',
},
}),
user_management_users: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_user_management_users.name',
defaultMessage: 'Users',
},
description: {
id: 'admin.permissions.sysconsole_section_user_management_users.description',
defaultMessage: 'Cannot reset admin passwords',
},
}),
user_management_groups: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_user_management_groups.name',
defaultMessage: 'Groups',
},
}),
user_management_teams: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_user_management_teams.name',
defaultMessage: 'Teams',
},
}),
user_management_channels: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_user_management_channels.name',
defaultMessage: 'Channels',
},
}),
user_management_permissions: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_user_management_permissions.name',
defaultMessage: 'Permissions',
},
}),
user_management_system_roles: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_user_management_system_roles.name',
defaultMessage: 'System Roles',
},
}),
environment: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_environment.name',
defaultMessage: 'Environment',
},
description: {
id: 'admin.permissions.sysconsole_section_environment.description',
defaultMessage: 'Review server environment configuration such as URLs, database and performance.',
},
}),
environment_web_server: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_environment_web_server.name',
defaultMessage: 'Web Server',
},
}),
environment_database: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_environment_database.name',
defaultMessage: 'Database',
},
}),
environment_elasticsearch: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_environment_elasticsearch.name',
defaultMessage: 'Elasticsearch',
},
}),
environment_file_storage: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_environment_file_storage.name',
defaultMessage: 'File Storage',
},
}),
environment_image_proxy: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_environment_image_proxy.name',
defaultMessage: 'Image Proxy',
},
}),
environment_smtp: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_environment_smtp.name',
defaultMessage: 'SMTP',
},
}),
environment_push_notification_server: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_environment_push_notification_server.name',
defaultMessage: 'Push Notification Server',
},
}),
environment_high_availability: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_environment_high_availability.name',
defaultMessage: 'High Availability',
},
}),
environment_rate_limiting: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_environment_rate_limiting.name',
defaultMessage: 'Rate Limiting',
},
}),
environment_logging: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_environment_logging.name',
defaultMessage: 'Logging',
},
}),
environment_session_lengths: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_environment_session_lengths.name',
defaultMessage: 'Session Lengths',
},
}),
environment_performance_monitoring: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_environment_performance_monitoring.name',
defaultMessage: 'Performance Monitoring',
},
}),
environment_developer: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_environment_developer.name',
defaultMessage: 'Developer',
},
}),
site: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_site.name',
defaultMessage: 'Site Configuration',
},
description: {
id: 'admin.permissions.sysconsole_section_site.description',
defaultMessage: 'Review site specific configurations such as site name, notification defaults and file sharing.',
},
}),
site_customization: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_site_customization.name',
defaultMessage: 'Customization',
},
}),
site_localization: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_site_localization.name',
defaultMessage: 'Localization',
},
}),
site_users_and_teams: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_site_users_and_teams.name',
defaultMessage: 'Users and Teams',
},
}),
site_notifications: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_site_notifications.name',
defaultMessage: 'Notifications',
},
}),
site_announcement_banner: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_site_announcement_banner.name',
defaultMessage: 'Announcement Banner',
},
}),
site_emoji: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_site_emoji.name',
defaultMessage: 'Emoji',
},
}),
site_posts: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_site_posts.name',
defaultMessage: 'Posts',
},
}),
site_file_sharing_and_downloads: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_site_file_sharing_and_downloads.name',
defaultMessage: 'File Sharing and Downloads',
},
}),
site_public_links: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_site_public_links.name',
defaultMessage: 'Public Links',
},
}),
site_notices: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_site_notices.name',
defaultMessage: 'Notices',
},
}),
authentication: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_authentication.name',
defaultMessage: 'Authentication',
},
description: {
id: 'admin.permissions.sysconsole_section_authentication.description',
defaultMessage: 'Review the configuration around how users can signup and access Mattermost.',
},
}),
authentication_signup: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_authentication_signup.name',
defaultMessage: 'Signup',
},
}),
authentication_email: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_authentication_email.name',
defaultMessage: 'Email',
},
}),
authentication_password: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_authentication_password.name',
defaultMessage: 'Password',
},
}),
authentication_mfa: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_authentication_mfa.name',
defaultMessage: 'MFA',
},
}),
authentication_ldap: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_authentication_ldap.name',
defaultMessage: 'AD/LDAP',
},
}),
authentication_saml: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_authentication_saml.name',
defaultMessage: 'SAML 2.0',
},
}),
authentication_openid: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_authentication_openid.name',
defaultMessage: 'OpenID Connect',
},
}),
authentication_guest_access: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_authentication_guest_access.name',
defaultMessage: 'Guest Access',
},
}),
plugins: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_plugins.name',
defaultMessage: 'Plugins',
},
description: {
id: 'admin.permissions.sysconsole_section_plugins.description',
defaultMessage: 'Review installed plugins and their configuration.',
},
}),
integrations: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_integrations.name',
defaultMessage: 'Integrations',
},
description: {
id: 'admin.permissions.sysconsole_section_integrations.description',
defaultMessage: 'Review integration configurations such as webhooks, bots and cross-origin requests.',
},
}),
integrations_integration_management: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_integrations_integration_management.name',
defaultMessage: 'Integration Management',
},
}),
integrations_bot_accounts: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_integrations_bot_accounts.name',
defaultMessage: 'Bot Accounts',
},
}),
integrations_gif: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_integrations_gif.name',
defaultMessage: 'GIF (Beta)',
},
}),
integrations_cors: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_integrations_cors.name',
defaultMessage: 'CORS',
},
}),
compliance: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_compliance.name',
defaultMessage: 'Compliance',
},
description: {
id: 'admin.permissions.sysconsole_section_compliance.description',
defaultMessage: 'Review compliance settings such as retention, exports and activity logs.',
},
}),
compliance_data_retention_policy: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_compliance_data_retention_policy.name',
defaultMessage: 'Data Retention Policy',
},
}),
compliance_compliance_export: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_compliance_compliance_export.name',
defaultMessage: 'Compliance Export',
},
}),
compliance_compliance_monitoring: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_compliance_compliance_monitoring.name',
defaultMessage: 'Compliance Monitoring',
},
}),
compliance_custom_terms_of_service: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_compliance_custom_terms_of_service.name',
defaultMessage: 'Custom Terms of Service',
},
}),
experimental: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_experimental.name',
defaultMessage: 'Experimental',
},
description: {
id: 'admin.permissions.sysconsole_section_experimental.description',
defaultMessage: 'Review the settings of experimental features',
},
}),
experimental_features: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_experimental_features.name',
defaultMessage: 'Features',
},
}),
experimental_feature_flags: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_experimental_feature_flags.name',
defaultMessage: 'Feature Flags',
},
}),
experimental_bleve: defineMessages({
name: {
id: 'admin.permissions.sysconsole_section_experimental_bleve.name',
defaultMessage: 'Bleve',
},
}),
};

View File

@ -27,6 +27,8 @@ import SystemRoleUsers from './system_role_users';
import {writeAccess} from './types';
import type {PermissionToUpdate, PermissionsToUpdate} from './types';
import {rolesStrings} from '../strings';
type Props = {
role: Role;
isDisabled?: boolean;
@ -241,7 +243,7 @@ export default class SystemRole extends React.PureComponent<Props, State> {
render() {
const {usersToAdd, usersToRemove, saving, saveNeeded, serverError, permissionsToUpdate, saveKey} = this.state;
const {role, isDisabled, isLicensedForCloud} = this.props;
const defaultName = role.name.split('').map((r) => r.charAt(0).toUpperCase() + r.slice(1)).join(' ');
const name = rolesStrings[role.name] ? <FormattedMessage {...rolesStrings[role.name].name}/> : role.name;
return (
<div className='wrapper--fixed'>
<AdminHeader withBackButton={true}>
@ -250,10 +252,7 @@ export default class SystemRole extends React.PureComponent<Props, State> {
to='/admin_console/user_management/system_roles'
className='fa fa-angle-left back'
/>
<FormattedMessage
id={`admin.permissions.roles.${role.name}.name`}
defaultMessage={defaultName}
/>
{name}
</div>
</AdminHeader>
<div className='admin-console__wrapper'>

View File

@ -15,7 +15,7 @@ describe('admin_console/system_role_permission', () => {
readOnly: true,
setSectionVisible: jest.fn(),
section: {
name: 'environemnt',
name: 'environment',
hasDescription: true,
subsections: [],
},

View File

@ -6,6 +6,7 @@ import {FormattedMessage} from 'react-intl';
import Permissions from 'mattermost-redux/constants/permissions';
import {sectionStrings} from './strings';
import SystemRolePermissionDropdown from './system_role_permission_dropdown';
import {noAccess, writeAccess, readAccess, mixedAccess} from './types';
import type {PermissionsToUpdate, PermissionToUpdate, SystemSection, PermissionAccess} from './types';
@ -78,6 +79,8 @@ export default class SystemRolePermission extends React.PureComponent<Props> {
};
renderSectionRow = (section: SystemSection, permissionsMap: Record<string, boolean>, permissionsToUpdate: PermissionsToUpdate, isSectionVisible: boolean) => {
const name = sectionStrings[section.name] ? <FormattedMessage {...sectionStrings[section.name].name}/> : section.name;
const description = sectionStrings[section.name] ? <FormattedMessage {...sectionStrings[section.name].description}/> : '';
return (
<div
key={section.name}
@ -85,18 +88,12 @@ export default class SystemRolePermission extends React.PureComponent<Props> {
>
<div className='PermissionSectionText'>
<div className='PermissionSectionText_title'>
<FormattedMessage
id={`admin.permissions.sysconsole_section_${section.name}.name`}
defaultMessage={section.name}
/>
{name}
</div>
{section.hasDescription &&
{section.hasDescription && description &&
<div className='PermissionSection_description'>
<FormattedMessage
id={`admin.permissions.sysconsole_section_${section.name}.description`}
defaultMessage={''}
/>
{description}
</div>
}

View File

@ -2,6 +2,7 @@
// See LICENSE.txt for license information.
import React from 'react';
import {defineMessage} from 'react-intl';
import type {Role} from '@mattermost/types/roles';
@ -11,7 +12,6 @@ import FormattedMarkdownMessage from 'components/formatted_markdown_message';
import AdminPanel from 'components/widgets/admin_console/admin_panel';
import Constants from 'utils/constants';
import {t} from 'utils/i18n';
import SystemRolePermission from './system_role_permission';
import type {PermissionsToUpdate, PermissionToUpdate, SystemSection} from './types';
@ -267,10 +267,8 @@ export default class SystemRolePermissions extends React.PureComponent<Props, St
return (
<AdminPanel
id='SystemRolePermissions'
titleId={t('admin.permissions.system_role_permissions.title')}
titleDefault='Privileges'
subtitleId={t('admin.permissions.system_role_permissions.description')}
subtitleDefault='Level of access to the system console.'
title={defineMessage({id: 'admin.permissions.system_role_permissions.title', defaultMessage: 'Privileges'})}
subtitle={defineMessage({id: 'admin.permissions.system_role_permissions.description', defaultMessage: 'Level of access to the system console.'})}
>
<div className='SystemRolePermissions'>
{this.getRows(permissionsMap, permissionsToUpdate, visibleSections)}
@ -279,79 +277,3 @@ export default class SystemRolePermissions extends React.PureComponent<Props, St
);
}
}
t('admin.permissions.sysconsole_section_about.name');
t('admin.permissions.sysconsole_section_about.description');
t('admin.permissions.sysconsole_section_about_edition_and_license.name');
t('admin.permissions.sysconsole_section_billing.name');
t('admin.permissions.sysconsole_section_billing.description');
t('admin.permissions.sysconsole_section_reporting.name');
t('admin.permissions.sysconsole_section_reporting.description');
t('admin.permissions.sysconsole_section_reporting_site_statistics.name');
t('admin.permissions.sysconsole_section_reporting_team_statistics.name');
t('admin.permissions.sysconsole_section_reporting_server_logs.name');
t('admin.permissions.sysconsole_section_user_management.name');
t('admin.permissions.sysconsole_section_user_management.description');
t('admin.permissions.sysconsole_section_user_management_users.name');
t('admin.permissions.sysconsole_section_user_management_users.description');
t('admin.permissions.sysconsole_section_user_management_groups.name');
t('admin.permissions.sysconsole_section_user_management_teams.name');
t('admin.permissions.sysconsole_section_user_management_channels.name');
t('admin.permissions.sysconsole_section_user_management_permissions.name');
t('admin.permissions.sysconsole_section_user_management_system_roles.name');
t('admin.permissions.sysconsole_section_environment.name');
t('admin.permissions.sysconsole_section_environment.description');
t('admin.permissions.sysconsole_section_environment_web_server.name');
t('admin.permissions.sysconsole_section_environment_database.name');
t('admin.permissions.sysconsole_section_environment_elasticsearch.name');
t('admin.permissions.sysconsole_section_environment_file_storage.name');
t('admin.permissions.sysconsole_section_environment_image_proxy.name');
t('admin.permissions.sysconsole_section_environment_smtp.name');
t('admin.permissions.sysconsole_section_environment_push_notification_server.name');
t('admin.permissions.sysconsole_section_environment_high_availability.name');
t('admin.permissions.sysconsole_section_environment_rate_limiting.name');
t('admin.permissions.sysconsole_section_environment_logging.name');
t('admin.permissions.sysconsole_section_environment_session_lengths.name');
t('admin.permissions.sysconsole_section_environment_performance_monitoring.name');
t('admin.permissions.sysconsole_section_environment_developer.name');
t('admin.permissions.sysconsole_section_site.name');
t('admin.permissions.sysconsole_section_site.description');
t('admin.permissions.sysconsole_section_site_customization.name');
t('admin.permissions.sysconsole_section_site_localization.name');
t('admin.permissions.sysconsole_section_site_users_and_teams.name');
t('admin.permissions.sysconsole_section_site_notifications.name');
t('admin.permissions.sysconsole_section_site_announcement_banner.name');
t('admin.permissions.sysconsole_section_site_emoji.name');
t('admin.permissions.sysconsole_section_site_posts.name');
t('admin.permissions.sysconsole_section_site_file_sharing_and_downloads.name');
t('admin.permissions.sysconsole_section_site_public_links.name');
t('admin.permissions.sysconsole_section_site_notices.name');
t('admin.permissions.sysconsole_section_authentication.name');
t('admin.permissions.sysconsole_section_authentication.description');
t('admin.permissions.sysconsole_section_authentication_signup.name');
t('admin.permissions.sysconsole_section_authentication_email.name');
t('admin.permissions.sysconsole_section_authentication_password.name');
t('admin.permissions.sysconsole_section_authentication_mfa.name');
t('admin.permissions.sysconsole_section_authentication_ldap.name');
t('admin.permissions.sysconsole_section_authentication_saml.name');
t('admin.permissions.sysconsole_section_authentication_openid.name');
t('admin.permissions.sysconsole_section_authentication_guest_access.name');
t('admin.permissions.sysconsole_section_plugins.name');
t('admin.permissions.sysconsole_section_plugins.description');
t('admin.permissions.sysconsole_section_integrations.name');
t('admin.permissions.sysconsole_section_integrations.description');
t('admin.permissions.sysconsole_section_integrations_integration_management.name');
t('admin.permissions.sysconsole_section_integrations_bot_accounts.name');
t('admin.permissions.sysconsole_section_integrations_gif.name');
t('admin.permissions.sysconsole_section_integrations_cors.name');
t('admin.permissions.sysconsole_section_compliance.name');
t('admin.permissions.sysconsole_section_compliance.description');
t('admin.permissions.sysconsole_section_compliance_data_retention_policy.name');
t('admin.permissions.sysconsole_section_compliance_compliance_export.name');
t('admin.permissions.sysconsole_section_compliance_compliance_monitoring.name');
t('admin.permissions.sysconsole_section_compliance_custom_terms_of_service.name');
t('admin.permissions.sysconsole_section_experimental.name');
t('admin.permissions.sysconsole_section_experimental.description');
t('admin.permissions.sysconsole_section_experimental_features.name');
t('admin.permissions.sysconsole_section_experimental_feature_flags.name');
t('admin.permissions.sysconsole_section_experimental_bleve.name');

View File

@ -123,12 +123,19 @@ exports[`admin_console/system_role_users should match snapshot 1`] = `
/>
</ToggleModalButton>
}
className=""
id="SystemRoleUsers"
subtitleDefault="List of people assigned to this system role."
subtitleId="admin.permissions.system_role_users.description"
titleDefault="Assigned People"
titleId="admin.permissions.system_role_users.title"
subtitle={
Object {
"defaultMessage": "List of people assigned to this system role.",
"id": "admin.permissions.system_role_users.description",
}
}
title={
Object {
"defaultMessage": "Assigned People",
"id": "admin.permissions.system_role_users.title",
}
}
>
<DataGrid
columns={
@ -485,12 +492,19 @@ exports[`admin_console/system_role_users should match snapshot with readOnly tru
/>
</ToggleModalButton>
}
className=""
id="SystemRoleUsers"
subtitleDefault="List of people assigned to this system role."
subtitleId="admin.permissions.system_role_users.description"
titleDefault="Assigned People"
titleId="admin.permissions.system_role_users.title"
subtitle={
Object {
"defaultMessage": "List of people assigned to this system role.",
"id": "admin.permissions.system_role_users.description",
}
}
title={
Object {
"defaultMessage": "Assigned People",
"id": "admin.permissions.system_role_users.title",
}
}
>
<DataGrid
columns={

View File

@ -2,7 +2,7 @@
// See LICENSE.txt for license information.
import React from 'react';
import {FormattedMessage} from 'react-intl';
import {FormattedMessage, defineMessage} from 'react-intl';
import type {Role} from '@mattermost/types/roles';
import type {UserProfile, UsersStats, GetFilteredUsersStatsOpts} from '@mattermost/types/users';
@ -17,7 +17,6 @@ import AdminPanel from 'components/widgets/admin_console/admin_panel';
import Tag from 'components/widgets/tag/tag';
import Constants, {ModalIdentifiers} from 'utils/constants';
import {t} from 'utils/i18n';
import AddUsersToRoleModal from '../add_users_to_role_modal';
@ -244,10 +243,8 @@ export default class SystemRoleUsers extends React.PureComponent<Props, State> {
<AdminPanel
id='SystemRoleUsers'
titleId={t('admin.permissions.system_role_users.title')}
titleDefault='Assigned People'
subtitleId={t('admin.permissions.system_role_users.description')}
subtitleDefault='List of people assigned to this system role.'
title={defineMessage({id: 'admin.permissions.system_role_users.title', defaultMessage: 'Assigned People'})}
subtitle={defineMessage({id: 'admin.permissions.system_role_users.description', defaultMessage: 'List of people assigned to this system role.'})}
button={
<ToggleModalButton
id='addRoleMembers'

Some files were not shown because too many files have changed in this diff Show More