diff --git a/cypress/e2e/feedbacks.cy.js b/cypress/e2e/feedbacks.cy.js
index beed540b..6cfabf48 100644
--- a/cypress/e2e/feedbacks.cy.js
+++ b/cypress/e2e/feedbacks.cy.js
@@ -20,30 +20,30 @@ describe('feedback editor', () => {
cy.contains('Die Rückmeldung "End-to-end test feedback" wurde erfolgreich erstellt.')
})
- it('edits and prints a feedback', function () {
- cy.visit(`/course/${this.courseId}/participants`)
- cy.get('img.card-img-top').first().click()
- cy.get('td[data-label=Titel] a').first().click()
- cy.contains('Rückmeldung Details')
-
- cy.get('div.editor.form-control [contenteditable]').first().type("Text from end-to-end test\n")
- cy.contains('Speichern...')
- cy.contains('Automatisch gespeichert')
- cy.get('a.btn-link').first().click()
-
- cy.get('[title="Drucken"]').click()
- cy.contains('PDF wird generiert...')
- cy.contains('PDF wurde heruntergeladen')
-
- cy.task('findFiles', 'cypress/downloads/*').then((foundPdf) => {
- expect(foundPdf).to.be.a('string')
- cy.log(`found PDF ${foundPdf}`)
- cy.task('parsePdf', foundPdf).then((parsedPdf) => {
- expect(parsedPdf.text).to.include('Text from end-to-end test')
- expect(parsedPdf.text).not.to.include('Some other text which certainly is not present in the pdf')
- })
+ it('edits and prints a feedback', function () {
+ cy.visit(`/course/${this.courseId}/participants`)
+ cy.get('img.card-img-top').first().click()
+ cy.get('td[data-label=Titel] a').first().click()
+ cy.contains('Rückmeldung Details')
+
+ cy.get('div.editor.form-control [contenteditable]').first().type("Text from end-to-end test\n")
+ cy.contains('Speichern...')
+ cy.contains('Automatisch gespeichert')
+ cy.get('a.btn-link').first().click()
+
+ cy.get('[title="Drucken"]').click()
+ cy.contains('PDF wird generiert...')
+ cy.contains('PDF wurde heruntergeladen')
+
+ cy.task('findFiles', 'cypress/downloads/*').then((foundPdf) => {
+ expect(foundPdf).to.be.a('string')
+ cy.log(`found PDF ${foundPdf}`)
+ cy.task('parsePdf', foundPdf).then((parsedPdf) => {
+ expect(parsedPdf.text).to.include('Text from end-to-end test')
+ expect(parsedPdf.text).not.to.include('Some other text which certainly is not present in the pdf')
+ })
+ })
+
+ cy.task('deleteFiles', 'cypress/downloads/*')
})
-
- cy.task('deleteFiles', 'cypress/downloads/*')
- })
})
diff --git a/cypress/e2e/requirements-matrix.cy.js b/cypress/e2e/requirements-matrix.cy.js
index 45fb14da..0540065e 100644
--- a/cypress/e2e/requirements-matrix.cy.js
+++ b/cypress/e2e/requirements-matrix.cy.js
@@ -1,74 +1,109 @@
-import { useDatabaseResets } from "../support/databaseTransactions"
+import {useDatabaseResets} from "../support/databaseTransactions"
describe('requirements matrix', () => {
- useDatabaseResets()
-
- beforeEach(() => {
- cy.then(() => {
- cy.login().then(user => {
- cy.artisan('e2e:scenario', { '--user-id': user.id })
- })
+ useDatabaseResets()
+
+ beforeEach(() => {
+ cy.then(() => {
+ cy.login().then(user => {
+ cy.artisan('e2e:scenario', {'--user-id': user.id})
+ })
+ })
})
- })
-
- it('can be displayed and edited', function () {
- cy.courseId().then((courseId) => {
- cy.create('App\\Models\\RequirementStatus', 1, { course_id: courseId, name: 'E2E status', color: 'green', icon: 'book' })
-
- cy.php(`App\\Models\\FeedbackData::orderBy('id', 'desc')->first();`).then(feedback => {
- cy.visit(`/course/${courseId}`)
- cy.contains(feedback.name).click()
-
- cy.contains('Anforderungs-Matrix')
-
- cy.contains(`Anforderungs-Matrix ${feedback.name}`)
- cy.get('[data-label]').eq(1).as('cell')
-
- cy.get('@cell').click()
- cy.get('#requirement-status').click()
- cy.get('#requirement-status .multiselect__option').eq(3).click()
- cy.get('#comment').type('{selectall}Test E2E Notes which should be truncated because they are way too long to fit into the matrix cell')
- cy.contains('Speichern...')
- cy.contains('Automatisch gespeichert')
-
- cy.get('[aria-label="Close"]').click()
- cy.contains('Automatisch gespeichert').should('not.exist')
- cy.contains('Test E2E Notes which should be truncated because…')
- cy.get('@cell').should('have.class', 'bg-green')
- })
+ it('can be displayed and edited', function () {
+ cy.courseId().then((courseId) => {
+ cy.create('App\\Models\\RequirementStatus', 1, {
+ course_id: courseId,
+ name: 'E2E status',
+ color: 'green',
+ icon: 'book'
+ })
+
+ cy.php(`App\\Models\\FeedbackData::orderBy('id', 'desc')->first();`).then(feedback => {
+ cy.visit(`/course/${courseId}`)
+ cy.contains(feedback.name).click()
+
+ cy.contains('Anforderungs-Matrix')
+
+ cy.contains(`Anforderungs-Matrix ${feedback.name}`)
+ cy.get('[data-label]').eq(1).as('cell')
+
+ cy.get('@cell').click()
+ cy.get('#requirement-status').click()
+ cy.get('#requirement-status .multiselect__option').eq(3).click()
+ cy.get('#comment').type('{selectall}Test E2E Notes which should be truncated because they are way too long to fit into the matrix cell')
+ cy.contains('Speichern...')
+ cy.contains('Automatisch gespeichert')
+
+ cy.get('[aria-label="Close"]').click()
+ cy.contains('Automatisch gespeichert').should('not.exist')
+ cy.contains('Test E2E Notes which should be truncated because…')
+ cy.get('@cell').should('have.class', 'bg-green')
+ })
+
+ })
})
- })
- it('can be displayed and edited if there are multiple feedbacks in course', function () {
- cy.courseId().then((courseId) => {
- cy.create('App\\Models\\RequirementStatus', 1, { course_id: courseId, name: 'E2E status', color: 'green', icon: 'book' })
- cy.create('App\\Models\\FeedbackData', 1, { course_id: courseId, name: 'E2E Feedback' })
+ it('can be displayed and edited if there are multiple feedbacks in course', function () {
+ cy.courseId().then((courseId) => {
+ cy.create('App\\Models\\RequirementStatus', 1, {
+ course_id: courseId,
+ name: 'E2E status',
+ color: 'green',
+ icon: 'book'
+ })
+ cy.create('App\\Models\\FeedbackData', 1, {course_id: courseId, name: 'E2E Feedback'})
+
+ cy.php(`App\\Models\\FeedbackData::orderBy('id', 'desc')->offset(1)->first();`).then(feedback => {
+ cy.visit(`/course/${courseId}`)
+ cy.contains('Rückmeldungen').click()
+ cy.contains('E2E Feedback')
+ cy.contains(feedback.name).click()
+
+ cy.contains('Anforderungs-Matrix')
+
+ cy.contains(`Anforderungs-Matrix ${feedback.name}`)
+ cy.get('[data-label]').eq(1).as('cell')
+
+ cy.get('@cell').click()
+ cy.get('#requirement-status').click()
+ cy.get('#requirement-status .multiselect__option').eq(3).click()
+ cy.get('#comment').type('{selectall}Test E2E Notes which should be truncated because they are way too long to fit into the matrix cell')
+ cy.contains('Speichern...')
+ cy.contains('Automatisch gespeichert')
+
+ cy.get('[aria-label="Close"]').click()
+ cy.contains('Automatisch gespeichert').should('not.exist')
+ cy.contains('Test E2E Notes which should be truncated because…')
+ cy.get('@cell').should('have.class', 'bg-green')
+ })
+
+ })
+ })
- cy.php(`App\\Models\\FeedbackData::orderBy('id', 'desc')->offset(1)->first();`).then(feedback => {
- cy.visit(`/course/${courseId}`)
- cy.contains('Rückmeldungen').click()
- cy.contains('E2E Feedback')
- cy.contains(feedback.name).click()
+ it('edits and prints all feedbacks', function () {
+ cy.courseId().then((courseId) => {
+ cy.create('App\\Models\\RequirementStatus', 1, { course_id: courseId, name: 'E2E status', color: 'green', icon: 'book' })
- cy.contains('Anforderungs-Matrix')
+ cy.php(`App\\Models\\FeedbackData::orderBy('id', 'desc')->first();`).then(feedback => {
+ cy.visit(`/course/${courseId}`)
+ cy.contains(feedback.name).click()
- cy.contains(`Anforderungs-Matrix ${feedback.name}`)
- cy.get('[data-label]').eq(1).as('cell')
+ cy.contains('Anforderungs-Matrix')
- cy.get('@cell').click()
- cy.get('#requirement-status').click()
- cy.get('#requirement-status .multiselect__option').eq(3).click()
- cy.get('#comment').type('{selectall}Test E2E Notes which should be truncated because they are way too long to fit into the matrix cell')
- cy.contains('Speichern...')
- cy.contains('Automatisch gespeichert')
+ cy.contains(`Anforderungs-Matrix ${feedback.name}`)
- cy.get('[aria-label="Close"]').click()
- cy.contains('Automatisch gespeichert').should('not.exist')
- cy.contains('Test E2E Notes which should be truncated because…')
- cy.get('@cell').should('have.class', 'bg-green')
- })
+ cy.get('[title="Drucken"]').first().click()
+ cy.contains('PDF wird generiert...')
+ cy.contains('PDF wurde heruntergeladen', { timeout: 20000})
+ cy.task('findFiles', 'cypress/downloads/*').then((foundZip) => {
+ expect(foundZip).to.be.a('string')
+ cy.log(`found PDF ${foundZip}`)
+ cy.readFile(foundZip)
+ })
+ })
+ })
})
- })
})
diff --git a/lang/de/t.php b/lang/de/t.php
index 36a2d30c..860ef558 100644
--- a/lang/de/t.php
+++ b/lang/de/t.php
@@ -518,6 +518,7 @@
"title" => ":name",
"requirements_matrix" => "Anforderungs-Matrix :name",
"view_as" => "Aus Sicht von",
+ "download_all" => "Alle Rückmeldungen herunterladen"
)
),
"invitation" => array(
diff --git a/package-lock.json b/package-lock.json
index 7b551b5a..b3317aba 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5010,8 +5010,7 @@
"core-util-is": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
- "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
- "dev": true
+ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
},
"cosmiconfig": {
"version": "7.0.1",
@@ -6769,6 +6768,11 @@
"loader-utils": "^1.1.0"
}
},
+ "immediate": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
+ "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="
+ },
"import-fresh": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
@@ -6822,8 +6826,7 @@
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
- "dev": true
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"ini": {
"version": "1.3.8",
@@ -6984,8 +6987,7 @@
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
- "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
- "dev": true
+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
},
"isexe": {
"version": "2.0.0",
@@ -8462,6 +8464,17 @@
}
}
},
+ "jszip": {
+ "version": "3.10.1",
+ "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz",
+ "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==",
+ "requires": {
+ "lie": "~3.3.0",
+ "pako": "~1.0.2",
+ "readable-stream": "~2.3.6",
+ "setimmediate": "^1.0.5"
+ }
+ },
"junk": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/junk/-/junk-3.1.0.tgz",
@@ -10269,6 +10282,14 @@
"isomorphic.js": "^0.2.4"
}
},
+ "lie": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
+ "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
+ "requires": {
+ "immediate": "~3.0.5"
+ }
+ },
"lilconfig": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.5.tgz",
@@ -11030,8 +11051,7 @@
"pako": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
- "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
- "dev": true
+ "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
},
"param-case": {
"version": "3.0.4",
@@ -11719,8 +11739,7 @@
"process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
- "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
- "dev": true
+ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
},
"prompts": {
"version": "2.4.1",
@@ -12056,7 +12075,6 @@
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
- "dev": true,
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
@@ -12071,7 +12089,6 @@
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
- "dev": true,
"requires": {
"safe-buffer": "~5.1.0"
}
@@ -12321,8 +12338,7 @@
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
- "dev": true
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
"safer-buffer": {
"version": "2.1.2",
@@ -12547,8 +12563,7 @@
"setimmediate": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
- "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=",
- "dev": true
+ "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU="
},
"setprototypeof": {
"version": "1.2.0",
@@ -13426,8 +13441,7 @@
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
- "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
- "dev": true
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
},
"utils-merge": {
"version": "1.0.1",
diff --git a/package.json b/package.json
index a6f7312a..5cf4215f 100644
--- a/package.json
+++ b/package.json
@@ -61,5 +61,8 @@
"vue-template-compiler": "^2.6.14",
"y-webrtc": "^10.2.0",
"yjs": "^13.5.12"
+ },
+ "dependencies": {
+ "jszip": "^3.10.1"
}
}
diff --git a/resources/js/components/print/ButtonPrintAllFeedbacks.vue b/resources/js/components/print/ButtonPrintAllFeedbacks.vue
new file mode 100644
index 00000000..d4708cd5
--- /dev/null
+++ b/resources/js/components/print/ButtonPrintAllFeedbacks.vue
@@ -0,0 +1,149 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/resources/views/feedback/progress-overview.blade.php b/resources/views/feedback/progress-overview.blade.php
index 5b907aa7..ff9ef764 100644
--- a/resources/views/feedback/progress-overview.blade.php
+++ b/resources/views/feedback/progress-overview.blade.php
@@ -11,6 +11,11 @@
@section('content')
+
+ {{__('t.views.feedback.progress_overview.download_all')}}
+
+
+
@if(count($feedbackRequirements))
{{__('t.views.feedback.progress_overview.requirements_matrix', ['name' => $feedbackData->name])}}
@else