Skip to content

Commit

Permalink
Merge pull request #1856 from yuvipanda/closure
Browse files Browse the repository at this point in the history
Rewrite the frontend
  • Loading branch information
manics authored Jan 3, 2025
2 parents 57e3b3a + 8679ba5 commit b72cd88
Show file tree
Hide file tree
Showing 71 changed files with 2,038 additions and 2,367 deletions.
54 changes: 44 additions & 10 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,48 @@
module.exports = {
env: {
browser: true,
jquery: true,
node: true,
es6: true,
"jest/globals": true,
},
extends: ["eslint:recommended"],
ignorePatterns: ["**/dist"],
parser: "@babel/eslint-parser",
plugins: ["jest"],
rules: {},
es2021: true,
},
extends: ["eslint:recommended", "plugin:react/recommended"],
ignorePatterns: ["dist"],
overrides: [
{
env: {
node: true,
},
files: [".eslintrc.{js,cjs}"],
parserOptions: {
sourceType: "script",
},
},
{
files: ["**/*.test.js", "**/*.test.jsx"],
env: {
jest: true,
node: true,
},
},
],
parserOptions: {
ecmaVersion: "latest",
sourceType: "module",
},
plugins: ["react"],
rules: {
"react/react-in-jsx-scope": "off",
"react/jsx-uses-react": "off",
// Temporarily turn off prop-types
"react/prop-types": "off",
"no-unused-vars": ["error", { args: "after-used" }],
},
ignorePatterns: [
"jupyterhub_fancy_profiles/static/*.js",
"webpack.config.js",
"babel.config.js",
],
settings: {
react: {
version: "detect",
},
},
};
6 changes: 6 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,9 @@ jobs:
pip install --no-binary pycurl -r dev-requirements.txt -r helm-chart/images/binderhub/requirements.txt
pip install -e .
- name: Install Playwright browser
run: playwright install firefox

- name: Install JupyterHub chart for main tests
if: matrix.test == 'main'
run: |
Expand Down Expand Up @@ -434,6 +437,9 @@ jobs:
pip install ".[pycurl]" --no-binary pycurl
pip install -e ".[pycurl]" --no-binary pycurl
- name: Install Playwright browser
run: playwright install firefox

- name: Setup JupyterHub NPM dependencies
run: npm install -g configurable-http-proxy

Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ coverage.xml
*.py,cover
.hypothesis/
.pytest_cache/
coverage

# Translations
*.mo
Expand Down
5 changes: 4 additions & 1 deletion babel.config.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
{
"presets": ["@babel/preset-env"]
"presets": [
"@babel/preset-env",
["@babel/preset-react", { "runtime": "automatic" }]
]
}
56 changes: 43 additions & 13 deletions binderhub/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,15 @@
)
from traitlets.config import Application

from .base import AboutHandler, Custom404, VersionHandler
from .base import VersionHandler
from .build import BuildExecutor, KubernetesBuildExecutor, KubernetesCleaner
from .builder import BuildHandler
from .config import ConfigHandler
from .events import EventLog
from .handlers.repoproviders import RepoProvidersHandlers
from .health import HealthHandler, KubernetesHealthHandler
from .launcher import Launcher
from .log import log_request
from .main import LegacyRedirectHandler, MainHandler, ParameterizedMainHandler
from .main import LegacyRedirectHandler, RepoLaunchUIHandler, UIHandler
from .metrics import MetricsHandler
from .quota import KubernetesLaunchQuota, LaunchQuota
from .ratelimit import RateLimiter
Expand Down Expand Up @@ -107,6 +107,11 @@ def _log_level(self):
None,
allow_none=True,
help="""
..removed::
No longer supported. If you want to use Google Analytics, use :attr:`extra_footer_scripts`
to load JS from Google Analytics.
The Google Analytics code to use on the main page.
Note that we'll respect Do Not Track settings, despite the fact that GA does not.
Expand All @@ -118,6 +123,11 @@ def _log_level(self):
google_analytics_domain = Unicode(
"auto",
help="""
..removed::
No longer supported. If you want to use Google Analytics, use :attr:`extra_footer_scripts`
to load JS from Google Analytics.
The Google Analytics domain to use on the main page.
By default this is set to 'auto', which sets it up for current domain and all
Expand All @@ -126,6 +136,13 @@ def _log_level(self):
config=True,
)

@observe("google_analytics_domain", "google_analytics_code")
def _google_analytics_deprecation(self, change):
if change.new:
raise ValueError(
f"Setting {change.owner.__class__.__name__}.{change.name} is no longer supported. Use {change.owner.__class__.__name__}.extra_footer_scripts to load Google Analytics JS directly"
)

