holoviz / panel

Panel: The powerful data exploration & web app framework for Python
https://panel.holoviz.org
BSD 3-Clause "New" or "Revised" License
4.84k stars 520 forks source link

Several stylings do not load when disconnected from the internet (i.e. behind a corporate firewall) #7073

Open giladpn opened 4 months ago

giladpn commented 4 months ago

ALL software version info

Panel 1.4.5 Panel is loaded with pn.serve from a Uvicorn FastAPI server. Uvicorn 0.30.5 Panel Server on Ubuntu 22.04 Browser is MS Edge on Windows 11

Description of expected behavior and the observed behavior

Please try disconnecting from the internet and connecting (locally) to a Panel server. This simulates the environment behind a corporate firewall, where both the server and the user are in the same network, but no access is available to the web.

Numerous stylings will not work, including:

The screenshots below are informative: they show (in MS Edge) the CDN URLs that are not being loaded. Please note there is more than one. I have not tried out all Panel features, so there may be more.

Extensions loaded

pn.extension('floatpanel', 'tabulator', 'codeeditor',
                     nthreads=n_concurrent_threads)
hv.extension('bokeh')

Screenshots or screencasts of the bug in action

image

image

DmitriyLeybel commented 4 months ago

I've also attempted using pn.config.inline = True, but that doesn't remedy the issue either.

DmitriyLeybel commented 4 months ago

Gave loading my own assets a shot, and that didn't work either. Looks like the absence of connection prevented the ToggleIcon from being loaded entirely(?).

pn.config.css_files = ['assets/file_icons/tabler-icons-outline.min.css']
srv1 = pn.serve(pn.widgets.ToggleIcon(icon="heart"), static_dirs={'assets': '/workspaces/pyllments/pyllments/assets'})

(internet connection disabled) image

The Tabler icons are awesome, but it would be great if there was an option to use them offline, and to include them throughout the Panel library for ease of access - such as in Markdown and other fields, without having to grab the css and font files, include them as static assets, etc... Would go a long way in helping skin Panel apps IMO.

This is what worked for me as far as MD goes:

