Repository: hashicorp/vault
File: ui/app/components/namespace-picker.js (JavaScript)

Code before:
import { service } from '@ember/service';

/**
 * @module NamespacePicker
 * @description component is used to display a dropdown listing all namespaces that the current user has access to.
 *  The user can select a namespace from the dropdown to navigate directly to that namespace.
 *  The "Manage" button directs the user to the namespace management page.
 *  The "Refresh List" button refrehes the list of namespaces in the dropdown.
 *
 * @example
 * <NamespacePicker class="hds-side-nav-hide-when-minimized" />
 */

export default class NamespacePicker extends Component {
  @service namespace;
  @service router;
  @service store;

  // Show/hide refresh & manage namespaces buttons
  @tracked showAfterOptions = false;

  @tracked selected = {};
  @tracked options = [];

  @tracked isSelected = (option) => this.selected?.id === option?.id;
  @tracked selectedNamespace = () => this.selected?.id || '-';

  constructor() {
    super(...arguments);
    this.loadOptions();
  }

  // TODO make private when converting from js to ts
  #matchesPath(option, currentNamespace) {
    // TODO: Revisit. A hardcoded check for "path" & "/path" seems hacky, but it fixes a breaking test:
    //  "Acceptance | Enterprise | namespaces: it shows nested namespaces if you log in with a namespace starting with a /"
    //  My assumption is that namespace shouldn't start with a "/", but is this a HVD thing? or is the test outdated?
    return option?.path === currentNamespace?.path || `/${option?.path}` === currentNamespace?.path;
  }

  // TODO make private when converting from js to ts
  #getSelected(options, currentNamespace) {
    return options.find((option) => this.#matchesPath(option, currentNamespace));
  }

  // TODO make private when converting from js to ts
  #getOptions(namespace) {
    /* Each namespace option has 3 properties: { id, path, and label }
     *   - id: node / namespace name (displayed when the namespace picker is closed)
     *   - path: full namespace path (used to navigate to the namespace)
     *   - label: text displayed inside the namespace picker dropdown (if root, then label = id, else label = path)

Review comment (refactor):
is this just to return the id for the selected namespace? A getter would be more appropriate to use here, if so. Local helper functions are great for passing args that we don't have easy access to in the component file (like if we're iterating in an `{{#each}}` loop)



Code after:
import { service } from '@ember/service';

/**
 * @module NamespacePicker
 * @description component is used to display a dropdown listing all namespaces that the current user has access to.
 *  The user can select a namespace from the dropdown to navigate directly to that namespace.
 *  The "Manage" button directs the user to the namespace management page.
 *  The "Refresh List" button refrehes the list of namespaces in the dropdown.
 *
 * @example
 * <NamespacePicker class="hds-side-nav-hide-when-minimized" />
 */

export default class NamespacePicker extends Component {
  @service namespace;
  @service router;
  @service store;

  // Show/hide refresh & manage namespaces buttons
  @tracked hasListPermissions = false;

  @tracked selected = {};
  @tracked options = [];
  @tracked searchInput = '';

  constructor() {
    super(...arguments);
    this.loadOptions();
  }

  // TODO make private when converting from js to ts
  #matchesPath(option, currentNamespace) {
    // TODO: Revisit. A hardcoded check for "path" & "/path" seems hacky, but it fixes a breaking test:
    //  "Acceptance | Enterprise | namespaces: it shows nested namespaces if you log in with a namespace starting with a /"
    //  My assumption is that namespace shouldn't start with a "/", but is this a HVD thing? or is the test outdated?
    return option?.path === currentNamespace?.path || `/${option?.path}` === currentNamespace?.path;
  }

  // TODO make private when converting from js to ts
  #getSelected(options, currentNamespace) {
    return options.find((option) => this.#matchesPath(option, currentNamespace));
  }

  // TODO make private when converting from js to ts
  #getOptions(namespace) {
    /* Each namespace option has 3 properties: { id, path, and label }
     *   - id: node / namespace name (displayed when the namespace picker is closed)
     *   - path: full namespace path (used to navigate to the namespace)
     *   - label: text displayed inside the namespace picker dropdown (if root, then label = id, else label = path)
     *
     *  Example: