Переглянути джерело

update init prompt to use new templates from reflex-dev/templates (#3677)

Thomas Brandého 10 місяців тому
батько
коміт
c4346c2624
1 змінених файлів з 67 додано та 35 видалено
  1. 67 35
      reflex/utils/prerequisites.py

+ 67 - 35
reflex/utils/prerequisites.py

@@ -1311,39 +1311,63 @@ def migrate_to_reflex():
                 print(line, end="")
                 print(line, end="")
 
 
 
 
-def fetch_app_templates() -> dict[str, Template]:
-    """Fetch the list of app templates from the Reflex backend server.
+RELEASES_URL = f"https://api.github.com/repos/reflex-dev/templates/releases"
+
+
+def fetch_app_templates(version: str) -> dict[str, Template]:
+    """Fetch a dict of templates from the templates repo using github API.
+
+    Args:
+        version: The version of the templates to fetch.
 
 
     Returns:
     Returns:
-        The name and download URL as a dictionary.
+        The dict of templates.
     """
     """
-    config = get_config()
-    if not config.cp_backend_url:
-        console.info(
-            "Skip fetching App templates. No backend URL is specified in the config."
-        )
-        return {}
-    try:
-        response = httpx.get(
-            f"{config.cp_backend_url}{constants.Templates.APP_TEMPLATES_ROUTE}"
-        )
+
+    def get_release_by_tag(tag: str) -> dict | None:
+        response = httpx.get(RELEASES_URL)
         response.raise_for_status()
         response.raise_for_status()
-        return {
-            template["name"]: Template.parse_obj(template)
-            for template in response.json()
-        }
-    except httpx.HTTPError as ex:
-        console.info(f"Failed to fetch app templates: {ex}")
+        releases = response.json()
+        for release in releases:
+            if release["tag_name"] == f"v{tag}":
+                return release
+        return None
+
+    release = get_release_by_tag(version)
+    if release is None:
+        console.warn(f"No templates known for version {version}")
         return {}
         return {}
-    except (TypeError, KeyError, json.JSONDecodeError) as tkje:
-        console.info(f"Unable to process server response for app templates: {tkje}")
+
+    assets = release.get("assets", [])
+    asset = next((a for a in assets if a["name"] == "templates.json"), None)
+    if asset is None:
+        console.warn(f"Templates metadata not found for version {version}")
         return {}
         return {}
+    else:
+        templates_url = asset["browser_download_url"]
 
 
+    templates_data = httpx.get(templates_url, follow_redirects=True).json()["templates"]
 
 
-def create_config_init_app_from_remote_template(
-    app_name: str,
-    template_url: str,
-):
+    for template in templates_data:
+        if template["name"] == "blank":
+            template["code_url"] = ""
+            continue
+        template["code_url"] = next(
+            (
+                a["browser_download_url"]
+                for a in assets
+                if a["name"] == f"{template['name']}.zip"
+            ),
+            None,
+        )
+    return {
+        tp["name"]: Template.parse_obj(tp)
+        for tp in templates_data
+        if not tp["hidden"] and tp["code_url"] is not None
+    }
+
+
+def create_config_init_app_from_remote_template(app_name: str, template_url: str):
     """Create new rxconfig and initialize app using a remote template.
     """Create new rxconfig and initialize app using a remote template.
 
 
     Args:
     Args:
@@ -1437,15 +1461,20 @@ def initialize_app(app_name: str, template: str | None = None):
         telemetry.send("reinit")
         telemetry.send("reinit")
         return
         return
 
 
-    # Get the available templates
-    templates: dict[str, Template] = fetch_app_templates()
+    templates: dict[str, Template] = {}
 
 
-    # Prompt for a template if not provided.
-    if template is None and len(templates) > 0:
-        template = prompt_for_template(list(templates.values()))
-    elif template is None:
-        template = constants.Templates.DEFAULT
-    assert template is not None
+    # Don't fetch app templates if the user directly asked for DEFAULT.
+    if template is None or (template != constants.Templates.DEFAULT):
+        try:
+            # Get the available templates
+            templates = fetch_app_templates(constants.Reflex.VERSION)
+            if template is None and len(templates) > 0:
+                template = prompt_for_template(list(templates.values()))
+        except Exception as e:
+            console.warn("Failed to fetch templates. Falling back to default template.")
+            console.debug(f"Error while fetching templates: {e}")
+        finally:
+            template = template or constants.Templates.DEFAULT
 
 
     # If the blank template is selected, create a blank app.
     # If the blank template is selected, create a blank app.
     if template == constants.Templates.DEFAULT:
     if template == constants.Templates.DEFAULT:
@@ -1468,9 +1497,12 @@ def initialize_app(app_name: str, template: str | None = None):
             else:
             else:
                 console.error(f"Template `{template}` not found.")
                 console.error(f"Template `{template}` not found.")
                 raise typer.Exit(1)
                 raise typer.Exit(1)
+
+        if template_url is None:
+            return
+
         create_config_init_app_from_remote_template(
         create_config_init_app_from_remote_template(
-            app_name=app_name,
-            template_url=template_url,
+            app_name=app_name, template_url=template_url
         )
         )
 
 
     telemetry.send("init", template=template)
     telemetry.send("init", template=template)