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

MR Permissions - Group and Project dropdown issues #3219

Merged

Conversation

YuliaKrimerman
Copy link
Contributor

RHOAIENG-12025

Description

  1. Verify that once you've selected an item in the dropdown, if you then open the dropdown, you can NOW focus the typeahead text field without the need to close the dropdown( it was blocking the user from doing it) - try typing something in the typeahead in addition to the selected option
  2. The Option in the bottom of the dropdown list is now Select and not Create
  3. After you choose an option in the drop down, try deleting it in the typeahead and verify that it's not creating duplicate entries of that field in the dropdown(see screenshot in the issue)

How Has This Been Tested?

Tested on the UI

Test Impact

One test change to update the Create to Select . Also When changing the label to select I didn't change all the variable names of that label so they are still mostly shown as "create ...." in the code and not as select (except at the original line)

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).
  • [x
Screenshot 2024-09-18 at 10 40 12 AM Screenshot 2024-09-18 at 10 40 29 AM ] 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

@@ -88,7 +88,7 @@ const TypeaheadSelect: React.FunctionComponent<TypeaheadSelectProps> = ({
noOptionsFoundMessage = defaultNoOptionsFoundMessage,
isCreatable = false,
isCreateOptionOnTop = false,
createOptionMessage = defaultCreateOptionMessage,
createOptionMessage = defaultSelectOptionMessage,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I didn't propagate the change of this name variable into the code. Let me know if it's needed ( I started but then decided that it will just be a bunch of places instead of just a label change, as we need it on the UI)

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 still call it defaultCreateOptionMessage so we're not disrupting things too much in here, we just need to pass a different value for createOptionMessage where we render this component in RoleBindingPermissionsNameInput.

Copy link

codecov bot commented Sep 18, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 85.49%. Comparing base (b5351a7) to head (186b5df).
Report is 17 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #3219      +/-   ##
==========================================
+ Coverage   85.39%   85.49%   +0.09%     
==========================================
  Files        1277     1280       +3     
  Lines       28082    28229     +147     
  Branches     7487     7558      +71     
==========================================
+ Hits        23980    24133     +153     
+ Misses       4102     4096       -6     
Files with missing lines Coverage Δ
frontend/src/components/TypeaheadSelect.tsx 66.47% <100.00%> (+0.75%) ⬆️
...ts/roleBinding/RoleBindingPermissionsNameInput.tsx 96.29% <100.00%> (+0.14%) ⬆️
...pts/roleBinding/RoleBindingPermissionsTableRow.tsx 89.83% <ø> (ø)

... and 32 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 b5351a7...186b5df. 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.

A few things here @YuliaKrimerman . There's one thing I'd love to get @jeff-phillips-18 's opinion on - and if we can't get that settled within the week we should probably exclude it from this issue and open a followup issue for just that focus bug that isn't a MR blocker.

@@ -69,7 +69,7 @@ export interface TypeaheadSelectProps extends Omit<SelectProps, 'toggle' | 'onSe
}

const defaultNoOptionsFoundMessage = (filter: string) => `No results found for "${filter}"`;
const defaultCreateOptionMessage = (newValue: string) => `Create "${newValue}"`;
const defaultSelectOptionMessage = (newValue: string) => `Select "${newValue}"`;
Copy link
Contributor

Choose a reason for hiding this comment

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

@YuliaKrimerman we need to not change this for all consumers of TypeaheadSelect, only our usage in RoleBindingPermissionsNameInput. Can you please undo this change and instead use the createOptionMessage prop to override it in that usage only?

@@ -88,7 +88,7 @@ const TypeaheadSelect: React.FunctionComponent<TypeaheadSelectProps> = ({
noOptionsFoundMessage = defaultNoOptionsFoundMessage,
isCreatable = false,
isCreateOptionOnTop = false,
createOptionMessage = defaultCreateOptionMessage,
createOptionMessage = defaultSelectOptionMessage,
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 still call it defaultCreateOptionMessage so we're not disrupting things too much in here, we just need to pass a different value for createOptionMessage where we render this component in RoleBindingPermissionsNameInput.

@@ -248,12 +246,17 @@ const TypeaheadSelect: React.FunctionComponent<TypeaheadSelectProps> = ({
};

const onTextInputChange = (_event: React.FormEvent<HTMLInputElement>, value: string) => {
setFilterValue(value || '');
setFilterValue(value);
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm curious if removing this was necessary?

Comment on lines 254 to 259
if (selected && value !== selected.content) {
// Clear the selection when the input value changes
if (onSelect) {
onSelect(undefined, '');
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

This seems possibly undesirable, the selection shouldn't change until the user clicks another option. I assume this was to fix the value being duplicated when there's a selected option that has a space and you type in the input? I wonder if there's another way to fix that.

Copy link
Contributor

Choose a reason for hiding this comment

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

Actually @YuliaKrimerman I think we should remove these lines, I troubleshooted a little and I think maybe the problem is outside this component. If you console.log selectOptions in RoleBindingPermissionsNameInput you'll see that actually when that option gets duplicated it is really being added in the list of options we pass down here. So it's something strange we're doing out there. It's also very strange that it only seems to happen for items that have a space in them.

I think it has something to do with these lines in RoleBindingPermissionsNameInput:

  if (value && !typeAhead.includes(value)) {
    selectOptions.push({ value, content: value });
  }

Ah -- it's because of the namespaceToProjectDisplayName thing we do there. When you select a project that includes spaces, that's a display name like "savitha MR test", which is what ends up in our selectOptions and is selected as our value there. But the typeAhead array is actual project names, like "savitha-mr-test". So the above lines are triggering adding the option to the list because it thinks it's missing.

I think the fix is to change the above line to:

  if (value && !selectOptions.some((option) => option.value === value)) {
    selectOptions.push({ value, content: value });
  }

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Screenshot 2024-09-19 at 2 03 59 PM
This is how it's behaving now when I implement it with the suggested fix. It does that and then after a few seconds it wipes out those funny duplicates and behave normally

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Addressed all other comments and kept the original implementation for this, let me know if it's ok to keep it, or if we want to take out this issue for the future.

Copy link
Contributor

Choose a reason for hiding this comment

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

@YuliaKrimerman with your other change in place to remove the selectOptions.push code, I tried removing the lines you added here (clear the selection when the input value changes) and it seems to behave like I would expect. I'm not seeing the above duplicates. Can you try removing this now and see if it works for you?

Comment on lines 214 to 219
openMenu();
setTimeout(() => {
textInputRef.current?.focus();
}, 100);
} else if (isFiltering) {
closeMenu();
}
setTimeout(() => {
textInputRef.current?.focus();
}, 100);
};
Copy link
Contributor

Choose a reason for hiding this comment

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

This change seems reasonable to me and does fix the focus issue, but I'm curious if @jeff-phillips-18 has an opinion on it since he wrote this code in #3094.

Copy link
Contributor

@jeff-phillips-18 jeff-phillips-18 Sep 19, 2024

Choose a reason for hiding this comment

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

Looking at this, I would say it is ok to remove the timeout, but in the <Select> component below, add parameter:

shouldFocusFirstItemOnOpen={false}

This will keep focus on the input when the user clicks.

Copy link
Contributor

@mturley mturley Sep 19, 2024

Choose a reason for hiding this comment

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

@jeff-phillips-18 what about the removal of the closeMenu() call here? I don't think I'm seeing the menu close when clicking the input anyway, I wonder if that's getting counteracted in the existing code. I don't see a problem with this part of the diff as-is, just wanted to make sure.

@@ -401,6 +403,7 @@ const TypeaheadSelect: React.FunctionComponent<TypeaheadSelectProps> = ({
onSelect={handleSelect}
onOpenChange={(open) => !open && closeMenu()}
toggle={toggle}
shouldFocusFirstItemOnOpen={false}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added as suggested from Jeff

if (value && !typeAhead.includes(value)) {
selectOptions.push({ value, content: value });
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed the code that was adding the current value to selectOptions if it wasn't in typeAhead. This ensures that custom items don't persist in the dropdown.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah fair point, I guess removing this entirely solves that as well

@@ -68,6 +64,18 @@ const RoleBindingPermissionsNameInput: React.FC<RoleBindingPermissionsNameInputP
}
}}
placeholder={placeholderText}
createOptionMessage={(newValue) => `Select "${newValue}"`}
filterFunction={(filterValue, options) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added this filterFunction in order to achieve the requirement It filters the existing options based on the input and adds a new option with the exact input value if no matches are found.

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't see any different behavior here when I try removing this filterFunction. With or without it, I'm actually seeing that if I click the new option that doesn't match any select items, it doesn't remain selected in the dropdown. I think that's because we still need it to be one of the selectOptions passed above for it to show as selected.

I also notice that with this filterFunction in place, if you type text that doesn't even partially match any other options, it gets shown as the sole option without the "Select ___" text. So I think we don't want this filterFunction and we need to fix the issue some other way.

Copy link
Contributor

Choose a reason for hiding this comment

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

@YuliaKrimerman I think I figured it out - Try this. Remove this filterFunction, and above where you removed the other code, add this:

  // If we've selected an option that doesn't exist via isCreatable, include it in the options so it remains selected
  if (!selectOptions.some((option) => option.value === value)) {
    selectOptions.push({ value, content: value });
  }

That ensures that our "newly created" item is in the list once it is selected, but disappears from the list if it is deselected.

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.

Sorry for the roundabout comments, I have a solution for the problem I identified here:

@@ -68,6 +64,18 @@ const RoleBindingPermissionsNameInput: React.FC<RoleBindingPermissionsNameInputP
}
}}
placeholder={placeholderText}
createOptionMessage={(newValue) => `Select "${newValue}"`}
filterFunction={(filterValue, options) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

@YuliaKrimerman I think I figured it out - Try this. Remove this filterFunction, and above where you removed the other code, add this:

  // If we've selected an option that doesn't exist via isCreatable, include it in the options so it remains selected
  if (!selectOptions.some((option) => option.value === value)) {
    selectOptions.push({ value, content: value });
  }

That ensures that our "newly created" item is in the list once it is selected, but disappears from the list if it is deselected.

@YuliaKrimerman
Copy link
Contributor Author

So I ended up removing the stuff you suggested to remove and not adding the code you proposed because it looks like it was creating this pre selected empty field. At the current state everything looks like it's working as desired, let me know what you think
Screenshot 2024-09-20 at 8 49 46 AM
Screenshot 2024-09-20 at 8 50 54 AM

@mturley
Copy link
Contributor

mturley commented Sep 20, 2024

@YuliaKrimerman without the code I proposed, when I type "istio" and click the "Select 'istio'" option, the dropdown appears as if nothing is selected even though the value has updated (the confirm button in the row becomes enabled).

I do notice the issue you pointed out with my suggestion, it's because I forgot to make sure value is defined before pushing it as an option. This should fix it:

  // If we've selected an option that doesn't exist via isCreatable, include it in the options so it remains selected
  if (value && !selectOptions.some((option) => option.value === value)) {
    selectOptions.push({ value, content: value });
  }

@YuliaKrimerman
Copy link
Contributor Author

@mturley Yep, you're right, now it works good. Pushed the latests and ready for re-review

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.

Perfect, thanks @YuliaKrimerman !!

@openshift-ci openshift-ci bot added the lgtm label Sep 20, 2024
Copy link
Contributor

openshift-ci bot commented Sep 20, 2024

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: mturley

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

The pull request process is described 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

@openshift-merge-bot openshift-merge-bot bot merged commit 83472f4 into opendatahub-io:main Sep 20, 2024
6 checks passed
@YuliaKrimerman YuliaKrimerman deleted the RHOAIENG-12025 branch October 10, 2024 19:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants