Skip to content

[Remove Vuetify from Studio] Replace CountryField VAutocomplete with KDS KMultiSelect - #6293

Open
LightCreator1007 wants to merge 2 commits into
learningequality:unstablefrom
LightCreator1007:replace-countryfield-kmultiselect
Open

LightCreator1007 wants to merge 2 commits into
learningequality:unstablefrom
LightCreator1007:replace-countryfield-kmultiselect

Conversation

@LightCreator1007

Copy link
Copy Markdown
Contributor

Summary

Replaces VAutocomplete in CountryField with KDS KMultiSelect.

  • The props stay the same (value, required, multiple, label, fullWidth), plus disabled, which the community library panel still uses. Values are still English country names; the list shows translated names.
  • required uses invalid/invalidText. Width uses appearanceOverrides.
  • Removed DropdownWrapper, the ::v-deep styles, the search-clearing setTimeout, and the Vuetify props on the four pages that use the field.
  • Screen-reader messages use createMultiSelectMessages (as in Replace LanguageDropdown VAutocomplete with KDS KMultiSelect #6154). Two country strings are added to commonStrings.js.
  • Rewrote countryField.spec.js with VTL. Re-enabled the skipped create.spec.js tests, which also needed a country and source picked, plus small fixes to the test store.

References

Closes #6139.

Reviewer guidance

Screen.Recording.2026-10-06.at.2.05.19.AM.mov

I tested the four flows from the issue in a dev server, with no console errors:

  • Sign up: multi select, required error, and the keyboard-only flow.
  • Storage request: multi select.
  • Community library panel: disabled while loading, full width.
  • Admin users: single select, with location=Kenya in the URL.

pnpm test and pre-commit run --all-files pass.

Notes:

  • KMultiSelect has no borderless style, so on the storage request form the field is now filled, like the KDS text boxes next to it (screenshots below). Is that OK?
  • The issue mentions 4 skipped tests, there were only 2. Both now pass.

AI usage

I used Claude Code to scope the issue against the KMultiSelect docs and source and the earlier migrations. It wrote the implementation and tests, ran Jest and pre-commit, and checked the flows in the browser. I checked the mentioned workflows too, audited the changes to the best fo my abilities.

Render KMultiSelect in CountryField instead of the Vuetify VAutocomplete
inside DropdownWrapper. The value, required, multiple, label and fullWidth
props are unchanged, so the four consumers keep the same English-name
values while the list shows translated country names.

- Validate required through invalid/invalidText once the field is left
- Size the field with appearanceOverrides instead of v-bind() in CSS
- Drop the setTimeout that cleared the search text; KMultiSelect does it
- Build messages with createMultiSelectMessages and add country strings
  to commonStrings
- Remove Vuetify-only props (box, outline, hide-details, menu-props,
  clearable) from Create, RequestForm, UserTable and the community
  library side panel
- Rewrite countryField.spec.js with Vue Testing Library
- Re-enable the skipped create.spec.js tests and fix the store setup and
  form filling they needed to pass

Closes learningequality#6139
@LightCreator1007
LightCreator1007 requested review from a team and leq-bot October 6, 2026 03:36
@learning-equality-bot

Copy link
Copy Markdown
Contributor

👋 Hi @LightCreator1007, thanks for contributing!

For the review process to begin, please verify that the following is satisfied:

  • Contribution is aligned with our contributing guidelines

  • Pull request description has correctly filled AI usage section & follows our AI guidance:

    AI guidance

    State explicitly whether you didn't use or used AI & how.

    If you used it, ensure that the PR is aligned with Using AI as well as our DEEP framework. DEEP asks you:

    • Disclose — Be open about when you've used AI for support.
    • Engage critically — Question what is generated. Review code for correctness and unnecessary complexity.
    • Edit — Review and refine AI output. Remove unnecessary code and verify it still works after your edits.
    • Process sharing — Explain how you used the AI so others can learn.

    Examples of good disclosures:

    "I used Claude Code to implement the component, prompting it to follow the pattern in ComponentX. I reviewed the generated code, removed unnecessary error handling, and verified the tests pass."

    "I brainstormed the approach with Gemini, then had it write failing tests for the feature. After reviewing the tests, I used Claude Code to generate the implementation. I refactored the output to reduce verbosity and ran the full test suite."

📢✨ Before we assign a reviewer:

  • @rtibblesbot will pre-review this pull request. Its comments are generated by an LLM, and should be evaluated accordingly.
  • We'll also invite community pre-review. See the community review guidance for both authors and reviewers.

Also check that issue requirements are satisfied & you ran pre-commit locally.

Pull requests that don't follow the guidelines will be closed.

Reviewer assignment can take up to 2 weeks.

@rtibblesbot

rtibblesbot commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

🟡 Waiting for changes

Last updated: 2026-10-06 03:46 UTC

@rtibblesbot rtibblesbot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

PR #6293: CountryField.vue meets the issue's component requirements. I checked it against the KMultiSelect 5.9.0 source. The remaining findings are test assertions.

CI passes. Manual QA did not run, so the UI is not visually verified.

  • suggestion: the re-enabled submit test doesn't check that the selected country reaches register (inline).
  • suggestion: two countryField.spec.js assertions only check that text is present (inline).
  • nitpick: countrySelectionsClearedLabel duplicates languageSelectionsClearedLabel (inline).
  • Upstream had two skipped tests, not the four the issue counts. Both now run; no change needed.
  • praise: the create.spec.js store now uses the account and policies namespaces that Create.vue binds to. That lets the re-enabled tests reach the register mock.

Written by rtibblesbot, an LLM-based coding agent.

await userEvent.click(screen.getByLabelText(/tagging content sources/i));

await userEvent.type(screen.getByRole('combobox', { name: /select all that apply/i }), 'Kenya');
await userEvent.click(await screen.findByRole('option', { name: 'Kenya' }));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

suggestion: The submit test doesn't check that the selected country reaches register. It only asserts toHaveBeenCalled() (L144). That passes if locations is empty, holds the translated label, or holds an {id, name} object. Pin the payload:

expect(mockRegisterAction).toHaveBeenCalledWith(
  expect.anything(),
  expect.objectContaining({ locations: 'Kenya' }),
);

This also covers the AC "The value sent to the server stays the English name".


await leaveField();

expect(await screen.findByText('Field is required')).toBeInTheDocument();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

suggestion: This assertion doesn't check that the field is marked invalid. It passes whenever the text renders. When invalid is true, KMultiSelect points the combobox's aria-describedby at the error. Assert that wiring:

expect(screen.getByRole('combobox')).toHaveAccessibleDescription('Field is required');


await userEvent.type(screen.getByRole('combobox'), 'zzzzz');

expect(await screen.findByText('No countries found')).toBeInTheDocument();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

suggestion: This assertion can match "No countries found" outside the dropdown. findByText searches the whole page. Scope it within the listbox, or also assert that no option role remains.

message: '{count, plural, one {# country selected} other {# countries selected}}',
context: 'Announced with the number of countries currently selected in a country picker',
},
countrySelectionsClearedLabel: {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nitpick: This string duplicates languageSelectionsClearedLabel. It doesn't name the item type, so translators get the same string twice. Replace both with one selectionsClearedLabel shared by the two pickers.

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.

[Remove Vuetify from Studio] Replace CountryField VAutocomplete with KDS KMultiSelect

2 participants