Skip to content

Commit

Permalink
feat(chat): add document_relative_url to application sharing/publishi…
Browse files Browse the repository at this point in the history
…ng flow (Issue #3054) (#3078)

Co-authored-by: Magomed-Elbi Dzhukalaev <[email protected]>
Co-authored-by: Alexander <[email protected]>
  • Loading branch information
3 people authored Feb 3, 2025
1 parent 8b6f709 commit 076c7b8
Show file tree
Hide file tree
Showing 9 changed files with 382 additions and 102 deletions.
152 changes: 152 additions & 0 deletions apps/chat/src/components/Chat/Publish/ApplicationPublishItems.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
import { IconDownload } from '@tabler/icons-react';
import { useEffect, useMemo } from 'react';

import classNames from 'classnames';

import { useTranslation } from '@/src/hooks/useTranslation';

import { getQuickAppDocumentUrl } from '@/src/utils/app/application';
import { constructPath } from '@/src/utils/app/file';
import { splitEntityId } from '@/src/utils/app/folders';
import { isEntityIdExternal } from '@/src/utils/app/id';
import { isEntityIdPublic } from '@/src/utils/app/publications';

import { PublishRequestDialAIEntityModel } from '@/src/types/models';
import { Translation } from '@/src/types/translation';

import { ApplicationSelectors } from '@/src/store/application/application.reducers';
import { FilesActions, FilesSelectors } from '@/src/store/files/files.reducers';
import { useAppDispatch, useAppSelector } from '@/src/store/hooks';

import CollapsibleSection from '@/src/components/Common/CollapsibleSection';
import { ErrorMessage } from '@/src/components/Common/ErrorMessage';
import {
ApplicationRow,
FilesRow,
} from '@/src/components/Common/ReplaceConfirmationModal/Components';
import { Spinner } from '@/src/components/Common/Spinner';

import { PublishActions } from '@epam/ai-dial-shared';

interface ApplicationPublishItemsProps {
entity: PublishRequestDialAIEntityModel;
handleSelectItems: (ids: string[]) => void;
publishAction: PublishActions;
chosenItemsIds: string[];
}

export const ApplicationPublishItems = ({
entity,
handleSelectItems,
publishAction,
chosenItemsIds,
}: ApplicationPublishItemsProps) => {
const { t } = useTranslation(Translation.Chat);
const dispatch = useAppDispatch();

const applicationDetails = useAppSelector(
ApplicationSelectors.selectApplicationDetail,
);
const isApplicationLoading = useAppSelector(
ApplicationSelectors.selectIsApplicationLoading,
);
const areFilesLoading = useAppSelector(FilesSelectors.selectAreFilesLoading);
const files = useAppSelector(FilesSelectors.selectFiles);

const quickAppDocumentUrl = getQuickAppDocumentUrl(applicationDetails);
const quickAppDocument = useMemo(
() => files.find((file) => file.id === quickAppDocumentUrl),
[files, quickAppDocumentUrl],
);

useEffect(() => {
if (quickAppDocumentUrl) {
const { apiKey, bucket, parentPath } = splitEntityId(quickAppDocumentUrl);
dispatch(
FilesActions.getFiles({
id: constructPath(apiKey, bucket, parentPath),
}),
);
}
}, [dispatch, quickAppDocumentUrl]);

return (
<>
<CollapsibleSection
togglerClassName="!text-sm !text-primary"
name={t('Applications')}
openByDefault
dataQa="applications-to-send-request"
className="!pl-0"
>
<ApplicationRow
onSelect={handleSelectItems}
itemComponentClassNames={classNames(
'cursor-pointer',
publishAction === PublishActions.DELETE && 'text-error',
)}
item={entity}
level={0}
isChosen={chosenItemsIds.some((id) => id === entity.id)}
/>
</CollapsibleSection>

{publishAction === PublishActions.ADD &&
'iconUrl' in entity &&
entity.iconUrl &&
isEntityIdExternal({ id: entity.iconUrl }) && (
<CollapsibleSection
togglerClassName="!text-sm !text-primary"
name={t('Files')}
openByDefault
dataQa="files-to-send-request"
className="!pl-0"
>
<ErrorMessage
type="warning"
error={t(
`The icon used for this application is in the "${isEntityIdPublic({ id: entity.iconUrl }) ? 'Organization' : 'Shared with me'}" section and cannot be published. Please replace the icon, otherwise the application will be published with the default one.`,
)}
/>
</CollapsibleSection>
)}

{(isApplicationLoading || areFilesLoading) && (
<div className="pl-3">
<Spinner size={20} dataQa="publication-items-spinner" />
</div>
)}

{!isApplicationLoading && quickAppDocument && (
<CollapsibleSection
name={t('Files')}
openByDefault
dataQa="files-to-send-request"
>
<div className="flex items-center gap-2">
<FilesRow
itemComponentClassNames={classNames(
'w-full cursor-pointer truncate',
publishAction === PublishActions.DELETE && 'text-error',
)}
item={quickAppDocument}
level={0}
onSelect={handleSelectItems}
isChosen={chosenItemsIds.some((id) => id === quickAppDocument.id)}
/>
<a
download={quickAppDocument.name}
href={constructPath('api', quickAppDocument.id)}
data-qa="download"
>
<IconDownload
className="shrink-0 text-secondary hover:text-accent-primary"
size={18}
/>
</a>
</div>
</CollapsibleSection>
)}
</>
);
};
56 changes: 8 additions & 48 deletions apps/chat/src/components/Chat/Publish/PublicationItemsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,8 @@ import { useTranslation } from '@/src/hooks/useTranslation';
import { findLatestVersion, isVersionValid } from '@/src/utils/app/common';
import { constructPath } from '@/src/utils/app/file';
import { splitEntityId } from '@/src/utils/app/folders';
import {
getIdWithoutRootPathSegments,
getRootId,
isEntityIdExternal,
} from '@/src/utils/app/id';
import { getIdWithoutRootPathSegments, getRootId } from '@/src/utils/app/id';
import { EnumMapper } from '@/src/utils/app/mappers';
import { isEntityIdPublic } from '@/src/utils/app/publications';

import { Conversation } from '@/src/types/chat';
import { FeatureType } from '@/src/types/common';
Expand All @@ -46,15 +41,14 @@ import {
PUBLIC_URL_PREFIX,
} from '@/src/constants/public';

import { ApplicationPublishItems } from '@/src/components/Chat/Publish/ApplicationPublishItems';
import CollapsibleSection from '@/src/components/Common/CollapsibleSection';
import {
ApplicationRow,
ConversationRow,
FilesRow,
PromptsRow,
} from '@/src/components/Common/ReplaceConfirmationModal/Components';

import { ErrorMessage } from '../../Common/ErrorMessage';
import Tooltip from '../../Common/Tooltip';
import Folder from '../../Folder/Folder';
import { PublicVersionSelector } from './PublicVersionSelector';
Expand Down Expand Up @@ -546,46 +540,12 @@ export const PublicationItemsList = memo(
</CollapsibleSection>
)}
{type === SharingType.Application && (
<>
<CollapsibleSection
togglerClassName="!text-sm !text-primary"
name={t('Applications')}
openByDefault
dataQa="applications-to-send-request"
className="!pl-0"
>
<ApplicationRow
onSelect={handleSelectItems}
itemComponentClassNames={classNames(
'cursor-pointer',
publishAction === PublishActions.DELETE && 'text-error',
)}
item={entity}
level={0}
isChosen={chosenItemsIds.some((id) => id === entity.id)}
/>
</CollapsibleSection>

{publishAction === PublishActions.ADD &&
'iconUrl' in entity &&
entity.iconUrl &&
isEntityIdExternal({ id: entity.iconUrl }) && (
<CollapsibleSection
togglerClassName="!text-sm !text-primary"
name={t('Files')}
openByDefault
dataQa="files-to-send-request"
className="!pl-0"
>
<ErrorMessage
type="warning"
error={t(
`The icon used for this application is in the "${isEntityIdPublic({ id: entity.iconUrl }) ? 'Organization' : 'Shared with me'}" section and cannot be published. Please replace the icon, otherwise the application will be published with the default one.`,
)}
/>
</CollapsibleSection>
)}
</>
<ApplicationPublishItems
entity={entity as PublishRequestDialAIEntityModel}
handleSelectItems={handleSelectItems}
publishAction={publishAction}
chosenItemsIds={chosenItemsIds}
/>
)}
</div>
);
Expand Down
84 changes: 53 additions & 31 deletions apps/chat/src/components/Chat/Publish/PublishWizard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@ import { getFolderIdFromEntityId } from '@/src/utils/app/folders';
import {
getIdWithoutRootPathSegments,
getRootId,
isEntityIdExternal,
isApplicationId,
} from '@/src/utils/app/id';
import { EnumMapper } from '@/src/utils/app/mappers';
import {
createTargetUrl,
getApplicationPublishResources,
isEntityIdPublic,
} from '@/src/utils/app/publications';
import { NotReplayFilter } from '@/src/utils/app/search';
Expand All @@ -41,6 +42,10 @@ import {
import { SharingType } from '@/src/types/share';
import { Translation } from '@/src/types/translation';

import {
ApplicationActions,
ApplicationSelectors,
} from '@/src/store/application/application.reducers';
import { ConversationsSelectors } from '@/src/store/conversations/conversations.reducers';
import { useAppDispatch, useAppSelector } from '@/src/store/hooks';
import {
Expand Down Expand Up @@ -114,6 +119,9 @@ export function PublishModal<
const areConversationsWithContentUploading = useAppSelector(
ConversationsSelectors.selectAreConversationsWithContentUploading,
);
const isApplicationLoading = useAppSelector(
ApplicationSelectors.selectIsApplicationLoading,
);
const isRulesLoading = useAppSelector(
PublicationSelectors.selectIsRulesLoading,
);
Expand All @@ -129,6 +137,11 @@ export function PublishModal<
const selectedItemsIds = useAppSelector(
PublicationSelectors.selectSelectedItemsToPublish,
);
const applicationDetails = useAppSelector(
ApplicationSelectors.selectApplicationDetail,
);

const applicationId = isApplicationId(entity?.id) ? entity.id : null;

const filteredFiles = useMemo(() => {
if (publishAction === PublishActions.DELETE) {
Expand Down Expand Up @@ -168,6 +181,12 @@ export function PublishModal<
}
}, [dispatch, path]);

useEffect(() => {
if (applicationId && isOpen) {
dispatch(ApplicationActions.get({ applicationId }));
}
}, [applicationId, dispatch, isOpen]);

useEffect(() => {
if (currentFolderRules) {
setOtherTargetAudienceFilters(
Expand Down Expand Up @@ -312,6 +331,7 @@ export function PublishModal<
: selectedFiles.reduce<PublicationRequestModel['resources']>(
(acc, file) => {
const decodedFileId = ApiUtils.decodeApiUrl(file.id);

const item = mappedFiles.find(
(f) => f.oldUrl === decodedFileId,
);
Expand All @@ -322,34 +342,34 @@ export function PublishModal<
sourceUrl: decodedFileId,
targetUrl: item.newUrl,
});
} else {
acc.push({
action: publishAction,
sourceUrl: decodedFileId,
targetUrl: ApiUtils.decodeApiUrl(
constructPath(
file.id.split('/')[0],
PUBLIC_URL_PREFIX,
trimmedPath,
getIdWithoutRootPathSegments(entity.folderId),
file.id.split('/').at(-1),
),
),
});
}

return acc;
},
[],
)),
...(type === SharingType.Application &&
'iconUrl' in entity &&
entity.iconUrl &&
!isEntityIdExternal({ id: entity.iconUrl })
? [
{
action: publishAction,
targetUrl: ApiUtils.decodeApiUrl(
constructPath(
entity.iconUrl.split('/')[0],
PUBLIC_URL_PREFIX,
trimmedPath,
getIdWithoutRootPathSegments(entity.folderId),
entity.iconUrl.split('/').at(-1),
),
),
sourceUrl:
publishAction === PublishActions.DELETE
? undefined
: ApiUtils.decodeApiUrl(entity.iconUrl),
},
]
...(type === SharingType.Application
? getApplicationPublishResources({
entity: entity as PublishRequestDialAIEntityModel,
path: trimmedPath,
publishAction,
applicationDetails,
selectedIds: selectedItemsIds,
})
: []),
],
rules: preparedFilters.map((filter) => ({
Expand All @@ -363,18 +383,19 @@ export function PublishModal<
onClose();
},
[
entity,
path,
publishRequestName,
otherTargetAudienceFilters,
currentFolderRules,
dispatch,
entitiesArray,
entity,
filteredFiles,
onClose,
otherTargetAudienceFilters,
path,
type,
dispatch,
publishAction,
publishRequestName,
applicationDetails,
selectedItemsIds,
type,
onClose,
],
);

Expand Down Expand Up @@ -417,7 +438,8 @@ export function PublishModal<
isRuleSetterOpened ||
isNothingSelectedAndNoRuleChanges ||
isSomeVersionInvalid ||
areConversationsWithContentUploading;
areConversationsWithContentUploading ||
isApplicationLoading;
const isSendBtnTooltipHidden =
!!publishRequestName.trim().length &&
!isRuleSetterOpened &&
Expand Down
Loading

0 comments on commit 076c7b8

Please sign in to comment.