mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-01-16 23:45:33 +01:00
Move data provider to shared package (#582)
* create data-provider package and move code from data-provider folder to be shared between apps * fix type issues * add packages to ignore * add new data-provider package to apps * refactor: change client imports to use @librechat/data-provider package * include data-provider build script in frontend build * fix type issue after rebasing * delete admin/package.json from this branch * update test ci script to include building of data-provider package * Try using regular build for test action * Switch frontend-review back to build:ci * Remove loginRedirect from Login.tsx * Add ChatGPT back to EModelEndpoint
This commit is contained in:
parent
d0078d478d
commit
04e4259005
48 changed files with 1472 additions and 141 deletions
|
|
@ -2,7 +2,7 @@ import { useEffect } from 'react';
|
|||
import LoginForm from './LoginForm';
|
||||
import { useAuthContext } from '~/hooks/AuthContext';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useGetStartupConfig } from '~/data-provider';
|
||||
import { useGetStartupConfig } from '@librechat/data-provider';
|
||||
|
||||
function Login() {
|
||||
const { login, error, isAuthenticated } = useAuthContext();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { useForm } from 'react-hook-form';
|
||||
import { TLoginUser } from '~/data-provider';
|
||||
import { TLoginUser } from '@librechat/data-provider';
|
||||
|
||||
type TLoginFormProps = {
|
||||
onSubmit: (data: TLoginUser) => void;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,11 @@
|
|||
import { useState, useEffect } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useRegisterUserMutation, TRegisterUser, useGetStartupConfig } from '~/data-provider';
|
||||
import {
|
||||
useRegisterUserMutation,
|
||||
TRegisterUser,
|
||||
useGetStartupConfig
|
||||
} from '@librechat/data-provider';
|
||||
|
||||
function Registration() {
|
||||
const navigate = useNavigate();
|
||||
|
|
@ -27,7 +31,9 @@ function Registration() {
|
|||
},
|
||||
onError: (error) => {
|
||||
setError(true);
|
||||
//@ts-ignore - error is of type unknown
|
||||
if (error.response?.data?.message) {
|
||||
//@ts-ignore - error is of type unknown
|
||||
setErrorMessage(error.response?.data?.message);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
import { useState } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useRequestPasswordResetMutation, TRequestPasswordReset } from '~/data-provider';
|
||||
import {
|
||||
useRequestPasswordResetMutation,
|
||||
TRequestPasswordReset,
|
||||
TRequestPasswordResetResponse
|
||||
} from '@librechat/data-provider';
|
||||
|
||||
function RequestPasswordReset() {
|
||||
const {
|
||||
|
|
@ -15,7 +19,7 @@ function RequestPasswordReset() {
|
|||
|
||||
const onSubmit = (data: TRequestPasswordReset) => {
|
||||
requestPasswordReset.mutate(data, {
|
||||
onSuccess: (data) => {
|
||||
onSuccess: (data: TRequestPasswordResetResponse) => {
|
||||
setSuccess(true);
|
||||
setResetLink(data.link);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { useState } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useResetPasswordMutation, TResetPassword } from '~/data-provider';
|
||||
import { useResetPasswordMutation, TResetPassword } from '@librechat/data-provider';
|
||||
import { useNavigate, useSearchParams } from 'react-router-dom';
|
||||
|
||||
function ResetPassword() {
|
||||
|
|
@ -73,12 +73,14 @@ function ResetPassword() {
|
|||
<input
|
||||
type="hidden"
|
||||
id="token"
|
||||
// @ts-ignore - Type 'string | null' is not assignable to type 'string | number | readonly string[] | undefined'
|
||||
value={params.get('token')}
|
||||
{...register('token', { required: 'Unable to process: No valid reset token' })}
|
||||
/>
|
||||
<input
|
||||
type="hidden"
|
||||
id="userId"
|
||||
// @ts-ignore - Type 'string | null' is not assignable to type 'string | number | readonly string[] | undefined'
|
||||
value={params.get('userId')}
|
||||
{...register('userId', { required: 'Unable to process: No valid user id' })}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { render, waitFor } from 'layout-test-utils';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import Login from '../Login';
|
||||
import * as mockDataProvider from '~/data-provider';
|
||||
import * as mockDataProvider from '@librechat/data-provider';
|
||||
|
||||
jest.mock('~/data-provider');
|
||||
jest.mock('@librechat/data-provider');
|
||||
|
||||
const setup = ({
|
||||
useGetUserQueryReturnValue = {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { render, waitFor } from 'layout-test-utils';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import Registration from '../Registration';
|
||||
import * as mockDataProvider from '~/data-provider';
|
||||
import * as mockDataProvider from '@librechat/data-provider';
|
||||
|
||||
jest.mock('~/data-provider');
|
||||
jest.mock('@librechat/data-provider');
|
||||
|
||||
const setup = ({
|
||||
useGetUserQueryReturnValue = {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { useState, useRef, useEffect } from 'react';
|
||||
import { useRecoilState, useSetRecoilState } from 'recoil';
|
||||
import { useUpdateConversationMutation } from '~/data-provider';
|
||||
import { useUpdateConversationMutation } from '@librechat/data-provider';
|
||||
import RenameButton from './RenameButton';
|
||||
import DeleteButton from './DeleteButton';
|
||||
import ConvoIcon from '../svg/ConvoIcon';
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { useEffect } from 'react';
|
|||
import TrashIcon from '../svg/TrashIcon';
|
||||
import CrossIcon from '../svg/CrossIcon';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { useDeleteConversationMutation } from '~/data-provider';
|
||||
import { useDeleteConversationMutation } from '@librechat/data-provider';
|
||||
|
||||
import store from '~/store';
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { Checkbox } from '~/components/ui/Checkbox.tsx';
|
|||
import SelectDropDown from '../../ui/SelectDropDown';
|
||||
import { cn } from '~/utils/';
|
||||
import useDebounce from '~/hooks/useDebounce';
|
||||
import { useUpdateTokenCountMutation } from '~/data-provider';
|
||||
import { useUpdateTokenCountMutation } from '@librechat/data-provider';
|
||||
|
||||
const defaultTextProps =
|
||||
'rounded-md border border-gray-200 focus:border-slate-400 focus:bg-gray-50 bg-transparent text-sm shadow-[0_0_10px_rgba(0,0,0,0.05)] outline-none placeholder:text-gray-400 focus:outline-none focus:ring-gray-400 focus:ring-opacity-20 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:border-gray-500 dark:bg-gray-700 focus:dark:bg-gray-600 dark:text-gray-50 dark:shadow-[0_0_15px_rgba(0,0,0,0.10)] dark:focus:border-gray-400 dark:focus:outline-none dark:focus:ring-0 dark:focus:ring-gray-400 dark:focus:ring-offset-0';
|
||||
|
|
@ -43,7 +43,7 @@ function Settings(props) {
|
|||
}, [debouncedContext]);
|
||||
|
||||
return (
|
||||
<div className="md:h-[350px] h-[490px] overflow-y-auto">
|
||||
<div className="h-[490px] overflow-y-auto md:h-[350px]">
|
||||
<div className="grid gap-6 sm:grid-cols-2">
|
||||
<div className="col-span-1 flex flex-col items-center justify-start gap-6">
|
||||
<div className="grid w-full items-center gap-2">
|
||||
|
|
@ -113,7 +113,8 @@ function Settings(props) {
|
|||
<a
|
||||
href="https://github.com/danny-avila/LibreChat/blob/main/client/defaultSystemMessage.md"
|
||||
target="_blank"
|
||||
className="text-blue-500 transition-colors duration-200 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-500" rel="noreferrer"
|
||||
className="text-blue-500 transition-colors duration-200 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-500"
|
||||
rel="noreferrer"
|
||||
>
|
||||
System Message
|
||||
</a>{' '}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import {Dialog, DialogTemplate, Input, Label} from '../ui/';
|
||||
import { Dialog, DialogTemplate, Input, Label } from '../ui/';
|
||||
import { cn } from '~/utils/';
|
||||
import cleanupPreset from '~/utils/cleanupPreset';
|
||||
import { useCreatePresetMutation } from '~/data-provider';
|
||||
import { useCreatePresetMutation } from '@librechat/data-provider';
|
||||
import store from '~/store';
|
||||
|
||||
const SaveAsPresetDialog = ({ open, onOpenChange, preset }) => {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import React from 'react';
|
||||
import { useGetStartupConfig } from '~/data-provider';
|
||||
import { useGetStartupConfig } from '@librechat/data-provider';
|
||||
|
||||
export default function Footer() {
|
||||
const { data: config } = useGetStartupConfig();
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import { Trash2 } from 'lucide-react';
|
|||
import FileUpload from './FileUpload';
|
||||
import getIcon from '~/utils/getIcon';
|
||||
import getDefaultConversation from '~/utils/getDefaultConversation';
|
||||
import { useDeletePresetMutation, useCreatePresetMutation } from '~/data-provider';
|
||||
import { useDeletePresetMutation, useCreatePresetMutation } from '@librechat/data-provider';
|
||||
import {
|
||||
Button,
|
||||
DropdownMenu,
|
||||
|
|
@ -19,7 +19,8 @@ import {
|
|||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
DialogTemplate,
|
||||
Dialog, DialogTrigger
|
||||
Dialog,
|
||||
DialogTrigger
|
||||
} from '../../ui/';
|
||||
import { cn } from '~/utils/';
|
||||
|
||||
|
|
@ -87,8 +88,9 @@ export default function NewConversationMenu() {
|
|||
// set the current model
|
||||
const onSelectEndpoint = (newEndpoint) => {
|
||||
setMenuOpen(false);
|
||||
if (!newEndpoint) { return; }
|
||||
else {
|
||||
if (!newEndpoint) {
|
||||
return;
|
||||
} else {
|
||||
newConversation({}, { endpoint: newEndpoint });
|
||||
}
|
||||
};
|
||||
|
|
@ -101,7 +103,7 @@ export default function NewConversationMenu() {
|
|||
const currentConvo = getDefaultConversation({
|
||||
conversation,
|
||||
endpointsConfig,
|
||||
preset: newPreset,
|
||||
preset: newPreset
|
||||
});
|
||||
|
||||
setConversation(currentConvo);
|
||||
|
|
@ -153,7 +155,7 @@ export default function NewConversationMenu() {
|
|||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent
|
||||
className="w-96 dark:bg-gray-900 z-[100]"
|
||||
className="z-[100] w-96 dark:bg-gray-900"
|
||||
onCloseAutoFocus={(event) => event.preventDefault()}
|
||||
>
|
||||
<DropdownMenuLabel
|
||||
|
|
@ -166,11 +168,15 @@ export default function NewConversationMenu() {
|
|||
<DropdownMenuRadioGroup
|
||||
value={endpoint}
|
||||
onValueChange={onSelectEndpoint}
|
||||
className="overflow-y-auto gap-1 flex flex-col"
|
||||
className="flex flex-col gap-1 overflow-y-auto"
|
||||
>
|
||||
{showEndpoints &&
|
||||
(availableEndpoints.length ? (
|
||||
<EndpointItems selectedEndpoint={endpoint} endpoints={availableEndpoints} onSelect={onSelectEndpoint} />
|
||||
<EndpointItems
|
||||
selectedEndpoint={endpoint}
|
||||
endpoints={availableEndpoints}
|
||||
onSelect={onSelectEndpoint}
|
||||
/>
|
||||
) : (
|
||||
<DropdownMenuLabel className="dark:text-gray-300">
|
||||
No endpoint available.
|
||||
|
|
@ -217,7 +223,10 @@ export default function NewConversationMenu() {
|
|||
<DropdownMenuSeparator />
|
||||
<DropdownMenuRadioGroup
|
||||
onValueChange={onSelectPreset}
|
||||
className={cn('overflow-y-auto overflow-x-hidden', showEndpoints ? 'max-h-[210px]' : 'max-h-[315px]')}
|
||||
className={cn(
|
||||
'overflow-y-auto overflow-x-hidden',
|
||||
showEndpoints ? 'max-h-[210px]' : 'max-h-[315px]'
|
||||
)}
|
||||
>
|
||||
{showPresets &&
|
||||
(presets.length ? (
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import { Settings, AgentSettings } from '../../Endpoints/Plugins/';
|
|||
import { cn } from '~/utils/';
|
||||
import store from '~/store';
|
||||
import { useAuthContext } from '~/hooks/AuthContext';
|
||||
import { useAvailablePluginsQuery } from '~/data-provider';
|
||||
import { useAvailablePluginsQuery } from '@librechat/data-provider';
|
||||
|
||||
function PluginsOptions() {
|
||||
const { data: allPlugins } = useAvailablePluginsQuery();
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import { useEffect } from 'react';
|
||||
import { useRecoilValue, useResetRecoilState, useSetRecoilState } from 'recoil';
|
||||
import { SSE } from '~/data-provider/sse.mjs';
|
||||
import createPayload from '~/data-provider/createPayload';
|
||||
import { SSE, createPayload } from '@librechat/data-provider';
|
||||
import store from '~/store';
|
||||
import { useAuthContext } from '~/hooks/AuthContext';
|
||||
|
||||
|
|
@ -224,7 +223,8 @@ export default function MessageHandler() {
|
|||
|
||||
events.onopen = () => console.log('connection is opened');
|
||||
|
||||
events.oncancel = () => abortConversation(message?.conversationId || submission?.conversationId);
|
||||
events.oncancel = () =>
|
||||
abortConversation(message?.conversationId || submission?.conversationId);
|
||||
|
||||
events.onerror = function (e) {
|
||||
console.log('error in opening conn.');
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import HoverButtons from './HoverButtons';
|
|||
import SiblingSwitch from './SiblingSwitch';
|
||||
import getIcon from '~/utils/getIcon';
|
||||
import { useMessageHandler } from '~/utils/handleSubmit';
|
||||
import { useGetConversationByIdQuery } from '~/data-provider';
|
||||
import { useGetConversationByIdQuery } from '@librechat/data-provider';
|
||||
import { cn } from '~/utils/';
|
||||
import store from '~/store';
|
||||
import getError from '~/utils/getError';
|
||||
|
|
@ -192,7 +192,7 @@ export default function Message({
|
|||
<div className="markdown prose dark:prose-invert light w-full break-words">
|
||||
{!isCreatedByUser ? (
|
||||
<>
|
||||
<Content content={text} message={message}/>
|
||||
<Content content={text} message={message} />
|
||||
</>
|
||||
) : (
|
||||
<>{text}</>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { Dialog, DialogTemplate } from '../ui/';
|
||||
import { ClearChatsButton } from './SettingsTabs/';
|
||||
import { useClearConversationsMutation } from '~/data-provider';
|
||||
import { useClearConversationsMutation } from '@librechat/data-provider';
|
||||
import store from '~/store';
|
||||
|
||||
const ClearConvos = ({ open, onOpenChange }) => {
|
||||
|
|
@ -32,7 +32,9 @@ const ClearConvos = ({ open, onOpenChange }) => {
|
|||
<DialogTemplate
|
||||
title="Clear conversations"
|
||||
description="Are you sure you want to clear all conversations? This is irreversible."
|
||||
leftButtons={<ClearChatsButton showText={false} confirmClear={confirmClear} onClick={clearConvos} />}
|
||||
leftButtons={
|
||||
<ClearChatsButton showText={false} confirmClear={confirmClear} onClick={clearConvos} />
|
||||
}
|
||||
/>
|
||||
</Dialog>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { General } from './SettingsTabs/';
|
|||
import { CogIcon } from '~/components/svg';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { cn } from '~/utils/';
|
||||
import { useClearConversationsMutation } from '~/data-provider';
|
||||
import { useClearConversationsMutation } from '@librechat/data-provider';
|
||||
import store from '~/store';
|
||||
|
||||
export default function Settings({ open, onOpenChange }) {
|
||||
|
|
|
|||
|
|
@ -2,9 +2,15 @@ import * as Tabs from '@radix-ui/react-tabs';
|
|||
import { CheckIcon } from 'lucide-react';
|
||||
import { ThemeContext } from '~/hooks/ThemeContext';
|
||||
import React, { useState, useContext, useCallback } from 'react';
|
||||
import { useClearConversationsMutation } from '~/data-provider';
|
||||
import { useClearConversationsMutation } from '@librechat/data-provider';
|
||||
|
||||
export const ThemeSelector = ({ theme, onChange }: { theme: string, onChange: (value: string) => void }) => (
|
||||
export const ThemeSelector = ({
|
||||
theme,
|
||||
onChange
|
||||
}: {
|
||||
theme: string;
|
||||
onChange: (value: string) => void;
|
||||
}) => (
|
||||
<div className="flex items-center justify-between">
|
||||
<div>Theme</div>
|
||||
<select
|
||||
|
|
@ -19,7 +25,15 @@ export const ThemeSelector = ({ theme, onChange }: { theme: string, onChange: (v
|
|||
</div>
|
||||
);
|
||||
|
||||
export const ClearChatsButton = ({ confirmClear, showText = true, onClick }: { confirmClear: boolean, showText: boolean, onClick: () => void }) => (
|
||||
export const ClearChatsButton = ({
|
||||
confirmClear,
|
||||
showText = true,
|
||||
onClick
|
||||
}: {
|
||||
confirmClear: boolean;
|
||||
showText: boolean;
|
||||
onClick: () => void;
|
||||
}) => (
|
||||
<div className="flex items-center justify-between">
|
||||
{showText && <div>Clear all chats</div>}
|
||||
<button
|
||||
|
|
@ -45,7 +59,7 @@ function General() {
|
|||
const { theme, setTheme } = useContext(ThemeContext);
|
||||
const clearConvosMutation = useClearConversationsMutation();
|
||||
const [confirmClear, setConfirmClear] = useState(false);
|
||||
|
||||
|
||||
const clearConvos = useCallback(() => {
|
||||
if (confirmClear) {
|
||||
console.log('Clearing conversations...');
|
||||
|
|
@ -56,18 +70,21 @@ function General() {
|
|||
}
|
||||
}, [confirmClear, clearConvosMutation]);
|
||||
|
||||
const changeTheme = useCallback((value: string) => {
|
||||
setTheme(value);
|
||||
}, [setTheme]);
|
||||
const changeTheme = useCallback(
|
||||
(value: string) => {
|
||||
setTheme(value);
|
||||
},
|
||||
[setTheme]
|
||||
);
|
||||
|
||||
return (
|
||||
<Tabs.Content value="general" role="tabpanel" className="w-full md:min-h-[300px]" >
|
||||
<Tabs.Content value="general" role="tabpanel" className="w-full md:min-h-[300px]">
|
||||
<div className="flex flex-col gap-3 text-sm text-gray-600 dark:text-gray-300">
|
||||
<div className="border-b pb-3 last-of-type:border-b-0 dark:border-gray-700">
|
||||
<ThemeSelector theme={theme} onChange={changeTheme} />
|
||||
</div>
|
||||
<div className="border-b pb-3 last-of-type:border-b-0 dark:border-gray-700">
|
||||
<ClearChatsButton confirmClear={confirmClear} onClick={clearConvos} showText={true}/>
|
||||
<ClearChatsButton confirmClear={confirmClear} onClick={clearConvos} showText={true} />
|
||||
</div>
|
||||
</div>
|
||||
</Tabs.Content>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { useGetConversationsQuery, useSearchQuery } from '~/data-provider';
|
||||
import { useGetConversationsQuery, useSearchQuery } from '@librechat/data-provider';
|
||||
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
||||
|
||||
import Conversations from '../Conversations';
|
||||
|
|
@ -9,7 +9,6 @@ import NewChat from './NewChat';
|
|||
import Pages from '../Conversations/Pages';
|
||||
import Panel from '../svg/Panel';
|
||||
import Spinner from '../svg/Spinner';
|
||||
// import { ThemeContext } from '~/hooks/ThemeContext';
|
||||
import { cn } from '~/utils/';
|
||||
import store from '~/store';
|
||||
import { useAuthContext } from '~/hooks/AuthContext';
|
||||
|
|
@ -38,7 +37,6 @@ import useDebounce from '~/hooks/useDebounce';
|
|||
export default function Nav({ navVisible, setNavVisible }) {
|
||||
const [isHovering, setIsHovering] = useState(false);
|
||||
const { isAuthenticated } = useAuthContext();
|
||||
// const { theme, } = useContext(ThemeContext);
|
||||
const containerRef = useRef(null);
|
||||
const scrollPositionRef = useRef(null);
|
||||
|
||||
|
|
@ -159,7 +157,8 @@ export default function Nav({ navVisible, setNavVisible }) {
|
|||
|
||||
const isMobile = () => {
|
||||
const userAgent = typeof window.navigator === 'undefined' ? '' : navigator.userAgent;
|
||||
const mobileRegex = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|Mobile|mobile|CriOS/i;
|
||||
const mobileRegex =
|
||||
/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|Mobile|mobile|CriOS/i;
|
||||
return mobileRegex.test(userAgent);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { TPlugin, TPluginAuthConfig } from '~/data-provider';
|
||||
import { TPlugin, TPluginAuthConfig } from '@librechat/data-provider';
|
||||
import { Save } from 'lucide-react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { TPluginAction } from './PluginStoreDialog';
|
||||
|
|
|
|||
|
|
@ -4,7 +4,11 @@ import { useRecoilState } from 'recoil';
|
|||
import { X } from 'lucide-react';
|
||||
import store from '~/store';
|
||||
import { PluginStoreItem, PluginPagination, PluginAuthForm } from '.';
|
||||
import { useAvailablePluginsQuery, useUpdateUserPluginsMutation, TPlugin } from '~/data-provider';
|
||||
import {
|
||||
useAvailablePluginsQuery,
|
||||
useUpdateUserPluginsMutation,
|
||||
TPlugin
|
||||
} from '@librechat/data-provider';
|
||||
import { useAuthContext } from '~/hooks/AuthContext';
|
||||
|
||||
type TPluginStoreDialogProps = {
|
||||
|
|
@ -95,8 +99,7 @@ function PluginStoreDialog({ isOpen, setIsOpen }: TPluginStoreDialogProps) {
|
|||
if (width < 501) {
|
||||
setItemsPerPage(8);
|
||||
return;
|
||||
} else
|
||||
if (width < 640) {
|
||||
} else if (width < 640) {
|
||||
columns = 2;
|
||||
} else if (width < 1024) {
|
||||
columns = 3;
|
||||
|
|
@ -140,7 +143,7 @@ function PluginStoreDialog({ isOpen, setIsOpen }: TPluginStoreDialogProps) {
|
|||
<div className="fixed inset-0 bg-gray-500/90 transition-opacity dark:bg-gray-800/90" />
|
||||
{/* Full-screen container to center the panel */}
|
||||
<div className="fixed inset-0 flex items-center justify-center p-4">
|
||||
<Dialog.Panel className="relative w-full max-sm:h-full overflow-y-auto transform overflow-hidden rounded-lg bg-white text-left shadow-xl transition-all dark:bg-gray-900 sm:mx-7 sm:my-8 sm:max-w-2xl lg:max-w-5xl xl:max-w-7xl">
|
||||
<Dialog.Panel className="relative w-full transform overflow-hidden overflow-y-auto rounded-lg bg-white text-left shadow-xl transition-all dark:bg-gray-900 max-sm:h-full sm:mx-7 sm:my-8 sm:max-w-2xl lg:max-w-5xl xl:max-w-7xl">
|
||||
<div className="flex items-center justify-between border-b-[1px] border-black/10 px-4 pb-4 pt-5 dark:border-white/10 sm:p-6">
|
||||
<div className="flex items-center">
|
||||
<div className="text-center sm:text-left">
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { TPlugin } from '~/data-provider';
|
||||
import { TPlugin } from '@librechat/data-provider';
|
||||
import { XCircle, DownloadCloud } from 'lucide-react';
|
||||
|
||||
type TPluginStoreItemProps = {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { render } from 'layout-test-utils';
|
||||
import PluginStoreDialog from '../PluginStoreDialog';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import * as mockDataProvider from '~/data-provider';
|
||||
import * as mockDataProvider from '@librechat/data-provider';
|
||||
|
||||
jest.mock('~/data-provider');
|
||||
jest.mock('@librechat/data-provider');
|
||||
|
||||
class ResizeObserver {
|
||||
observe() {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import SunIcon from '../svg/SunIcon';
|
|||
import LightningIcon from '../svg/LightningIcon';
|
||||
import CautionIcon from '../svg/CautionIcon';
|
||||
import store from '~/store';
|
||||
import { useGetStartupConfig } from '~/data-provider';
|
||||
import { useGetStartupConfig } from '@librechat/data-provider';
|
||||
|
||||
export default function Landing() {
|
||||
const { data: config } = useGetStartupConfig();
|
||||
|
|
|
|||
|
|
@ -1,95 +0,0 @@
|
|||
export const user = () => {
|
||||
return `/api/user`;
|
||||
};
|
||||
|
||||
export const userPlugins = () => {
|
||||
return `/api/user/plugins`;
|
||||
};
|
||||
|
||||
export const messages = (id: string) => {
|
||||
return `/api/messages/${id}`;
|
||||
};
|
||||
|
||||
export const abortRequest = (endpoint: string) => {
|
||||
return `/api/ask/${endpoint}/abort`;
|
||||
};
|
||||
|
||||
export const conversations = (pageNumber: string) => {
|
||||
return `/api/convos?pageNumber=${pageNumber}`;
|
||||
};
|
||||
|
||||
export const conversationById = (id: string) => {
|
||||
return `/api/convos/${id}`;
|
||||
};
|
||||
|
||||
export const updateConversation = () => {
|
||||
return `/api/convos/update`;
|
||||
};
|
||||
|
||||
export const deleteConversation = () => {
|
||||
return `/api/convos/clear`;
|
||||
};
|
||||
|
||||
export const search = (q: string, pageNumber: string) => {
|
||||
return `/api/search?q=${q}&pageNumber=${pageNumber}`;
|
||||
};
|
||||
|
||||
export const searchEnabled = () => {
|
||||
return `/api/search/enable`;
|
||||
};
|
||||
|
||||
export const presets = () => {
|
||||
return `/api/presets`;
|
||||
};
|
||||
|
||||
export const deletePreset = () => {
|
||||
return `/api/presets/delete`;
|
||||
};
|
||||
|
||||
export const aiEndpoints = () => {
|
||||
return `/api/endpoints`;
|
||||
};
|
||||
|
||||
export const tokenizer = () => {
|
||||
return `/api/tokenizer`;
|
||||
};
|
||||
|
||||
export const login = () => {
|
||||
return '/api/auth/login';
|
||||
};
|
||||
|
||||
export const logout = () => {
|
||||
return '/api/auth/logout';
|
||||
};
|
||||
|
||||
export const register = () => {
|
||||
return '/api/auth/register';
|
||||
};
|
||||
|
||||
export const loginFacebook = () => {
|
||||
return '/api/auth/facebook';
|
||||
};
|
||||
|
||||
export const loginGoogle = () => {
|
||||
return '/api/auth/google';
|
||||
};
|
||||
|
||||
export const refreshToken = () => {
|
||||
return '/api/auth/refresh';
|
||||
};
|
||||
|
||||
export const requestPasswordReset = () => {
|
||||
return '/api/auth/requestPasswordReset';
|
||||
};
|
||||
|
||||
export const resetPassword = () => {
|
||||
return '/api/auth/resetPassword';
|
||||
};
|
||||
|
||||
export const plugins = () => {
|
||||
return '/api/plugins';
|
||||
};
|
||||
|
||||
export const config = () => {
|
||||
return '/api/config';
|
||||
}
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
import type { TConversation, TSubmission, EModelEndpoint } from './types';
|
||||
|
||||
export default function createPayload(submission: TSubmission) {
|
||||
const { conversation, message, endpointOption } = submission;
|
||||
const { conversationId } = conversation as TConversation;
|
||||
const { endpoint } = endpointOption as { endpoint: EModelEndpoint };
|
||||
|
||||
const endpointUrlMap = {
|
||||
azureOpenAI: '/api/ask/azureOpenAI',
|
||||
openAI: '/api/ask/openAI',
|
||||
google: '/api/ask/google',
|
||||
bingAI: '/api/ask/bingAI',
|
||||
chatGPTBrowser: '/api/ask/chatGPTBrowser',
|
||||
gptPlugins: '/api/ask/gptPlugins'
|
||||
};
|
||||
|
||||
const server = endpointUrlMap[endpoint];
|
||||
|
||||
const payload = {
|
||||
...message,
|
||||
...endpointOption,
|
||||
conversationId
|
||||
};
|
||||
|
||||
return { server, payload };
|
||||
}
|
||||
|
|
@ -1,117 +0,0 @@
|
|||
import * as t from './types';
|
||||
import request from './request';
|
||||
import * as endpoints from './api-endpoints';
|
||||
|
||||
export function getConversations(pageNumber: string): Promise<t.TGetConversationsResponse> {
|
||||
return request.get(endpoints.conversations(pageNumber));
|
||||
}
|
||||
|
||||
export function abortRequestWithMessage(
|
||||
endpoint: string,
|
||||
abortKey: string,
|
||||
message: string
|
||||
): Promise<void> {
|
||||
return request.post(endpoints.abortRequest(endpoint), { arg: { abortKey, message } });
|
||||
}
|
||||
|
||||
export function deleteConversation(payload: t.TDeleteConversationRequest) {
|
||||
//todo: this should be a DELETE request
|
||||
return request.post(endpoints.deleteConversation(), { arg: payload });
|
||||
}
|
||||
|
||||
export function clearAllConversations(): Promise<unknown> {
|
||||
return request.post(endpoints.deleteConversation(), { arg: {} });
|
||||
}
|
||||
|
||||
export function getMessagesByConvoId(id: string): Promise<t.TMessage[]> {
|
||||
return request.get(endpoints.messages(id));
|
||||
}
|
||||
|
||||
export function getConversationById(id: string): Promise<t.TConversation> {
|
||||
return request.get(endpoints.conversationById(id));
|
||||
}
|
||||
|
||||
export function updateConversation(
|
||||
payload: t.TUpdateConversationRequest
|
||||
): Promise<t.TUpdateConversationResponse> {
|
||||
return request.post(endpoints.updateConversation(), { arg: payload });
|
||||
}
|
||||
|
||||
export function getPresets(): Promise<t.TPreset[]> {
|
||||
return request.get(endpoints.presets());
|
||||
}
|
||||
|
||||
export function createPreset(payload: t.TPreset): Promise<t.TPreset[]> {
|
||||
return request.post(endpoints.presets(), payload);
|
||||
}
|
||||
|
||||
export function updatePreset(payload: t.TPreset): Promise<t.TPreset[]> {
|
||||
return request.post(endpoints.presets(), payload);
|
||||
}
|
||||
|
||||
export function deletePreset(arg: t.TPreset | object): Promise<t.TPreset[]> {
|
||||
return request.post(endpoints.deletePreset(), arg);
|
||||
}
|
||||
|
||||
export function getSearchEnabled(): Promise<boolean> {
|
||||
return request.get(endpoints.searchEnabled());
|
||||
}
|
||||
|
||||
export function getUser(): Promise<t.TUser> {
|
||||
return request.get(endpoints.user());
|
||||
}
|
||||
|
||||
export const searchConversations = async (
|
||||
q: string,
|
||||
pageNumber: string
|
||||
): Promise<t.TSearchResults> => {
|
||||
return request.get(endpoints.search(q, pageNumber));
|
||||
};
|
||||
|
||||
export const getAIEndpoints = () => {
|
||||
return request.get(endpoints.aiEndpoints());
|
||||
};
|
||||
|
||||
export const updateTokenCount = (text: string) => {
|
||||
return request.post(endpoints.tokenizer(), { arg: text });
|
||||
};
|
||||
|
||||
export const login = (payload: t.TLoginUser) => {
|
||||
return request.post(endpoints.login(), payload);
|
||||
};
|
||||
|
||||
export const logout = () => {
|
||||
return request.post(endpoints.logout());
|
||||
};
|
||||
|
||||
export const register = (payload: t.TRegisterUser) => {
|
||||
return request.post(endpoints.register(), payload);
|
||||
};
|
||||
|
||||
export const refreshToken = () => {
|
||||
return request.post(endpoints.refreshToken());
|
||||
};
|
||||
|
||||
export const getLoginGoogle = () => {
|
||||
return request.get(endpoints.loginGoogle());
|
||||
};
|
||||
|
||||
export const requestPasswordReset = (payload: t.TRequestPasswordReset) => {
|
||||
return request.post(endpoints.requestPasswordReset(), payload);
|
||||
};
|
||||
|
||||
export const resetPassword = (payload: t.TResetPassword) => {
|
||||
return request.post(endpoints.resetPassword(), payload);
|
||||
};
|
||||
|
||||
export const getAvailablePlugins = (): Promise<t.TPlugin[]> => {
|
||||
return request.get(endpoints.plugins());
|
||||
};
|
||||
|
||||
export const updateUserPlugins = (payload: t.TUpdateUserPlugins) => {
|
||||
return request.post(endpoints.userPlugins(), payload);
|
||||
};
|
||||
|
||||
export const getStartupConfig = (): Promise<t.TStartupConfig> => {
|
||||
return request.get(endpoints.config());
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
import axios from 'axios';
|
||||
|
||||
export function setAcceptLanguageHeader(value: string): void {
|
||||
axios.defaults.headers.common['Accept-Language'] = value;
|
||||
}
|
||||
|
||||
export function setTokenHeader(token: string) {
|
||||
axios.defaults.headers.common['Authorization'] = 'Bearer ' + token;
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
export * from './data-service';
|
||||
// export * from './endpoints';
|
||||
export * from './request';
|
||||
export * from './types';
|
||||
export * from './react-query-service';
|
||||
export * from './headers-helpers';
|
||||
// export * from './events';
|
||||
|
|
@ -1,347 +0,0 @@
|
|||
import {
|
||||
UseQueryOptions,
|
||||
useQuery,
|
||||
useMutation,
|
||||
useQueryClient,
|
||||
UseMutationResult,
|
||||
QueryObserverResult
|
||||
} from '@tanstack/react-query';
|
||||
import * as t from './types';
|
||||
import * as dataService from './data-service';
|
||||
|
||||
export enum QueryKeys {
|
||||
messages = 'messsages',
|
||||
allConversations = 'allConversations',
|
||||
conversation = 'conversation',
|
||||
searchEnabled = 'searchEnabled',
|
||||
user = 'user',
|
||||
endpoints = 'endpoints',
|
||||
presets = 'presets',
|
||||
searchResults = 'searchResults',
|
||||
tokenCount = 'tokenCount',
|
||||
availablePlugins = 'availablePlugins',
|
||||
startupConfig = 'startupConfig',
|
||||
}
|
||||
|
||||
export const useAbortRequestWithMessage = (): UseMutationResult<
|
||||
void,
|
||||
Error,
|
||||
{ endpoint: string; abortKey: string; message: string }
|
||||
> => {
|
||||
return useMutation(({ endpoint, abortKey, message }) =>
|
||||
dataService.abortRequestWithMessage(endpoint, abortKey, message)
|
||||
);
|
||||
};
|
||||
|
||||
export const useGetUserQuery = (
|
||||
config?: UseQueryOptions<t.TUser>
|
||||
): QueryObserverResult<t.TUser> => {
|
||||
return useQuery<t.TUser>([QueryKeys.user], () => dataService.getUser(), {
|
||||
refetchOnWindowFocus: false,
|
||||
refetchOnReconnect: false,
|
||||
refetchOnMount: false,
|
||||
retry: false,
|
||||
...config
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetMessagesByConvoId = (
|
||||
id: string,
|
||||
config?: UseQueryOptions<t.TMessage[]>
|
||||
): QueryObserverResult<t.TMessage[]> => {
|
||||
return useQuery<t.TMessage[]>(
|
||||
[QueryKeys.messages, id],
|
||||
() => dataService.getMessagesByConvoId(id),
|
||||
{
|
||||
refetchOnWindowFocus: false,
|
||||
refetchOnReconnect: false,
|
||||
refetchOnMount: false,
|
||||
...config
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export const useGetConversationByIdQuery = (
|
||||
id: string,
|
||||
config?: UseQueryOptions<t.TConversation>
|
||||
): QueryObserverResult<t.TConversation> => {
|
||||
return useQuery<t.TConversation>(
|
||||
[QueryKeys.conversation, id],
|
||||
() => dataService.getConversationById(id),
|
||||
{
|
||||
refetchOnWindowFocus: false,
|
||||
refetchOnReconnect: false,
|
||||
refetchOnMount: false,
|
||||
...config
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
//This isn't ideal because its just a query and we're using mutation, but it was the only way
|
||||
//to make it work with how the Chat component is structured
|
||||
export const useGetConversationByIdMutation = (id: string): UseMutationResult<t.TConversation> => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation(() => dataService.getConversationById(id), {
|
||||
// onSuccess: (res: t.TConversation) => {
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries([QueryKeys.conversation, id]);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useUpdateConversationMutation = (
|
||||
id: string
|
||||
): UseMutationResult<
|
||||
t.TUpdateConversationResponse,
|
||||
unknown,
|
||||
t.TUpdateConversationRequest,
|
||||
unknown
|
||||
> => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation(
|
||||
(payload: t.TUpdateConversationRequest) => dataService.updateConversation(payload),
|
||||
{
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries([QueryKeys.conversation, id]);
|
||||
queryClient.invalidateQueries([QueryKeys.allConversations]);
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export const useDeleteConversationMutation = (
|
||||
id?: string
|
||||
): UseMutationResult<
|
||||
t.TDeleteConversationResponse,
|
||||
unknown,
|
||||
t.TDeleteConversationRequest,
|
||||
unknown
|
||||
> => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation(
|
||||
(payload: t.TDeleteConversationRequest) => dataService.deleteConversation(payload),
|
||||
{
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries([QueryKeys.conversation, id]);
|
||||
queryClient.invalidateQueries([QueryKeys.allConversations]);
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export const useClearConversationsMutation = (): UseMutationResult<unknown> => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation(() => dataService.clearAllConversations(), {
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries([QueryKeys.allConversations]);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetConversationsQuery = (
|
||||
pageNumber: string,
|
||||
config?: UseQueryOptions<t.TConversation[]>
|
||||
): QueryObserverResult<t.TConversation[]> => {
|
||||
return useQuery<t.TConversation[]>(
|
||||
[QueryKeys.allConversations, pageNumber],
|
||||
() => dataService.getConversations(pageNumber),
|
||||
{
|
||||
refetchOnReconnect: false,
|
||||
refetchOnMount: false,
|
||||
retry: 1,
|
||||
...config
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export const useGetSearchEnabledQuery = (
|
||||
config?: UseQueryOptions<boolean>
|
||||
): QueryObserverResult<boolean> => {
|
||||
return useQuery<boolean>([QueryKeys.searchEnabled], () => dataService.getSearchEnabled(), {
|
||||
refetchOnWindowFocus: false,
|
||||
refetchOnReconnect: false,
|
||||
refetchOnMount: false,
|
||||
...config
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetEndpointsQuery = (): QueryObserverResult<t.TEndpoints> => {
|
||||
return useQuery([QueryKeys.endpoints], () => dataService.getAIEndpoints(), {
|
||||
refetchOnWindowFocus: false,
|
||||
refetchOnReconnect: false,
|
||||
refetchOnMount: false
|
||||
});
|
||||
};
|
||||
|
||||
export const useCreatePresetMutation = (): UseMutationResult<
|
||||
t.TPreset[],
|
||||
unknown,
|
||||
t.TPreset,
|
||||
unknown
|
||||
> => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation((payload: t.TPreset) => dataService.createPreset(payload), {
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries([QueryKeys.presets]);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useUpdatePresetMutation = (): UseMutationResult<
|
||||
t.TPreset[],
|
||||
unknown,
|
||||
t.TPreset,
|
||||
unknown
|
||||
> => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation((payload: t.TPreset) => dataService.updatePreset(payload), {
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries([QueryKeys.presets]);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetPresetsQuery = (
|
||||
config?: UseQueryOptions<t.TPreset[]>
|
||||
): QueryObserverResult<t.TPreset[], unknown> => {
|
||||
return useQuery<t.TPreset[]>([QueryKeys.presets], () => dataService.getPresets(), {
|
||||
refetchOnWindowFocus: false,
|
||||
refetchOnReconnect: false,
|
||||
refetchOnMount: false,
|
||||
...config
|
||||
});
|
||||
};
|
||||
|
||||
export const useDeletePresetMutation = (): UseMutationResult<
|
||||
t.TPreset[],
|
||||
unknown,
|
||||
t.TPreset | object,
|
||||
unknown
|
||||
> => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation((payload: t.TPreset | object) => dataService.deletePreset(payload), {
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries([QueryKeys.presets]);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useSearchQuery = (
|
||||
searchQuery: string,
|
||||
pageNumber: string,
|
||||
config?: UseQueryOptions<t.TSearchResults>
|
||||
): QueryObserverResult<t.TSearchResults> => {
|
||||
return useQuery<t.TSearchResults>(
|
||||
[QueryKeys.searchResults, pageNumber, searchQuery],
|
||||
() => dataService.searchConversations(searchQuery, pageNumber),
|
||||
{
|
||||
refetchOnWindowFocus: false,
|
||||
refetchOnReconnect: false,
|
||||
refetchOnMount: false,
|
||||
...config
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export const useUpdateTokenCountMutation = (): UseMutationResult<
|
||||
t.TUpdateTokenCountResponse,
|
||||
unknown,
|
||||
string,
|
||||
unknown
|
||||
> => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation((text: string) => dataService.updateTokenCount(text), {
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries([QueryKeys.tokenCount]);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useLoginUserMutation = (): UseMutationResult<
|
||||
t.TLoginResponse,
|
||||
unknown,
|
||||
t.TLoginUser,
|
||||
unknown
|
||||
> => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation((payload: t.TLoginUser) => dataService.login(payload), {
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries([QueryKeys.user]);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useRegisterUserMutation = (): UseMutationResult<
|
||||
unknown,
|
||||
unknown,
|
||||
t.TRegisterUser,
|
||||
unknown
|
||||
> => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation((payload: t.TRegisterUser) => dataService.register(payload), {
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries([QueryKeys.user]);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useLogoutUserMutation = (): UseMutationResult<unknown> => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation(() => dataService.logout(), {
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries([QueryKeys.user]);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useRefreshTokenMutation = (): UseMutationResult<
|
||||
t.TRefreshTokenResponse,
|
||||
unknown,
|
||||
unknown,
|
||||
unknown
|
||||
> => {
|
||||
return useMutation(() => dataService.refreshToken(), {});
|
||||
};
|
||||
export const useRequestPasswordResetMutation = (): UseMutationResult<unknown> => {
|
||||
return useMutation((payload: t.TRequestPasswordReset) =>
|
||||
dataService.requestPasswordReset(payload)
|
||||
);
|
||||
};
|
||||
|
||||
export const useResetPasswordMutation = (): UseMutationResult<unknown> => {
|
||||
return useMutation((payload: t.TResetPassword) => dataService.resetPassword(payload));
|
||||
};
|
||||
|
||||
export const useAvailablePluginsQuery = (): QueryObserverResult<t.TPlugin[]> => {
|
||||
return useQuery<t.TPlugin[]>(
|
||||
[QueryKeys.availablePlugins],
|
||||
() => dataService.getAvailablePlugins(),
|
||||
{
|
||||
refetchOnWindowFocus: false,
|
||||
refetchOnReconnect: false,
|
||||
refetchOnMount: false
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export const useUpdateUserPluginsMutation = (): UseMutationResult<
|
||||
t.TUser,
|
||||
unknown,
|
||||
t.TUpdateUserPlugins,
|
||||
unknown
|
||||
> => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation((payload: t.TUpdateUserPlugins) => dataService.updateUserPlugins(payload), {
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries([QueryKeys.user]);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetStartupConfig = (): QueryObserverResult<t.TStartupConfig> => {
|
||||
return useQuery<t.TStartupConfig>([QueryKeys.startupConfig], () => dataService.getStartupConfig(), {
|
||||
refetchOnWindowFocus: false,
|
||||
refetchOnReconnect: false,
|
||||
refetchOnMount: false
|
||||
});
|
||||
}
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
import axios, { AxiosRequestConfig } from 'axios';
|
||||
|
||||
async function _get<T>(url: string, options?: AxiosRequestConfig): Promise<T> {
|
||||
const response = await axios.get(url, { ...options });
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async function _post(url: string, data?: any) {
|
||||
const response = await axios.post(url, JSON.stringify(data), {
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
});
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async function _postMultiPart(url: string, formData: FormData, options?: AxiosRequestConfig) {
|
||||
const response = await axios.post(url, formData, {
|
||||
...options,
|
||||
headers: { 'Content-Type': 'multipart/form-data' }
|
||||
});
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async function _put(url: string, data?: any) {
|
||||
const response = await axios.put(url, JSON.stringify(data), {
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
});
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async function _delete<T>(url: string): Promise<T> {
|
||||
const response = await axios.delete(url);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async function _deleteWithOptions<T>(url: string, options?: AxiosRequestConfig): Promise<T> {
|
||||
const response = await axios.delete(url, { ...options });
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async function _patch(url: string, data?: any) {
|
||||
const response = await axios.patch(url, JSON.stringify(data), {
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
});
|
||||
return response.data;
|
||||
}
|
||||
|
||||
export default {
|
||||
get: _get,
|
||||
post: _post,
|
||||
postMultiPart: _postMultiPart,
|
||||
put: _put,
|
||||
delete: _delete,
|
||||
deleteWithOptions: _deleteWithOptions,
|
||||
patch: _patch
|
||||
};
|
||||
|
|
@ -1,219 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2016 Maxime Petazzoni <maxime.petazzoni@bulix.org>.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
var SSE = function (url, options) {
|
||||
if (!(this instanceof SSE)) {
|
||||
return new SSE(url, options);
|
||||
}
|
||||
|
||||
this.INITIALIZING = -1;
|
||||
this.CONNECTING = 0;
|
||||
this.OPEN = 1;
|
||||
this.CLOSED = 2;
|
||||
|
||||
this.url = url;
|
||||
|
||||
options = options || {};
|
||||
this.headers = options.headers || {};
|
||||
this.payload = options.payload !== undefined ? options.payload : '';
|
||||
this.method = options.method || (this.payload && 'POST' || 'GET');
|
||||
this.withCredentials = !!options.withCredentials;
|
||||
|
||||
this.FIELD_SEPARATOR = ':';
|
||||
this.listeners = {};
|
||||
|
||||
this.xhr = null;
|
||||
this.readyState = this.INITIALIZING;
|
||||
this.progress = 0;
|
||||
this.chunk = '';
|
||||
|
||||
this.addEventListener = function(type, listener) {
|
||||
if (this.listeners[type] === undefined) {
|
||||
this.listeners[type] = [];
|
||||
}
|
||||
|
||||
if (this.listeners[type].indexOf(listener) === -1) {
|
||||
this.listeners[type].push(listener);
|
||||
}
|
||||
};
|
||||
|
||||
this.removeEventListener = function(type, listener) {
|
||||
if (this.listeners[type] === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
var filtered = [];
|
||||
this.listeners[type].forEach(function(element) {
|
||||
if (element !== listener) {
|
||||
filtered.push(element);
|
||||
}
|
||||
});
|
||||
if (filtered.length === 0) {
|
||||
delete this.listeners[type];
|
||||
} else {
|
||||
this.listeners[type] = filtered;
|
||||
}
|
||||
};
|
||||
|
||||
this.dispatchEvent = function(e) {
|
||||
if (!e) {
|
||||
return true;
|
||||
}
|
||||
|
||||
e.source = this;
|
||||
|
||||
var onHandler = 'on' + e.type;
|
||||
if (this.hasOwnProperty(onHandler)) {
|
||||
this[onHandler].call(this, e);
|
||||
if (e.defaultPrevented) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.listeners[e.type]) {
|
||||
return this.listeners[e.type].every(function(callback) {
|
||||
callback(e);
|
||||
return !e.defaultPrevented;
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
this._setReadyState = function(state) {
|
||||
var event = new CustomEvent('readystatechange');
|
||||
event.readyState = state;
|
||||
this.readyState = state;
|
||||
this.dispatchEvent(event);
|
||||
};
|
||||
|
||||
this._onStreamFailure = function(e) {
|
||||
var event = new CustomEvent('error');
|
||||
event.data = e.currentTarget.response;
|
||||
this.dispatchEvent(event);
|
||||
this.close();
|
||||
}
|
||||
|
||||
this._onStreamAbort = function(e) {
|
||||
this.dispatchEvent(new CustomEvent('abort'));
|
||||
this.close();
|
||||
}
|
||||
|
||||
this._onStreamProgress = function(e) {
|
||||
if (!this.xhr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.xhr.status !== 200) {
|
||||
this._onStreamFailure(e);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.readyState == this.CONNECTING) {
|
||||
this.dispatchEvent(new CustomEvent('open'));
|
||||
this._setReadyState(this.OPEN);
|
||||
}
|
||||
|
||||
var data = this.xhr.responseText.substring(this.progress);
|
||||
this.progress += data.length;
|
||||
data.split(/(\r\n|\r|\n){2}/g).forEach(function(part) {
|
||||
if (part.trim().length === 0) {
|
||||
this.dispatchEvent(this._parseEventChunk(this.chunk.trim()));
|
||||
this.chunk = '';
|
||||
} else {
|
||||
this.chunk += part;
|
||||
}
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
this._onStreamLoaded = function(e) {
|
||||
this._onStreamProgress(e);
|
||||
|
||||
// Parse the last chunk.
|
||||
this.dispatchEvent(this._parseEventChunk(this.chunk));
|
||||
this.chunk = '';
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse a received SSE event chunk into a constructed event object.
|
||||
*/
|
||||
this._parseEventChunk = function(chunk) {
|
||||
if (!chunk || chunk.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var e = {'id': null, 'retry': null, 'data': '', 'event': 'message'};
|
||||
chunk.split(/\n|\r\n|\r/).forEach(function(line) {
|
||||
line = line.trimRight();
|
||||
var index = line.indexOf(this.FIELD_SEPARATOR);
|
||||
if (index <= 0) {
|
||||
// Line was either empty, or started with a separator and is a comment.
|
||||
// Either way, ignore.
|
||||
return;
|
||||
}
|
||||
|
||||
var field = line.substring(0, index);
|
||||
if (!(field in e)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var value = line.substring(index + 1).trimLeft();
|
||||
if (field === 'data') {
|
||||
e[field] += value;
|
||||
} else {
|
||||
e[field] = value;
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
var event = new CustomEvent(e.event);
|
||||
event.data = e.data;
|
||||
event.id = e.id;
|
||||
return event;
|
||||
};
|
||||
|
||||
this._checkStreamClosed = function() {
|
||||
if (!this.xhr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.xhr.readyState === XMLHttpRequest.DONE) {
|
||||
this._setReadyState(this.CLOSED);
|
||||
}
|
||||
};
|
||||
|
||||
this.stream = function() {
|
||||
this._setReadyState(this.CONNECTING);
|
||||
|
||||
this.xhr = new XMLHttpRequest();
|
||||
this.xhr.addEventListener('progress', this._onStreamProgress.bind(this));
|
||||
this.xhr.addEventListener('load', this._onStreamLoaded.bind(this));
|
||||
this.xhr.addEventListener('readystatechange', this._checkStreamClosed.bind(this));
|
||||
this.xhr.addEventListener('error', this._onStreamFailure.bind(this));
|
||||
this.xhr.addEventListener('abort', this._onStreamAbort.bind(this));
|
||||
this.xhr.open(this.method, this.url);
|
||||
for (var header in this.headers) {
|
||||
this.xhr.setRequestHeader(header, this.headers[header]);
|
||||
}
|
||||
this.xhr.withCredentials = this.withCredentials;
|
||||
this.xhr.send(this.payload);
|
||||
};
|
||||
|
||||
this.close = function() {
|
||||
if (this.readyState === this.CLOSED) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.xhr.abort();
|
||||
this.xhr = null;
|
||||
this._setReadyState(this.CLOSED);
|
||||
};
|
||||
};
|
||||
|
||||
export { SSE };
|
||||
// Export our SSE module for npm.js
|
||||
// if (typeof exports !== 'undefined') {
|
||||
// // exports.SSE = SSE;
|
||||
// module.exports = { SSE };
|
||||
// }
|
||||
|
|
@ -1,249 +0,0 @@
|
|||
export type TMessage = {
|
||||
messageId: string;
|
||||
conversationId: string;
|
||||
clientId: string;
|
||||
parentMessageId: string;
|
||||
sender: string;
|
||||
text: string;
|
||||
isCreatedByUser: boolean;
|
||||
error: boolean;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
};
|
||||
|
||||
export type TExample = {
|
||||
input: string;
|
||||
output: string;
|
||||
};
|
||||
|
||||
export type TPluginAuthConfig = {
|
||||
authField: string;
|
||||
label: string;
|
||||
description: string;
|
||||
};
|
||||
|
||||
export type TPlugin = {
|
||||
name: string;
|
||||
pluginKey: string;
|
||||
description: string;
|
||||
icon: string;
|
||||
authConfig: TPluginAuthConfig[];
|
||||
authenticated: boolean;
|
||||
};
|
||||
|
||||
export enum EModelEndpoint {
|
||||
azureOpenAI = 'azureOpenAI',
|
||||
openAI = 'openAI',
|
||||
bingAI = 'bingAI',
|
||||
chatGPT = 'chatGPT',
|
||||
chatGPTBrowser = 'chatGPTBrowser',
|
||||
google = 'google',
|
||||
gptPlugins = 'gptPlugins'
|
||||
}
|
||||
|
||||
export type TConversation = {
|
||||
conversationId: string;
|
||||
title: string;
|
||||
user?: string;
|
||||
endpoint: EModelEndpoint;
|
||||
suggestions?: string[];
|
||||
messages?: TMessage[];
|
||||
tools?: TPlugin[];
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
// google only
|
||||
modelLabel?: string;
|
||||
examples?: TExample[];
|
||||
// for azureOpenAI, openAI only
|
||||
chatGptLabel?: string;
|
||||
userLabel?: string;
|
||||
model?: string;
|
||||
promptPrefix?: string;
|
||||
temperature?: number;
|
||||
topP?: number;
|
||||
topK?: number;
|
||||
// bing and google
|
||||
context?: string;
|
||||
top_p?: number;
|
||||
presence_penalty?: number;
|
||||
// for bingAI only
|
||||
jailbreak?: boolean;
|
||||
jailbreakConversationId?: string;
|
||||
conversationSignature?: string;
|
||||
parentMessageId?: string;
|
||||
clientId?: string;
|
||||
invocationId?: string;
|
||||
toneStyle?: string;
|
||||
};
|
||||
|
||||
export type TSubmission = {
|
||||
conversation?: TConversation;
|
||||
message?: TMessage;
|
||||
endpointOption?: object;
|
||||
clientId?: string;
|
||||
context?: string;
|
||||
conversationId?: string;
|
||||
conversationSignature?: string;
|
||||
current: boolean;
|
||||
endpoint: EModelEndpoint;
|
||||
invocationId: number;
|
||||
isCreatedByUser: boolean;
|
||||
jailbreak: boolean;
|
||||
jailbreakConversationId?: string;
|
||||
messageId: string;
|
||||
overrideParentMessageId?: string | boolean;
|
||||
parentMessageId?: string;
|
||||
sender: string;
|
||||
systemMessage?: string;
|
||||
text: string;
|
||||
toneStyle?: string;
|
||||
model?: string;
|
||||
promptPrefix?: string;
|
||||
temperature?: number;
|
||||
top_p?: number;
|
||||
presence_penalty?: number;
|
||||
frequence_penalty?: number;
|
||||
};
|
||||
|
||||
export type TUpdateUserPlugins = {
|
||||
pluginKey: string;
|
||||
action: string;
|
||||
auth?: unknown;
|
||||
};
|
||||
|
||||
export type TPreset = {
|
||||
title: string;
|
||||
endpoint: EModelEndpoint;
|
||||
conversationSignature?: string;
|
||||
createdAt?: string;
|
||||
updatedAt?: string;
|
||||
presetId?: string;
|
||||
user?: string;
|
||||
// for azureOpenAI, openAI only
|
||||
chatGptLabel?: string;
|
||||
frequence_penalty?: number;
|
||||
model?: string;
|
||||
presence_penalty?: number;
|
||||
promptPrefix?: string;
|
||||
temperature?: number;
|
||||
top_p?: number;
|
||||
//for BingAI
|
||||
clientId?: string;
|
||||
invocationId?: number;
|
||||
jailbreak?: boolean;
|
||||
jailbreakPresetId?: string;
|
||||
presetSignature?: string;
|
||||
toneStyle?: string;
|
||||
};
|
||||
|
||||
export type TUser = {
|
||||
id: string;
|
||||
username: string;
|
||||
email: string;
|
||||
name: string;
|
||||
avatar: string;
|
||||
role: string;
|
||||
provider: string;
|
||||
plugins: string[];
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
};
|
||||
|
||||
export type TGetConversationsResponse = {
|
||||
conversations: TConversation[];
|
||||
pageNumber: string;
|
||||
pageSize: string | number;
|
||||
pages: string | number;
|
||||
};
|
||||
|
||||
export type TUpdateConversationRequest = {
|
||||
conversationId: string;
|
||||
title: string;
|
||||
};
|
||||
|
||||
export type TUpdateConversationResponse = {
|
||||
data: TConversation;
|
||||
};
|
||||
|
||||
export type TDeleteConversationRequest = {
|
||||
conversationId?: string;
|
||||
source?: string;
|
||||
};
|
||||
|
||||
export type TDeleteConversationResponse = {
|
||||
acknowledged: boolean;
|
||||
deletedCount: number;
|
||||
messages: {
|
||||
acknowledged: boolean;
|
||||
deletedCount: number;
|
||||
};
|
||||
};
|
||||
|
||||
export type TSearchResults = {
|
||||
conversations: TConversation[];
|
||||
messages: TMessage[];
|
||||
pageNumber: string;
|
||||
pageSize: string | number;
|
||||
pages: string | number;
|
||||
filter: object;
|
||||
};
|
||||
|
||||
export type TEndpoints = {
|
||||
azureOpenAI: boolean;
|
||||
bingAI: boolean;
|
||||
ChatGptBrowser: {
|
||||
availableModels: [];
|
||||
};
|
||||
OpenAI: {
|
||||
availableModels: [];
|
||||
};
|
||||
};
|
||||
|
||||
export type TUpdateTokenCountResponse = {
|
||||
count: number;
|
||||
};
|
||||
|
||||
export type TMessageTreeNode = object;
|
||||
|
||||
export type TSearchMessage = object;
|
||||
|
||||
export type TSearchMessageTreeNode = object;
|
||||
|
||||
export type TRegisterUser = {
|
||||
name: string;
|
||||
email: string;
|
||||
username: string;
|
||||
password: string;
|
||||
confirm_password?: string;
|
||||
};
|
||||
|
||||
export type TLoginUser = {
|
||||
email: string;
|
||||
password: string;
|
||||
};
|
||||
|
||||
export type TLoginResponse = {
|
||||
token: string;
|
||||
user: TUser;
|
||||
};
|
||||
|
||||
export type TRequestPasswordReset = {
|
||||
email: string;
|
||||
};
|
||||
|
||||
export type TResetPassword = {
|
||||
userId: string;
|
||||
token: string;
|
||||
password: string;
|
||||
};
|
||||
|
||||
export type TStartupConfig = {
|
||||
appTitle: boolean;
|
||||
googleLoginEnabled: boolean;
|
||||
openidLoginEnabled: boolean;
|
||||
openidLabel: string;
|
||||
openidImageUrl: string;
|
||||
githubLoginEnabled: boolean;
|
||||
serverDomain: string;
|
||||
registrationEnabled: boolean;
|
||||
}
|
||||
|
|
@ -16,7 +16,7 @@ import {
|
|||
useGetUserQuery,
|
||||
useRefreshTokenMutation,
|
||||
TLoginUser
|
||||
} from '~/data-provider';
|
||||
} from '@librechat/data-provider';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
export type TAuthContext = {
|
||||
|
|
@ -35,10 +35,20 @@ export type TUserContext = {
|
|||
redirect?: string;
|
||||
};
|
||||
|
||||
export type TAuthConfig = {
|
||||
loginRedirect: string;
|
||||
};
|
||||
//@ts-ignore - index expression is not of type number
|
||||
window['errorTimeout'] = undefined;
|
||||
const AuthContext = createContext<TAuthContext | undefined>(undefined);
|
||||
|
||||
const AuthContextProvider = ({ children }: { children: ReactNode }) => {
|
||||
const AuthContextProvider = ({
|
||||
authConfig,
|
||||
children
|
||||
}: {
|
||||
authConfig: TAuthConfig;
|
||||
children: ReactNode;
|
||||
}) => {
|
||||
const [user, setUser] = useState<TUser | undefined>(undefined);
|
||||
const [token, setToken] = useState<string | undefined>(undefined);
|
||||
const [error, setError] = useState<string | undefined>(undefined);
|
||||
|
|
@ -60,7 +70,7 @@ const AuthContextProvider = ({ children }: { children: ReactNode }) => {
|
|||
setError(error);
|
||||
}, 400);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const setUserContext = useCallback(
|
||||
(userContext: TUserContext) => {
|
||||
|
|
@ -79,7 +89,7 @@ const AuthContextProvider = ({ children }: { children: ReactNode }) => {
|
|||
[navigate]
|
||||
);
|
||||
|
||||
const getCookieValue = (key) => {
|
||||
const getCookieValue = (key: string) => {
|
||||
let keyValue = document.cookie.match('(^|;) ?' + key + '=([^;]*)(;|$)');
|
||||
return keyValue ? keyValue[2] : null;
|
||||
};
|
||||
|
|
@ -157,7 +167,7 @@ const AuthContextProvider = ({ children }: { children: ReactNode }) => {
|
|||
// setError(error.message);
|
||||
// }
|
||||
// });
|
||||
//
|
||||
//
|
||||
// }, [setUserContext]);
|
||||
|
||||
// useEffect(() => {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import {
|
|||
useGetMessagesByConvoId,
|
||||
useGetConversationByIdMutation,
|
||||
useGetStartupConfig
|
||||
} from '~/data-provider';
|
||||
} from '@librechat/data-provider';
|
||||
|
||||
export default function Chat() {
|
||||
const [shouldNavigate, setShouldNavigate] = useState(true);
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import {
|
|||
useGetEndpointsQuery,
|
||||
useGetPresetsQuery,
|
||||
useGetSearchEnabledQuery
|
||||
} from '~/data-provider';
|
||||
} from '@librechat/data-provider';
|
||||
|
||||
import MessageHandler from '../components/MessageHandler';
|
||||
import MobileNav from '../components/Nav/MobileNav';
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue