Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import type { ReactElement, ComponentProps } from 'react';
import type { ComponentProps } from 'react';
import { memo } from 'react';
import { useTranslation } from 'react-i18next';

import ContextualbarAction from './ContextualbarAction';

type ContextualbarBackProps = Partial<ComponentProps<typeof ContextualbarAction>>;

const ContextualbarBack = (props: ContextualbarBackProps): ReactElement => {
const ContextualbarBack = (props: ContextualbarBackProps) => {
const { t } = useTranslation();
return <ContextualbarAction {...props} title={t('Back')} name='arrow-back' />;
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import type { ComponentProps, ReactElement } from 'react';
import type { ComponentProps } from 'react';
import { memo } from 'react';
import { useTranslation } from 'react-i18next';

import ContextualbarAction from './ContextualbarAction';

type ContextualbarCloseProps = Partial<ComponentProps<typeof ContextualbarAction>>;

const ContextualbarClose = (props: ContextualbarCloseProps): ReactElement => {
const ContextualbarClose = (props: ContextualbarCloseProps) => {
const { t } = useTranslation();
return <ContextualbarAction data-qa='ContextualbarActionClose' {...props} aria-label={t('Close')} name='cross' />;
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Box } from '@rocket.chat/fuselage';
import type { ReactElement, ComponentProps } from 'react';
import type { ComponentProps } from 'react';
import { memo } from 'react';

const ContextualbarInnerContent = (props: ComponentProps<typeof Box>): ReactElement => (
const ContextualbarInnerContent = (props: ComponentProps<typeof Box>) => (
<Box rcx-vertical-bar--inner-content position='absolute' height='full' display='flex' insetInline={0} {...props} />
);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { Box, Skeleton } from '@rocket.chat/fuselage';
import type { ReactElement } from 'react';

import ContextualbarHeader from './ContextualbarHeader';

const ContextualbarSkeletonBody = (): ReactElement => (
const ContextualbarSkeletonBody = () => (
<>
<ContextualbarHeader>
<Skeleton width='100%' />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { useOverlayScrollbars } from 'overlayscrollbars-react';
import type { HTMLAttributes, ReactElement } from 'react';
import type { HTMLAttributes, ReactNode } from 'react';
import { useEffect, useRef, forwardRef, memo } from 'react';

import type { OverlayScrollbars } from '.';
import BaseScrollbars, { getScrollbarsOptions } from './BaseScrollbars';

type CustomScrollbarsProps = {
children: ReactElement;
children: ReactNode;
overflowX?: boolean;
onScroll?: (args: OverlayScrollbars) => void;
} & Omit<HTMLAttributes<HTMLDivElement>, 'is' | 'onScroll'>;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { useOverlayScrollbars } from 'overlayscrollbars-react';
import type { HTMLAttributes, ReactElement } from 'react';
import type { HTMLAttributes, ReactNode } from 'react';
import { useEffect, memo, forwardRef, useRef } from 'react';

import BaseScrollbars from './BaseScrollbars';

type CustomScrollbarsProps = {
children: ReactElement;
children: ReactNode;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: children was widened to ReactNode, but this component requires an element child for firstElementChild-based initialization; the new type allows inputs that silently break scrollbar setup.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/ui-client/src/components/CustomScrollbars/CustomVirtuaScrollbars.tsx, line 8:

<comment>`children` was widened to `ReactNode`, but this component requires an element child for `firstElementChild`-based initialization; the new type allows inputs that silently break scrollbar setup.</comment>

<file context>
@@ -1,11 +1,11 @@
 
 type CustomScrollbarsProps = {
-	children: ReactElement;
+	children: ReactNode;
 } & Omit<HTMLAttributes<HTMLDivElement>, 'is' | 'onScroll'>;
 
</file context>

} & Omit<HTMLAttributes<HTMLDivElement>, 'is' | 'onScroll'>;

const CustomVirtuaScrollbars = forwardRef<HTMLElement, CustomScrollbarsProps>(function CustomScrollbars({ ...props }, ref) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import BaseScrollbars, { getScrollbarsOptions } from './BaseScrollbars';

type VirtualizedScrollbarsProps = {
overflowX?: boolean;
children: ReactElement;
children: ReactElement<any>;
} & Omit<HTMLAttributes<HTMLDivElement>, 'is'>;

const VirtualizedScrollbars = forwardRef<HTMLElement, VirtualizedScrollbarsProps>(function VirtualizedScrollbars(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Box, TableCell } from '@rocket.chat/fuselage';
import type { ComponentProps, ReactElement } from 'react';
import type { ComponentProps } from 'react';
import { useCallback } from 'react';

import SortIcon from './SortIcon';
Expand All @@ -18,7 +18,7 @@ export const GenericTableHeaderCell = <T extends string = string>({
sort,
onClick,
...props
}: GenericTableHeaderCellProps<T>): ReactElement => {
}: GenericTableHeaderCellProps<T>) => {
const fn = useCallback(() => onClick && sort && onClick(sort), [sort, onClick]);
return (
<TableCell clickable={!!sort} onClick={fn} {...props}>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Box, Skeleton, TableRow, TableCell } from '@rocket.chat/fuselage';
import type { ReactElement } from 'react';

export const GenericTableLoadingRow = ({ cols }: { cols: number }): ReactElement => (
export const GenericTableLoadingRow = ({ cols }: { cols: number }) => (
<TableRow>
<TableCell>
<Box display='flex'>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import type { ReactElement } from 'react';

import { GenericTableLoadingRow } from './GenericTableLoadingRow';

export const GenericTableLoadingTable = ({ headerCells }: { headerCells: number }): ReactElement => (
export const GenericTableLoadingTable = ({ headerCells }: { headerCells: number }) => (
<>
{Array.from({ length: 10 }, (_, i) => (
<GenericTableLoadingRow key={i} cols={headerCells} />
Expand Down
2 changes: 1 addition & 1 deletion packages/ui-client/src/components/Header/HeaderIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Box, Icon } from '@rocket.chat/fuselage';
import type { ComponentPropsWithoutRef, ReactElement } from 'react';
import { isValidElement } from 'react';

type HeaderIconProps = { icon: ReactElement | ComponentPropsWithoutRef<typeof Icon> | null };
type HeaderIconProps = { icon: ReactElement<any> | ComponentPropsWithoutRef<typeof Icon> | null };

const HeaderIcon = ({ icon }: HeaderIconProps) =>
icon && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { ComponentPropsWithoutRef, ReactElement } from 'react';
import { isValidElement } from 'react';

type HeaderIconProps = {
icon: ReactElement | Pick<ComponentPropsWithoutRef<typeof Icon>, 'name' | 'color'> | null;
icon: ReactElement<any> | Pick<ComponentPropsWithoutRef<typeof Icon>, 'name' | 'color'> | null;
};

const HeaderTagIcon = ({ icon }: HeaderIconProps) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { Button } from '@rocket.chat/fuselage';
import type { Keys as IconName } from '@rocket.chat/icons';
import type { ComponentProps, ReactElement, ReactNode } from 'react';
import type { ComponentProps, ReactNode } from 'react';

type InfoPanelActionProps = Omit<ComponentProps<typeof Button>, 'label'> & {
icon?: IconName;
label: ReactNode;
};

const InfoPanelAction = ({ label, icon, ...props }: InfoPanelActionProps): ReactElement => (
const InfoPanelAction = ({ label, icon, ...props }: InfoPanelActionProps) => (
<Button
title={typeof label === 'string' ? label : undefined}
aria-label={typeof label === 'string' ? label : undefined}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ import { useSetModal } from '@rocket.chat/ui-contexts';
import { act, screen, renderHook } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { axe } from 'jest-axe';
import type { ReactElement } from 'react';
import type { ReactNode } from 'react';
import { Suspense } from 'react';

import GenericModal from './GenericModal';
import ModalProviderWithRegion from '../../../providers/ModalProvider/ModalProviderWithRegion';

const renderModal = (modalElement: ReactElement) => {
const renderModal = (modalElement: ReactNode) => {
const {
result: { current: setModal },
} = renderHook(() => useSetModal(), {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ type GenericModalProps = RequiredModalProps & {
children?: ReactNode;
cancelText?: ReactNode;
confirmText?: ReactNode;
title?: string | ReactElement;
icon?: IconName | ReactElement | null;
title?: string | ReactElement<any>;
icon?: IconName | ReactElement<any> | null;
confirmDisabled?: boolean;
confirmLoading?: boolean;
tagline?: ReactNode;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Box, Label, CheckBox } from '@rocket.chat/fuselage';
import { useUserPreference, useTranslation, useEndpoint } from '@rocket.chat/ui-contexts';
import type { ReactElement, ComponentType } from 'react';
import type { ComponentType, ReactNode } from 'react';
import { useId, useState } from 'react';

import type { DontAskAgainList } from '../../../hooks/useDontAskAgain';
Expand All @@ -15,13 +15,10 @@ type DoNotAskAgainProps = {

export type RequiredModalProps = {
onConfirm?: (...args: any) => Promise<void> | void;
dontAskAgain?: ReactElement;
dontAskAgain?: ReactNode;
};

function withDoNotAskAgain<T extends RequiredModalProps>(
// eslint-disable-next-line @typescript-eslint/naming-convention
Component: ComponentType<any>,
) {
function withDoNotAskAgain<T extends RequiredModalProps>(Component: ComponentType<any>) {
type WrappedComponentProps = DoNotAskAgainProps & Omit<T, keyof RequiredModalProps>;
const WrappedComponent = function ({ onConfirm, dontAskAgain, ...props }: WrappedComponentProps) {
const t = useTranslation();
Expand Down
4 changes: 2 additions & 2 deletions packages/ui-client/src/components/Modal/ModalBackdrop.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ const useEscapeKey = (onDismiss: (() => void) | undefined): void => {
}, [onDismiss]);
};

const isAtBackdropChildren = (e: MouseEvent, ref: RefObject<HTMLElement>): boolean => {
const isAtBackdropChildren = (e: MouseEvent, ref: RefObject<HTMLElement | null>): boolean => {
const backdrop = ref.current;
const { parentElement } = e.target as HTMLElement;

return (Boolean(parentElement) && backdrop?.contains(parentElement)) ?? false;
};

const useOutsideClick = (ref: RefObject<HTMLElement>, onDismiss: (() => void) | undefined) => {
const useOutsideClick = (ref: RefObject<HTMLElement | null>, onDismiss: (() => void) | undefined) => {
const hasClicked = useRef<boolean>(false);

const onMouseDown = useCallback(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { mockAppRoot } from '@rocket.chat/mock-providers';
import { useSetModal } from '@rocket.chat/ui-contexts';
import { act, render, screen } from '@testing-library/react';
import type { ForwardedRef, ReactElement } from 'react';
import type { ForwardedRef, ReactNode } from 'react';
import { Suspense, createContext, createRef, forwardRef, useContext, useImperativeHandle } from 'react';

import ModalProvider from './ModalProvider';
Expand All @@ -10,7 +10,7 @@ import GenericModal from '../../components/Modal/GenericModal';
import ModalRegion from '../../components/Modal/ModalRegion';
import { imperativeModal } from '../../helpers/imperativeModal';

const renderWithSuspense = (ui: ReactElement) =>
const renderWithSuspense = (ui: ReactNode) =>
render(ui, {
wrapper: mockAppRoot()
.wrap((children) => <Suspense fallback={null}>{children}</Suspense>)
Expand Down
2 changes: 1 addition & 1 deletion packages/ui-client/src/providers/TooltipProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ type TooltipProviderProps = {
};

const TooltipProvider = ({ children, ownerDocument = window.document }: TooltipProviderProps) => {
const lastAnchor = useRef<HTMLElement>();
const lastAnchor = useRef<HTMLElement>(undefined);
const hasHover = !useMediaQuery('(hover: none)');

const [tooltip, setTooltip] = useDebouncedState<ReactNode>(null, 300);
Expand Down
4 changes: 1 addition & 3 deletions packages/ui-client/src/views/setupWizard/SetupWizardPage.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import type { ReactElement } from 'react';

import { useSetupWizardContext } from './contexts/SetupWizardContext';
import AdminInfoStep from './steps/AdminInfoStep';
import CloudAccountConfirmation from './steps/CloudAccountConfirmation';
import OrganizationInfoStep from './steps/OrganizationInfoStep';
import RegisterServerStep from './steps/RegisterServerStep';

const SetupWizardPage = (): ReactElement => {
const SetupWizardPage = () => {
const { currentStep } = useSetupWizardContext();

switch (currentStep) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import { useBreakpoints } from '@rocket.chat/fuselage-hooks';
import { DarkModeProvider } from '@rocket.chat/layout';
import type { ReactElement } from 'react';

import SetupWizardPage from './SetupWizardPage';
import { useBodyPosition } from './hooks/useBodyPosition';
import { useRouteLock } from './hooks/useRouteLock';
import SetupWizardProvider from './providers/SetupWizardProvider';
import { ModalRegion } from '../../components';

export const SetupWizardRoute = (): ReactElement | null => {
export const SetupWizardRoute = () => {
const locked = useRouteLock();
const breakpoints = useBreakpoints();
const isMobile = !breakpoints.includes('md');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
useTranslation,
} from '@rocket.chat/ui-contexts';
import { useQueryClient } from '@tanstack/react-query';
import type { ReactElement, ContextType } from 'react';
import type { ContextType, ReactNode } from 'react';
import { useCallback, useMemo, useState } from 'react';

import { useInvalidateLicense } from '../../../hooks';
Expand All @@ -37,7 +37,11 @@ const initialData: ContextType<typeof SetupWizardContext>['setupWizardData'] = {

type HandleRegisterServer = (params: { email: string; resend?: boolean }) => Promise<void>;

const SetupWizardProvider = ({ children }: { children: ReactElement }): ReactElement => {
type SetupWizardProviderProps = {
children: ReactNode;
};

const SetupWizardProvider = ({ children }: SetupWizardProviderProps) => {
const invalidateLicenseQuery = useInvalidateLicense();
const t = useTranslation();
const [setupWizardData, setSetupWizardData] = useState<ContextType<typeof SetupWizardContext>['setupWizardData']>(initialData);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { AdminInfoPage } from '@rocket.chat/onboarding-ui';
import { escapeRegExp } from '@rocket.chat/string-helpers';
import { useSetting, useVerifyPassword, usePasswordPolicy, usePasswordPolicyOptions } from '@rocket.chat/ui-contexts';
import type { ReactElement, ComponentProps } from 'react';
import type { ComponentProps } from 'react';
import { useMemo } from 'react';
import { I18nextProvider, useTranslation } from 'react-i18next';

Expand All @@ -12,9 +12,9 @@ const usernameBlackList = ['all', 'here', 'admin'].map(toRegExp);
const hasBlockedName = (username: string): boolean =>
!!usernameBlackList.length && usernameBlackList.some((restrictedUsername) => restrictedUsername.test(escapeRegExp(username).trim()));

const AdminInfoStep = (): ReactElement => {
const AdminInfoStep = () => {
const { t, i18n } = useTranslation();
const regexpForUsernameValidation = useSetting('UTF8_User_Names_Validation');
const regexpForUsernameValidation = useSetting('UTF8_User_Names_Validation', '[0-9a-zA-Z-_.]+');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if UTF8_User_Names_Validation setting is guaranteed to exist
rg -n -C3 "UTF8_User_Names_Validation" --type ts --type js -g '!*.spec.*' -g '!*.test.*'

Repository: RocketChat/Rocket.Chat

Length of output: 7672


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Inspect the relevant part of AdminInfoStep.tsx
echo "=== AdminInfoStep.tsx (context around useSetting) ==="
sed -n '1,120p' packages/ui-client/src/views/setupWizard/steps/AdminInfoStep.tsx

# 2) Find the useSetting hook definition and inspect its signature (to see if fallback is supported/expected)
echo "=== Searching for useSetting implementation/signature ==="
fd -t f -e ts -e tsx -e js -e jsx -e d.ts "useSetting" packages/ui-client/src | head -n 50

# Also search globally for the hook definition
rg -n "function useSetting|const useSetting|export (function|const) useSetting" packages/ui-client/src --hidden

# 3) Check other UI usages of useSetting with a fallback for UTF8_User_Names_Validation
echo "=== Other useSetting('UTF8_User_Names_Validation', ...) usages in ui-client ==="
rg -n "useSetting\('UTF8_User_Names_Validation'" packages/ui-client/src

# 4) If available, compare the setting default on the server side (already partially found, but re-show the exact add)
echo "=== Server setting default for UTF8_User_Names_Validation ==="
rg -n "add\\('UTF8_User_Names_Validation'" apps/meteor/server/settings/general.ts

Repository: RocketChat/Rocket.Chat

Length of output: 3106


🏁 Script executed:

#!/bin/bash
set -uo pipefail

echo "=== Searching for useSetting definition/signature across repo ==="
rg -n --hidden --no-ignore-vcs \
  "export (const|function) useSetting|function useSetting|const useSetting" . \
  --glob '!**/node_modules/**' --glob '!**/dist/**' --glob '!**/build/**' | head -n 50

echo "=== Searching for useSetting type declaration (d.ts) ==="
fd -e d.ts -e ts -e tsx --hidden useSetting . 2>/dev/null | head -n 50

# Find any d.ts files that mention UTF8_User_Names_Validation defaults/fallback
rg -n --hidden --no-ignore-vcs "useSetting\\(.*UTF8_User_Names_Validation" . \
  --glob '!**/node_modules/**' --glob '!**/dist/**' --glob '!**/build/**' | head -n 50

Repository: RocketChat/Rocket.Chat

Length of output: 3450


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== packages/ui-contexts/src/hooks/useSetting.ts ==="
sed -n '1,200p' packages/ui-contexts/src/hooks/useSetting.ts

echo "=== Server default for UTF8_User_Names_Validation ==="
sed -n '240,310p' apps/meteor/server/settings/general.ts

echo "=== Server validateUsername fallback behavior ==="
sed -n '1,120p' apps/meteor/app/lib/server/functions/validateUsername.ts

echo "=== Other ui-client usages of fallback for UTF8_User_Names_Validation ==="
for f in \
  apps/meteor/client/views/room/contextualBar/Threads/hooks/useNormalizedThreadTitleHtml.ts \
  apps/meteor/client/views/root/hooks/loggedIn/useE2EEncryption.ts \
  apps/meteor/client/views/account/profile/useAccountProfileSettings.ts
do
  echo "---- $f ----"
  sed -n '1,80p' "$f"
done

Repository: RocketChat/Rocket.Chat

Length of output: 8885


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== packages/ui-contexts/src/hooks/useSettingStructure.ts ==="
sed -n '1,200p' packages/ui-contexts/src/hooks/useSettingStructure.ts

echo "=== packages/ui-contexts/src/hooks/useSettings.ts ==="
sed -n '1,200p' packages/ui-contexts/src/hooks/useSettings.ts

echo "=== packages/ui-contexts/src/hooks/useSettingSetValue.ts ==="
sed -n '1,120p' packages/ui-contexts/src/hooks/useSettingSetValue.ts

echo "=== Search for SettingsContext default/initial state ==="
rg -n "SettingsContext|createContext" packages/ui-contexts/src --hidden

# show the SettingsContext provider if it exists
fd -t f -e ts -e tsx "SettingsContext" packages/ui-contexts/src --hidden | head -n 20

Repository: RocketChat/Rocket.Chat

Length of output: 7717


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== packages/ui-contexts/src/SettingsContext.ts ==="
sed -n '1,120p' packages/ui-contexts/src/SettingsContext.ts

echo "=== Inspect SettingsContextValue/querySetting behavior ==="
sed -n '120,260p' packages/ui-contexts/src/SettingsContext.ts

Repository: RocketChat/Rocket.Chat

Length of output: 1275


🏁 Script executed:

#!/bin/bash
# Find any UI usages of UTF8_User_Names_Validation without a fallback
rg -n --hidden "useSetting\\('UTF8_User_Names_Validation'\\)" --type ts --type tsx packages/ui-client/src apps/meteor/client/views -g '!*.spec.*' -g '!*.test.*'

Repository: RocketChat/Rocket.Chat

Length of output: 94


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== UI usages of useSetting('UTF8_User_Names_Validation') without fallback ==="
rg -n --hidden --no-ignore-vcs \
  "useSetting\\(['\"]UTF8_User_Names_Validation['\"]\\)" \
  packages/ui-client apps/meteor/client \
  -g '!*.spec.*' -g '!*.test.*'

echo "=== UI usages of useSetting('UTF8_User_Names_Validation', ... ) ==="
rg -n --hidden --no-ignore-vcs \
  "useSetting\\(['\"]UTF8_User_Names_Validation['\"],\\s*[^\\)]+" \
  packages/ui-client apps/meteor/client \
  -g '!*.spec.*' -g '!*.test.*'

Repository: RocketChat/Rocket.Chat

Length of output: 145


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== UI usages of useSetting('UTF8_User_Names_Validation') ==="
rg -n --hidden --no-ignore-vcs \
  "useSetting\\(['\"]UTF8_User_Names_Validation['\"]\\)" \
  packages/ui-client apps/meteor/client \
  -g '!*.spec.*' -g '!*.test.*' || true

echo "=== UI usages of useSetting('UTF8_User_Names_Validation', <fallback>) ==="
rg -n --hidden --no-ignore-vcs \
  "useSetting\\(['\"]UTF8_User_Names_Validation['\"],\\s*[^\\)]+\\)" \
  packages/ui-client apps/meteor/client \
  -g '!*.spec.*' -g '!*.test.*' || true

Repository: RocketChat/Rocket.Chat

Length of output: 846


Clarify impact of adding useSetting fallback for UTF8_User_Names_Validation

useSetting already supports the provided fallback, so this doesn’t look like a crash fix at new RegExp(...). Instead, it changes the temporary username-validation behavior during SettingsContext loading: without the fallback, the interpolated value could be undefined (yielding an incorrect ^undefined$ regex) until the setting arrives; with the fallback it uses [0-9a-zA-Z-_.]+.

This fallback pattern is already used in other client code (useNormalizedThreadTitleHtml, useE2EEncryption, useAccountProfileSettings), so confirm the PR description’s “no runtime behavior changes expected” wording accounts for this initial-load validation semantics.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/ui-client/src/views/setupWizard/steps/AdminInfoStep.tsx` at line 17,
The change adds a fallback value to useSetting in the
regexpForUsernameValidation declaration which alters initial-load validation
behavior (uses '[0-9a-zA-Z-_.]+' until settings arrive) rather than fixing a new
RegExp crash; either remove the fallback from
useSetting('UTF8_User_Names_Validation', ...) to preserve the previous temporary
behavior, or update the PR description to explicitly state this semantic change
for initial SettingsContext loading and cite that other hooks
(useNormalizedThreadTitleHtml, useE2EEncryption, useAccountProfileSettings)
already follow this pattern so reviewers understand the impact on temporary
username validation.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Adding a fallback value to useSetting changes runtime behavior, contradicting PR description claims of "no runtime behavior changes." Previously the fallback was implicitly undefined; now it's '[0-9a-zA-Z-_.]+'. If intended as a pre-existing bugfix, the PR description/scope should be updated to reflect the runtime impact.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/ui-client/src/views/setupWizard/steps/AdminInfoStep.tsx, line 17:

<comment>Adding a fallback value to `useSetting` changes runtime behavior, contradicting PR description claims of "no runtime behavior changes." Previously the fallback was implicitly `undefined`; now it's `'[0-9a-zA-Z-_.]+'`. If intended as a pre-existing bugfix, the PR description/scope should be updated to reflect the runtime impact.</comment>

<file context>
@@ -12,9 +12,9 @@ const usernameBlackList = ['all', 'here', 'admin'].map(toRegExp);
+const AdminInfoStep = () => {
 	const { t, i18n } = useTranslation();
-	const regexpForUsernameValidation = useSetting('UTF8_User_Names_Validation');
+	const regexpForUsernameValidation = useSetting('UTF8_User_Names_Validation', '[0-9a-zA-Z-_.]+');
 	const usernameRegExp = new RegExp(`^${regexpForUsernameValidation}$`);
 
</file context>

const usernameRegExp = new RegExp(`^${regexpForUsernameValidation}$`);

const { currentStep, validateEmail, registerAdminUser, maxSteps } = useSetupWizardContext();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import { AwaitingConfirmationPage } from '@rocket.chat/onboarding-ui';
import { useToastMessageDispatch, useSettingSetValue, useEndpoint } from '@rocket.chat/ui-contexts';
import type { ReactElement } from 'react';
import { useEffect, useCallback } from 'react';
import { I18nextProvider, useTranslation } from 'react-i18next';

import { useSetupWizardContext } from '../contexts/SetupWizardContext';

const setIntervalTime = (interval?: number): number => (interval ? interval * 1000 : 0);

const CloudAccountConfirmation = (): ReactElement => {
const CloudAccountConfirmation = () => {
const {
registerServer,
currentStep,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { OrganizationInfoPage } from '@rocket.chat/onboarding-ui';
import type { TranslationKey } from '@rocket.chat/ui-contexts';
import { useRole } from '@rocket.chat/ui-contexts';
import type { TFunction } from 'i18next';
import type { ComponentProps, ReactElement } from 'react';
import type { ComponentProps } from 'react';
import { I18nextProvider, useTranslation } from 'react-i18next';

import { useSetupWizardContext } from '../contexts/SetupWizardContext';
Expand All @@ -26,7 +26,7 @@ const getSettingOptions = (
return setting.values.map(({ i18nLabel, key }) => [String(key), t(i18nLabel as TranslationKey)]);
};

const OrganizationInfoStep = (): ReactElement => {
const OrganizationInfoStep = () => {
const { t, i18n } = useTranslation();
const hasAdminRole = useRole('admin');

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { RegisterServerPage, RegisterOfflinePage } from '@rocket.chat/onboarding-ui';
import { useEndpoint, useMethod, useToastMessageDispatch } from '@rocket.chat/ui-contexts';
import { useMutation, useQuery } from '@tanstack/react-query';
import type { ReactElement, ComponentProps } from 'react';
import type { ComponentProps } from 'react';
import { useState } from 'react';
import { I18nextProvider, useTranslation } from 'react-i18next';

Expand All @@ -14,7 +14,7 @@ const SERVER_OPTIONS = {
OFFLINE: 'OFFLINE',
};

const RegisterServerStep = (): ReactElement => {
const RegisterServerStep = () => {
const { t, i18n } = useTranslation();
const { currentStep, goToNextStep, setSetupWizardData, registerServer, maxSteps, completeSetupWizard, saveAgreementData } =
useSetupWizardContext();
Expand Down
Loading