22 @license
33 Copyright (c) 2015-2026 Lablup Inc. All rights reserved.
44 */
5- import { ModelCardDrawerFragment$key } from '../__generated__/ModelCardDrawerFragment .graphql' ;
5+ import { ModelStoreListPageV2DrawerQuery } from '../__generated__/ModelStoreListPageV2DrawerQuery .graphql' ;
66import {
77 ModelCardV2Filter ,
88 ModelStoreListPageV2Query ,
@@ -34,6 +34,7 @@ import {
3434 BAIGraphQLPropertyFilter ,
3535 BAISelect ,
3636 type GraphQLFilter ,
37+ safeDecodeUuid ,
3738 useUpdatableState ,
3839} from 'backend.ai-ui' ;
3940import dayjs from 'dayjs' ;
@@ -43,7 +44,7 @@ import {
4344 parseAsStringLiteral ,
4445 useQueryStates ,
4546} from 'nuqs' ;
46- import React , { useDeferredValue , useEffectEvent , useState } from 'react' ;
47+ import React , { useDeferredValue , useEffectEvent } from 'react' ;
4748import { useTranslation } from 'react-i18next' ;
4849import { graphql , useFragment , useLazyLoadQuery } from 'react-relay' ;
4950
@@ -204,9 +205,7 @@ const ModelCardV2Grid: React.FC<{
204205 pageSize : number ;
205206 offset : number ;
206207 onTotalChange : ( total : number ) => void ;
207- onCardClick ?: ( id : string , frgmt : ModelCardDrawerFragment$key ) => void ;
208- selectedModelCardId ?: string | null ;
209- onSelectedModelCardFound ?: ( frgmt : ModelCardDrawerFragment$key ) => void ;
208+ onCardClick ?: ( id : string ) => void ;
210209} > = ( {
211210 projectId,
212211 filter,
@@ -218,8 +217,6 @@ const ModelCardV2Grid: React.FC<{
218217 offset,
219218 onTotalChange,
220219 onCardClick,
221- selectedModelCardId,
222- onSelectedModelCardFound,
223220} ) => {
224221 'use memo' ;
225222
@@ -246,7 +243,6 @@ const ModelCardV2Grid: React.FC<{
246243 node {
247244 id
248245 ...ModelStoreListPageV2_ModelCardV2Fragment
249- ...ModelCardDrawerFragment
250246 }
251247 }
252248 }
@@ -276,23 +272,6 @@ const ModelCardV2Grid: React.FC<{
276272 onTotalChanged ( ) ;
277273 } , [ total ] ) ;
278274
279- // When items load and a selectedModelCardId is set (e.g. after refresh),
280- // find the matching fragment and report it to the parent.
281- const onResolveSelectedModelCard = useEffectEvent ( ( ) => {
282- if ( selectedModelCardId ) {
283- const match = items . find (
284- ( edge ) => edge ?. node ?. id === selectedModelCardId ,
285- ) ;
286- if ( match ?. node ) {
287- onSelectedModelCardFound ?.( match . node ) ;
288- }
289- }
290- } ) ;
291-
292- React . useEffect ( ( ) => {
293- onResolveSelectedModelCard ( ) ;
294- } , [ selectedModelCardId , result ] ) ;
295-
296275 if ( items . length === 0 ) {
297276 return (
298277 < Empty
@@ -312,7 +291,7 @@ const ModelCardV2Grid: React.FC<{
312291 < ModelCardV2Card
313292 modelCardV2Frgmt = { item }
314293 searchKeyword = { searchKeyword }
315- onClick = { ( ) => onCardClick ?.( item . id , item ) }
294+ onClick = { ( ) => onCardClick ?.( item . id ) }
316295 />
317296 </ Col >
318297 ) ;
@@ -343,9 +322,6 @@ const ModelStoreListPageV2: React.FC = () => {
343322 queryParams . sort ,
344323 ) ;
345324
346- const [ selectedModelCard , setSelectedModelCard ] =
347- useState < ModelCardDrawerFragment$key | null > ( null ) ;
348-
349325 const filter : GraphQLFilter | undefined = queryParams . filter ?? undefined ;
350326 const deferredFilter = useDeferredValue ( filter ) ;
351327 const deferredSortField = useDeferredValue ( sortField ) ;
@@ -364,6 +340,37 @@ const ModelStoreListPageV2: React.FC = () => {
364340 const deferredLimit = useDeferredValue ( baiPaginationOption . limit ) ;
365341 const deferredOffset = useDeferredValue ( baiPaginationOption . offset ) ;
366342
343+ // Drawer data is intentionally NOT fetched as part of the main list query
344+ // — the per-card drawer fragment (readme, all presets, vfolder metadata)
345+ // is heavy, and including it via `...ModelCardDrawerFragment` on every
346+ // edge multiplies the list-page payload. Instead we run a separate query
347+ // here gated by `useDeferredValue(drawerOpen)`: while no card is selected
348+ // (`deferredDrawerOpen` falsy), `fetchPolicy: 'store-only'` keeps the
349+ // network quiet and the empty-string `id` is never sent. Same pattern as
350+ // `FolderExplorerOpener` → `FolderExplorerModalV2`.
351+ const selectedModelCardId = queryParams . modelCard ;
352+ const drawerOpen = ! ! selectedModelCardId ;
353+ const deferredDrawerOpen = useDeferredValue ( drawerOpen ) ;
354+ const localSelectedModelCardId = selectedModelCardId
355+ ? safeDecodeUuid ( selectedModelCardId )
356+ : undefined ;
357+ const drawerData = useLazyLoadQuery < ModelStoreListPageV2DrawerQuery > (
358+ graphql `
359+ query ModelStoreListPageV2DrawerQuery($id: UUID!) {
360+ modelCardV2(id: $id) {
361+ ...ModelCardDrawerFragment
362+ }
363+ }
364+ ` ,
365+ { id : localSelectedModelCardId ?? '' } ,
366+ {
367+ fetchPolicy :
368+ deferredDrawerOpen && localSelectedModelCardId
369+ ? 'store-and-network'
370+ : 'store-only' ,
371+ } ,
372+ ) ;
373+
367374 const isPendingPage =
368375 deferredLimit !== baiPaginationOption . limit ||
369376 deferredOffset !== baiPaginationOption . offset ;
@@ -481,10 +488,7 @@ const ModelStoreListPageV2: React.FC = () => {
481488 pageSize = { deferredLimit }
482489 offset = { deferredOffset }
483490 onTotalChange = { setTotal }
484- selectedModelCardId = { queryParams . modelCard }
485- onSelectedModelCardFound = { ( frgmt ) => setSelectedModelCard ( frgmt ) }
486- onCardClick = { ( id , frgmt ) => {
487- setSelectedModelCard ( frgmt ) ;
491+ onCardClick = { ( id ) => {
488492 setQueryParams ( { modelCard : id } ) ;
489493 } }
490494 />
@@ -525,10 +529,9 @@ const ModelStoreListPageV2: React.FC = () => {
525529 ) }
526530
527531 < ModelCardDrawer
528- modelCardDrawerFrgmt = { selectedModelCard }
529- open = { ! ! queryParams . modelCard && ! ! selectedModelCard }
532+ modelCardDrawerFrgmt = { drawerData . modelCardV2 ?? null }
533+ open = { drawerOpen }
530534 onClose = { ( ) => {
531- setSelectedModelCard ( null ) ;
532535 setQueryParams ( { modelCard : null } ) ;
533536 } }
534537 />
0 commit comments