<commit_before><template>
  <div>
    <q-input
      outlined
      dense
      debounce="300"
      v-model="filter"
      placeholder="Search"
      style="max-width: 300px"
      @input="query"
      :loading="loading"
      :error="errorMessage !== null"
      :error-message="errorMessage"
      hint="Discover official and community App Extensions"
      bottom-slots
      ref="searchInput"
    >
      <template v-slot:append>
        <q-icon
          class="cursor-pointer"
          :name="filter !== '' ? 'clear' : 'search'"
          @click="searchIconClick"
        />
      </template>
    </q-input>

    <q-list
      v-if="results.length > 0"
      class="q-mt-md bg-white rounded-borders"
      bordered
      separator
    >
      <q-item
        v-for="item in results"
        :key="item.name"
        clickable
        @click="onPackageClick(item)"
      >
        <q-item-section>
          <q-item-label class="q-gutter-sm">
            <strong>{{ item.extId }}</strong>
            <q-badge>{{ item.version }}</q-badge>
            <q-badge v-if="item.official" color="purple">official</q-badge>
          </q-item-label>
          <q-item-label caption>
            {{ item.description }}
          </q-item-label>
        </q-item-section>
      </q-item>
    </q-list>
  </div>
</template>

<script>
import { openURL } from 'quasar'

export default {
  data () {
    return {
      filter: '',
      errorMessage: null,
      results: [],
      loading: false
    }
  },

  watch: {
    filter (val) {
      if (val === '') {
        this.loading = false
        this.results = []
        this.errorMessage = null
      }
    }
  },

  methods: {
    onPackageClick (item) {
      openURL(item.links.homepage || item.links.repository || item.links.npm)
    },

    searchIconClick () {
      if (this.filter !== '') {
        this.filter = ''
      }
      this.$refs.searchInput.focus()
    },

    query (filter) {
      if (this.xhr !== void 0) {
        this.xhr.abort()
        this.xhr = void 0
      }

      if (filter === '') {
        return
      }

      this.loading = true

      const self = this
      const xhr = new XMLHttpRequest()

      xhr.addEventListener('load', function () {
        self.loading = false
        const json = JSON.parse(this.responseText)

        if (json.code !== void 0 || json.results === void 0) {
          self.errorMessage = 'NPM API service is currently unavailable. Please try again later.'
          return
        }

        if (json.results.length === 0) {
          self.errorMessage = 'Sorry, nothing found. Please refine search terms.'
          return<commit_msg>fix(discovery): Clear array to avoid stale results (#3799)<commit_after><template>
  <div>
    <q-input
      outlined
      dense
      debounce="300"
      v-model="filter"
      placeholder="Search"
      style="max-width: 300px"
      @input="query"
      :loading="loading"
      :error="errorMessage !== null"
      :error-message="errorMessage"
      hint="Discover official and community App Extensions"
      bottom-slots
      ref="searchInput"
    >
      <template v-slot:append>
        <q-icon
          class="cursor-pointer"
          :name="filter !== '' ? 'clear' : 'search'"
          @click="searchIconClick"
        />
      </template>
    </q-input>

    <q-list
      v-if="results.length > 0"
      class="q-mt-md bg-white rounded-borders"
      bordered
      separator
    >
      <q-item
        v-for="item in results"
        :key="item.name"
        clickable
        @click="onPackageClick(item)"
      >
        <q-item-section>
          <q-item-label class="q-gutter-sm">
            <strong>{{ item.extId }}</strong>
            <q-badge>{{ item.version }}</q-badge>
            <q-badge v-if="item.official" color="purple">official</q-badge>
          </q-item-label>
          <q-item-label caption>
            {{ item.description }}
          </q-item-label>
        </q-item-section>
      </q-item>
    </q-list>
  </div>
</template>

<script>
import { openURL } from 'quasar'

export default {
  data () {
    return {
      filter: '',
      errorMessage: null,
      results: [],
      loading: false
    }
  },

  watch: {
    filter (val) {
      if (val === '') {
        this.loading = false
        this.results = []
        this.errorMessage = null
      }
    }
  },

  methods: {
    onPackageClick (item) {
      openURL(item.links.homepage || item.links.repository || item.links.npm)
    },

    searchIconClick () {
      if (this.filter !== '') {
        this.filter = ''
      }
      this.$refs.searchInput.focus()
    },

    query (filter) {
      if (this.xhr !== void 0) {
        this.xhr.abort()
        this.xhr = void 0
      }

      if (filter === '') {
        return
      }

      this.loading = true
      this.results = []

      const self = this
      const xhr = new XMLHttpRequest()

      xhr.addEventListener('load', function () {
        self.loading = false
        const json = JSON.parse(this.responseText)

        if (json.code !== void 0 || json.results === void 0) {
          self.errorMessage = 'NPM API service is currently unavailable. Please try again later.'
          return
        }

        if (json.results.length === 0) {
          self.errorMessage = 'Sorry, nothing found. Please refine search terms.'
          return
{'fraction_non_alphanumeric': 0.14634146341463414, 'fraction_numerical': 0.005213181902811394, 'mean_word_length': 1.735234215885947, 'pattern_counts': {'":': 0, '<': 55, '<?xml version=': 0, '>': 57, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3944309', 'n_tokens_mistral': 1708, 'n_tokens_neox': 1641, 'n_words': 339}