diff --git a/.github/workflows/deploy_dev.yml b/.github/workflows/deploy_dev.yml index e6e90aef3d..23d40f9948 100644 --- a/.github/workflows/deploy_dev.yml +++ b/.github/workflows/deploy_dev.yml @@ -6,7 +6,7 @@ on: jobs: gitlab-dev-deploy: if: ${{ github.event.registry_package.package_version.container_metadata.tag.name == 'development' }} - uses: epam/ai-dial-ci/.github/workflows/deploy-development.yml@1.3.1 + uses: epam/ai-dial-ci/.github/workflows/deploy-development.yml@1.4.0 with: gitlab-project-id: '1827' secrets: @@ -16,7 +16,7 @@ jobs: gitlab-dev-deploy-overlay: if: ${{ github.event.registry_package.package_version.container_metadata.tag.name == 'development' }} - uses: epam/ai-dial-ci/.github/workflows/deploy-development.yml@1.3.1 + uses: epam/ai-dial-ci/.github/workflows/deploy-development.yml@1.4.0 with: gitlab-project-id: '1856' secrets: diff --git a/.github/workflows/e2e_tests.yml b/.github/workflows/e2e_tests.yml index b76a9c4dbc..0373b8857e 100644 --- a/.github/workflows/e2e_tests.yml +++ b/.github/workflows/e2e_tests.yml @@ -6,7 +6,7 @@ on: jobs: e2e-tests: if: ${{ github.event.registry_package.package_version.container_metadata.tag.name == 'development' }} - uses: epam/ai-dial-ci/.github/workflows/e2e-test.yml@1.3.1 + uses: epam/ai-dial-ci/.github/workflows/e2e-test.yml@1.4.0 with: gitlab-project-id: "1843" secrets: diff --git a/.github/workflows/pr-title-check.yml b/.github/workflows/pr-title-check.yml index 8aef1e8d84..f6d358fa66 100644 --- a/.github/workflows/pr-title-check.yml +++ b/.github/workflows/pr-title-check.yml @@ -9,6 +9,6 @@ on: jobs: pr-title-check: - uses: epam/ai-dial-ci/.github/workflows/pr-title-check.yml@1.3.1 + uses: epam/ai-dial-ci/.github/workflows/pr-title-check.yml@1.4.0 secrets: ACTIONS_BOT_TOKEN: ${{ secrets.ACTIONS_BOT_TOKEN }} diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml new file mode 100644 index 0000000000..1e47c58892 --- /dev/null +++ b/.github/workflows/pr.yml @@ -0,0 +1,10 @@ +name: PR Workflow + +on: + pull_request: + branches: [development, release-*] + +jobs: + run_tests: + uses: epam/ai-dial-ci/.github/workflows/node_pr.yml@1.4.0 + secrets: inherit diff --git a/.github/workflows/pr_check_tests.yml b/.github/workflows/pr_check_tests.yml deleted file mode 100644 index b3ea178ccd..0000000000 --- a/.github/workflows/pr_check_tests.yml +++ /dev/null @@ -1,12 +0,0 @@ -name: Code checks - tests - -on: - pull_request: - branches: [development, release-*] - -jobs: - run_tests: - uses: epam/ai-dial-ci/.github/workflows/test_yarn_docker.yml@1.3.1 - secrets: inherit - with: - bypass_ort: false diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ab89195d30..73586da443 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,13 +1,10 @@ -name: Release version +name: Release Workflow on: push: branches: [ development, release-* ] -env: - IMAGE_NAME: ${{ github.repository }} - jobs: release: - uses: epam/ai-dial-ci/.github/workflows/publish_yarn_docker.yml@1.3.1 + uses: epam/ai-dial-ci/.github/workflows/node_release.yml@1.4.0 secrets: inherit diff --git a/Dockerfile b/Dockerfile index f556ba2968..757a3d743f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,7 +15,7 @@ COPY . . RUN npm run build # ---- Only required dependencies ---- -FROM build AS run_ependencies +FROM build AS run_dependencies WORKDIR /app/dist/apps/chat COPY /tools /app/dist/apps/chat/tools RUN npm i @@ -25,8 +25,8 @@ RUN node tools/patch-nextjs.js FROM node:20-alpine AS production RUN apk update && apk upgrade --no-cache libcrypto3 libssl3 WORKDIR /app -COPY --from=run_ependencies /app/dist/apps/chat ./ -COPY --from=run_ependencies /app/startup.sh ./startup.sh +COPY --from=run_dependencies /app/dist/apps/chat ./ +COPY --from=run_dependencies /app/startup.sh ./startup.sh ENV NODE_ENV production ENV NEXT_TELEMETRY_DISABLED 1 diff --git a/apps/chat-e2e/README.md b/apps/chat-e2e/README.md index b6aea9161d..e08840bcf3 100644 --- a/apps/chat-e2e/README.md +++ b/apps/chat-e2e/README.md @@ -59,11 +59,11 @@ CI report includes screenshots for failed tests. The following variables should be placed inside `chat-e2e/.env.local` file in order to run tests locally -| Variable | Required | Description | Available Values | Default values | -|-----------------| -------- |----------------------------------------------------------------------------------------------------------------------------------------------------|------------------| -------------- | -| `E2E_HOST` | No | The host URL for end-to-end testing. | Any string | | -| `E2E_USERNAME` | No | Comma separated list of usernames for e2e authentification. The number of users should be more or equal number of workers set in playwright config | Any string | | -| `E2E_WORKERS` | No | Number of threads to run e2e tests | Any number | | -| `E2E_PASSWORD` | No | A password for e2e authentification | Any string | | -| `TMS_URL` | No | TMS URL | Any string | | -| `ISSUE_URL` | No | Issue URL | Any string | | +| Variable | Required | Description | Available Values | Default values | +| -------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------- | -------------- | +| `E2E_HOST` | No | The host URL for end-to-end testing. | Any string | | +| `E2E_USERNAME` | No | Comma separated list of usernames for e2e authentification. The number of users should be more or equal number of workers set in playwright config | Any string | | +| `E2E_WORKERS` | No | Number of threads to run e2e tests | Any number | | +| `E2E_PASSWORD` | No | A password for e2e authentification | Any string | | +| `TMS_URL` | No | TMS URL | Any string | | +| `ISSUE_URL` | No | Issue URL | Any string | | 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..1e501b33e4 100644 --- a/apps/chat/src/store/prompts/prompts.selectors.ts +++ b/apps/chat/src/store/prompts/prompts.selectors.ts @@ -42,7 +42,7 @@ export const selectFilteredPrompts = createSelector( (!searchTerm || doesPromptOrConversationContainSearchTerm(prompt, searchTerm)) && filters.searchFilter(prompt) && - (prompt.folderId || filters.sectionFilter(prompt)), + filters.sectionFilter(prompt), ); }, ); @@ -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",