Skip to content

Commit

Permalink
Merge pull request #9518 from weseek/feat/159531-chat-modal
Browse files Browse the repository at this point in the history
feat: Chat Modal
  • Loading branch information
yuki-takei authored Dec 25, 2024
2 parents 67fa754 + a65c48d commit 436b76b
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 33 deletions.
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import type { KeyboardEvent } from 'react';
import React, { useCallback, useEffect, useState } from 'react';
import React, { useCallback, useState } from 'react';

import { useForm, Controller } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import {
Collapse,
Modal, ModalBody, ModalFooter, ModalHeader,
UncontrolledTooltip,
UncontrolledTooltip, Input,
} from 'reactstrap';

import { apiv3Post } from '~/client/util/apiv3-client';
import { toastError } from '~/client/util/toastr';
import { useGrowiCloudUri } from '~/stores-universal/context';
import loggerFactory from '~/utils/logger';

import { SelectedPageList } from '../../../client/components/Common/SelectedPageList';
import { useRagSearchModal } from '../../../client/stores/rag-search';
import { MessageErrorCode, StreamErrorCode } from '../../../interfaces/message-error';

Expand Down Expand Up @@ -193,7 +194,46 @@ const AiChatModalSubstance = (): JSX.Element => {
return (
<>
<ModalBody className="pb-0 pt-3 pt-lg-4 px-3 px-lg-4">
<div className="vstack gap-4 pb-4">
<div className="d-flex mb-4">
<Input type="select" className="border rounded">
<option>
GROWI AI の機能について
</option>
</Input>

<button type="button" className="btn btn-outline-secondary bg-transparent ms-2">
<span className="fs-5 material-symbols-outlined">edit</span>
</button>

<button type="button" className="btn btn-outline-secondary bg-transparent ms-2">
<span className="fs-5 material-symbols-outlined">add</span>
</button>
</div>

<div className="text-muted mb-4">
ここに設定したアシスタントの説明が入ります。ここに設定したアシスタントの説明が入ります。
</div>

<div className="mb-4">
<p className="mb-2">アシスタントへの指示</p>
<div className="p-3 alert alert-primary">
<p className="mb-0 text-break">
あなたは生成AIの専門家および、リサーチャーです。ナレッジベースのWikiツールである GROWIのAI機能に関する情報を提示したり、使われている技術に関する説明をしたりします。
</p>
</div>
</div>

<div className="d-flex align-items-center mb-2">
<p className="mb-0">参照するページ</p>
<span className="ms-1 fs-5 material-symbols-outlined text-secondary">help</span>
</div>
<SelectedPageList selectedPages={[
{ page: { _id: '1', path: '/Project/GROWI/新機能/GROWI AI' }, isIncludeSubPage: true },
{ page: { _id: '2', path: '/AI導入検討/調査' }, isIncludeSubPage: false },
]}
/>

<div className="vstack gap-4 pb-2">
{ messageLogs.map(message => (
<MessageCard key={message.id} role={message.isUserMessage ? 'user' : 'assistant'}>{message.content}</MessageCard>
)) }
Expand Down Expand Up @@ -315,7 +355,7 @@ export const AiChatModal = (): JSX.Element => {
<Modal size="lg" isOpen={isOpened} toggle={closeRagSearchModal} className={moduleClass} scrollable>

<ModalHeader tag="h4" toggle={closeRagSearchModal} className="pe-4">
<span className="growi-custom-icons growi-ai-chat-icon me-3 fs-4">knowledge_assistant</span>
<span className="growi-custom-icons growi-ai-chat-icon me-3 fs-4">ai_assistant</span>
<span className="fw-bold">{t('modal_aichat.title')}</span>
<span className="fs-5 text-body-secondary ms-3">{t('modal_aichat.title_beta_label')}</span>
</ModalHeader>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { memo, useCallback, useState } from 'react';
import React, { useCallback, useState } from 'react';

import { useTranslation } from 'react-i18next';
import {
Expand All @@ -8,42 +8,19 @@ import {
import type { IPageForItem } from '~/interfaces/page';
import { usePageSelectModal } from '~/stores/modal';

import type { SelectedPage } from '../../../interfaces/selected-page';
import { useAiAssistantManegementModal } from '../../stores/ai-assistant';
import { SelectedPageList } from '../Common/SelectedPageList';

import styles from './AiAssistantManegementModal.module.scss';

const moduleClass = styles['grw-ai-assistant-manegement'] ?? '';


type SelectedPage = {
page: IPageForItem,
isIncludeSubPage: boolean,
}

const SelectedPageList = memo(({ selectedPages }: { selectedPages: SelectedPage[] }): JSX.Element => {
const { t } = useTranslation();

if (selectedPages.length === 0) {
return <></>;
}

return (
<div className="mb-3">
{selectedPages.map(({ page, isIncludeSubPage }) => (
<p key={page._id} className="mb-1">
<code>{ page.path }</code>
{isIncludeSubPage && <span className="badge rounded-pill text-bg-secondary ms-2">{t('Include Subordinated Page')}</span>}
</p>
))}
</div>
);
});

const AiAssistantManegementModalSubstance = (): JSX.Element => {
const { open: openPageSelectModal } = usePageSelectModal();
const [selectedPages, setSelectedPages] = useState<SelectedPage[]>([]);

const onClickOpenPageSelectModalButton = useCallback(() => {
const clickOpenPageSelectModalHandler = useCallback(() => {
const onSelected = (page: IPageForItem, isIncludeSubPage: boolean) => {
const selectedPageIds = selectedPages.map(selectedPage => selectedPage.page._id);
if (page._id != null && !selectedPageIds.includes(page._id)) {
Expand All @@ -55,6 +32,11 @@ const AiAssistantManegementModalSubstance = (): JSX.Element => {
}, [openPageSelectModal, selectedPages]);


const clickRmoveSelectedPageHandler = useCallback((pageId: string) => {
setSelectedPages(selectedPages.filter(selectedPage => selectedPage.page._id !== pageId));
}, [selectedPages]);


return (
<div className="px-4">
<ModalBody>
Expand Down Expand Up @@ -104,11 +86,11 @@ const AiAssistantManegementModalSubstance = (): JSX.Element => {
<Label className="mb-0">参照するページ</Label>
<span className="ms-1 fs-5 material-symbols-outlined text-secondary">help</span>
</div>
<SelectedPageList selectedPages={selectedPages} />
<SelectedPageList selectedPages={selectedPages} onRemove={clickRmoveSelectedPageHandler} />
<button
type="button"
className="btn btn-outline-primary d-flex align-items-center gap-1"
onClick={onClickOpenPageSelectModalButton}
onClick={clickOpenPageSelectModalHandler}
>
<span>+</span>
追加する
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { memo } from 'react';

import { useTranslation } from 'react-i18next';

import type { SelectedPage } from '../../../interfaces/selected-page';

export const SelectedPageList = memo(({ selectedPages, onRemove }: { selectedPages: SelectedPage[], onRemove?: (pageId?: string) => void }): JSX.Element => {
const { t } = useTranslation();

if (selectedPages.length === 0) {
return <></>;
}

return (
<div className="mb-3">
{selectedPages.map(({ page, isIncludeSubPage }) => (
<div key={page._id} className="mb-1 d-flex align-items-center">
<code>{ page.path }</code>
{isIncludeSubPage && <span className="badge rounded-pill text-bg-secondary ms-2">{t('Include Subordinated Page')}</span>}
{onRemove != null && page._id != null && page._id && (
<button className="btn border-0 " type="button" onClick={() => onRemove(page._id)}>
<span className="fs-5 material-symbols-outlined text-secondary">delete</span>
</button>
)}
</div>
))}
</div>
);
});
6 changes: 6 additions & 0 deletions apps/app/src/features/openai/interfaces/selected-page.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import type { IPageForItem } from '~/interfaces/page';

export type SelectedPage = {
page: IPageForItem,
isIncludeSubPage: boolean,
}

0 comments on commit 436b76b

Please sign in to comment.