Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,8 @@ const SAML_SETTINGS_CANONICAL_ALGORITHM_C14N11 = 'Canonical1.1';
// - type: which define the widget type.
// - label (and label_default): which define the main text of the setting.
// - isDisabled: a function which receive current config, the state of the page and the license.
// Prefer depending on a parent bool setting (it.stateIsFalse('Parent.Key')) over repeating that
// parent's config/state checks; @mattermost/no-redundant-admin-config-deps enforces this.
// - isHidden: a function which receive current config, the state of the page and the license.
//
// Custom Widget (extends from Widget):
Expand Down Expand Up @@ -4619,7 +4621,6 @@ const AdminDefinition: AdminDefinitionType = {
it.not(it.userHasWritePermissionOnResource(RESOURCE_KEYS.AUTHENTICATION.SAML)),
it.configIsFalse('GuestAccountsSettings', 'Enable'),
it.stateIsFalse('SamlSettings.EnableSyncWithLdap'),
it.stateIsFalse('SamlSettings.Enable'),
),
},
{
Expand All @@ -4641,7 +4642,6 @@ const AdminDefinition: AdminDefinitionType = {
help_text_markdown: false,
isDisabled: it.any(
it.not(it.userHasWritePermissionOnResource(RESOURCE_KEYS.AUTHENTICATION.SAML)),
it.stateIsFalse('SamlSettings.Enable'),
it.stateIsFalse('SamlSettings.EnableSyncWithLdap'),
),
},
Expand Down Expand Up @@ -4795,7 +4795,6 @@ const AdminDefinition: AdminDefinitionType = {
remove_action: removePrivateSamlCertificate,
isDisabled: it.any(
it.not(it.userHasWritePermissionOnResource(RESOURCE_KEYS.AUTHENTICATION.SAML)),
it.stateIsFalse('SamlSettings.Enable'),
it.stateIsFalse('SamlSettings.Encrypt'),
),
},
Expand All @@ -4813,7 +4812,6 @@ const AdminDefinition: AdminDefinitionType = {
remove_action: removePublicSamlCertificate,
isDisabled: it.any(
it.not(it.userHasWritePermissionOnResource(RESOURCE_KEYS.AUTHENTICATION.SAML)),
it.stateIsFalse('SamlSettings.Enable'),
it.stateIsFalse('SamlSettings.Encrypt'),
),
},
Expand All @@ -4835,7 +4833,6 @@ const AdminDefinition: AdminDefinitionType = {
label: defineMessage({id: 'admin.saml.signatureAlgorithmTitle', defaultMessage: 'Signature Algorithm'}),
isDisabled: it.any(
it.not(it.userHasWritePermissionOnResource(RESOURCE_KEYS.AUTHENTICATION.SAML)),
it.stateIsFalse('SamlSettings.Encrypt'),
it.stateIsFalse('SamlSettings.SignRequest'),
),
options: [
Expand Down Expand Up @@ -4879,7 +4876,6 @@ const AdminDefinition: AdminDefinitionType = {
],
isDisabled: it.any(
it.not(it.userHasWritePermissionOnResource(RESOURCE_KEYS.AUTHENTICATION.SAML)),
it.stateIsFalse('SamlSettings.Encrypt'),
it.stateIsFalse('SamlSettings.SignRequest'),
),
},
Expand Down Expand Up @@ -4948,7 +4944,6 @@ const AdminDefinition: AdminDefinitionType = {
isDisabled: it.any(
it.not(it.isSystemAdmin),
it.stateIsFalse('SamlSettings.EnableAdminAttribute'),
it.stateIsFalse('SamlSettings.Enable'),
),
},
{
Expand Down Expand Up @@ -6060,7 +6055,6 @@ const AdminDefinition: AdminDefinitionType = {
placeholder: defineMessage({id: 'admin.oauth.dcrRedirectURIAllowlistPlaceholder', defaultMessage: 'E.g.: https://*.example.com/**, https://app.example.com/callback'}),
isDisabled: it.any(
it.not(it.userHasWritePermissionOnResource(RESOURCE_KEYS.INTEGRATIONS.INTEGRATION_MANAGEMENT)),
it.stateIsFalse('ServiceSettings.EnableOAuthServiceProvider'),
it.stateIsFalse('ServiceSettings.EnableDynamicClientRegistration'),
),
isHidden: it.licensedForFeature('Cloud'),
Expand Down
48 changes: 48 additions & 0 deletions webapp/platform/eslint-plugin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,54 @@ export function someAction() {
}
```

### no-redundant-admin-config-deps

Enforces that System Console settings in `admin_definition` files do not repeat `isDisabled` config/state checks already implied by a parent setting they depend on.

When setting B disables itself with `it.stateIsFalse('A')`, A is a bool setting, and A already includes condition C (for example `it.configIsTrue('ClusterSettings', 'Enable')`), repeating C on B is redundant and tends to drift. Keep the dependency on A and omit the duplicated checks. Inheritance only follows bool parents (disabled bools are forced false on save). Permission and license helpers are not treated as config dependencies.

The rule builds the full bool-parent dependency tree before reporting. If a setting lists both a parent and a grandparent, redundant conditions are attributed to the closest (most specific) parent — not whichever ancestor appears first in `isDisabled`.

Examples of **incorrect** code for this rule:
```javascript
{
type: 'bool',
key: 'EmailSettings.EnableEmailBatching',
isDisabled: it.any(
it.stateIsFalse('EmailSettings.SendEmailNotifications'),
it.configIsTrue('ClusterSettings', 'Enable'),
),
},
{
type: 'number',
key: 'EmailSettings.EmailBatchingBufferSize',
isDisabled: it.any(
it.stateIsFalse('EmailSettings.SendEmailNotifications'),
it.stateIsFalse('EmailSettings.EnableEmailBatching'),
it.configIsTrue('ClusterSettings', 'Enable'),
),
},
```

Examples of **correct** code for this rule:
```javascript
{
type: 'bool',
key: 'EmailSettings.EnableEmailBatching',
isDisabled: it.any(
it.stateIsFalse('EmailSettings.SendEmailNotifications'),
it.configIsTrue('ClusterSettings', 'Enable'),
),
},
{
type: 'number',
key: 'EmailSettings.EmailBatchingBufferSize',
isDisabled: it.any(
it.stateIsFalse('EmailSettings.EnableEmailBatching'),
),
},
```

### use-external-link

Ensures that any link which opens a URL outside of Mattermost using `target="_blank"` uses the `ExternalLink` component.
Expand Down
1 change: 1 addition & 0 deletions webapp/platform/eslint-plugin/configs/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ const base = {
},
rules: {
'@mattermost/no-dispatch-getstate': 2,
'@mattermost/no-redundant-admin-config-deps': 2,
'@mattermost/use-external-link': 2,
'@stylistic/array-bracket-spacing': [
2,
Expand Down
1 change: 1 addition & 0 deletions webapp/platform/eslint-plugin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"scripts": {
"check": "eslint . --quiet",
"fix": "eslint . --quiet --fix",
"test": "node --test rules/*.test.js",
"clean": "rm -rf node_modules"
}
}
2 changes: 2 additions & 0 deletions webapp/platform/eslint-plugin/rules/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
// See LICENSE.txt for license information.

import noDispatchGetState from './no-dispatch-getstate.js';
import noRedundantAdminConfigDeps from './no-redundant-admin-config-deps.js';
import useExternalLink from './use-external-link.js';

export default {
'no-dispatch-getstate': noDispatchGetState,
'no-redundant-admin-config-deps': noRedundantAdminConfigDeps,
'use-external-link': useExternalLink,
};
Loading
Loading