🎨 style: update Assistants builder (#3397)

* style: update Assistant builder

* fix(Eng): re-introduce old file_search info message

* feat: new OGDialogTemplate; style: imporved tools + actions dialogs

* style: fix alignment issue for delete tool dialog

* chore: import order

---------

Co-authored-by: Danny Avila <danny@librechat.ai>
This commit is contained in:
Marco Beretta 2024-07-21 19:46:43 +02:00 committed by GitHub
parent 344297021f
commit 0bd59c0efe
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
29 changed files with 1115 additions and 916 deletions

View file

@ -2,7 +2,7 @@ export default function RemoveFile({ onRemove }: { onRemove: () => void }) {
return ( return (
<button <button
type="button" type="button"
className="absolute right-1 top-1 -translate-y-1/2 translate-x-1/2 rounded-full border border-white bg-gray-500 p-0.5 text-white transition-colors hover:bg-black hover:opacity-100 group-hover:opacity-100 md:opacity-0" className="absolute right-1 top-1 -translate-y-1/2 translate-x-1/2 rounded-full border border-gray-500 bg-gray-500 p-0.5 text-white transition-colors hover:bg-gray-700 hover:opacity-100 group-hover:opacity-100 md:opacity-0"
onClick={onRemove} onClick={onRemove}
> >
<span> <span>
@ -15,6 +15,8 @@ export default function RemoveFile({ onRemove }: { onRemove: () => void }) {
strokeLinejoin="round" strokeLinejoin="round"
className="icon-sm" className="icon-sm"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
width="32"
height="32"
> >
<line x1="18" y1="6" x2="6" y2="18" /> <line x1="18" y1="6" x2="6" y2="18" />
<line x1="6" y1="6" x2="18" y2="18" /> <line x1="6" y1="6" x2="18" y2="18" />

View file

@ -32,7 +32,7 @@ import {
DropdownMenuTrigger, DropdownMenuTrigger,
} from '~/components/ui'; } from '~/components/ui';
import { useDeleteFilesFromTable } from '~/hooks/Files'; import { useDeleteFilesFromTable } from '~/hooks/Files';
import { NewTrashIcon, Spinner } from '~/components/svg'; import { TrashIcon, Spinner } from '~/components/svg';
import useLocalize from '~/hooks/useLocalize'; import useLocalize from '~/hooks/useLocalize';
interface DataTableProps<TData, TValue> { interface DataTableProps<TData, TValue> {
@ -102,7 +102,7 @@ export default function DataTable<TData, TValue>({ columns, data }: DataTablePro
{isDeleting ? ( {isDeleting ? (
<Spinner className="h-4 w-4" /> <Spinner className="h-4 w-4" />
) : ( ) : (
<NewTrashIcon className="h-4 w-4 text-red-400" /> <TrashIcon className="h-4 w-4 text-red-400" />
)} )}
{localize('com_ui_delete')} {localize('com_ui_delete')}
</Button> </Button>

View file

@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import { CrossIcon, NewTrashIcon } from '~/components/svg'; import { CrossIcon, TrashIcon } from '~/components/svg';
import { Button } from '~/components/ui'; import { Button } from '~/components/ui';
type DeleteIconButtonProps = { type DeleteIconButtonProps = {
@ -10,7 +10,7 @@ export default function DeleteIconButton({ onClick }: DeleteIconButtonProps) {
return ( return (
<div className="w-fit"> <div className="w-fit">
<Button className="bg-red-400 p-3" onClick={onClick}> <Button className="bg-red-400 p-3" onClick={onClick}>
<NewTrashIcon /> <TrashIcon />
</Button> </Button>
</div> </div>
); );

View file

@ -32,7 +32,7 @@ import {
DropdownMenuTrigger, DropdownMenuTrigger,
} from '~/components/ui'; } from '~/components/ui';
import { useDeleteFilesFromTable } from '~/hooks/Files'; import { useDeleteFilesFromTable } from '~/hooks/Files';
import { NewTrashIcon, Spinner } from '~/components/svg'; import { TrashIcon, Spinner } from '~/components/svg';
import useLocalize from '~/hooks/useLocalize'; import useLocalize from '~/hooks/useLocalize';
import ActionButton from '../ActionButton'; import ActionButton from '../ActionButton';
import UploadFileButton from './UploadFileButton'; import UploadFileButton from './UploadFileButton';
@ -112,7 +112,7 @@ export default function DataTableFile<TData, TValue>({
{isDeleting ? ( {isDeleting ? (
<Spinner className="h-4 w-4" /> <Spinner className="h-4 w-4" />
) : ( ) : (
<NewTrashIcon className="h-4 w-4 text-red-400" /> <TrashIcon className="h-4 w-4 text-red-400" />
)} )}
{localize('com_ui_delete')} {localize('com_ui_delete')}
</Button> </Button>

View file

@ -1,6 +1,6 @@
import type { TFile } from 'librechat-data-provider'; import type { TFile } from 'librechat-data-provider';
import React from 'react'; import React from 'react';
import { NewTrashIcon } from '~/components/svg'; import { TrashIcon } from '~/components/svg';
import { Button } from '~/components/ui'; import { Button } from '~/components/ui';
type FileListItemProps = { type FileListItemProps = {
@ -25,7 +25,7 @@ export default function FileListItem({ file, deleteFile, width = '400px' }: File
className="my-0 ml-3 bg-transparent p-0 text-[#666666] hover:bg-slate-200" className="my-0 ml-3 bg-transparent p-0 text-[#666666] hover:bg-slate-200"
onClick={() => deleteFile(file._id)} onClick={() => deleteFile(file._id)}
> >
<NewTrashIcon className="m-0 p-0" /> <TrashIcon className="m-0 p-0" />
</Button> </Button>
</div> </div>
</div> </div>

View file

@ -2,7 +2,7 @@ import type { TFile } from 'librechat-data-provider';
import { FileIcon, PlusIcon } from 'lucide-react'; import { FileIcon, PlusIcon } from 'lucide-react';
import React from 'react'; import React from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { DotsIcon, NewTrashIcon } from '~/components/svg'; import { DotsIcon, TrashIcon } from '~/components/svg';
import { Button } from '~/components/ui'; import { Button } from '~/components/ui';
type FileListItemProps = { type FileListItemProps = {
@ -68,7 +68,7 @@ export default function FileListItem2({
className="w-min bg-transparent text-[#666666] hover:bg-slate-200" className="w-min bg-transparent text-[#666666] hover:bg-slate-200"
onClick={() => deleteFile(file._id)} onClick={() => deleteFile(file._id)}
> >
<NewTrashIcon className="" /> <TrashIcon className="" />
</Button> </Button>
</div> </div>
</div> </div>

View file

@ -1,7 +1,7 @@
import { TFile } from 'librechat-data-provider/dist/types'; import { TFile } from 'librechat-data-provider/dist/types';
import React, { useState } from 'react'; import React, { useState } from 'react';
import { TThread, TVectorStore } from '~/common'; import { TThread, TVectorStore } from '~/common';
import { CheckMark, NewTrashIcon } from '~/components/svg'; import { CheckMark, TrashIcon } from '~/components/svg';
import { Button } from '~/components/ui'; import { Button } from '~/components/ui';
import DeleteIconButton from '../DeleteIconButton'; import DeleteIconButton from '../DeleteIconButton';
import VectorStoreButton from '../VectorStore/VectorStoreButton'; import VectorStoreButton from '../VectorStore/VectorStoreButton';
@ -140,7 +140,7 @@ export default function FilePreview() {
}} }}
variant={'ghost'} variant={'ghost'}
> >
<NewTrashIcon className="m-0 p-0" /> <TrashIcon className="m-0 p-0" />
</Button> </Button>
</div> </div>
</div> </div>
@ -167,7 +167,7 @@ export default function FilePreview() {
console.log('Remove from thread'); console.log('Remove from thread');
}} }}
> >
<NewTrashIcon className="m-0 p-0" /> <TrashIcon className="m-0 p-0" />
</Button> </Button>
</div> </div>
</div> </div>

View file

@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { TVectorStore } from '~/common'; import { TVectorStore } from '~/common';
import { DotsIcon, NewTrashIcon, TrashIcon } from '~/components/svg'; import { DotsIcon, TrashIcon, TrashIcon } from '~/components/svg';
import { Button } from '~/components/ui'; import { Button } from '~/components/ui';
type VectorStoreListItemProps = { type VectorStoreListItemProps = {
@ -39,7 +39,7 @@ export default function VectorStoreListItem({
className="m-0 w-full bg-transparent p-0 text-[#666666] hover:bg-slate-200 sm:w-fit" className="m-0 w-full bg-transparent p-0 text-[#666666] hover:bg-slate-200 sm:w-fit"
onClick={() => deleteVectorStore(vectorStore._id)} onClick={() => deleteVectorStore(vectorStore._id)}
> >
<NewTrashIcon className="m-0 p-0" /> <TrashIcon className="m-0 p-0" />
</Button> </Button>
</div> </div>
</div> </div>

View file

@ -1,7 +1,7 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import DeleteIconButton from '../DeleteIconButton'; import DeleteIconButton from '../DeleteIconButton';
import { Button } from '~/components/ui'; import { Button } from '~/components/ui';
import { NewTrashIcon } from '~/components/svg'; import { TrashIcon } from '~/components/svg';
import { TFile } from 'librechat-data-provider/dist/types'; import { TFile } from 'librechat-data-provider/dist/types';
import UploadFileButton from '../FileList/UploadFileButton'; import UploadFileButton from '../FileList/UploadFileButton';
import UploadFileModal from '../FileList/UploadFileModal'; import UploadFileModal from '../FileList/UploadFileModal';
@ -204,7 +204,7 @@ export default function VectorStorePreview() {
className="my-0 ml-3 h-min bg-transparent p-0 text-[#666666] hover:bg-slate-200" className="my-0 ml-3 h-min bg-transparent p-0 text-[#666666] hover:bg-slate-200"
onClick={() => console.log('click')} onClick={() => console.log('click')}
> >
<NewTrashIcon className="m-0 p-0" /> <TrashIcon className="m-0 p-0" />
</Button> </Button>
</div> </div>
</div> </div>

View file

@ -18,7 +18,7 @@ import CategoryIcon from '~/components/Prompts/Groups/CategoryIcon';
import DialogTemplate from '~/components/ui/DialogTemplate'; import DialogTemplate from '~/components/ui/DialogTemplate';
import { RenameButton } from '~/components/Conversations'; import { RenameButton } from '~/components/Conversations';
import { useLocalize, useAuthContext } from '~/hooks'; import { useLocalize, useAuthContext } from '~/hooks';
import { NewTrashIcon } from '~/components/svg'; import { TrashIcon } from '~/components/svg';
import { cn } from '~/utils/'; import { cn } from '~/utils/';
export default function DashGroupItem({ export default function DashGroupItem({
@ -169,7 +169,7 @@ export default function DashGroupItem({
e.stopPropagation(); e.stopPropagation();
}} }}
> >
<NewTrashIcon className="icon-md text-gray-600 dark:text-gray-300" /> <TrashIcon className="icon-md text-gray-600 dark:text-gray-300" />
</Button> </Button>
</DialogTrigger> </DialogTrigger>
<DialogTemplate <DialogTemplate

View file

@ -7,9 +7,10 @@ import {
} from 'librechat-data-provider'; } from 'librechat-data-provider';
import type { AssistantPanelProps, ActionAuthForm } from '~/common'; import type { AssistantPanelProps, ActionAuthForm } from '~/common';
import { useAssistantsMapContext, useToastContext } from '~/Providers'; import { useAssistantsMapContext, useToastContext } from '~/Providers';
import { Dialog, DialogTrigger } from '~/components/ui'; import { Dialog, DialogTrigger, OGDialog, OGDialogTrigger, Label } from '~/components/ui';
import OGDialogTemplate from '~/components/ui/OGDialogTemplate';
import { useDeleteAction } from '~/data-provider'; import { useDeleteAction } from '~/data-provider';
import { NewTrashIcon } from '~/components/svg'; import { TrashIcon } from '~/components/svg';
import useLocalize from '~/hooks/useLocalize'; import useLocalize from '~/hooks/useLocalize';
import ActionsInput from './ActionsInput'; import ActionsInput from './ActionsInput';
import ActionsAuth from './ActionsAuth'; import ActionsAuth from './ActionsAuth';
@ -119,33 +120,52 @@ export default function ActionsPanel({
</div> </div>
</button> </button>
</div> </div>
{!!action && ( {!!action && (
<OGDialog>
<OGDialogTrigger asChild>
<div className="absolute right-0 top-6"> <div className="absolute right-0 top-6">
<button <button
type="button" type="button"
disabled={!assistant_id || !action.action_id} disabled={!assistant_id || !action.action_id}
className="btn relative bg-transparent text-red-500 hover:bg-gray-100 dark:hover:bg-gray-800" className="btn btn-neutral border-token-border-light relative h-9 rounded-lg font-medium"
onClick={() => { >
if (!assistant_id) { <TrashIcon className="text-red-500" />
return prompt('No assistant_id found, is the assistant created?'); </button>
</div>
</OGDialogTrigger>
<OGDialogTemplate
showCloseButton={false}
title={localize('com_ui_delete_action')}
className="max-w-[450px]"
main={
<Label className="text-left text-sm font-medium">
{localize('com_ui_delete_action_confirm')}
</Label>
}
selection={{
selectHandler: () => {
if (!assistant_id) {
return showToast({
message: 'No assistant_id found, is the assistant created?',
status: 'error',
});
} }
const confirmed = confirm('Are you sure you want to delete this action?');
if (confirmed) {
deleteAction.mutate({ deleteAction.mutate({
model: assistantMap[endpoint][assistant_id].model, model: assistantMap[endpoint][assistant_id].model,
action_id: action.action_id, action_id: action.action_id,
assistant_id, assistant_id,
endpoint, endpoint,
}); });
} },
selectClasses:
'bg-red-700 dark:bg-red-600 hover:bg-red-800 dark:hover:bg-red-800 transition-color duration-200 text-white',
selectText: localize('com_ui_delete'),
}} }}
> />
<div className="flex w-full items-center justify-center gap-2"> </OGDialog>
<NewTrashIcon className="icon-md text-red-500" />
</div>
</button>
</div>
)} )}
<div className="text-xl font-medium">{(action ? 'Edit' : 'Add') + ' ' + 'actions'}</div> <div className="text-xl font-medium">{(action ? 'Edit' : 'Add') + ' ' + 'actions'}</div>
<div className="text-token-text-tertiary text-sm"> <div className="text-token-text-tertiary text-sm">
{localize('com_assistants_actions_info')} {localize('com_assistants_actions_info')}

View file

@ -1,3 +1,4 @@
import { useState } from 'react';
import type { Action } from 'librechat-data-provider'; import type { Action } from 'librechat-data-provider';
import GearIcon from '~/components/svg/GearIcon'; import GearIcon from '~/components/svg/GearIcon';
@ -8,11 +9,15 @@ export default function AssistantAction({
action: Action; action: Action;
onClick: () => void; onClick: () => void;
}) { }) {
const [isHovering, setIsHovering] = useState(false);
return ( return (
<div> <div>
<div <div
onClick={onClick} onClick={onClick}
className="border-token-border-medium flex w-full rounded-lg border text-sm hover:cursor-pointer" className="flex w-full rounded-lg text-sm hover:cursor-pointer"
onMouseEnter={() => setIsHovering(true)}
onMouseLeave={() => setIsHovering(false)}
> >
<div <div
className="h-9 grow whitespace-nowrap px-3 py-2" className="h-9 grow whitespace-nowrap px-3 py-2"
@ -20,13 +25,14 @@ export default function AssistantAction({
> >
{action.metadata.domain} {action.metadata.domain}
</div> </div>
<div className="w-px bg-gray-300 dark:bg-gray-600" /> {isHovering && (
<button <button
type="button" type="button"
className="flex h-9 w-9 min-w-9 items-center justify-center rounded-lg rounded-l-none" className="transition-color flex h-9 w-9 min-w-9 items-center justify-center rounded-lg duration-200 hover:bg-gray-200 dark:hover:bg-gray-700"
> >
<GearIcon className="icon-sm" /> <GearIcon className="icon-sm" />
</button> </button>
)}
</div> </div>
</div> </div>
); );

View file

@ -13,6 +13,7 @@ import {
import type { FunctionTool, TConfig, TPlugin } from 'librechat-data-provider'; import type { FunctionTool, TConfig, TPlugin } from 'librechat-data-provider';
import type { AssistantForm, AssistantPanelProps } from '~/common'; import type { AssistantForm, AssistantPanelProps } from '~/common';
import { useCreateAssistantMutation, useUpdateAssistantMutation } from '~/data-provider'; import { useCreateAssistantMutation, useUpdateAssistantMutation } from '~/data-provider';
import { cn, cardStyle, defaultTextProps, removeFocusOutlines } from '~/utils';
import { useAssistantsMapContext, useToastContext } from '~/Providers'; import { useAssistantsMapContext, useToastContext } from '~/Providers';
import { useSelectAssistant, useLocalize } from '~/hooks'; import { useSelectAssistant, useLocalize } from '~/hooks';
import { ToolSelectDialog } from '~/components/Tools'; import { ToolSelectDialog } from '~/components/Tools';
@ -24,13 +25,15 @@ import AssistantAction from './AssistantAction';
import ContextButton from './ContextButton'; import ContextButton from './ContextButton';
import AssistantTool from './AssistantTool'; import AssistantTool from './AssistantTool';
import { Spinner } from '~/components/svg'; import { Spinner } from '~/components/svg';
import { cn, cardStyle } from '~/utils/';
import Knowledge from './Knowledge'; import Knowledge from './Knowledge';
import { Panel } from '~/common'; import { Panel } from '~/common';
const labelClass = 'mb-2 block text-xs font-bold text-gray-700 dark:text-gray-400'; const labelClass = 'mb-2 text-token-text-primary block font-medium';
const inputClass = const inputClass = cn(
'focus:shadow-outline w-full appearance-none rounded-md border px-3 py-2 text-sm leading-tight text-gray-700 dark:text-white shadow focus:border-green-500 focus:outline-none focus:ring-0 dark:bg-gray-800 dark:border-gray-700/80'; defaultTextProps,
'flex w-full px-3 py-2 dark:border-gray-800 dark:bg-gray-800',
removeFocusOutlines,
);
export default function AssistantPanel({ export default function AssistantPanel({
// index = 0, // index = 0,
@ -297,7 +300,7 @@ export default function AssistantPanel({
{...field} {...field}
value={field.value ?? ''} value={field.value ?? ''}
{...{ max: 32768 }} {...{ max: 32768 }}
className="focus:shadow-outline min-h-[150px] w-full resize-none resize-y appearance-none rounded-md border px-3 py-2 text-sm leading-tight text-gray-700 shadow focus:border-green-500 focus:outline-none focus:ring-0 dark:border-gray-700/80 dark:bg-gray-800 dark:text-white" className={cn(inputClass, 'min-h-[100px] resize-none resize-y')}
id="instructions" id="instructions"
placeholder={localize('com_assistants_instructions_placeholder')} placeholder={localize('com_assistants_instructions_placeholder')}
rows={3} rows={3}
@ -357,7 +360,7 @@ export default function AssistantPanel({
${toolsEnabled && actionsEnabled ? ' + ' : ''} ${toolsEnabled && actionsEnabled ? ' + ' : ''}
${actionsEnabled ? localize('com_assistants_actions') : ''}`} ${actionsEnabled ? localize('com_assistants_actions') : ''}`}
</label> </label>
<div className="space-y-1"> <div className="space-y-2">
{functions.map((func, i) => ( {functions.map((func, i) => (
<AssistantTool <AssistantTool
key={`${func}-${i}-${assistant_id}`} key={`${func}-${i}-${assistant_id}`}
@ -373,11 +376,12 @@ export default function AssistantPanel({
<AssistantAction key={i} action={action} onClick={() => setAction(action)} /> <AssistantAction key={i} action={action} onClick={() => setAction(action)} />
); );
})} })}
<div className="flex space-x-2">
{toolsEnabled && ( {toolsEnabled && (
<button <button
type="button" type="button"
onClick={() => setShowToolDialog(true)} onClick={() => setShowToolDialog(true)}
className="btn border-token-border-light relative mx-1 mt-2 h-8 rounded-lg bg-transparent font-medium hover:bg-gray-100 dark:hover:bg-gray-800" className="btn btn-neutral border-token-border-light relative h-8 w-full rounded-lg font-medium"
> >
<div className="flex w-full items-center justify-center gap-2"> <div className="flex w-full items-center justify-center gap-2">
{localize('com_assistants_add_tools')} {localize('com_assistants_add_tools')}
@ -397,7 +401,7 @@ export default function AssistantPanel({
} }
setActivePanel(Panel.actions); setActivePanel(Panel.actions);
}} }}
className="btn border-token-border-light relative mt-2 h-8 rounded-lg bg-transparent font-medium hover:bg-gray-100 dark:hover:bg-gray-800" className="btn btn-neutral border-token-border-light relative h-8 w-full rounded-lg font-medium"
> >
<div className="flex w-full items-center justify-center gap-2"> <div className="flex w-full items-center justify-center gap-2">
{localize('com_assistants_add_actions')} {localize('com_assistants_add_actions')}
@ -406,6 +410,7 @@ export default function AssistantPanel({
)} )}
</div> </div>
</div> </div>
</div>
<div className="flex items-center justify-end gap-2"> <div className="flex items-center justify-end gap-2">
{/* Context Button */} {/* Context Button */}
<ContextButton <ContextButton
@ -415,23 +420,9 @@ export default function AssistantPanel({
createMutation={create} createMutation={create}
endpoint={endpoint} endpoint={endpoint}
/> />
{/* Secondary Select Button */}
{assistant_id && (
<button
className="btn btn-secondary"
type="button"
disabled={!assistant_id}
onClick={(e) => {
e.preventDefault();
onSelectAssistant(assistant_id);
}}
>
{localize('com_ui_select')}
</button>
)}
{/* Submit Button */} {/* Submit Button */}
<button <button
className="btn btn-primary focus:shadow-outline flex w-[90px] items-center justify-center px-4 py-2 font-semibold text-white hover:bg-green-600 focus:border-green-500" className="btn btn-primary focus:shadow-outline flex w-full items-center justify-center px-4 py-2 font-semibold text-white hover:bg-green-600 focus:border-green-500"
type="submit" type="submit"
> >
{create.isLoading || update.isLoading ? ( {create.isLoading || update.isLoading ? (

View file

@ -1,5 +1,12 @@
import React, { useState } from 'react';
import { useFormContext } from 'react-hook-form';
import type { TPlugin } from 'librechat-data-provider'; import type { TPlugin } from 'librechat-data-provider';
import GearIcon from '~/components/svg/GearIcon'; import { useUpdateUserPluginsMutation } from 'librechat-data-provider/react-query';
import { OGDialog, OGDialogTrigger, Label } from '~/components/ui';
import OGDialogTemplate from '~/components/ui/OGDialogTemplate';
import { useToastContext } from '~/Providers';
import { TrashIcon } from '~/components/svg';
import { useLocalize } from '~/hooks';
import { cn } from '~/utils'; import { cn } from '~/utils';
export default function AssistantTool({ export default function AssistantTool({
@ -11,20 +18,46 @@ export default function AssistantTool({
allTools: TPlugin[]; allTools: TPlugin[];
assistant_id?: string; assistant_id?: string;
}) { }) {
const [isHovering, setIsHovering] = useState(false);
const localize = useLocalize();
const { showToast } = useToastContext();
const updateUserPlugins = useUpdateUserPluginsMutation();
const { getValues, setValue } = useFormContext();
const currentTool = allTools.find((t) => t.pluginKey === tool); const currentTool = allTools.find((t) => t.pluginKey === tool);
const removeTool = (tool: string) => {
if (tool) {
updateUserPlugins.mutate(
{ pluginKey: tool, action: 'uninstall', auth: null, isAssistantTool: true },
{
onError: (error: unknown) => {
showToast({ message: `Error while deleting the tool: ${error}`, status: 'error' });
},
onSuccess: () => {
const fns = getValues('functions').filter((fn) => fn !== tool);
setValue('functions', fns);
showToast({ message: 'Tool deleted successfully', status: 'success' });
},
},
);
}
};
if (!currentTool) { if (!currentTool) {
return null; return null;
} }
return ( return (
<div> <OGDialog>
<div <div
className={cn( className={cn(
'border-token-border-medium flex w-full rounded-lg border text-sm hover:cursor-pointer', 'flex w-full items-center rounded-lg text-sm',
!assistant_id ? 'opacity-40' : '', !assistant_id ? 'opacity-40' : '',
)} )}
onMouseEnter={() => setIsHovering(true)}
onMouseLeave={() => setIsHovering(false)}
> >
<div className="flex grow items-center">
{currentTool.icon && ( {currentTool.icon && (
<div className="flex h-9 w-9 items-center justify-center overflow-hidden rounded-full"> <div className="flex h-9 w-9 items-center justify-center overflow-hidden rounded-full">
<div <div
@ -39,14 +72,36 @@ export default function AssistantTool({
> >
{currentTool.name} {currentTool.name}
</div> </div>
<div className="w-px bg-gray-300 dark:bg-gray-600" /> </div>
{isHovering && (
<OGDialogTrigger asChild>
<button <button
type="button" type="button"
className="flex h-9 w-9 min-w-9 items-center justify-center rounded-lg rounded-l-none" className="transition-color flex h-9 w-9 min-w-9 items-center justify-center rounded-lg duration-200 hover:bg-gray-200 dark:hover:bg-gray-700"
> >
<GearIcon className="icon-sm" /> <TrashIcon />
</button> </button>
</OGDialogTrigger>
)}
</div> </div>
</div> <OGDialogTemplate
showCloseButton={false}
title={localize('com_ui_delete_tool')}
mainClassName="px-0"
className="max-w-[450px]"
main={
<Label className="text-left text-sm font-medium">
{localize('com_ui_delete_tool_confirm')}
</Label>
}
selection={{
selectHandler: () => removeTool(currentTool.pluginKey),
selectClasses:
'bg-red-700 dark:bg-red-600 hover:bg-red-800 dark:hover:bg-red-800 transition-color duration-200 text-white',
selectText: localize('com_ui_delete'),
}}
/>
</OGDialog>
); );
} }

View file

@ -1,9 +1,12 @@
import { useMemo } from 'react'; import { useMemo } from 'react';
import { Capabilities } from 'librechat-data-provider'; import { Capabilities } from 'librechat-data-provider';
import { useFormContext, useWatch } from 'react-hook-form';
import type { TConfig, AssistantsEndpoint } from 'librechat-data-provider'; import type { TConfig, AssistantsEndpoint } from 'librechat-data-provider';
import type { AssistantForm } from '~/common';
import ImageVision from './ImageVision'; import ImageVision from './ImageVision';
import { useLocalize } from '~/hooks'; import { useLocalize } from '~/hooks';
import Retrieval from './Retrieval'; import Retrieval from './Retrieval';
import CodeFiles from './CodeFiles';
import Code from './Code'; import Code from './Code';
export default function CapabilitiesForm({ export default function CapabilitiesForm({
@ -21,6 +24,17 @@ export default function CapabilitiesForm({
}) { }) {
const localize = useLocalize(); const localize = useLocalize();
const methods = useFormContext<AssistantForm>();
const { control } = methods;
const assistant = useWatch({ control, name: 'assistant' });
const assistant_id = useWatch({ control, name: 'id' });
const files = useMemo(() => {
if (typeof assistant === 'string') {
return [];
}
return assistant.code_files;
}, [assistant]);
const retrievalModels = useMemo( const retrievalModels = useMemo(
() => new Set(assistantsConfig?.retrievalModels ?? []), () => new Set(assistantsConfig?.retrievalModels ?? []),
[assistantsConfig], [assistantsConfig],
@ -31,7 +45,7 @@ export default function CapabilitiesForm({
); );
return ( return (
<div className="mb-6"> <div className="mb-4">
<div className="mb-1.5 flex items-center"> <div className="mb-1.5 flex items-center">
<span> <span>
<label className="text-token-text-primary block font-medium"> <label className="text-token-text-primary block font-medium">
@ -40,11 +54,19 @@ export default function CapabilitiesForm({
</span> </span>
</div> </div>
<div className="flex flex-col items-start gap-2"> <div className="flex flex-col items-start gap-2">
{codeEnabled && <Code endpoint={endpoint} version={version} />} {codeEnabled && <Code version={version} />}
{imageVisionEnabled && version == 1 && <ImageVision />}
{retrievalEnabled && ( {retrievalEnabled && (
<Retrieval endpoint={endpoint} version={version} retrievalModels={retrievalModels} /> <Retrieval endpoint={endpoint} version={version} retrievalModels={retrievalModels} />
)} )}
{imageVisionEnabled && version == 1 && <ImageVision />}
{codeEnabled && version && (
<CodeFiles
assistant_id={assistant_id}
version={version}
endpoint={endpoint}
files={files}
/>
)}
</div> </div>
</div> </div>
); );

View file

@ -1,33 +1,25 @@
import { useMemo } from 'react';
import { Capabilities } from 'librechat-data-provider'; import { Capabilities } from 'librechat-data-provider';
import { useFormContext, Controller, useWatch } from 'react-hook-form'; import { useFormContext, Controller } from 'react-hook-form';
import type { AssistantsEndpoint } from 'librechat-data-provider';
import type { AssistantForm } from '~/common'; import type { AssistantForm } from '~/common';
import { Checkbox, QuestionMark } from '~/components/ui'; import {
Checkbox,
HoverCard,
HoverCardContent,
HoverCardPortal,
HoverCardTrigger,
} from '~/components/ui';
import { CircleHelpIcon } from '~/components/svg';
import { useLocalize } from '~/hooks'; import { useLocalize } from '~/hooks';
import CodeFiles from './CodeFiles'; import { ESide } from '~/common';
export default function Code({ export default function Code({ version }: { version: number | string }) {
version,
endpoint,
}: {
version: number | string;
endpoint: AssistantsEndpoint;
}) {
const localize = useLocalize(); const localize = useLocalize();
const methods = useFormContext<AssistantForm>(); const methods = useFormContext<AssistantForm>();
const { control, setValue, getValues } = methods; const { control, setValue, getValues } = methods;
const assistant = useWatch({ control, name: 'assistant' });
const assistant_id = useWatch({ control, name: 'id' });
const files = useMemo(() => {
if (typeof assistant === 'string') {
return [];
}
return assistant.code_files;
}, [assistant]);
return ( return (
<> <>
<HoverCard openDelay={50}>
<div className="flex items-center"> <div className="flex items-center">
<Controller <Controller
name={Capabilities.code_interpreter} name={Capabilities.code_interpreter}
@ -42,6 +34,7 @@ export default function Code({
/> />
)} )}
/> />
<div className="flex items-center space-x-2">
<label <label
className="form-check-label text-token-text-primary w-full cursor-pointer" className="form-check-label text-token-text-primary w-full cursor-pointer"
htmlFor={Capabilities.code_interpreter} htmlFor={Capabilities.code_interpreter}
@ -51,20 +44,23 @@ export default function Code({
}) })
} }
> >
<div className="flex select-none items-center">
{localize('com_assistants_code_interpreter')} {localize('com_assistants_code_interpreter')}
<QuestionMark />
</div>
</label> </label>
<HoverCardTrigger>
<CircleHelpIcon className="h-5 w-5 text-gray-500" />
</HoverCardTrigger>
</div> </div>
{version == 2 && ( <HoverCardPortal>
<CodeFiles <HoverCardContent side={ESide.Top} className="w-80">
assistant_id={assistant_id} <div className="space-y-2">
version={version} <p className="text-sm text-gray-600 dark:text-gray-300">
endpoint={endpoint} {version == 2 && localize('com_assistants_code_interpreter_info')}
files={files} </p>
/> </div>
)} </HoverCardContent>
</HoverCardPortal>
</div>
</HoverCard>
</> </>
); );
} }

View file

@ -58,7 +58,7 @@ export default function CodeFiles({
}; };
return ( return (
<div className={'mb-2'}> <div className="mb-2 w-full">
<div className="flex flex-col gap-4"> <div className="flex flex-col gap-4">
<div className="text-token-text-tertiary rounded-lg text-xs"> <div className="text-token-text-tertiary rounded-lg text-xs">
{localize('com_assistants_code_interpreter_files')} {localize('com_assistants_code_interpreter_files')}
@ -75,7 +75,7 @@ export default function CodeFiles({
<button <button
type="button" type="button"
disabled={!assistant_id} disabled={!assistant_id}
className="btn btn-neutral border-token-border-light relative h-8 rounded-lg font-medium" className="btn btn-neutral border-token-border-light relative h-8 w-full rounded-lg font-medium"
onClick={handleButtonClick} onClick={handleButtonClick}
> >
<div className="flex w-full items-center justify-center gap-2"> <div className="flex w-full items-center justify-center gap-2">

View file

@ -1,4 +1,3 @@
import * as Popover from '@radix-ui/react-popover';
import type { Assistant, AssistantCreateParams, AssistantsEndpoint } from 'librechat-data-provider'; import type { Assistant, AssistantCreateParams, AssistantsEndpoint } from 'librechat-data-provider';
import type { UseMutationResult } from '@tanstack/react-query'; import type { UseMutationResult } from '@tanstack/react-query';
import { Dialog, DialogTrigger, Label } from '~/components/ui'; import { Dialog, DialogTrigger, Label } from '~/components/ui';
@ -7,7 +6,7 @@ import { useDeleteAssistantMutation } from '~/data-provider';
import DialogTemplate from '~/components/ui/DialogTemplate'; import DialogTemplate from '~/components/ui/DialogTemplate';
import { useLocalize, useSetIndexOptions } from '~/hooks'; import { useLocalize, useSetIndexOptions } from '~/hooks';
import { cn, removeFocusOutlines } from '~/utils/'; import { cn, removeFocusOutlines } from '~/utils/';
import { NewTrashIcon } from '~/components/svg'; import { TrashIcon } from '~/components/svg';
export default function ContextButton({ export default function ContextButton({
activeModel, activeModel,
@ -78,66 +77,19 @@ export default function ContextButton({
return ( return (
<Dialog> <Dialog>
<Popover.Root> <DialogTrigger asChild>
<Popover.Trigger asChild>
<button <button
className={cn( className={cn(
'btn border-token-border-light relative h-9 rounded-lg bg-transparent font-medium hover:bg-gray-100 dark:hover:bg-gray-800', 'btn btn-neutral border-token-border-light relative h-9 rounded-lg font-medium',
removeFocusOutlines, removeFocusOutlines,
)} )}
type="button" type="button"
> >
<div className="flex w-full items-center justify-center gap-2"> <div className="flex w-full items-center justify-center gap-2 text-red-500">
<svg <TrashIcon />
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className="icon-md"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M3 12C3 10.8954 3.89543 10 5 10C6.10457 10 7 10.8954 7 12C7 13.1046 6.10457 14 5 14C3.89543 14 3 13.1046 3 12ZM10 12C10 10.8954 10.8954 10 12 10C13.1046 10 14 10.8954 14 12C14 13.1046 13.1046 14 12 14C10.8954 14 10 13.1046 10 12ZM17 12C17 10.8954 17.8954 10 19 10C20.1046 10 21 10.8954 21 12C21 13.1046 20.1046 14 19 14C17.8954 14 17 13.1046 17 12Z"
fill="currentColor"
/>
</svg>
</div> </div>
</button> </button>
</Popover.Trigger>
<div
style={{
position: 'fixed',
left: ' 0px',
top: ' 0px',
transform: 'translate(1772.8px, 49.6px)',
minWidth: 'max-content',
zIndex: 'auto',
}}
dir="ltr"
>
<Popover.Content
side="top"
role="menu"
className="bg-token-surface-primary min-w-[180px] max-w-xs rounded-lg border border-gray-100 bg-white shadow-lg dark:border-gray-900 dark:bg-gray-850"
style={{ outline: 'none', pointerEvents: 'auto' }}
sideOffset={8}
tabIndex={-1}
align="end"
>
<DialogTrigger asChild>
<Popover.Close
role="menuitem"
className="group m-1.5 flex w-full cursor-pointer gap-2 rounded p-2.5 text-sm text-red-500 hover:bg-black/5 focus:ring-0 radix-disabled:pointer-events-none radix-disabled:opacity-50 dark:hover:bg-white/5"
tabIndex={-1}
>
<NewTrashIcon />
{localize('com_ui_delete') + ' ' + localize('com_ui_assistant')}
</Popover.Close>
</DialogTrigger> </DialogTrigger>
</Popover.Content>
</div>
<DialogTemplate <DialogTemplate
title={localize('com_ui_delete') + ' ' + localize('com_ui_assistant')} title={localize('com_ui_delete') + ' ' + localize('com_ui_assistant')}
className="max-w-[450px]" className="max-w-[450px]"
@ -159,7 +111,6 @@ export default function ContextButton({
selectText: localize('com_ui_delete'), selectText: localize('com_ui_delete'),
}} }}
/> />
</Popover.Root>
</Dialog> </Dialog>
); );
} }

View file

@ -33,10 +33,7 @@ export default function ImageVision() {
}) })
} }
> >
<div className="flex items-center"> <div className="flex items-center">{localize('com_assistants_image_vision')}</div>
{localize('com_assistants_image_vision')}
<QuestionMark />
</div>
</label> </label>
</div> </div>
); );

View file

@ -1,10 +1,17 @@
import { useEffect, useMemo } from 'react'; import { useEffect, useMemo } from 'react';
import { useFormContext, Controller, useWatch } from 'react-hook-form';
import { Capabilities } from 'librechat-data-provider'; import { Capabilities } from 'librechat-data-provider';
import type { AssistantsEndpoint } from 'librechat-data-provider'; import type { AssistantsEndpoint } from 'librechat-data-provider';
import type { AssistantForm } from '~/common'; import { useFormContext, Controller, useWatch } from 'react-hook-form';
import {
Checkbox,
HoverCard,
HoverCardContent,
HoverCardPortal,
HoverCardTrigger,
} from '~/components/ui';
import OptionHover from '~/components/SidePanel/Parameters/OptionHover'; import OptionHover from '~/components/SidePanel/Parameters/OptionHover';
import { Checkbox, HoverCard, HoverCardTrigger } from '~/components/ui'; import { CircleHelpIcon } from '~/components/svg';
import type { AssistantForm } from '~/common';
import { useLocalize } from '~/hooks'; import { useLocalize } from '~/hooks';
import { ESide } from '~/common'; import { ESide } from '~/common';
import { cn } from '~/utils/'; import { cn } from '~/utils/';
@ -40,6 +47,7 @@ export default function Retrieval({
return ( return (
<> <>
<HoverCard openDelay={50}>
<div className="flex items-center"> <div className="flex items-center">
<Controller <Controller
name={Capabilities.retrieval} name={Capabilities.retrieval}
@ -55,8 +63,7 @@ export default function Retrieval({
/> />
)} )}
/> />
<HoverCard openDelay={50}> <div className="flex items-center space-x-2">
<HoverCardTrigger asChild>
<label <label
className={cn( className={cn(
'form-check-label text-token-text-primary w-full select-none', 'form-check-label text-token-text-primary w-full select-none',
@ -74,21 +81,29 @@ export default function Retrieval({
? localize('com_assistants_retrieval') ? localize('com_assistants_retrieval')
: localize('com_assistants_file_search')} : localize('com_assistants_file_search')}
</label> </label>
<HoverCardTrigger>
<CircleHelpIcon className="h-5 w-5 text-gray-500" />
</HoverCardTrigger> </HoverCardTrigger>
</div>
<HoverCardPortal>
<HoverCardContent side={ESide.Top} disabled={isDisabled} className="ml-16 w-80">
<div className="space-y-2">
<p className="text-sm text-gray-600 dark:text-gray-300">
{version == 2 && localize('com_assistants_file_search_info')}
</p>
</div>
</HoverCardContent>
</HoverCardPortal>
<OptionHover <OptionHover
side={ESide.Top} side={ESide.Top}
disabled={!isDisabled} disabled={!isDisabled}
description="com_assistants_non_retrieval_model" description="com_assistants_non_retrieval_model"
langCode={true} langCode={true}
sideOffset={20} sideOffset={20}
className="ml-16"
/> />
</div>
</HoverCard> </HoverCard>
</div>
{version == 2 && (
<div className="text-token-text-tertiary rounded-lg text-xs">
{localize('com_assistants_file_search_info')}
</div>
)}
</> </>
); );
} }

View file

@ -9,6 +9,7 @@ type TOptionHoverProps = {
sideOffset?: number; sideOffset?: number;
disabled?: boolean; disabled?: boolean;
side: ESide; side: ESide;
className?: string;
}; };
function OptionHover({ function OptionHover({
@ -17,6 +18,7 @@ function OptionHover({
disabled, disabled,
langCode, langCode,
sideOffset = 30, sideOffset = 30,
className,
}: TOptionHoverProps) { }: TOptionHoverProps) {
const localize = useLocalize(); const localize = useLocalize();
if (disabled) { if (disabled) {
@ -25,11 +27,7 @@ function OptionHover({
const text = langCode ? localize(description) : description; const text = langCode ? localize(description) : description;
return ( return (
<HoverCardPortal> <HoverCardPortal>
<HoverCardContent <HoverCardContent side={side} className={`z-[999] w-80 ${className}`} sideOffset={sideOffset}>
side={side}
className="z-[999] w-80 dark:bg-gray-700"
sideOffset={sideOffset}
>
<div className="space-y-2"> <div className="space-y-2">
<p className="text-sm text-gray-600 dark:text-gray-300">{text}</p> <p className="text-sm text-gray-600 dark:text-gray-300">{text}</p>
</div> </div>

View file

@ -1,19 +0,0 @@
export default function NewTrashIcon({ className = 'icon-md' }) {
return (
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className={className}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M10.5555 4C10.099 4 9.70052 4.30906 9.58693 4.75114L9.29382 5.8919H14.715L14.4219 4.75114C14.3083 4.30906 13.9098 4 13.4533 4H10.5555ZM16.7799 5.8919L16.3589 4.25342C16.0182 2.92719 14.8226 2 13.4533 2H10.5555C9.18616 2 7.99062 2.92719 7.64985 4.25342L7.22886 5.8919H4C3.44772 5.8919 3 6.33961 3 6.8919C3 7.44418 3.44772 7.8919 4 7.8919H4.10069L5.31544 19.3172C5.47763 20.8427 6.76455 22 8.29863 22H15.7014C17.2354 22 18.5224 20.8427 18.6846 19.3172L19.8993 7.8919H20C20.5523 7.8919 21 7.44418 21 6.8919C21 6.33961 20.5523 5.8919 20 5.8919H16.7799ZM17.888 7.8919H6.11196L7.30423 19.1057C7.3583 19.6142 7.78727 20 8.29863 20H15.7014C16.2127 20 16.6417 19.6142 16.6958 19.1057L17.888 7.8919ZM10 10C10.5523 10 11 10.4477 11 11V16C11 16.5523 10.5523 17 10 17C9.44772 17 9 16.5523 9 16V11C9 10.4477 9.44772 10 10 10ZM14 10C14.5523 10 15 10.4477 15 11V16C15 16.5523 14.5523 17 14 17C13.4477 17 13 16.5523 13 16V11C13 10.4477 13.4477 10 14 10Z"
fill="currentColor"
/>
</svg>
);
}

View file

@ -1,6 +1,10 @@
import { cn } from '~/utils'; import { cn } from '~/utils';
export default function TrashIcon({ className = '' }) { type TrashIconProps = {
className?: string;
};
export default function TrashIcon({ className = '' }: TrashIconProps) {
return ( return (
<svg <svg
fill="none" fill="none"
@ -8,7 +12,7 @@ export default function TrashIcon({ className = '' }) {
viewBox="0 0 24 24" viewBox="0 0 24 24"
strokeLinecap="round" strokeLinecap="round"
strokeLinejoin="round" strokeLinejoin="round"
className={cn('icon-md', className)} className={cn('icon-md h-4 w-4', className)}
height="1em" height="1em"
width="1em" width="1em"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"

View file

@ -29,7 +29,6 @@ export { default as DotsIcon } from './DotsIcon';
export { default as GearIcon } from './GearIcon'; export { default as GearIcon } from './GearIcon';
export { default as PinIcon } from './PinIcon'; export { default as PinIcon } from './PinIcon';
export { default as TrashIcon } from './TrashIcon'; export { default as TrashIcon } from './TrashIcon';
export { default as NewTrashIcon } from './NewTrashIcon';
export { default as MinimalPlugin } from './MinimalPlugin'; export { default as MinimalPlugin } from './MinimalPlugin';
export { default as AzureMinimalIcon } from './AzureMinimalIcon'; export { default as AzureMinimalIcon } from './AzureMinimalIcon';
export { default as OpenAIMinimalIcon } from './OpenAIMinimalIcon'; export { default as OpenAIMinimalIcon } from './OpenAIMinimalIcon';

View file

@ -11,8 +11,13 @@ const HoverCardPortal = HoverCardPrimitive.Portal;
const HoverCardContent = React.forwardRef< const HoverCardContent = React.forwardRef<
React.ElementRef<typeof HoverCardPrimitive.Content>, React.ElementRef<typeof HoverCardPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof HoverCardPrimitive.Content> React.ComponentPropsWithoutRef<typeof HoverCardPrimitive.Content> & { disabled?: boolean }
>(({ className = '', align = 'center', sideOffset = 6, ...props }, ref) => ( >(({ className = '', align = 'center', sideOffset = 6, disabled = false, ...props }, ref) => {
if (disabled) {
return null;
}
return (
<HoverCardPrimitive.Content <HoverCardPrimitive.Content
ref={ref} ref={ref}
align={align} align={align}
@ -23,7 +28,8 @@ const HoverCardContent = React.forwardRef<
)} )}
{...props} {...props}
/> />
)); );
});
HoverCardContent.displayName = HoverCardPrimitive.Content.displayName; HoverCardContent.displayName = HoverCardPrimitive.Content.displayName;
export { HoverCard, HoverCardTrigger, HoverCardContent, HoverCardPortal }; export { HoverCard, HoverCardTrigger, HoverCardContent, HoverCardPortal };

View file

@ -0,0 +1,95 @@
import { forwardRef, ReactNode, Ref } from 'react';
import {
OGDialogTitle,
OGDialogClose,
OGDialogFooter,
OGDialogHeader,
OGDialogContent,
OGDialogDescription,
} from './';
import { useLocalize } from '~/hooks';
import { cn } from '~/utils/';
type SelectionProps = {
selectHandler?: () => void;
selectClasses?: string;
selectText?: string;
};
type DialogTemplateProps = {
title: string;
description?: string;
main?: ReactNode;
buttons?: ReactNode;
leftButtons?: ReactNode;
selection?: SelectionProps;
className?: string;
headerClassName?: string;
mainClassName?: string;
footerClassName?: string;
showCloseButton?: boolean;
showCancelButton?: boolean;
};
const OGDialogTemplate = forwardRef((props: DialogTemplateProps, ref: Ref<HTMLDivElement>) => {
const localize = useLocalize();
const {
title,
main,
buttons,
selection,
className,
leftButtons,
description,
mainClassName,
headerClassName,
footerClassName,
showCloseButton,
showCancelButton = true,
} = props;
const { selectHandler, selectClasses, selectText } = selection || {};
const Cancel = localize('com_ui_cancel');
const defaultSelect =
'bg-gray-800 text-white transition-colors hover:bg-gray-700 disabled:cursor-not-allowed disabled:opacity-50 dark:bg-gray-200 dark:text-gray-800 dark:hover:bg-gray-200';
return (
<OGDialogContent
showCloseButton={showCloseButton}
ref={ref}
className={cn(
'bg-white dark:border-gray-700 dark:bg-gray-850 dark:text-gray-300',
className || '',
)}
onClick={(e) => e.stopPropagation()}
>
<OGDialogHeader className={cn(headerClassName ?? '')}>
<OGDialogTitle>{title}</OGDialogTitle>
{description && <OGDialogDescription className="">{description}</OGDialogDescription>}
</OGDialogHeader>
<div className={cn('px-6', mainClassName)}>{main ? main : null}</div>
<OGDialogFooter className={footerClassName}>
<div>{leftButtons ? leftButtons : null}</div>
<div className="flex h-auto gap-3">
{showCancelButton && (
<OGDialogClose className="btn btn-neutral border-token-border-light relative rounded-lg text-sm">
{Cancel}
</OGDialogClose>
)}
{buttons ? buttons : null}
{selection ? (
<OGDialogClose
onClick={selectHandler}
className={`${
selectClasses || defaultSelect
} inline-flex h-10 items-center justify-center rounded-lg border-none px-4 py-2 text-sm`}
>
{selectText}
</OGDialogClose>
) : null}
</div>
</OGDialogFooter>
</OGDialogContent>
);
});
export default OGDialogTemplate;

View file

@ -26,10 +26,15 @@ const DialogOverlay = React.forwardRef<
)); ));
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName; DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
type DialogContentProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> & {
showCloseButton?: boolean;
disableScroll?: boolean;
};
const DialogContent = React.forwardRef< const DialogContent = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Content>, React.ElementRef<typeof DialogPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> DialogContentProps
>(({ className, children, ...props }, ref) => ( >(({ className, showCloseButton = true, children, ...props }, ref) => (
<DialogPortal> <DialogPortal>
<DialogOverlay /> <DialogOverlay />
<DialogPrimitive.Content <DialogPrimitive.Content
@ -41,10 +46,12 @@ const DialogContent = React.forwardRef<
{...props} {...props}
> >
{children} {children}
{showCloseButton && (
<DialogPrimitive.Close className="ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute right-4 top-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:pointer-events-none"> <DialogPrimitive.Close className="ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute right-4 top-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:pointer-events-none">
<X className="h-4 w-4" /> <X className="h-4 w-4" />
<span className="sr-only">Close</span> <span className="sr-only">Close</span>
</DialogPrimitive.Close> </DialogPrimitive.Close>
)}
</DialogPrimitive.Content> </DialogPrimitive.Content>
</DialogPortal> </DialogPortal>
)); ));

View file

@ -22,7 +22,9 @@ export default {
com_assistants_capabilities: 'Capabilities', com_assistants_capabilities: 'Capabilities',
com_assistants_file_search: 'File Search', com_assistants_file_search: 'File Search',
com_assistants_file_search_info: com_assistants_file_search_info:
'Attaching vector stores for File Search is not yet supported. You can attach them from the Provider Playground or attach files to messages for file search on a thread basis.', 'File search enables the assistant with knowledge from files that you or your users upload. Once a file is uploaded, the assistant automatically decides when to retrieve content based on user requests. Attaching vector stores for File Search is not yet supported. You can attach them from the Provider Playground or attach files to messages for file search on a thread basis.',
com_assistants_code_interpreter_info:
'Code Interpreter enables the assistant to write and run code. This tool can process files with diverse data and formatting, and generate files such as graphs.',
com_assistants_knowledge: 'Knowledge', com_assistants_knowledge: 'Knowledge',
com_assistants_knowledge_info: com_assistants_knowledge_info:
'If you upload files under Knowledge, conversations with your Assistant may include file contents.', 'If you upload files under Knowledge, conversations with your Assistant may include file contents.',
@ -30,8 +32,7 @@ export default {
'Assistant must be created, and Code Interpreter or Retrieval must be enabled and saved before uploading files as Knowledge.', 'Assistant must be created, and Code Interpreter or Retrieval must be enabled and saved before uploading files as Knowledge.',
com_assistants_image_vision: 'Image Vision', com_assistants_image_vision: 'Image Vision',
com_assistants_code_interpreter: 'Code Interpreter', com_assistants_code_interpreter: 'Code Interpreter',
com_assistants_code_interpreter_files: com_assistants_code_interpreter_files: 'Files below are for Code Interpreter only:',
'The following files are only available for Code Interpreter:',
com_assistants_retrieval: 'Retrieval', com_assistants_retrieval: 'Retrieval',
com_assistants_search_name: 'Search assistants by name', com_assistants_search_name: 'Search assistants by name',
com_assistants_tools: 'Tools', com_assistants_tools: 'Tools',
@ -266,6 +267,10 @@ export default {
com_ui_shared_link_not_found: 'Shared link not found', com_ui_shared_link_not_found: 'Shared link not found',
com_ui_delete_conversation: 'Delete chat?', com_ui_delete_conversation: 'Delete chat?',
com_ui_delete_confirm: 'This will delete', com_ui_delete_confirm: 'This will delete',
com_ui_delete_tool: 'Delete Tool',
com_ui_delete_tool_confirm: 'Are you sure you want to delete this tool?',
com_ui_delete_action: 'Delete Action',
com_ui_delete_action_confirm: 'Are you sure you want to delete this action?',
com_ui_delete_confirm_prompt_version_var: com_ui_delete_confirm_prompt_version_var:
'This will delete the selected version for "{0}." If no other versions exist, the prompt will be deleted.', 'This will delete the selected version for "{0}." If no other versions exist, the prompt will be deleted.',
com_ui_delete_assistant_confirm: com_ui_delete_assistant_confirm:

File diff suppressed because it is too large Load diff