Files
6083cc2282 MM-68196 Adding Global Classification configuration and banners (#36231)
* Add Classification Markings admin console page

Adds a new admin console page under Site Configuration for managing
classification markings. This allows system administrators to define
classification levels (e.g., UNCLASSIFIED, SECRET, TOP SECRET) with
associated colors and rank ordering, which will be used for system-wide
and per-channel classification banners.

The page includes:
- Enable/disable toggle backed by the property field system (field
  existence = enabled)
- Country preset dropdown (US DoD, NATO, UK GSCP, Canada, Australia
  PSPF) that auto-fills standard classification levels
- Editable classification levels table with drag-and-drop reorder,
  inline text editing, color picker, and delete
- Auto-switch to "Custom" preset when levels are manually modified
- Confirmation dialog when switching presets would overwrite custom data

Also adds:
- ClassificationMarkings feature flag (default off)
- Generic property field client methods (get/create/patch/delete) for
  the /api/v4/properties/ endpoints
- Enterprise license + feature flag gating on the admin page

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fix classification markings: add validation, error handling, and system object type

- Add "system" as a valid property field object type so the
  classification markings API calls succeed
- Surface load errors instead of silently swallowing them (only
  suppress 404 for unconfigured state)
- Validate before save: require at least one level, non-empty names,
  and no duplicates
- Default to custom preset with empty levels on first open
- Add section strings to searchableStrings for admin console search

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Move classification field to CPA group targeting users

Store the classification markings property field in the
custom_profile_attributes group with object_type 'user' instead of the
attributes group with object_type 'system'. Clear target_id for PSAv2
system target compliance and mark the field as admin-managed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Stabilize preset option IDs and add danger warning on preset switch

Hardcode deterministic IDs for all preset classification levels so
switching away and back preserves option IDs, preventing orphaned
property values. Compare only level data (not preset label) for change
detection so cosmetic preset switches don't trigger false save states.

Show a danger modal with red confirm button when changing presets on an
existing field, warning about system-wide impact on classified resources.
The warning appears once per session then allows frictionless switching.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Remove system object type from property fields

Not needed yet — will be added when system/channel banners are implemented.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fix ESLint errors in classification markings admin page

Fix import ordering and remove unused generateId import.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Address CodeRabbit review feedback for classification markings

- Register property field API endpoints when ClassificationMarkings flag
  is enabled (not just IntegratedBoards) to prevent 404s
- Preserve preset option IDs when creating a new classification field
  instead of blanking them with empty strings
- Add sysconsole read/write permission constants for classification
  markings across server and webapp, and wire up resource-level
  permission checks in the admin definition

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Add rank attribute to classification marking options

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Add classification markings permissions migration and read-only support

Add a permissions migration to grant classification markings sysconsole
permissions to existing roles on upgrade. Wire up the disabled prop so
read-only users can view but not edit classification settings. Register
the permission in the Delegated Granular Administration UI.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Paginate loadField to find classification field beyond first page

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fix lint errors and warnings in classification markings

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Remove classification markings sysconsole permissions; gate on sysadmin instead

Classification markings admin page no longer uses feature-specific
read/write permissions. Visibility is gated on license + feature flag,
editing is gated on system admin role. This avoids coupling
feature-specific permissions to the generic property service.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Set sysadmin-level permissions on classification markings field creation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Use stable IDs instead of array indices for classification level operations

Switch updateLevel/deleteLevel to identify levels by ID rather than
index, sort levels by rank on load, and extract i18n strings.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Refactor classification markings into extracted helper functions

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Add tests for classification markings admin console feature

Add unit and component tests covering:
- Pure function tests for detectPreset, optionsToLevels, levelsToOptions,
  processClassificationField, and fetchClassificationField pagination logic
- React component tests for rendering states, validation, and user interactions
- Client4 property field method tests for URL construction and HTTP verbs
- Server routing test verifying routes register with ClassificationMarkings flag
- Feature flag default and serialization test

Export pure functions from classification_markings.tsx to enable direct testing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fix lint errors in classification markings tests

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fix test compilation error

* Fix color input auto-filling after 3 hex characters in classification markings

Buffer ColorInput onChange in a LevelColorCell wrapper so the table
doesn't re-render mid-typing, preventing the input from losing its
focus-guarded local state.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fixing style issues with color picker z-index

* Added fix to prevent immediate dismissal when clicking inside color picker

* Adding E2E test suite for configuration

* Removing duplicates

* Fixing unrelated linter error

* Fixing test linting issues

* Updating tests to skip appropriately

* Matching configuration to UX specs

* Fixing style lint

* Added informational banner for presentational nature of markings

* Enabling the markings flag on playwright server

* Added missing feature flag to e2e test environment in ci

* Reverting changes to color_input

- Not needed as we're using a custom component

* Added and polished global banner configuration

* Refactoring webapp for readability

- Separating components
- Adding unit tests
- Isolating helper methods into utilities

* Fixing linter errors

* linter fix

* Manually fixing linter issues

* Separating global classification component

* Added persistence of classification marking configuration

* Changing LevelID with LevelName

* Making changes for PR reviews

* Changing property object of classification field to template

* syncing i18n file

* Removing inaccurate note from comments

* PR fixes for UX review

* Cleaning up unused value

* Added GlobalClassificationBanner component

- Made sure it syncs on change by using normal configuration values on it
- Works with "top" and "top_and_bottom"
- Renders on both root and admin_console

* Adding E2E test cases for global classification

* Linter fixes, i18n extract

* PR Fixes

* Linter fix

* Matching default messages

* Fixing type errors

* Fixing pipeline and runtime errors

* Fixing announcementbar rendering on top of global classifications

* Increasing banner & font sizes

* Fixing font size to 12px instead of 16px

- I read it wrong

* Replacing config values with property

* Test linter fixes

* Fixing type errors and go format error

* Making changes needed to align with specs

- Ensuring system_classification is a separate linked property that differs from the template
- Saving the global classification banner values as a propertyvalue

* Added missing arguments in e2e tests

* Added missing conditions for useEffect

- Also fixing E2E error in pipeline

* Fixing issues with V1 and V2 group mismatch

* Fixes for linter errors and coderabbit review

* Addressing more issues found by coderabbit

* Fixing issues found by coderabbit

* Migrating to use system properties

* Ran all linters and prettier

- Resolving coding style drift that happened from not running prettier on the webapp (even though CI doesn't check for this)

* Undoing the prettier changes in webapp

* Cleaning up unwanted autoformatted changes

* Reverting prettier changes to clean diff

* Fixing E2E test

* Import fixes in test

* Applying changes for PR feedback

* Fixing issues with failing e2e tests

* Changing key of selection from name to id

* Replacing field setup in E2E tests to use levelId instead of levelName

---------

Co-authored-by: David Krauser <david@krauser.org>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: David Krauser <david@kruser.org>
Co-authored-by: Mattermost Build <build@mattermost.com>
2026-05-11 21:35:38 +03:00
..
2023-03-22 17:22:27 -04:00
2025-11-12 18:05:50 +00:00

Mattermost Client

npm version

This package contains the JavaScript/TypeScript client for Mattermost. It's used by the Mattermost web app and related projects.

Installation

JavaScript

$ npm install @mattermost/client

TypeScript

$ npm install @mattermost/client @mattermost/types

Usage

Rest Client

To use this client, create an instance of Client4, set the server URL, and log in, and then you can start making requests.

import {Client4} from '@mattermost/client';

const client = new Client4();
client.setUrl('https://mymattermostserver.example.com');

client.login('username', 'password').then((user) => {
    // ...
});

If you already have a session token or a user access token, you can call Client4.setToken instead of logging in.

import {Client4} from '@mattermost/client';

const client = new Client4();
client.setUrl('https://mymattermostserver.example.com');

client.setToken('accesstoken');

If needed, methods exist to set other headers such as the User-Agent (Client4.setUserAgent), the CSRF token (Client4.setCSRF), or any extra headers you wish to include (Client4.setHeader).

Methods of Client4 which make requests to the server return a Promise which does the following:

  • On success, the promise resolves to a ClientResponse<T> object which contains the the Response (response), a Map of headers (headers), and the data sent from the server (data).
  • On an error, the promise rejects with a ClientError which contains the error message and the URL being requested. If the error happened on the server, the status code and an error ID (server_error_id) are included.
let user;
try {
    user = (await client.getUser('userid')).data;
} catch (e) {
    console.error(`An error occurred when making a request to ${e.url}: ${e.message}`);
}

WebSocket Client

To use the WebSocket client, create an instance of WebSocketClient and then call its initialize method with the connection URL and an optional session token or user access token. After that, you can call the client's addMessageListener method to register a listener which will be called whenever a WebSocket message is received from the server.

import {WebSocketClient} from '@mattermost/client';

// If you already have an instance of Client4, you can call its getWebSocketUrl method to get this URL
const connectionUrl = 'https://mymattermostserver.example.com/api/v4/websocket';

// In a browser, the token may be passed automatically from a cookie
const authToken = process.env.TOKEN;

const wsClient = new WebSocketClient();
wsClient.initialize(connectionUrl, authToken);

wsClient.addMessageListener((msg) => {
    if (msg.event === 'posted') {
        console.log('New post received', JSON.parse(msg.data.post));
    }
});

Node.js

Note that WebSocketClient expects globalThis.WebSocket to be defined as it was originally written for use in the Mattermost web app. If you're using it in a Node.js environment, you should set globalThis.WebSocket before instantiating the WebSocketClient.

import WebSocket from 'ws';

if (!globalThis.WebSocket) {
    globalThis.WebSocket = WebSocket;
}

const wsClient = new WebSocketClient();

This can also be done using dynamic imports if you're using them.

if (!globalThis.WebSocket) {
    const {WebSocket} = await import('ws');
    globalThis.WebSocket = WebSocket;
}

const wsClient = new WebSocketClient();

Compilation and Packaging

As a member of Mattermost with write access to our NPM organization, you can build and publish this package by running the following commands:

npm run build --workspace=platform/client
npm publish --workspace=platform/client

Make sure to increment the version number in package.json first! You can add -0, -1, etc for pre-release versions.