Skip to content

Commit

Permalink
feat(tupaiaWeb): RN-1402: Ability to generate continuous PDF for dash…
Browse files Browse the repository at this point in the history
…board export (#5894)

* setup controls

* Working exports

* Add page numbers

* Update DisplayOptionsSettings.tsx

* Only show format options on whole dashboard export

* Remove unused vars

* Fix logo height

---------

Co-authored-by: Andrew <[email protected]>
  • Loading branch information
alexd-bes and avaek authored Oct 3, 2024
1 parent 12e1b16 commit be5a588
Show file tree
Hide file tree
Showing 16 changed files with 194 additions and 50 deletions.
9 changes: 9 additions & 0 deletions packages/server-utils/src/downloadPageAsPDF.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ const buildParams = (pdfPageUrl: string, userCookie: string, cookieDomain: strin
return { verifiedPDFPageUrl, cookies: finalisedCookieObjects };
};

const pageNumberHTML = `<div style="text-align: right;width: 297mm;font-size: 8px;font-family: Arial, Helvetica, sans-serif;"><span style="margin-right: 1cm"><span class="pageNumber"></span></span></div>`;

/**
* @param pdfPageUrl the url to visit and download as a pdf
* @param userCookie the user's cookie to bypass auth, and ensure page renders under the correct user context
Expand All @@ -43,6 +45,7 @@ export const downloadPageAsPDF = async (
userCookie = '',
cookieDomain: string | undefined,
landscape = false,
includePageNumber = false,
) => {
let browser;
let buffer;
Expand All @@ -57,6 +60,12 @@ export const downloadPageAsPDF = async (
format: 'a4',
printBackground: true,
landscape,
displayHeaderFooter: includePageNumber,
// remove the default header so that only the page number is displayed, not a header
headerTemplate: `<div></div>`,
footerTemplate: pageNumberHTML,
//add a margin so the page number doesn't overlap with the content, and the top margin is set for overflow content
margin: includePageNumber ? { bottom: '10mm', top: '10mm' } : undefined,
});
} catch (e) {
throw new Error(`puppeteer error: ${(e as Error).message}`);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export const downloadDashboardAsPdf = (
settings: TupaiaWebExportDashboardRequest.ReqBody['settings'] = {
exportWithLabels: false,
exportWithTable: false,
separatePagePerItem: true,
},
) => {
const endpoint = `${projectCode}/${entityCode}/${dashboardName}/dashboard-pdf-export`;
Expand All @@ -26,5 +27,5 @@ export const downloadDashboardAsPdf = (
settings: JSON.stringify(settings),
});

return downloadPageAsPDF(pdfPageUrl, cookie, cookieDomain);
return downloadPageAsPDF(pdfPageUrl, cookie, cookieDomain, false, true);
};
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ import { Button, LoadingContainer } from '@tupaia/ui-components';
import { useEntity, useProject } from '../../../api/queries';
import { useExportDashboard } from '../../../api/mutations';
import { DashboardItemVizTypes, MOBILE_BREAKPOINT } from '../../../constants';
import { DisplayOptionsSettings, useExportSettings } from '../../ExportSettings';
import {
DisplayFormatSettings,
DisplayOptionsSettings,
useExportSettings,
} from '../../ExportSettings';
import { useDashboard } from '../utils';
import { ExportSubtitle } from './ExportSubtitle';
import { MailingListSection } from './MailingListSection';
Expand Down Expand Up @@ -99,6 +103,17 @@ const ExportSettingsInstructionsContainer = styled.div`
padding-bottom: 1.4rem;
`;

const ExportSettingsWrapper = styled.div`
padding-block-end: 2rem;
& + & {
padding-block-start: 1.5rem;
border-top: 0.1rem solid ${({ theme }) => theme.palette.text.secondary};
}
&:last-child {
padding-block-end: 0;
}
`;

interface ExportDashboardProps {
onClose: () => void;
selectedDashboardItems: string[];
Expand All @@ -109,7 +124,7 @@ export const ExportConfig = ({ onClose, selectedDashboardItems }: ExportDashboar
const { data: project } = useProject(projectCode);
const { data: entity } = useEntity(projectCode, entityCode);
const { activeDashboard } = useDashboard();
const { exportWithLabels, exportWithTable } = useExportSettings();
const { exportWithLabels, exportWithTable, separatePagePerItem } = useExportSettings();

const exportFileName = `${project?.name}-${entity?.name}-${dashboardName}-dashboard-export`;

Expand All @@ -124,6 +139,7 @@ export const ExportConfig = ({ onClose, selectedDashboardItems }: ExportDashboar
settings: {
exportWithLabels,
exportWithTable,
separatePagePerItem,
},
});

Expand All @@ -149,19 +165,30 @@ export const ExportConfig = ({ onClose, selectedDashboardItems }: ExportDashboar
<ExportSetting>
{hasChartItems && (
<section>
<DisplayOptionsSettings />
<ExportSettingsWrapper>
<DisplayFormatSettings />
</ExportSettingsWrapper>
<ExportSettingsWrapper>
<DisplayOptionsSettings />
</ExportSettingsWrapper>
</section>
)}
<MailingListSection
selectedDashboardItems={selectedDashboardItems}
settings={{
exportWithTable,
exportWithLabels,
separatePagePerItem,
}}
/>
</ExportSetting>
</ExportSettingsContainer>
{!isLoading && <Preview selectedDashboardItems={selectedDashboardItems} />}
{!isLoading && (
<Preview
selectedDashboardItems={selectedDashboardItems}
separatePagePerItem={separatePagePerItem}
/>
)}
</Container>
</Wrapper>
<ButtonGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ export const ExportDashboard = () => {
exportWithLabels: false,
exportWithTable: true,
exportWithTableDisabled: false,
separatePagePerItem: true,
}}
>
<Wrapper>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import React, { useState } from 'react';
import styled from 'styled-components';
import { Typography } from '@material-ui/core';
import { Pagination } from '@material-ui/lab';
import { A4Page } from '@tupaia/ui-components';
import { DashboardPDFExport } from '../../../views';
import { MOBILE_BREAKPOINT } from '../../../constants';

Expand Down Expand Up @@ -46,6 +47,13 @@ const PreviewContainer = styled.div`
min-width: 20rem;
overflow-y: auto;
overflow-x: hidden;
${A4Page} {
// simulate the margins of the printed page
padding-block-start: 5rem;
&:last-child {
padding-block-end: 5rem;
}
}
`;

const PreviewTitle = styled(Typography).attrs({
Expand All @@ -57,24 +65,34 @@ const PreviewTitle = styled(Typography).attrs({
line-height: 1.4;
`;

export const Preview = ({ selectedDashboardItems }: { selectedDashboardItems: string[] }) => {
export const Preview = ({
selectedDashboardItems,
separatePagePerItem,
}: {
selectedDashboardItems: string[];
separatePagePerItem: boolean;
}) => {
const [page, setPage] = useState(1);
const onPageChange = (_: unknown, newPage: number) => setPage(newPage);
const visualisationToPreview = selectedDashboardItems[page - 1];
const visualisationToPreview = separatePagePerItem
? [selectedDashboardItems[page - 1]]
: selectedDashboardItems;

return (
<PreviewPanelContainer>
<PreviewHeaderContainer>
<PreviewTitle>Preview</PreviewTitle>
<PreviewPagination
size="small"
siblingCount={0}
count={selectedDashboardItems.length}
onChange={onPageChange}
/>
{separatePagePerItem && (
<PreviewPagination
size="small"
siblingCount={0}
count={selectedDashboardItems.length}
onChange={onPageChange}
/>
)}
</PreviewHeaderContainer>
<PreviewContainer>
<DashboardPDFExport selectedDashboardItems={[visualisationToPreview]} isPreview={true} />
<DashboardPDFExport selectedDashboardItems={visualisationToPreview} isPreview={true} />
</PreviewContainer>
</PreviewPanelContainer>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* Tupaia
* Copyright (c) 2017 - 2024 Beyond Essential Systems Pty Ltd
*/

import React from 'react';
import styled from 'styled-components';
import { FormControl, FormControlLabel, Radio, RadioGroup } from '@material-ui/core';
import { useExportSettings } from './ExportSettingsContext';
import { ExportSettingLabel } from './ExportSettingLabel';

const Wrapper = styled.div`
display: flex;
flex-direction: column;
`;

const RadioItem = styled(FormControlLabel)`
padding-block-end: 0.625rem;
&:first-child {
padding-block-start: 0.625rem;
}
.MuiButtonBase-root {
padding-block: 0;
}
`;

export const DisplayFormatSettings = () => {
const { separatePagePerItem, updateSeparatePagePerItem } = useExportSettings();

return (
<Wrapper>
<FormControl component="fieldset">
<ExportSettingLabel as="legend">Format</ExportSettingLabel>
<RadioGroup
name="separatePagePerItem"
value={separatePagePerItem}
onChange={updateSeparatePagePerItem}
>
<RadioItem value={true} control={<Radio color="primary" />} label="One per page" />
<RadioItem value={false} control={<Radio color="primary" />} label="Print continuous" />
</RadioGroup>
</FormControl>
</Wrapper>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ const Group = styled(FormGroup)`
}
`;

const Wrapper = styled.div`
display: flex;
flex-direction: column;
`;

export const DisplayOptionsSettings = () => {
const {
exportWithLabels,
Expand All @@ -41,28 +46,30 @@ export const DisplayOptionsSettings = () => {
if (exportFormat !== ExportFormats.PNG) return null;

return (
<FormControl component="fieldset">
<ExportSettingLabel as="legend">Display options</ExportSettingLabel>
<Group>
<Checkbox
label="Export with labels"
value={true}
name="displayOptions"
color="primary"
checked={exportWithLabels}
onChange={updateExportWithLabels}
/>
{!exportWithTableDisabled && (
<Wrapper>
<FormControl component="fieldset">
<ExportSettingLabel as="legend">Display options</ExportSettingLabel>
<Group>
<Checkbox
label="Export with table"
label="Export with labels"
value={true}
name="displayOptions"
color="primary"
checked={exportWithTable}
onChange={updateExportWithTable}
checked={exportWithLabels}
onChange={updateExportWithLabels}
/>
)}
</Group>
</FormControl>
{!exportWithTableDisabled && (
<Checkbox
label="Export with table"
value={true}
name="displayOptions"
color="primary"
checked={exportWithTable}
onChange={updateExportWithTable}
/>
)}
</Group>
</FormControl>
</Wrapper>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,26 @@ type ExportSettings = {
exportWithLabels: boolean;
exportWithTable: boolean;
exportWithTableDisabled: boolean;
separatePagePerItem: boolean;
};

type ExportSettingsContextType = ExportSettings & {
setExportFormat: (value: ExportFormats) => void;
setExportWithLabels: (value: boolean) => void;
setExportWithTable: (value: boolean) => void;
setSeparatePagePerItem: (value: boolean) => void;
};

const defaultContext = {
exportFormat: ExportFormats.PNG,
exportWithLabels: false,
exportWithTable: true,
exportWithTableDisabled: false,
separatePagePerItem: true,
setExportFormat: () => {},
setExportWithLabels: () => {},
setExportWithTable: () => {},
setSeparatePagePerItem: () => {},
} as ExportSettingsContextType;

// This is the context for the export settings
Expand All @@ -45,6 +49,8 @@ export const useExportSettings = () => {
setExportFormat,
setExportWithLabels,
setExportWithTable,
separatePagePerItem,
setSeparatePagePerItem,
} = useContext(ExportSettingsContext);

const updateExportFormat = (e: ChangeEvent<HTMLInputElement>) =>
Expand All @@ -58,10 +64,15 @@ export const useExportSettings = () => {
setExportWithTable(e.target.checked);
};

const updateSeparatePagePerItem = (e: ChangeEvent<HTMLInputElement>) => {
setSeparatePagePerItem(e.target.value === 'true');
};

const resetExportSettings = (dashboardItemType?: string) => {
setExportFormat(dashboardItemType === 'matrix' ? ExportFormats.XLSX : ExportFormats.PNG);
setExportWithLabels(false);
setExportWithTable(true);
setSeparatePagePerItem(true);
};

return {
Expand All @@ -73,6 +84,8 @@ export const useExportSettings = () => {
updateExportWithLabels,
updateExportWithTable,
resetExportSettings,
separatePagePerItem,
updateSeparatePagePerItem,
};
};

Expand All @@ -95,6 +108,11 @@ export const ExportSettingsContextProvider = ({
const [exportWithTableDisabled] = useState<boolean>(
defaultSettings?.exportWithTableDisabled || false,
);

const [separatePagePerItem, setSeparatePagePerItem] = useState<boolean>(
defaultSettings?.separatePagePerItem || true,
);

return (
<ExportSettingsContext.Provider
value={{
Expand All @@ -105,6 +123,8 @@ export const ExportSettingsContextProvider = ({
setExportFormat,
setExportWithLabels,
setExportWithTable,
separatePagePerItem,
setSeparatePagePerItem,
}}
>
{children}
Expand Down
1 change: 1 addition & 0 deletions packages/tupaia-web/src/features/ExportSettings/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@
export { DisplayOptionsSettings } from './DisplayOptionsSettings';
export { ExportSettingLabel } from './ExportSettingLabel';
export { ExportFormatSettings } from './ExportFormatSettings';
export { DisplayFormatSettings } from './DisplayFormatSettings';
export * from './ExportSettingsContext';
Loading

0 comments on commit be5a588

Please sign in to comment.