From dbfbe1f45d0e453a4ba7c05fa43aafac467bf9bb Mon Sep 17 00:00:00 2001 From: Davud Evren Date: Sun, 1 Oct 2023 00:26:53 +0200 Subject: [PATCH] add print/download all feedbacks feature #275 --- cypress/e2e/feedbacks.cy.js | 50 +++--- cypress/e2e/requirements-matrix.cy.js | 155 +++++++++++------- lang/de/t.php | 1 + package-lock.json | 50 ++++-- package.json | 3 + .../print/ButtonPrintAllFeedbacks.vue | 149 +++++++++++++++++ .../feedback/progress-overview.blade.php | 5 + 7 files changed, 310 insertions(+), 103 deletions(-) create mode 100644 resources/js/components/print/ButtonPrintAllFeedbacks.vue 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)) @else