Quantum 0.12.0
Added
quantum admin, with the new [admin] extra (pip install "quantum-framework[admin]"): starts the Quantum Admin — its .q screens and services now ship in the wheel. Data goes to ./.quantum-admin (--data), application paths are relative to the current folder (--root), it listens on 127.0.0.1:8090. Session keys are kept in the data folder, so a restart does not sign everyone out. See Quantum Admin in the guide.- Declared services (SVC-1..3): a Python function registered with
@service("name"), in a module listed under services: in quantum.config.yaml, is called from a page with <q:invoke name="x" service="name">. q:invoke service= had been parsed since the first version and failed with "Unsupported invocation type". See the new guide page Declared Services. login_url (AUTH-4): where require_auth sends a visitor without a session — security.login_url in quantum.config.yaml, or login_url= on the component. It was always /login. Only local paths are accepted.- Route segments inside
q:action (ROUTE-2): a POST to components/app/[name].q has name in the action, as the page render does; a form field with the same name does not replace it. [...path] catch-all segments are now documented (ROUTE-1). - Private components (ROUTE-3): a file or folder under
components/ whose name starts with _ is not served; it exists to be imported, like a layout.
Security
- A layout's slot content leaked between requests. Filling a
q:slot mutated the component held in the resolver cache, so after the first request every later page rendered with that component showed the first page's slot content. Composition no longer mutates cached components (COMP-3). - The session cookie is sent with
SameSite=Lax and HttpOnly (AUTH-5), so a form on another site cannot post to a q:action with the visitor's session.
Fixed
- Component composition (COMP-1..4): components are found under
paths.components and the from= of q:import (they were searched in ./components of the process's working directory); slot content is rendered in the page's scope, so loops and conditions over the page's data work inside a layout; child components run with the page's configuration (datasources, services); props are expressions; a missing or failing component is an error instead of an HTML comment on a 200 page. A child component sees the page's session, application and request scopes. flash and the url of q:redirect evaluate expressions (ACT-3): flash="{result.error}" ended the action with a 500. flash and flashType always exist on a rendered page ('' without a message).condition="1", condition="2" and condition="{1}" are true (IF-2). They were read as regex quantifiers and were always false in a q:if outside the markup; the same condition inside the markup was true.and / or short-circuit (EXPR-6): user and user.name failed when user did not exist, because both sides were evaluated first.
Breaking
q:invoke endpoint= is refused by the parser; it never did anything.- The admin's screens moved from
components/admin to quantum_admin/components/admin (and their CSS/JS from static/ to quantum_admin/assets); quantum start at the repository root no longer serves /admin. Use quantum admin --data quantum_admin to open the repository's existing admin data. components/_anything.q and everything under a _folder/ answer 404 (ROUTE-3). Rename a page that starts with _.- A component call that cannot be resolved or fails now makes the page fail.
- Inside a layout, slot content no longer sees the layout's own variables — it renders with the page's.
- A statement (
q:set, q:query, q:invoke, q:action…) inside an HTML element or inside the content of a component call is a parse error (PARSE-2). It never ran: statements run before the page is rendered, so <ul><q:set name="y" .../><li>{y}</li></ul> printed a literal {y}, and a q:action inside a <section> was never found. Move it above the markup. So is a q:set in a q:loop that renders rows, when those rows read the value it sets: every row showed the last iteration's value. A total accumulated in the loop and read after it still works. The comment form of projects/blog was affected and never worked.
← 0.11.0 · All versions · 0.13.0 →