Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge upstream into jm-production #19

Merged
merged 3 commits into from
Dec 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions api/app/clients/OpenAIClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,7 @@ class OpenAIClient extends BaseClient {
promptPrefix: this.options.promptPrefix,
resendFiles: this.options.resendFiles,
imageDetail: this.options.imageDetail,
modelLabel: this.options.modelLabel,
iconURL: this.options.iconURL,
greeting: this.options.greeting,
spec: this.options.spec,
Expand Down
1 change: 1 addition & 0 deletions api/app/clients/PluginsClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class PluginsClient extends OpenAIClient {
return {
artifacts: this.options.artifacts,
chatGptLabel: this.options.chatGptLabel,
modelLabel: this.options.modelLabel,
promptPrefix: this.options.promptPrefix,
tools: this.options.tools,
...this.modelOptions,
Expand Down
1 change: 1 addition & 0 deletions api/app/clients/specs/OpenAIClient.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,7 @@ describe('OpenAIClient', () => {
it('should return the correct save options', () => {
const options = client.getSaveOptions();
expect(options).toHaveProperty('chatGptLabel');
expect(options).toHaveProperty('modelLabel');
expect(options).toHaveProperty('promptPrefix');
});
});
Expand Down
1 change: 1 addition & 0 deletions api/models/Agent.js
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ const getListAgents = async (searchParameter) => {
avatar: 1,
author: 1,
projectIds: 1,
description: 1,
isCollaborative: 1,
}).lean()
).map((agent) => {
Expand Down
4 changes: 4 additions & 0 deletions api/server/middleware/buildEndpointOption.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ async function buildEndpointOption(req, res, next) {
}

try {
currentModelSpec.preset.spec = spec;
if (currentModelSpec.iconURL != null && currentModelSpec.iconURL !== '') {
currentModelSpec.preset.iconURL = currentModelSpec.iconURL;
}
parsedBody = parseCompactConvo({
endpoint,
endpointType,
Expand Down
2 changes: 1 addition & 1 deletion client/src/a11y/LiveAnnouncer.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// client/src/a11y/LiveAnnouncer.tsx
import React, { useState, useCallback, useRef, useEffect, useMemo } from 'react';
import type { AnnounceOptions } from '~/Providers/AnnouncerContext';
import type { AnnounceOptions } from '~/common';
import AnnouncerContext from '~/Providers/AnnouncerContext';
import useLocalize from '~/hooks/useLocalize';
import Announcer from './Announcer';
Expand Down
1 change: 0 additions & 1 deletion client/src/components/Audio/Voices.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React from 'react';
import { useRecoilState } from 'recoil';
import type { Option } from '~/common';
import DropdownNoState from '~/components/ui/DropdownNoState';
import { useLocalize, useTTSBrowser, useTTSEdge, useTTSExternal } from '~/hooks';
import { Dropdown } from '~/components/ui';
import { logger } from '~/utils';
Expand Down
16 changes: 11 additions & 5 deletions client/src/components/Auth/AuthLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ import Footer from './Footer';
const ErrorRender = ({ children }: { children: React.ReactNode }) => (
<div className="mt-16 flex justify-center">
<div
className="rounded-md border border-red-500 bg-red-500/10 px-3 py-2 text-sm text-gray-600 dark:text-gray-200"
role="alert"
aria-live="assertive"
className="rounded-md border border-red-500 bg-red-500/10 px-3 py-2 text-sm text-gray-600 dark:text-gray-200"
>
{children}
</div>
Expand All @@ -36,8 +37,9 @@ function AuthLayout({
}) {
const localize = useLocalize();

const hasStartupConfigError = startupConfigError !== null && startupConfigError !== undefined;
const DisplayError = () => {
if (startupConfigError !== null && startupConfigError !== undefined) {
if (hasStartupConfigError) {
return <ErrorRender>{localize('com_auth_error_login_server')}</ErrorRender>;
} else if (error === 'com_auth_error_invalid_reset_token') {
return (
Expand All @@ -49,7 +51,7 @@ function AuthLayout({
{localize('com_auth_to_try_again')}
</ErrorRender>
);
} else if (error) {
} else if (error != null && error) {
return <ErrorRender>{localize(error)}</ErrorRender>;
}
return null;
Expand All @@ -60,7 +62,11 @@ function AuthLayout({
<Banner />
<BlinkAnimation active={isFetching}>
<div className="mt-6 h-10 w-full bg-cover">
<img src="/assets/logo.svg" className="h-full w-full object-contain" alt="Logo" />
<img
src="/assets/logo.svg"
className="h-full w-full object-contain"
alt={localize('com_ui_logo', startupConfig?.appTitle ?? 'LibreChat')}
/>
</div>
</BlinkAnimation>
<DisplayError />
Expand All @@ -70,7 +76,7 @@ function AuthLayout({

<div className="flex flex-grow items-center justify-center">
<div className="w-authPageWidth overflow-hidden bg-white px-6 py-4 dark:bg-gray-900 sm:max-w-md sm:rounded-lg">
{!startupConfigError && !isFetching && (
{!hasStartupConfigError && !isFetching && (
<h1
className="mb-4 text-center text-3xl font-semibold text-black dark:text-white"
style={{ userSelect: 'none' }}
Expand Down
3 changes: 2 additions & 1 deletion client/src/components/Auth/ErrorMessage.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
export const ErrorMessage = ({ children }: { children: React.ReactNode }) => (
<div
className="rounded-md border border-red-500 bg-red-500/10 px-3 py-2 text-sm text-gray-600 dark:text-gray-200"
role="alert"
aria-live="assertive"
className="rounded-md border border-red-500 bg-red-500/10 px-3 py-2 text-sm text-gray-600 dark:text-gray-200"
>
{children}
</div>
Expand Down
9 changes: 6 additions & 3 deletions client/src/components/Chat/ExportAndShareMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { useState, useId } from 'react';
import { useState, useId, useRef } from 'react';
import { useRecoilValue } from 'recoil';
import * as Ariakit from '@ariakit/react';
import { Upload, Share2 } from 'lucide-react';
import { ShareButton } from '~/components/Conversations/ConvoOptions';
import { useMediaQuery, useLocalize } from '~/hooks';
import ExportModal from '~/components/Nav/ExportConversation/ExportModal';
import { DropdownPopup } from '~/components/ui';
import { ExportModal } from '../Nav';
import store from '~/store';

export default function ExportAndShareMenu({
Expand All @@ -19,6 +19,7 @@ export default function ExportAndShareMenu({
const [showShareDialog, setShowShareDialog] = useState(false);

const menuId = useId();
const exportButtonRef = useRef<HTMLButtonElement>(null);
const isSmallScreen = useMediaQuery('(max-width: 768px)');
const conversation = useRecoilValue(store.conversationByIndex(0));

Expand Down Expand Up @@ -68,6 +69,7 @@ export default function ExportAndShareMenu({
setIsOpen={setIsPopoverActive}
trigger={
<Ariakit.MenuButton
ref={exportButtonRef}
id="export-menu-button"
aria-label="Export options"
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"
Expand All @@ -91,7 +93,8 @@ export default function ExportAndShareMenu({
open={showExports}
onOpenChange={onOpenChange}
conversation={conversation}
aria-label="Export conversation modal"
triggerRef={exportButtonRef}
aria-label={localize('com_ui_export_convo_modal')}
/>
)}
</>
Expand Down
5 changes: 5 additions & 0 deletions client/src/components/Chat/Menus/EndpointsMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ import type { FC } from 'react';
import { useChatContext, useAgentsMapContext, useAssistantsMapContext } from '~/Providers';
import { mapEndpoints, getEntity } from '~/utils';
import EndpointItems from './Endpoints/MenuItems';
import useLocalize from '~/hooks/useLocalize';
import TitleButton from './UI/TitleButton';

const EndpointsMenu: FC = () => {
const { data: endpoints = [] } = useGetEndpointsQuery({
select: mapEndpoints,
});

const localize = useLocalize();
const agentsMap = useAgentsMapContext();
const assistantMap = useAssistantsMapContext();
const { conversation } = useChatContext();
Expand Down Expand Up @@ -51,6 +53,9 @@ const EndpointsMenu: FC = () => {
<Content
side="bottom"
align="start"
role="listbox"
id="llm-endpoint-menu"
aria-label={localize('com_ui_endpoints_available')}
className="mt-2 max-h-[65vh] min-w-[340px] overflow-y-auto rounded-lg border border-border-light bg-header-primary text-text-primary shadow-lg lg:max-h-[75vh]"
>
<EndpointItems endpoints={endpoints} selected={endpoint} />
Expand Down
11 changes: 10 additions & 1 deletion client/src/components/Chat/Menus/Models/MenuButton.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useState } from 'react';
import { Trigger } from '@radix-ui/react-popover';
import type { TModelSpec, TEndpointsConfig } from 'librechat-data-provider';
import { useLocalize } from '~/hooks';
Expand All @@ -20,6 +21,8 @@ export default function MenuButton({
endpointsConfig: TEndpointsConfig;
}) {
const localize = useLocalize();
const [isExpanded, setIsExpanded] = useState(false);

return (
<Trigger asChild>
<button
Expand All @@ -28,7 +31,13 @@ export default function MenuButton({
className,
)}
type="button"
aria-label={`Select ${primaryText}`}
aria-label={localize('com_ui_llm_menu')}
role="combobox"
aria-haspopup="listbox"
aria-expanded={isExpanded}
aria-controls="llm-menu"
aria-activedescendant={isExpanded ? 'selected-llm' : undefined}
onClick={() => setIsExpanded(!isExpanded)}
>
{selected && selected.showIconInHeader === true && (
<SpecIcon currentSpec={selected} endpointsConfig={endpointsConfig} />
Expand Down
4 changes: 3 additions & 1 deletion client/src/components/Chat/Menus/Models/ModelSpec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ const MenuItem: FC<MenuItemProps> = ({
return (
<>
<div
role="menuitem"
id={selected ? 'selected-llm' : undefined}
role="option"
aria-selected={selected}
className="group m-1.5 flex cursor-pointer gap-2 rounded px-1 py-2.5 !pr-3 text-sm !opacity-100 hover:bg-black/5 focus:ring-0 radix-disabled:pointer-events-none radix-disabled:opacity-50 dark:hover:bg-white/5"
tabIndex={0}
{...rest}
Expand Down
4 changes: 2 additions & 2 deletions client/src/components/Chat/Menus/Models/ModelSpecs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ import MenuSeparator from '~/components/Chat/Menus/UI/MenuSeparator';
import ModelSpec from './ModelSpec';

const ModelSpecs: FC<{
specs?: TModelSpec[];
specs?: Array<TModelSpec | undefined>;
selected?: TModelSpec;
setSelected?: (spec: TModelSpec) => void;
endpointsConfig: TEndpointsConfig;
}> = ({ specs = [], selected, setSelected = () => ({}), endpointsConfig }) => {
return (
<>
{specs &&
{specs.length &&
specs.map((spec, i) => {
if (!spec) {
return null;
Expand Down
6 changes: 5 additions & 1 deletion client/src/components/Chat/Menus/Models/ModelSpecsMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ 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 { useChatContext, useAssistantsMapContext } from '~/Providers';
import { useDefaultConvo, useNewConvo, useLocalize } from '~/hooks';
import { getConvoSwitchLogic, getModelSpecIconURL } from '~/utils';
import { useDefaultConvo, useNewConvo } from '~/hooks';
import MenuButton from './MenuButton';
import ModelSpecs from './ModelSpecs';
import store from '~/store';
Expand All @@ -15,6 +15,7 @@ export default function ModelSpecsMenu({ modelSpecs }: { modelSpecs?: TModelSpec
const { conversation } = useChatContext();
const { newConversation } = useNewConvo();

const localize = useLocalize();
const { data: endpointsConfig = {} as TEndpointsConfig } = useGetEndpointsQuery();
const modularChat = useRecoilValue(store.modularChat);
const getDefaultConversation = useDefaultConvo();
Expand Down Expand Up @@ -111,6 +112,9 @@ export default function ModelSpecsMenu({ modelSpecs }: { modelSpecs?: TModelSpec
<Content
side="bottom"
align="start"
id="llm-menu"
role="listbox"
aria-label={localize('com_ui_llms_available')}
className="models-scrollbar mt-2 max-h-[65vh] min-w-[340px] max-w-xs overflow-y-auto rounded-lg border border-gray-100 bg-white shadow-lg dark:border-gray-700 dark:bg-gray-700 dark:text-white lg:max-h-[75vh]"
>
<ModelSpecs
Expand Down
4 changes: 3 additions & 1 deletion client/src/components/Chat/Menus/UI/MenuItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ const MenuItem: FC<MenuItemProps> = ({
}) => {
return (
<div
role="menuitem"
id={selected ? 'selected-endpoint' : undefined}
role="option"
aria-selected={selected}
aria-label={title}
data-testid="chat-menu-item"
className={cn(
Expand Down
10 changes: 7 additions & 3 deletions client/src/components/Chat/Menus/UI/TitleButton.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
import { useState } from 'react';
import { ChevronDown } from 'lucide-react';
import { Trigger } from '@radix-ui/react-popover';
import useLocalize from '~/hooks/useLocalize';

export default function TitleButton({ primaryText = '', secondaryText = '' }) {
const localize = useLocalize();
const [isExpanded, setIsExpanded] = useState(false);

return (
<Trigger asChild>
<button
className="group flex cursor-pointer items-center gap-2 rounded-lg px-3 py-1.5 text-lg font-medium transition-colors duration-200 hover:bg-surface-hover radix-state-open:bg-surface-hover"
aria-label={`Select ${primaryText}`}
aria-haspopup="dialog"
aria-label={localize('com_ui_endpoint_menu')}
aria-expanded={isExpanded}
aria-controls="radix-:r6:"
role="combobox"
aria-haspopup="listbox"
aria-controls="llm-endpoint-menu"
aria-activedescendant={isExpanded ? 'selected-endpoint' : undefined}
onClick={() => setIsExpanded(!isExpanded)}
>
<div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ export const ErrorMessage = ({
return (
<Container message={message}>
<div
role="alert"
aria-live="assertive"
className={cn(
'rounded-xl border border-red-500/20 bg-red-500/5 px-3 py-2 text-sm text-gray-600 dark:text-gray-200',
className,
Expand Down
12 changes: 10 additions & 2 deletions client/src/components/Nav/ExportConversation/ExportModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ export default function ExportModal({
open,
onOpenChange,
conversation,
triggerRef,
}: {
open: boolean;
onOpenChange: (open: boolean) => void;
conversation: TConversation | null;
onOpenChange: (open: boolean) => void;
triggerRef: React.RefObject<HTMLButtonElement>;
}) {
const localize = useLocalize();

Expand All @@ -31,6 +33,12 @@ export default function ExportModal({
{ value: 'csv', label: 'csv (.csv)' },
];

useEffect(() => {
if (!open && triggerRef.current) {
triggerRef.current.focus();
}
}, [open, triggerRef]);

useEffect(() => {
setFileName(filenamify(String(conversation?.title ?? 'file')));
setType('screenshot');
Expand Down Expand Up @@ -61,7 +69,7 @@ export default function ExportModal({
});

return (
<OGDialog open={open} onOpenChange={onOpenChange}>
<OGDialog open={open} onOpenChange={onOpenChange} triggerRef={triggerRef}>
<OGDialogTemplate
title={localize('com_nav_export_conversation')}
className="max-w-full sm:max-w-2xl"
Expand Down
23 changes: 22 additions & 1 deletion client/src/components/ui/OriginalDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,28 @@ import * as DialogPrimitive from '@radix-ui/react-dialog';
import { X } from 'lucide-react';
import { cn } from '~/utils';

const Dialog = DialogPrimitive.Root;
interface OGDialogProps extends DialogPrimitive.DialogProps {
triggerRef?: React.RefObject<HTMLButtonElement>;
}

const Dialog = React.forwardRef<HTMLDivElement, OGDialogProps>(
({ children, triggerRef, onOpenChange, ...props }) => {
const handleOpenChange = (open: boolean) => {
if (!open && triggerRef?.current) {
setTimeout(() => {
triggerRef.current?.focus();
}, 0);
}
onOpenChange?.(open);
};

return (
<DialogPrimitive.Root {...props} onOpenChange={handleOpenChange}>
{children}
</DialogPrimitive.Root>
);
},
);

const DialogTrigger = DialogPrimitive.Trigger;

Expand Down
1 change: 0 additions & 1 deletion client/src/components/ui/Toast.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ export default function Toast() {
className={`alert-root pointer-events-auto inline-flex flex-row gap-2 rounded-md border px-3 py-2 text-white ${
severityClassName[toast.severity]
}`}
role="alert"
>
{toast.showIcon && (
<div className="mt-1 flex-shrink-0 flex-grow-0">
Expand Down
Loading
Loading