about_message = Unicode(
"",
help="""
Expand All @@ -149,6 +166,14 @@ def _log_level(self):
config=True,
)

default_opengraph_title = Unicode(
"The Binder Project",
help="""
The default opengraph title for pages that don't have a generated opengraph title.
""",
config=True,
)

extra_footer_scripts = Dict(
{},
help="""
Expand Down Expand Up @@ -785,7 +810,6 @@ def _template_path_default(self):
- /versions
- /build/([^/]+)/(.+)
- /health
- /_config
- /* -> shows a 404 page
""",
config=True,
Expand Down Expand Up @@ -913,6 +937,7 @@ def initialize(self, *args, **kwargs):
"log_function": log_request,
"image_prefix": self.image_prefix,
"debug": self.debug,
"default_opengraph_title": self.default_opengraph_title,
"launcher": self.launcher,
"ban_networks": self.ban_networks,
"build_pool": self.build_pool,
Expand All @@ -931,8 +956,6 @@ def initialize(self, *args, **kwargs):
"registry": registry,
"traitlets_config": self.config,
"traitlets_parent": self,
"google_analytics_code": self.google_analytics_code,
"google_analytics_domain": self.google_analytics_domain,
"about_message": self.about_message,
"banner_message": self.banner_message,
"extra_footer_scripts": self.extra_footer_scripts,
Expand Down Expand Up @@ -961,15 +984,23 @@ def initialize(self, *args, **kwargs):
(r"/versions", VersionHandler),
(r"/build/([^/]+)/(.+)", BuildHandler),
(r"/health", self.health_handler_class, {"hub_url": self.hub_url_local}),
(r"/_config", ConfigHandler),
(r"/api/repoproviders", RepoProvidersHandlers),
]
if not self.enable_api_only_mode:
# In API only mode the endpoints in the list below
# are unregistered as they don't make sense in a API only scenario
# are not registered since they are primarily about providing UI

for provider_id in self.repo_providers:
# Register launchable URLs for all our repo providers
# These render social previews, but otherwise redirect to UIHandler
handlers += [
(
rf"/v2/({provider_id})/(.+)",
RepoLaunchUIHandler,
{"repo_provider": self.repo_providers[provider_id]},
)
]
handlers += [
(r"/about", AboutHandler),
(r"/v2/([^/]+)/(.+)", ParameterizedMainHandler),
(r"/", MainHandler),
(r"/repo/([^/]+)/([^/]+)(/.*)?", LegacyRedirectHandler),
# for backward-compatible mybinder.org badge URLs
# /assets/images/badge.svg
Expand Down Expand Up @@ -1036,9 +1067,8 @@ def initialize(self, *args, **kwargs):
)
},
),
(r"/.*", UIHandler),
]
# This needs to be the last handler in the list, because it needs to match "everything else"
handlers.append((r".*", Custom404))
handlers = self.add_url_prefix(self.base_url, handlers)
if self.extra_static_path:
handlers.insert(
Expand Down
38 changes: 0 additions & 38 deletions binderhub/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import json
import urllib.parse
from http.client import responses

import jwt
from jupyterhub.services.auth import HubOAuth, HubOAuthenticated
Expand Down Expand Up @@ -204,47 +203,10 @@ def extract_message(self, exc_info):
except Exception:
return ""

def write_error(self, status_code, **kwargs):
exc_info = kwargs.get("exc_info")
message = ""
status_message = responses.get(status_code, "Unknown HTTP Error")
if exc_info:
message = self.extract_message(exc_info)

self.render_template(
"error.html",
status_code=status_code,
status_message=status_message,
message=message,
)

def options(self, *args, **kwargs):
pass


class Custom404(BaseHandler):
"""Raise a 404 error, rendering the error.html template"""

def prepare(self):
raise web.HTTPError(404)


class AboutHandler(BaseHandler):
"""Serve the about page"""

async def get(self):
self.render_template(
"about.html",
base_url=self.settings["base_url"],
submit=False,
binder_version=binder_version,
message=self.settings["about_message"],
google_analytics_code=self.settings["google_analytics_code"],
google_analytics_domain=self.settings["google_analytics_domain"],
extra_footer_scripts=self.settings["extra_footer_scripts"],
)


class VersionHandler(BaseHandler):
"""Serve information about versions running"""

Expand Down
Empty file added binderhub/handlers/__init__.py
Empty file.
15 changes: 15 additions & 0 deletions binderhub/handlers/repoproviders.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import json

from ..base import BaseHandler


class RepoProvidersHandlers(BaseHandler):
"""Serve config"""

async def get(self):
config = [
repo_provider_class.display_config
for repo_provider_class in self.settings["repo_providers"].values()
]
self.set_header("Content-type", "application/json")
self.write(json.dumps(config))
Loading

0 comments on commit b72cd88

Please sign in to comment.