From 0424fcb86bd16a523a459bcb5c24cfaa0c70b261 Mon Sep 17 00:00:00 2001 From: Mario Ruiz <11815099+mariodruiz@users.noreply.github.com> Date: Wed, 17 Jun 2026 12:50:15 +0100 Subject: [PATCH 01/48] fix(hub): decouple GitHub username prefix from login_service label --- runtime/hub/core/authenticators/__init__.py | 3 ++- runtime/hub/core/authenticators/github_app.py | 3 +++ runtime/hub/core/groups.py | 6 ++++-- runtime/hub/core/handlers.py | 14 +++++++------- runtime/hub/core/setup.py | 7 ++++--- runtime/hub/tests/test_groups.py | 10 ++++++++++ 6 files changed, 30 insertions(+), 13 deletions(-) diff --git a/runtime/hub/core/authenticators/__init__.py b/runtime/hub/core/authenticators/__init__.py index ca0e3255..b5119042 100644 --- a/runtime/hub/core/authenticators/__init__.py +++ b/runtime/hub/core/authenticators/__init__.py @@ -25,7 +25,7 @@ from core.authenticators.auto_login import AutoLoginAuthenticator from core.authenticators.firstuse import CustomFirstUseAuthenticator -from core.authenticators.github_app import CustomGitHubOAuthenticator +from core.authenticators.github_app import CustomGitHubOAuthenticator, GITHUB_USERNAME_PREFIX from core.authenticators.jwt import RemoteLabAuthenticator from core.authenticators.multi import CustomMultiAuthenticator @@ -64,4 +64,5 @@ def create_authenticator(auth_mode: str, **kwargs): "CustomMultiAuthenticator", "create_authenticator", "LOCAL_ACCOUNT_PREFIX", + "GITHUB_USERNAME_PREFIX", ] diff --git a/runtime/hub/core/authenticators/github_app.py b/runtime/hub/core/authenticators/github_app.py index f9939644..6e04b2c7 100644 --- a/runtime/hub/core/authenticators/github_app.py +++ b/runtime/hub/core/authenticators/github_app.py @@ -35,6 +35,8 @@ log = logging.getLogger("jupyterhub.auth.github") +GITHUB_USERNAME_PREFIX = "github:" + class _GitHubAppInstallCallbackHandler(OAuthCallbackHandler): """Callback handler that gracefully handles GitHub App installation redirects. @@ -57,6 +59,7 @@ class CustomGitHubOAuthenticator(GitHubOAuthenticator): """GitHub App authenticator with access token preservation and refresh.""" name = "github" + prefix = GITHUB_USERNAME_PREFIX callback_handler = _GitHubAppInstallCallbackHandler app_id = Unicode( diff --git a/runtime/hub/core/groups.py b/runtime/hub/core/groups.py index f245d9fd..30d7b085 100644 --- a/runtime/hub/core/groups.py +++ b/runtime/hub/core/groups.py @@ -39,6 +39,8 @@ from jupyterhub.user import User as JupyterHubUser from sqlalchemy.orm import Session +from core.authenticators.github_app import GITHUB_USERNAME_PREFIX + log = logging.getLogger("jupyterhub.groups") GITHUB_TEAM_SOURCE = "github-team" @@ -548,7 +550,7 @@ async def sync_github_teams_for_user( protection. Concurrent spawns for the same user coalesce into one set of GitHub team membership checks within the TTL window. """ - if not user.name.startswith("github:") or not app_id: + if not user.name.startswith(GITHUB_USERNAME_PREFIX) or not app_id: return False lock = _GITHUB_TEAM_SYNC_LOCKS.setdefault(user.name, asyncio.Lock()) @@ -714,7 +716,7 @@ def resolve_resources_for_user( if available_resources: return available_resources - if not username.startswith("github:"): + if not username.startswith(GITHUB_USERNAME_PREFIX): return team_resource_mapping.get("native-users", team_resource_mapping.get("official", [])) return ["none"] diff --git a/runtime/hub/core/handlers.py b/runtime/hub/core/handlers.py index 42786695..42b401fd 100644 --- a/runtime/hub/core/handlers.py +++ b/runtime/hub/core/handlers.py @@ -41,7 +41,7 @@ from pydantic import ValidationError from tornado import web -from core.authenticators import CustomFirstUseAuthenticator +from core.authenticators import GITHUB_USERNAME_PREFIX, CustomFirstUseAuthenticator from core.git_validation import validate_and_sanitize_repo_url from core.notifications import get_normalized_notifications from core.quota import ( @@ -265,7 +265,7 @@ def _render_error(msg: str): return self.finish(html) username = user.name - if username.startswith("github:"): + if username.startswith(GITHUB_USERNAME_PREFIX): html = await _render_error("GitHub users cannot change password here") self.set_status(400) return self.finish(html) @@ -322,7 +322,7 @@ async def get(self): from jupyterhub.orm import User for user in self.db.query(User).all(): - if not user.name.startswith("github:") and user.name != "admin": + if not user.name.startswith(GITHUB_USERNAME_PREFIX) and user.name != "admin": native_users.append(user.name) html = await self.render_template( @@ -356,7 +356,7 @@ async def post(self): ) username = target_user - if username.startswith("github:"): + if username.startswith(GITHUB_USERNAME_PREFIX): return self.redirect( self.hub.base_url + f"admin/reset-password?user={target_user}&error=Cannot+reset+password+for+GitHub+users" @@ -438,7 +438,7 @@ async def post(self): self.set_header("Content-Type", "application/json") return self.finish(json.dumps({"error": "Username and password are required"})) - if username.startswith("github:"): + if username.startswith(GITHUB_USERNAME_PREFIX): self.set_status(400) self.set_header("Content-Type", "application/json") return self.finish(json.dumps({"error": "Cannot set password for GitHub users"})) @@ -532,7 +532,7 @@ async def post(self): self.set_status(400) self.set_header("Content-Type", "application/json") return self.finish(json.dumps({"error": "Each entry must have username and password"})) - if entry.get("username", "").startswith("github:"): + if entry.get("username", "").startswith(GITHUB_USERNAME_PREFIX): self.set_status(400) self.set_header("Content-Type", "application/json") return self.finish( @@ -1583,7 +1583,7 @@ async def post(self): skipped = 0 for user in self.users.values(): - if not user.name.startswith("github:"): + if not user.name.startswith(GITHUB_USERNAME_PREFIX): skipped += 1 continue diff --git a/runtime/hub/core/setup.py b/runtime/hub/core/setup.py index 84d395ee..04692456 100644 --- a/runtime/hub/core/setup.py +++ b/runtime/hub/core/setup.py @@ -65,6 +65,7 @@ def setup_hub(c: Any) -> None: """ from core import z2jh from core.authenticators import ( + GITHUB_USERNAME_PREFIX, CustomFirstUseAuthenticator, CustomGitHubOAuthenticator, create_authenticator, @@ -121,7 +122,7 @@ async def auth_state_hook(spawner, auth_state): if auth_state is None: spawner.github_access_token = None # Still assign native users to their default group - if not spawner.user.name.startswith("github:"): + if not spawner.user.name.startswith(GITHUB_USERNAME_PREFIX): try: from core.groups import assign_user_to_group @@ -131,7 +132,7 @@ async def auth_state_hook(spawner, auth_state): return spawner.github_access_token = auth_state.get("access_token") - if spawner.user.name.startswith("github:"): + if spawner.user.name.startswith(GITHUB_USERNAME_PREFIX): try: from core.groups import sync_github_teams_for_user @@ -160,7 +161,7 @@ async def auth_state_hook(spawner, auth_state): assign_user_to_group(spawner.user, "github-users", spawner.user.db) except Exception as e: print(f"[GROUPS] Warning: Failed to assign github-users group for {spawner.user.name}: {e}") - elif not spawner.user.name.startswith("github:"): + elif not spawner.user.name.startswith(GITHUB_USERNAME_PREFIX): # Native user with auth_state but no GitHub teams try: from core.groups import assign_user_to_group diff --git a/runtime/hub/tests/test_groups.py b/runtime/hub/tests/test_groups.py index 641848aa..3276b4dd 100644 --- a/runtime/hub/tests/test_groups.py +++ b/runtime/hub/tests/test_groups.py @@ -51,6 +51,16 @@ core_module.__path__ = [str(CORE)] sys.modules["core"] = core_module +if "core.authenticators" not in sys.modules: + authenticators_module = types.ModuleType("core.authenticators") + authenticators_module.__path__ = [str(CORE / "authenticators")] + sys.modules["core.authenticators"] = authenticators_module + +if "core.authenticators.github_app" not in sys.modules: + github_app_module = types.ModuleType("core.authenticators.github_app") + github_app_module.GITHUB_USERNAME_PREFIX = "github:" + sys.modules["core.authenticators.github_app"] = github_app_module + def load_module(name: str, path: Path): spec = importlib.util.spec_from_file_location(name, path) From 779f79924e4b194df4a2216b6068d03f293e48d7 Mon Sep 17 00:00:00 2001 From: Mario Ruiz <11815099+mariodruiz@users.noreply.github.com> Date: Wed, 17 Jun 2026 12:59:05 +0100 Subject: [PATCH 02/48] Make ruff happy --- runtime/hub/core/authenticators/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/hub/core/authenticators/__init__.py b/runtime/hub/core/authenticators/__init__.py index b5119042..7a491341 100644 --- a/runtime/hub/core/authenticators/__init__.py +++ b/runtime/hub/core/authenticators/__init__.py @@ -25,7 +25,7 @@ from core.authenticators.auto_login import AutoLoginAuthenticator from core.authenticators.firstuse import CustomFirstUseAuthenticator -from core.authenticators.github_app import CustomGitHubOAuthenticator, GITHUB_USERNAME_PREFIX +from core.authenticators.github_app import GITHUB_USERNAME_PREFIX, CustomGitHubOAuthenticator from core.authenticators.jwt import RemoteLabAuthenticator from core.authenticators.multi import CustomMultiAuthenticator From 9cc95ba679d7eca77af88710f214701158257bdc Mon Sep 17 00:00:00 2001 From: ShifZhan <252984256+MioYuuIH@users.noreply.github.com> Date: Thu, 18 Jun 2026 11:50:31 +0800 Subject: [PATCH 03/48] chore: update multinodes description --- runtime/values-multi-nodes.yaml.example | 28 ++++++++++++++++--------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/runtime/values-multi-nodes.yaml.example b/runtime/values-multi-nodes.yaml.example index 000e4baf..ff40c339 100644 --- a/runtime/values-multi-nodes.yaml.example +++ b/runtime/values-multi-nodes.yaml.example @@ -200,6 +200,14 @@ custom: code-cpu: "ghcr.io/amdresearch/auplc-code-cpu:latest" code-gpu: "ghcr.io/amdresearch/auplc-code-gpu:latest" + # Optional spawn/Home group display order. Groups not listed here are shown + # after these entries using the default alphabetical order. + # Example: move DEVELOPMENT before COURSE by listing DEVELOPMENT first. + groupOrder: + - TEACHING LABS + - DEVELOPMENT ENVIRONMENT + - CUSTOM REPOS + requirements: cpu: cpu: "0" @@ -237,7 +245,7 @@ custom: metadata: cpu: - group: "CUSTOM REPO" + group: "CUSTOM REPOS" description: "Basic Python Environment" subDescription: "CPU Only Environment" accelerator: "" @@ -245,8 +253,8 @@ custom: allowGitClone: true resourceType: "notebook" code-cpu: - group: "DEVELOPMENT" - description: "VSCode Server CPU Environment" + group: "DEVELOPMENT ENVIRONMENT" + description: "VSCode Server - CPU Environment" subDescription: "CPU-only development workspace" accelerator: "" acceleratorKeys: [] @@ -254,7 +262,7 @@ custom: launchMode: "code-server" resourceType: "browser-ide" gpu: - group: "CUSTOM REPO" + group: "CUSTOM REPOS" description: "Basic GPU Environment" subDescription: "GPU Accelerated Environment" accelerator: "GPU" @@ -263,8 +271,8 @@ custom: allowGitClone: true resourceType: "notebook" code-gpu: - group: "DEVELOPMENT" - description: "VSCode Server GPU Environment" + group: "DEVELOPMENT ENVIRONMENT" + description: "VSCode Server - GPU Environment" subDescription: "GPU-accelerated development workspace" accelerator: "GPU" acceleratorKeys: @@ -273,7 +281,7 @@ custom: launchMode: "code-server" resourceType: "browser-ide" Course-CV: - group: "COURSE" + group: "TEACHING LABS" description: "Computer Vision Course" subDescription: "Suitable for CV experiments with GPU" accelerator: "GPU" @@ -290,7 +298,7 @@ custom: # strix-halo: # image: "ghcr.io/your-org/auplc-cv:latest-gfx1151" Course-DL: - group: "COURSE" + group: "TEACHING LABS" description: "Deep Learning Course" subDescription: "Suitable for DL experiments with GPU" accelerator: "GPU" @@ -298,7 +306,7 @@ custom: - strix-halo resourceType: "notebook" Course-LLM: - group: "COURSE" + group: "TEACHING LABS" description: "Large Language Models Course" subDescription: "Suitable for LLM experiments with GPU" accelerator: "GPU" @@ -306,7 +314,7 @@ custom: - strix-halo resourceType: "notebook" Course-PhySim: - group: "COURSE" + group: "TEACHING LABS" description: "Genesis Physical Simulation Course" subDescription: "Suitable for physical simulation experiments with GPU" accelerator: "GPU" From a2dc970bccae2e1ef7adcf5f061491195f99d04b Mon Sep 17 00:00:00 2001 From: ShifZhan <252984256+MioYuuIH@users.noreply.github.com> Date: Thu, 18 Jun 2026 12:32:44 +0800 Subject: [PATCH 04/48] chore: update config --- runtime/values.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/runtime/values.yaml b/runtime/values.yaml index ea76d624..e2aab44e 100644 --- a/runtime/values.yaml +++ b/runtime/values.yaml @@ -311,7 +311,7 @@ custom: resourceType: "notebook" code-cpu: group: "DEVELOPMENT ENVIRONMENT" - description: "VSCode Server - CPU Environment" + description: "VSCode Server CPU" subDescription: "CPU-only development workspace" accelerator: "" acceleratorKeys: [] @@ -329,7 +329,7 @@ custom: resourceType: "notebook" code-gpu: group: "DEVELOPMENT ENVIRONMENT" - description: "VSCode Server - GPU Environment" + description: "VSCode Server GPU" subDescription: "GPU-accelerated development workspace" accelerator: "GPU" acceleratorKeys: From 868d6dbb837fa4572d93acb22c6ae80c2ac51d90 Mon Sep 17 00:00:00 2001 From: Mario Ruiz Date: Thu, 18 Jun 2026 12:51:31 +0100 Subject: [PATCH 05/48] Allow for a custom cluster name --- runtime/chart/values.yaml | 4 ++++ runtime/hub/core/config.py | 9 +++++++++ runtime/hub/core/handlers.py | 10 +++++++--- runtime/hub/core/setup.py | 3 +++ runtime/hub/frontend/apps/admin/src/App.tsx | 10 ++++++++-- runtime/hub/frontend/apps/home/src/App.tsx | 11 +++++++++-- runtime/hub/frontend/apps/spawn/src/App.tsx | 9 +++++++-- runtime/hub/frontend/templates/admin.html | 2 +- runtime/hub/frontend/templates/home.html | 2 +- runtime/hub/frontend/templates/login.html | 6 +++--- runtime/hub/frontend/templates/page.html | 10 +++++----- runtime/values-multi-nodes.yaml.example | 4 ++++ runtime/values.yaml | 4 ++++ 13 files changed, 65 insertions(+), 19 deletions(-) diff --git a/runtime/chart/values.yaml b/runtime/chart/values.yaml index 2e0a07ff..412e6bc3 100644 --- a/runtime/chart/values.yaml +++ b/runtime/chart/values.yaml @@ -38,6 +38,10 @@ custom: # - multi: GitHub App + Local accounts authMode: "auto-login" + # Cluster display name (optional). Appended to "AUP Learning Cloud" in the UI. + # Example: "City/University" → "AUP Learning Cloud City/University" + clusterName: "" + # Auto-create admin user on first install (optional) adminUser: enabled: false diff --git a/runtime/hub/core/config.py b/runtime/hub/core/config.py index 469d5de3..121fce4e 100644 --- a/runtime/hub/core/config.py +++ b/runtime/hub/core/config.py @@ -231,6 +231,7 @@ def __init__(self): self.auth_mode: str = "auto-login" self.single_node_mode: bool = False self.github_org_name: str = "" + self.cluster_name: str = "" self.quota_enabled: bool = False # Parsed configuration @@ -268,6 +269,7 @@ def init(cls, config_path: str | Path) -> HubConfig: # Extract runtime settings instance.auth_mode = raw_config.get("authMode", "auto-login") instance.github_org_name = raw_config.get("githubOrgName", "") + instance.cluster_name = raw_config.get("clusterName", "") # Single-node mode: from config or auto-enable for auto-login single_node_mode = raw_config.get("singleNodeMode") @@ -331,6 +333,13 @@ def is_initialized(cls) -> bool: # Convenience Properties # ========================================================================= + @property + def platform_display_name(self) -> str: + base = "AUP Learning Cloud" + if self.cluster_name: + return f"{base} {self.cluster_name}" + return base + @property def resources(self) -> ResourcesConfig: """Get resources configuration.""" diff --git a/runtime/hub/core/handlers.py b/runtime/hub/core/handlers.py index 483433de..14978cb4 100644 --- a/runtime/hub/core/handlers.py +++ b/runtime/hub/core/handlers.py @@ -73,6 +73,7 @@ "default_quota": 0, "team_resource_mapping": {}, "auth_mode": "auto-login", + "platform_name": "AUP Learning Cloud", } @@ -121,6 +122,7 @@ def configure_handlers( team_resource_mapping: dict[str, list[str]] | None = None, github_org: str = "", auth_mode: str = "auto-login", + platform_name: str = "AUP Learning Cloud", ) -> None: """Configure handler module with runtime settings.""" if accelerator_options is not None: @@ -134,6 +136,7 @@ def configure_handlers( _handler_config["team_resource_mapping"] = team_resource_mapping _handler_config["github_org"] = github_org _handler_config["auth_mode"] = auth_mode + _handler_config["platform_name"] = platform_name # ============================================================================= @@ -1313,14 +1316,15 @@ class PlatformInfoHandler(APIHandler): """ async def get(self): + name = _handler_config.get("platform_name", "AUP Learning Cloud") self.set_header("Content-Type", "application/json") - self.set_header("X-Powered-By", "AUP Learning Cloud") + self.set_header("X-Powered-By", name) self.finish( json.dumps( { - "platform": "AUP Learning Cloud", + "platform": name, "vendor": "Advanced Micro Devices, Inc.", - "powered_by": "AUP Learning Cloud", + "powered_by": name, "website": "https://github.com/AMDResearch/aup-learning-cloud", } ) diff --git a/runtime/hub/core/setup.py b/runtime/hub/core/setup.py index 84d395ee..34e5316e 100644 --- a/runtime/hub/core/setup.py +++ b/runtime/hub/core/setup.py @@ -202,6 +202,7 @@ async def auth_state_hook(spawner, auth_state): team_resource_mapping=dict(config.teams.mapping), github_org=config.github_org_name, auth_mode=config.auth_mode, + platform_name=config.platform_display_name, ) if not hasattr(c.JupyterHub, "extra_handlers") or c.JupyterHub.extra_handlers is None: @@ -381,6 +382,8 @@ async def delete(self, group_name): c.JupyterHub.template_vars = {} c.JupyterHub.template_vars["authenticator_mode"] = config.auth_mode # type: ignore[assignment] c.JupyterHub.template_vars["hide_logout"] = config.auth_mode == "auto-login" # type: ignore[assignment] + c.JupyterHub.template_vars["cluster_name"] = config.cluster_name # type: ignore[assignment] + c.JupyterHub.template_vars["platform_name"] = config.platform_display_name # type: ignore[assignment] print(f"[SETUP] Hub setup complete: auth_mode={config.auth_mode}") print(f"[SETUP] template_vars: {c.JupyterHub.template_vars}") diff --git a/runtime/hub/frontend/apps/admin/src/App.tsx b/runtime/hub/frontend/apps/admin/src/App.tsx index 30f77ea5..3bf00751 100644 --- a/runtime/hub/frontend/apps/admin/src/App.tsx +++ b/runtime/hub/frontend/apps/admin/src/App.tsx @@ -22,7 +22,8 @@ import { UserList } from './pages/UserList'; import { GroupList } from './pages/GroupList'; import { Dashboard } from './pages/Dashboard'; import { NavBar } from './components/NavBar'; -import { PLATFORM_NAME } from '@auplc/shared'; +import { useState, useEffect } from 'react'; +import { PLATFORM_NAME, fetchPlatformInfo } from '@auplc/shared'; function App() { @@ -30,9 +31,14 @@ function App() { const baseUrl = (jhdata.base_url || '/hub/').replace(/\/+$/, ''); const basePath = `${baseUrl}/admin`; + const [platformName, setPlatformName] = useState(PLATFORM_NAME); + useEffect(() => { + fetchPlatformInfo().then(info => setPlatformName(info.platform)).catch(() => {}); + }, []); + return ( -
+
} /> diff --git a/runtime/hub/frontend/apps/home/src/App.tsx b/runtime/hub/frontend/apps/home/src/App.tsx index f9e9d121..bae15914 100644 --- a/runtime/hub/frontend/apps/home/src/App.tsx +++ b/runtime/hub/frontend/apps/home/src/App.tsx @@ -27,6 +27,7 @@ import { getResourceType, getResourceTypeLabel, PLATFORM_NAME, + fetchPlatformInfo, } from "@auplc/shared"; import onboardingLaunchWorkspaceUrl from "./onboarding-launch-workspace.png"; import onboardingResourcePickerUrl from "./onboarding-resource-picker.png"; @@ -193,6 +194,8 @@ function App() { const [showOnboardingModal, setShowOnboardingModal] = useState(false); const [onboardingStep, setOnboardingStep] = useState(0); + const [platformName, setPlatformName] = useState(PLATFORM_NAME); + const [theme, setTheme] = useState(getInitialTheme); const toggleTheme = useCallback(() => { setTheme(t => { @@ -202,6 +205,10 @@ function App() { }); }, []); + useEffect(() => { + fetchPlatformInfo().then(info => setPlatformName(info.platform)).catch(() => {}); + }, []); + useEffect(() => { getMyQuota().then(setQuota).catch(() => {}); }, []); @@ -457,7 +464,7 @@ function App() { {getGreeting()}, {jhdata.user ?? "student"}

- Welcome to {PLATFORM_NAME} + Welcome to {platformName}

Experience next-generation AI acceleration with AMD ROCm. Launch @@ -874,7 +881,7 @@ function App() {

Welcome -

Welcome to {PLATFORM_NAME}

+

Welcome to {platformName}

This short guide will show you how to get started, where to launch your environment, and where to find AMD developer resources later. diff --git a/runtime/hub/frontend/apps/spawn/src/App.tsx b/runtime/hub/frontend/apps/spawn/src/App.tsx index 8d9556b4..c2e5435f 100644 --- a/runtime/hub/frontend/apps/spawn/src/App.tsx +++ b/runtime/hub/frontend/apps/spawn/src/App.tsx @@ -19,7 +19,7 @@ import { useState, useMemo, useCallback, useEffect, useRef } from 'react'; import type { Resource, Accelerator, GitHubRepo } from '@auplc/shared'; -import { validateRepo, fetchGitHubRepos, isCurrentUserGitHub, PLATFORM_NAME } from '@auplc/shared'; +import { validateRepo, fetchGitHubRepos, isCurrentUserGitHub, PLATFORM_NAME, fetchPlatformInfo } from '@auplc/shared'; type Theme = 'light' | 'dark'; function getInitialTheme(): Theme { @@ -91,6 +91,7 @@ function App() { const [expandedGroup, setExpandedGroup] = useState(null); const [runtime, setRuntime] = useState(20); const [runtimeInput, setRuntimeInput] = useState('20'); + const [platformName, setPlatformName] = useState(PLATFORM_NAME); const [repoUrl, setRepoUrl] = useState(initialRepoUrl); const [repoUrlError, setRepoUrlError] = useState(''); const [repoValidating, setRepoValidating] = useState(false); @@ -117,6 +118,10 @@ function App() { const loading = resourcesLoading || acceleratorsLoading || quotaLoading; + useEffect(() => { + fetchPlatformInfo().then(info => setPlatformName(info.platform)).catch(() => {}); + }, []); + useEffect(() => { if (!initialRepoUrl || allowedGitProviders.length === 0) return; const { url } = normalizeRepoUrl(initialRepoUrl); @@ -351,7 +356,7 @@ function App() {

Launch Your Server

-

Select a resource, configure your environment, and launch on {PLATFORM_NAME}

+

Select a resource, configure your environment, and launch on {platformName}

{/* Warnings */} diff --git a/runtime/hub/frontend/templates/admin.html b/runtime/hub/frontend/templates/admin.html index 6922f1a3..31342b84 100644 --- a/runtime/hub/frontend/templates/admin.html +++ b/runtime/hub/frontend/templates/admin.html @@ -30,5 +30,5 @@
{% endblock main %} {% block footer %} - + {% endblock footer %} diff --git a/runtime/hub/frontend/templates/home.html b/runtime/hub/frontend/templates/home.html index 36f4bb0c..54db7732 100644 --- a/runtime/hub/frontend/templates/home.html +++ b/runtime/hub/frontend/templates/home.html @@ -24,7 +24,7 @@ {% set announcement = announcement_home %} {% endif %} -{%- block title -%}Home - AUP Learning Cloud{%- endblock title -%} +{%- block title -%}Home - {{ platform_name or 'AUP Learning Cloud' }}{%- endblock title -%} {% block stylesheet %} {{ super() }} diff --git a/runtime/hub/frontend/templates/login.html b/runtime/hub/frontend/templates/login.html index b342ef70..ef3ef647 100755 --- a/runtime/hub/frontend/templates/login.html +++ b/runtime/hub/frontend/templates/login.html @@ -32,7 +32,7 @@ {% endblock login_widget %} {%- block title -%} -AUP Learning Cloud +{{ platform_name or 'AUP Learning Cloud' }} {%- endblock title -%} {% block stylesheet %} @@ -88,7 +88,7 @@ -

AUP Learning Cloud

+

{{ platform_name or 'AUP Learning Cloud' }}

Experience the next generation of AI acceleration with AMD ROCm™.

{% if login_service %} AUP Learning Cloud
-

Login to AUP Learning Cloud

+

Login to {{ platform_name or 'AUP Learning Cloud' }}

{% if authenticator_mode == 'dummy' %}

⚠️ Development Mode - Any username/password accepted

{% endif %} diff --git a/runtime/hub/frontend/templates/page.html b/runtime/hub/frontend/templates/page.html index f41961ac..6f186605 100755 --- a/runtime/hub/frontend/templates/page.html +++ b/runtime/hub/frontend/templates/page.html @@ -58,7 +58,7 @@ {%- block title -%} - AUP Learning Cloud + {{ platform_name or 'AUP Learning Cloud' }} {%- endblock title -%} @@ -275,15 +275,15 @@ {% endblock require_config %} {# djlint: on #} {% block meta %} - + - + {% endblock meta %}
-
+
{% block login_container %} - + -
+
-

Login to AUP Learning Cloud

+

Login to AUP Learning Cloud

{% if authenticator_mode == 'dummy' %} -

⚠️ Development Mode - Any username/password accepted

+

⚠️ Development Mode - Any username/password accepted

{% endif %}
{% if login_error %} -

{{ login_error }}

+

{{ login_error }}

{% endif %} {% if authenticator_mode == 'dummy' %} @@ -139,21 +144,21 @@

Login to AUP Learning Cloud

- + + class="block w-full pl-3 pr-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 placeholder-gray-400 dark:placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500" />
- + + class="block w-full pl-3 pr-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 placeholder-gray-400 dark:placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500" />
@@ -167,12 +172,13 @@

Login to AUP Learning Cloud

Form POST actions DO need urlencode due to different browser/server handling. --> {% else %} @@ -181,20 +187,21 @@

Login to AUP Learning Cloud

-
+
- Or use local account + Or use local account
@@ -203,21 +210,21 @@

Login to AUP Learning Cloud

- + + class="block w-full pl-3 pr-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 placeholder-gray-400 dark:placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500" />
- + + class="block w-full pl-3 pr-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 placeholder-gray-400 dark:placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500" />
From 577ae71e8551ea11b8a7999759784218b34f6302 Mon Sep 17 00:00:00 2001 From: ShifZhan <252984256+MioYuuIH@users.noreply.github.com> Date: Wed, 24 Jun 2026 11:38:39 +0800 Subject: [PATCH 15/48] fix(hub): align login dark theme --- .../frontend/packages/login-css/src/login.css | 140 +++++++++++++++++- runtime/hub/frontend/templates/login.html | 57 +++---- runtime/values.yaml | 7 +- 3 files changed, 176 insertions(+), 28 deletions(-) diff --git a/runtime/hub/frontend/packages/login-css/src/login.css b/runtime/hub/frontend/packages/login-css/src/login.css index 4094a80a..355780d9 100644 --- a/runtime/hub/frontend/packages/login-css/src/login.css +++ b/runtime/hub/frontend/packages/login-css/src/login.css @@ -40,5 +40,143 @@ * small login bundle doesn't need. */ @import "tailwindcss" source(none); -@custom-variant dark (&:where([data-bs-theme="dark"], [data-bs-theme="dark"] *)); @source "../../../templates/**/*.html"; + +@layer components { + .login-main-panel { + background: #f9fafb; + } + + .login-card { + background: #ffffff; + border: 1px solid transparent; + } + + .login-heading { + color: #1f2937; + } + + .login-announcement { + background: #eff6ff; + border: 1px solid #bfdbfe; + color: #1e3a8a; + } + + .login-error { + color: #ef4444; + } + + .login-dev-mode { + color: #ea580c; + } + + .login-github-button, + .login-input { + background: #ffffff; + border: 1px solid #d1d5db; + color: #374151; + } + + .login-github-button:hover { + background: #f9fafb; + } + + .login-helper { + color: #4b5563; + } + + .login-field-label { + color: #374151; + } + + .login-input { + color: #111827; + } + + .login-input::placeholder { + color: #9ca3af; + } + + .login-submit { + background: #2563eb; + } + + .login-submit:hover { + background: #1d4ed8; + } + + .login-divider .border-t { + border-color: #d1d5db; + } + + .login-divider span { + background: #ffffff; + color: #6b7280; + } + + [data-bs-theme="dark"] .login-main-panel { + background: #030712 !important; + } + + [data-bs-theme="dark"] .login-card { + background: #111827 !important; + border-color: #374151 !important; + box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.4) !important; + } + + [data-bs-theme="dark"] .login-heading { + color: #f9fafb !important; + } + + [data-bs-theme="dark"] .login-announcement { + background: #172554 !important; + border-color: #1e40af !important; + color: #dbeafe !important; + } + + [data-bs-theme="dark"] .login-error { + color: #fca5a5 !important; + } + + [data-bs-theme="dark"] .login-dev-mode { + color: #fdba74 !important; + } + + [data-bs-theme="dark"] .login-github-button, + [data-bs-theme="dark"] .login-input { + background: #1f2937 !important; + border-color: #4b5563 !important; + color: #f9fafb !important; + } + + [data-bs-theme="dark"] .login-github-button:hover { + background: #374151 !important; + } + + [data-bs-theme="dark"] .login-helper, + [data-bs-theme="dark"] .login-divider span { + color: #d1d5db !important; + } + + [data-bs-theme="dark"] .login-field-label { + color: #e5e7eb !important; + } + + [data-bs-theme="dark"] .login-input::placeholder { + color: #9ca3af !important; + } + + [data-bs-theme="dark"] .login-divider .border-t { + border-color: #374151 !important; + } + + [data-bs-theme="dark"] .login-divider span { + background: #111827 !important; + } + + [data-bs-theme="dark"] .login-submit:focus, + [data-bs-theme="dark"] .login-github-button:focus, + [data-bs-theme="dark"] .login-input:focus { + --tw-ring-offset-color: #111827; + } +} diff --git a/runtime/hub/frontend/templates/login.html b/runtime/hub/frontend/templates/login.html index eb2c834d..3a06870a 100755 --- a/runtime/hub/frontend/templates/login.html +++ b/runtime/hub/frontend/templates/login.html @@ -27,6 +27,7 @@ {% if announcement_login is string %} {% set announcement = announcement_login %} {% endif %} +{% set github_helper_text = login_github_helper_text|default("", true)|trim %} {% block login_widget %} {% endblock login_widget %} @@ -96,16 +97,16 @@

AUP Learning Cloud Sign in with {{ login_service }} - {% if 'github' in login_service|lower %} -

Start a free 2-hour trial with GitHub sign-in.

+ {% if 'github' in login_service|lower and github_helper_text %} + {% endif %} {% endif %}

-
+