mirror of
https://github.com/mattermost/mattermost.git
synced 2026-11-02 20:31:01 -06:00
master
23773
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
cbdf4c779b |
Migrate FeatureDiscovery to Compass FeatureDiscoveryPanel (#39051)
* Migrate FeatureDiscovery to Compass FeatureDiscoveryPanel Replace legacy SkuTag and layout markup with Compass FeatureDiscoveryPanel while keeping trial, cloud, and sales logic in the host adapter. Map license SKUs to panel skuLabel, pass feature SVGs via illustration.children, and use Compass button actions for contact-sales flows with host-rendered Start trial CTAs on self-hosted. Preserve existing test ids and trial legal copy keys. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Use medium button size in FeatureDiscoveryPanel actions Post-trial Contact sales / Learn more actions were forcing large buttons; align them with the panel default and other CTA paths. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Restore FeatureDiscovery SKU tag as opt-in for Compass panel Pass null when showSkuTag is unset so FeatureDiscoveryPanel does not fall back to its PROFESSIONAL default. Add unit coverage for both cases. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Simplify AutoTranslation FeatureDiscovery to panel defaults Drop AdminSection/SectionContent wrappers and CSS that unset FeatureDiscoveryPanel styles. Keep auto-translation from wrapping with a non-breaking hyphen in the title and copy. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Revert non-breaking hyphen in AutoTranslation discovery copy Keep a normal hyphen in the title and body; drop the matching test change. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Bump compass-ui to alpha.15 and use Button asChild for Learn more Upgrade @mattermost/compass-ui so Feature Discovery Learn more can render as a styled ExternalLink via asChild instead of nesting an anchor in a button (fixes hover underline and invalid HTML). Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Reuse SkuTag licenseSkuToLabel for FeatureDiscovery skuLabel Export the existing SKU→label mapping from SkuTag and delete the duplicated feature_discovery_sku_label helper. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Drop redundant FeatureDiscovery panel/illustration CSS Remove width and imageWrapper flex overrides now covered by Compass FeatureDiscoveryPanel. Keep host-trial overlay and trial extras styles. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Move host Start trial into FeatureDiscoveryPanel actions Use Compass primary/secondary actions for self-hosted Start trial via withOpenStartTrialFormModal, and drop the overlay footer CSS that stacked StartTrialBtn over the panel. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Fix FeatureDiscovery eslint nested ternary and comment spacing Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Allow data-testid on FeatureDiscovery panel button props Compass ButtonProps does not declare data-testid; widen the local primary-action type so Cypress selectors keep working and tsc passes. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Bump compass-ui to 0.1.0-alpha.18. Co-authored-by: Cursor <cursoragent@cursor.com> * Update snapshots for compass-ui radio class hashes. Co-authored-by: Cursor <cursoragent@cursor.com> * Revert the compass-ui alpha.18 bump. Feature Discovery uses FeatureDiscoveryPanel and Button asChild, which match alpha.15 already on master. Alpha.16 only changed the Radio CSS module hash, and that rewrote unrelated radio snapshots. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Select Feature Discovery titles by test id in Cypress. The title test id is on a span inside the panel heading, so a div selector misses it. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Matthew Birtch <2040554+matthewbirtch@users.noreply.github.com> |
||
|
|
e3d074ff02 |
Migrate Toggle to Compass Switch (#39038)
* Migrate Toggle component to Compass Switch adapter Rewrite components/toggle.tsx to wrap @mattermost/compass-ui Switch with prop mapping and sibling labels for onText/offText. Update Jest tests and snapshots for switch/checkbox semantics (role=switch, checked state). Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Place Toggle onText/offText on Compass Switch label Pass state text through Switch children so Public/Private sits left of the control and remains clickable for accessibility. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Use medium Compass Switch for plugin enable control PluginEnableButton Toggle size btn-sm → btn-md (Compass Switch medium). Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Stop forwarding legacy btn-toggle classes onto Compass Switch Toggle is a Compass Switch adapter; call sites still passed toggleClassName='btn-toggle-primary', which painted the old gray rectangular track chrome from _toggle.scss behind the Switch. Remove the prop, drop those call-site classNames, and delete the unused legacy toggle stylesheet. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Fix post priority Switch double-toggle in menu items Clicking the Compass Switch inside ToggleItem fired both Switch onChange and MenuItem onClick for the same gesture, so the handler ran twice and the control appeared stuck. Stop click propagation on the switch and add a unit test covering switch and row activation. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Use Compass Switch settings-row for channel settings toggles Replace custom __text + Toggle header rows with Switch children + secondaryLabel for configuration, discoverable, and shared-channels sections. Drop obsolete header SCSS; keep existing testids/behavior. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Migrate Admin Console LineSwitch rows to Compass Switch Replace Toggle-based LineSwitch with AdminSettingsSwitch (children + secondaryLabel), covering group mentions, team modes, and channel modes. Public/Private uses state text as the primary label; domain input stays as a footer under the switch. Delete unused LineSwitch styles and update Cypress selectors for role=switch inputs. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Migrate remaining Toggle call sites to Compass Switch Replace production Toggle adapters with direct @mattermost/compass-ui Switch usage across new channel modal, post priority, recaps, plugin enable, user properties, auto-translation, IP filtering, and content flagging reviewers. Delete the unused Toggle component and its tests. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Document medium Switch size for Admin Console Public/Private row AdminSettingsSwitch intentionally uses Compass medium (14px) + semiBold so short state labels like Public/Private match Channel Settings and do not inherit the old Toggle btn-lg → large (16px) default. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Fix Team Modes separator when Sync Group Members is on Omit the Sync row section separator only when no later row is visible. ABAC still renders disabled while synced, so last must not track isSynced alone. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Use static Public/Private Switch title in Channel Management Stop swapping Switch children between "Public" and "Private". Keep a static "Public channel or private channel" label with help text as secondaryLabel; checked remains public and unchecked private. Update Cypress assertions and channel_modes snapshots accordingly. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Show current Public/Private mode on channel Switch label Use a dynamic primary label (Public channel / Private channel) so checked state is scannable without a segmented control. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Update Cypress for dynamic Public/Private Switch labels Assert Public channel when checked and Private channel when unchecked. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Fix plugin enable Switch alignment next to actions menu Zero Bootstrap label margin-bottom and Switch width:100% on the PluginMetadataPanel enable control so it lines up with the ⋯ button. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Use segmented Public/Private control in Channel Management Replace the ambiguous Switch for channel privacy with a temporary AdminSettingsSegmentedRow (Public | Private) until Compass ships a segmented control. Update Cypress selectors accordingly. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Fix IP Filtering enable Switch not revealing edit config Use event.checked for the Compass Switch, skip the filterToggle sync effect while ipFilters is still null so an empty [] does not race the fetch, and show EditSection whenever filters are loaded and the toggle is on (do not wait on currentUsersIP). Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Increase Public/Private segmented control border radii Round the track to 8px and active segments to 4px for a softer Channel Management Public/Private control. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Increase Public/Private segmented control track padding Bump &__segments padding from 2px to 4px. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Soften Public/Private segmented control border Lower track border opacity from 0.16 to 0.08. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Darken Public/Private segmented control track background Raise &__segments background opacity from 0.04 to 0.08. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Address review comments on Switch a11y and formatting Align LDAP Cypress private-toggle assertion indentation, add aria-labels on IP Filtering and Auto-translation switches, and fix AdminSettingsSwitch import order for eslint import/order. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Fix eslint failures blocking Web App CI check-lint Add blank line before comment in channel_modes and reorder imports in post_priority_picker_item.test to satisfy import/order. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Align en catalogue isPublicDescr with segmented control copy Update admin.channel_settings.channel_details.isPublicDescr to say "Use this control" instead of "Use this switch", matching channel_modes. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Fix Switch migration CI failures in unit and Playwright tests Update recap configuration queries to role=switch, refresh channel_details snapshots for the Public/Private segmented control, and assert/set Compass Switch via aria-checked check/uncheck in Playwright helpers and related specs. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Stabilize Switch snapshots and fix Playwright check interception Mock Compass Switch CSS-module styles in Jest so snapshots no longer embed install-specific content hashes, and use force:true on Switch check/uncheck so the wrapping label does not intercept pointer events. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Update Channel Management Public/Private docs for segmented control Replace toggle wording with select Public or Private, and refresh the System Console screenshot to match AdminSettingsSegmentedRow. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Revert Public/Private docs wording; keep screenshot refresh only The step text can stay as toggle between Public or Private; only the stale screenshot needed updating for the segmented control. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Refresh Sync Group Members channel docs screenshot for Compass Switch Replace the stale Channel Management flip-toggle image with an updated System Console capture showing Sync Group Members enabled. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Refresh Anyone can join this team docs screenshot for Compass Switch Replace the stale Team Management flip-toggle image with an updated System Console capture showing Anyone can join enabled. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Refresh specific email domains team docs screenshot for Compass Switch Replace the stale Team Management flip-toggle image with an updated System Console capture showing email-domain restriction enabled. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Refresh Public/Private channel docs screenshot for segmented control Replace the Channel Management Public/Private docs image with an updated System Console capture showing the Public|Private segmented row. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Refresh Sync Group Members team docs screenshot for Compass Switch Replace the stale Team Management flip-toggle image with an updated System Console capture showing Sync Group Members enabled. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Fix Playwright Switch assertions for join/leave and scheduled recaps Assert join/leave defaults with toBeChecked instead of the legacy active CSS class, and pause/resume scheduled recaps via click plus polled expect helpers so async-controlled Compass Switches can settle. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Bump @mattermost/compass-ui to 0.1.0-alpha.15 Upgrade the Compass UI dependency used by Switch and related admin console controls. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Restore currentUsersIP gate for IP Filtering EditSection Keep the Toggle→Switch migration scoped to the adapter swap. Showing EditSection still requires the user's IP to be loaded, matching prior behavior. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Fix plugin install Cypress asserts for Compass Switch aria-checked Plugin enable controls use Switch (aria-checked), not segmented buttons (aria-pressed). Update MM-T5714/MM-T5715 assertions accordingly. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Revert IP Filtering filterToggle sync to master behavior The ipFilters === null early return and consolidated map were outside the Toggle→Switch swap scope and mildly changed load-time behavior. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> |
||
|
|
d87f9beedb |
[MM-71163] Enable the metrics plugin by default when Performance Monitoring is enabled (#39142)
* MM-71163: Enable the metrics plugin by default when performance monitoring is enabled Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * MM-71163: Leave metrics plugin state unset while performance monitoring is off Writing an explicit false on first load meant existing installs never got the plugin enabled when performance monitoring was turned on later. Also apply LogSettings defaults before PluginSettings, which reads them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
0cfb066fe4 | drip: AppError -> error: password migration (#39312) | ||
|
|
82b042b9b2 |
Redesign and refactor system console logs view (#35569)
* Overhaul Server Logs admin view for better sysadmin experience
Rewrites the Server Logs view from the ground up to address major
usability issues: truncated messages, wasted screen space, no visual
hierarchy, no live updates, and painful navigation on busy servers.
Key changes:
- Rewrite all components as functional React (hooks) replacing class components
- Replace rigid DataGrid table with purpose-built log viewer layout
- Color-coded log level badges (error=red, warn=amber, info=blue, debug=gray)
- Row background tinting for error/warn entries
- Inline row expansion replacing modal-only "Full Log event" workflow
- Compact timestamps (HH:MM:SS.mmm) with full timestamp on hover
- Log level quick-filter toggle buttons with counts (like browser DevTools)
- Configurable page size (50/100/200/500, default 200)
- Polling-based live tail with configurable interval (2s/5s/10s/30s)
- Time range presets (5m/15m/1h/24h) using existing API date params
- Search highlight with match count display
- Keyboard navigation (j/k, Enter expand, e jump to error, / search)
- Text wrapping and compact/comfortable density toggles
- Preferences persisted to localStorage
- Empty state with clear-filters action
- Warn-level color coding added to plain text view
- Updated tests for new component structure
https://claude.ai/code/session_012NLTVDoJnzFJDRduBKrxv9
* Update package-lock.json after dependency installation
https://claude.ai/code/session_012NLTVDoJnzFJDRduBKrxv9
* Fix four UX issues in server logs view
1. Pagination buttons no longer shift - page indicator has fixed min-width
2. Keyboard shortcuts shown via hover tooltip on ? button instead of
raw unicode in footer
3. Empty toolbar buttons replaced with text labels (Compact/Comfortable,
Wrap/No wrap) since compass-icons lacks line-spacing/wrap icons
4. Top banner buttons properly spaced with vertical separators between
format toggle, time presets, live tail, and action buttons
https://claude.ai/code/session_012NLTVDoJnzFJDRduBKrxv9
* Fix remaining UX issues in server logs view
1. Remove Compact/Comfortable density toggle - always use compact mode
2. Fix pagination button shifting - footer-info and page-indicator have
fixed min-widths, left group keeps all pagination controls together
3. Replace invisible ? tooltip with proper keyboard shortcut hints
rendered as styled kbd elements in the footer
4. Restyle Reload/Download buttons as small tertiary buttons with icons
(icon-refresh, icon-download-outline) to match the rest of the toolbar
https://claude.ai/code/session_012NLTVDoJnzFJDRduBKrxv9
* Redesign server logs toolbar for a cleaner, more professional layout
Move all toolbar controls into LogViewer component with two-row layout:
actions row (time presets, live tail, reload, download) and filter row
(search, level pills, wrap toggle). Rewrite SCSS to match new structure
with unified action-btn style, proper toolbar grouping, and per-level
color-coded pill states.
https://claude.ai/code/session_012NLTVDoJnzFJDRduBKrxv9
* Fix time filter using local time instead of UTC
The formatDate helper used local time methods (getHours, etc.) but
appended a +00:00 UTC offset, causing the date range to be shifted
by the user's timezone offset. Use UTC methods to match the offset.
https://claude.ai/code/session_012NLTVDoJnzFJDRduBKrxv9
* Enhance log detail view with copy buttons and admin deep links
- Add inline copy-to-clipboard buttons on ID fields, caller, URL, and
other copyable values
- Deep link user_id, team_id, and channel_id to their admin console
pages (only when value matches Mattermost 26-char ID pattern)
- Split detail view into core fields section and extra fields section
with a visual separator for better hierarchy
- Add "Copy log line" action alongside existing "Copy JSON"
- Style copy buttons as subtle icons that appear inline with values
https://claude.ai/code/session_012NLTVDoJnzFJDRduBKrxv9
* Fix plain text toggle not fetching logs on format switch
onLogFormatToggle only set the isPlainLogs state but never triggered
a data fetch, so switching to plain text showed an empty view and
switching back to JSON showed stale data. Now explicitly fetch the
appropriate log format on toggle.
https://claude.ai/code/session_012NLTVDoJnzFJDRduBKrxv9
* Rewrite plain text log view with toolbar and better UX
Rewrite PlainLogList as a functional component with:
- Toolbar with Reload, Download, Wrap toggle, and Copy All buttons
matching the JSON viewer's design language
- Proper footer with page info, chevron pagination buttons, and a
"Scroll to bottom" button that appears when you scroll up
- Smart follow-tail: auto-scrolls on new data, disengages when you
scroll up manually, re-engages when you scroll back to bottom
- Color-coded error/warn lines with hover highlight
- Theme-aware styling (no more hardcoded white background)
- Dedicated SCSS file instead of relying on legacy admin-console styles
https://claude.ai/code/session_012NLTVDoJnzFJDRduBKrxv9
* Fix null crash in PlainLogList when logs prop is null
Redux state can be null before the plain logs fetch resolves, causing
a TypeError on .length access. Default to empty array.
https://claude.ai/code/session_012NLTVDoJnzFJDRduBKrxv9
* Add line numbers, syntax highlighting, and fix wrap in plain text view
- Fix wrap adding newlines: changed from white-space pre-wrap on the
line div to wrapping only the inner text span, and removed padding
that caused visual offset
- Add non-selectable line numbers via CSS ::before pseudo-element with
user-select: none, so Ctrl+A copies only log text
- Add line number toggle button in toolbar
- Add JSON/JSONL syntax highlighting: keys in blue, strings in green,
numbers/bools in amber, brackets dimmed
- Add plain log format highlighting: timestamp dimmed, level tags
color-coded (error=red, warn=amber, info=blue, debug=gray),
key=value pairs with colored keys
- Memoize highlighted lines to avoid re-rendering on scroll/toggles
https://claude.ai/code/session_012NLTVDoJnzFJDRduBKrxv9
* Fix syntax highlighting contrast and page info unicode escape
- Replace CSS variable colors with hardcoded high-contrast values for
syntax highlighting (GitHub-style palette): keys #0550ae, strings
#0a3069, numbers #953800, error #cf222e, warn #9a6700
- Fix \u00B7 rendering literally in page footer by using the actual ·
character in the defaultMessage string
https://claude.ai/code/session_012NLTVDoJnzFJDRduBKrxv9
* Add sort order toggle and improved pagination to plain text view
- Fix line number button being shorter than siblings by adding a
text label ("Lines")
- Add newest-first/oldest-first sort toggle (client-side reverse)
with sort-ascending/sort-descending icons
- Replace simple prev/next with full pagination: first page, prev,
clickable page number, next buttons
- Click the page number to open a "Go to page" input with Enter to
navigate and Escape to dismiss
- Line numbers stay correct when reversed (count down from total)
- Pass goToPage callback from parent logs.tsx
https://claude.ai/code/session_012NLTVDoJnzFJDRduBKrxv9
* Fix missing icons for sort toggle and first-page button
Replace non-existent compass icons with available alternatives:
- sort-ascending/sort-descending -> arrow-up/arrow-down
- page-first -> « (double chevron character) with styled span
These icons were not in the @mattermost/compass-icons set.
https://claude.ai/code/session_012NLTVDoJnzFJDRduBKrxv9
* Fix all lint errors and add PlainLogList tests
- Fix 29 ESLint errors: unused imports, prop placement, regex wrapping,
mixed operators, ExternalLink usage, nested ternaries, consistent-return
- Fix 47 Stylelint property order errors in both SCSS files
- Add 17 tests for PlainLogList component covering rendering, pagination,
toolbar toggles, go-to-page, and empty/loading states
https://claude.ai/code/session_012NLTVDoJnzFJDRduBKrxv9
* Address code review findings
- Extract shared LogObjectWithAdditionalInfo type into types.ts
- Remove unused onFiltersChange prop from LogList and dead code in logs.tsx
- Fix potential interval stacking in useLogPolling visibility handler
- Add error handling for navigator.clipboard calls (non-HTTPS fallback)
- Fix highlightSearchTerm to highlight all occurrences, not just first
- Remove unused compact prop from LogRow (was always hardcoded true)
- Translate hardcoded strings in CopyButton and DetailValue with useIntl
- Fix time preset buttons to use intl.formatMessage for i18n
https://claude.ai/code/session_012NLTVDoJnzFJDRduBKrxv9
* Fix recursive clipboard call, LogObject reference, and stylelint errors
- Fix copyToClipboard calling itself instead of navigator.clipboard
- Move import to before function declaration
- Replace unimported LogObject with LogObjectWithAdditionalInfo
- Fix CSS property order in _admin-console.scss
https://claude.ai/code/session_012NLTVDoJnzFJDRduBKrxv9
* Fix duplicate i18n message IDs with different defaultMessages
Rename admin.logs.loading and admin.logs.noLogs in plain log view
to admin.logs.plain.loading and admin.logs.plain.noLogs to avoid
conflicts with the JSON log view which uses different default text.
https://claude.ai/code/session_012NLTVDoJnzFJDRduBKrxv9
* Persist log format preference and rename JSON to Structured
- Remember the user's Structured/Plain text choice in localStorage
so it persists across page navigations and sessions
- Rename "JSON" label to "Structured" since the view now offers
filtering, live tail, keyboard nav, and expandable detail rows
- Only applies when the server supports both formats (toggle visible)
https://claude.ai/code/session_012NLTVDoJnzFJDRduBKrxv9
* Fix review findings: accessibility, type safety, polling, and theme support
- Add aria-labels to icon-only pagination and clear-preset buttons
- Reset page/expandedIndex/focusedIndex when logs dataset changes
- Fix extraFields filter to use != null instead of truthiness check
- Guard handleKeyDown from bubbling up from interactive descendants
- Refactor copyToClipboard to return Promise, set success only on resolve
- Fix live-tail with time presets by recomputing date range dynamically
- Fix duplicate reload on mount with hasMountedRef guard
- Fix LogObjectWithAdditionalInfo index signature to use unknown
- Add immediate fetch when polling enables
- Guard against duplicate intervals in visibility change handler
- Use ICU number formatting in i18n strings
- Replace hardcoded colors with theme-aware CSS variables
- Extract isPlainChar helper for readability
- Show copy failure feedback in plain log view
https://claude.ai/code/session_012NLTVDoJnzFJDRduBKrxv9
* Replace custom JSON highlighter with highlight.js
Use the project's existing highlight.js dependency and SyntaxHighlighting
utility for JSON syntax highlighting in the plain log viewer. This:
- Removes ~120 lines of custom JSON tokenizer (highlightJson, findStringEnd,
isPlainChar) and 5 custom CSS classes
- Uses async highlight.js with the user's selected code theme (github,
monokai, solarized-dark, solarized-light) for consistent styling
- Renders JSON lines with dangerouslySetInnerHTML inside .hljs container
- Shows sanitized HTML as initial fallback while highlight.js loads the
JSON grammar asynchronously
- Keeps custom highlightPlainLog for Mattermost's [LEVEL] key=value format
https://claude.ai/code/session_012NLTVDoJnzFJDRduBKrxv9
* Fix hljs background override in plain log viewer
The highlight.js theme CSS sets background on .hljs elements (typically
white), causing JSON log lines to have a white background instead of
inheriting from the log viewer. Override to transparent.
https://claude.ai/code/session_012NLTVDoJnzFJDRduBKrxv9
* Update webapp/channels/src/i18n/en.json
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* Add visible focus indicator to search input in log viewer
The search input had outline: none with no replacement focus style,
making it invisible to keyboard users. Add :focus-within on the
wrapper to show a border + box-shadow ring matching the theme's
button-bg color when the input is focused.
https://claude.ai/code/session_012NLTVDoJnzFJDRduBKrxv9
* Use React Router Link for admin deep links in log row
Replace plain <a href> with React Router <Link to> for admin console
deep links (user_id, team_id, channel_id). This ensures links work
correctly on subpath deployments where the app is served from e.g.
/mattermost, since React Router automatically prepends the basename.
Also gives client-side navigation instead of full page reloads.
https://claude.ai/code/session_012NLTVDoJnzFJDRduBKrxv9
* Fix follow-tail to honor newestFirst sort order in plain log viewer
When newestFirst is true, the tail (newest entries) is at the top of
the scroll container. Updated three locations:
- Auto-scroll useEffect: scrolls to top when newestFirst, bottom otherwise
- handleScroll: detects proximity to top as "at tail" when newestFirst
- Scroll-to-tail button: scrolls to top and shows up arrow when newestFirst
https://claude.ai/code/session_012NLTVDoJnzFJDRduBKrxv9
* Refactor copyToClipboard to guard navigator.clipboard and propagate errors
- Check for navigator.clipboard availability before calling writeText,
rejecting the promise if unavailable instead of silently swallowing
- CopyButton now awaits the promise before showing success feedback
- All copy handlers (handleCopyJson, handleCopyLine, handleKeyDown 'c')
now have .catch() handlers so unhandled rejections don't occur
https://claude.ai/code/session_012NLTVDoJnzFJDRduBKrxv9
* Clamp page index and clear stale selection on dataset changes
Previously the reset effect always set page to 0 when logs changed,
losing the user's position on reloads and live-tail updates. Now:
- Filter/sort changes still reset to page 0
- Dataset changes (reload, live-tail) clamp page to valid range
- handlePageSizeChange also clears focusedIndex (was missing)
https://claude.ai/code/session_012NLTVDoJnzFJDRduBKrxv9
* Guard navigator.clipboard in handleCopyAll to prevent TypeError
Check navigator.clipboard?.writeText exists before calling it. In
non-secure contexts where the Clipboard API is unavailable, show the
failure state immediately instead of throwing a synchronous TypeError.
https://claude.ai/code/session_012NLTVDoJnzFJDRduBKrxv9
* Preserve wall-clock time in formatTimestampShort
Extract the time substring directly from the raw timestamp string via
regex before attempting Date parsing. This avoids toISOString() converting
to UTC and losing the original timezone offset from the server logs.
https://claude.ai/code/session_012NLTVDoJnzFJDRduBKrxv9
* Fix "1 lines" pluralization in plain log viewer page info
Use ICU plural syntax so the message reads "1 line" (singular) and
"N lines" (plural) instead of always showing "lines".
https://claude.ai/code/session_012NLTVDoJnzFJDRduBKrxv9
* Align header column widths with row layout in log viewer
Header widths were mismatched with row columns:
- header-level: 40px → 32px (matches LogRow level badge)
- header-timestamp: 100px → 92px (matches LogRow timestamp)
- header-caller: 200px → 216px (192px caller + 8px gap + 16px expand indicator)
https://claude.ai/code/session_012NLTVDoJnzFJDRduBKrxv9
* Prevent overlapping poll fetches in useLogPolling
Added an isPollingRef guard so tick() returns immediately if a previous
fetch is still in-flight. Applied to both the main polling effect and
the visibility-resume branch to prevent concurrent fetches when
fetchLogs takes longer than intervalMs.
https://claude.ai/code/session_012NLTVDoJnzFJDRduBKrxv9
* fix linter errors
* Fix post-merge lint and E2E fallout from master
- useMemo(loadPrefs, []) -> inline arrow, for react-hooks/use-memo which
landed with the ESLint 9 upgrade (#37039).
- Restore the trailing comma in logs.tsx dropped while resolving the
conflict, for @stylistic/comma-dangle (#36770).
- Update the MM-T908 Cypress spec, which still asserted on .LogTable and
the old banner reload button; both were replaced by the LogViewer
markup on this branch.
* Remove CSS orphaned by the log viewer rewrite
.log__panel, .banner-buttons (incl. the __separator this branch added)
.LogTable and .plain-log-list no longer match anything: the class
components that rendered them were replaced by LogViewer/PlainLogViewer,
which carry their own flex sizing in log_list.scss / plain_log_list.scss.
* Add unit tests for LogRow and useLogPolling
The log viewer rewrite added log_row.tsx and use_log_polling.ts without
tests, while its sibling plain_log_list.tsx got a dedicated suite.
LogRow (51 tests): expand/collapse by click and Enter/Space, the `c` copy
shortcut, the copy-line format, search highlighting, extra field
rendering with admin console deep links, level classes, and the
stopPropagation that keeps the copy controls from toggling the row.
useLogPolling (21 tests): the immediate fetch on enable, interval
restarts, the re-entrancy guard, and the visibilitychange pause/resume.
The advance() helper flushes microtasks before advancing the fake
timers, otherwise the re-entrancy guard swallows the next tick and
several tests pass for the wrong reason. The resume test asserts on
jest.getTimerCount() rather than call counts, because counting fetches
cannot distinguish one interval from two.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* Harden the server logs live-tail polling
A failed poll rejected out of the interval callback with nothing to
catch it, so any 500 or network blip from /api/v4/logs during live tail
surfaced as an unhandled promise rejection in the admin's browser.
Catch it and let the next tick recover.
Also collapse the two copies of the tick closure into one, so the
visibilitychange resume path cannot drift from the main effect.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* Address review feedback on the server logs viewer
Restore the search debounce (PR review): the rewrite filtered on every
keystroke with the input value owned by the parent, so typing was gated
on a pass over every fetched log entry. /logs/query sends no pagination,
so the server returns up to LogsPerPageDefault (10000) entries per node.
The input value is now local to LogList and the term is debounced
upwards at 200ms, matching the interval the class component used.
Clearing bypasses the debounce so it feels immediate.
Fix the grid semantics (PR review): rows carried role='row' with plain
spans as children, the column header sat outside the role='grid'
container with no columnheader roles, and the empty state was a
non-row child. Drop to role='list'/'listitem', which matches the
row-level arrow key navigation that is actually implemented, and move
the disclosure semantics onto the row summary so aria-expanded sits on
a role that supports it. The keyboard navigation now focuses
.LogRow__main, and the empty state and refreshing indicator moved out
of the list so it only owns list items.
Also stop background polls from touching the loading state, and hoist
the repeated date formatting and filter constants.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* Extract the remaining hardcoded strings in the logs viewer
The rewrite left literal strings in the level filter pills, the plain
text viewer controls and several titles. Move them to defineMessages so
they are translatable and extractable, and sync en.json.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* Keep the expanded log row stable across reloads
The expanded row was tracked by its index in the visible page, so a
reload or a live-tail poll either collapsed it or moved the expansion to
whatever log now sat at that index. Track it by content instead, and
give repeated identical lines distinct React keys.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* Remove the stale User/Token ID lookup hint from the logs page
The banner told admins to look up a User ID or Token ID by pasting it
into the User Management search filter. That search is the user report
query, whose searchable columns are Username, FirstName, LastName,
Nickname and Email, so neither kind of ID matches anything.
It worked until the new User Management screen replaced the old page in
|
||
|
|
346c94f0d6 |
Normalize changelog generator output, handle major-version rollover, and keep reviewer edits on reruns (#38478)
* Tighten changelog generator formatting rules and normalize output Refines the SYSTEM_PROMPT in the changelog generator and adds a deterministic post-processing pass so generated entries match the established changelog format without manual cleanup. SYSTEM_PROMPT changes: - State the exact bullet indentation convention: one space for top-level bullets, three for nested ones. The previous instruction asked for two spaces, which did not match the changelog file. - Give the Database Schema Changes subsection an explicit shape: a summary bullet naming the release, with each individual change nested beneath it. - Extend the config.json block with a removed-setting example and spell out that removed settings are top-level bullets rather than nested under a plan grouping. - Show the Improvements section verbatim so the blog post line lands immediately after the heading with no blank line between them. - Strengthen the prohibition on horizontal rules, which break the MDX document, into an explicit NEVER in both the section-structure and markdown-formatting rules. Add normalize_formatting(), applied to the model output before the entry is assembled. The prompt specifies all of these, but compliance is not guaranteed and each mistake produces a visibly wrong diff: - strips standalone horizontal rules - reduces even bullet indents by one (2 -> 1, 4 -> 3) - closes a blank line between ### Improvements and its blog post line - collapses the blank-line runs left behind by rule removal Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Nrmq4ezefYWqa9YkxtX3mR * Escape MDX-unsafe characters in generated changelog prose The changelog is an .mdx file, so an unescaped `{` opens a JSX expression and `<` followed by a letter, `/` or `!` opens a JSX element. Release-note prose containing text such as `<plugin ID>` or `{"status": "ok"}` therefore breaks the docs build. The SYSTEM_PROMPT already instructs the model to wrap such text in backticks, but compliance is not guaranteed and the failure mode is a broken build, so escape defensively. Add escape_mdx_unsafe(), applied to the model output after normalize_formatting(). It backslash-escapes bare `{` and bare `<` when followed by a letter, `/` or `!`, while copying protected regions verbatim: inline code spans (double- and single-backtick) and Markdown link destinations. A negative lookbehind avoids double-escaping text that is already escaped. Closing `}` is deliberately left alone - escaping the opening brace is sufficient to prevent a JSX expression, and this keeps the generated heading anchor intact. Escaping runs before BLOG_POST_LINK substitution and Go Version injection, so the Markdown link and the backticked Go version are inserted after the escape pass and are never touched by it. Also harden normalize_formatting(): its horizontal-rule removal would strip the `---` delimiters of a YAML frontmatter block, which MDX requires at the very start of a file. A leading frontmatter block is now split off and restored verbatim, so the function is safe if it is ever applied to whole file contents rather than just the generated fragment. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Nrmq4ezefYWqa9YkxtX3mR * Update generate_changelog.py * Update generate_changelog.py * Update generate_changelog.py * Update generate_changelog.py * Update generate-changelog.yml * Update generate_changelog.py * Derive the changelog path in the script and guard version/milestone Two gaps remained in the major-rollover handling: The workflow resolves the changelog file from the version, but the script still fell back to a fixed "CHANGELOG.md" when CHANGELOG_PATH was unset, so a direct invocation would append a v12 entry to the repository-root changelog with nothing to warn about it. changelog_path_for_version() derives the default from VERSION instead, and major_version() now raises on a version it cannot parse rather than returning an empty string. The script prints the file it targets so a wrong path is visible in the run log. Nothing validated the two dispatch inputs against each other. The milestone selects which PRs are collected and the version selects both the entry heading and its file, so a mismatch files one release's notes under another's. The workflow now compares their major versions in its first step and fails before anything is generated. It compares majors only, so a deliberate v11.10.0/v11.9.0 pairing still runs. insert_changelog_entry() also creates the parent directory when writing a file for a new major that does not exist yet. Verified: the derived path for v11.9.0/v12.0.0/12.0.0 and the raise for malformed versions; bootstrapping mattermost-v12-changelog.mdx into a missing directory writes the frontmatter header before the entry; a second insert lands after that header and above the first entry; the workflow parses and the guard is the job's first step; the guard's shell logic accepts matching majors and rejects mismatched ones. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014gJFVcJtw4rdpjWrmpP9T7 * Rank bullet indents per list block in normalize_formatting Rule 2 took a single minimum indent across the whole fragment and treated anything deeper as nested. That had two failure modes: - Sections are generated independently and can disagree on base indent. A fragment with one section at indent 0 and another at indent 1 gave base 0, so the depth-1 bullets — already correct top-level — were pushed to three spaces and rendered as nested. - A three-level list collapsed to two, because every indent deeper than the minimum mapped to the same three spaces. Indents are now ranked within each list block, mapping level n to 1 + 2n spaces. Blocks are delimited by lines that are neither bullets nor bullet continuations, so each section resolves its own levels, and ranking keeps a third level distinct instead of flattening it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DR6hsSCuRfXqAnyHNY7sKo * Add a major release type and guard against truncated changelog output Three fixes on top of this branch, all of which v12.0 exercised in practice. release_type had no "major" option. The dispatch input offered only "feature" and "esr", so generating v12.0 emitted "Feature Release" and the anchor #release-v12-0-feature-release. Both had to be corrected by hand, and four docs pages deep-link to #release-v12-0-major-release. "major" is now a third choice, and the anchor slug is derived from the heading label instead of being written out separately, so the two cannot drift apart. A vX.0 release generated under any other release type now prints a warning naming the heading and anchor it is about to produce. Truncation. polish_with_ai capped output at 4096 tokens and never looked at stop_reason, so a response that overran the cap was silently cut mid-word — the v12.0 entry is ~32k characters, roughly twice the cap. The cap is raised to 16384 and a max_tokens stop reason is now a hard error. As a backstop for truncation arriving any other way, check_for_truncation rejects an entry containing a bullet that ends without terminal punctuation, before anything is written. It allows the endings that legitimately occur — a bare inline-code span, a fully bold label, a Markdown link or parenthetical, a bare URL, and a bullet continued on the next line — and flags nothing across the 2,702 bullets in the existing v10, v11 and v12 changelogs. Identifier fidelity. The same run shortened ``/ephemeral_mode/cleanup`` to ``/cleanup``. A prompt rule now requires endpoint paths, setting names, commands, table and column names, and feature flags to be reproduced in full. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DR6hsSCuRfXqAnyHNY7sKo * Run the truncation check only on AI-polished prose Applying it to the no-API-key fallback would block legitimate runs: that path emits PR authors' raw release notes verbatim, and those routinely end without a full stop. Across the 71 release notes on the v12.0.0 milestone, 4 do — "Fixed deeplink routing" among them — none of which is truncated. polish_with_ai now reports whether it actually polished, and the check runs only when it did. The AI output itself is reliably punctuated: the 188 bullets of the generated v12.0 entry all pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DR6hsSCuRfXqAnyHNY7sKo * Keep reviewer edits on changelog reruns and record each bullet's source PRs A rerun rebuilt the changelog branch from master and force-pushed it, discarding every edit made in the PR, and then failed at gh pr create because the PR already existed. That rules out running the generator repeatedly while a release is in review. - Add a mode input. auto (default) updates an open changelog PR in place: only notes from PRs its body does not list yet are generated, and they are inserted into the matching sections of the existing entry as new commits, never a force-push. With no open PR it creates one. regenerate keeps the old rebuild-from-scratch behaviour on request. dry_run generates only, with nothing pushed. - Open the PR as a draft. - Tag each note with an ID and have the model mark every bullet with the IDs it used. Markers are stripped before writing, and the attribution goes to sections.json (bullets per section with their source PRs) and to a changelog-sources comment in the PR body, which is how the next run tells new PRs from ones already included. - Upload entry.mdx, sections.json and pr_body.md as an artifact and show the generated text in the run summary. - Run the generator from the workflow's own checkout, since the PR branch may carry an older copy. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DR6hsSCuRfXqAnyHNY7sKo * Keep changelog reruns inside the list and refuse unattributed notes Update mode appended new config bullets after the upgrade admonition and did not recognize two-space plan labels, so a rerun could split a section or repeat a plan heading. New bullets now stop at an MDX admonition, and top-level is the shallowest indent already in that section. A note with no source marker is no longer recorded as included, because the next run would skip it. Multi-line raw notes keep their marker, and star or plus bullets are rewritten to dashes so update mode does not drop them. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Mattermost Build <build@mattermost.com> Co-authored-by: Eva Sarafianou <eva.sarafianou@gmail.com> Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
578fbba586 | Docs: Remove obsolete v12 config settings (#39276) | ||
|
|
459a3af42b |
Docs: Clarify validated TLS and S3 configuration values (#39284)
* Docs: Clarify validated TLS and S3 configuration values * Docs: Document config validation constraints added in MM-69349 Reflect the bounds, accepted values, and formats enforced by server config validation, and fix unclosed paragraph tags in the TLS and S3 rows. * Docs: Use uncompressed as the WebserverMode value * Docs: Fix wording of export S3 upload part size * Docs: Note empty GroupFilter and FeedbackEmail skip validation * Docs: Fix connected workspace sync defaults and MaxPostsPerSync key --------- Co-authored-by: Ben Schumacher <ben.schumacher@mattermost.com> |
||
|
|
d0d6f36df1 | Docs: Increase interactive dialog title max length to 80 (#39278) | ||
|
|
4d716b67f9 |
fix(e2e): repair master flakes from the channel intro user limit and tour-tip pulse rings (#38986)
* fix(e2e): repair file_permissions_edge_cases.spec.ts on master MM-T5828 built its permalink from testConfig.internalBaseURL and assumed the server's SiteURL still matched. pw.ensureSiteUrl() restarts the Mattermost container with MM_SERVICESETTINGS_SITEURL pointing at the host-reachable baseURL, and because that is an env override, initSetup()'s patchConfig cannot put it back. On a reused server, every spec that runs after an auth/claim or oidc spec therefore sees a SiteURL the permalink no longer matches, the server emits no permalink embed, and .post-preview never renders. Read SiteURL off the running server instead of assuming it. Co-authored-by: yasserfaraazkhan <attitude3cena.yf@gmail.com> * fix(e2e): share permalinkUrl helper across SiteURL-sensitive specs Build /pl/ permalinks from the SiteURL the running server reports, via one helper used by MM-T5828 and the post_list specs that had the same internalBaseURL assumption. Co-authored-by: mattermost-code <matty-code@mattermost.com> * fix(e2e): reject empty SiteURL in permalinkUrl helper Fail fast instead of building a relative /pl/ path when the server reports no SiteURL. Co-authored-by: mattermost-code <matty-code@mattermost.com> * fix(e2e): converge SiteURL for demo_dialog interactive dialogs demo_dialog.spec.ts's two bare-/dialog tests fail on any CI worker that earlier ran a spec calling pw.ensureSiteUrl(). The demo plugin registers its dialog callback as <SiteURL>/plugins/<id>/dialog/1, and App.DoActionRequest only dispatches in-process for relative URLs, so an absolute one is a real outbound POST. Once SiteURL points at the host-mapped baseURL the server cannot reach that address from inside its own container: the submit returns 400, leaving the dialog open, and the cancel posts no notification. Add pw.ensureInternalSiteUrl(), which converges SiteURL back to internalBaseURL and is a no-op on a stack booted with the default, and call it from the two tests whose callback URL is absolute. Co-authored-by: yasserfaraazkhan <attitude3cena.yf@gmail.com> * fix(e2e): repair channel_headers.spec.ts MM-T880 on master A channel intro replaces its action buttons -- favorite, "Set header" and notification preferences -- with just the invite button while the server has fewer users than the webapp's usersLimit of 10. On a reused Testcontainers server that count depends on how many specs the worker ran before, so MM-T880's click on the intro's "Set header" button only found it by luck. Add ensureChannelIntroActions(), which tops the server up to that many users, and call it from the test. Co-authored-by: yasserfaraazkhan <attitude3cena.yf@gmail.com> * fix(webapp): stop tour-tip pulse rings from swallowing clicks PulsatingDot's ::before/::after rings animate to scale(2.5), 30px across a 12px dot, and were hit-testable. The burn-on-read tour tip puts that dot on top of the burn-on-read button, so for ~77% of every 2s pulse cycle the element at the button's own centre is the dot, not the button. A click whose mousedown and mouseup land on different elements is delivered to their nearest common ancestor, so when a ring crosses the cursor between the two, `click` fires on .BurnOnReadControl and neither the button's toggle nor the tip's open handler runs. That is the intermittent dm_gm_flow.spec.ts "MM-66742_1 BoR toggle is available in DM channel" failure on master: the click reports success and the BURN ON READ label never appears. The rings are decoration; the dot itself stays clickable. https://github.com/mattermost/mattermost/actions/runs/37978315300 Co-authored-by: yasserfaraazkhan <attitude3cena.yf@gmail.com> * fix(e2e): drop the permalinkUrl helper now that master resets SiteURL per spec #39091's ensureDefaultServerEnv() restores the default SiteURL before each spec file, so the permalink specs pass with master's own copies (12/12 and 210/210 on a server with a leaked SiteURL). Revert them and remove the helper. --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: mattermost-code <matty-code@mattermost.com> Co-authored-by: yasserfaraazkhan <attitude3cena.yf@gmail.com> |
||
|
|
926f347bd5 |
Interactive dialogs: refresh parent on return, submit_buttons, action button descriptions (#39155)
* Interactive dialogs: stacked dialog refresh, submit_buttons, action button layout * fix from review comment |
||
|
|
de9d77e456 |
[MM-65788] Make PermanentDeleteUser delete all of a user's data (#38773)
* [MM-65788] Make PermanentDeleteUser delete all of a user's data PermanentDeleteUser left orphaned rows behind and could abort halfway through, leaving an account in a half-deleted state. Posts are deleted in batches with a hard fail-safe, so a user with more posts than the store can walk had their sessions, preferences, channel memberships and some of their posts destroyed before the delete failed. The account is now rejected up front, before anything is removed, with an error telling the admin how many posts need to go first. The fail-safe also fired one batch early, so the effective ceiling was 9,000 rather than the advertised 10,000; it now checks the batch count before deleting rather than after. Several tables holding per-user data were never cleaned up at all. These are now removed along with the account: Status, ChannelMemberHistory, SidebarCategories, SidebarChannels, ProductNoticeViewState, ThreadMemberships, PostAcknowledgements, ReadReceipts, PostReminders, UploadSessions, NotifyAdmin, UserTermsOfService, CommandWebhooks, DesktopTokens, SharedChannelUsers and OAuthAuthData. Co-authored-by: mattermost-code <matty-code@mattermost.com> * [MM-65788] Count posts on master before permanently deleting a user The up-front post-count gate used AnalyticsPostCount, which reads a replica. Replica lag could let the gate pass and then fail inside PermanentDeleteByUser after sessions, preferences, and memberships were already removed. Count on the writer instead so the 10,000-post limit is checked against the same database the delete will use. Co-authored-by: mattermost-code <matty-code@mattermost.com> * [MM-65788] Stop flaking webhook override setup on a no-op Save MM-T622 failed twice in Cypress because the helper visited the admin console and waited for Save to enable after checking radios that were already in the desired state. Set EnablePostUsernameOverride and EnablePostIconOverride through the config API instead, matching the other incoming webhook specs. Co-authored-by: mattermost-code <matty-code@mattermost.com> * [MM-65788] Retrigger CI after Enterprise docker image setup failed Enterprise tests and style were already green; ci / Build docker image exited during cosign install (curl 35). gh run rerun is not available, so this empty commit starts a new Enterprise image build. Co-authored-by: mattermost-code <matty-code@mattermost.com> * [MM-65788] Patch webhook override flags without resetting config apiUpdateConfig merges e2e defaults, which moved MM-T622 off the save-button flake and onto a wrong webhook avatar (static file instead of the image-proxy URL). PUT the current config with only EnablePostUsernameOverride and EnablePostIconOverride changed. Co-authored-by: mattermost-code <matty-code@mattermost.com> * [MM-65788] Skip no-op Save when webhook override radios are already set Setting EnablePost*Override through the config API left MM-T622 asserting the default webhook avatar instead of the image-proxy icon URL. Keep the admin-console path that the rest of the incoming-webhook suite uses, and skip Save when both radios are already in the requested state so it does not time out on a disabled button. Co-authored-by: mattermost-code <matty-code@mattermost.com> * [MM-65788] Wait for webhook override flags after config PUT MM-T622 still showed the default webhook avatar after the flags were written: username override applied but EnablePostIconOverride was stale when the incoming webhook was posted. PUT only those two flags (no e2e-default merge, no no-op admin Save) and wait until GET config reports both before continuing. Co-authored-by: mattermost-code <matty-code@mattermost.com> * [MM-65788] Give MM-T622 a hook-level icon after enabling overrides PUT+waitUntil on EnablePostIconOverride still left the webhook avatar at DEFAULT_WEBHOOK_LOGO: username override applied but override_icon_url was missing. MM-T620 passes on the same fleet by setting the hook icon in-app after the flags are on. Mirror that, and point at the stable fixture used by the markdown image specs (icon_WS.png on mattermost.com is 404). Co-authored-by: mattermost-code <matty-code@mattermost.com> * [MM-65788] Advance the schedule calendar when the target day is next month On the last days of a month, dayFromToday=2 lands on the 1st of the next month. The helper still saw day 1 of the current month (visible but disabled) and clicked it instead of going forward. Always go to next month when the target month differs, and pick a future day in the demo plugin date dialog. Co-authored-by: mattermost-code <matty-code@mattermost.com> * Address PR feedback: 0 answered, 1 resolved, 0 declined Make PermanentDeleteUser resumable instead of rejecting users up front: - Drop the up-front post count and PostCountOptions.UserId/UseMaster. - Delete posts in batches of 1,000 per transaction, replies included, with at most 10,000 of the user's posts per call; hitting the limit returns an error asking the admin to run the delete again. - Delete post-keyed data (reactions, read receipts, acknowledgements, priority, persistent notifications, reminders) for the deleted posts and every reply to them in the same transaction. - Remove files from storage before deleting their FileInfo rows, listed from master including soft-deleted files and files on replies. - Delete the Users row last, and report any failure after deactivation as a partial delete that is safe to re-run. - PermanentDeleteAllUsers reports the users it could not finish. * Address PR feedback: 0 answered, 3 resolved, 0 declined - Split post-keyed deletes in permanentDeleteAssociatedData into separate statements for the post ids and their replies, so Postgres can use the PostId indexes instead of scanning each table. - Combine the arms of FileInfo GetForPermanentDeleteByUser with UNION instead of OR so the post-based arms use idx_fileinfo_postid_at. - Permanently deleting a user now also removes their property values across all groups, scheduled recaps, recaps with their channels, and channel join requests. * Address PR feedback: 2 answered, 7 resolved, 0 declined * Remove the profile image directory even when the image is already gone A removal that deleted profile.png but then failed to remove the directory it sat in left that directory behind permanently: the retry checked for profile.png first, found it absent, and returned without removing anything. Removing the directory is now unconditional, which every file backend tolerates and which matches the rest of permanentDeleteUserData being safe to repeat. The assertion in requireFullyDeleted was also checking only the image file, so it could not see the leftover directory. It now checks the directory, which covers both. 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> |
||
|
|
46ed11842e |
Stricter i18n catalog checkers (#39275)
* Fail an empty translation even under the warn-missing flags CI runs both checkers with --warn-missing-keys / --warn-missing-ids so a catalog can lag en.json. That was also downgrading an empty value to a warning, so a "" placeholder left in a catalog would merge. An absent key is work in progress; an empty one is a leftover placeholder, and now always fails. * Check each webapp catalog's formatting A hand edit that reindents or reorders a catalog buries its one real change in a diff of thousands of lines, and nothing caught it. check_icu.mjs now requires each catalog to be its own canonical serialization: keys in code-point order, which every webapp catalog already has, a 2-space indent and a trailing newline. A duplicate key fails too, since JSON.parse keeps only the last one. Co-authored-by: Jesse Hallam <lieut-data@users.noreply.github.com> * Check each server catalog's formatting A hand edit that reindents a catalog buries its one real change in a diff of thousands of lines, and nothing caught it. mmgotool i18n verify now requires each catalog to be its own canonical serialization: a 2-space indent and a trailing newline. The server catalogs have no order, so entry order is left alone. A duplicate id fails, which the loader silently collapses. Co-authored-by: Jesse Hallam <lieut-data@users.noreply.github.com> * Warn about horizontal arrows in right-to-left locales Arrows are not bidi-mirrored, so in a sentence read right to left an arrow meaning "next" or "leads to" points backwards, and nothing checked for it. check_icu.mjs now warns when a right-to-left locale's translation contains a horizontal arrow or pointer. The locale's direction comes from Intl, so no locale is listed by hand. Vertical arrows and the ↵ key symbol read the same either way and are not flagged. * Warn about horizontal arrows in right-to-left server catalogs too check_icu.mjs warns when a right-to-left locale uses an arrow that is not bidi-mirrored. mmgotool i18n verify now does as well, for single and plural translations. It reports the one such string fa.json ships today. Co-authored-by: Jesse Hallam <lieut-data@users.noreply.github.com> * Stop using -- as a dash in the checkers' comments Both checkers take --flags, and a -- dash beside them reads as one. * Move check_icu.mjs's per-message rules into icu_rules.mjs check_icu.mjs held the file-level checks and the per-message ICU rules in one script, so nothing else could run exactly the rules CI runs. The per-message rules now live in icu_rules.mjs: analyzeSource parses an en.json message once, and checkMessage returns each finding with a stable rule id and a severity. check_icu.mjs keeps the file-level checks and reports each finding as before. The output over the shipped catalogs is byte-identical before and after, with and without --warn-missing-keys. The i18n CI workflow now also runs when icu_rules.mjs changes. Co-authored-by: Jesse Hallam <lieut-data@users.noreply.github.com> * Warn about plurals missing a form their locale needs A plural that shows its count but lacks a form its locale needs for some integer renders that count with "other": Russian ships "5 каналы" where it should say "5 каналов". check_icu.mjs now warns about it. Explicit =N arms count as covering N. Forms that only fractions or numbers in the millions select are not required. A source plural that itself leaves out a form English needs is not held against the translations that copy it. When two plurals on one variable fail the same way, the finding is reported once. It is a warning because 370 shipped strings have the problem, nearly all in pl, cs, uk, ru, lt and ro. Co-authored-by: Jesse Hallam <lieut-data@users.noreply.github.com> * Show "this user" for one user in two zh-CN removal prompts Chinese never selects the plural category one, so the one {这位用户} arm was dead and a single user read as 这些用户 (these users). =1 selects exactly one. Co-authored-by: Jesse Hallam <lieut-data@users.noreply.github.com> --------- Co-authored-by: Jesse Hallam <lieut-data@users.noreply.github.com> Co-authored-by: Cursor Agent <cursoragent@cursor.com> |
||
|
|
a0ce180676 |
Apply the current team theme on backstage pages (#38804)
* Apply the current team theme on integrations and custom emoji pages. Backstage omitted app__body and hardcoded a light palette, so only shared buttons followed the user's theme. Co-authored-by: Cursor <cursoragent@cursor.com> * Update integrations cards with themed compass illustrations and a tinted backstage surface. Co-authored-by: Cursor <cursoragent@cursor.com> * Use a responsive grid for integrations cards and fix light-theme webhook icon contrast. Co-authored-by: Cursor <cursoragent@cursor.com> * Replace OAuth integrations card icon with a themeable SVG seal. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Use compass OAuth card illustrations with a fixed dark logo and outgoing arrow. Co-authored-by: Cursor <cursoragent@cursor.com> * Update _backstage.scss * Fix backstage mobile layout cascade, content margins, and SVG lint. Co-authored-by: Cursor <cursoragent@cursor.com> * Fix stylelint property order in backstage styles. Co-authored-by: Cursor <cursoragent@cursor.com> * Update the integrations page e2e selector for the grid layout. The backstage integrations list no longer uses Bootstrap flex classes, so MM-T569 timed out looking for .integrations-list.d-flex.flex-wrap. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Use a live image for the webhook icon override e2e. The mattermost.com marketing icon 404s, so the avatar falls back to the default icon and MM-T622 never sees the proxied src. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Align session attribute e2e with String types and scroll rows into view. Text fields render as String, and a bottom-row dot menu was opening upward so Escape never dismissed it. Co-authored-by: Matthew Birtch <mattbirtch@gmail.com> * Revert session attribute e2e changes unrelated to the backstage theme. Co-authored-by: Cursor <cursoragent@cursor.com> * Use published Compass illustrations on the integration cards. Import the webhook, slash command, and bot artwork through Illustration instead of copied SVGs, and target those card links by role in the e2e. Co-authored-by: Cursor <cursoragent@cursor.com> * fixes for sectionnotice --------- Co-authored-by: Matthew Birtch <2040554+matthewbirtch@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
f292f95d5a |
ci(docs-preview): avoid spurious failures from superseded runs (#39123)
* ci(docs-preview): stop rebuilding on ready_for_review * ci(docs-preview): don't report failure when a run is superseded |
||
|
|
491e853f7b |
Monthly maintenance (2026-10): Update server dependencies (#39220)
* Update server Go dependencies for October 2026. Bump module dependencies within their current major versions, including golang.org/x/net v0.61.0 which fixes the HTTP/2 issues addressed in v0.60.0. Co-authored-by: jesse <jesse@mattermost.com> * Retrigger Server CI after Postgres shard runner kills. Co-authored-by: mattermost-code <matty-code@mattermost.com> * Hold back logr v2.0.22 and azblob v1.8.0. logr v2.0.23 defaults to a sync.Map level cache and pre-fills 65535 entries on every clear, which OOMs fully parallel app/api4 tests. azblob v1.8.1+ pulls apache/arrow-go into every filestore binary. Co-authored-by: mattermost-code <matty-code@mattermost.com> * Upgrade azblob to v1.8.2. Keep list-blobs on the SDK default format. The module links arrow-go for the opt-in Arrow parser. Co-authored-by: jesse <jesse@mattermost.com> * ci: make e2e dispatch-run job names unique per chain --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: jesse <jesse@mattermost.com> Co-authored-by: mattermost-code <matty-code@mattermost.com> Co-authored-by: Mattermost Build <build@mattermost.com> |
||
|
|
5f4342d7f8 |
drip: AppError -> error: delivery tracking config (#39285)
Return error from SaveDeliveryTrackingConfig so its caller no longer converts validateTrackedChannelIDs through model.AsAppError. Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: jesse <jesse@mattermost.com> |
||
|
|
b0ddc5a13a |
Add Conflicts Babysit workflow to dispatch conflicting PRs to a Cursor agent (#39272)
* Add Conflicts Babysit workflow to dispatch conflicting labeled PRs to Cursor On every push to master, find open PRs labeled AI/ConflictsBabysit whose mergeable state is CONFLICTING (retrying briefly while GitHub reports UNKNOWN) and POST each one to the Cursor automation webhook. Co-authored-by: Maria A Nunez <maria.nunez@mattermost.com> * Remove workflow_dispatch trigger from Conflicts Babysit Manual dispatch can target any branch, which would run that branch's version of the script with the webhook secrets. Co-authored-by: Maria A Nunez <maria.nunez@mattermost.com> * Make Conflicts Babysit best-effort so it never fails master CI Webhook and PR search failures are reported as warnings and in the job summary instead of failing the run; checkout and dispatch steps are continue-on-error as a backstop. Co-authored-by: Maria A Nunez <maria.nunez@mattermost.com> * Report Conflicts Babysit failures hidden by continue-on-error Skip dispatch when checkout fails, add a step that warns and writes the job summary when checkout or dispatch fails, and write the job summary when the PR search fails. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> |
||
|
|
be207f8972 |
Stop forcing SizeAwareImage containers to display:block (#39216)
* Stop forcing SizeAwareImage containers to display:block A loaded SizeAwareImage set `display: block` as an inline style on its `.file-preview__button` container. Because an inline style beats every stylesheet rule, inline Markdown images were torn out of the text flow: the channel header, the header-change system message and any message with two images next to each other wrapped after every image, hiding the rest of the header. Only set `display` inline for the hidden state and let CSS pick the visible display mode. The surfaces that need block-level images (`.image-loaded` attachments and MM Blocks) already say so in their stylesheets, and `.file-preview__button` defaults to `inline-block`, which is what the Markdown and channel-header rules were already asking for. Fixes: https://github.com/mattermost/mattermost/issues/39212 Co-authored-by: Jesse Hallam <lieut-data@users.noreply.github.com> * Assert inline Markdown images share a row with surrounding text Co-authored-by: mattermost-code <matty-code@mattermost.com> * Clarify inline image e2e text-box coordinate space Co-authored-by: mattermost-code <matty-code@mattermost.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Jesse Hallam <lieut-data@users.noreply.github.com> Co-authored-by: Mattermost Build <build@mattermost.com> Co-authored-by: mattermost-code <matty-code@mattermost.com> |
||
|
|
4772545518 |
Bumping prepackaged Dataminr plugin version to v3.0.0 (#39291)
Automatic Merge |
||
|
|
05aa23fcae |
Skip flaky TestGenerateFlaggedPostReportAttachmentsOmittedAudit (#39274)
Skipping while the root cause is investigated under MM-71235. Tests-only change. Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: mattermost-code <matty-code@mattermost.com> |
||
|
|
5ab80bea86 |
[MM-71255] Deduplicate healthcheck rule helpers and add missing license gates (#39288)
Add shared Snapshot accessors (LeaderDiag, ConfigRoot, RegisteredUsers, ClusterEnabled, Since, LicenseAllows) and rule combinators (Single, Gate, Licensed and their node variants), replacing per-package copies. Gate cluster, Elasticsearch, LDAP, SAML, job and read-replica rules on their license feature, since the server ignores those settings without it. The license is consulted only when a rule would not resolve anyway, and packets that predate the license feature list keep their findings. |
||
|
|
3cef243d18 |
[MM-71188] Fix slash command autocomplete splitting single and curly quoted values (#39235)
* MM-71188 End single and curly quoted autocomplete args where execution does parseInputTextArgument only grouped words in straight double quotes, so autocomplete for /secure-connection and /share-channel split a single or curly quoted value at its first space and showed wrong or no suggestions after it, even though parseNamedArgs executes the command correctly. Built-in commands that execute through parseNamedArgs now opt in through AutocompleteQuotedArgProvider, which ends a quoted value with the same quoteStyles and quotedToken rules the execution tokenizer uses. Other commands, including plugins that split on whitespace, keep the old behavior so their autocomplete does not diverge from execution. Co-authored-by: mattermost-code <matty-code@mattermost.com> * MM-71188 Test quoted value autocomplete for /secure-connection Co-authored-by: mattermost-code <matty-code@mattermost.com> * MM-71188 Cover input after quoted values and non opted-in built-ins Co-authored-by: mattermost-code <matty-code@mattermost.com> * MM-71188 Preserve separator whitespace after a closed autocomplete quote After a closed quoted value, keep all existing spaces in parsed and insert a space when the quote has no following separator so the next flag completion is not glued on. Co-authored-by: mattermost-code <matty-code@mattermost.com> * Address PR feedback: 0 answered, 8 resolved, 0 declined * Address PR feedback: 0 answered, 1 resolved, 0 declined --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: mattermost-code <matty-code@mattermost.com> |
||
|
|
9b1c4fd558 |
[MM-71057] Health Dashboard PR18: rules for auth and identity (#38917)
* [MM-71057] Add health rules for auth and identity Port the script's LDAP, SAML and session checks as rules in a new rules/auth package, plus two probe rules over the leader's LDAP and SAML connection tests. Each code emits one result per cycle: unknown when its config is missing, resolved when its gate (LDAP, LDAP sync or SAML) is closed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com> * [MM-71057] Cover the auth rules in the packet fixtures The fixture configs had no LdapSettings or SamlSettings, so every auth rule read unknown. The standalone packet now models an upgraded install without AD/LDAP or SAML; the HA packet uses SAML sign-in with AD/LDAP sync only, with matching probe results in each node's diagnostics. The mmctl --packet test packet gains the settings and user count the auth rules read, so its expected output is unchanged. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com> * [MM-71057] Use shared unknown reasons, raise SAML_VERIFY_OFF to warning The probe rules, LDAP_RECOMMENDED_AT_SCALE and LDAP_SYNC_DUTY_CYCLE now report a missing source with the shared diagnostics, stats and jobs reasons instead of per-code ids. Only the duty cycle's "no measurable run" message stays per code. With Verify off, the SAML response signature is not validated, so a forged response is accepted; that warrants warning rather than info. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com> * [MM-71057] Fold the auth probe evals into one helper Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * [MM-71057] Skip auth rules for settings that have no effect SAML_SIGNATURE_SHA1 now requires SignRequest, LDAP_SKIP_CERT requires TLS or STARTTLS, SAML IdAttribute matching handles claim URIs, and ldapEnabled no longer needs EnableSync when Enable is already true. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * [MM-71057] Tone down the LDAP sync duty cycle message Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * [MM-71057] Evaluate the LDAP and SAML rules on Cloud Cloud admins can change these settings, unlike the cloud_restrictable ones or the pages RestrictSystemAdmin hides. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Keep the mmctl packet fixture under the AD/LDAP recommendation threshold The fixture's 300 users made LDAP_RECOMMENDED_AT_SCALE fire, adding an unexpected finding to the packet output tests. * Address review on the auth health rules - SAML_VERIFY_OFF is critical: with Verify off the SP skips signature validation, so a self-made response to the ACS URL signs in as anyone. - SAML_METADATA_UNREACHABLE becomes SAML_PROBE_FAILED, gated only on SAML being enabled. MM-71043 changes the probe to check the IdP certificate and IdP URL that sign-in uses instead of IdpMetadataURL. - LDAP_SYNC_DUTY_CYCLE only averages success and warning runs; running, canceled and failed runs end early and understate the load. - SAML_ID_IS_EMAIL is info, since it fires on every default SAML install, and the remediation says accounts migrate at next sign-in. - LDAP_RECOMMENDED_AT_SCALE resolves for GitLab, Google, Office 365 and OpenID too. - SAML_ID_MUTABLE also matches upn, userprincipalname and name (Entra's UPN claim). - LDAP_SYNC_INTERVAL_LOW is removed; LDAP_SYNC_DUTY_CYCLE measures the actual load for short intervals. * Simplify the auth rule test helpers Drop the single-use codes() helper, read LDAP_RECOMMENDED_AT_SCALE's state directly, and reuse configSnapshot's sections in probeSnapshot and gateSnapshot. Note why leaderProbe skips the probe section errors that its siblings check. * Tighten LDAP_RECOMMENDED_AT_SCALE and the probe rules - Count active users, not registered ones, which include deactivated accounts. - Sync-only LDAP no longer counts as SSO: it signs no one in, so those users still have local passwords. - An enabled provider resolves the rule even if another provider's setting is missing from the config. - The probe rules resolve only on OK. A disabled status while the gate is open means the leader never ran the probe, so it is unknown. - assertResults fails on a code that is not in allRules instead of skipping it. - The standalone fixture gains the GitLab, Google, Office 365 and OpenID sections a real packet always has. --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
d430bb294f |
SEC-11251 Add Playwright subpath deployment E2E testing (#38833)
* Add Playwright subpath deployment E2E testing * Address CodeRabbit findings: subpath CI trigger gap, container cleanup scope, internal webhook URL * Widen subpath CI trigger to cover the full deployment configuration * Also trigger subpath E2E tests on reusable Playwright workflow changes * Also trigger subpath E2E tests when the goto/baseURL fixture chokepoints change * Fix defaultBootEnv() dropping subpath SiteURL on per-spec-file reset ensureDefaultServerEnv() restarts the server with defaultBootEnv() before each spec file's first test. defaultBootEnv() didn't know about subpath mode, so it reset SiteURL back to the plain default and broke every subpath spec after the first server restart. Co-authored-by: saturnino <saturnino@mattermost.com> * Fix baseURL on mid-test restart in subpath mode; widen CI path filter restartMattermostContainerLocked() always reset baseURL to the direct server URL, dropping the subpath prefix after any mid-suite restart (e.g. via ensureFeatureFlag()). Keep it pointed through nginx when subpathMode is set. Also widen the SHOULD_RUN_SUBPATH file filter to cover util.ts and the channels/system_console page objects, which subpath specs depend on. Co-authored-by: saturnino <saturnino@mattermost.com> * fix specs that broke when the server runs behind nginx at /subpath: - Add toHavePath/toHaveHrefPath matchers that prepend the subpath, and lint against toHaveURL('/path'), which Playwright resolves against baseURL and so drops the subpath - Route unprefixed API calls onto the subpath, point mmctl at the subpath-aware URL, and build permalinks from the site URL - Auto-start nginx whenever PW_SERVER_DEPLOY=subpath - Skip the OIDC/SAML error-page cases (signature mismatch under a subpath) and the MM-69979 post_height cases for the subpath project - Wait for the phase2 permissions migration before the autotranslation scheme tests - Fix the mobile schedule menu dimmed-area click when the dialog starts above the viewport, and pin the date separator rollover test to UTC * keep the subpath SiteURL reachable from the server --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: saturnino <saturnino@mattermost.com> Co-authored-by: Mattermost Build <build@mattermost.com> |
||
|
|
bbe3f71849 |
[MM-71216] Apply incoming AcknowledgedAt when receiving synced acknowledgements (#39240)
The shared channel receiver chose create or delete based on whether a matching acknowledgement row existed, ignoring the incoming AcknowledgedAt. A removed acknowledgement the receiver had no row for was created as active, and an acknowledgement re-sent after a withdrawal was dropped because the withdrawn row still exists with AcknowledgedAt == 0. Apply the sender's state idempotently instead, as MM-71096 does for reactions. Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: mattermost-code <matty-code@mattermost.com> |
||
|
|
9df984246f |
Render URL too long errors inline to stop the redirect loop (#38286)
A request that exceeds ServiceSettings.MaximumURLLength is rejected with a 414 and answered with a page that sends the browser to a signed /error URL. When the limit is small enough, that generated URL is over the limit too, so the browser bounces between freshly signed error URLs forever. RenderWebError now serves the error inline whenever the error page URL would itself be rejected, so the browser settles on a single stable page. Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: mattermost-code <matty-code@mattermost.com> |
||
|
|
aeccde2d90 |
[MM-69961] Fix login being blocked for all users when Guest Access is disabled while Magic Link stays enabled (#38749)
* MM-69961: don't block all logins when guest access is disabled The login page gated its POST /users/login/type pre-check on EnableGuestMagicLink alone, while the server also requires guest accounts to be enabled and licensed. With magic links on and Guest Access off the endpoint answered 404 with an empty body under a JSON content type, so the client's response.json() threw "Received invalid response from the server.", the password field never rendered and every login method was blocked. Mirror the server's availability conditions in the login page so the pre-check is only attempted when it can succeed, and have getLoginType return a JSON error body instead of a bare 404. The nil license is now guarded too; it previously panicked on an unlicensed server. Co-authored-by: mattermost-code <matty-code@mattermost.com> * MM-69961: close coverage gaps found by mutation testing Mutation testing showed three production paths the new tests did not pin: the server gate's EnableGuestMagicLink and license feature conditions, and the redundant isLicensed term on the client. The client license only carries GuestAccounts when a license is present, so that term is dropped rather than tested. Adds action-layer coverage for the response shapes getLoginType can now return, since that is where MM-69961 actually surfaced. Co-authored-by: mattermost-code <matty-code@mattermost.com> * MM-69961: drive the login type pre-check over real HTTP in tests The component tests mocked the getUserLoginType action, so they could never reproduce the empty-404-under-application/json response that actually broke login. Nock the endpoint instead and assert on the banner the user sees, including the case the server fix removes. The regression tests now prove the pre-check is skipped by leaving that response unconsumed rather than by asserting on a mock. Co-authored-by: mattermost-code <matty-code@mattermost.com> * MM-69961: assert the message the login page renders, not just the error id model.NewAppError falls back to using the id as the message, so a missing en.json entry would have left the raw id on screen with every suite green. Co-authored-by: mattermost-code <matty-code@mattermost.com> * MM-69961: trim comments and match local error-variable naming Co-authored-by: mattermost-code <matty-code@mattermost.com> * MM-69961: retrigger CI after Enterprise Postgres flake Co-authored-by: mattermost-code <matty-code@mattermost.com> * MM-69961: retrigger CI after Postgres shard flake Co-authored-by: mattermost-code <matty-code@mattermost.com> * MM-69961: match Playwright login error banners used on enterprise 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> |
||
|
|
5c012a1184 |
[MM-61894] Keep markdown formatting when pasting text copied from a message (#38287)
* MM-61894: keep markdown when pasting a copied message The paste handler only converted pasted HTML into markdown when it held a table or a link, so copying a rendered message out of a channel and pasting it dropped headings, lists, emphasis and code. It now converts any HTML that carries formatting markdown can express, and Turndown knows how to read back the markup Mattermost renders for code blocks, channel links and hashtags. Co-authored-by: mattermost-code <matty-code@mattermost.com> * MM-61894: cover pasting a copied message with tests Renders messages through the real Markdown component and pastes the resulting markup back, so the tests exercise the markup a browser actually puts on the clipboard. Co-authored-by: mattermost-code <matty-code@mattermost.com> * MM-61894: lengthen code-block fences past inner backticks When a copied Mattermost code block contains ```, a hardcoded three-backtick fence would close early. Size the fence from the longest run in the code. 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> |
||
|
|
06f070f339 |
[MM-70052] Fix group search returning nothing when the term starts with "@" (#38748)
* Fix group search ignoring results when the term starts with "@" The group search queries matched the raw term against UserGroups.Name and UserGroups.DisplayName, so a mention such as "@developers" never matched a stored group name. The channel "Add people" dialog searches by mention, so its request returned nothing and the dialog kept rendering the locally cached group, which loses its member IDs once the User Groups list is browsed. That left the "Add N people" shortcut with an empty tooltip and no members to add. Strip a single leading "@" when building the search pattern, matching how user search and the webapp's own group filtering already treat mentions. Co-authored-by: mattermost-code <matty-code@mattermost.com> * chore: match max login attempts e2e to current login error banner The Playwright full suite failed on max_login_attempts.spec.ts because it asserted the old exact invalid-credentials and lockout strings. Use the login page helper (which already matches both banner variants) and a prefix check for the lock message. Co-authored-by: mattermost-code <matty-code@mattermost.com> * Revert unrelated max login attempts e2e change The login-banner assertion update was a pre-existing full-suite test fix unrelated to the MM-70052 group-search fix. Removing it here to keep this PR scoped; it can be addressed in its own change. * chore: match max login attempts e2e to current login error banner The full Playwright suite fails this spec on the old exact invalid-credentials and lockout strings. Use the shared login-page helper (which already matches both banner variants) and a prefix check for the lock message. 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> |
||
|
|
b4484b200a |
[MM-71061] Health Dashboard PR24: rules for compliance and data governance (#38915)
* [MM-71061] Add compliance and data governance health rules COMPLIANCE_NO_DIR, AUDIT_LOG_OFF, RETENTION_TIGHT_BATCHES and EXPORT_GR_TIMEOUT_LOW, each gated on the feature it lints so a disabled feature resolves. AUDIT_LOG_OFF follows the server's IsAuditLoggingActive, so an advanced logging target bound to an audit level counts as a sink and audit-delivery alone does not. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com> * [MM-71061] Cover the compliance rules in the packet fixtures Add the audit, compliance, retention and message export settings to the golden packet configs so the new rules evaluate offline: standalone fires COMPLIANCE_NO_DIR, ha fires EXPORT_GR_TIMEOUT_LOW. The mmctl packet stub gets the same settings with resolving values. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com> * [MM-71061] Fire a compliance rule in the live/offline parity test Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com> * [MM-71061] Use the shared stats reason in AUDIT_LOG_OFF Replace health.rule.audit_log_off.message.stats_unavailable with healthcheck.ReasonStatsUnavailable from the base branch. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com> * [MM-71061] Reuse config.IsAuditLoggingActive in AUDIT_LOG_OFF Drop the local copy of the audit sink check and its tests, short-circuit retentionEnabled once message deletion is on, and list the new codes in TestBuiltinRegistry instead of a per-package registration test. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * [MM-71061] Honor the AdvancedLogging license in AUDIT_LOG_OFF The server ignores advanced audit targets on a license without AdvancedLogging, so they no longer count as a sink there. Also reuse the model default as the retention batch pause threshold. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * [MM-71061] Read the AdvancedLogging license from leader diagnostics Packets now carry the license features, so AUDIT_LOG_OFF only allows advanced audit targets unconditionally when the license is unknown. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * [MM-71061] Share the sibling rule test helpers in the compliance tests Use the want/configSnapshot/withUsers/assertResult set from the platform and cluster packages so results are checked on all details and value, and drop two unused subjects from the packet reader test. * [MM-71061] Count custom retention policies in RETENTION_TIGHT_BATCHES Custom team and channel policies run the data retention job with the same batch pause even when both global deletion flags are off. The packet has no policy count, so treat a data retention job created within 48 hours of collection as the job running. * [MM-71061] Lower compliance rules to info and gate AUDIT_LOG_OFF on Enterprise AUDIT_LOG_OFF, RETENTION_TIGHT_BATCHES and EXPORT_GR_TIMEOUT_LOW flag configuration choices rather than faults, so they report as info. AUDIT_LOG_OFF now only evaluates on Enterprise tier and above, matching the System Console, which hides the Audit Logging page below that tier. * [MM-71061] Add SupportPacketLicense.MinimumEnterprise for the AUDIT_LOG_OFF gate * [MM-71061] List one rule code per line in TestBuiltinRegistry * Fix shadowed ok in evalAuditLogOff * [MM-71061] Gate compliance rules on their license features COMPLIANCE_NO_DIR, RETENTION_TIGHT_BATCHES and EXPORT_GR_TIMEOUT_LOW now require the Compliance, DataRetention and MessageExport features their runtimes check, so stale settings on an unlicensed or downgraded server no longer fire. Unlicensed servers resolve; licensed packets without feature data return unknown. * [MM-71061] Resolve unlicensed servers in LicenseFeature Snapshot.LicenseFeature now reports a feature as off for an unlicensed server, which carries no features, and keeps unknown for licensed packets that predate them. The compliance rules wrap their Eval in requireFeature instead of repeating the gate, and the tests drop the cases the shared license/config test already covers. * Add compliance license features to mmctl health test packet --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
e7e0ee99d2 |
Docs: interactive dialog checkbox elements and per-channel join/leave messages (#39260)
* update documentation for checkbox group/matrix and join/leave channel settings * update docs from coderabbit review |
||
|
|
70a7b86bb1 | Resolve Jest src imports from rootDir only (#39150) | ||
|
|
57ea425e5a |
Fix existing translation errors and add glossary terms (#39207)
* Fix "Updating..." strings translated as "Uploading..." ja, ko and pt-BR rendered several "Updating..." labels as "Uploading...", and bg used the ungrammatical "Актуализира ...". Match the sibling *.updating strings each locale already translates correctly. * Fix Swedish "emoij" misspelling Spell it "emoji" (definite "emojin") across the webapp and server catalogs, as the sv glossary requires, and translate the custom emoji delete confirmation title, which read "Enable custom emoji". * Retranslate stale "Attribute Management" link label The English label changed from "User Attributes" to "Attribute Management", but ten locales still shipped the old meaning. Reuse each locale's existing translation of the Attribute Management section title. * Fix Hosted Push Notification Service name in de and ru ru rendered it as Mattermost's "own" push service, and de garbled the name into "Hosted Push Notifications Dienste". * Translate "orphaned field" as an attribute of an uninstalled plugin Locales rendered the label as a literal "orphaned field", "field without an owner" or "attribute of a removed plugin". The button deletes a user attribute whose owning plugin is no longer installed, which is how the neighbouring strings already describe it, so say that, using each locale's word for attribute. Spell this out in the en.json description for future passes. * Use the glossary term 用户组 for user groups in zh-CN zh-CN rendered user groups (synced AD/LDAP groups, custom groups, group mentions) as 群组, which it also uses for group messages. Switch the user-group sense to the glossary target 用户组, leaving group messages and group channels as 群组. * Add five glossary terms from the health dashboard and push settings health dashboard, health finding, Agents plugin, Hosted Push Notification Service and PushNotificationServer appeared in new strings with no agreed rendering. Targets follow each locale's majority rendering, with notes recording the catalog strings that deviate. * Render Hosted Push Notification Service per the glossary The push terms checkbox and help text garbled, truncated or dropped the service name in most locales (vi "Hosted Hosted", ro "Împinge", it with no name at all), and cs, zh-CN and zh-TW called the hosted service TPNS. Use each locale's new glossary target. * Point the TPNS help text at the Test Push Notification Service The help under the TPNS option told admins to learn about the Hosted Push Notification Service, copied from the HPNS help. Name the test service and rename its link tag to linkTPNS to match; the docs link is unchanged since one page covers both services. * Spell Romanian "pluginul" without a hyphen The ro catalogs mixed "plugin-ul" with "pluginul". Romanian hyphenates the article only when a loanword's final letter is not pronounced as written, so use "pluginul", "pluginuri" and so on throughout, and correct the glossary note that asked for the hyphen. * Keep push service names in English in the glossary Hosted Push Notification Service and Test Push Notification Service are named Mattermost services, so mark both doNotTranslate, as for Calls and Playbooks, and add the missing TPNS entry. Locale notes say how to frame the name grammatically. * Retranslate push service help and names per the glossary Retranslate the TPNS help text from its corrected English, keep the service names in English where catalogs had translated them, and fix help text that was half English or garbled (ro, vi, lt). * Use neuter forms of "plugin" in Swedish The sv glossary treats plugin as neuter (ett plugin), but many strings used common-gender forms such as "pluginen", "Agents-pluginen" and "en plugin". Use "pluginet", "ett plugin" and neuter agreement throughout. * Fix "uptime SLA" in the Swedish HPNS option "senast SLA" read as "latest SLA". * Fix zh-CN team group sync description saying adding a user removes them |
||
|
|
2de97aee85 |
[MM-69775] Delete the server-side draft when sending from the Drafts panel (#38861)
* MM-69775: Delete the server draft when sending from the Drafts panel Sending a draft from the Drafts panel only cleared the locally stored copy: createPost dispatches storeDraft(null), which is a setGlobalItem and never reaches Client4.deleteDraft. The server draft survived and getDrafts restored it on the next team switch or reload. The channel composer is unaffected because its handleDraftChange sees the emptied draft after submit and dispatches removeDraft, which does delete the server copy. afterSubmit now calls handleOnDelete for a plain send as well as for a scheduled one, leaving the scheduled-post send path untouched. Co-authored-by: mattermost-code <matty-code@mattermost.com> * MM-69775: Cover the Drafts panel send path with real submit wiring draft_row.test.tsx mocked useSubmit outright, so nothing exercised what DraftRow does after a post is created. The mock is gone and the action rows are now interactive fakes that invoke the real callbacks, so the tests run through useSubmit, onSubmit, createPost and afterSubmit and assert on the requests Client4 actually receives. Covers a plain channel send, a thread send, scheduling, sending a scheduled post, and both failure paths. Co-authored-by: mattermost-code <matty-code@mattermost.com> * MM-69775: Add E2E coverage for sending a draft from the Drafts panel Both specs assert the server draft list is empty after the send, which is the invariant the bug broke; the UI assertions alone could not see it for the thread case. Reverting the draft_row fix fails both specs on that assertion. DraftsPage gains the Send message now modal and a sendDraft helper, mirroring ScheduledPostsPage. Co-authored-by: mattermost-code <matty-code@mattermost.com> * MM-69775: Drop the now-dead isBeingScheduled ref and sharpen the tests afterSubmit no longer branches on isBeingScheduled, which left the ref written in two places and read in none, so it is gone. Test changes come from a review pass that found three assertions which passed with the fix reverted: - the drafts-list assertion is now driven by a fake server draft table that deleteDraft mutates and getUserDrafts serves back, with a real getDrafts refetch, so it reproduces the reported symptom - the create-failure test became a pending-promise test, since a rejected createPost never reaches afterSubmit; it now pins that the delete waits for the created post instead of firing on click - the scheduled-post test also asserts the live channel draft survives, which kills a keepDraft flip, and sends twice - the Playwright thread test dropped its post-reload assertions, which could not fail for this bug, and says what it actually proves Co-authored-by: mattermost-code <matty-code@mattermost.com> * MM-69775: Assert the scheduled draft leaves the panel, not just the server Scheduling returns before createPost, so handleOnDelete is the only thing that clears the local copy on that path. Asserting only on deleteDraft's arguments let a wrong storage key survive: the server delete still looked right while the row stayed in the Drafts panel. Also assert the fake server draft table itself shrank after a plain send, so a degraded fixture cannot quietly weaken that test. Co-authored-by: mattermost-code <matty-code@mattermost.com> * MM-69775: Tighten comments across the change Drops comments that restated the assertion on the following line, keeps the ones carrying facts the code cannot show, and matches the comment style of each surrounding file. 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> |
||
|
|
640b099b64 |
Update minimum supported Firefox version (#39253)
* Update minimum supported Firefox version * Update minimum supported Firefox version in the requirements docs Matches the i18n change in this PR: the PC web browser support table now lists Firefox v153+ for both self-hosted and Cloud. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Nrmq4ezefYWqa9YkxtX3mR --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
b25056d4ea |
drip: AppError -> error: delivery tracking (#39171)
* drip: AppError -> error: delivery tracking Return error from validateTrackedChannelIDs so callers no longer receive a concrete *model.AppError that can collapse into a typed nil. Co-authored-by: jesse <jesse@mattermost.com> * Add model.AsAppError and Context.SetError for error-to-AppError boundaries * Use model.AsAppError in SaveDeliveryTrackingConfig * Use model.AsAppError in TestLdapConnection and TestLdapDiagnostics --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: jesse <jesse@mattermost.com> |
||
|
|
2657f70938 |
[MM-71062] Health Dashboard PR26: rules for license and seats (#38916)
* [MM-71062] Add license seat and expiry snapshot accessors LicenseSeats and LicenseExpiresAt read the leader's license summary, so license rules give the same answer offline as live. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * [MM-71062] Add health rules for license and adoption Ten rules in a new license area package: license expiry, trial license, seat utilization and the enforced seat limit, monthly engagement, and how much of Mattermost's integration surface is in use. Seats are counted the way the server counts them, and expiry is measured against the snapshot's collection time. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com> * [MM-71062] Report why license and adoption rules are unknown Unknown results now carry the shared reason for the missing source (license, stats, plugins, collection time) instead of an empty id. SEATS_LOW_ENGAGEMENT keeps its own reason for a server with no active users, which no shared reason describes. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com> * [MM-71062] Simplify license rules Reuse seatUtilization in the seat limit rule, use License.IsTrialLicense, and trim comments. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * [MM-71062] Count single-channel guests as seats when guest accounts are disabled Mirror GetServerLimits, which only exempts single-channel guests while guest accounts are enabled. Keep the trial rule on the raw IsTrial flag so live and Support Packet results agree. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * [MM-71062] Describe seats as counting toward the license limit Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * [MM-71062] Evaluate the engagement and workflow usage rules on Cloud Cloud admins can change these settings, unlike the cloud_restrictable ones or the pages RestrictSystemAdmin hides. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * [MM-71062] Read the license rules' inputs from leader diagnostics Snapshot.License is now an accessor over the Support Packet license summary, so the rules and their tests read it from the leader node. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * [MM-71062] Fix shadowed ok in seatsUsed Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * [MM-71062] Align the latest version in the packet-without-expiry parity check * [MM-71062] Remove code text from engagement subtest names * [MM-71062] Record the canonical trial status in the Support Packet Use License.IsTrialLicense() so trials recognized only by their duration are reported as trials. * [MM-71062] Describe seats as counted users and qualify license removal The seat messages count users who take a seat, not active users. The server never removes an expired Mattermost Entry license, so the removal consequence moves from the remediation into the message, with an Entry variant that omits it. * [MM-71062] Drop the trial, utilization, engagement and workflow rules LICENSE_TRIAL duplicated LICENSE_EXPIRING for the whole trial; the trial status now selects a trial variant of the expiry messages instead. SEATS_LOW_UTILIZATION, SEATS_LOW_ENGAGEMENT and the WORKFLOW_USAGE codes are account-management signals, not problems an admin can fix. * [MM-71062] Move the seat rule tests to seats_test.go * [MM-71062] Simplify the seat rule helpers * [MM-71062] Add SupportPacketLicense.IsMattermostEntry * Drop the unreachable Entry message from LICENSE_EXPIRED LoadLicense rebuilds the Entry license in memory with a fresh 100-day expiry every time it runs, so an Entry snapshot can never reach either expiry rule. * Resolve both license expiry rules for Mattermost Entry The server never expires an Entry license, so neither rule should fire for one, matching doLicenseExpirationCheck. --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
f79ba36eed |
Skip flaky TestDoSetupContentFlaggingProperties (MM-71223) (#39249)
* Skip flaky TestDoSetupContentFlaggingProperties Skipping while the root cause is investigated under MM-71223. Tests-only change. Co-authored-by: mattermost-code <matty-code@mattermost.com> * Retrigger CodeRabbit review 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> |
||
|
|
7df5e30433 |
[MM-71059] Health Dashboard PR21: rules for jobs (#38914)
* [MM-71059] Add health rules for stuck, wedged and failed jobs JOB_STUCK, JOB_WEDGED_AT_ZERO and JOB_FAILED report one result per collected job type. Each type is gated on the setting that runs its worker, and ages are measured from the snapshot's collection time. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com> * [MM-71059] Cover the job rules in the packet fixtures The fixtures gain the job gate settings and realistic job runs, so the standalone packet reports a failed LDAP sync and the HA packet a stuck message export. The mmctl test packet gets the settings and jobs file it needs to stay fully evaluated. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com> * [MM-71059] Exercise the job rules in the live/offline parity test Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com> * [MM-71059] Use the shared reasons for missing jobs data The job rules' unknown results for missing job history and an unknown collection time now use ReasonJobsUnavailable and ReasonCollectedAtUnknown, so their five per-code ids are gone. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com> * [MM-71059] Tidy the job rule tests Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * [MM-71059] Look past pending runs queued behind a stuck job Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * [MM-71059] Report unknown when queued runs fill the collected job history Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * [MM-71059] Skip canceled runs when checking for a failed job A worker stop on restart or upgrade cancels the running job, so a canceled run after a failure cleared JOB_FAILED without any run having succeeded. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * [MM-71059] Fire JOB_WEDGED_AT_ZERO on idle time instead of runtime Progress is a whole percentage for search indexing and message export, so a large job that is working still reads 0 for hours and fired the rule after 6h. Every batch updates LastActivityAt, so requiring an hour without activity only catches jobs that never got going, and catches them sooner. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * [MM-71059] Resolve old data retention failures once retention is off With both global deletion settings off and no custom policy, the scheduler stops creating data retention runs, so a failed run stayed the latest one and JOB_FAILED fired forever. Custom policies are not in the snapshot, but an active one would have produced a newer run within a week. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
a21d6019b5 |
Add a hub channel broadcast benchmark (#38991)
* Add a hub channel broadcast benchmark BenchmarkHubChannelBroadcast measures delivering one channel-scoped posted event through the production WebSocket hubs (one per CPU): publish with PublishSkipClusterSend, then wait until every member connection has received it. There are 5000 connections, each user a member of 200 channels drawn from a pool of 20000; 50 or all 5000 of them belong to the event's channel. Cases cover EnableWebHubChannelIteration off and on, plus a churn case (on, 50 members) that invalidates a random user's channel membership every millisecond while membership loads take a millisecond, as a primary database round trip would. Membership loads are served from an in-memory store stub that returns freshly allocated strings on every load, like a database scan, so the benchmark needs no database. An untimed warm-up fills the per-connection membership caches as the first event does in production. Besides time and allocations per event, each case reports: - live-MB, live-kobjs: heap and objects held once connections have loaded their memberships - gc-ms: wall time of a full collection over that heap - p99-us: 99th percentile latency of one event Each case drops its connections and stops its hubs, so every case starts from the same heap. There is no benchmark at this level today (the existing hub benchmarks cover the connection index only). It uses only existing APIs, so it runs unchanged before and after changes to the broadcast path and gives those changes a common, reproducible measurement. Release Note: NONE Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Use the nearest-rank index for the benchmark's p99 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Read the benchmark's base heap after the store is filled The mock channel store's memberships (5000 slices of 200 IDs, plus the ID pool) were allocated after the base reading, so the live heap the benchmark reports counted them: about 17 MB that belongs to the fixture, not to the hubs or connections. The store is now filled first, then the base is read, then the platform starts and the connections register. Same for every case, so earlier comparisons hold; the absolute live-heap figures are lower by the fixture's size. Release Note: NONE Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
acb011f1ea |
[MM-71100] Health Dashboard PR25: rules for platform, filestore, logging and plugins (#39020)
* [MM-71100] Health Dashboard PR25: rules for platform, filestore, logging and plugins Adds the rules/platform package with 14 codes: file storage (local storage in a cluster, S3 bucket and SSL, the connection test), logging, metrics, plugins (framework, health check, enabled plugins that are not running), the server OS, privileged listen ports, and per-node file descriptor use. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * [MM-71100] Health Dashboard: update packet fixtures and finding expectations for the platform rules The fixture configs gain the file, log, metrics and plugin settings a real packet carries. The parity test ignores the file descriptor ratio, which each collection samples separately. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * [MM-71100] Health Dashboard: reuse shared test helpers in the file descriptor rule tests Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * [MM-71100] Health Dashboard: resolve the cluster file storage rules before reading the driver Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * [MM-71100] Health Dashboard: resolve METRICS_OFF when the license lacks the Metrics feature Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * [MM-71100] Health Dashboard: merge the cluster local file storage rules and check file storage on every node FILESTORE_LOCAL_IN_CLUSTER now covers relative and absolute directories as a single warning, since the HA guide's ./data/ on an NFS mount is a valid shared setup. FILESTORE_UNREACHABLE evaluates each node's connection test, and BIND_PRIVILEGED_PORT says the warning stays after granting the capability through systemd. * [MM-71100] Health Dashboard: lower LOG_FILE_OFF to info The message already says file logging off is fine when an external collector captures the logs, so a warning overstates it. * [MM-71100] Health Dashboard: move LOG_DEBUG_PROD and PLUGINS_OFF to internal, reword LOG_FILE_OFF LOG_DEBUG_PROD drops to info. LOG_FILE_OFF now explains that without a log file the Support Packet carries no server logs, even when an external collector captures stdout. * [MM-71100] Health Dashboard: lower ENV_UNSUPPORTED_OS to warning * [MM-71100] Health Dashboard: simplify platform rules and their tests * [MM-71100] Health Dashboard: enable metrics in the live/offline parity test --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
c77a59ea33 |
Add dot release docs for server v11.11.2, v11.10.3 and v11.7.13 (ESR) (#39004)
* Add dot release docs for server v11.11.2, v11.10.3 and v11.7.12 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DR6hsSCuRfXqAnyHNY7sKo * Update mattermost-v11-changelog.mdx * Move v11.7.12 docs out to their own PR The v11.7.12 (ESR) content from this PR now lives in its own branch and PR so it can land on its own schedule, independently of v11.11.2 and v11.10.3. Removed here, unchanged there: - deploy-rhel.mdx / deploy-tar.mdx: Current ESR back to 11.7.11 - mattermost-server-releases.mdx: v11.7 row back to 11.7.11 - mattermost-v11-changelog.mdx: 11.7.12 entry removed - version-archive.mdx: v11.7 Enterprise and Team entries back to 11.7.11, including their original SHA-256 checksums This PR now covers v11.11.2 and v11.10.3 only. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Nrmq4ezefYWqa9YkxtX3mR * Update mattermost-v11-changelog.mdx * Refresh v11.11.2/v11.10.3 notes and add v11.7.13 dot release docs Adds the release notes merged to release-11.11 and release-11.10 after this PR was drafted, backfills three entries that shipped in v11.7.12 but were missed in its changelog entry, and documents the v11.7.13 ESR dot release across the five dot-release pages. 11.11.2: Jira v4.8.2, EXIF orientation read (#38739), connection string reporting (#38644), received_group WebSocket scope (#38299), PDF content-stream array parsing (#38781). 11.10.3: EXIF orientation read (#38739), connection string reporting (#38644), PDF content-stream array parsing (#38781). 11.7.12: EXIF orientation read (#38739), PDF content-stream array parsing (#38781), signed-in user's theme on the full-page error screen (#38812). All three are in the v11.7.12 tag but were merged after the entry was written. 11.7.13: new entry for Jira v4.7.4 and the commits in release-11.7 since the v11.7.12 tag, plus the ESR version bump in the deployment guides, the server releases table and the version archive. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Nrmq4ezefYWqa9YkxtX3mR * Update mattermost-v11-changelog.mdx * Add GitLab plugin v1.13.1 to the v11.11.2 and v11.10.3 notes Picks up the prepackaged GitLab bump merged to release-11.11 (#39139) and release-11.10 (#39138) after the last changelog refresh. No new commits on release-11.7 since v11.7.13 was written up. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Nrmq4ezefYWqa9YkxtX3mR * Add the Enable File Search setting to the v11.7.13 notes Picks up #39059, cherry-picked to release-11.7 as #39148 after the last changelog refresh. No new commits on release-11.11 or release-11.10. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Nrmq4ezefYWqa9YkxtX3mR * Update mattermost-v11-changelog.mdx * Add Elasticsearch file indexing setting and move dot releases to Oct 19 Adds the ElasticsearchSettings.EnableFileIndexing bullet to the v11.7.13 entry (server #39058, cherry-picked to release-11.7 as #39147), and moves the v11.11.2, v11.10.3, and v11.7.13 release dates to 2026-10-19. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Nrmq4ezefYWqa9YkxtX3mR * Add OpenSearch indexing fixes to the v11.7.13 release notes Covers server #39151 (MM-70268), cherry-picked to release-11.7 as #39244: the stalled OpenSearch bulk indexing timeout and the nil-pointer panic in the shared search logger on failed node discovery. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Nrmq4ezefYWqa9YkxtX3mR * Update version-archive.mdx * Update version-archive.mdx --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
08cf1105ab |
[MM-71060] Health Dashboard PR23: rules for notifications and messaging (#38912)
* [MM-71060] Add the ConfigInt64 health snapshot accessor TeamSettings.MaxNotificationsPerChannel is the first rule input stored as *int64, so rules need an int64 counterpart to ConfigInt. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com> * [MM-71060] Add notification and messaging health rules Adds PUSH_ID_ONLY, LINK_PREVIEWS_DISABLED, MAX_NOTIFICATIONS_PER_CHANNEL, TYPING_MESSAGES_AT_SCALE and SMTP_UNREACHABLE to the notifications area, with their English text. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com> * [MM-71060] Update packet and parity expectations for the messaging rules The packet fixtures gain the default values of the settings the new rules read, so offline evaluation resolves them instead of reporting unknown. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com> * [MM-71060] Scope the push round-trip test to the push server codes PUSH_ID_ONLY fires under the test server's default push contents. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * [MM-71060] Use shared unknown reasons and keep parity off SMTP TYPING_MESSAGES_AT_SCALE and SMTP_UNREACHABLE now report the shared ReasonStatsUnavailable and ReasonDiagnosticsUnavailable instead of their own ids. The live/offline parity test turns email notifications off so the two collections never probe SMTP separately. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com> * [MM-71060] Simplify the SMTP rule guard and push test filtering Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * [MM-71060] Share one generic body across the config accessors Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * [MM-71060] Check the SMTP leader explicitly and assert value checks Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * [MM-71060] Evaluate the push contents and link preview rules on Cloud Cloud admins can change these settings, unlike the cloud_restrictable ones or the pages RestrictSystemAdmin hides. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * [MM-71060] Note that configValue can become a generic method on Go 1.27 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * [MM-71060] Only flag full push contents when the license offers id_loaded full is the server default, and without the ID-only push notifications feature the server falls back to generic, so the finding is only actionable when the license includes it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Drop LINK_PREVIEWS_DISABLED rule It only reports a setting an admin deliberately turned off, so it adds noise without a useful signal. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Drop TYPING_MESSAGES_AT_SCALE rule Typing events are already bounded by MaxNotificationsPerChannel, the client throttle, and server-side delivery only to viewers of the channel, so total account count is a poor proxy for typing load. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Clarify push and channel-mention health rule text PUSH_ID_ONLY now states the device reachability cost of id_loaded and when to mute. MAX_NOTIFICATIONS_PER_CHANNEL now matches its 5000 threshold and states that lowering the limit disables channel-wide mentions in larger channels. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * [MM-71060] Probe SMTP for invitations and verification, fix mention limit wording Invitation and verification emails go through SMTP even when notification emails are off, so the Support Packet probe and SMTP_UNREACHABLE now run when any of those is enabled. Channel-wide mentions are blocked once a channel reaches MaxNotificationsPerChannel, not only above it; the finding now shows the configured limit instead of an off-by-one member count. * [MM-71060] Set the SMTP-gating settings in the mmctl test packet The SMTP rule now reads RequireEmailVerification and EnableEmailInvitations, so a packet missing them reports the rule as not evaluated. * [MM-71060] Probe SMTP when password sign-in is enabled Local password users can request a reset email even with notification, verification and invitation emails off, so SMTP_UNREACHABLE and the Support Packet probe now also run when email or username sign-in is on. * [MM-71060] Reduce merge conflicts in health rule test fixtures Expected finding lists are sorted by code and the mmctl test packet config is built from defaults, so parallel rule PRs stop editing the same lines. --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
353f76fe30 |
[MM-71101] Health Dashboard PR19: rules for database (#39021)
* [MM-71101] Add ConfigStrings snapshot accessor ConfigStrings reads list settings such as DataSourceReplicas. It returns ok=false when the config section is absent or any element is redacted, so a redacted replica DSN cannot be read as a host name. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * [MM-71101] Add database health rules Ports the database checks from the health check script into a new rules/database package: replica sizing, Trace, MaxOpenConns, QueryTimeout, HA failover connection bursts (merged with the pooler check), PostgreSQL version, pool saturation, unused replicas, IP-literal DSN hosts, replica lag monitoring and MaxIdleConns above MaxOpenConns. Rules that read DSNs only report derived facts; no DSN or host leaves the rule. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * [MM-71101] Update health packet fixtures and expectations for database rules The fixture configs gain the SqlSettings and ElasticsearchSettings keys a real packet carries, and the HA fixture raises MaxOpenConns to 200 so the golden set covers DB_HA_FAILOVER_STORM_RISK offline. The mmctl test packet gains the database diagnostics and stats the rules read, and the parity test expects DB_QUERY_TIMEOUT_HIGH from the test store's 60 s timeout. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * [MM-71101] Parse every DSN host and skip non-Postgres version checks hostsFromDSN replaces hostFromDSN and returns every host a DSN names: comma-separated host lists, host/hostaddr query parameters in URL form, and hostaddr in keyword form. DB_CONNECTION_IS_IP fires when any host is an IP; the failover rule treats a DSN as pooled when any host is a pooler. DB_POSTGRES_UNSUPPORTED returns unknown when the diagnostics report a database type other than Postgres, so older MySQL packets no longer raise a Postgres version warning. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Raise DB_NO_SEARCH_REPLICA threshold to 2M posts Matches the documented point where database search starts to degrade. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Remove DB_CONNECTION_IS_IP rule An IP address in a DSN is correct for loopback, floating VIPs and k8s services, and harmless on single-node installs, so the rule was mostly noise. hostsFromDSN stays for the failover rule's pooler check. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Remove DB_REPLICA_LAG_UNMONITORED rule ReplicaLagSettings only feeds Prometheus gauges, and managed databases already report replica lag, so the rule was an observability nudge with nothing misconfigured. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Simplify database health rules and tighten failover storm risk - Drop Snapshot.ConfigStrings; its only caller now just counts entries. - Parse only URL-form DSNs: sanitized config redacts every other form. - DB_HA_FAILOVER_STORM_RISK counts only primary pools in the burst and treats loopback hosts and Unix sockets as a per-node pooler. - DB_POOL_SATURATED checks the unlimited-pool gate before reading diagnostics. - Share the minimum PostgreSQL version via model so sqlstore and DB_POSTGRES_UNSUPPORTED cannot drift apart. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fire DB_HA_FAILOVER_STORM_RISK when any host bypasses the pooler The driver tries a host list in order, so a direct host in the list can take the full reconnection burst. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Skip DB_NO_SEARCH_REPLICA when database search is disabled DB_POSTGRES_UNSUPPORTED now also reports unknown when the database type is missing. * Base DB_REPLICA_UNUSED on replica online state Open connection counts drop to zero on idle replica pools, so the rule now reads a new replicas_online support packet diagnostic. --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
f491fb9299 |
[MM-71058] Health Dashboard PR20: rules for search (#38913)
* [MM-71058] Add the search health rules Ports the Elasticsearch / OpenSearch checks: localhost ConnectionURL in a cluster, a failed connection test, post-count scale thresholds, live indexing batch size, unsupported major version, missing analysis-icu plugin, and skipped TLS verification. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com> * [MM-71058] Cover the search rules in the packet fixtures The fixtures had no ElasticsearchSettings or search diagnostics, so the search rules could only report unknown offline. Standalone now runs with indexing off; HA runs OpenSearch with an upgraded LiveIndexingBatchSize of 1. The mmctl test packet gets the search data every real packet has. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com> * [MM-71058] Use the shared reasons in the search rules The post count and the leader's search diagnostics are plain missing sources, so they report the shared stats and diagnostics reasons instead of per-code strings. The version rule keeps its own reason, now only for an unrecognized backend or version, and the ICU rule keeps its reason for a plugin list skipped because the version could not be read. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com> * [MM-71058] Share the indexing gate across the search rules Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * [MM-71058] Tighten the search rule edge cases Report an uncollected cluster version as unavailable, mask passwords containing '@', treat batch sizes <= 1 as synchronous, and flag unspecified addresses as local. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * [MM-71058] Fire the search scale rules above the post thresholds Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Add SEARCH_UNAVAILABLE rule and no-fallback ES_SERVER_ERROR message SEARCH_UNAVAILABLE fires when SqlSettings.DisableDatabaseSearch is on and Elasticsearch searching is off, so searches silently return nothing. ES_SERVER_ERROR now says search is fully down when there is no database fallback. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * [MM-71058] Lower ES_MISSING_ICU to info and drop the batch size default The plugin list is advisory and cannot prove a plugin is absent, so the missing ICU finding is informational until per-node plugin data exists. * [MM-71058] Avoid duplicate search findings and simplify the search rules The scale rules resolve when database search is disabled, and ES_SERVER_ERROR uses the no-fallback message only while Elasticsearch serves search, so SEARCH_UNAVAILABLE alone reports a fully disabled search. The loopback check also matches localhost. and *.localhost. * [MM-71058] Split the unsupported search version message by direction Upgrading the search cluster is the wrong advice when it is newer than the supported range, so the finding message now says whether the cluster is too old or too new, and the remediation is direction-neutral. --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
03f584b735 |
test(e2e): add pw.ensureDemoPlugin fixture, dedupe demo plugin URL (#38918)
* test(e2e): add pw.ensureDemoPlugin fixture, dedupe demo plugin URL
Centralizes the demo plugin id/URL/version into a single constant
(lib/src/constant.ts) instead of three separate hardcoded copies, and
replaces the old setupDemoPlugin(adminClient, pw) helper — called
redundantly at the top of nearly every demo plugin spec — with a
pw.ensureDemoPlugin({activate}) fixture.
The setup project now installs and configures the plugin once for the
whole run via pw.ensureDemoPlugin({activate: false}); individual specs
activate it themselves via the (default activate: true) fixture call,
which is now a cheap no-op once the plugin is already installed and
active — patching PluginSettings/reinstalling on every call was found
to make the plugin supervisor reload repeatedly and eventually get
stuck inactive after enough consecutive specs.
Also bumps the demo plugin to v0.12.1 (fixing a previously-skipped
test), removes now-unnecessary test.setTimeout calls and magic-number
assertion timeouts now that activation is fast, and reformats demo
plugin spec comments to the repo's "# step / * assertion" convention.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* test(e2e): force a clean plugin reload after crash recovery
ensureDemoPlugin() is a no-op once isPluginActive() is true, so it no
longer re-applies patchConfig on every demo-plugin spec the way the
old setupDemoPlugin() did. That unconditional per-spec patchConfig
call was incidentally triggering a full plugin supervisor reload (a
clean OnActivate) before nearly every spec, which papered over any
partial corruption left by plugin_crash.spec.ts's deliberate crash:
the server's auto-restart only guarantees isPluginActive flips back
to true, not that every hook (interactive dialog submit, post action
callbacks) came back in a working state.
With that incidental self-healing gone, whichever demo-plugin spec
happens to run next after plugin_crash.spec.ts in a given worker can
inherit a plugin that reports active but whose submit/callback paths
are still broken - matching the CI failures on PR #38918 in
demo_ephemeral.spec.ts, demo_dialog.spec.ts, demo_dialog_date.spec.ts,
and demo_dialog_field_refresh.spec.ts (dialogs open fine but never
close after submit, or post actions never update the post), always
exactly one such failure per run, immediately downstream of the crash
test.
Force a real disable/enable cycle after verifying crash recovery so
later specs in the same worker inherit a fully, not just nominally,
recovered plugin.
Co-authored-by: saturnino <saturnino@mattermost.com>
* test(e2e): fix prettier formatting in demo plugin fixture files
npm run check (ci/playwright/npm-check) was failing on this branch:
lib/src/index.ts, lib/src/server/plugin.ts, and plugin_crash.spec.ts
had pre-existing prettier violations (lines exceeding printWidth).
Re-formatted with 'prettier --write' so lint/prettier/tsc all pass
locally before push.
Co-authored-by: saturnino <saturnino@mattermost.com>
* test(e2e): fix test-isolation bug in demo_sidebar_components.spec.ts
The first test asserted the hooks toggle indicator shows 'Enabled' as an
ambient precondition without first establishing that state. A concurrently
running instance of this spec (e.g. via --repeat-each) or another spec
toggling the same global /demo_plugin hooks state could leave it disabled,
causing a flaky failure on the initial assertion. Explicitly enable hooks
first, using the same resilient retry pattern as demo_plugin_hook_toggle.spec.ts
(re-enable via adminClient + poll for active state if the plugin is
transiently unavailable).
Co-authored-by: saturnino <saturnino@mattermost.com>
* test(e2e): add crash-tolerance retries to demo plugin webapp specs
demo_channel_header_button.spec.ts and demo_root_modal_post_dropdown.spec.ts
interact with demo-plugin-rendered UI (App Bar button, post actions menu
items) with no tolerance for the plugin being transiently unavailable, e.g.
while a concurrently running plugin_crash.spec.ts worker is mid
crash-recovery. Add retry loops (reload + re-click for the App Bar button;
reopen menu + re-click for the post actions menu items) matching the
resilience pattern already used elsewhere in the demo_plugin suite
(demo_dialog.spec.ts, demo_interactive.spec.ts, demo_show_mentions.spec.ts).
Co-authored-by: saturnino <saturnino@mattermost.com>
* test(e2e): retry dialog submit/cancel actions on transient plugin failure
CI reported consistent failures (reproduced identically across the
enterprise job and 3 separate upgrade-matrix jobs) where demo_dialog.spec.ts
and demo_dialog_field_refresh.spec.ts's dialog remained open after clicking
Submit/Create Project, or demo_dialog.spec.ts's cancellation post never
appeared after clicking Cancel. In all cases the dialog opened successfully
(so the earlier open-dialog retry wasn't the issue); the submit/cancel
network request itself silently failed, consistent with the demo plugin
being transiently crashed/unavailable due to a concurrently running
plugin_crash.spec.ts worker.
Add retry loops around the submit/cancel actions: re-click Submit/Create
Project (idempotent — filled-in fields are retained) if the dialog doesn't
close, and reopen+re-cancel the dialog if the cancellation post doesn't
appear after a successful close. Also harden demo_dialog_field_refresh.spec.ts's
initial dialog-open retry and demo_ephemeral.spec.ts's /ephemeral_override
command with the same sendDemoSlashCommand + retry pattern used elsewhere.
Co-authored-by: saturnino <saturnino@mattermost.com>
* test(e2e): widen demo plugin retry budgets to outlast plugin_crash recovery
CI still showed demo_dialog.spec.ts, demo_dialog_field_refresh.spec.ts, and
demo_ephemeral.spec.ts failing after the previous retry fix, plus newly
surfaced the same failure mode in demo_interactive.spec.ts and
demo_dialog_date.spec.ts. plugin_crash.spec.ts's documented worst-case
recovery (crash detection + isPluginActive poll + forced disable/enable
cycle) is ~50s, but the prior retry loops only budgeted 4 x 10s = 40s,
and the suite's default 60s test timeout left no room to extend that
within the existing structure.
Add test.slow() (triples the per-test timeout) to each affected test and
widen the submit/click retry loops to 8 attempts (~80s), comfortably
outlasting the documented recovery window. Also add the same retry
pattern to demo_ephemeral.spec.ts's Update/Delete button clicks and
demo_interactive.spec.ts's Interactive Button click, which had no retry
at all despite making the same kind of request that silently fails
during a plugin crash.
Co-authored-by: saturnino <saturnino@mattermost.com>
* test(e2e): widen dialog submit retry budget to outlast compounded plugin_crash recovery
CI on this PR observed demo_dialog_date.spec.ts failing twice across the
rolling-upgrade matrix (release-11.9, release-11.10) with the dialog still
visible after exhausting the 8-attempt/~80s submit-retry budget. Root
cause: if a concurrent plugin_crash.spec.ts worker itself needs a
Playwright CI retry, its crash+recovery cycle effectively runs twice
back-to-back, pushing the broken-hook window past our originally assumed
~50s (and past the 80s retry budget meant to cover it) to ~100s+.
Widen the submit/cancel retry loops in demo_dialog.spec.ts,
demo_dialog_date.spec.ts, and demo_dialog_field_refresh.spec.ts from 8 to
12 attempts (~120s), and switch from test.slow() (an implicit 3x
multiplier) to an explicit test.setTimeout(duration.four_min) so the
outer test timeout has clear, generous headroom over the retry budget.
Co-authored-by: saturnino <saturnino@mattermost.com>
* test(e2e): restore ensureDemoPlugin/demoPluginId exports dropped while adding permalinkUrl
Adopting permalinkUrl() from another branch's index.ts/server/index.ts via
a wholesale file checkout clobbered this PR's own ensureDemoPlugin,
demoPluginId, demoPluginUrl, and EnsureDemoPluginOptions exports (added
earlier in this branch, after the other branch's copy was taken). This
broke the lib's rollup build (test_fixture.ts imports ensureDemoPlugin
from ./server) for any uncommitted work importing permalinkUrl, though it
never reached a commit or CI.
Co-authored-by: saturnino <saturnino@mattermost.com>
* test(e2e): fix CPA field reuse to reset leftover attrs and permission pins
setupCustomProfileAttributeFields() reused a same-name/type field as-is,
silently inheriting whatever visibility/managed/value_type/display_name a
prior test left on it. Because custom profile attribute field names are
unique server-wide and ABAC's edit_policies tests share this same helper
and field namespace (both live in the AccessControlPropertyGroupName
property group), a field created by one suite (e.g. ABAC's
'Department'/'Office' with managed: 'admin') could be silently reused by
an unrelated custom_attributes.spec.ts test expecting a plain field, and
vice versa. This isn't a concurrency issue - these specs run sequentially,
one spec file at a time, within a single shard - it's state one test
leaves behind that the next test (same file retried, or a different file
later in the same shard) doesn't expect.
On a type or managed-state match, now patch the reused field's
visibility/value_type/display_name back to this call's request (nulling
any key the caller didn't specify so the merge-patch deletes the stale
value instead of preserving it). On a type or managed-state mismatch -
including a field whose permission_values is already stuck at sysadmin
from a prior managed: 'admin' state, since the server's merge-patch never
downgrades that pin - delete and recreate instead, so permissions are
computed fresh for the new state.
Also replaces edit_policies.spec.ts's MM-T5791/MM-T5792 destructive
delete-all-then-recreate setup (which silently swallowed delete errors,
letting an undeletable field collide with the very next unconditional
create) with this same reuse-by-name helper, matching the pattern
MM-T5790 already uses.
Verified by running edit_policies.spec.ts and custom_attributes.spec.ts
back to back against the same server (reproducing same-shard execution
order) three times via testcontainers: all 15 tests pass on every run.
Co-authored-by: saturnino <saturnino@mattermost.com>
* test(e2e): recover demo plugin interactive hooks mid-retry instead of blaming plugin_crash.spec.ts
demo_dialog.spec.ts (submit and cancel), demo_interactive.spec.ts, and
demo_dialog_field_refresh.spec.ts each retry their interactive-hook action
(dialog submit/cancel, button click) on transient failure, with comments
attributing the failure to a concurrent plugin_crash.spec.ts worker
recovering the shared demo plugin. That theory doesn't hold up: the
matrix's playwright jobs are one Playwright worker each with their own
isolated server, so there's no concurrent worker to blame, and CI job
logs confirm plugin_crash.spec.ts never ran on the shards that hit this
failure. The hooks genuinely stop responding for the rest of a worker's
run, for reasons not yet understood, and plain action retries don't clear
it.
Add recoverDemoPlugin() (disable/enable/poll-active, the same cycle
plugin_crash.spec.ts already uses after a deliberate crash) and call it
partway through each retry loop as a last-resort recovery step once plain
retries have had a chance to clear a merely-transient failure first.
Co-authored-by: saturnino <saturnino@mattermost.com>
* test(e2e): force profile-popover load before notification race check; widen masking cache-warmup retry budget
desktop_notification_support.ts: the marker-post-rendered signal doesn't guarantee the async
sender-profile fetch (which getNotificationUsername's getUser(state, post.user_id) depends on)
has resolved, so a notification firing right after can still race it and fall back to the raw
websocket sender_name. Open and close the marker post's profile popover, which only becomes
visible once its data has loaded, to force and wait out the same fetch.
masking_admin_roles.spec.ts: the ABAC enforcement cache can take longer than 6 retries to warm
up on a cold cache; widen the retry budget to 10 attempts and align the final assertion's
timeout with the loop's own per-attempt wait, with a proportionally increased test timeout.
Co-authored-by: saturnino <saturnino@mattermost.com>
* test(e2e): fix apostrophe_values.spec.ts policy-list pagination miss and ownedIds cleanup typo
The policy list page paginates at 10 rows; by the time this test runs, other
ABAC specs earlier in the same shard can have accumulated dozens of
policies, pushing the newly created one off page 1 so the row lookup never
finds it. Filter with the list's own Search box instead of scanning the
unfiltered first page, and widen the row-visibility timeout to leave room
for the list refresh after a save.
Also fix the afterEach cleanup call, which built the ownedIds marker under
the key __ownedIds instead of the ownedIds property deleteCustomProfileAttributes
actually checks for; the mismatch made it silently fall back to treating every
key of the plain object -- including the literal string "__ownedIds" -- as a
field ID to delete, producing a harmless but noisy 404 on every run.
Co-authored-by: saturnino <saturnino@mattermost.com>
* test(e2e): widen DirectChannelsModal.selectUser's remove-button timeout
Selecting a row re-renders the modal's selected-user chips; under load in CI
this can take longer than the default 10s expect timeout, causing MM-T460 and
MM-T466/MM-T480-style flakes in specs that select multiple group-message
members in sequence.
Co-authored-by: saturnino <saturnino@mattermost.com>
* test(e2e): avoid re-querying search after the indexing poll succeeds
postAndFindMessage polled userClient.searchPosts until it returned results,
then made a second, independent search call for the assertions. That second
call can race the search backend's own eventual consistency (e.g.
Elasticsearch's near-real-time refresh) and transiently see zero results
even though the immediately preceding poll attempt just found the post.
Reuse the exact results snapshot that satisfied the poll instead.
Co-authored-by: saturnino <saturnino@mattermost.com>
* test(e2e): surface CPA visibility-patch failures instead of swallowing them
updateCustomProfileAttributeVisibility() caught and console.log'd any patch
failure, then returned as if it had succeeded. If the patch is ever rejected
(e.g. a field left in a state the server won't allow a visibility patch
against) the test would silently keep going with the old visibility and fail
confusingly on a UI assertion minutes later instead of on the real cause.
Let the error propagate, and also verify the server echoed back the visibility
we asked for rather than trusting a 200 alone.
Co-authored-by: saturnino <saturnino@mattermost.com>
* test(e2e): add missing plugin-recovery cycle to demo_dialog_date.spec.ts
This spec's submit retry loop never forced a recoverDemoPlugin() cycle the
way its sibling demo_dialog.spec.ts does, so if the interactive dialog submit
hook ever got stuck it had no way to recover within the retry budget — it
would just keep clicking the same broken Submit button 12 times. Add the same
attempt-6 recovery cycle demo_dialog.spec.ts uses. Also corrects the spec's
doc comments from 'concurrent worker' framing to match how CI actually runs
these specs: one worker per job, tests run sequentially against a single
shared server, so the risk is prior-test state leakage within the same
worker, not true concurrency.
Co-authored-by: saturnino <saturnino@mattermost.com>
* test(e2e): wait for attribute view sync before checking masking RHS tags
MM-68508-23's CEL expression ANDs three separate user attributes together,
but unlike the other masking_admin_roles tests (which wait for
waitForAttributeViewToInclude before relying on policy evaluation), this one
went straight to polling the channel members RHS for the enforcement cache to
warm up. Under load a three-attribute expression can take longer for the
user-attribute view to resolve than the UI retry loop budgets for, so wait
for the attribute view to reflect the full expression first, the same way the
sibling tests in this file already do before assigning policies.
Co-authored-by: saturnino <saturnino@mattermost.com>
* test(e2e): never reuse a CPA field linked to a Global Attribute template
setupCustomProfileAttributeFields matched existing fields purely by name,
type, and managed state. A field left behind by a Global Attributes test
(linked_field_id set, e.g. a leftover 'Department' linked to a template's
'Applies to: User' resource) matched on all three and was reused as-is,
then later patched by updateCustomProfileAttributeVisibility -- which the
server now surfaces as a real error since that helper no longer swallows
failures: 'This field is linked to a Global Attribute template and cannot
be modified through the User Attributes API.' This was causing MM-T5776
to fail deterministically across the upgrade matrix jobs.
Detect linked_field_id on the existing field and route it through the
same delete+recreate path used for a type/managed mismatch, using the
generic property-field delete route (the CPA-specific one also rejects
deleting a linked field, since it exists to protect a live template's
dependents -- not to protect the dependent field itself).
Verified via testcontainers: reproduced the exact CI error message by
seeding a template + linked 'Department' field, confirmed
setupCustomProfileAttributeFields now returns a fresh unlinked field, and
confirmed updateCustomProfileAttributeVisibility succeeds against it.
custom_attributes.spec.ts passes x3 after the fix.
Co-authored-by: saturnino <saturnino@mattermost.com>
* debug(e2e): instrument demo plugin dialog retries to diagnose CI-only hang
Temporary, diagnostic-only instrumentation to narrow down why the demo
plugin's dialog submit/cancel hooks go permanently unresponsive partway
through some full-matrix CI runs, a symptom that recoverDemoPlugin()'s
disable/enable cycle does not fix (see its doc comment).
Logs, via console.log so it lands directly in CI job output:
- ServiceSettings.SiteURL, AllowedUntrustedInternalConnections, and
OutgoingIntegrationRequestsTimeout at the start of each retry loop and
around recoverDemoPlugin()'s disable/enable cycle.
- Demo plugin active/installed state at the same points.
- The actual HTTP status of every /api/v4/actions/dialogs/submit response
the browser receives, so we can tell whether the request ever completes,
hangs, or errors server-side.
Local reproduction against the exact real-CI predecessor specs (and an
in-progress larger-scale repro against the full auth+channels suite) has
not reproduced the hang, so this is meant to capture evidence from a real
CI run instead, where the bug has consistently reproduced. Intended to be
reverted once the root cause is confirmed.
Co-authored-by: saturnino <saturnino@mattermost.com>
* test(e2e): extend MM-68508-23 timeout budget for the attribute-view wait
The waitForAttributeViewToInclude() call added for this test's three-attribute
CEL expression can take up to 45s on its own, on top of the existing 10-attempt
UI retry loop's already-documented ~180s worst case. test.setTimeout(180000)
was sized only for the retry loop and left no room for the added wait, risking
a silent global test-timeout cutoff mid-retry (which surfaces as a generic
timeout error instead of the specific assertion failure, making a real
regression harder to diagnose). Bump to 240000 to cover the combined worst
case.
Co-authored-by: saturnino <saturnino@mattermost.com>
* TEMPORARY(validation-only): cherry-pick plugin activation race fix for real-CI confirmation
DO NOT MERGE. This is a throwaway validation commit, not a permanent part of
this e2e-test branch.
Cherry-picks the server-side fix from PR #38989
(cursor/fix-plugin-activation-race-condition-be2b, commit
|
||
|
|
3051bab1b2 |
update Calls to v1.12.6 (#39219)
Automatic Merge |
||
|
|
f38678d08d |
[MM-71099] Health Dashboard PR22: rules for cluster, deployment and network (#39022)
* [MM-71099] Read node versions from cluster info first A live snapshot attaches diagnostics to the leader only, so NodeVersion read the leader's version from diagnostics (CurrentVersion) and every follower's from gossip (CurrentVersion plus the build number). A healthy cluster then looked like two versions. Reading cluster info first, as SchemaVersion does, answers every live node from gossip; packet and standalone nodes have no cluster info and still answer from diagnostics. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * [MM-71100] Health Dashboard: name the standalone leader node from its diagnostics A live standalone snapshot left the leader's hostname empty, while the packet reader names the node from diagnostics.yaml. Node-scoped findings then got a different scope, and so a different fingerprint, live and offline. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * [MM-71099] Health Dashboard PR22: rules for cluster, deployment and network Adds eight checks to rules/cluster: gossip encryption, the LRU cache at scale, a configured cluster running a single node, an unreachable advertise address and a writable file config under HA, rate limiting off on a large instance and an undersized rate limit store, and version skew between nodes. Version skew emits one global result plus one result per node. Nothing reads NodeSnapshot.ConfigHash now that config drift is deferred, so it is removed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * [MM-71099] Health Dashboard: give the test packets the settings the cluster rules read The fixture configs and the mmctl test packet were trimmed to the settings earlier rules read, so the new rules reported them as unknown. They now carry the server defaults for gossip encryption, the cache and rate limiting, and every new rule resolves on them. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * [MM-71099] Health Dashboard: make CLUSTER_GOSSIP_UNENCRYPTED internal Keep the gossip encryption finding off the product surface for now. TestRegistered asserts each rule's surface instead of product for all. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * [MM-71099] Health Dashboard: drop the build number from gossip node versions Gossip advertises CurrentVersion.BuildNumber while support packets carry only CurrentVersion, so a build-number-only difference fired version skew live but not offline, and live details showed build numbers. NodeVersion now keeps the first three parts of the gossip version, so live and offline always agree. The System Console cluster table still warns on a build-only difference. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * [MM-71099] Health Dashboard: move the rate-limit rules to the platform area The rate limiter is a per-node API setting with nothing to do with HA, and RATELIMIT_OFF_LARGE fires on single-node installs too. RATELIMIT_OFF_LARGE and RATELIMIT_STORE_SMALL move to rules/platform with AreaPlatform, next to the other server runtime settings. platform_test.go shares its name with the platform rules PR's helpers on purpose, so merging the two conflicts instead of silently redeclaring them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * [MM-71099] Health Dashboard: reword the version skew no-majority reason Say in plain words that the nodes are split between versions, and fix the translator description: a tie for the most common version, not only an even split, leaves a node unknown. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * [MM-71099] Health Dashboard: surface CLUSTER_GOSSIP_UNENCRYPTED as info Show the gossip encryption finding to admins at info severity: it only fires when the default was explicitly turned off. The remediation now says the nodes must restart together, since encrypted and unencrypted nodes cannot talk to each other. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * [MM-71099] Health Dashboard: make RATELIMIT_OFF_LARGE internal info Rate limiting is off by default and the docs point larger installs at throttling in a load balancer, which the rule cannot see, so it would warn on most correctly run large installs. Keep it for CSE only. TestRegistered asserts each rule's surface. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * [MM-71099] Health Dashboard: compare the rate limit store with the user count The docs size RateLimitSettings.MemoryStoreSize to the expected number of users, so a small install with a store below the default but above its user count is configured correctly. RATELIMIT_STORE_SMALL now fires when the store is smaller than the registered users, and is unknown without stats. The mmctl test packet gets stats so it still resolves. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * [MM-71099] Health Dashboard: count only connected nodes for CLUSTER_SINGLE_NODE NumberOfNodes comes from GetClusterInfos, which also returns nodes that are registered in the database but not in the gossip cluster. A node cut off from gossip keeps pinging the database, so the rule resolved in the exact case it is meant to catch. The support packet now writes number_of_connected_nodes, counting only gossip members (those with an IP address), and the rule reads it. Packets without the field are unknown rather than falling back to the inflated count. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Co-authored-by: Mattermost Build <build@mattermost.com> |
||
|
|
f5227e664f |
[MM-71096] Apply incoming DeleteAt when receiving synced reactions (#39239)
* [MM-71096] Apply incoming DeleteAt when receiving synced reactions The shared channel receiver toggled reactions based on whether a matching row existed, ignoring the incoming DeleteAt. Re-sent active reactions were deleted, removed reactions the receiver never had were created as active, and remote-initiated removals rewrote the row's RemoteId to empty so they echoed back to the origin. Apply the sender's state idempotently instead, and keep the remote's ID on the row when deleting so the removal is not synced back. Co-authored-by: mattermost-code <matty-code@mattermost.com> * Retrigger CI after hung Postgres shard and unrelated Enterprise FIPS test failure. Co-authored-by: mattermost-code <matty-code@mattermost.com> * Address PR feedback: 0 answered, 2 resolved, 0 declined --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: mattermost-code <matty-code@mattermost.com> |