Просмотр исходного кода

fix growi cloud link to ai integration settings

ryota-t 2 недель назад
Родитель
Сommit
65fd783ef0

+ 20 - 3
apps/app/.env.development

@@ -7,7 +7,17 @@ MIGRATIONS_DIR=src/migrations/
 NEXT_TELEMETRY_DISABLED=1
 
 APP_SITE_URL=http://localhost:3000
-FILE_UPLOAD=mongodb
+FILE_UPLOAD=gcs
+
+# ストレージタイプを固定(ラジオボタンが disabled になる)
+FILE_UPLOAD_USES_ONLY_ENV_VAR_FOR_FILE_UPLOAD_TYPE=true
+
+# GCS設定を環境変数のみに固定(フィールドが readOnly になる)
+GCS_USES_ONLY_ENV_VARS_FOR_SOME_OPTIONS=true
+
+# Azure設定を環境変数のみに固定(フィールドが readOnly になる)
+AZURE_USES_ONLY_ENV_VARS_FOR_SOME_OPTIONS=true
+
 # MONGO_GRIDFS_TOTAL_LIMIT=10485760
 MONGO_URI="mongodb://mongo:27017/growi"
 # REDIS_URI="http://redis:6379"
@@ -24,13 +34,20 @@ OGP_URI="http://ogp:8088"
 # FORCE_WIKI_MODE=private
 # SLACKBOT_WITHOUT_PROXY_SIGNING_SECRET=''
 # SLACKBOT_WITHOUT_PROXY_BOT_TOKEN=''
-# GROWI_CLOUD_URI='http://growi.cloud'
-# GROWI_APP_ID_FOR_GROWI_CLOUD=012345
+GROWI_CLOUD_URI='http://growi.cloud'
+GROWI_APP_ID_FOR_GROWI_CLOUD=012345
 # AUDIT_LOG_ENABLED=false
 # ACTIVITY_EXPIRATION_SECONDS=2592000
 # AUDIT_LOG_ACTION_GROUP_SIZE=SMALL
 # AUDIT_LOG_ADDITIONAL_ACTIONS=
 # AUDIT_LOG_EXCLUDE_ACTIONS=
+AI_ENABLED=true
+OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxx
+
+# アシスタントモデルの設定
+OPENAI_SERVICE_TYPE=openai
+OPENAI_CHAT_ASSISTANT_MODEL=gpt-4.1-mini
+OPENAI_EDITOR_ASSISTANT_MODEL=gpt-4.1-mini
 
 SERVICE_TYPE=dev
 

+ 3 - 1
apps/app/public/static/locales/en_US/translation.json

@@ -660,7 +660,9 @@
     }
   },
   "default_ai_assistant": {
-    "not_set": "Default assistant is not set"
+    "not_set": "Default assistant is not set",
+    "open_cloud_settings_to_enable": "Please check the GROWI.cloud management screen to enable AI integration",
+    "to_cloud_settings": "Open GROWI.cloud Settings"
   },
   "ai_assistant_substance": {
     "add_assistant": "Add Assistant",

+ 3 - 1
apps/app/public/static/locales/fr_FR/translation.json

@@ -655,7 +655,9 @@
     }
   },
   "default_ai_assistant": {
-    "not_set": "L'assistant par défaut n'est pas configuré"
+    "not_set": "L'assistant par défaut n'est pas configuré",
+    "open_cloud_settings_to_enable": "Veuillez consulter l'écran de gestion GROWI.cloud pour activer l'intégration AI",
+    "to_cloud_settings": "Ouvrir les paramètres GROWI.cloud"
   },
   "ai_assistant_substance": {
     "add_assistant": "Ajouter un assistant",

+ 3 - 1
apps/app/public/static/locales/ja_JP/translation.json

@@ -693,7 +693,9 @@
     }
   },
   "default_ai_assistant": {
-    "not_set": "デフォルトアシスタントが設定されていません"
+    "not_set": "デフォルトアシスタントが設定されていません",
+    "open_cloud_settings_to_enable": "AI 連携を有効にするには GROWI.cloud の管理画面をご確認ください",
+    "to_cloud_settings": "GROWI.cloud の管理画面へ"
   },
   "ai_assistant_substance": {
     "add_assistant": "アシスタントを追加する",

+ 3 - 1
apps/app/public/static/locales/ko_KR/translation.json

@@ -620,7 +620,9 @@
     }
   },
   "default_ai_assistant": {
-    "not_set": "기본 어시스턴트가 설정되지 않았습니다."
+    "not_set": "기본 어시스턴트가 설정되지 않았습니다.",
+    "open_cloud_settings_to_enable": "AI 통합을 활성화하려면 GROWI.cloud 관리 화면을 확인하십시오",
+    "to_cloud_settings": "GROWI.cloud 관리 화면 열기"
   },
   "ai_assistant_substance": {
     "add_assistant": "어시스턴트 추가",

+ 3 - 1
apps/app/public/static/locales/zh_CN/translation.json

@@ -651,7 +651,9 @@
     }
   },
   "default_ai_assistant": {
-    "not_set": "未设置默认助手"
+    "not_set": "未设置默认助手",
+    "open_cloud_settings_to_enable": "请查看 GROWI.cloud 管理界面以启用 AI 集成",
+    "to_cloud_settings": "前往 GROWI.cloud 管理界面"
   },
   "ai_assistant_substance": {
     "add_assistant": "添加助手",

+ 21 - 2
apps/app/src/features/openai/client/components/AiAssistant/AiAssistantSidebar/AiAssistantSidebar.tsx

@@ -13,7 +13,7 @@ import { Collapse } from 'reactstrap';
 import SimpleBar from 'simplebar-react';
 
 import { toastError } from '~/client/util/toastr';
-import { useGrowiCloudUri } from '~/states/global';
+import { useGrowiAppIdForGrowiCloud, useGrowiCloudUri } from '~/states/global';
 import loggerFactory from '~/utils/logger';
 
 import type { AiAssistantHasId } from '../../../../interfaces/ai-assistant';
@@ -80,6 +80,8 @@ const AiAssistantSidebarSubstance: React.FC<
   // Hooks
   const { t } = useTranslation();
   const growiCloudUri = useGrowiCloudUri();
+  const growiAppIdForGrowiCloud = useGrowiAppIdForGrowiCloud();
+  const isCloud = growiCloudUri != null && growiAppIdForGrowiCloud != null;
 
   // useSWRxThreads is executed only when Substance is rendered
   const { data: threads, mutate: mutateThreads } = useSWRxThreads(
@@ -605,7 +607,24 @@ const AiAssistantSidebarSubstance: React.FC<
                   )}
                 </div>
               ) : (
-                <>{initialView}</>
+                <>
+                  {!isEditorAssistant && aiAssistantData == null && isCloud && (
+                    <div className="text-center mb-3">
+                      <a
+                        href={`${growiCloudUri}/my/apps/${growiAppIdForGrowiCloud}`}
+                        className="btn btn-outline-secondary"
+                      >
+                        <span className="material-symbols-outlined me-1">
+                          share
+                        </span>
+                        {t('cloud_setting_management.to_cloud_settings', {
+                          ns: 'admin',
+                        })}
+                      </a>
+                    </div>
+                  )}
+                  {initialView}
+                </>
               )}
             </div>
           </div>

+ 101 - 11
apps/app/src/features/openai/client/components/AiAssistant/OpenDefaultAiAssistantButton.tsx

@@ -1,9 +1,12 @@
 import React, { type JSX, useCallback, useMemo } from 'react';
 import { useAtomValue } from 'jotai';
+import { Disable } from 'react-disable';
 import { useTranslation } from 'react-i18next';
+import { PopoverBody, UncontrolledPopover } from 'reactstrap';
 
 import { NotAvailable } from '~/client/components/NotAvailable';
 import { NotAvailableForGuest } from '~/client/components/NotAvailableForGuest';
+import { useGrowiAppIdForGrowiCloud, useGrowiCloudUri } from '~/states/global';
 import { aiEnabledAtom } from '~/states/server-configurations';
 
 import { useAiAssistantSidebarActions } from '../../states';
