Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add register model page for model catalog #3781

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

ppadti
Copy link
Contributor

@ppadti ppadti commented Feb 20, 2025

Closes: RHOAIENG-19060 and RHOAIENG-20245

Description

This PR aims to add Register model page for model catalog. Also, fixed https://issues.redhat.com/browse/RHOAIENG-20245

  1. Register model button is disabled with popover, when no registry present:
Screenshot 2025-02-20 at 2 03 11 PM
  1. Register model page, when more than one registry present:
Screenshot 2025-02-20 at 2 07 21 PM
  1. Register model flow from model catalog page:
Screen.Recording.2025-02-20.at.2.01.01.PM.mov
  1. You will see this error, if you try to register a model with unavailable model registry:
Screenshot 2025-02-26 at 10 27 58 AM

NOTE:

  1. Now we won't be able to see the model name duplicate error helptext on onChange (but you will see duplicate error name on submit), as we need to consume ModelRegistryConext in modelCatalog - will create a new issue for that.

How Has This Been Tested?

  • Go to the model catalog, click a model, and see that there is a Register button in the top right corner.

  • Verify that the Register button is disabled with a tooltip if there are no model registries the user can access.

  • With model registries available, click the Register button. See that you are taken to a register form that shows the correct model name, prefills the correct URI and if more than one model registries are present you will be able to select it. If you have only one model registry, then the model registry will auto selected and the field will be disabled.

  • Verify that you are able to select a model registry, fill out the form and register a model. Verify that the registered model and version contain all the expected details based on the mockup.

Test Impact

Updated unit and added new cypress tests for register model and model details page.

Request review criteria:

Self checklist (all need to be checked):

  • The developer has manually tested the changes and verified that the changes work
  • Testing instructions have been added in the PR body (for PRs involving changes that are not immediately obvious).
  • The developer has added tests or explained why testing cannot be added (unit or cypress tests for related changes)

If you have UI changes:

  • Included any necessary screenshots or gifs if it was a UI change.
  • Included tags to the UX team if it was a UI/UX change.

After the PR is posted & before it merges:

  • The developer has tested their solution on a cluster by using the image produced by the PR to main

Copy link
Contributor

openshift-ci bot commented Feb 20, 2025

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign manosnoam for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@ppadti
Copy link
Contributor Author

ppadti commented Feb 20, 2025

@yih-wang could you please take a look at the screenshots attached? Also, let me know what do you think about the placeholder text of model registry selector.

Copy link

codecov bot commented Feb 20, 2025

Codecov Report

Attention: Patch coverage is 91.52542% with 10 lines in your changes missing coverage. Please review.

Project coverage is 84.70%. Comparing base (fbca67a) to head (b46964b).

Files with missing lines Patch % Lines
...ages/modelCatalog/screens/RegisterCatalogModel.tsx 87.50% 7 Missing ⚠️
...ns/ModelVersionDetails/ModelVersionDetailsView.tsx 60.00% 2 Missing ⚠️
.../screens/components/DeployRegisteredModelModal.tsx 66.66% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #3781      +/-   ##
==========================================
+ Coverage   84.66%   84.70%   +0.03%     
==========================================
  Files        1517     1519       +2     
  Lines       35134    35231      +97     
  Branches     9836     9872      +36     
==========================================
+ Hits        29747    29843      +96     
- Misses       5387     5388       +1     
Files with missing lines Coverage Δ
frontend/src/api/modelRegistry/custom.ts 100.00% <100.00%> (ø)
frontend/src/concepts/modelRegistry/types.ts 100.00% <ø> (ø)
...c/concepts/modelRegistry/utils/updateTimestamps.ts 100.00% <100.00%> (ø)
...tend/src/pages/modelCatalog/ModelCatalogRoutes.tsx 100.00% <ø> (ø)
frontend/src/pages/modelCatalog/routeUtils.ts 100.00% <100.00%> (ø)
...rc/pages/modelCatalog/screens/ModelDetailsPage.tsx 100.00% <100.00%> (ø)
frontend/src/pages/modelCatalog/utils.ts 100.00% <100.00%> (ø)
...es/modelRegistry/screens/ModelRegistrySelector.tsx 81.39% <100.00%> (+2.82%) ⬆️
...elRegistry/screens/RegisterModel/RegisterModel.tsx 79.41% <ø> (-3.93%) ⬇️
.../RegisterModel/RegisterModelDetailsFormSection.tsx 100.00% <100.00%> (ø)
... and 6 more

