From eb77812a68e457b449fd369baecfac91e9bacd8e Mon Sep 17 00:00:00 2001 From: Mikita Butsko Date: Wed, 14 Feb 2024 14:43:30 +0100 Subject: [PATCH 1/2] fix: fix shared with me display --- .../src/components/Common/ItemContextMenu.tsx | 1 + apps/chat/src/hooks/useHandleFileFolders.ts | 2 +- .../conversations/conversations.epics.ts | 27 +++++- .../conversations/conversations.reducers.ts | 3 + .../conversations/conversations.selectors.ts | 12 +++ apps/chat/src/store/files/files.epics.ts | 3 +- .../src/store/prompts/prompts.selectors.ts | 12 +++ apps/chat/src/store/share/share.epics.ts | 87 ++++++++++++++----- apps/chat/src/utils/app/data/share-service.ts | 26 +++--- .../data/storages/api/api-entity-storage.ts | 4 +- apps/chat/src/utils/app/file.ts | 5 +- apps/chat/src/utils/app/folders.ts | 2 +- apps/chat/src/utils/app/import-export.ts | 10 ++- apps/chat/src/utils/app/share.ts | 2 +- package-lock.json | 22 +---- package.json | 4 +- 16 files changed, 151 insertions(+), 71 deletions(-) diff --git a/apps/chat/src/components/Common/ItemContextMenu.tsx b/apps/chat/src/components/Common/ItemContextMenu.tsx index f72e0a838f..c27a9e8f7e 100644 --- a/apps/chat/src/components/Common/ItemContextMenu.tsx +++ b/apps/chat/src/components/Common/ItemContextMenu.tsx @@ -240,6 +240,7 @@ export default function ItemContextMenu({ name: t('Delete'), dataQa: 'delete', Icon: IconTrashX, + display: !isExternal, onClick: onDelete, }, ], diff --git a/apps/chat/src/hooks/useHandleFileFolders.ts b/apps/chat/src/hooks/useHandleFileFolders.ts index 6dc693b7ce..1fbd680a1e 100644 --- a/apps/chat/src/hooks/useHandleFileFolders.ts +++ b/apps/chat/src/hooks/useHandleFileFolders.ts @@ -77,7 +77,7 @@ export const useHandleFileFolders = ( * @param folderId - ID of the folder to toggle. */ const handleToggleFolder = useCallback( - (folderId: string | undefined) => { + (folderId: string) => { if (!folderId) { setIsAllFilesOpened((value) => !value); setOpenedFoldersIds([]); diff --git a/apps/chat/src/store/conversations/conversations.epics.ts b/apps/chat/src/store/conversations/conversations.epics.ts index 4349528929..537247c25c 100644 --- a/apps/chat/src/store/conversations/conversations.epics.ts +++ b/apps/chat/src/store/conversations/conversations.epics.ts @@ -76,6 +76,7 @@ import { ApiKeys } from '@/src/utils/server/api'; import { ChatBody, Conversation, + ConversationInfo, Message, MessageSettings, Playback, @@ -83,7 +84,7 @@ import { Role, } from '@/src/types/chat'; import { EntityType, FeatureType, UploadStatus } from '@/src/types/common'; -import { FolderType } from '@/src/types/folder'; +import { FolderInterface, FolderType } from '@/src/types/folder'; import { MigrationStorageKeys, StorageType } from '@/src/types/storage'; import { AppEpic } from '@/src/types/store'; @@ -2096,8 +2097,18 @@ const uploadConversationsWithFoldersEpic: AppEpic = (action$) => ), ).pipe( switchMap((foldersAndEntities) => { - const folders = foldersAndEntities.flatMap((f) => f.folders); - const conversations = foldersAndEntities.flatMap((f) => f.entities); + const folders = foldersAndEntities + .flatMap((f) => f.folders) + .map((item) => ({ + ...item, + ...(payload.inheritedMetadata as Partial), + })); + const conversations = foldersAndEntities + .flatMap((f) => f.entities) + .map((item) => ({ + ...item, + ...(payload.inheritedMetadata as Partial), + })); return concat( of( ConversationsActions.uploadFoldersSuccess({ @@ -2150,10 +2161,15 @@ const uploadConversationsWithFoldersRecursiveEpic: AppEpic = (action$) => of( ConversationsActions.uploadFoldersSuccess({ paths: new Set(), - folders: getFoldersFromIds(paths, FolderType.Chat), + folders: getFoldersFromIds( + paths, + FolderType.Chat, + UploadStatus.LOADED, + ), allLoaded: true, }), ), + of(ConversationsActions.initFoldersAndConversationsSuccess()), ); }), catchError(() => of(ConversationsActions.uploadConversationsFail())), // TODO: handle error it in https://github.com/epam/ai-dial-chat/issues/663 @@ -2198,6 +2214,9 @@ const openFolderEpic: AppEpic = (action$, state$) => of( ConversationsActions.uploadConversationsWithFolders({ paths: [payload.id], + inheritedMetadata: { + sharedWithMe: true, + }, }), ), ); diff --git a/apps/chat/src/store/conversations/conversations.reducers.ts b/apps/chat/src/store/conversations/conversations.reducers.ts index 2f2883496c..cbf3e01acc 100644 --- a/apps/chat/src/store/conversations/conversations.reducers.ts +++ b/apps/chat/src/store/conversations/conversations.reducers.ts @@ -86,6 +86,7 @@ export const conversationsSlice = createSlice({ ) => state, initSelectedConversations: (state) => state, initFoldersAndConversations: (state) => state, + initFoldersAndConversationsSuccess: (state) => state, saveConversation: (state, _action: PayloadAction) => state, recreateConversation: ( state, @@ -595,6 +596,8 @@ export const conversationsSlice = createSlice({ payload, }: PayloadAction<{ paths: (string | undefined)[]; + // Needed for open shared with me folder and keep shared with me flag + inheritedMetadata?: unknown; }>, ) => { state.foldersStatus = UploadStatus.LOADING; diff --git a/apps/chat/src/store/conversations/conversations.selectors.ts b/apps/chat/src/store/conversations/conversations.selectors.ts index 1e36f6b762..a0f075aba9 100644 --- a/apps/chat/src/store/conversations/conversations.selectors.ts +++ b/apps/chat/src/store/conversations/conversations.selectors.ts @@ -168,6 +168,18 @@ export const selectChildAndCurrentFoldersIdsById = createSelector( return new Set(getChildAndCurrentFoldersIdsById(folderId, folders)); }, ); +export const selectFullTreeChildConversationsByFolderId = createSelector( + [selectConversations, selectChildAndCurrentFoldersIdsById], + (conversations, foldersIds) => { + return conversations.filter((conv) => foldersIds.has(conv.folderId)); + }, +); +export const selectFullTreeChildFoldersByFolderId = createSelector( + [selectFolders, selectChildAndCurrentFoldersIdsById], + (folders, foldersIds) => { + return folders.filter((folder) => foldersIds.has(folder.id)); + }, +); export const selectFirstSelectedConversation = createSelector( [selectSelectedConversations], (conversations): Conversation | undefined => { diff --git a/apps/chat/src/store/files/files.epics.ts b/apps/chat/src/store/files/files.epics.ts index 448d5cdc9a..a72fce3199 100644 --- a/apps/chat/src/store/files/files.epics.ts +++ b/apps/chat/src/store/files/files.epics.ts @@ -17,6 +17,7 @@ import { combineEpics } from 'redux-observable'; import { FileService } from '@/src/utils/app/data/file-service'; import { triggerDownload } from '@/src/utils/app/file'; import { translate } from '@/src/utils/app/translation'; +import { encodeApiUrl } from '@/src/utils/server/api'; import { UploadStatus } from '@/src/types/common'; import { AppEpic } from '@/src/types/store'; @@ -229,7 +230,7 @@ const downloadFilesListEpic: AppEpic = (action$, state$) => tap(({ files }) => { files.forEach((file) => triggerDownload( - `api/${encodeURI(`${file.absolutePath}/${file.name}`)}`, + `api/${encodeApiUrl(`${file.absolutePath}/${file.name}`)}`, file.name, ), ); diff --git a/apps/chat/src/store/prompts/prompts.selectors.ts b/apps/chat/src/store/prompts/prompts.selectors.ts index 6c7bdd6b33..f0b0933630 100644 --- a/apps/chat/src/store/prompts/prompts.selectors.ts +++ b/apps/chat/src/store/prompts/prompts.selectors.ts @@ -124,6 +124,18 @@ export const selectChildAndCurrentFoldersIdsById = createSelector( return new Set(getChildAndCurrentFoldersIdsById(folderId, folders)); }, ); +export const selectFullTreeChildPromptsByFolderId = createSelector( + [selectPrompts, selectChildAndCurrentFoldersIdsById], + (prompts, foldersIds) => { + return prompts.filter((conv) => foldersIds.has(conv.folderId)); + }, +); +export const selectFullTreeChildFoldersByFolderId = createSelector( + [selectFolders, selectChildAndCurrentFoldersIdsById], + (folders, foldersIds) => { + return folders.filter((folder) => foldersIds.has(folder.id)); + }, +); export const selectSearchTerm = createSelector([rootSelector], (state) => { return state.searchTerm; diff --git a/apps/chat/src/store/share/share.epics.ts b/apps/chat/src/store/share/share.epics.ts index 59f69f3d53..c6f0f2d679 100644 --- a/apps/chat/src/store/share/share.epics.ts +++ b/apps/chat/src/store/share/share.epics.ts @@ -17,7 +17,7 @@ import { ShareService } from '@/src/utils/app/data/share-service'; import { constructPath } from '@/src/utils/app/file'; import { splitEntityId } from '@/src/utils/app/folders'; import { translate } from '@/src/utils/app/translation'; -import { parseConversationApiKey } from '@/src/utils/server/api'; +import { encodeApiUrl, parseConversationApiKey } from '@/src/utils/server/api'; import { Conversation, Message } from '@/src/types/chat'; import { @@ -111,7 +111,7 @@ const shareConversationEpic: AppEpic = (action$) => invitationType: ShareRequestType.link, resources: [ { - url: encodeURI(payload.resourceId), + url: encodeApiUrl(payload.resourceId), }, ...internalResources.map((res) => ({ url: res })), ], @@ -159,7 +159,7 @@ const shareConversationFolderEpic: AppEpic = (action$) => invitationType: ShareRequestType.link, resources: [ { - url: encodeURI(payload.resourceId + '/'), + url: encodeApiUrl(payload.resourceId) + '/', }, ...internalResourcesIds, ], @@ -190,7 +190,7 @@ const sharePromptEpic: AppEpic = (action$) => invitationType: ShareRequestType.link, resources: [ { - url: encodeURI(payload.resourceId), + url: encodeApiUrl(payload.resourceId), }, ], }).pipe( @@ -215,7 +215,7 @@ const sharePromptFolderEpic: AppEpic = (action$) => invitationType: ShareRequestType.link, resources: [ { - url: encodeURI(payload.resourceId + '/'), + url: encodeApiUrl(payload.resourceId) + '/', }, ], }).pipe( @@ -289,7 +289,7 @@ const triggerGettingSharedListingsConversationsEpic: AppEpic = ( action$.pipe( filter( (action) => - ConversationsActions.uploadConversationsSuccess.match(action) || + ConversationsActions.initFoldersAndConversationsSuccess.match(action) || ShareActions.acceptShareInvitationSuccess.match(action), ), filter(() => @@ -391,20 +391,44 @@ const getSharedListingSuccessEpic: AppEpic = (action$, state$) => state$.value, ); const folders = ConversationsSelectors.selectFolders(state$.value); + actions.push( ...(folders - .map((item) => { + .flatMap((item) => { const isShared = payload.resources.folders.find( (res) => res.id === item.id, ); if (isShared) { - return ConversationsActions.updateFolder({ - folderId: item.id, - values: { - isShared: true, - }, - }); + const childConversations = + ConversationsSelectors.selectFullTreeChildConversationsByFolderId( + state$.value, + item.id, + ); + const childFolders = + ConversationsSelectors.selectFullTreeChildFoldersByFolderId( + state$.value, + item.id, + ); + + return [ + ...childFolders.map((folder) => + ConversationsActions.updateFolder({ + folderId: folder.id, + values: { + isShared: true, + }, + }), + ), + ...childConversations.map((conv) => + ConversationsActions.updateConversation({ + id: conv.id, + values: { + isShared: true, + }, + }), + ), + ]; } return undefined; }) @@ -473,18 +497,41 @@ const getSharedListingSuccessEpic: AppEpic = (action$, state$) => const folders = PromptsSelectors.selectFolders(state$.value); actions.push( ...(folders - .map((item) => { + .flatMap((item) => { const isShared = payload.resources.folders.find( (res) => res.id === item.id, ); if (isShared) { - return PromptsActions.updateFolder({ - folderId: item.id, - values: { - isShared: true, - }, - }); + const childPrompts = + PromptsSelectors.selectFullTreeChildPromptsByFolderId( + state$.value, + item.id, + ); + const childFolders = + PromptsSelectors.selectFullTreeChildFoldersByFolderId( + state$.value, + item.id, + ); + + return [ + ...childFolders.map((folder) => + PromptsActions.updateFolder({ + folderId: folder.id, + values: { + isShared: true, + }, + }), + ), + ...childPrompts.map((prompt) => + PromptsActions.updatePrompt({ + id: prompt.id, + values: { + isShared: true, + }, + }), + ), + ]; } return undefined; }) diff --git a/apps/chat/src/utils/app/data/share-service.ts b/apps/chat/src/utils/app/data/share-service.ts index ec4d45adc7..9c44be1bdc 100644 --- a/apps/chat/src/utils/app/data/share-service.ts +++ b/apps/chat/src/utils/app/data/share-service.ts @@ -20,6 +20,7 @@ import { import { ApiKeys, ApiUtils, + decodeApiUrl, getFolderTypeByApiKey, parseConversationApiKey, parsePromptApiKey, @@ -66,25 +67,26 @@ export class ShareService { if (entity.nodeType === BackendDataNodeType.ITEM) { const conversation = conversationResource as BackendChatEntity; - const id = decodeURI( - conversation.url.slice(0, conversation.url.length - 1), - ); + const id = decodeApiUrl(conversation.url); + const { apiKey, bucket, parentPath } = splitEntityId(id); entities.push({ ...parseConversationApiKey(conversation.name), - id: decodeURI(conversation.url), + id, lastActivityDate: conversation.updatedAt, folderId: constructPath(apiKey, bucket, parentPath), }); } if (entity.nodeType === BackendDataNodeType.FOLDER) { const folder = conversationResource as BackendChatFolder; - const id = decodeURI(folder.url.slice(0, folder.url.length - 1)); + const id = decodeApiUrl( + folder.url.slice(0, folder.url.length - 1), + ); const { apiKey, bucket, parentPath } = splitEntityId(id); folders.push({ - id: decodeURI(folder.url.slice(0, folder.url.length - 1)), + id, name: folder.name, folderId: constructPath(apiKey, bucket, parentPath), type: getFolderTypeByApiKey(ApiKeys.Conversations), @@ -99,25 +101,25 @@ export class ShareService { if (entity.nodeType === BackendDataNodeType.ITEM) { const conversation = conversationResource as BackendChatEntity; - const id = decodeURI( - conversation.url.slice(0, conversation.url.length - 1), - ); + const id = decodeApiUrl(conversation.url); const { apiKey, bucket, parentPath } = splitEntityId(id); entities.push({ ...parsePromptApiKey(conversation.name), - id: decodeURI(conversation.url), + id, lastActivityDate: conversation.updatedAt, folderId: constructPath(apiKey, bucket, parentPath), }); } if (entity.nodeType === BackendDataNodeType.FOLDER) { const folder = conversationResource as BackendChatFolder; - const id = decodeURI(folder.url.slice(0, folder.url.length - 1)); + const id = decodeApiUrl( + folder.url.slice(0, folder.url.length - 1), + ); const { apiKey, bucket, parentPath } = splitEntityId(id); folders.push({ - id: decodeURI(folder.url.slice(0, folder.url.length - 1)), + id, name: folder.name, folderId: constructPath(apiKey, bucket, parentPath), type: getFolderTypeByApiKey(ApiKeys.Prompts), diff --git a/apps/chat/src/utils/app/data/storages/api/api-entity-storage.ts b/apps/chat/src/utils/app/data/storages/api/api-entity-storage.ts index 4a5f0d685e..17b987ff39 100644 --- a/apps/chat/src/utils/app/data/storages/api/api-entity-storage.ts +++ b/apps/chat/src/utils/app/data/storages/api/api-entity-storage.ts @@ -36,6 +36,7 @@ export abstract class ApiEntityStorage< name: folder.name, folderId: constructPath(apiKey, bucket, parentPath), type: getFolderTypeByApiKey(this.getStorageKey()), + isShared: false, }; } @@ -49,6 +50,7 @@ export abstract class ApiEntityStorage< id, lastActivityDate: entity.updatedAt, folderId: constructPath(apiKey, bucket, parentPath), + isShared: false, } as unknown as TEntityInfo; } @@ -150,7 +152,7 @@ export abstract class ApiEntityStorage< 'Content-Type': 'application/json', }, body: JSON.stringify(this.cleanUpEntity(entity)), - }) // TODO: handle error it in https://github.com/epam/ai-dial-chat/issues/663 + }); // TODO: handle error it in https://github.com/epam/ai-dial-chat/issues/663 } updateEntity(entity: TEntity): Observable { diff --git a/apps/chat/src/utils/app/file.ts b/apps/chat/src/utils/app/file.ts index ccfb5fc0b5..9e030cb4ce 100644 --- a/apps/chat/src/utils/app/file.ts +++ b/apps/chat/src/utils/app/file.ts @@ -3,6 +3,7 @@ import { UploadStatus } from '@/src/types/common'; import { DialFile } from '@/src/types/files'; import { FolderInterface } from '@/src/types/folder'; +import { decodeApiUrl, encodeApiUrl } from '../server/api'; import { getPathToFolderById } from './folders'; import escapeStringRegexp from 'escape-string-regexp'; @@ -53,7 +54,7 @@ export const getUserCustomContent = ( .map((file) => ({ type: file.contentType, title: file.name, - url: encodeURI(`${file.absolutePath}/${file.name}`), + url: encodeApiUrl(`${file.absolutePath}/${file.name}`), })), }; }; @@ -122,7 +123,7 @@ export const getFilesWithInvalidFileSize = ( }; const parseAttachmentUrl = (url: string) => { - const decodedUrl = decodeURI(url); + const decodedUrl = decodeApiUrl(url); const lastIndexSlash = decodedUrl.lastIndexOf('/'); return { diff --git a/apps/chat/src/utils/app/folders.ts b/apps/chat/src/utils/app/folders.ts index c4e29e7570..83e8e8c8e8 100644 --- a/apps/chat/src/utils/app/folders.ts +++ b/apps/chat/src/utils/app/folders.ts @@ -323,7 +323,7 @@ export const findRootFromItems = ( const parentIds = new Set(items.map((item) => item.id)); return items.find((item) => { - if (!item.folderId) return true; + if (isRootId(item.folderId)) return true; return !parentIds.has(item.folderId); }); }; diff --git a/apps/chat/src/utils/app/import-export.ts b/apps/chat/src/utils/app/import-export.ts index eca89499cd..001dc03950 100644 --- a/apps/chat/src/utils/app/import-export.ts +++ b/apps/chat/src/utils/app/import-export.ts @@ -14,7 +14,7 @@ import { } from '@/src/types/import-export'; import { Prompt } from '@/src/types/prompt'; -import { ApiKeys } from '../server/api'; +import { ApiKeys, decodeApiUrl, encodeApiUrl } from '../server/api'; import { cleanConversationHistory } from './clean'; import { combineEntities } from './common'; import { triggerDownload } from './file'; @@ -329,7 +329,7 @@ export const getAttachmentId = ({ }) => { const regExpForAttachmentId = /^files\/\w*\//; - const attachmentId = decodeURI(url).split(regExpForAttachmentId)[ + const attachmentId = decodeApiUrl(url).split(regExpForAttachmentId)[ attachmentIdIndex ]; @@ -392,13 +392,15 @@ export const updateAttachment = ({ const newAttachmentUrl = oldAttachment.url && - encodeURI(`${newAttachmentFile.absolutePath}/${newAttachmentFile.name}`); + encodeApiUrl(`${newAttachmentFile.absolutePath}/${newAttachmentFile.name}`); const lastSlashIndex = oldAttachmentId.lastIndexOf('/'); const oldAttachmentNameInPath = oldAttachmentId.slice(lastSlashIndex + 1); const newReferenceUrl = oldAttachment.reference_url && - encodeURI(`${newAttachmentFile.absolutePath}/${oldAttachmentNameInPath}`); + encodeApiUrl( + `${newAttachmentFile.absolutePath}/${oldAttachmentNameInPath}`, + ); const updatedAttachment: Attachment = { ...oldAttachment, diff --git a/apps/chat/src/utils/app/share.ts b/apps/chat/src/utils/app/share.ts index 84442ba2ad..4c73ef7292 100644 --- a/apps/chat/src/utils/app/share.ts +++ b/apps/chat/src/utils/app/share.ts @@ -50,7 +50,7 @@ export const hasExternalParent = ( folderId: string | undefined, featureType: FeatureType, ) => { - if (!featureType || !folderId) return false; + if (!featureType) return false; return featureType === FeatureType.Chat ? ConversationsSelectors.hasExternalParent(state, folderId) diff --git a/package-lock.json b/package-lock.json index 4a29947ba4..209f63fd49 100644 --- a/package-lock.json +++ b/package-lock.json @@ -55,8 +55,7 @@ "remark-gfm": "^3.0.1", "rxjs": "^7.8.1", "svgo": "^3.0.2", - "tslib": "^2.6.0", - "uuid": "^9.0.0" + "tslib": "^2.6.0" }, "devDependencies": { "@mozilla/readability": "^0.4.4", @@ -85,7 +84,6 @@ "@types/react": "18.2.33", "@types/react-dom": "18.2.14", "@types/react-syntax-highlighter": "^15.5.6", - "@types/uuid": "^9.0.1", "@typescript-eslint/eslint-plugin": "^6.7.0", "@typescript-eslint/parser": "^6.7.0", "@vitejs/plugin-react": "^4.2.1", @@ -7184,12 +7182,6 @@ "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==" }, - "node_modules/@types/uuid": { - "version": "9.0.8", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz", - "integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==", - "dev": true - }, "node_modules/@types/yargs": { "version": "17.0.32", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", @@ -20682,18 +20674,6 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, - "node_modules/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "bin": { - "uuid": "dist/bin/uuid" - } - }, "node_modules/uvu": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/uvu/-/uvu-0.5.6.tgz", diff --git a/package.json b/package.json index 5974770640..3e667aa59b 100644 --- a/package.json +++ b/package.json @@ -76,8 +76,7 @@ "remark-gfm": "^3.0.1", "rxjs": "^7.8.1", "svgo": "^3.0.2", - "tslib": "^2.6.0", - "uuid": "^9.0.0" + "tslib": "^2.6.0" }, "devDependencies": { "@mozilla/readability": "^0.4.4", @@ -106,7 +105,6 @@ "@types/react": "18.2.33", "@types/react-dom": "18.2.14", "@types/react-syntax-highlighter": "^15.5.6", - "@types/uuid": "^9.0.1", "@typescript-eslint/eslint-plugin": "^6.7.0", "@typescript-eslint/parser": "^6.7.0", "@vitejs/plugin-react": "^4.2.1", From a674332f8c727a7895b9c4502865bb74aa9af8e9 Mon Sep 17 00:00:00 2001 From: Mikita Butsko Date: Wed, 14 Feb 2024 14:45:57 +0100 Subject: [PATCH 2/2] fix: return back delete item --- apps/chat/src/components/Common/ItemContextMenu.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/chat/src/components/Common/ItemContextMenu.tsx b/apps/chat/src/components/Common/ItemContextMenu.tsx index c27a9e8f7e..f72e0a838f 100644 --- a/apps/chat/src/components/Common/ItemContextMenu.tsx +++ b/apps/chat/src/components/Common/ItemContextMenu.tsx @@ -240,7 +240,6 @@ export default function ItemContextMenu({ name: t('Delete'), dataQa: 'delete', Icon: IconTrashX, - display: !isExternal, onClick: onDelete, }, ],