-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
When manually exporting a report to PDF, the report header would not …
…be collapsed before generating the PDF. Prevent the need for collapsing the header by moving the PDF button to the menu bar. Fixes #8054.
- Loading branch information
Showing
13 changed files
with
158 additions
and
134 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
62 changes: 62 additions & 0 deletions
62
components/frontend/src/header_footer/DownloadAsPDFButton.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import React, { useState } from 'react'; | ||
import PropTypes from 'prop-types'; | ||
import { Icon } from 'semantic-ui-react'; | ||
import { Button, Popup } from '../semantic_ui_react_wrappers'; | ||
import { get_report_pdf } from '../api/report'; | ||
import { registeredURLSearchParams } from '../hooks/url_search_query'; | ||
import { showMessage } from '../widgets/toast'; | ||
|
||
function download_pdf(report_uuid, query_string, callback) { | ||
const reportId = report_uuid ? `report-${report_uuid}` : "reports-overview" | ||
get_report_pdf(report_uuid, query_string) | ||
.then(response => { | ||
if (response.ok === false) { | ||
showMessage("error", "PDF rendering failed", "HTTP code " + response.status + ": " + response.statusText) | ||
} else { | ||
let url = window.URL.createObjectURL(response); | ||
let a = document.createElement('a'); | ||
a.href = url; | ||
const now = new Date(); | ||
const local_now = new Date(now.getTime() - (now.getTimezoneOffset() * 60000)); | ||
a.download = `Quality-time-${reportId}-${local_now.toISOString().split(".")[0]}.pdf`; | ||
a.click(); | ||
} | ||
}).finally(() => callback()); | ||
} | ||
|
||
export function DownloadAsPDFButton({ report_uuid }) { | ||
const [loading, setLoading] = useState(false); | ||
// Make sure the report_url contains only registered query parameters | ||
const query = registeredURLSearchParams(); | ||
const queryString = query.toString() ? ("?" + query.toString()) : "" | ||
query.set("report_url", window.location.origin + window.location.pathname + queryString + window.location.hash); | ||
const itemType = report_uuid ? "report" : "reports overview" | ||
const label = `Download ${itemType} as PDF` | ||
return ( | ||
<Popup | ||
on={["hover", "focus"]} | ||
trigger={ | ||
<Button | ||
aria-label={label} | ||
basic | ||
icon | ||
loading={loading} | ||
onClick={() => { | ||
console.log(loading) | ||
if (!loading) { | ||
setLoading(true); | ||
download_pdf(report_uuid, `?${query.toString()}`, () => { setLoading(false) }) | ||
} | ||
}} | ||
inverted | ||
> | ||
<Icon name="file pdf" /> Download as PDF | ||
</Button> | ||
} | ||
content={`Generate a PDF version of the ${itemType} as currently displayed. This may take some time.`} | ||
/> | ||
) | ||
} | ||
DownloadAsPDFButton.propTypes = { | ||
report_uuid: PropTypes.string, | ||
} |
71 changes: 71 additions & 0 deletions
71
components/frontend/src/header_footer/DownloadAsPDFButton.test.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
import React from 'react'; | ||
import { act, fireEvent, render, screen } from '@testing-library/react'; | ||
import history from 'history/browser'; | ||
import { DownloadAsPDFButton } from './DownloadAsPDFButton'; | ||
import * as fetch_server_api from '../api/fetch_server_api'; | ||
|
||
test("DownloadAsPDFButton has the correct label for reports overview", () => { | ||
render(<DownloadAsPDFButton />); | ||
expect(screen.getAllByLabelText(/reports overview as PDF/).length).toBe(1); | ||
|
||
}); | ||
|
||
test("DownloadAsPDFButton has the correct label for a report", () => { | ||
render(<DownloadAsPDFButton report_uuid={"report_uuid"}/>); | ||
expect(screen.getAllByLabelText(/report as PDF/).length).toBe(1); | ||
|
||
}); | ||
|
||
const test_report = { report_uuid: "report_uuid" }; | ||
|
||
test("DownloadAsPDFButton indicates loading on click", async () => { | ||
fetch_server_api.fetch_server_api = jest.fn().mockReturnValue({ then: jest.fn().mockReturnValue({ finally: jest.fn() }) }); | ||
render(<DownloadAsPDFButton report={test_report} report_uuid="report_uuid" />); | ||
await act(async () => { | ||
fireEvent.click(screen.getByLabelText(/Download/)); | ||
}); | ||
expect(screen.getByLabelText(/Download/).className).toContain("loading") | ||
expect(fetch_server_api.fetch_server_api).toHaveBeenCalledWith("get", "report/report_uuid/pdf?report_url=http%3A%2F%2Flocalhost%2F", {}, "application/pdf") | ||
}); | ||
|
||
test("DownloadAsPDFButton ignores unregistered query parameters", async () => { | ||
fetch_server_api.fetch_server_api = jest.fn().mockReturnValue({ then: jest.fn().mockReturnValue({ finally: jest.fn() }) }); | ||
history.push("?unregister_key=value&nr_dates=4"); | ||
render(<DownloadAsPDFButton report={test_report} report_uuid="report_uuid" />); | ||
await act(async () => { | ||
fireEvent.click(screen.getByLabelText(/Download/)); | ||
}); | ||
expect(fetch_server_api.fetch_server_api).toHaveBeenCalledWith("get", "report/report_uuid/pdf?nr_dates=4&report_url=http%3A%2F%2Flocalhost%2F%3Fnr_dates%3D4", {}, "application/pdf") | ||
}); | ||
|
||
test("DownloadAsPDFButton ignores a second click", async () => { | ||
fetch_server_api.fetch_server_api = jest.fn().mockReturnValue({ then: jest.fn().mockReturnValue({ finally: jest.fn() }) }); | ||
render(<DownloadAsPDFButton report={test_report} />); | ||
await act(async () => { | ||
fireEvent.click(screen.getByLabelText(/Download/)); | ||
}); | ||
await act(async () => { | ||
fireEvent.click(screen.getByLabelText(/Download/)); | ||
}); | ||
expect(screen.getByLabelText(/Download/).className).toContain("loading") | ||
}); | ||
|
||
test("DownloadAsPDFButton stops loading after returning pdf", async () => { | ||
fetch_server_api.fetch_server_api = jest.fn().mockResolvedValue("pdf"); | ||
HTMLAnchorElement.prototype.click = jest.fn() // Prevent "Not implemented: navigation (except hash changes)" | ||
window.URL.createObjectURL = jest.fn(); | ||
render(<DownloadAsPDFButton report={test_report} />); | ||
await act(async () => { | ||
fireEvent.click(screen.getByLabelText(/Download/)); | ||
}); | ||
expect(screen.getByLabelText(/Download/).className).not.toContain("loading") | ||
}); | ||
|
||
test("DownloadAsPDFButton stops loading after receiving error", async () => { | ||
fetch_server_api.fetch_server_api = jest.fn().mockResolvedValue({ ok: false }); | ||
render(<DownloadAsPDFButton report={test_report} />); | ||
await act(async () => { | ||
fireEvent.click(screen.getByLabelText(/Download/)); | ||
}); | ||
expect(screen.getByLabelText(/Download/).className).not.toContain("loading") | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.