Skip to content

Commit 7a6ffb9

Browse files
mikitabutnartovm
andauthored
feat(overlay): add rename, delete, playback and export actions (#3833)
Co-authored-by: Maksim Nartov <[email protected]>
1 parent 33bd925 commit 7a6ffb9

File tree

8 files changed

+627
-78
lines changed

8 files changed

+627
-78
lines changed

apps/chat/src/store/overlay/overlay.epics.ts

Lines changed: 283 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,11 @@ import {
2222

2323
import { combineEpics, ofType } from 'redux-observable';
2424

25-
import { parseCommaSeparatedList } from '@/src/utils/app/common';
25+
import {
26+
doesHaveDotsInTheEnd,
27+
isEntityNameOnSameLevelUnique,
28+
parseCommaSeparatedList,
29+
} from '@/src/utils/app/common';
2630
import { constructPath } from '@/src/utils/app/file';
2731
import {
2832
getActionsAddFoldersFromFolderId,
@@ -50,6 +54,7 @@ import { UISelectors } from '@/src/store/ui/ui.selectors';
5054

5155
import { DEFAULT_CONVERSATION_NAME } from '@/src/constants/default-ui-settings';
5256

57+
import { ImportExportActions } from '../actions';
5358
import { AuthSelectors } from '../auth/auth.selectors';
5459
import { ModelsSelectors } from '../models/models.selectors';
5560
import { OverlayActions } from './overlay.reducers';
@@ -59,12 +64,18 @@ import {
5964
ChatOverlayOptions,
6065
CreateConversationRequest,
6166
CreateConversationResponse,
67+
CreatePlaybackConversationRequest,
68+
CreatePlaybackConversationResponse,
69+
DeleteConversationRequest,
70+
ExportConversationRequest,
6271
Feature,
6372
GetConversationsResponse,
6473
GetMessagesResponse,
6574
OverlayEvents,
6675
OverlayRequest,
6776
OverlayRequests,
77+
RenameConversationRequest,
78+
RenameConversationResponse,
6879
Role,
6980
SelectConversationRequest,
7081
SelectConversationResponse,
@@ -117,6 +128,47 @@ export const postMessageMapperEpic: AppEpic = (_, state$) =>
117128
}),
118129
);
119130
}
131+
case OverlayRequests.deleteConversation: {
132+
const options = payload as DeleteConversationRequest;
133+
134+
return of(
135+
OverlayActions.deleteConversation({
136+
requestId,
137+
id: options.id,
138+
}),
139+
);
140+
}
141+
case OverlayRequests.renameConversation: {
142+
const options = payload as RenameConversationRequest;
143+
144+
return of(
145+
OverlayActions.renameConversation({
146+
requestId,
147+
id: options.id,
148+
newName: options.newName,
149+
}),
150+
);
151+
}
152+
case OverlayRequests.createPlaybackConversation: {
153+
const options = payload as CreatePlaybackConversationRequest;
154+
155+
return of(
156+
OverlayActions.createPlaybackConversation({
157+
requestId,
158+
id: options.id,
159+
}),
160+
);
161+
}
162+
case OverlayRequests.exportConversation: {
163+
const options = payload as ExportConversationRequest;
164+
165+
return of(
166+
OverlayActions.exportConversation({
167+
requestId,
168+
id: options.id,
169+
}),
170+
);
171+
}
120172
case OverlayRequests.setOverlayOptions: {
121173
const options = payload as ChatOverlayOptions;
122174

@@ -301,6 +353,230 @@ const createConversationEffectEpic: AppEpic = (action$, state$) =>
301353
}),
302354
);
303355

