diff --git a/app/components/objective-manage-competency.js b/app/components/objective-manage-competency.js index da9d9d2624..844fa55888 100644 --- a/app/components/objective-manage-competency.js +++ b/app/components/objective-manage-competency.js @@ -1,79 +1,97 @@ import Ember from 'ember'; -import DS from 'ember-data'; -const { Component, computed } = Ember; -const { notEmpty, oneWay } = computed; +const { Component, RSVP, computed } = Ember; +const { Promise, all, filter} = RSVP; export default Component.extend({ objective: null, - programYear: oneWay('objective.programYear'), - showCompetencyList: notEmpty('programYear.competencies'), classNames: ['objective-manager', 'objective-manage-competency'], - competencies: computed('programYear.competencies.[]', 'objective.competency', function(){ - if(!this.get('programYear')){ - return []; - } - return DS.PromiseArray.create({ - promise: this.get('programYear.competencies') + schoolCompetencies: computed('programYear.program.school.competencies.[]', function(){ + return new Promise(resolve => { + this.get('programYear').then(programYear => { + programYear.get('program').then(program => { + program.get('school').then(school => { + school.get('competencies').then(competencies => { + resolve(competencies); + }); + }); + }); + }); }); }), - domains: computed('competencies.@each.domain', 'objective.competency', function(){ - var defer = Ember.RSVP.defer(); - var domainContainer = {}; - var domainIds = []; - var promises = []; - let domainProxy = Ember.ObjectProxy.extend({ - selectedCompetency: null, - subCompetencies: [], - selected: computed('subCompetencies.[]', 'selectedCompetency', function(){ - let selectedSubCompetencies = this.get('subCompetencies').filter(competencyProxy => { - return competencyProxy.get('id') === this.get('selectedCompetency.id'); - }); - return selectedSubCompetencies.length > 0; - }), + + programYear: computed('objective.programYears.[]', function(){ + return new Promise(resolve => { + const objective = this.get('objective'); + objective.get('programYears').then(programYears => { + if (programYears.length) { + let programYear = programYears.get('firstObject'); + resolve(programYear); + } else { + resolve(null); + } + }); }); - let competencyProxy = Ember.ObjectProxy.extend({ - selectedCompetency: null, - selected: computed('content', 'selectedCompetency', function(){ - return this.get('content.id') === this.get('selectedCompetency.id'); - }), + }), + + competencies: computed('programYear.competencies.[]', function(){ + return new Promise(resolve => { + this.get('programYear').then(programYear => { + programYear.get('competencies').then(competencies => { + resolve(competencies); + }); + }); }); - this.get('competencies').forEach((competency) =>{ - promises.pushObject(competency.get('domain').then( - domain => { - if(!domainContainer.hasOwnProperty(domain.get('id'))){ - domainIds.pushObject(domain.get('id')); - domainContainer[domain.get('id')] = domainProxy.create({ - content: domain, - selectedCompetency: this.get('objective.competency'), - subCompetencies: [], + }), + + competenciesWithSelectedChildren: computed('schoolCompetencies.[]', 'objective.competency', function(){ + return new Promise(resolve => { + const objective = this.get('objective'); + objective.get('competency').then(selectedCompetency => { + if (selectedCompetency) { + this.get('schoolCompetencies').then(competencies => { + filter(competencies.toArray(), (competency => { + return new Promise(resolve => { + competency.get('treeChildren').then(children => { + let selectedChildren = children.filter(competency => selectedCompetency.get('id') === competency.get('id')); + resolve(selectedChildren.length > 0); + }); + }); + })).then(competenciesWithSelectedChildren => { + resolve(competenciesWithSelectedChildren); }); - } - if(competency.get('id') !== domain.get('id')){ - var subCompetencies = domainContainer[domain.get('id')].get('subCompetencies'); - if(!subCompetencies.contains(competency)){ - subCompetencies.pushObject(competencyProxy.create({ - content: competency, - selectedCompetency: this.get('objective.competency') - })); - subCompetencies.sortBy('title'); - } - } + }); + } else { + resolve([]); } - )); + }); }); - Ember.RSVP.all(promises).then(function(){ - var domains = domainIds.map(function(id){ - return domainContainer[id]; - }).filter( - domain => domain.get('subCompetencies').length > 0 - ).sortBy('title'); - defer.resolve(domains); + }), + + domains: computed('competencies.[]', function(){ + return new Promise(resolve => { + this.get('competencies').then(competencies => { + all(competencies.mapBy('domain')).then(domains => { + resolve(domains.uniq()); + }); + }); }); + }), - return DS.PromiseArray.create({ - promise: defer.promise + domainsWithNoChildren: computed('domains.[]', function(){ + return new Promise(resolve => { + this.get('domains').then(domains => { + filter(domains.toArray(), (competency => { + return new Promise(resolve => { + competency.get('children').then(children => { + resolve(children.length === 0); + }); + }); + })).then(domainsWithNoChildren => { + resolve(domainsWithNoChildren); + }); + }); }); }), actions: { diff --git a/app/components/programyear-competencies.js b/app/components/programyear-competencies.js index 7c25707bb8..92e91f5ada 100644 --- a/app/components/programyear-competencies.js +++ b/app/components/programyear-competencies.js @@ -1,65 +1,115 @@ import Ember from 'ember'; +import { task, timeout } from 'ember-concurrency'; -const { Component, computed } = Ember; +const { Component, RSVP, computed } = Ember; +const { Promise, all, filter } = RSVP; export default Component.extend({ + init(){ + this._super(...arguments); + this.get('loadSelectedCompetencies').perform(); + }, + didUpdateAttrs(){ + this._super(...arguments); + this.get('loadSelectedCompetencies').perform(); + }, programYear: null, + isManaging: null, classNames: ['programyear-competencies'], - isManaging: false, isSaving: false, - bufferCompetencies: [], + selectedCompetencies: [], - showCollapsible: computed('isManaging', 'programYear.competencies.[]', function () { - const isManaging = this.get('isManaging'); - const competencies = this.get('programYear.competencies'); - return !isManaging && competencies.get('length'); - }), + loadSelectedCompetencies: task(function * (){ + const programYear = this.get('programYear'); + if (programYear){ + let selectedCompetencies = yield programYear.get('competencies'); + this.set('selectedCompetencies', selectedCompetencies.toArray()); + } else { + yield timeout(1000); + } + }).restartable(), - actions: { - manage: function(){ - var self = this; - this.get('programYear.competencies').then(function(competencies){ - self.set('bufferCompetencies', competencies.toArray()); - self.set('isManaging', true); + save: task(function * () { + yield timeout(10); + let programYear = this.get('programYear'); + let selectedCompetencies = this.get('selectedCompetencies'); + programYear.set('competencies', selectedCompetencies); + try { + yield programYear.save(); + } finally { + this.get('flashMessages').success('general.savedSuccessfully'); + this.get('setIsManaging')(false); + this.get('expand')(); + } + + }).drop(), + + competencies: computed('programYear.program.school.competencies.[]', function(){ + return new Promise(resolve => { + const programYear = this.get('programYear') + programYear.get('program').then(program => { + program.get('school').then(school => { + school.get('competencies').then(competencies => { + resolve(competencies); + }); + }); }); - }, - save: function(){ - this.set('isSaving', true); - let programYear = this.get('programYear'); - programYear.get('competencies').then(competencies => { - competencies.clear(); - this.get('bufferCompetencies').forEach(competency => { - competency.get('programYears').addObject(programYear); - competencies.addObject(competency); + }); + }), + + domains: computed('competencies.[]', function(){ + return new Promise(resolve => { + this.get('competencies').then(competencies => { + all(competencies.mapBy('domain')).then(domains => { + resolve(domains.uniq()); }); - programYear.save().then(()=> { - this.set('isSaving', false); - this.set('isManaging', false); + }); + }); + }), + + competenciesWithSelectedChildren: computed('competencies.[]', 'selectedCompetencies.[]', function(){ + const selectedCompetencies = this.get('selectedCompetencies'); + return new Promise(resolve => { + this.get('competencies').then(competencies => { + filter(competencies.toArray(), (competency => { + return new Promise(resolve => { + competency.get('treeChildren').then(children => { + let selectedChildren = children.filter(competency => selectedCompetencies.contains(competency)); + resolve(selectedChildren.length > 0); + }); + }); + })).then(competenciesWithSelectedChildren => { + resolve(competenciesWithSelectedChildren); }); }); - }, + }); + }), + + actions: { cancel: function(){ - this.set('bufferCompetencies', []); - this.set('isManaging', false); + this.get('loadSelectedCompetencies').perform(); + this.get('setIsManaging')(false); }, addCompetencyToBuffer: function(competency){ - this.get('bufferCompetencies').addObject(competency); + let selectedCompetencies = this.get('selectedCompetencies').toArray(); + selectedCompetencies.addObject(competency); competency.get('children').then(children => { - this.get('bufferCompetencies').addObjects(children); + selectedCompetencies.addObjects(children.toArray()); }); + this.set('selectedCompetencies', selectedCompetencies); }, removeCompetencyFromBuffer: function(competency){ - this.get('bufferCompetencies').removeObject(competency); + let selectedCompetencies = this.get('selectedCompetencies').toArray(); + selectedCompetencies.removeObject(competency); competency.get('children').then(children => { - children.forEach(child => { - this.get('bufferCompetencies').removeObject(child); - }); + selectedCompetencies.removeObjects(children.toArray()); }); + this.set('selectedCompetencies', selectedCompetencies); }, collapse(){ this.get('programYear.competencies').then(competencies => { if (competencies.get('length')) { - this.attrs.collapse(); + this.get('collapse')(); } }); }, diff --git a/app/components/programyear-competency-manager.js b/app/components/programyear-competency-manager.js deleted file mode 100644 index a81816f128..0000000000 --- a/app/components/programyear-competency-manager.js +++ /dev/null @@ -1,107 +0,0 @@ -import Ember from 'ember'; -import DS from 'ember-data'; - -const { Component, computed } = Ember; - -export default Component.extend({ - filter: '', - availableCompetencies: [], - selectedCompetencies: [], - tagName: 'section', - classNames: ['detail-block'], - filteredCompetencies: computed('availableCompetencies.[]', 'selectedCompetencies.[]', function(){ - return this.get('availableCompetencies').filter( - competency => { - return !this.get('selectedCompetencies').contains(competency); - } - ); - }), - filteredDomains: computed('filteredCompetencies.@each.domain', function(){ - var defer = Ember.RSVP.defer(); - var domainContainer = {}; - var domainIds = []; - var promises = []; - this.get('filteredCompetencies').forEach(function(competency){ - promises.pushObject(competency.get('domain').then( - domain => { - if(!domainContainer.hasOwnProperty(domain.get('id'))){ - domainIds.pushObject(domain.get('id')); - domainContainer[domain.get('id')] = Ember.ObjectProxy.create({ - content: domain, - subCompetencies: [] - }); - } - if(competency.get('id') !== domain.get('id')){ - var subCompetencies = domainContainer[domain.get('id')].get('subCompetencies'); - if(!subCompetencies.contains(competency)){ - subCompetencies.pushObject(competency); - subCompetencies.sortBy('title'); - } - } - } - )); - }); - Ember.RSVP.all(promises).then(function(){ - var domains = domainIds.map(function(id){ - return domainContainer[id]; - }).filter( - domain => domain.get('subCompetencies').length > 0 - ).sortBy('title'); - defer.resolve(domains); - }); - - return DS.PromiseArray.create({ - promise: defer.promise - }); - }), - selectedDomains: computed('selectedCompetencies.@each.domain', function(){ - var defer = Ember.RSVP.defer(); - var domainContainer = {}; - var domainIds = []; - var promises = []; - this.get('selectedCompetencies').forEach(function(competency){ - promises.pushObject(competency.get('domain').then( - domain => { - if(!domainContainer.hasOwnProperty(domain.get('id'))){ - domainIds.pushObject(domain.get('id')); - domainContainer[domain.get('id')] = Ember.ObjectProxy.create({ - content: domain, - subCompetencies: [] - }); - } - if(competency.get('id') !== domain.get('id')){ - var subCompetencies = domainContainer[domain.get('id')].get('subCompetencies'); - if(!subCompetencies.contains(competency)){ - subCompetencies.pushObject(competency); - subCompetencies.sortBy('title'); - } - } - } - )); - }); - Ember.RSVP.all(promises).then(function(){ - var domains = domainIds.map(function(id){ - return domainContainer[id]; - }).sortBy('title'); - defer.resolve(domains); - }); - - return DS.PromiseArray.create({ - promise: defer.promise - }); - }), - actions: { - removeCompetency: function(competency){ - this.sendAction('remove', competency); - }, - removeDomain: function(proxy){ - this.sendAction('remove', proxy.get('content')); - }, - addCompetency: function(competency){ - this.sendAction('add', competency); - }, - addDomain: function(proxy){ - this.sendAction('add', proxy.get('content')); - } - } -}); diff --git a/app/controllers/program-year/index.js b/app/controllers/program-year/index.js index 3dd070c39f..1e87a9088e 100644 --- a/app/controllers/program-year/index.js +++ b/app/controllers/program-year/index.js @@ -5,10 +5,16 @@ const { controller } = inject; const { alias, not } = computed; export default Controller.extend({ - queryParams: ['pyObjectiveDetails', 'pyTaxonomyDetails', 'pyCompetencyDetails'], + queryParams: [ + 'pyObjectiveDetails', + 'pyTaxonomyDetails', + 'pyCompetencyDetails', + 'managePyCompetencies', + ], pyObjectiveDetails: false, pyTaxonomyDetails: false, pyCompetencyDetails: false, + managePyCompetencies: false, programYearController: controller('programYear'), programController: controller('program'), diff --git a/app/models/competency.js b/app/models/competency.js index dd583115de..f305d56dbf 100644 --- a/app/models/competency.js +++ b/app/models/competency.js @@ -1,17 +1,19 @@ import DS from 'ember-data'; import Ember from 'ember'; -const { computed } = Ember; +const { computed, RSVP } = Ember; const { empty, not } = computed; +const { Promise, all } = RSVP; +const { Model, attr, belongsTo, hasMany } = DS; -export default DS.Model.extend({ - title: DS.attr('string'), - school: DS.belongsTo('school', {async: true}), - objectives: DS.hasMany('objective', {async: true}), - parent: DS.belongsTo('competency', {async: true, inverse: 'children'}), - children: DS.hasMany('competency', {async: true, inverse: 'parent'}), - aamcPcrses: DS.hasMany('aamc-pcrs', {async: true}), - programYears: DS.hasMany('program-year', {async: true}), +export default Model.extend({ + title: attr('string'), + school: belongsTo('school', {async: true}), + objectives: hasMany('objective', {async: true}), + parent: belongsTo('competency', {async: true, inverse: 'children'}), + children: hasMany('competency', {async: true, inverse: 'parent'}), + aamcPcrses: hasMany('aamc-pcrs', {async: true}), + programYears: hasMany('program-year', {async: true}), isDomain: empty('parent.content'), isNotDomain: not('isDomain'), domain: computed('parent', 'parent.domain', function(){ @@ -34,4 +36,23 @@ export default DS.Model.extend({ promise: promise }); }), + treeChildren: computed('children.[]', function(){ + return new Promise(resolve => { + let rhett = []; + this.get('children').then(children => { + rhett.pushObjects(children.toArray()); + all(children.mapBy('treeChildren')).then(trees => { + let competencies = trees.reduce(function(array, set){ + return array.pushObjects(set.toArray()); + }, []); + rhett.pushObjects(competencies); + rhett = rhett.uniq().filter(function(item){ + return item != null; + }); + resolve(rhett); + }) + }) + }); + + }) }); diff --git a/app/styles/components/_objectivemanager.scss b/app/styles/components/_objectivemanager.scss index c184221261..5c2efb27a9 100644 --- a/app/styles/components/_objectivemanager.scss +++ b/app/styles/components/_objectivemanager.scss @@ -19,10 +19,11 @@ li { list-style-position: outside; - margin-left: 1.5em; - margin-right: 1.5em; padding: .2em 0 .3em 1.5em; - text-indent: -1.2em; + + ul { + margin-left: 1.5em; + } } } diff --git a/app/styles/newcomponents.scss b/app/styles/newcomponents.scss index 08af097de6..6c4c083f06 100644 --- a/app/styles/newcomponents.scss +++ b/app/styles/newcomponents.scss @@ -37,3 +37,4 @@ @import 'newcomponents/session-copy'; @import 'newcomponents/instructorgroup-header'; @import 'newcomponents/programyear-list'; +@import 'newcomponents/programyear-competencies'; diff --git a/app/styles/newcomponents/programyear-competencies.scss b/app/styles/newcomponents/programyear-competencies.scss new file mode 100644 index 0000000000..9d7368e21d --- /dev/null +++ b/app/styles/newcomponents/programyear-competencies.scss @@ -0,0 +1,35 @@ +.programyear-competencies { + @include detail-container($ilios-orange); + + .title { + @include detail-container-title; + } + + .programyear-competencies-actions { + @include detail-container-actions; + } + + .programyear-competencies-content { + @include detail-container-content; + } + + .competency-list, + .managed-competency-list { + @include ilios-list-tree; + border: 1px solid $input-box-grey; + border-radius: 3px; + margin: 2em; + + li { + font-weight: bold; + } + + ul { + margin-left: 1em; + + li { + font-weight: normal; + } + } + } +} diff --git a/app/templates/components/objective-manage-competency.hbs b/app/templates/components/objective-manage-competency.hbs index 4e37e6b7d9..c5e25123be 100644 --- a/app/templates/components/objective-manage-competency.hbs +++ b/app/templates/components/objective-manage-competency.hbs @@ -1,26 +1,42 @@
{{{objective.title}}}
-{{#if showCompetencyList}} -
- {{#each domains as |domain|}} -
{{domain.title}}
-
+ {{else}}

diff --git a/app/templates/components/programyear-competencies.hbs b/app/templates/components/programyear-competencies.hbs index 9a38549c23..ce2af0e24b 100644 --- a/app/templates/components/programyear-competencies.hbs +++ b/app/templates/components/programyear-competencies.hbs @@ -1,45 +1,87 @@ -

+{{#if isManaging}} +
+ + {{t 'programs.competenciesManageTitle'}} + +
+{{else}} +
+ {{t 'general.competencies'}} ({{get (await programYear.competencies) 'length'}}) +
+{{/if}} +
{{#if isManaging}} -
- - {{t 'programs.competenciesManageTitle'}} - -
+ + {{else}} -
- {{t 'general.competencies'}} ({{programYear.competencies.length}}) -
+ {{/if}} -
- {{#if isManaging}} - - - {{else}} - - {{/if}} -
-
- {{#liquid-if isManaging class="horizontal"}} - {{programyear-competency-manager - availableCompetencies=programYear.program.school.competencies - selectedCompetencies=bufferCompetencies - add='addCompetencyToBuffer' - remove='removeCompetencyFromBuffer' - }} - {{else}} -
    - {{#each programYear.domains as |domain|}} -
  • {{domain.title}} -
      - {{#each domain.subCompetencies as |competency|}} -
    • {{competency.title}}
    • - {{/each}} -
    -
  • - {{/each}} +
+
+ {{#if (and (is-fulfilled programYear.competencies) (is-fulfilled competencies) (not loadSelectedCompetencies.isRunning))}} +
    + {{#if isManaging}} + {{#each (sort-by 'title' (await domains)) as |domain|}} +
  • + {{#if (contains (get domain 'id') (map-by 'id' selectedCompetencies))}} + + + {{domain.title}} + + {{else if (contains domain (await competenciesWithSelectedChildren))}} + + + {{domain.title}} + + {{else}} + + + {{domain.title}} + + {{/if}} +
      + {{#each (sort-by 'title' (await competencies)) as |competency|}} + {{#if (contains competency (await domain.treeChildren))}} +
    • + {{#if (contains (get competency 'id') (map-by 'id' selectedCompetencies))}} + + + {{competency.title}} + + {{else}} + + + {{competency.title}} + + {{/if}} +
    • + {{/if}} + {{/each}} +
    +
  • + {{/each}} + {{else}} + {{#each (sort-by 'title' (await domains)) as |domain|}} + {{#if (or (contains domain.id (map-by 'id' selectedCompetencies)) (contains domain (await competenciesWithSelectedChildren)))}} +
  • + {{domain.title}} +
      + {{#each (sort-by 'title' (await competencies)) as |competency|}} + {{#if (and (contains competency (await domain.treeChildren)) (contains competency.id (map-by 'id' selectedCompetencies)))}} +
    • + {{competency.title}} +
    • + {{/if}} + {{/each}} +
    +
  • + {{/if}} + {{/each}} + {{/if}}
- {{/liquid-if}} -
-
+ {{else}} + {{fa-icon 'spinner' spin=true}} + {{/if}} +
diff --git a/app/templates/components/programyear-competency-manager.hbs b/app/templates/components/programyear-competency-manager.hbs deleted file mode 100644 index 401fa762b1..0000000000 --- a/app/templates/components/programyear-competency-manager.hbs +++ /dev/null @@ -1,36 +0,0 @@ -
-
{{t 'general.selected'}}
- -
- -
-
{{t 'general.available'}}
- -
diff --git a/app/templates/components/programyear-details.hbs b/app/templates/components/programyear-details.hbs index 6506d8b51b..aa6f518871 100644 --- a/app/templates/components/programyear-details.hbs +++ b/app/templates/components/programyear-details.hbs @@ -1,11 +1,13 @@ {{#liquid-if (or (eq programYear.competencies.length 0) pyCompetencyDetails)}} {{programyear-competencies programYear=programYear - collapse=(action this.attrs.setPyCompetencyDetails false) - expand=(action this.attrs.setPyCompetencyDetails true) + isManaging=managePyCompetencies + collapse=(action setPyCompetencyDetails false) + expand=(action setPyCompetencyDetails true) + setIsManaging=(action setManagePyCompetencies) }} {{else}} - {{collapsed-competencies subject=programYear expand=(action this.attrs.setPyCompetencyDetails true)}} + {{collapsed-competencies subject=programYear expand=(action setPyCompetencyDetails true)}} {{/liquid-if}} {{#liquid-if (or (eq programYear.objectives.length 0) pyObjectiveDetails)}} @@ -13,22 +15,22 @@ subject=programYear isProgramYear=true editable=editable - collapse=(action this.attrs.setPyObjectiveDetails false) - expand=(action this.attrs.setPyObjectiveDetails true) + collapse=(action setPyObjectiveDetails false) + expand=(action setPyObjectiveDetails true) }} {{else}} - {{collapsed-objectives subject=programYear editable=editable expand=(action this.attrs.setPyObjectiveDetails true)}} + {{collapsed-objectives subject=programYear editable=editable expand=(action setPyObjectiveDetails true)}} {{/liquid-if}} {{#liquid-if (or (eq programYear.terms.length 0) pyTaxonomyDetails)}} {{detail-taxonomies subject=programYear editable=editable - collapse=(action this.attrs.setPyTaxonomyDetails false) - expand=(action this.attrs.setPyTaxonomyDetails true) + collapse=(action setPyTaxonomyDetails false) + expand=(action setPyTaxonomyDetails true) }} {{else}} - {{collapsed-taxonomies subject=programYear expand=(action this.attrs.setPyTaxonomyDetails true)}} + {{collapsed-taxonomies subject=programYear expand=(action setPyTaxonomyDetails true)}} {{/liquid-if}} {{detail-stewards programYear=programYear}} diff --git a/app/templates/components/programyear-objective-list-item.hbs b/app/templates/components/programyear-objective-list-item.hbs index 4027f4110e..017ac06288 100644 --- a/app/templates/components/programyear-objective-list-item.hbs +++ b/app/templates/components/programyear-objective-list-item.hbs @@ -21,7 +21,9 @@ {{objective.competency.title}} - ({{objective.competency.domain.title}}) + {{#if (not-eq (await objective.competency.id) (await objective.competency.domain.id))}} + ({{objective.competency.domain.title}}) + {{/if}} {{else}} {{/if}} diff --git a/app/templates/program-year/index.hbs b/app/templates/program-year/index.hbs index 6d46646d1c..3579a53c0d 100644 --- a/app/templates/program-year/index.hbs +++ b/app/templates/program-year/index.hbs @@ -5,7 +5,9 @@ pyObjectiveDetails=pyObjectiveDetails pyTaxonomyDetails=pyTaxonomyDetails pyCompetencyDetails=pyCompetencyDetails + managePyCompetencies=managePyCompetencies setPyObjectiveDetails=(action (mut pyObjectiveDetails)) setPyTaxonomyDetails=(action (mut pyTaxonomyDetails)) setPyCompetencyDetails=(action (mut pyCompetencyDetails)) + setManagePyCompetencies=(action (mut managePyCompetencies)) }} diff --git a/tests/acceptance/program/programyear/competencies-test.js b/tests/acceptance/program/programyear/competencies-test.js index 3fe7d653f8..5e71b70cd8 100644 --- a/tests/acceptance/program/programyear/competencies-test.js +++ b/tests/acceptance/program/programyear/competencies-test.js @@ -7,8 +7,8 @@ import startApp from 'ilios/tests/helpers/start-app'; import {b as testgroup} from 'ilios/tests/helpers/test-groups'; import setupAuthentication from 'ilios/tests/helpers/setup-authentication'; -var application; -var url = '/programs/1/programyears/1?pyCompetencyDetails=true'; +let application; +let url = '/programs/1/programyears/1?pyCompetencyDetails=true'; module('Acceptance: Program Year - Competencies' + testgroup, { beforeEach: function() { application = startApp(); @@ -54,33 +54,35 @@ test('list', function(assert) { visit(url); andThen(function() { - var container = find('.programyear-competencies'); - assert.equal(getElementText(find('.detail-title', container)), getText('Competencies (2)')); - var competencies = 'competency 0 competency 1 competency 2'; - assert.equal(getElementText(find('.static-list', container)), getText(competencies)); + let container = find('.programyear-competencies'); + assert.equal(getElementText(find('.title', container)), getText('Competencies (2)')); + let competencies = 'competency 0 competency 1 competency 2'; + assert.equal(getElementText(find('.programyear-competencies-content', container)), getText(competencies)); }); }); test('manager', function(assert) { visit(url); andThen(function() { - var container = find('.programyear-competencies'); - click('.detail-actions button', container).then(function(){ - assert.equal(getElementText(find('.tree-list.selectable', container)), getText('competency3competency4competency5')); - assert.equal(getElementText(find('.tree-list.removable', container)), getText('competency0competency1competency2')); - - click('.tree-list.selectable li:eq(0) ul li:eq(0)', container); - click('.tree-list.removable li:eq(0) ul li:eq(0)', container); - andThen(function(){ - assert.equal(getElementText(find('.tree-list.selectable', container)), getText('competency0competency1competency3competency5')); - assert.equal(getElementText(find('.tree-list.removable', container)), getText('competency0competency2competency3competency4')); - }); + let container = find('.programyear-competencies'); + click('.programyear-competencies-actions button', container).then(function(){ + let checkboxes = find('input[type=checkbox]', container); + assert.equal(checkboxes.length, 6); + assert.ok(checkboxes.eq(0).prop('indeterminate')); + assert.ok(!checkboxes.eq(0).prop('checked')); + assert.ok(checkboxes.eq(1).prop('checked')); + assert.ok(checkboxes.eq(2).prop('checked')); + assert.ok(!checkboxes.eq(3).prop('checked')); + assert.ok(!checkboxes.eq(4).prop('checked')); + assert.ok(!checkboxes.eq(5).prop('checked')); + click('input[type=checkbox]:eq(1)', container); + click('input[type=checkbox]:eq(4)', container); click('.bigadd', container); andThen(function(){ - var competencies = 'competency 0 competency 2 competency 3 competency 4'; - assert.equal(getElementText(find('.static-list', container)), getText(competencies)); + let competencies = 'competency 0 competency 2 competency 3 competency 4'; + assert.equal(getElementText(find('.programyear-competencies-content', container)), getText(competencies)); }); }); }); diff --git a/tests/acceptance/program/programyear/objectives-test.js b/tests/acceptance/program/programyear/objectives-test.js index ebdccb7dbf..db74b6c3d2 100644 --- a/tests/acceptance/program/programyear/objectives-test.js +++ b/tests/acceptance/program/programyear/objectives-test.js @@ -15,8 +15,8 @@ module('Acceptance: Program Year - Objectives' + testgroup, { setupAuthentication(application); server.create('school', { school: 1, - programYears: [1], - competencies: [1,2] + programs: [1], + competencies: [1,2,3,4,5] }); server.create('program', { school: 1, @@ -24,8 +24,8 @@ module('Acceptance: Program Year - Objectives' + testgroup, { }); server.create('programYear', { program: 1, - competencies: [2,3], - objectives: [1,2] + competencies: [2,3,4,5], + objectives: [1,2,3] }); server.create('competency', { school: 1, @@ -42,6 +42,15 @@ module('Acceptance: Program Year - Objectives' + testgroup, { school: 1, programYears: [1], }); + server.create('competency', { + school: 1, + programYears: [1], + objectives: [2] + }); + server.create('competency', { + school: 1, + programYears: [1], + }); server.createList('meshDescriptor', 2, { objectives: [1] }); @@ -52,6 +61,10 @@ module('Acceptance: Program Year - Objectives' + testgroup, { competency: 2, meshDescriptors: [1,2] }); + server.create('objective', { + programYears: [1], + competency: 4 + }); server.create('objective', { programYears: [1] }); @@ -66,14 +79,18 @@ test('list', function(assert) { visit(url); andThen(function() { let objectiveRows = find('.programyear-objective-list tbody tr'); - assert.equal(objectiveRows.length, 2); + assert.equal(objectiveRows.length, 3); assert.equal(getElementText(find('td:eq(0)', objectiveRows.eq(0))), getText('objective 0')); assert.equal(getElementText(find('td:eq(1)', objectiveRows.eq(0))), getText('competency 1 (competency 0)')); assert.equal(getElementText(find('td:eq(2)', objectiveRows.eq(0))), getText('descriptor 0 descriptor 1')); assert.equal(getElementText(find('td:eq(0)', objectiveRows.eq(1))), getText('objective 1')); - assert.equal(getElementText(find('td:eq(1)', objectiveRows.eq(1))), getText('Add New')); + assert.equal(getElementText(find('td:eq(1)', objectiveRows.eq(1))), getText('competency 3')); assert.equal(getElementText(find('td:eq(2)', objectiveRows.eq(1))), getText('Add New')); + + assert.equal(getElementText(find('td:eq(0)', objectiveRows.eq(2))), getText('objective 2')); + assert.equal(getElementText(find('td:eq(1)', objectiveRows.eq(2))), getText('Add New')); + assert.equal(getElementText(find('td:eq(2)', objectiveRows.eq(2))), getText('Add New')); }); }); @@ -188,7 +205,7 @@ test('cancel term changes', function(assert) { }); test('manage competencies', function(assert) { - assert.expect(10); + assert.expect(14); visit(url); andThen(function() { let tds = find('.programyear-objective-list tbody tr:eq(0) td'); @@ -198,18 +215,22 @@ test('manage competencies', function(assert) { assert.equal(getElementText(find('.specific-title')), 'SelectObjectiveCompetency'); let objectiveManager = find('.objective-manage-competency').eq(0); assert.equal(getElementText(find('.objectivetitle', objectiveManager)), getText('objective 0')); - assert.equal(getElementText(find('.parent-picker', objectiveManager)), getText('competency0 competency1 competency2')); - let items = find('.parent-picker li.clickable'); - assert.equal(items.length, 2); - assert.ok(find('.parent-picker h5').hasClass('selected')); + assert.equal(getElementText(find('.parent-picker', objectiveManager)), getText('competency0 competency1 competency2 competency3 competency4')); + let items = find('.parent-picker .clickable'); + assert.equal(items.length, 4); + assert.ok(find('.parent-picker h5:eq(0)').hasClass('selected')); assert.ok($(items[0]).hasClass('selected')); assert.ok(!$(items[1]).hasClass('selected')); + assert.ok(!find('.parent-picker h5:eq(1)').hasClass('selected')); + assert.ok(!find('.parent-picker h5:eq(2)').hasClass('selected')); andThen(function(){ - click('.parent-picker li:eq(1)', objectiveManager).then(function(){ - let items = find('.parent-picker li.clickable'); + click('.parent-picker .clickable:eq(2)', objectiveManager).then(function(){ + let items = find('.parent-picker .clickable'); assert.ok(!$(items[0]).hasClass('selected')); - assert.ok($(items[1]).hasClass('selected')); + assert.ok(!$(items[1]).hasClass('selected')); + assert.ok($(items[2]).hasClass('selected')); + assert.ok(!$(items[3]).hasClass('selected')); }); }); }); @@ -223,7 +244,7 @@ test('save competency', function(assert) { click('.programyear-objective-list tbody tr:eq(0) td:eq(1) .link'); andThen(function() { let objectiveManager = find('.objective-manage-competency').eq(0); - click('.parent-picker li:eq(1)', objectiveManager).then(function(){ + click('.parent-picker .clickable:eq(1)', objectiveManager).then(function(){ click('.detail-objectives button.bigadd'); }); andThen(function(){ @@ -240,7 +261,7 @@ test('save no competency', function(assert) { click('.programyear-objective-list tbody tr:eq(0) td:eq(1) .link'); andThen(function() { let objectiveManager = find('.objective-manage-competency').eq(0); - click('.parent-picker li:eq(0)', objectiveManager).then(function(){ + click('.parent-picker .clickable:eq(0)', objectiveManager).then(function(){ click('.detail-objectives button.bigadd'); }); andThen(function(){ @@ -288,14 +309,14 @@ test('add competency', function(assert) { assert.expect(1); visit(url); andThen(function() { - click('.programyear-objective-list tbody tr:eq(1) td:eq(1) button'); + click('.programyear-objective-list tbody tr:eq(2) td:eq(1) button'); andThen(function() { let objectiveManager = find('.objective-manage-competency').eq(0); - click('.parent-picker li:eq(1)', objectiveManager).then(function(){ + click('.parent-picker .clickable:eq(1)', objectiveManager).then(function(){ click('.detail-objectives button.bigadd'); }); andThen(function(){ - assert.equal(getElementText(find('.programyear-objective-list tbody tr:eq(1) td:eq(1)')), getText('competency 2 (competency 0)')); + assert.equal(getElementText(find('.programyear-objective-list tbody tr:eq(2) td:eq(1)')), getText('competency 2 (competency 0)')); }); }); }); diff --git a/tests/helpers/start-app.js b/tests/helpers/start-app.js index cdba24ee45..1ebec23b8e 100644 --- a/tests/helpers/start-app.js +++ b/tests/helpers/start-app.js @@ -14,7 +14,7 @@ export default function startApp(attrs) { application = Application.create(attributes); application.setupForTesting(); application.injectTestHelpers(); - // QUnit.config.testTimeout = 100000; + QUnit.config.testTimeout = 100000; }); return application; diff --git a/tests/integration/components/programyear-competencies-test.js b/tests/integration/components/programyear-competencies-test.js new file mode 100644 index 0000000000..a2dbd3ba97 --- /dev/null +++ b/tests/integration/components/programyear-competencies-test.js @@ -0,0 +1,104 @@ +import Ember from 'ember'; +import { moduleForComponent, test } from 'ember-qunit'; +import hbs from 'htmlbars-inline-precompile'; + +const { Object, RSVP } = Ember; +const { resolve } = RSVP; + +let school = Object.create({ +}); +let program = Object.create({ + school: resolve(school) +}); +let programYear = Object.create({ + program: resolve(program) +}); +let domain1 = Object.create({ + id: 1, + title: 'domain1', + programYears: resolve([programYear]), +}); +domain1.set('domain', resolve(domain1)); +let competency1 = Object.create({ + id: 2, + domain: resolve(domain1), + title: 'competency1', + children: resolve([]), + programYears: resolve([programYear]), + treeChildren: resolve([]), +}); +let competency2 = Object.create({ + id: 2, + domain: resolve(domain1), + title: 'competency2', + children: resolve([]), + programYears: resolve([programYear]), + treeChildren: resolve([]), +}); +domain1.set('children', resolve([competency1, competency2])); +domain1.set('treeChildren', resolve([competency1, competency2])); +school.set('competencies', resolve([domain1, competency1, competency2])); +programYear.set('competencies', resolve([competency1, competency2])); + + +moduleForComponent('programyear-competencies', 'Integration | Component | programyear competencies', { + integration: true +}); + +test('it renders', function(assert) { + this.set('programYear', programYear); + this.set('nothing', parseInt); + this.render(hbs`{{programyear-competencies + programYear=programYear + isManaging=false + collapse=(action nothing) + expand=(action nothing) + setIsManaging=(action nothing) + }}`); + const title = '.title'; + const button = '.programyear-competencies-actions button'; + const list = '.programyear-competencies-content'; + + assert.equal(this.$(title).text().trim(), 'Competencies (2)'); + assert.equal(this.$(button).text().trim(), 'Manage Competencies'); + assert.equal(this.$(list).text().replace(/[\t\n\s]+/g, ""), 'domain1competency1competency2'); + +}); + +test('clicking manage fires action', function(assert) { + assert.expect(1); + this.set('programYear', programYear); + this.set('nothing', parseInt); + this.set('setIsManaging', (b => { + assert.ok(b === true); + })); + this.render(hbs`{{programyear-competencies + programYear=programYear + isManaging=false + collapse=(action nothing) + expand=(action nothing) + setIsManaging=(action setIsManaging) + }}`); + const button = '.programyear-competencies-actions button'; + + this.$(button).click(); +}); + +test('clicking collapse fires action', function(assert) { + assert.expect(1); + this.set('programYear', programYear); + this.set('nothing', parseInt); + this.set('collapse', (() => { + assert.ok(true); + })); + this.render(hbs`{{programyear-competencies + programYear=programYear + isManaging=false + collapse=(action collapse) + expand=(action nothing) + setIsManaging=(action nothing) + }}`); + const title = '.title'; + + this.$(title).click(); +});