diff --git a/packages/frontend/.lint-todo b/packages/frontend/.lint-todo
index 2080df9e80..ad10ac59ba 100644
--- a/packages/frontend/.lint-todo
+++ b/packages/frontend/.lint-todo
@@ -1,75 +1,75 @@
-add|ember-template-lint|no-at-ember-render-modifiers|5|2|5|2|23cd787c79c34a628dadb6e96dd4004d42eebb79|1719360000000|1734915600000|1750464000000|app/components/new-directory-user.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|4|4|4|4|5d93dc162628c4faaa7bce9ef9bfba305f14ce38|1719360000000|1734915600000|1750464000000|app/components/unassigned-students-summary.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|5|4|5|4|5f7f17419fe451673ab74fb58778311bc01912c0|1719360000000|1734915600000|1750464000000|app/components/unassigned-students-summary.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|5|4|5|4|ddf86727990ead62165fe28c6dff53552a4d49b7|1719360000000|1734915600000|1750464000000|app/components/user-menu.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|28|43|28|43|5c127b0b8124a93b18177d7580bcc47dbb8ebbff|1719360000000|1734915600000|1750464000000|app/components/user-menu.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|4|2|4|2|23cd787c79c34a628dadb6e96dd4004d42eebb79|1719360000000|1734915600000|1750464000000|app/components/user-profile-bio.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|5|2|5|2|f53982efe02d2bef9e7f12b5b862288c594579c2|1719360000000|1734915600000|1750464000000|app/components/user-profile-bio.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|5|2|5|2|cb63b416987d7c877a388fbd8e02681fb5571202|1719360000000|1734915600000|1750464000000|app/components/user-profile-cohorts.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|4|2|4|2|23cd787c79c34a628dadb6e96dd4004d42eebb79|1719360000000|1734915600000|1750464000000|app/components/user-profile-roles.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|5|2|5|2|e5120f87b74c5ae8e4c76b9089e0b4a4504c6e3c|1719360000000|1734915600000|1750464000000|app/components/user-profile-roles.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|4|2|4|2|1fb0566922ce4f066916e5e2931f650f69d7cfba|1719360000000|1734915600000|1750464000000|app/components/visualizer-program-year-objectives.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|5|2|5|2|38e65b45b56fdfd4160d3b0884114b6643e3a036|1719360000000|1734915600000|1750464000000|app/components/visualizer-program-year-objectives.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|4|4|4|4|23cd787c79c34a628dadb6e96dd4004d42eebb79|1719360000000|1734915600000|1750464000000|app/components/courses/new.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|5|2|5|2|23cd787c79c34a628dadb6e96dd4004d42eebb79|1719360000000|1734915600000|1750464000000|app/components/curriculum-inventory/new-report.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|4|2|4|2|23cd787c79c34a628dadb6e96dd4004d42eebb79|1719360000000|1734915600000|1750464000000|app/components/curriculum-inventory/new-sequence-block.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|5|2|5|2|77e3831e4ae1b00caee1f808711f2e26ab452a23|1719360000000|1734915600000|1750464000000|app/components/curriculum-inventory/new-sequence-block.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|3|2|3|2|ec3a02c7de9a846320bb33eb702a742de00e56bd|1719360000000|1734915600000|1750464000000|app/components/curriculum-inventory/report-header.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|4|2|4|2|708f3a1a4359e7d1bd669262535d882c49469947|1719360000000|1734915600000|1750464000000|app/components/curriculum-inventory/report-header.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|3|2|3|2|23cd787c79c34a628dadb6e96dd4004d42eebb79|1719360000000|1734915600000|1750464000000|app/components/curriculum-inventory/report-overview.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|3|2|3|2|23cd787c79c34a628dadb6e96dd4004d42eebb79|1719360000000|1734915600000|1750464000000|app/components/curriculum-inventory/report-rollover.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|4|2|4|2|5e634ade97cc174a33ee6f2fdce6c42465ec31e3|1719360000000|1734915600000|1750464000000|app/components/curriculum-inventory/report-rollover.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|3|2|3|2|23cd787c79c34a628dadb6e96dd4004d42eebb79|1719360000000|1734915600000|1750464000000|app/components/curriculum-inventory/reports.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|4|2|4|2|7f75978f3cd895409aab8b335e6816db689c6155|1719360000000|1734915600000|1750464000000|app/components/curriculum-inventory/reports.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|5|2|5|2|c34ed16d221405a625e5c23907f49fd55e6ba231|1719360000000|1734915600000|1750464000000|app/components/curriculum-inventory/sequence-block-header.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|6|2|6|2|6236d751dee8e47f88ffd257c6bfcec223f2b91c|1719360000000|1734915600000|1750464000000|app/components/curriculum-inventory/sequence-block-header.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|4|2|4|2|e65bc0e9138a1521733c31ef990721569f51eb20|1719360000000|1734915600000|1750464000000|app/components/curriculum-inventory/sequence-block-overview.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|5|2|5|2|bd1419d59d5caf1243719b72f63702d3b5bebc07|1719360000000|1734915600000|1750464000000|app/components/curriculum-inventory/sequence-block-overview.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|5|2|5|2|23cd787c79c34a628dadb6e96dd4004d42eebb79|1719360000000|1734915600000|1750464000000|app/components/curriculum-inventory/sequence-block-session-manager.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|6|2|6|2|394d8c8b6b1bc28f48ede0d39dcbfbb4dcd8261e|1719360000000|1734915600000|1750464000000|app/components/curriculum-inventory/sequence-block-session-manager.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|4|2|4|2|62efc8d35f68e3f08387ec86aefd237a3165b683|1719360000000|1734915600000|1750464000000|app/components/curriculum-inventory/verification-preview.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|5|2|5|2|5e634ade97cc174a33ee6f2fdce6c42465ec31e3|1719360000000|1734915600000|1750464000000|app/components/curriculum-inventory/verification-preview.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|12|6|12|6|6b0fce6c690e7738c0a5c4d7c948aa33081989d9|1719360000000|1734915600000|1750464000000|app/components/curriculum-inventory/verification-preview.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|63|6|63|6|b6db22ec9563ff51f1de52c44e83cbf68cbcba25|1719360000000|1734915600000|1750464000000|app/components/curriculum-inventory/verification-preview.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|68|6|68|6|8d3d1b46c14db7639ed115e00e82558c82c47ef6|1719360000000|1734915600000|1750464000000|app/components/curriculum-inventory/verification-preview.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|79|6|79|6|cf9fc0a5f1656f4a0d6a6b3193f15996466a1c72|1719360000000|1734915600000|1750464000000|app/components/curriculum-inventory/verification-preview.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|90|6|90|6|b363c92a92a834938ea231382d1b1db885d2a558|1719360000000|1734915600000|1750464000000|app/components/curriculum-inventory/verification-preview.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|100|6|100|6|7e8a296e37ffe138e13632833a23de0e7a69964a|1719360000000|1734915600000|1750464000000|app/components/curriculum-inventory/verification-preview.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|111|6|111|6|b432d5e6ea21f6bf8c201d4453c8bea767d9a928|1719360000000|1734915600000|1750464000000|app/components/curriculum-inventory/verification-preview.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|122|6|122|6|7888b1986f039c99dbc62e306f5d5bc34c90ae39|1719360000000|1734915600000|1750464000000|app/components/curriculum-inventory/verification-preview.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|133|6|133|6|4d6c3374c9f845e60bda3b640ec49a3be3ee6fbb|1719360000000|1734915600000|1750464000000|app/components/curriculum-inventory/verification-preview.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|144|6|144|6|e49fa902e44c371593d62096c490244ec75a9083|1719360000000|1734915600000|1750464000000|app/components/curriculum-inventory/verification-preview.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|4|2|4|2|7312526529ca39ed820819d1478d8e1b8f555279|1719360000000|1734915600000|1750464000000|app/components/instructor-group/header.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|5|2|5|2|10c85f1f7f9cf2d05a7f36c4618679ea04c51154|1719360000000|1734915600000|1750464000000|app/components/instructor-group/header.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|4|2|4|2|7312526529ca39ed820819d1478d8e1b8f555279|1719360000000|1734915600000|1750464000000|app/components/learner-group/header.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|5|2|5|2|c33c821719fcbe918954f20b45e0959a3a40c62b|1719360000000|1734915600000|1750464000000|app/components/learner-group/header.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|3|2|3|2|cb6d7acb9879902b89ad1575846d290a564ffbae|1719360000000|1734915600000|1750464000000|app/components/learner-group/instructor-manager.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|4|2|4|2|2bdc98d02ac5ea2a4bd5bac6a0f9e880abafdcbe|1719360000000|1734915600000|1750464000000|app/components/learner-group/instructor-manager.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|4|4|4|4|170987df2d1e4c134a0ac459fc0bdd8dd91b9929|1719360000000|1734915600000|1750464000000|app/components/learner-group/root.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|5|4|5|4|7c59a55b95fd159dd99afa6b20e5f05b5b68def0|1719360000000|1734915600000|1750464000000|app/components/learner-group/root.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|4|4|4|4|66fe3cf991d61995cda5f5935874230700b5e21f|1719360000000|1734915600000|1750464000000|app/components/program/header.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|5|4|5|4|0bcfaa7865c6a954a5b5226ffe44ddc6c63945ba|1719360000000|1734915600000|1750464000000|app/components/program/header.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|3|2|3|2|66fe3cf991d61995cda5f5935874230700b5e21f|1719360000000|1734915600000|1750464000000|app/components/program/overview.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|4|2|4|2|0bcfaa7865c6a954a5b5226ffe44ddc6c63945ba|1719360000000|1734915600000|1750464000000|app/components/program/overview.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|5|2|5|2|12f77ac1f8c43640397b771ba2c9830dd2041f23|1719360000000|1734915600000|1750464000000|app/components/program-year/collapsed-objectives.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|6|2|6|2|87dcba868bd23c9305b095ffbda9e90ab5b4918e|1719360000000|1734915600000|1750464000000|app/components/program-year/collapsed-objectives.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|3|2|3|2|b759467cf4c3dc1d7e39d4bed1d085d51090d363|1719360000000|1734915600000|1750464000000|app/components/program-year/objective-list-item-expanded.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|4|2|4|2|c4f87a15e0dbf28e3a3b95d7b8259a419f93b29d|1719360000000|1734915600000|1750464000000|app/components/program-year/objective-list-item-expanded.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|5|2|5|2|fc55335d86e2b3d97a0614f6c046ba360820801c|1719360000000|1734915600000|1750464000000|app/components/program-year/objective-list-item.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|6|2|6|2|12443b4ba50f603e3c3af3d9e10ce840e7b67d9e|1719360000000|1734915600000|1750464000000|app/components/program-year/objective-list-item.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|3|2|3|2|286929067e02096dda5597efc45c876218621874|1719360000000|1734915600000|1750464000000|app/components/program-year/objectives.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|4|2|4|2|f37fd8ee0b117114a09137593ed6f113b2c80806|1719360000000|1734915600000|1750464000000|app/components/program-year/objectives.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|10|6|10|6|d919d2af254f782c01fe2ba15416673e52e91124|1719360000000|1734915600000|1750464000000|app/components/reports/subject/new/academic-year.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|11|6|11|6|940005188b476a060b0e5d3f05baea24ba178878|1719360000000|1734915600000|1750464000000|app/components/reports/subject/new/academic-year.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|10|6|10|6|d919d2af254f782c01fe2ba15416673e52e91124|1719360000000|1734915600000|1750464000000|app/components/reports/subject/new/competency.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|11|6|11|6|940005188b476a060b0e5d3f05baea24ba178878|1719360000000|1734915600000|1750464000000|app/components/reports/subject/new/competency.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|10|6|10|6|d919d2af254f782c01fe2ba15416673e52e91124|1719360000000|1734915600000|1750464000000|app/components/reports/subject/new/instructor-group.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|11|6|11|6|940005188b476a060b0e5d3f05baea24ba178878|1719360000000|1734915600000|1750464000000|app/components/reports/subject/new/instructor-group.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|10|6|10|6|d919d2af254f782c01fe2ba15416673e52e91124|1719360000000|1734915600000|1750464000000|app/components/reports/subject/new/program-year.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|11|6|11|6|940005188b476a060b0e5d3f05baea24ba178878|1719360000000|1734915600000|1750464000000|app/components/reports/subject/new/program-year.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|10|6|10|6|d919d2af254f782c01fe2ba15416673e52e91124|1719360000000|1734915600000|1750464000000|app/components/reports/subject/new/program.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|11|6|11|6|940005188b476a060b0e5d3f05baea24ba178878|1719360000000|1734915600000|1750464000000|app/components/reports/subject/new/program.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|10|6|10|6|d919d2af254f782c01fe2ba15416673e52e91124|1719360000000|1734915600000|1750464000000|app/components/reports/subject/new/session-type.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|11|6|11|6|940005188b476a060b0e5d3f05baea24ba178878|1719360000000|1734915600000|1750464000000|app/components/reports/subject/new/session-type.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|10|6|10|6|d919d2af254f782c01fe2ba15416673e52e91124|1719360000000|1734915600000|1750464000000|app/components/reports/subject/new/term.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|11|6|11|6|940005188b476a060b0e5d3f05baea24ba178878|1719360000000|1734915600000|1750464000000|app/components/reports/subject/new/term.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|5|2|5|2|23cd787c79c34a628dadb6e96dd4004d42eebb79|1721088000000|1723680000000|1726272000000|app/components/new-directory-user.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|4|4|4|4|5d93dc162628c4faaa7bce9ef9bfba305f14ce38|1721088000000|1723680000000|1726272000000|app/components/unassigned-students-summary.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|5|4|5|4|5f7f17419fe451673ab74fb58778311bc01912c0|1721088000000|1723680000000|1726272000000|app/components/unassigned-students-summary.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|5|4|5|4|ddf86727990ead62165fe28c6dff53552a4d49b7|1721088000000|1723680000000|1726272000000|app/components/user-menu.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|28|43|28|43|5c127b0b8124a93b18177d7580bcc47dbb8ebbff|1721088000000|1723680000000|1726272000000|app/components/user-menu.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|4|2|4|2|23cd787c79c34a628dadb6e96dd4004d42eebb79|1721088000000|1723680000000|1726272000000|app/components/user-profile-bio.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|5|2|5|2|f53982efe02d2bef9e7f12b5b862288c594579c2|1721088000000|1723680000000|1726272000000|app/components/user-profile-bio.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|5|2|5|2|cb63b416987d7c877a388fbd8e02681fb5571202|1721088000000|1723680000000|1726272000000|app/components/user-profile-cohorts.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|4|2|4|2|23cd787c79c34a628dadb6e96dd4004d42eebb79|1721088000000|1723680000000|1726272000000|app/components/user-profile-roles.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|5|2|5|2|e5120f87b74c5ae8e4c76b9089e0b4a4504c6e3c|1721088000000|1723680000000|1726272000000|app/components/user-profile-roles.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|4|2|4|2|1fb0566922ce4f066916e5e2931f650f69d7cfba|1721088000000|1723680000000|1726272000000|app/components/visualizer-program-year-objectives.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|5|2|5|2|38e65b45b56fdfd4160d3b0884114b6643e3a036|1721088000000|1723680000000|1726272000000|app/components/visualizer-program-year-objectives.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|4|4|4|4|23cd787c79c34a628dadb6e96dd4004d42eebb79|1721088000000|1723680000000|1726272000000|app/components/courses/new.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|5|2|5|2|23cd787c79c34a628dadb6e96dd4004d42eebb79|1721088000000|1723680000000|1726272000000|app/components/curriculum-inventory/new-report.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|4|2|4|2|23cd787c79c34a628dadb6e96dd4004d42eebb79|1721088000000|1723680000000|1726272000000|app/components/curriculum-inventory/new-sequence-block.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|5|2|5|2|77e3831e4ae1b00caee1f808711f2e26ab452a23|1721088000000|1723680000000|1726272000000|app/components/curriculum-inventory/new-sequence-block.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|3|2|3|2|ec3a02c7de9a846320bb33eb702a742de00e56bd|1721088000000|1723680000000|1726272000000|app/components/curriculum-inventory/report-header.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|4|2|4|2|708f3a1a4359e7d1bd669262535d882c49469947|1721088000000|1723680000000|1726272000000|app/components/curriculum-inventory/report-header.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|3|2|3|2|23cd787c79c34a628dadb6e96dd4004d42eebb79|1721088000000|1723680000000|1726272000000|app/components/curriculum-inventory/report-overview.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|3|2|3|2|23cd787c79c34a628dadb6e96dd4004d42eebb79|1721088000000|1723680000000|1726272000000|app/components/curriculum-inventory/report-rollover.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|4|2|4|2|5e634ade97cc174a33ee6f2fdce6c42465ec31e3|1721088000000|1723680000000|1726272000000|app/components/curriculum-inventory/report-rollover.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|3|2|3|2|23cd787c79c34a628dadb6e96dd4004d42eebb79|1721088000000|1723680000000|1726272000000|app/components/curriculum-inventory/reports.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|4|2|4|2|7f75978f3cd895409aab8b335e6816db689c6155|1721088000000|1723680000000|1726272000000|app/components/curriculum-inventory/reports.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|5|2|5|2|c34ed16d221405a625e5c23907f49fd55e6ba231|1721088000000|1723680000000|1726272000000|app/components/curriculum-inventory/sequence-block-header.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|6|2|6|2|6236d751dee8e47f88ffd257c6bfcec223f2b91c|1721088000000|1723680000000|1726272000000|app/components/curriculum-inventory/sequence-block-header.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|4|2|4|2|e65bc0e9138a1521733c31ef990721569f51eb20|1721088000000|1723680000000|1726272000000|app/components/curriculum-inventory/sequence-block-overview.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|5|2|5|2|bd1419d59d5caf1243719b72f63702d3b5bebc07|1721088000000|1723680000000|1726272000000|app/components/curriculum-inventory/sequence-block-overview.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|5|2|5|2|23cd787c79c34a628dadb6e96dd4004d42eebb79|1721088000000|1723680000000|1726272000000|app/components/curriculum-inventory/sequence-block-session-manager.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|6|2|6|2|394d8c8b6b1bc28f48ede0d39dcbfbb4dcd8261e|1721088000000|1723680000000|1726272000000|app/components/curriculum-inventory/sequence-block-session-manager.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|4|2|4|2|62efc8d35f68e3f08387ec86aefd237a3165b683|1721088000000|1723680000000|1726272000000|app/components/curriculum-inventory/verification-preview.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|5|2|5|2|5e634ade97cc174a33ee6f2fdce6c42465ec31e3|1721088000000|1723680000000|1726272000000|app/components/curriculum-inventory/verification-preview.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|12|6|12|6|6b0fce6c690e7738c0a5c4d7c948aa33081989d9|1721088000000|1723680000000|1726272000000|app/components/curriculum-inventory/verification-preview.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|63|6|63|6|b6db22ec9563ff51f1de52c44e83cbf68cbcba25|1721088000000|1723680000000|1726272000000|app/components/curriculum-inventory/verification-preview.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|68|6|68|6|8d3d1b46c14db7639ed115e00e82558c82c47ef6|1721088000000|1723680000000|1726272000000|app/components/curriculum-inventory/verification-preview.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|79|6|79|6|cf9fc0a5f1656f4a0d6a6b3193f15996466a1c72|1721088000000|1723680000000|1726272000000|app/components/curriculum-inventory/verification-preview.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|90|6|90|6|b363c92a92a834938ea231382d1b1db885d2a558|1721088000000|1723680000000|1726272000000|app/components/curriculum-inventory/verification-preview.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|100|6|100|6|7e8a296e37ffe138e13632833a23de0e7a69964a|1721088000000|1723680000000|1726272000000|app/components/curriculum-inventory/verification-preview.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|111|6|111|6|b432d5e6ea21f6bf8c201d4453c8bea767d9a928|1721088000000|1723680000000|1726272000000|app/components/curriculum-inventory/verification-preview.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|122|6|122|6|7888b1986f039c99dbc62e306f5d5bc34c90ae39|1721088000000|1723680000000|1726272000000|app/components/curriculum-inventory/verification-preview.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|133|6|133|6|4d6c3374c9f845e60bda3b640ec49a3be3ee6fbb|1721088000000|1723680000000|1726272000000|app/components/curriculum-inventory/verification-preview.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|144|6|144|6|e49fa902e44c371593d62096c490244ec75a9083|1721088000000|1723680000000|1726272000000|app/components/curriculum-inventory/verification-preview.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|4|2|4|2|7312526529ca39ed820819d1478d8e1b8f555279|1721088000000|1723680000000|1726272000000|app/components/instructor-group/header.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|5|2|5|2|10c85f1f7f9cf2d05a7f36c4618679ea04c51154|1721088000000|1723680000000|1726272000000|app/components/instructor-group/header.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|4|2|4|2|7312526529ca39ed820819d1478d8e1b8f555279|1721088000000|1723680000000|1726272000000|app/components/learner-group/header.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|5|2|5|2|c33c821719fcbe918954f20b45e0959a3a40c62b|1721088000000|1723680000000|1726272000000|app/components/learner-group/header.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|3|2|3|2|cb6d7acb9879902b89ad1575846d290a564ffbae|1721088000000|1723680000000|1726272000000|app/components/learner-group/instructor-manager.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|4|2|4|2|2bdc98d02ac5ea2a4bd5bac6a0f9e880abafdcbe|1721088000000|1723680000000|1726272000000|app/components/learner-group/instructor-manager.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|4|4|4|4|170987df2d1e4c134a0ac459fc0bdd8dd91b9929|1721088000000|1723680000000|1726272000000|app/components/learner-group/root.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|5|4|5|4|7c59a55b95fd159dd99afa6b20e5f05b5b68def0|1721088000000|1723680000000|1726272000000|app/components/learner-group/root.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|4|4|4|4|66fe3cf991d61995cda5f5935874230700b5e21f|1721088000000|1723680000000|1726272000000|app/components/program/header.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|5|4|5|4|0bcfaa7865c6a954a5b5226ffe44ddc6c63945ba|1721088000000|1723680000000|1726272000000|app/components/program/header.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|3|2|3|2|66fe3cf991d61995cda5f5935874230700b5e21f|1721088000000|1723680000000|1726272000000|app/components/program/overview.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|4|2|4|2|0bcfaa7865c6a954a5b5226ffe44ddc6c63945ba|1721088000000|1723680000000|1726272000000|app/components/program/overview.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|5|2|5|2|12f77ac1f8c43640397b771ba2c9830dd2041f23|1721088000000|1723680000000|1726272000000|app/components/program-year/collapsed-objectives.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|6|2|6|2|87dcba868bd23c9305b095ffbda9e90ab5b4918e|1721088000000|1723680000000|1726272000000|app/components/program-year/collapsed-objectives.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|3|2|3|2|b759467cf4c3dc1d7e39d4bed1d085d51090d363|1721088000000|1723680000000|1726272000000|app/components/program-year/objective-list-item-expanded.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|4|2|4|2|c4f87a15e0dbf28e3a3b95d7b8259a419f93b29d|1721088000000|1723680000000|1726272000000|app/components/program-year/objective-list-item-expanded.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|5|2|5|2|fc55335d86e2b3d97a0614f6c046ba360820801c|1721088000000|1723680000000|1726272000000|app/components/program-year/objective-list-item.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|6|2|6|2|12443b4ba50f603e3c3af3d9e10ce840e7b67d9e|1721088000000|1723680000000|1726272000000|app/components/program-year/objective-list-item.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|3|2|3|2|286929067e02096dda5597efc45c876218621874|1721088000000|1723680000000|1726272000000|app/components/program-year/objectives.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|4|2|4|2|f37fd8ee0b117114a09137593ed6f113b2c80806|1721088000000|1723680000000|1726272000000|app/components/program-year/objectives.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|10|6|10|6|d919d2af254f782c01fe2ba15416673e52e91124|1721088000000|1723680000000|1726272000000|app/components/reports/subject/new/academic-year.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|11|6|11|6|940005188b476a060b0e5d3f05baea24ba178878|1721088000000|1723680000000|1726272000000|app/components/reports/subject/new/academic-year.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|10|6|10|6|d919d2af254f782c01fe2ba15416673e52e91124|1721088000000|1723680000000|1726272000000|app/components/reports/subject/new/competency.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|11|6|11|6|940005188b476a060b0e5d3f05baea24ba178878|1721088000000|1723680000000|1726272000000|app/components/reports/subject/new/competency.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|10|6|10|6|d919d2af254f782c01fe2ba15416673e52e91124|1721088000000|1723680000000|1726272000000|app/components/reports/subject/new/instructor-group.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|11|6|11|6|940005188b476a060b0e5d3f05baea24ba178878|1721088000000|1723680000000|1726272000000|app/components/reports/subject/new/instructor-group.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|10|6|10|6|d919d2af254f782c01fe2ba15416673e52e91124|1721088000000|1723680000000|1726272000000|app/components/reports/subject/new/program-year.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|11|6|11|6|940005188b476a060b0e5d3f05baea24ba178878|1721088000000|1723680000000|1726272000000|app/components/reports/subject/new/program-year.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|10|6|10|6|d919d2af254f782c01fe2ba15416673e52e91124|1721088000000|1723680000000|1726272000000|app/components/reports/subject/new/program.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|11|6|11|6|940005188b476a060b0e5d3f05baea24ba178878|1721088000000|1723680000000|1726272000000|app/components/reports/subject/new/program.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|10|6|10|6|d919d2af254f782c01fe2ba15416673e52e91124|1721088000000|1723680000000|1726272000000|app/components/reports/subject/new/session-type.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|11|6|11|6|940005188b476a060b0e5d3f05baea24ba178878|1721088000000|1723680000000|1726272000000|app/components/reports/subject/new/session-type.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|10|6|10|6|d919d2af254f782c01fe2ba15416673e52e91124|1721088000000|1723680000000|1726272000000|app/components/reports/subject/new/term.hbs
+add|ember-template-lint|no-at-ember-render-modifiers|11|6|11|6|940005188b476a060b0e5d3f05baea24ba178878|1721088000000|1723680000000|1726272000000|app/components/reports/subject/new/term.hbs
diff --git a/packages/frontend/config/environment.js b/packages/frontend/config/environment.js
index 3987f9e425..031f27ebca 100644
--- a/packages/frontend/config/environment.js
+++ b/packages/frontend/config/environment.js
@@ -47,6 +47,11 @@ module.exports = function (environment) {
visualNoiseLevel: 1,
},
},
+ 'ember-local-storage': {
+ namespace: true,
+ keyDelimiter: '/',
+ includeEmberDataSupport: false,
+ },
fontawesome: {
enableExperimentalBuildTimeTransform: false,
defaultPrefix: 'fas',
diff --git a/packages/frontend/tests/acceptance/dashboard/calendar-test.js b/packages/frontend/tests/acceptance/dashboard/calendar-test.js
index 19a7f07b2d..4139df4f09 100644
--- a/packages/frontend/tests/acceptance/dashboard/calendar-test.js
+++ b/packages/frontend/tests/acceptance/dashboard/calendar-test.js
@@ -1,19 +1,10 @@
-import {
- click,
- findAll,
- find,
- currentURL,
- currentRouteName,
- visit,
- triggerEvent,
-} from '@ember/test-helpers';
-import { isEmpty } from '@ember/utils';
+import { currentURL, currentRouteName } from '@ember/test-helpers';
import { DateTime } from 'luxon';
import { module, test } from 'qunit';
import { setupAuthentication, freezeDateAt, unfreezeDate } from 'ilios-common';
import { setupApplicationTest } from 'frontend/tests/helpers';
-import { map } from 'rsvp';
import page from 'ilios-common/page-objects/dashboard-calendar';
+import resetStorages from 'ember-local-storage/test-support/reset-storage';
import percySnapshot from '@percy/ember';
module('Acceptance | Dashboard Calendar', function (hooks) {
@@ -89,6 +80,10 @@ module('Acceptance | Dashboard Calendar', function (hooks) {
hooks.afterEach(() => {
unfreezeDate();
+ if (window.localStorage) {
+ window.localStorage.clear();
+ }
+ resetStorages();
});
test('load month calendar', async function (assert) {
@@ -117,11 +112,10 @@ module('Acceptance | Dashboard Calendar', function (hooks) {
endDate: endOfMonth.plus({ hour: 1 }).toJSDate(),
lastModified: today.minus({ year: 1 }),
});
- await visit('/dashboard/calendar?view=month');
+ await page.visit({ view: 'month' });
await percySnapshot(assert);
assert.strictEqual(currentRouteName(), 'dashboard.calendar');
- const events = findAll('[data-test-ilios-calendar-event]');
- assert.strictEqual(events.length, 2);
+ assert.strictEqual(page.calendar.calendar.monthly.events.length, 2);
const startOfMonthStartFormat = this.intl.formatTime(startOfMonth.toJSDate(), {
hour: '2-digit',
minute: '2-digit',
@@ -130,9 +124,10 @@ module('Acceptance | Dashboard Calendar', function (hooks) {
hour: '2-digit',
minute: '2-digit',
});
- assert
- .dom(events[0])
- .hasText(`${startOfMonthStartFormat} - ${startOfMonthEndFormat} : start of month`);
+ assert.strictEqual(
+ page.calendar.calendar.monthly.events[0].text,
+ `${startOfMonthStartFormat} - ${startOfMonthEndFormat} : start of month`,
+ );
const endOfMonthStartFormat = this.intl.formatTime(endOfMonth.toJSDate(), {
hour: 'numeric',
minute: 'numeric',
@@ -141,9 +136,10 @@ module('Acceptance | Dashboard Calendar', function (hooks) {
hour: 'numeric',
minute: 'numeric',
});
- assert
- .dom(events[1])
- .hasText(`${endOfMonthStartFormat} - ${endOfMonthEndFormat} : end of month`);
+ assert.strictEqual(
+ page.calendar.calendar.monthly.events[1].text,
+ `${endOfMonthStartFormat} - ${endOfMonthEndFormat} : end of month`,
+ );
});
test('load week calendar', async function (assert) {
@@ -187,18 +183,18 @@ module('Acceptance | Dashboard Calendar', function (hooks) {
await percySnapshot(assert);
assert.strictEqual(currentRouteName(), 'dashboard.calendar');
- assert.strictEqual(page.calendar.weeklyCalendar.dayHeadings.length, 7);
- assert.ok(page.calendar.weeklyCalendar.dayHeadings[0].isFirstDayOfWeek);
+ assert.strictEqual(page.calendar.calendar.weekly.dayHeadings.length, 7);
+ assert.ok(page.calendar.calendar.weekly.dayHeadings[0].isFirstDayOfWeek);
assert.strictEqual(
- page.calendar.weeklyCalendar.dayHeadings[0].text,
+ page.calendar.calendar.weekly.dayHeadings[0].text,
`Sunday Sun ${longDayHeading} ${shortDayHeading}`,
);
- assert.strictEqual(page.calendar.weeklyCalendar.events.length, 2);
- assert.ok(page.calendar.weeklyCalendar.events[0].isFirstDayOfWeek);
- assert.strictEqual(page.calendar.weeklyCalendar.events[0].name, 'start of week');
- assert.ok(page.calendar.weeklyCalendar.events[1].isSeventhDayOfWeek);
- assert.strictEqual(page.calendar.weeklyCalendar.events[1].name, 'end of week');
+ assert.strictEqual(page.calendar.calendar.weekly.events.length, 2);
+ assert.ok(page.calendar.calendar.weekly.events[0].isFirstDayOfWeek);
+ assert.strictEqual(page.calendar.calendar.weekly.events[0].name, 'start of week');
+ assert.ok(page.calendar.calendar.weekly.events[1].isSeventhDayOfWeek);
+ assert.strictEqual(page.calendar.calendar.weekly.events[1].name, 'end of week');
});
test('load week calendar on Sunday', async function (assert) {
@@ -242,22 +238,22 @@ module('Acceptance | Dashboard Calendar', function (hooks) {
await page.visit({ show: 'calendar' });
assert.strictEqual(currentRouteName(), 'dashboard.calendar');
- assert.strictEqual(page.calendar.weeklyCalendar.dayHeadings.length, 7);
- assert.ok(page.calendar.weeklyCalendar.dayHeadings[0].isFirstDayOfWeek);
+ assert.strictEqual(page.calendar.calendar.weekly.dayHeadings.length, 7);
+ assert.ok(page.calendar.calendar.weekly.dayHeadings[0].isFirstDayOfWeek);
assert.strictEqual(
- page.calendar.weeklyCalendar.dayHeadings[0].text,
+ page.calendar.calendar.weekly.dayHeadings[0].text,
`Sunday Sun ${longDayHeading} ${shortDayHeading}`,
);
assert.strictEqual(
- page.calendar.weeklyCalendar.title.longWeekOfYear,
+ page.calendar.calendar.weekly.title.longWeekOfYear,
'Week of October 9, 2022',
);
- assert.strictEqual(page.calendar.weeklyCalendar.events.length, 2);
- assert.ok(page.calendar.weeklyCalendar.events[0].isFirstDayOfWeek);
- assert.strictEqual(page.calendar.weeklyCalendar.events[0].name, 'start of week');
- assert.ok(page.calendar.weeklyCalendar.events[1].isSeventhDayOfWeek);
- assert.strictEqual(page.calendar.weeklyCalendar.events[1].name, 'end of week');
+ assert.strictEqual(page.calendar.calendar.weekly.events.length, 2);
+ assert.ok(page.calendar.calendar.weekly.events[0].isFirstDayOfWeek);
+ assert.strictEqual(page.calendar.calendar.weekly.events[0].name, 'start of week');
+ assert.ok(page.calendar.calendar.weekly.events[1].isSeventhDayOfWeek);
+ assert.strictEqual(page.calendar.calendar.weekly.events[1].name, 'end of week');
});
test('load day calendar', async function (assert) {
@@ -293,12 +289,12 @@ module('Acceptance | Dashboard Calendar', function (hooks) {
endDate: yesterday.plus({ hour: 1 }).toJSDate(),
lastModified: today.minus({ year: 1 }),
});
- await visit('/dashboard/calendar?view=day');
+ await page.visit({ view: 'day' });
await percySnapshot(assert);
assert.strictEqual(currentRouteName(), 'dashboard.calendar');
- assert.strictEqual(page.calendar.dailyCalendar.events.length, 1);
- assert.strictEqual(page.calendar.dailyCalendar.events[0].name, 'today');
+ assert.strictEqual(page.calendar.calendar.daily.events.length, 1);
+ assert.strictEqual(page.calendar.calendar.daily.events[0].name, 'today');
});
test('invalid date loads today #5342', async function (assert) {
@@ -310,9 +306,9 @@ module('Acceptance | Dashboard Calendar', function (hooks) {
day: 24,
}).toJSDate(),
);
- await visit('/dashboard/calendar?view=day&date=somethinginvalid');
+ await page.visit({ view: 'day', date: 'somethinginvalid' });
assert.strictEqual(currentRouteName(), 'dashboard.calendar');
- assert.strictEqual(page.calendar.dailyCalendar.title.longDayOfWeek, 'Friday, June 24, 2005');
+ assert.strictEqual(page.calendar.calendar.daily.title.longDayOfWeek, 'Friday, June 24, 2005');
});
test('click month day number and go to day', async function (assert) {
@@ -323,8 +319,8 @@ module('Acceptance | Dashboard Calendar', function (hooks) {
startDate: aDayInTheMonth.toJSDate(),
endDate: aDayInTheMonth.plus({ hour: 1 }).toJSDate(),
});
- await visit('/dashboard/calendar?view=month');
- await click(`[data-test-day-button="${aDayInTheMonth.day}"]`);
+ await page.visit({ view: 'month' });
+ await page.calendar.calendar.monthly.days[aDayInTheMonth.day - 1].selectDay();
assert.strictEqual(
currentURL(),
'/dashboard/calendar?date=' + aDayInTheMonth.toFormat('y-MM-dd') + '&view=day',
@@ -346,11 +342,11 @@ module('Acceptance | Dashboard Calendar', function (hooks) {
endDate: june24th2005.plus({ hour: 1 }).toJSDate(),
});
await page.visit({ show: 'calendar', view: 'week' });
- assert.strictEqual(page.calendar.weeklyCalendar.dayHeadings.length, 7);
- await page.calendar.weeklyCalendar.dayHeadings[0].selectDay();
+ assert.strictEqual(page.calendar.calendar.weekly.dayHeadings.length, 7);
+ await page.calendar.calendar.weekly.dayHeadings[0].selectDay();
assert.strictEqual(currentURL(), '/dashboard/calendar?date=2005-06-19&view=day');
await page.visit({ show: 'calendar', view: 'week' });
- await page.calendar.weeklyCalendar.dayHeadings[5].selectDay();
+ await page.calendar.calendar.weekly.dayHeadings[5].selectDay();
assert.strictEqual(currentURL(), '/dashboard/calendar?date=2005-06-24&view=day');
});
@@ -362,8 +358,8 @@ module('Acceptance | Dashboard Calendar', function (hooks) {
startDate: today.toJSDate(),
endDate: today.plus({ hour: 1 }).toJSDate(),
});
- await visit('/dashboard/calendar?view=day');
- await click('.calendar-time-picker li:nth-of-type(3) a');
+ await page.visit({ view: 'day' });
+ await page.calendar.calendar.goForward.click();
assert.strictEqual(
currentURL(),
'/dashboard/calendar?date=' + today.plus({ day: 1 }).toFormat('y-MM-dd') + '&view=day',
@@ -378,8 +374,8 @@ module('Acceptance | Dashboard Calendar', function (hooks) {
startDate: today.toJSDate(),
endDate: today.plus({ hour: 1 }).toJSDate(),
});
- await visit('/dashboard/calendar?view=week');
- await click('.calendar-time-picker li:nth-of-type(3) a');
+ await page.visit({ view: 'week' });
+ await page.calendar.calendar.goForward.click();
assert.strictEqual(
currentURL(),
'/dashboard/calendar?date=' + today.plus({ week: 1 }).toFormat('y-MM-dd'),
@@ -394,9 +390,8 @@ module('Acceptance | Dashboard Calendar', function (hooks) {
startDate: today.toJSDate(),
endDate: today.plus({ hour: 1 }).toJSDate(),
});
- await visit('/dashboard/calendar?view=month');
- await click('.calendar-time-picker li:nth-of-type(3) a');
- await click(findAll('.calendar-time-picker li')[2]);
+ await page.visit({ view: 'month' });
+ await page.calendar.calendar.goForward.click();
assert.strictEqual(
currentURL(),
'/dashboard/calendar?date=' + today.plus({ month: 1 }).toFormat('y-MM-dd') + '&view=month',
@@ -411,8 +406,8 @@ module('Acceptance | Dashboard Calendar', function (hooks) {
startDate: today.toJSDate(),
endDate: today.plus({ hour: 1 }).toJSDate(),
});
- await visit('/dashboard/calendar?view=day');
- await click('.calendar-time-picker li:nth-of-type(1) a');
+ await page.visit({ view: 'day' });
+ await page.calendar.calendar.goBack.click();
assert.strictEqual(
currentURL(),
'/dashboard/calendar?date=' + today.minus({ day: 1 }).toFormat('y-MM-dd') + '&view=day',
@@ -427,8 +422,8 @@ module('Acceptance | Dashboard Calendar', function (hooks) {
startDate: today.toJSDate(),
endDate: today.plus({ hour: 1 }).toJSDate(),
});
- await visit('/dashboard/calendar?view=week');
- await click('.calendar-time-picker li:nth-of-type(1) a');
+ await page.visit({ view: 'week' });
+ await page.calendar.calendar.goBack.click();
assert.strictEqual(
currentURL(),
'/dashboard/calendar?date=' + today.minus({ week: 1 }).toFormat('y-MM-dd'),
@@ -443,8 +438,8 @@ module('Acceptance | Dashboard Calendar', function (hooks) {
startDate: today.toJSDate(),
endDate: today.plus({ hour: 1 }).toJSDate(),
});
- await visit('/dashboard/calendar?view=month');
- await click('.calendar-time-picker li:nth-of-type(1) a');
+ await page.visit({ view: 'month' });
+ await page.calendar.calendar.goBack.click();
assert.strictEqual(
currentURL(),
'/dashboard/calendar?date=' + today.minus({ month: 1 }).toFormat('y-MM-dd') + '&view=month',
@@ -476,12 +471,9 @@ module('Acceptance | Dashboard Calendar', function (hooks) {
});
await page.visit({ show: 'calendar' });
await percySnapshot(assert);
- assert.strictEqual(page.calendar.weeklyCalendar.events.length, 2);
+ assert.strictEqual(page.calendar.calendar.weekly.events.length, 2);
});
- const chooseSchoolEvents = async function () {
- return await click(find(findAll('.togglemyschedule label')[1]));
- };
test('show school events', async function (assert) {
assert.expect(1);
const day = DateTime.fromObject({
@@ -506,18 +498,164 @@ module('Acceptance | Dashboard Calendar', function (hooks) {
offering: 2,
});
await page.visit();
- await chooseSchoolEvents();
+ await page.calendar.controls.mySchedule.toggle.secondLabel.click();
await percySnapshot(assert);
- assert.strictEqual(page.calendar.weeklyCalendar.events.length, 2);
+ assert.strictEqual(page.calendar.calendar.weekly.events.length, 2);
});
- const showFilters = async function () {
- return await click('.showfilters label:nth-of-type(2)');
- };
+ test('user context filters are not present on student-only user calendar', async function (assert) {
+ assert.expect(1);
+ await page.visit({ show: 'calendar' });
+ assert.notOk(page.calendar.controls.userContextFilter.isPresent);
+ });
- const pickSessionType = async function (i) {
- return await click(find(`.sessiontypefilter li:nth-of-type(${i}) [data-test-target]`));
- };
+ test('user context filters are present on user calendar for privileged users', async function (assert) {
+ assert.expect(1);
+ await setupAuthentication({ school: this.school }, true);
+ await page.visit({ show: 'calendar' });
+ await percySnapshot(assert);
+ assert.ok(page.calendar.controls.userContextFilter.isPresent);
+ });
+
+ test('user context filters are not present on school calendar', async function (assert) {
+ assert.expect(2);
+ await setupAuthentication({ school: this.school }, true);
+ await page.visit({ show: 'calendar' });
+ assert.ok(page.calendar.controls.userContextFilter.isPresent);
+ await page.calendar.controls.mySchedule.toggle.secondLabel.click();
+ await percySnapshot(assert);
+ assert.notOk(page.calendar.controls.userContextFilter.isPresent);
+ });
+
+ test('test user context filters', async function (assert) {
+ assert.expect(11);
+ this.user = await setupAuthentication({ school: this.school }, true);
+ const day = DateTime.fromObject({
+ month: 4,
+ day: 4,
+ year: 2004,
+ hour: 4,
+ minute: 0,
+ second: 7,
+ });
+ freezeDateAt(day.toJSDate());
+ this.server.create('userevent', {
+ user: this.user.id,
+ startDate: day.toJSDate(),
+ endDate: day.plus({ hour: 1 }).toJSDate(),
+ offering: 1,
+ userContexts: ['learner'],
+ });
+ this.server.create('userevent', {
+ user: this.user.id,
+ startDate: day.plus({ hour: 1 }).toJSDate(),
+ endDate: day.plus({ hour: 2 }).toJSDate(),
+ offering: 2,
+ userContexts: ['instructor'],
+ });
+ this.server.create('userevent', {
+ user: this.user.id,
+ startDate: day.plus({ hour: 2 }).toJSDate(),
+ endDate: day.plus({ hour: 3 }).toJSDate(),
+ offering: 3,
+ userContexts: ['course director'],
+ });
+ await page.visit({ show: 'calendar' });
+ assert.strictEqual(page.calendar.calendar.weekly.events.length, 3);
+ assert.strictEqual(page.calendar.calendar.weekly.events[0].text, '04:00 AM event 0');
+ assert.strictEqual(page.calendar.calendar.weekly.events[1].text, '05:00 AM event 1');
+ assert.strictEqual(page.calendar.calendar.weekly.events[2].text, '06:00 AM event 2');
+ await page.calendar.controls.userContextFilter.learning.toggle();
+ assert.strictEqual(page.calendar.calendar.weekly.events.length, 1);
+ assert.strictEqual(page.calendar.calendar.weekly.events[0].text, '04:00 AM event 0');
+ await page.calendar.controls.userContextFilter.instructing.toggle();
+ assert.strictEqual(page.calendar.calendar.weekly.events.length, 1);
+ assert.strictEqual(page.calendar.calendar.weekly.events[0].text, '05:00 AM event 1');
+ await page.calendar.controls.userContextFilter.admin.toggle();
+ assert.strictEqual(page.calendar.calendar.weekly.events.length, 1);
+ assert.strictEqual(page.calendar.calendar.weekly.events[0].text, '06:00 AM event 2');
+ await page.calendar.controls.userContextFilter.admin.toggle();
+ assert.strictEqual(page.calendar.calendar.weekly.events.length, 3);
+ });
+
+ test('user context filter selections persist across page reloads', async function (assert) {
+ assert.expect(27);
+ this.user = await setupAuthentication({ school: this.school }, true);
+ const day = DateTime.fromObject({
+ month: 4,
+ day: 4,
+ year: 2004,
+ hour: 4,
+ minute: 0,
+ second: 7,
+ });
+ freezeDateAt(day.toJSDate());
+ this.server.create('userevent', {
+ user: this.user.id,
+ startDate: day.toJSDate(),
+ endDate: day.plus({ hour: 1 }).toJSDate(),
+ offering: 1,
+ userContexts: ['learner'],
+ });
+ this.server.create('userevent', {
+ user: this.user.id,
+ startDate: day.plus({ hour: 1 }).toJSDate(),
+ endDate: day.plus({ hour: 2 }).toJSDate(),
+ offering: 2,
+ userContexts: ['instructor'],
+ });
+ this.server.create('userevent', {
+ user: this.user.id,
+ startDate: day.plus({ hour: 2 }).toJSDate(),
+ endDate: day.plus({ hour: 3 }).toJSDate(),
+ offering: 3,
+ userContexts: ['course director'],
+ });
+ await page.visit({ show: 'calendar' });
+ assert.ok(page.calendar.controls.userContextFilter.learning.isActive);
+ assert.ok(page.calendar.controls.userContextFilter.instructing.isActive);
+ assert.ok(page.calendar.controls.userContextFilter.admin.isActive);
+
+ await page.calendar.controls.userContextFilter.learning.toggle();
+ assert.ok(page.calendar.controls.userContextFilter.learning.isActive);
+ assert.notOk(page.calendar.controls.userContextFilter.instructing.isActive);
+ assert.notOk(page.calendar.controls.userContextFilter.admin.isActive);
+
+ await page.visit({ show: 'calendar' });
+ assert.ok(page.calendar.controls.userContextFilter.learning.isActive);
+ assert.notOk(page.calendar.controls.userContextFilter.instructing.isActive);
+ assert.notOk(page.calendar.controls.userContextFilter.admin.isActive);
+
+ await page.calendar.controls.userContextFilter.instructing.toggle();
+ assert.notOk(page.calendar.controls.userContextFilter.learning.isActive);
+ assert.ok(page.calendar.controls.userContextFilter.instructing.isActive);
+ assert.notOk(page.calendar.controls.userContextFilter.admin.isActive);
+
+ await page.visit({ show: 'calendar' });
+ assert.notOk(page.calendar.controls.userContextFilter.learning.isActive);
+ assert.ok(page.calendar.controls.userContextFilter.instructing.isActive);
+ assert.notOk(page.calendar.controls.userContextFilter.admin.isActive);
+
+ await page.calendar.controls.userContextFilter.admin.toggle();
+ assert.notOk(page.calendar.controls.userContextFilter.learning.isActive);
+ assert.notOk(page.calendar.controls.userContextFilter.instructing.isActive);
+ assert.ok(page.calendar.controls.userContextFilter.admin.isActive);
+
+ await page.visit({ show: 'calendar' });
+ assert.notOk(page.calendar.controls.userContextFilter.learning.isActive);
+ assert.notOk(page.calendar.controls.userContextFilter.instructing.isActive);
+ assert.ok(page.calendar.controls.userContextFilter.admin.isActive);
+
+ await page.calendar.controls.userContextFilter.admin.toggle();
+ assert.ok(page.calendar.controls.userContextFilter.learning.isActive);
+ assert.ok(page.calendar.controls.userContextFilter.instructing.isActive);
+ assert.ok(page.calendar.controls.userContextFilter.admin.isActive);
+
+ await page.visit({ show: 'calendar' });
+ assert.ok(page.calendar.controls.userContextFilter.learning.isActive);
+ assert.ok(page.calendar.controls.userContextFilter.instructing.isActive);
+ assert.ok(page.calendar.controls.userContextFilter.admin.isActive);
+ });
test('test session type filter', async function (assert) {
const today = DateTime.fromObject({ hour: 8, minute: 8, second: 8 });
@@ -534,26 +672,18 @@ module('Acceptance | Dashboard Calendar', function (hooks) {
sessionTypeId: 2,
});
await page.visit({ show: 'calendar', view: 'week' });
- await showFilters();
- assert.strictEqual(page.calendar.weeklyCalendar.events.length, 2);
- await pickSessionType(1);
- assert.strictEqual(page.calendar.weeklyCalendar.events.length, 1);
- await pickSessionType(2);
- assert.strictEqual(page.calendar.weeklyCalendar.events.length, 2);
-
- await pickSessionType(1);
- await pickSessionType(2);
- await pickSessionType(3);
- assert.strictEqual(page.calendar.weeklyCalendar.events.length, 0);
- });
-
- const pickCourseLevel = async function (i) {
- return await click(find(`.courselevelfilter li:nth-of-type(${i}) [data-test-target]`));
- };
- const clearCourseLevels = async function () {
- const selected = findAll('.courselevelfilter [data-test-checked]');
- await map(selected, (e) => click(e));
- };
+ await page.calendar.controls.showFilters.toggle.secondLabel.click();
+ assert.strictEqual(page.calendar.calendar.weekly.events.length, 2);
+ await page.calendar.controls.filters.sessionTypesFilter.sessionTypes[0].click();
+ assert.strictEqual(page.calendar.calendar.weekly.events.length, 1);
+ await page.calendar.controls.filters.sessionTypesFilter.sessionTypes[1].click();
+ assert.strictEqual(page.calendar.calendar.weekly.events.length, 2);
+
+ await page.calendar.controls.filters.sessionTypesFilter.sessionTypes[0].click();
+ await page.calendar.controls.filters.sessionTypesFilter.sessionTypes[1].click();
+ await page.calendar.controls.filters.sessionTypesFilter.sessionTypes[2].click();
+ assert.strictEqual(page.calendar.calendar.weekly.events.length, 0);
+ });
test('test course level filter', async function (assert) {
const today = DateTime.fromObject({ hour: 8, minute: 8, second: 8 });
@@ -570,21 +700,15 @@ module('Acceptance | Dashboard Calendar', function (hooks) {
courseLevel: 1,
});
await page.visit({ show: 'calendar', view: 'week' });
- await showFilters();
- await chooseDetailFilter();
- assert.strictEqual(page.calendar.weeklyCalendar.events.length, 2);
- await pickCourseLevel(1);
- assert.strictEqual(page.calendar.weeklyCalendar.events.length, 2);
- await clearCourseLevels();
- await pickCourseLevel(3);
- assert.strictEqual(page.calendar.weeklyCalendar.events.length, 0);
- });
-
- const pickCohort = async function (i) {
- return await click(
- find(`[data-test-cohort-calendar-filter] li:nth-of-type(${i}) [data-test-target]`),
- );
- };
+ await page.calendar.controls.showFilters.toggle.secondLabel.click();
+ await page.calendar.controls.showCourseFilters.toggle.secondLabel.click();
+ assert.strictEqual(page.calendar.calendar.weekly.events.length, 2);
+ await page.calendar.controls.filters.courseLevelsFilter.courseLevels[0].click();
+ assert.strictEqual(page.calendar.calendar.weekly.events.length, 2);
+ await page.calendar.filterTags.clearAll.click();
+ await page.calendar.controls.filters.courseLevelsFilter.courseLevels[1].click();
+ assert.strictEqual(page.calendar.calendar.weekly.events.length, 0);
+ });
test('test cohort filter', async function (assert) {
const today = DateTime.fromObject({ hour: 8, minute: 8, second: 8 });
@@ -601,30 +725,17 @@ module('Acceptance | Dashboard Calendar', function (hooks) {
cohorts: [{ id: 1 }],
});
await page.visit({ show: 'calendar', view: 'week' });
- await showFilters();
- await chooseDetailFilter();
- assert.strictEqual(page.calendar.weeklyCalendar.events.length, 2);
- await pickCohort(2);
- assert.strictEqual(page.calendar.weeklyCalendar.events.length, 2);
-
- await pickCohort(1);
- await pickCohort(2);
- assert.strictEqual(page.calendar.weeklyCalendar.events.length, 0);
- });
+ await page.calendar.controls.showFilters.toggle.secondLabel.click();
+ await page.calendar.controls.showCourseFilters.toggle.secondLabel.click();
+ assert.strictEqual(page.calendar.calendar.weekly.events.length, 2);
- const chooseDetailFilter = async function () {
- return await click(find(findAll('.togglecoursefilters label')[1]));
- };
+ await page.calendar.controls.filters.cohortsFilter.cohorts[1].toggle();
+ assert.strictEqual(page.calendar.calendar.weekly.events.length, 2);
- const pickCourse = async function (i) {
- return await click(
- find(`[data-test-courses-calendar-filter] li:nth-of-type(${i}) [data-test-target]`),
- );
- };
- const clearCourses = async function () {
- const selected = findAll('[data-test-courses-calendar-filter] [data-test-checked]');
- await map(selected, (e) => click(e));
- };
+ await page.calendar.controls.filters.cohortsFilter.cohorts[0].toggle();
+ await page.calendar.controls.filters.cohortsFilter.cohorts[1].toggle();
+ assert.strictEqual(page.calendar.calendar.weekly.events.length, 0);
+ });
test('test course filter', async function (assert) {
const today = DateTime.fromObject({ hour: 8, minute: 8, second: 8 });
@@ -647,13 +758,13 @@ module('Acceptance | Dashboard Calendar', function (hooks) {
course: 1,
});
await page.visit({ show: 'calendar', view: 'week' });
- await showFilters();
- assert.strictEqual(page.calendar.weeklyCalendar.events.length, 3);
- await pickCourse(1);
- assert.strictEqual(page.calendar.weeklyCalendar.events.length, 2);
- await clearCourses();
- await pickCourse(2);
- assert.strictEqual(page.calendar.weeklyCalendar.events.length, 1);
+ await page.calendar.controls.showFilters.toggle.secondLabel.click();
+ assert.strictEqual(page.calendar.calendar.weekly.events.length, 3);
+ await page.calendar.controls.filters.coursesFilter.years[0].courses[0].toggle();
+ assert.strictEqual(page.calendar.calendar.weekly.events.length, 2);
+ await page.calendar.controls.filters.coursesFilter.years[0].courses[0].toggle();
+ await page.calendar.controls.filters.coursesFilter.years[0].courses[1].toggle();
+ assert.strictEqual(page.calendar.calendar.weekly.events.length, 1);
});
test('test course and session type filter together', async function (assert) {
@@ -680,19 +791,19 @@ module('Acceptance | Dashboard Calendar', function (hooks) {
sessionTypeId: 2,
});
await page.visit({ show: 'calendar', view: 'week' });
- await showFilters();
-
- assert.strictEqual(page.calendar.weeklyCalendar.events.length, 3);
- await pickCourse(1);
- assert.strictEqual(page.calendar.weeklyCalendar.events.length, 2);
- await clearCourses();
- await pickCourse(1);
- await pickSessionType(1);
- assert.strictEqual(page.calendar.weeklyCalendar.events.length, 1);
+ await page.calendar.controls.showFilters.toggle.secondLabel.click();
+
+ assert.strictEqual(page.calendar.calendar.weekly.events.length, 3);
+ await page.calendar.controls.filters.coursesFilter.years[0].courses[0].toggle();
+ assert.strictEqual(page.calendar.calendar.weekly.events.length, 2);
+ await page.calendar.controls.filters.coursesFilter.years[0].courses[0].toggle();
+ await page.calendar.controls.filters.coursesFilter.years[0].courses[0].toggle();
+ await page.calendar.controls.filters.sessionTypesFilter.sessionTypes[0].click();
+ assert.strictEqual(page.calendar.calendar.weekly.events.length, 1);
});
test('clear all filters', async function (assert) {
- assert.expect(9);
+ assert.expect(18);
const vocabulary = this.server.create('vocabulary', {
school: this.school,
});
@@ -700,98 +811,116 @@ module('Acceptance | Dashboard Calendar', function (hooks) {
vocabulary,
});
- const clearFilter = '.filters-clear-filters';
- const sessiontype = '.sessiontypefilter li:nth-of-type(1) input';
- const course = '[data-test-courses-calendar-filter] li:nth-of-type(1) input';
- const term = '.vocabularyfilter li:nth-of-type(1) input';
-
await page.visit({ show: 'calendar', view: 'week' });
- await showFilters();
- assert.ok(isEmpty(find(clearFilter)), 'clear filter button is inactive');
-
- await click(sessiontype);
- await click(course);
- await click(term);
+ await page.calendar.controls.showFilters.toggle.secondLabel.click();
+ assert.notOk(page.calendar.filterTags.clearAll.isPresent);
+ assert.strictEqual(page.calendar.filterTags.tags.length, 0);
+
+ await page.calendar.controls.filters.sessionTypesFilter.sessionTypes[0].click();
+ assert.strictEqual(page.calendar.filterTags.tags.length, 1);
+ await page.calendar.controls.filters.coursesFilter.years[0].courses[0].toggle();
+ assert.strictEqual(page.calendar.filterTags.tags.length, 2);
+ await page.calendar.controls.filters.vocabularyFilter.vocabularies[0].selectedTermTree.checkboxes[0].click();
+ assert.strictEqual(page.calendar.filterTags.tags.length, 3);
+
+ assert.ok(page.calendar.filterTags.clearAll.isPresent);
+ assert.strictEqual(page.calendar.filterTags.clearAll.text, 'Clear Filters');
+ assert.strictEqual(page.calendar.filterTags.tags[0].text, '2015 course 0');
+ assert.strictEqual(page.calendar.filterTags.tags[1].text, 'session type 0');
+ assert.strictEqual(page.calendar.filterTags.tags[2].text, 'Vocabulary 1 > term 0');
+ assert.ok(page.calendar.controls.filters.sessionTypesFilter.sessionTypes[0].isChecked);
+ assert.ok(page.calendar.controls.filters.coursesFilter.years[0].courses[0].isChecked);
+ assert.ok(
+ page.calendar.controls.filters.vocabularyFilter.vocabularies[0].selectedTermTree.checkboxes[0]
+ .isChecked,
+ );
- assert.dom(clearFilter).hasText('Clear Filters', 'clear filter button is active');
- assert.dom(sessiontype).isChecked('filter is checked');
- assert.dom(course).isChecked('filter is checked');
- assert.dom(term).isChecked('filter is checked');
+ await page.calendar.filterTags.clearAll.click();
- await click(clearFilter);
- assert.ok(isEmpty(find(clearFilter)), 'clear filter button is inactive');
- assert.dom(sessiontype).isNotChecked('filter is unchecked');
- assert.dom(course).isNotChecked('filter is unchecked');
- assert.dom(term).isNotChecked('filter is unchecked');
+ assert.notOk(page.calendar.filterTags.clearAll.isPresent);
+ assert.strictEqual(page.calendar.filterTags.tags.length, 0);
+ assert.notOk(page.calendar.controls.filters.sessionTypesFilter.sessionTypes[0].isChecked);
+ assert.notOk(page.calendar.controls.filters.coursesFilter.years[0].courses[0].isChecked);
+ assert.notOk(
+ page.calendar.controls.filters.vocabularyFilter.vocabularies[0].selectedTermTree.checkboxes[0]
+ .isChecked,
+ );
});
test('clear all detail filters', async function (assert) {
- const clearFilter = '.filters-clear-filters';
- const sessiontype = '.sessiontypefilter li:nth-of-type(1) input';
- const courselevel = '.courselevelfilter li:nth-of-type(1) input';
- const cohort = '[data-test-cohort-calendar-filter] li:nth-of-type(1) input';
-
await page.visit({ show: 'calendar', view: 'week' });
- await showFilters();
- await chooseDetailFilter();
- assert.ok(isEmpty(find(clearFilter)), 'clear filter button is inactive');
-
- await click(sessiontype);
- await click(courselevel);
- await click(cohort);
-
- assert.dom(clearFilter).hasText('Clear Filters', 'clear filter button is active');
- assert.dom(sessiontype).isChecked('filter is checked');
- assert.dom(courselevel).isChecked('filter is checked');
- assert.dom(cohort).isChecked('filter is checked');
-
- await click(clearFilter);
- assert.ok(isEmpty(find(clearFilter)), 'clear filter button is inactive');
- assert.dom(sessiontype).isNotChecked('filter is unchecked');
- assert.dom(courselevel).isNotChecked('filter is unchecked');
- assert.dom(cohort).isNotChecked('filter is unchecked');
+ await page.calendar.controls.showFilters.toggle.secondLabel.click();
+ await page.calendar.controls.showCourseFilters.toggle.secondLabel.click();
+ assert.notOk(page.calendar.filterTags.clearAll.isPresent);
+
+ await page.calendar.controls.filters.sessionTypesFilter.sessionTypes[0].click();
+ assert.strictEqual(page.calendar.filterTags.tags.length, 1);
+ await page.calendar.controls.filters.courseLevelsFilter.courseLevels[0].click();
+ assert.strictEqual(page.calendar.filterTags.tags.length, 2);
+ await page.calendar.controls.filters.cohortsFilter.cohorts[0].toggle();
+ assert.strictEqual(page.calendar.filterTags.tags.length, 3);
+
+ assert.ok(page.calendar.filterTags.clearAll.isPresent);
+ assert.strictEqual(page.calendar.filterTags.tags[0].text, 'cohort 1 program 0');
+ assert.strictEqual(page.calendar.filterTags.tags[1].text, 'Course Level 1');
+ assert.strictEqual(page.calendar.filterTags.tags[2].text, 'session type 0');
+ assert.ok(page.calendar.controls.filters.sessionTypesFilter.sessionTypes[0].isChecked);
+ assert.ok(page.calendar.controls.filters.courseLevelsFilter.courseLevels[0].isChecked);
+ assert.ok(page.calendar.controls.filters.cohortsFilter.cohorts[0].isChecked);
+
+ await page.calendar.filterTags.clearAll.click();
+
+ assert.notOk(page.calendar.filterTags.clearAll.isPresent);
+ assert.notOk(page.calendar.controls.filters.sessionTypesFilter.sessionTypes[0].isChecked);
+ assert.notOk(page.calendar.controls.filters.courseLevelsFilter.courseLevels[0].isChecked);
+ assert.notOk(page.calendar.controls.filters.cohortsFilter.cohorts[0].isChecked);
});
test('filter tags work properly', async function (assert) {
- const sessiontype = '.sessiontypefilter li:nth-of-type(1) [data-test-target]';
- const courselevel = '.courselevelfilter li:nth-of-type(1) [data-test-target]';
- const cohort = '[data-test-cohort-calendar-filter] li:nth-of-type(2) [data-test-target]';
-
- const filtersList = '.filters-list';
- const clearFilter = '.filters-clear-filters';
-
- function getTagText(n) {
- return find(`.filter-tag:nth-of-type(${n + 1})`).textContent.trim();
- }
-
- async function clickTag(n) {
- return await click(`.filter-tag:nth-of-type(${n + 1})`);
- }
-
await page.visit({ show: 'calendar', view: 'week' });
- await showFilters();
- await chooseDetailFilter();
- assert.ok(isEmpty(find(filtersList)), 'filter tags list is inactive');
-
- await click(sessiontype);
- await click(courselevel);
- await click(cohort);
- assert.strictEqual(getTagText(0), 'cohort 0 program 0', 'filter tag is active');
- assert.strictEqual(getTagText(1), 'Course Level 1', 'filter tag is active');
- assert.strictEqual(getTagText(2), 'session type 0', 'filter tag is active');
-
- await clickTag(1);
- assert.dom(courselevel).isNotChecked('filter is unchecked');
- assert.strictEqual(getTagText(0), 'cohort 0 program 0', 'filter tag is active');
- assert.strictEqual(getTagText(1), 'session type 0', 'filter tag is active');
-
- await clickTag(0);
- assert.strictEqual(getTagText(0), 'session type 0', 'filter tag is active');
-
- await click(clearFilter);
- assert.ok(isEmpty(find(filtersList)), 'filter tags list is inactive');
- assert.dom(sessiontype).isNotChecked('filter is unchecked');
- assert.dom(cohort).isNotChecked('filter is unchecked');
+ await page.calendar.controls.showFilters.toggle.secondLabel.click();
+ await page.calendar.controls.showCourseFilters.toggle.secondLabel.click();
+ assert.notOk(page.calendar.filterTags.clearAll.isPresent);
+
+ await page.calendar.controls.filters.sessionTypesFilter.sessionTypes[0].click();
+ await page.calendar.controls.filters.courseLevelsFilter.courseLevels[0].click();
+ await page.calendar.controls.filters.cohortsFilter.cohorts[0].toggle();
+
+ assert.ok(page.calendar.filterTags.clearAll.isPresent);
+ assert.strictEqual(page.calendar.filterTags.tags.length, 3);
+ assert.strictEqual(page.calendar.filterTags.tags[0].text, 'cohort 1 program 0');
+ assert.strictEqual(page.calendar.filterTags.tags[1].text, 'Course Level 1');
+ assert.strictEqual(page.calendar.filterTags.tags[2].text, 'session type 0');
+ assert.ok(page.calendar.controls.filters.sessionTypesFilter.sessionTypes[0].isChecked);
+ assert.ok(page.calendar.controls.filters.courseLevelsFilter.courseLevels[0].isChecked);
+ assert.ok(page.calendar.controls.filters.cohortsFilter.cohorts[0].isChecked);
+
+ await page.calendar.filterTags.tags[0].click();
+
+ assert.ok(page.calendar.filterTags.clearAll.isPresent);
+ assert.strictEqual(page.calendar.filterTags.tags.length, 2);
+ assert.strictEqual(page.calendar.filterTags.tags[0].text, 'Course Level 1');
+ assert.strictEqual(page.calendar.filterTags.tags[1].text, 'session type 0');
+ assert.ok(page.calendar.controls.filters.sessionTypesFilter.sessionTypes[0].isChecked);
+ assert.ok(page.calendar.controls.filters.courseLevelsFilter.courseLevels[0].isChecked);
+ assert.notOk(page.calendar.controls.filters.cohortsFilter.cohorts[0].isChecked);
+
+ await page.calendar.filterTags.tags[0].click();
+
+ assert.ok(page.calendar.filterTags.clearAll.isPresent);
+ assert.strictEqual(page.calendar.filterTags.tags.length, 1);
+ assert.strictEqual(page.calendar.filterTags.tags[0].text, 'session type 0');
+ assert.ok(page.calendar.controls.filters.sessionTypesFilter.sessionTypes[0].isChecked);
+ assert.notOk(page.calendar.controls.filters.courseLevelsFilter.courseLevels[0].isChecked);
+ assert.notOk(page.calendar.controls.filters.cohortsFilter.cohorts[0].isChecked);
+
+ await page.calendar.filterTags.tags[0].click();
+
+ assert.notOk(page.calendar.filterTags.clearAll.isPresent);
+ assert.strictEqual(page.calendar.filterTags.tags.length, 0);
+ assert.notOk(page.calendar.controls.filters.sessionTypesFilter.sessionTypes[0].isChecked);
+ assert.notOk(page.calendar.controls.filters.courseLevelsFilter.courseLevels[0].isChecked);
+ assert.notOk(page.calendar.controls.filters.cohortsFilter.cohorts[0].isChecked);
});
test('calendar is active in dashboard navigation', async function (assert) {
@@ -801,53 +930,6 @@ module('Acceptance | Dashboard Calendar', function (hooks) {
assert.notOk(page.navigation.week.isActive);
});
- test('week summary displays the whole week', async function (assert) {
- assert.expect(3);
- const startOfTheWeek = DateTime.fromJSDate(
- this.owner.lookup('service:locale-days').firstDayOfThisWeek,
- ).set({ minute: 2 });
- const endOfTheWeek = DateTime.fromJSDate(
- this.owner.lookup('service:locale-days').lastDayOfThisWeek,
- ).set({ hour: 22, minute: 5 });
-
- this.server.create('userevent', {
- user: this.user.id,
- startDate: startOfTheWeek.toJSDate(),
- endDate: startOfTheWeek.plus({ hour: 1 }).toJSDate(),
- offering: 1,
- isPublished: true,
- });
- this.server.create('userevent', {
- user: this.user.id,
- startDate: endOfTheWeek.toJSDate(),
- endDate: endOfTheWeek.plus({ hour: 1 }).toJSDate(),
- offering: 2,
- isPublished: true,
- });
- const dashboard = '.dashboard-week';
- const events = `${dashboard} .event`;
-
- await visit('/dashboard/week');
-
- const eventBLocks = findAll(events);
- assert.strictEqual(eventBLocks.length, 2);
- const options = {
- weekday: 'long',
- hour: 'numeric',
- minute: 'numeric',
- };
- assert
- .dom(eventBLocks[0])
- .hasText('event 0 ' + this.intl.formatTime(startOfTheWeek.toJSDate(), options));
- assert
- .dom(eventBLocks[1])
- .hasText('event 1 ' + this.intl.formatTime(endOfTheWeek.toJSDate(), options));
- });
-
- const pickTerm = async function (i) {
- return await click(find(`.vocabularyfilter [data-test-filter-checkbox-target-id="${i}"]`));
- };
-
test('test term filter', async function (assert) {
const vocabulary = this.server.create('vocabulary', {
school: this.school,
@@ -873,13 +955,13 @@ module('Acceptance | Dashboard Calendar', function (hooks) {
sessionTerms: [{ id: 1 }],
});
await page.visit({ show: 'calendar', view: 'week' });
- await showFilters();
- assert.strictEqual(page.calendar.weeklyCalendar.events.length, 2);
- await pickTerm(1);
- assert.strictEqual(page.calendar.weeklyCalendar.events.length, 2);
- await pickTerm(1);
- await pickTerm(2);
- assert.strictEqual(page.calendar.weeklyCalendar.events.length, 0);
+ await page.calendar.controls.showFilters.toggle.secondLabel.click();
+ assert.strictEqual(page.calendar.calendar.weekly.events.length, 2);
+ await page.calendar.controls.filters.vocabularyFilter.vocabularies[0].selectedTermTree.checkboxes[0].click();
+ assert.strictEqual(page.calendar.calendar.weekly.events.length, 2);
+ await page.calendar.controls.filters.vocabularyFilter.vocabularies[0].selectedTermTree.checkboxes[0].click();
+ await page.calendar.controls.filters.vocabularyFilter.vocabularies[0].selectedTermTree.checkboxes[1].click();
+ assert.strictEqual(page.calendar.calendar.weekly.events.length, 0);
});
test('clear vocab filter #3450', async function (assert) {
@@ -903,23 +985,21 @@ module('Acceptance | Dashboard Calendar', function (hooks) {
endDate: today.plus({ hour: 1 }).toJSDate(),
sessionTerms: [],
});
- const filters = '.filter-tags .filter-tag';
- const filter = `${filters}:nth-of-type(1)`;
await page.visit({ show: 'calendar', view: 'week' });
- await showFilters();
- assert.strictEqual(page.calendar.weeklyCalendar.events.length, 2);
- await pickTerm(1);
- assert.strictEqual(page.calendar.weeklyCalendar.events.length, 1);
-
- assert.dom(filters).exists({ count: 1 });
- await click(filter);
- assert.dom(filters).doesNotExist();
- assert.strictEqual(page.calendar.weeklyCalendar.events.length, 2);
+ await page.calendar.controls.showFilters.toggle.secondLabel.click();
+ assert.strictEqual(page.calendar.calendar.weekly.events.length, 2);
+ await page.calendar.controls.filters.vocabularyFilter.vocabularies[0].selectedTermTree.checkboxes[0].click();
+ assert.strictEqual(page.calendar.calendar.weekly.events.length, 1);
+
+ assert.strictEqual(page.calendar.filterTags.tags.length, 1);
+ await page.calendar.filterTags.tags[0].click();
+ assert.strictEqual(page.calendar.filterTags.tags.length, 0);
+ assert.strictEqual(page.calendar.calendar.weekly.events.length, 2);
});
test('test tooltip', async function (assert) {
- assert.expect(1);
+ assert.expect(2);
const november11th = DateTime.fromObject({ month: 11, day: 11, hour: 8, minute: 8, second: 8 });
this.server.create('userevent', {
user: this.user.id,
@@ -928,9 +1008,11 @@ module('Acceptance | Dashboard Calendar', function (hooks) {
offering: 1,
});
await page.visit({ show: 'calendar', view: 'week', date: november11th.toFormat('yyyy-LL-dd') });
- await triggerEvent('[data-test-weekly-calendar-event]', 'mouseover');
+ assert.notOk(page.calendar.calendar.weekly.events[0].tooltip.isPresent);
+
+ await page.calendar.calendar.weekly.events[0].mouseOver();
await percySnapshot(assert);
- assert.dom('[data-test-ilios-calendar-event-tooltip]').exists();
+ assert.ok(page.calendar.calendar.weekly.events[0].tooltip.isPresent);
});
test('visit with course filters open #5098', async function (assert) {
@@ -947,7 +1029,7 @@ module('Acceptance | Dashboard Calendar', function (hooks) {
showFilters: 'true',
courseFilters: 'true',
});
- assert.strictEqual(page.calendar.weeklyCalendar.events.length, 1);
+ assert.strictEqual(page.calendar.calendar.weekly.events.length, 1);
});
test('visit with detail filters open #5098', async function (assert) {
@@ -964,7 +1046,7 @@ module('Acceptance | Dashboard Calendar', function (hooks) {
showFilters: 'true',
courseFilters: 'false',
});
- assert.strictEqual(page.calendar.weeklyCalendar.events.length, 1);
+ assert.strictEqual(page.calendar.calendar.weekly.events.length, 1);
});
test('transition from weekly calendar to day calendar when multi-event is clicked', async function (assert) {
@@ -985,13 +1067,13 @@ module('Acceptance | Dashboard Calendar', function (hooks) {
offering: 1,
});
await page.visit({ show: 'calendar', view: 'week' });
- assert.strictEqual(page.calendar.weeklyCalendar.events.length, 1);
- await page.calendar.weeklyCalendar.events[0].click();
+ assert.strictEqual(page.calendar.calendar.weekly.events.length, 1);
+ await page.calendar.calendar.weekly.events[0].click();
assert.strictEqual(
currentURL(),
`/dashboard/calendar?date=${today.toFormat('yyyy-MM-dd')}&view=day`,
);
- assert.strictEqual(page.calendar.dailyCalendar.events.length, 2);
+ assert.strictEqual(page.calendar.calendar.daily.events.length, 2);
});
test('transition from monthly calendar to day calendar when multi-event is clicked', async function (assert) {
@@ -1012,12 +1094,12 @@ module('Acceptance | Dashboard Calendar', function (hooks) {
offering: 1,
});
await page.visit({ show: 'calendar', view: 'month' });
- assert.strictEqual(page.calendar.monthlyCalendar.events.length, 1);
- await page.calendar.monthlyCalendar.events[0].click();
+ assert.strictEqual(page.calendar.calendar.monthly.events.length, 1);
+ await page.calendar.calendar.monthly.events[0].click();
assert.strictEqual(
currentURL(),
`/dashboard/calendar?date=${today.toFormat('yyyy-MM-dd')}&view=day`,
);
- assert.strictEqual(page.calendar.dailyCalendar.events.length, 2);
+ assert.strictEqual(page.calendar.calendar.daily.events.length, 2);
});
});
diff --git a/packages/frontend/tests/acceptance/dashboard/week-test.js b/packages/frontend/tests/acceptance/dashboard/week-test.js
index 626fd9cfe8..8a59c2c55d 100644
--- a/packages/frontend/tests/acceptance/dashboard/week-test.js
+++ b/packages/frontend/tests/acceptance/dashboard/week-test.js
@@ -1,4 +1,4 @@
-import { currentRouteName } from '@ember/test-helpers';
+import { currentRouteName, findAll } from '@ember/test-helpers';
import { DateTime } from 'luxon';
import { module, test } from 'qunit';
import { setupAuthentication, freezeDateAt, unfreezeDate } from 'ilios-common';
@@ -9,9 +9,11 @@ import percySnapshot from '@percy/ember';
module('Acceptance | Dashboard Week at a Glance', function (hooks) {
setupApplicationTest(hooks);
+
const today = DateTime.fromObject({ hour: 8 });
hooks.beforeEach(async function () {
+ this.intl = this.owner.lookup('service:intl');
this.school = this.server.create('school');
this.user = await setupAuthentication({ school: this.school });
});
@@ -133,6 +135,51 @@ module('Acceptance | Dashboard Week at a Glance', function (hooks) {
assert.ok(true, 'no a11y errors found!');
});
+ test('week summary displays the whole week', async function (assert) {
+ assert.expect(3);
+ const startOfTheWeek = DateTime.fromJSDate(
+ this.owner.lookup('service:locale-days').firstDayOfThisWeek,
+ ).set({ minute: 2 });
+ const endOfTheWeek = DateTime.fromJSDate(
+ this.owner.lookup('service:locale-days').lastDayOfThisWeek,
+ ).set({ hour: 22, minute: 5 });
+
+ this.server.create('userevent', {
+ user: this.user.id,
+ startDate: startOfTheWeek.toJSDate(),
+ endDate: startOfTheWeek.plus({ hour: 1 }).toJSDate(),
+ offering: 1,
+ isPublished: true,
+ });
+ this.server.create('userevent', {
+ user: this.user.id,
+ startDate: endOfTheWeek.toJSDate(),
+ endDate: endOfTheWeek.plus({ hour: 1 }).toJSDate(),
+ offering: 2,
+ isPublished: true,
+ });
+ const dashboard = '.dashboard-week';
+ const events = `${dashboard} .event`;
+
+ await page.visit();
+
+ const eventBLocks = findAll(events);
+ assert.strictEqual(eventBLocks.length, 2);
+ const options = {
+ weekday: 'long',
+ hour: 'numeric',
+ minute: 'numeric',
+ };
+ assert.strictEqual(
+ page.week.weekGlance.events[0].text,
+ 'event 0 ' + this.intl.formatTime(startOfTheWeek.toJSDate(), options),
+ );
+ assert.strictEqual(
+ page.week.weekGlance.events[1].text,
+ 'event 1 ' + this.intl.formatTime(endOfTheWeek.toJSDate(), options),
+ );
+ });
+
test('calendar is active in dashboard navigation', async function (assert) {
await page.visit();
assert.notOk(page.navigation.calendar.isActive);
diff --git a/packages/ilios-common/.lint-todo b/packages/ilios-common/.lint-todo
index 223e453d84..d19123492d 100644
--- a/packages/ilios-common/.lint-todo
+++ b/packages/ilios-common/.lint-todo
@@ -77,8 +77,6 @@ add|ember-template-lint|no-at-ember-render-modifiers|4|2|4|2|23cd787c79c34a628da
add|ember-template-lint|no-at-ember-render-modifiers|4|2|4|2|23cd787c79c34a628dadb6e96dd4004d42eebb79|1720137600000|1722729600000|1725321600000|addon/components/course/visualize-instructors.hbs
add|ember-template-lint|no-at-ember-render-modifiers|4|2|4|2|23cd787c79c34a628dadb6e96dd4004d42eebb79|1720137600000|1722729600000|1725321600000|addon/components/course/visualize-session-type.hbs
add|ember-template-lint|no-at-ember-render-modifiers|4|2|4|2|23cd787c79c34a628dadb6e96dd4004d42eebb79|1720137600000|1722729600000|1725321600000|addon/components/course/visualize-term.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|105|6|105|6|1e67fb6d3c62d7707918389c0b1b072c756afbd2|1720137600000|1722729600000|1725321600000|addon/components/dashboard/calendar.hbs
-add|ember-template-lint|no-at-ember-render-modifiers|106|6|106|6|448d60c76fbd9ee5aeb7219dde978518fcba1aea|1720137600000|1722729600000|1725321600000|addon/components/dashboard/calendar.hbs
add|ember-template-lint|no-at-ember-render-modifiers|3|2|3|2|9b56ba661238d88b20a82b6f8647d8e16a07b05f|1720137600000|1722729600000|1725321600000|addon/components/dashboard/courses-calendar-filter.hbs
add|ember-template-lint|no-at-ember-render-modifiers|4|2|4|2|23cd787c79c34a628dadb6e96dd4004d42eebb79|1720137600000|1722729600000|1725321600000|addon/components/dashboard/courses-calendar-filter.hbs
add|ember-template-lint|no-at-ember-render-modifiers|5|2|5|2|a90be151f45cd8ab32827e9247a9a9eb7f1baef2|1720137600000|1722729600000|1725321600000|addon/components/dashboard/courses-calendar-filter.hbs
diff --git a/packages/ilios-common/addon-test-support/ilios-common/page-objects/components/dashboard/calendar-filters.js b/packages/ilios-common/addon-test-support/ilios-common/page-objects/components/dashboard/calendar-filters.js
new file mode 100644
index 0000000000..fc9e851de1
--- /dev/null
+++ b/packages/ilios-common/addon-test-support/ilios-common/page-objects/components/dashboard/calendar-filters.js
@@ -0,0 +1,30 @@
+import { collection, create, text } from 'ember-cli-page-object';
+import c from './filter-checkbox';
+import cohortsFilter from './cohort-calendar-filter';
+import coursesFilter from './courses-calendar-filter';
+import selectedVocabulary from './selected-vocabulary';
+
+const definition = {
+ scope: '[data-test-dashboard-calendar-filters]',
+ coursesFilter,
+ sessionTypesFilter: {
+ scope: '[data-test-session-type-filter]',
+ title: text('h5'),
+ sessionTypes: collection('li', c),
+ },
+ vocabularyFilter: {
+ scope: '[data-test-vocabulary-filter]',
+ title: text('h5'),
+ sessionTypes: collection('li', c),
+ vocabularies: collection('[data-test-dashboard-selected-vocabulary]', selectedVocabulary),
+ },
+ courseLevelsFilter: {
+ scope: '[data-test-course-level-filter]',
+ title: text('h5'),
+ courseLevels: collection('li', c),
+ },
+ cohortsFilter,
+};
+
+export default definition;
+export const component = create(definition);
diff --git a/packages/ilios-common/addon-test-support/ilios-common/page-objects/components/dashboard/calendar.js b/packages/ilios-common/addon-test-support/ilios-common/page-objects/components/dashboard/calendar.js
index 4669ef895f..ed68fb6132 100644
--- a/packages/ilios-common/addon-test-support/ilios-common/page-objects/components/dashboard/calendar.js
+++ b/packages/ilios-common/addon-test-support/ilios-common/page-objects/components/dashboard/calendar.js
@@ -1,15 +1,41 @@
-import { create } from 'ember-cli-page-object';
-import weeklyCalendar from './../weekly-calendar';
-import dailyCalendar from './../daily-calendar';
-import weekGlance from './../week-glance';
-import monthlyCalendar from './../monthly-calendar';
+import { collection, create, fillable, property } from 'ember-cli-page-object';
+import toggle from '../toggle-buttons';
+import userContextFilter from './user-context-filter';
+import filters from './calendar-filters';
+import filterTags from './filter-tags';
+import calendar from './../ilios-calendar';
const definition = {
scope: '[data-test-dashboard-calendar]',
- dailyCalendar,
- weekGlance,
- weeklyCalendar,
- monthlyCalendar,
+ controls: {
+ scope: '[data-test-dashboard-calendar-controls]',
+ mySchedule: {
+ scope: '[data-test-myschedule]',
+ toggle,
+ },
+ showFilters: {
+ scope: '[data-test-showfilters]',
+ toggle,
+ },
+ showCourseFilters: {
+ scope: '[data-test-showcoursefilters]',
+ toggle,
+ },
+ userContextFilter,
+ schoolPicker: {
+ scope: '[data-test-schoolpicker]',
+ select: {
+ scope: '[data-test-select-school]',
+ set: fillable(),
+ options: collection('option', {
+ isSelected: property('selected'),
+ }),
+ },
+ },
+ filters,
+ },
+ filterTags,
+ calendar,
};
export default definition;
diff --git a/packages/ilios-common/addon-test-support/ilios-common/page-objects/components/dashboard/filter-tags.js b/packages/ilios-common/addon-test-support/ilios-common/page-objects/components/dashboard/filter-tags.js
new file mode 100644
index 0000000000..fdfad59863
--- /dev/null
+++ b/packages/ilios-common/addon-test-support/ilios-common/page-objects/components/dashboard/filter-tags.js
@@ -0,0 +1,12 @@
+import { collection, create } from 'ember-cli-page-object';
+
+const definition = {
+ scope: '[data-test-dashboard-filter-tags]',
+ tags: collection('[data-test-filter-tag]'),
+ clearAll: {
+ scope: '[data-test-clear-filters]',
+ },
+};
+
+export default definition;
+export const component = create(definition);
diff --git a/packages/ilios-common/addon-test-support/ilios-common/page-objects/components/dashboard/user-context-filter.js b/packages/ilios-common/addon-test-support/ilios-common/page-objects/components/dashboard/user-context-filter.js
new file mode 100644
index 0000000000..631d4322db
--- /dev/null
+++ b/packages/ilios-common/addon-test-support/ilios-common/page-objects/components/dashboard/user-context-filter.js
@@ -0,0 +1,32 @@
+import { attribute, clickable, create, hasClass, property, text } from 'ember-cli-page-object';
+
+const definition = {
+ scope: '[data-test-dashboard-user-context-filter]',
+ instructing: {
+ isChecked: property('checked', '[data-test-instructing-input]'),
+ label: text('[data-test-instructing-label]'),
+ toggle: clickable('[data-test-instructing-label]'),
+ isActive: hasClass('active', '[data-test-instructing-label]'),
+ ariaDescription: attribute('aria-description', '[data-test-instructing-label]'),
+ title: attribute('title', '[data-test-instructing-label]'),
+ },
+ learning: {
+ isChecked: property('checked', '[data-test-learning-input]'),
+ label: text('[data-test-learning-label]'),
+ toggle: clickable('[data-test-learning-label]'),
+ isActive: hasClass('active', '[data-test-learning-label]'),
+ ariaDescription: attribute('aria-description', '[data-test-learning-label]'),
+ title: attribute('title', '[data-test-learning-label]'),
+ },
+ admin: {
+ isChecked: property('checked', '[data-test-admin-input]'),
+ label: text('[data-test-admin-label]'),
+ toggle: clickable('[data-test-admin-label]'),
+ isActive: hasClass('active', '[data-test-admin-label]'),
+ ariaDescription: attribute('aria-description', '[data-test-admin-label]'),
+ title: attribute('title', '[data-test-admin-label]'),
+ },
+};
+
+export default definition;
+export const component = create(definition);
diff --git a/packages/ilios-common/addon-test-support/ilios-common/page-objects/components/weekly-calendar-event.js b/packages/ilios-common/addon-test-support/ilios-common/page-objects/components/weekly-calendar-event.js
index da4eb107e5..41a37e025b 100644
--- a/packages/ilios-common/addon-test-support/ilios-common/page-objects/components/weekly-calendar-event.js
+++ b/packages/ilios-common/addon-test-support/ilios-common/page-objects/components/weekly-calendar-event.js
@@ -1,4 +1,4 @@
-import { attribute, create, hasClass, isPresent, text } from 'ember-cli-page-object';
+import { attribute, create, hasClass, isPresent, text, triggerable } from 'ember-cli-page-object';
const definition = {
scope: '[data-test-weekly-calendar-event]',
@@ -15,6 +15,11 @@ const definition = {
isScheduled: isPresent('[data-test-scheduled-icon]'),
isDraft: isPresent('[data-test-draft-icon]'),
wasRecentlyUpdated: isPresent('[data-test-recently-updated-icon]'),
+ mouseOver: triggerable('mouseover'),
+ tooltip: {
+ scope: '[data-test-ilios-calendar-event-tooltip]',
+ resetScope: true,
+ },
};
export default definition;
diff --git a/packages/ilios-common/addon/components/dashboard/calendar-filters.hbs b/packages/ilios-common/addon/components/dashboard/calendar-filters.hbs
index 32b5258c53..6c6891aae2 100644
--- a/packages/ilios-common/addon/components/dashboard/calendar-filters.hbs
+++ b/packages/ilios-common/addon/components/dashboard/calendar-filters.hbs
@@ -1,116 +1,124 @@
-{{#if @courseFilters}}
-