Skip to content

Commit

Permalink
feat(chat): add marketplace my applications tab (Issue #2038) (#2138)
Browse files Browse the repository at this point in the history
Co-authored-by: Magomed-Elbi Dzhukalaev <magomed-elbi_dzhukalaev@epam.com>
Co-authored-by: Alexander <98586297+Alexander-Kezik@users.noreply.github.com>
  • Loading branch information
3 people authored Sep 18, 2024
1 parent 9145ec3 commit 904193e
Show file tree
Hide file tree
Showing 17 changed files with 655 additions and 220 deletions.
20 changes: 10 additions & 10 deletions apps/chat/src/components/Chatbar/Chatbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,16 @@ const ChatActionsBlock = () => {

return (
<>
<div className="flex px-2 py-1">
<button
className="flex shrink-0 grow cursor-pointer select-none items-center gap-3 rounded px-3 py-2 transition-colors duration-200 hover:bg-accent-primary-alpha disabled:cursor-not-allowed hover:disabled:bg-transparent"
onClick={() => router.push('/marketplace')}
data-qa="link-to-marketplace"
>
<IconApps className="text-secondary" width={18} height={18} />
{t('DIAL Marketplace')}
</button>
</div>
<div className="flex px-2 py-1">
<button
className="flex shrink-0 grow cursor-pointer select-none items-center gap-3 rounded px-3 py-2 transition-colors duration-200 hover:bg-accent-primary-alpha disabled:cursor-not-allowed hover:disabled:bg-transparent"
Expand All @@ -75,16 +85,6 @@ const ChatActionsBlock = () => {
{t('New conversation')}
</button>
</div>
<div className="flex px-2 py-1">
<button
className="flex shrink-0 grow cursor-pointer select-none items-center gap-3 rounded px-3 py-2 transition-colors duration-200 hover:bg-accent-primary-alpha disabled:cursor-not-allowed hover:disabled:bg-transparent"
onClick={() => router.push('/marketplace')}
data-qa="link-to-marketplace"
>
<IconApps className="text-secondary" width={18} height={18} />
{t('DIAL Marketplace')}
</button>
</div>
</>
);
};
Expand Down
10 changes: 8 additions & 2 deletions apps/chat/src/components/Common/FolderContextMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import {
isEntityNameInvalid,
} from '@/src/utils/app/common';
import { getRootId } from '@/src/utils/app/id';
import { isItemPublic } from '@/src/utils/app/publications';
import { isEntityOrParentsExternal } from '@/src/utils/app/share';

import { FeatureType } from '@/src/types/common';
Expand All @@ -30,6 +29,8 @@ import { Translation } from '@/src/types/translation';
import { useAppSelector } from '@/src/store/hooks';
import { SettingsSelectors } from '@/src/store/settings/settings.reducers';

import { PUBLIC_URL_PREFIX } from '@/src/constants/public';

import ContextMenu from './ContextMenu';

import UnpublishIcon from '@/public/images/icons/unpublish.svg';
Expand Down Expand Up @@ -159,7 +160,12 @@ export const FolderContextMenu = ({
dataQa: 'unpublish',
display:
isPublishingEnabled &&
isItemPublic(folder.id) &&
folder.id.startsWith(
getRootId({
featureType,
bucket: PUBLIC_URL_PREFIX,
}),
) &&
!!onUnpublish &&
isSidePanelFolder,
Icon: UnpublishIcon,
Expand Down
12 changes: 10 additions & 2 deletions apps/chat/src/components/Common/ItemContextMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import {
isEntityNameInvalid,
} from '@/src/utils/app/common';
import { getRootId } from '@/src/utils/app/id';
import { isItemPublic } from '@/src/utils/app/publications';
import { isEntityOrParentsExternal } from '@/src/utils/app/share';

import { FeatureType, ShareEntity } from '@/src/types/common';
Expand All @@ -37,6 +36,8 @@ import { Translation } from '@/src/types/translation';
import { useAppSelector } from '@/src/store/hooks';
import { SettingsSelectors } from '@/src/store/settings/settings.reducers';

import { PUBLIC_URL_PREFIX } from '@/src/constants/public';

import ContextMenu from './ContextMenu';

import UnpublishIcon from '@/public/images/icons/unpublish.svg';
Expand Down Expand Up @@ -293,7 +294,14 @@ export default function ItemContextMenu({
name: t('Unpublish'),
dataQa: 'unpublish',
display:
isPublishingEnabled && !!onUnpublish && isItemPublic(entity.id),
isPublishingEnabled &&
!!onUnpublish &&
entity.id.startsWith(
getRootId({
featureType,
bucket: PUBLIC_URL_PREFIX,
}),
),
Icon: UnpublishIcon,
onClick: onUnpublish,
disabled: disableAll,
Expand Down
78 changes: 68 additions & 10 deletions apps/chat/src/components/Marketplace/ApplicationCard.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
IconDotsVertical,
IconPencilMinus,
IconTrashX,
IconWorldShare,
TablerIconsProps,
Expand All @@ -10,15 +11,21 @@ import { useTranslation } from 'next-i18next';

import classNames from 'classnames';

import { getRootId } from '@/src/utils/app/id';
import { isSmallScreen } from '@/src/utils/app/mobile';
import { isItemPublic } from '@/src/utils/app/publications';

import { FeatureType } from '@/src/types/common';
import { DisplayMenuItemProps } from '@/src/types/menu';
import { DialAIEntityModel } from '@/src/types/models';
import { PublishActions } from '@/src/types/publication';
import { Translation } from '@/src/types/translation';

import { useAppSelector } from '@/src/store/hooks';
import { MarketplaceSelectors } from '@/src/store/marketplace/marketplace.reducers';

import { MarketplaceTabs } from '@/src/constants/marketplace';
import { PUBLIC_URL_PREFIX } from '@/src/constants/public';

import { ModelIcon } from '@/src/components/Chatbar/ModelIcon';
import ContextMenu from '@/src/components/Common/ContextMenu';
import { EntityMarkdownDescription } from '@/src/components/Common/MarkdownDescription';
Expand Down Expand Up @@ -50,55 +57,106 @@ export const CardFooter = () => {
interface ApplicationCardProps {
entity: DialAIEntityModel;
onClick: (entity: DialAIEntityModel) => void;
onPublish: (entity: DialAIEntityModel, action: PublishActions) => void;
onPublish?: (entity: DialAIEntityModel, action: PublishActions) => void;
onDelete?: (entity: DialAIEntityModel) => void;
onEdit?: (entity: DialAIEntityModel) => void;
onRemove?: (entity: DialAIEntityModel) => void;
isMobile?: boolean;
selected?: boolean;
}

export const ApplicationCard = ({
entity,
onClick,
onDelete,
onEdit,
onRemove,
isMobile,
selected,
onPublish,
}: ApplicationCardProps) => {
const { t } = useTranslation(Translation.Marketplace);

const isPublishedEntity = isItemPublic(entity.id);
const selectedTab = useAppSelector(MarketplaceSelectors.selectSelectedTab);

const isPublishedEntity = entity.id.startsWith(
getRootId({
featureType: FeatureType.Application,
bucket: PUBLIC_URL_PREFIX,
}),
);
const isMyEntity = entity.id.startsWith(
getRootId({ featureType: FeatureType.Application }),
);

const menuItems: DisplayMenuItemProps[] = useMemo(
() => [
{
name: t('Edit'),
dataQa: 'edit',
display: isMyEntity && !!onEdit,
Icon: IconPencilMinus,
onClick: (e: React.MouseEvent) => {
e.stopPropagation();
onEdit?.(entity);
},
},
{
name: t('Publish'),
dataQa: 'publish',
display: !isPublishedEntity,
display: isMyEntity && !!onPublish,
Icon: IconWorldShare,
onClick: (e: React.MouseEvent) => {
e.stopPropagation();
onPublish(entity, PublishActions.ADD);
onPublish?.(entity, PublishActions.ADD);
},
},
{
name: t('Unpublish'),
dataQa: 'unpublish',
display: isPublishedEntity,
display: isPublishedEntity && !!onPublish,
Icon: UnpublishIcon,
onClick: (e: React.MouseEvent) => {
e.stopPropagation();
onPublish(entity, PublishActions.DELETE);
onPublish?.(entity, PublishActions.DELETE);
},
},
{
name: t('Delete'),
dataQa: 'delete',
display: !isPublishedEntity,
display: isMyEntity && !!onDelete,
Icon: (props: TablerIconsProps) => (
<IconTrashX {...props} className="stroke-error" />
),
onClick: (e: React.MouseEvent) => {
e.stopPropagation();
onDelete?.(entity);
},
},
{
name: t('Remove'),
dataQa: 'remove',
display: selectedTab === MarketplaceTabs.MY_APPLICATIONS && !!onRemove,
Icon: (props: TablerIconsProps) => (
<IconTrashX {...props} className="stroke-error" />
),
onClick: (e: React.MouseEvent) => e.stopPropagation(), // placeholder
onClick: (e: React.MouseEvent) => {
e.stopPropagation();
onRemove?.(entity);
},
},
],
[entity, isPublishedEntity, onPublish, t],
[
entity,
isPublishedEntity,
onPublish,
t,
selectedTab,
onDelete,
isMyEntity,
onEdit,
onRemove,
],
);

const iconSize =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,15 @@ interface Props {
entity: DialAIEntityModel;
onClose: () => void;
onPublish: (entity: DialAIEntityModel, action: PublishActions) => void;
onEdit: (entity: DialAIEntityModel) => void;
}

const ApplicationDetails = ({
entity,
isMobileView,
onClose,
onPublish,
onEdit,
}: Props) => {
const dispatch = useAppDispatch();

Expand Down Expand Up @@ -134,9 +136,7 @@ const ApplicationDetails = ({
modelType={EntityType.Model}
entity={selectedVersionEntity}
entities={filteredEntities}
onEdit={function (_: DialAIEntityModel): void {
throw new Error('Function not implemented.');
}}
onEdit={onEdit}
/>
</Modal>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ import { IconEdit, IconPlayerPlay, IconWorldShare } from '@tabler/icons-react';
import { useTranslation } from 'next-i18next';

import { getRootId, isApplicationId } from '@/src/utils/app/id';
import { isItemPublic } from '@/src/utils/app/publications';

import { FeatureType } from '@/src/types/common';
import { DialAIEntityModel } from '@/src/types/models';
import { PublishActions } from '@/src/types/publication';
import { Translation } from '@/src/types/translation';

import { PUBLIC_URL_PREFIX } from '@/src/constants/public';

import { ModelVersionSelect } from '../../Chat/ModelVersionSelect';
import Tooltip from '../../Common/Tooltip';

Expand All @@ -36,6 +37,12 @@ export const ApplicationDetailsFooter = ({
}: Props) => {
const { t } = useTranslation(Translation.Marketplace);

const isPublishedApplication = entity.id.startsWith(
getRootId({
featureType: FeatureType.Application,
bucket: PUBLIC_URL_PREFIX,
}),
);
const isMyApp = entity.id.startsWith(
getRootId({ featureType: FeatureType.Application }),
);
Expand All @@ -50,21 +57,21 @@ export const ApplicationDetailsFooter = ({
/> */}
{isApplicationId(entity.id) && (
<Tooltip
tooltip={isItemPublic(entity.id) ? t('Unpublish') : t('Publish')}
tooltip={isPublishedApplication ? t('Unpublish') : t('Publish')}
>
<button
onClick={() =>
onPublish(
entity,
isItemPublic(entity.id)
isPublishedApplication
? PublishActions.DELETE
: PublishActions.ADD,
)
}
className="group flex size-[34px] items-center justify-center rounded text-secondary hover:bg-accent-primary-alpha hover:text-accent-primary"
data-qa="application-publish"
>
{isItemPublic(entity.id) ? (
{isPublishedApplication ? (
<UnpublishIcon className="size-6 shrink-0 cursor-pointer text-secondary hover:text-accent-primary group-hover:text-accent-primary" />
) : (
<IconWorldShare
Expand Down
54 changes: 54 additions & 0 deletions apps/chat/src/components/Marketplace/CardsList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { useTranslation } from 'next-i18next';

import { DialAIEntityModel } from '@/src/types/models';
import { PublishActions } from '@/src/types/publication';
import { Translation } from '@/src/types/translation';

import { ApplicationCard } from '@/src/components/Marketplace/ApplicationCard';

interface CardsListProps {
entities: DialAIEntityModel[];
onCardClick: (entity: DialAIEntityModel) => void;
onPublish?: (entity: DialAIEntityModel, action: PublishActions) => void;
onDelete?: (entity: DialAIEntityModel) => void;
onEdit?: (entity: DialAIEntityModel) => void;
onRemove?: (entity: DialAIEntityModel) => void;
isMobile?: boolean;
title?: string;
className?: string;
}

export const CardsList = ({
entities,
onCardClick,
onPublish,
onDelete,
onEdit,
onRemove,
isMobile,
title,
className,
}: CardsListProps) => {
const { t } = useTranslation(Translation.Marketplace);

return (
<section className={className}>
{!!title && <h2 className="text-xl font-semibold">{t(title)}</h2>}

<div className="mt-4 grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 lg:gap-6 2xl:grid-cols-4">
{entities.map((entity) => (
<ApplicationCard
key={entity.id}
entity={entity}
onClick={onCardClick}
onPublish={onPublish}
onDelete={onDelete}
onEdit={onEdit}
onRemove={onRemove}
isMobile={isMobile}
/>
))}
</div>
</section>
);
};
Loading

0 comments on commit 904193e

Please sign in to comment.