@redocly/theme 0.62.0-next.6 → 0.62.0-next.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/components/Breadcrumbs/Breadcrumb.js +1 -1
- package/lib/components/Breadcrumbs/BreadcrumbDropdown.js +1 -1
- package/lib/components/Catalog/CatalogTagsWithTooltip.js +1 -1
- package/lib/components/CodeBlock/CodeBlockControls.js +5 -5
- package/lib/components/Menu/variables.js +3 -3
- package/lib/components/Search/SearchAiDialog.d.ts +4 -2
- package/lib/components/Search/SearchAiDialog.js +23 -4
- package/lib/components/Search/SearchAiMessage.d.ts +4 -2
- package/lib/components/Search/SearchAiMessage.js +72 -16
- package/lib/components/Search/SearchDialog.js +1 -1
- package/lib/components/Tooltip/Tooltip.d.ts +2 -3
- package/lib/components/Tooltip/Tooltip.js +66 -113
- package/lib/components/Tooltip/variables.dark.js +4 -0
- package/lib/components/Tooltip/variables.js +3 -3
- package/lib/components/UserMenu/LoginButton.js +1 -1
- package/lib/core/constants/search.d.ts +5 -1
- package/lib/core/constants/search.js +24 -1
- package/lib/core/hooks/use-outside-click.d.ts +3 -1
- package/lib/core/hooks/use-outside-click.js +8 -4
- package/lib/core/types/hooks.d.ts +10 -1
- package/lib/core/types/l10n.d.ts +1 -1
- package/lib/core/types/search.d.ts +24 -0
- package/lib/core/types/search.js +9 -1
- package/lib/core/utils/content-segments.d.ts +2 -0
- package/lib/core/utils/content-segments.js +22 -0
- package/lib/core/utils/index.d.ts +1 -0
- package/lib/core/utils/index.js +1 -0
- package/package.json +7 -7
- package/src/components/Breadcrumbs/Breadcrumb.tsx +3 -3
- package/src/components/Breadcrumbs/BreadcrumbDropdown.tsx +3 -3
- package/src/components/Catalog/CatalogTagsWithTooltip.tsx +3 -3
- package/src/components/CodeBlock/CodeBlockControls.tsx +13 -9
- package/src/components/Menu/variables.ts +3 -3
- package/src/components/Search/SearchAiDialog.tsx +31 -2
- package/src/components/Search/SearchAiMessage.tsx +94 -10
- package/src/components/Search/SearchDialog.tsx +2 -0
- package/src/components/Tooltip/Tooltip.tsx +77 -120
- package/src/components/Tooltip/variables.dark.ts +4 -0
- package/src/components/Tooltip/variables.ts +3 -3
- package/src/components/UserMenu/LoginButton.tsx +2 -2
- package/src/core/constants/search.ts +27 -1
- package/src/core/hooks/__mocks__/use-theme-hooks.ts +9 -1
- package/src/core/hooks/use-outside-click.ts +16 -5
- package/src/core/types/hooks.ts +9 -0
- package/src/core/types/l10n.ts +3 -0
- package/src/core/types/search.ts +19 -0
- package/src/core/utils/content-segments.ts +27 -0
- package/src/core/utils/index.ts +1 -0
- package/lib/components/Tooltip/TooltipWrapper.d.ts +0 -12
- package/lib/components/Tooltip/TooltipWrapper.js +0 -34
- package/src/components/Tooltip/TooltipWrapper.tsx +0 -70
|
@@ -51,7 +51,7 @@ function Breadcrumb({ label, link, isActive, onClick, icon }) {
|
|
|
51
51
|
react_1.default.createElement(BreadcrumbIcon_1.BreadcrumbIcon, { icon: icon }),
|
|
52
52
|
displayLabel));
|
|
53
53
|
const breadcrumbContent = link ? (react_1.default.createElement(BreadcrumbLink, { "data-component-name": "Breadcrumbs/BreadcrumbLink", to: link, onClick: onClick, "$isActive": isActive }, content)) : (react_1.default.createElement(BreadcrumbWrapper, { "data-component-name": "Breadcrumbs/BreadcrumbWrapper", "$isActive": isActive, onClick: onClick, tabIndex: -1 }, content));
|
|
54
|
-
return isTruncated ? (react_1.default.createElement(Tooltip_1.
|
|
54
|
+
return isTruncated ? (react_1.default.createElement(Tooltip_1.Tooltip, { tip: label, placement: "bottom" }, breadcrumbContent)) : (breadcrumbContent);
|
|
55
55
|
}
|
|
56
56
|
const baseBreadcrumbStyles = `
|
|
57
57
|
display: flex;
|
|
@@ -55,7 +55,7 @@ function BreadcrumbDropdown({ children, label, items, onItemClick, className, })
|
|
|
55
55
|
return null;
|
|
56
56
|
}
|
|
57
57
|
const isTruncated = label.length > constants_1.BREADCRUMB_MAX_LENGTH;
|
|
58
|
-
const triggerContent = isTruncated ? (react_1.default.createElement(Tooltip_1.
|
|
58
|
+
const triggerContent = isTruncated ? (react_1.default.createElement(Tooltip_1.Tooltip, { tip: label, placement: "bottom" },
|
|
59
59
|
react_1.default.createElement(TriggerContentWrapper, null, children))) : (children);
|
|
60
60
|
const trigger = react_1.default.createElement(StyledDropdownTrigger, null, triggerContent);
|
|
61
61
|
return (react_1.default.createElement(BreadcrumbDropdownWrapper, { "data-component-name": "Breadcrumbs/BreadcrumbDropdown", className: className, "data-testid": "breadcrumb-dropdown" },
|
|
@@ -27,7 +27,7 @@ function CatalogTagsWithTooltip({ items, itemsToShow = 1, showPlaceholder = true
|
|
|
27
27
|
}
|
|
28
28
|
const displayedItems = items.slice(0, itemsToShow);
|
|
29
29
|
const remainingCount = items.length - itemsToShow;
|
|
30
|
-
return (react_1.default.createElement(Tooltip_1.
|
|
30
|
+
return (react_1.default.createElement(Tooltip_1.Tooltip, { tip: items.join(', '), placement: "bottom", className: "catalog", width: "400px" },
|
|
31
31
|
react_1.default.createElement(CatalogTagsWrapper, { "data-component-name": "Catalog/CatalogTagsWithTooltip" },
|
|
32
32
|
displayedItems.map((item, index) => (react_1.default.createElement(Tag_1.Tag, Object.assign({ key: `${item}-${index}` }, tagProps, { textTransform: "none", maxLength: constants_1.CATALOG_TAG_MAX_LENGTH }),
|
|
33
33
|
react_1.default.createElement(CatalogHighlight_1.CatalogHighlight, null, item)))),
|
|
@@ -8,7 +8,7 @@ const react_1 = __importDefault(require("react"));
|
|
|
8
8
|
const styled_components_1 = __importDefault(require("styled-components"));
|
|
9
9
|
const CodeBlockTabs_1 = require("../../components/CodeBlock/CodeBlockTabs");
|
|
10
10
|
const CopyButton_1 = require("../../components/Buttons/CopyButton");
|
|
11
|
-
const
|
|
11
|
+
const Tooltip_1 = require("../../components/Tooltip/Tooltip");
|
|
12
12
|
const hooks_1 = require("../../core/hooks");
|
|
13
13
|
const DeselectIcon_1 = require("../../icons/DeselectIcon/DeselectIcon");
|
|
14
14
|
const MaximizeIcon_1 = require("../../icons/MaximizeIcon/MaximizeIcon");
|
|
@@ -38,15 +38,15 @@ function CodeBlockControls({ children, className, title, controls, tabs, dropdow
|
|
|
38
38
|
tabs && react_1.default.createElement(CodeBlockTabs_1.CodeBlockTabs, { tabs: tabs }),
|
|
39
39
|
react_1.default.createElement(ControlsWrapper, null,
|
|
40
40
|
dropdown && react_1.default.createElement(CodeBlockDropdown_1.CodeBlockDropdown, Object.assign({}, dropdown)),
|
|
41
|
-
report && !report.hidden && !((_a = report === null || report === void 0 ? void 0 : report.props) === null || _a === void 0 ? void 0 : _a.hide) ? (react_1.default.createElement(
|
|
41
|
+
report && !report.hidden && !((_a = report === null || report === void 0 ? void 0 : report.props) === null || _a === void 0 ? void 0 : _a.hide) ? (react_1.default.createElement(Tooltip_1.Tooltip, { tip: translate('codeSnippet.report.tooltipText', 'Report a problem'), placement: "top", arrowPosition: "right" },
|
|
42
42
|
react_1.default.createElement(ControlButton, Object.assign({ variant: "text", size: "small", "data-testid": "report-button", icon: controlsType === 'icon' ? react_1.default.createElement(WarningSquareIcon_1.WarningSquareIcon, { size: "18px" }) : undefined }, report.props), controlsType != 'icon' && (((_b = report.props) === null || _b === void 0 ? void 0 : _b.buttonText) || 'Report')))) : null,
|
|
43
|
-
expand && !((_c = codeSnippet === null || codeSnippet === void 0 ? void 0 : codeSnippet.expand) === null || _c === void 0 ? void 0 : _c.hide) ? (react_1.default.createElement(
|
|
43
|
+
expand && !((_c = codeSnippet === null || codeSnippet === void 0 ? void 0 : codeSnippet.expand) === null || _c === void 0 ? void 0 : _c.hide) ? (react_1.default.createElement(Tooltip_1.Tooltip, { tip: translate('codeSnippet.expand.tooltipText', 'Expand all'), placement: "top", arrowPosition: "right" },
|
|
44
44
|
react_1.default.createElement(ControlButton, { variant: "text", size: "small", "data-testid": "expand-all", icon: controlsType === 'icon' ? react_1.default.createElement(MaximizeIcon_1.MaximizeIcon, null) : undefined, onClick: expand === null || expand === void 0 ? void 0 : expand.onClick }, controlsType !== 'icon' && ((expand === null || expand === void 0 ? void 0 : expand.label) || 'Expand all')))) : null,
|
|
45
|
-
collapse && !((_d = codeSnippet === null || codeSnippet === void 0 ? void 0 : codeSnippet.collapse) === null || _d === void 0 ? void 0 : _d.hide) ? (react_1.default.createElement(
|
|
45
|
+
collapse && !((_d = codeSnippet === null || codeSnippet === void 0 ? void 0 : codeSnippet.collapse) === null || _d === void 0 ? void 0 : _d.hide) ? (react_1.default.createElement(Tooltip_1.Tooltip, { tip: translate('codeSnippet.collapse.tooltipText', 'Collapse all'), placement: "top", arrowPosition: "right" },
|
|
46
46
|
react_1.default.createElement(ControlButton, { variant: "text", size: "small", "data-testid": "collapse-all", icon: controlsType === 'icon' ? react_1.default.createElement(MinimizeIcon_1.MinimizeIcon, null) : undefined, onClick: collapse === null || collapse === void 0 ? void 0 : collapse.onClick }, controlsType !== 'icon' && ((expand === null || expand === void 0 ? void 0 : expand.label) || 'Collapse all')))) : null,
|
|
47
47
|
select ? (react_1.default.createElement(ControlButton, { variant: "text", size: "small", "data-testid": "select-all", icon: controlsType === 'icon' ? react_1.default.createElement(SelectIcon_1.SelectIcon, null) : undefined, onClick: select === null || select === void 0 ? void 0 : select.onClick }, controlsType !== 'icon' && (select === null || select === void 0 ? void 0 : select.label) ? select.label : 'Select all')) : null,
|
|
48
48
|
deselect ? (react_1.default.createElement(ControlButton, { variant: "text", size: "small", "data-testid": "clear-all", icon: controlsType === 'icon' ? react_1.default.createElement(DeselectIcon_1.DeselectIcon, null) : undefined, onClick: deselect === null || deselect === void 0 ? void 0 : deselect.onClick }, controlsType !== 'icon' && (deselect === null || deselect === void 0 ? void 0 : deselect.label) ? deselect.label : 'Clear all')) : null,
|
|
49
|
-
copy && !((_e = codeSnippet === null || codeSnippet === void 0 ? void 0 : codeSnippet.copy) === null || _e === void 0 ? void 0 : _e.hide) ? (react_1.default.createElement(
|
|
49
|
+
copy && !((_e = codeSnippet === null || codeSnippet === void 0 ? void 0 : codeSnippet.copy) === null || _e === void 0 ? void 0 : _e.hide) ? (react_1.default.createElement(Tooltip_1.Tooltip, { tip: translate('codeSnippet.copy.tooltipText', 'Copy to clipboard'), placement: "top", arrowPosition: "right" },
|
|
50
50
|
react_1.default.createElement(StyledCopyButton, { data: copy.data, "data-source": copy.dataSource, "data-hash": copy.dataHash, type: controlsType, toasterPlacement: copy.toasterPlacement, toasterDuration: copy.toasterDuration, buttonText: copy.label, onCopyClick: () => {
|
|
51
51
|
var _a;
|
|
52
52
|
// If there already is a click handler, events should be handled there, cause they pass additional data
|
|
@@ -131,12 +131,12 @@ exports.mobileMenu = (0, styled_components_1.css) `
|
|
|
131
131
|
* @tokens Mobile Menu
|
|
132
132
|
* */
|
|
133
133
|
/* Fallback for older browsers. dvh accounts for dynamic UI elements like mobile address bars */
|
|
134
|
-
--menu-mobile-height: calc(100vh - var(--navbar-height));
|
|
135
|
-
--menu-mobile-height: calc(100dvh - var(--navbar-height));
|
|
134
|
+
--menu-mobile-height: calc(100vh - var(--navbar-height) - var(--banner-height));
|
|
135
|
+
--menu-mobile-height: calc(100dvh - var(--navbar-height) - var(--banner-height));
|
|
136
136
|
--menu-mobile-width: 100%;
|
|
137
137
|
--menu-mobile-z-index: var(--z-index-raised);
|
|
138
138
|
--menu-mobile-left: 0;
|
|
139
|
-
--menu-mobile-top: var(--navbar-height);
|
|
139
|
+
--menu-mobile-top: calc(var(--navbar-height) + var(--banner-height));
|
|
140
140
|
--menu-mobile-transition: 0.5s;
|
|
141
141
|
--menu-mobile-bg: var(--bg-color); // @presenter Color
|
|
142
142
|
--menu-mobile-margin: var(--menu-mobile-items-margin-top) var(--menu-mobile-margin-horizontal) 0 var(--menu-mobile-margin-horizontal);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { JSX } from 'react';
|
|
3
|
-
import type { AiSearchConversationItem, SearchAiMessageResource } from '../../core/types';
|
|
3
|
+
import type { AiSearchConversationItem, SearchAiMessageResource, ToolCall, ContentSegment } from '../../core/types';
|
|
4
4
|
import { AiSearchError } from '../../core/constants';
|
|
5
5
|
export type SearchAiDialogProps = {
|
|
6
6
|
response: string | undefined;
|
|
@@ -12,5 +12,7 @@ export type SearchAiDialogProps = {
|
|
|
12
12
|
conversation: AiSearchConversationItem[];
|
|
13
13
|
setConversation: React.Dispatch<React.SetStateAction<AiSearchConversationItem[]>>;
|
|
14
14
|
onMessageSent: (message: string, history?: AiSearchConversationItem[], messageId?: string) => void;
|
|
15
|
+
toolCalls?: ToolCall[];
|
|
16
|
+
contentSegments?: ContentSegment[];
|
|
15
17
|
};
|
|
16
|
-
export declare function SearchAiDialog({ isGeneratingResponse, response, initialMessage, error, resources, onMessageSent, className, conversation, setConversation, }: SearchAiDialogProps): JSX.Element;
|
|
18
|
+
export declare function SearchAiDialog({ isGeneratingResponse, response, initialMessage, error, resources, onMessageSent, className, conversation, setConversation, toolCalls, contentSegments, }: SearchAiDialogProps): JSX.Element;
|
|
@@ -46,7 +46,7 @@ const constants_1 = require("../../core/constants");
|
|
|
46
46
|
const SearchAiMessage_1 = require("../../components/Search/SearchAiMessage");
|
|
47
47
|
const Admonition_1 = require("../../components/Admonition/Admonition");
|
|
48
48
|
const AiStarsIcon_1 = require("../../icons/AiStarsIcon/AiStarsIcon");
|
|
49
|
-
function SearchAiDialog({ isGeneratingResponse, response, initialMessage, error, resources, onMessageSent, className, conversation, setConversation, }) {
|
|
49
|
+
function SearchAiDialog({ isGeneratingResponse, response, initialMessage, error, resources, onMessageSent, className, conversation, setConversation, toolCalls = [], contentSegments, }) {
|
|
50
50
|
const { useTranslate } = (0, hooks_1.useThemeHooks)();
|
|
51
51
|
const { aiAssistant } = (0, hooks_1.useThemeConfig)();
|
|
52
52
|
const { translate } = useTranslate();
|
|
@@ -99,12 +99,31 @@ function SearchAiDialog({ isGeneratingResponse, response, initialMessage, error,
|
|
|
99
99
|
content,
|
|
100
100
|
resources,
|
|
101
101
|
messageId: lastMessage.messageId,
|
|
102
|
+
toolCalls,
|
|
103
|
+
contentSegments,
|
|
102
104
|
},
|
|
103
105
|
];
|
|
104
106
|
}
|
|
105
|
-
return [
|
|
107
|
+
return [
|
|
108
|
+
...prev,
|
|
109
|
+
{
|
|
110
|
+
role: constants_1.AiSearchConversationRole.ASSISTANT,
|
|
111
|
+
content,
|
|
112
|
+
resources,
|
|
113
|
+
toolCalls,
|
|
114
|
+
contentSegments,
|
|
115
|
+
},
|
|
116
|
+
];
|
|
106
117
|
});
|
|
107
|
-
}, [
|
|
118
|
+
}, [
|
|
119
|
+
response,
|
|
120
|
+
conversation.length,
|
|
121
|
+
error,
|
|
122
|
+
resources,
|
|
123
|
+
toolCalls,
|
|
124
|
+
contentSegments,
|
|
125
|
+
setConversation,
|
|
126
|
+
]);
|
|
108
127
|
(0, react_1.useEffect)(() => {
|
|
109
128
|
if (error) {
|
|
110
129
|
setConversation((prev) => prev.slice(0, -1));
|
|
@@ -123,7 +142,7 @@ function SearchAiDialog({ isGeneratingResponse, response, initialMessage, error,
|
|
|
123
142
|
react_1.default.createElement(ConversationWrapper, null,
|
|
124
143
|
conversation.map((item, index) => (react_1.default.createElement(SearchAiMessage_1.SearchAiMessage, { key: `search-ai-message-${index}`, role: item.role, content: item.content, isThinking: item.role === constants_1.AiSearchConversationRole.ASSISTANT &&
|
|
125
144
|
isGeneratingResponse &&
|
|
126
|
-
index === conversation.length - 1, resources: item.resources, messageId: item.messageId, feedback: item.feedback, onFeedbackChange: handleFeedbackChange }))),
|
|
145
|
+
index === conversation.length - 1, resources: item.resources, messageId: item.messageId, feedback: item.feedback, onFeedbackChange: handleFeedbackChange, toolCalls: item.toolCalls || (index === conversation.length - 1 ? toolCalls : undefined), contentSegments: item.contentSegments }))),
|
|
127
146
|
error && (react_1.default.createElement(Admonition_1.Admonition, { type: "danger", name: translate(constants_1.AI_SEARCH_ERROR_CONFIG[error].headerKey, constants_1.AI_SEARCH_ERROR_CONFIG[error].headerDefault) }, translate(constants_1.AI_SEARCH_ERROR_CONFIG[error].messageKey, constants_1.AI_SEARCH_ERROR_CONFIG[error].messageDefault))),
|
|
128
147
|
!conversation.length && !error && (react_1.default.createElement(SuggestionsWrapper, null, suggestions === null || suggestions === void 0 ? void 0 : suggestions.map((suggestion) => (react_1.default.createElement(Button_1.Button, { key: suggestion, variant: "outlined", onClick: () => handleOnMessageSent(suggestion) }, suggestion))))),
|
|
129
148
|
react_1.default.createElement("div", { ref: conversationEndRef })),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { JSX } from 'react';
|
|
3
|
-
import { FeedbackType, type SearchAiMessageResource } from '../../core/types';
|
|
3
|
+
import { FeedbackType, type SearchAiMessageResource, type ToolCall, type ContentSegment } from '../../core/types';
|
|
4
4
|
import { AiSearchConversationRole } from '../../core/constants';
|
|
5
5
|
export type SearchAiMessageProps = {
|
|
6
6
|
role: AiSearchConversationRole;
|
|
@@ -11,7 +11,9 @@ export type SearchAiMessageProps = {
|
|
|
11
11
|
messageId?: string;
|
|
12
12
|
feedback?: FeedbackType;
|
|
13
13
|
onFeedbackChange: (messageId: string, feedback: FeedbackType | undefined) => void;
|
|
14
|
+
toolCalls?: ToolCall[];
|
|
15
|
+
contentSegments?: ContentSegment[];
|
|
14
16
|
};
|
|
15
|
-
declare function SearchAiMessageComponent({ role, content, isThinking, resources, className, messageId, feedback, onFeedbackChange, }: SearchAiMessageProps): JSX.Element;
|
|
17
|
+
declare function SearchAiMessageComponent({ role, content, isThinking, resources, className, messageId, feedback, onFeedbackChange, toolCalls, contentSegments, }: SearchAiMessageProps): JSX.Element;
|
|
16
18
|
export declare const SearchAiMessage: React.MemoExoticComponent<typeof SearchAiMessageComponent>;
|
|
17
19
|
export {};
|
|
@@ -40,9 +40,10 @@ exports.SearchAiMessage = void 0;
|
|
|
40
40
|
const react_1 = __importStar(require("react"));
|
|
41
41
|
const styled_components_1 = __importDefault(require("styled-components"));
|
|
42
42
|
const types_1 = require("../../core/types");
|
|
43
|
+
const constants_1 = require("../../core/constants");
|
|
43
44
|
const Link_1 = require("../../components/Link/Link");
|
|
44
45
|
const Tag_1 = require("../../components/Tag/Tag");
|
|
45
|
-
const
|
|
46
|
+
const constants_2 = require("../../core/constants");
|
|
46
47
|
const hooks_1 = require("../../core/hooks");
|
|
47
48
|
const Markdown_1 = require("../../components/Markdown/Markdown");
|
|
48
49
|
const DocumentIcon_1 = require("../../icons/DocumentIcon/DocumentIcon");
|
|
@@ -50,16 +51,21 @@ const AiStarsIcon_1 = require("../../icons/AiStarsIcon/AiStarsIcon");
|
|
|
50
51
|
const CheckmarkOutlineIcon_1 = require("../../icons/CheckmarkOutlineIcon/CheckmarkOutlineIcon");
|
|
51
52
|
const SearchAiActionButtons_1 = require("../../components/Search/SearchAiActionButtons");
|
|
52
53
|
const SearchAiNegativeFeedbackForm_1 = require("../../components/Search/SearchAiNegativeFeedbackForm");
|
|
53
|
-
function
|
|
54
|
+
function MarkdownSegment({ text }) {
|
|
55
|
+
const { useMarkdownText } = (0, hooks_1.useThemeHooks)();
|
|
56
|
+
const markdown = useMarkdownText(text);
|
|
57
|
+
return react_1.default.createElement(ResponseText, { as: "div", children: markdown, "data-testid": "response-text" });
|
|
58
|
+
}
|
|
59
|
+
function SearchAiMessageComponent({ role, content, isThinking, resources, className, messageId, feedback, onFeedbackChange, toolCalls = [], contentSegments = [{ type: 'text', text: content }], }) {
|
|
54
60
|
var _a;
|
|
55
|
-
const {
|
|
56
|
-
const markDownContent = useMarkdownText(content || '');
|
|
61
|
+
const { useTranslate, useTelemetry } = (0, hooks_1.useThemeHooks)();
|
|
57
62
|
const { translate } = useTranslate();
|
|
58
63
|
const telemetry = useTelemetry();
|
|
59
64
|
const [feedbackSent, setFeedbackSent] = (0, react_1.useState)(false);
|
|
60
65
|
const hasResources = !isThinking && resources && resources.length > 0;
|
|
61
66
|
const resourcesCount = (_a = resources === null || resources === void 0 ? void 0 : resources.length) !== null && _a !== void 0 ? _a : 0;
|
|
62
67
|
const showSuccessMessage = feedbackSent && feedback;
|
|
68
|
+
const isLoading = isThinking && content.length === 0 && toolCalls.length === 0;
|
|
63
69
|
const sendFeedbackTelemetry = (feedbackValue, dislikeReason) => {
|
|
64
70
|
if (!messageId)
|
|
65
71
|
return;
|
|
@@ -90,10 +96,25 @@ function SearchAiMessageComponent({ role, content, isThinking, resources, classN
|
|
|
90
96
|
}
|
|
91
97
|
};
|
|
92
98
|
return (react_1.default.createElement(SearchAiMessageWrapper, { "data-component-name": "Search/SearchAiMessage", role: role, className: className, "data-testid": "search-ai-message" },
|
|
93
|
-
role ===
|
|
94
|
-
react_1.default.createElement(MessageContentWrapper, null, role ===
|
|
99
|
+
role === constants_2.AiSearchConversationRole.ASSISTANT && (react_1.default.createElement(AiStarsIcon_1.AiStarsIcon, { size: "32px", background: "var(--search-ai-icon-bg-color)", borderRadius: "var(--border-radius-lg)", color: "var(--search-ai-icon-color)", margin: "0 var(--spacing-xs) 0 0" })),
|
|
100
|
+
react_1.default.createElement(MessageContentWrapper, null, role === constants_2.AiSearchConversationRole.ASSISTANT ? (react_1.default.createElement(react_1.default.Fragment, null,
|
|
95
101
|
react_1.default.createElement(MessageWrapper, { role: role },
|
|
96
|
-
|
|
102
|
+
contentSegments.map((segment, index) => {
|
|
103
|
+
var _a, _b, _c, _d, _e, _f;
|
|
104
|
+
if (segment.type === 'tool') {
|
|
105
|
+
const toolCallCompleted = Boolean(segment.toolCall.result);
|
|
106
|
+
const toolCallCompletedText = (_b = (_a = constants_1.TOOL_CALL_DISPLAY_TEXT[segment.toolCall.name]) === null || _a === void 0 ? void 0 : _a.completedText) !== null && _b !== void 0 ? _b : `${translate('search.ai.toolResult.found', 'Found')} ${(_d = (_c = segment.toolCall.result) === null || _c === void 0 ? void 0 : _c.documentCount) !== null && _d !== void 0 ? _d : 0} ${translate('search.ai.toolResult.found.documents', 'documents')}`;
|
|
107
|
+
const toolCallInProgressText = (_f = (_e = constants_1.TOOL_CALL_DISPLAY_TEXT[segment.toolCall.name]) === null || _e === void 0 ? void 0 : _e.inProgressText) !== null && _f !== void 0 ? _f : translate('search.ai.toolCall.searching', 'Searching...');
|
|
108
|
+
const toolCallDisplayText = toolCallCompleted
|
|
109
|
+
? toolCallCompletedText
|
|
110
|
+
: toolCallInProgressText;
|
|
111
|
+
return (react_1.default.createElement(ToolCallsInfoWrapper, { key: `tool-${index}`, "data-testid": "tool-calls-info" },
|
|
112
|
+
react_1.default.createElement(ToolCallInfoItem, null,
|
|
113
|
+
react_1.default.createElement(DocumentIcon_1.DocumentIcon, { size: "14px", color: "--search-ai-text-color" }),
|
|
114
|
+
react_1.default.createElement(ToolCallText, { "$isSearching": !toolCallCompleted }, toolCallDisplayText))));
|
|
115
|
+
}
|
|
116
|
+
return react_1.default.createElement(MarkdownSegment, { key: `text-${index}`, text: segment.text });
|
|
117
|
+
}),
|
|
97
118
|
hasResources && (react_1.default.createElement(react_1.default.Fragment, null,
|
|
98
119
|
react_1.default.createElement(ResourcesWrapper, { "data-testid": "resources-wrapper" },
|
|
99
120
|
react_1.default.createElement(ResourcesTitle, { "data-translation-key": "search.ai.resourcesFound" },
|
|
@@ -102,9 +123,9 @@ function SearchAiMessageComponent({ role, content, isThinking, resources, classN
|
|
|
102
123
|
resourcesCount,
|
|
103
124
|
' ',
|
|
104
125
|
translate('search.ai.resourcesFound.resources', 'resources')),
|
|
105
|
-
react_1.default.createElement(ResourceTagsWrapper, null, resources === null || resources === void 0 ? void 0 : resources.map((resource,
|
|
126
|
+
react_1.default.createElement(ResourceTagsWrapper, null, resources === null || resources === void 0 ? void 0 : resources.map((resource, index) => (react_1.default.createElement(Link_1.Link, { key: `${resource.url}-${index}`, to: resource.url, target: "_blank" },
|
|
106
127
|
react_1.default.createElement(ResourceTag, { borderless: true, icon: react_1.default.createElement(DocumentIcon_1.DocumentIcon, { color: "--search-ai-resource-tag-icon-color" }) }, resource.title)))))))),
|
|
107
|
-
|
|
128
|
+
isLoading && (react_1.default.createElement(ThinkingDotsWrapper, { "data-testid": "thinking-dots-wrapper" },
|
|
108
129
|
react_1.default.createElement(ThinkingDot, null),
|
|
109
130
|
react_1.default.createElement(ThinkingDot, null),
|
|
110
131
|
react_1.default.createElement(ThinkingDot, null))),
|
|
@@ -129,20 +150,23 @@ function areResourcesEqual(prev, next) {
|
|
|
129
150
|
});
|
|
130
151
|
}
|
|
131
152
|
exports.SearchAiMessage = (0, react_1.memo)(SearchAiMessageComponent, (prevProps, nextProps) => {
|
|
153
|
+
var _a, _b;
|
|
132
154
|
return (prevProps.role === nextProps.role &&
|
|
133
155
|
prevProps.content === nextProps.content &&
|
|
134
156
|
prevProps.isThinking === nextProps.isThinking &&
|
|
135
157
|
prevProps.messageId === nextProps.messageId &&
|
|
136
158
|
prevProps.feedback === nextProps.feedback &&
|
|
137
159
|
prevProps.onFeedbackChange === nextProps.onFeedbackChange &&
|
|
138
|
-
areResourcesEqual(prevProps.resources, nextProps.resources)
|
|
160
|
+
areResourcesEqual(prevProps.resources, nextProps.resources) &&
|
|
161
|
+
((_a = prevProps.toolCalls) === null || _a === void 0 ? void 0 : _a.length) === ((_b = nextProps.toolCalls) === null || _b === void 0 ? void 0 : _b.length) &&
|
|
162
|
+
prevProps.contentSegments === nextProps.contentSegments);
|
|
139
163
|
});
|
|
140
164
|
const SearchAiMessageWrapper = styled_components_1.default.div `
|
|
141
165
|
display: flex;
|
|
142
166
|
flex-direction: row;
|
|
143
167
|
align-items: flex-start;
|
|
144
168
|
width: 100%;
|
|
145
|
-
justify-content: ${({ role }) => role ===
|
|
169
|
+
justify-content: ${({ role }) => role === constants_2.AiSearchConversationRole.USER ? 'flex-end' : 'flex-start'};
|
|
146
170
|
`;
|
|
147
171
|
const MessageContentWrapper = styled_components_1.default.div `
|
|
148
172
|
display: flex;
|
|
@@ -168,18 +192,19 @@ const ResponseText = (0, styled_components_1.default)(Markdown_1.Markdown) `
|
|
|
168
192
|
}
|
|
169
193
|
`;
|
|
170
194
|
const MessageWrapper = styled_components_1.default.div `
|
|
171
|
-
padding: ${({ role }) => role ===
|
|
172
|
-
var(--spacing-sm)
|
|
195
|
+
padding: ${({ role }) => role === constants_2.AiSearchConversationRole.USER
|
|
196
|
+
? 'var(--spacing-sm)'
|
|
197
|
+
: 'var(--spacing-sm) var(--spacing-sm) var(--spacing-xs) var(--spacing-sm)'};
|
|
173
198
|
border-radius: var(--border-radius-lg);
|
|
174
199
|
width: fit-content;
|
|
175
200
|
max-width: 100%;
|
|
176
201
|
word-wrap: break-word;
|
|
177
202
|
white-space: pre-wrap;
|
|
178
|
-
background-color: ${({ role }) => role ===
|
|
203
|
+
background-color: ${({ role }) => role === constants_2.AiSearchConversationRole.USER
|
|
179
204
|
? 'var(--search-ai-user-bg-color)'
|
|
180
205
|
: 'var(--search-ai-assistant-bg-color)'};
|
|
181
|
-
border: ${({ role }) => role ===
|
|
182
|
-
color: ${({ role }) => role ===
|
|
206
|
+
border: ${({ role }) => role === constants_2.AiSearchConversationRole.USER ? 'none' : 'var(--search-ai-assistant-border)'};
|
|
207
|
+
color: ${({ role }) => role === constants_2.AiSearchConversationRole.USER
|
|
183
208
|
? 'var(--search-ai-user-text-color)'
|
|
184
209
|
: 'var(--search-ai-assistant-text-color)'};
|
|
185
210
|
`;
|
|
@@ -273,4 +298,35 @@ const SuccessMessageText = styled_components_1.default.div `
|
|
|
273
298
|
font-size: var(--font-size-base);
|
|
274
299
|
color: var(--color-success-darker);
|
|
275
300
|
`;
|
|
301
|
+
const ToolCallsInfoWrapper = styled_components_1.default.div `
|
|
302
|
+
display: flex;
|
|
303
|
+
flex-direction: column;
|
|
304
|
+
gap: var(--spacing-xxs);
|
|
305
|
+
margin: 0 0 var(--spacing-sm) 0;
|
|
306
|
+
font-size: var(--font-size-xs);
|
|
307
|
+
color: var(--search-ai-text-color);
|
|
308
|
+
opacity: 0.6;
|
|
309
|
+
`;
|
|
310
|
+
const ToolCallInfoItem = styled_components_1.default.div `
|
|
311
|
+
display: flex;
|
|
312
|
+
align-items: center;
|
|
313
|
+
gap: var(--spacing-xxs);
|
|
314
|
+
`;
|
|
315
|
+
const ToolCallText = styled_components_1.default.span `
|
|
316
|
+
font-weight: var(--font-weight-regular);
|
|
317
|
+
|
|
318
|
+
${({ $isSearching }) => $isSearching &&
|
|
319
|
+
`
|
|
320
|
+
animation: pulse 1.5s ease-in-out infinite;
|
|
321
|
+
|
|
322
|
+
@keyframes pulse {
|
|
323
|
+
0%, 100% {
|
|
324
|
+
opacity: 1;
|
|
325
|
+
}
|
|
326
|
+
50% {
|
|
327
|
+
opacity: 0.4;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
`}
|
|
331
|
+
`;
|
|
276
332
|
//# sourceMappingURL=SearchAiMessage.js.map
|
|
@@ -287,7 +287,7 @@ function SearchDialog({ onClose, className, initialMode = 'search', }) {
|
|
|
287
287
|
setQuery(query);
|
|
288
288
|
focusSearchInput();
|
|
289
289
|
} }),
|
|
290
|
-
react_1.default.createElement(SearchSuggestedPages_1.SearchSuggestedPages, null)))))) : (react_1.default.createElement(SearchAiDialog_1.SearchAiDialog, { initialMessage: query, response: aiSearch.response, isGeneratingResponse: aiSearch.isGeneratingResponse, error: aiSearch.error, resources: aiSearch.resources, conversation: aiSearch.conversation, setConversation: aiSearch.setConversation, onMessageSent: aiSearch.askQuestion }))),
|
|
290
|
+
react_1.default.createElement(SearchSuggestedPages_1.SearchSuggestedPages, null)))))) : (react_1.default.createElement(SearchAiDialog_1.SearchAiDialog, { initialMessage: query, response: aiSearch.response, isGeneratingResponse: aiSearch.isGeneratingResponse, error: aiSearch.error, resources: aiSearch.resources, conversation: aiSearch.conversation, setConversation: aiSearch.setConversation, onMessageSent: aiSearch.askQuestion, toolCalls: aiSearch.toolCalls, contentSegments: aiSearch.contentSegments }))),
|
|
291
291
|
react_1.default.createElement(SearchDialogFooter, null, mode === 'ai-dialog' ? (react_1.default.createElement(AiDisclaimer, null, translate('search.ai.disclaimer', 'AI search might provide incomplete or incorrect results. Verify important information.'))) : (react_1.default.createElement(react_1.default.Fragment, null,
|
|
292
292
|
react_1.default.createElement(SearchShortcuts, null,
|
|
293
293
|
react_1.default.createElement(SearchShortcut_1.SearchShortcut, { "data-translation-key": "search.keys.navigate", combination: "Tab", text: translate('search.keys.navigate', 'to navigate') }),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import type {
|
|
2
|
+
import type { ReactNode } from 'react';
|
|
3
3
|
export type TooltipProps = {
|
|
4
4
|
tip: string | ReactNode;
|
|
5
5
|
isOpen?: boolean;
|
|
@@ -9,7 +9,6 @@ export type TooltipProps = {
|
|
|
9
9
|
width?: string;
|
|
10
10
|
dataTestId?: string;
|
|
11
11
|
disabled?: boolean;
|
|
12
|
-
arrowPosition?: '
|
|
12
|
+
arrowPosition?: 'left' | 'right' | 'center';
|
|
13
13
|
};
|
|
14
|
-
export declare function TooltipComponent({ children, isOpen, tip, withArrow, placement, className, width, dataTestId, disabled, arrowPosition, }: PropsWithChildren<TooltipProps>): JSX.Element;
|
|
15
14
|
export declare const Tooltip: React.NamedExoticComponent<React.PropsWithChildren<TooltipProps>>;
|