@redocly/theme
Version:
Shared UI components lib
204 lines (203 loc) • 9.67 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SearchAiDialog = SearchAiDialog;
const react_1 = __importStar(require("react"));
const styled_components_1 = __importDefault(require("styled-components"));
const hooks_1 = require("../../core/hooks");
const Button_1 = require("../../components/Button/Button");
const SearchAiConversationInput_1 = require("../../components/Search/SearchAiConversationInput");
const constants_1 = require("../../core/constants");
const SearchAiMessage_1 = require("../../components/Search/SearchAiMessage");
const Admonition_1 = require("../../components/Admonition/Admonition");
const AiStarsIcon_1 = require("../../icons/AiStarsIcon/AiStarsIcon");
function SearchAiDialog({ isGeneratingResponse, response, initialMessage, error, resources, onMessageSent, className, conversation, setConversation, toolCalls = [], contentSegments, }) {
const { useTranslate } = (0, hooks_1.useThemeHooks)();
const { aiAssistant } = (0, hooks_1.useThemeConfig)();
const { translate } = useTranslate();
const conversationEndRef = react_1.default.useRef(null);
const suggestions = aiAssistant === null || aiAssistant === void 0 ? void 0 : aiAssistant.suggestions;
const placeholder = isGeneratingResponse
? translate('search.ai.generatingResponse', 'Generating response...')
: conversation.length > 0
? translate('search.ai.followUpQuestion', 'Ask a follow up question?')
: translate('search.ai.placeholder', 'Ask a question...');
const scrollToBottom = (0, react_1.useCallback)(() => {
var _a;
(_a = conversationEndRef.current) === null || _a === void 0 ? void 0 : _a.scrollIntoView({ block: 'end' });
}, []);
const handleOnMessageSent = (0, react_1.useCallback)((message) => {
if (!message.trim()) {
return;
}
const mappedHistory = conversation.map(({ role, content }) => ({
role,
content,
}));
onMessageSent(message, mappedHistory);
setConversation((prev) => [
...prev,
{ role: constants_1.AiSearchConversationRole.USER, content: message },
]);
}, [conversation, onMessageSent, setConversation]);
(0, react_1.useEffect)(() => {
if (!(initialMessage === null || initialMessage === void 0 ? void 0 : initialMessage.trim().length)) {
return;
}
setConversation((prev) => [
...prev,
{ role: constants_1.AiSearchConversationRole.USER, content: initialMessage },
]);
}, [initialMessage, setConversation]);
(0, react_1.useEffect)(() => {
if (response === undefined || conversation.length === 0 || error) {
return;
}
setConversation((prev) => {
const lastMessage = prev[prev.length - 1];
const content = response || '';
if (lastMessage && lastMessage.role === constants_1.AiSearchConversationRole.ASSISTANT) {
return [
...prev.slice(0, -1),
{
role: constants_1.AiSearchConversationRole.ASSISTANT,
content,
resources,
messageId: lastMessage.messageId,
toolCalls,
contentSegments,
},
];
}
return [
...prev,
{
role: constants_1.AiSearchConversationRole.ASSISTANT,
content,
resources,
toolCalls,
contentSegments,
},
];
});
}, [
response,
conversation.length,
error,
resources,
toolCalls,
contentSegments,
setConversation,
]);
(0, react_1.useEffect)(() => {
if (error) {
setConversation((prev) => prev.slice(0, -1));
}
}, [error, setConversation]);
(0, react_1.useEffect)(() => {
scrollToBottom();
}, [conversation, isGeneratingResponse, scrollToBottom]);
const handleFeedbackChange = (0, react_1.useCallback)((messageId, feedback) => {
setConversation((prev) => prev.map((item) => (item.messageId === messageId ? Object.assign(Object.assign({}, item), { feedback }) : item)));
}, [setConversation]);
return (react_1.default.createElement(SearchAiDialogWrapper, { "data-component-name": "Search/SearchAiDialog", className: className },
!conversation.length && (react_1.default.createElement(WelcomeWrapper, null,
react_1.default.createElement(AiStarsIcon_1.AiStarsIcon, { color: "var(--search-ai-icon-color)", size: "32px", background: "var(--search-ai-icon-bg-color)", borderRadius: "var(--border-radius-lg)", margin: "0 var(--spacing-xs) 0 0" }),
translate('search.ai.welcomeText', 'Welcome to AI search! Feel free to ask me anything. How can I help you? '))),
react_1.default.createElement(ConversationWrapper, null,
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 &&
isGeneratingResponse &&
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 }))),
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))),
!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))))),
react_1.default.createElement("div", { ref: conversationEndRef })),
react_1.default.createElement(ConversationInputWrapper, null,
react_1.default.createElement(SearchAiConversationInput_1.SearchAiConversationInput, { onMessageSent: handleOnMessageSent, isGeneratingResponse: isGeneratingResponse, placeholder: placeholder }))));
}
const SearchAiDialogWrapper = styled_components_1.default.div `
display: flex;
flex-direction: column;
flex: 1 1 auto;
width: 100%;
min-width: 0;
min-height: 0;
position: relative;
background: var(--search-ai-dialog-bg-color);
overflow: hidden;
`;
const ConversationWrapper = styled_components_1.default.div `
flex: 1 1 auto;
overflow-y: auto;
overflow-x: hidden;
padding: var(--search-ai-dialog-body-padding);
padding-bottom: 0;
display: flex;
flex-direction: column;
align-items: stretch;
gap: var(--search-ai-dialog-body-gap);
min-height: 0;
> :first-child {
margin-top: auto;
}
> :last-child {
margin-bottom: 0;
gap: 0;
}
`;
const SuggestionsWrapper = styled_components_1.default.div `
display: flex;
flex-direction: row;
flex-wrap: wrap;
gap: var(--search-ai-suggestions-gap);
align-items: center;
justify-content: center;
`;
const ConversationInputWrapper = styled_components_1.default.div `
padding: var(--search-ai-dialog-input-padding);
border-top: var(--search-ai-dialog-input-border);
background: var(--search-ai-dialog-input-bg-color);
`;
const WelcomeWrapper = styled_components_1.default.div `
display: flex;
flex-direction: row;
align-items: center;
width: auto;
margin: var(--search-ai-welcome-margin);
position: relative;
`;
//# sourceMappingURL=SearchAiDialog.js.map