Skip to content

Commit

Permalink
fix(chat): Fix recipient of the shared code app can not upload new fi…
Browse files Browse the repository at this point in the history
…les in the code editor (Issues #3040, #2968, #2971) (#3061)
  • Loading branch information
denys-kolomiitsev authored Feb 3, 2025
1 parent 1bd4666 commit ca2cbbc
Show file tree
Hide file tree
Showing 14 changed files with 166 additions and 108 deletions.
21 changes: 2 additions & 19 deletions apps/chat/src/components/Chat/TalkTo/TalkToCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
getApplicationNextStatus,
getApplicationSimpleStatus,
getModelShortDescription,
getPlayerCaption,
isApplicationStatusUpdating,
isExecutableApp,
} from '@/src/utils/app/application';
Expand All @@ -24,10 +25,7 @@ import { isMyApplication } from '@/src/utils/app/id';
import { canWriteSharedWithMe } from '@/src/utils/app/share';
import { PseudoModel, isPseudoModel } from '@/src/utils/server/api';

import {
ApplicationStatus,
SimpleApplicationStatus,
} from '@/src/types/applications';
import { SimpleApplicationStatus } from '@/src/types/applications';
import { Conversation } from '@/src/types/chat';
import { FeatureType } from '@/src/types/common';
import { DisplayMenuItemProps } from '@/src/types/menu';
Expand Down Expand Up @@ -62,21 +60,6 @@ import ShareIcon from '../../Common/ShareIcon';
import IconUserUnshare from '@/public/images/icons/unshare-user.svg';
import { Feature } from '@epam/ai-dial-shared';

const getPlayerCaption = (entity: DialAIEntityModel) => {
switch (entity.functionStatus) {
case ApplicationStatus.DEPLOYED:
return 'Undeploy';
case ApplicationStatus.UNDEPLOYED:
case ApplicationStatus.FAILED:
return 'Deploy';
case ApplicationStatus.UNDEPLOYING:
return 'Undeploying';
case ApplicationStatus.DEPLOYING:
default:
return 'Deploying';
}
};

interface ApplicationCardProps {
entity: DialAIEntityModel;
conversation: Conversation;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { useCallback } from 'react';
import { useCallback, useMemo } from 'react';
import { useFormContext } from 'react-hook-form';

import classNames from 'classnames';

import { useTranslation } from '@/src/hooks/useTranslation';

import { constructPath } from '@/src/utils/app/file';
import { splitEntityId } from '@/src/utils/app/folders';
import { getIdWithoutRootPathSegments } from '@/src/utils/app/id';

import { Translation } from '@/src/types/translation';
Expand Down Expand Up @@ -36,6 +37,11 @@ export const CodeAppExampleLink = ({

const dispatch = useAppDispatch();

const bucket = useMemo(() => {
const { bucket } = splitEntityId(folderId);
return bucket;
}, [folderId]);

const handleClick = useCallback(() => {
const example = CODE_APPS_EXAMPLES[exampleType];
Object.entries(example.files).forEach(([newFileName, content]) => {
Expand All @@ -48,6 +54,7 @@ export const CodeAppExampleLink = ({
relativePath: getIdWithoutRootPathSegments(folderId),
id: constructPath(folderId, newFileName),
name: newFileName,
bucket,
}),
);
}
Expand Down Expand Up @@ -83,7 +90,7 @@ export const CodeAppExampleLink = ({
}
});
}
}, [exampleType, fileNames, dispatch, folderId, setValue, getValues]);
}, [exampleType, fileNames, dispatch, folderId, bucket, getValues, setValue]);

return (
<span
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -313,11 +313,20 @@ export const CodeEditor = ({ sourcesFolderId }: Props) => {
rootFolders: [],
};
}, [files, folders, sourcesFolderId]);

const rootFileNames = useMemo(
() => rootFiles.map((f) => f.name),
[rootFiles],
);

const { bucket, parentPath } = useMemo(() => {
if (sourcesFolderId) {
const { bucket, parentPath } = splitEntityId(sourcesFolderId);
return { bucket, parentPath };
}
return { bucket: undefined, parentPath: undefined };
}, [sourcesFolderId]);

useEffect(() => {
if (sourcesFolderId) {
dispatch(CodeEditorActions.initCodeEditor({ sourcesFolderId }));
Expand All @@ -342,6 +351,11 @@ export const CodeEditor = ({ sourcesFolderId }: Props) => {
[dispatch, openedFoldersIds],
);

const openUploadDialog = useCallback(() => {
setUploadFolderId(sourcesFolderId);
dispatch(FilesActions.getFolders({ id: parentPath }));
}, [dispatch, parentPath, sourcesFolderId]);

const handleUploadFiles = useCallback(
(
selectedFiles: Required<Pick<DialFile, 'fileContent' | 'id' | 'name'>>[],
Expand All @@ -354,11 +368,12 @@ export const CodeEditor = ({ sourcesFolderId }: Props) => {
id: file.id,
relativePath: folderPath,
name: file.name,
bucket,
}),
);
});
},
[dispatch],
[bucket, dispatch],
);

const handleDeleteFile = useCallback(
Expand Down Expand Up @@ -395,7 +410,6 @@ export const CodeEditor = ({ sourcesFolderId }: Props) => {
const handleUploadEmptyFile = useCallback(
(fileName: string) => {
if (fileName && sourcesFolderId) {
const { bucket } = splitEntityId(sourcesFolderId);
dispatch(
FilesActions.uploadFile({
fileContent: new File([''], fileName, {
Expand All @@ -411,7 +425,7 @@ export const CodeEditor = ({ sourcesFolderId }: Props) => {
setNewFileName('');
}
},
[dispatch, sourcesFolderId],
[bucket, dispatch, sourcesFolderId],
);

const handleToggleFolder = useCallback(
Expand Down Expand Up @@ -597,7 +611,7 @@ export const CodeEditor = ({ sourcesFolderId }: Props) => {
<Tooltip tooltip={t('Upload file')}>
<button
type="button"
onClick={() => setUploadFolderId(sourcesFolderId)}
onClick={openUploadDialog}
className="text-secondary hover:text-accent-primary"
>
<IconUpload size={18} />
Expand Down Expand Up @@ -652,6 +666,7 @@ export const CodeEditor = ({ sourcesFolderId }: Props) => {
onUploadFiles={handleUploadFiles}
onClose={() => setUploadFolderId(undefined)}
maximumAttachmentsAmount={Number.MAX_SAFE_INTEGER}
rootFolderId={sourcesFolderId}
/>
)}
<ConfirmDialog
Expand Down
36 changes: 24 additions & 12 deletions apps/chat/src/components/Common/FolderContextMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
hasInvalidNameInPath,
isEntityNameInvalid,
} from '@/src/utils/app/common';
import { canEditSharedFolderOrParent } from '@/src/utils/app/folders';
import { isEntityIdExternal, isMyEntity } from '@/src/utils/app/id';
import { isEntityIdPublic } from '@/src/utils/app/publications';

Expand All @@ -26,6 +27,7 @@ import { FolderInterface } from '@/src/types/folder';
import { DisplayMenuItemProps } from '@/src/types/menu';
import { Translation } from '@/src/types/translation';

import { FilesSelectors } from '@/src/store/files/files.reducers';
import { useAppSelector } from '@/src/store/hooks';
import { SettingsSelectors } from '@/src/store/settings/settings.reducers';

Expand Down Expand Up @@ -79,11 +81,23 @@ export const FolderContextMenu = ({
SettingsSelectors.isSharingEnabled(state, featureType),
);

const folders = useAppSelector(FilesSelectors.selectFolders);

const isExternal = isEntityIdExternal(folder);
const isNameInvalid = isEntityNameInvalid(folder.name);
const isInvalidPath = hasInvalidNameInPath(folder.folderId);
const disableAll = isNameInvalid || isInvalidPath;

const canEditShared = useMemo(() => {
return canEditSharedFolderOrParent(folders, folder.folderId);
}, [folder.folderId, folders]);

const isMyFolder = useMemo(() => {
return isMyEntity(folder, featureType);
}, [featureType, folder]);

const isMyOrCanEdit = isMyFolder || canEditShared;

const menuItems: DisplayMenuItemProps[] = useMemo(
() => [
{
Expand All @@ -95,15 +109,15 @@ export const FolderContextMenu = ({
},
{
name: t('Upload'),
display: !!onUpload && !isExternal,
display: !!onUpload && isMyOrCanEdit,
dataQa: 'upload',
Icon: IconUpload,
onClick: onUpload,
disabled: disableAll,
},
{
name: t('Rename'),
display: (!!onRename && !isExternal) || !!folder.temporary,
display: !!onRename && (!isExternal || !!folder.temporary),
dataQa: 'rename',
Icon: IconPencilMinus,
onClick: onRename,
Expand Down Expand Up @@ -166,23 +180,20 @@ export const FolderContextMenu = ({
{
name: t('Delete'),
display:
(!!onDelete && isMyEntity(folder, featureType)) || !!folder.temporary,
dataQa: 'delete',
Icon: IconTrashX,
onClick: onDelete,
},
{
name: t('Delete'),
display: !!onDelete && !!folder.sharedWithMe,
!!onDelete &&
(isMyEntity(folder, featureType) ||
!!folder.temporary ||
!!folder.sharedWithMe),
dataQa: 'delete',
Icon: IconTrashX,
onClick: onDelete,
},

{
name: t('Add new folder'),
display:
(!!onAddFolder && !isExternal) ||
!!additionalItemData?.isChangePathFolder,
!!onAddFolder &&
(isMyOrCanEdit || !!additionalItemData?.isChangePathFolder),
dataQa: 'new-folder',
Icon: IconFolderPlus,
onClick: onAddFolder,
Expand All @@ -197,6 +208,7 @@ export const FolderContextMenu = ({
onSelect,
featureType,
onUpload,
isMyOrCanEdit,
disableAll,
onRename,
folder,
Expand Down
4 changes: 2 additions & 2 deletions apps/chat/src/components/Files/FileItemContextMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { MouseEvent, MouseEventHandler, useMemo } from 'react';

import { useTranslation } from '@/src/hooks/useTranslation';

import { isCurrentFolderOrParentSharedWithMeAndCanEdit } from '@/src/utils/app/folders';
import { canEditSharedFolderOrParent } from '@/src/utils/app/folders';
import { isMyEntity } from '@/src/utils/app/id';

import { FeatureType } from '@/src/types/common';
Expand Down Expand Up @@ -118,7 +118,7 @@ export function FileItemContextMenu({
display:
isMyEntity(file, FeatureType.File) ||
!!file.sharedWithMe ||
isCurrentFolderOrParentSharedWithMeAndCanEdit(folders, file.folderId),
canEditSharedFolderOrParent(folders, file.folderId),

Icon: IconTrashX,
onClick: onDelete,
Expand Down
33 changes: 26 additions & 7 deletions apps/chat/src/components/Files/PreUploadModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,11 @@ import {
notAllowedSymbols,
prepareFileName,
} from '@/src/utils/app/file';
import { getParentAndCurrentFoldersById } from '@/src/utils/app/folders';
import { getFileRootId } from '@/src/utils/app/id';
import {
getParentAndCurrentFoldersById,
splitEntityId,
} from '@/src/utils/app/folders';
import { getFileRootId, isMyBucket } from '@/src/utils/app/id';

import { DialFile } from '@/src/types/files';
import { ModalState } from '@/src/types/modal';
Expand All @@ -33,6 +36,7 @@ import { FilesActions, FilesSelectors } from '@/src/store/files/files.reducers';
import { useAppDispatch, useAppSelector } from '@/src/store/hooks';

import { OUTSIDE_PRESS_AND_MOUSE_EVENT } from '@/src/constants/modal';
import { SHARED_WITH_ME_SECTION_NAME } from '@/src/constants/sections';

import Modal from '@/src/components/Common/Modal';

Expand All @@ -52,6 +56,7 @@ interface Props {
) => void;
uploadFolderId?: string;
customUploadButtonLabel?: string;
rootFolderId?: string;
}

const bytesInMb = 1_048_576;
Expand All @@ -66,6 +71,7 @@ export const PreUploadDialog = ({
onUploadFiles,
uploadFolderId,
customUploadButtonLabel,
rootFolderId,
}: Props) => {
const dispatch = useAppDispatch();
const { t } = useTranslation(Translation.Chat);
Expand All @@ -82,12 +88,20 @@ export const PreUploadDialog = ({
const [isChangeFolderModalOpened, setIsChangeFolderModalOpened] =
useState(false);
const [selectedFolderId, setSelectedFolderId] = useState(
uploadFolderId || getFileRootId(),
uploadFolderId || rootFolderId || getFileRootId(),
);

const headingId = useId();
const descriptionId = useId();

const { bucket, name: rootFolderName } = useMemo(
() =>
rootFolderId
? splitEntityId(rootFolderId)
: { bucket: undefined, name: undefined },
[rootFolderId],
);

const folderPath = useMemo(() => {
return (
getParentAndCurrentFoldersById(folders, selectedFolderId)
Expand Down Expand Up @@ -156,7 +170,7 @@ export const PreUploadDialog = ({
return {
fileContent: file,
id: constructPath(
getFileRootId(),
getFileRootId(bucket),
folderPath,
prepareFileName(file.name),
),
Expand All @@ -169,7 +183,7 @@ export const PreUploadDialog = ({
uploadInputRef.current.value = '';
}
},
[allowedTypes, folderPath, t],
[allowedTypes, bucket, folderPath, t],
);

const handleUpload = useCallback(() => {
Expand Down Expand Up @@ -400,7 +414,12 @@ export const PreUploadDialog = ({
data-qa="change-path-container"
>
<span className="truncate" data-qa="path">
{constructPath(t('All files'), folderPath)}
{!bucket || isMyBucket(bucket)
? constructPath(t('All files'), folderPath ?? rootFolderName)
: constructPath(
t(SHARED_WITH_ME_SECTION_NAME),
folderPath ?? rootFolderName,
)}
</span>
<span
className="cursor-pointer text-accent-primary"
Expand Down Expand Up @@ -490,7 +509,7 @@ export const PreUploadDialog = ({
<SelectFolderModal
isOpen={isChangeFolderModalOpened}
initialSelectedFolderId={selectedFolderId}
rootFolderId={getFileRootId()}
rootFolderId={rootFolderId ?? getFileRootId(bucket)}
onClose={(folderId) => {
if (folderId) {
setSelectedFolderId(folderId);
Expand Down
Loading

0 comments on commit ca2cbbc

Please sign in to comment.