Skip to content

Commit 7f29f2f

Browse files
🎨 feat: UI Refresh for Enhanced UX (#6346)
* ✨ feat: Add Expand Chat functionality and improve UI components * ✨ feat: Introduce Chat Badges feature with editing capabilities and UI enhancements * ✨ feat: re-implement file attachment functionality with new components and improved UI * ✨ feat: Enhance BadgeRow component with drag-and-drop functionality and add animations for better user experience * ✨ feat: Add useChatBadges hook and enhance Badge component with animations and toggle functionality * feat: Improve Add/Delete Badges + style and bug fixes * ✨ feat: Refactor EditBadges component and optimize useChatBadges hook for improved performance and readability * ✨ feat: Add type definition for LucideIcon in EditBadges component * refactor: Clean up BadgeRow component by removing outdated comment and improving code readability * refactor: Rename app-icon class to badge-icon for consistency and improve badge styling * feat: Add Center Chat Input toggle and update related components for improved UI/UX * refactor: Simplify ChatView and MessagesView components for improved readability and performance * refactor: Improve layout and positioning of scroll button in MessagesView component * refactor: Adjust scroll button position in MessagesView component for better visibility * refactor: Remove redundant background class from Badge component for cleaner styling * feat: disable chat badges * refactor: adjust positioning of scroll button and popover for improved layout * refactor: simplify class names in ChatForm and RemoveFile components for cleaner code * refactor: move Switcher to HeaderOptions from SidePanel * fix(Landing): duplicate description * feat: add SplitText component for animated text display and update Landing component to use it * feat(Chat): add ConversationStarters component and integrate it into ChatView; remove ConvoStarter component * feat(Chat): enhance Message component layout and styling for improved readability * feat(ControlCombobox, Select): enhance styling and add animation for improved UI experience * feat(Chat): update Header and HeaderNewChat components for improved layout and styling * feat(Chat): add ModelDropdown (now includes both endpoint and model) and refactor Menu components for improved UI * feat(ModelDropdown): add Agent Select; removed old AgentSwitcher components * feat(ModelDropdown): add settings button for user key configuration * fix(ModelDropdown): the model dropdown wasn't opening automatically when opening the endpoint one * refactor(Chat): remove unused EndpointsMenu and related components to streamline codebase * feat: enhance greeting message and improve accessibility fro ModelDropdown * refactor(Endpoints): add new hooks and components for endpoint management * feat(Endpoint): add support for modelSpecs * feat(Endpoints): add mobile support * fix: type issues * fix(modelSpec): type issue * fix(EndpointMenuDropdown): double overflow scroller in mobile model list * fix: search model on mobile * refactor: Endpoint/Model/modelSpec dropdown * refactor: reorganize imports in Endpoint components * refactor: remove unused translation keys from English locale * BREAKING: moving to ariakit with new CustomMenu * refactor: remove unnecessary comments * refactor: remove EndpointItem, ModelDropdownButton, SpecIcon, and SpecItem components * 🔧 fix: AI Icon bump when regenerating message * wip: chat UI refactoring, fix issues * chore: add recent update to useAutoSave * feat: add access control for agent permissions in useMentions hook * refactor: streamline ModelSelector by removing unused endpoints logic * refactor: enhance ModelSelector and context by integrating endpointsConfig and improving type usage * feat: update ModelSelectorContext to utilize conversation data for initial state * feat: add selector effects for synced endpoint handling * feat: add guard clause for conversation endpoint in useSelectorEffects hook * fix: safely call onSelectMention and add autofocus to mention input * chore: typing * refactor: ModelSelector to streamline key dialog handling and improve endpoint rendering * refactor: extract SettingsButton component for cleaner endpoint item rendering * wip: first pass, expand set api key * wip: first pass, expanding set key * refactor: update EndpointItem styles for improved layout and hover effects * refactor: adjust padding in EndpointItem for improved layout consistency * refactor: update preset structure in useSelectMention to include spec as null * refactor: rename setKeyDialogOpen to onOpenChange for clarity and consistency, bring focus back to button that opened dialog * feat: add SpecIcon component for dynamic model spec icons in menu, adjust icon styling * refactor: update getSelectedIcon to accept additional parameters and improve icon rendering logic * fix: adjust padding in MessageRender for improved layout * refactor: remove inline style for menu width in CustomMenu component * refactor: enhance layout and styling in ModelSpecItem component for better responsiveness * refactor: update getDefaultModelSpec to accept startupConfig and improve model spec retrieval logic * refactor: improve key management and default values in ModelSelector and related components * refactor: adjust menu width and improve responsiveness in CustomMenu and EndpointItem components * refactor: enhance focus styles and responsiveness in EndpointItem component * refactor: improve layout and spacing in Header and ModelSelector components for better responsiveness * refactor: adjust button styles for consistency and improved layout in AddMultiConvo and PresetsMenu components * fix: initial fix of assistant names * fix: assistants handling * chore: update version of librechat-data-provider to 0.7.75 and add 'spec' to excludedKeys * fix: improve endpoint filtering logic based on interface configuration and access rights * fix: remove unused HeaderOptions import and set spec to null in presets and mentions * fix: ensure currentExample is always an object when updating examples * fix: update interfaceConfig checks to ensure modelSelect is considered for rendering components * fix: update model selection logic to consider interface configuration when prioritizing model specs * fix: add missing localizations * fix: remove unused agent and assistant selection translations * fix: implement debounced state updates for selected values in useSelectorEffects * style: minor style changes related to the ModelSelector * fix: adjust maximum height for popover and set fixed height for model item * fix: update placeholders for model and endpoint search inputs * fix: refactor MessageRender and ContentRender components to better match each other * fix: remove convo fallback for iconURL in MessageRender and ContentRender components * fix: update handling of spec, iconURL, and modelLabel in conversation presets, to allow better interchangeability * fix: replace chatGptLabel with modelLabel in OpenAI settings configuration (fully deprecate chatGptLabel) * fix: remove console log for assistantNames in useEndpoints hook * refactor: add cleanInput and cleanOutput options to default conversation handling * chore: update bun.lockb * fix: set default value for showIconInHeader in getSelectedIcon function * refactor: enhance error handling in message processing when latest message has existing content blocks * chore: allow import/no-cycle for messages * fix: adjust flex properties in BookmarkMenu for better layout * feat: support both 'prompt' and 'q' as query parameters in useQueryParams hook * feat: re-enable Badges components * refactor: disable edit badge component * chore: rename assistantMap to assistantsMap for consistency * chore: rename assistantMap to assistantsMap for consistency in Mention component * feat: set staleTime for various queries to improve data freshness * feat: add spec field to tQueryParamsSchema for model specification * feat: enhance useQueryParams to handle model specs --------- Co-authored-by: Danny Avila <[email protected]>
1 parent c4fea9c commit 7f29f2f

File tree

127 files changed

+4489
-2145
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

127 files changed

+4489
-2145
lines changed

‎api/app/clients/BaseClient.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -879,13 +879,14 @@ class BaseClient {
879879
: await getConvo(this.options.req?.user?.id, message.conversationId);
880880

881881
const unsetFields = {};
882+
const exceptions = new Set(['spec', 'iconURL']);
882883
if (existingConvo != null) {
883884
this.fetchedConvo = true;
884885
for (const key in existingConvo) {
885886
if (!key) {
886887
continue;
887888
}
888-
if (excludedKeys.has(key)) {
889+
if (excludedKeys.has(key) && !exceptions.has(key)) {
889890
continue;
890891
}
891892

‎bun.lockb

145 KB
Binary file not shown.

‎client/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
"@radix-ui/react-switch": "^1.0.3",
5353
"@radix-ui/react-tabs": "^1.0.3",
5454
"@radix-ui/react-toast": "^1.1.5",
55+
"@react-spring/web": "^9.7.5",
5556
"@tanstack/react-query": "^4.28.0",
5657
"@tanstack/react-table": "^8.11.7",
5758
"class-variance-authority": "^0.6.0",
@@ -141,8 +142,8 @@
141142
"ts-jest": "^29.2.5",
142143
"typescript": "^5.3.3",
143144
"vite": "^6.1.0",
144-
"vite-plugin-node-polyfills": "^0.17.0",
145145
"vite-plugin-compression": "^0.5.1",
146+
"vite-plugin-node-polyfills": "^0.17.0",
146147
"vite-plugin-pwa": "^0.21.1"
147148
}
148149
}

‎client/src/common/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@ export * from './artifacts';
33
export * from './types';
44
export * from './menus';
55
export * from './tools';
6+
export * from './selector';
67
export * from './assistants-types';
78
export * from './agents-types';

‎client/src/common/selector.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import React from 'react';
2+
import { TModelSpec, TInterfaceConfig } from 'librechat-data-provider';
3+
4+
export interface Endpoint {
5+
value: string;
6+
label: string;
7+
hasModels: boolean;
8+
models?: string[];
9+
icon: React.ReactNode;
10+
agentNames?: Record<string, string>;
11+
assistantNames?: Record<string, string>;
12+
modelIcons?: Record<string, string | undefined>;
13+
}
14+
15+
export interface SelectedValues {
16+
endpoint: string | null;
17+
model: string | null;
18+
modelSpec: string | null;
19+
}
20+
21+
export interface ModelSelectorProps {
22+
interfaceConfig: TInterfaceConfig;
23+
modelSpecs: TModelSpec[];
24+
}

‎client/src/common/types.ts

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { RefObject } from 'react';
2-
import { FileSources } from 'librechat-data-provider';
2+
import { FileSources, EModelEndpoint } from 'librechat-data-provider';
3+
import type { UseMutationResult } from '@tanstack/react-query';
34
import type * as InputNumberPrimitive from 'rc-input-number';
5+
import type { SetterOrUpdater, RecoilState } from 'recoil';
46
import type { ColumnDef } from '@tanstack/react-table';
5-
import type { SetterOrUpdater } from 'recoil';
67
import type * as t from 'librechat-data-provider';
7-
import type { UseMutationResult } from '@tanstack/react-query';
88
import type { LucideIcon } from 'lucide-react';
99
import type { TranslationKeys } from '~/hooks';
1010

@@ -48,6 +48,14 @@ export type AudioChunk = {
4848
};
4949
};
5050

51+
export type BadgeItem = {
52+
id: string;
53+
icon: React.ComponentType<any>;
54+
label: string;
55+
atom: RecoilState<boolean>;
56+
isAvailable: boolean;
57+
};
58+
5159
export type AssistantListItem = {
5260
id: string;
5361
name: string;
@@ -488,6 +496,27 @@ export interface ExtendedFile {
488496
metadata?: t.TFile['metadata'];
489497
}
490498

499+
export interface ExtendedEndpoint {
500+
value: EModelEndpoint;
501+
label: string;
502+
hasModels: boolean;
503+
icon: JSX.Element | null;
504+
models?: string[];
505+
agentNames?: Record<string, string>;
506+
assistantNames?: Record<string, string>;
507+
modelIcons?: Record<string, string | undefined>;
508+
}
509+
510+
export interface ModelItemProps {
511+
modelName: string;
512+
endpoint: EModelEndpoint;
513+
isSelected: boolean;
514+
onSelect: () => void;
515+
onNavigateBack: () => void;
516+
icon?: JSX.Element;
517+
className?: string;
518+
}
519+
491520
export type ContextType = { navVisible: boolean; setNavVisible: (visible: boolean) => void };
492521

493522
export interface SwitcherProps {

‎client/src/components/Chat/AddMultiConvo.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ function AddMultiConvo() {
1212
const localize = useLocalize();
1313

1414
const clickHandler = () => {
15-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
15+
1616
const { title: _t, ...convo } = conversation ?? ({} as TConversation);
1717
setAddedConvo({
1818
...convo,
@@ -42,7 +42,7 @@ function AddMultiConvo() {
4242
role="button"
4343
onClick={clickHandler}
4444
data-testid="parameters-button"
45-
className="inline-flex size-10 items-center justify-center rounded-lg border border-border-light bg-transparent text-text-primary transition-all ease-in-out hover:bg-surface-tertiary disabled:pointer-events-none disabled:opacity-50 radix-state-open:bg-surface-tertiary"
45+
className="inline-flex size-10 flex-shrink-0 items-center justify-center rounded-lg border border-border-light bg-transparent text-text-primary transition-all ease-in-out hover:bg-surface-tertiary disabled:pointer-events-none disabled:opacity-50 radix-state-open:bg-surface-tertiary"
4646
>
4747
<PlusCircle size={16} aria-label="Plus Icon" />
4848
</TooltipAnchor>

‎client/src/components/Chat/ChatView.tsx

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import type { TMessage } from 'librechat-data-provider';
77
import type { ChatFormValues } from '~/common';
88
import { ChatContext, AddedChatContext, useFileMapContext, ChatFormProvider } from '~/Providers';
99
import { useChatHelpers, useAddedResponse, useSSE } from '~/hooks';
10+
import ConversationStarters from './Input/ConversationStarters';
1011
import MessagesView from './Messages/MessagesView';
1112
import { Spinner } from '~/components/svg';
1213
import Presentation from './Presentation';
@@ -21,6 +22,7 @@ function ChatView({ index = 0 }: { index?: number }) {
2122
const { conversationId } = useParams();
2223
const rootSubmission = useRecoilValue(store.submissionByIndex(index));
2324
const addedSubmission = useRecoilValue(store.submissionByIndex(index + 1));
25+
const centerFormOnLanding = useRecoilValue(store.centerFormOnLanding);
2426

2527
const fileMap = useFileMapContext();
2628

@@ -46,27 +48,46 @@ function ChatView({ index = 0 }: { index?: number }) {
4648
});
4749

4850
let content: JSX.Element | null | undefined;
51+
const isLandingPage = !messagesTree || messagesTree.length === 0;
52+
4953
if (isLoading && conversationId !== 'new') {
5054
content = (
5155
<div className="flex h-screen items-center justify-center">
52-
<Spinner className="opacity-0" />
56+
<Spinner className="text-text-primary" />
5357
</div>
5458
);
55-
} else if (messagesTree && messagesTree.length !== 0) {
56-
content = <MessagesView messagesTree={messagesTree} Header={<Header />} />;
59+
} else if (!isLandingPage) {
60+
content = <MessagesView messagesTree={messagesTree} />;
5761
} else {
58-
content = <Landing Header={<Header />} />;
62+
content = <Landing centerFormOnLanding={centerFormOnLanding} />;
5963
}
6064

6165
return (
6266
<ChatFormProvider {...methods}>
6367
<ChatContext.Provider value={chatHelpers}>
6468
<AddedChatContext.Provider value={addedChatHelpers}>
6569
<Presentation>
66-
{content}
67-
<div className="w-full border-t-0 pl-0 pt-2 dark:border-white/20 md:w-[calc(100%-.5rem)] md:border-t-0 md:border-transparent md:pl-0 md:pt-0 md:dark:border-transparent">
68-
<ChatForm index={index} />
69-
<Footer />
70+
<div className="flex h-full w-full flex-col">
71+
{!isLoading && <Header />}
72+
73+
{isLandingPage ? (
74+
<div className="flex flex-1 flex-col items-center justify-end sm:justify-center">
75+
{content}
76+
<div className="w-full max-w-3xl transition-all duration-200 xl:max-w-4xl">
77+
<ChatForm index={index} />
78+
<ConversationStarters />
79+
<Footer />
80+
</div>
81+
</div>
82+
) : (
83+
<div className="flex h-full flex-col overflow-y-auto">
84+
{content}
85+
<div className="w-full">
86+
<ChatForm index={index} />
87+
<Footer />
88+
</div>
89+
</div>
90+
)}
7091
</div>
7192
</Presentation>
7293
</AddedChatContext.Provider>

‎client/src/components/Chat/ConvoStarter.tsx

Lines changed: 0 additions & 17 deletions
This file was deleted.

‎client/src/components/Chat/Footer.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ export default function Footer({ className }: { className?: string }) {
5656
<React.Fragment key={`main-content-part-${index}`}>
5757
<ReactMarkdown
5858
components={{
59-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
59+
6060
a: ({ node: _n, href, children, ...otherProps }) => {
6161
return (
6262
<a
@@ -70,7 +70,7 @@ export default function Footer({ className }: { className?: string }) {
7070
</a>
7171
);
7272
},
73-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
73+
7474
p: ({ node: _n, ...props }) => <span {...props} />,
7575
}}
7676
>
@@ -87,7 +87,7 @@ export default function Footer({ className }: { className?: string }) {
8787
<div
8888
className={
8989
className ??
90-
'relative flex items-center justify-center gap-2 px-2 py-2 text-center text-xs text-text-primary md:px-[60px]'
90+
'relative hidden items-center justify-center gap-2 px-2 py-2 text-center text-xs text-text-primary sm:flex md:px-[60px]'
9191
}
9292
role="contentinfo"
9393
>

0 commit comments

Comments
 (0)