* 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>
* 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
* 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
* 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
* 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
* 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
* 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