import Component from '@glimmer/component'; import {action} from '@ember/object'; import {inject as service} from '@ember/service'; export default class GhMemberLabelInput extends Component { @service store; get availableLabels() { return this._availableLabels.toArray().sort((labelA, labelB) => { return (labelA.name || '').localeCompare((labelB.name || ''), undefined, {ignorePunctuation: true}); }); } get availableLabelNames() { return this.availableLabels.map(label => label.name.toLowerCase()); } constructor(...args) { super(...args); // perform a background query to fetch all users and set `availableLabels` // to a live-query that will be immediately populated with what's in the // store and be updated when the above query returns this.store.query('label', {limit: 'all'}); this._availableLabels = this.store.peekAll('label'); } get selectedLabels() { if (typeof this.args.labels === 'object') { if (this.args.labels?.length && typeof this.args.labels[0] === 'string') { return this.args.labels.map((d) => { return this.availableLabels.find(label => label.slug === d); }) || []; } return this.args.labels || []; } return []; } willDestroy() { super.willDestroy?.(...arguments); this._availableLabels.forEach((label) => { if (label.get('isNew')) { this.store.deleteRecord(label); } }); } @action hideCreateOptionOnMatchingLabel(term) { return !this.availableLabelNames.includes(term.toLowerCase()); } @action updateLabels(newLabels) { let currentLabels = this.selectedLabels; // destroy new+unsaved labels that are no longer selected currentLabels.forEach(function (label) { if (!newLabels.includes(label) && label.get('isNew')) { label.destroyRecord(); } }); // update labels this.args.onChange(newLabels); } @action editLabel(label, event) { event.stopPropagation(); this.args.onLabelEdit?.(label.slug); } @action createLabel(labelName) { let currentLabels = this.selectedLabels; let currentLabelNames = currentLabels.map(label => label.get('name').toLowerCase()); let labelToAdd; labelName = labelName.trim(); // abort if label is already selected if (currentLabelNames.includes(labelName.toLowerCase())) { return; } // find existing label if there is one labelToAdd = this._findLabelByName(labelName); // create new label if no match if (!labelToAdd) { labelToAdd = this.store.createRecord('label', { name: labelName }); } // push label onto member relationship currentLabels.pushObject(labelToAdd); this.args.onChange(currentLabels); } _findLabelByName(name) { let withMatchingName = function (label) { return label.name.toLowerCase() === name.toLowerCase(); }; return this.availableLabels.find(withMatchingName); } }