Custom settings forms¶
When an experimenter creates a session, they can adjust the config's default session settings by editing raw JSON in the admin interface. Raw JSON is flexible, but it is also easy to get wrong: a mistyped key or a string where a list is expected, and the session runs with the wrong parameters.
An app can replace that JSON editor with its own settings form. If your app folder contains a file named AdminSettings.html, the admin's new-session page shows your form instead of the JSON editor whenever a config containing your app is selected.
Super advanced
This is one of the most advanced features in uproot. You will write raw HTML, Jinja template code, and JavaScript by hand — uproot's form fields are not available here. Most apps are perfectly fine with the JSON editor. This page assumes you have read Session settings.
A minimal example¶
Suppose your app defines a default number of rounds in its constants class and reads it from the session settings:
Create AdminSettings.html next to your app's __init__.py:
{% set n_rounds = settings.get("n_rounds", C.DEFAULT_ROUNDS) %}
<div class="border rounded p-3" id="{{ editor_id }}">
<label class="form-label" for="{{ editor_id }}-rounds">Number of rounds</label>
<input class="form-control" id="{{ editor_id }}-rounds"
min="1" step="1" type="number" value="{{ n_rounds }}">
</div>
<script>
registerSessionSettingsEditor("{{ editor_id }}", () => {
const rounds = Number(document.getElementById("{{ editor_id }}-rounds").value);
if (!Number.isInteger(rounds) || rounds < 1) {
throw new TypeError("Number of rounds must be a positive integer.");
}
return { n_rounds: rounds };
});
</script>
Three things happen here:
- The fragment prefills the input from
settings(the config's defaults), falling back toC.DEFAULT_ROUNDS— so the form always starts at the values the session would get anyway. - The inline script registers a reader function for this editor with
registerSessionSettingsEditor. - When the experimenter clicks Create session, the reader runs. It validates the input and returns an object whose keys are merged into the session settings. Throwing an error blocks session creation and shows the error message to the experimenter — this is your validation mechanism.
The fragment is not a full page: do not extend Base.html or any other template. Write only the form markup and its script. Admin pages load Bootstrap 5, so classes like form-control and form-label work as expected.
Where uproot looks¶
your_app/AdminSettings.html— used for every config that includesyour_app. If a config contains several apps with such a file, all their forms are shown, stacked in the config's app order.AdminSettings.htmlat the project root — a project-level form that takes over for all configs; app-level fragments are then ignored.- A fragment that renders to only whitespace is skipped, so you can opt out per config with a Jinja
{% if %}around the whole file. - Configs without any fragment keep the plain JSON editor.
Template variables¶
Fragments are rendered server-side when the new-session page loads, once per config. They receive:
| Variable | Meaning |
|---|---|
config |
Name of the config this rendering belongs to |
apps |
List of app names in that config |
appname |
The app the fragment belongs to (None for a project-level fragment) |
settings |
The config's default settings, as declared via load_config(..., settings={...}) |
editor_id |
Unique id for this editor — use it as your root element's id and pass it to registerSessionSettingsEditor |
C |
The app's constants class (app fragments only) |
appstatic |
URL helper for the app's static files (app fragments only) |
Warning
The same app can appear in several configs, so your fragment may be rendered several times into the same admin page. Never hard-code element ids — always derive them from editor_id, as in the example above.
The reader function¶
The reader you register runs when the experimenter submits the form. It receives one argument, an object with:
config— the selected config's namesettings— the settings collected so far: the config's defaults, already merged with the contributions of readers registered before yours
Return a JSON-serializable object; its keys are merged over those settings. Keys your form does not touch keep their default values. Return undefined to contribute nothing. Throw an Error with a human-readable message to abort session creation and display the message.
What the experimenter sees¶
When a config with a custom form is selected, the Keep default settings checkbox starts unchecked and the form is shown, prefilled with the defaults. Checking the box hides the form and uses the config's defaults unchanged. For such configs, the custom form fully replaces the JSON editor — there is no raw JSON fallback in the UI.
If a fragment raises an error while rendering, or a config's default settings are not a JSON object, the new-session page shows a red error message for that config instead of a form, and the config falls back to the JSON editor. The full traceback lands in the server log.
Complete example¶
The double auction example ships a settings form covering eight settings, including comma-separated integer lists and values that may be either a scalar or one entry per round: