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
Auto-close duplicate issues / auto-close-duplicates (push) Failing after 1s
Code scanning - action / CodeQL-Build (push) Failing after 1s
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
Auto-close duplicate issues / auto-close-duplicates (push) Failing after 1s
Code scanning - action / CodeQL-Build (push) Failing after 1s
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
import { PaginatedSelectFiltered } from '@rocket.chat/fuselage';
|
||||
import { useDebouncedValue, useStableCallback } from '@rocket.chat/fuselage-hooks';
|
||||
import type { ComponentProps } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import type { UnitOption } from '../hooks/useUnitsList';
|
||||
import { useUnitsList } from '../hooks/useUnitsList';
|
||||
|
||||
export type AutoCompleteUnitProps = Omit<
|
||||
ComponentProps<typeof PaginatedSelectFiltered>,
|
||||
'filter' | 'setFilter' | 'options' | 'endReached' | 'renderItem'
|
||||
> & {
|
||||
haveNone?: boolean;
|
||||
value: string | undefined;
|
||||
onChange: (value: string) => void;
|
||||
onLoadItems?: (list: UnitOption[]) => void;
|
||||
};
|
||||
|
||||
const AutoCompleteUnit = ({
|
||||
id,
|
||||
value,
|
||||
disabled = false,
|
||||
error,
|
||||
placeholder,
|
||||
haveNone,
|
||||
onChange,
|
||||
onLoadItems = () => undefined,
|
||||
}: AutoCompleteUnitProps) => {
|
||||
const { t } = useTranslation();
|
||||
const [unitsFilter, setUnitsFilter] = useState<string>('');
|
||||
|
||||
const debouncedUnitFilter = useDebouncedValue(unitsFilter, 500);
|
||||
|
||||
const { data: unitsList, fetchNextPage } = useUnitsList({ filter: debouncedUnitFilter, haveNone });
|
||||
|
||||
const handleLoadItems = useStableCallback(onLoadItems);
|
||||
|
||||
useEffect(() => {
|
||||
handleLoadItems(unitsList);
|
||||
}, [handleLoadItems, unitsList]);
|
||||
|
||||
return (
|
||||
<PaginatedSelectFiltered
|
||||
id={id}
|
||||
aria-label={t('Unit')} // FIXME: remove this when PaginatedSelectFiltered properly associates the input with the label htmlFor
|
||||
error={error}
|
||||
filter={unitsFilter}
|
||||
flexGrow={0}
|
||||
flexShrink={0}
|
||||
disabled={disabled}
|
||||
onChange={onChange}
|
||||
options={unitsList}
|
||||
placeholder={placeholder || t('Select_an_option')}
|
||||
setFilter={setUnitsFilter as (value: string | number | undefined) => void}
|
||||
value={value}
|
||||
width='100%'
|
||||
endReached={() => fetchNextPage()}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default AutoCompleteUnit;
|
||||
@@ -0,0 +1,38 @@
|
||||
import { PaginatedMultiSelectFiltered } from '@rocket.chat/fuselage';
|
||||
import { useDebouncedValue } from '@rocket.chat/fuselage-hooks';
|
||||
import type { ComponentProps } from 'react';
|
||||
import { memo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { useUnitsList } from '../hooks/useUnitsList';
|
||||
|
||||
export type AutoCompleteUnitsProps = Omit<
|
||||
ComponentProps<typeof PaginatedMultiSelectFiltered>,
|
||||
'filter' | 'setFilter' | 'options' | 'endReached' | 'renderItem'
|
||||
>;
|
||||
|
||||
const AutoCompleteUnits = ({ value, placeholder, onChange, ...props }: AutoCompleteUnitsProps) => {
|
||||
const { t } = useTranslation();
|
||||
const [unitsFilter, setUnitsFilter] = useState<string>('');
|
||||
const debouncedUnitFilter = useDebouncedValue(unitsFilter, 500);
|
||||
|
||||
const { data: unitItems, fetchNextPage } = useUnitsList({ filter: debouncedUnitFilter });
|
||||
|
||||
return (
|
||||
<PaginatedMultiSelectFiltered
|
||||
{...props}
|
||||
value={value}
|
||||
placeholder={placeholder || t('Select_an_option')}
|
||||
filter={unitsFilter}
|
||||
width='100%'
|
||||
flexShrink={0}
|
||||
flexGrow={0}
|
||||
setFilter={setUnitsFilter as (value: string | number | undefined) => void}
|
||||
options={unitItems}
|
||||
onChange={onChange}
|
||||
endReached={() => fetchNextPage()}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(AutoCompleteUnits);
|
||||
@@ -0,0 +1,30 @@
|
||||
import { Box, Skeleton } from '@rocket.chat/fuselage';
|
||||
import type { StoryObj, Meta } from '@storybook/react';
|
||||
|
||||
import BusinessHoursMultiple from './BusinessHoursMultiple';
|
||||
|
||||
export default {
|
||||
component: BusinessHoursMultiple,
|
||||
parameters: {
|
||||
layout: 'fullscreen',
|
||||
},
|
||||
decorators: [
|
||||
(fn) => (
|
||||
<Box maxWidth='x600' alignSelf='center' width='full' margin={24}>
|
||||
{fn()}
|
||||
</Box>
|
||||
),
|
||||
],
|
||||
} satisfies Meta<typeof BusinessHoursMultiple>;
|
||||
|
||||
export const Default: StoryObj<typeof BusinessHoursMultiple> = {
|
||||
name: 'BusinessHoursMultiple',
|
||||
|
||||
args: {
|
||||
departmentList: [
|
||||
[1, 'Support'],
|
||||
[2, 'Marketing'],
|
||||
[3, <Skeleton width='x100' key={3} />],
|
||||
],
|
||||
} as any,
|
||||
};
|
||||
@@ -0,0 +1,83 @@
|
||||
import { Field, FieldLabel, FieldRow, FieldError, TextInput, ToggleSwitch } from '@rocket.chat/fuselage';
|
||||
import { useId } from 'react';
|
||||
import type { ComponentProps } from 'react';
|
||||
import { Controller, useFormContext } from 'react-hook-form';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { useHasLicenseModule } from '../../../hooks/useHasLicenseModule';
|
||||
import type { BusinessHoursFormData } from '../businessHours/BusinessHoursForm';
|
||||
import AutoCompleteDepartmentMultiple from '../components/AutoCompleteDepartmentMultiple';
|
||||
|
||||
export type BusinessHoursMultipleProps = { className?: ComponentProps<typeof Field>['className'] };
|
||||
|
||||
const BusinessHoursMultiple = ({ className }: BusinessHoursMultipleProps) => {
|
||||
const { t } = useTranslation();
|
||||
const {
|
||||
control,
|
||||
formState: { errors },
|
||||
} = useFormContext<BusinessHoursFormData>();
|
||||
const { data: hasLicense = false } = useHasLicenseModule('livechat-enterprise');
|
||||
|
||||
const enabledField = useId();
|
||||
const nameField = useId();
|
||||
const departmentsFieldLabelId = useId();
|
||||
|
||||
if (!hasLicense) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Field className={className}>
|
||||
<FieldRow>
|
||||
<FieldLabel htmlFor={enabledField}>{t('Enabled')}</FieldLabel>
|
||||
<Controller
|
||||
name='active'
|
||||
control={control}
|
||||
render={({ field: { value, ...field } }) => <ToggleSwitch id={enabledField} {...field} checked={value} />}
|
||||
/>
|
||||
</FieldRow>
|
||||
</Field>
|
||||
<Field className={className}>
|
||||
<FieldLabel htmlFor={nameField} required>
|
||||
{t('Name')}
|
||||
</FieldLabel>
|
||||
<FieldRow>
|
||||
<Controller
|
||||
name='name'
|
||||
control={control}
|
||||
rules={{ required: t('Required_field', { field: t('Name') }) }}
|
||||
render={({ field }) => <TextInput id={nameField} {...field} aria-describedby={`${nameField}-error`} />}
|
||||
/>
|
||||
</FieldRow>
|
||||
{errors?.name && (
|
||||
<FieldError aria-live='assertive' id={`${nameField}-error`}>
|
||||
{errors.name.message}
|
||||
</FieldError>
|
||||
)}
|
||||
</Field>
|
||||
<Field className={className}>
|
||||
<FieldLabel id={departmentsFieldLabelId}>{t('Departments')}</FieldLabel>
|
||||
<FieldRow>
|
||||
<Controller
|
||||
name='departments'
|
||||
control={control}
|
||||
render={({ field: { value, onChange, name, onBlur } }) => (
|
||||
<AutoCompleteDepartmentMultiple
|
||||
withCheckbox
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
name={name}
|
||||
onBlur={onBlur}
|
||||
enabled={true}
|
||||
aria-labelledby={departmentsFieldLabelId}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</FieldRow>
|
||||
</Field>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default BusinessHoursMultiple;
|
||||
@@ -0,0 +1,27 @@
|
||||
import { useHasLicenseModule } from '../../../hooks/useHasLicenseModule';
|
||||
import AutoCompleteAgent from '../components/AutoCompleteAgent';
|
||||
|
||||
export type ContactManagerInputProps = {
|
||||
value: string;
|
||||
onChange: (currentValue: string) => void;
|
||||
};
|
||||
|
||||
const ContactManagerInput = ({ value: userId, onChange }: ContactManagerInputProps) => {
|
||||
const { data: hasLicense = false } = useHasLicenseModule('livechat-enterprise');
|
||||
|
||||
if (!hasLicense) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const handleChange = (currentValue: string) => {
|
||||
if (currentValue === 'no-agent-selected') {
|
||||
return onChange('');
|
||||
}
|
||||
|
||||
onChange(currentValue);
|
||||
};
|
||||
|
||||
return <AutoCompleteAgent haveNoAgentsSelectedOption value={userId} onChange={handleChange} />;
|
||||
};
|
||||
|
||||
export default ContactManagerInput;
|
||||
@@ -0,0 +1,23 @@
|
||||
import type { ComponentProps } from 'react';
|
||||
|
||||
import { useHasLicenseModule } from '../../../hooks/useHasLicenseModule';
|
||||
import AutoCompleteTagsMultiple from '../tags/AutoCompleteTagsMultiple';
|
||||
|
||||
export type CurrentChatTagsProps = Pick<ComponentProps<typeof AutoCompleteTagsMultiple>, 'id' | 'aria-labelledby'> & {
|
||||
value: NonNullable<ComponentProps<typeof AutoCompleteTagsMultiple>['value']>;
|
||||
handler: NonNullable<ComponentProps<typeof AutoCompleteTagsMultiple>['onChange']>;
|
||||
department?: string;
|
||||
viewAll?: boolean;
|
||||
};
|
||||
|
||||
const CurrentChatTags = ({ value, handler, department, viewAll, ...props }: CurrentChatTagsProps) => {
|
||||
const { data: hasLicense = false } = useHasLicenseModule('livechat-enterprise');
|
||||
|
||||
if (!hasLicense) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return <AutoCompleteTagsMultiple {...props} onChange={handler} value={value} department={department} viewAll={viewAll} />;
|
||||
};
|
||||
|
||||
export default CurrentChatTags;
|
||||
@@ -0,0 +1,118 @@
|
||||
import type { SelectOption } from '@rocket.chat/fuselage';
|
||||
import { Field, FieldLabel, FieldRow, FieldError, FieldHint, ToggleSwitch, TextInput, Select } from '@rocket.chat/fuselage';
|
||||
import type { ComponentProps } from 'react';
|
||||
import { useId, useMemo } from 'react';
|
||||
import { useFormContext, Controller } from 'react-hook-form';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { useHasLicenseModule } from '../../../hooks/useHasLicenseModule';
|
||||
import type { EditCustomFieldsFormData } from '../customFields/EditCustomFields';
|
||||
|
||||
const checkIsOptionsValid = (value: string) => {
|
||||
if (!value || value.trim() === '') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return value.split(',').every((v) => /^[a-zA-Z0-9-_ ]+$/.test(v));
|
||||
};
|
||||
|
||||
export type CustomFieldsAdditionalFormProps = { className?: ComponentProps<typeof Field>['className'] };
|
||||
|
||||
const CustomFieldsAdditionalForm = ({ className }: CustomFieldsAdditionalFormProps) => {
|
||||
const { t } = useTranslation();
|
||||
const {
|
||||
control,
|
||||
watch,
|
||||
formState: { errors },
|
||||
} = useFormContext<EditCustomFieldsFormData>();
|
||||
const { data: hasLicense = false } = useHasLicenseModule('livechat-enterprise');
|
||||
|
||||
const { visibility, type } = watch();
|
||||
|
||||
const typeOptions: SelectOption[] = useMemo(
|
||||
() => [
|
||||
['input', t('Input')],
|
||||
['select', t('Select')],
|
||||
],
|
||||
[t],
|
||||
);
|
||||
|
||||
const requiredField = useId();
|
||||
const typeField = useId();
|
||||
const defaultValueField = useId();
|
||||
const optionsField = useId();
|
||||
const publicField = useId();
|
||||
|
||||
if (!hasLicense) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Field className={className}>
|
||||
<FieldRow>
|
||||
<FieldLabel htmlFor={requiredField}>{t('Required')}</FieldLabel>
|
||||
<Controller
|
||||
name='required'
|
||||
control={control}
|
||||
render={({ field: { value, ...field } }) => <ToggleSwitch id={requiredField} {...field} checked={value} />}
|
||||
/>
|
||||
</FieldRow>
|
||||
</Field>
|
||||
<Field className={className}>
|
||||
<FieldLabel htmlFor={typeField}>{t('Type')}</FieldLabel>
|
||||
<FieldRow>
|
||||
<Controller name='type' control={control} render={({ field }) => <Select id={typeField} options={typeOptions} {...field} />} />
|
||||
</FieldRow>
|
||||
</Field>
|
||||
<Field className={className}>
|
||||
<FieldLabel htmlFor={defaultValueField}>{t('Default_value')}</FieldLabel>
|
||||
<FieldRow>
|
||||
<Controller name='defaultValue' control={control} render={({ field }) => <TextInput id={defaultValueField} {...field} />} />
|
||||
</FieldRow>
|
||||
</Field>
|
||||
<Field className={className}>
|
||||
<FieldLabel htmlFor={optionsField}>{t('Options')}</FieldLabel>
|
||||
<FieldRow>
|
||||
<Controller
|
||||
name='options'
|
||||
control={control}
|
||||
rules={{
|
||||
validate: (optionsValue) => (type === 'select' && !checkIsOptionsValid(optionsValue) ? t('error-invalid-value') : undefined),
|
||||
}}
|
||||
render={({ field }) => (
|
||||
<TextInput
|
||||
id={optionsField}
|
||||
{...field}
|
||||
disabled={type === 'input'}
|
||||
aria-invalid={Boolean(errors?.options)}
|
||||
aria-describedby={`${optionsField}-hint ${optionsField}-error`}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</FieldRow>
|
||||
<FieldHint id={`${optionsField}-hint`}>{t('Livechat_custom_fields_options_placeholder')}</FieldHint>
|
||||
{errors.options && (
|
||||
<FieldError aria-live='assertive' id={`${optionsField}-error`}>
|
||||
{errors.options.message}
|
||||
</FieldError>
|
||||
)}
|
||||
</Field>
|
||||
<Field className={className}>
|
||||
<FieldRow>
|
||||
<FieldLabel htmlFor={publicField}>{t('Public')}</FieldLabel>
|
||||
<Controller
|
||||
name='public'
|
||||
control={control}
|
||||
render={({ field: { value, ...field } }) => (
|
||||
<ToggleSwitch id={publicField} {...field} disabled={!visibility} checked={value} aria-describedby={`${publicField}-hint`} />
|
||||
)}
|
||||
/>
|
||||
</FieldRow>
|
||||
<FieldHint id={`${publicField}-hint`}>{t('Livechat_custom_fields_public_description')}</FieldHint>
|
||||
</Field>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default CustomFieldsAdditionalForm;
|
||||
@@ -0,0 +1,35 @@
|
||||
import { Field, FieldLabel, FieldRow, TextInput } from '@rocket.chat/fuselage';
|
||||
import { useEndpoint } from '@rocket.chat/ui-contexts';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { useHasLicenseModule } from '../../../hooks/useHasLicenseModule';
|
||||
|
||||
export type DepartmentBusinessHoursProps = { bhId: string | undefined };
|
||||
|
||||
export const DepartmentBusinessHours = ({ bhId }: DepartmentBusinessHoursProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { data: hasLicense = false } = useHasLicenseModule('livechat-enterprise');
|
||||
const getBusinessHour = useEndpoint('GET', '/v1/livechat/business-hour');
|
||||
const { data } = useQuery({
|
||||
queryKey: ['/v1/livechat/business-hour', bhId],
|
||||
queryFn: () => getBusinessHour({ _id: bhId, type: 'custom' }),
|
||||
});
|
||||
|
||||
const name = data?.businessHour?.name;
|
||||
|
||||
if (!hasLicense) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Field>
|
||||
<FieldLabel>{t('Business_Hour')}</FieldLabel>
|
||||
<FieldRow>
|
||||
<TextInput readOnly value={name || ''} />
|
||||
</FieldRow>
|
||||
</Field>
|
||||
);
|
||||
};
|
||||
|
||||
export default DepartmentBusinessHours;
|
||||
@@ -0,0 +1,25 @@
|
||||
import { NumberInput, Field, FieldLabel, FieldRow } from '@rocket.chat/fuselage';
|
||||
import type { ComponentProps } from 'react';
|
||||
|
||||
import { useHasLicenseModule } from '../../../hooks/useHasLicenseModule';
|
||||
|
||||
export type EeNumberInputProps = { label: string } & ComponentProps<typeof NumberInput>;
|
||||
|
||||
export const EeNumberInput = ({ label, ...props }: EeNumberInputProps) => {
|
||||
const { data: hasLicense = false } = useHasLicenseModule('livechat-enterprise');
|
||||
|
||||
if (!hasLicense) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Field>
|
||||
<FieldLabel>{label}</FieldLabel>
|
||||
<FieldRow>
|
||||
<NumberInput {...props} flexGrow={1} />
|
||||
</FieldRow>
|
||||
</Field>
|
||||
);
|
||||
};
|
||||
|
||||
export default EeNumberInput;
|
||||
@@ -0,0 +1,25 @@
|
||||
import { TextAreaInput, Field, FieldLabel, FieldRow } from '@rocket.chat/fuselage';
|
||||
import type { ComponentProps } from 'react';
|
||||
|
||||
import { useHasLicenseModule } from '../../../hooks/useHasLicenseModule';
|
||||
|
||||
export type EeTextAreaInputProps = { label: string } & ComponentProps<typeof TextAreaInput>;
|
||||
|
||||
export const EeTextAreaInput = ({ label, ...props }: EeTextAreaInputProps) => {
|
||||
const { data: hasLicense = false } = useHasLicenseModule('livechat-enterprise');
|
||||
|
||||
if (!hasLicense) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Field>
|
||||
<FieldLabel>{label}</FieldLabel>
|
||||
<FieldRow>
|
||||
<TextAreaInput {...props} />
|
||||
</FieldRow>
|
||||
</Field>
|
||||
);
|
||||
};
|
||||
|
||||
export default EeTextAreaInput;
|
||||
@@ -0,0 +1,25 @@
|
||||
import { TextInput, Field, FieldLabel, FieldRow } from '@rocket.chat/fuselage';
|
||||
import type { ComponentProps } from 'react';
|
||||
|
||||
import { useHasLicenseModule } from '../../../hooks/useHasLicenseModule';
|
||||
|
||||
export type EeTextInputProps = { label: string } & ComponentProps<typeof TextInput>;
|
||||
|
||||
export const EeTextInput = ({ label, ...props }: EeTextInputProps) => {
|
||||
const { data: hasLicense = false } = useHasLicenseModule('livechat-enterprise');
|
||||
|
||||
if (!hasLicense) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Field>
|
||||
<FieldLabel>{label}</FieldLabel>
|
||||
<FieldRow>
|
||||
<TextInput {...props} />
|
||||
</FieldRow>
|
||||
</Field>
|
||||
);
|
||||
};
|
||||
|
||||
export default EeTextInput;
|
||||
@@ -0,0 +1,36 @@
|
||||
import { NumberInput, Field, FieldLabel, FieldRow } from '@rocket.chat/fuselage';
|
||||
import { useId } from 'react';
|
||||
import type { ComponentProps } from 'react';
|
||||
import { useFormContext, Controller } from 'react-hook-form';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { useHasLicenseModule } from '../../../hooks/useHasLicenseModule';
|
||||
|
||||
export type MaxChatsPerAgentProps = { className?: ComponentProps<typeof Field>['className'] };
|
||||
|
||||
const MaxChatsPerAgent = ({ className }: MaxChatsPerAgentProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { control } = useFormContext();
|
||||
const { data: hasLicense = false } = useHasLicenseModule('livechat-enterprise');
|
||||
|
||||
const maxChatsField = useId();
|
||||
|
||||
if (!hasLicense) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Field className={className}>
|
||||
<FieldLabel htmlFor={maxChatsField}>{t('Max_number_of_chats_per_agent')}</FieldLabel>
|
||||
<FieldRow>
|
||||
<Controller
|
||||
name='maxNumberSimultaneousChat'
|
||||
control={control}
|
||||
render={({ field }) => <NumberInput id={maxChatsField} {...field} />}
|
||||
/>
|
||||
</FieldRow>
|
||||
</Field>
|
||||
);
|
||||
};
|
||||
|
||||
export default MaxChatsPerAgent;
|
||||
@@ -0,0 +1,22 @@
|
||||
import { InfoPanelLabel, InfoPanelText } from '@rocket.chat/ui-client';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { useHasLicenseModule } from '../../../hooks/useHasLicenseModule';
|
||||
|
||||
const MaxChatsPerAgentDisplay = ({ maxNumberSimultaneousChat = 0 }) => {
|
||||
const { t } = useTranslation();
|
||||
const { data: hasLicense = false } = useHasLicenseModule('livechat-enterprise');
|
||||
|
||||
if (!hasLicense) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<InfoPanelLabel>{t('Max_number_of_chats_per_agent')}</InfoPanelLabel>
|
||||
<InfoPanelText>{maxNumberSimultaneousChat}</InfoPanelText>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default MaxChatsPerAgentDisplay;
|
||||
@@ -0,0 +1,71 @@
|
||||
import type { ILivechatPriority, Serialized } from '@rocket.chat/core-typings';
|
||||
import { LivechatPriorityWeight } from '@rocket.chat/core-typings';
|
||||
import type { SelectOption } from '@rocket.chat/fuselage';
|
||||
import { Options, Box, Option, Field, FieldLabel, FieldRow, SelectLegacy } from '@rocket.chat/fuselage';
|
||||
import type { TranslationKey } from '@rocket.chat/ui-contexts';
|
||||
import type { ComponentProps } from 'react';
|
||||
import { useCallback, forwardRef, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { useHasLicenseModule } from '../../../hooks/useHasLicenseModule';
|
||||
import { PriorityIcon } from '../priorities/PriorityIcon';
|
||||
|
||||
export type PrioritiesSelectProps = {
|
||||
value: string;
|
||||
label: string;
|
||||
options: Serialized<ILivechatPriority[]>;
|
||||
onChange: (value: string) => void;
|
||||
};
|
||||
|
||||
export const PrioritiesSelect = ({ value = '', label, options, onChange }: PrioritiesSelectProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { data: hasLicense = false } = useHasLicenseModule('livechat-enterprise');
|
||||
const [sorting] = useState<Record<string, LivechatPriorityWeight>>({});
|
||||
|
||||
const formattedOptions = useMemo<SelectOption[]>(() => {
|
||||
const opts: SelectOption[] = options?.map(({ dirty, name, i18n, _id, sortItem }) => {
|
||||
const label = dirty && name ? name : t(i18n as TranslationKey);
|
||||
sorting[_id] = sortItem;
|
||||
return [_id, label];
|
||||
});
|
||||
return [['', t('Unprioritized')], ...opts];
|
||||
}, [options, sorting, t]);
|
||||
|
||||
const renderOption = useCallback(
|
||||
(label: string, value: string) => {
|
||||
return (
|
||||
<>
|
||||
<PriorityIcon level={sorting[value] || LivechatPriorityWeight.NOT_SPECIFIED} showUnprioritized /> {label}
|
||||
</>
|
||||
);
|
||||
},
|
||||
[sorting],
|
||||
);
|
||||
|
||||
// eslint-disable-next-line react/no-multi-comp
|
||||
const renderOptions = forwardRef<HTMLElement, ComponentProps<typeof Options>>(function OptionsWrapper(props, ref) {
|
||||
return <Options ref={ref} {...props} maxHeight={200} />;
|
||||
});
|
||||
|
||||
if (!hasLicense) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Field>
|
||||
<FieldLabel>{label}</FieldLabel>
|
||||
<FieldRow>
|
||||
<SelectLegacy
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
options={formattedOptions}
|
||||
renderOptions={renderOptions}
|
||||
renderSelected={({ label, value }) => <Box flexGrow='1'>{renderOption(label, value)}</Box>}
|
||||
renderItem={({ label, value, ...props }) => <Option {...props} label={renderOption(label, value)} />}
|
||||
/>
|
||||
</FieldRow>
|
||||
</Field>
|
||||
);
|
||||
};
|
||||
|
||||
export default PrioritiesSelect;
|
||||
@@ -0,0 +1,34 @@
|
||||
import type { IOmnichannelServiceLevelAgreements, Serialized } from '@rocket.chat/core-typings';
|
||||
import type { SelectOption } from '@rocket.chat/fuselage';
|
||||
import { Field, FieldLabel, FieldRow, Select } from '@rocket.chat/fuselage';
|
||||
import { useId, useMemo } from 'react';
|
||||
|
||||
import { useHasLicenseModule } from '../../../hooks/useHasLicenseModule';
|
||||
|
||||
export type SlaPoliciesSelectProps = {
|
||||
value: string;
|
||||
label: string;
|
||||
options: Serialized<IOmnichannelServiceLevelAgreements[]>;
|
||||
onChange: (value: string) => void;
|
||||
};
|
||||
|
||||
export const SlaPoliciesSelect = ({ value, label, options, onChange }: SlaPoliciesSelectProps) => {
|
||||
const { data: hasLicense = false } = useHasLicenseModule('livechat-enterprise');
|
||||
const optionsSelect = useMemo<SelectOption[]>(() => options?.map((option) => [option._id, option.name]), [options]);
|
||||
const fieldId = useId();
|
||||
|
||||
if (!hasLicense) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Field>
|
||||
<FieldLabel id={fieldId}>{label}</FieldLabel>
|
||||
<FieldRow>
|
||||
<Select aria-labelledby={fieldId} value={value} options={optionsSelect} onChange={(value) => onChange(String(value))} />
|
||||
</FieldRow>
|
||||
</Field>
|
||||
);
|
||||
};
|
||||
|
||||
export default SlaPoliciesSelect;
|
||||
Reference in New Issue
Block a user