... and 6 files with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update fbca67a...b46964b. Read the comment docs.

Copy link
Contributor

@mturley mturley left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @ppadti I'm sorry, I ran out of time to review things for the sprint - I'll get back to this ASAP. You've got some merge conflicts though.

@yih-wang
Copy link

Thanks for the updates @ppadti! Look great!
The only comment is for the model registry selector, which might need an update to both this form and the MR main page -
after consulting @angesDing, the latest ux guidelines of displaying a single option dropdown is not disabling the selector (FYI). So in the video, the field 'Model Registry' should be enabled, and the only option is selected by default.

@ppadti
Copy link
Contributor Author

ppadti commented Feb 24, 2025

Thanks for the updates @ppadti! Look great! The only comment is for the model registry selector, which might need an update to both this form and the MR main page - after consulting @angesDing, the latest ux guidelines of displaying a single option dropdown is not disabling the selector (FYI). So in the video, the field 'Model Registry' should be enabled, and the only option is selected by default.

Thanks @yih-wang for taking a look at the screenshots.
I think for the model registry selector to update to not to disable the dropdown when only one option available - this will require me to update SimpleSelect component - this is used in multiple places, so updating this might impact other components. I think this might be out of scope for this issue. Would it makes sense to create a separate issue to track and handle this? Let me know your thoughts!

@yih-wang
Copy link

@ppadti I see. Yes I agree with you that this shouldn't belong to this issue then. cc @angesDing @simrandhaliw, we might need a consistency issue to address this change as a whole.

@gitdallas
Copy link
Contributor

i'm getting errors when i try to submit the form, is there something i am missing?

you mention we won't be able to see duplicate name error, but that's all i'm seeing:
image

if i use test instead of eder-mr for the form, i get this:
image

also kind of curious why in your recording, the MR looks disabled. i'm able to change it.

@ppadti
Copy link
Contributor Author

ppadti commented Feb 26, 2025

i'm getting errors when i try to submit the form, is there something i am missing?

you mention we won't be able to see duplicate name error, but that's all i'm seeing: image

if i use test instead of eder-mr for the form, i get this: image

also kind of curious why in your recording, the MR looks disabled. i'm able to change it.

Sorry, I think the PR description was not clear enough to test this. Updated the description let me know if you need anything else.

@mturley
Copy link
Contributor

mturley commented Feb 26, 2025

after consulting @angesDing, the latest ux guidelines of displaying a single option dropdown is not disabling the selector (FYI). So in the video, the field 'Model Registry' should be enabled, and the only option is selected by default.

@yih-wang I'm a little surprised to see that guidance - that's how it used to work and it was changed fairly recently (this past November) to the current disabled-single-option behavior (PR by @DaoDaoNoCode , issue). I'll comment in the doc.

Copy link
Contributor

@mturley mturley left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ppadti this is looking awesome! tested and it's working great. just a few tweaks I think we need.

@@ -46,6 +47,8 @@ export const createModelVersionForRegisteredModel =
opts: K8sAPIOptions,
registeredModelId: string,
data: CreateModelVersionData,
customProperties: ModelRegistryCustomProperties,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we rename this to modelCustomProperties? It could be confusing since these are passed when creating the version but they are for the model. I wonder if there's a way we can avoid passing them, to be honest.

