Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions ghost/admin/app/components/gh-tags-token-input.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,14 @@ export default class GhTagsTokenInput extends Component {

constructor() {
super(...arguments);
this.addInitialTags(this.args.selected?.toArray ? this.args.selected.toArray() : (this.args.selected || []));
const selectedTags = this.args.selected?.toArray ? this.args.selected.toArray() : (this.args.selected || []);
this._initialTags = new TrackedArray(selectedTags);
}

get availableTags() {
const selectedTags = this.args.selected || [];
return this.tagsManager.sortTags(this._initialTags.filter(tag => !selectedTags.includes(tag)));
const selectedTagIds = new Set(selectedTags.map(tag => tag.id));
return this.tagsManager.sortTags(this._initialTags.filter(tag => !selectedTagIds.has(tag.id)));
}

// if we only have one page of tags available or we've already loaded all tags
Expand All @@ -43,15 +45,15 @@ export default class GhTagsTokenInput extends Component {

@action
addInitialTags(tags) {
const selectedTags = this.args.selected || [];
const deduplicatedTags = tags.filter(tag => !selectedTags.includes(tag));
const existingTagIds = new Set(this._initialTags.map(tag => tag.id));
const deduplicatedTags = tags.filter(tag => !existingTagIds.has(tag.id));
this._initialTags.push(...deduplicatedTags);
}

@action
addSearchedTags(tags) {
const selectedTags = this.args.selected || [];
const deduplicatedTags = tags.filter(tag => !selectedTags.includes(tag));
const selectedTagIds = new Set((this.args.selected || []).map(tag => tag.id));
const deduplicatedTags = tags.filter(tag => !selectedTagIds.has(tag.id));
this._searchedTags.push(...deduplicatedTags);
}

Expand Down
35 changes: 35 additions & 0 deletions ghost/admin/tests/integration/components/gh-psm-tags-input-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,28 @@ describe('Integration: Component: gh-psm-tags-input', function () {
expect(options[3]).to.contain.text('Tag 4');
});

it('shows a removed tag in the options list again', async function () {
await assignPostWithTags(this, 'one', 'three');
await render(hbs`<GhPsmTagsInput @post={{post}} />`);
await clickTrigger();
await settled();
await waitUntil(() => findAll('.ember-power-select-option').length >= 2);

let options = findAll('.ember-power-select-option');
expect(options.length).to.equal(2);
expect(options[0]).to.contain.text('#Tag 2');
expect(options[1]).to.contain.text('Tag 4');

// remove the "Tag 1" token then re-open the dropdown
await click('.ember-power-select-multiple-remove-btn');
await clickTrigger();
await settled();

options = findAll('.ember-power-select-option');
expect(options.length).to.equal(3);
expect(options[0]).to.contain.text('Tag 1');
});
Comment thread
9larsons marked this conversation as resolved.

it('uses local search if all tags have been loaded in first page', async function () {
this.set('post', this.store.findRecord('post', 1));
await settled();
Expand Down Expand Up @@ -185,7 +207,20 @@ describe('Integration: Component: gh-psm-tags-input', function () {
});

describe('server-side search', function () {
it('excludes selected tags from search results', async function () {
server.create('tag', {name: 'Alpha', slug: 'alpha'});
server.createList('tag', 150, {name: i => `Search ${i.toString().padStart(3, '0')}`});

await assignPostWithTags(this, 'alpha');
await render(hbs`<GhPsmTagsInput @post={{post}} />`);
await clickTrigger();
await typeInSearch('Alph');
await settled();

let options = findAll('.ember-power-select-option');
expect(options.length).to.equal(1);
expect(options[0]).to.contain.text('Add "Alph"...');
});
});

it('highlights internal tags', async function () {
Expand Down
Loading