diff --git a/scripts/addons_core/bl_pkg/cli/blender_ext.py b/scripts/addons_core/bl_pkg/cli/blender_ext.py
index 4cfef981f58..aff2957db3a 100755
--- a/scripts/addons_core/bl_pkg/cli/blender_ext.py
+++ b/scripts/addons_core/bl_pkg/cli/blender_ext.py
@@ -2627,7 +2627,10 @@ class subcmd_server:
) -> bool:
import html
import datetime
- from string import Template
+ from string import (
+ Template,
+ capwords,
+ )
import urllib
import urllib.parse
@@ -2636,64 +2639,90 @@ class subcmd_server:
fh = io.StringIO()
- fh.write("
\n")
- fh.write(" \n")
- fh.write(" ID | \n")
- fh.write(" Name | \n")
- fh.write(" Description | \n")
- fh.write(" Blender Versions | \n")
- fh.write(" Platforms | \n")
- fh.write(" Size | \n")
- fh.write("
\n")
- for manifest_dict in sorted(repo_data, key=lambda manifest: (manifest["id"], manifest["version"])):
+ # Group extensions by their type.
+ repo_data_by_type: Dict[str, List[Dict[str, Any]]] = {}
+
+ for manifest_dict in repo_data:
+ manifest_type = manifest_dict["type"]
+ try:
+ repo_data_typed = repo_data_by_type[manifest_type]
+ except KeyError:
+ repo_data_typed = repo_data_by_type[manifest_type] = []
+ repo_data_typed.append(manifest_dict)
+
+ for manifest_type, repo_data_typed in sorted(repo_data_by_type.items(), key=lambda item: item[0]):
+ # Type heading.
+ fh.write("{:s}
\n".format(capwords(manifest_type)))
+ fh.write("
\n")
+
+ fh.write("\n")
fh.write(" \n")
-
- platforms = [platform for platform in manifest_dict.get("platforms", "").split(",") if platform]
-
- # Parse the URL and add parameters use for drag & drop.
- parsed_url = urllib.parse.urlparse(manifest_dict["archive_url"])
- # We could support existing values, currently always empty.
- # `query = dict(urllib.parse.parse_qsl(parsed_url.query))`
- query = {"repository": "/index.json"}
- if (value := manifest_dict.get("blender_version_min", "")):
- query["blender_version_min"] = value
- if (value := manifest_dict.get("blender_version_max", "")):
- query["blender_version_max"] = value
- if platforms:
- query["platforms"] = ",".join(platforms)
- del value
-
- id_and_link = "{:s}".format(
- urllib.parse.urlunparse((
- parsed_url.scheme,
- parsed_url.netloc,
- parsed_url.path,
- parsed_url.params,
- urllib.parse.urlencode(query, doseq=True) if query else None,
- parsed_url.fragment,
- )),
- html.escape("{:s}-{:s}".format(manifest_dict["id"], manifest_dict["version"])),
- )
-
- # Write the table data.
- fh.write(" {:s} | \n".format(id_and_link))
- fh.write(" {:s} | \n".format(html.escape(manifest_dict["name"])))
- fh.write(" {:s} | \n".format(html.escape(manifest_dict["tagline"] or "")))
- blender_version_min = manifest_dict.get("blender_version_min", "")
- blender_version_max = manifest_dict.get("blender_version_max", "")
- if blender_version_min or blender_version_max:
- blender_version_str = "{:s} - {:s}".format(
- blender_version_min or "~",
- blender_version_max or "~",
- )
- else:
- blender_version_str = "all"
- fh.write(" {:s} | \n".format(html.escape(blender_version_str)))
- fh.write(" {:s} | \n".format(html.escape(", ".join(platforms) if platforms else "all")))
- fh.write(" {:s} | \n".format(html.escape(size_as_fmt_string(manifest_dict["archive_size"]))))
+ fh.write(" ID | \n")
+ fh.write(" Name | \n")
+ fh.write(" Description | \n")
+ fh.write(" Website | \n")
+ fh.write(" Blender Versions | \n")
+ fh.write(" Platforms | \n")
+ fh.write(" Size | \n")
fh.write("
\n")
- fh.write("
\n")
+ for manifest_dict in sorted(
+ repo_data_typed,
+ key=lambda manifest_dict: (manifest_dict["id"], manifest_dict["version"]),
+ ):
+ fh.write(" \n")
+
+ platforms = [platform for platform in manifest_dict.get("platforms", "").split(",") if platform]
+
+ # Parse the URL and add parameters use for drag & drop.
+ parsed_url = urllib.parse.urlparse(manifest_dict["archive_url"])
+ # We could support existing values, currently always empty.
+ # `query = dict(urllib.parse.parse_qsl(parsed_url.query))`
+ query = {"repository": "/index.json"}
+ if (value := manifest_dict.get("blender_version_min", "")):
+ query["blender_version_min"] = value
+ if (value := manifest_dict.get("blender_version_max", "")):
+ query["blender_version_max"] = value
+ if platforms:
+ query["platforms"] = ",".join(platforms)
+ del value
+
+ id_and_link = "{:s}".format(
+ urllib.parse.urlunparse((
+ parsed_url.scheme,
+ parsed_url.netloc,
+ parsed_url.path,
+ parsed_url.params,
+ urllib.parse.urlencode(query, doseq=True) if query else None,
+ parsed_url.fragment,
+ )),
+ html.escape("{:s}-{:s}".format(manifest_dict["id"], manifest_dict["version"])),
+ )
+
+ # Write the table data.
+ fh.write(" {:s} | \n".format(id_and_link))
+ fh.write(" {:s} | \n".format(html.escape(manifest_dict["name"])))
+ fh.write(" {:s} | \n".format(html.escape(manifest_dict["tagline"] or "")))
+ if value := manifest_dict.get("website", ""):
+ fh.write(" link | \n".format(html.escape(value)))
+ else:
+ fh.write(" ~ | \n")
+ del value
+ blender_version_min = manifest_dict.get("blender_version_min", "")
+ blender_version_max = manifest_dict.get("blender_version_max", "")
+ if blender_version_min or blender_version_max:
+ blender_version_str = "{:s} - {:s}".format(
+ blender_version_min or "~",
+ blender_version_max or "~",
+ )
+ else:
+ blender_version_str = "all"
+ fh.write(" {:s} | \n".format(html.escape(blender_version_str)))
+ fh.write(" {:s} | \n".format(html.escape(", ".join(platforms) if platforms else "all")))
+ fh.write(" {:s} | \n".format(html.escape(size_as_fmt_string(manifest_dict["archive_size"]))))
+ fh.write("
\n")
+
+ fh.write("
\n")
body = fh.getvalue()
del fh