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

feat(tupaiaWeb): RN-1402: Ability to generate continuous PDF for dashboard export #5894

Merged
merged 9 commits into from
Oct 3, 2024
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
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