mirror of
https://github.com/mattermost/mattermost.git
synced 2026-09-24 16:05:00 +08:00
2d8a5f94baa48be310aecb357d8b7b794d0e1237
694
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
51a2dbf1b9 |
E2E/Playwright: Complete Rainforest browser test migration (batch 7, 121-142) (#37453)
* E2E/Playwright: Migrate RFQA browser tests (batch 4, 61-80) Migrate the fourth batch of Rainforest QA browser tests into Playwright (migration plan None-core #34-53, keys MM-T480..MM-T1257): 17 new/covered specs across notifications, search, channel_settings, sidebar_left, keyboard_shortcuts, and direct_messages_modal, plus 3 duplicate keys folded into existing tests (MM-T480, MM-T1256, MM-T1257). POM/infra: add a ChannelMenu page object for the channel header dropdown, an EditChannelHeaderModal, a header field on the channel-settings info tab, a channel-wide-mentions checkbox on NotificationsSettings, a getConfirmModal helper, and a clickNotification browser-API mock helper. Give the channel header menu and the confirm modal proper accessible names so they can be targeted semantically. Notification specs run on all browsers now that the Notification API stub works headless on Chromium and Firefox. * E2E/Playwright: Migrate RFQA browser tests (batch 5, 81-100) Migrate the fifth batch of Rainforest QA browser tests into Playwright across keyboard_shortcuts, search, archived_channels, channel_settings, plugin_marketplace, messaging, and emoji_picker (keys MM-T1247..MM-T2365), folding duplicate coverage into existing keyboard-shortcut specs and documenting skipped cases inline. POM/infra: add AddPeopleToChannelModal and MarketplaceModal page objects, manage/add member buttons on the channel members RHS, and an App Marketplace entry on the global header; target the search "Jump" link through the existing SearchResultsPanel POM. Also fix a webapp bug where a post body disappeared when an inline edit was cancelled mid-animation (found via the up-arrow edit shortcut spec). * E2E/Playwright: Migrate RFQA browser tests (batch 6, 101-120) Migrate the sixth batch of Rainforest QA browser tests into Playwright (migration plan None-core #74-93, keys MM-T2547..MM-T5604) across multi_team, channel_settings, system_console, keyboard_shortcuts, search, plugin_marketplace, messaging, channel_bookmarks, and custom_groups. Fold duplicate coverage into existing specs (MM-T3680 into the marketplace spec; MM-T4872 is already covered by the batch-5 search-prefill spec) and document the plugin-install skip (MM-T4023, same external-download limitation as MM-T1987). POM/infra: add a ChannelBookmarksCreateModal page object and Bookmarks Bar submenu actions on the ChannelMenu, plus a channel-bookmarks-bar locator and bookmark-create-modal on ChannelsPage. * E2E/Playwright: Fail on missing scroll bounding boxes * E2E/Playwright: Locate user group dialog semantically * E2E/Playwright: Address batch 6 review feedback * E2E/Playwright: Locate user group rows semantically * E2E/Playwright: Complete Rainforest migration batch 7 * CI: Rerun flaky webapp unit test * E2E/Playwright: Keep batch 7 test data isolated * E2E/Playwright: Group related batch 7 specs * E2E/Playwright: Address batch 7 review feedback * E2E/Playwright: Use bookmark bar POM in grouped spec * add method to retrieve all bookmark links and update tests for bookmark order verification --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> |
||
|
|
bd0d8866d6 |
Remove deprecated Playwright/Cypress v1 dispatch (#37413)
* Remove deprecated Playwright/Cypress v1 e2e CI dispatch Deletes the legacy in-job execution templates and their calculate-results actions, and unconditionally routes both wrappers to the v2 (Test System IO) templates. Test suites and local-dev tooling are untouched. * remove v2 references * remove aws dependencies in e2e tests, remove deprecated workflows |
||
|
|
d628dbc0ec |
E2E/Playwright: Migrate RFQA browser tests (batch 6, 101-120) (#37431)
* E2E/Playwright: Migrate RFQA browser tests (batch 4, 61-80) Migrate the fourth batch of Rainforest QA browser tests into Playwright (migration plan None-core #34-53, keys MM-T480..MM-T1257): 17 new/covered specs across notifications, search, channel_settings, sidebar_left, keyboard_shortcuts, and direct_messages_modal, plus 3 duplicate keys folded into existing tests (MM-T480, MM-T1256, MM-T1257). POM/infra: add a ChannelMenu page object for the channel header dropdown, an EditChannelHeaderModal, a header field on the channel-settings info tab, a channel-wide-mentions checkbox on NotificationsSettings, a getConfirmModal helper, and a clickNotification browser-API mock helper. Give the channel header menu and the confirm modal proper accessible names so they can be targeted semantically. Notification specs run on all browsers now that the Notification API stub works headless on Chromium and Firefox. * E2E/Playwright: Migrate RFQA browser tests (batch 5, 81-100) Migrate the fifth batch of Rainforest QA browser tests into Playwright across keyboard_shortcuts, search, archived_channels, channel_settings, plugin_marketplace, messaging, and emoji_picker (keys MM-T1247..MM-T2365), folding duplicate coverage into existing keyboard-shortcut specs and documenting skipped cases inline. POM/infra: add AddPeopleToChannelModal and MarketplaceModal page objects, manage/add member buttons on the channel members RHS, and an App Marketplace entry on the global header; target the search "Jump" link through the existing SearchResultsPanel POM. Also fix a webapp bug where a post body disappeared when an inline edit was cancelled mid-animation (found via the up-arrow edit shortcut spec). * E2E/Playwright: Migrate RFQA browser tests (batch 6, 101-120) Migrate the sixth batch of Rainforest QA browser tests into Playwright (migration plan None-core #74-93, keys MM-T2547..MM-T5604) across multi_team, channel_settings, system_console, keyboard_shortcuts, search, plugin_marketplace, messaging, channel_bookmarks, and custom_groups. Fold duplicate coverage into existing specs (MM-T3680 into the marketplace spec; MM-T4872 is already covered by the batch-5 search-prefill spec) and document the plugin-install skip (MM-T4023, same external-download limitation as MM-T1987). POM/infra: add a ChannelBookmarksCreateModal page object and Bookmarks Bar submenu actions on the ChannelMenu, plus a channel-bookmarks-bar locator and bookmark-create-modal on ChannelsPage. * E2E/Playwright: Fail on missing scroll bounding boxes * E2E/Playwright: Locate user group dialog semantically * E2E/Playwright: Address batch 6 review feedback * E2E/Playwright: Locate user group rows semantically * E2E/Playwright: Group related batch 6 specs --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> |
||
|
|
7748bf749e |
E2E/Playwright: Migrate RFQA browser tests (batch 5, 81-100) (#37417)
* E2E/Playwright: Migrate RFQA browser tests (batch 4, 61-80) Migrate the fourth batch of Rainforest QA browser tests into Playwright (migration plan None-core #34-53, keys MM-T480..MM-T1257): 17 new/covered specs across notifications, search, channel_settings, sidebar_left, keyboard_shortcuts, and direct_messages_modal, plus 3 duplicate keys folded into existing tests (MM-T480, MM-T1256, MM-T1257). POM/infra: add a ChannelMenu page object for the channel header dropdown, an EditChannelHeaderModal, a header field on the channel-settings info tab, a channel-wide-mentions checkbox on NotificationsSettings, a getConfirmModal helper, and a clickNotification browser-API mock helper. Give the channel header menu and the confirm modal proper accessible names so they can be targeted semantically. Notification specs run on all browsers now that the Notification API stub works headless on Chromium and Firefox. * E2E/Playwright: Migrate RFQA browser tests (batch 5, 81-100) Migrate the fifth batch of Rainforest QA browser tests into Playwright across keyboard_shortcuts, search, archived_channels, channel_settings, plugin_marketplace, messaging, and emoji_picker (keys MM-T1247..MM-T2365), folding duplicate coverage into existing keyboard-shortcut specs and documenting skipped cases inline. POM/infra: add AddPeopleToChannelModal and MarketplaceModal page objects, manage/add member buttons on the channel members RHS, and an App Marketplace entry on the global header; target the search "Jump" link through the existing SearchResultsPanel POM. Also fix a webapp bug where a post body disappeared when an inline edit was cancelled mid-animation (found via the up-arrow edit shortcut spec). * E2E/Playwright: Fail on missing scroll bounding boxes * E2E/Playwright: Group related batch 5 specs * E2E/Playwright: Avoid duplicate creator membership * E2E/Playwright: Group Rainforest batches 1 through 4 --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> |
||
|
|
17466f3638 |
E2E/Playwright: Migrate RFQA browser tests (batch 4, 61-80) (#37411)
Migrate the fourth batch of Rainforest QA browser tests into Playwright (migration plan None-core #34-53, keys MM-T480..MM-T1257): 17 new/covered specs across notifications, search, channel_settings, sidebar_left, keyboard_shortcuts, and direct_messages_modal, plus 3 duplicate keys folded into existing tests (MM-T480, MM-T1256, MM-T1257). POM/infra: add a ChannelMenu page object for the channel header dropdown, an EditChannelHeaderModal, a header field on the channel-settings info tab, a channel-wide-mentions checkbox on NotificationsSettings, a getConfirmModal helper, and a clickNotification browser-API mock helper. Give the channel header menu and the confirm modal proper accessible names so they can be targeted semantically. Notification specs run on all browsers now that the Notification API stub works headless on Chromium and Firefox. Co-authored-by: Cursor Agent <cursoragent@cursor.com> |
||
|
|
cce485f605 |
[MM-69561] Add ability to rotate (regenerate) Personal Access Tokens (#37295)
* MM-69561: Add ability to rotate (regenerate) Personal Access Tokens - Add UpdateTokenRotate to UserAccessTokenStore interface and implement in sqlstore: deletes sessions on the old secret, then updates the token row with the new secret and expiry in one transaction - Regenerate store retrylayer, timerlayer, and mocks - Add RotateUserAccessToken app method: validates expiry (bot-exempt), captures old session for cache eviction, generates new secret, and sends a notification email - Register POST /api/v4/users/tokens/rotate handler with full permission checks (create_user_access_token + edit_other_users + manage_system for sysadmin targets); rejects OAuth sessions and disabled tokens - Add RotateUserAccessToken to the Go client (client4.go) - Add storetest covering secret rotation and old-session cleanup - Add API4 tests: happy path, permission denials, OAuth rejection, and max-lifetime enforcement Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * MM-69561: Add dedicated rotate email and i18n strings - Add SendUserAccessTokenRotatedEmail (subject/body distinct from the 'added' email so users aren't confused by a rotation event) - Add SendUserAccessTokenRotatedEmail to ServiceInterface + mock - Add en.json strings for the rotate email and the two new error ids (rotate.app_error, disabled_token.app_error) - Switch RotateUserAccessToken to call SendUserAccessTokenRotatedEmail Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * MM-69561: Add mmctl token rotate subcommand - Add RotateUserAccessToken to the mmctl Client interface and mock - Add 'mmctl token rotate <token-id> [--expires-in <duration>]' command reusing the existing resolveTokenExpiry/parseExpiresIn helpers from 'generate'; prints the new secret once on success - Add unit tests: happy path, --expires-in passed through, server error, invalid --expires-in Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * MM-69561: Regenerate mmctl docs for token rotate Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * MM-69561: Add API docs for POST /users/tokens/rotate Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * MM-69561: Fix i18n string ordering after extract Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * MM-69561: Add missing API4 test cases for token rotate Cover the three untested access-control branches flagged by the test analysis bot: - Rotating a disabled token returns 400 - Non-system-admin rotating a sysadmin's token returns 403 - Rotating a remote user's token returns 403 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * MM-69561: Address review comments - Fix handler authorization order: check SessionHasPermissionToUserOrBot and manage_system before IsRemote/IsActive to avoid leaking token state to unauthorized callers; matches revokeUserAccessToken/disableUserAccessToken - Fix API docs minimum server version: 10.8 -> 10.10 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * MM-69561: Restore i18n strings accidentally deleted by extract The earlier i18n-extract run stripped ~164 unrelated translation keys (mostly enterprise-only strings like app.pap.* and api.ldap.*) because the enterprise codebase isn't present in this checkout, so the extractor treated them as unused. Restore them while keeping the 5 new keys added for token rotation. * comment * [MM-69561] Add webapp Regenerate option for Personal Access Tokens Adds a "Regenerate" link to Account Settings > Security > Personal Access Tokens that calls the POST /users/tokens/rotate endpoint added in the server-side rotate PAT work. Regenerating shows a confirmation modal naming the token, then reveals the new secret via the existing one-time-copy flow used for token creation. - webapp Client4.rotateUserAccessToken - mattermost-redux rotateUserAccessToken action - Regenerate link/confirm modal/reveal flow in user_access_token_section - i18n strings - Playwright e2e coverage * Fix regenerate PAT e2e test: confirm modal is not nested in the Profile dialog ConfirmModal renders via react-bootstrap's Modal, which portals to document.body as a sibling of the Profile dialog rather than a descendant, so it must be located via #confirmModal on the page instead of scoped to the Profile dialog locator. * Let users pick a new expiry when regenerating a Personal Access Token Previously, regenerating a token always called rotateUserAccessToken with no expiresAt, so the rotated secret never expired even if the original token did. The Regenerate confirmation modal now includes the same expiry picker used by token creation (extracted into a shared renderExpiryPicker helper), enforces MaximumPersonalAccessTokenLifetimeDays the same way, and disables the confirm button until a valid expiry is selected. * Scope the red background in the Regenerate modal to the warning text only The confirmation question, expiry picker, and its hints were sitting inside the same alert-danger box as the warning, making the whole modal read as an error. Only the warning paragraph keeps the red background now. * Move the regenerate confirmation question below the expiry picker * Align rotate-token wording with UI: use 'regenerate/regenerated' Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * [MM-69561] rename pat_expiry_notify job to notify_expiring_access_tokens Unifies naming with the sibling cleanup_expired_access_tokens job and fixes the "expiry" vs "expiring" ambiguity: this job warns about tokens approaching expiry, not ones that have already expired. Safe to rename outright since the job hasn't shipped yet. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * [MM-69561] remove dead session lookup from EnableUserAccessToken The GetSessionContext call and its result were never used: both branches returned nil regardless. Leftover from mirroring DisableUserAccessToken's shape, which does use its session (to revoke it) unlike Enable. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * [MM-69561] rename remaining PAT identifiers to match AccessToken convention The job-level rename (pat_expiry_notify -> notify_expiring_access_tokens) left the app-layer function and its helpers using the old PAT/ PersonalAccessToken naming. Rename them to match: - NotifyPersonalAccessTokensExpiring -> NotifyExpiringAccessTokens - patExpiryBucket -> accessTokenExpiryBucket - sendPATExpiryNotification -> sendAccessTokenExpiryNotification - patExpiryNotifyBatchLimit -> expiringAccessTokenBatchLimit - patExpiryThresholds -> expiringAccessTokenThresholds - maxPersonalAccessTokenExpiry -> maxUserAccessTokenExpiry Also reword the package doc on notify_expiring_access_tokens, which no longer needs to explain a PAT/UserAccessToken naming split now that the app-layer method matches the job name. Pure rename, no behavior change. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
09bda773d8 |
MM-69585: remove AttributeBasedAccessControl feature flag (#37366)
* MM-69585: remove AttributeBasedAccessControl feature flag * Gate channel ABAC UI on EnableAttributeBasedAccessControl config |
||
|
|
6619448fec | [MM-69589] Remove ExperimentalAuditSettingsSystemConsoleUI feature flag (#37385) | ||
|
|
0d7ae8e58d |
Add file upload element to interactive dialogs (#36881)
* Add file upload element to interactive dialogs
Adds a new file element type to interactive dialogs, letting users
upload files in a dialog and forward the file IDs to the integration.
Server:
- model: new file DialogElement type with validation, AllowMultiple
field, and SubmitDialogRequest.FileIds.
- SubmitInteractiveDialog validates submitted file IDs (existence +
ownership) from both file_ids and any file IDs referenced in
submission values; bounded and batched.
- client4.getFileInfo / Client4.GetFileInfo.
Webapp:
- AppsFormFileUpload component: upload, progress, removal, and
hydration of pre-set file IDs; single vs allow_multiple selection.
- Wired into the dialog -> apps-form conversion (file field type).
- Submit is blocked while any field has an upload in progress
(per-field pending tracking).
Tests:
- Go unit tests for model + submit-time file-ID validation.
- Jest tests for the upload component.
- Cypress e2e spec (file_upload_spec.js) + webhook fixtures.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* coderabbit review fixes, linter fixes
* update openAPI spec for file upload
* revert changes to package-lock.json
* review fixes, add correct ids to E2Etests
* fix dryrun security issue
* lint fixes
* Address dialog file upload review feedback and UI file cap
* test fixes
* add several unit tests
* lint fix
---------
Co-authored-by: Scott Bishel <sbishel@ScottsFderalMac.home.local>
|
||
|
|
ca25611b0c |
MM-69219: Add multiple concurrent dialogs via action_button element type (#37119)
* Add multiple concurrent dialogs support with action_button element type Enable plugins to open child dialogs from within an existing dialog via a new action_button dialog element and POST /actions/dialogs/execute endpoint. Parent dialogs stay open while children stack (cap of 3). Dialog handlers derive the team permission and forwarded team from the server-loaded channel, not the client-supplied TeamId. * update docs, code rabbit review fixes * update comment per coderabbit * fix tests * increase test coverage * fix bad merge * Replace PostActionAPIResponse with ExecuteDialogActionResponse; replace single-dialog Redux slot with dialogs map --------- Co-authored-by: Mattermost Build <build@mattermost.com> |
||
|
|
a6060f5d05 |
MM-68754: Add silent post delivery for bots and integrations (#36771)
* MM-68754: Add silent post delivery for bots and integrations Bot, OAuth, incoming webhook, and plugin posts can request silent delivery via ?silent=true (REST), silent:true (webhook payload), or silent_notification:true (plugin Props). Silent posts are visible in the channel but produce no notifications, unread, or New Messages line. force_notification overrides silent. Non-integration senders requesting silent receive HTTP 403. Also tightens SanitizeProps to strip from_webhook, from_bot, from_oauth_app, from_plugin, force_notification, and silent_notification from client input. These props are now set server-side based on session and entry-point flags, preventing identity spoofing. Legitimate callers see no behavior change since the server already controlled these props at the response shape; the hardening only affects callers attempting to forge them. * Drop redundant prop-bag silent_notification path from webhooks * Address CodeRabbit feedback + rebase test fixup * Update tests to use CreatePostFlags.FromIncomingWebhook instead of forging from_webhook prop * update api documentation * test fixes * added additional tests * review fixes, update comments * code review changes, fix test * fix formatting issues * fix lint errors * avoid backward compatibility issues, by no longer stripping the Post properties. will add them back in v12 when breaking changes are allowed --------- Co-authored-by: Mattermost Build <build@mattermost.com> |
||
|
|
befdb0175a |
Stop leaking message body via the Notifications API tag (#36364)
* Stop leaking message body via the Notifications API tag showNotification was passing the rendered chat body as the Web Notifications API tag option. On Chromium-based browsers (Chrome, Edge, Brave), the tag is serialised into the notification-activation command line via the --notification-launch-id argument, where endpoint detection tooling such as CrowdStrike Falcon FDR, Microsoft Defender for Endpoint, and Sysmon Event ID 1 captures the full process-start command line and forwards it to the customer's SIEM. That meant private message content (including incident-response messages, credentials accidentally pasted into chat, and customer PII) was being copied into telemetry pipelines that were never in scope to receive it. Use the title - which already carries only the sender / channel context - as the tag instead. As a side benefit this is closer to the spec-intended use of tag: subsequent notifications from the same conversation now replace the prior one rather than stacking. Add a regression test covering the leak: the test pushes a body with a plausible secret pattern (token=AKIA-...) and asserts the tag never echoes any of it. Signed-off-by: Vishal Kumar Singh <vishal.kr.singh2021@gmail.com> * Allow callers to pass an explicit notification tag Threads channelId through dispatchNotification so per-conversation notifications coalesce by a stable opaque id rather than the user-visible title. The title remains as a safe fallback when callers do not supply a tag, preserving the existing behaviour for the session-expired notification emitted from login.tsx where no channel context exists. Signed-off-by: Vishal Kumar Singh <vishal.kr.singh2021@gmail.com> * fix: explain desktop notification path * Avoid title fallback for notification tags Signed-off-by: Vishal Kumar Singh <vishal.kr.singh2021@gmail.com> * test: align notification action payload expectations Signed-off-by: Vishal Kumar Singh <vishal.kr.singh2021@gmail.com> * test: align notification tag e2e expectation --------- Signed-off-by: Vishal Kumar Singh <vishal.kr.singh2021@gmail.com> Co-authored-by: Mattermost Build <build@mattermost.com> |
||
|
|
49b7406ad7 |
Add Playwright E2E test for maximum login attempts lockout (#36932)
Tests that a user account is locked after exceeding the configured MaximumLoginAttempts limit and can be unlocked via the admin API. Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Mattermost Build <build@mattermost.com> |
||
|
|
f0abe8a596 |
[MM-69591] Remove WebSocketEventScope feature flag (#37384)
* Remove WebSocketEventScope feature flag gating on server Leave the typing/reaction WebSocket event scoping permanently enabled. Co-authored-by: mattermost-code <matty-code@mattermost.com> * Remove WebSocketEventScope feature flag usage in webapp Always update the active channel/team/thread over the WebSocket so the event scoping stays permanently enabled. Co-authored-by: mattermost-code <matty-code@mattermost.com> * Remove WebSocketEventScope feature flag from e2e default config 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> Co-authored-by: Jesse Hallam <lieut-data@users.noreply.github.com> |
||
|
|
af43bfdbb0 |
[MM-69593] Remove StreamlinedMarketplace feature flag (#37390)
* Remove StreamlinedMarketplace feature flag definition Co-authored-by: mattermost-code <matty-code@mattermost.com> * Remove StreamlinedMarketplace feature flag from webapp The streamlined marketplace UI is now the permanent behavior. Remove the selector, the legacy tabbed/search branch of the marketplace modal, and update the affected tests and snapshots. Co-authored-by: mattermost-code <matty-code@mattermost.com> * Remove obsolete StreamlinedMarketplace feature flag guard in cypress spec Co-authored-by: mattermost-code <matty-code@mattermost.com> * Remove unused marketplace i18n strings after flag removal Co-authored-by: mattermost-code <matty-code@mattermost.com> * Clamp marketplace pagination when listing shrinks When fetchListing() or plugin-status refetches reduce the listing size, keep the current page within the last valid page so users are not left on an empty view with no pagination footer. 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> |
||
|
|
7870605fb1 |
[MM-69590] Remove NotificationMonitoring feature flag (#37386)
* [MM-69590] Remove NotificationMonitoring feature flag The NotificationMonitoring feature flag shipped and defaulted true in v9.9. Remove the flag and all conditional gating so notification delivery metrics collection is permanently enabled, gated only by the MetricsSettings.EnableNotificationMetrics admin setting. Co-authored-by: mattermost-code <matty-code@mattermost.com> * [MM-69590] Cover notification metrics client config Assert EnableNotificationMetrics client config prop tracks the MetricsSettings.EnableNotificationMetrics admin setting now that the NotificationMonitoring feature flag gate is removed. Co-authored-by: mattermost-code <matty-code@mattermost.com> * [MM-69590] Cover notification counter gating Add app-layer coverage asserting CountNotification increments the notification counter only when MetricsSettings.EnableNotificationMetrics is set, exercising the un-gated notificationMetricsDisabled path. Co-authored-by: mattermost-code <matty-code@mattermost.com> * [MM-69590] Cover websocket notification counter gating Assert the websocket notification counter increments via the posted-ack broadcast hook only when MetricsSettings.EnableNotificationMetrics is set, exercising the un-gated incrementWebsocketCounter path. Co-authored-by: mattermost-code <matty-code@mattermost.com> * Address PR feedback: 0 answered, 1 resolved, 0 declined Document that MetricsSettings.EnableNotificationMetrics must be set to true for notification monitoring, matching the code gating and the push-notification-health-targets doc. --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: mattermost-code <matty-code@mattermost.com> |
||
|
|
fe7fd4ebec | SEC-10721 E2E/Playwright: Migrate RFQA browser tests (batch 3, 41-60) (#37380) | ||
|
|
147777a8c6 | SEC-10588 E2E/Playwright: Migrate RFQA browser tests (batch 2, 21-40) (#37375) | ||
|
|
02d770d64b | SEC-10587 E2E/Playwright: Migrate RFQA browser tests (batch 1, 1-20) (#37352) | ||
|
|
8fa7e72a6e |
E2E/Playwright: Reorg POM using accessibility locators (#37315)
* Use semantic locators in Playwright POM * Refactor test IDs for badges and modals to use more descriptive names * remove unused field-with-error |
||
|
|
87b7433d2d |
E2E/Cypress: Upgrade cypress to 15.18 and its deps (#37278)
* chore: cypress upgrade to 15.18 and its deps * handle non-zero exit |
||
|
|
68389fabbb | MM-69466: re-fetch admin config on config_changed to prevent concurrent save clobber (#37338) | ||
|
|
076370e690 |
MM-67412: System Console — Board Attributes screen (PSAv2-based) (#36518)
Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Mattermost Build <build@mattermost.com> |
||
|
|
ef60931ab9 |
[MM-69075] Revoke non-compliant personal access tokens (#37030)
* [MM-68421] Frontend: PAT creation UI — expiry picker and status display
Wires the webapp UI to the server-side support added in PR #36706 (and
the MM-68419 model changes):
- Extends UserAccessToken type with expires_at, and ClientConfig with
EnforcePersonalAccessTokenExpiry / MaximumPersonalAccessTokenLifetimeDays.
- Threads expires_at through Client4.createUserAccessToken and the
mattermost-redux createUserAccessToken action.
- Adds a date/time picker to the PAT creation form (reuses
DateTimePickerModal). Honors enforcement and clamps to the
max-lifetime setting; maps server error ids
(expires_at_required/in_past/too_far) to localized messages.
- Displays expiry, derived status badge (active/expired/disabled), and
an approaching-expiry warning (<7 days) in the account settings token
list. Mirrors expiry + status in the admin Manage Tokens modal.
- Adds the supporting i18n keys.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* [MM-68421] Address review: i18n, ServerError type, scss, explicit guards
- Inject intl so the "Expires in N days" tooltip and the picker
ariaLabel are localized instead of hard-coded English.
- Use the canonical ServerError type from @mattermost/types/errors
instead of an ad-hoc inline cast.
- Dedupe the new i18n ids — keep a single "Expires: " string per
namespace and drop the duplicates introduced in the first pass.
- Add scss for setting-box__token-expiry / __token-status /
__token-expiry-warning so the new status pill and warning render
with the expected styling.
- Replace truthy checks on the numeric expiresAt with explicit
> 0 comparisons for readability.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* [MM-68421] Replace expiry datetime picker with preset chooser + custom date
Per UX discussion: PATs are long-lived so sub-day precision is noise.
Swap the DateTimePickerModal for a native <select> of presets
(No expiry, 7d, 30d, 90d, 1 year, Custom date) with a date-only
<input type="date"> revealed when Custom is selected. Effective time
is end-of-local-day, which matches how users think about expiry.
- Drops the DateTimePickerModal import and the picker open/close
handlers; removes the moment-timezone import.
- Adds isPresetAllowed() that hides presets exceeding
MaximumPersonalAccessTokenLifetimeDays, and a defaultExpiryPreset()
that picks 30d (then 7d, then Custom) when enforcement is on,
No expiry otherwise.
- The custom <input type="date"> uses min=today and max=now+maxDays
for native bounds; submit-time validation still maps server error
ids if the user bypasses the bounds.
- i18n: adds preset labels; drops the now-unused picker/clear/change
strings.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* [MM-68421] Fix CI: playwright config and ESLint blank line
- Add EnforcePersonalAccessTokenExpiry / MaximumPersonalAccessTokenLifetimeDays
to e2e-tests/playwright/lib/src/server/default_config.ts so its tsc -b
matches the updated ServiceSettings shape.
- Drop a stray double blank line in user_access_token_section.tsx that
tripped no-multiple-empty-lines.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* [MM-68421] Sort i18n keys to match formatjs extract output
ci/i18n-extract diffs en.json against the formatjs extractor's sorted
output and fails on any difference. Re-run the extract so the new
PAT-expiry keys land in alphabetical position.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* [MM-68421] Address CodeRabbit findings
- Clamp the default custom-expiry date to maxLifetimeDays when set
so the form doesn't open in an invalid state when
defaultExpiryPreset() falls back to 'custom'.
- Reject a cleared/empty custom date with expires_at_required
instead of silently submitting without an expiry; only forward
expiresAt to the action when it's > 0.
- Use an explicit undefined check in Client4.createUserAccessToken
so an intentional 0 isn't dropped from the request body.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* [MM-68421] Update manage_tokens_modal snapshot for expiry + status row
The admin token list now renders an Expires row and a status badge per
token; refresh the jest snapshot.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* [MM-68421] Add unit tests for PAT expiry helpers
Per the PR Test Analysis advisory: export the pure helpers from
user_access_token_section.tsx and add unit tests covering them.
Coverage:
- deriveTokenStatus: active / expired / inactive branches.
- mapServerErrorIdToMessage: all three server error ids (short and
api.user.create_user_access_token.*.app_error variants) and the
default null path.
- endOfLocalDayPlusDays: end-of-day on the Nth future day, 0 days.
- endOfLocalDayFromIsoDate: valid ISO date and malformed inputs.
- PRESET_DAYS: snapshot of the preset durations.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* [MM-68421] Freeze time in PAT helper tests to avoid midnight flake
The date arithmetic helpers (Date.now, new Date()) could disagree
across a midnight boundary, making the tests theoretically flaky.
Pin system time to a stable mid-day in 2026 via jest.useFakeTimers.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* [MM-68421] Add component tests for PAT expiry creation UI
Covers the create-form validation branches (missing description, empty
custom date, past date, beyond maxLifetimeDays), enforceExpiry rendering
(no-expiry option hidden + enforced hint), maxLifetimeDays preset
filtering, and token-list status display (active/expired/disabled, never,
and the "expires soon" warning).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [MM-68421] Add behavioral status/expiry tests for manage_tokens_modal
Covers the admin token modal's derived status display: Active + "Never"
for an active token without expiry, Expired for an active token past its
expiry, Disabled for an inactive token regardless of expiry, and Active
with a rendered date (not "Never") for a token expiring in the future.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [MM-68421] Align PAT expiry UI with shipped server contract
The server (#36706) did not ship a separate EnforcePersonalAccessTokenExpiry
flag — expiry enforcement is implied by MaximumPersonalAccessTokenLifetimeDays
> 0. Two webapp gaps surfaced once the server side merged:
- enforceExpiry was read from the never-sent config.EnforcePersonalAccessToken
Expiry, so the "hide No-expiry / require expiry" path was dead. Derive it from
maxLifetimeDays > 0 instead and drop the dead config flag from the component,
redux props, ClientConfig/ServiceSettings types, and the e2e default config.
- The server returns app.user_access_token.expires_at_{required,in_past,too_far}
.app_error, but mapServerErrorIdToMessage matched the api.user.create_user_
access_token.* namespace, so the localized errors never fired. Map the actual
ids.
Unit tests updated accordingly.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [MM-68421] Add Playwright e2e for PAT expiry UI
Covers, against a real server, the personal access token expiry surfaces in
Account Settings > Security:
- the expiry picker renders all presets and reveals the custom-date input
- a custom expiry with no date is blocked client-side
- MaximumPersonalAccessTokenLifetimeDays > 0 hides "No expiry" and oversized
presets, shows the enforced hint, and rejects an over-the-limit custom date
- the token list shows Active/Never, an "expires in N days" warning, and the
Disabled badge (seeded via the API)
The expired-status badge is left to the component unit tests since the server
rejects creating a token whose expiry is already in the past.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [MM-68421] Use locator('option') for native select assertions
getByRole('option') does not reliably match the options of a closed native
<select>, which would make the absence assertions (toHaveCount(0)) pass
vacuously. Query option elements by DOM instead, matching the repo's house
pattern for native selects.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [MM-68421] Fix expiry overshoot vs server cap and review nits
Review found that presets/custom dates resolve to end-of-local-day, which can
sit up to ~24h beyond the server cap of "now + MaximumPersonalAccessTokenLife
timeDays" (an exact duration from creation time). With a max configured, the
default preset equals the cap, so accepting the default and saving was rejected
server-side with expires_at_too_far for most of the day.
- Clamp the submitted expiry to the server cap when a maximum lifetime is set.
Validation still runs on the raw end-of-day value so an explicitly out-of-range
custom date is still rejected; only the in-range end-of-day overshoot is clamped.
- Count "expires in N days" from the start of today and floor it, so an end-of-day
expiry no longer over-reports by one (a 7-day token reads "7 days", not "8").
- Add an aria-label to the custom expiry date input.
Tests: unit coverage for clampExpiresAtToMaxLifetime; a Playwright spec that
creates a token with the default preset under a 30-day cap and asserts success.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [MM-68421] Apply prettier formatting to PAT e2e spec
The ci/playwright/npm-check job (lint + prettier + tsc + lint:test-docs) failed
on prettier formatting. eslint and tsc were clean; reformat the spec to satisfy
prettier as well.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [MM-68421] Add PAT max-lifetime System Console setting and creation-form UX fixes
- Add ServiceSettings.MaximumPersonalAccessTokenLifetimeDays number field to
System Console > Integrations > Integration Management, after Enable Personal
Access Tokens (disabled when tokens are disabled).
- Disable the token creation Save button until a non-empty description is
entered (description input is now controlled; whitespace-only rejected).
- Render the token creation form as a distinct "Create New Token" card so it no
longer blends into the existing token list.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* Fix stylelint property order in new-token card
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* [MM-68421] Validate PAT expiry inline before submit
Surface the expiry validation error in the create-token form and disable
Save while the selection is invalid, instead of only failing inside the
create-confirmation flow. Previously a system admin had to click Save then
"Yes, Create" before seeing "An expiry date is required." for an empty
custom date.
Extracts the expiry checks into getExpiryValidationError(), reuses it as
the handleCreateToken guard, and renders the result inline + in the Save
button's disabled condition.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [MM-68421] Fix PAT expiry e2e specs for inline validation
The "blocks submitting a custom expiry with no date chosen" and "enforces
expiry when a maximum lifetime is configured" specs clicked the Save button
and expected an inline error afterward. Since
|
||
|
|
6332bc948d |
[MM-64430] Allow editing team name and description from the System Console (#37206)
* [MM-64430] Allow editing team name and description in System Console Make the Team Profile panel on the System Console team detail page editable so admins can rename a team and edit its description without switching to the chat-facing team settings. Changes are saved through the existing SaveChangesPanel flow via patchTeam. Co-authored-by: mattermost-code <matty-code@mattermost.com> * [MM-64430] Widen team profile edit inputs to fit full team name The Team Name and Team Description inputs inherited the narrow team-desc-col width, making long values appear visually truncated. Let the edit column grow to fill the panel so the full value is visible. Co-authored-by: mattermost-code <matty-code@mattermost.com> * [MM-64430] Add tests for editing team name and description in System Console Cover the new editable Team Profile fields and TeamDetails save flow: team_profile renders/edits the name and description inputs and surfaces the name validation error; team_details saves the trimmed name and description via patchTeam and blocks the save when the name is too short. Co-authored-by: mattermost-code <matty-code@mattermost.com> * [MM-64430] Strengthen team profile edit tests per review Scope the name validation error assertion to the name field, and cover error recovery, whitespace-only names, navigation blocking on edit, and resetting the fields when a different team is loaded. Co-authored-by: mattermost-code <matty-code@mattermost.com> * [MM-64430] Pre-commit fixes: i18n sync, lint and stylelint Run i18n-extract to drop the now-unused team profile strings, reorder the new SCSS rule properties, and reformat the new tests to satisfy JSX lint rules. Co-authored-by: mattermost-code <matty-code@mattermost.com> * Remove stray comment in TeamProfile cloud guard Co-authored-by: mattermost-code <matty-code@mattermost.com> * Retrigger CodeRabbit review after rate limit Co-authored-by: mattermost-code <matty-code@mattermost.com> * Address CodeRabbit feedback on team profile save flow - Only reset editable fields when the selected team changes, not when totalGroups updates - Validate team name before archive/restore operations - Patch profile fields before archiving so Save and Archive persists edits Co-authored-by: mattermost-code <matty-code@mattermost.com> * Retrigger Enterprise CI after transient npm ECONNRESET Co-authored-by: mattermost-code <matty-code@mattermost.com> * Validate team name before opening Save and Archive modal When the team name is invalid (too short) and the team is toggled to be archived, clicking Save opened the Save and Archive confirm modal and the validation error rendered behind it, so confirming appeared to do nothing. Validate the name in onSave before opening the modal so the inline error fires immediately, and defensively close the archive modal in handleSubmit. * Add e2e test for editing team name and description in System Console * Address review: exact URL assertion + archive-invalid-name e2e coverage --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: mattermost-code <matty-code@mattermost.com> |
||
|
|
cb136ac81e | MM-61199: Remove channelBookmarks feature flag (#37120) | ||
|
|
0fa2713b59 |
MM-67755: WYSIWYG editor for message composition (#36143)
* MM-67755: WYSIWYG editor for message composition - Add TipTap-based WYSIWYG editor as an opt-in setting - Implement formatting bar with text styles dropdown, link popover - Add custom list extension for Mattermost markdown compatibility - Add suggestion list integration for mentions and emoji - Add feature flag and user preference toggle - Update e2e tests for WYSIWYG editor compatibility Made-with: Cursor * Fix package versions to match current master (11.7.0) Made-with: Cursor * Add missing PermissionPolicies feature flag from master Made-with: Cursor * Fix remaining WYSIWYG UX issues: toolbar overlap, autocomplete, emoji, tables Made-with: Cursor * Address CodeRabbit review: null guards, XSS fix, e2e tests, constants alignment Made-with: Cursor * UX fixes required by Matt * linter * fix e2e * Fix CI failures: resolve merge conflicts with master - Fix TS errors from useRewrite hook refactor (additionalControl → rewriteMenuProps) - Fix onComposition → onCompositionUpdate prop rename on Textbox - Remove accidentally re-added enzyme-to-json/serializer from jest config - Extract new i18n strings for WYSIWYG editor components Made-with: Cursor * Fix lint: remove unused aiRewriteEnabled and rewriteMenuProps vars Made-with: Cursor * Fix jest and E2E test failures - Add lowlight and ESM deps to jest transformIgnorePatterns - Replace have.value with have.text for contenteditable elements - Remove selectionStart/selectionEnd assertions for WYSIWYG editor Made-with: Cursor * e2e test * Expose focus()/blur() on WysiwygEditor handle so focus hooks work useTextboxFocus drives focus into the composer for many flows (channel switch, RHS open, post-submit refocus, Reply shortcut, "type to focus main input"). It calls textboxRef.current?.focus(), but textboxRef is the legacy <Textbox> ref and is null when the WYSIWYG editor is the mounted composer, so every focus call becomes a silent no-op. Add focus() and blur() to WysiwygEditorHandle, backed by editor.commands .focus()/blur(), and pass wysiwygRef into useTextboxFocus so it picks whichever ref is mounted. The hook keeps its existing signature for legacy callers; wysiwygRef is optional. Verified locally on the WYSIWYG branch: - messaging/focus_move_spec (3/6 failing -> 6/6 passing) - messaging/message_edit_post_clear_text_spec (0/1 -> 1/1) - messaging/message_edit_post_history_spec (0/3 -> 1/3) - keyboard_shortcuts/dot_menu_spec gets past the Reply-focus assertion Co-authored-by: Cursor <cursoragent@cursor.com> * e2e: coerce postMessage args to string in WYSIWYG branch The legacy textarea path used cy.invoke('val', message) which silently coerced numbers/undefined to strings. The WYSIWYG branch added in the previous refactor calls message.replace() and crashes with "TypeError: message.replace is not a function" whenever a spec passes a non-string value, e.g. cy.uiPostMessageQuickly(0) or before-each hooks that pass undefined. Funnel everything through asPostMessage() so the WYSIWYG branch is just as forgiving as the textarea branch. Loosen postMessage / postMessageReplyInRHS / uiPostMessageQuickly typings to `unknown` to match what callers actually pass. Fixes failures in: copy_post_text_spec, save_post_spec, search_filter/{after,before,future_date}_spec, and scroll/default_images_collapsed_spec. Co-authored-by: Cursor <cursoragent@cursor.com> * filtetr by feature flag for now * coderabbit ai feedback * coderabbitai comments * align with code conventions * fix e2e test * PR comments * fix i18n * anchor link popover to editor selectio * UX issues * regression * Final UX feedback * linter * e2e test rename * Final UX * Fix playwright lint * Align e2e mocks with master * Disable feature flag * Sanitize urls before handling actions with link popove --------- Co-authored-by: Nevyana Angelova <nevyangelova@192.168.100.47> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Mattermost Build <build@mattermost.com> |
||
|
|
d85da5ce2c |
E2E/Playwright: Upgrade Playwright to 1.61 and its deps (#37277)
* chore: upgrade playwright to 1.61 and its deps * fix failed tests * address comments * use assignTeamsToPolicy helper method |
||
|
|
1c801690a0 |
Mattermost Blocks (#36338)
* Mattermost Blocks * Rethink some block props and styles * Remove obsolete comment * Style fixes and add examples * Add mention, search, and image metadata support * Several UI improvements * Validate blocks by translating them * Add initial e2e tests * Fix lint * Fix tests and lint * Fix lint * Improve e2e and simplify doPostAction * server side cleanup * Fix typo * Fix style * Fix some tests * Fix more tests * Fix cypress tests * Fix playwhright tests * Fix flaky system console test * Frontend cleanup * Add blocks editor * Fix CI * Limit all blocks width * Fix test * Enable webhook service on playwhright CI * fix flaky test * Fix style * Cleanups * Address coderabbit comments * Address coderabbit comments * Address CI errors * Fix tests * Address changes in valid actions * UX fixes * Fix test * Fix danger buttons and add allow emojis in buttons * style tweaks use semantic color tokens for buttons and accents, update max-heights for scollables, adjustments to containers, removed btn-sm (using default button size for mm blocks with height and padding adjustments for use within blocks. removed hover selector from utils to prevent hover state issue with primary button, refined semantic-color-warning. * Address feedback * Add interactive content to post previews * Add collapse transitions * Address autocomplete position * Handle columns within column sets * Fix css lint * Fix tests * Use feature flag * Address feedback * Fix lint and add missing tests * Fix e2e tests * Fix e2e test * Allow interactive posts without a message * Fix lint * Address feedback * Fix ci * Fix lint * Add limits to block translations * Fix lint * Address feedback * Address feedback * Update snapshot * Fix collapsible not defaulting to the right value * Add total text limit * Sync translations with mobile * Fix snapshot --------- Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> Co-authored-by: Mattermost Build <build@mattermost.com> |
||
|
|
f4f69470d3 |
MM-24208: Improve multiple image previews and add video preview (#36922)
* MM-24208: Improve multiple image previews and add video preview * linter * fix lint and e2 * PR fixes * UX feedback * coderabbit ai feedback * UX feedback * Refactor useContainerDimensions hook * Refactor useContainerdimentions hook to desctructure width * UI feedback final * lint * Remove redundant video previe * Add caching for thumbnails --------- Co-authored-by: Nevyana Angelova <nevyangelova@192.168.100.47> |
||
|
|
7b10409141 |
[MM-69229] Remove CloudAnnualRenewals feature flag and dead code (#37151)
* [MM-69229] Remove CloudAnnualRenewals feature flag and dead code The CloudAnnualRenewals flag (default false, shipped v9.4) gated whether the cloud subscription's WillRenew/CancelAt timing was exposed to clients. The feature never launched — the flag has been off since 2023, so those fields have always been blanked and the webapp banner that would have consumed them was already removed. - Server: blank WillRenew/CancelAt unconditionally in getSubscription (locking in the long-standing behavior) and drop the now-dead CancelAt assignment in the end-user subscription branch. - Webapp: remove the orphaned CLOUD_ANNUAL_RENEWAL_BANNER and ANNUAL_RENEWAL_60_DAY/30_DAY constants (defined but unused). - Remove the struct field, its SetDefaults entry, and the e2e mirror. * gofmt feature_flags.go |
||
|
|
ba033eae47 |
[MM-69229] Promote ConsumePostHook: remove the feature flag (#37148)
* perf: skip ConsumePostHook clones when no plugin implements it applyPostsWillBeConsumedHook deep-cloned every returned post via Post.ForPlugin() on each batch read path before dispatching the MessagesWillBeConsumed hook, even when no plugin implements it. Add Environment.HasPluginImplementing(hookId) — the same cheap supervisor.Implements scan RunMultiPluginHook does internally, minus the clone, closure, and metrics observe — and guard both apply helpers on it so stock servers pay nothing for the gate. * [MM-69229] Promote ConsumePostHook: remove the feature flag The ConsumePostHook flag (default false, shipped v9.3) gated the public MessagesWillBeConsumed plugin hook. With the per-read clone now skipped when no plugin implements the hook, the gate is safe to remove and the hook becomes always-on (still subject to HasPluginImplementing and the burn-on-read carve-out). Drops the struct field, its SetDefaults entry, the e2e default_config mirror, and the flag-toggling tests that no longer have a flag to toggle. * Fix early return to also check MessagesWillBeConsumedWithContext |
||
|
|
dbcd904cc2 |
[MM-69229] Promote CloudIPFiltering: remove the feature flag (#37150)
The CloudIPFiltering flag (default false, shipped v9.4) gated the
cloud-only IP filtering admin feature. The feature stays cloud-only
independent of the flag:
- Server: ensureIPFilteringInterface still requires license.IsCloud()
and MinimumEnterpriseLicense, so non-cloud servers continue to get
501 Not Implemented. Added not-cloud coverage to applyIPFilters and
getMyIP to match the existing getIPFilters case.
- Webapp: the admin console section now gates on a Cloud license +
Enterprise tier (it.licensedForFeature('Cloud')) instead of the flag,
preserving cloud-only visibility.
Drops the struct field, its SetDefaults entry, the e2e default_config
mirror, the admin_sidebar test fixtures, and the flag-toggling test
cases.
|
||
|
|
c55282c738 |
[MM-69229] Remove orphaned PermalinkPreviews feature flag (#37147)
The PermalinkPreviews feature flag had no consumers and no SetDefaults entry (zero-value false). The feature is gated by the separate ServiceSettings.EnablePermalinkPreviews config setting (defaults true). |
||
|
|
86732989e8 |
[MM-69229] Remove orphaned DeprecateCloudFree feature flag (#37149)
DeprecateCloudFree (shipped v8.0.0) had no consumers anywhere in the server or webapp — the Cloud Free deprecation-banner code that once read it is long gone, leaving only the struct field, its SetDefaults entry, and the e2e default_config mirror. Removing it changes no behavior. |
||
|
|
159fe5502b |
Fix MM-T643 long URL embedded image E2E test (#37073)
* Fix long URL embedded image E2E test by raising MaximumURLLength The test posts an incoming webhook containing an embedded image with a very long URL. With the image proxy enabled, the rendered image src points to /api/v4/image?url=<encoded>, whose request URI (~3165 chars) exceeds the default MaximumURLLength of 2048 and is rejected with 'basicSecurityChecks: URL is too long'. Raise the limit in the test config so the long URL is accepted, restoring the test's original intent. Co-authored-by: mattermost-code <matty-code@mattermost.com> * Make long URL embedded image E2E test self-contained and robust via.placeholder.com is no longer a live image host (it now returns an HTML redirect), so the embedded image never loaded and the 'file thumbnail' assertion failed. Point the long image URL at a static asset served by the Mattermost server itself (allowed via AllowedUntrustedInternalConnections), keeping the URL long while removing the external dependency. Also drive the post past the Show more overflow threshold via the message text instead of relying on the image height, and target the stable #showMoreButton id rather than matching the localized 'Show more' text, which resolves to a non-visible span. Co-authored-by: mattermost-code <matty-code@mattermost.com> * Scope assertions to the post and verify the proxied image loads Address test-quality review: scope the thumbnail and Show more/less queries to the specific post via #post_<id> (the #showMoreButton id repeats per overflowing post), and assert the embedded image actually decoded (naturalWidth > 0) so the test proves the long proxied URL was served, not just that an <img> element exists. Co-authored-by: mattermost-code <matty-code@mattermost.com> * Restore MaximumURLLength config after incoming webhook spec Back up ServiceSettings via cy.apiGetConfig() in before() and restore the original values in after() to prevent test-order leakage. 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> |
||
|
|
017a7102f8 |
[MM-69055] Add rank property field type (#36809)
* Add rank property field type and migrate classification field to use it Introduces a new 'rank' property field type that behaves identically to 'select' across validation, access-control masking, options handling, and rendering. The classification markings admin panel now creates its template, system, and channel fields as 'rank' instead of 'select', with a paired DB migration to flip any existing classification rows. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * Enforce rank validation on ranked property field options For PropertyFieldTypeRank fields, every option must carry a non-negative, unique rank. Adds the Rank field to CustomProfileAttributesSelectOption and strips stray Rank values from options on non-rank field types so they cannot drift into persisted attrs. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * Materialize rank options in AttributeView and signal field updates to access control Extend the AttributeView materialized view so rank-typed property values are exposed as {"name", "rank"} objects, enabling downstream ABAC SQL and CEL machinery to compare a user's rank against a named option without baking rank integers into policy expressions. Add OnPropertyFieldOptionsChanged on the access control service interface and call it after every property field update so the service can drop any per-field metadata it caches (such as the rank-by-name map) and invalidate compiled-policy cache entries that reference the field. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Show rank-and-lower options/values for shared_only rank fields shared_only masking on a rank field previously required an exact option match, the same as select/multiselect. For rank fields the intended semantics are clearance-style: a caller sees every option and every target value at or below their own rank. filterSharedOnlyFieldOptions and filterSharedOnlyValue now branch rank fields to filterSharedOnlyRankFieldOptions / filterSharedOnlyRankValue, which compare against the caller's rank instead of intersecting option IDs. Select, multiselect, and scalar (text/date/user) masking are unchanged. A caller with no value of their own has no rank and sees nothing; the source plugin still sees everything. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Render rank property field type like select in webapp Treat the new 'rank' custom profile attribute type as a single-select everywhere it is editable, and make it fully usable from the system console: - user_settings/general: render rank fields as a single-select dropdown (resolving option IDs to names) instead of a free-text input. - system_user_detail: resolve rank option names and render the value input as a native single-select. - user_properties_type_menu: add a selectable "Rank" field type (reusing the Select icon) so existing rank fields display correctly and admins can create new rank fields from the UI. - en.json: add the "Rank" type label string. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Make rank cache invalidation cluster-aware and cover field deletion OnPropertyFieldOptionsChanged previously dropped the access control service's per-field rank cache only on the node handling the property field update, so peer nodes kept serving stale name->rank maps until restart. It was also wired into the update path only, leaving deleted rank fields cached indefinitely. Call OnPropertyFieldOptionsChanged from DeletePropertyField so a removed rank field's cached options are dropped too. The access control service now broadcasts the invalidation cluster-wide (see companion enterprise change). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Backfill option ranks when migrating classification fields to rank The select->rank conversion previously only flipped the field type. On upgrades the existing classification options carry no rank (master's select option struct has no rank field, so the UI-sent rank was dropped on save), which left an invalid rank field: the matview projected null ranks, shared_only masking hid every value, and the validation hook rejected any later edit. Backfill a rank onto each option from its 1-based array position. The classification UI keeps levels in severity order and rewrites the full options array on every save, so position is the authoritative ordering; 1-based matches both the UI's `opt.rank ?? (i+1)` fallback and the presets' ranks, so a configured preset is still recognized after upgrade. The flip and backfill share one migration (one transaction), so the field is never observable in the invalid (rank, null-rank) state, and the down migration strips the rank key to restore the prior select shape. Only the three known classification fields with a non-empty options array are touched; the updates match at most three rows and add no meaningful lock footprint. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Add System Console UI for ranked property fields Implements the admin UI for the ranked property field type across three System Console surfaces: - User Attributes: the "Ranked" attribute type, numbered value chips in ascending rank order, a per-chip popover (rename / change rank / remove), and an "Edit ranking" modal with drag-reorder, arrow steppers, numeric rank inputs, auto-assigned next rank, and inline duplicate rejection. - Membership Policy editor: ranked comparison operators (is exactly, is not, is at least, is greater than, is at most, is less than) shown for ranked attributes in place of the standard set, with CEL build/parse and default-operator wiring. - User detail: a ranked-value picker rendering options highest-rank-first with numbered badges and a checkmark on the assigned value. Adds Playwright e2e coverage for all three surfaces (plus page-object helpers) and webapp unit tests for the operator wiring and rank utilities. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Fix enterprise CI: regenerate access-control mocks and add rank i18n key The enterprise CI lane fails on two pre-existing backend gaps on this branch: - go vet (check-style): OnPropertyFieldOptionsChanged was added to PolicyAdministrationPointInterface but the generated einterfaces mocks were never regenerated, so AccessControlServiceInterface / PolicyAdministrationPointInterface mocks no longer satisfy the interface (access_control_test.go, access_control_masking_test.go). Add the missing method to both mocks. - Check i18n: enterprise access_control/administration.go references the app.pap.rehydrate_rank.app_error key, which was never added to server/i18n/en.json. Add it so `make i18n-extract` produces a clean diff. Verified: both affected test packages compile, `make i18n-extract` yields no diff, and `make i18n-check` passes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Retrigger enterprise CI Pick up enterprise fix 15914c11 (require.NoError in rank cel_utils tests) in the combined Enterprise CI/tests lane, which pins the enterprise SHA at mattermost-side dispatch time. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Retrigger enterprise CI Pick up enterprise fix 48db14db (golangci-lint findings in rank access-control code) in the combined Enterprise CI/tests lane. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Clamp shared_only rank values to the caller's rank instead of hiding For a shared_only rank field, filterSharedOnlyRankValue previously hid a target's value entirely when the target outranked the caller, returning nil. That answered "is the target at or below me?" but not the question the field exists for: "what can we talk about, and at what level?" A higher-ranked target simply disappeared. Now the value is clamped to the highest rank the caller shares with the target — the target's own value when it is at or below the caller's rank, otherwise the option at the caller's own rank. The caller always learns their shared ceiling and never sees a rank above their own. Ranks are unique per field, so the clamp target is unambiguous. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Renumber rank migrations to 194-197 (after property_groups 193) 000193_add_property_groups_schema_version was already on master, so our rank migrations should follow it: 194-197. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Fix e2e classification helper field names after rename migration Migration 000196 renamed channel_classification → classification and system_classification → classification. Update the e2e helpers to create and clean up fields with the new canonical names so the frontend (which looks for 'classification') can find them. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Remove unused i18n key and fix e2e prettier formatting app.pap.save_policy.advanced_expression_blocked was added to en.json but never used as an AppError key in Go code — remove it so i18n-check passes. Also fix prettier formatting in ranked_operators.spec.ts. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Fix 000194 down migration: drop AttributeView before enum rebuild TestUpAndDownMigrations/Should_be_reversible_for_postgres failed because the down migration rebuilds the property_field_type enum (Postgres can't drop an enum value in place), which requires ALTER COLUMN on PropertyFields.Type. The AttributeView materialized view reads that column, so Postgres rejects the alter: "cannot alter type of a column used by a view or rule". The up path is unaffected because it uses ADD VALUE (no column rewrite); only the down rebuild trips the dependency. Mirror the canonical drop-view / alter-column / recreate-view pattern: drop AttributeView, rebuild the enum, then recreate the no-rank view (the same definition 000197's down restores, which 000177's down later replaces). Verified end-to-end against PostgreSQL 16: full up-then-down sequence now passes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Add unit tests for rank validation and field-change signalling Fills two gaps flagged by PR test analysis: - access_control_attribute_validation_test.go: rank option validation (valid ranks persist; missing/negative/duplicate rank rejected; zero rank allowed; non-rank fields strip stray rank values). - property_field_test.go: UpdatePropertyFields/DeletePropertyField signal the access control service via OnPropertyFieldOptionsChanged for each affected field, and stay nil-safe when no AC service exists. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Add api4 tests for rank-field permission branching Fills the API gap flagged by PR test analysis: rank fields participate in the isOptionsOnly permission branch alongside select/multiselect. - properties_test.go: an options-only PATCH on a rank field uses the narrower manage-options permission (member succeeds), while a structural PATCH (name change) requires the full edit-field permission (member forbidden, admin succeeds). - custom_profile_attributes_test.go: an options-only PATCH on a rank CPA field routes through the options path and round-trips ranks. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Add mmctl unit tests for rank attribute resolution Fills the mmctl gap flagged by PR test analysis. Both resolution directions for rank-typed attributes were untested: - user_attributes_test.go (TestResolveDisplayValue): a stored rank option ID resolves to its option name for display; unknown IDs and option-less fields fall back to the raw value. - user_attributes_value_test.go (TestResolveOptionNamesToIDs): setting a rank value by option name resolves to the option ID; already-an-ID and unknown names pass through. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Refine ranked attribute editing UI Edit ranking modal: - Derive ranks from row position so reordering or removing a value always keeps them contiguous (1..N) with no gaps or duplicates - Drop the arrow steppers in favor of drag-only reordering; render the drag clone through a body portal so it isn't offset by the modal dialog transform - Show values as read-only chips (lowest-first) with Lowest/Highest labels - "Add value" toggles into an inline row (fake handle + borderless field); Enter commits the value instead of closing the modal - Title shows the field name plus "Ranked attribute" Inline rank values: - Rank badge fills the left of the chip; add an inline remove (X) that reuses react-select's CrossIcon so it matches select fields Also give the rank attribute type its own SortAscendingIcon and trim a couple of stale comments. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Fix SCSS property order lint errors Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Fix e2e rank modal tests to match drag-and-drop UX The ranked schema modal uses position-based ranks (drag to reorder) — there are no editable numeric rank inputs per row and no per-row name inputs. The two failing tests were written against an earlier design that had those inputs: - "rejects a duplicate rank inline" expected .ranked-schema-modal__rank-input and .ranked-schema-modal__error (neither exists). Replaced with a test that covers the actual duplicate-label guard on the add-value inline input. - "adds a value via the Edit ranking modal" expected .ranked-schema-modal__name-input (doesn't exist) and that save is disabled while the add input is open (it isn't — save is disabled only when rows is empty). Updated to use the real add-value flow: click "Add value", fill .ranked-schema-modal__add-input, blur to commit. Also removes the three broken page-object helpers (rankedModalRankInputs, rankedModalError, rankedModalNameInputs) whose CSS selectors never existed. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Enforce positive ranks and backfill them on select-to-rank conversion Rank values must be positive integers (>= 1), matching the webapp's isValidRank helper and rankForIndex which both require rank >= 1. The server was accepting rank = 0 (rank < 0 check), allowing invalid data that would cause filtering bugs: a caller with a rank-0 option would see nothing in a shared-only field since no option would satisfy rank <= 0. Change the guard to rank <= 0 and update the error message and tests accordingly. When converting a field from select/multiselect to rank via the type dropdown, the existing options had no ranks. The server's option validation then rejected the save (or the UI showed stale local state appearing valid). Auto-assign contiguous 1-based ranks in array order at the point of type change so the conversion is immediately valid and the user does not need to open the rank-ordering modal just to commit. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Show an inline error when a ranked option is renamed to a duplicate Renaming a ranked option to a name already used by another option was silently ignored: the draft reverted with no feedback, leaving the user unsure why their edit didn't stick. The add-value flow already warns on duplicates; the rename path now matches it. The chip popover surfaces "Values must be unique." beneath the label input while the typed name collides, and the rename stays blocked so a duplicate is never committed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Scroll the ranked schema list so the modal footer stays in view A ranked attribute with many values (e.g. 30) grew the edit modal taller than the viewport, pushing the Save/Cancel footer off the bottom of the screen where it couldn't be reached. Cap the value list at 50vh and scroll it internally, keeping the header and footer anchored. The list is the droppable's own scroll container, so react-beautiful-dnd auto-scrolls it while a row is being dragged, and a small right padding keeps the scrollbar clear of the remove buttons. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Add a shared allow-list for option-bearing property field types The "is this a select/multiselect/rank field?" check was open-coded as a three-way type-negation chain in the model, both PSAv2 patch handlers, and the access-control shared-options filter. Each copy had to be kept in sync by hand as field types were added. Introduce an optionFieldTypes allow-list in the model with a PropertyFieldType.SupportsOptions() helper (mirroring the webapp's supportsOptions) and route every call site through it, so adding a future option-bearing type is a one-line change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Guard the rank options filter before its store lookup filterSharedOnlyRankFieldOptions built the option-rank map and ran the caller-rank store lookup before checking whether the field had a usable options array at all. A field with no options (or a malformed attrs blob) has nothing to filter, yet still paid for a database query. Move the cheap nil/shape guards to the top so an optionless field returns immediately, and reuse the extracted options slice in the filter loop instead of pulling it out of attrs a second time. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Memoize the ranked attribute editors' event handlers The rank schema modal and the inline rank-values cell recreated every handler (drag-end, move, remove, confirm, rename, add) on each render. These are passed down to the modal footer, the drag-and-drop context, and per-chip popovers, so the fresh identities defeated memoization downstream. Wrap them in useCallback with explicit dependencies. No behavior change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Add tests for the classification select-to-rank migration The 000195 conversion is non-trivial: it flips specific (Name, ObjectType) fields in the access_control group from select to rank, then backfills a 1-based rank onto each option from its array position, guarding against empty or absent options arrays. Cover the behavior end to end against a real Postgres schema: the type flip with position-derived ranks in order, the empty- and absent-options guards (type flips without fabricating options), the name/object-type/group mismatches that must stay select, and the down round-trip that strips the ranks and reverts the type. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Gate the rank property field type behind a feature flag Add a PropertyFieldRank feature flag (off by default) that gates the "rank" custom profile attribute type. The enforcement is a single app-layer gate, rankPropertyFieldGate, shared by both CreatePropertyField (blocks creating a rank field) and UpdatePropertyFields (blocks converting an existing field to rank). When the flag is off it returns app.property_field.rank_disabled.app_error. The admin console CPA type menu hides the rank option unless the flag is on, read via useGetFeatureFlagValue. Existing app/api4 tests that exercise rank fields now enable the flag in their setup so they continue to pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Scope the rank feature-flag gate to user-object fields The PropertyFieldRank gate rejected any rank-typed field create/update when the flag was off. But classification markings now uses the rank type internally (template/system/channel object types) and ships GA behind the separate ClassificationMarkings flag, which is on by default while PropertyFieldRank is off by default. The migration also converts existing classification fields to rank unconditionally. Together this broke the classification admin panel in the default configuration: both creating new classification fields and editing existing (migrated) ones returned app.property_field.rank_disabled.app_error. Scope the gate to ObjectType == user, which is the only origin of the user-facing rank CPA type (createCPAField forces ObjectType=user). Rank fields on other object types are exempt, so classification keeps working regardless of the flag while the user-facing CPA rank type stays gated. Add regression cases proving a non-user (classification-style) rank field is creatable and convertible-to with the flag off, and enable PropertyFieldRank in the e2e default config so the user-facing rank specs pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Update webapp/channels/src/components/admin_console/system_properties/rank_badge.scss Co-authored-by: abhijit-singh <abhijitsingh0702@gmail.com> * Enable the rank feature flag in the e2e CI server env The new rank e2e tests failed in playwright-full because the CI docker server gets feature flags from MM_FEATUREFLAGS_* env vars (config patches don't stick without a SplitKey), and PropertyFieldRank was only set in the local default_config.ts. Add the matching env var so the flag is on in CI. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Fix stale migration-number references in classification rank down migrations The 000195 and 000196 down migrations carried comment references to their development-era numbers (000191/000192). Correct them to the current numbering (000195 reverses itself; 000196's down restores distinct names before 000195's down matches on them). Addresses review feedback from @mgdelacroix. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Use PropertyFieldType.SupportsOptions() for option-field type checks Replace the repeated `Select || Multiselect || Rank` comparisons with the existing SupportsOptions() helper across the access-control masking, validation, and option-filtering paths, and in mmctl value resolution. Behavior is unchanged (SupportsOptions covers exactly those three types). Addresses review feedback from @mgdelacroix. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * webapp: use supportsOptions() helper for option-field type checks Replace the repeated `type === 'select' || 'multiselect' || 'rank'` checks with the existing supportsOptions() helper from @mattermost/types/properties, matching the server-side SupportsOptions() usage. Addresses review feedback from @mgdelacroix. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Include rank in extractOptionIDsFromValue error message The function handles select, multiselect and rank, but the error message only listed select and multiselect. Addresses review feedback from @mgdelacroix. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Validate option rank in CustomProfileAttributesSelectOption.IsValid When an option carries a rank, enforce that it is a positive integer at the model layer, mirroring the field-level option validation. Rank stays optional so select/multiselect options (which carry none) remain valid. Addresses review feedback from @mgdelacroix. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Invalidate access-control cache before broadcasting field update In UpdatePropertyFields, move the OnPropertyFieldOptionsChanged notification above the websocket broadcast so a client reacting to the update event never re-reads stale cached field metadata. This matches the ordering already used in DeletePropertyField. Addresses review feedback from @mgdelacroix. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Assert stored options in options-only patch permission tests The select/multiselect/rank options-only update tests only checked that the request succeeded; also assert the returned field's options (id, name, and rank for the rank case) so the tests actually verify the change was persisted. Addresses review feedback from @mgdelacroix. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Add FeatureFlagPropertyFieldRank to webapp ClientConfig type The server-side PropertyFieldRank feature flag and user_properties_type_menu.test.tsx reference FeatureFlagPropertyFieldRank, but it was never added to the webapp ClientConfig FeatureFlags type, leaving tsc -b red. Add the missing field. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Tighten the ranked option popover spacing Drop MUI's default 8px MuiList top/bottom padding on the per-option popover and reduce the label input's bottom padding to 4px, so the popover reads tighter without jamming the label input against the top edge. Addresses design feedback from @abhijit-singh. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Add header and footer dividers to the Edit ranking modal Enable GenericModal's bodyDivider and footerDivider so the ranked schema modal shows a divider under the header and above the Save/Cancel footer, which also delineates the scroll area when the value list is long. Addresses design feedback from @abhijit-singh. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Match ranked 'Add values…' affordance to select/multiselect The ranked values cell now mirrors the select/multiselect CreatableSelect cell for consistency across field types: - Tab commits a pending value (keeping focus in the input for the next one) when it's non-empty and not a duplicate, matching the select cell; a blank/duplicate input lets Tab move focus away normally. - The empty-state placeholder uses the shared 'Add values… (required)' text and matches react-select's placeholder color (full-opacity neutral50) and 10px content inset, so size, color, and left alignment line up with the select cell. - The placeholder is hidden once values exist, mirroring react-select. - The chips well gets the same hover/focus background tint and text cursor as the select control. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Auto-size the ranked 'Add values…' input like react-select The bare <input> scrolled its overflow in a fixed-width box, while the select/multiselect cell grows its input and wraps to a new row as you type. Replicate react-select's sizer technique: wrap the input in an inline-grid whose hidden ::after mirrors the live text (content: attr(data-value), white-space: pre, font: inherit) and sizes the grid column the input fills. The input now grows with its content and, as a flex child of the values well, wraps to a new row when it no longer fits. Both the input and the sizer use 'font: inherit' (matching react-select) so the measured and rendered text line up and the font matches the select cell. Since the auto-sized input no longer spans the whole cell, a mousedown handler on the well forwards focus to the input, mirroring react-select's clickable control. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Fix consistent-type-imports lint errors in Playwright e2e specs Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Enable PropertyFieldRank feature flag in rank e2e test setup The Rank type option in the attribute type menu is gated behind the PropertyFieldRank feature flag. initSetup resets config, so the flag must be explicitly re-enabled before the test exercises the UI selector. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Remove broken feature-flag patchConfig from rank e2e setup setupTest called patchConfig({FeatureFlags: {PropertyFieldRank: 'true'}}) with the string 'true'. PropertyFieldRank is a Go bool, so the server's patchConfig handler (which does json.Decode(&cfg) into *model.Config before any filtering) failed to unmarshal the string into a bool and returned 400 "Invalid or missing config in request body." This hard-failed setupTest and all four specs (CI run 27387310039: 4/4 failed at spec line 36). The call was both broken and unnecessary: - Without a SplitKey the config store marks FeatureFlags read-only (PlatformService.SetupFeatureFlags -> SetReadOnlyFF(!splitConfigured)), so no patchConfig can toggle a flag. The flag is enabled at the server level: the MM_FEATUREFLAGS_PROPERTYFIELDRANK env var in CI (added to e2e-tests/.ci/server.generate.sh) and the server config locally. - With the env var in place, all four specs passed at commit 8fca57bf3b; the later commit that added this line is what regressed them. Remove the call and document where the flag actually comes from. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Locate ranked add-value input by class, not placeholder The "creates a ranked attribute" spec timed out at addRankValuesToLast waiting for getByPlaceholder('Add value…') on the inline add-value input. Commit |
||
|
|
5b132e2230 |
[MM-68421] Frontend: PAT creation UI: expiry picker and status display (#36707)
* [MM-68421] Frontend: PAT creation UI — expiry picker and status display
Wires the webapp UI to the server-side support added in PR #36706 (and
the MM-68419 model changes):
- Extends UserAccessToken type with expires_at, and ClientConfig with
EnforcePersonalAccessTokenExpiry / MaximumPersonalAccessTokenLifetimeDays.
- Threads expires_at through Client4.createUserAccessToken and the
mattermost-redux createUserAccessToken action.
- Adds a date/time picker to the PAT creation form (reuses
DateTimePickerModal). Honors enforcement and clamps to the
max-lifetime setting; maps server error ids
(expires_at_required/in_past/too_far) to localized messages.
- Displays expiry, derived status badge (active/expired/disabled), and
an approaching-expiry warning (<7 days) in the account settings token
list. Mirrors expiry + status in the admin Manage Tokens modal.
- Adds the supporting i18n keys.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* [MM-68421] Address review: i18n, ServerError type, scss, explicit guards
- Inject intl so the "Expires in N days" tooltip and the picker
ariaLabel are localized instead of hard-coded English.
- Use the canonical ServerError type from @mattermost/types/errors
instead of an ad-hoc inline cast.
- Dedupe the new i18n ids — keep a single "Expires: " string per
namespace and drop the duplicates introduced in the first pass.
- Add scss for setting-box__token-expiry / __token-status /
__token-expiry-warning so the new status pill and warning render
with the expected styling.
- Replace truthy checks on the numeric expiresAt with explicit
> 0 comparisons for readability.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* [MM-68421] Replace expiry datetime picker with preset chooser + custom date
Per UX discussion: PATs are long-lived so sub-day precision is noise.
Swap the DateTimePickerModal for a native <select> of presets
(No expiry, 7d, 30d, 90d, 1 year, Custom date) with a date-only
<input type="date"> revealed when Custom is selected. Effective time
is end-of-local-day, which matches how users think about expiry.
- Drops the DateTimePickerModal import and the picker open/close
handlers; removes the moment-timezone import.
- Adds isPresetAllowed() that hides presets exceeding
MaximumPersonalAccessTokenLifetimeDays, and a defaultExpiryPreset()
that picks 30d (then 7d, then Custom) when enforcement is on,
No expiry otherwise.
- The custom <input type="date"> uses min=today and max=now+maxDays
for native bounds; submit-time validation still maps server error
ids if the user bypasses the bounds.
- i18n: adds preset labels; drops the now-unused picker/clear/change
strings.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* [MM-68421] Fix CI: playwright config and ESLint blank line
- Add EnforcePersonalAccessTokenExpiry / MaximumPersonalAccessTokenLifetimeDays
to e2e-tests/playwright/lib/src/server/default_config.ts so its tsc -b
matches the updated ServiceSettings shape.
- Drop a stray double blank line in user_access_token_section.tsx that
tripped no-multiple-empty-lines.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* [MM-68421] Sort i18n keys to match formatjs extract output
ci/i18n-extract diffs en.json against the formatjs extractor's sorted
output and fails on any difference. Re-run the extract so the new
PAT-expiry keys land in alphabetical position.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* [MM-68421] Address CodeRabbit findings
- Clamp the default custom-expiry date to maxLifetimeDays when set
so the form doesn't open in an invalid state when
defaultExpiryPreset() falls back to 'custom'.
- Reject a cleared/empty custom date with expires_at_required
instead of silently submitting without an expiry; only forward
expiresAt to the action when it's > 0.
- Use an explicit undefined check in Client4.createUserAccessToken
so an intentional 0 isn't dropped from the request body.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* [MM-68421] Update manage_tokens_modal snapshot for expiry + status row
The admin token list now renders an Expires row and a status badge per
token; refresh the jest snapshot.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* [MM-68421] Add unit tests for PAT expiry helpers
Per the PR Test Analysis advisory: export the pure helpers from
user_access_token_section.tsx and add unit tests covering them.
Coverage:
- deriveTokenStatus: active / expired / inactive branches.
- mapServerErrorIdToMessage: all three server error ids (short and
api.user.create_user_access_token.*.app_error variants) and the
default null path.
- endOfLocalDayPlusDays: end-of-day on the Nth future day, 0 days.
- endOfLocalDayFromIsoDate: valid ISO date and malformed inputs.
- PRESET_DAYS: snapshot of the preset durations.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* [MM-68421] Freeze time in PAT helper tests to avoid midnight flake
The date arithmetic helpers (Date.now, new Date()) could disagree
across a midnight boundary, making the tests theoretically flaky.
Pin system time to a stable mid-day in 2026 via jest.useFakeTimers.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* [MM-68421] Add component tests for PAT expiry creation UI
Covers the create-form validation branches (missing description, empty
custom date, past date, beyond maxLifetimeDays), enforceExpiry rendering
(no-expiry option hidden + enforced hint), maxLifetimeDays preset
filtering, and token-list status display (active/expired/disabled, never,
and the "expires soon" warning).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [MM-68421] Add behavioral status/expiry tests for manage_tokens_modal
Covers the admin token modal's derived status display: Active + "Never"
for an active token without expiry, Expired for an active token past its
expiry, Disabled for an inactive token regardless of expiry, and Active
with a rendered date (not "Never") for a token expiring in the future.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [MM-68421] Align PAT expiry UI with shipped server contract
The server (#36706) did not ship a separate EnforcePersonalAccessTokenExpiry
flag — expiry enforcement is implied by MaximumPersonalAccessTokenLifetimeDays
> 0. Two webapp gaps surfaced once the server side merged:
- enforceExpiry was read from the never-sent config.EnforcePersonalAccessToken
Expiry, so the "hide No-expiry / require expiry" path was dead. Derive it from
maxLifetimeDays > 0 instead and drop the dead config flag from the component,
redux props, ClientConfig/ServiceSettings types, and the e2e default config.
- The server returns app.user_access_token.expires_at_{required,in_past,too_far}
.app_error, but mapServerErrorIdToMessage matched the api.user.create_user_
access_token.* namespace, so the localized errors never fired. Map the actual
ids.
Unit tests updated accordingly.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [MM-68421] Add Playwright e2e for PAT expiry UI
Covers, against a real server, the personal access token expiry surfaces in
Account Settings > Security:
- the expiry picker renders all presets and reveals the custom-date input
- a custom expiry with no date is blocked client-side
- MaximumPersonalAccessTokenLifetimeDays > 0 hides "No expiry" and oversized
presets, shows the enforced hint, and rejects an over-the-limit custom date
- the token list shows Active/Never, an "expires in N days" warning, and the
Disabled badge (seeded via the API)
The expired-status badge is left to the component unit tests since the server
rejects creating a token whose expiry is already in the past.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [MM-68421] Use locator('option') for native select assertions
getByRole('option') does not reliably match the options of a closed native
<select>, which would make the absence assertions (toHaveCount(0)) pass
vacuously. Query option elements by DOM instead, matching the repo's house
pattern for native selects.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [MM-68421] Fix expiry overshoot vs server cap and review nits
Review found that presets/custom dates resolve to end-of-local-day, which can
sit up to ~24h beyond the server cap of "now + MaximumPersonalAccessTokenLife
timeDays" (an exact duration from creation time). With a max configured, the
default preset equals the cap, so accepting the default and saving was rejected
server-side with expires_at_too_far for most of the day.
- Clamp the submitted expiry to the server cap when a maximum lifetime is set.
Validation still runs on the raw end-of-day value so an explicitly out-of-range
custom date is still rejected; only the in-range end-of-day overshoot is clamped.
- Count "expires in N days" from the start of today and floor it, so an end-of-day
expiry no longer over-reports by one (a 7-day token reads "7 days", not "8").
- Add an aria-label to the custom expiry date input.
Tests: unit coverage for clampExpiresAtToMaxLifetime; a Playwright spec that
creates a token with the default preset under a 30-day cap and asserts success.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [MM-68421] Apply prettier formatting to PAT e2e spec
The ci/playwright/npm-check job (lint + prettier + tsc + lint:test-docs) failed
on prettier formatting. eslint and tsc were clean; reformat the spec to satisfy
prettier as well.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [MM-68421] Add PAT max-lifetime System Console setting and creation-form UX fixes
- Add ServiceSettings.MaximumPersonalAccessTokenLifetimeDays number field to
System Console > Integrations > Integration Management, after Enable Personal
Access Tokens (disabled when tokens are disabled).
- Disable the token creation Save button until a non-empty description is
entered (description input is now controlled; whitespace-only rejected).
- Render the token creation form as a distinct "Create New Token" card so it no
longer blends into the existing token list.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* Fix stylelint property order in new-token card
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* [MM-68421] Validate PAT expiry inline before submit
Surface the expiry validation error in the create-token form and disable
Save while the selection is invalid, instead of only failing inside the
create-confirmation flow. Previously a system admin had to click Save then
"Yes, Create" before seeing "An expiry date is required." for an empty
custom date.
Extracts the expiry checks into getExpiryValidationError(), reuses it as
the handleCreateToken guard, and renders the result inline + in the Save
button's disabled condition.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* [MM-68421] Fix PAT expiry e2e specs for inline validation
The "blocks submitting a custom expiry with no date chosen" and "enforces
expiry when a maximum lifetime is configured" specs clicked the Save button
and expected an inline error afterward. Since
|
||
|
|
6a3b21eb8f |
Mm 68846 masking from visual to canonical walker (#36772)
* MM-68846 - add canonical CEL AST masking walker and model resolver interface * add canonical masking methods to PAP einterface and update mock * Migrate app-layer masking to canonical CEL AST walker * Remove Visual AST masking dead code and obsolete i18n key * Update simulation masking tests to mock MaskExpressionForCaller * reject persisted tokens and enforce merge shape match and add corresponding tests * MM-68900 - abac masking add e2e back * add missing config values and split the tests * implement coderabbit feedback * adjust timeout and disable button logic * enhance masking logic and tests for access control policies * refactor masking tests and database setup for improved field deletion handling * Enhance error handling in TestMergeStoredPolicyExpressions to verify error ID and status code * Refactor error handling in access control policy methods for clarity * Refactor masking logic and improve clarity in access control methods * Allow deny-all 'false' policies by dropping the redundant sentinel check in rejectMaskedTokens; add tests * Add masking-related error messages and update test descriptions with tags * Add error handling for uninitialized Policy Administration Point in access control |
||
|
|
d90ea343bc |
MM-69003 Update ESLint and related dependencies (#37039)
* Remove everything * Re-add most ESLint plugins and run --fix * Additional fixes * Fix or disable linter warnings caused by require imports * Fix how prop types for SearchResults are defined * More additional fixes * Update deprecated stylistic rule names * Remove deprecated .eslintignore * Update eslint-plugin-react-hooks * Enable react-hooks/error-boundaries * Fix react-hooks/static-components wherever possible * Fix react-hooks/use-memo wherever possible * Disable warnings for new rules and update comment * Update eslint-plugin-no-only-tests * Update eslint dependencies in E2E test packages * Remove now-uneeded patch * Address Coderabbit feedback * Actually fix inverted tooltip logic |
||
|
|
4641761122 |
MM - 69063 - team abac backend and security gate (#36903)
* MM-69063 - Add team ABAC model and constants foundation * Add team ABAC store EXISTS, channel Type retrofit, policy count split, and index migration * Add team ABAC app layer: access gate, hydrators, assign/unassign, cleanup, and GetTeamMembersToRemove store * Enforce team membership ABAC on join and hide policy governed teams from non-qualifying users in the directory * Add team_ids to access policy assign/unassign, expose per-team policy GET, and support abac_match_only for not_in_team user listing * Add team ABAC client methods, websocket handler, per-team System Console policy UI, and hide policy-governed teams from non-qualifying users * Make team ABAC mode-aware: advisory on public teams, strict on private, and surface governed private teams to qualifying users in directory listings * Flag-gate team ABAC mutation/read APIs and fix policy-save error handling, member-removal limit, team-id validation, export, and audit cleanup * coderabbit feedback; Broadcast team policy enforcement updates on policy create/update and activation, not only on delete * Update team access control policy schema to allow nullable policies and enhance test cases with channel counts * Enhance access control policy tests to include team policy search alongside channel policy search * Add team membership access control feature flag to docker-compose generation * Implement team access control policy checks and refactor related components * Audit-log team ABAC policy removal on team archive and delete --------- Co-authored-by: Mattermost Build <build@mattermost.com> |
||
|
|
aad6c8afe8 | [MM-69228] Default the CJKSearch feature flag to true (#37032) | ||
|
|
5cbbb76b7b |
MM-69003 Switch to using @stylistic/eslint-plugin for deprecated ESLint rules (#36770)
* MM-69003 Switch to using @stylistic/eslint-plugin for deprecated ESLint rules * Run --fix on all web app packages These changes are mostly around TypeScript linting where the @stylistic versions are more accurate and therefore stricter about spacing and semicolons in TS types. * Run --fix on Cypress tests |
||
|
|
6583982b26 |
Fix stale channel members RHS list after ABAC access-rule member removal (#36964)
* Fix stale channel members RHS list after ABAC member removal The channel members RHS list is built from the profilesInChannel and membersInChannel Redux stores, which are only pruned by the user_removed websocket handler when the affected channel is currently focused. When a removal is not handled over the websocket (e.g. an ABAC access-rule change processed while another channel is focused, or a missed event), reopening the members list performs an additive reload that never prunes removed members, so the list stays stale even though the member count is refreshed separately via getChannelStats. Make the first-page members reload authoritative: reconcile the channel member stores against the server response and prune members the server no longer returns. Scoped to the initial full-membership page to avoid pruning members that belong to later pages. Co-authored-by: mattermost-code <matty-code@mattermost.com> * Add tests for channel members RHS reconcile on reload Covers pruning members the server no longer returns on the first page, and the guards that prevent pruning when reconcile is disabled, on a full page (more pages may follow), or on subsequent pages. Co-authored-by: mattermost-code <matty-code@mattermost.com> * Strengthen channel members reconcile tests Cover pruning across both the member and profile stores, multiple stale members, the no-false-positive case (present members are never pruned), and assert the members RHS passes reconcile=true on its first-page mount reload (but not on pagination). Co-authored-by: mattermost-code <matty-code@mattermost.com> * Tighten reconcile tests with exact-set and perPage guard Co-authored-by: mattermost-code <matty-code@mattermost.com> * Tighten reconcile comment Co-authored-by: mattermost-code <matty-code@mattermost.com> * Add ABAC channel members RHS e2e coverage * Stabilize ABAC RHS e2e sync job wait --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: mattermost-code <matty-code@mattermost.com> |
||
|
|
471fd8d1dd |
Bound document content extraction time and decouple it from uploads (MM-69098) (#36856)
* Bound document content extraction to prevent upload DoS (MM-69098) Extraction of uploaded Office documents ran with no time or size bound and acquired a shared worker-pool slot on the request goroutine, so a low-privilege user could keep cheap-to-upload but expensive-to-extract documents in flight and degrade file uploads for every user on the server. - Enforce a configurable per-extraction timeout (FileSettings.ExtractContentTimeout, default 10s) and honor the previously-ignored size argument in the document and PDF extractors to bound the work performed. - Run extraction on a dedicated, bounded worker pool with non-blocking submit (GoExtraction) so saturating it can never block the request goroutines that dispatch uploads; overflow is skipped and backfilled by the ExtractContent job. - Route the file and resumable-upload extraction dispatch sites through the new pool instead of the shared GoBuffered/Go pools. Co-authored-by: Julien Tant <JulienTant@users.noreply.github.com> * Use require.Fail instead of t.Fatal in extraction pool test The mattermost-govet tFatal analyzer (run by check-style) forbids t.Fatal in tests in favor of testify assertions. Co-authored-by: Julien Tant <JulienTant@users.noreply.github.com> * ci: retrigger workflows (transient container init failure) Co-authored-by: Julien Tant <JulienTant@users.noreply.github.com> * Use sync.WaitGroup.Go for extraction workers Satisfies the golangci-lint waitgroupgo/modernize analyzer flagged by check-style at goroutines.go:58. Co-authored-by: Julien Tant <JulienTant@users.noreply.github.com> * Fix file close race with detached extraction goroutine On timeout, extractWithTimeout returns while the converter may still be reading the input on a detached goroutine. ExtractContentFromFileInfo previously closed the file via defer as soon as Extract returned, racing with (and closing the file out from under) that goroutine. Transfer close ownership to docextractor via ExtractSettings.ReaderCloser: the reader is now closed only after extraction actually finishes - in the detached goroutine on the timeout path, or after Extract returns on the synchronous path. ExtractContentFromFileInfo no longer closes the file itself. Co-authored-by: Julien Tant <JulienTant@users.noreply.github.com> * Document that extraction timeout bounds wait time, not CPU Clarify in ExtractSettings.Timeout and extractWithTimeout that on timeout the docconv converter keeps running on a detached goroutine (docconv is not context-aware), so the timeout bounds how long an extraction occupies a worker slot, not the CPU it consumes. MaxFileSize is the primary bound on per-extraction work. Note load-shedding as a possible future improvement. Co-authored-by: Julien Tant <JulienTant@users.noreply.github.com> * Add tests for PDF size cap and ExtractContentTimeout validation - TestPdfMaxFileSize exercises the LimitedReaderWithError branch in pdf.go: a tight MaxFileSize errors out before extraction, while zero and generous limits extract normally. - TestFileSettingsExtractContentTimeout asserts ExtractContentTimeout=-1 fails IsValid while 0 (disabled) and 10 (default) pass. Co-authored-by: Julien Tant <JulienTant@users.noreply.github.com> * Harden extraction shutdown, panic safety, and timeout input validation - stopExtractionWorkers now drains the queue after signaling stop so a worker cannot dequeue and run buffered tasks during shutdown. - The detached extraction goroutine recovers panics and converts them to errors, so a panic in an extractor cannot crash the server. - Admin console enforces a client-side minimum of 0 for ExtractContentTimeout (validators.minValue). - Test hardening: bounded wait for the detached extractor to start, plus a test that a panic is surfaced as an error. Co-authored-by: Julien Tant <JulienTant@users.noreply.github.com> * ci: retrigger workflows (transient Docker Hub image pull timeout) Co-authored-by: Julien Tant <JulienTant@users.noreply.github.com> * Correct misleading extraction-skip logs and comments The queue-full warning logs and GoExtraction doc comments claimed skipped content would be backfilled by a 'periodic ExtractContent job'. That job is registered with a nil scheduler, so it never runs automatically -- it only runs when an admin manually triggers a content extraction job (mmctl extract). Reword the logs and comments to state that skipped files stay unsearchable until an admin runs a content extraction job, so we don't imply automatic recovery that doesn't exist. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Julien Tant <JulienTant@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
f3836530b7 |
MM-69003 Mostly share ESLint config between web app and E2E tests (#36767)
* Switch Cypress to use shared ESLint config * Run --fix in Cypress * Manually fix remaining lint issues in Cypress * Switch Playwright to use shared ESLint config * Run --fix in Playwright * Manually fix remaining lint issues in Playwright * Install and cache web app deps during Cypress CI builds This also caches the types and client package. That isn't needed currently since it uses prepackaged versions of those, but I imagine we might change that at some point. * Run e2e-tests-check when ESLint plugin is updated * Change E2E test GHA caching to cache all of web app node_modules * Fix mismatch between cache save and restore * Try bumping cache keys * Copy step to install dependencies to server.run_cypress.sh I don't know how this must've worked before, but if this fixes the issue, it seems like neither Cypress nor Playwright actually use the cached depenendencies. * Try disabling caching entirely for Cypress tests * Try bypassing makefile? * Try also manually building dependencies in run_specs.sh I don't know why this appears to duplicate run_cypress.sh and run_playwright.sh, both of which are called run_test.sh which might not be used any more as best I can tell. * Try installing the web app dependencies in yet another place * Disable the extra steps in server.prepare.sh specifically for Cypress * Revert changes to update cache key and disable web app depenedency cache on Cypress builds |
||
|
|
684ddb32a9 |
[MM-68988][MM-68989][MM-68990][MM-68991][MM-68997][MM-68998] Session Attributes MVF - Server-work (#36934)
* [MM-68988][MM-68989][MM-68990][MM-68991][MM-68997] Session Attributes MVF - Server-work * PR feedback * [MM-68998] Add web app hooks for Desktop App to signal a refresh of attributes/manifest * Fix types * Adjust the test to test the license first * PR feedback * Coderabbit feedback * More tests |
||
|
|
f6e7e71695 |
Migrate Zephyr manual tests to Cypress E2E (#36971)
* MM-T1814: add 'Add a BOT to a team' Cypress E2E test Co-authored-by: Maria A Nunez <maria.nunez@mattermost.com> * MM-T1335: invite guests to public and private channels Extend invitePeople() helper to accept multiple channels and add a spec verifying both a public and a private channel are added to the guest invite list. Co-authored-by: Maria A Nunez <maria.nunez@mattermost.com> * MM-T1340: verify guest invite email and join flow (not_cloud) Add a non-cloud spec covering step 2 of MM-T1340: read the invitation email, open the join link, complete guest signup, and verify the guest is added to the team. Co-authored-by: Maria A Nunez <maria.nunez@mattermost.com> * MM-T1335: assert channel chips via icons and count Verified against a licensed E2E server: assert exactly two channel chips with public and private channel icons rather than an exact text match, which failed due to extra text in the chip label. Co-authored-by: Maria A Nunez <maria.nunez@mattermost.com> * MM-T1340: accept terms and use valid password in guest signup Verified against a licensed E2E server: the signup Create account button is gated on a 14+ char password and the terms/privacy checkbox. Use newTestPassword(), check the agreement, and assert the app loads. Co-authored-by: Maria A Nunez <maria.nunez@mattermost.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> |
||
|
|
ffd4814940 |
MM-T3436: add Cypress E2E for Actiance XML compliance export download (#36970)
Add a Cypress test covering Zephyr case MM-T3436, verifying that with DownloadExportResults enabled and the Actiance XML export format, a compliance export provides a Download link and the downloaded archive contains the posted message content and the file attachment. Reuses existing compliance helpers (uiEnableComplianceExport, uiExportCompliance, gotoTeamAndPostImage, downloadAndUnzipExportFile, verifyActianceXMLFile); modeled on MM-T1173 without the delete step. Co-authored-by: Cursor Agent <cursoragent@cursor.com> |
||
|
|
aa03fae744 |
[MM-69026] Add zoom and pan to the image file preview (#36775)
* [MM-69026] Add zoom and pan to the image file preview Enables the existing file-preview-modal zoom controls for image previews (previously PDF-only) and adds cursor-aware wheel zoom, drag-to-pan, keyboard shortcuts, and overflow clipping so the panned image can't escape behind the modal header. - Per-file default scale (1.0 for images, 1.75 stays for PDFs). - Translate state alongside scale; auto-snaps to the origin at default scale. - Native non-passive wheel listener so preventDefault actually fires. - Wheel step scaled by deltaY magnitude for trackpad pinch. - Keyboard: +/=, -, 0; skipped when an input/textarea/contentEditable is focused. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Fix eslint no-mixed-operators and lines-around-comment Parenthesise mixed +/* and -/ arithmetic to satisfy eslint(no-mixed-operators) and add the blank line before the inline-input guard comment for lines-around-comment. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Cap image zoom at 2x and harden lifecycle / drag-pan - Add ZoomSettings.MAX_SCALE_IMAGE = 2.0 and route image-path clamp sites through a new FilePreviewModal.getMaxScaleForFile. PDFs keep the original 3.0 ceiling. - Reconcile scale/translate in getDerivedStateFromProps when props.fileInfos changes so newly appearing indexes get seeded with the file's default instead of reading as undefined. - Gate drag-to-pan on currentScale > defaultScale so dragging at default scale (image fits the viewport) doesn't slide the image around in empty space. - Tighten the e2e style-match regex so it only accepts scale values strictly greater than 1. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Reset image zoom state on same-length file swaps A websocket post update can replace an attachment at the same index without changing the array length, which previously bypassed the length-based reconciliation in getDerivedStateFromProps and let the old file's zoom/translate state apply to the new file. Track a per-index identity (file id, falling back to link) and trigger the same reconciliation when any identity differs at its index; indexes whose identity is unchanged keep their existing scale/translate. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Add unit tests for zoom-related instance behavior and helpers Covers the gaps flagged by Tests/analysis: - Static helpers getDefaultScaleForFile, getMaxScaleForFile, and getFileIdentity (incl. namespace separation for file vs link identities). - handleKeyDown: +/= zoom in, - zoom out, 0 reset, modifier-key bailout, and the INPUT-focus guard. - handleImageMouseDown drag gate: ignored at default scale and on non-left-button mousedowns; sets isDragging when zoomed. - handleImageWheel clamping at MAX_SCALE_IMAGE (2.0) and MIN_SCALE (0.25), plus deltaY=0 short-circuit. - getDerivedStateFromProps identity reconciliation: same-length swap resets the affected index while preserving others; list growth seeds the new index with the file's default. 68 tests pass (was 50). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |