Commit graph

11 commits

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

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

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

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

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

Still in draft, needs documentation and e2e support.

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

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

* Fixed a snapshot test and a missing i18n member

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

* fix(server): fix lint issue with gofmt

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

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

* fix from upstream changes

* fix: eslint errors in teams actions

* document new API endpoints

* fix i18n

* fix err id

* remove unused localhost methods

* use ShortcutKey and ShortcutSequence

* feature_enhancements, mark as read toast enchancements

* read all modal mount point, use openModal

* use handler

* fix style

* fix: fix refactoring typo

* Merge fix: realign branch with upstream changes

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

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

* Clean up TestReadAllInTeam

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

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

* Use SelectBuilder for team channels query

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

* Mark all team-channel threads on team read

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

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

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

* Mark mark-read audit records as success

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

* Mark all DM/GM threads on full read

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

* Polish DM/GM channels-with-unreads query

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

* Fix stale ReadAllMessages godoc

* Type last_viewed_at_times as int64 map in OpenAPI

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

* Gate MarkAllAsReadToast mount on feature flag

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

* Return data from markAllInTeamAsRead thunk

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

* Coerce undefined suffix in createStoredKey

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

* Refactor mark-read websocket events

* Polish DM/GM channels-with-unreads query

* Fix import order in shortcut_key consumers

* Fix CI

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
Co-authored-by: Jesse Hallam <jesse@mattermost.com>
Co-authored-by: Caleb Roseland <caleb@calebroseland.com>
Co-authored-by: Alejandro García Montoro <alejandro.garciamontoro@gmail.com>
2026-05-13 16:38:30 +00:00
Harrison Healey
10ad2505a7
Split out buttonClassNames utility and use for most places Button isn't (#36328)
* 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
2026-05-06 17:35:10 -04:00
Harrison Healey
34ef034dd9
MM-68261 Add Button component to shared package (#36191)
* 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
2026-05-06 09:38:16 -04:00
unified-ci-app[bot]
d5946e9477
Update latest minor version to 11.8.0 (#36437)
Automatic Merge
2026-05-06 08:23:38 +02:00
Harrison Healey
f8bf924ebf
MM-67319/MM-67320 Move ShortcutKey and WithTooltip into shared package (#36037)
* MM-67319 Move ShortcutKey component into Shared Package

* MM-67322 Add i18n-extract support for shared package and move key constants

* MM-67320 Move WithTooltip into shared package without modification

* Add CSS variables for standard z-indices

* Update TooltipShortcut to point to shared ShortcutKey

* Update TooltipContent to use shared Emoji

* Move isMessageDescriptor into shared package

* Add Floating UI as explicit dependency of shared package

* Fix WithTooltip imports

* Fix imports for ShortcutX types

* Move/copy tooltip constants into shared package

* Fix WithTooltip tests

* Remove unneeded TODO comments

* Actually share new modules with plugins

* Stop publishing src folder for shared package
2026-04-27 20:26:58 +00:00
Harrison Healey
5e42f6f80c
Fix web app run script crashing (#36271) 2026-04-27 11:10:54 -04:00
Harrison Healey
f6341a17ba
MM-68247 Move user agent utilities into shared package and clean it up (#36033)
* Start moving user agent utils into shared package

* Remove inobounce and stop exporting isIosSafari

Based on some quick testing on my phone, inobounce is no longer needed. Both
local and Community:
1. Let you overscroll on the landing and login pages
2. Don't overscroll in a channel, a thread, or the LHS while fully zoomed out
3. Do let you overscroll when zoomed in

That also lets me reduce the size of the interface for utils/user_agent.

* Remove unneeded exports and unused functions

* Remove outdated workarounds from FileUpload component

These were only needed to support a 10 year old version of iOS Chrome and the classic app.

* Remove useOrientationHandler

This was added in https://github.com/mattermost/mattermost-webapp/pull/2504,
but I don't think the extra complexity is worth keeping it around
when we mostly support mobile view for desktop accessibility reasons.

* Replace isIosWeb/isAndroidWeb with isIos/isAndroid

These were previously needed to differentiate between the mobile web app
and the classic app.

* Replace isMobileApp with isMobile

Similar to the last commit, we used to need to differentiate
between the mobile web and the classic app. For most places,
I just replaced isMobileApp with isMobile, but I removed the
check in ProductMenuList because we want to show that link
on mobile web.

* Move isInternetExplorer and isEdge out of the shared package

Those should be removed, so I don't want to include them in
the shared package at all. I also renamed isChromiumEdge to
just isEdge since that should be its name once the old ones
are removed.

* Change how functions are re-exported to fix tests

* Update web app code to use shared user agent utils directly

* Removed useless mock

* Fix how tests mock utils/user_agent now that it's fully moved

* Actually export user_agent utils from shared package
2026-04-16 21:34:31 +00:00
unified-ci-app[bot]
6662021dd5
Update latest minor version to 11.7.0 (#35964)
Co-authored-by: unified-ci-app[bot] <121569378+unified-ci-app[bot]@users.noreply.github.com>
2026-04-07 09:34:34 +03:00
Harrison Healey
6397fd5971
Update web app package versions to 11.6.0 (#35536) 2026-03-10 10:26:28 -04:00
Harrison Healey
2da1e56e6c
MM-67323 Add system for plugins to use shared package and allow plugins to load asynchronously (#35183)
* Remove jest-junit and unignore build folder in web app packages

We don't actually use the file output by jest-junit, and I don't think we
have since we moved off of Jenkins for CI

* Move parcel-namer-shared into build folder

* MM-67323 Add loadSharedDependency API and script for plugins to use it

* Fix client and mattermost-redux packages missing const enums

* Change interface for webAppExternals
2026-02-17 12:57:49 -05:00
Harrison Healey
1e98250566
MM-66867/MM-67318 Add initial version of shared package (#35065)
* Change moduleResolution to bundler

This makes TS follow the module resolution of newer versions of Node.js which
makes it use the `imports` and `exports` fields of the package.json while not
requiring file extensions in some cases which it does when set to node16 or
nodenext.

I'm changing this to make it so that VS Code can correctly import things from
our types package without adding `/src/` to the import path erroneously.
Hopefully it doesn't introduce any other issues.

* Change make clean to use package.json script

* Remove missing fields from SystemEmoji type

These were removed from emoji.json in
https://github.com/mattermost/mattermost-webapp/pull/9597, but we forgot to
remove the fields from the type definition. They weren't used anyway.

* MM-66867 Add initial version of shared package

This initial version includes the shared context, React Intl support (although
that's currently untested), linting, and testing support. It builds with
Parcel.

* Move isSystemEmoji into Types package

* MM-67318 Add Emoji component to shared package

To limit the number of changes to the web app, it still uses RenderEmoji which
wraps the new component for the time being. I'll likely replace RenderEmoji
with using it directly in a future PR, but I may leave it as-is if the changes
are too big because the API is different.

* Add postinstall script to build shared package

* Revert changes to moduleResolution and add typesVersions to shared package

I plan to still change moduleResolution to bundler since it's the new default
for TS projects, and since it lets TS use the exports field in package.json,
but it requires other changes to fix some minor issues in this repo which I
don't want to muddy this PR with.

Adding typesVersions lets TS resolve the components in the shared package like
it does with the types package while using the old value for moduleResolution.
Plugins still use the old value for moduleResolution, so this will let them use
the shared package with fewer updates changes as well.

* Fix Webpack not always watching other packages for changes

* Add shared package dependencies and build output to CI cache

* Update @parcel/watcher to fix segfaults

This package seems to be older than the rest of the newly added Parcel
dependencies because it's used by sass.

* Fix build script not doing that

* Go back to manually specifying postinstall order

I just learned that postinstall scripts run in parallel because I was running
into an issue where the client and types packages were building at the same
time, causing one of them to fail. They still run in parallel, so that may
still occasionally happen, but by specifying the order manually, we hopefully
avoid that happening like we seemed to do before.

* Further revert changes to postinstall script

The subpackages were also being built when installed
by a plugin

* Increment cache keys

* Fix typo

* Change the cache busting to look at shared/package.json

* Attempt to debug tests and caching

* Debugging...

* Add shared package to platform code coverage

* Remove caching of package builds and manually run postinstall during web app CI setup

* Debugging...

* Remove CI debugging logic

* Update package-lock.json

* Change Emoji component back to taking an emojiName prop

* Add .parcel-cache to .gitignore
2026-02-13 14:53:10 -05:00