diff --git a/binderhub/launcher.py b/binderhub/launcher.py
index 8d7b81fbe..a6f0cd423 100644
--- a/binderhub/launcher.py
+++ b/binderhub/launcher.py
@@ -148,6 +148,17 @@ async def get_user_data(self, username):
body = json.loads(resp.body.decode("utf-8"))
return body
+ async def get_named_server_count(self, username):
+ """Return the number of named servers for a given JupyterHub user."""
+ try:
+ user_data = await self.get_user_data(username)
+ except RuntimeError:
+ return 0
+ servers = user_data.get("servers", {})
+ if not isinstance(servers, dict):
+ return 0
+ return sum(1 for server_name in servers if server_name != "")
+
def unique_name_from_repo(self, repo_url):
"""Generate a unique name for a git repo url
diff --git a/binderhub/main.py b/binderhub/main.py
index 357e2bef4..570075b79 100644
--- a/binderhub/main.py
+++ b/binderhub/main.py
@@ -23,17 +23,32 @@ def initialize(self):
return super().initialize()
@authenticated
- def get(self):
+ async def get(self):
repoproviders_display_config = [
repo_provider_class.display_config
for repo_provider_class in self.settings["repo_providers"].values()
]
+ running_environment_count = None
+ launcher = self.settings.get("launcher")
+ if launcher is not None:
+ try:
+ user = self.get_current_user()
+ username = user.get("name") if isinstance(user, dict) else user
+ if username:
+ running_environment_count = await launcher.get_named_server_count(
+ username
+ )
+ except Exception:
+ self.log.debug(
+ "Unable to determine current environment count", exc_info=True
+ )
self.page_config |= {
"baseUrl": self.settings["base_url"],
"badgeBaseUrl": self.get_badge_base_url(),
"logoUrl": self.static_url("logo.svg"),
"logoWidth": "320px",
"repoProviders": repoproviders_display_config,
+ "runningEnvironmentCount": running_environment_count,
"aboutMessage": self.settings["about_message"],
"bannerHtml": self.settings["banner_message"],
"binderVersion": binder_version,
@@ -58,7 +73,7 @@ def initialize(self, repo_provider):
return super().initialize()
@authenticated
- def get(self, provider_id, _escaped_spec):
+ async def get(self, provider_id, _escaped_spec):
prefix = "/v2/" + provider_id
spec = self.get_spec_from_request(prefix)
@@ -75,7 +90,7 @@ def get(self, provider_id, _escaped_spec):
self.opengraph_title = (
f"{self.repo_provider.display_config['displayName']}: {spec}"
)
- return super().get()
+ return await super().get()
class LegacyRedirectHandler(BaseHandler):
diff --git a/binderhub/static/js/components/LinkGenerator.jsx b/binderhub/static/js/components/LinkGenerator.jsx
index 7492ee08d..439b03587 100644
--- a/binderhub/static/js/components/LinkGenerator.jsx
+++ b/binderhub/static/js/components/LinkGenerator.jsx
@@ -1,5 +1,6 @@
import { useEffect, useState } from "react";
import copy from "copy-to-clipboard";
+import { PAGE_CONFIG } from "../App.jsx";
/**
* @typedef {object} ProviderSelectorProps
@@ -346,6 +347,17 @@ export function LinkGenerator({
→問い合わせ先/エラーが発生したときは
→Contact Information/Troubleshooting
+ {PAGE_CONFIG.runningEnvironmentCount !== undefined &&
+ PAGE_CONFIG.runningEnvironmentCount !== null && (
+