snapshot of https://github.com/RocketChat/Rocket.Chat.git (develop, 2026-09-16; blobs > 131072B omitted)
Some checks failed
Create issues from TODOs / todos (push) Failing after 3s
Close inactive issues / close-issues (push) Has been cancelled
Deploy GitHub Pages / deploy-preview (push) Has been cancelled
CI / ⚙️ Variables Setup (push) Has been cancelled
CI / ⚙️ Test Guard (push) Has been cancelled
CI / 🚀 Notify external services - draft (push) Has been cancelled
CI / 📦 Build Packages (push) Has been cancelled
CI / 📦 Meteor Build (coverage) (push) Has been cancelled
CI / 📦 Meteor Build (production) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], fips) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Publish Docker Images (ghcr.io) (push) Has been cancelled
CI / 📦 Track Image Sizes (push) Has been cancelled
CI / 🔎 Code Check - Action Lint (push) Has been cancelled
CI / 🔎 Code Check (push) Has been cancelled
CI / 🔨 Test Storybook (push) Has been cancelled
CI / 🔨 Test Unit (push) Has been cancelled
CI / 🔨 Test API (CE) (push) Has been cancelled
CI / 🔨 Test API Livechat (CE) (push) Has been cancelled
CI / 🔨 Test UI (CE) (push) Has been cancelled
CI / 🔨 Test API (EE) (push) Has been cancelled
CI / 🔨 Test API Livechat (EE) (push) Has been cancelled
CI / 🔨 Test API Apps (deno-runtime - EE) (push) Has been cancelled
CI / 🔨 Test UI (EE) (push) Has been cancelled
CI / 🔨 Test API (FIPS) (push) Has been cancelled
CI / 🔨 Test API Livechat (FIPS) (push) Has been cancelled
CI / 🔨 Test UI (FIPS) (push) Has been cancelled
CI / 🔨 Test Federation Matrix (push) Has been cancelled
CI / 📊 Report Coverage (push) Has been cancelled
CI / ✅ Tests Done (push) Has been cancelled
CI / 🚀 Publish build assets (push) Has been cancelled
CI / 🚀 Publish Docker Images (DockerHub) (push) Has been cancelled
CI / 🚀 Notify external services (push) Has been cancelled
CI / Update Version Durability (push) Has been cancelled
Release / Release (push) Has been cancelled
Code scanning - action / CodeQL-Build (push) Failing after 2s
Auto-close duplicate issues / auto-close-duplicates (push) Failing after 1s

This commit is contained in:
upstream-mirror
2026-09-16 01:21:02 +05:00
commit 30810eecd7
10161 changed files with 987110 additions and 0 deletions

View File

@@ -0,0 +1,20 @@
import { useTranslation } from 'react-i18next';
import { GenericResourceUsage, GenericResourceUsageSkeleton } from '../../../components/GenericResourceUsage';
import { useActiveConnections } from '../../hooks/useActiveConnections';
const CustomUserActiveConnections = () => {
const { t } = useTranslation();
const result = useActiveConnections();
if (result.isPending || result.isError) {
return <GenericResourceUsageSkeleton title={t('Active_connections')} />;
}
const { current, max, percentage } = result.data;
return <GenericResourceUsage title={t('Active_connections')} value={current} max={max} percentage={percentage} />;
};
export default CustomUserActiveConnections;

View File

@@ -0,0 +1,28 @@
import { GenericModal } from '@rocket.chat/ui-client';
import { useTranslation } from 'react-i18next';
export type CustomUserStatusDisabledModalProps = { isAdmin: boolean; onConfirm: () => void; onClose: () => void };
const CustomUserStatusDisabledModal = ({ isAdmin, onConfirm, onClose }: CustomUserStatusDisabledModalProps) => {
const { t } = useTranslation();
return isAdmin ? (
<GenericModal
title={t('User_status_disabled_learn_more')}
cancelText={t('Close')}
confirmText={t('Go_to_workspace_settings')}
onConfirm={onConfirm}
onClose={onClose}
onCancel={onClose}
icon={null}
variant='warning'
>
{t('User_status_disabled_learn_more_description')}
</GenericModal>
) : (
<GenericModal title={t('User_status_disabled_learn_more')} confirmText={t('Close')} onConfirm={onConfirm} onClose={onClose} icon={null}>
{t('User_status_disabled_learn_more_description')}
</GenericModal>
);
};
export default CustomUserStatusDisabledModal;