Comment on lines 10 to +13
export const bumpModelVersionTimestamp = async (
api: ModelRegistryAPIs,
modelVersionId: string,
customProperties: ModelRegistryCustomProperties,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. @ppadti please don't kill me. Looking more at this I think it's not good for us to have to pass in the customProperties in bumpModelVersionTimestamp and bumpRegisteredModelTimestamp. If they are accidentally passed as {} for some reason or passed the wrong thing (model/version properties mixed up), we'll have a problem.

If it's practical, I think it would be better to refactor both of these utils so that they don't take customProperties or ids, but they take the entire current copy of the object they're updating, and then use the customProperties from it. So we'd have bumpModelVersionTimestamp(api, modelVersion) which uses ...modelVersion.customProperties, bumpRegisteredModelTimestamp(api, registeredModel) which uses ...registeredModel.customProperties, and bumpBothTimestamps(api, modelVersion, registeredModel)`.

That would require making sure everywhere we call all these we have the full model/version object in scope, but I think we do for the most part. The one place I think we don't is inside createModelVersionForRegisteredModel in frontend/src/api/modelRegistry/custom.ts. We only call that in one place though (the registerVersion util in frontend/src/pages/modelRegistry/screens/RegisterModel/utils.ts), and we could either just pass in the whole registeredModel there or lift out the bump so it happens in registerVersion and not in the underlying api util, whichever you think is cleaner.

I think this way we'll save ourselves some potential future headaches and also make the code a bit readable, right now it's not immediately clear why we'd be passing around customProperties like this.

Comment on lines +53 to +55
const [registeredModelName, setRegisteredModelName] = React.useState<string>('');
const [versionName, setVersionName] = React.useState<string>('');
const [errorName, setErrorName] = React.useState<string | undefined>(undefined);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - it's ok not to block this PR on this since I know this is duplicated from the RegisterModel and RegisterVersion pages, but I think this state is a little confusing. I know it exists because when there's an error submitting we need to show the names of the resources that were attempted to be created even if the form has since changed, but with these names it looks like duplicated state that we might try to use expecting it to be the form values. I would love to rename these to something like submittedRegisteredModelName and submittedVersionName, and maybe errorName (and the ErrorName type) should be registrationErrorType or something.

We probably also want to see what we can deduplicate between these 3 pages... that definitely belongs in a followup tech debt issue though.

key,
encodeURIComponent(value).replace(/\./g, '%252E'),
]),
Object.entries(params).map(([key, value]) => [key, encodeURIComponent(value)]),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, this is way better, thanks.

};

const ModelRegistrySelector: React.FC<ModelRegistrySelectorProps> = ({
modelRegistry,
onSelection,
primary,
isCatalogModel,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this prop can just be called isFullWidth, there may be other forms in the future other than catalog where we want to use the ModelRegistrySelector.

@@ -43,6 +44,7 @@ const ModelVersionDetailsView: React.FC<ModelVersionDetailsViewProps> = ({
const modelArtifact = modelArtifacts.items.length ? modelArtifacts.items[0] : null;
const { apiState } = React.useContext(ModelRegistryContext);
const storageFields = uriToStorageFields(modelArtifact?.uri || '');
const [rm] = useRegisteredModelById(mv.registeredModelId);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should pull in loaded, loadError and refresh from this fetch hook and make sure we handle them properly.

We can create composite variables for:

const loaded = modelArtifactsLoaded && registeredModelLoaded;
const loadError = modelArtifactsLoadError || registeredModelLoadError;
const refresh = () => {
  refreshModelArtifacts();
  refreshRegisteredModel();
};

and then use those any place we currently use modelArtifactsLoaded, modelArtifactsLoadError and refreshModelArtifacts here.

Comment on lines +165 to +171
export const isRegisterCatalogModelSubmitDisabled = (
formData: RegisterCatalogModelFormData,
): boolean =>
!formData.modelRegistry ||
!formData.modelName ||
isSubmitDisabledForCommonFields(formData) ||
!isNameValid(formData.modelName);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this form state extends the register model form state, I think this can just be

isRegisterModelSubmitDisabled(formData, []) || !formData.modelRegistry

and then we should add a comment explaining that the [] there is temporary and linking to the future issue for fixing the isModelNameExisting validation on the catalog registration page. Or if you prefer, have a registeredModels param here and pass in [] when calling isRegisterCatalogModelSubmitDisabled, and put the comment there.

@@ -51,6 +52,7 @@ const DeployRegisteredModelModal: React.FC<DeployRegisteredModelModalProps> = ({
const [dataConnections] = useDataConnections(selectedProject?.metadata.name);
const [connections] = useConnections(selectedProject?.metadata.name, true);
const error = platformError || projectError;
const [rm] = useRegisteredModelById(modelVersion.registeredModelId);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same deal here with the loading/error states. We should combine the loading/error here with deployInfoLoaded and deployInfoError below.

@@ -68,12 +70,21 @@ const DeployRegisteredModelModal: React.FC<DeployRegisteredModelModalProps> = ({
modelRegistryApi.api,
modelVersion.id,
modelVersion.registeredModelId,
rm?.customProperties || {},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also (and this applies to everywhere we'll pass in the objects to these bump utils) since they're not optional, we shouldn't fall back to a blank value like this. We can just narrow the type within the scope of calling these utils so we know they're defined, like by wrapping the call in a if (rm). In this case, we can edit the early return a few lines above this (currently if (!modelVersion.registeredModelId)) so it returns early if rm isn't defined.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants