From e190c0f1e490e87ef00bbb9d0efde5dfe7d68cb7 Mon Sep 17 00:00:00 2001 From: Matthew Birtch Date: Tue, 27 Oct 2026 10:39:56 -0400 Subject: [PATCH] Migrate product Buttons from shared to compass-ui (#38903) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Migrate modal and save-panel Buttons from shared to compass-ui Continue the leaf-first Button migration by moving GenericModal, standalone modal leaves, SaveChangesPanel/SaveButton, SpinnerButton, and the component library demo onto @mattermost/compass-ui Button. Replace confirmButtonVariant with a destructive boolean on ConfirmModal and GenericModal, and update agent/style docs to prefer compass-ui for new and migrated call sites. Co-authored-by: Matthew Birtch * Fix modal footer button spacing after compass-ui migration Replace Bootstrap .btn+.btn margin with flex gap on .modal-footer so compass-ui Buttons keep the 8px horizontal spacing. Drop the redundant ChannelNotificationModal nested footer so buttons are direct flex children. Co-authored-by: Matthew Birtch * Neutralize Bootstrap clearfix on flex modal footers Bootstrap 3 ::before/::after clearfix pseudos were participating in .modal-footer flex layout and adding extra 8px gap spacing. Hide them so only real footer buttons receive the gap. Co-authored-by: Matthew Birtch * Fix multi-select Go button spacing after compass-ui migration Use flex gap on .multi-select__container instead of Bootstrap .btn margin-left so the search field and Go button keep an 8px gap when SaveButton uses compass-ui Button without the .btn class. Co-authored-by: Matthew Birtch * Migrate InvitationModal footer Buttons to compass-ui InvitationModal views were skipped in the Phase 2 modal migration because their filenames do not contain "modal". Move Copy invite link, Invite, Invite More, and Done buttons onto compass-ui Button, and drop the redundant InviteView footer .btn font-weight override (compass Button already uses semibold). Co-authored-by: Matthew Birtch * Restore 8px gap between Cancel/Save in floating SaveChangesPanel Compass-ui Buttons no longer get Bootstrap .btn + .btn margins; add gap: 8px on the flex button container instead. Co-authored-by: Matthew Birtch * Migrate Browse Channels Create New Channel Button to compass-ui Replace the shared Button in the Browse Channels modal header (and shared empty-state helper) with @mattermost/compass-ui Button. Header CTA uses small size and tertiary emphasis; empty-state keeps primary/medium. Co-authored-by: Matthew Birtch * Change modal header secondary Buttons to tertiary Update User Groups Create Group and View User Group header CTAs (Add people / Restore Group) from emphasis secondary to tertiary. Co-authored-by: Matthew Birtch * Fix admin save bar Cancel to compass-ui tertiary Button Cancel with cancelLink was still a BlockableLink using shared buttonClassNames (quaternary), so it did not match Save and misaligned. Use compass-ui Button emphasis=tertiary for both cancel paths, preserve unsaved-changes deferral via deferNavigation + getHistory, and align controls with flex gap on .admin-console-save. Co-authored-by: Matthew Birtch * Migrate backstage-form footer Buttons to compass-ui Replace Cancel/Done Links styled with buttonClassNames (.btn) with @mattermost/compass-ui Button in integrations and emoji backstage form footers. Add flex gap: 8px on .backstage-form__footer so Cancel and SpinnerButton keep 8px spacing without Bootstrap .btn+.btn margins. Co-authored-by: Matthew Birtch * Remove redundant admin save-bar button style overrides Save and Cancel in .admin-console-save are compass-ui Buttons, so the legacy .save-button / .cancel-button height, color, and hover overrides no longer apply. Keep flex/gap bar chrome and error-message styles; drop the dead IP Filtering .btn.btn-primary:disabled override as well. Co-authored-by: Matthew Birtch * Fix component library Button demo to use compass-ui icon slots Pass selected glyphs via leadingIcon/trailingIcon with compass-ui Icon instead of rendering font icons as Button children. Co-authored-by: Matthew Birtch * Fix all admin save-bar Cancel buttons to compass-ui tertiary Prior SaveChangesPanel-only fix left many .admin-console-save footers using BlockableLink + shared buttonClassNames (btn-tertiary/quaternary on ). Rewrite unused BlockableButton as a compass-ui Button with navigation blocking, use it for cancelLink and every remaining save-bar Cancel, and migrate system_user_detail Cancel/Buttons to compass-ui. Co-authored-by: Matthew Birtch * Restore 8px gap between AdminUserCard footer buttons Compass-ui Buttons no longer get Bootstrap .btn + .btn margins; add gap: 8px on the AdminUserCard__footer flex container instead. Co-authored-by: Matthew Birtch * Migrate remaining admin_console Buttons to compass-ui Move in-page admin console Button call sites from @mattermost/shared onto @mattermost/compass-ui, remapping sizes (xs/sm/md/lg → x-small/small/medium/large) and destructive/inverted variants. Convert clear buttonClassNames CTAs that are real buttons, and retarget SCSS that depended on Bootstrap .btn / .btn+.btn spacing to flex gap and custom class selectors. Leave link-styled navigation, menu triggers, and ToggleModalButton buttonClassNames for a later wave. Co-authored-by: Matthew Birtch * Fix admin_console Button migration follow-ups Repair a corrupted logs.tsx import left by the bulk rewrite, update graph_values tests for compass-ui emphasis class names, and refresh admin_console snapshots after the Button migration. Co-authored-by: Matthew Birtch * Migrate Section C Button icon children to leadingIcon slots Wire compass-ui Button iconography through leadingIcon + Icon glyph instead of nested font-icon children, and migrate remaining Section C admin call sites from shared Button with size/destructive updates. Co-authored-by: Matthew Birtch * Update Section C snapshots and drop obsolete button icon SCSS Refresh Jest snapshots for leadingIcon wiring and remove unused .btn-primary .icon overrides that no longer apply to compass-ui Button. Co-authored-by: Matthew Birtch * Migrate ToggleModalButton CTAs from buttonClassNames to compass-ui Add optional emphasis/size props so button-looking ToggleModalButton shells render compass-ui Button, and update admin + channel intro CTAs. Co-authored-by: Matthew Birtch * Migrate StartTrialBtn and AD/LDAP banner CTAs to compass-ui Button Replace buttonClassNames / anchor shells with compass-ui Button, and use inverted link emphasis for the AD/LDAP upsell banner on colored chrome. Co-authored-by: Matthew Birtch * Migrate Bootstrap .btn modal and toast CTAs to compass-ui Button Convert leave-channel, mark-all-as-read, feature toast, and revoke non-compliant tokens action buttons; keep footer gap at 8px. Co-authored-by: Matthew Birtch * Update snapshots for compass-ui buttonClassNames CTA migrations Co-authored-by: Matthew Birtch * Fix ESLint import/order, unused JSX, and indent in compass-ui button migration Reorder @mattermost/compass-ui imports before @mattermost/components, fix import group blank lines, remove unused JSX type import, and correct jsx-indent-props on channel access rules confirm modal. Co-authored-by: Matthew Birtch * Fix Admin Console Logs banner button spacing Add flex gap between Reload Logs and Download Logs after the compass-ui Button migration removed Bootstrap .btn+.btn margins. Co-authored-by: Matthew Birtch * Migrate Edition and License Contact Sales CTA to compass-ui Button Co-authored-by: Cursor * Fix New attribute button icon alignment via leadingIcon Use compass-ui Icon + leadingIcon instead of nesting PlusIcon in Button children so the header CTA matches the Section C icon-slot pattern and aligns correctly with the label. Co-authored-by: Matthew Birtch * Fix stylelint order/properties-order in multi-select and backstage SCSS Reorder padding before gap and overflow before justify-content to satisfy stylelint-config-idiomatic-order in the compass-ui button migration styles. Co-authored-by: Matthew Birtch * Update denim theme linkColor to #1c58d9 Align denim linkColor with the Compass primary button blue and refresh the custom theme chooser snapshot. Co-authored-by: Matthew Birtch * Fix check-types and button test assertions for compass-ui migration - Use undefined instead of null for onNavigationConfirmed mock state - Wrap Filters Button so Floating UI can set a reference without relying on unsupported Button ref typing - Update new_channel_modal and permission scheme tests to query compass-ui button markup Co-authored-by: Matthew Birtch * Fix Playwright selectors after compass-ui Button migration Replace Bootstrap btn/btn-tertiary/btn-primary class selectors with role+name and GenericModal classes, and update Cancel from link to button where SaveChangesPanel/BlockableButton now renders a button. Co-authored-by: Matthew Birtch * Fix TypeScript errors and e2e selectors for compass-ui Button Replace null onNavigationConfirmed mocks with undefined, wrap the system users Filters Button for Floating UI refs, and update Playwright Cancel selectors to target role=button instead of Bootstrap link/btn classes. Co-authored-by: Matthew Birtch * Fix Cypress selectors broken by compass-ui Button migration Update enterprise e2e specs that still targeted Bootstrap btn-* classes or disabled classes on compass-ui label spans. Prefer GenericModal__button, role+name, and the button disabled attribute instead. Co-authored-by: Matthew Birtch * Update Jest snapshots for compass-ui Button markup Refresh failing channels snapshots that still expected Bootstrap btn* classes, and close the graph-attribute menu before asserting Create channel so getByRole is not blocked by floating focus aria-hiding. Co-authored-by: Matthew Birtch * Fix webapp package-lock for dual compass-ui versions Regenerate package-lock.json so root keeps @mattermost/compass-ui 0.1.0-alpha.10 as a peer while channels nests 0.1.0-alpha.13, matching what npm from .nvmrc produces after the master merge. Co-authored-by: Matthew Birtch * Use default medium size for SaveChangesPanel buttons Drop the explicit small size on Reset/Save so compass-ui Button uses its medium default in channel settings and other modal panels. Co-authored-by: Matthew Birtch * Adjust SaveChangesPanel message spacing Co-authored-by: Cursor * Use Compass button loading spinner and migrate settings Cancel buttons Co-authored-by: Cursor * Fix nested button-in-link markup, migrate emoji buttons, drop clipping overflow Co-authored-by: Cursor * Fix import order lint, keep a11y--focused class, hide ring on Compass buttons Co-authored-by: Cursor * Fix stylelint property order in SaveChangesPanel SCSS Reorder padding/margin/color/gap so check-lint order/properties-order passes after the SaveChangesPanel message spacing tweak. Co-authored-by: Matthew Birtch * Update Jest snapshots for compass-ui Button markup Regenerate channels component snapshots after migrating shared Button to @mattermost/compass-ui so CI shards pass again. Co-authored-by: Matthew Birtch * Retrigger CI after flaky demo_dialog_date Playwright failure Snapshot-only commit 3a255e0 left product code unchanged from the prior green Playwright run; demo plugin date dialog submit returned a transient Action integration error. Co-authored-by: Matthew Birtch * Move Compass button a11y focus override to double-borders PR Suppressing the webapp a11y--focused ring on Compass Buttons belongs with the other Compass double-border fixes, not this Button migration. Co-authored-by: Matthew Birtch * Align @mattermost/compass-ui to 0.1.0-alpha.14 Bump root, channels, and components peer pins from the split alpha.10/alpha.13 setup to a single alpha.14 and refresh the lockfile. Co-authored-by: Matthew Birtch * Target MultiSelect Go button via explicit multi-select__go class Replace the generic > button height rule with a stable extraClasses hook on SaveButton so Compass Button styling stays explicit. Co-authored-by: Matthew Birtch * Update MultiSelect consumer snapshots for multi-select__go class Adding the explicit multi-select__go class to the MultiSelect Go SaveButton required regenerating snapshots in downstream modals. Co-authored-by: Matthew Birtch * Bump @mattermost/compass-ui to 0.1.0-alpha.15 Pick up Button asChild support so navigational CTAs can stay real links while using Compass Button styles. Co-authored-by: Matthew Birtch * Restore navigational Buttons as real links via asChild Use Compass Button asChild around Link for integrations Cancel/Done, backstage Add, emoji Add/Cancel, and marketplace Configure so middle-click and open-in-new-tab work again. Co-authored-by: Matthew Birtch * Restore admin Cancel as BlockableLink via Button asChild Replace BlockableButton with Compass Button asChild wrapping BlockableLink so unsaved-changes blocking and real link navigation both work. Delete the temporary blockable_button helper. Co-authored-by: Matthew Birtch * Migrate remaining shared Button usages to compass-ui Button Replace @mattermost/shared Button consumers with @mattermost/compass-ui/components/button, mapping size/variant props. Remove the shared Button component and keep buttonClassNames for menu triggers. Update webapp agent and style guidance accordingly. Co-authored-by: Matthew Birtch * Migrate file upload and integration message buttons to Compass Button Replace add_bot/setting_picture btn-file overlays with Compass Button plus hidden file input, and migrate block_renderer/action_button to Compass Button (size small, primary/tertiary/destructive, loading). Co-authored-by: Matthew Birtch * Migrate remaining plain btn text buttons to Compass UI Button Convert GenericModal footers, download/report CTAs, link-style actions, and styled.button.attrs wrappers to @mattermost/compass-ui Button with mapped emphasis/size/destructive props. Keep local classNames such as GenericModal__button. Skip icon-only and Toggle cases. Co-authored-by: Matthew Birtch * Update snapshots and loading assertions for Compass Button migration Co-authored-by: Matthew Birtch * Update snapshots after Compass Button plain-btn migration Refresh get_link_modal, openid_convert, and user_settings_notifications snapshots for compass-ui Button markup. Co-authored-by: Matthew Birtch * Wrap remaining link CTAs with Compass Button asChild Convert Link/ExternalLink/BlockableLink sites that still used buttonClassNames into Compass Button asChild wrappers so they keep real navigation while using compass-ui button styling. Co-authored-by: Matthew Birtch * Fix focus selectors and SCSS after Compass Button migration Update SettingItemMax to find focusable controls without Bootstrap .btn classes, mark _buttons.scss as plugin-compat deprecated, and retarget component SCSS that still assumed .btn / .btn-tertiary. Co-authored-by: Matthew Birtch * Fix broken BlockableLink JSX in admin Cancel buttons Restore missing BlockableLink closing tags and remove stray Cancel string literals left by an earlier rewrite. Co-authored-by: Matthew Birtch * Use medium Compass Button size for mm_blocks with 8px 16px padding Co-authored-by: Matthew Birtch * Fix styled(Button) interop for Compass UI Button Webpack may resolve @mattermost/compass-ui/components/button to Button.js (default-only) instead of index.js (named Button). Add a small namespace-import helper with default fallback and use it at styled(Button) call sites to avoid styled-components error #1. Co-authored-by: Matthew Birtch * Fix attachment action WithTooltip crash from Compass Button import interop Stop wrapping Compass Button with styled-components in ActionButton (use style/loading props instead), route ButtonElement through the Button interop helper, and alias the compass-ui button entry to the named-export index so WithTooltip no longer receives an undefined child type. Co-authored-by: Matthew Birtch * Harden Compass Button interop helper typing Prefer typeof NamedButton for the exported Button and ensure classification_markings_styled ends with a newline for lint. Co-authored-by: Matthew Birtch * Restore shared Button component for plugin loadSharedDependency consumers. Co-authored-by: Cursor * Stop styling Compass Button and re-export shared Button for plugins. Replace styled(CompassButton) with prop/style wrappers, drop the interop helper and webpack alias, and restore the shared Button export so Playbooks loadSharedDependency keeps working. Co-authored-by: Cursor * Set --button-fg so mm-blocks and attachment button text colors work with Compass Button. Co-authored-by: Cursor * Fix ESLint import order and JSX indentation after Compass Button migration. Co-authored-by: Cursor * Migrate marketplace Install/Try Again buttons to Compass UI Button with loading. Co-authored-by: Cursor * Restore MultiSelect Avatar size sm so selected-user chips are not oversized. Co-authored-by: Cursor * Migrate remaining admin console CTAs to Compass Button and fix always-expanded card height. Co-authored-by: Cursor * Fix prefer-arrow-callback on Compass Button menu triggers. Co-authored-by: Cursor * Fix check-types and TourTip test fallout from Compass Button migration. Co-authored-by: Cursor * Fix unused _className lint on Compass Button menu triggers. Co-authored-by: Cursor * Fix Web App CI snapshot and assertion drift for compass-ui Button. Refresh Jest snapshots for alpha.15 CSS-module hashes, assert emoji Add CTA as a link, and locate new-channel URL Edit via closest button. Co-authored-by: Matthew Birtch * Fix remaining channels shard-1 Compass Button test fallout. Assert SaveChangesPanel Cancel as a link, drop Bootstrap btn class checks on AdminPanelWithButton, query archive via accessible name, and refresh leftover Button snapshots. Co-authored-by: Matthew Birtch * Update send_test_notification_notice snapshot for Compass Button. Co-authored-by: Matthew Birtch * Fix E2E selectors for Compass Button asChild links and classes. Revert Cancel/Configure queries to role=link where Button asChild renders anchors, and replace Bootstrap btn-* lookups with role or container-scoped button selectors. Co-authored-by: Matthew Birtch * Use profile-popover container button selector in CRT E2E. Co-authored-by: Matthew Birtch * Fix Compass Button migration review regressions (#39210) * Fix Compass Button migration regressions from review findings. Restore link emphasis, Floating UI refs on Button, Team Edition link scoping, setting autofocus/Enter-submit guards, OpenID convert styling, action-button hover tints, GenericModal confirmButtonVariant alias, and remove-policy icon chrome. Co-authored-by: Matthew Birtch * Add 8px Compass spacing gap between SectionNotice actions. Use var(--spacing-s, 8px) on .sectionNoticeActions so button/action rows have consistent spacing after the Compass Button migration. Co-authored-by: Matthew Birtch * Fix remove-license control to use destructive link emphasis. Default primary+destructive painted white --button-fg while SCSS cleared the red fill. Use emphasis='link' so Compass sets error-text label color, and keep only layout margin in SCSS. Co-authored-by: Matthew Birtch * Revert remove-policy icon Compass Button tweaks. Leave channel membership policy remove/edit icon controls alone; those will move to icon buttons separately. Co-authored-by: Matthew Birtch * Use a plain button for channel policy remove icon. Keep this control out of Compass Button; it will become an icon button later, matching the team membership policy remove control. Co-authored-by: Matthew Birtch * Fix wrap-regex lint in SettingItemMax emphasis checks. Co-authored-by: Matthew Birtch --------- Co-authored-by: Cursor Agent * Restore peer marker on compass-ui in package-lock.json. Merge conflict resolution dropped "peer": true; regenerating the lockfile with npm puts it back and satisfies the CI lockfile check. Co-authored-by: Matthew Birtch * Fix unresolved conflict markers from master merge. Keep Compass Button/icons in system_user_detail and both add_bot fileInputRef plus master's submitting/unmounted guards. Co-authored-by: Matthew Birtch * fix unused compass icon imports in system_user_detail Remove SyncIcon, PowerPlugOutlineIcon, CheckIcon, and ChevronDownIcon imports left over from a merge conflict so check-lint (no-unused-vars) passes. Co-authored-by: Matthew Birtch * Restore SettingItemMax autofocus for react-select controls. Compass Button migration autofocus dropped [tabindex] matching, so Edit on settings like Number of direct messages no longer focused the select and broke the Playwright aria snapshot. Prefer form controls including tabindex again while still skipping footer Save/Cancel. Co-authored-by: Matthew Birtch * Fix SettingItemMax focus and language Space-to-open after Compass Button migration. Restore [tabindex] targeting so react-select receives Edit→expand focus (Compass Save/Cancel no longer match .btn), and open the controlled language menu on Space as well as Enter so MM-T1485 keyboard a11y still works. Co-authored-by: Matthew Birtch * Open controlled language menu on Space as well as Enter. SettingItemMax autofocus for react-select was restored separately; this makes ManageLanguage's controlled menuIsOpen open on Space so MM-T1485 keyboard a11y still expands the dropdown after the Compass Button migration. Co-authored-by: Matthew Birtch * Fix ESLint import/order and lines-around-comment in PR files. Reorder setting_item_max test imports and add a blank line before the manage_languages keyboard handler comment so check-lint passes. Co-authored-by: Matthew Birtch * Address review feedback on the compass-ui Button migration. Most of these share a root cause: legacy SCSS targets Bootstrap hooks (.btn, .btn-primary, .btn-tertiary, .btn-success) that the Compass Button no longer emits, and `color` no longer reaches the label because Compass reads --button-fg. Fixes: - Browse Channels: the Withdraw request button was hidden and out of the tab order, because browse_channels.scss only revealed .primaryButton, .outlineButton and .btn-tertiary on row hover. Give it a class and add that to the reveal rule. - tour_tip: move the Next/Previous overrides off .btn-primary / .btn-tertiary and onto the Compass buttons, so they stop rendering blue-on-blue and link-coloured-on-blue on the tip box. - appearance='inverted' resolves to --sidebar-text, which goes dark on Quartz. Drop it from the tour tip opt-out and the AD/LDAP banner CTAs and drive --button-fg from the container instead. - Use --button-fg rather than `color` for the save panel error state, the user detail pager arrows, the jobs table row hover and the url_input Edit link. - url_input: .url-input-button.btn no longer matched. Drop .btn, and write the rule out rather than via mixins.link, whose `color` and `font-size` would not have reached the label either. - hierarchical_value_menu: Retry becomes emphasis='link' instead of a tertiary pill with a dead &__retry.btn override. - GetLinkModal: btn-success no longer turns the Copied state green; use a local class. Drop the inert pull-left. - _modal.scss: reset Bootstrap's `.btn + .btn` margin so it stops stacking on the new gap in footers that still hold Bootstrap buttons. - Admin filter: restore the open state and add aria-expanded. - AdminPanelWithButton takes a `destructive` prop, passed by the channel membership policy panel so Remove all is red again. - Move icons from children into leadingIcon/trailingIcon so the Button's gap applies. - SaveChangesPanel: restore size='small' (the panel had grown from 58px to 66px) and drop the dead btn-force-disabled. - Size the notifications and channel invite links so their labels match the copy they sit in. Two notes. In company_info_display the `color` override was already dead on master, where .btn-primary set `color: ... !important`, so it is removed rather than converted -- converting it would have made the label blue on a blue button. And the classification attribute's trailing icon takes the raw glyph rather than , because renders divs and that button sits inside a

. Also migrates the Reload, Download and Wrap text buttons in the rewritten system console logs view, which master expressed as Bootstrap buttons. Co-Authored-By: Claude Opus 5 (1M context) * Fix regressions found testing the Compass Button review fixes. Mostly the same root cause as the review itself: rules written against Bootstrap hooks that the Compass Button no longer matches. - Browse Channels: Withdraw was visible on hover but still unreachable by keyboard. visibility: hidden takes a control out of the tab order, so the button could never be focused to reveal itself. Row actions now hide with opacity and reveal on their own :focus-visible; pointer-events stops an invisible button swallowing row clicks. - Tour tip: restore the 8px between Previous and Next, which came from the global `.btn + .btn` rule in _buttons.scss, and pin the buttons to master's fixed 32px box so the labels sit where they used to. - Tour tip opt-out: the --button-fg override has to sit on the button, not the container. Compass declares --button-fg on the element itself, which beats anything inherited, so the link stayed link-coloured. - Announcement bar CTA: .btn.btn-tertiary.btn-xs.btn-inverted no longer matches, so the warning bar lost its dark-on-gold text and inherited white from appearance='inverted'. The CTA carries a class now. - Jobs table: Compass quaternary is already --link-color, so View details was blue at rest and the row hover changed nothing. Muted at rest again. - Filters: the held-open state needs to beat Compass's own :hover rule, which has the same specificity, and clear the 8% resting tertiary tint to read as a state at all. The Users list uses a different trigger entirely (floating-ui, via useRole) and never had the state -- it does now. - Modal footers: scope the `.btn + .btn` margin reset to direct children. Buttons nested in a wrapper are not flex items, get no gap, and still need Bootstrap's margin -- the broad selector left them touching. - Review license changes modal: its footer is .content-footer, not .modal-footer, so it never picked up the gap either. - Notifications "Learn more": the icon was inside the label span, where the Button's gap does not apply. Moved to leadingIcon, and the button is now quaternary small. - Revert the user detail team list pager to the shared Button. Those are icon-only controls and become IconButton in a later pass. Co-Authored-By: Claude Opus 5 (1M context) * Fix tour tip button alignment by using Compass icon slots. Co-authored-by: Cursor * Fix rewrite menu icons and restore button gaps lost with Bootstrap. The rewrite feature's Stop generating, Discard and Regenerate buttons passed their icons as children, which puts them inside .button__label where the Button's gap does not apply, so they sat on the text baseline instead of centred. All six call sites (menu and inline variants) now use leadingIcon with Icon-wrapped glyphs. Also restores spacing in three containers that relied on the global `.btn + .btn` margin in _buttons.scss, which the Compass buttons no longer match: the cloud preview modal's navigation buttons, the terms of service agree/disagree pair, and the rewrite menu footer. While in the rewrite footer, its `.btn-quaternary` override was dead too, so Regenerate had lost its muted grey treatment and was rendering as a transparent link-coloured button. Reinstated against a class, through --button-fg. Co-Authored-By: Claude Opus 5 (1M context) * Restore the peer marker npm generates for compass-ui in the lockfile. I dropped "peer": true from the node_modules/@mattermost/compass-ui entry while resolving the merge, on the reasoning that compass-ui is now a direct dependency of the root manifest. npm still resolves it as a peer, through @mattermost/components' peerDependencies, so a regenerated lockfile puts the marker back and check-lockfile fails on the difference. This is exactly the case that job exists for: `npm ci` accepts a lockfile with the peer markers stripped, so only regenerating and diffing catches it. Produced with `npm install --package-lock-only`, which is what CI runs and which leaves node_modules alone. Co-Authored-By: Claude Opus 5 (1M context) * Use a standard Compass leading icon for the notifications learn-more link. The lightbulb was a bare compass-icons glyph carrying a `circular-border` class, which drew an 18px tinted circle behind it. Pass it through Icon instead, so it picks up the size the Button's slot provides (12px at size='small') and renders like every other leading icon. `circular-border` had exactly one caller, so its rule in setting_desktop_header.scss goes with it. Co-Authored-By: Claude Opus 5 (1M context) * Restore the Compass focus ring and master's modal footer spacing. **Focus ring.** Keyboard focus on a Compass button showed no ring. The webapp has a global `*:focus { outline: none }` in base/_structure.scss, and Compass's :focus-visible rule overrides only outline-color and outline-offset -- never outline-style -- so the reset wins and nothing paints. _modifiers.scss already suppresses our own a11y--focused box-shadow on Compass controls on the grounds that "Compass draws its own focus ring", so those controls were left with no indicator at all. Restoring outline-style and width at that same seam keeps the blast radius to Compass controls. Narrowing the global reset to `*:focus:not(:focus-visible)` would also work and is arguably where this belongs, but it re-enables native rings app-wide on top of the a11y--focused box-shadow, which deserves its own PR. Measured in Chromium: solid 2px with the reset still in place, and no doubled box-shadow. **Modal footers.** Playbooks modals had 5px between footer buttons. I had scoped the margin reset to direct children, which left buttons nested in a wrapper falling back to Bootstrap's own `.modal-footer .btn + .btn` margin of 5px (bootstrap.css:6033). Master overrode that to 8px for every descendant; do the same, and keep zeroing it for direct children, which are flex items and already have the gap. Both cases now measure 8px, matching master exactly -- the descendant rule has the same reach and value master's had, so it cannot introduce a doubling that master did not already have. Co-Authored-By: Claude Opus 5 (1M context) * Drop two dead .btn + .btn resets. Both containers set their own gap and used `.btn + .btn { margin-left: 0 }` to cancel the extra 8px the global rule in _buttons.scss would otherwise stack on top. Both now render Compass buttons, which never carry .btn, so there is nothing left to cancel and the gap applies on its own. No visual change -- these only ever removed spacing. Co-Authored-By: Claude Opus 5 (1M context) * Fix remaining icon, spacing and focus-ring issues from the broad sweep. - Archive channel button: .btn-danger no longer matches (destructive is a prop now), so the button stretched to fill its column flex container. Retarget the rule at the button's id. - Permissions policy tab: Add rule's plus icon was a child, landing in the label span where the Button's gap does not apply. Moved to leadingIcon and deleted its override block -- padding, gap and icon sizing were all fighting what Compass already provides for a medium button with a leading icon. - Team creation Next button: the chevron was baked into the buttonText fragment passed down from create_team_form, so it rendered inside the label rather than the trailing slot. Added a buttonTrailingIcon prop threaded through DisplayNameStep. - signup-team__container: the Compass focus ring (3px offset, 2px wide) was clipped by this container's overflow: hidden, which is load-bearing -- it stops .terms-of-service__markdown (min-width: 100vw) from blowing the page out horizontally. Added an 8px gutter and widened max-width by 16px to compensate, since box-sizing is border-box globally. Shared by password reset, MFA setup, Select Team and Terms of Service. - get-app__buttons (the "Where would you like to view this?" landing page): was not flex and had no gap, so the two buttons touched once the global `.btn + .btn` margin stopped applying. Co-Authored-By: Claude Opus 5 (1M context) * Add the 8px gap between interactive dialog footer buttons. Cancel and the submit buttons weren't direct children of .modal-footer -- they sat inside a single unstyled wrapper div alongside the error text, so .modal-footer's own gap never reached them, and neither Button nor SpinnerButton carries .btn for the descendant margin rule to match either. Split the wrapper into apps-form-footer (column: error text, then the button row) and apps-form-footer__buttons (the row itself), both using --spacing-xs for the gap. Co-Authored-By: Claude Opus 5 (1M context) * Migrate InlineActionButton to the Compass Button (tertiary, x-small). Deliberately not using the Button's own `loading` prop: it forces native `disabled`, which would drop the deliberate aria-disabled + aria-busy pattern this component uses to stay focusable and announced to screen readers while an action is in flight (see the existing test "button uses aria-disabled (not native disabled) while executing"). Those two attributes pass through Button's prop spread unchanged, and the spinner swap still comes from LoadingWrapper around the children, so the a11y behavior and the executingRef double-click guard are untouched -- only the rendering primitive changed. Dropped the hand-rolled pill styling (border, custom background, custom hover color) in favor of what tertiary already provides; kept the --executing opacity modifier since the control stays enabled (no native disabled to dim it). Co-Authored-By: Claude Opus 5 (1M context) * Migrate secure connections and log row copy/add buttons to Compass Button. Fixes icons passed as raw children instead of leadingIcon/trailingIcon (secure connection detail, invite modal copy buttons, logs Copy JSON/ Copy log line), migrates the Add a connection and row kebab menu triggers off legacy buttonClassNames, and swaps the invite modal's negative-margin hack for align-self/spacing-token based positioning. * Update stale aria-snapshot for Notifications settings panel. The Compass Button migration changed how the panel's "Edit" row buttons expose their accessible name/structure (status text like "On"/"None" now renders as separate text nodes, and the "Learn more" link icon is aria-hidden), so the hardcoded snapshot baseline no longer matched. Regenerated against the CI build image and reconciled the user-specific literals back to their template expressions. * Use Button's native loading prop instead of LoadingSpinner children Several Compass Button instances rendered LoadingSpinner as a child/icon instead of using Button's own loading state, which would otherwise double up once LoadingSpinner itself renders the Compass spinner. Adds an isConfirmLoading prop to GenericModal so its internal confirm button can use the same pattern. * Fix remaining Button+LoadingSpinner instances missed in prior pass searchable_channel_list.tsx (Join/Request to join/Withdraw) and button_binding.tsx both swapped children for a legacy LoadingWrapper spinner instead of using Button's native loading prop. * Update tests and snapshots for Button's native loading spinner Co-Authored-By: Claude Sonnet 5.5 --------- Co-authored-by: Cursor Agent Co-authored-by: Matthew Birtch <2040554+matthewbirtch@users.noreply.github.com> Co-authored-by: Claude Opus 5 (1M context) Co-authored-by: mattermost-code Co-authored-by: maria.nunez --- .../accessibility_account_settings_spec.js | 17 +- .../collapsed_reply_threads/replies_spec.ts | 6 +- .../channels/emoji/custom_emoji_1_1_spec.ts | 4 +- .../channels/emoji/custom_emoji_1_spec.ts | 4 +- .../guest_invitation_ui_more_spec.ts | 2 +- .../system_console_manage_guest_spec.ts | 2 +- .../system_console/archived_channels_spec.js | 6 +- .../slash_commands_spec.js | 2 +- .../interactive_dialog/file_upload_spec.js | 4 +- .../forward_message_from_dm_spec.js | 8 +- ...rward_message_from_private_channel_spec.js | 4 +- .../existing_channel_name_spec.js | 4 +- .../user_management/users_spec.js | 14 +- .../system_console/user_management_spec.js | 4 +- .../delete_post_confirmation_dialog.ts | 2 +- .../components/channels/marketplace_modal.ts | 4 +- .../restore_post_confirmation_dialog.ts | 4 +- .../settings_dialog/notifications.spec.ts | 5 +- webapp/AGENTS.md | 1 + webapp/CLAUDE.OPTIONAL.md | 2 +- webapp/STYLE_GUIDE.md | 2 +- .../get_link_modal.test.tsx.snap | 176 ++++- .../__snapshots__/list_modal.test.tsx.snap | 9 +- .../post_deleted_modal.test.tsx.snap | 8 +- .../__snapshots__/save_button.test.tsx.snap | 52 +- .../setting_item_max.test.tsx.snap | 199 ++++-- .../setting_picture.test.tsx.snap | 353 ++++++--- .../spinner_button.test.tsx.snap | 44 +- .../actions_menu_empty_popover.tsx | 4 +- .../__snapshots__/activity_log.test.tsx.snap | 18 +- .../components/activity_log.tsx | 2 +- .../add_groups_to_channel_modal.test.tsx.snap | 6 +- .../add_groups_to_team_modal.test.tsx.snap | 6 +- .../add_user_to_channel_modal.test.tsx.snap | 16 +- .../add_user_to_channel_modal.tsx | 2 +- ...dd_user_to_group_multiselect.test.tsx.snap | 18 +- .../add_users_to_group_modal.test.tsx.snap | 15 +- .../add_users_to_team_modal.test.tsx.snap | 6 +- .../cluster_settings.test.tsx.snap | 24 +- .../database_settings.test.tsx.snap | 14 +- .../elasticsearch_settings.test.tsx.snap | 114 ++- .../message_export_settings.test.tsx.snap | 70 +- .../__snapshots__/push_settings.test.tsx.snap | 12 +- .../__snapshots__/policies.test.tsx.snap | 105 ++- .../access_control/editors/shared.test.tsx | 10 +- .../access_control/editors/shared.tsx | 12 +- .../jobs/access_control_sync_job_table.scss | 10 - .../jobs/access_control_sync_job_table.tsx | 10 +- .../searchable_sync_job_channel_list.tsx | 6 +- .../searchable_sync_job_team_list.tsx | 6 +- .../session_attribute_editor.tsx | 2 +- .../simulate_access_modal.scss | 2 +- .../simulate_access/simulate_access_modal.tsx | 20 +- .../access_control/policies.scss | 10 - .../admin_console/access_control/policies.tsx | 18 +- .../policy_details.test.tsx.snap | 163 ++++- .../__snapshots__/channel_list.test.tsx.snap | 180 ++++- .../policy_details/policy_details.tsx | 22 +- .../__snapshots__/admin_setting.test.tsx.snap | 6 +- .../admin_user_card/admin_user_card.scss | 2 + .../admin_console/audits/audits.tsx | 2 +- .../cancel_subscription.tsx | 27 +- .../contact_sales_card.tsx | 26 +- .../billing/billing_subscriptions/limits.scss | 27 +- .../billing/billing_subscriptions/limits.tsx | 2 +- .../billing_summary/billing_summary.tsx | 46 +- .../billing/company_info_display.scss | 4 - .../billing/company_info_display.tsx | 44 +- .../billing/company_info_edit.tsx | 20 +- .../billing/plan_details/plan_details.tsx | 2 +- .../blockable_button/blockable_button.tsx | 45 -- .../admin_console/blockable_button/index.ts | 29 - .../blockable_link/blockable_link.tsx | 1 + .../board_attributes_delete_modal.tsx | 2 +- .../brand_image_setting.tsx | 2 +- .../classification_markings.tsx | 2 +- .../classification_markings_styled.tsx | 21 +- .../admin_console/cluster_table.tsx | 2 +- .../compliance_reports/compliance_reports.tsx | 2 +- .../team_reviewers_section.tsx | 8 +- .../custom_plugin_settings.test.tsx.snap | 34 +- .../enable_plugin_button.tsx | 2 +- ...om_terms_of_service_settings.test.tsx.snap | 6 +- .../data_retention_settings.test.tsx.snap | 72 +- .../__snapshots__/channel_list.test.tsx.snap | 90 ++- .../custom_policy_form.test.tsx.snap | 154 +++- .../custom_policy_form/custom_policy_form.tsx | 20 +- .../global_policy_form.test.tsx.snap | 14 +- .../global_policy_form/global_policy_form.tsx | 20 +- .../admin_console/file_upload_setting.tsx | 2 +- .../admin_console/filter/filter.scss | 31 +- .../admin_console/filter/filter.tsx | 18 +- .../admin_console/generated_setting.tsx | 2 +- .../applies_to/applies_to_card.scss | 6 +- .../applies_to/applies_to_card.tsx | 13 +- .../channels/channels_resource_row.scss | 2 +- .../channels/channels_resource_row.tsx | 6 +- .../attribute_applies_to.tsx | 3 +- .../attribute_applies_to_channel_item.tsx | 6 +- .../attribute_applies_to_item.scss | 7 +- .../attribute_applies_to_post_item.tsx | 6 +- .../attribute_applies_to_user_item.tsx | 6 +- .../attribute_details/attribute_details.tsx | 14 +- .../attribute_external_source.scss | 30 +- .../attribute_external_source.tsx | 34 +- ...ribute_remove_applies_to_warning_modal.tsx | 2 +- .../graph/delete_modal.test.tsx | 1 - .../attribute_details/graph/delete_modal.tsx | 2 +- .../attribute_details/graph/draft_forms.tsx | 8 +- .../attribute_details/graph/graph_values.scss | 5 +- .../graph/graph_values.test.tsx | 8 +- .../classification_attribute.tsx | 38 +- .../remove_channel_resource_modal.tsx | 2 +- .../global_attribute_delete_modal.tsx | 2 +- .../global_attributes/global_attributes.tsx | 9 +- .../group_settings.test.tsx.snap | 36 +- .../__snapshots__/group_details.test.tsx.snap | 224 ++++-- .../group_teams_and_channels.test.tsx.snap | 56 +- ...group_teams_and_channels_row.test.tsx.snap | 48 +- .../__snapshots__/group_users.test.tsx.snap | 196 +++-- .../group_details/group_details.tsx | 2 +- .../group_teams_and_channels_row.tsx | 2 +- .../group_details/group_users.tsx | 2 +- .../__snapshots__/groups_list.test.tsx.snap | 629 ++++++++++++---- .../groups_list/groups_list.tsx | 10 +- .../inline_section_feature_discovery.tsx | 2 +- .../ip_filtering/add_edit_ip_filter_modal.tsx | 2 +- .../ip_filtering/delete_confirmation.tsx | 4 +- .../edit_section/edit_section_header.tsx | 2 +- .../edit_section_ip_not_in_range_panel.tsx | 3 +- .../edit_section_no_filters_panel.tsx | 2 +- .../edit_section/edit_sections.scss | 6 +- .../ip_filtering/ip_filtering.scss | 6 - .../ip_filtering/save_confirmation_modal.tsx | 4 +- .../components/admin_console/jobs/table.scss | 22 +- .../components/admin_console/jobs/table.tsx | 8 +- .../license_settings.test.tsx.snap | 669 +++++++++++++----- .../enterprise_edition.scss | 22 +- .../enterprise_edition_left_panel.tsx | 13 +- .../enterprise_edition_right_panel.tsx | 15 +- .../modals/confirm_license_removal_modal.tsx | 2 +- .../modals/ee_license_modal.tsx | 2 +- .../modals/upload_license_modal.scss | 6 + .../modals/upload_license_modal.tsx | 16 +- .../starter_edition/starter_left_panel.tsx | 4 +- .../team_edition/team_edition.scss | 3 +- .../team_edition/team_edition_right_panel.tsx | 61 +- .../trial_banner/trial_banner.tsx | 49 +- .../manage_roles_modal/manage_roles_modal.tsx | 2 +- .../remove_from_team_button.test.tsx.snap | 8 +- .../remove_from_team_button.tsx | 4 +- .../manage_tokens_modal.test.tsx.snap | 16 +- .../openid_convert.test.tsx.snap | 17 +- .../openid_convert/openid_convert.scss | 36 +- .../openid_convert/openid_convert.tsx | 31 +- .../permission_policies.tsx | 2 +- .../permission_policy_details.scss | 23 - .../permission_policy_details.tsx | 62 +- .../permission_schemes_settings.test.tsx.snap | 84 ++- .../edit_post_time_limit_modal.tsx | 2 +- ...ssion_system_scheme_settings.test.tsx.snap | 92 ++- ...permission_system_scheme_settings.test.tsx | 2 +- .../permission_system_scheme_settings.tsx | 20 +- .../permission_team_scheme_settings.tsx | 20 +- .../plugin_management.test.tsx.snap | 90 ++- .../plugin_management/plugin_management.tsx | 2 +- .../plugin_upload_overwrite_review_modal.tsx | 2 +- .../admin_console/remove_file_setting.tsx | 4 +- .../request_button.test.tsx.snap | 40 +- .../request_button/request_button.tsx | 29 +- .../revoke_non_compliant_tokens_button.tsx | 10 +- .../revoke_token_button.tsx | 4 +- .../admin_console/save_changes_panel.test.tsx | 114 +++ .../admin_console/save_changes_panel.tsx | 56 +- .../secure_connections/controls.tsx | 36 +- .../secure_connection_create_invite_modal.tsx | 35 +- .../modals/secure_connection_delete_modal.tsx | 2 +- .../modals/shared_channels_remove_modal.tsx | 2 +- .../secure_connection_detail.tsx | 15 +- .../secure_connection_row.tsx | 24 +- .../secure_connections/secure_connections.tsx | 44 +- .../admin_console/server_logs/log_list.tsx | 52 +- .../admin_console/server_logs/log_row.tsx | 23 +- .../server_logs/plain_log_list.tsx | 46 +- .../disable_attribute_modal.tsx | 2 +- .../system_properties/controls.tsx | 42 +- .../user_properties_delete_modal.tsx | 2 +- .../__snapshots__/system_role.test.tsx.snap | 28 +- .../add_users_to_role_modal.test.tsx.snap | 30 +- .../system_role_users.test.tsx.snap | 18 +- .../system_role_users/system_role_users.tsx | 3 +- .../system_user_detail.test.tsx.snap | 237 +++++-- .../system_user_detail/system_user_detail.tsx | 6 +- .../revoke_sessions_button/index.tsx | 6 +- .../system_users_export/index.tsx | 4 +- .../system_users_filters_popover/index.tsx | 15 +- .../system_users_filter_popover.scss | 13 + .../confirm_reset_failed_attempts_modal.tsx | 2 +- ...reate_group_syncables_membership_modal.tsx | 2 +- .../deactivate_member_modal.tsx | 2 +- .../demote_to_guest_modal.tsx | 2 +- .../promote_to_member_modal.tsx | 2 +- .../revoke_sessions_modal.tsx | 2 +- .../__snapshots__/abstract_list.test.tsx.snap | 28 +- .../team_channel_settings/abstract_list.tsx | 2 +- .../channel_details.test.tsx.snap | 374 ++++++++-- .../channel_groups.test.tsx.snap | 37 +- .../channel_profile.test.tsx.snap | 72 +- .../channel_access_control_policy.scss | 14 - .../details/channel_access_control_policy.tsx | 7 +- .../channel/details/channel_groups.tsx | 3 +- .../channel_members.test.tsx.snap | 108 ++- .../channel_members/channel_members.tsx | 3 +- .../channel/details/channel_profile.tsx | 12 +- .../__snapshots__/channel_list.test.tsx.snap | 225 +++++- .../team_channel_settings/errors.tsx | 3 +- .../__snapshots__/group_list.test.tsx.snap | 56 +- .../group_members_modal.test.tsx.snap | 8 +- .../group/group_members_modal.tsx | 2 +- .../users_to_remove.test.tsx.snap | 135 +++- .../__snapshots__/team_details.test.tsx.snap | 28 +- .../__snapshots__/team_groups.test.tsx.snap | 37 +- .../__snapshots__/team_profile.test.tsx.snap | 188 ++++- .../details/team_access_control_policy.tsx | 2 +- .../team/details/team_groups.tsx | 3 +- .../__snapshots__/team_members.test.tsx.snap | 108 ++- .../details/team_members/team_members.tsx | 3 +- .../team/details/team_profile.tsx | 28 +- .../users_to_be_removed_modal.tsx | 2 +- .../__snapshots__/user_grid.test.tsx.snap | 135 +++- .../__snapshots__/cta_buttons.test.tsx.snap | 18 +- .../workspace-optimization/cta_buttons.tsx | 6 +- .../workspace-optimization/dashboard.scss | 12 +- .../advanced_text_editor/rewrite_menu.tsx | 29 +- .../advanced_text_editor/use_rewrite.scss | 21 +- .../configuration_bar.test.tsx.snap | 36 +- .../contact_sales/contact_us.tsx | 2 +- .../announcement_bar.tsx | 12 +- .../__snapshots__/index.test.tsx.snap | 18 +- .../purchase_link/purchase_link.tsx | 6 +- .../renewal_link/renewal_link.tsx | 6 +- .../apps_form_container.test.tsx.snap | 42 +- .../apps_form_action_button.test.tsx | 5 +- .../apps_form/apps_form_action_button.tsx | 2 +- .../apps_form/apps_form_component.scss | 13 + .../apps_form/apps_form_component.tsx | 20 +- .../apps_form_file_upload.tsx | 2 +- .../src/components/authorize/authorize.tsx | 2 +- .../backstage/components/backstage_list.tsx | 22 +- .../block_renderer/block_renderer.scss | 41 +- .../block_renderer/button_element.test.tsx | 28 +- .../block_renderer/button_element.tsx | 15 +- .../block_renderer/utils/button.test.ts | 27 +- .../components/block_renderer/utils/button.ts | 28 +- .../browse_channels.test.tsx.snap | 18 +- .../browse_channels/browse_channels.scss | 20 +- .../browse_channels/browse_channels.tsx | 16 +- .../burn_on_read_confirmation_modal.tsx | 2 +- .../card/__snapshots__/card.test.tsx.snap | 9 +- .../title_and_button_card_header.tsx | 4 +- .../bookmark_delete_modal.tsx | 2 +- .../channel_invite_modal.tsx | 11 +- .../channel_members_modal.test.tsx.snap | 9 +- .../channel_members_modal.tsx | 4 +- .../pending_join_requests.scss | 4 - .../pending_join_requests.tsx | 8 +- .../channel_notifications_modal.tsx | 10 +- .../channel_access_rules_confirm_modal.scss | 2 +- .../channel_access_rules_confirm_modal.tsx | 4 +- .../channel_activity_warning_modal.tsx | 2 +- .../channel_settings_archive_tab.test.tsx | 4 +- .../channel_settings_archive_tab.tsx | 6 +- .../channel_settings_modal.scss | 5 +- ...annel_settings_permissions_policy_tab.scss | 13 +- ...hannel_settings_permissions_policy_tab.tsx | 21 +- .../__snapshots__/channel_view.test.tsx.snap | 18 +- .../components/channel_view/channel_view.tsx | 2 +- .../components/channel_view/input_loading.tsx | 2 +- .../claim/components/email_to_ldap.tsx | 2 +- .../claim/components/email_to_oauth.tsx | 2 +- .../claim/components/ldap_to_email.tsx | 2 +- .../claim/components/oauth_to_email.tsx | 2 +- .../components/cloud_fetch_error/index.tsx | 2 +- .../preview_modal_content_controller.tsx | 2 +- .../preview_modal_controller.scss | 4 + .../__snapshots__/success.test.tsx.snap | 9 +- .../commercial_support_modal.test.tsx.snap | 37 +- .../commercial_support_modal.tsx | 8 +- .../src/components/common/hooks/useWords.tsx | 9 +- .../component_library/button.cl.tsx | 87 ++- .../mm_blocks_hierarchy_editor.tsx | 8 +- .../channels/src/components/confirm_modal.tsx | 9 +- .../convert_channel_modal.tsx | 2 +- .../convert_gm_to_channel_modal.tsx | 2 +- .../create_recap_modal.scss | 2 +- .../create_recap_modal/create_recap_modal.tsx | 10 +- .../__snapshots__/create_team.test.tsx.snap | 36 +- .../create_team_form.test.tsx.snap | 44 +- .../create_team_form/create_team_form.tsx | 24 +- .../create_team_form/display_name_step.tsx | 9 +- .../create_team_form/team_url_step.tsx | 2 +- .../delete_category_modal.tsx | 2 +- .../delete_channel_modal.test.tsx.snap | 16 +- .../delete_channel_modal.tsx | 4 +- .../delete_post_modal.test.tsx.snap | 48 +- .../delete_post_modal/delete_post_modal.tsx | 10 +- .../draft_actions/delete_draft_modal.tsx | 2 +- .../delete_scheduled_post_modal.tsx | 2 +- .../edit_channel_header_modal.test.tsx.snap | 80 ++- .../edit_channel_header_modal.tsx | 2 +- .../edit_channel_purpose_modal.tsx | 2 +- .../__snapshots__/emoji_page.test.tsx.snap | 9 +- .../__snapshots__/add_emoji.test.tsx.snap | 75 +- .../components/emoji/add_emoji/add_emoji.tsx | 20 +- .../emoji/emoji_list/emoji_list.tsx | 2 +- .../src/components/emoji/emoji_page.test.tsx | 4 +- .../src/components/emoji/emoji_page.tsx | 17 +- .../emoji_picker_custom_emoji_button.tsx | 25 +- .../feature_toast/feature_toast.tsx | 8 +- .../src/components/get_link_modal.scss | 9 + .../src/components/get_link_modal.test.tsx | 15 +- .../src/components/get_link_modal.tsx | 33 +- .../get_public_link_modal.test.tsx.snap | 88 ++- .../plan_upgrade_button/index.tsx | 4 +- .../components/inline_action_button/index.tsx | 13 +- .../inline_action_button.scss | 15 - .../abstract_command.test.tsx.snap | 50 +- .../abstract_incoming_hook.test.tsx.snap | 112 ++- .../abstract_oauth_app.test.tsx.snap | 32 +- .../abstract_outgoing_webhook.test.tsx.snap | 16 +- .../integrations/abstract_command.tsx | 20 +- .../abstract_incoming_webhook.tsx | 20 +- .../integrations/abstract_oauth_app.tsx | 20 +- .../abstract_outgoing_webhook.tsx | 20 +- .../__snapshots__/add_command.test.tsx.snap | 18 +- .../add_incoming_webhook.test.tsx.snap | 16 +- .../__snapshots__/add_oauth_app.test.tsx.snap | 16 +- .../add_outgoing_webhook.test.tsx.snap | 16 +- .../__snapshots__/add_bot.test.tsx.snap | 41 +- .../integrations/bots/add_bot/add_bot.tsx | 47 +- .../src/components/integrations/bots/bot.tsx | 8 +- .../confirm_integration.test.tsx.snap | 45 +- .../confirm_integration.tsx | 21 +- .../delete_integration_link.tsx | 2 +- .../__snapshots__/edit_command.test.tsx.snap | 32 +- .../edit_incoming_webhook.test.tsx.snap | 66 +- .../edit_oauth_app.test.tsx.snap | 32 +- .../edit_outgoing_webhook.test.tsx.snap | 32 +- .../installed_oauth_apps.test.tsx.snap | 22 +- .../installed_outgoing_webhooks.test.tsx.snap | 11 +- ...ct_outgoing_oauth_connection.test.tsx.snap | 48 +- ...dd_outgoing_oauth_connection.test.tsx.snap | 24 +- ...it_outgoing_oauth_connection.test.tsx.snap | 72 +- ...d_outgoing_oauth_connections.test.tsx.snap | 11 +- ...bstract_outgoing_oauth_connection.test.tsx | 4 +- .../abstract_outgoing_oauth_connection.tsx | 22 +- .../invitation_modal/invite_view.scss | 4 - .../invitation_modal/invite_view.tsx | 36 +- .../invitation_modal/no_permissions_view.tsx | 2 +- .../invitation_modal/result_view.tsx | 2 +- .../learn_more_trial_modal.test.tsx.snap | 13 +- .../start_trial_btn.test.tsx.snap | 13 +- .../start_trial_btn.test.tsx | 6 +- .../start_trial_btn.tsx | 37 +- .../leave_channel_modal.test.tsx.snap | 16 +- .../leave_channel_modal.tsx | 22 +- .../leave_team_modal.test.tsx.snap | 16 +- .../leave_team_modal/leave_team_modal.tsx | 4 +- .../linking_landing_page.tsx | 89 ++- webapp/channels/src/components/list_modal.tsx | 8 +- .../__snapshots__/login_mfa.test.tsx.snap | 6 +- .../components/mark_all_as_read_modal.scss | 2 +- .../src/components/mark_all_as_read_modal.tsx | 16 +- .../mfa/__snapshots__/confirm.test.tsx.snap | 8 +- .../channels/src/components/mfa/confirm.tsx | 2 +- .../setup/__snapshots__/setup.test.tsx.snap | 8 +- .../src/components/mfa/setup/setup.tsx | 2 +- .../more_direct_channels.test.tsx.snap | 12 +- .../__snapshots__/multiselect.test.tsx.snap | 45 +- .../components/multiselect/multiselect.tsx | 7 +- .../new_channel_modal.test.tsx | 72 +- .../new_channel_modal/new_channel_modal.tsx | 9 +- ...nboarding_tasklist_completed.test.tsx.snap | 13 +- .../password_reset_form.test.tsx.snap | 8 +- .../password_reset_form.tsx | 2 +- .../password_reset_send_link.tsx | 2 +- .../marketplace_modal.test.tsx.snap | 41 +- .../marketplace_item_app.test.tsx.snap | 102 ++- .../marketplace_item_app.test.tsx | 2 +- .../marketplace_item_app.tsx | 42 +- .../marketplace_item_plugin.test.tsx.snap | 102 ++- .../marketplace_item_plugin.tsx | 50 +- .../marketplace_list/marketplace_list.tsx | 5 +- .../plugin_marketplace/marketplace_modal.scss | 16 - .../components/post/post_error_boundary.tsx | 2 +- .../src/components/post_deleted_modal.tsx | 2 +- .../add_members_button.tsx | 4 +- .../data_spillage_actions.scss | 4 - .../data_spillage_actions.tsx | 8 +- .../data_spillage_download_report.scss | 2 +- .../data_spillage_download_report.tsx | 95 +-- .../data_spillage_exposure_report.tsx | 26 +- .../data_spillage_footer.tsx | 4 +- .../button_binding/button_binding.tsx | 26 +- .../action_button/action_button.scss | 16 + .../action_button/action_button.test.tsx | 65 +- .../action_button/action_button.tsx | 93 +-- .../product_notices.test.tsx.snap | 50 +- .../profile_popover_custom_status.tsx | 4 +- .../profile_popover_other_user_row.tsx | 8 +- .../profile_popover_self_user_row.tsx | 4 +- .../hierarchical_value_menu.scss | 10 - .../hierarchical_value_menu_parts.tsx | 6 +- .../purchase_modal/icon_message.tsx | 2 +- .../src/components/recaps/recap_item.tsx | 2 +- .../channels/src/components/recaps/recaps.tsx | 2 +- .../recaps/scheduled_recap_item.tsx | 2 +- .../recaps/scheduled_recaps_empty_state.tsx | 2 +- .../error_step/error_step_body.tsx | 8 +- .../error_step/error_step_footer.tsx | 28 +- .../form_step/form_step_footer.tsx | 22 +- .../generated_step/generated_step_footer.tsx | 27 +- .../generating_step_footer.tsx | 28 +- .../skip_confirm_step_footer.tsx | 17 +- .../removed_from_channel_modal.test.tsx.snap | 8 +- .../removed_from_channel_modal.tsx | 2 +- .../rename_channel_modal.tsx | 2 +- .../channels/src/components/save_button.tsx | 42 +- .../scroll_to_bottom_toast.tsx | 2 +- .../components/searchable_channel_list.tsx | 47 +- .../searchable_user_list.tsx | 6 +- .../src/components/setting_item_max.test.tsx | 56 ++ .../src/components/setting_item_max.tsx | 61 +- .../src/components/setting_picture.tsx | 51 +- .../signup/__snapshots__/signup.test.tsx.snap | 12 +- .../src/components/spinner_button.tsx | 50 +- .../start_trial_form_modal.test.tsx.snap | 8 +- .../air_gapped_modal.tsx | 2 +- .../start_trial_form_modal/index.tsx | 2 +- .../suggestion/switch_channel_provider.tsx | 4 +- .../__snapshots__/system_notice.test.tsx.snap | 117 ++- .../system_notice/system_notice.tsx | 6 +- .../team_members_modal/team_members_modal.tsx | 4 +- .../team_access_policies_tab.tsx | 2 +- .../team_policy_confirmation_modal.tsx | 4 +- .../team_policy_editor.tsx | 6 +- .../team_access_tab/invite_section_input.tsx | 2 +- .../terms_of_service.test.tsx.snap | 70 +- .../terms_of_service/terms_of_service.tsx | 7 +- .../components/toggle_modal_button.test.tsx | 21 + .../src/components/toggle_modal_button.tsx | 35 + .../components/tours/channels_tour_tip.tsx | 73 +- .../unarchive_channel_modal.test.tsx.snap | 16 +- .../unarchive_channel_modal.tsx | 4 +- .../update_user_group_modal.test.tsx.snap | 15 +- .../update_user_group_modal.tsx | 2 +- .../user_groups_modal.test.tsx.snap | 18 +- .../ad_ldap_upsell_banner.tsx | 11 +- .../user_groups_modal/user_groups_modal.scss | 9 +- .../user_groups_modal/user_groups_modal.tsx | 6 +- .../join_leave_section.test.tsx.snap | 43 +- .../advanced/user_settings_advanced.tsx | 2 +- .../user_settings_display.test.tsx.snap | 270 ++++--- .../manage_languages/manage_languages.tsx | 11 +- .../render_emoticons_as_emoji.test.tsx.snap | 43 +- .../custom_theme_chooser.test.tsx.snap | 15 +- .../custom_theme_chooser.tsx | 2 +- .../headers/setting_desktop_header.scss | 9 - .../user_settings_notifications.test.tsx.snap | 276 +++++--- .../__snapshots__/index.test.tsx.snap | 86 ++- .../email_notification_setting.test.tsx.snap | 236 +++--- .../manage_auto_responder.test.tsx.snap | 86 ++- .../user_settings_notifications.tsx | 21 +- .../__snapshots__/mfa_section.test.tsx.snap | 90 ++- .../security/mfa_section/mfa_section.tsx | 2 +- .../user_access_token_section.tsx | 2 +- .../security/user_settings_security.tsx | 216 +++--- .../view_user_group_modal_header.tsx | 10 +- .../admin_panel_with_button.test.tsx | 5 +- .../admin_console/admin_panel_with_button.tsx | 8 +- .../admin_panel_with_link.test.tsx | 17 +- .../admin_console/admin_panel_with_link.tsx | 20 +- .../widgets/inputs/url_input/url_input.scss | 19 +- .../widgets/inputs/url_input/url_input.tsx | 4 +- .../modals/components/save_changes_panel.scss | 43 +- .../modals/components/save_changes_panel.tsx | 22 +- .../widgets/settings/radio_setting.tsx | 4 +- .../src/constants/preferences.ts | 2 +- .../sass/components/_announcement-bar.scss | 19 +- .../src/sass/components/_buttons.scss | 4 + .../components/_channel-invite-modal.scss | 1 - .../channels/src/sass/components/_forms.scss | 16 - .../channels/src/sass/components/_modal.scss | 29 +- .../src/sass/components/_multi-select.scss | 6 +- .../src/sass/components/_save-button.scss | 6 + .../channels/src/sass/responsive/_mobile.scss | 4 +- .../src/sass/routes/_admin-console.scss | 33 +- .../channels/src/sass/routes/_backstage.scss | 12 +- webapp/channels/src/sass/routes/_get-app.scss | 7 + webapp/channels/src/sass/routes/_signup.scss | 17 +- .../channels/src/sass/utils/_modifiers.scss | 20 + webapp/package-lock.json | 3 + webapp/package.json | 1 + webapp/platform/components/README.md | 8 + webapp/platform/components/package.json | 1 + webapp/platform/components/rollup.config.js | 11 +- .../src/generic_modal/generic_modal.test.tsx | 33 + .../src/generic_modal/generic_modal.tsx | 19 +- .../components/src/tour_tip/tour_tip.scss | 88 ++- .../components/src/tour_tip/tour_tip.test.tsx | 9 +- .../components/src/tour_tip/tour_tip.tsx | 18 +- .../shared/src/components/button/index.ts | 2 + 512 files changed, 9783 insertions(+), 4728 deletions(-) delete mode 100644 webapp/channels/src/components/admin_console/blockable_button/blockable_button.tsx delete mode 100644 webapp/channels/src/components/admin_console/blockable_button/index.ts create mode 100644 webapp/channels/src/components/admin_console/save_changes_panel.test.tsx create mode 100644 webapp/channels/src/components/get_link_modal.scss create mode 100644 webapp/channels/src/components/post_view/message_attachments/action_button/action_button.scss diff --git a/e2e-tests/cypress/tests/integration/channels/accessibility/accessibility_account_settings_spec.js b/e2e-tests/cypress/tests/integration/channels/accessibility/accessibility_account_settings_spec.js index 092bdb0a669..0692a4769b9 100644 --- a/e2e-tests/cypress/tests/integration/channels/accessibility/accessibility_account_settings_spec.js +++ b/e2e-tests/cypress/tests/integration/channels/accessibility/accessibility_account_settings_spec.js @@ -176,13 +176,20 @@ describe('Verify Accessibility Support in different sections in Settings and Pro cy.get('#changeInterfaceLanguageLabel').should('be.visible').and('have.text', 'Change interface language'); // # When space key is pressed on dropdown, it should expand and should collapse when esc key is pressed - cy.get('@inputEl').typeWithForce(' '); - cy.findByRole('listbox').should('have.class', 'react-select__menu-list').as('listBox'); + // Menu is portaled to document.body (outside the aria-modal dialog), so query by class + // and assert role=listbox rather than findByRole (inaccessible outside the modal). + cy.get('@inputEl').focus().typeWithForce(' '); + cy.get('.react-select__menu-list'). + should('be.visible'). + and('have.attr', 'role', 'listbox'). + and('have.class', 'react-select__menu-list'). + as('listBox'); cy.get('@inputEl').typeWithForce('{esc}'); cy.get('@listBox').should('not.exist'); // # Press down arrow twice and check aria label - cy.get('@inputEl').typeWithForce(' '); + cy.get('@inputEl').focus().typeWithForce(' '); + cy.get('.react-select__menu-list').should('be.visible'); cy.get('@inputEl').typeWithForce('{downarrow}{downarrow}'); cy.get('#displayLanguage').within(($el) => { cy.wrap($el).findByRole('log').should('have.attr', 'aria-live', 'assertive').as('ariaEl'); @@ -276,7 +283,7 @@ describe('Verify Accessibility Support in different sections in Settings and Pro // * Check Tab behavior in MFA section cy.get('#mfaEdit').click(); cy.get('#passwordEdit').focus().tab({shift: true}).tab().tab(); - cy.get('.setting-list button.btn').should('have.class', 'a11y--active a11y--focused').tab(); + cy.get('.setting-list').findByRole('button', {name: /Add|Remove/i}).should('have.class', 'a11y--active a11y--focused').tab(); cy.get('#cancelSetting').should('have.class', 'a11y--active a11y--focused'); // * Check Tab behavior in Sign-In Method if its available @@ -284,7 +291,7 @@ describe('Verify Accessibility Support in different sections in Settings and Pro if (el.find('#signinEdit').length) { cy.get('#signinEdit').click(); cy.get('#mfaEdit').focus().tab({shift: true}).tab().tab(); - cy.get('.setting-list a.btn').should('have.class', 'a11y--active a11y--focused').tab(); + cy.get('.setting-list').findByRole('link').should('have.class', 'a11y--active a11y--focused').tab(); cy.get('#cancelSetting').should('have.class', 'a11y--active a11y--focused'); } }); diff --git a/e2e-tests/cypress/tests/integration/channels/collapsed_reply_threads/replies_spec.ts b/e2e-tests/cypress/tests/integration/channels/collapsed_reply_threads/replies_spec.ts index 30562d1c6e3..a6fcb71c833 100644 --- a/e2e-tests/cypress/tests/integration/channels/collapsed_reply_threads/replies_spec.ts +++ b/e2e-tests/cypress/tests/integration/channels/collapsed_reply_threads/replies_spec.ts @@ -145,7 +145,7 @@ describe('Collapsed Reply Threads', () => { cy.uiGetPostThreadFooter(postForAvatar.id).find('.Avatars').find('button').first().click(); // * Profile popover should be visible and close on ESC - cy.get('div.user-profile-popover').first().should('be.visible').find('button.btn-primary.btn-sm').type('{esc}'); + cy.get('div.user-profile-popover').first().should('be.visible').find('.user-popover__bottom-row-container button').type('{esc}'); // # Visit global threads cy.uiClickSidebarItem('threads'); @@ -153,8 +153,8 @@ describe('Collapsed Reply Threads', () => { // * Find the first avatar and click it cy.get('div.ThreadItem').find('.activity').find('.Avatars').find('button').first().click(); - // * Profile popover should be visible and close on ESC - cy.get('div.user-profile-popover').first().should('be.visible').find('button.btn-primary.btn-sm'); + // * Profile popover should be visible + cy.get('div.user-profile-popover').first().should('be.visible').find('.user-popover__bottom-row-container button'); }); it('MM-T4143 Emoji reaction - type +:+1:', () => { diff --git a/e2e-tests/cypress/tests/integration/channels/emoji/custom_emoji_1_1_spec.ts b/e2e-tests/cypress/tests/integration/channels/emoji/custom_emoji_1_1_spec.ts index 9e81ff19cce..aa5da966413 100644 --- a/e2e-tests/cypress/tests/integration/channels/emoji/custom_emoji_1_1_spec.ts +++ b/e2e-tests/cypress/tests/integration/channels/emoji/custom_emoji_1_1_spec.ts @@ -55,7 +55,7 @@ describe('Custom emojis', () => { cy.uiOpenCustomEmoji(); // # Click on add custom emoji - cy.findByRole('button', {name: 'Add Custom Emoji'}).should('be.visible').click(); + cy.findByRole('link', {name: 'Add Custom Emoji'}).should('be.visible').click(); // # Type emoji name cy.get('#name').type(customEmojiWithColons); @@ -122,5 +122,5 @@ function saveCustomEmoji(teamName: string) { // * Should return to list of custom emojis cy.url().should('include', `${teamName}/emoji`); - cy.findByRole('button', {name: 'Add Custom Emoji'}).should('be.visible'); + cy.findByRole('link', {name: 'Add Custom Emoji'}).should('be.visible'); } diff --git a/e2e-tests/cypress/tests/integration/channels/emoji/custom_emoji_1_spec.ts b/e2e-tests/cypress/tests/integration/channels/emoji/custom_emoji_1_spec.ts index 5a777268906..d85e450e30c 100644 --- a/e2e-tests/cypress/tests/integration/channels/emoji/custom_emoji_1_spec.ts +++ b/e2e-tests/cypress/tests/integration/channels/emoji/custom_emoji_1_spec.ts @@ -105,7 +105,7 @@ describe('Custom emojis', () => { cy.uiOpenCustomEmoji(); // # Click on add custom emoji - cy.findByRole('button', {name: 'Add Custom Emoji'}).should('be.visible').click(); + cy.findByRole('link', {name: 'Add Custom Emoji'}).should('be.visible').click(); // # Type emoji name cy.get('#name').should('be.visible').type(customEmojiWithColons); @@ -180,5 +180,5 @@ function saveCustomEmoji(teamName: string) { // * Should return to list of custom emojis cy.url().should('include', `${teamName}/emoji`); - cy.findByRole('button', {name: 'Add Custom Emoji'}).should('be.visible'); + cy.findByRole('link', {name: 'Add Custom Emoji'}).should('be.visible'); } diff --git a/e2e-tests/cypress/tests/integration/channels/enterprise/guest_accounts/guest_invitation_ui_more_spec.ts b/e2e-tests/cypress/tests/integration/channels/enterprise/guest_accounts/guest_invitation_ui_more_spec.ts index 5b63917bc26..b97c12df8db 100644 --- a/e2e-tests/cypress/tests/integration/channels/enterprise/guest_accounts/guest_invitation_ui_more_spec.ts +++ b/e2e-tests/cypress/tests/integration/channels/enterprise/guest_accounts/guest_invitation_ui_more_spec.ts @@ -136,7 +136,7 @@ describe('Guest Account - Guest User Invitation Flow', () => { // * Update email outside whitelisted domain and verify error message cy.get('#resetEmailModal').should('be.visible').within(() => { cy.get('input[type="email"]').type(email); - cy.get('button.btn-primary.confirm').click(); + cy.get('button.GenericModal__button.confirm').click(); cy.get('.error').should('be.visible').and('have.text', 'The email you provided does not belong to an accepted domain for guest accounts. Please contact your administrator or sign up with a different email.'); cy.get('.close').click(); }); diff --git a/e2e-tests/cypress/tests/integration/channels/enterprise/guest_accounts/system_console_manage_guest_spec.ts b/e2e-tests/cypress/tests/integration/channels/enterprise/guest_accounts/system_console_manage_guest_spec.ts index 56122570081..72fabcca7d7 100644 --- a/e2e-tests/cypress/tests/integration/channels/enterprise/guest_accounts/system_console_manage_guest_spec.ts +++ b/e2e-tests/cypress/tests/integration/channels/enterprise/guest_accounts/system_console_manage_guest_spec.ts @@ -87,7 +87,7 @@ describe('Guest Account - Verify Manage Guest Users', () => { const email = `temp-${getRandomId()}@mattermost.com`; cy.get('#resetEmailModal').should('be.visible').within(() => { cy.get('input[type="email"]').type(email); - cy.get('button.btn-primary.confirm').click(); + cy.get('button.GenericModal__button.confirm').click(); }); // * Verify if Guest's email was updated diff --git a/e2e-tests/cypress/tests/integration/channels/enterprise/system_console/archived_channels_spec.js b/e2e-tests/cypress/tests/integration/channels/enterprise/system_console/archived_channels_spec.js index 676d387d48b..6b469906ea1 100644 --- a/e2e-tests/cypress/tests/integration/channels/enterprise/system_console/archived_channels_spec.js +++ b/e2e-tests/cypress/tests/integration/channels/enterprise/system_console/archived_channels_spec.js @@ -62,7 +62,7 @@ describe('Archived channels', () => { cy.visit(`/admin_console/user_management/channels/${testChannel.id}`); // * Verify the Unarchive Channel button is visible - cy.get('button.btn-secondary', {timeout: TIMEOUTS.TWO_SEC}).should('have.text', 'Unarchive Channel').should('be.visible').should('be.enabled'); + cy.findByRole('button', {name: 'Unarchive Channel', timeout: TIMEOUTS.TWO_SEC}).should('be.visible').should('be.enabled'); // * Verify that only one widget is visible cy.get('div.AdminPanel').should('be.visible').and('have.length', 1); @@ -73,10 +73,10 @@ describe('Archived channels', () => { cy.visit(`/admin_console/user_management/channels/${testChannel.id}`); // # Click Unarchive Channel button - cy.get('button.btn-secondary', {timeout: TIMEOUTS.TWO_SEC}).findAllByText('Unarchive Channel').click(); + cy.findByRole('button', {name: 'Unarchive Channel', timeout: TIMEOUTS.TWO_SEC}).click(); // * Verify the Archive Channel button is visible - cy.get('button.btn-secondary.btn-danger', {timeout: TIMEOUTS.TWO_SEC}).findAllByText('Archive Channel').should('be.visible'); + cy.findByRole('button', {name: 'Archive Channel', timeout: TIMEOUTS.TWO_SEC}).should('be.visible'); // * Verify that the other widget appears cy.get('div.AdminPanel').should('be.visible').should('have.length', 5); diff --git a/e2e-tests/cypress/tests/integration/channels/integrations/custom_slash_commands/slash_commands_spec.js b/e2e-tests/cypress/tests/integration/channels/integrations/custom_slash_commands/slash_commands_spec.js index e73d5e317c3..f21bc2a060c 100644 --- a/e2e-tests/cypress/tests/integration/channels/integrations/custom_slash_commands/slash_commands_spec.js +++ b/e2e-tests/cypress/tests/integration/channels/integrations/custom_slash_commands/slash_commands_spec.js @@ -155,7 +155,7 @@ describe('Slash commands page', () => { cy.get('#url').clear().type('http://mattermost.com'); // # Click on Cancel - cy.get('a').contains('Cancel').click(); + cy.findByRole('link', {name: 'Cancel'}).click(); // # Click on edit again cy.get('a[href*="/edit"]').click(); diff --git a/e2e-tests/cypress/tests/integration/channels/interactive_dialog/file_upload_spec.js b/e2e-tests/cypress/tests/integration/channels/interactive_dialog/file_upload_spec.js index ae2704f647f..d9fe2af9a4a 100644 --- a/e2e-tests/cypress/tests/integration/channels/interactive_dialog/file_upload_spec.js +++ b/e2e-tests/cypress/tests/integration/channels/interactive_dialog/file_upload_spec.js @@ -76,7 +76,7 @@ describe('Interactive Dialog - File Upload', () => { cy.get('label').should('be.visible').and('contain', singleElement.display_name); // * Verify "Choose File" button for allow_multiple=false - cy.get('button.btn-tertiary').should('be.visible').and('have.text', 'Choose File'); + cy.findByRole('button', {name: 'Choose File'}).should('be.visible'); // * Verify placeholder / help text is visible before any upload cy.get('.help-text').should('be.visible'); @@ -87,7 +87,7 @@ describe('Interactive Dialog - File Upload', () => { cy.get('label').should('be.visible').and('contain', multipleElement.display_name); // * Verify "Choose Files" button for allow_multiple=true - cy.get('button.btn-tertiary').should('be.visible').and('have.text', 'Choose Files'); + cy.findByRole('button', {name: 'Choose Files'}).should('be.visible'); // * Verify placeholder / help text is visible before any upload cy.get('.help-text').should('be.visible'); diff --git a/e2e-tests/cypress/tests/integration/channels/message_forwarding/forward_message_from_dm_spec.js b/e2e-tests/cypress/tests/integration/channels/message_forwarding/forward_message_from_dm_spec.js index 6f386a80a25..035a8c2b5d9 100644 --- a/e2e-tests/cypress/tests/integration/channels/message_forwarding/forward_message_from_dm_spec.js +++ b/e2e-tests/cypress/tests/integration/channels/message_forwarding/forward_message_from_dm_spec.js @@ -191,8 +191,8 @@ describe('Forward Message', () => { // * Assert channel select is not existent cy.get('.forward-post__select').should('not.exist'); - // * Assert if button is enabled - cy.get('.btn-tertiary').should('not.be.disabled'); + // * Assert if cancel button is enabled + cy.findByRole('button', {name: 'Cancel'}).should('not.be.disabled'); // * Assert Notification is shown cy.findByTestId('notification_forward_post').should('be.visible').should('contain.text', `This message is from a private conversation and can only be shared with ${dmChannel.display_name}`); @@ -206,8 +206,8 @@ describe('Forward Message', () => { } if (cancel) { - // * Assert if button is active - cy.get('.btn-tertiary').should('not.be.disabled').type('{esc}', {force: true}); + // * Assert if cancel button is active, then dismiss with escape + cy.findByRole('button', {name: 'Cancel'}).should('not.be.disabled').type('{esc}', {force: true}); } else { // * Assert if button is active cy.get('.GenericModal__button.confirm').should('not.be.disabled').type('{enter}', {force: true}); diff --git a/e2e-tests/cypress/tests/integration/channels/message_forwarding/forward_message_from_private_channel_spec.js b/e2e-tests/cypress/tests/integration/channels/message_forwarding/forward_message_from_private_channel_spec.js index 5fa8cb785fb..fae10016ed0 100644 --- a/e2e-tests/cypress/tests/integration/channels/message_forwarding/forward_message_from_private_channel_spec.js +++ b/e2e-tests/cypress/tests/integration/channels/message_forwarding/forward_message_from_private_channel_spec.js @@ -188,8 +188,8 @@ describe('Forward Message', () => { cy.findByTestId('notification_forward_post').should('be.visible').should('contain.text', `This message is from a private channel and can only be shared with ~${privateChannel.display_name}`); if (cancel) { - // * Assert if button is active - cy.get('.btn-tertiary').should('not.be.disabled').click(); + // * Assert if cancel button is active + cy.findByRole('button', {name: 'Cancel'}).should('not.be.disabled').click(); } else { // * Assert if button is active cy.get('.GenericModal__button.confirm').should('not.be.disabled').click(); diff --git a/e2e-tests/cypress/tests/integration/channels/multi_team_and_dm/existing_channel_name_spec.js b/e2e-tests/cypress/tests/integration/channels/multi_team_and_dm/existing_channel_name_spec.js index c075ca6347e..9b4f442bed8 100644 --- a/e2e-tests/cypress/tests/integration/channels/multi_team_and_dm/existing_channel_name_spec.js +++ b/e2e-tests/cypress/tests/integration/channels/multi_team_and_dm/existing_channel_name_spec.js @@ -62,7 +62,7 @@ describe('Channel', () => { cy.get('.url-input-error').should('not.exist'); // * 'Create Channel' button should be enabled - cy.findByText('Create channel').should('not.have.class', 'disabled'); + cy.findByRole('button', {name: 'Create channel'}).should('not.be.disabled'); // # Click on Cancel button to move out of New Channel Modal cy.findByText('Cancel').click(); @@ -92,7 +92,7 @@ function verifyExistingChannelError(newChannelName, makePrivate = false) { cy.get('.url-input-error').contains('A channel with that URL already exists'); // * 'Create Channel' button should be disabled - cy.findByText('Create channel').should('have.class', 'disabled'); + cy.findByRole('button', {name: 'Create channel'}).should('be.disabled'); } /** diff --git a/e2e-tests/cypress/tests/integration/channels/system_console/user_management/users_spec.js b/e2e-tests/cypress/tests/integration/channels/system_console/user_management/users_spec.js index fff50a3a33a..673137e1577 100644 --- a/e2e-tests/cypress/tests/integration/channels/system_console/user_management/users_spec.js +++ b/e2e-tests/cypress/tests/integration/channels/system_console/user_management/users_spec.js @@ -70,7 +70,7 @@ describe('System Console > User Management > Users', () => { // # Type new password and submit. cy.get('input[type=password]').type('new' + testUser.password); - cy.get('button.btn-primary.confirm').should('contain', 'Reset').click().wait(TIMEOUTS.HALF_SEC); + cy.get('button.GenericModal__button.confirm').should('contain', 'Reset').click().wait(TIMEOUTS.HALF_SEC); // # Log out. cy.apiLogout(); @@ -96,7 +96,7 @@ describe('System Console > User Management > Users', () => { cy.get('input[type=password]').eq(1).type('new' + otherAdmin.password); // # Click the 'Cancel' button. - cy.get('.modal-footer > .btn-tertiary').should('contain', 'Cancel').click().wait(TIMEOUTS.HALF_SEC); + cy.get('.modal-footer').findByRole('button', {name: 'Cancel'}).click().wait(TIMEOUTS.HALF_SEC); // # Log out. cy.apiLogout(); @@ -113,7 +113,7 @@ describe('System Console > User Management > Users', () => { cy.get('input[type=password]').eq(1).type('new' + otherAdmin.password); // # Click the 'Reset' button. - cy.get('button.btn-primary.confirm').should('contain', 'Reset').click().wait(TIMEOUTS.HALF_SEC); + cy.get('button.GenericModal__button.confirm').should('contain', 'Reset').click().wait(TIMEOUTS.HALF_SEC); // * Verify the appropriate error is returned (current password error shows in modal header area). cy.get('.genericModalError .error').should('be.visible'). @@ -128,7 +128,7 @@ describe('System Console > User Management > Users', () => { cy.get('input[type=password]').eq(1).type('new'); // # Click the 'Reset' button. - cy.get('button.btn-primary.confirm').should('contain', 'Reset').click().wait(TIMEOUTS.HALF_SEC); + cy.get('button.GenericModal__button.confirm').should('contain', 'Reset').click().wait(TIMEOUTS.HALF_SEC); // * Verify the appropriate error is returned (new password error shows under the input). cy.get('.Input___error').should('be.visible').and('contain', 'characters long'); @@ -138,7 +138,7 @@ describe('System Console > User Management > Users', () => { searchUserAndOpenResetPassword(otherAdmin.username, otherAdmin.email); // # Click the 'Reset' button. - cy.get('button.btn-primary.confirm').should('contain', 'Reset').click().wait(TIMEOUTS.HALF_SEC); + cy.get('button.GenericModal__button.confirm').should('contain', 'Reset').click().wait(TIMEOUTS.HALF_SEC); // * Verify the appropriate error is returned (current password missing). cy.get('.genericModalError .error').should('be.visible'). @@ -148,7 +148,7 @@ describe('System Console > User Management > Users', () => { cy.get('input[type=password]').eq(0).type(otherAdmin.password); // # Click the 'Reset' button. - cy.get('button.btn-primary.confirm').should('contain', 'Reset').click().wait(TIMEOUTS.HALF_SEC); + cy.get('button.GenericModal__button.confirm').should('contain', 'Reset').click().wait(TIMEOUTS.HALF_SEC); // * Verify the appropriate error is returned (new password error shows under the input). cy.get('.Input___error').should('be.visible').and('contain', 'characters long'); @@ -162,7 +162,7 @@ describe('System Console > User Management > Users', () => { cy.get('input[type=password]').eq(1).type('new' + otherAdmin.password); // # Click the 'Reset' button. - cy.get('button.btn-primary.confirm').should('contain', 'Reset').click().wait(TIMEOUTS.HALF_SEC); + cy.get('button.GenericModal__button.confirm').should('contain', 'Reset').click().wait(TIMEOUTS.HALF_SEC); // # Log out. cy.apiLogout(); diff --git a/e2e-tests/cypress/tests/integration/channels/system_console/user_management_spec.js b/e2e-tests/cypress/tests/integration/channels/system_console/user_management_spec.js index 5dbecfefac5..8dc6bd2ca94 100644 --- a/e2e-tests/cypress/tests/integration/channels/system_console/user_management_spec.js +++ b/e2e-tests/cypress/tests/integration/channels/system_console/user_management_spec.js @@ -194,7 +194,7 @@ describe('User Management', () => { // # Set new password. cy.get('input[type=password]').type('new' + testUser.password); - cy.get('button.btn-primary.confirm').should('contain', 'Reset').click().wait(TIMEOUTS.HALF_SEC); + cy.get('button.GenericModal__button.confirm').should('contain', 'Reset').click().wait(TIMEOUTS.HALF_SEC); // * Verify Update email option is visible. cy.get('#systemUsersTable-cell-0_actionsColumn').click().wait(TIMEOUTS.HALF_SEC); @@ -269,7 +269,7 @@ describe('User Management', () => { } // # Click the "Update" button. - cy.get('button.btn-primary.confirm').click(); + cy.get('button.GenericModal__button.confirm').click(); // * Check for the error messages, if any. if (errorMsg.length > 0) { diff --git a/e2e-tests/playwright/lib/src/ui/components/channels/delete_post_confirmation_dialog.ts b/e2e-tests/playwright/lib/src/ui/components/channels/delete_post_confirmation_dialog.ts index 5f32a3f3178..a5a603c8681 100644 --- a/e2e-tests/playwright/lib/src/ui/components/channels/delete_post_confirmation_dialog.ts +++ b/e2e-tests/playwright/lib/src/ui/components/channels/delete_post_confirmation_dialog.ts @@ -13,7 +13,7 @@ export default class DeletePostConfirmationDialog { constructor(container: Locator) { this.container = container; - this.cancelButton = container.locator('button.btn.btn-tertiary'); + this.cancelButton = container.getByRole('button', {name: 'Cancel'}); this.confirmButton = container.locator('button#deletePostModalButton'); } diff --git a/e2e-tests/playwright/lib/src/ui/components/channels/marketplace_modal.ts b/e2e-tests/playwright/lib/src/ui/components/channels/marketplace_modal.ts index 85b90cc51bc..d58b4b175c2 100644 --- a/e2e-tests/playwright/lib/src/ui/components/channels/marketplace_modal.ts +++ b/e2e-tests/playwright/lib/src/ui/components/channels/marketplace_modal.ts @@ -56,7 +56,7 @@ export default class MarketplaceModal { } await installButton.click(); - await expect(this.pluginRow(pluginId).getByRole('button', {name: 'Configure'})).toBeVisible({ + await expect(this.pluginRow(pluginId).getByRole('link', {name: 'Configure'})).toBeVisible({ timeout: duration.one_min, }); @@ -67,6 +67,6 @@ export default class MarketplaceModal { * Clicks "Configure" for the given plugin, which navigates to its System Console settings page. */ async clickConfigure(pluginId: string) { - await this.pluginRow(pluginId).getByRole('button', {name: 'Configure'}).click(); + await this.pluginRow(pluginId).getByRole('link', {name: 'Configure'}).click(); } } diff --git a/e2e-tests/playwright/lib/src/ui/components/channels/restore_post_confirmation_dialog.ts b/e2e-tests/playwright/lib/src/ui/components/channels/restore_post_confirmation_dialog.ts index 9e1ad0ad71d..f5f88728833 100644 --- a/e2e-tests/playwright/lib/src/ui/components/channels/restore_post_confirmation_dialog.ts +++ b/e2e-tests/playwright/lib/src/ui/components/channels/restore_post_confirmation_dialog.ts @@ -13,8 +13,8 @@ export default class RestorePostConfirmationDialog { constructor(container: Locator) { this.container = container; - this.cancelButton = container.locator('button.btn.btn-tertiary'); - this.confirmButton = container.locator('button.GenericModal__button.btn.btn-primary.confirm'); + this.cancelButton = container.getByRole('button', {name: 'Cancel'}); + this.confirmButton = container.locator('button.GenericModal__button.confirm'); } async toBeVisible() { diff --git a/e2e-tests/playwright/specs/accessibility/channels/settings_dialog/notifications.spec.ts b/e2e-tests/playwright/specs/accessibility/channels/settings_dialog/notifications.spec.ts index 4c420d9baf2..e80e1b17003 100644 --- a/e2e-tests/playwright/specs/accessibility/channels/settings_dialog/notifications.spec.ts +++ b/e2e-tests/playwright/specs/accessibility/channels/settings_dialog/notifications.spec.ts @@ -104,9 +104,10 @@ test( - heading "Notifications" [level=3] - link "Learn more about notifications": - /url: https://mattermost.com/pl/about-notifications?utm_source=mattermost&utm_medium=in-product&utm_content=user_settings_notifications&uid=${user.id}&sid=${clientConfig.DiagnosticId}&edition=enterprise&server_version=${clientConfig.Version} - - img - heading "Desktop and mobile notifications Permission required" [level=4]: + - text: "" - img + - text: "" - button "Desktop and mobile notifications Permission required Edit" - text: Mentions, direct messages, and group messages - heading "Desktop notification sounds" [level=4] @@ -114,6 +115,7 @@ test( - text: "\\"Bing\\" for messages" - heading "Email notifications" [level=4] - button "Email notifications Edit" + - text: "On" - heading "Auto-follow threads on channel-wide mentions" [level=4] - button "Auto-follow threads on channel-wide mentions Edit" - text: "On" @@ -122,6 +124,7 @@ test( - text: "\\"@${user.username}\\", \\"@channel\\", \\"@all\\", \\"@here\\"" - heading "Keywords that get highlighted (without notifications)" [level=4] - button "Keywords that get highlighted (without notifications) Edit" + - text: None - heading "Troubleshooting notifications" [level=4] - text: Not receiving notifications? Start by sending a test notification to all your devices to check if they’re working as expected. If issues persist, explore ways to solve them with troubleshooting steps. - button "Send a test notification" diff --git a/webapp/AGENTS.md b/webapp/AGENTS.md index f3fdbcaa4a8..c65edc4c49a 100644 --- a/webapp/AGENTS.md +++ b/webapp/AGENTS.md @@ -12,6 +12,7 @@ Follow `webapp/STYLE_GUIDE.md` for canonical style, accessibility, and testing s - **New UI**: prefer `@mattermost/compass-ui` when a published (on npm) component exists. Import via subpaths: `import {Button} from '@mattermost/compass-ui/components/button';` Do not use the root barrel. Do not recreate Compass primitives. +- **Button**: use Compass UI for text-based button UI. Do not use `@mattermost/shared` `Button` (removed); `buttonClassNames` from `@mattermost/shared/components/button` remains for menu triggers and similar class-only cases. Sizes: `x-small` / `small` / `medium` / `large`. Use `destructive` (boolean) and `appearance="inverted"` for those styles. For link-styled CTAs, use `asChild` with a single `` or router `Link` child instead of nesting a button. - **Do not mass-migrate** existing UI components to Compass. Only switch when building new UI or when the task is an intentional migration of the code you are already changing. - **`@mattermost/compass-proto`**: prototyping package not published to npm (shells, call composites, hardcoded menu recipes, proto `WithTooltip`). Not for Mattermost webapp product code — do not add the dependency or import from it unless explicitly adopting that package. Prefer existing webapp / shared / MUI stacks for those surfaces. - **Exceptions (keep current stacks)**: icons → `@mattermost/compass-icons`; emoji → `Emoji` (`@mattermost/shared`); modals → existing shared / `GenericModal`; menus → existing MUI menus. Do not switch Modal/Menu to compass-ui yet. diff --git a/webapp/CLAUDE.OPTIONAL.md b/webapp/CLAUDE.OPTIONAL.md index c4cbeca2b01..bbfbfd742ee 100644 --- a/webapp/CLAUDE.OPTIONAL.md +++ b/webapp/CLAUDE.OPTIONAL.md @@ -67,7 +67,7 @@ import Client4 from '../platform/client/src/client4.ts'; - **React Router 5.3**: Client-side routing - **React Intl**: Internationalization - **Floating UI**: Tooltips and popovers (prefer `WithTooltip` from `@mattermost/shared/components/tooltip`) -- **@mattermost/compass-ui**: Published Compass UI components (prefer `Button` from `@mattermost/compass-ui/components/button` over hand-rolled or shared Button) +- **@mattermost/compass-ui**: Published Compass UI components (prefer `Button` from `@mattermost/compass-ui/components/button` over hand-rolled or shared Button; shared `Button` is removed, `buttonClassNames` remains for class-only cases) - **@mattermost/shared**: Shared components and utilities (`WithTooltip`, `Emoji`, etc.) — use where `webapp/AGENTS.md` specifies them - **@mattermost/compass-icons**: Icon library (prefer over font-awesome) - **Monaco Editor**: Code editor integration diff --git a/webapp/STYLE_GUIDE.md b/webapp/STYLE_GUIDE.md index efe3e276c34..254ff6d5649 100644 --- a/webapp/STYLE_GUIDE.md +++ b/webapp/STYLE_GUIDE.md @@ -102,7 +102,7 @@ The following guidelines should be applied to both new and existing code. Howeve - **React Bootstrap**: Avoid using React Bootstrap directly. - **Modals**: Use `GenericModal` from `@mattermost/components` instead of React Bootstrap's `Modal`. - - **Buttons**: Use `Button` from `@mattermost/compass-ui/components/button` instead of React Bootstrap's `Button` or raw Bootstrap like ` @@ -160,22 +190,52 @@ exports[`components/GetLinkModal should have called onHide when close button is class="modal-footer" > @@ -257,22 +317,52 @@ exports[`components/GetLinkModal should match snapshot when all props is set 1`] class="modal-footer" > @@ -349,22 +439,52 @@ exports[`components/GetLinkModal should match snapshot when helpText is not set class="modal-footer" > diff --git a/webapp/channels/src/components/__snapshots__/list_modal.test.tsx.snap b/webapp/channels/src/components/__snapshots__/list_modal.test.tsx.snap index 15bed1551ec..0163a068a9b 100644 --- a/webapp/channels/src/components/__snapshots__/list_modal.test.tsx.snap +++ b/webapp/channels/src/components/__snapshots__/list_modal.test.tsx.snap @@ -175,9 +175,14 @@ exports[`components/ListModal should match snapshot with title bar button 1`] =

diff --git a/webapp/channels/src/components/__snapshots__/save_button.test.tsx.snap b/webapp/channels/src/components/__snapshots__/save_button.test.tsx.snap index 42afb762be5..61006aafbec 100644 --- a/webapp/channels/src/components/__snapshots__/save_button.test.tsx.snap +++ b/webapp/channels/src/components/__snapshots__/save_button.test.tsx.snap @@ -3,12 +3,14 @@ exports[`components/SaveButton should match snapshot, extraClasses 1`] = `
@@ -18,12 +20,14 @@ exports[`components/SaveButton should match snapshot, extraClasses 1`] = ` exports[`components/SaveButton should match snapshot, on defaultMessage 1`] = `
@@ -33,12 +37,14 @@ exports[`components/SaveButton should match snapshot, on defaultMessage 1`] = ` exports[`components/SaveButton should match snapshot, on defaultMessage 2`] = `
@@ -48,21 +54,26 @@ exports[`components/SaveButton should match snapshot, on defaultMessage 2`] = ` exports[`components/SaveButton should match snapshot, on savingMessage 1`] = `
@@ -72,21 +83,26 @@ exports[`components/SaveButton should match snapshot, on savingMessage 1`] = ` exports[`components/SaveButton should match snapshot, on savingMessage 2`] = `
diff --git a/webapp/channels/src/components/__snapshots__/setting_item_max.test.tsx.snap b/webapp/channels/src/components/__snapshots__/setting_item_max.test.tsx.snap index d8ca91faef2..b0e51d6c14c 100644 --- a/webapp/channels/src/components/__snapshots__/setting_item_max.test.tsx.snap +++ b/webapp/channels/src/components/__snapshots__/setting_item_max.test.tsx.snap @@ -3,7 +3,7 @@ exports[`components/SettingItemMax should match snapshot 1`] = `
@@ -57,7 +68,7 @@ exports[`components/SettingItemMax should match snapshot 1`] = ` exports[`components/SettingItemMax should match snapshot, on clientError 1`] = `
@@ -111,7 +133,7 @@ exports[`components/SettingItemMax should match snapshot, on clientError 1`] = ` exports[`components/SettingItemMax should match snapshot, on serverError 1`] = `

- - + + + @@ -215,23 +248,34 @@ exports[`components/SettingItemMax should match snapshot, with new saveTextButto
- - + + +
@@ -269,13 +313,22 @@ exports[`components/SettingItemMax should match snapshot, without submit 1`] = `
- + +
diff --git a/webapp/channels/src/components/__snapshots__/setting_picture.test.tsx.snap b/webapp/channels/src/components/__snapshots__/setting_picture.test.tsx.snap index 8d3751ae01a..251ad92582c 100644 --- a/webapp/channels/src/components/__snapshots__/setting_picture.test.tsx.snap +++ b/webapp/channels/src/components/__snapshots__/setting_picture.test.tsx.snap @@ -39,7 +39,9 @@ exports[`components/SettingItemMin should match snapshot with active Save button class="setting-list-item" >
- +
- - + +
@@ -107,7 +124,9 @@ exports[`components/SettingItemMin should match snapshot with removeSrc state ac class="setting-list-item" >
- +
- - + +
@@ -185,7 +219,9 @@ exports[`components/SettingItemMin should match snapshot, on loading picture 1`] class="setting-list-item" >
- +
- - + +
@@ -283,7 +335,9 @@ exports[`components/SettingItemMin should match snapshot, profile picture on fil class="setting-list-item" >
- +
- - + +
@@ -362,7 +431,9 @@ exports[`components/SettingItemMin should match snapshot, profile picture on sou class="setting-list-item" >
- +
- - + +
@@ -448,7 +534,9 @@ exports[`components/SettingItemMin should match snapshot, team icon on file 1`] class="setting-list-item" >
- +
- - + +
@@ -551,7 +654,9 @@ exports[`components/SettingItemMin should match snapshot, team icon on source 1` class="setting-list-item" >
- +
- - + +
@@ -654,7 +774,9 @@ exports[`components/SettingItemMin should match snapshot, user icon on source 1` class="setting-list-item" >
- +
- - + +
diff --git a/webapp/channels/src/components/__snapshots__/spinner_button.test.tsx.snap b/webapp/channels/src/components/__snapshots__/spinner_button.test.tsx.snap index dc40f38b5ed..7cb0c51b1a4 100644 --- a/webapp/channels/src/components/__snapshots__/spinner_button.test.tsx.snap +++ b/webapp/channels/src/components/__snapshots__/spinner_button.test.tsx.snap @@ -3,14 +3,19 @@ exports[`components/SpinnerButton should match snapshot with children 1`] = `
`; @@ -18,9 +23,14 @@ exports[`components/SpinnerButton should match snapshot with children 1`] = ` exports[`components/SpinnerButton should match snapshot with required props 1`] = `
`; @@ -28,18 +38,24 @@ exports[`components/SpinnerButton should match snapshot with required props 1`] exports[`components/SpinnerButton should match snapshot with spinning 1`] = `
diff --git a/webapp/channels/src/components/actions_menu/actions_menu_empty_popover.tsx b/webapp/channels/src/components/actions_menu/actions_menu_empty_popover.tsx index b3213793206..4f7d034462c 100644 --- a/webapp/channels/src/components/actions_menu/actions_menu_empty_popover.tsx +++ b/webapp/channels/src/components/actions_menu/actions_menu_empty_popover.tsx @@ -4,7 +4,7 @@ import React from 'react'; import {FormattedMessage} from 'react-intl'; -import {Button} from '@mattermost/shared/components/button'; +import {Button} from '@mattermost/compass-ui/components/button'; import {Permissions} from 'mattermost-redux/constants'; @@ -57,7 +57,7 @@ export default function ActionsMenuEmptyPopover({
@@ -85,9 +90,14 @@ exports[`components/activity_log_modal/ActivityLog should match snapshot with mo class="activity-log__action" > diff --git a/webapp/channels/src/components/activity_log_modal/components/activity_log.tsx b/webapp/channels/src/components/activity_log_modal/components/activity_log.tsx index bde15f9390f..2d08103d2bd 100644 --- a/webapp/channels/src/components/activity_log_modal/components/activity_log.tsx +++ b/webapp/channels/src/components/activity_log_modal/components/activity_log.tsx @@ -5,7 +5,7 @@ import React, {type JSX} from 'react'; import type {MessageDescriptor} from 'react-intl'; import {FormattedDate, FormattedMessage, FormattedTime, defineMessages} from 'react-intl'; -import {Button} from '@mattermost/shared/components/button'; +import {Button} from '@mattermost/compass-ui/components/button'; import type {Session} from '@mattermost/types/sessions'; import {General} from 'mattermost-redux/constants'; diff --git a/webapp/channels/src/components/add_groups_to_channel_modal/__snapshots__/add_groups_to_channel_modal.test.tsx.snap b/webapp/channels/src/components/add_groups_to_channel_modal/__snapshots__/add_groups_to_channel_modal.test.tsx.snap index 59e4424b2ec..bbc15205888 100644 --- a/webapp/channels/src/components/add_groups_to_channel_modal/__snapshots__/add_groups_to_channel_modal.test.tsx.snap +++ b/webapp/channels/src/components/add_groups_to_channel_modal/__snapshots__/add_groups_to_channel_modal.test.tsx.snap @@ -123,12 +123,14 @@ exports[`components/AddGroupsToChannelModal should match snapshot 1`] = ` diff --git a/webapp/channels/src/components/add_groups_to_team_modal/__snapshots__/add_groups_to_team_modal.test.tsx.snap b/webapp/channels/src/components/add_groups_to_team_modal/__snapshots__/add_groups_to_team_modal.test.tsx.snap index aa32d624df3..3054c9a63f4 100644 --- a/webapp/channels/src/components/add_groups_to_team_modal/__snapshots__/add_groups_to_team_modal.test.tsx.snap +++ b/webapp/channels/src/components/add_groups_to_team_modal/__snapshots__/add_groups_to_team_modal.test.tsx.snap @@ -123,12 +123,14 @@ exports[`components/AddGroupsToTeamModal should match snapshot 1`] = ` diff --git a/webapp/channels/src/components/add_user_to_channel_modal/__snapshots__/add_user_to_channel_modal.test.tsx.snap b/webapp/channels/src/components/add_user_to_channel_modal/__snapshots__/add_user_to_channel_modal.test.tsx.snap index 1f8835a0c86..74f5a479654 100644 --- a/webapp/channels/src/components/add_user_to_channel_modal/__snapshots__/add_user_to_channel_modal.test.tsx.snap +++ b/webapp/channels/src/components/add_user_to_channel_modal/__snapshots__/add_user_to_channel_modal.test.tsx.snap @@ -72,18 +72,26 @@ exports[`components/AddUserToChannelModal should match snapshot 1`] = ` class="modal-footer" > diff --git a/webapp/channels/src/components/add_user_to_channel_modal/add_user_to_channel_modal.tsx b/webapp/channels/src/components/add_user_to_channel_modal/add_user_to_channel_modal.tsx index d0acc0dc67d..e098888a102 100644 --- a/webapp/channels/src/components/add_user_to_channel_modal/add_user_to_channel_modal.tsx +++ b/webapp/channels/src/components/add_user_to_channel_modal/add_user_to_channel_modal.tsx @@ -6,7 +6,7 @@ import type {ChangeEvent, FormEvent} from 'react'; import {Modal} from 'react-bootstrap'; import {FormattedMessage} from 'react-intl'; -import {Button} from '@mattermost/shared/components/button'; +import {Button} from '@mattermost/compass-ui/components/button'; import type {Channel, ChannelMembership} from '@mattermost/types/channels'; import type {UserProfile} from '@mattermost/types/users'; import type {RelationOneToOne} from '@mattermost/types/utilities'; diff --git a/webapp/channels/src/components/add_user_to_group_multiselect/__snapshots__/add_user_to_group_multiselect.test.tsx.snap b/webapp/channels/src/components/add_user_to_group_multiselect/__snapshots__/add_user_to_group_multiselect.test.tsx.snap index 5db533d13c3..38c2c58cb44 100644 --- a/webapp/channels/src/components/add_user_to_group_multiselect/__snapshots__/add_user_to_group_multiselect.test.tsx.snap +++ b/webapp/channels/src/components/add_user_to_group_multiselect/__snapshots__/add_user_to_group_multiselect.test.tsx.snap @@ -81,13 +81,15 @@ exports[`component/add_user_to_group_multiselect should match snapshot with diff class="multi-select__footer modal-footer" > @@ -176,13 +178,15 @@ exports[`component/add_user_to_group_multiselect should match snapshot with prof class="multi-select__footer modal-footer" > @@ -271,13 +275,15 @@ exports[`component/add_user_to_group_multiselect should match snapshot without a class="multi-select__footer modal-footer" > diff --git a/webapp/channels/src/components/add_users_to_group_modal/__snapshots__/add_users_to_group_modal.test.tsx.snap b/webapp/channels/src/components/add_users_to_group_modal/__snapshots__/add_users_to_group_modal.test.tsx.snap index 16bf0617f19..dbce0590e9c 100644 --- a/webapp/channels/src/components/add_users_to_group_modal/__snapshots__/add_users_to_group_modal.test.tsx.snap +++ b/webapp/channels/src/components/add_users_to_group_modal/__snapshots__/add_users_to_group_modal.test.tsx.snap @@ -158,18 +158,25 @@ exports[`component/add_users_to_group_modal should match snapshot 1`] = ` class="multi-select__footer modal-footer" > diff --git a/webapp/channels/src/components/add_users_to_team_modal/__snapshots__/add_users_to_team_modal.test.tsx.snap b/webapp/channels/src/components/add_users_to_team_modal/__snapshots__/add_users_to_team_modal.test.tsx.snap index 5d7b0d61cd1..9e77ee7bbed 100644 --- a/webapp/channels/src/components/add_users_to_team_modal/__snapshots__/add_users_to_team_modal.test.tsx.snap +++ b/webapp/channels/src/components/add_users_to_team_modal/__snapshots__/add_users_to_team_modal.test.tsx.snap @@ -123,12 +123,14 @@ exports[`components/admin_console/add_users_to_team_modal/AddUsersToTeamModal sh diff --git a/webapp/channels/src/components/admin_console/__snapshots__/cluster_settings.test.tsx.snap b/webapp/channels/src/components/admin_console/__snapshots__/cluster_settings.test.tsx.snap index 30c25c4d98d..f9460314e53 100644 --- a/webapp/channels/src/components/admin_console/__snapshots__/cluster_settings.test.tsx.snap +++ b/webapp/channels/src/components/admin_console/__snapshots__/cluster_settings.test.tsx.snap @@ -469,13 +469,15 @@ exports[`components/ClusterSettings should match snapshot, compression disabled class="admin-console-save" > @@ -957,13 +959,15 @@ exports[`components/ClusterSettings should match snapshot, compression enabled 1 class="admin-console-save" > @@ -1445,13 +1449,15 @@ exports[`components/ClusterSettings should match snapshot, encryption disabled 1 class="admin-console-save" > @@ -1933,13 +1939,15 @@ exports[`components/ClusterSettings should match snapshot, encryption enabled 1` class="admin-console-save" > diff --git a/webapp/channels/src/components/admin_console/__snapshots__/database_settings.test.tsx.snap b/webapp/channels/src/components/admin_console/__snapshots__/database_settings.test.tsx.snap index 8bc20b3ca91..280c7459a2a 100644 --- a/webapp/channels/src/components/admin_console/__snapshots__/database_settings.test.tsx.snap +++ b/webapp/channels/src/components/admin_console/__snapshots__/database_settings.test.tsx.snap @@ -378,10 +378,14 @@ exports[`components/DatabaseSettings should match snapshot 1`] = ` >
diff --git a/webapp/channels/src/components/admin_console/__snapshots__/elasticsearch_settings.test.tsx.snap b/webapp/channels/src/components/admin_console/__snapshots__/elasticsearch_settings.test.tsx.snap index 633488a8aa4..4305dfb124e 100644 --- a/webapp/channels/src/components/admin_console/__snapshots__/elasticsearch_settings.test.tsx.snap +++ b/webapp/channels/src/components/admin_console/__snapshots__/elasticsearch_settings.test.tsx.snap @@ -508,11 +508,15 @@ exports[`components/ElasticSearchSettings should match snapshot, disabled 1`] = >
@@ -1527,10 +1545,14 @@ exports[`components/ElasticSearchSettings should match snapshot, enabled 1`] = ` >
@@ -2542,10 +2578,14 @@ exports[`components/ElasticSearchSettings should match snapshot, sniff enabled 1 >
diff --git a/webapp/channels/src/components/admin_console/__snapshots__/message_export_settings.test.tsx.snap b/webapp/channels/src/components/admin_console/__snapshots__/message_export_settings.test.tsx.snap index 8d4e9ea30f7..25e31d6c3ad 100644 --- a/webapp/channels/src/components/admin_console/__snapshots__/message_export_settings.test.tsx.snap +++ b/webapp/channels/src/components/admin_console/__snapshots__/message_export_settings.test.tsx.snap @@ -202,11 +202,15 @@ exports[`components/MessageExportSettings should match snapshot, disabled, actia >
@@ -722,11 +728,15 @@ exports[`components/MessageExportSettings should match snapshot, disabled, globa >
@@ -992,10 +1004,14 @@ exports[`components/MessageExportSettings should match snapshot, enabled, actian >
@@ -1502,10 +1520,14 @@ exports[`components/MessageExportSettings should match snapshot, enabled, global >
@@ -2136,10 +2160,14 @@ exports[`components/MessageExportSettings should match snapshot, enabled, global >
diff --git a/webapp/channels/src/components/admin_console/__snapshots__/push_settings.test.tsx.snap b/webapp/channels/src/components/admin_console/__snapshots__/push_settings.test.tsx.snap index ea10aacfd33..44f7f69a14d 100644 --- a/webapp/channels/src/components/admin_console/__snapshots__/push_settings.test.tsx.snap +++ b/webapp/channels/src/components/admin_console/__snapshots__/push_settings.test.tsx.snap @@ -257,13 +257,15 @@ exports[`components/PushSettings should match snapshot, licensed 1`] = ` class="admin-console-save" > @@ -414,13 +416,15 @@ exports[`components/PushSettings should match snapshot, unlicensed 1`] = ` class="admin-console-save" > diff --git a/webapp/channels/src/components/admin_console/access_control/__snapshots__/policies.test.tsx.snap b/webapp/channels/src/components/admin_console/access_control/__snapshots__/policies.test.tsx.snap index f1efd32d466..e19981b9442 100644 --- a/webapp/channels/src/components/admin_console/access_control/__snapshots__/policies.test.tsx.snap +++ b/webapp/channels/src/components/admin_console/access_control/__snapshots__/policies.test.tsx.snap @@ -19,12 +19,37 @@ exports[`components/admin_console/access_control/PolicyList should match snapsho

@@ -127,12 +152,37 @@ exports[`components/admin_console/access_control/PolicyList should match snapsho

@@ -357,12 +407,37 @@ exports[`components/admin_console/access_control/PolicyList should match snapsho

diff --git a/webapp/channels/src/components/admin_console/access_control/editors/shared.test.tsx b/webapp/channels/src/components/admin_console/access_control/editors/shared.test.tsx index 9014aff5c36..80359636906 100644 --- a/webapp/channels/src/components/admin_console/access_control/editors/shared.test.tsx +++ b/webapp/channels/src/components/admin_console/access_control/editors/shared.test.tsx @@ -45,11 +45,11 @@ describe('TestButton', () => { const button = screen.getByRole('button', {name: /test access rule/i}); expect(button).toBeInTheDocument(); - expect(button).toHaveClass('btn', 'btn-sm', 'btn-tertiary'); + expect(button.className).toEqual(expect.stringContaining('_button--emphasis-tertiary')); + expect(button.className).toEqual(expect.stringContaining('_button--size-small')); - // Check for icon - const icon = button.querySelector('i.icon.icon-lock-outline'); - expect(icon).toBeInTheDocument(); + // Leading icon is provided via compass-ui Icon glyph slot + expect(button.querySelector('svg')).toBeInTheDocument(); }); test('should render the supplied label override instead of the default copy', () => { @@ -67,7 +67,7 @@ describe('TestButton', () => { expect(screen.queryByRole('button', {name: /test access rule/i})).not.toBeInTheDocument(); const button = screen.getByRole('button', {name: /simulate rules/i}); expect(button).toBeInTheDocument(); - expect(button.querySelector('i.icon.icon-lock-outline')).toBeInTheDocument(); + expect(button.querySelector('svg')).toBeInTheDocument(); }); test('should be enabled and clickable when disabled is false', () => { diff --git a/webapp/channels/src/components/admin_console/access_control/editors/shared.tsx b/webapp/channels/src/components/admin_console/access_control/editors/shared.tsx index ec153ddec76..45d112f57b2 100644 --- a/webapp/channels/src/components/admin_console/access_control/editors/shared.tsx +++ b/webapp/channels/src/components/admin_console/access_control/editors/shared.tsx @@ -5,7 +5,9 @@ import React, {type JSX} from 'react'; import {defineMessage, FormattedMessage} from 'react-intl'; import type {MessageDescriptor} from 'react-intl'; -import {Button} from '@mattermost/shared/components/button'; +import {LockOutlineIcon, PlusIcon} from '@mattermost/compass-icons/components'; +import {Button} from '@mattermost/compass-ui/components/button'; +import {Icon} from '@mattermost/compass-ui/components/icon'; import {WithTooltip} from '@mattermost/shared/components/tooltip'; import type {AccessControlTestResult} from '@mattermost/types/access_control'; import type {UserPropertyField} from '@mattermost/types/properties_user'; @@ -505,11 +507,11 @@ export function TestButton({onClick, disabled, disabledTooltip, label}: TestButt const button = (
{teamAbacEnabled && ( diff --git a/webapp/channels/src/components/admin_console/access_control/modals/job_details/searchable_sync_job_channel_list.tsx b/webapp/channels/src/components/admin_console/access_control/modals/job_details/searchable_sync_job_channel_list.tsx index 276f8fb49f4..75caf8a8a1f 100644 --- a/webapp/channels/src/components/admin_console/access_control/modals/job_details/searchable_sync_job_channel_list.tsx +++ b/webapp/channels/src/components/admin_console/access_control/modals/job_details/searchable_sync_job_channel_list.tsx @@ -4,7 +4,7 @@ import React, {useState, useRef, useEffect, type JSX} from 'react'; import {FormattedMessage, defineMessages, injectIntl, type WrappedComponentProps} from 'react-intl'; -import {Button} from '@mattermost/shared/components/button'; +import {Button} from '@mattermost/compass-ui/components/button'; import type {Channel} from '@mattermost/types/channels'; import type {Team} from '@mattermost/types/teams'; import type {IDMappedObjects} from '@mattermost/types/utilities'; @@ -214,7 +214,7 @@ const SearchableSyncJobChannelList = (props: Props) => { nextButton = (
)} @@ -503,7 +503,7 @@ export default function PolicyList(props: Props): JSX.Element { defaultMessage='Delete Policy' /> } - confirmButtonVariant='destructive' + destructive={true} compassDesign={true} > <> diff --git a/webapp/channels/src/components/admin_console/access_control/policy_details/__snapshots__/policy_details.test.tsx.snap b/webapp/channels/src/components/admin_console/access_control/policy_details/__snapshots__/policy_details.test.tsx.snap index b97017e6a04..fbdc57a0d3f 100644 --- a/webapp/channels/src/components/admin_console/access_control/policy_details/__snapshots__/policy_details.test.tsx.snap +++ b/webapp/channels/src/components/admin_console/access_control/policy_details/__snapshots__/policy_details.test.tsx.snap @@ -75,9 +75,14 @@ exports[`components/admin_console/access_control/policy_details/PolicyDetails sh


@@ -382,9 +423,14 @@ exports[`components/admin_console/access_control/policy_details/PolicyDetails sh

- Cancel + + Cancel +
@@ -493,9 +545,14 @@ exports[`components/admin_console/access_control/policy_details/PolicyDetails sh


@@ -775,21 +868,27 @@ exports[`components/admin_console/access_control/policy_details/PolicyDetails sh class="admin-console-save" > - Cancel + + Cancel + diff --git a/webapp/channels/src/components/admin_console/access_control/policy_details/channel_list/__snapshots__/channel_list.test.tsx.snap b/webapp/channels/src/components/admin_console/access_control/policy_details/channel_list/__snapshots__/channel_list.test.tsx.snap index de5702dc627..9d58c3cc74c 100644 --- a/webapp/channels/src/components/admin_console/access_control/policy_details/channel_list/__snapshots__/channel_list.test.tsx.snap +++ b/webapp/channels/src/components/admin_console/access_control/policy_details/channel_list/__snapshots__/channel_list.test.tsx.snap @@ -39,13 +39,40 @@ exports[`components/admin_console/access_control/channel_list should match snaps class="Filter" >
@@ -318,13 +349,40 @@ exports[`components/admin_console/access_control/channel_list should match snaps class="Filter" >
@@ -597,13 +659,40 @@ exports[`components/admin_console/access_control/channel_list should match snaps class="Filter" >
@@ -876,13 +969,40 @@ exports[`components/admin_console/access_control/channel_list should match snaps class="Filter" >
diff --git a/webapp/channels/src/components/admin_console/access_control/policy_details/policy_details.tsx b/webapp/channels/src/components/admin_console/access_control/policy_details/policy_details.tsx index f85ab4d8b83..67113e6ca86 100644 --- a/webapp/channels/src/components/admin_console/access_control/policy_details/policy_details.tsx +++ b/webapp/channels/src/components/admin_console/access_control/policy_details/policy_details.tsx @@ -5,9 +5,9 @@ import cloneDeep from 'lodash/cloneDeep'; import React, {useState, useEffect, useMemo, type JSX} from 'react'; import {FormattedMessage, useIntl} from 'react-intl'; +import {Button} from '@mattermost/compass-ui/components/button'; import {SectionNotice} from '@mattermost/compass-ui/components/section-notice'; import {GenericModal} from '@mattermost/components'; -import {buttonClassNames} from '@mattermost/shared/components/button'; import type {AccessControlPolicy, AccessControlPolicyActiveUpdate, AccessControlPolicyRule} from '@mattermost/types/access_control'; import {getMembershipRule, buildRulesWithMembership, getAutoAddFromRules} from '@mattermost/types/access_control'; import type {ChannelSearchOpts, ChannelWithTeamData} from '@mattermost/types/channels'; @@ -872,7 +872,7 @@ function PolicyDetails({ defaultMessage='Delete Policy' /> } - confirmButtonVariant='destructive' + destructive={true} compassDesign={true} > <> @@ -905,15 +905,17 @@ function PolicyDetails({ /> } /> - - - + + + + {serverError && ( diff --git a/webapp/channels/src/components/admin_console/admin_settings/__snapshots__/admin_setting.test.tsx.snap b/webapp/channels/src/components/admin_console/admin_settings/__snapshots__/admin_setting.test.tsx.snap index e0337db3539..e307547131c 100644 --- a/webapp/channels/src/components/admin_console/admin_settings/__snapshots__/admin_setting.test.tsx.snap +++ b/webapp/channels/src/components/admin_console/admin_settings/__snapshots__/admin_setting.test.tsx.snap @@ -20,13 +20,15 @@ exports[`AdminSettings should match snapshot 1`] = ` class="admin-console-save" > diff --git a/webapp/channels/src/components/admin_console/admin_user_card/admin_user_card.scss b/webapp/channels/src/components/admin_console/admin_user_card/admin_user_card.scss index 702edeb15e1..999d7075444 100644 --- a/webapp/channels/src/components/admin_console/admin_user_card/admin_user_card.scss +++ b/webapp/channels/src/components/admin_console/admin_user_card/admin_user_card.scss @@ -83,9 +83,11 @@ input.AdminUserCard__picture-input[type='file'] { .AdminUserCard__footer { display: flex; flex-direction: row; + align-items: center; padding: 20px; border-top: solid 1px rgba(0, 0, 0, 0.2); background-color: #fff; + gap: 8px; } .AdminUserCard__user-info { diff --git a/webapp/channels/src/components/admin_console/audits/audits.tsx b/webapp/channels/src/components/admin_console/audits/audits.tsx index b8f70380c1a..9504fdeabb1 100644 --- a/webapp/channels/src/components/admin_console/audits/audits.tsx +++ b/webapp/channels/src/components/admin_console/audits/audits.tsx @@ -5,7 +5,7 @@ import React, {useEffect, useState, memo, useCallback} from 'react'; import type {CSSProperties} from 'react'; import {FormattedMessage, defineMessages} from 'react-intl'; -import {Button} from '@mattermost/shared/components/button'; +import {Button} from '@mattermost/compass-ui/components/button'; import type {Audit} from '@mattermost/types/audits'; import type {ActionResult} from 'mattermost-redux/types/actions'; diff --git a/webapp/channels/src/components/admin_console/billing/billing_subscriptions/cancel_subscription.tsx b/webapp/channels/src/components/admin_console/billing/billing_subscriptions/cancel_subscription.tsx index a07e7c6e76c..dcf58f3ecc5 100644 --- a/webapp/channels/src/components/admin_console/billing/billing_subscriptions/cancel_subscription.tsx +++ b/webapp/channels/src/components/admin_console/billing/billing_subscriptions/cancel_subscription.tsx @@ -4,7 +4,7 @@ import React from 'react'; import {FormattedMessage} from 'react-intl'; -import {buttonClassNames} from '@mattermost/shared/components/button'; +import {Button} from '@mattermost/compass-ui/components/button'; import {useOpenCloudZendeskSupportForm} from 'components/common/hooks/useOpenZendeskForm'; import ExternalLink from 'components/external_link'; @@ -28,16 +28,23 @@ const CancelSubscription = () => { defaultMessage='At this time, deleting a workspace can only be done with the help of a customer support representative.' /> - - - + + + + ); diff --git a/webapp/channels/src/components/admin_console/billing/billing_subscriptions/contact_sales_card.tsx b/webapp/channels/src/components/admin_console/billing/billing_subscriptions/contact_sales_card.tsx index 70eab1e0bb1..a6113fce254 100644 --- a/webapp/channels/src/components/admin_console/billing/billing_subscriptions/contact_sales_card.tsx +++ b/webapp/channels/src/components/admin_console/billing/billing_subscriptions/contact_sales_card.tsx @@ -4,7 +4,7 @@ import React from 'react'; import {FormattedMessage} from 'react-intl'; -import {Button, buttonClassNames} from '@mattermost/shared/components/button'; +import {Button} from '@mattermost/compass-ui/components/button'; import useOpenSalesLink from 'components/common/hooks/useOpenSalesLink'; import CloudTrialSvg from 'components/common/svg_images_components/cloud_trial_svg'; @@ -140,17 +140,21 @@ const ContactSalesCard = (props: Props) => { {description} {(isFreeTrial || subscriptionPlan === CloudProducts.ENTERPRISE || isCloudLegacyPlan) && - - - - + + + + } {(!isFreeTrial && subscriptionPlan !== CloudProducts.ENTERPRISE && subscriptionPlan !== CloudProducts.LEGACY) && ); @@ -115,17 +121,17 @@ export const FreeTrial = ({daysLeftOnTrial}: FreeTrialProps) => { /> } - + ); }; @@ -337,16 +343,18 @@ export const InvoiceInfo = ({invoice, product, fullCharges, partialCharges, hasM
- +
- }/>} > - - - + + + + ); @@ -41,15 +46,18 @@ const noCompanyInfoSection = ( defaultMessage='There is currently no company information on file.' /> - - - + + + + ); diff --git a/webapp/channels/src/components/admin_console/billing/company_info_edit.tsx b/webapp/channels/src/components/admin_console/billing/company_info_edit.tsx index e604772cd3e..f5472052f21 100644 --- a/webapp/channels/src/components/admin_console/billing/company_info_edit.tsx +++ b/webapp/channels/src/components/admin_console/billing/company_info_edit.tsx @@ -7,7 +7,7 @@ import {defineMessage, FormattedMessage} from 'react-intl'; import {useDispatch, useSelector} from 'react-redux'; import {useHistory} from 'react-router-dom'; -import {buttonClassNames} from '@mattermost/shared/components/button'; +import {Button} from '@mattermost/compass-ui/components/button'; import {getCloudCustomer, updateCloudCustomer, updateCloudCustomerAddress} from 'mattermost-redux/actions/cloud'; @@ -285,15 +285,17 @@ const CompanyInfoEdit: React.FC = () => { /> )} /> - - - + + + + ); diff --git a/webapp/channels/src/components/admin_console/billing/plan_details/plan_details.tsx b/webapp/channels/src/components/admin_console/billing/plan_details/plan_details.tsx index 31c6bc32a21..73526994209 100644 --- a/webapp/channels/src/components/admin_console/billing/plan_details/plan_details.tsx +++ b/webapp/channels/src/components/admin_console/billing/plan_details/plan_details.tsx @@ -4,7 +4,7 @@ import React from 'react'; import {FormattedMessage, useIntl} from 'react-intl'; -import {Button} from '@mattermost/shared/components/button'; +import {Button} from '@mattermost/compass-ui/components/button'; import useOpenPricingModal from 'components/common/hooks/useOpenPricingModal'; import Tag from 'components/widgets/tag/tag'; diff --git a/webapp/channels/src/components/admin_console/blockable_button/blockable_button.tsx b/webapp/channels/src/components/admin_console/blockable_button/blockable_button.tsx deleted file mode 100644 index 229cc0a3f5d..00000000000 --- a/webapp/channels/src/components/admin_console/blockable_button/blockable_button.tsx +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -import React, {useCallback} from 'react'; -import type {MouseEvent} from 'react'; - -type Props = { - id?: string; - activeClassName?: string; - - // Bool whether navigation is blocked - blocked: boolean; - - actions: { - - // Function for deferring navigation while blocked - deferNavigation: (func: () => void) => void; - }; - children?: React.ReactNode; - className?: string; - onClick?: (e: React.MouseEvent) => void; - onCancelConfirmed: () => void; -}; - -const BlockableButton = ({blocked, actions, onClick, onCancelConfirmed, ...restProps}: Props) => { - const handleClick = useCallback((e: MouseEvent) => { - onClick?.(e); - - if (blocked) { - e.preventDefault(); - actions.deferNavigation(() => { - onCancelConfirmed(); - }); - } - }, [actions, blocked, onClick, onCancelConfirmed]); - - return ( - + ), [disabled, intl, handleDisableForAllTeams]); diff --git a/webapp/channels/src/components/admin_console/custom_plugin_settings/__snapshots__/custom_plugin_settings.test.tsx.snap b/webapp/channels/src/components/admin_console/custom_plugin_settings/__snapshots__/custom_plugin_settings.test.tsx.snap index b6f71ffdd2b..7d7d7da4d42 100644 --- a/webapp/channels/src/components/admin_console/custom_plugin_settings/__snapshots__/custom_plugin_settings.test.tsx.snap +++ b/webapp/channels/src/components/admin_console/custom_plugin_settings/__snapshots__/custom_plugin_settings.test.tsx.snap @@ -349,10 +349,14 @@ exports[`components/admin_console/CustomPluginSettings should match snapshot wit class="help-text" >
@@ -488,13 +494,15 @@ exports[`components/admin_console/CustomPluginSettings should match snapshot wit class="admin-console-save" > @@ -856,10 +864,14 @@ exports[`components/admin_console/CustomPluginSettings should match snapshot wit class="help-text" >
diff --git a/webapp/channels/src/components/admin_console/custom_plugin_settings/enable_plugin_button.tsx b/webapp/channels/src/components/admin_console/custom_plugin_settings/enable_plugin_button.tsx index 2a04e2a9556..07684ce1492 100644 --- a/webapp/channels/src/components/admin_console/custom_plugin_settings/enable_plugin_button.tsx +++ b/webapp/channels/src/components/admin_console/custom_plugin_settings/enable_plugin_button.tsx @@ -171,7 +171,7 @@ export function PluginEnableButton({actions, disabled, homepageUrl, id, saveNeed defaultMessage='Are you sure you would like to remove the plugin?' /> } - confirmButtonVariant='destructive' + destructive={true} confirmButtonText={ diff --git a/webapp/channels/src/components/admin_console/data_retention_settings/__snapshots__/data_retention_settings.test.tsx.snap b/webapp/channels/src/components/admin_console/data_retention_settings/__snapshots__/data_retention_settings.test.tsx.snap index 002ecfcf778..48a42496667 100644 --- a/webapp/channels/src/components/admin_console/data_retention_settings/__snapshots__/data_retention_settings.test.tsx.snap +++ b/webapp/channels/src/components/admin_console/data_retention_settings/__snapshots__/data_retention_settings.test.tsx.snap @@ -86,9 +86,14 @@ exports[`components/admin_console/data_retention_settings/data_retention_setting








@@ -426,13 +457,40 @@ exports[`components/admin_console/data_retention_settings/channel_list should ma class="Filter" >
diff --git a/webapp/channels/src/components/admin_console/data_retention_settings/custom_policy_form/__snapshots__/custom_policy_form.test.tsx.snap b/webapp/channels/src/components/admin_console/data_retention_settings/custom_policy_form/__snapshots__/custom_policy_form.test.tsx.snap index cce996a0fcd..5f2947b779e 100644 --- a/webapp/channels/src/components/admin_console/data_retention_settings/custom_policy_form/__snapshots__/custom_policy_form.test.tsx.snap +++ b/webapp/channels/src/components/admin_console/data_retention_settings/custom_policy_form/__snapshots__/custom_policy_form.test.tsx.snap @@ -200,9 +200,14 @@ exports[`components/admin_console/data_retention_settings/custom_policy_form sho

@@ -598,21 +639,27 @@ exports[`components/admin_console/data_retention_settings/custom_policy_form sho class="admin-console-save" > - Cancel + + Cancel + @@ -814,9 +861,14 @@ exports[`components/admin_console/data_retention_settings/custom_policy_form sho

@@ -1236,21 +1324,27 @@ exports[`components/admin_console/data_retention_settings/custom_policy_form sho class="admin-console-save" > - Cancel + + Cancel + diff --git a/webapp/channels/src/components/admin_console/data_retention_settings/custom_policy_form/custom_policy_form.tsx b/webapp/channels/src/components/admin_console/data_retention_settings/custom_policy_form/custom_policy_form.tsx index 06e6911c3e9..f5b194242cc 100644 --- a/webapp/channels/src/components/admin_console/data_retention_settings/custom_policy_form/custom_policy_form.tsx +++ b/webapp/channels/src/components/admin_console/data_retention_settings/custom_policy_form/custom_policy_form.tsx @@ -5,7 +5,7 @@ import React, {type JSX} from 'react'; import {defineMessages, FormattedMessage, injectIntl} from 'react-intl'; import type {WrappedComponentProps} from 'react-intl'; -import {buttonClassNames} from '@mattermost/shared/components/button'; +import {Button} from '@mattermost/compass-ui/components/button'; import type {ChannelWithTeamData} from '@mattermost/types/channels'; import type { DataRetentionCustomPolicy, @@ -536,15 +536,17 @@ class CustomPolicyForm extends React.PureComponent { /> )} /> - - - + + + + {serverError && diff --git a/webapp/channels/src/components/admin_console/data_retention_settings/global_policy_form/__snapshots__/global_policy_form.test.tsx.snap b/webapp/channels/src/components/admin_console/data_retention_settings/global_policy_form/__snapshots__/global_policy_form.test.tsx.snap index 461d78ee141..beb4b31d9dc 100644 --- a/webapp/channels/src/components/admin_console/data_retention_settings/global_policy_form/__snapshots__/global_policy_form.test.tsx.snap +++ b/webapp/channels/src/components/admin_console/data_retention_settings/global_policy_form/__snapshots__/global_policy_form.test.tsx.snap @@ -239,21 +239,27 @@ exports[`components/PluginManagement should match snapshot 1`] = ` class="admin-console-save" > - Cancel + + Cancel + diff --git a/webapp/channels/src/components/admin_console/data_retention_settings/global_policy_form/global_policy_form.tsx b/webapp/channels/src/components/admin_console/data_retention_settings/global_policy_form/global_policy_form.tsx index e6a7606401b..6cce8b7c540 100644 --- a/webapp/channels/src/components/admin_console/data_retention_settings/global_policy_form/global_policy_form.tsx +++ b/webapp/channels/src/components/admin_console/data_retention_settings/global_policy_form/global_policy_form.tsx @@ -4,7 +4,7 @@ import React, {type JSX} from 'react'; import {defineMessages, FormattedMessage} from 'react-intl'; -import {buttonClassNames} from '@mattermost/shared/components/button'; +import {Button} from '@mattermost/compass-ui/components/button'; import type {AdminConfig, EnvironmentConfig} from '@mattermost/types/config'; import type {DeepPartial} from '@mattermost/types/utilities'; @@ -273,15 +273,17 @@ export default class GlobalPolicyForm extends React.PureComponent /> )} /> - - - + + + + {this.state.serverError && diff --git a/webapp/channels/src/components/admin_console/file_upload_setting.tsx b/webapp/channels/src/components/admin_console/file_upload_setting.tsx index 5b3fbebf00d..37d865b7971 100644 --- a/webapp/channels/src/components/admin_console/file_upload_setting.tsx +++ b/webapp/channels/src/components/admin_console/file_upload_setting.tsx @@ -4,7 +4,7 @@ import React, {memo, useCallback, useEffect, useRef, useState} from 'react'; import {FormattedMessage} from 'react-intl'; -import {Button} from '@mattermost/shared/components/button'; +import {Button} from '@mattermost/compass-ui/components/button'; import * as Utils from 'utils/utils'; diff --git a/webapp/channels/src/components/admin_console/filter/filter.scss b/webapp/channels/src/components/admin_console/filter/filter.scss index c3aac90eb1f..623aaf5b619 100644 --- a/webapp/channels/src/components/admin_console/filter/filter.scss +++ b/webapp/channels/src/components/admin_console/filter/filter.scss @@ -3,29 +3,14 @@ display: inline-block; padding-left: 8px; - .Filter_button { - width: auto; - height: 32px; - padding: 0 10px; - border: 0; - border-radius: 4px; - background: var(--sys-center-channel-bg); - color: var(--sys-button-bg); - font-size: 12px; - - &.Filter__active, - &:focus { - background: rgba(var(--sys-button-bg-rgb), 0.12); - } - - &:hover { - background: rgba(var(--sys-button-bg-rgb), 0.06); - } - } - - .Icon { - margin-right: 2px; - font-size: 14px; + // Held-open state. Compass's :active is momentary, so drive this off + // aria-expanded, which is already the source of truth for the popover. + // The :hover variant is spelled out because Compass's own hover rule has + // the same specificity as the bare one and would otherwise win on order, + // and the tint has to clear the 8% resting tertiary to read as a state. + .Filter_button[aria-expanded='true'], + .Filter_button[aria-expanded='true']:hover { + background-color: rgba(var(--link-color-rgb), 0.24); } .Filter_content { diff --git a/webapp/channels/src/components/admin_console/filter/filter.tsx b/webapp/channels/src/components/admin_console/filter/filter.tsx index 30c6ca4c86c..09bb2b2bf82 100644 --- a/webapp/channels/src/components/admin_console/filter/filter.tsx +++ b/webapp/channels/src/components/admin_console/filter/filter.tsx @@ -5,7 +5,9 @@ import classNames from 'classnames'; import React, {type JSX} from 'react'; import {FormattedMessage} from 'react-intl'; -import {Button} from '@mattermost/shared/components/button'; +import {FilterVariantIcon} from '@mattermost/compass-icons/components'; +import {Button} from '@mattermost/compass-ui/components/button'; +import {Icon} from '@mattermost/compass-ui/components/icon'; import FilterList from './filter_list'; @@ -190,20 +192,22 @@ class Filter extends React.PureComponent { className='Filter' ref={this.filterRef} > - +
{ +
)} diff --git a/webapp/channels/src/components/admin_console/global_attributes/applies_to/channels/channels_resource_row.scss b/webapp/channels/src/components/admin_console/global_attributes/applies_to/channels/channels_resource_row.scss index 6d1195040e1..998212a138c 100644 --- a/webapp/channels/src/components/admin_console/global_attributes/applies_to/channels/channels_resource_row.scss +++ b/webapp/channels/src/components/admin_console/global_attributes/applies_to/channels/channels_resource_row.scss @@ -54,7 +54,7 @@ } } -.btn.btn-sm.ChannelsResourceRow__remove { +.ChannelsResourceRow__remove { height: 32px; flex-shrink: 0; align-self: center; diff --git a/webapp/channels/src/components/admin_console/global_attributes/applies_to/channels/channels_resource_row.tsx b/webapp/channels/src/components/admin_console/global_attributes/applies_to/channels/channels_resource_row.tsx index b855a679a80..2640f23d061 100644 --- a/webapp/channels/src/components/admin_console/global_attributes/applies_to/channels/channels_resource_row.tsx +++ b/webapp/channels/src/components/admin_console/global_attributes/applies_to/channels/channels_resource_row.tsx @@ -6,7 +6,7 @@ import React, {useMemo, useState} from 'react'; import {defineMessages, FormattedMessage, useIntl} from 'react-intl'; import {ChevronDownIcon, ChevronRightIcon} from '@mattermost/compass-icons/components'; -import {Button} from '@mattermost/shared/components/button'; +import {Button} from '@mattermost/compass-ui/components/button'; import ChannelsResourceSettings from './channels_resource_settings'; import {summarizeChannelResource} from './summary'; @@ -79,8 +79,8 @@ const ChannelsResourceRow = ({value, onChange, onRemove, ordered, disabled}: Pro {errorKind && ( ((props, ref) => { + const {children, ...rest} = props; + return ( + + ); +}); +ExternalSourceMenuTrigger.displayName = 'ExternalSourceMenuTrigger'; + const LINK_MODAL_IDS: Record = { ldap: ModalIdentifiers.ATTRIBUTE_MODAL_LDAP, saml: ModalIdentifiers.ATTRIBUTE_MODAL_SAML, @@ -231,15 +249,11 @@ function AttributeExternalSource({links, fieldType, onLink, disabled = false, di - - - - + ), dataTestId: 'attributeExternalSourceTrigger', }} diff --git a/webapp/channels/src/components/admin_console/global_attributes/attribute_details/attribute_remove_applies_to_warning_modal.tsx b/webapp/channels/src/components/admin_console/global_attributes/attribute_details/attribute_remove_applies_to_warning_modal.tsx index 92f60ac815a..83a1bbc38bf 100644 --- a/webapp/channels/src/components/admin_console/global_attributes/attribute_details/attribute_remove_applies_to_warning_modal.tsx +++ b/webapp/channels/src/components/admin_console/global_attributes/attribute_details/attribute_remove_applies_to_warning_modal.tsx @@ -79,7 +79,7 @@ function ConfirmRemoveAppliesToModal({resourceTypes, onConfirm, onCancel, onExit return ( { const confirm = screen.getByRole('button', {name: 'Delete'}); expect(confirm).toHaveClass('delete'); - expect(confirm).toHaveClass('btn-danger'); }); it('uses the singular surviving-child lead for the diamond fixture', () => { diff --git a/webapp/channels/src/components/admin_console/global_attributes/attribute_details/graph/delete_modal.tsx b/webapp/channels/src/components/admin_console/global_attributes/attribute_details/graph/delete_modal.tsx index b5f3d248e3b..211828b2250 100644 --- a/webapp/channels/src/components/admin_console/global_attributes/attribute_details/graph/delete_modal.tsx +++ b/webapp/channels/src/components/admin_console/global_attributes/attribute_details/graph/delete_modal.tsx @@ -177,7 +177,7 @@ function AttributeGraphDeleteModal({optionName, options, onConfirm, onExited}: P compassDesign={true} modalHeaderText={formatMessage(messages.safeTitle, {name: model.optionName})} confirmButtonText={formatMessage(messages.deleteValue)} - confirmButtonVariant='destructive' + destructive={true} handleCancel={noop} handleConfirm={onConfirm} onExited={onExited} diff --git a/webapp/channels/src/components/admin_console/global_attributes/attribute_details/graph/draft_forms.tsx b/webapp/channels/src/components/admin_console/global_attributes/attribute_details/graph/draft_forms.tsx index ff8a677c261..f9a253cb301 100644 --- a/webapp/channels/src/components/admin_console/global_attributes/attribute_details/graph/draft_forms.tsx +++ b/webapp/channels/src/components/admin_console/global_attributes/attribute_details/graph/draft_forms.tsx @@ -5,7 +5,7 @@ import React from 'react'; import {defineMessages, FormattedMessage, useIntl} from 'react-intl'; import {PlusIcon} from '@mattermost/compass-icons/components'; -import {Button} from '@mattermost/shared/components/button'; +import {Button} from '@mattermost/compass-ui/components/button'; import Input from 'components/widgets/inputs/input/input'; @@ -87,7 +87,7 @@ export const AddTopLevelForm = ({

@@ -520,13 +526,15 @@ export default function ClassificationAttribute({disabled = false}: Props): JSX. onClick={handleSave} defaultMessage={} /> - - - + + + + {saveFailed && ( { getHistory().push(ATTRIBUTE_DETAILS_ROUTE); }} data-testid='newAttributeButton' + leadingIcon={}/>} > - - - - +
diff --git a/webapp/channels/src/components/admin_console/group_settings/__snapshots__/group_settings.test.tsx.snap b/webapp/channels/src/components/admin_console/group_settings/__snapshots__/group_settings.test.tsx.snap index 34a16ae2d4c..ca02083032a 100644 --- a/webapp/channels/src/components/admin_console/group_settings/__snapshots__/group_settings.test.tsx.snap +++ b/webapp/channels/src/components/admin_console/group_settings/__snapshots__/group_settings.test.tsx.snap @@ -104,13 +104,39 @@ For more information on Groups, please see class="group-list-link-unlink" >
diff --git a/webapp/channels/src/components/admin_console/group_settings/group_details/__snapshots__/group_details.test.tsx.snap b/webapp/channels/src/components/admin_console/group_settings/group_details/__snapshots__/group_details.test.tsx.snap index 085c2e680f1..e8653781894 100644 --- a/webapp/channels/src/components/admin_console/group_settings/group_details/__snapshots__/group_details.test.tsx.snap +++ b/webapp/channels/src/components/admin_console/group_settings/group_details/__snapshots__/group_details.test.tsx.snap @@ -164,14 +164,18 @@ exports[`components/admin_console/group_settings/group_details/GroupDetails shou class="MenuWrapper " > @@ -356,24 +360,32 @@ exports[`components/admin_console/group_settings/group_details/GroupDetails shou 1 - 20 of 20 @@ -384,22 +396,28 @@ exports[`components/admin_console/group_settings/group_details/GroupDetails shou class="admin-console-save" > - Cancel + + Cancel +
@@ -766,24 +788,32 @@ exports[`components/admin_console/group_settings/group_details/GroupDetails shou 1 - 20 of 20 @@ -794,22 +824,28 @@ exports[`components/admin_console/group_settings/group_details/GroupDetails shou class="admin-console-save" > - Cancel + + Cancel +
@@ -1174,24 +1214,32 @@ exports[`components/admin_console/group_settings/group_details/GroupDetails shou 1 - 20 of 20 @@ -1202,22 +1250,28 @@ exports[`components/admin_console/group_settings/group_details/GroupDetails shou class="admin-console-save" > - Cancel + + Cancel +
@@ -1580,24 +1638,32 @@ exports[`components/admin_console/group_settings/group_details/GroupDetails shou 1 - 20 of 20 @@ -1608,22 +1674,28 @@ exports[`components/admin_console/group_settings/group_details/GroupDetails shou class="admin-console-save" > - Cancel + + Cancel +
@@ -113,11 +117,15 @@ exports[`components/admin_console/group_settings/group_details/GroupTeamsAndChan class="text-right" > @@ -144,11 +152,15 @@ exports[`components/admin_console/group_settings/group_details/GroupTeamsAndChan class="text-right" > @@ -175,11 +187,15 @@ exports[`components/admin_console/group_settings/group_details/GroupTeamsAndChan class="text-right" > @@ -210,11 +226,15 @@ exports[`components/admin_console/group_settings/group_details/GroupTeamsAndChan class="text-right" > @@ -285,11 +305,15 @@ exports[`components/admin_console/group_settings/group_details/GroupTeamsAndChan class="text-right" > @@ -360,11 +384,15 @@ exports[`components/admin_console/group_settings/group_details/GroupTeamsAndChan class="text-right" > diff --git a/webapp/channels/src/components/admin_console/group_settings/group_details/__snapshots__/group_teams_and_channels_row.test.tsx.snap b/webapp/channels/src/components/admin_console/group_settings/group_details/__snapshots__/group_teams_and_channels_row.test.tsx.snap index 2a7d0d36b25..5043cb77b8f 100644 --- a/webapp/channels/src/components/admin_console/group_settings/group_details/__snapshots__/group_teams_and_channels_row.test.tsx.snap +++ b/webapp/channels/src/components/admin_console/group_settings/group_details/__snapshots__/group_teams_and_channels_row.test.tsx.snap @@ -71,11 +71,15 @@ exports[`components/admin_console/group_settings/group_details/GroupTeamsAndChan class="text-right" > @@ -111,11 +115,15 @@ exports[`components/admin_console/group_settings/group_details/GroupTeamsAndChan class="text-right" > @@ -170,11 +178,15 @@ exports[`components/admin_console/group_settings/group_details/GroupTeamsAndChan class="text-right" > @@ -210,11 +222,15 @@ exports[`components/admin_console/group_settings/group_details/GroupTeamsAndChan class="text-right" > @@ -254,11 +270,15 @@ exports[`components/admin_console/group_settings/group_details/GroupTeamsAndChan class="text-right" > @@ -298,11 +318,15 @@ exports[`components/admin_console/group_settings/group_details/GroupTeamsAndChan class="text-right" > diff --git a/webapp/channels/src/components/admin_console/group_settings/group_details/__snapshots__/group_users.test.tsx.snap b/webapp/channels/src/components/admin_console/group_settings/group_details/__snapshots__/group_users.test.tsx.snap index ef9981811a8..b722f08f2ec 100644 --- a/webapp/channels/src/components/admin_console/group_settings/group_details/__snapshots__/group_users.test.tsx.snap +++ b/webapp/channels/src/components/admin_console/group_settings/group_details/__snapshots__/group_users.test.tsx.snap @@ -855,24 +855,32 @@ exports[`components/admin_console/group_settings/group_details/GroupUsers should 1 - 20 of 20
@@ -1734,23 +1742,31 @@ exports[`components/admin_console/group_settings/group_details/GroupUsers should 1 - 20 of 55 @@ -2612,22 +2628,30 @@ exports[`components/admin_console/group_settings/group_details/GroupUsers should 21 - 40 of 55 @@ -3284,23 +3308,31 @@ exports[`components/admin_console/group_settings/group_details/GroupUsers should 41 - 55 of 55 @@ -4162,24 +4194,32 @@ exports[`components/admin_console/group_settings/group_details/GroupUsers should 1 - 20 of 20 @@ -5079,24 +5119,32 @@ exports[`components/admin_console/group_settings/group_details/GroupUsers should 1 - 20 of 20 @@ -5991,24 +6039,32 @@ exports[`components/admin_console/group_settings/group_details/GroupUsers should 1 - 20 of 20 diff --git a/webapp/channels/src/components/admin_console/group_settings/group_details/group_details.tsx b/webapp/channels/src/components/admin_console/group_settings/group_details/group_details.tsx index b1606632818..fa16559c3aa 100644 --- a/webapp/channels/src/components/admin_console/group_settings/group_details/group_details.tsx +++ b/webapp/channels/src/components/admin_console/group_settings/group_details/group_details.tsx @@ -5,7 +5,7 @@ import React, {type JSX} from 'react'; import type {WrappedComponentProps} from 'react-intl'; import {FormattedMessage, defineMessage, injectIntl} from 'react-intl'; -import {Button} from '@mattermost/shared/components/button'; +import {Button} from '@mattermost/compass-ui/components/button'; import type {ChannelWithTeamData} from '@mattermost/types/channels'; import { SyncableType, diff --git a/webapp/channels/src/components/admin_console/group_settings/group_details/group_teams_and_channels_row.tsx b/webapp/channels/src/components/admin_console/group_settings/group_details/group_teams_and_channels_row.tsx index 4472f640ab3..3882ee4f052 100644 --- a/webapp/channels/src/components/admin_console/group_settings/group_details/group_teams_and_channels_row.tsx +++ b/webapp/channels/src/components/admin_console/group_settings/group_details/group_teams_and_channels_row.tsx @@ -6,7 +6,7 @@ import isNil from 'lodash/isNil'; import React from 'react'; import {FormattedMessage} from 'react-intl'; -import {Button} from '@mattermost/shared/components/button'; +import {Button} from '@mattermost/compass-ui/components/button'; import ConfirmModal from 'components/confirm_modal'; import GlobeIcon from 'components/widgets/icons/globe_icon'; diff --git a/webapp/channels/src/components/admin_console/group_settings/group_details/group_users.tsx b/webapp/channels/src/components/admin_console/group_settings/group_details/group_users.tsx index e02bdd4c3a2..e64c72c945b 100644 --- a/webapp/channels/src/components/admin_console/group_settings/group_details/group_users.tsx +++ b/webapp/channels/src/components/admin_console/group_settings/group_details/group_users.tsx @@ -6,7 +6,7 @@ import React from 'react'; import {FormattedMessage} from 'react-intl'; import {Link} from 'react-router-dom'; -import {Button} from '@mattermost/shared/components/button'; +import {Button} from '@mattermost/compass-ui/components/button'; import {GroupSource, PluginGroupSourcePrefix} from '@mattermost/types/groups'; import type {UserProfile} from '@mattermost/types/users'; diff --git a/webapp/channels/src/components/admin_console/group_settings/groups_list/__snapshots__/groups_list.test.tsx.snap b/webapp/channels/src/components/admin_console/group_settings/groups_list/__snapshots__/groups_list.test.tsx.snap index 26c6d0f61c1..296df94a0f4 100644 --- a/webapp/channels/src/components/admin_console/group_settings/groups_list/__snapshots__/groups_list.test.tsx.snap +++ b/webapp/channels/src/components/admin_console/group_settings/groups_list/__snapshots__/groups_list.test.tsx.snap @@ -43,13 +43,39 @@ exports[`components/admin_console/group_settings/GroupsList.tsx should match sna class="group-list-link-unlink" > @@ -201,22 +227,53 @@ exports[`components/admin_console/group_settings/GroupsList.tsx should match sna @@ -277,13 +334,39 @@ exports[`components/admin_console/group_settings/GroupsList.tsx should match sna class="group-list-link-unlink" > @@ -483,24 +566,32 @@ exports[`components/admin_console/group_settings/GroupsList.tsx should match sna 1 - 2 of 2 @@ -550,13 +641,39 @@ exports[`components/admin_console/group_settings/GroupsList.tsx should match sna class="group-list-link-unlink" > @@ -730,24 +847,32 @@ exports[`components/admin_console/group_settings/GroupsList.tsx should match sna 1 - 2 of 2 @@ -797,13 +922,39 @@ exports[`components/admin_console/group_settings/GroupsList.tsx should match sna class="group-list-link-unlink" > @@ -977,24 +1128,32 @@ exports[`components/admin_console/group_settings/GroupsList.tsx should match sna 1 - 2 of 2 @@ -1044,13 +1203,39 @@ exports[`components/admin_console/group_settings/GroupsList.tsx should match sna class="group-list-link-unlink" > @@ -1256,24 +1441,32 @@ exports[`components/admin_console/group_settings/GroupsList.tsx should match sna 1 - 3 of 3 @@ -1323,13 +1516,39 @@ exports[`components/admin_console/group_settings/GroupsList.tsx should match sna class="group-list-link-unlink" > @@ -1892,23 +2111,31 @@ exports[`components/admin_console/group_settings/GroupsList.tsx should match sna 1 - 200 of 401 @@ -1958,13 +2185,39 @@ exports[`components/admin_console/group_settings/GroupsList.tsx should match sna class="group-list-link-unlink" > @@ -2527,22 +2780,30 @@ exports[`components/admin_console/group_settings/GroupsList.tsx should match sna 201 - 400 of 401 @@ -2592,13 +2853,39 @@ exports[`components/admin_console/group_settings/GroupsList.tsx should match sna class="group-list-link-unlink" > @@ -2804,22 +3091,30 @@ exports[`components/admin_console/group_settings/GroupsList.tsx should match sna 201 - 400 of 401 @@ -2869,13 +3164,39 @@ exports[`components/admin_console/group_settings/GroupsList.tsx should match sna class="group-list-link-unlink" > @@ -2936,13 +3257,39 @@ exports[`components/admin_console/group_settings/GroupsList.tsx should match sna class="group-list-link-unlink" > @@ -3090,24 +3437,32 @@ exports[`components/admin_console/group_settings/GroupsList.tsx should match sna 1 - 2 of 2 diff --git a/webapp/channels/src/components/admin_console/group_settings/groups_list/groups_list.tsx b/webapp/channels/src/components/admin_console/group_settings/groups_list/groups_list.tsx index 4e6cdc0338d..c9156462a2b 100644 --- a/webapp/channels/src/components/admin_console/group_settings/groups_list/groups_list.tsx +++ b/webapp/channels/src/components/admin_console/group_settings/groups_list/groups_list.tsx @@ -5,8 +5,10 @@ import classNames from 'classnames'; import React, {type JSX} from 'react'; import {defineMessage, FormattedMessage} from 'react-intl'; +import {LinkVariantIcon, LinkVariantOffIcon} from '@mattermost/compass-icons/components'; +import {Button} from '@mattermost/compass-ui/components/button'; import {Checkbox} from '@mattermost/compass-ui/components/checkbox'; -import {Button} from '@mattermost/shared/components/button'; +import {Icon} from '@mattermost/compass-ui/components/icon'; import type {GroupSearchOpts, MixedUnlinkedGroupRedux} from '@mattermost/types/groups'; import type {ActionResult} from 'mattermost-redux/types/actions'; @@ -164,8 +166,8 @@ export default class GroupsList extends React.PureComponent { emphasis='primary' onClick={() => this.linkSelectedGroups()} disabled={this.props.readOnly} + leadingIcon={}/>} > - { emphasis='primary' onClick={() => this.unlinkSelectedGroups()} disabled={this.props.readOnly} + leadingIcon={}/>} > - { type='button' emphasis='primary' disabled={this.props.readOnly} + leadingIcon={}/>} > - onConfirm?.(filterToDelete!)} > {formatMessage({id: 'admin.ip_filtering.delete_filter', defaultMessage: 'Delete filter'})} diff --git a/webapp/channels/src/components/admin_console/ip_filtering/edit_section/edit_section_header.tsx b/webapp/channels/src/components/admin_console/ip_filtering/edit_section/edit_section_header.tsx index 613a374d457..12f20a6bc67 100644 --- a/webapp/channels/src/components/admin_console/ip_filtering/edit_section/edit_section_header.tsx +++ b/webapp/channels/src/components/admin_console/ip_filtering/edit_section/edit_section_header.tsx @@ -4,7 +4,7 @@ import React from 'react'; import {FormattedMessage} from 'react-intl'; -import {Button} from '@mattermost/shared/components/button'; +import {Button} from '@mattermost/compass-ui/components/button'; import IPNotInRangeErrorPanel from './edit_section_ip_not_in_range_panel'; diff --git a/webapp/channels/src/components/admin_console/ip_filtering/edit_section/edit_section_ip_not_in_range_panel.tsx b/webapp/channels/src/components/admin_console/ip_filtering/edit_section/edit_section_ip_not_in_range_panel.tsx index 4b29de9d659..8a2274e2b14 100644 --- a/webapp/channels/src/components/admin_console/ip_filtering/edit_section/edit_section_ip_not_in_range_panel.tsx +++ b/webapp/channels/src/components/admin_console/ip_filtering/edit_section/edit_section_ip_not_in_range_panel.tsx @@ -5,8 +5,7 @@ import React from 'react'; import {FormattedMessage} from 'react-intl'; import {AlertOutlineIcon} from '@mattermost/compass-icons/components'; -import {Button} from '@mattermost/shared/components/button'; - +import {Button} from '@mattermost/compass-ui/components/button'; type IPNotInRangeErrorPanelProps = { currentUsersIP: string | null; setShowAddModal: (show: boolean) => void; diff --git a/webapp/channels/src/components/admin_console/ip_filtering/edit_section/edit_section_no_filters_panel.tsx b/webapp/channels/src/components/admin_console/ip_filtering/edit_section/edit_section_no_filters_panel.tsx index cd311c1fbe8..f7b8fbb4b01 100644 --- a/webapp/channels/src/components/admin_console/ip_filtering/edit_section/edit_section_no_filters_panel.tsx +++ b/webapp/channels/src/components/admin_console/ip_filtering/edit_section/edit_section_no_filters_panel.tsx @@ -4,7 +4,7 @@ import React from 'react'; import {FormattedMessage} from 'react-intl'; -import {Button} from '@mattermost/shared/components/button'; +import {Button} from '@mattermost/compass-ui/components/button'; import IPFilteringEarthSvg from 'components/common/svg_images_components/ip_filtering_earth_svg'; diff --git a/webapp/channels/src/components/admin_console/ip_filtering/edit_section/edit_sections.scss b/webapp/channels/src/components/admin_console/ip_filtering/edit_section/edit_sections.scss index b9edd246441..39b55c52d10 100644 --- a/webapp/channels/src/components/admin_console/ip_filtering/edit_section/edit_sections.scss +++ b/webapp/channels/src/components/admin_console/ip_filtering/edit_section/edit_sections.scss @@ -143,12 +143,8 @@ line-height: 20px; text-align: center; - .btn-primary { + button { margin-top: 16px; - - &:hover { - cursor: pointer; - } } } } diff --git a/webapp/channels/src/components/admin_console/ip_filtering/ip_filtering.scss b/webapp/channels/src/components/admin_console/ip_filtering/ip_filtering.scss index d957fc9b686..f2e2f637b50 100644 --- a/webapp/channels/src/components/admin_console/ip_filtering/ip_filtering.scss +++ b/webapp/channels/src/components/admin_console/ip_filtering/ip_filtering.scss @@ -1,12 +1,6 @@ .IPFiltering { height: 100%; - .admin-console-save { - .btn.btn-primary:disabled { - color: rgba(var(--center-channel-color-rgb), 0.32) !important; - } - } - .MainPanel { display: flex; height: 100%; diff --git a/webapp/channels/src/components/admin_console/ip_filtering/save_confirmation_modal.tsx b/webapp/channels/src/components/admin_console/ip_filtering/save_confirmation_modal.tsx index 6a4323250ff..4c9c22b091b 100644 --- a/webapp/channels/src/components/admin_console/ip_filtering/save_confirmation_modal.tsx +++ b/webapp/channels/src/components/admin_console/ip_filtering/save_confirmation_modal.tsx @@ -6,7 +6,7 @@ import {Modal} from 'react-bootstrap'; import {FormattedMessage, useIntl} from 'react-intl'; import {InformationOutlineIcon} from '@mattermost/compass-icons/components'; -import {Button} from '@mattermost/shared/components/button'; +import {Button} from '@mattermost/compass-ui/components/button'; import ExternalLink from 'components/external_link'; @@ -77,7 +77,7 @@ export default function SaveConfirmationModal({onExited, onConfirm, title, subti data-testid='save-confirmation-button' type='button' emphasis='primary' - variant='destructive' + destructive={true} onClick={() => onConfirm?.()} > {buttonText} diff --git a/webapp/channels/src/components/admin_console/jobs/table.scss b/webapp/channels/src/components/admin_console/jobs/table.scss index 6c01b5aeae6..11d88c272ab 100644 --- a/webapp/channels/src/components/admin_console/jobs/table.scss +++ b/webapp/channels/src/components/admin_console/jobs/table.scss @@ -34,7 +34,7 @@ background-color: rgba(0, 0, 0, 0.05); .view-details-link { - color: var(--button-bg); + --button-fg: var(--button-bg); } } @@ -48,24 +48,22 @@ text-align: right; } - .view-details-link.btn { - display: inline-flex; - align-items: center; + // Muted at rest so the row hover has something to reveal. Compass + // quaternary is --link-color out of the box, which left the link already + // blue and the hover a no-op. Colours go through --button-fg because the + // Compass label does not read `color`. + .view-details-link { + --button-fg: rgba(var(--sys-center-channel-color-rgb), 0.56); + padding: 0; background: transparent; - color: rgba(var(--sys-center-channel-color-rgb), 0.56); - font-size: 12px; - font-weight: 600; white-space: nowrap; &:hover, &:focus { - background: transparent; - color: var(--button-bg); - } + --button-fg: var(--button-bg); - .icon { - font-size: 16px; + background: transparent; } } diff --git a/webapp/channels/src/components/admin_console/jobs/table.tsx b/webapp/channels/src/components/admin_console/jobs/table.tsx index 86dd621ce5e..26b6776f0aa 100644 --- a/webapp/channels/src/components/admin_console/jobs/table.tsx +++ b/webapp/channels/src/components/admin_console/jobs/table.tsx @@ -5,7 +5,9 @@ import classNames from 'classnames'; import React, {type JSX} from 'react'; import {FormattedMessage} from 'react-intl'; -import {Button} from '@mattermost/shared/components/button'; +import {ChevronRightIcon} from '@mattermost/compass-icons/components'; +import {Button} from '@mattermost/compass-ui/components/button'; +import {Icon} from '@mattermost/compass-ui/components/icon'; import type {Job, JobType} from '@mattermost/types/jobs'; import type {ActionResult} from 'mattermost-redux/types/actions'; @@ -153,8 +155,9 @@ class JobTable extends React.PureComponent { )} diff --git a/webapp/channels/src/components/admin_console/license_settings/__snapshots__/license_settings.test.tsx.snap b/webapp/channels/src/components/admin_console/license_settings/__snapshots__/license_settings.test.tsx.snap index 3ee15dd09a4..fc2029202b1 100644 --- a/webapp/channels/src/components/admin_console/license_settings/__snapshots__/license_settings.test.tsx.snap +++ b/webapp/channels/src/components/admin_console/license_settings/__snapshots__/license_settings.test.tsx.snap @@ -86,9 +86,14 @@ exports[`components/admin_console/license_settings/LicenseSettings load screen a class="purchase-card" > @@ -463,10 +468,14 @@ exports[`components/admin_console/license_settings/LicenseSettings load screen a

@@ -566,9 +575,14 @@ exports[`components/admin_console/license_settings/LicenseSettings load screen w class="purchase-card" > @@ -940,18 +954,24 @@ exports[`components/admin_console/license_settings/LicenseSettings load screen w

@@ -1068,9 +1088,14 @@ exports[`components/admin_console/license_settings/LicenseSettings should match class="purchase-card" >

@@ -1103,10 +1128,15 @@ exports[`components/admin_console/license_settings/LicenseSettings should match

@@ -1611,15 +1655,16 @@ See ENTERPRISE-EDITION-LICENSE.txt in your root install directory for details. S
-
- -
+ +
@@ -1731,9 +1776,14 @@ exports[`components/admin_console/license_settings/LicenseSettings should match class="purchase-card" > @@ -1766,10 +1816,15 @@ exports[`components/admin_console/license_settings/LicenseSettings should match

@@ -2274,15 +2343,16 @@ See ENTERPRISE-EDITION-LICENSE.txt in your root install directory for details. S
-
- -
+ +
@@ -2380,9 +2450,14 @@ exports[`components/admin_console/license_settings/LicenseSettings should match class="purchase-card" > @@ -2415,10 +2490,15 @@ exports[`components/admin_console/license_settings/LicenseSettings should match

@@ -2939,15 +3033,16 @@ See ENTERPRISE-EDITION-LICENSE.txt in your root install directory for details. S
-
- -
+ +
@@ -3045,9 +3140,14 @@ exports[`components/admin_console/license_settings/LicenseSettings should match class="purchase-card" > @@ -3080,10 +3180,15 @@ exports[`components/admin_console/license_settings/LicenseSettings should match

@@ -3588,15 +3707,16 @@ See ENTERPRISE-EDITION-LICENSE.txt in your root install directory for details. S
-
- -
+ +
@@ -3694,9 +3814,14 @@ exports[`components/admin_console/license_settings/LicenseSettings should match class="purchase-card" > @@ -3729,10 +3854,15 @@ exports[`components/admin_console/license_settings/LicenseSettings should match

@@ -4238,15 +4382,16 @@ See ENTERPRISE-EDITION-LICENSE.txt in your root install directory for details. S
-
- -
+ +
@@ -4344,9 +4489,14 @@ exports[`components/admin_console/license_settings/LicenseSettings should match class="purchase-card" > @@ -4379,10 +4529,15 @@ exports[`components/admin_console/license_settings/LicenseSettings should match

@@ -4893,15 +5062,16 @@ exports[`components/admin_console/license_settings/LicenseSettings should match
-
- -
+ +
@@ -5026,10 +5196,15 @@ exports[`components/admin_console/license_settings/LicenseSettings should match

@@ -5461,15 +5650,16 @@ See ENTERPRISE-EDITION-LICENSE.txt in your root install directory for details. S
-
- -
+ +
@@ -5580,10 +5770,14 @@ exports[`components/admin_console/license_settings/LicenseSettings should match class="trial" > @@ -5604,10 +5798,15 @@ exports[`components/admin_console/license_settings/LicenseSettings should match class="StarterLeftPanel" >
@@ -6121,10 +6330,14 @@ exports[`components/admin_console/license_settings/LicenseSettings should match class="trial" > @@ -6145,10 +6358,15 @@ exports[`components/admin_console/license_settings/LicenseSettings should match class="StarterLeftPanel" >
@@ -6669,9 +6897,14 @@ exports[`components/admin_console/license_settings/LicenseSettings should match class="purchase-card" > @@ -7043,10 +7276,14 @@ exports[`components/admin_console/license_settings/LicenseSettings should match

@@ -8100,10 +8360,15 @@ exports[`components/admin_console/license_settings/LicenseSettings should match

@@ -8608,15 +8887,16 @@ See ENTERPRISE-EDITION-LICENSE.txt in your root install directory for details. S
-
- -
+ +
@@ -8714,9 +8994,14 @@ exports[`components/admin_console/license_settings/LicenseSettings should match class="purchase-card" > @@ -8749,10 +9034,15 @@ exports[`components/admin_console/license_settings/LicenseSettings should match

@@ -9257,15 +9561,16 @@ See ENTERPRISE-EDITION-LICENSE.txt in your root install directory for details. S
-
- -
+ +
diff --git a/webapp/channels/src/components/admin_console/license_settings/enterprise_edition/enterprise_edition.scss b/webapp/channels/src/components/admin_console/license_settings/enterprise_edition/enterprise_edition.scss index bd3fa16b169..5001ca8f47f 100644 --- a/webapp/channels/src/components/admin_console/license_settings/enterprise_edition/enterprise_edition.scss +++ b/webapp/channels/src/components/admin_console/license_settings/enterprise_edition/enterprise_edition.scss @@ -37,14 +37,14 @@ } .purchase_buttons { + display: flex; + flex-direction: column; margin-top: 20px; - .btn-primary { - margin-bottom: 8px; - } + gap: 8px; .trial-btn { width: 100%; - margin-left: 0px; + margin-left: 0; } } @@ -173,21 +173,7 @@ } #remove-button { - padding: 0; - border: none !important; margin: 10px 0; - background: none !important; - color: var(--error-text); - font-weight: 700; - - &:hover { - text-decoration: underline; - } - - &:focus, - &:focus-visible { - outline: none !important; - } } } diff --git a/webapp/channels/src/components/admin_console/license_settings/enterprise_edition/enterprise_edition_left_panel.tsx b/webapp/channels/src/components/admin_console/license_settings/enterprise_edition/enterprise_edition_left_panel.tsx index edcf00330de..9a8f890d6a2 100644 --- a/webapp/channels/src/components/admin_console/license_settings/enterprise_edition/enterprise_edition_left_panel.tsx +++ b/webapp/channels/src/components/admin_console/license_settings/enterprise_edition/enterprise_edition_left_panel.tsx @@ -7,8 +7,10 @@ import type {JSX, RefObject} from 'react'; import {FormattedDate, FormattedMessage, FormattedNumber, FormattedTime, defineMessage, defineMessages, useIntl} from 'react-intl'; import {useSelector} from 'react-redux'; +import {UploadOutlineIcon} from '@mattermost/compass-icons/components'; import AlertOutlineIcon from '@mattermost/compass-icons/components/alert-outline'; -import {Button} from '@mattermost/shared/components/button'; +import {Button} from '@mattermost/compass-ui/components/button'; +import {Icon} from '@mattermost/compass-ui/components/icon'; import {WithTooltip} from '@mattermost/shared/components/tooltip'; import type {ClientLicense} from '@mattermost/types/config'; @@ -98,7 +100,7 @@ const EnterpriseEditionLeftPanel = ({ id='enterprise_edition_view_plans' onClick={openPricingModal} emphasis='tertiary' - size='sm' + size='small' className='PlanDetails__viewPlansButton' > {formatMessage({ @@ -167,8 +169,8 @@ const EnterpriseEditionLeftPanel = ({ emphasis='primary' onClick={() => fileInputRef.current?.click()} disabled={isLicenseSetByEnvVar} + leadingIcon={}/>} > - {'License details'}
); const title = () => { diff --git a/webapp/channels/src/components/admin_console/license_settings/modals/confirm_license_removal_modal.tsx b/webapp/channels/src/components/admin_console/license_settings/modals/confirm_license_removal_modal.tsx index 6a205a49928..0a04bf009cd 100644 --- a/webapp/channels/src/components/admin_console/license_settings/modals/confirm_license_removal_modal.tsx +++ b/webapp/channels/src/components/admin_console/license_settings/modals/confirm_license_removal_modal.tsx @@ -5,8 +5,8 @@ import React, {type JSX} from 'react'; import {FormattedMessage} from 'react-intl'; import {useSelector, useDispatch} from 'react-redux'; +import {Button} from '@mattermost/compass-ui/components/button'; import {GenericModal} from '@mattermost/components'; -import {Button} from '@mattermost/shared/components/button'; import {closeModal} from 'actions/views/modals'; import {isModalOpen} from 'selectors/views/modals'; diff --git a/webapp/channels/src/components/admin_console/license_settings/modals/ee_license_modal.tsx b/webapp/channels/src/components/admin_console/license_settings/modals/ee_license_modal.tsx index c6ca0cb9e4b..eb5b9ffce43 100644 --- a/webapp/channels/src/components/admin_console/license_settings/modals/ee_license_modal.tsx +++ b/webapp/channels/src/components/admin_console/license_settings/modals/ee_license_modal.tsx @@ -4,8 +4,8 @@ import React, {type JSX} from 'react'; import {useSelector, useDispatch} from 'react-redux'; +import {Button} from '@mattermost/compass-ui/components/button'; import {GenericModal} from '@mattermost/components'; -import {Button} from '@mattermost/shared/components/button'; import {closeModal} from 'actions/views/modals'; import {isModalOpen} from 'selectors/views/modals'; diff --git a/webapp/channels/src/components/admin_console/license_settings/modals/upload_license_modal.scss b/webapp/channels/src/components/admin_console/license_settings/modals/upload_license_modal.scss index 9e84166f266..d416e21a1e8 100644 --- a/webapp/channels/src/components/admin_console/license_settings/modals/upload_license_modal.scss +++ b/webapp/channels/src/components/admin_console/license_settings/modals/upload_license_modal.scss @@ -96,6 +96,12 @@ &.preview-footer { flex-direction: row; + // The 8px between Cancel and Apply used to come from the global + // `.btn + .btn` rule in _buttons.scss, which the Compass buttons + // no longer match. This footer is not a .modal-footer, so it does + // not pick up that gap either. + gap: 8px; + button { margin-top: 0 !important; } diff --git a/webapp/channels/src/components/admin_console/license_settings/modals/upload_license_modal.tsx b/webapp/channels/src/components/admin_console/license_settings/modals/upload_license_modal.tsx index 9a19d6dbf45..cc8e6281833 100644 --- a/webapp/channels/src/components/admin_console/license_settings/modals/upload_license_modal.tsx +++ b/webapp/channels/src/components/admin_console/license_settings/modals/upload_license_modal.tsx @@ -5,8 +5,8 @@ import React, {useEffect, useCallback, type JSX} from 'react'; import {defineMessage, FormattedDate, FormattedMessage, useIntl} from 'react-intl'; import {useSelector, useDispatch} from 'react-redux'; +import {Button} from '@mattermost/compass-ui/components/button'; import {GenericModal} from '@mattermost/components'; -import {Button} from '@mattermost/shared/components/button'; import type {ClientLicense, License} from '@mattermost/types/config'; import {previewLicense, uploadLicense} from 'mattermost-redux/actions/admin'; @@ -248,18 +248,20 @@ const UploadLicenseModal = (props: Props): JSX.Element | null => { emphasis='primary' onClick={handleConfirmUpload} disabled={isLoading} + loading={Boolean(isLoading)} id='confirm-button' > - + {isLoading ? ( + + ) : ( - + )} diff --git a/webapp/channels/src/components/admin_console/license_settings/starter_edition/starter_left_panel.tsx b/webapp/channels/src/components/admin_console/license_settings/starter_edition/starter_left_panel.tsx index e418ae4e191..52cb4f1c9ea 100644 --- a/webapp/channels/src/components/admin_console/license_settings/starter_edition/starter_left_panel.tsx +++ b/webapp/channels/src/components/admin_console/license_settings/starter_edition/starter_left_panel.tsx @@ -5,7 +5,7 @@ import React from 'react'; import type {JSX, RefObject} from 'react'; import {FormattedMessage, defineMessages, useIntl} from 'react-intl'; -import {Button} from '@mattermost/shared/components/button'; +import {Button} from '@mattermost/compass-ui/components/button'; import useOpenPricingModal from 'components/common/hooks/useOpenPricingModal'; @@ -39,7 +39,7 @@ const StarterLeftPanel: React.FC = ({ id='starter_edition_view_plans' onClick={openPricingModal} emphasis='tertiary' - size='sm' + size='small' className='PlanDetails__viewPlansButton' > {intl.formatMessage({ diff --git a/webapp/channels/src/components/admin_console/license_settings/team_edition/team_edition.scss b/webapp/channels/src/components/admin_console/license_settings/team_edition/team_edition.scss index d200a9a07ca..5a1106a4c40 100644 --- a/webapp/channels/src/components/admin_console/license_settings/team_edition/team_edition.scss +++ b/webapp/channels/src/components/admin_console/license_settings/team_edition/team_edition.scss @@ -34,7 +34,8 @@ } } - button, a.btn { + button, + p:not(.upgrade-legal-terms) a { width: 100%; border-radius: 4px; margin: 5px auto; diff --git a/webapp/channels/src/components/admin_console/license_settings/team_edition/team_edition_right_panel.tsx b/webapp/channels/src/components/admin_console/license_settings/team_edition/team_edition_right_panel.tsx index f92359a18b1..9946a657708 100644 --- a/webapp/channels/src/components/admin_console/license_settings/team_edition/team_edition_right_panel.tsx +++ b/webapp/channels/src/components/admin_console/license_settings/team_edition/team_edition_right_panel.tsx @@ -4,11 +4,10 @@ import React from 'react'; import {FormattedMessage, useIntl} from 'react-intl'; -import {Button, buttonClassNames} from '@mattermost/shared/components/button'; +import {Button} from '@mattermost/compass-ui/components/button'; import SetupSystemSvg from 'components/common/svg_images_components/setup_system_svg'; import ExternalLink from 'components/external_link'; -import LoadingWrapper from 'components/widgets/loading/loading_wrapper'; import {LicenseLinks} from 'utils/constants'; import {format} from 'utils/markdown'; @@ -61,17 +60,21 @@ const TeamEditionRightPanel: React.FC = ({ upgradeButton = (

- - - + + + +

); @@ -83,23 +86,20 @@ const TeamEditionRightPanel: React.FC = ({ type='button' onClick={onHandleUpgrade} emphasis='primary' + loading={upgradingPercentage > 0} > - 0} - text={ - - } - > + {upgradingPercentage > 0 ? ( + + ) : ( - + )}

@@ -152,20 +152,19 @@ const TeamEditionRightPanel: React.FC = ({ type='button' onClick={handleRestart} emphasis='primary' + loading={restarting} > - + }) + ) : ( - + )}

{restartError && ( diff --git a/webapp/channels/src/components/admin_console/license_settings/trial_banner/trial_banner.tsx b/webapp/channels/src/components/admin_console/license_settings/trial_banner/trial_banner.tsx index 425ccf8ba04..c744bdc76a8 100644 --- a/webapp/channels/src/components/admin_console/license_settings/trial_banner/trial_banner.tsx +++ b/webapp/channels/src/components/admin_console/license_settings/trial_banner/trial_banner.tsx @@ -5,7 +5,7 @@ import React, {useEffect, useState} from 'react'; import {FormattedMessage, useIntl} from 'react-intl'; import {useDispatch, useSelector} from 'react-redux'; -import {Button} from '@mattermost/shared/components/button'; +import {Button} from '@mattermost/compass-ui/components/button'; import {savePreferences} from 'mattermost-redux/actions/preferences'; import {getBool as getBoolPreference} from 'mattermost-redux/selectors/entities/preferences'; @@ -14,7 +14,6 @@ import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users'; import AlertBanner from 'components/alert_banner'; import withOpenStartTrialFormModal from 'components/common/hocs/cloud/with_open_start_trial_form_modal'; import ExternalLink from 'components/external_link'; -import LoadingWrapper from 'components/widgets/loading/loading_wrapper'; import {AboutLinks, LicenseLinks, Preferences, Unique} from 'utils/constants'; import {format} from 'utils/markdown'; @@ -301,32 +300,38 @@ const TrialBanner = ({ ); } else { gettingTrialErrorMsg = null; + + let trialButtonLabel = ( + + ); + if (upgradingPercentage === 100 && restarting) { + trialButtonLabel = ( + + ); + } else if (upgradingPercentage > 0) { + trialButtonLabel = ( + + ); + } + trialButton = ( ); diff --git a/webapp/channels/src/components/admin_console/manage_roles_modal/manage_roles_modal.tsx b/webapp/channels/src/components/admin_console/manage_roles_modal/manage_roles_modal.tsx index de0671a823d..a15efc11c2b 100644 --- a/webapp/channels/src/components/admin_console/manage_roles_modal/manage_roles_modal.tsx +++ b/webapp/channels/src/components/admin_console/manage_roles_modal/manage_roles_modal.tsx @@ -6,7 +6,7 @@ import {Modal} from 'react-bootstrap'; import {FormattedMessage} from 'react-intl'; import {Link} from 'react-router-dom'; -import {Button} from '@mattermost/shared/components/button'; +import {Button} from '@mattermost/compass-ui/components/button'; import type {Role} from '@mattermost/types/roles'; import type {UserProfile} from '@mattermost/types/users'; diff --git a/webapp/channels/src/components/admin_console/manage_teams_modal/__snapshots__/remove_from_team_button.test.tsx.snap b/webapp/channels/src/components/admin_console/manage_teams_modal/__snapshots__/remove_from_team_button.test.tsx.snap index 367736b3763..6dd1ce7ec8d 100644 --- a/webapp/channels/src/components/admin_console/manage_teams_modal/__snapshots__/remove_from_team_button.test.tsx.snap +++ b/webapp/channels/src/components/admin_console/manage_teams_modal/__snapshots__/remove_from_team_button.test.tsx.snap @@ -3,10 +3,14 @@ exports[`RemoveFromTeamButton should match snapshot init 1`] = `
`; diff --git a/webapp/channels/src/components/admin_console/manage_teams_modal/remove_from_team_button.tsx b/webapp/channels/src/components/admin_console/manage_teams_modal/remove_from_team_button.tsx index 4b25c46a647..b38403ab081 100644 --- a/webapp/channels/src/components/admin_console/manage_teams_modal/remove_from_team_button.tsx +++ b/webapp/channels/src/components/admin_console/manage_teams_modal/remove_from_team_button.tsx @@ -4,7 +4,7 @@ import React from 'react'; import {FormattedMessage} from 'react-intl'; -import {Button} from '@mattermost/shared/components/button'; +import {Button} from '@mattermost/compass-ui/components/button'; type Props = { teamId: string; @@ -20,7 +20,7 @@ const RemoveFromTeamButton = ({teamId, handleRemoveUserFromTeam}: Props) => { return ( @@ -317,10 +321,14 @@ exports[`components/admin_console/manage_tokens_modal/manage_tokens_modal.tsx sh class="manage-teams__team-actions" > diff --git a/webapp/channels/src/components/admin_console/openid_convert/__snapshots__/openid_convert.test.tsx.snap b/webapp/channels/src/components/admin_console/openid_convert/__snapshots__/openid_convert.test.tsx.snap index b23f7b9e4e4..af247b0baf4 100644 --- a/webapp/channels/src/components/admin_console/openid_convert/__snapshots__/openid_convert.test.tsx.snap +++ b/webapp/channels/src/components/admin_console/openid_convert/__snapshots__/openid_convert.test.tsx.snap @@ -24,20 +24,29 @@ exports[`components/OpenIdConvert should match snapshot 1`] = ` class="OpenIdConvert_actionWrapper" > - Learn more + + Learn more +

- - +
((props, ref) => { + const {children, ...rest} = props; + return ( + + ); +}); +AddPermissionMenuTrigger.displayName = 'AddPermissionMenuTrigger'; + const roleMessages = defineMessages({ guestLabel: {id: 'admin.permission_policies.role.system_guest.label', defaultMessage: 'Guest users'}, guestDescription: {id: 'admin.permission_policies.role.system_guest.description', defaultMessage: 'Applies only to guest users'}, @@ -455,6 +475,7 @@ function PermissionPolicyDetails({ {/* "Who this policy applies to" */} @@ -528,6 +549,7 @@ function PermissionPolicyDetails({ {/* Attribute-based access rules */} @@ -664,6 +686,7 @@ function PermissionPolicyDetails({ {/* "What permissions are modified" */} @@ -728,15 +751,12 @@ function PermissionPolicyDetails({ - - - + ), }} menu={{ @@ -769,6 +789,7 @@ function PermissionPolicyDetails({ {policyId && ( @@ -791,6 +812,7 @@ function PermissionPolicyDetails({ defaultMessage='Delete' /> } + destructive={true} onClick={() => setShowDeleteConfirmationModal(true)} /> @@ -816,7 +838,7 @@ function PermissionPolicyDetails({ defaultMessage='Delete Policy' /> } - confirmButtonVariant='destructive' + destructive={true} compassDesign={true} > } /> - - - + + + + {serverError && ( diff --git a/webapp/channels/src/components/admin_console/permission_schemes_settings/__snapshots__/permission_schemes_settings.test.tsx.snap b/webapp/channels/src/components/admin_console/permission_schemes_settings/__snapshots__/permission_schemes_settings.test.tsx.snap index 1a51f86d033..92268038635 100644 --- a/webapp/channels/src/components/admin_console/permission_schemes_settings/__snapshots__/permission_schemes_settings.test.tsx.snap +++ b/webapp/channels/src/components/admin_console/permission_schemes_settings/__snapshots__/permission_schemes_settings.test.tsx.snap @@ -95,11 +95,15 @@ exports[`components/admin_console/permission_schemes_settings/permission_schemes class="button" > - Edit Scheme + + Edit Scheme +
@@ -134,11 +138,15 @@ exports[`components/admin_console/permission_schemes_settings/permission_schemes class="button" > - New Team Override Scheme + + New Team Override Scheme +
@@ -333,11 +341,15 @@ exports[`components/admin_console/permission_schemes_settings/permission_schemes class="button" > - Edit Scheme + + Edit Scheme + @@ -372,11 +384,15 @@ exports[`components/admin_console/permission_schemes_settings/permission_schemes class="button" > - New Team Override Scheme + + New Team Override Scheme + @@ -459,11 +475,16 @@ exports[`components/admin_console/permission_schemes_settings/permission_schemes class="button" > - Edit Scheme + + Edit Scheme + @@ -498,11 +519,16 @@ exports[`components/admin_console/permission_schemes_settings/permission_schemes class="button" > - New Team Override Scheme + + New Team Override Scheme + @@ -715,11 +741,16 @@ exports[`components/admin_console/permission_schemes_settings/permission_schemes class="button" > - Edit Scheme + + Edit Scheme + @@ -754,11 +785,16 @@ exports[`components/admin_console/permission_schemes_settings/permission_schemes class="button" > - New Team Override Scheme + + New Team Override Scheme + @@ -971,11 +1007,15 @@ exports[`components/admin_console/permission_schemes_settings/permission_schemes class="button" > - Edit Scheme + + Edit Scheme + @@ -1010,11 +1050,15 @@ exports[`components/admin_console/permission_schemes_settings/permission_schemes class="button" > - New Team Override Scheme + + New Team Override Scheme + diff --git a/webapp/channels/src/components/admin_console/permission_schemes_settings/edit_post_time_limit_modal/edit_post_time_limit_modal.tsx b/webapp/channels/src/components/admin_console/permission_schemes_settings/edit_post_time_limit_modal/edit_post_time_limit_modal.tsx index 1a5a6841aa0..7a10287133a 100644 --- a/webapp/channels/src/components/admin_console/permission_schemes_settings/edit_post_time_limit_modal/edit_post_time_limit_modal.tsx +++ b/webapp/channels/src/components/admin_console/permission_schemes_settings/edit_post_time_limit_modal/edit_post_time_limit_modal.tsx @@ -5,7 +5,7 @@ import React, {useState} from 'react'; import {Modal} from 'react-bootstrap'; import {FormattedMessage, useIntl} from 'react-intl'; -import {Button} from '@mattermost/shared/components/button'; +import {Button} from '@mattermost/compass-ui/components/button'; import type {AdminConfig} from '@mattermost/types/config'; import type {DeepPartial} from '@mattermost/types/utilities'; diff --git a/webapp/channels/src/components/admin_console/permission_schemes_settings/permission_system_scheme_settings/__snapshots__/permission_system_scheme_settings.test.tsx.snap b/webapp/channels/src/components/admin_console/permission_schemes_settings/permission_system_scheme_settings/__snapshots__/permission_system_scheme_settings.test.tsx.snap index 7bc60e4d5ff..56e63b00c5f 100644 --- a/webapp/channels/src/components/admin_console/permission_schemes_settings/permission_system_scheme_settings/__snapshots__/permission_system_scheme_settings.test.tsx.snap +++ b/webapp/channels/src/components/admin_console/permission_schemes_settings/permission_system_scheme_settings/__snapshots__/permission_system_scheme_settings.test.tsx.snap @@ -4206,28 +4206,39 @@ exports[`components/admin_console/permission_schemes_settings/permission_system_ class="admin-console-save" > - Cancel + + Cancel +
- Cancel + + Cancel +
- Cancel + + Cancel +
- Cancel + + Cancel +
, ); expect(ref.current!.state.showResetDefaultModal).toBe(false); - const resetButton = container.querySelector('.btn-quaternary'); + const resetButton = container.querySelector('[data-testid="resetPermissionsToDefault"]'); expect(resetButton).not.toBeNull(); act(() => { (resetButton as HTMLElement).click(); diff --git a/webapp/channels/src/components/admin_console/permission_schemes_settings/permission_system_scheme_settings/permission_system_scheme_settings.tsx b/webapp/channels/src/components/admin_console/permission_schemes_settings/permission_system_scheme_settings/permission_system_scheme_settings.tsx index 77021deb24a..668142721af 100644 --- a/webapp/channels/src/components/admin_console/permission_schemes_settings/permission_system_scheme_settings/permission_system_scheme_settings.tsx +++ b/webapp/channels/src/components/admin_console/permission_schemes_settings/permission_system_scheme_settings/permission_system_scheme_settings.tsx @@ -5,7 +5,7 @@ import React from 'react'; import type {WrappedComponentProps} from 'react-intl'; import {FormattedMessage, defineMessage, injectIntl} from 'react-intl'; -import {Button, buttonClassNames} from '@mattermost/shared/components/button'; +import {Button} from '@mattermost/compass-ui/components/button'; import type {ClientConfig, ClientLicense} from '@mattermost/types/config'; import type {Role} from '@mattermost/types/roles'; @@ -543,16 +543,18 @@ export class PermissionSystemSchemeSettings extends React.PureComponent - - - + + + +
diff --git a/webapp/channels/src/components/admin_console/plugin_management/__snapshots__/plugin_management.test.tsx.snap b/webapp/channels/src/components/admin_console/plugin_management/__snapshots__/plugin_management.test.tsx.snap index 616b4c86bb5..54f59a01302 100644 --- a/webapp/channels/src/components/admin_console/plugin_management/__snapshots__/plugin_management.test.tsx.snap +++ b/webapp/channels/src/components/admin_console/plugin_management/__snapshots__/plugin_management.test.tsx.snap @@ -554,13 +554,15 @@ exports[`components/PluginManagement should match snapshot 1`] = ` class="admin-console-save" > @@ -1130,13 +1132,15 @@ exports[`components/PluginManagement should match snapshot when \`Enable Marketp class="admin-console-save" > @@ -1203,13 +1207,15 @@ exports[`components/PluginManagement should match snapshot when \`Enable Plugins class="admin-console-save" > @@ -1777,13 +1783,15 @@ exports[`components/PluginManagement should match snapshot when \`Enable Remote class="admin-console-save" > @@ -2359,13 +2367,15 @@ exports[`components/PluginManagement should match snapshot when \`Require Signat class="admin-console-save" > @@ -2933,13 +2943,15 @@ exports[`components/PluginManagement should match snapshot, No installed plugins class="admin-console-save" > @@ -3506,13 +3518,15 @@ exports[`components/PluginManagement should match snapshot, allow insecure URL e class="admin-console-save" > @@ -4082,13 +4096,15 @@ exports[`components/PluginManagement should match snapshot, disabled 1`] = ` class="admin-console-save" > @@ -4655,13 +4671,15 @@ exports[`components/PluginManagement should match snapshot, text entered into th class="admin-console-save" > @@ -5249,13 +5267,15 @@ exports[`components/PluginManagement should match snapshot, upload disabled 1`] class="admin-console-save" > @@ -6105,13 +6125,15 @@ exports[`components/PluginManagement should match snapshot, with installed plugi class="admin-console-save" > @@ -6759,13 +6781,15 @@ exports[`components/PluginManagement should match snapshot, with installed plugi class="admin-console-save" > @@ -7413,13 +7437,15 @@ exports[`components/PluginManagement should match snapshot, with installed plugi class="admin-console-save" > @@ -8067,13 +8093,15 @@ exports[`components/PluginManagement should match snapshot, with installed plugi class="admin-console-save" > @@ -8907,13 +8935,15 @@ exports[`components/PluginManagement should match snapshot, with installed plugi class="admin-console-save" > diff --git a/webapp/channels/src/components/admin_console/plugin_management/plugin_management.tsx b/webapp/channels/src/components/admin_console/plugin_management/plugin_management.tsx index 2b3f4a99c22..ad6c575c0e7 100644 --- a/webapp/channels/src/components/admin_console/plugin_management/plugin_management.tsx +++ b/webapp/channels/src/components/admin_console/plugin_management/plugin_management.tsx @@ -1020,7 +1020,7 @@ export class PluginManagement extends OLDAdminSettings { show={show} title={title} message={message} - confirmButtonVariant='destructive' + destructive={true} confirmButtonText={removeButton} onConfirm={onConfirm} onCancel={onCancel} diff --git a/webapp/channels/src/components/admin_console/plugin_management/plugin_upload_overwrite_review_modal.tsx b/webapp/channels/src/components/admin_console/plugin_management/plugin_upload_overwrite_review_modal.tsx index f0b4e8a610d..0fd27ff35db 100644 --- a/webapp/channels/src/components/admin_console/plugin_management/plugin_upload_overwrite_review_modal.tsx +++ b/webapp/channels/src/components/admin_console/plugin_management/plugin_upload_overwrite_review_modal.tsx @@ -143,7 +143,7 @@ export default function PluginUploadOverwriteReviewModal({show, conflict, onConf show={show} title={title} message={renderReviewMessage(conflict)} - confirmButtonVariant={direction === 'downgrade' ? 'destructive' : undefined} + destructive={direction === 'downgrade'} confirmButtonText={overwriteButton} onConfirm={onConfirm} onCancel={onCancel} diff --git a/webapp/channels/src/components/admin_console/remove_file_setting.tsx b/webapp/channels/src/components/admin_console/remove_file_setting.tsx index a18be557625..18a788ae5ea 100644 --- a/webapp/channels/src/components/admin_console/remove_file_setting.tsx +++ b/webapp/channels/src/components/admin_console/remove_file_setting.tsx @@ -4,7 +4,7 @@ import React, {memo, useCallback, useState} from 'react'; import type {FC, MouseEvent} from 'react'; -import {Button} from '@mattermost/shared/components/button'; +import {Button} from '@mattermost/compass-ui/components/button'; import Setting from './setting'; import type {Props as SettingsProps} from './setting'; @@ -53,7 +53,7 @@ const RemoveFileSetting: FC = ({
{ emphasis={this.props.buttonEmphasis || 'tertiary'} onClick={this.handleRequest} disabled={this.props.disabled} + loading={this.state.busy} > - - ) - } - > - {this.props.buttonText} - + {this.state.busy ? ( + this.props.loadingText || + ( + + ) + ) : this.props.buttonText} {this.props.alternativeActionElement} {message} diff --git a/webapp/channels/src/components/admin_console/revoke_non_compliant_tokens_button/revoke_non_compliant_tokens_button.tsx b/webapp/channels/src/components/admin_console/revoke_non_compliant_tokens_button/revoke_non_compliant_tokens_button.tsx index 261f162f1a6..233d69b636a 100644 --- a/webapp/channels/src/components/admin_console/revoke_non_compliant_tokens_button/revoke_non_compliant_tokens_button.tsx +++ b/webapp/channels/src/components/admin_console/revoke_non_compliant_tokens_button/revoke_non_compliant_tokens_button.tsx @@ -4,6 +4,8 @@ import React, {useCallback, useEffect, useState} from 'react'; import {FormattedMessage} from 'react-intl'; +import {Button} from '@mattermost/compass-ui/components/button'; + import {Client4} from 'mattermost-redux/client'; import AlertBanner from 'components/alert_banner'; @@ -96,9 +98,9 @@ const RevokeNonCompliantTokensButton = ({disabled, registerSaveAction, unRegiste className='RevokeNonCompliantTokensButton' style={{display: 'flex', flexDirection: 'column', alignItems: 'flex-start', gap: '8px'}} > - + {error && ( )} - confirmButtonVariant='destructive' + destructive={true} confirmButtonText={( { return ( + {showCancel && ( + cancelLink ? ( + + ) : ( + + ) )}
; -export const LinkButton = styled.button.attrs({className: 'btn btn-link'})<{$destructive?: boolean}>` - font-weight: normal; - ${({$destructive}) => $destructive && css` - && { - color: #D24B4E; - } - `}; -`; +export const Button = ({style, ...props}: CompassButtonProps) => ( + +); + +export const LinkButton = ({ + $destructive, + style, + ...props +}: CompassButtonProps & {$destructive?: boolean}) => ( + +); export const ConnectionStatusLabel = ({rc}: {rc: RemoteCluster}) => { if (!isConfirmed(rc)) { diff --git a/webapp/channels/src/components/admin_console/secure_connections/modals/secure_connection_create_invite_modal.tsx b/webapp/channels/src/components/admin_console/secure_connections/modals/secure_connection_create_invite_modal.tsx index 5228ead19fb..def58fcfa95 100644 --- a/webapp/channels/src/components/admin_console/secure_connections/modals/secure_connection_create_invite_modal.tsx +++ b/webapp/channels/src/components/admin_console/secure_connections/modals/secure_connection_create_invite_modal.tsx @@ -5,6 +5,7 @@ import React, {useEffect, useState} from 'react'; import {FormattedMessage, useIntl} from 'react-intl'; import {CheckIcon, ContentCopyIcon} from '@mattermost/compass-icons/components'; +import {Icon} from '@mattermost/compass-ui/components/icon'; import {SectionNotice} from '@mattermost/compass-ui/components/section-notice'; import {GenericModal} from '@mattermost/components'; import type {RemoteCluster} from '@mattermost/types/remote_clusters'; @@ -146,8 +147,13 @@ function SecureConnectionCreateInviteModal({ data-testid='invite-code' readOnly={true} addon={( - )} /> @@ -165,8 +171,13 @@ function SecureConnectionCreateInviteModal({ data-testid='password' readOnly={done} addon={done ? ( - ) : undefined} @@ -178,18 +189,10 @@ function SecureConnectionCreateInviteModal({ ); } -const copy = ( - <> - - - -); +const copyIcon = }/>; +const copiedIcon = }/>; -const copied = ( - <> - - - -); +const copyLabel = ; +const copiedLabel = ; export default SecureConnectionCreateInviteModal; diff --git a/webapp/channels/src/components/admin_console/secure_connections/modals/secure_connection_delete_modal.tsx b/webapp/channels/src/components/admin_console/secure_connections/modals/secure_connection_delete_modal.tsx index 51d6b9f5cf7..101b329d9c2 100644 --- a/webapp/channels/src/components/admin_console/secure_connections/modals/secure_connection_delete_modal.tsx +++ b/webapp/channels/src/components/admin_console/secure_connections/modals/secure_connection_delete_modal.tsx @@ -47,7 +47,7 @@ function SecureConnectionDeleteModal({ return ( )} - confirmButtonVariant='destructive' + destructive={true} onExited={onExited} compassDesign={true} bodyPadding={false} diff --git a/webapp/channels/src/components/admin_console/secure_connections/secure_connection_detail.tsx b/webapp/channels/src/components/admin_console/secure_connections/secure_connection_detail.tsx index bef1df812c5..8074804b646 100644 --- a/webapp/channels/src/components/admin_console/secure_connections/secure_connection_detail.tsx +++ b/webapp/channels/src/components/admin_console/secure_connections/secure_connection_detail.tsx @@ -11,7 +11,8 @@ import {useHistory, useParams, useLocation} from 'react-router-dom'; import styled from 'styled-components'; import {PlusIcon} from '@mattermost/compass-icons/components'; -import {Button} from '@mattermost/shared/components/button'; +import {Button} from '@mattermost/compass-ui/components/button'; +import {Icon} from '@mattermost/compass-ui/components/icon'; import {isRemoteClusterPatch, type RemoteCluster} from '@mattermost/types/remote_clusters'; import {getChannel} from 'mattermost-redux/selectors/entities/channels'; @@ -291,13 +292,15 @@ function SharedChannelRemotes(props: {remoteId: string; rc: RemoteCluster | unde defaultMessage="A list of all the channels shared with your organization and channels you're sharing externally." /> - - + {showTabs && ( @@ -366,10 +369,6 @@ const Placeholder = (props: {filter: 'home' | 'remote'; rc: RemoteCluster}) => { ); }; -const AddChannelsButton = styled(Button)` - padding-left: 15px; -`; - const TabsWrapper = styled.div` .tabs { display: flex; diff --git a/webapp/channels/src/components/admin_console/secure_connections/secure_connection_row.tsx b/webapp/channels/src/components/admin_console/secure_connections/secure_connection_row.tsx index 69c4263c4bb..10c0db9a8f0 100644 --- a/webapp/channels/src/components/admin_console/secure_connections/secure_connection_row.tsx +++ b/webapp/channels/src/components/admin_console/secure_connections/secure_connection_row.tsx @@ -1,16 +1,18 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React from 'react'; +import React, {forwardRef} from 'react'; import {FormattedMessage, useIntl} from 'react-intl'; import {Link, useHistory} from 'react-router-dom'; import styled from 'styled-components'; import {DotsHorizontalIcon, CodeTagsIcon, PencilOutlineIcon, TrashCanOutlineIcon} from '@mattermost/compass-icons/components'; -import {buttonClassNames} from '@mattermost/shared/components/button'; +import {Icon} from '@mattermost/compass-ui/components/icon'; +import {IconButton} from '@mattermost/compass-ui/components/icon-button'; import type {RemoteCluster} from '@mattermost/types/remote_clusters'; import * as Menu from 'components/menu'; +import type {MenuButtonComponentProps} from 'components/menu'; import {ConnectionStatusLabel} from './controls'; import {useRemoteClusterCreateInvite, useRemoteClusterDelete} from './modals/modal_utils'; @@ -43,6 +45,17 @@ export default function SecureConnectionRow(props: Props) { const menuId = 'secure_connection_row_menu'; +const RowMenuTrigger = forwardRef((props, ref) => ( + }/>} + /> +)); +RowMenuTrigger.displayName = 'RowMenuTrigger'; + const RowMenu = ({remoteCluster: rc, onDeleteSuccess, disabled}: Props) => { const {formatMessage} = useIntl(); const history = useHistory(); @@ -65,9 +78,8 @@ const RowMenu = ({remoteCluster: rc, onDeleteSuccess, disabled}: Props) => { , 'aria-label': formatMessage({id: 'admin.secure_connection_row.menu-button.aria_label', defaultMessage: 'Connection options for {connection}'}, {connection: rc.display_name}), }} menu={{ @@ -131,10 +143,6 @@ const RowLink = styled(Link).attrs({className: 'secure-connection &:last-child { border-bottom: 0; } - - .connection-row-menu-button { - padding: 0px 8px; - } `; const Title = styled.strong` diff --git a/webapp/channels/src/components/admin_console/secure_connections/secure_connections.tsx b/webapp/channels/src/components/admin_console/secure_connections/secure_connections.tsx index ab8e49c5c29..a574720c224 100644 --- a/webapp/channels/src/components/admin_console/secure_connections/secure_connections.tsx +++ b/webapp/channels/src/components/admin_console/secure_connections/secure_connections.tsx @@ -2,16 +2,18 @@ // See LICENSE.txt for license information. import type {ReactNode} from 'react'; -import React from 'react'; +import React, {forwardRef} from 'react'; import {useIntl, FormattedMessage, defineMessages} from 'react-intl'; import {useHistory} from 'react-router-dom'; +import {ChevronDownIcon} from '@mattermost/compass-icons/components'; +import {Button, type ButtonEmphasis} from '@mattermost/compass-ui/components/button'; +import {Icon} from '@mattermost/compass-ui/components/icon'; import {SectionNotice} from '@mattermost/compass-ui/components/section-notice'; -import type {ButtonEmphasis} from '@mattermost/shared/components/button'; -import {buttonClassNames} from '@mattermost/shared/components/button'; import LoadingScreen from 'components/loading_screen'; import * as Menu from 'components/menu'; +import type {MenuButtonComponentProps} from 'components/menu'; import AdminHeader from 'components/widgets/admin_console/admin_header'; import BuildingSvg from './building.svg'; @@ -115,6 +117,28 @@ const Placeholder = ({disabled, serviceNotRunning}: {disabled: boolean; serviceN const menuId = 'secure_connections_add_menu'; +const makeAddConnectionMenuTrigger = (emphasis: ButtonEmphasis) => { + const Trigger = forwardRef((props, ref) => { + const {children, disabled, ...rest} = props; + return ( + + ); + }); + Trigger.displayName = 'AddConnectionMenuTrigger'; + return Trigger; +}; + +const AddConnectionPrimaryMenuTrigger = makeAddConnectionMenuTrigger('primary'); +const AddConnectionTertiaryMenuTrigger = makeAddConnectionMenuTrigger('tertiary'); + const AddMenu = ({buttonEmphasis = 'primary', disabled}: {buttonEmphasis?: ButtonEmphasis; disabled: boolean}) => { const {formatMessage} = useIntl(); const history = useHistory(); @@ -135,19 +159,9 @@ const AddMenu = ({buttonEmphasis = 'primary', disabled}: {buttonEmphasis?: Butto - - {!disabled && ( -