Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Backport 2.x] Make the generated report use the correct background color #170

Merged
merged 1 commit into from
Sep 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 5 additions & 12 deletions public/components/visual_report/assets/report_styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,14 @@ iframe, embed, object {
display: none !important;
}

/* nice padding + matches Kibana default UI colors you could also set this to inherit if
the wrapper gets inserted inside a kibana section. I might also remove the manual text color here as well, potentially */
.reportWrapper {
padding: 8px;
background-color: #fafbfd;
}

/* Notice that I'm using an ID of #reportingHeader, and #reportingFooter, instead of a classname (.reportingHeader, .reportingFooter). This is
in order to force specificity here higher in case any other styles would conflict */
#reportingHeader,
#reportingFooter {
font-family: 'Inter UI', -apple-system, BlinkMacSystemFont, 'Segoe UI',
Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
'Segoe UI Symbol';
background-color: #fff;
border: 1px solid #d3dae6;
box-shadow: 0 2px 2px -1px rgba(152, 162, 179, 0.3),
0 1px 5px -2px rgba(152, 162, 179, 0.3);
Expand Down Expand Up @@ -99,11 +92,11 @@ iframe, embed, object {
margin-bottom: inherit;
}
</style>
<style>
/* mde style sheet*/
.mde-preview .mde-preview-content {
padding: 10px;
}
<style>
/* mde style sheet*/
.mde-preview .mde-preview-content {
padding: 10px;
}
.mde-preview .mde-preview-content p,
.mde-preview .mde-preview-content blockquote,
.mde-preview .mde-preview-content ul,
Expand Down
58 changes: 37 additions & 21 deletions public/components/visual_report/generate_report.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,10 @@ const removeNonReportElements = (
doc
.querySelectorAll("button[class^='euiButton']:not(.visLegend__button)")
.forEach((e) => e.remove());
// remove top navBar
doc.querySelectorAll("[class^='euiHeader']").forEach((e) => e.remove());

// remove anything that shouldn't be shared
doc.querySelectorAll('.hide-for-sharing').forEach((e) => e.remove());

// remove visualization editor
if (reportSource === VISUAL_REPORT_TYPE.visualization) {
doc.querySelector('[data-test-subj="splitPanelResizer"]')?.remove();
Expand All @@ -84,6 +86,8 @@ const addReportHeader = (doc: Document, header: string) => {
};

const addReportFooter = (doc: Document, footer: string) => {
// If there is no content, don't bother creating an element
if (!footer) return;
const footerHtml = `<div id="reportingFooter">
<div class="mde-preview" data-testid="mde-preview">
<div class="mde-preview-content">${footer}</div>
Expand All @@ -104,19 +108,6 @@ const addReportStyle = (doc: Document, style: string) => {
doc.body.style.paddingTop = '0px';
};

const computeHeight = (height: number, header: string, footer: string) => {
let computedHeight = height;
const headerLines = header.split('\n').length;
const footerLines = footer.split('\n').length;
if (headerLines) {
computedHeight += 24 * headerLines;
}
if (footerLines) {
computedHeight += 50 + 24 * footerLines;
}
return computedHeight;
};

export const generateReport = async (id: string, forceDelay = 15000) => {
const http = uiSettingsService.getHttpClient();
const useForeignObjectRendering = uiSettingsService.get('reporting:useFOR');
Expand Down Expand Up @@ -179,26 +170,48 @@ export const generateReport = async (id: string, forceDelay = 15000) => {
await timeout(1000);
}

const width = document.documentElement.scrollWidth;
const height = computeHeight(
document.documentElement.scrollHeight,
header,
footer
);
/* The left-nav impacts the dimensions of the report; `#opensearch-dashboards-body`
* is the safest way to know the width.
* Since `html2canvas` without `foreignObjectRendering` copies computed styles of
* elements, we cannot rely on re-calculation of cloned widths after we remove all
* `.hide-for-sharing` elements in `removeNonReportElements`. The only option is to
* produce a narrower report when left-nav is docked.
*
* If `#opensearch-dashboards-body` is not found, it will fall back to `scrollWidth`.
*/
const innerBodyDims = document.getElementById('opensearch-dashboards-body')?.getBoundingClientRect();
const width = innerBodyDims?.width || document.documentElement.scrollWidth;
const height = document.documentElement.scrollHeight;

const documentBackgroundColor: string = (window.getComputedStyle(document.documentElement) as CSSStyleDeclaration).backgroundColor;
const bgColor = documentBackgroundColor.startsWith('#')
? documentBackgroundColor
// convert rgb() and rgba() to hex
: '#' + documentBackgroundColor.split(/[,()]/, 4).slice(1).map(v => parseInt(v).toString(16)).join('');

/* ToDo: `html2canvas` doesn't copy stylesheets when `foreignObjectRendering` is false. As a result
* `@font-family` definitions are lost; find a way to get them from the document and add
* them to the cloned document.
* ToDo: Don't add the header and footer to the document before cloning as they mess with what the
* users see.
*/
return html2canvas(document.body, {
scrollX: 0,
scrollY: 0,
windowWidth: width,
windowHeight: height,
width,
height,
backgroundColor: bgColor,
imageTimeout: 30000,
useCORS: true,
removeContainer: false,
allowTaint: true,
foreignObjectRendering: useForeignObjectRendering,
onclone: function (documentClone) {
removeNonReportElements(documentClone, reportSource);
// When the left nav is docked, the body element gets left-padded; this forces it to left-align
documentClone.body.style.padding = '0px';
if (!useForeignObjectRendering) {
addReportHeader(documentClone, header);
addReportFooter(documentClone, footer);
Expand Down Expand Up @@ -259,6 +272,9 @@ export const generateReport = async (id: string, forceDelay = 15000) => {
} else {
const orient = canvas.width > canvas.height ? 'landscape' : 'portrait';
const pdf = new jsPDF(orient, 'px', [canvas.width, canvas.height]);
pdf.setFillColor(bgColor);
// `+ 10` to fill in any uncolored areas that appear on the right and bottom edges of the PDF
pdf.rect(0, 0, canvas.width + 10, canvas.height + 10, "F");
pdf.addImage(canvas, 'JPEG', 0, 0, canvas.width, canvas.height);
pdf.save(fileName);
}
Expand Down
Loading