Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions react/src/components/BAIGeneralNotificationItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,16 +70,19 @@ const BAIGeneralNotificationItem: React.FC<{
</Typography.Paragraph>
</BAIFlex>
<BAIFlex direction="row" align="end" gap={'xxs'} justify="between">
<Typography.Paragraph>
<Typography.Paragraph
style={{ flex: 1, minWidth: 0, marginBottom: 0 }}
>
{_.isString(notification.description)
? _.truncate(notification.description, {
length: 300,
})
: notification.description}
</Typography.Paragraph>
{notification.to ? (
<BAIFlex>
<BAIFlex style={{ flexShrink: 0 }}>
<Typography.Link
style={{ whiteSpace: 'nowrap' }}
onClick={(e) => {
onClickAction && onClickAction(e, notification);
}}
Expand All @@ -91,15 +94,16 @@ const BAIGeneralNotificationItem: React.FC<{
</BAIFlex>
) : null}
{notification?.onCancel ? (
<BAIFlex>
<BAIFlex style={{ flexShrink: 0 }}>
<Button type="link" onClick={notification.onCancel}>
{t('button.Cancel')}
</Button>
</BAIFlex>
) : null}
{notification.extraDescription && !notification?.onCancel ? (
<BAIFlex>
<BAIFlex style={{ flexShrink: 0 }}>
<Typography.Link
style={{ whiteSpace: 'nowrap' }}
onClick={() => {
// onClickAction && onClickAction(e, notification);
setShowExtraDescription(!showExtraDescription);
Expand Down
21 changes: 21 additions & 0 deletions react/src/components/BAINodeNotificationItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,17 @@
*/
import { NotificationState } from '../hooks/useBAINotification';
import BAIComputeSessionNodeNotificationItem from './BAIComputeSessionNodeNotificationItem';
import BAIVFolderNotificationItem from './BAIVFolderNotificationItem';
import BAIVirtualFolderNodeNotificationItem from './BAIVirtualFolderNodeNotificationItem';
import React from 'react';
import { graphql, useRefetchableFragment } from 'react-relay';
import { BAINodeNotificationItemFragment$key } from 'src/__generated__/BAINodeNotificationItemFragment.graphql';

// `... on VFolder` is the V2 (Strawberry GraphQL, FR-2573) branch and the
// preferred path for new VFolder list/mutation flows.
// `... on VirtualFolderNode` is the legacy V1 branch and is **deprecated** —
// kept here only so callers that still hold V1 fragments keep rendering. It
// will be removed once all VFolder callers migrate to V2 `VFolder`.
const nodeFragmentOperation = graphql`
fragment BAINodeNotificationItemFragment on Node
@refetchable(queryName: "BAINodeNotificationItemRefetchQuery") {
Expand All @@ -20,6 +26,10 @@ const nodeFragmentOperation = graphql`
...BAIComputeSessionNodeNotificationItemFragment
@alias(as: "sessionFrgmt")
}
... on VFolder {
__typename
...BAIVFolderNotificationItemFragment @alias(as: "vfolderFrgmt")
}
... on VirtualFolderNode {
__typename
status
Expand All @@ -45,7 +55,18 @@ const BAINodeNotificationItem: React.FC<{
primaryAppOption={notification.extraData}
/>
);
} else if (node?.__typename === 'VFolder') {
return (
<BAIVFolderNotificationItem
notification={notification}
vfolderFrgmt={node.vfolderFrgmt || null}
showDate={showDate}
/>
);
} else if (node?.__typename === 'VirtualFolderNode') {
// @deprecated Renders the legacy V1 VFolder notification. Will be removed
// once all V1 callers are gone — see the matching note on the V2 branch
// above.
return (
<BAIVirtualFolderNodeNotificationItem
notification={notification}
Expand Down
151 changes: 151 additions & 0 deletions react/src/components/BAIVFolderNotificationItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
/**
@license
Copyright (c) 2015-2026 Lablup Inc. All rights reserved.
*/
import BAINotificationBackgroundProgress from './BAINotificationBackgroundProgress';
import { useToggle } from 'ahooks';
import { Card, List, theme, Typography } from 'antd';
import {
BAIFlex,
BAILink,
BAINotificationItem,
BAIText,
toLocalId,
} from 'backend.ai-ui';
import dayjs from 'dayjs';
import * as _ from 'lodash-es';
import { useTranslation } from 'react-i18next';
import { graphql, useFragment } from 'react-relay';
import { useNavigate } from 'react-router-dom';

Check failure on line 19 in react/src/components/BAIVFolderNotificationItem.tsx

View workflow job for this annotation

GitHub Actions / react-coverage

'useNavigate' import from 'react-router-dom' is restricted. Use 'useWebUINavigate' from 'src/hooks' or '<WebUINavigate>' from 'src/components/WebUINavigate' instead
import { BAIVFolderNotificationItemFragment$key } from 'src/__generated__/BAIVFolderNotificationItemFragment.graphql';
import {
NotificationState,
useSetBAINotification,
} from 'src/hooks/useBAINotification';

interface BAIVFolderNotificationItemProps {
notification: NotificationState;
vfolderFrgmt: BAIVFolderNotificationItemFragment$key | null;
showDate?: boolean;
}

// V2 counterpart of `BAIVirtualFolderNodeNotificationItem`. Operates on the
// Strawberry V2 `VFolder` type (`VFolder implements Node`, FR-2573) so V2
// list/mutation flows can pass `node: vfolder` to `upsertNotification` and
// get the same rich folder-link + extra-description rendering as the legacy
// V1 path. The V1 component stays in place until all callers migrate.
const BAIVFolderNotificationItem: React.FC<BAIVFolderNotificationItemProps> = ({
notification,
vfolderFrgmt,
showDate,
}) => {
'use memo';

const navigate = useNavigate();
const { t } = useTranslation();
const { token } = theme.useToken();
const { closeNotification } = useSetBAINotification();
const [showExtraDescription, { toggle: toggleShowExtraDescription }] =
useToggle(false);

const node = useFragment(
graphql`
fragment BAIVFolderNotificationItemFragment on VFolder {
id
metadata {
name
}
}
`,
vfolderFrgmt,
);

if (!node) return null;

const localId = toLocalId(node.id);
const folderName = node.metadata?.name;

return (
<BAINotificationItem
title={
<BAIText ellipsis>
{t('general.Folder')}:&nbsp;
<BAILink
style={{
fontWeight: 'normal',
}}
title={folderName || ''}
onClick={() => {
navigate(
`/data${localId ? `?${new URLSearchParams({ folder: localId }).toString()}` : ''}`,
);
closeNotification(notification.key);
}}
>
{folderName}
</BAILink>
</BAIText>
}
description={
<List.Item>
<BAIFlex direction="column" align="stretch" gap={'xxs'}>
<BAIFlex direction="row" align="end" gap={'xxs'} justify="between">
{_.isString(notification.description) ? (
<BAIText style={{ flex: 1, minWidth: 0 }}>
{_.truncate(notification.description, { length: 300 })}
</BAIText>
) : (
notification.description
)}

{notification.extraDescription && !notification?.onCancel ? (
<BAIFlex style={{ flexShrink: 0 }}>
<Typography.Link
style={{ whiteSpace: 'nowrap' }}
onClick={() => {
toggleShowExtraDescription();
}}
>
{showExtraDescription
? t('notification.SeeSummary')
: t('notification.SeeDetail')}
</Typography.Link>
</BAIFlex>
) : null}
</BAIFlex>

{notification.extraDescription && showExtraDescription ? (
<Card
size="small"
style={{
maxHeight: '300px',
overflow: 'auto',
overflowX: 'hidden',
marginTop: token.marginSM,
}}
>
{_.isString(notification.extraDescription) ? (
<Typography.Text type="secondary" copyable>
{notification.extraDescription}
</Typography.Text>
) : (
notification.extraDescription
)}
</Card>
) : null}

{notification.backgroundTask && (
<BAINotificationBackgroundProgress
backgroundTask={notification.backgroundTask}
showDate={showDate}
/>
)}
</BAIFlex>
</List.Item>
}
footer={showDate ? dayjs(notification.created).format('lll') : undefined}
/>
);
};

export default BAIVFolderNotificationItem;
11 changes: 9 additions & 2 deletions react/src/components/BAIVirtualFolderNodeNotificationItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ interface BAIVirtualFolderNodeNotificationItemProps {
showDate?: boolean;
}

/**
* @deprecated Renders V1 `VirtualFolderNode` notifications. The V2 counterpart
* `BAIVFolderNotificationItem` (operating on `VFolder implements Node` from
* the Strawberry GraphQL API, FR-2573) is the preferred path going forward.
* This component will be removed once all V1 callers migrate.
*/
const BAIVirtualFolderNodeNotificationItem: React.FC<
BAIVirtualFolderNodeNotificationItemProps
> = ({ notification, virtualFolderNodeFrgmt, showDate }) => {
Expand Down Expand Up @@ -79,16 +85,17 @@ const BAIVirtualFolderNodeNotificationItem: React.FC<
justify="between"
>
{_.isString(notification.description) ? (
<BAIText>
<BAIText style={{ flex: 1, minWidth: 0 }}>
{_.truncate(notification.description, { length: 300 })}
</BAIText>
) : (
notification.description
)}

{notification.extraDescription && !notification?.onCancel ? (
<BAIFlex>
<BAIFlex style={{ flexShrink: 0 }}>
<Typography.Link
style={{ whiteSpace: 'nowrap' }}
onClick={() => {
toggleShowExtraDescription();
}}
Expand Down
Loading
Loading