From cb9c65050a85576e5ed833a4dd8aec2e12dbfa3e Mon Sep 17 00:00:00 2001 From: Denys Kolomiitsev Date: Tue, 21 Jan 2025 11:59:00 +0100 Subject: [PATCH 1/4] feat: add shared with me app to the installed models --- apps/chat/src/store/models/models.epics.ts | 9 ++-- apps/chat/src/store/share/share.epics.ts | 57 ++++++++++++++-------- 2 files changed, 42 insertions(+), 24 deletions(-) diff --git a/apps/chat/src/store/models/models.epics.ts b/apps/chat/src/store/models/models.epics.ts index f7f09b73e..9e014460e 100644 --- a/apps/chat/src/store/models/models.epics.ts +++ b/apps/chat/src/store/models/models.epics.ts @@ -174,10 +174,11 @@ const getInstalledModelIdsEpic: AppEpic = (action$, state$) => const allModels = ModelsSelectors.selectModels(state$.value); return allModels - .filter((model) => - model.id.startsWith( - getRootId({ featureType: FeatureType.Application }), - ), + .filter( + (model) => + model.id.startsWith( + getRootId({ featureType: FeatureType.Application }), + ) || model.sharedWithMe, ) .map((app) => app.reference); }), diff --git a/apps/chat/src/store/share/share.epics.ts b/apps/chat/src/store/share/share.epics.ts index aa72f2c9a..c138b79eb 100644 --- a/apps/chat/src/store/share/share.epics.ts +++ b/apps/chat/src/store/share/share.epics.ts @@ -899,30 +899,47 @@ const getSharedListingSuccessEpic: AppEpic = (action$, state$) => } else { //TODO make request for the shared applications to add them into the state when share invitation is accepted. //TODO new action-service needs to be created. - //TODO add all shared with me agents to installedModels - // const sharedReferences: string[] = []; //part of TODO uncomment or remove if not needed; + const updateSharedActions = payload.resources.entities + .map((sharedItem) => { + const sharedModel = modelsMap[sharedItem.id]; - actions.push( - ...(payload.resources.entities - .map((sharedItem) => { - const sharedModel = modelsMap[sharedItem.id]; + if (sharedModel) { + return ModelsActions.updateLocalModels({ + reference: sharedModel.reference, + updatedValues: { + sharedWithMe: true, + permissions: sharedItem.permissions, + }, + }); + } + return undefined; + }) + .filter(Boolean) as AnyAction[]; + + if (updateSharedActions.length) { + updateSharedActions.push(ModelsActions.getInstalledModelIds()); + + const { acceptedId } = ShareSelectors.selectAcceptedEntityInfo( + state$.value, + ); - if (sharedModel) { - // sharedReferences.push(sharedModel.reference); //part of TODO uncomment or remove if not needed; + const acceptedApplicationReference = + acceptedId && modelsMap[acceptedId]?.reference; - return ModelsActions.updateLocalModels({ - reference: sharedModel.reference, - updatedValues: { - sharedWithMe: true, - permissions: sharedItem.permissions, - }, - }); - } - return undefined; - }) - .filter(Boolean) as AnyAction[]), - ); + if (acceptedApplicationReference) { + updateSharedActions.push( + MarketplaceActions.setDetailsModel({ + reference: acceptedApplicationReference, + isSuggested: false, + }), + ); + } + + actions.push(...updateSharedActions); + } + + actions.push(ShareActions.resetAcceptedEntityInfo()); } } From 5a0b454d3096c9f0f8bc3ea7b6807e3d4fd27a5d Mon Sep 17 00:00:00 2001 From: Denys Kolomiitsev Date: Tue, 21 Jan 2025 12:35:12 +0100 Subject: [PATCH 2/4] feat: hide bookmark for the shared with me app --- .../Marketplace/ApplicationCard.tsx | 2 +- .../ApplicationDetails/ApplicationFooter.tsx | 57 ++++++++++--------- 2 files changed, 30 insertions(+), 29 deletions(-) diff --git a/apps/chat/src/components/Marketplace/ApplicationCard.tsx b/apps/chat/src/components/Marketplace/ApplicationCard.tsx index 78e559c2a..01ef01e17 100644 --- a/apps/chat/src/components/Marketplace/ApplicationCard.tsx +++ b/apps/chat/src/components/Marketplace/ApplicationCard.tsx @@ -325,7 +325,7 @@ export const ApplicationCard = ({ triggerIconSize={18} className="m-0 xl:invisible group-hover:xl:visible" /> - {!isMyApp && ( + {!isMyApp && !entity.sharedWithMe && ( )} - {isMyApp ? ( - - - - ) : ( - - + + ) : ( + - - - - )} + + + ))} {isApplicationId(entity.id) && (isMyApp || isPublicApp) && ( From 9620fa1de0810ca6103ac74da4742201fc7da87d Mon Sep 17 00:00:00 2001 From: Denys Kolomiitsev Date: Wed, 22 Jan 2025 18:13:23 +0100 Subject: [PATCH 3/4] fix: fix not all app resources available during sharing --- apps/chat/src/components/Chat/ModelList.tsx | 2 +- .../Chat/Publish/PublicationChatControls.tsx | 6 +- .../Chat/Publish/PublicationHandler.tsx | 11 +- .../ApplicationDetails/ApplicationHeader.tsx | 78 -------------- .../components/Marketplace/TabRenderer.tsx | 2 +- .../store/application/application.epics.ts | 47 ++++++-- .../store/application/application.reducers.ts | 5 +- apps/chat/src/store/models/models.reducers.ts | 45 ++++---- apps/chat/src/store/models/models.types.ts | 6 ++ apps/chat/src/store/share/share.epics.ts | 100 ++++++++++++------ apps/chat/src/store/share/share.reducers.ts | 93 +++------------- apps/chat/src/store/share/share.selectors.ts | 75 +++++++++++++ apps/chat/src/store/share/share.types.ts | 24 +++++ 13 files changed, 259 insertions(+), 235 deletions(-) create mode 100644 apps/chat/src/store/share/share.selectors.ts create mode 100644 apps/chat/src/store/share/share.types.ts diff --git a/apps/chat/src/components/Chat/ModelList.tsx b/apps/chat/src/components/Chat/ModelList.tsx index e4a6544d2..f6adaf1b4 100644 --- a/apps/chat/src/components/Chat/ModelList.tsx +++ b/apps/chat/src/components/Chat/ModelList.tsx @@ -354,7 +354,7 @@ export const ModelList = ({ const handleEdit = useCallback( (currentEntity: DialAIEntityModel) => { - dispatch(ApplicationActions.get(currentEntity.id)); + dispatch(ApplicationActions.get({ applicationId: currentEntity.id })); handleOpenApplicationModal(getApplicationType(currentEntity)); }, [dispatch, handleOpenApplicationModal], diff --git a/apps/chat/src/components/Chat/Publish/PublicationChatControls.tsx b/apps/chat/src/components/Chat/Publish/PublicationChatControls.tsx index 2449b7a9d..23a74064c 100644 --- a/apps/chat/src/components/Chat/Publish/PublicationChatControls.tsx +++ b/apps/chat/src/components/Chat/Publish/PublicationChatControls.tsx @@ -133,9 +133,9 @@ export function PublicationControlsView< unselectConversation(); unselectPrompt(); dispatch( - ApplicationActions.get( - resourcesToReview[publicationIdx + offset].reviewUrl, - ), + ApplicationActions.get({ + applicationId: resourcesToReview[publicationIdx + offset].reviewUrl, + }), ); dispatch(PublicationActions.setIsApplicationReview(true)); } diff --git a/apps/chat/src/components/Chat/Publish/PublicationHandler.tsx b/apps/chat/src/components/Chat/Publish/PublicationHandler.tsx index 6f407877e..c21bd6bd2 100644 --- a/apps/chat/src/components/Chat/Publish/PublicationHandler.tsx +++ b/apps/chat/src/components/Chat/Publish/PublicationHandler.tsx @@ -284,13 +284,10 @@ export function PublicationHandler({ publication }: Props) { }; const startApplicationsReview = () => { - dispatch( - ApplicationActions.get( - applicationsToReviewIds.length - ? applicationsToReviewIds[0].reviewUrl - : reviewedApplicationsIds[0].reviewUrl, - ), - ); + const applicationId = applicationsToReviewIds.length + ? applicationsToReviewIds[0].reviewUrl + : reviewedApplicationsIds[0].reviewUrl; + dispatch(ApplicationActions.get({ applicationId })); dispatch(PublicationActions.setIsApplicationReview(true)); }; diff --git a/apps/chat/src/components/Marketplace/ApplicationDetails/ApplicationHeader.tsx b/apps/chat/src/components/Marketplace/ApplicationDetails/ApplicationHeader.tsx index a148e3f37..88e9c78b9 100644 --- a/apps/chat/src/components/Marketplace/ApplicationDetails/ApplicationHeader.tsx +++ b/apps/chat/src/components/Marketplace/ApplicationDetails/ApplicationHeader.tsx @@ -47,34 +47,6 @@ export const ApplicationDetailsHeader = ({ entity, isMobileView }: Props) => { const isApplicationsSharingEnabled = useAppSelector((state) => SettingsSelectors.isFeatureEnabled(state, Feature.ApplicationsSharing), ); - // const dispatch = useAppDispatch(); - - // const contextMenuItems = useMemo( - // () => [ - // { - // BrandIcon: IconLink, - // text: t('Copy link'), - // onClick: () => { - // dispatch(UIActions.showInfoToast(t('Link copied'))); - // }, - // }, - // { - // BrandIcon: IconBrandFacebook, - // text: t('Share via Facebook'), - // onClick: () => { - // return 'Share via Facebook'; - // }, - // }, - // { - // BrandIcon: IconBrandX, - // text: t('Share via X'), - // onClick: () => { - // return 'Share via X'; - // }, - // }, - // ], - // [dispatch, t], - // ); return (
@@ -109,57 +81,7 @@ export const ApplicationDetailsHeader = ({ entity, isMobileView }: Props) => { - {/*
- - - {t('Share')} - - } - > -
-
- -
{entity.name}
-
-
- {contextMenuItems.map(({ BrandIcon, text, ...props }) => ( - - - {text} - - } - className="flex w-full items-center gap-3 px-3 py-2 hover:bg-accent-primary-alpha" - {...props} - /> - ))} -
-
-
- -
*/} - {/*

- {application.title} -

*/} {isMyApp && isApplicationsSharingEnabled && ( diff --git a/apps/chat/src/components/Marketplace/TabRenderer.tsx b/apps/chat/src/components/Marketplace/TabRenderer.tsx index d8eefd47b..61011ed02 100644 --- a/apps/chat/src/components/Marketplace/TabRenderer.tsx +++ b/apps/chat/src/components/Marketplace/TabRenderer.tsx @@ -320,7 +320,7 @@ export const TabRenderer = ({ screenState }: TabRendererProps) => { const handleEditApplication = useCallback( (entity: DialAIEntityModel) => { - dispatch(ApplicationActions.get(entity.id)); + dispatch(ApplicationActions.get({ applicationId: entity.id })); setApplicationModel({ entity, action: ApplicationActionType.EDIT, diff --git a/apps/chat/src/store/application/application.epics.ts b/apps/chat/src/store/application/application.epics.ts index 7737b4520..556103679 100644 --- a/apps/chat/src/store/application/application.epics.ts +++ b/apps/chat/src/store/application/application.epics.ts @@ -1,5 +1,6 @@ import { EMPTY, + Observable, concat, concatMap, from, @@ -10,6 +11,8 @@ import { } from 'rxjs'; import { catchError, filter, map, switchMap } from 'rxjs/operators'; +import { AnyAction } from '@reduxjs/toolkit'; + import { combineEpics } from 'redux-observable'; import { regenerateApplicationId } from '@/src/utils/app/application'; @@ -33,6 +36,7 @@ import { DeleteType } from '@/src/constants/marketplace'; import { ApplicationActions } from '../application/application.reducers'; import { AuthSelectors } from '../auth/auth.reducers'; import { ModelsActions, ModelsSelectors } from '../models/models.reducers'; +import { ShareActions, ShareSelectors } from '../share/share.reducers'; const createApplicationEpic: AppEpic = (action$) => action$.pipe( @@ -179,17 +183,42 @@ const getApplicationEpic: AppEpic = (action$, state$) => action$.pipe( filter(ApplicationActions.get.match), switchMap(({ payload }) => - ApplicationService.get(payload).pipe( - map((application) => { + ApplicationService.get(payload.applicationId).pipe( + switchMap((application) => { + if (!application) { + return of(ApplicationActions.getFail()); + } + const modelsMap = ModelsSelectors.selectModelsMap(state$.value); - return application - ? ApplicationActions.getSuccess({ + const modelFromState = modelsMap[application.reference]; + + const actions: Observable[] = []; + actions.push( + of( + ApplicationActions.getSuccess({ ...application, - sharedWithMe: modelsMap[application.reference]?.sharedWithMe, - permissions: modelsMap[application.reference]?.permissions, - isShared: modelsMap[application.reference]?.isShared, - }) - : ApplicationActions.getFail(); + sharedWithMe: modelFromState?.sharedWithMe, + permissions: modelFromState?.permissions, + isShared: modelFromState?.isShared, + }), + ), + ); + + if (payload.isForSharing) { + const permissionsFromState = ShareSelectors.selectSharePermissions( + state$.value, + ); + actions.push( + of( + ShareActions.shareApplication({ + resourceId: application.id, + permissions: permissionsFromState, + }), + ), + ); + } + + return concat(...actions); }), catchError((err) => { console.error('Failed to get application:', err); diff --git a/apps/chat/src/store/application/application.reducers.ts b/apps/chat/src/store/application/application.reducers.ts index 066ddab0a..05e983097 100644 --- a/apps/chat/src/store/application/application.reducers.ts +++ b/apps/chat/src/store/application/application.reducers.ts @@ -73,7 +73,10 @@ export const applicationSlice = createSlice({ updateFail: (state) => { state.appLoading = UploadStatus.FAILED; }, - get: (state, _action: PayloadAction) => { + get: ( + state, + _action: PayloadAction<{ applicationId: string; isForSharing?: boolean }>, + ) => { state.appLoading = UploadStatus.LOADING; }, getSuccess: (state, action: PayloadAction) => { diff --git a/apps/chat/src/store/models/models.reducers.ts b/apps/chat/src/store/models/models.reducers.ts index d13855c62..6726c9c63 100644 --- a/apps/chat/src/store/models/models.reducers.ts +++ b/apps/chat/src/store/models/models.reducers.ts @@ -3,7 +3,7 @@ import { PayloadAction, createSlice } from '@reduxjs/toolkit'; import { combineEntities } from '@/src/utils/app/common'; import { translate } from '@/src/utils/app/translation'; -import { ApplicationInfo, ApplicationStatus } from '@/src/types/applications'; +import { ApplicationStatus } from '@/src/types/applications'; import { ErrorMessage } from '@/src/types/error'; import { DialAIEntityModel, @@ -16,7 +16,7 @@ import { errorsMessages } from '@/src/constants/errors'; import { DeleteType } from '@/src/constants/marketplace'; import * as ModelsSelectors from './models.selectors'; -import { ModelsState } from './models.types'; +import { ModelUpdatedValues, ModelsState } from './models.types'; import { UploadStatus } from '@epam/ai-dial-shared'; import cloneDeep from 'lodash-es/cloneDeep'; @@ -274,31 +274,32 @@ export const modelsSlice = createSlice({ { payload, }: PayloadAction<{ - reference: string; - updatedValues: Partial; + modelsToUpdate: ModelUpdatedValues[]; }>, ) => { - const model = state.modelsMap[payload.reference]; + payload.modelsToUpdate.forEach((modelToUpdate) => { + const model = state.modelsMap[modelToUpdate.reference]; - if (model) { - const updatedModel = { - ...model, - ...payload.updatedValues, - }; - state.modelsMap[model.reference] = updatedModel; - state.modelsMap[model.id] = updatedModel; + if (model) { + const updatedModel = { + ...model, + ...modelToUpdate.updatedValues, + }; + state.modelsMap[model.reference] = updatedModel; + state.modelsMap[model.id] = updatedModel; - state.models = state.models.map((model) => { - if (model.reference === payload.reference) { - return { - ...model, - ...payload.updatedValues, - }; - } + state.models = state.models.map((modelFromState) => { + if (modelFromState.reference === modelToUpdate.reference) { + return { + ...modelFromState, + ...modelToUpdate.updatedValues, + }; + } - return model; - }); - } + return modelFromState; + }); + } + }); }, }, }); diff --git a/apps/chat/src/store/models/models.types.ts b/apps/chat/src/store/models/models.types.ts index 4ee7761ed..f82ce8e67 100644 --- a/apps/chat/src/store/models/models.types.ts +++ b/apps/chat/src/store/models/models.types.ts @@ -1,3 +1,4 @@ +import { ApplicationInfo } from '@/src/types/applications'; import { ErrorMessage } from '@/src/types/error'; import { DialAIEntityModel, @@ -21,3 +22,8 @@ export interface ModelsState { publishRequestModels: PublishRequestDialAIEntityModel[]; publishedApplicationIds: string[]; } + +export interface ModelUpdatedValues { + reference: string; + updatedValues: Partial; +} diff --git a/apps/chat/src/store/share/share.epics.ts b/apps/chat/src/store/share/share.epics.ts index c138b79eb..b174f90b0 100644 --- a/apps/chat/src/store/share/share.epics.ts +++ b/apps/chat/src/store/share/share.epics.ts @@ -16,6 +16,7 @@ import { AnyAction } from '@reduxjs/toolkit'; import { combineEpics } from 'redux-observable'; +import { getApplicationType } from '@/src/utils/app/application'; import { ConversationService } from '@/src/utils/app/data/conversation-service'; import { ShareService } from '@/src/utils/app/data/share-service'; import { @@ -35,6 +36,7 @@ import { hasWritePermission } from '@/src/utils/app/share'; import { translate } from '@/src/utils/app/translation'; import { ApiUtils, parseConversationApiKey } from '@/src/utils/server/api'; +import { ApplicationType } from '@/src/types/applications'; import { Conversation } from '@/src/types/chat'; import { FeatureType } from '@/src/types/common'; import { DialFile } from '@/src/types/files'; @@ -52,7 +54,10 @@ import { DEFAULT_CONVERSATION_NAME } from '@/src/constants/default-ui-settings'; import { errorsMessages } from '@/src/constants/errors'; import { DeleteType } from '@/src/constants/marketplace'; -import { ApplicationSelectors } from '../application/application.reducers'; +import { + ApplicationActions, + ApplicationSelectors, +} from '../application/application.reducers'; import { ConversationsActions, ConversationsSelectors, @@ -60,6 +65,7 @@ import { import { FilesActions, FilesSelectors } from '../files/files.reducers'; import { MarketplaceActions } from '../marketplace/marketplace.reducers'; import { ModelsActions, ModelsSelectors } from '../models/models.reducers'; +import { ModelUpdatedValues } from '../models/models.types'; import { PromptsActions, PromptsSelectors } from '../prompts/prompts.reducers'; import { SettingsSelectors } from '../settings/settings.reducers'; import { UIActions } from '../ui/ui.reducers'; @@ -293,6 +299,30 @@ const shareApplicationEpic: AppEpic = (action$, state$) => action$.pipe( filter(ShareActions.shareApplication.match), switchMap(({ payload }) => { + const modelsMap = ModelsSelectors.selectModelsMap(state$.value); + const application = modelsMap[payload.resourceId]; + + if (!application) { + return of(ShareActions.shareFail()); + } + + const applicationType = getApplicationType(application); + const applicationDetails = ApplicationSelectors.selectApplicationDetail( + state$.value, + ); + + if ( + applicationType === ApplicationType.CODE_APP && + applicationDetails?.reference !== application.reference + ) { + return of( + ApplicationActions.get({ + applicationId: payload.resourceId, + isForSharing: true, + }), + ); + } + const resources: ShareResource[] = [ { url: ApiUtils.encodeApiUrl(payload.resourceId), @@ -300,18 +330,15 @@ const shareApplicationEpic: AppEpic = (action$, state$) => }, ]; - const applicationDetails = ApplicationSelectors.selectApplicationDetail( - state$.value, - ); - - if (applicationDetails?.iconUrl) { + if (application?.iconUrl) { resources.push({ - url: ApiUtils.encodeApiUrl(applicationDetails.iconUrl), + url: ApiUtils.encodeApiUrl(application.iconUrl), }); } if ( hasWritePermission(payload.permissions) && + applicationType && applicationDetails?.function?.sourceFolder ) { resources.push({ @@ -879,45 +906,50 @@ const getSharedListingSuccessEpic: AppEpic = (action$, state$) => if (payload.featureType === FeatureType.Application) { const modelsMap = ModelsSelectors.selectModelsMap(state$.value); if (payload.sharedWith === ShareRelations.others) { - actions.push( - ...(payload.resources.entities - .map((sharedItem) => { - const sharedModel = modelsMap[sharedItem.id]; + const modelsToUpdate = payload.resources.entities + .map((sharedItem) => { + const sharedModel = modelsMap[sharedItem.id]; - if (sharedModel) { - return ModelsActions.updateLocalModels({ - reference: sharedModel.reference, - updatedValues: { - isShared: true, - }, - }); - } - return undefined; - }) - .filter(Boolean) as AnyAction[]), - ); + if (sharedModel) { + return { + reference: sharedModel.reference, + updatedValues: { + isShared: true, + }, + }; + } + return undefined; + }) + .filter(Boolean) as ModelUpdatedValues[]; + + actions.push(ModelsActions.updateLocalModels({ modelsToUpdate })); } else { //TODO make request for the shared applications to add them into the state when share invitation is accepted. //TODO new action-service needs to be created. - const updateSharedActions = payload.resources.entities + const updateSharedActions: AnyAction[] = []; + const modelsToUpdate = payload.resources.entities .map((sharedItem) => { const sharedModel = modelsMap[sharedItem.id]; if (sharedModel) { - return ModelsActions.updateLocalModels({ + return { reference: sharedModel.reference, updatedValues: { sharedWithMe: true, permissions: sharedItem.permissions, }, - }); + }; } return undefined; }) - .filter(Boolean) as AnyAction[]; + .filter(Boolean) as ModelUpdatedValues[]; + + if (modelsToUpdate.length) { + updateSharedActions.push( + ModelsActions.updateLocalModels({ modelsToUpdate }), + ); - if (updateSharedActions.length) { updateSharedActions.push(ModelsActions.getInstalledModelIds()); const { acceptedId } = ShareSelectors.selectAcceptedEntityInfo( @@ -1027,10 +1059,14 @@ const revokeAccessSuccessEpic: AppEpic = (action$, state$) => } return of( ModelsActions.updateLocalModels({ - reference: applicationReference, - updatedValues: { - isShared: false, - }, + modelsToUpdate: [ + { + reference: applicationReference, + updatedValues: { + isShared: false, + }, + }, + ], }), ); } diff --git a/apps/chat/src/store/share/share.reducers.ts b/apps/chat/src/store/share/share.reducers.ts index f094e649c..0dc0d125f 100644 --- a/apps/chat/src/store/share/share.reducers.ts +++ b/apps/chat/src/store/share/share.reducers.ts @@ -1,4 +1,4 @@ -import { PayloadAction, createSelector, createSlice } from '@reduxjs/toolkit'; +import { PayloadAction, createSlice } from '@reduxjs/toolkit'; import { splitEntityId } from '@/src/utils/app/folders'; import { hasWritePermission } from '@/src/utils/app/share'; @@ -9,14 +9,14 @@ import { import { ApplicationInfo } from '@/src/types/applications'; import { FeatureType } from '@/src/types/common'; -import { ErrorMessage } from '@/src/types/error'; import { DialFile } from '@/src/types/files'; import { FolderInterface } from '@/src/types/folder'; import { ModalState } from '@/src/types/modal'; import { Prompt } from '@/src/types/prompt'; import { ShareRelations } from '@/src/types/share'; -import { RootState } from '../index'; +import * as ShareSelectors from './share.selectors'; +import { ShareState } from './share.types'; import { ConversationInfo, @@ -24,23 +24,7 @@ import { UploadStatus, } from '@epam/ai-dial-shared'; -export interface ShareState { - initialized: boolean; - status: UploadStatus; - error: ErrorMessage | undefined; - invitationId: string | undefined; - writeInvitationId: string | undefined; - shareResourceName: string | undefined; - shareResourceVersion: string | undefined; - shareResourceId: string | undefined; - shareModalState: ModalState; - acceptedId: string | undefined; - isFolderAccepted: boolean | undefined; - shareFeatureType?: FeatureType; - shareIsFolder?: boolean; - isConversation?: boolean; - isPrompt?: boolean; -} +export { ShareSelectors }; const initialState: ShareState = { initialized: false, @@ -85,6 +69,7 @@ export const shareSlice = createSlice({ state.shareFeatureType = payload.featureType; state.shareIsFolder = payload.isFolder; state.shareResourceId = payload.resourceId; + state.sharePermissions = payload.permissions; const name = splitEntityId(payload.resourceId).name; state.shareResourceName = @@ -125,12 +110,16 @@ export const shareSlice = createSlice({ ) => state, shareApplication: ( state, - _action: PayloadAction<{ + { + payload, + }: PayloadAction<{ resourceId: string; permissions?: SharePermission[]; }>, ) => { state.shareModalState = ModalState.LOADING; + state.sharePermissions = payload.permissions; + state.shareResourceId = payload.resourceId; }, shareSuccess: ( state, @@ -148,10 +137,12 @@ export const shareSlice = createSlice({ } state.shareModalState = ModalState.OPENED; + state.sharePermissions = undefined; }, shareFail: (state, _action: PayloadAction) => { state.invitationId = undefined; state.shareModalState = ModalState.CLOSED; + state.sharePermissions = undefined; }, revokeAccess: ( @@ -264,64 +255,4 @@ export const shareSlice = createSlice({ }, }); -const rootSelector = (state: RootState): ShareState => state.share; - -const selectInvitationId = createSelector([rootSelector], (state) => { - return state.invitationId; -}); - -const selectWriteInvitationId = createSelector([rootSelector], (state) => { - return state.writeInvitationId; -}); - -const selectShareModalState = createSelector([rootSelector], (state) => { - return state.shareModalState; -}); -const selectShareModalClosed = createSelector([rootSelector], (state) => { - return state.shareModalState === ModalState.CLOSED; -}); - -const selectShareResourceId = createSelector([rootSelector], (state) => { - return state.shareResourceId; -}); - -const selectShareResourceName = createSelector([rootSelector], (state) => { - return state.shareResourceName; -}); -const selectShareResourceVersion = createSelector([rootSelector], (state) => { - return state.shareResourceVersion; -}); -const selectShareFeatureType = createSelector([rootSelector], (state) => { - return state.shareFeatureType; -}); -const selectShareIsFolder = createSelector([rootSelector], (state) => { - return state.shareIsFolder; -}); -const selectAcceptedEntityInfo = createSelector([rootSelector], (state) => { - return { - acceptedId: state.acceptedId, - isFolderAccepted: state.isFolderAccepted, - isConversation: state.isConversation, - isPrompt: state.isPrompt, - }; -}); -const selectInitialized = createSelector( - [rootSelector], - (state) => state.initialized, -); - -export const ShareSelectors = { - selectInvitationId, - selectWriteInvitationId, - selectShareModalState, - selectShareModalClosed, - selectShareResourceName, - selectShareResourceVersion, - selectShareResourceId, - selectAcceptedEntityInfo, - selectShareFeatureType, - selectShareIsFolder, - selectInitialized, -}; - export const ShareActions = shareSlice.actions; diff --git a/apps/chat/src/store/share/share.selectors.ts b/apps/chat/src/store/share/share.selectors.ts new file mode 100644 index 000000000..ce1f6bcae --- /dev/null +++ b/apps/chat/src/store/share/share.selectors.ts @@ -0,0 +1,75 @@ +import { createSelector } from '@reduxjs/toolkit'; + +import { ModalState } from '@/src/types/modal'; + +import { RootState } from '..'; +import { ShareState } from './share.types'; + +const rootSelector = (state: RootState): ShareState => state.share; + +export const selectInvitationId = createSelector([rootSelector], (state) => { + return state.invitationId; +}); + +export const selectWriteInvitationId = createSelector( + [rootSelector], + (state) => { + return state.writeInvitationId; + }, +); + +export const selectShareModalState = createSelector([rootSelector], (state) => { + return state.shareModalState; +}); +export const selectShareModalClosed = createSelector( + [rootSelector], + (state) => { + return state.shareModalState === ModalState.CLOSED; + }, +); + +export const selectShareResourceId = createSelector([rootSelector], (state) => { + return state.shareResourceId; +}); + +export const selectShareResourceName = createSelector( + [rootSelector], + (state) => { + return state.shareResourceName; + }, +); +export const selectShareResourceVersion = createSelector( + [rootSelector], + (state) => { + return state.shareResourceVersion; + }, +); +export const selectShareFeatureType = createSelector( + [rootSelector], + (state) => { + return state.shareFeatureType; + }, +); +export const selectShareIsFolder = createSelector([rootSelector], (state) => { + return state.shareIsFolder; +}); +export const selectAcceptedEntityInfo = createSelector( + [rootSelector], + (state) => { + return { + acceptedId: state.acceptedId, + isFolderAccepted: state.isFolderAccepted, + isConversation: state.isConversation, + isPrompt: state.isPrompt, + }; + }, +); +export const selectInitialized = createSelector( + [rootSelector], + (state) => state.initialized, +); + +export const selectSharePermissions = createSelector( + [rootSelector], + (state) => state.sharePermissions, +); diff --git a/apps/chat/src/store/share/share.types.ts b/apps/chat/src/store/share/share.types.ts new file mode 100644 index 000000000..ba4eba608 --- /dev/null +++ b/apps/chat/src/store/share/share.types.ts @@ -0,0 +1,24 @@ +import { FeatureType } from '@/src/types/common'; +import { ErrorMessage } from '@/src/types/error'; +import { ModalState } from '@/src/types/modal'; + +import { SharePermission, UploadStatus } from '@epam/ai-dial-shared'; + +export interface ShareState { + initialized: boolean; + status: UploadStatus; + error: ErrorMessage | undefined; + invitationId: string | undefined; + writeInvitationId: string | undefined; + shareResourceName: string | undefined; + shareResourceVersion: string | undefined; + shareResourceId: string | undefined; + shareModalState: ModalState; + acceptedId: string | undefined; + isFolderAccepted: boolean | undefined; + shareFeatureType?: FeatureType; + shareIsFolder?: boolean; + isConversation?: boolean; + isPrompt?: boolean; + sharePermissions?: SharePermission[]; +} From df1ec24170cb0497d1cb6773ff757de73805ca26 Mon Sep 17 00:00:00 2001 From: Denys Kolomiitsev Date: Wed, 22 Jan 2025 20:29:02 +0100 Subject: [PATCH 4/4] fix: fix tests --- apps/chat/src/components/Chat/TalkTo/TalkToModal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/chat/src/components/Chat/TalkTo/TalkToModal.tsx b/apps/chat/src/components/Chat/TalkTo/TalkToModal.tsx index 529adcfa9..cdce7fc56 100644 --- a/apps/chat/src/components/Chat/TalkTo/TalkToModal.tsx +++ b/apps/chat/src/components/Chat/TalkTo/TalkToModal.tsx @@ -229,7 +229,7 @@ const TalkToModalView = ({ const handleEditApplication = useCallback( (entity: DialAIEntityModel) => { - dispatch(ApplicationActions.get(entity.id)); + dispatch(ApplicationActions.get({ applicationId: entity.id })); setEditModel(entity); }, [dispatch],