356+
const deleteConversationEpic: AppEpic = (action$, state$) =>
357+
action$.pipe(
358+
ofType(OverlayActions.deleteConversation.type),
359+
switchMap(({ payload: { requestId, id } }) => {
360+
const hostDomain = OverlaySelectors.selectHostDomain(state$.value);
361+
const conversation = ConversationsSelectors.selectConversation(
362+
state$.value,
363+
id,
364+
);
365+
366+
if (!conversation) {
367+
console.warn(`[Overlay] Conversation not exists with id '${id}'`);
368+
369+
return EMPTY;
370+
}
371+
372+
return concat(
373+
of(
374+
ConversationsActions.deleteConversations({
375+
conversationIds: [conversation.id],
376+
}),
377+
),
378+
of(
379+
OverlayActions.sendPMResponse({
380+
type: OverlayRequests.deleteConversation,
381+
requestParams: {
382+
requestId,
383+
hostDomain,
384+
},
385+
}),
386+
),
387+
);
388+
}),
389+
);
390+
391+
const createPlaybackConversationEpic: AppEpic = (action$, state$) =>
392+
action$.pipe(
393+
ofType(OverlayActions.createPlaybackConversation.type),
394+
switchMap(({ payload }) => {
395+
const conversation = ConversationsSelectors.selectConversation(
396+
state$.value,
397+
payload.id,
398+
);
399+
400+
if (!conversation) {
401+
console.warn(
402+
`[Overlay] Conversation not exists with id '${payload.id}'`,
403+
);
404+
405+
return EMPTY;
406+
}
407+
408+
return concat(
409+
of(ConversationsActions.createNewPlaybackConversation(conversation)),
410+
of(OverlayActions.createPlaybackConversationEffect(payload)),
411+
);
412+
}),
413+
);
414+
415+
const createPlaybackConversationEffectEpic: AppEpic = (action$, state$) =>
416+
action$.pipe(
417+
ofType(OverlayActions.createPlaybackConversationEffect.type),
418+
switchMap(({ payload: { requestId } }) => {
419+
return action$.pipe(
420+
ofType(ConversationsActions.saveNewConversationSuccess.type),
421+
takeUntil(timer(10000)),
422+
filter(Boolean),
423+
mergeMap(({ payload: { newConversation } }) => {
424+
const hostDomain = OverlaySelectors.selectHostDomain(state$.value);
425+
426+
const { bucket, parentPath } = splitEntityId(newConversation.id);
427+
const resultConversation = {
428+
...newConversation,
429+
bucket,
430+
parentPath,
431+
};
432+
433+
return concat(
434+
of(UIActions.setScrollToEntityId(newConversation.id)),
435+
of(
436+
OverlayActions.sendPMResponse({
437+
type: OverlayRequests.createPlaybackConversation,
438+
requestParams: {
439+
requestId,
440+
hostDomain,
441+
payload: {
442+
conversation: resultConversation,
443+
} as CreatePlaybackConversationResponse,
444+
},
445+
}),
446+
),
447+
);
448+
}),
449+
);
450+
}),
451+
);
452+
453+
const renameConversationEpic: AppEpic = (action$, state$) =>
454+
action$.pipe(
455+
ofType(OverlayActions.renameConversation.type),
456+
switchMap(({ payload }) => {
457+
const conversations = ConversationsSelectors.selectConversations(
458+
state$.value,
459+
);
460+
const conversation = ConversationsSelectors.selectConversation(
461+
state$.value,
462+
payload.id,
463+
);
464+
465+
if (!conversation) {
466+
console.warn(
467+
`[Overlay] Conversation not exists with id '${payload.id}'`,
468+
);
469+
470+
return EMPTY;
471+
}
472+
473+
if (
474+
!isEntityNameOnSameLevelUnique(
475+
payload.newName,
476+
conversation,
477+
conversations,
478+
) ||
479+
doesHaveDotsInTheEnd(payload.newName)
480+
) {
481+
console.warn(
482+
'[Overlay] Conversation rename failed because new name is invalid',
483+
);
484+
485+
return EMPTY;
486+
}
487+
488+
return concat(
489+
of(
490+
ConversationsActions.updateConversation({
491+
id: conversation.id,
492+
values: { name: payload.newName, isNameChanged: true },
493+
}),
494+
),
495+
of(OverlayActions.renameConversationEffect(payload)),
496+
);
497+
}),
498+
);
499+
500+
const renameConversationEffectEpic: AppEpic = (action$, state$) =>
501+
action$.pipe(
502+
ofType(OverlayActions.renameConversationEffect.type),
503+
switchMap(({ payload: { requestId } }) => {
504+
return action$.pipe(
505+
ofType(ConversationsActions.updateConversationSuccess.type),
506+
takeUntil(timer(10000)),
507+
filter(Boolean),
508+
mergeMap(({ payload: { id } }) => {
509+
const conversation = ConversationsSelectors.selectConversation(
510+
state$.value,
511+
id,
512+
);
513+
514+
if (!conversation) return EMPTY;
515+
516+
const hostDomain = OverlaySelectors.selectHostDomain(state$.value);
517+
518+
const { bucket, parentPath } = splitEntityId(conversation.id);
519+
const resultConversation = {
520+
...conversation,
521+
bucket,
522+
parentPath,
523+
};
524+
525+
return concat(
526+
of(UIActions.setScrollToEntityId(conversation.id)),
527+
of(
528+
OverlayActions.sendPMResponse({
529+
type: OverlayRequests.renameConversation,
530+
requestParams: {
531+
requestId,
532+
hostDomain,
533+
payload: {
534+
conversation: resultConversation,
535+
} as RenameConversationResponse,
536+
},
537+
}),
538+
),
539+
);
540+
}),
541+
);
542+
}),
543+
);
544+
545+
const exportConversationEpic: AppEpic = (action$, state$) =>
546+
action$.pipe(
547+
ofType(OverlayActions.exportConversation.type),
548+
switchMap(({ payload: { requestId, id } }) => {
549+
const hostDomain = OverlaySelectors.selectHostDomain(state$.value);
550+
const conversation = ConversationsSelectors.selectConversation(
551+
state$.value,
552+
id,
553+
);
554+
555+
if (!conversation) {
556+
console.warn(`[Overlay] Conversation not exists with id '${id}'`);
557+
558+
return EMPTY;
559+
}
560+
561+
return concat(
562+
of(
563+
ImportExportActions.exportConversation({
564+
conversationId: conversation.id,
565+
}),
566+
),
567+
of(
568+
OverlayActions.sendPMResponse({
569+
type: OverlayRequests.exportConversation,
570+
requestParams: {
571+
requestId,
572+
hostDomain,
573+
},
574+
}),
575+
),
576+
);
577+
}),
578+
);
579+
304580
const selectConversationEpic: AppEpic = (action$, state$) =>
305581
action$.pipe(
306582
ofType(OverlayActions.selectConversation.type),
@@ -710,6 +986,12 @@ export const OverlayEpics = combineEpics(
710986
createConversationEpic,
711987
createConversationEffectEpic,
712988
selectConversationEpic,
989+
deleteConversationEpic,
990+
createPlaybackConversationEpic,
991+
createPlaybackConversationEffectEpic,
992+
exportConversationEpic,
993+
renameConversationEpic,
994+
renameConversationEffectEpic,
713995

714996
initOverlayEpic,
715997
sendPMEventEpic,

apps/chat/src/store/overlay/overlay.reducers.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,12 @@ import { OverlayState } from './overlay.types';
1010
import {
1111
ChatOverlayOptions,
1212
CreateConversationRequest,
13+
CreatePlaybackConversationRequest,
14+
DeleteConversationRequest,
15+
ExportConversationRequest,
1316
OverlayEvents,
1417
OverlayRequests,
18+
RenameConversationRequest,
1519
SelectConversationRequest,
1620
SendMessageRequest,
1721
SetSystemPromptRequest,
@@ -45,6 +49,30 @@ export const overlaySlice = createSlice({
4549
state,
4650
_action: PayloadAction<WithRequestId<SelectConversationRequest>>,
4751
) => state,
52+
deleteConversation: (
53+
state,
54+
_action: PayloadAction<WithRequestId<DeleteConversationRequest>>,
55+
) => state,
56+
renameConversation: (
57+
state,
58+
_action: PayloadAction<WithRequestId<RenameConversationRequest>>,
59+
) => state,
60+
renameConversationEffect: (
61+
state,
62+
_action: PayloadAction<WithRequestId<RenameConversationRequest>>,
63+
) => state,
64+
createPlaybackConversation: (
65+
state,
66+
_action: PayloadAction<WithRequestId<CreatePlaybackConversationRequest>>,
67+
) => state,
68+
createPlaybackConversationEffect: (
69+
state,
70+
_action: PayloadAction<WithRequestId<CreatePlaybackConversationRequest>>,
71+
) => state,
72+
exportConversation: (
73+
state,
74+
_action: PayloadAction<WithRequestId<ExportConversationRequest>>,
75+
) => state,
4876
createConversation: (
4977
state,
5078
_action: PayloadAction<WithRequestId<CreateConversationRequest>>,

0 commit comments

Comments
 (0)