Cookbook
Short recipes for one task each. Every recipe is a small app in examples/cookbook/ with its own quantum test suite: the code on its page is imported from the tested files, and what it shows as a result was produced by running it.
Basics
- A first page, and a second — Each file in components/ is a page at its own URL; a URL with no file is 404.
- Variables and expressions — q:set stores a value, braces compute with it, and default fills in what is missing.
- Loops — q:loop over a list (with its position), a range of numbers and comma-separated text.
- Conditionals — q:if, q:elseif and q:else, with conditions that are expressions.
- Functions — A q:function with typed, checked params, called from q:set and from the HTML.
- A page per URL — components/product/[id].q answers /product/1, /product/2...; the segment is a variable.
- Read the query string — query.name reads ?name= from the address; default covers a missing one; urlencode builds a link.
- Reusable components — A component with props and a slot, imported from a _ folder that is never served.
Screens
- A layout that fits the screen — ui:hbox side by side on a wide screen, stacked on a narrow one, with grow, width and hide-below.
- A table you edit in place — ui:table edit= turns each cell into a small form checked against the table's schema; no action to write.
- Tabs — ui:tabpanel with one ui:tab per section of a page.
- Cards — ui:card with a header, a body and a footer, in a ui:grid; or a card with just a title.
- Every kind of field — ui:form with ui:formitem labels: text, number, a select with options, a switch, radios and a multi-line field.
- The same page in a terminal — One ui:* page, served to the browser by quantum start and drawn in a terminal by quantum console.
Testing the app
- A first test with quantum test — Test a page and its action in Quantum itself — visit, submit, check the flash, the table and the field error.
- Test data with test:given — Put the rows a test needs in its fresh database with test:given, and sign a user in with test:as.
- Testing what an action refuses — Test the field errors, the business rule and the success of an action — error=, message=, flash= and the table.
Files & mail
- Mail in development — Send mail from an action without a mail server while you develop — host: log writes each message to the log.
- When the mail server says no — Keep an order even when its confirmation e-mail cannot be sent — onerror=continue, and tell the visitor.
Login & permissions
- Log in with a hashed password — Check a password against its bcrypt hash with verifyPassword, open the session, and keep a page for signed-in users.
- Sign up and store a password hash — Create an account with hashPassword, so the database never holds the password, with rules on each field.
- A page for one role only — require_role keeps a page to the admins: a member gets 403, and a visitor who is not signed in is sent to sign in.
- A guard that redirects — A top-level q:if with q:redirect protects a page and every action on it: a post without a session writes nothing.
- Sign out — A logout page that clears the session and redirects; the protected pages are closed again.
Forms & actions
- Show each error on its field — Write the rules once on the action's q:param; the form reads them and shows every refusal next to its field.
- A refused form keeps what was typed — After a refusal, the form comes back filled with the values sent, once, so nobody types a long message twice.
- Redirect and say what happened — End an action with q:redirect and a flash; q:flash for a warning; the message shows once on the next page.
- Several forms on one page — Each form and button posts the name of its action; a name the page does not have answers 400.
- A form from the table — q:action table= takes its params from the schema; a ui:form with no fields draws one field per column.
- Edit a row — A page per row with [id].q, a form opened with the row's values, and the table's rules on save.
- Confirm before deleting — A page that asks first, reached by a link, and the delete as a POST from its button; no JavaScript.
- Numbers and dates — type=integer, decimal and date on q:param: the action gets checked numbers and real dates, with min and max.
- A choice from a list — enum on q:param gives ui:select and ui:radio their options and refuses anything else; a box is a boolean.
Data & SQL
- A query with parameters — Filter by a value from the URL, bound as a q:param — the value never becomes SQL.
- A paginated list — One page of a long list at a time, with ui:pager drawing the links to the others.
- Search as you type — A field that refreshes the results after each pause in typing — the page's own query does the search.
- Filter and sort a table — Links that filter the rows and headers that sort them — both in SQL, both in the URL.
- Writes that happen together — A q:transaction: the debit, the credit and the log line commit together, or none of them does.
- Change history — history: true records who changed which row, and how; ui:history shows it on the page.
- Add a column with a migration — Change the schema with a new migration file; the old one stays as it was.
- Read a CSV file — q:data turns a CSV file into typed records, filtered and sorted — no database needed.
- Load a CSV file into a table — Insert every row of a file in one transaction — a row that fails leaves nothing behind.
- Read a JSON file — A JSON array as a list of records, with a computed field on each.
- Totals from one query — SQL over a query's result, in memory — the database is asked once.
AI
- Answers with their sources — Answer questions from your own documents with q:knowledge and q:llm knowledge=, and list the sources.
- When the documents do not know — minRelevance keeps unrelated chunks out; with nothing left, the model is not asked and the page says so.
- Stream an answer — A streamed q:llm and ui:stream: the page renders at once, the answer appears as it is written.
- An agent over your database — q:agent with a read-only query tool: the model picks the tool and its arguments, never the SQL.
- When the model fails — onerror on q:llm: a model that is down or too slow does not take the page down with it.
- Sort messages with JSON answers — responseFormat json: the model's answer is an object whose fields you check and store.
- Answers from a table — A q:knowledge source that is a query: the rows of your FAQ table, retrieved like documents.