+
+
+
+
+ {{#if @showNewReportForm}}
+
+ {{/if}}
+ {{#if this.newReport}}
+
+
+
+ {{this.newReport.title}}
+
+ {{t "general.savedSuccessfully"}}
+
+ {{/if}}
+
+ {{#if @runningSubjectReport}}
+
+ {{else}}
+
+ {{#if (and this.subjectReportObjects this.subjectReportObjects.isResolved)}}
+ {{#if this.reportsCount}}
+
+ {{/if}}
+ {{else}}
+
+ {{/if}}
+
+ {{/if}}
+
+
\ No newline at end of file
diff --git a/packages/frontend/app/components/reports/list.js b/packages/frontend/app/components/reports/subjects-list.js
similarity index 95%
rename from packages/frontend/app/components/reports/list.js
rename to packages/frontend/app/components/reports/subjects-list.js
index eb968013f4..95e8e2b6b4 100644
--- a/packages/frontend/app/components/reports/list.js
+++ b/packages/frontend/app/components/reports/subjects-list.js
@@ -5,7 +5,7 @@ import { dropTask, restartableTask } from 'ember-concurrency';
import { TrackedAsyncData } from 'ember-async-data';
import { action } from '@ember/object';
-export default class ReportsListComponent extends Component {
+export default class ReportsSubjectsListComponent extends Component {
@service store;
@service currentUser;
@service reporting;
@@ -134,8 +134,8 @@ export default class ReportsListComponent extends Component {
);
@action
- toggleNewReportForm() {
+ createNewReport(type) {
this.args.setRunningSubjectReport(null);
- this.args.toggleNewReportForm;
+ this.args[`setShowNew${type}ReportForm`](true);
}
}
diff --git a/packages/frontend/app/components/reports/switcher.hbs b/packages/frontend/app/components/reports/switcher.hbs
new file mode 100644
index 0000000000..744e0277e7
--- /dev/null
+++ b/packages/frontend/app/components/reports/switcher.hbs
@@ -0,0 +1,8 @@
+
+
+ {{t "general.subjectReports"}}
+
+
+ {{t "general.curriculumReports"}}
+
+
\ No newline at end of file
diff --git a/packages/frontend/app/components/reports/table-row.hbs b/packages/frontend/app/components/reports/table-row.hbs
index e562689515..5cab937372 100644
--- a/packages/frontend/app/components/reports/table-row.hbs
+++ b/packages/frontend/app/components/reports/table-row.hbs
@@ -5,7 +5,7 @@
>
{{#if (eq @decoratedReport.type "subject")}}
-
+
{{@decoratedReport.title}}
{{/if}}
diff --git a/packages/frontend/app/controllers/reports/curriculum.js b/packages/frontend/app/controllers/reports/curriculum.js
new file mode 100644
index 0000000000..e794173d54
--- /dev/null
+++ b/packages/frontend/app/controllers/reports/curriculum.js
@@ -0,0 +1,21 @@
+import Controller from '@ember/controller';
+import { tracked } from '@glimmer/tracking';
+
+export default class ReportsCurriculumController extends Controller {
+ queryParams = [{ courses: 'courses' }, { report: 'report' }];
+
+ @tracked courses = null;
+
+ get selectedCourseIds() {
+ return this.courses?.split('-');
+ }
+
+ setSelectedCourseIds = (ids) => {
+ if (!ids || !ids.length) {
+ this.courses = null;
+ } else {
+ //use a Set to remove duplicates
+ this.courses = [...new Set(ids)].join('-');
+ }
+ };
+}
diff --git a/packages/frontend/app/controllers/subject-report.js b/packages/frontend/app/controllers/reports/subject.js
similarity index 100%
rename from packages/frontend/app/controllers/subject-report.js
rename to packages/frontend/app/controllers/reports/subject.js
diff --git a/packages/frontend/app/controllers/reports.js b/packages/frontend/app/controllers/reports/subjects.js
similarity index 92%
rename from packages/frontend/app/controllers/reports.js
rename to packages/frontend/app/controllers/reports/subjects.js
index e9ca720ace..d8ad316016 100644
--- a/packages/frontend/app/controllers/reports.js
+++ b/packages/frontend/app/controllers/reports/subjects.js
@@ -3,7 +3,7 @@ import { tracked } from '@glimmer/tracking';
import { restartableTask, timeout } from 'ember-concurrency';
import { action } from '@ember/object';
-export default class ReportsController extends Controller {
+export default class ReportsSubjectsController extends Controller {
queryParams = [
{ sortReportsBy: 'sortBy' },
{ titleFilter: 'filter' },
diff --git a/packages/frontend/app/router.js b/packages/frontend/app/router.js
index b585ab7eaf..75a7a64622 100644
--- a/packages/frontend/app/router.js
+++ b/packages/frontend/app/router.js
@@ -77,6 +77,9 @@ Router.map(function () {
path: 'data/programyears/:program_year_id/objectives',
});
this.route('search');
- this.route('reports');
- this.route('subject-report', { path: 'reports/subjects/:report_id' });
+ this.route('reports', function () {
+ this.route('curriculum');
+ this.route('subjects');
+ this.route('subject', { path: 'subjects/:report_id' });
+ });
});
diff --git a/packages/frontend/app/routes/reports.js b/packages/frontend/app/routes/reports.js
index 5e05cbfba1..22e9df4675 100644
--- a/packages/frontend/app/routes/reports.js
+++ b/packages/frontend/app/routes/reports.js
@@ -1,10 +1,3 @@
import Route from '@ember/routing/route';
-import { service } from '@ember/service';
-export default class ReportsRoute extends Route {
- @service session;
-
- beforeModel(transition) {
- this.session.requireAuthentication(transition, 'login');
- }
-}
+export default class ReportsRoute extends Route {}
diff --git a/packages/frontend/app/routes/reports/curriculum.js b/packages/frontend/app/routes/reports/curriculum.js
new file mode 100644
index 0000000000..c0f6b9856d
--- /dev/null
+++ b/packages/frontend/app/routes/reports/curriculum.js
@@ -0,0 +1,48 @@
+import Route from '@ember/routing/route';
+import { service } from '@ember/service';
+import { DateTime } from 'luxon';
+
+export default class ReportsCurriculumRoute extends Route {
+ @service session;
+ @service store;
+ @service graphql;
+ @service currentUser;
+
+ beforeModel(transition) {
+ this.session.requireAuthentication(transition, 'login');
+ }
+
+ async model() {
+ const schools = await this.store.findAll('school');
+ const threeYearsAgo = DateTime.now().year - 3;
+ // Limit query to surounding years
+ const years = [...Array(7).keys()].map((i) => threeYearsAgo + i);
+ const result = await this.graphql.find(
+ 'courses',
+ [`academicYears: [${years.join(', ')}]`],
+ 'id, title, year, externalId',
+ );
+ const allCourseData = result.data.courses;
+
+ return schools.map((school) => {
+ const courseIds = school.hasMany('courses').ids();
+ const courses = allCourseData.filter((course) => courseIds.includes(course.id));
+ const years = courses.map(({ year }) => year);
+ const uniqueYears = [...new Set(years)].sort().reverse();
+ return {
+ id: school.id,
+ title: school.title,
+ years: uniqueYears.map((year) => {
+ return {
+ year,
+ courses: courses.filter((course) => course.year === year),
+ };
+ }),
+ };
+ });
+ }
+
+ async afterModel() {
+ return this.currentUser.getModel();
+ }
+}
diff --git a/packages/frontend/app/routes/reports/index.js b/packages/frontend/app/routes/reports/index.js
new file mode 100644
index 0000000000..d9e5c4ae06
--- /dev/null
+++ b/packages/frontend/app/routes/reports/index.js
@@ -0,0 +1,12 @@
+import Route from '@ember/routing/route';
+import { service } from '@ember/service';
+
+export default class ReportsIndexRoute extends Route {
+ @service session;
+ @service router;
+
+ beforeModel(transition) {
+ this.session.requireAuthentication(transition, 'login');
+ this.router.replaceWith('reports.subjects');
+ }
+}
diff --git a/packages/frontend/app/routes/subject-report.js b/packages/frontend/app/routes/reports/subject.js
similarity index 100%
rename from packages/frontend/app/routes/subject-report.js
rename to packages/frontend/app/routes/reports/subject.js
index 456e98c243..f1edb372c5 100644
--- a/packages/frontend/app/routes/subject-report.js
+++ b/packages/frontend/app/routes/reports/subject.js
@@ -1,5 +1,5 @@
-import { service } from '@ember/service';
import Route from '@ember/routing/route';
+import { service } from '@ember/service';
export default class ReportsSubjectRoute extends Route {
@service reporting;
diff --git a/packages/frontend/app/routes/reports/subjects.js b/packages/frontend/app/routes/reports/subjects.js
new file mode 100644
index 0000000000..88d251f8e4
--- /dev/null
+++ b/packages/frontend/app/routes/reports/subjects.js
@@ -0,0 +1,3 @@
+import Route from '@ember/routing/route';
+
+export default class ReportsSubjectsRoute extends Route {}
diff --git a/packages/frontend/app/styles/components.scss b/packages/frontend/app/styles/components.scss
index 220fdb8370..7a6aaf7d80 100644
--- a/packages/frontend/app/styles/components.scss
+++ b/packages/frontend/app/styles/components.scss
@@ -139,11 +139,16 @@
@forward "components/curriculum-inventory/verification-preview-table7";
@forward "components/curriculum-inventory/verification-preview-table8";
+@forward "components/reports/choose-course";
+@forward "components/reports/choose-new-report";
+@forward "components/reports/curriculum";
+@forward "components/reports/curriculum-loading";
@forward "components/reports/new-subject";
+@forward "components/reports/switcher";
@forward "components/reports/subject";
@forward "components/reports/subject-header";
@forward "components/reports/subjects";
-@forward "components/reports/root";
+@forward "components/reports/subjects-list";
@forward "components/reports/list-loading";
@forward "components/school/session-type-visualize-vocabularies";
diff --git a/packages/frontend/app/styles/components/reports/choose-course.scss b/packages/frontend/app/styles/components/reports/choose-course.scss
new file mode 100644
index 0000000000..1fc0d28df6
--- /dev/null
+++ b/packages/frontend/app/styles/components/reports/choose-course.scss
@@ -0,0 +1,19 @@
+@use "../../ilios-common/mixins" as cm;
+
+.reports-choose-course {
+ .schools {
+ margin: 0 0 1em 0;
+ }
+ button {
+ @include cm.ilios-button-reset;
+ font-weight: bold;
+ }
+
+ ul {
+ @include cm.ilios-list-reset;
+
+ li {
+ margin-left: 0.5em;
+ }
+ }
+}
diff --git a/packages/frontend/app/styles/components/reports/choose-new-report.scss b/packages/frontend/app/styles/components/reports/choose-new-report.scss
new file mode 100644
index 0000000000..cafedd14d2
--- /dev/null
+++ b/packages/frontend/app/styles/components/reports/choose-new-report.scss
@@ -0,0 +1,60 @@
+@use "../../ilios-common/colors" as c;
+
+@use "sass:color";
+
+.choose-new-report {
+ margin: 0 0.5rem;
+ position: relative;
+ text-align: right;
+
+ button {
+ background-color: transparent;
+ border: 1px solid c.$slightWhite;
+ border-radius: 0.2rem;
+ color: c.$raisinBlack;
+ font-weight: normal;
+ padding: 0.25rem 0.5rem;
+ }
+
+ .menu {
+ background-color: c.$slightWhite;
+ box-shadow: 0 2px 2px color.adjust(c.$black, $alpha: 0.8);
+ display: flex;
+ flex-direction: column;
+ list-style-type: none;
+ margin: 0;
+ padding: 0;
+ position: absolute;
+ top: 1.6rem;
+ right: 0;
+ z-index: 100;
+
+ button {
+ border: 0;
+ background-color: c.$slightWhite;
+ color: c.$raisinBlack;
+ display: block;
+ outline: none;
+ padding: 0.5rem 1rem;
+ text-align: right;
+ text-decoration: none;
+ white-space: nowrap;
+
+ &:hover,
+ &:focus {
+ background-color: c.$tealBlue;
+ color: c.$white;
+ }
+ }
+ }
+
+ .toggle {
+ background-color: c.$tealBlue;
+ color: c.$white;
+
+ &[aria-expanded="true"] {
+ border-bottom-right-radius: 0;
+ border-bottom-left-radius: 0;
+ }
+ }
+}
diff --git a/packages/frontend/app/styles/components/reports/curriculum-loading.scss b/packages/frontend/app/styles/components/reports/curriculum-loading.scss
new file mode 100644
index 0000000000..835a15679c
--- /dev/null
+++ b/packages/frontend/app/styles/components/reports/curriculum-loading.scss
@@ -0,0 +1,11 @@
+@use "../../ilios-common/mixins" as cm;
+@use "sass:color";
+
+.reports-curriculum-loading {
+ @include cm.loading-text;
+ @include cm.loading-shimmer;
+
+ select {
+ @include cm.loading-text;
+ }
+}
diff --git a/packages/frontend/app/styles/components/reports/curriculum.scss b/packages/frontend/app/styles/components/reports/curriculum.scss
new file mode 100644
index 0000000000..5a29232e1d
--- /dev/null
+++ b/packages/frontend/app/styles/components/reports/curriculum.scss
@@ -0,0 +1,37 @@
+@use "../../ilios-common/colors" as c;
+@use "../../ilios-common/mixins" as cm;
+@use "sass:color";
+
+.reports-curriculum {
+ @include cm.main-section;
+
+ .input-buttons {
+ display: flex;
+ width: 100%;
+ margin-top: 0.5rem;
+ justify-content: flex-end;
+ button {
+ margin-left: 0.5rem;
+
+ &:disabled {
+ cursor: default;
+ background-color: c.$davysGrey;
+ }
+ }
+ }
+
+ table {
+ width: 100%;
+ caption {
+ @include cm.ilios-heading-h5;
+ }
+ th,
+ td {
+ text-align: left;
+ }
+ }
+
+ .run {
+ @include cm.font-size("medium");
+ }
+}
diff --git a/packages/frontend/app/styles/components/reports/root.scss b/packages/frontend/app/styles/components/reports/subjects-list.scss
similarity index 96%
rename from packages/frontend/app/styles/components/reports/root.scss
rename to packages/frontend/app/styles/components/reports/subjects-list.scss
index 6135b39f51..fc07b0abc6 100644
--- a/packages/frontend/app/styles/components/reports/root.scss
+++ b/packages/frontend/app/styles/components/reports/subjects-list.scss
@@ -1,6 +1,6 @@
@use "../../ilios-common/mixins" as m;
-.reports-root {
+.reports-subjects-list {
@include m.main-section;
.filters {
diff --git a/packages/frontend/app/styles/components/reports/switcher.scss b/packages/frontend/app/styles/components/reports/switcher.scss
new file mode 100644
index 0000000000..4121d6b9c2
--- /dev/null
+++ b/packages/frontend/app/styles/components/reports/switcher.scss
@@ -0,0 +1,28 @@
+@use "../../ilios-common/mixins" as cm;
+@use "../../ilios-common/colors" as c;
+
+.reports-switcher {
+ display: flex;
+ justify-content: center;
+ margin: 1em;
+ a {
+ @include cm.ilios-link-button;
+ background-color: c.$white;
+ color: c.$tealBlue;
+ border: 1px solid rgba(c.$black, 0.2);
+ @include cm.font-size("medium");
+ font-weight: 600;
+ padding: 0.25em 0.5em;
+ text-align: center;
+ text-shadow: none;
+
+ &:hover {
+ cursor: pointer;
+ }
+
+ &.active {
+ background-color: c.$tealBlue;
+ color: c.$white;
+ }
+ }
+}
diff --git a/packages/frontend/app/templates/reports.hbs b/packages/frontend/app/templates/reports.hbs
index 43bef86f8f..da8d892494 100644
--- a/packages/frontend/app/templates/reports.hbs
+++ b/packages/frontend/app/templates/reports.hbs
@@ -1,11 +1,3 @@
{{page-title (t "general.reports")}}
-
\ No newline at end of file
+
+{{outlet}}
\ No newline at end of file
diff --git a/packages/frontend/app/templates/reports/curriculum-loading.hbs b/packages/frontend/app/templates/reports/curriculum-loading.hbs
new file mode 100644
index 0000000000..b1f3c329bb
--- /dev/null
+++ b/packages/frontend/app/templates/reports/curriculum-loading.hbs
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/packages/frontend/app/templates/reports/curriculum.hbs b/packages/frontend/app/templates/reports/curriculum.hbs
new file mode 100644
index 0000000000..b31c99ffe3
--- /dev/null
+++ b/packages/frontend/app/templates/reports/curriculum.hbs
@@ -0,0 +1,7 @@
+
\ No newline at end of file
diff --git a/packages/frontend/app/templates/subject-report.hbs b/packages/frontend/app/templates/reports/subject.hbs
similarity index 100%
rename from packages/frontend/app/templates/subject-report.hbs
rename to packages/frontend/app/templates/reports/subject.hbs
diff --git a/packages/frontend/app/templates/reports/subjects.hbs b/packages/frontend/app/templates/reports/subjects.hbs
new file mode 100644
index 0000000000..d53872805b
--- /dev/null
+++ b/packages/frontend/app/templates/reports/subjects.hbs
@@ -0,0 +1,10 @@
+
\ No newline at end of file
diff --git a/packages/frontend/tests/acceptance/reports/subjects-test.js b/packages/frontend/tests/acceptance/reports/subjects-test.js
index 8aab7bdc74..1f5cbe771e 100644
--- a/packages/frontend/tests/acceptance/reports/subjects-test.js
+++ b/packages/frontend/tests/acceptance/reports/subjects-test.js
@@ -65,7 +65,7 @@ module('Acceptance | Reports - Subject Reports', function (hooks) {
test('visiting /reports', async function (assert) {
await page.visit();
- assert.strictEqual(currentRouteName(), 'reports');
+ assert.strictEqual(currentRouteName(), 'reports.index');
});
test('shows reports', async function (assert) {
@@ -90,7 +90,8 @@ module('Acceptance | Reports - Subject Reports', function (hooks) {
);
assert.strictEqual(page.root.list.table.reports[1].title, 'my report 0');
assert.ok(page.root.list.newReportLinkIsHidden);
- await page.root.list.toggleNewSubjectReportForm();
+ await page.root.list.chooser.toggle.click();
+ await page.root.list.chooser.subject.click();
await page.root.list.newSubject.title.set('aardvark');
await page.root.list.newSubject.schools.choose('1');
await page.root.list.newSubject.subjects.choose('session');
@@ -139,7 +140,8 @@ module('Acceptance | Reports - Subject Reports', function (hooks) {
await page.visit();
assert.strictEqual(page.root.list.table.reports.length, 2);
assert.ok(page.root.list.newReportLinkIsHidden);
- await page.root.list.toggleNewSubjectReportForm();
+ await page.root.list.chooser.toggle.click();
+ await page.root.list.chooser.subject.click();
await page.root.list.newSubject.schools.choose('1');
await page.root.list.newSubject.subjects.choose('session');
await page.root.list.newSubject.save();
@@ -158,7 +160,8 @@ module('Acceptance | Reports - Subject Reports', function (hooks) {
'All Sessions for term 0 in school 0',
);
assert.strictEqual(page.root.list.table.reports[1].title, 'my report 0');
- await page.root.list.toggleNewSubjectReportForm();
+ await page.root.list.chooser.toggle.click();
+ await page.root.list.chooser.subject.click();
await page.root.list.newSubject.schools.choose('1');
await page.root.list.newSubject.subjects.choose('term');
await page.root.list.newSubject.objects.choose('session');
@@ -208,7 +211,8 @@ module('Acceptance | Reports - Subject Reports', function (hooks) {
'All Sessions for term 0 in school 0',
);
assert.strictEqual(page.root.list.table.reports[1].title, 'my report 0');
- await page.root.list.toggleNewSubjectReportForm();
+ await page.root.list.chooser.toggle.click();
+ await page.root.list.chooser.subject.click();
await page.root.list.newSubject.schools.choose('1');
await page.root.list.newSubject.subjects.choose('course');
await page.root.list.newSubject.objects.choose('mesh term');
@@ -264,7 +268,8 @@ module('Acceptance | Reports - Subject Reports', function (hooks) {
'All Sessions for term 0 in school 0',
);
assert.strictEqual(page.root.list.table.reports[1].title, 'my report 0');
- await page.root.list.toggleNewSubjectReportForm();
+ await page.root.list.chooser.toggle.click();
+ await page.root.list.chooser.subject.click();
await page.root.list.newSubject.schools.choose('1');
await page.root.list.newSubject.subjects.choose('term');
await page.root.list.newSubject.objects.choose('program year');
@@ -293,7 +298,8 @@ module('Acceptance | Reports - Subject Reports', function (hooks) {
'All Sessions for term 0 in school 0',
);
assert.strictEqual(page.root.list.table.reports[1].title, 'my report 0');
- await page.root.list.toggleNewSubjectReportForm();
+ await page.root.list.chooser.toggle.click();
+ await page.root.list.chooser.subject.click();
await page.root.list.newSubject.schools.choose('All Schools');
await page.root.list.newSubject.subjects.choose('course');
await page.root.list.newSubject.save();
@@ -344,7 +350,8 @@ module('Acceptance | Reports - Subject Reports', function (hooks) {
test('run subject report', async function (assert) {
assert.expect(5);
await page.visit();
- await page.root.list.toggleNewSubjectReportForm();
+ await page.root.list.chooser.toggle.click();
+ await page.root.list.chooser.subject.click();
await page.root.list.newSubject.schools.choose('1');
await page.root.list.newSubject.subjects.choose('session');
await page.root.list.newSubject.objects.choose('course');
@@ -369,7 +376,7 @@ module('Acceptance | Reports - Subject Reports', function (hooks) {
});
await page.root.list.newSubject.run();
await percySnapshot(assert);
- assert.strictEqual(currentURL(), '/reports?showNewReportForm=true');
+ assert.strictEqual(currentURL(), '/reports?showNewSubjectReportForm=true');
assert.strictEqual(
page.root.results.description,
'This report shows all Sessions associated with Course "course 0" (2015) in school 0.',
@@ -381,7 +388,8 @@ module('Acceptance | Reports - Subject Reports', function (hooks) {
test('reset year when subject report is run', async function (assert) {
assert.expect(12);
await page.visit();
- await page.root.list.toggleNewSubjectReportForm();
+ await page.root.list.chooser.toggle.click();
+ await page.root.list.chooser.subject.click();
await page.root.list.newSubject.schools.choose('1');
await page.root.list.newSubject.subjects.choose('course');
this.server.post('api/graphql', ({ db }, { requestBody }) => {
@@ -459,7 +467,8 @@ module('Acceptance | Reports - Subject Reports', function (hooks) {
await page.visit();
assert.strictEqual(page.root.list.table.reports.length, 2);
assert.ok(page.root.list.newReportLinkIsHidden);
- await page.root.list.toggleNewSubjectReportForm();
+ await page.root.list.chooser.toggle.click();
+ await page.root.list.chooser.subject.click();
await page.root.list.newSubject.schools.choose('1');
await page.root.list.newSubject.subjects.choose('instructor');
await page.root.list.newSubject.objects.choose('academic year');
@@ -504,7 +513,8 @@ module('Acceptance | Reports - Subject Reports', function (hooks) {
test('courses by academic year hides year', async function (assert) {
assert.expect(5);
await page.visit();
- await page.root.list.toggleNewSubjectReportForm();
+ await page.root.list.chooser.toggle.click();
+ await page.root.list.chooser.subject.click();
await page.root.list.newSubject.schools.choose('');
await page.root.list.newSubject.subjects.choose('course');
await page.root.list.newSubject.objects.choose('academic year');
diff --git a/packages/frontend/tests/integration/components/reports/choose-course-test.js b/packages/frontend/tests/integration/components/reports/choose-course-test.js
new file mode 100644
index 0000000000..0a8151ef2d
--- /dev/null
+++ b/packages/frontend/tests/integration/components/reports/choose-course-test.js
@@ -0,0 +1,14 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'frontend/tests/helpers';
+import { render } from '@ember/test-helpers';
+import { hbs } from 'ember-cli-htmlbars';
+
+module('Integration | Component | reports/choose-course', function (hooks) {
+ setupRenderingTest(hooks);
+
+ test('it renders', async function (assert) {
+ await render(hbs``);
+
+ assert.dom().hasText('');
+ });
+});
diff --git a/packages/frontend/tests/integration/components/reports/curriculum-test.js b/packages/frontend/tests/integration/components/reports/curriculum-test.js
new file mode 100644
index 0000000000..d974c504b2
--- /dev/null
+++ b/packages/frontend/tests/integration/components/reports/curriculum-test.js
@@ -0,0 +1,14 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'frontend/tests/helpers';
+import { render } from '@ember/test-helpers';
+import { hbs } from 'ember-cli-htmlbars';
+
+module('Integration | Component | reports/curriculum', function (hooks) {
+ setupRenderingTest(hooks);
+
+ test('it renders', async function (assert) {
+ await render(hbs``);
+
+ assert.dom().hasText('');
+ });
+});
diff --git a/packages/frontend/tests/integration/components/reports/curriculum/learner-groups-test.js b/packages/frontend/tests/integration/components/reports/curriculum/learner-groups-test.js
new file mode 100644
index 0000000000..926a950066
--- /dev/null
+++ b/packages/frontend/tests/integration/components/reports/curriculum/learner-groups-test.js
@@ -0,0 +1,14 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'frontend/tests/helpers';
+import { render } from '@ember/test-helpers';
+import { hbs } from 'ember-cli-htmlbars';
+
+module('Integration | Component | reports/curriculum/learner-groups', function (hooks) {
+ setupRenderingTest(hooks);
+
+ test('it renders', async function (assert) {
+ await render(hbs``);
+
+ assert.dom().hasText('');
+ });
+});
diff --git a/packages/frontend/tests/integration/components/reports/curriculum/loading-test.js b/packages/frontend/tests/integration/components/reports/curriculum/loading-test.js
new file mode 100644
index 0000000000..da7cbb023d
--- /dev/null
+++ b/packages/frontend/tests/integration/components/reports/curriculum/loading-test.js
@@ -0,0 +1,14 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'frontend/tests/helpers';
+import { render } from '@ember/test-helpers';
+import { hbs } from 'ember-cli-htmlbars';
+
+module('Integration | Component | reports/curriculum/loading', function (hooks) {
+ setupRenderingTest(hooks);
+
+ test('it renders', async function (assert) {
+ await render(hbs``);
+
+ assert.dom().hasText('');
+ });
+});
diff --git a/packages/frontend/tests/integration/components/reports/curriculum/result-buttons-test.js b/packages/frontend/tests/integration/components/reports/curriculum/result-buttons-test.js
new file mode 100644
index 0000000000..cba56b9aca
--- /dev/null
+++ b/packages/frontend/tests/integration/components/reports/curriculum/result-buttons-test.js
@@ -0,0 +1,14 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'frontend/tests/helpers';
+import { render } from '@ember/test-helpers';
+import { hbs } from 'ember-cli-htmlbars';
+
+module('Integration | Component | reports/curriculum/result-buttons', function (hooks) {
+ setupRenderingTest(hooks);
+
+ test('it renders', async function (assert) {
+ await render(hbs``);
+
+ assert.dom().hasText('');
+ });
+});
diff --git a/packages/frontend/tests/integration/components/reports/curriculum/session-objectives-test.js b/packages/frontend/tests/integration/components/reports/curriculum/session-objectives-test.js
new file mode 100644
index 0000000000..ff93a4bb3f
--- /dev/null
+++ b/packages/frontend/tests/integration/components/reports/curriculum/session-objectives-test.js
@@ -0,0 +1,14 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'frontend/tests/helpers';
+import { render } from '@ember/test-helpers';
+import { hbs } from 'ember-cli-htmlbars';
+
+module('Integration | Component | reports/curriculum/session-objectives', function (hooks) {
+ setupRenderingTest(hooks);
+
+ test('it renders', async function (assert) {
+ await render(hbs``);
+
+ assert.dom().hasText('');
+ });
+});
diff --git a/packages/frontend/tests/integration/components/reports/root-test.js b/packages/frontend/tests/integration/components/reports/root-test.js
deleted file mode 100644
index 3d1198d179..0000000000
--- a/packages/frontend/tests/integration/components/reports/root-test.js
+++ /dev/null
@@ -1,80 +0,0 @@
-import { module, test } from 'qunit';
-import { setupRenderingTest } from 'frontend/tests/helpers';
-import { render } from '@ember/test-helpers';
-import { hbs } from 'ember-cli-htmlbars';
-import { setupMirage } from 'frontend/tests/test-support/mirage';
-import { setupAuthentication } from 'ilios-common';
-import { component } from 'frontend/tests/pages/components/reports/root';
-import a11yAudit from 'ember-a11y-testing/test-support/audit';
-
-module('Integration | Component | reports/root', function (hooks) {
- setupRenderingTest(hooks);
- setupMirage(hooks);
-
- hooks.beforeEach(async function () {
- this.user = await setupAuthentication();
- });
-
- test('it renders', async function (assert) {
- this.server.create('report', {
- title: null,
- subject: 'course',
- user: this.user,
- });
- this.server.create('report', {
- title: null,
- subject: 'session',
- user: this.user,
- });
-
- await render(hbs``);
-
- assert.strictEqual(component.list.table.reports.length, 2);
- assert.strictEqual(component.list.table.reports[0].title, 'All Courses in All Schools');
- assert.strictEqual(component.list.table.reports[1].title, 'All Sessions in All Schools');
-
- await a11yAudit(this.element);
- assert.ok(true, 'no a11y errors found!');
- });
-
- test('it renders empty', async function (assert) {
- await render(hbs``);
- assert.notOk(component.list.table.isVisible);
- a11yAudit(this.element);
- });
-
- test('toggle new report form', async function (assert) {
- this.set('showNewReportForm', false);
- this.set('toggleNewReportForm', () => {
- this.set('showNewReportForm', !this.showNewReportForm);
- });
-
- await render(hbs``);
- assert.notOk(component.list.newSubject.isVisible);
- await component.list.toggleNewSubjectReportForm();
- assert.ok(component.list.newSubject.isVisible);
- await component.list.toggleNewSubjectReportForm();
- assert.notOk(component.list.newSubject.isVisible);
- });
-});
diff --git a/packages/frontend/tests/integration/components/reports/list-test.js b/packages/frontend/tests/integration/components/reports/subjects-list-test.js
similarity index 72%
rename from packages/frontend/tests/integration/components/reports/list-test.js
rename to packages/frontend/tests/integration/components/reports/subjects-list-test.js
index 1813301f44..5a899d2612 100644
--- a/packages/frontend/tests/integration/components/reports/list-test.js
+++ b/packages/frontend/tests/integration/components/reports/subjects-list-test.js
@@ -7,7 +7,7 @@ import { setupAuthentication } from 'ilios-common';
import { component } from 'frontend/tests/pages/components/reports/list';
import a11yAudit from 'ember-a11y-testing/test-support/audit';
-module('Integration | Component | reports/list', function (hooks) {
+module('Integration | Component | reports/subjects-list', function (hooks) {
setupRenderingTest(hooks);
setupMirage(hooks);
@@ -27,7 +27,7 @@ module('Integration | Component | reports/list', function (hooks) {
user: this.user,
});
- await render(hbs` {
- this.set('showNewReportForm', !this.showNewReportForm);
+ assert.expect(5);
+ this.set('showNewSubjectReportForm', false);
+ this.set('setShowNewSubjectReportForm', (val) => {
+ assert.deepEqual(!this.showNewSubjectReportForm, val);
+ this.set('showNewSubjectReportForm', val);
});
- await render(hbs``);
assert.notOk(component.newSubject.isVisible);
- await component.toggleNewSubjectReportForm();
+ await component.chooser.toggle.click();
+ await component.chooser.subject.click();
assert.ok(component.newSubject.isVisible);
- await component.toggleNewSubjectReportForm();
+ await component.newSubject.cancel();
assert.notOk(component.newSubject.isVisible);
});
});
diff --git a/packages/frontend/tests/integration/components/reports/switcher-test.js b/packages/frontend/tests/integration/components/reports/switcher-test.js
new file mode 100644
index 0000000000..5a16b2eb53
--- /dev/null
+++ b/packages/frontend/tests/integration/components/reports/switcher-test.js
@@ -0,0 +1,14 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'frontend/tests/helpers';
+import { render } from '@ember/test-helpers';
+import { hbs } from 'ember-cli-htmlbars';
+
+module('Integration | Component | reports/switcher', function (hooks) {
+ setupRenderingTest(hooks);
+
+ test('it renders', async function (assert) {
+ await render(hbs``);
+
+ assert.dom().hasText('');
+ });
+});
diff --git a/packages/frontend/tests/pages/components/reports/choose-new-report.js b/packages/frontend/tests/pages/components/reports/choose-new-report.js
new file mode 100644
index 0000000000..5f7cef0d93
--- /dev/null
+++ b/packages/frontend/tests/pages/components/reports/choose-new-report.js
@@ -0,0 +1,25 @@
+import { create, collection, triggerable } from 'ember-cli-page-object';
+import { hasFocus } from 'ilios-common';
+export default create({
+ scope: '[data-test-choose-new-report]',
+ toggle: {
+ scope: '[data-test-toggle]',
+ enter: triggerable('keyup', '', { eventProperties: { key: 'Enter' } }),
+ down: triggerable('keyup', '', { eventProperties: { key: 'ArrowDown' } }),
+ esc: triggerable('keyup', '', { eventProperties: { key: 'Escape' } }),
+ hasFocus: hasFocus(),
+ },
+ types: collection('[data-test-item]', {
+ hasFocus: hasFocus(),
+ mouseEnter: triggerable('mouseenter'),
+ down: triggerable('keyup', '', { eventProperties: { key: 'ArrowDown' } }),
+ esc: triggerable('keyup', '', { eventProperties: { key: 'Escape' } }),
+ left: triggerable('keyup', '', { eventProperties: { key: 'ArrowLeft' } }),
+ right: triggerable('keyup', '', { eventProperties: { key: 'ArrowRight' } }),
+ tab: triggerable('keyup', '', { eventProperties: { key: 'Tab' } }),
+ up: triggerable('keyup', '', { eventProperties: { key: 'ArrowUp' } }),
+ }),
+ subject: {
+ scope: '[data-test-item]:nth-of-type(1)',
+ },
+});
diff --git a/packages/frontend/tests/pages/components/reports/list.js b/packages/frontend/tests/pages/components/reports/list.js
index 85e22a7212..18fd87a8c3 100644
--- a/packages/frontend/tests/pages/components/reports/list.js
+++ b/packages/frontend/tests/pages/components/reports/list.js
@@ -2,11 +2,12 @@ import { clickable, create, fillable, isHidden, text } from 'ember-cli-page-obje
import { hasFocus } from 'ilios-common';
import table from './table';
import newSubject from './new-subject';
+import chooser from './choose-new-report';
const definition = {
filterByTitle: fillable('[data-test-title-filter]'),
headerTitle: text('[data-test-reports-header-title]'),
- toggleNewSubjectReportForm: clickable('[data-test-expand-collapse-button] button'),
+ chooser,
newSubject,
newReportLink: text('[data-test-newly-saved-report] a'),
newReportLinkIsHidden: isHidden('[data-test-newly-saved-report] a'),
diff --git a/packages/frontend/tests/pages/reports.js b/packages/frontend/tests/pages/reports.js
index 7b48444dae..14828eb96e 100644
--- a/packages/frontend/tests/pages/reports.js
+++ b/packages/frontend/tests/pages/reports.js
@@ -1,9 +1,9 @@
import { create, visitable } from 'ember-cli-page-object';
-import root from './components/reports/root';
+// import root from './components/reports/root';
const page = {
visit: visitable('/reports'),
- root,
+ // root,
};
export default create(page);
diff --git a/packages/frontend/tests/unit/controllers/reports-test.js b/packages/frontend/tests/unit/controllers/reports-test.js
deleted file mode 100644
index 4387823580..0000000000
--- a/packages/frontend/tests/unit/controllers/reports-test.js
+++ /dev/null
@@ -1,17 +0,0 @@
-import { module, test } from 'qunit';
-import { setupTest } from 'frontend/tests/helpers';
-import Controller from 'frontend/controllers/reports';
-
-module('Unit | Controller | reports', function (hooks) {
- setupTest(hooks);
-
- hooks.beforeEach(function () {
- this.owner.register('controller:reports', Controller);
- });
-
- // TODO: Replace this with your real tests.
- test('it exists', function (assert) {
- let controller = this.owner.lookup('controller:reports');
- assert.ok(controller);
- });
-});
diff --git a/packages/frontend/translations/en-us.yaml b/packages/frontend/translations/en-us.yaml
index 6f8a29348f..85a28450dd 100644
--- a/packages/frontend/translations/en-us.yaml
+++ b/packages/frontend/translations/en-us.yaml
@@ -99,6 +99,7 @@ general:
curriculumInventoryReportRolloverSummary: "This action will copy the structure of this report to be used in your target year. It will not copy course information, only the higher level sequence block structure. You will need to add the appropriate course information and modify the sequence block start and end dates once you have rolled over the existing report structure."
curriculumInventoryReportRolloverSuccess: Report-Rollover Completed Successfully
curriculumInventoryReports: Curriculum Inventory Reports
+ curriculumReports: Curriculum Reports
dashboard: Dashboard
deactivate: Deactivate
defaultInstructors: Default Instructors
@@ -232,6 +233,7 @@ general:
narrative: Narrative
navigationCompleteText: Ilios page navigation is complete. You may now navigate the page content as you wish.
newCourse: New Course
+ newCourseReport: New Course Report
newCurriculumInventoryReport: New Curriculum Inventory Report
newDomain: New Domain
newInstructorGroup: New Instructor Group
@@ -241,6 +243,7 @@ general:
newReport: New Report
newSchool: New School
newSequenceBlock: New Sequence Block
+ newSubjectReport: New Subject Report
newTerm: New Term
newToken: New Token
newUser: New User
@@ -346,13 +349,16 @@ general:
reportDisplayDescriptionWithoutObject: "This report shows all {subject} in {school}."
reportDisplayTitleWithObject: "All {subject} for {object} in {school}"
reportDisplayTitleWithoutObject: "All {subject} in {school}"
+ reportForCourses: report for {courseCount, plural, one {one course} other {# courses}}
reportName: Report Name
reportNamePlaceholder: Please enter a report name.
reports: Reports
reportTitle: Report Title
requiredInTrack: Required In Track
resourceTypes: Resource Types
+ resultsSummary: Results Summary
root: Root
+ run: Run
runReport: Run Report
sampleFile: Sample File
saved: New User Saved Successfully
@@ -364,7 +370,9 @@ general:
select: Select
selectAcademicYear: Select Academic Year
selectAllOrNone: Select All or None
+ selectCoursesToRunReport: Select Courses to Run Report
selected: Selected
+ selectedCourses: Selected Courses
selectProgram: Select a Program
selectSchool: Select School
selectUser: Select User
@@ -377,6 +385,7 @@ general:
sequenceBlockTitlePlaceholder: Please enter a title for this sequence block.
sequenceNumber: "Sequence #"
sessionAttributes: Session Attributes
+ sessionObjectives: Session Objectives
sessionTitlePlaceholder: Enter a title for this session
sessionTypeConfirmRemoval: Are you sure you want to delete this session type? This action cannot be undone.
showResultsFor: Show Results For
diff --git a/packages/frontend/translations/es.yaml b/packages/frontend/translations/es.yaml
index 0b5a23ac91..43409eb2a1 100644
--- a/packages/frontend/translations/es.yaml
+++ b/packages/frontend/translations/es.yaml
@@ -232,6 +232,7 @@ general:
narrative: narrativa
navigationCompleteText: La navegación de la página de Ilios está completa. Ahora puede navegar por el contenido de la página como desee.
newCourse: Curso Nuevo
+ newCourseReport: Nuevo Informe de Curso
newCurriculumInventoryReport: Nuevo Informe de Inventario de Plan de Estudios
newDomain: Nuevo Dominio
newInstructorGroup: Nuevo Grupo de Instructores
@@ -241,6 +242,7 @@ general:
newReport: Nuevo Reporte
newSchool: Nueva Escuela
newSequenceBlock: Nuevo Bloque de Secuencia
+ newSubjectReport: Nuevo Informe de Tema
newTerm: Nuevo Termino
newToken: Nuevo Símbolo (Token)
newUser: Nuevo Usuario
diff --git a/packages/frontend/translations/fr.yaml b/packages/frontend/translations/fr.yaml
index 84f4322fdb..ea5a7caf60 100644
--- a/packages/frontend/translations/fr.yaml
+++ b/packages/frontend/translations/fr.yaml
@@ -232,6 +232,7 @@ general:
narrative: narrative
navigationCompleteText: La navigation sur la page Ilios est terminée. Vous pouvez maintenant naviguer dans le contenu de la page comme vous le souhaitez.
newCourse: Cours neuf
+ newCourseReport: nouveau rapport de cours
newCurriculumInventoryReport: "Nouveau Rapport d'inventaire des Programmes d'études"
newDomain: Domaine nouvelle
newInstructorGroup: Groupe des Instructeurs nouveau
@@ -240,6 +241,7 @@ general:
newProgramYear: Année de diplôme neuf
newReport: Nouveau rapport
newSchool: École nouvelle
+ newSubjectReport: nouveau rapport thématique
newSequenceBlock: Nouveau bloc de séquence
newTerm: Nouveau terme
newToken: Nouveau jeton
|