Skip to content

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, and retention_date, ascending or descending. A click on a column header sets the hidden sort fields and re-submits the form; headers carry aria-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 the maxLength values of the Site CRD (SITE_SPACE_MAX_LENGTH and SITE_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_quota GB; 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 private Site 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 public Site unless site.allow_public_custom_application allows 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).