Browse Source

file name to download (#433) (#1020)

* file name to download (#433)
default content provider plotly and matplotlib)

* isort

* fix tests

* black

* fix tests

* Revert "fix tests"

This reverts commit c3bdf37e8067e91aedaf93b90cd44c23231da932.

* leave / for better readability

---------

Co-authored-by: Fred Lefévère-Laoide <Fred.Lefevere-Laoide@Taipy.io>
Fred Lefévère-Laoide 1 year ago
parent
commit
740abf9660

+ 2 - 2
gui/src/components/Taipy/FileDownload.spec.tsx

@@ -78,7 +78,7 @@ describe("FileDownload Component", () => {
     });
     it("dispatch a well formed message when content is not empty", async () => {
         const server = newServer({
-            get: ['/some/link/to.png', {
+            get: ['/some/link/to.png?bypass=', {
               // status: 200 is the default
               //headers: { 'Content-Type': 'application/json' },
               body: '{ "message": "Success!" }',
@@ -96,7 +96,7 @@ describe("FileDownload Component", () => {
         await userEvent.click(elt);
         await waitFor(() => expect(dispatch).toHaveBeenCalledWith({
             name: "anId",
-            payload: { args: ["from.png", "/some/link/to.png"], action: "on_action" },
+            payload: { args: ["from.png", "/some/link/to.png?bypass="], action: "on_action" },
             type: "SEND_ACTION_ACTION",
         }));
         server.remove();

+ 2 - 2
gui/src/components/Taipy/FileDownload.tsx

@@ -36,7 +36,7 @@ interface FileDownloadProps extends TaipyActiveProps {
 }
 
 const FileDownload = (props: FileDownloadProps) => {
-    const { id, auto, name = "", bypassPreview, onAction, label, defaultLabel = "" } = props;
+    const { id, auto, name = "", bypassPreview = true, onAction, label, defaultLabel = "" } = props;
     const aRef = useRef<HTMLAnchorElement>(null);
     const dispatch = useDispatch();
     const module = useModule();
@@ -57,7 +57,7 @@ const FileDownload = (props: FileDownloadProps) => {
             usp.append("bypass", "");
         }
         const ret = usp.toString();
-        return [ret.length ? url + "?" + ret : url, !!bypassPreview && (name || true)];
+        return [ret.length ? url + "?" + ret : url, bypassPreview && (name || true)];
     }, [props.content, bypassPreview, name, props.defaultContent]);
 
     useEffect(() => {

+ 2 - 1
src/taipy/gui/data/content_accessor.py

@@ -13,6 +13,7 @@ import base64
 import pathlib
 import tempfile
 import typing as t
+import urllib.parse
 from importlib import util
 from pathlib import Path
 from sys import getsizeof
@@ -112,7 +113,7 @@ class _ContentAccessor:
             self.__content_paths[url_path] = dir_path
             file_url = f"{url_path}/{path.name}"
             self.__url_is_image[file_url] = image
-            return (file_url,)
+            return (urllib.parse.quote_plus(file_url, safe="/"),)
         elif _has_magic_module:
             try:
                 mime = magic.from_buffer(value, mime=True)

+ 32 - 0
src/taipy/gui/gui.py

@@ -24,6 +24,7 @@ import time
 import typing as t
 import warnings
 from importlib import metadata, util
+from importlib.util import find_spec
 from types import FrameType, SimpleNamespace
 from urllib.parse import unquote, urlencode, urlparse
 
@@ -416,6 +417,37 @@ class Gui:
             if isinstance(content, _TaipyContentHtml):
                 content = content.get()
             provider_fn = Gui.__content_providers.get(type(content))
+            if provider_fn is None:
+                # try plotly
+                if find_spec("plotly") and find_spec("plotly.graph_objs"):
+                    from plotly.graph_objs import Figure as PlotlyFigure
+
+                    if isinstance(content, PlotlyFigure):
+
+                        def get_plotly_content(figure: PlotlyFigure):
+                            return figure.to_html()
+
+                        Gui.register_content_provider(PlotlyFigure, get_plotly_content)
+                        provider_fn = get_plotly_content
+            if provider_fn is None:
+                # try matplotlib
+                if find_spec("matplotlib") and find_spec("matplotlib.figure"):
+                    from matplotlib.figure import Figure as MatplotlibFigure
+
+                    if isinstance(content, MatplotlibFigure):
+
+                        def get_matplotlib_content(figure: MatplotlibFigure):
+                            import base64
+                            from io import BytesIO
+
+                            buf = BytesIO()
+                            figure.savefig(buf, format="png")
+                            data = base64.b64encode(buf.getbuffer()).decode("ascii")
+                            return f'<img src="data:image/png;base64,{data}"/>'
+
+                        Gui.register_content_provider(MatplotlibFigure, get_matplotlib_content)
+                        provider_fn = get_matplotlib_content
+
             if callable(provider_fn):
                 try:
                     return provider_fn(content)