mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-09-22 08:12:00 +02:00
🛂 feat: OpenID Logout Redirect to end_session_endpoint
(#5626)
* WIP: end session endpoint * refactor: move useGetBannerQuery outside of package * refactor: add queriesEnabled and move useGetEndpointsConfigQuery to data-provider (local) * refactor: move useGetEndpointsQuery import to data-provider * refactor: relocate useGetEndpointsQuery import to improve module organization * refactor: move `useGetStartupConfig` from package to `~/data-provider` * refactor: move useGetUserBalance to data-provider and update imports * refactor: update query enabled conditions to include config check * refactor: remove unused useConfigOverride import from useAppStartup * refactor: integrate queriesEnabled state into file and search queries and move useGetSearchEnabledQuery to data-provider (local) * refactor: move useGetUserQuery to data-provider and update imports * refactor: enhance loginUser mutation with success and error handling as pass in options to hook * refactor: update enabled condition in queries to handle undefined config * refactor: enhance authentication mutations with queriesEnabled state management * refactor: improve conditional rendering for error messages and feature flags in Login component * refactor: remove unused queriesEnabled state from AuthContextProvider * refactor: implement queriesEnabled state management in LoginLayout with timeout handling * refactor: add conditional check for end session endpoint in OpenID strategy * ci: fix tests after changes * refactor: remove endSessionEndpoint from user schema and update logoutController to use OpenID issuer's end_session_endpoint * refactor: update logoutController to use end_session_endpoint from issuer metadata
This commit is contained in:
parent
d93f5c9061
commit
45dd2b262f
73 changed files with 385 additions and 270 deletions
|
@ -1,5 +1,7 @@
|
|||
const cookies = require('cookie');
|
||||
const { Issuer } = require('openid-client');
|
||||
const { logoutUser } = require('~/server/services/AuthService');
|
||||
const { isEnabled } = require('~/server/utils');
|
||||
const { logger } = require('~/config');
|
||||
|
||||
const logoutController = async (req, res) => {
|
||||
|
@ -8,7 +10,23 @@ const logoutController = async (req, res) => {
|
|||
const logout = await logoutUser(req, refreshToken);
|
||||
const { status, message } = logout;
|
||||
res.clearCookie('refreshToken');
|
||||
return res.status(status).send({ message });
|
||||
const response = { message };
|
||||
if (
|
||||
req.user.openidId != null &&
|
||||
isEnabled(process.env.OPENID_USE_END_SESSION_ENDPOINT) &&
|
||||
process.env.OPENID_ISSUER
|
||||
) {
|
||||
const issuer = await Issuer.discover(process.env.OPENID_ISSUER);
|
||||
const redirect = issuer.metadata.end_session_endpoint;
|
||||
if (!redirect) {
|
||||
logger.warn(
|
||||
'[logoutController] end_session_endpoint not found in OpenID issuer metadata. Please verify that the issuer is correct.',
|
||||
);
|
||||
} else {
|
||||
response.redirect = redirect;
|
||||
}
|
||||
}
|
||||
return res.status(status).send(response);
|
||||
} catch (err) {
|
||||
logger.error('[logoutController]', err);
|
||||
return res.status(500).json({ message: err.message });
|
||||
|
|
|
@ -129,7 +129,8 @@ async function setupOpenId() {
|
|||
redirect_uris: [process.env.DOMAIN_SERVER + process.env.OPENID_CALLBACK_URL],
|
||||
};
|
||||
if (isEnabled(process.env.OPENID_SET_FIRST_SUPPORTED_ALGORITHM)) {
|
||||
clientMetadata.id_token_signed_response_alg = issuer.id_token_signing_alg_values_supported?.[0] || 'RS256';
|
||||
clientMetadata.id_token_signed_response_alg =
|
||||
issuer.id_token_signing_alg_values_supported?.[0] || 'RS256';
|
||||
}
|
||||
const client = new issuer.Client(clientMetadata);
|
||||
const requiredRole = process.env.OPENID_REQUIRED_ROLE;
|
||||
|
|
|
@ -412,7 +412,7 @@ export type TAuthConfig = {
|
|||
};
|
||||
|
||||
export type IconProps = Pick<t.TMessage, 'isCreatedByUser' | 'model'> &
|
||||
Pick<t.TConversation, 'chatGptLabel' | 'modelLabel' | 'jailbreak'> & {
|
||||
Pick<t.TConversation, 'chatGptLabel' | 'modelLabel'> & {
|
||||
size?: number;
|
||||
button?: boolean;
|
||||
iconURL?: string;
|
||||
|
|
|
@ -13,8 +13,8 @@ function Login() {
|
|||
|
||||
return (
|
||||
<>
|
||||
{error && <ErrorMessage>{localize(getLoginError(error))}</ErrorMessage>}
|
||||
{startupConfig?.emailLoginEnabled && (
|
||||
{error != null && <ErrorMessage>{localize(getLoginError(error))}</ErrorMessage>}
|
||||
{startupConfig?.emailLoginEnabled === true && (
|
||||
<LoginForm
|
||||
onSubmit={login}
|
||||
startupConfig={startupConfig}
|
||||
|
@ -22,7 +22,7 @@ function Login() {
|
|||
setError={setError}
|
||||
/>
|
||||
)}
|
||||
{startupConfig?.registrationEnabled && (
|
||||
{startupConfig?.registrationEnabled === true && (
|
||||
<p className="my-4 text-center text-sm font-light text-gray-700 dark:text-white">
|
||||
{' '}
|
||||
{localize('com_auth_no_account')}{' '}
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import { useForm } from 'react-hook-form';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useGetStartupConfig } from 'librechat-data-provider/react-query';
|
||||
import type { TLoginUser, TStartupConfig } from 'librechat-data-provider';
|
||||
import type { TAuthContext } from '~/common';
|
||||
import { useResendVerificationEmail } from '~/data-provider';
|
||||
import { useResendVerificationEmail, useGetStartupConfig } from '~/data-provider';
|
||||
import { useLocalize } from '~/hooks';
|
||||
|
||||
type TLoginFormProps = {
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import reactRouter from 'react-router-dom';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { getByTestId, render, waitFor } from 'test/layout-test-utils';
|
||||
import * as mockDataProvider from 'librechat-data-provider/react-query';
|
||||
import type { TStartupConfig } from 'librechat-data-provider';
|
||||
import * as authDataProvider from '~/data-provider/Auth/mutations';
|
||||
import * as endpointQueries from '~/data-provider/Endpoints/queries';
|
||||
import * as miscDataProvider from '~/data-provider/Misc/queries';
|
||||
import * as authMutations from '~/data-provider/Auth/mutations';
|
||||
import * as authQueries from '~/data-provider/Auth/queries';
|
||||
import AuthLayout from '~/components/Auth/AuthLayout';
|
||||
import Login from '~/components/Auth/Login';
|
||||
|
||||
|
@ -62,23 +64,23 @@ const setup = ({
|
|||
},
|
||||
} = {}) => {
|
||||
const mockUseLoginUser = jest
|
||||
.spyOn(authDataProvider, 'useLoginUserMutation')
|
||||
.spyOn(authMutations, 'useLoginUserMutation')
|
||||
//@ts-ignore - we don't need all parameters of the QueryObserverSuccessResult
|
||||
.mockReturnValue(useLoginUserReturnValue);
|
||||
const mockUseGetUserQuery = jest
|
||||
.spyOn(mockDataProvider, 'useGetUserQuery')
|
||||
.spyOn(authQueries, 'useGetUserQuery')
|
||||
//@ts-ignore - we don't need all parameters of the QueryObserverSuccessResult
|
||||
.mockReturnValue(useGetUserQueryReturnValue);
|
||||
const mockUseGetStartupConfig = jest
|
||||
.spyOn(mockDataProvider, 'useGetStartupConfig')
|
||||
.spyOn(endpointQueries, 'useGetStartupConfig')
|
||||
//@ts-ignore - we don't need all parameters of the QueryObserverSuccessResult
|
||||
.mockReturnValue(useGetStartupConfigReturnValue);
|
||||
const mockUseRefreshTokenMutation = jest
|
||||
.spyOn(mockDataProvider, 'useRefreshTokenMutation')
|
||||
.spyOn(authMutations, 'useRefreshTokenMutation')
|
||||
//@ts-ignore - we don't need all parameters of the QueryObserverSuccessResult
|
||||
.mockReturnValue(useRefreshTokenMutationReturnValue);
|
||||
const mockUseGetBannerQuery = jest
|
||||
.spyOn(mockDataProvider, 'useGetBannerQuery')
|
||||
.spyOn(miscDataProvider, 'useGetBannerQuery')
|
||||
//@ts-ignore - we don't need all parameters of the QueryObserverSuccessResult
|
||||
.mockReturnValue(useGetBannerQueryReturnValue);
|
||||
const mockUseOutletContext = jest.spyOn(reactRouter, 'useOutletContext').mockReturnValue({
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
import { render, getByTestId } from 'test/layout-test-utils';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import * as mockDataProvider from 'librechat-data-provider/react-query';
|
||||
import type { TStartupConfig } from 'librechat-data-provider';
|
||||
import * as authDataProvider from '~/data-provider/Auth/mutations';
|
||||
import * as endpointQueries from '~/data-provider/Endpoints/queries';
|
||||
import * as miscDataProvider from '~/data-provider/Misc/queries';
|
||||
import * as authMutations from '~/data-provider/Auth/mutations';
|
||||
import * as authQueries from '~/data-provider/Auth/queries';
|
||||
import Login from '../LoginForm';
|
||||
|
||||
jest.mock('librechat-data-provider/react-query');
|
||||
|
@ -67,23 +69,23 @@ const setup = ({
|
|||
},
|
||||
} = {}) => {
|
||||
const mockUseLoginUser = jest
|
||||
.spyOn(authDataProvider, 'useLoginUserMutation')
|
||||
.spyOn(authMutations, 'useLoginUserMutation')
|
||||
//@ts-ignore - we don't need all parameters of the QueryObserverSuccessResult
|
||||
.mockReturnValue(useLoginUserReturnValue);
|
||||
const mockUseGetUserQuery = jest
|
||||
.spyOn(mockDataProvider, 'useGetUserQuery')
|
||||
.spyOn(authQueries, 'useGetUserQuery')
|
||||
//@ts-ignore - we don't need all parameters of the QueryObserverSuccessResult
|
||||
.mockReturnValue(useGetUserQueryReturnValue);
|
||||
const mockUseGetStartupConfig = jest
|
||||
.spyOn(mockDataProvider, 'useGetStartupConfig')
|
||||
.spyOn(endpointQueries, 'useGetStartupConfig')
|
||||
//@ts-ignore - we don't need all parameters of the QueryObserverSuccessResult
|
||||
.mockReturnValue(useGetStartupConfigReturnValue);
|
||||
const mockUseRefreshTokenMutation = jest
|
||||
.spyOn(mockDataProvider, 'useRefreshTokenMutation')
|
||||
.spyOn(authMutations, 'useRefreshTokenMutation')
|
||||
//@ts-ignore - we don't need all parameters of the QueryObserverSuccessResult
|
||||
.mockReturnValue(useRefreshTokenMutationReturnValue);
|
||||
const mockUseGetBannerQuery = jest
|
||||
.spyOn(mockDataProvider, 'useGetBannerQuery')
|
||||
.spyOn(miscDataProvider, 'useGetBannerQuery')
|
||||
//@ts-ignore - we don't need all parameters of the QueryObserverSuccessResult
|
||||
.mockReturnValue(useGetBannerQueryReturnValue);
|
||||
return {
|
||||
|
|
|
@ -3,6 +3,10 @@ import userEvent from '@testing-library/user-event';
|
|||
import { render, waitFor, screen } from 'test/layout-test-utils';
|
||||
import * as mockDataProvider from 'librechat-data-provider/react-query';
|
||||
import type { TStartupConfig } from 'librechat-data-provider';
|
||||
import * as miscDataProvider from '~/data-provider/Misc/queries';
|
||||
import * as endpointQueries from '~/data-provider/Endpoints/queries';
|
||||
import * as authMutations from '~/data-provider/Auth/mutations';
|
||||
import * as authQueries from '~/data-provider/Auth/queries';
|
||||
import Registration from '~/components/Auth/Registration';
|
||||
import AuthLayout from '~/components/Auth/AuthLayout';
|
||||
|
||||
|
@ -62,22 +66,22 @@ const setup = ({
|
|||
//@ts-ignore - we don't need all parameters of the QueryObserverSuccessResult
|
||||
.mockReturnValue(useRegisterUserMutationReturnValue);
|
||||
const mockUseGetUserQuery = jest
|
||||
.spyOn(mockDataProvider, 'useGetUserQuery')
|
||||
.spyOn(authQueries, 'useGetUserQuery')
|
||||
//@ts-ignore - we don't need all parameters of the QueryObserverSuccessResult
|
||||
.mockReturnValue(useGetUserQueryReturnValue);
|
||||
const mockUseGetStartupConfig = jest
|
||||
.spyOn(mockDataProvider, 'useGetStartupConfig')
|
||||
.spyOn(endpointQueries, 'useGetStartupConfig')
|
||||
//@ts-ignore - we don't need all parameters of the QueryObserverSuccessResult
|
||||
.mockReturnValue(useGetStartupConfigReturnValue);
|
||||
const mockUseRefreshTokenMutation = jest
|
||||
.spyOn(mockDataProvider, 'useRefreshTokenMutation')
|
||||
.spyOn(authMutations, 'useRefreshTokenMutation')
|
||||
//@ts-ignore - we don't need all parameters of the QueryObserverSuccessResult
|
||||
.mockReturnValue(useRefreshTokenMutationReturnValue);
|
||||
const mockUseOutletContext = jest.spyOn(reactRouter, 'useOutletContext').mockReturnValue({
|
||||
startupConfig: useGetStartupConfigReturnValue.data,
|
||||
});
|
||||
const mockUseGetBannerQuery = jest
|
||||
.spyOn(mockDataProvider, 'useGetBannerQuery')
|
||||
.spyOn(miscDataProvider, 'useGetBannerQuery')
|
||||
//@ts-ignore - we don't need all parameters of the QueryObserverSuccessResult
|
||||
.mockReturnValue(useGetBannerQueryReturnValue);
|
||||
const renderResult = render(
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { useEffect, useRef } from 'react';
|
||||
import { XIcon } from 'lucide-react';
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { useGetBannerQuery } from 'librechat-data-provider/react-query';
|
||||
import { useGetBannerQuery } from '~/data-provider';
|
||||
import store from '~/store';
|
||||
import { useEffect, useRef } from 'react';
|
||||
|
||||
export const Banner = ({ onHeightChange }: { onHeightChange?: (height: number) => void }) => {
|
||||
const { data: banner } = useGetBannerQuery();
|
||||
|
|
|
@ -2,7 +2,7 @@ import React, { useEffect } from 'react';
|
|||
import ReactMarkdown from 'react-markdown';
|
||||
import TagManager from 'react-gtm-module';
|
||||
import { Constants } from 'librechat-data-provider';
|
||||
import { useGetStartupConfig } from 'librechat-data-provider/react-query';
|
||||
import { useGetStartupConfig } from '~/data-provider';
|
||||
import { useLocalize } from '~/hooks';
|
||||
|
||||
export default function Footer({ className }: { className?: string }) {
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { useMemo } from 'react';
|
||||
import { useOutletContext } from 'react-router-dom';
|
||||
import { getConfigDefaults, PermissionTypes, Permissions } from 'librechat-data-provider';
|
||||
import { useGetStartupConfig } from 'librechat-data-provider/react-query';
|
||||
import type { ContextType } from '~/common';
|
||||
import { EndpointsMenu, ModelSpecsMenu, PresetsMenu, HeaderNewChat } from './Menus';
|
||||
import { useGetStartupConfig } from '~/data-provider';
|
||||
import ExportAndShareMenu from './ExportAndShareMenu';
|
||||
import { useMediaQuery, useHasAccess } from '~/hooks';
|
||||
import HeaderOptions from './Input/HeaderOptions';
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { useMemo } from 'react';
|
||||
import { useGetEndpointsQuery } from 'librechat-data-provider/react-query';
|
||||
import type { TConversation, TEndpointOption, TPreset } from 'librechat-data-provider';
|
||||
import type { SetterOrUpdater } from 'recoil';
|
||||
import useGetSender from '~/hooks/Conversations/useGetSender';
|
||||
import { useGetEndpointsQuery } from '~/data-provider';
|
||||
import { EndpointIcon } from '~/components/Endpoints';
|
||||
import { getPresetTitle } from '~/utils';
|
||||
|
||||
|
|
|
@ -2,8 +2,8 @@ import * as Ariakit from '@ariakit/react';
|
|||
import React, { useRef, useState, useMemo } from 'react';
|
||||
import { FileSearch, ImageUpIcon, TerminalSquareIcon } from 'lucide-react';
|
||||
import { EToolResources, EModelEndpoint } from 'librechat-data-provider';
|
||||
import { useGetEndpointsQuery } from 'librechat-data-provider/react-query';
|
||||
import { FileUpload, TooltipAnchor, DropdownPopup } from '~/components/ui';
|
||||
import { useGetEndpointsQuery } from '~/data-provider';
|
||||
import { AttachmentIcon } from '~/components/svg';
|
||||
import { useLocalize } from '~/hooks';
|
||||
import { cn } from '~/utils';
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import React, { useMemo } from 'react';
|
||||
import { EModelEndpoint, EToolResources } from 'librechat-data-provider';
|
||||
import { useGetEndpointsQuery } from 'librechat-data-provider/react-query';
|
||||
import { FileSearch, ImageUpIcon, TerminalSquareIcon } from 'lucide-react';
|
||||
import OGDialogTemplate from '~/components/ui/OGDialogTemplate';
|
||||
import { useGetEndpointsQuery } from '~/data-provider';
|
||||
import useLocalize from '~/hooks/useLocalize';
|
||||
import { OGDialog } from '~/components/ui';
|
||||
|
||||
|
|
|
@ -2,13 +2,13 @@ import { useRecoilState } from 'recoil';
|
|||
import { Settings2 } from 'lucide-react';
|
||||
import { Root, Anchor } from '@radix-ui/react-popover';
|
||||
import { useState, useEffect, useMemo } from 'react';
|
||||
import { useGetEndpointsQuery } from 'librechat-data-provider/react-query';
|
||||
import { tConvoUpdateSchema, EModelEndpoint, isParamEndpoint } from 'librechat-data-provider';
|
||||
import type { TPreset, TInterfaceConfig } from 'librechat-data-provider';
|
||||
import { EndpointSettings, SaveAsPresetDialog, AlternativeSettings } from '~/components/Endpoints';
|
||||
import { PluginStoreDialog, TooltipAnchor } from '~/components';
|
||||
import { ModelSelect } from '~/components/Input/ModelSelect';
|
||||
import { useSetIndexOptions, useLocalize } from '~/hooks';
|
||||
import { useGetEndpointsQuery } from '~/data-provider';
|
||||
import OptionsPopover from './OptionsPopover';
|
||||
import PopoverButtons from './PopoverButtons';
|
||||
import { useChatContext } from '~/Providers';
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
import { useMemo } from 'react';
|
||||
import { EModelEndpoint, Constants } from 'librechat-data-provider';
|
||||
import { useGetEndpointsQuery, useGetStartupConfig } from 'librechat-data-provider/react-query';
|
||||
import type * as t from 'librechat-data-provider';
|
||||
import type { ReactNode } from 'react';
|
||||
import { useChatContext, useAgentsMapContext, useAssistantsMapContext } from '~/Providers';
|
||||
import { useGetAssistantDocsQuery } from '~/data-provider';
|
||||
import {
|
||||
useGetAssistantDocsQuery,
|
||||
useGetEndpointsQuery,
|
||||
useGetStartupConfig,
|
||||
} from '~/data-provider';
|
||||
import ConvoIcon from '~/components/Endpoints/ConvoIcon';
|
||||
import { getIconEndpoint, getEntity, cn } from '~/utils';
|
||||
import { useLocalize, useSubmitMessage } from '~/hooks';
|
||||
|
|
|
@ -2,12 +2,12 @@ import { useState } from 'react';
|
|||
import { Settings } from 'lucide-react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { EModelEndpoint } from 'librechat-data-provider';
|
||||
import { useGetEndpointsQuery } from 'librechat-data-provider/react-query';
|
||||
import type { TConversation } from 'librechat-data-provider';
|
||||
import type { FC } from 'react';
|
||||
import { cn, getConvoSwitchLogic, getEndpointField, getIconKey } from '~/utils';
|
||||
import { useLocalize, useUserKey, useDefaultConvo } from '~/hooks';
|
||||
import { SetKeyDialog } from '~/components/Input/SetKeyDialog';
|
||||
import { useGetEndpointsQuery } from '~/data-provider';
|
||||
import { useChatContext } from '~/Providers';
|
||||
import { icons } from './Icons';
|
||||
import store from '~/store';
|
||||
|
|
|
@ -6,7 +6,7 @@ import {
|
|||
PermissionTypes,
|
||||
Permissions,
|
||||
} from 'librechat-data-provider';
|
||||
import { useGetEndpointsQuery } from 'librechat-data-provider/react-query';
|
||||
import { useGetEndpointsQuery } from '~/data-provider';
|
||||
import MenuSeparator from '../UI/MenuSeparator';
|
||||
import { getEndpointField } from '~/utils';
|
||||
import { useHasAccess } from '~/hooks';
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { useCallback, useRef } from 'react';
|
||||
import { alternateName } from 'librechat-data-provider';
|
||||
import { Content, Portal, Root } from '@radix-ui/react-popover';
|
||||
import { useGetEndpointsQuery } from 'librechat-data-provider/react-query';
|
||||
import type { FC, KeyboardEvent } from 'react';
|
||||
import { useChatContext, useAgentsMapContext, useAssistantsMapContext } from '~/Providers';
|
||||
import { useGetEndpointsQuery } from '~/data-provider';
|
||||
import { mapEndpoints, getEntity } from '~/utils';
|
||||
import EndpointItems from './Endpoints/MenuItems';
|
||||
import useLocalize from '~/hooks/useLocalize';
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import { useRecoilValue } from 'recoil';
|
||||
import { useMemo, useCallback, useRef } from 'react';
|
||||
import { Content, Portal, Root } from '@radix-ui/react-popover';
|
||||
import { useGetEndpointsQuery } from 'librechat-data-provider/react-query';
|
||||
import { EModelEndpoint, isAssistantsEndpoint } from 'librechat-data-provider';
|
||||
import type { TModelSpec, TConversation, TEndpointsConfig } from 'librechat-data-provider';
|
||||
import type { KeyboardEvent } from 'react';
|
||||
import { useChatContext, useAssistantsMapContext } from '~/Providers';
|
||||
import { useDefaultConvo, useNewConvo, useLocalize } from '~/hooks';
|
||||
import { getConvoSwitchLogic, getModelSpecIconURL } from '~/utils';
|
||||
import { useGetEndpointsQuery } from '~/data-provider';
|
||||
import MenuButton from './MenuButton';
|
||||
import ModelSpecs from './ModelSpecs';
|
||||
import store from '~/store';
|
||||
|
|
|
@ -2,7 +2,6 @@ import { useRecoilState } from 'recoil';
|
|||
import { useCallback, useEffect, useMemo } from 'react';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { QueryKeys, isAgentsEndpoint } from 'librechat-data-provider';
|
||||
import { useGetEndpointsQuery } from 'librechat-data-provider/react-query';
|
||||
import type { TModelsConfig, TEndpointsConfig } from 'librechat-data-provider';
|
||||
import {
|
||||
cn,
|
||||
|
@ -16,6 +15,7 @@ import { useSetIndexOptions, useLocalize, useDebouncedInput } from '~/hooks';
|
|||
import PopoverButtons from '~/components/Chat/Input/PopoverButtons';
|
||||
import DialogTemplate from '~/components/ui/DialogTemplate';
|
||||
import { EndpointSettings } from '~/components/Endpoints';
|
||||
import { useGetEndpointsQuery } from '~/data-provider';
|
||||
import { useChatContext } from '~/Providers';
|
||||
import store from '~/store';
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import { useRecoilValue } from 'recoil';
|
||||
import { Close } from '@radix-ui/react-popover';
|
||||
import { Flipper, Flipped } from 'react-flip-toolkit';
|
||||
import { useGetEndpointsQuery } from 'librechat-data-provider/react-query';
|
||||
import type { FC } from 'react';
|
||||
import type { TPreset } from 'librechat-data-provider';
|
||||
import { getPresetTitle, getEndpointField, getIconKey } from '~/utils';
|
||||
|
@ -9,6 +8,7 @@ import FileUpload from '~/components/Chat/Input/Files/FileUpload';
|
|||
import { PinIcon, EditIcon, TrashIcon } from '~/components/svg';
|
||||
import { Dialog, DialogTrigger, Label } from '~/components/ui';
|
||||
import DialogTemplate from '~/components/ui/DialogTemplate';
|
||||
import { useGetEndpointsQuery } from '~/data-provider';
|
||||
import { MenuSeparator, MenuItem } from '../UI';
|
||||
import { icons } from '../Endpoints/Icons';
|
||||
import { useLocalize } from '~/hooks';
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import React, { useMemo, memo } from 'react';
|
||||
import { useGetEndpointsQuery } from 'librechat-data-provider/react-query';
|
||||
import type { Assistant, Agent } from 'librechat-data-provider';
|
||||
import type { TMessageIcon } from '~/common';
|
||||
import { getEndpointField, getIconEndpoint, logger } from '~/utils';
|
||||
import ConvoIconURL from '~/components/Endpoints/ConvoIconURL';
|
||||
import { useGetEndpointsQuery } from '~/data-provider';
|
||||
import Icon from '~/components/Endpoints/Icon';
|
||||
|
||||
const MessageIcon = memo(
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
import { useRecoilValue } from 'recoil';
|
||||
import { useEffect, useMemo } from 'react';
|
||||
import { useGetStartupConfig } from 'librechat-data-provider/react-query';
|
||||
import { FileSources, LocalStorageKeys, getConfigDefaults } from 'librechat-data-provider';
|
||||
import type { ExtendedFile } from '~/common';
|
||||
import { useDeleteFilesMutation, useGetStartupConfig } from '~/data-provider';
|
||||
import DragDropWrapper from '~/components/Chat/Input/Files/DragDropWrapper';
|
||||
import { useDeleteFilesMutation } from '~/data-provider';
|
||||
import Artifacts from '~/components/Artifacts/Artifacts';
|
||||
import { SidePanel } from '~/components/SidePanel';
|
||||
import { useSetFilesToDelete } from '~/hooks';
|
||||
|
|
|
@ -3,12 +3,12 @@ import { useRecoilValue } from 'recoil';
|
|||
import { Check, X } from 'lucide-react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { Constants } from 'librechat-data-provider';
|
||||
import { useGetEndpointsQuery } from 'librechat-data-provider/react-query';
|
||||
import type { MouseEvent, FocusEvent, KeyboardEvent } from 'react';
|
||||
import type { TConversation } from 'librechat-data-provider';
|
||||
import { useNavigateToConvo, useMediaQuery, useLocalize } from '~/hooks';
|
||||
import { useUpdateConversationMutation } from '~/data-provider';
|
||||
import EndpointIcon from '~/components/Endpoints/EndpointIcon';
|
||||
import { useGetEndpointsQuery } from '~/data-provider';
|
||||
import { NotificationSeverity } from '~/common';
|
||||
import { useToastContext } from '~/Providers';
|
||||
import { ConvoOptions } from './ConvoOptions';
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
import { useState, useId, useRef, memo } from 'react';
|
||||
import * as Menu from '@ariakit/react/menu';
|
||||
import { Ellipsis, Share2, Copy, Archive, Pen, Trash } from 'lucide-react';
|
||||
import { useGetStartupConfig } from 'librechat-data-provider/react-query';
|
||||
import type { MouseEvent } from 'react';
|
||||
import type * as t from '~/common';
|
||||
import { useDuplicateConversationMutation, useGetStartupConfig } from '~/data-provider';
|
||||
import { useLocalize, useArchiveHandler, useNavigateToConvo } from '~/hooks';
|
||||
import { useToastContext, useChatContext } from '~/Providers';
|
||||
import { useDuplicateConversationMutation } from '~/data-provider';
|
||||
import { DropdownPopup } from '~/components/ui';
|
||||
import DeleteButton from './DeleteButton';
|
||||
import ShareButton from './ShareButton';
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import { useRecoilValue } from 'recoil';
|
||||
import { SettingsViews, TConversation } from 'librechat-data-provider';
|
||||
import { useGetModelsQuery, useGetEndpointsQuery } from 'librechat-data-provider/react-query';
|
||||
import { useGetModelsQuery } from 'librechat-data-provider/react-query';
|
||||
import type { TSettingsProps } from '~/common';
|
||||
import { getSettings } from './Settings';
|
||||
import { useGetEndpointsQuery } from '~/data-provider';
|
||||
import { cn, getEndpointField } from '~/utils';
|
||||
import { getSettings } from './Settings';
|
||||
import store from '~/store';
|
||||
|
||||
export default function Settings({
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import React, { useState } from 'react';
|
||||
import { useForm, FormProvider } from 'react-hook-form';
|
||||
import { EModelEndpoint, alternateName, isAssistantsEndpoint } from 'librechat-data-provider';
|
||||
import { useGetEndpointsQuery } from 'librechat-data-provider/react-query';
|
||||
import type { TDialogProps } from '~/common';
|
||||
import OGDialogTemplate from '~/components/ui/OGDialogTemplate';
|
||||
import { RevokeKeysButton } from '~/components/Nav';
|
||||
import { useGetEndpointsQuery } from '~/data-provider';
|
||||
import { OGDialog, Dropdown } from '~/components/ui';
|
||||
import { RevokeKeysButton } from '~/components/Nav';
|
||||
import { useUserKey, useLocalize } from '~/hooks';
|
||||
import { useToastContext } from '~/Providers';
|
||||
import CustomConfig from './CustomEndpoint';
|
||||
|
@ -118,7 +118,7 @@ const SetKeyDialog = ({
|
|||
if (isOpenAIBase && key === 'baseURL') {
|
||||
return false;
|
||||
}
|
||||
if (key === 'baseURL' && !userProvideURL) {
|
||||
if (key === 'baseURL' && !(userProvideURL ?? false)) {
|
||||
return false;
|
||||
}
|
||||
return data[key] === '';
|
||||
|
@ -205,7 +205,7 @@ const SetKeyDialog = ({
|
|||
leftButtons={
|
||||
<RevokeKeysButton
|
||||
endpoint={endpoint}
|
||||
disabled={!expiryTime}
|
||||
disabled={!(expiryTime ?? '')}
|
||||
setDialogOpen={onOpenChange}
|
||||
/>
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { Disclosure, DisclosureButton, DisclosurePanel } from '@headlessui/react';
|
||||
import { useCallback, memo, ReactNode } from 'react';
|
||||
import { useGetEndpointsQuery } from 'librechat-data-provider/react-query';
|
||||
import type { TResPlugin, TInput } from 'librechat-data-provider';
|
||||
import { ChevronDownIcon, LucideProps } from 'lucide-react';
|
||||
import type { TResPlugin, TInput } from 'librechat-data-provider';
|
||||
import { useGetEndpointsQuery } from '~/data-provider';
|
||||
import { useShareContext } from '~/Providers';
|
||||
import { cn, formatJSON } from '~/utils';
|
||||
import { Spinner } from '~/components';
|
||||
|
@ -47,7 +47,7 @@ const Plugin: React.FC<PluginProps> = ({ plugin }) => {
|
|||
if (pluginKey === 'n/a' || pluginKey === 'self reflection') {
|
||||
return pluginKey;
|
||||
}
|
||||
return plugins?.[pluginKey] ?? 'self reflection';
|
||||
return plugins[pluginKey] ?? 'self reflection';
|
||||
},
|
||||
[plugins],
|
||||
);
|
||||
|
@ -105,7 +105,7 @@ const Plugin: React.FC<PluginProps> = ({ plugin }) => {
|
|||
|
||||
<DisclosurePanel className="mt-3 flex max-w-full flex-col gap-3">
|
||||
<CodeBlock
|
||||
lang={latestPlugin ? `REQUEST TO ${latestPlugin?.toUpperCase()}` : 'REQUEST'}
|
||||
lang={latestPlugin ? `REQUEST TO ${latestPlugin.toUpperCase()}` : 'REQUEST'}
|
||||
codeChildren={formatInputs(plugin.inputs ?? [])}
|
||||
plugin={true}
|
||||
classProp="max-h-[450px]"
|
||||
|
@ -113,7 +113,7 @@ const Plugin: React.FC<PluginProps> = ({ plugin }) => {
|
|||
{plugin.outputs && plugin.outputs.length > 0 && (
|
||||
<CodeBlock
|
||||
lang={
|
||||
latestPlugin ? `RESPONSE FROM ${latestPlugin?.toUpperCase()}` : 'RESPONSE'
|
||||
latestPlugin ? `RESPONSE FROM ${latestPlugin.toUpperCase()}` : 'RESPONSE'
|
||||
}
|
||||
codeChildren={formatJSON(plugin.outputs ?? '')}
|
||||
plugin={true}
|
||||
|
|
|
@ -2,8 +2,8 @@ import { useRecoilState } from 'recoil';
|
|||
import * as Select from '@ariakit/react/select';
|
||||
import { Fragment, useState, memo } from 'react';
|
||||
import { FileText, LogOut } from 'lucide-react';
|
||||
import { useGetUserBalance, useGetStartupConfig } from 'librechat-data-provider/react-query';
|
||||
import { LinkIcon, GearIcon, DropdownMenuSeparator } from '~/components';
|
||||
import { useGetStartupConfig, useGetUserBalance } from '~/data-provider';
|
||||
import FilesView from '~/components/Chat/Input/Files/FilesView';
|
||||
import { useAuthContext } from '~/hooks/AuthContext';
|
||||
import useAvatar from '~/hooks/Messages/useAvatar';
|
||||
|
|
|
@ -3,11 +3,11 @@ import { useRecoilValue } from 'recoil';
|
|||
import { useNavigate } from 'react-router-dom';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { QueryKeys, Constants } from 'librechat-data-provider';
|
||||
import { useGetEndpointsQuery } from 'librechat-data-provider/react-query';
|
||||
import type { TConversation, TMessage } from 'librechat-data-provider';
|
||||
import { getEndpointField, getIconEndpoint, getIconKey } from '~/utils';
|
||||
import { icons } from '~/components/Chat/Menus/Endpoints/Icons';
|
||||
import ConvoIconURL from '~/components/Endpoints/ConvoIconURL';
|
||||
import { useGetEndpointsQuery } from '~/data-provider';
|
||||
import { useLocalize, useNewConvo } from '~/hooks';
|
||||
import { NewChatIcon } from '~/components/svg';
|
||||
import { cn } from '~/utils';
|
||||
|
|
|
@ -2,6 +2,8 @@ import { render, screen, fireEvent } from 'test/layout-test-utils';
|
|||
import PluginStoreDialog from '../PluginStoreDialog';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import * as mockDataProvider from 'librechat-data-provider/react-query';
|
||||
import * as authMutations from '~/data-provider/Auth/mutations';
|
||||
import * as authQueries from '~/data-provider/Auth/queries';
|
||||
|
||||
jest.mock('librechat-data-provider/react-query');
|
||||
|
||||
|
@ -143,11 +145,11 @@ const setup = ({
|
|||
//@ts-ignore - we don't need all parameters of the QueryObserverSuccessResult
|
||||
.mockReturnValue(useUpdateUserPluginsMutationReturnValue);
|
||||
const mockUseGetUserQuery = jest
|
||||
.spyOn(mockDataProvider, 'useGetUserQuery')
|
||||
.spyOn(authQueries, 'useGetUserQuery')
|
||||
//@ts-ignore - we don't need all parameters of the QueryObserverSuccessResult
|
||||
.mockReturnValue(useGetUserQueryReturnValue);
|
||||
const mockUseRefreshTokenMutation = jest
|
||||
.spyOn(mockDataProvider, 'useRefreshTokenMutation')
|
||||
.spyOn(authMutations, 'useRefreshTokenMutation')
|
||||
//@ts-ignore - we don't need all parameters of the QueryObserverSuccessResult
|
||||
.mockReturnValue(useRefreshTokenMutationReturnValue);
|
||||
const mockSetIsOpen = jest.fn();
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { useNavigate } from 'react-router-dom';
|
||||
import { PermissionTypes, Permissions } from 'librechat-data-provider';
|
||||
import { useGetStartupConfig } from 'librechat-data-provider/react-query';
|
||||
import type { TPromptGroup, TStartupConfig } from 'librechat-data-provider';
|
||||
import DashGroupItem from '~/components/Prompts/Groups/DashGroupItem';
|
||||
import ChatGroupItem from '~/components/Prompts/Groups/ChatGroupItem';
|
||||
import { useGetStartupConfig } from '~/data-provider';
|
||||
import { useLocalize, useHasAccess } from '~/hooks';
|
||||
import { Button, Skeleton } from '~/components/ui';
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@ import React, { useEffect, useMemo } from 'react';
|
|||
import { Share2Icon } from 'lucide-react';
|
||||
import { useForm, Controller } from 'react-hook-form';
|
||||
import { Permissions } from 'librechat-data-provider';
|
||||
import { useGetStartupConfig } from 'librechat-data-provider/react-query';
|
||||
import type {
|
||||
TPromptGroup,
|
||||
TStartupConfig,
|
||||
|
@ -15,7 +14,7 @@ import {
|
|||
OGDialogTrigger,
|
||||
OGDialogClose,
|
||||
} from '~/components/ui';
|
||||
import { useUpdatePromptGroup } from '~/data-provider';
|
||||
import { useUpdatePromptGroup, useGetStartupConfig } from '~/data-provider';
|
||||
import { Button, Switch } from '~/components/ui';
|
||||
import { useToastContext } from '~/Providers';
|
||||
import { useLocalize } from '~/hooks';
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import { memo } from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { useGetSharedMessages, useGetStartupConfig } from 'librechat-data-provider/react-query';
|
||||
import { useGetSharedMessages } from 'librechat-data-provider/react-query';
|
||||
import { useLocalize, useDocumentTitle } from '~/hooks';
|
||||
import { useGetStartupConfig } from '~/data-provider';
|
||||
import { ShareContext } from '~/Providers';
|
||||
import { Spinner } from '~/components/svg';
|
||||
import MessagesView from './MessagesView';
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import { useState, useEffect, useMemo } from 'react';
|
||||
import { EModelEndpoint } from 'librechat-data-provider';
|
||||
import { useGetEndpointsQuery } from 'librechat-data-provider/react-query';
|
||||
import type { ActionsEndpoint } from '~/common';
|
||||
import type { Action, TConfig, TEndpointsConfig } from 'librechat-data-provider';
|
||||
import { useGetActionsQuery } from '~/data-provider';
|
||||
import { useGetActionsQuery, useGetEndpointsQuery } from '~/data-provider';
|
||||
import { useChatContext } from '~/Providers';
|
||||
import ActionsPanel from './ActionsPanel';
|
||||
import AgentPanel from './AgentPanel';
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
import { Plus, EarthIcon } from 'lucide-react';
|
||||
import { useCallback, useEffect, useRef } from 'react';
|
||||
import { useGetStartupConfig } from 'librechat-data-provider/react-query';
|
||||
import { AgentCapabilities, defaultAgentFormValues } from 'librechat-data-provider';
|
||||
import type { UseMutationResult, QueryObserverResult } from '@tanstack/react-query';
|
||||
import type { Agent, AgentCreateParams } from 'librechat-data-provider';
|
||||
import type { UseFormReset } from 'react-hook-form';
|
||||
import type { TAgentCapabilities, AgentForm, TAgentOption } from '~/common';
|
||||
import { cn, createDropdownSetter, createProviderOption, processAgentOption } from '~/utils';
|
||||
import { useListAgentsQuery, useGetStartupConfig } from '~/data-provider';
|
||||
import SelectDropDown from '~/components/ui/SelectDropDown';
|
||||
import { useListAgentsQuery } from '~/data-provider';
|
||||
import { useLocalize } from '~/hooks';
|
||||
|
||||
const keys = new Set(Object.keys(defaultAgentFormValues));
|
||||
|
|
|
@ -2,12 +2,12 @@ import React, { useMemo, useEffect } from 'react';
|
|||
import { ChevronLeft, RotateCcw } from 'lucide-react';
|
||||
import { getSettingsKeys } from 'librechat-data-provider';
|
||||
import { useFormContext, useWatch, Controller } from 'react-hook-form';
|
||||
import { useGetEndpointsQuery } from 'librechat-data-provider/react-query';
|
||||
import type * as t from 'librechat-data-provider';
|
||||
import type { AgentForm, AgentModelPanelProps, StringOption } from '~/common';
|
||||
import { componentMapping } from '~/components/SidePanel/Parameters/components';
|
||||
import { agentSettings } from '~/components/SidePanel/Parameters/settings';
|
||||
import { getEndpointField, cn, cardStyle } from '~/utils';
|
||||
import { useGetEndpointsQuery } from '~/data-provider';
|
||||
import { SelectDropDown } from '~/components/ui';
|
||||
import { useLocalize } from '~/hooks';
|
||||
import { Panel } from '~/common';
|
||||
|
|
|
@ -2,7 +2,6 @@ import React, { useEffect, useMemo } from 'react';
|
|||
import { Share2Icon } from 'lucide-react';
|
||||
import { useForm, Controller } from 'react-hook-form';
|
||||
import { Permissions } from 'librechat-data-provider';
|
||||
import { useGetStartupConfig } from 'librechat-data-provider/react-query';
|
||||
import type { TStartupConfig, AgentUpdateParams } from 'librechat-data-provider';
|
||||
import {
|
||||
Button,
|
||||
|
@ -13,7 +12,7 @@ import {
|
|||
OGDialogContent,
|
||||
OGDialogTrigger,
|
||||
} from '~/components/ui';
|
||||
import { useUpdateAgentMutation } from '~/data-provider';
|
||||
import { useUpdateAgentMutation, useGetStartupConfig } from '~/data-provider';
|
||||
import { cn, removeFocusOutlines } from '~/utils';
|
||||
import { useToastContext } from '~/Providers';
|
||||
import { useLocalize } from '~/hooks';
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
import { useState, useEffect, useMemo } from 'react';
|
||||
import { defaultAssistantsVersion } from 'librechat-data-provider';
|
||||
import { useGetEndpointsQuery } from 'librechat-data-provider/react-query';
|
||||
import type { Action, TEndpointsConfig, AssistantsEndpoint } from 'librechat-data-provider';
|
||||
import type { ActionsEndpoint } from '~/common';
|
||||
import { useGetActionsQuery, useGetAssistantDocsQuery } from '~/data-provider';
|
||||
import {
|
||||
useGetActionsQuery,
|
||||
useGetEndpointsQuery,
|
||||
useGetAssistantDocsQuery,
|
||||
} from '~/data-provider';
|
||||
import AssistantPanel from './AssistantPanel';
|
||||
import { useChatContext } from '~/Providers';
|
||||
import ActionsPanel from './ActionsPanel';
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import React, { useMemo, useState, useEffect, useCallback } from 'react';
|
||||
import { useGetEndpointsQuery } from 'librechat-data-provider/react-query';
|
||||
import { getSettingsKeys, tConvoUpdateSchema } from 'librechat-data-provider';
|
||||
import type { TPreset } from 'librechat-data-provider';
|
||||
import { SaveAsPresetDialog } from '~/components/Endpoints';
|
||||
import { useSetIndexOptions, useLocalize } from '~/hooks';
|
||||
import { useGetEndpointsQuery } from '~/data-provider';
|
||||
import { getEndpointField, logger } from '~/utils';
|
||||
import { componentMapping } from './components';
|
||||
import { useChatContext } from '~/Providers';
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
import throttle from 'lodash/throttle';
|
||||
import { getConfigDefaults } from 'librechat-data-provider';
|
||||
import { useUserKeyQuery } from 'librechat-data-provider/react-query';
|
||||
import { useState, useRef, useCallback, useEffect, useMemo, memo } from 'react';
|
||||
import {
|
||||
useGetEndpointsQuery,
|
||||
useGetStartupConfig,
|
||||
useUserKeyQuery,
|
||||
} from 'librechat-data-provider/react-query';
|
||||
import type { TEndpointsConfig, TInterfaceConfig } from 'librechat-data-provider';
|
||||
import type { ImperativePanelHandle } from 'react-resizable-panels';
|
||||
import { ResizableHandleAlt, ResizablePanel, ResizablePanelGroup } from '~/components/ui/Resizable';
|
||||
import { useGetEndpointsQuery, useGetStartupConfig } from '~/data-provider';
|
||||
import { useMediaQuery, useLocalStorage, useLocalize } from '~/hooks';
|
||||
import useSideNavLinks from '~/hooks/Nav/useSideNavLinks';
|
||||
import NavToggle from '~/components/Nav/NavToggle';
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
export * from './queries';
|
||||
export * from './mutations';
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { useResetRecoilState } from 'recoil';
|
||||
import { useResetRecoilState, useSetRecoilState } from 'recoil';
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { MutationKeys, dataService } from 'librechat-data-provider';
|
||||
import { MutationKeys, dataService, request } from 'librechat-data-provider';
|
||||
import type { UseMutationResult } from '@tanstack/react-query';
|
||||
import type * as t from 'librechat-data-provider';
|
||||
import useClearStates from '~/hooks/Config/useClearStates';
|
||||
|
@ -9,15 +9,17 @@ import store from '~/store';
|
|||
/* login/logout */
|
||||
export const useLogoutUserMutation = (
|
||||
options?: t.LogoutOptions,
|
||||
): UseMutationResult<unknown, unknown, undefined, unknown> => {
|
||||
): UseMutationResult<t.TLogoutResponse, unknown, undefined, unknown> => {
|
||||
const queryClient = useQueryClient();
|
||||
const clearStates = useClearStates();
|
||||
const resetDefaultPreset = useResetRecoilState(store.defaultPreset);
|
||||
const setQueriesEnabled = useSetRecoilState<boolean>(store.queriesEnabled);
|
||||
|
||||
return useMutation([MutationKeys.logoutUser], {
|
||||
mutationFn: () => dataService.logout(),
|
||||
...(options || {}),
|
||||
onSuccess: (...args) => {
|
||||
setQueriesEnabled(false);
|
||||
resetDefaultPreset();
|
||||
clearStates();
|
||||
queryClient.removeQueries();
|
||||
|
@ -26,20 +28,39 @@ export const useLogoutUserMutation = (
|
|||
});
|
||||
};
|
||||
|
||||
export const useLoginUserMutation = (): UseMutationResult<
|
||||
t.TLoginResponse,
|
||||
unknown,
|
||||
t.TLoginUser,
|
||||
unknown
|
||||
> => {
|
||||
export const useLoginUserMutation = (
|
||||
options?: t.MutationOptions<t.TLoginResponse, t.TLoginUser, unknown, unknown>,
|
||||
): UseMutationResult<t.TLoginResponse, unknown, t.TLoginUser, unknown> => {
|
||||
const queryClient = useQueryClient();
|
||||
const clearStates = useClearStates();
|
||||
const resetDefaultPreset = useResetRecoilState(store.defaultPreset);
|
||||
return useMutation((payload: t.TLoginUser) => dataService.login(payload), {
|
||||
onMutate: () => {
|
||||
const setQueriesEnabled = useSetRecoilState<boolean>(store.queriesEnabled);
|
||||
return useMutation([MutationKeys.loginUser], {
|
||||
mutationFn: (payload: t.TLoginUser) => dataService.login(payload),
|
||||
...(options || {}),
|
||||
onMutate: (vars) => {
|
||||
resetDefaultPreset();
|
||||
clearStates();
|
||||
queryClient.removeQueries();
|
||||
options?.onMutate?.(vars);
|
||||
},
|
||||
onSuccess: (...args) => {
|
||||
setQueriesEnabled(true);
|
||||
options?.onSuccess?.(...args);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const useRefreshTokenMutation = (
|
||||
options?: t.MutationOptions<t.TRefreshTokenResponse | undefined, undefined, unknown, unknown>,
|
||||
): UseMutationResult<t.TRefreshTokenResponse | undefined, unknown, undefined, unknown> => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation([MutationKeys.refreshToken], {
|
||||
mutationFn: () => request.refreshToken(),
|
||||
...(options || {}),
|
||||
onMutate: (vars) => {
|
||||
queryClient.removeQueries();
|
||||
options?.onMutate?.(vars);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
20
client/src/data-provider/Auth/queries.ts
Normal file
20
client/src/data-provider/Auth/queries.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { useRecoilValue } from 'recoil';
|
||||
import { QueryKeys, dataService } from 'librechat-data-provider';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import type { QueryObserverResult, UseQueryOptions } from '@tanstack/react-query';
|
||||
import type t from 'librechat-data-provider';
|
||||
import store from '~/store';
|
||||
|
||||
export const useGetUserQuery = (
|
||||
config?: UseQueryOptions<t.TUser>,
|
||||
): QueryObserverResult<t.TUser> => {
|
||||
const queriesEnabled = useRecoilValue<boolean>(store.queriesEnabled);
|
||||
return useQuery<t.TUser>([QueryKeys.user], () => dataService.getUser(), {
|
||||
refetchOnWindowFocus: false,
|
||||
refetchOnReconnect: false,
|
||||
refetchOnMount: false,
|
||||
retry: false,
|
||||
...config,
|
||||
enabled: (config?.enabled ?? true) === true && queriesEnabled,
|
||||
});
|
||||
};
|
1
client/src/data-provider/Endpoints/index.ts
Normal file
1
client/src/data-provider/Endpoints/index.ts
Normal file
|
@ -0,0 +1 @@
|
|||
export * from './queries';
|
41
client/src/data-provider/Endpoints/queries.ts
Normal file
41
client/src/data-provider/Endpoints/queries.ts
Normal file
|
@ -0,0 +1,41 @@
|
|||
import { useRecoilValue } from 'recoil';
|
||||
import { QueryKeys, dataService } from 'librechat-data-provider';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import type { QueryObserverResult, UseQueryOptions } from '@tanstack/react-query';
|
||||
import type t from 'librechat-data-provider';
|
||||
import store from '~/store';
|
||||
|
||||
export const useGetEndpointsQuery = <TData = t.TEndpointsConfig>(
|
||||
config?: UseQueryOptions<t.TEndpointsConfig, unknown, TData>,
|
||||
): QueryObserverResult<TData> => {
|
||||
const queriesEnabled = useRecoilValue<boolean>(store.queriesEnabled);
|
||||
return useQuery<t.TEndpointsConfig, unknown, TData>(
|
||||
[QueryKeys.endpoints],
|
||||
() => dataService.getAIEndpoints(),
|
||||
{
|
||||
staleTime: Infinity,
|
||||
refetchOnWindowFocus: false,
|
||||
refetchOnReconnect: false,
|
||||
refetchOnMount: false,
|
||||
...config,
|
||||
enabled: (config?.enabled ?? true) === true && queriesEnabled,
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
export const useGetStartupConfig = (
|
||||
config?: UseQueryOptions<t.TStartupConfig>,
|
||||
): QueryObserverResult<t.TStartupConfig> => {
|
||||
const queriesEnabled = useRecoilValue<boolean>(store.queriesEnabled);
|
||||
return useQuery<t.TStartupConfig>(
|
||||
[QueryKeys.startupConfig],
|
||||
() => dataService.getStartupConfig(),
|
||||
{
|
||||
refetchOnWindowFocus: false,
|
||||
refetchOnReconnect: false,
|
||||
refetchOnMount: false,
|
||||
...config,
|
||||
enabled: (config?.enabled ?? true) === true && queriesEnabled,
|
||||
},
|
||||
);
|
||||
};
|
|
@ -1,17 +1,21 @@
|
|||
import { useRecoilValue } from 'recoil';
|
||||
import { QueryKeys, dataService } from 'librechat-data-provider';
|
||||
import { useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import type { QueryObserverResult, UseQueryOptions } from '@tanstack/react-query';
|
||||
import type t from 'librechat-data-provider';
|
||||
import { addFileToCache } from '~/utils';
|
||||
import store from '~/store';
|
||||
|
||||
export const useGetFiles = <TData = t.TFile[] | boolean>(
|
||||
config?: UseQueryOptions<t.TFile[], unknown, TData>,
|
||||
): QueryObserverResult<TData, unknown> => {
|
||||
const queriesEnabled = useRecoilValue<boolean>(store.queriesEnabled);
|
||||
return useQuery<t.TFile[], unknown, TData>([QueryKeys.files], () => dataService.getFiles(), {
|
||||
refetchOnWindowFocus: false,
|
||||
refetchOnReconnect: false,
|
||||
refetchOnMount: false,
|
||||
...config,
|
||||
enabled: (config?.enabled ?? true) === true && queriesEnabled,
|
||||
});
|
||||
};
|
||||
|
||||
|
|
1
client/src/data-provider/Misc/index.ts
Normal file
1
client/src/data-provider/Misc/index.ts
Normal file
|
@ -0,0 +1 @@
|
|||
export * from './queries';
|
45
client/src/data-provider/Misc/queries.ts
Normal file
45
client/src/data-provider/Misc/queries.ts
Normal file
|
@ -0,0 +1,45 @@
|
|||
import { useRecoilValue } from 'recoil';
|
||||
import { QueryKeys, dataService } from 'librechat-data-provider';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import type { QueryObserverResult, UseQueryOptions } from '@tanstack/react-query';
|
||||
import type t from 'librechat-data-provider';
|
||||
import store from '~/store';
|
||||
|
||||
export const useGetBannerQuery = (
|
||||
config?: UseQueryOptions<t.TBannerResponse>,
|
||||
): QueryObserverResult<t.TBannerResponse> => {
|
||||
const queriesEnabled = useRecoilValue<boolean>(store.queriesEnabled);
|
||||
return useQuery<t.TBannerResponse>([QueryKeys.banner], () => dataService.getBanner(), {
|
||||
refetchOnWindowFocus: false,
|
||||
refetchOnReconnect: false,
|
||||
refetchOnMount: false,
|
||||
...config,
|
||||
enabled: (config?.enabled ?? true) === true && queriesEnabled,
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetUserBalance = (
|
||||
config?: UseQueryOptions<string>,
|
||||
): QueryObserverResult<string> => {
|
||||
const queriesEnabled = useRecoilValue<boolean>(store.queriesEnabled);
|
||||
return useQuery<string>([QueryKeys.balance], () => dataService.getUserBalance(), {
|
||||
refetchOnWindowFocus: true,
|
||||
refetchOnReconnect: true,
|
||||
refetchOnMount: true,
|
||||
...config,
|
||||
enabled: (config?.enabled ?? true) === true && queriesEnabled,
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetSearchEnabledQuery = (
|
||||
config?: UseQueryOptions<boolean>,
|
||||
): QueryObserverResult<boolean> => {
|
||||
const queriesEnabled = useRecoilValue<boolean>(store.queriesEnabled);
|
||||
return useQuery<boolean>([QueryKeys.searchEnabled], () => dataService.getSearchEnabled(), {
|
||||
refetchOnWindowFocus: false,
|
||||
refetchOnReconnect: false,
|
||||
refetchOnMount: false,
|
||||
...config,
|
||||
enabled: (config?.enabled ?? true) === true && queriesEnabled,
|
||||
});
|
||||
};
|
|
@ -1,7 +1,9 @@
|
|||
export * from './Auth';
|
||||
export * from './Agents';
|
||||
export * from './Endpoints';
|
||||
export * from './Files';
|
||||
export * from './Messages';
|
||||
export * from './Misc';
|
||||
export * from './Tools';
|
||||
export * from './connection';
|
||||
export * from './mutations';
|
||||
|
|
|
@ -5,6 +5,7 @@ import {
|
|||
defaultOrderQuery,
|
||||
defaultAssistantsVersion,
|
||||
} from 'librechat-data-provider';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { useQuery, useInfiniteQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import type {
|
||||
UseInfiniteQueryOptions,
|
||||
|
@ -28,6 +29,7 @@ import type {
|
|||
SharedLinksResponse,
|
||||
} from 'librechat-data-provider';
|
||||
import { findPageForConversation } from '~/utils';
|
||||
import store from '~/store';
|
||||
|
||||
export const useGetPresetsQuery = (
|
||||
config?: UseQueryOptions<TPreset[]>,
|
||||
|
@ -115,6 +117,7 @@ export const useConversationsInfiniteQuery = (
|
|||
params?: ConversationListParams,
|
||||
config?: UseInfiniteQueryOptions<ConversationListResponse, unknown>,
|
||||
) => {
|
||||
const queriesEnabled = useRecoilValue<boolean>(store.queriesEnabled);
|
||||
return useInfiniteQuery<ConversationListResponse, unknown>(
|
||||
params?.isArchived === true ? [QueryKeys.archivedConversations] : [QueryKeys.allConversations],
|
||||
({ pageParam = '' }) =>
|
||||
|
@ -135,6 +138,7 @@ export const useConversationsInfiniteQuery = (
|
|||
refetchOnReconnect: false,
|
||||
refetchOnMount: false,
|
||||
...config,
|
||||
enabled: (config?.enabled ?? true) === true && queriesEnabled,
|
||||
},
|
||||
);
|
||||
};
|
||||
|
@ -156,7 +160,7 @@ export const useSharedLinksQuery = (
|
|||
sortBy,
|
||||
sortDirection,
|
||||
}),
|
||||
getNextPageParam: (lastPage) => lastPage?.nextCursor ?? undefined,
|
||||
getNextPageParam: (lastPage) => lastPage.nextCursor ?? undefined,
|
||||
keepPreviousData: true,
|
||||
staleTime: 5 * 60 * 1000, // 5 minutes
|
||||
cacheTime: 30 * 60 * 1000, // 30 minutes
|
||||
|
|
|
@ -7,12 +7,17 @@ import {
|
|||
useCallback,
|
||||
createContext,
|
||||
} from 'react';
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||
import { setTokenHeader, SystemRoles } from 'librechat-data-provider';
|
||||
import { useGetUserQuery, useRefreshTokenMutation } from 'librechat-data-provider/react-query';
|
||||
import type { TLoginResponse, TLoginUser } from 'librechat-data-provider';
|
||||
import { useLoginUserMutation, useLogoutUserMutation, useGetRole } from '~/data-provider';
|
||||
import type * as t from 'librechat-data-provider';
|
||||
import {
|
||||
useGetRole,
|
||||
useGetUserQuery,
|
||||
useLoginUserMutation,
|
||||
useLogoutUserMutation,
|
||||
useRefreshTokenMutation,
|
||||
} from '~/data-provider';
|
||||
import { TAuthConfig, TUserContext, TAuthContext, TResError } from '~/common';
|
||||
import useTimeout from './useTimeout';
|
||||
import store from '~/store';
|
||||
|
@ -42,14 +47,20 @@ const AuthContextProvider = ({
|
|||
const setUserContext = useCallback(
|
||||
(userContext: TUserContext) => {
|
||||
const { token, isAuthenticated, user, redirect } = userContext;
|
||||
if (user) {
|
||||
setUser(user);
|
||||
}
|
||||
setUser(user);
|
||||
setToken(token);
|
||||
//@ts-ignore - ok for token to be undefined initially
|
||||
setTokenHeader(token);
|
||||
setIsAuthenticated(isAuthenticated);
|
||||
if (redirect != null && redirect) {
|
||||
if (redirect == null) {
|
||||
return;
|
||||
}
|
||||
if (redirect.startsWith('http://') || redirect.startsWith('https://')) {
|
||||
// For external links, use window.location
|
||||
window.location.href = redirect;
|
||||
// Or if you want to open in a new tab:
|
||||
// window.open(redirect, '_blank');
|
||||
} else {
|
||||
navigate(redirect, { replace: true });
|
||||
}
|
||||
},
|
||||
|
@ -57,14 +68,25 @@ const AuthContextProvider = ({
|
|||
);
|
||||
const doSetError = useTimeout({ callback: (error) => setError(error as string | undefined) });
|
||||
|
||||
const loginUser = useLoginUserMutation();
|
||||
const loginUser = useLoginUserMutation({
|
||||
onSuccess: (data: t.TLoginResponse) => {
|
||||
const { user, token } = data;
|
||||
setError(undefined);
|
||||
setUserContext({ token, isAuthenticated: true, user, redirect: '/c/new' });
|
||||
},
|
||||
onError: (error: TResError | unknown) => {
|
||||
const resError = error as TResError;
|
||||
doSetError(resError.message);
|
||||
navigate('/login', { replace: true });
|
||||
},
|
||||
});
|
||||
const logoutUser = useLogoutUserMutation({
|
||||
onSuccess: () => {
|
||||
onSuccess: (data) => {
|
||||
setUserContext({
|
||||
token: undefined,
|
||||
isAuthenticated: false,
|
||||
user: undefined,
|
||||
redirect: '/login',
|
||||
redirect: data.redirect ?? '/login',
|
||||
});
|
||||
},
|
||||
onError: (error) => {
|
||||
|
@ -77,24 +99,13 @@ const AuthContextProvider = ({
|
|||
});
|
||||
},
|
||||
});
|
||||
const refreshToken = useRefreshTokenMutation();
|
||||
|
||||
const logout = useCallback(() => logoutUser.mutate(undefined), [logoutUser]);
|
||||
const userQuery = useGetUserQuery({ enabled: !!(token ?? '') });
|
||||
const refreshToken = useRefreshTokenMutation();
|
||||
|
||||
const login = (data: TLoginUser) => {
|
||||
loginUser.mutate(data, {
|
||||
onSuccess: (data: TLoginResponse) => {
|
||||
const { user, token } = data;
|
||||
setError(undefined);
|
||||
setUserContext({ token, isAuthenticated: true, user, redirect: '/c/new' });
|
||||
},
|
||||
onError: (error: TResError | unknown) => {
|
||||
const resError = error as TResError;
|
||||
doSetError(resError.message);
|
||||
navigate('/login', { replace: true });
|
||||
},
|
||||
});
|
||||
const login = (data: t.TLoginUser) => {
|
||||
loginUser.mutate(data);
|
||||
};
|
||||
|
||||
const silentRefresh = useCallback(() => {
|
||||
|
@ -103,7 +114,7 @@ const AuthContextProvider = ({
|
|||
return;
|
||||
}
|
||||
refreshToken.mutate(undefined, {
|
||||
onSuccess: (data: TLoginResponse | undefined) => {
|
||||
onSuccess: (data: t.TRefreshTokenResponse | undefined) => {
|
||||
const { user, token = '' } = data ?? {};
|
||||
if (token) {
|
||||
setUserContext({ token, isAuthenticated: true, user });
|
||||
|
|
|
@ -5,7 +5,6 @@ import { LocalStorageKeys } from 'librechat-data-provider';
|
|||
import { useAvailablePluginsQuery } from 'librechat-data-provider/react-query';
|
||||
import type { TStartupConfig, TPlugin, TUser } from 'librechat-data-provider';
|
||||
import { mapPlugins, selectPlugins, processPlugins } from '~/utils';
|
||||
import useConfigOverride from './useConfigOverride';
|
||||
import store from '~/store';
|
||||
|
||||
const pluginStore: TPlugin = {
|
||||
|
@ -25,7 +24,6 @@ export default function useAppStartup({
|
|||
startupConfig?: TStartupConfig;
|
||||
user?: TUser;
|
||||
}) {
|
||||
useConfigOverride();
|
||||
const setAvailableTools = useSetRecoilState(store.availableTools);
|
||||
const [defaultPreset, setDefaultPreset] = useRecoilState(store.defaultPreset);
|
||||
const { data: allPlugins } = useAvailablePluginsQuery({
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import { useGetEndpointsQuery, useGetModelsQuery } from 'librechat-data-provider/react-query';
|
||||
import { useGetModelsQuery } from 'librechat-data-provider/react-query';
|
||||
import type {
|
||||
TConversation,
|
||||
TPreset,
|
||||
TEndpointsConfig,
|
||||
TModelsConfig,
|
||||
TConversation,
|
||||
TPreset,
|
||||
} from 'librechat-data-provider';
|
||||
import { getDefaultEndpoint, buildDefaultConvo } from '~/utils';
|
||||
import { useGetEndpointsQuery } from '~/data-provider';
|
||||
|
||||
type TDefaultConvo = { conversation: Partial<TConversation>; preset?: Partial<TPreset> | null };
|
||||
|
||||
|
|
|
@ -1,17 +1,19 @@
|
|||
import { useRecoilValue } from 'recoil';
|
||||
import { useCallback, useRef, useEffect } from 'react';
|
||||
import { useGetModelsQuery } from 'librechat-data-provider/react-query';
|
||||
import { LocalStorageKeys, isAssistantsEndpoint } from 'librechat-data-provider';
|
||||
import { useGetModelsQuery, useGetEndpointsQuery } from 'librechat-data-provider/react-query';
|
||||
import type {
|
||||
TPreset,
|
||||
TModelsConfig,
|
||||
TConversation,
|
||||
TEndpointsConfig,
|
||||
EModelEndpoint,
|
||||
} from 'librechat-data-provider';
|
||||
import type { SetterOrUpdater } from 'recoil';
|
||||
import type { AssistantListItem } from '~/common';
|
||||
import { getEndpointField, buildDefaultConvo, getDefaultEndpoint } from '~/utils';
|
||||
import useAssistantListMap from '~/hooks/Assistants/useAssistantListMap';
|
||||
import { useGetEndpointsQuery } from '~/data-provider';
|
||||
import { mainTextareaId } from '~/common';
|
||||
import store from '~/store';
|
||||
|
||||
|
@ -32,7 +34,7 @@ const useGenerateConvo = ({
|
|||
const rootConvo = useRecoilValue(store.conversationByKeySelector(rootIndex));
|
||||
|
||||
useEffect(() => {
|
||||
if (rootConvo?.conversationId && setConversation) {
|
||||
if (rootConvo?.conversationId != null && setConversation) {
|
||||
setConversation((prevState) => {
|
||||
if (!prevState) {
|
||||
return prevState;
|
||||
|
@ -85,11 +87,11 @@ const useGenerateConvo = ({
|
|||
}
|
||||
|
||||
const isAssistantEndpoint = isAssistantsEndpoint(defaultEndpoint);
|
||||
const assistants: AssistantListItem[] = assistantsListMap[defaultEndpoint] ?? [];
|
||||
const assistants: AssistantListItem[] = assistantsListMap[defaultEndpoint ?? ''] ?? [];
|
||||
|
||||
if (
|
||||
conversation.assistant_id &&
|
||||
!assistantsListMap[defaultEndpoint]?.[conversation.assistant_id]
|
||||
!assistantsListMap[defaultEndpoint ?? '']?.[conversation.assistant_id]
|
||||
) {
|
||||
conversation.assistant_id = undefined;
|
||||
}
|
||||
|
@ -101,7 +103,7 @@ const useGenerateConvo = ({
|
|||
}
|
||||
|
||||
if (
|
||||
conversation.assistant_id &&
|
||||
conversation.assistant_id != null &&
|
||||
isAssistantEndpoint &&
|
||||
conversation.conversationId === 'new'
|
||||
) {
|
||||
|
@ -109,19 +111,19 @@ const useGenerateConvo = ({
|
|||
conversation.model = assistant?.model;
|
||||
}
|
||||
|
||||
if (conversation.assistant_id && !isAssistantEndpoint) {
|
||||
if (conversation.assistant_id != null && !isAssistantEndpoint) {
|
||||
conversation.assistant_id = undefined;
|
||||
}
|
||||
|
||||
const models = modelsConfig?.[defaultEndpoint] ?? [];
|
||||
const models = modelsConfig?.[defaultEndpoint ?? ''] ?? [];
|
||||
conversation = buildDefaultConvo({
|
||||
conversation,
|
||||
lastConversationSetup: preset as TConversation,
|
||||
endpoint: defaultEndpoint,
|
||||
endpoint: defaultEndpoint ?? ('' as EModelEndpoint),
|
||||
models,
|
||||
});
|
||||
|
||||
if (preset?.title) {
|
||||
if (preset?.title != null && preset.title !== '') {
|
||||
conversation.title = preset.title;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { useCallback } from 'react';
|
||||
import { getResponseSender } from 'librechat-data-provider';
|
||||
import { useGetEndpointsQuery } from 'librechat-data-provider/react-query';
|
||||
import type { TEndpointOption, TEndpointsConfig } from 'librechat-data-provider';
|
||||
import { useGetEndpointsQuery } from '~/data-provider';
|
||||
|
||||
export default function useGetSender() {
|
||||
const { data: endpointsConfig = {} as TEndpointsConfig } = useGetEndpointsQuery();
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
import { useEffect, useState, useCallback } from 'react';
|
||||
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
||||
import { useNavigate, useLocation } from 'react-router-dom';
|
||||
import { useGetSearchEnabledQuery } from 'librechat-data-provider/react-query';
|
||||
import type { UseInfiniteQueryResult } from '@tanstack/react-query';
|
||||
import type { ConversationListResponse } from 'librechat-data-provider';
|
||||
import { useSearchInfiniteQuery } from '~/data-provider';
|
||||
import { useSearchInfiniteQuery, useGetSearchEnabledQuery } from '~/data-provider';
|
||||
import useNewConvo from '~/hooks/useNewConvo';
|
||||
import store from '~/store';
|
||||
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
import { useMemo } from 'react';
|
||||
import {
|
||||
useGetModelsQuery,
|
||||
useGetStartupConfig,
|
||||
useGetEndpointsQuery,
|
||||
} from 'librechat-data-provider/react-query';
|
||||
import { useGetModelsQuery } from 'librechat-data-provider/react-query';
|
||||
import {
|
||||
alternateName,
|
||||
EModelEndpoint,
|
||||
|
@ -13,8 +9,13 @@ import {
|
|||
} from 'librechat-data-provider';
|
||||
import type { TAssistantsMap, TEndpointsConfig } from 'librechat-data-provider';
|
||||
import type { MentionOption } from '~/common';
|
||||
import {
|
||||
useGetPresetsQuery,
|
||||
useGetEndpointsQuery,
|
||||
useListAgentsQuery,
|
||||
useGetStartupConfig,
|
||||
} from '~/data-provider';
|
||||
import useAssistantListMap from '~/hooks/Assistants/useAssistantListMap';
|
||||
import { useGetPresetsQuery, useListAgentsQuery } from '~/data-provider';
|
||||
import { mapEndpoints, getPresetTitle } from '~/utils';
|
||||
import { EndpointIcon } from '~/components/Endpoints';
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { useGetEndpointsQuery } from 'librechat-data-provider/react-query';
|
||||
import { useChatContext } from '~/Providers/ChatContext';
|
||||
import { useGetEndpointsQuery } from '~/data-provider';
|
||||
import { getEndpointField } from '~/utils';
|
||||
import useUserKey from './useUserKey';
|
||||
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
import { useMemo, useCallback } from 'react';
|
||||
import { EModelEndpoint } from 'librechat-data-provider';
|
||||
import {
|
||||
useUserKeyQuery,
|
||||
useGetEndpointsQuery,
|
||||
useUpdateUserKeysMutation,
|
||||
} from 'librechat-data-provider/react-query';
|
||||
import { useUserKeyQuery, useUpdateUserKeysMutation } from 'librechat-data-provider/react-query';
|
||||
import { useGetEndpointsQuery } from '~/data-provider';
|
||||
|
||||
const useUserKey = (endpoint: string) => {
|
||||
const { data: endpointsConfig } = useGetEndpointsQuery();
|
||||
|
@ -24,7 +21,7 @@ const useUserKey = (endpoint: string) => {
|
|||
|
||||
const getExpiry = useCallback(() => {
|
||||
if (checkUserKey.data) {
|
||||
return checkUserKey.data?.expiresAt || 'never';
|
||||
return checkUserKey.data.expiresAt || 'never';
|
||||
}
|
||||
}, [checkUserKey.data]);
|
||||
|
||||
|
|
|
@ -1,23 +1,22 @@
|
|||
import type { EventSubmission, TMessage, TPayload, TSubmission } from 'librechat-data-provider';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { v4 } from 'uuid';
|
||||
import { SSE } from 'sse.js';
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
import {
|
||||
request,
|
||||
/* @ts-ignore */
|
||||
createPayload,
|
||||
isAgentsEndpoint,
|
||||
isAssistantsEndpoint,
|
||||
removeNullishValues,
|
||||
request,
|
||||
isAssistantsEndpoint,
|
||||
} from 'librechat-data-provider';
|
||||
import { useGetStartupConfig, useGetUserBalance } from 'librechat-data-provider/react-query';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
import { SSE } from 'sse.js';
|
||||
import { v4 } from 'uuid';
|
||||
import type { TResData } from '~/common';
|
||||
import { useGenTitleMutation } from '~/data-provider';
|
||||
import { useAuthContext } from '~/hooks/AuthContext';
|
||||
import store from '~/store';
|
||||
import type { EventSubmission, TMessage, TPayload, TSubmission } from 'librechat-data-provider';
|
||||
import type { EventHandlerParams } from './useEventHandlers';
|
||||
import type { TResData } from '~/common';
|
||||
import { useGenTitleMutation, useGetStartupConfig, useGetUserBalance } from '~/data-provider';
|
||||
import { useAuthContext } from '~/hooks/AuthContext';
|
||||
import useEventHandlers from './useEventHandlers';
|
||||
import store from '~/store';
|
||||
|
||||
type ChatHelpers = Pick<
|
||||
EventHandlerParams,
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
import { useCallback, useRef } from 'react';
|
||||
import {
|
||||
useGetModelsQuery,
|
||||
useGetStartupConfig,
|
||||
useGetEndpointsQuery,
|
||||
} from 'librechat-data-provider/react-query';
|
||||
import { useGetModelsQuery } from 'librechat-data-provider/react-query';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import {
|
||||
Constants,
|
||||
|
@ -30,8 +26,8 @@ import {
|
|||
getModelSpecIconURL,
|
||||
updateLastSelectedModel,
|
||||
} from '~/utils';
|
||||
import { useDeleteFilesMutation, useGetEndpointsQuery, useGetStartupConfig } from '~/data-provider';
|
||||
import useAssistantListMap from './Assistants/useAssistantListMap';
|
||||
import { useDeleteFilesMutation } from '~/data-provider';
|
||||
import { usePauseGlobalAudio } from './Audio';
|
||||
import { mainTextareaId } from '~/common';
|
||||
import store from '~/store';
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
import { useEffect } from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { Constants, EModelEndpoint } from 'librechat-data-provider';
|
||||
import {
|
||||
useGetModelsQuery,
|
||||
useGetStartupConfig,
|
||||
useGetEndpointsQuery,
|
||||
} from 'librechat-data-provider/react-query';
|
||||
import { useGetModelsQuery } from 'librechat-data-provider/react-query';
|
||||
import type { TPreset } from 'librechat-data-provider';
|
||||
import {
|
||||
useGetConvoIdQuery,
|
||||
useHealthCheck,
|
||||
useGetEndpointsQuery,
|
||||
useGetStartupConfig,
|
||||
} from '~/data-provider';
|
||||
import { useNewConvo, useAppStartup, useAssistantListMap } from '~/hooks';
|
||||
import { useGetConvoIdQuery, useHealthCheck } from '~/data-provider';
|
||||
import { getDefaultModelSpec, getModelSpecIconURL } from '~/utils';
|
||||
import { ToolCallsMapProvider } from '~/Providers';
|
||||
import ChatView from '~/components/Chat/ChatView';
|
||||
|
|
|
@ -1,7 +1,23 @@
|
|||
import { useEffect } from 'react';
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { useAuthContext } from '~/hooks/AuthContext';
|
||||
import StartupLayout from './Startup';
|
||||
import store from '~/store';
|
||||
|
||||
export default function LoginLayout() {
|
||||
const { isAuthenticated } = useAuthContext();
|
||||
const [queriesEnabled, setQueriesEnabled] = useRecoilState<boolean>(store.queriesEnabled);
|
||||
useEffect(() => {
|
||||
if (queriesEnabled) {
|
||||
return;
|
||||
}
|
||||
const timeout: NodeJS.Timeout = setTimeout(() => {
|
||||
setQueriesEnabled(true);
|
||||
}, 500);
|
||||
|
||||
return () => {
|
||||
clearTimeout(timeout);
|
||||
};
|
||||
}, [queriesEnabled, setQueriesEnabled]);
|
||||
return <StartupLayout isAuthenticated={isAuthenticated} />;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { useEffect, useState } from 'react';
|
||||
import { Outlet, useNavigate, useLocation } from 'react-router-dom';
|
||||
import { useGetStartupConfig } from 'librechat-data-provider/react-query';
|
||||
import type { TStartupConfig } from 'librechat-data-provider';
|
||||
import { useGetStartupConfig } from '~/data-provider';
|
||||
import AuthLayout from '~/components/Auth/AuthLayout';
|
||||
import { useLocalize } from '~/hooks';
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import { Outlet, useNavigate } from 'react-router-dom';
|
||||
import { useGetStartupConfig } from 'librechat-data-provider/react-query';
|
||||
import type { ContextType } from '~/common';
|
||||
import {
|
||||
AgentsMapContext,
|
||||
|
@ -11,7 +10,7 @@ import {
|
|||
} from '~/Providers';
|
||||
import { useAuthContext, useAssistantsMap, useAgentsMap, useFileMap, useSearch } from '~/hooks';
|
||||
import TermsAndConditionsModal from '~/components/ui/TermsAndConditionsModal';
|
||||
import { useUserTermsQuery } from '~/data-provider';
|
||||
import { useUserTermsQuery, useGetStartupConfig } from '~/data-provider';
|
||||
import { Nav, MobileNav } from '~/components/Nav';
|
||||
import { Banner } from '~/components/Banners';
|
||||
|
||||
|
|
|
@ -9,4 +9,9 @@ const messageAttachmentsMap = atom<Record<string, TAttachment[] | undefined>>({
|
|||
default: {},
|
||||
});
|
||||
|
||||
export default { hideBannerHint, messageAttachmentsMap };
|
||||
const queriesEnabled = atom<boolean>({
|
||||
key: 'queriesEnabled',
|
||||
default: true,
|
||||
});
|
||||
|
||||
export default { hideBannerHint, messageAttachmentsMap, queriesEnabled };
|
||||
|
|
|
@ -133,11 +133,11 @@ export const updateTokenCount = (text: string) => {
|
|||
return request.post(endpoints.tokenizer(), { arg: text });
|
||||
};
|
||||
|
||||
export const login = (payload: t.TLoginUser) => {
|
||||
export const login = (payload: t.TLoginUser): Promise<t.TLoginResponse> => {
|
||||
return request.post(endpoints.login(), payload);
|
||||
};
|
||||
|
||||
export const logout = () => {
|
||||
export const logout = (): Promise<m.TLogoutResponse> => {
|
||||
return request.post(endpoints.logout());
|
||||
};
|
||||
|
||||
|
|
|
@ -53,7 +53,9 @@ export enum MutationKeys {
|
|||
fileDelete = 'fileDelete',
|
||||
updatePreset = 'updatePreset',
|
||||
deletePreset = 'deletePreset',
|
||||
loginUser = 'loginUser',
|
||||
logoutUser = 'logoutUser',
|
||||
refreshToken = 'refreshToken',
|
||||
avatarUpload = 'avatarUpload',
|
||||
speechToText = 'speechToText',
|
||||
textToSpeech = 'textToSpeech',
|
||||
|
|
|
@ -5,12 +5,10 @@ import type {
|
|||
QueryObserverResult,
|
||||
} from '@tanstack/react-query';
|
||||
import { initialModelsConfig } from '../config';
|
||||
import type { TStartupConfig } from '../config';
|
||||
import { defaultOrderQuery } from '../types/assistants';
|
||||
import * as dataService from '../data-service';
|
||||
import * as m from '../types/mutations';
|
||||
import { QueryKeys } from '../keys';
|
||||
import request from '../request';
|
||||
import * as s from '../schemas';
|
||||
import * as t from '../types';
|
||||
|
||||
|
@ -31,18 +29,6 @@ export const useAbortRequestWithMessage = (): UseMutationResult<
|
|||
);
|
||||
};
|
||||
|
||||
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 = <TData = s.TMessage[]>(
|
||||
id: string,
|
||||
config?: UseQueryOptions<s.TMessage[], unknown, TData>,
|
||||
|
@ -98,17 +84,6 @@ export const useGetSharedLinkQuery = (
|
|||
);
|
||||
};
|
||||
|
||||
export const useGetUserBalance = (
|
||||
config?: UseQueryOptions<string>,
|
||||
): QueryObserverResult<string> => {
|
||||
return useQuery<string>([QueryKeys.balance], () => dataService.getUserBalance(), {
|
||||
refetchOnWindowFocus: true,
|
||||
refetchOnReconnect: true,
|
||||
refetchOnMount: true,
|
||||
...config,
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetConversationByIdQuery = (
|
||||
id: string,
|
||||
config?: UseQueryOptions<s.TConversation>,
|
||||
|
@ -226,33 +201,6 @@ export const useRevokeAllUserKeysMutation = (): UseMutationResult<unknown> => {
|
|||
});
|
||||
};
|
||||
|
||||
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 = <TData = t.TEndpointsConfig>(
|
||||
config?: UseQueryOptions<t.TEndpointsConfig, unknown, TData>,
|
||||
): QueryObserverResult<TData> => {
|
||||
return useQuery<t.TEndpointsConfig, unknown, TData>(
|
||||
[QueryKeys.endpoints],
|
||||
() => dataService.getAIEndpoints(),
|
||||
{
|
||||
staleTime: Infinity,
|
||||
refetchOnWindowFocus: false,
|
||||
refetchOnReconnect: false,
|
||||
refetchOnMount: false,
|
||||
...config,
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
export const useGetModelsQuery = (
|
||||
config?: UseQueryOptions<t.TModelsConfig>,
|
||||
): QueryObserverResult<t.TModelsConfig> => {
|
||||
|
@ -343,20 +291,6 @@ export const useRegisterUserMutation = (
|
|||
);
|
||||
};
|
||||
|
||||
export const useRefreshTokenMutation = (): UseMutationResult<
|
||||
t.TRefreshTokenResponse | undefined,
|
||||
unknown,
|
||||
unknown,
|
||||
unknown
|
||||
> => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation(() => request.refreshToken(), {
|
||||
onMutate: () => {
|
||||
queryClient.removeQueries();
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const useUserKeyQuery = (
|
||||
name: string,
|
||||
config?: UseQueryOptions<t.TCheckUserKeyResponse>,
|
||||
|
@ -428,17 +362,6 @@ export const useUpdateUserPluginsMutation = (
|
|||
});
|
||||
};
|
||||
|
||||
export const useGetStartupConfig = (
|
||||
config?: UseQueryOptions<TStartupConfig>,
|
||||
): QueryObserverResult<TStartupConfig> => {
|
||||
return useQuery<TStartupConfig>([QueryKeys.startupConfig], () => dataService.getStartupConfig(), {
|
||||
refetchOnWindowFocus: false,
|
||||
refetchOnReconnect: false,
|
||||
refetchOnMount: false,
|
||||
...config,
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetCustomConfigSpeechQuery = (
|
||||
config?: UseQueryOptions<t.TCustomConfigSpeechResponse>,
|
||||
): QueryObserverResult<t.TCustomConfigSpeechResponse> => {
|
||||
|
@ -453,14 +376,3 @@ export const useGetCustomConfigSpeechQuery = (
|
|||
},
|
||||
);
|
||||
};
|
||||
|
||||
export const useGetBannerQuery = (
|
||||
config?: UseQueryOptions<t.TBannerResponse>,
|
||||
): QueryObserverResult<t.TBannerResponse> => {
|
||||
return useQuery<t.TBannerResponse>([QueryKeys.banner], () => dataService.getBanner(), {
|
||||
refetchOnWindowFocus: false,
|
||||
refetchOnReconnect: false,
|
||||
refetchOnMount: false,
|
||||
...config,
|
||||
});
|
||||
};
|
||||
|
|
|
@ -91,6 +91,10 @@ axios.interceptors.response.use(
|
|||
return Promise.reject(error);
|
||||
}
|
||||
|
||||
if (originalRequest.url?.includes('/api/auth/logout') === true) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
||||
if (error.response.status === 401 && !originalRequest._retry) {
|
||||
console.warn('401 error, refreshing token');
|
||||
originalRequest._retry = true;
|
||||
|
|
|
@ -49,8 +49,6 @@ export type UpdatePresetOptions = MutationOptions<types.TPreset, types.TPreset>;
|
|||
|
||||
export type DeletePresetOptions = MutationOptions<PresetDeleteResponse, types.TPreset | undefined>;
|
||||
|
||||
export type LogoutOptions = MutationOptions<unknown, undefined>;
|
||||
|
||||
/* Assistant mutations */
|
||||
|
||||
export type AssistantAvatarVariables = {
|
||||
|
@ -331,3 +329,10 @@ export type EditArtifactOptions = MutationOptions<
|
|||
unknown,
|
||||
Error
|
||||
>;
|
||||
|
||||
export type TLogoutResponse = {
|
||||
message: string;
|
||||
redirect?: string;
|
||||
};
|
||||
|
||||
export type LogoutOptions = MutationOptions<TLogoutResponse, undefined>;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue