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

Add fallback method for CSV download #8452

Merged
merged 20 commits into from May 16, 2024
Merged

Add fallback method for CSV download #8452

merged 20 commits into from May 16, 2024

Conversation

LukasMasuch
Copy link
Collaborator

@LukasMasuch LukasMasuch commented Apr 6, 2024

Describe your changes

This PR adds a fallback to an old browser download method for CSV dataframe download feature. Some browser or situations might not correctly support the file picker feature, in these cases it will fallback to an older more commonly supported download method.

We also add iframe tests together with CSPs here. This can be used in the future also by other tests.

GitHub Issue Link (if applicable)

Testing Plan

  • E2E tests: added e2e tests for downloading a CSV file from the dataframe; also within an iframe and with a content-security-policy in-place

Contribution License Agreement

By submitting this pull request you agree that all contributions to this project are made under the Apache 2.0 license.

})
// Write row to CSV:
await writer.write(textEncoder.encode(toCsvRow(rowData)))
const url = URL.createObjectURL(blob)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Copy link

This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@@ -145,6 +146,10 @@ function DataFrame({

const { theme, headerIcons, tableBorderRadius } = useCustomTheme()

const {
libConfig: { enforceDownloadInNewTab = false }, // Default to false, if no libConfig, e.g. for tests
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

nit: I believe we can also just call that within the useDataExporter. Thought, I don't have any strong opinion if its better to get the context here or within the useDataExporter hook.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yeah, I just thought that not having nested hooks could be easier to comprehend, so keep it in DataFrame component, and pass to useDataExperter as parameter a little bit more preferable for me, although I also don't have super strong opinion here.

const url = URL.createObjectURL(blob)
const link = document.createElement("a")
if (enforceDownloadInNewTab) {
link.setAttribute("target", "_blank")
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

nit: maybe add a one-liner comment here why we are doing this

Copy link
Collaborator

Choose a reason for hiding this comment

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

Done!

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I meant more like answering why we are doing that: "Open the download link in a new tab to ensure that this is working in embedded setups that limit the URL that an iframe can navigate to (e.g. via CSP)."

Copy link
Collaborator

Choose a reason for hiding this comment

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

I rephrased with your suggestion!

@LukasMasuch LukasMasuch marked this pull request as ready for review May 14, 2024 17:26
<iframe
src="{app_url}"
title="Iframed Streamlit App"
sandbox="allow-popups allow-same-origin allow-scripts allow-downloads"
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

nit: are these also the same permissions we use in SIS / community cloud?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yeah I believe so, at least they are the ones @sfc-gh-jkinkead posted in the example in #8528
I will double-check!

Copy link
Collaborator

Choose a reason for hiding this comment

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

I have added allow="clipboard-write;" to the iframe which is used in SiS. CC has some more things allowed, but I guess its good to use the more locked-down one

timeout=10000,
):
frame_locator: FrameLocator = iframed_app.open_app()
_test_csv_download(page, frame_locator)
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

In this case, its using the fallback and not the file picker API or?

Copy link
Collaborator

Choose a reason for hiding this comment

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

yep it looks like in all iframe cases the fallback is used

Copy link
Collaborator

Choose a reason for hiding this comment

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

I have added another comment here to make this clear

@raethlein raethlein merged commit 48f50ad into develop May 16, 2024
35 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants