AIAssistantHeader.tsx148 lines · main
1import { Clipboard, Ellipsis, Plus, Settings, X } from 'lucide-react'
2import { useState } from 'react'
3import {
4 AiIconAnimation,
5 Button,
6 copyToClipboard,
7 DropdownMenu,
8 DropdownMenuContent,
9 DropdownMenuItem,
10 DropdownMenuTrigger,
11} from 'ui'
12import { Admonition } from 'ui-patterns'
13
14import { ButtonTooltip } from '../ButtonTooltip'
15import { AIAssistantChatSelector } from './AIAssistantChatSelector'
16import { AIOptInModal } from './AIOptInModal'
17import { useAiAssistantStateSnapshot } from '@/state/ai-assistant-state'
18
19interface AIAssistantHeaderProps {
20 isChatLoading: boolean
21 onNewChat: () => void
22 onCloseAssistant: () => void
23 showMetadataWarning: boolean
24 updatedOptInSinceMCP: boolean
25 isHipaaProjectDisallowed: boolean
26 aiOptInLevel: 'disabled' | 'schema' | 'full' | string | undefined
27}
28
29export const AIAssistantHeader = ({
30 isChatLoading,
31 onNewChat,
32 onCloseAssistant,
33 showMetadataWarning,
34 updatedOptInSinceMCP,
35 isHipaaProjectDisallowed,
36 aiOptInLevel,
37}: AIAssistantHeaderProps) => {
38 const snap = useAiAssistantStateSnapshot()
39 const [isOptInModalOpen, setIsOptInModalOpen] = useState(false)
40 return (
41 <div className="z-30 sticky top-0">
42 <div className="border-b border-b-muted flex items-center bg gap-x-4 pl-4 pr-3 min-h-(--header-height)">
43 <div className="text-sm flex-1 flex items-center">
44 <AiIconAnimation size={20} allowHoverEffect={false} />
45 <span className="text-border-stronger dark:text-border-strong ml-3">
46 <svg
47 viewBox="0 0 24 24"
48 width="16"
49 height="16"
50 stroke="currentColor"
51 strokeWidth="1"
52 strokeLinecap="round"
53 strokeLinejoin="round"
54 fill="none"
55 shapeRendering="geometricPrecision"
56 >
57 <path d="M16 3.549L7.12 20.600" />
58 </svg>
59 </span>
60 <AIAssistantChatSelector />
61 </div>
62 <div className="flex items-center gap-x-4">
63 <div className="flex items-center">
64 <ButtonTooltip
65 type="text"
66 size="tiny"
67 icon={<Plus strokeWidth={1.5} />}
68 onClick={onNewChat}
69 className="h-7 w-7 p-0"
70 tooltip={{ content: { side: 'bottom', text: 'New chat' } }}
71 />
72 <ButtonTooltip
73 type="text"
74 size="tiny"
75 icon={<Settings strokeWidth={1.5} />}
76 onClick={() => setIsOptInModalOpen(true)}
77 className="h-7 w-7 p-0"
78 disabled={isChatLoading}
79 tooltip={{
80 content: { side: 'bottom', text: 'Permission settings' },
81 }}
82 />
83 <DropdownMenu>
84 <DropdownMenuTrigger asChild>
85 <ButtonTooltip
86 type="text"
87 size="tiny"
88 icon={<Ellipsis strokeWidth={1.5} />}
89 className="h-7 w-7 p-0"
90 tooltip={{ content: { side: 'bottom', text: 'More options' } }}
91 />
92 </DropdownMenuTrigger>
93 <DropdownMenuContent align="end">
94 <DropdownMenuItem
95 className="gap-x-2"
96 onClick={() => copyToClipboard(snap.activeChatId ?? '')}
97 >
98 <Clipboard size={14} strokeWidth={1.5} />
99 <span>Copy chat ID</span>
100 </DropdownMenuItem>
101 </DropdownMenuContent>
102 </DropdownMenu>
103 <ButtonTooltip
104 type="text"
105 className="w-7 h-7"
106 onClick={onCloseAssistant}
107 icon={<X strokeWidth={1.5} />}
108 tooltip={{ content: { side: 'bottom', text: 'Close assistant' } }}
109 />
110 </div>
111 </div>
112 </div>
113 {showMetadataWarning && (
114 <Admonition
115 type="default"
116 title={
117 !updatedOptInSinceMCP
118 ? 'The Assistant has just been updated to help you better!'
119 : isHipaaProjectDisallowed
120 ? 'Project metadata is not shared due to HIPAA'
121 : aiOptInLevel === 'disabled'
122 ? 'Project metadata is currently not shared'
123 : 'Limited metadata is shared to the Assistant'
124 }
125 description={
126 !updatedOptInSinceMCP
127 ? 'You may now opt-in to share schema metadata and even logs for better results'
128 : isHipaaProjectDisallowed
129 ? 'Your organization has the HIPAA addon and will not send project metadata with your prompts for projects marked as HIPAA.'
130 : aiOptInLevel === 'disabled'
131 ? 'The Assistant can provide better answers if you opt-in to share schema metadata.'
132 : aiOptInLevel === 'schema'
133 ? 'Sharing query data in addition to schema can further improve responses. Update AI settings to enable this.'
134 : ''
135 }
136 className="border-0 border-b rounded-none bg-background"
137 >
138 {!isHipaaProjectDisallowed && (
139 <Button type="default" className="w-fit mt-4" onClick={() => setIsOptInModalOpen(true)}>
140 Permission settings
141 </Button>
142 )}
143 </Admonition>
144 )}
145 <AIOptInModal visible={isOptInModalOpen} onCancel={() => setIsOptInModalOpen(false)} />
146 </div>
147 )
148}