mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-20 18:30:15 +01:00
🗨️ refactor: Optimize Prompt Queries
feat: Refactor prompt and prompt group schemas; move types to separate file feat: Implement paginated access to prompt groups with filtering and public visibility refactor: Add PromptGroups context provider and integrate it into relevant components refactor: Optimize filter change handling and query invalidation in usePromptGroupsNav hook refactor: Simplify context usage in FilterPrompts and GroupSidePanel components
This commit is contained in:
parent
53c31b85d0
commit
dcd96c29c5
22 changed files with 583 additions and 259 deletions
|
|
@ -1,25 +1,21 @@
|
|||
import React, { useState, useCallback, useMemo, useEffect } from 'react';
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { ListFilter, User, Share2 } from 'lucide-react';
|
||||
import { SystemCategories } from 'librechat-data-provider';
|
||||
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
||||
import { Dropdown, AnimatedSearchInput } from '@librechat/client';
|
||||
import type { Option } from '~/common';
|
||||
import { usePromptGroupsNav, useLocalize, useCategories } from '~/hooks';
|
||||
import { useLocalize, useCategories } from '~/hooks';
|
||||
import { usePromptGroupsContext } from '~/Providers';
|
||||
import { cn } from '~/utils';
|
||||
import store from '~/store';
|
||||
|
||||
export default function FilterPrompts({
|
||||
setName,
|
||||
className = '',
|
||||
}: Pick<ReturnType<typeof usePromptGroupsNav>, 'setName'> & {
|
||||
className?: string;
|
||||
}) {
|
||||
export default function FilterPrompts({ className = '' }: { className?: string }) {
|
||||
const localize = useLocalize();
|
||||
const [displayName, setDisplayName] = useState('');
|
||||
const setCategory = useSetRecoilState(store.promptsCategory);
|
||||
const categoryFilter = useRecoilValue(store.promptsCategory);
|
||||
const { setName } = usePromptGroupsContext();
|
||||
const { categories } = useCategories('h-4 w-4');
|
||||
const [displayName, setDisplayName] = useState('');
|
||||
const [isSearching, setIsSearching] = useState(false);
|
||||
const [categoryFilter, setCategory] = useRecoilState(store.promptsCategory);
|
||||
|
||||
const filterOptions = useMemo(() => {
|
||||
const baseOptions: Option[] = [
|
||||
|
|
|
|||
|
|
@ -3,30 +3,31 @@ import { useLocation } from 'react-router-dom';
|
|||
import { useMediaQuery } from '@librechat/client';
|
||||
import PanelNavigation from '~/components/Prompts/Groups/PanelNavigation';
|
||||
import ManagePrompts from '~/components/Prompts/ManagePrompts';
|
||||
import { usePromptGroupsContext } from '~/Providers';
|
||||
import List from '~/components/Prompts/Groups/List';
|
||||
import { usePromptGroupsNav } from '~/hooks';
|
||||
import { cn } from '~/utils';
|
||||
|
||||
export default function GroupSidePanel({
|
||||
children,
|
||||
isDetailView,
|
||||
className = '',
|
||||
/* usePromptGroupsNav */
|
||||
nextPage,
|
||||
prevPage,
|
||||
isFetching,
|
||||
hasNextPage,
|
||||
groupsQuery,
|
||||
promptGroups,
|
||||
hasPreviousPage,
|
||||
}: {
|
||||
children?: React.ReactNode;
|
||||
isDetailView?: boolean;
|
||||
className?: string;
|
||||
} & ReturnType<typeof usePromptGroupsNav>) {
|
||||
}) {
|
||||
const location = useLocation();
|
||||
const isSmallerScreen = useMediaQuery('(max-width: 1024px)');
|
||||
const isChatRoute = useMemo(() => location.pathname?.startsWith('/c/'), [location.pathname]);
|
||||
const {
|
||||
nextPage,
|
||||
prevPage,
|
||||
isFetching,
|
||||
hasNextPage,
|
||||
groupsQuery,
|
||||
promptGroups,
|
||||
hasPreviousPage,
|
||||
} = usePromptGroupsContext();
|
||||
|
||||
return (
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -3,10 +3,15 @@ import React from 'react';
|
|||
import debounce from 'lodash/debounce';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { Menu, Rocket } from 'lucide-react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { useForm, FormProvider } from 'react-hook-form';
|
||||
import { useParams, useOutletContext } from 'react-router-dom';
|
||||
import { Button, Skeleton, useToastContext } from '@librechat/client';
|
||||
import { Permissions, PermissionTypes, PermissionBits } from 'librechat-data-provider';
|
||||
import {
|
||||
Permissions,
|
||||
ResourceType,
|
||||
PermissionBits,
|
||||
PermissionTypes,
|
||||
} from 'librechat-data-provider';
|
||||
import type { TCreatePrompt, TPrompt, TPromptGroup } from 'librechat-data-provider';
|
||||
import {
|
||||
useGetPrompts,
|
||||
|
|
@ -15,8 +20,9 @@ import {
|
|||
useUpdatePromptGroup,
|
||||
useMakePromptProduction,
|
||||
} from '~/data-provider';
|
||||
import { useResourcePermissions, usePromptGroupsNav, useHasAccess, useLocalize } from '~/hooks';
|
||||
import { useResourcePermissions, useHasAccess, useLocalize } from '~/hooks';
|
||||
import CategorySelector from './Groups/CategorySelector';
|
||||
import { usePromptGroupsContext } from '~/Providers';
|
||||
import NoPromptGroup from './Groups/NoPromptGroup';
|
||||
import PromptVariables from './PromptVariables';
|
||||
import { cn, findPromptGroup } from '~/utils';
|
||||
|
|
@ -173,16 +179,14 @@ const PromptForm = () => {
|
|||
const [showSidePanel, setShowSidePanel] = useState(false);
|
||||
const sidePanelWidth = '320px';
|
||||
|
||||
// Fetch group early so it is available for later hooks.
|
||||
const { data: group, isLoading: isLoadingGroup } = useGetPromptGroup(promptId);
|
||||
const { data: prompts = [], isLoading: isLoadingPrompts } = useGetPrompts(
|
||||
{ groupId: promptId },
|
||||
{ enabled: !!promptId },
|
||||
);
|
||||
|
||||
// Check permissions for the promptGroup
|
||||
const { hasPermission, isLoading: permissionsLoading } = useResourcePermissions(
|
||||
'promptGroup',
|
||||
ResourceType.PROMPTGROUP,
|
||||
group?._id || '',
|
||||
);
|
||||
|
||||
|
|
@ -206,7 +210,7 @@ const PromptForm = () => {
|
|||
|
||||
const selectedPromptId = useMemo(() => selectedPrompt?._id, [selectedPrompt?._id]);
|
||||
|
||||
const { groupsQuery } = useOutletContext<ReturnType<typeof usePromptGroupsNav>>();
|
||||
const { groupsQuery } = usePromptGroupsContext();
|
||||
|
||||
const updateGroupMutation = useUpdatePromptGroup({
|
||||
onError: () => {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import PromptSidePanel from '~/components/Prompts/Groups/GroupSidePanel';
|
||||
import AutoSendPrompt from '~/components/Prompts/Groups/AutoSendPrompt';
|
||||
import FilterPrompts from '~/components/Prompts/Groups/FilterPrompts';
|
||||
import { usePromptGroupsNav } from '~/hooks';
|
||||
import { usePromptGroupsContext } from '~/Providers';
|
||||
|
||||
export default function PromptsAccordion() {
|
||||
const groupsNav = usePromptGroupsNav();
|
||||
const groupsNav = usePromptGroupsContext();
|
||||
return (
|
||||
<div className="flex h-full w-full flex-col">
|
||||
<PromptSidePanel className="mt-2 space-y-2 lg:w-full xl:w-full" {...groupsNav}>
|
||||
|
|
|
|||
|
|
@ -3,14 +3,14 @@ import { Outlet, useParams, useNavigate } from 'react-router-dom';
|
|||
import { PermissionTypes, Permissions } from 'librechat-data-provider';
|
||||
import FilterPrompts from '~/components/Prompts/Groups/FilterPrompts';
|
||||
import DashBreadcrumb from '~/routes/Layouts/DashBreadcrumb';
|
||||
import { usePromptGroupsNav, useHasAccess } from '~/hooks';
|
||||
import GroupSidePanel from './Groups/GroupSidePanel';
|
||||
import { PromptGroupsProvider } from '~/Providers';
|
||||
import { useHasAccess } from '~/hooks';
|
||||
import { cn } from '~/utils';
|
||||
|
||||
export default function PromptsView() {
|
||||
const params = useParams();
|
||||
const navigate = useNavigate();
|
||||
const groupsNav = usePromptGroupsNav();
|
||||
const isDetailView = useMemo(() => !!(params.promptId || params['*'] === 'new'), [params]);
|
||||
const hasAccess = useHasAccess({
|
||||
permissionType: PermissionTypes.PROMPTS,
|
||||
|
|
@ -34,23 +34,25 @@ export default function PromptsView() {
|
|||
}
|
||||
|
||||
return (
|
||||
<div className="flex h-screen w-full flex-col bg-surface-primary p-0 lg:p-2">
|
||||
<DashBreadcrumb />
|
||||
<div className="flex w-full flex-grow flex-row divide-x overflow-hidden dark:divide-gray-600">
|
||||
<GroupSidePanel isDetailView={isDetailView} {...groupsNav}>
|
||||
<div className="mx-2 mt-1 flex flex-row items-center justify-between">
|
||||
<FilterPrompts setName={groupsNav.setName} />
|
||||
<PromptGroupsProvider>
|
||||
<div className="flex h-screen w-full flex-col bg-surface-primary p-0 lg:p-2">
|
||||
<DashBreadcrumb />
|
||||
<div className="flex w-full flex-grow flex-row divide-x overflow-hidden dark:divide-gray-600">
|
||||
<GroupSidePanel isDetailView={isDetailView}>
|
||||
<div className="mx-2 mt-1 flex flex-row items-center justify-between">
|
||||
<FilterPrompts />
|
||||
</div>
|
||||
</GroupSidePanel>
|
||||
<div
|
||||
className={cn(
|
||||
'scrollbar-gutter-stable w-full overflow-y-auto lg:w-3/4 xl:w-3/4',
|
||||
isDetailView ? 'block' : 'hidden md:block',
|
||||
)}
|
||||
>
|
||||
<Outlet />
|
||||
</div>
|
||||
</GroupSidePanel>
|
||||
<div
|
||||
className={cn(
|
||||
'scrollbar-gutter-stable w-full overflow-y-auto lg:w-3/4 xl:w-3/4',
|
||||
isDetailView ? 'block' : 'hidden md:block',
|
||||
)}
|
||||
>
|
||||
<Outlet context={groupsNav} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</PromptGroupsProvider>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue