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

Merge branch 'feat/160664-implement-access-scope-dropdown' into feat/160857-implement-share-scope-warning-modal

Shun Miyazawa 1 год назад
Родитель
Сommit
7f67580c69

+ 3 - 3
apps/app/src/features/openai/client/components/AiAssistant/AiAssistantManagementModal/AccessScopeDropdown.tsx

@@ -7,13 +7,13 @@ import {
 
 import { useCurrentUser } from '~/stores-universal/context';
 
-import { AiAssistantScopeType, AiAssistantAccessScope } from '../../../../interfaces/ai-assistant';
+import { AiAssistantAccessScope } from '../../../../interfaces/ai-assistant';
 
 type Props = {
   isDisabled: boolean,
   isDisabledGroups: boolean,
   selectedAccessScope: AiAssistantAccessScope,
-  onSelect: (accessScope: AiAssistantAccessScope, scopeType: AiAssistantScopeType) => void,
+  onSelect: (accessScope: AiAssistantAccessScope) => void,
 }
 
 export const AccessScopeDropdown: React.FC<Props> = (props: Props) => {
@@ -35,7 +35,7 @@ export const AccessScopeDropdown: React.FC<Props> = (props: Props) => {
   }, [currentUser?.username, t]);
 
   const selectAccessScopeHandler = useCallback((accessScope: AiAssistantAccessScope) => {
-    onSelect(accessScope, AiAssistantScopeType.ACCESS);
+    onSelect(accessScope);
   }, [onSelect]);
 
   return (

+ 49 - 22
apps/app/src/features/openai/client/components/AiAssistant/AiAssistantManagementModal/AiAssistantManagementEditShare.tsx

@@ -4,7 +4,7 @@ import {
   ModalBody, Input, Label,
 } from 'reactstrap';
 
-import { AiAssistantScopeType, AiAssistantShareScope, AiAssistantAccessScope } from '~/features/openai/interfaces/ai-assistant';
+import { AiAssistantShareScope, AiAssistantAccessScope } from '~/features/openai/interfaces/ai-assistant';
 import type { PopulatedGrantedGroup } from '~/interfaces/page-grant';
 import { useSWRxUserRelatedGroups } from '~/stores/user';
 
@@ -13,14 +13,22 @@ import { AiAssistantManagementHeader } from './AiAssistantManagementHeader';
 import { SelectUserGroupModal } from './SelectUserGroupModal';
 import { ShareScopeSwitch } from './ShareScopeSwitch';
 
+const ScopeType = {
+  ACCESS: 'Access',
+  SHARE: 'Share',
+} as const;
+
+type ScopeType = typeof ScopeType[keyof typeof ScopeType];
 
 type Props = {
   selectedShareScope: AiAssistantShareScope,
   selectedAccessScope: AiAssistantAccessScope,
   selectedUserGroupsForShareScope: PopulatedGrantedGroup[],
   selectedUserGroupsForAccessScope: PopulatedGrantedGroup[],
-  onSelectUserGroup: (userGroup: PopulatedGrantedGroup, scopeType: AiAssistantScopeType) => void,
-  onSelectScope: (scopeType: AiAssistantScopeType, scope: AiAssistantAccessScope | AiAssistantShareScope) => void,
+  onSelectShareScope: (scope: AiAssistantShareScope) => void,
+  onSelectAccessScope: (scope: AiAssistantAccessScope) => void,
+  onSelectShareScopeUserGroups: (userGroup: PopulatedGrantedGroup) => void,
+  onSelectAccessScopeUserGroups: (userGroup: PopulatedGrantedGroup) => void,
 }
 
 export const AiAssistantManagementEditShare = (props: Props): JSX.Element => {
@@ -29,8 +37,10 @@ export const AiAssistantManagementEditShare = (props: Props): JSX.Element => {
     selectedAccessScope,
     selectedUserGroupsForShareScope,
     selectedUserGroupsForAccessScope,
-    onSelectScope,
-    onSelectUserGroup,
+    onSelectShareScope,
+    onSelectAccessScope,
+    onSelectShareScopeUserGroups,
+    onSelectAccessScopeUserGroups,
   } = props;
 
   const { data: userRelatedGroups } = useSWRxUserRelatedGroups();
@@ -38,28 +48,40 @@ export const AiAssistantManagementEditShare = (props: Props): JSX.Element => {
 
   const [isShared, setIsShared] = useState(false);
   const [isSelectUserGroupModalOpen, setIsSelectUserGroupModalOpen] = useState(false);
-  const [selectedUserGroupType, setSelectedUserGroupType] = useState<AiAssistantScopeType>(AiAssistantScopeType.ACCESS);
+  const [selectedUserGroupType, setSelectedUserGroupType] = useState<ScopeType>(ScopeType.ACCESS);
 
   const changeShareToggleHandler = useCallback(() => {
     setIsShared((prev) => {
       if (prev) { // if isShared === true
-        onSelectScope(AiAssistantScopeType.ACCESS, AiAssistantAccessScope.OWNER);
-        onSelectScope(AiAssistantScopeType.SHARE, AiAssistantShareScope.SAME_AS_ACCESS_SCOPE);
+        onSelectShareScope(AiAssistantShareScope.SAME_AS_ACCESS_SCOPE);
+        onSelectAccessScope(AiAssistantAccessScope.OWNER);
       }
       else {
-        onSelectScope(AiAssistantScopeType.SHARE, AiAssistantShareScope.PUBLIC_ONLY);
+        onSelectShareScope(AiAssistantShareScope.PUBLIC_ONLY);
       }
       return !prev;
     });
-  }, [onSelectScope]);
+  }, [onSelectAccessScope, onSelectShareScope]);
+
+  const selectGroupScopeHandler = useCallback((scopeType: ScopeType) => {
+    setSelectedUserGroupType(scopeType);
+    setIsSelectUserGroupModalOpen(true);
+  }, []);
+
+  const selectShareScopeHandler = useCallback((shareScope: AiAssistantShareScope) => {
+    onSelectShareScope(shareScope);
+    if (shareScope === AiAssistantShareScope.GROUPS && !hasNoRelatedGroups) {
+      selectGroupScopeHandler(ScopeType.SHARE);
+    }
+  }, [hasNoRelatedGroups, onSelectShareScope, selectGroupScopeHandler]);
 
-  const selectScopeHandler = useCallback((scope: AiAssistantAccessScope | AiAssistantShareScope, scopeType: AiAssistantScopeType) => {
-    onSelectScope(scopeType, scope);
-    if (scope === 'groups' && !hasNoRelatedGroups) {
-      setSelectedUserGroupType(scopeType);
-      setIsSelectUserGroupModalOpen(true);
+  const selectAccessScopeHandler = useCallback((accessScope: AiAssistantAccessScope) => {
+    onSelectAccessScope(accessScope);
+    if (accessScope === AiAssistantAccessScope.GROUPS && !hasNoRelatedGroups) {
+      selectGroupScopeHandler(ScopeType.ACCESS);
     }
-  }, [hasNoRelatedGroups, onSelectScope]);
+  }, [hasNoRelatedGroups, onSelectAccessScope, selectGroupScopeHandler]);
+
 
   return (
     <>
@@ -84,24 +106,29 @@ export const AiAssistantManagementEditShare = (props: Props): JSX.Element => {
           isDisabled={!isShared}
           isDisabledGroups={hasNoRelatedGroups}
           selectedAccessScope={selectedAccessScope}
-          onSelect={selectScopeHandler}
+          onSelect={selectAccessScopeHandler}
         />
 
         <ShareScopeSwitch
           isDisabled={!isShared}
           isDisabledGroups={hasNoRelatedGroups}
           selectedShareScope={selectedShareScope}
-          selectedAccessScope={selectedAccessScope}
-          onSelect={selectScopeHandler}
+          onSelect={selectShareScopeHandler}
         />
 
         <SelectUserGroupModal
           isOpen={isSelectUserGroupModalOpen}
           userRelatedGroups={userRelatedGroups?.relatedGroups}
           closeModal={() => setIsSelectUserGroupModalOpen(false)}
-          selectedUserGroupType={selectedUserGroupType}
-          selectedUserGroup={selectedUserGroupType === AiAssistantScopeType.ACCESS ? selectedUserGroupsForAccessScope : selectedUserGroupsForShareScope}
-          onSelect={onSelectUserGroup}
+          selectedUserGroups={selectedUserGroupType === ScopeType.ACCESS ? selectedUserGroupsForAccessScope : selectedUserGroupsForShareScope}
+          onSelect={(userGroup) => {
+            if (selectedUserGroupType === ScopeType.ACCESS) {
+              onSelectAccessScopeUserGroups(userGroup);
+            }
+            else {
+              onSelectShareScopeUserGroups(userGroup);
+            }
+          }}
         />
       </ModalBody>
     </>

+ 27 - 19
apps/app/src/features/openai/client/components/AiAssistant/AiAssistantManagementModal/AiAssistantManagementModal.tsx

@@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next';
 import { Modal, TabContent, TabPane } from 'reactstrap';
 
 import { toastError, toastSuccess } from '~/client/util/toastr';
-import { AiAssistantAccessScope, AiAssistantShareScope, AiAssistantScopeType } from '~/features/openai/interfaces/ai-assistant';
+import { AiAssistantAccessScope, AiAssistantShareScope } from '~/features/openai/interfaces/ai-assistant';
 import type { IPageForItem } from '~/interfaces/page';
 import type { PopulatedGrantedGroup } from '~/interfaces/page-grant';
 import loggerFactory from '~/utils/logger';
@@ -105,31 +105,37 @@ const AiAssistantManagementModalSubstance = (): JSX.Element => {
   /*
   *  For AiAssistantManagementEditShare methods
   */
-  const selectScopeHandler = useCallback((scopeType: AiAssistantScopeType, targetScope: AiAssistantAccessScope | AiAssistantShareScope) => {
-    if (scopeType === AiAssistantScopeType.ACCESS) {
-      setSelectedAccessScope(targetScope as AiAssistantAccessScope);
-      return;
-    }
-    if (scopeType === AiAssistantScopeType.SHARE) {
-      setSelectedShareScope(targetScope as AiAssistantShareScope);
-      return;
-    }
+  const selectShareScopeHandler = useCallback((shareScope: AiAssistantShareScope) => {
+    setSelectedShareScope(shareScope);
   }, []);
 
-  const selectUserGroupsHandler = useCallback((targetUserGroup: PopulatedGrantedGroup, scopeType: AiAssistantScopeType) => {
-    const selectedUserGroups = scopeType === AiAssistantScopeType.ACCESS ? selectedUserGroupsForAccessScope : selectedUserGroupsForShareScope;
-    const setSelectedUserGroups = scopeType === AiAssistantScopeType.ACCESS ? setSelectedUserGroupsForAccessScope : setSelectedUserGroupsForShareScope;
+  const selectAccessScopeHandler = useCallback((accessScope: AiAssistantAccessScope) => {
+    setSelectedAccessScope(accessScope);
+  }, []);
+
+  const selectShareScopeUserGroups = useCallback((targetUserGroup: PopulatedGrantedGroup) => {
+    const selectedUserGroupIds = selectedUserGroupsForShareScope.map(userGroup => userGroup.item._id);
+    if (selectedUserGroupIds.includes(targetUserGroup.item._id)) {
+      // if selected, remove it
+      setSelectedUserGroupsForShareScope(selectedUserGroupsForShareScope.filter(userGroup => userGroup.item._id !== targetUserGroup.item._id));
+    }
+    else {
+      // if not selected, add it
+      setSelectedUserGroupsForShareScope([...selectedUserGroupsForShareScope, targetUserGroup]);
+    }
+  }, [selectedUserGroupsForShareScope]);
 
-    const selectedUserGroupIds = selectedUserGroups.map(userGroup => userGroup.item._id);
+  const selectAccessScopeUserGroups = useCallback((targetUserGroup: PopulatedGrantedGroup) => {
+    const selectedUserGroupIds = selectedUserGroupsForAccessScope.map(userGroup => userGroup.item._id);
     if (selectedUserGroupIds.includes(targetUserGroup.item._id)) {
       // if selected, remove it
-      setSelectedUserGroups(selectedUserGroups.filter(userGroup => userGroup.item._id !== targetUserGroup.item._id));
+      setSelectedUserGroupsForAccessScope(selectedUserGroupsForAccessScope.filter(userGroup => userGroup.item._id !== targetUserGroup.item._id));
     }
     else {
       // if not selected, add it
-      setSelectedUserGroups([...selectedUserGroups, targetUserGroup]);
+      setSelectedUserGroupsForAccessScope([...selectedUserGroupsForAccessScope, targetUserGroup]);
     }
-  }, [selectedUserGroupsForAccessScope, selectedUserGroupsForShareScope]);
+  }, [selectedUserGroupsForAccessScope]);
 
 
   /*
@@ -179,8 +185,10 @@ const AiAssistantManagementModalSubstance = (): JSX.Element => {
             selectedAccessScope={selectedAccessScope}
             selectedUserGroupsForShareScope={selectedUserGroupsForShareScope}
             selectedUserGroupsForAccessScope={selectedUserGroupsForAccessScope}
-            onSelectScope={selectScopeHandler}
-            onSelectUserGroup={selectUserGroupsHandler}
+            onSelectShareScope={selectShareScopeHandler}
+            onSelectAccessScope={selectAccessScopeHandler}
+            onSelectAccessScopeUserGroups={selectAccessScopeUserGroups}
+            onSelectShareScopeUserGroups={selectShareScopeUserGroups}
           />
         </TabPane>
 

+ 6 - 9
apps/app/src/features/openai/client/components/AiAssistant/AiAssistantManagementModal/SelectUserGroupModal.tsx

@@ -6,23 +6,20 @@ import {
   Modal, ModalHeader, ModalBody,
 } from 'reactstrap';
 
-import type { AiAssistantScopeType } from '~/features/openai/interfaces/ai-assistant';
 import type { PopulatedGrantedGroup } from '~/interfaces/page-grant';
 
 type Props = {
   isOpen: boolean,
   userRelatedGroups?: PopulatedGrantedGroup[],
-  selectedUserGroupType: AiAssistantScopeType,
-  selectedUserGroup: PopulatedGrantedGroup[],
+  selectedUserGroups: PopulatedGrantedGroup[],
   closeModal: () => void,
-  onSelect: (userGroup: PopulatedGrantedGroup, scopeType: AiAssistantScopeType) => void,
+  onSelect: (userGroup: PopulatedGrantedGroup) => void,
 }
 
 const SelectUserGroupModalSubstance: React.FC<Props> = (props: Props) => {
   const {
     userRelatedGroups,
-    selectedUserGroup,
-    selectedUserGroupType,
+    selectedUserGroups,
     onSelect,
     closeModal,
   } = props;
@@ -30,9 +27,9 @@ const SelectUserGroupModalSubstance: React.FC<Props> = (props: Props) => {
   const { t } = useTranslation();
 
   const checked = useCallback((targetUserGroup: PopulatedGrantedGroup) => {
-    const selectedUserGroupIds = selectedUserGroup.map(userGroup => userGroup.item._id);
+    const selectedUserGroupIds = selectedUserGroups.map(userGroup => userGroup.item._id);
     return selectedUserGroupIds.includes(targetUserGroup.item._id);
-  }, [selectedUserGroup]);
+  }, [selectedUserGroups]);
 
   return (
     <ModalBody className="d-flex flex-column">
@@ -41,7 +38,7 @@ const SelectUserGroupModalSubstance: React.FC<Props> = (props: Props) => {
           className="btn btn-outline-primary d-flex justify-content-start mb-3 mx-4 align-items-center p-3"
           type="button"
           key={userGroup.item._id}
-          onClick={() => onSelect(userGroup, selectedUserGroupType)}
+          onClick={() => onSelect(userGroup)}
         >
           <input type="checkbox" checked={checked(userGroup)} onChange={() => {}} />
           <p className="ms-3 mb-0">{userGroup.item.name}</p>

+ 3 - 6
apps/app/src/features/openai/client/components/AiAssistant/AiAssistantManagementModal/ShareScopeSwitch.tsx

@@ -5,16 +5,13 @@ import {
   Input, Label, FormGroup,
 } from 'reactstrap';
 
-import type { AiAssistantAccessScope } from '../../../../interfaces/ai-assistant';
-import { AiAssistantShareScope, AiAssistantScopeType } from '../../../../interfaces/ai-assistant';
-
+import { AiAssistantShareScope } from '../../../../interfaces/ai-assistant';
 
 type Props = {
   isDisabled: boolean,
   isDisabledGroups: boolean,
   selectedShareScope: AiAssistantShareScope,
-  selectedAccessScope: AiAssistantAccessScope,
-  onSelect: (shareScope: AiAssistantShareScope, scopeType: AiAssistantScopeType) => void,
+  onSelect: (shareScope: AiAssistantShareScope) => void,
 }
 
 export const ShareScopeSwitch: React.FC<Props> = (props: Props) => {
@@ -40,7 +37,7 @@ export const ShareScopeSwitch: React.FC<Props> = (props: Props) => {
               id="shareGroup"
               className="form-check-input"
               disabled={isDisabled || (isDisabledGroups && shareScope === AiAssistantShareScope.GROUPS)}
-              onChange={() => onSelect(shareScope, AiAssistantScopeType.SHARE)}
+              onChange={() => onSelect(shareScope)}
               checked={selectedShareScope === shareScope}
             />
             <Label check for="shareGroup" className="d-flex flex-column">

+ 0 - 6
apps/app/src/features/openai/interfaces/ai-assistant.ts

@@ -5,11 +5,6 @@ import type { VectorStore } from '../server/models/vector-store';
 /*
 *  Objects
 */
-export const AiAssistantScopeType = {
-  ACCESS: 'Access',
-  SHARE: 'Share',
-} as const;
-
 export const AiAssistantShareScope = {
   SAME_AS_ACCESS_SCOPE: 'sameAsAccessScope',
   PUBLIC_ONLY: 'publicOnly', // TODO: Rename to "PUBLIC"
@@ -26,7 +21,6 @@ export const AiAssistantAccessScope = {
 /*
 *  Interfaces
 */
-export type AiAssistantScopeType = typeof AiAssistantScopeType[keyof typeof AiAssistantScopeType];
 export type AiAssistantShareScope = typeof AiAssistantShareScope[keyof typeof AiAssistantShareScope];
 export type AiAssistantAccessScope = typeof AiAssistantAccessScope[keyof typeof AiAssistantAccessScope];