heart_markdown = pn.pane.Markdown("""<i class="ti ti-heart"></i>"""
srv = pn.serve(heart_markdown, static_dirs={'assets': '/workspaces/pyllments/pyllments/assets'})
ahuang11 commented 4 months ago

Does it work with button icon? pn.widgets.Button(icon="heart")

giladpn commented 4 months ago

@ahuang11 sorry but no. I tested with

pn.widgets.Button(icon="plus")
ahuang11 commented 4 months ago

Could be a Bokeh upstream issue; could you test it with vanilla Bokeh?

https://docs.bokeh.org/en/3.1.0/docs/examples/interaction/widgets/button_icon.html

from bokeh.io import show
from bokeh.models import BuiltinIcon, Button, SetValue

icon = BuiltinIcon("settings", size="1.2em", color="white")
button = Button(label="Foo", icon=icon, button_type="primary")
button.js_on_event("button_click", SetValue(button, "label", "Bar"))

show(button)

Maybe relevant info https://github.com/holoviz/panel/issues/6022

DmitriyLeybel commented 4 months ago

Isn't this just a connection issue? Code editor uses ace, which calls the CDN

class AcePlot(HTMLBox):
    """
    A Bokeh model that wraps around a Ace editor and renders it inside
    a Bokeh plot.
    """

    __javascript_raw__ = [
        'https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.11/ace.js',
        'https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.11/ext-language_tools.js',
        'https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.11/ext-modelist.js'
    ]

    __tarball__ = {
        'tar': 'https://registry.npmjs.org/ace-builds/-/ace-builds-1.4.11.tgz',
        'src': 'package/src-min/',
        'dest': 'ajax/libs/1.4.11',
        'exclude': ['*snippets/*']
    }
giladpn commented 4 months ago

@ahuang11 thanks for the suggestion, that particular snippet of code did work on my system (Jupyter notebook). The bokeh icon showed, though it doesn't when I use a Panel button and disconnect from the web.

But more generally, I do want to add that the issue is not just with button icons. In order of priority, I think the sub-issues of the general issue are

  1. pn.pane.image.Image widgets do not load properly
  2. progress bars as used in the Progress widget are mis-styled
  3. adding the Code Editor widget (using `pn.extension('codeeditor') may cause the entire app to not come up
  4. button icons from the "tablers" icons
  5. stylings look a bit different ... and since I did not test every feature in Panel, there may be more than that.
giladpn commented 4 months ago

Sure. Point is it effects all these different cases.

I am guessing your solution would be a minified js that contains - inside panel - all the missing CDN files. If true, you would need to list all the missing css/js files. The above is a first draft of such a list.

On Mon, 5 Aug 2024, 20:23 Dmitriy Leybel, @.***> wrote:

Isn't this just a connection issue? Code editor uses ace, which calls the CDN

class AcePlot(HTMLBox): """ A Bokeh model that wraps around a Ace editor and renders it inside a Bokeh plot. """

__javascript_raw__ = [
    'https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.11/ace.js',
    'https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.11/ext-language_tools.js',
    'https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.11/ext-modelist.js'
]

__tarball__ = {
    'tar': 'https://registry.npmjs.org/ace-builds/-/ace-builds-1.4.11.tgz',
    'src': 'package/src-min/',
    'dest': 'ajax/libs/1.4.11',
    'exclude': ['*snippets/*']
}

— Reply to this email directly, view it on GitHub https://github.com/holoviz/panel/issues/7073#issuecomment-2269553224, or unsubscribe https://github.com/notifications/unsubscribe-auth/AOLOROEI7H3XPKBDYZPTBR3ZP6YKZAVCNFSM6AAAAABL6XFIO6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDENRZGU2TGMRSGQ . You are receiving this because you authored the thread.Message ID: @.***>

philippjfr commented 4 months ago

Just as a bit of background, by default Panel bundles CDN resources into the package at build time. In a notebook we currently do not have a good way to load these local resources (although in theory it's possible), on a server we generally load it from the local server.

giladpn commented 4 months ago

@philippjfr thanks. My use case as noted above is a server. My server is uvicorn fastapi and I am using pn.serve in my python server code to bring up the panel server.

Can you advise how to get the benefit of the panel bundled resources?

giladpn commented 3 months ago

@philippjfr @ahuang11 @DmitriyLeybel thanks for all the support so far. Based on @philippjfr last comment, I checked: I ran my server as a panel serve ... standalone server rather than within uvicorn.

Several issues were indeed solved, and several issues were not. The solved issues are:

The unresolved issues are:

Below is a screenshot of the CDN errors when using the panel serve standalone configuration.

Based on your insight, I assume that the last two components (ACE code editor, tabler icons) are not included in your bundled CDN resources.

and here are the screenshots with the CDN errors:

image


The related issue, which is what started this thread, is still open: I still want to run my app in a larger uvicorn fastapi server which does more things. In this case, the "resolved" issues above come back and bite us.

So, I assume such a configuration disables the Panel bundle - though interestingly it does not disable Bokeh. The pure Bokeh min.js still comes up well enough.

Hopefully, if Bokeh can do it then there is a way to do this for Panel as well. Can you bundle your CDN resources in such a way that the uvicorn approach is not broken?

If it helps, I am glad to share my uvicorn code. Below is the main idea, but I can share more if it's needed.

from fastapi import FastAPI, Request, Response, BackgroundTasks
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import FileResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates

import panel as pn
from bokeh.embed import server_document

##### Instantiate the FastAPI server
app = FastAPI(title="My server")

##### Allow our server to receive requests from other URIs (CORS)
origins = ["*"]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

##### Instantiate the Panel/Bokeh plots' sub-server
def make_plot_server():
    return pn.serve(
        {'/app': createApp},
        threaded=True,
        port=5000, allow_websocket_origin=["127.0.0.1:8000"],
        address="127.0.0.1", show=False,
    )
templates = Jinja2Templates(directory="./templates")
server = make_plot_server()

@app.get("/")
async def bkapp_page(request: Request):
    script = server_document('http://127.0.0.1:5000/app')
    return templates.TemplateResponse("base.html", {"request": request, "script": script})

class MyApp:

    def __init__(self, n_concurrent_threads=4):
        pn.extension(_selection_ui_type, 'tabulator', 'codeeditor',
                     nthreads=n_concurrent_threads)
        hv.extension('bokeh')

    ...   # much irrelevant code

def createApp():
    app = App()
    return app.servable()

Many thanks as always.

giladpn commented 3 months ago

@philippjfr @ahuang11 @DmitriyLeybel thanks for all the support so far. Based on @philippjfr last comment, I checked: I ran my server as a panel serve ... standalone server rather than within uvicorn.

Several issues were indeed solved, and several issues were not. The solved issues are:

The unresolved issues are:

Below is a screenshot of the CDN errors when using the panel serve standalone configuration.

Based on your insight, I assume that the last two components (ACE code editor, tabler icons) are not included in your bundled CDN resources.

and here are the screenshots with the CDN errors:

image


The related issue, which is what started this thread, is still open: I still want to run my app in a larger uvicorn fastapi server which does more things. In this case, the "resolved" issues above come back and bite us.

So, I assume such a configuration disables the Panel bundle - though interestingly it does not disable Bokeh. The pure Bokeh min.js still comes up well enough.

Hopefully, if Bokeh can do it then there is a way to do this for Panel as well. Can you bundle your CDN resources in such a way that the uvicorn approach is not broken?

If it helps I am glad to share my uvicorn code. Below is the main idea, but I can share more if it's needed.

from fastapi import FastAPI, Request, Response, BackgroundTasks
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import FileResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates

import panel as pn
from bokeh.embed import server_document
import holoviews as hv

##### Instantiate the FastAPI server
app = FastAPI(title="My server")

##### Allow our server to receive requests from other URIs (CORS)
origins = ["*"]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

##### Instantiate the Panel/Bokeh plots' sub-server
def make_plot_server():
    return pn.serve(
        {'/app': createApp},
        threaded=True,
        port=5000, allow_websocket_origin=["127.0.0.1:8000"],
        address="127.0.0.1", show=False,
    )
templates = Jinja2Templates(directory="./templates")
server = make_plot_server()

@app.get("/")
async def bkapp_page(request: Request):
    script = server_document('http://127.0.0.1:5000/app')
    return templates.TemplateResponse("base.html", {"request": request, "script": script})

class MyApp:

    def __init__(self, n_concurrent_threads=4):
        pn.extension('floatpanel', 'tabulator', 'codeeditor',
                     nthreads=n_concurrent_threads)
        hv.extension('bokeh')

    ...   # much irrelevant code

def createApp():
    app = MyApp()
    return app.servable()

Many thanks as always.

giladpn commented 1 month ago

Hi.

Progress report.

@philippjfr @ahuang11 @DmitriyLeybel

I upgraded to use the new panel-fastapi integration as described in https://panel.holoviz.org/how_to/integrations/FastAPI.html

I also changed my code in accordance with the above. I can report that the situation has improved to the same level I had with using "panel serve" (as reported above) but is not completely solved. Meaning the solved issues are:

The unresolved issues are:

Below is a screenshot of what I see in the current state. This is progress - I can now use fastapi and achieve the same level as with the pure tornado implementation; but it is not yet a complete solution. Thank you for the progress.

image