From e57ffd43cfaec96eb81d60738b86ca618d342970 Mon Sep 17 00:00:00 2001 From: Stefan Topfstedt Date: Thu, 19 Dec 2024 14:33:20 -0800 Subject: [PATCH 01/11] moves load() task up for easier access while dismantling. --- .../app/components/learner-group/root.js | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/packages/frontend/app/components/learner-group/root.js b/packages/frontend/app/components/learner-group/root.js index 28d2948dc3..9fd1c525e7 100644 --- a/packages/frontend/app/components/learner-group/root.js +++ b/packages/frontend/app/components/learner-group/root.js @@ -39,6 +39,24 @@ export default class LearnerGroupRootComponent extends Component { @tracked totalGroupsToSave = 0; @service iliosConfig; + load = restartableTask(async (element, [learnerGroup]) => { + if (isPresent(learnerGroup)) { + this.location = learnerGroup.location; + this.url = learnerGroup.url; + this.learnerGroupId = learnerGroup.id; + this.learnerGroupTitle = learnerGroup.title; + const cohort = await learnerGroup.cohort; + this.cohortTitle = cohort.title; + const topLevelGroup = await learnerGroup.getTopLevelGroup(); + this.topLevelGroupTitle = topLevelGroup.title; + const allDescendants = await topLevelGroup.getAllDescendants(); + this.treeGroups = [topLevelGroup, ...allDescendants]; + this.usersToPassToManager = await this.createUsersToPassToManager.perform(); + this.usersToPassToCohortManager = await this.createUsersToPassToCohortManager.perform(); + this.courses = await this.getCoursesForGroupWithSubgroupName(null, this.args.learnerGroup); + } + }); + @cached get subGroupsData() { return new TrackedAsyncData(this.args.learnerGroup.children); @@ -67,24 +85,6 @@ export default class LearnerGroupRootComponent extends Component { return this.args.sortUsersBy || 'fullName'; } - load = restartableTask(async (element, [learnerGroup]) => { - if (isPresent(learnerGroup)) { - this.location = learnerGroup.location; - this.url = learnerGroup.url; - this.learnerGroupId = learnerGroup.id; - this.learnerGroupTitle = learnerGroup.title; - const cohort = await learnerGroup.cohort; - this.cohortTitle = cohort.title; - const topLevelGroup = await learnerGroup.getTopLevelGroup(); - this.topLevelGroupTitle = topLevelGroup.title; - const allDescendants = await topLevelGroup.getAllDescendants(); - this.treeGroups = [topLevelGroup, ...allDescendants]; - this.usersToPassToManager = await this.createUsersToPassToManager.perform(); - this.usersToPassToCohortManager = await this.createUsersToPassToCohortManager.perform(); - this.courses = await this.getCoursesForGroupWithSubgroupName(null, this.args.learnerGroup); - } - }); - saveNewLearnerGroup = dropTask(async (title) => { const cohort = await this.args.learnerGroup.cohort; const newLearnerGroup = this.store.createRecord('learner-group', { From fe4e85913f7144d7eb3d733049af1bb8d497ad2f Mon Sep 17 00:00:00 2001 From: Stefan Topfstedt Date: Thu, 19 Dec 2024 16:05:44 -0800 Subject: [PATCH 02/11] extract updatable props that don't need async from load() faction, convert read-only learnerGroupId prop into a getter. --- .../app/components/learner-group/root.js | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/packages/frontend/app/components/learner-group/root.js b/packages/frontend/app/components/learner-group/root.js index 9fd1c525e7..02bf673988 100644 --- a/packages/frontend/app/components/learner-group/root.js +++ b/packages/frontend/app/components/learner-group/root.js @@ -21,7 +21,6 @@ export default class LearnerGroupRootComponent extends Component { @service intl; @service store; @tracked cohortTitle = null; - @tracked learnerGroupId = null; @tracked learnerGroupTitle = null; @tracked location = null; @IsURL() @Length(2, 2000) @tracked url = null; @@ -39,12 +38,15 @@ export default class LearnerGroupRootComponent extends Component { @tracked totalGroupsToSave = 0; @service iliosConfig; + constructor() { + super(...arguments); + this.location = this.args.learnerGroup.location; + this.url = this.args.learnerGroup.url; + this.learnerGroupTitle = this.args.learnerGroup.title; + } + load = restartableTask(async (element, [learnerGroup]) => { if (isPresent(learnerGroup)) { - this.location = learnerGroup.location; - this.url = learnerGroup.url; - this.learnerGroupId = learnerGroup.id; - this.learnerGroupTitle = learnerGroup.title; const cohort = await learnerGroup.cohort; this.cohortTitle = cohort.title; const topLevelGroup = await learnerGroup.getTopLevelGroup(); @@ -57,6 +59,11 @@ export default class LearnerGroupRootComponent extends Component { } }); + @cached + get learnerGroupId() { + return this.args.learnerGroup.id; + } + @cached get subGroupsData() { return new TrackedAsyncData(this.args.learnerGroup.children); From bb5e10f70d68593200317f7910a466a38205e940 Mon Sep 17 00:00:00 2001 From: Stefan Topfstedt Date: Thu, 19 Dec 2024 16:28:26 -0800 Subject: [PATCH 03/11] replaces read-only tracked prop learnerGroupTitle with getter. --- packages/frontend/app/components/learner-group/root.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/frontend/app/components/learner-group/root.js b/packages/frontend/app/components/learner-group/root.js index 02bf673988..e4f1f8e30b 100644 --- a/packages/frontend/app/components/learner-group/root.js +++ b/packages/frontend/app/components/learner-group/root.js @@ -21,7 +21,6 @@ export default class LearnerGroupRootComponent extends Component { @service intl; @service store; @tracked cohortTitle = null; - @tracked learnerGroupTitle = null; @tracked location = null; @IsURL() @Length(2, 2000) @tracked url = null; @tracked topLevelGroupTitle = null; @@ -42,7 +41,6 @@ export default class LearnerGroupRootComponent extends Component { super(...arguments); this.location = this.args.learnerGroup.location; this.url = this.args.learnerGroup.url; - this.learnerGroupTitle = this.args.learnerGroup.title; } load = restartableTask(async (element, [learnerGroup]) => { @@ -64,6 +62,10 @@ export default class LearnerGroupRootComponent extends Component { return this.args.learnerGroup.id; } + get learnerGroupTitle() { + return this.args.learnerGroup.title; + } + @cached get subGroupsData() { return new TrackedAsyncData(this.args.learnerGroup.children); From 735ab44fd139a2589c18e0819b9766ff9f2574cb Mon Sep 17 00:00:00 2001 From: Stefan Topfstedt Date: Thu, 19 Dec 2024 16:34:10 -0800 Subject: [PATCH 04/11] replaces read-only tracked prop learnerGroupTitle with getter. --- .../app/components/learner-group/root.js | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/packages/frontend/app/components/learner-group/root.js b/packages/frontend/app/components/learner-group/root.js index e4f1f8e30b..7ea942aa03 100644 --- a/packages/frontend/app/components/learner-group/root.js +++ b/packages/frontend/app/components/learner-group/root.js @@ -20,7 +20,6 @@ export default class LearnerGroupRootComponent extends Component { @service flashMessages; @service intl; @service store; - @tracked cohortTitle = null; @tracked location = null; @IsURL() @Length(2, 2000) @tracked url = null; @tracked topLevelGroupTitle = null; @@ -45,8 +44,6 @@ export default class LearnerGroupRootComponent extends Component { load = restartableTask(async (element, [learnerGroup]) => { if (isPresent(learnerGroup)) { - const cohort = await learnerGroup.cohort; - this.cohortTitle = cohort.title; const topLevelGroup = await learnerGroup.getTopLevelGroup(); this.topLevelGroupTitle = topLevelGroup.title; const allDescendants = await topLevelGroup.getAllDescendants(); @@ -66,6 +63,19 @@ export default class LearnerGroupRootComponent extends Component { return this.args.learnerGroup.title; } + @cached + get cohortData() { + return new TrackedAsyncData(this.args.learnerGroup.cohort); + } + + get cohort() { + return this.cohortData.isResolved ? this.cohortData.value : null; + } + + get cohortTitle() { + return this.cohort?.title; + } + @cached get subGroupsData() { return new TrackedAsyncData(this.args.learnerGroup.children); From b616740ab61679be15afed94b626ad7e5d5468d0 Mon Sep 17 00:00:00 2001 From: Stefan Topfstedt Date: Thu, 19 Dec 2024 16:39:14 -0800 Subject: [PATCH 05/11] replace read-only tracked prop topLevelGroupTitle with getter. --- .../frontend/app/components/learner-group/root.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/frontend/app/components/learner-group/root.js b/packages/frontend/app/components/learner-group/root.js index 7ea942aa03..79e563dc12 100644 --- a/packages/frontend/app/components/learner-group/root.js +++ b/packages/frontend/app/components/learner-group/root.js @@ -22,7 +22,6 @@ export default class LearnerGroupRootComponent extends Component { @service store; @tracked location = null; @IsURL() @Length(2, 2000) @tracked url = null; - @tracked topLevelGroupTitle = null; @tracked showLearnerGroupCalendar = false; @tracked courses = []; @tracked treeGroups = []; @@ -45,7 +44,6 @@ export default class LearnerGroupRootComponent extends Component { load = restartableTask(async (element, [learnerGroup]) => { if (isPresent(learnerGroup)) { const topLevelGroup = await learnerGroup.getTopLevelGroup(); - this.topLevelGroupTitle = topLevelGroup.title; const allDescendants = await topLevelGroup.getAllDescendants(); this.treeGroups = [topLevelGroup, ...allDescendants]; this.usersToPassToManager = await this.createUsersToPassToManager.perform(); @@ -76,6 +74,19 @@ export default class LearnerGroupRootComponent extends Component { return this.cohort?.title; } + @cached + get topLevelGroupData() { + return new TrackedAsyncData(this.args.learnerGroup.getTopLevelGroup()); + } + + get topLevelGroup() { + return this.topLevelGroupData.isResolved ? this.topLevelGroupData.value : null; + } + + get topLevelGroupTitle() { + return this.topLevelGroup?.title; + } + @cached get subGroupsData() { return new TrackedAsyncData(this.args.learnerGroup.children); From 78bb978aca8727d2fdfe3e16e2d6aa4d398d4b3a Mon Sep 17 00:00:00 2001 From: Stefan Topfstedt Date: Thu, 19 Dec 2024 16:45:45 -0800 Subject: [PATCH 06/11] replace read-only tracked prop treeGroups with local variable in the only place where it is actually used.. --- packages/frontend/app/components/learner-group/root.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/frontend/app/components/learner-group/root.js b/packages/frontend/app/components/learner-group/root.js index 79e563dc12..9616eeb19f 100644 --- a/packages/frontend/app/components/learner-group/root.js +++ b/packages/frontend/app/components/learner-group/root.js @@ -24,7 +24,6 @@ export default class LearnerGroupRootComponent extends Component { @IsURL() @Length(2, 2000) @tracked url = null; @tracked showLearnerGroupCalendar = false; @tracked courses = []; - @tracked treeGroups = []; @tracked usersToPassToManager = []; @tracked usersToPassToCohortManager = []; @tracked sortGroupsBy = 'title'; @@ -43,9 +42,6 @@ export default class LearnerGroupRootComponent extends Component { load = restartableTask(async (element, [learnerGroup]) => { if (isPresent(learnerGroup)) { - const topLevelGroup = await learnerGroup.getTopLevelGroup(); - const allDescendants = await topLevelGroup.getAllDescendants(); - this.treeGroups = [topLevelGroup, ...allDescendants]; this.usersToPassToManager = await this.createUsersToPassToManager.perform(); this.usersToPassToCohortManager = await this.createUsersToPassToCohortManager.perform(); this.courses = await this.getCoursesForGroupWithSubgroupName(null, this.args.learnerGroup); @@ -275,14 +271,16 @@ export default class LearnerGroupRootComponent extends Component { createUsersToPassToManager = task(async () => { let users; + const topLevelGroup = await this.args.learnerGroup.getTopLevelGroup(); + const allDescendants = await topLevelGroup.getAllDescendants(); + const treeGroups = [topLevelGroup, ...allDescendants]; if (this.args.isEditing) { - const topLevelGroup = await this.args.learnerGroup.getTopLevelGroup(); users = await topLevelGroup.getAllDescendantUsers(); } else { users = await this.args.learnerGroup.getUsersOnlyAtThisLevel(); } return await map(users, async (user) => { - const lowestGroupInTree = await user.getLowestMemberGroupInALearnerGroupTree(this.treeGroups); + const lowestGroupInTree = await user.getLowestMemberGroupInALearnerGroupTree(treeGroups); return ObjectProxy.create({ content: user, lowestGroupInTree, From 528ecd94d9b45a45e33fbc43c277b0af67f0f16c Mon Sep 17 00:00:00 2001 From: Stefan Topfstedt Date: Thu, 19 Dec 2024 17:00:52 -0800 Subject: [PATCH 07/11] replaces read-only tracked prop courses with getter. --- .../frontend/app/components/learner-group/root.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/frontend/app/components/learner-group/root.js b/packages/frontend/app/components/learner-group/root.js index 9616eeb19f..0494499fc5 100644 --- a/packages/frontend/app/components/learner-group/root.js +++ b/packages/frontend/app/components/learner-group/root.js @@ -23,7 +23,6 @@ export default class LearnerGroupRootComponent extends Component { @tracked location = null; @IsURL() @Length(2, 2000) @tracked url = null; @tracked showLearnerGroupCalendar = false; - @tracked courses = []; @tracked usersToPassToManager = []; @tracked usersToPassToCohortManager = []; @tracked sortGroupsBy = 'title'; @@ -44,7 +43,6 @@ export default class LearnerGroupRootComponent extends Component { if (isPresent(learnerGroup)) { this.usersToPassToManager = await this.createUsersToPassToManager.perform(); this.usersToPassToCohortManager = await this.createUsersToPassToCohortManager.perform(); - this.courses = await this.getCoursesForGroupWithSubgroupName(null, this.args.learnerGroup); } }); @@ -57,6 +55,17 @@ export default class LearnerGroupRootComponent extends Component { return this.args.learnerGroup.title; } + @cached + get coursesData() { + return new TrackedAsyncData( + this.getCoursesForGroupWithSubgroupName(null, this.args.learnerGroup), + ); + } + + get courses() { + return this.coursesData.isResolved ? this.coursesData.value : []; + } + @cached get cohortData() { return new TrackedAsyncData(this.args.learnerGroup.cohort); From 9113a2dc5870a03692bba893726a3bdb0584e020 Mon Sep 17 00:00:00 2001 From: Stefan Topfstedt Date: Fri, 20 Dec 2024 09:47:16 -0800 Subject: [PATCH 08/11] replaces read-only tracked prop usersToPassToManager with two getters. i split this into two - one for the user manager subcomponent, and one for the membership list subcomponent. edit vs view mode, the data is slightly different. i hope this makes things a bit more grokkable. --- .../app/components/learner-group/root.hbs | 6 +- .../app/components/learner-group/root.js | 90 +++++++++++++------ 2 files changed, 65 insertions(+), 31 deletions(-) diff --git a/packages/frontend/app/components/learner-group/root.hbs b/packages/frontend/app/components/learner-group/root.hbs index e036aaccbf..3cef23359b 100644 --- a/packages/frontend/app/components/learner-group/root.hbs +++ b/packages/frontend/app/components/learner-group/root.hbs @@ -138,7 +138,7 @@ {{t "general.uploadGroupAssignments"}} {{else}} {{t "general.members"}} - ({{this.usersToPassToManager.length}}) + ({{this.usersForUserManager.length}}) {{/if}} @@ -191,7 +191,7 @@ @learnerGroupTitle={{this.learnerGroupTitle}} @topLevelGroupTitle={{this.topLevelGroupTitle}} @cohortTitle={{this.cohortTitle}} - @users={{this.usersToPassToManager}} + @users={{this.usersForUserManager}} @sortBy={{this.sortUsersBy}} @setSortBy={{@setSortUsersBy}} @addUserToGroup={{perform this.addUserToGroup}} @@ -209,7 +209,7 @@ @learnerGroupId={{this.learnerGroupId}} @setSortBy={{@setSortUsersBy}} @sortBy={{this.sortUsersBy}} - @users={{this.usersToPassToManager}} + @users={{this.usersForMembersList}} /> {{/if}} diff --git a/packages/frontend/app/components/learner-group/root.js b/packages/frontend/app/components/learner-group/root.js index 0494499fc5..9aa805ee39 100644 --- a/packages/frontend/app/components/learner-group/root.js +++ b/packages/frontend/app/components/learner-group/root.js @@ -23,7 +23,6 @@ export default class LearnerGroupRootComponent extends Component { @tracked location = null; @IsURL() @Length(2, 2000) @tracked url = null; @tracked showLearnerGroupCalendar = false; - @tracked usersToPassToManager = []; @tracked usersToPassToCohortManager = []; @tracked sortGroupsBy = 'title'; @tracked isSavingGroups = false; @@ -41,7 +40,6 @@ export default class LearnerGroupRootComponent extends Component { load = restartableTask(async (element, [learnerGroup]) => { if (isPresent(learnerGroup)) { - this.usersToPassToManager = await this.createUsersToPassToManager.perform(); this.usersToPassToCohortManager = await this.createUsersToPassToCohortManager.perform(); } }); @@ -225,6 +223,68 @@ export default class LearnerGroupRootComponent extends Component { return this.args.learnerGroup.save(); } + @cached + get usersForMembersListData() { + return new TrackedAsyncData( + this.getUsersForMembersList( + this.args.learnerGroup, + // Learnergroup members are only referenced here to trigger a re-computation on membership changes. + this.args.learnerGroup.users, + ), + ); + } + + get usersForMembersList() { + return this.usersForMembersListData.isResolved ? this.usersForMembersListData.value : []; + } + + async getUsersForMembersList(learnerGroup) { + const topLevelGroup = await learnerGroup.getTopLevelGroup(); + const allDescendants = await topLevelGroup.getAllDescendants(); + const treeGroups = [topLevelGroup, ...allDescendants]; + const users = await learnerGroup.getUsersOnlyAtThisLevel(); + return await map(users, async (user) => { + const lowestGroupInTree = await user.getLowestMemberGroupInALearnerGroupTree(treeGroups); + return ObjectProxy.create({ + content: user, + lowestGroupInTree, + //special sorting property + lowestGroupInTreeTitle: lowestGroupInTree.title, + }); + }); + } + + @cached + get usersForUserManagerData() { + return new TrackedAsyncData( + this.getUsersForUserManager( + this.args.learnerGroup, + // Learnergroup members are only referenced here to trigger a re-computation on membership changes. + this.args.learnerGroup.users, + ), + ); + } + + get usersForUserManager() { + return this.usersForUserManagerData.isResolved ? this.usersForUserManagerData.value : []; + } + + async getUsersForUserManager(learnerGroup) { + const topLevelGroup = await learnerGroup.getTopLevelGroup(); + const allDescendants = await topLevelGroup.getAllDescendants(); + const treeGroups = [topLevelGroup, ...allDescendants]; + const users = await topLevelGroup.getAllDescendantUsers(); + return await map(users, async (user) => { + const lowestGroupInTree = await user.getLowestMemberGroupInALearnerGroupTree(treeGroups); + return ObjectProxy.create({ + content: user, + lowestGroupInTree, + //special sorting property + lowestGroupInTreeTitle: lowestGroupInTree.title, + }); + }); + } + addUserToGroup = enqueueTask(async (user) => { const learnerGroup = this.args.learnerGroup; const topLevelGroup = await learnerGroup.topLevelGroup; @@ -232,7 +292,6 @@ export default class LearnerGroupRootComponent extends Component { const addGroups = await learnerGroup.addUserToGroupAndAllParents(user); await Promise.all(removeGroups.map((g) => g.save())); await Promise.all(addGroups.map((g) => g.save())); - this.usersToPassToManager = await this.createUsersToPassToManager.perform(); this.usersToPassToCohortManager = await this.createUsersToPassToCohortManager.perform(); }); @@ -240,7 +299,6 @@ export default class LearnerGroupRootComponent extends Component { const topLevelGroup = await this.args.learnerGroup.topLevelGroup; const groups = await topLevelGroup.removeUserFromGroupAndAllDescendants(user); await all(groups.map((group) => group.save())); - this.usersToPassToManager = await this.createUsersToPassToManager.perform(); this.usersToPassToCohortManager = await this.createUsersToPassToCohortManager.perform(); }); @@ -260,8 +318,6 @@ export default class LearnerGroupRootComponent extends Component { await Promise.all(uniqueValues(removeGroups).map((g) => g.save())); await Promise.all(uniqueValues(addGroups).map((g) => g.save())); - - this.usersToPassToManager = await this.createUsersToPassToManager.perform(); this.usersToPassToCohortManager = await this.createUsersToPassToCohortManager.perform(); }); @@ -274,31 +330,9 @@ export default class LearnerGroupRootComponent extends Component { groupsToSave = [...groupsToSave, ...removeGroups]; } await all(uniqueValues(groupsToSave).map((group) => group.save())); - this.usersToPassToManager = await this.createUsersToPassToManager.perform(); this.usersToPassToCohortManager = await this.createUsersToPassToCohortManager.perform(); }); - createUsersToPassToManager = task(async () => { - let users; - const topLevelGroup = await this.args.learnerGroup.getTopLevelGroup(); - const allDescendants = await topLevelGroup.getAllDescendants(); - const treeGroups = [topLevelGroup, ...allDescendants]; - if (this.args.isEditing) { - users = await topLevelGroup.getAllDescendantUsers(); - } else { - users = await this.args.learnerGroup.getUsersOnlyAtThisLevel(); - } - return await map(users, async (user) => { - const lowestGroupInTree = await user.getLowestMemberGroupInALearnerGroupTree(treeGroups); - return ObjectProxy.create({ - content: user, - lowestGroupInTree, - //special sorting property - lowestGroupInTreeTitle: lowestGroupInTree.title, - }); - }); - }); - createUsersToPassToCohortManager = task(async () => { const learnerGroup = this.args.learnerGroup; const cohort = await learnerGroup.cohort; From bd99907ec0d7120e9e163be55112869ea00a8b92 Mon Sep 17 00:00:00 2001 From: Stefan Topfstedt Date: Fri, 20 Dec 2024 10:38:47 -0800 Subject: [PATCH 09/11] replaces tracked prop usersToPassToCohortManager with getter, then rm obsolete load() task. --- packages/frontend/.lint-todo | 2 - .../app/components/learner-group/root.hbs | 504 +++++++++--------- .../app/components/learner-group/root.js | 32 +- 3 files changed, 268 insertions(+), 270 deletions(-) diff --git a/packages/frontend/.lint-todo b/packages/frontend/.lint-todo index d67a2cbdb8..3c0a994fab 100644 --- a/packages/frontend/.lint-todo +++ b/packages/frontend/.lint-todo @@ -7,8 +7,6 @@ add|ember-template-lint|no-at-ember-render-modifiers|3|2|3|2|1fb0566922ce4f06691 add|ember-template-lint|no-at-ember-render-modifiers|4|2|4|2|38e65b45b56fdfd4160d3b0884114b6643e3a036|1731542400000|1762646400000|1793750400000|app/components/visualizer-program-year-objectives.hbs add|ember-template-lint|no-at-ember-render-modifiers|3|2|3|2|cb6d7acb9879902b89ad1575846d290a564ffbae|1731542400000|1762646400000|1793750400000|app/components/learner-group/instructor-manager.hbs add|ember-template-lint|no-at-ember-render-modifiers|4|2|4|2|2bdc98d02ac5ea2a4bd5bac6a0f9e880abafdcbe|1731542400000|1762646400000|1793750400000|app/components/learner-group/instructor-manager.hbs -add|ember-template-lint|no-at-ember-render-modifiers|4|4|4|4|170987df2d1e4c134a0ac459fc0bdd8dd91b9929|1731542400000|1762646400000|1793750400000|app/components/learner-group/root.hbs -add|ember-template-lint|no-at-ember-render-modifiers|5|4|5|4|7c59a55b95fd159dd99afa6b20e5f05b5b68def0|1731542400000|1762646400000|1793750400000|app/components/learner-group/root.hbs add|ember-template-lint|no-at-ember-render-modifiers|10|6|10|6|d919d2af254f782c01fe2ba15416673e52e91124|1731542400000|1762646400000|1793750400000|app/components/reports/subject/new/academic-year.hbs add|ember-template-lint|no-at-ember-render-modifiers|11|6|11|6|940005188b476a060b0e5d3f05baea24ba178878|1731542400000|1762646400000|1793750400000|app/components/reports/subject/new/academic-year.hbs add|ember-template-lint|no-at-ember-render-modifiers|10|6|10|6|d919d2af254f782c01fe2ba15416673e52e91124|1731542400000|1762646400000|1793750400000|app/components/reports/subject/new/competency.hbs diff --git a/packages/frontend/app/components/learner-group/root.hbs b/packages/frontend/app/components/learner-group/root.hbs index 3cef23359b..2ad3357d40 100644 --- a/packages/frontend/app/components/learner-group/root.hbs +++ b/packages/frontend/app/components/learner-group/root.hbs @@ -1,279 +1,271 @@ {{#let (unique-id) as |templateId|}} -
- {{#unless this.load.isRunning}} - {{#if this.isSavingGroups}} - - {{/if}} - + {{#if this.isSavingGroups}} + -
-
- - - {{#if @canUpdate}} - - {{else}} - {{#if @learnerGroup.needsAccommodation}} - {{t "general.yes"}} - {{else}} - {{t "general.no"}} - {{/if}} - {{/if}} - -
-
- - - {{#if @canUpdate}} - - - - - {{else if this.location}} - {{this.location}} + {{/if}} + +
+
+ + + {{#if @canUpdate}} + + {{else}} + {{#if @learnerGroup.needsAccommodation}} + {{t "general.yes"}} {{else}} - {{t "general.none"}} + {{t "general.no"}} {{/if}} - + {{/if}} + +
+
+ + + {{#if @canUpdate}} + + + + + {{else if this.location}} + {{this.location}} + {{else}} + {{t "general.none"}} + {{/if}} + +
+
+ + + {{#if @canUpdate}} + + {{! template-lint-disable no-bare-strings}} + + + + {{else if this.url}} + {{this.url}} + {{else}} + {{t "general.none"}} + {{/if}} + +
+
+ +
    + {{#each (sort-by "courseTitle" this.courses) as |obj|}} +
  • + + {{obj.courseTitle}} + {{#if this.academicYearCrossesCalendarYearBoundaries}} + ({{obj.course.year}} + - + {{add obj.course.year 1}}) + {{else}} + ({{obj.course.year}}) + {{/if}} + +
  • + {{/each}} +
+
+ +
+
+ {{#if @isEditing}} + {{t "general.manageGroupMembership"}} + {{else if @isBulkAssigning}} + {{t "general.uploadGroupAssignments"}} + {{else}} + {{t "general.members"}} + ({{this.usersForUserManager.length}}) + {{/if}}
-
- - + + {{#if (or @isEditing @isBulkAssigning)}} + + {{else}} + {{#if @canUpdate}} - - {{! template-lint-disable no-bare-strings}} - - - - {{else if this.url}} - {{this.url}} - {{else}} - {{t "general.none"}} - {{/if}} - -
-
- -
    - {{#each (sort-by "courseTitle" this.courses) as |obj|}} -
  • - - {{obj.courseTitle}} - {{#if this.academicYearCrossesCalendarYearBoundaries}} - ({{obj.course.year}} - - - {{add obj.course.year 1}}) - {{else}} - ({{obj.course.year}}) - {{/if}} - -
  • - {{/each}} -
-
- -
-
- {{#if @isEditing}} - {{t "general.manageGroupMembership"}} - {{else if @isBulkAssigning}} - {{t "general.uploadGroupAssignments"}} - {{else}} - {{t "general.members"}} - ({{this.usersForUserManager.length}}) - {{/if}} -
- - {{#if (or @isEditing @isBulkAssigning)}} + {{t "general.uploadGroupAssignments"}} + - {{else}} - - {{#if @canUpdate}} - - - {{/if}} {{/if}} - -
- {{#if @isBulkAssigning}} - - {{else if @isEditing}} -
- -
- {{else}} - {{#if this.showLearnerGroupCalendar}} - {{/if}} -
- -
- {{/if}} -
-
-

- {{t "general.subgroups"}} - ({{this.learnerGroups.length}}) -

-
- {{#if @canCreate}} - - {{/if}} -
-
-
- {{#if this.showNewLearnerGroupForm}} - - {{/if}} - {{#if this.newLearnerGroup}} -
- - - {{this.newLearnerGroup.title}} - - {{t "general.savedSuccessfully"}} -
- {{/if}} -
-
- {{#if @learnerGroup.childrenCount}} - - {{/if}} -
-
-
- +
+ {{#if @isBulkAssigning}} + + {{else if @isEditing}} +
+ +
+ {{else}} + {{#if this.showLearnerGroupCalendar}} + + {{/if}} +
+ -
+
+ {{/if}} +
+
+

+ {{t "general.subgroups"}} + ({{this.learnerGroups.length}}) +

+
+ {{#if @canCreate}} + + {{/if}} +
+
+
+ {{#if this.showNewLearnerGroupForm}} + + {{/if}} + {{#if this.newLearnerGroup}} +
+ + + {{this.newLearnerGroup.title}} + + {{t "general.savedSuccessfully"}} +
+ {{/if}} +
+
+ {{#if @learnerGroup.childrenCount}} + + {{/if}} +
+
+
+
- {{/unless}} +
{{/let}} \ No newline at end of file diff --git a/packages/frontend/app/components/learner-group/root.js b/packages/frontend/app/components/learner-group/root.js index 9aa805ee39..30fe0b8c61 100644 --- a/packages/frontend/app/components/learner-group/root.js +++ b/packages/frontend/app/components/learner-group/root.js @@ -3,7 +3,6 @@ import { cached, tracked } from '@glimmer/tracking'; import { action } from '@ember/object'; import ObjectProxy from '@ember/object/proxy'; import { service } from '@ember/service'; -import { isPresent } from '@ember/utils'; import { all, map } from 'rsvp'; import { dropTask, enqueueTask, restartableTask, task } from 'ember-concurrency'; import pad from 'pad'; @@ -23,7 +22,6 @@ export default class LearnerGroupRootComponent extends Component { @tracked location = null; @IsURL() @Length(2, 2000) @tracked url = null; @tracked showLearnerGroupCalendar = false; - @tracked usersToPassToCohortManager = []; @tracked sortGroupsBy = 'title'; @tracked isSavingGroups = false; @tracked savedGroup; @@ -38,12 +36,6 @@ export default class LearnerGroupRootComponent extends Component { this.url = this.args.learnerGroup.url; } - load = restartableTask(async (element, [learnerGroup]) => { - if (isPresent(learnerGroup)) { - this.usersToPassToCohortManager = await this.createUsersToPassToCohortManager.perform(); - } - }); - @cached get learnerGroupId() { return this.args.learnerGroup.id; @@ -285,6 +277,26 @@ export default class LearnerGroupRootComponent extends Component { }); } + @cached + get usersForCohortManagerData() { + // Learnergroup members are only referenced here to trigger a re-computation on membership changes. + return new TrackedAsyncData( + this.getUsersToPassToCohortManager(this.args.learnerGroup, this.args.learnerGroup.users), + ); + } + + get usersForCohortManager() { + return this.usersForCohortManagerData.isResolved ? this.usersForCohortManagerData.value : []; + } + + async getUsersToPassToCohortManager(learnerGroup) { + const cohort = await learnerGroup.cohort; + const topLevelGroup = await learnerGroup.getTopLevelGroup(); + const currentUsers = await topLevelGroup.getAllDescendantUsers(); + const users = await cohort.users; + return users.filter((user) => !currentUsers.includes(user)); + } + addUserToGroup = enqueueTask(async (user) => { const learnerGroup = this.args.learnerGroup; const topLevelGroup = await learnerGroup.topLevelGroup; @@ -292,14 +304,12 @@ export default class LearnerGroupRootComponent extends Component { const addGroups = await learnerGroup.addUserToGroupAndAllParents(user); await Promise.all(removeGroups.map((g) => g.save())); await Promise.all(addGroups.map((g) => g.save())); - this.usersToPassToCohortManager = await this.createUsersToPassToCohortManager.perform(); }); removeUserToCohort = enqueueTask(async (user) => { const topLevelGroup = await this.args.learnerGroup.topLevelGroup; const groups = await topLevelGroup.removeUserFromGroupAndAllDescendants(user); await all(groups.map((group) => group.save())); - this.usersToPassToCohortManager = await this.createUsersToPassToCohortManager.perform(); }); addUsersToGroup = enqueueTask(async (users) => { @@ -318,7 +328,6 @@ export default class LearnerGroupRootComponent extends Component { await Promise.all(uniqueValues(removeGroups).map((g) => g.save())); await Promise.all(uniqueValues(addGroups).map((g) => g.save())); - this.usersToPassToCohortManager = await this.createUsersToPassToCohortManager.perform(); }); removeUsersToCohort = enqueueTask(async (users) => { @@ -330,7 +339,6 @@ export default class LearnerGroupRootComponent extends Component { groupsToSave = [...groupsToSave, ...removeGroups]; } await all(uniqueValues(groupsToSave).map((group) => group.save())); - this.usersToPassToCohortManager = await this.createUsersToPassToCohortManager.perform(); }); createUsersToPassToCohortManager = task(async () => { From a112678f7ee5640af669c110844ec4941022232c Mon Sep 17 00:00:00 2001 From: Stefan Topfstedt Date: Fri, 20 Dec 2024 15:20:16 -0800 Subject: [PATCH 10/11] rm unnecessary @cached decorator from getter. --- packages/frontend/app/components/learner-group/root.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/frontend/app/components/learner-group/root.js b/packages/frontend/app/components/learner-group/root.js index 30fe0b8c61..c6ee0ebb90 100644 --- a/packages/frontend/app/components/learner-group/root.js +++ b/packages/frontend/app/components/learner-group/root.js @@ -36,7 +36,6 @@ export default class LearnerGroupRootComponent extends Component { this.url = this.args.learnerGroup.url; } - @cached get learnerGroupId() { return this.args.learnerGroup.id; } From 7b199fbfca65e008e365b02d5c650af0886274bc Mon Sep 17 00:00:00 2001 From: Stefan Topfstedt Date: Fri, 20 Dec 2024 15:22:13 -0800 Subject: [PATCH 11/11] groups iliosconfig service with the other services. --- packages/frontend/app/components/learner-group/root.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/app/components/learner-group/root.js b/packages/frontend/app/components/learner-group/root.js index c6ee0ebb90..1b3501e7bb 100644 --- a/packages/frontend/app/components/learner-group/root.js +++ b/packages/frontend/app/components/learner-group/root.js @@ -19,6 +19,7 @@ export default class LearnerGroupRootComponent extends Component { @service flashMessages; @service intl; @service store; + @service iliosConfig; @tracked location = null; @IsURL() @Length(2, 2000) @tracked url = null; @tracked showLearnerGroupCalendar = false; @@ -28,7 +29,6 @@ export default class LearnerGroupRootComponent extends Component { @tracked showNewLearnerGroupForm = false; @tracked currentGroupsSaved = 0; @tracked totalGroupsToSave = 0; - @service iliosConfig; constructor() { super(...arguments);