Skip to content

Commit 940f221

Browse files
authored
Rename AI Assistant to match the OpenOps edition (#1630)
Fixes OPS-3091. ## UI Changes <img width="623" height="275" alt="Screenshot 2025-11-20 at 12 54 00 PM" src="https://github.com/user-attachments/assets/1716aa2b-edc1-4ec1-a0b9-358f0e9e63f8" /> <img width="578" height="472" alt="Screenshot 2025-11-20 at 12 53 31 PM" src="https://github.com/user-attachments/assets/3338dfc0-3c11-4305-a695-b1d74cfd5abd" />
1 parent 9e24d6b commit 940f221

File tree

11 files changed

+51
-38
lines changed

11 files changed

+51
-38
lines changed

packages/react-ui/public/locales/en/translation.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
"Refresh Page": "Refresh Page",
1717
"Contact Support": "Contact Support",
1818
"AI Assistant": "AI Assistant",
19+
"OpenOps Assistant": "OpenOps Assistant",
20+
"OpenOps Agent": "OpenOps Agent",
1921
"Enable AI": "Enable AI",
2022
"Save": "Save",
2123
"Valid Connection": "Valid Connection",

packages/react-ui/src/app/features/ai/ai-assistant-button.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1+
import { useAssistantName } from '@/app/features/ai/lib/use-assistant-name';
12
import { useAppStore } from '@/app/store/app-store';
23
import { Button, cn, TooltipWrapper } from '@openops/components/ui';
3-
import { t } from 'i18next';
44
import { Bot } from 'lucide-react';
55
import { useCallback } from 'react';
66

@@ -10,12 +10,14 @@ const AiAssistantButton = ({ className }: { className?: string }) => {
1010
setIsAiChatOpened: s.setIsAiChatOpened,
1111
}));
1212

13+
const assistantName = useAssistantName();
14+
1315
const onToggleAiChat = useCallback(() => {
1416
setIsAiChatOpened(!isAiChatOpened);
1517
}, [isAiChatOpened, setIsAiChatOpened]);
1618