View File

@@ -0,0 +1,143 @@
import type { IUserStatus } from '@rocket.chat/core-typings';
import type { SelectOption } from '@rocket.chat/fuselage';
import { FieldGroup, Button, ButtonGroup, TextInput, Field, FieldLabel, FieldRow, FieldError, Select, Box } from '@rocket.chat/fuselage';
import { GenericModal, ContextualbarScrollableContent, ContextualbarFooter } from '@rocket.chat/ui-client';
import { useSetModal, useRoute, useToastMessageDispatch, useTranslation, useEndpoint } from '@rocket.chat/ui-contexts';
import { useId, useCallback } from 'react';
import { useForm, Controller } from 'react-hook-form';
type CustomUserStatusFormFormData = {
name: string;
statusType: string;
};
export type CustomUserStatusFormProps = {
onClose: () => void;
onReload: () => void;
status?: IUserStatus;
};
const CustomUserStatusForm = ({ onClose, onReload, status }: CustomUserStatusFormProps) => {
const t = useTranslation();
const { _id } = status || {};
const setModal = useSetModal();
const route = useRoute('user-status');
const dispatchToastMessage = useToastMessageDispatch();
const formId = useId();
const {
register,
control,
handleSubmit,
formState: { errors },
} = useForm<CustomUserStatusFormFormData>({
defaultValues: { name: status?.name ?? '', statusType: status?.statusType ?? '' },
mode: 'all',
});
const createStatus = useEndpoint('POST', '/v1/custom-user-status.create');
const updateStatus = useEndpoint('POST', '/v1/custom-user-status.update');
const deleteStatus = useEndpoint('POST', '/v1/custom-user-status.delete');
const handleSave = useCallback(
async (data: CustomUserStatusFormFormData) => {
try {
if (status?._id) {
await updateStatus({ _id: status?._id, ...data });
} else {
await createStatus({ ...data });
}
dispatchToastMessage({
type: 'success',
message: t('Custom_User_Status_Updated_Successfully'),
});
onReload();
route.push({});
} catch (error) {
dispatchToastMessage({ type: 'error', message: error });
}
},
[status?._id, dispatchToastMessage, t, onReload, route, updateStatus, createStatus],
);
const handleDeleteStatus = useCallback(() => {
const handleCancel = (): void => {
setModal(null);
};
const handleDelete = async (): Promise<void> => {
try {
await deleteStatus({ customUserStatusId: status?._id ?? '' });
dispatchToastMessage({ type: 'success', message: t('Custom_User_Status_Has_Been_Deleted') });
onReload();
route.push({});
} catch (error) {
dispatchToastMessage({ type: 'error', message: error });
} finally {
setModal(null);
}
};
setModal(
<GenericModal variant='danger' onConfirm={handleDelete} onCancel={handleCancel} onClose={handleCancel} confirmText={t('Delete')}>
{t('Custom_User_Status_Delete_Warning')}
</GenericModal>,
);
}, [status?._id, route, deleteStatus, dispatchToastMessage, onReload, setModal, t]);
const presenceOptions: SelectOption[] = [
['online', t('Online')],
['busy', t('Busy')],
['away', t('Away')],
['offline', t('Offline')],
];
return (
<>
<ContextualbarScrollableContent>
<FieldGroup id={formId} is='form' onSubmit={handleSubmit(handleSave)}>
<Field>
<FieldLabel>{t('Name')}</FieldLabel>
<FieldRow>
<TextInput {...register('name', { required: t('Required_field', { field: t('Name') }) })} placeholder={t('Name')} />
</FieldRow>
{errors.name && <FieldError>{errors.name.message}</FieldError>}
</Field>
<Field>
<FieldLabel>{t('Presence')}</FieldLabel>
<FieldRow>
<Controller
name='statusType'
control={control}
rules={{ required: t('Required_field', { field: t('Presence') }) }}
render={({ field }) => <Select {...field} placeholder={t('Presence')} options={presenceOptions} />}
/>
</FieldRow>
{errors.statusType && <FieldError>{errors.statusType.message}</FieldError>}
</Field>
</FieldGroup>
</ContextualbarScrollableContent>
<ContextualbarFooter>
<ButtonGroup stretch>
<Button onClick={onClose}>{t('Cancel')}</Button>
<Button form={formId} primary type='submit'>
{t('Save')}
</Button>
</ButtonGroup>
{_id && (
<Box marginBlockStart={8}>
<ButtonGroup stretch>
<Button icon='trash' danger onClick={handleDeleteStatus}>
{t('Delete')}
</Button>
</ButtonGroup>
</Box>
)}
</ContextualbarFooter>
</>
);
};
export default CustomUserStatusForm;

