Cyrus
Cyrus
SSolara
Created by Cyrus on 8/19/2024 in #questions-issues
Force solara to use https in redirect uris
Using Chrome's Dev Tools, I observed the following network requests after clicking the login button in my application: Initial Login Request: https://example.com/_solara/auth/login?redirect_uri=https%3A//example.com/return_to_path This request looks correct as it uses https. Authorization Request to Okta: https://my-okta-domain.oktapreview.com/oauth2/v1/authorize?response_type=code&client_id=MY_CLIENT_ID&redirect_uri=http%3A%2F%2Fexample.com%2F_solara%2Fauth%2Fauthorize&scope=openid+profile+email&state=MY_STATE&nonce=MY_NONCE The issue here is that the redirect_uri parameter is using http instead of https. Is there a way to force a solara application to use https scheme/protocol for redirect URIs (for auth). I tried setting SOLARA_SESSION_HTTPS_ONLY=True and SOLARA_BASE_URL=https://example.com/ but I still see http. Maybe I could mount my solara app to a Starlette app with an added HTTPSRedirectMiddleware middleware?
37 replies
SSolara
Created by Cyrus on 8/8/2024 in #questions-issues
Redirect URI error when testing login in solara app
Hi, I am trying to test an auth example in solara via okta. I have configured my app in okta following the solara docs and I am trying to test (locally) a simple login button. The relevant part of the snippet is

import solara
from solara_enterprise import auth

@solara.component
def Page():

[...]

if not auth.user.value:
#print(auth.get_login_url())
with solara.Tooltip('Login'):
solara.Button(icon_name="mdi-login", href=auth.get_login_url(), icon=True)

import solara
from solara_enterprise import auth

@solara.component
def Page():

[...]

