Commit graph

5613 commits

Author SHA1 Message Date
Harshil Sharma
cfafefe58c
Used short mode of data spillage report card in threads view to fix spacing issue (#36709)
Some checks are pending
Server CI / Postgres (shard 0) (push) Blocked by required conditions
Server CI / Postgres (shard 1) (push) Blocked by required conditions
Server CI / Postgres (shard 2) (push) Blocked by required conditions
Server CI / Postgres (shard 3) (push) Blocked by required conditions
Server CI / Merge Postgres Test Results (push) Blocked by required conditions
Server CI / Elasticsearch v8 Compatibility (push) Blocked by required conditions
Server CI / OpenSearch v2 Compatibility (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 0) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 1) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 2) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 3) (push) Blocked by required conditions
Server CI / Merge Postgres FIPS Test Results (push) Blocked by required conditions
Server CI / Run mmctl tests (push) Blocked by required conditions
Server CI / Run mmctl tests (FIPS) (push) Blocked by required conditions
Server CI / Build mattermost server app (push) Blocked by required conditions
Tools CI / check-style (mattermost-govet) (push) Waiting to run
Tools CI / Test (mattermost-govet) (push) Waiting to run
Web App CI / check-lint (push) Waiting to run
Web App CI / check-i18n (push) Blocked by required conditions
Web App CI / check-external-links (push) Blocked by required conditions
Web App CI / check-types (push) Blocked by required conditions
Web App CI / test (platform) (push) Blocked by required conditions
Web App CI / test (mattermost-redux) (push) Blocked by required conditions
Web App CI / test (channels shard 1/4) (push) Blocked by required conditions
Web App CI / test (channels shard 2/4) (push) Blocked by required conditions
Web App CI / test (channels shard 3/4) (push) Blocked by required conditions
Web App CI / test (channels shard 4/4) (push) Blocked by required conditions
Web App CI / upload-coverage (push) Blocked by required conditions
Web App CI / build (push) Blocked by required conditions
YAML Lint / yamllint (push) Waiting to run
2026-05-25 09:36:01 +05:30
cursor[bot]
7e75035cb6
Add Data Spillage discovery page (#36697)
Some checks failed
Server CI / Check migration files (push) Has been cancelled
Server CI / Generate email templates (push) Has been cancelled
Server CI / Check store layers (push) Has been cancelled
Server CI / Check mmctl docs (push) Has been cancelled
Server CI / Postgres (shard 0) (push) Has been cancelled
Server CI / Postgres (shard 1) (push) Has been cancelled
Server CI / Postgres (shard 2) (push) Has been cancelled
Server CI / Postgres (shard 3) (push) Has been cancelled
Server CI / Merge Postgres Test Results (push) Has been cancelled
Server CI / Elasticsearch v8 Compatibility (push) Has been cancelled
Server CI / OpenSearch v2 Compatibility (push) Has been cancelled
Server CI / Postgres FIPS (shard 0) (push) Has been cancelled
Server CI / Postgres FIPS (shard 1) (push) Has been cancelled
Server CI / Postgres FIPS (shard 2) (push) Has been cancelled
Server CI / Postgres FIPS (shard 3) (push) Has been cancelled
Server CI / Merge Postgres FIPS Test Results (push) Has been cancelled
Server CI / Run mmctl tests (push) Has been cancelled
Server CI / Run mmctl tests (FIPS) (push) Has been cancelled
Server CI / Build mattermost server app (push) Has been cancelled
Web App CI / check-i18n (push) Has been cancelled
Web App CI / check-external-links (push) Has been cancelled
Web App CI / check-types (push) Has been cancelled
Web App CI / test (platform) (push) Has been cancelled
Web App CI / test (mattermost-redux) (push) Has been cancelled
Web App CI / test (channels shard 1/4) (push) Has been cancelled
Web App CI / test (channels shard 2/4) (push) Has been cancelled
Web App CI / test (channels shard 3/4) (push) Has been cancelled
Web App CI / test (channels shard 4/4) (push) Has been cancelled
Web App CI / upload-coverage (push) Has been cancelled
Web App CI / build (push) Has been cancelled
* Add Data Spillage feature discovery page

Co-authored-by: mattermost-code <matty-code@mattermost.com>

* Strengthen Data Spillage discovery tests

Co-authored-by: mattermost-code <matty-code@mattermost.com>

* Fix Data Spillage discovery precommit issues

Co-authored-by: mattermost-code <matty-code@mattermost.com>

* Address PR feedback: 1 items resolved, 0 declined

* Remove Entry SKU hide condition for content flagging discovery

* Update Data Spillage discovery illustration

Co-authored-by: mattermost-code <matty-code@mattermost.com>

* Replace Data Spillage discovery illustration

Co-authored-by: mattermost-code <matty-code@mattermost.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: mattermost-code <matty-code@mattermost.com>
2026-05-22 14:44:44 -04:00
Pablo Vélez
b0185d9817
update packages to Fix npm audit vulnerabilities (#35810)
* Fix npm audit vulnerabilities and replace image-webpack-loader with sharp

* remove dead webp config and restore SVG optimization via svgoMinify

* fix import order

* removed unused gif from testing, and add missing peer dependency

* make sure only svgs are parsed

* scope svgoMinify to src- SVGs via loader rule

* remove redundant npm overrides per review feedback

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
2026-05-22 17:57:53 +02:00
Ben Cooke
f8e233cc39
Fix Group Details role dropdown not updating UI when changing role (#36561) 2026-05-22 11:07:10 -04:00
David Krauser
e8632bd456
[MM-68777] Add admin property field permission level (#36558) 2026-05-22 11:01:41 -04:00
Doug Lauder
c63154598c
MM-66162: harden GET /sharedchannels/{id}/remotes error path and add WS guard (#36696)
Some checks are pending
Server CI / Check mmctl docs (push) Blocked by required conditions
Server CI / Postgres (shard 0) (push) Blocked by required conditions
Server CI / Postgres (shard 1) (push) Blocked by required conditions
Server CI / Postgres (shard 2) (push) Blocked by required conditions
Server CI / Postgres (shard 3) (push) Blocked by required conditions
Server CI / Merge Postgres Test Results (push) Blocked by required conditions
Server CI / Elasticsearch v8 Compatibility (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 0) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 1) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 2) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 3) (push) Blocked by required conditions
Server CI / Merge Postgres FIPS Test Results (push) Blocked by required conditions
Server CI / Run mmctl tests (push) Blocked by required conditions
Server CI / Run mmctl tests (FIPS) (push) Blocked by required conditions
Server CI / Build mattermost server app (push) Blocked by required conditions
Tools CI / check-style (mattermost-govet) (push) Waiting to run
Tools CI / Test (mattermost-govet) (push) Waiting to run
Web App CI / check-lint (push) Waiting to run
Web App CI / check-i18n (push) Blocked by required conditions
Web App CI / check-external-links (push) Blocked by required conditions
Web App CI / check-types (push) Blocked by required conditions
Web App CI / test (platform) (push) Blocked by required conditions
Web App CI / test (mattermost-redux) (push) Blocked by required conditions
Web App CI / test (channels shard 1/4) (push) Blocked by required conditions
Web App CI / test (channels shard 2/4) (push) Blocked by required conditions
Web App CI / test (channels shard 3/4) (push) Blocked by required conditions
Web App CI / test (channels shard 4/4) (push) Blocked by required conditions
Web App CI / upload-coverage (push) Blocked by required conditions
Web App CI / build (push) Blocked by required conditions
YAML Lint / yamllint (push) Waiting to run
* MM-66162: harden GET /sharedchannels/{id}/remotes error path and add WS guard

  Two small follow-ups on top of the existing fix that returns 200 with an
  empty list when a channel is not shared.

  Server: getSharedChannelRemotes built its 500 AppError with nil params,
  so the i18n template "Could not fetch status for secure connections:
  {{.Error}}." rendered as "<no value>" in logs and response bodies when a
  genuinely unexpected error occurred. Pass map[string]any{"Error":
  err.Error()} so the underlying error surfaces, matching the pattern
  already used by the slash command caller in
  channels/app/slashcommands/command_share.go.

  Webapp: handleSharedChannelRemoteUpdatedEvent dispatched
  fetchChannelRemotes unconditionally on every shared_channel_remote_updated
  WS event, including for channels the local state already knows are not
  shared. The server publishes this event from the onInvite callback after
  a remote accepts a channel invitation, by which point the channel has
  already been flipped to shared and the channel_updated event that did so
  has already fired, so the local channel should reflect shared=true when
  this event arrives. If it does not, the event is not actionable and we
  skip the fetch.

  Adds jest coverage for the four cases of the new guard.

* add regression test for stale shared channel state

  Pins the DB inconsistency scenario suggested in the original ticket
  investigation: Channel.shared is true and a SharedChannelRemote row
  exists, but the SharedChannels row is missing. The endpoint should
  return 200 with an empty list rather than surfacing the stale state
  as an internal server error. Also tightens the existing
  TestGetSharedChannelRemotes by asserting the status code on the
  success path.
2026-05-22 09:59:15 -04:00
cursor[bot]
27d144226f
Fix inactive team icon active styling (#36683)
Prevent decorative team icons from showing the active sidebar highlight when clicked, and pass the channel ID needed by the access-control subject builder so the current checkout can build.

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: mattermost-code <matty-code@mattermost.com>
Co-authored-by: Mattermost Build <build@mattermost.com>
2026-05-22 18:31:23 +05:30
Weblate (bot)
b0d2f83620
Translations update from Mattermost Weblate (#36695)
Some checks are pending
Server CI / Check mmctl docs (push) Blocked by required conditions
Server CI / Postgres (shard 0) (push) Blocked by required conditions
Server CI / Postgres (shard 1) (push) Blocked by required conditions
Server CI / Postgres (shard 2) (push) Blocked by required conditions
Server CI / Postgres (shard 3) (push) Blocked by required conditions
Server CI / Merge Postgres Test Results (push) Blocked by required conditions
Server CI / Elasticsearch v8 Compatibility (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 0) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 1) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 2) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 3) (push) Blocked by required conditions
Server CI / Merge Postgres FIPS Test Results (push) Blocked by required conditions
Server CI / Run mmctl tests (push) Blocked by required conditions
Server CI / Run mmctl tests (FIPS) (push) Blocked by required conditions
Server CI / Build mattermost server app (push) Blocked by required conditions
Tools CI / check-style (mattermost-govet) (push) Waiting to run
Tools CI / Test (mattermost-govet) (push) Waiting to run
Web App CI / check-lint (push) Waiting to run
Web App CI / check-i18n (push) Blocked by required conditions
Web App CI / check-external-links (push) Blocked by required conditions
Web App CI / check-types (push) Blocked by required conditions
Web App CI / test (platform) (push) Blocked by required conditions
Web App CI / test (mattermost-redux) (push) Blocked by required conditions
Web App CI / test (channels shard 1/4) (push) Blocked by required conditions
Web App CI / test (channels shard 2/4) (push) Blocked by required conditions
Web App CI / test (channels shard 3/4) (push) Blocked by required conditions
Web App CI / test (channels shard 4/4) (push) Blocked by required conditions
Web App CI / upload-coverage (push) Blocked by required conditions
Web App CI / build (push) Blocked by required conditions
YAML Lint / yamllint (push) Waiting to run
* Translated using Weblate (Lithuanian)

Currently translated at 62.6% (4601 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/lt/

* Translated using Weblate (Lithuanian)

Currently translated at 62.6% (4601 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/lt/

* Translated using Weblate (Estonian)

Currently translated at 0.4% (31 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/et/

* Translated using Weblate (Estonian)

Currently translated at 0.4% (31 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/et/

* Translated using Weblate (Danish)

Currently translated at 8.1% (266 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/da/

* Translated using Weblate (Danish)

Currently translated at 8.1% (266 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/da/

* Translated using Weblate (Italian)

Currently translated at 44.6% (3281 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/it/

* Translated using Weblate (Italian)

Currently translated at 44.6% (3281 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/it/

* Translated using Weblate (Belarusian)

Currently translated at 88.6% (6509 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/be/

* Translated using Weblate (Khmer (Central))

Currently translated at 0.6% (48 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/km/

* Translated using Weblate (Khmer (Central))

Currently translated at 0.6% (48 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/km/

* Translated using Weblate (Latin)

Currently translated at 0.0% (0 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/la/

* Translated using Weblate (Latin)

Currently translated at 0.0% (0 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/la/

* Translated using Weblate (Latin)

Currently translated at 0.0% (0 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/la/

* Translated using Weblate (Persian)

Currently translated at 54.5% (4006 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/fa/

* Translated using Weblate (Persian)

Currently translated at 54.5% (4006 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/fa/

* Translated using Weblate (Portuguese)

Currently translated at 27.1% (1993 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/pt/

* Translated using Weblate (Portuguese)

Currently translated at 27.1% (1993 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/pt/

* Translated using Weblate (Albanian)

Currently translated at 3.1% (228 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/sq/

* Translated using Weblate (Albanian)

Currently translated at 3.1% (228 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/sq/

* Translated using Weblate (Catalan)

Currently translated at 33.3% (1089 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/ca/

* Translated using Weblate (Lao)

Currently translated at 0.1% (1 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/lo/

* Translated using Weblate (Macedonian)

Currently translated at 1.7% (126 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/mk/

* Translated using Weblate (Macedonian)

Currently translated at 1.7% (126 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/mk/

* Translated using Weblate (Hungarian)

Currently translated at 62.9% (2058 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/hu/

* Translated using Weblate (Estonian)

Currently translated at 0.5% (19 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/et/

* Translated using Weblate (Georgian)

Currently translated at 7.1% (525 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ka/

* Translated using Weblate (Georgian)

Currently translated at 7.1% (525 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ka/

* Translated using Weblate (Georgian)

Currently translated at 7.1% (525 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ka/

* Translated using Weblate (Norwegian Bokmål)

Currently translated at 4.4% (147 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/nb_NO/

* Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 99.4% (7304 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/zh_Hans/

* Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 99.4% (7304 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/zh_Hans/

* Translated using Weblate (Nepali)

Currently translated at 0.1% (6 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/ne/

* Translated using Weblate (Malayalam)

Currently translated at 3.7% (272 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ml/

* Translated using Weblate (Malayalam)

Currently translated at 3.7% (272 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ml/

* Translated using Weblate (Mongolian)

Currently translated at 0.6% (21 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/mn/

* Translated using Weblate (French)

Currently translated at 65.2% (4788 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/fr/

* Translated using Weblate (French)

Currently translated at 65.2% (4788 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/fr/

* Translated using Weblate (Swedish)

Currently translated at 83.6% (2733 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/sv/

* Translated using Weblate (Japanese)

Currently translated at 91.4% (6715 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ja/

* Translated using Weblate (Japanese)

Currently translated at 91.4% (6715 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ja/

* Translated using Weblate (Croatian)

Currently translated at 25.8% (1896 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/hr/

* Translated using Weblate (Croatian)

Currently translated at 25.8% (1896 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/hr/

* Translated using Weblate (Filipino)

Currently translated at 0.0% (0 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/fil/

* Translated using Weblate (Filipino)

Currently translated at 0.0% (0 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/fil/

* Translated using Weblate (Filipino)

Currently translated at 0.0% (0 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/fil/

* Translated using Weblate (Romanian)

Currently translated at 48.3% (3551 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ro/

* Translated using Weblate (Romanian)

Currently translated at 48.3% (3551 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ro/

* Translated using Weblate (Amharic)

Currently translated at 0.1% (4 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/am/

* Translated using Weblate (Amharic)

Currently translated at 0.1% (4 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/am/

* Translated using Weblate (Sinhala)

Currently translated at 0.3% (12 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/si/

* Translated using Weblate (French)

Currently translated at 65.1% (2129 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/fr/

* Translated using Weblate (Bengali)

Currently translated at 0.9% (70 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/bn/

* Translated using Weblate (Bengali)

Currently translated at 0.9% (70 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/bn/

* Translated using Weblate (Bengali)

Currently translated at 0.9% (70 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/bn/

* Translated using Weblate (Georgian)

Currently translated at 3.6% (120 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/ka/

* Translated using Weblate (Georgian)

Currently translated at 3.6% (120 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/ka/

* Translated using Weblate (Romanian)

Currently translated at 58.0% (1897 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/ro/

* Translated using Weblate (Frisian)

Currently translated at 56.6% (4161 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/fy/

* Translated using Weblate (Frisian)

Currently translated at 56.6% (4161 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/fy/

* Translated using Weblate (Frisian)

Currently translated at 56.6% (4161 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/fy/

* Translated using Weblate (Russian)

Currently translated at 80.7% (2638 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/ru/

* Translated using Weblate (Kazakh)

Currently translated at 12.7% (938 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/kk/

* Translated using Weblate (Kazakh)

Currently translated at 12.7% (938 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/kk/

* Translated using Weblate (Kazakh)

Currently translated at 12.7% (938 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/kk/

* Translated using Weblate (English (Australia))

Currently translated at 88.0% (2875 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/en_AU/

* Translated using Weblate (English (Australia))

Currently translated at 88.0% (2875 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/en_AU/

* Translated using Weblate (Hindi)

Currently translated at 26.7% (1961 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/hi/

* Translated using Weblate (Hindi)

Currently translated at 26.7% (1961 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/hi/

* Translated using Weblate (Dutch)

Currently translated at 98.4% (7230 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/nl/

* Translated using Weblate (Dutch)

Currently translated at 98.4% (7230 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/nl/

* Translated using Weblate (Galician)

Currently translated at 19.8% (1458 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/gl/

* Translated using Weblate (Galician)

Currently translated at 19.8% (1458 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/gl/

* Translated using Weblate (Swedish)

Currently translated at 88.4% (6497 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/sv/

* Translated using Weblate (Swedish)

Currently translated at 88.4% (6497 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/sv/

* Translated using Weblate (Arabic)

Currently translated at 0.1% (7 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ar/

* Translated using Weblate (Arabic)

Currently translated at 0.1% (7 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ar/

* Translated using Weblate (Albanian)

Currently translated at 0.9% (32 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/sq/

* Translated using Weblate (Vietnamese)

Currently translated at 66.5% (2174 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/vi/

* Translated using Weblate (German)

Currently translated at 90.6% (2962 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/de/

* Translated using Weblate (German)

Currently translated at 90.6% (2962 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/de/

* Translated using Weblate (Latvian)

Currently translated at 0.3% (24 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/lv/

* Translated using Weblate (Latvian)

Currently translated at 0.3% (24 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/lv/

* Translated using Weblate (Latvian)

Currently translated at 0.3% (24 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/lv/

* Translated using Weblate (Thai)

Currently translated at 1.0% (77 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/th/

* Translated using Weblate (Thai)

Currently translated at 1.0% (77 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/th/

* Translated using Weblate (English (Australia))

Currently translated at 94.2% (6922 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/en_AU/

* Translated using Weblate (Serbian)

Currently translated at 8.4% (275 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/sr/

* Translated using Weblate (Turkish)

Currently translated at 83.4% (2725 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/tr/

* Translated using Weblate (Turkish)

Currently translated at 83.4% (2725 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/tr/

* Translated using Weblate (Portuguese)

Currently translated at 6.3% (207 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/pt/

* Translated using Weblate (Greek)

Currently translated at 25.3% (829 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/el/

* Translated using Weblate (Gujarati)

Currently translated at 0.1% (9 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/gu/

* Translated using Weblate (Gujarati)

Currently translated at 0.1% (9 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/gu/

* Translated using Weblate (Arabic (Saudi Arabia))

Currently translated at 0.0% (0 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ar_SA/

* Translated using Weblate (Arabic (Saudi Arabia))

Currently translated at 0.0% (0 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ar_SA/

* Translated using Weblate (English (Pirate))

Currently translated at 0.1% (2 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/en@pirate/

* Translated using Weblate (English (Pirate))

Currently translated at 0.1% (2 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/en@pirate/

* Translated using Weblate (English (Pirate))

Currently translated at 0.1% (2 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/en@pirate/

* Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 98.1% (3208 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/zh_Hans/

* Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 98.1% (3208 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/zh_Hans/

* Translated using Weblate (Bulgarian)

Currently translated at 61.5% (2011 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/bg/

* Translated using Weblate (Bulgarian)

Currently translated at 61.5% (2011 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/bg/

* Translated using Weblate (Korean)

Currently translated at 79.5% (2600 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/ko/

* Translated using Weblate (Korean)

Currently translated at 79.5% (2600 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/ko/

* Translated using Weblate (Indonesian)

Currently translated at 27.0% (883 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/id/

* Translated using Weblate (Basque)

Currently translated at 1.3% (43 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/eu/

* Translated using Weblate (Slovenian)

Currently translated at 13.8% (1015 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/sl/

* Translated using Weblate (Slovenian)

Currently translated at 13.8% (1015 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/sl/

* Translated using Weblate (Arabic (Saudi Arabia))

Currently translated at 0.0% (0 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/ar_SA/

* Translated using Weblate (Breton)

Currently translated at 0.1% (7 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/br/

* Translated using Weblate (Breton)

Currently translated at 0.1% (7 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/br/

* Translated using Weblate (Bulgarian)

Currently translated at 59.0% (4335 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/bg/

* Translated using Weblate (Bulgarian)

Currently translated at 59.0% (4335 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/bg/

* Translated using Weblate (Amharic)

Currently translated at 3.0% (101 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/am/

* Translated using Weblate (Thai)

Currently translated at 0.7% (23 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/th/

* Translated using Weblate (Polish)

Currently translated at 99.4% (7304 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/pl/

* Translated using Weblate (Polish)

Currently translated at 99.4% (7304 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/pl/

* Translated using Weblate (Korean)

Currently translated at 84.1% (6179 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ko/

* Translated using Weblate (Korean)

Currently translated at 84.1% (6179 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ko/

* Translated using Weblate (Slovenian)

Currently translated at 33.4% (1092 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/sl/

* Translated using Weblate (Slovenian)

Currently translated at 33.4% (1092 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/sl/

* Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 75.3% (5535 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/zh_Hant/

* Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 75.3% (5535 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/zh_Hant/

* Translated using Weblate (Finnish)

Currently translated at 38.2% (1249 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/fi/

* Translated using Weblate (Japanese)

Currently translated at 81.5% (2665 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/ja/

* Translated using Weblate (Japanese)

Currently translated at 81.5% (2665 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/ja/

* Translated using Weblate (Catalan)

Currently translated at 1.6% (121 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ca/

* Translated using Weblate (Catalan)

Currently translated at 1.6% (121 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ca/

* Translated using Weblate (Mongolian)

Currently translated at 1.6% (124 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/mn/

* Translated using Weblate (Mongolian)

Currently translated at 1.6% (124 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/mn/

* Translated using Weblate (Polish)

Currently translated at 96.6% (3159 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/pl/

* Translated using Weblate (Polish)

Currently translated at 96.6% (3159 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/pl/

* Translated using Weblate (Hebrew)

Currently translated at 0.6% (50 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/he/

* Translated using Weblate (Hebrew)

Currently translated at 0.6% (50 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/he/

* Translated using Weblate (Belarusian)

Currently translated at 85.6% (2799 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/be/

* Translated using Weblate (Belarusian)

Currently translated at 85.6% (2799 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/be/

* Translated using Weblate (Turkish)

Currently translated at 91.8% (6747 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/tr/

* Translated using Weblate (Turkish)

Currently translated at 91.8% (6747 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/tr/

* Translated using Weblate (Turkish)

Currently translated at 91.8% (6747 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/tr/

* Translated using Weblate (Italian)

Currently translated at 62.0% (2026 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/it/

* Translated using Weblate (Spanish)

Currently translated at 60.2% (4426 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/es/

* Translated using Weblate (Spanish)

Currently translated at 60.2% (4426 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/es/

* Translated using Weblate (Basque)

Currently translated at 0.1% (11 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/eu/

* Translated using Weblate (Basque)

Currently translated at 0.1% (11 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/eu/

* Translated using Weblate (Vietnamese)

Currently translated at 62.1% (4562 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/vi/

* Translated using Weblate (Vietnamese)

Currently translated at 62.1% (4562 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/vi/

* Translated using Weblate (Czech)

Currently translated at 82.2% (6037 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/cs/

* Translated using Weblate (Czech)

Currently translated at 82.2% (6037 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/cs/

* Translated using Weblate (Icelandic)

Currently translated at 0.0% (0 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/is/

* Translated using Weblate (Icelandic)

Currently translated at 0.0% (0 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/is/

* Translated using Weblate (Icelandic)

Currently translated at 0.0% (0 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/is/

* Translated using Weblate (Danish)

Currently translated at 8.9% (659 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/da/

* Translated using Weblate (Danish)

Currently translated at 8.9% (659 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/da/

* Translated using Weblate (Serbian)

Currently translated at 7.6% (559 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/sr/

* Translated using Weblate (Serbian)

Currently translated at 7.6% (559 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/sr/

* Translated using Weblate (Breton)

Currently translated at 0.8% (29 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/br/

* Translated using Weblate (German)

Currently translated at 96.2% (7071 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/de/

* Translated using Weblate (German)

Currently translated at 96.2% (7071 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/de/

* Translated using Weblate (Indonesian)

Currently translated at 2.6% (191 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/id/

* Translated using Weblate (Indonesian)

Currently translated at 2.6% (191 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/id/

* Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 73.3% (2396 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/zh_Hant/

* Translated using Weblate (Arabic)

Currently translated at 0.5% (18 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/ar/

* Translated using Weblate (Kazakh (Latin script))

Currently translated at 3.2% (235 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/kk_Latn/

* Translated using Weblate (Kazakh (Latin script))

Currently translated at 3.2% (235 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/kk_Latn/

* Translated using Weblate (Kazakh (Latin script))

Currently translated at 3.2% (235 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/kk_Latn/

* Translated using Weblate (Gujarati)

Currently translated at 0.5% (19 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/gu/

* Translated using Weblate (Portuguese (Brazil))

Currently translated at 74.5% (2436 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/pt_BR/

* Translated using Weblate (Czech)

Currently translated at 81.7% (2670 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/cs/

* Translated using Weblate (Czech)

Currently translated at 81.7% (2670 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/cs/

* Translated using Weblate (Persian)

Currently translated at 60.0% (1963 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/fa/

* Translated using Weblate (Hungarian)

Currently translated at 59.6% (4383 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/hu/

* Translated using Weblate (Hungarian)

Currently translated at 59.6% (4383 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/hu/

* Translated using Weblate (Hungarian)

Currently translated at 59.6% (4383 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/hu/

* Translated using Weblate (Hebrew)

Currently translated at 1.1% (39 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/he/

* Translated using Weblate (Finnish)

Currently translated at 20.9% (1538 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/fi/

* Translated using Weblate (Finnish)

Currently translated at 20.9% (1538 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/fi/

* Translated using Weblate (Croatian)

Currently translated at 8.0% (264 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/hr/

* Translated using Weblate (Sinhala)

Currently translated at 0.1% (10 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/si/

* Translated using Weblate (Sinhala)

Currently translated at 0.1% (10 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/si/

* Translated using Weblate (Greek)

Currently translated at 6.5% (482 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/el/

* Translated using Weblate (Greek)

Currently translated at 6.5% (482 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/el/

* Translated using Weblate (Malayalam)

Currently translated at 8.9% (292 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/ml/

* Translated using Weblate (Galician)

Currently translated at 1.7% (58 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/gl/

* Translated using Weblate (Ukrainian)

Currently translated at 80.4% (5905 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/uk/

* Translated using Weblate (Ukrainian)

Currently translated at 80.4% (5905 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/uk/

* Translated using Weblate (Nepali)

Currently translated at 5.7% (424 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ne/

* Translated using Weblate (Nepali)

Currently translated at 5.7% (424 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ne/

* Translated using Weblate (Norwegian Bokmål)

Currently translated at 76.4% (5613 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/nb_NO/

* Translated using Weblate (Norwegian Bokmål)

Currently translated at 76.4% (5613 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/nb_NO/

* Translated using Weblate (Norwegian Bokmål)

Currently translated at 76.4% (5613 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/nb_NO/

* Translated using Weblate (Hindi)

Currently translated at 58.5% (1913 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/hi/

* Translated using Weblate (Portuguese (Brazil))

Currently translated at 62.0% (4557 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/pt_BR/

* Translated using Weblate (Portuguese (Brazil))

Currently translated at 62.0% (4557 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/pt_BR/

* Translated using Weblate (Khmer (Central))

Currently translated at 0.7% (26 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/km/

* Translated using Weblate (Lithuanian)

Currently translated at 6.7% (221 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/lt/

* Translated using Weblate (Ukrainian)

Currently translated at 78.5% (2567 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/uk/

* Translated using Weblate (Ukrainian)

Currently translated at 78.5% (2567 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/uk/

* Translated using Weblate (Spanish)

Currently translated at 67.0% (2191 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/es/

* Translated using Weblate (Spanish)

Currently translated at 67.0% (2191 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/es/

* Translated using Weblate (Spanish)

Currently translated at 67.0% (2191 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/es/

* Translated using Weblate (Dutch)

Currently translated at 95.8% (3131 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/nl/

* Translated using Weblate (Macedonian)

Currently translated at 6.7% (221 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/mk/

* Translated using Weblate (Lao)

Currently translated at 3.9% (290 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/lo/

* Translated using Weblate (Lao)

Currently translated at 3.9% (290 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/lo/

* Translated using Weblate (Russian)

Currently translated at 76.7% (5636 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ru/

* Translated using Weblate (Russian)

Currently translated at 76.7% (5636 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ru/

* Translated using Weblate (Russian)

Currently translated at 76.7% (5636 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ru/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/

---------

Co-authored-by: jprusch <rs@schaeferbarthold.de>
Co-authored-by: Martin Popp Fredslund (SektorCERT) <martin@sektorcert.dk>
Co-authored-by: Tom De Moor <tom@controlaltdieliet.be>
Co-authored-by: Ekaterine Papava <papava.e@gtu.ge>
Co-authored-by: Sharuru <mave@foxmail.com>
Co-authored-by: Matthew Williams <Matthew.Williams@outlook.com.au>
Co-authored-by: Kristoffer Grundström <swedishsailfishosuser@tutanota.com>
Co-authored-by: Kaya Zeren <kayazeren@gmail.com>
Co-authored-by: Nikolai Zahariev <nikolaiz@yahoo.com>
Co-authored-by: master7 <marcin.karkosz@rajska.info>
Co-authored-by: DeepL <noreply-mt-deepl@weblate.org>
Co-authored-by: Takayuki Maruyama <bis5.wsys@gmail.com>
Co-authored-by: Vadim Asadchi <vadim.asadchi@codex-soft.com>
Co-authored-by: Martin Mičuda <micuda@rematiptop.cz>
Co-authored-by: ritchierope <ritchierope@users.noreply.translate.mattermost.com>
Co-authored-by: Frank Paul Silye <frankps@gmail.com>
Co-authored-by: Serhii Khomiuk <sergiy.khomiuk@gmail.com>
Co-authored-by: Ricardo Obregón <robregonm@gmail.com>
Co-authored-by: Carloswaldo <waldosaurio@gmail.com>
Co-authored-by: Dmitriy Q <krotesk@mail.ru>
2026-05-22 01:47:43 +00:00
cursor[bot]
6ee3fb9af1
Fix membership policy edit action navigation (#36690)
Automatic Merge
2026-05-22 01:23:39 +02:00
Sven Hüster
29fe2789a0
Exclude webhook posts from thread participation check (#36673)
Some checks are pending
Server CI / Check mmctl docs (push) Blocked by required conditions
Server CI / Postgres (shard 0) (push) Blocked by required conditions
Server CI / Postgres (shard 1) (push) Blocked by required conditions
Server CI / Postgres (shard 2) (push) Blocked by required conditions
Server CI / Postgres (shard 3) (push) Blocked by required conditions
Server CI / Merge Postgres Test Results (push) Blocked by required conditions
Server CI / Elasticsearch v8 Compatibility (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 0) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 1) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 2) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 3) (push) Blocked by required conditions
Server CI / Merge Postgres FIPS Test Results (push) Blocked by required conditions
Server CI / Run mmctl tests (push) Blocked by required conditions
Server CI / Run mmctl tests (FIPS) (push) Blocked by required conditions
Server CI / Build mattermost server app (push) Blocked by required conditions
Tools CI / check-style (mattermost-govet) (push) Waiting to run
Tools CI / Test (mattermost-govet) (push) Waiting to run
Web App CI / check-lint (push) Waiting to run
Web App CI / check-i18n (push) Blocked by required conditions
Web App CI / check-external-links (push) Blocked by required conditions
Web App CI / check-types (push) Blocked by required conditions
Web App CI / test (platform) (push) Blocked by required conditions
Web App CI / test (mattermost-redux) (push) Blocked by required conditions
Web App CI / test (channels shard 1/4) (push) Blocked by required conditions
Web App CI / test (channels shard 2/4) (push) Blocked by required conditions
Web App CI / test (channels shard 3/4) (push) Blocked by required conditions
Web App CI / test (channels shard 4/4) (push) Blocked by required conditions
Web App CI / upload-coverage (push) Blocked by required conditions
Web App CI / build (push) Blocked by required conditions
YAML Lint / yamllint (push) Waiting to run
* Exclude webhook posts from thread participation check

When determining if the current user has replied to a thread for
comment mention notifications, ignore posts made by webhooks even if
they use the owning user's user_id.

Co-authored-by: Sven Hüster <svelle@users.noreply.github.com>

* Add missing isFromWebhook import in posts selector

Co-authored-by: Sven Hüster <svelle@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Sven Hüster <svelle@users.noreply.github.com>
2026-05-21 15:22:43 +02:00
Asaad Mahmood
eeb3c1ec04
MM-67237 - Open file preview modal when clicking draft attachment thumbnails. (#36590)
* Open file preview modal when clicking draft attachment thumbnails.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Document draft thumbnail preview handler for CodeRabbit/doc checks.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Fix ESLint import/order in FilePreview connector and tests.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Add tests for archived and deleted draft attachment preview guards.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Enable draft attachment preview for all file types.

Draft thumbnails were only clickable for images and SVGs; other attachments now open the standard file preview modal like post attachments do.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-21 18:12:25 +05:00
Ibrahim Serdar Acikgoz
ba1cec51a5
[MM-68693] Resource level permission policies and new simulation (#36472) 2026-05-21 14:40:05 +02:00
cursor[bot]
bc757c5c54
Fix content flagging update for unloaded posts (#36504)
* Fix content flagging update for unloaded posts

Co-authored-by: mattermost-code <matty-code@mattermost.com>

* Strengthen content flagging reducer tests

Co-authored-by: mattermost-code <matty-code@mattermost.com>

* Guard content flagging reducer updates

Co-authored-by: mattermost-code <matty-code@mattermost.com>

* Add non-array content flagging reducer test

Co-authored-by: mattermost-code <matty-code@mattermost.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: mattermost-code <matty-code@mattermost.com>
2026-05-21 15:14:16 +05:30
Miguel de la Cruz
6b20092e7a
Fix MM-57406: prevent IPv6 hex segments from parsing as emoji (#36541)
* Fix MM-57406: prevent IPv6 hex segments from parsing as emoji

Add word-boundary lookbehind and lookahead to EMOJI_PATTERN so a
:name: token is only matched when neither side abuts an
alphanumeric/underscore. Without this, hex runs in IPv6
addresses (e.g. :beef: in 2001:18:1:beef::/64) were tokenized and
rendered as custom emoji. The new semantics align with the server
parser at server/public/shared/markdown/emoji.go.

Bump the webapp babel safari target from 16.2 to 16.4 since regex
lookbehind is a syntax feature and is not lowered by
@babel/preset-env. The actual supported minimum is well above 16.4, so
the previous target was stale.

Add regression tests for the IPv6 case and guardrail tests for
back-to-back, paren-wrapped, and punctuation-terminated emoji.  Update
the existing asdf🐐asdf💨asdf test to reflect the
new (server-aligned) semantics.

* Dedupe word-char class in EMOJI_PATTERN

Use \w in the lookarounds and inside the name matcher ([\w+-])
so the word-char set is expressed once instead of being repeated
as two slightly different literal character classes. Same set,
same semantics; addresses review feedback on PR #36541.

---------

Co-authored-by: Miguel de la Cruz <miguel@ctrlz.es>
2026-05-21 10:34:30 +02:00
Miguel de la Cruz
02bae8c3a1
Fix: Global Threads view shows only 1 quick reaction emoji instead of 3 (MM-68681) (#36512)
* Fix: Global Threads shows 1 quick reaction emoji instead of 3 (MM-68681)

When posts are viewed in the Global Threads full-width view, the hover
toolbar was incorrectly showing only 1 quick reaction emoji instead of 3.

Root cause: In post/index.tsx, the isExpanded prop (which controls whether
the toolbar shows 3 or 1 emojis) was derived only from
state.views.rhs.isSidebarExpanded. When navigating to Global Threads,
suppressRHS is dispatched (setting state.views.rhsSuppressed = true), but
isSidebarExpanded remains false. Since posts in the thread viewer use
RHS_ROOT/RHS_COMMENT locations (not CENTER), and the #sidebar-right element
is suppressed (width = 0), the showMoreReactions check in post_options.tsx
always fell through to showing only 1 emoji.

Fix: Include state.views.rhsSuppressed in the isExpanded computation so that
when the RHS is suppressed (i.e., we are in a full-width context like Global
Threads or Drafts), the toolbar correctly renders 3 quick reaction emojis.

Tests: Added post_options.test.tsx with 4 unit tests verifying:
- CENTER location → 3 emojis (existing behavior)
- RHS_ROOT + isExpanded=false → 1 emoji (narrow RHS, existing behavior)
- RHS_ROOT + isExpanded=true → 3 emojis (expanded RHS or Global Threads)
- RHS_COMMENT + isExpanded=true → 3 emojis

Co-authored-by: Miguel de la Cruz <mgdelacroix@users.noreply.github.com>

* Refactor: use getIsGlobalThreadsView selector instead of rhsSuppressed (MM-68681)

Replace the broad state.views.rhsSuppressed check (which also fires for the
Drafts view) with a precise getIsGlobalThreadsView() selector that reads the
already-existing state.views.lhs.currentStaticPageId field.

When global_threads.tsx mounts it dispatches selectLhsItem(LhsItemType.Page,
LhsPage.Threads) which sets currentStaticPageId to LhsPage.Threads ('threads').
This is the existing, canonical signal that the Global Threads full-width view
is active; the selector wraps it with a name that conveys intent directly.

Changes:
- selectors/lhs.ts: add getIsGlobalThreadsView() — returns true iff
  state.views.lhs.currentStaticPageId === LhsPage.Threads
- selectors/lhs.test.ts: 3 new tests covering Threads, Drafts, and empty page
- post/index.tsx: import getIsGlobalThreadsView and use it in isExpanded
- post_options.test.tsx: update test description to match new mechanism

Co-authored-by: Miguel de la Cruz <mgdelacroix@users.noreply.github.com>

* Fix tests: use renderWithContext + real component tree, not jest.mock

The previous post_options.test.tsx used jest.mock() to replace
PostRecentReactions, DotMenu, and several other components. That pattern
is not established in this codebase — post_component.test.tsx and
post_reaction.test.tsx both exercise the real connected component tree
via renderWithContext with a partial Redux state.

Rewrite to match:
- Drop all jest.mock() calls for child components.
- Provide minimal Redux state (roles with ADD_REACTION + user with
  system_user role) so that ChannelPermissionGate lets the emoji
  buttons render — the same pattern used in post_reaction.test.tsx.
- Use proper SystemEmoji shaped objects (with short_name) as
  recentEmojis so that getEmojiName() does not crash.
- Assert on the real rendered emoji buttons (data-testid=
  'post-menu__item_emoji') rather than a mocked prop capture.

Co-authored-by: Miguel de la Cruz <mgdelacroix@users.noreply.github.com>

* Remove selector comment; add e2e test for Global Threads quick reactions (MM-68681)

- selectors/lhs.ts: remove JSDoc block from getIsGlobalThreadsView; the
  name is self-explanatory and the comment was narrating the code.

- emoji_recently_used_spec.js:
  * Add group tag @collapsed_reply_threads (test now requires CRT config).
  * Add MM-T4261_3: verifies that hovering a post in the Global Threads
    full-width panel shows 3 quick reaction emojis, matching the center
    channel and unlike the narrow RHS sidebar which shows 1.
  * Add GLOBAL_THREADS case to validateQuickReactions helper (uses
    rhsPost id prefix, numReactions=3).

Co-authored-by: Miguel de la Cruz <mgdelacroix@users.noreply.github.com>

* Fix lint: correct import order in post_options.test.tsx and post/index.tsx

- post_options.test.tsx: move @mattermost/types/emojis type import before
  mattermost-redux/constants; add missing blank line between import groups.
- post/index.tsx: move selectors/lhs import before selectors/posts
  (alphabetical order within the selectors/* group).

Co-authored-by: Miguel de la Cruz <mgdelacroix@users.noreply.github.com>

* Fix types: use correct EmojiCategory value 'people-body' not 'people'

Co-authored-by: Miguel de la Cruz <mgdelacroix@users.noreply.github.com>

* Remove dead RHS_EXPANDED branch from validateQuickReactions helper

No call site ever passes 'RHS_EXPANDED' to validateQuickReactions — the
branch was unreachable. Keep only the 'GLOBAL_THREADS' case that the new
MM-T4261_3 test actually exercises.

Co-authored-by: Miguel de la Cruz <mgdelacroix@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Miguel de la Cruz <mgdelacroix@users.noreply.github.com>
2026-05-21 10:33:56 +02:00
Maria A Nunez
c4b36dee16
Add user attribute validation banners (#36595)
Some checks failed
Server CI / Postgres (shard 1) (push) Blocked by required conditions
Server CI / Postgres (shard 2) (push) Blocked by required conditions
Server CI / Postgres (shard 3) (push) Blocked by required conditions
Server CI / Merge Postgres Test Results (push) Blocked by required conditions
Server CI / Elasticsearch v8 Compatibility (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 0) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 1) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 2) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 3) (push) Blocked by required conditions
Server CI / Merge Postgres FIPS Test Results (push) Blocked by required conditions
Server CI / Run mmctl tests (push) Blocked by required conditions
Server CI / Run mmctl tests (FIPS) (push) Blocked by required conditions
Server CI / Build mattermost server app (push) Blocked by required conditions
Tools CI / check-style (mattermost-govet) (push) Waiting to run
Tools CI / Test (mattermost-govet) (push) Waiting to run
Web App CI / check-lint (push) Waiting to run
Web App CI / check-i18n (push) Blocked by required conditions
Web App CI / check-external-links (push) Blocked by required conditions
Web App CI / check-types (push) Blocked by required conditions
Web App CI / test (platform) (push) Blocked by required conditions
Web App CI / test (mattermost-redux) (push) Blocked by required conditions
Web App CI / test (channels shard 1/4) (push) Blocked by required conditions
Web App CI / test (channels shard 2/4) (push) Blocked by required conditions
Web App CI / test (channels shard 3/4) (push) Blocked by required conditions
Web App CI / test (channels shard 4/4) (push) Blocked by required conditions
Web App CI / upload-coverage (push) Blocked by required conditions
Web App CI / build (push) Blocked by required conditions
YAML Lint / yamllint (push) Waiting to run
BuildEnv Docker Image / build-image (push) Has been cancelled
BuildEnv Docker Image / build-image-fips (push) Has been cancelled
* Add user attribute validation banners

Add row-level and banner validation coverage for user attribute names so admins get clearer feedback before saving invalid attributes.

Co-authored-by: Cursor <cursoragent@cursor.com>

* UX Feedback

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Mattermost Build <build@mattermost.com>
2026-05-20 17:23:18 -04:00
Scott Bishel
448a642835
Add inline action buttons for bot-posted markdown (#36219)
* Add inline action buttons for bot-posted markdown

Bots, webhooks, and plugins can now embed clickable action buttons
inside markdown (including table cells) using mmaction://actionId
links, with row-specific parameters forwarded to the integration on
click. This enables use cases like a per-row "Mx Plan" button in a
fleet-status table that opens a dialog scoped to the clicked row.

Design
- New post prop inline_actions maps actionId (alphanumeric) to a
  PostActionIntegration {URL, Context}, capped at 50 entries.
- Markdown link with scheme mmaction:// emits a placeholder span that
  messageHtmlToComponent converts to the InlineActionButton component.
- Click POSTs inline_context (parsed from the URL query string) to the
  existing /posts/{id}/actions/{action_id} endpoint; the server merges
  it into the integration request as context.inline_params while
  preserving the post-level context.
- Only bot, webhook, and plugin posts render the button; non-integration
  posts have inline_actions stripped on create, update, and ephemeral
  broadcast. Hardened-mode also covers the new prop.
- Reuses the existing PostAction dialog pipeline: plugin handlers reply
  with a trigger_id and call /actions/dialogs/open as before.

Security
- InlineContext capped at 50 entries / 128-char keys / 2 KB values.
- Integration Context cloned per click so per-click inline_params and
  selected_option cannot leak into the cached post for other clickers.
- Plugin response updates cannot add inline_actions to a post that did
  not already have them; invalid entries are dropped with a warn log.
- Label content and data attributes are escaped; labels are flattened
  to plain text (tags stripped, entities decoded, then escaped).
- Malformed JSON request bodies now return 400 instead of falling
  through with an empty inline_context.

Tests
- Model: validators, normalization, GetInlineAction, strip, fallback.
- App: create strip, update guard (4 subtests including
  AllowInlineActionsUpdate bypass), ephemeral strip, inline_params
  merge, context-map isolation, plugin-response guards, from_bot and
  from_plugin retention across plugin updates.
- API: inline_context validation (size bounds + error id),
  omitempty backward compat, malformed JSON 400.
- Webapp: renderer scheme handling, allow/deny flags, size caps,
  HTML escape, tag strip, entity decode, attribute-injection defense;
  component click dispatch, double-click race guard, unmount safety,
  error-result recovery, aria state.

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

* lint fix

* i18n-extract

* Review fixes for inline action buttons

- renderer: preserve actionId case; reject opaque mmaction: URI
- app: require bot AND integration session to preserve inline_actions
- app: restore original inline_actions when plugin response is invalid
- i18n: rename key to ...app_error to match convention

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

* Tighten UpdatePost inline_actions guard; fix test seeds

- app: UpdatePost now requires AllowInlineActionsUpdate to modify
  inline_actions. Integration session alone is insufficient — a
  PAT-wielding user could otherwise inject inline_actions on any
  post they could edit.
- tests: seed bot posts with inline_actions via an integration
  session (intSeedCtx) so they survive the create-time strip.
- renderer: lint fix (blank line before comment block).

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

* Reject malformed inline-action authorities at render time

- renderer: enforce ^[A-Za-z0-9]+$ on actionId, mirroring the server
  regex. Authorities like mmaction://plan:443 or mmaction://user@plan
  now fall through to plain text instead of rendering a dead button.
- post: clarify in the strip comment that webhooks and plugins bypass
  CreatePostAsUser entirely (they call CreatePost / CreatePostMissingChannel
  directly), so the strip block does not apply to them.

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

* Tighten inline-action renderer tests

- Replace oversized-params test with boundary pair (at-cap and over-cap)
  to lock in the > vs >= behavior of the size-limit check.
- Add a "surrounding text survives" assertion for the tag-strip path so
  a future swap from regex strip to a DOM sanitizer won't silently
  drop legitimate content along with tags.

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

* Inline action buttons via mmaction:// markdown links

Adds inline action buttons rendered from mmaction:// links in markdown,
with the click pipeline reusing the existing post-action infrastructure.
Aligned with the broader mm_blocks_actions framework (Daniel's PR).

* fix lint, DoS hardening, fix and rename test

* Address review feedback

* lint fix

* Reject percent-encoded path traversal in validateIntegrationURL (e.g. %2e%2e%2f) by parsing the URL and checking the decoded path.

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Mattermost Build <build@mattermost.com>
2026-05-20 13:34:44 -06:00
Scott Bishel
a84941bec1
Remove Legacy Interactive Dialog code (#35874) 2026-05-20 13:34:13 -06:00
Ben Cooke
6189a3f54a
[MM-66489] Pull and populate certificate from metadata endpoint (#36557) 2026-05-20 14:51:24 -04:00
Pablo Vélez
345a0b76a6
Mm 68506 fe abac mask fe table editor cel and e2e (#36517)
Some checks are pending
Server CI / Check mmctl docs (push) Blocked by required conditions
Server CI / Postgres (shard 0) (push) Blocked by required conditions
Server CI / Postgres (shard 1) (push) Blocked by required conditions
Server CI / Postgres (shard 2) (push) Blocked by required conditions
Server CI / Postgres (shard 3) (push) Blocked by required conditions
Server CI / Merge Postgres Test Results (push) Blocked by required conditions
Server CI / Elasticsearch v8 Compatibility (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 0) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 1) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 2) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 3) (push) Blocked by required conditions
Server CI / Merge Postgres FIPS Test Results (push) Blocked by required conditions
Server CI / Run mmctl tests (push) Blocked by required conditions
Server CI / Run mmctl tests (FIPS) (push) Blocked by required conditions
Server CI / Build mattermost server app (push) Blocked by required conditions
Tools CI / check-style (mattermost-govet) (push) Waiting to run
Tools CI / Test (mattermost-govet) (push) Waiting to run
Web App CI / check-lint (push) Waiting to run
Web App CI / check-i18n (push) Blocked by required conditions
Web App CI / check-external-links (push) Blocked by required conditions
Web App CI / check-types (push) Blocked by required conditions
Web App CI / test (platform) (push) Blocked by required conditions
Web App CI / test (mattermost-redux) (push) Blocked by required conditions
Web App CI / test (channels shard 1/4) (push) Blocked by required conditions
Web App CI / test (channels shard 2/4) (push) Blocked by required conditions
Web App CI / test (channels shard 3/4) (push) Blocked by required conditions
Web App CI / test (channels shard 4/4) (push) Blocked by required conditions
Web App CI / upload-coverage (push) Blocked by required conditions
Web App CI / build (push) Blocked by required conditions
YAML Lint / yamllint (push) Waiting to run
* MM-68501 - implement GetMaskedVisualAST and wire API handler

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

* add missing test and fix style issues

* fix styles

* implement coderabbit feedback

* MM-68501 - PR review: split masking file, model-level access mode, reject contradictory config

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

* MM-68501 - apply shared_only filter to non-option field values (binary masking)

* MM-68501 - consolidate masking flag check and log corrupt text value during masking

* MM-68503 - add CEL utilities, write-path validation, and merge helpers

Combined set of helpers consumed by BE-5's save path:

CEL construction / serialization
  - extractStringValues, buildCELFromConditions, conditionToCEL,
    celStringLiteral, celValueLiteral. Used to rebuild a CEL string from a
    VisualExpression, including for GetMaskedExpression on the read-side
    of policy GET / search responses.

Merge-on-save helpers
  - getHiddenValues (per-condition, with pre-fetched fields map for N+1
    avoidance) — finds which stored values are not visible to the caller.
  - mergeConditionValues — re-injects the hidden values into a submitted
    condition without duplicates.
  - Together, these let BE-5 preserve attribute values the caller cannot
    see while still letting them edit the visible parts of a policy.

Write-path value-hold validation
  - validatePolicyExpressionValues, invalidValueError, validateConditionValues.
  - Generic "Invalid value." error on every rejection — no signal about
    whether the value exists or is merely not held (prevents enumeration).
  - Rejects the masked-token sentinel "--------" if submitted as a literal.

These all live in access_control_masking.go alongside the masking primitives
that BE-2 introduced. i18n entries added for the two new error IDs
(app.pap.save_policy.invalid_value, app.pap.validate_expression_values.app_error).

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

* MM-68503 - handle the masked-token sentinel in validation and merge

When the GET /policies endpoint returns a policy via MaskPolicyExpressions,
the raw expression contains the masked-token sentinel "--------" in place
of hidden values. If the frontend round-trips that expression unchanged
back to the server (e.g., the admin only modified channel assignment, not
the rules), the sentinel reaches the save path.

The previous code in validateConditionValues rejected the sentinel as
"Invalid value." This blocks the legitimate round-trip case.

Fix:
  - validateConditionValues: treat the sentinel as a placeholder and skip
    it during visibility / source-only / unknown-mode checks. Other values
    are still validated normally.
  - mergeConditionValues: strip the sentinel from submitted values before
    appending hidden values, so it never propagates to the stored result.
    Both array and single-value forms (string == "--------") are handled.

TestMaskedTokenRejection (which asserted the old rejection behavior) is
replaced by TestMaskedTokenConstant which only verifies the sentinel
string itself.

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

* MM-68504 - integrate save-path masking: 403 block on delete, merge-on-save, response masking

Save path (CreateOrUpdateAccessControlPolicy):
  * validatePolicyExpressionValues runs on the submitted expression before
    merge so re-injected hidden values are never validated against the
    caller's holdings.
  * mergeStoredPolicyExpressions re-injects hidden values from the stored
    policy and blocks (HTTP 403) any attempt to remove a condition that
    contained values the caller cannot see — closes the row-deletion gap
    in classified environments.
  * mergeExpressionWithMaskedValues unwraps single-element arrays for scalar
    operators after restoring the stored operator (avoids "attr == [val]"
    invalid CEL when the frontend submits "attr in []" as the masked-row
    placeholder for an originally-scalar condition).
  * checkSelfInclusion is bypassed for system admins (they may legitimately
    write conditions for values they do not hold); masking and value-hold
    validation still apply to system admins.

Delete path (DeleteAccessControlPolicy):
  * Same masked-values 403 block — a caller with masked values cannot delete
    the policy at all (UI Delete button is also disabled in FE-3).

Response masking:
  * createAccessControlPolicy and setAccessControlPolicyActiveStatus run
    MaskPolicyExpressions on the response so even a save reply doesn't
    leak the values the caller does not hold.

GetMaskedExpression, maskConditionValuesWithToken, replaceHiddenValuesWithToken,
MaskPolicyExpressions live alongside the rest of the masking helpers in
access_control_masking.go.

team_access_control.go: corrects ValidateChannelEligibilityForAccessControl
call site (drops the spurious receiver and rctx; it's a package-level helper
that only takes channel).

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

* MM-68503 - address PR review: batch field fetches, propagate errors, fail-closed write path

* MM-68503 - restore team-admin api4 tests accidentally dropped during BE-5 rebuild

* MM-68503 - address review and CodeRabbit feedback on save-path masking

* add tests for delete masking, self-inclusion, GET mask

* add assertions to strengten tests

* MM-68505 - add has_masked_values type and MaskedChip component

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

* MM-68506 - add masking support to TableEditor and team settings modal

TableEditor (table_editor.tsx, table_editor.scss):
  - hasMaskedValues plumbed through rows; lock operator/attribute selectors on
    masked rows.
  - Row remove (trash) button disabled on masked rows; disabled-state CSS so
    the icon doesn't show the destructive hover colour or a pointer cursor.
  - Test Rules button disabled when any row has masked values, with tooltip.
  - onMaskedStateChange callback to notify the parent for cross-component
    states (CEL editor read-only, Save disabled, banners).

Value selectors (single_value_selector_menu.tsx, multi_value_selector_menu.tsx,
selector_menus.scss, value_selector_menu.tsx):
  - Append MaskedChip after visible chips on multi-value rows.
  - Render MaskedChip as the sole value on single-value rows where the caller
    holds no visible value.

Policy details (policy_details.tsx, .scss, .test.tsx):
  - Track hasMaskedRows state; receive from TableEditor via onMaskedStateChange.
  - Show masked-values warning banner above the editor when present.
  - Same banner on the Delete confirmation modal so admins understand why
    deletion is consequential.

Team settings modal (team_policy_editor.tsx, .scss):
  - Same masked-values plumbing; delete button uses the disabled state when
    a policy has masked values, regardless of whether channels are assigned.
  - Pre-save check no longer treats "in []" as an incomplete rule — that
    placeholder comes from fully-masked rows that merge-on-save will fill in.

i18n entries added for the new strings.

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

* MM-68506 - fix hook order in SingleValueSelector when masked state changes

The early return for `hasMaskedValues && !value` sat between useState
and useCallback declarations, so when a parent re-render flipped the
masked state (e.g. after deleting a sibling rule) React saw a different
hook count and crashed with "Rendered fewer hooks than expected".

Move the read-only short-circuit after all hook declarations so the hook
order stays stable across renders.

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

* MM-68507 - CEL editor read-only when masked + system console wiring

CEL editor (editor.tsx, editor.scss):
  - hasMaskedRows prop: when true, Monaco is set to read-only and a banner
    explains why ("This expression contains restricted values. Switch to
    Simple mode to edit the values you have access to, or delete the entire
    rule.").
  - Test Rules button disabled in CEL mode when hasMaskedRows is true.

Policy details (policy_details.tsx, .scss):
  - hasMaskedRows state plumbed to CELEditor, TableEditor, and the Save /
    Delete buttons.
  - Save button disabled while masked rows are present (kept after the
    save-allowed-with-masked-values change in BE-5? — no, here we keep Save
    enabled so admins can add/modify rules; only row removal of masked rows
    is blocked).
  - Delete Policy button disabled when hasMaskedRows; a SectionNotice above
    the Delete card explains why ("This policy contains restricted values
    - Deletion not allowed").
  - New save error messages: invalid_value and self_exclusion are surfaced
    from the server's generic responses.

Policies list (policies.tsx): minor wiring change for the new state plumbing.

Table editor (table_editor.tsx): cross-component coordination — emits
onMaskedStateChange and respects the disabled-for-masked-row policy.

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

* MM-68508 - E2E suite for attribute-value masking

Covers the full read+write masking flow against a real server:
  - Masked chip rendering, operator/attribute lock, Test Rules disabled.
  - System admin subject to masking like any other caller (no role bypass).
  - Save with masked values: hidden values preserved by merge-on-save.
  - Trash button disabled on masked rows; server returns 403 on direct
    API attempt to remove a masked condition.
  - Delete Policy button disabled + server 403 when policy has masked values
    (both system console and team settings modal paths).
  - Self-inclusion failure only fires when the caller holds full visibility.
  - CEL editor read-only with banner when masked rows present.
  - Direct API validation: non-held values and the masked-token sentinel
    rejected with a generic "Invalid value." error.
  - Feature-flag-off path: no masking, all values visible.
  - Text-field shared_only masking (binary) with `in` and `==` operators.

A pluggable DB-setup helper marks specific CPA fields as shared_only for
the duration of a test (with per-test cleanup) since the API blocks setting
access_mode=shared_only without a source_plugin_id.

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

* MM-68506 - fix lint, jest mock factory, and unreachable delete-modal test

* MM-68506 - localize masked-condition-deleted save error

* MM-68506 - fix masked-policy delete warning detection and localize masked_rule_deleted

* fix linter issues

* MM-68506 - surface delete error, lock value selector on masked rows, drop dead remove-modal

* fix linter, add translations, adjust specs

* import wittoltip from shared

* fix linter and use the correct button variant

* MM-68506 - drop dangling rationale comment in access_control_field_test

* fix linter, translation and e2e tests

* use pg ts types and dependencies for e2e types mocks

* adjust switch mode persistance restriction

* fix team settings style buttons

* fail-closed guard for advanced expressions in  merge-on-save, plus  helper unit tests, and FF/test-helper cleanups

* MM-68505 - add has_masked_values type and MaskedChip component

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

* MM-68506 - add masking support to TableEditor and team settings modal

TableEditor (table_editor.tsx, table_editor.scss):
  - hasMaskedValues plumbed through rows; lock operator/attribute selectors on
    masked rows.
  - Row remove (trash) button disabled on masked rows; disabled-state CSS so
    the icon doesn't show the destructive hover colour or a pointer cursor.
  - Test Rules button disabled when any row has masked values, with tooltip.
  - onMaskedStateChange callback to notify the parent for cross-component
    states (CEL editor read-only, Save disabled, banners).

Value selectors (single_value_selector_menu.tsx, multi_value_selector_menu.tsx,
selector_menus.scss, value_selector_menu.tsx):
  - Append MaskedChip after visible chips on multi-value rows.
  - Render MaskedChip as the sole value on single-value rows where the caller
    holds no visible value.

Policy details (policy_details.tsx, .scss, .test.tsx):
  - Track hasMaskedRows state; receive from TableEditor via onMaskedStateChange.
  - Show masked-values warning banner above the editor when present.
  - Same banner on the Delete confirmation modal so admins understand why
    deletion is consequential.

Team settings modal (team_policy_editor.tsx, .scss):
  - Same masked-values plumbing; delete button uses the disabled state when
    a policy has masked values, regardless of whether channels are assigned.
  - Pre-save check no longer treats "in []" as an incomplete rule — that
    placeholder comes from fully-masked rows that merge-on-save will fill in.

i18n entries added for the new strings.

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

* MM-68506 - fix hook order in SingleValueSelector when masked state changes

The early return for `hasMaskedValues && !value` sat between useState
and useCallback declarations, so when a parent re-render flipped the
masked state (e.g. after deleting a sibling rule) React saw a different
hook count and crashed with "Rendered fewer hooks than expected".

Move the read-only short-circuit after all hook declarations so the hook
order stays stable across renders.

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

* MM-68507 - CEL editor read-only when masked + system console wiring

CEL editor (editor.tsx, editor.scss):
  - hasMaskedRows prop: when true, Monaco is set to read-only and a banner
    explains why ("This expression contains restricted values. Switch to
    Simple mode to edit the values you have access to, or delete the entire
    rule.").
  - Test Rules button disabled in CEL mode when hasMaskedRows is true.

Policy details (policy_details.tsx, .scss):
  - hasMaskedRows state plumbed to CELEditor, TableEditor, and the Save /
    Delete buttons.
  - Save button disabled while masked rows are present (kept after the
    save-allowed-with-masked-values change in BE-5? — no, here we keep Save
    enabled so admins can add/modify rules; only row removal of masked rows
    is blocked).
  - Delete Policy button disabled when hasMaskedRows; a SectionNotice above
    the Delete card explains why ("This policy contains restricted values
    - Deletion not allowed").
  - New save error messages: invalid_value and self_exclusion are surfaced
    from the server's generic responses.

Policies list (policies.tsx): minor wiring change for the new state plumbing.

Table editor (table_editor.tsx): cross-component coordination — emits
onMaskedStateChange and respects the disabled-for-masked-row policy.

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

* MM-68508 - E2E suite for attribute-value masking

Covers the full read+write masking flow against a real server:
  - Masked chip rendering, operator/attribute lock, Test Rules disabled.
  - System admin subject to masking like any other caller (no role bypass).
  - Save with masked values: hidden values preserved by merge-on-save.
  - Trash button disabled on masked rows; server returns 403 on direct
    API attempt to remove a masked condition.
  - Delete Policy button disabled + server 403 when policy has masked values
    (both system console and team settings modal paths).
  - Self-inclusion failure only fires when the caller holds full visibility.
  - CEL editor read-only with banner when masked rows present.
  - Direct API validation: non-held values and the masked-token sentinel
    rejected with a generic "Invalid value." error.
  - Feature-flag-off path: no masking, all values visible.
  - Text-field shared_only masking (binary) with `in` and `==` operators.

A pluggable DB-setup helper marks specific CPA fields as shared_only for
the duration of a test (with per-test cleanup) since the API blocks setting
access_mode=shared_only without a source_plugin_id.

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

* MM-68506 - fix lint, jest mock factory, and unreachable delete-modal test

* MM-68506 - localize masked-condition-deleted save error

* MM-68506 - fix masked-policy delete warning detection and localize masked_rule_deleted

* fix linter issues

* MM-68506 - surface delete error, lock value selector on masked rows, drop dead remove-modal

* fix linter, add translations, adjust specs

* import wittoltip from shared

* fix linter and use the correct button variant

* MM-68506 - drop dangling rationale comment in access_control_field_test

* fix linter, translation and e2e tests

* use pg ts types and dependencies for e2e types mocks

* adjust switch mode persistance restriction

* fix team settings style buttons

* fail-closed guard for advanced expressions in  merge-on-save, plus  helper unit tests, and FF/test-helper cleanups

* Refactor access control methods to use GetPropertyGroup for CPA group ID retrieval

* fix styles

* disable delete on masked policies in list view and remove dead modal warnings

* fix unit tests

* preserve hasAnyOf operator display for fully-masked multiselect conditions

* address PR feedback: lock Actions on masked save, filter source/shared_only from /attributes, add unit tests and e2e tests

* fix e2e tests

* comment out e2e to isolate issue

* completely remove the files to pass linter

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Mattermost Build <build@mattermost.com>
2026-05-19 21:25:14 +02:00
Maria A Nunez
5cd26002d3
Hide Download Apps link when running in Desktop app (#36614)
* Hide Download Apps UI when running in Desktop app

Co-authored-by: Maria A Nunez <maria.nunez@mattermost.com>

* Fix ESLint import order for Desktop app visibility changes

Co-authored-by: Maria A Nunez <maria.nunez@mattermost.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-05-19 09:55:31 -04:00
Asaad Mahmood
7bb6fb347b
Fix AI toolbar separator visibility (#36356)
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-05-19 18:41:43 +05:00
Daniel Espino García
92f6870a2b
Add "last used" field for incoming webhooks (#36416)
* Add "last used" field for incoming webhooks

* Address feedback

* Rename migrations

* Fix web lint
2026-05-19 15:22:04 +02:00
Andre Vasconcelos
23b4d8275b
MM-68197 Show classification banners in web and desktop apps (#36490)
* 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

* Added classification setup per channel on channel creation

* WIP: Adding classification banner integrated with channel banners

- Using a hook to resolve which values should be evaluated when displaying the banner

* Fixing style of dropdown input for classifications

* Fixing visual issues with dropdown inputs

* Adding E2E Tests and linter fixes

* General fixes and improvements

* Applying linter fixes

* Resolving lingering linter issues

* Updated snapshot and extracted i18n

* Adding test cleanup to prevent failures due to duplicates

* Addressing nitpick comment for test mapping of values

* Applying more fixes to E2E tests

* Improving test coverage and e2e test cleanup

* Resolving type issues

* Refactoring classification constant names an documentation

* Ensuring propertyvalue only stores single id, storing banner text in banner_info

* Fixing issues with linter alongside style issues on header

* Updating test assertion to account for fallback

* Fixing issues found during testing

- Removing custom selection from being an option and turned it into a state
- Ensuring only system administrators can set channel classification levels

* Fixing z-index issue with color input popover

* Setting classification level to lowest available value when switching it on

* Updating unit tests to match new spec for preselection

---------

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-19 00:05:26 +03:00
Carlos Garcia
548183d748
Mm 68282 admin ephemeral mode (#36194)
* adds feature flag to enable mattermost ephemeral mode

* add ephemeral mode config settings to system console

When feature flag is set to true a new section for Mobile Ephemeral Mode
settings shows under the Mobile Security section in case a valid Enterprise
Advanced License is active.

* adds Mobile Ephemeral Mode settings playwright tests

* improve descriptions for settings

* improves error messages and hints

* move validation to common helper and add new tests

* reverts package-lock.json changes

* proper struct alignment

* proper message sorting in json file

* use generic doc url for MEM section while docs are not ready

* Proper formatting for playwright tests

* fixes test
2026-05-18 22:23:58 +02:00
Harshil Sharma
f0360a838a
Data spillage report generation UI (#36340)
* Added base fr report generation

* WIP

* implemented UI flow

* implemented UI flow

* restructured the modal code into sub components

* Refactoring and cleanup

* lint fixes, added new tests

* i18n fix

* test fix

* Updated test

* CI

* Several improvements

* WIP

* Added tests

* Addressed some security enhancements

* Created zip writer entery later

* Improved a test to check for file content

* Improved error handling

* Made a geneeric function

* Updated classes

* accepting comment in report API

* Added more tests

* Integrated new API param

* Removed an unnecessary check

* Made a geneeric function

* Made a geneeric function

* Made the comment body not required and updated API docs

* Updated report generation API call in download report button

* Included decision in report and removed confirmation when keeping message

* Updated test

* Add explicit wait for removeWithoutReportButton visibility in test

Prevent race condition by waiting for the button to be visible after UI transitions to skip-confirm step before clicking it.

Co-authored-by: Maria A Nunez <maria.nunez@mattermost.com>

* PR Feedback

* explicitelly added return statement

* Included actor details in report

* Updated tests

---------

Co-authored-by: maria.nunez <maria.nunez@mattermost.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Mattermost Build <build@mattermost.com>
2026-05-18 20:24:50 +05:30
Ibrahim Serdar Acikgoz
bab9009825
MM-68592: Add leave confirmation modal for policy-added public channels (#36439)
* MM-68592: Add leave confirmation modal for policy-added public channels

When a user attempts to leave a public channel they were auto-added to via
a membership policy (channel.policy_enforced), show a confirmation modal
informing them that the leave is permanent and offering a 'Mute instead'
option as a lighter alternative. The flow follows the existing pattern
used for private channel leave confirmation.

The modal is opened from:
- Channel header menu Leave action
- Sidebar channel menu Leave action
- /leave slash command

The Mute instead button is hidden when the channel is already muted.

Co-authored-by: Ibrahim Serdar Acikgoz <isacikgoz@users.noreply.github.com>

* MM-68592: address CodeRabbit review

- Make handleMuteInstead async and only close the modal when the mute
  action resolves successfully, leaving it open on error so the user can
  retry or choose to leave instead.
- Move autoFocus from the destructive 'Leave channel' button to the
  non-destructive secondary action ('Mute instead' or 'Cancel') so
  pressing Enter does not default-confirm a permanent leave.
- Cover the failure path with a new unit test that asserts the modal
  remains open when muteChannel returns an error.

Co-authored-by: Ibrahim Serdar Acikgoz <isacikgoz@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Ibrahim Serdar Acikgoz <isacikgoz@users.noreply.github.com>
2026-05-18 13:47:45 +02:00
Maria A Nunez
f067fcde92
MM-66339 Hide empty content-flagging "With comment" section in reviewer DM (#36552)
* Add Cursor Cloud Agent Docker environment

Co-authored-by: Cursor <cursoragent@cursor.com>

* Fix Cloud Agent enterprise and Docker access

Co-authored-by: Cursor <cursoragent@cursor.com>

* Fix Cloud Agent Go path setup

Co-authored-by: Cursor <cursoragent@cursor.com>

* MM-66339 Stop double-JSON-stringifying content flagging comments

The flagPost, removeFlaggedPost, and keepFlaggedPost Client4 helpers were
calling JSON.stringify on the comment value before placing it in the JSON
request body. When the reporter or reviewer left the optional comment blank,
JSON.stringify('') returned the literal two-character string '""', which
the server then stored as the comment and embedded in the reviewer DM as
'With comment:\n\n> ""'. Send comment as the plain string instead so an
empty comment stays empty and the 'With comment' section is omitted entirely.

Co-authored-by: Maria A Nunez <maria.nunez@mattermost.com>

---------

Co-authored-by: Nick Misasi <nick.misasi@mattermost.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-18 16:52:16 +05:30
Miguel de la Cruz
669eb104c6
Fix webhook list ordering instability when paginating (MM-65732) (#36470)
* Fix webhook list ordering instability when paginating (MM-65732)

The webhook list view reorders entries when navigating between pages.
The first page initially shows webhooks in insertion order (from the
server), but after loading additional pages the display settles into
alphabetical order. Going back to page 1 then shows different items
than were originally visible.

Root causes:
1. Server: GetIncomingByTeamByUser, GetIncomingListByUser,
   GetOutgoingByTeamByUser, and GetOutgoingListByUser had no ORDER BY
   clause, so the database could return rows in any order.
2. Client (incoming webhooks): incomingWebhookCompare only resolved
   the channel-name fallback for the 'a' argument, not 'b', making
   the comparator asymmetric and producing an unstable sort.
3. Client: both installed_incoming_webhooks and installed_outgoing_webhooks
   called Array.prototype.sort() directly on the props array, mutating it.

Fix:
- Add ORDER BY DisplayName, Id to the four listing SQL queries so API
  pages always come back in alphabetical order. With a stable server
  order, the client sort over merged pages produces the same slice for
  each page number regardless of how many pages have been loaded.
- Symmetrise incomingWebhookCompare by applying the same channel-name
  and 'Private Webhook' fallback to the 'b' argument.
- Sort a copy ([...hooks].sort()) in both webhook list components so
  the original prop arrays are never mutated.

Co-authored-by: Miguel de la Cruz <mgdelacroix@users.noreply.github.com>

* Fix lint: remove space before JSX closing tag in webhook test

Co-authored-by: Miguel de la Cruz <mgdelacroix@users.noreply.github.com>

* Fold ordering tests into existing webhook store test functions

Instead of four separate top-level test registrations
(GetIncomingListByUserOrdering, etc.), each ordering assertion is
now a t.Run sub-test inside its corresponding existing function:

  testWebhookStoreGetIncomingListByUser
    └─ "GetIncomingListByUser, ordered alphabetically by display name"

  TestWebhookStoreGetIncomingByTeamByUser
    └─ "GetIncomingByTeamByUser, ordered alphabetically by display name"

  testWebhookStoreGetOutgoingListByUser
    └─ "GetOutgoingListByUser, ordered alphabetically by display name"

  testWebhookStoreGetOutgoingByTeamByUser
    └─ "GetOutgoingByTeamByUser, ordered alphabetically by display name"

Each sub-test creates fresh hooks (Charlie, Alpha, Bravo in insertion
order) scoped to its own IDs so they do not interfere with the
outer test's fixtures.

Co-authored-by: Miguel de la Cruz <mgdelacroix@users.noreply.github.com>

* Fix govet shadow and gofmt issues in webhook store tests

- Rename the outer err variable to errSave in three functions
  (testWebhookStoreGetIncomingListByUser,
  TestWebhookStoreGetIncomingByTeamByUser,
  testWebhookStoreGetOutgoingByTeamByUser) so that hooks, err :=
  declarations in sub-test closures no longer shadow it.
- Change hookC, err = to hookC, err := in each ordering sub-test
  to declare a local err instead of capturing the outer one.
- Remove a trailing blank line at the end of the file (gofmt).

Co-authored-by: Miguel de la Cruz <mgdelacroix@users.noreply.github.com>

* Remove jest.mock from installed_incoming_webhooks test

The mock for delete_integration_link was copied from the outgoing
webhooks list test but is not needed here: the real component renders
fine within renderWithContext (as shown by installed_incoming_webhook.test.tsx
which tests the individual item without any mocks). Since the ordering
tests do not interact with delete functionality, drop the mock and align
the action stub style to mockReturnValue(Promise.resolve()).

Co-authored-by: Miguel de la Cruz <mgdelacroix@users.noreply.github.com>

* Add ORDER BY to GetOutgoingByChannelByUser; add ordering sub-test

GetOutgoingByChannelByUser was the last paginated webhook listing
function without an ORDER BY clause. Add OrderBy("DisplayName", "Id")
consistent with all other listing functions.

Add the corresponding ordering sub-test inside
testWebhookStoreGetOutgoingByChannelByUser, following the same
errSave pattern established for the other functions to avoid
govet shadow warnings.

Co-authored-by: Miguel de la Cruz <mgdelacroix@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Miguel de la Cruz <mgdelacroix@users.noreply.github.com>
2026-05-18 12:25:05 +02:00
Ibrahim Serdar Acikgoz
deafd88fd5
MM-68762: Discoverable Private Channels — Server data layer (#36539)
* MM-68762: Add Postgres migrations for discoverable private channels

Three online-safe migrations introduce the schema that supports the
Discoverable Private Channels feature (PRs 2-5 of MM-68430 will land
behind it):

- 000175 adds Channels.Discoverable BOOLEAN NOT NULL DEFAULT FALSE.
  Metadata-only on Postgres >= 11; no table rewrite.
- 000176 creates a partial index on
  (TeamId) WHERE Discoverable AND Type='P' AND DeleteAt=0
  using CREATE INDEX CONCURRENTLY (-- morph:nontransactional) so the
  build never blocks writes on the populated Channels table.
- 000177 creates the ChannelJoinRequests table with three indexes, the
  important one being the partial unique index on (ChannelId, UserId)
  WHERE Status = 'pending'. That keeps the full audit history intact
  while still enforcing at-most-one active pending request per
  (channel, user).

Co-authored-by: Ibrahim Serdar Acikgoz <isacikgoz@users.noreply.github.com>

* MM-68762: Add FeatureFlagDiscoverableChannels (default false)

Gates the per-channel Discoverable toggle and the channel-join-request
flow. Default-OFF so all PRs in the MM-68430 series can land on master
without exposing partial UX.

Co-authored-by: Ibrahim Serdar Acikgoz <isacikgoz@users.noreply.github.com>

* MM-68762: Add Discoverable + ChannelJoinRequest models

- Channel gains a Discoverable bool, ChannelPatch a *bool, both serialized
  as 'discoverable'. Patch() applies it, Auditable() logs it, and IsValid()
  rejects Discoverable=true on any non-private channel so a misconfigured
  patch can never produce a public discoverable channel.
- New ChannelJoinRequest type captures the per-row state of a non-member's
  request: pending -> approved | denied | withdrawn. Rows are append-only
  with reviewer and timestamps so the table is also the audit trail.
  IsValid() enforces:
  * recognized status,
  * Message and DenialReason rune limits,
  * DenialReason only on denied rows (no orphan reasons),
  * reviewer + reviewed_at present for any terminal review (approved /
    denied) but not for self-service withdrawal.
- Two new WebSocket event constants -- channel_join_request_created and
  channel_join_request_updated -- that later PRs broadcast on the admin
  queue and the requester's My Pending Requests panel.

Unit tests cover Patch(), the new IsValid() rule on Discoverable, the
PreSave/PreUpdate timestamp behavior on ChannelJoinRequest, and every
IsValid branch including the reviewer-required-on-review invariant.

Co-authored-by: Ibrahim Serdar Acikgoz <isacikgoz@users.noreply.github.com>

* MM-68762: Add discoverable-channel permissions

Two new channel-scoped permissions, each independently rebindable from
the System Console:

- manage_private_channel_discoverability gates the per-channel toggle so
  admins can restrict who can flip discoverability without also handing
  out manage_private_channel_properties.
- manage_channel_join_requests gates the queue list / approve / deny /
  count endpoints (added in PR 2).

Both are added to the channel_admin role bootstrap so new deployments
get them by default, and a new permissions migration
(add_discoverable_channel_permissions) grants them to channel_admin,
team_admin and system_admin scheme roles on existing deployments.

Co-authored-by: Ibrahim Serdar Acikgoz <isacikgoz@users.noreply.github.com>

* MM-68762: Add ChannelJoinRequestStore and wire Discoverable into channel store

- channelSliceColumns / channelToSlice / updateChannelT now include the
  new Discoverable column so Save() and Update() round-trip the field.
  Existing select paths inherit the column automatically because every
  read goes through channelSliceColumns.
- New ChannelJoinRequestStore interface and SQL implementation:
  Save / Get / GetPendingForChannelAndUser / GetForChannel / GetForUser
  / Update / CountPending. Save translates the
  idx_channeljoinrequests_pending_unique partial unique index violation
  into store.ErrConflict so the app layer (PR 2) can return 409 without
  re-parsing pq errors.
- Storetest suite at storetest/channel_join_request_store.go is invoked
  from sqlstore via the existing StoreTest harness; covers insert /
  partial-unique conflict / re-insert after withdrawal / NotFound /
  status filtering / pagination with TotalCount / Update / CountPending.
- Mocks and retrylayer / timerlayer are regenerated via make store-mocks
  and go generate ./channels/store -- no hand-written generator output.

Co-authored-by: Ibrahim Serdar Acikgoz <isacikgoz@users.noreply.github.com>

* MM-68762: Add TS types for Discoverable channels + join requests

webapp/platform/types:
- Channel.discoverable?: boolean alongside existing policy_enforced /
  policy_is_active so the web client sees the same wire shape the server
  emits.
- ChannelJoinRequest, ChannelJoinRequestStatus, ChannelJoinRequestList,
  GetChannelJoinRequestsOptions for the API contract surfaced in PR 2.

webapp/platform/client:
- WebSocketEvents enum gains ChannelJoinRequestCreated and
  ChannelJoinRequestUpdated so PR 3 can hang WS handlers off them
  without redeclaring constants.

These are model-only updates with no UI consumer yet; PR 3 introduces
the toggle, request flow, and admin queue surfaces.

Co-authored-by: Ibrahim Serdar Acikgoz <isacikgoz@users.noreply.github.com>

* MM-68762: Split ChannelJoinRequests indexes into concurrent migrations

The mattermost-govet concurrentIndex lint check enforces CREATE INDEX
CONCURRENTLY on every CREATE INDEX statement, even on an empty
freshly-created table where it would be a no-op. The original 000177
file inlined three CREATE INDEX statements; that failed check-style.

Mirror the convention used by 000166_create_views +
000167_create_views_channel_id_delete_at_index: keep the CREATE TABLE
in its own (transactional) file, and move each index into a separate
nontransactional file that runs CREATE INDEX CONCURRENTLY. Verified
locally against Postgres 15 that all four new migrations apply in
order and the storetest suite (partial unique constraint + paged
list + count) still passes.

Co-authored-by: Ibrahim Serdar Acikgoz <isacikgoz@users.noreply.github.com>

* MM-68762: Wire new permission migration into test fixtures

Two CI test surfaces missed when the channel_admin role and the
permission-migration list gained the new
manage_private_channel_discoverability and manage_channel_join_requests
entries:

- testlib/store.go: the shared mocked SystemStore used by
  SetupWithStoreMock / SetupEnterpriseWithStoreMock needs an explicit
  GetByName expectation for every migration key (because the mock
  panics on unexpected calls). Add the new
  MigrationKeyAddDiscoverableChannelPermissions key so
  TestCreateOrUpdateAccessControlPolicy, the elasticsearch
  aggregation_job_test, and every other mock-store test stop panicking
  on server bootstrap.
- cmd/mmctl/commands/permissions_test.go: TestResetPermissionsCmd
  hard-codes the channel_admin default permission list and expects
  PatchRole to be called with exactly that slice. Extend the expected
  slice with the two new permission ids so the mmctl reset path stays
  in sync with the role bootstrap.

Co-authored-by: Ibrahim Serdar Acikgoz <isacikgoz@users.noreply.github.com>

* MM-68762: Register new idx_channels_discoverable_team in TestGetSchemaDefinition

The schema-dump test asserts an exact index count and definition map
for the channels table. Migration 000176 added
idx_channels_discoverable_team — a partial btree on (teamid) gated by
discoverable=true AND type='P' AND deleteat=0. Bump the expected count
from 12 to 13 and add the index's CREATE INDEX definition as produced
by pg_indexes (note: type is cast to channel_type, the existing
domain). Verified locally against Postgres 15.

Co-authored-by: Ibrahim Serdar Acikgoz <isacikgoz@users.noreply.github.com>

* MM-68762: Fix golangci-lint findings in ChannelJoinRequest store

Two golangci-lint findings on the freshly-added files:

- sqlstore/channel_join_request_store.go:133 (modernize): collapse the
  'if page < 0 { page = 0 }' clamp into max(opts.Page, 0).
- storetest/channel_join_request_store.go:243 (govet shadow): the
  inner Save loop redeclared err with :=, shadowing the outer err
  captured from the first CountPending call. Switch to plain
  assignment so the same err is reused.

Verified locally with golangci-lint v2.11.4 across public/...,
channels/app/..., channels/store/..., channels/testlib/... and
cmd/mmctl/commands/... — 0 issues.

Co-authored-by: Ibrahim Serdar Acikgoz <isacikgoz@users.noreply.github.com>

* MM-68762: Sync channel_admin bootstrap with TestDoAdvancedPermissionsMigration

app_test.go pins the exact list of permissions the channel_admin role
is expected to hold after DoAdvancedPermissionsMigration completes.
The role bootstrap in role.go grew two entries
(manage_private_channel_discoverability and manage_channel_join_requests),
so the test's expected slice needs the same two entries appended in
the same order, otherwise assert.Equal fails on slice ordering.

This is the same class of fix as the mmctl/permissions_test.go change
in a previous commit -- two parallel test fixtures encode the
channel_admin defaults and have to be updated in lockstep with the
bootstrap.

Co-authored-by: Ibrahim Serdar Acikgoz <isacikgoz@users.noreply.github.com>

* MM-68762: Add English translations for new model error keys

12 keys were emitted by the new Discoverable + ChannelJoinRequest
validation paths but had no en.json entry, which trips i18n-check on
CI. Add the missing entries with one-line English copy that mirrors
adjacent model errors (Invalid <field>., Create at must be a valid
time., etc.). The new entries are:

- model.channel.is_valid.discoverable.app_error
- model.channel_join_request.is_valid.channel_id.app_error
- model.channel_join_request.is_valid.create_at.app_error
- model.channel_join_request.is_valid.denial_reason.app_error
- model.channel_join_request.is_valid.denial_reason_status.app_error
- model.channel_join_request.is_valid.id.app_error
- model.channel_join_request.is_valid.message.app_error
- model.channel_join_request.is_valid.reviewed_by.app_error
- model.channel_join_request.is_valid.reviewer.app_error
- model.channel_join_request.is_valid.status.app_error
- model.channel_join_request.is_valid.update_at.app_error
- model.channel_join_request.is_valid.user_id.app_error

Generated through 'make i18n-extract'; verified clean with
'make i18n-check'. Per the workspace rule, only en.json was modified --
no other locale files.

Co-authored-by: Ibrahim Serdar Acikgoz <isacikgoz@users.noreply.github.com>

* MM-68762: Address CodeRabbit review: stable pagination + redact denial reason from audit log

Two production-code findings from CodeRabbit on the freshly-added
ChannelJoinRequest server code:

- sqlstore/channel_join_request_store.go (GetForChannel / GetForUser):
  OrderBy("CreateAt DESC") alone is unstable when two rows share a
  millisecond (NewId is monotonic-ish but CreateAt is millisecond
  resolution), so offset paging could duplicate or skip rows between
  pages. Add Id DESC as a deterministic tie-breaker on both list
  queries.
- model/channel_join_request.Auditable: the denial reason is admin-typed
  free text and could carry sensitive content. Mirror the existing
  has_message pattern by emitting has_denial_reason as a boolean
  presence flag instead of the raw value. Reviewer id, review timestamp,
  and status are still logged, so the audit trail keeps every piece
  needed for compliance review.

Co-authored-by: Ibrahim Serdar Acikgoz <isacikgoz@users.noreply.github.com>

* MM-68762: Tighten model tests per CodeRabbit review

Two test-only findings from CodeRabbit:

- TestChannelJoinRequestPreUpdateAdvancesUpdateAt previously asserted
  GreaterOrEqual(r.UpdateAt, originalCreate). Because validRequest
  initialises UpdateAt to GetMillis() (same call site as CreateAt), a
  no-op PreUpdate would still pass that check. Seed r.UpdateAt = 1
  before calling PreUpdate() and assert Greater(r.UpdateAt, int64(1))
  so any regression that drops the GetMillis assignment fails the test.
- TestChannelIsValidDiscoverable did not cover ChannelTypeGroup. Add the
  case alongside ChannelTypeOpen and ChannelTypeDirect so the contract
  that 'only ChannelTypePrivate accepts Discoverable=true' is fully
  pinned across all four channel types.

Co-authored-by: Ibrahim Serdar Acikgoz <isacikgoz@users.noreply.github.com>

* MM-68762: Mock ChannelJoinRequest accessor in retrylayer test

retrylayer_test.go's genStore() helper mocks every Store() accessor
because retrylayer.New() wraps the entire surface. The new
ChannelJoinRequest() method I added on Store was missing from the
mock, so TestRetry/on_regular_error_should_not_retry panicked with
'Unexpected Method Call ChannelJoinRequest()' on Postgres shard 0.

Add the mock alongside the other accessors. No production code
change.

Co-authored-by: Ibrahim Serdar Acikgoz <isacikgoz@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Ibrahim Serdar Acikgoz <isacikgoz@users.noreply.github.com>
2026-05-15 21:04:32 +02:00
Maria A Nunez
6aae94f20b
Add Display Name to User Properties in Webapp (#36363)
* Phase 1: CPA display_name + CEL-safe name validation (server)

- Add typed DisplayName field to CPAAttrs + display_name attr key constant.
- Add ValidateCPAFieldName helper enforcing CEL IDENTIFIER + reserved-word blacklist.
- Wire validation into App.CreateCPAField (always) and App.PatchCPAField (lenient grandfather: skip when Name unchanged).
- Trim + 255-rune cap DisplayName in CPAField.SanitizeAndValidate.
- Developer-facing godoc note documenting rule, sources of truth, and Option C scoping.
- Asserting test for documented Option C plugin-API bypass (closed by PR #36173).

Spec: planner/projects/property-display-name/ideas/001-cpa-display-name/spec.md
Plan: .planning/phase-1/PLAN.md
Made-with: Cursor

* Phase 1 (review): address Reza's Major + Minor findings

- Rename misleading subtest "empty DisplayName is omitted from attrs"
  to "empty DisplayName round-trips as empty string" (Major #1).
- Add TestCPAAttrs_JSONOmitEmpty pinning the omitempty wire-format
  contract that PR #36173's typed-attrs strategy relies on (Major #1).
- Extend TestValidateCPAFieldName: case-sensitivity (IN/In ok),
  single-character names (a/_/A ok), missing "as" reserved word
  (Minor #2). Add whitespace-only DisplayName case (Minor #2).
- Document PropertyFieldNameMaxRunes reuse in SanitizeAndValidate
  to prevent drift (Minor #3).
- Replace broken PLAN-server.md reference in bypass-test docstring
  with in-tree CPAAttrs godoc reference (Minor #4).
- Document omitempty semantics on CPAAttrs.DisplayName field to
  prevent the same misreading caught in review (Minor #5).
- Document grouping intent above CPAFieldNameReservedWords (Minor #8).

Review: .planning/phase-1/REVIEW.md
Made-with: Cursor

* Phase 2: in-app backfill migration for CPA display_name

- Add cpaDisplayNameBackfillKey + cpaDisplayNameBackfillVersion constants.
- Implement (*Server).doSetupCPADisplayNameBackfill: idempotent, cursor-paged
  scan over CPA group fields; backfill attrs.display_name = name when empty.
- Register in m1 migration slice in doAppMigrations (mlog.Fatal on error,
  matching existing convention).
- Three migration tests: NoExistingFields, BackfillsMissing, Idempotent.

System-key idempotency + per-field DisplayName-empty check together provide
HA-safe behavior on rolling deploys (last-write-wins on the System key;
data-level idempotency from the per-field check).

Spec: planner/projects/property-display-name/ideas/001-cpa-display-name/spec.md
Plan: .planning/phase-2/PLAN.md
Made-with: Cursor

* Phase 2 (review): document race + harden idempotency test

- Document SearchPropertyFields→UpdatePropertyFields rolling-deploy
  race: stale snapshot can revert concurrent admin CPA rename. Pre-
  existing systemic shape (no UpdateAt optimistic-lock); narrow
  window; bounded blast radius (admin re-rename, ABAC ID-keyed).
  Accepted limitation per spec Out of Scope (Major #1, Option C).
- Tighten TestCPADisplayNameBackfill_Idempotent: snapshot UpdateAt
  before second run; assert no DB write on the System key or the
  field row (Major #2).
- Extract clearCPABackfillMarker helper with explanatory godoc to
  centralize the 3x-repeated test precondition (Minor #1).
- Comment fieldA seed as the "key-present-as-empty-string" idempotency
  boundary case (Minor #6).
- Add godoc to doSetupCPADisplayNameBackfill (Minor #10).

Review: .planning/phase-2/REVIEW.md
Made-with: Cursor

* Linting

* Removing unnecessary comments

* Clean up tests

* Linting

* Fix tests

* Updated API doc

* Phase 3: webapp helper + render-site migration for CPA display_name

- Add display_name?: string to UserPropertyField.attrs type.
- New getUserPropertyFieldLabel(field) helper: returns
  attrs.display_name?.trim() || name. Defensive against missing attrs.
- Migrate ~10 user-facing CPA-name render sites to the helper:
  profile popover, user settings general (4 usages incl. line 1673
  missed by high-level plan), admin user detail, admin CPA list (2
  usages), and ABAC editor's selected-attribute UI (3 usages incl.
  the button label found in planning-stage research).
- CEL paths (table_editor, attribute_selector_menu user.attributes
  expression construction, ABAC search filters) keep using `name`
  per spec — display_name is label-only.
- Phase 4 boundary marker: TODOs in admin table + delete modal for
  follow-up admin-edit UX + client-side validator.

Spec: planner/projects/property-display-name/ideas/001-cpa-display-name/spec.md
Plan: .planning/phase-3/PLAN.md

* Phase 3 (review): add Unicode test + correct helper docblock scope

Address Reza's Phase 3 review:
- Major #1: add missing test case for non-ASCII display_name
  (Latin-extended + CJK), pinning the trim/passthrough contract.
- Nitpick #3: correct the helper's JSDoc to reflect that the
  delete modal is intentionally not migrated until Phase 4.

No production behavior change. No new dependencies.

Made-with: Cursor

* Phase 4: admin CPA edit UX + client-side identifier validation

Made-with: Cursor

* docs: append Phase 4 implementation summary

Made-with: Cursor

* Phase 4: admin CPA edit UX + client-side identifier validation

Complete the Phase 4 takeover from the existing dirty worktree and record the verified Stage 2 scope for admin CPA display-name editing, client-side identifier validation, and the required grandfather regression follow-ups.
Document the targeted Jest, typecheck, and lint-equivalent validation results in the Phase 4 plan without widening the implementation scope or rewriting the prior in-scope work.

Made-with: Cursor

* docs: finalize Phase 4 implementation summary

Made-with: Cursor

* docs: correct Phase 4 summary commit reference

Made-with: Cursor

* Phase 4 (review): fix empty-name warning precedence

Required-name validation now short-circuits before uniqueness checks so empty identifiers keep the correct warning. Add duplicate collision regression coverage for the dot-menu flow and add a stable validation-error testid for Phase 5 automation.

Made-with: Cursor

* Test updates

* Fix merge issue

* Fix tests

* PR Feedback

* Move migration to PropertyService

* Updates to UX

* Comment cleanup

* Add webapp tests for CPA display_name and fix CEL-affected specs

Update E2E seeds to use CEL-safe identifiers with display_name,
add ABAC selector spec, and extend Jest coverage for label-rendering
sites, auto-fill guard rails, and required-warning suppression.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Remove .planning/phase-4/PLAN.md

This planning artifact was committed inadvertently and should not be
part of the codebase.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Address CodeRabbit review comments

- Fix e2e test to use display_name in label assertions
- Make getIncrementedCELName case-insensitive to prevent collisions
- Update tooltip to mention reserved CEL words
- Replace hasSpaces check with full CEL identifier validation
- Use CPA_FIELD_NAME_MAX_RUNES for consistent maxLength
- Fix race condition by removing global cleanupAllFields
- Enable IntegratedBoards flag for legacy field seeding
- Replace fixed sleeps with state-based waits in tests

Co-authored-by: Maria A Nunez <maria.nunez@mattermost.com>

* Fix linting errors in getIncrementedCELName

- Use camelCase for destructured delete_at parameter
- Place dots on same line for method chaining

Co-authored-by: Maria A Nunez <maria.nunez@mattermost.com>

* Remove unused imports in user_attributes_display_name.spec.ts

- Remove unused deleteCustomProfileAttributes import
- Remove unused getFieldsMap function
- Remove unused FieldsMap type

Co-authored-by: Maria A Nunez <maria.nunez@mattermost.com>

* Fix webapp test failure - remove htmlFor assertion

The htmlFor attribute assertion was failing in the test environment,
likely due to a testing library issue. The important functionality
(displaying display_name in labels) is still properly tested.

Co-authored-by: Maria A Nunez <maria.nunez@mattermost.com>

* Fix post-merge CI failures: i18n drift and Playwright Prettier

- Re-extract webapp en.json so the identifier tooltip string matches
  user_properties_table.tsx (source of truth was already shortened in
  Phase 4; en.json was not regenerated).
- Apply Prettier formatting to three CPA display_name Playwright specs
  (whitespace and import/expression collapsing only). No test logic
  changes.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Address CodeRabbit feedback: use stable locators, add reserved words to tooltip, remove regex from hasText

Co-authored-by: Maria A Nunez <maria.nunez@mattermost.com>

* Fix i18n drift: align defaultMessage with en.json for identifier tooltip

Co-authored-by: Maria A Nunez <maria.nunez@mattermost.com>

* Comment cleanup

* Slugify CPA duplicate names to snake_case

slugifyForCEL now lowercases and inserts underscores at camel/PascalCase
boundaries (e.g. MyField -> my_field, XMLParser -> xml_parser) so
duplicated CPA fields get conventional snake_case names instead of
preserving the source casing.

Co-authored-by: Cursor <cursoragent@cursor.com>

* UX improvements: CEL identifier tooltip, validation, and attribute picker dual-name display

- Add info tooltip to the Attribute column header explaining CEL identifier rules
- Add client-side CEL identifier validation (pattern + reserved words) with a descriptive error message
- Show both display name and unique identifier in the policy attribute picker
- Filter attribute picker search by both display name and unique name
- Add display_name to UserPropertyField attrs TypeScript type
- Expand "CEL" to "Common Expression Language (CEL)" in the attribute-spaces tooltip

Co-authored-by: Cursor <cursoragent@cursor.com>

* Linting

* PR Feedback

* Restore name limit

* Fix tests

* Revert stray comment block above TestCPADisplayNameBackfill_BackfillsProtectedSourceOnlyField

Co-authored-by: Maria A Nunez <maria.nunez@mattermost.com>

* Revert extended fieldA comment in TestCPADisplayNameBackfill_BackfillsMissing

Co-authored-by: Maria A Nunez <maria.nunez@mattermost.com>

* Fix E2E tests

* Fix test

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-15 12:18:31 -04:00
Vishal
51fd952ae6
MM-67771: Update Report a Problem to email flow (#35900)
* MM-67771 Update Report a Problem to email flow for licensed servers

Change the default "Report a Problem" behavior for licensed servers to
open a mailto link to reportaproblem@mattermost.com with pre-filled
metadata instead of redirecting to the support portal. Unlicensed servers
continue to redirect to the troubleshooting forums. Admin console help
text is now license-aware with separate descriptions for each plan type.

* Add isFreeEdition check for Report a Problem flow

Treat both unlicensed servers and licensed servers with entry SKU as
free edition. This affects the Report a Problem default behavior
(forum redirect vs mailto) and the admin console help text shown.

- Add isFreeEdition to general.ts selectors and admin_definition_helpers
- Add SKUEntry constant to general constants
- Reuse isFreeEdition in product_menu.tsx
- Add entry SKU test case for report_a_problem

* Add the link to forums for free edition

* Add permission and restricted-mode guards to ReportAProblemType dropdown

The ReportAProblemType dropdown was missing the write-permission check
and RestrictSystemAdmin guard that all other fields in the section have.
2026-05-15 16:33:54 +05:30
David Krauser
9f1fe90b69
Migrate CPA to the v2 Property System (#36180) 2026-05-14 12:46:07 -04:00
Harrison Healey
0c98113a17
MM-65058 Make Direct Messages modal load GMs when needed (#36548)
* Changed batchGetProfilesInChannel to batchGetProfilesInGroupChannel and have it use bulk API

* MM-65058 Add useUserIdsInGroupChannel and use to populate Direct Messages modal

* Address feedback

* Run Prettier

* Fix types
2026-05-14 10:16:48 -04:00
Joshua D Schoep
d8612e378f
[MM-2541] Shortcut to mark all channels as read for a team (#34012)
Some checks are pending
Server CI / Check mmctl docs (push) Blocked by required conditions
Server CI / Postgres (shard 0) (push) Blocked by required conditions
Server CI / Postgres (shard 1) (push) Blocked by required conditions
Server CI / Postgres (shard 2) (push) Blocked by required conditions
Server CI / Postgres (shard 3) (push) Blocked by required conditions
Server CI / Merge Postgres Test Results (push) Blocked by required conditions
Server CI / Elasticsearch v8 Compatibility (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 0) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 1) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 2) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 3) (push) Blocked by required conditions
Server CI / Merge Postgres FIPS Test Results (push) Blocked by required conditions
Server CI / Run mmctl tests (push) Blocked by required conditions
Server CI / Run mmctl tests (FIPS) (push) Blocked by required conditions
Server CI / Build mattermost server app (push) Blocked by required conditions
Tools CI / check-style (mattermost-govet) (push) Waiting to run
Tools CI / Test (mattermost-govet) (push) Waiting to run
Web App CI / check-lint (push) Waiting to run
Web App CI / check-i18n (push) Blocked by required conditions
Web App CI / check-external-links (push) Blocked by required conditions
Web App CI / check-types (push) Blocked by required conditions
Web App CI / test (platform) (push) Blocked by required conditions
Web App CI / test (mattermost-redux) (push) Blocked by required conditions
Web App CI / test (channels shard 1/4) (push) Blocked by required conditions
Web App CI / test (channels shard 2/4) (push) Blocked by required conditions
Web App CI / test (channels shard 3/4) (push) Blocked by required conditions
Web App CI / test (channels shard 4/4) (push) Blocked by required conditions
Web App CI / upload-coverage (push) Blocked by required conditions
Web App CI / build (push) Blocked by required conditions
YAML Lint / yamllint (push) Waiting to run
* feat(webapp): added keyboard shortcut for Mark All As Read (MM-2541)

- Added shortcut (within sidebar) for Shift+ESC to mark _all_ messages, teams as read
    - Desktop only
- Added feature toasts for new features and localStorage support
- Added feature toast for mark-all-as-read feature
    - Should decide when/how people want this shown, I just followed designs
    - Will only show if the user has not clicked 'Got it' before, and is not on mobile
- Added confirmation modal for mark all as read shortcut
    - Contains option to not show again, saved in localStorage
- Added English translations for read shortcut
    - Will need i18n aid on other languages

This is a draft version of this feature update that still needs testing and i18n support, along with a11y validation.

* feat(webapp): feature flags and fixes for mark all as read shortcut

- Added feature flags surrounding rollout of mark-all-as-read shortcut
- Added shortcut to list of shortcuts in help section
- Extended tests for new components
- Updated snapshot for sidebar_list, keyboard_shortcuts_modal
- Fixed styling and CSS issues

Still in draft, needs documentation and e2e support.

* fix(webapp): fixed some issues with new mark-all-read feature

- Scoped persistent storage to current user ID
  so that subsequent new logins also get the notification
- Replaced LocalStorage calls with useGlobalState calls, sad
  that I missed that this updated call was being used.
- Fixed an issue that would have caused the new shortcut to
  show up in the Help menu's shortcuts without being enabled.

* Fixed a snapshot test and a missing i18n member

* Replaced useGlobalState with backend-ready usePreference. Previous version was just a mistake as we didnt know about the supported API

* fix(server): fix lint issue with gofmt

* feat(server,webapp): added cleaner and more effective method with which to mark-all-read

- Added 2 new routes to the API (need to find docs to update those):
    - `PUT /api/v4/channels/members/<userId>/direct/read` will mark a user's non-team DMs and GMs as read
    - `PUT /api/v4/users/<userId>/teams/<teamId>/read` will do a similar action as the multi-channel mark_read action, but with a teamId signifier. Because this is using a teamId, it will _not_ handle DMs or GMs.
- Updated sidebar_list.tsx to use these new routes for the new shortcut
- Added extensive testing, including feature flag assurance.

* fix from upstream changes

* fix: eslint errors in teams actions

* document new API endpoints

* fix i18n

* fix err id

* remove unused localhost methods

* use ShortcutKey and ShortcutSequence

* feature_enhancements, mark as read toast enchancements

* read all modal mount point, use openModal

* use handler

* fix style

* fix: fix refactoring typo

* Merge fix: realign branch with upstream changes

Upstream MM-67319/MM-67320 (#36037) moved ShortcutKey and
WithTooltip into the shared package and rewrote the keyboard
shortcuts test to snapshot real DOM instead of a
react-test-renderer tree. The merge resolution missed several
follow-on consequences; clean them up so the branch builds, type
checks, lints, passes i18n-extract-check and runs without
throwing at mount.

- Port the inline-content variant from the deleted channels-side
  shortcut_key.scss to the new shared shortcut_key.css.
- Refresh the keyboard_shortcuts_sequence snapshot so it matches
  Testing Library's container output (DOM only, no component
  nodes, class= not className=).
- Repoint mark_all_as_read_modal and mark_all_as_read_toast at
  components/shortcut_key for ShortcutKeys and use
  ShortcutKeys.escape; the channels-side with_tooltip is now a
  thin re-export and the field was renamed in the shared keys
  map. Without this both consumers threw "Cannot read properties
  of undefined" at mount.
- Switch mark_all_as_read_toast's UserAgent import to
  @mattermost/shared/utils/user_agent; the channels-local
  utils/user_agent path no longer resolves.
- Drop the orphan mark_all_threads_as_read_modal.cancel string
  from en.json so formatjs extraction is in sync.

* Clean up TestReadAllInTeam

Drop four lines left from debugging and replace them with a real
assertion: LastViewedAtTimes must contain the test channel with a
value at or after the most recent post.

Update three client.GetChannel calls to the (ctx, id) signature;
the prior etag argument no longer compiles after upstream removed
it.

* Use SelectBuilder for team channels query

GetTeamChannelsWithUnreadAndMentions built a squirrel query and
then manually called ToSql before handing the string+args to
GetReplica().Select. SelectBuilder accepts the builder directly
and removes the intermediate dance, matching the pattern used
elsewhere in this store.

* Mark all team-channel threads on team read

MarkTeamChannelsAndThreadsViewed used Thread().MarkAllAsReadByTeam
unconditionally, writing every thread membership in the team for
the user even when nothing was stale. Scoping the call to
channelsToView (channels with unread channel-level messages) would
have closed the perf concern but introduced a regression: in CRT
mode a thread reply does not bump the channel's TotalMsgCount, so
a channel can be read at the channel level while still having
unread thread replies, and those would have been silently skipped.

Build the channel-id list from the keys of the times map instead.
GetTeamChannelsWithUnreadAndMentions already populates that map
for every team channel the user belongs to, so no extra query is
needed. MarkAllAsReadByChannels then filters the actual UPDATE
through its LastReplyAt > LastViewed clause, keeping writes
bounded to genuinely stale rows.

Gate the channel-level work (UpdateLastViewedAt, push clearing,
the MultipleChannelsViewed event) on channelsToView being
non-empty, but always run the thread mark and broadcast
ThreadReadChanged for every team channel so CRT clients refresh
thread state in channels that had no channel-level change.

* Mark mark-read audit records as success

The handlers for mark all DM/GM and mark team read created an
audit record with status Fail and never updated it on success,
so successful calls were always logged as failures.

* Mark all DM/GM threads on full read

MarkAllDirectAndGroupMessagesViewed early-returned when no
channel had unreads, so followed threads in DMs/GMs whose
channel-level counters were already current stayed unread under
CRT. Mirror MarkTeamChannelsAndThreadsViewed and call
MarkAllAsReadByChannels for every DM/GM in times.

* Polish DM/GM channels-with-unreads query

Use model.ChannelTypeDirect/Group constants instead of bare
"D"/"G" literals, and update the error wrap to mention DM/GM
channels (it was copied from the team variant).

* Fix stale ReadAllMessages godoc

* Type last_viewed_at_times as int64 map in OpenAPI

The response field was declared as a generic object. Add
additionalProperties so generated clients see it as a
channelId -> int64 timestamp map.

* Gate MarkAllAsReadToast mount on feature flag

The toast was mounted unconditionally, so its async chunk loaded
even when EnableShiftEscapeToMarkAllRead was off. Gate the mount
with the flag so the chunk only loads when the feature is on.

* Return data from markAllInTeamAsRead thunk

Match the {data: response} shape used by adjacent thunks instead
of returning {}, so callers can read the API payload.

* Coerce undefined suffix in createStoredKey

createStoredKey('foo') returned 'fooundefined' when the suffix
arg was omitted. Coerce a missing suffix to ''.

* Refactor mark-read websocket events

* Polish DM/GM channels-with-unreads query

* Fix import order in shortcut_key consumers

* Fix CI

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
Co-authored-by: Jesse Hallam <jesse@mattermost.com>
Co-authored-by: Caleb Roseland <caleb@calebroseland.com>
Co-authored-by: Alejandro García Montoro <alejandro.garciamontoro@gmail.com>
2026-05-13 16:38:30 +00:00
Ibrahim Serdar Acikgoz
5c21fbbc0f
[MM-68588] Add notice in System Console when policy has mixed channel… (#36350)
Some checks are pending
Server CI / Check mmctl docs (push) Blocked by required conditions
Server CI / Postgres (shard 0) (push) Blocked by required conditions
Server CI / Postgres (shard 1) (push) Blocked by required conditions
Server CI / Postgres (shard 2) (push) Blocked by required conditions
Server CI / Postgres (shard 3) (push) Blocked by required conditions
Server CI / Merge Postgres Test Results (push) Blocked by required conditions
Server CI / Elasticsearch v8 Compatibility (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 0) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 1) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 2) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 3) (push) Blocked by required conditions
Server CI / Merge Postgres FIPS Test Results (push) Blocked by required conditions
Server CI / Run mmctl tests (push) Blocked by required conditions
Server CI / Run mmctl tests (FIPS) (push) Blocked by required conditions
Server CI / Build mattermost server app (push) Blocked by required conditions
Tools CI / check-style (mattermost-govet) (push) Waiting to run
Tools CI / Test (mattermost-govet) (push) Waiting to run
Web App CI / check-lint (push) Waiting to run
Web App CI / check-i18n (push) Blocked by required conditions
Web App CI / check-external-links (push) Blocked by required conditions
Web App CI / check-types (push) Blocked by required conditions
Web App CI / test (platform) (push) Blocked by required conditions
Web App CI / test (mattermost-redux) (push) Blocked by required conditions
Web App CI / test (channels shard 1/4) (push) Blocked by required conditions
Web App CI / test (channels shard 2/4) (push) Blocked by required conditions
Web App CI / test (channels shard 3/4) (push) Blocked by required conditions
Web App CI / test (channels shard 4/4) (push) Blocked by required conditions
Web App CI / upload-coverage (push) Blocked by required conditions
Web App CI / build (push) Blocked by required conditions
YAML Lint / yamllint (push) Waiting to run
* [MM-68588] Add notice in System Console when policy has mixed channel types

When a membership policy in the System Console policy editor has both
public and private channels assigned, the implications differ by type:
private channels restrict access while public channels are advisory.

Add an informational SectionNotice below the assigned-channels list
explaining the distinction so admins understand the behavior before
saving. The notice only appears when the effective channel set
(saved - removed + added) contains at least one channel of each type.

Refactored the public/private counting that was previously inlined in
the confirmation modal block into a useMemo so the same calculation
drives both the new notice and the existing confirmation modal.

Made-with: Cursor

* Add mixed channel notice to team policy editor

Co-authored-by: Ibrahim Serdar Acikgoz <isacikgoz@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Ibrahim Serdar Acikgoz <isacikgoz@users.noreply.github.com>
2026-05-12 10:08:42 +02:00
Maria A Nunez
3c39d61544
Fix invite modal autocomplete clipping (#36505)
Some checks are pending
Server CI / Check mmctl docs (push) Blocked by required conditions
Server CI / Postgres (shard 0) (push) Blocked by required conditions
Server CI / Postgres (shard 1) (push) Blocked by required conditions
Server CI / Postgres (shard 2) (push) Blocked by required conditions
Server CI / Postgres (shard 3) (push) Blocked by required conditions
Server CI / Merge Postgres Test Results (push) Blocked by required conditions
Server CI / Elasticsearch v8 Compatibility (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 0) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 1) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 2) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 3) (push) Blocked by required conditions
Server CI / Merge Postgres FIPS Test Results (push) Blocked by required conditions
Server CI / Run mmctl tests (push) Blocked by required conditions
Server CI / Run mmctl tests (FIPS) (push) Blocked by required conditions
Server CI / Build mattermost server app (push) Blocked by required conditions
Tools CI / check-style (mattermost-govet) (push) Waiting to run
Tools CI / Test (mattermost-govet) (push) Waiting to run
Web App CI / check-lint (push) Waiting to run
Web App CI / check-i18n (push) Blocked by required conditions
Web App CI / check-external-links (push) Blocked by required conditions
Web App CI / check-types (push) Blocked by required conditions
Web App CI / test (platform) (push) Blocked by required conditions
Web App CI / test (mattermost-redux) (push) Blocked by required conditions
Web App CI / test (channels shard 1/4) (push) Blocked by required conditions
Web App CI / test (channels shard 2/4) (push) Blocked by required conditions
Web App CI / test (channels shard 3/4) (push) Blocked by required conditions
Web App CI / test (channels shard 4/4) (push) Blocked by required conditions
Web App CI / upload-coverage (push) Blocked by required conditions
Web App CI / build (push) Blocked by required conditions
YAML Lint / yamllint (push) Waiting to run
* Fix invite modal autocomplete clipping

* Preserve invite modal dropdown overflow

* Add invite modal layout regression tests

* Add additional test

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Harrison Healey <harrisonmhealey@gmail.com>
2026-05-11 19:54:23 -04:00
Andre Vasconcelos
6083cc2282
MM-68196 Adding Global Classification configuration and banners (#36231)
Some checks are pending
Server CI / Check mmctl docs (push) Blocked by required conditions
Server CI / Postgres (shard 0) (push) Blocked by required conditions
Server CI / Postgres (shard 1) (push) Blocked by required conditions
Server CI / Postgres (shard 2) (push) Blocked by required conditions
Server CI / Postgres (shard 3) (push) Blocked by required conditions
Server CI / Merge Postgres Test Results (push) Blocked by required conditions
Server CI / Elasticsearch v8 Compatibility (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 0) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 1) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 2) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 3) (push) Blocked by required conditions
Server CI / Merge Postgres FIPS Test Results (push) Blocked by required conditions
Server CI / Run mmctl tests (push) Blocked by required conditions
Server CI / Run mmctl tests (FIPS) (push) Blocked by required conditions
Server CI / Build mattermost server app (push) Blocked by required conditions
Tools CI / check-style (mattermost-govet) (push) Waiting to run
Tools CI / Test (mattermost-govet) (push) Waiting to run
Web App CI / check-lint (push) Waiting to run
Web App CI / check-i18n (push) Blocked by required conditions
Web App CI / check-external-links (push) Blocked by required conditions
Web App CI / check-types (push) Blocked by required conditions
Web App CI / test (platform) (push) Blocked by required conditions
Web App CI / test (mattermost-redux) (push) Blocked by required conditions
Web App CI / test (channels shard 1/4) (push) Blocked by required conditions
Web App CI / test (channels shard 2/4) (push) Blocked by required conditions
Web App CI / test (channels shard 3/4) (push) Blocked by required conditions
Web App CI / test (channels shard 4/4) (push) Blocked by required conditions
Web App CI / upload-coverage (push) Blocked by required conditions
Web App CI / build (push) Blocked by required conditions
YAML Lint / yamllint (push) Waiting to run
* 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
Caleb Roseland
7e1bec4d4f
MM-68233: Fix sidebar icon not updating on channel privacy conversion via WS (#36006)
Some checks failed
Server CI / Postgres (shard 1) (push) Blocked by required conditions
Server CI / Postgres (shard 2) (push) Blocked by required conditions
Server CI / Postgres (shard 3) (push) Blocked by required conditions
Server CI / Merge Postgres Test Results (push) Blocked by required conditions
Server CI / Elasticsearch v8 Compatibility (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 0) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 1) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 2) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 3) (push) Blocked by required conditions
Server CI / Merge Postgres FIPS Test Results (push) Blocked by required conditions
Server CI / Run mmctl tests (push) Blocked by required conditions
Server CI / Run mmctl tests (FIPS) (push) Blocked by required conditions
Server CI / Build mattermost server app (push) Blocked by required conditions
Tools CI / check-style (mattermost-govet) (push) Waiting to run
Tools CI / Test (mattermost-govet) (push) Waiting to run
Web App CI / check-lint (push) Waiting to run
Web App CI / check-i18n (push) Blocked by required conditions
Web App CI / check-external-links (push) Blocked by required conditions
Web App CI / check-types (push) Blocked by required conditions
Web App CI / test (platform) (push) Blocked by required conditions
Web App CI / test (mattermost-redux) (push) Blocked by required conditions
Web App CI / test (channels shard 1/4) (push) Blocked by required conditions
Web App CI / test (channels shard 2/4) (push) Blocked by required conditions
Web App CI / test (channels shard 3/4) (push) Blocked by required conditions
Web App CI / test (channels shard 4/4) (push) Blocked by required conditions
Web App CI / upload-coverage (push) Blocked by required conditions
Web App CI / build (push) Blocked by required conditions
YAML Lint / yamllint (push) Waiting to run
BuildEnv Docker Image / build-image (push) Has been cancelled
BuildEnv Docker Image / build-image-fips (push) Has been cancelled
* fix(channels): update sidebar icon when channel converted via mmctl

The handleChannelConvertedEvent WebSocket handler hardcoded
type as PRIVATE_CHANNEL, so private-to-public conversions were
silently ignored. Now the server includes channel_type in the
channel_converted WS event and the frontend reads it.

Ref: MM-68233

* test(channels): add tests for channel_converted WS event

Add server-side tests verifying the WebSocket event payload includes
channel_type for both private→public and public→private conversions.
Add frontend tests for handleChannelConvertedEvent covering both
conversion directions, backwards compatibility fallback when
channel_type is absent, and edge cases.

Ref: MM-68233

* test(channels): add E2E test for channel privacy WS icon update

Playwright E2E tests verify that the sidebar channel icon updates
in real-time when channel privacy is changed via the API (simulating
mmctl). Tests both public→private and private→public directions.

Ref: MM-68233

* refactor: review feedback on channel_converted fix

Narrow channel_type WS field to 'O' | 'P' union type instead of
string. Drop hardcoded channel names in E2E tests to let
pw.random.channel() generate unique names and avoid collisions.

Ref: MM-68233

* fix(e2e): provide name + unique flag for channel creation

pw.random.channel() requires a name field — server rejects channels
without a valid lowercase alphanumeric name. Use unique: true to
append a random suffix for test isolation.

Ref: MM-68233

* refactor(channels): use channel type constants in channel_converted code

Address review feedback: replace inlined 'O'/'P' string literals with
predefined constants. websocket_messages.ts now types channel_type as
ChannelType (already imported); websocket_actions tests use
Constants.OPEN_CHANNEL / Constants.PRIVATE_CHANNEL.

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
2026-05-11 13:37:19 +02:00
Daniel Espino García
55496c07c1
Update API docs (#36302)
* Update API docs

* Coderabbit comments

* Address feedback

* Address feedback

* Coderabbit feedback
2026-05-11 12:29:25 +02:00
Felipe Martin
0afef7760c
Include connection ID in plugin context (#36074)
* feat: include connection id in the plugin context

* refactor: group ConnectionId next to SessionId in plugin Context

Addresses review feedback to keep related identifier fields adjacent.

* fix(files): forward Connection-Id on file uploads to plugin hooks

The webapp uploadFile XHR didn't attach the Connection-Id header, so
FileWillBeUploaded plugin hooks always received an empty ConnectionId.
Read it from the websocket selector and set it on the request, matching
how drafts and channel bookmarks already do it. Adds a server-side test
asserting the connection id propagates through pluginContext.

* fix(lint): reorder file_actions imports to satisfy import/order

* Document ConnectionId on request.Context
2026-05-11 10:09:47 +02:00
yasser khan
b052f3463a
E2E/Playwright: balance shard timing by enabling fullyParallel in CI (#36054) 2026-05-08 21:04:32 +00:00
cursor[bot]
4a1fa5e2af
Fix autocomplete clipping when RHS is open (#36287)
* Fix autocomplete clipping beside RHS

Co-authored-by: Nick Misasi <nick13misasi@gmail.com>

* Address Copilot autocomplete findings

Co-authored-by: Nick Misasi <nick13misasi@gmail.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Nick Misasi <nick13misasi@gmail.com>
2026-05-08 13:54:14 -04:00
Miguel de la Cruz
40fe8782ef
Fix compact mode: consecutive bot reply header floating incorrectly in RHS (#36467)
* Fix compact mode: consecutive bot reply header floating incorrectly in RHS

MM-67419: In compact display mode, when a bot sends consecutive replies in
the RHS thread view, the .post__header floats incorrectly because the
global CSS rule in _post.scss gains higher specificity (7 classes) than
the ThreadViewer override (6 classes) when the post also carries .post--bot
and .same--user classes.

Fix: add an explicit .same--user.post--bot sub-selector inside the
.post-right__container / .ThreadViewer compact-reply block, raising the
override specificity to 8 classes so it correctly beats the global rule
and resets float to none.

Co-authored-by: Miguel de la Cruz <mgdelacroix@users.noreply.github.com>

* Remove redundant height/margin declarations from bot post-header override

The enclosing .post__header rule already sets height: auto and margin-left: 0;
the only property the global compact bot rule overrides is float: left, so
the new sub-selector only needs float: none to win the specificity contest.

Co-authored-by: Miguel de la Cruz <mgdelacroix@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Miguel de la Cruz <mgdelacroix@users.noreply.github.com>
2026-05-08 17:18:57 +02:00
Pablo Vélez
3c792a0535
MM-68433 - Fix DM/GM menu gating and header save in Channel Settings (#36213)
* MM-68433 - Fix DM/GM menu gating and header save in Channel Settings

* fix linter

* Avoid global role mutation in autotranslation DM e2e tests

* adjust menu item display based on config

* fix e2e tests

* Stabilize DM autotranslation Playwright menu/settings tests

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
2026-05-08 15:37:55 +02:00
Miguel de la Cruz
e7c517bc98
Fix modal title line-height regression (#36452)
* Fix modal title line-height regression introduced in MM-66442

The current inflated value for the modal's line-height causes
multi-line modal titles to overflow or be clipped. Restores the
original value and adds an e2e test to prevent future regressions.

* Improvements

---------

Co-authored-by: Miguel de la Cruz <miguel@ctrlz.es>
2026-05-08 13:19:41 +02:00
Miguel de la Cruz
6d30bff0a6
fix: use Blob with application/json type for client_perf sendBeacon (#36466)
When navigator.sendBeacon() is called with a plain string body, the
browser defaults to Content-Type: text/plain;charset=UTF-8. This
causes legitimate WAF alerts because the payload is JSON, not plain
text. Many deployments have been blocking users because of this
mismatch (MM-61530 / mattermost/mattermost#29101).

Fix: wrap the JSON string in a Blob with type 'application/json'
before passing it to sendBeacon. Also add the matching
Content-Type: application/json header to the fallback fetch call
that fires when sendBeacon returns false.

Tests: add three new focused tests in the
PerformanceReporter.sendReport content-type suite that verify:
1. sendBeacon receives a Blob with type application/json
2. The Blob's text content is valid JSON matching the report
3. The fallback fetch includes Content-Type: application/json
Also update the existing (currently skipped) tests to parse the
Blob body via FileReader instead of JSON.parse(string).

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Miguel de la Cruz <mgdelacroix@users.noreply.github.com>
2026-05-08 00:38:07 +02:00
Caleb Roseland
826c2cef0f
fix(bookmarks): disable DnD with one item; don't open menu without overflow (#36457) 2026-05-07 16:52:57 -05:00
Miguel de la Cruz
81f3af4738
MM-67904 Fix inflated count in search results Messages tab (#36465)
* MM-67904 Fix inflated count in search results Messages tab

The "Messages" counter in the search results RHS was rendering
`results.length`, but `results` is the array produced by
`makeAddDateSeparatorsForSearchResults`, which interleaves
date-line strings between posts (one per date group). A search
returning a single post therefore showed "2", and N posts spread
across D dates showed N+D.

Filter date-line strings out of `results` before computing the
counter so it reflects only the actual matching posts. File
results are unaffected.

Co-authored-by: Miguel de la Cruz <mgdelacroix@users.noreply.github.com>

* Address review feedback: simplify count predicate, drop unnecessary type casts in tests

- Count non-string entries in results directly. The Props type already
  declares results as Array<Post | string>, so any string entry is a
  separator; this is clearer than checking isDateLine and is more
  defensive against future marker strings.
- Drop the as any casts on the new test results props. The literals are
  assignable to Array<Post | string>, so the casts only suppressed
  type checking.

Co-authored-by: Miguel de la Cruz <mgdelacroix@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Miguel de la Cruz <mgdelacroix@users.noreply.github.com>
2026-05-07 19:47:19 +02:00
Devin Binnie
69fbaeced9
[MM-68496] Feature flag Managed Categories, expose Default Category Name to UI for channel creation and settings (#36289)
* [MM-68496] Feature flag Managed Categories, expose Default Category Name to UI for Channels

* PR feedback

* PR feedback

* Fix i18n

* Fix test

* Fix E2E

* Merge'd

* Add tests

* Re-add old tests (skipped)

* Add IncrementVersion to PropertyGroup store, increment version on managed category group

* Fix lint

* Fix mock

* Fix prettier

* Add tests

* Fixed issue when moving from existing category to existing category

* Fix e2e

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
2026-05-07 09:37:53 -04:00