@@ -15,6 +18,11 @@ const OpenDefaultAiAssistantButtonSubstance = (): JSX.Element => {
   const { t } = useTranslation();
   const { data: aiAssistantData } = useSWRxAiAssistants();
   const { openChat } = useAiAssistantSidebarActions();
+  const growiCloudUri = useGrowiCloudUri();
+  const growiAppIdForGrowiCloud = useGrowiAppIdForGrowiCloud();
+  const isCloud = growiCloudUri != null && growiAppIdForGrowiCloud != null;
+
+  const popoverTargetId = 'ai-assistant-btn';
 
   const defaultAiAssistant = useMemo(() => {
     if (aiAssistantData == null) {
@@ -36,21 +44,57 @@ const OpenDefaultAiAssistantButtonSubstance = (): JSX.Element => {
     openChat(defaultAiAssistant);
   }, [defaultAiAssistant, openChat]);
 
+  const isDisabled = defaultAiAssistant == null;
+
+  const button = (
+    <button
+      type="button"
+      className={`btn btn-search ${styles['btn-open-default-ai-assistant']}`}
+      onClick={openDefaultAiAssistantButtonClickHandler}
+    >
+      <span className="growi-custom-icons fs-4 align-middle lh-1">
+        ai_assistant
+      </span>
+    </button>
+  );
+
+  if (isDisabled && isCloud) {
+    return (
+      <NotAvailableForGuest>
+        <>
+          <div id={popoverTargetId}>
+            <Disable disabled>{button}</Disable>
+          </div>
+          <UncontrolledPopover
+            trigger="hover"
+            placement="top"
+            target={popoverTargetId}
+          >
+            <PopoverBody>
+              <p className="mb-2">{t('default_ai_assistant.not_set')}</p>
+              <a href={`${growiCloudUri}/my/apps/${growiAppIdForGrowiCloud}`}>
+                <span
+                  className="material-symbols-outlined me-1"
+                  style={{ fontSize: '1rem', verticalAlign: 'middle' }}
+                >
+                  share
+                </span>
+                {t('default_ai_assistant.to_cloud_settings')}
+              </a>
+            </PopoverBody>
+          </UncontrolledPopover>
+        </>
+      </NotAvailableForGuest>
+    );
+  }
+
   return (
     <NotAvailableForGuest>
       <NotAvailable
-        isDisabled={defaultAiAssistant == null}
+        isDisabled={isDisabled}
         title={t('default_ai_assistant.not_set')}
       >
-        <button
-          type="button"
-          className={`btn btn-search ${styles['btn-open-default-ai-assistant']}`}
-          onClick={openDefaultAiAssistantButtonClickHandler}
-        >
-          <span className="growi-custom-icons fs-4 align-middle lh-1">
-            ai_assistant
-          </span>
-        </button>
+        {button}
       </NotAvailable>
     </NotAvailableForGuest>
   );
@@ -58,9 +102,55 @@ const OpenDefaultAiAssistantButtonSubstance = (): JSX.Element => {
 
 const OpenDefaultAiAssistantButton = (): JSX.Element => {
   const isAiEnabled = useAtomValue(aiEnabledAtom);
+  const { t } = useTranslation();
+  const growiCloudUri = useGrowiCloudUri();
+  const growiAppIdForGrowiCloud = useGrowiAppIdForGrowiCloud();
+  const isCloud = growiCloudUri != null && growiAppIdForGrowiCloud != null;
+
+  const popoverTargetId = 'ai-disabled-btn';
 
   if (!isAiEnabled) {
-    return <></>;
+    // biome-ignore lint/security/noDangerouslySetInnerHtml: trusted translation markup
+    if (!isCloud) return <></>;
+
+    const button = (
+      <button
+        type="button"
+        className={`btn btn-search ${styles['btn-open-default-ai-assistant']}`}
+      >
+        <span className="growi-custom-icons fs-4 align-middle lh-1">
+          ai_assistant
+        </span>
+      </button>
+    );
+
+    return (
+      <>
+        <div id={popoverTargetId}>
+          <Disable disabled>{button}</Disable>
+        </div>
+        <UncontrolledPopover
+          trigger="hover"
+          placement="top"
+          target={popoverTargetId}
+        >
+          <PopoverBody>
+            <p className="mb-2">
+              {t('default_ai_assistant.open_cloud_settings_to_enable')}
+            </p>
+            <a href={`${growiCloudUri}/my/apps/${growiAppIdForGrowiCloud}`}>
+              <span
+                className="material-symbols-outlined me-1"
+                style={{ fontSize: '1rem', verticalAlign: 'middle' }}
+              >
+                share
+              </span>
+              {t('default_ai_assistant.to_cloud_settings')}
+            </a>
+          </PopoverBody>
+        </UncontrolledPopover>
+      </>
+    );
   }
 
   return <OpenDefaultAiAssistantButtonSubstance />;