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
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { collection, clickable, create, property, text } from 'ember-cli-page-object';

const definition = {
scope: '[data-test-vocabulary-filter]',
vocabularies: collection('[data-test-dashboard-selected-vocabulary]', {
title: text('[data-test-title]'),
terms: collection('[data-test-selected-term-tree]', {
title: text(),
toggle: clickable('[data-test-target]'),
isChecked: property('checked', '[data-test-target] input'),
}),
}),
};

export default definition;
export const component = create(definition);
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import FilterCheckbox from 'ilios-common/components/dashboard/filter-checkbox';
import includes from 'ilios-common/helpers/includes';
import { fn } from '@ember/helper';
import FaIcon from 'ilios-common/components/fa-icon';
import SelectedVocabulary from 'ilios-common/components/dashboard/selected-vocabulary';
import CohortCalendarFilter from 'ilios-common/components/dashboard/cohort-calendar-filter';
import TermsCalendarFilter from 'ilios-common/components/dashboard/terms-calendar-filter';

export default class DashboardCalendarFiltersComponent extends Component {
@service dataLoader;
Expand Down Expand Up @@ -93,27 +93,12 @@ export default class DashboardCalendarFiltersComponent extends Component {
{{/if}}
</div>
</div>
<div class="calendar-filter-list vocabularyfilter" data-test-vocabulary-filter>
<h2>
{{t "general.terms"}}
</h2>
<div class="filters">
{{#if this.vocabulariesLoaded}}
<ul>
{{#each this.vocabularies as |vocabulary|}}
<SelectedVocabulary
@selectedTermIds={{@selectedTermIds}}
@vocabulary={{vocabulary}}
@add={{@addTermId}}
@remove={{@removeTermId}}
/>
{{/each}}
</ul>
{{else}}
<FaIcon @icon="spinner" @spin={{true}} />
{{/if}}
</div>
</div>
<TermsCalendarFilter
@addTermId={{@addTermId}}
@removeTermId={{@removeTermId}}
@selectedTermIds={{@selectedTermIds}}
@vocabularies={{this.vocabularies}}
/>
{{else}}
<div
id="calendar-sessiontypefilter"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import Component from '@glimmer/component';
import { cached } from '@glimmer/tracking';
import { TrackedAsyncData } from 'ember-async-data';
import { fn } from '@ember/helper';
import inViewport from 'ember-in-viewport/modifiers/in-viewport';
import sortBy from 'ilios-common/helpers/sort-by';
import SelectedTermTree from 'ilios-common/components/dashboard/selected-term-tree';

Expand All @@ -14,8 +16,22 @@ export default class DashboardSelectedVocabularyComponent extends Component {
return this.topLevelTermsData.isResolved ? this.topLevelTermsData.value : [];
}
<template>
<li data-test-dashboard-selected-vocabulary>
<h3 data-test-title>
<li
{{inViewport
onEnter=(fn @addVocabularyInView @vocabulary.title)
onExit=(fn @removeVocabularyInView @vocabulary.title)
viewportSpy=true
}}
data-test-dashboard-selected-vocabulary
>
<h3
data-test-title
{{inViewport
onEnter=(fn @addTitleInView @vocabulary.title)
onExit=(fn @removeTitleInView @vocabulary.title)
viewportSpy=true
}}
>
{{@vocabulary.title}}
</h3>
{{#each (sortBy "title" this.topLevelTerms) as |term|}}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import { service } from '@ember/service';
import t from 'ember-intl/helpers/t';
import LoadingSpinner from 'ilios-common/components/loading-spinner';
import SelectedVocabulary from 'ilios-common/components/dashboard/selected-vocabulary';

export default class DashboardTermsCalendarFilterComponent extends Component {
@service dataLoader;
@service iliosConfig;

@tracked vocabulariesInView = [];
@tracked titlesInView = [];

@action
addVocabularyInView(vocabulary) {
if (!this.vocabulariesInView.includes(vocabulary)) {
this.vocabulariesInView = [...this.vocabulariesInView, vocabulary];
}
}
@action
removeVocabularyInView(vocabulary) {
this.vocabulariesInView = this.vocabulariesInView.filter(
(theVocabulary) => theVocabulary !== vocabulary,
);
}
@action
addTitleInView(title) {
if (!this.titlesInView.includes(title)) {
this.titlesInView = [...this.titlesInView, title];
}
}
@action
removeTitleInView(title) {
this.titlesInView = this.titlesInView.filter((theTitle) => theTitle !== title);
}

get vocabularyWithoutTitleView() {
const vocabulariesWithNoTitle = this.vocabulariesInView.filter(
(vocabulary) => !this.titlesInView.includes(vocabulary),
);
const expandedVocabulariesWithNoTitle = vocabulariesWithNoTitle.filter((vocabulary) =>
this.vocabulariesInView.includes(vocabulary),
);

if (expandedVocabulariesWithNoTitle.length) {
return expandedVocabulariesWithNoTitle[0];
}

return null;
}
<template>
<div class="calendar-filter-list vocabularyfilter" data-test-vocabulary-filter>
<h2>
{{t "general.terms"}}
{{#if this.vocabularyWithoutTitleView}}
({{this.vocabularyWithoutTitleView}})
{{/if}}
</h2>
<div class="filters">
{{#if @vocabularies}}
<ul>
{{#each @vocabularies as |vocabulary|}}
<SelectedVocabulary
@selectedTermIds={{@selectedTermIds}}
@vocabulary={{vocabulary}}
@add={{@addTermId}}
@remove={{@removeTermId}}
@addVocabularyInView={{this.addVocabularyInView}}
@removeVocabularyInView={{this.removeVocabularyInView}}
@addTitleInView={{this.addTitleInView}}
@removeTitleInView={{this.removeTitleInView}}
/>
{{/each}}
</ul>
{{else}}
<LoadingSpinner />
{{/if}}
</div>
</div>
</template>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from 'ilios-common/components/dashboard/terms-calendar-filter';
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ module('Integration | Component | dashboard/selected-vocabulary', function (hook
@selectedTermIds={{this.selectedTermIds}}
@add={{(noop)}}
@remove={{(noop)}}
@addVocabularyInView={{(noop)}}
@removeVocabularyInView={{(noop)}}
@addTitleInView={{(noop)}}
@removeTitleInView={{(noop)}}
/>
</template>,
);
Expand Down Expand Up @@ -68,6 +72,10 @@ module('Integration | Component | dashboard/selected-vocabulary', function (hook
@selectedTermIds={{(array)}}
@add={{this.add}}
@remove={{(noop)}}
@addVocabularyInView={{(noop)}}
@removeVocabularyInView={{(noop)}}
@addTitleInView={{(noop)}}
@removeTitleInView={{(noop)}}
/>
</template>,
);
Expand All @@ -88,6 +96,10 @@ module('Integration | Component | dashboard/selected-vocabulary', function (hook
@selectedTermIds={{this.selectedTermIds}}
@add={{(noop)}}
@remove={{this.remove}}
@addVocabularyInView={{(noop)}}
@removeVocabularyInView={{(noop)}}
@addTitleInView={{(noop)}}
@removeTitleInView={{(noop)}}
/>
</template>,
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
import { module, test } from 'qunit';
import { setupRenderingTest } from 'test-app/tests/helpers';
import { render } from '@ember/test-helpers';
import { setupMirage } from 'test-app/tests/test-support/mirage';
import { component } from 'ilios-common/page-objects/components/dashboard/terms-calendar-filter';
import { a11yAudit } from 'ember-a11y-testing/test-support';
import TermsCalendarFilter from 'ilios-common/components/dashboard/terms-calendar-filter';
import noop from 'ilios-common/helpers/noop';
import { array } from '@ember/helper';

module('Integration | Component | dashboard/terms-calendar-filter', function (hooks) {
setupRenderingTest(hooks);
setupMirage(hooks);

hooks.beforeEach(async function () {
this.school = this.server.create('school');
this.vocab1 = this.server.create('vocabulary', {
school: this.school,
active: true,
});
const term1 = this.server.create('term', {
vocabulary: this.vocab1,
active: true,
});
const term2 = this.server.create('term', {
vocabulary: this.vocab1,
active: true,
});
this.vocab2 = this.server.create('vocabulary', {
school: this.school,
active: true,
});
const term3 = this.server.create('term', {
vocabulary: this.vocab2,
active: true,
});
const term4 = this.server.create('term', {
vocabulary: this.vocab2,
active: true,
});
this.server.create('course', {
year: 2024,
school: this.school,
terms: [term1, term2],
});
this.server.create('course', {
year: 2025,
school: this.school,
terms: [term3, term4],
});

this.vocabModel1 = await this.owner
.lookup('service:store')
.findRecord('vocabulary', this.vocab1.id);
this.vocabModel2 = await this.owner
.lookup('service:store')
.findRecord('vocabulary', this.vocab2.id);
});

test('it renders and is accessible', async function (assert) {
await render(
<template>
<TermsCalendarFilter
@addTermId={{(noop)}}
@removeTermId={{(noop)}}
@vocabularies={{array this.vocabModel1 this.vocabModel2}}
/>
</template>,
);

assert.strictEqual(component.vocabularies.length, 2, 'vocabulary count is correct');
assert.strictEqual(
component.vocabularies[0].title,
'Vocabulary 1',
'first vocabulary title is correct',
);
assert.strictEqual(
component.vocabularies[1].title,
'Vocabulary 2',
'second vocabulary title is correct',
);

assert.strictEqual(
component.vocabularies[0].terms.length,
2,
'first vocabulary terms count is correct',
);
assert.strictEqual(
component.vocabularies[0].terms[0].title,
'term 0',
'first vocabulary, first term title is correct',
);
assert.strictEqual(
component.vocabularies[0].terms[1].title,
'term 1',
'first vocabulary, second term title is correct',
);

assert.strictEqual(
component.vocabularies[1].terms.length,
2,
'second vocabulary terms count is correct',
);
assert.strictEqual(
component.vocabularies[1].terms[0].title,
'term 2',
'second vocabulary, first term title is correct',
);
assert.strictEqual(
component.vocabularies[1].terms[1].title,
'term 3',
'second vocabulary, second term title is correct',
);

await a11yAudit(this.element);
assert.ok(true, 'no a11y errors found!');
});

test('selected terms are checked', async function (assert) {
await render(
<template>
<TermsCalendarFilter
@selectedTermIds={{array "2" "3"}}
@addTermId={{(noop)}}
@removeTermId={{(noop)}}
@vocabularies={{array this.vocabModel1 this.vocabModel2}}
/>
</template>,
);
assert.strictEqual(component.vocabularies[0].terms.length, 2);

assert.strictEqual(component.vocabularies[0].terms[0].title, 'term 0');
assert.notOk(component.vocabularies[0].terms[0].isChecked);

assert.strictEqual(component.vocabularies[0].terms[1].title, 'term 1');
assert.ok(component.vocabularies[0].terms[1].isChecked);

assert.strictEqual(component.vocabularies[1].terms[0].title, 'term 2');
assert.ok(component.vocabularies[1].terms[0].isChecked);

assert.strictEqual(component.vocabularies[1].terms[1].title, 'term 3');
assert.notOk(component.vocabularies[1].terms[1].isChecked);
});

test('selected terms toggle remove', async function (assert) {
assert.expect(2);
this.set('remove', (id) => {
assert.strictEqual(id, '1');
});
await render(
<template>
<TermsCalendarFilter
@selectedTermIds={{array "1"}}
@addTermId={{(noop)}}
@removeTermId={{this.remove}}
@vocabularies={{array this.vocabModel1 this.vocabModel2}}
/>
</template>,
);
assert.ok(component.vocabularies[0].terms[0].isChecked);
await component.vocabularies[0].terms[0].toggle();
});

test('unselected terms toggle add', async function (assert) {
assert.expect(2);
this.set('add', (id) => {
assert.strictEqual(id, '1');
});
await render(
<template>
<TermsCalendarFilter
@addTermId={{this.add}}
@removeTermId={{(noop)}}
@vocabularies={{array this.vocabModel1 this.vocabModel2}}
/>
</template>,
);
assert.notOk(component.vocabularies[0].terms[0].isChecked);
await component.vocabularies[0].terms[0].toggle();
});
});