Skip to content

Web Lab 2: autocomplete in preview file name input#70621

Open
bencodeorg wants to merge 24 commits intostagingfrom
ben/weblab2-autocomplete-preview
Open

Web Lab 2: autocomplete in preview file name input#70621
bencodeorg wants to merge 24 commits intostagingfrom
ben/weblab2-autocomplete-preview

Conversation

@bencodeorg
Copy link
Contributor

@bencodeorg bencodeorg commented Feb 3, 2026

Replaces the free text input in the Web Lab 2 preview panel with one that shows an autocompletes on user input. It re-uses and modifies an existing professional development-focused AutocompleteInput that is very generic. I moved it over to the templates directory (not exactly sure what the right place is, but felt like it shouldn't be in PD if shared).

A couple tricky cases:

  • Hitting enter without an option selected should update the preview with whatever is in the input box at a given time.
  • Hiding the dropdown when you use our "navigation" arrows to switch between pages.
  • Making sure the dropdown doesn't appear when files are edited.
weblab2.autocomplete.mov

Links

Testing story

Tested manually with Web Lab 2 (see video above).

I also tested the one use case I could see of the existing component (used in the location picker at /pd/workshop_dashboard/workshops/new/build_your_own_workshop) and saw no changes in behavior.

Follow-up work

We might want to tweak the styling here a bit (Moshe and I discussed a look where we display both the file name and path in the dropdown in the Slack thread linked above) and/or adjust behavior around whether to allow users to enter file paths that aren't valid, but thought I'd try and get the core functionality merged first.

@bencodeorg bencodeorg requested a review from a team February 3, 2026 20:56
Copy link
Contributor

@molly-moen molly-moen left a comment

Choose a reason for hiding this comment

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

looks good to me!

@@ -0,0 +1,18 @@
import {MultiFileSource, ProjectFile} from '@cdo/apps/lab2/types';

// Returns a list of files matching the given language (by file.language or extension).
Copy link
Contributor

Choose a reason for hiding this comment

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

is this comment correct? It looks like we only check the language field, not the extension.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oops good catch, I removed the extension check. Will update.

const containerRef = useOutsideClick<HTMLDivElement>(reset);

useEffect(() => {
if (!value || value.length < 3) {
Copy link
Contributor

Choose a reason for hiding this comment

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

why do we reset if the value's length is less than 3?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

3 is the magic number that the autocomplete doesn't start giving you options until you hit. It was producing some weird behavior where options would still be visible if you deleted your input below three characters and started typing something else:

if (debouncedValue && debouncedValue.length >= 3) {
const fetchSuggestions = async () => {
try {
setLoading(true);
const suggestedOptions = await fetchOptions(debouncedValue);
setOptions(suggestedOptions);
setActiveIndex(-1);
} catch (error) {
console.error(error);
} finally {
setLoading(false);
}
};
fetchSuggestions();
}
}, [debouncedValue, fetchOptions]);

I'll move 3 into a constant to be shared (we could also configure this via props if we wanted autocomplete to hit faster?)

Before and after video of the updated behavior in this Slack thread if you're curious.

Copy link
Contributor

Choose a reason for hiding this comment

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

thanks! If you could also add a comment explaining this that would be great.

Copy link
Contributor

Choose a reason for hiding this comment

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

It was producing some weird behavior where options would still be visible if you deleted your input below three characters and started typing something else:

Do you mind explaining what the behavior is you noticed? I see that you've implemented searching the substring within the file pathname. When I set the min length to 1 it seems to work as expected.
Did you consider looking for whether the filename begins with the substring in fetchHtmlOptions? Something like...

      // Get the filename (last part after splitting by '/')
      const segments = option.toLowerCase().split('/');
      const filename = segments[segments.length - 1];
      return filename.startsWith(normalizedSearch);

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 "weird behavior" thing was more about what happens if you went under 3 characters, not the number of characters that sets the limit for when we show the dropdown. If you typed more than 3 characters and cleared the input, it would retain the same set of dropdown options until your new query was 3 characters long.

Re: beginning filename/substring, I thought it was a nice feature that it would be searchable by say, folder name? Anyway, I think there are finer points like this that we can iterate on in the implementation here (a couple more in the follow-up section in the description as well).

setPreviewViewMode: (previewViewMode: PreviewViewMode) => void;
onStopPreview: () => void;
isStopEnabled: boolean;
fetchOptions: (value: string) => Promise<string[]>;
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: this variable name isn't super clear to me. Can we name it something to do with file search or something?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep can do!

Copy link
Contributor

@bethanyaconnor bethanyaconnor left a comment

Choose a reason for hiding this comment

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

Glad you could so easily reuse this component!


import styles from './AutocompleteInput.module.scss';

const FETCH_SUGGESTIONS_MIN_LENGTH = 3;
Copy link
Contributor

Choose a reason for hiding this comment

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

Curious how this value was set? And does it change the behavior of current use of AutocompleteInput in PD workshop forms where sessions are used?

Copy link
Contributor

@fisher-alice fisher-alice Feb 4, 2026

Choose a reason for hiding this comment

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

Oh - I see discussion above! Still curious about 2nd part of question.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, there's a video linked in the discussion above showing the behavior change in the PD form (it only has one use).

Copy link
Contributor

Choose a reason for hiding this comment

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

Gotcha - appreciate the check-in with teacher tools team!

Copy link
Contributor

@fisher-alice fisher-alice left a comment

Choose a reason for hiding this comment

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

Just left a couple questions/suggestions. Nice work!

if (key === 'Enter' && onEnter && activeIndex < 0) {
e.preventDefault();
onEnter(value);
reset();
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 noticing that if I don't select an option from dropdown and just press enter, the dropdown options are still displayed. This seems to happen when I press 'Enter' immediately after typing.

Screen.Recording.2026-02-04.at.10.04.59.AM.mov

Maybe add a call to blur to close dropdown and remove focus on enter?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ooh nice catch. We already close the dropdown / remove focus on enter, but it looks like this happens only if you hit enter quickly after finishing typing because there's some logic that debounces refetching the options every 300ms, and the scheduled refetch happens after you hit enter and reopens the dropdown.

I just added a commit that gates showing options on the input being focused -- does that seem reasonable to you? ie, even if we refetch options, we won't show them because of the new gate.

I also took a look at the existing use of this component, and this problem exists there too (and is fixed with this change). So seems like an improvement overall!

Copy link
Contributor

Choose a reason for hiding this comment

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

NIce! thanks for the update!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

oof nvm seeing a problem with that commit, working on an update...

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