<commit_before>import Component from '@glimmer/component';
import { inject as service } from '@ember/service';
import { computed, get, action } from '@ember/object';
import { alias } from '@ember/object/computed';
import { tracked } from '@glimmer/tracking';
import { sort } from '@ember/object/computed';
import { defineProperty } from '@ember/object';

export default class DataCollectionComponent extends Component {
  @service('filter') filter;
  @service('sort') sort;
  @service('search') searchService;

  @tracked term = '';

  @alias('searchService.searchables') searchableMap;

  get type() {
    return this.args.type;
  }

  get searchMethod() {
    return this.args.searchable || 'exact';
  }

  get searchProperties() {
    return this.args.filters.searchproperties;
  }

  @computed('term', 'args.search')
  get searchTerm() {
    return this.term || this.args.search || '';
  }

  @computed('type', 'searchMethod', 'filtered', 'args.filters')
  get searchable() {
    const searchproperties =
      get(this, 'args.filters.searchproperty.value') || get(this, 'args.filters.searchproperty');
    const Searchable =
      typeof this.searchMethod === 'string'
        ? this.searchableMap[this.searchMethod]
        : this.args.searchable;

    return new Searchable(this.filtered, {
      finders: Object.fromEntries(
        Object.entries(this.searchService.predicate(this.type)).filter(([key, value]) => {
          return typeof searchproperties === 'undefined' ? true : searchproperties.includes(key);
        })
      ),
    });
  }

  @computed('type', 'args.sort')
  get comparator() {
    if (typeof this.args.sort === 'undefined') {
      return [];
    }
    return this.sort.comparator(this.type)(this.args.sort);
  }

  @computed('comparator', 'searched')
  get items() {
    // the ember sort computed accepts either:
    // 1. The name of a property (as a string) returning an array properties to sort by
    // 2. A function to use for sorting
    let comparator = 'comparator';
    if (typeof this.comparator === 'function') {
      comparator = this.comparator;
    }
    defineProperty(this, 'sorted', sort('searched', comparator));
    return this.sorted;
  }

  @computed('searchTerm', 'searchable', 'filtered')
  get searched() {
    if (this.searchTerm === '') {
      return this.filtered;
    }
    return this.searchable.search(this.searchTerm);
  }

  @computed('type', 'content', 'args.filters')
  get filtered() {
    // if we don't filter, return a copy of the content so we end up with what
    // filter will return when filtering ED recordsets
    if (typeof this.args.filters === 'undefined') {
      return this.content.slice();
    }
    const predicate = this.filter.predicate(this.type);
    if (typeof predicate === 'undefined') {
      return this.content.slice();
    }
    const filters = Object.entries(this.args.filters)
      .filter(([key, value]) => Boolean(value))
      .map(([key, value]) => {
        const val = typeof value !== 'string' ? value.value : value;
        return [key, val];
      });
    return this.content.filter(predicate(Object.fromEntries(filters)));
  }

  @computed('args.{items.[],items.content.[]}')
  get content() {
    // TODO: Temporary little hack to ensure we detect DataSource proxy
    // objects but not any other special Ember Proxy object like ember-data
    // things. Remove this once we no longer need the Proxies
    if (this.args.items.dispatchEvent === 'function') {
      return this.args.items.content;
    }
    return this.args.items;
  }

  @action
  search(term) {
    this.term = term;
    return this.items;
  }
}<commit_msg>ui: Check for a non-existent items argument/attribute within DataCollection (#9662)<commit_after>import Component from '@glimmer/component';
import { inject as service } from '@ember/service';
import { computed, get, action } from '@ember/object';
import { alias } from '@ember/object/computed';
import { tracked } from '@glimmer/tracking';
import { sort } from '@ember/object/computed';
import { defineProperty } from '@ember/object';

export default class DataCollectionComponent extends Component {
  @service('filter') filter;
  @service('sort') sort;
  @service('search') searchService;

  @tracked term = '';

  @alias('searchService.searchables') searchableMap;

  get type() {
    return this.args.type;
  }

  get searchMethod() {
    return this.args.searchable || 'exact';
  }

  get searchProperties() {
    return this.args.filters.searchproperties;
  }

  @computed('term', 'args.search')
  get searchTerm() {
    return this.term || this.args.search || '';
  }

  @computed('type', 'searchMethod', 'filtered', 'args.filters')
  get searchable() {
    const searchproperties =
      get(this, 'args.filters.searchproperty.value') || get(this, 'args.filters.searchproperty');
    const Searchable =
      typeof this.searchMethod === 'string'
        ? this.searchableMap[this.searchMethod]
        : this.args.searchable;

    return new Searchable(this.filtered, {
      finders: Object.fromEntries(
        Object.entries(this.searchService.predicate(this.type)).filter(([key, value]) => {
          return typeof searchproperties === 'undefined' ? true : searchproperties.includes(key);
        })
      ),
    });
  }

  @computed('type', 'args.sort')
  get comparator() {
    if (typeof this.args.sort === 'undefined') {
      return [];
    }
    return this.sort.comparator(this.type)(this.args.sort);
  }

  @computed('comparator', 'searched')
  get items() {
    // the ember sort computed accepts either:
    // 1. The name of a property (as a string) returning an array properties to sort by
    // 2. A function to use for sorting
    let comparator = 'comparator';
    if (typeof this.comparator === 'function') {
      comparator = this.comparator;
    }
    defineProperty(this, 'sorted', sort('searched', comparator));
    return this.sorted;
  }

  @computed('searchTerm', 'searchable', 'filtered')
  get searched() {
    if (this.searchTerm === '') {
      return this.filtered;
    }
    return this.searchable.search(this.searchTerm);
  }

  @computed('type', 'content', 'args.filters')
  get filtered() {
    // if we don't filter, return a copy of the content so we end up with what
    // filter will return when filtering ED recordsets
    if (typeof this.args.filters === 'undefined') {
      return this.content.slice();
    }
    const predicate = this.filter.predicate(this.type);
    if (typeof predicate === 'undefined') {
      return this.content.slice();
    }
    const filters = Object.entries(this.args.filters)
      .filter(([key, value]) => Boolean(value))
      .map(([key, value]) => {
        const val = typeof value !== 'string' ? value.value : value;
        return [key, val];
      });
    return this.content.filter(predicate(Object.fromEntries(filters)));
  }

  @computed('args.{items.[],items.content.[]}')
  get content() {
    // TODO: Temporary little hack to ensure we detect DataSource proxy
    // objects but not any other special Ember Proxy object like ember-data
    // things. Remove this once we no longer need the Proxies
    const items = this.args.items || [];
    if (typeof items.dispatchEvent === 'function') {
      return items.content;
    }
    return items;
  }

  @action
  search(term) {
    this.term = term;
    return this.items;
  }
}
{'fraction_non_alphanumeric': 0.1444082519001086, 'fraction_numerical': 0.0010857763300760044, 'mean_word_length': 3.222922636103152, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 9, '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': '6438688', 'n_tokens_mistral': 2208, 'n_tokens_neox': 2153, 'n_words': 573}