refactor(client): Refactors recent typescript changes for best practices (#763)

* create common types in client

* remove unnecessary rules from eslint config

* cleanup types

* put back eslintrc rules
This commit is contained in:
Dan Orlando 2023-08-05 13:45:26 -07:00 committed by GitHub
parent 5828200197
commit 96d29f7390
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
32 changed files with 233 additions and 245 deletions

View file

@ -45,9 +45,9 @@ module.exports = {
'linebreak-style': 0, 'linebreak-style': 0,
curly: ['error', 'all'], curly: ['error', 'all'],
semi: ['error', 'always'], semi: ['error', 'always'],
'no-trailing-spaces': 'error',
'object-curly-spacing': ['error', 'always'], 'object-curly-spacing': ['error', 'always'],
'no-multiple-empty-lines': ['error', { max: 1 }], 'no-multiple-empty-lines': ['error', { max: 1 }],
'no-trailing-spaces': 'error',
'comma-dangle': ['error', 'always-multiline'], 'comma-dangle': ['error', 'always-multiline'],
// "arrow-parens": [2, "as-needed", { requireForBlockBody: true }], // "arrow-parens": [2, "as-needed", { requireForBlockBody: true }],
// 'no-plusplus': ['error', { allowForLoopAfterthoughts: true }], // 'no-plusplus': ['error', { allowForLoopAfterthoughts: true }],

View file

@ -0,0 +1 @@
export * from './types';

View file

@ -0,0 +1,50 @@
import { TConversation, TPreset } from 'librechat-data-provider';
export type TSetOption = (param: number | string) => (newValue: number | string | boolean) => void;
export type TSetExample = (
i: number,
type: string,
newValue: number | string | boolean | null,
) => void;
export enum ESide {
Top = 'top',
Right = 'right',
Bottom = 'bottom',
Left = 'left',
}
export type TBaseSettingsProps = {
conversation: TConversation | TPreset | null;
className?: string;
isPreset?: boolean;
readonly?: boolean;
};
export type TSettingsProps = TBaseSettingsProps & {
setOption: TSetOption;
};
export type TModels = {
models: string[];
};
export type TModelSelectProps = TSettingsProps & TModels;
export type TEditPresetProps = {
open: boolean;
onOpenChange: React.Dispatch<React.SetStateAction<boolean>>;
preset: TPreset;
title?: string;
};
export type TSetOptionsPayload = {
setOption: TSetOption;
setExample: TSetExample;
addExample: () => void;
removeExample: () => void;
setAgentOption: TSetOption;
getConversation: () => TConversation | TPreset | null;
checkPluginSelection: (value: string) => boolean;
setTools: (newValue: string) => void;
};

View file

@ -1,5 +1,12 @@
import React from 'react'; import React from 'react';
import { PagesProps } from 'librechat-data-provider';
type TPagesProps = {
pages: number;
pageNumber: number;
setPageNumber: (pageNumber: number) => void;
nextPage: () => Promise<void>;
previousPage: () => Promise<void>;
};
export default function Pages({ export default function Pages({
pageNumber, pageNumber,
@ -7,7 +14,7 @@ export default function Pages({
nextPage, nextPage,
previousPage, previousPage,
setPageNumber, setPageNumber,
}: PagesProps) { }: TPagesProps) {
const clickHandler = const clickHandler =
(func: () => Promise<void>) => async (e: React.MouseEvent<HTMLButtonElement>) => { (func: () => Promise<void>) => async (e: React.MouseEvent<HTMLButtonElement>) => {
e.preventDefault(); e.preventDefault();

View file

@ -1,7 +1,8 @@
import exportFromJSON from 'export-from-json'; import exportFromJSON from 'export-from-json';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { useRecoilValue, useRecoilState } from 'recoil'; import { useRecoilValue, useRecoilState } from 'recoil';
import { EditPresetProps, SetOption, tPresetSchema } from 'librechat-data-provider'; import { tPresetSchema } from 'librechat-data-provider';
import type { TSetOption, TEditPresetProps } from '~/common';
import { Dialog, DialogButton } from '~/components/ui'; import { Dialog, DialogButton } from '~/components/ui';
import DialogTemplate from '~/components/ui/DialogTemplate'; import DialogTemplate from '~/components/ui/DialogTemplate';
import SaveAsPresetDialog from './SaveAsPresetDialog'; import SaveAsPresetDialog from './SaveAsPresetDialog';
@ -12,13 +13,18 @@ import { useLocalize } from '~/hooks';
import store from '~/store'; import store from '~/store';
// A preset dialog to show readonly preset values. // A preset dialog to show readonly preset values.
const EndpointOptionsDialog = ({ open, onOpenChange, preset: _preset, title }: EditPresetProps) => { const EndpointOptionsDialog = ({
open,
onOpenChange,
preset: _preset,
title,
}: TEditPresetProps) => {
const [preset, setPreset] = useRecoilState(store.preset); const [preset, setPreset] = useRecoilState(store.preset);
const [saveAsDialogShow, setSaveAsDialogShow] = useState(false); const [saveAsDialogShow, setSaveAsDialogShow] = useState(false);
const endpointsConfig = useRecoilValue(store.endpointsConfig); const endpointsConfig = useRecoilValue(store.endpointsConfig);
const localize = useLocalize(); const localize = useLocalize();
const setOption: SetOption = (param) => (newValue) => { const setOption: TSetOption = (param) => (newValue) => {
const update = {}; const update = {};
update[param] = newValue; update[param] = newValue;
setPreset((prevState) => setPreset((prevState) =>

View file

@ -1,19 +1,27 @@
import React from 'react'; import React from 'react';
import { Save } from 'lucide-react'; import { Save } from 'lucide-react';
import { EndpointOptionsPopoverProps } from 'librechat-data-provider'; import { EModelEndpoint } from 'librechat-data-provider';
import { Button } from '~/components/ui'; import { Button } from '~/components/ui';
import { CrossIcon } from '~/components/svg'; import { CrossIcon } from '~/components/svg';
import PopoverButtons from './PopoverButtons'; import PopoverButtons from './PopoverButtons';
import { cn, removeFocusOutlines } from '~/utils'; import { cn, removeFocusOutlines } from '~/utils';
import { useLocalize } from '~/hooks'; import { useLocalize } from '~/hooks';
type TEndpointOptionsPopoverProps = {
children: React.ReactNode;
visible: boolean;
endpoint: EModelEndpoint;
saveAsPreset: () => void;
closePopover: () => void;
};
export default function EndpointOptionsPopover({ export default function EndpointOptionsPopover({
children, children,
endpoint, endpoint,
visible, visible,
saveAsPreset, saveAsPreset,
closePopover, closePopover,
}: EndpointOptionsPopoverProps) { }: TEndpointOptionsPopoverProps) {
const localize = useLocalize(); const localize = useLocalize();
const cardStyle = const cardStyle =
'shadow-xl rounded-md min-w-[75px] font-normal bg-white border-black/10 border dark:bg-gray-700 text-black dark:text-white'; 'shadow-xl rounded-md min-w-[75px] font-normal bg-white border-black/10 border dark:bg-gray-700 text-black dark:text-white';

View file

@ -1,18 +1,18 @@
import { useRecoilValue } from 'recoil'; import { useRecoilValue } from 'recoil';
import { OpenAISettings, BingAISettings, AnthropicSettings } from './Settings'; import { OpenAISettings, BingAISettings, AnthropicSettings } from './Settings';
import { GoogleSettings, PluginsSettings } from './Settings/MultiView'; import { GoogleSettings, PluginsSettings } from './Settings/MultiView';
import { SettingsProps, OptionComponent, MultiViewComponent } from 'librechat-data-provider'; import type { TSettingsProps, TModelSelectProps, TBaseSettingsProps, TModels } from '~/common';
import { cn } from '~/utils'; import { cn } from '~/utils';
import store from '~/store'; import store from '~/store';
const optionComponents: { [key: string]: OptionComponent } = { const optionComponents: { [key: string]: React.FC<TModelSelectProps> } = {
openAI: OpenAISettings, openAI: OpenAISettings,
azureOpenAI: OpenAISettings, azureOpenAI: OpenAISettings,
bingAI: BingAISettings, bingAI: BingAISettings,
anthropic: AnthropicSettings, anthropic: AnthropicSettings,
}; };
const multiViewComponents: { [key: string]: MultiViewComponent } = { const multiViewComponents: { [key: string]: React.FC<TBaseSettingsProps & TModels> } = {
google: GoogleSettings, google: GoogleSettings,
gptPlugins: PluginsSettings, gptPlugins: PluginsSettings,
}; };
@ -22,7 +22,7 @@ export default function Settings({
setOption, setOption,
isPreset = false, isPreset = false,
className = '', className = '',
}: SettingsProps) { }: TSettingsProps) {
const endpointsConfig = useRecoilValue(store.endpointsConfig); const endpointsConfig = useRecoilValue(store.endpointsConfig);
if (!conversation?.endpoint) { if (!conversation?.endpoint) {
return null; return null;

View file

@ -1,10 +1,17 @@
import { EModelEndpoint, PopoverButton } from 'librechat-data-provider'; import { EModelEndpoint } from 'librechat-data-provider';
import { MessagesSquared, GPTIcon } from '~/components/svg'; import { MessagesSquared, GPTIcon } from '~/components/svg';
import { useRecoilState } from 'recoil'; import { useRecoilState } from 'recoil';
import { Button } from '~/components'; import { Button } from '~/components';
import { cn } from '~/utils/'; import { cn } from '~/utils/';
import store from '~/store'; import store from '~/store';
type TPopoverButton = {
label: string;
buttonClass: string;
handler: () => void;
icon: React.ReactNode;
};
export default function PopoverButtons({ export default function PopoverButtons({
endpoint, endpoint,
buttonClass, buttonClass,
@ -20,7 +27,7 @@ export default function PopoverButtons({
const triggerExamples = () => const triggerExamples = () =>
setOptionSettings((prev) => ({ ...prev, showExamples: !prev.showExamples })); setOptionSettings((prev) => ({ ...prev, showExamples: !prev.showExamples }));
const buttons: { [key: string]: PopoverButton[] } = { const buttons: { [key: string]: TPopoverButton[] } = {
google: [ google: [
{ {
label: (showExamples ? 'Hide' : 'Show') + ' Examples', label: (showExamples ? 'Hide' : 'Show') + ' Examples',

View file

@ -1,14 +1,15 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { useRecoilValue } from 'recoil'; import { useRecoilValue } from 'recoil';
import { useCreatePresetMutation, EditPresetProps } from 'librechat-data-provider'; import { useCreatePresetMutation } from 'librechat-data-provider';
import type { TEditPresetProps } from '~/common';
import { Dialog, Input, Label } from '~/components/ui/'; import { Dialog, Input, Label } from '~/components/ui/';
import DialogTemplate from '~/components/ui/DialogTemplate'; import DialogTemplate from '~/components/ui/DialogTemplate';
import { cn, defaultTextPropsLabel, removeFocusOutlines, cleanupPreset } from '~/utils/'; import { cn, defaultTextPropsLabel, removeFocusOutlines, cleanupPreset } from '~/utils/';
import { useLocalize } from '~/hooks'; import { useLocalize } from '~/hooks';
import store from '~/store'; import store from '~/store';
const SaveAsPresetDialog = ({ open, onOpenChange, preset }: EditPresetProps) => { const SaveAsPresetDialog = ({ open, onOpenChange, preset }: TEditPresetProps) => {
const [title, setTitle] = useState(preset?.title || 'My Preset'); const [title, setTitle] = useState<string>(preset?.title || 'My Preset');
const endpointsConfig = useRecoilValue(store.endpointsConfig); const endpointsConfig = useRecoilValue(store.endpointsConfig);
const createPresetMutation = useCreatePresetMutation(); const createPresetMutation = useCreatePresetMutation();
const localize = useLocalize(); const localize = useLocalize();

View file

@ -1,4 +1,5 @@
import { ModelSelectProps, Side } from 'librechat-data-provider'; import { TModelSelectProps } from '~/common';
import type { ESide } from '~/common';
import { import {
Switch, Switch,
SelectDropDown, SelectDropDown,
@ -12,7 +13,7 @@ import OptionHover from './OptionHover';
import { cn, optionText, defaultTextProps, removeFocusOutlines } from '~/utils/'; import { cn, optionText, defaultTextProps, removeFocusOutlines } from '~/utils/';
import { useLocalize } from '~/hooks'; import { useLocalize } from '~/hooks';
export default function Settings({ conversation, setOption, models, readonly }: ModelSelectProps) { export default function Settings({ conversation, setOption, models, readonly }: TModelSelectProps) {
const localize = useLocalize(); const localize = useLocalize();
if (!conversation) { if (!conversation) {
return null; return null;
@ -83,7 +84,7 @@ export default function Settings({ conversation, setOption, models, readonly }:
className="flex h-4 w-full" className="flex h-4 w-full"
/> />
</HoverCardTrigger> </HoverCardTrigger>
<OptionHover endpoint={conversation.endpoint ?? ''} type="temp" side={Side.Left} /> <OptionHover endpoint={conversation.endpoint ?? ''} type="temp" side={ESide.Left} />
</HoverCard> </HoverCard>
<div className="grid w-full grid-cols-2 items-center gap-10"> <div className="grid w-full grid-cols-2 items-center gap-10">
<HoverCard openDelay={500}> <HoverCard openDelay={500}>
@ -102,7 +103,7 @@ export default function Settings({ conversation, setOption, models, readonly }:
className="ml-4 mt-2" className="ml-4 mt-2"
/> />
</HoverCardTrigger> </HoverCardTrigger>
<OptionHover endpoint={conversation.endpoint ?? ''} type="func" side={Side.Bottom} /> <OptionHover endpoint={conversation.endpoint ?? ''} type="func" side={ESide.Bottom} />
</HoverCard> </HoverCard>
<HoverCard openDelay={500}> <HoverCard openDelay={500}>
<HoverCardTrigger className="ml-[-60px] w-[100px]"> <HoverCardTrigger className="ml-[-60px] w-[100px]">
@ -120,7 +121,7 @@ export default function Settings({ conversation, setOption, models, readonly }:
className="ml-4 mt-2" className="ml-4 mt-2"
/> />
</HoverCardTrigger> </HoverCardTrigger>
<OptionHover endpoint={conversation.endpoint ?? ''} type="skip" side={Side.Bottom} /> <OptionHover endpoint={conversation.endpoint ?? ''} type="skip" side={ESide.Bottom} />
</HoverCard> </HoverCard>
</div> </div>
{/* <HoverCard openDelay={300}> {/* <HoverCard openDelay={300}>

View file

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import TextareaAutosize from 'react-textarea-autosize'; import TextareaAutosize from 'react-textarea-autosize';
import { ModelSelectProps, Side } from 'librechat-data-provider'; import { ESide, TModelSelectProps } from '~/common';
import { import {
Input, Input,
Label, Label,
@ -13,7 +13,7 @@ import {
import OptionHover from './OptionHover'; import OptionHover from './OptionHover';
import { cn, defaultTextProps, optionText, removeFocusOutlines } from '~/utils/'; import { cn, defaultTextProps, optionText, removeFocusOutlines } from '~/utils/';
export default function Settings({ conversation, setOption, models, readonly }: ModelSelectProps) { export default function Settings({ conversation, setOption, models, readonly }: TModelSelectProps) {
if (!conversation) { if (!conversation) {
return null; return null;
} }
@ -111,7 +111,7 @@ export default function Settings({ conversation, setOption, models, readonly }:
className="flex h-4 w-full" className="flex h-4 w-full"
/> />
</HoverCardTrigger> </HoverCardTrigger>
<OptionHover endpoint={conversation?.endpoint ?? ''} type="temp" side={Side.Left} /> <OptionHover endpoint={conversation?.endpoint ?? ''} type="temp" side={ESide.Left} />
</HoverCard> </HoverCard>
<HoverCard openDelay={300}> <HoverCard openDelay={300}>
<HoverCardTrigger className="grid w-full items-center gap-2"> <HoverCardTrigger className="grid w-full items-center gap-2">
@ -148,7 +148,7 @@ export default function Settings({ conversation, setOption, models, readonly }:
className="flex h-4 w-full" className="flex h-4 w-full"
/> />
</HoverCardTrigger> </HoverCardTrigger>
<OptionHover endpoint={conversation?.endpoint ?? ''} type="topp" side={Side.Left} /> <OptionHover endpoint={conversation?.endpoint ?? ''} type="topp" side={ESide.Left} />
</HoverCard> </HoverCard>
<HoverCard openDelay={300}> <HoverCard openDelay={300}>
@ -186,7 +186,7 @@ export default function Settings({ conversation, setOption, models, readonly }:
className="flex h-4 w-full" className="flex h-4 w-full"
/> />
</HoverCardTrigger> </HoverCardTrigger>
<OptionHover endpoint={conversation?.endpoint ?? ''} type="topk" side={Side.Left} /> <OptionHover endpoint={conversation?.endpoint ?? ''} type="topk" side={ESide.Left} />
</HoverCard> </HoverCard>
<HoverCard openDelay={300}> <HoverCard openDelay={300}>
<HoverCardTrigger className="grid w-full items-center gap-2"> <HoverCardTrigger className="grid w-full items-center gap-2">
@ -226,7 +226,7 @@ export default function Settings({ conversation, setOption, models, readonly }:
<OptionHover <OptionHover
endpoint={conversation?.endpoint ?? ''} endpoint={conversation?.endpoint ?? ''}
type="maxoutputtokens" type="maxoutputtokens"
side={Side.Left} side={ESide.Left}
/> />
</HoverCard> </HoverCard>
</div> </div>

View file

@ -1,15 +1,12 @@
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import TextareaAutosize from 'react-textarea-autosize'; import TextareaAutosize from 'react-textarea-autosize';
import { import { useUpdateTokenCountMutation, TUpdateTokenCountResponse } from 'librechat-data-provider';
useUpdateTokenCountMutation, import type { TSettingsProps } from '~/common';
TUpdateTokenCountResponse,
SettingsProps,
} from 'librechat-data-provider';
import { Label, Checkbox, SelectDropDown } from '~/components/ui'; import { Label, Checkbox, SelectDropDown } from '~/components/ui';
import { cn, defaultTextProps, removeFocusOutlines } from '~/utils/'; import { cn, defaultTextProps, removeFocusOutlines } from '~/utils/';
import { useLocalize, useDebounce } from '~/hooks'; import { useLocalize, useDebounce } from '~/hooks';
export default function Settings({ conversation, setOption, readonly }: SettingsProps) { export default function Settings({ conversation, setOption, readonly }: TSettingsProps) {
const localize = useLocalize(); const localize = useLocalize();
const [tokenCount, setTokenCount] = useState(0); const [tokenCount, setTokenCount] = useState(0);
const debouncedContext = useDebounce(conversation?.context?.trim() ?? '', 250); const debouncedContext = useDebounce(conversation?.context?.trim() ?? '', 250);

View file

@ -1,12 +1,22 @@
import React from 'react'; import React from 'react';
import { Plus, Minus } from 'lucide-react'; import { Plus, Minus } from 'lucide-react';
import TextareaAutosize from 'react-textarea-autosize'; import TextareaAutosize from 'react-textarea-autosize';
import { ExamplesProps } from 'librechat-data-provider'; import type { TExample } from 'librechat-data-provider';
import type { TSetExample } from '~/common';
import { Button, Label } from '~/components/ui'; import { Button, Label } from '~/components/ui';
import { cn, defaultTextProps } from '~/utils/'; import { cn, defaultTextProps } from '~/utils/';
import { useLocalize } from '~/hooks'; import { useLocalize } from '~/hooks';
function Examples({ readonly, examples, setExample, addExample, removeExample }: ExamplesProps) { type TExamplesProps = {
readonly?: boolean;
className?: string;
examples: TExample[];
setExample: TSetExample;
addExample: () => void;
removeExample: () => void;
};
function Examples({ readonly, examples, setExample, addExample, removeExample }: TExamplesProps) {
const localize = useLocalize(); const localize = useLocalize();
return ( return (
<> <>

View file

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import TextareaAutosize from 'react-textarea-autosize'; import TextareaAutosize from 'react-textarea-autosize';
import { ModelSelectProps, Side } from 'librechat-data-provider'; import { ESide, TModelSelectProps } from '~/common';
import { import {
SelectDropDown, SelectDropDown,
Input, Input,
@ -14,7 +14,7 @@ import OptionHover from './OptionHover';
import { cn, defaultTextProps, optionText, removeFocusOutlines } from '~/utils/'; import { cn, defaultTextProps, optionText, removeFocusOutlines } from '~/utils/';
import { useLocalize } from '~/hooks'; import { useLocalize } from '~/hooks';
export default function Settings({ conversation, setOption, models, readonly }: ModelSelectProps) { export default function Settings({ conversation, setOption, models, readonly }: TModelSelectProps) {
const localize = useLocalize(); const localize = useLocalize();
if (!conversation) { if (!conversation) {
return null; return null;
@ -122,7 +122,7 @@ export default function Settings({ conversation, setOption, models, readonly }:
className="flex h-4 w-full" className="flex h-4 w-full"
/> />
</HoverCardTrigger> </HoverCardTrigger>
<OptionHover endpoint={conversation?.endpoint ?? ''} type="temp" side={Side.Left} /> <OptionHover endpoint={conversation?.endpoint ?? ''} type="temp" side={ESide.Left} />
</HoverCard> </HoverCard>
{!codeChat && ( {!codeChat && (
<> <>
@ -164,7 +164,7 @@ export default function Settings({ conversation, setOption, models, readonly }:
className="flex h-4 w-full" className="flex h-4 w-full"
/> />
</HoverCardTrigger> </HoverCardTrigger>
<OptionHover endpoint={conversation?.endpoint ?? ''} type="topp" side={Side.Left} /> <OptionHover endpoint={conversation?.endpoint ?? ''} type="topp" side={ESide.Left} />
</HoverCard> </HoverCard>
<HoverCard openDelay={300}> <HoverCard openDelay={300}>
@ -205,7 +205,7 @@ export default function Settings({ conversation, setOption, models, readonly }:
className="flex h-4 w-full" className="flex h-4 w-full"
/> />
</HoverCardTrigger> </HoverCardTrigger>
<OptionHover endpoint={conversation?.endpoint ?? ''} type="topk" side={Side.Left} /> <OptionHover endpoint={conversation?.endpoint ?? ''} type="topk" side={ESide.Left} />
</HoverCard> </HoverCard>
</> </>
)} )}
@ -250,7 +250,7 @@ export default function Settings({ conversation, setOption, models, readonly }:
<OptionHover <OptionHover
endpoint={conversation?.endpoint ?? ''} endpoint={conversation?.endpoint ?? ''}
type="maxoutputtokens" type="maxoutputtokens"
side={Side.Left} side={ESide.Left}
/> />
</HoverCard> </HoverCard>
</div> </div>

View file

@ -1,5 +1,5 @@
import TextareaAutosize from 'react-textarea-autosize'; import TextareaAutosize from 'react-textarea-autosize';
import { ModelSelectProps, Side } from 'librechat-data-provider'; import { ESide, TModelSelectProps } from '~/common';
import { import {
SelectDropDown, SelectDropDown,
Input, Input,
@ -13,7 +13,7 @@ import OptionHover from './OptionHover';
import { cn, defaultTextProps, optionText, removeFocusOutlines } from '~/utils/'; import { cn, defaultTextProps, optionText, removeFocusOutlines } from '~/utils/';
import { useLocalize } from '~/hooks'; import { useLocalize } from '~/hooks';
export default function Settings({ conversation, setOption, models, readonly }: ModelSelectProps) { export default function Settings({ conversation, setOption, models, readonly }: TModelSelectProps) {
const localize = useLocalize(); const localize = useLocalize();
if (!conversation) { if (!conversation) {
return null; return null;
@ -130,7 +130,7 @@ export default function Settings({ conversation, setOption, models, readonly }:
className="flex h-4 w-full" className="flex h-4 w-full"
/> />
</HoverCardTrigger> </HoverCardTrigger>
<OptionHover endpoint={conversation?.endpoint ?? ''} type="temp" side={Side.Left} /> <OptionHover endpoint={conversation?.endpoint ?? ''} type="temp" side={ESide.Left} />
</HoverCard> </HoverCard>
<HoverCard openDelay={300}> <HoverCard openDelay={300}>
<HoverCardTrigger className="grid w-full items-center gap-2"> <HoverCardTrigger className="grid w-full items-center gap-2">
@ -168,7 +168,7 @@ export default function Settings({ conversation, setOption, models, readonly }:
className="flex h-4 w-full" className="flex h-4 w-full"
/> />
</HoverCardTrigger> </HoverCardTrigger>
<OptionHover endpoint={conversation?.endpoint ?? ''} type="topp" side={Side.Left} /> <OptionHover endpoint={conversation?.endpoint ?? ''} type="topp" side={ESide.Left} />
</HoverCard> </HoverCard>
<HoverCard openDelay={300}> <HoverCard openDelay={300}>
@ -207,7 +207,7 @@ export default function Settings({ conversation, setOption, models, readonly }:
className="flex h-4 w-full" className="flex h-4 w-full"
/> />
</HoverCardTrigger> </HoverCardTrigger>
<OptionHover endpoint={conversation?.endpoint ?? ''} type="freq" side={Side.Left} /> <OptionHover endpoint={conversation?.endpoint ?? ''} type="freq" side={ESide.Left} />
</HoverCard> </HoverCard>
<HoverCard openDelay={300}> <HoverCard openDelay={300}>
@ -246,7 +246,7 @@ export default function Settings({ conversation, setOption, models, readonly }:
className="flex h-4 w-full" className="flex h-4 w-full"
/> />
</HoverCardTrigger> </HoverCardTrigger>
<OptionHover endpoint={conversation?.endpoint ?? ''} type="pres" side={Side.Left} /> <OptionHover endpoint={conversation?.endpoint ?? ''} type="pres" side={ESide.Left} />
</HoverCard> </HoverCard>
</div> </div>
</div> </div>

View file

@ -1,8 +1,14 @@
import React from 'react'; import React from 'react';
import { HoverCardPortal, HoverCardContent } from '~/components/ui'; import { HoverCardPortal, HoverCardContent } from '~/components/ui';
import { OptionHoverProps } from 'librechat-data-provider'; import type { ESide } from '~/common';
import { useLocalize } from '~/hooks'; import { useLocalize } from '~/hooks';
type TOptionHoverProps = {
endpoint: string;
type: string;
side: ESide;
};
const openAI = { const openAI = {
max: 'com_endpoint_openai_max', max: 'com_endpoint_openai_max',
temp: 'com_endpoint_openai_temp', temp: 'com_endpoint_openai_temp',
@ -33,7 +39,7 @@ const types = {
}, },
}; };
function OptionHover({ endpoint, type, side }: OptionHoverProps) { function OptionHover({ endpoint, type, side }: TOptionHoverProps) {
const localize = useLocalize(); const localize = useLocalize();
const text = types?.[endpoint]?.[type]; const text = types?.[endpoint]?.[type];
if (!text) { if (!text) {

View file

@ -9,11 +9,11 @@ import {
HoverCardTrigger, HoverCardTrigger,
} from '~/components'; } from '~/components';
import OptionHover from './OptionHover'; import OptionHover from './OptionHover';
import { ModelSelectProps, Side } from 'librechat-data-provider'; import { ESide, TModelSelectProps } from '~/common';
import { cn, defaultTextProps, optionText, removeFocusOutlines } from '~/utils/'; import { cn, defaultTextProps, optionText, removeFocusOutlines } from '~/utils/';
import { useLocalize } from '~/hooks'; import { useLocalize } from '~/hooks';
export default function Settings({ conversation, setOption, models, readonly }: ModelSelectProps) { export default function Settings({ conversation, setOption, models, readonly }: TModelSelectProps) {
const localize = useLocalize(); const localize = useLocalize();
if (!conversation) { if (!conversation) {
return null; return null;
@ -144,7 +144,7 @@ export default function Settings({ conversation, setOption, models, readonly }:
className="flex h-4 w-full" className="flex h-4 w-full"
/> />
</HoverCardTrigger> </HoverCardTrigger>
<OptionHover endpoint={conversation?.endpoint ?? ''} type="temp" side={Side.Left} /> <OptionHover endpoint={conversation?.endpoint ?? ''} type="temp" side={ESide.Left} />
</HoverCard> </HoverCard>
<HoverCard openDelay={300}> <HoverCard openDelay={300}>
<HoverCardTrigger className="grid w-full items-center gap-2"> <HoverCardTrigger className="grid w-full items-center gap-2">
@ -184,7 +184,7 @@ export default function Settings({ conversation, setOption, models, readonly }:
className="flex h-4 w-full" className="flex h-4 w-full"
/> />
</HoverCardTrigger> </HoverCardTrigger>
<OptionHover endpoint={conversation?.endpoint ?? ''} type="topp" side={Side.Left} /> <OptionHover endpoint={conversation?.endpoint ?? ''} type="topp" side={ESide.Left} />
</HoverCard> </HoverCard>
<HoverCard openDelay={300}> <HoverCard openDelay={300}>
@ -225,7 +225,7 @@ export default function Settings({ conversation, setOption, models, readonly }:
className="flex h-4 w-full" className="flex h-4 w-full"
/> />
</HoverCardTrigger> </HoverCardTrigger>
<OptionHover endpoint={conversation?.endpoint ?? ''} type="freq" side={Side.Left} /> <OptionHover endpoint={conversation?.endpoint ?? ''} type="freq" side={ESide.Left} />
</HoverCard> </HoverCard>
<HoverCard openDelay={300}> <HoverCard openDelay={300}>
@ -266,7 +266,7 @@ export default function Settings({ conversation, setOption, models, readonly }:
className="flex h-4 w-full" className="flex h-4 w-full"
/> />
</HoverCardTrigger> </HoverCardTrigger>
<OptionHover endpoint={conversation?.endpoint ?? ''} type="pres" side={Side.Left} /> <OptionHover endpoint={conversation?.endpoint ?? ''} type="pres" side={ESide.Left} />
</HoverCard> </HoverCard>
</div> </div>
</div> </div>

View file

@ -1,8 +1,8 @@
import { SelectDropDown } from '~/components/ui'; import { SelectDropDown } from '~/components/ui';
import { cn, cardStyle } from '~/utils/'; import { cn, cardStyle } from '~/utils/';
import { ModelSelectProps } from 'librechat-data-provider'; import type { TModelSelectProps } from '~/common';
export default function Anthropic({ conversation, setOption, models }: ModelSelectProps) { export default function Anthropic({ conversation, setOption, models }: TModelSelectProps) {
return ( return (
<SelectDropDown <SelectDropDown
value={conversation?.model ?? ''} value={conversation?.model ?? ''}

View file

@ -1,10 +1,10 @@
import { useRecoilValue } from 'recoil'; import { useRecoilValue } from 'recoil';
import { SelectDropDown, Tabs, TabsList, TabsTrigger } from '~/components/ui'; import { SelectDropDown, Tabs, TabsList, TabsTrigger } from '~/components/ui';
import { cn, cardStyle } from '~/utils/'; import { cn, cardStyle } from '~/utils/';
import { ModelSelectProps } from 'librechat-data-provider'; import type { TModelSelectProps } from '~/common';
import store from '~/store'; import store from '~/store';
export default function BingAI({ conversation, setOption, models }: ModelSelectProps) { export default function BingAI({ conversation, setOption, models }: TModelSelectProps) {
const showBingToneSetting = useRecoilValue(store.showBingToneSetting); const showBingToneSetting = useRecoilValue(store.showBingToneSetting);
if (!conversation) { if (!conversation) {
return null; return null;

View file

@ -1,8 +1,8 @@
import { SelectDropDown } from '~/components/ui'; import { SelectDropDown } from '~/components/ui';
import { cn, cardStyle } from '~/utils/'; import { cn, cardStyle } from '~/utils/';
import { ModelSelectProps } from 'librechat-data-provider'; import type { TModelSelectProps } from '~/common';
export default function ChatGPT({ conversation, setOption, models }: ModelSelectProps) { export default function ChatGPT({ conversation, setOption, models }: TModelSelectProps) {
if (!conversation) { if (!conversation) {
return null; return null;
} }

View file

@ -1,8 +1,8 @@
import { SelectDropDown } from '~/components/ui'; import { SelectDropDown } from '~/components/ui';
import { cn, cardStyle } from '~/utils/'; import { cn, cardStyle } from '~/utils/';
import { ModelSelectProps } from 'librechat-data-provider'; import type { TModelSelectProps } from '~/common';
export default function Google({ conversation, setOption, models }: ModelSelectProps) { export default function Google({ conversation, setOption, models }: TModelSelectProps) {
return ( return (
<SelectDropDown <SelectDropDown
value={conversation?.model ?? ''} value={conversation?.model ?? ''}

View file

@ -6,12 +6,22 @@ import Plugins from './Plugins';
import ChatGPT from './ChatGPT'; import ChatGPT from './ChatGPT';
import Anthropic from './Anthropic'; import Anthropic from './Anthropic';
import { useRecoilValue } from 'recoil'; import { useRecoilValue } from 'recoil';
import { SelectProps, ModelSelectProps } from 'librechat-data-provider'; import type { TConversation } from 'librechat-data-provider';
import type { TSetOption, TModelSelectProps } from '~/common';
import store from '~/store'; import store from '~/store';
type OptionComponentType = React.FC<ModelSelectProps>; type TGoogleProps = {
showExamples: boolean;
isCodeChat: boolean;
};
const optionComponents: { [key: string]: OptionComponentType } = { type TSelectProps = {
conversation: TConversation | null;
setOption: TSetOption;
extraProps?: TGoogleProps;
};
const optionComponents: { [key: string]: React.FC<TModelSelectProps> } = {
openAI: OpenAI, openAI: OpenAI,
azureOpenAI: OpenAI, azureOpenAI: OpenAI,
bingAI: BingAI, bingAI: BingAI,
@ -21,7 +31,7 @@ const optionComponents: { [key: string]: OptionComponentType } = {
chatGPTBrowser: ChatGPT, chatGPTBrowser: ChatGPT,
}; };
export default function ModelSelect({ conversation, setOption }: SelectProps) { export default function ModelSelect({ conversation, setOption }: TSelectProps) {
const endpointsConfig = useRecoilValue(store.endpointsConfig); const endpointsConfig = useRecoilValue(store.endpointsConfig);
if (!conversation?.endpoint) { if (!conversation?.endpoint) {
return null; return null;

View file

@ -1,8 +1,8 @@
import { SelectDropDown } from '~/components/ui'; import { SelectDropDown } from '~/components/ui';
import { cn, cardStyle } from '~/utils/'; import { cn, cardStyle } from '~/utils/';
import { ModelSelectProps } from 'librechat-data-provider'; import type { TModelSelectProps } from '~/common';
export default function OpenAI({ conversation, setOption, models }: ModelSelectProps) { export default function OpenAI({ conversation, setOption, models }: TModelSelectProps) {
return ( return (
<SelectDropDown <SelectDropDown
value={conversation?.model ?? ''} value={conversation?.model ?? ''}

View file

@ -1,7 +1,8 @@
import { useRecoilState } from 'recoil'; import { useRecoilState } from 'recoil';
import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
import { ChevronDownIcon } from 'lucide-react'; import { ChevronDownIcon } from 'lucide-react';
import { ModelSelectProps, useAvailablePluginsQuery, TPlugin } from 'librechat-data-provider'; import { useAvailablePluginsQuery, TPlugin } from 'librechat-data-provider';
import type { TModelSelectProps } from '~/common';
import { SelectDropDown, MultiSelectDropDown, Button } from '~/components/ui'; import { SelectDropDown, MultiSelectDropDown, Button } from '~/components/ui';
import { useSetOptions, useAuthContext, useMediaQuery } from '~/hooks'; import { useSetOptions, useAuthContext, useMediaQuery } from '~/hooks';
import { cn, cardStyle } from '~/utils/'; import { cn, cardStyle } from '~/utils/';
@ -17,7 +18,7 @@ const pluginStore: TPlugin = {
authenticated: false, authenticated: false,
}; };
export default function Plugins({ conversation, setOption, models }: ModelSelectProps) { export default function Plugins({ conversation, setOption, models }: TModelSelectProps) {
const { data: allPlugins } = useAvailablePluginsQuery(); const { data: allPlugins } = useAvailablePluginsQuery();
const [visible, setVisibility] = useState<boolean>(true); const [visible, setVisibility] = useState<boolean>(true);
const [availableTools, setAvailableTools] = useRecoilState(store.availableTools); const [availableTools, setAvailableTools] = useRecoilState(store.availableTools);

View file

@ -3,8 +3,22 @@ import { Listbox, Transition } from '@headlessui/react';
import { Wrench, ArrowRight } from 'lucide-react'; import { Wrench, ArrowRight } from 'lucide-react';
import { CheckMark } from '~/components/svg'; import { CheckMark } from '~/components/svg';
import useOnClickOutside from '~/hooks/useOnClickOutside'; import useOnClickOutside from '~/hooks/useOnClickOutside';
import { MultiSelectDropDownProps } from 'librechat-data-provider';
import { cn } from '~/utils/'; import { cn } from '~/utils/';
import type { TPlugin } from 'librechat-data-provider';
export type TMultiSelectDropDownProps = {
title?: string;
value: Array<{ icon?: string; name?: string; isButton?: boolean }>;
disabled?: boolean;
setSelected: (option: string) => void;
availableValues: TPlugin[];
showAbove?: boolean;
showLabel?: boolean;
containerClassName?: string;
isSelected: (value: string) => boolean;
className?: string;
optionValueKey?: string;
};
function MultiSelectDropDown({ function MultiSelectDropDown({
title = 'Plugins', title = 'Plugins',
@ -18,7 +32,7 @@ function MultiSelectDropDown({
isSelected, isSelected,
className, className,
optionValueKey = 'value', optionValueKey = 'value',
}: MultiSelectDropDownProps) { }: TMultiSelectDropDownProps) {
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const menuRef = useRef(null); const menuRef = useRef(null);
const excludeIds = ['select-plugin', 'plugins-label', 'selected-plugins']; const excludeIds = ['select-plugin', 'plugins-label', 'selected-plugins'];

View file

@ -1,16 +1,20 @@
import { UsePresetOptions, TPreset, SetOption, SetExample } from 'librechat-data-provider'; import { TPreset } from 'librechat-data-provider';
import type { TSetOptionsPayload, TSetExample, TSetOption } from '~/common';
import { useRecoilState, useRecoilValue } from 'recoil'; import { useRecoilState, useRecoilValue } from 'recoil';
import { cleanupPreset } from '~/utils'; import { cleanupPreset } from '~/utils';
import store from '~/store'; import store from '~/store';
const usePresetOptions: UsePresetOptions = (_preset) => { type TUsePresetOptions = (preset?: TPreset | boolean | null) => TSetOptionsPayload | boolean;
const usePresetOptions: TUsePresetOptions = (_preset) => {
const [preset, setPreset] = useRecoilState(store.preset); const [preset, setPreset] = useRecoilState(store.preset);
const endpointsConfig = useRecoilValue(store.endpointsConfig); const endpointsConfig = useRecoilValue(store.endpointsConfig);
if (!_preset) { if (!_preset) {
return false; return false;
} }
const getConversation: () => TPreset | null = () => preset; const getConversation: () => TPreset | null = () => preset;
const setOption: SetOption = (param) => (newValue) => {
const setOption: TSetOption = (param) => (newValue) => {
const update = {}; const update = {};
update[param] = newValue; update[param] = newValue;
setPreset((prevState) => setPreset((prevState) =>
@ -24,7 +28,7 @@ const usePresetOptions: UsePresetOptions = (_preset) => {
); );
}; };
const setExample: SetExample = (i, type, newValue = null) => { const setExample: TSetExample = (i, type, newValue = null) => {
const update = {}; const update = {};
const current = preset?.examples?.slice() || []; const current = preset?.examples?.slice() || [];
const currentExample = { ...current[i] } || {}; const currentExample = { ...current[i] } || {};

View file

@ -1,16 +1,12 @@
import { import { TConversation, TPreset, TPlugin, tConversationSchema } from 'librechat-data-provider';
UseSetOptions, import type { TSetExample, TSetOption, TSetOptionsPayload } from '~/common';
TConversation,
SetOption,
SetExample,
TPlugin,
tConversationSchema,
} from 'librechat-data-provider';
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil'; import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil';
import usePresetOptions from './usePresetOptions'; import usePresetOptions from './usePresetOptions';
import store from '~/store'; import store from '~/store';
const useSetOptions: UseSetOptions = (preset = false) => { type TUseSetOptions = (preset?: TPreset | boolean | null) => TSetOptionsPayload;
const useSetOptions: TUseSetOptions = (preset = false) => {
const setShowPluginStoreDialog = useSetRecoilState(store.showPluginStoreDialog); const setShowPluginStoreDialog = useSetRecoilState(store.showPluginStoreDialog);
const [conversation, setConversation] = useRecoilState(store.conversation); const [conversation, setConversation] = useRecoilState(store.conversation);
const availableTools = useRecoilValue(store.availableTools); const availableTools = useRecoilValue(store.availableTools);
@ -21,7 +17,7 @@ const useSetOptions: UseSetOptions = (preset = false) => {
return result; return result;
} }
const setOption: SetOption = (param) => (newValue) => { const setOption: TSetOption = (param) => (newValue) => {
const update = {}; const update = {};
update[param] = newValue; update[param] = newValue;
setConversation((prevState) => setConversation((prevState) =>
@ -32,7 +28,7 @@ const useSetOptions: UseSetOptions = (preset = false) => {
); );
}; };
const setExample: SetExample = (i, type, newValue = null) => { const setExample: TSetExample = (i, type, newValue = null) => {
const update = {}; const update = {};
const current = conversation?.examples?.slice() || []; const current = conversation?.examples?.slice() || [];
const currentExample = { ...current[i] } || {}; const currentExample = { ...current[i] } || {};
@ -92,7 +88,7 @@ const useSetOptions: UseSetOptions = (preset = false) => {
return conversation.tools.find((el) => el.pluginKey === value) ? true : false; return conversation.tools.find((el) => el.pluginKey === value) ? true : false;
} }
const setAgentOption: SetOption = (param) => (newValue) => { const setAgentOption: TSetOption = (param) => (newValue) => {
const editableConvo = JSON.stringify(conversation); const editableConvo = JSON.stringify(conversation);
const convo = JSON.parse(editableConvo); const convo = JSON.parse(editableConvo);
const { agentOptions } = convo; const { agentOptions } = convo;

View file

@ -1,5 +1,9 @@
import { atom } from 'recoil'; import { atom } from 'recoil';
import { TOptionSettings } from 'librechat-data-provider';
type TOptionSettings = {
showExamples?: boolean;
isCodeChat?: boolean;
};
const optionSettings = atom<TOptionSettings>({ const optionSettings = atom<TOptionSettings>({
key: 'optionSettings', key: 'optionSettings',

View file

@ -1,6 +1,11 @@
import { CleanupPreset, TPreset } from 'librechat-data-provider'; import { TEndpointsConfig, TPreset } from 'librechat-data-provider';
const cleanupPreset = ({ preset: _preset, endpointsConfig = {} }: CleanupPreset): TPreset => { type TCleanupPreset = {
preset: Partial<TPreset>;
endpointsConfig?: TEndpointsConfig | Record<string, unknown>;
};
const cleanupPreset = ({ preset: _preset, endpointsConfig = {} }: TCleanupPreset): TPreset => {
const { endpoint } = _preset; const { endpoint } = _preset;
let preset = {} as TPreset; let preset = {} as TPreset;

4
package-lock.json generated
View file

@ -26944,7 +26944,7 @@
}, },
"packages/data-provider": { "packages/data-provider": {
"name": "librechat-data-provider", "name": "librechat-data-provider",
"version": "0.1.3", "version": "0.1.4",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@tanstack/react-query": "^4.28.0", "@tanstack/react-query": "^4.28.0",
@ -39521,7 +39521,7 @@
"rollup": "^3.26.0", "rollup": "^3.26.0",
"rollup-plugin-typescript2": "^0.35.0", "rollup-plugin-typescript2": "^0.35.0",
"typescript": "^5.0.4", "typescript": "^5.0.4",
"zod": "*" "zod": "^3.21.4"
}, },
"dependencies": { "dependencies": {
"brace-expansion": { "brace-expansion": {

View file

@ -1,5 +1,5 @@
import { tConversationSchema } from './schemas'; import { tConversationSchema } from './schemas';
import type { TSubmission, EModelEndpoint } from './types'; import { TSubmission, EModelEndpoint } from './types';
export default function createPayload(submission: TSubmission) { export default function createPayload(submission: TSubmission) {
const { conversation, message, endpointOption } = submission; const { conversation, message, endpointOption } = submission;

View file

@ -1,5 +1,4 @@
import * as React from 'react'; import { TMessage, EModelEndpoint, TConversation } from './schemas';
import { TExample, TMessage, EModelEndpoint, TPlugin, TConversation, TPreset } from './schemas';
export * from './schemas'; export * from './schemas';
@ -49,19 +48,20 @@ export type TPluginAction = {
auth?: unknown; auth?: unknown;
}; };
export type TTemplate = {
[key: string]: TPlugin;
};
export type TUpdateUserPlugins = { export type TUpdateUserPlugins = {
pluginKey: string; pluginKey: string;
action: string; action: string;
auth?: unknown; auth?: unknown;
}; };
export type TOptionSettings = { export type TError = {
showExamples?: boolean; message: string;
isCodeChat?: boolean; code?: number;
response?: {
data?: {
message?: string;
};
};
}; };
export type TUser = { export type TUser = {
@ -204,143 +204,3 @@ export type TRequestPasswordResetResponse = {
link?: string; link?: string;
message?: string; message?: string;
}; };
export type File = {
name: string;
date: number;
size: number;
};
export type SetOption = (param: number | string) => (newValue: number | string | boolean) => void;
export type SetExample = (
i: number,
type: string,
newValue: number | string | boolean | null,
) => void;
export enum Side {
Top = 'top',
Right = 'right',
Bottom = 'bottom',
Left = 'left',
}
export type OptionHoverProps = {
endpoint: string;
type: string;
side: Side;
};
export type BaseProps = {
conversation: TConversation | TPreset | null;
className?: string;
isPreset?: boolean;
readonly?: boolean;
};
export type SettingsProps = BaseProps & {
setOption: SetOption;
};
export type TModels = {
models: string[];
};
export type ModelSelectProps = SettingsProps & TModels;
export type ExamplesProps = {
readonly?: boolean;
className?: string;
examples: TExample[];
setExample: SetExample;
addExample: () => void;
removeExample: () => void;
};
export type GoogleProps = {
showExamples: boolean;
isCodeChat: boolean;
};
export type GoogleViewProps = SettingsProps & GoogleProps;
export type OptionComponent = React.FC<ModelSelectProps>;
export type MultiViewComponent = React.FC<BaseProps & TModels>;
export type SelectProps = {
conversation: TConversation | null;
setOption: SetOption;
extraProps?: GoogleProps;
};
export type SetOptionsPayload = {
setOption: SetOption;
setExample: SetExample;
addExample: () => void;
removeExample: () => void;
setAgentOption: SetOption;
getConversation: () => TConversation | TPreset | null;
checkPluginSelection: (value: string) => boolean;
setTools: (newValue: string) => void;
};
export type UseSetOptions = (preset?: TPreset | boolean | null) => SetOptionsPayload;
export type UsePresetOptions = (preset?: TPreset | boolean | null) => SetOptionsPayload | boolean;
export type PopoverButton = {
label: string;
buttonClass: string;
handler: () => void;
icon: React.ReactNode;
};
export type EndpointOptionsPopoverProps = {
children: React.ReactNode;
visible: boolean;
endpoint: EModelEndpoint;
saveAsPreset: () => void;
closePopover: () => void;
};
export type EditPresetProps = {
open: boolean;
onOpenChange: React.Dispatch<React.SetStateAction<boolean>>;
preset: TPreset;
title?: string;
};
export type MultiSelectDropDownProps = {
title?: string;
value: Array<{ icon?: string; name?: string; isButton?: boolean }>;
disabled?: boolean;
setSelected: (option: string) => void;
availableValues: TPlugin[];
showAbove?: boolean;
showLabel?: boolean;
containerClassName?: string;
isSelected: (value: string) => boolean;
className?: string;
optionValueKey?: string;
};
export type TError = {
message: string;
code?: number;
response?: {
data?: {
message?: string;
};
};
};
export type CleanupPreset = {
preset: Partial<TPreset>;
endpointsConfig?: TEndpointsConfig | Record<string, unknown>;
};
export type PagesProps = {
pages: number;
pageNumber: number;
setPageNumber: (pageNumber: number) => void;
nextPage: () => Promise<void>;
previousPage: () => Promise<void>;
};