Skip to content

Commit

Permalink
🐛 fix(autocomplete): tags not generated for preselected options (#1403)
Browse files Browse the repository at this point in the history
closes jira 1315

---------

Signed-off-by: gitdallas <dallas.nicol@gmail.com>
Co-authored-by: Ian Bolton <ibolton@redhat.com>
  • Loading branch information
gitdallas and ibolton336 authored Sep 27, 2023
1 parent e269b74 commit 84ffaca
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 108 deletions.
50 changes: 22 additions & 28 deletions client/src/app/components/Autocomplete.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,21 +42,13 @@ export const Autocomplete: React.FC<IAutocompleteProps> = ({
}) => {
const [inputValue, setInputValue] = useState(searchString);
const [menuIsOpen, setMenuIsOpen] = useState(false);
const [currentChips, setCurrentChips] = useState<Set<string>>(
new Set(selections)
);
const [hint, setHint] = useState("");
const [menuItems, setMenuItems] = useState<React.ReactElement[]>([]);

/** refs used to detect when clicks occur inside vs outside of the textInputGroup and menu popper */
const menuRef = useRef<HTMLDivElement>(null);
const searchInputRef = useRef<HTMLInputElement>(null);

React.useEffect(() => {
onChange([...currentChips]);
buildMenu();
}, [currentChips]);

React.useEffect(() => {
buildMenu();
}, [options]);
Expand All @@ -67,7 +59,7 @@ export const Autocomplete: React.FC<IAutocompleteProps> = ({
.filter(
(item: string, index: number, arr: string[]) =>
arr.indexOf(item) === index &&
!currentChips.has(item) &&
!selections.includes(item) &&
(!inputValue || item.toLowerCase().includes(inputValue.toLowerCase()))
)
.map((currentValue, index) => (
Expand Down Expand Up @@ -127,33 +119,32 @@ export const Autocomplete: React.FC<IAutocompleteProps> = ({
buildMenu();
};

/** callback for removing a chip from the chip selections */
const deleteChip = (chipToDelete: string) => {
const newChips = new Set(currentChips);
newChips.delete(chipToDelete);
setCurrentChips(newChips);
/** callback for removing a selection */
const deleteSelection = (selectionToDelete: string) => {
onChange(selections.filter((s) => s !== selectionToDelete));
};

/** add the given string as a chip in the chip group and clear the input */
const addChip = (newChipText: string) => {
/** add the given string as a selection */
const addSelection = (newSelectionText: string) => {
if (!allowUserOptions) {
const matchingOption = options.find(
(o) => o.toLowerCase() === (hint || newChipText).toLowerCase()
(o) => o.toLowerCase() === (hint || newSelectionText).toLowerCase()
);
if (!matchingOption) {
console.log({ matchingOption, newSelectionText, options });
if (!matchingOption || selections.includes(matchingOption)) {
return;
}
newChipText = matchingOption;
newSelectionText = matchingOption;
}
setCurrentChips(new Set([...currentChips, newChipText]));
onChange([...selections, newSelectionText]);
setInputValue("");
setMenuIsOpen(false);
};

/** add the current input value as a chip */
/** add the current input value as a selection */
const handleEnter = () => {
if (inputValue.length) {
addChip(inputValue);
addSelection(inputValue);
}
};

Expand Down Expand Up @@ -216,13 +207,13 @@ export const Autocomplete: React.FC<IAutocompleteProps> = ({
closeMenu && setMenuIsOpen(false);
};

/** add the text of the selected item as a new chip */
/** add the text of the selected menu item to the selected items */
const onSelect = (event?: React.MouseEvent<Element, MouseEvent>) => {
if (!event) {
return;
}
const selectedText = (event.target as HTMLElement).innerText;
addChip(selectedText);
addSelection(selectedText);
event.stopPropagation();
focusTextInput(true);
};
Expand Down Expand Up @@ -301,10 +292,13 @@ export const Autocomplete: React.FC<IAutocompleteProps> = ({
</FlexItem>
<FlexItem key="chips">
<Flex spaceItems={{ default: "spaceItemsXs" }}>
{Array.from(currentChips).map((currentChip) => (
<FlexItem key={currentChip}>
<Label color={labelColor} onClose={() => deleteChip(currentChip)}>
{currentChip}
{selections.map((currentSelection) => (
<FlexItem key={currentSelection}>
<Label
color={labelColor}
onClose={() => deleteSelection(currentSelection)}
>
{currentSelection}
</Label>
</FlexItem>
))}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,13 +106,12 @@ export const ApplicationForm: React.FC<ApplicationFormProps> = ({
}
}, []);

const tagOptions =
tags?.map((tag) => {
return {
value: tag.name,
toString: () => tag.name,
};
}) || [];
const tagOptions = new Set(
(tags || []).reduce<string[]>(
(acc, curr) => (!curr.source ? [...acc, curr.name] : acc),
[]
)
);

const getBinaryInitialValue = (
application: Application | null,
Expand Down Expand Up @@ -385,7 +384,7 @@ export const ApplicationForm: React.FC<ApplicationFormProps> = ({
];

const getTagRef = (tagName: string) =>
tags?.find((tag) => tag.name === tagName);
Object.assign({ source: "" }, tags?.find((tag) => tag.name === tagName));

return (
<Form onSubmit={handleSubmit(onSubmit)}>
Expand Down Expand Up @@ -445,78 +444,34 @@ export const ApplicationForm: React.FC<ApplicationFormProps> = ({
name="tags"
label={t("terms.tags")}
fieldId="tags"
renderInput={({ field: { value, name, onChange } }) => (
<Autocomplete
noResultsMessage={t("message.noResultsFoundTitle")}
onChange={(selections) => {
onChange(
selections
.map((sel) => getTagRef(sel))
.filter((sel) => sel !== undefined) as TagRef[]
);
}}
options={tagOptions.map((o) => o.value)}
placeholderText={t("composed.selectMany", {
what: t("terms.tags").toLowerCase(),
})}
searchInputAriaLabel="tags-select-toggle"
selections={
value
.map(
(formTag) =>
tags?.find((tagRef) => tagRef.name === formTag.name)
)
.map((matchingTag) =>
matchingTag ? matchingTag.name : undefined
)
.filter((e) => e !== undefined) as string[]
}
/>
// <SimpleSelect
// maxHeight={DEFAULT_SELECT_MAX_HEIGHT}
// placeholderText={t("composed.selectMany", {
// what: t("terms.tags").toLowerCase(),
// })}
// id="tags-select"
// variant="typeaheadmulti"
// toggleId="tags-select-toggle"
// toggleAriaLabel="tags dropdown toggle"
// aria-label={name}
// value={value
// .map((formTag) =>
// tags?.find((tagRef) => tagRef.name === formTag.name)
// )
// .map((matchingTag) =>
// matchingTag
// ? {
// value: matchingTag.name,
// toString: () => matchingTag.name,
// }
// : undefined
// )
// .filter((e) => e !== undefined)}
// options={tagOptions}
// onChange={(selection) => {
// const selectionWithValue = selection.toString();

// const currentValue = value || [];
// const e = currentValue.find(
// (f) => f.name === selectionWithValue
// );
// if (e) {
// onChange(
// currentValue.filter((f) => f.name !== selectionWithValue)
// );
// } else {
// const tag = getTagRef(selectionWithValue);
// if (currentValue && typeof tag !== "undefined")
// onChange([...currentValue, tag]);
// }
// }}
// onClear={() => onChange([])}
// noResultsFoundText={t("message.noResultsFoundTitle")}
// />
)}
renderInput={({ field: { value, name, onChange } }) => {
const selections = value.reduce<string[]>(
(acc, curr) =>
curr.source === "" && tagOptions.has(curr.name)
? [...acc, curr.name]
: acc,
[]
);

return (
<Autocomplete
noResultsMessage={t("message.noResultsFoundTitle")}
onChange={(selections) => {
onChange(
selections
.map((sel) => getTagRef(sel))
.filter((sel) => sel !== undefined) as TagRef[]
);
}}
options={Array.from(tagOptions)}
placeholderText={t("composed.selectMany", {
what: t("terms.tags").toLowerCase(),
})}
searchInputAriaLabel="tags-select-toggle"
selections={selections}
/>
);
}}
/>
<HookFormPFGroupController
control={control}
Expand Down

0 comments on commit 84ffaca

Please sign in to comment.