* chore(eslint): add ignore pattern for packages/data-provider/types
chore(data-provider): fix import formatting in index.ts
chore(data-provider): add types/index.d.ts to tsconfig include

* fix(Auth): fix "skip login" bug, where UI would render in an unauthenticated state
fix(Login.tsx): replace navigate('/chat/new') with navigate('/chat/new', { replace: true })
fix(AuthContext.tsx): replace navigate(redirect) with navigate(redirect, { replace: true })
fix(AuthContext.tsx): replace navigate('/login') with navigate('/login', { replace: true })
fix(AuthContext.tsx): replace navigate('/login') with navigate('/login', { replace: true })
fix(routes/Chat.jsx): add check for isAuthenticated: navigate to '/login' and render null if not authenticated
fix(routes/index.jsx): add check for isAuthenticated: navigate to '/login' and render null if not authenticated

* refactor(SubmitButton.jsx): create a set of endpoints to hide set tokens
fix(SubmitButton.jsx): fix condition to check if token is provided for certain endpoints
This commit is contained in:
Danny Avila 2023-07-12 11:37:27 -04:00 committed by GitHub
parent 747e087cf5
commit f5672ddcf8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 47 additions and 21 deletions

View file

@ -13,6 +13,9 @@ module.exports = {
'plugin:jest/recommended', 'plugin:jest/recommended',
'prettier' 'prettier'
], ],
ignorePatterns: [
'packages/data-provider/types/**/*',
],
parser: '@typescript-eslint/parser', parser: '@typescript-eslint/parser',
parserOptions: { parserOptions: {
ecmaVersion: 'latest', ecmaVersion: 'latest',

View file

@ -19,7 +19,7 @@ function Login() {
useEffect(() => { useEffect(() => {
if (isAuthenticated) { if (isAuthenticated) {
navigate('/chat/new'); navigate('/chat/new', { replace: true });
} }
}, [isAuthenticated, navigate]); }, [isAuthenticated, navigate]);

View file

@ -16,6 +16,7 @@ export default function SubmitButton({
const { getToken } = store.useToken(endpoint); const { getToken } = store.useToken(endpoint);
const isTokenProvided = endpointsConfig?.[endpoint]?.userProvide ? !!getToken() : true; const isTokenProvided = endpointsConfig?.[endpoint]?.userProvide ? !!getToken() : true;
const endpointsToHideSetTokens = new Set(['openAI', 'azureOpenAI', 'bingAI']);
const clickHandler = (e) => { const clickHandler = (e) => {
e.preventDefault(); e.preventDefault();
@ -38,7 +39,7 @@ export default function SubmitButton({
</div> </div>
</button> </button>
); );
} else if (!isTokenProvided && (endpoint !== 'openAI' || endpoint !== 'azureOpenAI' )) { } else if (!isTokenProvided && (!endpointsToHideSetTokens.has(endpoint))) {
return ( return (
<> <>
<button <button

View file

@ -83,7 +83,7 @@ const AuthContextProvider = ({
setTokenHeader(token); setTokenHeader(token);
setIsAuthenticated(isAuthenticated); setIsAuthenticated(isAuthenticated);
if (redirect) { if (redirect) {
navigate(redirect); navigate(redirect, { replace: true });
} }
}, },
[navigate] [navigate]
@ -101,7 +101,8 @@ const AuthContextProvider = ({
setUserContext({ token, isAuthenticated: true, user, redirect: '/chat/new' }); setUserContext({ token, isAuthenticated: true, user, redirect: '/chat/new' });
}, },
onError: (error) => { onError: (error) => {
doSetError(error.message); doSetError((error as Error).message);
navigate('/login', { replace: true });
} }
}); });
}; };
@ -122,7 +123,7 @@ const AuthContextProvider = ({
}); });
}, },
onError: (error) => { onError: (error) => {
doSetError(error.message); doSetError((error as Error).message);
} }
}); });
}; };
@ -131,9 +132,8 @@ const AuthContextProvider = ({
if (userQuery.data) { if (userQuery.data) {
setUser(userQuery.data); setUser(userQuery.data);
} else if (userQuery.isError) { } else if (userQuery.isError) {
//@ts-ignore - userQuery.error is of type unknown doSetError((userQuery?.error as Error).message);
doSetError(userQuery?.error.message); navigate('/login', { replace: true });
navigate('/login');
} }
if (error && isAuthenticated) { if (error && isAuthenticated) {
doSetError(undefined); doSetError(undefined);
@ -143,7 +143,7 @@ const AuthContextProvider = ({
if (tokenFromCookie) { if (tokenFromCookie) {
setUserContext({ token: tokenFromCookie, isAuthenticated: true, user: userQuery.data }); setUserContext({ token: tokenFromCookie, isAuthenticated: true, user: userQuery.data });
} else { } else {
navigate('/login'); navigate('/login', { replace: true });
} }
} }
}, [ }, [

View file

@ -1,4 +1,5 @@
import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
import { useAuthContext } from '~/hooks/AuthContext';
import { useNavigate, useParams } from 'react-router-dom'; import { useNavigate, useParams } from 'react-router-dom';
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil'; import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil';
@ -14,6 +15,7 @@ import {
} from '@librechat/data-provider'; } from '@librechat/data-provider';
export default function Chat() { export default function Chat() {
const { isAuthenticated } = useAuthContext();
const [shouldNavigate, setShouldNavigate] = useState(true); const [shouldNavigate, setShouldNavigate] = useState(true);
const searchQuery = useRecoilValue(store.searchQuery); const searchQuery = useRecoilValue(store.searchQuery);
const [conversation, setConversation] = useRecoilState(store.conversation); const [conversation, setConversation] = useRecoilState(store.conversation);
@ -29,6 +31,18 @@ export default function Chat() {
const getConversationMutation = useGetConversationByIdMutation(conversationId); const getConversationMutation = useGetConversationByIdMutation(conversationId);
const { data: config } = useGetStartupConfig(); const { data: config } = useGetStartupConfig();
useEffect(() => {
let timeout = setTimeout(() => {
if (!isAuthenticated) {
navigate('/login', { replace: true });
}
}, 300)
return () => {
clearTimeout(timeout);
}
}, [isAuthenticated, navigate]);
useEffect(() => { useEffect(() => {
if (!isSubmitting && !shouldNavigate) { if (!isSubmitting && !shouldNavigate) {
setShouldNavigate(true); setShouldNavigate(true);
@ -41,7 +55,7 @@ export default function Chat() {
if (conversation === null && conversationId === 'new') { if (conversation === null && conversationId === 'new') {
newConversation(); newConversation();
setShouldNavigate(true); setShouldNavigate(true);
} }
// No current conversation and conversationId exists // No current conversation and conversationId exists
else if (conversation === null && conversationId) { else if (conversation === null && conversationId) {
getConversationMutation.mutate(conversationId, { getConversationMutation.mutate(conversationId, {
@ -53,24 +67,24 @@ export default function Chat() {
onError: (error) => { onError: (error) => {
console.error('Failed to fetch the conversation'); console.error('Failed to fetch the conversation');
console.error(error); console.error(error);
navigate(`/chat/new`); navigate('/chat/new');
newConversation(); newConversation();
setShouldNavigate(true); setShouldNavigate(true);
} }
}); });
setMessages(null); setMessages(null);
} }
// No current conversation and no conversationId // No current conversation and no conversationId
else if (conversation === null) { else if (conversation === null) {
navigate(`/chat/new`); navigate('/chat/new');
setShouldNavigate(true); setShouldNavigate(true);
} }
// Current conversationId is 'search' // Current conversationId is 'search'
else if (conversation?.conversationId === 'search') { else if (conversation?.conversationId === 'search') {
navigate(`/search/${searchQuery}`); navigate(`/search/${searchQuery}`);
setShouldNavigate(true); setShouldNavigate(true);
} }
// Conversation change and isSubmitting // Conversation change and isSubmitting
else if (conversation?.conversationId !== conversationId && isSubmitting) { else if (conversation?.conversationId !== conversationId && isSubmitting) {
setShouldNavigate(false); setShouldNavigate(false);
} }
@ -101,6 +115,10 @@ export default function Chat() {
} }
}, [messagesQuery.data, messagesQuery.isError, setMessages]); }, [messagesQuery.data, messagesQuery.isError, setMessages]);
if (!isAuthenticated) {
return null;
}
// if not a conversation // if not a conversation
if (conversation?.conversationId === 'search') return null; if (conversation?.conversationId === 'search') return null;
// if conversationId not match // if conversationId not match

View file

@ -23,7 +23,7 @@ export default function Root() {
const setIsSearchEnabled = useSetRecoilState(store.isSearchEnabled); const setIsSearchEnabled = useSetRecoilState(store.isSearchEnabled);
const setEndpointsConfig = useSetRecoilState(store.endpointsConfig); const setEndpointsConfig = useSetRecoilState(store.endpointsConfig);
const setPresets = useSetRecoilState(store.presets); const setPresets = useSetRecoilState(store.presets);
const { user } = useAuthContext(); const { user, isAuthenticated } = useAuthContext();
const searchEnabledQuery = useGetSearchEnabledQuery(); const searchEnabledQuery = useGetSearchEnabledQuery();
const endpointsQuery = useGetEndpointsQuery(); const endpointsQuery = useGetEndpointsQuery();
@ -57,6 +57,10 @@ export default function Root() {
} }
}, [searchEnabledQuery.data, searchEnabledQuery.isError]); }, [searchEnabledQuery.data, searchEnabledQuery.isError]);
if (!isAuthenticated) {
return null;
}
return ( return (
<> <>
<div className="flex h-screen"> <div className="flex h-screen">

View file

@ -23,7 +23,7 @@ export default function Search() {
searchPlaceholderConversation(); searchPlaceholderConversation();
setSearchQuery(query); setSearchQuery(query);
} else { } else {
navigate(`/chat/new`); navigate('/chat/new');
} }
} else if (conversation?.conversationId === 'search') { } else if (conversation?.conversationId === 'search') {
// jump to search page // jump to search page

View file

@ -16,7 +16,7 @@ const AuthLayout = () => (
export const router = createBrowserRouter([ export const router = createBrowserRouter([
{ {
path: 'register', path: 'register',
element: <Registration /> element: <Registration />
}, },
{ {
path: 'forgot-password', path: 'forgot-password',

View file

@ -4,4 +4,4 @@ export * from './types';
export * from './react-query-service'; export * from './react-query-service';
export * from './headers-helpers'; export * from './headers-helpers';
export * from './sse.mjs'; export * from './sse.mjs';
export {default as createPayload} from './createPayload'; export { default as createPayload } from './createPayload';

View file

@ -23,5 +23,5 @@
} }
}, },
"exclude": ["node_modules", "dist", "types"], "exclude": ["node_modules", "dist", "types"],
"include": ["src/**/*"] "include": ["src/**/*", "types/index.d.ts"]
} }