|
@@ -1,9 +1,7 @@
|
|
|
import React, { useCallback, useState } from 'react';
|
|
import React, { useCallback, useState } from 'react';
|
|
|
|
|
|
|
|
import { useTranslation } from 'react-i18next';
|
|
import { useTranslation } from 'react-i18next';
|
|
|
-import {
|
|
|
|
|
- Modal, ModalHeader, ModalBody, ModalFooter, Form, FormGroup, Label, Input,
|
|
|
|
|
-} from 'reactstrap';
|
|
|
|
|
|
|
+import { Modal } from 'reactstrap';
|
|
|
|
|
|
|
|
import { toastError, toastSuccess } from '~/client/util/toastr';
|
|
import { toastError, toastSuccess } from '~/client/util/toastr';
|
|
|
import type { IPageForItem } from '~/interfaces/page';
|
|
import type { IPageForItem } from '~/interfaces/page';
|
|
@@ -12,9 +10,11 @@ import loggerFactory from '~/utils/logger';
|
|
|
|
|
|
|
|
import type { SelectedPage } from '../../../interfaces/selected-page';
|
|
import type { SelectedPage } from '../../../interfaces/selected-page';
|
|
|
import { createAiAssistant } from '../../services/ai-assistant';
|
|
import { createAiAssistant } from '../../services/ai-assistant';
|
|
|
-import { useAiAssistantManegementModal } from '../../stores/ai-assistant';
|
|
|
|
|
|
|
+import { useAiAssistantManegementModal, AiAssistantManegementModalPageMode } from '../../stores/ai-assistant';
|
|
|
import { SelectedPageList } from '../Common/SelectedPageList';
|
|
import { SelectedPageList } from '../Common/SelectedPageList';
|
|
|
|
|
|
|
|
|
|
+import { AiAssistantManagementEditInstruction } from './AiAssistantManagementModal/AiAssistantManagementEditInstruction';
|
|
|
|
|
+import { AiAssistantManagementHome } from './AiAssistantManagementModal/AiAssistantManagementHome';
|
|
|
|
|
|
|
|
import styles from './AiAssistantManegementModal.module.scss';
|
|
import styles from './AiAssistantManegementModal.module.scss';
|
|
|
|
|
|
|
@@ -23,9 +23,18 @@ const moduleClass = styles['grw-ai-assistant-manegement'] ?? '';
|
|
|
const logger = loggerFactory('growi:openai:client:components:AiAssistantManegementModal');
|
|
const logger = loggerFactory('growi:openai:client:components:AiAssistantManegementModal');
|
|
|
|
|
|
|
|
const AiAssistantManegementModalSubstance = (): JSX.Element => {
|
|
const AiAssistantManegementModalSubstance = (): JSX.Element => {
|
|
|
|
|
+ // Hooks
|
|
|
|
|
+ const { t } = useTranslation();
|
|
|
const { open: openPageSelectModal } = usePageSelectModal();
|
|
const { open: openPageSelectModal } = usePageSelectModal();
|
|
|
|
|
+ const { data: aiAssistantManegementModalData } = useAiAssistantManegementModal();
|
|
|
|
|
+
|
|
|
|
|
+ const pageMode = aiAssistantManegementModalData?.pageMode ?? AiAssistantManegementModalPageMode.HOME;
|
|
|
|
|
+
|
|
|
|
|
+ // States
|
|
|
const [selectedPages, setSelectedPages] = useState<SelectedPage[]>([]);
|
|
const [selectedPages, setSelectedPages] = useState<SelectedPage[]>([]);
|
|
|
|
|
+ const [instruction, setInstruction] = useState<string>(t('modal_ai_assistant.default_instruction'));
|
|
|
|
|
|
|
|
|
|
+ // Functions
|
|
|
const clickOpenPageSelectModalHandler = useCallback(() => {
|
|
const clickOpenPageSelectModalHandler = useCallback(() => {
|
|
|
const onSelected = (page: IPageForItem, isIncludeSubPage: boolean) => {
|
|
const onSelected = (page: IPageForItem, isIncludeSubPage: boolean) => {
|
|
|
const selectedPageIds = selectedPages.map(selectedPage => selectedPage.page._id);
|
|
const selectedPageIds = selectedPages.map(selectedPage => selectedPage.page._id);
|
|
@@ -37,7 +46,6 @@ const AiAssistantManegementModalSubstance = (): JSX.Element => {
|
|
|
openPageSelectModal({ onSelected, isHierarchicalSelectionMode: true });
|
|
openPageSelectModal({ onSelected, isHierarchicalSelectionMode: true });
|
|
|
}, [openPageSelectModal, selectedPages]);
|
|
}, [openPageSelectModal, selectedPages]);
|
|
|
|
|
|
|
|
-
|
|
|
|
|
const clickRmoveSelectedPageHandler = useCallback((pageId: string) => {
|
|
const clickRmoveSelectedPageHandler = useCallback((pageId: string) => {
|
|
|
setSelectedPages(selectedPages.filter(selectedPage => selectedPage.page._id !== pageId));
|
|
setSelectedPages(selectedPages.filter(selectedPage => selectedPage.page._id !== pageId));
|
|
|
}, [selectedPages]);
|
|
}, [selectedPages]);
|
|
@@ -51,7 +59,7 @@ const AiAssistantManegementModalSubstance = (): JSX.Element => {
|
|
|
await createAiAssistant({
|
|
await createAiAssistant({
|
|
|
name: 'test',
|
|
name: 'test',
|
|
|
description: 'test',
|
|
description: 'test',
|
|
|
- additionalInstruction: 'test',
|
|
|
|
|
|
|
+ additionalInstruction: instruction,
|
|
|
pagePathPatterns,
|
|
pagePathPatterns,
|
|
|
shareScope: 'publicOnly',
|
|
shareScope: 'publicOnly',
|
|
|
accessScope: 'publicOnly',
|
|
accessScope: 'publicOnly',
|
|
@@ -62,133 +70,151 @@ const AiAssistantManegementModalSubstance = (): JSX.Element => {
|
|
|
toastError('アシスタントの作成に失敗しました');
|
|
toastError('アシスタントの作成に失敗しました');
|
|
|
logger.error(err);
|
|
logger.error(err);
|
|
|
}
|
|
}
|
|
|
- }, [selectedPages]);
|
|
|
|
|
|
|
+ }, [instruction, selectedPages]);
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ /*
|
|
|
|
|
+ * For AiAssistantManagementEditInstruction methods
|
|
|
|
|
+ */
|
|
|
|
|
+ const changeInstructionHandler = useCallback((value: string) => {
|
|
|
|
|
+ setInstruction(value);
|
|
|
|
|
+ }, []);
|
|
|
|
|
+
|
|
|
|
|
+ const resetInstructionHandler = useCallback(() => {
|
|
|
|
|
+ setInstruction(t('modal_ai_assistant.default_instruction'));
|
|
|
|
|
+ }, [t]);
|
|
|
|
|
|
|
|
return (
|
|
return (
|
|
|
- <div className="px-4">
|
|
|
|
|
- <ModalBody>
|
|
|
|
|
- <Form>
|
|
|
|
|
- <FormGroup className="mb-4">
|
|
|
|
|
- <Label className="mb-2 ">アシスタント名</Label>
|
|
|
|
|
- <Input
|
|
|
|
|
- type="text"
|
|
|
|
|
- placeholder="アシスタント名を入力"
|
|
|
|
|
- className="border rounded"
|
|
|
|
|
- />
|
|
|
|
|
- </FormGroup>
|
|
|
|
|
-
|
|
|
|
|
- <FormGroup className="mb-4">
|
|
|
|
|
- <div className="d-flex align-items-center mb-2">
|
|
|
|
|
- <Label className="mb-0">アシスタントの種類</Label>
|
|
|
|
|
- <span className="ms-1 fs-5 material-symbols-outlined text-secondary">help</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div className="d-flex gap-4">
|
|
|
|
|
- <FormGroup check>
|
|
|
|
|
- <Input type="checkbox" defaultChecked />
|
|
|
|
|
- <Label check>ナレッジアシスタント</Label>
|
|
|
|
|
- </FormGroup>
|
|
|
|
|
- <FormGroup check>
|
|
|
|
|
- <Input type="checkbox" />
|
|
|
|
|
- <Label check>エディタアシスタント</Label>
|
|
|
|
|
- </FormGroup>
|
|
|
|
|
- <FormGroup check>
|
|
|
|
|
- <Input type="checkbox" />
|
|
|
|
|
- <Label check>ラーニングアシスタント</Label>
|
|
|
|
|
- </FormGroup>
|
|
|
|
|
- </div>
|
|
|
|
|
- </FormGroup>
|
|
|
|
|
-
|
|
|
|
|
- <FormGroup className="mb-4">
|
|
|
|
|
- <div className="d-flex align-items-center mb-2">
|
|
|
|
|
- <Label className="mb-0">共有範囲</Label>
|
|
|
|
|
- <span className="ms-1 fs-5 material-symbols-outlined text-secondary">help</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- <Input type="select" className="border rounded w-50">
|
|
|
|
|
- <option>自分のみ</option>
|
|
|
|
|
- </Input>
|
|
|
|
|
- </FormGroup>
|
|
|
|
|
-
|
|
|
|
|
- <FormGroup className="mb-4">
|
|
|
|
|
- <div className="d-flex align-items-center mb-2">
|
|
|
|
|
- <Label className="mb-0">参照するページ</Label>
|
|
|
|
|
- <span className="ms-1 fs-5 material-symbols-outlined text-secondary">help</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- <SelectedPageList selectedPages={selectedPages} onRemove={clickRmoveSelectedPageHandler} />
|
|
|
|
|
- <button
|
|
|
|
|
- type="button"
|
|
|
|
|
- className="btn btn-outline-primary d-flex align-items-center gap-1"
|
|
|
|
|
- onClick={clickOpenPageSelectModalHandler}
|
|
|
|
|
- >
|
|
|
|
|
- <span>+</span>
|
|
|
|
|
- 追加する
|
|
|
|
|
- </button>
|
|
|
|
|
- </FormGroup>
|
|
|
|
|
-
|
|
|
|
|
- <FormGroup>
|
|
|
|
|
- <div className="d-flex align-items-center mb-2">
|
|
|
|
|
- <Label className="mb-0 me-2">アシスタントへの指示</Label>
|
|
|
|
|
- <label className="form-label form-check-label">
|
|
|
|
|
- <span className="badge text-bg-danger mt-2">
|
|
|
|
|
- 必須
|
|
|
|
|
- </span>
|
|
|
|
|
- </label>
|
|
|
|
|
- </div>
|
|
|
|
|
- <Input
|
|
|
|
|
- type="textarea"
|
|
|
|
|
- placeholder="アシスタントに実行して欲しい内容を具体的に記入してください"
|
|
|
|
|
- className="border rounded"
|
|
|
|
|
- rows={4}
|
|
|
|
|
- />
|
|
|
|
|
- </FormGroup>
|
|
|
|
|
-
|
|
|
|
|
- <FormGroup>
|
|
|
|
|
- <div className="d-flex align-items-center mb-2">
|
|
|
|
|
- <Label className="mb-0 me-2">アシスタントのメモ</Label>
|
|
|
|
|
- <label className="form-label form-check-label">
|
|
|
|
|
- <span className="badge text-bg-secondary mt-2">
|
|
|
|
|
- 必須
|
|
|
|
|
- </span>
|
|
|
|
|
- </label>
|
|
|
|
|
- </div>
|
|
|
|
|
- <Input
|
|
|
|
|
- type="textarea"
|
|
|
|
|
- placeholder="内容や用途のメモを表示させることができます"
|
|
|
|
|
- className="border rounded"
|
|
|
|
|
- rows={4}
|
|
|
|
|
- />
|
|
|
|
|
- <p className="mt-1 text-muted">メモ内容はアシスタントには影響しません。</p>
|
|
|
|
|
- </FormGroup>
|
|
|
|
|
- </Form>
|
|
|
|
|
- </ModalBody>
|
|
|
|
|
-
|
|
|
|
|
- <ModalFooter className="border-0 pt-0 mb-3">
|
|
|
|
|
- <button type="button" className="btn btn-outline-secondary" onClick={() => {}}>キャンセル</button>
|
|
|
|
|
- <button type="button" className="btn btn-primary" onClick={clickCreateAiAssistantHandler}>作成</button>
|
|
|
|
|
- </ModalFooter>
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ <>
|
|
|
|
|
+ {pageMode === AiAssistantManegementModalPageMode.HOME && (
|
|
|
|
|
+ <AiAssistantManagementHome
|
|
|
|
|
+ instruction={instruction}
|
|
|
|
|
+ />
|
|
|
|
|
+ )}
|
|
|
|
|
+
|
|
|
|
|
+ {pageMode === AiAssistantManegementModalPageMode.INSTRUCTION && (
|
|
|
|
|
+ <AiAssistantManagementEditInstruction
|
|
|
|
|
+ instruction={instruction}
|
|
|
|
|
+ onChange={changeInstructionHandler}
|
|
|
|
|
+ onReset={resetInstructionHandler}
|
|
|
|
|
+ />
|
|
|
|
|
+ )}
|
|
|
|
|
+ </>
|
|
|
|
|
+ // <div className="px-4">
|
|
|
|
|
+ // <ModalBody>
|
|
|
|
|
+ // <Form>
|
|
|
|
|
+ // <FormGroup className="mb-4">
|
|
|
|
|
+ // <Label className="mb-2 ">アシスタント名</Label>
|
|
|
|
|
+ // <Input
|
|
|
|
|
+ // type="text"
|
|
|
|
|
+ // placeholder="アシスタント名を入力"
|
|
|
|
|
+ // className="border rounded"
|
|
|
|
|
+ // />
|
|
|
|
|
+ // </FormGroup>
|
|
|
|
|
+
|
|
|
|
|
+ // <FormGroup className="mb-4">
|
|
|
|
|
+ // <div className="d-flex align-items-center mb-2">
|
|
|
|
|
+ // <Label className="mb-0">アシスタントの種類</Label>
|
|
|
|
|
+ // <span className="ms-1 fs-5 material-symbols-outlined text-secondary">help</span>
|
|
|
|
|
+ // </div>
|
|
|
|
|
+ // <div className="d-flex gap-4">
|
|
|
|
|
+ // <FormGroup check>
|
|
|
|
|
+ // <Input type="checkbox" defaultChecked />
|
|
|
|
|
+ // <Label check>ナレッジアシスタント</Label>
|
|
|
|
|
+ // </FormGroup>
|
|
|
|
|
+ // <FormGroup check>
|
|
|
|
|
+ // <Input type="checkbox" />
|
|
|
|
|
+ // <Label check>エディタアシスタント</Label>
|
|
|
|
|
+ // </FormGroup>
|
|
|
|
|
+ // <FormGroup check>
|
|
|
|
|
+ // <Input type="checkbox" />
|
|
|
|
|
+ // <Label check>ラーニングアシスタント</Label>
|
|
|
|
|
+ // </FormGroup>
|
|
|
|
|
+ // </div>
|
|
|
|
|
+ // </FormGroup>
|
|
|
|
|
+
|
|
|
|
|
+ // <FormGroup className="mb-4">
|
|
|
|
|
+ // <div className="d-flex align-items-center mb-2">
|
|
|
|
|
+ // <Label className="mb-0">共有範囲</Label>
|
|
|
|
|
+ // <span className="ms-1 fs-5 material-symbols-outlined text-secondary">help</span>
|
|
|
|
|
+ // </div>
|
|
|
|
|
+ // <Input type="select" className="border rounded w-50">
|
|
|
|
|
+ // <option>自分のみ</option>
|
|
|
|
|
+ // </Input>
|
|
|
|
|
+ // </FormGroup>
|
|
|
|
|
+
|
|
|
|
|
+ // <FormGroup className="mb-4">
|
|
|
|
|
+ // <div className="d-flex align-items-center mb-2">
|
|
|
|
|
+ // <Label className="mb-0">参照するページ</Label>
|
|
|
|
|
+ // <span className="ms-1 fs-5 material-symbols-outlined text-secondary">help</span>
|
|
|
|
|
+ // </div>
|
|
|
|
|
+ // <SelectedPageList selectedPages={selectedPages} onRemove={clickRmoveSelectedPageHandler} />
|
|
|
|
|
+ // <button
|
|
|
|
|
+ // type="button"
|
|
|
|
|
+ // className="btn btn-outline-primary d-flex align-items-center gap-1"
|
|
|
|
|
+ // onClick={clickOpenPageSelectModalHandler}
|
|
|
|
|
+ // >
|
|
|
|
|
+ // <span>+</span>
|
|
|
|
|
+ // 追加する
|
|
|
|
|
+ // </button>
|
|
|
|
|
+ // </FormGroup>
|
|
|
|
|
+
|
|
|
|
|
+ // <FormGroup>
|
|
|
|
|
+ // <div className="d-flex align-items-center mb-2">
|
|
|
|
|
+ // <Label className="mb-0 me-2">アシスタントへの指示</Label>
|
|
|
|
|
+ // <label className="form-label form-check-label">
|
|
|
|
|
+ // <span className="badge text-bg-danger mt-2">
|
|
|
|
|
+ // 必須
|
|
|
|
|
+ // </span>
|
|
|
|
|
+ // </label>
|
|
|
|
|
+ // </div>
|
|
|
|
|
+ // <Input
|
|
|
|
|
+ // type="textarea"
|
|
|
|
|
+ // placeholder="アシスタントに実行して欲しい内容を具体的に記入してください"
|
|
|
|
|
+ // className="border rounded"
|
|
|
|
|
+ // rows={4}
|
|
|
|
|
+ // />
|
|
|
|
|
+ // </FormGroup>
|
|
|
|
|
+
|
|
|
|
|
+ // <FormGroup>
|
|
|
|
|
+ // <div className="d-flex align-items-center mb-2">
|
|
|
|
|
+ // <Label className="mb-0 me-2">アシスタントのメモ</Label>
|
|
|
|
|
+ // <label className="form-label form-check-label">
|
|
|
|
|
+ // <span className="badge text-bg-secondary mt-2">
|
|
|
|
|
+ // 必須
|
|
|
|
|
+ // </span>
|
|
|
|
|
+ // </label>
|
|
|
|
|
+ // </div>
|
|
|
|
|
+ // <Input
|
|
|
|
|
+ // type="textarea"
|
|
|
|
|
+ // placeholder="内容や用途のメモを表示させることができます"
|
|
|
|
|
+ // className="border rounded"
|
|
|
|
|
+ // rows={4}
|
|
|
|
|
+ // />
|
|
|
|
|
+ // <p className="mt-1 text-muted">メモ内容はアシスタントには影響しません。</p>
|
|
|
|
|
+ // </FormGroup>
|
|
|
|
|
+ // </Form>
|
|
|
|
|
+ // </ModalBody>
|
|
|
|
|
+
|
|
|
|
|
+ // <ModalFooter className="border-0 pt-0 mb-3">
|
|
|
|
|
+ // <button type="button" className="btn btn-outline-secondary" onClick={() => {}}>キャンセル</button>
|
|
|
|
|
+ // <button type="button" className="btn btn-primary" onClick={clickCreateAiAssistantHandler}>作成</button>
|
|
|
|
|
+ // </ModalFooter>
|
|
|
|
|
+ // </div>
|
|
|
);
|
|
);
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
export const AiAssistantManegementModal = (): JSX.Element => {
|
|
export const AiAssistantManegementModal = (): JSX.Element => {
|
|
|
- const { t } = useTranslation();
|
|
|
|
|
-
|
|
|
|
|
const { data: aiAssistantManegementModalData, close: closeAiAssistantManegementModal } = useAiAssistantManegementModal();
|
|
const { data: aiAssistantManegementModalData, close: closeAiAssistantManegementModal } = useAiAssistantManegementModal();
|
|
|
|
|
|
|
|
const isOpened = aiAssistantManegementModalData?.isOpened ?? false;
|
|
const isOpened = aiAssistantManegementModalData?.isOpened ?? false;
|
|
|
|
|
|
|
|
return (
|
|
return (
|
|
|
<Modal size="lg" isOpen={isOpened} toggle={closeAiAssistantManegementModal} className={moduleClass} scrollable>
|
|
<Modal size="lg" isOpen={isOpened} toggle={closeAiAssistantManegementModal} className={moduleClass} scrollable>
|
|
|
-
|
|
|
|
|
- <ModalHeader tag="h4" toggle={closeAiAssistantManegementModal} className="pe-4">
|
|
|
|
|
- <span className="growi-custom-icons growi-ai-assistant-icon me-3 fs-4">ai_assistant</span>
|
|
|
|
|
- <span className="fw-bold">新規アシスタントの追加</span> {/* TODO i18n */}
|
|
|
|
|
- </ModalHeader>
|
|
|
|
|
-
|
|
|
|
|
{ isOpened && (
|
|
{ isOpened && (
|
|
|
<AiAssistantManegementModalSubstance />
|
|
<AiAssistantManegementModalSubstance />
|
|
|
) }
|
|
) }
|
|
|
-
|
|
|
|
|
</Modal>
|
|
</Modal>
|
|
|
);
|
|
);
|
|
|
};
|
|
};
|