diff --git a/.changeset/fuselage-no-styling-props.md b/.changeset/fuselage-no-styling-props.md new file mode 100644 index 0000000000000..2e4e8ba0ccf00 --- /dev/null +++ b/.changeset/fuselage-no-styling-props.md @@ -0,0 +1,114 @@ +--- +'@rocket.chat/fuselage': minor +'@rocket.chat/fuselage-ui-kit': patch +'@rocket.chat/layout': patch +'@rocket.chat/meteor': patch +'@rocket.chat/onboarding-ui': patch +'@rocket.chat/ui-client': patch +'@rocket.chat/ui-composer': patch +'@rocket.chat/ui-voip': patch +'@rocket.chat/web-ui-registration': patch +--- + +Fuselage components no longer take Box styling props from their callers: containers own layout through `gap`, and components declare the variations they support. + +**fuselage** + +- `Button` accepts `compact`, which lowers its minimum width so a label of one or two characters fits. +- `ButtonGroup` accepts `stretch='equal'`, which stretches its buttons and gives them all the same width. +- Square buttons, such as `IconButton`, keep their size inside a `ButtonGroup` with `stretch` instead of growing with the other buttons. +- The icon inside a `Button` takes its spacing from the Button styles instead of a styling prop. +- `CardGrid` accepts `CardGridItem` children with their own column spans and a `minRowHeight`, and skips empty children instead of rendering empty cells. +- `CardGrid` stretches each card to the height of its row, so cards no longer need `height='full'`. +- `Chip` accepts `label`, which renders its text in uppercase for chips that categorize rather than select. +- `Chip` accepts `small`, which renders a 20px tall chip. +- Inputs with an addon have the same minimum height as the other inputs. +- `AutoComplete` and `MultiSelect` space their input and selected items with a 4px gap instead of wrapping them in `Margins`, so a `renderSelected` item no longer needs to forward its class name or bring its own margin to be spaced. +- Button and IconButton render only as a button or a link: `is` accepts `'button'` or `'a'`. +- Button and IconButton rendered as links no longer carry `type="button"`, and IconButton accepts `external` to open its link in a new tab. +- `Chip` has a fixed 28px height, so chips holding an inline avatar no longer grow past it; `small` chips stay 20px. +- Date and time inputs match the other inputs' height +- Adds a `flush` prop to `Divider` that removes its own margin, so its container sets the spacing. +- Adds a `light` variation to `Divider`, drawn with the `stroke-light` color. +- A vertical `Divider` with `variation='danger'` is drawn in the error colour instead of the default grey. +- Adds `small` and `stretch` props to the vertical `Divider`: `small` uses a 4px inline margin, `stretch` makes it as tall as its container. +- Adds a `justify='end'` variation to `FieldRow` that packs the row's content at the end of the line. +- Declares `color` on `Icon`, `MenuItemIcon` and `MessageStatusIndicatorItem`, restricted to the semantic text and status font tokens. +- Icons no longer shrink in a flex container. +- Adds `endAddonFlush` to `InputBox` and the inputs built on it, so a button in `endAddon` sits flush with the input edge without negative margins +- Adds a `transparent` flag to `ModalBackdrop` that drops its overlay colour. +- Declares `width` and `height` on `ModalHeroImage`, the size the image renders at. +- Adds a `variant` (`danger`, `warning`, `info`, `success`) to `ModalIcon` that tints the icon, and a `subtle` flag to `ModalTagline` that mutes its colour. +- Declares `width` and `height` on `Modal`, makes its `hidden` attribute hide it while keeping it mounted, and adds a `fill` mode to `ModalContent` that stretches the content to the modal's height. +- Adds `PopoverSurface`, the raised and scrolling surface of a dropdown or popover, which takes `maxHeight`, `flush` and `elevation` instead of `Box` styling props. +- Adds the `inverted` variation to `Skeleton`, for placeholders on a dark surface such as a tooltip. +- Adds `Stack`, a flex container that lays out its children in a row or a column spaced by `gap`, without taking `Box` styling props. +- TableCell renders only as a data or header cell: `is` accepts `'td'` or `'th'`. +- `Tag` now spaces its `icon` from the label, so the icon no longer needs a margin of its own. +- Adds a `flush` flag to `Tile` that drops its default padding, for surfaces whose content brings its own. +- Adds `badgePosition` to `IconButton`, which pins the badge to the top end (default) or bottom end corner. +- Fixes the `IconButton` badge jumping toward the button's center while the button is pressed; it now keeps its corner and moves 1px with the icon. +- `IconButton` accepts `color`, `'default'` or `'danger'`, which paints the icon with that font color. +- A Divider with a label no longer adds 20px of inline padding, so its bars run from edge to edge of its container. +- `SelectLegacy`, `SelectFiltered`, `PaginatedSelectFiltered` and `PaginatedMultiSelectFiltered` put `id` on their focusable control, so clicking a `FieldLabel` whose `htmlFor` points to that `id` focuses the field. +- `SelectLegacy`, `SelectFiltered`, `PaginatedSelectFiltered` and `PaginatedMultiSelectFiltered` put `aria-labelledby`, `aria-describedby` and `aria-invalid` on their focusable control instead of the wrapper, so screen readers announce the field's label instead of its placeholder. +- `MessageGenericPreviewIcon` takes its icon colour from the preview's styles and no longer accepts a `color` prop. +- Fixes `Select` adding an extra gap before its trigger when placed directly inside a container that spaces its children with `gap`. +- `TableCell` accepts `rowHeader`, which renders the cell as the header of its row, styled as the label of a key/value pair. +- `Table` accepts `columns`, which declares the width of each column once instead of on every cell. +- `Tabs` accepts `stretch`, which grows its items to fill the whole width. + +**fuselage-ui-kit** + +- The `context` block spaces its elements with an 8px column gap instead of margins, so it no longer overhangs the surface edges and its images sit 8px from their neighbours. +- The `linear_scale` element spaces its buttons with the button group's gap alone, so they sit 8px apart instead of 12px. +- UiKit surfaces space their blocks with a 16px gap instead of per-block margins, so blocks sit 16px apart, divider and tabs no longer add their own 24px margins, and only the message surface keeps 16px of space after its last block. +- Colours UiKit icon elements with `danger`, `warning` and `secondary` variants through Fuselage's `Icon` `color`; `secondary` now uses the hint colour. + +**layout** + +- `Form` renders a form element that wraps its `Tile`, instead of rendering the `Tile` itself as the form. +- Narrows `ListItem`'s `iconColor` to a status (`hint`, `info`, `danger`, `warning` or `success`); without one the icon follows the item's text colour, as it already did. +- `VerticalWizardLayoutForm` sizes its `Tile` with a full-width wrapper instead of a `width` prop on `Tile`. + +**meteor** + +- When an app has no price, its status tags on the details page sit 8px closer to the Buy button. +- The author row of quote and message attachments spaces its avatar, name, timestamp and jump link 4px apart. +- Audited messages on the Message auditing page no longer inherit an extra vertical margin, so each one is 8px shorter. +- The contact details panel no longer draws a divider above the custom fields; they follow the other fields with the same spacing. +- The custom emoji upload button and the canned response preview toggle sit next to their label in a `FieldRow` instead of inside the label. +- Form labels in the thread composer, the workspace registration terms, the onboarding terms and the new-user password options use the default field label typography, and the close-chat modal note is shown as a field hint. +- Fixes the "Counters" header of the import history table so it also spans the "Total" column. +- Fixes the instances modal announcing each property name as a column header instead of a row header +- Colours the icons of the room priority menu like the priority icon shown in the room, by the priority's status. +- The room header leaves 4px instead of 8px after the encrypted and translated status icons. +- Fixes the user menu button so screen readers announce the user's current status and its changes. + +**onboarding-ui** + +- The cloud workspace form spaces its server region and language fields with padding around the grid instead of a margin on it, which adds 24 to 32px of height to the form. + +**ui-client** + +- Fixes the warning and success icons of `GenericModal` showing in the default text colour instead of their status colours. +- `HeaderTagIcon` no longer carries a trailing margin; pass it to `HeaderTag`'s `icon` prop, which spaces it from the text. +- Page header spaces its sidebar toggler and back button with gap; `SidebarToggler` no longer carries a trailing margin. +- `HeaderContentRow` spaces its items 4px apart, and `HeaderState` no longer adds its own trailing margin. +- The `MultiSelectCustom` list is drawn on Fuselage's `PopoverSurface`, so its corners are rounded like the other dropdowns. + +**ui-composer** + +- `MessageFooterCallout` spaces its children with an 8px gap instead of margins on `MessageComposerIcon`, `MessageFooterCalloutContent`, `MessageFooterCalloutDivider` and `MessageFooterCalloutAction`, so the action button now sits flush with the callout padding. + +**ui-voip** + +- Call history footer buttons lay out their icon and label with gap. +- The keypad keys take their size and corner radius from their own class instead of styling props on `Button`. +- Call widget info slots lay out their icon and text with gap. + +**web-ui-registration** + +- The desktop app's "Log in on the web" button sits in the same button group as the login services. +- The login services divider takes its spacing from a padded container. +- The login language switch buttons are spaced with an 8px gap instead of a trailing margin, so they are centred in the footer. diff --git a/.github/workflows/ci-code-check.yml b/.github/workflows/ci-code-check.yml index 4fee1415ab08e..4250699f86bdc 100644 --- a/.github/workflows/ci-code-check.yml +++ b/.github/workflows/ci-code-check.yml @@ -101,11 +101,11 @@ jobs: - name: Styling props on Fuselage components if: matrix.check == 'lint' - run: node scripts/scan-style-props.mjs --max 914 "$RUNNER_TEMP/style-props-findings.json" + run: node scripts/scan-style-props.mjs --max 1 "$RUNNER_TEMP/style-props-findings.json" - name: Raw layout elements in screens if: matrix.check == 'lint' - run: node scripts/scan-raw-layout.mjs --max 1166 "$RUNNER_TEMP/raw-layout-findings.json" + run: node scripts/scan-raw-layout.mjs --max 1248 "$RUNNER_TEMP/raw-layout-findings.json" - name: Stylelint if: matrix.check == 'lint' diff --git a/apps/meteor/client/components/ABAC/AbacAttributesRemovalWarning.tsx b/apps/meteor/client/components/ABAC/AbacAttributesRemovalWarning.tsx index dfe6c9a790616..14b3e311f18e8 100644 --- a/apps/meteor/client/components/ABAC/AbacAttributesRemovalWarning.tsx +++ b/apps/meteor/client/components/ABAC/AbacAttributesRemovalWarning.tsx @@ -12,7 +12,7 @@ const AbacAttributesRemovalWarning = ({ roomNames }: AbacAttributesRemovalWarnin const enforcementOn = useIsAbacEnforcementOn(); return ( - + {roomNames ? t('ABAC_Attributes_will_be_removed_from_rooms', { rooms: roomNames.join(', ') }) : t('ABAC_Attributes_will_be_removed')} {enforcementOn && ` ${roomNames ? t('ABAC_Rooms_locked_until_attributes_reassigned') : t('ABAC_Room_locked_until_attributes_reassigned')}`} diff --git a/apps/meteor/client/components/ABAC/AbacMembershipPreview/AbacMembershipPreview.tsx b/apps/meteor/client/components/ABAC/AbacMembershipPreview/AbacMembershipPreview.tsx index f78ba6984824a..8dabec490d27d 100644 --- a/apps/meteor/client/components/ABAC/AbacMembershipPreview/AbacMembershipPreview.tsx +++ b/apps/meteor/client/components/ABAC/AbacMembershipPreview/AbacMembershipPreview.tsx @@ -17,9 +17,9 @@ const AbacMembershipPreview = ({ data, isPending, isError, error }: AbacMembersh if (isPending) { return ( - + {Array.from({ length: 4 }, (_, index) => ( - + ))} ); @@ -33,27 +33,13 @@ const AbacMembershipPreview = ({ data, isPending, isError, error }: AbacMembersh const hasCompliant = compliant.length > 0; return ( - - {!hasCompliant && ( - - {t('ABAC_Preview_No_Compliant_Members')} - - )} + + {!hasCompliant && {t('ABAC_Preview_No_Compliant_Members')}} {hasCompliant && (nonCompliant.length > 0 || inconclusive.length > 0) && ( - - {t('ABAC_Preview_Only_Compliant_Added')} - - )} - {hasCompliant && creator === 'nonCompliant' && ( - - {t('ABAC_Preview_Creator_Not_Added')} - - )} - {inconclusive.length > 0 && ( - - {t('ABAC_Preview_Inconclusive_Warning')} - + {t('ABAC_Preview_Only_Compliant_Added')} )} + {hasCompliant && creator === 'nonCompliant' && {t('ABAC_Preview_Creator_Not_Added')}} + {inconclusive.length > 0 && {t('ABAC_Preview_Inconclusive_Warning')}} diff --git a/apps/meteor/client/components/ABAC/AbacMembershipPreview/AbacPreviewMemberGroup.tsx b/apps/meteor/client/components/ABAC/AbacMembershipPreview/AbacPreviewMemberGroup.tsx index 0e225c493a89b..84da410806c42 100644 --- a/apps/meteor/client/components/ABAC/AbacMembershipPreview/AbacPreviewMemberGroup.tsx +++ b/apps/meteor/client/components/ABAC/AbacMembershipPreview/AbacPreviewMemberGroup.tsx @@ -21,12 +21,12 @@ const AbacPreviewMemberGroup = ({ title, members, verdict }: AbacPreviewMemberGr } return ( - + {title} {members.length} - + {members.map(({ _id, username, name }) => ( @@ -35,7 +35,7 @@ const AbacPreviewMemberGroup = ({ title, members, verdict }: AbacPreviewMemberGr )} - + {name || username} @@ -45,16 +45,7 @@ const AbacPreviewMemberGroup = ({ title, members, verdict }: AbacPreviewMemberGr )} - + ))} diff --git a/apps/meteor/client/components/ABAC/AbacRoomCreation/CreateRoomModalSkeleton.tsx b/apps/meteor/client/components/ABAC/AbacRoomCreation/CreateRoomModalSkeleton.tsx index ff6833ddf7d54..fd880d48fdb38 100644 --- a/apps/meteor/client/components/ABAC/AbacRoomCreation/CreateRoomModalSkeleton.tsx +++ b/apps/meteor/client/components/ABAC/AbacRoomCreation/CreateRoomModalSkeleton.tsx @@ -1,4 +1,4 @@ -import { InputBoxSkeleton, Modal, ModalClose, ModalContent, ModalHeader, ModalTitle } from '@rocket.chat/fuselage'; +import { Box, InputBoxSkeleton, Modal, ModalClose, ModalContent, ModalHeader, ModalTitle } from '@rocket.chat/fuselage'; import { useTranslation } from 'react-i18next'; type CreateRoomModalSkeletonProps = { @@ -15,10 +15,12 @@ const CreateRoomModalSkeleton = ({ title, onClose }: CreateRoomModalSkeletonProp {title} - - {Array.from({ length: 4 }, (_, index) => ( - - ))} + + + {Array.from({ length: 4 }, (_, index) => ( + + ))} + ); diff --git a/apps/meteor/client/components/ABAC/AbacRoomCreation/CreateRoomSteps.tsx b/apps/meteor/client/components/ABAC/AbacRoomCreation/CreateRoomSteps.tsx index cce8a0bc9d874..3568a07d18853 100644 --- a/apps/meteor/client/components/ABAC/AbacRoomCreation/CreateRoomSteps.tsx +++ b/apps/meteor/client/components/ABAC/AbacRoomCreation/CreateRoomSteps.tsx @@ -1,6 +1,7 @@ import { Accordion, AccordionItem, + Box, Button, ModalContent, ModalFooter, @@ -32,34 +33,36 @@ const CreateRoomSteps = ({ abac, flow, details, security, onCancel, submitDisabl return ( <> - - {step === 'details' && ( - <> - {details} - {!isStepped && ( - - {security} - - )} - - )} - {step === 'attributes' && ( - - )} - {step === 'security' && security} - {step === 'preview' && ( - - )} + + + {step === 'details' && ( + <> + {details} + {!isStepped && ( + + {security} + + )} + + )} + {step === 'attributes' && ( + + )} + {step === 'security' && security} + {step === 'preview' && ( + + )} + {isStepped && {t('Step_of_total', { step: index + 1, total })}} diff --git a/apps/meteor/client/components/ABAC/AbacRoomMembershipPreview/AbacRoomPreviewLoadMore.tsx b/apps/meteor/client/components/ABAC/AbacRoomMembershipPreview/AbacRoomPreviewLoadMore.tsx index 15d77be73fa8b..433890dfb5dee 100644 --- a/apps/meteor/client/components/ABAC/AbacRoomMembershipPreview/AbacRoomPreviewLoadMore.tsx +++ b/apps/meteor/client/components/ABAC/AbacRoomMembershipPreview/AbacRoomPreviewLoadMore.tsx @@ -10,8 +10,8 @@ const AbacRoomPreviewLoadMore = ({ context }: { context?: AbacRoomPreviewLoadMor const { t } = useTranslation(); return ( - - diff --git a/apps/meteor/client/components/ABAC/AbacRoomMembershipPreview/AbacRoomPreviewMemberRow.tsx b/apps/meteor/client/components/ABAC/AbacRoomMembershipPreview/AbacRoomPreviewMemberRow.tsx index 10814fa96bdbd..d94eedac6251e 100644 --- a/apps/meteor/client/components/ABAC/AbacRoomMembershipPreview/AbacRoomPreviewMemberRow.tsx +++ b/apps/meteor/client/components/ABAC/AbacRoomMembershipPreview/AbacRoomPreviewMemberRow.tsx @@ -35,7 +35,7 @@ const AbacRoomPreviewMemberRow = ({ member: { username, name, verdict, roles = [ )} - + {name || username} @@ -52,7 +52,7 @@ const AbacRoomPreviewMemberRow = ({ member: { username, name, verdict, roles = [ )} - + ); }; diff --git a/apps/meteor/client/components/ABAC/AbacRoomMembershipPreview/AbacRoomPreviewSkeleton.tsx b/apps/meteor/client/components/ABAC/AbacRoomMembershipPreview/AbacRoomPreviewSkeleton.tsx index 9681f1f43fa06..54bb82db7fdf1 100644 --- a/apps/meteor/client/components/ABAC/AbacRoomMembershipPreview/AbacRoomPreviewSkeleton.tsx +++ b/apps/meteor/client/components/ABAC/AbacRoomMembershipPreview/AbacRoomPreviewSkeleton.tsx @@ -3,9 +3,17 @@ import { Box, Skeleton } from '@rocket.chat/fuselage'; const AbacRoomPreviewSkeleton = () => ( <> {Array.from({ length: 3 }, (_, index) => ( - - - + + + ))} diff --git a/apps/meteor/client/components/Backdrop.tsx b/apps/meteor/client/components/Backdrop.tsx index a3ed3ea4001ef..29efaa8fde17c 100644 --- a/apps/meteor/client/components/Backdrop.tsx +++ b/apps/meteor/client/components/Backdrop.tsx @@ -3,4 +3,4 @@ import type { ComponentProps } from 'react'; export type BackdropProps = ComponentProps; -export const Backdrop = (props: BackdropProps) => ; +export const Backdrop = (props: BackdropProps) => ; diff --git a/apps/meteor/client/components/FilterByText.tsx b/apps/meteor/client/components/FilterByText.tsx index 4a1cb35a44b53..50d86f26a8df6 100644 --- a/apps/meteor/client/components/FilterByText.tsx +++ b/apps/meteor/client/components/FilterByText.tsx @@ -24,14 +24,12 @@ const FilterByText = forwardRef(function Fi return ( - + } - flexGrow={2} - minWidth='x220' aria-label={placeholder ?? t('Search')} /> diff --git a/apps/meteor/client/components/ImageGallery/ImageGallery.tsx b/apps/meteor/client/components/ImageGallery/ImageGallery.tsx index cb8fb1878c421..3a8467b20deeb 100644 --- a/apps/meteor/client/components/ImageGallery/ImageGallery.tsx +++ b/apps/meteor/client/components/ImageGallery/ImageGallery.tsx @@ -135,27 +135,18 @@ export const ImageGallery = ({
{zoomScale !== 1 && ( - + )} - + void }) => { const { t } = useTranslation(); return createPortal( - - - + + + + + , document.body, ); diff --git a/apps/meteor/client/components/ImageGallery/ImageGalleryLoading.tsx b/apps/meteor/client/components/ImageGallery/ImageGalleryLoading.tsx index a27a56096861d..eb465fc20c96e 100644 --- a/apps/meteor/client/components/ImageGallery/ImageGalleryLoading.tsx +++ b/apps/meteor/client/components/ImageGallery/ImageGalleryLoading.tsx @@ -1,5 +1,5 @@ import { css } from '@rocket.chat/css-in-js'; -import { IconButton, ModalBackdrop, Throbber } from '@rocket.chat/fuselage'; +import { Box, IconButton, ModalBackdrop, Throbber } from '@rocket.chat/fuselage'; import { createPortal } from 'react-dom'; import { useTranslation } from 'react-i18next'; @@ -14,9 +14,11 @@ export const ImageGalleryLoading = ({ onClose }: { onClose: () => void }) => { const { t } = useTranslation(); return createPortal( - - - + + + + + , document.body, ); diff --git a/apps/meteor/client/components/PageSkeleton.tsx b/apps/meteor/client/components/PageSkeleton.tsx index 19f7b682fad55..0d30c5b8dfffe 100644 --- a/apps/meteor/client/components/PageSkeleton.tsx +++ b/apps/meteor/client/components/PageSkeleton.tsx @@ -3,7 +3,7 @@ import { Page, PageHeader, PageContent } from '@rocket.chat/ui-client'; const PageSkeleton = () => ( - }> + }> + + + + {t('Enter_the_code_we_just_emailed_you')} + + ( + { + clearErrors('code'); + onChange(e); + }} + placeholder={t('Enter_code_here')} + autoComplete='one-time-code' + inputMode='numeric' + disabled={isSubmitting} + error={errors.code?.message} + /> + )} + /> + + {errors.code && {errors.code.message}} + + + + + + ); }; diff --git a/apps/meteor/client/components/UserAndRoomAutoCompleteMultiple/UserAndRoomAutoCompleteMultiple.tsx b/apps/meteor/client/components/UserAndRoomAutoCompleteMultiple/UserAndRoomAutoCompleteMultiple.tsx index 22632b7bf6284..d36ab63f5b5e0 100644 --- a/apps/meteor/client/components/UserAndRoomAutoCompleteMultiple/UserAndRoomAutoCompleteMultiple.tsx +++ b/apps/meteor/client/components/UserAndRoomAutoCompleteMultiple/UserAndRoomAutoCompleteMultiple.tsx @@ -105,7 +105,7 @@ const UserAndRoomAutoCompleteMultiple = ({ setFilter={setFilter} multiple renderSelected={({ selected: { value, label }, onRemove, ...props }) => ( - + {label.name} diff --git a/apps/meteor/client/components/UserAutoCompleteMultiple/UserAutoCompleteMultiple.tsx b/apps/meteor/client/components/UserAutoCompleteMultiple/UserAutoCompleteMultiple.tsx index 8a65bcb2d4e58..64c853a32148d 100644 --- a/apps/meteor/client/components/UserAutoCompleteMultiple/UserAutoCompleteMultiple.tsx +++ b/apps/meteor/client/components/UserAutoCompleteMultiple/UserAutoCompleteMultiple.tsx @@ -107,8 +107,6 @@ const UserAutoCompleteMultiple = forwardRef & { const UserAvatarChip = ({ federated, username, name, ...props }: UserAvatarChipProps) => { const displayName = useUserDisplayName({ name, username }); return ( - - {federated ? : } - + + + {federated ? : } {displayName} diff --git a/apps/meteor/client/components/UserStatusDisabledInfo.tsx b/apps/meteor/client/components/UserStatusDisabledInfo.tsx index 8e103c2a3469d..8f291e16fc6e9 100644 --- a/apps/meteor/client/components/UserStatusDisabledInfo.tsx +++ b/apps/meteor/client/components/UserStatusDisabledInfo.tsx @@ -9,8 +9,8 @@ const UserStatusDisabledInfo = ({ workspace }: UserStatusDisabledInfoProps) => { const reason = workspace ? t('User_status_disabled_on_this_workspace') : t('User_status_disabled_by_an_admin'); return ( - - + + ); }; diff --git a/apps/meteor/client/components/UserStatusMenu.tsx b/apps/meteor/client/components/UserStatusMenu.tsx index 2ced358d5d0de..748c75490fc8b 100644 --- a/apps/meteor/client/components/UserStatusMenu.tsx +++ b/apps/meteor/client/components/UserStatusMenu.tsx @@ -11,16 +11,10 @@ import { UserStatus } from './UserStatus'; export type UserStatusMenuProps = { onChange: (type: UserStatusType) => void; initialStatus?: UserStatusType; - optionWidth?: ComponentProps['width']; placement?: ComponentProps['placement']; }; -const UserStatusMenu = ({ - onChange, - initialStatus = UserStatusType.OFFLINE, - optionWidth = undefined, - placement = 'bottom-start', -}: UserStatusMenuProps) => { +const UserStatusMenu = ({ onChange, initialStatus = UserStatusType.OFFLINE, placement = 'bottom-start' }: UserStatusMenuProps) => { const { t } = useTranslation(); const [status, setStatus] = useState(initialStatus); const allowInvisibleStatus = useSetting('Accounts_AllowInvisibleStatusOption', true); @@ -92,7 +86,7 @@ const UserStatusMenu = ({ - + ); diff --git a/apps/meteor/client/components/UserStatusText/UserStatusText.tsx b/apps/meteor/client/components/UserStatusText/UserStatusText.tsx index a8ee963b06564..4e7f11673146c 100644 --- a/apps/meteor/client/components/UserStatusText/UserStatusText.tsx +++ b/apps/meteor/client/components/UserStatusText/UserStatusText.tsx @@ -35,8 +35,8 @@ const UserStatusText = ({ status, statusText, statusExpiresAt }: UserStatusTextP <> {headline && } {expirationText && ( - - + + {expirationText} )} diff --git a/apps/meteor/client/components/WarningModal.tsx b/apps/meteor/client/components/WarningModal.tsx index 4290696221a1d..db23a3371e90a 100644 --- a/apps/meteor/client/components/WarningModal.tsx +++ b/apps/meteor/client/components/WarningModal.tsx @@ -26,11 +26,11 @@ const WarningModal = ({ text, confirmText, close, cancel, cancelText, confirm, . return ( - + {t('Are_you_sure')} - {text} + {text} - + @@ -126,18 +126,8 @@ function UserAvatarEditor({ currentUsername, username, setAvatarObj, name, disab - } + endAddonFlush + endAddon={} disabled={disabled} value={avatarFromUrl} onChange={handleAvatarFromUrlChange} diff --git a/apps/meteor/client/components/avatar/UserAvatarEditor/UserAvatarSuggestions.tsx b/apps/meteor/client/components/avatar/UserAvatarEditor/UserAvatarSuggestions.tsx index 5587c83ad2b77..198c85f759b16 100644 --- a/apps/meteor/client/components/avatar/UserAvatarEditor/UserAvatarSuggestions.tsx +++ b/apps/meteor/client/components/avatar/UserAvatarEditor/UserAvatarSuggestions.tsx @@ -19,7 +19,7 @@ function UserAvatarSuggestions({ disabled, onSelectOne }: UserAvatarSuggestionsP {suggestions.map( (suggestion) => suggestion.blob && ( - ), diff --git a/apps/meteor/client/components/dashboards/DownloadDataButton.tsx b/apps/meteor/client/components/dashboards/DownloadDataButton.tsx index 1c737ddb3430b..b3946b736bb4d 100644 --- a/apps/meteor/client/components/dashboards/DownloadDataButton.tsx +++ b/apps/meteor/client/components/dashboards/DownloadDataButton.tsx @@ -1,4 +1,3 @@ -import type { Box } from '@rocket.chat/fuselage'; import { IconButton } from '@rocket.chat/fuselage'; import { useToastMessageDispatch } from '@rocket.chat/ui-contexts'; import type { ComponentProps } from 'react'; @@ -15,7 +14,7 @@ type DownloadDataButtonProps = { headers: RowFor; dataAvailable: boolean; dataExtractor: () => Promise[] | undefined> | RowFor[] | undefined; -} & Omit, 'attachmentName' | 'headers' | 'data'>; +} & Omit, 'icon' | 'attachmentName' | 'headers' | 'data'>; const DownloadDataButton = ({ attachmentName, diff --git a/apps/meteor/client/components/deviceManagement/DeviceIcon.tsx b/apps/meteor/client/components/deviceManagement/DeviceIcon.tsx index 00e28d5f765fd..dc4265bbbe811 100644 --- a/apps/meteor/client/components/deviceManagement/DeviceIcon.tsx +++ b/apps/meteor/client/components/deviceManagement/DeviceIcon.tsx @@ -18,11 +18,12 @@ const DeviceIcon = ({ deviceType }: DeviceIconProps) => ( justifyContent='center' padding={4} backgroundColor='selected' + color='hint' size='x24' borderRadius='full' marginInlineEnd={8} > - + ); diff --git a/apps/meteor/client/components/message/MessageCollapsible.tsx b/apps/meteor/client/components/message/MessageCollapsible.tsx index f2dab78b68284..739860e130131 100644 --- a/apps/meteor/client/components/message/MessageCollapsible.tsx +++ b/apps/meteor/client/components/message/MessageCollapsible.tsx @@ -1,4 +1,4 @@ -import { Box } from '@rocket.chat/fuselage'; +import { Box, ButtonGroup } from '@rocket.chat/fuselage'; import type { ReactNode } from 'react'; import AttachmentDownload from './content/attachments/structure/AttachmentDownload'; @@ -20,13 +20,15 @@ const MessageCollapsible = ({ children, title, hasDownload, link, size, isCollap return ( <> - + {title} {size && }{' '} - - {hasDownload && link && } + + + {hasDownload && link && } + {!collapsed && children} diff --git a/apps/meteor/client/components/message/ReadReceiptIndicator.tsx b/apps/meteor/client/components/message/ReadReceiptIndicator.tsx index 987b5813be129..c5d7145721b69 100644 --- a/apps/meteor/client/components/message/ReadReceiptIndicator.tsx +++ b/apps/meteor/client/components/message/ReadReceiptIndicator.tsx @@ -18,8 +18,9 @@ const ReadReceiptIndicator = ({ mid, unread }: ReadReceiptIndicatorProps) => { position='absolute' insetBlockStart={2} insetInlineEnd={8} + color={unread ? 'secondary-info' : 'info'} > - + ); }; diff --git a/apps/meteor/client/components/message/content/Action.tsx b/apps/meteor/client/components/message/content/Action.tsx index c1000302829af..88db3c3f32a02 100644 --- a/apps/meteor/client/components/message/content/Action.tsx +++ b/apps/meteor/client/components/message/content/Action.tsx @@ -3,6 +3,6 @@ import type { ComponentProps } from 'react'; export type ActionProps = ComponentProps & { icon: string }; -const Action = (props: ActionProps) => ; +const Action = (props: ActionProps) => ; export default Action; diff --git a/apps/meteor/client/components/message/content/MessageActions.tsx b/apps/meteor/client/components/message/content/MessageActions.tsx index 264500df84677..298775f16e1ba 100644 --- a/apps/meteor/client/components/message/content/MessageActions.tsx +++ b/apps/meteor/client/components/message/content/MessageActions.tsx @@ -29,8 +29,8 @@ const MessageActions = ({ message, actions }: MessageActionsProps) => { const alignment = actions[0]?.actionLinksAlignment || 'center'; return ( - - + + {actions.map((action, key) => ( ))} diff --git a/apps/meteor/client/components/message/content/ThreadMetrics.tsx b/apps/meteor/client/components/message/content/ThreadMetrics.tsx index b1be9ee7830ca..cdc518f01affc 100644 --- a/apps/meteor/client/components/message/content/ThreadMetrics.tsx +++ b/apps/meteor/client/components/message/content/ThreadMetrics.tsx @@ -40,14 +40,7 @@ const ThreadMetrics = ({ unread, mention, all, rid, mid, counter, participants, return ( - goToThread({ rid, tmid: mid })} - primary={!!unread} - position='relative' - overflow='visible' - > + goToThread({ rid, tmid: mid })} primary={!!unread}> {t('View_thread')} diff --git a/apps/meteor/client/components/message/content/UrlPreviews.tsx b/apps/meteor/client/components/message/content/UrlPreviews.tsx index 3981e10ff35da..3c0b628c6ed5e 100644 --- a/apps/meteor/client/components/message/content/UrlPreviews.tsx +++ b/apps/meteor/client/components/message/content/UrlPreviews.tsx @@ -1,7 +1,7 @@ import type { IMessage } from '@rocket.chat/core-typings'; import { MessageBlock } from '@rocket.chat/fuselage'; +import { useLayout } from '@rocket.chat/ui-contexts'; -import { useOembedLayout } from '../hooks/useOembedLayout'; import type { OEmbedPreviewMetadata } from './urlPreviews/OEmbedPreviewMetadata'; import OEmbedResolver from './urlPreviews/OEmbedResolver'; import UrlPreview from './urlPreviews/UrlPreview'; @@ -107,7 +107,7 @@ const isMetaPreview = (_data: PreviewData['data'], type: PreviewTypes): _data is export type UrlPreviewsProps = { urls: OembedUrlLegacy[] }; const UrlPreviews = ({ urls }: UrlPreviewsProps) => { - const { maxWidth: oembedMaxWidth } = useOembedLayout(); + const { isMobile } = useLayout(); const metaAndHeaders = urls.map(processMetaAndHeaders).filter(isPreviewData); return ( @@ -115,13 +115,13 @@ const UrlPreviews = ({ urls }: UrlPreviewsProps) => { {metaAndHeaders.map(({ type, data }, index) => { if (isMetaPreview(data, type)) { return ( - + ); } return ( - + ); diff --git a/apps/meteor/client/components/message/content/actions/MessageAction.tsx b/apps/meteor/client/components/message/content/actions/MessageAction.tsx index 24f5520eb063c..86c80bbfa5abb 100644 --- a/apps/meteor/client/components/message/content/actions/MessageAction.tsx +++ b/apps/meteor/client/components/message/content/actions/MessageAction.tsx @@ -26,7 +26,7 @@ const MessageAction = ({ icon, methodId, i18nLabel, label, runAction, danger }: const resolvedIcon = resolveLegacyIcon(icon); return ( - ); diff --git a/apps/meteor/client/components/message/content/attachments/DefaultAttachment.tsx b/apps/meteor/client/components/message/content/attachments/DefaultAttachment.tsx index 3e3240e90a2d5..1c23df9e31079 100644 --- a/apps/meteor/client/components/message/content/attachments/DefaultAttachment.tsx +++ b/apps/meteor/client/components/message/content/attachments/DefaultAttachment.tsx @@ -58,7 +58,7 @@ const DefaultAttachment = ({ collapseKey, ...attachment }: DefaultAttachmentProp )} {attachment.title && ( - + ; const AttachmentAuthor = (props: AttachmentAuthorProps) => ( - + ); export default AttachmentAuthor; diff --git a/apps/meteor/client/components/message/content/attachments/structure/AttachmentAuthorName.tsx b/apps/meteor/client/components/message/content/attachments/structure/AttachmentAuthorName.tsx index adc84cd6c1d82..3c9caf066b83a 100644 --- a/apps/meteor/client/components/message/content/attachments/structure/AttachmentAuthorName.tsx +++ b/apps/meteor/client/components/message/content/attachments/structure/AttachmentAuthorName.tsx @@ -3,6 +3,6 @@ import type { ComponentPropsWithoutRef } from 'react'; export type AttachmentAuthorNameProps = ComponentPropsWithoutRef; -const AttachmentAuthorName = (props: AttachmentAuthorNameProps) => ; +const AttachmentAuthorName = (props: AttachmentAuthorNameProps) => ; export default AttachmentAuthorName; diff --git a/apps/meteor/client/components/message/content/attachments/structure/AttachmentMessageLink.tsx b/apps/meteor/client/components/message/content/attachments/structure/AttachmentMessageLink.tsx index 364fac0fda37a..91c02a8ddc847 100644 --- a/apps/meteor/client/components/message/content/attachments/structure/AttachmentMessageLink.tsx +++ b/apps/meteor/client/components/message/content/attachments/structure/AttachmentMessageLink.tsx @@ -1,14 +1,13 @@ -import type { Box } from '@rocket.chat/fuselage'; import { IconButton } from '@rocket.chat/fuselage'; import type { ComponentPropsWithoutRef } from 'react'; import { useTranslation } from 'react-i18next'; -type AttachmentAuthorMessageLinkProps = ComponentPropsWithoutRef; +type AttachmentAuthorMessageLinkProps = Omit, 'icon' | 'is'>; const AttachmentAuthorMessageLink = ({ href, ...props }: AttachmentAuthorMessageLinkProps) => { const { t } = useTranslation(); - return ; + return ; }; export default AttachmentAuthorMessageLink; diff --git a/apps/meteor/client/components/message/content/attachments/structure/image/Load.tsx b/apps/meteor/client/components/message/content/attachments/structure/image/Load.tsx index e803e09150c85..ac6d6c9819c17 100644 --- a/apps/meteor/client/components/message/content/attachments/structure/image/Load.tsx +++ b/apps/meteor/client/components/message/content/attachments/structure/image/Load.tsx @@ -19,8 +19,8 @@ const Load = ({ load, ...props }: LoadProps) => { } `; return ( - - + + {t('Click_to_load')} diff --git a/apps/meteor/client/components/message/content/attachments/structure/image/Retry.tsx b/apps/meteor/client/components/message/content/attachments/structure/image/Retry.tsx index abe48ec135a04..c555493eaa638 100644 --- a/apps/meteor/client/components/message/content/attachments/structure/image/Retry.tsx +++ b/apps/meteor/client/components/message/content/attachments/structure/image/Retry.tsx @@ -18,8 +18,8 @@ const Retry = ({ retry }: RetryProps) => { } `; return ( - - + + {t('Retry')} diff --git a/apps/meteor/client/components/message/content/reactions/ReactionTooltip.tsx b/apps/meteor/client/components/message/content/reactions/ReactionTooltip.tsx index 69acc2dcb27b0..2055ef225b4de 100644 --- a/apps/meteor/client/components/message/content/reactions/ReactionTooltip.tsx +++ b/apps/meteor/client/components/message/content/reactions/ReactionTooltip.tsx @@ -78,10 +78,10 @@ const ReactionTooltip = ({ emojiName, usernames, mine, messageId, showRealName, if (isLoading) { return ( <> - - - {usernames.length > 5 && } - {usernames.length > 8 && } + + + {usernames.length > 5 && } + {usernames.length > 8 && } ); } diff --git a/apps/meteor/client/components/message/content/urlPreviews/UrlPreview.tsx b/apps/meteor/client/components/message/content/urlPreviews/UrlPreview.tsx index dd5da1eb9a7dc..8222c9e2d198e 100644 --- a/apps/meteor/client/components/message/content/urlPreviews/UrlPreview.tsx +++ b/apps/meteor/client/components/message/content/urlPreviews/UrlPreview.tsx @@ -14,7 +14,7 @@ const UrlPreview = (props: UrlPreviewMetadata) => { return ( <> - + {t('Link_Preview')} {!collapsed && } diff --git a/apps/meteor/client/components/message/hooks/useOembedLayout.ts b/apps/meteor/client/components/message/hooks/useOembedLayout.ts index be9acfa5fac2a..ce2fdc47a9b47 100644 --- a/apps/meteor/client/components/message/hooks/useOembedLayout.ts +++ b/apps/meteor/client/components/message/hooks/useOembedLayout.ts @@ -1,10 +1,7 @@ -import { useLayout } from '@rocket.chat/ui-contexts'; - import { useMessageListOembedEnabled } from '../list/MessageListContext'; type OembedLayout = { enabled: boolean; - maxWidth: number | '100%'; maxHeight: number; }; @@ -12,16 +9,8 @@ type OembedLayout = { * Returns the layout parameters for oembeds */ export const useOembedLayout = (): OembedLayout => { - /* - Note: both `useSetting` and `useLayout` are hooks that don't force a re-render - very often, so this hook is not going to be re-evaluated very often either; - this is why we don't need to memoize the result or store it in a context - */ const enabled = useMessageListOembedEnabled(); - const { isMobile } = useLayout(); - - const maxWidth = isMobile ? ('100%' as const) : 368; const maxHeight = 368; - return { enabled, maxWidth, maxHeight }; + return { enabled, maxHeight }; }; diff --git a/apps/meteor/client/components/message/toolbar/items/actions/Timestamp/TimestampPicker/FormatSelector.tsx b/apps/meteor/client/components/message/toolbar/items/actions/Timestamp/TimestampPicker/FormatSelector.tsx index 0e3deb123d01f..e5319ab873787 100644 --- a/apps/meteor/client/components/message/toolbar/items/actions/Timestamp/TimestampPicker/FormatSelector.tsx +++ b/apps/meteor/client/components/message/toolbar/items/actions/Timestamp/TimestampPicker/FormatSelector.tsx @@ -26,7 +26,7 @@ const FormatSelector = ({ value, onChange }: FormatSelectorProps) => { {t('Format')} - diff --git a/apps/meteor/client/components/message/toolbar/items/actions/Timestamp/TimestampPicker/TimezoneSelector.tsx b/apps/meteor/client/components/message/toolbar/items/actions/Timestamp/TimestampPicker/TimezoneSelector.tsx index 57fd0ef16bb03..682e8ddd2933e 100644 --- a/apps/meteor/client/components/message/toolbar/items/actions/Timestamp/TimestampPicker/TimezoneSelector.tsx +++ b/apps/meteor/client/components/message/toolbar/items/actions/Timestamp/TimestampPicker/TimezoneSelector.tsx @@ -28,7 +28,7 @@ const TimezoneSelector = ({ value, onChange }: TimezoneSelectorProps) => { {t('Timezone')} {t('Timezone_picker_description')} - {t('Timezone_picker_hint')} diff --git a/apps/meteor/client/hooks/roomActions/useThreadRoomAction.tsx b/apps/meteor/client/hooks/roomActions/useThreadRoomAction.tsx index b863048550c17..a5dbe7fd72cb4 100644 --- a/apps/meteor/client/hooks/roomActions/useThreadRoomAction.tsx +++ b/apps/meteor/client/hooks/roomActions/useThreadRoomAction.tsx @@ -1,8 +1,10 @@ +import { VisuallyHidden } from '@react-aria/visually-hidden'; +import { Badge } from '@rocket.chat/fuselage'; import type { BadgeProps } from '@rocket.chat/fuselage'; -import { HeaderToolbarAction, HeaderToolbarActionBadge } from '@rocket.chat/ui-client'; +import { HeaderToolbarAction } from '@rocket.chat/ui-client'; import { useSetting } from '@rocket.chat/ui-contexts'; import type { RoomToolboxActionConfig } from '@rocket.chat/ui-contexts'; -import { lazy, useMemo } from 'react'; +import { Fragment, lazy, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { useRoomSubscription } from '../../views/room/contexts/RoomContext'; @@ -46,20 +48,22 @@ export const useThreadRoomAction = () => { tabComponent: Threads, order: 2, renderToolboxItem: ({ id, className, icon, title, toolbox: { tab }, disabled, action, tooltip }) => ( - - {!!unread && {unread}} - + + {unread}} + /> + {!!tunread && t('Threads_unread_count', { count: tunread })} + ), }; - }, [enabled, t, unread, variant]); + }, [enabled, t, tunread, unread, variant]); }; diff --git a/apps/meteor/client/hooks/useUserStatusTooltip.tsx b/apps/meteor/client/hooks/useUserStatusTooltip.tsx index 66e38b2e4cfd7..3f3b79058c800 100644 --- a/apps/meteor/client/hooks/useUserStatusTooltip.tsx +++ b/apps/meteor/client/hooks/useUserStatusTooltip.tsx @@ -11,7 +11,7 @@ const UserStatusTooltipContent = ({ uid }: UserStatusTooltipContentProps) => { const presence = useUserPresence(uid); if (!presence) { - return ; + return ; } return ; diff --git a/apps/meteor/client/navbar/NavBarOmnichannelGroup/NavBarItemOmnichannelContact.tsx b/apps/meteor/client/navbar/NavBarOmnichannelGroup/NavBarItemOmnichannelContact.tsx index 2049e1f93e02b..3d7e3ea5b17ad 100644 --- a/apps/meteor/client/navbar/NavBarOmnichannelGroup/NavBarItemOmnichannelContact.tsx +++ b/apps/meteor/client/navbar/NavBarOmnichannelGroup/NavBarItemOmnichannelContact.tsx @@ -3,7 +3,7 @@ import type { HTMLAttributes } from 'react'; import { useOmnichannelContactAction } from './hooks/useOmnichannelContactAction'; -export type NavBarItemOmnichannelContactProps = Omit, 'is'>; +export type NavBarItemOmnichannelContactProps = Omit, 'is' | 'color'>; const NavBarItemOmnichannelContact = (props: NavBarItemOmnichannelContactProps) => { const { icon, isPressed, title, handleGoToContactCenter } = useOmnichannelContactAction(); diff --git a/apps/meteor/client/navbar/NavBarOmnichannelGroup/NavBarItemOmnichannelLivechatToggle.tsx b/apps/meteor/client/navbar/NavBarOmnichannelGroup/NavBarItemOmnichannelLivechatToggle.tsx index f73da9a42a7d6..ac5fbef3cd946 100644 --- a/apps/meteor/client/navbar/NavBarOmnichannelGroup/NavBarItemOmnichannelLivechatToggle.tsx +++ b/apps/meteor/client/navbar/NavBarOmnichannelGroup/NavBarItemOmnichannelLivechatToggle.tsx @@ -3,7 +3,7 @@ import type { HTMLAttributes } from 'react'; import { useOmnichannelLivechatToggle } from './hooks/useOmnichannelLivechatToggle'; -export type NavBarItemOmnichannelLivechatToggleProps = Omit, 'is'>; +export type NavBarItemOmnichannelLivechatToggleProps = Omit, 'is' | 'color'>; const NavBarItemOmnichannelLivechatToggle = (props: NavBarItemOmnichannelLivechatToggleProps) => { const { handleAvailableStatusChange, title, icon, isSuccess } = useOmnichannelLivechatToggle(); diff --git a/apps/meteor/client/navbar/NavBarOmnichannelGroup/NavBarItemOmnichannelQueue.tsx b/apps/meteor/client/navbar/NavBarOmnichannelGroup/NavBarItemOmnichannelQueue.tsx index 9078a1a7c8503..59115baf3405f 100644 --- a/apps/meteor/client/navbar/NavBarOmnichannelGroup/NavBarItemOmnichannelQueue.tsx +++ b/apps/meteor/client/navbar/NavBarOmnichannelGroup/NavBarItemOmnichannelQueue.tsx @@ -3,7 +3,7 @@ import type { HTMLAttributes } from 'react'; import { useOmnichannelQueueAction } from './hooks/useOmnichannelQueueAction'; -export type NavBarItemOmnichannelQueueProps = Omit, 'is'>; +export type NavBarItemOmnichannelQueueProps = Omit, 'is' | 'color'>; const NavBarItemOmnichannelQueue = (props: NavBarItemOmnichannelQueueProps) => { const { isEnabled, title, icon, isPressed, handleGoToQueue } = useOmnichannelQueueAction(); diff --git a/apps/meteor/client/navbar/NavBarPagesGroup/NavBarItemDirectoryPage.tsx b/apps/meteor/client/navbar/NavBarPagesGroup/NavBarItemDirectoryPage.tsx index f18401f3f0037..b53e6a93c37cb 100644 --- a/apps/meteor/client/navbar/NavBarPagesGroup/NavBarItemDirectoryPage.tsx +++ b/apps/meteor/client/navbar/NavBarPagesGroup/NavBarItemDirectoryPage.tsx @@ -3,7 +3,7 @@ import { useStableCallback } from '@rocket.chat/fuselage-hooks'; import { useRouter, useCurrentRoutePath } from '@rocket.chat/ui-contexts'; import type { HTMLAttributes } from 'react'; -export type NavBarItemDirectoryPageProps = Omit, 'is'>; +export type NavBarItemDirectoryPageProps = Omit, 'is' | 'color'>; const NavBarItemDirectoryPage = (props: NavBarItemDirectoryPageProps) => { const router = useRouter(); diff --git a/apps/meteor/client/navbar/NavBarPagesGroup/NavBarItemHomePage.tsx b/apps/meteor/client/navbar/NavBarPagesGroup/NavBarItemHomePage.tsx index c84d8068602e2..fb9da31fe2392 100644 --- a/apps/meteor/client/navbar/NavBarPagesGroup/NavBarItemHomePage.tsx +++ b/apps/meteor/client/navbar/NavBarPagesGroup/NavBarItemHomePage.tsx @@ -3,7 +3,7 @@ import { useStableCallback } from '@rocket.chat/fuselage-hooks'; import { useRouter, useLayout, useSetting, useCurrentRoutePath } from '@rocket.chat/ui-contexts'; import type { HTMLAttributes } from 'react'; -export type NavBarItemHomePageProps = Omit, 'is'>; +export type NavBarItemHomePageProps = Omit, 'is' | 'color'>; const NavBarItemHomePage = (props: NavBarItemHomePageProps) => { const router = useRouter(); diff --git a/apps/meteor/client/navbar/NavBarPagesGroup/actions/CreateChannelModal.tsx b/apps/meteor/client/navbar/NavBarPagesGroup/actions/CreateChannelModal.tsx index 6e02ff197e699..7fa64a7af3b84 100644 --- a/apps/meteor/client/navbar/NavBarPagesGroup/actions/CreateChannelModal.tsx +++ b/apps/meteor/client/navbar/NavBarPagesGroup/actions/CreateChannelModal.tsx @@ -317,13 +317,13 @@ const CreateChannelModal = ({ teamId = '', mainRoom, onClose, reload, onSuccess, submitDisabled={creationBlocked} isSubmitting={isSubmitting} details={ - <> + {creationBlocked && ( - + {t(canUseFederation ? 'ABAC_Room_Creation_Federated_Only' : 'ABAC_Room_Creation_Not_Allowed')} )} - + {t('Name')} @@ -387,7 +387,7 @@ const CreateChannelModal = ({ teamId = '', mainRoom, onClose, reload, onSuccess, {isPrivate ? t('People_can_only_join_by_being_invited') : t('Anyone_can_access')} - + } /> diff --git a/apps/meteor/client/navbar/NavBarPagesGroup/actions/CreateDirectMessage.tsx b/apps/meteor/client/navbar/NavBarPagesGroup/actions/CreateDirectMessage.tsx index 6aee1fd16c48e..471acd3660236 100644 --- a/apps/meteor/client/navbar/NavBarPagesGroup/actions/CreateDirectMessage.tsx +++ b/apps/meteor/client/navbar/NavBarPagesGroup/actions/CreateDirectMessage.tsx @@ -64,38 +64,40 @@ const CreateDirectMessage = ({ onClose, onSuccess }: CreateDirectMessageProps) = {t('Create_direct_message')} - - - - {t('Direct_message_creation_description')} - - - users.length + 1 > directMaxUsers - ? t('error-direct-message-max-user-exceeded', { maxUsers: directMaxUsers }) - : undefined, - }} - control={control} - render={({ field: { name, onChange, value, onBlur } }) => ( - - )} - /> - - {errors.users && {errors.users.message}} - {t('Direct_message_creation_description_hint')} - - + + + + + {t('Direct_message_creation_description')} + + + users.length + 1 > directMaxUsers + ? t('error-direct-message-max-user-exceeded', { maxUsers: directMaxUsers }) + : undefined, + }} + control={control} + render={({ field: { name, onChange, value, onBlur } }) => ( + + )} + /> + + {errors.users && {errors.users.message}} + {t('Direct_message_creation_description_hint')} + + + diff --git a/apps/meteor/client/navbar/NavBarPagesGroup/actions/CreateTeamModal.tsx b/apps/meteor/client/navbar/NavBarPagesGroup/actions/CreateTeamModal.tsx index 5c3da9333c038..6eae7f38b2bbe 100644 --- a/apps/meteor/client/navbar/NavBarPagesGroup/actions/CreateTeamModal.tsx +++ b/apps/meteor/client/navbar/NavBarPagesGroup/actions/CreateTeamModal.tsx @@ -248,16 +248,10 @@ const CreateTeamModal = ({ onClose, onSuccess, abac }: CreateTeamModalProps) => submitDisabled={!canCreateTeam || creationBlocked} isSubmitting={isSubmitting} details={ - <> - - {t('Teams_new_description')} - - {creationBlocked && ( - - {t('ABAC_Room_Creation_Not_Allowed')} - - )} - + + {t('Teams_new_description')} + {creationBlocked && {t('ABAC_Room_Creation_Not_Allowed')}} + {t('Teams_New_Name_Label')} @@ -320,7 +314,7 @@ const CreateTeamModal = ({ onClose, onSuccess, abac }: CreateTeamModalProps) => {isPrivate ? t('People_can_only_join_by_being_invited') : t('Anyone_can_access')} - + } /> diff --git a/apps/meteor/client/navbar/NavBarSearch/NavBarAISearchListbox.tsx b/apps/meteor/client/navbar/NavBarSearch/NavBarAISearchListbox.tsx index ec20b78787c9a..2e4c538e542a0 100644 --- a/apps/meteor/client/navbar/NavBarSearch/NavBarAISearchListbox.tsx +++ b/apps/meteor/client/navbar/NavBarSearch/NavBarAISearchListbox.tsx @@ -1,7 +1,7 @@ import type { OverlayTriggerAria } from '@react-aria/overlays'; import type { OverlayTriggerState } from '@react-stately/overlays'; import type { NavBarSearchFormValues } from '@rocket.chat/ai-search'; -import { Tile, Box, ToggleSwitch, Divider, Icon } from '@rocket.chat/fuselage'; +import { Box, ToggleSwitch, Divider, Icon, Stack, PopoverSurface } from '@rocket.chat/fuselage'; import { useOutsideClick, useStableCallback } from '@rocket.chat/fuselage-hooks'; import { CustomScrollbars } from '@rocket.chat/ui-client'; import { useId, useMemo, useRef } from 'react'; @@ -64,93 +64,85 @@ const NavBarAISearchListBox = ({ const listboxLabel = aiSearchActive ? t('AI_Search_results') : t('Channels'); return ( - - {filtersOpen ? ( - - ) : ( - <> - - {aiSearchAvailable && ( - <> - - - - {t('AI_Search')} - - - - - - {aiSearchActive && } - - )} -
+ + + {filtersOpen ? ( + + ) : ( + <> + {aiSearchAvailable && ( <> - {aiItems.filterSuggestions.length > 0 && ( -
event.preventDefault()} - > - -
- )} - - {hasAISearchProblem && ( - - )} + + + + {t('AI_Search')} + + + + + + {aiSearchActive && } )} - -
event.preventDefault()} - > - - {aiItems.intelligent.length > 0 && rooms.length > 0 && } - -
-
-
- - )} -
+
+ {aiSearchAvailable && ( + <> + {aiItems.filterSuggestions.length > 0 && ( +
event.preventDefault()} + > + +
+ )} + + + + {hasAISearchProblem && ( + + )} + + )} + +
event.preventDefault()} + > + + {aiItems.intelligent.length > 0 && rooms.length > 0 && } + +
+
+
+ + )} + +
); }; diff --git a/apps/meteor/client/navbar/NavBarSearch/NavBarSearchFilterChips.tsx b/apps/meteor/client/navbar/NavBarSearch/NavBarSearchFilterChips.tsx index 6d960efeb995b..25a2abf996bc9 100644 --- a/apps/meteor/client/navbar/NavBarSearch/NavBarSearchFilterChips.tsx +++ b/apps/meteor/client/navbar/NavBarSearch/NavBarSearchFilterChips.tsx @@ -32,8 +32,7 @@ const NavBarSearchFilterChips = ({ filters, onRemove, wrap = false }: NavBarSear return ( onRemove(filter.id)} title={t(title, { value: filter.value })} diff --git a/apps/meteor/client/navbar/NavBarSearch/NavBarSearchFilterTypeRow.tsx b/apps/meteor/client/navbar/NavBarSearch/NavBarSearchFilterTypeRow.tsx index 301eb2cb4e120..0cb9119ba5127 100644 --- a/apps/meteor/client/navbar/NavBarSearch/NavBarSearchFilterTypeRow.tsx +++ b/apps/meteor/client/navbar/NavBarSearch/NavBarSearchFilterTypeRow.tsx @@ -1,6 +1,6 @@ import type { DraftSearchFilter } from '@rocket.chat/ai-search'; import { SEARCH_FILTER_KEYS, getSearchFilterConfig } from '@rocket.chat/ai-search'; -import { Box, Button, Icon } from '@rocket.chat/fuselage'; +import { Box, Button } from '@rocket.chat/fuselage'; import type { ReactElement } from 'react'; import { useTranslation } from 'react-i18next'; @@ -26,9 +26,9 @@ const NavBarSearchFilterTypeRow = ({ draft }: NavBarSearchFilterTypeRowProps): R size='small' variant={isActive ? 'primary' : 'secondary'} aria-pressed={isActive} + icon={icon} onClick={() => startFilter(key)} > - {t(pillLabel)} ); diff --git a/apps/meteor/client/navbar/NavBarSearch/NavBarSearchFiltersView.tsx b/apps/meteor/client/navbar/NavBarSearch/NavBarSearchFiltersView.tsx index 444995b478607..4d863cddb47f9 100644 --- a/apps/meteor/client/navbar/NavBarSearch/NavBarSearchFiltersView.tsx +++ b/apps/meteor/client/navbar/NavBarSearch/NavBarSearchFiltersView.tsx @@ -1,5 +1,5 @@ import type { AppliedFilter } from '@rocket.chat/ai-search'; -import { Box, Button, Icon, IconButton } from '@rocket.chat/fuselage'; +import { Box, Button, IconButton } from '@rocket.chat/fuselage'; import type { ReactElement } from 'react'; import { useId } from 'react'; import { useTranslation } from 'react-i18next'; @@ -30,14 +30,13 @@ const NavBarSearchFiltersView = ({ id, filters, onBack }: NavBarSearchFiltersVie gap={12} > - + {t('Search_filters_with_count', { count: filters.length })} - diff --git a/apps/meteor/client/navbar/NavBarSearch/NavBarSearchInputAddon.tsx b/apps/meteor/client/navbar/NavBarSearch/NavBarSearchInputAddon.tsx index 08dc8f0b30417..081cadbf675d5 100644 --- a/apps/meteor/client/navbar/NavBarSearch/NavBarSearchInputAddon.tsx +++ b/apps/meteor/client/navbar/NavBarSearch/NavBarSearchInputAddon.tsx @@ -26,10 +26,10 @@ const NavBarSearchInputAddon = ({ return ( {filters.length > 1 ? ( - null}> - + null}> + {t('Search_filters_with_count', { count: filters.length })} - + ) : ( diff --git a/apps/meteor/client/navbar/NavBarSearch/NavBarSearchIntelligentSection.tsx b/apps/meteor/client/navbar/NavBarSearch/NavBarSearchIntelligentSection.tsx index 9269bcc627ef9..6ab0471e81bcd 100644 --- a/apps/meteor/client/navbar/NavBarSearch/NavBarSearchIntelligentSection.tsx +++ b/apps/meteor/client/navbar/NavBarSearch/NavBarSearchIntelligentSection.tsx @@ -52,9 +52,11 @@ const NavBarSearchIntelligentSection = ({ items, onSelect, onClose }: NavBarSear {items.map((item) => ( ))} - + + + ); }; diff --git a/apps/meteor/client/navbar/NavBarSearch/NavBarSearchListbox.tsx b/apps/meteor/client/navbar/NavBarSearch/NavBarSearchListbox.tsx index 9378a601d3984..8df3251e8c5d8 100644 --- a/apps/meteor/client/navbar/NavBarSearch/NavBarSearchListbox.tsx +++ b/apps/meteor/client/navbar/NavBarSearch/NavBarSearchListbox.tsx @@ -1,6 +1,6 @@ import type { OverlayTriggerAria } from '@react-aria/overlays'; import type { OverlayTriggerState } from '@react-stately/overlays'; -import { ItemGroupHeader, ItemGroupTitle, Tile } from '@rocket.chat/fuselage'; +import { Box, ItemGroupHeader, ItemGroupTitle, PopoverSurface } from '@rocket.chat/fuselage'; import { useStableCallback, useOutsideClick } from '@rocket.chat/fuselage-hooks'; import { CustomScrollbars } from '@rocket.chat/ui-client'; import { useRef } from 'react'; @@ -37,42 +37,32 @@ const NavBarSearchListBox = ({ state, overlayProps }: NavBarSearchListBoxProps) useSyncSearchOptions(items); return ( - - - -
event.preventDefault()} - > - {items.length === 0 && !isLoading && } - {items.length > 0 && ( - - {filterText ? t('Results') : t('Recent')} - - )} - {items.map((item) => ( - - ))} - {isLoading && Array.from({ length: 4 }, (_, index) => )} -
-
-
+ + + + +
event.preventDefault()} + > + {items.length === 0 && !isLoading && } + {items.length > 0 && ( + + {filterText ? t('Results') : t('Recent')} + + )} + {items.map((item) => ( + + ))} + {isLoading && Array.from({ length: 4 }, (_, index) => )} +
+
+
+
); }; diff --git a/apps/meteor/client/navbar/NavBarSettingsToolbar/UserMenu/EditStatusModal.tsx b/apps/meteor/client/navbar/NavBarSettingsToolbar/UserMenu/EditStatusModal.tsx index 282f8700034ee..18bad0f37871e 100644 --- a/apps/meteor/client/navbar/NavBarSettingsToolbar/UserMenu/EditStatusModal.tsx +++ b/apps/meteor/client/navbar/NavBarSettingsToolbar/UserMenu/EditStatusModal.tsx @@ -1,6 +1,6 @@ import { UserStatus as UserStatusType } from '@rocket.chat/core-typings'; import type { SelectOption } from '@rocket.chat/fuselage'; -import { InputBox, Margins, Box } from '@rocket.chat/fuselage'; +import { InputBox, Box } from '@rocket.chat/fuselage'; import { Field, FieldGroup, FieldLabel, FieldRow, FieldError, FieldHint, TextInput, Select } from '@rocket.chat/fuselage-forms'; import { useLocalStorage } from '@rocket.chat/fuselage-hooks'; import { GenericModal } from '@rocket.chat/ui-client'; @@ -150,36 +150,32 @@ const EditStatusModal = ({ onClose }: EditStatusModalProps) => { /> {statusDuration === 'custom' && ( - - - ( - ) => onChange(e.currentTarget.value)} - min={new Date().toLocaleDateString('en-CA')} - /> - )} - /> - ( - ) => onChange(e.currentTarget.value)} - /> - )} - /> - + + ( + ) => onChange(e.currentTarget.value)} + min={new Date().toLocaleDateString('en-CA')} + /> + )} + /> + ( + ) => onChange(e.currentTarget.value)} + /> + )} + /> )} {errors.statusDuration && {errors.statusDuration.message}} diff --git a/apps/meteor/client/navbar/NavBarSettingsToolbar/UserMenu/KeyboardShortcutsModal.tsx b/apps/meteor/client/navbar/NavBarSettingsToolbar/UserMenu/KeyboardShortcutsModal.tsx index 23244d2799389..1e67d6bd81a5e 100644 --- a/apps/meteor/client/navbar/NavBarSettingsToolbar/UserMenu/KeyboardShortcutsModal.tsx +++ b/apps/meteor/client/navbar/NavBarSettingsToolbar/UserMenu/KeyboardShortcutsModal.tsx @@ -124,7 +124,7 @@ const KeyboardShortcutsModal = ({ onClose }: KeyboardShortcutsModalProps) => { ); })} -
))}
diff --git a/apps/meteor/client/navbar/NavBarSettingsToolbar/UserMenu/UserMenuButton.spec.tsx b/apps/meteor/client/navbar/NavBarSettingsToolbar/UserMenu/UserMenuButton.spec.tsx index e49adbf2c59da..0c53a3970b398 100644 --- a/apps/meteor/client/navbar/NavBarSettingsToolbar/UserMenu/UserMenuButton.spec.tsx +++ b/apps/meteor/client/navbar/NavBarSettingsToolbar/UserMenu/UserMenuButton.spec.tsx @@ -1,8 +1,39 @@ +import { UserStatus, type IUser } from '@rocket.chat/core-typings'; import { mockAppRoot } from '@rocket.chat/mock-providers'; -import { render, screen } from '@testing-library/react'; +import { UserContext } from '@rocket.chat/ui-contexts'; +import { render, screen, waitFor } from '@testing-library/react'; +import { useContext, useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; import UserMenuButton from './UserMenuButton'; +const UserMenuButtonWithStatus = ({ status, language }: { status: IUser['status']; language?: string }) => { + const userContext = useContext(UserContext); + const { i18n } = useTranslation(); + useEffect(() => { + if (language) { + void i18n.changeLanguage(language); + } + }, [i18n, language]); + return ( + + + + ); +}; + +const appRoot = () => + mockAppRoot() + .withUser({ _id: 'alice-id', username: 'alice', status: 'online' } as IUser) + .withTranslations('en', 'core', { + Online: 'Online', + Away: 'Away', + Busy: 'Busy', + Offline: 'Offline', + User_status_disabled: 'Status disabled', + }) + .withTranslations('pt-BR', 'core', { Away: 'Ausente' }); + describe('UserMenuButton', () => { it.each([ { @@ -43,6 +74,68 @@ describe('UserMenuButton', () => { }); // eslint-disable-next-line testing-library/no-node-access - expect(screen.getByRole('status').querySelector(`.rcx-status-bullet--${expected}`)).toBeInTheDocument(); + expect(screen.getByRole('button').querySelector(`.rcx-button__badge .rcx-status-bullet--${expected}`)).toBeInTheDocument(); + }); + + it.each([ + { scenario: 'the real status', settings: {}, presenceDisabledByAdmin: false, expected: 'Online' }, + { + scenario: 'Offline when status is off for the workspace', + settings: { Accounts_UserStatus_Enabled: false }, + presenceDisabledByAdmin: false, + expected: 'Offline', + }, + { + scenario: 'Offline when an admin hid it', + settings: { Accounts_StatusVisibility_Admin_Enabled: true }, + presenceDisabledByAdmin: true, + expected: 'Offline', + }, + { + scenario: 'that status is disabled when presence broadcast is off', + settings: { Presence_broadcast_disabled: true }, + presenceDisabledByAdmin: false, + expected: 'Status disabled', + }, + ])('describes the button with $scenario', ({ settings, presenceDisabledByAdmin, expected }) => { + const root = appRoot().withUser({ _id: 'alice-id', username: 'alice', status: 'online', presenceDisabledByAdmin } as IUser); + Object.entries(settings).forEach(([id, value]) => root.withSetting(id, value)); + + render(, { wrapper: root.build() }); + + expect(screen.getByRole('button', { name: 'User menu' })).toHaveAccessibleDescription(expected); + }); + + it('updates the description and announces the status only when it changes', () => { + const { rerender } = render(, { wrapper: appRoot().build() }); + + expect(screen.getByRole('button', { name: 'User menu' })).toHaveAccessibleDescription('Away'); + expect(screen.getByRole('status')).toBeEmptyDOMElement(); + + rerender(); + + expect(screen.getByRole('button', { name: 'User menu' })).toHaveAccessibleDescription('Busy'); + expect(screen.getByRole('status')).toHaveTextContent('Busy'); + }); + + it('does not announce when only the language changes', async () => { + const { rerender } = render(, { wrapper: appRoot().build() }); + + rerender(); + + await waitFor(() => expect(screen.getByRole('button', { name: 'User menu' })).toHaveAccessibleDescription('Ausente')); + expect(screen.getByRole('status')).toBeEmptyDOMElement(); + }); + + it('keeps the description passed by the caller', () => { + render( + <> + Opens the user menu + + , + { wrapper: appRoot().build() }, + ); + + expect(screen.getByRole('button', { name: 'User menu' })).toHaveAccessibleDescription('Opens the user menu Online'); }); }); diff --git a/apps/meteor/client/navbar/NavBarSettingsToolbar/UserMenu/UserMenuButton.tsx b/apps/meteor/client/navbar/NavBarSettingsToolbar/UserMenu/UserMenuButton.tsx index 071f7acb2d1e9..e804a2aab3005 100644 --- a/apps/meteor/client/navbar/NavBarSettingsToolbar/UserMenu/UserMenuButton.tsx +++ b/apps/meteor/client/navbar/NavBarSettingsToolbar/UserMenu/UserMenuButton.tsx @@ -1,9 +1,10 @@ -import { css } from '@rocket.chat/css-in-js'; +import { VisuallyHidden } from '@react-aria/visually-hidden'; import { Box, IconButton } from '@rocket.chat/fuselage'; import { UserAvatar } from '@rocket.chat/ui-avatar'; import { useSetting, useUser } from '@rocket.chat/ui-contexts'; import type { ComponentPropsWithoutRef, ForwardedRef } from 'react'; -import { forwardRef } from 'react'; +import { forwardRef, useEffect, useId, useRef, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { UserStatus } from '../../../components/UserStatus'; @@ -14,9 +15,21 @@ const anon = { avatarETag: undefined, } as const; +const statusLabels = { + online: 'Online', + away: 'Away', + busy: 'Busy', + offline: 'Offline', + disabled: 'User_status_disabled', +} as const; + export type UserMenuButtonProps = ComponentPropsWithoutRef; -const UserMenuButton = forwardRef(function UserMenuButton(props: UserMenuButtonProps, ref: ForwardedRef) { +const UserMenuButton = forwardRef(function UserMenuButton( + { 'aria-describedby': ariaDescribedBy, ...props }: UserMenuButtonProps, + ref: ForwardedRef, +) { + const { t } = useTranslation(); const user = useUser(); const { status = !user ? 'online' : 'offline', username, avatarETag } = user || anon; @@ -32,37 +45,48 @@ const UserMenuButton = forwardRef(function UserMenuButton(props: UserMenuButtonP return presenceDisabled ? 'disabled' : status; }; + const displayedStatus = getDisplayedStatus(); + const statusLabel = t(statusLabels[displayedStatus as keyof typeof statusLabels] ?? 'Loading'); + const descriptionId = useId(); + + // Announces status changes only: neither the status the page loaded with nor a language change. + const [announcement, setAnnouncement] = useState(''); + const previousStatus = useRef(displayedStatus); + useEffect(() => { + if (previousStatus.current === displayedStatus) { + return; + } + previousStatus.current = displayedStatus; + setAnnouncement(statusLabel); + }, [displayedStatus, statusLabel]); + return ( - : 'user'} - > - - - - + <> + : 'user'} + badgePosition='bottom-end' + badge={ + + + + } + /> + {statusLabel} + {announcement} + ); }); diff --git a/apps/meteor/client/navbar/NavBarSettingsToolbar/UserMenu/hooks/useStatusItems.tsx b/apps/meteor/client/navbar/NavBarSettingsToolbar/UserMenu/hooks/useStatusItems.tsx index 5870035800165..0d26c3b21c9dd 100644 --- a/apps/meteor/client/navbar/NavBarSettingsToolbar/UserMenu/hooks/useStatusItems.tsx +++ b/apps/meteor/client/navbar/NavBarSettingsToolbar/UserMenu/hooks/useStatusItems.tsx @@ -80,8 +80,8 @@ export const useStatusItems = (user?: IUser): GenericMenuItemProps[] => { <> {contentValue && } {customStatusExpiration && ( - - + + {customStatusExpiration} )} diff --git a/apps/meteor/client/sidebar/SidebarRail/SidebarRailLoginPage.tsx b/apps/meteor/client/sidebar/SidebarRail/SidebarRailLoginPage.tsx index 6eae2924116e4..f5b9f3814a966 100644 --- a/apps/meteor/client/sidebar/SidebarRail/SidebarRailLoginPage.tsx +++ b/apps/meteor/client/sidebar/SidebarRail/SidebarRailLoginPage.tsx @@ -3,7 +3,7 @@ import { useSessionDispatch } from '@rocket.chat/ui-contexts'; import type { HTMLAttributes } from 'react'; import { useTranslation } from 'react-i18next'; -type SidebarRailLoginPageProps = Omit, 'is'>; +type SidebarRailLoginPageProps = Omit, 'is' | 'color'>; const SidebarRailLoginPage = (props: SidebarRailLoginPageProps) => { const setForceLogin = useSessionDispatch('forceLogin'); diff --git a/apps/meteor/client/sidebar/SidebarRail/SidebarRailPhone.tsx b/apps/meteor/client/sidebar/SidebarRail/SidebarRailPhone.tsx index 4860c09674cba..f23b6f683d557 100644 --- a/apps/meteor/client/sidebar/SidebarRail/SidebarRailPhone.tsx +++ b/apps/meteor/client/sidebar/SidebarRail/SidebarRailPhone.tsx @@ -5,7 +5,7 @@ import { useMediaCallAction } from '@rocket.chat/ui-voip'; import type { HTMLAttributes } from 'react'; import { useTranslation } from 'react-i18next'; -type SidebarRailPhoneProps = Omit, 'is'>; +type SidebarRailPhoneProps = Omit, 'is' | 'color'>; const SidebarRailPhone = (props: SidebarRailPhoneProps) => { const { t } = useTranslation(); diff --git a/apps/meteor/client/sidebar/footer/SidebarFooterWatermark.tsx b/apps/meteor/client/sidebar/footer/SidebarFooterWatermark.tsx index ca73bcd957975..4b1789b4623d6 100644 --- a/apps/meteor/client/sidebar/footer/SidebarFooterWatermark.tsx +++ b/apps/meteor/client/sidebar/footer/SidebarFooterWatermark.tsx @@ -26,12 +26,12 @@ export const SidebarFooterWatermark = () => { } return ( - + {t('Powered_by_RocketChat')} - + {licenseName.data} diff --git a/apps/meteor/client/views/account/omnichannel/PreferencesConversationTranscript.tsx b/apps/meteor/client/views/account/omnichannel/PreferencesConversationTranscript.tsx index bfc046b0f86a2..7ca9bd5aaba4d 100644 --- a/apps/meteor/client/views/account/omnichannel/PreferencesConversationTranscript.tsx +++ b/apps/meteor/client/views/account/omnichannel/PreferencesConversationTranscript.tsx @@ -1,4 +1,4 @@ -import { AccordionItem, Tag } from '@rocket.chat/fuselage'; +import { AccordionItem, Box, Tag } from '@rocket.chat/fuselage'; import { Field, FieldGroup, FieldLabel, FieldRow, FieldHint, ToggleSwitch } from '@rocket.chat/fuselage-forms'; import { useTranslation, usePermission, useSetting } from '@rocket.chat/ui-contexts'; import { Controller, useFormContext } from 'react-hook-form'; @@ -22,13 +22,11 @@ const PreferencesConversationTranscript = () => { - {t('Omnichannel_transcript_pdf')} - {!hasLicense && ( - - {t('Premium')} - - )} - {!canSendTranscriptPDF && hasLicense && {t('No_permission')}} + + {t('Omnichannel_transcript_pdf')} + {!hasLicense && {t('Premium')}} + {!canSendTranscriptPDF && hasLicense && {t('No_permission')}} + { - {t('Omnichannel_transcript_email')} - {!canSendTranscriptEmailPermission && {t('No_permission')}} + + {t('Omnichannel_transcript_email')} + {!canSendTranscriptEmailPermission && {t('No_permission')}} + ) => { )} /> - - - {t('Name')} - - ( - - )} - /> - - {errors.name && {errors.name.message}} - {!allowRealNameChange && {t('RealName_Change_Disabled')}} - - - {t('Username')} - - ( - } - error={errors.username?.message} - /> - )} - /> - - {errors.username && {errors.username.message}} - {!canChangeUsername && {t('Username_Change_Disabled')}} - - - - - {t('Status')} - - ( - : undefined} - startAddon={ - presenceDisabledByAdmin ? ( - - ) : ( - } - /> - ) - } + + + + {t('Name')} + + ( + + )} /> - )} - /> - - {errors.statusText && {errors.statusText.message}} - {!allowUserStatusMessageChange && {t('StatusMessage_Change_Disabled')}} - {allowUserStatusMessageChange && !presenceDisabledByAdmin && {t('Status_you_can_use_emoji')}} - - - {t('Status_clear_after')} - - - validateStatusExpiration(value, { statusCustomDate, statusCustomTime }, t), - }} - render={({ field: { value, onChange } }) => ( - { onChange={(value) => setFilterType(value)} /> - - + {(!data || data.rooms?.length === 0) && !isLoading ? ( diff --git a/apps/meteor/client/views/admin/aiCenter/AICenterCapabilityCard.tsx b/apps/meteor/client/views/admin/aiCenter/AICenterCapabilityCard.tsx index 74b759bd152d5..2b66799c6dd8d 100644 --- a/apps/meteor/client/views/admin/aiCenter/AICenterCapabilityCard.tsx +++ b/apps/meteor/client/views/admin/aiCenter/AICenterCapabilityCard.tsx @@ -16,7 +16,7 @@ const AICenterCapabilityCard = ({ icon, title, description, status, actionLabel, const descriptionId = useId(); return ( - + {status && {status}} diff --git a/apps/meteor/client/views/admin/aiCenter/AICenterOverview.tsx b/apps/meteor/client/views/admin/aiCenter/AICenterOverview.tsx index ba75fc9ea58e4..f45ed36d2d07c 100644 --- a/apps/meteor/client/views/admin/aiCenter/AICenterOverview.tsx +++ b/apps/meteor/client/views/admin/aiCenter/AICenterOverview.tsx @@ -41,44 +41,48 @@ const AICenterOverview = (): ReactElement => { - + {hasAILicense === false && ( - + {t('AI_Center_license_required_description')} - + + + )} - - {t('Capabilities')} + + + {t('Capabilities')} + + + + + + - - - - - diff --git a/apps/meteor/client/views/admin/customEmoji/AddCustomEmoji.tsx b/apps/meteor/client/views/admin/customEmoji/AddCustomEmoji.tsx index 3be2d02e78f74..f2997925232b2 100644 --- a/apps/meteor/client/views/admin/customEmoji/AddCustomEmoji.tsx +++ b/apps/meteor/client/views/admin/customEmoji/AddCustomEmoji.tsx @@ -3,7 +3,7 @@ import { ContextualbarScrollableContent, ContextualbarFooter } from '@rocket.cha import { useToastMessageDispatch } from '@rocket.chat/ui-contexts'; import { useQueryClient } from '@tanstack/react-query'; import type { ChangeEvent } from 'react'; -import { useCallback, useState } from 'react'; +import { useCallback, useId, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useEndpointUploadMutation } from '../../../hooks/useEndpointUploadMutation'; @@ -16,6 +16,7 @@ export type AddCustomEmojiProps = { const AddCustomEmoji = ({ close, onChange, ...props }: AddCustomEmojiProps) => { const { t } = useTranslation(); + const emojiLabelId = useId(); const [name, setName] = useState(''); const [aliases, setAliases] = useState(''); const [emojiFile, setEmojiFile] = useState(); @@ -99,10 +100,10 @@ const AddCustomEmoji = ({ close, onChange, ...props }: AddCustomEmojiProps) => { {errors.aliases && {t('Custom_Emoji_Error_Same_Name_And_Alias')}} - - {t('Custom_Emoji')} - - + + {t('Custom_Emoji')} + + {errors.emoji && {t('Required_field', { field: t('Custom_Emoji') })}} {newEmojiPreview && ( diff --git a/apps/meteor/client/views/admin/customEmoji/EditCustomEmoji.tsx b/apps/meteor/client/views/admin/customEmoji/EditCustomEmoji.tsx index 979e6ec8b48ea..7c9b4187d2938 100644 --- a/apps/meteor/client/views/admin/customEmoji/EditCustomEmoji.tsx +++ b/apps/meteor/client/views/admin/customEmoji/EditCustomEmoji.tsx @@ -15,7 +15,7 @@ import { GenericModal, ContextualbarScrollableContent, ContextualbarFooter } fro import { useSetModal, useAbsoluteUrl, useToastMessageDispatch } from '@rocket.chat/ui-contexts'; import { useQueryClient } from '@tanstack/react-query'; import type { ChangeEvent } from 'react'; -import { useCallback, useState, useMemo, useEffect } from 'react'; +import { useCallback, useId, useState, useMemo, useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import { useEndpointMutation } from '../../../hooks/useEndpointMutation'; @@ -36,6 +36,7 @@ export type EditCustomEmojiProps = { const EditCustomEmoji = ({ close, onChange, data, ...props }: EditCustomEmojiProps) => { const { t } = useTranslation(); + const emojiLabelId = useId(); const setModal = useSetModal(); const absoluteUrl = useAbsoluteUrl(); const queryClient = useQueryClient(); @@ -168,10 +169,10 @@ const EditCustomEmoji = ({ close, onChange, data, ...props }: EditCustomEmojiPro {errors.aliases && {t('Custom_Emoji_Error_Same_Name_And_Alias')}} - - {t('Custom_Emoji')} - - + + {t('Custom_Emoji')} + + {newEmojiPreview && ( diff --git a/apps/meteor/client/views/admin/customSounds/AddCustomSound.tsx b/apps/meteor/client/views/admin/customSounds/AddCustomSound.tsx index 84d87065bb6cb..37c746029d4de 100644 --- a/apps/meteor/client/views/admin/customSounds/AddCustomSound.tsx +++ b/apps/meteor/client/views/admin/customSounds/AddCustomSound.tsx @@ -1,4 +1,4 @@ -import { Field, FieldLabel, FieldRow, TextInput, Box, Margins, Button, ButtonGroup, IconButton } from '@rocket.chat/fuselage'; +import { Field, FieldLabel, FieldRow, TextInput, Box, Button, ButtonGroup, IconButton } from '@rocket.chat/fuselage'; import { ContextualbarScrollableContent, ContextualbarFooter } from '@rocket.chat/ui-client'; import { useToastMessageDispatch, type UploadResult } from '@rocket.chat/ui-contexts'; import fileSize from 'filesize'; @@ -92,12 +92,10 @@ const AddCustomSound = ({ goToNew, close, onChange, ...props }: AddCustomSoundPr - {t('Sound File')} - - - - {sound?.name || t('None')} - + {t('Sound File')} + + + {sound?.name || t('None')} diff --git a/apps/meteor/client/views/admin/customSounds/EditSound.tsx b/apps/meteor/client/views/admin/customSounds/EditSound.tsx index 5f4e5a412c75e..603ba7d827231 100644 --- a/apps/meteor/client/views/admin/customSounds/EditSound.tsx +++ b/apps/meteor/client/views/admin/customSounds/EditSound.tsx @@ -1,4 +1,4 @@ -import { Box, Button, ButtonGroup, Margins, TextInput, Field, FieldLabel, FieldRow, IconButton } from '@rocket.chat/fuselage'; +import { Box, Button, ButtonGroup, TextInput, Field, FieldLabel, FieldRow, IconButton } from '@rocket.chat/fuselage'; import { GenericModal, ContextualbarScrollableContent, ContextualbarFooter } from '@rocket.chat/ui-client'; import { useSetModal, useToastMessageDispatch, useEndpoint } from '@rocket.chat/ui-contexts'; import fileSize from 'filesize'; @@ -123,12 +123,10 @@ function EditSound({ close, onChange, data, ...props }: EditSoundProps) { - {t('Sound File')} - - - - {file?.name || (data?.name && data?.extension && `${data.name}.${data.extension}`) || t('None')} - + {t('Sound File')} + + + {file?.name || (data?.name && data?.extension && `${data.name}.${data.extension}`) || t('None')} diff --git a/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusForm.tsx b/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusForm.tsx index 2e3a8a687c2f6..6816211c82ad1 100644 --- a/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusForm.tsx +++ b/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusForm.tsx @@ -97,27 +97,29 @@ const CustomUserStatusForm = ({ onClose, onReload, status }: CustomUserStatusFor return ( <> - - - {t('Name')} - - - - {errors.name && {errors.name.message}} - - - {t('Presence')} - - } + /> + + {errors.statusType && {errors.statusType.message}} + + + diff --git a/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusService.tsx b/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusService.tsx index 54e6844b285c3..4551b388e5cde 100644 --- a/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusService.tsx +++ b/apps/meteor/client/views/admin/customUserStatus/CustomUserStatusService.tsx @@ -3,7 +3,6 @@ import { Button, ButtonGroup, Callout, - Margins, ProgressBar, Skeleton, StatesAction, @@ -58,8 +57,8 @@ const CustomUserStatusService = () => { return ( <> -
- + + {t('Service_status')} { onChange={() => disablePresenceService.mutate()} /> - + {t('Active_connections')} {license?.isEnterprise ? current : `${current}/${max}`} {!license?.isEnterprise && 80 ? 'danger' : 'success'} />} {presenceDisabled && ( - - - {t('Service_disabled_description')} - - + + {t('Service_disabled_description')} + )} -
+
{license?.isEnterprise ? ( <> @@ -111,7 +108,7 @@ const CustomUserStatusService = () => { {!license?.isEnterprise && ( - diff --git a/apps/meteor/client/views/admin/emailInbox/EmailInboxForm.tsx b/apps/meteor/client/views/admin/emailInbox/EmailInboxForm.tsx index e5ca21513cf73..14d4dc0114483 100644 --- a/apps/meteor/client/views/admin/emailInbox/EmailInboxForm.tsx +++ b/apps/meteor/client/views/admin/emailInbox/EmailInboxForm.tsx @@ -10,7 +10,6 @@ import { ToggleSwitch, FieldGroup, Box, - Margins, NumberInput, PasswordInput, FieldLabel, @@ -601,15 +600,13 @@ const EmailInboxForm = ({ inboxData }: EmailInboxFormProps) => { - - - - - - - + + + + + {inboxData?._id && ( )} - + diff --git a/apps/meteor/client/views/admin/engagementDashboard/channels/ChannelsOverview.tsx b/apps/meteor/client/views/admin/engagementDashboard/channels/ChannelsOverview.tsx index bee6f89eb9c9b..5ba67bd6781af 100644 --- a/apps/meteor/client/views/admin/engagementDashboard/channels/ChannelsOverview.tsx +++ b/apps/meteor/client/views/admin/engagementDashboard/channels/ChannelsOverview.tsx @@ -1,4 +1,4 @@ -import { Icon, Margins, Pagination, Skeleton, Table, TableBody, TableCell, TableHead, TableRow, Tile } from '@rocket.chat/fuselage'; +import { Box, Icon, Pagination, Skeleton, Table, TableBody, TableCell, TableHead, TableRow, Tile } from '@rocket.chat/fuselage'; import { format } from 'date-fns/format'; import { useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; @@ -60,8 +60,10 @@ const ChannelsOverview = () => {
{channels && !channels.length && ( - - {t('No_data_found')} + + + {t('No_data_found')} + )} {(!channels || channels.length) && ( @@ -80,10 +82,10 @@ const ChannelsOverview = () => { {i + 1}. - + {(t === 'd' && ) || (t === 'p' && ) || (t === 'c' && )} - - {name} + {name} + {format(new Date(createdAt ?? new Date()), 'P')} {format(new Date(updatedAt ?? new Date()), 'P')} diff --git a/apps/meteor/client/views/admin/engagementDashboard/messages/MessagesPerChannelSection.tsx b/apps/meteor/client/views/admin/engagementDashboard/messages/MessagesPerChannelSection.tsx index 31c7ee427d9a5..9c6fd40878dfc 100644 --- a/apps/meteor/client/views/admin/engagementDashboard/messages/MessagesPerChannelSection.tsx +++ b/apps/meteor/client/views/admin/engagementDashboard/messages/MessagesPerChannelSection.tsx @@ -4,7 +4,6 @@ import { FlexContainer, FlexItem, Icon, - Margins, Skeleton, Table, Tile, @@ -14,6 +13,7 @@ import { TableRow, TableBody, TableCell, + Stack, } from '@rocket.chat/fuselage'; import { useMemo } from 'react'; import { useTranslation } from 'react-i18next'; @@ -70,160 +70,150 @@ const MessagesPerChannelSection = () => { - - - - - - - {pie ? ( - - - - - - {t('Value_messages', { value: datum.value })}} - /> - - - - - - - - - - - {t('Private_Chats')} - - - - {t('Private_Channels')} - - - - {t('Public_Channels')} - - - - - + + + + + {pie ? ( + + + + + {t('Value_messages', { value: datum.value })}} + /> + - ) : ( - - )} - - - - - - - {table ? {t('Most_popular_channels_top_5')} : } - - {table && !table.length && ( - - {t('Not_enough_data')} - - )} - {(!table || !!table.length) && ( - - - - # - {t('Channel')} - {t('Number_of_messages')} + + + + + + {t('Private_Chats')} + + + + {t('Private_Channels')} + + + + {t('Public_Channels')} + + + + + ) : ( + + )} + + + + + + {table ? {t('Most_popular_channels_top_5')} : } + {table && !table.length && ( + + + {t('Not_enough_data')} + + + )} + {(!table || !!table.length) && ( +
+ + + # + {t('Channel')} + {t('Number_of_messages')} + + + + {table?.map(({ i, t, name, messages }) => ( + + {i + 1}. + + + {(t === 'd' && ) || + (t === 'p' && ) || + (t === 'c' && )} + {name} + + + {messages} + + ))} + {!table && + Array.from({ length: 5 }, (_, i) => ( + + + + + + + + + + - - - {table?.map(({ i, t, name, messages }) => ( - - {i + 1}. - - - {(t === 'd' && ) || - (t === 'p' && ) || - (t === 'c' && )} - - {name} - - {messages} - - ))} - {!table && - Array.from({ length: 5 }, (_, i) => ( - - - - - - - - - - - - ))} - -
- )} -
-
-
-
-
+ ))} + + + )} + + +
); diff --git a/apps/meteor/client/views/admin/engagementDashboard/users/ContentForDays.tsx b/apps/meteor/client/views/admin/engagementDashboard/users/ContentForDays.tsx index 99c630a04eeb8..96a2b18c77a25 100644 --- a/apps/meteor/client/views/admin/engagementDashboard/users/ContentForDays.tsx +++ b/apps/meteor/client/views/admin/engagementDashboard/users/ContentForDays.tsx @@ -46,7 +46,7 @@ const ContentForDays = ({ displacement, onPreviousDateClick, onNextDateClick, ti <> - + diff --git a/apps/meteor/client/views/admin/featurePreview/AdminFeaturePreviewPage.tsx b/apps/meteor/client/views/admin/featurePreview/AdminFeaturePreviewPage.tsx index 2a05a6500c4d0..ce4665ce7e8f0 100644 --- a/apps/meteor/client/views/admin/featurePreview/AdminFeaturePreviewPage.tsx +++ b/apps/meteor/client/views/admin/featurePreview/AdminFeaturePreviewPage.tsx @@ -11,7 +11,6 @@ import { FieldRow, FieldHint, Callout, - Margins, } from '@rocket.chat/fuselage'; import { useDefaultSettingFeaturePreviewList, @@ -82,13 +81,11 @@ const AdminFeaturePreviewPage = () => { - - - {t('Feature_preview_admin_page_description')} - {t('Feature_preview_page_callout')} - {t('Feature_preview_admin_page_callout')} - - + + {t('Feature_preview_admin_page_description')} + {t('Feature_preview_page_callout')} + {t('Feature_preview_admin_page_callout')} + {grouppedFeaturesPreview?.map(([group, features], index) => ( @@ -107,7 +104,7 @@ const AdminFeaturePreviewPage = () => { disabled={feature.disabled || !allowFeaturePreviewSetting.value} /> - {feature.description && {t(feature.description)}} + {feature.description && {t(feature.description)}} {feature.imageUrl && } diff --git a/apps/meteor/client/views/admin/import/ImportHistoryPage.tsx b/apps/meteor/client/views/admin/import/ImportHistoryPage.tsx index 8e0933ca3ab97..48e03f8ef34f4 100644 --- a/apps/meteor/client/views/admin/import/ImportHistoryPage.tsx +++ b/apps/meteor/client/views/admin/import/ImportHistoryPage.tsx @@ -131,24 +131,20 @@ function ImportHistoryPage() { - +
- - {t('Import_Type')} - - - {t('Last_Updated')} - + {t('Import_Type')} + {t('Last_Updated')} {!small && ( <> - - {t('Last_Status')} - - - {t('File')} - - + {t('Last_Status')} + {t('File')} + {t('Counters')} @@ -156,21 +152,11 @@ function ImportHistoryPage() { {!small && ( - - {t('Users')} - - - {t('Contacts')} - - - {t('Channels')} - - - {t('Messages')} - - - {t('Total')} - + {t('Users')} + {t('Contacts')} + {t('Channels')} + {t('Messages')} + {t('Total')} )} diff --git a/apps/meteor/client/views/admin/import/ImportProgressPage.tsx b/apps/meteor/client/views/admin/import/ImportProgressPage.tsx index b12a761e43169..8cd34790b1ddb 100644 --- a/apps/meteor/client/views/admin/import/ImportProgressPage.tsx +++ b/apps/meteor/client/views/admin/import/ImportProgressPage.tsx @@ -1,5 +1,5 @@ import type { ProgressStep } from '@rocket.chat/core-typings'; -import { Box, Margins, ProgressBar, Throbber } from '@rocket.chat/fuselage'; +import { Box, ProgressBar, Throbber } from '@rocket.chat/fuselage'; import { useStableCallback } from '@rocket.chat/fuselage-hooks'; import { Page, PageHeader, PageScrollableContentWithShadow } from '@rocket.chat/ui-client'; import { useToastMessageDispatch, useEndpoint, useStream, useRouter } from '@rocket.chat/ui-contexts'; @@ -159,26 +159,24 @@ const ImportProgressPage = function ImportProgressPage() { - - - {currentOperation.isLoading && } - {progress.fetchStatus !== 'idle' && progress.isLoading && } - - {(currentOperation.isError || progress.isError) && {t('Failed_To_Load_Import_Data')}} - {progress.isSuccess && ( - <> - - {t((progress.data.step[0].toUpperCase() + progress.data.step.slice(1)) as any)} + + {currentOperation.isLoading && } + {progress.fetchStatus !== 'idle' && progress.isLoading && } + + {(currentOperation.isError || progress.isError) && {t('Failed_To_Load_Import_Data')}} + {progress.isSuccess && ( + <> + + {t((progress.data.step[0].toUpperCase() + progress.data.step.slice(1)) as any)} + + + + + {numberFormat((progress.data.completed / progress.data.total) * 100, 0)}% - - - - {numberFormat((progress.data.completed / progress.data.total) * 100, 0)}% - - - - )} - + + + )} diff --git a/apps/meteor/client/views/admin/import/NewImportPage.tsx b/apps/meteor/client/views/admin/import/NewImportPage.tsx index fcaa8864e74e1..d9312a08d474b 100644 --- a/apps/meteor/client/views/admin/import/NewImportPage.tsx +++ b/apps/meteor/client/views/admin/import/NewImportPage.tsx @@ -5,7 +5,6 @@ import { Callout, Chip, Field, - Margins, Select, InputBox, TextInput, @@ -205,119 +204,99 @@ function NewImportPage() { router.navigate('/admin/import')}> {importer && ( - )} - - + + + {t('Import_Type')} + + - {importer && ( - - {importer.key === 'csv' ? t('Importer_From_Description_CSV') : t('Importer_From_Description', { from: t(importer.name) })} - - )} - {importer && ( - - - {t('File_Type')} - - -
+
- + 0} indeterminate={channelsCount > 0 && channelsCount !== channels.length} @@ -54,14 +54,14 @@ const PrepareChannels = ({ channels, channelsCount, setChannels }: PrepareChanne }} /> - {t('Name')} - + {t('Name')} + {channels.slice(current, current + itemsPerPage).map((channel) => ( - + ): void => { diff --git a/apps/meteor/client/views/admin/import/PrepareContacts.tsx b/apps/meteor/client/views/admin/import/PrepareContacts.tsx index 62550334fd6ae..b9e9aa67663c4 100644 --- a/apps/meteor/client/views/admin/import/PrepareContacts.tsx +++ b/apps/meteor/client/views/admin/import/PrepareContacts.tsx @@ -16,10 +16,10 @@ const PrepareContacts = ({ contactsCount, contacts, setContacts }: PrepareContac return ( <> -
+
- + 0} indeterminate={contactsCount > 0 && contactsCount !== contacts.length} @@ -32,15 +32,15 @@ const PrepareContacts = ({ contactsCount, contacts, setContacts }: PrepareContac }} /> - {t('Name')} - {t('Emails')} - {t('Phones')} + {t('Name')} + {t('Emails')} + {t('Phones')} {contacts.slice(current, current + itemsPerPage).map((contact) => ( - + ): void => { diff --git a/apps/meteor/client/views/admin/import/PrepareImportPage.tsx b/apps/meteor/client/views/admin/import/PrepareImportPage.tsx index a09a8d54c28ea..5843d9a4df25c 100644 --- a/apps/meteor/client/views/admin/import/PrepareImportPage.tsx +++ b/apps/meteor/client/views/admin/import/PrepareImportPage.tsx @@ -1,5 +1,5 @@ import type { IImport, IImporterSelection, IImporterSelectionContact, Serialized } from '@rocket.chat/core-typings'; -import { Badge, Box, Button, ButtonGroup, Margins, ProgressBar, Throbber, Tabs, TabsItem } from '@rocket.chat/fuselage'; +import { Badge, Box, Button, ButtonGroup, ProgressBar, Throbber, Tabs, TabsItem } from '@rocket.chat/fuselage'; import { useDebouncedValue, useSafely } from '@rocket.chat/fuselage-hooks'; import { Page, PageHeader, PageScrollableContentWithShadow } from '@rocket.chat/ui-client'; import { useEndpoint, useStream, useRouter } from '@rocket.chat/ui-contexts'; @@ -202,50 +202,59 @@ function PrepareImportPage() { - - - {statusDebounced && t(statusDebounced.replace('importer_', 'importer_status_'))} + + + + {statusDebounced && t(statusDebounced.replace('importer_', 'importer_status_'))} + + {!isPreparing && ( + + + {t('Users')} {usersCount} + + + {t('Contacts')} {contactsCount} + + + {t('Channels')} {channelsCount} + + + {t('Messages')} + {messageCount} + + + )} - {!isPreparing && ( - - - {t('Users')} {usersCount} - - - {t('Contacts')} {contactsCount} - - - {t('Channels')} {channelsCount} - - - {t('Messages')} - {messageCount} - - - )} - - {isPreparing && ( - <> - {progressRate ? ( - - - - {numberFormat(progressRate, 0)}% - + {isPreparing && ( + <> + {progressRate ? ( + + + + {numberFormat(progressRate, 0)}% - ) : ( - - )} - - )} - {!isPreparing && tab === 'users' && } - {!isPreparing && tab === 'contacts' && ( - - )} - {!isPreparing && tab === 'channels' && ( - - )} - + + ) : ( + + )} + + )} + {!isPreparing && tab === 'users' && } + {!isPreparing && tab === 'contacts' && ( + + )} + {!isPreparing && tab === 'channels' && ( + + )} diff --git a/apps/meteor/client/views/admin/import/PrepareUsers.tsx b/apps/meteor/client/views/admin/import/PrepareUsers.tsx index 59b9c9ce2c3ea..936cf1a0cee0c 100644 --- a/apps/meteor/client/views/admin/import/PrepareUsers.tsx +++ b/apps/meteor/client/views/admin/import/PrepareUsers.tsx @@ -25,10 +25,10 @@ const PrepareUsers = ({ usersCount, users, setUsers }: PrepareUsersProps) => { return ( <> -
+
- + 0} indeterminate={usersCount > 0 && usersCount !== users.length} @@ -50,15 +50,15 @@ const PrepareUsers = ({ usersCount, users, setUsers }: PrepareUsersProps) => { }} /> - {t('Username')} - {t('Email')} - + {t('Username')} + {t('Email')} + {users.slice(current, current + itemsPerPage).map((user) => ( - + ): void => { diff --git a/apps/meteor/client/views/admin/integrations/EditIntegrationsPageWithData.tsx b/apps/meteor/client/views/admin/integrations/EditIntegrationsPageWithData.tsx index 6339474af190e..449949c20c491 100644 --- a/apps/meteor/client/views/admin/integrations/EditIntegrationsPageWithData.tsx +++ b/apps/meteor/client/views/admin/integrations/EditIntegrationsPageWithData.tsx @@ -1,5 +1,5 @@ import type { IIncomingIntegration } from '@rocket.chat/core-typings'; -import { Box, Skeleton } from '@rocket.chat/fuselage'; +import { Box, Skeleton, Stack } from '@rocket.chat/fuselage'; import { useEndpoint } from '@rocket.chat/ui-contexts'; import { useQuery } from '@tanstack/react-query'; import { useMemo } from 'react'; @@ -22,13 +22,19 @@ const EditIntegrationsPageWithData = ({ integrationId }: EditIntegrationsPageWit if (isPending) { return ( - - - - - - - + + + + + + + + + + + + + ); } diff --git a/apps/meteor/client/views/admin/integrations/NewZapier.tsx b/apps/meteor/client/views/admin/integrations/NewZapier.tsx index f9447a1bae792..a64420db862d2 100644 --- a/apps/meteor/client/views/admin/integrations/NewZapier.tsx +++ b/apps/meteor/client/views/admin/integrations/NewZapier.tsx @@ -1,4 +1,4 @@ -import { Box, Skeleton, Margins, Callout } from '@rocket.chat/fuselage'; +import { Box, Skeleton, Callout } from '@rocket.chat/fuselage'; import { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; @@ -49,33 +49,29 @@ const NewZapier = ({ ...props }) => { } return ( - <> + {t(!zapierAvailable ? 'Install_Zapier_from_marketplace_new_workspaces' : 'Install_Zapier_from_marketplace')} {zapierAvailable && ( - <> + {!script && ( - - - - - - - - + + + + + + )} - + )} - + ); }; diff --git a/apps/meteor/client/views/admin/integrations/incoming/IncomingWebhookForm.tsx b/apps/meteor/client/views/admin/integrations/incoming/IncomingWebhookForm.tsx index 3b575f181abdf..77469bc3d19dd 100644 --- a/apps/meteor/client/views/admin/integrations/incoming/IncomingWebhookForm.tsx +++ b/apps/meteor/client/views/admin/integrations/incoming/IncomingWebhookForm.tsx @@ -252,7 +252,7 @@ const IncomingWebhookForm = ({ webhookData }: IncomingWebhookFormProps) => { id={avatarField} {...field} aria-describedby={`${avatarField}-hint-1 ${avatarField}-hint-2`} - endAddon={} + endAddon={} /> )} /> @@ -271,7 +271,7 @@ const IncomingWebhookForm = ({ webhookData }: IncomingWebhookFormProps) => { id={emojiField} {...field} aria-describedby={`${emojiField}-hint-1 ${emojiField}-hint-2`} - endAddon={} + endAddon={} /> )} /> @@ -327,9 +327,7 @@ const IncomingWebhookForm = ({ webhookData }: IncomingWebhookFormProps) => { ( - } /> - )} + render={({ field }) => } />} /> diff --git a/apps/meteor/client/views/admin/integrations/outgoing/OutgoingWebhookForm.tsx b/apps/meteor/client/views/admin/integrations/outgoing/OutgoingWebhookForm.tsx index a691ce5077f0b..afc7401ff93e6 100644 --- a/apps/meteor/client/views/admin/integrations/outgoing/OutgoingWebhookForm.tsx +++ b/apps/meteor/client/views/admin/integrations/outgoing/OutgoingWebhookForm.tsx @@ -316,14 +316,7 @@ const OutgoingWebhookForm = () => { - } + endAddon={} /> )} /> @@ -341,9 +334,7 @@ const OutgoingWebhookForm = () => { - } + endAddon={} /> )} /> @@ -414,9 +405,7 @@ const OutgoingWebhookForm = () => { ( - } /> - )} + render={({ field }) => } />} /> diff --git a/apps/meteor/client/views/admin/integrations/outgoing/history/HistoryContent.tsx b/apps/meteor/client/views/admin/integrations/outgoing/history/HistoryContent.tsx index 2798d33bc88f8..8829bfa38b256 100644 --- a/apps/meteor/client/views/admin/integrations/outgoing/history/HistoryContent.tsx +++ b/apps/meteor/client/views/admin/integrations/outgoing/history/HistoryContent.tsx @@ -1,5 +1,5 @@ import type { IIntegrationHistory, Serialized } from '@rocket.chat/core-typings'; -import { Skeleton, Box, Accordion } from '@rocket.chat/fuselage'; +import { Skeleton, Box, Accordion, Stack } from '@rocket.chat/fuselage'; import { useTranslation } from 'react-i18next'; import HistoryItem from './HistoryItem'; @@ -11,13 +11,19 @@ const HistoryContent = ({ data, isLoading }: HistoryContentProps) => { if (isLoading) { return ( - - - - - - - + + + + + + + + + + + + + ); } @@ -27,8 +33,8 @@ const HistoryContent = ({ data, isLoading }: HistoryContentProps) => { } return ( - - + + {data.map((current) => ( ))} diff --git a/apps/meteor/client/views/admin/integrations/outgoing/history/HistoryItem.tsx b/apps/meteor/client/views/admin/integrations/outgoing/history/HistoryItem.tsx index ae85552308789..c8df447895e0c 100644 --- a/apps/meteor/client/views/admin/integrations/outgoing/history/HistoryItem.tsx +++ b/apps/meteor/client/views/admin/integrations/outgoing/history/HistoryItem.tsx @@ -1,5 +1,5 @@ import type { IIntegrationHistory, Serialized } from '@rocket.chat/core-typings'; -import { Button, Icon, Box, AccordionItem, Field, FieldGroup, FieldLabel, FieldRow } from '@rocket.chat/fuselage'; +import { Button, Icon, Box, AccordionItem, Field, FieldGroup, FieldLabel, FieldRow, Stack } from '@rocket.chat/fuselage'; import { useStableCallback } from '@rocket.chat/fuselage-hooks'; import { useFormatDateAndTime } from '@rocket.chat/ui-client'; import { useEndpoint } from '@rocket.chat/ui-contexts'; @@ -57,10 +57,10 @@ const HistoryItem = ({ data }: HistoryItemProps) => { - - + + {formatDateAndTime(_createdAt)} - + diff --git a/apps/meteor/client/views/admin/moderation/ModConsoleReportDetails.tsx b/apps/meteor/client/views/admin/moderation/ModConsoleReportDetails.tsx index 743f449a2b000..db3323bb69e18 100644 --- a/apps/meteor/client/views/admin/moderation/ModConsoleReportDetails.tsx +++ b/apps/meteor/client/views/admin/moderation/ModConsoleReportDetails.tsx @@ -1,5 +1,5 @@ import type { IUser } from '@rocket.chat/core-typings'; -import { Tabs, TabsItem } from '@rocket.chat/fuselage'; +import { Box, Tabs, TabsItem } from '@rocket.chat/fuselage'; import { useStableCallback } from '@rocket.chat/fuselage-hooks'; import { ContextualbarClose, ContextualbarDialog, ContextualbarHeader, ContextualbarTitle } from '@rocket.chat/ui-client'; import { useTranslation, useRouter, useRouteParameter } from '@rocket.chat/ui-contexts'; @@ -29,14 +29,16 @@ const ModConsoleReportDetails = ({ userId, default: defaultTab, onRedirect }: Mo {t('Reports')} - - setTab('messages')}> - {t('Messages')} - - setTab('users')}> - {t('User')} - - + + + setTab('messages')}> + {t('Messages')} + + setTab('users')}> + {t('User')} + + + {tab === 'messages' && } {tab === 'users' && } diff --git a/apps/meteor/client/views/admin/moderation/UserMessages.tsx b/apps/meteor/client/views/admin/moderation/UserMessages.tsx index 1a8f68048eca5..f93cb79266268 100644 --- a/apps/meteor/client/views/admin/moderation/UserMessages.tsx +++ b/apps/meteor/client/views/admin/moderation/UserMessages.tsx @@ -40,14 +40,14 @@ const UserMessages = ({ userId, onRedirect }: { userId: string; onRedirect: (mid {isLoading && {t('Loading')}} {isSuccess && ( - + {report.messages.length > 0 && ( {t('Moderation_Duplicate_messages_warning')} )} {!report.user && ( - + {t('Moderation_User_deleted_warning')} )} diff --git a/apps/meteor/client/views/admin/moderation/UserReports/UserReportInfo.tsx b/apps/meteor/client/views/admin/moderation/UserReports/UserReportInfo.tsx index 21a3d22d27751..7322acf89373e 100644 --- a/apps/meteor/client/views/admin/moderation/UserReports/UserReportInfo.tsx +++ b/apps/meteor/client/views/admin/moderation/UserReports/UserReportInfo.tsx @@ -85,10 +85,12 @@ const UserReportInfo = ({ userId }: UserReportInfoProps) => { {userProfile} {t('Roles')} - - {report.user.roles.map((role, index) => ( - {role} - ))} + + + {report.user.roles.map((role, index) => ( + {role} + ))} + @@ -101,9 +103,11 @@ const UserReportInfo = ({ userId }: UserReportInfoProps) => { ) : ( - - {t('Moderation_User_deleted_warning')} - + + + {t('Moderation_User_deleted_warning')} + + )} {report.reports.map((report, ind) => ( diff --git a/apps/meteor/client/views/admin/moderation/helpers/DateRangePicker.tsx b/apps/meteor/client/views/admin/moderation/helpers/DateRangePicker.tsx index ecdc6b17053fa..4df1b00cee1ce 100644 --- a/apps/meteor/client/views/admin/moderation/helpers/DateRangePicker.tsx +++ b/apps/meteor/client/views/admin/moderation/helpers/DateRangePicker.tsx @@ -86,7 +86,7 @@ const DateRangePicker = ({ onChange, defaultSelectedKey = 'alldates' }: DateRang return ( - ); }; diff --git a/apps/meteor/client/views/admin/oauthApps/EditOauthApp.tsx b/apps/meteor/client/views/admin/oauthApps/EditOauthApp.tsx index 8b2f6ba1d1d91..09a18026d2c52 100644 --- a/apps/meteor/client/views/admin/oauthApps/EditOauthApp.tsx +++ b/apps/meteor/client/views/admin/oauthApps/EditOauthApp.tsx @@ -1,5 +1,6 @@ import type { IOAuthApps, Serialized } from '@rocket.chat/core-typings'; import { + Box, Button, ButtonGroup, TextInput, @@ -106,78 +107,80 @@ const EditOauthApp = ({ onChange, data, ...props }: EditOauthAppProps) => { return ( - - - - {t('Active')} - } - /> - - - - {t('Application_Name')} - - - - {t('Give_the_application_a_name_This_will_be_seen_by_your_users')} - {errors?.name && {t('Required_field', { field: t('Name') })}} - - - {t('Redirect_URI')} - - - - {t('After_OAuth2_authentication_users_will_be_redirected_to_this_URL')} - {errors?.redirectUri && {t('Required_field', { field: t('Redirect_URI') })}} - - - {t('Client_ID')} - - - - - - {t('Client_Secret')} - - - - - - {t('Authorization_URL')} - - - - - - {t('Access_Token_URL')} - - - - - - - - - - - - - - - - - - - - + + + + + {t('Active')} + } + /> + + + + {t('Application_Name')} + + + + {t('Give_the_application_a_name_This_will_be_seen_by_your_users')} + {errors?.name && {t('Required_field', { field: t('Name') })}} + + + {t('Redirect_URI')} + + + + {t('After_OAuth2_authentication_users_will_be_redirected_to_this_URL')} + {errors?.redirectUri && {t('Required_field', { field: t('Redirect_URI') })}} + + + {t('Client_ID')} + + + + + + {t('Client_Secret')} + + + + + + {t('Authorization_URL')} + + + + + + {t('Access_Token_URL')} + + + + + + + + + + + + + + + + + + + + + ); }; diff --git a/apps/meteor/client/views/admin/oauthApps/OAuthAddApp.tsx b/apps/meteor/client/views/admin/oauthApps/OAuthAddApp.tsx index 2253920796522..7da2a6dad1fdc 100644 --- a/apps/meteor/client/views/admin/oauthApps/OAuthAddApp.tsx +++ b/apps/meteor/client/views/admin/oauthApps/OAuthAddApp.tsx @@ -1,4 +1,5 @@ import { + Box, Button, ButtonGroup, TextInput, @@ -56,45 +57,47 @@ const OAuthAddApp = () => { return ( - - - - {t('Active')} - } - /> - - - - {t('Application_Name')} - - - - {t('Give_the_application_a_name_This_will_be_seen_by_your_users')} - {errors?.name && {errors.name.message}} - - - {t('Redirect_URI')} - - - - {t('After_OAuth2_authentication_users_will_be_redirected_to_this_URL')} - {errors?.redirectUri && {t('Required_field', { field: t('Redirect_URI') })}} - - - - - - - - - - + + + + + {t('Active')} + } + /> + + + + {t('Application_Name')} + + + + {t('Give_the_application_a_name_This_will_be_seen_by_your_users')} + {errors?.name && {errors.name.message}} + + + {t('Redirect_URI')} + + + + {t('After_OAuth2_authentication_users_will_be_redirected_to_this_URL')} + {errors?.redirectUri && {t('Required_field', { field: t('Redirect_URI') })}} + + + + + + + + + + + ); }; diff --git a/apps/meteor/client/views/admin/permissions/PermissionsPage.tsx b/apps/meteor/client/views/admin/permissions/PermissionsPage.tsx index ac66a33cf49f1..6da018ae8a8eb 100644 --- a/apps/meteor/client/views/admin/permissions/PermissionsPage.tsx +++ b/apps/meteor/client/views/admin/permissions/PermissionsPage.tsx @@ -57,21 +57,19 @@ const PermissionsPage = ({ isEnterprise }: PermissionsPageProps) => { {t('New_role')} - - - - {t('Permissions')} - - - {t('Settings')} - - - - + + + {t('Permissions')} + + + {t('Settings')} + + + - + - {!loading && ( - - {description || name} - - )} - {loading && } - + + {!loading && ( + + {description || name} + + )} + {loading && ( + + + + )} ); }; diff --git a/apps/meteor/client/views/admin/permissions/UsersInRole/UsersInRolePage.tsx b/apps/meteor/client/views/admin/permissions/UsersInRole/UsersInRolePage.tsx index 984d12ead454c..96492695862c0 100644 --- a/apps/meteor/client/views/admin/permissions/UsersInRole/UsersInRolePage.tsx +++ b/apps/meteor/client/views/admin/permissions/UsersInRole/UsersInRolePage.tsx @@ -1,5 +1,5 @@ import type { IRole, IRoom } from '@rocket.chat/core-typings'; -import { Box, Field, FieldLabel, FieldRow, Margins, ButtonGroup, Button, Callout, FieldError } from '@rocket.chat/fuselage'; +import { Box, Field, FieldLabel, FieldRow, ButtonGroup, Button, Callout, FieldError, Stack } from '@rocket.chat/fuselage'; import { useStableCallback } from '@rocket.chat/fuselage-hooks'; import { usePagination, Page, PageHeader, PageContent } from '@rocket.chat/ui-client'; import { useToastMessageDispatch, useEndpoint, useRouter } from '@rocket.chat/ui-contexts'; @@ -87,41 +87,41 @@ const UsersInRolePage = ({ role }: UsersInRolePageProps) => { - - - - {role.scope !== 'Users' && ( - - {t('Choose_a_room')} - - ( - - )} - /> - - {errors.rid && ( - - {errors.rid.message} - - )} - - )} + + + {role.scope !== 'Users' && ( - {t('Add_users')} + {t('Choose_a_room')} + ( + + )} + /> + + {errors.rid && ( + + {errors.rid.message} + + )} + + )} + + {t('Add_users')} + + { /> )} /> - + + + {errors.users && ( + + + {errors.users.message} + - {errors.users && ( - - - {errors.users.message} - - - )} - - + )} + - - {(role.scope === 'Users' || rid) && ( - - )} - {role.scope !== 'Users' && !rid && {t('Select_a_room')}} - + {(role.scope === 'Users' || rid) && ( + + )} + {role.scope !== 'Users' && !rid && {t('Select_a_room')}} ); diff --git a/apps/meteor/client/views/admin/rooms/EditRoom.tsx b/apps/meteor/client/views/admin/rooms/EditRoom.tsx index f26679414d662..24b3bc3c52074 100644 --- a/apps/meteor/client/views/admin/rooms/EditRoom.tsx +++ b/apps/meteor/client/views/admin/rooms/EditRoom.tsx @@ -142,7 +142,9 @@ const EditRoom = ({ room, onChange, onDelete, onClose }: EditRoomProps) => { onCancel={() => setModal(null)} onClose={() => setModal(null)} > - + + + , ); }); diff --git a/apps/meteor/client/views/admin/rooms/RoomRow.tsx b/apps/meteor/client/views/admin/rooms/RoomRow.tsx index 722085881417d..c3b0a60beb9cb 100644 --- a/apps/meteor/client/views/admin/rooms/RoomRow.tsx +++ b/apps/meteor/client/views/admin/rooms/RoomRow.tsx @@ -71,8 +71,12 @@ const RoomRow = ({ room }: RoomRowProps) => { alignSelf='center' alignItems='center' withTruncatedText + gap={4} + paddingInlineStart={icon ? 4 : undefined} + fontScale='p2m' + color='hint' > - {icon && } + {icon && } {roomName} diff --git a/apps/meteor/client/views/admin/rooms/RoomsTableFilters.tsx b/apps/meteor/client/views/admin/rooms/RoomsTableFilters.tsx index 4b9c61c5d284e..bb49be0c22994 100644 --- a/apps/meteor/client/views/admin/rooms/RoomsTableFilters.tsx +++ b/apps/meteor/client/views/admin/rooms/RoomsTableFilters.tsx @@ -88,7 +88,6 @@ const RoomsTableFilters = ({ setFilters }: RoomsTableFiltersProps) => { } onChange={handleSearchTextChange} diff --git a/apps/meteor/client/views/admin/settings/Setting/MemoizedSetting.tsx b/apps/meteor/client/views/admin/settings/Setting/MemoizedSetting.tsx index 135b6352cc112..ff9da90d9603c 100644 --- a/apps/meteor/client/views/admin/settings/Setting/MemoizedSetting.tsx +++ b/apps/meteor/client/views/admin/settings/Setting/MemoizedSetting.tsx @@ -1,5 +1,5 @@ import type { ISettingBase, SettingEditor, SettingValue } from '@rocket.chat/core-typings'; -import { Box, Callout, Field, Margins } from '@rocket.chat/fuselage'; +import { Box, Callout } from '@rocket.chat/fuselage'; import type { ElementType, ReactNode } from 'react'; import { memo } from 'react'; @@ -92,25 +92,19 @@ const MemoizedSetting = ({ const InputComponent = inputsByType[type]; return ( - - - - {callout && ( - - {callout} - - )} - {showUpgradeButton} - - + + + {callout && {callout}} + {showUpgradeButton} + ); }; diff --git a/apps/meteor/client/views/admin/settings/Setting/ResetSettingButton/ResetSettingButton.tsx b/apps/meteor/client/views/admin/settings/Setting/ResetSettingButton/ResetSettingButton.tsx index 2193dcbb39f71..8a514f3e9702a 100644 --- a/apps/meteor/client/views/admin/settings/Setting/ResetSettingButton/ResetSettingButton.tsx +++ b/apps/meteor/client/views/admin/settings/Setting/ResetSettingButton/ResetSettingButton.tsx @@ -1,9 +1,8 @@ -import type { Button } from '@rocket.chat/fuselage'; import { IconButton } from '@rocket.chat/fuselage'; import type { ComponentProps } from 'react'; import { useTranslation } from 'react-i18next'; -function ResetSettingButton(props: ComponentProps) { +function ResetSettingButton(props: Omit, 'icon'>) { const { t } = useTranslation(); return ; diff --git a/apps/meteor/client/views/admin/settings/Setting/Setting.tsx b/apps/meteor/client/views/admin/settings/Setting/Setting.tsx index 9d4a4b9d59051..f9aed9174969c 100644 --- a/apps/meteor/client/views/admin/settings/Setting/Setting.tsx +++ b/apps/meteor/client/views/admin/settings/Setting/Setting.tsx @@ -1,6 +1,6 @@ import type { ISettingColor, SettingEditor, SettingValue } from '@rocket.chat/core-typings'; import { isSettingColor, isSetting, isSettingCode } from '@rocket.chat/core-typings'; -import { Box, Button, Tag } from '@rocket.chat/fuselage'; +import { Box, Button, ButtonGroup, Tag } from '@rocket.chat/fuselage'; import { useDebouncedCallback } from '@rocket.chat/fuselage-hooks'; import { useSettingStructure } from '@rocket.chat/ui-contexts'; import { useEffect, useMemo, useState, useCallback } from 'react'; @@ -139,9 +139,11 @@ function Setting({ className = undefined, settingId, sectionChanged }: SettingPr const showUpgradeButton = useMemo( () => shouldDisableEnterprise ? ( - + + + ) : undefined, [shouldDisableEnterprise, t], ); diff --git a/apps/meteor/client/views/admin/settings/Setting/inputs/ActionInputBase.spec.tsx b/apps/meteor/client/views/admin/settings/Setting/inputs/ActionInputBase.spec.tsx new file mode 100644 index 0000000000000..714a6c806a94a --- /dev/null +++ b/apps/meteor/client/views/admin/settings/Setting/inputs/ActionInputBase.spec.tsx @@ -0,0 +1,24 @@ +import { mockAppRoot } from '@rocket.chat/mock-providers'; +import type { TranslationKey } from '@rocket.chat/ui-contexts'; +import { render, screen } from '@testing-library/react'; + +import ActionInputBase from './ActionInputBase'; + +it('describes the action button with the setting label and keeps the action as its name', () => { + render( + , + { wrapper: mockAppRoot().withTranslations('en', 'core', { Send_a_test_mail_to_my_user: 'Send a test email to my user' }).build() }, + ); + + expect(screen.getByRole('button', { name: 'Send a test email to my user' })).toHaveAccessibleDescription('Send a test email'); +}); diff --git a/apps/meteor/client/views/admin/settings/Setting/inputs/ActionInputBase.tsx b/apps/meteor/client/views/admin/settings/Setting/inputs/ActionInputBase.tsx index d2a860152e4fd..bad800341d361 100644 --- a/apps/meteor/client/views/admin/settings/Setting/inputs/ActionInputBase.tsx +++ b/apps/meteor/client/views/admin/settings/Setting/inputs/ActionInputBase.tsx @@ -1,6 +1,7 @@ -import { Button, FieldRow, FieldHint } from '@rocket.chat/fuselage'; +import { Button, Field, FieldHint, FieldLabel, FieldRow } from '@rocket.chat/fuselage'; import type { TranslationKey } from '@rocket.chat/ui-contexts'; import { useToastMessageDispatch } from '@rocket.chat/ui-contexts'; +import { useId } from 'react'; import { useTranslation } from 'react-i18next'; import type { SettingInputProps } from './types'; @@ -11,9 +12,10 @@ export type ActionInputBaseProps = SettingInputProps & { onAction: () => Promise<{ message: TranslationKey; params?: string[] }>; }; -function ActionInputBase({ actionText, hint, disabled, sectionChanged, onAction }: ActionInputBaseProps) { +function ActionInputBase({ _id, label, actionText, hint, disabled, sectionChanged, onAction }: ActionInputBaseProps) { const { t } = useTranslation(); const dispatchToastMessage = useToastMessageDispatch(); + const labelId = useId(); const handleClick = async (): Promise => { try { @@ -26,15 +28,20 @@ function ActionInputBase({ actionText, hint, disabled, sectionChanged, onAction }; return ( - <> + - {sectionChanged && {t('Save_to_enable_this_action')}} {hint && {hint}} - + ); } diff --git a/apps/meteor/client/views/admin/settings/Setting/inputs/ActionSettingInput.stories.tsx b/apps/meteor/client/views/admin/settings/Setting/inputs/ActionSettingInput.stories.tsx index c8923dfb6b01f..b9bcfbf1c5a25 100644 --- a/apps/meteor/client/views/admin/settings/Setting/inputs/ActionSettingInput.stories.tsx +++ b/apps/meteor/client/views/admin/settings/Setting/inputs/ActionSettingInput.stories.tsx @@ -1,17 +1,16 @@ import type { ServerMethods } from '@rocket.chat/ddp-client'; -import { Field } from '@rocket.chat/fuselage'; import type { Meta } from '@storybook/react'; import ActionSettingInput from './ActionSettingInput'; export default { component: ActionSettingInput, - decorators: [(fn) => {fn()}], } satisfies Meta; export const Default = { args: { _id: 'setting_id', + label: 'Test SMTP settings', actionText: 'Action text', value: 'methodName' as keyof ServerMethods, }, @@ -20,6 +19,7 @@ export const Default = { export const Disabled = { args: { _id: 'setting_id', + label: 'Test SMTP settings', actionText: 'Action text', value: 'methodName' as keyof ServerMethods, disabled: true, @@ -29,6 +29,7 @@ export const Disabled = { export const WithinChangedSection = { args: { _id: 'setting_id', + label: 'Test SMTP settings', actionText: 'Action text', value: 'methodName' as keyof ServerMethods, sectionChanged: true, diff --git a/apps/meteor/client/views/admin/settings/Setting/inputs/AssetSettingInput.spec.tsx b/apps/meteor/client/views/admin/settings/Setting/inputs/AssetSettingInput.spec.tsx index 42dd9e8cb24da..fa1d9537e9bb2 100644 --- a/apps/meteor/client/views/admin/settings/Setting/inputs/AssetSettingInput.spec.tsx +++ b/apps/meteor/client/views/admin/settings/Setting/inputs/AssetSettingInput.spec.tsx @@ -161,6 +161,12 @@ describe('AssetSettingInput', () => { expect(label).toHaveTextContent('Site logo*'); }); + it('labels the file input with the setting label', () => { + const { getFileInput } = setup(); + + expect(screen.getByLabelText('Site logo', { selector: 'input' })).toBe(getFileInput()); + }); + it('renders an optional label without a required marker', () => { setup({ required: false }); diff --git a/apps/meteor/client/views/admin/settings/Setting/inputs/AssetSettingInput.tsx b/apps/meteor/client/views/admin/settings/Setting/inputs/AssetSettingInput.tsx index 705188b794403..533a7c41ac955 100644 --- a/apps/meteor/client/views/admin/settings/Setting/inputs/AssetSettingInput.tsx +++ b/apps/meteor/client/views/admin/settings/Setting/inputs/AssetSettingInput.tsx @@ -3,6 +3,7 @@ import { Box, Button, Field, FieldHint, FieldLabel, FieldRow, Icon, Palette } fr import { Random } from '@rocket.chat/random'; import { useToastMessageDispatch, useEndpoint, useTranslation, useUpload } from '@rocket.chat/ui-contexts'; import type { ChangeEventHandler, DragEvent, SyntheticEvent } from 'react'; +import { useId } from 'react'; import type { SettingInputProps } from './types'; @@ -13,6 +14,7 @@ export type AssetSettingInputProps = Omit, 'o function AssetSettingInput({ _id, label, value, hint, asset, required, disabled, fileConstraints }: AssetSettingInputProps) { const t = useTranslation(); + const labelId = useId(); const dispatchToastMessage = useToastMessageDispatch(); const setAsset = useUpload('/v1/assets.setAsset'); @@ -94,11 +96,13 @@ function AssetSettingInput({ _id, label, value, hint, asset, required, disabled, return ( - - {label} - - + + {label} + + + + {value?.url ? (
{t('Select_file')} - + )}
diff --git a/apps/meteor/client/views/admin/settings/Setting/inputs/BooleanSettingInput.tsx b/apps/meteor/client/views/admin/settings/Setting/inputs/BooleanSettingInput.tsx index 5648d7e60d500..d668e7cd23b7c 100644 --- a/apps/meteor/client/views/admin/settings/Setting/inputs/BooleanSettingInput.tsx +++ b/apps/meteor/client/views/admin/settings/Setting/inputs/BooleanSettingInput.tsx @@ -25,7 +25,7 @@ function BooleanSettingInput({ return ( - + {label} diff --git a/apps/meteor/client/views/admin/settings/Setting/inputs/CodeMirror/CodeMirrorBox.tsx b/apps/meteor/client/views/admin/settings/Setting/inputs/CodeMirror/CodeMirrorBox.tsx index 4ca407311d066..b364390577340 100644 --- a/apps/meteor/client/views/admin/settings/Setting/inputs/CodeMirror/CodeMirrorBox.tsx +++ b/apps/meteor/client/views/admin/settings/Setting/inputs/CodeMirror/CodeMirrorBox.tsx @@ -44,7 +44,7 @@ const CodeMirrorBox = ({ label, children, error }: CodeMirrorBoxProps) => { {children}
{error && ( - + {error} )} @@ -75,7 +75,7 @@ const CodeMirrorBox = ({ label, children, error }: CodeMirrorBoxProps) => { {children}
{error && ( - + {error} )} diff --git a/apps/meteor/client/views/admin/settings/Setting/inputs/ColorSettingInput.tsx b/apps/meteor/client/views/admin/settings/Setting/inputs/ColorSettingInput.tsx index 6e2dc26932ac3..119d29e7b8bdd 100644 --- a/apps/meteor/client/views/admin/settings/Setting/inputs/ColorSettingInput.tsx +++ b/apps/meteor/client/views/admin/settings/Setting/inputs/ColorSettingInput.tsx @@ -1,5 +1,5 @@ import type { SettingEditor } from '@rocket.chat/core-typings'; -import { FieldLabel, FieldRow, FieldHint, FlexItem, InputBox, Margins, TextInput, Select, Field } from '@rocket.chat/fuselage'; +import { Box, FieldLabel, FieldRow, FieldHint, FlexItem, InputBox, TextInput, Select, Field } from '@rocket.chat/fuselage'; import type { TranslationKey } from '@rocket.chat/ui-contexts'; import type { ChangeEvent, Key } from 'react'; import { useCallback } from 'react'; @@ -55,47 +55,45 @@ function ColorSettingInput({ {hasResetButton && } - - - - - {editor === 'color' && ( - - )} - {editor === 'expression' && ( - - )} - - [type, t(type)])} + /> +
+ Variable name: {_id.replace(/theme-color-/, '@')} {hint && {hint}} diff --git a/apps/meteor/client/views/admin/settings/Setting/inputs/RangeSettingInput.tsx b/apps/meteor/client/views/admin/settings/Setting/inputs/RangeSettingInput.tsx index ec062c060d9cb..ec4956ab03540 100644 --- a/apps/meteor/client/views/admin/settings/Setting/inputs/RangeSettingInput.tsx +++ b/apps/meteor/client/views/admin/settings/Setting/inputs/RangeSettingInput.tsx @@ -31,11 +31,6 @@ function RangeSettingInput({ {hasResetButton && } - {hint && ( - - {hint} - - )} + {hint && {hint}} ); } diff --git a/apps/meteor/client/views/admin/settings/SettingsGroupCard.tsx b/apps/meteor/client/views/admin/settings/SettingsGroupCard.tsx index a48e26001c3d4..0594c6d8abace 100644 --- a/apps/meteor/client/views/admin/settings/SettingsGroupCard.tsx +++ b/apps/meteor/client/views/admin/settings/SettingsGroupCard.tsx @@ -28,7 +28,7 @@ const SettingsGroupCard = ({ id, title, description, ...props }: SettingsGroupCa const descriptionId = useId(); return ( - + {t(title)} diff --git a/apps/meteor/client/views/admin/settings/SettingsSection/SettingsSection.tsx b/apps/meteor/client/views/admin/settings/SettingsSection/SettingsSection.tsx index 0561b7502db76..2a1e401150c5e 100644 --- a/apps/meteor/client/views/admin/settings/SettingsSection/SettingsSection.tsx +++ b/apps/meteor/client/views/admin/settings/SettingsSection/SettingsSection.tsx @@ -1,5 +1,5 @@ import { isSetting, isSettingColor } from '@rocket.chat/core-typings'; -import { AccordionItem, Box, Button, FieldGroup } from '@rocket.chat/fuselage'; +import { AccordionItem, Box, Button, ButtonGroup, FieldGroup, Stack } from '@rocket.chat/fuselage'; import { useStableCallback } from '@rocket.chat/fuselage-hooks'; import type { ReactNode } from 'react'; import { useMemo } from 'react'; @@ -81,18 +81,22 @@ function SettingsSection({ groupId, hasReset = true, sectionTitle, sectionName, {help} )} - - {editableSettings.map( - (setting) => isSetting(setting) && , - )} + + + {editableSettings.map( + (setting) => isSetting(setting) && , + )} - {children} - - {hasReset && canReset && ( - - )} + {children} + + {hasReset && canReset && ( + + + + )} +
); } diff --git a/apps/meteor/client/views/admin/settings/groups/SAMLGroupPage/SamlMetadataModal.tsx b/apps/meteor/client/views/admin/settings/groups/SAMLGroupPage/SamlMetadataModal.tsx index 36c2a3150c5bc..e155ba4f7318f 100644 --- a/apps/meteor/client/views/admin/settings/groups/SAMLGroupPage/SamlMetadataModal.tsx +++ b/apps/meteor/client/views/admin/settings/groups/SAMLGroupPage/SamlMetadataModal.tsx @@ -1,4 +1,4 @@ -import { Box, Callout, Field, FieldLabel, FieldRow, TextAreaInput, TextInput } from '@rocket.chat/fuselage'; +import { Box, Callout, Field, FieldLabel, FieldRow, TextAreaInput, TextInput, Stack } from '@rocket.chat/fuselage'; import { GenericModal } from '@rocket.chat/ui-client'; import type { ChangeEvent } from 'react'; import { useId, useState } from 'react'; @@ -98,8 +98,8 @@ const SamlMetadataModal = ({ onClose, onFetch, onApply, showIdentifierFormat = f confirmDisabled={fetching || (!values && url.trim() === '')} confirmLoading={fetching} > - - {t('SAML_Metadata_modal_description')} + + {t('SAML_Metadata_modal_description')} {t('SAML_Metadata_url')} @@ -115,19 +115,15 @@ const SamlMetadataModal = ({ onClose, onFetch, onApply, showIdentifierFormat = f /> - {error && ( - - {t(error as Parameters[0])} - - )} + {error && {t(error as Parameters[0])}} {warnings.map((warning) => ( - + {t(warning as Parameters[0])} ))} {values && ( <> - + {t('SAML_Custom_Entry_point')} - + {t('SAML_Custom_IDP_SLO_Redirect_URL')} - + {t('SAML_Custom_Cert')} {showIdentifierFormat && ( - + {t('SAML_Identifier_Format')} )} - + ); }; diff --git a/apps/meteor/client/views/admin/statusAndPresence/UserPresenceEditorForm.tsx b/apps/meteor/client/views/admin/statusAndPresence/UserPresenceEditorForm.tsx index 3e920a030f149..d8967b11bd473 100644 --- a/apps/meteor/client/views/admin/statusAndPresence/UserPresenceEditorForm.tsx +++ b/apps/meteor/client/views/admin/statusAndPresence/UserPresenceEditorForm.tsx @@ -255,7 +255,6 @@ const UserPresenceEditorForm = ({ user, defaultUsername, onClose }: UserPresence } secondary - flexGrow={0} title={t('Remove_user_status_settings')} onClick={handleResetClick} /> diff --git a/apps/meteor/client/views/admin/subscription/SubscriptionCalloutLimits.tsx b/apps/meteor/client/views/admin/subscription/SubscriptionCalloutLimits.tsx index b9bf64c29451e..de4eb4ac08f44 100644 --- a/apps/meteor/client/views/admin/subscription/SubscriptionCalloutLimits.tsx +++ b/apps/meteor/client/views/admin/subscription/SubscriptionCalloutLimits.tsx @@ -1,5 +1,5 @@ import type { LicenseInfo } from '@rocket.chat/core-typings'; -import { Callout } from '@rocket.chat/fuselage'; +import { Box, Callout } from '@rocket.chat/fuselage'; import { ExternalLink } from '@rocket.chat/ui-client'; import { Trans, useTranslation } from 'react-i18next'; @@ -19,12 +19,16 @@ export const SubscriptionCalloutLimits = () => { const { prevent_action, disable_modules, invalidate_license, start_fair_policy } = licenseLimits; + if (!start_fair_policy && !prevent_action && !disable_modules && !invalidate_license) { + return null; + } + const toTranslationKey = (key: keyof LicenseInfo['limits']) => t(`subscription.callout.${key}`); return ( - <> + {start_fair_policy && ( - + { )} {prevent_action && ( - + { )} {disable_modules && ( - + { )} {invalidate_license && ( - + { )} - + ); }; diff --git a/apps/meteor/client/views/admin/subscription/SubscriptionPage.tsx b/apps/meteor/client/views/admin/subscription/SubscriptionPage.tsx index 7b277f672f41c..b09f16240f9a4 100644 --- a/apps/meteor/client/views/admin/subscription/SubscriptionPage.tsx +++ b/apps/meteor/client/views/admin/subscription/SubscriptionPage.tsx @@ -1,4 +1,4 @@ -import { Accordion, AccordionItem, Box, Button, ButtonGroup, Callout, Grid, GridItem } from '@rocket.chat/fuselage'; +import { Accordion, AccordionItem, Box, Button, ButtonGroup, Callout, CardGrid, CardGridItem } from '@rocket.chat/fuselage'; import { useDebouncedValue, useSessionStorage } from '@rocket.chat/fuselage-hooks'; import { Page, @@ -124,9 +124,11 @@ const SubscriptionPage = () => { )} {(showSubscriptionCallout || syncLicenseUpdate.isPending) && ( - - {t('Sync_license_update_Callout')} - + + + {t('Sync_license_update_Callout')} + + )} {isLicenseLoading && } @@ -140,52 +142,54 @@ const SubscriptionPage = () => {
)} - - - - - - - - - - {seatsLimit.value !== undefined && ( - - {seatsLimit.max !== Infinity ? ( - - ) : ( - - )} - - )} - - {macLimit.value !== undefined && ( - - {macLimit.max !== Infinity ? ( - - ) : ( - - )} - - )} - - {!license && ( - <> - {limits?.marketplaceApps !== undefined && ( - - - - )} - - + + + + + + + + + + + {seatsLimit.value !== undefined && ( + + {seatsLimit.max !== Infinity ? ( + + ) : ( + + )} + + )} + + {macLimit.value !== undefined && ( + + {macLimit.max !== Infinity ? ( + + ) : ( + + )} + + )} + + {!license && limits?.marketplaceApps !== undefined && ( + + + + )} + + {!license && ( + - - + + )} + {!license && ( + - - - )} - + + )} + + {Boolean(licensesData?.license?.information.cancellable) && ( - + + + + + ); diff --git a/apps/meteor/client/views/admin/users/AdminUserCreated.tsx b/apps/meteor/client/views/admin/users/AdminUserCreated.tsx index a3a783b16186b..8c96b7270e0e4 100644 --- a/apps/meteor/client/views/admin/users/AdminUserCreated.tsx +++ b/apps/meteor/client/views/admin/users/AdminUserCreated.tsx @@ -13,11 +13,11 @@ const AdminUserCreated = ({ uid }: AdminUserCreatedProps) => { <> - - - diff --git a/apps/meteor/client/views/admin/users/AdminUserForm.tsx b/apps/meteor/client/views/admin/users/AdminUserForm.tsx index 1d38c126afa77..61ce636743eb6 100644 --- a/apps/meteor/client/views/admin/users/AdminUserForm.tsx +++ b/apps/meteor/client/views/admin/users/AdminUserForm.tsx @@ -15,8 +15,10 @@ import { Icon, FieldGroup, Button, + ButtonGroup, Callout, Skeleton, + Stack, } from '@rocket.chat/fuselage'; import type { SelectOption } from '@rocket.chat/fuselage'; import { useStableCallback } from '@rocket.chat/fuselage-hooks'; @@ -271,7 +273,6 @@ const AdminUserForm = ({ userData, onReload, context, refetchUserFormData, roleD aria-invalid={errors.email ? 'true' : 'false'} aria-describedby={`${emailId}-error`} error={errors.email?.message} - flexGrow={1} /> )} /> @@ -285,19 +286,13 @@ const AdminUserForm = ({ userData, onReload, context, refetchUserFormData, roleD ) : ( <> - - - + + + {t('Mark_email_as_verified')} - - + + )} /> @@ -375,7 +369,6 @@ const AdminUserForm = ({ userData, onReload, context, refetchUserFormData, roleD aria-invalid={errors.username ? 'true' : 'false'} aria-describedby={`${usernameId}-error`} error={errors.username?.message} - flexGrow={1} /> )} /> @@ -390,11 +383,7 @@ const AdminUserForm = ({ userData, onReload, context, refetchUserFormData, roleD {t('Voice_call_extension')} - } - /> + } /> )} @@ -403,9 +392,7 @@ const AdminUserForm = ({ userData, onReload, context, refetchUserFormData, roleD ) : ( <> - - {t('Password')} - + {t('Password')} @@ -493,7 +479,7 @@ const AdminUserForm = ({ userData, onReload, context, refetchUserFormData, roleD
{!isSmtpEnabled && ( - + )} /> @@ -554,8 +539,7 @@ const AdminUserForm = ({ userData, onReload, context, refetchUserFormData, roleD error={errors?.bio?.message} aria-invalid={errors.bio ? 'true' : 'false'} aria-describedby={`${bioId}-error`} - flexGrow={1} - endAddon={} + endAddon={} /> )} /> @@ -569,22 +553,16 @@ const AdminUserForm = ({ userData, onReload, context, refetchUserFormData, roleD {t('Nickname')} - } /> + } /> {!!customFieldsMetadata.length && ( <> - + + + {showCustomFields && } )} @@ -619,9 +597,7 @@ const AdminUserForm = ({ userData, onReload, context, refetchUserFormData, roleD />
- - {t('User_status_admin_hint')} - + {t('User_status_admin_hint')} @@ -645,7 +621,6 @@ const AdminUserForm = ({ userData, onReload, context, refetchUserFormData, roleD error={errors?.statusText?.message} aria-invalid={errors.statusText ? 'true' : 'false'} aria-describedby={`${statusTextId}-error ${statusTextId}-hint`} - flexGrow={1} /> )} /> @@ -688,9 +663,11 @@ const AdminUserForm = ({ userData, onReload, context, refetchUserFormData, roleD )} - + + + ); diff --git a/apps/meteor/client/views/admin/users/AdminUserFormWithData.tsx b/apps/meteor/client/views/admin/users/AdminUserFormWithData.tsx index 74e8aa9aa1d56..7662b211fbf44 100644 --- a/apps/meteor/client/views/admin/users/AdminUserFormWithData.tsx +++ b/apps/meteor/client/views/admin/users/AdminUserFormWithData.tsx @@ -34,17 +34,17 @@ const AdminUserFormWithData = ({ uid, onReload, context, roleData, roleError }: if (isError) { return ( - - {t('User_not_found')} - + + {t('User_not_found')} + ); } if (data?.user && !!data.user.federated) { return ( - - {t('Edit_Federated_User_Not_Allowed')} - + + {t('Edit_Federated_User_Not_Allowed')} + ); } diff --git a/apps/meteor/client/views/admin/users/AdminUserSetRandomPasswordContent.tsx b/apps/meteor/client/views/admin/users/AdminUserSetRandomPasswordContent.tsx index 38e3745018f69..bcc6219e10f8c 100644 --- a/apps/meteor/client/views/admin/users/AdminUserSetRandomPasswordContent.tsx +++ b/apps/meteor/client/views/admin/users/AdminUserSetRandomPasswordContent.tsx @@ -74,7 +74,6 @@ const AdminUserSetRandomPasswordContent = ({ aria-invalid={errors.password ? 'true' : 'false'} aria-describedby={`${passwordId}-error`} error={errors.password?.message} - flexGrow={1} placeholder={passwordPlaceholder || t('Password')} /> )} @@ -102,7 +101,6 @@ const AdminUserSetRandomPasswordContent = ({ aria-invalid={errors.passwordConfirmation ? 'true' : 'false'} aria-describedby={`${passwordConfirmationId}-error`} error={errors.passwordConfirmation?.message} - flexGrow={1} placeholder={passwordConfirmationPlaceholder || t('Confirm_password')} /> )} diff --git a/apps/meteor/client/views/admin/users/AdminUserSetRandomPasswordRadios.tsx b/apps/meteor/client/views/admin/users/AdminUserSetRandomPasswordRadios.tsx index 55f9249fb5b61..6207869c692ea 100644 --- a/apps/meteor/client/views/admin/users/AdminUserSetRandomPasswordRadios.tsx +++ b/apps/meteor/client/views/admin/users/AdminUserSetRandomPasswordRadios.tsx @@ -32,9 +32,9 @@ const AdminUserSetRandomPasswordRadios = ({ }; return ( - <> - - + + + - - {t('Set_randomly_and_send_by_email')} - + + + {t('Set_randomly_and_send_by_email')} + + {!isSmtpEnabled && ( - - , - }} - /> - + + + , + }} + /> + + )} - - + + - - {t('Set_manually')} - + + {t('Set_manually')} + - + ); }; diff --git a/apps/meteor/client/views/admin/users/AdminUsersPage.tsx b/apps/meteor/client/views/admin/users/AdminUsersPage.tsx index 4147c84007cee..f8ab967ac6bcc 100644 --- a/apps/meteor/client/views/admin/users/AdminUsersPage.tsx +++ b/apps/meteor/client/views/admin/users/AdminUsersPage.tsx @@ -1,5 +1,5 @@ import type { LicenseInfo } from '@rocket.chat/core-typings'; -import { Callout, Skeleton, Tabs, TabsItem } from '@rocket.chat/fuselage'; +import { Box, Callout, Skeleton, Tabs, TabsItem } from '@rocket.chat/fuselage'; import { useDebouncedValue, useStableCallback } from '@rocket.chat/fuselage-hooks'; import type { UsersListStatusParamsGET } from '@rocket.chat/rest-typings'; import type { OptionProp } from '@rocket.chat/ui-client'; @@ -125,34 +125,38 @@ const AdminUsersPage = () => { {preventAction?.includes('activeUsers') && ( - - - Your workspace exceeded the <>{preventAction.map(toTranslationKey)} license limit. - + + - Manage your subscription - - to increase limits. - - + Your workspace exceeded the <>{preventAction.map(toTranslationKey)} license limit. + + Manage your subscription + + to increase limits. + + + )} handleTabChange('all')}> {t('All')} - handleTabChange('pending')} display='flex' flexDirection='row'> - {`${t('Pending')} `} - {pendingUsersCount.isLoading && } - {pendingUsersCount.isSuccess && `(${pendingUsersCount.data})`} + handleTabChange('pending')}> + + {`${t('Pending')} `} + {pendingUsersCount.isLoading && } + {pendingUsersCount.isSuccess && `(${pendingUsersCount.data})`} + handleTabChange('active')}> {t('Active')} diff --git a/apps/meteor/client/views/admin/users/UsersTable/UsersTableFilters.tsx b/apps/meteor/client/views/admin/users/UsersTable/UsersTableFilters.tsx index 7153d06511134..22289d1690d7f 100644 --- a/apps/meteor/client/views/admin/users/UsersTable/UsersTableFilters.tsx +++ b/apps/meteor/client/views/admin/users/UsersTable/UsersTableFilters.tsx @@ -1,5 +1,5 @@ import type { IRole, Serialized } from '@rocket.chat/core-typings'; -import { Box, Icon, Margins, Select, TextInput } from '@rocket.chat/fuselage'; +import { Box, Icon, Select, TextInput } from '@rocket.chat/fuselage'; import { useBreakpoints } from '@rocket.chat/fuselage-hooks'; import type { OptionProp } from '@rocket.chat/ui-client'; import { MultiSelectCustom } from '@rocket.chat/ui-client'; @@ -90,18 +90,17 @@ const UsersTableFilters = ({ roleData, setUsersFilters, showStatusManagementFilt display='flex' flexWrap='wrap' alignItems='center' + columnGap={isLargeScreenOrBigger ? 16 : undefined} > - + } onChange={handleSearchTextChange} value={text} - flexGrow={2} - minWidth='x220' aria-label={t('Search_Users')} /> - + {showStatusManagementFilter && ( - +
+
{children}
- +
); export default memo(DescriptionList); diff --git a/apps/meteor/client/views/admin/workspace/DeploymentCard/components/InstancesModal/DescriptionListEntry.tsx b/apps/meteor/client/views/admin/workspace/DeploymentCard/components/InstancesModal/DescriptionListEntry.tsx index a1bb64d606fe7..9f4eb283435ab 100644 --- a/apps/meteor/client/views/admin/workspace/DeploymentCard/components/InstancesModal/DescriptionListEntry.tsx +++ b/apps/meteor/client/views/admin/workspace/DeploymentCard/components/InstancesModal/DescriptionListEntry.tsx @@ -1,4 +1,4 @@ -import { TableRow, TableCell } from '@rocket.chat/fuselage'; +import { Box, TableRow, TableCell } from '@rocket.chat/fuselage'; import type { ReactNode } from 'react'; import { memo } from 'react'; @@ -9,11 +9,11 @@ export type DescriptionListEntryProps = { const DescriptionListEntry = ({ children, label }: DescriptionListEntryProps) => ( - + {label} - - {children} + + {children} ); diff --git a/apps/meteor/client/views/admin/workspace/MessagesRoomsCard/MessagesRoomsCard.tsx b/apps/meteor/client/views/admin/workspace/MessagesRoomsCard/MessagesRoomsCard.tsx index 829f8d69f9aaf..a744307583317 100644 --- a/apps/meteor/client/views/admin/workspace/MessagesRoomsCard/MessagesRoomsCard.tsx +++ b/apps/meteor/client/views/admin/workspace/MessagesRoomsCard/MessagesRoomsCard.tsx @@ -15,7 +15,7 @@ const MessagesRoomsCard = ({ statistics }: MessagesRoomsCardProps) => { const { t } = useTranslation(); return ( - + diff --git a/apps/meteor/client/views/admin/workspace/UsersUploadsCard/UsersUploadsCard.tsx b/apps/meteor/client/views/admin/workspace/UsersUploadsCard/UsersUploadsCard.tsx index 064bdf718767c..bb1ec32bbcd68 100644 --- a/apps/meteor/client/views/admin/workspace/UsersUploadsCard/UsersUploadsCard.tsx +++ b/apps/meteor/client/views/admin/workspace/UsersUploadsCard/UsersUploadsCard.tsx @@ -28,7 +28,7 @@ const UsersUploadsCard = ({ statistics }: UsersUploadsCardProps) => { const { data: canViewEngagement = false } = useHasLicenseModule('engagement-dashboard'); return ( - + diff --git a/apps/meteor/client/views/admin/workspace/VersionCard/components/VersionCardSkeleton.tsx b/apps/meteor/client/views/admin/workspace/VersionCard/components/VersionCardSkeleton.tsx index e2899ac98da7f..712fa8c4e5326 100644 --- a/apps/meteor/client/views/admin/workspace/VersionCard/components/VersionCardSkeleton.tsx +++ b/apps/meteor/client/views/admin/workspace/VersionCard/components/VersionCardSkeleton.tsx @@ -5,16 +5,16 @@ export const VersionCardSkeleton = () => { <> - - + + - - + + - - + + diff --git a/apps/meteor/client/views/admin/workspace/VersionCard/modals/RegisterWorkspaceSetupModal/RegisterWorkspaceSetupStepOneModal.tsx b/apps/meteor/client/views/admin/workspace/VersionCard/modals/RegisterWorkspaceSetupModal/RegisterWorkspaceSetupStepOneModal.tsx index 04df61a99dc54..69510c99700bb 100644 --- a/apps/meteor/client/views/admin/workspace/VersionCard/modals/RegisterWorkspaceSetupModal/RegisterWorkspaceSetupStepOneModal.tsx +++ b/apps/meteor/client/views/admin/workspace/VersionCard/modals/RegisterWorkspaceSetupModal/RegisterWorkspaceSetupStepOneModal.tsx @@ -15,6 +15,7 @@ import { ModalClose, ModalContent, ModalFooter, + Stack, } from '@rocket.chat/fuselage'; import { ExternalLink } from '@rocket.chat/ui-client'; import { useEndpoint, useSetModal, useToastMessageDispatch } from '@rocket.chat/ui-contexts'; @@ -83,20 +84,22 @@ const RegisterWorkspaceSetupStepOneModal = ({ - - {t('RegisterWorkspace_Setup_Subtitle')} - - - {t('RegisterWorkspace_Setup_Label')} - - { - setEmail((e.target as HTMLInputElement).value); - }} - /> - - + + + {t('RegisterWorkspace_Setup_Subtitle')} + + + {t('RegisterWorkspace_Setup_Label')} + + { + setEmail((e.target as HTMLInputElement).value); + }} + /> + + + {t('RegisterWorkspace_Setup_Have_Account_Title')} @@ -108,14 +111,18 @@ const RegisterWorkspaceSetupStepOneModal = ({ {t('RegisterWorkspace_Setup_No_Account_Subtitle')} - - - - I agree with Terms and Conditions and{' '} - Privacy Policy - - - setTerms(!terms)} /> + + + + + + I agree with Terms and Conditions and{' '} + Privacy Policy + + + + setTerms(!terms)} /> + diff --git a/apps/meteor/client/views/admin/workspace/VersionCard/modals/RegisterWorkspaceSetupModal/RegisterWorkspaceSetupStepTwoModal.tsx b/apps/meteor/client/views/admin/workspace/VersionCard/modals/RegisterWorkspaceSetupModal/RegisterWorkspaceSetupStepTwoModal.tsx index e3ec09ed2645e..02c44a6658f91 100644 --- a/apps/meteor/client/views/admin/workspace/VersionCard/modals/RegisterWorkspaceSetupModal/RegisterWorkspaceSetupStepTwoModal.tsx +++ b/apps/meteor/client/views/admin/workspace/VersionCard/modals/RegisterWorkspaceSetupModal/RegisterWorkspaceSetupStepTwoModal.tsx @@ -12,6 +12,7 @@ import { ModalClose, ModalContent, ModalFooter, + Stack, } from '@rocket.chat/fuselage'; import { useEndpoint, useToastMessageDispatch } from '@rocket.chat/ui-contexts'; import { useCallback, useEffect } from 'react'; @@ -93,13 +94,15 @@ const RegisterWorkspaceSetupStepTwoModal = ({ email, step, setStep, onClose, int - {t('RegisterWorkspace_Setup_Email_Verification')} - - {t('Security_code')} - - - - + + {t('RegisterWorkspace_Setup_Email_Verification')} + + {t('Security_code')} + + + + + diff --git a/apps/meteor/client/views/admin/workspace/VersionCard/modals/RegisterWorkspaceTokenModal.tsx b/apps/meteor/client/views/admin/workspace/VersionCard/modals/RegisterWorkspaceTokenModal.tsx index 6f2ca10aeb577..b88f69798733b 100644 --- a/apps/meteor/client/views/admin/workspace/VersionCard/modals/RegisterWorkspaceTokenModal.tsx +++ b/apps/meteor/client/views/admin/workspace/VersionCard/modals/RegisterWorkspaceTokenModal.tsx @@ -14,6 +14,7 @@ import { ModalClose, ModalContent, ModalFooter, + Stack, } from '@rocket.chat/fuselage'; import { useEndpoint, useSetModal, useToastMessageDispatch } from '@rocket.chat/ui-contexts'; import type { ChangeEvent } from 'react'; @@ -89,14 +90,16 @@ const RegisterWorkspaceTokenModal = ({ onClose, onStatusChange, ...props }: Regi . - {`2. ${t('RegisterWorkspace_Token_Step_Two')}`} - - {t('Registration_Token')} - - - - {error && {t('Token_Not_Recognized')}} - + + {`2. ${t('RegisterWorkspace_Token_Step_Two')}`} + + {t('Registration_Token')} + + + + {error && {t('Token_Not_Recognized')}} + + diff --git a/apps/meteor/client/views/admin/workspace/WorkspacePage.tsx b/apps/meteor/client/views/admin/workspace/WorkspacePage.tsx index 3f5183988ba02..6321e994f099b 100644 --- a/apps/meteor/client/views/admin/workspace/WorkspacePage.tsx +++ b/apps/meteor/client/views/admin/workspace/WorkspacePage.tsx @@ -50,11 +50,9 @@ const WorkspacePage = ({ - - {warningMultipleInstances && ( - - )} - + + {warningMultipleInstances && } + diff --git a/apps/meteor/client/views/admin/workspace/components/WorkspaceCardTextSeparator.tsx b/apps/meteor/client/views/admin/workspace/components/WorkspaceCardTextSeparator.tsx index b2b998f491b39..54cbba9ffe7e4 100644 --- a/apps/meteor/client/views/admin/workspace/components/WorkspaceCardTextSeparator.tsx +++ b/apps/meteor/client/views/admin/workspace/components/WorkspaceCardTextSeparator.tsx @@ -12,15 +12,15 @@ export type WorkspaceCardTextSeparatorProps = { const WorkspaceCardTextSeparator = ({ icon, label, value, status }: WorkspaceCardTextSeparatorProps) => ( - {icon && } + + {icon && } {status && ( )} {label && label} - + } value={value} /> diff --git a/apps/meteor/client/views/audit/AuditPage.tsx b/apps/meteor/client/views/audit/AuditPage.tsx index c58fff59e7dc9..82ad5ef005f2a 100644 --- a/apps/meteor/client/views/audit/AuditPage.tsx +++ b/apps/meteor/client/views/audit/AuditPage.tsx @@ -1,5 +1,5 @@ import type { IRoom } from '@rocket.chat/core-typings'; -import { Box, Callout, Margins, States, StatesIcon, StatesSubtitle, StatesTitle, Tabs, TabsItem } from '@rocket.chat/fuselage'; +import { Box, Callout, States, StatesIcon, StatesSubtitle, StatesTitle, Tabs, TabsItem } from '@rocket.chat/fuselage'; import { Page, PageHeader, PageScrollableContentWithShadow } from '@rocket.chat/ui-client'; import { useState } from 'react'; import { useTranslation } from 'react-i18next'; @@ -34,25 +34,25 @@ const AuditPage = () => { {t('Omnichannel')} - - - - {selectedRoom?.encrypted && type === '' ? ( - + + + {selectedRoom?.encrypted && type === '' ? ( + + {t('Encrypted_content_cannot_be_searched_and_audited')} {t('Encrypted_content_cannot_be_searched_and_audited_subtitle')} - ) : null} - {auditMutation.isPending && } - {auditMutation.isError && ( - - - {t('Error')} - {getErrorMessage(auditMutation.error)} - - )} - {auditMutation.isSuccess && } - + + ) : null} + {auditMutation.isPending && } + {auditMutation.isError && ( + + + {t('Error')} + {getErrorMessage(auditMutation.error)} + + )} + {auditMutation.isSuccess && } ); diff --git a/apps/meteor/client/views/audit/components/AuditForm.tsx b/apps/meteor/client/views/audit/components/AuditForm.tsx index 801f29d8f1277..793602fe14afe 100644 --- a/apps/meteor/client/views/audit/components/AuditForm.tsx +++ b/apps/meteor/client/views/audit/components/AuditForm.tsx @@ -1,5 +1,5 @@ import type { IAuditLog, IRoom } from '@rocket.chat/core-typings'; -import { Box, Field, FieldLabel, FieldRow, FieldError, TextInput, Button, ButtonGroup } from '@rocket.chat/fuselage'; +import { Box, Field, FieldLabel, FieldRow, FieldError, TextInput, Button, ButtonGroup, Stack } from '@rocket.chat/fuselage'; import type { Dispatch, SetStateAction } from 'react'; import { useController } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; @@ -38,29 +38,33 @@ const AuditForm = ({ type, onSubmit, setSelectedRoom }: AuditFormProps) => { }; return ( -
- - - {t('Message')} - - - - - - {t('Date')} - - - {dateRangeFieldState.error?.type === 'required' && {t('Required_field', { field: t('Date') })}} - {dateRangeFieldState.error?.type === 'validate' && {dateRangeFieldState.error.message}} - - - - + + + + + {t('Message')} + + + + + + + + {t('Date')} + + + {dateRangeFieldState.error?.type === 'required' && {t('Required_field', { field: t('Date') })}} + {dateRangeFieldState.error?.type === 'validate' && {dateRangeFieldState.error.message}} + + + + + {type === '' && } {type === 'u' && } {type === 'd' && } {type === 'l' && } - + - - + + ); }; diff --git a/apps/meteor/client/views/audit/components/AuditLogTable.tsx b/apps/meteor/client/views/audit/components/AuditLogTable.tsx index 6569cbe300d23..1d7db9d3f4d07 100644 --- a/apps/meteor/client/views/audit/components/AuditLogTable.tsx +++ b/apps/meteor/client/views/audit/components/AuditLogTable.tsx @@ -66,10 +66,10 @@ const AuditLogTable = () => { return ( <> - + {t('Date')} - + {isLoading && ( diff --git a/apps/meteor/client/views/audit/components/SecurityLogsTable.tsx b/apps/meteor/client/views/audit/components/SecurityLogsTable.tsx index 3d77f805fa98a..f69e25eba6d9c 100644 --- a/apps/meteor/client/views/audit/components/SecurityLogsTable.tsx +++ b/apps/meteor/client/views/audit/components/SecurityLogsTable.tsx @@ -1,5 +1,5 @@ import type { IAuditServerAppActor, IAuditServerSystemActor, IAuditServerUserActor } from '@rocket.chat/core-typings'; -import { Box, Button, ButtonGroup, Field, FieldLabel, Margins, Pagination } from '@rocket.chat/fuselage'; +import { Box, Button, Field, FieldLabel, Pagination } from '@rocket.chat/fuselage'; import { UserAvatar } from '@rocket.chat/ui-avatar'; import { GenericTable, @@ -102,28 +102,30 @@ const SecurityLogsTable = () => { return ( <> - - - {t('Date')} - - - - - - {t('Setting')} - - - - - - - - - + + + + {t('Date')} + + + + + + + + {t('Setting')} + + + + + + + + {isLoading && ( diff --git a/apps/meteor/client/views/audit/components/SettingSelect.tsx b/apps/meteor/client/views/audit/components/SettingSelect.tsx index 2baa9c4958d75..c9d66dc6d6f07 100644 --- a/apps/meteor/client/views/audit/components/SettingSelect.tsx +++ b/apps/meteor/client/views/audit/components/SettingSelect.tsx @@ -16,7 +16,6 @@ export const SettingSelect = ({ value, onChange }: { value: string; onChange: (v return ( onChange(val)} placeholder={t('All_Settings')} diff --git a/apps/meteor/client/views/audit/components/forms/DateRangePicker.tsx b/apps/meteor/client/views/audit/components/forms/DateRangePicker.tsx index 3c80b434cc118..b7cafb261e37c 100644 --- a/apps/meteor/client/views/audit/components/forms/DateRangePicker.tsx +++ b/apps/meteor/client/views/audit/components/forms/DateRangePicker.tsx @@ -1,4 +1,4 @@ -import { Box, InputBox, Margins } from '@rocket.chat/fuselage'; +import { Box, InputBox } from '@rocket.chat/fuselage'; import { useStableCallback } from '@rocket.chat/fuselage-hooks'; import { GenericMenu } from '@rocket.chat/ui-client'; import { endOfDay } from 'date-fns/endOfDay'; @@ -200,12 +200,10 @@ const DateRangePicker = ({ value, onChange, ...props }: DateRangePickerProps) => ); return ( - - - - - - + + + + ); }; diff --git a/apps/meteor/client/views/audit/components/tabs/DirectTab.tsx b/apps/meteor/client/views/audit/components/tabs/DirectTab.tsx index 68a3b354eb927..f2c6c68f1d2a0 100644 --- a/apps/meteor/client/views/audit/components/tabs/DirectTab.tsx +++ b/apps/meteor/client/views/audit/components/tabs/DirectTab.tsx @@ -1,4 +1,4 @@ -import { Field, FieldLabel, FieldRow, FieldError } from '@rocket.chat/fuselage'; +import { Box, Field, FieldLabel, FieldRow, FieldError } from '@rocket.chat/fuselage'; import type { UseFormReturn } from 'react-hook-form'; import { useController } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; @@ -27,19 +27,21 @@ const DirectTab = ({ form: { control } }: DirectTabProps) => { }); return ( - - {t('Users')} - - - - {usersFieldState.error?.type === 'required' && {t('Required_field', { field: t('Users') })}} - {usersFieldState.error?.type === 'validate' && {usersFieldState.error.message}} - + + + {t('Users')} + + + + {usersFieldState.error?.type === 'required' && {t('Required_field', { field: t('Users') })}} + {usersFieldState.error?.type === 'validate' && {usersFieldState.error.message}} + + ); }; diff --git a/apps/meteor/client/views/audit/components/tabs/OmnichannelTab.tsx b/apps/meteor/client/views/audit/components/tabs/OmnichannelTab.tsx index 6c73fcd8e6ad3..35ec689fac4da 100644 --- a/apps/meteor/client/views/audit/components/tabs/OmnichannelTab.tsx +++ b/apps/meteor/client/views/audit/components/tabs/OmnichannelTab.tsx @@ -1,4 +1,4 @@ -import { Field, FieldLabel, FieldRow, FieldError } from '@rocket.chat/fuselage'; +import { Box, Field, FieldLabel, FieldRow, FieldError } from '@rocket.chat/fuselage'; import type { UseFormReturn } from 'react-hook-form'; import { useController } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; @@ -27,38 +27,42 @@ const OmnichannelTab = ({ form: { control } }: OmnichannelTabProps) => { return ( <> - - {t('Visitor')} - - - - {visitorFieldState.error?.type === 'required' && {t('Required_field', { field: t('Visitor') })}} - {visitorFieldState.error?.type === 'validate' && {visitorFieldState.error.message}} - - - {t('Agent')} - - { - if (agentFieldState.error?.type === 'required') { - return t('Required_field', { field: t('Agent') }); - } + + + {t('Visitor')} + + + + {visitorFieldState.error?.type === 'required' && {t('Required_field', { field: t('Visitor') })}} + {visitorFieldState.error?.type === 'validate' && {visitorFieldState.error.message}} + + + + + {t('Agent')} + + { + if (agentFieldState.error?.type === 'required') { + return t('Required_field', { field: t('Agent') }); + } - return agentFieldState.error?.message; - })()} - value={agentField.value} - onChange={agentField.onChange} - placeholder={t('Username_Placeholder')} - /> - - {agentFieldState.error?.type === 'required' && {t('Required_field', { field: t('Agent') })}} - {agentFieldState.error?.type === 'validate' && {agentFieldState.error.message}} - + return agentFieldState.error?.message; + })()} + value={agentField.value} + onChange={agentField.onChange} + placeholder={t('Username_Placeholder')} + /> + + {agentFieldState.error?.type === 'required' && {t('Required_field', { field: t('Agent') })}} + {agentFieldState.error?.type === 'validate' && {agentFieldState.error.message}} + + ); }; diff --git a/apps/meteor/client/views/audit/components/tabs/RoomsTab.tsx b/apps/meteor/client/views/audit/components/tabs/RoomsTab.tsx index d4b69b078d72a..f59c67635764b 100644 --- a/apps/meteor/client/views/audit/components/tabs/RoomsTab.tsx +++ b/apps/meteor/client/views/audit/components/tabs/RoomsTab.tsx @@ -1,5 +1,5 @@ import type { IRoom } from '@rocket.chat/core-typings'; -import { Field, FieldLabel, FieldRow, FieldError, Icon } from '@rocket.chat/fuselage'; +import { Box, Field, FieldLabel, FieldRow, FieldError, Icon } from '@rocket.chat/fuselage'; import type { Dispatch, SetStateAction } from 'react'; import type { UseFormReturn } from 'react-hook-form'; import { useController } from 'react-hook-form'; @@ -19,24 +19,26 @@ const RoomsTab = ({ form: { control }, setSelectedRoom }: RoomsTabProps) => { const { field: ridField, fieldState: ridFieldState } = useController({ name: 'rid', control, rules: { required: true } }); return ( - - {t('Channel_name')} - - - encrypted ? : null - } - /> - - {ridFieldState.error?.type === 'required' && {t('Required_field', { field: t('Channel_name') })}} - {ridFieldState.error?.type === 'validate' && {ridFieldState.error.message}} - + + + {t('Channel_name')} + + + encrypted ? : null + } + /> + + {ridFieldState.error?.type === 'required' && {t('Required_field', { field: t('Channel_name') })}} + {ridFieldState.error?.type === 'validate' && {ridFieldState.error.message}} + + ); }; diff --git a/apps/meteor/client/views/audit/components/tabs/UsersTab.tsx b/apps/meteor/client/views/audit/components/tabs/UsersTab.tsx index 8037f74e62cba..3f66d9244193e 100644 --- a/apps/meteor/client/views/audit/components/tabs/UsersTab.tsx +++ b/apps/meteor/client/views/audit/components/tabs/UsersTab.tsx @@ -1,4 +1,4 @@ -import { Field, FieldLabel, FieldRow, FieldError } from '@rocket.chat/fuselage'; +import { Box, Field, FieldLabel, FieldRow, FieldError } from '@rocket.chat/fuselage'; import type { UseFormReturn } from 'react-hook-form'; import { useController } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; @@ -27,19 +27,21 @@ const UsersTab = ({ form: { control } }: UsersTabProps) => { }); return ( - - {t('Users')} - - - - {usersFieldState.error?.type === 'required' && {t('Required_field', { field: t('Users') })}} - {usersFieldState.error?.type === 'validate' && {usersFieldState.error.message}} - + + + {t('Users')} + + + + {usersFieldState.error?.type === 'required' && {t('Required_field', { field: t('Users') })}} + {usersFieldState.error?.type === 'validate' && {usersFieldState.error.message}} + + ); }; diff --git a/apps/meteor/client/views/composer/AudioMessageRecorder/AudioMessageRecorder.tsx b/apps/meteor/client/views/composer/AudioMessageRecorder/AudioMessageRecorder.tsx index 283e1f8085f4a..b51bdfa1391fd 100644 --- a/apps/meteor/client/views/composer/AudioMessageRecorder/AudioMessageRecorder.tsx +++ b/apps/meteor/client/views/composer/AudioMessageRecorder/AudioMessageRecorder.tsx @@ -1,5 +1,5 @@ import type { IRoom } from '@rocket.chat/core-typings'; -import { Box, Icon, Throbber } from '@rocket.chat/fuselage'; +import { Box, Throbber, Icon } from '@rocket.chat/fuselage'; import { useStableCallback } from '@rocket.chat/fuselage-hooks'; import { MessageComposerAction } from '@rocket.chat/ui-composer'; import { useEffect, useState } from 'react'; @@ -117,7 +117,7 @@ const AudioMessageRecorder = ({ rid, isMicrophoneDenied }: AudioMessageRecorderP <> - + {time} diff --git a/apps/meteor/client/views/composer/EmojiPicker/EmojiElement.tsx b/apps/meteor/client/views/composer/EmojiPicker/EmojiElement.tsx index 2ad25cff61aad..34ff31adb681c 100644 --- a/apps/meteor/client/views/composer/EmojiPicker/EmojiElement.tsx +++ b/apps/meteor/client/views/composer/EmojiPicker/EmojiElement.tsx @@ -9,7 +9,7 @@ import type { EmojiItem } from '../../../lib/emoji'; export type EmojiElementProps = EmojiItem & { small?: boolean; onClick: (e: MouseEvent) => void } & Omit< AllHTMLAttributes, - 'is' + 'is' | 'color' >; const smallEmojiClass = css` diff --git a/apps/meteor/client/views/composer/EmojiPicker/EmojiPicker.tsx b/apps/meteor/client/views/composer/EmojiPicker/EmojiPicker.tsx index 88bb88a647dff..4f588cbe48701 100644 --- a/apps/meteor/client/views/composer/EmojiPicker/EmojiPicker.tsx +++ b/apps/meteor/client/views/composer/EmojiPicker/EmojiPicker.tsx @@ -1,4 +1,4 @@ -import { TextInput, Icon, Button, Divider } from '@rocket.chat/fuselage'; +import { Box, TextInput, Icon, Button, Divider } from '@rocket.chat/fuselage'; import { useMediaQuery, useOutsideClick } from '@rocket.chat/fuselage-hooks'; import { EmojiPickerCategoryHeader, @@ -215,7 +215,9 @@ const EmojiPicker = ({ reference, onClose, onPickEmoji }: EmojiPickerProps) => { /> ))} - + + + {searching && } {!searching && ( diff --git a/apps/meteor/client/views/composer/EmojiPicker/EmojiPickerCategoryItem.tsx b/apps/meteor/client/views/composer/EmojiPicker/EmojiPickerCategoryItem.tsx index 582d248f4867c..9b9f57f5fa76e 100644 --- a/apps/meteor/client/views/composer/EmojiPicker/EmojiPickerCategoryItem.tsx +++ b/apps/meteor/client/views/composer/EmojiPicker/EmojiPickerCategoryItem.tsx @@ -8,7 +8,7 @@ export type EmojiPickerCategoryItemProps = { category: EmojiCategory; active: boolean; handleGoToCategory: () => void; -} & Omit, 'is'>; +} & Omit, 'is' | 'color'>; const mapCategoryIcon = (category: string) => { switch (category) { diff --git a/apps/meteor/client/views/composer/EmojiPicker/EmojiPickerDesktopDropdown.tsx b/apps/meteor/client/views/composer/EmojiPicker/EmojiPickerDesktopDropdown.tsx index 640d985a3a71b..c984be31876ef 100644 --- a/apps/meteor/client/views/composer/EmojiPicker/EmojiPickerDesktopDropdown.tsx +++ b/apps/meteor/client/views/composer/EmojiPicker/EmojiPickerDesktopDropdown.tsx @@ -1,4 +1,4 @@ -import { Box, Tile } from '@rocket.chat/fuselage'; +import { Box, PopoverSurface } from '@rocket.chat/fuselage'; import { useMergedRefs, usePosition } from '@rocket.chat/fuselage-hooks'; import type { ReactNode, Ref, RefObject } from 'react'; import { useMemo, useRef, forwardRef } from 'react'; @@ -61,20 +61,9 @@ const EmojiPickerDesktopDropdown = forwardRef(function ToolboxDropdownDesktop( const style = useDropdownPosition(reference, targetRef); return ( - - - {children} - - + + {children} + ); }); diff --git a/apps/meteor/client/views/composer/EmojiPicker/ToneSelector/ToneSelector.tsx b/apps/meteor/client/views/composer/EmojiPicker/ToneSelector/ToneSelector.tsx index 529bc14543a11..da7a53f068311 100644 --- a/apps/meteor/client/views/composer/EmojiPicker/ToneSelector/ToneSelector.tsx +++ b/apps/meteor/client/views/composer/EmojiPicker/ToneSelector/ToneSelector.tsx @@ -58,7 +58,6 @@ const ToneSelector = ({ tone, setTone }: { tone: number; setTone: (tone: number) onBlur={hide} onKeyUp={handleKeyUp} onKeyDown={handleKeyDown} - marginInlineStart={4} icon={} /> diff --git a/apps/meteor/client/views/composer/EmojiPicker/ToneSelector/ToneSelectorWrapper.tsx b/apps/meteor/client/views/composer/EmojiPicker/ToneSelector/ToneSelectorWrapper.tsx index f534b155b4fd7..2d0d2898c895f 100644 --- a/apps/meteor/client/views/composer/EmojiPicker/ToneSelector/ToneSelectorWrapper.tsx +++ b/apps/meteor/client/views/composer/EmojiPicker/ToneSelector/ToneSelectorWrapper.tsx @@ -7,7 +7,7 @@ export type ToneSelectorWrapperProps = { const ToneSelectorWrapper = ({ caption, children, ...props }: ToneSelectorWrapperProps) => { return ( - + {caption} {children} diff --git a/apps/meteor/client/views/composer/VideoMessageRecorder/VideoMessageRecorder.tsx b/apps/meteor/client/views/composer/VideoMessageRecorder/VideoMessageRecorder.tsx index c22aff3864040..f397c15113f8d 100644 --- a/apps/meteor/client/views/composer/VideoMessageRecorder/VideoMessageRecorder.tsx +++ b/apps/meteor/client/views/composer/VideoMessageRecorder/VideoMessageRecorder.tsx @@ -121,8 +121,8 @@ const VideoMessageRecorder = ({ rid, tmid, reference }: VideoMessageRecorderProp diff --git a/apps/meteor/client/views/directory/DirectoryPage.tsx b/apps/meteor/client/views/directory/DirectoryPage.tsx index 8e5610401409d..12186d3217e9f 100644 --- a/apps/meteor/client/views/directory/DirectoryPage.tsx +++ b/apps/meteor/client/views/directory/DirectoryPage.tsx @@ -39,7 +39,7 @@ const DirectoryPage = () => { return ( - + {t('Channels')} diff --git a/apps/meteor/client/views/directory/RoomTags.tsx b/apps/meteor/client/views/directory/RoomTags.tsx index cf6504e66729a..bff7580de7577 100644 --- a/apps/meteor/client/views/directory/RoomTags.tsx +++ b/apps/meteor/client/views/directory/RoomTags.tsx @@ -1,5 +1,5 @@ import type { IRoom, Serialized } from '@rocket.chat/core-typings'; -import { Box, Margins, Tag } from '@rocket.chat/fuselage'; +import { Box, Tag } from '@rocket.chat/fuselage'; import { useTranslation } from 'react-i18next'; export type RoomTagsProps = { @@ -10,11 +10,16 @@ const RoomTags = ({ room }: RoomTagsProps) => { const { t } = useTranslation(); return ( - - - {room.default && {t('default')}} - {room.featured && {t('featured')}} - + + {room.default && {t('default')}} + {room.featured && {t('featured')}} ); }; diff --git a/apps/meteor/client/views/e2e/EnterE2EPasswordModal/EnterE2EPasswordModal.tsx b/apps/meteor/client/views/e2e/EnterE2EPasswordModal/EnterE2EPasswordModal.tsx index 6813afceb8310..6150df460caf4 100644 --- a/apps/meteor/client/views/e2e/EnterE2EPasswordModal/EnterE2EPasswordModal.tsx +++ b/apps/meteor/client/views/e2e/EnterE2EPasswordModal/EnterE2EPasswordModal.tsx @@ -1,4 +1,4 @@ -import { Box, PasswordInput, Field, FieldGroup, FieldRow, FieldError, FieldLink } from '@rocket.chat/fuselage'; +import { Box, PasswordInput, Field, FieldGroup, FieldRow, FieldError, FieldLink, Stack } from '@rocket.chat/fuselage'; import { GenericModal } from '@rocket.chat/ui-client'; import { useToastMessageDispatch } from '@rocket.chat/ui-contexts'; import { useEffect, useId, useState } from 'react'; @@ -79,45 +79,47 @@ const EnterE2EPasswordModal = ({ onConfirm, onClose, onCancel }: EnterE2EPasswor onClose={onClose} onCancel={onCancel} > - {t('E2E_password_request_text')} - - - - ( - - )} - /> - - {errors.password && ( - - {errors.password.message} - - )} - - { - e.preventDefault(); - setConfirmResetPassword(true); - }} - > - {t('Forgot_E2EE_Password')} - - - - + + {t('E2E_password_request_text')} + + + + ( + + )} + /> + + {errors.password && ( + + {errors.password.message} + + )} + + { + e.preventDefault(); + setConfirmResetPassword(true); + }} + > + {t('Forgot_E2EE_Password')} + + + + + ); }; diff --git a/apps/meteor/client/views/e2e/SaveE2EPasswordModal.tsx b/apps/meteor/client/views/e2e/SaveE2EPasswordModal.tsx index 6b6c2c0ce6017..c71a64186d484 100644 --- a/apps/meteor/client/views/e2e/SaveE2EPasswordModal.tsx +++ b/apps/meteor/client/views/e2e/SaveE2EPasswordModal.tsx @@ -1,4 +1,4 @@ -import { Box, CodeSnippet } from '@rocket.chat/fuselage'; +import { Box, CodeSnippet, Stack } from '@rocket.chat/fuselage'; import { useClipboard } from '@rocket.chat/fuselage-hooks'; import { ExternalLink, GenericModal } from '@rocket.chat/ui-client'; import { useId } from 'react'; @@ -40,16 +40,17 @@ const SaveE2EPasswordModal = ({ randomPassword, onClose, onCancel, onConfirm }: {t('E2E_password_save_text')} -

{t('Your_E2EE_password_is')}

- copy()} - marginBlockStart={8} - > - {randomPassword} - + +

{t('Your_E2EE_password_is')}

+ copy()} + > + {randomPassword} + +
); }; diff --git a/apps/meteor/client/views/home/cards/CustomContentCard.tsx b/apps/meteor/client/views/home/cards/CustomContentCard.tsx index cdbb3e9b6eac4..a83f97d9d6386 100644 --- a/apps/meteor/client/views/home/cards/CustomContentCard.tsx +++ b/apps/meteor/client/views/home/cards/CustomContentCard.tsx @@ -53,8 +53,7 @@ const CustomContentCard = (props: Omit, 'type'>) => return ( - - + }> {willNotShowCustomContent ? t('Not_Visible_To_Workspace') : t('Visible_To_Workspace')} diff --git a/apps/meteor/client/views/marketplace/AppDetailsPage/AppDetailsPageLoading.tsx b/apps/meteor/client/views/marketplace/AppDetailsPage/AppDetailsPageLoading.tsx index 9bf81218f3eb0..4c0d9f910e08b 100644 --- a/apps/meteor/client/views/marketplace/AppDetailsPage/AppDetailsPageLoading.tsx +++ b/apps/meteor/client/views/marketplace/AppDetailsPage/AppDetailsPageLoading.tsx @@ -1,8 +1,8 @@ import { Box, Skeleton } from '@rocket.chat/fuselage'; const AppDetailsPageLoading = () => ( - - + + diff --git a/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppDetails/AppDetails.tsx b/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppDetails/AppDetails.tsx index 78b870a6482dc..fb9cd9a9f9c9d 100644 --- a/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppDetails/AppDetails.tsx +++ b/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppDetails/AppDetails.tsx @@ -44,36 +44,38 @@ const AppDetails = ({ app }: AppDetailsProps) => { const openExternalLink = useExternalLink(); + const showAddonCallout = !!appAddon && !workspaceHasAddon; + const licenseWarnings = Object.keys(app.licenseValidation?.warnings ?? {}); + const licenseErrors = Object.keys(app.licenseValidation?.errors ?? {}); + return ( - {appAddon && !workspaceHasAddon && ( - openExternalLink(GET_ADDONS_LINK)}> - {t('Contact_sales')} - - } - > - {t('App_cannot_be_enabled_without_add-on')} - - )} - {app.licenseValidation && ( - <> - {Object.entries(app.licenseValidation.warnings).map(([key]) => ( - + {(showAddonCallout || licenseWarnings.length > 0 || licenseErrors.length > 0) && ( + + {showAddonCallout && ( + openExternalLink(GET_ADDONS_LINK)}> + {t('Contact_sales')} + + } + > + {t('App_cannot_be_enabled_without_add-on')} + + )} + {licenseWarnings.map((key) => ( + {t(`Apps_License_Message_${key}`)} ))} - - {Object.entries(app.licenseValidation.errors).map(([key]) => ( - + {licenseErrors.map((key) => ( + {t(`Apps_License_Message_${key}`)} ))} - + )} @@ -98,9 +100,17 @@ const AppDetails = ({ app }: AppDetailsProps) => { {t('Categories')} - - {categories?.map((current) => ( - + 0 ? 4 : undefined} + > + {categories.map((current) => ( + {current} ))} diff --git a/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppInstances/AppInstances.tsx b/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppInstances/AppInstances.tsx index a71ebf49bf80c..76ec40445cdf4 100644 --- a/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppInstances/AppInstances.tsx +++ b/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppInstances/AppInstances.tsx @@ -1,6 +1,6 @@ import type { AppStatus } from '@rocket.chat/apps'; import { AppStatusUtils } from '@rocket.chat/apps-engine/definition/AppStatus'; -import { Box, Palette, Tag } from '@rocket.chat/fuselage'; +import { Box, Tag } from '@rocket.chat/fuselage'; import { GenericMenu, CustomScrollbars, @@ -26,13 +26,7 @@ const AppInstances = ({ id }: AppInstanceProps) => { const { t } = useTranslation(); const { data, isSuccess, isError, isLoading } = useAppInstances({ appId: id }); - const getStatusColor = (status: AppStatus) => { - if (AppStatusUtils.isDisabled(status) || AppStatusUtils.isError(status)) { - return Palette.text['font-danger'].toString(); - } - - return Palette.text['font-default'].toString(); - }; + const isFailing = (status: AppStatus) => AppStatusUtils.isDisabled(status) || AppStatusUtils.isError(status); const router = useRouter(); @@ -69,7 +63,7 @@ const AppInstances = ({ id }: AppInstanceProps) => { {instance.instanceId} - + {t(`App_status_${instance.status}`)} diff --git a/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/AppLogsItem.tsx b/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/AppLogsItem.tsx index 98fe2793fa4c1..9886b85ca0770 100644 --- a/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/AppLogsItem.tsx +++ b/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/AppLogsItem.tsx @@ -58,7 +58,7 @@ const AppLogsItem = ({ regionId, expanded, onExpand, ...props }: AppLogsItemProp - + ); diff --git a/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/Filters/AppLogsFilter.tsx b/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/Filters/AppLogsFilter.tsx index 190b329e5250f..118081ad66b3a 100644 --- a/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/Filters/AppLogsFilter.tsx +++ b/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/Filters/AppLogsFilter.tsx @@ -58,8 +58,8 @@ export const AppLogsFilter = ({ appId, expandAll, collapseAll, refetchLogs, isLo const compactMode = useCompactMode(); return ( - - + + @@ -71,14 +71,14 @@ export const AppLogsFilter = ({ appId, expandAll, collapseAll, refetchLogs, isLo {!compactMode && ( <> - + - + @@ -91,7 +91,7 @@ export const AppLogsFilter = ({ appId, expandAll, collapseAll, refetchLogs, isLo /> - + } /> @@ -101,7 +101,6 @@ export const AppLogsFilter = ({ appId, expandAll, collapseAll, refetchLogs, isLo disabled={isLoading} icon='refresh' secondary - marginInlineEnd={10} onClick={() => refreshLogs()} /> @@ -110,7 +109,6 @@ export const AppLogsFilter = ({ appId, expandAll, collapseAll, refetchLogs, isLo icon='circle-arrow-down' disabled={noResults} secondary - marginInlineEnd={10} onClick={() => openExportModal()} aria-label={noResults ? t('No_data_to_export') : t('Export')} aria-disabled={noResults} @@ -122,7 +120,7 @@ export const AppLogsFilter = ({ appId, expandAll, collapseAll, refetchLogs, isLo {compactMode && ( <> - undefined }: - + + + ); diff --git a/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppReleases/AppReleases.tsx b/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppReleases/AppReleases.tsx index e8108fb6ae63d..73ae3cb5a77f6 100644 --- a/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppReleases/AppReleases.tsx +++ b/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppReleases/AppReleases.tsx @@ -30,7 +30,7 @@ const AppReleases = ({ id }: AppReleasesProps) => { return ( <> - + {isLoading && } {isFetched && ( <> diff --git a/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppStatus/AppStatus.tsx b/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppStatus/AppStatus.tsx index ec5b1fa4fd872..8b1b640d38505 100644 --- a/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppStatus/AppStatus.tsx +++ b/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppStatus/AppStatus.tsx @@ -1,5 +1,5 @@ import type { App } from '@rocket.chat/core-typings'; -import { Box, Button, Tag, Margins, Icon } from '@rocket.chat/fuselage'; +import { Box, Button, Tag, Icon, Stack } from '@rocket.chat/fuselage'; import { useSafely } from '@rocket.chat/fuselage-hooks'; import { useRouteParameter, usePermission, useSetModal } from '@rocket.chat/ui-contexts'; import { useCallback, useState, memo } from 'react'; @@ -35,7 +35,7 @@ const AppStatus = ({ app, showStatus = true, isAppDetailsPage, installed, ...pro const button = appButtonProps({ ...app, isAdminUser, endUserRequested }); const isAppRequestsPage = context === 'requested'; - const shouldShowPriceDisplay = isAppDetailsPage && button && !app.isEnterpriseOnly; + const shouldShowPriceDisplay = isAppDetailsPage && button && !app.isEnterpriseOnly && !installed; const canUpdate = installed && app?.version && app?.marketplaceVersion && semver.lt(app?.version, app?.marketplaceVersion); const { data } = useIsEnterprise(); @@ -144,6 +144,8 @@ const AppStatus = ({ app, showStatus = true, isAppDetailsPage, installed, ...pro alignItems='center' justifyContent='center' borderRadius='medium' + gap={12} + paddingInlineEnd={shouldShowPriceDisplay ? 4 : undefined} invisible={!showStatus && !loading} > - {shouldShowPriceDisplay && !installed && ( + {shouldShowPriceDisplay && ( )} )} - {statuses?.map((status, index) => ( - - - - {status.icon && } + + {statuses?.map((status, index) => ( + + + {status.icon && } {handleAppRequestsNumber(status)} {t(status.label)} - - ))} + ))} + ); }; diff --git a/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppStatus/AppStatusPriceDisplay.tsx b/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppStatus/AppStatusPriceDisplay.tsx index 357da84770bc7..7e0b4b576bcc5 100644 --- a/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppStatus/AppStatusPriceDisplay.tsx +++ b/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppStatus/AppStatusPriceDisplay.tsx @@ -1,5 +1,5 @@ import type { AppPricingPlan, PurchaseType } from '@rocket.chat/core-typings'; -import { Box, Margins, Tag } from '@rocket.chat/fuselage'; +import { Box, Tag } from '@rocket.chat/fuselage'; import { useMemo } from 'react'; import { useTranslation } from 'react-i18next'; @@ -22,12 +22,10 @@ const AppStatusPriceDisplay = ({ purchaseType, pricingPlans, price, showType = t ); return ( - - - {showType && {i18n.exists(type) ? t(type) : type}} - {!showType && type === 'Free' ? t(type) : formattedPrice} - - + + {showType && {i18n.exists(type) ? t(type) : type}} + {!showType && type === 'Free' ? t(type) : formattedPrice} + ); }; diff --git a/apps/meteor/client/views/marketplace/AppInstallPage.tsx b/apps/meteor/client/views/marketplace/AppInstallPage.tsx index 1a50c472221a2..e0622942acfe1 100644 --- a/apps/meteor/client/views/marketplace/AppInstallPage.tsx +++ b/apps/meteor/client/views/marketplace/AppInstallPage.tsx @@ -1,4 +1,4 @@ -import { Button, ButtonGroup, Field, FieldGroup, FieldLabel, FieldRow, TextInput } from '@rocket.chat/fuselage'; +import { Box, Button, ButtonGroup, Field, FieldGroup, FieldLabel, FieldRow, TextInput } from '@rocket.chat/fuselage'; import { PageScrollableContent, Page, PageHeader } from '@rocket.chat/ui-client'; import { useTranslation, useRouter } from '@rocket.chat/ui-contexts'; import { useCallback, useId } from 'react'; @@ -33,38 +33,41 @@ const AppInstallPage = () => { - - - {t('App_Url_to_Install_From_File')} - - ( - - {t('Browse_Files')} - - } - /> - )} - /> - - - - - - - - - + + + + {t('App_Url_to_Install_From_File')} + + ( + + {t('Browse_Files')} + + } + /> + )} + /> + + + + + + + + + + ); diff --git a/apps/meteor/client/views/marketplace/AppUpdateModal.tsx b/apps/meteor/client/views/marketplace/AppUpdateModal.tsx index 1ad6a5bea9c18..fbeeade1e3b31 100644 --- a/apps/meteor/client/views/marketplace/AppUpdateModal.tsx +++ b/apps/meteor/client/views/marketplace/AppUpdateModal.tsx @@ -34,11 +34,11 @@ const AppUpdateModal = ({ confirm, cancel, ...props }: AppUpdateModalProps) => { return ( - + {t('Apps_Manual_Update_Modal_Title')} - {t('Apps_Manual_Update_Modal_Body')} + {t('Apps_Manual_Update_Modal_Body')} + + + +
diff --git a/apps/meteor/client/views/omnichannel/analytics/AnalyticsPage.tsx b/apps/meteor/client/views/omnichannel/analytics/AnalyticsPage.tsx index 7184f6bdb2113..11cd5853700fd 100644 --- a/apps/meteor/client/views/omnichannel/analytics/AnalyticsPage.tsx +++ b/apps/meteor/client/views/omnichannel/analytics/AnalyticsPage.tsx @@ -1,7 +1,7 @@ import type { SelectOption } from '@rocket.chat/fuselage'; -import { Box, Select, Margins, Field, FieldLabel, FieldRow, Label, Option } from '@rocket.chat/fuselage'; +import { Box, Select, Field, FieldLabel, FieldRow, Option } from '@rocket.chat/fuselage'; import { Page, PageHeader, PageScrollableContentWithShadow } from '@rocket.chat/ui-client'; -import { useMemo, useState, useEffect } from 'react'; +import { useId, useMemo, useState, useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import AgentOverview from './AgentOverview'; @@ -35,6 +35,8 @@ const AnalyticsPage = () => { const [department, setDepartment] = useState(null); const [dateRange, setDateRange] = useState({ start: '', end: '' }); const [chartName, setChartName] = useState(); + const typeLabelId = useId(); + const departmentsLabelId = useId(); const typeOptions: SelectOption[] = useMemo( () => [ @@ -53,55 +55,62 @@ const AnalyticsPage = () => { return ( - - - - - - - setType(String(value))} /> + + - - - - - - - + - {t('Chart')} + {t('Departments')} - setChartName(String(value))} /> + + + + + + + + + ); diff --git a/apps/meteor/client/views/omnichannel/analytics/DateRangePicker.tsx b/apps/meteor/client/views/omnichannel/analytics/DateRangePicker.tsx index f6c33870fe703..742835e1bb37e 100644 --- a/apps/meteor/client/views/omnichannel/analytics/DateRangePicker.tsx +++ b/apps/meteor/client/views/omnichannel/analytics/DateRangePicker.tsx @@ -129,26 +129,26 @@ const DateRangePicker = ({ onChange = () => undefined, ...props }: DateRangePick return ( - - - {t('Start')} - - + + + + {t('Start')} + - - - - - {t('End')} - - + + + + + + {t('End')} + - - - - - - + + + + + +
); diff --git a/apps/meteor/client/views/omnichannel/businessHours/BusinessHoursForm.tsx b/apps/meteor/client/views/omnichannel/businessHours/BusinessHoursForm.tsx index fefaa3f2aa0c2..9ccaa84b6220f 100644 --- a/apps/meteor/client/views/omnichannel/businessHours/BusinessHoursForm.tsx +++ b/apps/meteor/client/views/omnichannel/businessHours/BusinessHoursForm.tsx @@ -1,5 +1,5 @@ import type { SelectOption } from '@rocket.chat/fuselage'; -import { InputBox, Field, MultiSelect, FieldGroup, Box, Select, FieldLabel, FieldRow, Callout } from '@rocket.chat/fuselage'; +import { InputBox, Field, MultiSelect, FieldGroup, Box, Select, FieldLabel, FieldRow, Callout, Stack } from '@rocket.chat/fuselage'; import { useId, useMemo } from 'react'; import { useFormContext, Controller, useFieldArray } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; @@ -63,16 +63,18 @@ const BusinessHoursForm = ({ type }: BusinessHoursFormProps) => { {type === 'custom' && } {t('Timezone')} - - } + /> + + + {t('Business_hours_will_update_automatically')} + + {t('Open_days_of_the_week')} @@ -92,7 +94,6 @@ const BusinessHoursForm = ({ type }: BusinessHoursFormProps) => { options={daysOptions} value={value} placeholder={t('Select_an_option')} - width='full' /> )} /> diff --git a/apps/meteor/client/views/omnichannel/cannedResponses/components/CannedResponseForm.tsx b/apps/meteor/client/views/omnichannel/cannedResponses/components/CannedResponseForm.tsx index 135025c9f00cb..60dae75e56a0d 100644 --- a/apps/meteor/client/views/omnichannel/cannedResponses/components/CannedResponseForm.tsx +++ b/apps/meteor/client/views/omnichannel/cannedResponses/components/CannedResponseForm.tsx @@ -63,14 +63,14 @@ const CannedResponseForm = () => { )} - - {t('Message')} + + {t('Message')} {text !== '' && ( setPreview(!preview)}> {preview ? t('Editor') : t('Preview')} )} - + {preview ? ( ) : ( diff --git a/apps/meteor/client/views/omnichannel/cannedResponses/components/CannedResponsesComposer/CannedResponsesComposer.tsx b/apps/meteor/client/views/omnichannel/cannedResponses/components/CannedResponsesComposer/CannedResponsesComposer.tsx index 3de6921b1316c..39ff37a6a5444 100644 --- a/apps/meteor/client/views/omnichannel/cannedResponses/components/CannedResponsesComposer/CannedResponsesComposer.tsx +++ b/apps/meteor/client/views/omnichannel/cannedResponses/components/CannedResponsesComposer/CannedResponsesComposer.tsx @@ -1,4 +1,4 @@ -import { Button, PositionAnimated, Tile } from '@rocket.chat/fuselage'; +import { Box, Button, PopoverSurface, PositionAnimated } from '@rocket.chat/fuselage'; import { MessageComposerAction, MessageComposerToolbarActions, @@ -123,9 +123,13 @@ const CannedResponsesComposer = ({ onChange, ...props }: CannedResponsesComposer }} /> - - - + + + + + + + diff --git a/apps/meteor/client/views/omnichannel/cannedResponses/modals/CannedResponseEditWithData.tsx b/apps/meteor/client/views/omnichannel/cannedResponses/modals/CannedResponseEditWithData.tsx index f2296e3504c3f..99642d8379044 100644 --- a/apps/meteor/client/views/omnichannel/cannedResponses/modals/CannedResponseEditWithData.tsx +++ b/apps/meteor/client/views/omnichannel/cannedResponses/modals/CannedResponseEditWithData.tsx @@ -1,19 +1,16 @@ import type { IOmnichannelCannedResponse } from '@rocket.chat/core-typings'; -import { Callout } from '@rocket.chat/fuselage'; import { useEndpoint } from '@rocket.chat/ui-contexts'; import { useQuery } from '@tanstack/react-query'; -import { useTranslation } from 'react-i18next'; import CannedResponseEdit from './CannedResponseEdit'; import CannedResponseEditWithDepartmentData from './CannedResponseEditWithDepartmentData'; import { useRemoveCannedResponse } from './useRemoveCannedResponse'; import { FormSkeleton } from '../../../../components/Skeleton'; +import NotAvailableCallout from '../../components/NotAvailableCallout'; export type CannedResponseEditWithDataProps = { cannedResponseId: IOmnichannelCannedResponse['_id'] }; const CannedResponseEditWithData = ({ cannedResponseId }: CannedResponseEditWithDataProps) => { - const { t } = useTranslation(); - const getCannedResponseById = useEndpoint('GET', '/v1/canned-responses/:_id', { _id: cannedResponseId }); const handleDelete = useRemoveCannedResponse(cannedResponseId); @@ -27,11 +24,7 @@ const CannedResponseEditWithData = ({ cannedResponseId }: CannedResponseEditWith } if (isError) { - return ( - - {t('Not_Available')} - - ); + return ; } if (data?.cannedResponse?.scope === 'department') { diff --git a/apps/meteor/client/views/omnichannel/cannedResponses/modals/CannedResponseEditWithDepartmentData.tsx b/apps/meteor/client/views/omnichannel/cannedResponses/modals/CannedResponseEditWithDepartmentData.tsx index 265e40917632f..54783fc2f4fcf 100644 --- a/apps/meteor/client/views/omnichannel/cannedResponses/modals/CannedResponseEditWithDepartmentData.tsx +++ b/apps/meteor/client/views/omnichannel/cannedResponses/modals/CannedResponseEditWithDepartmentData.tsx @@ -1,13 +1,12 @@ import type { IOmnichannelCannedResponse, Serialized } from '@rocket.chat/core-typings'; -import { Callout } from '@rocket.chat/fuselage'; import { useEndpoint } from '@rocket.chat/ui-contexts'; import { useQuery } from '@tanstack/react-query'; import { useMemo } from 'react'; -import { useTranslation } from 'react-i18next'; import CannedResponseEdit from './CannedResponseEdit'; import { FormSkeleton } from '../../../../components/Skeleton'; import { omnichannelQueryKeys } from '../../../../lib/queryKeys'; +import NotAvailableCallout from '../../components/NotAvailableCallout'; const CannedResponseEditWithDepartmentData = ({ cannedResponseData, @@ -31,18 +30,12 @@ const CannedResponseEditWithDepartmentData = ({ }, }); - const { t } = useTranslation(); - if (isPending) { return ; } if (isError) { - return ( - - {t('Not_Available')} - - ); + return ; } return ; diff --git a/apps/meteor/client/views/omnichannel/cannedResponses/modals/CannedResponseFilter.tsx b/apps/meteor/client/views/omnichannel/cannedResponses/modals/CannedResponseFilter.tsx index 319cd2c0fa22e..ceceb722ae2ab 100644 --- a/apps/meteor/client/views/omnichannel/cannedResponses/modals/CannedResponseFilter.tsx +++ b/apps/meteor/client/views/omnichannel/cannedResponses/modals/CannedResponseFilter.tsx @@ -1,7 +1,7 @@ import type { SelectOption } from '@rocket.chat/fuselage'; -import { Box, Icon, TextInput, Select } from '@rocket.chat/fuselage'; +import { Box, Field, FieldLabel, FieldRow, Icon, TextInput, Select } from '@rocket.chat/fuselage'; import type { ChangeEvent } from 'react'; -import { memo } from 'react'; +import { memo, useId } from 'react'; import { useTranslation } from 'react-i18next'; import AutoCompleteAgent from '../../components/AutoCompleteAgent'; @@ -20,6 +20,10 @@ export type CannedResponsesFilterProps = { const CannedResponsesFilter = ({ createdBy, setCreatedBy, sharing, setSharing, text, setText }: CannedResponsesFilterProps) => { const { t } = useTranslation(); + const searchId = useId(); + const sharingLabelId = useId(); + const createdByLabelId = useId(); + const sharingList: SelectOption[] = [ ['', t('All')], ['user', t('Private')], @@ -28,22 +32,40 @@ const CannedResponsesFilter = ({ createdBy, setCreatedBy, sharing, setSharing, t ]; return ( - - - {t('Search')} - ) => setText(e.target.value)} - endAddon={} - /> + + + + {t('Search')} + + ) => setText(e.target.value)} + endAddon={} + /> + + - - {t('Sharing')} - setSharing(value as SharingValues)} + options={sharingList} + /> + + - - {t('Created_by')} - + + + {t('Created_by')} + + + + ); diff --git a/apps/meteor/client/views/omnichannel/components/AutoCompleteAgent.tsx b/apps/meteor/client/views/omnichannel/components/AutoCompleteAgent.tsx index 9ce414aa3e763..8bfb914731d62 100644 --- a/apps/meteor/client/views/omnichannel/components/AutoCompleteAgent.tsx +++ b/apps/meteor/client/views/omnichannel/components/AutoCompleteAgent.tsx @@ -1,4 +1,4 @@ -import { PaginatedSelectFiltered } from '@rocket.chat/fuselage'; +import { Box, PaginatedSelectFiltered } from '@rocket.chat/fuselage'; import { useDebouncedValue } from '@rocket.chat/fuselage-hooks'; import type { ComponentProps } from 'react'; import { memo, useState } from 'react'; @@ -41,16 +41,17 @@ const AutoCompleteAgent = ({ }); return ( - void} - options={agentsItems} - onChange={onChange} - endReached={() => fetchNextPage()} - /> + + void} + options={agentsItems} + onChange={onChange} + endReached={() => fetchNextPage()} + /> + ); }; diff --git a/apps/meteor/client/views/omnichannel/components/AutoCompleteContact/AutoCompleteContact.tsx b/apps/meteor/client/views/omnichannel/components/AutoCompleteContact/AutoCompleteContact.tsx index 0dc476e608891..96ccc30f02d6f 100644 --- a/apps/meteor/client/views/omnichannel/components/AutoCompleteContact/AutoCompleteContact.tsx +++ b/apps/meteor/client/views/omnichannel/components/AutoCompleteContact/AutoCompleteContact.tsx @@ -1,5 +1,5 @@ import type { Serialized } from '@rocket.chat/core-typings'; -import { PaginatedSelectFiltered } from '@rocket.chat/fuselage'; +import { Box, PaginatedSelectFiltered } from '@rocket.chat/fuselage'; import { useDebouncedValue } from '@rocket.chat/fuselage-hooks'; import type { ILivechatContactWithManagerData } from '@rocket.chat/rest-typings'; import type { ComponentProps, ReactNode, SyntheticEvent } from 'react'; @@ -42,21 +42,22 @@ const AutoCompleteContact = ({ value, placeholder, disabled, renderItem, onChang }); return ( - void} - options={contactsItems} - onChange={onChange} - endReached={() => fetchNextPage()} - renderItem={renderItem ? (props: OptionProps) => renderItem(props, contactsItems[props.index]) : undefined} - /> + + void} + options={contactsItems} + onChange={onChange} + endReached={() => fetchNextPage()} + renderItem={renderItem ? (props: OptionProps) => renderItem(props, contactsItems[props.index]) : undefined} + /> + ); }; diff --git a/apps/meteor/client/views/omnichannel/components/AutoCompleteDepartmentMultiple.tsx b/apps/meteor/client/views/omnichannel/components/AutoCompleteDepartmentMultiple.tsx index 930cbee3e4771..77f51b14a9315 100644 --- a/apps/meteor/client/views/omnichannel/components/AutoCompleteDepartmentMultiple.tsx +++ b/apps/meteor/client/views/omnichannel/components/AutoCompleteDepartmentMultiple.tsx @@ -62,9 +62,6 @@ const AutoCompleteDepartmentMultiple = ({ filter={departmentsFilter} setFilter={setDepartmentsFilter} options={departmentOptions} - width='100%' - flexShrink={0} - flexGrow={0} placeholder={t('Select_an_option')} renderItem={({ label, value, ...props }) => { if (withCheckbox) { diff --git a/apps/meteor/client/views/omnichannel/components/AutoCompleteMultipleAgent.tsx b/apps/meteor/client/views/omnichannel/components/AutoCompleteMultipleAgent.tsx index 9838cfd8c8d9e..c0cd17876dff1 100644 --- a/apps/meteor/client/views/omnichannel/components/AutoCompleteMultipleAgent.tsx +++ b/apps/meteor/client/views/omnichannel/components/AutoCompleteMultipleAgent.tsx @@ -47,9 +47,6 @@ const AutoCompleteMultipleAgent = ({ error={error} placeholder={placeholder} onChange={onChange} - width='100%' - flexShrink={0} - flexGrow={0} filter={agentsFilter} setFilter={setAgentsFilter as (value: string | number | undefined) => void} options={agentsItems} diff --git a/apps/meteor/client/views/omnichannel/components/FormSkeleton.tsx b/apps/meteor/client/views/omnichannel/components/FormSkeleton.tsx index e99c610476787..e4faceef0e4f8 100644 --- a/apps/meteor/client/views/omnichannel/components/FormSkeleton.tsx +++ b/apps/meteor/client/views/omnichannel/components/FormSkeleton.tsx @@ -4,8 +4,8 @@ import type { ComponentPropsWithoutRef } from 'react'; export type FormSkeletonProps = ComponentPropsWithoutRef; export const FormSkeleton = (props: FormSkeletonProps) => ( - - - + + + ); diff --git a/apps/meteor/client/views/omnichannel/components/NotAvailableCallout.tsx b/apps/meteor/client/views/omnichannel/components/NotAvailableCallout.tsx new file mode 100644 index 0000000000000..17ec4d207d053 --- /dev/null +++ b/apps/meteor/client/views/omnichannel/components/NotAvailableCallout.tsx @@ -0,0 +1,14 @@ +import { Box, Callout } from '@rocket.chat/fuselage'; +import { useTranslation } from 'react-i18next'; + +const NotAvailableCallout = () => { + const { t } = useTranslation(); + + return ( + + {t('Not_Available')} + + ); +}; + +export default NotAvailableCallout; diff --git a/apps/meteor/client/views/omnichannel/components/OmnichannelVerificationTag.tsx b/apps/meteor/client/views/omnichannel/components/OmnichannelVerificationTag.tsx index 626e3282f2686..638ea30c5829e 100644 --- a/apps/meteor/client/views/omnichannel/components/OmnichannelVerificationTag.tsx +++ b/apps/meteor/client/views/omnichannel/components/OmnichannelVerificationTag.tsx @@ -17,7 +17,7 @@ const OmnichannelVerificationTag = ({ verified, onClick }: OmnichannelVerificati } + icon={} > {isVerified ? t('Verified') : t('Unverified')} diff --git a/apps/meteor/client/views/omnichannel/components/RoomActivityIcon.tsx b/apps/meteor/client/views/omnichannel/components/RoomActivityIcon.tsx index ac8ad2cc54459..57a6e0c827b62 100644 --- a/apps/meteor/client/views/omnichannel/components/RoomActivityIcon.tsx +++ b/apps/meteor/client/views/omnichannel/components/RoomActivityIcon.tsx @@ -12,9 +12,7 @@ const RoomActivityIcon = ({ room }: RoomActivityIconProps) => { const { t } = useTranslation(); const isRoomOverMacLimit = useIsRoomOverMacLimit(room); - return isRoomOverMacLimit ? ( - - ) : null; + return isRoomOverMacLimit ? : null; }; export default RoomActivityIcon; diff --git a/apps/meteor/client/views/omnichannel/components/Tags.tsx b/apps/meteor/client/views/omnichannel/components/Tags.tsx index 5c69272634b46..022c36af1aa0d 100644 --- a/apps/meteor/client/views/omnichannel/components/Tags.tsx +++ b/apps/meteor/client/views/omnichannel/components/Tags.tsx @@ -1,4 +1,4 @@ -import { TextInput, Chip, Button, FieldLabel, FieldRow } from '@rocket.chat/fuselage'; +import { Box, TextInput, Chip, Button, FieldLabel, FieldRow, Stack } from '@rocket.chat/fuselage'; import { useStableCallback } from '@rocket.chat/fuselage-hooks'; import { useToastMessageDispatch } from '@rocket.chat/ui-contexts'; import type { ChangeEvent } from 'react'; @@ -67,7 +67,7 @@ const Tags = ({ tags = [], handler, error, tagRequired, department }: TagsProps) return ( <> - + {t('Tags')} @@ -86,28 +86,31 @@ const Tags = ({ tags = [], handler, error, tagRequired, department }: TagsProps) ) : ( <> - ): void => handleTagValue(currentTarget.value)} - flexGrow={1} - placeholder={t('Enter_a_tag')} - /> - + + ): void => handleTagValue(currentTarget.value)} + placeholder={t('Enter_a_tag')} + /> + + )} {customTags.length > 0 && ( - - {customTags?.map((tag, i) => ( - removeTag(tag)} marginInlineEnd={8}> - {tag} - - ))} + + + {customTags?.map((tag, i) => ( + removeTag(tag)}> + {tag} + + ))} + )} diff --git a/apps/meteor/client/views/omnichannel/components/outboundMessage/components/AutoCompleteDepartmentAgent.tsx b/apps/meteor/client/views/omnichannel/components/outboundMessage/components/AutoCompleteDepartmentAgent.tsx index d66daa3001f81..a2538959ebf99 100644 --- a/apps/meteor/client/views/omnichannel/components/outboundMessage/components/AutoCompleteDepartmentAgent.tsx +++ b/apps/meteor/client/views/omnichannel/components/outboundMessage/components/AutoCompleteDepartmentAgent.tsx @@ -41,7 +41,7 @@ const AutoCompleteDepartmentAgent = ({ value, onChange, agents, placeholder, ... options={options} renderSelected={({ selected: { value, label }, ...props }) => { return ( - onChange('')} marginInlineEnd={4}> + onChange('')}> {label} diff --git a/apps/meteor/client/views/omnichannel/components/outboundMessage/components/AutoCompleteOutboundProvider.tsx b/apps/meteor/client/views/omnichannel/components/outboundMessage/components/AutoCompleteOutboundProvider.tsx index 4a67ec7845a3e..fc9cf7896cfcb 100644 --- a/apps/meteor/client/views/omnichannel/components/outboundMessage/components/AutoCompleteOutboundProvider.tsx +++ b/apps/meteor/client/views/omnichannel/components/outboundMessage/components/AutoCompleteOutboundProvider.tsx @@ -1,5 +1,5 @@ import type { ILivechatContact, Serialized } from '@rocket.chat/core-typings'; -import { Option, OptionDescription, PaginatedSelectFiltered } from '@rocket.chat/fuselage'; +import { Box, Option, OptionDescription, PaginatedSelectFiltered } from '@rocket.chat/fuselage'; import type { ComponentProps } from 'react'; import { useState } from 'react'; import { useTranslation } from 'react-i18next'; @@ -32,30 +32,31 @@ const AutoCompleteOutboundProvider = ({ contact, disabled, value, placeholder, o }); return ( - void} - options={options} - onChange={onChange} - renderItem={({ label, value, ...props }) => { - const lastChat = findLastChatFromChannel(contact?.channels, value); + + void} + options={options} + onChange={onChange} + renderItem={({ label, value, ...props }) => { + const lastChat = findLastChatFromChannel(contact?.channels, value); - return ( - - ); - }} - /> + return ( + + ); + }} + /> + ); }; diff --git a/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/components/OutboundMessageWizardErrorState.tsx b/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/components/OutboundMessageWizardErrorState.tsx index 12545da673fc2..fa602cc450a48 100644 --- a/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/components/OutboundMessageWizardErrorState.tsx +++ b/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/components/OutboundMessageWizardErrorState.tsx @@ -10,7 +10,7 @@ type Props = { const OutboundMessageWizardErrorState = ({ title, description, onRetry }: Props) => { const { t } = useTranslation(); return ( - + {title ?? t('Something_went_wrong')} {description ? {description} : null} diff --git a/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/components/OutboundMessageWizardSkeleton.tsx b/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/components/OutboundMessageWizardSkeleton.tsx index 364b454895579..205a0fa3ac11e 100644 --- a/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/components/OutboundMessageWizardSkeleton.tsx +++ b/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/components/OutboundMessageWizardSkeleton.tsx @@ -1,14 +1,14 @@ -import { Box, Skeleton } from '@rocket.chat/fuselage'; +import { Box, Skeleton, Stack } from '@rocket.chat/fuselage'; const OutboubdMessageWizardSkeleton = () => { return ( - + - - - - + + + + diff --git a/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/components/RetryButton.tsx b/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/components/RetryButton.tsx index 17791fcda5f60..aeab09e70c2c3 100644 --- a/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/components/RetryButton.tsx +++ b/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/components/RetryButton.tsx @@ -23,12 +23,10 @@ const RetryButton = ({ loading, onClick }: RetryButtonProps) => { mini danger secondary - className={btnStyle} + className={[btnStyle, loading && 'rcx-button--loading']} disabled={loading} - rcx-button--loading={loading} icon={loading ? 'loading' : 'reload'} title={loading ? t('Loading...') : t('Retry')} - marginInlineStart={4} onClick={() => onClick()} /> ); diff --git a/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/MessageForm/MessageForm.spec.tsx b/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/MessageForm/MessageForm.spec.tsx index 43ae32747a68d..522136e92e9a7 100644 --- a/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/MessageForm/MessageForm.spec.tsx +++ b/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/MessageForm/MessageForm.spec.tsx @@ -65,7 +65,7 @@ describe('MessageForm', () => { const defaultValues = { templateId: 'template-1' }; render(, { wrapper: appRoot.build() }); - expect(screen.getByLabelText('Template*')).toHaveTextContent('Template One'); + expect(screen.getByLabelText('Template*').parentElement).toHaveTextContent('Template One'); }); it('should show TemplateEditor when a template is selected', async () => { @@ -76,7 +76,7 @@ describe('MessageForm', () => { await userEvent.click(screen.getByLabelText('Template*')); await userEvent.click(await screen.findByRole('option', { name: /Template One/ })); - expect(screen.getByLabelText('Template*')).toHaveTextContent('Template One'); + expect(screen.getByLabelText('Template*').parentElement).toHaveTextContent('Template One'); expect(await screen.findByText(component.body.text)).toBeInTheDocument(); }); diff --git a/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/MessageForm/MessageForm.tsx b/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/MessageForm/MessageForm.tsx index 01509334edd2c..9438bd37caacb 100644 --- a/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/MessageForm/MessageForm.tsx +++ b/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/MessageForm/MessageForm.tsx @@ -80,15 +80,17 @@ const MessageForm = (props: MessageFormProps) => { return (
- - setValue('templateParameters', {})} /> + + + setValue('templateParameters', {})} /> - {parametersMetadata.map((metadata) => ( - - ))} + {parametersMetadata.map((metadata) => ( + + ))} - {template ? : null} - + {template ? : null} + + {customActions ?? ( diff --git a/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/MessageForm/components/TemplateField.tsx b/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/MessageForm/components/TemplateField.tsx index cfba1d7ad1263..d70709155bb0e 100644 --- a/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/MessageForm/components/TemplateField.tsx +++ b/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/MessageForm/components/TemplateField.tsx @@ -48,12 +48,12 @@ const TemplateField = ({ control, templates, onChange: onChangeExternal, ...prop return ( - + {t('Template')} { expect(screen.getByLabelText('To*')).toBeInTheDocument(); expect(screen.getByLabelText('From*')).toBeInTheDocument(); - await waitFor(() => expect(screen.getByLabelText('Contact*')).not.toHaveAttribute('aria-disabled')); - await waitFor(() => expect(screen.getByLabelText('Channel*')).toHaveAttribute('aria-disabled', 'true')); + await waitFor(() => expect(screen.getByLabelText('Contact*')).toBeEnabled()); + await waitFor(() => expect(screen.getByLabelText('Channel*')).toBeDisabled()); expect(screen.getByLabelText('To*')).toHaveClass('disabled'); expect(screen.getByLabelText('From*')).toHaveClass('disabled'); }); @@ -128,8 +128,8 @@ describe('RecipientForm', () => { render(, { wrapper: appRoot.build() }); - await waitFor(() => expect(screen.getByLabelText('Contact*')).toHaveTextContent('Contact 1')); - await waitFor(() => expect(screen.getByLabelText('Channel*')).toHaveTextContent('Provider 1')); + await waitFor(() => expect(screen.getByLabelText('Contact*').parentElement).toHaveTextContent('Contact 1')); + await waitFor(() => expect(screen.getByLabelText('Channel*').parentElement).toHaveTextContent('Provider 1')); expect(screen.getByLabelText('To*')).toHaveTextContent(/\+1 212-555-4567/); expect(screen.getByLabelText('From*')).toHaveTextContent(/\+1 212-777-4567/); }); @@ -137,15 +137,15 @@ describe('RecipientForm', () => { it('should disable provider selection when no contact is selected', async () => { render(, { wrapper: appRoot.build() }); - await waitFor(() => expect(screen.getByLabelText('Contact*')).not.toHaveAttribute('aria-disabled')); - expect(screen.getByLabelText('Channel*')).toHaveAttribute('aria-disabled', 'true'); + await waitFor(() => expect(screen.getByLabelText('Contact*')).toBeEnabled()); + expect(screen.getByLabelText('Channel*')).toBeDisabled(); }); it('should disable recipient selection when no provider is selected', async () => { const defaultValues = { contactId: 'contact-1' }; render(, { wrapper: appRoot.build() }); - await waitFor(() => expect(screen.getByLabelText('Channel*')).toHaveAttribute('aria-disabled', 'false')); + await waitFor(() => expect(screen.getByLabelText('Channel*')).toBeEnabled()); expect(screen.getByLabelText('To*')).toHaveClass('disabled'); }); diff --git a/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/RecipientForm/RecipientForm.tsx b/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/RecipientForm/RecipientForm.tsx index b8ad99bbb6355..365b4e378b339 100644 --- a/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/RecipientForm/RecipientForm.tsx +++ b/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/RecipientForm/RecipientForm.tsx @@ -186,33 +186,35 @@ const RecipientForm = (props: RecipientFormProps) => { return ( - - - - - - - - - + + + + + + + + + + + {customActions ?? ( diff --git a/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/RecipientForm/components/ChannelField.tsx b/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/RecipientForm/components/ChannelField.tsx index 2aac35bdfd0dd..2897006a87340 100644 --- a/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/RecipientForm/components/ChannelField.tsx +++ b/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/RecipientForm/components/ChannelField.tsx @@ -1,5 +1,5 @@ import type { Serialized, ILivechatContact } from '@rocket.chat/core-typings'; -import { Field, FieldError, FieldHint, FieldLabel, FieldRow } from '@rocket.chat/fuselage'; +import { Box, Field, FieldError, FieldHint, FieldLabel, FieldRow } from '@rocket.chat/fuselage'; import { useId, useMemo } from 'react'; import type { ComponentProps } from 'react'; import type { Control } from 'react-hook-form'; @@ -55,13 +55,13 @@ const ProviderField = ({ return ( - + {t('Channel')} {providerFieldError && ( - - {providerFieldError.message} - {isError && } + + + {providerFieldError.message} + {isError && } + )} {providerLastChat && ( diff --git a/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/RecipientForm/components/ContactField.tsx b/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/RecipientForm/components/ContactField.tsx index 6847d285fb93d..5161275833c6d 100644 --- a/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/RecipientForm/components/ContactField.tsx +++ b/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/RecipientForm/components/ContactField.tsx @@ -57,12 +57,12 @@ const ContactField = ({ control, isError = false, isFetching = false, onRetry, . return ( - + {t('Contact')} {contactFieldError && ( - - {contactFieldError.message} - {isError && } + + + {contactFieldError.message} + {isError && } + )} diff --git a/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/RecipientForm/components/RecipientField.tsx b/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/RecipientForm/components/RecipientField.tsx index 43f3839eba92a..b03413dc93751 100644 --- a/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/RecipientForm/components/RecipientField.tsx +++ b/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/RecipientForm/components/RecipientField.tsx @@ -36,7 +36,7 @@ const RecipientField = ({ control, contact, type, disabled = false, isLoading = return ( - + {t('To')} diff --git a/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/RecipientForm/components/SenderField.tsx b/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/RecipientForm/components/SenderField.tsx index da0057c3e0bc5..c3acdeea8ad8a 100644 --- a/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/RecipientForm/components/SenderField.tsx +++ b/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/RecipientForm/components/SenderField.tsx @@ -37,7 +37,7 @@ const SenderField = ({ control, provider, disabled = false, isLoading = false, . return ( - + {t('From')} diff --git a/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/RepliesForm/RepliesForm.spec.tsx b/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/RepliesForm/RepliesForm.spec.tsx index 886543e008ba3..79d62678a5cd5 100644 --- a/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/RepliesForm/RepliesForm.spec.tsx +++ b/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/RepliesForm/RepliesForm.spec.tsx @@ -132,7 +132,7 @@ describe('RepliesForm', () => { expect(screen.getByLabelText('Department (optional)')).toBeInTheDocument(); expect(screen.getByLabelText('Agent (optional)')).toBeInTheDocument(); - expect(screen.getByLabelText('Department (optional)')).not.toHaveAttribute('aria-disabled'); + expect(screen.getByLabelText('Department (optional)')).toBeEnabled(); expect(screen.getByLabelText('Agent (optional)')).toBeDisabled(); }); @@ -146,8 +146,8 @@ describe('RepliesForm', () => { wrapper: appRoot().build(), }); - await waitFor(() => expect(screen.getByLabelText('Department (optional)')).toHaveTextContent('Department 1')); - await waitFor(() => expect(screen.getByLabelText('Agent (optional)')).toHaveTextContent('agent.one')); + await waitFor(() => expect(screen.getByLabelText('Department (optional)').parentElement).toHaveTextContent('Department 1')); + await waitFor(() => expect(screen.getByLabelText('Agent (optional)').parentElement).toHaveTextContent('agent.one')); }); it('should enable agent selection when a department is selected', async () => { @@ -156,7 +156,7 @@ describe('RepliesForm', () => { const departmentInput = screen.getByLabelText('Department (optional)'); const agentInput = screen.getByLabelText('Agent (optional)'); - await waitFor(() => expect(departmentInput).not.toHaveAttribute('aria-busy', 'true')); + await waitFor(() => expect(departmentInput).not.toHaveAttribute('placeholder', 'Loading...')); expect(agentInput).toBeDisabled(); await userEvent.click(departmentInput); diff --git a/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/RepliesForm/RepliesForm.tsx b/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/RepliesForm/RepliesForm.tsx index 0daaa83e0d18d..3e7584b833fe7 100644 --- a/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/RepliesForm/RepliesForm.tsx +++ b/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/RepliesForm/RepliesForm.tsx @@ -118,24 +118,26 @@ const RepliesForm = (props: RepliesFormProps) => { return ( - - setValue('agentId', '')} - /> - - - + + + setValue('agentId', '')} + /> + + + + {customActions ?? ( diff --git a/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/RepliesForm/components/AgentField.tsx b/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/RepliesForm/components/AgentField.tsx index 887e78ebd2aed..6a32f5dad185a 100644 --- a/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/RepliesForm/components/AgentField.tsx +++ b/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/RepliesForm/components/AgentField.tsx @@ -52,7 +52,7 @@ const AgentField = ({ control, agents, canAssignAgent, disabled = false, isLoadi /> {agentFieldError && ( - + {agentFieldError.message} )} diff --git a/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/RepliesForm/components/DepartmentField.tsx b/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/RepliesForm/components/DepartmentField.tsx index f42fe85535462..d441b3dab619a 100644 --- a/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/RepliesForm/components/DepartmentField.tsx +++ b/apps/meteor/client/views/omnichannel/components/outboundMessage/components/OutboundMessageWizard/forms/RepliesForm/components/DepartmentField.tsx @@ -1,4 +1,4 @@ -import { Field, FieldError, FieldHint, FieldLabel, FieldRow } from '@rocket.chat/fuselage'; +import { Box, Field, FieldError, FieldHint, FieldLabel, FieldRow } from '@rocket.chat/fuselage'; import { useStableCallback } from '@rocket.chat/fuselage-hooks'; import type { ComponentProps } from 'react'; import { useId } from 'react'; @@ -52,12 +52,12 @@ const DepartmentField = ({ return ( - {`${t('Department')} (${t('optional')})`} + {`${t('Department')} (${t('optional')})`} {departmentFieldError && ( - - {departmentFieldError.message} - {isError && } + + + {departmentFieldError.message} + {isError && } + )} {t('Outbound_message_department_hint')} diff --git a/apps/meteor/client/views/omnichannel/components/outboundMessage/modals/OutboundMessageModal/OutboundMessageModal.tsx b/apps/meteor/client/views/omnichannel/components/outboundMessage/modals/OutboundMessageModal/OutboundMessageModal.tsx index 93c9910f93a72..55916adf6a7e3 100644 --- a/apps/meteor/client/views/omnichannel/components/outboundMessage/modals/OutboundMessageModal/OutboundMessageModal.tsx +++ b/apps/meteor/client/views/omnichannel/components/outboundMessage/modals/OutboundMessageModal/OutboundMessageModal.tsx @@ -45,19 +45,14 @@ const OutboundMessageModal = ({ defaultValues, onClose }: OutboundMessageModalPr }); return ( - e.stopPropagation()} - onMouseDown={(e) => e.stopPropagation()} - onKeyDown={handleKeyDown} - > - + e.stopPropagation()} onMouseDown={(e) => e.stopPropagation()} onKeyDown={handleKeyDown}> + diff --git a/apps/meteor/client/views/omnichannel/contactHistory/MessageList/ContactHistoryMessagesList.tsx b/apps/meteor/client/views/omnichannel/contactHistory/MessageList/ContactHistoryMessagesList.tsx index eacc77a09d0ae..c6b816e50d4f6 100644 --- a/apps/meteor/client/views/omnichannel/contactHistory/MessageList/ContactHistoryMessagesList.tsx +++ b/apps/meteor/client/views/omnichannel/contactHistory/MessageList/ContactHistoryMessagesList.tsx @@ -3,7 +3,6 @@ import { Button, ButtonGroup, Icon, - Margins, States, StatesIcon, StatesSubtitle, @@ -89,15 +88,13 @@ const ContactHistoryMessagesList = ({ chatId, onClose, onOpenRoom }: ContactHist borderBlockEndColor='extra-light' flexShrink={0} > - - - } - /> - + + } + /> {isPending && ( diff --git a/apps/meteor/client/views/omnichannel/contactInfo/EditContactInfo.tsx b/apps/meteor/client/views/omnichannel/contactInfo/EditContactInfo.tsx index 8a6fd114ed085..40277b4d9db99 100644 --- a/apps/meteor/client/views/omnichannel/contactInfo/EditContactInfo.tsx +++ b/apps/meteor/client/views/omnichannel/contactInfo/EditContactInfo.tsx @@ -1,5 +1,5 @@ import type { ILivechatContact, Serialized } from '@rocket.chat/core-typings'; -import { ButtonGroup, Button, IconButton, Divider } from '@rocket.chat/fuselage'; +import { Box, ButtonGroup, Button, IconButton, Divider, Stack } from '@rocket.chat/fuselage'; import { Field, FieldLabel, FieldRow, FieldError, TextInput } from '@rocket.chat/fuselage-forms'; import { validateEmail } from '@rocket.chat/tools'; import { @@ -219,57 +219,71 @@ const EditContactInfo = ({ contactData, onClose, onCancel }: ContactNewEditProps {t('Email')} - {emailFields.map((field, index) => ( - - - } - /> - removeEmail(index)} marginInlineStart={8} icon='trash' /> - - {errors.emails?.[index]?.address && {errors.emails?.[index]?.address?.message}} - - ))} - + + + {emailFields.map((field, index) => ( + + + + ( + + )} + /> + removeEmail(index)} icon='trash' /> + + + {errors.emails?.[index]?.address && {errors.emails?.[index]?.address?.message}} + + ))} + + + {t('Phone')} - {phoneFields.map((field, index) => ( - - - } - /> - removePhone(index)} marginInlineStart={8} icon='trash' /> - - {errors.phones?.[index]?.phoneNumber && {errors.phones?.[index]?.phoneNumber?.message}} - - ))} - + + + {phoneFields.map((field, index) => ( + + + + ( + + )} + /> + removePhone(index)} icon='trash' /> + + + {errors.phones?.[index]?.phoneNumber && {errors.phones?.[index]?.phoneNumber?.message}} + + ))} + + + {t('Contact_Manager')} diff --git a/apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoDetails/ContactInfoDetails.tsx b/apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoDetails/ContactInfoDetails.tsx index 47669d603c356..09444ce6aa515 100644 --- a/apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoDetails/ContactInfoDetails.tsx +++ b/apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoDetails/ContactInfoDetails.tsx @@ -1,5 +1,4 @@ import type { ILivechatContact } from '@rocket.chat/core-typings'; -import { Divider, Margins } from '@rocket.chat/fuselage'; import { ContextualbarScrollableContent } from '@rocket.chat/ui-client'; import { useTranslation } from 'react-i18next'; @@ -51,23 +50,16 @@ const ContactInfoDetails = ({ contact, emails, phones, createdAt, customFieldEnt {contactManager ? : null} - - {createdAt && ( - - - {formatDate(createdAt)} - - )} + {createdAt && ( + + + {formatDate(createdAt)} + + )} - {customFieldEntries.length > 0 && ( - <> - - {customFieldEntries?.map(([key, value]) => ( - - ))} - - )} - + {customFieldEntries.map(([key, value]) => ( + + ))} ); }; diff --git a/apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoDetails/ContactInfoDetailsEntry.tsx b/apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoDetails/ContactInfoDetailsEntry.tsx index 6c1c3feddaf58..adce60b2175fe 100644 --- a/apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoDetails/ContactInfoDetailsEntry.tsx +++ b/apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoDetails/ContactInfoDetailsEntry.tsx @@ -9,8 +9,8 @@ export type ContactInfoDetailsEntryProps = Pick, 'is' }; const ContactInfoDetailsEntry = ({ icon, value, actions, ...props }: ContactInfoDetailsEntryProps) => ( - - + + {value} diff --git a/apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoHistory/ContactInfoHistory.tsx b/apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoHistory/ContactInfoHistory.tsx index fd57ee0d05378..9f8a522645b03 100644 --- a/apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoHistory/ContactInfoHistory.tsx +++ b/apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoHistory/ContactInfoHistory.tsx @@ -1,6 +1,6 @@ import type { ILivechatContact, Serialized } from '@rocket.chat/core-typings'; import { OmnichannelSourceType } from '@rocket.chat/core-typings'; -import { Box, Margins, Throbber, States, StatesIcon, StatesTitle, Select } from '@rocket.chat/fuselage'; +import { Box, Throbber, States, StatesIcon, StatesTitle, Select } from '@rocket.chat/fuselage'; import { useLocalStorage } from '@rocket.chat/fuselage-hooks'; import { VirtualizedScrollbars, ContextualbarContent, ContextualbarEmptyContent } from '@rocket.chat/ui-client'; import { useEndpoint, useSetModal } from '@rocket.chat/ui-contexts'; @@ -80,16 +80,14 @@ const ContactInfoHistory = ({ contact, setChatId }: ContactInfoHistoryProps) => borderBlockEndColor='extra-light' flexShrink={0} > - - - {isLoading && ( diff --git a/apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoHistory/ContactInfoHistoryItem.tsx b/apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoHistory/ContactInfoHistoryItem.tsx index 404aa316d4940..ac4c78c8419a7 100644 --- a/apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoHistory/ContactInfoHistoryItem.tsx +++ b/apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoHistory/ContactInfoHistoryItem.tsx @@ -1,6 +1,5 @@ import type { Serialized } from '@rocket.chat/core-typings'; import { - Icon, IconButton, Item, ItemActions, @@ -15,6 +14,7 @@ import { MessageGenericPreviewContent, MessageGenericPreviewDescription, MessageGenericPreviewTitle, + Icon, } from '@rocket.chat/fuselage'; import type { ContactSearchChatsResult } from '@rocket.chat/rest-typings'; import { useSetModal } from '@rocket.chat/ui-contexts'; @@ -56,7 +56,7 @@ const ContactInfoHistoryItem = ({ source, lastMessage, verified, onClick }: Cont {lastMessage && {getTimeFromNow(lastMessage.ts)}} {isVerified && ( - + )} diff --git a/apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoHistory/ContactInfoHistoryMessages.tsx b/apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoHistory/ContactInfoHistoryMessages.tsx index e94002505da59..7b46bbd09286e 100644 --- a/apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoHistory/ContactInfoHistoryMessages.tsx +++ b/apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoHistory/ContactInfoHistoryMessages.tsx @@ -4,13 +4,13 @@ import { ButtonGroup, Icon, IconButton, - Margins, States, StatesIcon, StatesSubtitle, StatesTitle, TextInput, Throbber, + Stack, } from '@rocket.chat/fuselage'; import { useDebouncedValue, useResizeObserver } from '@rocket.chat/fuselage-hooks'; import { VirtualizedScrollbars, ContextualbarContent, ContextualbarEmptyContent, ContextualbarFooter } from '@rocket.chat/ui-client'; @@ -68,17 +68,15 @@ const ContactInfoHistoryMessages = ({ chatId, onBack, onOpenRoom }: ContactHisto borderBlockEndColor='extra-light' flexShrink={0} > - - - } - /> - - - + + } + /> + + {isPending && ( diff --git a/apps/meteor/client/views/omnichannel/departments/DepartmentAgentsTable/AddAgent.tsx b/apps/meteor/client/views/omnichannel/departments/DepartmentAgentsTable/AddAgent.tsx index 950c763c588dc..98c95a6fa940d 100644 --- a/apps/meteor/client/views/omnichannel/departments/DepartmentAgentsTable/AddAgent.tsx +++ b/apps/meteor/client/views/omnichannel/departments/DepartmentAgentsTable/AddAgent.tsx @@ -1,4 +1,4 @@ -import { Box, Button } from '@rocket.chat/fuselage'; +import { Button, Stack } from '@rocket.chat/fuselage'; import { useStableCallback } from '@rocket.chat/fuselage-hooks'; import { useToastMessageDispatch } from '@rocket.chat/ui-contexts'; import type { AriaAttributes } from 'react'; @@ -43,12 +43,12 @@ function AddAgent({ agentList, onAdd, 'aria-labelledby': ariaLabelledBy }: AddAg }); return ( - + - - + ); } diff --git a/apps/meteor/client/views/omnichannel/departments/DepartmentAgentsTable/AgentRow.tsx b/apps/meteor/client/views/omnichannel/departments/DepartmentAgentsTable/AgentRow.tsx index bb5f9976ca84c..0877d1ed8328e 100644 --- a/apps/meteor/client/views/omnichannel/departments/DepartmentAgentsTable/AgentRow.tsx +++ b/apps/meteor/client/views/omnichannel/departments/DepartmentAgentsTable/AgentRow.tsx @@ -24,10 +24,10 @@ const AgentRow = ({ index, agent, register, onRemove }: AgentRowProps) => { - + - + diff --git a/apps/meteor/client/views/omnichannel/departments/DepartmentTags.tsx b/apps/meteor/client/views/omnichannel/departments/DepartmentTags.tsx index 3045ffb40206d..1738898ad8719 100644 --- a/apps/meteor/client/views/omnichannel/departments/DepartmentTags.tsx +++ b/apps/meteor/client/views/omnichannel/departments/DepartmentTags.tsx @@ -1,4 +1,4 @@ -import { Button, Chip, FieldRow, TextInput } from '@rocket.chat/fuselage'; +import { Box, Button, Chip, FieldRow, TextInput, Stack } from '@rocket.chat/fuselage'; import type { ComponentProps, ChangeEvent } from 'react'; import { useCallback, useState } from 'react'; import { useTranslation } from 'react-i18next'; @@ -29,24 +29,28 @@ const DepartmentTags = ({ error, value: tags, onChange, ...props }: DepartmentTa return ( <> - ) => setTagText(e.currentTarget.value)} - {...props} - /> - + + ) => setTagText(e.currentTarget.value)} + {...props} + /> + + {tags?.length > 0 && ( - - {tags.map((tag, i) => ( - - {tag} - - ))} + + + {tags.map((tag, i) => ( + + {tag} + + ))} + )} diff --git a/apps/meteor/client/views/omnichannel/departments/EditDepartment.tsx b/apps/meteor/client/views/omnichannel/departments/EditDepartment.tsx index de64b864a6c47..7d4d736433a77 100644 --- a/apps/meteor/client/views/omnichannel/departments/EditDepartment.tsx +++ b/apps/meteor/client/views/omnichannel/departments/EditDepartment.tsx @@ -16,6 +16,7 @@ import { PaginatedSelectFiltered, FieldHint, Option, + Stack, } from '@rocket.chat/fuselage'; import { useDebouncedValue } from '@rocket.chat/fuselage-hooks'; import { validateEmail } from '@rocket.chat/tools'; @@ -148,285 +149,281 @@ function EditDepartment({ data, id, title, allowedToForwardData }: EditDepartmen - - - - {t('Enabled')} - - - - - - {t('Name')} - - - - - {errors.name && ( - - {errors.name?.message} - - )} - - - {t('Description')} - - - - - - - {t('Show_on_registration_page')} - - - - - - {t('Email')} - - - } - placeholder={t('Email')} - {...register('email', { - required: t('Required_field', { field: t('Email') }), - validate: (email) => validateEmail(email) || t('error-invalid-email-address'), - })} - aria-describedby={`${emailField}-error`} - /> - - {errors.email && ( - - {errors.email?.message} - - )} - - - - {t('Show_on_offline_page')} - - - - - {t('Livechat_DepartmentOfflineMessageToChannel')} - - ( - void} - options={roomItems} - placeholder={t('Channel_name')} - endReached={() => fetchNextPage()} - aria-busy={fallbackFilter !== debouncedFallbackFilter} - /> - )} - /> - - - {hasLicense && ( - <> - - ( - - )} - /> - - - ( - - )} - /> - - - ( - - )} + + + + + {t('Enabled')} + + + + + + {t('Name')} + + + - - - ( - - )} + + {errors.name && ( + + {errors.name?.message} + + )} + + + {t('Description')} + + + + + + + {t('Show_on_registration_page')} + + + + + + {t('Email')} + + + } + placeholder={t('Email')} + {...register('email', { + required: t('Required_field', { field: t('Email') }), + validate: (email) => validateEmail(email) || t('error-invalid-email-address'), + })} + aria-describedby={`${emailField}-error`} /> - - - {t('List_of_departments_for_forward')} - - - ( - - )} - /> - - - {t('List_of_departments_for_forward_description')} - - - {t('Fallback_forward_department')} + + {errors.email && ( + + {errors.email?.message} + + )} + + + + {t('Show_on_offline_page')} + + + + + {t('Livechat_DepartmentOfflineMessageToChannel')} + ( - ( - - - - {t('Unit')} - - + + + {hasLicense && ( + <> + ( + + )} + /> + + + ( + + )} + /> + + + ( + + )} + /> + + + ( + + )} + /> + + + {t('List_of_departments_for_forward')} + + + ( + + )} + /> + + + {t('List_of_departments_for_forward_description')} + + + {t('Fallback_forward_department')} + ( - { - // NOTE: list.itemCount > 1 to account for the "None" option - setUnitRequired(!canManageUnits && list.length > 1); - }} + onlyMyDepartments + showArchived + withTitle={false} + renderItem={({ label, ...props }) => ( + - {errors.unit && ( - - {errors.unit?.message} - + + + + {t('Unit')} + + + ( + { + // NOTE: list.itemCount > 1 to account for the "None" option + setUnitRequired(!canManageUnits && list.length > 1); + }} + /> + )} + /> + + {errors.unit && ( + + {errors.unit?.message} + + )} + + + )} + + + {t('Request_tag_before_closing_chat')} + + + + + {t('Conversation_closing_tags')} + ( + )} - - - )} - - - {t('Request_tag_before_closing_chat')} - - - - - {t('Conversation_closing_tags')} - ( - + /> + {t('Conversation_closing_tags_description')} + {errors.chatClosingTags && ( + + {errors.chatClosingTags?.message} + )} - /> - {t('Conversation_closing_tags_description')} - {errors.chatClosingTags && ( - - {errors.chatClosingTags?.message} - - )} - - - - {t('Accept_receive_inquiry_no_online_agents')} - - - - {t('Accept_receive_inquiry_no_online_agents_Hint')} - - - - - - - - - {t('Agents')} - - - - - - + + + + {t('Accept_receive_inquiry_no_online_agents')} + + + + {t('Accept_receive_inquiry_no_online_agents_Hint')} + + + + + + + + + + + {t('Agents')} + + + + + + + diff --git a/apps/meteor/client/views/omnichannel/directory/OmnichannelDirectoryPage.tsx b/apps/meteor/client/views/omnichannel/directory/OmnichannelDirectoryPage.tsx index 11f8b17b16c61..7227b169cdbfe 100644 --- a/apps/meteor/client/views/omnichannel/directory/OmnichannelDirectoryPage.tsx +++ b/apps/meteor/client/views/omnichannel/directory/OmnichannelDirectoryPage.tsx @@ -34,7 +34,7 @@ const OmnichannelDirectoryPage = () => { - + handleTabClick('chats')}> {t('Chats')} diff --git a/apps/meteor/client/views/omnichannel/directory/chats/ChatInfo/RoomEdit/RoomEdit.tsx b/apps/meteor/client/views/omnichannel/directory/chats/ChatInfo/RoomEdit/RoomEdit.tsx index bb2a490011a98..e04463ed55da6 100644 --- a/apps/meteor/client/views/omnichannel/directory/chats/ChatInfo/RoomEdit/RoomEdit.tsx +++ b/apps/meteor/client/views/omnichannel/directory/chats/ChatInfo/RoomEdit/RoomEdit.tsx @@ -137,7 +137,7 @@ function RoomEdit({ room, visitor, reload, reloadInfo, onClose }: RoomEditProps) {t('Topic')} - + @@ -155,18 +155,9 @@ function RoomEdit({ room, visitor, reload, reloadInfo, onClose }: RoomEditProps) - + - diff --git a/apps/meteor/client/views/omnichannel/directory/chats/ChatsFiltersContextualBar.tsx b/apps/meteor/client/views/omnichannel/directory/chats/ChatsFiltersContextualBar.tsx index fb5e2dd7e2e46..4befb1c55ba9d 100644 --- a/apps/meteor/client/views/omnichannel/directory/chats/ChatsFiltersContextualBar.tsx +++ b/apps/meteor/client/views/omnichannel/directory/chats/ChatsFiltersContextualBar.tsx @@ -100,24 +100,20 @@ const ChatsFiltersContextualBar = ({ onClose }: ChatsFiltersContextualBarProps) {canViewLivechatRooms && ( - - {t('Served_By')} - + {t('Served_By')} ( - + )} /> )} - - {t('Status')} - + {t('Status')} - - {t('Department')} - + {t('Department')} ( - + )} /> @@ -160,16 +148,12 @@ const ChatsFiltersContextualBar = ({ onClose }: ChatsFiltersContextualBarProps) {isEnterprise && ( - - {t('Units')} - + {t('Units')} ( - - )} + render={({ field: { value, onChange } }) => } /> @@ -179,9 +163,7 @@ const ChatsFiltersContextualBar = ({ onClose }: ChatsFiltersContextualBarProps) if (customField.type === 'select') { return ( - - {customField.label} - + {customField.label} { const canRemoveAllClosedChats = usePermission('remove-closed-livechat-rooms'); const { filtersQuery, displayFilters, setFiltersQuery, removeFilter, textInputRef } = useChatsContext(); + const filterChips = Object.entries(displayFilters).filter(([, label]) => label); const handleRemoveAllClosed = useStableCallback(async () => { const onDeleteAll = async () => { @@ -73,18 +74,19 @@ const ChatsTableFilter = () => { {menuItems.length > 0 && } - - {Object.entries(displayFilters).map(([value, label], index) => { - if (!label) { - return null; - } - - return ( - removeFilter(value)}> - {label} - - ); - })} + + {filterChips.map(([value, label]) => ( + removeFilter(value)}> + {label} + + ))} ); diff --git a/apps/meteor/client/views/omnichannel/directory/chats/ChatsTable/ChatsTableRow.tsx b/apps/meteor/client/views/omnichannel/directory/chats/ChatsTable/ChatsTableRow.tsx index 1d8fceb17d7b5..97de7e8bcda0f 100644 --- a/apps/meteor/client/views/omnichannel/directory/chats/ChatsTable/ChatsTableRow.tsx +++ b/apps/meteor/client/views/omnichannel/directory/chats/ChatsTable/ChatsTableRow.tsx @@ -114,8 +114,10 @@ const ChatsTableRow = (room: IOmnichannelRoomWithDepartment) => { )} - - {getStatusText(open, onHold)} + + + {getStatusText(open, onHold)} + {canRemoveClosedChats && {!open && }} diff --git a/apps/meteor/client/views/omnichannel/directory/components/FormSkeleton.tsx b/apps/meteor/client/views/omnichannel/directory/components/FormSkeleton.tsx index 7029dd30a39da..c53235b9e960d 100644 --- a/apps/meteor/client/views/omnichannel/directory/components/FormSkeleton.tsx +++ b/apps/meteor/client/views/omnichannel/directory/components/FormSkeleton.tsx @@ -1,15 +1 @@ -import { Box, Skeleton } from '@rocket.chat/fuselage'; -import type { ComponentPropsWithoutRef } from 'react'; - -export type FormSkeletonProps = ComponentPropsWithoutRef; - -export const FormSkeleton = (props: FormSkeletonProps) => ( - - - - - - - - -); +export { FormSkeleton } from '../../../../components/Skeleton'; diff --git a/apps/meteor/client/views/omnichannel/hooks/useOmnichannelPrioritiesConfig.ts b/apps/meteor/client/views/omnichannel/hooks/useOmnichannelPrioritiesConfig.ts index 7245e4bafd14e..b4f9975b89a77 100644 --- a/apps/meteor/client/views/omnichannel/hooks/useOmnichannelPrioritiesConfig.ts +++ b/apps/meteor/client/views/omnichannel/hooks/useOmnichannelPrioritiesConfig.ts @@ -1,12 +1,15 @@ import { LivechatPriorityWeight } from '@rocket.chat/core-typings'; -import { Palette } from '@rocket.chat/fuselage'; import type { Keys } from '@rocket.chat/icons'; import { useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { useOmnichannelPriorities } from './useOmnichannelPriorities'; -type PrioritiesConfig = { iconName: Keys; color?: string; variant?: 'secondary-danger' | 'secondary-warning' | 'secondary-info' }; +type PrioritiesConfig = { + iconName: Keys; + color?: 'danger' | 'status-font-on-warning' | 'info'; + variant?: 'secondary-danger' | 'secondary-warning' | 'secondary-info'; +}; export const PRIORITIES_CONFIG: Record = { [LivechatPriorityWeight.NOT_SPECIFIED]: { @@ -14,27 +17,27 @@ export const PRIORITIES_CONFIG: Record = { }, [LivechatPriorityWeight.HIGHEST]: { iconName: 'chevron-double-up', - color: Palette.badge['badge-background-level-4'].toString(), + color: 'danger', variant: 'secondary-danger', }, [LivechatPriorityWeight.HIGH]: { iconName: 'chevron-up', - color: Palette.badge['badge-background-level-4'].toString(), + color: 'danger', variant: 'secondary-danger', }, [LivechatPriorityWeight.MEDIUM]: { iconName: 'equal', - color: Palette.badge['badge-background-level-3'].toString(), + color: 'status-font-on-warning', variant: 'secondary-warning', }, [LivechatPriorityWeight.LOW]: { iconName: 'chevron-down', - color: Palette.badge['badge-background-level-2'].toString(), + color: 'info', variant: 'secondary-info', }, [LivechatPriorityWeight.LOWEST]: { iconName: 'chevron-double-down', - color: Palette.badge['badge-background-level-2'].toString(), + color: 'info', variant: 'secondary-info', }, }; diff --git a/apps/meteor/client/views/omnichannel/managers/AddManager.tsx b/apps/meteor/client/views/omnichannel/managers/AddManager.tsx index 9342b080a04e9..8c47adc2bd0bc 100644 --- a/apps/meteor/client/views/omnichannel/managers/AddManager.tsx +++ b/apps/meteor/client/views/omnichannel/managers/AddManager.tsx @@ -1,4 +1,4 @@ -import { Button, Box, Field, FieldLabel, FieldRow } from '@rocket.chat/fuselage'; +import { Button, Box, Field, FieldLabel, FieldRow, Stack } from '@rocket.chat/fuselage'; import { useStableCallback } from '@rocket.chat/fuselage-hooks'; import { UserAutoComplete } from '@rocket.chat/ui-client'; import { useToastMessageDispatch } from '@rocket.chat/ui-contexts'; @@ -41,10 +41,12 @@ const AddManager = () => { {t('Username')} - - + + + + diff --git a/apps/meteor/client/views/omnichannel/modals/CloseChatModal.tsx b/apps/meteor/client/views/omnichannel/modals/CloseChatModal.tsx index adb2ceb2e70cf..2a8dc5e43f052 100644 --- a/apps/meteor/client/views/omnichannel/modals/CloseChatModal.tsx +++ b/apps/meteor/client/views/omnichannel/modals/CloseChatModal.tsx @@ -12,6 +12,7 @@ import { FieldLabel, FieldRow, FieldError, + FieldHint, ModalHeader, ModalIcon, ModalTitle, @@ -19,6 +20,7 @@ import { ModalFooter, ModalFooterControllers, ModalContent, + Stack, } from '@rocket.chat/fuselage'; import { GenericModal } from '@rocket.chat/ui-client'; import { usePermission, useSetting, useUserPreference, useToastMessageDispatch } from '@rocket.chat/ui-contexts'; @@ -162,7 +164,7 @@ const CloseChatModal = ({ department, visitorEmail, onCancel, onConfirm }: Close {t('Wrap_up_conversation')} - + {t('Close_room_description')} @@ -171,7 +173,6 @@ const CloseChatModal = ({ department, visitorEmail, onCancel, onConfirm }: Close @@ -182,59 +183,62 @@ const CloseChatModal = ({ department, visitorEmail, onCancel, onConfirm }: Close {errors.tags?.message} {canSendTranscript && ( - <> - - - {t('Chat_transcript')} - - {canSendTranscriptPDF && ( - - - {t('Omnichannel_transcript_pdf')} - - + + + + + + {t('Chat_transcript')} + - )} - {canSendTranscriptEmail && ( - <> - + {canSendTranscriptPDF && ( + - {t('Omnichannel_transcript_email')} - + {t('Omnichannel_transcript_pdf')} + - {transcriptEmail && ( - <> - - {t('Contact_email')} - - - - - - {t('Subject')} - - - - {errors.subject?.message} - - - )} - - )} - - + )} + {canSendTranscriptEmail && ( + + + + {t('Omnichannel_transcript_email')} + + + + {transcriptEmail && ( + + + {t('Contact_email')} + + + + + + {t('Subject')} + + + + {errors.subject?.message} + + + )} + + )} + + + {canSendTranscriptPDF && canSendTranscriptEmail ? t('These_options_affect_this_conversation_only_To_set_default_selections_go_to_My_Account_Omnichannel') : t('This_option_affect_this_conversation_only_To_set_default_selection_go_to_My_Account_Omnichannel')} - + - + )} diff --git a/apps/meteor/client/views/omnichannel/modals/EnterpriseDepartmentsModal.tsx b/apps/meteor/client/views/omnichannel/modals/EnterpriseDepartmentsModal.tsx index 1331f9ff3e12b..afedb0aaff210 100644 --- a/apps/meteor/client/views/omnichannel/modals/EnterpriseDepartmentsModal.tsx +++ b/apps/meteor/client/views/omnichannel/modals/EnterpriseDepartmentsModal.tsx @@ -51,7 +51,7 @@ const EnterpriseDepartmentsModal = ({ closeModal }: { closeModal: () => void }) - + {t('Premium_Departments_title')} diff --git a/apps/meteor/client/views/omnichannel/modals/ForwardChatModal.tsx b/apps/meteor/client/views/omnichannel/modals/ForwardChatModal.tsx index 137c8ab9a4a8e..4e4756c0c3df2 100644 --- a/apps/meteor/client/views/omnichannel/modals/ForwardChatModal.tsx +++ b/apps/meteor/client/views/omnichannel/modals/ForwardChatModal.tsx @@ -128,44 +128,46 @@ const ForwardChatModal = ({ room, onCancel }: ForwardChatModalProps) => { /> - {t('or')} - - {t('Forward_to_user')} - - ( - - )} - /> - - - - - {t('Leave_a_comment')} - - ({t('Optional')}) - - - - } - /> - - + {t('or')} + + + {t('Forward_to_user')} + + ( + + )} + /> + + + + + {t('Leave_a_comment')} + + ({t('Optional')}) + + + + } + /> + + + ); diff --git a/apps/meteor/client/views/omnichannel/modals/PlaceChatOnHoldModal.tsx b/apps/meteor/client/views/omnichannel/modals/PlaceChatOnHoldModal.tsx index aebccb5cf3fc0..4acb6daf86c14 100644 --- a/apps/meteor/client/views/omnichannel/modals/PlaceChatOnHoldModal.tsx +++ b/apps/meteor/client/views/omnichannel/modals/PlaceChatOnHoldModal.tsx @@ -28,7 +28,7 @@ const PlaceChatOnHoldModal = ({ onCancel, onOnHoldChat, confirm = onOnHoldChat, {t('Omnichannel_onHold_Chat')} - {t('Would_you_like_to_place_chat_on_hold')} + {t('Would_you_like_to_place_chat_on_hold')} diff --git a/apps/meteor/client/views/omnichannel/modals/TranscriptModal.tsx b/apps/meteor/client/views/omnichannel/modals/TranscriptModal.tsx index 3583cdff014ff..ebc3f68010af7 100644 --- a/apps/meteor/client/views/omnichannel/modals/TranscriptModal.tsx +++ b/apps/meteor/client/views/omnichannel/modals/TranscriptModal.tsx @@ -74,7 +74,7 @@ const TranscriptModal = ({ email: emailDefault = '', room, onRequest, onSend, on {t('Transcript')} - + {!!transcriptRequest &&

{t('Livechat_transcript_already_requested_warning')}

} diff --git a/apps/meteor/client/views/omnichannel/monitors/MonitorsTable.tsx b/apps/meteor/client/views/omnichannel/monitors/MonitorsTable.tsx index 6f50ce7bb5baf..44626b9933a63 100644 --- a/apps/meteor/client/views/omnichannel/monitors/MonitorsTable.tsx +++ b/apps/meteor/client/views/omnichannel/monitors/MonitorsTable.tsx @@ -11,6 +11,7 @@ import { StatesTitle, StatesActions, StatesAction, + Stack, } from '@rocket.chat/fuselage'; import { useDebouncedValue } from '@rocket.chat/fuselage-hooks'; import { @@ -134,10 +135,12 @@ const MonitorsTable = () => { {t('Username')} - void} /> - + + void} /> + + diff --git a/apps/meteor/client/views/omnichannel/priorities/PriorityEditFormWithData.tsx b/apps/meteor/client/views/omnichannel/priorities/PriorityEditFormWithData.tsx index d451937ed3b26..19e567999b604 100644 --- a/apps/meteor/client/views/omnichannel/priorities/PriorityEditFormWithData.tsx +++ b/apps/meteor/client/views/omnichannel/priorities/PriorityEditFormWithData.tsx @@ -1,9 +1,7 @@ -import { Callout } from '@rocket.chat/fuselage'; -import { useTranslation } from 'react-i18next'; - import type { PriorityEditFormProps } from './PriorityEditForm'; import PriorityEditForm from './PriorityEditForm'; import { FormSkeleton } from '../../../components/Skeleton'; +import NotAvailableCallout from '../components/NotAvailableCallout'; import { usePriorityInfo } from '../directory/hooks/usePriorityInfo'; export type PriorityEditFormWithDataProps = Omit & { @@ -11,7 +9,6 @@ export type PriorityEditFormWithDataProps = Omit }; function PriorityEditFormWithData({ priorityId, ...props }: PriorityEditFormWithDataProps) { - const { t } = useTranslation(); const { data, isLoading, isError } = usePriorityInfo(priorityId); if (isLoading) { @@ -19,11 +16,7 @@ function PriorityEditFormWithData({ priorityId, ...props }: PriorityEditFormWith } if (isError || !data) { - return ( - - {t('Not_Available')} - - ); + return ; } return ; diff --git a/apps/meteor/client/views/omnichannel/priorities/PriorityIcon.tsx b/apps/meteor/client/views/omnichannel/priorities/PriorityIcon.tsx index 358c24ad39e64..3101b6b26424b 100644 --- a/apps/meteor/client/views/omnichannel/priorities/PriorityIcon.tsx +++ b/apps/meteor/client/views/omnichannel/priorities/PriorityIcon.tsx @@ -1,10 +1,9 @@ import type { LivechatPriorityWeight } from '@rocket.chat/core-typings'; -import { Icon } from '@rocket.chat/fuselage'; -import type { ComponentProps } from 'react'; +import { Icon, type IconProps } from '@rocket.chat/fuselage'; import { useOmnichannelPrioritiesConfig } from '../hooks/useOmnichannelPrioritiesConfig'; -export type PriorityIconProps = Omit, 'name' | 'color'> & { +export type PriorityIconProps = Omit & { level: LivechatPriorityWeight; showUnprioritized?: boolean; }; diff --git a/apps/meteor/client/views/omnichannel/queueList/QueueListFilter.tsx b/apps/meteor/client/views/omnichannel/queueList/QueueListFilter.tsx index e0ed5e8c9e5ab..4850d7597ebba 100644 --- a/apps/meteor/client/views/omnichannel/queueList/QueueListFilter.tsx +++ b/apps/meteor/client/views/omnichannel/queueList/QueueListFilter.tsx @@ -1,7 +1,7 @@ -import { Box, Select, Label } from '@rocket.chat/fuselage'; +import { Box, Field, FieldLabel, FieldRow, Select } from '@rocket.chat/fuselage'; import { useStableCallback, useLocalStorage } from '@rocket.chat/fuselage-hooks'; import type { Dispatch, FormEvent, Key, SetStateAction } from 'react'; -import { useEffect } from 'react'; +import { useEffect, useId } from 'react'; import { useTranslation } from 'react-i18next'; import AutoCompleteAgent from '../components/AutoCompleteAgent'; @@ -19,6 +19,10 @@ export const QueueListFilter = ({ setFilter, ...props }: QueueListFilterProps) = ['offline', t('Include_Offline_Agents')], ]; + const servedByLabelId = useId(); + const statusLabelId = useId(); + const departmentLabelId = useId(); + const [servedBy, setServedBy] = useLocalStorage('servedBy', 'all'); const [status, setStatus] = useLocalStorage('status', 'online'); const [department, setDepartment] = useLocalStorage('department', 'all'); @@ -48,18 +52,42 @@ export const QueueListFilter = ({ setFilter, ...props }: QueueListFilterProps) = return ( - - - - + + + + {t('Served_By')} + + + + - - - + + - - - + + + {t('Department')} + + + + diff --git a/apps/meteor/client/views/omnichannel/realTimeMonitoring/RealTimeMonitoringPage.tsx b/apps/meteor/client/views/omnichannel/realTimeMonitoring/RealTimeMonitoringPage.tsx index f01d76fbe6624..0144b8241bf35 100644 --- a/apps/meteor/client/views/omnichannel/realTimeMonitoring/RealTimeMonitoringPage.tsx +++ b/apps/meteor/client/views/omnichannel/realTimeMonitoring/RealTimeMonitoringPage.tsx @@ -1,15 +1,14 @@ import type { SelectOption } from '@rocket.chat/fuselage'; -import { Box, Select, Margins, Option } from '@rocket.chat/fuselage'; +import { Box, Field, FieldLabel, FieldRow, Select, Margins, Option } from '@rocket.chat/fuselage'; import { useStableCallback } from '@rocket.chat/fuselage-hooks'; import { Page, PageHeader, PageScrollableContentWithShadow } from '@rocket.chat/ui-client'; import { useQueryClient } from '@tanstack/react-query'; import type { Key } from 'react'; -import { useState, useMemo, useEffect, Fragment } from 'react'; +import { useId, useState, useMemo, useEffect, Fragment } from 'react'; import { useTranslation } from 'react-i18next'; import { getDateRange } from '../../../lib/utils/getDateRange'; import AutoCompleteDepartment from '../components/AutoCompleteDepartment'; -import Label from '../components/Label'; import AgentStatusChart from './charts/AgentStatusChart'; import ChatDurationChart from './charts/ChatDurationChart'; import ChatsChart from './charts/ChatsChart'; @@ -29,6 +28,8 @@ const RealTimeMonitoringPage = () => { const [reloadFrequency, setReloadFrequency] = useState(5); const [departmentId, setDepartment] = useState(''); + const departmentsLabelId = useId(); + const updateEveryLabelId = useId(); const queryClient = useQueryClient(); @@ -59,26 +60,38 @@ const RealTimeMonitoringPage = () => { - - - - + {download && ( ( - + {' '} diff --git a/packages/fuselage/src/components/AutoComplete/AutoComplete.styles.scss b/packages/fuselage/src/components/AutoComplete/AutoComplete.styles.scss index d6670e4bdff39..7414c0a28a9fa 100644 --- a/packages/fuselage/src/components/AutoComplete/AutoComplete.styles.scss +++ b/packages/fuselage/src/components/AutoComplete/AutoComplete.styles.scss @@ -2,4 +2,8 @@ .rcx-autocomplete { @extend .rcx-select; + + &__input { + order: 1; + } } diff --git a/packages/fuselage/src/components/AutoComplete/AutoComplete.tsx b/packages/fuselage/src/components/AutoComplete/AutoComplete.tsx index 6f7a740896a43..dcc7626a0167b 100644 --- a/packages/fuselage/src/components/AutoComplete/AutoComplete.tsx +++ b/packages/fuselage/src/components/AutoComplete/AutoComplete.tsx @@ -16,7 +16,6 @@ import { Box } from '../Box'; import { Chip } from '../Chip'; import { Icon } from '../Icon'; import { Input } from '../InputBox'; -import { Margins } from '../Margins'; import { useCursor, Options, type OptionType } from '../Options'; import { PositionAnimated } from '../PositionAnimated'; @@ -162,38 +161,35 @@ function AutoComplete({ flexGrow={1} className={useMemo(() => [error && 'invalid', disabled && 'disabled'], [error, disabled])} > - - - ) => setFilter?.(e.currentTarget.value))} - onBlur={handleOnBlur} - onFocus={show} - onKeyDown={handleKeyDown} - placeholder={optionsAreVisible === AnimatedVisibility.HIDDEN || !value ? placeholder : undefined} - order={1} - rcx-input-box--undecorated - value={filter} - disabled={disabled} - {...props} - /> - {selected.map((itemSelected) => - RenderSelected ? ( - - ) : ( - - {itemSelected.label as ReactNode} - - ), - )} - + + ) => setFilter?.(e.currentTarget.value))} + onBlur={handleOnBlur} + onFocus={show} + onKeyDown={handleKeyDown} + placeholder={optionsAreVisible === AnimatedVisibility.HIDDEN || !value ? placeholder : undefined} + value={filter} + disabled={disabled} + {...props} + className={['rcx-input-box--undecorated', 'rcx-autocomplete__input', props.className]} + /> + {selected.map((itemSelected) => + RenderSelected ? ( + + ) : ( + + {itemSelected.label as ReactNode} + + ), + )} - - + + .rcx-icon { + margin-inline-end: lengths.margin(8); + } + &--primary { color: button-colors.$button-primary-color; background-color: button-colors.$button-primary-background-color; diff --git a/packages/fuselage/src/components/Bubble/BubbleItem.tsx b/packages/fuselage/src/components/Bubble/BubbleItem.tsx index e9c5226dc0541..efe92b96db70f 100644 --- a/packages/fuselage/src/components/Bubble/BubbleItem.tsx +++ b/packages/fuselage/src/components/Bubble/BubbleItem.tsx @@ -11,7 +11,7 @@ type BubbleItemProps = { export const BubbleItem = ({ secondary, label, icon, ...props }: BubbleItemProps) => ( - {icon && } + {icon && } {label && {label}} ); diff --git a/packages/fuselage/src/components/Button/Button.spec.tsx b/packages/fuselage/src/components/Button/Button.spec.tsx index 1d37371d10240..e01b3be5e74b2 100644 --- a/packages/fuselage/src/components/Button/Button.spec.tsx +++ b/packages/fuselage/src/components/Button/Button.spec.tsx @@ -1,6 +1,8 @@ import { composeStories } from '@storybook/react-webpack5'; +import { screen } from '@testing-library/react'; import { axe } from 'jest-axe'; +import Button from './Button'; import * as stories from './Button.stories'; import { render } from '../../testing'; @@ -17,4 +19,18 @@ describe('[Button Component]', () => { const results = await axe(container); expect(results).toHaveNoViolations(); }); + + it('should render a button of type button by default', () => { + render(); + expect(screen.getByRole('button', { name: 'Save' })).toHaveAttribute('type', 'button'); + }); + + it('should render a link without a type when is is a', () => { + render( + , + ); + expect(screen.getByRole('link', { name: 'Go' })).not.toHaveAttribute('type'); + }); }); diff --git a/packages/fuselage/src/components/Button/Button.stories.tsx b/packages/fuselage/src/components/Button/Button.stories.tsx index 58efb288285f7..2b90a561c70de 100644 --- a/packages/fuselage/src/components/Button/Button.stories.tsx +++ b/packages/fuselage/src/components/Button/Button.stories.tsx @@ -49,6 +49,11 @@ export default { description: 'Renders as a square icon-only footprint instead of the default pill shape.', table: { category: 'Shape' }, }, + compact: { + control: 'boolean', + description: 'Lowers the minimum width so a label of one or two characters fits.', + table: { category: 'Shape' }, + }, icon: { control: 'text', description: 'Name of the Fuselage icon rendered before the label.', @@ -168,6 +173,18 @@ export const Sizes: Story = { ), }; +export const Compact: Story = { + render: () => ( + + {['1', '2', '10'].map((label) => ( + + ))} + + ), +}; + export const AsLink: Story = { args: { is: 'a', diff --git a/packages/fuselage/src/components/Button/Button.styles.scss b/packages/fuselage/src/components/Button/Button.styles.scss index 4c031cdf40295..9e0673abf0578 100644 --- a/packages/fuselage/src/components/Button/Button.styles.scss +++ b/packages/fuselage/src/components/Button/Button.styles.scss @@ -50,6 +50,10 @@ @include use-with-truncated-text(); } + .rcx-button__icon { + margin-inline-end: lengths.margin(4); + } + @include clickable; @include use-font-scale(p2m); @include use-text-ellipsis; @@ -82,6 +86,10 @@ @include with-rectangular-size($height: 48, $padding-x: 24, $line-height: line-height(p2)); } + &--compact { + min-width: 4ch; + } + &--square { @include with-squared-size($size: 40); display: flex; @@ -103,10 +111,20 @@ display: flex; - transform: translate(30%, -30%); + translate: 30% -30%; &:dir(rtl) { - transform: translate(-30%, -30%); + translate: -30% -30%; + } + + &--bottom-end { + inset-block: auto 0; + + translate: 30% 30%; + + &:dir(rtl) { + translate: -30% 30%; + } } } diff --git a/packages/fuselage/src/components/Button/Button.tsx b/packages/fuselage/src/components/Button/Button.tsx index 717d95e8c7a32..4bf1320a4e996 100644 --- a/packages/fuselage/src/components/Button/Button.tsx +++ b/packages/fuselage/src/components/Button/Button.tsx @@ -4,7 +4,9 @@ import { useMemo } from 'react'; import { Box, type BoxProps } from '../Box'; import { Icon, type IconProps } from '../Icon'; -export type ButtonProps = Omit & { +export type ButtonProps = Omit & { + /** Renders a link instead of a button, for actions that navigate or download. */ + is?: 'button' | 'a'; variant?: 'primary' | 'secondary' | 'danger' | 'warning' | 'success' | 'secondary-danger' | 'secondary-warning' | 'secondary-success'; size?: 'mini' | 'tiny' | 'small' | 'medium' | 'large'; /** @deprecated Use `variant="primary"` instead. */ @@ -30,6 +32,8 @@ export type ButtonProps = Omit & { /** @deprecated Use `size="large"` instead. */ large?: boolean; square?: boolean; + /** Lowers the minimum width so a label of one or two characters fits. */ + compact?: boolean; external?: boolean; icon?: IconProps['name']; } & Omit, 'is' | 'className' | 'size'> & @@ -57,6 +61,7 @@ function Button({ medium, large, square, + compact, loading, disabled, children, @@ -99,13 +104,13 @@ function Button({ return ( - {icon && !loading && } - {loading && } + {icon && !loading && } + {loading && } {children} diff --git a/packages/fuselage/src/components/Button/IconButton.spec.tsx b/packages/fuselage/src/components/Button/IconButton.spec.tsx index 2c98460438390..fc24df00b9225 100644 --- a/packages/fuselage/src/components/Button/IconButton.spec.tsx +++ b/packages/fuselage/src/components/Button/IconButton.spec.tsx @@ -37,4 +37,28 @@ describe('[IconButton Component]', () => { expect(screen.getByRole('button', { name: 'balloon, 2 unread messages' })).toBeInTheDocument(); expect(container.querySelector('.rcx-button__badge')).toHaveAttribute('aria-hidden', 'true'); }); + + it('should pin the badge to the bottom end corner', () => { + const { container } = render(2} />); + expect(container.querySelector('.rcx-button__badge')).toHaveClass('rcx-button__badge--bottom-end'); + }); + + it('should render a button of type button by default', () => { + render(); + expect(screen.getByRole('button', { name: 'balloon' })).toHaveAttribute('type', 'button'); + }); + + it('should render a link without a type when is is a', () => { + render(); + const link = screen.getByRole('link', { name: 'balloon' }); + expect(link).not.toHaveAttribute('type'); + expect(link).not.toHaveAttribute('target'); + }); + + it('should open an external link in a new tab without access to the opener', () => { + render(); + const link = screen.getByRole('link', { name: 'balloon' }); + expect(link).toHaveAttribute('target', '_blank'); + expect(link).toHaveAttribute('rel', 'noopener noreferrer'); + }); }); diff --git a/packages/fuselage/src/components/Button/IconButton.stories.tsx b/packages/fuselage/src/components/Button/IconButton.stories.tsx index 79bce84e80627..21b3d678728a6 100644 --- a/packages/fuselage/src/components/Button/IconButton.stories.tsx +++ b/packages/fuselage/src/components/Button/IconButton.stories.tsx @@ -36,6 +36,12 @@ export default { 'What to pin to the button’s corner, a `Badge` as a rule. It is hidden from assistive technology, so what it says belongs in `aria-label` too.', table: { category: 'Content' }, }, + badgePosition: { + control: 'inline-radio', + options: ['top-end', 'bottom-end'], + description: 'The corner the badge is pinned to.', + table: { category: 'Content', defaultValue: { summary: 'top-end' } }, + }, primary: { control: 'boolean', description: 'Solid, high-emphasis color kind.', @@ -331,6 +337,15 @@ export const _IconButtonSecondaryDanger: Story = { }, }; +export const Colors: Story = { + render: () => ( + + + + + ), +}; + export const _IconButtonWithBadge: Story = { render: () => ( @@ -359,3 +374,17 @@ export const _IconButtonWithDot: Story = { ), }; + +export const _IconButtonWithBadgeAtBottom: Story = { + render: () => ( + + } + aria-label='profile, online' + medium + badgePosition='bottom-end' + badge={} + /> + + ), +}; diff --git a/packages/fuselage/src/components/Button/IconButton.tsx b/packages/fuselage/src/components/Button/IconButton.tsx index 2d64bc8f6fcd2..e6d7a182c122a 100644 --- a/packages/fuselage/src/components/Button/IconButton.tsx +++ b/packages/fuselage/src/components/Button/IconButton.tsx @@ -23,6 +23,8 @@ export type IconButtonProps = { * instead, which is the caller's to write. */ badge?: ReactNode; + /** The corner the badge is pinned to. */ + badgePosition?: 'top-end' | 'bottom-end'; primary?: boolean; secondary?: boolean; info?: boolean; @@ -30,8 +32,14 @@ export type IconButtonProps = { warning?: boolean; success?: boolean; pressed?: boolean; + /** Renders a link instead of a button, for actions that navigate or download. */ + is?: 'button' | 'a'; + /** Opens the link in a new tab, without giving it access to this page. */ + external?: boolean; + /** Paints the glyph with a font token, for icon-only actions on light surfaces. */ + color?: 'default' | 'danger'; } & IconButtonSize & - BoxProps; + Omit; const getVariantClass = (variant: string) => { if (variant) { @@ -49,6 +57,7 @@ const getPressedClass = (variant: string) => { function IconButton({ icon, badge, + badgePosition = 'top-end', primary, info, secondary, @@ -61,6 +70,9 @@ function IconButton({ small, medium, pressed, + is = 'button', + external, + color, children, ...props }: IconButtonProps) { @@ -102,8 +114,10 @@ function IconButton({ return ( {isValidElement(icon) ? icon : } {Boolean(badge) && ( -