* Split out buttonClassNames utility and use for most places Button isn't
* Update StartTrialBtn to use buttonClassNames
Ideally, we'd:
1. Use Button, but that requires sorting out the one case that overrides
btnClass entirely.
2. Use a button for all of these since none of these should have a link
role, but that's outside of the scope of this ticket.
* Update another new button to use Button
* Lower default test console log level from stdlog to debug
Suppresses trace-level log spam (e.g. MlvlNotificationTrace) that
flooded CI output. MM_LOGSETTINGS_CONSOLELEVEL still overrides for
local debugging.
* Fix TestEnvironmentVariableHandling to expect debug default
Updates the assertion to match the new default console log level.
* feat(color_input): migrate ColorInput to function component
* test(color_input): migrate tests from enzyme to react testing library
* test(color_input): remove obsolete snapshots
* test(color_input): update snapshots
* test(color_input): update test
* refactor(color_input): remove unnecessary state update in function body
* Revert "refactor(color_input): remove unnecessary state update in function body"
This reverts commit 2c7647a3e4.
* Fix ColorInput tests
* Simplify click outside handler
By changing the button to always show the picker instead of toggling it
and making it so that the click outside handler checks for clicks
outside of the whole ColorInput, we can get rid of the setTimeout and
the very specific timing needed for the click outside handler.
* Wrap handleColorChange in useCallback
* Update snapshot
---------
Co-authored-by: Mattermost Build <build@mattermost.com>
Co-authored-by: Harrison Healey <harrisonmhealey@gmail.com>
* Add initial version of Button
* Use Button in ConfirmModal
* Use Button in easy places that use className='btn btn-primary'
This is everywhere that I could just replace `<button className='btn
btn-primary'>` with `<Button emphasis='primary'>` (and some other
emphasis versions) without any additional changes. There's still more
places where this could be used which require more in-depth changes that
will be in a following commit.
* Use Button in place of divs with className='btn btn-primary'
This is a minor functional change because these elements are now
accessible.
* Use Button in SpinnerButton
This is removing some usage of a save-button CSS class
that doesn't seem to affect these components.
* Replace RB Button with our Button
There's a small functional change here because the copy button in the
header of the FullLogEventModal is now styled when it wasn't before.
* Use Button in many places which used btn-secondary, btn-tertiary, and btn-danger
This removes some CSS classes from some different elements, but as
elsewhere, those CSS classes don't actually do anything. I think some
might have had a purpose once, but there seems to be quite a few that
were copied around during previous, possibly AI-assisted refactors.
* Use Button in many places in System Console
Notably, this includes:
1. Cleaning up some complicated logic in PurchaseLink/RenewalLink for
determining their styling.
2. Making some minor functional changes in ChannelProfile/TeamProfile
because they didn't use standard CSS classes previously. The styles
mostly match a secondary button, but they had slightly different
padding and colours previously.
3. I also removed a workaround for an old issue with OverlayTrigger and
disabled buttons in favour of just using the disabled attribute. For
more information on the previous code, see
https://github.com/mattermost/mattermost-webapp/pull/10387. Based on
some brief testing, that's no longer needed.
* Use Button in MultiSelect and remove unneeded backButtonClass prop
Everything that used that prop either passed the tertiary class that
was the default or passed a class that didn't exist.
* Use Button in more places that used btn-primary/secondary/tertiary/quaternary
* Use Button in more places that used btn-danger
* Use Button for all buttons with a className starting with 'btn btn-...'
* Migrate anchors that really should've been buttons to Buttons
All of these are anchors with click handlers and the btn class, so
they'd appear as buttons anyway.
* Migrate SettingItemMax and SettingPicture to Button
* Use Button in BrowseChannels
* Use Button in TourTip
* Migrate GenericModal to Button
There's a minor UX change due to the old `delete` class having a slightly
different colour from `btn-danger`, but I think that was from an older
version of the default themes.
Ideally, we'd remove the `GenericModal__button`, `confirm`, and `delete`
classes from the buttons on that modal, but doing that would require
changes to a large number of E2E tests that I'd rather not do now.
* Change order of building packages in postinstall
* Fix move_thread E2E tests
* Coderabbit feedback
* Address feedback
* Add JSDoc comments and remove width prop
I don't think we need this since this should be set by a parent with
`display: flex`, so I'm not going to add it to the Button.
* Share Button with plugins
* Add unread badge to Recaps sidebar link
Shows the count of unread finished recaps (completed or failed) on the
LHS Recaps link. Pending and processing recaps are excluded so the badge
only reflects work the user can actually read. When any unread recap has
failed, the badge is colored as an error to surface the failure.
The badge updates live through the existing recap_updated WebSocket
event, which refreshes the recap in the Redux store.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Fix Recaps failed-badge color losing to active sidebar rule
The failed-badge modifier selector had the same specificity (0,4,0) as
`.channel-view .sidebar--left .active .badge` in _badge.scss, so when
the Recaps link was the active route the global mention background
color won on cascade order. Scope the rule with `#SidebarContainer` so
it wins on specificity (1 id + 4 classes) regardless of active state.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Fix Recaps badge selector memoization
getUnreadFinishedRecapsBadge was keyed off getAllRecaps, which is not
memoized and returns a new array on every call. That broke reselect's
reference-equality input check, so the selector recomputed and returned
a fresh {count, hasFailed} object on every store dispatch — forcing
RecapsLink (always mounted when the feature flag is on) to re-render
on every action. Key the selector off state.entities.recaps directly
and iterate ids in the result function so memoization holds when the
recaps slice is unchanged.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Address PR feedback on Recaps sidebar badge
- Pass shallowEqual to the useSelector consuming
getUnreadFinishedRecapsBadge. The selector returns a plain
{count, hasFailed} object, so recap updates that change a recap
but leave the badge values the same (e.g. marking a read recap)
would otherwise force RecapsLink to re-render.
- Scope the "no badge" negative assertion to the render container so
it only asserts on the badge element, not any '1' or '.badge'
elsewhere in the DOM.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Address UX feedback on Recaps sidebar badge
- Add `unread` class to the sidebar item and `unread-title` to the
link when there are unread recaps so the label goes bold and the
icon goes full-opacity, matching how channels and the threads link
indicate unread state.
- Keep the badge (and the new failed icon) visible on hover so it
doesn't disappear under the cursor -- same override the threads
link uses.
- Replace the red failed-badge modifier with an amber alert icon
rendered in place of the count badge when any unread recap has
failed. Red mention badges are reserved for urgent priority
messages and caused confusion here.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Keep Recaps badge in place on hover
The global sidebar hover rule shrinks padding-right from 16px to 5px
to make room for the per-channel menu button, which shifted the badge
right since it stays visible. Restore padding-right: 16px on hover for
the Recaps link, matching what the threads link already does.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Align Recaps failed-icon aria-label with tooltip
The aria-label on the .RecapsFailedIcon span was a hardcoded English
string ("Recap failed") that differed from the tooltip shown to
sighted users ("One or more recaps failed"). Derive the aria-label
from the same intl message used by the tooltip so screen readers and
sighted users get the same wording and the label is localized.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Stop Recaps link from overriding global unread label styling
The combined `.active .SidebarLink, .SidebarLink.unread-title` rule
pushed font-weight: 400 onto .SidebarChannelLinkLabel with specificity
(0,4,0), overriding the global `.SidebarChannel.unread` rule that sets
font-weight: 600 and --sidebar-unread-text at (0,3,0). As a result the
Recaps label rendered at normal weight when unread, inconsistent with
channels and the threads link. Split the rules: keep the active-state
overrides as they were, and limit the unread-title rule to the
icon-specific styling Recaps actually needs, letting the global unread
styling apply to the label.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Add i18n entry for Recaps failed-tooltip
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* change size of alert icon
* fix the right icon
* Add ViewedAt to recaps and POST /recaps/mark_viewed endpoint
Introduce a new ViewedAt field on Recap, separate from ReadAt, that
tracks whether the user has at least seen a finished recap on the
recaps page. ReadAt keeps its existing per-recap "Mark read" semantics.
- New Postgres migration 000172 adds the ViewedAt column (default 0)
and an idx_recaps_user_id_viewed_at index mirroring the existing
ReadAt index.
- New store method MarkRecapsAsViewed(userId, statuses) does a single
UPDATE ... WHERE ViewedAt = 0 AND Status IN (...) RETURNING Id so
the app layer can fan out one WS event per affected recap.
- New App.MarkRecapsAsViewed(rctx) marks the user's not-yet-viewed
completed/failed recaps and broadcasts WebsocketEventRecapUpdated
per affected id.
- New POST /recaps/mark_viewed handler. Registered before the
{recap_id} regex routes so mark_viewed isn't captured as an id.
- RegenerateRecap now resets ViewedAt = 0 so a regenerated recap is
surfaced again in the badge once it completes. As a related fix,
UpdateRecap now persists ReadAt and ViewedAt -- previously it
silently dropped the ReadAt = 0 reset that RegenerateRecap was
setting in memory.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Mark recaps as viewed when the recaps page mounts
Wire the new server endpoint into the webapp:
- Recap type now includes viewed_at: number.
- Client4.markRecapsAsViewed posts to /recaps/mark_viewed.
- New markRecapsAsViewed redux action, fired alongside getRecaps and
getAgents in the recaps page mount effect. The server broadcasts
recap_updated per affected recap so other tabs/devices receive the
update through the existing handleRecapUpdated WS handler -- no new
client-side handler needed.
- getUnreadFinishedRecapsBadge now filters on viewed_at === 0 instead
of read_at === 0, so the sidebar badge clears on page open instead
of requiring per-recap "Mark read" clicks. Selector tests updated to
match.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Address review feedback on Recaps viewed_at change
- Defer markRecapsAsViewed until after getRecaps resolves on the
recaps page mount. Previously they ran in parallel, so getRecaps
could land last and overwrite the viewed_at: <now> timestamps the
WS-driven refresh had just written, briefly re-showing the badge.
- Switch the markRecapsAsViewed audit log to LevelContent and record
the affected ids as result state, matching the pattern of every
other mutating recap handler (markRecapAsRead, deleteRecap, etc).
recap_count meta is now recorded unconditionally.
- Add an app-layer test that asserts MarkRecapsAsViewed publishes a
recap_updated websocket event for each affected recap. The fan-out
is the entire reason this lives in the app layer, so a regression
removing the publish loop should fail loudly.
- Add a store-layer regression test that UpdateRecap actually
persists ReadAt = 0 / ViewedAt = 0 resets, guarding the regenerate
flow against a future change that drops those columns from the
update map.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Update migrations.list for 000172_add_recaps_viewed_at
Regenerated via `make migrations-extract` so the autogenerated
sequence list includes the new recaps ViewedAt migration files.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Use AddMeta for Recaps mark_viewed audit ids
AddEventResultState takes a model.Auditable, not a plain map[string]any,
so the previous attempt to record the affected ids did not compile.
Record them as audit metadata instead, matching the pattern used by
getRecaps which similarly returns a slice and uses AddMeta only.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Split Recaps ViewedAt index into a CONCURRENTLY migration
The lint check rejects bare CREATE/DROP INDEX in migrations because
they take an ACCESS EXCLUSIVE lock and block DML. Split the index off
into 000173 with CONCURRENTLY + the morph:nontransactional directive,
matching the pattern used by 000168/000169 (LinkedFieldID column +
its index). 000172 keeps just the ALTER TABLE ADD COLUMN, which can
stay transactional.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Add viewed_at to existing Recap test fixtures
The Recap type now requires viewed_at, so the fixtures in
recap_item.test.tsx, recap_processing.test.tsx, and recaps_list.test.tsx
need it too. CI was rejecting them with TS2741.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Mock markRecapsAsViewed in recaps.test.tsx
The mount effect now also dispatches markRecapsAsViewed, but the
manual jest.mock for 'mattermost-redux/actions/recaps' only exposed
getRecaps, so the runtime call resolved to undefined and crashed
with "markRecapsAsViewed is not a function". Add the missing entry
to the mock.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Add /recaps/mark_viewed and Recap.viewed_at to OpenAPI spec
The recap-spec validator rejected the new POST /api/v4/recaps/mark_viewed
handler because it had no documented operation. Add the path with its
MarkRecapsAsViewed operationId, response shape, and behavior, and add
the new viewed_at timestamp field to the Recap schema in definitions.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Fill in app.recap.mark_viewed.app_error translation
The new MarkRecapsAsViewed app method references this i18n key but the
en.json entry was added with an empty translation.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Skip markRecapsAsViewed when getRecaps fails
Marking recaps as viewed implies the user just looked at them. If
getRecaps fails the user is staring at an error/empty state, so we
shouldn't ack them on the server. Gate the dispatch on the thunk's
result.error -- the codebase's bindClientFunc swallows errors and
returns {error}, so the conventional try/catch pattern doesn't apply
here.
Update the recaps.test.tsx dispatch mock to return a resolved promise
so the new awaited result has the expected shape.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Clear and assert markRecapsAsViewed mock in recaps.test.tsx
Reset the new mock in beforeEach so it doesn't carry state across
tests, and assert that the mount effect dispatches markRecapsAsViewed
after getRecaps resolves. Awaiting via waitFor since the mark fires
inside an async fetchData chain.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* MM-68532: default EnableSearchPublicChannelsWithoutMembership to true for new installations
* fix test: disable backfill in watcher tests to avoid mock store panic
* fix test: mock System store so backfill returns early in watcher tests
* MM-68532: add SetDefaults unit test for EnableSearchPublicChannelsWithoutMembership
* MM-68647: Fix Data Spillage reviewer pill background in dark mode
The SelectableUserPropertyRenderer wraps a react-select component using a
UserMultiSelector classNamePrefix, so the global .react-select styles in
_react-select.scss did not apply. As a result the inner control kept its
default white react-select background, which clashed with dark themes
when viewing the Data Spillage reviewer field.
Make the control transparent and ensure the value/placeholder/input/menu
all use theme-driven colors so the reviewer pill blends correctly in
both light and dark mode.
Co-authored-by: Maria A Nunez <maria.nunez@mattermost.com>
* Fix stylelint: order color before gap in placeholder
Co-authored-by: Maria A Nunez <maria.nunez@mattermost.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
When two servers race through doSetupContentFlaggingProperties
simultaneously (e.g. HA deployments or parallel CI tests sharing a DB),
both read the same UpdateAt timestamps for existing property fields and
both call UpdatePropertyFields. The store's optimistic concurrency
control causes the second writer to get ErrConflict. Since both servers
are writing identical expected values, tolerate the conflict the same
way the create path already does.
Adds a regression test that fires 5 concurrent goroutines at the
migration after fields already exist, verifying all succeed.
GetChannelCounts was only reachable from App and had no callers.
Remove SqlChannelStore implementation, store interface, timer/retry
layers, tests, mock, model.ChannelCounts, and the orphaned i18n key.
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Julien Tant <JulienTant@users.noreply.github.com>
* MM-68494 Directly import WithTooltip and ShortcutKeys from shared package
* Fix import order
* Remove unneeded mocks for WithTooltip
* Remove mock from Input test
* Update newly added import paths and remove mocks from new tests
* add WithRPCErr hooks (server-facing/internal only)
* zero _returns on RPC failure in WithRPCErr companions
Aligns the WithRPCErr template with the HooksRPCErr godoc contract: when
g.client.Call returns a transport error, gob may have partially decoded the
reply. Reassign _returns to a zero value before destructuring so callers always
receive zeroed outputs alongside a non-nil transport error.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* rename HooksRPCErr to HooksWithRPCErr for naming consistency
Every related symbol uses the WithRPCErr suffix (MessageHasBeenPostedWithRPCErr,
RunMultiPluginHookWithRPCErr, RunMultiHookWithRPCErr, etc.). Aligning the
interface name removes the only outlier and makes the convention uniform.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* rename rpcErrImpl to hooksWithRPCErrImpl
Mirrors the existing hooksImpl/Hooks naming pattern on hooksTimerLayer.
* add supervisor.HooksWithRPCErr() and drop runtime type assertion
The old path did rp.supervisor.Hooks().(HooksWithRPCErr) and handled the
"doesn't implement" branch — but that branch was structurally unreachable
(the compile-time `_ HooksWithRPCErr = (*hooksTimerLayer)(nil)` assertion
guards it).
Change supervisor.hooks from `Hooks` to the concrete `*hooksTimerLayer`
(which implements both interfaces, enforced at field assignment), add a
parallel HooksWithRPCErr() accessor, and call it directly. Hooks() keeps
its public Hooks-interface signature via implicit conversion at return.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* drop "implemented by" clause from HooksWithRPCErr godoc
Both hooksRPCClient and hooksTimerLayer satisfy the interface, and naming
implementations in interface godocs adds rot — the contract is what readers
need, not the list of wrappers.
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* MM-68547: Tighten authorization on group syncable link and patch endpoints
Adds an additional permission check on the group syncable link and patch
endpoints. Callers must hold the role-management permission for the
target team or channel (or the sysconsole groups-management permission).
Made-with: Cursor
* Linting
* MM-68547: Extend group syncable scheme_admin authorization checks
Gate any explicit scheme_admin value (in either direction) on link and
patch. Populate SchemeAdmin in the singular getGroupSyncable so that
patches that do not touch scheme_admin no longer overwrite the persisted
value. Restrict PermittedSyncableAdmins to active syncables. Start the
link upsert from the existing active row to preserve fields the caller
did not, or could not, set.
Made-with: Cursor
* MM-68547: Add store-layer regression coverage for SchemeAdmin handling
Extend testGetGroupSyncable to round-trip SchemeAdmin: true through
UpdateGroupSyncable and re-fetch, locking in that getGroupSyncable
populates the field from the persisted row.
Strengthen groupTestPermittedSyncableAdmins{Team,Channel} to assert
that DeleteGroupSyncable preserves SchemeAdmin in the persisted row
and that PermittedSyncableAdmins still excludes the row, making the
coupling between the two store changes explicit.
Made-with: Cursor
* MM-68547: Fix group details role-change dedup on remove
The roleChangeKey helper was reading team_id/channel_id from the items
in itemsToRemove, but onRemoveTeamOrChannel pushes those items with a
generic id field. The deletion of the staged role change in
handleRemovedTeamsAndChannels therefore never matched the key produced
by onChangeRoles, and a stale patchGroupSyncable was dispatched after
the unlink.
Accept either id or team_id/channel_id when computing the key. Also
extend the e2e assertion to verify the channel removal took effect
(delete_at != 0) alongside the existing scheme_admin check.
Made-with: Cursor
* MM-68547: Mirror delete_at assertion on the removed-team e2e test
The team variant of "does not update the role of a removed X" was left
asserting only on scheme_admin. Add the matching delete_at != 0 check
already present in the channel variant so both tests verify the same
user-visible contract.
Made-with: Cursor
* Skip SyncSyncableRoles if no scheme_admin
* Implemented edit file permission
* lint fixes
* Updated snapshot
* Updated tests
* Updated test
* CI
* Permission reordering and tooltip text update
* Made a geneeric function
* MM-68536: Show actual remote names in system console channel list
The system console "Channels" list rendered SharedChannelIndicator
without a remoteNames prop, so every shared channel showed the generic
"Shared with trusted organizations" fallback even after PR 35908.
Add a small connected wrapper that selects remote names via
getRemoteNamesForChannel and dispatches fetchChannelRemotes on mount,
mirroring the pattern used by the LHS sidebar. The shared_channel_remote_updated
websocket event added in PR 35908 already refreshes the same Redux slice,
so the system console list now stays in sync automatically.
Bump the default prepackaged Agents plugin from 2.0.2 to 2.0.3 (non-FIPS).
FIPS prepackaged plugin package list is unchanged.
Co-authored-by: Cursor <cursoragent@cursor.com>
* MM-68622: start inter-cluster services before plugin activation
Move startInterClusterServices from the end of Server.Start() to the
beginning, before Channels().Start() initializes plugins. This lets
plugins call shared channels APIs (ShareChannel, InviteRemoteToChannel,
UninviteRemoteFromChannel, UnshareChannel, UpdateSharedChannel,
CheckCanInviteToSharedChannel) during OnActivate instead of failing with
"Shared Channels Service is disabled".
Side-effect analysis:
* Plugin API gating: getSharedChannelsService in
channels/app/shared_channel.go:32 only requires the service to be
non-nil. The plugin-facing wrappers all pass ensureIsActive=false, so
Active() is bypassed. Once SetSharedChannelService runs, calls succeed
on both leader and follower nodes. This is the fix path.
* Multi-node leader timing: the enterprise cluster impl in
enterprise/cluster/cluster.go:70 initializes currentLeader="", so
IsLeader() returns false before StartInterNodeCommunication runs. The
immediate onClusterLeaderChange in scs.Start at
platform/services/sharedchannel/service.go:151 therefore takes the
pause path, which is a no-op since the service was never active. When
memberlist.Create fires NotifyJoin for the local node,
addPotentialLeader runs and InvokeClusterLeaderChangedListeners drives
the registered listener to resume() the sync loop on the elected
leader. End state matches the prior ordering.
* Single-node: IsLeader() returns true unconditionally per
channels/app/platform/cluster.go:33, so SharedChannelSyncHandler is
active during plugin OnActivate. Events emitted by plugins during
activation (posts to shared channels, DM creation) now flow through
sync where they were previously dropped. This is intended correctness,
not a regression.
* Transport and handlers: api4 remote-cluster routes are registered
before Server.Start, so HTTP handlers exist when rcs.Start runs early.
rcs and scs do not send cluster-broadcast messages during Start; they
only register topic listeners on the rcs transport, which is
independent of cluster gossip. registerClusterHandlers ordering is
unaffected.
* Config: scs reads only ConnectedWorkspacesSettings and the License at
construction, both stable from the initial config load. ReloadConfig
at server.go:912 has no bearing on inter-cluster service init.
Errors from startInterClusterServices remain logged and non-fatal,
matching prior behavior.
Restore the `fullyparallel: false` override for the unsharded
`Postgres with binary parameters` and `Postgres FIPS` jobs in the
weekly workflow. The override was originally added to the binary
parameters job in #35995 to prevent resource exhaustion on a single
runner, but was dropped when both jobs moved into
server-ci-weekly.yml in #36036, leaving them on the template default
of `true`.
Without it, the hosted runner is overwhelmed (too many server
instances, WebSocket hubs, and DB connections) and the runner agent
itself loses communication with GitHub mid-run, surfacing as
"hosted runner lost communication with the server" at ~55-60 min
into the Run Tests step. Both runs on April 27 and May 4 failed
this way; the sharded FIPS variant retained for FIPS-touching PRs
in server-ci.yml is unaffected because each shard handles only a
fraction of the packages.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
#### Summary
Moving Hungarian language from Beta to Alpha as Hungarian has fallen below the 79% quality threshold for over three months.
#### Release Note
```release-note
Downgrading Hungarian translations from Beta to Alpha.
```
* Report POC
* Including more error logs
* Added localisationj for each reviewer
* Optimisations
* Minor tweaks
* restored go module files
* lint fixes
* Added back transslations
* Added translations
* linter and test fixes
* restored go module files
* e2e lint fix
* lint fixes
* AI fixes
* fixed typo
* fixed nil pointer error
* Added more tests
* Publish report even if deletion fails
* Fixed the e2e test
* Distinguished between no data and deleted data
* lint fixes
* fixed tests
* e2e test fix
* Updated test to also upload actual file
* Removed file name tracking
* Text updates
* fixed e2e test
* lint fix
* [MM-67867] Update Playbooks plugin to v2.8.1
Updates the prepackaged Playbooks plugin to v2.8.1 (regular and FIPS builds).
Prepackage FIPS version for Playbooks.
* Removing FIPS version
* Move min_date, max_date, time_interval into DialogElement.datetime_config
Consolidate date/datetime configuration into the datetime_config sub-object
on both DialogElement (Go/TS) and AppField (TS), deprecating the top-level
fields while keeping them for backward compatibility. DateTimeConfig values
take precedence over legacy fields via EffectiveDateTimeConfig() (Go) and
nullish coalescing fallback chains (TS).
Also fixes: timezone indicator now uses FormattedMessage for i18n, CSS class
with theme variable instead of inline styles, and proper DateTimeConfig type
instead of Record<string, unknown> cast.
* MM-68382 - align team creation invite permissions
Keep invite-related team settings consistent during team creation so authorization matches existing update and patch behavior.
Made-with: Cursor
* MM-68382 - move team create helper closer to usage
Keep the create-team authorization helper next to createTeam so the file reads in usage order.
Made-with: Cursor
* commit before ff
* MM-68382 - reject invite fields on create without permission
Reject createTeam with 403 (matching updateTeam/patchTeam) when the creator
tries to set AllowOpenInvite or AllowedDomains without PermissionInviteUser,
instead of silently stripping those fields. Add scheme-branch coverage and
log scheme-fetch failures from the permission check.
Made-with: Cursor
* api4: add symmetric happy path test for scheme InviteUser without invite fields
Cover team creation when the scheme grants InviteUser but AllowOpenInvite and
AllowedDomains are unset, asserting InviteId is returned in the response.
Made-with: Cursor
* [MM-68393] Tighten protected role patch authorization
Harden role patch authorization for protected system roles and cover the restricted paths with focused API tests.
Made-with: Cursor
* [MM-68393] Fix role patch test shadowing
Rename shadowing response variables in the protected role patch tests so govet passes in core and enterprise check-style jobs.
Made-with: Cursor
* [MM-68393] Block privileged role permissions
Made-with: Cursor
* MM-64977: Fix channel switcher row overlap with long names
In the Find Channels modal, very long channel names overflowed
their row and visually overlapped the team name shown on the right
because the team label was absolutely positioned and the channel
column did not reserve horizontal space.
Restructure the SwitchChannelSuggestion row to use a real flex
layout: a primary column wrapper holds the channel name and inline
metadata with `flex: 1 1 auto; min-width: 0;` so the name truncates
with an ellipsis, and the team-name span becomes a flex sibling
with `flex: 0 0 auto; max-width: 40%;` so it remains visible. The
channel name is wrapped in WithTooltip whose disabled prop is
driven by a useLayoutEffect-based scrollWidth > clientWidth check,
so the full name is shown on hover only when truncation occurs.
Made-with: Cursor
* MM-64977: Show tooltip on truncated team name as well
Mirror the channel-name tooltip behavior on the team-name span in
the channel switcher row: track its truncation state via the same
useLayoutEffect + ref pattern, and wrap the team name in WithTooltip
whose disabled prop is driven by scrollWidth > clientWidth. Hovering
the team label now reveals the full team display name when (and only
when) it is actually truncated.
Extend existing tooltip tests to assert the team-name tooltip
disabled flag mirrors the truncation state in both branches; loosen
the layout test to permit the WithTooltip wrapper around the team
span while still asserting the team name does not live inside the
primary column.
Made-with: Cursor