Skip to content

Commit c26b016

Browse files
committed
fix(FR-2813): render folder-create notification with VFolder node card
1 parent 7a4501f commit c26b016

5 files changed

Lines changed: 69 additions & 51 deletions

File tree

react/src/components/BAINodeNotificationItem.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
import { BAINodeNotificationItemFragment$key } from '../__generated__/BAINodeNotificationItemFragment.graphql';
66
import { NotificationState } from '../hooks/useBAINotification';
77
import BAIComputeSessionNodeNotificationItem from './BAIComputeSessionNodeNotificationItem';
8-
import BAIVFolderNotificationItem from './BAIVFolderNotificationItem';
98
import BAIVirtualFolderNodeNotificationItem from './BAIVirtualFolderNodeNotificationItem';
9+
import BAIVirtualFolderNodeNotificationItemV2 from './BAIVirtualFolderNodeNotificationItemV2';
1010
import React from 'react';
1111
import { graphql, useRefetchableFragment } from 'react-relay';
1212

@@ -28,7 +28,8 @@ const nodeFragmentOperation = graphql`
2828
}
2929
... on VFolder {
3030
__typename
31-
...BAIVFolderNotificationItemFragment @alias(as: "vfolderFrgmt")
31+
...BAIVirtualFolderNodeNotificationItemV2Fragment
32+
@alias(as: "vfolderFrgmt")
3233
}
3334
... on VirtualFolderNode {
3435
__typename
@@ -57,7 +58,7 @@ const BAINodeNotificationItem: React.FC<{
5758
);
5859
} else if (node?.__typename === 'VFolder') {
5960
return (
60-
<BAIVFolderNotificationItem
61+
<BAIVirtualFolderNodeNotificationItemV2
6162
notification={notification}
6263
vfolderFrgmt={node.vfolderFrgmt || null}
6364
showDate={showDate}

react/src/components/BAIVirtualFolderNodeNotificationItem.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
Copyright (c) 2015-2026 Lablup Inc. All rights reserved.
44
*/
55
import { BAIVirtualFolderNodeNotificationItemFragment$key } from '../__generated__/BAIVirtualFolderNodeNotificationItemFragment.graphql';
6-
import { useWebUINavigate } from '../hooks';
76
import {
87
NotificationState,
98
useSetBAINotification,
109
} from '../hooks/useBAINotification';
1110
import BAINotificationBackgroundProgress from './BAINotificationBackgroundProgress';
11+
import { useFolderExplorerOpener } from './FolderExplorerOpener';
1212
import { useToggle } from 'ahooks';
1313
import { Card, List, theme, Typography } from 'antd';
1414
import { BAIFlex, BAILink, BAINotificationItem, BAIText } from 'backend.ai-ui';
@@ -25,7 +25,7 @@ interface BAIVirtualFolderNodeNotificationItemProps {
2525

2626
/**
2727
* @deprecated Renders V1 `VirtualFolderNode` notifications. The V2 counterpart
28-
* `BAIVFolderNotificationItem` (operating on `VFolder implements Node` from
28+
* `BAIVirtualFolderNodeNotificationItemV2` (operating on `VFolder implements Node` from
2929
* the Strawberry GraphQL API, FR-2573) is the preferred path going forward.
3030
* This component will be removed once all V1 callers migrate.
3131
*/
@@ -34,7 +34,7 @@ const BAIVirtualFolderNodeNotificationItem: React.FC<
3434
> = ({ notification, virtualFolderNodeFrgmt, showDate }) => {
3535
'use memo';
3636

37-
const navigate = useWebUINavigate();
37+
const { open: openFolderExplorer } = useFolderExplorerOpener();
3838
const { t } = useTranslation();
3939
const { token } = theme.useToken();
4040
const { closeNotification } = useSetBAINotification();
@@ -65,9 +65,9 @@ const BAIVirtualFolderNodeNotificationItem: React.FC<
6565
}}
6666
title={node.name || ''}
6767
onClick={() => {
68-
navigate(
69-
`/data${node.row_id ? `?${new URLSearchParams({ folder: node.row_id }).toString()}` : ''}`,
70-
);
68+
if (node.row_id) {
69+
openFolderExplorer(node.row_id);
70+
}
7171
closeNotification(notification.key);
7272
}}
7373
>

react/src/components/BAIVFolderNotificationItem.tsx renamed to react/src/components/BAIVirtualFolderNodeNotificationItemV2.tsx

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22
@license
33
Copyright (c) 2015-2026 Lablup Inc. All rights reserved.
44
*/
5-
import { BAIVFolderNotificationItemFragment$key } from '../__generated__/BAIVFolderNotificationItemFragment.graphql';
6-
import { useWebUINavigate } from '../hooks';
5+
import { BAIVirtualFolderNodeNotificationItemV2Fragment$key } from '../__generated__/BAIVirtualFolderNodeNotificationItemV2Fragment.graphql';
76
import {
87
NotificationState,
98
useSetBAINotification,
109
} from '../hooks/useBAINotification';
1110
import BAINotificationBackgroundProgress from './BAINotificationBackgroundProgress';
11+
import { useFolderExplorerOpener } from './FolderExplorerOpener';
1212
import { useToggle } from 'ahooks';
1313
import { Card, List, theme, Typography } from 'antd';
1414
import {
@@ -23,9 +23,9 @@ import * as _ from 'lodash-es';
2323
import { useTranslation } from 'react-i18next';
2424
import { graphql, useFragment } from 'react-relay';
2525

26-
interface BAIVFolderNotificationItemProps {
26+
interface BAIVirtualFolderNodeNotificationItemV2Props {
2727
notification: NotificationState;
28-
vfolderFrgmt: BAIVFolderNotificationItemFragment$key | null;
28+
vfolderFrgmt: BAIVirtualFolderNodeNotificationItemV2Fragment$key | null;
2929
showDate?: boolean;
3030
}
3131

@@ -34,14 +34,12 @@ interface BAIVFolderNotificationItemProps {
3434
// list/mutation flows can pass `node: vfolder` to `upsertNotification` and
3535
// get the same rich folder-link + extra-description rendering as the legacy
3636
// V1 path. The V1 component stays in place until all callers migrate.
37-
const BAIVFolderNotificationItem: React.FC<BAIVFolderNotificationItemProps> = ({
38-
notification,
39-
vfolderFrgmt,
40-
showDate,
41-
}) => {
37+
const BAIVirtualFolderNodeNotificationItemV2: React.FC<
38+
BAIVirtualFolderNodeNotificationItemV2Props
39+
> = ({ notification, vfolderFrgmt, showDate }) => {
4240
'use memo';
4341

44-
const navigate = useWebUINavigate();
42+
const { open: openFolderExplorer } = useFolderExplorerOpener();
4543
const { t } = useTranslation();
4644
const { token } = theme.useToken();
4745
const { closeNotification } = useSetBAINotification();
@@ -50,7 +48,7 @@ const BAIVFolderNotificationItem: React.FC<BAIVFolderNotificationItemProps> = ({
5048

5149
const node = useFragment(
5250
graphql`
53-
fragment BAIVFolderNotificationItemFragment on VFolder {
51+
fragment BAIVirtualFolderNodeNotificationItemV2Fragment on VFolder {
5452
id
5553
metadata {
5654
name
@@ -76,9 +74,9 @@ const BAIVFolderNotificationItem: React.FC<BAIVFolderNotificationItemProps> = ({
7674
}}
7775
title={folderName || ''}
7876
onClick={() => {
79-
navigate(
80-
`/data${localId ? `?${new URLSearchParams({ folder: localId }).toString()}` : ''}`,
81-
);
77+
if (localId) {
78+
openFolderExplorer(localId);
79+
}
8280
closeNotification(notification.key);
8381
}}
8482
>
@@ -148,4 +146,4 @@ const BAIVFolderNotificationItem: React.FC<BAIVFolderNotificationItemProps> = ({
148146
);
149147
};
150148

151-
export default BAIVFolderNotificationItem;
149+
export default BAIVirtualFolderNodeNotificationItemV2;

react/src/components/FolderCreateModalV2.tsx

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ const FolderCreateModalV2: React.FC<FolderCreateModalProps> = ({
197197
createVfolderV2(input: $input) {
198198
vfolder {
199199
id
200-
status
200+
vfolderStatus: status
201201
host
202202
metadata {
203203
name
@@ -214,6 +214,7 @@ const FolderCreateModalV2: React.FC<FolderCreateModalProps> = ({
214214
projectId
215215
creatorEmail
216216
}
217+
...BAINodeNotificationItemFragment @alias(as: "notificationFrgmt")
217218
}
218219
}
219220
}
@@ -232,7 +233,7 @@ const FolderCreateModalV2: React.FC<FolderCreateModalProps> = ({
232233
createVFolderInProject(projectId: $projectId, input: $input) {
233234
vfolder {
234235
id
235-
status
236+
vfolderStatus: status
236237
host
237238
metadata {
238239
name
@@ -249,6 +250,7 @@ const FolderCreateModalV2: React.FC<FolderCreateModalProps> = ({
249250
projectId
250251
creatorEmail
251252
}
253+
...BAINodeNotificationItemFragment @alias(as: "notificationFrgmt")
252254
}
253255
}
254256
}
@@ -323,19 +325,14 @@ const FolderCreateModalV2: React.FC<FolderCreateModalProps> = ({
323325
user: vfolder.ownership.userId ?? '',
324326
group: vfolder.ownership.projectId ?? null,
325327
cloneable: vfolder.metadata.cloneable,
326-
status: vfolder.status ?? '',
328+
status: vfolder.vfolderStatus ?? '',
327329
};
328330

329331
upsertNotification({
330332
key: `folder-create-success-${result.id}`,
331333
icon: 'folder',
332-
message: `${result.name}: ${t('data.folders.FolderCreated')}`,
333-
toText: t('data.folders.OpenAFolder'),
334-
to: {
335-
search: new URLSearchParams({
336-
folder: result.id,
337-
}).toString(),
338-
},
334+
node: vfolder.notificationFrgmt ?? null,
335+
description: t('data.folders.FolderCreated'),
339336
open: true,
340337
});
341338
document.dispatchEvent(new CustomEvent('backend-ai-folder-list-changed'));

react/src/components/ImportRepoForm.tsx

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
@license
33
Copyright (c) 2015-2026 Lablup Inc. All rights reserved.
44
*/
5+
import { ImportRepoFormCreateVFolderMutation } from '../__generated__/ImportRepoFormCreateVFolderMutation.graphql';
56
import { useSuspendedBackendaiClient } from '../hooks';
67
import { useSetBAINotification } from '../hooks/useBAINotification';
78
import {
@@ -20,13 +21,27 @@ import {
2021
} from 'antd';
2122
import {
2223
BAIButton,
24+
toLocalId,
2325
useBAILogger,
2426
useErrorMessageResolver,
2527
useGetAvailableFolderName,
28+
useMutationWithPromise,
2629
} from 'backend.ai-ui';
2730
import { FolderInput } from 'lucide-react';
2831
import { useRef } from 'react';
2932
import { useTranslation } from 'react-i18next';
33+
import { graphql } from 'react-relay';
34+
35+
const IMPORT_REPO_FORM_CREATE_VFOLDER_MUTATION = graphql`
36+
mutation ImportRepoFormCreateVFolderMutation($input: CreateVFolderV2Input!) {
37+
createVfolderV2(input: $input) {
38+
vfolder {
39+
id
40+
...BAINodeNotificationItemFragment @alias(as: "notificationFrgmt")
41+
}
42+
}
43+
}
44+
`;
3045

3146
type URLType = 'github' | 'gitlab';
3247

@@ -104,6 +119,11 @@ const ImportRepoForm: React.FC<ImportFromURLFormProps> = ({
104119
const { startSessionWithDefault, upsertSessionNotification } =
105120
useStartSession();
106121

122+
const commitCreateMutation =
123+
useMutationWithPromise<ImportRepoFormCreateVFolderMutation>(
124+
IMPORT_REPO_FORM_CREATE_VFOLDER_MUTATION,
125+
);
126+
107127
const prepareGitHubArchive = async (inputUrl: string) => {
108128
const sanitizedUrl = inputUrl.trim().replace(/\.git$/, '');
109129
let parsedUrl: URL;
@@ -217,25 +237,27 @@ const ImportRepoForm: React.FC<ImportFromURLFormProps> = ({
217237
repoInfo.repoName || 'imported-from-repo',
218238
);
219239

220-
// create virtual folder
221-
const vfolderInfo = await baiClient.vfolder.create(
222-
folderName,
223-
values.storageHost,
224-
'', // group
225-
values.vfolder_usage_mode ?? 'general', // usage mode
226-
'rw', // permission
227-
);
240+
// Create the virtual folder via the V2 mutation; its payload already
241+
// includes the rich folder-card fragment, so the notification can be
242+
// driven directly without a separate `vfolder_node` lookup.
243+
const { createVfolderV2 } = await commitCreateMutation({
244+
input: {
245+
name: folderName,
246+
host: values.storageHost,
247+
cloneable: false,
248+
usageMode: values.vfolder_usage_mode ?? 'general',
249+
permission: 'rw',
250+
projectId: null,
251+
},
252+
});
253+
const vfolder = createVfolderV2.vfolder;
254+
const vfolderLocalId = toLocalId(vfolder.id);
228255

229256
upsertNotification({
230-
key: `folder-create-success-${vfolderInfo.id}`,
257+
key: `folder-create-success-${vfolderLocalId}`,
231258
icon: 'folder',
232-
message: `${vfolderInfo.name}: ${t('data.folders.FolderCreated')}`,
233-
toText: t('data.folders.OpenAFolder'),
234-
to: {
235-
search: new URLSearchParams({
236-
folder: vfolderInfo.id,
237-
}).toString(),
238-
},
259+
node: vfolder.notificationFrgmt ?? null,
260+
description: t('data.folders.FolderCreated'),
239261
open: true,
240262
duration: 0,
241263
});
@@ -254,7 +276,7 @@ const ImportRepoForm: React.FC<ImportFromURLFormProps> = ({
254276
),
255277
enabled: true,
256278
},
257-
mount_ids: [vfolderInfo.id],
279+
mount_ids: [vfolderLocalId],
258280
};
259281

260282
const results = await startSessionWithDefault(launcherValue);

0 commit comments

Comments
 (0)