mirror of
https://github.com/langgenius/dify.git
synced 2026-05-04 17:38:04 +08:00
fix: hide divider when OnlineUsers component is not rendered
Move the Divider into the OnlineUsers component so it conditionally renders together with the online users content, preventing an orphaned divider from appearing next to the preview button.
This commit is contained in:
@ -5,7 +5,6 @@ import {
|
||||
} from 'react'
|
||||
import { useNodes } from 'reactflow'
|
||||
import { useInputFieldPanel } from '@/app/components/rag-pipeline/hooks'
|
||||
import Divider from '../../base/divider'
|
||||
import {
|
||||
useNodesInteractions,
|
||||
useNodesReadOnly,
|
||||
@ -75,7 +74,6 @@ const HeaderInNormal = ({
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<OnlineUsers />
|
||||
<Divider type="vertical" className="mx-auto h-3.5" />
|
||||
<RunAndHistory {...runAndHistoryProps} />
|
||||
<div className="shrink-0 cursor-pointer rounded-lg border-[0.5px] border-components-button-secondary-border bg-components-button-secondary-bg shadow-xs backdrop-blur-[10px]">
|
||||
{components?.chatVariableTrigger}
|
||||
|
||||
@ -4,6 +4,7 @@ import { ChevronDownIcon } from '@heroicons/react/20/solid'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useReactFlow } from 'reactflow'
|
||||
import Avatar from '@/app/components/base/avatar'
|
||||
import Divider from '@/app/components/base/divider'
|
||||
import {
|
||||
PortalToFollowElem,
|
||||
PortalToFollowElemContent,
|
||||
@ -107,134 +108,137 @@ const OnlineUsers = () => {
|
||||
const hasCounter = remainingCount > 0
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
'flex h-8 items-center rounded-full border-[0.5px] border-components-panel-border',
|
||||
'bg-components-panel-bg py-1 shadow-xs shadow-shadow-shadow-3 backdrop-blur-[10px]',
|
||||
hasCounter ? 'min-w-[87px] gap-px pl-1 pr-1.5' : 'gap-1 px-1.5',
|
||||
)}
|
||||
>
|
||||
<div className="flex h-6 items-center">
|
||||
<div className="flex items-center">
|
||||
{visibleUsers.map((user, index) => {
|
||||
const isCurrentUser = user.user_id === currentUserId
|
||||
const userColor = isCurrentUser ? undefined : getUserColor(user.user_id)
|
||||
return (
|
||||
<Tooltip
|
||||
key={`${user.sid}-${index}`}
|
||||
popupContent={renderDisplayName(
|
||||
user,
|
||||
'system-xs-medium text-text-secondary',
|
||||
'text-text-quaternary',
|
||||
)}
|
||||
position="bottom"
|
||||
triggerMethod="hover"
|
||||
needsDelay={false}
|
||||
asChild
|
||||
popupClassName="flex h-[28px] items-center justify-center gap-1 rounded-md border-[0.5px] border-components-panel-border bg-components-tooltip-bg px-3 py-[6px] shadow-lg shadow-shadow-shadow-5 backdrop-blur-[10px]"
|
||||
noDecoration
|
||||
>
|
||||
<div
|
||||
className={cn(
|
||||
'relative flex size-6 items-center justify-center',
|
||||
index > 0 && '-ml-1.5',
|
||||
!isCurrentUser && 'cursor-pointer transition-transform hover:scale-110',
|
||||
<>
|
||||
<div
|
||||
className={cn(
|
||||
'flex h-8 items-center rounded-full border-[0.5px] border-components-panel-border',
|
||||
'bg-components-panel-bg py-1 shadow-xs shadow-shadow-shadow-3 backdrop-blur-[10px]',
|
||||
hasCounter ? 'min-w-[87px] gap-px pl-1 pr-1.5' : 'gap-1 px-1.5',
|
||||
)}
|
||||
>
|
||||
<div className="flex h-6 items-center">
|
||||
<div className="flex items-center">
|
||||
{visibleUsers.map((user, index) => {
|
||||
const isCurrentUser = user.user_id === currentUserId
|
||||
const userColor = isCurrentUser ? undefined : getUserColor(user.user_id)
|
||||
return (
|
||||
<Tooltip
|
||||
key={`${user.sid}-${index}`}
|
||||
popupContent={renderDisplayName(
|
||||
user,
|
||||
'system-xs-medium text-text-secondary',
|
||||
'text-text-quaternary',
|
||||
)}
|
||||
style={{ zIndex: visibleUsers.length - index }}
|
||||
onClick={() => !isCurrentUser && jumpToUserCursor(user.user_id)}
|
||||
position="bottom"
|
||||
triggerMethod="hover"
|
||||
needsDelay={false}
|
||||
asChild
|
||||
popupClassName="flex h-[28px] items-center justify-center gap-1 rounded-md border-[0.5px] border-components-panel-border bg-components-tooltip-bg px-3 py-[6px] shadow-lg shadow-shadow-shadow-5 backdrop-blur-[10px]"
|
||||
noDecoration
|
||||
>
|
||||
<Avatar
|
||||
name={user.username || 'User'}
|
||||
avatar={getAvatarUrl(user)}
|
||||
size={24}
|
||||
className="ring-1 ring-components-panel-bg"
|
||||
backgroundColor={userColor}
|
||||
/>
|
||||
</div>
|
||||
</Tooltip>
|
||||
)
|
||||
})}
|
||||
{remainingCount > 0 && (
|
||||
<PortalToFollowElem
|
||||
open={dropdownOpen}
|
||||
onOpenChange={setDropdownOpen}
|
||||
placement="bottom-start"
|
||||
offset={{
|
||||
mainAxis: 8,
|
||||
crossAxis: -48,
|
||||
}}
|
||||
>
|
||||
<PortalToFollowElemTrigger
|
||||
onClick={() => setDropdownOpen(prev => !prev)}
|
||||
asChild
|
||||
>
|
||||
<div className="flex items-center gap-1">
|
||||
<div
|
||||
className={cn(
|
||||
'flex h-6 w-6 cursor-pointer select-none items-center justify-center rounded-full bg-components-icon-bg-midnight-solid text-[10px] font-semibold uppercase leading-[12px] text-white ring-1 ring-components-panel-bg',
|
||||
visibleUsers.length > 0 && '-ml-1',
|
||||
'relative flex size-6 items-center justify-center',
|
||||
index > 0 && '-ml-1.5',
|
||||
!isCurrentUser && 'cursor-pointer transition-transform hover:scale-110',
|
||||
)}
|
||||
style={{ zIndex: visibleUsers.length - index }}
|
||||
onClick={() => !isCurrentUser && jumpToUserCursor(user.user_id)}
|
||||
>
|
||||
<Avatar
|
||||
name={user.username || 'User'}
|
||||
avatar={getAvatarUrl(user)}
|
||||
size={24}
|
||||
className="ring-1 ring-components-panel-bg"
|
||||
backgroundColor={userColor}
|
||||
/>
|
||||
</div>
|
||||
</Tooltip>
|
||||
)
|
||||
})}
|
||||
{remainingCount > 0 && (
|
||||
<PortalToFollowElem
|
||||
open={dropdownOpen}
|
||||
onOpenChange={setDropdownOpen}
|
||||
placement="bottom-start"
|
||||
offset={{
|
||||
mainAxis: 8,
|
||||
crossAxis: -48,
|
||||
}}
|
||||
>
|
||||
<PortalToFollowElemTrigger
|
||||
onClick={() => setDropdownOpen(prev => !prev)}
|
||||
asChild
|
||||
>
|
||||
<div className="flex items-center gap-1">
|
||||
<div
|
||||
className={cn(
|
||||
'flex h-6 w-6 cursor-pointer select-none items-center justify-center rounded-full bg-components-icon-bg-midnight-solid text-[10px] font-semibold uppercase leading-[12px] text-white ring-1 ring-components-panel-bg',
|
||||
visibleUsers.length > 0 && '-ml-1',
|
||||
)}
|
||||
>
|
||||
+
|
||||
{remainingCount}
|
||||
</div>
|
||||
<ChevronDownIcon className="h-3 w-3 cursor-pointer text-gray-500" />
|
||||
</div>
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent
|
||||
className="z-[9999]"
|
||||
>
|
||||
<div
|
||||
className={cn(
|
||||
'mt-1.5',
|
||||
'flex flex-col',
|
||||
'max-h-[200px] w-[240px] overflow-y-auto',
|
||||
'rounded-xl border-[0.5px] border-components-panel-border',
|
||||
'bg-components-panel-bg-blur p-1',
|
||||
'shadow-lg shadow-shadow-shadow-5',
|
||||
'backdrop-blur-[10px]',
|
||||
)}
|
||||
>
|
||||
+
|
||||
{remainingCount}
|
||||
</div>
|
||||
<ChevronDownIcon className="h-3 w-3 cursor-pointer text-gray-500" />
|
||||
</div>
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent
|
||||
className="z-[9999]"
|
||||
>
|
||||
<div
|
||||
className={cn(
|
||||
'mt-1.5',
|
||||
'flex flex-col',
|
||||
'max-h-[200px] w-[240px] overflow-y-auto',
|
||||
'rounded-xl border-[0.5px] border-components-panel-border',
|
||||
'bg-components-panel-bg-blur p-1',
|
||||
'shadow-lg shadow-shadow-shadow-5',
|
||||
'backdrop-blur-[10px]',
|
||||
)}
|
||||
>
|
||||
{onlineUsers.map((user) => {
|
||||
const isCurrentUser = user.user_id === currentUserId
|
||||
const userColor = isCurrentUser ? undefined : getUserColor(user.user_id)
|
||||
return (
|
||||
<div
|
||||
key={user.sid}
|
||||
className={cn(
|
||||
'flex items-center gap-2 rounded-lg px-3 py-1.5',
|
||||
!isCurrentUser && 'cursor-pointer hover:bg-components-panel-on-panel-item-bg-hover',
|
||||
)}
|
||||
onClick={() => {
|
||||
if (!isCurrentUser) {
|
||||
jumpToUserCursor(user.user_id)
|
||||
setDropdownOpen(false)
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div className="relative">
|
||||
<Avatar
|
||||
name={user.username || 'User'}
|
||||
avatar={getAvatarUrl(user)}
|
||||
size={24}
|
||||
backgroundColor={userColor}
|
||||
/>
|
||||
{onlineUsers.map((user) => {
|
||||
const isCurrentUser = user.user_id === currentUserId
|
||||
const userColor = isCurrentUser ? undefined : getUserColor(user.user_id)
|
||||
return (
|
||||
<div
|
||||
key={user.sid}
|
||||
className={cn(
|
||||
'flex items-center gap-2 rounded-lg px-3 py-1.5',
|
||||
!isCurrentUser && 'cursor-pointer hover:bg-components-panel-on-panel-item-bg-hover',
|
||||
)}
|
||||
onClick={() => {
|
||||
if (!isCurrentUser) {
|
||||
jumpToUserCursor(user.user_id)
|
||||
setDropdownOpen(false)
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div className="relative">
|
||||
<Avatar
|
||||
name={user.username || 'User'}
|
||||
avatar={getAvatarUrl(user)}
|
||||
size={24}
|
||||
backgroundColor={userColor}
|
||||
/>
|
||||
</div>
|
||||
{renderDisplayName(
|
||||
user,
|
||||
'system-xs-medium text-text-secondary',
|
||||
'text-text-tertiary',
|
||||
)}
|
||||
</div>
|
||||
{renderDisplayName(
|
||||
user,
|
||||
'system-xs-medium text-text-secondary',
|
||||
'text-text-tertiary',
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</PortalToFollowElemContent>
|
||||
</PortalToFollowElem>
|
||||
)}
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</PortalToFollowElemContent>
|
||||
</PortalToFollowElem>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Divider type="vertical" className="mx-auto h-3.5" />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user