diff --git a/.github/workflows/check_outdated_dependencies.yml b/.github/workflows/check_outdated_dependencies.yml index 74524e56d43..80e90f617fe 100644 --- a/.github/workflows/check_outdated_dependencies.yml +++ b/.github/workflows/check_outdated_dependencies.yml @@ -42,6 +42,10 @@ jobs: frontend: runs-on: ubuntu-latest + env: + # reflex-enterprise restricts `reflex run --env prod` to paid tiers but + # exempts reflex's own integration tests via the app harness flag. + APP_HARNESS_FLAG: "true" steps: - name: Checkout code diff --git a/.github/workflows/integration_tests.yml b/.github/workflows/integration_tests.yml index a3a086de83b..1f218240cb5 100644 --- a/.github/workflows/integration_tests.yml +++ b/.github/workflows/integration_tests.yml @@ -112,6 +112,9 @@ jobs: env: REFLEX_WEB_WINDOWS_OVERRIDE: "1" + # reflex-enterprise restricts `reflex run --env prod` to paid tiers but + # exempts reflex's own integration tests via the app harness flag. + APP_HARNESS_FLAG: "true" runs-on: ubuntu-latest steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 @@ -220,6 +223,10 @@ jobs: matrix: # Note: py311 version chosen due to available arm64 darwin builds. python-version: ["3.11", "3.12"] + env: + # reflex-enterprise restricts `reflex run --env prod` to paid tiers but + # exempts reflex's own integration tests via the app harness flag. + APP_HARNESS_FLAG: "true" runs-on: macos-latest steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ec81045b765..552fd7f0945 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -96,6 +96,13 @@ following command to generate the `CHANGELOG.md` file in each subpackage. uv run towncrier build --config pyproject.toml --version v0.9.4 ``` +**Where changelogs are published:** the docs site renders every `CHANGELOG.md` +in the repo (repo root and `packages/*/`) under +[reflex.dev/docs/changelog/](https://reflex.dev/docs/changelog/). The +`reflex-enterprise` changelog is read from the installed `reflex-enterprise` +distribution at docs build time; it appears once the published wheel ships a +`CHANGELOG.md` and the docs app's lockfile picks up that version. + ## ✅ Making a PR Once you solve a current issue or improvement to Reflex, you can make a PR, and we will review the changes. diff --git a/docs/app/agent_files/_plugin.py b/docs/app/agent_files/_plugin.py index c3e3aaba506..57d118f3bce 100644 --- a/docs/app/agent_files/_plugin.py +++ b/docs/app/agent_files/_plugin.py @@ -205,7 +205,7 @@ def _section_for_path(url_path: Path) -> str: return "Skills" if path.startswith("ai/"): return "AI Builder" - return _format_title(path.split("/", maxsplit=1)[0]) + return _format_title(path.split("/", maxsplit=1)[0].removesuffix(".md")) def _ordered_sections( diff --git a/docs/app/pyproject.toml b/docs/app/pyproject.toml index 0214e7fdea3..1a36dec57b5 100644 --- a/docs/app/pyproject.toml +++ b/docs/app/pyproject.toml @@ -14,7 +14,7 @@ dependencies = [ "python-frontmatter", "reflex", "reflex-docgen", - "reflex-enterprise", + "reflex-enterprise>=0.9.0.post1", "reflex-hosting-cli", "reflex-pyplot", "reflex-integrations-docs", diff --git a/docs/app/reflex_docs/changelogs.py b/docs/app/reflex_docs/changelogs.py new file mode 100644 index 00000000000..a06339ab2e0 --- /dev/null +++ b/docs/app/reflex_docs/changelogs.py @@ -0,0 +1,111 @@ +"""Discovery of package changelogs surfaced on the docs site. + +The monorepo packages manage their changelogs with towncrier: the main +``reflex`` changelog lives at the repo root and each subpackage ships its own +under ``packages//CHANGELOG.md``. The ``reflex-enterprise`` package is +developed in a separate repo, so its changelog is read from the installed +distribution instead (it only appears once the published wheel ships a +``CHANGELOG.md``). +""" + +from importlib.metadata import PackageNotFoundError, distribution +from pathlib import Path + +ENTERPRISE_PACKAGE = "reflex-enterprise" + + +def discover_repo_changelogs(repo_root: Path) -> dict[str, Path]: + """Find the changelogs maintained in this repo. + + Args: + repo_root: The repo checkout root (parent of the docs content tree). + + Returns: + A mapping of package name to its CHANGELOG.md path — ``reflex`` for + the repo-root changelog plus one entry per subpackage that ships one. + """ + changelogs: dict[str, Path] = {} + root_changelog = repo_root / "CHANGELOG.md" + if root_changelog.is_file(): + changelogs["reflex"] = root_changelog + for pkg_changelog in (repo_root / "packages").glob("*/CHANGELOG.md"): + changelogs[pkg_changelog.parent.name] = pkg_changelog + return changelogs + + +def find_distribution_changelog(package: str) -> Path | None: + """Locate the CHANGELOG.md shipped with an installed distribution. + + Args: + package: The distribution name (e.g. ``reflex-enterprise``). + + Returns: + The path to the installed CHANGELOG.md, or None when the distribution + is not installed or does not ship one. + """ + try: + dist = distribution(package) + except PackageNotFoundError: + return None + candidates = [file for file in dist.files or () if file.name == "CHANGELOG.md"] + # Prefer the shallowest record — a wheel may also vendor third-party + # changelogs deeper in its tree. + for file in sorted(candidates, key=lambda file: len(file.parts)): + path = Path(str(dist.locate_file(file))) + if path.is_file(): + return path + return None + + +def discover_changelogs(repo_root: Path) -> dict[str, Path]: + """Find all package changelogs to publish on the docs site. + + Args: + repo_root: The repo checkout root. + + Returns: + A mapping of package name to CHANGELOG.md path, with ``reflex`` first + and the remaining packages in alphabetical order. + """ + changelogs = discover_repo_changelogs(repo_root) + enterprise_changelog = find_distribution_changelog(ENTERPRISE_PACKAGE) + if enterprise_changelog is not None: + changelogs[ENTERPRISE_PACKAGE] = enterprise_changelog + return { + name: changelogs[name] + for name in sorted(changelogs, key=lambda name: (name != "reflex", name)) + } + + +def changelog_page_title(package: str) -> str: + """Return the display title for a package changelog page. + + Args: + package: The package name. + + Returns: + The page title. + """ + return "Reflex Changelog" if package == "reflex" else f"{package} Changelog" + + +def normalize_changelog(source: str, title: str) -> str: + """Give changelog markdown a canonical top-level heading. + + Towncrier-generated changelogs have no top-level heading, while + Keep-a-Changelog files (e.g. reflex-enterprise) start with a generic + ``# Changelog``. Replace any existing H1 with *title* so every changelog + page renders consistently. + + Args: + source: The raw changelog markdown. + title: The canonical page title. + + Returns: + The normalized markdown. + """ + lines = source.lstrip().splitlines() + if lines and lines[0].startswith("# "): + del lines[0] + body = "\n".join(lines).strip("\n") + return f"# {title}\n\n{body}\n" diff --git a/docs/app/reflex_docs/docgen_pipeline.py b/docs/app/reflex_docs/docgen_pipeline.py index 100a1d8b731..7a737329535 100644 --- a/docs/app/reflex_docs/docgen_pipeline.py +++ b/docs/app/reflex_docs/docgen_pipeline.py @@ -869,6 +869,21 @@ def render_markdown(text: str) -> rx.Component: return transformer.transform(doc) +def render_markdown_with_toc(text: str) -> tuple[list[tuple[int, str]], rx.Component]: + """Render a plain markdown text string, also extracting its TOC headings. + + Args: + text: The markdown source. + + Returns: + A ``(toc, body)`` tuple where ``toc`` is a list of ``(level, text)`` + heading tuples and ``body`` is the rendered component. + """ + doc = parse_document(text) + toc = [(h.level, _spans_to_plaintext(h.children)) for h in doc.headings] + return toc, ReflexDocTransformer().transform(doc) + + def render_inline_markdown(text: str, class_name: str = "") -> rx.Component: """Render a short markdown string inline (links, code spans, emphasis). diff --git a/docs/app/reflex_docs/pages/docs/__init__.py b/docs/app/reflex_docs/pages/docs/__init__.py index 971ca615b7a..957f9b25e8a 100644 --- a/docs/app/reflex_docs/pages/docs/__init__.py +++ b/docs/app/reflex_docs/pages/docs/__init__.py @@ -11,7 +11,16 @@ from reflex_pyplot import pyplot as pyplot from reflex_site_shared.route import Route -from reflex_docs.docgen_pipeline import get_docgen_toc, render_docgen_document +from reflex_docs.changelogs import ( + changelog_page_title, + discover_changelogs, + normalize_changelog, +) +from reflex_docs.docgen_pipeline import ( + get_docgen_toc, + render_docgen_document, + render_markdown_with_toc, +) from reflex_docs.pages.docs.component import multi_docs from reflex_docs.pages.library_previews import components_previews_pages from reflex_docs.templates.docpage import docpage @@ -203,6 +212,26 @@ def make_docpage(route: str, title: str, doc_virtual: str, render_fn): return docpage(set_path=route, t=title)(render_fn) +CHANGELOG_VIRTUAL_PREFIX = "docs/changelog/" + + +def handle_changelog_doc(doc: str, actual_path: str, resolved: ResolvedDoc): + """Handle docs/changelog/** docs — package changelogs pulled from outside the docs tree. + + Changelog markdown ships without a meaningful top-level heading, so the + canonical page title is normalized in and the table of contents is limited + to version headings. + """ + + def comp(_actual=actual_path, _title=resolved.display_title): + source = normalize_changelog(Path(_actual).read_text(encoding="utf-8"), _title) + toc, body = render_markdown_with_toc(source) + toc = [(level, text) for level, text in toc if level <= 2] + return ((toc, source), body) + + return make_docpage(resolved.route, resolved.display_title, doc, comp) + + def handle_library_doc( doc: str, actual_path: str, @@ -240,6 +269,9 @@ def get_component_docgen(virtual_doc: str, actual_path: str, title: str): if virtual_doc.startswith("docs/library"): return handle_library_doc(virtual_doc, actual_path, title, resolved) + if virtual_doc.startswith(CHANGELOG_VIRTUAL_PREFIX): + return handle_changelog_doc(virtual_doc, actual_path, resolved) + def comp(_actual=actual_path, _virtual=virtual_doc): toc = get_docgen_toc(_actual) doc_content = Path(_actual).read_text(encoding="utf-8") @@ -253,6 +285,22 @@ def comp(_actual=actual_path, _virtual=virtual_doc): return make_docpage(resolved.route, resolved.display_title, virtual_doc, comp) +# Package changelogs live outside the docs tree — the towncrier-managed ones +# at the repo root (CHANGELOG.md and packages/*/CHANGELOG.md) and the +# reflex-enterprise one inside the installed distribution. Reach up and pull +# them in as regular docs under docs/changelog/, with the main reflex +# changelog served at the section index. +changelog_packages: dict[str, str] = {} # package name → route +for _package, _changelog_path in discover_changelogs(_docs_dir.parent).items(): + _virtual = ( + f"{CHANGELOG_VIRTUAL_PREFIX}index.md" + if _package == "reflex" + else f"{CHANGELOG_VIRTUAL_PREFIX}{_package}.md" + ) + all_docs[_virtual] = str(_changelog_path) + manual_titles[_virtual] = changelog_page_title(_package) + changelog_packages[_package] = doc_route_from_path(_virtual) + # Build doc_markdown_sources mapping for _virtual, _actual in all_docs.items(): if _virtual.endswith("-style.md"): diff --git a/docs/app/reflex_docs/templates/docpage/docpage.py b/docs/app/reflex_docs/templates/docpage/docpage.py index 9a76ecef990..f6a2d6b9f07 100644 --- a/docs/app/reflex_docs/templates/docpage/docpage.py +++ b/docs/app/reflex_docs/templates/docpage/docpage.py @@ -361,9 +361,7 @@ def docpage_footer(path: rx.Var[str]) -> rx.Component: [ footer_link("Home", "/"), footer_link("Blog", "/blog"), - footer_link( - "Changelog", "https://github.com/reflex-dev/reflex/releases" - ), + footer_link("Changelog", "/changelog/"), ], ), footer_link_flex( diff --git a/docs/app/reflex_docs/templates/docpage/sidebar/sidebar.py b/docs/app/reflex_docs/templates/docpage/sidebar/sidebar.py index 53ba88f6b7f..0dd9cced424 100644 --- a/docs/app/reflex_docs/templates/docpage/sidebar/sidebar.py +++ b/docs/app/reflex_docs/templates/docpage/sidebar/sidebar.py @@ -21,7 +21,7 @@ ) from .sidebar_items.learn import backend, frontend, hosting, learn from .sidebar_items.recipes import recipes -from .sidebar_items.reference import api_reference +from .sidebar_items.reference import api_reference, changelog_items from .state import SideBarBase, SideBarItem SIDEBAR_ICON_MAP = { @@ -318,6 +318,7 @@ def append_to_items(items, flat_items): + mcp_items + skills_items + api_reference + + changelog_items + enterprise_items, flat_items, ) @@ -451,6 +452,7 @@ def sidebar_comp( html_lib_index: rx.vars.ArrayVar[list[int]], graphing_libs_index: rx.vars.ArrayVar[list[int]], api_reference_index: rx.vars.ArrayVar[list[int]], + changelog_index: rx.vars.ArrayVar[list[int]], recipes_index: rx.vars.ArrayVar[list[int]], enterprise_usage_index: rx.vars.ArrayVar[list[int]], enterprise_component_index: rx.vars.ArrayVar[list[int]], @@ -485,7 +487,7 @@ def sidebar_comp( ) is_library = url.contains("library") | url.contains("/mcp-") - is_api_reference = url.contains("api-reference") + is_api_reference = url.contains("api-reference") | url.startswith("/changelog/") is_enterprise = url.contains("enterprise") is_default_docs = ~is_library & ~is_api_reference & ~is_enterprise @@ -652,6 +654,14 @@ def sidebar_comp( api_reference_index, url, ), + create_sidebar_section( + "Changelog", + "/changelog/", + changelog_items, + changelog_index, + url, + connected_line=True, + ), class_name="m-0 p-0 flex flex-col items-start gap-8 w-full list-none list-style-none", ) enterprise_content = rx.el.ul( @@ -761,6 +771,7 @@ def sidebar(url=None, width: str = "100%") -> rx.Component: html_lib_index=calculate_index(html_lib, normalized_url), graphing_libs_index=calculate_index(graphing_libs, normalized_url), api_reference_index=calculate_index(api_reference, normalized_url), + changelog_index=calculate_index(changelog_items, normalized_url), recipes_index=calculate_index(recipes, normalized_url), enterprise_usage_index=calculate_index( enterprise_usage_items, normalized_url diff --git a/docs/app/reflex_docs/templates/docpage/sidebar/sidebar_items/reference.py b/docs/app/reflex_docs/templates/docpage/sidebar/sidebar_items/reference.py index 62ced3ff040..99ebe52d58c 100644 --- a/docs/app/reflex_docs/templates/docpage/sidebar/sidebar_items/reference.py +++ b/docs/app/reflex_docs/templates/docpage/sidebar/sidebar_items/reference.py @@ -1,6 +1,16 @@ +from ..state import SideBarItem from .item import create_item +def get_sidebar_items_changelog(): + from reflex_docs.pages.docs import changelog_packages + + return [ + SideBarItem(names=package, link=route) + for package, route in changelog_packages.items() + ] + + def get_sidebar_items_api_reference(): from reflex_docs.pages.docs import api_reference, apiref @@ -24,3 +34,4 @@ def get_sidebar_items_api_reference(): api_reference = get_sidebar_items_api_reference() +changelog_items = get_sidebar_items_changelog() diff --git a/docs/app/tests/test_agent_files.py b/docs/app/tests/test_agent_files.py index 382cd2111bc..9993df7a2d8 100644 --- a/docs/app/tests/test_agent_files.py +++ b/docs/app/tests/test_agent_files.py @@ -271,6 +271,14 @@ def test_generate_dynamic_api_reference_files(monkeypatch): ) +def test_section_for_root_level_markdown_strips_extension(): + """Root-level docs (e.g. the changelog index) get a clean section name.""" + from agent_files._plugin import _section_for_path + + assert _section_for_path(Path("changelog.md")) == "Changelog" + assert _section_for_path(Path("changelog/reflex-base.md")) == "Changelog" + + def test_generate_llms_full_txt_stitches_markdown_docs(monkeypatch, tmp_path): """llms-full.txt contains full Markdown page bodies with source URLs.""" monkeypatch.setattr( diff --git a/docs/app/tests/test_changelogs.py b/docs/app/tests/test_changelogs.py new file mode 100644 index 00000000000..00a68ae3d89 --- /dev/null +++ b/docs/app/tests/test_changelogs.py @@ -0,0 +1,175 @@ +"""Tests for package changelog discovery and normalization.""" + +from pathlib import Path, PurePosixPath + +from reflex_docs.changelogs import ( + ENTERPRISE_PACKAGE, + changelog_page_title, + discover_changelogs, + discover_repo_changelogs, + find_distribution_changelog, + normalize_changelog, +) + +REPO_ROOT = Path(__file__).resolve().parents[3] + + +class _FakeDist: + """Minimal stand-in for importlib.metadata.Distribution.""" + + def __init__(self, files, root): + self._files = files + self._root = root + + @property + def files(self): + return self._files + + def locate_file(self, file): + return self._root / file + + +def test_discover_repo_changelogs(tmp_path): + """Repo discovery picks up the root changelog and one per subpackage.""" + (tmp_path / "CHANGELOG.md").write_text("## v1.0.0\n") + foo = tmp_path / "packages" / "foo" + foo.mkdir(parents=True) + (foo / "CHANGELOG.md").write_text("## v0.1.0\n") + (tmp_path / "packages" / "bar").mkdir() + + changelogs = discover_repo_changelogs(tmp_path) + + assert changelogs == { + "reflex": tmp_path / "CHANGELOG.md", + "foo": foo / "CHANGELOG.md", + } + + +def test_discover_repo_changelogs_real_repo(): + """The docs app reaches up to the actual repo root for changelogs.""" + changelogs = discover_repo_changelogs(REPO_ROOT) + + assert changelogs["reflex"] == REPO_ROOT / "CHANGELOG.md" + assert "reflex-base" in changelogs + assert all(path.is_file() for path in changelogs.values()) + + +def test_discover_changelogs_orders_reflex_first(tmp_path, monkeypatch): + """The reflex changelog sorts first; the rest are alphabetical.""" + (tmp_path / "CHANGELOG.md").write_text("## v1.0.0\n") + for pkg in ("reflex-zeta", "reflex-alpha"): + pkg_dir = tmp_path / "packages" / pkg + pkg_dir.mkdir(parents=True) + (pkg_dir / "CHANGELOG.md").write_text("## v0.1.0\n") + enterprise = tmp_path / "enterprise-changelog.md" + enterprise.write_text("# Changelog\n") + monkeypatch.setattr( + "reflex_docs.changelogs.find_distribution_changelog", + lambda package: enterprise, + ) + + changelogs = discover_changelogs(tmp_path) + + assert list(changelogs) == [ + "reflex", + "reflex-alpha", + ENTERPRISE_PACKAGE, + "reflex-zeta", + ] + assert changelogs[ENTERPRISE_PACKAGE] == enterprise + + +def test_discover_changelogs_skips_missing_enterprise(tmp_path, monkeypatch): + """No enterprise entry when the installed distribution has no changelog.""" + (tmp_path / "CHANGELOG.md").write_text("## v1.0.0\n") + monkeypatch.setattr( + "reflex_docs.changelogs.find_distribution_changelog", + lambda package: None, + ) + + assert ENTERPRISE_PACKAGE not in discover_changelogs(tmp_path) + + +def test_find_distribution_changelog_not_installed(): + assert find_distribution_changelog("definitely-not-a-real-package-xyz") is None + + +def test_find_distribution_changelog_found(tmp_path, monkeypatch): + """The changelog is located through the distribution's file records.""" + changelog = tmp_path / "reflex_enterprise" / "CHANGELOG.md" + changelog.parent.mkdir() + changelog.write_text("# Changelog\n") + files = [ + PurePosixPath("reflex_enterprise/__init__.py"), + PurePosixPath("reflex_enterprise/CHANGELOG.md"), + ] + monkeypatch.setattr( + "reflex_docs.changelogs.distribution", + lambda package: _FakeDist(files, tmp_path), + ) + + assert find_distribution_changelog(ENTERPRISE_PACKAGE) == changelog + + +def test_find_distribution_changelog_prefers_shallowest_record(tmp_path, monkeypatch): + """Vendored changelogs deeper in the tree don't shadow the package one.""" + vendored = tmp_path / "reflex_enterprise" / "vendor" / "lib" / "CHANGELOG.md" + vendored.parent.mkdir(parents=True) + vendored.write_text("# Vendored\n") + changelog = tmp_path / "reflex_enterprise" / "CHANGELOG.md" + changelog.write_text("# Changelog\n") + files = [ + PurePosixPath("reflex_enterprise/vendor/lib/CHANGELOG.md"), + PurePosixPath("reflex_enterprise/CHANGELOG.md"), + ] + monkeypatch.setattr( + "reflex_docs.changelogs.distribution", + lambda package: _FakeDist(files, tmp_path), + ) + + assert find_distribution_changelog(ENTERPRISE_PACKAGE) == changelog + + +def test_find_distribution_changelog_no_file_records(monkeypatch): + """Distributions without file records (files is None) are skipped.""" + monkeypatch.setattr( + "reflex_docs.changelogs.distribution", + lambda package: _FakeDist(None, Path("/nonexistent")), + ) + + assert find_distribution_changelog(ENTERPRISE_PACKAGE) is None + + +def test_find_distribution_changelog_stale_record(tmp_path, monkeypatch): + """A recorded changelog that is missing on disk is ignored.""" + files = [PurePosixPath("reflex_enterprise/CHANGELOG.md")] + monkeypatch.setattr( + "reflex_docs.changelogs.distribution", + lambda package: _FakeDist(files, tmp_path), + ) + + assert find_distribution_changelog(ENTERPRISE_PACKAGE) is None + + +def test_changelog_page_title(): + assert changelog_page_title("reflex") == "Reflex Changelog" + assert changelog_page_title("reflex-base") == "reflex-base Changelog" + + +def test_normalize_changelog_towncrier(): + """Towncrier changelogs (no H1) get the canonical title prepended.""" + source = "## v0.9.4 (2026-06-03)\n\n### Features\n\n- A change.\n" + + assert normalize_changelog(source, "Reflex Changelog") == ( + "# Reflex Changelog\n\n## v0.9.4 (2026-06-03)\n\n### Features\n\n- A change.\n" + ) + + +def test_normalize_changelog_replaces_existing_h1(): + """Keep-a-Changelog files have their generic H1 replaced.""" + source = "# Changelog\n\n## [0.9.0] - 2026-06-09\n\n### Changed\n\n- A change.\n" + + assert normalize_changelog(source, "reflex-enterprise Changelog") == ( + "# reflex-enterprise Changelog\n\n" + "## [0.9.0] - 2026-06-09\n\n### Changed\n\n- A change.\n" + ) diff --git a/docs/app/tests/test_routes.py b/docs/app/tests/test_routes.py index f764d3adc0c..1ca1692ae45 100644 --- a/docs/app/tests/test_routes.py +++ b/docs/app/tests/test_routes.py @@ -28,6 +28,18 @@ def test_unique_routes(routes_fixture): print(f"Test passed. All {len(paths)} routes are unique.") +def test_changelog_routes(routes_fixture): + """Every discovered package changelog is served under /changelog/.""" + from reflex_docs.pages.docs import changelog_packages + + paths = {route.path for route in routes_fixture if route.path} + + assert changelog_packages["reflex"] == "/changelog/" + assert "/changelog/reflex-base/" in paths + for changelog_route in changelog_packages.values(): + assert changelog_route in paths + + def test_ai_builder_routes_use_ai_prefix(routes_fixture): paths = {route.path for route in routes_fixture if route.path} diff --git a/packages/reflex-site-shared/src/reflex_site_shared/constants.py b/packages/reflex-site-shared/src/reflex_site_shared/constants.py index 1c2379b1b86..1c8588b654f 100644 --- a/packages/reflex-site-shared/src/reflex_site_shared/constants.py +++ b/packages/reflex-site-shared/src/reflex_site_shared/constants.py @@ -2,7 +2,7 @@ import os -CHANGELOG_URL = "https://github.com/reflex-dev/reflex/releases" +CHANGELOG_URL = "https://reflex.dev/docs/changelog/" CONTRIBUTING_URL = "https://github.com/reflex-dev/reflex/blob/main/CONTRIBUTING.md" DISCUSSIONS_URL = "https://github.com/orgs/reflex-dev/discussions" GITHUB_STARS = 28000 diff --git a/pyproject.toml b/pyproject.toml index 525ef5332f5..d4a8ff77b4c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -392,6 +392,7 @@ reflex-components-radix = false reflex-components-react-player = false reflex-components-recharts = false reflex-components-sonner = false +reflex-enterprise = false reflex-hosting-cli = false [tool.uv.sources] diff --git a/uv.lock b/uv.lock index 1980545ad95..789b7db8b7e 100644 --- a/uv.lock +++ b/uv.lock @@ -23,6 +23,7 @@ reflex-components-sonner = false hatch-reflex-pyi = false reflex-components-gridjs = false reflex = false +reflex-enterprise = false reflex-components-code = false reflex-components-recharts = false reflex-components-core = false @@ -3841,7 +3842,7 @@ requires-dist = [ { name = "reflex", editable = "." }, { name = "reflex-components-internal", editable = "packages/reflex-components-internal" }, { name = "reflex-docgen", editable = "packages/reflex-docgen" }, - { name = "reflex-enterprise" }, + { name = "reflex-enterprise", specifier = ">=0.9.0.post1" }, { name = "reflex-hosting-cli", editable = "packages/reflex-hosting-cli" }, { name = "reflex-integrations-docs", editable = "packages/integrations-docs" }, { name = "reflex-pyplot" }, @@ -3868,7 +3869,7 @@ source = { editable = "docs/package" } [[package]] name = "reflex-enterprise" -version = "0.7.0.post1" +version = "0.9.0.post1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "asgiproxy" }, @@ -3877,9 +3878,9 @@ dependencies = [ { name = "psutil" }, { name = "reflex", extra = ["db"] }, ] -sdist = { url = "https://files.pythonhosted.org/packages/17/5e/386cda3b7bd54aba75267f52fa32f93766bf9973382a6dec384b83779493/reflex_enterprise-0.7.0.post1.tar.gz", hash = "sha256:cc23343bd0d8b2d5ed45a0c551ca0b833c735125a855a74cae608ef39be94ccf", size = 396669, upload-time = "2026-04-21T17:36:43.127Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/51/77a3a97de2466fd66d0e78ea644e4e7793604afe01fd81c8f2383a88e22e/reflex_enterprise-0.9.0.post1.tar.gz", hash = "sha256:dc40120fecff5c5ba6d1471b7c7cbb56db8596305a83a34142cc810bde3cd5f1", size = 431732, upload-time = "2026-06-09T20:10:58.083Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5e/02/b45cdf9a9322ae0c1f31ca51736f70b2508e05339149153c6e902d609651/reflex_enterprise-0.7.0.post1-py3-none-any.whl", hash = "sha256:bc510d05a4bc8abe26ab4d02e1f06e82af4d255ea29209d620c8d3d662c8a203", size = 219320, upload-time = "2026-04-21T17:36:44.379Z" }, + { url = "https://files.pythonhosted.org/packages/bc/55/01983923203174b8e3adf1cb702f62785bef30735c2d81f3c8e67ae60639/reflex_enterprise-0.9.0.post1-py3-none-any.whl", hash = "sha256:0bc2d2d92ba79a7620d4e1fcf6bc609c791f3eba5c6c051daf65fb41921d1634", size = 233834, upload-time = "2026-06-09T20:10:56.82Z" }, ] [[package]]