if not auth.user.value:
#print(auth.get_login_url())
with solara.Tooltip('Login'):
solara.Button(icon_name="mdi-login", href=auth.get_login_url(), icon=True)
I see the login button appear in my app but when I click on it a get a invalid_request error in the browser saying that the redirect_uri parameter in the request did not match any of the Login redirect URIs configured in the client application settings. If I print the output of get_login_url I get /_solara/auth/login?redirect_uri=http%3A//localhost%3A8080 which is missing the main base url (what sets that value?)? Am I missing something in the configuration? I am setting these in my .env
SOLARA_SESSION_SECRET_KEY=<<mysecretkey>>
SOLARA_OAUTH_CLIENT_ID=<<myclientid>>
SOLARA_OAUTH_CLIENT_SECRET=<<myclientsecret>>
SOLARA_OAUTH_API_BASE_URL=https://<<myissuer>>
SOLARA_SESSION_HTTPS_ONLY=False
SOLARA_BASE_URL=http://localhost:8080
SOLARA_SESSION_SECRET_KEY=<<mysecretkey>>
SOLARA_OAUTH_CLIENT_ID=<<myclientid>>
SOLARA_OAUTH_CLIENT_SECRET=<<myclientsecret>>
SOLARA_OAUTH_API_BASE_URL=https://<<myissuer>>
SOLARA_SESSION_HTTPS_ONLY=False
SOLARA_BASE_URL=http://localhost:8080
and in okta I have set application login url as: http://localhost:8080/_solara/auth/login and allowed callback urls as: authorize: http://localhost:8080/_solara/auth/authorize logout: http://localhost:8080/_solara/auth/logout is this correct?
13 replies
SSolara
Created by Cyrus on 4/23/2024 in #questions-issues
ipyaggrid memory leak
Hi, I have an app that uses a few sizeable ipyaggrid grids (one per tab) that are leading to memory leaks (when I replace them with solara.Dataframe's for example, then there is no leak). I am using a AgGrid component with a cleanup function, along the lines below, and it seems to be improving things but wanted to know if there is a better approach, on either python and JS side (using js_post_grid) ?
import ipyaggrid
import plotly.express as px
import solara

df = solara.reactive(px.data.iris())
species = solara.reactive('setosa')

@solara.component
def AgGrid(grid_data, grid_options, **kwargs):

def update_data():
widget = solara.get_widget(el)
widget.grid_options = grid_options
widget.update_grid_data(grid_data)

def cleanup():
widget.children = () # does this help?
widget.layout.close() # does this help?
widget.update_grid_data([]) # leads to flickering when cross-filtering grid data
# widget.close() # leads to widget permanently disappearing after cross-filtering grid data once
# gc.collect() # would forcing garbage collection help?

return cleanup

el = ipyaggrid.Grid.element(
grid_data=grid_data,
grid_options=grid_options,
**kwargs,
)

solara.use_effect(update_data, [grid_data, grid_options])

@solara.component
def Page():

grid_options = {
'columnDefs': [
{'headerName': 'Species', 'field': 'species', 'enableRowGroup': True},
{'headerName': 'Sepal Length', 'field': 'sepal_length'},
]
}

df_filtered = df.value.query(f'species == {species.value!r}')
solara.Select('Species', value=species, values=['setosa', 'versicolor', 'virginica'])

AgGrid(grid_data=df_filtered, grid_options=grid_options)

Page()
import ipyaggrid
import plotly.express as px
import solara

df = solara.reactive(px.data.iris())
species = solara.reactive('setosa')

@solara.component
def AgGrid(grid_data, grid_options, **kwargs):

def update_data():
widget = solara.get_widget(el)
widget.grid_options = grid_options
widget.update_grid_data(grid_data)

def cleanup():
widget.children = () # does this help?
widget.layout.close() # does this help?
widget.update_grid_data([]) # leads to flickering when cross-filtering grid data
# widget.close() # leads to widget permanently disappearing after cross-filtering grid data once
# gc.collect() # would forcing garbage collection help?

return cleanup

el = ipyaggrid.Grid.element(
grid_data=grid_data,
grid_options=grid_options,
**kwargs,
)

solara.use_effect(update_data, [grid_data, grid_options])

@solara.component
def Page():

grid_options = {
'columnDefs': [
{'headerName': 'Species', 'field': 'species', 'enableRowGroup': True},
{'headerName': 'Sepal Length', 'field': 'sepal_length'},
]
}

df_filtered = df.value.query(f'species == {species.value!r}')
solara.Select('Species', value=species, values=['setosa', 'versicolor', 'virginica'])

AgGrid(grid_data=df_filtered, grid_options=grid_options)

Page()
8 replies
SSolara
Created by Cyrus on 4/12/2024 in #questions-issues
Setting height of `ipyaggrid` in Solara app gives error
Hi, how can I set the height of a ipyaggrid that is being cross-filtered by a solara component? I am using @MaartenBreddels 's snippet here https://discord.com/channels/1106593685241614489/1106593686223069309/1212429587867504730. However, if I pass an integer height to the grid element like this ipyaggrid.Grid.element(..., height=500) it renders fine but then leads to this error: trait of a Grid instance expected a unicode string, not the int 500, whenever the data is filtered. Could it be a bug in ipyaggrid where the widget expects height to be an int but the trait is defined as unicode, leading to data type issues? I found a workaround but wonder if I am missing something or if there is a better approach. Thanks!
from typing import cast
import ipyaggrid
import plotly.express as px
import solara

df = solara.reactive(px.data.iris())
species = solara.reactive('setosa')

@solara.component
def AgGrid(df, grid_options):

height = solara.use_reactive(500) # set as int

def update_df():
widget = cast(ipyaggrid.Grid, solara.get_widget(el))
widget.grid_options = grid_options
widget.update_grid_data(df)
print(widget.height)

# workaround where we recast height
if isinstance(widget.height, int):
height.set(f'{widget.height}px')
else:
height.set(widget.height)

el = ipyaggrid.Grid.element(grid_data=df, grid_options=grid_options, height=height.value)
solara.use_effect(update_df, [df, grid_options])

return el

@solara.component
def Page():
grid_options = {
'columnDefs': [
{'headerName': 'Sepal Length', 'field': 'sepal_length'},
{'headerName': 'Species', 'field': 'species'},
]
}
df_filtered = df.value.query(f'species == {species.value!r}')
solara.Select('Species', value=species, values=['setosa', 'versicolor', 'virginica'])
AgGrid(df=df_filtered, grid_options=grid_options)
from typing import cast
import ipyaggrid
import plotly.express as px
import solara

df = solara.reactive(px.data.iris())
species = solara.reactive('setosa')

@solara.component
def AgGrid(df, grid_options):

height = solara.use_reactive(500) # set as int

def update_df():
widget = cast(ipyaggrid.Grid, solara.get_widget(el))
widget.grid_options = grid_options
widget.update_grid_data(df)
print(widget.height)

# workaround where we recast height
if isinstance(widget.height, int):
height.set(f'{widget.height}px')
else:
height.set(widget.height)

el = ipyaggrid.Grid.element(grid_data=df, grid_options=grid_options, height=height.value)
solara.use_effect(update_df, [df, grid_options])

return el

@solara.component
def Page():
grid_options = {
'columnDefs': [
{'headerName': 'Sepal Length', 'field': 'sepal_length'},
{'headerName': 'Species', 'field': 'species'},
]
}
df_filtered = df.value.query(f'species == {species.value!r}')
solara.Select('Species', value=species, values=['setosa', 'versicolor', 'virginica'])
AgGrid(df=df_filtered, grid_options=grid_options)
8 replies
SSolara
Created by Cyrus on 2/26/2024 in #questions-issues
cross-filtering ipyaggrid element in Solara
Hi, is there a way to cross filter a ipyaggrid element in solara based on other Solara components (Sliders, Select, etc)? I tried creating a custom solara.CrossFilterGrid similar to solara.CrossFilterDataFrame. I could not get it to work but maybe I am missing something. Here is my reproducible example
import ipyaggrid
import plotly.express as px
import solara

df = px.data.iris()
column_defs = [
{'headerName': 'Sepal Length', 'field': 'sepal_length'},
{'headerName': 'Species', 'field': 'species'},
]
grid_options = {'columnDefs': column_defs}


@solara.component
def CrossFilterGrid(df, grid_options):
dff = df
filter, set_filter = solara.use_cross_filter(id(df), 'grid')
if filter is not None:
dff = df[filter]
return ipyaggrid.Grid.element(grid_data=dff, grid_options=grid_options)


@solara.component
def Page():
solara.provide_cross_filter()
with solara.Columns([1,1]):
solara.CrossFilterDataFrame(df) # <--- This works
CrossFilterGrid(df, grid_options) # <--- This does not work
with solara.Column():
solara.CrossFilterSelect(df, 'species')
solara.CrossFilterSlider(df, 'sepal_length', mode='>')
import ipyaggrid
import plotly.express as px
import solara

df = px.data.iris()
column_defs = [
{'headerName': 'Sepal Length', 'field': 'sepal_length'},
{'headerName': 'Species', 'field': 'species'},
]
grid_options = {'columnDefs': column_defs}


@solara.component
def CrossFilterGrid(df, grid_options):
dff = df
filter, set_filter = solara.use_cross_filter(id(df), 'grid')
if filter is not None:
dff = df[filter]
return ipyaggrid.Grid.element(grid_data=dff, grid_options=grid_options)


@solara.component
def Page():
solara.provide_cross_filter()
with solara.Columns([1,1]):
solara.CrossFilterDataFrame(df) # <--- This works
CrossFilterGrid(df, grid_options) # <--- This does not work
with solara.Column():
solara.CrossFilterSelect(df, 'species')
solara.CrossFilterSlider(df, 'sepal_length', mode='>')
I am actually also interested in doing the reverse: have Solara charts react to when I filter my ipyaggrid by clicking on the grid directly (for example, when clicking on checkboxes for each row). This might be harder to do? Thanks!
2 replies