Ghost/ghost/admin/app/components/gh-member-label-input-labs.js
Rishabh 6e3d2bef3a Updated filter UI to show existing filters on page refresh
refs https://github.com/TryGhost/Team/issues/972

If a filter is applied in the new members list then the URL gets updated and the filter dropdown contains the filters that have been created. When refreshing the page while a filter is applied, the URL remains the same, the filter is still applied but the UI in the filter dropdown resets and doesn't show the appropriate filter fields and values.

This change parses the nql filter from URL using `nql-lang` library and rebuilds the filter UI blocks based on current filter in URL. It also ignores any invalid or unexpected filters in the UI.
2021-09-09 15:13:58 +05:30

109 lines
3.2 KiB
JavaScript

import Component from '@glimmer/component';
import {action} from '@ember/object';
import {inject as service} from '@ember/service';
export default class GhMemberLabelInputLabs 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);
}
}