1719
return (
18-
<TooltipWrapper tooltipText={t('AI Assistant')} tooltipPlacement="right">
20+
<TooltipWrapper tooltipText={assistantName} tooltipPlacement="right">
1921
<Button
2022
variant="ai"
2123
className={cn('size-9 p-0 gap-2', className, {

packages/react-ui/src/app/features/ai/ai-configuration-prompt.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { aiSettingsHooks } from '@/app/features/ai/lib/ai-settings-hooks';
2+
import { useAssistantName } from '@/app/features/ai/lib/use-assistant-name';
23
import { useAppStore } from '@/app/store/app-store';
34
import { cn, NoAiEnabledPopover } from '@openops/components/ui';
45

@@ -15,12 +16,15 @@ const AiConfigurationPrompt = ({ className }: AiConfigurationPromptProps) => {
1516
setIsAiChatOpened: s.setIsAiChatOpened,
1617
}));
1718

19+
const assistantName = useAssistantName();
20+
1821
if (isLoading || hasActiveAiSettings || !isAiChatOpened) return null;
1922

2023
return (
2124
<NoAiEnabledPopover
2225
className={cn('absolute left-4 bottom-[17px] z-50', className)}
2326
onCloseClick={() => setIsAiChatOpened(false)}
27+
title={assistantName}
2428
/>
2529
);
2630
};

packages/react-ui/src/app/features/ai/assistant/ai-chat-resizable-panel.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ import { useResizablePanelGroup } from '@/app/common/hooks/use-resizable-panel-g
22
import { RESIZABLE_PANEL_IDS } from '@/app/constants/layout';
33
import AssistantUiChat from '@/app/features/ai/assistant/assistant-ui-chat';
44
import { aiSettingsHooks } from '@/app/features/ai/lib/ai-settings-hooks';
5+
import { useAssistantName } from '@/app/features/ai/lib/use-assistant-name';
56
import { useAppStore } from '@/app/store/app-store';
67
import { cn, ResizableHandle, ResizablePanel } from '@openops/components/ui';
7-
import { t } from 'i18next';
88
import { useCallback, useEffect, useMemo, useRef } from 'react';
99
import { ImperativePanelHandle } from 'react-resizable-panels';
1010

@@ -21,6 +21,8 @@ const AiChatResizablePanel = ({ onDragging }: AiChatResizablePanelProps) => {
2121
const { hasActiveAiSettings, isLoading } =
2222
aiSettingsHooks.useHasActiveAiSettings();
2323

24+
const assistantName = useAssistantName();
25+
2426
const resizablePanelRef = useRef<ImperativePanelHandle | null>(null);
2527

2628
const { getPanelSize } = useResizablePanelGroup();
@@ -71,7 +73,7 @@ const AiChatResizablePanel = ({ onDragging }: AiChatResizablePanelProps) => {
7173
>
7274
<div className="w-full h-full flex bg-secondary overflow-hidden border-r">
7375
<AssistantUiChat
74-
title={t('AI Assistant')}
76+
title={assistantName}
7577
onClose={() => setIsAiChatOpened(false)}
7678
/>
7779
</div>

packages/react-ui/src/app/features/ai/assistant/assistant-ui-chat.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ const AssistantUiChat = ({
9191
return title;
9292
}, [chatId, chats, title]);
9393

94+
const isTitleDefault = currentChatTitle === title;
95+
9496
const onChatSelected = useCallback(
9597
(id: string) => {
9698
onChatIdChange(id);
@@ -139,6 +141,7 @@ const AssistantUiChat = ({
139141
runtime={runtime}
140142
onNewChat={onNewChatClick}
141143
title={currentChatTitle}
144+
isTitleDefault={isTitleDefault}
142145
availableModels={availableModels}
143146
onModelSelected={onModelSelected}
144147
isModelSelectorLoading={isModelSelectorLoading}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { flagsHooks } from '@/app/common/hooks/flags-hooks';
2+
import { FlagId, OpsEdition } from '@openops/shared';
3+
import { t } from 'i18next';
4+
5+
export const useAssistantName = () => {
6+
const edition = flagsHooks.useFlag<OpsEdition>(FlagId.EDITION).data;
7+
return edition === OpsEdition.COMMUNITY
8+
? t('OpenOps Assistant')
9+
: t('OpenOps Agent');
10+
};

packages/ui-components/src/components/ai-chat-container/no-ai-enabled-popover.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@ import { TooltipWrapper } from '../tooltip-wrapper';
88
const NoAiEnabledPopover = ({
99
className,
1010
onCloseClick,
11+
title,
1112
}: {
1213
className?: string;
1314
onCloseClick: () => void;
15+
title: string;
1416
}) => {
1517
return (
1618
<div className={cn('bg-background shadow-editor rounded-lg', className)}>
@@ -19,7 +21,7 @@ const NoAiEnabledPopover = ({
1921
<div className="size-8 flex justify-center items-center bg-background bg-gradient-to-b from-ring/40 to-primary-200/40 rounded-xl">
2022
<Bot size={20} />
2123
</div>
22-
<h2 className="font-bold text-base">{t('AI Assistant')}</h2>
24+
<h2 className="font-bold text-base">{title}</h2>
2325
</div>
2426
<TooltipWrapper tooltipText={t('Close')}>
2527
<Button

packages/ui-components/src/components/assistant-ui/assistant-top-bar.tsx

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,15 @@ import { Popover, PopoverContent, PopoverTrigger } from '../../ui/popover';
1010
type AssistantTopBarProps = {
1111
onClose: () => void;
1212
onNewChat: () => void;
13-
title?: string;
13+
title: string;
14+
isTitleDefault?: boolean;
1415
onHistoryOpenChange?: (open: boolean) => void;
1516
isHistoryOpen?: boolean;
1617
historyContent?: ReactNode;
1718
children: ReactNode;
1819
chatId?: string | null;
1920
};
2021

21-
const AI_ASSISTANT_DEFAULT_TITLE = 'AI Assistant';
22-
2322
const AssistantTopBar = ({
2423
onNewChat,
2524
onClose,
@@ -29,13 +28,13 @@ const AssistantTopBar = ({
2928
historyContent,
3029
children,
3130
chatId,
31+
isTitleDefault,
3232
}: AssistantTopBarProps) => {
3333
const animatedTitle = useTypingAnimation({
34-
text: title || AI_ASSISTANT_DEFAULT_TITLE,
34+
text: title,
3535
speed: 50,
36-
fromText: AI_ASSISTANT_DEFAULT_TITLE,
37-
defaultText: AI_ASSISTANT_DEFAULT_TITLE,
3836
chatId: chatId,
37+
enableAnimation: !isTitleDefault,
3938
});
4039

4140
return (

packages/ui-components/src/components/assistant-ui/assistant-ui-chat-container.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ type AssistantUiChatContainerProps = {
1414
runtime: AssistantRuntime;
1515
toolComponents?: Record<string, ReactNode>;
1616
handleInject?: (codeContent: string | SourceCode) => void;
17+
isTitleDefault?: boolean;
1718
} & ConnectionStatusProps &
1819
AssistantTopBarProps &
1920
ThreadProps;
@@ -36,6 +37,7 @@ const AssistantUiChatContainer = ({
3637
isShowingSlowWarning,
3738
connectionError,
3839
chatId,
40+
isTitleDefault,
3941
}: AssistantUiChatContainerProps) => {
4042
const codeVariation = useMemo(() => {
4143
return handleInject
@@ -53,6 +55,7 @@ const AssistantUiChatContainer = ({
5355
isHistoryOpen={isHistoryOpen}
5456
historyContent={children}
5557
chatId={chatId}
58+
isTitleDefault={isTitleDefault}
5659
>
5760
{null}
5861
</AssistantTopBar>

packages/ui-components/src/hooks/use-typing-animation.ts

Lines changed: 12 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,41 +3,30 @@ import { useEffect, useRef, useState } from 'react';
33
type UseTypingAnimationOptions = {
44
text: string;
55
speed?: number;
6-
fromText?: string;
76
chatId?: string | null;
8-
defaultText?: string;
7+
enableAnimation?: boolean;
98
};
109

1110
export function useTypingAnimation({
1211
text,
1312
speed = 50,
14-
fromText,
1513
chatId,
16-
defaultText,
14+
enableAnimation,
1715
}: UseTypingAnimationOptions): string {
1816
const [displayedText, setDisplayedText] = useState(text);
19-
const prevTextRef = useRef(text);
20-
const prevChatIdRef = useRef<string | null | undefined>(chatId);
17+
const prevChatIdRef = useRef(chatId);
18+
const prevEnableAnimationRef = useRef(enableAnimation);
2119

2220
useEffect(() => {
23-
let shouldAnimate = false;
2421
let interval: NodeJS.Timeout | undefined;
25-
26-
if (fromText !== undefined && defaultText !== undefined) {
27-
const isSameChat = prevChatIdRef.current === chatId;
28-
const wasDefault =
29-
prevTextRef.current === defaultText || prevTextRef.current === fromText;
30-
const nowHasName = text !== defaultText && text !== fromText;
31-
32-
shouldAnimate = isSameChat && wasDefault && nowHasName;
33-
} else if (fromText !== undefined) {
34-
shouldAnimate = prevTextRef.current === fromText && text !== fromText;
35-
}
22+
const shouldAnimate =
23+
prevChatIdRef.current === chatId &&
24+
prevEnableAnimationRef.current === false &&
25+
enableAnimation === true;
3626

3727
if (shouldAnimate && text.length > 0) {
3828
setDisplayedText('');
3929
let currentIndex = 0;
40-
4130
interval = setInterval(() => {
4231
if (currentIndex < text.length) {
4332
setDisplayedText(text.slice(0, currentIndex + 1));
@@ -46,19 +35,15 @@ export function useTypingAnimation({
4635
clearInterval(interval);
4736
}
4837
}, speed);
38+
39+
return () => clearInterval(interval);
4940
} else {
5041
setDisplayedText(text);
5142
}
5243

53-
prevTextRef.current = text;
5444
prevChatIdRef.current = chatId;
55-
56-
return () => {
57-
if (interval) {
58-
clearInterval(interval);
59-
}
60-
};
61-
}, [text, speed, fromText, chatId, defaultText]);
45+
prevEnableAnimationRef.current = enableAnimation;
46+
}, [text, speed, chatId, enableAnimation]);
6247

6348
return displayedText;
6449
}

0 commit comments

Comments
 (0)