diff --git a/frontend/src/__mocks__/mockModelVersion.ts b/frontend/src/__mocks__/mockModelVersion.ts index e1b9e5dfe6..afe27ff872 100644 --- a/frontend/src/__mocks__/mockModelVersion.ts +++ b/frontend/src/__mocks__/mockModelVersion.ts @@ -2,12 +2,12 @@ import { ModelVersion, ModelVersionState } from '~/concepts/modelRegistry/types' type MockModelVersionType = { author?: string; - registeredModelID?: string; + registeredModelId?: string; }; export const mockModelVersion = ({ author = 'Test author', - registeredModelID = '1', + registeredModelId = '1', }: MockModelVersionType): ModelVersion => ({ author, createTimeSinceEpoch: '1712234877179', @@ -16,5 +16,5 @@ export const mockModelVersion = ({ lastUpdateTimeSinceEpoch: '1712234877179', name: 'fraud detection model version 1', state: ModelVersionState.ARCHIVED, - registeredModelID, + registeredModelId, }); diff --git a/frontend/src/__mocks__/mockModelVersionList.ts b/frontend/src/__mocks__/mockModelVersionList.ts index 79f80ce406..c9e845c93f 100644 --- a/frontend/src/__mocks__/mockModelVersionList.ts +++ b/frontend/src/__mocks__/mockModelVersionList.ts @@ -2,7 +2,7 @@ import { ModelVersionList } from '~/concepts/modelRegistry/types'; import { mockModelVersion } from './mockModelVersion'; export const mockModelVersionList = (): ModelVersionList => ({ - items: [mockModelVersion({ author: 'Author 1', registeredModelID: '1' })], + items: [mockModelVersion({ author: 'Author 1', registeredModelId: '1' })], nextPageToken: '', pageSize: 0, size: 1, diff --git a/frontend/src/api/modelRegistry/__tests__/custom.spec.ts b/frontend/src/api/modelRegistry/__tests__/custom.spec.ts index d899326f6c..30e2a396d2 100644 --- a/frontend/src/api/modelRegistry/__tests__/custom.spec.ts +++ b/frontend/src/api/modelRegistry/__tests__/custom.spec.ts @@ -19,6 +19,7 @@ import { patchModelArtifact, patchModelVersion, patchRegisteredModel, + getModelArtifactsByModelVersion, } from '~/api/modelRegistry/custom'; import { MODEL_REGISTRY_API_VERSION } from '~/concepts/modelRegistry/const'; @@ -80,7 +81,7 @@ describe('createModelVersion', () => { description: 'test', externalID: '1', author: 'test author', - registeredModelID: '1', + registeredModelId: '1', name: 'test new model version', state: ModelVersionState.LIVE, customProperties: {}, @@ -94,7 +95,7 @@ describe('createModelVersion', () => { description: 'test', externalID: '1', author: 'test author', - registeredModelID: '1', + registeredModelId: '1', name: 'test new model version', state: ModelVersionState.LIVE, customProperties: {}, @@ -254,6 +255,21 @@ describe('getModelVersionsByRegisteredModel', () => { }); }); +describe('getModelArtifactsByModelVersion', () => { + it('should call proxyGET and handleModelRegistryFailures to list models artifacts by model version', () => { + expect(getModelArtifactsByModelVersion('hostPath')({}, '1')).toBe(mockResultPromise); + expect(proxyGETMock).toHaveBeenCalledTimes(1); + expect(proxyGETMock).toHaveBeenCalledWith( + 'hostPath', + `/api/model_registry/${MODEL_REGISTRY_API_VERSION}/model_versions/1/artifacts`, + {}, + K8sAPIOptionsMock, + ); + expect(handleModelRegistryFailuresMock).toHaveBeenCalledTimes(1); + expect(handleModelRegistryFailuresMock).toHaveBeenCalledWith(mockProxyPromise); + }); +}); + describe('patchRegisteredModel', () => { it('should call proxyPATCH and handleModelRegistryFailures to update registered model', () => { expect( diff --git a/frontend/src/api/modelRegistry/custom.ts b/frontend/src/api/modelRegistry/custom.ts index 272eebe953..8282cc51ff 100644 --- a/frontend/src/api/modelRegistry/custom.ts +++ b/frontend/src/api/modelRegistry/custom.ts @@ -55,11 +55,11 @@ export const createModelArtifact = export const getRegisteredModel = (hostPath: string) => - (opts: K8sAPIOptions, registeredModelID: string): Promise => + (opts: K8sAPIOptions, registeredModelId: string): Promise => handleModelRegistryFailures( proxyGET( hostPath, - `/api/model_registry/${MODEL_REGISTRY_API_VERSION}/registered_models/${registeredModelID}`, + `/api/model_registry/${MODEL_REGISTRY_API_VERSION}/registered_models/${registeredModelId}`, {}, opts, ), @@ -137,17 +137,29 @@ export const getModelVersionsByRegisteredModel = ), ); +export const getModelArtifactsByModelVersion = + (hostpath: string) => + (opts: K8sAPIOptions, modelVersionId: string): Promise => + handleModelRegistryFailures( + proxyGET( + hostpath, + `/api/model_registry/${MODEL_REGISTRY_API_VERSION}/model_versions/${modelVersionId}/artifacts`, + {}, + opts, + ), + ); + export const patchRegisteredModel = (hostPath: string) => ( opts: K8sAPIOptions, data: Partial, - registeredModelID: string, + registeredModelId: string, ): Promise => handleModelRegistryFailures( proxyPATCH( hostPath, - `/api/model_registry/${MODEL_REGISTRY_API_VERSION}/registered_models/${registeredModelID}`, + `/api/model_registry/${MODEL_REGISTRY_API_VERSION}/registered_models/${registeredModelId}`, data, opts, ), diff --git a/frontend/src/components/DashboardDescriptionListGroup.tsx b/frontend/src/components/DashboardDescriptionListGroup.tsx index 8f40df0d70..acfdc1482b 100644 --- a/frontend/src/components/DashboardDescriptionListGroup.tsx +++ b/frontend/src/components/DashboardDescriptionListGroup.tsx @@ -8,6 +8,7 @@ import { DescriptionListTerm, Split, SplitItem, + Text, } from '@patternfly/react-core'; import text from '@patternfly/react-styles/css/utilities/Text/text'; import { CheckIcon, PencilAltIcon, TimesIcon } from '@patternfly/react-icons'; @@ -99,7 +100,13 @@ const DashboardDescriptionListGroup: React.FC{title} )} - {isEditing ? contentWhenEditing : isEmpty ? contentWhenEmpty : children} + {isEditing ? ( + contentWhenEditing + ) : isEmpty ? ( + {contentWhenEmpty} + ) : ( + children + )} ); diff --git a/frontend/src/concepts/modelRegistry/apiHooks/useModelArtifactsByVersionId.ts b/frontend/src/concepts/modelRegistry/apiHooks/useModelArtifactsByVersionId.ts new file mode 100644 index 0000000000..74d96bee28 --- /dev/null +++ b/frontend/src/concepts/modelRegistry/apiHooks/useModelArtifactsByVersionId.ts @@ -0,0 +1,29 @@ +import * as React from 'react'; +import useFetchState, { + FetchState, + FetchStateCallbackPromise, + NotReadyError, +} from '~/utilities/useFetchState'; +import { ModelArtifactList } from '~/concepts/modelRegistry/types'; +import { useModelRegistryAPI } from '~/concepts/modelRegistry/context/ModelRegistryContext'; + +const useModelArtifactsByVersionId = (modelVersionId?: string): FetchState => { + const { api } = useModelRegistryAPI(); + const callback = React.useCallback>( + (opts) => { + if (!modelVersionId) { + return Promise.reject(new NotReadyError('No model registeredModel id')); + } + return api.getModelArtifactsByModelVersion(opts, modelVersionId); + }, + [api, modelVersionId], + ); + + return useFetchState( + callback, + { items: [], size: 0, pageSize: 0, nextPageToken: '' }, + { initialPromisePurity: true }, + ); +}; + +export default useModelArtifactsByVersionId; diff --git a/frontend/src/concepts/modelRegistry/context/useModelRegistryAPIState.tsx b/frontend/src/concepts/modelRegistry/context/useModelRegistryAPIState.tsx index 0c7b5a30d1..ee5e5627ac 100644 --- a/frontend/src/concepts/modelRegistry/context/useModelRegistryAPIState.tsx +++ b/frontend/src/concepts/modelRegistry/context/useModelRegistryAPIState.tsx @@ -9,6 +9,7 @@ import { getListModelVersions, getListRegisteredModels, getModelArtifact, + getModelArtifactsByModelVersion, getModelVersion, getModelVersionsByRegisteredModel, getRegisteredModel, @@ -35,6 +36,7 @@ const useModelRegistryAPIState = ( listModelVersions: getListModelVersions(path), listRegisteredModels: getListRegisteredModels(path), getModelVersionsByRegisteredModel: getModelVersionsByRegisteredModel(path), + getModelArtifactsByModelVersion: getModelArtifactsByModelVersion(path), patchRegisteredModel: patchRegisteredModel(path), patchModelVersion: patchModelVersion(path), patchModelArtifact: patchModelArtifact(path), diff --git a/frontend/src/concepts/modelRegistry/types.ts b/frontend/src/concepts/modelRegistry/types.ts index f29008e90a..ae01447f8d 100644 --- a/frontend/src/concepts/modelRegistry/types.ts +++ b/frontend/src/concepts/modelRegistry/types.ts @@ -60,7 +60,7 @@ export type ModelArtifact = ModelRegistryBase & { export type ModelVersion = ModelRegistryBase & { state?: ModelVersionState; author?: string; - registeredModelID: string; + registeredModelId: string; }; export type RegisteredModel = ModelRegistryBase & { @@ -131,7 +131,7 @@ export type CreateModelArtifact = ( export type GetRegisteredModel = ( opts: K8sAPIOptions, - registeredModelID: string, + registeredModelId: string, ) => Promise; export type GetModelVersion = ( @@ -155,10 +155,15 @@ export type GetModelVersionsByRegisteredModel = ( registeredmodelId: string, ) => Promise; +export type GetModelArtifactsByModelVersion = ( + opts: K8sAPIOptions, + modelVersionId: string, +) => Promise; + export type PatchRegisteredModel = ( opts: K8sAPIOptions, data: Partial, - registeredModelID: string, + registeredModelId: string, ) => Promise; export type PatchModelVersion = ( @@ -184,6 +189,7 @@ export type ModelRegistryAPIs = { listModelVersions: GetListModelVersions; listRegisteredModels: GetListRegisteredModels; getModelVersionsByRegisteredModel: GetModelVersionsByRegisteredModel; + getModelArtifactsByModelVersion: GetModelArtifactsByModelVersion; patchRegisteredModel: PatchRegisteredModel; patchModelVersion: PatchModelVersion; patchModelArtifact: PatchModelArtifact; diff --git a/frontend/src/pages/modelRegistry/ModelRegistryRoutes.tsx b/frontend/src/pages/modelRegistry/ModelRegistryRoutes.tsx index 69e8835626..1efe05a190 100644 --- a/frontend/src/pages/modelRegistry/ModelRegistryRoutes.tsx +++ b/frontend/src/pages/modelRegistry/ModelRegistryRoutes.tsx @@ -5,6 +5,8 @@ import ModelRegistryCoreLoader from './ModelRegistryCoreLoader'; import ModelRegistry from './screens/ModelRegistry'; import { ModelVersionsTabs } from './screens/const'; import ModelVersions from './screens/ModelVersions'; +import ModelVersionsDetails from './screens/ModelVersionDetails/ModelVersionDetails'; +import { ModelVersionDetailsTab } from './screens/ModelVersionDetails/const'; const ModelRegistryRoutes: React.FC = () => ( @@ -28,6 +30,14 @@ const ModelRegistryRoutes: React.FC = () => ( path={ModelVersionsTabs.DETAILS} element={} /> + + } /> + } + /> + } /> + } /> } /> diff --git a/frontend/src/pages/modelRegistry/screens/ModelVersionDetails/ModelVersionDetails.tsx b/frontend/src/pages/modelRegistry/screens/ModelVersionDetails/ModelVersionDetails.tsx new file mode 100644 index 0000000000..009a41139a --- /dev/null +++ b/frontend/src/pages/modelRegistry/screens/ModelVersionDetails/ModelVersionDetails.tsx @@ -0,0 +1,88 @@ +import React from 'react'; +import { useNavigate, useParams } from 'react-router'; +import { Breadcrumb, BreadcrumbItem, Flex, FlexItem } from '@patternfly/react-core'; +import { Link } from 'react-router-dom'; +import ApplicationsPage from '~/pages/ApplicationsPage'; +import useModelVersionById from '~/concepts/modelRegistry/apiHooks/useModelVersionById'; +import { ModelRegistrySelectorContext } from '~/concepts/modelRegistry/context/ModelRegistrySelectorContext'; +import { modelVersionUrl, registeredModelUrl } from '~/pages/modelRegistry/screens/routeUtils'; +import useRegisteredModelById from '~/concepts/modelRegistry/apiHooks/useRegisteredModelById'; +import { ModelVersionDetailsTab } from './const'; +import ModelVersionsDetailsHeaderActions from './ModelVersionDetailsHeaderActions'; +import ModelVersionDetailsTabs from './ModelVersionDetailsTabs'; +import ModelVersionSelector from './ModelVersionSelector'; + +type ModelVersionsDetailProps = { + tab: ModelVersionDetailsTab; +} & Omit< + React.ComponentProps, + 'breadcrumb' | 'title' | 'description' | 'loadError' | 'loaded' | 'provideChildrenPadding' +>; + +const ModelVersionsDetails: React.FC = ({ tab, ...pageProps }) => { + const navigate = useNavigate(); + + const { preferredModelRegistry } = React.useContext(ModelRegistrySelectorContext); + + const { modelVersionId: mvId, registeredModelId: rmId } = useParams(); + const [rm] = useRegisteredModelById(rmId); + const [mv, mvLoaded, mvLoadError] = useModelVersionById(mvId); + + return ( + + ( + + Registered models - {preferredModelRegistry?.metadata.name} + + )} + /> + ( + + {rm?.name} + + )} + /> + {mv?.name} + + } + title={mv?.name} + headerAction={ + mvLoaded && + mv && ( + + + + navigate( + modelVersionUrl(modelVersionId, rmId, preferredModelRegistry?.metadata.name), + ) + } + /> + + + + + + ) + } + description={mv?.description} + loadError={mvLoadError} + loaded={mvLoaded} + provideChildrenPadding + > + {mv !== null && } + + ); +}; + +export default ModelVersionsDetails; diff --git a/frontend/src/pages/modelRegistry/screens/ModelVersionDetails/ModelVersionDetailsHeaderActions.tsx b/frontend/src/pages/modelRegistry/screens/ModelVersionDetails/ModelVersionDetailsHeaderActions.tsx new file mode 100644 index 0000000000..cc3ed325e1 --- /dev/null +++ b/frontend/src/pages/modelRegistry/screens/ModelVersionDetails/ModelVersionDetailsHeaderActions.tsx @@ -0,0 +1,52 @@ +import * as React from 'react'; +import { Dropdown, DropdownList, MenuToggle, DropdownItem } from '@patternfly/react-core'; + +const ModelVersionsDetailsHeaderActions: React.FC = () => { + const [isOpenActionDropdown, setOpenActionDropdown] = React.useState(false); + const tooltipRef = React.useRef(null); + + return ( + setOpenActionDropdown(false)} + onOpenChange={(open) => setOpenActionDropdown(open)} + toggle={(toggleRef) => ( + setOpenActionDropdown(!isOpenActionDropdown)} + isExpanded={isOpenActionDropdown} + aria-label="Model version details action toggle" + data-testid="model-version-details-action-button" + > + Actions + + )} + > + + undefined} + ref={tooltipRef} + isDisabled // TODO This feature is currently disabled but will be enabled in a future PR post-summit release. + > + Deploy + + undefined} + ref={tooltipRef} + isDisabled // TODO This feature is currently disabled but will be enabled in a future PR post-summit release. + > + Archive version + + + + ); +}; + +export default ModelVersionsDetailsHeaderActions; diff --git a/frontend/src/pages/modelRegistry/screens/ModelVersionDetails/ModelVersionDetailsTabs.tsx b/frontend/src/pages/modelRegistry/screens/ModelVersionDetails/ModelVersionDetailsTabs.tsx new file mode 100644 index 0000000000..232095917b --- /dev/null +++ b/frontend/src/pages/modelRegistry/screens/ModelVersionDetails/ModelVersionDetailsTabs.tsx @@ -0,0 +1,46 @@ +import * as React from 'react'; +import { PageSection, Tab, Tabs, TabTitleText } from '@patternfly/react-core'; +import '~/pages/pipelines/global/runs/GlobalPipelineRunsTabs.scss'; +import { ModelVersion } from '~/concepts/modelRegistry/types'; +import { ModelVersionDetailsTabTitle, ModelVersionDetailsTab } from './const'; +import ModelVersionDetailsView from './ModelVersionDetailsView'; + +type ModelVersionDetailTabsProps = { + tab: ModelVersionDetailsTab; + modelVersion: ModelVersion; +}; + +const ModelVersionDetailsTabs: React.FC = ({ + tab, + modelVersion: mv, +}) => ( + + {ModelVersionDetailsTabTitle.DETAILS}} + aria-label="Model versions details tab" + data-testid="model-versions-details-tab" + > + + + + + {ModelVersionDetailsTabTitle.REGISTERED_DEPLOYMENTS}} + aria-label="Registered deployments tab" + data-testid="registered-deployments-tab" + > + + {/* TODO: Fill Model Details Page Component here */} + + + +); + +export default ModelVersionDetailsTabs; diff --git a/frontend/src/pages/modelRegistry/screens/ModelVersionDetails/ModelVersionDetailsView.tsx b/frontend/src/pages/modelRegistry/screens/ModelVersionDetails/ModelVersionDetailsView.tsx new file mode 100644 index 0000000000..565bbed99e --- /dev/null +++ b/frontend/src/pages/modelRegistry/screens/ModelVersionDetails/ModelVersionDetailsView.tsx @@ -0,0 +1,114 @@ +import * as React from 'react'; +import { Button, ClipboardCopy, DescriptionList, Flex, FlexItem } from '@patternfly/react-core'; +import { PlusCircleIcon } from '@patternfly/react-icons'; +import { ModelVersion } from '~/concepts/modelRegistry/types'; +import DashboardDescriptionListGroup from '~/components/DashboardDescriptionListGroup'; +import EditableTextDescriptionListGroup from '~/components/EditableTextDescriptionListGroup'; +import EditableLabelsDescriptionListGroup from '~/components/EditableLabelsDescriptionListGroup'; +import { getLabels } from '~/pages/modelRegistry/screens/utils'; +import ModelTimestamp from '~/pages/modelRegistry/screens/ModelTimestamp'; +import useModelArtifactsByVersionId from '~/concepts/modelRegistry/apiHooks/useModelArtifactsByVersionId'; + +type ModelVersionDetailsViewProps = { + modelVersion: ModelVersion; +}; + +const ModelVersionDetailsView: React.FC = ({ modelVersion: mv }) => { + const [modelArtifact] = useModelArtifactsByVersionId(mv.id); + + return ( + + + + { + // eslint-disable-next-line no-console + console.log('TODO: save description', value); // TODO API patch and refetch + return new Promise((resolve) => { + setTimeout(() => { + resolve(); + }, 2000); + }); + }} + /> + { + // eslint-disable-next-line no-console + console.log('TODO: save labels', editedLabels); // TODO API patch and refetch + return new Promise((resolve) => { + setTimeout(() => { + resolve(); + }, 2000); + }); + }} + /> + } iconPosition="start"> + Add property + + } + isEmpty // TODO + contentWhenEmpty="No properties" + > + TODO properties here + + + + + + + + {mv.id} + + + + + {modelArtifact.items[0]?.uri} + + + + {modelArtifact.items[0]?.modelFormatName} + + {mv.author} + + + + + + + + + + ); +}; +export default ModelVersionDetailsView; diff --git a/frontend/src/pages/modelRegistry/screens/ModelVersionDetails/ModelVersionSelector.tsx b/frontend/src/pages/modelRegistry/screens/ModelVersionDetails/ModelVersionSelector.tsx new file mode 100644 index 0000000000..0f0db24a3b --- /dev/null +++ b/frontend/src/pages/modelRegistry/screens/ModelVersionDetails/ModelVersionSelector.tsx @@ -0,0 +1,108 @@ +import * as React from 'react'; +import { + HelperText, + HelperTextItem, + Menu, + MenuContainer, + MenuContent, + MenuItem, + MenuList, + MenuSearch, + MenuSearchInput, + MenuToggle, + SearchInput, +} from '@patternfly/react-core'; +import useModelVersionsByRegisteredModel from '~/concepts/modelRegistry/apiHooks/useModelVersionsByRegisteredModel'; +import { ModelVersion } from '~/concepts/modelRegistry/types'; + +type ModelVersionSelectorProps = { + rmId?: string; + selection: ModelVersion; + onSelect: (versionId: string) => void; +}; + +const ModelVersionSelector: React.FC = ({ + rmId, + selection, + onSelect, +}) => { + const [isOpen, setOpen] = React.useState(false); + const [input, setInput] = React.useState(''); + + const toggleRef = React.useRef(null); + const menuRef = React.useRef(null); + + const [modelVersions] = useModelVersionsByRegisteredModel(rmId); + + const menuListItems = modelVersions.items + .filter((item) => !input || item.name.toLowerCase().includes(input.toString().toLowerCase())) + .map((mv, index) => ( + + {mv.name} + + )); + + if (input && modelVersions.size === 0) { + menuListItems.push( + + No results found + , + ); + } + + const menu = ( + { + onSelect(itemId as string); + setOpen(false); + }} + data-id="model-version-selector-menu" + ref={menuRef} + isScrollable + activeItemId={selection.id} + > + + + + setInput(value)} + /> + + + + {`Type a name to search your ${modelVersions.size} versions.`} + + + + {menuListItems} + + + ); + + return ( + setOpen(!isOpen)} + isExpanded={isOpen} + isFullWidth + data-testid="model-version-toggle-button" + > + {selection.name} + + } + menu={menu} + menuRef={menuRef} + popperProps={{ maxWidth: 'trigger' }} + onOpenChange={(open) => setOpen(open)} + /> + ); +}; + +export default ModelVersionSelector; diff --git a/frontend/src/pages/modelRegistry/screens/ModelVersionDetails/const.ts b/frontend/src/pages/modelRegistry/screens/ModelVersionDetails/const.ts new file mode 100644 index 0000000000..280d3a3832 --- /dev/null +++ b/frontend/src/pages/modelRegistry/screens/ModelVersionDetails/const.ts @@ -0,0 +1,9 @@ +export enum ModelVersionDetailsTab { + DETAILS = 'details', + REGISTERED_DEPLOYMENTS = 'registered_deployments', +} + +export enum ModelVersionDetailsTabTitle { + DETAILS = 'Details', + REGISTERED_DEPLOYMENTS = 'Registered deployments', +} diff --git a/frontend/src/pages/modelRegistry/screens/ModelVersionsTableRow.tsx b/frontend/src/pages/modelRegistry/screens/ModelVersionsTableRow.tsx index 30bb635c19..8a35711176 100644 --- a/frontend/src/pages/modelRegistry/screens/ModelVersionsTableRow.tsx +++ b/frontend/src/pages/modelRegistry/screens/ModelVersionsTableRow.tsx @@ -1,49 +1,66 @@ import * as React from 'react'; import { ActionsColumn, Td, Tr } from '@patternfly/react-table'; -import { Text, TextVariants, Truncate } from '@patternfly/react-core'; +import { Text, TextVariants, Truncate, FlexItem } from '@patternfly/react-core'; +import { Link } from 'react-router-dom'; import { ModelVersion } from '~/concepts/modelRegistry/types'; +import { ModelRegistrySelectorContext } from '~/concepts/modelRegistry/context/ModelRegistrySelectorContext'; import ModelLabels from './ModelLabels'; import ModelTimestamp from './ModelTimestamp'; +import { modelVersionUrl } from './routeUtils'; type ModelVersionsTableRowProps = { modelVersion: ModelVersion; }; -const ModelVersionsTableRow: React.FC = ({ modelVersion: mv }) => ( - - -
- -
- {mv.description && ( - - - - )} - - - - - {mv.author} - - - - - undefined, - }, - { - title: 'Archive version', - isDisabled: true, // This feature is currently disabled but will be enabled in a future PR post-summit release. - }, - ]} - /> - - -); +const ModelVersionsTableRow: React.FC = ({ modelVersion: mv }) => { + const { preferredModelRegistry } = React.useContext(ModelRegistrySelectorContext); + + return ( + + +
+ + + + + +
+ {mv.description && ( + + + + )} + + + + + {mv.author} + + + + + undefined, + }, + { + title: 'Archive version', + isDisabled: true, // This feature is currently disabled but will be enabled in a future PR post-summit release. + }, + ]} + /> + + + ); +}; export default ModelVersionsTableRow; diff --git a/frontend/src/pages/modelRegistry/screens/RegisteredModelLink.tsx b/frontend/src/pages/modelRegistry/screens/RegisteredModelLink.tsx deleted file mode 100644 index 62a13d51ac..0000000000 --- a/frontend/src/pages/modelRegistry/screens/RegisteredModelLink.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { Truncate } from '@patternfly/react-core'; -import * as React from 'react'; -import { Link } from 'react-router-dom'; -import { RegisteredModel } from '~/concepts/modelRegistry/types'; -import useRegisteredModelUrl from './useRegisteredModelUrl'; - -type RegisteredModelLinkProps = { - registeredModel: RegisteredModel; -}; - -const RegisteredModelLink: React.FC = ({ registeredModel }) => ( - - - -); - -export default RegisteredModelLink; diff --git a/frontend/src/pages/modelRegistry/screens/RegisteredModelTableRow.tsx b/frontend/src/pages/modelRegistry/screens/RegisteredModelTableRow.tsx index ca2de53612..179d53e81d 100644 --- a/frontend/src/pages/modelRegistry/screens/RegisteredModelTableRow.tsx +++ b/frontend/src/pages/modelRegistry/screens/RegisteredModelTableRow.tsx @@ -1,14 +1,14 @@ import * as React from 'react'; -import { useNavigate } from 'react-router-dom'; +import { useNavigate, Link } from 'react-router-dom'; import { ActionsColumn, Td, Tr } from '@patternfly/react-table'; import { FlexItem, Text, TextVariants, Truncate } from '@patternfly/react-core'; import { RegisteredModel } from '~/concepts/modelRegistry/types'; +import { ModelRegistrySelectorContext } from '~/concepts/modelRegistry/context/ModelRegistrySelectorContext'; import RegisteredModelOwner from './RegisteredModelOwner'; -import RegisteredModelLink from './RegisteredModelLink'; import ModelLabels from './ModelLabels'; import ModelTimestamp from './ModelTimestamp'; -import useRegisteredModelUrl from './useRegisteredModelUrl'; import { ModelVersionsTabs } from './const'; +import { registeredModelUrl } from './routeUtils'; type RegisteredModelTableRowProps = { registeredModel: RegisteredModel; @@ -18,13 +18,17 @@ const RegisteredModelTableRow: React.FC = ({ registeredModel: rm, }) => { const navigate = useNavigate(); - const rmUrl = useRegisteredModelUrl(rm); + const { preferredModelRegistry } = React.useContext(ModelRegistrySelectorContext); + const rmUrl = registeredModelUrl(rm.id, preferredModelRegistry?.metadata.name); + return (
- + + +
{rm.description && ( diff --git a/frontend/src/pages/modelRegistry/screens/routeUtils.ts b/frontend/src/pages/modelRegistry/screens/routeUtils.ts new file mode 100644 index 0000000000..bfa9f48870 --- /dev/null +++ b/frontend/src/pages/modelRegistry/screens/routeUtils.ts @@ -0,0 +1,8 @@ +export const registeredModelUrl = (rmId?: string, preferredModelRegistry?: string): string => + `/modelRegistry/${preferredModelRegistry}/registeredModels/${rmId}`; + +export const modelVersionUrl = ( + mvId: string, + rmId?: string, + preferredModelRegistry?: string, +): string => `${registeredModelUrl(rmId, preferredModelRegistry)}/versions/${mvId}`; diff --git a/frontend/src/pages/modelRegistry/screens/useRegisteredModelUrl.ts b/frontend/src/pages/modelRegistry/screens/useRegisteredModelUrl.ts deleted file mode 100644 index 97b2473aa1..0000000000 --- a/frontend/src/pages/modelRegistry/screens/useRegisteredModelUrl.ts +++ /dev/null @@ -1,11 +0,0 @@ -import * as React from 'react'; -import { ModelRegistrySelectorContext } from '~/concepts/modelRegistry/context/ModelRegistrySelectorContext'; -import { RegisteredModel } from '~/concepts/modelRegistry/types'; - -const useRegisteredModelUrl = (rm: RegisteredModel): string => { - const { preferredModelRegistry } = React.useContext(ModelRegistrySelectorContext); - const registeredModelId = rm.id; - return `/modelRegistry/${preferredModelRegistry?.metadata.name}/registeredModels/${registeredModelId}`; -}; - -export default useRegisteredModelUrl;