From d119f49981ecc4b48208e19ab0533860fc2f9ad7 Mon Sep 17 00:00:00 2001 From: Daniel Perrefort Date: Tue, 22 Sep 2026 10:02:53 -0400 Subject: [PATCH 1/2] Bumps zensical version and fixes minor typos --- docs/deploy/configure/notifications.md | 247 +++++++++++-------------- docs/deploy/operate/upgrades.md | 4 +- docs/index.md | 4 +- requirements.txt | 2 +- zensical.toml | 4 +- 5 files changed, 114 insertions(+), 147 deletions(-) diff --git a/docs/deploy/configure/notifications.md b/docs/deploy/configure/notifications.md index ed1253c..06c12df 100644 --- a/docs/deploy/configure/notifications.md +++ b/docs/deploy/configure/notifications.md @@ -35,32 +35,14 @@ The following templates are available for customization. ### Common Fields The following fields are available to all notification templates. +All other fields are specific to the notification being issued and are listed in full in later sections. -??? info "Available Template Fields" +!!! info "Available Template Fields" | Field Name | Type | Description | |------------------|---------|-------------------------------------------------------------------| | `frontend_url` | `str` | Base URL of the frontend application, without a trailing slash. | -All templates rendered for a specific user additionally receive the fields below. - -??? info "Available Template Fields" - - | Field Name | Type | Description | - |----------------|---------|------------------------------------| - | `user_name` | `str` | Username of the notified user. | - | `user_first` | `str` | First name of the notified user. | - | `user_last` | `str` | Last name of the notified user. | - -Templates triggered by a change to a database record also receive the fields below. - -??? info "Available Template Fields" - - | Field Name | Type | Description | - |---------------------|--------------|-----------------------------------------------------------| - | `actor_username` | `str` | Username of the user who performed the recorded action. | - | `record_modified` | `datetime` | Date and time when the record was modified. | - ### Base Template **Template file:** `base.html` @@ -296,24 +278,21 @@ cluster. ??? info "Available Template Fields" - | Field Name | Type | Description | - |-----------------------|--------------------|------------------------------------------------------------------------| - | `user_name` | `str` | Username of the notified user. | - | `user_first` | `str` | First name of the notified user. | - | `user_last` | `str` | Last name of the notified user. | - | `actor_username` | `str` | Username of the user who submitted the request. | - | `record_modified` | `datetime` | Date and time when the request was submitted. | - | `req_id` | `int` | ID of the allocation request being notified about. | - | `req_title` | `str` | Title of the allocation request. | - | `req_team` | `str` | Name of the team associated with the allocation request. | - | `req_status` | `str` | Human readable status of the allocation request. | - | `req_submitter` | `str` | Username of the user the request was submitted by. | - | `req_submitted` | `date` or `None` | Date when the allocation request was submitted. | - | `req_active` | `date` or `None` | Date when the allocation request becomes active. | - | `req_expire` | `date` or `None` | Date when the allocation request expires. | - | `allocations` | `list[dict]` | List of allocated resources tied to the request. Each item includes: | - | ├ `alloc_cluster` | `str` | Name of the cluster where the resource is allocated. | - | └ `alloc_requested` | `int` | Number of service units requested (or `0` if unavailable). | + | Field Name | Type | Description | + |--------------------|--------------------|-------------------------------------------------------------------------| + | `recipient_name` | `str` | Display name of the notified user. | + | `submitter_name` | `str` | Display name of the user who submitted the request. | + | `event_date` | `date` or `None` | Date when the allocation request was submitted. | + | `request_id` | `int` | ID of the allocation request being notified about. | + | `request_title` | `str` | Title of the allocation request. | + | `request_status` | `str` | Human readable status of the allocation request. | + | `request_active` | `date` or `None` | Date when the allocation request becomes active. | + | `request_expire` | `date` or `None` | Date when the allocation request expires. | + | `team_name` | `str` | Name of the team associated with the allocation request. | + | `team_slug` | `str` | URL safe identifier for the team, suitable for building frontend URLs. | + | `allocations` | `tuple[dict]` | Allocated resources tied to the request. Each item includes: | + | ├ `cluster` | `str` | Name of the cluster where the resource is allocated. | + | └ `requested` | `int` | Number of service units requested (or `0` if unavailable). | ??? abstract "Default Template Content" @@ -332,25 +311,24 @@ reviewers can coordinate their work. ??? info "Available Template Fields" - | Field Name | Type | Description | - |-----------------------|--------------------|------------------------------------------------------------------------| - | `user_name` | `str` | Username of the notified user. | - | `user_first` | `str` | First name of the notified user. | - | `user_last` | `str` | Last name of the notified user. | - | `actor_username` | `str` | Username of the user who made the reviewer assignment. | - | `record_modified` | `datetime` | Date and time when the assignment was made. | - | `req_id` | `int` | ID of the allocation request being notified about. | - | `req_title` | `str` | Title of the allocation request. | - | `req_team` | `str` | Name of the team associated with the allocation request. | - | `req_status` | `str` | Human readable status of the allocation request. | - | `req_submitter` | `str` | Username of the user the request was submitted by. | - | `req_submitted` | `date` or `None` | Date when the allocation request was submitted. | - | `req_active` | `date` or `None` | Date when the allocation request becomes active. | - | `req_expire` | `date` or `None` | Date when the allocation request expires. | - | `req_coassignees` | `list[str]` | Usernames of any other reviewers assigned to the request. | - | `allocations` | `list[dict]` | List of allocated resources tied to the request. Each item includes: | - | ├ `alloc_cluster` | `str` | Name of the cluster where the resource is allocated. | - | └ `alloc_requested` | `int` | Number of service units requested (or `0` if unavailable). | + | Field Name | Type | Description | + |-------------------------|--------------------|-------------------------------------------------------------------------| + | `recipient_name` | `str` | Display name of the notified user. | + | `submitter_name` | `str` | Display name of the user who made the reviewer assignment. | + | `event_date` | `datetime` | Date and time when the assignment was made. | + | `request_id` | `int` | ID of the allocation request being notified about. | + | `request_title` | `str` | Title of the allocation request. | + | `request_status` | `str` | Human readable status of the allocation request. | + | `request_submitted` | `date` or `None` | Date when the allocation request was submitted. | + | `request_active` | `date` or `None` | Date when the allocation request becomes active. | + | `request_expire` | `date` or `None` | Date when the allocation request expires. | + | `team_name` | `str` | Name of the team associated with the allocation request. | + | `team_slug` | `str` | URL safe identifier for the team, suitable for building frontend URLs. | + | `request_coassignees` | `tuple[dict]` | Other reviewers assigned to the request. Each item includes: | + | └ `name` | `str` | Display name of the coassigned reviewer. | + | `allocations` | `tuple[dict]` | Allocated resources tied to the request. Each item includes: | + | ├ `cluster` | `str` | Name of the cluster where the resource is allocated. | + | └ `requested` | `int` | Number of service units requested (or `0` if unavailable). | ??? abstract "Default Template Content" @@ -368,21 +346,18 @@ reviewers. ??? info "Available Template Fields" - | Field Name | Type | Description | - |-----------------------|------------------------|------------------------------------------------------------| - | `user_name` | `str` | Username of the notified user. | - | `user_first` | `str` | First name of the notified user. | - | `user_last` | `str` | Last name of the notified user. | - | `actor_username` | `str` | Username of the user who posted the comment. | - | `record_modified` | `datetime` | Date and time when the comment was posted. | - | `req_id` | `int` | ID of the allocation request being notified about. | - | `req_title` | `str` | Title of the allocation request. | - | `req_team` | `str` | Name of the team associated with the allocation request. | - | `req_status` | `str` | Human readable status of the allocation request. | - | `comment_user` | `str` | Username of the comment author. | - | `comment_content` | `str` | Body of the comment as it was written. | - | `comment_created` | `datetime` or `None` | Date and time when the comment was created. | - | `comment_private` | `bool` | Whether the comment is only visible to staff reviewers. | + | Field Name | Type | Description | + |------------------------|--------------|-------------------------------------------------------------------------| + | `recipient_name` | `str` | Display name of the notified user. | + | `submitter_name` | `str` | Display name of the comment author. | + | `event_date` | `datetime` | Date and time when the comment was created. | + | `request_id` | `int` | ID of the allocation request being notified about. | + | `request_title` | `str` | Title of the allocation request. | + | `request_status` | `str` | Human readable status of the allocation request. | + | `team_name` | `str` | Name of the team associated with the allocation request. | + | `team_slug` | `str` | URL safe identifier for the team, suitable for building frontend URLs. | + | `comment_content` | `str` | Body of the comment, sanitized for safe rendering as HTML. | + | `comment_is_private` | `bool` | Whether the comment is only visible to staff reviewers. | ??? abstract "Default Template Content" @@ -395,31 +370,29 @@ reviewers. **Template file:** `request_status_changed.html` The _status changed_ notification alerts users that the status of a resource allocation request has changed. -The default template branches on the `req_status_code` field to render dedicated messaging for approved (`AP`), -declined (`DC`), and changes requested (`CR`) requests, and falls back to a generic message describing the old and new -status for all other transitions. +The default template branches on the `request_status` field to render dedicated messaging for approved, declined, and +changes requested reviews, and falls back to a generic message describing the old and new status for all other +transitions. ??? info "Available Template Fields" - | Field Name | Type | Description | - |----------------------|-----------------------|--------------------------------------------------------------------------| - | `user_name` | `str` | Username of the notified user. | - | `user_first` | `str` | First name of the notified user. | - | `user_last` | `str` | Last name of the notified user. | - | `actor_username` | `str` | Username of the user who changed the request status. | - | `record_modified` | `datetime` | Date and time when the status change was recorded. | - | `req_id` | `int` | ID of the allocation request being notified about. | - | `req_title` | `str` | Title of the allocation request. | - | `req_team` | `str` | Name of the team associated with the allocation request. | - | `req_status_code` | `str` | Status code of the request after the change (e.g., `AP`, `DC`, `CR`). | - | `req_status_old` | `str` | Human readable status of the request before the change. | - | `req_status_new` | `str` | Human readable status of the request after the change. | - | `req_active` | `date` or `None` | Date when the allocation request becomes active. | - | `req_expire` | `date` or `None` | Date when the allocation request expires. | - | `allocations` | `list[dict]` | List of allocated resources tied to the request. Each item includes: | - | ├ `alloc_cluster` | `str` | Name of the cluster where the resource is allocated. | - | ├ `alloc_requested` | `int` | Number of service units requested (or `0` if unavailable). | - | └ `alloc_awarded` | `int` or `None` | Number of service units awarded (or `None` if not yet awarded). | + | Field Name | Type | Description | + |-----------------------------|--------------------|-------------------------------------------------------------------------| + | `recipient_name` | `str` | Display name of the notified user. | + | `submitter_name` | `str` | Display name of the user who changed the request status. | + | `event_date` | `datetime` | Date and time when the status change was recorded. | + | `request_id` | `int` | ID of the allocation request being notified about. | + | `request_title` | `str` | Title of the allocation request. | + | `request_status` | `str` | Human readable status of the request after the change. | + | `request_status_previous` | `str` | Human readable status of the request before the change. | + | `request_active` | `date` or `None` | Date when the allocation request becomes active. | + | `request_expire` | `date` or `None` | Date when the allocation request expires. | + | `team_name` | `str` | Name of the team associated with the allocation request. | + | `team_slug` | `str` | URL safe identifier for the team, suitable for building frontend URLs. | + | `allocations` | `tuple[dict]` | Allocated resources tied to the request. Each item includes: | + | ├ `cluster` | `str` | Name of the cluster where the resource is allocated. | + | ├ `requested` | `int` | Number of service units requested (or `0` if unavailable). | + | └ `awarded` | `int` or `None` | Number of service units awarded (or `None` if not yet awarded). | ??? abstract "Default Template Content" @@ -436,29 +409,26 @@ its expiration date. ??? info "Available Template Fields" - | Field Name | Type | Description | - |---------------------------------|--------------------|-----------------------------------------------------------------------------| - | `user_name` | `str` | Username of the notified user. | - | `user_first` | `str` | First name of the notified user. | - | `user_last` | `str` | Last name of the notified user. | - | `req_id` | `int` | ID of the allocation request being notified about. | - | `req_title` | `str` | Title of the allocation request. | - | `req_team` | `str` | Name of the team associated with the allocation request. | - | `req_submitted` | `date` | Date when the allocation request was submitted. | - | `req_active` | `date` | Date when the allocation request became active. | - | `req_expire` | `date` or `None` | Date when the allocation request expires. | - | `req_days_left` | `int` or `None` | Number of days remaining until expiration (calculated from current date). | - | `allocations` | `list[dict]` | List of allocated resources tied to the request. Each item includes: | - | ├ `alloc_cluster` | `str` | Name of the cluster where the resource is allocated. | - | ├ `alloc_requested` | `int` | Number of service units requested (or `0` if unavailable). | - | └ `alloc_awarded` | `int` | Number of service units awarded (or `0` if unavailable). | - | `upcoming_requests` | `list[dict]` | List of upcoming or active requests for the same team. Each item includes: | - | ├ `id` | `int` | ID of the upcoming allocation request. | - | ├ `title` | `str` | Title of the upcoming allocation request. | - | ├ `submitted` | `date` | Date when the upcoming request was submitted. | - | ├ `active` | `date` | Date when the upcoming request became active. | - | ├ `expire` | `date` or `None` | Date when the upcoming request expires. | - | └ `status` | `str` | Status of the upcoming allocation request. | + | Field Name | Type | Description | + |--------------------------------|--------------------|-------------------------------------------------------------------------| + | `recipient_name` | `str` | Display name of the notified user. | + | `request_id` | `int` | ID of the allocation request being notified about. | + | `request_title` | `str` | Title of the allocation request. | + | `request_active` | `date` | Date when the allocation request became active. | + | `request_expire` | `date` | Date when the allocation request expires. | + | `request_days_until_expire` | `int` | Number of days remaining until the request expires. | + | `team_name` | `str` | Name of the team associated with the allocation request. | + | `team_slug` | `str` | URL safe identifier for the team, suitable for building frontend URLs. | + | `allocations` | `tuple[dict]` | Allocated resources tied to the request. Each item includes: | + | ├ `awarded` | `int` | Number of service units awarded (or `0` if unavailable). | + | └ `cluster` | `str` | Name of the cluster where the resource is allocated. | + | `upcoming_requests` | `tuple[dict]` | Other active or pending requests for the team. Each item includes: | + | ├ `active` | `date` or `None` | Date when the upcoming request became active. | + | ├ `expire` | `date` or `None` | Date when the upcoming request expires. | + | ├ `id` | `int` | ID of the upcoming allocation request. | + | ├ `status` | `str` | Human readable status of the upcoming allocation request. | + | ├ `submitted` | `date` or `None` | Date when the upcoming request was submitted. | + | └ `title` | `str` | Title of the upcoming allocation request. | ??? abstract "Default Template Content" @@ -475,29 +445,26 @@ and that the resources granted under that allocation are no longer available for ??? info "Available Template Fields" - | Field Name | Type | Description | - |---------------------------------|--------------------|-----------------------------------------------------------------------------| - | `user_name` | `str` | Username of the notified user. | - | `user_first` | `str` | First name of the notified user. | - | `user_last` | `str` | Last name of the notified user. | - | `req_id` | `int` | ID of the allocation request being notified about. | - | `req_title` | `str` | Title of the allocation request. | - | `req_team` | `str` | Name of the team associated with the allocation request. | - | `req_submitted` | `date` | Date when the allocation request was submitted. | - | `req_active` | `date` | Date when the allocation request became active. | - | `req_expire` | `date` or `None` | Date when the allocation request expires. | - | `allocations` | `list[dict]` | List of allocated resources tied to the request. Each item includes: | - | ├ `alloc_cluster` | `str` | Name of the cluster where the resource is allocated. | - | ├ `alloc_requested` | `int` | Number of service units requested (or `0` if unavailable). | - | ├ `alloc_awarded` | `int` | Number of service units awarded (or `0` if unavailable). | - | └ `alloc_final` | `int` | Number of service units used by the team (or `0` if unavailable). | - | `upcoming_requests` | `list[dict]` | List of upcoming or active requests for the same team. Each item includes: | - | ├ `id` | `int` | ID of the upcoming allocation request. | - | ├ `title` | `str` | Title of the upcoming allocation request. | - | ├ `submitted` | `date` | Date when the upcoming request was submitted. | - | ├ `active` | `date` | Date when the upcoming request became active. | - | ├ `expire` | `date` or `None` | Date when the upcoming request expires. | - | └ `status` | `str` | Status of the upcoming allocation request. | + | Field Name | Type | Description | + |-----------------------|--------------------|-------------------------------------------------------------------------| + | `recipient_name` | `str` | Display name of the notified user. | + | `request_id` | `int` | ID of the allocation request being notified about. | + | `request_title` | `str` | Title of the allocation request. | + | `request_active` | `date` | Date when the allocation request became active. | + | `request_expire` | `date` | Date when the allocation request expired. | + | `team_name` | `str` | Name of the team associated with the allocation request. | + | `team_slug` | `str` | URL safe identifier for the team, suitable for building frontend URLs. | + | `allocations` | `tuple[dict]` | Allocated resources tied to the request. Each item includes: | + | ├ `awarded` | `int` | Number of service units awarded (or `0` if unavailable). | + | ├ `cluster` | `str` | Name of the cluster where the resource is allocated. | + | └ `final` | `int` | Number of service units used by the team (or `0` if unavailable). | + | `upcoming_requests` | `tuple[dict]` | Other active or pending requests for the team. Each item includes: | + | ├ `active` | `date` or `None` | Date when the upcoming request became active. | + | ├ `expire` | `date` or `None` | Date when the upcoming request expires. | + | ├ `id` | `int` | ID of the upcoming allocation request. | + | ├ `status` | `str` | Human readable status of the upcoming allocation request. | + | ├ `submitted` | `date` or `None` | Date when the upcoming request was submitted. | + | └ `title` | `str` | Title of the upcoming allocation request. | ??? abstract "Default Template Content" diff --git a/docs/deploy/operate/upgrades.md b/docs/deploy/operate/upgrades.md index 5b11f3d..319ddf5 100644 --- a/docs/deploy/operate/upgrades.md +++ b/docs/deploy/operate/upgrades.md @@ -62,8 +62,8 @@ docker compose down # Pause here to back up the application database -# Edit the docker compose recipe to reference the desired version +# Edit the docker compose recipe to reference the desired versions -# Bring service back online +# Bring services back online docker compose up -d ``` diff --git a/docs/index.md b/docs/index.md index 68ac62d..4384ad3 100644 --- a/docs/index.md +++ b/docs/index.md @@ -17,8 +17,8 @@ administrators and translates into a worse customer experience for HPC users. Keystone solves this problem by providing a unified management platform for HPC resources. Users get self-service access to request resources and monitor -team consumption. Administrators get a central control plane for setting -allocation policy, monitoring usage in real time, and tracing that usage +team consumption. Meanwhile, administrators get a central control plane for +setting allocation policy, monitoring usage in real time, and tracing that usage back to individual teams and projects. Because allocation and access are governed together, the two never drift apart. Keystone's built-in automation keeps every change in sync, so what Keystone records and what the diff --git a/requirements.txt b/requirements.txt index 9112693..3416ff6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1 @@ -zensical==0.0.57 +zensical==0.0.63 diff --git a/zensical.toml b/zensical.toml index 79bc1bd..cd047d3 100644 --- a/zensical.toml +++ b/zensical.toml @@ -8,8 +8,8 @@ copyright = "Copyright © - Better HPC" extra_css = ["assets/stylesheets/extra.css"] extra_javascript = [ - "assets/javascripts/tex-mml-chtml.js", # Matchjax library - "assets/javascripts/mathjax.js", # Commands to trigger mathjax rendering + "assets/javascripts/mathjax.js", + "assets/javascripts/tex-mml-chtml.js", ] nav = [ From 7972d3e16ea058325fe68d33cbf27e479b8d663c Mon Sep 17 00:00:00 2001 From: Daniel Perrefort Date: Tue, 22 Sep 2026 10:29:18 -0400 Subject: [PATCH 2/2] Adds documentation for dotpath navigation --- docs/integrate/api/batch-jobs.md | 53 +++++++++++++++++++++++++++---- docs/integrate/provision/slurm.md | 2 +- zensical.toml | 1 + 3 files changed, 48 insertions(+), 8 deletions(-) diff --git a/docs/integrate/api/batch-jobs.md b/docs/integrate/api/batch-jobs.md index 290d777..a211329 100644 --- a/docs/integrate/api/batch-jobs.md +++ b/docs/integrate/api/batch-jobs.md @@ -52,9 +52,9 @@ This allows the output of one action, such as a newly created record's ID, to be To use a reference, assign a `ref` alias to the action whose output you want to capture. Then use the `@ref{alias.dotpath}` syntax in any subsequent `path`, `payload`, or `query_params` value. -References support both dictionary key access and integer list indexing, allowing deep traversal into nested objects. +Reference aliases may only contain letters, numbers, hyphens, and underscores, and must be unique within a job. -In the following example, a user and team are created in the first two steps, each with a unique reference. +In the following example, a user and team are created in the first two steps, each with a unique reference. The user is then assigned team membership using the generated team and user id values in a subsequent request. ```json @@ -98,6 +98,45 @@ The user is then assigned team membership using the generated team and user id v An action can only reference the output of previous steps in the execution order. Forward references are not supported. +## Traversing Nested Data + +The portion of a reference following the alias is a dotpath resolved against the referenced response body. +Each segment is either a dictionary key or a zero-based list index, so responses can be traversed to arbitrary depth. + +Given a step aliased as `team_list` that returned the following body: + +```json +{ + "count": 2, + "results": [ + { + "id": 17, + "name": "Team 1", + "_members": [ + { + "id": 5, + "username": "member1" + } + ] + }, + { + "id": 18, + "name": "Team 2", + "_members": [] + } + ] +} +``` + +The following tokens resolve as shown: + +| Token | Resolved Value | +|-------------------------------------------------|----------------| +| `@ref{team_list.count}` | `2` | +| `@ref{team_list.results.0.id}` | `17` | +| `@ref{team_list.results.1.name}` | `"Team 2"` | +| `@ref{team_list.results.0._members.0.username}` | `"member1"` | + ## Uploading Files Actions can include file attachments by submitting the job as a `multipart/form-data` request instead of JSON. @@ -175,7 +214,7 @@ Each result contains the following fields: | Field | Description | |----------|------------------------------------------------------------------------------| -| `ref` | The actions's alias, or `null` if none was provided. | +| `ref` | The actions's alias, or an empty string if none was provided. | | `index` | The one-based position of the step within the job. | | `method` | The HTTP method executed. | | `path` | The resolved path that was called, after any `@ref` tokens were substituted. | @@ -190,11 +229,11 @@ For example: ```json { - "detail": "Step #1 (POST /users/users/) failed with status 400", + "detail": "Step #2 (POST /users/users/) failed with status 400", "step": 2, "status": 400, "body": { - "title": [ + "username": [ "user with this username already exists." ] } @@ -203,8 +242,8 @@ For example: ### Reference Resolution Failure -If a `@ref` or `@file` token cannot be resolved — for example because the alias is undefined, the dotpath is -invalid, or a referenced file part was not uploaded — the job halts and a `422` error is returned: +If a `@ref` or `@file` token cannot be resolved, the job will halt and return a `422` error containing the +token and error description: ```json { diff --git a/docs/integrate/provision/slurm.md b/docs/integrate/provision/slurm.md index 37d6b8f..12c5619 100644 --- a/docs/integrate/provision/slurm.md +++ b/docs/integrate/provision/slurm.md @@ -23,7 +23,7 @@ $\left ( W \right )$ summed over all resource types $\left ( R \right )$. This value is also commonly referred to as an HPC _service unit_. $$ -\text{Billable Usage} = \sum_\text{R} \,\, \left ( W_\text{R} * U_\text{R} \right ) +\text{Billable Usage} = \sum_\text{R} \left ( W_\text{R} * U_\text{R} \right ) $$ !!! Warning diff --git a/zensical.toml b/zensical.toml index cd047d3..2b73756 100644 --- a/zensical.toml +++ b/zensical.toml @@ -67,6 +67,7 @@ features = [ "content.action.view", "content.code.annotate", "content.code.copy", + "content.tabs.link", "navigation.indexes", "navigation.instant", "navigation.instant.progress",