From 0c991e1f50e1b38d40d498f4e50e017dc81fa158 Mon Sep 17 00:00:00 2001 From: ppadti Date: Tue, 10 Sep 2024 14:42:31 +0530 Subject: [PATCH] Upadte archived models and archived versions components --- .../modelRegistry/registeredModelArchive.ts | 6 + .../registeredModelArchive.cy.ts | 32 ++- .../EditableTextDescriptionListGroup.tsx | 4 +- .../modelRegistry/ModelRegistryRoutes.tsx | 20 ++ .../ModelPropertiesDescriptionListGroup.tsx | 27 ++- .../screens/ModelPropertiesTableRow.tsx | 78 ++++--- .../ModelVersionDetailsTabs.tsx | 8 +- .../ModelVersionDetailsView.tsx | 60 +++-- .../ModelVersions/ModelDetailsView.tsx | 65 ++++-- .../ModelVersions/ModelVersionListView.tsx | 216 +++++++++++------- .../ModelVersions/ModelVersionsTable.tsx | 9 +- .../ModelVersions/ModelVersionsTableRow.tsx | 127 +++++----- .../ModelVersions/ModelVersionsTabs.tsx | 9 +- .../ArchiveModelVersionDetails.tsx | 83 +++++++ .../ArchiveModelVersionDetailsBreadcrumb.tsx | 41 ++++ .../ModelVersionArchiveDetails.tsx | 1 + .../RegisteredModelArchiveDetails.tsx | 1 + .../pages/modelRegistry/screens/routeUtils.ts | 11 + 18 files changed, 565 insertions(+), 233 deletions(-) create mode 100644 frontend/src/pages/modelRegistry/screens/ModelVersionsArchive/ArchiveModelVersionDetails.tsx create mode 100644 frontend/src/pages/modelRegistry/screens/ModelVersionsArchive/ArchiveModelVersionDetailsBreadcrumb.tsx diff --git a/frontend/src/__tests__/cypress/cypress/pages/modelRegistry/registeredModelArchive.ts b/frontend/src/__tests__/cypress/cypress/pages/modelRegistry/registeredModelArchive.ts index fcba9d4102..05b1186ea3 100644 --- a/frontend/src/__tests__/cypress/cypress/pages/modelRegistry/registeredModelArchive.ts +++ b/frontend/src/__tests__/cypress/cypress/pages/modelRegistry/registeredModelArchive.ts @@ -66,6 +66,12 @@ class ModelArchive { cy.visit(`/modelRegistry/${preferredModelRegistry}/registeredModels/archive/${rmId}`); } + visitArchiveModelVersionList() { + const rmId = '2'; + const preferredModelRegistry = 'modelregistry-sample'; + cy.visit(`/modelRegistry/${preferredModelRegistry}/registeredModels/archive/${rmId}/versions`); + } + visitModelList() { cy.visit('/modelRegistry/modelregistry-sample'); this.wait(); diff --git a/frontend/src/__tests__/cypress/cypress/tests/mocked/modelRegistry/registeredModelArchive.cy.ts b/frontend/src/__tests__/cypress/cypress/tests/mocked/modelRegistry/registeredModelArchive.cy.ts index 9495185943..90334245bd 100644 --- a/frontend/src/__tests__/cypress/cypress/tests/mocked/modelRegistry/registeredModelArchive.cy.ts +++ b/frontend/src/__tests__/cypress/cypress/tests/mocked/modelRegistry/registeredModelArchive.cy.ts @@ -47,7 +47,7 @@ const initIntercepts = ({ mockRegisteredModel({ id: '4', name: 'model 4' }), ], modelVersions = [ - mockModelVersion({ author: 'Author 1' }), + mockModelVersion({ author: 'Author 1', registeredModelId: '2' }), mockModelVersion({ name: 'model version' }), ], }: HandlersProps) => { @@ -74,13 +74,25 @@ const initIntercepts = ({ mockRegisteredModelList({ items: registeredModels }), ); + cy.interceptOdh( + `GET /api/service/modelregistry/:serviceName/api/model_registry/:apiVersion/model_versions/:modelVersionId`, + { + path: { + serviceName: 'modelregistry-sample', + apiVersion: MODEL_REGISTRY_API_VERSION, + modelVersionId: 1, + }, + }, + mockModelVersion({ id: '1', name: 'Version 2' }), + ); + cy.interceptOdh( `GET /api/service/modelregistry/:serviceName/api/model_registry/:apiVersion/registered_models/:registeredModelId/versions`, { path: { serviceName: 'modelregistry-sample', apiVersion: MODEL_REGISTRY_API_VERSION, - registeredModelId: 1, + registeredModelId: 2, }, }, mockModelVersionList({ items: modelVersions }), @@ -123,6 +135,22 @@ describe('Model archive list', () => { registeredModelArchive.findArchiveModelTable().should('be.visible'); }); + it('Archived model flow', () => { + initIntercepts({}); + registeredModelArchive.visitArchiveModelVersionList(); + verifyRelativeURL('/modelRegistry/modelregistry-sample/registeredModels/archive/2/versions'); + + modelRegistry.findModelVersionsTable().should('be.visible'); + modelRegistry.findModelVersionsTableRows().should('have.length', 2); + const version = modelRegistry.getModelVersionRow('model version'); + version.findModelVersionName().contains('model version').click(); + verifyRelativeURL( + '/modelRegistry/modelregistry-sample/registeredModels/archive/2/versions/1/details', + ); + cy.go('back'); + verifyRelativeURL('/modelRegistry/modelregistry-sample/registeredModels/archive/2/versions'); + }); + it('Archive models list', () => { initIntercepts({}); registeredModelArchive.visit(); diff --git a/frontend/src/components/EditableTextDescriptionListGroup.tsx b/frontend/src/components/EditableTextDescriptionListGroup.tsx index 2084d77ab5..8f248f9df7 100644 --- a/frontend/src/components/EditableTextDescriptionListGroup.tsx +++ b/frontend/src/components/EditableTextDescriptionListGroup.tsx @@ -11,12 +11,14 @@ type EditableTextDescriptionListGroupProps = Pick< value: string; saveEditedValue: (value: string) => Promise; testid?: string; + isArchive?: boolean; }; const EditableTextDescriptionListGroup: React.FC = ({ title, contentWhenEmpty, value, + isArchive, saveEditedValue, testid, }) => { @@ -29,7 +31,7 @@ const EditableTextDescriptionListGroup: React.FC ( @@ -91,6 +92,25 @@ const ModelRegistryRoutes: React.FC = () => ( } /> + + } /> + + } + /> + + } + /> + } /> + } /> } /> diff --git a/frontend/src/pages/modelRegistry/screens/ModelPropertiesDescriptionListGroup.tsx b/frontend/src/pages/modelRegistry/screens/ModelPropertiesDescriptionListGroup.tsx index c493a3babe..bdded1d537 100644 --- a/frontend/src/pages/modelRegistry/screens/ModelPropertiesDescriptionListGroup.tsx +++ b/frontend/src/pages/modelRegistry/screens/ModelPropertiesDescriptionListGroup.tsx @@ -11,11 +11,13 @@ import { getProperties, mergeUpdatedProperty } from './utils'; type ModelPropertiesDescriptionListGroupProps = { customProperties: ModelRegistryCustomProperties; + isArchive?: boolean; saveEditedCustomProperties: (properties: ModelRegistryCustomProperties) => Promise; }; const ModelPropertiesDescriptionListGroup: React.FC = ({ customProperties = {}, + isArchive, saveEditedCustomProperties, }) => { const [editingPropertyKeys, setEditingPropertyKeys] = React.useState([]); @@ -51,16 +53,18 @@ const ModelPropertiesDescriptionListGroup: React.FC} - iconPosition="start" - isDisabled={isAdding || isSavingEdits} - onClick={() => setIsAdding(true)} - > - Add property - + !isArchive && ( + + ) } isEmpty={!isAdding && keys.length === 0} contentWhenEmpty="No properties" @@ -70,13 +74,14 @@ const ModelPropertiesDescriptionListGroup: React.FC Key {isEditingSomeRow && requiredAsterisk} Value {isEditingSomeRow && requiredAsterisk} - + {shownKeys.map((key) => ( void; isSavingEdits: boolean; + isArchive?: boolean; setIsSavingEdits: (isSaving: boolean) => void; saveEditedProperty: (oldKey: string, newPair: KeyValuePair) => Promise; } & EitherNotBoth< @@ -38,6 +39,7 @@ const ModelPropertiesTableRow: React.FC = ({ setIsEditing, isSavingEdits, setIsSavingEdits, + isArchive, saveEditedProperty, }) => { const { key, value } = keyValuePair; @@ -143,43 +145,45 @@ const ModelPropertiesTableRow: React.FC = ({ )} - - {isEditing ? ( - - - - - - - - - ) : ( - - )} - + {!isArchive && ( + + {isEditing ? ( + + + + + + + + + ) : ( + + )} + + )} ); }; diff --git a/frontend/src/pages/modelRegistry/screens/ModelVersionDetails/ModelVersionDetailsTabs.tsx b/frontend/src/pages/modelRegistry/screens/ModelVersionDetails/ModelVersionDetailsTabs.tsx index 54deea14dc..53ec95ec7f 100644 --- a/frontend/src/pages/modelRegistry/screens/ModelVersionDetails/ModelVersionDetailsTabs.tsx +++ b/frontend/src/pages/modelRegistry/screens/ModelVersionDetails/ModelVersionDetailsTabs.tsx @@ -14,6 +14,7 @@ type ModelVersionDetailTabsProps = { modelVersion: ModelVersion; inferenceServices: FetchStateObject; servingRuntimes: FetchStateObject; + isArchiveVersion?: boolean; refresh: () => void; }; @@ -22,6 +23,7 @@ const ModelVersionDetailsTabs: React.FC = ({ modelVersion: mv, inferenceServices, servingRuntimes, + isArchiveVersion, refresh, }) => { const navigate = useNavigate(); @@ -40,7 +42,11 @@ const ModelVersionDetailsTabs: React.FC = ({ data-testid="model-versions-details-tab" > - + void; }; const ModelVersionDetailsView: React.FC = ({ modelVersion: mv, + isArchiveVersion, refresh, }) => { const [modelArtifact] = useModelArtifactsByVersionId(mv.id); @@ -36,6 +46,7 @@ const ModelVersionDetailsView: React.FC = ({ = ({ .then(refresh) } /> - - apiState.api - .patchModelVersion( - {}, - { - customProperties: mergeUpdatedLabels(mv.customProperties, editedLabels), - }, - mv.id, - ) - .then(refresh) - } - /> + {isArchiveVersion ? ( + + + {getLabels(mv.customProperties).map((label) => ( + + ))} + + + ) : ( + + apiState.api + .patchModelVersion( + {}, + { + customProperties: mergeUpdatedLabels(mv.customProperties, editedLabels), + }, + mv.id, + ) + .then(refresh) + } + /> + )} apiState.api diff --git a/frontend/src/pages/modelRegistry/screens/ModelVersions/ModelDetailsView.tsx b/frontend/src/pages/modelRegistry/screens/ModelVersions/ModelDetailsView.tsx index bdf7f79801..5363c5bc48 100644 --- a/frontend/src/pages/modelRegistry/screens/ModelVersions/ModelDetailsView.tsx +++ b/frontend/src/pages/modelRegistry/screens/ModelVersions/ModelDetailsView.tsx @@ -1,5 +1,13 @@ import * as React from 'react'; -import { ClipboardCopy, DescriptionList, Flex, FlexItem, Text } from '@patternfly/react-core'; +import { + ClipboardCopy, + DescriptionList, + Flex, + FlexItem, + Label, + LabelGroup, + Text, +} from '@patternfly/react-core'; import { RegisteredModel } from '~/concepts/modelRegistry/types'; import { ModelRegistryContext } from '~/concepts/modelRegistry/context/ModelRegistryContext'; import DashboardDescriptionListGroup from '~/components/DashboardDescriptionListGroup'; @@ -12,9 +20,14 @@ import ModelPropertiesDescriptionListGroup from '~/pages/modelRegistry/screens/M type ModelDetailsViewProps = { registeredModel: RegisteredModel; refresh: () => void; + isArchiveModel?: boolean; }; -const ModelDetailsView: React.FC = ({ registeredModel: rm, refresh }) => { +const ModelDetailsView: React.FC = ({ + registeredModel: rm, + refresh, + isArchiveModel, +}) => { const { apiState } = React.useContext(ModelRegistryContext); return ( = ({ registeredModel: rm @@ -40,22 +54,39 @@ const ModelDetailsView: React.FC = ({ registeredModel: rm .then(refresh) } /> - - apiState.api - .patchRegisteredModel( - {}, - { - customProperties: mergeUpdatedLabels(rm.customProperties, editedLabels), - }, - rm.id, - ) - .then(refresh) - } - /> + {isArchiveModel ? ( + + + {getLabels(rm.customProperties).map((label) => ( + + ))} + + + ) : ( + + apiState.api + .patchRegisteredModel( + {}, + { + customProperties: mergeUpdatedLabels(rm.customProperties, editedLabels), + }, + rm.id, + ) + .then(refresh) + } + /> + )} apiState.api diff --git a/frontend/src/pages/modelRegistry/screens/ModelVersions/ModelVersionListView.tsx b/frontend/src/pages/modelRegistry/screens/ModelVersions/ModelVersionListView.tsx index 458ef9f5a8..5ad1c599df 100644 --- a/frontend/src/pages/modelRegistry/screens/ModelVersions/ModelVersionListView.tsx +++ b/frontend/src/pages/modelRegistry/screens/ModelVersions/ModelVersionListView.tsx @@ -1,5 +1,6 @@ import * as React from 'react'; import { + Alert, Button, Dropdown, DropdownItem, @@ -35,12 +36,14 @@ import ModelVersionsTable from './ModelVersionsTable'; type ModelVersionListViewProps = { modelVersions: ModelVersion[]; registeredModel?: RegisteredModel; + isArchiveModel?: boolean; refresh: () => void; }; const ModelVersionListView: React.FC = ({ modelVersions: unfilteredModelVersions, registeredModel: rm, + isArchiveModel, refresh, }) => { const navigate = useNavigate(); @@ -55,8 +58,18 @@ const ModelVersionListView: React.FC = ({ React.useState(false); const filteredModelVersions = filterModelVersions(unfilteredModelVersions, search, searchType); + const date = rm?.lastUpdateTimeSinceEpoch && new Date(parseInt(rm.lastUpdateTimeSinceEpoch)); if (unfilteredModelVersions.length === 0) { + if (isArchiveModel) { + return ( + + ); + } return ( = ({ } return ( - setSearch('')} - modelVersions={sortModelVersionsByCreateTime(filteredModelVersions)} - toolbarContent={ - - } breakpoint="xl"> - - setSearch('')} - deleteChipGroup={() => setSearch('')} - categoryName={searchType} - > - ({ - key, - label: key, - }))} - value={searchType} - onChange={(newSearchType) => { - const enumMember = asEnumMember(newSearchType, SearchType); - if (enumMember !== null) { - setSearchType(enumMember); - } - }} - icon={} - /> - - - { - setSearch(searchValue); - }} - onClear={() => setSearch('')} - style={{ minWidth: '200px' }} - data-testid="model-versions-table-search" - /> - - - - - - - - setIsArchivedModelVersionKebabOpen(false)} - onOpenChange={(isOpen: boolean) => setIsArchivedModelVersionKebabOpen(isOpen)} - toggle={(tr: React.Ref) => ( - - setIsArchivedModelVersionKebabOpen(!isArchivedModelVersionKebabOpen) - } - isExpanded={isArchivedModelVersionKebabOpen} - aria-label="View archived versions" + <> + {isArchiveModel && ( + + )} + setSearch('')} + modelVersions={sortModelVersionsByCreateTime(filteredModelVersions)} + toolbarContent={ + + } breakpoint="xl"> + + setSearch('')} + deleteChipGroup={() => setSearch('')} + categoryName={searchType} > - - - )} - shouldFocusToggleOnSelect - > - - - navigate(modelVersionArchiveUrl(rm?.id, preferredModelRegistry?.metadata.name)) - } - > - View archived versions - - - - - - } - /> + ({ + key, + label: key, + }))} + value={searchType} + onChange={(newSearchType) => { + const enumMember = asEnumMember(newSearchType, SearchType); + if (enumMember !== null) { + setSearchType(enumMember); + } + }} + icon={} + /> + + + { + setSearch(searchValue); + }} + onClear={() => setSearch('')} + style={{ minWidth: '200px' }} + data-testid="model-versions-table-search" + /> + + + + {!isArchiveModel && ( + <> + + + + + setIsArchivedModelVersionKebabOpen(false)} + onOpenChange={(isOpen: boolean) => setIsArchivedModelVersionKebabOpen(isOpen)} + toggle={(tr: React.Ref) => ( + + setIsArchivedModelVersionKebabOpen(!isArchivedModelVersionKebabOpen) + } + isExpanded={isArchivedModelVersionKebabOpen} + aria-label="View archived versions" + > + + + )} + shouldFocusToggleOnSelect + > + + + navigate( + modelVersionArchiveUrl(rm?.id, preferredModelRegistry?.metadata.name), + ) + } + > + View archived versions + + + + + + )} + + } + /> + ); }; diff --git a/frontend/src/pages/modelRegistry/screens/ModelVersions/ModelVersionsTable.tsx b/frontend/src/pages/modelRegistry/screens/ModelVersions/ModelVersionsTable.tsx index e959d4630b..fa1c75034b 100644 --- a/frontend/src/pages/modelRegistry/screens/ModelVersions/ModelVersionsTable.tsx +++ b/frontend/src/pages/modelRegistry/screens/ModelVersions/ModelVersionsTable.tsx @@ -8,6 +8,7 @@ import { mvColumns } from './ModelVersionsTableColumns'; type ModelVersionsTableProps = { clearFilters: () => void; modelVersions: ModelVersion[]; + isArchiveModel?: boolean; refresh: () => void; } & Partial, 'toolbarContent'>>; @@ -15,6 +16,7 @@ const ModelVersionsTable: React.FC = ({ clearFilters, modelVersions, toolbarContent, + isArchiveModel, refresh, }) => ( = ({ enablePagination emptyTableView={} rowRenderer={(mv) => ( - + )} /> ); diff --git a/frontend/src/pages/modelRegistry/screens/ModelVersions/ModelVersionsTableRow.tsx b/frontend/src/pages/modelRegistry/screens/ModelVersions/ModelVersionsTableRow.tsx index fc97221cb6..88e7fe3a11 100644 --- a/frontend/src/pages/modelRegistry/screens/ModelVersions/ModelVersionsTableRow.tsx +++ b/frontend/src/pages/modelRegistry/screens/ModelVersions/ModelVersionsTableRow.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { ActionsColumn, Td, Tr } from '@patternfly/react-table'; +import { ActionsColumn, IAction, Td, Tr } from '@patternfly/react-table'; import { Text, TextVariants, Truncate, FlexItem } from '@patternfly/react-core'; import { Link, useNavigate } from 'react-router-dom'; import { ModelVersion, ModelState } from '~/concepts/modelRegistry/types'; @@ -7,6 +7,7 @@ import { ModelRegistrySelectorContext } from '~/concepts/modelRegistry/context/M import ModelLabels from '~/pages/modelRegistry/screens/components/ModelLabels'; import ModelTimestamp from '~/pages/modelRegistry/screens/components/ModelTimestamp'; import { + archiveModelVersionDetailsUrl, modelVersionArchiveDetailsUrl, modelVersionDeploymentsUrl, modelVersionUrl, @@ -19,12 +20,14 @@ import DeployRegisteredModelModal from '~/pages/modelRegistry/screens/components type ModelVersionsTableRowProps = { modelVersion: ModelVersion; isArchiveRow?: boolean; + isArchiveModel?: boolean; refresh: () => void; }; const ModelVersionsTableRow: React.FC = ({ modelVersion: mv, isArchiveRow, + isArchiveModel, refresh, }) => { const navigate = useNavigate(); @@ -34,7 +37,7 @@ const ModelVersionsTableRow: React.FC = ({ const [isDeployModalOpen, setIsDeployModalOpen] = React.useState(false); const { apiState } = React.useContext(ModelRegistryContext); - const actions = isArchiveRow + const actions: IAction[] = isArchiveRow ? [ { title: 'Restore version', @@ -59,7 +62,13 @@ const ModelVersionsTableRow: React.FC = ({ = ({ - + } + onCancel={() => setIsDeployModalOpen(false)} + isOpen={isDeployModalOpen} + modelVersion={mv} + /> + setIsRestoreModalOpen(false)} + onSubmit={() => + apiState.api + .patchModelVersion( + {}, + { + state: ModelState.LIVE, + }, + mv.id, + ) + .then(() => + navigate( + modelVersionUrl( + mv.id, + mv.registeredModelId, + preferredModelRegistry?.metadata.name, + ), + ), + ) + } + isOpen={isRestoreModalOpen} + modelVersionName={mv.name} + /> + + )} ); }; diff --git a/frontend/src/pages/modelRegistry/screens/ModelVersions/ModelVersionsTabs.tsx b/frontend/src/pages/modelRegistry/screens/ModelVersions/ModelVersionsTabs.tsx index 562c9c2068..6eaaf75df0 100644 --- a/frontend/src/pages/modelRegistry/screens/ModelVersions/ModelVersionsTabs.tsx +++ b/frontend/src/pages/modelRegistry/screens/ModelVersions/ModelVersionsTabs.tsx @@ -11,6 +11,7 @@ type ModelVersionsTabProps = { tab: ModelVersionsTab; registeredModel: RegisteredModel; modelVersions: ModelVersion[]; + isArchiveModel?: boolean; refresh: () => void; mvRefresh: () => void; }; @@ -20,6 +21,7 @@ const ModelVersionsTabs: React.FC = ({ registeredModel: rm, modelVersions, refresh, + isArchiveModel, mvRefresh, }) => { const navigate = useNavigate(); @@ -39,6 +41,7 @@ const ModelVersionsTabs: React.FC = ({ > = ({ data-testid="model-details-tab" > - + diff --git a/frontend/src/pages/modelRegistry/screens/ModelVersionsArchive/ArchiveModelVersionDetails.tsx b/frontend/src/pages/modelRegistry/screens/ModelVersionsArchive/ArchiveModelVersionDetails.tsx new file mode 100644 index 0000000000..f8069af2a5 --- /dev/null +++ b/frontend/src/pages/modelRegistry/screens/ModelVersionsArchive/ArchiveModelVersionDetails.tsx @@ -0,0 +1,83 @@ +import React from 'react'; +import { useParams } from 'react-router'; +import { Button, Flex, FlexItem, Label, Text, Tooltip, Truncate } from '@patternfly/react-core'; +import ApplicationsPage from '~/pages/ApplicationsPage'; +import useModelVersionById from '~/concepts/modelRegistry/apiHooks/useModelVersionById'; +import { ModelRegistrySelectorContext } from '~/concepts/modelRegistry/context/ModelRegistrySelectorContext'; +import useRegisteredModelById from '~/concepts/modelRegistry/apiHooks/useRegisteredModelById'; +import { ModelVersionDetailsTab } from '~/pages/modelRegistry/screens/ModelVersionDetails/const'; +import ModelVersionDetailsTabs from '~/pages/modelRegistry/screens/ModelVersionDetails/ModelVersionDetailsTabs'; +import useInferenceServices from '~/pages/modelServing/useInferenceServices'; +import useServingRuntimes from '~/pages/modelServing/useServingRuntimes'; +import { useMakeFetchObject } from '~/utilities/useMakeFetchObject'; +import ArchiveModelVersionDetailsBreadcrumb from './ArchiveModelVersionDetailsBreadcrumb'; + +type ArchiveModelVersionDetailsProps = { + tab: ModelVersionDetailsTab; +} & Omit< + React.ComponentProps, + 'breadcrumb' | 'title' | 'description' | 'loadError' | 'loaded' | 'provideChildrenPadding' +>; + +const ArchiveModelVersionDetails: React.FC = ({ + tab, + ...pageProps +}) => { + const { preferredModelRegistry } = React.useContext(ModelRegistrySelectorContext); + const { modelVersionId: mvId, registeredModelId: rmId } = useParams(); + const [rm] = useRegisteredModelById(rmId); + const [mv, mvLoaded, mvLoadError, refreshModelVersion] = useModelVersionById(mvId); + const inferenceServices = useMakeFetchObject( + useInferenceServices(undefined, mv?.registeredModelId, mv?.id), + ); + const servingRuntimes = useMakeFetchObject(useServingRuntimes()); + + return ( + + } + title={ + mv && ( + + + {mv.name} + + + + + + ) + } + headerAction={ + + + + } + description={} + loadError={mvLoadError} + loaded={mvLoaded} + provideChildrenPadding + > + {mv !== null && ( + + )} + + ); +}; + +export default ArchiveModelVersionDetails; diff --git a/frontend/src/pages/modelRegistry/screens/ModelVersionsArchive/ArchiveModelVersionDetailsBreadcrumb.tsx b/frontend/src/pages/modelRegistry/screens/ModelVersionsArchive/ArchiveModelVersionDetailsBreadcrumb.tsx new file mode 100644 index 0000000000..15fdcaf124 --- /dev/null +++ b/frontend/src/pages/modelRegistry/screens/ModelVersionsArchive/ArchiveModelVersionDetailsBreadcrumb.tsx @@ -0,0 +1,41 @@ +import { Breadcrumb, BreadcrumbItem } from '@patternfly/react-core'; +import React from 'react'; +import { Link } from 'react-router-dom'; +import { RegisteredModel } from '~/concepts/modelRegistry/types'; +import { + registeredModelArchiveDetailsUrl, + registeredModelArchiveUrl, +} from '~/pages/modelRegistry/screens/routeUtils'; + +type ArchiveModelVersionDetailsBreadcrumbProps = { + preferredModelRegistry?: string; + registeredModel: RegisteredModel | null; + modelVersionName?: string; +}; + +const ArchiveModelVersionDetailsBreadcrumb: React.FC = ({ + preferredModelRegistry, + registeredModel, + modelVersionName, +}) => ( + + Model registry - {preferredModelRegistry}} + /> + ( + Archived models + )} + /> + ( + + {registeredModel?.name || 'Loading...'} + + )} + /> + {modelVersionName || 'Loading...'} + +); + +export default ArchiveModelVersionDetailsBreadcrumb; diff --git a/frontend/src/pages/modelRegistry/screens/ModelVersionsArchive/ModelVersionArchiveDetails.tsx b/frontend/src/pages/modelRegistry/screens/ModelVersionsArchive/ModelVersionArchiveDetails.tsx index b522672092..177cd31a20 100644 --- a/frontend/src/pages/modelRegistry/screens/ModelVersionsArchive/ModelVersionArchiveDetails.tsx +++ b/frontend/src/pages/modelRegistry/screens/ModelVersionsArchive/ModelVersionArchiveDetails.tsx @@ -76,6 +76,7 @@ const ModelVersionsArchiveDetails: React.FC = > {mv !== null && ( `${registeredModelUrl(rmId, preferredModelRegistry)}/versions`; +export const archiveModelVersionListUrl = ( + rmId?: string, + preferredModelRegistry?: string, +): string => `${registeredModelArchiveDetailsUrl(rmId, preferredModelRegistry)}/versions`; + export const modelVersionUrl = ( mvId: string, rmId?: string, @@ -27,6 +32,12 @@ export const modelVersionUrl = ( export const modelVersionArchiveUrl = (rmId?: string, preferredModelRegistry?: string): string => `${modelVersionListUrl(rmId, preferredModelRegistry)}/archive`; +export const archiveModelVersionDetailsUrl = ( + mvId: string, + rmId?: string, + preferredModelRegistry?: string, +): string => `${archiveModelVersionListUrl(rmId, preferredModelRegistry)}/${mvId}`; + export const modelVersionArchiveDetailsUrl = ( mvId: string, rmId?: string,
- - setIsArchiveModalOpen(false)} - onSubmit={() => - apiState.api - .patchModelVersion( - {}, - { - state: ModelState.ARCHIVED, - }, - mv.id, - ) - .then(refresh) - } - isOpen={isArchiveModalOpen} - modelVersionName={mv.name} - /> - - navigate( - modelVersionDeploymentsUrl( - mv.id, - mv.registeredModelId, - preferredModelRegistry?.metadata.name, - ), - ) - } - onCancel={() => setIsDeployModalOpen(false)} - isOpen={isDeployModalOpen} - modelVersion={mv} - /> - setIsRestoreModalOpen(false)} - onSubmit={() => - apiState.api - .patchModelVersion( - {}, - { - state: ModelState.LIVE, - }, - mv.id, - ) - .then(() => - navigate( - modelVersionUrl( - mv.id, - mv.registeredModelId, - preferredModelRegistry?.metadata.name, - ), + {!isArchiveModel && ( + + + setIsArchiveModalOpen(false)} + onSubmit={() => + apiState.api + .patchModelVersion( + {}, + { + state: ModelState.ARCHIVED, + }, + mv.id, + ) + .then(refresh) + } + isOpen={isArchiveModalOpen} + modelVersionName={mv.name} + /> + + navigate( + modelVersionDeploymentsUrl( + mv.id, + mv.registeredModelId, + preferredModelRegistry?.metadata.name, ), ) - } - isOpen={isRestoreModalOpen} - modelVersionName={mv.name} - /> -