mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-17 00:40:14 +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
20
.eslintrc.js
20
.eslintrc.js
|
|
@ -24,7 +24,7 @@ module.exports = {
|
||||||
plugins: ['react', 'react-hooks', '@typescript-eslint'],
|
plugins: ['react', 'react-hooks', '@typescript-eslint'],
|
||||||
rules: {
|
rules: {
|
||||||
'react/react-in-jsx-scope': 'off',
|
'react/react-in-jsx-scope': 'off',
|
||||||
'@typescript-eslint/ban-ts-comment': ['error', { 'ts-ignore': 'allow-with-description' }],
|
'@typescript-eslint/ban-ts-comment': ['error', { 'ts-ignore': 'allow' }],
|
||||||
indent: ['error', 2, { SwitchCase: 1 }],
|
indent: ['error', 2, { SwitchCase: 1 }],
|
||||||
'max-len': [
|
'max-len': [
|
||||||
'error',
|
'error',
|
||||||
|
|
@ -42,12 +42,6 @@ module.exports = {
|
||||||
// 'no-plusplus': ['error', { allowForLoopAfterthoughts: true }],
|
// 'no-plusplus': ['error', { allowForLoopAfterthoughts: true }],
|
||||||
'no-console': 'off',
|
'no-console': 'off',
|
||||||
'import/extensions': 'off',
|
'import/extensions': 'off',
|
||||||
'no-use-before-define': [
|
|
||||||
'error',
|
|
||||||
{
|
|
||||||
functions: false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
'no-promise-executor-return': 'off',
|
'no-promise-executor-return': 'off',
|
||||||
'no-param-reassign': 'off',
|
'no-param-reassign': 'off',
|
||||||
'no-continue': 'off',
|
'no-continue': 'off',
|
||||||
|
|
@ -103,6 +97,18 @@ module.exports = {
|
||||||
'plugin:@typescript-eslint/eslint-recommended',
|
'plugin:@typescript-eslint/eslint-recommended',
|
||||||
'plugin:@typescript-eslint/recommended'
|
'plugin:@typescript-eslint/recommended'
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
files: './packages/data-provider/**/*.ts',
|
||||||
|
overrides: [
|
||||||
|
{
|
||||||
|
files: "**/*.ts",
|
||||||
|
parser: "@typescript-eslint/parser",
|
||||||
|
parserOptions: {
|
||||||
|
project: "./packages/data-provider/tsconfig.json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
settings: {
|
settings: {
|
||||||
|
|
|
||||||
4
.github/workflows/frontend-review.yml
vendored
4
.github/workflows/frontend-review.yml
vendored
|
|
@ -25,10 +25,10 @@ jobs:
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: npm ci --ignore-scripts
|
run: npm ci
|
||||||
|
|
||||||
- name: Build Client
|
- name: Build Client
|
||||||
run: cd client && npm run build:ci
|
run: npm run frontend:ci
|
||||||
|
|
||||||
- name: Run unit tests
|
- name: Run unit tests
|
||||||
run: cd client && npm run test:ci
|
run: cd client && npm run test:ci
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -39,6 +39,7 @@ meili_data/
|
||||||
api/node_modules/
|
api/node_modules/
|
||||||
client/node_modules/
|
client/node_modules/
|
||||||
bower_components/
|
bower_components/
|
||||||
|
types/
|
||||||
|
|
||||||
# Floobits
|
# Floobits
|
||||||
.floo
|
.floo
|
||||||
|
|
@ -72,3 +73,5 @@ junit.xml
|
||||||
meilisearch
|
meilisearch
|
||||||
data.ms/*
|
data.ms/*
|
||||||
auth.json
|
auth.json
|
||||||
|
|
||||||
|
/packages/ux-shared/
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
"version": "0.5.2",
|
"version": "0.5.2",
|
||||||
"description": "",
|
"description": "",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"data-provider": "cd .. && npm run build:data-provider",
|
||||||
"build": "cross-env NODE_ENV=production dotenv -e ../.env -- vite build",
|
"build": "cross-env NODE_ENV=production dotenv -e ../.env -- vite build",
|
||||||
"build:ci": "cross-env NODE_ENV=dev vite build --mode ci",
|
"build:ci": "cross-env NODE_ENV=dev vite build --mode ci",
|
||||||
"dev": "cross-env NODE_ENV=dev dotenv -e ../.env -- vite",
|
"dev": "cross-env NODE_ENV=dev dotenv -e ../.env -- vite",
|
||||||
|
|
@ -75,7 +76,8 @@
|
||||||
"tailwind-merge": "^1.9.1",
|
"tailwind-merge": "^1.9.1",
|
||||||
"tailwindcss-animate": "^1.0.5",
|
"tailwindcss-animate": "^1.0.5",
|
||||||
"tailwindcss-radix": "^2.8.0",
|
"tailwindcss-radix": "^2.8.0",
|
||||||
"url": "^0.11.0"
|
"url": "^0.11.0",
|
||||||
|
"@librechat/data-provider": "*"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/cli": "^7.20.7",
|
"@babel/cli": "^7.20.7",
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import { useEffect } from 'react';
|
||||||
import LoginForm from './LoginForm';
|
import LoginForm from './LoginForm';
|
||||||
import { useAuthContext } from '~/hooks/AuthContext';
|
import { useAuthContext } from '~/hooks/AuthContext';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { useGetStartupConfig } from '~/data-provider';
|
import { useGetStartupConfig } from '@librechat/data-provider';
|
||||||
|
|
||||||
function Login() {
|
function Login() {
|
||||||
const { login, error, isAuthenticated } = useAuthContext();
|
const { login, error, isAuthenticated } = useAuthContext();
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
import { TLoginUser } from '~/data-provider';
|
import { TLoginUser } from '@librechat/data-provider';
|
||||||
|
|
||||||
type TLoginFormProps = {
|
type TLoginFormProps = {
|
||||||
onSubmit: (data: TLoginUser) => void;
|
onSubmit: (data: TLoginUser) => void;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,11 @@
|
||||||
import { useState, useEffect } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
import { useRegisterUserMutation, TRegisterUser, useGetStartupConfig } from '~/data-provider';
|
import {
|
||||||
|
useRegisterUserMutation,
|
||||||
|
TRegisterUser,
|
||||||
|
useGetStartupConfig
|
||||||
|
} from '@librechat/data-provider';
|
||||||
|
|
||||||
function Registration() {
|
function Registration() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
@ -27,7 +31,9 @@ function Registration() {
|
||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
setError(true);
|
setError(true);
|
||||||
|
//@ts-ignore - error is of type unknown
|
||||||
if (error.response?.data?.message) {
|
if (error.response?.data?.message) {
|
||||||
|
//@ts-ignore - error is of type unknown
|
||||||
setErrorMessage(error.response?.data?.message);
|
setErrorMessage(error.response?.data?.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
import { useRequestPasswordResetMutation, TRequestPasswordReset } from '~/data-provider';
|
import {
|
||||||
|
useRequestPasswordResetMutation,
|
||||||
|
TRequestPasswordReset,
|
||||||
|
TRequestPasswordResetResponse
|
||||||
|
} from '@librechat/data-provider';
|
||||||
|
|
||||||
function RequestPasswordReset() {
|
function RequestPasswordReset() {
|
||||||
const {
|
const {
|
||||||
|
|
@ -15,7 +19,7 @@ function RequestPasswordReset() {
|
||||||
|
|
||||||
const onSubmit = (data: TRequestPasswordReset) => {
|
const onSubmit = (data: TRequestPasswordReset) => {
|
||||||
requestPasswordReset.mutate(data, {
|
requestPasswordReset.mutate(data, {
|
||||||
onSuccess: (data) => {
|
onSuccess: (data: TRequestPasswordResetResponse) => {
|
||||||
setSuccess(true);
|
setSuccess(true);
|
||||||
setResetLink(data.link);
|
setResetLink(data.link);
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useForm } from 'react-hook-form';
|
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';
|
import { useNavigate, useSearchParams } from 'react-router-dom';
|
||||||
|
|
||||||
function ResetPassword() {
|
function ResetPassword() {
|
||||||
|
|
@ -73,12 +73,14 @@ function ResetPassword() {
|
||||||
<input
|
<input
|
||||||
type="hidden"
|
type="hidden"
|
||||||
id="token"
|
id="token"
|
||||||
|
// @ts-ignore - Type 'string | null' is not assignable to type 'string | number | readonly string[] | undefined'
|
||||||
value={params.get('token')}
|
value={params.get('token')}
|
||||||
{...register('token', { required: 'Unable to process: No valid reset token' })}
|
{...register('token', { required: 'Unable to process: No valid reset token' })}
|
||||||
/>
|
/>
|
||||||
<input
|
<input
|
||||||
type="hidden"
|
type="hidden"
|
||||||
id="userId"
|
id="userId"
|
||||||
|
// @ts-ignore - Type 'string | null' is not assignable to type 'string | number | readonly string[] | undefined'
|
||||||
value={params.get('userId')}
|
value={params.get('userId')}
|
||||||
{...register('userId', { required: 'Unable to process: No valid user id' })}
|
{...register('userId', { required: 'Unable to process: No valid user id' })}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import { render, waitFor } from 'layout-test-utils';
|
import { render, waitFor } from 'layout-test-utils';
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
import Login from '../Login';
|
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 = ({
|
const setup = ({
|
||||||
useGetUserQueryReturnValue = {
|
useGetUserQueryReturnValue = {
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import { render, waitFor } from 'layout-test-utils';
|
import { render, waitFor } from 'layout-test-utils';
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
import Registration from '../Registration';
|
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 = ({
|
const setup = ({
|
||||||
useGetUserQueryReturnValue = {
|
useGetUserQueryReturnValue = {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { useState, useRef, useEffect } from 'react';
|
import { useState, useRef, useEffect } from 'react';
|
||||||
import { useRecoilState, useSetRecoilState } from 'recoil';
|
import { useRecoilState, useSetRecoilState } from 'recoil';
|
||||||
import { useUpdateConversationMutation } from '~/data-provider';
|
import { useUpdateConversationMutation } from '@librechat/data-provider';
|
||||||
import RenameButton from './RenameButton';
|
import RenameButton from './RenameButton';
|
||||||
import DeleteButton from './DeleteButton';
|
import DeleteButton from './DeleteButton';
|
||||||
import ConvoIcon from '../svg/ConvoIcon';
|
import ConvoIcon from '../svg/ConvoIcon';
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import { useEffect } from 'react';
|
||||||
import TrashIcon from '../svg/TrashIcon';
|
import TrashIcon from '../svg/TrashIcon';
|
||||||
import CrossIcon from '../svg/CrossIcon';
|
import CrossIcon from '../svg/CrossIcon';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
import { useDeleteConversationMutation } from '~/data-provider';
|
import { useDeleteConversationMutation } from '@librechat/data-provider';
|
||||||
|
|
||||||
import store from '~/store';
|
import store from '~/store';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import { Checkbox } from '~/components/ui/Checkbox.tsx';
|
||||||
import SelectDropDown from '../../ui/SelectDropDown';
|
import SelectDropDown from '../../ui/SelectDropDown';
|
||||||
import { cn } from '~/utils/';
|
import { cn } from '~/utils/';
|
||||||
import useDebounce from '~/hooks/useDebounce';
|
import useDebounce from '~/hooks/useDebounce';
|
||||||
import { useUpdateTokenCountMutation } from '~/data-provider';
|
import { useUpdateTokenCountMutation } from '@librechat/data-provider';
|
||||||
|
|
||||||
const defaultTextProps =
|
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';
|
'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]);
|
}, [debouncedContext]);
|
||||||
|
|
||||||
return (
|
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="grid gap-6 sm:grid-cols-2">
|
||||||
<div className="col-span-1 flex flex-col items-center justify-start gap-6">
|
<div className="col-span-1 flex flex-col items-center justify-start gap-6">
|
||||||
<div className="grid w-full items-center gap-2">
|
<div className="grid w-full items-center gap-2">
|
||||||
|
|
@ -113,7 +113,8 @@ function Settings(props) {
|
||||||
<a
|
<a
|
||||||
href="https://github.com/danny-avila/LibreChat/blob/main/client/defaultSystemMessage.md"
|
href="https://github.com/danny-avila/LibreChat/blob/main/client/defaultSystemMessage.md"
|
||||||
target="_blank"
|
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
|
System Message
|
||||||
</a>{' '}
|
</a>{' '}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
import {Dialog, DialogTemplate, Input, Label} from '../ui/';
|
import { Dialog, DialogTemplate, Input, Label } from '../ui/';
|
||||||
import { cn } from '~/utils/';
|
import { cn } from '~/utils/';
|
||||||
import cleanupPreset from '~/utils/cleanupPreset';
|
import cleanupPreset from '~/utils/cleanupPreset';
|
||||||
import { useCreatePresetMutation } from '~/data-provider';
|
import { useCreatePresetMutation } from '@librechat/data-provider';
|
||||||
import store from '~/store';
|
import store from '~/store';
|
||||||
|
|
||||||
const SaveAsPresetDialog = ({ open, onOpenChange, preset }) => {
|
const SaveAsPresetDialog = ({ open, onOpenChange, preset }) => {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useGetStartupConfig } from '~/data-provider';
|
import { useGetStartupConfig } from '@librechat/data-provider';
|
||||||
|
|
||||||
export default function Footer() {
|
export default function Footer() {
|
||||||
const { data: config } = useGetStartupConfig();
|
const { data: config } = useGetStartupConfig();
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import { Trash2 } from 'lucide-react';
|
||||||
import FileUpload from './FileUpload';
|
import FileUpload from './FileUpload';
|
||||||
import getIcon from '~/utils/getIcon';
|
import getIcon from '~/utils/getIcon';
|
||||||
import getDefaultConversation from '~/utils/getDefaultConversation';
|
import getDefaultConversation from '~/utils/getDefaultConversation';
|
||||||
import { useDeletePresetMutation, useCreatePresetMutation } from '~/data-provider';
|
import { useDeletePresetMutation, useCreatePresetMutation } from '@librechat/data-provider';
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
|
|
@ -19,7 +19,8 @@ import {
|
||||||
DropdownMenuSeparator,
|
DropdownMenuSeparator,
|
||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
DialogTemplate,
|
DialogTemplate,
|
||||||
Dialog, DialogTrigger
|
Dialog,
|
||||||
|
DialogTrigger
|
||||||
} from '../../ui/';
|
} from '../../ui/';
|
||||||
import { cn } from '~/utils/';
|
import { cn } from '~/utils/';
|
||||||
|
|
||||||
|
|
@ -87,8 +88,9 @@ export default function NewConversationMenu() {
|
||||||
// set the current model
|
// set the current model
|
||||||
const onSelectEndpoint = (newEndpoint) => {
|
const onSelectEndpoint = (newEndpoint) => {
|
||||||
setMenuOpen(false);
|
setMenuOpen(false);
|
||||||
if (!newEndpoint) { return; }
|
if (!newEndpoint) {
|
||||||
else {
|
return;
|
||||||
|
} else {
|
||||||
newConversation({}, { endpoint: newEndpoint });
|
newConversation({}, { endpoint: newEndpoint });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -101,7 +103,7 @@ export default function NewConversationMenu() {
|
||||||
const currentConvo = getDefaultConversation({
|
const currentConvo = getDefaultConversation({
|
||||||
conversation,
|
conversation,
|
||||||
endpointsConfig,
|
endpointsConfig,
|
||||||
preset: newPreset,
|
preset: newPreset
|
||||||
});
|
});
|
||||||
|
|
||||||
setConversation(currentConvo);
|
setConversation(currentConvo);
|
||||||
|
|
@ -153,7 +155,7 @@ export default function NewConversationMenu() {
|
||||||
</Button>
|
</Button>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent
|
<DropdownMenuContent
|
||||||
className="w-96 dark:bg-gray-900 z-[100]"
|
className="z-[100] w-96 dark:bg-gray-900"
|
||||||
onCloseAutoFocus={(event) => event.preventDefault()}
|
onCloseAutoFocus={(event) => event.preventDefault()}
|
||||||
>
|
>
|
||||||
<DropdownMenuLabel
|
<DropdownMenuLabel
|
||||||
|
|
@ -166,11 +168,15 @@ export default function NewConversationMenu() {
|
||||||
<DropdownMenuRadioGroup
|
<DropdownMenuRadioGroup
|
||||||
value={endpoint}
|
value={endpoint}
|
||||||
onValueChange={onSelectEndpoint}
|
onValueChange={onSelectEndpoint}
|
||||||
className="overflow-y-auto gap-1 flex flex-col"
|
className="flex flex-col gap-1 overflow-y-auto"
|
||||||
>
|
>
|
||||||
{showEndpoints &&
|
{showEndpoints &&
|
||||||
(availableEndpoints.length ? (
|
(availableEndpoints.length ? (
|
||||||
<EndpointItems selectedEndpoint={endpoint} endpoints={availableEndpoints} onSelect={onSelectEndpoint} />
|
<EndpointItems
|
||||||
|
selectedEndpoint={endpoint}
|
||||||
|
endpoints={availableEndpoints}
|
||||||
|
onSelect={onSelectEndpoint}
|
||||||
|
/>
|
||||||
) : (
|
) : (
|
||||||
<DropdownMenuLabel className="dark:text-gray-300">
|
<DropdownMenuLabel className="dark:text-gray-300">
|
||||||
No endpoint available.
|
No endpoint available.
|
||||||
|
|
@ -217,7 +223,10 @@ export default function NewConversationMenu() {
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
<DropdownMenuRadioGroup
|
<DropdownMenuRadioGroup
|
||||||
onValueChange={onSelectPreset}
|
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 &&
|
{showPresets &&
|
||||||
(presets.length ? (
|
(presets.length ? (
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ import { Settings, AgentSettings } from '../../Endpoints/Plugins/';
|
||||||
import { cn } from '~/utils/';
|
import { cn } from '~/utils/';
|
||||||
import store from '~/store';
|
import store from '~/store';
|
||||||
import { useAuthContext } from '~/hooks/AuthContext';
|
import { useAuthContext } from '~/hooks/AuthContext';
|
||||||
import { useAvailablePluginsQuery } from '~/data-provider';
|
import { useAvailablePluginsQuery } from '@librechat/data-provider';
|
||||||
|
|
||||||
function PluginsOptions() {
|
function PluginsOptions() {
|
||||||
const { data: allPlugins } = useAvailablePluginsQuery();
|
const { data: allPlugins } = useAvailablePluginsQuery();
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { useRecoilValue, useResetRecoilState, useSetRecoilState } from 'recoil';
|
import { useRecoilValue, useResetRecoilState, useSetRecoilState } from 'recoil';
|
||||||
import { SSE } from '~/data-provider/sse.mjs';
|
import { SSE, createPayload } from '@librechat/data-provider';
|
||||||
import createPayload from '~/data-provider/createPayload';
|
|
||||||
import store from '~/store';
|
import store from '~/store';
|
||||||
import { useAuthContext } from '~/hooks/AuthContext';
|
import { useAuthContext } from '~/hooks/AuthContext';
|
||||||
|
|
||||||
|
|
@ -224,7 +223,8 @@ export default function MessageHandler() {
|
||||||
|
|
||||||
events.onopen = () => console.log('connection is opened');
|
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) {
|
events.onerror = function (e) {
|
||||||
console.log('error in opening conn.');
|
console.log('error in opening conn.');
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import HoverButtons from './HoverButtons';
|
||||||
import SiblingSwitch from './SiblingSwitch';
|
import SiblingSwitch from './SiblingSwitch';
|
||||||
import getIcon from '~/utils/getIcon';
|
import getIcon from '~/utils/getIcon';
|
||||||
import { useMessageHandler } from '~/utils/handleSubmit';
|
import { useMessageHandler } from '~/utils/handleSubmit';
|
||||||
import { useGetConversationByIdQuery } from '~/data-provider';
|
import { useGetConversationByIdQuery } from '@librechat/data-provider';
|
||||||
import { cn } from '~/utils/';
|
import { cn } from '~/utils/';
|
||||||
import store from '~/store';
|
import store from '~/store';
|
||||||
import getError from '~/utils/getError';
|
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">
|
<div className="markdown prose dark:prose-invert light w-full break-words">
|
||||||
{!isCreatedByUser ? (
|
{!isCreatedByUser ? (
|
||||||
<>
|
<>
|
||||||
<Content content={text} message={message}/>
|
<Content content={text} message={message} />
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>{text}</>
|
<>{text}</>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { useState, useEffect, useCallback } from 'react';
|
import { useState, useEffect, useCallback } from 'react';
|
||||||
import { Dialog, DialogTemplate } from '../ui/';
|
import { Dialog, DialogTemplate } from '../ui/';
|
||||||
import { ClearChatsButton } from './SettingsTabs/';
|
import { ClearChatsButton } from './SettingsTabs/';
|
||||||
import { useClearConversationsMutation } from '~/data-provider';
|
import { useClearConversationsMutation } from '@librechat/data-provider';
|
||||||
import store from '~/store';
|
import store from '~/store';
|
||||||
|
|
||||||
const ClearConvos = ({ open, onOpenChange }) => {
|
const ClearConvos = ({ open, onOpenChange }) => {
|
||||||
|
|
@ -32,7 +32,9 @@ const ClearConvos = ({ open, onOpenChange }) => {
|
||||||
<DialogTemplate
|
<DialogTemplate
|
||||||
title="Clear conversations"
|
title="Clear conversations"
|
||||||
description="Are you sure you want to clear all conversations? This is irreversible."
|
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>
|
</Dialog>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import { General } from './SettingsTabs/';
|
||||||
import { CogIcon } from '~/components/svg';
|
import { CogIcon } from '~/components/svg';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { cn } from '~/utils/';
|
import { cn } from '~/utils/';
|
||||||
import { useClearConversationsMutation } from '~/data-provider';
|
import { useClearConversationsMutation } from '@librechat/data-provider';
|
||||||
import store from '~/store';
|
import store from '~/store';
|
||||||
|
|
||||||
export default function Settings({ open, onOpenChange }) {
|
export default function Settings({ open, onOpenChange }) {
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,15 @@ import * as Tabs from '@radix-ui/react-tabs';
|
||||||
import { CheckIcon } from 'lucide-react';
|
import { CheckIcon } from 'lucide-react';
|
||||||
import { ThemeContext } from '~/hooks/ThemeContext';
|
import { ThemeContext } from '~/hooks/ThemeContext';
|
||||||
import React, { useState, useContext, useCallback } from 'react';
|
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 className="flex items-center justify-between">
|
||||||
<div>Theme</div>
|
<div>Theme</div>
|
||||||
<select
|
<select
|
||||||
|
|
@ -19,7 +25,15 @@ export const ThemeSelector = ({ theme, onChange }: { theme: string, onChange: (v
|
||||||
</div>
|
</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">
|
<div className="flex items-center justify-between">
|
||||||
{showText && <div>Clear all chats</div>}
|
{showText && <div>Clear all chats</div>}
|
||||||
<button
|
<button
|
||||||
|
|
@ -45,7 +59,7 @@ function General() {
|
||||||
const { theme, setTheme } = useContext(ThemeContext);
|
const { theme, setTheme } = useContext(ThemeContext);
|
||||||
const clearConvosMutation = useClearConversationsMutation();
|
const clearConvosMutation = useClearConversationsMutation();
|
||||||
const [confirmClear, setConfirmClear] = useState(false);
|
const [confirmClear, setConfirmClear] = useState(false);
|
||||||
|
|
||||||
const clearConvos = useCallback(() => {
|
const clearConvos = useCallback(() => {
|
||||||
if (confirmClear) {
|
if (confirmClear) {
|
||||||
console.log('Clearing conversations...');
|
console.log('Clearing conversations...');
|
||||||
|
|
@ -56,18 +70,21 @@ function General() {
|
||||||
}
|
}
|
||||||
}, [confirmClear, clearConvosMutation]);
|
}, [confirmClear, clearConvosMutation]);
|
||||||
|
|
||||||
const changeTheme = useCallback((value: string) => {
|
const changeTheme = useCallback(
|
||||||
setTheme(value);
|
(value: string) => {
|
||||||
}, [setTheme]);
|
setTheme(value);
|
||||||
|
},
|
||||||
|
[setTheme]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
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="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">
|
<div className="border-b pb-3 last-of-type:border-b-0 dark:border-gray-700">
|
||||||
<ThemeSelector theme={theme} onChange={changeTheme} />
|
<ThemeSelector theme={theme} onChange={changeTheme} />
|
||||||
</div>
|
</div>
|
||||||
<div className="border-b pb-3 last-of-type:border-b-0 dark:border-gray-700">
|
<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>
|
||||||
</div>
|
</div>
|
||||||
</Tabs.Content>
|
</Tabs.Content>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/* eslint-disable react-hooks/exhaustive-deps */
|
/* eslint-disable react-hooks/exhaustive-deps */
|
||||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
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 { useRecoilValue, useSetRecoilState } from 'recoil';
|
||||||
|
|
||||||
import Conversations from '../Conversations';
|
import Conversations from '../Conversations';
|
||||||
|
|
@ -9,7 +9,6 @@ import NewChat from './NewChat';
|
||||||
import Pages from '../Conversations/Pages';
|
import Pages from '../Conversations/Pages';
|
||||||
import Panel from '../svg/Panel';
|
import Panel from '../svg/Panel';
|
||||||
import Spinner from '../svg/Spinner';
|
import Spinner from '../svg/Spinner';
|
||||||
// import { ThemeContext } from '~/hooks/ThemeContext';
|
|
||||||
import { cn } from '~/utils/';
|
import { cn } from '~/utils/';
|
||||||
import store from '~/store';
|
import store from '~/store';
|
||||||
import { useAuthContext } from '~/hooks/AuthContext';
|
import { useAuthContext } from '~/hooks/AuthContext';
|
||||||
|
|
@ -38,7 +37,6 @@ import useDebounce from '~/hooks/useDebounce';
|
||||||
export default function Nav({ navVisible, setNavVisible }) {
|
export default function Nav({ navVisible, setNavVisible }) {
|
||||||
const [isHovering, setIsHovering] = useState(false);
|
const [isHovering, setIsHovering] = useState(false);
|
||||||
const { isAuthenticated } = useAuthContext();
|
const { isAuthenticated } = useAuthContext();
|
||||||
// const { theme, } = useContext(ThemeContext);
|
|
||||||
const containerRef = useRef(null);
|
const containerRef = useRef(null);
|
||||||
const scrollPositionRef = useRef(null);
|
const scrollPositionRef = useRef(null);
|
||||||
|
|
||||||
|
|
@ -159,7 +157,8 @@ export default function Nav({ navVisible, setNavVisible }) {
|
||||||
|
|
||||||
const isMobile = () => {
|
const isMobile = () => {
|
||||||
const userAgent = typeof window.navigator === 'undefined' ? '' : navigator.userAgent;
|
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);
|
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 { Save } from 'lucide-react';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
import { TPluginAction } from './PluginStoreDialog';
|
import { TPluginAction } from './PluginStoreDialog';
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,11 @@ import { useRecoilState } from 'recoil';
|
||||||
import { X } from 'lucide-react';
|
import { X } from 'lucide-react';
|
||||||
import store from '~/store';
|
import store from '~/store';
|
||||||
import { PluginStoreItem, PluginPagination, PluginAuthForm } from '.';
|
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';
|
import { useAuthContext } from '~/hooks/AuthContext';
|
||||||
|
|
||||||
type TPluginStoreDialogProps = {
|
type TPluginStoreDialogProps = {
|
||||||
|
|
@ -95,8 +99,7 @@ function PluginStoreDialog({ isOpen, setIsOpen }: TPluginStoreDialogProps) {
|
||||||
if (width < 501) {
|
if (width < 501) {
|
||||||
setItemsPerPage(8);
|
setItemsPerPage(8);
|
||||||
return;
|
return;
|
||||||
} else
|
} else if (width < 640) {
|
||||||
if (width < 640) {
|
|
||||||
columns = 2;
|
columns = 2;
|
||||||
} else if (width < 1024) {
|
} else if (width < 1024) {
|
||||||
columns = 3;
|
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" />
|
<div className="fixed inset-0 bg-gray-500/90 transition-opacity dark:bg-gray-800/90" />
|
||||||
{/* Full-screen container to center the panel */}
|
{/* Full-screen container to center the panel */}
|
||||||
<div className="fixed inset-0 flex items-center justify-center p-4">
|
<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 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="flex items-center">
|
||||||
<div className="text-center sm:text-left">
|
<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';
|
import { XCircle, DownloadCloud } from 'lucide-react';
|
||||||
|
|
||||||
type TPluginStoreItemProps = {
|
type TPluginStoreItemProps = {
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import { render } from 'layout-test-utils';
|
import { render } from 'layout-test-utils';
|
||||||
import PluginStoreDialog from '../PluginStoreDialog';
|
import PluginStoreDialog from '../PluginStoreDialog';
|
||||||
import userEvent from '@testing-library/user-event';
|
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 {
|
class ResizeObserver {
|
||||||
observe() {
|
observe() {
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import SunIcon from '../svg/SunIcon';
|
||||||
import LightningIcon from '../svg/LightningIcon';
|
import LightningIcon from '../svg/LightningIcon';
|
||||||
import CautionIcon from '../svg/CautionIcon';
|
import CautionIcon from '../svg/CautionIcon';
|
||||||
import store from '~/store';
|
import store from '~/store';
|
||||||
import { useGetStartupConfig } from '~/data-provider';
|
import { useGetStartupConfig } from '@librechat/data-provider';
|
||||||
|
|
||||||
export default function Landing() {
|
export default function Landing() {
|
||||||
const { data: config } = useGetStartupConfig();
|
const { data: config } = useGetStartupConfig();
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ import {
|
||||||
useGetUserQuery,
|
useGetUserQuery,
|
||||||
useRefreshTokenMutation,
|
useRefreshTokenMutation,
|
||||||
TLoginUser
|
TLoginUser
|
||||||
} from '~/data-provider';
|
} from '@librechat/data-provider';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
export type TAuthContext = {
|
export type TAuthContext = {
|
||||||
|
|
@ -35,10 +35,20 @@ export type TUserContext = {
|
||||||
redirect?: string;
|
redirect?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type TAuthConfig = {
|
||||||
|
loginRedirect: string;
|
||||||
|
};
|
||||||
|
//@ts-ignore - index expression is not of type number
|
||||||
window['errorTimeout'] = undefined;
|
window['errorTimeout'] = undefined;
|
||||||
const AuthContext = createContext<TAuthContext | undefined>(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 [user, setUser] = useState<TUser | undefined>(undefined);
|
||||||
const [token, setToken] = useState<string | undefined>(undefined);
|
const [token, setToken] = useState<string | undefined>(undefined);
|
||||||
const [error, setError] = useState<string | undefined>(undefined);
|
const [error, setError] = useState<string | undefined>(undefined);
|
||||||
|
|
@ -60,7 +70,7 @@ const AuthContextProvider = ({ children }: { children: ReactNode }) => {
|
||||||
setError(error);
|
setError(error);
|
||||||
}, 400);
|
}, 400);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const setUserContext = useCallback(
|
const setUserContext = useCallback(
|
||||||
(userContext: TUserContext) => {
|
(userContext: TUserContext) => {
|
||||||
|
|
@ -79,7 +89,7 @@ const AuthContextProvider = ({ children }: { children: ReactNode }) => {
|
||||||
[navigate]
|
[navigate]
|
||||||
);
|
);
|
||||||
|
|
||||||
const getCookieValue = (key) => {
|
const getCookieValue = (key: string) => {
|
||||||
let keyValue = document.cookie.match('(^|;) ?' + key + '=([^;]*)(;|$)');
|
let keyValue = document.cookie.match('(^|;) ?' + key + '=([^;]*)(;|$)');
|
||||||
return keyValue ? keyValue[2] : null;
|
return keyValue ? keyValue[2] : null;
|
||||||
};
|
};
|
||||||
|
|
@ -157,7 +167,7 @@ const AuthContextProvider = ({ children }: { children: ReactNode }) => {
|
||||||
// setError(error.message);
|
// setError(error.message);
|
||||||
// }
|
// }
|
||||||
// });
|
// });
|
||||||
//
|
//
|
||||||
// }, [setUserContext]);
|
// }, [setUserContext]);
|
||||||
|
|
||||||
// useEffect(() => {
|
// useEffect(() => {
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ import {
|
||||||
useGetMessagesByConvoId,
|
useGetMessagesByConvoId,
|
||||||
useGetConversationByIdMutation,
|
useGetConversationByIdMutation,
|
||||||
useGetStartupConfig
|
useGetStartupConfig
|
||||||
} from '~/data-provider';
|
} from '@librechat/data-provider';
|
||||||
|
|
||||||
export default function Chat() {
|
export default function Chat() {
|
||||||
const [shouldNavigate, setShouldNavigate] = useState(true);
|
const [shouldNavigate, setShouldNavigate] = useState(true);
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import {
|
||||||
useGetEndpointsQuery,
|
useGetEndpointsQuery,
|
||||||
useGetPresetsQuery,
|
useGetPresetsQuery,
|
||||||
useGetSearchEnabledQuery
|
useGetSearchEnabledQuery
|
||||||
} from '~/data-provider';
|
} from '@librechat/data-provider';
|
||||||
|
|
||||||
import MessageHandler from '../components/MessageHandler';
|
import MessageHandler from '../components/MessageHandler';
|
||||||
import MobileNav from '../components/Nav/MobileNav';
|
import MobileNav from '../components/Nav/MobileNav';
|
||||||
|
|
|
||||||
1125
package-lock.json
generated
1125
package-lock.json
generated
File diff suppressed because it is too large
Load diff
15
package.json
15
package.json
|
|
@ -4,16 +4,19 @@
|
||||||
"description": "",
|
"description": "",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"api",
|
"api",
|
||||||
"client"
|
"client",
|
||||||
|
"packages/data-provider"
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"install": "node config/install.js",
|
"install": "node config/install.js",
|
||||||
"upgrade": "node config/upgrade.js",
|
"upgrade": "node config/upgrade.js",
|
||||||
"create-user": "node config/create-user.js",
|
"create-user": "node config/create-user.js",
|
||||||
"backend": "cross-env NODE_ENV=production node api/server/index.js",
|
"backend": "cross-env NODE_ENV=production node api/server/index.js",
|
||||||
"backend-dev": "cross-env NODE_ENV=development npx nodemon api/server/index.js",
|
"backend:dev": "cross-env NODE_ENV=development npx nodemon api/server/index.js",
|
||||||
"frontend": "cd client && npm run build",
|
"build:data-provider": "cd packages/data-provider && npm run build && npm link && cd ../../client && npm link @librechat/data-provider",
|
||||||
"frontend-dev": "cd client && npm run dev",
|
"frontend": "npm run build:data-provider && cd client && npm run build",
|
||||||
|
"frontend:ci": "npm run build:data-provider && cd client && npm run build:ci",
|
||||||
|
"frontend:dev": "cd client && npm run dev",
|
||||||
"e2e": "playwright test --config=e2e/playwright.config.local.ts",
|
"e2e": "playwright test --config=e2e/playwright.config.local.ts",
|
||||||
"e2e:ci": "playwright test --config=e2e/playwright.config.ts",
|
"e2e:ci": "playwright test --config=e2e/playwright.config.ts",
|
||||||
"e2e:debug": "cross-env PWDEBUG=1 playwright test --config=e2e/playwright.config.local.ts",
|
"e2e:debug": "cross-env PWDEBUG=1 playwright test --config=e2e/playwright.config.local.ts",
|
||||||
|
|
@ -66,7 +69,9 @@
|
||||||
"ignore": [
|
"ignore": [
|
||||||
"api/data/",
|
"api/data/",
|
||||||
"data",
|
"data",
|
||||||
"client/"
|
"client/",
|
||||||
|
"admin/",
|
||||||
|
"packages/"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
4
packages/data-provider/babel.config.js
Normal file
4
packages/data-provider/babel.config.js
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
module.exports = {
|
||||||
|
presets: [['@babel/preset-env', {targets: {node: 'current'}}], '@babel/preset-typescript'],
|
||||||
|
plugins: ['babel-plugin-replace-ts-export-assignment'],
|
||||||
|
};
|
||||||
18
packages/data-provider/jest.config.js
Normal file
18
packages/data-provider/jest.config.js
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
module.exports = {
|
||||||
|
collectCoverageFrom: ['src/**/*.{js,jsx,ts,tsx}', '!<rootDir>/node_modules/'],
|
||||||
|
coveragePathIgnorePatterns: ['/node_modules/', '/dist/'],
|
||||||
|
coverageReporters: ['text', 'cobertura'],
|
||||||
|
testResultsProcessor: 'jest-junit',
|
||||||
|
moduleNameMapper: {
|
||||||
|
'^@src/(.*)$': '<rootDir>/src/$1',
|
||||||
|
},
|
||||||
|
// coverageThreshold: {
|
||||||
|
// global: {
|
||||||
|
// statements: 58,
|
||||||
|
// branches: 49,
|
||||||
|
// functions: 50,
|
||||||
|
// lines: 57,
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
restoreMocks: true
|
||||||
|
};
|
||||||
47
packages/data-provider/package.json
Normal file
47
packages/data-provider/package.json
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
{
|
||||||
|
"name": "@librechat/data-provider",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"description": "data services for librechat apps",
|
||||||
|
"main": "dist/index.js",
|
||||||
|
"module": "dist/index.es.js",
|
||||||
|
"types": "types/",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"clean": "rimraf dist",
|
||||||
|
"build": "npm run clean && rollup -c --silent --bundleConfigAsCjs",
|
||||||
|
"build:watch": "rollup -c -w",
|
||||||
|
"test": "jest --coverage --watch",
|
||||||
|
"test:ci": "jest --coverage --ci",
|
||||||
|
"verify": "npm run test:ci"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/danny-avila/LibreChat.git"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/danny-avila/LibreChat/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/danny-avila/LibreChat#readme",
|
||||||
|
"dependencies": {
|
||||||
|
"@tanstack/react-query": "^4.28.0",
|
||||||
|
"axios": "^1.3.4"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/preset-env": "^7.21.5",
|
||||||
|
"@babel/preset-react": "^7.18.6",
|
||||||
|
"@babel/preset-typescript": "^7.21.0",
|
||||||
|
"@rollup/plugin-commonjs": "^25.0.2",
|
||||||
|
"@rollup/plugin-node-resolve": "^15.1.0",
|
||||||
|
"@tanstack/query-core": "^4.29.19",
|
||||||
|
"@types/jest": "^29.5.2",
|
||||||
|
"@types/node": "^20.3.0",
|
||||||
|
"jest": "^29.5.0",
|
||||||
|
"jest-junit": "^16.0.0",
|
||||||
|
"rimraf": "^5.0.1",
|
||||||
|
"rollup": "^3.26.0",
|
||||||
|
"rollup-plugin-typescript2": "^0.35.0",
|
||||||
|
"typescript": "^5.0.4"
|
||||||
|
}
|
||||||
|
}
|
||||||
31
packages/data-provider/rollup.config.js
Normal file
31
packages/data-provider/rollup.config.js
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
import typescript from 'rollup-plugin-typescript2';
|
||||||
|
import resolve from '@rollup/plugin-node-resolve';
|
||||||
|
import pkg from './package.json';
|
||||||
|
|
||||||
|
export default [
|
||||||
|
{
|
||||||
|
input: 'src/index.ts',
|
||||||
|
output: [
|
||||||
|
{
|
||||||
|
file: pkg.main,
|
||||||
|
format: 'cjs',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
file: pkg.module,
|
||||||
|
format: 'esm',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
...{
|
||||||
|
external: [
|
||||||
|
...Object.keys(pkg.dependencies || {}),
|
||||||
|
...Object.keys(pkg.devDependencies || {}),
|
||||||
|
...Object.keys(pkg.peerDependencies || {}),
|
||||||
|
],
|
||||||
|
preserveSymlinks: true,
|
||||||
|
plugins: [
|
||||||
|
resolve(),
|
||||||
|
typescript({useTsconfigDeclarationDir: true, tsconfig: './tsconfig.json'}),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
@ -10,6 +10,7 @@ export default function createPayload(submission: TSubmission) {
|
||||||
openAI: '/api/ask/openAI',
|
openAI: '/api/ask/openAI',
|
||||||
google: '/api/ask/google',
|
google: '/api/ask/google',
|
||||||
bingAI: '/api/ask/bingAI',
|
bingAI: '/api/ask/bingAI',
|
||||||
|
chatGPT: '/api/ask/chatGPT',
|
||||||
chatGPTBrowser: '/api/ask/chatGPTBrowser',
|
chatGPTBrowser: '/api/ask/chatGPTBrowser',
|
||||||
gptPlugins: '/api/ask/gptPlugins'
|
gptPlugins: '/api/ask/gptPlugins'
|
||||||
};
|
};
|
||||||
|
|
@ -23,4 +24,4 @@ export default function createPayload(submission: TSubmission) {
|
||||||
};
|
};
|
||||||
|
|
||||||
return { server, payload };
|
return { server, payload };
|
||||||
}
|
}
|
||||||
|
|
@ -96,7 +96,7 @@ export const getLoginGoogle = () => {
|
||||||
return request.get(endpoints.loginGoogle());
|
return request.get(endpoints.loginGoogle());
|
||||||
};
|
};
|
||||||
|
|
||||||
export const requestPasswordReset = (payload: t.TRequestPasswordReset) => {
|
export const requestPasswordReset = (payload: t.TRequestPasswordReset): Promise<t.TRequestPasswordResetResponse> => {
|
||||||
return request.post(endpoints.requestPasswordReset(), payload);
|
return request.post(endpoints.requestPasswordReset(), payload);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
export * from './data-service';
|
export * from './data-service';
|
||||||
// export * from './endpoints';
|
|
||||||
export * from './request';
|
export * from './request';
|
||||||
export * from './types';
|
export * from './types';
|
||||||
export * from './react-query-service';
|
export * from './react-query-service';
|
||||||
export * from './headers-helpers';
|
export * from './headers-helpers';
|
||||||
// export * from './events';
|
export * from './sse.mjs';
|
||||||
|
export {default as createPayload} from './createPayload';
|
||||||
|
|
@ -140,9 +140,9 @@ export const useClearConversationsMutation = (): UseMutationResult<unknown> => {
|
||||||
|
|
||||||
export const useGetConversationsQuery = (
|
export const useGetConversationsQuery = (
|
||||||
pageNumber: string,
|
pageNumber: string,
|
||||||
config?: UseQueryOptions<t.TConversation[]>
|
config?: UseQueryOptions<t.TGetConversationsResponse>
|
||||||
): QueryObserverResult<t.TConversation[]> => {
|
): QueryObserverResult<t.TGetConversationsResponse> => {
|
||||||
return useQuery<t.TConversation[]>(
|
return useQuery<t.TGetConversationsResponse>(
|
||||||
[QueryKeys.allConversations, pageNumber],
|
[QueryKeys.allConversations, pageNumber],
|
||||||
() => dataService.getConversations(pageNumber),
|
() => dataService.getConversations(pageNumber),
|
||||||
{
|
{
|
||||||
|
|
@ -302,13 +302,19 @@ export const useRefreshTokenMutation = (): UseMutationResult<
|
||||||
> => {
|
> => {
|
||||||
return useMutation(() => dataService.refreshToken(), {});
|
return useMutation(() => dataService.refreshToken(), {});
|
||||||
};
|
};
|
||||||
export const useRequestPasswordResetMutation = (): UseMutationResult<unknown> => {
|
|
||||||
|
export const useRequestPasswordResetMutation = (): UseMutationResult<t.TRequestPasswordResetResponse, unknown, t.TRequestPasswordReset, unknown> => {
|
||||||
return useMutation((payload: t.TRequestPasswordReset) =>
|
return useMutation((payload: t.TRequestPasswordReset) =>
|
||||||
dataService.requestPasswordReset(payload)
|
dataService.requestPasswordReset(payload)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useResetPasswordMutation = (): UseMutationResult<unknown> => {
|
export const useResetPasswordMutation = (): UseMutationResult<
|
||||||
|
unknown,
|
||||||
|
unknown,
|
||||||
|
t.TResetPassword,
|
||||||
|
unknown
|
||||||
|
> => {
|
||||||
return useMutation((payload: t.TResetPassword) => dataService.resetPassword(payload));
|
return useMutation((payload: t.TResetPassword) => dataService.resetPassword(payload));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -16,6 +16,52 @@ export type TExample = {
|
||||||
output: string;
|
output: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export enum EModelEndpoint {
|
||||||
|
azureOpenAI = 'azureOpenAI',
|
||||||
|
openAI = 'openAI',
|
||||||
|
bingAI = 'bingAI',
|
||||||
|
chatGPT = 'chatGPT',
|
||||||
|
chatGPTBrowser = 'chatGPTBrowser',
|
||||||
|
google = 'google',
|
||||||
|
gptPlugins = 'gptPlugins',
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TSubmission = {
|
||||||
|
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;
|
||||||
|
conversation: TConversation;
|
||||||
|
message: TMessage;
|
||||||
|
endpointOption: TEndpointOption;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TEndpointOption = {
|
||||||
|
endpoint: EModelEndpoint;
|
||||||
|
model?: string;
|
||||||
|
promptPrefix?: string;
|
||||||
|
temperature?: number;
|
||||||
|
}
|
||||||
|
|
||||||
export type TPluginAuthConfig = {
|
export type TPluginAuthConfig = {
|
||||||
authField: string;
|
authField: string;
|
||||||
label: string;
|
label: string;
|
||||||
|
|
@ -31,15 +77,11 @@ export type TPlugin = {
|
||||||
authenticated: boolean;
|
authenticated: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export enum EModelEndpoint {
|
export type TUpdateUserPlugins = {
|
||||||
azureOpenAI = 'azureOpenAI',
|
pluginKey: string;
|
||||||
openAI = 'openAI',
|
action: string;
|
||||||
bingAI = 'bingAI',
|
auth?: unknown;
|
||||||
chatGPT = 'chatGPT',
|
};
|
||||||
chatGPTBrowser = 'chatGPTBrowser',
|
|
||||||
google = 'google',
|
|
||||||
gptPlugins = 'gptPlugins'
|
|
||||||
}
|
|
||||||
|
|
||||||
export type TConversation = {
|
export type TConversation = {
|
||||||
conversationId: string;
|
conversationId: string;
|
||||||
|
|
@ -76,41 +118,6 @@ export type TConversation = {
|
||||||
toneStyle?: 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 = {
|
export type TPreset = {
|
||||||
title: string;
|
title: string;
|
||||||
endpoint: EModelEndpoint;
|
endpoint: EModelEndpoint;
|
||||||
|
|
@ -235,15 +242,25 @@ export type TResetPassword = {
|
||||||
userId: string;
|
userId: string;
|
||||||
token: string;
|
token: string;
|
||||||
password: string;
|
password: string;
|
||||||
|
confirm_password?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TStartupConfig = {
|
export type TStartupConfig = {
|
||||||
appTitle: boolean;
|
appTitle: boolean;
|
||||||
googleLoginEnabled: boolean;
|
googleLoginEnabled: boolean;
|
||||||
openidLoginEnabled: boolean;
|
openidLoginEnabled: boolean;
|
||||||
|
githubLoginEnabled: boolean;
|
||||||
openidLabel: string;
|
openidLabel: string;
|
||||||
openidImageUrl: string;
|
openidImageUrl: string;
|
||||||
githubLoginEnabled: boolean;
|
|
||||||
serverDomain: string;
|
serverDomain: string;
|
||||||
registrationEnabled: boolean;
|
registrationEnabled: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type TRefreshTokenResponse = {
|
||||||
|
token: string;
|
||||||
|
user: TUser;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TRequestPasswordResetResponse = {
|
||||||
|
link: string;
|
||||||
|
};
|
||||||
27
packages/data-provider/tsconfig.json
Normal file
27
packages/data-provider/tsconfig.json
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"declaration": true,
|
||||||
|
"declarationDir": "./types",
|
||||||
|
"module": "esnext",
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"outDir": "./types",
|
||||||
|
"target": "es5",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"lib": ["es2017", "dom"],
|
||||||
|
"allowJs": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"strict": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"noEmit": true,
|
||||||
|
"baseUrl": "src",
|
||||||
|
"paths": {
|
||||||
|
"@src/*": ["./*"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"exclude": ["node_modules", "dist", "types"],
|
||||||
|
"include": ["src/**/*"]
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue