Merge branch 'fix/ai-chat-role-cards-fit' into develop

Fit full role-card description text in the AI chat empty state and show a
generic "AI is typing…" indicator (role name kept only as the dimmed
interlocutor label).
This commit is contained in:
claude_code
2026-06-21 17:11:56 +03:00
7 changed files with 20 additions and 8 deletions

View File

@@ -1147,6 +1147,7 @@
"Take a look at the current document": "Take a look at the current document", "Take a look at the current document": "Take a look at the current document",
"AI agent is typing…": "AI agent is typing…", "AI agent is typing…": "AI agent is typing…",
"{{name}} is typing…": "{{name}} is typing…", "{{name}} is typing…": "{{name}} is typing…",
"AI is typing…": "AI is typing…",
"Send": "Send", "Send": "Send",
"Stop": "Stop", "Stop": "Stop",
"Chat menu": "Chat menu", "Chat menu": "Chat menu",

View File

@@ -672,6 +672,7 @@
"Take a look at the current document": "Посмотри текущий документ", "Take a look at the current document": "Посмотри текущий документ",
"AI agent is typing…": "AI-агент печатает…", "AI agent is typing…": "AI-агент печатает…",
"{{name}} is typing…": "{{name}} печатает…", "{{name}} is typing…": "{{name}} печатает…",
"AI is typing…": "AI печатает…",
"Agent role": "Роль агента", "Agent role": "Роль агента",
"AI chat": "AI-чат", "AI chat": "AI-чат",
"AI chat is disabled for this workspace.": "AI-чат отключён для этого рабочего пространства.", "AI chat is disabled for this workspace.": "AI-чат отключён для этого рабочего пространства.",

View File

@@ -43,7 +43,7 @@ interface MessageListProps {
const BOTTOM_THRESHOLD = 40; const BOTTOM_THRESHOLD = 40;
/** /**
* Whether to show the standalone "AI agent is typing…" indicator. It bridges the * Whether to show the standalone "AI is typing…" indicator. It bridges the
* gap between sending and the first streamed content, so it shows only while a * gap between sending and the first streamed content, so it shows only while a
* turn is in flight AND the latest assistant message has nothing visible yet: * turn is in flight AND the latest assistant message has nothing visible yet:
* - the last message is still the user's (assistant hasn't started a row), or * - the last message is still the user's (assistant hasn't started a row), or

View File

@@ -4,7 +4,11 @@
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
justify-content: center; justify-content: center;
align-content: center; /* flex-start keeps the first row reachable when the wrapped cards overflow and
the container scrolls. With align-content: center, an overflowing top row is
pushed out of the scrollable area and becomes unreachable. The parent Mantine
Center still vertically centers the whole block when it fits. */
align-content: flex-start;
gap: 10px; gap: 10px;
/* Cap the height so a large number of roles scrolls instead of blowing out /* Cap the height so a large number of roles scrolls instead of blowing out
the empty chat area. */ the empty chat area. */
@@ -21,7 +25,7 @@
justify-content: center; justify-content: center;
gap: 4px; gap: 4px;
min-width: 140px; min-width: 140px;
max-width: 180px; max-width: 200px;
min-height: 90px; min-height: 90px;
padding: 12px 10px; padding: 12px 10px;
border-radius: var(--mantine-radius-md); border-radius: var(--mantine-radius-md);
@@ -50,4 +54,8 @@
.description { .description {
opacity: 0.8; opacity: 0.8;
line-height: 1.3; line-height: 1.3;
/* Break long unbreakable tokens (URLs, long foreign words) in the
admin-configured description so they wrap instead of overflowing the card
width now that the line clamp no longer caps the text. */
overflow-wrap: anywhere;
} }

View File

@@ -45,7 +45,7 @@ function RoleCard({
{name} {name}
</Text> </Text>
{description && ( {description && (
<Text size="xs" lineClamp={3} className={classes.description}> <Text size="xs" className={classes.description}>
{description} {description}
</Text> </Text>
)} )}

View File

@@ -5,7 +5,7 @@ import { showTypingIndicator } from "@/features/ai-chat/components/message-list.
/** /**
* Pure-helper tests for the typing-indicator bridging logic that the internal * Pure-helper tests for the typing-indicator bridging logic that the internal
* chat and the public share widget now share. This is the behavior that decides * chat and the public share widget now share. This is the behavior that decides
* whether the animated "AI agent is typing…" placeholder shows in the gap * whether the animated "AI is typing…" placeholder shows in the gap
* between sending and the first streamed token. * between sending and the first streamed token.
*/ */
const msg = ( const msg = (

View File

@@ -19,8 +19,10 @@ interface TypingIndicatorProps {
* the real assistant message once content starts arriving. * the real assistant message once content starts arriving.
* *
* Mirrors the assistant row layout in MessageItem (the dimmed label), so it reads * Mirrors the assistant row layout in MessageItem (the dimmed label), so it reads
* as the assistant's bubble taking shape. The label and typing line use the * as the assistant's bubble taking shape. The dimmed label uses the configured
* configured identity name when provided, otherwise the generic "AI agent". * identity name when provided (otherwise the generic "AI agent"), while the
* typing line is always the generic "AI is typing…" (it never includes the
* role/identity name).
*/ */
export default function TypingIndicator({ assistantName }: TypingIndicatorProps) { export default function TypingIndicator({ assistantName }: TypingIndicatorProps) {
const { t } = useTranslation(); const { t } = useTranslation();
@@ -38,7 +40,7 @@ export default function TypingIndicator({ assistantName }: TypingIndicatorProps)
<span /> <span />
</span> </span>
<Text size="sm" c="dimmed"> <Text size="sm" c="dimmed">
{name ? t("{{name}} is typing…", { name }) : t("AI agent is typing…")} {t("AI is typing…")}
</Text> </Text>
</Group> </Group>
</Box> </Box>