Site lists and site creation¶
The My Sites and All Sites pages, the table fragment, and the create-site modal. The Site view is in Site view; the API behind them is in 12-hub-api.
Site list pages¶
Routes and data sources¶
/hub/list/ lists My Sites: the Sites whose owner label matches the
logged-in username (sites_service.get_my_sites, an owner-label selector on
the Site Custom Resource Definition (CRD) list, core/.../service/sites.py). Sites shared with the user
as a Site administrator but owned by someone else appear on All Sites
(/hub/list/all/, sites_service.get_all_sites). One view
(list_sites) serves both pages; the table fragment endpoint
(list_my_table) selects the data source from the request path.
Table fragment and lazy loading¶
The list page is a shell. $.lazyLoadSites() (hub/.../static/js/utilities.js)
requests the sibling URL …/table/ and injects the rendered hub/table.html
fragment. Search, sort, and pagination changes re-submit the fragment form
through AJAX (interceptFormSubmission) and replace only the fragment. The
form carries hidden fields for the page window, sort field, and sort
direction, and a cross-site request forgery (CSRF) field.
Columns and badges¶
The table shows: Name (link to the Site view, with an archived badge
for disabled Sites and a retention expired badge for expired retention
dates), Owner, Retention Date, and URL (a public-site icon, a
custom-application/ecBox/repository icon, and a content link when the user
can access the Site; plain text otherwise). Platform administrators also
see a Creation Date column, and an Upgrade column when at least one
enabled Site in the list is not up to date. The Upgrade column has a
per-row upgrade button (POST /hub/api/v2/sites/<space>/<site>/upgrade/,
with a confirmation) and an Upgrade All Sites header button
(POST /hub/api/v2/sites/upgrade/, with a confirmation).
Search, sort, and pagination¶
SiteSearchPaginationForm (core/.../form/forms.py) filters and orders
the list server-side:
- The search query matches the Site ID, owner, space, name, type, and description. A placeholder hints "Search by name, owner, or path".
- Sorting supports
site_name,owner,registered_date, andretention_date, ascending or descending. A click on a column header sets the hidden sort fields and re-submits the form; headers carryaria-sort. - Pagination shows a "Results N | Page x / y" summary with Previous and
Next buttons. The page size is
hub.pagination_max_items(default 15).
Messages and read-only mode¶
For staff users, the list view processes global messages (admin users also
receive admin-only messages, core/.../service/message.py) and checks the
platform read-only state. In read-only mode the Hub flashes
"The system is in ReadOnly mode, no changes are allowed...".
Empty-list hints¶
When the list has no rows, the table shows a filter hint when a query is active, a "Create a new site" link for staff users, and — for non-staff users on My Sites — text that explains where their Sites appear and a link to All Sites.
Create site¶
Access and modal flow¶
There is no full create page. The staff Create nav item (and the
empty-list link) calls $.modalCreate() (hub/.../static/js/wizard.js).
The script requests GET /hub/create/?template=<name> with
accept: text/html and opens the returned hub/create.html fragment in a
jQuery UI dialog. A response that is not the form fragment (for example an
error page) produces a warning toast instead. The view
(hub/views.py:create) requires staff, and redirects to My Sites when the
platform is in read-only mode.
Form fields¶
The form shows the fields a normal user may set: the creation template
selector, owner (an on-demand user picker; defaults to the current
user), storage quota, space (optional; the URL uses the owner when
it is empty), name, and a collapsible description. A live preview
composes the full website address from the space (or owner) and name. A
governance panel states the usage condition and links to the governance
page and the configured terms URL. The create fragment renders no other
AddEditSiteForm controls, and the protection is server-side rather than
rendered: on add, pre_initialize_add_form generates the site ID, fixes
registered_date to today, and for non-administrators overwrites the
submitted data of the protected fields
(_default_non_admin_fields); _protect_form_fields additionally marks the
master token read-only. Creation defaults for
non-administrators: type private, owner and registered-by set to the
current user, monitoring off, and retention date today + 365 days.
A create template may only fill fields the submitter is allowed to change
(is_allowed_to_change_field).
Creation templates¶
The template selector lists the default template plus the templates from
both sources: the read-only platform templates the deployment mounts at
/sites-templates/ (Helm value siteTemplates) and the ad-hoc templates
on the data volume that platform administrators manage through the Hub API
(site_templates.get_template_names, see requirement HUI-02). The platform
source wins a name collision. The server
applies a template with AddEditSiteForm.pre_initialize_add_form: it
overrides only fields that are still unfilled and that the user is allowed
to change. Changing the selector re-opens the modal with
?template=<name>, so the template values arrive rendered
(AddSiteApiRequest/TemplateApiRequest parse the parameter).
Validation¶
The same AddEditSiteForm validates UI input and API input (HUB-02 in
12). The main rules:
- Space: 1–60 characters,
SiteSpaceValid, and the URL-path character set; name: 1–60 characters and the same character set. These limits are themaxLengthvalues of the Site CRD (SITE_SPACE_MAX_LENGTHandSITE_NAME_MAX_LENGTH). When the custom space is empty, the owner username is the space, so the form refuses an owner with more than 60 characters and asks for a custom space. - Quota: 1 to
site.storage_max_quotaGB; the error message tells the user to create the Site with the maximum and request more. When storage expansion is supported, a quota change can only increase the value; platform administrators bypass the range check. - Retention date: later than today, and at most one year from today for non-administrators.
- A
privateSite requires at least one Access User or Access Group. - A custom application image must match the image format, must come from
an allowed registry when the list is configured, and is rejected on a
publicSite unlesssite.allow_public_custom_applicationallows it. An existing public Site with a custom image reverts to private on edit (site_type_reverted; the Hub explains this in the action message,hub/tests/test_edit_site_reverted.py). - Custom error paths, no-cache file extensions, and CORS extra domains have strict formats because the Hub writes them into the proxy configuration.
Submit and errors¶
The dialog posts the serialized form to POST /hub/api/v2/sites/ — the
same endpoint as API creation — not to a Hub form handler. On status: OK
the script shows a success toast with the new Site view URL and redirects
there after two seconds. On an error response, $.showErrors
(hub/.../static/js/utilities.js) extracts each [field] token from the
API message, marks those fields is-invalid so the template's
invalid-feedback slots show the reason, and a toast repeats the message
(hub/.../app/api/request_models.py:validate_form composes those messages).