Hub web interface¶
This page describes the browser-facing Hub: its pages, their access rules, their behaviour, and how they use the Hub API. API routes, authorization, and the server side of administration actions are in 08-hub-api-and-administration; branding and configurable labels are in 16-platform-configuration-and-branding.
This document uses these path shortcuts:
hub/.../ishub/src/ecmwf/sites/hub/.core/.../iscore/src/ecmwf/sites/core/.
The server renders all pages with Flask templates. The scripts in
hub/.../static/js/ add behaviour on top of the rendered HTML. The page
views are in hub/.../app/hub/views.py, the administration views in
hub/.../app/admin/views.py, and the legacy-URL views in
hub/.../app/redirects/views.py.
Blueprints and access levels¶
hub/.../server.py registers these blueprints:
| Blueprint | URL prefix | Content |
|---|---|---|
hub |
/hub |
Landing, lists, create fragment, Site view, per-Site spec, governance, about, error pages |
admin |
/hub/admin |
Platform administration pages |
api_v1, api_v2 |
/hub/api/v1/, /hub/api/v2/ |
Hub APIs (see 12) |
auth |
/auth |
/auth/login/ and /auth/logout/ (core/.../auth/views.py) |
redirects |
/ |
Legacy URLs and favicons |
The pages use these access levels:
| Level | Check | Who |
|---|---|---|
| Anonymous | @oidc.optional_login |
Any visitor (landing, about, error pages) |
| Logged in | @oidc.require_login |
Any user with a Hub session |
| Staff | auth_utils.is_current_user_staff_or_raise() |
Users in the configured staff users/groups; platform administrators are implicitly staff |
| Platform administrator | auth_utils.is_current_user_admin_or_raise() |
Users in the configured administrator users/groups |
| Site administrator | site.get_access_management().is_current_user_admin |
Users and groups in the Site's administrator lists |
Pages and routes¶
| Page | Route | Template | Access |
|---|---|---|---|
| Landing | /hub/ |
hub/index.html |
Anonymous |
| My Sites | /hub/list/ |
hub/list.html |
Logged in |
| All Sites | /hub/list/all/ |
hub/list.html |
Logged in |
| List table fragment | /hub/list/table/, /hub/list/all/table/ (GET, POST) |
hub/table.html |
Logged in |
| Site view | /hub/view/<space>/<site>/ |
hub/view.html |
Logged in; management content needs the Site administrator role |
| View fragments | /hub/view/<space>/<site>/details/, …/sharing/, …/settings/, …/actions/ |
hub/view-tab-*.html, hub/view-actions.html |
Site administrator |
| Site API specification | /hub/spec/<space>/<site>/ and …/swagger.json |
hub/spec.html |
Site administrator |
| Create form fragment | /hub/create/ (GET) |
hub/create.html (fragment) |
Staff |
| Governance | /hub/governance/ |
hub/governance.html |
Staff; an anonymous caller is sent to the login first |
| About | /hub/about/ |
about.html |
Anonymous |
| Error pages | /hub/error/page/<status_code>/ |
see Page shell and navigation | Anonymous |
| Administration | /hub/admin/ and sub-pages |
admin/*.html |
Platform administrator |
| Metrics exposition | /hub/metrics/ |
— (Prometheus text) | Not a page; returns 503 when the metrics integration is inactive |
The redirects blueprint keeps old URLs working: / and /about/ and
/list/, /list/all/, /view/<space>/<site>/, /edit/<space>/<site>/,
/spec/<space>/<site>/, and /error/page/<code>/ redirect to the current
hub routes. /edit/ maps to the Site view because editing is now in-place
on that page. The same blueprint serves /favicon.ico (redirect) and
/favicon.svg (the branded SVG, cached 24 hours).
Page shell and navigation¶
Pages extend a template chain: ecmwf-template.html (header, footer, asset
bundles) → sites-template.html (flash-message rendering) →
hub-template.html (the Hub navigation bar).
- The base template loads jQuery, jQuery UI, Bootstrap, toastr, Bootstrap
Icons, Chart.js, and TomSelect (JS and CSS) from the Hub origin
(
static/vendor). The image build installs these packages from the npm lockfile inhub/frontend(see 06 — Security). No page loads files from a CDN. The Hub sends the vendor files unchanged; the response minifier skipsstatic/vendor. The Hub Content Security Policy (CSP) allows scripts, styles, and fonts only from'self'. The API specification pages load Swagger UI from the same directory, with the online validator badge off (validatorUrl: null). The base template bundles the Hub scripts throughwebassets(hub/.../assets.py):static_js(inplace, autocomplete, utilities, admin-pages, dashboards, notifications, modal-utils),wizard_js, andsite-view-content-refresher_js. - Every HTML page carries the session cross-site request forgery (CSRF) token in a
<meta name="csrf-token">tag; the server-side rule is in 08 — Authorization. - The header shows the branded logo and title, a Help menu built from the
configured
branding.help_links, and a user menu (role, email, an Account link to the provideruserinfoURL, and Log out). Anonymous visitors see a Log in link to/auth/login/. The footer shows the configuredbranding.footer_links. See 16. - The Hub navigation bar shows My Sites (
/hub/list/), All Sites (/hub/list/all/), Create (staff only; opens the create modal, see Create site), Administration (platform administrators only;/hub/admin/), and About. The labels are configurable (core/.../config/labels.py). sites-template.htmlrenders flashed messages as toastr toast notifications through$.notify(category, message), not as inline banners.- Error statuses map to templates through
TEMPLATE_BY_ERROR(core/.../misc/error_utils.py):400,403,404,405,410,500,502,503,504, andgeneric-error.html. The 410 page is the target for routes of disabled Sites (14-routing).
Other pages¶
- Landing (
/hub/): a branded intro with "get started" cards (create a Site for staff, browse all Sites, support). Anonymous visitors can open it; the create card appears only for staff. - About (
/hub/about/): support, documentation, terms, and governance links from the branding configuration (staff reach the governance page here), and a link to the Hub API specification page (/hub/api/v2/spec/, Swagger UI). - Governance (
/hub/governance/): the platform governance statement with the configured policy and terms links; staff only. - Login / logout:
/auth/login/starts the OpenID Connect (OIDC) flow;/auth/logout/ends the session (core/.../auth/views.py). There is no user profile page; the user menu links to the identity provider's account URL.
JavaScript behaviour layer¶
The pages stay server-rendered; static/js/ adds behaviour on top. Scripts
are packaged through webassets (hub/.../assets.py). The image build runs
python -m ecmwf.sites.hub.assets, which writes the bundles to static/gen/.
The Hub root filesystem is read-only at runtime, so the Hub keeps the webassets
cache in /tmp/webassets-cache and does not write to its package directory.
The Hub creates this directory when it starts, because /tmp is an empty
volume and webassets does not create a configured cache directory.
| Script | Behaviour |
|---|---|
wizard.js |
$.modalCreate(): loads the create form fragment into a modal, re-opens it on template change, posts the form to the Hub API, and shows success/error feedback. $.wizard(): Site view section switching with the URL hash. |
inplace.js |
Generic in-place editing: forms and action buttons declare data-endpoint, data-method, and data-refresh-page attributes; the script collects the fields and calls the Hub API (usually PATCH /hub/api/v2/sites/<space>/<site>/…) and shows inline success or error feedback. |
site-view-content-refresher.js |
$.refreshContent(): the Site view poller described in Content refresher. |
autocomplete.js |
User, group, and application pickers backed by /hub/api/v2/users/?q=, /hub/api/v2/groups/?q=, and /hub/api/v2/sites/applications/?q=. |
utilities.js |
Shared helpers: $.lazyLoadSites() (list table fragment), $.getCall/$.postCall/$.deleteCall API wrappers, $.showErrors (field marking from [field] message tokens), $.getLogs, weekly/monthly analytics report loaders, and a jQuery prefilter that adds the X-CSRF-Token header (from the base-template meta tag) to every non-GET request. |
notifications.js |
Toast messages for action results ($.notify), with linkified messages. |
modal-utils.js |
Shared modal dialogs for the in-place setting editors. |
admin-pages.js |
initAdminActions(): the declarative data-admin-action handlers on the administration pages. |
dashboards.js |
Chart.js chart builders (stacked bar, horizontal bar, doughnut) for the dashboards. |
Behaviour requirements¶
| ID | Requirement | Implemented in | Verified by |
|---|---|---|---|
| HUI-01 | The create modal loads a saved Site template into the create form through GET /hub/create/?template=; changing the template re-opens the modal with the template applied. |
hub/.../static/js/wizard.js, hub/.../app/hub/views.py |
core/tests/test_site_templates.py (template service), core/tests/test_add_edit_site_form.py (template fill); the script itself is not tested |
| HUI-02 | Site templates come from two sources read on demand: the read-only platform ConfigMap mounted at /sites-templates/ (Helm value siteTemplates), then ad-hoc files under /sites-data/<namespace>/templates/. The platform source wins name collisions, names are validated, and a broken file is skipped without affecting other templates. |
core/.../service/site_templates.py |
core/tests/test_site_templates.py, hub/tests/test_site_templates_api.py |
| HUI-03 | In-place edits and row actions call the Hub API from data-endpoint/data-method attributes instead of full-page form posts. |
hub/.../static/js/inplace.js |
— |
| HUI-04 | The Site view refreshes status and health without a reload from the status endpoint. | hub/.../static/js/site-view-content-refresher.js |
— |
| HUI-05 | The settings editor rewrites the live sites-config ConfigMap and, when the Master Token field holds a value, the HUB_MASTER_TOKEN secret; an empty field keeps the stored token. A save restarts the Hub Deployment. |
hub/.../app/admin/views.py, core/.../form/forms.py (apply_master_token) |
core/tests/test_hub_settings_config.py |
| HUI-06 | Platform-wide messages persist in the Redis cache and render as toast notifications on Hub pages. | hub/.../app/admin/views.py, core/.../service/message.py |
— |
| HUI-07 | Administration dashboards render client-side Chart.js charts from JSON data objects that the admin views provide. | hub/.../static/js/dashboards.js, hub/.../app/admin/dashboards/utils.py |
hub/tests/test_branding_rendering.py (chart data is JSON-encoded) |
| HUI-08 | HTML form pages carry the session CSRF token as a meta tag and a hidden csrf_token input; every jQuery request adds the X-CSRF-Token header. |
hub/.../templates/ecmwf-template.html, hub/.../static/js/utilities.js |
hub/tests/test_csrf.py (server-side enforcement) |
| HUI-09 | /hub/list/ lists the Sites owned by the logged-in user (owner-label match); /hub/list/all/ lists all Sites. |
hub/.../app/hub/views.py, core/.../service/sites.py (get_my_sites) |
hub/tests/test_sites_service.py (list pre-processing; the owner filter itself is not asserted) |
| HUI-10 | The list pages fetch the table from the sibling table/ fragment endpoint and re-submit search, sort, and pagination changes through AJAX; only the fragment re-renders. |
hub/.../templates/hub/list.html, hub/table.html, hub/.../static/js/utilities.js ($.lazyLoadSites) |
— |
| HUI-11 | The list search matches Site ID, owner, space, name, type, and description; sorting supports the four sort fields; the page size is hub.pagination_max_items (default 15). |
core/.../form/forms.py (SiteSearchPaginationForm.filter_sites) |
core/tests/test_add_edit_site_form.py (test_filter_sites, test_pagination_logic) |
| HUI-12 | The list table shows Name, Owner, Retention Date, and URL to every logged-in user; Creation Date and the Upgrade actions appear only for platform administrators; archived and retention-expired badges appear on rows. | hub/.../templates/hub/table.html |
— |
| HUI-13 | The create form fragment requires staff; in read-only mode the Hub redirects the request to My Sites. | hub/.../app/hub/views.py (create) |
— |
| HUI-14 | The create modal posts the serialized form to POST /hub/api/v2/sites/; on success it redirects to the Site view after two seconds; on error it marks each field named as [field] in the API message. |
hub/.../static/js/wizard.js, hub/.../static/js/utilities.js ($.showErrors), hub/.../app/api/request_models.py |
hub/tests/test_api_request_validation.py (the API validation path; the script itself is not tested) |
| HUI-15 | Site creation and edit input must pass the AddEditSiteForm rules: space and name length and character sets, quota range and increase-only rule, retention date cap of one year for non-administrators, access users or groups for private Sites, custom-image registry and public-site rules, and strict formats for custom errors, no-cache extensions, and CORS domains. |
core/.../form/forms.py (AddEditSiteForm.validate) |
core/tests/test_add_edit_site_form.py, core/tests/test_form_fixes.py, hub/tests/test_edit_site_reverted.py (public-to-private revert message) |
| HUI-16 | The create form fixes owner, type, monitoring, registered-by/date, and resource limits for non-administrators, and defaults retention to today plus 365 days. | core/.../form/forms.py (_protect_form_fields, _default_non_admin_fields) |
core/tests/test_add_edit_site_form.py (pre-initialize as admin and non-admin) |
| HUI-17 | Any logged-in user can open the Site view; users without the Site administrator role see the Overview section read-only, and the details, sharing, settings, and actions fragments refuse them. | hub/.../app/hub/views.py, hub/.../templates/hub/view.html |
— |
| HUI-18 | The Overview section edits owner, space, name, type, quota, retention date, and description in place through the Site PATCH endpoints of the Hub API; the edit controls appear per role. | hub/.../templates/hub/view-tab-details.html, hub/.../static/js/inplace.js |
— |
| HUI-19 | Publish and storage request buttons appear only when the notification provider is enabled, and post through requests/publish/ and requests/storage/. |
hub/.../server.py (context flag), hub/.../templates/hub/view-tab-details.html, hub/.../app/api/ |
core/tests/test_requests_service.py (the request services; the modals are not tested) |
| HUI-20 | The Extend action sets the Site retention date to one year from today (PATCH …/retention-date/, extend_retention_date_site). |
hub/.../templates/hub/view-tab-details.html, hub/.../app/api/common.py |
— |
| HUI-21 | The Actions menu offers Archive/Enable and Delete to Site administrators, Restart when enabled, Upgrade when enabled and not up to date, Force Upgrade to platform administrators (enabled or archived), and Request Access to logged-in users without access; each action confirms first. | hub/.../app/hub/actions.py, hub/.../templates/hub/view-actions.html |
hub/tests/test_sites_upgrade.py (the upgrade API); the menu builder is not tested |
| HUI-22 | For Site administrators the Site view polls the status endpoint every 15 seconds, pauses while the tab is hidden, and re-fetches the details, settings, sharing, actions, and conditions fragments when status, enabled state, or the last transition changes. | hub/.../static/js/site-view-content-refresher.js |
— |
| HUI-23 | The health payload updates the health cards, the storage bar and badges at the 50%, 80%, and 90% thresholds, the quota badge, and the retention-expired banner; a failed request marks the health cards Unknown. | hub/.../static/js/site-view-content-refresher.js |
— |
| HUI-24 | The Operations section shows Site conditions and a logs console that requests GET …/logs/?name=&limit= for the selected application. |
hub/.../templates/hub/view-tab-system.html, hub/.../static/js/utilities.js ($.getLogs) |
— |
| HUI-25 | The Analytics section and its weekly/monthly report buttons appear only when the analytics integration is active; archived Sites have no reports. | hub/.../templates/hub/view.html, hub/view-tab-analytics.html, hub/.../static/js/utilities.js |
— |
| HUI-26 | The Configuration section manages the master token, HTTP access tokens (create, history with revoke and JSON export, revoke), signed URLs, and session URLs through the Hub API endpoints. | hub/.../templates/hub/view-tab-settings.html, hub/.../static/js/inplace.js, modal-utils.js |
— |
| HUI-27 | The Access section edits administrator and access users and groups with on-demand pickers backed by the users, groups, and applications search endpoints. | hub/.../templates/hub/view-tab-share.html, hub/.../static/js/autocomplete.js |
— |
| HUI-28 | The per-Site API specification page renders the Site OpenAPI document from the site-api-spec.yaml template with Site, domain, and branding values, cached in Redis, for Site administrators. |
hub/.../app/hub/views.py (_load_site_open_api_template) |
— |
| HUI-29 | Every /hub/admin/ page requires a logged-in platform administrator. |
hub/.../app/admin/views.py |
— |
| HUI-30 | The administration index performs Clear cache, the read-only toggle, and Upgrade all, Restart all, and Force Upgrade all through declarative data-admin-action handlers with confirmation where destructive. |
hub/.../templates/admin/index.html, hub/.../static/js/admin-pages.js |
— |
| HUI-31 | Administrators add a typed global message and delete all messages from the Messages page. | hub/.../app/admin/views.py (add_message), core/.../form/forms.py (SitesGlobalMessageForm) |
— |
| HUI-32 | The Backup/restore page restores selected Sites or a full restore from a dated backup file, continues past per-Site failures, and clears the admin message and Sites caches on success. | hub/.../app/admin/views.py (backup_restore) |
core/tests/test_backups.py (backup files and service; the page is not tested) |
| HUI-33 | The Storage-management page deletes the selected Released PersistentVolumes and writes an audit entry per volume. |
hub/.../app/admin/views.py (storage_management) |
— |
| HUI-34 | The Dependencies page shows version, package, configuration-consistency, and integration probe data, with secret configuration values replaced by *** in the YAML dump; probe refresh runs asynchronously behind a non-blocking lock. |
hub/.../app/admin/views.py (dependencies, _refresh_integrations_async), core/.../config/schema/models.py (redacted_dump) |
core/tests/test_integration_status.py (the status service), core/tests/test_config_schema.py (redaction) |
| HUI-35 | The navigation bar shows My Sites, All Sites, and About to logged-in users, Create to staff, and Administration to platform administrators; labels come from the configurable label set. | hub/.../templates/hub-template.html, core/.../config/labels.py |
— |
| HUI-36 | The Hub renders flashed messages as toast notifications. | hub/.../templates/sites-template.html, hub/.../static/js/notifications.js |
— |
| HUI-37 | The Hub serves a mapped template page for error statuses 400, 403, 404, 405, 410, 500, 502, 503, and 504, and a generic error template otherwise. | hub/.../app/hub/views.py (error), core/.../misc/error_utils.py |
hub/tests/test_branding_rendering.py (branding on error pages) |
| HUI-38 | Legacy URLs (/, /list/, /view/, /edit/, /spec/, /error/page/) redirect to the current Hub routes. |
hub/.../app/redirects/views.py |
— |