* MM-68149: upgrade to Go 1.26.2
Update go directive in go.mod and .go-version.
* MM-68149: replace pointer helpers with Go 1.26 new()
Go 1.26 extends the built-in new() to accept an initial value expression,
making typed-pointer helpers like model.NewPointer(x), bToP(x), and boolPtr(x)
redundant. Replace every call site with new(x) and remove the now-unused
helper functions and their //go:fix inline directives.
* MM-68149: apply go fix for reflect API and format-string changes
- reflect.Ptr → reflect.Pointer (renamed in Go 1.18, deprecated alias removed in 1.26)
- reflect range-over-struct: for i := 0; i < t.NumField(); i++ → for field := range t.Fields()
and the equivalent for Methods() and interface types
- Fix format-string concatenation and variadic-arg mismatches flagged by go vet
* MM-68149: update JPEG fixtures and test infrastructure for Go 1.26 encoder
Go 1.26 ships a new image/jpeg encoder that produces slightly different output.
Regenerate all JPEG fixture files and switch the comparison helpers from
byte-equality to pixel-level comparison with a small per-channel tolerance,
so minor encoder drift across patch versions is handled automatically.
Add -update-fixtures flag to make it easy to regenerate fixtures after future
major Go upgrades. Document the update procedure in tests/README.md.
* MM-68149: CI check that go fix ./... produces no changes
* Fix real bugs flagged by CodeRabbit review
- group.go: set newGroup.MemberCount not group.MemberCount (member count
was populated on the wrong variable and lost before publish/return)
- file_test.go: guard compareImage(GetFilePreview) on the preview slice
length, not the thumbnail slice length (copy-paste error)
- config_test.go: remove duplicate MinimumLength assignment
* fixup! Fix real bugs flagged by CodeRabbit review
* wrap instead of embedding sqlx.DB
Expose helper methods that route to sqlx.DB instead of requiring callers
to sometimes access .DB directly for themselves. (We could rename this
to `.db` to emphasize that it's internal, but some callers legitimately
do need it, and it's all the same package so the diff just gets
noisier.)
This change continues to improve our ability to avoid queries without
configured timeouts, but does not yet directly address the original
report.
Relates-to: https://mattermost.atlassian.net/browse/MM-68332
* fix contradictory comment on sqlxTxWrapper.Query
* rename DB→db and Tx→tx; add DB() accessor
Make the sqlx.DB and sqlx.Tx fields unexported within the package to
signal they are internal, while exposing a DB() method for the cases
where callers need the sqlx handle directly.
* pipe passthrough errors through checkErr for offline detection
Ensure network failures in Query, ExecContext, and QueryContext methods
mark the replica offline, consistent with all other wrapper methods.
* fix config test: DB is now a method, not a field
* MM-68722 - Set higher statistics target on posts.rootid and posts.channelid
The default PostgreSQL column statistics target (100) is too coarse for
posts.rootid: most rows have an empty rootid and the remainder is a long
tail of distinct thread IDs, so the planner cannot accurately estimate
selectivity for a specific non-empty rootid. As a result, queries like
the per-thread MAX(createat) issued from updateThreadsFromPosts get
planned to scan idx_posts_create_at backward and filter by rootid,
scanning tens of millions of rows per call instead of using the
idx_posts_root_id_delete_at index. This was observed during a large DM
import where 16 workers were each stuck on the same query for 20 to 70
seconds, dropping import throughput from a few thousand posts per minute
to ~155 per minute.
Raising the statistics target to 5000 on rootid (and on channelid for
the same reason) lets ANALYZE record enough most-common-values that the
planner correctly recognizes specific non-empty values as highly
selective and picks the right index. Verified locally: post-fix the
query runs in 0.058 ms with 11 buffer hits, vs 20725 ms with 25.8M
buffer hits before.
This is a metadata-only change. ALTER TABLE ... SET STATISTICS takes a
SHARE UPDATE EXCLUSIVE lock and does not block concurrent DML.
* MM-68722 - Run ANALYZE in migration so new statistics target takes effect immediately
ALTER TABLE ... SET STATISTICS only changes the target; the planner keeps
using the existing sample in pg_statistic until ANALYZE runs. On a busy
Posts table autoanalyze fires after ~10 percent of rows change, and on a
quiet site it may not fire at all before the operator runs the import that
motivates this change. Running ANALYZE in the migration ensures the new
sample is collected at deploy time rather than at an indeterminate later
point.
Scoped to (rootid, channelid) since those are the only columns whose
statistics target changed. Both are gathered in a single table scan.
ANALYZE takes SHARE UPDATE EXCLUSIVE and does not block DML. No
corresponding change in the down migration: resetting the target to -1
leaves the existing samples valid for continued planner use, so no
rollback-time ANALYZE is needed.
The two shared DM/GM subtests in TestCreatePost rely on
FeatureFlags.EnableSharedChannelsDMs being false, but the config store
reapplies MM_FEATUREFLAGS_* env overrides on every Set, so an
UpdateConfig pin gets clobbered. Use t.Setenv to force the flag false
for the duration of each subtest, and drop the parent's
mainHelper.Parallel(t) so Go's "no Setenv under a parallel ancestor"
rule is satisfied. Sibling subtests still parallelize via their own
mainHelper.Parallel(t) calls.
* [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>
* 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>
* Fix flaky TestCreatePost upload_file subtests
The tests removed upload_file from the global channel_user role, which races
with other parallel api4 tests, and (for channel-scoped schemes) could not
actually revoke upload_file because non-moderated permissions merge from the
higher-scoped team channel role.
Use an isolated team with its own team scheme, revoke upload_file on that
scheme's channel user role, re-login after subtests that clear the client
session, and align UpdatePost file-permission cases.
Tests-only change. Verified with ENABLE_FULLY_PARALLEL_TESTS=true go test
-run '^TestCreatePost$' -race -count=100 ./channels/api4/...
Co-authored-by: Maria A Nunez <maria.nunez@mattermost.com>
* Add no-scheme TestCreatePost/TestUpdatePost upload_file subtests
The team-scheme isolation introduced earlier in this PR fixed the
flakiness that came from mutating the shared channel_user role from
parallel api4 tests, but it changed the scope under test from the
global default scheme to a team scheme. The original test from PR
#34538 was validating the no-scheme path, where the user's effective
channel role is the built-in channel_user.
Restore that coverage by adding two new subtests that isolate at the
channel-member level instead of at the role level. The new helper:
* creates a fresh channel inside th.BasicTeam (no team scheme, no
channel scheme);
* creates a unique non-scheme-managed role with channel_user's
default permissions minus upload_file;
* sets SchemeUser/SchemeAdmin/SchemeGuest=false and ExplicitRoles
to the custom role on the user's membership via the store, so the
built-in channel_user role is not merged into the effective role
set;
* invalidates GetAllChannelMembersForUser cache so
SessionHasPermissionToChannel sees the new roles.
upload_file is PermissionScopeChannel and is not granted by team_user,
team_admin, system_user, etc. (only by channel_user/channel_guest), so
removing it from the channel-member role is sufficient to deny the API
request without touching any process-shared state. The new subtests
are therefore safe under ENABLE_FULLY_PARALLEL_TESTS=true.
This keeps the team-scheme deny subtests added earlier in the PR as
extra coverage for the team-scheme path.
Co-authored-by: Maria A Nunez <maria.nunez@mattermost.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Only comment when action-junit-report reports no failing tests after retry
merging, so all-failure retries are not labeled flaky.
Remove skip/JIRA guidance from the comment body and use neutral wording
for the workflow run link.
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
* Add benchmarks for image transformation functions
Covers GeneratePreview, GenerateThumbnail, GenerateMiniPreviewImage,
FillCenter, and MakeImageUpright — all functions that delegate to the
external imaging library. Baseline before/after the library swap.
* Replace anthonynsimon/bild with boxes-ltd/imaging
Reverts the imaging library swap from PR #29657 (disintegration/imaging →
anthonynsimon/bild) and replaces it with github.com/boxes-ltd/imaging, the
maintained fork of disintegration/imaging with the same API.
- emoji.go: restore direct use of imaging.Fit with Lanczos filter
- orientation.go: restore FlipH/FlipV/Rotate90/180/270/Transpose/Transverse
- preview.go: restore imaging.Resize calls with Lanczos filter
- utils.go: remove bild-based Resize/Fit/CropCenter helpers; restore the
original FillCenter using imaging.Fill
- Remove tests and test images added for the bild-specific helpers
- Regenerate orientation test expected images (2,3,6,7,8) and GIF thumbnail
to match boxes-ltd/imaging output
https://claude.ai/code/session_012f5wLSCRQrQeRraPj282sT
* gofmt imaging package files
* Add tests and fixtures for the boxes-ltd/imaging-backed functions
Cover MakeImageUpright across all 8 EXIF orientations, GeneratePreview,
GenerateMiniPreviewImage, and FillCenter against fixtures regenerated
under the new library.
* Contain boxes-ltd/imaging behind the local imaging wrapper
Add a Fit wrapper alongside FillCenter and route emoji.go through the
local package so boxes-ltd/imaging is only imported from
channels/app/imaging.
* Add TestFit to cover the local Fit wrapper
Dimensional checks for the Fit wrapper used by emoji.go, mirroring
TestGenerateThumbnail. Pixel correctness is covered by the upstream
boxes-ltd/imaging tests; this guards against wrapper-level mistakes
(transposed args, wrong filter).
* Address CodeRabbit nits in TestFillCenter and TestFit
Decode a fresh source image per TestFillCenter subtest so cases stay
isolated even if the wrapper ever mutates input. Rename the TestFit
"smaller than bounds (clone)" case to "no resize when smaller than
bounds" since the assertion only checks dimensions, not clone semantics.
* Revert per-subtest decode in TestFillCenter
imaging.Fill never mutates its input — it always returns a fresh
*image.NRGBA — so re-decoding the source for every subtest was
unnecessary work. Decode once, share across subtests.
* Compare decoded pixels instead of raw PNG/JPEG bytes in tests
image/png isn't byte-stable across Go versions, so comparing
re-encoded byte streams against checked-in fixtures is brittle to
toolchain bumps and re-encoding. Decode both sides and compare RGBA
pixels via a shared requireSameImage helper. Fixtures stay on disk
unchanged.
Covers TestFillCenter, TestGeneratePreview, TestGenerateMiniPreviewImage,
and TestMakeImageUpright. TestFillImageTransparency is left alone since
its byte-comparison pattern predates this branch.
* Report total diff rate when requireSameImage fails
Walk every pixel before failing instead of stopping at the first
mismatch. The failure message now includes how many pixels differ, the
percentage of the image that's off, and the first divergence.
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Mattermost Build <build@mattermost.com>
* 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>
Wire Microsoft's local Azure Blob Storage emulator into the dev/CI
docker-compose stack so an upcoming Azure FileBackend driver and its
tests have a target to run against, without requiring an Azure
account.
* Define the azurite service in docker-compose.common.yml (used by
both the local-dev and CI compose files).
* Add azurite to the makefile + main docker-compose.yml service maps,
and to docker-compose-generator so callers can include it via
ENABLED_DOCKER_SERVICES.
* Auto-include azurite in `make start-docker` (mirrors how minio is
auto-included today), so existing local workflows keep working
without any per-developer config change.
* Add azurite to the CI start_dependencies wait set so CI brings it up
alongside postgres/minio.
* Set CI_AZURITE_HOST / CI_AZURITE_PORT in dotenv/test.env, mirroring
the CI_MINIO_* pattern.
No production filestore changes — this PR is mergeable in isolation
with no user-visible behavior.
------
AI assisted commit
* 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
* Update E2E test workflows to use context names and server images and bump playwright workers to 10
* refactor: update branch naming conventions in E2E test workflows for better aggregation
* MM-68705 - Make ReceiveSharedChannelAttachmentSyncMsg order tolerant
Allow plugin remotes to invoke ReceiveSharedChannelAttachmentSyncMsg
and ReceiveSharedChannelSyncMsg in either order without losing the
post/file binding, and make repeat deliveries of the same file id
idempotent.
Two localised changes inside ReceiveSharedChannelAttachmentSyncMsg:
- Idempotency check before CreateUploadSession. If a FileInfo with
the sender's id already exists for the same channel and creator,
return it instead of inserting a duplicate (which would violate
the FileInfo PK and force the caller to retry indefinitely after
any transient ack failure). A mismatched channel or creator on the
same id is rejected.
- Lazy bind to post after UploadData. When the matching post is
already present (post-then-file ordering), CreatePost will have
stripped the unmatched file id from Post.FileIds; AttachToPost
plus Post.Overwrite restore the binding. When the post is not
yet present (file-then-post ordering), the FileInfo is left
unbound so the eventual post arrival's CreatePost path binds it.
The post is fetched first because AttachToPost is a blind UPDATE
that does not validate post existence, so calling it before the
post exists would orphan the FileInfo.
No other paths change. Cluster (non-plugin) shared-channel attachments,
ReceiveSharedChannelProfileImageSyncMsg, and UI uploads are unaffected.
New tests in shared_channel_test.go cover both orderings, repeated
receive success and rejection on channel/creator mismatch, and the
empty-PostId no-op.
* 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>
* 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>
* Added base fr report generation
* WIP
* Refactoring and cleanup
* lint fixes, added new tests
* test fix
* Several improvements
* Addressed some security enhancements
* Created zip writer entery later
* Improved a test to check for file content
* Improved error handling
* Made a geneeric function
* accepting comment in report API
* Removed an unnecessary check
* Made a geneeric function
* Made the comment body not required and updated API docs
* 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>
* api4: block user managers from toggling bot active status without bot permissions
The PUT /api/v4/users/{id}/active endpoint only checked for
PermissionSysconsoleWriteUserManagementUsers and a special-case for system
admins, but had no equivalent guard for bot accounts.
This meant a User Manager with edit access to users but no access to
Integrations could deactivate (or reactivate) bot accounts — causing the
bot's sessions to be revoked and its tokens invalidated — even though every
dedicated bot endpoint (/api/v4/bots/{id}/disable, /enable, PATCH, etc.)
requires the caller to pass SessionHasPermissionToManageBot.
Fix: after fetching the target user and running the system-admin guard, add
an equivalent check for IsBot that delegates to the same
SessionHasPermissionToManageBot helper used by all other bot endpoints.
Fixes MM-68686
Co-authored-by: Miguel de la Cruz <mgdelacroix@users.noreply.github.com>
* api4: assert bot is inactive after deactivation in test
Co-authored-by: Miguel de la Cruz <mgdelacroix@users.noreply.github.com>
* api4: pin bot-deactivation test assertion to 404 and clarify comment
Co-authored-by: Miguel de la Cruz <mgdelacroix@users.noreply.github.com>
* api4: use require.Zero for DeleteAt assertion in bot test
Co-authored-by: Miguel de la Cruz <mgdelacroix@users.noreply.github.com>
* api4: fix err shadow in updateUserActive bot permission check
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>
Co-authored-by: Mattermost Build <build@mattermost.com>
* change retry to 1, fixed and disabled failed tests
* add v2 templates for Cypress and Playwright E2E tests with test system io integration
* add commenting to pr
* identify more playwrights to fix separately
* disable deletion-report.spec for separate fix
---------
Co-authored-by: Mattermost Build <build@mattermost.com>
Set ReqFileId on the UploadSession created in
ReceiveSharedChannelAttachmentSyncMsg so the attachment is persisted
under the sender's file ID. Without this, the receiving server stored
the bytes under a freshly generated ID while the synced post's FileIds
still referenced the sender's ID, leaving the attachment invisible in
the UI even though the file and FileInfo row existed on disk.
Mirrors the existing cluster-to-cluster path in
platform/services/sharedchannel/attachment.go.
Also tightens TestPluginAPIReceiveSharedChannelAttachmentSyncMsg to
pass a sender-side fi.Id and assert the saved FileInfo keeps it. The
prior assertion only checked that some ID was assigned, which the
buggy code also satisfied.
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>
* 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>
GetPreferencesForUser returns default preferences in non-deterministic order
under the race detector and Postgres, but the test asserted fixed slice
indices. Look up each default preference by category instead.
Tests-only change. Verified with go test -run '^TestPluginAPIUpdateUserPreferences$' -race -count=100 ./channels/app.
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Maria A Nunez <maria.nunez@mattermost.com>
* MM-68543 Invalidate active WebConn session cache on global session revocation
Mirrors the per-user revocation pattern (ClearUserSessionCache ->
ClearSessionCacheForUserSkipClusterSend -> hub fan-out) for the global
revocation path so that ClearAllUsersSessionCache invokes the same
local-side primitive on the originating node as the cluster handler
runs on remote nodes. Also covers single-node deployments where the
cluster broadcast was previously the only trigger of the WebConn
invalidation.
Adds a Hub.InvalidateAll fan-out primitive on the websocket hub and
two contract tests covering the SkipClusterSend variant and the
production RevokeSessionsFromAllUsers entry point.
Made-with: Cursor
* MM-68543 Restore error propagation on ClearAllUsersSessionCache
The previous commit moved the local-side work into
ClearSessionCacheForAllUsersSkipClusterSend, which returned no error,
so ClearAllUsersSessionCache started always returning nil even when the
underlying session-cache purge failed.
Make the helper return the cache-purge error and propagate it back
through ClearAllUsersSessionCache, restoring the historical error
contract for callers (RevokeSessionsFromAllUsers,
App.ClearSessionCacheForAllUsers, TestCache). The hub fan-out and the
cluster broadcast still run unconditionally so security invalidation
happens even on local-purge failure.
Made-with: Cursor
* MM-68543 Trim comments and fix unchecked errcheck on App wrapper
Address review feedback: trim verbose comments across the touched
files and check the error returned by ClearSessionCacheForAllUsersSkipClusterSend
in the App-level wrapper to fix the golangci-lint errcheck failure
introduced when the helper started returning an error.
Made-with: Cursor
* MM-68543 Wipe channel routing index instead of rebuilding it on global revoke
Rebuilding byChannelID per user via InvalidateCMCacheForUser issues a
GetAllChannelMembersForUser DB query for every user with a live conn
on the hub, which is wasted work when those conns have just been
invalidated. Replace it with a single clear() of byChannelID, hidden
behind a small clearChannels() helper. Index entries repopulate
naturally as conns re-handshake or fully reconnect.
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
* Split out buttonClassNames utility and use for most places Button isn't
* Update StartTrialBtn to use buttonClassNames
Ideally, we'd:
1. Use Button, but that requires sorting out the one case that overrides
btnClass entirely.
2. Use a button for all of these since none of these should have a link
role, but that's outside of the scope of this ticket.
* Update another new button to use Button
* Lower default test console log level from stdlog to debug
Suppresses trace-level log spam (e.g. MlvlNotificationTrace) that
flooded CI output. MM_LOGSETTINGS_CONSOLELEVEL still overrides for
local debugging.
* Fix TestEnvironmentVariableHandling to expect debug default
Updates the assertion to match the new default console log level.
* feat(color_input): migrate ColorInput to function component
* test(color_input): migrate tests from enzyme to react testing library
* test(color_input): remove obsolete snapshots
* test(color_input): update snapshots
* test(color_input): update test
* refactor(color_input): remove unnecessary state update in function body
* Revert "refactor(color_input): remove unnecessary state update in function body"
This reverts commit 2c7647a3e4.
* Fix ColorInput tests
* Simplify click outside handler
By changing the button to always show the picker instead of toggling it
and making it so that the click outside handler checks for clicks
outside of the whole ColorInput, we can get rid of the setTimeout and
the very specific timing needed for the click outside handler.
* Wrap handleColorChange in useCallback
* Update snapshot
---------
Co-authored-by: Mattermost Build <build@mattermost.com>
Co-authored-by: Harrison Healey <harrisonmhealey@gmail.com>
* Add initial version of Button
* Use Button in ConfirmModal
* Use Button in easy places that use className='btn btn-primary'
This is everywhere that I could just replace `<button className='btn
btn-primary'>` with `<Button emphasis='primary'>` (and some other
emphasis versions) without any additional changes. There's still more
places where this could be used which require more in-depth changes that
will be in a following commit.
* Use Button in place of divs with className='btn btn-primary'
This is a minor functional change because these elements are now
accessible.
* Use Button in SpinnerButton
This is removing some usage of a save-button CSS class
that doesn't seem to affect these components.
* Replace RB Button with our Button
There's a small functional change here because the copy button in the
header of the FullLogEventModal is now styled when it wasn't before.
* Use Button in many places which used btn-secondary, btn-tertiary, and btn-danger
This removes some CSS classes from some different elements, but as
elsewhere, those CSS classes don't actually do anything. I think some
might have had a purpose once, but there seems to be quite a few that
were copied around during previous, possibly AI-assisted refactors.
* Use Button in many places in System Console
Notably, this includes:
1. Cleaning up some complicated logic in PurchaseLink/RenewalLink for
determining their styling.
2. Making some minor functional changes in ChannelProfile/TeamProfile
because they didn't use standard CSS classes previously. The styles
mostly match a secondary button, but they had slightly different
padding and colours previously.
3. I also removed a workaround for an old issue with OverlayTrigger and
disabled buttons in favour of just using the disabled attribute. For
more information on the previous code, see
https://github.com/mattermost/mattermost-webapp/pull/10387. Based on
some brief testing, that's no longer needed.
* Use Button in MultiSelect and remove unneeded backButtonClass prop
Everything that used that prop either passed the tertiary class that
was the default or passed a class that didn't exist.
* Use Button in more places that used btn-primary/secondary/tertiary/quaternary
* Use Button in more places that used btn-danger
* Use Button for all buttons with a className starting with 'btn btn-...'
* Migrate anchors that really should've been buttons to Buttons
All of these are anchors with click handlers and the btn class, so
they'd appear as buttons anyway.
* Migrate SettingItemMax and SettingPicture to Button
* Use Button in BrowseChannels
* Use Button in TourTip
* Migrate GenericModal to Button
There's a minor UX change due to the old `delete` class having a slightly
different colour from `btn-danger`, but I think that was from an older
version of the default themes.
Ideally, we'd remove the `GenericModal__button`, `confirm`, and `delete`
classes from the buttons on that modal, but doing that would require
changes to a large number of E2E tests that I'd rather not do now.
* Change order of building packages in postinstall
* Fix move_thread E2E tests
* Coderabbit feedback
* Address feedback
* Add JSDoc comments and remove width prop
I don't think we need this since this should be set by a parent with
`display: flex`, so I'm not going to add it to the Button.
* Share Button with plugins