From 94bb483f44fbdba58ad8a2427cffbc72726377f7 Mon Sep 17 00:00:00 2001 From: anastasiia Date: Mon, 8 Apr 2024 15:08:22 +0200 Subject: [PATCH] add multiple files to studio --- client/src/CommandBar/Body/Item.tsx | 37 +++--- client/src/CommandBar/steps/SeachFiles.tsx | 124 +++++++++++++----- .../NavPanel/Studios/AddContextFile.tsx | 36 +++-- .../NavPanel/Studios/StudioEntry.tsx | 10 +- client/src/locales/en.json | 3 +- client/src/locales/es.json | 3 +- client/src/locales/it.json | 3 +- client/src/locales/ja.json | 3 +- client/src/locales/zh-CN.json | 3 +- client/src/types/general.ts | 2 +- 10 files changed, 154 insertions(+), 70 deletions(-) diff --git a/client/src/CommandBar/Body/Item.tsx b/client/src/CommandBar/Body/Item.tsx index ae69efec25..cb1a21b5ac 100644 --- a/client/src/CommandBar/Body/Item.tsx +++ b/client/src/CommandBar/Body/Item.tsx @@ -76,23 +76,26 @@ const CommandBarItem = ({ [index, setFocusedIndex], ); - const handleClick = useCallback(() => { - if (onClick) { - onClick(); - if (closeOnClick) { - setIsVisible(false); - setChosenStep({ id: CommandBarStepEnum.INITIAL }); + const handleClick = useCallback( + (e: React.MouseEvent | KeyboardEvent) => { + if (onClick) { + onClick(e); + if (closeOnClick) { + setIsVisible(false); + setChosenStep({ id: CommandBarStepEnum.INITIAL }); + } + } else { + setChosenStep({ + id: id as Exclude< + CommandBarStepEnum, + CommandBarStepEnum.ADD_TO_STUDIO | CommandBarStepEnum.SEARCH_DOCS + >, + }); } - } else { - setChosenStep({ - id: id as Exclude< - CommandBarStepEnum, - CommandBarStepEnum.ADD_TO_STUDIO | CommandBarStepEnum.SEARCH_DOCS - >, - }); - } - updateArrayInStorage(RECENT_COMMANDS_KEY, itemKey); - }, [id, onClick, closeOnClick, itemKey]); + updateArrayInStorage(RECENT_COMMANDS_KEY, itemKey); + }, + [id, onClick, closeOnClick, itemKey], + ); const handleKeyEvent = useCallback( (e: KeyboardEvent) => { @@ -103,7 +106,7 @@ const CommandBarItem = ({ ) { e.preventDefault(); e.stopPropagation(); - handleClick(); + handleClick(e); return; } if (focusedIndex === index && shortAction?.action) { diff --git a/client/src/CommandBar/steps/SeachFiles.tsx b/client/src/CommandBar/steps/SeachFiles.tsx index a2a59737eb..20fe826fca 100644 --- a/client/src/CommandBar/steps/SeachFiles.tsx +++ b/client/src/CommandBar/steps/SeachFiles.tsx @@ -1,4 +1,4 @@ -import { +import React, { ChangeEvent, memo, useCallback, @@ -12,7 +12,11 @@ import { Trans, useTranslation } from 'react-i18next'; import Header from '../Header'; import { CommandBarStepEnum, TabTypesEnum } from '../../types/general'; import { CommandBarContext } from '../../context/commandBarContext'; -import { getAutocomplete } from '../../services/api'; +import { + getAutocomplete, + getCodeStudio, + patchCodeStudio, +} from '../../services/api'; import { FileResItem } from '../../types/api'; import Body from '../Body'; import FileIcon from '../../components/FileIcon'; @@ -34,7 +38,9 @@ const SearchFiles = ({ studioId }: Props) => { const { setChosenStep, setIsVisible } = useContext( CommandBarContext.Handlers, ); - const { project } = useContext(ProjectContext.Current); + const { project, refreshCurrentProjectRepos } = useContext( + ProjectContext.Current, + ); const { openNewTab } = useContext(TabsContext.Handlers); const { setIsLeftSidebarFocused } = useContext(UIContext.Focus); const [files, setFiles] = useState< @@ -65,7 +71,7 @@ const SearchFiles = ({ studioId }: Props) => { if (project?.id) { getAutocomplete( project.id, - `path:${searchValue}&content=false&page_size=20`, + `path:${searchValue}&content=false&file=true&page_size=20`, ).then((respPath) => { const fileResults = respPath.data .filter( @@ -96,41 +102,89 @@ const SearchFiles = ({ studioId }: Props) => { items: filterOutDuplicates( files.map((f) => ({ ...f, key: `${f.path}-${f.repo}-${f.branch}` })), 'key', - ).map(({ path, repo, branch, key }) => ({ - key, - id: key, - onClick: () => { - openNewTab({ - type: TabTypesEnum.FILE, - path, - repoRef: repo, - branch, - studioId, - }); - setIsLeftSidebarFocused(false); - setIsVisible(false); - setChosenStep({ id: CommandBarStepEnum.INITIAL }); - }, - label: path, - footerHint: `${splitPath(repo) - .slice(repo.startsWith('local//') ? -1 : -2) - .join('/')} ${ - branch ? `/ ${splitPath(branch).pop()} ` : '' - }/ ${path}`, - footerBtns: [ - { - label: studioId ? t('Add file') : t('Open'), - shortcut: ['entr'], + ).map(({ path, repo, branch, key }) => { + const addMultipleFilesToStudio = async () => { + if (project?.id && studioId) { + const studio = await getCodeStudio(project.id, studioId); + const patchedFile = studio?.context.find( + (f) => + f.path === path && f.repo === repo && f.branch === branch, + ); + if (!patchedFile) { + await patchCodeStudio(project.id, studioId, { + context: [ + ...(studio?.context || []), + { + path, + branch: branch, + repo, + hidden: false, + ranges: [], + }, + ], + }); + refreshCurrentProjectRepos(); + openNewTab({ + type: TabTypesEnum.FILE, + path, + repoRef: repo, + branch, + studioId, + isFileInContext: true, + initialRanges: [], + }); + } + } + }; + return { + key, + id: key, + onClick: async (e: React.MouseEvent | KeyboardEvent) => { + if (studioId && e.shiftKey && project?.id) { + await addMultipleFilesToStudio(); + } else { + openNewTab({ + type: TabTypesEnum.FILE, + path, + repoRef: repo, + branch, + studioId, + }); + setIsLeftSidebarFocused(false); + setIsVisible(false); + setChosenStep({ id: CommandBarStepEnum.INITIAL }); + } }, - ], - Icon: (props: { sizeClassName?: string }) => ( - - ), - })), + label: path, + footerHint: `${splitPath(repo) + .slice(repo.startsWith('local//') ? -1 : -2) + .join('/')} ${ + branch ? `/ ${splitPath(branch).pop()} ` : '' + }/ ${path}`, + footerBtns: [ + ...(studioId + ? [ + { + label: t('Add multiple files'), + shortcut: ['shift', 'entr'], + action: addMultipleFilesToStudio, + }, + ] + : []), + { + label: studioId ? t('Add file') : t('Open'), + shortcut: ['entr'], + }, + ], + Icon: (props: { sizeClassName?: string }) => ( + + ), + }; + }), itemsOffset: 0, }, ]; - }, [files, studioId]); + }, [files, studioId, project?.id]); return (
diff --git a/client/src/Project/LeftSidebar/NavPanel/Studios/AddContextFile.tsx b/client/src/Project/LeftSidebar/NavPanel/Studios/AddContextFile.tsx index c09f6ca80f..31ee9e3cce 100644 --- a/client/src/Project/LeftSidebar/NavPanel/Studios/AddContextFile.tsx +++ b/client/src/Project/LeftSidebar/NavPanel/Studios/AddContextFile.tsx @@ -4,13 +4,15 @@ import Button from '../../../../components/Button'; import { CommandBarContext } from '../../../../context/commandBarContext'; import { CommandBarStepEnum } from '../../../../types/general'; import { useArrowNavigationItemProps } from '../../../../hooks/useArrowNavigationItemProps'; +import PlusSign from '../../../../icons/PlusSign'; type Props = { studioId: string; index: string; + isFull?: boolean; }; -const AddContextFile = ({ studioId, index }: Props) => { +const AddContextFile = ({ studioId, index, isFull }: Props) => { useTranslation(); const { setChosenStep, setIsVisible } = useContext( CommandBarContext.Handlers, @@ -28,17 +30,31 @@ const AddContextFile = ({ studioId, index }: Props) => { return (
-
-

- Studio conversation require at least one context file. -

- -
+ {isFull ? ( +
+

+ + Studio conversation require at least one context file. + +

+ +
+ ) : ( +
+ + Add files +
+ )}
); }; diff --git a/client/src/Project/LeftSidebar/NavPanel/Studios/StudioEntry.tsx b/client/src/Project/LeftSidebar/NavPanel/Studios/StudioEntry.tsx index 5823207921..a228b3207c 100644 --- a/client/src/Project/LeftSidebar/NavPanel/Studios/StudioEntry.tsx +++ b/client/src/Project/LeftSidebar/NavPanel/Studios/StudioEntry.tsx @@ -21,6 +21,8 @@ import Tooltip from '../../../../components/Tooltip'; import Badge from '../../../../components/Badge'; import { IndexingStatusType } from '../../../../types/general'; import { useArrowNavigationItemProps } from '../../../../hooks/useArrowNavigationItemProps'; +import PlusSign from '../../../../icons/PlusSign'; +import Button from '../../../../components/Button'; import StudioSubItem from './StudioSubItem'; import AddContextFile from './AddContextFile'; import StudioFile from './StudioFile'; @@ -121,8 +123,12 @@ const StudioEntry = ({
Context files
- {!context.length && !previewingSnapshot && ( - + {!previewingSnapshot && ( + )} {(previewingSnapshot?.context || context).map((f, i) => ( void | Promise; }[]; iconContainerClassName?: string; - onClick?: () => void; + onClick?: (e: React.MouseEvent | KeyboardEvent) => void | Promise; }; export type CommandBarItemInvisibleType = {