Merge branch 'main' into masenf/unrestrict-show-built-with-reflex
This commit is contained in:
commit
93a01373c0
@ -111,7 +111,7 @@ from reflex.utils import (
|
|||||||
prerequisites,
|
prerequisites,
|
||||||
types,
|
types,
|
||||||
)
|
)
|
||||||
from reflex.utils.exec import is_prod_mode, is_testing_env
|
from reflex.utils.exec import get_compile_context, is_prod_mode, is_testing_env
|
||||||
from reflex.utils.imports import ImportVar
|
from reflex.utils.imports import ImportVar
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
@ -201,14 +201,17 @@ def default_overlay_component() -> Component:
|
|||||||
Returns:
|
Returns:
|
||||||
The default overlay_component, which is a connection_modal.
|
The default overlay_component, which is a connection_modal.
|
||||||
"""
|
"""
|
||||||
config = get_config()
|
|
||||||
from reflex.components.component import memo
|
from reflex.components.component import memo
|
||||||
|
|
||||||
def default_overlay_components():
|
def default_overlay_components():
|
||||||
return Fragment.create(
|
return Fragment.create(
|
||||||
connection_pulser(),
|
connection_pulser(),
|
||||||
connection_toaster(),
|
connection_toaster(),
|
||||||
*([backend_disabled()] if config.is_reflex_cloud else []),
|
*(
|
||||||
|
[backend_disabled()]
|
||||||
|
if get_compile_context() == constants.CompileContext.DEPLOY
|
||||||
|
else []
|
||||||
|
),
|
||||||
*codespaces.codespaces_auto_redirect(),
|
*codespaces.codespaces_auto_redirect(),
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1136,6 +1139,16 @@ class App(MiddlewareMixin, LifespanMixin):
|
|||||||
|
|
||||||
self._validate_var_dependencies()
|
self._validate_var_dependencies()
|
||||||
self._setup_overlay_component()
|
self._setup_overlay_component()
|
||||||
|
|
||||||
|
if config.show_built_with_reflex is None:
|
||||||
|
if (
|
||||||
|
get_compile_context() == constants.CompileContext.DEPLOY
|
||||||
|
and prerequisites.get_user_tier() in ["pro", "team", "enterprise"]
|
||||||
|
):
|
||||||
|
config.show_built_with_reflex = False
|
||||||
|
else:
|
||||||
|
config.show_built_with_reflex = True
|
||||||
|
|
||||||
if is_prod_mode() and config.show_built_with_reflex:
|
if is_prod_mode() and config.show_built_with_reflex:
|
||||||
self._setup_sticky_badge()
|
self._setup_sticky_badge()
|
||||||
|
|
||||||
|
@ -589,6 +589,11 @@ class ExecutorType(enum.Enum):
|
|||||||
class EnvironmentVariables:
|
class EnvironmentVariables:
|
||||||
"""Environment variables class to instantiate environment variables."""
|
"""Environment variables class to instantiate environment variables."""
|
||||||
|
|
||||||
|
# Indicate the current command that was invoked in the reflex CLI.
|
||||||
|
REFLEX_COMPILE_CONTEXT: EnvVar[constants.CompileContext] = env_var(
|
||||||
|
constants.CompileContext.UNDEFINED, internal=True
|
||||||
|
)
|
||||||
|
|
||||||
# Whether to use npm over bun to install frontend packages.
|
# Whether to use npm over bun to install frontend packages.
|
||||||
REFLEX_USE_NPM: EnvVar[bool] = env_var(False)
|
REFLEX_USE_NPM: EnvVar[bool] = env_var(False)
|
||||||
|
|
||||||
@ -636,7 +641,7 @@ class EnvironmentVariables:
|
|||||||
REFLEX_COMPILE_THREADS: EnvVar[Optional[int]] = env_var(None)
|
REFLEX_COMPILE_THREADS: EnvVar[Optional[int]] = env_var(None)
|
||||||
|
|
||||||
# The directory to store reflex dependencies.
|
# The directory to store reflex dependencies.
|
||||||
REFLEX_DIR: EnvVar[Path] = env_var(Path(constants.Reflex.DIR))
|
REFLEX_DIR: EnvVar[Path] = env_var(constants.Reflex.DIR)
|
||||||
|
|
||||||
# Whether to print the SQL queries if the log level is INFO or lower.
|
# Whether to print the SQL queries if the log level is INFO or lower.
|
||||||
SQLALCHEMY_ECHO: EnvVar[bool] = env_var(False)
|
SQLALCHEMY_ECHO: EnvVar[bool] = env_var(False)
|
||||||
@ -844,7 +849,7 @@ class Config(Base):
|
|||||||
env_file: Optional[str] = None
|
env_file: Optional[str] = None
|
||||||
|
|
||||||
# Whether to display the sticky "Built with Reflex" badge on all pages.
|
# Whether to display the sticky "Built with Reflex" badge on all pages.
|
||||||
show_built_with_reflex: bool = True
|
show_built_with_reflex: Optional[bool] = None
|
||||||
|
|
||||||
# Whether the app is running in the reflex cloud environment.
|
# Whether the app is running in the reflex cloud environment.
|
||||||
is_reflex_cloud: bool = False
|
is_reflex_cloud: bool = False
|
||||||
|
@ -25,6 +25,7 @@ from .base import (
|
|||||||
from .compiler import (
|
from .compiler import (
|
||||||
NOCOMPILE_FILE,
|
NOCOMPILE_FILE,
|
||||||
SETTER_PREFIX,
|
SETTER_PREFIX,
|
||||||
|
CompileContext,
|
||||||
CompileVars,
|
CompileVars,
|
||||||
ComponentName,
|
ComponentName,
|
||||||
Ext,
|
Ext,
|
||||||
@ -65,6 +66,7 @@ __ALL__ = [
|
|||||||
ColorMode,
|
ColorMode,
|
||||||
Config,
|
Config,
|
||||||
COOKIES,
|
COOKIES,
|
||||||
|
CompileContext,
|
||||||
ComponentName,
|
ComponentName,
|
||||||
CustomComponents,
|
CustomComponents,
|
||||||
DefaultPage,
|
DefaultPage,
|
||||||
|
@ -111,6 +111,15 @@ class ComponentName(Enum):
|
|||||||
return self.value.lower() + Ext.ZIP
|
return self.value.lower() + Ext.ZIP
|
||||||
|
|
||||||
|
|
||||||
|
class CompileContext(str, Enum):
|
||||||
|
"""The context in which the compiler is running."""
|
||||||
|
|
||||||
|
RUN = "run"
|
||||||
|
EXPORT = "export"
|
||||||
|
DEPLOY = "deploy"
|
||||||
|
UNDEFINED = "undefined"
|
||||||
|
|
||||||
|
|
||||||
class Imports(SimpleNamespace):
|
class Imports(SimpleNamespace):
|
||||||
"""Common sets of import vars."""
|
"""Common sets of import vars."""
|
||||||
|
|
||||||
|
@ -292,6 +292,8 @@ def run(
|
|||||||
if frontend and backend:
|
if frontend and backend:
|
||||||
console.error("Cannot use both --frontend-only and --backend-only options.")
|
console.error("Cannot use both --frontend-only and --backend-only options.")
|
||||||
raise typer.Exit(1)
|
raise typer.Exit(1)
|
||||||
|
|
||||||
|
environment.REFLEX_COMPILE_CONTEXT.set(constants.CompileContext.RUN)
|
||||||
environment.REFLEX_BACKEND_ONLY.set(backend)
|
environment.REFLEX_BACKEND_ONLY.set(backend)
|
||||||
environment.REFLEX_FRONTEND_ONLY.set(frontend)
|
environment.REFLEX_FRONTEND_ONLY.set(frontend)
|
||||||
|
|
||||||
@ -338,6 +340,8 @@ def export(
|
|||||||
from reflex.utils import export as export_utils
|
from reflex.utils import export as export_utils
|
||||||
from reflex.utils import prerequisites
|
from reflex.utils import prerequisites
|
||||||
|
|
||||||
|
environment.REFLEX_COMPILE_CONTEXT.set(constants.CompileContext.EXPORT)
|
||||||
|
|
||||||
frontend, backend = prerequisites.check_running_mode(frontend, backend)
|
frontend, backend = prerequisites.check_running_mode(frontend, backend)
|
||||||
|
|
||||||
if prerequisites.needs_reinit(frontend=frontend or not backend):
|
if prerequisites.needs_reinit(frontend=frontend or not backend):
|
||||||
@ -537,6 +541,8 @@ def deploy(
|
|||||||
|
|
||||||
check_version()
|
check_version()
|
||||||
|
|
||||||
|
environment.REFLEX_COMPILE_CONTEXT.set(constants.CompileContext.DEPLOY)
|
||||||
|
|
||||||
# Set the log level.
|
# Set the log level.
|
||||||
console.set_log_level(loglevel)
|
console.set_log_level(loglevel)
|
||||||
|
|
||||||
|
@ -584,3 +584,12 @@ def is_prod_mode() -> bool:
|
|||||||
"""
|
"""
|
||||||
current_mode = environment.REFLEX_ENV_MODE.get()
|
current_mode = environment.REFLEX_ENV_MODE.get()
|
||||||
return current_mode == constants.Env.PROD
|
return current_mode == constants.Env.PROD
|
||||||
|
|
||||||
|
|
||||||
|
def get_compile_context() -> constants.CompileContext:
|
||||||
|
"""Check if the app is compiled for deploy.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Whether the app is being compiled for deploy.
|
||||||
|
"""
|
||||||
|
return environment.REFLEX_COMPILE_CONTEXT.get()
|
||||||
|
@ -2001,6 +2001,22 @@ def is_generation_hash(template: str) -> bool:
|
|||||||
return re.match(r"^[0-9a-f]{32,}$", template) is not None
|
return re.match(r"^[0-9a-f]{32,}$", template) is not None
|
||||||
|
|
||||||
|
|
||||||
|
def get_user_tier():
|
||||||
|
"""Get the current user's tier.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The current user's tier.
|
||||||
|
"""
|
||||||
|
from reflex_cli.v2.utils import hosting
|
||||||
|
|
||||||
|
authenticated_token = hosting.authenticated_token()
|
||||||
|
return (
|
||||||
|
authenticated_token[1].get("tier", "").lower()
|
||||||
|
if authenticated_token[0]
|
||||||
|
else "anonymous"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def check_config_option_in_tier(
|
def check_config_option_in_tier(
|
||||||
option_name: str,
|
option_name: str,
|
||||||
allowed_tiers: list[str],
|
allowed_tiers: list[str],
|
||||||
@ -2015,23 +2031,21 @@ def check_config_option_in_tier(
|
|||||||
fallback_value: The fallback value if the option is not allowed.
|
fallback_value: The fallback value if the option is not allowed.
|
||||||
help_link: The help link to show to a user that is authenticated.
|
help_link: The help link to show to a user that is authenticated.
|
||||||
"""
|
"""
|
||||||
from reflex_cli.v2.utils import hosting
|
|
||||||
|
|
||||||
config = get_config()
|
config = get_config()
|
||||||
authenticated_token = hosting.authenticated_token()
|
current_tier = get_user_tier()
|
||||||
if not authenticated_token[0]:
|
|
||||||
|
if current_tier == "anonymous":
|
||||||
the_remedy = (
|
the_remedy = (
|
||||||
"You are currently logged out. Run `reflex login` to access this option."
|
"You are currently logged out. Run `reflex login` to access this option."
|
||||||
)
|
)
|
||||||
current_tier = "anonymous"
|
|
||||||
else:
|
else:
|
||||||
current_tier = authenticated_token[1].get("tier", "").lower()
|
|
||||||
the_remedy = (
|
the_remedy = (
|
||||||
f"Your current subscription tier is `{current_tier}`. "
|
f"Your current subscription tier is `{current_tier}`. "
|
||||||
f"Please upgrade to {allowed_tiers} to access this option. "
|
f"Please upgrade to {allowed_tiers} to access this option. "
|
||||||
)
|
)
|
||||||
if help_link:
|
if help_link:
|
||||||
the_remedy += f"See {help_link} for more information."
|
the_remedy += f"See {help_link} for more information."
|
||||||
|
|
||||||
if current_tier not in allowed_tiers:
|
if current_tier not in allowed_tiers:
|
||||||
console.warn(f"Config option `{option_name}` is restricted. {the_remedy}")
|
console.warn(f"Config option `{option_name}` is restricted. {the_remedy}")
|
||||||
setattr(config, option_name, fallback_value)
|
setattr(config, option_name, fallback_value)
|
||||||
|
@ -7,24 +7,19 @@ import pytest
|
|||||||
from selenium.common.exceptions import NoSuchElementException
|
from selenium.common.exceptions import NoSuchElementException
|
||||||
from selenium.webdriver.common.by import By
|
from selenium.webdriver.common.by import By
|
||||||
|
|
||||||
|
from reflex import constants
|
||||||
|
from reflex.config import environment
|
||||||
from reflex.testing import AppHarness, WebDriver
|
from reflex.testing import AppHarness, WebDriver
|
||||||
|
|
||||||
from .utils import SessionStorage
|
from .utils import SessionStorage
|
||||||
|
|
||||||
|
|
||||||
def ConnectionBanner(is_reflex_cloud: bool = False):
|
def ConnectionBanner():
|
||||||
"""App with a connection banner.
|
"""App with a connection banner."""
|
||||||
|
|
||||||
Args:
|
|
||||||
is_reflex_cloud: The value for config.is_reflex_cloud.
|
|
||||||
"""
|
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
import reflex as rx
|
import reflex as rx
|
||||||
|
|
||||||
# Simulate reflex cloud deploy
|
|
||||||
rx.config.get_config().is_reflex_cloud = is_reflex_cloud
|
|
||||||
|
|
||||||
class State(rx.State):
|
class State(rx.State):
|
||||||
foo: int = 0
|
foo: int = 0
|
||||||
|
|
||||||
@ -49,16 +44,17 @@ def ConnectionBanner(is_reflex_cloud: bool = False):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture(
|
@pytest.fixture(
|
||||||
params=[False, True], ids=["reflex_cloud_disabled", "reflex_cloud_enabled"]
|
params=[constants.CompileContext.RUN, constants.CompileContext.DEPLOY],
|
||||||
|
ids=["compile_context_run", "compile_context_deploy"],
|
||||||
)
|
)
|
||||||
def simulate_is_reflex_cloud(request) -> bool:
|
def simulate_compile_context(request) -> constants.CompileContext:
|
||||||
"""Fixture to simulate reflex cloud deployment.
|
"""Fixture to simulate reflex cloud deployment.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
request: pytest request fixture.
|
request: pytest request fixture.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
True if reflex cloud is enabled, False otherwise.
|
The context to run the app with.
|
||||||
"""
|
"""
|
||||||
return request.param
|
return request.param
|
||||||
|
|
||||||
@ -66,25 +62,27 @@ def simulate_is_reflex_cloud(request) -> bool:
|
|||||||
@pytest.fixture()
|
@pytest.fixture()
|
||||||
def connection_banner(
|
def connection_banner(
|
||||||
tmp_path,
|
tmp_path,
|
||||||
simulate_is_reflex_cloud: bool,
|
simulate_compile_context: constants.CompileContext,
|
||||||
) -> Generator[AppHarness, None, None]:
|
) -> Generator[AppHarness, None, None]:
|
||||||
"""Start ConnectionBanner app at tmp_path via AppHarness.
|
"""Start ConnectionBanner app at tmp_path via AppHarness.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
tmp_path: pytest tmp_path fixture
|
tmp_path: pytest tmp_path fixture
|
||||||
simulate_is_reflex_cloud: Whether is_reflex_cloud is set for the app.
|
simulate_compile_context: Which context to run the app with.
|
||||||
|
|
||||||
Yields:
|
Yields:
|
||||||
running AppHarness instance
|
running AppHarness instance
|
||||||
"""
|
"""
|
||||||
|
environment.REFLEX_COMPILE_CONTEXT.set(simulate_compile_context)
|
||||||
|
|
||||||
with AppHarness.create(
|
with AppHarness.create(
|
||||||
root=tmp_path,
|
root=tmp_path,
|
||||||
app_source=functools.partial(
|
app_source=functools.partial(ConnectionBanner),
|
||||||
ConnectionBanner, is_reflex_cloud=simulate_is_reflex_cloud
|
app_name=(
|
||||||
|
"connection_banner_reflex_cloud"
|
||||||
|
if simulate_compile_context == constants.CompileContext.DEPLOY
|
||||||
|
else "connection_banner"
|
||||||
),
|
),
|
||||||
app_name="connection_banner_reflex_cloud"
|
|
||||||
if simulate_is_reflex_cloud
|
|
||||||
else "connection_banner",
|
|
||||||
) as harness:
|
) as harness:
|
||||||
yield harness
|
yield harness
|
||||||
|
|
||||||
@ -194,13 +192,13 @@ async def test_connection_banner(connection_banner: AppHarness):
|
|||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_cloud_banner(
|
async def test_cloud_banner(
|
||||||
connection_banner: AppHarness, simulate_is_reflex_cloud: bool
|
connection_banner: AppHarness, simulate_compile_context: constants.CompileContext
|
||||||
):
|
):
|
||||||
"""Test that the connection banner is displayed when the websocket drops.
|
"""Test that the connection banner is displayed when the websocket drops.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
connection_banner: AppHarness instance.
|
connection_banner: AppHarness instance.
|
||||||
simulate_is_reflex_cloud: Whether is_reflex_cloud is set for the app.
|
simulate_compile_context: Which context to set for the app.
|
||||||
"""
|
"""
|
||||||
assert connection_banner.app_instance is not None
|
assert connection_banner.app_instance is not None
|
||||||
assert connection_banner.backend is not None
|
assert connection_banner.backend is not None
|
||||||
@ -213,7 +211,7 @@ async def test_cloud_banner(
|
|||||||
|
|
||||||
driver.add_cookie({"name": "backend-enabled", "value": "false"})
|
driver.add_cookie({"name": "backend-enabled", "value": "false"})
|
||||||
driver.refresh()
|
driver.refresh()
|
||||||
if simulate_is_reflex_cloud:
|
if simulate_compile_context == constants.CompileContext.DEPLOY:
|
||||||
assert connection_banner._poll_for(lambda: has_cloud_banner(driver))
|
assert connection_banner._poll_for(lambda: has_cloud_banner(driver))
|
||||||
else:
|
else:
|
||||||
_assert_token(connection_banner, driver)
|
_assert_token(connection_banner, driver)
|
||||||
|
Loading…
Reference in New Issue
Block a user