View File

@@ -0,0 +1,56 @@
import type { IUserStatus } from '@rocket.chat/core-typings';
import { Box, 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 CustomUserStatusForm from './CustomUserStatusForm';
import { FormSkeleton } from '../../../components/Skeleton';
export type CustomUserStatusFormWithDataProps = {
_id?: IUserStatus['_id'];
onClose: () => void;
onReload: () => void;
};
const CustomUserStatusFormWithData = ({ _id, onReload, onClose }: CustomUserStatusFormWithDataProps) => {
const { t } = useTranslation();
const query = useMemo(() => ({ _id }), [_id]);
const getCustomUserStatus = useEndpoint('GET', '/v1/custom-user-status.list');
const { data, isPending, error, refetch } = useQuery({
queryKey: ['custom-user-statuses', query],
queryFn: async () => {
const customUserStatus = await getCustomUserStatus(query);
return customUserStatus;
},
});
const handleReload = (): void => {
onReload?.();
refetch?.();
};
if (!_id) {
return <CustomUserStatusForm onReload={handleReload} onClose={onClose} />;
}
if (isPending) {
return <FormSkeleton paddingInline={20} />;
}
if (error || !data || data.count < 1) {
return (
<Box padding={20}>
<Callout type='danger'>{t('Custom_User_Status_Error_Invalid_User_Status')}</Callout>
</Box>
);
}
return <CustomUserStatusForm status={data.statuses[0]} onReload={handleReload} onClose={onClose} />;
};
export default CustomUserStatusFormWithData;

View File

@@ -0,0 +1,97 @@
import { Button, ButtonGroup } from '@rocket.chat/fuselage';
import {
ContextualbarHeader,
ContextualbarClose,
ContextualbarTitle,
ContextualbarDialog,
Page,
PageHeader,
PageContent,
} from '@rocket.chat/ui-client';
import { useRoute, useRouteParameter, usePermission, useTranslation, useSetting } from '@rocket.chat/ui-contexts';
import { useCallback, useRef, useEffect } from 'react';
import CustomUserActiveConnections from './CustomUserActiveConnections';
import CustomUserStatusFormWithData from './CustomUserStatusFormWithData';
import CustomUserStatusService from './CustomUserStatusService';
import CustomUserStatusTable from './CustomUserStatusTable';
import { useIsEnterprise } from '../../../hooks/useIsEnterprise';
import NotAuthorizedPage from '../../notAuthorized/NotAuthorizedPage';
const CustomUserStatusRoute = () => {
const t = useTranslation();
const route = useRoute('user-status');
const context = useRouteParameter('context');
const id = useRouteParameter('id');
const canManageUserStatus = usePermission('manage-user-status');
const { data: license } = useIsEnterprise();
const presenceDisabled = useSetting('Presence_broadcast_disabled', false);
useEffect(() => {
presenceDisabled && route.push({ context: 'presence-service' });
}, [presenceDisabled, route]);
const handleItemClick = (id: string): void => {
route.push({
context: 'edit',
id,
});
};
const handleNewButtonClick = useCallback(() => {
route.push({ context: 'new' });
}, [route]);
const handlePresenceServiceClick = useCallback(() => {
route.push({ context: 'presence-service' });
}, [route]);
const handleClose = useCallback(() => {
route.push({});
}, [route]);
const reload = useRef(() => null);
const handleReload = useCallback(() => {
reload.current();
}, [reload]);
if (!canManageUserStatus) {
return <NotAuthorizedPage />;
}
return (
<Page flexDirection='row'>
<Page name='admin-user-status'>
<PageHeader title={t('User_Status')}>
{!license?.isEnterprise && <CustomUserActiveConnections />}
<ButtonGroup>
<Button onClick={handlePresenceServiceClick}>{t('Presence_service')}</Button>
<Button onClick={handleNewButtonClick}>{t('New_custom_status')}</Button>
</ButtonGroup>
</PageHeader>
<PageContent>
<CustomUserStatusTable reload={reload} onClick={handleItemClick} />
</PageContent>
</Page>
{context && (
<ContextualbarDialog onClose={handleClose}>
<ContextualbarHeader>
<ContextualbarTitle>
{context === 'edit' && t('Custom_User_Status_Edit')}
{context === 'new' && t('Custom_User_Status_Add')}
{context === 'presence-service' && t('Presence_service_cap')}
</ContextualbarTitle>
<ContextualbarClose onClick={handleClose} />
</ContextualbarHeader>
{context === 'presence-service' && <CustomUserStatusService />}
{(context === 'new' || context === 'edit') && (
<CustomUserStatusFormWithData _id={id} onClose={handleClose} onReload={handleReload} />
)}
</ContextualbarDialog>
)}
</Page>
);
};
export default CustomUserStatusRoute;

View File

@@ -0,0 +1,124 @@
import {
Box,
Button,
ButtonGroup,
Callout,
Margins,
ProgressBar,
Skeleton,
StatesAction,
StatesIcon,
StatesSubtitle,
ToggleSwitch,
} from '@rocket.chat/fuselage';
import { ContextualbarContent, ContextualbarFooter } from '@rocket.chat/ui-client';
import { useEndpoint, useSetting } from '@rocket.chat/ui-contexts';
import { useMutation } from '@tanstack/react-query';
import { Trans, useTranslation } from 'react-i18next';
import { useIsEnterprise } from '../../../hooks/useIsEnterprise';
import { links } from '../../../lib/links';
import { useActiveConnections } from '../../hooks/useActiveConnections';
const CustomUserStatusService = () => {
const { t } = useTranslation();
const result = useActiveConnections();
const presenceDisabled = useSetting('Presence_broadcast_disabled', false);
const togglePresenceServiceEndpoint = useEndpoint('POST', '/v1/presence.enableBroadcast');
const disablePresenceService = useMutation({
mutationFn: () => togglePresenceServiceEndpoint(),
});
const { data: license, isPending: licenseIsLoading } = useIsEnterprise();
if (result.isPending || disablePresenceService.isPending || licenseIsLoading) {
return (
<Box paddingInline={16} paddingBlock={8}>
<Skeleton />
<Skeleton />
<Skeleton />
<Skeleton />
<Skeleton />
</Box>
);
}
if (result.isError || disablePresenceService.isError) {
return (
<Box display='flex' flexDirection='column' alignItems='center' paddingBlock={20} color='default'>
<StatesIcon name='circle-exclamation' />
<StatesSubtitle>{t('Unable_to_load_active_connections')}</StatesSubtitle>
<StatesAction icon='reload' onClick={() => result.refetch()}>
{t('Retry')}
</StatesAction>
</Box>
);
}
const { current, max, percentage } = result.data;
return (
<>
<ContextualbarContent display='flex' flexDirection='column' justifyContent='space-between' color='default'>
<div>
<Box display='flex' justifyContent='space-between' marginBlock={16}>
<Box fontScale='p1'>{t('Service_status')}</Box>
<ToggleSwitch
disabled={disablePresenceService.isPending || !presenceDisabled || percentage === 100}
checked={!presenceDisabled}
onChange={() => disablePresenceService.mutate()}
/>
</Box>
<Box display='flex' fontScale='c1' justifyContent='space-between' marginBlock={16}>
<Box>{t('Active_connections')}</Box>
<Box>{license?.isEnterprise ? current : `${current}/${max}`}</Box>
</Box>
{!license?.isEnterprise && <ProgressBar percentage={percentage} variant={percentage > 80 ? 'danger' : 'success'} />}
{presenceDisabled && (
<Margins block={16}>
<Callout type='danger' title={t('Service_disabled')}>
{t('Service_disabled_description')}
</Callout>
</Margins>
)}
</div>
<Box display='flex' flexDirection='column' marginBlock={16}>
{license?.isEnterprise ? (
<>
<Box fontScale='p2' marginBlock={8}>
{t('Premium_cap_description')}
</Box>
<Box fontScale='p2' marginBlock={8}>
<Trans i18nKey='Larger_amounts_of_active_connections'>
For larger amounts of active connections you can consider our
<Box is='a' href={links.scaling} target='_blank' color='info'>
multiple instance solutions
</Box>
.
</Trans>
</Box>
</>
) : (
<>
<Box fontScale='p2' marginBlock={8}>
{t('Community_cap_description')}
</Box>
<Box fontScale='p2' marginBlock={8}>
{t('Premium_cap_description')}
</Box>
</>
)}
</Box>
</ContextualbarContent>
{!license?.isEnterprise && (
<ContextualbarFooter borderBlockStartWidth='default' borderBlockColor='extra-light'>
<ButtonGroup stretch vertical>
<Button primary width='100%' is='a' href={links.enterprise} target='_blank'>
{t('More_about_Premium_plans')}
</Button>
</ButtonGroup>
</ContextualbarFooter>
)}
</>
);
};
export default CustomUserStatusService;

View File

@@ -0,0 +1,31 @@
import type { IUserStatus } from '@rocket.chat/core-typings';
import { GenericTableRow, GenericTableCell } from '@rocket.chat/ui-client';
import type { CSSProperties } from 'react';
import { useTranslation } from 'react-i18next';
import MarkdownText from '../../../../components/MarkdownText';
const style: CSSProperties = { whiteSpace: 'nowrap', textOverflow: 'ellipsis', overflow: 'hidden' };
export type CustomUserStatusRowProps = {
status: IUserStatus;
onClick: (id: string) => void;
};
const CustomUserStatusRow = ({ status, onClick }: CustomUserStatusRowProps) => {
const { _id, name, statusType } = status;
const { t } = useTranslation();
return (
<GenericTableRow key={_id} onKeyDown={() => onClick(_id)} onClick={() => onClick(_id)} tabIndex={0} action>
<GenericTableCell fontScale='p2' color='default' style={style}>
<MarkdownText content={name} parseEmoji={true} variant='inline' />
</GenericTableCell>
<GenericTableCell fontScale='p2' color='default' style={style}>
{t(statusType)}
</GenericTableCell>
</GenericTableRow>
);
};
export default CustomUserStatusRow;

View File

@@ -0,0 +1,114 @@
import { Pagination } from '@rocket.chat/fuselage';
import { useDebouncedValue } from '@rocket.chat/fuselage-hooks';
import { escapeRegExp } from '@rocket.chat/tools';
import {
GenericTable,
GenericTableHeader,
GenericTableHeaderCell,
GenericTableBody,
GenericTableLoadingTable,
usePagination,
useSort,
} from '@rocket.chat/ui-client';
import { useEndpoint } from '@rocket.chat/ui-contexts';
import { useQuery } from '@tanstack/react-query';
import type { MutableRefObject } from 'react';
import { useState, useMemo, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import CustomUserStatusRow from './CustomUserStatusRow';
import FilterByText from '../../../../components/FilterByText';
import GenericNoResult from '../../../../components/GenericNoResults';
export type CustomUserStatusProps = {
reload: MutableRefObject<() => void>;
onClick: (id: string) => void;
};
// TODO: Missing error state
const CustomUserStatus = ({ reload, onClick }: CustomUserStatusProps) => {
const { t } = useTranslation();
const [text, setText] = useState('');
const { current, itemsPerPage, setItemsPerPage: onSetItemsPerPage, setCurrent: onSetCurrent, ...paginationProps } = usePagination();
const { sortBy, sortDirection, setSort } = useSort<'name' | 'statusType'>('name');
const query = useDebouncedValue(
useMemo(
() => ({
name: escapeRegExp(text),
sort: `{ "${sortBy}": ${sortDirection === 'asc' ? 1 : -1} }`,
count: itemsPerPage,
offset: current,
}),
[text, itemsPerPage, current, sortBy, sortDirection],
),
500,
);
const getCustomUserStatus = useEndpoint('GET', '/v1/custom-user-status.list');
const { data, isLoading, refetch, isFetched } = useQuery({
queryKey: ['custom-user-statuses', query],
queryFn: async () => {
const { statuses } = await getCustomUserStatus(query);
return statuses;
},
meta: {
apiErrorToastMessage: true,
},
});
useEffect(() => {
reload.current = refetch;
}, [reload, refetch]);
if (!data) {
return null;
}
return (
<>
<FilterByText value={text} onChange={(event) => setText(event.target.value)} />
{data.length === 0 && <GenericNoResult />}
{data && data.length > 0 && (
<>
<GenericTable>
<GenericTableHeader>
<GenericTableHeaderCell key='name' direction={sortDirection} active={sortBy === 'name'} onClick={setSort} sort='name'>
{t('Name')}
</GenericTableHeaderCell>
<GenericTableHeaderCell
key='presence'
direction={sortDirection}
active={sortBy === 'statusType'}
onClick={setSort}
sort='statusType'
>
{t('Presence')}
</GenericTableHeaderCell>
</GenericTableHeader>
<GenericTableBody>
{isLoading && <GenericTableLoadingTable headerCells={2} />}
{data?.map((status) => (
<CustomUserStatusRow key={status._id} status={status} onClick={onClick} />
))}
</GenericTableBody>
</GenericTable>
{isFetched && (
<Pagination
current={current}
itemsPerPage={itemsPerPage}
count={data.length}
onSetItemsPerPage={onSetItemsPerPage}
onSetCurrent={onSetCurrent}
{...paginationProps}
/>
)}
</>
)}
</>
);
};
export default CustomUserStatus;

View File

@@ -0,0 +1 @@
export { default } from './CustomUserStatusTable';

View File

@@ -0,0 +1,21 @@
import { useStableCallback } from '@rocket.chat/fuselage-hooks';
import { useRole, useRoute, useSetModal } from '@rocket.chat/ui-contexts';
import CustomUserStatusDisabledModal from '../CustomUserStatusDisabledModal';
export const useStatusDisabledModal = () => {
const userStatusRoute = useRoute('user-status');
const setModal = useSetModal();
const closeModal = useStableCallback(() => setModal());
const handleGoToSettings = useStableCallback(() => {
userStatusRoute.push({ context: 'presence-service' });
closeModal();
});
const isAdmin = useRole('admin');
const handleSetModal = () => {
setModal(<CustomUserStatusDisabledModal isAdmin={isAdmin} onConfirm={handleGoToSettings} onClose={closeModal} />);
};
return handleSetModal;
};