mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-01-08 19:48:51 +01:00
Build/Refactor: lint pre-commit hook and reformat repo to spec (#314)
* build/refactor: move lint/prettier packages to project root, install husky, add pre-commit hook * refactor: reformat files * build: put full eslintrc back with all rules
This commit is contained in:
parent
8d75b25104
commit
7fdc862042
157 changed files with 4836 additions and 2403 deletions
|
|
@ -25,9 +25,7 @@ export default function ClearConvos() {
|
|||
return (
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<button
|
||||
className="flex w-full cursor-pointer items-center gap-3 px-3 py-3 text-sm text-white transition-colors duration-200 hover:bg-gray-700"
|
||||
>
|
||||
<button className="flex w-full cursor-pointer items-center gap-3 px-3 py-3 text-sm text-white transition-colors duration-200 hover:bg-gray-700">
|
||||
<TrashIcon />
|
||||
Clear conversations
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ export default function ExportModel({ open, onOpenChange }) {
|
|||
setRecursive(true);
|
||||
}, [open]);
|
||||
|
||||
const _setType = newType => {
|
||||
const _setType = (newType) => {
|
||||
const exportBranchesSupport = newType === 'json' || newType === 'csv' || newType === 'webpage';
|
||||
const exportOptionsSupport = newType !== 'csv' && newType !== 'screenshot';
|
||||
|
||||
|
|
@ -66,7 +66,13 @@ export default function ExportModel({ open, onOpenChange }) {
|
|||
|
||||
// return an object or an array based on branches and recursive option
|
||||
// messageId is used to get siblindIdx from recoil snapshot
|
||||
const buildMessageTree = async ({ messageId, message, messages, branches = false, recursive = false }) => {
|
||||
const buildMessageTree = async ({
|
||||
messageId,
|
||||
message,
|
||||
messages,
|
||||
branches = false,
|
||||
recursive = false
|
||||
}) => {
|
||||
let children = [];
|
||||
if (messages?.length)
|
||||
if (branches)
|
||||
|
|
@ -137,21 +143,39 @@ export default function ExportModel({ open, onOpenChange }) {
|
|||
extension: 'csv',
|
||||
exportType: exportFromJSON.types.csv,
|
||||
beforeTableEncode: entries => [
|
||||
{ fieldName: 'sender', fieldValues: entries.find(e => e.fieldName == 'sender').fieldValues },
|
||||
{
|
||||
fieldName: 'sender',
|
||||
fieldValues: entries.find(e => e.fieldName == 'sender').fieldValues
|
||||
},
|
||||
{ fieldName: 'text', fieldValues: entries.find(e => e.fieldName == 'text').fieldValues },
|
||||
{
|
||||
fieldName: 'isCreatedByUser',
|
||||
fieldValues: entries.find(e => e.fieldName == 'isCreatedByUser').fieldValues
|
||||
},
|
||||
{ fieldName: 'error', fieldValues: entries.find(e => e.fieldName == 'error').fieldValues },
|
||||
{ fieldName: 'unfinished', fieldValues: entries.find(e => e.fieldName == 'unfinished').fieldValues },
|
||||
{ fieldName: 'cancelled', fieldValues: entries.find(e => e.fieldName == 'cancelled').fieldValues },
|
||||
{ fieldName: 'messageId', fieldValues: entries.find(e => e.fieldName == 'messageId').fieldValues },
|
||||
{
|
||||
fieldName: 'error',
|
||||
fieldValues: entries.find(e => e.fieldName == 'error').fieldValues
|
||||
},
|
||||
{
|
||||
fieldName: 'unfinished',
|
||||
fieldValues: entries.find(e => e.fieldName == 'unfinished').fieldValues
|
||||
},
|
||||
{
|
||||
fieldName: 'cancelled',
|
||||
fieldValues: entries.find(e => e.fieldName == 'cancelled').fieldValues
|
||||
},
|
||||
{
|
||||
fieldName: 'messageId',
|
||||
fieldValues: entries.find(e => e.fieldName == 'messageId').fieldValues
|
||||
},
|
||||
{
|
||||
fieldName: 'parentMessageId',
|
||||
fieldValues: entries.find(e => e.fieldName == 'parentMessageId').fieldValues
|
||||
},
|
||||
{ fieldName: 'createdAt', fieldValues: entries.find(e => e.fieldName == 'createdAt').fieldValues }
|
||||
{
|
||||
fieldName: 'createdAt',
|
||||
fieldValues: entries.find(e => e.fieldName == 'createdAt').fieldValues
|
||||
}
|
||||
]
|
||||
});
|
||||
};
|
||||
|
|
@ -284,10 +308,7 @@ export default function ExportModel({ open, onOpenChange }) {
|
|||
'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';
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
open={open}
|
||||
onOpenChange={onOpenChange}
|
||||
>
|
||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||
<DialogTemplate
|
||||
title="Export conversation"
|
||||
className="max-w-full sm:max-w-2xl"
|
||||
|
|
@ -295,10 +316,7 @@ export default function ExportModel({ open, onOpenChange }) {
|
|||
<div className="flex w-full flex-col items-center gap-6">
|
||||
<div className="grid w-full gap-6 sm:grid-cols-2">
|
||||
<div className="col-span-1 flex flex-col items-start justify-start gap-2">
|
||||
<Label
|
||||
htmlFor="filename"
|
||||
className="text-left text-sm font-medium"
|
||||
>
|
||||
<Label htmlFor="filename" className="text-left text-sm font-medium">
|
||||
Filename
|
||||
</Label>
|
||||
<Input
|
||||
|
|
@ -313,10 +331,7 @@ export default function ExportModel({ open, onOpenChange }) {
|
|||
/>
|
||||
</div>
|
||||
<div className="col-span-1 flex flex-col items-start justify-start gap-2">
|
||||
<Label
|
||||
htmlFor="type"
|
||||
className="text-left text-sm font-medium"
|
||||
>
|
||||
<Label htmlFor="type" className="text-left text-sm font-medium">
|
||||
Type
|
||||
</Label>
|
||||
<Dropdown
|
||||
|
|
@ -335,10 +350,7 @@ export default function ExportModel({ open, onOpenChange }) {
|
|||
<div className="grid w-full gap-6 sm:grid-cols-2">
|
||||
<div className="col-span-1 flex flex-col items-start justify-start gap-2">
|
||||
<div className="grid w-full items-center gap-2">
|
||||
<Label
|
||||
htmlFor="includeOptions"
|
||||
className="text-left text-sm font-medium"
|
||||
>
|
||||
<Label htmlFor="includeOptions" className="text-left text-sm font-medium">
|
||||
Include endpoint options
|
||||
</Label>
|
||||
<div className="flex h-[40px] w-full items-center space-x-3">
|
||||
|
|
@ -359,10 +371,7 @@ export default function ExportModel({ open, onOpenChange }) {
|
|||
</div>
|
||||
</div>
|
||||
<div className="grid w-full items-center gap-2">
|
||||
<Label
|
||||
htmlFor="exportBranches"
|
||||
className="text-left text-sm font-medium"
|
||||
>
|
||||
<Label htmlFor="exportBranches" className="text-left text-sm font-medium">
|
||||
Export all message branches
|
||||
</Label>
|
||||
<div className="flex h-[40px] w-full items-center space-x-3">
|
||||
|
|
@ -383,10 +392,7 @@ export default function ExportModel({ open, onOpenChange }) {
|
|||
</div>
|
||||
{type === 'json' ? (
|
||||
<div className="grid w-full items-center gap-2">
|
||||
<Label
|
||||
htmlFor="recursive"
|
||||
className="text-left text-sm font-medium"
|
||||
>
|
||||
<Label htmlFor="recursive" className="text-left text-sm font-medium">
|
||||
Recursive or sequential?
|
||||
</Label>
|
||||
<div className="flex h-[40px] w-full items-center space-x-3">
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ export default function ExportConversation() {
|
|||
<>
|
||||
<button
|
||||
className={cn(
|
||||
'flex py-3 px-3 items-center gap-3 transition-colors duration-200 text-white cursor-pointer text-sm hover:bg-gray-700 w-full',
|
||||
'flex w-full cursor-pointer items-center gap-3 px-3 py-3 text-sm text-white transition-colors duration-200 hover:bg-gray-700',
|
||||
exportable ? 'cursor-pointer text-white' : 'cursor-not-allowed text-gray-400'
|
||||
)}
|
||||
onClick={clickHandler}
|
||||
|
|
@ -34,10 +34,7 @@ export default function ExportConversation() {
|
|||
Export conversation
|
||||
</button>
|
||||
|
||||
<ExportModel
|
||||
open={open}
|
||||
onOpenChange={setOpen}
|
||||
/>
|
||||
<ExportModel open={open} onOpenChange={setOpen} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,13 +6,13 @@ export default function Logout() {
|
|||
const { user, logout } = useAuthContext();
|
||||
|
||||
const handleLogout = () => {
|
||||
logout()
|
||||
logout();
|
||||
window.location.reload();
|
||||
};
|
||||
|
||||
return (
|
||||
<button
|
||||
className="flex py-3 px-3 items-center gap-3 transition-colors duration-200 text-white cursor-pointer text-sm hover:bg-gray-700 w-full"
|
||||
className="flex w-full cursor-pointer items-center gap-3 px-3 py-3 text-sm text-white transition-colors duration-200 hover:bg-gray-700"
|
||||
onClick={handleLogout}
|
||||
>
|
||||
<LogOutIcon />
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ export default function MobileNav({ setNavVisible }) {
|
|||
const { title = 'New Chat' } = conversation || {};
|
||||
|
||||
return (
|
||||
<div className="fixed top-0 left-0 right-0 z-10 flex items-center border-b border-white/20 bg-gray-800 pl-1 pt-1 text-gray-200 sm:pl-3 md:hidden">
|
||||
<div className="fixed left-0 right-0 top-0 z-10 flex items-center border-b border-white/20 bg-gray-800 pl-1 pt-1 text-gray-200 sm:pl-3 md:hidden">
|
||||
<button
|
||||
type="button"
|
||||
className="-ml-0.5 -mt-0.5 inline-flex h-10 w-10 items-center justify-center rounded-md hover:text-gray-900 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-white dark:hover:text-white"
|
||||
|
|
@ -28,32 +28,13 @@ export default function MobileNav({ setNavVisible }) {
|
|||
width="1em"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<line
|
||||
x1="3"
|
||||
y1="12"
|
||||
x2="21"
|
||||
y2="12"
|
||||
/>
|
||||
<line
|
||||
x1="3"
|
||||
y1="6"
|
||||
x2="21"
|
||||
y2="6"
|
||||
/>
|
||||
<line
|
||||
x1="3"
|
||||
y1="18"
|
||||
x2="21"
|
||||
y2="18"
|
||||
/>
|
||||
<line x1="3" y1="12" x2="21" y2="12" />
|
||||
<line x1="3" y1="6" x2="21" y2="6" />
|
||||
<line x1="3" y1="18" x2="21" y2="18" />
|
||||
</svg>
|
||||
</button>
|
||||
<h1 className="flex-1 text-center text-base font-normal">{title || 'New Chat'}</h1>
|
||||
<button
|
||||
type="button"
|
||||
className="px-3"
|
||||
onClick={() => newConversation()}
|
||||
>
|
||||
<button type="button" className="px-3" onClick={() => newConversation()}>
|
||||
<svg
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
|
|
@ -66,18 +47,8 @@ export default function MobileNav({ setNavVisible }) {
|
|||
width="1em"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<line
|
||||
x1="12"
|
||||
y1="5"
|
||||
x2="12"
|
||||
y2="19"
|
||||
/>
|
||||
<line
|
||||
x1="5"
|
||||
y1="12"
|
||||
x2="19"
|
||||
y2="12"
|
||||
/>
|
||||
<line x1="12" y1="5" x2="12" y2="19" />
|
||||
<line x1="5" y1="12" x2="19" y2="12" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -12,10 +12,7 @@ import DotsIcon from '../svg/DotsIcon';
|
|||
export default function NavLinks({ clearSearch, isSearchEnabled }) {
|
||||
const { user, logout } = useAuthContext();
|
||||
return (
|
||||
<Menu
|
||||
as="div"
|
||||
className="group relative"
|
||||
>
|
||||
<Menu as="div" className="group relative">
|
||||
{({ open }) => (
|
||||
<>
|
||||
<Menu.Button
|
||||
|
|
@ -28,7 +25,9 @@ export default function NavLinks({ clearSearch, isSearchEnabled }) {
|
|||
<div className="relative flex">
|
||||
<img
|
||||
className="rounded-sm"
|
||||
src={user?.avatar || `https://avatars.dicebear.com/api/initials/${user?.name}.svg`}
|
||||
src={
|
||||
user?.avatar || `https://avatars.dicebear.com/api/initials/${user?.name}.svg`
|
||||
}
|
||||
alt=""
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -54,17 +53,11 @@ export default function NavLinks({ clearSearch, isSearchEnabled }) {
|
|||
</Menu.Item>
|
||||
<Menu.Item>{({}) => <ExportConversation />}</Menu.Item>
|
||||
|
||||
<div
|
||||
className="my-1.5 h-px bg-white/20"
|
||||
role="none"
|
||||
></div>
|
||||
<div className="my-1.5 h-px bg-white/20" role="none"></div>
|
||||
<Menu.Item>{({}) => <DarkMode />}</Menu.Item>
|
||||
<Menu.Item>{({}) => <ClearConvos />}</Menu.Item>
|
||||
|
||||
<div
|
||||
className="my-1.5 h-px bg-white/20"
|
||||
role="none"
|
||||
></div>
|
||||
<div className="my-1.5 h-px bg-white/20" role="none"></div>
|
||||
<Menu.Item>
|
||||
<Logout />
|
||||
</Menu.Item>
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ export default function NewChat() {
|
|||
return (
|
||||
<a
|
||||
onClick={clickHandler}
|
||||
className="mb-2 flex flex-shrink-0 cursor-pointer items-center gap-3 rounded-md border border-white/20 py-3 px-3 text-sm text-white transition-colors duration-200 hover:bg-gray-500/10"
|
||||
className="mb-2 flex flex-shrink-0 cursor-pointer items-center gap-3 rounded-md border border-white/20 px-3 py-3 text-sm text-white transition-colors duration-200 hover:bg-gray-500/10"
|
||||
>
|
||||
<svg
|
||||
stroke="currentColor"
|
||||
|
|
@ -27,18 +27,8 @@ export default function NewChat() {
|
|||
width="1em"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<line
|
||||
x1="12"
|
||||
y1="5"
|
||||
x2="12"
|
||||
y2="19"
|
||||
/>
|
||||
<line
|
||||
x1="5"
|
||||
y1="12"
|
||||
x2="19"
|
||||
y2="12"
|
||||
/>
|
||||
<line x1="12" y1="5" x2="12" y2="19" />
|
||||
<line x1="5" y1="12" x2="19" y2="12" />
|
||||
</svg>
|
||||
New chat
|
||||
</a>
|
||||
|
|
|
|||
|
|
@ -3,10 +3,9 @@ import { useRecoilState } from 'recoil';
|
|||
import store from '~/store';
|
||||
|
||||
export default function SearchBar({ clearSearch }) {
|
||||
|
||||
const [searchQuery, setSearchQuery] = useRecoilState(store.searchQuery);
|
||||
|
||||
const handleKeyUp = e => {
|
||||
const handleKeyUp = (e) => {
|
||||
const { value } = e.target;
|
||||
if (e.keyCode === 8 && value === '') {
|
||||
setSearchQuery('');
|
||||
|
|
@ -15,7 +14,7 @@ export default function SearchBar({ clearSearch }) {
|
|||
};
|
||||
|
||||
return (
|
||||
<div className="flex cursor-pointer items-center gap-3 rounded-md py-3 px-3 text-sm text-white transition-colors duration-200 hover:bg-gray-500/10">
|
||||
<div className="flex cursor-pointer items-center gap-3 rounded-md px-3 py-3 text-sm text-white transition-colors duration-200 hover:bg-gray-500/10">
|
||||
{<Search className="h-4 w-4" />}
|
||||
<input
|
||||
type="text"
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@ export default function Nav({ navVisible, setNavVisible }) {
|
|||
const [pageNumber, setPageNumber] = useState(1);
|
||||
// total pages
|
||||
const [pages, setPages] = useState(1);
|
||||
|
||||
// data provider
|
||||
|
||||
// data provider
|
||||
const getConversationsQuery = useGetConversationsQuery(pageNumber, { enabled: isAuthenticated });
|
||||
|
||||
// search
|
||||
|
|
@ -41,11 +41,9 @@ export default function Nav({ navVisible, setNavVisible }) {
|
|||
const [isFetching, setIsFetching] = useState(false);
|
||||
|
||||
const debouncedSearchTerm = useDebounce(searchQuery, 750);
|
||||
const searchQueryFn = useSearchQuery(debouncedSearchTerm, pageNumber, {
|
||||
enabled: !!debouncedSearchTerm &&
|
||||
debouncedSearchTerm.length > 0 &&
|
||||
isSearchEnabled &&
|
||||
isSearching,
|
||||
const searchQueryFn = useSearchQuery(debouncedSearchTerm, pageNumber, {
|
||||
enabled:
|
||||
!!debouncedSearchTerm && debouncedSearchTerm.length > 0 && isSearchEnabled && isSearching
|
||||
});
|
||||
|
||||
const onSearchSuccess = (data, expectedPage) => {
|
||||
|
|
@ -64,11 +62,10 @@ export default function Nav({ navVisible, setNavVisible }) {
|
|||
//we use isInitialLoading here instead of isLoading because query is disabled by default
|
||||
if (searchQueryFn.isInitialLoading) {
|
||||
setIsFetching(true);
|
||||
}
|
||||
else if (searchQueryFn.data) {
|
||||
} else if (searchQueryFn.data) {
|
||||
onSearchSuccess(searchQueryFn.data);
|
||||
}
|
||||
}, [searchQueryFn.data, searchQueryFn.isInitialLoading])
|
||||
}, [searchQueryFn.data, searchQueryFn.isInitialLoading]);
|
||||
|
||||
const clearSearch = () => {
|
||||
setPageNumber(1);
|
||||
|
|
@ -98,7 +95,9 @@ export default function Nav({ navVisible, setNavVisible }) {
|
|||
setPageNumber(pages);
|
||||
} else {
|
||||
if (!isSearching) {
|
||||
conversations = conversations.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt));
|
||||
conversations = conversations.sort(
|
||||
(a, b) => new Date(b.createdAt) - new Date(a.createdAt)
|
||||
);
|
||||
}
|
||||
setConversations(conversations);
|
||||
setPages(pages);
|
||||
|
|
@ -119,7 +118,6 @@ export default function Nav({ navVisible, setNavVisible }) {
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
const toggleNavVisible = () => {
|
||||
setNavVisible(prev => !prev);
|
||||
};
|
||||
|
|
@ -142,8 +140,8 @@ export default function Nav({ navVisible, setNavVisible }) {
|
|||
}
|
||||
>
|
||||
<div className="flex h-full min-h-0 flex-col ">
|
||||
<div className="scrollbar-trigger flex h-full w-full flex-1 items-start border-white/20 relative">
|
||||
<nav className="flex h-full flex-1 flex-col space-y-1 p-2 relative">
|
||||
<div className="scrollbar-trigger relative flex h-full w-full flex-1 items-start border-white/20">
|
||||
<nav className="relative flex h-full flex-1 flex-col space-y-1 p-2">
|
||||
<NewChat />
|
||||
<div
|
||||
className={`flex-1 flex-col overflow-y-auto ${
|
||||
|
|
@ -171,10 +169,7 @@ export default function Nav({ navVisible, setNavVisible }) {
|
|||
/>
|
||||
</div>
|
||||
</div>
|
||||
<NavLinks
|
||||
clearSearch={clearSearch}
|
||||
isSearchEnabled={isSearchEnabled}
|
||||
/>
|
||||
<NavLinks clearSearch={clearSearch} isSearchEnabled={isSearchEnabled} />
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -196,25 +191,12 @@ export default function Nav({ navVisible, setNavVisible }) {
|
|||
width="1em"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<line
|
||||
x1="3"
|
||||
y1="6"
|
||||
x2="15"
|
||||
y2="18"
|
||||
/>
|
||||
<line
|
||||
x1="3"
|
||||
y1="18"
|
||||
x2="15"
|
||||
y2="6"
|
||||
/>
|
||||
<line x1="3" y1="6" x2="15" y2="18" />
|
||||
<line x1="3" y1="18" x2="15" y2="6" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
className={'nav-mask' + (navVisible ? ' active' : '')}
|
||||
onClick={toggleNavVisible}
|
||||
></div>
|
||||
<div className={'nav-mask' + (navVisible ? ' active' : '')} onClick={toggleNavVisible}></div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue