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

[DataGrid] Print export #2519

Merged
merged 30 commits into from
Oct 13, 2021
Merged

Conversation

DanailH
Copy link
Member

@DanailH DanailH commented Sep 1, 2021

Fixes #200

This is the initial version of the Print Export feature. I'll keep the PR as a Draft for now as tests and docs are missing from the PR and I would like to discuss the approach and features before adding the tests and docs and converting it to normal PR.

Preview: https://deploy-preview-2519--material-ui-x.netlify.app/storybook/?path=/story/x-grid-tests-toolbar--export

Explanation:

In the Export drop-down menu in the GridToolbar is now an additional button called Print. The remaining API is part of the useGridPrintExport hook. The setup is identical to the CSV Export feature.

Options available for the Print Export:

export interface GridPrintExportOptions {
  /**
   * The string used as the print window title.
   * @default 'Print Window'
   */
  fileName?: string;
  /**
   * The columns to be printed.
   * This should only be used if you want to restrict the columns exports.
   */
  fields?: string[];
  /**
   * If `true`, the hidden columns will also be printed.
   * @default false
   */
  allColumns?: boolean;
  /**
   * If `true`, the toolbar is removed for when printing.
   * @default false
   */
  hideToolbar?: boolean;
  /**
   * If `true`, the footer is removed for when printing.
   * @default false
   */
  hideFooter?: boolean;
  /**
   * If `false`, all <style> and <link type="stylesheet" /> tags from the <head> will not be copied
   * to the print window.
   * @default true
   */
  copyStyles?: boolean;
  /**
   * One or more classes passed to the print window.
   */
  bodyClass?: string;
  /**
   * Provide Print specific styles to the print window.
   */
  pageStyle?: string | Function;
}

These options can also be passed to the GridToolbarExport component (same as the CSV export).


ToDo:

  • Add tests
  • Add docs

@DanailH DanailH added component: data grid This is the name of the generic UI component, not the React module! new feature New feature or request labels Sep 1, 2021
@DanailH DanailH self-assigned this Sep 1, 2021
@DanailH DanailH marked this pull request as draft September 1, 2021 13:31
@DanailH DanailH added this to the Sprint 21 milestone Sep 1, 2021
Copy link
Member

@m4theushw m4theushw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had a quick look and it's working fantastically. 👌

  1. Did you think about exposing the function below as a disableVirtualization API call? It could be used instead of updating the state.

https://github.com/mui-org/material-ui-x/blob/4eb92a6dcae63f6fbb0bb9d195a8adde805a356f/packages/grid/_modules_/grid/hooks/features/virtualization/useGridNoVirtualization.ts#L23

  1. We could add a few CSS rules with @media print to make the grid print-safe. The left and right borders could be removed, the same for the padding.

  2. In the full-featured demo, when I close the print window it shows columns that were hidden before, like the ID.

@DanailH
Copy link
Member Author

DanailH commented Sep 2, 2021

I had a quick look and it's working fantastically. 👌

  1. Did you think about exposing the function below as a disableVirtualization API call? It could be used instead of updating the state.

https://github.com/mui-org/material-ui-x/blob/4eb92a6dcae63f6fbb0bb9d195a8adde805a356f/packages/grid/_modules_/grid/hooks/features/virtualization/useGridNoVirtualization.ts#L23

  1. We could add a few CSS rules with @media print to make the grid print-safe. The left and right borders could be removed, the same for the padding.
  2. In the full-featured demo, when I close the print window it shows columns that were hidden before, like the ID.

@m4theushw thanks for the review. I'll wait to see what the others have to say and fix the issues.

For the disableVirtualization - when worked on the implementation that wasn't available. I can have a look and see about exposing it.

I was thinking of adding the CSS rules. We can add a few but that's why I added the option for people to provide their own riles directly.

I'll check about the hidden columns, that shouldn't happen

@flaviendelangle
Copy link
Member

Concerning the rename of the CSV option interface

We will need to make a PR in the core (adding also the print at the same time I suppose) and then delete this file (and the js part).

https://github.com/mui-org/material-ui-x/blob/2dbaca1a24fb554408e6b8ec225bf612d8e445a9/docs/pages/api-docs/data-grid/grid-export-csv-options.md

Copy link
Member

@oliviertassinari oliviertassinari left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like a great start. We are going further than what I was expecting for the first iteration, which is cool. I would propose we offer two different levels of solution:

  1. You have built an API to turn the rendering of the grid in a print-ready mode. I would propose that we double down on it:
  1. The new export menu option is cool. It's what I mean by "going further than what I was expecting". I didn't notice something specific about it, outside of a few changes, some breaking, on the existing CSV feature that maybe should be done standalone (not sure, I assume we fixed stuff not directly related to the print).

A side thought, for the docs, we could try to sell developers to use the Print export when they need the PDF export 😁

// Revert columns to their original state
apiRef!.current.updateColumns(
columns.map((column) => {
if (previousHiddenColumns.current.includes(column.field)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of keeping track of a previousHiddenColumns state, could it be simpler to store the whole column state and restore it?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, it won't work unless I deep clone it.

Comment on lines 61 to 78
setGridState((state) => {
previousGridState.current = state;
return {
...state,
containerSizes: {
...state.containerSizes!,
renderingZone: {
...state.containerSizes!.renderingZone,
height: visibleSortedRows.size * props.rowHeight!,
},
renderingZonePageSize: visibleSortedRows.size,
},
viewportSizes: {
...state.viewportSizes,
height: visibleSortedRows.size * props.rowHeight!,
},
};
});
Copy link
Member

@oliviertassinari oliviertassinari Sep 2, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This logic looks brittle (away from the related logic, and might duplicate). Is there a way we could call an imperative API, e.g. an enableAutoHeight() method to move it closer to the hooks that manage containerSizes and viewportSizes as well as not duplicating the logic that handles the autoHeight prop?

Copy link
Member Author

@DanailH DanailH Sep 8, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I took a bit more time to check this more in-depth. The problem is that this logic doesn't really do enable autoHeight neither it disables the virtualization. What it does is force the grid to render all rows (have all the HTML for the rows be in the dom but still keep the scroll so that the content on the page doesn't jump).

For example @m4theushw suggestion to reuse his logic from the useGridNoVirtualization won't work because as far as can see there are other places where that prop is directly red and used (same as the autoHeight , which was my original idea). I'll see if moving that chunk into useGridNoVirtualization will make sense and expose it as an API from there.


Update: Another solution is to explain in the docs that in order to use the feature one needs to set disableVirtualization={true}. I would love some feedback on this approach as it will only be applicable for the DataGridPro

@oliviertassinari oliviertassinari modified the milestones: Sprint 21, Sprint 22 Sep 6, 2021
@flaviendelangle
Copy link
Member

@DanailH https://github.com/mui-org/material-ui-x/blob/next/docs/src/pages/components/data-grid/getting-started/getting-started.md

We can update the Print line on this page

@flaviendelangle flaviendelangle removed this from the v5 stable version milestone Oct 4, 2021
Copy link
Member

@m4theushw m4theushw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the dark mode is used it will print with the styles from the dark mode. Since we only have the dark styles to copy I don't see an easy alternative. I think only with option 3 from #2519 (comment) we can solve that, by creating another theme to wrap the grid before rendering.

image

packages/grid/_modules_/grid/models/gridExport.ts Outdated Show resolved Hide resolved
const buildPrintWindow = React.useCallback((title?: string): HTMLIFrameElement => {
const iframeEl = document.createElement('iframe');

iframeEl.id = 'grid-print-window';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will it work without the id? If not, useId() could be used to generate a unique value.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The id is only used for the tests. If we are going with your approach, setting the id is not needed.

previousGridState.current = gridState;

if (props.pagination) {
apiRef.current.setPageSize(visibleRowCount);
Copy link
Member

@m4theushw m4theushw Oct 5, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This won't work if the user is controlling the page size. Forcing the state also doesn't work, because it will require a forceUpdate() to propagate the changes, and when this runs, all effects will also run again and reset the value back to the prop value. I see some options:

  1. Add a escape hatch to temporarily disable the state update constraint. https://github.com/mui-org/material-ui-x/blob/95fed89847c5f1489ddb63dafedcf0d907d46354/packages/grid/_modules_/grid/hooks/features/core/useGridControlState.ts#L40
  2. Add a note to the docs mentioning that the print export doesn't work if pageSize or page is present.
  3. Render the grid inside the iframe and disable the virtualization:
ReactDOM.render(<DataGrid {...props} disableVirtualization />, iframeEl)

There's going to be a dependency cycle with 3., which I believe we could solve by using require() instead of import.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would go with option 2. -> the reason is that 3. for me will be too expensive in terms of the time it will take to render.
Also, this feature (along with a couple of other ones) doesn't work with server-side pagination which is controlled. If a developer is controlling the pagination the print export has an API that they can call manually.

This looks to me like a corner case - we can see what the feedback will be and if it is problem then we can spend time fixing it.

@DanailH DanailH removed the PR: out-of-date The pull request has merge conflicts and can't be merged label Oct 6, 2021
@github-actions github-actions bot added the PR: out-of-date The pull request has merge conflicts and can't be merged label Oct 6, 2021
@github-actions
Copy link

github-actions bot commented Oct 6, 2021

This pull request has conflicts, please resolve those before we can evaluate the pull request.

@github-actions github-actions bot removed the PR: out-of-date The pull request has merge conflicts and can't be merged label Oct 6, 2021
* Print the grid's data.
* @param {GridPrintExportOptions} options The options to apply on the export.
*/
exportDataAsPrint: (options?: GridPrintExportOptions) => void;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should rename this one UNSTABLE_exportDataAsPrint for a few months, the time to stabilize the API and behavior.

We should probably do it for most of the new API methods.
On the Tree Data I also hide them from the documentation (@ignore) but the UNSTABLE_ may be enough

Copy link
Member Author

@DanailH DanailH Oct 12, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm with this as long as we keep it as a general rule of thumb - new API methods should be marked as unstable @m2mathew @oliviertassinari what do you think?

Update: I'll keep this one as it is because I use it on the toolbar button directly. But I marked the disableVirtualization one as unstable.

@@ -58,7 +58,8 @@ dataGridComponentAPI.children = [
{ pathname: '/api-docs/data-grid/grid-col-def', title: 'GridColDef' },
{ pathname: '/api-docs/data-grid/grid-cell-params', title: 'GridCellParams' },
{ pathname: '/api-docs/data-grid/grid-row-params', title: 'GridRowParams' },
{ pathname: '/api-docs/data-grid/grid-export-csv-options', title: 'GridExportCSVOptions' },
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do we avoid having 404 on the doc while we update the core page list ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can merge that and then open a PR against the core with this change.

packages/grid/_modules_/grid/models/gridExport.ts Outdated Show resolved Hide resolved
@DanailH
Copy link
Member Author

DanailH commented Oct 12, 2021

@m2mathew @flaviendelangle I would like to proceed with merging this and releasing it to see what the feedback will be. Ideally, I would like to merge it tomorrow or today so that it is included in this week's release.

@github-actions
Copy link

This pull request has conflicts, please resolve those before we can evaluate the pull request.

@github-actions github-actions bot added the PR: out-of-date The pull request has merge conflicts and can't be merged label Oct 12, 2021
@github-actions github-actions bot removed the PR: out-of-date The pull request has merge conflicts and can't be merged label Oct 12, 2021
@github-actions
Copy link

This pull request has conflicts, please resolve those before we can evaluate the pull request.

@github-actions github-actions bot added the PR: out-of-date The pull request has merge conflicts and can't be merged label Oct 13, 2021
@github-actions github-actions bot removed the PR: out-of-date The pull request has merge conflicts and can't be merged label Oct 13, 2021
@DanailH DanailH merged commit f422f9a into mui:next Oct 13, 2021
@DanailH
Copy link
Member Author

DanailH commented Oct 13, 2021

As we discussed I'm merging this.

Copy link
Member

@m4theushw m4theushw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The print button is not working. We should fix this before the release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
component: data grid This is the name of the generic UI component, not the React module! new feature New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[DataGrid] Implement Print export
4 participants