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 a multi-value input component #47804

Open
wants to merge 2 commits into
base: bl-nero/role-editor-4
Choose a base branch
from

Conversation

bl-nero
Copy link
Contributor

@bl-nero bl-nero commented Oct 22, 2024

I created this component to handle sets of long strings that make use of FieldSelectCreate impractical. The first use of it will be the app access section of the role editor, which will need to accommodate Azure identity IDs. These strings are very long and can't be effectively dealt with by FieldSelectCreate, which is our current go-to solution for editing collections of strings.

The design borrows both from existing label editors, but uses the "X" symbol for removing rows to be consistent with the new designs. Further updates will also use the same icon for label removal.

Also pending: making the "add more" buttons smaller across the board in both this and label editor components. This is now kept as is to maintain consistency with other UIs so far.

field-multi-input

This change depends on #47674, but only because it's a part of a bigger PR chain. It's self-contained, so it should be easy to backport.

Followed up by #47803.

@bl-nero bl-nero added no-changelog Indicates that a PR does not require a changelog entry backport/branch/v15 backport/branch/v16 labels Oct 22, 2024
@bl-nero bl-nero marked this pull request as ready for review October 22, 2024 14:23
<Fieldset>
{label && <Legend>{label}</Legend>}
{value.map((val, i) => (
// Note on keys: using index as a key is an anti-pattern in general,
Copy link
Contributor

Choose a reason for hiding this comment

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

// Note on keys: using index as a key is an anti-pattern in general,

TIL 👍

Copy link
Contributor

@avatus avatus left a comment

Choose a reason for hiding this comment

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

Really sick idea! Left a discussion comment but in general its great

Comment on lines +31 to +33
if (value.length === 0) {
value = [''];
}
Copy link
Contributor

Choose a reason for hiding this comment

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

This doesn't seem right. I don't like updating the prop value here directly, especially with an array of length 1. Because arrays are passed by reference, and this is probably provided by some state, this is technically mutating state directly which we shouldn't do in react.

Can we think of another way to do this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It doesn't work this way: if you pass an array by to a function (or set it to a variable), then reassigning to it only changes the local reference, and leaves the original object alone. However, I get it that it may look ugly, so I can just introduce a new variable.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

(What would be a violation of rules would be saying value[0] = ''.)

// synthetically and injected from outside (which would make the API
// difficult to use) or to keep the array with generated IDs as local
// state (which would require us to write a prop/state reconciliation
// procedure whose complexity would probably outweigh the benefits).
Copy link
Contributor

Choose a reason for hiding this comment

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

sure, im convinced.

onClick={() => removeItem(i)}
disabled={disabled}
>
<Icon.Cross size="small" color={theme.colors.text.muted} />
Copy link
Contributor

Choose a reason for hiding this comment

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

Love the cross here instead of trashcan, thank you!

onClick={() => insertItem(value.length)}
>
<Icon.Plus size="small" mr={2} />
Add More
Copy link
Contributor

Choose a reason for hiding this comment

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

Related to my comment about the empty value, perhaps we don't have any input and if length === 0, this says "add field" and then "add more" if greater than 1? Idk, spitballin here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The way I wrote it, I assumed that there's always at least 1 input element, and if it's empty, it simply means an empty array. Therefore there's no case where length === 0. It's an arbitrary decision, I know; it just felt right for the time being, since it's easiest to populate the input (no need to click a button). I know, however, that it leaves an edge case that is unsupported, which is a single empty string. It wasn't really important for the job I was doing at the moment; perhaps if we use this component in more places, we can toggle this behavior with a boolean flag.

Copy link
Contributor

Choose a reason for hiding this comment

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

Fair enough

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backport/branch/v15 backport/branch/v16 no-changelog Indicates that a PR does not require a changelog entry size/md ui
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants