Skip to content

Commit

Permalink
Merge branch 'development' into feat/update-e2e-with-stateful-api
Browse files Browse the repository at this point in the history
  • Loading branch information
irinakartun authored Feb 14, 2024
2 parents 8412955 + acc322c commit fe7e8b8
Show file tree
Hide file tree
Showing 15 changed files with 150 additions and 71 deletions.
2 changes: 1 addition & 1 deletion apps/chat/src/hooks/useHandleFileFolders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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([]);
Expand Down
27 changes: 23 additions & 4 deletions apps/chat/src/store/conversations/conversations.epics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,14 +76,15 @@ import { ApiKeys } from '@/src/utils/server/api';
import {
ChatBody,
Conversation,
ConversationInfo,
Message,
MessageSettings,
Playback,
RateBody,
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';

Expand Down Expand Up @@ -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<FolderInterface>),
}));
const conversations = foldersAndEntities
.flatMap((f) => f.entities)
.map((item) => ({
...item,
...(payload.inheritedMetadata as Partial<ConversationInfo>),
}));
return concat(
of(
ConversationsActions.uploadFoldersSuccess({
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -2198,6 +2214,9 @@ const openFolderEpic: AppEpic = (action$, state$) =>
of(
ConversationsActions.uploadConversationsWithFolders({
paths: [payload.id],
inheritedMetadata: {
sharedWithMe: true,
},
}),
),
);
Expand Down
3 changes: 3 additions & 0 deletions apps/chat/src/store/conversations/conversations.reducers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ export const conversationsSlice = createSlice({
) => state,
initSelectedConversations: (state) => state,
initFoldersAndConversations: (state) => state,
initFoldersAndConversationsSuccess: (state) => state,
saveConversation: (state, _action: PayloadAction<Conversation>) => state,
recreateConversation: (
state,
Expand Down Expand Up @@ -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;
Expand Down
12 changes: 12 additions & 0 deletions apps/chat/src/store/conversations/conversations.selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 => {
Expand Down
3 changes: 2 additions & 1 deletion apps/chat/src/store/files/files.epics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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,
),
);
Expand Down
12 changes: 12 additions & 0 deletions apps/chat/src/store/prompts/prompts.selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
87 changes: 67 additions & 20 deletions apps/chat/src/store/share/share.epics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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 })),
],
Expand Down Expand Up @@ -159,7 +159,7 @@ const shareConversationFolderEpic: AppEpic = (action$) =>
invitationType: ShareRequestType.link,
resources: [
{
url: encodeURI(payload.resourceId + '/'),
url: encodeApiUrl(payload.resourceId) + '/',
},
...internalResourcesIds,
],
Expand Down Expand Up @@ -190,7 +190,7 @@ const sharePromptEpic: AppEpic = (action$) =>
invitationType: ShareRequestType.link,
resources: [
{
url: encodeURI(payload.resourceId),
url: encodeApiUrl(payload.resourceId),
},
],
}).pipe(
Expand All @@ -215,7 +215,7 @@ const sharePromptFolderEpic: AppEpic = (action$) =>
invitationType: ShareRequestType.link,
resources: [
{
url: encodeURI(payload.resourceId + '/'),
url: encodeApiUrl(payload.resourceId) + '/',
},
],
}).pipe(
Expand Down Expand Up @@ -289,7 +289,7 @@ const triggerGettingSharedListingsConversationsEpic: AppEpic = (
action$.pipe(
filter(
(action) =>
ConversationsActions.uploadConversationsSuccess.match(action) ||
ConversationsActions.initFoldersAndConversationsSuccess.match(action) ||
ShareActions.acceptShareInvitationSuccess.match(action),
),
filter(() =>
Expand Down Expand Up @@ -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;
})
Expand Down Expand Up @@ -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;
})
Expand Down
26 changes: 14 additions & 12 deletions apps/chat/src/utils/app/data/share-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
import {
ApiKeys,
ApiUtils,
decodeApiUrl,
getFolderTypeByApiKey,
parseConversationApiKey,
parsePromptApiKey,
Expand Down Expand Up @@ -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),
Expand All @@ -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),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export abstract class ApiEntityStorage<
name: folder.name,
folderId: constructPath(apiKey, bucket, parentPath),
type: getFolderTypeByApiKey(this.getStorageKey()),
isShared: false,
};
}

Expand All @@ -49,6 +50,7 @@ export abstract class ApiEntityStorage<
id,
lastActivityDate: entity.updatedAt,
folderId: constructPath(apiKey, bucket, parentPath),
isShared: false,
} as unknown as TEntityInfo;
}

Expand Down Expand Up @@ -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<void> {
Expand Down
Loading

0 comments on commit fe7e8b8

Please sign in to comment.